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:
parent
f4d13ef596
commit
b110fd5fb7
23 changed files with 260 additions and 91 deletions
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue