Render a context menu when right-clicking in project panel

It doesn't currently do anything, but I managed to get it rendering in an absolutely positioned way.
This commit is contained in:
Nathan Sobo 2022-05-24 18:30:04 -06:00 committed by Antonio Scandurra
parent f4d13ef596
commit b110fd5fb7
23 changed files with 260 additions and 91 deletions

View file

@ -612,7 +612,10 @@ mod tests {
});
let mut list = List::new(state.clone());
let (size, _) = list.layout(constraint, &mut presenter.build_layout_context(false, cx));
let (size, _) = list.layout(
constraint,
&mut presenter.build_layout_context(vec2f(100., 40.), false, cx),
);
assert_eq!(size, vec2f(100., 40.));
assert_eq!(
state.0.borrow().items.summary().clone(),
@ -634,8 +637,10 @@ mod tests {
true,
&mut presenter.build_event_context(cx),
);
let (_, logical_scroll_top) =
list.layout(constraint, &mut presenter.build_layout_context(false, cx));
let (_, logical_scroll_top) = list.layout(
constraint,
&mut presenter.build_layout_context(vec2f(100., 40.), false, cx),
);
assert_eq!(
logical_scroll_top,
ListOffset {
@ -659,8 +664,10 @@ mod tests {
}
);
let (size, logical_scroll_top) =
list.layout(constraint, &mut presenter.build_layout_context(false, cx));
let (size, logical_scroll_top) = list.layout(
constraint,
&mut presenter.build_layout_context(vec2f(100., 40.), false, cx),
);
assert_eq!(size, vec2f(100., 40.));
assert_eq!(
state.0.borrow().items.summary().clone(),
@ -770,11 +777,12 @@ mod tests {
}
let mut list = List::new(state.clone());
let window_size = vec2f(width, height);
let (size, logical_scroll_top) = list.layout(
SizeConstraint::new(vec2f(0., 0.), vec2f(width, height)),
&mut presenter.build_layout_context(false, cx),
SizeConstraint::new(vec2f(0., 0.), window_size),
&mut presenter.build_layout_context(window_size, false, cx),
);
assert_eq!(size, vec2f(width, height));
assert_eq!(size, window_size);
last_logical_scroll_top = Some(logical_scroll_top);
let state = state.0.borrow();

View file

@ -14,9 +14,11 @@ pub struct MouseEventHandler {
state: ElementStateHandle<MouseState>,
child: ElementBox,
cursor_style: Option<CursorStyle>,
mouse_down_handler: Option<Box<dyn FnMut(&mut EventContext)>>,
click_handler: Option<Box<dyn FnMut(usize, &mut EventContext)>>,
mouse_down_handler: Option<Box<dyn FnMut(Vector2F, &mut EventContext)>>,
click_handler: Option<Box<dyn FnMut(Vector2F, usize, &mut EventContext)>>,
drag_handler: Option<Box<dyn FnMut(Vector2F, &mut EventContext)>>,
right_mouse_down_handler: Option<Box<dyn FnMut(Vector2F, &mut EventContext)>>,
right_click_handler: Option<Box<dyn FnMut(Vector2F, usize, &mut EventContext)>>,
padding: Padding,
}
@ -24,6 +26,7 @@ pub struct MouseEventHandler {
pub struct MouseState {
pub hovered: bool,
pub clicked: bool,
pub right_clicked: bool,
prev_drag_position: Option<Vector2F>,
}
@ -43,6 +46,8 @@ impl MouseEventHandler {
mouse_down_handler: None,
click_handler: None,
drag_handler: None,
right_mouse_down_handler: None,
right_click_handler: None,
padding: Default::default(),
}
}
@ -52,12 +57,18 @@ impl MouseEventHandler {
self
}
pub fn on_mouse_down(mut self, handler: impl FnMut(&mut EventContext) + 'static) -> Self {
pub fn on_mouse_down(
mut self,
handler: impl FnMut(Vector2F, &mut EventContext) + 'static,
) -> Self {
self.mouse_down_handler = Some(Box::new(handler));
self
}
pub fn on_click(mut self, handler: impl FnMut(usize, &mut EventContext) + 'static) -> Self {
pub fn on_click(
mut self,
handler: impl FnMut(Vector2F, usize, &mut EventContext) + 'static,
) -> Self {
self.click_handler = Some(Box::new(handler));
self
}
@ -67,6 +78,22 @@ impl MouseEventHandler {
self
}
pub fn on_right_mouse_down(
mut self,
handler: impl FnMut(Vector2F, &mut EventContext) + 'static,
) -> Self {
self.right_mouse_down_handler = Some(Box::new(handler));
self
}
pub fn on_right_click(
mut self,
handler: impl FnMut(Vector2F, usize, &mut EventContext) + 'static,
) -> Self {
self.right_click_handler = Some(Box::new(handler));
self
}
pub fn with_padding(mut self, padding: Padding) -> Self {
self.padding = padding;
self
@ -120,6 +147,8 @@ impl Element for MouseEventHandler {
let mouse_down_handler = self.mouse_down_handler.as_mut();
let click_handler = self.click_handler.as_mut();
let drag_handler = self.drag_handler.as_mut();
let right_mouse_down_handler = self.right_mouse_down_handler.as_mut();
let right_click_handler = self.right_click_handler.as_mut();
let handled_in_child = self.child.dispatch_event(event, cx);
@ -144,7 +173,7 @@ impl Element for MouseEventHandler {
state.prev_drag_position = Some(*position);
cx.notify();
if let Some(handler) = mouse_down_handler {
handler(cx);
handler(*position, cx);
}
true
} else {
@ -162,7 +191,7 @@ impl Element for MouseEventHandler {
cx.notify();
if let Some(handler) = click_handler {
if hit_bounds.contains_point(*position) {
handler(*click_count, cx);
handler(*position, *click_count, cx);
}
}
true
@ -184,6 +213,36 @@ impl Element for MouseEventHandler {
handled_in_child
}
}
Event::RightMouseDown { position, .. } => {
if !handled_in_child && hit_bounds.contains_point(*position) {
state.right_clicked = true;
cx.notify();
if let Some(handler) = right_mouse_down_handler {
handler(*position, cx);
}
true
} else {
handled_in_child
}
}
Event::RightMouseUp {
position,
click_count,
..
} => {
if !handled_in_child && state.right_clicked {
state.right_clicked = false;
cx.notify();
if let Some(handler) = right_click_handler {
if hit_bounds.contains_point(*position) {
handler(*position, *click_count, cx);
}
}
true
} else {
handled_in_child
}
}
_ => handled_in_child,
})
}

View file

@ -1,16 +1,28 @@
use serde_json::json;
use crate::{
geometry::{rect::RectF, vector::Vector2F},
json::ToJson,
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
};
pub struct Overlay {
child: ElementBox,
abs_position: Option<Vector2F>,
}
impl Overlay {
pub fn new(child: ElementBox) -> Self {
Self { child }
Self {
child,
abs_position: None,
}
}
pub fn with_abs_position(mut self, position: Vector2F) -> Self {
self.abs_position = Some(position);
self
}
}
@ -23,6 +35,11 @@ impl Element for Overlay {
constraint: SizeConstraint,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let constraint = if self.abs_position.is_some() {
SizeConstraint::new(Vector2F::zero(), cx.window_size)
} else {
constraint
};
let size = self.child.layout(constraint, cx);
(Vector2F::zero(), size)
}
@ -34,9 +51,10 @@ impl Element for Overlay {
size: &mut Self::LayoutState,
cx: &mut PaintContext,
) {
let bounds = RectF::new(bounds.origin(), *size);
let origin = self.abs_position.unwrap_or(bounds.origin());
let visible_bounds = RectF::new(origin, *size);
cx.scene.push_stacking_context(None);
self.child.paint(bounds.origin(), bounds, cx);
self.child.paint(origin, visible_bounds, cx);
cx.scene.pop_stacking_context();
}
@ -59,6 +77,10 @@ impl Element for Overlay {
_: &Self::PaintState,
cx: &DebugContext,
) -> serde_json::Value {
self.child.debug(cx)
json!({
"type": "Overlay",
"abs_position": self.abs_position.to_json(),
"child": self.child.debug(cx),
})
}
}