mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
Add missing mouse button events and mouse history navigation
Co-Authored-By: Max Brunsfeld Co-Authored-By: Nathan Sobo
This commit is contained in:
parent
03aa906068
commit
fc36c706d3
@ -10,6 +10,8 @@ pub struct EventHandler {
|
||||
child: ElementBox,
|
||||
capture: Option<Box<dyn FnMut(&Event, RectF, &mut EventContext) -> bool>>,
|
||||
mouse_down: Option<Box<dyn FnMut(&mut EventContext) -> bool>>,
|
||||
right_mouse_down: Option<Box<dyn FnMut(&mut EventContext) -> bool>>,
|
||||
other_mouse_down: Option<Box<dyn FnMut(u16, &mut EventContext) -> bool>>,
|
||||
}
|
||||
|
||||
impl EventHandler {
|
||||
@ -18,6 +20,8 @@ impl EventHandler {
|
||||
child,
|
||||
capture: None,
|
||||
mouse_down: None,
|
||||
right_mouse_down: None,
|
||||
other_mouse_down: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +33,22 @@ impl EventHandler {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_right_mouse_down<F>(mut self, callback: F) -> Self
|
||||
where
|
||||
F: 'static + FnMut(&mut EventContext) -> bool,
|
||||
{
|
||||
self.right_mouse_down = Some(Box::new(callback));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_other_mouse_down<F>(mut self, callback: F) -> Self
|
||||
where
|
||||
F: 'static + FnMut(u16, &mut EventContext) -> bool,
|
||||
{
|
||||
self.other_mouse_down = Some(Box::new(callback));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn capture<F>(mut self, callback: F) -> Self
|
||||
where
|
||||
F: 'static + FnMut(&Event, RectF, &mut EventContext) -> bool,
|
||||
@ -86,7 +106,23 @@ impl Element for EventHandler {
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
},
|
||||
Event::RightMouseDown { position, .. } => {
|
||||
if let Some(callback) = self.right_mouse_down.as_mut() {
|
||||
if bounds.contains_point(*position) {
|
||||
return callback(cx);
|
||||
}
|
||||
}
|
||||
false
|
||||
},
|
||||
Event::OtherMouseDown { position, button, .. } => {
|
||||
if let Some(callback) = self.other_mouse_down.as_mut() {
|
||||
if bounds.contains_point(*position) {
|
||||
return callback(*button, cx);
|
||||
}
|
||||
}
|
||||
false
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,30 @@ pub enum Event {
|
||||
LeftMouseDragged {
|
||||
position: Vector2F,
|
||||
},
|
||||
RightMouseDown {
|
||||
position: Vector2F,
|
||||
ctrl: bool,
|
||||
alt: bool,
|
||||
shift: bool,
|
||||
cmd: bool,
|
||||
click_count: usize,
|
||||
},
|
||||
RightMouseUp {
|
||||
position: Vector2F,
|
||||
},
|
||||
OtherMouseDown {
|
||||
position: Vector2F,
|
||||
button: u16,
|
||||
ctrl: bool,
|
||||
alt: bool,
|
||||
shift: bool,
|
||||
cmd: bool,
|
||||
click_count: usize,
|
||||
},
|
||||
OtherMouseUp {
|
||||
position: Vector2F,
|
||||
button: u16,
|
||||
},
|
||||
MouseMoved {
|
||||
position: Vector2F,
|
||||
left_mouse_down: bool,
|
||||
|
@ -125,6 +125,48 @@ impl Event {
|
||||
window_height - native_event.locationInWindow().y as f32,
|
||||
),
|
||||
}),
|
||||
NSEventType::NSRightMouseDown => {
|
||||
let modifiers = native_event.modifierFlags();
|
||||
window_height.map(|window_height| Self::RightMouseDown {
|
||||
position: vec2f(
|
||||
native_event.locationInWindow().x as f32,
|
||||
window_height - native_event.locationInWindow().y as f32,
|
||||
),
|
||||
ctrl: modifiers.contains(NSEventModifierFlags::NSControlKeyMask),
|
||||
alt: modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask),
|
||||
shift: modifiers.contains(NSEventModifierFlags::NSShiftKeyMask),
|
||||
cmd: modifiers.contains(NSEventModifierFlags::NSCommandKeyMask),
|
||||
click_count: native_event.clickCount() as usize,
|
||||
})
|
||||
}
|
||||
NSEventType::NSRightMouseUp => window_height.map(|window_height| Self::RightMouseUp {
|
||||
position: vec2f(
|
||||
native_event.locationInWindow().x as f32,
|
||||
window_height - native_event.locationInWindow().y as f32,
|
||||
),
|
||||
}),
|
||||
NSEventType::NSOtherMouseDown => {
|
||||
let modifiers = native_event.modifierFlags();
|
||||
window_height.map(|window_height| Self::OtherMouseDown {
|
||||
position: vec2f(
|
||||
native_event.locationInWindow().x as f32,
|
||||
window_height - native_event.locationInWindow().y as f32,
|
||||
),
|
||||
button: native_event.buttonNumber() as u16,
|
||||
ctrl: modifiers.contains(NSEventModifierFlags::NSControlKeyMask),
|
||||
alt: modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask),
|
||||
shift: modifiers.contains(NSEventModifierFlags::NSShiftKeyMask),
|
||||
cmd: modifiers.contains(NSEventModifierFlags::NSCommandKeyMask),
|
||||
click_count: native_event.clickCount() as usize,
|
||||
})
|
||||
}
|
||||
NSEventType::NSOtherMouseUp => window_height.map(|window_height| Self::OtherMouseUp {
|
||||
position: vec2f(
|
||||
native_event.locationInWindow().x as f32,
|
||||
window_height - native_event.locationInWindow().y as f32,
|
||||
),
|
||||
button: native_event.buttonNumber() as u16,
|
||||
}),
|
||||
NSEventType::NSLeftMouseDragged => {
|
||||
window_height.map(|window_height| Self::LeftMouseDragged {
|
||||
position: vec2f(
|
||||
|
@ -95,6 +95,22 @@ unsafe fn build_classes() {
|
||||
sel!(mouseUp:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(rightMouseDown:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(rightMouseUp:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(otherMouseDown:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(otherMouseUp:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(mouseMoved:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
|
@ -8,7 +8,7 @@ use gpui::{
|
||||
keymap::Binding,
|
||||
platform::CursorStyle,
|
||||
AnyViewHandle, Entity, MutableAppContext, Quad, RenderContext, Task, View, ViewContext,
|
||||
ViewHandle,
|
||||
ViewHandle, WeakViewHandle,
|
||||
};
|
||||
use postage::watch;
|
||||
use project::ProjectPath;
|
||||
@ -27,8 +27,8 @@ action!(ActivateNextItem);
|
||||
action!(CloseActiveItem);
|
||||
action!(CloseInactiveItems);
|
||||
action!(CloseItem, usize);
|
||||
action!(GoBack);
|
||||
action!(GoForward);
|
||||
action!(GoBack, Option<WeakViewHandle<Pane>>);
|
||||
action!(GoForward, Option<WeakViewHandle<Pane>>);
|
||||
|
||||
const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
|
||||
|
||||
@ -54,11 +54,19 @@ pub fn init(cx: &mut MutableAppContext) {
|
||||
cx.add_action(|pane: &mut Pane, action: &Split, cx| {
|
||||
pane.split(action.0, cx);
|
||||
});
|
||||
cx.add_action(|workspace: &mut Workspace, _: &GoBack, cx| {
|
||||
Pane::go_back(workspace, cx).detach();
|
||||
cx.add_action(|workspace: &mut Workspace, action: &GoBack, cx| {
|
||||
Pane::go_back(
|
||||
workspace,
|
||||
action.0.as_ref().and_then(|weak_handle| weak_handle.upgrade(cx)),
|
||||
cx
|
||||
).detach();
|
||||
});
|
||||
cx.add_action(|workspace: &mut Workspace, _: &GoForward, cx| {
|
||||
Pane::go_forward(workspace, cx).detach();
|
||||
cx.add_action(|workspace: &mut Workspace, action: &GoForward, cx| {
|
||||
Pane::go_forward(
|
||||
workspace,
|
||||
action.0.as_ref().and_then(|weak_handle| weak_handle.upgrade(cx)),
|
||||
cx
|
||||
).detach();
|
||||
});
|
||||
|
||||
cx.add_bindings(vec![
|
||||
@ -70,8 +78,8 @@ pub fn init(cx: &mut MutableAppContext) {
|
||||
Binding::new("cmd-k down", Split(SplitDirection::Down), Some("Pane")),
|
||||
Binding::new("cmd-k left", Split(SplitDirection::Left), Some("Pane")),
|
||||
Binding::new("cmd-k right", Split(SplitDirection::Right), Some("Pane")),
|
||||
Binding::new("ctrl--", GoBack, Some("Pane")),
|
||||
Binding::new("shift-ctrl-_", GoForward, Some("Pane")),
|
||||
Binding::new("ctrl--", GoBack(None), Some("Pane")),
|
||||
Binding::new("shift-ctrl-_", GoForward(None), Some("Pane")),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -163,19 +171,19 @@ impl Pane {
|
||||
cx.emit(Event::Activate);
|
||||
}
|
||||
|
||||
pub fn go_back(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> Task<()> {
|
||||
pub fn go_back(workspace: &mut Workspace, pane: Option<ViewHandle<Pane>>, cx: &mut ViewContext<Workspace>) -> Task<()> {
|
||||
Self::navigate_history(
|
||||
workspace,
|
||||
workspace.active_pane().clone(),
|
||||
pane.unwrap_or_else(|| workspace.active_pane().clone()),
|
||||
NavigationMode::GoingBack,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn go_forward(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> Task<()> {
|
||||
pub fn go_forward(workspace: &mut Workspace, pane: Option<ViewHandle<Pane>>, cx: &mut ViewContext<Workspace>) -> Task<()> {
|
||||
Self::navigate_history(
|
||||
workspace,
|
||||
workspace.active_pane().clone(),
|
||||
pane.unwrap_or_else(|| workspace.active_pane().clone()),
|
||||
NavigationMode::GoingForward,
|
||||
cx,
|
||||
)
|
||||
@ -187,6 +195,8 @@ impl Pane {
|
||||
mode: NavigationMode,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) -> Task<()> {
|
||||
workspace.activate_pane(pane.clone(), cx);
|
||||
|
||||
let to_load = pane.update(cx, |pane, cx| {
|
||||
// Retrieve the weak item handle from the history.
|
||||
let entry = pane.nav_history.borrow_mut().pop(mode)?;
|
||||
@ -634,19 +644,33 @@ impl View for Pane {
|
||||
}
|
||||
|
||||
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
|
||||
if let Some(active_item) = self.active_item() {
|
||||
Flex::column()
|
||||
.with_child(self.render_tabs(cx))
|
||||
.with_children(
|
||||
self.active_toolbar()
|
||||
.as_ref()
|
||||
.map(|view| ChildView::new(view).boxed()),
|
||||
)
|
||||
.with_child(ChildView::new(active_item).flexible(1., true).boxed())
|
||||
.named("pane")
|
||||
} else {
|
||||
Empty::new().named("pane")
|
||||
}
|
||||
let this = cx.handle();
|
||||
|
||||
EventHandler::new(
|
||||
if let Some(active_item) = self.active_item() {
|
||||
Flex::column()
|
||||
.with_child(self.render_tabs(cx))
|
||||
.with_children(
|
||||
self.active_toolbar()
|
||||
.as_ref()
|
||||
.map(|view| ChildView::new(view).boxed()),
|
||||
)
|
||||
.with_child(ChildView::new(active_item).flexible(1., true).boxed())
|
||||
.boxed()
|
||||
} else {
|
||||
Empty::new().boxed()
|
||||
}
|
||||
)
|
||||
.on_other_mouse_down(move |button, cx| {
|
||||
match button {
|
||||
3 => cx.dispatch_action(GoBack(Some(this.clone()))),
|
||||
4 => cx.dispatch_action(GoForward(Some(this.clone()))),
|
||||
_ => return false,
|
||||
};
|
||||
true
|
||||
})
|
||||
.named("pane")
|
||||
|
||||
}
|
||||
|
||||
fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
|
||||
|
@ -747,44 +747,44 @@ mod tests {
|
||||
(file3.clone(), DisplayPoint::new(15, 0))
|
||||
);
|
||||
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, cx)).await;
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, None, cx)).await;
|
||||
assert_eq!(
|
||||
active_location(&workspace, cx),
|
||||
(file3.clone(), DisplayPoint::new(0, 0))
|
||||
);
|
||||
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, cx)).await;
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, None, cx)).await;
|
||||
assert_eq!(
|
||||
active_location(&workspace, cx),
|
||||
(file2.clone(), DisplayPoint::new(0, 0))
|
||||
);
|
||||
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, cx)).await;
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, None, cx)).await;
|
||||
assert_eq!(
|
||||
active_location(&workspace, cx),
|
||||
(file1.clone(), DisplayPoint::new(10, 0))
|
||||
);
|
||||
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, cx)).await;
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, None, cx)).await;
|
||||
assert_eq!(
|
||||
active_location(&workspace, cx),
|
||||
(file1.clone(), DisplayPoint::new(0, 0))
|
||||
);
|
||||
|
||||
// Go back one more time and ensure we don't navigate past the first item in the history.
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, cx)).await;
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, None, cx)).await;
|
||||
assert_eq!(
|
||||
active_location(&workspace, cx),
|
||||
(file1.clone(), DisplayPoint::new(0, 0))
|
||||
);
|
||||
|
||||
workspace.update(cx, |w, cx| Pane::go_forward(w, cx)).await;
|
||||
workspace.update(cx, |w, cx| Pane::go_forward(w, None, cx)).await;
|
||||
assert_eq!(
|
||||
active_location(&workspace, cx),
|
||||
(file1.clone(), DisplayPoint::new(10, 0))
|
||||
);
|
||||
|
||||
workspace.update(cx, |w, cx| Pane::go_forward(w, cx)).await;
|
||||
workspace.update(cx, |w, cx| Pane::go_forward(w, None, cx)).await;
|
||||
assert_eq!(
|
||||
active_location(&workspace, cx),
|
||||
(file2.clone(), DisplayPoint::new(0, 0))
|
||||
@ -798,7 +798,7 @@ mod tests {
|
||||
.update(cx, |pane, cx| pane.close_item(editor3.id(), cx));
|
||||
drop(editor3);
|
||||
});
|
||||
workspace.update(cx, |w, cx| Pane::go_forward(w, cx)).await;
|
||||
workspace.update(cx, |w, cx| Pane::go_forward(w, None, cx)).await;
|
||||
assert_eq!(
|
||||
active_location(&workspace, cx),
|
||||
(file3.clone(), DisplayPoint::new(0, 0))
|
||||
@ -818,12 +818,12 @@ mod tests {
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, cx)).await;
|
||||
workspace.update(cx, |w, cx| Pane::go_back(w, None, cx)).await;
|
||||
assert_eq!(
|
||||
active_location(&workspace, cx),
|
||||
(file1.clone(), DisplayPoint::new(10, 0))
|
||||
);
|
||||
workspace.update(cx, |w, cx| Pane::go_forward(w, cx)).await;
|
||||
workspace.update(cx, |w, cx| Pane::go_forward(w, None, cx)).await;
|
||||
assert_eq!(
|
||||
active_location(&workspace, cx),
|
||||
(file3.clone(), DisplayPoint::new(0, 0))
|
||||
|
Loading…
Reference in New Issue
Block a user