diff --git a/crates/chat_panel/src/chat_panel.rs b/crates/chat_panel/src/chat_panel.rs index 0c22c21c71..ccd33db3ab 100644 --- a/crates/chat_panel/src/chat_panel.rs +++ b/crates/chat_panel/src/chat_panel.rs @@ -397,7 +397,7 @@ impl View for ChatPanel { .boxed() } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if matches!( *self.rpc.status().borrow(), client::Status::Connected { .. } diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 702d8a9121..1279d30437 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -526,18 +526,6 @@ impl Element for AvatarRibbon { cx.scene.push_path(path.build(self.color, None)); } - fn dispatch_event( - &mut self, - _: &gpui::Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - _: &mut gpui::EventContext, - ) -> bool { - false - } - fn rect_for_text_range( &self, _: Range, diff --git a/crates/collab_ui/src/contact_finder.rs b/crates/collab_ui/src/contact_finder.rs index a4ec02d2f0..5165c3b1f6 100644 --- a/crates/collab_ui/src/contact_finder.rs +++ b/crates/collab_ui/src/contact_finder.rs @@ -36,7 +36,7 @@ impl View for ContactFinder { ChildView::new(self.picker.clone(), cx).boxed() } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { cx.focus(&self.picker); } diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index cf8a8f8223..7a51cc83ec 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -1121,13 +1121,13 @@ impl View for ContactList { .boxed() } - fn on_focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext) { if !self.filter_editor.is_focused(cx) { cx.focus(&self.filter_editor); } } - fn on_focus_out(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext) { + fn focus_out(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext) { if !self.filter_editor.is_focused(cx) { cx.emit(Event::Dismissed); } diff --git a/crates/collab_ui/src/contacts_popover.rs b/crates/collab_ui/src/contacts_popover.rs index 075255d727..37280f929e 100644 --- a/crates/collab_ui/src/contacts_popover.rs +++ b/crates/collab_ui/src/contacts_popover.rs @@ -160,7 +160,7 @@ impl View for ContactsPopover { .boxed() } - fn on_focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { match &self.child { Child::ContactList(child) => cx.focus(child), diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index 7702aaaf2a..51474be1be 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -135,7 +135,7 @@ impl View for CommandPalette { ChildView::new(self.picker.clone(), cx).boxed() } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { cx.focus(&self.picker); } diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index 5fbc2b9875..96d99f5109 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -107,7 +107,7 @@ impl View for ContextMenu { .boxed() } - fn on_focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { self.reset(cx); } } diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 8180a6c9f6..4409fa17ad 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -99,7 +99,7 @@ impl View for ProjectDiagnosticsEditor { } } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if !self.path_states.is_empty() { cx.focus(&self.editor); } diff --git a/crates/drag_and_drop/src/drag_and_drop.rs b/crates/drag_and_drop/src/drag_and_drop.rs index 7a16acae07..31265a1697 100644 --- a/crates/drag_and_drop/src/drag_and_drop.rs +++ b/crates/drag_and_drop/src/drag_and_drop.rs @@ -4,7 +4,7 @@ use collections::HashSet; use gpui::{ elements::{MouseEventHandler, Overlay}, geometry::vector::Vector2F, - scene::DragRegionEvent, + scene::MouseDrag, CursorStyle, Element, ElementBox, EventContext, MouseButton, MutableAppContext, RenderContext, View, WeakViewHandle, }; @@ -70,7 +70,7 @@ impl DragAndDrop { } pub fn dragging( - event: DragRegionEvent, + event: MouseDrag, payload: Rc, cx: &mut EventContext, render: Rc) -> ElementBox>, diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index f3edee1a9e..07fc965542 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -48,7 +48,9 @@ use language::{ Diagnostic, DiagnosticSeverity, IndentKind, IndentSize, Language, OffsetRangeExt, OffsetUtf16, Point, Selection, SelectionGoal, TransactionId, }; -use link_go_to_definition::{hide_link_definition, LinkGoToDefinitionState}; +use link_go_to_definition::{ + hide_link_definition, show_link_definition, LinkDefinitionKind, LinkGoToDefinitionState, +}; pub use multi_buffer::{ Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint, @@ -6425,7 +6427,7 @@ impl View for Editor { "Editor" } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { let focused_event = EditorFocused(cx.handle()); cx.emit_global(focused_event); if let Some(rename) = self.pending_rename.as_ref() { @@ -6447,7 +6449,7 @@ impl View for Editor { } } - fn on_focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { let blurred_event = EditorBlurred(cx.handle()); cx.emit_global(blurred_event); self.focused = false; @@ -6460,6 +6462,44 @@ impl View for Editor { cx.notify(); } + fn modifiers_changed( + &mut self, + event: &gpui::ModifiersChangedEvent, + cx: &mut ViewContext, + ) -> bool { + let pending_selection = self.has_pending_selection(); + + if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() { + if event.cmd && !pending_selection { + let snapshot = self.snapshot(cx); + let kind = if event.shift { + LinkDefinitionKind::Type + } else { + LinkDefinitionKind::Symbol + }; + + show_link_definition(kind, self, point, snapshot, cx); + return false; + } + } + + { + if self.link_go_to_definition_state.symbol_range.is_some() + || !self.link_go_to_definition_state.definitions.is_empty() + { + self.link_go_to_definition_state.symbol_range.take(); + self.link_go_to_definition_state.definitions.clear(); + cx.notify(); + } + + self.link_go_to_definition_state.task = None; + + self.clear_text_highlights::(cx); + } + + false + } + fn keymap_context(&self, _: &AppContext) -> gpui::keymap::Context { let mut context = Self::default_keymap_context(); let mode = match self.mode { diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index ba84559e5e..d18c168fde 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -9,7 +9,7 @@ use crate::{ HoverAt, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT, }, link_go_to_definition::{ - CmdShiftChanged, GoToFetchedDefinition, GoToFetchedTypeDefinition, UpdateGoToDefinitionLink, + GoToFetchedDefinition, GoToFetchedTypeDefinition, UpdateGoToDefinitionLink, }, mouse_context_menu::DeployMouseContextMenu, AnchorRangeExt, EditorStyle, @@ -29,10 +29,9 @@ use gpui::{ json::{self, ToJson}, platform::CursorStyle, text_layout::{self, Line, RunStyle, TextLayoutCache}, - AppContext, Axis, Border, CursorRegion, Element, ElementBox, Event, EventContext, - LayoutContext, ModifiersChangedEvent, MouseButton, MouseButtonEvent, MouseMovedEvent, - MouseRegion, MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, - WeakViewHandle, + AppContext, Axis, Border, CursorRegion, Element, ElementBox, EventContext, LayoutContext, + MouseButton, MouseButtonEvent, MouseMovedEvent, MouseRegion, MutableAppContext, PaintContext, + Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle, }; use json::json; use language::{Bias, CursorShape, DiagnosticSeverity, OffsetUtf16, Point, Selection}; @@ -412,14 +411,6 @@ impl EditorElement { true } - fn modifiers_changed(&self, event: ModifiersChangedEvent, cx: &mut EventContext) -> bool { - cx.dispatch_action(CmdShiftChanged { - cmd_down: event.cmd, - shift_down: event.shift, - }); - false - } - fn scroll( position: Vector2F, mut delta: Vector2F, @@ -1930,22 +1921,6 @@ impl Element for EditorElement { cx.scene.pop_layer(); } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - _: &mut LayoutState, - _: &mut (), - cx: &mut EventContext, - ) -> bool { - if let Event::ModifiersChanged(event) = event { - self.modifiers_changed(*event, cx); - } - - false - } - fn rect_for_text_range( &self, range_utf16: Range, diff --git a/crates/editor/src/link_go_to_definition.rs b/crates/editor/src/link_go_to_definition.rs index c8294ddb43..705a1b2760 100644 --- a/crates/editor/src/link_go_to_definition.rs +++ b/crates/editor/src/link_go_to_definition.rs @@ -19,12 +19,6 @@ pub struct UpdateGoToDefinitionLink { pub shift_held: bool, } -#[derive(Clone, PartialEq)] -pub struct CmdShiftChanged { - pub cmd_down: bool, - pub shift_down: bool, -} - #[derive(Clone, PartialEq)] pub struct GoToFetchedDefinition { pub point: DisplayPoint, @@ -39,7 +33,6 @@ impl_internal_actions!( editor, [ UpdateGoToDefinitionLink, - CmdShiftChanged, GoToFetchedDefinition, GoToFetchedTypeDefinition ] @@ -47,7 +40,6 @@ impl_internal_actions!( pub fn init(cx: &mut MutableAppContext) { cx.add_action(update_go_to_definition_link); - cx.add_action(cmd_shift_changed); cx.add_action(go_to_fetched_definition); cx.add_action(go_to_fetched_type_definition); } @@ -113,37 +105,6 @@ pub fn update_go_to_definition_link( hide_link_definition(editor, cx); } -pub fn cmd_shift_changed( - editor: &mut Editor, - &CmdShiftChanged { - cmd_down, - shift_down, - }: &CmdShiftChanged, - cx: &mut ViewContext, -) { - let pending_selection = editor.has_pending_selection(); - - if let Some(point) = editor - .link_go_to_definition_state - .last_mouse_location - .clone() - { - if cmd_down && !pending_selection { - let snapshot = editor.snapshot(cx); - let kind = if shift_down { - LinkDefinitionKind::Type - } else { - LinkDefinitionKind::Symbol - }; - - show_link_definition(kind, editor, point, snapshot, cx); - return; - } - } - - hide_link_definition(editor, cx) -} - #[derive(Debug, Clone, Copy, PartialEq)] pub enum LinkDefinitionKind { Symbol, @@ -397,6 +358,7 @@ fn go_to_fetched_definition_of_kind( #[cfg(test)] mod tests { use futures::StreamExt; + use gpui::{ModifiersChangedEvent, View}; use indoc::indoc; use lsp::request::{GotoDefinition, GotoTypeDefinition}; @@ -467,11 +429,10 @@ mod tests { // Unpress shift causes highlight to go away (normal goto-definition is not valid here) cx.update_editor(|editor, cx| { - cmd_shift_changed( - editor, - &CmdShiftChanged { - cmd_down: true, - shift_down: false, + editor.modifiers_changed( + &gpui::ModifiersChangedEvent { + cmd: true, + ..Default::default() }, cx, ); @@ -581,14 +542,7 @@ mod tests { // Unpress cmd causes highlight to go away cx.update_editor(|editor, cx| { - cmd_shift_changed( - editor, - &CmdShiftChanged { - cmd_down: false, - shift_down: false, - }, - cx, - ); + editor.modifiers_changed(&Default::default(), cx); }); // Assert no link highlights @@ -704,11 +658,10 @@ mod tests { ]))) }); cx.update_editor(|editor, cx| { - cmd_shift_changed( - editor, - &CmdShiftChanged { - cmd_down: true, - shift_down: false, + editor.modifiers_changed( + &ModifiersChangedEvent { + cmd: true, + ..Default::default() }, cx, ); diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index e787e3c1a6..1a82613b84 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -53,7 +53,7 @@ impl View for FileFinder { ChildView::new(self.picker.clone(), cx).boxed() } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { cx.focus(&self.picker); } diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index eddb014b63..ad1dacf743 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -183,7 +183,7 @@ impl View for GoToLine { .named("go to line") } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { cx.focus(&self.line_editor); } } diff --git a/crates/gpui/examples/text.rs b/crates/gpui/examples/text.rs index d4e873f039..4d84fefab6 100644 --- a/crates/gpui/examples/text.rs +++ b/crates/gpui/examples/text.rs @@ -101,18 +101,6 @@ impl gpui::Element for TextElement { line.paint(bounds.origin(), visible_bounds, bounds.height(), cx); } - fn dispatch_event( - &mut self, - _: &gpui::Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - _: &mut gpui::EventContext, - ) -> bool { - false - } - fn rect_for_text_range( &self, _: Range, diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index a9529f3f9f..a9020cf350 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -41,8 +41,8 @@ use crate::{ platform::{self, KeyDownEvent, Platform, PromptLevel, WindowOptions}, presenter::Presenter, util::post_inc, - Appearance, AssetCache, AssetSource, ClipboardItem, FontCache, InputHandler, MouseButton, - MouseRegionId, PathPromptOptions, TextLayoutCache, + Appearance, AssetCache, AssetSource, ClipboardItem, FontCache, InputHandler, KeyUpEvent, + ModifiersChangedEvent, MouseButton, MouseRegionId, PathPromptOptions, TextLayoutCache, }; pub trait Entity: 'static { @@ -60,8 +60,18 @@ pub trait Entity: 'static { pub trait View: Entity + Sized { fn ui_name() -> &'static str; fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox; - fn on_focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext) {} - fn on_focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext) {} + fn focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext) {} + fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext) {} + fn key_down(&mut self, _: &KeyDownEvent, _: &mut ViewContext) -> bool { + false + } + fn key_up(&mut self, _: &KeyUpEvent, _: &mut ViewContext) -> bool { + false + } + fn modifiers_changed(&mut self, _: &ModifiersChangedEvent, _: &mut ViewContext) -> bool { + false + } + fn keymap_context(&self, _: &AppContext) -> keymap::Context { Self::default_keymap_context() } @@ -1297,7 +1307,7 @@ impl MutableAppContext { ) -> impl Iterator, SmallVec<[&Binding; 1]>)> { let mut action_types: HashSet<_> = self.global_actions.keys().copied().collect(); - for view_id in self.parents(window_id, view_id) { + for view_id in self.ancestors(window_id, view_id) { if let Some(view) = self.views.get(&(window_id, view_id)) { let view_type = view.as_any().type_id(); if let Some(actions) = self.actions.get(&view_type) { @@ -1327,7 +1337,7 @@ impl MutableAppContext { let action_type = action.as_any().type_id(); if let Some(window_id) = self.cx.platform.key_window_id() { if let Some(focused_view_id) = self.focused_view_id(window_id) { - for view_id in self.parents(window_id, focused_view_id) { + for view_id in self.ancestors(window_id, focused_view_id) { if let Some(view) = self.views.get(&(window_id, view_id)) { let view_type = view.as_any().type_id(); if let Some(actions) = self.actions.get(&view_type) { @@ -1376,7 +1386,7 @@ impl MutableAppContext { mut visit: impl FnMut(usize, bool, &mut MutableAppContext) -> bool, ) -> bool { // List of view ids from the leaf to the root of the window - let path = self.parents(window_id, view_id).collect::>(); + let path = self.ancestors(window_id, view_id).collect::>(); // Walk down from the root to the leaf calling visit with capture_phase = true for view_id in path.iter().rev() { @@ -1397,7 +1407,7 @@ impl MutableAppContext { // Returns an iterator over all of the view ids from the passed view up to the root of the window // Includes the passed view itself - fn parents(&self, window_id: usize, mut view_id: usize) -> impl Iterator + '_ { + fn ancestors(&self, window_id: usize, mut view_id: usize) -> impl Iterator + '_ { std::iter::once(view_id) .into_iter() .chain(std::iter::from_fn(move || { @@ -1445,11 +1455,81 @@ impl MutableAppContext { self.keystroke_matcher.clear_bindings(); } + pub fn dispatch_key_down(&mut self, window_id: usize, event: &KeyDownEvent) -> bool { + if let Some(focused_view_id) = self.focused_view_id(window_id) { + for view_id in self + .ancestors(window_id, focused_view_id) + .collect::>() + { + if let Some(mut view) = self.cx.views.remove(&(window_id, view_id)) { + let handled = view.key_down(event, self, window_id, view_id); + self.cx.views.insert((window_id, view_id), view); + if handled { + return true; + } + } else { + log::error!("view {} does not exist", view_id) + } + } + } + + false + } + + pub fn dispatch_key_up(&mut self, window_id: usize, event: &KeyUpEvent) -> bool { + if let Some(focused_view_id) = self.focused_view_id(window_id) { + for view_id in self + .ancestors(window_id, focused_view_id) + .collect::>() + { + if let Some(mut view) = self.cx.views.remove(&(window_id, view_id)) { + let handled = view.key_up(event, self, window_id, view_id); + self.cx.views.insert((window_id, view_id), view); + if handled { + return true; + } + } else { + log::error!("view {} does not exist", view_id) + } + } + } + + false + } + + pub fn dispatch_modifiers_changed( + &mut self, + window_id: usize, + event: &ModifiersChangedEvent, + ) -> bool { + if let Some(focused_view_id) = self.focused_view_id(window_id) { + for view_id in self + .ancestors(window_id, focused_view_id) + .collect::>() + { + if let Some(mut view) = self.cx.views.remove(&(window_id, view_id)) { + let handled = view.modifiers_changed(event, self, window_id, view_id); + self.cx.views.insert((window_id, view_id), view); + if handled { + return true; + } + } else { + log::error!("view {} does not exist", view_id) + } + } + } + + false + } + pub fn dispatch_keystroke(&mut self, window_id: usize, keystroke: &Keystroke) -> bool { let mut pending = false; if let Some(focused_view_id) = self.focused_view_id(window_id) { - for view_id in self.parents(window_id, focused_view_id).collect::>() { + for view_id in self + .ancestors(window_id, focused_view_id) + .collect::>() + { let keymap_context = self .cx .views @@ -1580,7 +1660,7 @@ impl MutableAppContext { is_fullscreen: false, }, ); - root_view.update(this, |view, cx| view.on_focus_in(cx.handle().into(), cx)); + root_view.update(this, |view, cx| view.focus_in(cx.handle().into(), cx)); let window = this.cx @@ -1612,7 +1692,7 @@ impl MutableAppContext { is_fullscreen: false, }, ); - root_view.update(this, |view, cx| view.on_focus_in(cx.handle().into(), cx)); + root_view.update(this, |view, cx| view.focus_in(cx.handle().into(), cx)); let status_item = this.cx.platform.add_status_item(); this.register_platform_window(window_id, status_item); @@ -2235,12 +2315,12 @@ impl MutableAppContext { //Handle focus let focused_id = window.focused_view_id?; - for view_id in this.parents(window_id, focused_id).collect::>() { + for view_id in this.ancestors(window_id, focused_id).collect::>() { if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) { if active { - view.on_focus_in(this, window_id, view_id, focused_id); + view.focus_in(this, window_id, view_id, focused_id); } else { - view.on_focus_out(this, window_id, view_id, focused_id); + view.focus_out(this, window_id, view_id, focused_id); } this.cx.views.insert((window_id, view_id), view); } @@ -2272,16 +2352,16 @@ impl MutableAppContext { }); let blurred_parents = blurred_id - .map(|blurred_id| this.parents(window_id, blurred_id).collect::>()) + .map(|blurred_id| this.ancestors(window_id, blurred_id).collect::>()) .unwrap_or_default(); let focused_parents = focused_id - .map(|focused_id| this.parents(window_id, focused_id).collect::>()) + .map(|focused_id| this.ancestors(window_id, focused_id).collect::>()) .unwrap_or_default(); if let Some(blurred_id) = blurred_id { for view_id in blurred_parents.iter().copied() { if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) { - view.on_focus_out(this, window_id, view_id, blurred_id); + view.focus_out(this, window_id, view_id, blurred_id); this.cx.views.insert((window_id, view_id), view); } } @@ -2294,7 +2374,7 @@ impl MutableAppContext { if let Some(focused_id) = focused_id { for view_id in focused_parents { if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) { - view.on_focus_in(this, window_id, view_id, focused_id); + view.focus_in(this, window_id, view_id, focused_id); this.cx.views.insert((window_id, view_id), view); } } @@ -2961,20 +3041,41 @@ pub trait AnyView { ) -> Option>>>; fn ui_name(&self) -> &'static str; fn render(&mut self, params: RenderParams, cx: &mut MutableAppContext) -> ElementBox; - fn on_focus_in( + fn focus_in( &mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize, focused_id: usize, ); - fn on_focus_out( + fn focus_out( &mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize, focused_id: usize, ); + fn key_down( + &mut self, + event: &KeyDownEvent, + cx: &mut MutableAppContext, + window_id: usize, + view_id: usize, + ) -> bool; + fn key_up( + &mut self, + event: &KeyUpEvent, + cx: &mut MutableAppContext, + window_id: usize, + view_id: usize, + ) -> bool; + fn modifiers_changed( + &mut self, + event: &ModifiersChangedEvent, + cx: &mut MutableAppContext, + window_id: usize, + view_id: usize, + ) -> bool; fn keymap_context(&self, cx: &AppContext) -> keymap::Context; fn debug_json(&self, cx: &AppContext) -> serde_json::Value; @@ -3040,7 +3141,7 @@ where View::render(self, &mut RenderContext::new(params, cx)) } - fn on_focus_in( + fn focus_in( &mut self, cx: &mut MutableAppContext, window_id: usize, @@ -3059,10 +3160,10 @@ where .type_id(); AnyViewHandle::new(window_id, focused_id, focused_type, cx.ref_counts.clone()) }; - View::on_focus_in(self, focused_view_handle, &mut cx); + View::focus_in(self, focused_view_handle, &mut cx); } - fn on_focus_out( + fn focus_out( &mut self, cx: &mut MutableAppContext, window_id: usize, @@ -3081,7 +3182,40 @@ where .type_id(); AnyViewHandle::new(window_id, blurred_id, blurred_type, cx.ref_counts.clone()) }; - View::on_focus_out(self, blurred_view_handle, &mut cx); + View::focus_out(self, blurred_view_handle, &mut cx); + } + + fn key_down( + &mut self, + event: &KeyDownEvent, + cx: &mut MutableAppContext, + window_id: usize, + view_id: usize, + ) -> bool { + let mut cx = ViewContext::new(cx, window_id, view_id); + View::key_down(self, event, &mut cx) + } + + fn key_up( + &mut self, + event: &KeyUpEvent, + cx: &mut MutableAppContext, + window_id: usize, + view_id: usize, + ) -> bool { + let mut cx = ViewContext::new(cx, window_id, view_id); + View::key_up(self, event, &mut cx) + } + + fn modifiers_changed( + &mut self, + event: &ModifiersChangedEvent, + cx: &mut MutableAppContext, + window_id: usize, + view_id: usize, + ) -> bool { + let mut cx = ViewContext::new(cx, window_id, view_id); + View::modifiers_changed(self, event, &mut cx) } fn keymap_context(&self, cx: &AppContext) -> keymap::Context { @@ -3463,7 +3597,7 @@ impl<'a, T: View> ViewContext<'a, T> { if self.window_id != view.window_id { return false; } - self.parents(view.window_id, view.view_id) + self.ancestors(view.window_id, view.view_id) .any(|parent| parent == self.view_id) } @@ -6354,13 +6488,13 @@ mod tests { "View" } - fn on_focus_in(&mut self, focused: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, focused: AnyViewHandle, cx: &mut ViewContext) { if cx.handle().id() == focused.id() { self.events.lock().push(format!("{} focused", &self.name)); } } - fn on_focus_out(&mut self, blurred: AnyViewHandle, cx: &mut ViewContext) { + fn focus_out(&mut self, blurred: AnyViewHandle, cx: &mut ViewContext) { if cx.handle().id() == blurred.id() { self.events.lock().push(format!("{} blurred", &self.name)); } diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index 59269f8af6..a648df6095 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -33,8 +33,8 @@ use crate::{ }, json, presenter::MeasurementContext, - Action, DebugContext, Event, EventContext, LayoutContext, PaintContext, RenderContext, - SizeConstraint, View, + Action, DebugContext, EventContext, LayoutContext, PaintContext, RenderContext, SizeConstraint, + View, }; use core::panic; use json::ToJson; @@ -50,7 +50,6 @@ use std::{ trait AnyElement { fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F; fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext); - fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool; fn rect_for_text_range( &self, range_utf16: Range, @@ -80,16 +79,6 @@ pub trait Element { cx: &mut PaintContext, ) -> Self::PaintState; - fn dispatch_event( - &mut self, - event: &Event, - bounds: RectF, - visible_bounds: RectF, - layout: &mut Self::LayoutState, - paint: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool; - fn rect_for_text_range( &self, range_utf16: Range, @@ -303,22 +292,6 @@ impl AnyElement for Lifecycle { } } - fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool { - if let Lifecycle::PostPaint { - element, - bounds, - visible_bounds, - layout, - paint, - .. - } = self - { - element.dispatch_event(event, *bounds, *visible_bounds, layout, paint, cx) - } else { - panic!("invalid element lifecycle state"); - } - } - fn rect_for_text_range( &self, range_utf16: Range, @@ -433,10 +406,6 @@ impl ElementRc { self.element.borrow_mut().paint(origin, visible_bounds, cx); } - pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool { - self.element.borrow_mut().dispatch_event(event, cx) - } - pub fn rect_for_text_range( &self, range_utf16: Range, diff --git a/crates/gpui/src/elements/align.rs b/crates/gpui/src/elements/align.rs index 5158b7229e..ec1a210f75 100644 --- a/crates/gpui/src/elements/align.rs +++ b/crates/gpui/src/elements/align.rs @@ -2,8 +2,7 @@ use crate::{ geometry::{rect::RectF, vector::Vector2F}, json, presenter::MeasurementContext, - DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, - SizeConstraint, + DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; use json::ToJson; @@ -84,18 +83,6 @@ impl Element for Align { ); } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - self.child.dispatch_event(event, cx) - } - fn rect_for_text_range( &self, range_utf16: std::ops::Range, diff --git a/crates/gpui/src/elements/canvas.rs b/crates/gpui/src/elements/canvas.rs index 6fec2dd1dc..31c56bb987 100644 --- a/crates/gpui/src/elements/canvas.rs +++ b/crates/gpui/src/elements/canvas.rs @@ -56,18 +56,6 @@ where self.0(bounds, visible_bounds, cx) } - fn dispatch_event( - &mut self, - _: &crate::Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - _: &mut crate::EventContext, - ) -> bool { - false - } - fn rect_for_text_range( &self, _: std::ops::Range, diff --git a/crates/gpui/src/elements/constrained_box.rs b/crates/gpui/src/elements/constrained_box.rs index 012bbe23dd..2e232c6197 100644 --- a/crates/gpui/src/elements/constrained_box.rs +++ b/crates/gpui/src/elements/constrained_box.rs @@ -7,8 +7,7 @@ use crate::{ geometry::{rect::RectF, vector::Vector2F}, json, presenter::MeasurementContext, - DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, - SizeConstraint, + DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; pub struct ConstrainedBox { @@ -157,18 +156,6 @@ impl Element for ConstrainedBox { self.child.paint(bounds.origin(), visible_bounds, cx); } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - self.child.dispatch_event(event, cx) - } - fn rect_for_text_range( &self, range_utf16: Range, diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index dc0d0bac1b..8e17fdd60f 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -11,7 +11,7 @@ use crate::{ platform::CursorStyle, presenter::MeasurementContext, scene::{self, Border, CursorRegion, Quad}, - Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, SizeConstraint, + Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; use serde::Deserialize; use serde_json::json; @@ -285,18 +285,6 @@ impl Element for Container { } } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - self.child.dispatch_event(event, cx) - } - fn rect_for_text_range( &self, range_utf16: Range, diff --git a/crates/gpui/src/elements/empty.rs b/crates/gpui/src/elements/empty.rs index a7c2fc1d60..b0a0481c05 100644 --- a/crates/gpui/src/elements/empty.rs +++ b/crates/gpui/src/elements/empty.rs @@ -9,7 +9,7 @@ use crate::{ presenter::MeasurementContext, DebugContext, }; -use crate::{Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint}; +use crate::{Element, LayoutContext, PaintContext, SizeConstraint}; #[derive(Default)] pub struct Empty { @@ -59,18 +59,6 @@ impl Element for Empty { ) -> Self::PaintState { } - fn dispatch_event( - &mut self, - _: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - _: &mut EventContext, - ) -> bool { - false - } - fn rect_for_text_range( &self, _: Range, diff --git a/crates/gpui/src/elements/expanded.rs b/crates/gpui/src/elements/expanded.rs index d77bbdbfb9..89e9c7c7d8 100644 --- a/crates/gpui/src/elements/expanded.rs +++ b/crates/gpui/src/elements/expanded.rs @@ -4,8 +4,7 @@ use crate::{ geometry::{rect::RectF, vector::Vector2F}, json, presenter::MeasurementContext, - DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, - SizeConstraint, + DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; use serde_json::json; @@ -66,18 +65,6 @@ impl Element for Expanded { self.child.paint(bounds.origin(), visible_bounds, cx); } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - self.child.dispatch_event(event, cx) - } - fn rect_for_text_range( &self, range_utf16: Range, diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index 1f1941a3d0..95477c7560 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -3,8 +3,8 @@ use std::{any::Any, cell::Cell, f32::INFINITY, ops::Range, rc::Rc}; use crate::{ json::{self, ToJson, Value}, presenter::MeasurementContext, - Axis, DebugContext, Element, ElementBox, ElementStateHandle, Event, EventContext, - LayoutContext, PaintContext, RenderContext, SizeConstraint, Vector2FExt, View, + Axis, DebugContext, Element, ElementBox, ElementStateHandle, LayoutContext, PaintContext, + RenderContext, SizeConstraint, Vector2FExt, View, }; use pathfinder_geometry::{ rect::RectF, @@ -318,23 +318,6 @@ impl Element for Flex { } } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - let mut handled = false; - for child in &mut self.children { - handled = child.dispatch_event(event, cx) || handled; - } - - handled - } - fn rect_for_text_range( &self, range_utf16: Range, @@ -420,18 +403,6 @@ impl Element for FlexItem { self.child.paint(bounds.origin(), visible_bounds, cx) } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - self.child.dispatch_event(event, cx) - } - fn rect_for_text_range( &self, range_utf16: Range, diff --git a/crates/gpui/src/elements/hook.rs b/crates/gpui/src/elements/hook.rs index c620847372..b77fef4fae 100644 --- a/crates/gpui/src/elements/hook.rs +++ b/crates/gpui/src/elements/hook.rs @@ -4,8 +4,7 @@ use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::json, presenter::MeasurementContext, - DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, - SizeConstraint, + DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; pub struct Hook { @@ -56,18 +55,6 @@ impl Element for Hook { self.child.paint(bounds.origin(), visible_bounds, cx); } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - self.child.dispatch_event(event, cx) - } - fn rect_for_text_range( &self, range_utf16: Range, diff --git a/crates/gpui/src/elements/image.rs b/crates/gpui/src/elements/image.rs index 7e231e5e29..37cb01ace8 100644 --- a/crates/gpui/src/elements/image.rs +++ b/crates/gpui/src/elements/image.rs @@ -6,8 +6,7 @@ use crate::{ }, json::{json, ToJson}, presenter::MeasurementContext, - scene, Border, DebugContext, Element, Event, EventContext, ImageData, LayoutContext, - PaintContext, SizeConstraint, + scene, Border, DebugContext, Element, ImageData, LayoutContext, PaintContext, SizeConstraint, }; use serde::Deserialize; use std::{ops::Range, sync::Arc}; @@ -81,18 +80,6 @@ impl Element for Image { }); } - fn dispatch_event( - &mut self, - _: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - _: &mut EventContext, - ) -> bool { - false - } - fn rect_for_text_range( &self, _: Range, diff --git a/crates/gpui/src/elements/keystroke_label.rs b/crates/gpui/src/elements/keystroke_label.rs index 9b21a1b8a8..ca317d9e11 100644 --- a/crates/gpui/src/elements/keystroke_label.rs +++ b/crates/gpui/src/elements/keystroke_label.rs @@ -2,7 +2,7 @@ use crate::{ elements::*, fonts::TextStyle, geometry::{rect::RectF, vector::Vector2F}, - Action, ElementBox, Event, EventContext, LayoutContext, PaintContext, SizeConstraint, + Action, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; use serde_json::json; @@ -64,18 +64,6 @@ impl Element for KeystrokeLabel { element.paint(bounds.origin(), visible_bounds, cx); } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - element: &mut ElementBox, - _: &mut (), - cx: &mut EventContext, - ) -> bool { - element.dispatch_event(event, cx) - } - fn rect_for_text_range( &self, _: Range, diff --git a/crates/gpui/src/elements/label.rs b/crates/gpui/src/elements/label.rs index 1865480868..605a3cb767 100644 --- a/crates/gpui/src/elements/label.rs +++ b/crates/gpui/src/elements/label.rs @@ -9,7 +9,7 @@ use crate::{ json::{ToJson, Value}, presenter::MeasurementContext, text_layout::{Line, RunStyle}, - DebugContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint, + DebugContext, Element, LayoutContext, PaintContext, SizeConstraint, }; use serde::Deserialize; use serde_json::json; @@ -165,18 +165,6 @@ impl Element for Label { line.paint(bounds.origin(), visible_bounds, bounds.size().y(), cx) } - fn dispatch_event( - &mut self, - _: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - _: &mut EventContext, - ) -> bool { - false - } - fn rect_for_text_range( &self, _: Range, diff --git a/crates/gpui/src/elements/list.rs b/crates/gpui/src/elements/list.rs index d0f87590fc..a1b4ef0c79 100644 --- a/crates/gpui/src/elements/list.rs +++ b/crates/gpui/src/elements/list.rs @@ -5,7 +5,7 @@ use crate::{ }, json::json, presenter::MeasurementContext, - DebugContext, Element, ElementBox, ElementRc, Event, EventContext, LayoutContext, MouseRegion, + DebugContext, Element, ElementBox, ElementRc, EventContext, LayoutContext, MouseRegion, PaintContext, RenderContext, SizeConstraint, View, ViewContext, }; use std::{cell::RefCell, collections::VecDeque, ops::Range, rc::Rc}; @@ -13,7 +13,6 @@ use sum_tree::{Bias, SumTree}; pub struct List { state: ListState, - invalidated_elements: Vec, } #[derive(Clone)] @@ -82,10 +81,7 @@ struct Height(f32); impl List { pub fn new(state: ListState) -> Self { - Self { - state, - invalidated_elements: Default::default(), - } + Self { state } } } @@ -289,50 +285,6 @@ impl Element for List { cx.scene.pop_layer(); } - fn dispatch_event( - &mut self, - event: &Event, - bounds: RectF, - _: RectF, - scroll_top: &mut ListOffset, - _: &mut (), - cx: &mut EventContext, - ) -> bool { - let mut handled = false; - - let mut state = self.state.0.borrow_mut(); - let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item); - let mut cursor = state.items.cursor::(); - let mut new_items = cursor.slice(&Count(scroll_top.item_ix), Bias::Right, &()); - while let Some(item) = cursor.item() { - if item_origin.y() > bounds.max_y() { - break; - } - - if let ListItem::Rendered(element) = item { - let prev_notify_count = cx.notify_count(); - let mut element = element.clone(); - handled = element.dispatch_event(event, cx) || handled; - item_origin.set_y(item_origin.y() + element.size().y()); - if cx.notify_count() > prev_notify_count { - new_items.push(ListItem::Unrendered, &()); - self.invalidated_elements.push(element); - } else { - new_items.push(item.clone(), &()); - } - cursor.next(&()); - } else { - unreachable!(); - } - } - - new_items.push_tree(cursor.suffix(&()), &()); - drop(cursor); - state.items = new_items; - - handled - } - fn rect_for_text_range( &self, range_utf16: Range, @@ -964,18 +916,6 @@ mod tests { todo!() } - fn dispatch_event( - &mut self, - _: &Event, - _: RectF, - _: RectF, - _: &mut (), - _: &mut (), - _: &mut EventContext, - ) -> bool { - todo!() - } - fn rect_for_text_range( &self, _: Range, diff --git a/crates/gpui/src/elements/mouse_event_handler.rs b/crates/gpui/src/elements/mouse_event_handler.rs index ab5aeb562b..c8ba330e70 100644 --- a/crates/gpui/src/elements/mouse_event_handler.rs +++ b/crates/gpui/src/elements/mouse_event_handler.rs @@ -6,11 +6,10 @@ use crate::{ }, platform::CursorStyle, scene::{ - ClickRegionEvent, CursorRegion, DownOutRegionEvent, DownRegionEvent, DragRegionEvent, - HandlerSet, HoverRegionEvent, MoveRegionEvent, ScrollWheelRegionEvent, UpOutRegionEvent, - UpRegionEvent, + CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover, + MouseMove, MouseScrollWheel, MouseUp, MouseUpOut, }, - DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, MeasurementContext, + DebugContext, Element, ElementBox, EventContext, LayoutContext, MeasurementContext, MouseButton, MouseRegion, MouseState, PaintContext, RenderContext, SizeConstraint, View, }; use serde_json::json; @@ -61,10 +60,7 @@ impl MouseEventHandler { self } - pub fn on_move( - mut self, - handler: impl Fn(MoveRegionEvent, &mut EventContext) + 'static, - ) -> Self { + pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self { self.handlers = self.handlers.on_move(handler); self } @@ -72,7 +68,7 @@ impl MouseEventHandler { pub fn on_down( mut self, button: MouseButton, - handler: impl Fn(DownRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseDown, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_down(button, handler); self @@ -81,7 +77,7 @@ impl MouseEventHandler { pub fn on_up( mut self, button: MouseButton, - handler: impl Fn(UpRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseUp, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_up(button, handler); self @@ -90,7 +86,7 @@ impl MouseEventHandler { pub fn on_click( mut self, button: MouseButton, - handler: impl Fn(ClickRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseClick, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_click(button, handler); self @@ -99,7 +95,7 @@ impl MouseEventHandler { pub fn on_down_out( mut self, button: MouseButton, - handler: impl Fn(DownOutRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseDownOut, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_down_out(button, handler); self @@ -108,7 +104,7 @@ impl MouseEventHandler { pub fn on_up_out( mut self, button: MouseButton, - handler: impl Fn(UpOutRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseUpOut, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_up_out(button, handler); self @@ -117,23 +113,20 @@ impl MouseEventHandler { pub fn on_drag( mut self, button: MouseButton, - handler: impl Fn(DragRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseDrag, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_drag(button, handler); self } - pub fn on_hover( - mut self, - handler: impl Fn(HoverRegionEvent, &mut EventContext) + 'static, - ) -> Self { + pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self { self.handlers = self.handlers.on_hover(handler); self } pub fn on_scroll( mut self, - handler: impl Fn(ScrollWheelRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_scroll(handler); self @@ -201,18 +194,6 @@ impl Element for MouseEventHandler { self.child.paint(bounds.origin(), visible_bounds, cx); } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - self.child.dispatch_event(event, cx) - } - fn rect_for_text_range( &self, range_utf16: Range, diff --git a/crates/gpui/src/elements/overlay.rs b/crates/gpui/src/elements/overlay.rs index 07442d1140..253c88f703 100644 --- a/crates/gpui/src/elements/overlay.rs +++ b/crates/gpui/src/elements/overlay.rs @@ -4,8 +4,8 @@ use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::ToJson, presenter::MeasurementContext, - Axis, DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, MouseRegion, - PaintContext, SizeConstraint, + Axis, DebugContext, Element, ElementBox, LayoutContext, MouseRegion, PaintContext, + SizeConstraint, }; use serde_json::json; @@ -225,18 +225,6 @@ impl Element for Overlay { cx.scene.pop_stacking_context(); } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - self.child.dispatch_event(event, cx) - } - fn rect_for_text_range( &self, range_utf16: Range, diff --git a/crates/gpui/src/elements/resizable.rs b/crates/gpui/src/elements/resizable.rs index 8024527903..fb5bfa4a11 100644 --- a/crates/gpui/src/elements/resizable.rs +++ b/crates/gpui/src/elements/resizable.rs @@ -4,7 +4,7 @@ use pathfinder_geometry::vector::{vec2f, Vector2F}; use serde_json::json; use crate::{ - geometry::rect::RectF, scene::DragRegionEvent, Axis, CursorStyle, Element, ElementBox, + geometry::rect::RectF, scene::MouseDrag, Axis, CursorStyle, Element, ElementBox, ElementStateHandle, MouseButton, MouseRegion, RenderContext, View, }; @@ -42,7 +42,7 @@ impl Side { } } - fn compute_delta(&self, e: DragRegionEvent) -> f32 { + fn compute_delta(&self, e: MouseDrag) -> f32 { if self.before_content() { self.relevant_component(e.prev_mouse_position) - self.relevant_component(e.position) } else { @@ -187,18 +187,6 @@ impl Element for Resizable { self.child.paint(bounds.origin(), visible_bounds, cx); } - fn dispatch_event( - &mut self, - event: &crate::Event, - _bounds: pathfinder_geometry::rect::RectF, - _visible_bounds: pathfinder_geometry::rect::RectF, - _layout: &mut Self::LayoutState, - _paint: &mut Self::PaintState, - cx: &mut crate::EventContext, - ) -> bool { - self.child.dispatch_event(event, cx) - } - fn rect_for_text_range( &self, range_utf16: std::ops::Range, diff --git a/crates/gpui/src/elements/stack.rs b/crates/gpui/src/elements/stack.rs index 5de53ff9e7..f08ce04649 100644 --- a/crates/gpui/src/elements/stack.rs +++ b/crates/gpui/src/elements/stack.rs @@ -4,8 +4,7 @@ use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::{self, json, ToJson}, presenter::MeasurementContext, - DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, - SizeConstraint, + DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; #[derive(Default)] @@ -49,23 +48,6 @@ impl Element for Stack { } } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - for child in self.children.iter_mut().rev() { - if child.dispatch_event(event, cx) { - return true; - } - } - false - } - fn rect_for_text_range( &self, range_utf16: Range, diff --git a/crates/gpui/src/elements/svg.rs b/crates/gpui/src/elements/svg.rs index 544abb3314..5bd2759f7a 100644 --- a/crates/gpui/src/elements/svg.rs +++ b/crates/gpui/src/elements/svg.rs @@ -9,7 +9,7 @@ use crate::{ vector::{vec2f, Vector2F}, }, presenter::MeasurementContext, - scene, DebugContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint, + scene, DebugContext, Element, LayoutContext, PaintContext, SizeConstraint, }; pub struct Svg { @@ -73,18 +73,6 @@ impl Element for Svg { } } - fn dispatch_event( - &mut self, - _: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - _: &mut EventContext, - ) -> bool { - false - } - fn rect_for_text_range( &self, _: Range, diff --git a/crates/gpui/src/elements/text.rs b/crates/gpui/src/elements/text.rs index 45dc2dbae3..073e343b9c 100644 --- a/crates/gpui/src/elements/text.rs +++ b/crates/gpui/src/elements/text.rs @@ -8,8 +8,7 @@ use crate::{ json::{ToJson, Value}, presenter::MeasurementContext, text_layout::{Line, RunStyle, ShapedBoundary}, - DebugContext, Element, Event, EventContext, FontCache, LayoutContext, PaintContext, - SizeConstraint, TextLayoutCache, + DebugContext, Element, FontCache, LayoutContext, PaintContext, SizeConstraint, TextLayoutCache, }; use log::warn; use serde_json::json; @@ -178,18 +177,6 @@ impl Element for Text { } } - fn dispatch_event( - &mut self, - _: &Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - _: &mut EventContext, - ) -> bool { - false - } - fn rect_for_text_range( &self, _: Range, diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index c86230a5e1..f81b4af701 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -186,18 +186,6 @@ impl Element for Tooltip { } } - fn dispatch_event( - &mut self, - event: &crate::Event, - _: RectF, - _: RectF, - _: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut crate::EventContext, - ) -> bool { - self.child.dispatch_event(event, cx) - } - fn rect_for_text_range( &self, range: Range, diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index c9cdbc1b2c..ca3601491a 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -1,4 +1,4 @@ -use super::{Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint}; +use super::{Element, EventContext, LayoutContext, PaintContext, SizeConstraint}; use crate::{ geometry::{ rect::RectF, @@ -6,7 +6,7 @@ use crate::{ }, json::{self, json}, presenter::MeasurementContext, - scene::ScrollWheelRegionEvent, + scene::MouseScrollWheel, ElementBox, MouseRegion, RenderContext, ScrollWheelEvent, View, }; use json::ToJson; @@ -292,7 +292,7 @@ impl Element for UniformList { MouseRegion::new::(self.view_id, 0, visible_bounds).on_scroll({ let scroll_max = layout.scroll_max; let state = self.state.clone(); - move |ScrollWheelRegionEvent { + move |MouseScrollWheel { platform_event: ScrollWheelEvent { position, @@ -324,23 +324,6 @@ impl Element for UniformList { cx.scene.pop_layer(); } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - layout: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - let mut handled = false; - for item in &mut layout.items { - handled = item.dispatch_event(event, cx) || handled; - } - - handled - } - fn rect_for_text_range( &self, range: Range, diff --git a/crates/gpui/src/platform/event.rs b/crates/gpui/src/platform/event.rs index 48043ac918..7e4b95c9a1 100644 --- a/crates/gpui/src/platform/event.rs +++ b/crates/gpui/src/platform/event.rs @@ -11,7 +11,7 @@ pub struct KeyUpEvent { pub keystroke: Keystroke, } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct ModifiersChangedEvent { pub ctrl: bool, pub alt: bool, diff --git a/crates/gpui/src/presenter.rs b/crates/gpui/src/presenter.rs index d082ebd095..74c2dddd66 100644 --- a/crates/gpui/src/presenter.rs +++ b/crates/gpui/src/presenter.rs @@ -7,9 +7,8 @@ use crate::{ keymap::Keystroke, platform::{CursorStyle, Event}, scene::{ - ClickRegionEvent, CursorRegion, DownOutRegionEvent, DownRegionEvent, DragRegionEvent, - HoverRegionEvent, MouseRegionEvent, MoveRegionEvent, ScrollWheelRegionEvent, - UpOutRegionEvent, UpRegionEvent, + CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover, + MouseMove, MouseScrollWheel, MouseUp, MouseUpOut, }, text_layout::TextLayoutCache, Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, Appearance, @@ -229,293 +228,283 @@ impl Presenter { event_reused: bool, cx: &mut MutableAppContext, ) -> bool { - if let Some(root_view_id) = cx.root_view_id(self.window_id) { - let mut events_to_send = Vec::new(); - let mut notified_views: HashSet = Default::default(); + let mut mouse_events = SmallVec::<[_; 2]>::new(); + let mut notified_views: HashSet = Default::default(); - // 1. Allocate the correct set of GPUI events generated from the platform events - // -> These are usually small: [Mouse Down] or [Mouse up, Click] or [Mouse Moved, Mouse Dragged?] - // -> Also moves around mouse related state - match &event { - Event::MouseDown(e) => { - // Click events are weird because they can be fired after a drag event. - // MDN says that browsers handle this by starting from 'the most - // specific ancestor element that contained both [positions]' - // So we need to store the overlapping regions on mouse down. + // 1. Handle platform event. Keyboard events get dispatched immediately, while mouse events + // get mapped into the mouse-specific MouseEvent type. + // -> These are usually small: [Mouse Down] or [Mouse up, Click] or [Mouse Moved, Mouse Dragged?] + // -> Also updates mouse-related state + match &event { + Event::KeyDown(e) => return cx.dispatch_key_down(self.window_id, e), + Event::KeyUp(e) => return cx.dispatch_key_up(self.window_id, e), + Event::ModifiersChanged(e) => return cx.dispatch_modifiers_changed(self.window_id, e), + Event::MouseDown(e) => { + // Click events are weird because they can be fired after a drag event. + // MDN says that browsers handle this by starting from 'the most + // specific ancestor element that contained both [positions]' + // So we need to store the overlapping regions on mouse down. - // If there is already clicked_button stored, don't replace it. - if self.clicked_button.is_none() { - self.clicked_region_ids = self - .mouse_regions - .iter() - .filter_map(|(region, _)| { - if region.bounds.contains_point(e.position) { - Some(region.id()) - } else { - None - } - }) - .collect(); - - self.clicked_button = Some(e.button); - } - - events_to_send.push(MouseRegionEvent::Down(DownRegionEvent { - region: Default::default(), - platform_event: e.clone(), - })); - events_to_send.push(MouseRegionEvent::DownOut(DownOutRegionEvent { - region: Default::default(), - platform_event: e.clone(), - })); - } - Event::MouseUp(e) => { - // NOTE: The order of event pushes is important! MouseUp events MUST be fired - // before click events, and so the UpRegionEvent events need to be pushed before - // ClickRegionEvents - events_to_send.push(MouseRegionEvent::Up(UpRegionEvent { - region: Default::default(), - platform_event: e.clone(), - })); - events_to_send.push(MouseRegionEvent::UpOut(UpOutRegionEvent { - region: Default::default(), - platform_event: e.clone(), - })); - events_to_send.push(MouseRegionEvent::Click(ClickRegionEvent { - region: Default::default(), - platform_event: e.clone(), - })); - } - Event::MouseMoved( - e @ MouseMovedEvent { - position, - pressed_button, - .. - }, - ) => { - let mut style_to_assign = CursorStyle::Arrow; - for region in self.cursor_regions.iter().rev() { - if region.bounds.contains_point(*position) { - style_to_assign = region.style; - break; - } - } - cx.platform().set_cursor_style(style_to_assign); - - if !event_reused { - if pressed_button.is_some() { - events_to_send.push(MouseRegionEvent::Drag(DragRegionEvent { - region: Default::default(), - prev_mouse_position: self.mouse_position, - platform_event: e.clone(), - })); - } else if let Some(clicked_button) = self.clicked_button { - // Mouse up event happened outside the current window. Simulate mouse up button event - let button_event = e.to_button_event(clicked_button); - events_to_send.push(MouseRegionEvent::Up(UpRegionEvent { - region: Default::default(), - platform_event: button_event.clone(), - })); - events_to_send.push(MouseRegionEvent::UpOut(UpOutRegionEvent { - region: Default::default(), - platform_event: button_event.clone(), - })); - events_to_send.push(MouseRegionEvent::Click(ClickRegionEvent { - region: Default::default(), - platform_event: button_event.clone(), - })); - } - - events_to_send.push(MouseRegionEvent::Move(MoveRegionEvent { - region: Default::default(), - platform_event: e.clone(), - })); - } - - events_to_send.push(MouseRegionEvent::Hover(HoverRegionEvent { - region: Default::default(), - platform_event: e.clone(), - started: false, - })); - - self.last_mouse_moved_event = Some(event.clone()); - } - Event::ScrollWheel(e) => { - events_to_send.push(MouseRegionEvent::ScrollWheel(ScrollWheelRegionEvent { - region: Default::default(), - platform_event: e.clone(), - })) - } - - _ => {} - } - - if let Some(position) = event.position() { - self.mouse_position = position; - } - - let mut any_event_handled = false; - // 2. Process the raw mouse events into region events - for mut region_event in events_to_send { - let mut valid_regions = Vec::new(); - - // GPUI elements are arranged by depth but sibling elements can register overlapping - // mouse regions. As such, hover events are only fired on overlapping elements which - // are at the same depth as the topmost element which overlaps with the mouse. - - match ®ion_event { - MouseRegionEvent::Hover(_) => { - let mut top_most_depth = None; - let mouse_position = self.mouse_position.clone(); - for (region, depth) in self.mouse_regions.iter().rev() { - // Allow mouse regions to appear transparent to hovers - if !region.hoverable { - continue; - } - - let contains_mouse = region.bounds.contains_point(mouse_position); - - if contains_mouse && top_most_depth.is_none() { - top_most_depth = Some(depth); - } - - // This unwrap relies on short circuiting boolean expressions - // The right side of the && is only executed when contains_mouse - // is true, and we know above that when contains_mouse is true - // top_most_depth is set - if contains_mouse && depth == top_most_depth.unwrap() { - //Ensure that hover entrance events aren't sent twice - if self.hovered_region_ids.insert(region.id()) { - valid_regions.push(region.clone()); - if region.notify_on_hover { - notified_views.insert(region.id().view_id()); - } - } + // If there is already clicked_button stored, don't replace it. + if self.clicked_button.is_none() { + self.clicked_region_ids = self + .mouse_regions + .iter() + .filter_map(|(region, _)| { + if region.bounds.contains_point(e.position) { + Some(region.id()) } else { - // Ensure that hover exit events aren't sent twice - if self.hovered_region_ids.remove(®ion.id()) { - valid_regions.push(region.clone()); - if region.notify_on_hover { - notified_views.insert(region.id().view_id()); - } - } + None } - } - } - MouseRegionEvent::Down(_) | MouseRegionEvent::Up(_) => { - for (region, _) in self.mouse_regions.iter().rev() { - if region.bounds.contains_point(self.mouse_position) { - if region.notify_on_click { - notified_views.insert(region.id().view_id()); - } - valid_regions.push(region.clone()); - } - } - } - MouseRegionEvent::Click(e) => { - // Only raise click events if the released button is the same as the one stored - if self - .clicked_button - .map(|clicked_button| clicked_button == e.button) - .unwrap_or(false) - { - // Clear clicked regions and clicked button - let clicked_region_ids = - std::mem::replace(&mut self.clicked_region_ids, Default::default()); - self.clicked_button = None; + }) + .collect(); - // Find regions which still overlap with the mouse since the last MouseDown happened - for (mouse_region, _) in self.mouse_regions.iter().rev() { - if clicked_region_ids.contains(&mouse_region.id()) { - if mouse_region.bounds.contains_point(self.mouse_position) { - valid_regions.push(mouse_region.clone()); - } - } - } - } - } - MouseRegionEvent::Drag(_) => { - for (mouse_region, _) in self.mouse_regions.iter().rev() { - if self.clicked_region_ids.contains(&mouse_region.id()) { - valid_regions.push(mouse_region.clone()); - } - } - } - - MouseRegionEvent::UpOut(_) | MouseRegionEvent::DownOut(_) => { - for (mouse_region, _) in self.mouse_regions.iter().rev() { - // NOT contains - if !mouse_region.bounds.contains_point(self.mouse_position) { - valid_regions.push(mouse_region.clone()); - } - } - } - _ => { - for (mouse_region, _) in self.mouse_regions.iter().rev() { - // Contains - if mouse_region.bounds.contains_point(self.mouse_position) { - valid_regions.push(mouse_region.clone()); - } - } - } + self.clicked_button = Some(e.button); } - //3. Fire region events - let hovered_region_ids = self.hovered_region_ids.clone(); - for valid_region in valid_regions.into_iter() { - let mut event_cx = self.build_event_context(&mut notified_views, cx); - - region_event.set_region(valid_region.bounds); - if let MouseRegionEvent::Hover(e) = &mut region_event { - e.started = hovered_region_ids.contains(&valid_region.id()) - } - // Handle Down events if the MouseRegion has a Click or Drag handler. This makes the api more intuitive as you would - // not expect a MouseRegion to be transparent to Down events if it also has a Click handler. - // This behavior can be overridden by adding a Down handler that calls cx.propogate_event - if let MouseRegionEvent::Down(e) = ®ion_event { - if valid_region - .handlers - .contains_handler(MouseRegionEvent::click_disc(), Some(e.button)) - || valid_region - .handlers - .contains_handler(MouseRegionEvent::drag_disc(), Some(e.button)) - { - event_cx.handled = true; - } - } - - if let Some(callback) = valid_region.handlers.get(®ion_event.handler_key()) { - event_cx.handled = true; - event_cx.with_current_view(valid_region.id().view_id(), { - let region_event = region_event.clone(); - |cx| { - callback(region_event, cx); - } - }); - } - - any_event_handled = any_event_handled || event_cx.handled; - // For bubbling events, if the event was handled, don't continue dispatching - // This only makes sense for local events. - if event_cx.handled && region_event.is_capturable() { + mouse_events.push(MouseEvent::Down(MouseDown { + region: Default::default(), + platform_event: e.clone(), + })); + mouse_events.push(MouseEvent::DownOut(MouseDownOut { + region: Default::default(), + platform_event: e.clone(), + })); + } + Event::MouseUp(e) => { + // NOTE: The order of event pushes is important! MouseUp events MUST be fired + // before click events, and so the MouseUp events need to be pushed before + // MouseClick events. + mouse_events.push(MouseEvent::Up(MouseUp { + region: Default::default(), + platform_event: e.clone(), + })); + mouse_events.push(MouseEvent::UpOut(MouseUpOut { + region: Default::default(), + platform_event: e.clone(), + })); + mouse_events.push(MouseEvent::Click(MouseClick { + region: Default::default(), + platform_event: e.clone(), + })); + } + Event::MouseMoved( + e @ MouseMovedEvent { + position, + pressed_button, + .. + }, + ) => { + let mut style_to_assign = CursorStyle::Arrow; + for region in self.cursor_regions.iter().rev() { + if region.bounds.contains_point(*position) { + style_to_assign = region.style; break; } } - } + cx.platform().set_cursor_style(style_to_assign); - if !any_event_handled && !event_reused { - let mut event_cx = self.build_event_context(&mut notified_views, cx); - any_event_handled = event_cx.dispatch_event(root_view_id, &event); - } + if !event_reused { + if pressed_button.is_some() { + mouse_events.push(MouseEvent::Drag(MouseDrag { + region: Default::default(), + prev_mouse_position: self.mouse_position, + platform_event: e.clone(), + })); + } else if let Some(clicked_button) = self.clicked_button { + // Mouse up event happened outside the current window. Simulate mouse up button event + let button_event = e.to_button_event(clicked_button); + mouse_events.push(MouseEvent::Up(MouseUp { + region: Default::default(), + platform_event: button_event.clone(), + })); + mouse_events.push(MouseEvent::UpOut(MouseUpOut { + region: Default::default(), + platform_event: button_event.clone(), + })); + mouse_events.push(MouseEvent::Click(MouseClick { + region: Default::default(), + platform_event: button_event.clone(), + })); + } - for view_id in notified_views { - cx.notify_view(self.window_id, view_id); - } + mouse_events.push(MouseEvent::Move(MouseMove { + region: Default::default(), + platform_event: e.clone(), + })); + } - any_event_handled - } else { - false + mouse_events.push(MouseEvent::Hover(MouseHover { + region: Default::default(), + platform_event: e.clone(), + started: false, + })); + + self.last_mouse_moved_event = Some(event.clone()); + } + Event::ScrollWheel(e) => mouse_events.push(MouseEvent::ScrollWheel(MouseScrollWheel { + region: Default::default(), + platform_event: e.clone(), + })), } + + if let Some(position) = event.position() { + self.mouse_position = position; + } + + // 2. Dispatch mouse events on regions + let mut any_event_handled = false; + for mut mouse_event in mouse_events { + let mut valid_regions = Vec::new(); + + // GPUI elements are arranged by depth but sibling elements can register overlapping + // mouse regions. As such, hover events are only fired on overlapping elements which + // are at the same depth as the topmost element which overlaps with the mouse. + match &mouse_event { + MouseEvent::Hover(_) => { + let mut top_most_depth = None; + let mouse_position = self.mouse_position.clone(); + for (region, depth) in self.mouse_regions.iter().rev() { + // Allow mouse regions to appear transparent to hovers + if !region.hoverable { + continue; + } + + let contains_mouse = region.bounds.contains_point(mouse_position); + + if contains_mouse && top_most_depth.is_none() { + top_most_depth = Some(depth); + } + + // This unwrap relies on short circuiting boolean expressions + // The right side of the && is only executed when contains_mouse + // is true, and we know above that when contains_mouse is true + // top_most_depth is set + if contains_mouse && depth == top_most_depth.unwrap() { + //Ensure that hover entrance events aren't sent twice + if self.hovered_region_ids.insert(region.id()) { + valid_regions.push(region.clone()); + if region.notify_on_hover { + notified_views.insert(region.id().view_id()); + } + } + } else { + // Ensure that hover exit events aren't sent twice + if self.hovered_region_ids.remove(®ion.id()) { + valid_regions.push(region.clone()); + if region.notify_on_hover { + notified_views.insert(region.id().view_id()); + } + } + } + } + } + MouseEvent::Down(_) | MouseEvent::Up(_) => { + for (region, _) in self.mouse_regions.iter().rev() { + if region.bounds.contains_point(self.mouse_position) { + if region.notify_on_click { + notified_views.insert(region.id().view_id()); + } + valid_regions.push(region.clone()); + } + } + } + MouseEvent::Click(e) => { + // Only raise click events if the released button is the same as the one stored + if self + .clicked_button + .map(|clicked_button| clicked_button == e.button) + .unwrap_or(false) + { + // Clear clicked regions and clicked button + let clicked_region_ids = + std::mem::replace(&mut self.clicked_region_ids, Default::default()); + self.clicked_button = None; + + // Find regions which still overlap with the mouse since the last MouseDown happened + for (mouse_region, _) in self.mouse_regions.iter().rev() { + if clicked_region_ids.contains(&mouse_region.id()) { + if mouse_region.bounds.contains_point(self.mouse_position) { + valid_regions.push(mouse_region.clone()); + } + } + } + } + } + MouseEvent::Drag(_) => { + for (mouse_region, _) in self.mouse_regions.iter().rev() { + if self.clicked_region_ids.contains(&mouse_region.id()) { + valid_regions.push(mouse_region.clone()); + } + } + } + + MouseEvent::UpOut(_) | MouseEvent::DownOut(_) => { + for (mouse_region, _) in self.mouse_regions.iter().rev() { + // NOT contains + if !mouse_region.bounds.contains_point(self.mouse_position) { + valid_regions.push(mouse_region.clone()); + } + } + } + _ => { + for (mouse_region, _) in self.mouse_regions.iter().rev() { + // Contains + if mouse_region.bounds.contains_point(self.mouse_position) { + valid_regions.push(mouse_region.clone()); + } + } + } + } + + //3. Fire region events + let hovered_region_ids = self.hovered_region_ids.clone(); + for valid_region in valid_regions.into_iter() { + let mut event_cx = self.build_event_context(&mut notified_views, cx); + + mouse_event.set_region(valid_region.bounds); + if let MouseEvent::Hover(e) = &mut mouse_event { + e.started = hovered_region_ids.contains(&valid_region.id()) + } + // Handle Down events if the MouseRegion has a Click or Drag handler. This makes the api more intuitive as you would + // not expect a MouseRegion to be transparent to Down events if it also has a Click handler. + // This behavior can be overridden by adding a Down handler that calls cx.propogate_event + if let MouseEvent::Down(e) = &mouse_event { + if valid_region + .handlers + .contains_handler(MouseEvent::click_disc(), Some(e.button)) + || valid_region + .handlers + .contains_handler(MouseEvent::drag_disc(), Some(e.button)) + { + event_cx.handled = true; + } + } + + if let Some(callback) = valid_region.handlers.get(&mouse_event.handler_key()) { + event_cx.handled = true; + event_cx.with_current_view(valid_region.id().view_id(), { + let region_event = mouse_event.clone(); + |cx| { + callback(region_event, cx); + } + }); + } + + any_event_handled = any_event_handled || event_cx.handled; + // For bubbling events, if the event was handled, don't continue dispatching + // This only makes sense for local events. + if event_cx.handled && mouse_event.is_capturable() { + break; + } + } + } + + for view_id in notified_views { + cx.notify_view(self.window_id, view_id); + } + + any_event_handled } pub fn build_event_context<'a>( @@ -524,7 +513,6 @@ impl Presenter { cx: &'a mut MutableAppContext, ) -> EventContext<'a> { EventContext { - rendered_views: &mut self.rendered_views, font_cache: &self.font_cache, text_layout_cache: &self.text_layout_cache, view_stack: Default::default(), @@ -743,7 +731,6 @@ impl<'a> Deref for PaintContext<'a> { } pub struct EventContext<'a> { - rendered_views: &'a mut HashMap, pub font_cache: &'a FontCache, pub text_layout_cache: &'a TextLayoutCache, pub app: &'a mut MutableAppContext, @@ -755,17 +742,6 @@ pub struct EventContext<'a> { } impl<'a> EventContext<'a> { - fn dispatch_event(&mut self, view_id: usize, event: &Event) -> bool { - if let Some(mut element) = self.rendered_views.remove(&view_id) { - let result = - self.with_current_view(view_id, |this| element.dispatch_event(event, this)); - self.rendered_views.insert(view_id, element); - result - } else { - false - } - } - fn with_current_view(&mut self, view_id: usize, f: F) -> T where F: FnOnce(&mut Self) -> T, @@ -1028,27 +1004,6 @@ impl Element for ChildView { } } - fn dispatch_event( - &mut self, - event: &Event, - _: RectF, - _: RectF, - view_is_valid: &mut Self::LayoutState, - _: &mut Self::PaintState, - cx: &mut EventContext, - ) -> bool { - if *view_is_valid { - cx.dispatch_event(self.view.id(), event) - } else { - log::error!( - "dispatch_event called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", - self.view.id(), - self.view_name - ); - false - } - } - fn rect_for_text_range( &self, range_utf16: Range, diff --git a/crates/gpui/src/scene.rs b/crates/gpui/src/scene.rs index 4ef17a3f8f..99b38a1852 100644 --- a/crates/gpui/src/scene.rs +++ b/crates/gpui/src/scene.rs @@ -1,5 +1,5 @@ +mod mouse_event; mod mouse_region; -mod mouse_region_event; #[cfg(debug_assertions)] use collections::HashSet; @@ -15,8 +15,8 @@ use crate::{ platform::{current::Surface, CursorStyle}, ImageData, }; +pub use mouse_event::*; pub use mouse_region::*; -pub use mouse_region_event::*; pub struct Scene { scale_factor: f32, diff --git a/crates/gpui/src/scene/mouse_event.rs b/crates/gpui/src/scene/mouse_event.rs new file mode 100644 index 0000000000..d7370ac75f --- /dev/null +++ b/crates/gpui/src/scene/mouse_event.rs @@ -0,0 +1,233 @@ +use std::{ + mem::{discriminant, Discriminant}, + ops::Deref, +}; + +use pathfinder_geometry::{rect::RectF, vector::Vector2F}; + +use crate::{MouseButton, MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent}; + +#[derive(Debug, Default, Clone)] +pub struct MouseMove { + pub region: RectF, + pub platform_event: MouseMovedEvent, +} + +impl Deref for MouseMove { + type Target = MouseMovedEvent; + + fn deref(&self) -> &Self::Target { + &self.platform_event + } +} + +#[derive(Debug, Default, Clone)] +pub struct MouseDrag { + pub region: RectF, + pub prev_mouse_position: Vector2F, + pub platform_event: MouseMovedEvent, +} + +impl Deref for MouseDrag { + type Target = MouseMovedEvent; + + fn deref(&self) -> &Self::Target { + &self.platform_event + } +} + +#[derive(Debug, Default, Clone)] +pub struct MouseHover { + pub region: RectF, + pub started: bool, + pub platform_event: MouseMovedEvent, +} + +impl Deref for MouseHover { + type Target = MouseMovedEvent; + + fn deref(&self) -> &Self::Target { + &self.platform_event + } +} + +#[derive(Debug, Default, Clone)] +pub struct MouseDown { + pub region: RectF, + pub platform_event: MouseButtonEvent, +} + +impl Deref for MouseDown { + type Target = MouseButtonEvent; + + fn deref(&self) -> &Self::Target { + &self.platform_event + } +} + +#[derive(Debug, Default, Clone)] +pub struct MouseUp { + pub region: RectF, + pub platform_event: MouseButtonEvent, +} + +impl Deref for MouseUp { + type Target = MouseButtonEvent; + + fn deref(&self) -> &Self::Target { + &self.platform_event + } +} + +#[derive(Debug, Default, Clone)] +pub struct MouseClick { + pub region: RectF, + pub platform_event: MouseButtonEvent, +} + +impl Deref for MouseClick { + type Target = MouseButtonEvent; + + fn deref(&self) -> &Self::Target { + &self.platform_event + } +} + +#[derive(Debug, Default, Clone)] +pub struct MouseDownOut { + pub region: RectF, + pub platform_event: MouseButtonEvent, +} + +impl Deref for MouseDownOut { + type Target = MouseButtonEvent; + + fn deref(&self) -> &Self::Target { + &self.platform_event + } +} + +#[derive(Debug, Default, Clone)] +pub struct MouseUpOut { + pub region: RectF, + pub platform_event: MouseButtonEvent, +} + +impl Deref for MouseUpOut { + type Target = MouseButtonEvent; + + fn deref(&self) -> &Self::Target { + &self.platform_event + } +} + +#[derive(Debug, Default, Clone)] +pub struct MouseScrollWheel { + pub region: RectF, + pub platform_event: ScrollWheelEvent, +} + +impl Deref for MouseScrollWheel { + type Target = ScrollWheelEvent; + + fn deref(&self) -> &Self::Target { + &self.platform_event + } +} + +#[derive(Debug, Clone)] +pub enum MouseEvent { + Move(MouseMove), + Drag(MouseDrag), + Hover(MouseHover), + Down(MouseDown), + Up(MouseUp), + Click(MouseClick), + DownOut(MouseDownOut), + UpOut(MouseUpOut), + ScrollWheel(MouseScrollWheel), +} + +impl MouseEvent { + pub fn set_region(&mut self, region: RectF) { + match self { + MouseEvent::Move(r) => r.region = region, + MouseEvent::Drag(r) => r.region = region, + MouseEvent::Hover(r) => r.region = region, + MouseEvent::Down(r) => r.region = region, + MouseEvent::Up(r) => r.region = region, + MouseEvent::Click(r) => r.region = region, + MouseEvent::DownOut(r) => r.region = region, + MouseEvent::UpOut(r) => r.region = region, + MouseEvent::ScrollWheel(r) => r.region = region, + } + } + + /// When true, mouse event handlers must call cx.propagate_event() to bubble + /// the event to handlers they are painted on top of. + pub fn is_capturable(&self) -> bool { + match self { + MouseEvent::Move(_) => true, + MouseEvent::Drag(_) => true, + MouseEvent::Hover(_) => false, + MouseEvent::Down(_) => true, + MouseEvent::Up(_) => true, + MouseEvent::Click(_) => true, + MouseEvent::DownOut(_) => false, + MouseEvent::UpOut(_) => false, + MouseEvent::ScrollWheel(_) => true, + } + } +} + +impl MouseEvent { + pub fn move_disc() -> Discriminant { + discriminant(&MouseEvent::Move(Default::default())) + } + + pub fn drag_disc() -> Discriminant { + discriminant(&MouseEvent::Drag(Default::default())) + } + + pub fn hover_disc() -> Discriminant { + discriminant(&MouseEvent::Hover(Default::default())) + } + + pub fn down_disc() -> Discriminant { + discriminant(&MouseEvent::Down(Default::default())) + } + + pub fn up_disc() -> Discriminant { + discriminant(&MouseEvent::Up(Default::default())) + } + + pub fn up_out_disc() -> Discriminant { + discriminant(&MouseEvent::UpOut(Default::default())) + } + + pub fn click_disc() -> Discriminant { + discriminant(&MouseEvent::Click(Default::default())) + } + + pub fn down_out_disc() -> Discriminant { + discriminant(&MouseEvent::DownOut(Default::default())) + } + + pub fn scroll_wheel_disc() -> Discriminant { + discriminant(&MouseEvent::ScrollWheel(Default::default())) + } + + pub fn handler_key(&self) -> (Discriminant, Option) { + match self { + MouseEvent::Move(_) => (Self::move_disc(), None), + MouseEvent::Drag(e) => (Self::drag_disc(), e.pressed_button), + MouseEvent::Hover(_) => (Self::hover_disc(), None), + MouseEvent::Down(e) => (Self::down_disc(), Some(e.button)), + MouseEvent::Up(e) => (Self::up_disc(), Some(e.button)), + MouseEvent::Click(e) => (Self::click_disc(), Some(e.button)), + MouseEvent::UpOut(e) => (Self::up_out_disc(), Some(e.button)), + MouseEvent::DownOut(e) => (Self::down_out_disc(), Some(e.button)), + MouseEvent::ScrollWheel(_) => (Self::scroll_wheel_disc(), None), + } + } +} diff --git a/crates/gpui/src/scene/mouse_region.rs b/crates/gpui/src/scene/mouse_region.rs index e84508622b..4b5217cc2d 100644 --- a/crates/gpui/src/scene/mouse_region.rs +++ b/crates/gpui/src/scene/mouse_region.rs @@ -7,11 +7,11 @@ use pathfinder_geometry::rect::RectF; use crate::{EventContext, MouseButton}; use super::{ - mouse_region_event::{ - ClickRegionEvent, DownOutRegionEvent, DownRegionEvent, DragRegionEvent, HoverRegionEvent, - MouseRegionEvent, MoveRegionEvent, UpOutRegionEvent, UpRegionEvent, + mouse_event::{ + MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover, MouseMove, MouseUp, + MouseUpOut, }, - ScrollWheelRegionEvent, + MouseScrollWheel, }; #[derive(Clone)] @@ -62,7 +62,7 @@ impl MouseRegion { pub fn on_down( mut self, button: MouseButton, - handler: impl Fn(DownRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseDown, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_down(button, handler); self @@ -71,7 +71,7 @@ impl MouseRegion { pub fn on_up( mut self, button: MouseButton, - handler: impl Fn(UpRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseUp, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_up(button, handler); self @@ -80,7 +80,7 @@ impl MouseRegion { pub fn on_click( mut self, button: MouseButton, - handler: impl Fn(ClickRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseClick, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_click(button, handler); self @@ -89,7 +89,7 @@ impl MouseRegion { pub fn on_down_out( mut self, button: MouseButton, - handler: impl Fn(DownOutRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseDownOut, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_down_out(button, handler); self @@ -98,7 +98,7 @@ impl MouseRegion { pub fn on_up_out( mut self, button: MouseButton, - handler: impl Fn(UpOutRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseUpOut, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_up_out(button, handler); self @@ -107,31 +107,25 @@ impl MouseRegion { pub fn on_drag( mut self, button: MouseButton, - handler: impl Fn(DragRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseDrag, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_drag(button, handler); self } - pub fn on_hover( - mut self, - handler: impl Fn(HoverRegionEvent, &mut EventContext) + 'static, - ) -> Self { + pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self { self.handlers = self.handlers.on_hover(handler); self } - pub fn on_move( - mut self, - handler: impl Fn(MoveRegionEvent, &mut EventContext) + 'static, - ) -> Self { + pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self { self.handlers = self.handlers.on_move(handler); self } pub fn on_scroll( mut self, - handler: impl Fn(ScrollWheelRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_scroll(handler); self @@ -187,8 +181,8 @@ impl MouseRegionId { pub struct HandlerSet { #[allow(clippy::type_complexity)] pub set: HashMap< - (Discriminant, Option), - Rc, + (Discriminant, Option), + Rc, >, } @@ -196,68 +190,50 @@ impl HandlerSet { pub fn capture_all() -> Self { #[allow(clippy::type_complexity)] let mut set: HashMap< - (Discriminant, Option), - Rc, + (Discriminant, Option), + Rc, > = Default::default(); - set.insert((MouseRegionEvent::move_disc(), None), Rc::new(|_, _| {})); - set.insert((MouseRegionEvent::hover_disc(), None), Rc::new(|_, _| {})); + set.insert((MouseEvent::move_disc(), None), Rc::new(|_, _| {})); + set.insert((MouseEvent::hover_disc(), None), Rc::new(|_, _| {})); for button in MouseButton::all() { + set.insert((MouseEvent::drag_disc(), Some(button)), Rc::new(|_, _| {})); + set.insert((MouseEvent::down_disc(), Some(button)), Rc::new(|_, _| {})); + set.insert((MouseEvent::up_disc(), Some(button)), Rc::new(|_, _| {})); + set.insert((MouseEvent::click_disc(), Some(button)), Rc::new(|_, _| {})); set.insert( - (MouseRegionEvent::drag_disc(), Some(button)), + (MouseEvent::down_out_disc(), Some(button)), Rc::new(|_, _| {}), ); set.insert( - (MouseRegionEvent::down_disc(), Some(button)), - Rc::new(|_, _| {}), - ); - set.insert( - (MouseRegionEvent::up_disc(), Some(button)), - Rc::new(|_, _| {}), - ); - set.insert( - (MouseRegionEvent::click_disc(), Some(button)), - Rc::new(|_, _| {}), - ); - set.insert( - (MouseRegionEvent::down_out_disc(), Some(button)), - Rc::new(|_, _| {}), - ); - set.insert( - (MouseRegionEvent::up_out_disc(), Some(button)), + (MouseEvent::up_out_disc(), Some(button)), Rc::new(|_, _| {}), ); } - set.insert( - (MouseRegionEvent::scroll_wheel_disc(), None), - Rc::new(|_, _| {}), - ); + set.insert((MouseEvent::scroll_wheel_disc(), None), Rc::new(|_, _| {})); HandlerSet { set } } pub fn get( &self, - key: &(Discriminant, Option), - ) -> Option> { + key: &(Discriminant, Option), + ) -> Option> { self.set.get(key).cloned() } pub fn contains_handler( &self, - event: Discriminant, + event: Discriminant, button: Option, ) -> bool { self.set.contains_key(&(event, button)) } - pub fn on_move( - mut self, - handler: impl Fn(MoveRegionEvent, &mut EventContext) + 'static, - ) -> Self { - self.set.insert((MouseRegionEvent::move_disc(), None), + pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self { + self.set.insert((MouseEvent::move_disc(), None), Rc::new(move |region_event, cx| { - if let MouseRegionEvent::Move(e) = region_event { + if let MouseEvent::Move(e) = region_event { handler(e, cx); } else { panic!( @@ -271,11 +247,11 @@ impl HandlerSet { pub fn on_down( mut self, button: MouseButton, - handler: impl Fn(DownRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseDown, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseRegionEvent::down_disc(), Some(button)), + self.set.insert((MouseEvent::down_disc(), Some(button)), Rc::new(move |region_event, cx| { - if let MouseRegionEvent::Down(e) = region_event { + if let MouseEvent::Down(e) = region_event { handler(e, cx); } else { panic!( @@ -289,11 +265,11 @@ impl HandlerSet { pub fn on_up( mut self, button: MouseButton, - handler: impl Fn(UpRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseUp, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseRegionEvent::up_disc(), Some(button)), + self.set.insert((MouseEvent::up_disc(), Some(button)), Rc::new(move |region_event, cx| { - if let MouseRegionEvent::Up(e) = region_event { + if let MouseEvent::Up(e) = region_event { handler(e, cx); } else { panic!( @@ -307,11 +283,11 @@ impl HandlerSet { pub fn on_click( mut self, button: MouseButton, - handler: impl Fn(ClickRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseClick, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseRegionEvent::click_disc(), Some(button)), + self.set.insert((MouseEvent::click_disc(), Some(button)), Rc::new(move |region_event, cx| { - if let MouseRegionEvent::Click(e) = region_event { + if let MouseEvent::Click(e) = region_event { handler(e, cx); } else { panic!( @@ -325,11 +301,11 @@ impl HandlerSet { pub fn on_down_out( mut self, button: MouseButton, - handler: impl Fn(DownOutRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseDownOut, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseRegionEvent::down_out_disc(), Some(button)), + self.set.insert((MouseEvent::down_out_disc(), Some(button)), Rc::new(move |region_event, cx| { - if let MouseRegionEvent::DownOut(e) = region_event { + if let MouseEvent::DownOut(e) = region_event { handler(e, cx); } else { panic!( @@ -343,11 +319,11 @@ impl HandlerSet { pub fn on_up_out( mut self, button: MouseButton, - handler: impl Fn(UpOutRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseUpOut, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseRegionEvent::up_out_disc(), Some(button)), + self.set.insert((MouseEvent::up_out_disc(), Some(button)), Rc::new(move |region_event, cx| { - if let MouseRegionEvent::UpOut(e) = region_event { + if let MouseEvent::UpOut(e) = region_event { handler(e, cx); } else { panic!( @@ -361,11 +337,11 @@ impl HandlerSet { pub fn on_drag( mut self, button: MouseButton, - handler: impl Fn(DragRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseDrag, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseRegionEvent::drag_disc(), Some(button)), + self.set.insert((MouseEvent::drag_disc(), Some(button)), Rc::new(move |region_event, cx| { - if let MouseRegionEvent::Drag(e) = region_event { + if let MouseEvent::Drag(e) = region_event { handler(e, cx); } else { panic!( @@ -376,13 +352,10 @@ impl HandlerSet { self } - pub fn on_hover( - mut self, - handler: impl Fn(HoverRegionEvent, &mut EventContext) + 'static, - ) -> Self { - self.set.insert((MouseRegionEvent::hover_disc(), None), + pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self { + self.set.insert((MouseEvent::hover_disc(), None), Rc::new(move |region_event, cx| { - if let MouseRegionEvent::Hover(e) = region_event { + if let MouseEvent::Hover(e) = region_event { handler(e, cx); } else { panic!( @@ -395,11 +368,11 @@ impl HandlerSet { pub fn on_scroll( mut self, - handler: impl Fn(ScrollWheelRegionEvent, &mut EventContext) + 'static, + handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseRegionEvent::scroll_wheel_disc(), None), + self.set.insert((MouseEvent::scroll_wheel_disc(), None), Rc::new(move |region_event, cx| { - if let MouseRegionEvent::ScrollWheel(e) = region_event { + if let MouseEvent::ScrollWheel(e) = region_event { handler(e, cx); } else { panic!( diff --git a/crates/gpui/src/scene/mouse_region_event.rs b/crates/gpui/src/scene/mouse_region_event.rs deleted file mode 100644 index 4d89cd5b6f..0000000000 --- a/crates/gpui/src/scene/mouse_region_event.rs +++ /dev/null @@ -1,233 +0,0 @@ -use std::{ - mem::{discriminant, Discriminant}, - ops::Deref, -}; - -use pathfinder_geometry::{rect::RectF, vector::Vector2F}; - -use crate::{MouseButton, MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent}; - -#[derive(Debug, Default, Clone)] -pub struct MoveRegionEvent { - pub region: RectF, - pub platform_event: MouseMovedEvent, -} - -impl Deref for MoveRegionEvent { - type Target = MouseMovedEvent; - - fn deref(&self) -> &Self::Target { - &self.platform_event - } -} - -#[derive(Debug, Default, Clone)] -pub struct DragRegionEvent { - pub region: RectF, - pub prev_mouse_position: Vector2F, - pub platform_event: MouseMovedEvent, -} - -impl Deref for DragRegionEvent { - type Target = MouseMovedEvent; - - fn deref(&self) -> &Self::Target { - &self.platform_event - } -} - -#[derive(Debug, Default, Clone)] -pub struct HoverRegionEvent { - pub region: RectF, - pub started: bool, - pub platform_event: MouseMovedEvent, -} - -impl Deref for HoverRegionEvent { - type Target = MouseMovedEvent; - - fn deref(&self) -> &Self::Target { - &self.platform_event - } -} - -#[derive(Debug, Default, Clone)] -pub struct DownRegionEvent { - pub region: RectF, - pub platform_event: MouseButtonEvent, -} - -impl Deref for DownRegionEvent { - type Target = MouseButtonEvent; - - fn deref(&self) -> &Self::Target { - &self.platform_event - } -} - -#[derive(Debug, Default, Clone)] -pub struct UpRegionEvent { - pub region: RectF, - pub platform_event: MouseButtonEvent, -} - -impl Deref for UpRegionEvent { - type Target = MouseButtonEvent; - - fn deref(&self) -> &Self::Target { - &self.platform_event - } -} - -#[derive(Debug, Default, Clone)] -pub struct ClickRegionEvent { - pub region: RectF, - pub platform_event: MouseButtonEvent, -} - -impl Deref for ClickRegionEvent { - type Target = MouseButtonEvent; - - fn deref(&self) -> &Self::Target { - &self.platform_event - } -} - -#[derive(Debug, Default, Clone)] -pub struct DownOutRegionEvent { - pub region: RectF, - pub platform_event: MouseButtonEvent, -} - -impl Deref for DownOutRegionEvent { - type Target = MouseButtonEvent; - - fn deref(&self) -> &Self::Target { - &self.platform_event - } -} - -#[derive(Debug, Default, Clone)] -pub struct UpOutRegionEvent { - pub region: RectF, - pub platform_event: MouseButtonEvent, -} - -impl Deref for UpOutRegionEvent { - type Target = MouseButtonEvent; - - fn deref(&self) -> &Self::Target { - &self.platform_event - } -} - -#[derive(Debug, Default, Clone)] -pub struct ScrollWheelRegionEvent { - pub region: RectF, - pub platform_event: ScrollWheelEvent, -} - -impl Deref for ScrollWheelRegionEvent { - type Target = ScrollWheelEvent; - - fn deref(&self) -> &Self::Target { - &self.platform_event - } -} - -#[derive(Debug, Clone)] -pub enum MouseRegionEvent { - Move(MoveRegionEvent), - Drag(DragRegionEvent), - Hover(HoverRegionEvent), - Down(DownRegionEvent), - Up(UpRegionEvent), - Click(ClickRegionEvent), - DownOut(DownOutRegionEvent), - UpOut(UpOutRegionEvent), - ScrollWheel(ScrollWheelRegionEvent), -} - -impl MouseRegionEvent { - pub fn set_region(&mut self, region: RectF) { - match self { - MouseRegionEvent::Move(r) => r.region = region, - MouseRegionEvent::Drag(r) => r.region = region, - MouseRegionEvent::Hover(r) => r.region = region, - MouseRegionEvent::Down(r) => r.region = region, - MouseRegionEvent::Up(r) => r.region = region, - MouseRegionEvent::Click(r) => r.region = region, - MouseRegionEvent::DownOut(r) => r.region = region, - MouseRegionEvent::UpOut(r) => r.region = region, - MouseRegionEvent::ScrollWheel(r) => r.region = region, - } - } - - /// When true, mouse event handlers must call cx.propagate_event() to bubble - /// the event to handlers they are painted on top of. - pub fn is_capturable(&self) -> bool { - match self { - MouseRegionEvent::Move(_) => true, - MouseRegionEvent::Drag(_) => true, - MouseRegionEvent::Hover(_) => false, - MouseRegionEvent::Down(_) => true, - MouseRegionEvent::Up(_) => true, - MouseRegionEvent::Click(_) => true, - MouseRegionEvent::DownOut(_) => false, - MouseRegionEvent::UpOut(_) => false, - MouseRegionEvent::ScrollWheel(_) => true, - } - } -} - -impl MouseRegionEvent { - pub fn move_disc() -> Discriminant { - discriminant(&MouseRegionEvent::Move(Default::default())) - } - - pub fn drag_disc() -> Discriminant { - discriminant(&MouseRegionEvent::Drag(Default::default())) - } - - pub fn hover_disc() -> Discriminant { - discriminant(&MouseRegionEvent::Hover(Default::default())) - } - - pub fn down_disc() -> Discriminant { - discriminant(&MouseRegionEvent::Down(Default::default())) - } - - pub fn up_disc() -> Discriminant { - discriminant(&MouseRegionEvent::Up(Default::default())) - } - - pub fn up_out_disc() -> Discriminant { - discriminant(&MouseRegionEvent::UpOut(Default::default())) - } - - pub fn click_disc() -> Discriminant { - discriminant(&MouseRegionEvent::Click(Default::default())) - } - - pub fn down_out_disc() -> Discriminant { - discriminant(&MouseRegionEvent::DownOut(Default::default())) - } - - pub fn scroll_wheel_disc() -> Discriminant { - discriminant(&MouseRegionEvent::ScrollWheel(Default::default())) - } - - pub fn handler_key(&self) -> (Discriminant, Option) { - match self { - MouseRegionEvent::Move(_) => (Self::move_disc(), None), - MouseRegionEvent::Drag(e) => (Self::drag_disc(), e.pressed_button), - MouseRegionEvent::Hover(_) => (Self::hover_disc(), None), - MouseRegionEvent::Down(e) => (Self::down_disc(), Some(e.button)), - MouseRegionEvent::Up(e) => (Self::up_disc(), Some(e.button)), - MouseRegionEvent::Click(e) => (Self::click_disc(), Some(e.button)), - MouseRegionEvent::UpOut(e) => (Self::up_out_disc(), Some(e.button)), - MouseRegionEvent::DownOut(e) => (Self::down_out_disc(), Some(e.button)), - MouseRegionEvent::ScrollWheel(_) => (Self::scroll_wheel_disc(), None), - } - } -} diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index a677ab5b67..cee5388800 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -52,7 +52,7 @@ impl View for OutlineView { ChildView::new(self.picker.clone(), cx).boxed() } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { cx.focus(&self.picker); } diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index 30ad7827ef..0945f6771b 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -116,7 +116,7 @@ impl View for Picker { cx } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { cx.focus(&self.query_editor); } diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index a81231b98f..e4a251de00 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -51,7 +51,7 @@ impl View for ProjectSymbolsView { ChildView::new(self.picker.clone(), cx).boxed() } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { cx.focus(&self.picker); } diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index a43f3eb486..cd7a74ce8e 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -82,7 +82,7 @@ impl View for BufferSearchBar { "BufferSearchBar" } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { cx.focus(&self.query_editor); } diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index eb5bf7d699..8eb8e110e4 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -195,7 +195,7 @@ impl View for ProjectSearchView { } } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { let handle = cx.weak_handle(); cx.update_global(|state: &mut ActiveSearches, cx| { state diff --git a/crates/terminal/src/mappings/mouse.rs b/crates/terminal/src/mappings/mouse.rs index 1616540cff..2254eea5af 100644 --- a/crates/terminal/src/mappings/mouse.rs +++ b/crates/terminal/src/mappings/mouse.rs @@ -6,7 +6,7 @@ use alacritty_terminal::grid::Dimensions; /// with modifications for our circumstances use alacritty_terminal::index::{Column as GridCol, Line as GridLine, Point, Side}; use alacritty_terminal::term::TermMode; -use gpui::scene::ScrollWheelRegionEvent; +use gpui::scene::MouseScrollWheel; use gpui::{geometry::vector::Vector2F, MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent}; use crate::TerminalSize; @@ -115,7 +115,7 @@ impl MouseButton { pub fn scroll_report( point: Point, scroll_lines: i32, - e: &ScrollWheelRegionEvent, + e: &MouseScrollWheel, mode: TermMode, ) -> Option>> { if mode.intersects(TermMode::MOUSE_MODE) { diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 735b00ca62..a18b90e56d 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -53,7 +53,7 @@ use thiserror::Error; use gpui::{ geometry::vector::{vec2f, Vector2F}, keymap::Keystroke, - scene::{DownRegionEvent, DragRegionEvent, ScrollWheelRegionEvent, UpRegionEvent}, + scene::{MouseDown, MouseDrag, MouseScrollWheel, MouseUp}, ClipboardItem, Entity, ModelContext, MouseButton, MouseMovedEvent, MutableAppContext, Task, }; @@ -971,7 +971,7 @@ impl Terminal { } } - pub fn mouse_drag(&mut self, e: DragRegionEvent, origin: Vector2F) { + pub fn mouse_drag(&mut self, e: MouseDrag, origin: Vector2F) { let position = e.position.sub(origin); self.last_mouse_position = Some(position); @@ -997,7 +997,7 @@ impl Terminal { } } - fn drag_line_delta(&mut self, e: DragRegionEvent) -> Option { + fn drag_line_delta(&mut self, e: MouseDrag) -> Option { //TODO: Why do these need to be doubled? Probably the same problem that the IME has let top = e.region.origin_y() + (self.last_content.size.line_height * 2.); let bottom = e.region.lower_left().y() - (self.last_content.size.line_height * 2.); @@ -1011,7 +1011,7 @@ impl Terminal { Some(scroll_delta) } - pub fn mouse_down(&mut self, e: &DownRegionEvent, origin: Vector2F) { + pub fn mouse_down(&mut self, e: &MouseDown, origin: Vector2F) { let position = e.position.sub(origin); let point = grid_point( position, @@ -1050,7 +1050,7 @@ impl Terminal { } } - pub fn mouse_up(&mut self, e: &UpRegionEvent, origin: Vector2F, cx: &mut ModelContext) { + pub fn mouse_up(&mut self, e: &MouseUp, origin: Vector2F, cx: &mut ModelContext) { let settings = cx.global::(); let copy_on_select = settings .terminal_overrides @@ -1095,7 +1095,7 @@ impl Terminal { } ///Scroll the terminal - pub fn scroll_wheel(&mut self, e: ScrollWheelRegionEvent, origin: Vector2F) { + pub fn scroll_wheel(&mut self, e: MouseScrollWheel, origin: Vector2F) { let mouse_mode = self.mouse_mode(e.shift); if let Some(scroll_lines) = self.determine_scroll_lines(&e, mouse_mode) { @@ -1134,11 +1134,7 @@ impl Terminal { self.hyperlink_from_position(self.last_mouse_position); } - fn determine_scroll_lines( - &mut self, - e: &ScrollWheelRegionEvent, - mouse_mode: bool, - ) -> Option { + fn determine_scroll_lines(&mut self, e: &MouseScrollWheel, mouse_mode: bool) -> Option { let scroll_multiplier = if mouse_mode { 1. } else { SCROLL_MULTIPLIER }; match e.phase { diff --git a/crates/terminal/src/terminal_container_view.rs b/crates/terminal/src/terminal_container_view.rs index 5cad16774d..d56631fd4f 100644 --- a/crates/terminal/src/terminal_container_view.rs +++ b/crates/terminal/src/terminal_container_view.rs @@ -174,7 +174,7 @@ impl View for TerminalContainer { } } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { cx.focus(self.content.handle()); } diff --git a/crates/terminal/src/terminal_element.rs b/crates/terminal/src/terminal_element.rs index 823d99c801..7dfe9c785d 100644 --- a/crates/terminal/src/terminal_element.rs +++ b/crates/terminal/src/terminal_element.rs @@ -15,9 +15,8 @@ use gpui::{ }, serde_json::json, text_layout::{Line, RunStyle}, - Element, ElementBox, Event, EventContext, FontCache, KeyDownEvent, ModelContext, MouseButton, - MouseRegion, PaintContext, Quad, SizeConstraint, TextLayoutCache, WeakModelHandle, - WeakViewHandle, + Element, ElementBox, EventContext, FontCache, ModelContext, MouseButton, MouseRegion, + PaintContext, Quad, SizeConstraint, TextLayoutCache, WeakModelHandle, WeakViewHandle, }; use itertools::Itertools; use language::CursorShape; @@ -800,46 +799,6 @@ impl Element for TerminalElement { }); } - fn dispatch_event( - &mut self, - event: &gpui::Event, - _bounds: gpui::geometry::rect::RectF, - _visible_bounds: gpui::geometry::rect::RectF, - _layout: &mut Self::LayoutState, - _paint: &mut Self::PaintState, - cx: &mut gpui::EventContext, - ) -> bool { - if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = event { - if !cx.is_parent_view_focused() { - return false; - } - - if let Some(view) = self.view.upgrade(cx.app) { - view.update(cx.app, |view, cx| { - view.clear_bel(cx); - view.pause_cursor_blinking(cx); - }) - } - - self.terminal - .upgrade(cx.app) - .map(|model_handle| { - model_handle.update(cx.app, |term, cx| { - term.try_keystroke( - keystroke, - cx.global::() - .terminal_overrides - .option_as_meta - .unwrap_or(false), - ) - }) - }) - .unwrap_or(false) - } else { - false - } - } - fn metadata(&self) -> Option<&dyn std::any::Any> { None } diff --git a/crates/terminal/src/terminal_view.rs b/crates/terminal/src/terminal_view.rs index 5ca5eb6dce..f67fa5bb92 100644 --- a/crates/terminal/src/terminal_view.rs +++ b/crates/terminal/src/terminal_view.rs @@ -332,20 +332,35 @@ impl View for TerminalView { .boxed() } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { self.has_new_content = false; self.terminal.read(cx).focus_in(); self.blink_cursors(self.blink_epoch, cx); cx.notify(); } - fn on_focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { self.terminal.update(cx, |terminal, _| { terminal.focus_out(); }); cx.notify(); } + fn key_down(&mut self, event: &gpui::KeyDownEvent, cx: &mut ViewContext) -> bool { + self.clear_bel(cx); + self.pause_cursor_blinking(cx); + + self.terminal.update(cx, |term, cx| { + term.try_keystroke( + &event.keystroke, + cx.global::() + .terminal_overrides + .option_as_meta + .unwrap_or(false), + ) + }) + } + //IME stuff fn selected_text_range(&self, cx: &AppContext) -> Option> { if self diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index 3236120857..1caeae75f5 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -266,7 +266,7 @@ impl View for ThemeSelector { ChildView::new(self.picker.clone(), cx).boxed() } - fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { cx.focus(&self.picker); } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index b7ae7f2ba0..882b501d2e 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1485,7 +1485,7 @@ impl View for Pane { .named("pane") } - fn on_focus_in(&mut self, focused: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, focused: AnyViewHandle, cx: &mut ViewContext) { if let Some(active_item) = self.active_item() { if cx.is_self_focused() { // Pane was focused directly. We need to either focus a view inside the active item, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 04a59c47b1..b9155220f6 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -2659,7 +2659,7 @@ impl View for Workspace { .named("workspace") } - fn on_focus_in(&mut self, view: AnyViewHandle, cx: &mut ViewContext) { + fn focus_in(&mut self, view: AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { cx.focus(&self.active_pane); } else {