From 2186de38ab0ec47478430996a10f2e7126ec65c4 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 7 Apr 2023 11:54:08 -0600 Subject: [PATCH 01/58] Merge AppContext impl blocks --- crates/gpui/src/app.rs | 188 ++++++++++++++++++++--------------------- 1 file changed, 93 insertions(+), 95 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index bc38b28bba..d0e512c081 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -601,6 +601,30 @@ impl AppContext { } } + pub fn background(&self) -> &Arc { + &self.background + } + + pub fn font_cache(&self) -> &Arc { + &self.font_cache + } + + pub fn platform(&self) -> &Arc { + &self.platform + } + + pub fn has_global(&self) -> bool { + self.globals.contains_key(&TypeId::of::()) + } + + pub fn global(&self) -> &T { + if let Some(global) = self.globals.get(&TypeId::of::()) { + global.downcast_ref().unwrap() + } else { + panic!("no global has been added for {}", type_name::()); + } + } + pub fn upgrade(&self) -> App { App(self.weak_self.as_ref().unwrap().upgrade().unwrap()) } @@ -645,12 +669,6 @@ impl AppContext { &self.foreground } - pub fn debug_elements(&self, window_id: usize) -> Option { - self.presenters_and_platform_windows - .get(&window_id) - .and_then(|(presenter, _)| presenter.borrow().debug_elements(self)) - } - pub fn deserialize_action( &self, name: &str, @@ -810,6 +828,75 @@ impl AppContext { window.screen().display_uuid() } + pub fn root_view(&self, window_id: usize) -> Option { + self.windows + .get(&window_id) + .map(|window| window.root_view.clone()) + } + + pub fn root_view_id(&self, window_id: usize) -> Option { + self.windows + .get(&window_id) + .map(|window| window.root_view.id()) + } + + pub fn focused_view_id(&self, window_id: usize) -> Option { + self.windows + .get(&window_id) + .and_then(|window| window.focused_view_id) + } + + pub fn view_ui_name(&self, window_id: usize, view_id: usize) -> Option<&'static str> { + Some(self.views.get(&(window_id, view_id))?.ui_name()) + } + + pub fn view_type_id(&self, window_id: usize, view_id: usize) -> Option { + self.views + .get(&(window_id, view_id)) + .map(|view| view.as_any().type_id()) + } + + /// 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 ancestors(&self, window_id: usize, mut view_id: usize) -> impl Iterator + '_ { + std::iter::once(view_id) + .into_iter() + .chain(std::iter::from_fn(move || { + if let Some(ParentId::View(parent_id)) = self.parents.get(&(window_id, view_id)) { + view_id = *parent_id; + Some(view_id) + } else { + None + } + })) + } + + /// Returns the id of the parent of the given view, or none if the given + /// view is the root. + pub fn parent(&self, window_id: usize, view_id: usize) -> Option { + if let Some(ParentId::View(view_id)) = self.parents.get(&(window_id, view_id)) { + Some(*view_id) + } else { + None + } + } + + pub fn is_child_focused(&self, view: &AnyViewHandle) -> bool { + if let Some(focused_view_id) = self.focused_view_id(view.window_id) { + self.ancestors(view.window_id, focused_view_id) + .skip(1) // Skip self id + .any(|parent| parent == view.view_id) + } else { + false + } + } + + pub fn debug_elements(&self, window_id: usize) -> Option { + self.presenters_and_platform_windows + .get(&window_id) + .and_then(|(presenter, _)| presenter.borrow().debug_elements(self)) + } + pub fn active_labeled_tasks<'a>( &'a self, ) -> impl DoubleEndedIterator + 'a { @@ -2713,95 +2800,6 @@ pub enum ParentId { Root, } -impl AppContext { - pub fn root_view(&self, window_id: usize) -> Option { - self.windows - .get(&window_id) - .map(|window| window.root_view.clone()) - } - - pub fn root_view_id(&self, window_id: usize) -> Option { - self.windows - .get(&window_id) - .map(|window| window.root_view.id()) - } - - pub fn focused_view_id(&self, window_id: usize) -> Option { - self.windows - .get(&window_id) - .and_then(|window| window.focused_view_id) - } - - pub fn view_ui_name(&self, window_id: usize, view_id: usize) -> Option<&'static str> { - Some(self.views.get(&(window_id, view_id))?.ui_name()) - } - - pub fn view_type_id(&self, window_id: usize, view_id: usize) -> Option { - self.views - .get(&(window_id, view_id)) - .map(|view| view.as_any().type_id()) - } - - pub fn background(&self) -> &Arc { - &self.background - } - - pub fn font_cache(&self) -> &Arc { - &self.font_cache - } - - pub fn platform(&self) -> &Arc { - &self.platform - } - - pub fn has_global(&self) -> bool { - self.globals.contains_key(&TypeId::of::()) - } - - pub fn global(&self) -> &T { - if let Some(global) = self.globals.get(&TypeId::of::()) { - global.downcast_ref().unwrap() - } else { - panic!("no global has been added for {}", type_name::()); - } - } - - /// 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 ancestors(&self, window_id: usize, mut view_id: usize) -> impl Iterator + '_ { - std::iter::once(view_id) - .into_iter() - .chain(std::iter::from_fn(move || { - if let Some(ParentId::View(parent_id)) = self.parents.get(&(window_id, view_id)) { - view_id = *parent_id; - Some(view_id) - } else { - None - } - })) - } - - /// Returns the id of the parent of the given view, or none if the given - /// view is the root. - pub fn parent(&self, window_id: usize, view_id: usize) -> Option { - if let Some(ParentId::View(view_id)) = self.parents.get(&(window_id, view_id)) { - Some(*view_id) - } else { - None - } - } - - pub fn is_child_focused(&self, view: &AnyViewHandle) -> bool { - if let Some(focused_view_id) = self.focused_view_id(view.window_id) { - self.ancestors(view.window_id, focused_view_id) - .skip(1) // Skip self id - .any(|parent| parent == view.view_id) - } else { - false - } - } -} - pub struct Window { root_view: AnyViewHandle, focused_view_id: Option, From 9d23a98157c311c2fe8bafc58926852a967ad2a8 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 8 Apr 2023 06:43:39 -0600 Subject: [PATCH 02/58] WIP --- crates/gpui/src/app.rs | 645 ++++++++++---------- crates/gpui/src/app/test_app_context.rs | 105 ++-- crates/gpui/src/app/window_input_handler.rs | 5 +- crates/gpui/src/presenter.rs | 7 +- 4 files changed, 382 insertions(+), 380 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index d0e512c081..86b466ebc5 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -321,6 +321,17 @@ impl App { state.pending_notifications.clear(); result } + + fn update_window T>( + &mut self, + window_id: usize, + callback: F, + ) -> Option { + let mut state = self.0.borrow_mut(); + let result = state.update_window(window_id, callback); + state.pending_notifications.clear(); + result + } } impl AsyncAppContext { @@ -341,6 +352,14 @@ impl AsyncAppContext { self.0.borrow_mut().update(callback) } + fn update_window T>( + &mut self, + window_id: usize, + callback: F, + ) -> Option { + self.0.borrow_mut().update_window(window_id, callback) + } + pub fn add_model(&mut self, build_model: F) -> ModelHandle where T: Entity, @@ -366,7 +385,7 @@ impl AsyncAppContext { } pub fn activate_window(&mut self, window_id: usize) { - self.update(|cx| cx.activate_window(window_id)) + self.update_window(window_id, |cx| cx.activate_window()); } pub fn prompt( @@ -375,8 +394,8 @@ impl AsyncAppContext { level: PromptLevel, msg: &str, answers: &[&str], - ) -> oneshot::Receiver { - self.update(|cx| cx.prompt(window_id, level, msg, answers)) + ) -> Option> { + self.update_window(window_id, |cx| cx.prompt(level, msg, answers)) } pub fn platform(&self) -> Arc { @@ -528,9 +547,6 @@ pub struct AppContext { keystroke_observations: CallbackCollection, active_labeled_task_observations: CallbackCollection<(), ActiveLabeledTasksCallback>, - #[allow(clippy::type_complexity)] - presenters_and_platform_windows: - HashMap>, Box)>, foreground: Rc, pending_effects: VecDeque, pending_notifications: HashSet, @@ -588,7 +604,6 @@ impl AppContext { keystroke_observations: Default::default(), action_dispatch_observations: Default::default(), active_labeled_task_observations: Default::default(), - presenters_and_platform_windows: Default::default(), foreground, pending_effects: VecDeque::new(), pending_notifications: Default::default(), @@ -659,9 +674,7 @@ impl AppContext { } pub fn remove_all_windows(&mut self) { - for (window_id, _) in self.windows.drain() { - self.presenters_and_platform_windows.remove(&window_id); - } + self.windows.clear(); self.flush_effects(); } @@ -782,14 +795,6 @@ impl AppContext { } } - pub fn is_topmost_window_for_position(&self, window_id: usize, position: Vector2F) -> bool { - self.presenters_and_platform_windows - .get(&window_id) - .map_or(false, |(_, window)| { - window.is_topmost_for_position(position) - }) - } - pub fn has_window(&self, window_id: usize) -> bool { self.window_ids() .find(|window| window == &window_id) @@ -800,12 +805,6 @@ impl AppContext { self.windows.keys().copied() } - pub fn activate_window(&self, window_id: usize) { - if let Some((_, window)) = self.presenters_and_platform_windows.get(&window_id) { - window.activate() - } - } - pub fn window_is_active(&self, window_id: usize) -> bool { self.windows .get(&window_id) @@ -818,16 +817,6 @@ impl AppContext { .map_or(false, |window| window.is_fullscreen) } - pub fn window_bounds(&self, window_id: usize) -> Option { - let (_, window) = self.presenters_and_platform_windows.get(&window_id)?; - Some(window.bounds()) - } - - pub fn window_display_uuid(&self, window_id: usize) -> Option { - let (_, window) = self.presenters_and_platform_windows.get(&window_id)?; - window.screen().display_uuid() - } - pub fn root_view(&self, window_id: usize) -> Option { self.windows .get(&window_id) @@ -891,12 +880,6 @@ impl AppContext { } } - pub fn debug_elements(&self, window_id: usize) -> Option { - self.presenters_and_platform_windows - .get(&window_id) - .and_then(|(presenter, _)| presenter.borrow().debug_elements(self)) - } - pub fn active_labeled_tasks<'a>( &'a self, ) -> impl DoubleEndedIterator + 'a { @@ -966,35 +949,23 @@ impl AppContext { result } - fn show_character_palette(&self, window_id: usize) { - let (_, window) = &self.presenters_and_platform_windows[&window_id]; - window.show_character_palette(); - } - - pub fn minimize_window(&self, window_id: usize) { - let (_, window) = &self.presenters_and_platform_windows[&window_id]; - window.minimize(); - } - - pub fn zoom_window(&self, window_id: usize) { - let (_, window) = &self.presenters_and_platform_windows[&window_id]; - window.zoom(); - } - - pub fn toggle_window_full_screen(&self, window_id: usize) { - let (_, window) = &self.presenters_and_platform_windows[&window_id]; - window.toggle_full_screen(); - } - - pub fn prompt( - &self, + pub fn update_window T>( + &mut self, window_id: usize, - level: PromptLevel, - msg: &str, - answers: &[&str], - ) -> oneshot::Receiver { - let (_, window) = &self.presenters_and_platform_windows[&window_id]; - window.prompt(level, msg, answers) + callback: F, + ) -> Option { + self.update(|app_context| { + let mut window = app_context.windows.remove(&window_id)?; + let mut window_context = WindowContext { + app_context, + window: &mut window, + window_id, + }; + + let result = callback(&mut window_context); + app_context.windows.insert(window_id, window); + Some(result) + }) } pub fn prompt_for_paths( @@ -1560,54 +1531,6 @@ impl AppContext { false } - pub fn dispatch_keystroke(&mut self, window_id: usize, keystroke: &Keystroke) -> bool { - if let Some(focused_view_id) = self.focused_view_id(window_id) { - let dispatch_path = self - .ancestors(window_id, focused_view_id) - .filter_map(|view_id| { - self.views - .get(&(window_id, view_id)) - .map(|view| (view_id, view.keymap_context(self))) - }) - .collect(); - - let match_result = self - .keystroke_matcher - .push_keystroke(keystroke.clone(), dispatch_path); - let mut handled_by = None; - - let keystroke_handled = match &match_result { - MatchResult::None => false, - MatchResult::Pending => true, - MatchResult::Matches(matches) => { - for (view_id, action) in matches { - if self.handle_dispatch_action_from_effect( - window_id, - Some(*view_id), - action.as_ref(), - ) { - self.keystroke_matcher.clear_pending(); - handled_by = Some(action.boxed_clone()); - break; - } - } - handled_by.is_some() - } - }; - - self.keystroke( - window_id, - keystroke.clone(), - handled_by, - match_result.clone(), - ); - keystroke_handled - } else { - self.keystroke(window_id, keystroke.clone(), None, MatchResult::None); - false - } - } - pub fn default_global(&mut self) -> &T { let type_id = TypeId::of::(); self.update(|this| { @@ -1696,6 +1619,16 @@ impl AppContext { let root_view = this .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx))) .unwrap(); + let platform_window = + this.platform + .open_window(window_id, window_options, this.foreground.clone()); + let presenter = self.build_presenter( + window_id, + platform_window.titlebar_height(), + platform_window.appearance(), + ); + this.register_platform_window(window_id, &mut presenter, platform_window.as_mut()); + this.windows.insert( window_id, Window { @@ -1704,15 +1637,12 @@ impl AppContext { is_active: false, invalidation: None, is_fullscreen: false, + platform_window, + presenter, }, ); root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx)); - let window = - this.platform - .open_window(window_id, window_options, this.foreground.clone()); - this.register_platform_window(window_id, window); - (window_id, root_view) }) } @@ -1727,6 +1657,15 @@ impl AppContext { let root_view = this .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx))) .unwrap(); + + let mut platform_window = this.platform.add_status_item(); + let mut presenter = self.build_presenter( + window_id, + platform_window.titlebar_height(), + platform_window.appearance(), + ); + this.register_platform_window(window_id, &mut presenter, platform_window.as_mut()); + let focused_view_id = root_view.id(); this.windows.insert( window_id, @@ -1736,13 +1675,12 @@ impl AppContext { is_active: false, invalidation: None, is_fullscreen: false, + platform_window, + presenter, }, ); root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx)); - let status_item = this.platform.add_status_item(); - this.register_platform_window(window_id, status_item); - (window_id, root_view) }) } @@ -1754,89 +1692,79 @@ impl AppContext { fn register_platform_window( &mut self, window_id: usize, - mut window: Box, + presenter: &mut Presenter, + platform_window: &mut dyn platform::Window, ) { - let presenter = Rc::new(RefCell::new(self.build_presenter( - window_id, - window.titlebar_height(), - window.appearance(), - ))); - { let mut app = self.upgrade(); - let presenter = Rc::downgrade(&presenter); - window.on_event(Box::new(move |event| { - app.update(|cx| { - if let Some(presenter) = presenter.upgrade() { - if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = &event { - if cx.dispatch_keystroke(window_id, keystroke) { - return true; - } + platform_window.on_event(Box::new(move |event| { + app.update_window(window_id, |cx| { + if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = &event { + if cx.dispatch_keystroke(keystroke) { + return true; } - - presenter.borrow_mut().dispatch_event(event, false, cx) - } else { - false } + + cx.dispatch_event(event, false) }) + .unwrap_or(false) })); } { let mut app = self.upgrade(); - window.on_active_status_change(Box::new(move |is_active| { + platform_window.on_active_status_change(Box::new(move |is_active| { app.update(|cx| cx.window_changed_active_status(window_id, is_active)) })); } { let mut app = self.upgrade(); - window.on_resize(Box::new(move || { + platform_window.on_resize(Box::new(move || { app.update(|cx| cx.window_was_resized(window_id)) })); } { let mut app = self.upgrade(); - window.on_moved(Box::new(move || { + platform_window.on_moved(Box::new(move || { app.update(|cx| cx.window_was_moved(window_id)) })); } { let mut app = self.upgrade(); - window.on_fullscreen(Box::new(move |is_fullscreen| { + platform_window.on_fullscreen(Box::new(move |is_fullscreen| { app.update(|cx| cx.window_was_fullscreen_changed(window_id, is_fullscreen)) })); } { let mut app = self.upgrade(); - window.on_close(Box::new(move || { + platform_window.on_close(Box::new(move || { app.update(|cx| cx.remove_window(window_id)); })); } { let mut app = self.upgrade(); - window.on_appearance_changed(Box::new(move || app.update(|cx| cx.refresh_windows()))); + platform_window + .on_appearance_changed(Box::new(move || app.update(|cx| cx.refresh_windows()))); } - window.set_input_handler(Box::new(WindowInputHandler { + platform_window.set_input_handler(Box::new(WindowInputHandler { app: self.upgrade().0, window_id, })); - let scene = presenter.borrow_mut().build_scene( - window.content_size(), - window.scale_factor(), + let scene = presenter.build_scene( + platform_window.content_size(), + platform_window.scale_factor(), false, self, ); - window.present_scene(scene); - self.presenters_and_platform_windows - .insert(window_id, (presenter.clone(), window)); + platform_window.present_scene(scene); } pub fn replace_root_view(&mut self, window_id: usize, build_root_view: F) -> ViewHandle @@ -1857,7 +1785,6 @@ impl AppContext { pub fn remove_window(&mut self, window_id: usize) { self.windows.remove(&window_id); - self.presenters_and_platform_windows.remove(&window_id); self.flush_effects(); } @@ -2217,30 +2144,20 @@ impl AppContext { } fn update_windows(&mut self) { - let mut invalidations: HashMap<_, _> = Default::default(); for (window_id, window) in &mut self.windows { - if let Some(invalidation) = window.invalidation.take() { - invalidations.insert(*window_id, invalidation); - } - } - - for (window_id, mut invalidation) in invalidations { - if let Some((presenter, mut window)) = - self.presenters_and_platform_windows.remove(&window_id) - { - { - let mut presenter = presenter.borrow_mut(); - presenter.invalidate(&mut invalidation, window.appearance(), self); - let scene = presenter.build_scene( - window.content_size(), - window.scale_factor(), - false, - self, - ); - window.present_scene(scene); - } - self.presenters_and_platform_windows - .insert(window_id, (presenter, window)); + if let Some(mut invalidation) = window.invalidation.take() { + window.presenter.invalidate( + &mut invalidation, + window.platform_window.appearance(), + self, + ); + let scene = window.presenter.build_scene( + window.platform_window.content_size(), + window.platform_window.scale_factor(), + false, + self, + ); + window.platform_window.present_scene(scene); } } } @@ -2306,20 +2223,21 @@ impl AppContext { } fn perform_window_refresh(&mut self) { - let mut presenters = mem::take(&mut self.presenters_and_platform_windows); - for (window_id, (presenter, window)) in &mut presenters { - let mut invalidation = self.windows.get_mut(window_id).unwrap().invalidation.take(); - let mut presenter = presenter.borrow_mut(); - presenter.refresh( - invalidation.as_mut().unwrap_or(&mut Default::default()), - window.appearance(), + for window in self.windows.values_mut() { + let mut invalidation = window.invalidation.take().unwrap_or_default(); + window.presenter.invalidate( + &mut invalidation, + window.platform_window.appearance(), self, ); - let scene = - presenter.build_scene(window.content_size(), window.scale_factor(), true, self); - window.present_scene(scene); + let scene = window.presenter.build_scene( + window.platform_window.content_size(), + window.platform_window.scale_factor(), + true, + self, + ); + window.platform_window.present_scene(scene); } - self.presenters_and_platform_windows = presenters; } fn emit_global_event(&mut self, payload: Box) { @@ -2365,33 +2283,19 @@ impl AppContext { } fn handle_fullscreen_effect(&mut self, window_id: usize, is_fullscreen: bool) { - //Short circuit evaluation if we're already g2g - if self - .windows - .get(&window_id) - .map(|w| w.is_fullscreen == is_fullscreen) - .unwrap_or(false) - { - return; - } + self.update_window(window_id, |cx| { + cx.window.is_fullscreen = is_fullscreen; - self.update(|this| { - let window = this.windows.get_mut(&window_id)?; - window.is_fullscreen = is_fullscreen; - - let mut fullscreen_observations = this.window_fullscreen_observations.clone(); - fullscreen_observations.emit(window_id, this, |callback, this| { + let mut fullscreen_observations = cx.window_fullscreen_observations.clone(); + fullscreen_observations.emit(window_id, cx, |callback, this| { callback(is_fullscreen, this) }); - if let Some((uuid, bounds)) = this - .window_display_uuid(window_id) - .zip(this.window_bounds(window_id)) - { - let mut bounds_observations = this.window_bounds_observations.clone(); - bounds_observations.emit(window_id, this, |callback, this| { - callback(bounds, uuid, this) - }); + if let Some(uuid) = cx.window_display_uuid() { + let bounds = cx.window_bounds(); + let mut bounds_observations = cx.window_bounds_observations.clone(); + bounds_observations + .emit(window_id, cx, |callback, this| callback(bounds, uuid, this)); } Some(()) @@ -2563,23 +2467,27 @@ impl AppContext { mut callback: WindowShouldCloseSubscriptionCallback, ) { let mut app = self.upgrade(); - if let Some((_, window)) = self.presenters_and_platform_windows.get_mut(&window_id) { - window.on_should_close(Box::new(move || app.update(|cx| callback(cx)))) + if let Some(window) = self.windows.get_mut(&window_id) { + window + .platform_window + .on_should_close(Box::new(move || app.update(|cx| callback(cx)))) } } fn handle_window_moved(&mut self, window_id: usize) { - if let Some((display, bounds)) = self - .window_display_uuid(window_id) - .zip(self.window_bounds(window_id)) - { - self.window_bounds_observations - .clone() - .emit(window_id, self, move |callback, this| { - callback(bounds, display, this); - true - }); - } + self.update_window(window_id, |cx| { + if let Some(display) = cx.window_display_uuid() { + let bounds = cx.window_bounds(); + cx.window_bounds_observations.clone().emit( + window_id, + self, + move |callback, this| { + callback(bounds, display, this); + true + }, + ); + } + }); } fn handle_active_labeled_tasks_changed_effect(&mut self) { @@ -2806,6 +2714,8 @@ pub struct Window { is_active: bool, is_fullscreen: bool, invalidation: Option, + presenter: Presenter, + platform_window: Box, } #[derive(Default, Clone)] @@ -3584,6 +3494,138 @@ impl DerefMut for ModelContext<'_, M> { } } +pub struct WindowContext<'a: 'b, 'b> { + app_context: &'a mut AppContext, + window: &'b mut Window, + window_id: usize, +} + +impl Deref for WindowContext<'_, '_> { + type Target = AppContext; + + fn deref(&self) -> &Self::Target { + self.app_context + } +} + +impl DerefMut for WindowContext<'_, '_> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.app_context + } +} + +impl WindowContext<'_, '_> { + pub fn dispatch_keystroke(&mut self, keystroke: &Keystroke) -> bool { + let window_id = self.window_id; + if let Some(focused_view_id) = self.focused_view_id(window_id) { + let dispatch_path = self + .ancestors(window_id, focused_view_id) + .filter_map(|view_id| { + self.views + .get(&(window_id, view_id)) + .map(|view| (view_id, view.keymap_context(self))) + }) + .collect(); + + let match_result = self + .keystroke_matcher + .push_keystroke(keystroke.clone(), dispatch_path); + let mut handled_by = None; + + let keystroke_handled = match &match_result { + MatchResult::None => false, + MatchResult::Pending => true, + MatchResult::Matches(matches) => { + for (view_id, action) in matches { + if self.handle_dispatch_action_from_effect( + window_id, + Some(*view_id), + action.as_ref(), + ) { + self.keystroke_matcher.clear_pending(); + handled_by = Some(action.boxed_clone()); + break; + } + } + handled_by.is_some() + } + }; + + self.keystroke( + window_id, + keystroke.clone(), + handled_by, + match_result.clone(), + ); + keystroke_handled + } else { + self.keystroke(window_id, keystroke.clone(), None, MatchResult::None); + false + } + } + + pub fn dispatch_event(&mut self, event: Event, event_reused: bool) -> bool { + self.window + .presenter + .dispatch_event(event, event_reused, self) + } + + pub fn set_window_title(&mut self, title: &str) { + self.window.platform_window.set_title(title); + } + + pub fn set_window_edited(&mut self, edited: bool) { + self.window.platform_window.set_edited(edited); + } + + pub fn is_topmost_window_for_position(&self, position: Vector2F) -> bool { + self.window + .platform_window + .is_topmost_for_position(position) + } + + pub fn activate_window(&self) { + self.window.platform_window.activate(); + } + + pub fn window_bounds(&self) -> WindowBounds { + self.window.platform_window.bounds() + } + + pub fn window_display_uuid(&self) -> Option { + self.window.platform_window.screen().display_uuid() + } + + pub fn debug_elements(&self) -> Option { + self.window.presenter.debug_elements(self) + } + + fn show_character_palette(&self) { + self.window.platform_window.show_character_palette(); + } + + pub fn minimize_window(&self) { + self.window.platform_window.minimize(); + } + + pub fn zoom_window(&self) { + self.window.platform_window.zoom(); + } + + pub fn toggle_window_full_screen(&self) { + self.window.platform_window.toggle_full_screen(); + } + + pub fn prompt( + &self, + level: PromptLevel, + msg: &str, + answers: &[&str], + ) -> oneshot::Receiver { + self.window.platform_window.prompt(level, msg, answers) + } +} + pub struct ViewContext<'a, T: ?Sized> { app: &'a mut AppContext, window_id: usize, @@ -3633,31 +3675,6 @@ impl<'a, T: View> ViewContext<'a, T> { self.app.platform() } - pub fn show_character_palette(&self) { - self.app.show_character_palette(self.window_id); - } - - pub fn minimize_window(&self) { - self.app.minimize_window(self.window_id) - } - - pub fn zoom_window(&self) { - self.app.zoom_window(self.window_id) - } - - pub fn toggle_full_screen(&self) { - self.app.toggle_window_full_screen(self.window_id) - } - - pub fn prompt( - &self, - level: PromptLevel, - msg: &str, - answers: &[&str], - ) -> oneshot::Receiver { - self.app.prompt(self.window_id, level, msg, answers) - } - pub fn prompt_for_paths( &self, options: PathPromptOptions, @@ -3673,10 +3690,6 @@ impl<'a, T: View> ViewContext<'a, T> { self.app.reveal_path(path) } - pub fn debug_elements(&self) -> crate::json::Value { - self.app.debug_elements(self.window_id).unwrap() - } - pub fn focus(&mut self, handle: &AnyViewHandle) { self.app.focus(handle.window_id, Some(handle.view_id)); } @@ -3703,20 +3716,6 @@ impl<'a, T: View> ViewContext<'a, T> { self.app.focus(self.window_id, None); } - pub fn set_window_title(&mut self, title: &str) { - let window_id = self.window_id(); - if let Some((_, window)) = self.presenters_and_platform_windows.get_mut(&window_id) { - window.set_title(title); - } - } - - pub fn set_window_edited(&mut self, edited: bool) { - let window_id = self.window_id(); - if let Some((_, window)) = self.presenters_and_platform_windows.get_mut(&window_id) { - window.set_edited(edited); - } - } - pub fn on_window_should_close(&mut self, mut callback: F) where F: 'static + FnMut(&mut T, &mut ViewContext) -> bool, @@ -5492,19 +5491,20 @@ mod tests { let (window_id, _) = cx.add_window(Default::default(), |_| View { mouse_down_count: mouse_down_count.clone(), }); - let presenter = cx.presenters_and_platform_windows[&window_id].0.clone(); - // Ensure window's root element is in a valid lifecycle state. - presenter.borrow_mut().dispatch_event( - Event::MouseDown(MouseButtonEvent { - position: Default::default(), - button: MouseButton::Left, - modifiers: Default::default(), - click_count: 1, - }), - false, - cx, - ); - assert_eq!(mouse_down_count.load(SeqCst), 1); + + cx.update_window(window_id, |cx| { + // Ensure window's root element is in a valid lifecycle state. + cx.dispatch_event( + Event::MouseDown(MouseButtonEvent { + position: Default::default(), + button: MouseButton::Left, + modifiers: Default::default(), + click_count: 1, + }), + false, + ); + assert_eq!(mouse_down_count.load(SeqCst), 1); + }); } #[crate::test(self)] @@ -6553,19 +6553,28 @@ mod tests { } }); - cx.dispatch_keystroke(window_id, &Keystroke::parse("a").unwrap()); + cx.update_window(window_id, |cx| { + cx.dispatch_keystroke(&Keystroke::parse("a").unwrap()) + }); assert_eq!(&*actions.borrow(), &["2 a"]); actions.borrow_mut().clear(); - cx.dispatch_keystroke(window_id, &Keystroke::parse("b").unwrap()); + cx.update_window(window_id, |cx| { + cx.dispatch_keystroke(&Keystroke::parse("b").unwrap()); + }); + assert_eq!(&*actions.borrow(), &["3 b", "2 b", "1 b", "global b"]); actions.borrow_mut().clear(); - cx.dispatch_keystroke(window_id, &Keystroke::parse("c").unwrap()); + cx.update_window(window_id, |cx| { + cx.dispatch_keystroke(&Keystroke::parse("c").unwrap()); + }); assert_eq!(&*actions.borrow(), &["3 c"]); actions.borrow_mut().clear(); - cx.dispatch_keystroke(window_id, &Keystroke::parse("d").unwrap()); + cx.update_window(window_id, |cx| { + cx.dispatch_keystroke(&Keystroke::parse("d").unwrap()); + }); assert_eq!(&*actions.borrow(), &["2 d"]); actions.borrow_mut().clear(); } @@ -6836,46 +6845,54 @@ mod tests { } let (window_id, root_view) = cx.add_window(Default::default(), |_| View(0)); - let presenter = cx.presenters_and_platform_windows[&window_id].0.clone(); - - assert_eq!( - presenter.borrow().rendered_views[&root_view.id()].name(), - Some("render count: 0") - ); + cx.update_window(window_id, |cx| { + assert_eq!( + cx.window.presenter.rendered_views[&root_view.id()].name(), + Some("render count: 0") + ); + }); let view = cx.add_view(&root_view, |cx| { cx.refresh_windows(); View(0) }); - assert_eq!( - presenter.borrow().rendered_views[&root_view.id()].name(), - Some("render count: 1") - ); - assert_eq!( - presenter.borrow().rendered_views[&view.id()].name(), - Some("render count: 0") - ); + cx.update_window(window_id, |cx| { + assert_eq!( + cx.window.presenter.rendered_views[&root_view.id()].name(), + Some("render count: 1") + ); + assert_eq!( + cx.window.presenter.rendered_views[&view.id()].name(), + Some("render count: 0") + ); + }); cx.update(|cx| cx.refresh_windows()); - assert_eq!( - presenter.borrow().rendered_views[&root_view.id()].name(), - Some("render count: 2") - ); - assert_eq!( - presenter.borrow().rendered_views[&view.id()].name(), - Some("render count: 1") - ); + + cx.update_window(window_id, |cx| { + assert_eq!( + cx.window.presenter.rendered_views[&root_view.id()].name(), + Some("render count: 2") + ); + assert_eq!( + cx.window.presenter.rendered_views[&view.id()].name(), + Some("render count: 1") + ); + }); cx.update(|cx| { cx.refresh_windows(); drop(view); }); - assert_eq!( - presenter.borrow().rendered_views[&root_view.id()].name(), - Some("render count: 3") - ); - assert_eq!(presenter.borrow().rendered_views.len(), 1); + + cx.update_window(window_id, |cx| { + assert_eq!( + cx.window.presenter.rendered_views[&root_view.id()].name(), + Some("render count: 3") + ); + assert_eq!(cx.window.presenter.rendered_views.len(), 1); + }); } #[crate::test(self)] diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index ac2f5408db..84fe2bafda 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -84,31 +84,28 @@ impl TestAppContext { } pub fn dispatch_keystroke(&mut self, window_id: usize, keystroke: Keystroke, is_held: bool) { - let handled = self.cx.borrow_mut().update(|cx| { - let presenter = cx - .presenters_and_platform_windows - .get(&window_id) - .unwrap() - .0 - .clone(); + let handled = self + .cx + .borrow_mut() + .update_window(window_id, |cx| { + if cx.dispatch_keystroke(&keystroke) { + return true; + } - if cx.dispatch_keystroke(window_id, &keystroke) { - return true; - } + if cx.window.presenter.dispatch_event( + Event::KeyDown(KeyDownEvent { + keystroke: keystroke.clone(), + is_held, + }), + false, + cx, + ) { + return true; + } - if presenter.borrow_mut().dispatch_event( - Event::KeyDown(KeyDownEvent { - keystroke: keystroke.clone(), - is_held, - }), - false, - cx, - ) { - return true; - } - - false - }); + false + }) + .unwrap_or(false); if !handled && !keystroke.cmd && !keystroke.ctrl { WindowInputHandler { @@ -244,7 +241,7 @@ impl TestAppContext { use postage::prelude::Sink as _; let mut done_tx = self - .window_mut(window_id) + .platform_window_mut(window_id) .pending_prompts .borrow_mut() .pop_front() @@ -253,20 +250,23 @@ impl TestAppContext { } pub fn has_pending_prompt(&self, window_id: usize) -> bool { - let window = self.window_mut(window_id); + let window = self.platform_window_mut(window_id); let prompts = window.pending_prompts.borrow_mut(); !prompts.is_empty() } pub fn current_window_title(&self, window_id: usize) -> Option { - self.window_mut(window_id).title.clone() + self.platform_window_mut(window_id).title.clone() } pub fn simulate_window_close(&self, window_id: usize) -> bool { - let handler = self.window_mut(window_id).should_close_handler.take(); + let handler = self + .platform_window_mut(window_id) + .should_close_handler + .take(); if let Some(mut handler) = handler { let should_close = handler(); - self.window_mut(window_id).should_close_handler = Some(handler); + self.platform_window_mut(window_id).should_close_handler = Some(handler); should_close } else { false @@ -274,47 +274,34 @@ impl TestAppContext { } pub fn simulate_window_resize(&self, window_id: usize, size: Vector2F) { - let mut window = self.window_mut(window_id); + let mut window = self.platform_window_mut(window_id); window.size = size; let mut handlers = mem::take(&mut window.resize_handlers); drop(window); for handler in &mut handlers { handler(); } - self.window_mut(window_id).resize_handlers = handlers; + self.platform_window_mut(window_id).resize_handlers = handlers; } pub fn simulate_window_activation(&self, to_activate: Option) { - let mut handlers = BTreeMap::new(); - { - let mut cx = self.cx.borrow_mut(); - for (window_id, (_, window)) in &mut cx.presenters_and_platform_windows { - let window = window - .as_any_mut() - .downcast_mut::() - .unwrap(); - handlers.insert( - *window_id, - mem::take(&mut window.active_status_change_handlers), - ); - } - }; - let mut handlers = handlers.into_iter().collect::>(); - handlers.sort_unstable_by_key(|(window_id, _)| Some(*window_id) == to_activate); - - for (window_id, mut window_handlers) in handlers { - for window_handler in &mut window_handlers { - window_handler(Some(window_id) == to_activate); + self.cx.borrow_mut().update(|cx| { + for window_id in cx + .windows + .keys() + .filter(|window_id| Some(**window_id) != to_activate) + { + cx.window_changed_active_status(*window_id, false) } - self.window_mut(window_id) - .active_status_change_handlers - .extend(window_handlers); - } + if let Some(to_activate) = to_activate { + cx.window_changed_active_status(to_activate, true) + } + }); } pub fn is_window_edited(&self, window_id: usize) -> bool { - self.window_mut(window_id).edited + self.platform_window_mut(window_id).edited } pub fn leak_detector(&self) -> Arc> { @@ -337,13 +324,11 @@ impl TestAppContext { self.assert_dropped(weak); } - fn window_mut(&self, window_id: usize) -> std::cell::RefMut { + fn platform_window_mut(&self, window_id: usize) -> std::cell::RefMut { std::cell::RefMut::map(self.cx.borrow_mut(), |state| { - let (_, window) = state - .presenters_and_platform_windows - .get_mut(&window_id) - .unwrap(); + let window = state.windows.get_mut(&window_id).unwrap(); let test_window = window + .platform_window .as_any_mut() .downcast_mut::() .unwrap(); diff --git a/crates/gpui/src/app/window_input_handler.rs b/crates/gpui/src/app/window_input_handler.rs index f3c7a742b5..997ec1c7a5 100644 --- a/crates/gpui/src/app/window_input_handler.rs +++ b/crates/gpui/src/app/window_input_handler.rs @@ -91,8 +91,7 @@ impl InputHandler for WindowInputHandler { fn rect_for_range(&self, range_utf16: Range) -> Option { let app = self.app.borrow(); - let (presenter, _) = app.presenters_and_platform_windows.get(&self.window_id)?; - let presenter = presenter.borrow(); - presenter.rect_for_text_range(range_utf16, &app) + let window = app.windows.get(&self.window_id)?; + window.presenter.rect_for_text_range(range_utf16, &app) } } diff --git a/crates/gpui/src/presenter.rs b/crates/gpui/src/presenter.rs index 0615b1117d..e11ae63c0b 100644 --- a/crates/gpui/src/presenter.rs +++ b/crates/gpui/src/presenter.rs @@ -315,9 +315,10 @@ impl Presenter { } } - if cx.is_topmost_window_for_position(self.window_id, *position) { - cx.platform().set_cursor_style(style_to_assign); - } + // TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // if cx.is_topmost_window_for_position(self.window_id, *position) { + // cx.platform().set_cursor_style(style_to_assign); + // } if !event_reused { if pressed_button.is_some() { From 7536645eea9000d0abfbf4c64e3e727447d2c1cf Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 8 Apr 2023 08:01:05 -0600 Subject: [PATCH 03/58] WIP --- crates/diagnostics/src/diagnostics.rs | 2 +- crates/editor/src/element.rs | 4 +- crates/gpui/src/app.rs | 340 +++------- crates/gpui/src/app/test_app_context.rs | 12 +- .../gpui/src/{presenter.rs => app/window.rs} | 581 +++++++++++------- crates/gpui/src/app/window_input_handler.rs | 7 +- crates/gpui/src/elements.rs | 8 +- crates/gpui/src/elements/align.rs | 2 +- crates/gpui/src/elements/canvas.rs | 2 +- crates/gpui/src/elements/constrained_box.rs | 2 +- crates/gpui/src/elements/container.rs | 2 +- crates/gpui/src/elements/empty.rs | 2 +- crates/gpui/src/elements/expanded.rs | 2 +- crates/gpui/src/elements/flex.rs | 2 +- crates/gpui/src/elements/hook.rs | 2 +- crates/gpui/src/elements/image.rs | 5 +- crates/gpui/src/elements/label.rs | 2 +- crates/gpui/src/elements/list.rs | 6 +- crates/gpui/src/elements/overlay.rs | 2 +- crates/gpui/src/elements/stack.rs | 2 +- crates/gpui/src/elements/svg.rs | 5 +- crates/gpui/src/elements/text.rs | 14 +- crates/gpui/src/elements/tooltip.rs | 2 +- crates/gpui/src/elements/uniform_list.rs | 2 +- crates/gpui/src/gpui.rs | 3 +- crates/gpui/src/platform/test.rs | 2 +- 26 files changed, 496 insertions(+), 519 deletions(-) rename crates/gpui/src/{presenter.rs => app/window.rs} (72%) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 0ac282d199..72337c4696 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -1177,7 +1177,7 @@ mod tests { } fn editor_blocks(editor: &ViewHandle, cx: &mut AppContext) -> Vec<(u32, String)> { - let mut presenter = cx.build_presenter(editor.id(), 0., Default::default()); + let mut presenter = cx.build_window(editor.id(), 0., Default::default()); let mut cx = presenter.build_layout_context(Default::default(), false, cx); cx.render(editor, |editor, cx| { let snapshot = editor.snapshot(cx); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 779a173c34..96d84f59af 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -2531,7 +2531,7 @@ mod tests { let layouts = editor.update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); - let mut presenter = cx.build_presenter(window_id, 30., Default::default()); + let mut presenter = cx.build_window(window_id, 30., Default::default()); let layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx); element .layout_line_numbers(0..6, &Default::default(), false, &snapshot, &layout_cx) @@ -2568,7 +2568,7 @@ mod tests { let mut element = EditorElement::new(editor.downgrade(), editor.read(cx).style(cx)); let mut scene = SceneBuilder::new(1.0); - let mut presenter = cx.build_presenter(window_id, 30., Default::default()); + let mut presenter = cx.build_window(window_id, 30., Default::default()); let mut layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx); let (size, mut state) = element.layout( SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)), diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 86b466ebc5..163ff86fcd 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -4,6 +4,7 @@ mod menu; pub(crate) mod ref_counts; #[cfg(any(test, feature = "test-support"))] pub mod test_app_context; +pub(crate) mod window; mod window_input_handler; use std::{ @@ -23,7 +24,6 @@ use std::{ use anyhow::{anyhow, Context, Result}; use parking_lot::Mutex; -use pathfinder_geometry::vector::Vector2F; use postage::oneshot; use smallvec::SmallVec; use smol::prelude::*; @@ -48,8 +48,8 @@ use crate::{ self, Appearance, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, MouseButton, PathPromptOptions, Platform, PromptLevel, WindowBounds, WindowOptions, }, - presenter::Presenter, util::post_inc, + window::{Window, WindowContext}, AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId, TextLayoutCache, }; @@ -1622,25 +1622,10 @@ impl AppContext { let platform_window = this.platform .open_window(window_id, window_options, this.foreground.clone()); - let presenter = self.build_presenter( - window_id, - platform_window.titlebar_height(), - platform_window.appearance(), - ); - this.register_platform_window(window_id, &mut presenter, platform_window.as_mut()); + let window = + this.build_window(window_id, root_view.clone().into_any(), platform_window); - this.windows.insert( - window_id, - Window { - root_view: root_view.clone().into_any(), - focused_view_id: Some(root_view.id()), - is_active: false, - invalidation: None, - is_fullscreen: false, - platform_window, - presenter, - }, - ); + this.windows.insert(window_id, window); root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx)); (window_id, root_view) @@ -1658,27 +1643,11 @@ impl AppContext { .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx))) .unwrap(); - let mut platform_window = this.platform.add_status_item(); - let mut presenter = self.build_presenter( - window_id, - platform_window.titlebar_height(), - platform_window.appearance(), - ); - this.register_platform_window(window_id, &mut presenter, platform_window.as_mut()); + let platform_window = this.platform.add_status_item(); + let window = + this.build_window(window_id, root_view.clone().into_any(), platform_window); - let focused_view_id = root_view.id(); - this.windows.insert( - window_id, - Window { - root_view: root_view.clone().into_any(), - focused_view_id: Some(focused_view_id), - is_active: false, - invalidation: None, - is_fullscreen: false, - platform_window, - presenter, - }, - ); + this.windows.insert(window_id, window); root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx)); (window_id, root_view) @@ -1689,12 +1658,33 @@ impl AppContext { self.remove_window(id); } - fn register_platform_window( + pub fn replace_root_view(&mut self, window_id: usize, build_root_view: F) -> ViewHandle + where + T: View, + F: FnOnce(&mut ViewContext) -> T, + { + self.update(|this| { + let root_view = this + .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx))) + .unwrap(); + let window = this.windows.get_mut(&window_id).unwrap(); + window.root_view = root_view.clone().into_any(); + window.focused_view_id = Some(root_view.id()); + root_view + }) + } + + pub fn remove_window(&mut self, window_id: usize) { + self.windows.remove(&window_id); + self.flush_effects(); + } + + pub fn build_window( &mut self, window_id: usize, - presenter: &mut Presenter, - platform_window: &mut dyn platform::Window, - ) { + root_view: AnyViewHandle, + mut platform_window: Box, + ) -> Window { { let mut app = self.upgrade(); @@ -1758,51 +1748,19 @@ impl AppContext { window_id, })); - let scene = presenter.build_scene( - platform_window.content_size(), - platform_window.scale_factor(), - false, - self, - ); - platform_window.present_scene(scene); - } - - pub fn replace_root_view(&mut self, window_id: usize, build_root_view: F) -> ViewHandle - where - T: View, - F: FnOnce(&mut ViewContext) -> T, - { - self.update(|this| { - let root_view = this - .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx))) - .unwrap(); - let window = this.windows.get_mut(&window_id).unwrap(); - window.root_view = root_view.clone().into_any(); - window.focused_view_id = Some(root_view.id()); - root_view - }) - } - - pub fn remove_window(&mut self, window_id: usize) { - self.windows.remove(&window_id); - self.flush_effects(); - } - - pub fn build_presenter( - &mut self, - window_id: usize, - titlebar_height: f32, - appearance: Appearance, - ) -> Presenter { - Presenter::new( + let mut window = Window::new( window_id, - titlebar_height, - appearance, + root_view, + platform_window, self.font_cache.clone(), TextLayoutCache::new(self.platform.fonts()), self.assets.clone(), self, - ) + ); + + let scene = WindowContext::new(self, &mut window, window_id).build_scene(false); + window.platform_window.present_scene(scene); + window } pub fn add_view(&mut self, parent_handle: &AnyViewHandle, build_view: F) -> ViewHandle @@ -2144,21 +2102,16 @@ impl AppContext { } fn update_windows(&mut self) { - for (window_id, window) in &mut self.windows { - if let Some(mut invalidation) = window.invalidation.take() { - window.presenter.invalidate( - &mut invalidation, - window.platform_window.appearance(), - self, - ); - let scene = window.presenter.build_scene( - window.platform_window.content_size(), - window.platform_window.scale_factor(), - false, - self, - ); - window.platform_window.present_scene(scene); - } + let window_ids = self.windows.keys().cloned().collect::>(); + for window_id in window_ids { + self.update_window(window_id, |cx| { + if let Some(mut invalidation) = cx.window.invalidation.take() { + let appearance = cx.window.platform_window.appearance(); + cx.invalidate(&mut invalidation, appearance); + let scene = cx.build_scene(false); + cx.window.platform_window.present_scene(scene); + } + }); } } @@ -2223,20 +2176,14 @@ impl AppContext { } fn perform_window_refresh(&mut self) { - for window in self.windows.values_mut() { - let mut invalidation = window.invalidation.take().unwrap_or_default(); - window.presenter.invalidate( - &mut invalidation, - window.platform_window.appearance(), - self, - ); - let scene = window.presenter.build_scene( - window.platform_window.content_size(), - window.platform_window.scale_factor(), - true, - self, - ); - window.platform_window.present_scene(scene); + let window_ids = self.windows.keys().cloned().collect::>(); + for window_id in window_ids { + self.update_window(window_id, |cx| { + let mut invalidation = cx.window.invalidation.take().unwrap_or_default(); + cx.invalidate(&mut invalidation, cx.window.platform_window.appearance()); + let scene = cx.build_scene(true); + cx.window.platform_window.present_scene(scene); + }); } } @@ -2478,14 +2425,12 @@ impl AppContext { self.update_window(window_id, |cx| { if let Some(display) = cx.window_display_uuid() { let bounds = cx.window_bounds(); - cx.window_bounds_observations.clone().emit( - window_id, - self, - move |callback, this| { + cx.window_bounds_observations + .clone() + .emit(window_id, cx, move |callback, this| { callback(bounds, display, this); true - }, - ); + }); } }); } @@ -2708,16 +2653,6 @@ pub enum ParentId { Root, } -pub struct Window { - root_view: AnyViewHandle, - focused_view_id: Option, - is_active: bool, - is_fullscreen: bool, - invalidation: Option, - presenter: Presenter, - platform_window: Box, -} - #[derive(Default, Clone)] pub struct WindowInvalidation { pub updated: HashSet, @@ -3494,138 +3429,6 @@ impl DerefMut for ModelContext<'_, M> { } } -pub struct WindowContext<'a: 'b, 'b> { - app_context: &'a mut AppContext, - window: &'b mut Window, - window_id: usize, -} - -impl Deref for WindowContext<'_, '_> { - type Target = AppContext; - - fn deref(&self) -> &Self::Target { - self.app_context - } -} - -impl DerefMut for WindowContext<'_, '_> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.app_context - } -} - -impl WindowContext<'_, '_> { - pub fn dispatch_keystroke(&mut self, keystroke: &Keystroke) -> bool { - let window_id = self.window_id; - if let Some(focused_view_id) = self.focused_view_id(window_id) { - let dispatch_path = self - .ancestors(window_id, focused_view_id) - .filter_map(|view_id| { - self.views - .get(&(window_id, view_id)) - .map(|view| (view_id, view.keymap_context(self))) - }) - .collect(); - - let match_result = self - .keystroke_matcher - .push_keystroke(keystroke.clone(), dispatch_path); - let mut handled_by = None; - - let keystroke_handled = match &match_result { - MatchResult::None => false, - MatchResult::Pending => true, - MatchResult::Matches(matches) => { - for (view_id, action) in matches { - if self.handle_dispatch_action_from_effect( - window_id, - Some(*view_id), - action.as_ref(), - ) { - self.keystroke_matcher.clear_pending(); - handled_by = Some(action.boxed_clone()); - break; - } - } - handled_by.is_some() - } - }; - - self.keystroke( - window_id, - keystroke.clone(), - handled_by, - match_result.clone(), - ); - keystroke_handled - } else { - self.keystroke(window_id, keystroke.clone(), None, MatchResult::None); - false - } - } - - pub fn dispatch_event(&mut self, event: Event, event_reused: bool) -> bool { - self.window - .presenter - .dispatch_event(event, event_reused, self) - } - - pub fn set_window_title(&mut self, title: &str) { - self.window.platform_window.set_title(title); - } - - pub fn set_window_edited(&mut self, edited: bool) { - self.window.platform_window.set_edited(edited); - } - - pub fn is_topmost_window_for_position(&self, position: Vector2F) -> bool { - self.window - .platform_window - .is_topmost_for_position(position) - } - - pub fn activate_window(&self) { - self.window.platform_window.activate(); - } - - pub fn window_bounds(&self) -> WindowBounds { - self.window.platform_window.bounds() - } - - pub fn window_display_uuid(&self) -> Option { - self.window.platform_window.screen().display_uuid() - } - - pub fn debug_elements(&self) -> Option { - self.window.presenter.debug_elements(self) - } - - fn show_character_palette(&self) { - self.window.platform_window.show_character_palette(); - } - - pub fn minimize_window(&self) { - self.window.platform_window.minimize(); - } - - pub fn zoom_window(&self) { - self.window.platform_window.zoom(); - } - - pub fn toggle_window_full_screen(&self) { - self.window.platform_window.toggle_full_screen(); - } - - pub fn prompt( - &self, - level: PromptLevel, - msg: &str, - answers: &[&str], - ) -> oneshot::Receiver { - self.window.platform_window.prompt(level, msg, answers) - } -} - pub struct ViewContext<'a, T: ?Sized> { app: &'a mut AppContext, window_id: usize, @@ -5139,6 +4942,7 @@ mod tests { elements::*, impl_actions, platform::{MouseButton, MouseButtonEvent}, + window::ChildView, }; use itertools::Itertools; use postage::{sink::Sink, stream::Stream}; @@ -6847,7 +6651,7 @@ mod tests { let (window_id, root_view) = cx.add_window(Default::default(), |_| View(0)); cx.update_window(window_id, |cx| { assert_eq!( - cx.window.presenter.rendered_views[&root_view.id()].name(), + cx.window.rendered_views[&root_view.id()].name(), Some("render count: 0") ); }); @@ -6859,11 +6663,11 @@ mod tests { cx.update_window(window_id, |cx| { assert_eq!( - cx.window.presenter.rendered_views[&root_view.id()].name(), + cx.window.rendered_views[&root_view.id()].name(), Some("render count: 1") ); assert_eq!( - cx.window.presenter.rendered_views[&view.id()].name(), + cx.window.rendered_views[&view.id()].name(), Some("render count: 0") ); }); @@ -6872,11 +6676,11 @@ mod tests { cx.update_window(window_id, |cx| { assert_eq!( - cx.window.presenter.rendered_views[&root_view.id()].name(), + cx.window.rendered_views[&root_view.id()].name(), Some("render count: 2") ); assert_eq!( - cx.window.presenter.rendered_views[&view.id()].name(), + cx.window.rendered_views[&view.id()].name(), Some("render count: 1") ); }); @@ -6888,10 +6692,10 @@ mod tests { cx.update_window(window_id, |cx| { assert_eq!( - cx.window.presenter.rendered_views[&root_view.id()].name(), + cx.window.rendered_views[&root_view.id()].name(), Some("render count: 3") ); - assert_eq!(cx.window.presenter.rendered_views.len(), 1); + assert_eq!(cx.window.rendered_views.len(), 1); }); } diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index 84fe2bafda..b8244f044b 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -92,13 +92,12 @@ impl TestAppContext { return true; } - if cx.window.presenter.dispatch_event( + if cx.dispatch_event( Event::KeyDown(KeyDownEvent { keystroke: keystroke.clone(), is_held, }), false, - cx, ) { return true; } @@ -286,12 +285,15 @@ impl TestAppContext { pub fn simulate_window_activation(&self, to_activate: Option) { self.cx.borrow_mut().update(|cx| { - for window_id in cx + let other_window_ids = cx .windows .keys() .filter(|window_id| Some(**window_id) != to_activate) - { - cx.window_changed_active_status(*window_id, false) + .copied() + .collect::>(); + + for window_id in other_window_ids { + cx.window_changed_active_status(window_id, false) } if let Some(to_activate) = to_activate { diff --git a/crates/gpui/src/presenter.rs b/crates/gpui/src/app/window.rs similarity index 72% rename from crates/gpui/src/presenter.rs rename to crates/gpui/src/app/window.rs index e11ae63c0b..ccb5a49ccf 100644 --- a/crates/gpui/src/presenter.rs +++ b/crates/gpui/src/app/window.rs @@ -4,7 +4,11 @@ use crate::{ font_cache::FontCache, geometry::rect::RectF, json::{self, ToJson}, - platform::{Appearance, CursorStyle, Event, FontSystem, MouseButton, MouseMovedEvent}, + keymap_matcher::{Keystroke, MatchResult}, + platform::{ + self, Appearance, CursorStyle, Event, FontSystem, MouseButton, MouseMovedEvent, + PromptLevel, WindowBounds, + }, scene::{ CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene, @@ -18,6 +22,7 @@ use crate::{ use anyhow::bail; use collections::{HashMap, HashSet}; use pathfinder_geometry::vector::{vec2f, Vector2F}; +use postage::oneshot; use serde_json::json; use smallvec::SmallVec; use sqlez::{ @@ -29,9 +34,16 @@ use std::{ ops::{Deref, DerefMut, Range}, sync::Arc, }; +use uuid::Uuid; -pub struct Presenter { +pub struct Window { window_id: usize, + pub(crate) root_view: AnyViewHandle, + pub(crate) focused_view_id: Option, + pub(crate) is_active: bool, + pub(crate) is_fullscreen: bool, + pub(crate) invalidation: Option, + pub(crate) platform_window: Box, pub(crate) rendered_views: HashMap, cursor_regions: Vec, mouse_regions: Vec<(MouseRegion, usize)>, @@ -47,18 +59,27 @@ pub struct Presenter { appearance: Appearance, } -impl Presenter { +impl Window { pub fn new( window_id: usize, - titlebar_height: f32, - appearance: Appearance, + root_view: AnyViewHandle, + platform_window: Box, font_cache: Arc, text_layout_cache: TextLayoutCache, asset_cache: Arc, cx: &mut AppContext, ) -> Self { + let focused_view_id = Some(root_view.id()); + let titlebar_height = platform_window.titlebar_height(); + let appearance = platform_window.appearance(); Self { window_id, + root_view, + focused_view_id, + is_active: false, + invalidation: None, + is_fullscreen: false, + platform_window, rendered_views: cx.render_views(window_id, titlebar_height, appearance), cursor_regions: Default::default(), mouse_regions: Default::default(), @@ -74,180 +95,101 @@ impl Presenter { appearance, } } +} - pub fn invalidate( - &mut self, - invalidation: &mut WindowInvalidation, - appearance: Appearance, - cx: &mut AppContext, - ) { - cx.start_frame(); - self.appearance = appearance; - for view_id in &invalidation.removed { - invalidation.updated.remove(view_id); - self.rendered_views.remove(view_id); +pub struct WindowContext<'a: 'b, 'b> { + app_context: &'a mut AppContext, + pub(crate) window: &'b mut Window, // TODO: make this private? + window_id: usize, +} + +impl Deref for WindowContext<'_, '_> { + type Target = AppContext; + + fn deref(&self) -> &Self::Target { + self.app_context + } +} + +impl DerefMut for WindowContext<'_, '_> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.app_context + } +} + +impl<'a: 'b, 'b> WindowContext<'a, 'b> { + pub fn new(app_context: &'a mut AppContext, window: &'b mut Window, window_id: usize) -> Self { + Self { + app_context, + window, + window_id, } - for view_id in &invalidation.updated { - self.rendered_views.insert( - *view_id, - cx.render_view(RenderParams { - window_id: self.window_id, - view_id: *view_id, - titlebar_height: self.titlebar_height, - hovered_region_ids: self.hovered_region_ids.clone(), - clicked_region_ids: self - .clicked_button - .map(|button| (self.clicked_region_ids.clone(), button)), - refreshing: false, - appearance, + } + + pub fn dispatch_keystroke(&mut self, keystroke: &Keystroke) -> bool { + let window_id = self.window_id; + if let Some(focused_view_id) = self.focused_view_id(window_id) { + let dispatch_path = self + .ancestors(window_id, focused_view_id) + .filter_map(|view_id| { + self.views + .get(&(window_id, view_id)) + .map(|view| (view_id, view.keymap_context(self))) }) - .unwrap(), - ); - } - } + .collect(); - pub fn refresh( - &mut self, - invalidation: &mut WindowInvalidation, - appearance: Appearance, - cx: &mut AppContext, - ) { - self.invalidate(invalidation, appearance, cx); - for (view_id, view) in &mut self.rendered_views { - if !invalidation.updated.contains(view_id) { - *view = cx - .render_view(RenderParams { - window_id: self.window_id, - view_id: *view_id, - titlebar_height: self.titlebar_height, - hovered_region_ids: self.hovered_region_ids.clone(), - clicked_region_ids: self - .clicked_button - .map(|button| (self.clicked_region_ids.clone(), button)), - refreshing: true, - appearance, - }) - .unwrap(); - } - } - } + let match_result = self + .keystroke_matcher + .push_keystroke(keystroke.clone(), dispatch_path); + let mut handled_by = None; - pub fn build_scene( - &mut self, - window_size: Vector2F, - scale_factor: f32, - refreshing: bool, - cx: &mut AppContext, - ) -> Scene { - let mut scene_builder = SceneBuilder::new(scale_factor); - - if let Some(root_view_id) = cx.root_view_id(self.window_id) { - self.layout(window_size, refreshing, cx); - let mut paint_cx = self.build_paint_context(&mut scene_builder, window_size, cx); - paint_cx.paint( - root_view_id, - Vector2F::zero(), - RectF::new(Vector2F::zero(), window_size), - ); - self.text_layout_cache.finish_frame(); - let scene = scene_builder.build(); - self.cursor_regions = scene.cursor_regions(); - self.mouse_regions = scene.mouse_regions(); - - // window.is_topmost for the mouse moved event's postion? - if cx.window_is_active(self.window_id) { - if let Some(event) = self.last_mouse_moved_event.clone() { - self.dispatch_event(event, true, cx); + let keystroke_handled = match &match_result { + MatchResult::None => false, + MatchResult::Pending => true, + MatchResult::Matches(matches) => { + for (view_id, action) in matches { + if self.handle_dispatch_action_from_effect( + window_id, + Some(*view_id), + action.as_ref(), + ) { + self.keystroke_matcher.clear_pending(); + handled_by = Some(action.boxed_clone()); + break; + } + } + handled_by.is_some() } - } - - scene - } else { - log::error!("could not find root_view_id for window {}", self.window_id); - scene_builder.build() - } - } - - fn layout(&mut self, window_size: Vector2F, refreshing: bool, cx: &mut AppContext) { - if let Some(root_view_id) = cx.root_view_id(self.window_id) { - self.build_layout_context(window_size, refreshing, cx) - .layout(root_view_id, SizeConstraint::strict(window_size)); - } - } - - pub fn build_layout_context<'a>( - &'a mut self, - window_size: Vector2F, - refreshing: bool, - cx: &'a mut AppContext, - ) -> LayoutContext<'a> { - LayoutContext { - window_id: self.window_id, - rendered_views: &mut self.rendered_views, - font_cache: &self.font_cache, - font_system: cx.platform().fonts(), - text_layout_cache: &self.text_layout_cache, - asset_cache: &self.asset_cache, - view_stack: Vec::new(), - refreshing, - hovered_region_ids: self.hovered_region_ids.clone(), - clicked_region_ids: self - .clicked_button - .map(|button| (self.clicked_region_ids.clone(), button)), - titlebar_height: self.titlebar_height, - appearance: self.appearance, - window_size, - app: cx, - } - } - - pub fn build_paint_context<'a>( - &'a mut self, - scene: &'a mut SceneBuilder, - window_size: Vector2F, - cx: &'a mut AppContext, - ) -> PaintContext { - PaintContext { - scene, - window_size, - font_cache: &self.font_cache, - text_layout_cache: &self.text_layout_cache, - rendered_views: &mut self.rendered_views, - view_stack: Vec::new(), - app: cx, - } - } - - pub fn rect_for_text_range(&self, range_utf16: Range, cx: &AppContext) -> Option { - cx.focused_view_id(self.window_id).and_then(|view_id| { - let cx = MeasurementContext { - app: cx, - rendered_views: &self.rendered_views, - window_id: self.window_id, }; - cx.rect_for_text_range(view_id, range_utf16) - }) + + self.keystroke( + window_id, + keystroke.clone(), + handled_by, + match_result.clone(), + ); + keystroke_handled + } else { + self.keystroke(window_id, keystroke.clone(), None, MatchResult::None); + false + } } - pub fn dispatch_event( - &mut self, - event: Event, - event_reused: bool, - cx: &mut AppContext, - ) -> bool { + pub fn dispatch_event(&mut self, event: Event, event_reused: bool) -> bool { let mut mouse_events = SmallVec::<[_; 2]>::new(); let mut notified_views: HashSet = Default::default(); + let window_id = self.window_id; // 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::KeyDown(e) => return self.dispatch_key_down(window_id, e), - Event::KeyUp(e) => return cx.dispatch_key_up(self.window_id, e), + Event::KeyUp(e) => return self.dispatch_key_up(window_id, e), - Event::ModifiersChanged(e) => return cx.dispatch_modifiers_changed(self.window_id, e), + Event::ModifiersChanged(e) => return self.dispatch_modifiers_changed(window_id, e), Event::MouseDown(e) => { // Click events are weird because they can be fired after a drag event. @@ -256,8 +198,9 @@ impl Presenter { // 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 + if self.window.clicked_button.is_none() { + self.window.clicked_region_ids = self + .window .mouse_regions .iter() .filter_map(|(region, _)| { @@ -269,7 +212,7 @@ impl Presenter { }) .collect(); - self.clicked_button = Some(e.button); + self.window.clicked_button = Some(e.button); } mouse_events.push(MouseEvent::Down(MouseDown { @@ -308,26 +251,29 @@ impl Presenter { }, ) => { let mut style_to_assign = CursorStyle::Arrow; - for region in self.cursor_regions.iter().rev() { + for region in self.window.cursor_regions.iter().rev() { if region.bounds.contains_point(*position) { style_to_assign = region.style; break; } } - // TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // if cx.is_topmost_window_for_position(self.window_id, *position) { - // cx.platform().set_cursor_style(style_to_assign); - // } + if self + .window + .platform_window + .is_topmost_for_position(*position) + { + self.platform().set_cursor_style(style_to_assign); + } if !event_reused { if pressed_button.is_some() { mouse_events.push(MouseEvent::Drag(MouseDrag { region: Default::default(), - prev_mouse_position: self.mouse_position, + prev_mouse_position: self.window.mouse_position, platform_event: e.clone(), })); - } else if let Some(clicked_button) = self.clicked_button { + } else if let Some(clicked_button) = self.window.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 { @@ -359,7 +305,7 @@ impl Presenter { region: Default::default(), })); - self.last_mouse_moved_event = Some(event.clone()); + self.window.last_mouse_moved_event = Some(event.clone()); } Event::MouseExited(event) => { @@ -373,7 +319,6 @@ impl Presenter { modifiers: event.modifiers, }), event_reused, - cx, ); } @@ -384,7 +329,7 @@ impl Presenter { } if let Some(position) = event.position() { - self.mouse_position = position; + self.window.mouse_position = position; } // 2. Dispatch mouse events on regions @@ -398,8 +343,8 @@ impl Presenter { match &mouse_event { MouseEvent::Hover(_) => { let mut highest_z_index = None; - let mouse_position = self.mouse_position.clone(); - for (region, z_index) in self.mouse_regions.iter().rev() { + let mouse_position = self.window.mouse_position.clone(); + for (region, z_index) in self.window.mouse_regions.iter().rev() { // Allow mouse regions to appear transparent to hovers if !region.hoverable { continue; @@ -417,7 +362,7 @@ impl Presenter { // highest_z_index is set. if contains_mouse && z_index == highest_z_index.unwrap() { //Ensure that hover entrance events aren't sent twice - if self.hovered_region_ids.insert(region.id()) { + if self.window.hovered_region_ids.insert(region.id()) { valid_regions.push(region.clone()); if region.notify_on_hover { notified_views.insert(region.id().view_id()); @@ -425,7 +370,7 @@ impl Presenter { } } else { // Ensure that hover exit events aren't sent twice - if self.hovered_region_ids.remove(®ion.id()) { + if self.window.hovered_region_ids.remove(®ion.id()) { valid_regions.push(region.clone()); if region.notify_on_hover { notified_views.insert(region.id().view_id()); @@ -436,8 +381,8 @@ impl Presenter { } MouseEvent::Down(_) | MouseEvent::Up(_) => { - for (region, _) in self.mouse_regions.iter().rev() { - if region.bounds.contains_point(self.mouse_position) { + for (region, _) in self.window.mouse_regions.iter().rev() { + if region.bounds.contains_point(self.window.mouse_position) { valid_regions.push(region.clone()); if region.notify_on_click { notified_views.insert(region.id().view_id()); @@ -449,19 +394,25 @@ impl Presenter { MouseEvent::Click(e) => { // Only raise click events if the released button is the same as the one stored if self + .window .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; + let clicked_region_ids = std::mem::replace( + &mut self.window.clicked_region_ids, + Default::default(), + ); + self.window.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() { + for (mouse_region, _) in self.window.mouse_regions.iter().rev() { if clicked_region_ids.contains(&mouse_region.id()) { - if mouse_region.bounds.contains_point(self.mouse_position) { + if mouse_region + .bounds + .contains_point(self.window.mouse_position) + { valid_regions.push(mouse_region.clone()); } } @@ -470,26 +421,32 @@ impl Presenter { } MouseEvent::Drag(_) => { - for (mouse_region, _) in self.mouse_regions.iter().rev() { - if self.clicked_region_ids.contains(&mouse_region.id()) { + for (mouse_region, _) in self.window.mouse_regions.iter().rev() { + if self.window.clicked_region_ids.contains(&mouse_region.id()) { valid_regions.push(mouse_region.clone()); } } } MouseEvent::MoveOut(_) | MouseEvent::UpOut(_) | MouseEvent::DownOut(_) => { - for (mouse_region, _) in self.mouse_regions.iter().rev() { + for (mouse_region, _) in self.window.mouse_regions.iter().rev() { // NOT contains - if !mouse_region.bounds.contains_point(self.mouse_position) { + if !mouse_region + .bounds + .contains_point(self.window.mouse_position) + { valid_regions.push(mouse_region.clone()); } } } _ => { - for (mouse_region, _) in self.mouse_regions.iter().rev() { + for (mouse_region, _) in self.window.mouse_regions.iter().rev() { // Contains - if mouse_region.bounds.contains_point(self.mouse_position) { + if mouse_region + .bounds + .contains_point(self.window.mouse_position) + { valid_regions.push(mouse_region.clone()); } } @@ -497,9 +454,9 @@ impl Presenter { } //3. Fire region events - let hovered_region_ids = self.hovered_region_ids.clone(); + let hovered_region_ids = self.window.hovered_region_ids.clone(); for valid_region in valid_regions.into_iter() { - let mut event_cx = self.build_event_context(&mut notified_views, cx); + let mut event_cx = self.build_event_context(&mut notified_views); mouse_event.set_region(valid_region.bounds); if let MouseEvent::Hover(e) = &mut mouse_event { @@ -548,43 +505,253 @@ impl Presenter { } for view_id in notified_views { - cx.notify_view(self.window_id, view_id); + self.notify_view(window_id, view_id); } any_event_handled } - pub fn build_event_context<'a>( - &'a mut self, - notified_views: &'a mut HashSet, - cx: &'a mut AppContext, - ) -> EventContext<'a> { + pub fn build_event_context<'c>( + &'c mut self, + notified_views: &'c mut HashSet, + ) -> EventContext<'c> { EventContext { - font_cache: &self.font_cache, - text_layout_cache: &self.text_layout_cache, + font_cache: &self.window.font_cache, + text_layout_cache: &self.window.text_layout_cache, view_stack: Default::default(), notified_views, notify_count: 0, handled: false, window_id: self.window_id, + app: self, + } + } + + pub fn invalidate(&mut self, invalidation: &mut WindowInvalidation, appearance: Appearance) { + self.start_frame(); + self.window.appearance = appearance; + for view_id in &invalidation.removed { + invalidation.updated.remove(view_id); + self.window.rendered_views.remove(view_id); + } + for view_id in &invalidation.updated { + let window_id = self.window_id; + let titlebar_height = self.window.titlebar_height; + let hovered_region_ids = self.window.hovered_region_ids.clone(); + let clicked_region_ids = self + .window + .clicked_button + .map(|button| (self.window.clicked_region_ids.clone(), button)); + + let element = self + .render_view(RenderParams { + window_id, + view_id: *view_id, + titlebar_height, + hovered_region_ids, + clicked_region_ids, + refreshing: false, + appearance, + }) + .unwrap(); + self.window.rendered_views.insert(*view_id, element); + } + } + + pub fn refresh(&mut self, invalidation: &mut WindowInvalidation, appearance: Appearance) { + self.invalidate(invalidation, appearance); + + let view_ids = self + .window + .rendered_views + .keys() + .copied() + .collect::>(); + + for view_id in view_ids { + if !invalidation.updated.contains(&view_id) { + let window_id = self.window_id; + let titlebar_height = self.window.titlebar_height; + let hovered_region_ids = self.window.hovered_region_ids.clone(); + let clicked_region_ids = self + .window + .clicked_button + .map(|button| (self.window.clicked_region_ids.clone(), button)); + let element = self + .render_view(RenderParams { + window_id, + view_id, + titlebar_height, + hovered_region_ids, + clicked_region_ids, + refreshing: true, + appearance, + }) + .unwrap(); + self.window.rendered_views.insert(view_id, element); + } + } + } + + pub fn build_scene(&mut self, refreshing: bool) -> Scene { + let window_size = self.window.platform_window.content_size(); + let scale_factor = self.window.platform_window.scale_factor(); + + let mut scene_builder = SceneBuilder::new(scale_factor); + + if let Some(root_view_id) = self.root_view_id(self.window_id) { + self.layout(window_size, refreshing, self); + let mut paint_cx = self.build_paint_context(&mut scene_builder, window_size); + paint_cx.paint( + root_view_id, + Vector2F::zero(), + RectF::new(Vector2F::zero(), window_size), + ); + self.window.text_layout_cache.finish_frame(); + let scene = scene_builder.build(); + self.window.cursor_regions = scene.cursor_regions(); + self.window.mouse_regions = scene.mouse_regions(); + + // window.is_topmost for the mouse moved event's postion? + if self.window_is_active(self.window_id) { + if let Some(event) = self.window.last_mouse_moved_event.clone() { + self.dispatch_event(event, true); + } + } + + scene + } else { + log::error!("could not find root_view_id for window {}", self.window_id); + scene_builder.build() + } + } + + fn layout(&mut self, window_size: Vector2F, refreshing: bool, cx: &mut AppContext) { + if let Some(root_view_id) = cx.root_view_id(self.window_id) { + self.build_layout_context(window_size, refreshing, cx) + .layout(root_view_id, SizeConstraint::strict(window_size)); + } + } + + pub fn build_layout_context<'c>( + &'c mut self, + window_size: Vector2F, + refreshing: bool, + cx: &'c mut AppContext, + ) -> LayoutContext<'c> { + LayoutContext { + window_id: self.window_id, + rendered_views: &mut self.window.rendered_views, + font_cache: &self.font_cache, + font_system: cx.platform().fonts(), + text_layout_cache: &self.window.text_layout_cache, + asset_cache: &self.window.asset_cache, + view_stack: Vec::new(), + refreshing, + hovered_region_ids: self.window.hovered_region_ids.clone(), + clicked_region_ids: self + .window + .clicked_button + .map(|button| (self.window.clicked_region_ids.clone(), button)), + titlebar_height: self.window.titlebar_height, + appearance: self.window.appearance, + window_size, app: cx, } } - pub fn debug_elements(&self, cx: &AppContext) -> Option { - let view = cx.root_view(self.window_id)?; + pub fn build_paint_context<'c>( + &'c mut self, + scene: &'c mut SceneBuilder, + window_size: Vector2F, + ) -> PaintContext { + PaintContext { + scene, + window_size, + font_cache: &self.font_cache, + text_layout_cache: &self.window.text_layout_cache, + rendered_views: &mut self.window.rendered_views, + view_stack: Vec::new(), + app: self, + } + } + + pub fn rect_for_text_range(&self, range_utf16: Range) -> Option { + self.focused_view_id(self.window_id).and_then(|view_id| { + let cx = MeasurementContext { + app: self, + rendered_views: &self.window.rendered_views, + window_id: self.window_id, + }; + cx.rect_for_text_range(view_id, range_utf16) + }) + } + + pub fn debug_elements(&self) -> Option { + let view = self.root_view(self.window_id)?; Some(json!({ - "root_view": view.debug_json(cx), - "root_element": self.rendered_views.get(&view.id()) + "root_view": view.debug_json(self), + "root_element": self.window.rendered_views.get(&view.id()) .map(|root_element| { root_element.debug(&DebugContext { - rendered_views: &self.rendered_views, - font_cache: &self.font_cache, - app: cx, + rendered_views: &self.window.rendered_views, + font_cache: &self.window.font_cache, + app: self, }) }) })) } + + pub fn set_window_title(&mut self, title: &str) { + self.window.platform_window.set_title(title); + } + + pub fn set_window_edited(&mut self, edited: bool) { + self.window.platform_window.set_edited(edited); + } + + pub fn is_topmost_window_for_position(&self, position: Vector2F) -> bool { + self.window + .platform_window + .is_topmost_for_position(position) + } + + pub fn activate_window(&self) { + self.window.platform_window.activate(); + } + + pub fn window_bounds(&self) -> WindowBounds { + self.window.platform_window.bounds() + } + + pub fn window_display_uuid(&self) -> Option { + self.window.platform_window.screen().display_uuid() + } + + fn show_character_palette(&self) { + self.window.platform_window.show_character_palette(); + } + + pub fn minimize_window(&self) { + self.window.platform_window.minimize(); + } + + pub fn zoom_window(&self) { + self.window.platform_window.zoom(); + } + + pub fn toggle_window_full_screen(&self) { + self.window.platform_window.toggle_full_screen(); + } + + pub fn prompt( + &self, + level: PromptLevel, + msg: &str, + answers: &[&str], + ) -> oneshot::Receiver { + self.window.platform_window.prompt(level, msg, answers) + } } pub struct LayoutContext<'a> { diff --git a/crates/gpui/src/app/window_input_handler.rs b/crates/gpui/src/app/window_input_handler.rs index 997ec1c7a5..db92dd0b47 100644 --- a/crates/gpui/src/app/window_input_handler.rs +++ b/crates/gpui/src/app/window_input_handler.rs @@ -90,8 +90,9 @@ impl InputHandler for WindowInputHandler { } fn rect_for_range(&self, range_utf16: Range) -> Option { - let app = self.app.borrow(); - let window = app.windows.get(&self.window_id)?; - window.presenter.rect_for_text_range(range_utf16, &app) + self.app + .borrow_mut() + .update_window(self.window_id, |cx| cx.rect_for_text_range(range_utf16)) + .flatten() } } diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index 3e3370a507..6322f99772 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -26,16 +26,14 @@ pub use self::{ stack::*, svg::*, text::*, tooltip::*, uniform_list::*, }; use self::{clipped::Clipped, expanded::Expanded}; -pub use crate::presenter::ChildView; use crate::{ + app::window::MeasurementContext, geometry::{ rect::RectF, vector::{vec2f, Vector2F}, }, - json, - presenter::MeasurementContext, - Action, DebugContext, EventContext, LayoutContext, PaintContext, RenderContext, SizeConstraint, - View, + json, Action, DebugContext, EventContext, LayoutContext, PaintContext, RenderContext, + SizeConstraint, View, }; use core::panic; use json::ToJson; diff --git a/crates/gpui/src/elements/align.rs b/crates/gpui/src/elements/align.rs index ec1a210f75..9887fc71d7 100644 --- a/crates/gpui/src/elements/align.rs +++ b/crates/gpui/src/elements/align.rs @@ -1,7 +1,7 @@ use crate::{ geometry::{rect::RectF, vector::Vector2F}, json, - presenter::MeasurementContext, + window::MeasurementContext, DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; use json::ToJson; diff --git a/crates/gpui/src/elements/canvas.rs b/crates/gpui/src/elements/canvas.rs index 31c56bb987..8dcdcce5ea 100644 --- a/crates/gpui/src/elements/canvas.rs +++ b/crates/gpui/src/elements/canvas.rs @@ -1,7 +1,7 @@ use super::Element; use crate::{ json::{self, json}, - presenter::MeasurementContext, + window::MeasurementContext, DebugContext, PaintContext, }; use json::ToJson; diff --git a/crates/gpui/src/elements/constrained_box.rs b/crates/gpui/src/elements/constrained_box.rs index e4d51f5730..ca48fdcbed 100644 --- a/crates/gpui/src/elements/constrained_box.rs +++ b/crates/gpui/src/elements/constrained_box.rs @@ -6,7 +6,7 @@ use serde_json::json; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json, - presenter::MeasurementContext, + window::MeasurementContext, DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index 8e17fdd60f..11ef42c413 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -9,8 +9,8 @@ use crate::{ }, json::ToJson, platform::CursorStyle, - presenter::MeasurementContext, scene::{self, Border, CursorRegion, Quad}, + window::MeasurementContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; use serde::Deserialize; diff --git a/crates/gpui/src/elements/empty.rs b/crates/gpui/src/elements/empty.rs index b0a0481c05..a1c805f456 100644 --- a/crates/gpui/src/elements/empty.rs +++ b/crates/gpui/src/elements/empty.rs @@ -6,7 +6,7 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::{json, ToJson}, - presenter::MeasurementContext, + window::MeasurementContext, DebugContext, }; use crate::{Element, LayoutContext, PaintContext, SizeConstraint}; diff --git a/crates/gpui/src/elements/expanded.rs b/crates/gpui/src/elements/expanded.rs index 89e9c7c7d8..e7d1cea3af 100644 --- a/crates/gpui/src/elements/expanded.rs +++ b/crates/gpui/src/elements/expanded.rs @@ -3,7 +3,7 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json, - presenter::MeasurementContext, + window::MeasurementContext, DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; use serde_json::json; diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index 5df283bfee..ba49557a8b 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -2,7 +2,7 @@ use std::{any::Any, cell::Cell, f32::INFINITY, ops::Range, rc::Rc}; use crate::{ json::{self, ToJson, Value}, - presenter::MeasurementContext, + window::MeasurementContext, Axis, DebugContext, Element, ElementBox, ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint, Vector2FExt, View, }; diff --git a/crates/gpui/src/elements/hook.rs b/crates/gpui/src/elements/hook.rs index b77fef4fae..37b6bb03c7 100644 --- a/crates/gpui/src/elements/hook.rs +++ b/crates/gpui/src/elements/hook.rs @@ -3,7 +3,7 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::json, - presenter::MeasurementContext, + window::MeasurementContext, DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; diff --git a/crates/gpui/src/elements/image.rs b/crates/gpui/src/elements/image.rs index cc49308e15..a94f45815c 100644 --- a/crates/gpui/src/elements/image.rs +++ b/crates/gpui/src/elements/image.rs @@ -5,8 +5,9 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::{json, ToJson}, - presenter::MeasurementContext, - scene, Border, DebugContext, Element, ImageData, LayoutContext, PaintContext, SizeConstraint, + scene, + window::MeasurementContext, + Border, DebugContext, Element, ImageData, LayoutContext, PaintContext, SizeConstraint, }; use serde::Deserialize; use std::{ops::Range, sync::Arc}; diff --git a/crates/gpui/src/elements/label.rs b/crates/gpui/src/elements/label.rs index 41eea05957..6b998a9c18 100644 --- a/crates/gpui/src/elements/label.rs +++ b/crates/gpui/src/elements/label.rs @@ -7,8 +7,8 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::{ToJson, Value}, - presenter::MeasurementContext, text_layout::{Line, RunStyle}, + window::MeasurementContext, DebugContext, Element, LayoutContext, PaintContext, SizeConstraint, }; use serde::Deserialize; diff --git a/crates/gpui/src/elements/list.rs b/crates/gpui/src/elements/list.rs index df06f05009..9326c447f0 100644 --- a/crates/gpui/src/elements/list.rs +++ b/crates/gpui/src/elements/list.rs @@ -4,7 +4,7 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::json, - presenter::MeasurementContext, + window::MeasurementContext, DebugContext, Element, ElementBox, ElementRc, EventContext, LayoutContext, MouseRegion, PaintContext, RenderContext, SizeConstraint, View, ViewContext, }; @@ -631,7 +631,6 @@ mod tests { #[crate::test(self)] fn test_layout(cx: &mut crate::AppContext) { - let mut presenter = cx.build_presenter(0, 0., Default::default()); let (_, view) = cx.add_window(Default::default(), |_| TestView); let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.)); @@ -730,8 +729,7 @@ mod tests { .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) .unwrap_or(10); - let (_, view) = cx.add_window(Default::default(), |_| TestView); - let mut presenter = cx.build_presenter(0, 0., Default::default()); + let (window_id, view) = cx.add_window(Default::default(), |_| TestView); let mut next_id = 0; let elements = Rc::new(RefCell::new( (0..rng.gen_range(0..=20)) diff --git a/crates/gpui/src/elements/overlay.rs b/crates/gpui/src/elements/overlay.rs index 3dd816ca2a..2c340c5c7c 100644 --- a/crates/gpui/src/elements/overlay.rs +++ b/crates/gpui/src/elements/overlay.rs @@ -3,7 +3,7 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::ToJson, - presenter::MeasurementContext, + window::MeasurementContext, Axis, DebugContext, Element, ElementBox, LayoutContext, MouseRegion, PaintContext, SizeConstraint, }; diff --git a/crates/gpui/src/elements/stack.rs b/crates/gpui/src/elements/stack.rs index 3b5c19505d..60f84f53e8 100644 --- a/crates/gpui/src/elements/stack.rs +++ b/crates/gpui/src/elements/stack.rs @@ -3,7 +3,7 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::{self, json, ToJson}, - presenter::MeasurementContext, + window::MeasurementContext, DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, }; diff --git a/crates/gpui/src/elements/svg.rs b/crates/gpui/src/elements/svg.rs index 5bd2759f7a..dc3e37723b 100644 --- a/crates/gpui/src/elements/svg.rs +++ b/crates/gpui/src/elements/svg.rs @@ -8,8 +8,9 @@ use crate::{ rect::RectF, vector::{vec2f, Vector2F}, }, - presenter::MeasurementContext, - scene, DebugContext, Element, LayoutContext, PaintContext, SizeConstraint, + scene, + window::MeasurementContext, + DebugContext, Element, LayoutContext, PaintContext, SizeConstraint, }; pub struct Svg { diff --git a/crates/gpui/src/elements/text.rs b/crates/gpui/src/elements/text.rs index f5ece8ba2c..03ed147cde 100644 --- a/crates/gpui/src/elements/text.rs +++ b/crates/gpui/src/elements/text.rs @@ -6,8 +6,8 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::{ToJson, Value}, - presenter::MeasurementContext, text_layout::{Line, RunStyle, ShapedBoundary}, + window::MeasurementContext, DebugContext, Element, FontCache, LayoutContext, PaintContext, SizeConstraint, TextLayoutCache, }; use log::warn; @@ -271,12 +271,18 @@ pub fn layout_highlighted_chunks<'a>( #[cfg(test)] mod tests { use super::*; - use crate::{elements::Empty, fonts, AppContext, ElementBox, Entity, RenderContext, View}; + use crate::{ + elements::Empty, fonts, platform, AppContext, ElementBox, Entity, RenderContext, View, + }; #[crate::test(self)] fn test_soft_wrapping_with_carriage_returns(cx: &mut AppContext) { - let (window_id, _) = cx.add_window(Default::default(), |_| TestView); - let mut presenter = cx.build_presenter(window_id, Default::default(), Default::default()); + let (window_id, root_view) = cx.add_window(Default::default(), |_| TestView); + let mut presenter = cx.build_window( + window_id, + root_view.into_any(), + Box::new(platform::test::Window::new(Vector2F::new(800., 600.))), + ); fonts::with_font_cache(cx.font_cache().clone(), || { let mut text = Text::new("Hello\r\n", Default::default()).with_soft_wrap(true); let (_, state) = text.layout( diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index 562f12295c..971d4bc3e0 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -6,7 +6,7 @@ use crate::{ fonts::TextStyle, geometry::{rect::RectF, vector::Vector2F}, json::json, - presenter::MeasurementContext, + window::MeasurementContext, Action, Axis, ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint, Task, View, }; diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index 9d91613f63..ea712994da 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -6,8 +6,8 @@ use crate::{ }, json::{self, json}, platform::ScrollWheelEvent, - presenter::MeasurementContext, scene::MouseScrollWheel, + window::MeasurementContext, ElementBox, MouseRegion, RenderContext, View, }; use json::ToJson; diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index dc84dc9619..52ed1197bb 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -14,7 +14,6 @@ mod clipboard; pub use clipboard::ClipboardItem; pub mod fonts; pub mod geometry; -mod presenter; pub mod scene; pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder}; pub mod text_layout; @@ -28,7 +27,7 @@ pub mod json; pub mod keymap_matcher; pub mod platform; pub use gpui_macros::test; -pub use presenter::{ +pub use window::{ Axis, DebugContext, EventContext, LayoutContext, MeasurementContext, PaintContext, SizeConstraint, Vector2FExt, }; diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index e2bd428303..fa711c3eea 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -261,7 +261,7 @@ pub struct Window { } impl Window { - fn new(size: Vector2F) -> Self { + pub fn new(size: Vector2F) -> Self { Self { size, event_handlers: Default::default(), From 6638407ff9cc853182432c739d64f3fb6374192c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 10 Apr 2023 16:10:32 -0600 Subject: [PATCH 04/58] WIP: Everything shredded --- crates/context_menu/src/context_menu.rs | 3 +- crates/editor/src/display_map/block_map.rs | 2 +- crates/gpui/src/app.rs | 759 ++++++++--------- crates/gpui/src/app/test_app_context.rs | 4 +- crates/gpui/src/app/window.rs | 784 ++++++------------ crates/gpui/src/elements.rs | 222 ++--- crates/gpui/src/elements/align.rs | 35 +- crates/gpui/src/elements/canvas.rs | 23 +- crates/gpui/src/elements/clipped.rs | 37 +- crates/gpui/src/elements/constrained_box.rs | 55 +- crates/gpui/src/elements/container.rs | 36 +- crates/gpui/src/elements/empty.rs | 19 +- crates/gpui/src/elements/expanded.rs | 36 +- crates/gpui/src/elements/flex.rs | 77 +- crates/gpui/src/elements/hook.rs | 39 +- crates/gpui/src/elements/image.rs | 21 +- crates/gpui/src/elements/keystroke_label.rs | 31 +- crates/gpui/src/elements/label.rs | 26 +- crates/gpui/src/elements/list.rs | 106 ++- .../gpui/src/elements/mouse_event_handler.rs | 79 +- crates/gpui/src/elements/overlay.rs | 33 +- crates/gpui/src/elements/uniform_list.rs | 46 +- crates/gpui/src/text_layout.rs | 7 +- crates/search/src/project_search.rs | 4 +- crates/theme_testbench/src/theme_testbench.rs | 4 +- crates/workspace/src/toolbar.rs | 2 +- 26 files changed, 1136 insertions(+), 1354 deletions(-) diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index f13ab3a9a3..25d9b0ec10 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -28,7 +28,8 @@ pub fn init(cx: &mut AppContext) { cx.add_action(ContextMenu::cancel); } -type ContextMenuItemBuilder = Box ElementBox>; +type ContextMenuItemBuilder = + Box ElementBox>; pub enum ContextMenuItemLabel { String(Cow<'static, str>), diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index 20af1535a0..cabc3ce3f9 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::{Anchor, ExcerptId, ExcerptRange, ToPoint as _}; use collections::{Bound, HashMap, HashSet}; -use gpui::{fonts::HighlightStyle, ElementBox, RenderContext}; +use gpui::{fonts::HighlightStyle, RenderContext, ElementBox}; use language::{BufferSnapshot, Chunk, Patch, Point}; use parking_lot::Mutex; use std::{ diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 163ff86fcd..1582130ba4 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -45,15 +45,15 @@ use crate::{ executor::{self, Task}, keymap_matcher::{self, Binding, KeymapContext, KeymapMatcher, Keystroke, MatchResult}, platform::{ - self, Appearance, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, MouseButton, + self, Appearance, FontSystem, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, MouseButton, PathPromptOptions, Platform, PromptLevel, WindowBounds, WindowOptions, }, util::post_inc, window::{Window, WindowContext}, - AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId, TextLayoutCache, + AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId, }; -use self::ref_counts::RefCounts; +use self::{ref_counts::RefCounts, window::RenderedView}; pub trait Entity: 'static { type Event; @@ -69,7 +69,7 @@ pub trait Entity: 'static { pub trait View: Entity + Sized { fn ui_name() -> &'static str; - fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox; + fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox; 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 { @@ -516,12 +516,13 @@ pub struct AppContext { element_states: HashMap>, background: Arc, ref_counts: Arc>, - font_cache: Arc, - platform: Arc, weak_self: Option>>, + platform: Arc, foreground_platform: Rc, - assets: Arc, + pub asset_cache: Arc, + font_system: Arc, + pub font_cache: Arc, action_deserializers: HashMap<&'static str, (TypeId, DeserializeActionCallback)>, capture_actions: HashMap>>>, // Entity Types -> { Action Types -> Action Handlers } @@ -577,12 +578,13 @@ impl AppContext { element_states: Default::default(), ref_counts: Arc::new(Mutex::new(ref_counts)), background, - font_cache, - platform, weak_self: None, + font_system: platform.fonts(), + platform, foreground_platform, - assets: Arc::new(AssetCache::new(asset_source)), + font_cache, + asset_cache: Arc::new(AssetCache::new(asset_source)), action_deserializers: Default::default(), capture_actions: Default::default(), actions: Default::default(), @@ -727,7 +729,7 @@ impl AppContext { window_id: usize, view_id: usize| { let action = action.as_any().downcast_ref().unwrap(); - let mut cx = ViewContext::new(cx, window_id, view_id); + let mut cx = ViewContext::new(cx, view_id); handler( view.as_any_mut() .downcast_mut() @@ -805,36 +807,6 @@ impl AppContext { self.windows.keys().copied() } - pub fn window_is_active(&self, window_id: usize) -> bool { - self.windows - .get(&window_id) - .map_or(false, |window| window.is_active) - } - - pub fn window_is_fullscreen(&self, window_id: usize) -> bool { - self.windows - .get(&window_id) - .map_or(false, |window| window.is_fullscreen) - } - - pub fn root_view(&self, window_id: usize) -> Option { - self.windows - .get(&window_id) - .map(|window| window.root_view.clone()) - } - - pub fn root_view_id(&self, window_id: usize) -> Option { - self.windows - .get(&window_id) - .map(|window| window.root_view.id()) - } - - pub fn focused_view_id(&self, window_id: usize) -> Option { - self.windows - .get(&window_id) - .and_then(|window| window.focused_view_id) - } - pub fn view_ui_name(&self, window_id: usize, view_id: usize) -> Option<&'static str> { Some(self.views.get(&(window_id, view_id))?.ui_name()) } @@ -886,57 +858,57 @@ impl AppContext { self.active_labeled_tasks.values().cloned() } - pub fn render_view(&mut self, params: RenderParams) -> Result { - let window_id = params.window_id; - let view_id = params.view_id; - let mut view = self - .views - .remove(&(window_id, view_id)) - .ok_or_else(|| anyhow!("view not found"))?; - let element = view.render(params, self); - self.views.insert((window_id, view_id), view); - Ok(element) - } + // pub fn render_view(&mut self, params: RenderParams) -> Result> { + // let window_id = params.window_id; + // let view_id = params.view_id; + // let mut view = self + // .views + // .remove(&(window_id, view_id)) + // .ok_or_else(|| anyhow!("view not found"))?; + // let element = view.render(params, self); + // self.views.insert((window_id, view_id), view); + // Ok(element) + // } - pub fn render_views( - &mut self, - window_id: usize, - titlebar_height: f32, - appearance: Appearance, - ) -> HashMap { - self.start_frame(); - #[allow(clippy::needless_collect)] - let view_ids = self - .views - .keys() - .filter_map(|(win_id, view_id)| { - if *win_id == window_id { - Some(*view_id) - } else { - None - } - }) - .collect::>(); + // pub fn render_views( + // &mut self, + // window_id: usize, + // titlebar_height: f32, + // appearance: Appearance, + // ) -> HashMap { + // self.start_frame(); + // #[allow(clippy::needless_collect)] + // let view_ids = self + // .views + // .keys() + // .filter_map(|(win_id, view_id)| { + // if *win_id == window_id { + // Some(*view_id) + // } else { + // None + // } + // }) + // .collect::>(); - view_ids - .into_iter() - .map(|view_id| { - ( - view_id, - self.render_view(RenderParams { - window_id, - view_id, - titlebar_height, - hovered_region_ids: Default::default(), - clicked_region_ids: None, - refreshing: false, - appearance, - }) - .unwrap(), - ) - }) - .collect() - } + // view_ids + // .into_iter() + // .map(|view_id| { + // ( + // view_id, + // self.render_view(RenderParams { + // window_id, + // view_id, + // titlebar_height, + // hovered_region_ids: Default::default(), + // clicked_region_ids: None, + // refreshing: false, + // appearance, + // }) + // .unwrap(), + // ) + // }) + // .collect() + // } pub(crate) fn start_frame(&mut self) { self.frame_count += 1; @@ -1464,73 +1436,6 @@ impl AppContext { 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.views.remove(&(window_id, view_id)) { - let handled = view.key_down(event, self, window_id, view_id); - self.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.views.remove(&(window_id, view_id)) { - let handled = view.key_up(event, self, window_id, view_id); - self.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.views.remove(&(window_id, view_id)) { - let handled = view.modifiers_changed(event, self, window_id, view_id); - self.views.insert((window_id, view_id), view); - if handled { - return true; - } - } else { - log::error!("view {} does not exist", view_id) - } - } - } - - false - } - pub fn default_global(&mut self) -> &T { let type_id = TypeId::of::(); self.update(|this| { @@ -1748,17 +1653,8 @@ impl AppContext { window_id, })); - let mut window = Window::new( - window_id, - root_view, - platform_window, - self.font_cache.clone(), - TextLayoutCache::new(self.platform.fonts()), - self.assets.clone(), - self, - ); - - let scene = WindowContext::new(self, &mut window, window_id).build_scene(false); + let mut window = Window::new(window_id, root_view, platform_window, self); + let scene = WindowContext::new(self, &mut window, window_id).build_scene(); window.platform_window.present_scene(scene); window } @@ -1807,7 +1703,7 @@ impl AppContext { let view_id = post_inc(&mut this.next_entity_id); // Make sure we can tell child views about their parent this.parents.insert((window_id, view_id), parent_id); - let mut cx = ViewContext::new(this, window_id, view_id); + let mut cx = ViewContext::new(this, view_id); let handle = if let Some(view) = build_view(&mut cx) { this.views.insert((window_id, view_id), Box::new(view)); if let Some(window) = this.windows.get_mut(&window_id) { @@ -2108,7 +2004,7 @@ impl AppContext { if let Some(mut invalidation) = cx.window.invalidation.take() { let appearance = cx.window.platform_window.appearance(); cx.invalidate(&mut invalidation, appearance); - let scene = cx.build_scene(false); + let scene = cx.build_scene(); cx.window.platform_window.present_scene(scene); } }); @@ -2181,7 +2077,8 @@ impl AppContext { self.update_window(window_id, |cx| { let mut invalidation = cx.window.invalidation.take().unwrap_or_default(); cx.invalidate(&mut invalidation, cx.window.platform_window.appearance()); - let scene = cx.build_scene(true); + cx.refreshing = true; + let scene = cx.build_scene(); cx.window.platform_window.present_scene(scene); }); } @@ -2275,78 +2172,76 @@ impl AppContext { return; } - self.update(|this| { - let window = this.windows.get_mut(&window_id)?; - window.is_active = active; - - //Handle focus - let focused_id = window.focused_view_id?; - for view_id in this.ancestors(window_id, focused_id).collect::>() { - if let Some(mut view) = this.views.remove(&(window_id, view_id)) { - if active { - view.focus_in(this, window_id, view_id, focused_id); - } else { - view.focus_out(this, window_id, view_id, focused_id); - } - this.views.insert((window_id, view_id), view); + self.update(|cx| { + cx.update_window(window_id, |cx| { + let focused_id = cx.window.focused_view_id?; + for view_id in cx.ancestors(window_id, focused_id).collect::>() { + cx.update_any_view(focused_id, |view, cx| { + if active { + view.focus_in(focused_id, cx, view_id); + } else { + view.focus_out(focused_id, cx, view_id); + } + }); } - } + }); - let mut observations = this.window_activation_observations.clone(); - observations.emit(window_id, this, |callback, this| callback(active, this)); + let mut observations = cx.window_activation_observations.clone(); + observations.emit(window_id, cx, |callback, this| callback(active, this)); Some(()) }); } fn handle_focus_effect(&mut self, window_id: usize, focused_id: Option) { - if self - .windows - .get(&window_id) - .map(|w| w.focused_view_id) - .map_or(false, |cur_focused| cur_focused == focused_id) - { - return; - } + todo!() + // if self + // .windows + // .get(&window_id) + // .map(|w| w.focused_view_id) + // .map_or(false, |cur_focused| cur_focused == focused_id) + // { + // return; + // } - self.update(|this| { - let blurred_id = this.windows.get_mut(&window_id).and_then(|window| { - let blurred_id = window.focused_view_id; - window.focused_view_id = focused_id; - blurred_id - }); + // self.update(|this| { + // let blurred_id = this.windows.get_mut(&window_id).and_then(|window| { + // let blurred_id = window.focused_view_id; + // window.focused_view_id = focused_id; + // blurred_id + // }); - let blurred_parents = blurred_id - .map(|blurred_id| this.ancestors(window_id, blurred_id).collect::>()) - .unwrap_or_default(); - let focused_parents = focused_id - .map(|focused_id| this.ancestors(window_id, focused_id).collect::>()) - .unwrap_or_default(); + // let blurred_parents = blurred_id + // .map(|blurred_id| this.ancestors(window_id, blurred_id).collect::>()) + // .unwrap_or_default(); + // let focused_parents = focused_id + // .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.views.remove(&(window_id, view_id)) { - view.focus_out(this, window_id, view_id, blurred_id); - this.views.insert((window_id, view_id), view); - } - } + // if let Some(blurred_id) = blurred_id { + // for view_id in blurred_parents.iter().copied() { + // if let Some(mut view) = this.views.remove(&(window_id, view_id)) { + // view.focus_out(this, window_id, view_id, blurred_id); + // this.views.insert((window_id, view_id), view); + // } + // } - let mut subscriptions = this.focus_observations.clone(); - subscriptions.emit(blurred_id, this, |callback, this| callback(false, this)); - } + // let mut subscriptions = this.focus_observations.clone(); + // subscriptions.emit(blurred_id, this, |callback, this| callback(false, this)); + // } - if let Some(focused_id) = focused_id { - for view_id in focused_parents { - if let Some(mut view) = this.views.remove(&(window_id, view_id)) { - view.focus_in(this, window_id, view_id, focused_id); - this.views.insert((window_id, view_id), view); - } - } + // if let Some(focused_id) = focused_id { + // for view_id in focused_parents { + // if let Some(mut view) = this.views.remove(&(window_id, view_id)) { + // view.focus_in(this, window_id, view_id, focused_id); + // this.views.insert((window_id, view_id), view); + // } + // } - let mut subscriptions = this.focus_observations.clone(); - subscriptions.emit(focused_id, this, |callback, this| callback(true, this)); - } - }) + // let mut subscriptions = this.focus_observations.clone(); + // subscriptions.emit(focused_id, this, |callback, this| callback(true, this)); + // } + // }) } fn handle_dispatch_action_from_effect( @@ -2634,7 +2529,7 @@ impl UpdateView for AppContext { .remove(&(handle.window_id, handle.view_id)) .expect("circular view update"); - let mut cx = ViewContext::new(this, handle.window_id, handle.view_id); + let mut cx = ViewContext::new(this, handle.view_id); let result = update( view.as_any_mut() .downcast_mut() @@ -2982,64 +2877,68 @@ pub trait AnyView { cx: &mut AppContext, ) -> Option>>>; fn ui_name(&self) -> &'static str; - fn render(&mut self, params: RenderParams, cx: &mut AppContext) -> ElementBox; - fn focus_in( + fn render<'a, 'b>( &mut self, - cx: &mut AppContext, - window_id: usize, - view_id: usize, - focused_id: usize, - ); - fn focus_out( + params: RenderParams, + cx: &'b mut WindowContext<'a, 'b>, + ) -> Box; + fn focus_in<'a, 'b>( &mut self, - cx: &mut AppContext, - window_id: usize, - view_id: usize, focused_id: usize, + cx: &'b mut WindowContext<'a, 'b>, + view_id: usize, ); - fn key_down( + fn focus_out<'a, 'b>( + &mut self, + focused_id: usize, + cx: &'b mut WindowContext<'a, 'b>, + view_id: usize, + ); + fn key_down<'a, 'b>( &mut self, event: &KeyDownEvent, - cx: &mut AppContext, - window_id: usize, + cx: &'b mut WindowContext<'a, 'b>, view_id: usize, ) -> bool; - fn key_up( + fn key_up<'a, 'b>( &mut self, event: &KeyUpEvent, - cx: &mut AppContext, - window_id: usize, + cx: &'b mut WindowContext<'a, 'b>, view_id: usize, ) -> bool; - fn modifiers_changed( + fn modifiers_changed<'a, 'b>( &mut self, event: &ModifiersChangedEvent, - cx: &mut AppContext, - window_id: usize, + cx: &'b mut WindowContext<'a, 'b>, view_id: usize, ) -> bool; - fn keymap_context(&self, cx: &AppContext) -> KeymapContext; - fn debug_json(&self, cx: &AppContext) -> serde_json::Value; + fn keymap_context<'a, 'b>(&self, cx: &'b mut WindowContext<'a, 'b>) -> KeymapContext; + fn debug_json<'a, 'b>(&self, cx: &'b WindowContext<'a, 'b>) -> serde_json::Value; - fn text_for_range(&self, range: Range, cx: &AppContext) -> Option; - fn selected_text_range(&self, cx: &AppContext) -> Option>; - fn marked_text_range(&self, cx: &AppContext) -> Option>; - fn unmark_text(&mut self, cx: &mut AppContext, window_id: usize, view_id: usize); - fn replace_text_in_range( + fn text_for_range<'a, 'b>( + &self, + range: Range, + cx: &'b mut WindowContext<'a, 'b>, + ) -> Option; + fn selected_text_range<'a, 'b>( + &self, + cx: &'b mut WindowContext<'a, 'b>, + ) -> Option>; + fn marked_text_range<'a, 'b>(&self, cx: &'b mut WindowContext<'a, 'b>) -> Option>; + fn unmark_text<'a, 'b>(&mut self, cx: &'b mut WindowContext<'a, 'b>, view_id: usize); + fn replace_text_in_range<'a, 'b>( &mut self, range: Option>, text: &str, - cx: &mut AppContext, - window_id: usize, + cx: &'b mut WindowContext<'a, 'b>, view_id: usize, ); - fn replace_and_mark_text_in_range( + fn replace_and_mark_text_in_range<'a, 'b>( &mut self, range: Option>, new_text: &str, new_selected_range: Option>, - cx: &mut AppContext, - window_id: usize, + cx: &'b mut WindowContext<'a, 'b>, view_id: usize, ); fn any_handle(&self, window_id: usize, view_id: usize, cx: &AppContext) -> AnyViewHandle { @@ -3079,134 +2978,145 @@ where T::ui_name() } - fn render(&mut self, params: RenderParams, cx: &mut AppContext) -> ElementBox { + fn render<'a, 'b>( + &mut self, + params: RenderParams, + cx: &mut WindowContext<'a, 'b>, + ) -> Box { View::render(self, &mut RenderContext::new(params, cx)) } - fn focus_in( + fn focus_in<'a, 'b>( &mut self, - cx: &mut AppContext, - window_id: usize, + cx: &mut WindowContext<'a, 'b>, view_id: usize, focused_id: usize, ) { - let mut cx = ViewContext::new(cx, window_id, view_id); + let mut cx = ViewContext::new(cx, view_id); let focused_view_handle: AnyViewHandle = if view_id == focused_id { cx.handle().into_any() } else { let focused_type = cx .views - .get(&(window_id, focused_id)) + .get(&(cx.window_id, focused_id)) .unwrap() .as_any() .type_id(); - AnyViewHandle::new(window_id, focused_id, focused_type, cx.ref_counts.clone()) + AnyViewHandle::new( + cx.window_id, + focused_id, + focused_type, + cx.ref_counts.clone(), + ) }; View::focus_in(self, focused_view_handle, &mut cx); } - fn focus_out( + fn focus_out<'a, 'b>( &mut self, - cx: &mut AppContext, - window_id: usize, + cx: &mut WindowContext<'a, 'b>, view_id: usize, blurred_id: usize, ) { - let mut cx = ViewContext::new(cx, window_id, view_id); + let mut cx = ViewContext::new(cx, view_id); let blurred_view_handle: AnyViewHandle = if view_id == blurred_id { cx.handle().into_any() } else { let blurred_type = cx .views - .get(&(window_id, blurred_id)) + .get(&(cx.window_id, blurred_id)) .unwrap() .as_any() .type_id(); - AnyViewHandle::new(window_id, blurred_id, blurred_type, cx.ref_counts.clone()) + AnyViewHandle::new( + cx.window_id, + blurred_id, + blurred_type, + cx.ref_counts.clone(), + ) }; View::focus_out(self, blurred_view_handle, &mut cx); } - fn key_down( + fn key_down<'a, 'b>( &mut self, event: &KeyDownEvent, - cx: &mut AppContext, - window_id: usize, + cx: &mut WindowContext<'a, 'b>, view_id: usize, ) -> bool { - let mut cx = ViewContext::new(cx, window_id, view_id); + let mut cx = ViewContext::new(cx, view_id); View::key_down(self, event, &mut cx) } - fn key_up( + fn key_up<'a, 'b>( &mut self, event: &KeyUpEvent, - cx: &mut AppContext, - window_id: usize, + cx: &mut WindowContext<'a, 'b>, view_id: usize, ) -> bool { - let mut cx = ViewContext::new(cx, window_id, view_id); + let mut cx = ViewContext::new(cx, view_id); View::key_up(self, event, &mut cx) } - fn modifiers_changed( + fn modifiers_changed<'a, 'b>( &mut self, event: &ModifiersChangedEvent, - cx: &mut AppContext, - window_id: usize, + cx: &mut WindowContext<'a, 'b>, view_id: usize, ) -> bool { - let mut cx = ViewContext::new(cx, window_id, view_id); + let mut cx = ViewContext::new(cx, view_id); View::modifiers_changed(self, event, &mut cx) } - fn keymap_context(&self, cx: &AppContext) -> KeymapContext { + fn keymap_context<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> KeymapContext { View::keymap_context(self, cx) } - fn debug_json(&self, cx: &AppContext) -> serde_json::Value { + fn debug_json<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> serde_json::Value { View::debug_json(self, cx) } - fn text_for_range(&self, range: Range, cx: &AppContext) -> Option { + fn text_for_range<'a, 'b>( + &self, + range: Range, + cx: &mut WindowContext<'a, 'b>, + ) -> Option { View::text_for_range(self, range, cx) } - fn selected_text_range(&self, cx: &AppContext) -> Option> { + fn selected_text_range<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> Option> { View::selected_text_range(self, cx) } - fn marked_text_range(&self, cx: &AppContext) -> Option> { + fn marked_text_range<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> Option> { View::marked_text_range(self, cx) } - fn unmark_text(&mut self, cx: &mut AppContext, window_id: usize, view_id: usize) { - let mut cx = ViewContext::new(cx, window_id, view_id); + fn unmark_text<'a, 'b>(&mut self, cx: &mut WindowContext<'a, 'b>, view_id: usize) { + let mut cx = ViewContext::new(cx, view_id); View::unmark_text(self, &mut cx) } - fn replace_text_in_range( + fn replace_text_in_range<'a, 'b>( &mut self, range: Option>, text: &str, - cx: &mut AppContext, - window_id: usize, + cx: &mut WindowContext<'a, 'b>, view_id: usize, ) { - let mut cx = ViewContext::new(cx, window_id, view_id); + let mut cx = ViewContext::new(cx, view_id); View::replace_text_in_range(self, range, text, &mut cx) } - fn replace_and_mark_text_in_range( + fn replace_and_mark_text_in_range<'a, 'b>( &mut self, range: Option>, new_text: &str, new_selected_range: Option>, - cx: &mut AppContext, - window_id: usize, + cx: &mut WindowContext<'a, 'b>, view_id: usize, ) { - let mut cx = ViewContext::new(cx, window_id, view_id); + let mut cx = ViewContext::new(cx, view_id); View::replace_and_mark_text_in_range(self, range, new_text, new_selected_range, &mut cx) } } @@ -3429,25 +3339,41 @@ impl DerefMut for ModelContext<'_, M> { } } -pub struct ViewContext<'a, T: ?Sized> { - app: &'a mut AppContext, - window_id: usize, +pub struct ViewContext<'a, 'b, T: ?Sized> { + window_context: WindowContext<'a, 'b>, view_id: usize, view_type: PhantomData, } -impl<'a, T: View> ViewContext<'a, T> { - fn new(app: &'a mut AppContext, window_id: usize, view_id: usize) -> Self { +impl<'a, 'b, T: View> Deref for ViewContext<'a, 'b, T> { + type Target = WindowContext<'a, 'b>; + + fn deref(&self) -> &Self::Target { + &self.window_context + } +} + +impl<'a, 'b, T: View> DerefMut for ViewContext<'a, 'b, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.window_context + } +} + +impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { + fn new(window_context: &'b mut WindowContext<'a, 'b>, view_id: usize) -> Self { Self { - app, - window_id, + window_context, view_id, view_type: PhantomData, } } pub fn handle(&self) -> ViewHandle { - ViewHandle::new(self.window_id, self.view_id, &self.app.ref_counts) + ViewHandle::new( + self.window_id, + self.view_id, + &self.window_context.ref_counts, + ) } pub fn weak_handle(&self) -> WeakViewHandle { @@ -3455,7 +3381,7 @@ impl<'a, T: View> ViewContext<'a, T> { } pub fn parent(&self) -> Option { - self.app.parent(self.window_id, self.view_id) + self.window_context.parent(self.window_id, self.view_id) } pub fn window_id(&self) -> usize { @@ -3467,42 +3393,44 @@ impl<'a, T: View> ViewContext<'a, T> { } pub fn foreground(&self) -> &Rc { - self.app.foreground() + self.window_context.foreground() } pub fn background_executor(&self) -> &Arc { - &self.app.background + &self.window_context.background } pub fn platform(&self) -> &Arc { - self.app.platform() + self.window_context.platform() } pub fn prompt_for_paths( &self, options: PathPromptOptions, ) -> oneshot::Receiver>> { - self.app.prompt_for_paths(options) + self.window_context.prompt_for_paths(options) } pub fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver> { - self.app.prompt_for_new_path(directory) + self.window_context.prompt_for_new_path(directory) } pub fn reveal_path(&self, path: &Path) { - self.app.reveal_path(path) + self.window_context.reveal_path(path) } pub fn focus(&mut self, handle: &AnyViewHandle) { - self.app.focus(handle.window_id, Some(handle.view_id)); + self.window_context + .focus(handle.window_id, Some(handle.view_id)); } pub fn focus_self(&mut self) { - self.app.focus(self.window_id, Some(self.view_id)); + self.window_context + .focus(self.window_id, Some(self.view_id)); } pub fn is_self_focused(&self) -> bool { - self.app.focused_view_id(self.window_id) == Some(self.view_id) + self.window.focused_view == Some(self.view_id) } pub fn is_child(&self, view: impl Into) -> bool { @@ -3516,7 +3444,7 @@ impl<'a, T: View> ViewContext<'a, T> { } pub fn blur(&mut self) { - self.app.focus(self.window_id, None); + self.window_context.focus(self.window_id, None); } pub fn on_window_should_close(&mut self, mut callback: F) @@ -3543,7 +3471,7 @@ impl<'a, T: View> ViewContext<'a, T> { S: Entity, F: FnOnce(&mut ModelContext) -> S, { - self.app.add_model(build_model) + self.window_context.add_model(build_model) } pub fn add_view(&mut self, build_view: F) -> ViewHandle @@ -3551,7 +3479,7 @@ impl<'a, T: View> ViewContext<'a, T> { S: View, F: FnOnce(&mut ViewContext) -> S, { - self.app + self.window_context .build_and_insert_view(self.window_id, ParentId::View(self.view_id), |cx| { Some(build_view(cx)) }) @@ -3563,8 +3491,11 @@ impl<'a, T: View> ViewContext<'a, T> { S: View, F: FnOnce(&mut ViewContext) -> Option, { - self.app - .build_and_insert_view(self.window_id, ParentId::View(self.view_id), build_view) + self.window_context.build_and_insert_view( + self.window_id, + ParentId::View(self.view_id), + build_view, + ) } pub fn reparent(&mut self, view_handle: &AnyViewHandle) { @@ -3605,7 +3536,7 @@ impl<'a, T: View> ViewContext<'a, T> { F: 'static + FnMut(&mut T, H, &E::Event, &mut ViewContext), { let subscriber = self.weak_handle(); - self.app + self.window_context .subscribe_internal(handle, move |emitter, event, cx| { if let Some(subscriber) = subscriber.upgrade(cx) { subscriber.update(cx, |subscriber, cx| { @@ -3625,16 +3556,17 @@ impl<'a, T: View> ViewContext<'a, T> { F: 'static + FnMut(&mut T, H, &mut ViewContext), { let observer = self.weak_handle(); - self.app.observe_internal(handle, move |observed, cx| { - if let Some(observer) = observer.upgrade(cx) { - observer.update(cx, |observer, cx| { - callback(observer, observed, cx); - }); - true - } else { - false - } - }) + self.window_context + .observe_internal(handle, move |observed, cx| { + if let Some(observer) = observer.upgrade(cx) { + observer.update(cx, |observer, cx| { + callback(observer, observed, cx); + }); + true + } else { + false + } + }) } pub fn observe_global(&mut self, mut callback: F) -> Subscription @@ -3643,7 +3575,7 @@ impl<'a, T: View> ViewContext<'a, T> { F: 'static + FnMut(&mut T, &mut ViewContext), { let observer = self.weak_handle(); - self.app.observe_global::(move |cx| { + self.window_context.observe_global::(move |cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| callback(observer, cx)); } @@ -3656,7 +3588,7 @@ impl<'a, T: View> ViewContext<'a, T> { V: View, { let observer = self.weak_handle(); - self.app + self.window_context .observe_focus(handle, move |observed, focused, cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { @@ -3676,13 +3608,14 @@ impl<'a, T: View> ViewContext<'a, T> { F: 'static + FnMut(&mut T, &E, &mut ViewContext), { let observer = self.weak_handle(); - self.app.observe_release(handle, move |released, cx| { - if let Some(observer) = observer.upgrade(cx) { - observer.update(cx, |observer, cx| { - callback(observer, released, cx); - }); - } - }) + self.window_context + .observe_release(handle, move |released, cx| { + if let Some(observer) = observer.upgrade(cx) { + observer.update(cx, |observer, cx| { + callback(observer, released, cx); + }); + } + }) } pub fn observe_actions(&mut self, mut callback: F) -> Subscription @@ -3690,7 +3623,7 @@ impl<'a, T: View> ViewContext<'a, T> { F: 'static + FnMut(&mut T, TypeId, &mut ViewContext), { let observer = self.weak_handle(); - self.app.observe_actions(move |action_id, cx| { + self.window_context.observe_actions(move |action_id, cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { callback(observer, action_id, cx); @@ -3704,7 +3637,7 @@ impl<'a, T: View> ViewContext<'a, T> { F: 'static + FnMut(&mut T, bool, &mut ViewContext), { let observer = self.weak_handle(); - self.app + self.window_context .observe_window_activation(self.window_id(), move |active, cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { @@ -3722,7 +3655,7 @@ impl<'a, T: View> ViewContext<'a, T> { F: 'static + FnMut(&mut T, bool, &mut ViewContext), { let observer = self.weak_handle(); - self.app + self.window_context .observe_fullscreen(self.window_id(), move |active, cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { @@ -3747,7 +3680,7 @@ impl<'a, T: View> ViewContext<'a, T> { ) -> bool, { let observer = self.weak_handle(); - self.app.observe_keystrokes( + self.window_context.observe_keystrokes( self.window_id(), move |keystroke, result, handled_by, cx| { if let Some(observer) = observer.upgrade(cx) { @@ -3767,7 +3700,7 @@ impl<'a, T: View> ViewContext<'a, T> { F: 'static + FnMut(&mut T, WindowBounds, Uuid, &mut ViewContext), { let observer = self.weak_handle(); - self.app + self.window_context .observe_window_bounds(self.window_id(), move |bounds, display, cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { @@ -3785,7 +3718,7 @@ impl<'a, T: View> ViewContext<'a, T> { F: 'static + FnMut(&mut T, &mut ViewContext), { let observer = self.weak_handle(); - self.app.observe_active_labeled_tasks(move |cx| { + self.window_context.observe_active_labeled_tasks(move |cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { callback(observer, cx); @@ -3798,29 +3731,32 @@ impl<'a, T: View> ViewContext<'a, T> { } pub fn emit(&mut self, payload: T::Event) { - self.app.pending_effects.push_back(Effect::Event { - entity_id: self.view_id, - payload: Box::new(payload), - }); + self.window_context + .pending_effects + .push_back(Effect::Event { + entity_id: self.view_id, + payload: Box::new(payload), + }); } pub fn notify(&mut self) { - self.app.notify_view(self.window_id, self.view_id); + self.window_context + .notify_view(self.window_id, self.view_id); } pub fn dispatch_action(&mut self, action: impl Action) { - self.app + self.window_context .dispatch_action_at(self.window_id, self.view_id, action) } pub fn dispatch_any_action(&mut self, action: Box) { - self.app + self.window_context .dispatch_any_action_at(self.window_id, self.view_id, action) } pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut T, &mut ViewContext)) { let handle = self.handle(); - self.app.defer(move |cx| { + self.window_context.defer(move |cx| { handle.update(cx, |view, cx| { callback(view, cx); }) @@ -3832,7 +3768,7 @@ impl<'a, T: View> ViewContext<'a, T> { callback: impl 'static + FnOnce(&mut T, &mut ViewContext), ) { let handle = self.handle(); - self.app.after_window_update(move |cx| { + self.window_context.after_window_update(move |cx| { handle.update(cx, |view, cx| { callback(view, cx); }) @@ -3840,7 +3776,7 @@ impl<'a, T: View> ViewContext<'a, T> { } pub fn propagate_action(&mut self) { - self.app.halt_action_dispatch = false; + self.window_context.halt_action_dispatch = false; } pub fn spawn_labeled(&mut self, task_label: &'static str, f: F) -> Task @@ -3850,7 +3786,8 @@ impl<'a, T: View> ViewContext<'a, T> { S: 'static, { let handle = self.handle(); - self.app.spawn_labeled(task_label, |cx| f(handle, cx)) + self.window_context + .spawn_labeled(task_label, |cx| f(handle, cx)) } pub fn spawn(&mut self, f: F) -> Task @@ -3860,7 +3797,7 @@ impl<'a, T: View> ViewContext<'a, T> { S: 'static, { let handle = self.handle(); - self.app.spawn(|cx| f(handle, cx)) + self.window_context.spawn(|cx| f(handle, cx)) } pub fn spawn_weak(&mut self, f: F) -> Task @@ -3870,7 +3807,7 @@ impl<'a, T: View> ViewContext<'a, T> { S: 'static, { let handle = self.weak_handle(); - self.app.spawn(|cx| f(handle, cx)) + self.window_context.spawn(|cx| f(handle, cx)) } } @@ -3884,18 +3821,6 @@ pub struct RenderParams { pub appearance: Appearance, } -pub struct RenderContext<'a, T: View> { - pub(crate) window_id: usize, - pub(crate) view_id: usize, - pub(crate) view_type: PhantomData, - pub(crate) hovered_region_ids: HashSet, - pub(crate) clicked_region_ids: Option<(HashSet, MouseButton)>, - pub app: &'a mut AppContext, - pub titlebar_height: f32, - pub appearance: Appearance, - pub refreshing: bool, -} - #[derive(Debug, Clone, Default)] pub struct MouseState { pub(crate) hovered: bool, @@ -4027,56 +3952,50 @@ impl ReadView for RenderContext<'_, V> { } } -impl Deref for ViewContext<'_, M> { - type Target = AppContext; +impl<'a, 'b, M> Deref for ViewContext<'a, 'b, M> { + type Target = WindowContext<'a, 'b>; fn deref(&self) -> &Self::Target { - self.app + &self.window_context } } -impl DerefMut for ViewContext<'_, M> { +impl DerefMut for ViewContext<'_, '_, M> { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.app + &mut self.window_context } } -impl AsMut for ViewContext<'_, M> { - fn as_mut(&mut self) -> &mut AppContext { - self.app - } -} - -impl ReadModel for ViewContext<'_, V> { +impl ReadModel for ViewContext<'_, '_, V> { fn read_model(&self, handle: &ModelHandle) -> &T { - self.app.read_model(handle) + self.window_context.read_model(handle) } } -impl UpgradeModelHandle for ViewContext<'_, V> { +impl UpgradeModelHandle for ViewContext<'_, '_, V> { fn upgrade_model_handle( &self, handle: &WeakModelHandle, ) -> Option> { - self.app.upgrade_model_handle(handle) + self.window_context.upgrade_model_handle(handle) } fn model_handle_is_upgradable(&self, handle: &WeakModelHandle) -> bool { - self.app.model_handle_is_upgradable(handle) + self.window_context.model_handle_is_upgradable(handle) } fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option { - self.app.upgrade_any_model_handle(handle) + self.window_context.upgrade_any_model_handle(handle) } } -impl UpgradeViewHandle for ViewContext<'_, V> { +impl UpgradeViewHandle for ViewContext<'_, '_, V> { fn upgrade_view_handle(&self, handle: &WeakViewHandle) -> Option> { - self.app.upgrade_view_handle(handle) + self.window_context.upgrade_view_handle(handle) } fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option { - self.app.upgrade_any_view_handle(handle) + self.window_context.upgrade_any_view_handle(handle) } } @@ -4090,23 +4009,23 @@ impl UpgradeViewHandle for RenderContext<'_, V> { } } -impl UpdateModel for ViewContext<'_, V> { +impl UpdateModel for ViewContext<'_, '_, V> { fn update_model( &mut self, handle: &ModelHandle, update: &mut dyn FnMut(&mut T, &mut ModelContext) -> O, ) -> O { - self.app.update_model(handle, update) + self.window_context.update_model(handle, update) } } -impl ReadView for ViewContext<'_, V> { +impl ReadView for ViewContext<'_, '_, V> { fn read_view(&self, handle: &ViewHandle) -> &T { - self.app.read_view(handle) + self.window_context.read_view(handle) } } -impl UpdateView for ViewContext<'_, V> { +impl UpdateView for ViewContext<'_, '_, V> { fn update_view( &mut self, handle: &ViewHandle, @@ -4115,7 +4034,7 @@ impl UpdateView for ViewContext<'_, V> { where T: View, { - self.app.update_view(handle, update) + self.window_context.update_view(handle, update) } } @@ -4583,7 +4502,7 @@ impl AnyViewHandle { self.view_type } - pub fn debug_json(&self, cx: &AppContext) -> serde_json::Value { + pub fn debug_json<'a, 'b>(&self, cx: &'b WindowContext<'a, 'b>) -> serde_json::Value { cx.views .get(&(self.window_id, self.view_id)) .map_or_else(|| serde_json::Value::Null, |view| view.debug_json(cx)) @@ -5159,7 +5078,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { post_inc(&mut self.render_count); Empty::new().boxed() } @@ -5212,7 +5131,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } @@ -5276,7 +5195,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut RenderContext) -> ElementBox { enum Handler {} let mouse_down_count = self.mouse_down_count.clone(); MouseEventHandler::::new(0, cx, |_, _| Empty::new().boxed()) @@ -5342,7 +5261,7 @@ mod tests { "View" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } } @@ -5860,7 +5779,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } @@ -5925,7 +5844,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } @@ -6101,7 +6020,7 @@ mod tests { } impl View for ViewA { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } @@ -6119,7 +6038,7 @@ mod tests { } impl View for ViewB { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } @@ -6271,7 +6190,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } @@ -6398,7 +6317,7 @@ mod tests { } impl super::View for View1 { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } fn ui_name() -> &'static str { @@ -6406,7 +6325,7 @@ mod tests { } } impl super::View for View2 { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } fn ui_name() -> &'static str { @@ -6581,7 +6500,7 @@ mod tests { "test view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } } @@ -6643,7 +6562,7 @@ mod tests { "test view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().named(format!("render count: {}", post_inc(&mut self.0))) } } @@ -6732,7 +6651,7 @@ mod tests { "test view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } } @@ -6812,7 +6731,7 @@ mod tests { "child view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { self.rendered.set(true); Empty::new().boxed() } @@ -6837,7 +6756,7 @@ mod tests { "parent view" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut RenderContext) -> ElementBox { if let Some(child) = self.child.as_ref() { ChildView::new(child, cx).boxed() } else { @@ -6879,7 +6798,7 @@ mod tests { "TestView" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { Empty::new().boxed() } } diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index b8244f044b..560ba66a77 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -23,8 +23,8 @@ use crate::{ platform, platform::{Appearance, Event, InputHandler, KeyDownEvent, Platform}, Action, AnyViewHandle, AppContext, Entity, FontCache, Handle, ModelContext, ModelHandle, - ReadModelWith, ReadViewWith, RenderContext, Task, UpdateModel, UpdateView, View, ViewContext, - ViewHandle, WeakHandle, + ReadModelWith, ReadViewWith, Task, UpdateModel, UpdateView, View, ViewContext, ViewHandle, + WeakHandle, }; use collections::BTreeMap; diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index ccb5a49ccf..7a167a3c0d 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -1,23 +1,20 @@ use crate::{ app::WindowInvalidation, elements::Element, - font_cache::FontCache, geometry::rect::RectF, json::{self, ToJson}, keymap_matcher::{Keystroke, MatchResult}, platform::{ - self, Appearance, CursorStyle, Event, FontSystem, MouseButton, MouseMovedEvent, - PromptLevel, WindowBounds, + self, Appearance, CursorStyle, Event, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, + MouseButton, MouseMovedEvent, PromptLevel, WindowBounds, }, scene::{ CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene, }, text_layout::TextLayoutCache, - Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, AppContext, - AssetCache, ElementBox, Entity, ModelHandle, MouseRegion, MouseRegionId, MouseState, ParentId, - ReadModel, ReadView, RenderContext, RenderParams, SceneBuilder, UpgradeModelHandle, - UpgradeViewHandle, View, ViewHandle, WeakModelHandle, WeakViewHandle, + Action, AnyView, AnyViewHandle, AnyWeakViewHandle, AppContext, ElementBox, MouseRegion, + MouseRegionId, RenderParams, SceneBuilder, View, }; use anyhow::bail; use collections::{HashMap, HashSet}; @@ -29,11 +26,7 @@ use sqlez::{ bindable::{Bind, Column, StaticColumnCount}, statement::Statement, }; -use std::{ - marker::PhantomData, - ops::{Deref, DerefMut, Range}, - sync::Arc, -}; +use std::ops::{Deref, DerefMut, Range}; use uuid::Uuid; pub struct Window { @@ -44,19 +37,17 @@ pub struct Window { pub(crate) is_fullscreen: bool, pub(crate) invalidation: Option, pub(crate) platform_window: Box, - pub(crate) rendered_views: HashMap, + pub(crate) rendered_views: HashMap>, + titlebar_height: f32, + appearance: Appearance, cursor_regions: Vec, mouse_regions: Vec<(MouseRegion, usize)>, - font_cache: Arc, - text_layout_cache: TextLayoutCache, - asset_cache: Arc, last_mouse_moved_event: Option, hovered_region_ids: HashSet, clicked_region_ids: HashSet, clicked_button: Option, mouse_position: Vector2F, - titlebar_height: f32, - appearance: Appearance, + text_layout_cache: TextLayoutCache, } impl Window { @@ -64,9 +55,6 @@ impl Window { window_id: usize, root_view: AnyViewHandle, platform_window: Box, - font_cache: Arc, - text_layout_cache: TextLayoutCache, - asset_cache: Arc, cx: &mut AppContext, ) -> Self { let focused_view_id = Some(root_view.id()); @@ -83,9 +71,7 @@ impl Window { rendered_views: cx.render_views(window_id, titlebar_height, appearance), cursor_regions: Default::default(), mouse_regions: Default::default(), - font_cache, - text_layout_cache, - asset_cache, + text_layout_cache: TextLayoutCache::new(cx.font_system.clone()), last_mouse_moved_event: None, hovered_region_ids: Default::default(), clicked_region_ids: Default::default(), @@ -100,7 +86,7 @@ impl Window { pub struct WindowContext<'a: 'b, 'b> { app_context: &'a mut AppContext, pub(crate) window: &'b mut Window, // TODO: make this private? - window_id: usize, + pub(crate) window_id: usize, } impl Deref for WindowContext<'_, '_> { @@ -126,9 +112,19 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { } } + pub fn update_any_view(&mut self, view_id: usize, f: F) -> Option + where + F: FnOnce(&mut dyn AnyView, &mut Self) -> T, + { + let view = self.views.remove(&(self.window_id, view_id))?; + let result = f(view.as_any_mut(), self); + self.views.insert((self.window_id, view_id), view); + Some(result) + } + pub fn dispatch_keystroke(&mut self, keystroke: &Keystroke) -> bool { let window_id = self.window_id; - if let Some(focused_view_id) = self.focused_view_id(window_id) { + if let Some(focused_view_id) = self.focused_view_id() { let dispatch_path = self .ancestors(window_id, focused_view_id) .filter_map(|view_id| { @@ -511,20 +507,71 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { any_event_handled } - pub fn build_event_context<'c>( - &'c mut self, - notified_views: &'c mut HashSet, - ) -> EventContext<'c> { - EventContext { - font_cache: &self.window.font_cache, - text_layout_cache: &self.window.text_layout_cache, - view_stack: Default::default(), - notified_views, - notify_count: 0, - handled: false, - window_id: self.window_id, - app: self, + pub fn dispatch_key_down(&mut self, window_id: usize, event: &KeyDownEvent) -> bool { + if let Some(focused_view_id) = self.window.focused_view_id { + for view_id in self + .ancestors(window_id, focused_view_id) + .collect::>() + { + if let Some(mut view) = self.views.remove(&(window_id, view_id)) { + let handled = view.key_down(event, self, view_id); + self.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.window.fo { + for view_id in self + .ancestors(window_id, focused_view_id) + .collect::>() + { + if let Some(mut view) = self.views.remove(&(window_id, view_id)) { + let handled = view.key_up(event, self, view_id); + self.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.window.focused_view_id { + for view_id in self + .ancestors(window_id, focused_view_id) + .collect::>() + { + if let Some(mut view) = self.views.remove(&(window_id, view_id)) { + let handled = view.modifiers_changed(event, self, view_id); + self.views.insert((window_id, view_id), view); + if handled { + return true; + } + } else { + log::error!("view {} does not exist", view_id) + } + } + } + + false } pub fn invalidate(&mut self, invalidation: &mut WindowInvalidation, appearance: Appearance) { @@ -593,113 +640,56 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { } } - pub fn build_scene(&mut self, refreshing: bool) -> Scene { + pub fn build_scene(&mut self) -> Scene { let window_size = self.window.platform_window.content_size(); let scale_factor = self.window.platform_window.scale_factor(); + let root_view_id = self.window.root_view.id(); + let rendered_root = self.window.rendered_views.remove(&root_view_id).unwrap(); + rendered_root.layout(root_view_id, SizeConstraint::strict(window_size), self); + let mut scene_builder = SceneBuilder::new(scale_factor); + let paint_bounds = RectF::from_points(Vector2F::zero(), window_size); + rendered_root.paint( + root_view_id, + &mut scene_builder, + paint_bounds, + paint_bounds, + self, + ); - if let Some(root_view_id) = self.root_view_id(self.window_id) { - self.layout(window_size, refreshing, self); - let mut paint_cx = self.build_paint_context(&mut scene_builder, window_size); - paint_cx.paint( - root_view_id, - Vector2F::zero(), - RectF::new(Vector2F::zero(), window_size), - ); - self.window.text_layout_cache.finish_frame(); - let scene = scene_builder.build(); - self.window.cursor_regions = scene.cursor_regions(); - self.window.mouse_regions = scene.mouse_regions(); + self.window.text_layout_cache.finish_frame(); + let scene = scene_builder.build(); + self.window.cursor_regions = scene.cursor_regions(); + self.window.mouse_regions = scene.mouse_regions(); - // window.is_topmost for the mouse moved event's postion? - if self.window_is_active(self.window_id) { - if let Some(event) = self.window.last_mouse_moved_event.clone() { - self.dispatch_event(event, true); - } + if self.window_is_active() { + if let Some(event) = self.window.last_mouse_moved_event.clone() { + self.dispatch_event(event, true); } - - scene - } else { - log::error!("could not find root_view_id for window {}", self.window_id); - scene_builder.build() } - } - fn layout(&mut self, window_size: Vector2F, refreshing: bool, cx: &mut AppContext) { - if let Some(root_view_id) = cx.root_view_id(self.window_id) { - self.build_layout_context(window_size, refreshing, cx) - .layout(root_view_id, SizeConstraint::strict(window_size)); - } - } - - pub fn build_layout_context<'c>( - &'c mut self, - window_size: Vector2F, - refreshing: bool, - cx: &'c mut AppContext, - ) -> LayoutContext<'c> { - LayoutContext { - window_id: self.window_id, - rendered_views: &mut self.window.rendered_views, - font_cache: &self.font_cache, - font_system: cx.platform().fonts(), - text_layout_cache: &self.window.text_layout_cache, - asset_cache: &self.window.asset_cache, - view_stack: Vec::new(), - refreshing, - hovered_region_ids: self.window.hovered_region_ids.clone(), - clicked_region_ids: self - .window - .clicked_button - .map(|button| (self.window.clicked_region_ids.clone(), button)), - titlebar_height: self.window.titlebar_height, - appearance: self.window.appearance, - window_size, - app: cx, - } - } - - pub fn build_paint_context<'c>( - &'c mut self, - scene: &'c mut SceneBuilder, - window_size: Vector2F, - ) -> PaintContext { - PaintContext { - scene, - window_size, - font_cache: &self.font_cache, - text_layout_cache: &self.window.text_layout_cache, - rendered_views: &mut self.window.rendered_views, - view_stack: Vec::new(), - app: self, - } + scene } pub fn rect_for_text_range(&self, range_utf16: Range) -> Option { - self.focused_view_id(self.window_id).and_then(|view_id| { - let cx = MeasurementContext { - app: self, - rendered_views: &self.window.rendered_views, - window_id: self.window_id, - }; - cx.rect_for_text_range(view_id, range_utf16) - }) + todo!() } pub fn debug_elements(&self) -> Option { - let view = self.root_view(self.window_id)?; - Some(json!({ - "root_view": view.debug_json(self), - "root_element": self.window.rendered_views.get(&view.id()) - .map(|root_element| { - root_element.debug(&DebugContext { - rendered_views: &self.window.rendered_views, - font_cache: &self.window.font_cache, - app: self, - }) - }) - })) + todo!() + // let view = self.root_view()?; + // Some(json!({ + // "root_view": view.debug_json(self), + // "root_element": self.window.rendered_views.get(&view.id()) + // .map(|root_element| { + // root_element.debug(&DebugContext { + // rendered_views: &self.window.rendered_views, + // font_cache: &self.window.font_cache, + // app: self, + // }) + // }) + // })) } pub fn set_window_title(&mut self, title: &str) { @@ -720,6 +710,26 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { self.window.platform_window.activate(); } + pub fn window_is_active(&self) -> bool { + self.window.is_active + } + + pub fn window_is_fullscreen(&self) -> bool { + self.window.is_fullscreen + } + + pub fn root_view(&self, window_id: usize) -> &AnyViewHandle { + &self.window.root_view + } + + pub fn root_view_id(&self) -> usize { + self.window.root_view.id() + } + + pub fn focused_view_id(&self) -> Option { + self.window.focused_view_id + } + pub fn window_bounds(&self) -> WindowBounds { self.window.platform_window.bounds() } @@ -754,330 +764,48 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { } } -pub struct LayoutContext<'a> { - window_id: usize, - rendered_views: &'a mut HashMap, - view_stack: Vec, - pub font_cache: &'a Arc, - pub font_system: Arc, - pub text_layout_cache: &'a TextLayoutCache, - pub asset_cache: &'a AssetCache, - pub app: &'a mut AppContext, - pub refreshing: bool, - pub window_size: Vector2F, - titlebar_height: f32, - appearance: Appearance, - hovered_region_ids: HashSet, - clicked_region_ids: Option<(HashSet, MouseButton)>, +pub trait RenderedView { + fn layout( + &self, + view_id: usize, + constraint: SizeConstraint, + cx: &mut WindowContext, + ) -> Vector2F; + fn paint( + &self, + view_id: usize, + scene: &mut SceneBuilder, + bounds: RectF, + visible_bounds: RectF, + cx: &mut WindowContext, + ); } -impl<'a> LayoutContext<'a> { - pub fn mouse_state(&self, region_id: usize) -> MouseState { - let view_id = self.view_stack.last().unwrap(); - - let region_id = MouseRegionId::new::(*view_id, region_id); - MouseState { - hovered: self.hovered_region_ids.contains(®ion_id), - clicked: self.clicked_region_ids.as_ref().and_then(|(ids, button)| { - if ids.contains(®ion_id) { - Some(*button) - } else { - None - } - }), - accessed_hovered: false, - accessed_clicked: false, - } +impl RenderedView for ElementBox { + fn layout( + &self, + view_id: usize, + constraint: SizeConstraint, + cx: &mut WindowContext, + ) -> Vector2F { + cx.update_view_for_id(view_id, |view, cx| self.layout(view, constraint, cx)) + .unwrap() } - fn layout(&mut self, view_id: usize, constraint: SizeConstraint) -> Vector2F { - let print_error = |view_id| { - format!( - "{} with id {}", - self.app.name_for_view(self.window_id, view_id).unwrap(), - view_id, - ) - }; - match ( - self.view_stack.last(), - self.app.parents.get(&(self.window_id, view_id)), - ) { - (Some(layout_parent), Some(ParentId::View(app_parent))) => { - if layout_parent != app_parent { - panic!( - "View {} was laid out with parent {} when it was constructed with parent {}", - print_error(view_id), - print_error(*layout_parent), - print_error(*app_parent)) - } - } - (None, Some(ParentId::View(app_parent))) => panic!( - "View {} was laid out without a parent when it was constructed with parent {}", - print_error(view_id), - print_error(*app_parent) - ), - (Some(layout_parent), Some(ParentId::Root)) => panic!( - "View {} was laid out with parent {} when it was constructed as a window root", - print_error(view_id), - print_error(*layout_parent), - ), - (_, None) => panic!( - "View {} did not have a registered parent in the app context", - print_error(view_id), - ), - _ => {} - } - - self.view_stack.push(view_id); - let mut rendered_view = self.rendered_views.remove(&view_id).unwrap(); - let size = rendered_view.layout(constraint, self); - self.rendered_views.insert(view_id, rendered_view); - self.view_stack.pop(); - size - } - - pub fn render(&mut self, handle: &ViewHandle, f: F) -> T - where - F: FnOnce(&mut V, &mut RenderContext) -> T, - V: View, - { - handle.update(self.app, |view, cx| { - let mut render_cx = RenderContext { - app: cx, - window_id: handle.window_id(), - view_id: handle.id(), - view_type: PhantomData, - titlebar_height: self.titlebar_height, - hovered_region_ids: self.hovered_region_ids.clone(), - clicked_region_ids: self.clicked_region_ids.clone(), - refreshing: self.refreshing, - appearance: self.appearance, - }; - f(view, &mut render_cx) + fn paint( + &self, + view_id: usize, + scene: &mut SceneBuilder, + bounds: RectF, + visible_bounds: RectF, + cx: &mut WindowContext, + ) { + cx.update_view_for_id(view_id, |view, cx| { + self.paint(view, scene, bounds, visible_bounds, cx) }) } } -impl<'a> Deref for LayoutContext<'a> { - type Target = AppContext; - - fn deref(&self) -> &Self::Target { - self.app - } -} - -impl<'a> DerefMut for LayoutContext<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.app - } -} - -impl<'a> ReadView for LayoutContext<'a> { - fn read_view(&self, handle: &ViewHandle) -> &T { - self.app.read_view(handle) - } -} - -impl<'a> ReadModel for LayoutContext<'a> { - fn read_model(&self, handle: &ModelHandle) -> &T { - self.app.read_model(handle) - } -} - -impl<'a> UpgradeModelHandle for LayoutContext<'a> { - fn upgrade_model_handle( - &self, - handle: &WeakModelHandle, - ) -> Option> { - self.app.upgrade_model_handle(handle) - } - - fn model_handle_is_upgradable(&self, handle: &WeakModelHandle) -> bool { - self.app.model_handle_is_upgradable(handle) - } - - fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option { - self.app.upgrade_any_model_handle(handle) - } -} - -impl<'a> UpgradeViewHandle for LayoutContext<'a> { - fn upgrade_view_handle(&self, handle: &WeakViewHandle) -> Option> { - self.app.upgrade_view_handle(handle) - } - - fn upgrade_any_view_handle(&self, handle: &crate::AnyWeakViewHandle) -> Option { - self.app.upgrade_any_view_handle(handle) - } -} - -pub struct PaintContext<'a> { - rendered_views: &'a mut HashMap, - view_stack: Vec, - pub window_size: Vector2F, - pub scene: &'a mut SceneBuilder, - pub font_cache: &'a FontCache, - pub text_layout_cache: &'a TextLayoutCache, - pub app: &'a AppContext, -} - -impl<'a> PaintContext<'a> { - fn paint(&mut self, view_id: usize, origin: Vector2F, visible_bounds: RectF) { - if let Some(mut tree) = self.rendered_views.remove(&view_id) { - self.view_stack.push(view_id); - tree.paint(origin, visible_bounds, self); - self.rendered_views.insert(view_id, tree); - self.view_stack.pop(); - } - } - - #[inline] - pub fn paint_stacking_context( - &mut self, - clip_bounds: Option, - z_index: Option, - f: F, - ) where - F: FnOnce(&mut Self), - { - self.scene.push_stacking_context(clip_bounds, z_index); - f(self); - self.scene.pop_stacking_context(); - } - - #[inline] - pub fn paint_layer(&mut self, clip_bounds: Option, f: F) - where - F: FnOnce(&mut Self), - { - self.scene.push_layer(clip_bounds); - f(self); - self.scene.pop_layer(); - } - - pub fn current_view_id(&self) -> usize { - *self.view_stack.last().unwrap() - } -} - -impl<'a> Deref for PaintContext<'a> { - type Target = AppContext; - - fn deref(&self) -> &Self::Target { - self.app - } -} - -pub struct EventContext<'a> { - pub font_cache: &'a FontCache, - pub text_layout_cache: &'a TextLayoutCache, - pub app: &'a mut AppContext, - pub window_id: usize, - pub notify_count: usize, - view_stack: Vec, - handled: bool, - notified_views: &'a mut HashSet, -} - -impl<'a> EventContext<'a> { - fn with_current_view(&mut self, view_id: usize, f: F) -> T - where - F: FnOnce(&mut Self) -> T, - { - self.view_stack.push(view_id); - let result = f(self); - self.view_stack.pop(); - result - } - - pub fn window_id(&self) -> usize { - self.window_id - } - - pub fn view_id(&self) -> Option { - self.view_stack.last().copied() - } - - pub fn is_parent_view_focused(&self) -> bool { - if let Some(parent_view_id) = self.view_stack.last() { - self.app.focused_view_id(self.window_id) == Some(*parent_view_id) - } else { - false - } - } - - pub fn focus_parent_view(&mut self) { - if let Some(parent_view_id) = self.view_stack.last() { - self.app.focus(self.window_id, Some(*parent_view_id)) - } - } - - pub fn dispatch_any_action(&mut self, action: Box) { - self.app - .dispatch_any_action_at(self.window_id, *self.view_stack.last().unwrap(), action) - } - - pub fn dispatch_action(&mut self, action: A) { - self.dispatch_any_action(Box::new(action)); - } - - pub fn notify(&mut self) { - self.notify_count += 1; - if let Some(view_id) = self.view_stack.last() { - self.notified_views.insert(*view_id); - } - } - - pub fn notify_count(&self) -> usize { - self.notify_count - } - - pub fn propagate_event(&mut self) { - self.handled = false; - } -} - -impl<'a> Deref for EventContext<'a> { - type Target = AppContext; - - fn deref(&self) -> &Self::Target { - self.app - } -} - -impl<'a> DerefMut for EventContext<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.app - } -} - -pub struct MeasurementContext<'a> { - app: &'a AppContext, - rendered_views: &'a HashMap, - pub window_id: usize, -} - -impl<'a> Deref for MeasurementContext<'a> { - type Target = AppContext; - - fn deref(&self) -> &Self::Target { - self.app - } -} - -impl<'a> MeasurementContext<'a> { - fn rect_for_text_range(&self, view_id: usize, range_utf16: Range) -> Option { - let element = self.rendered_views.get(&view_id)?; - element.rect_for_text_range(range_utf16, self) - } -} - -pub struct DebugContext<'a> { - rendered_views: &'a HashMap, - pub font_cache: &'a FontCache, - pub app: &'a AppContext, -} - #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub enum Axis { #[default] @@ -1235,88 +963,88 @@ impl ChildView { } } -impl Element for ChildView { - type LayoutState = bool; - type PaintState = (); +// impl Element for ChildView { +// type LayoutState = bool; +// type PaintState = (); - fn layout( - &mut self, - constraint: SizeConstraint, - cx: &mut LayoutContext, - ) -> (Vector2F, Self::LayoutState) { - if cx.rendered_views.contains_key(&self.view.id()) { - let size = cx.layout(self.view.id(), constraint); - (size, true) - } else { - log::error!( - "layout called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", - self.view.id(), - self.view_name - ); - (Vector2F::zero(), false) - } - } +// fn layout( +// &mut self, +// constraint: SizeConstraint, +// cx: &mut LayoutContext, +// ) -> (Vector2F, Self::LayoutState) { +// if cx.rendered_views.contains_key(&self.view.id()) { +// let size = cx.layout(self.view.id(), constraint); +// (size, true) +// } else { +// log::error!( +// "layout called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", +// self.view.id(), +// self.view_name +// ); +// (Vector2F::zero(), false) +// } +// } - fn paint( - &mut self, - bounds: RectF, - visible_bounds: RectF, - view_is_valid: &mut Self::LayoutState, - cx: &mut PaintContext, - ) { - if *view_is_valid { - cx.paint(self.view.id(), bounds.origin(), visible_bounds); - } else { - log::error!( - "paint called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", - self.view.id(), - self.view_name - ); - } - } +// fn paint( +// &mut self, +// bounds: RectF, +// visible_bounds: RectF, +// view_is_valid: &mut Self::LayoutState, +// cx: &mut PaintContext, +// ) { +// if *view_is_valid { +// cx.paint(self.view.id(), bounds.origin(), visible_bounds); +// } else { +// log::error!( +// "paint called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", +// self.view.id(), +// self.view_name +// ); +// } +// } - fn rect_for_text_range( - &self, - range_utf16: Range, - _: RectF, - _: RectF, - view_is_valid: &Self::LayoutState, - _: &Self::PaintState, - cx: &MeasurementContext, - ) -> Option { - if *view_is_valid { - cx.rect_for_text_range(self.view.id(), range_utf16) - } else { - log::error!( - "rect_for_text_range called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", - self.view.id(), - self.view_name - ); - None - } - } +// fn rect_for_text_range( +// &self, +// range_utf16: Range, +// _: RectF, +// _: RectF, +// view_is_valid: &Self::LayoutState, +// _: &Self::PaintState, +// cx: &MeasurementContext, +// ) -> Option { +// if *view_is_valid { +// cx.rect_for_text_range(self.view.id(), range_utf16) +// } else { +// log::error!( +// "rect_for_text_range called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", +// self.view.id(), +// self.view_name +// ); +// None +// } +// } - fn debug( - &self, - bounds: RectF, - _: &Self::LayoutState, - _: &Self::PaintState, - cx: &DebugContext, - ) -> serde_json::Value { - json!({ - "type": "ChildView", - "view_id": self.view.id(), - "bounds": bounds.to_json(), - "view": if let Some(view) = self.view.upgrade(cx.app) { - view.debug_json(cx.app) - } else { - json!(null) - }, - "child": if let Some(view) = cx.rendered_views.get(&self.view.id()) { - view.debug(cx) - } else { - json!(null) - } - }) - } -} +// fn debug( +// &self, +// bounds: RectF, +// _: &Self::LayoutState, +// _: &Self::PaintState, +// cx: &DebugContext, +// ) -> serde_json::Value { +// json!({ +// "type": "ChildView", +// "view_id": self.view.id(), +// "bounds": bounds.to_json(), +// "view": if let Some(view) = self.view.upgrade(cx.app) { +// view.debug_json(cx.app) +// } else { +// json!(null) +// }, +// "child": if let Some(view) = cx.rendered_views.get(&self.view.id()) { +// view.debug(cx) +// } else { +// json!(null) +// } +// }) +// } +// } diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index 6322f99772..e5125e11a8 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -32,42 +32,52 @@ use crate::{ rect::RectF, vector::{vec2f, Vector2F}, }, - json, Action, DebugContext, EventContext, LayoutContext, PaintContext, RenderContext, - SizeConstraint, View, + json, Action, RenderContext, SceneBuilder, SizeConstraint, View, ViewContext, }; use core::panic; use json::ToJson; -use std::{ - any::Any, - borrow::Cow, - cell::RefCell, - mem, - ops::{Deref, DerefMut, Range}, - rc::Rc, -}; +use std::{any::Any, borrow::Cow, cell::RefCell, marker::PhantomData, mem, ops::Range}; + +trait AnyElement { + fn layout( + &mut self, + view: &mut V, + constraint: SizeConstraint, + cx: &mut ViewContext, + ) -> Vector2F; + + fn paint( + &mut self, + view: &mut V, + scene: &mut SceneBuilder, + origin: Vector2F, + visible_bounds: RectF, + cx: &mut ViewContext, + ); -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 rect_for_text_range( &self, + view: &V, range_utf16: Range, - cx: &MeasurementContext, + cx: &ViewContext, ) -> Option; - fn debug(&self, cx: &DebugContext) -> serde_json::Value; + + fn debug(&self, view: &V, cx: &mut ViewContext) -> serde_json::Value; fn size(&self) -> Vector2F; + fn metadata(&self) -> Option<&dyn Any>; } -pub trait Element { +pub trait Element { type LayoutState; type PaintState; fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState); fn paint( @@ -75,7 +85,8 @@ pub trait Element { bounds: RectF, visible_bounds: RectF, layout: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState; fn rect_for_text_range( @@ -85,7 +96,8 @@ pub trait Element { visible_bounds: RectF, layout: &Self::LayoutState, paint: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option; fn metadata(&self) -> Option<&dyn Any> { @@ -97,27 +109,28 @@ pub trait Element { bounds: RectF, layout: &Self::LayoutState, paint: &Self::PaintState, - cx: &DebugContext, + view: &V, + cx: &ViewContext, ) -> serde_json::Value; - fn boxed(self) -> ElementBox + fn boxed(self) -> ElementBox where Self: 'static + Sized, { - ElementBox(ElementRc { + ElementBox { + element: RefCell::new(Lifecycle::Init { element: self }), name: None, - element: Rc::new(RefCell::new(Lifecycle::Init { element: self })), - }) + } } - fn named(self, name: impl Into>) -> ElementBox + fn named(self, name: impl Into>) -> ElementBox where Self: 'static + Sized, { - ElementBox(ElementRc { + ElementBox { + element: RefCell::new(Lifecycle::Init { element: self }), name: Some(name.into()), - element: Rc::new(RefCell::new(Lifecycle::Init { element: self })), - }) + } } fn constrained(self) -> ConstrainedBox @@ -205,44 +218,41 @@ pub trait Element { } } -pub enum Lifecycle { +pub enum Lifecycle> { Empty, Init { - element: T, + element: E, }, PostLayout { - element: T, + element: E, constraint: SizeConstraint, size: Vector2F, - layout: T::LayoutState, + layout: E::LayoutState, }, PostPaint { - element: T, + element: E, constraint: SizeConstraint, bounds: RectF, visible_bounds: RectF, - layout: T::LayoutState, - paint: T::PaintState, + layout: E::LayoutState, + paint: E::PaintState, }, } -pub struct ElementBox(ElementRc); - -#[derive(Clone)] -pub struct ElementRc { - name: Option>, - element: Rc>, -} - -impl AnyElement for Lifecycle { - fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F { +impl> AnyElement for Lifecycle { + fn layout( + &mut self, + view: &mut V, + constraint: SizeConstraint, + cx: &mut ViewContext, + ) -> Vector2F { let result; *self = match mem::take(self) { Lifecycle::Empty => unreachable!(), Lifecycle::Init { mut element } | Lifecycle::PostLayout { mut element, .. } | Lifecycle::PostPaint { mut element, .. } => { - let (size, layout) = element.layout(constraint, cx); + let (size, layout) = element.layout(view, constraint, cx); debug_assert!(size.x().is_finite()); debug_assert!(size.y().is_finite()); @@ -258,7 +268,13 @@ impl AnyElement for Lifecycle { result } - fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) { + fn paint( + &mut self, + view: &mut V, + origin: Vector2F, + visible_bounds: RectF, + cx: &mut ViewContext, + ) { *self = match mem::take(self) { Lifecycle::PostLayout { mut element, @@ -267,7 +283,7 @@ impl AnyElement for Lifecycle { mut layout, } => { let bounds = RectF::new(origin, size); - let paint = element.paint(bounds, visible_bounds, &mut layout, cx); + let paint = element.paint(view, bounds, visible_bounds, &mut layout, cx); Lifecycle::PostPaint { element, constraint, @@ -285,7 +301,7 @@ impl AnyElement for Lifecycle { .. } => { let bounds = RectF::new(origin, bounds.size()); - let paint = element.paint(bounds, visible_bounds, &mut layout, cx); + let paint = element.paint(view, bounds, visible_bounds, &mut layout, cx); Lifecycle::PostPaint { element, constraint, @@ -304,8 +320,9 @@ impl AnyElement for Lifecycle { fn rect_for_text_range( &self, + view: &V, range_utf16: Range, - cx: &MeasurementContext, + cx: &mut ViewContext, ) -> Option { if let Lifecycle::PostPaint { element, @@ -316,7 +333,15 @@ impl AnyElement for Lifecycle { .. } = self { - element.rect_for_text_range(range_utf16, *bounds, *visible_bounds, layout, paint, cx) + element.rect_for_text_range( + view, + range_utf16, + *bounds, + *visible_bounds, + layout, + paint, + cx, + ) } else { None } @@ -339,7 +364,7 @@ impl AnyElement for Lifecycle { } } - fn debug(&self, cx: &DebugContext) -> serde_json::Value { + fn debug(&self, view: &V, cx: &ViewContext) -> serde_json::Value { match self { Lifecycle::PostPaint { element, @@ -349,7 +374,7 @@ impl AnyElement for Lifecycle { layout, paint, } => { - let mut value = element.debug(*bounds, layout, paint, cx); + let mut value = element.debug(view, *bounds, layout, paint, cx); if let json::Value::Object(map) = &mut value { let mut new_map: crate::json::Map = Default::default(); @@ -371,72 +396,67 @@ impl AnyElement for Lifecycle { } } -impl Default for Lifecycle { +impl> Default for Lifecycle { fn default() -> Self { Self::Empty } } -impl ElementBox { +pub struct ElementBox { + element: RefCell>, + view_type: PhantomData, + name: Option>, +} + +impl ElementBox { pub fn name(&self) -> Option<&str> { self.0.name.as_deref() } pub fn metadata(&self) -> Option<&T> { - let element = unsafe { &*self.0.element.as_ptr() }; - element.metadata().and_then(|m| m.downcast_ref()) - } -} - -impl Clone for ElementBox { - fn clone(&self) -> Self { - ElementBox(self.0.clone()) - } -} - -impl From for ElementRc { - fn from(val: ElementBox) -> Self { - val.0 - } -} - -impl Deref for ElementBox { - type Target = ElementRc; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for ElementBox { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl ElementRc { - pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F { - self.element.borrow_mut().layout(constraint, cx) + // let element = unsafe { &*self.0.element.as_ptr() }; + // element.metadata().and_then(|m| m.downcast_ref()) } - pub fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) { - self.element.borrow_mut().paint(origin, visible_bounds, cx); + pub fn layout( + &self, + view: &mut V, + constraint: SizeConstraint, + cx: &mut ViewContext, + ) -> Vector2F { + self.element.borrow_mut().layout(view, constraint, cx) + } + + pub fn paint( + &self, + view: &mut V, + scene: &mut SceneBuilder, + origin: Vector2F, + visible_bounds: RectF, + cx: &mut ViewContext, + ) { + self.element + .borrow_mut() + .paint(view, scene, origin, visible_bounds, cx); } pub fn rect_for_text_range( &self, + view: &V, range_utf16: Range, - cx: &MeasurementContext, + cx: &ViewContext, ) -> Option { - self.element.borrow().rect_for_text_range(range_utf16, cx) + self.element + .borrow() + .rect_for_text_range(view, range_utf16, cx) } pub fn size(&self) -> Vector2F { self.element.borrow().size() } - pub fn debug(&self, cx: &DebugContext) -> json::Value { - let mut value = self.element.borrow().debug(cx); + pub fn debug(&self, view: &V, cx: &ViewContext) -> json::Value { + let mut value = self.element.borrow().debug(view, cx); if let Some(name) = &self.name { if let json::Value::Object(map) = &mut value { @@ -460,26 +480,26 @@ impl ElementRc { } } -pub trait ParentElement<'a>: Extend + Sized { - fn add_children(&mut self, children: impl IntoIterator) { +pub trait ParentElement<'a, V: View>: Extend> + Sized { + fn add_children(&mut self, children: impl IntoIterator>) { self.extend(children); } - fn add_child(&mut self, child: ElementBox) { + fn add_child(&mut self, child: ElementBox) { self.add_children(Some(child)); } - fn with_children(mut self, children: impl IntoIterator) -> Self { + fn with_children(mut self, children: impl IntoIterator>) -> Self { self.add_children(children); self } - fn with_child(self, child: ElementBox) -> Self { + fn with_child(self, child: ElementBox) -> Self { self.with_children(Some(child)) } } -impl<'a, T> ParentElement<'a> for T where T: Extend {} +impl<'a, V: View, T> ParentElement<'a, V> for T where T: Extend> {} pub fn constrain_size_preserving_aspect_ratio(max_size: Vector2F, size: Vector2F) -> Vector2F { if max_size.x().is_infinite() && max_size.y().is_infinite() { diff --git a/crates/gpui/src/elements/align.rs b/crates/gpui/src/elements/align.rs index 9887fc71d7..8915dc2b4f 100644 --- a/crates/gpui/src/elements/align.rs +++ b/crates/gpui/src/elements/align.rs @@ -1,20 +1,18 @@ use crate::{ geometry::{rect::RectF, vector::Vector2F}, - json, - window::MeasurementContext, - DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, + json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext, }; use json::ToJson; use serde_json::json; -pub struct Align { - child: ElementBox, +pub struct Align { + child: ElementBox, alignment: Vector2F, } -impl Align { - pub fn new(child: ElementBox) -> Self { +impl Align { + pub fn new(child: ElementBox) -> Self { Self { child, alignment: Vector2F::zero(), @@ -42,18 +40,19 @@ impl Align { } } -impl Element for Align { +impl Element for Align { type LayoutState = (); type PaintState = (); fn layout( &mut self, + view: &mut V, mut constraint: SizeConstraint, - cx: &mut LayoutContext, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.max; constraint.min = Vector2F::zero(); - let child_size = self.child.layout(constraint, cx); + let child_size = self.child.layout(view, constraint, cx); if size.x().is_infinite() { size.set_x(child_size.x()); } @@ -65,10 +64,12 @@ impl Element for Align { fn paint( &mut self, + view: &mut V, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + cx: &mut ViewContext, ) -> Self::PaintState { let my_center = bounds.size() / 2.; let my_target = my_center + my_center * self.alignment; @@ -77,6 +78,8 @@ impl Element for Align { let child_target = child_center + child_center * self.alignment; self.child.paint( + view, + scene, bounds.origin() - (child_target - my_target), visible_bounds, cx, @@ -85,28 +88,30 @@ impl Element for Align { fn rect_for_text_range( &self, + view: &V, range_utf16: std::ops::Range, _: RectF, _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(view, range_utf16, cx) } fn debug( &self, + view: &V, bounds: pathfinder_geometry::rect::RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &DebugContext, + cx: &ViewContext, ) -> json::Value { json!({ "type": "Align", "bounds": bounds.to_json(), "alignment": self.alignment.to_json(), - "child": self.child.debug(cx), + "child": self.child.debug(view, cx), }) } } diff --git a/crates/gpui/src/elements/canvas.rs b/crates/gpui/src/elements/canvas.rs index 8dcdcce5ea..10d222c506 100644 --- a/crates/gpui/src/elements/canvas.rs +++ b/crates/gpui/src/elements/canvas.rs @@ -1,8 +1,7 @@ use super::Element; use crate::{ json::{self, json}, - window::MeasurementContext, - DebugContext, PaintContext, + SceneBuilder, View, ViewContext, }; use json::ToJson; use pathfinder_geometry::{ @@ -10,20 +9,20 @@ use pathfinder_geometry::{ vector::{vec2f, Vector2F}, }; -pub struct Canvas(F); +pub struct Canvas(F); -impl Canvas +impl Canvas where - F: FnMut(RectF, RectF, &mut PaintContext), + F: FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext), { pub fn new(f: F) -> Self { Self(f) } } -impl Element for Canvas +impl Element for Canvas where - F: FnMut(RectF, RectF, &mut PaintContext), + F: FnMut(RectF, RectF, &mut ViewContext), { type LayoutState = (); type PaintState = (); @@ -48,10 +47,12 @@ where fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { self.0(bounds, visible_bounds, cx) } @@ -63,7 +64,8 @@ where _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &V, + _: &ViewContext, ) -> Option { None } @@ -73,7 +75,8 @@ where bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &DebugContext, + _: &V, + _: &ViewContext, ) -> json::Value { json!({"type": "Canvas", "bounds": bounds.to_json()}) } diff --git a/crates/gpui/src/elements/clipped.rs b/crates/gpui/src/elements/clipped.rs index 2ee7b542a8..96c4f46f22 100644 --- a/crates/gpui/src/elements/clipped.rs +++ b/crates/gpui/src/elements/clipped.rs @@ -3,42 +3,43 @@ use std::ops::Range; use pathfinder_geometry::{rect::RectF, vector::Vector2F}; use serde_json::json; -use crate::{ - json, DebugContext, Element, ElementBox, LayoutContext, MeasurementContext, PaintContext, - SizeConstraint, -}; +use crate::{json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext}; -pub struct Clipped { - child: ElementBox, +pub struct Clipped { + child: ElementBox, } -impl Clipped { - pub fn new(child: ElementBox) -> Self { +impl Clipped { + pub fn new(child: ElementBox) -> Self { Self { child } } } -impl Element for Clipped { +impl Element for Clipped { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { - (self.child.layout(constraint, cx), ()) + (self.child.layout(constraint, view, cx), ()) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { cx.scene.push_layer(Some(bounds)); - self.child.paint(bounds.origin(), visible_bounds, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); cx.scene.pop_layer(); } @@ -49,9 +50,10 @@ impl Element for Clipped { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn debug( @@ -59,11 +61,12 @@ impl Element for Clipped { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &DebugContext, + view: &V, + cx: &ViewContext, ) -> json::Value { json!({ "type": "Clipped", - "child": self.child.debug(cx) + "child": self.child.debug(view, cx) }) } } diff --git a/crates/gpui/src/elements/constrained_box.rs b/crates/gpui/src/elements/constrained_box.rs index ca48fdcbed..64d78e87a9 100644 --- a/crates/gpui/src/elements/constrained_box.rs +++ b/crates/gpui/src/elements/constrained_box.rs @@ -5,22 +5,20 @@ use serde_json::json; use crate::{ geometry::{rect::RectF, vector::Vector2F}, - json, - window::MeasurementContext, - DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, + json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext, }; -pub struct ConstrainedBox { - child: ElementBox, - constraint: Constraint, +pub struct ConstrainedBox { + child: ElementBox, + constraint: Constraint, } -pub enum Constraint { +pub enum Constraint { Static(SizeConstraint), - Dynamic(Box SizeConstraint>), + Dynamic(Box) -> SizeConstraint>), } -impl ToJson for Constraint { +impl ToJson for Constraint { fn to_json(&self) -> serde_json::Value { match self { Constraint::Static(constraint) => constraint.to_json(), @@ -29,8 +27,8 @@ impl ToJson for Constraint { } } -impl ConstrainedBox { - pub fn new(child: ElementBox) -> Self { +impl ConstrainedBox { + pub fn new(child: ElementBox) -> Self { Self { child, constraint: Constraint::Static(Default::default()), @@ -39,7 +37,7 @@ impl ConstrainedBox { pub fn dynamically( mut self, - constraint: impl 'static + FnMut(SizeConstraint, &mut LayoutContext) -> SizeConstraint, + constraint: impl 'static + FnMut(SizeConstraint, &mut V, &mut ViewContext) -> SizeConstraint, ) -> Self { self.constraint = Constraint::Dynamic(Box::new(constraint)); self @@ -120,41 +118,48 @@ impl ConstrainedBox { fn constraint( &mut self, input_constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> SizeConstraint { match &mut self.constraint { Constraint::Static(constraint) => *constraint, - Constraint::Dynamic(compute_constraint) => compute_constraint(input_constraint, cx), + Constraint::Dynamic(compute_constraint) => { + compute_constraint(input_constraint, view, cx) + } } } } -impl Element for ConstrainedBox { +impl Element for ConstrainedBox { type LayoutState = (); type PaintState = (); fn layout( &mut self, mut parent_constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { - let constraint = self.constraint(parent_constraint, cx); + let constraint = self.constraint(parent_constraint, view, cx); parent_constraint.min = parent_constraint.min.max(constraint.min); parent_constraint.max = parent_constraint.max.min(constraint.max); parent_constraint.max = parent_constraint.max.max(parent_constraint.min); - let size = self.child.layout(parent_constraint, cx); + let size = self.child.layout(parent_constraint, view, cx); (size, ()) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { cx.paint_layer(Some(visible_bounds), |cx| { - self.child.paint(bounds.origin(), visible_bounds, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); }) } @@ -165,9 +170,10 @@ impl Element for ConstrainedBox { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn debug( @@ -175,8 +181,9 @@ impl Element for ConstrainedBox { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &DebugContext, + view: &V, + cx: &ViewContext, ) -> json::Value { - json!({"type": "ConstrainedBox", "assigned_constraint": self.constraint.to_json(), "child": self.child.debug(cx)}) + json!({"type": "ConstrainedBox", "assigned_constraint": self.constraint.to_json(), "child": self.child.debug(view, cx)}) } } diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index 11ef42c413..531f893c4f 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -10,8 +10,7 @@ use crate::{ json::ToJson, platform::CursorStyle, scene::{self, Border, CursorRegion, Quad}, - window::MeasurementContext, - Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, + Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext, }; use serde::Deserialize; use serde_json::json; @@ -36,13 +35,13 @@ pub struct ContainerStyle { pub cursor: Option, } -pub struct Container { - child: ElementBox, +pub struct Container { + child: ElementBox, style: ContainerStyle, } -impl Container { - pub fn new(child: ElementBox) -> Self { +impl Container { + pub fn new(child: ElementBox) -> Self { Self { child, style: Default::default(), @@ -185,14 +184,15 @@ impl Container { } } -impl Element for Container { +impl Element for Container { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let mut size_buffer = self.margin_size() + self.padding_size(); if !self.style.border.overlay { @@ -202,16 +202,18 @@ impl Element for Container { min: (constraint.min - size_buffer).max(Vector2F::zero()), max: (constraint.max - size_buffer).max(Vector2F::zero()), }; - let child_size = self.child.layout(child_constraint, cx); + let child_size = self.child.layout(child_constraint, view, cx); (child_size + size_buffer, ()) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { let quad_bounds = RectF::from_points( bounds.origin() + vec2f(self.style.margin.left, self.style.margin.top), @@ -247,7 +249,8 @@ impl Element for Container { corner_radius: self.style.corner_radius, }); - self.child.paint(child_origin, visible_bounds, cx); + self.child + .paint(scene, child_origin, visible_bounds, view, cx); cx.scene.push_layer(None); cx.scene.push_quad(Quad { @@ -270,7 +273,8 @@ impl Element for Container { self.style.border.left_width(), self.style.border.top_width(), ); - self.child.paint(child_origin, visible_bounds, cx); + self.child + .paint(scene, child_origin, visible_bounds, view, cx); if self.style.overlay_color.is_some() { cx.scene.push_layer(None); @@ -292,9 +296,10 @@ impl Element for Container { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn debug( @@ -302,13 +307,14 @@ impl Element for Container { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, + view: &V, cx: &crate::DebugContext, ) -> serde_json::Value { json!({ "type": "Container", "bounds": bounds.to_json(), "details": self.style.to_json(), - "child": self.child.debug(cx), + "child": self.child.debug(view, cx), }) } } diff --git a/crates/gpui/src/elements/empty.rs b/crates/gpui/src/elements/empty.rs index a1c805f456..98289128b5 100644 --- a/crates/gpui/src/elements/empty.rs +++ b/crates/gpui/src/elements/empty.rs @@ -6,10 +6,9 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::{json, ToJson}, - window::MeasurementContext, - DebugContext, + SceneBuilder, View, ViewContext, }; -use crate::{Element, LayoutContext, PaintContext, SizeConstraint}; +use crate::{Element, SizeConstraint}; #[derive(Default)] pub struct Empty { @@ -27,14 +26,15 @@ impl Empty { } } -impl Element for Empty { +impl Element for Empty { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - _: &mut LayoutContext, + _: &V, + _: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let x = if constraint.max.x().is_finite() && !self.collapsed { constraint.max.x() @@ -52,10 +52,11 @@ impl Element for Empty { fn paint( &mut self, + _: &mut SceneBuilder, _: RectF, _: RectF, _: &mut Self::LayoutState, - _: &mut PaintContext, + _: &mut ViewContext, ) -> Self::PaintState { } @@ -66,7 +67,8 @@ impl Element for Empty { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &V, + _: &ViewContext, ) -> Option { None } @@ -76,7 +78,8 @@ impl Element for Empty { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &DebugContext, + _: &V, + _: &ViewContext, ) -> serde_json::Value { json!({ "type": "Empty", diff --git a/crates/gpui/src/elements/expanded.rs b/crates/gpui/src/elements/expanded.rs index e7d1cea3af..186ad0300e 100644 --- a/crates/gpui/src/elements/expanded.rs +++ b/crates/gpui/src/elements/expanded.rs @@ -2,20 +2,18 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, - json, - window::MeasurementContext, - DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, + json, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext, }; use serde_json::json; -pub struct Expanded { - child: ElementBox, +pub struct Expanded { + child: ElementBox, full_width: bool, full_height: bool, } -impl Expanded { - pub fn new(child: ElementBox) -> Self { +impl Expanded { + pub fn new(child: ElementBox) -> Self { Self { child, full_width: true, @@ -36,14 +34,15 @@ impl Expanded { } } -impl Element for Expanded { +impl Element for Expanded { type LayoutState = (); type PaintState = (); fn layout( &mut self, mut constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { if self.full_width { constraint.min.set_x(constraint.max.x()); @@ -51,18 +50,21 @@ impl Element for Expanded { if self.full_height { constraint.min.set_y(constraint.max.y()); } - let size = self.child.layout(constraint, cx); + let size = self.child.layout(constraint, view, cx); (size, ()) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { - self.child.paint(bounds.origin(), visible_bounds, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); } fn rect_for_text_range( @@ -72,9 +74,10 @@ impl Element for Expanded { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn debug( @@ -82,13 +85,14 @@ impl Element for Expanded { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &DebugContext, + view: &V, + cx: &ViewContext, ) -> json::Value { json!({ "type": "Expanded", "full_width": self.full_width, "full_height": self.full_height, - "child": self.child.debug(cx) + "child": self.child.debug(view, cx) }) } } diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index ba49557a8b..fff35eb800 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -2,9 +2,8 @@ use std::{any::Any, cell::Cell, f32::INFINITY, ops::Range, rc::Rc}; use crate::{ json::{self, ToJson, Value}, - window::MeasurementContext, - Axis, DebugContext, Element, ElementBox, ElementStateHandle, LayoutContext, PaintContext, - RenderContext, SizeConstraint, Vector2FExt, View, + Axis, Element, ElementBox, ElementStateHandle, SceneBuilder, SizeConstraint, Vector2FExt, View, + ViewContext, }; use pathfinder_geometry::{ rect::RectF, @@ -18,14 +17,14 @@ struct ScrollState { scroll_position: Cell, } -pub struct Flex { +pub struct Flex { axis: Axis, - children: Vec, + children: Vec>, scroll_state: Option<(ElementStateHandle>, usize)>, child_alignment: f32, } -impl Flex { +impl Flex { pub fn new(axis: Axis) -> Self { Self { axis, @@ -52,15 +51,14 @@ impl Flex { self } - pub fn scrollable( + pub fn scrollable( mut self, element_id: usize, scroll_to: Option, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Self where Tag: 'static, - V: View, { let scroll_state = cx.default_element_state::>(element_id); scroll_state.read(cx).scroll_to.set(scroll_to); @@ -75,7 +73,8 @@ impl Flex { remaining_space: &mut f32, remaining_flex: &mut f32, cross_axis_max: &mut f32, - cx: &mut LayoutContext, + view: &V, + cx: &mut ViewContext, ) { let cross_axis = self.axis.invert(); for child in &mut self.children { @@ -112,20 +111,21 @@ impl Flex { } } -impl Extend for Flex { - fn extend>(&mut self, children: T) { +impl Extend> for Flex { + fn extend>>(&mut self, children: T) { self.children.extend(children); } } -impl Element for Flex { +impl Element for Flex { type LayoutState = f32; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let mut total_flex = None; let mut fixed_space = 0.0; @@ -150,7 +150,7 @@ impl Element for Flex { vec2f(constraint.max.x(), INFINITY), ), }; - let size = child.layout(child_constraint, cx); + let size = child.layout(child_constraint, view, cx); fixed_space += size.along(self.axis); cross_axis_max = cross_axis_max.max(size.along(cross_axis)); } @@ -168,6 +168,7 @@ impl Element for Flex { &mut remaining_space, &mut remaining_flex, &mut cross_axis_max, + view, cx, ); self.layout_flex_children( @@ -176,6 +177,7 @@ impl Element for Flex { &mut remaining_space, &mut remaining_flex, &mut cross_axis_max, + view, cx, ); @@ -247,10 +249,12 @@ impl Element for Flex { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, remaining_space: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &V, + cx: &mut ViewContext, ) -> Self::PaintState { let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); @@ -343,7 +347,7 @@ impl Element for Flex { aligned_child_origin }; - child.paint(aligned_child_origin, visible_bounds, cx); + child.paint(scene, aligned_child_origin, visible_bounds, view, cx); match self.axis { Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0), @@ -363,11 +367,12 @@ impl Element for Flex { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { self.children .iter() - .find_map(|child| child.rect_for_text_range(range_utf16.clone(), cx)) + .find_map(|child| child.rect_for_text_range(view, range_utf16.clone(), cx)) } fn debug( @@ -375,13 +380,14 @@ impl Element for Flex { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &DebugContext, + view: &V, + cx: &ViewContext, ) -> json::Value { json!({ "type": "Flex", "bounds": bounds.to_json(), "axis": self.axis.to_json(), - "children": self.children.iter().map(|child| child.debug(cx)).collect::>() + "children": self.children.iter().map(|child| child.debug(view, cx)).collect::>() }) } } @@ -391,13 +397,13 @@ struct FlexParentData { float: bool, } -pub struct FlexItem { +pub struct FlexItem { metadata: FlexParentData, - child: ElementBox, + child: ElementBox, } -impl FlexItem { - pub fn new(child: ElementBox) -> Self { +impl FlexItem { + pub fn new(child: ElementBox) -> Self { FlexItem { metadata: FlexParentData { flex: None, @@ -418,14 +424,15 @@ impl FlexItem { } } -impl Element for FlexItem { +impl Element for FlexItem { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let size = self.child.layout(constraint, cx); (size, ()) @@ -433,12 +440,15 @@ impl Element for FlexItem { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, + view: &V, cx: &mut PaintContext, ) -> Self::PaintState { - self.child.paint(bounds.origin(), visible_bounds, cx) + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx) } fn rect_for_text_range( @@ -448,9 +458,10 @@ impl Element for FlexItem { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn metadata(&self) -> Option<&dyn Any> { @@ -462,12 +473,14 @@ impl Element for FlexItem { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &DebugContext, + view: &V, + + cx: &ViewContext, ) -> Value { json!({ "type": "Flexible", "flex": self.metadata.flex, - "child": self.child.debug(cx) + "child": self.child.debug(view, cx) }) } } diff --git a/crates/gpui/src/elements/hook.rs b/crates/gpui/src/elements/hook.rs index 37b6bb03c7..eec7b3aad3 100644 --- a/crates/gpui/src/elements/hook.rs +++ b/crates/gpui/src/elements/hook.rs @@ -3,17 +3,16 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::json, - window::MeasurementContext, - DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, + Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext, }; -pub struct Hook { - child: ElementBox, - after_layout: Option>, +pub struct Hook { + child: ElementBox, + after_layout: Option)>>, } -impl Hook { - pub fn new(child: ElementBox) -> Self { +impl Hook { + pub fn new(child: ElementBox) -> Self { Self { child, after_layout: None, @@ -22,23 +21,24 @@ impl Hook { pub fn on_after_layout( mut self, - f: impl 'static + FnMut(Vector2F, &mut LayoutContext), + f: impl 'static + FnMut(Vector2F, &mut ViewContext), ) -> Self { self.after_layout = Some(Box::new(f)); self } } -impl Element for Hook { +impl Element for Hook { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { - let size = self.child.layout(constraint, cx); + let size = self.child.layout(constraint, view, cx); if let Some(handler) = self.after_layout.as_mut() { handler(size, cx); } @@ -47,12 +47,15 @@ impl Element for Hook { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) { - self.child.paint(bounds.origin(), visible_bounds, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); } fn rect_for_text_range( @@ -62,9 +65,10 @@ impl Element for Hook { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn debug( @@ -72,11 +76,12 @@ impl Element for Hook { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &DebugContext, + view: &V, + cx: &ViewContext, ) -> serde_json::Value { json!({ "type": "Hooks", - "child": self.child.debug(cx), + "child": self.child.debug(view, cx), }) } } diff --git a/crates/gpui/src/elements/image.rs b/crates/gpui/src/elements/image.rs index a94f45815c..479801a50c 100644 --- a/crates/gpui/src/elements/image.rs +++ b/crates/gpui/src/elements/image.rs @@ -5,9 +5,7 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::{json, ToJson}, - scene, - window::MeasurementContext, - Border, DebugContext, Element, ImageData, LayoutContext, PaintContext, SizeConstraint, + scene, Border, Element, ImageData, SceneBuilder, SizeConstraint, View, ViewContext, }; use serde::Deserialize; use std::{ops::Range, sync::Arc}; @@ -57,14 +55,15 @@ impl Image { } } -impl Element for Image { +impl Element for Image { type LayoutState = Option>; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let data = match &self.source { ImageSource::Path(path) => match cx.asset_cache.png(path) { @@ -91,13 +90,15 @@ impl Element for Image { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, _: RectF, layout: &mut Self::LayoutState, - cx: &mut PaintContext, + _: &V, + cx: &mut ViewContext, ) -> Self::PaintState { if let Some(data) = layout { - cx.scene.push_image(scene::Image { + scene.push_image(scene::Image { bounds, border: self.style.border, corner_radius: self.style.corner_radius, @@ -114,7 +115,8 @@ impl Element for Image { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &V, + _: &ViewContext, ) -> Option { None } @@ -124,7 +126,8 @@ impl Element for Image { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &DebugContext, + _: &V, + _: &ViewContext, ) -> serde_json::Value { json!({ "type": "Image", diff --git a/crates/gpui/src/elements/keystroke_label.rs b/crates/gpui/src/elements/keystroke_label.rs index 6553b2fa8d..5727a9f011 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, LayoutContext, PaintContext, SizeConstraint, + Action, ElementBox, SizeConstraint, }; use serde_json::json; @@ -34,15 +34,16 @@ impl KeystrokeLabel { } } -impl Element for KeystrokeLabel { - type LayoutState = ElementBox; +impl Element for KeystrokeLabel { + type LayoutState = ElementBox; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, - ) -> (Vector2F, ElementBox) { + view: &V, + cx: &mut ViewContext, + ) -> (Vector2F, ElementBox) { let mut element = if let Some(keystrokes) = cx.app .keystrokes_for_action(self.window_id, self.view_id, self.action.as_ref()) @@ -59,18 +60,20 @@ impl Element for KeystrokeLabel { Empty::new().collapsed().boxed() }; - let size = element.layout(constraint, cx); + let size = element.layout(constraint, view, cx); (size, element) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, - element: &mut ElementBox, - cx: &mut PaintContext, + element: &mut ElementBox, + view: &V, + cx: &mut ViewContext, ) { - element.paint(bounds.origin(), visible_bounds, cx); + element.paint(scene, bounds.origin(), visible_bounds, view, cx); } fn rect_for_text_range( @@ -80,7 +83,8 @@ impl Element for KeystrokeLabel { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &V, + _: &ViewContext, ) -> Option { None } @@ -88,14 +92,15 @@ impl Element for KeystrokeLabel { fn debug( &self, _: RectF, - element: &ElementBox, + element: &ElementBox, _: &(), - cx: &crate::DebugContext, + view: &V, + cx: &ViewContext, ) -> serde_json::Value { json!({ "type": "KeystrokeLabel", "action": self.action.name(), - "child": element.debug(cx) + "child": element.debug(view, cx) }) } } diff --git a/crates/gpui/src/elements/label.rs b/crates/gpui/src/elements/label.rs index 6b998a9c18..2f68967a2f 100644 --- a/crates/gpui/src/elements/label.rs +++ b/crates/gpui/src/elements/label.rs @@ -8,8 +8,7 @@ use crate::{ }, json::{ToJson, Value}, text_layout::{Line, RunStyle}, - window::MeasurementContext, - DebugContext, Element, LayoutContext, PaintContext, SizeConstraint, + Element, SceneBuilder, SizeConstraint, View, ViewContext, }; use serde::Deserialize; use serde_json::json; @@ -128,14 +127,15 @@ impl Label { } } -impl Element for Label { +impl Element for Label { type LayoutState = Line; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let runs = self.compute_runs(); let line = @@ -155,12 +155,20 @@ impl Element for Label { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, line: &mut Self::LayoutState, - cx: &mut PaintContext, + _: &V, + cx: &mut ViewContext, ) -> Self::PaintState { - line.paint(bounds.origin(), visible_bounds, bounds.size().y(), cx) + line.paint( + scene, + bounds.origin(), + visible_bounds, + bounds.size().y(), + cx, + ) } fn rect_for_text_range( @@ -170,7 +178,8 @@ impl Element for Label { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &V, + _: &ViewContext, ) -> Option { None } @@ -180,7 +189,8 @@ impl Element for Label { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &DebugContext, + _: &V, + _: &ViewContext, ) -> Value { json!({ "type": "Label", diff --git a/crates/gpui/src/elements/list.rs b/crates/gpui/src/elements/list.rs index 9326c447f0..3adaf1fbae 100644 --- a/crates/gpui/src/elements/list.rs +++ b/crates/gpui/src/elements/list.rs @@ -4,19 +4,17 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::json, - window::MeasurementContext, - DebugContext, Element, ElementBox, ElementRc, EventContext, LayoutContext, MouseRegion, - PaintContext, RenderContext, SizeConstraint, View, ViewContext, + Element, ElementBox, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext, }; use std::{cell::RefCell, collections::VecDeque, ops::Range, rc::Rc}; use sum_tree::{Bias, SumTree}; -pub struct List { - state: ListState, +pub struct List { + state: ListState, } #[derive(Clone)] -pub struct ListState(Rc>); +pub struct ListState(Rc>>); #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Orientation { @@ -24,16 +22,16 @@ pub enum Orientation { Bottom, } -struct StateInner { +struct StateInner { last_layout_width: Option, - render_item: Box Option>, + render_item: Box) -> Option>>, rendered_range: Range, - items: SumTree, + items: SumTree>, logical_scroll_top: Option, orientation: Orientation, overdraw: f32, #[allow(clippy::type_complexity)] - scroll_handler: Option, &mut EventContext)>>, + scroll_handler: Option, &mut V, &mut ViewContext)>>, } #[derive(Clone, Copy, Debug, Default, PartialEq)] @@ -43,13 +41,13 @@ pub struct ListOffset { } #[derive(Clone)] -enum ListItem { +enum ListItem { Unrendered, - Rendered(ElementRc), + Rendered(Rc>), Removed(f32), } -impl std::fmt::Debug for ListItem { +impl std::fmt::Debug for ListItem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Unrendered => write!(f, "Unrendered"), @@ -79,20 +77,21 @@ struct UnrenderedCount(usize); #[derive(Clone, Debug, Default)] struct Height(f32); -impl List { - pub fn new(state: ListState) -> Self { +impl List { + pub fn new(state: ListState) -> Self { Self { state } } } -impl Element for List { +impl Element for List { type LayoutState = ListOffset; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let state = &mut *self.state.0.borrow_mut(); let size = constraint.max; @@ -134,6 +133,7 @@ impl Element for List { scroll_top.item_ix + ix, existing_element, item_constraint, + view, cx, ) { rendered_height += element.size().y(); @@ -151,7 +151,7 @@ impl Element for List { cursor.prev(&()); if cursor.item().is_some() { if let Some(element) = - state.render_item(cursor.start().0, None, item_constraint, cx) + state.render_item(cursor.start().0, None, item_constraint, view, cx) { rendered_height += element.size().y(); rendered_items.push_front(ListItem::Rendered(element)); @@ -187,7 +187,7 @@ impl Element for List { cursor.prev(&()); if let Some(item) = cursor.item() { if let Some(element) = - state.render_item(cursor.start().0, Some(item), item_constraint, cx) + state.render_item(cursor.start().0, Some(item), item_constraint, view, cx) { leading_overdraw += element.size().y(); rendered_items.push_front(ListItem::Rendered(element)); @@ -241,10 +241,12 @@ impl Element for List { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, scroll_top: &mut ListOffset, - cx: &mut PaintContext, + view: &V, + cx: &mut ViewContext, ) { let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default(); cx.scene.push_layer(Some(visible_bounds)); @@ -268,7 +270,7 @@ impl Element for List { let state = &mut *self.state.0.borrow_mut(); for (mut element, origin) in state.visible_elements(bounds, scroll_top) { - element.paint(origin, visible_bounds, cx); + element.paint(scene, origin, visible_bounds, view, cx); } cx.scene.pop_layer(); @@ -281,7 +283,8 @@ impl Element for List { _: RectF, scroll_top: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { let state = self.state.0.borrow(); let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item); @@ -293,7 +296,7 @@ impl Element for List { } if let ListItem::Rendered(element) = item { - if let Some(rect) = element.rect_for_text_range(range_utf16.clone(), cx) { + if let Some(rect) = element.rect_for_text_range(range_utf16.clone(), view, cx) { return Some(rect); } @@ -312,12 +315,13 @@ impl Element for List { bounds: RectF, scroll_top: &Self::LayoutState, _: &(), - cx: &DebugContext, + view: &V, + cx: &ViewContext, ) -> serde_json::Value { let state = self.state.0.borrow_mut(); let visible_elements = state .visible_elements(bounds, scroll_top) - .map(|e| e.0.debug(cx)) + .map(|e| e.0.debug(view, cx)) .collect::>(); let visible_range = scroll_top.item_ix..(scroll_top.item_ix + visible_elements.len()); json!({ @@ -328,8 +332,8 @@ impl Element for List { } } -impl ListState { - pub fn new( +impl ListState { + pub fn new( element_count: usize, orientation: Orientation, overdraw: f32, @@ -338,7 +342,7 @@ impl ListState { ) -> Self where V: View, - F: 'static + FnMut(&mut V, usize, &mut RenderContext) -> ElementBox, + F: 'static + FnMut(&mut V, usize, &mut ViewContext) -> ElementBox, { let mut items = SumTree::new(); items.extend((0..element_count).map(|_| ListItem::Unrendered), &()); @@ -406,7 +410,7 @@ impl ListState { pub fn set_scroll_handler( &mut self, - handler: impl FnMut(Range, &mut EventContext) + 'static, + handler: impl FnMut(Range, &mut V, &mut ViewContext) + 'static, ) { self.0.borrow_mut().scroll_handler = Some(Box::new(handler)) } @@ -426,14 +430,15 @@ impl ListState { } } -impl StateInner { +impl StateInner { fn render_item( &mut self, ix: usize, - existing_element: Option<&ListItem>, + existing_element: Option<&ListItem>, constraint: SizeConstraint, - cx: &mut LayoutContext, - ) -> Option { + view: &mut V, + cx: &mut ViewContext, + ) -> Option>> { if let Some(ListItem::Rendered(element)) = existing_element { Some(element.clone()) } else { @@ -455,7 +460,7 @@ impl StateInner { &'a self, bounds: RectF, scroll_top: &ListOffset, - ) -> impl Iterator + 'a { + ) -> impl Iterator, Vector2F)> + 'a { let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item); let mut cursor = self.items.cursor::(); cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &()); @@ -485,7 +490,8 @@ impl StateInner { height: f32, mut delta: Vector2F, precise: bool, - cx: &mut EventContext, + view: &mut V, + cx: &mut ViewContext, ) { if !precise { delta *= 20.; @@ -538,7 +544,7 @@ impl StateInner { } } -impl ListItem { +impl ListItem { fn remove(&self) -> Self { match self { ListItem::Unrendered => ListItem::Unrendered, @@ -548,7 +554,7 @@ impl ListItem { } } -impl sum_tree::Item for ListItem { +impl sum_tree::Item for ListItem { type Summary = ListItemSummary; fn summary(&self) -> Self::Summary { @@ -900,7 +906,7 @@ mod tests { "TestView" } - fn render(&mut self, _: &mut RenderContext<'_, Self>) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } @@ -919,15 +925,28 @@ mod tests { } } - impl Element for TestElement { + impl Element for TestElement { type LayoutState = (); type PaintState = (); - fn layout(&mut self, _: SizeConstraint, _: &mut LayoutContext) -> (Vector2F, ()) { + fn layout( + &mut self, + _: SizeConstraint, + _: &mut V, + _: &mut ViewContext, + ) -> (Vector2F, ()) { (self.size, ()) } - fn paint(&mut self, _: RectF, _: RectF, _: &mut (), _: &mut PaintContext) { + fn paint( + &mut self, + _: &mut SceneBuilder, + _: RectF, + _: RectF, + _: &mut (), + _: &mut V, + _: &mut ViewContext, + ) { todo!() } @@ -938,12 +957,13 @@ mod tests { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &V, + _: &ViewContext, ) -> Option { todo!() } - fn debug(&self, _: RectF, _: &(), _: &(), _: &DebugContext) -> serde_json::Value { + fn debug(&self, _: RectF, _: &(), _: &(), _: &V, _: &ViewContext) -> serde_json::Value { self.id.into() } diff --git a/crates/gpui/src/elements/mouse_event_handler.rs b/crates/gpui/src/elements/mouse_event_handler.rs index b4cb84e920..ba8405f7f5 100644 --- a/crates/gpui/src/elements/mouse_event_handler.rs +++ b/crates/gpui/src/elements/mouse_event_handler.rs @@ -10,14 +10,13 @@ use crate::{ CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, }, - DebugContext, Element, ElementBox, EventContext, LayoutContext, MeasurementContext, - MouseRegion, MouseState, PaintContext, RenderContext, SizeConstraint, View, + Element, ElementBox, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View, ViewContext, }; use serde_json::json; use std::{marker::PhantomData, ops::Range}; -pub struct MouseEventHandler { - child: ElementBox, +pub struct MouseEventHandler { + child: ElementBox, region_id: usize, cursor_style: Option, handlers: HandlerSet, @@ -31,14 +30,14 @@ pub struct MouseEventHandler { /// Element which provides a render_child callback with a MouseState and paints a mouse /// region under (or above) it for easy mouse event handling. -impl MouseEventHandler { - pub fn new(region_id: usize, cx: &mut RenderContext, render_child: F) -> Self +impl MouseEventHandler { + pub fn new(region_id: usize, view: &mut V, cx: &mut ViewContext, render_child: F) -> Self where V: View, - F: FnOnce(&mut MouseState, &mut RenderContext) -> ElementBox, + F: FnOnce(&mut MouseState, &mut V, &mut ViewContext) -> ElementBox, { let mut mouse_state = cx.mouse_state::(region_id); - let child = render_child(&mut mouse_state, cx); + let child = render_child(&mut mouse_state, view, cx); let notify_on_hover = mouse_state.accessed_hovered(); let notify_on_click = mouse_state.accessed_clicked(); Self { @@ -58,12 +57,17 @@ impl MouseEventHandler { /// Modifies the MouseEventHandler to render the MouseRegion above the child element. Useful /// for drag and drop handling and similar events which should be captured before the child /// gets the opportunity - pub fn above(region_id: usize, cx: &mut RenderContext, render_child: F) -> Self + pub fn above( + region_id: usize, + view: &mut V, + cx: &mut ViewContext, + render_child: F, + ) -> Self where V: View, - F: FnOnce(&mut MouseState, &mut RenderContext) -> ElementBox, + F: FnOnce(&mut MouseState, &mut V, &mut ViewContext) -> ElementBox, { - let mut handler = Self::new(region_id, cx, render_child); + let mut handler = Self::new(region_id, view, cx, render_child); handler.above = true; handler } @@ -78,14 +82,14 @@ impl MouseEventHandler { self } - pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self { + pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut ViewContext) + 'static) -> Self { self.handlers = self.handlers.on_move(handler); self } pub fn on_move_out( mut self, - handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static, + handler: impl Fn(MouseMoveOut, &mut ViewContext) + 'static, ) -> Self { self.handlers = self.handlers.on_move_out(handler); self @@ -94,7 +98,7 @@ impl MouseEventHandler { pub fn on_down( mut self, button: MouseButton, - handler: impl Fn(MouseDown, &mut EventContext) + 'static, + handler: impl Fn(MouseDown, &mut ViewContext) + 'static, ) -> Self { self.handlers = self.handlers.on_down(button, handler); self @@ -103,7 +107,7 @@ impl MouseEventHandler { pub fn on_up( mut self, button: MouseButton, - handler: impl Fn(MouseUp, &mut EventContext) + 'static, + handler: impl Fn(MouseUp, &mut ViewContext) + 'static, ) -> Self { self.handlers = self.handlers.on_up(button, handler); self @@ -112,7 +116,7 @@ impl MouseEventHandler { pub fn on_click( mut self, button: MouseButton, - handler: impl Fn(MouseClick, &mut EventContext) + 'static, + handler: impl Fn(MouseClick, &mut ViewContext) + 'static, ) -> Self { self.handlers = self.handlers.on_click(button, handler); self @@ -121,7 +125,7 @@ impl MouseEventHandler { pub fn on_down_out( mut self, button: MouseButton, - handler: impl Fn(MouseDownOut, &mut EventContext) + 'static, + handler: impl Fn(MouseDownOut, &mut ViewContext) + 'static, ) -> Self { self.handlers = self.handlers.on_down_out(button, handler); self @@ -130,7 +134,7 @@ impl MouseEventHandler { pub fn on_up_out( mut self, button: MouseButton, - handler: impl Fn(MouseUpOut, &mut EventContext) + 'static, + handler: impl Fn(MouseUpOut, &mut ViewContext) + 'static, ) -> Self { self.handlers = self.handlers.on_up_out(button, handler); self @@ -139,20 +143,20 @@ impl MouseEventHandler { pub fn on_drag( mut self, button: MouseButton, - handler: impl Fn(MouseDrag, &mut EventContext) + 'static, + handler: impl Fn(MouseDrag, &mut ViewContext) + 'static, ) -> Self { self.handlers = self.handlers.on_drag(button, handler); self } - pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self { + pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut ViewContext) + 'static) -> Self { self.handlers = self.handlers.on_hover(handler); self } pub fn on_scroll( mut self, - handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static, + handler: impl Fn(MouseScrollWheel, &mut ViewContext) + 'static, ) -> Self { self.handlers = self.handlers.on_scroll(handler); self @@ -176,7 +180,13 @@ impl MouseEventHandler { .round_out() } - fn paint_regions(&self, bounds: RectF, visible_bounds: RectF, cx: &mut PaintContext) { + fn paint_regions( + &self, + scene: &mut SceneBuilder, + bounds: RectF, + visible_bounds: RectF, + cx: &mut ViewContext, + ) { let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default(); let hit_bounds = self.hit_bounds(visible_bounds); @@ -200,34 +210,37 @@ impl MouseEventHandler { } } -impl Element for MouseEventHandler { +impl Element for MouseEventHandler { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { - (self.child.layout(constraint, cx), ()) + (self.child.layout(constraint, view, cx), ()) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { if self.above { - self.child.paint(bounds.origin(), visible_bounds, cx); + self.child.paint(bounds.origin(), visible_bounds, view, cx); cx.paint_layer(None, |cx| { self.paint_regions(bounds, visible_bounds, cx); }); } else { self.paint_regions(bounds, visible_bounds, cx); - self.child.paint(bounds.origin(), visible_bounds, cx); + self.child.paint(bounds.origin(), visible_bounds, view, cx); } } @@ -238,9 +251,10 @@ impl Element for MouseEventHandler { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn debug( @@ -248,11 +262,12 @@ impl Element for MouseEventHandler { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &DebugContext, + view: &V, + cx: &ViewContext, ) -> serde_json::Value { json!({ "type": "MouseEventHandler", - "child": self.child.debug(cx), + "child": self.child.debug(view, cx), }) } } diff --git a/crates/gpui/src/elements/overlay.rs b/crates/gpui/src/elements/overlay.rs index 2c340c5c7c..0225453ecf 100644 --- a/crates/gpui/src/elements/overlay.rs +++ b/crates/gpui/src/elements/overlay.rs @@ -3,14 +3,12 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::ToJson, - window::MeasurementContext, - Axis, DebugContext, Element, ElementBox, LayoutContext, MouseRegion, PaintContext, - SizeConstraint, + Axis, Element, ElementBox, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext, }; use serde_json::json; -pub struct Overlay { - child: ElementBox, +pub struct Overlay { + child: ElementBox, anchor_position: Option, anchor_corner: AnchorCorner, fit_mode: OverlayFitMode, @@ -74,8 +72,8 @@ impl AnchorCorner { } } -impl Overlay { - pub fn new(child: ElementBox) -> Self { +impl Overlay { + pub fn new(child: ElementBox) -> Self { Self { child, anchor_position: None, @@ -118,14 +116,15 @@ impl Overlay { } } -impl Element for Overlay { +impl Element for Overlay { type LayoutState = Vector2F; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let constraint = if self.anchor_position.is_some() { SizeConstraint::new(Vector2F::zero(), cx.window_size) @@ -138,10 +137,12 @@ impl Element for Overlay { fn paint( &mut self, + scene: SceneBuilder, bounds: RectF, _: RectF, size: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) { let (anchor_position, mut bounds) = match self.position_mode { OverlayPositionMode::Window => { @@ -224,8 +225,10 @@ impl Element for Overlay { } self.child.paint( + scene, bounds.origin(), RectF::new(Vector2F::zero(), cx.window_size), + view, cx, ); }); @@ -238,9 +241,10 @@ impl Element for Overlay { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn debug( @@ -248,12 +252,13 @@ impl Element for Overlay { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &DebugContext, + view: &V, + cx: &ViewContext, ) -> serde_json::Value { json!({ "type": "Overlay", "abs_position": self.anchor_position.to_json(), - "child": self.child.debug(cx), + "child": self.child.debug(view, cx), }) } } diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index ea712994da..c83f83a419 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -1,4 +1,4 @@ -use super::{Element, EventContext, LayoutContext, PaintContext, SizeConstraint}; +use super::{Element, SizeConstraint}; use crate::{ geometry::{ rect::RectF, @@ -7,8 +7,7 @@ use crate::{ json::{self, json}, platform::ScrollWheelEvent, scene::MouseScrollWheel, - window::MeasurementContext, - ElementBox, MouseRegion, RenderContext, View, + ElementBox, MouseRegion, SceneBuilder, View, ViewContext, }; use json::ToJson; use std::{cell::RefCell, cmp, ops::Range, rc::Rc}; @@ -38,33 +37,33 @@ struct StateInner { scroll_to: Option, } -pub struct LayoutState { +pub struct LayoutState { scroll_max: f32, item_height: f32, - items: Vec, + items: Vec>, } -pub struct UniformList { +pub struct UniformList { state: UniformListState, item_count: usize, #[allow(clippy::type_complexity)] - append_items: Box, &mut Vec, &mut LayoutContext)>, + append_items: Box, &mut Vec>, &mut V, &mut ViewContext)>, padding_top: f32, padding_bottom: f32, get_width_from_item: Option, view_id: usize, } -impl UniformList { - pub fn new( +impl UniformList { + pub fn new( state: UniformListState, item_count: usize, - cx: &mut RenderContext, + cx: &mut ViewContext, append_items: F, ) -> Self where V: View, - F: 'static + Fn(&mut V, Range, &mut Vec, &mut RenderContext), + F: 'static + Fn(&mut V, Range, &mut Vec>, &mut V, &mut ViewContext), { let handle = cx.handle(); Self { @@ -160,14 +159,15 @@ impl UniformList { } } -impl Element for UniformList { - type LayoutState = LayoutState; +impl Element for UniformList { + type LayoutState = LayoutState; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { if constraint.max.y().is_infinite() { unimplemented!( @@ -262,7 +262,7 @@ impl Element for UniformList { } for item in &mut items { - let item_size = item.layout(item_constraint, cx); + let item_size = item.layout(item_constraint, view, cx); if item_size.x() > size.x() { size.set_x(item_size.x()); } @@ -280,10 +280,12 @@ impl Element for UniformList { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, layout: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default(); @@ -322,7 +324,7 @@ impl Element for UniformList { ); for item in &mut layout.items { - item.paint(item_origin, visible_bounds, cx); + item.paint(scene, item_origin, visible_bounds, view, cx); item_origin += vec2f(0.0, layout.item_height); } @@ -336,12 +338,13 @@ impl Element for UniformList { _: RectF, layout: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { layout .items .iter() - .find_map(|child| child.rect_for_text_range(range.clone(), cx)) + .find_map(|child| child.rect_for_text_range(range.clone(), view, cx)) } fn debug( @@ -349,14 +352,15 @@ impl Element for UniformList { bounds: RectF, layout: &Self::LayoutState, _: &Self::PaintState, - cx: &crate::DebugContext, + view: &V, + cx: &ViewContext, ) -> json::Value { json!({ "type": "UniformList", "bounds": bounds.to_json(), "scroll_max": layout.scroll_max, "item_height": layout.item_height, - "items": layout.items.iter().map(|item| item.debug(cx)).collect::>() + "items": layout.items.iter().map(|item| item.debug(view, cx)).collect::>() }) } diff --git a/crates/gpui/src/text_layout.rs b/crates/gpui/src/text_layout.rs index ae4cf7f0c6..44b1e81c34 100644 --- a/crates/gpui/src/text_layout.rs +++ b/crates/gpui/src/text_layout.rs @@ -7,7 +7,9 @@ use crate::{ }, platform, platform::FontSystem, - scene, PaintContext, + scene, + window::WindowContext, + AppContext, PaintContext, SceneBuilder, }; use ordered_float::OrderedFloat; use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; @@ -271,10 +273,11 @@ impl Line { pub fn paint( &self, + scene: &SceneBuilder, origin: Vector2F, visible_bounds: RectF, line_height: f32, - cx: &mut PaintContext, + cx: &mut WindowContext, ) { let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.; let baseline_offset = vec2f(0., padding_top + self.layout.ascent); diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index c7660aa336..a47b1ec76d 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -12,8 +12,8 @@ use gpui::{ actions, elements::*, platform::{CursorStyle, MouseButton}, - Action, AnyViewHandle, AppContext, ElementBox, Entity, ModelContext, ModelHandle, - RenderContext, Subscription, Task, View, ViewContext, ViewHandle, WeakModelHandle, + Action, AnyViewHandle, AppContext, Entity, ModelContext, ModelHandle, RenderContext, + Subscription, Task, View, ViewContext, ElementBox, ViewHandle, WeakModelHandle, WeakViewHandle, }; use menu::Confirm; diff --git a/crates/theme_testbench/src/theme_testbench.rs b/crates/theme_testbench/src/theme_testbench.rs index 963b06083c..9707b0a453 100644 --- a/crates/theme_testbench/src/theme_testbench.rs +++ b/crates/theme_testbench/src/theme_testbench.rs @@ -2,8 +2,8 @@ use gpui::{ actions, color::Color, elements::{ - Canvas, Container, ContainerStyle, ElementBox, Flex, Label, Margin, MouseEventHandler, - Padding, ParentElement, + Canvas, Container, ContainerStyle, Flex, Label, Margin, MouseEventHandler, Padding, + ParentElement, ElementBox, }, fonts::TextStyle, AppContext, Border, Element, Entity, ModelHandle, Quad, RenderContext, Task, View, ViewContext, diff --git a/crates/workspace/src/toolbar.rs b/crates/workspace/src/toolbar.rs index 7531ab9f92..5df64bea1f 100644 --- a/crates/workspace/src/toolbar.rs +++ b/crates/workspace/src/toolbar.rs @@ -1,7 +1,7 @@ use crate::{ItemHandle, Pane}; use gpui::{ elements::*, platform::CursorStyle, platform::MouseButton, Action, AnyViewHandle, AppContext, - ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle, WeakViewHandle, + Entity, RenderContext, View, ViewContext, ElementBox, ViewHandle, WeakViewHandle, }; use settings::Settings; From 3de8fe0f877ebcc740fe25b82ef138c0d3d66a42 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 10 Apr 2023 17:27:47 -0600 Subject: [PATCH 05/58] WIP --- crates/gpui/src/app.rs | 262 +++------ crates/gpui/src/app/test_app_context.rs | 6 +- crates/gpui/src/app/window.rs | 1 + crates/gpui/src/elements.rs | 53 +- crates/gpui/src/elements/canvas.rs | 14 +- crates/gpui/src/elements/container.rs | 2 +- crates/gpui/src/elements/flex.rs | 6 +- crates/gpui/src/elements/list.rs | 515 +++++++++--------- .../gpui/src/elements/mouse_event_handler.rs | 10 +- crates/gpui/src/elements/overlay.rs | 2 +- crates/gpui/src/elements/resizable.rs | 36 +- crates/gpui/src/elements/stack.rs | 38 +- crates/gpui/src/elements/svg.rs | 21 +- crates/gpui/src/elements/text.rs | 27 +- crates/gpui/src/elements/tooltip.rs | 104 ++-- crates/gpui/src/elements/uniform_list.rs | 2 +- crates/gpui/src/gpui.rs | 7 +- crates/gpui/src/scene/mouse_region.rs | 184 ++++--- crates/gpui/src/test.rs | 6 +- crates/gpui/src/text_layout.rs | 9 +- crates/gpui/src/views/select.rs | 64 ++- 21 files changed, 675 insertions(+), 694 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 1582130ba4..70307063e1 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -69,7 +69,7 @@ pub trait Entity: 'static { pub trait View: Entity + Sized { fn ui_name() -> &'static str; - fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox; + fn render(&mut self, cx: &mut ViewContext<'_, '_, Self>) -> ElementBox; 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 { @@ -2983,7 +2983,7 @@ where params: RenderParams, cx: &mut WindowContext<'a, 'b>, ) -> Box { - View::render(self, &mut RenderContext::new(params, cx)) + View::render(self, &mut ViewContext::new(params, cx)) } fn focus_in<'a, 'b>( @@ -3359,7 +3359,7 @@ impl<'a, 'b, T: View> DerefMut for ViewContext<'a, 'b, T> { } } -impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { +impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { fn new(window_context: &'b mut WindowContext<'a, 'b>, view_id: usize) -> Self { Self { window_context, @@ -3368,7 +3368,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { } } - pub fn handle(&self) -> ViewHandle { + pub fn handle(&self) -> ViewHandle { ViewHandle::new( self.window_id, self.view_id, @@ -3376,7 +3376,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { ) } - pub fn weak_handle(&self) -> WeakViewHandle { + pub fn weak_handle(&self) -> WeakViewHandle { WeakViewHandle::new(self.window_id, self.view_id) } @@ -3449,7 +3449,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn on_window_should_close(&mut self, mut callback: F) where - F: 'static + FnMut(&mut T, &mut ViewContext) -> bool, + F: 'static + FnMut(&mut V, &mut ViewContext) -> bool, { let window_id = self.window_id(); let view = self.weak_handle(); @@ -3511,10 +3511,10 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { ); } - pub fn replace_root_view(&mut self, build_root_view: F) -> ViewHandle + pub fn replace_root_view(&mut self, build_root_view: F) -> ViewHandle where - V: View, - F: FnOnce(&mut ViewContext) -> V, + W: View, + F: FnOnce(&mut ViewContext) -> W, { let window_id = self.window_id; self.update(|this| { @@ -3533,7 +3533,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { E: Entity, E::Event: 'static, H: Handle, - F: 'static + FnMut(&mut T, H, &E::Event, &mut ViewContext), + F: 'static + FnMut(&mut V, H, &E::Event, &mut ViewContext), { let subscriber = self.weak_handle(); self.window_context @@ -3553,7 +3553,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { where E: Entity, H: Handle, - F: 'static + FnMut(&mut T, H, &mut ViewContext), + F: 'static + FnMut(&mut V, H, &mut ViewContext), { let observer = self.weak_handle(); self.window_context @@ -3572,7 +3572,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_global(&mut self, mut callback: F) -> Subscription where G: Any, - F: 'static + FnMut(&mut T, &mut ViewContext), + F: 'static + FnMut(&mut V, &mut ViewContext), { let observer = self.weak_handle(); self.window_context.observe_global::(move |cx| { @@ -3582,10 +3582,10 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { }) } - pub fn observe_focus(&mut self, handle: &ViewHandle, mut callback: F) -> Subscription + pub fn observe_focus(&mut self, handle: &ViewHandle, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, ViewHandle, bool, &mut ViewContext), - V: View, + F: 'static + FnMut(&mut V, ViewHandle, bool, &mut ViewContext), + W: View, { let observer = self.weak_handle(); self.window_context @@ -3605,7 +3605,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { where E: Entity, H: Handle, - F: 'static + FnMut(&mut T, &E, &mut ViewContext), + F: 'static + FnMut(&mut V, &E, &mut ViewContext), { let observer = self.weak_handle(); self.window_context @@ -3620,7 +3620,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_actions(&mut self, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, TypeId, &mut ViewContext), + F: 'static + FnMut(&mut V, TypeId, &mut ViewContext), { let observer = self.weak_handle(); self.window_context.observe_actions(move |action_id, cx| { @@ -3634,7 +3634,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_window_activation(&mut self, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, bool, &mut ViewContext), + F: 'static + FnMut(&mut V, bool, &mut ViewContext), { let observer = self.weak_handle(); self.window_context @@ -3652,7 +3652,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_fullscreen(&mut self, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, bool, &mut ViewContext), + F: 'static + FnMut(&mut V, bool, &mut ViewContext), { let observer = self.weak_handle(); self.window_context @@ -3672,11 +3672,11 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { where F: 'static + FnMut( - &mut T, + &mut V, &Keystroke, Option<&Box>, &MatchResult, - &mut ViewContext, + &mut ViewContext, ) -> bool, { let observer = self.weak_handle(); @@ -3697,7 +3697,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_window_bounds(&mut self, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, WindowBounds, Uuid, &mut ViewContext), + F: 'static + FnMut(&mut V, WindowBounds, Uuid, &mut ViewContext), { let observer = self.weak_handle(); self.window_context @@ -3715,7 +3715,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn observe_active_labeled_tasks(&mut self, mut callback: F) -> Subscription where - F: 'static + FnMut(&mut T, &mut ViewContext), + F: 'static + FnMut(&mut V, &mut ViewContext), { let observer = self.weak_handle(); self.window_context.observe_active_labeled_tasks(move |cx| { @@ -3730,7 +3730,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { }) } - pub fn emit(&mut self, payload: T::Event) { + pub fn emit(&mut self, payload: V::Event) { self.window_context .pending_effects .push_back(Effect::Event { @@ -3754,7 +3754,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { .dispatch_any_action_at(self.window_id, self.view_id, action) } - pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut T, &mut ViewContext)) { + pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut V, &mut ViewContext)) { let handle = self.handle(); self.window_context.defer(move |cx| { handle.update(cx, |view, cx| { @@ -3765,7 +3765,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn after_window_update( &mut self, - callback: impl 'static + FnOnce(&mut T, &mut ViewContext), + callback: impl 'static + FnOnce(&mut V, &mut ViewContext), ) { let handle = self.handle(); self.window_context.after_window_update(move |cx| { @@ -3781,7 +3781,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn spawn_labeled(&mut self, task_label: &'static str, f: F) -> Task where - F: FnOnce(ViewHandle, AsyncAppContext) -> Fut, + F: FnOnce(ViewHandle, AsyncAppContext) -> Fut, Fut: 'static + Future, S: 'static, { @@ -3792,7 +3792,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn spawn(&mut self, f: F) -> Task where - F: FnOnce(ViewHandle, AsyncAppContext) -> Fut, + F: FnOnce(ViewHandle, AsyncAppContext) -> Fut, Fut: 'static + Future, S: 'static, { @@ -3802,79 +3802,13 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { pub fn spawn_weak(&mut self, f: F) -> Task where - F: FnOnce(WeakViewHandle, AsyncAppContext) -> Fut, + F: FnOnce(WeakViewHandle, AsyncAppContext) -> Fut, Fut: 'static + Future, S: 'static, { let handle = self.weak_handle(); self.window_context.spawn(|cx| f(handle, cx)) } -} - -pub struct RenderParams { - pub window_id: usize, - pub view_id: usize, - pub titlebar_height: f32, - pub hovered_region_ids: HashSet, - pub clicked_region_ids: Option<(HashSet, MouseButton)>, - pub refreshing: bool, - pub appearance: Appearance, -} - -#[derive(Debug, Clone, Default)] -pub struct MouseState { - pub(crate) hovered: bool, - pub(crate) clicked: Option, - pub(crate) accessed_hovered: bool, - pub(crate) accessed_clicked: bool, -} - -impl MouseState { - pub fn hovered(&mut self) -> bool { - self.accessed_hovered = true; - self.hovered - } - - pub fn clicked(&mut self) -> Option { - self.accessed_clicked = true; - self.clicked - } - - pub fn accessed_hovered(&self) -> bool { - self.accessed_hovered - } - - pub fn accessed_clicked(&self) -> bool { - self.accessed_clicked - } -} - -impl<'a, V: View> RenderContext<'a, V> { - fn new(params: RenderParams, app: &'a mut AppContext) -> Self { - Self { - app, - window_id: params.window_id, - view_id: params.view_id, - view_type: PhantomData, - titlebar_height: params.titlebar_height, - hovered_region_ids: params.hovered_region_ids.clone(), - clicked_region_ids: params.clicked_region_ids.clone(), - refreshing: params.refreshing, - appearance: params.appearance, - } - } - - pub fn handle(&self) -> WeakViewHandle { - WeakViewHandle::new(self.window_id, self.view_id) - } - - pub fn window_id(&self) -> usize { - self.window_id - } - - pub fn view_id(&self) -> usize { - self.view_id - } pub fn mouse_state(&self, region_id: usize) -> MouseState { let region_id = MouseRegionId::new::(self.view_id, region_id); @@ -3916,62 +3850,6 @@ impl<'a, V: View> RenderContext<'a, V> { } } -impl Deref for RenderContext<'_, V> { - type Target = AppContext; - - fn deref(&self) -> &Self::Target { - self.app - } -} - -impl DerefMut for RenderContext<'_, V> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.app - } -} - -impl ReadModel for RenderContext<'_, V> { - fn read_model(&self, handle: &ModelHandle) -> &T { - self.app.read_model(handle) - } -} - -impl UpdateModel for RenderContext<'_, V> { - fn update_model( - &mut self, - handle: &ModelHandle, - update: &mut dyn FnMut(&mut T, &mut ModelContext) -> O, - ) -> O { - self.app.update_model(handle, update) - } -} - -impl ReadView for RenderContext<'_, V> { - fn read_view(&self, handle: &ViewHandle) -> &T { - self.app.read_view(handle) - } -} - -impl<'a, 'b, M> Deref for ViewContext<'a, 'b, M> { - type Target = WindowContext<'a, 'b>; - - fn deref(&self) -> &Self::Target { - &self.window_context - } -} - -impl DerefMut for ViewContext<'_, '_, M> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.window_context - } -} - -impl ReadModel for ViewContext<'_, '_, V> { - fn read_model(&self, handle: &ModelHandle) -> &T { - self.window_context.read_model(handle) - } -} - impl UpgradeModelHandle for ViewContext<'_, '_, V> { fn upgrade_model_handle( &self, @@ -3999,16 +3877,6 @@ impl UpgradeViewHandle for ViewContext<'_, '_, V> { } } -impl UpgradeViewHandle for RenderContext<'_, V> { - fn upgrade_view_handle(&self, handle: &WeakViewHandle) -> Option> { - self.app.upgrade_view_handle(handle) - } - - fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option { - self.app.upgrade_any_view_handle(handle) - } -} - impl UpdateModel for ViewContext<'_, '_, V> { fn update_model( &mut self, @@ -4038,6 +3906,44 @@ impl UpdateView for ViewContext<'_, '_, V> { } } +pub struct RenderParams { + pub window_id: usize, + pub view_id: usize, + pub titlebar_height: f32, + pub hovered_region_ids: HashSet, + pub clicked_region_ids: Option<(HashSet, MouseButton)>, + pub refreshing: bool, + pub appearance: Appearance, +} + +#[derive(Debug, Clone, Default)] +pub struct MouseState { + pub(crate) hovered: bool, + pub(crate) clicked: Option, + pub(crate) accessed_hovered: bool, + pub(crate) accessed_clicked: bool, +} + +impl MouseState { + pub fn hovered(&mut self) -> bool { + self.accessed_hovered = true; + self.hovered + } + + pub fn clicked(&mut self) -> Option { + self.accessed_clicked = true; + self.clicked + } + + pub fn accessed_hovered(&self) -> bool { + self.accessed_hovered + } + + pub fn accessed_clicked(&self) -> bool { + self.accessed_clicked + } +} + pub trait Handle { type Weak: 'static; fn id(&self) -> usize; @@ -5078,7 +4984,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { post_inc(&mut self.render_count); Empty::new().boxed() } @@ -5131,7 +5037,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -5195,7 +5101,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { enum Handler {} let mouse_down_count = self.mouse_down_count.clone(); MouseEventHandler::::new(0, cx, |_, _| Empty::new().boxed()) @@ -5261,7 +5167,7 @@ mod tests { "View" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } @@ -5779,7 +5685,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -5844,7 +5750,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -6020,7 +5926,7 @@ mod tests { } impl View for ViewA { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -6038,7 +5944,7 @@ mod tests { } impl View for ViewB { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -6190,7 +6096,7 @@ mod tests { } impl super::View for View { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } @@ -6317,7 +6223,7 @@ mod tests { } impl super::View for View1 { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } fn ui_name() -> &'static str { @@ -6325,7 +6231,7 @@ mod tests { } } impl super::View for View2 { - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } fn ui_name() -> &'static str { @@ -6500,7 +6406,7 @@ mod tests { "test view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } @@ -6562,7 +6468,7 @@ mod tests { "test view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().named(format!("render count: {}", post_inc(&mut self.0))) } } @@ -6651,7 +6557,7 @@ mod tests { "test view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } @@ -6731,7 +6637,7 @@ mod tests { "child view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { self.rendered.set(true); Empty::new().boxed() } @@ -6756,7 +6662,7 @@ mod tests { "parent view" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if let Some(child) = self.child.as_ref() { ChildView::new(child, cx).boxed() } else { @@ -6798,7 +6704,7 @@ mod tests { "TestView" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index 560ba66a77..7816b42ac9 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -74,7 +74,7 @@ impl TestAppContext { pub fn dispatch_action(&self, window_id: usize, action: A) { let mut cx = self.cx.borrow_mut(); - if let Some(view_id) = cx.focused_view_id(window_id) { + if let Some(view_id) = cx.focused_view_id { cx.handle_dispatch_action_from_effect(window_id, Some(view_id), &action); } } @@ -169,11 +169,11 @@ impl TestAppContext { pub fn render(&mut self, handle: &ViewHandle, f: F) -> T where - F: FnOnce(&mut V, &mut RenderContext) -> T, + F: FnOnce(&mut V, &mut ViewContext) -> T, V: View, { handle.update(&mut *self.cx.borrow_mut(), |view, cx| { - let mut render_cx = RenderContext { + let mut render_cx = ViewContext { app: cx, window_id: handle.window_id(), view_id: handle.id(), diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 7a167a3c0d..b7a9a0636a 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -87,6 +87,7 @@ pub struct WindowContext<'a: 'b, 'b> { app_context: &'a mut AppContext, pub(crate) window: &'b mut Window, // TODO: make this private? pub(crate) window_id: usize, + pub refreshing: bool, } impl Deref for WindowContext<'_, '_> { diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index e5125e11a8..d23134acaf 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -27,12 +27,11 @@ pub use self::{ }; use self::{clipped::Clipped, expanded::Expanded}; use crate::{ - app::window::MeasurementContext, geometry::{ rect::RectF, vector::{vec2f, Vector2F}, }, - json, Action, RenderContext, SceneBuilder, SizeConstraint, View, ViewContext, + json, Action, SceneBuilder, SizeConstraint, View, ViewContext, }; use core::panic; use json::ToJson; @@ -62,7 +61,7 @@ trait AnyElement { cx: &ViewContext, ) -> Option; - fn debug(&self, view: &V, cx: &mut ViewContext) -> serde_json::Value; + fn debug(&self, view: &V, cx: &ViewContext) -> serde_json::Value; fn size(&self) -> Vector2F; @@ -82,6 +81,7 @@ pub trait Element { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, layout: &mut Self::LayoutState, @@ -133,81 +133,81 @@ pub trait Element { } } - fn constrained(self) -> ConstrainedBox + fn constrained(self) -> ConstrainedBox where Self: 'static + Sized, { ConstrainedBox::new(self.boxed()) } - fn aligned(self) -> Align + fn aligned(self) -> Align where Self: 'static + Sized, { Align::new(self.boxed()) } - fn clipped(self) -> Clipped + fn clipped(self) -> Clipped where Self: 'static + Sized, { Clipped::new(self.boxed()) } - fn contained(self) -> Container + fn contained(self) -> Container where Self: 'static + Sized, { Container::new(self.boxed()) } - fn expanded(self) -> Expanded + fn expanded(self) -> Expanded where Self: 'static + Sized, { Expanded::new(self.boxed()) } - fn flex(self, flex: f32, expanded: bool) -> FlexItem + fn flex(self, flex: f32, expanded: bool) -> FlexItem where Self: 'static + Sized, { FlexItem::new(self.boxed()).flex(flex, expanded) } - fn flex_float(self) -> FlexItem + fn flex_float(self) -> FlexItem where Self: 'static + Sized, { FlexItem::new(self.boxed()).float() } - fn with_tooltip( + fn with_tooltip( self, id: usize, text: String, action: Option>, style: TooltipStyle, - cx: &mut RenderContext, - ) -> Tooltip + cx: &mut ViewContext, + ) -> Tooltip where Self: 'static + Sized, { - Tooltip::new::(id, text, action, style, self.boxed(), cx) + Tooltip::new::(id, text, action, style, self.boxed(), cx) } - fn with_resize_handle( + fn with_resize_handle( self, element_id: usize, side: Side, handle_size: f32, initial_size: f32, - cx: &mut RenderContext, - ) -> Resizable + cx: &mut ViewContext, + ) -> Resizable where Self: 'static + Sized, { - Resizable::new::( + Resizable::new::( self.boxed(), element_id, side, @@ -270,6 +270,7 @@ impl> AnyElement for Lifecycle { fn paint( &mut self, + scene: &mut SceneBuilder, view: &mut V, origin: Vector2F, visible_bounds: RectF, @@ -283,7 +284,7 @@ impl> AnyElement for Lifecycle { mut layout, } => { let bounds = RectF::new(origin, size); - let paint = element.paint(view, bounds, visible_bounds, &mut layout, cx); + let paint = element.paint(scene, bounds, visible_bounds, &mut layout, view, cx); Lifecycle::PostPaint { element, constraint, @@ -301,7 +302,7 @@ impl> AnyElement for Lifecycle { .. } => { let bounds = RectF::new(origin, bounds.size()); - let paint = element.paint(view, bounds, visible_bounds, &mut layout, cx); + let paint = element.paint(scene, bounds, visible_bounds, &mut layout, view, cx); Lifecycle::PostPaint { element, constraint, @@ -334,12 +335,12 @@ impl> AnyElement for Lifecycle { } = self { element.rect_for_text_range( - view, range_utf16, *bounds, *visible_bounds, layout, paint, + view, cx, ) } else { @@ -374,7 +375,7 @@ impl> AnyElement for Lifecycle { layout, paint, } => { - let mut value = element.debug(view, *bounds, layout, paint, cx); + let mut value = element.debug(*bounds, layout, paint, view, cx); if let json::Value::Object(map) = &mut value { let mut new_map: crate::json::Map = Default::default(); @@ -403,7 +404,7 @@ impl> Default for Lifecycle { } pub struct ElementBox { - element: RefCell>, + element: Box>>, view_type: PhantomData, name: Option>, } @@ -420,8 +421,8 @@ impl ElementBox { pub fn layout( &self, - view: &mut V, constraint: SizeConstraint, + view: &mut V, cx: &mut ViewContext, ) -> Vector2F { self.element.borrow_mut().layout(view, constraint, cx) @@ -429,10 +430,10 @@ impl ElementBox { pub fn paint( &self, - view: &mut V, scene: &mut SceneBuilder, origin: Vector2F, visible_bounds: RectF, + view: &mut V, cx: &mut ViewContext, ) { self.element @@ -442,8 +443,8 @@ impl ElementBox { pub fn rect_for_text_range( &self, - view: &V, range_utf16: Range, + view: &V, cx: &ViewContext, ) -> Option { self.element diff --git a/crates/gpui/src/elements/canvas.rs b/crates/gpui/src/elements/canvas.rs index 10d222c506..fb842f92f7 100644 --- a/crates/gpui/src/elements/canvas.rs +++ b/crates/gpui/src/elements/canvas.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use super::Element; use crate::{ json::{self, json}, @@ -9,18 +11,19 @@ use pathfinder_geometry::{ vector::{vec2f, Vector2F}, }; -pub struct Canvas(F); +pub struct Canvas(F, PhantomData); -impl Canvas +impl Canvas where + V: View, F: FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext), { pub fn new(f: F) -> Self { - Self(f) + Self(f, PhantomData) } } -impl Element for Canvas +impl Element for Canvas where F: FnMut(RectF, RectF, &mut ViewContext), { @@ -30,7 +33,8 @@ where fn layout( &mut self, constraint: crate::SizeConstraint, - _: &mut crate::LayoutContext, + _: &mut V, + _: &mut crate::ViewContext, ) -> (Vector2F, Self::LayoutState) { let x = if constraint.max.x().is_finite() { constraint.max.x() diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index 531f893c4f..5631c01bc0 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -308,7 +308,7 @@ impl Element for Container { _: &Self::LayoutState, _: &Self::PaintState, view: &V, - cx: &crate::DebugContext, + cx: &ViewContext, ) -> serde_json::Value { json!({ "type": "Container", diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index fff35eb800..31e3f25308 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -101,7 +101,7 @@ impl Flex { vec2f(constraint.max.x(), child_max), ), }; - let child_size = child.layout(child_constraint, cx); + let child_size = child.layout(child_constraint, view, cx); *remaining_space -= child_size.along(self.axis); *remaining_flex -= flex; *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis)); @@ -434,7 +434,7 @@ impl Element for FlexItem { view: &V, cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { - let size = self.child.layout(constraint, cx); + let size = self.child.layout(constraint, view, cx); (size, ()) } @@ -445,7 +445,7 @@ impl Element for FlexItem { visible_bounds: RectF, _: &mut Self::LayoutState, view: &V, - cx: &mut PaintContext, + cx: &mut ViewContext, ) -> Self::PaintState { self.child .paint(scene, bounds.origin(), visible_bounds, view, cx) diff --git a/crates/gpui/src/elements/list.rs b/crates/gpui/src/elements/list.rs index 3adaf1fbae..ef9a202f1a 100644 --- a/crates/gpui/src/elements/list.rs +++ b/crates/gpui/src/elements/list.rs @@ -6,7 +6,7 @@ use crate::{ json::json, Element, ElementBox, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext, }; -use std::{cell::RefCell, collections::VecDeque, ops::Range, rc::Rc}; +use std::{cell::RefCell, collections::VecDeque, fmt::Debug, ops::Range, rc::Rc}; use sum_tree::{Bias, SumTree}; pub struct List { @@ -24,7 +24,7 @@ pub enum Orientation { struct StateInner { last_layout_width: Option, - render_item: Box) -> Option>>, + render_item: Box) -> ElementBox>, rendered_range: Range, items: SumTree>, logical_scroll_top: Option, @@ -40,14 +40,23 @@ pub struct ListOffset { pub offset_in_item: f32, } -#[derive(Clone)] enum ListItem { Unrendered, Rendered(Rc>), Removed(f32), } -impl std::fmt::Debug for ListItem { +impl Clone for ListItem { + fn clone(&self) -> Self { + match self { + Self::Unrendered => Self::Unrendered, + Self::Rendered(element) => Self::Rendered(element.clone()), + Self::Removed(height) => Self::Removed(*height), + } + } +} + +impl Debug for ListItem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Unrendered => write!(f, "Unrendered"), @@ -245,14 +254,13 @@ impl Element for List { bounds: RectF, visible_bounds: RectF, scroll_top: &mut ListOffset, - view: &V, + view: &mut V, cx: &mut ViewContext, ) { let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default(); - cx.scene.push_layer(Some(visible_bounds)); - - cx.scene.push_mouse_region( - MouseRegion::new::(cx.current_view_id(), 0, bounds).on_scroll({ + scene.push_layer(Some(visible_bounds)); + scene.push_mouse_region( + MouseRegion::new::(cx.view_id(), 0, bounds).on_scroll({ let state = self.state.clone(); let height = bounds.height(); let scroll_top = scroll_top.clone(); @@ -273,7 +281,7 @@ impl Element for List { element.paint(scene, origin, visible_bounds, view, cx); } - cx.scene.pop_layer(); + scene.pop_layer(); } fn rect_for_text_range( @@ -349,9 +357,10 @@ impl ListState { let handle = cx.weak_handle(); Self(Rc::new(RefCell::new(StateInner { last_layout_width: None, - render_item: Box::new(move |ix, cx| { - let handle = handle.upgrade(cx)?; - Some(cx.render(&handle, |view, cx| render_item(view, ix, cx))) + render_item: Box::new(move |ix, view, cx| { + render_item(view, ix, cx) + // let handle = handle.upgrade(cx)?; + // Some(cx.render(&handle, |view, cx| render_item(view, ix, cx))) }), rendered_range: 0..0, items, @@ -442,8 +451,8 @@ impl StateInner { if let Some(ListItem::Rendered(element)) = existing_element { Some(element.clone()) } else { - let mut element = (self.render_item)(ix, cx)?; - element.layout(constraint, cx); + let mut element = (self.render_item)(view, ix, cx); + element.layout(constraint, view, cx); Some(element.into()) } } @@ -460,7 +469,7 @@ impl StateInner { &'a self, bounds: RectF, scroll_top: &ListOffset, - ) -> impl Iterator, Vector2F)> + 'a { + ) -> impl Iterator>, Vector2F)> + 'a { let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item); let mut cursor = self.items.cursor::(); cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &()); @@ -637,262 +646,264 @@ mod tests { #[crate::test(self)] fn test_layout(cx: &mut crate::AppContext) { - let (_, view) = cx.add_window(Default::default(), |_| TestView); - let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.)); + todo!() + // let (_, view) = cx.add_window(Default::default(), |_| TestView); + // let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.)); - let elements = Rc::new(RefCell::new(vec![(0, 20.), (1, 30.), (2, 100.)])); + // let elements = Rc::new(RefCell::new(vec![(0, 20.), (1, 30.), (2, 100.)])); - let state = view.update(cx, |_, cx| { - ListState::new(elements.borrow().len(), Orientation::Top, 1000.0, cx, { - let elements = elements.clone(); - move |_, ix, _| { - let (id, height) = elements.borrow()[ix]; - TestElement::new(id, height).boxed() - } - }) - }); + // let state = view.update(cx, |_, cx| { + // ListState::new(elements.borrow().len(), Orientation::Top, 1000.0, cx, { + // let elements = elements.clone(); + // move |_, ix, _| { + // let (id, height) = elements.borrow()[ix]; + // TestElement::new(id, height).boxed() + // } + // }) + // }); - let mut list = List::new(state.clone()); - let (size, _) = list.layout( - constraint, - &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), - ); - assert_eq!(size, vec2f(100., 40.)); - assert_eq!( - state.0.borrow().items.summary().clone(), - ListItemSummary { - count: 3, - rendered_count: 3, - unrendered_count: 0, - height: 150. - } - ); + // let mut list = List::new(state.clone()); + // let (size, _) = list.layout( + // constraint, + // &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), + // ); + // assert_eq!(size, vec2f(100., 40.)); + // assert_eq!( + // state.0.borrow().items.summary().clone(), + // ListItemSummary { + // count: 3, + // rendered_count: 3, + // unrendered_count: 0, + // height: 150. + // } + // ); - state.0.borrow_mut().scroll( - &ListOffset { - item_ix: 0, - offset_in_item: 0., - }, - 40., - vec2f(0., -54.), - true, - &mut presenter.build_event_context(&mut Default::default(), cx), - ); - let (_, logical_scroll_top) = list.layout( - constraint, - &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), - ); - assert_eq!( - logical_scroll_top, - ListOffset { - item_ix: 2, - offset_in_item: 4. - } - ); - assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 54.); + // state.0.borrow_mut().scroll( + // &ListOffset { + // item_ix: 0, + // offset_in_item: 0., + // }, + // 40., + // vec2f(0., -54.), + // true, + // &mut presenter.build_event_context(&mut Default::default(), cx), + // ); + // let (_, logical_scroll_top) = list.layout( + // constraint, + // &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), + // ); + // assert_eq!( + // logical_scroll_top, + // ListOffset { + // item_ix: 2, + // offset_in_item: 4. + // } + // ); + // assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 54.); - elements.borrow_mut().splice(1..2, vec![(3, 40.), (4, 50.)]); - elements.borrow_mut().push((5, 60.)); - state.splice(1..2, 2); - state.splice(4..4, 1); - assert_eq!( - state.0.borrow().items.summary().clone(), - ListItemSummary { - count: 5, - rendered_count: 2, - unrendered_count: 3, - height: 120. - } - ); + // elements.borrow_mut().splice(1..2, vec![(3, 40.), (4, 50.)]); + // elements.borrow_mut().push((5, 60.)); + // state.splice(1..2, 2); + // state.splice(4..4, 1); + // assert_eq!( + // state.0.borrow().items.summary().clone(), + // ListItemSummary { + // count: 5, + // rendered_count: 2, + // unrendered_count: 3, + // height: 120. + // } + // ); - let (size, logical_scroll_top) = list.layout( - constraint, - &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), - ); - assert_eq!(size, vec2f(100., 40.)); - assert_eq!( - state.0.borrow().items.summary().clone(), - ListItemSummary { - count: 5, - rendered_count: 5, - unrendered_count: 0, - height: 270. - } - ); - assert_eq!( - logical_scroll_top, - ListOffset { - item_ix: 3, - offset_in_item: 4. - } - ); - assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 114.); + // let (size, logical_scroll_top) = list.layout( + // constraint, + // &mut presenter.build_layout_context(vec2f(100., 40.), false, cx), + // ); + // assert_eq!(size, vec2f(100., 40.)); + // assert_eq!( + // state.0.borrow().items.summary().clone(), + // ListItemSummary { + // count: 5, + // rendered_count: 5, + // unrendered_count: 0, + // height: 270. + // } + // ); + // assert_eq!( + // logical_scroll_top, + // ListOffset { + // item_ix: 3, + // offset_in_item: 4. + // } + // ); + // assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 114.); } #[crate::test(self, iterations = 10, seed = 0)] fn test_random(cx: &mut crate::AppContext, mut rng: StdRng) { - let operations = env::var("OPERATIONS") - .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) - .unwrap_or(10); + todo!() + // let operations = env::var("OPERATIONS") + // .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) + // .unwrap_or(10); - let (window_id, view) = cx.add_window(Default::default(), |_| TestView); - let mut next_id = 0; - let elements = Rc::new(RefCell::new( - (0..rng.gen_range(0..=20)) - .map(|_| { - let id = next_id; - next_id += 1; - (id, rng.gen_range(0..=200) as f32 / 2.0) - }) - .collect::>(), - )); - let orientation = *[Orientation::Top, Orientation::Bottom] - .choose(&mut rng) - .unwrap(); - let overdraw = rng.gen_range(1..=100) as f32; + // let (window_id, view) = cx.add_window(Default::default(), |_| TestView); + // let mut next_id = 0; + // let elements = Rc::new(RefCell::new( + // (0..rng.gen_range(0..=20)) + // .map(|_| { + // let id = next_id; + // next_id += 1; + // (id, rng.gen_range(0..=200) as f32 / 2.0) + // }) + // .collect::>(), + // )); + // let orientation = *[Orientation::Top, Orientation::Bottom] + // .choose(&mut rng) + // .unwrap(); + // let overdraw = rng.gen_range(1..=100) as f32; - let state = view.update(cx, |_, cx| { - ListState::new(elements.borrow().len(), orientation, overdraw, cx, { - let elements = elements.clone(); - move |_, ix, _| { - let (id, height) = elements.borrow()[ix]; - TestElement::new(id, height).boxed() - } - }) - }); + // let state = view.update(cx, |_, cx| { + // ListState::new(elements.borrow().len(), orientation, overdraw, cx, { + // let elements = elements.clone(); + // move |_, ix, _| { + // let (id, height) = elements.borrow()[ix]; + // TestElement::new(id, height).boxed() + // } + // }) + // }); - let mut width = rng.gen_range(0..=2000) as f32 / 2.; - let mut height = rng.gen_range(0..=2000) as f32 / 2.; - log::info!("orientation: {:?}", orientation); - log::info!("overdraw: {}", overdraw); - log::info!("elements: {:?}", elements.borrow()); - log::info!("size: ({:?}, {:?})", width, height); - log::info!("=================="); + // let mut width = rng.gen_range(0..=2000) as f32 / 2.; + // let mut height = rng.gen_range(0..=2000) as f32 / 2.; + // log::info!("orientation: {:?}", orientation); + // log::info!("overdraw: {}", overdraw); + // log::info!("elements: {:?}", elements.borrow()); + // log::info!("size: ({:?}, {:?})", width, height); + // log::info!("=================="); - let mut last_logical_scroll_top = None; - for _ in 0..operations { - match rng.gen_range(0..=100) { - 0..=29 if last_logical_scroll_top.is_some() => { - let delta = vec2f(0., rng.gen_range(-overdraw..=overdraw)); - log::info!( - "Scrolling by {:?}, previous scroll top: {:?}", - delta, - last_logical_scroll_top.unwrap() - ); - state.0.borrow_mut().scroll( - last_logical_scroll_top.as_ref().unwrap(), - height, - delta, - true, - &mut presenter.build_event_context(&mut Default::default(), cx), - ); - } - 30..=34 => { - width = rng.gen_range(0..=2000) as f32 / 2.; - log::info!("changing width: {:?}", width); - } - 35..=54 => { - height = rng.gen_range(0..=1000) as f32 / 2.; - log::info!("changing height: {:?}", height); - } - _ => { - let mut elements = elements.borrow_mut(); - let end_ix = rng.gen_range(0..=elements.len()); - let start_ix = rng.gen_range(0..=end_ix); - let new_elements = (0..rng.gen_range(0..10)) - .map(|_| { - let id = next_id; - next_id += 1; - (id, rng.gen_range(0..=200) as f32 / 2.) - }) - .collect::>(); - log::info!("splice({:?}, {:?})", start_ix..end_ix, new_elements); - state.splice(start_ix..end_ix, new_elements.len()); - elements.splice(start_ix..end_ix, new_elements); - for (ix, item) in state.0.borrow().items.cursor::<()>().enumerate() { - if let ListItem::Rendered(element) = item { - let (expected_id, _) = elements[ix]; - element.with_metadata(|metadata: Option<&usize>| { - assert_eq!(*metadata.unwrap(), expected_id); - }); - } - } - } - } + // let mut last_logical_scroll_top = None; + // for _ in 0..operations { + // match rng.gen_range(0..=100) { + // 0..=29 if last_logical_scroll_top.is_some() => { + // let delta = vec2f(0., rng.gen_range(-overdraw..=overdraw)); + // log::info!( + // "Scrolling by {:?}, previous scroll top: {:?}", + // delta, + // last_logical_scroll_top.unwrap() + // ); + // state.0.borrow_mut().scroll( + // last_logical_scroll_top.as_ref().unwrap(), + // height, + // delta, + // true, + // &mut presenter.build_event_context(&mut Default::default(), cx), + // ); + // } + // 30..=34 => { + // width = rng.gen_range(0..=2000) as f32 / 2.; + // log::info!("changing width: {:?}", width); + // } + // 35..=54 => { + // height = rng.gen_range(0..=1000) as f32 / 2.; + // log::info!("changing height: {:?}", height); + // } + // _ => { + // let mut elements = elements.borrow_mut(); + // let end_ix = rng.gen_range(0..=elements.len()); + // let start_ix = rng.gen_range(0..=end_ix); + // let new_elements = (0..rng.gen_range(0..10)) + // .map(|_| { + // let id = next_id; + // next_id += 1; + // (id, rng.gen_range(0..=200) as f32 / 2.) + // }) + // .collect::>(); + // log::info!("splice({:?}, {:?})", start_ix..end_ix, new_elements); + // state.splice(start_ix..end_ix, new_elements.len()); + // elements.splice(start_ix..end_ix, new_elements); + // for (ix, item) in state.0.borrow().items.cursor::<()>().enumerate() { + // if let ListItem::Rendered(element) = item { + // let (expected_id, _) = elements[ix]; + // element.with_metadata(|metadata: Option<&usize>| { + // assert_eq!(*metadata.unwrap(), expected_id); + // }); + // } + // } + // } + // } - let mut list = List::new(state.clone()); - let window_size = vec2f(width, height); - let (size, logical_scroll_top) = list.layout( - SizeConstraint::new(vec2f(0., 0.), window_size), - &mut presenter.build_layout_context(window_size, false, cx), - ); - assert_eq!(size, window_size); - last_logical_scroll_top = Some(logical_scroll_top); + // let mut list = List::new(state.clone()); + // let window_size = vec2f(width, height); + // let (size, logical_scroll_top) = list.layout( + // SizeConstraint::new(vec2f(0., 0.), window_size), + // &mut presenter.build_layout_context(window_size, false, cx), + // ); + // assert_eq!(size, window_size); + // last_logical_scroll_top = Some(logical_scroll_top); - let state = state.0.borrow(); - log::info!("items {:?}", state.items.items(&())); + // let state = state.0.borrow(); + // log::info!("items {:?}", state.items.items(&())); - let scroll_top = state.scroll_top(&logical_scroll_top); - let rendered_top = (scroll_top - overdraw).max(0.); - let rendered_bottom = scroll_top + height + overdraw; - let mut item_top = 0.; + // let scroll_top = state.scroll_top(&logical_scroll_top); + // let rendered_top = (scroll_top - overdraw).max(0.); + // let rendered_bottom = scroll_top + height + overdraw; + // let mut item_top = 0.; - log::info!( - "rendered top {:?}, rendered bottom {:?}, scroll top {:?}", - rendered_top, - rendered_bottom, - scroll_top, - ); + // log::info!( + // "rendered top {:?}, rendered bottom {:?}, scroll top {:?}", + // rendered_top, + // rendered_bottom, + // scroll_top, + // ); - let mut first_rendered_element_top = None; - let mut last_rendered_element_bottom = None; - assert_eq!(state.items.summary().count, elements.borrow().len()); - for (ix, item) in state.items.cursor::<()>().enumerate() { - match item { - ListItem::Unrendered => { - let item_bottom = item_top; - assert!(item_bottom <= rendered_top || item_top >= rendered_bottom); - item_top = item_bottom; - } - ListItem::Removed(height) => { - let (id, expected_height) = elements.borrow()[ix]; - assert_eq!( - *height, expected_height, - "element {} height didn't match", - id - ); - let item_bottom = item_top + height; - assert!(item_bottom <= rendered_top || item_top >= rendered_bottom); - item_top = item_bottom; - } - ListItem::Rendered(element) => { - let (expected_id, expected_height) = elements.borrow()[ix]; - element.with_metadata(|metadata: Option<&usize>| { - assert_eq!(*metadata.unwrap(), expected_id); - }); - assert_eq!(element.size().y(), expected_height); - let item_bottom = item_top + element.size().y(); - first_rendered_element_top.get_or_insert(item_top); - last_rendered_element_bottom = Some(item_bottom); - assert!(item_bottom > rendered_top || item_top < rendered_bottom); - item_top = item_bottom; - } - } - } + // let mut first_rendered_element_top = None; + // let mut last_rendered_element_bottom = None; + // assert_eq!(state.items.summary().count, elements.borrow().len()); + // for (ix, item) in state.items.cursor::<()>().enumerate() { + // match item { + // ListItem::Unrendered => { + // let item_bottom = item_top; + // assert!(item_bottom <= rendered_top || item_top >= rendered_bottom); + // item_top = item_bottom; + // } + // ListItem::Removed(height) => { + // let (id, expected_height) = elements.borrow()[ix]; + // assert_eq!( + // *height, expected_height, + // "element {} height didn't match", + // id + // ); + // let item_bottom = item_top + height; + // assert!(item_bottom <= rendered_top || item_top >= rendered_bottom); + // item_top = item_bottom; + // } + // ListItem::Rendered(element) => { + // let (expected_id, expected_height) = elements.borrow()[ix]; + // element.with_metadata(|metadata: Option<&usize>| { + // assert_eq!(*metadata.unwrap(), expected_id); + // }); + // assert_eq!(element.size().y(), expected_height); + // let item_bottom = item_top + element.size().y(); + // first_rendered_element_top.get_or_insert(item_top); + // last_rendered_element_bottom = Some(item_bottom); + // assert!(item_bottom > rendered_top || item_top < rendered_bottom); + // item_top = item_bottom; + // } + // } + // } - match orientation { - Orientation::Top => { - if let Some(first_rendered_element_top) = first_rendered_element_top { - assert!(first_rendered_element_top <= scroll_top); - } - } - Orientation::Bottom => { - if let Some(last_rendered_element_bottom) = last_rendered_element_bottom { - assert!(last_rendered_element_bottom >= scroll_top + height); - } - } - } - } + // match orientation { + // Orientation::Top => { + // if let Some(first_rendered_element_top) = first_rendered_element_top { + // assert!(first_rendered_element_top <= scroll_top); + // } + // } + // Orientation::Bottom => { + // if let Some(last_rendered_element_bottom) = last_rendered_element_bottom { + // assert!(last_rendered_element_bottom >= scroll_top + height); + // } + // } + // } + // } } struct TestView; diff --git a/crates/gpui/src/elements/mouse_event_handler.rs b/crates/gpui/src/elements/mouse_event_handler.rs index ba8405f7f5..93515bbc43 100644 --- a/crates/gpui/src/elements/mouse_event_handler.rs +++ b/crates/gpui/src/elements/mouse_event_handler.rs @@ -233,14 +233,16 @@ impl Element for MouseEventHandler { cx: &mut ViewContext, ) -> Self::PaintState { if self.above { - self.child.paint(bounds.origin(), visible_bounds, view, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); cx.paint_layer(None, |cx| { - self.paint_regions(bounds, visible_bounds, cx); + self.paint_regions(scene, bounds, visible_bounds, cx); }); } else { - self.paint_regions(bounds, visible_bounds, cx); - self.child.paint(bounds.origin(), visible_bounds, view, cx); + self.paint_regions(scene, bounds, visible_bounds, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); } } diff --git a/crates/gpui/src/elements/overlay.rs b/crates/gpui/src/elements/overlay.rs index 0225453ecf..a95667934b 100644 --- a/crates/gpui/src/elements/overlay.rs +++ b/crates/gpui/src/elements/overlay.rs @@ -131,7 +131,7 @@ impl Element for Overlay { } else { constraint }; - let size = self.child.layout(constraint, cx); + let size = self.child.layout(constraint, view, cx); (Vector2F::zero(), size) } diff --git a/crates/gpui/src/elements/resizable.rs b/crates/gpui/src/elements/resizable.rs index d378491f85..33f885bf9b 100644 --- a/crates/gpui/src/elements/resizable.rs +++ b/crates/gpui/src/elements/resizable.rs @@ -7,7 +7,7 @@ use crate::{ geometry::rect::RectF, platform::{CursorStyle, MouseButton}, scene::MouseDrag, - Axis, Element, ElementBox, ElementStateHandle, MouseRegion, RenderContext, View, + Axis, Element, ElementBox, ElementStateHandle, MouseRegion, SceneBuilder, View, ViewContext, }; use super::{ConstrainedBox, Hook}; @@ -75,22 +75,22 @@ struct ResizeHandleState { custom_dimension: Cell, } -pub struct Resizable { +pub struct Resizable { side: Side, handle_size: f32, - child: ElementBox, + child: ElementBox, state: Rc, _state_handle: ElementStateHandle>, } -impl Resizable { +impl Resizable { pub fn new( - child: ElementBox, + child: ElementBox, element_id: usize, side: Side, handle_size: f32, initial_size: f32, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Self { let state_handle = cx.element_state::>( element_id, @@ -132,24 +132,27 @@ impl Resizable { } } -impl Element for Resizable { +impl Element for Resizable { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: crate::SizeConstraint, - cx: &mut crate::LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { - (self.child.layout(constraint, cx), ()) + (self.child.layout(constraint, view, cx), ()) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: pathfinder_geometry::rect::RectF, visible_bounds: pathfinder_geometry::rect::RectF, _child_size: &mut Self::LayoutState, - cx: &mut crate::PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { cx.scene.push_stacking_context(None, None); @@ -186,7 +189,8 @@ impl Element for Resizable { cx.scene.pop_stacking_context(); - self.child.paint(bounds.origin(), visible_bounds, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); } fn rect_for_text_range( @@ -196,9 +200,10 @@ impl Element for Resizable { _visible_bounds: pathfinder_geometry::rect::RectF, _layout: &Self::LayoutState, _paint: &Self::PaintState, - cx: &crate::MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn debug( @@ -206,10 +211,11 @@ impl Element for Resizable { _bounds: pathfinder_geometry::rect::RectF, _layout: &Self::LayoutState, _paint: &Self::PaintState, - cx: &crate::DebugContext, + view: &V, + cx: &ViewContext, ) -> serde_json::Value { json!({ - "child": self.child.debug(cx), + "child": self.child.debug(view, cx), }) } } diff --git a/crates/gpui/src/elements/stack.rs b/crates/gpui/src/elements/stack.rs index 60f84f53e8..175c5182a7 100644 --- a/crates/gpui/src/elements/stack.rs +++ b/crates/gpui/src/elements/stack.rs @@ -3,41 +3,41 @@ use std::ops::Range; use crate::{ geometry::{rect::RectF, vector::Vector2F}, json::{self, json, ToJson}, - window::MeasurementContext, - DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint, + Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext, }; /// Element which renders it's children in a stack on top of each other. /// The first child determines the size of the others. #[derive(Default)] -pub struct Stack { - children: Vec, +pub struct Stack { + children: Vec>, } -impl Stack { +impl Stack { pub fn new() -> Self { Self::default() } } -impl Element for Stack { +impl Element for Stack { type LayoutState = (); type PaintState = (); fn layout( &mut self, mut constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.min; let mut children = self.children.iter_mut(); if let Some(bottom_child) = children.next() { - size = bottom_child.layout(constraint, cx); + size = bottom_child.layout(constraint, view, cx); constraint = SizeConstraint::strict(size); } for child in children { - child.layout(constraint, cx); + child.layout(constraint, view, cx); } (size, ()) @@ -45,14 +45,16 @@ impl Element for Stack { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { for child in &mut self.children { cx.paint_layer(None, |cx| { - child.paint(bounds.origin(), visible_bounds, cx); + child.paint(scene, bounds.origin(), visible_bounds, view, cx); }); } } @@ -64,12 +66,13 @@ impl Element for Stack { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { self.children .iter() .rev() - .find_map(|child| child.rect_for_text_range(range_utf16.clone(), cx)) + .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx)) } fn debug( @@ -77,18 +80,19 @@ impl Element for Stack { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &DebugContext, + view: &V, + cx: &ViewContext, ) -> json::Value { json!({ "type": "Stack", "bounds": bounds.to_json(), - "children": self.children.iter().map(|child| child.debug(cx)).collect::>() + "children": self.children.iter().map(|child| child.debug(view, cx)).collect::>() }) } } -impl Extend for Stack { - fn extend>(&mut self, children: T) { +impl Extend> for Stack { + fn extend>>(&mut self, children: T) { self.children.extend(children) } } diff --git a/crates/gpui/src/elements/svg.rs b/crates/gpui/src/elements/svg.rs index dc3e37723b..ace6af7ffa 100644 --- a/crates/gpui/src/elements/svg.rs +++ b/crates/gpui/src/elements/svg.rs @@ -8,9 +8,7 @@ use crate::{ rect::RectF, vector::{vec2f, Vector2F}, }, - scene, - window::MeasurementContext, - DebugContext, Element, LayoutContext, PaintContext, SizeConstraint, + scene, Element, SceneBuilder, SizeConstraint, View, ViewContext, }; pub struct Svg { @@ -32,14 +30,15 @@ impl Svg { } } -impl Element for Svg { +impl Element for Svg { type LayoutState = Option; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { match cx.asset_cache.svg(&self.path) { Ok(tree) => { @@ -59,13 +58,15 @@ impl Element for Svg { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, _visible_bounds: RectF, svg: &mut Self::LayoutState, - cx: &mut PaintContext, + _: &mut V, + _: &mut ViewContext, ) { if let Some(svg) = svg.clone() { - cx.scene.push_icon(scene::Icon { + scene.push_icon(scene::Icon { bounds, svg, path: self.path.clone(), @@ -81,7 +82,8 @@ impl Element for Svg { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &V, + _: &ViewContext, ) -> Option { None } @@ -91,7 +93,8 @@ impl Element for Svg { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &DebugContext, + _: &V, + _: &ViewContext, ) -> serde_json::Value { json!({ "type": "Svg", diff --git a/crates/gpui/src/elements/text.rs b/crates/gpui/src/elements/text.rs index 03ed147cde..6a6a217aee 100644 --- a/crates/gpui/src/elements/text.rs +++ b/crates/gpui/src/elements/text.rs @@ -7,8 +7,7 @@ use crate::{ }, json::{ToJson, Value}, text_layout::{Line, RunStyle, ShapedBoundary}, - window::MeasurementContext, - DebugContext, Element, FontCache, LayoutContext, PaintContext, SizeConstraint, TextLayoutCache, + Element, FontCache, SceneBuilder, SizeConstraint, TextLayoutCache, View, ViewContext, }; use log::warn; use serde_json::json; @@ -53,14 +52,15 @@ impl Text { } } -impl Element for Text { +impl Element for Text { type LayoutState = LayoutState; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + _: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { // Convert the string and highlight ranges into an iterator of highlighted chunks. @@ -99,7 +99,7 @@ impl Element for Text { chunks, &self.style, cx.text_layout_cache, - cx.font_cache, + &cx.font_cache, usize::MAX, self.text.matches('\n').count() + 1, ); @@ -143,10 +143,12 @@ impl Element for Text { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, layout: &mut Self::LayoutState, - cx: &mut PaintContext, + _: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { let mut origin = bounds.origin(); let empty = Vec::new(); @@ -163,6 +165,7 @@ impl Element for Text { if boundaries.intersects(visible_bounds) { if self.soft_wrap { line.paint_wrapped( + scene, origin, visible_bounds, layout.line_height, @@ -170,7 +173,7 @@ impl Element for Text { cx, ); } else { - line.paint(origin, visible_bounds, layout.line_height, cx); + line.paint(scene, origin, visible_bounds, layout.line_height, cx); } } origin.set_y(boundaries.max_y()); @@ -184,7 +187,8 @@ impl Element for Text { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &V, + _: &ViewContext, ) -> Option { None } @@ -194,7 +198,8 @@ impl Element for Text { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &DebugContext, + _: &V, + _: &ViewContext, ) -> Value { json!({ "type": "Text", @@ -272,7 +277,7 @@ pub fn layout_highlighted_chunks<'a>( mod tests { use super::*; use crate::{ - elements::Empty, fonts, platform, AppContext, ElementBox, Entity, RenderContext, View, + elements::Empty, fonts, platform, AppContext, ElementBox, Entity, View, ViewContext, }; #[crate::test(self)] @@ -305,7 +310,7 @@ mod tests { "TestView" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index 971d4bc3e0..39a2a61288 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -6,9 +6,7 @@ use crate::{ fonts::TextStyle, geometry::{rect::RectF, vector::Vector2F}, json::json, - window::MeasurementContext, - Action, Axis, ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint, - Task, View, + Action, Axis, ElementStateHandle, SceneBuilder, SizeConstraint, Task, View, ViewContext, }; use serde::Deserialize; use std::{ @@ -20,9 +18,9 @@ use std::{ const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(500); -pub struct Tooltip { - child: ElementBox, - tooltip: Option, +pub struct Tooltip { + child: ElementBox, + tooltip: Option>, _state: ElementStateHandle>, } @@ -50,18 +48,19 @@ pub struct KeystrokeStyle { text: TextStyle, } -impl Tooltip { +impl Tooltip { pub fn new( id: usize, text: String, action: Option>, style: TooltipStyle, - child: ElementBox, - cx: &mut RenderContext, + child: ElementBox, + view: &mut V, + cx: &mut ViewContext, ) -> Self { struct ElementState(Tag); struct MouseEventHandlerState(Tag); - let focused_view_id = cx.focused_view_id(cx.window_id); + let focused_view_id = cx.focused_view_id(); let state_handle = cx.default_element_state::, Rc>(id); let state = state_handle.read(cx).clone(); @@ -94,35 +93,36 @@ impl Tooltip { } else { None }; - let child = MouseEventHandler::>::new(id, cx, |_, _| child) - .on_hover(move |e, cx| { - let position = e.position; - let window_id = cx.window_id(); - if let Some(view_id) = cx.view_id() { - if e.started { - if !state.visible.get() { - state.position.set(position); + let child = + MouseEventHandler::>::new(id, view, cx, |_, _| child) + .on_hover(move |e, cx| { + let position = e.position; + let window_id = cx.window_id(); + if let Some(view_id) = cx.view_id() { + if e.started { + if !state.visible.get() { + state.position.set(position); - let mut debounce = state.debounce.borrow_mut(); - if debounce.is_none() { - *debounce = Some(cx.spawn({ - let state = state.clone(); - |mut cx| async move { - cx.background().timer(DEBOUNCE_TIMEOUT).await; - state.visible.set(true); - cx.update(|cx| cx.notify_view(window_id, view_id)); - } - })); + let mut debounce = state.debounce.borrow_mut(); + if debounce.is_none() { + *debounce = Some(cx.spawn({ + let state = state.clone(); + |mut cx| async move { + cx.background().timer(DEBOUNCE_TIMEOUT).await; + state.visible.set(true); + cx.update(|cx| cx.notify_view(window_id, view_id)); + } + })); + } } + } else { + state.visible.set(false); + state.debounce.take(); + cx.notify(); } - } else { - state.visible.set(false); - state.debounce.take(); - cx.notify(); } - } - }) - .boxed(); + }) + .boxed(); Self { child, tooltip, @@ -168,32 +168,40 @@ impl Tooltip { } } -impl Element for Tooltip { +impl Element for Tooltip { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { - let size = self.child.layout(constraint, cx); + let size = self.child.layout(constraint, view, cx); if let Some(tooltip) = self.tooltip.as_mut() { - tooltip.layout(SizeConstraint::new(Vector2F::zero(), cx.window_size), cx); + tooltip.layout( + SizeConstraint::new(Vector2F::zero(), cx.window_size), + view, + cx, + ); } (size, ()) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) { - self.child.paint(bounds.origin(), visible_bounds, cx); + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx); if let Some(tooltip) = self.tooltip.as_mut() { - tooltip.paint(bounds.origin(), visible_bounds, cx); + tooltip.paint(scene, bounds.origin(), visible_bounds, view, cx); } } @@ -204,9 +212,10 @@ impl Element for Tooltip { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &MeasurementContext, + view: &V, + cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(range, cx) + self.child.rect_for_text_range(range, view, cx) } fn debug( @@ -214,11 +223,12 @@ impl Element for Tooltip { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - cx: &crate::DebugContext, + view: &V, + cx: &ViewContext, ) -> serde_json::Value { json!({ - "child": self.child.debug(cx), - "tooltip": self.tooltip.as_ref().map(|t| t.debug(cx)), + "child": self.child.debug(view, cx), + "tooltip": self.tooltip.as_ref().map(|t| t.debug(view, cx)), }) } } diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index c83f83a419..d6eb4f01d1 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -104,7 +104,7 @@ impl UniformList { mut delta: Vector2F, precise: bool, scroll_max: f32, - cx: &mut EventContext, + cx: &mut ViewContext, ) -> bool { if !precise { delta *= 20.; diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 52ed1197bb..90a4357c5e 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -19,7 +19,7 @@ pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene, S pub mod text_layout; pub use text_layout::TextLayoutCache; mod util; -pub use elements::{Element, ElementBox, ElementRc}; +pub use elements::{Element, ElementBox}; pub mod executor; pub use executor::Task; pub mod color; @@ -27,10 +27,7 @@ pub mod json; pub mod keymap_matcher; pub mod platform; pub use gpui_macros::test; -pub use window::{ - Axis, DebugContext, EventContext, LayoutContext, MeasurementContext, PaintContext, - SizeConstraint, Vector2FExt, -}; +pub use window::{Axis, SizeConstraint, Vector2FExt}; pub use anyhow; pub use serde_json; diff --git a/crates/gpui/src/scene/mouse_region.rs b/crates/gpui/src/scene/mouse_region.rs index e2f8abcf26..ac945af38a 100644 --- a/crates/gpui/src/scene/mouse_region.rs +++ b/crates/gpui/src/scene/mouse_region.rs @@ -5,7 +5,7 @@ use collections::HashMap; use pathfinder_geometry::rect::RectF; use smallvec::SmallVec; -use crate::{platform::MouseButton, EventContext}; +use crate::{platform::MouseButton, window::WindowContext, View, ViewContext}; use super::{ mouse_event::{ @@ -60,82 +60,92 @@ impl MouseRegion { } } - pub fn on_down( - mut self, - button: MouseButton, - handler: impl Fn(MouseDown, &mut EventContext) + 'static, - ) -> Self { + pub fn on_down(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDown, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_down(button, handler); self } - pub fn on_up( - mut self, - button: MouseButton, - handler: impl Fn(MouseUp, &mut EventContext) + 'static, - ) -> Self { + pub fn on_up(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseUp, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_up(button, handler); self } - pub fn on_click( - mut self, - button: MouseButton, - handler: impl Fn(MouseClick, &mut EventContext) + 'static, - ) -> Self { + pub fn on_click(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseClick, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_click(button, handler); self } - pub fn on_down_out( - mut self, - button: MouseButton, - handler: impl Fn(MouseDownOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_down_out(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDownOut, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_down_out(button, handler); self } - pub fn on_up_out( - mut self, - button: MouseButton, - handler: impl Fn(MouseUpOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_up_out(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseUpOut, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_up_out(button, handler); self } - pub fn on_drag( - mut self, - button: MouseButton, - handler: impl Fn(MouseDrag, &mut EventContext) + 'static, - ) -> Self { + pub fn on_drag(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDrag, &mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_drag(button, handler); self } - pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self { + pub fn on_hover(mut self, handler: F) -> Self + where + V: View, + F: Fn(&mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_hover(handler); self } - pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self { + pub fn on_move(mut self, handler: F) -> Self + where + V: View, + F: Fn(&mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_move(handler); self } - pub fn on_move_out( - mut self, - handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_move_out(mut self, handler: F) -> Self + where + V: View, + F: Fn(&mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_move_out(handler); self } - pub fn on_scroll( - mut self, - handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static, - ) -> Self { + pub fn on_scroll(mut self, handler: F) -> Self + where + V: View, + F: Fn(&mut V, &mut ViewContext) + 'static, + { self.handlers = self.handlers.on_scroll(handler); self } @@ -186,7 +196,7 @@ impl MouseRegionId { } } -pub type HandlerCallback = Rc; +pub type HandlerCallback = Rc; #[derive(Clone, PartialEq, Eq, Hash)] pub struct HandlerKey { @@ -283,7 +293,11 @@ impl HandlerSet { } } - pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self { + pub fn on_move(mut self, handler: F) -> Self + where + V: View, + F: Fn(MouseMove, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::move_disc(), None, Rc::new(move |region_event, cx| { if let MouseEvent::Move(e) = region_event { @@ -297,10 +311,11 @@ impl HandlerSet { self } - pub fn on_move_out( - mut self, - handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_move_out(mut self, handler: F) -> Self + where + V: View, + F: Fn(MouseMoveOut, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::move_out_disc(), None, Rc::new(move |region_event, cx| { if let MouseEvent::MoveOut(e) = region_event { @@ -314,11 +329,11 @@ impl HandlerSet { self } - pub fn on_down( - mut self, - button: MouseButton, - handler: impl Fn(MouseDown, &mut EventContext) + 'static, - ) -> Self { + pub fn on_down(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDown, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::down_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Down(e) = region_event { @@ -332,11 +347,11 @@ impl HandlerSet { self } - pub fn on_up( - mut self, - button: MouseButton, - handler: impl Fn(MouseUp, &mut EventContext) + 'static, - ) -> Self { + pub fn on_up(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseUp, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::up_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Up(e) = region_event { @@ -350,11 +365,11 @@ impl HandlerSet { self } - pub fn on_click( - mut self, - button: MouseButton, - handler: impl Fn(MouseClick, &mut EventContext) + 'static, - ) -> Self { + pub fn on_click(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseClick, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::click_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Click(e) = region_event { @@ -368,11 +383,11 @@ impl HandlerSet { self } - pub fn on_down_out( - mut self, - button: MouseButton, - handler: impl Fn(MouseDownOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_down_out(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDownOut, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::down_out_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::DownOut(e) = region_event { @@ -386,11 +401,11 @@ impl HandlerSet { self } - pub fn on_up_out( - mut self, - button: MouseButton, - handler: impl Fn(MouseUpOut, &mut EventContext) + 'static, - ) -> Self { + pub fn on_up_out(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseUpOut, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::up_out_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::UpOut(e) = region_event { @@ -404,11 +419,11 @@ impl HandlerSet { self } - pub fn on_drag( - mut self, - button: MouseButton, - handler: impl Fn(MouseDrag, &mut EventContext) + 'static, - ) -> Self { + pub fn on_drag(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseDrag, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::drag_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Drag(e) = region_event { @@ -422,7 +437,11 @@ impl HandlerSet { self } - pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self { + pub fn on_hover(mut self, handler: F) -> Self + where + V: View, + F: Fn(MouseHover, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::hover_disc(), None, Rc::new(move |region_event, cx| { if let MouseEvent::Hover(e) = region_event { @@ -436,10 +455,11 @@ impl HandlerSet { self } - pub fn on_scroll( - mut self, - handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static, - ) -> Self { + pub fn on_scroll(mut self, handler: F) -> Self + where + V: View, + F: Fn(MouseScrollWheel, &mut V, &mut ViewContext) + 'static, + { self.insert(MouseEvent::scroll_wheel_disc(), None, Rc::new(move |region_event, cx| { if let MouseEvent::ScrollWheel(e) = region_event { diff --git a/crates/gpui/src/test.rs b/crates/gpui/src/test.rs index ce3039f562..97803f43bb 100644 --- a/crates/gpui/src/test.rs +++ b/crates/gpui/src/test.rs @@ -19,8 +19,8 @@ use crate::{ platform, platform::Platform, util::CwdBacktrace, - AppContext, Element, ElementBox, Entity, FontCache, Handle, RenderContext, Subscription, - TestAppContext, View, + AppContext, Element, ElementBox, Entity, FontCache, Handle, Subscription, TestAppContext, View, + ViewContext, }; #[cfg(test)] @@ -240,7 +240,7 @@ impl View for EmptyView { "empty view" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Element::boxed(Empty::new()) } } diff --git a/crates/gpui/src/text_layout.rs b/crates/gpui/src/text_layout.rs index 44b1e81c34..8f1b9190a8 100644 --- a/crates/gpui/src/text_layout.rs +++ b/crates/gpui/src/text_layout.rs @@ -9,7 +9,7 @@ use crate::{ platform::FontSystem, scene, window::WindowContext, - AppContext, PaintContext, SceneBuilder, + SceneBuilder, }; use ordered_float::OrderedFloat; use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; @@ -376,11 +376,12 @@ impl Line { pub fn paint_wrapped( &self, + scene: &SceneBuilder, origin: Vector2F, visible_bounds: RectF, line_height: f32, boundaries: impl IntoIterator, - cx: &mut PaintContext, + cx: &mut WindowContext, ) { let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.; let baseline_origin = vec2f(0., padding_top + self.layout.ascent); @@ -419,14 +420,14 @@ impl Line { ); if glyph_bounds.intersects(visible_bounds) { if glyph.is_emoji { - cx.scene.push_image_glyph(scene::ImageGlyph { + scene.push_image_glyph(scene::ImageGlyph { font_id: run.font_id, font_size: self.layout.font_size, id: glyph.id, origin: glyph_bounds.origin() + baseline_origin, }); } else { - cx.scene.push_glyph(scene::Glyph { + scene.push_glyph(scene::Glyph { font_id: run.font_id, font_size: self.layout.font_size, id: glyph.id, diff --git a/crates/gpui/src/views/select.rs b/crates/gpui/src/views/select.rs index fc93fce98b..1bfaba4c3b 100644 --- a/crates/gpui/src/views/select.rs +++ b/crates/gpui/src/views/select.rs @@ -1,13 +1,13 @@ use serde::Deserialize; use crate::{ - actions, elements::*, impl_actions, platform::MouseButton, AppContext, Entity, RenderContext, - View, ViewContext, WeakViewHandle, + actions, elements::*, impl_actions, platform::MouseButton, AppContext, Entity, View, + ViewContext, WeakViewHandle, }; pub struct Select { handle: WeakViewHandle, - render_item: Box ElementBox>, + render_item: Box ElementBox>, selected_item_ix: usize, item_count: usize, is_open: bool, @@ -41,7 +41,7 @@ pub fn init(cx: &mut AppContext) { } impl Select { - pub fn new ElementBox>( + pub fn new ElementBox>( item_count: usize, cx: &mut ViewContext, render_item: F, @@ -92,7 +92,7 @@ impl View for Select { "Select" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if self.item_count == 0 { return Empty::new().boxed(); } @@ -106,16 +106,21 @@ impl View for Select { Default::default() }; let mut result = Flex::column().with_child( - MouseEventHandler::
::new(self.handle.id(), cx, |mouse_state, cx| { - Container::new((self.render_item)( - self.selected_item_ix, - ItemType::Header, - mouse_state.hovered(), - cx, - )) - .with_style(style.header) - .boxed() - }) + MouseEventHandler::
::new( + self.handle.id(), + self, + cx, + |mouse_state, this, cx| { + Container::new((self.render_item)( + self.selected_item_ix, + ItemType::Header, + mouse_state.hovered(), + cx, + )) + .with_style(style.header) + .boxed() + }, + ) .on_click(MouseButton::Left, move |_, cx| { cx.dispatch_action(ToggleSelect) }) @@ -134,18 +139,23 @@ impl View for Select { let selected_item_ix = this.selected_item_ix; range.end = range.end.min(this.item_count); items.extend(range.map(|ix| { - MouseEventHandler::::new(ix, cx, |mouse_state, cx| { - (this.render_item)( - ix, - if ix == selected_item_ix { - ItemType::Selected - } else { - ItemType::Unselected - }, - mouse_state.hovered(), - cx, - ) - }) + MouseEventHandler::::new( + ix, + self, + cx, + |mouse_state, this, cx| { + (this.render_item)( + ix, + if ix == selected_item_ix { + ItemType::Selected + } else { + ItemType::Unselected + }, + mouse_state.hovered(), + cx, + ) + }, + ) .on_click(MouseButton::Left, move |_, cx| { cx.dispatch_action(SelectItem(ix)) }) From e115baa60c143dc50733c4e9923913813bb0bbe1 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 11 Apr 2023 18:21:56 -0600 Subject: [PATCH 06/58] WIP --- .../src/activity_indicator.rs | 6 +- crates/auto_update/src/update_notification.rs | 2 +- crates/breadcrumbs/src/breadcrumbs.rs | 6 +- crates/collab_ui/src/collab_titlebar_item.rs | 30 +- .../src/collaborator_list_popover.rs | 11 +- crates/collab_ui/src/contact_finder.rs | 6 +- crates/collab_ui/src/contact_list.rs | 22 +- crates/collab_ui/src/contact_notification.rs | 5 +- crates/collab_ui/src/contacts_popover.rs | 6 +- crates/collab_ui/src/face_pile.rs | 4 +- .../src/incoming_call_notification.rs | 8 +- crates/collab_ui/src/notifications.rs | 4 +- .../src/project_shared_notification.rs | 8 +- .../collab_ui/src/sharing_status_indicator.rs | 4 +- crates/command_palette/src/command_palette.rs | 9 +- crates/context_menu/src/context_menu.rs | 38 +- crates/copilot/src/sign_in.rs | 10 +- crates/copilot_button/src/copilot_button.rs | 6 +- crates/diagnostics/src/diagnostics.rs | 5 +- crates/diagnostics/src/items.rs | 6 +- crates/drag_and_drop/src/drag_and_drop.rs | 54 +- crates/editor/src/display_map/block_map.rs | 6 +- crates/editor/src/editor.rs | 18 +- crates/editor/src/element.rs | 149 +++-- crates/editor/src/hover_popover.rs | 8 +- crates/editor/src/items.rs | 6 +- crates/feedback/src/deploy_feedback_button.rs | 4 +- crates/feedback/src/feedback_editor.rs | 6 +- crates/feedback/src/feedback_info_text.rs | 4 +- crates/feedback/src/submit_feedback_button.rs | 4 +- crates/file_finder/src/file_finder.rs | 6 +- crates/go_to_line/src/go_to_line.rs | 4 +- crates/gpui/examples/text.rs | 25 +- crates/gpui/src/app.rs | 619 ++++++++---------- crates/gpui/src/app/menu.rs | 6 +- crates/gpui/src/app/test_app_context.rs | 43 +- crates/gpui/src/app/window.rs | 441 ++++++++----- crates/gpui/src/app/window_input_handler.rs | 49 +- crates/gpui/src/elements.rs | 58 +- crates/gpui/src/elements/align.rs | 14 +- crates/gpui/src/elements/canvas.rs | 4 +- crates/gpui/src/elements/clipped.rs | 8 +- crates/gpui/src/elements/constrained_box.rs | 2 +- crates/gpui/src/elements/container.rs | 20 +- crates/gpui/src/elements/empty.rs | 3 +- crates/gpui/src/elements/expanded.rs | 2 +- crates/gpui/src/elements/flex.rs | 23 +- crates/gpui/src/elements/hook.rs | 2 +- crates/gpui/src/elements/image.rs | 6 +- crates/gpui/src/elements/keystroke_label.rs | 7 +- crates/gpui/src/elements/label.rs | 14 +- crates/gpui/src/elements/list.rs | 59 +- .../gpui/src/elements/mouse_event_handler.rs | 57 +- crates/gpui/src/elements/overlay.rs | 31 +- crates/gpui/src/elements/resizable.rs | 38 +- crates/gpui/src/elements/stack.rs | 11 +- crates/gpui/src/elements/svg.rs | 2 +- crates/gpui/src/elements/text.rs | 34 +- crates/gpui/src/elements/tooltip.rs | 59 +- crates/gpui/src/elements/uniform_list.rs | 45 +- crates/gpui/src/gpui.rs | 4 +- crates/gpui/src/scene.rs | 22 + crates/gpui/src/scene/mouse_region.rs | 180 +++-- crates/gpui/src/text_layout.rs | 12 +- crates/gpui/src/views/select.rs | 34 +- .../src/active_buffer_language.rs | 4 +- .../src/language_selector.rs | 6 +- crates/outline/src/outline.rs | 4 +- crates/picker/src/picker.rs | 6 +- crates/project_panel/src/project_panel.rs | 16 +- crates/project_symbols/src/project_symbols.rs | 6 +- crates/recent_projects/src/recent_projects.rs | 5 +- crates/search/src/buffer_search.rs | 15 +- crates/search/src/project_search.rs | 13 +- crates/terminal_view/src/terminal_button.rs | 8 +- crates/terminal_view/src/terminal_element.rs | 52 +- crates/terminal_view/src/terminal_view.rs | 10 +- crates/theme/src/ui.rs | 69 +- crates/theme_selector/src/theme_selector.rs | 6 +- crates/theme_testbench/src/theme_testbench.rs | 20 +- crates/welcome/src/base_keymap_picker.rs | 2 +- crates/welcome/src/welcome.rs | 2 +- crates/workspace/src/dock.rs | 5 +- .../workspace/src/dock/toggle_dock_button.rs | 2 +- crates/workspace/src/item.rs | 6 +- crates/workspace/src/notifications.rs | 2 +- crates/workspace/src/pane.rs | 53 +- .../src/pane/dragged_item_receiver.rs | 16 +- crates/workspace/src/pane_group.rs | 8 +- crates/workspace/src/shared_screen.rs | 6 +- crates/workspace/src/sidebar.rs | 6 +- crates/workspace/src/status_bar.rs | 23 +- crates/workspace/src/toolbar.rs | 6 +- crates/workspace/src/workspace.rs | 11 +- 94 files changed, 1477 insertions(+), 1310 deletions(-) diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index 2fd8774398..99b0b9dc8b 100644 --- a/crates/activity_indicator/src/activity_indicator.rs +++ b/crates/activity_indicator/src/activity_indicator.rs @@ -5,7 +5,7 @@ use gpui::{ actions, elements::*, platform::{CursorStyle, MouseButton}, - Action, AppContext, Entity, ModelHandle, RenderContext, View, ViewContext, ViewHandle, + Action, AppContext, Entity, ModelHandle, View, ViewContext, ViewHandle, }; use language::{LanguageRegistry, LanguageServerBinaryStatus}; use project::{LanguageServerProgress, Project}; @@ -172,7 +172,7 @@ impl ActivityIndicator { .flatten() } - fn content_to_render(&mut self, cx: &mut RenderContext) -> Content { + fn content_to_render(&mut self, cx: &mut ViewContext) -> Content { // Show any language server has pending activity. let mut pending_work = self.pending_language_server_work(cx); if let Some(PendingWork { @@ -314,7 +314,7 @@ impl View for ActivityIndicator { "ActivityIndicator" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let Content { icon, message, diff --git a/crates/auto_update/src/update_notification.rs b/crates/auto_update/src/update_notification.rs index 414dcdf5a1..c3a8f9ed69 100644 --- a/crates/auto_update/src/update_notification.rs +++ b/crates/auto_update/src/update_notification.rs @@ -26,7 +26,7 @@ impl View for UpdateNotification { "UpdateNotification" } - fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext) -> gpui::ElementBox { let theme = cx.global::().theme.clone(); let theme = &theme.update_notification; diff --git a/crates/breadcrumbs/src/breadcrumbs.rs b/crates/breadcrumbs/src/breadcrumbs.rs index 6c8cbc5516..ecb5d8adaf 100644 --- a/crates/breadcrumbs/src/breadcrumbs.rs +++ b/crates/breadcrumbs/src/breadcrumbs.rs @@ -1,6 +1,6 @@ use gpui::{ - elements::*, platform::MouseButton, AppContext, Entity, RenderContext, Subscription, View, - ViewContext, ViewHandle, + elements::*, platform::MouseButton, AppContext, Entity, Subscription, View, ViewContext, + ViewHandle, }; use itertools::Itertools; use search::ProjectSearchView; @@ -41,7 +41,7 @@ impl View for Breadcrumbs { "Breadcrumbs" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let active_item = match &self.active_item { Some(active_item) => active_item, None => return Empty::new().boxed(), diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 60272b66bb..537c77a7e4 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -16,8 +16,8 @@ use gpui::{ impl_internal_actions, json::{self, ToJson}, platform::{CursorStyle, MouseButton}, - AppContext, Entity, ImageData, ModelHandle, RenderContext, Subscription, View, ViewContext, - ViewHandle, WeakViewHandle, + AppContext, Entity, ImageData, ModelHandle, Subscription, View, ViewContext, ViewHandle, + WeakViewHandle, }; use settings::Settings; use std::{ops::Range, sync::Arc}; @@ -68,7 +68,7 @@ impl View for CollabTitlebarItem { "CollabTitlebarItem" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let workspace = if let Some(workspace) = self.workspace.upgrade(cx) { workspace } else { @@ -325,7 +325,7 @@ impl CollabTitlebarItem { fn render_toggle_contacts_button( &self, theme: &Theme, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let titlebar = &theme.workspace.titlebar; @@ -390,7 +390,7 @@ impl CollabTitlebarItem { &self, theme: &Theme, room: &ModelHandle, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let icon; let tooltip; @@ -436,7 +436,7 @@ impl CollabTitlebarItem { &self, workspace: &ViewHandle, theme: &Theme, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Option { let project = workspace.read(cx).project(); if project.read(cx).is_remote() { @@ -491,7 +491,7 @@ impl CollabTitlebarItem { ) } - fn render_user_menu_button(&self, theme: &Theme, cx: &mut RenderContext) -> ElementBox { + fn render_user_menu_button(&self, theme: &Theme, cx: &mut ViewContext) -> ElementBox { let titlebar = &theme.workspace.titlebar; Stack::new() @@ -535,7 +535,7 @@ impl CollabTitlebarItem { .boxed() } - fn render_sign_in_button(&self, theme: &Theme, cx: &mut RenderContext) -> ElementBox { + fn render_sign_in_button(&self, theme: &Theme, cx: &mut ViewContext) -> ElementBox { let titlebar = &theme.workspace.titlebar; MouseEventHandler::::new(0, cx, |state, _| { let style = titlebar.sign_in_prompt.style_for(state, false); @@ -554,7 +554,7 @@ impl CollabTitlebarItem { fn render_contacts_popover_host<'a>( &'a self, _theme: &'a theme::Titlebar, - cx: &'a RenderContext, + cx: &'a ViewContext, ) -> Option { self.contacts_popover.as_ref().map(|popover| { Overlay::new(ChildView::new(popover, cx).boxed()) @@ -573,7 +573,7 @@ impl CollabTitlebarItem { workspace: &ViewHandle, theme: &Theme, room: &ModelHandle, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Vec { let mut participants = room .read(cx) @@ -615,7 +615,7 @@ impl CollabTitlebarItem { theme: &Theme, user: &Arc, peer_id: PeerId, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let replica_id = workspace.read(cx).project().read(cx).replica_id(); Container::new(self.render_face_pile( @@ -639,7 +639,7 @@ impl CollabTitlebarItem { location: Option, workspace: &ViewHandle, theme: &Theme, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let project_id = workspace.read(cx).project().read(cx).remote_id(); let room = ActiveCall::global(cx).read(cx).room(); @@ -804,7 +804,7 @@ impl CollabTitlebarItem { workspace: &ViewHandle, location: Option, mut style: AvatarStyle, - cx: &RenderContext, + cx: &ViewContext, ) -> AvatarStyle { if let Some(location) = location { if let ParticipantLocation::SharedProject { project_id } = location { @@ -840,7 +840,7 @@ impl CollabTitlebarItem { fn render_connection_status( &self, status: &client::Status, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Option { enum ConnectionStatusButton {} @@ -927,7 +927,7 @@ impl Element for AvatarRibbon { path.line_to(bounds.upper_right() - vec2f(bounds.height(), 0.)); path.curve_to(bounds.lower_right(), bounds.upper_right()); path.line_to(bounds.lower_left()); - cx.scene.push_path(path.build(self.color, None)); + scene.push_path(path.build(self.color, None)); } fn rect_for_text_range( diff --git a/crates/collab_ui/src/collaborator_list_popover.rs b/crates/collab_ui/src/collaborator_list_popover.rs index c409b541c9..bfdcf69eeb 100644 --- a/crates/collab_ui/src/collaborator_list_popover.rs +++ b/crates/collab_ui/src/collaborator_list_popover.rs @@ -1,10 +1,7 @@ use call::ActiveCall; use client::UserStore; use gpui::Action; -use gpui::{ - actions, elements::*, platform::MouseButton, Entity, ModelHandle, RenderContext, View, - ViewContext, -}; +use gpui::{actions, elements::*, platform::MouseButton, Entity, ModelHandle, View, ViewContext}; use settings::Settings; use crate::collab_titlebar_item::ToggleCollaboratorList; @@ -21,7 +18,7 @@ enum Collaborator { actions!(collaborator_list_popover, [NoOp]); pub(crate) struct CollaboratorListPopover { - list_state: ListState, + list_state: ListState, } impl Entity for CollaboratorListPopover { @@ -33,7 +30,7 @@ impl View for CollaboratorListPopover { "CollaboratorListPopover" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); MouseEventHandler::::new(0, cx, |_, _| { @@ -120,7 +117,7 @@ fn render_collaborator_list_entry( icon: Svg, icon_action: IA, icon_tooltip: String, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { enum Username {} enum UsernameTooltip {} diff --git a/crates/collab_ui/src/contact_finder.rs b/crates/collab_ui/src/contact_finder.rs index d34a344cd6..5d0f315400 100644 --- a/crates/collab_ui/src/contact_finder.rs +++ b/crates/collab_ui/src/contact_finder.rs @@ -1,7 +1,7 @@ use client::{ContactRequestStatus, User, UserStore}; use gpui::{ - elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, RenderContext, Task, - View, ViewContext, ViewHandle, + elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, Task, View, + ViewContext, ViewHandle, }; use picker::{Picker, PickerDelegate}; use settings::Settings; @@ -32,7 +32,7 @@ impl View for ContactFinder { "ContactFinder" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index adbc4d7ec8..891db3d2ac 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -11,7 +11,7 @@ use gpui::{ impl_actions, impl_internal_actions, keymap_matcher::KeymapContext, platform::{CursorStyle, MouseButton, PromptLevel}, - AppContext, Entity, ModelHandle, RenderContext, Subscription, View, ViewContext, ViewHandle, + AppContext, Entity, ModelHandle, Subscription, View, ViewContext, ViewHandle, }; use menu::{Confirm, SelectNext, SelectPrev}; use project::Project; @@ -799,7 +799,7 @@ impl ContactList { is_last: bool, is_selected: bool, theme: &theme::ContactList, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let font_cache = cx.font_cache(); let host_avatar_height = theme @@ -834,7 +834,7 @@ impl ContactList { let start_y = bounds.min_y(); let end_y = bounds.min_y() + baseline_offset - (cap_height / 2.); - cx.scene.push_quad(gpui::Quad { + scene.push_quad(gpui::Quad { bounds: RectF::from_points( vec2f(start_x, start_y), vec2f( @@ -846,7 +846,7 @@ impl ContactList { border: gpui::Border::default(), corner_radius: 0., }); - cx.scene.push_quad(gpui::Quad { + scene.push_quad(gpui::Quad { bounds: RectF::from_points( vec2f(start_x, end_y), vec2f(end_x, end_y + tree_branch.width), @@ -898,7 +898,7 @@ impl ContactList { is_last: bool, is_selected: bool, theme: &theme::ContactList, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let font_cache = cx.font_cache(); let host_avatar_height = theme @@ -932,7 +932,7 @@ impl ContactList { let end_y = bounds.min_y() + baseline_offset - (cap_height / 2.); - cx.scene.push_quad(gpui::Quad { + scene.push_quad(gpui::Quad { bounds: RectF::from_points( vec2f(start_x, start_y), vec2f( @@ -944,7 +944,7 @@ impl ContactList { border: gpui::Border::default(), corner_radius: 0., }); - cx.scene.push_quad(gpui::Quad { + scene.push_quad(gpui::Quad { bounds: RectF::from_points( vec2f(start_x, end_y), vec2f(end_x, end_y + tree_branch.width), @@ -999,7 +999,7 @@ impl ContactList { theme: &theme::ContactList, is_selected: bool, is_collapsed: bool, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { enum Header {} enum LeaveCallContactList {} @@ -1077,7 +1077,7 @@ impl ContactList { project: &ModelHandle, theme: &theme::ContactList, is_selected: bool, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let online = contact.online; let busy = contact.busy || calling; @@ -1194,7 +1194,7 @@ impl ContactList { theme: &theme::ContactList, is_incoming: bool, is_selected: bool, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { enum Decline {} enum Accept {} @@ -1331,7 +1331,7 @@ impl View for ContactList { cx } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { enum AddContact {} let theme = cx.global::().theme.clone(); diff --git a/crates/collab_ui/src/contact_notification.rs b/crates/collab_ui/src/contact_notification.rs index 5badae695b..c504a5771b 100644 --- a/crates/collab_ui/src/contact_notification.rs +++ b/crates/collab_ui/src/contact_notification.rs @@ -3,8 +3,7 @@ use std::sync::Arc; use crate::notifications::render_user_notification; use client::{ContactEventKind, User, UserStore}; use gpui::{ - elements::*, impl_internal_actions, AppContext, Entity, ModelHandle, RenderContext, View, - ViewContext, + elements::*, impl_internal_actions, AppContext, Entity, ModelHandle, View, ViewContext, }; use workspace::notifications::Notification; @@ -43,7 +42,7 @@ impl View for ContactNotification { "ContactNotification" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { match self.kind { ContactEventKind::Requested => render_user_notification( self.user.clone(), diff --git a/crates/collab_ui/src/contacts_popover.rs b/crates/collab_ui/src/contacts_popover.rs index 52925738b7..ee900c285c 100644 --- a/crates/collab_ui/src/contacts_popover.rs +++ b/crates/collab_ui/src/contacts_popover.rs @@ -1,8 +1,8 @@ use crate::{contact_finder::ContactFinder, contact_list::ContactList, ToggleContactsMenu}; use client::UserStore; use gpui::{ - actions, elements::*, platform::MouseButton, AppContext, Entity, ModelHandle, RenderContext, - View, ViewContext, ViewHandle, + actions, elements::*, platform::MouseButton, AppContext, Entity, ModelHandle, View, + ViewContext, ViewHandle, }; use project::Project; use settings::Settings; @@ -91,7 +91,7 @@ impl View for ContactsPopover { "ContactsPopover" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); let child = match &self.child { Child::ContactList(child) => ChildView::new(child, cx), diff --git a/crates/collab_ui/src/face_pile.rs b/crates/collab_ui/src/face_pile.rs index 3b95443fee..9269a32fdb 100644 --- a/crates/collab_ui/src/face_pile.rs +++ b/crates/collab_ui/src/face_pile.rs @@ -37,7 +37,7 @@ impl Element for FacePile { let mut width = 0.; for face in &mut self.faces { - width += face.layout(constraint, cx).x(); + width += face.layout(constraint, view, cx).x(); } width -= self.overlap * self.faces.len().saturating_sub(1) as f32; @@ -60,7 +60,7 @@ impl Element for FacePile { let size = face.size(); origin_x -= size.x(); cx.paint_layer(None, |cx| { - face.paint(vec2f(origin_x, origin_y), visible_bounds, cx); + face.paint(scene, vec2f(origin_x, origin_y), visible_bounds, view, cx); }); origin_x += self.overlap; } diff --git a/crates/collab_ui/src/incoming_call_notification.rs b/crates/collab_ui/src/incoming_call_notification.rs index 58c42f919f..ed60959413 100644 --- a/crates/collab_ui/src/incoming_call_notification.rs +++ b/crates/collab_ui/src/incoming_call_notification.rs @@ -6,7 +6,7 @@ use gpui::{ geometry::{rect::RectF, vector::vec2f}, impl_internal_actions, platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions}, - AppContext, Entity, RenderContext, View, ViewContext, + AppContext, Entity, View, ViewContext, }; use settings::Settings; use util::ResultExt; @@ -99,7 +99,7 @@ impl IncomingCallNotification { } } - fn render_caller(&self, cx: &mut RenderContext) -> ElementBox { + fn render_caller(&self, cx: &mut ViewContext) -> ElementBox { let theme = &cx.global::().theme.incoming_call_notification; let default_project = proto::ParticipantProject::default(); let initial_project = self @@ -165,7 +165,7 @@ impl IncomingCallNotification { .boxed() } - fn render_buttons(&self, cx: &mut RenderContext) -> ElementBox { + fn render_buttons(&self, cx: &mut ViewContext) -> ElementBox { enum Accept {} enum Decline {} @@ -222,7 +222,7 @@ impl View for IncomingCallNotification { "IncomingCallNotification" } - fn render(&mut self, cx: &mut RenderContext) -> gpui::ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> gpui::ElementBox { let background = cx .global::() .theme diff --git a/crates/collab_ui/src/notifications.rs b/crates/collab_ui/src/notifications.rs index 0353557681..952c6777a3 100644 --- a/crates/collab_ui/src/notifications.rs +++ b/crates/collab_ui/src/notifications.rs @@ -2,7 +2,7 @@ use client::User; use gpui::{ elements::*, platform::{CursorStyle, MouseButton}, - Action, Element, ElementBox, RenderContext, View, + Action, Element, ElementBox, View, ViewContext, }; use settings::Settings; use std::sync::Arc; @@ -16,7 +16,7 @@ pub fn render_user_notification( body: Option<&'static str>, dismiss_action: A, buttons: Vec<(&'static str, Box)>, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let theme = cx.global::().theme.clone(); let theme = &theme.contact_notification; diff --git a/crates/collab_ui/src/project_shared_notification.rs b/crates/collab_ui/src/project_shared_notification.rs index 7cf666c7ca..9c22ed734e 100644 --- a/crates/collab_ui/src/project_shared_notification.rs +++ b/crates/collab_ui/src/project_shared_notification.rs @@ -6,7 +6,7 @@ use gpui::{ elements::*, geometry::{rect::RectF, vector::vec2f}, platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions}, - AppContext, Entity, RenderContext, View, ViewContext, + AppContext, Entity, View, ViewContext, }; use settings::Settings; use std::sync::Arc; @@ -104,7 +104,7 @@ impl ProjectSharedNotification { cx.remove_window(window_id); } - fn render_owner(&self, cx: &mut RenderContext) -> ElementBox { + fn render_owner(&self, cx: &mut ViewContext) -> ElementBox { let theme = &cx.global::().theme.project_shared_notification; Flex::row() .with_children(self.owner.avatar.clone().map(|avatar| { @@ -164,7 +164,7 @@ impl ProjectSharedNotification { .boxed() } - fn render_buttons(&self, cx: &mut RenderContext) -> ElementBox { + fn render_buttons(&self, cx: &mut ViewContext) -> ElementBox { enum Open {} enum Dismiss {} @@ -227,7 +227,7 @@ impl View for ProjectSharedNotification { "ProjectSharedNotification" } - fn render(&mut self, cx: &mut RenderContext) -> gpui::ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> gpui::ElementBox { let background = cx .global::() .theme diff --git a/crates/collab_ui/src/sharing_status_indicator.rs b/crates/collab_ui/src/sharing_status_indicator.rs index aa5c50f449..340c048bf9 100644 --- a/crates/collab_ui/src/sharing_status_indicator.rs +++ b/crates/collab_ui/src/sharing_status_indicator.rs @@ -3,7 +3,7 @@ use gpui::{ color::Color, elements::{MouseEventHandler, Svg}, platform::{Appearance, MouseButton}, - AppContext, Element, ElementBox, Entity, RenderContext, View, + AppContext, Element, ElementBox, Entity, View, ViewContext, }; use settings::Settings; @@ -40,7 +40,7 @@ impl View for SharingStatusIndicator { "SharingStatusIndicator" } - fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox { let color = match cx.appearance { Appearance::Light | Appearance::VibrantLight => Color::black(), Appearance::Dark | Appearance::VibrantDark => Color::white(), diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index bc49f4f101..d7e2178302 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -4,8 +4,7 @@ use gpui::{ actions, elements::{ChildView, Flex, Label, ParentElement}, keymap_matcher::Keystroke, - Action, AnyViewHandle, AppContext, Element, Entity, MouseState, RenderContext, View, - ViewContext, ViewHandle, + Action, AnyViewHandle, AppContext, Element, Entity, MouseState, View, ViewContext, ViewHandle, }; use picker::{Picker, PickerDelegate}; use settings::Settings; @@ -80,9 +79,7 @@ impl CommandPalette { fn toggle(_: &mut Workspace, _: &Toggle, cx: &mut ViewContext) { let workspace = cx.handle(); let window_id = cx.window_id(); - let focused_view_id = cx - .focused_view_id(window_id) - .unwrap_or_else(|| workspace.id()); + let focused_view_id = cx.focused_view_id().unwrap_or_else(|| workspace.id()); cx.as_mut().defer(move |cx| { let this = cx.add_view(&workspace, |cx| Self::new(focused_view_id, cx)); @@ -128,7 +125,7 @@ impl View for CommandPalette { "CommandPalette" } - fn render(&mut self, cx: &mut RenderContext) -> gpui::ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> gpui::ElementBox { ChildView::new(&self.picker, cx).boxed() } diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index 25d9b0ec10..47cb253a4e 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -4,15 +4,13 @@ use gpui::{ impl_internal_actions, keymap_matcher::KeymapContext, platform::{CursorStyle, MouseButton}, - Action, AnyViewHandle, AppContext, Axis, Entity, MouseState, RenderContext, SizeConstraint, - Subscription, View, ViewContext, + Action, AnyViewHandle, AppContext, Axis, Entity, MouseState, SizeConstraint, Subscription, + View, ViewContext, }; use menu::*; use settings::Settings; use std::{any::TypeId, borrow::Cow, time::Duration}; -pub type StaticItem = Box ElementBox>; - #[derive(Copy, Clone, PartialEq)] struct Clicked; @@ -28,8 +26,10 @@ pub fn init(cx: &mut AppContext) { cx.add_action(ContextMenu::cancel); } +pub type StaticItem = Box ElementBox>; + type ContextMenuItemBuilder = - Box ElementBox>; + Box ElementBox>; pub enum ContextMenuItemLabel { String(Cow<'static, str>), @@ -142,7 +142,7 @@ impl View for ContextMenu { cx } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if !self.visible { return Empty::new().boxed(); } @@ -152,10 +152,10 @@ impl View for ContextMenu { let expanded_menu = self .render_menu(cx) .constrained() - .dynamically(move |constraint, cx| { + .dynamically(move |constraint, view, cx| { SizeConstraint::strict_along( Axis::Horizontal, - collapsed_menu.layout(constraint, cx).x(), + collapsed_menu.layout(constraint, view, cx).x(), ) }) .boxed(); @@ -315,7 +315,7 @@ impl ContextMenu { self.visible = true; self.show_count += 1; if !cx.is_self_focused() { - self.previously_focused_view_id = cx.focused_view_id(cx.window_id()); + self.previously_focused_view_id = cx.focused_view_id(); } cx.focus_self(); } else { @@ -328,7 +328,7 @@ impl ContextMenu { self.position_mode = mode; } - fn render_menu_for_measurement(&self, cx: &mut RenderContext) -> impl Element { + fn render_menu_for_measurement(&self, cx: &mut ViewContext) -> impl Element { let window_id = cx.window_id(); let style = cx.global::().theme.context_menu.clone(); Flex::row() @@ -415,14 +415,14 @@ impl ContextMenu { .with_style(style.container) } - fn render_menu(&self, cx: &mut RenderContext) -> impl Element { + fn render_menu(&self, cx: &mut ViewContext) -> impl Element { enum Menu {} enum MenuItem {} let style = cx.global::().theme.context_menu.clone(); let window_id = cx.window_id(); - MouseEventHandler::::new(0, cx, |_, cx| { + MouseEventHandler::::new(0, cx, |_, cx| { Flex::column() .with_children(self.items.iter().enumerate().map(|(ix, item)| { match item { @@ -436,7 +436,7 @@ impl ContextMenu { } }; - MouseEventHandler::::new(ix, cx, |state, _| { + MouseEventHandler::::new(ix, cx, |state, _| { let style = style.item.style_for(state, Some(ix) == self.selected_index); @@ -467,14 +467,14 @@ impl ContextMenu { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_up(MouseButton::Left, |_, _| {}) // Capture these events - .on_down(MouseButton::Left, |_, _| {}) // Capture these events - .on_click(MouseButton::Left, move |_, cx| { + .on_up(MouseButton::Left, |_, _, _| {}) // Capture these events + .on_down(MouseButton::Left, |_, _, _| {}) // Capture these events + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(Clicked); let window_id = cx.window_id(); cx.dispatch_any_action_at(window_id, view_id, action.boxed_clone()); }) - .on_drag(MouseButton::Left, |_, _| {}) + .on_drag(MouseButton::Left, |_, _, _| {}) .boxed() } @@ -492,7 +492,7 @@ impl ContextMenu { .with_style(style.container) .boxed() }) - .on_down_out(MouseButton::Left, |_, cx| cx.dispatch_action(Cancel)) - .on_down_out(MouseButton::Right, |_, cx| cx.dispatch_action(Cancel)) + .on_down_out(MouseButton::Left, |_, _, cx| cx.dispatch_action(Cancel)) + .on_down_out(MouseButton::Right, |_, _, cx| cx.dispatch_action(Cancel)) } } diff --git a/crates/copilot/src/sign_in.rs b/crates/copilot/src/sign_in.rs index a65be325ce..74f9828598 100644 --- a/crates/copilot/src/sign_in.rs +++ b/crates/copilot/src/sign_in.rs @@ -96,7 +96,7 @@ impl CopilotCodeVerification { fn render_device_code( data: &PromptUserDeviceFlow, style: &theme::Copilot, - cx: &mut gpui::RenderContext, + cx: &mut gpui::ViewContext, ) -> ElementBox { let copied = cx .read_from_clipboard() @@ -145,7 +145,7 @@ impl CopilotCodeVerification { fn render_prompting_modal( data: &PromptUserDeviceFlow, style: &theme::Copilot, - cx: &mut gpui::RenderContext, + cx: &mut gpui::ViewContext, ) -> ElementBox { Flex::column() .with_children([ @@ -205,7 +205,7 @@ impl CopilotCodeVerification { } fn render_enabled_modal( style: &theme::Copilot, - cx: &mut gpui::RenderContext, + cx: &mut gpui::ViewContext, ) -> ElementBox { let enabled_style = &style.auth.authorized; Flex::column() @@ -254,7 +254,7 @@ impl CopilotCodeVerification { } fn render_unauthorized_modal( style: &theme::Copilot, - cx: &mut gpui::RenderContext, + cx: &mut gpui::ViewContext, ) -> ElementBox { let unauthorized_style = &style.auth.not_authorized; @@ -333,7 +333,7 @@ impl View for CopilotCodeVerification { cx.notify() } - fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox { let style = cx.global::().theme.clone(); modal("Connect Copilot to Zed", &style.copilot.modal, cx, |cx| { diff --git a/crates/copilot_button/src/copilot_button.rs b/crates/copilot_button/src/copilot_button.rs index 8721829241..e9e83d4f0c 100644 --- a/crates/copilot_button/src/copilot_button.rs +++ b/crates/copilot_button/src/copilot_button.rs @@ -6,8 +6,8 @@ use gpui::{ elements::*, impl_internal_actions, platform::{CursorStyle, MouseButton}, - AppContext, Element, ElementBox, Entity, MouseState, RenderContext, Subscription, View, - ViewContext, ViewHandle, + AppContext, Element, ElementBox, Entity, MouseState, Subscription, View, ViewContext, + ViewHandle, }; use settings::{settings_file::SettingsFile, Settings}; use workspace::{ @@ -91,7 +91,7 @@ impl View for CopilotButton { "CopilotButton" } - fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox { let settings = cx.global::(); if !settings.enable_copilot_integration { diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 72337c4696..a341ea4449 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -11,8 +11,7 @@ use editor::{ }; use gpui::{ actions, elements::*, fonts::TextStyle, impl_internal_actions, serde_json, AnyViewHandle, - AppContext, Entity, ModelHandle, RenderContext, Task, View, ViewContext, ViewHandle, - WeakViewHandle, + AppContext, Entity, ModelHandle, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; use language::{ Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, @@ -87,7 +86,7 @@ impl View for ProjectDiagnosticsEditor { "ProjectDiagnosticsEditor" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if self.path_states.is_empty() { let theme = &cx.global::().theme.project_diagnostics; Label::new("No problems in workspace", theme.empty_message.clone()) diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index 6ebae6e204..5c8f91e32f 100644 --- a/crates/diagnostics/src/items.rs +++ b/crates/diagnostics/src/items.rs @@ -3,8 +3,8 @@ use editor::{Editor, GoToDiagnostic}; use gpui::{ elements::*, platform::{CursorStyle, MouseButton}, - serde_json, AppContext, Entity, ModelHandle, RenderContext, Subscription, View, ViewContext, - ViewHandle, WeakViewHandle, + serde_json, AppContext, Entity, ModelHandle, Subscription, View, ViewContext, ViewHandle, + WeakViewHandle, }; use language::Diagnostic; use project::Project; @@ -84,7 +84,7 @@ impl View for DiagnosticIndicator { "DiagnosticIndicator" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { enum Summary {} enum Message {} diff --git a/crates/drag_and_drop/src/drag_and_drop.rs b/crates/drag_and_drop/src/drag_and_drop.rs index d54e7a86ac..2fd068c408 100644 --- a/crates/drag_and_drop/src/drag_and_drop.rs +++ b/crates/drag_and_drop/src/drag_and_drop.rs @@ -6,7 +6,7 @@ use gpui::{ geometry::{rect::RectF, vector::Vector2F}, platform::{CursorStyle, MouseButton}, scene::{MouseDown, MouseDrag}, - AppContext, Element, ElementBox, EventContext, RenderContext, View, WeakViewHandle, + AppContext, Element, ElementBox, View, ViewContext, WeakViewHandle, }; const DEAD_ZONE: f32 = 4.; @@ -26,7 +26,7 @@ enum State { region_offset: Vector2F, region: RectF, payload: Rc, - render: Rc, &mut RenderContext) -> ElementBox>, + render: Rc, &mut ViewContext) -> ElementBox>, }, Canceled, } @@ -111,7 +111,7 @@ impl DragAndDrop { }) } - pub fn drag_started(event: MouseDown, cx: &mut EventContext) { + pub fn drag_started(event: MouseDown, cx: &mut ViewContext) { cx.update_global(|this: &mut Self, _| { this.currently_dragged = Some(State::Down { region_offset: event.position - event.region.origin(), @@ -123,8 +123,8 @@ impl DragAndDrop { pub fn dragging( event: MouseDrag, payload: Rc, - cx: &mut EventContext, - render: Rc) -> ElementBox>, + cx: &mut ViewContext, + render: Rc) -> ElementBox>, ) { let window_id = cx.window_id(); cx.update_global(|this: &mut Self, cx| { @@ -178,7 +178,7 @@ impl DragAndDrop { }); } - pub fn render(cx: &mut RenderContext) -> Option { + pub fn render(cx: &mut ViewContext) -> Option> { enum DraggedElementHandler {} cx.global::() .currently_dragged @@ -202,20 +202,22 @@ impl DragAndDrop { let position = position - region_offset; Some( Overlay::new( - MouseEventHandler::::new(0, cx, |_, cx| { - render(payload, cx) - }) + MouseEventHandler::::new( + 0, + cx, + |_, cx| render(payload, cx), + ) .with_cursor_style(CursorStyle::Arrow) - .on_up(MouseButton::Left, |_, cx| { - cx.defer(|cx| { + .on_up(MouseButton::Left, |_, _, cx| { + cx.defer(|_, cx| { cx.update_global::(|this, cx| { this.finish_dragging(cx) }); }); cx.propagate_event(); }) - .on_up_out(MouseButton::Left, |_, cx| { - cx.defer(|cx| { + .on_up_out(MouseButton::Left, |_, _, cx| { + cx.defer(|_, cx| { cx.update_global::(|this, cx| { this.finish_dragging(cx) }); @@ -234,22 +236,22 @@ impl DragAndDrop { } State::Canceled => Some( - MouseEventHandler::::new(0, cx, |_, _| { + MouseEventHandler::::new(0, cx, |_, _| { Empty::new() .constrained() .with_width(0.) .with_height(0.) .boxed() }) - .on_up(MouseButton::Left, |_, cx| { - cx.defer(|cx| { + .on_up(MouseButton::Left, |_, _, cx| { + cx.defer(|_, cx| { cx.update_global::(|this, _| { this.currently_dragged = None; }); }); }) - .on_up_out(MouseButton::Left, |_, cx| { - cx.defer(|cx| { + .on_up_out(MouseButton::Left, |_, _, cx| { + cx.defer(|_, cx| { cx.update_global::(|this, _| { this.currently_dragged = None; }); @@ -294,32 +296,32 @@ impl DragAndDrop { } } -pub trait Draggable { - fn as_draggable( +pub trait Draggable { + fn as_draggable( self, payload: P, - render: impl 'static + Fn(&P, &mut RenderContext) -> ElementBox, + render: impl 'static + Fn(&P, &mut ViewContext) -> ElementBox, ) -> Self where Self: Sized; } -impl Draggable for MouseEventHandler { - fn as_draggable( +impl Draggable for MouseEventHandler { + fn as_draggable( self, payload: P, - render: impl 'static + Fn(&P, &mut RenderContext) -> ElementBox, + render: impl 'static + Fn(&P, &mut ViewContext) -> ElementBox, ) -> Self where Self: Sized, { let payload = Rc::new(payload); let render = Rc::new(render); - self.on_down(MouseButton::Left, move |e, cx| { + self.on_down(MouseButton::Left, move |e, _, cx| { cx.propagate_event(); DragAndDrop::::drag_started(e, cx); }) - .on_drag(MouseButton::Left, move |e, cx| { + .on_drag(MouseButton::Left, move |e, _, cx| { let payload = payload.clone(); let render = render.clone(); DragAndDrop::::dragging(e, payload, cx, render) diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index cabc3ce3f9..a88c96863b 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::{Anchor, ExcerptId, ExcerptRange, ToPoint as _}; use collections::{Bound, HashMap, HashSet}; -use gpui::{fonts::HighlightStyle, RenderContext, ElementBox}; +use gpui::{fonts::HighlightStyle, ElementBox, ViewContext}; use language::{BufferSnapshot, Chunk, Patch, Point}; use parking_lot::Mutex; use std::{ @@ -81,7 +81,7 @@ pub enum BlockStyle { } pub struct BlockContext<'a, 'b> { - pub cx: &'b mut RenderContext<'a, crate::Editor>, + pub cx: &'b mut ViewContext<'a, crate::Editor>, pub anchor_x: f32, pub scroll_x: f32, pub gutter_width: f32, @@ -933,7 +933,7 @@ impl BlockDisposition { } impl<'a, 'b> Deref for BlockContext<'a, 'b> { - type Target = RenderContext<'a, crate::Editor>; + type Target = ViewContext<'a, crate::Editor>; fn deref(&self) -> &Self::Target { self.cx diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index dd5bb7b053..fba189b709 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -42,7 +42,7 @@ use gpui::{ platform::{CursorStyle, MouseButton}, serde_json::{self, json}, AnyViewHandle, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox, Entity, - ModelHandle, RenderContext, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, + ModelHandle, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; use highlight_matching_bracket::refresh_matching_bracket_highlights; use hover_popover::{hide_hover, HideHover, HoverState}; @@ -721,7 +721,7 @@ impl ContextMenu { &self, cursor_position: DisplayPoint, style: EditorStyle, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> (DisplayPoint, ElementBox) { match self { ContextMenu::Completions(menu) => (cursor_position, menu.render(style, cx)), @@ -774,7 +774,7 @@ impl CompletionsMenu { !self.matches.is_empty() } - fn render(&self, style: EditorStyle, cx: &mut RenderContext) -> ElementBox { + fn render(&self, style: EditorStyle, cx: &mut ViewContext) -> ElementBox { enum CompletionTag {} let completions = self.completions.clone(); @@ -950,7 +950,7 @@ impl CodeActionsMenu { &self, mut cursor_position: DisplayPoint, style: EditorStyle, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> (DisplayPoint, ElementBox) { enum ActionTag {} @@ -2928,7 +2928,7 @@ impl Editor { &self, style: &EditorStyle, active: bool, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Option { if self.available_code_actions.is_some() { enum CodeActions {} @@ -2959,7 +2959,7 @@ impl Editor { gutter_hovered: bool, line_height: f32, gutter_margin: f32, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Vec> { enum FoldIndicators {} @@ -3027,7 +3027,7 @@ impl Editor { &self, cursor_position: DisplayPoint, style: EditorStyle, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Option<(DisplayPoint, ElementBox)> { self.context_menu .as_ref() @@ -6795,7 +6795,7 @@ impl Entity for Editor { } impl View for Editor { - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let style = self.style(cx); let font_changed = self.display_map.update(cx, |map, cx| { map.set_fold_ellipses_color(style.folds.ellipses.text_color); @@ -6804,7 +6804,7 @@ impl View for Editor { if font_changed { let handle = self.handle.clone(); - cx.defer(move |cx| { + cx.defer(move |cx: &mut ViewContext| { if let Some(editor) = handle.upgrade(cx) { editor.update(cx, |editor, cx| { hide_hover(editor, &HideHover, cx); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 96d84f59af..59fe561e48 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -31,8 +31,8 @@ use gpui::{ json::{self, ToJson}, platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent}, text_layout::{self, Line, RunStyle, TextLayoutCache}, - AppContext, Axis, Border, CursorRegion, Element, ElementBox, EventContext, LayoutContext, - MouseRegion, PaintContext, Quad, SceneBuilder, SizeConstraint, ViewContext, WeakViewHandle, + AppContext, Axis, Border, CursorRegion, Element, ElementBox, MouseRegion, Quad, SceneBuilder, + SizeConstraint, ViewContext, WeakViewHandle, }; use itertools::Itertools; use json::json; @@ -124,7 +124,7 @@ impl EditorElement { cx: &mut PaintContext, ) { enum EditorElementMouseHandlers {} - cx.scene.push_mouse_region( + scene.push_mouse_region( MouseRegion::new::(view.id(), view.id(), visible_bounds) .on_down(MouseButton::Left, { let position_map = position_map.clone(); @@ -216,7 +216,7 @@ impl EditorElement { ); enum GutterHandlers {} - cx.scene.push_mouse_region( + scene.push_mouse_region( MouseRegion::new::(view.id(), view.id() + 1, gutter_bounds).on_hover( |hover, cx| { cx.dispatch_action(GutterHover { @@ -409,7 +409,7 @@ impl EditorElement { }: MouseMovedEvent, position_map: &PositionMap, text_bounds: RectF, - cx: &mut EventContext, + cx: &mut ViewContext, ) -> bool { // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed // Don't trigger hover popover if mouse is hovering over context menu @@ -432,7 +432,7 @@ impl EditorElement { precise: bool, position_map: &PositionMap, bounds: RectF, - cx: &mut EventContext, + cx: &mut ViewContext, ) -> bool { if !bounds.contains_point(position) { return false; @@ -465,21 +465,22 @@ impl EditorElement { fn paint_background( &self, + scene: &mut SceneBuilder, gutter_bounds: RectF, text_bounds: RectF, layout: &LayoutState, - cx: &mut PaintContext, + cx: &mut ViewContext, ) { let bounds = gutter_bounds.union_rect(text_bounds); let scroll_top = layout.position_map.snapshot.scroll_position().y() * layout.position_map.line_height; - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: gutter_bounds, background: Some(self.style.gutter_background), border: Border::new(0., Color::transparent_black()), corner_radius: 0., }); - cx.scene.push_quad(Quad { + c.push_quad(Quad { bounds: text_bounds, background: Some(self.style.background), border: Border::new(0., Color::transparent_black()), @@ -507,7 +508,7 @@ impl EditorElement { bounds.width(), layout.position_map.line_height * (end_row - start_row + 1) as f32, ); - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: RectF::new(origin, size), background: Some(self.style.active_line_background), border: Border::default(), @@ -527,7 +528,7 @@ impl EditorElement { bounds.width(), layout.position_map.line_height * highlighted_rows.len() as f32, ); - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: RectF::new(origin, size), background: Some(self.style.highlighted_line_background), border: Border::default(), @@ -539,9 +540,11 @@ impl EditorElement { fn paint_gutter( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, layout: &mut LayoutState, + editor: &mut Editor, cx: &mut PaintContext, ) { let line_height = layout.position_map.line_height; @@ -569,7 +572,7 @@ impl EditorElement { ix as f32 * line_height - (scroll_top % line_height), ); - line.paint(line_origin, visible_bounds, line_height, cx); + line.paint(scene, line_origin, visible_bounds, line_height, cx); } } @@ -586,7 +589,7 @@ impl EditorElement { let indicator_origin = bounds.origin() + position + centering_offset; - indicator.paint(indicator_origin, visible_bounds, cx); + indicator.paint(scene, indicator_origin, visible_bounds, editor, cx); } } @@ -595,7 +598,13 @@ impl EditorElement { let mut y = *row as f32 * line_height - scroll_top; x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x()) / 2.; y += (line_height - indicator.size().y()) / 2.; - indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, cx); + indicator.paint( + scene, + bounds.origin() + vec2f(x, y), + visible_bounds, + editor, + cx, + ); } } @@ -618,7 +627,7 @@ impl EditorElement { let highlight_size = vec2f(width * 2., end_y - start_y); let highlight_bounds = RectF::new(highlight_origin, highlight_size); - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: highlight_bounds, background: Some(diff_style.modified), border: Border::new(0., Color::transparent_black()), @@ -651,7 +660,7 @@ impl EditorElement { let highlight_size = vec2f(width * 2., end_y - start_y); let highlight_bounds = RectF::new(highlight_origin, highlight_size); - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: highlight_bounds, background: Some(diff_style.deleted), border: Border::new(0., Color::transparent_black()), @@ -673,7 +682,7 @@ impl EditorElement { let highlight_size = vec2f(width * 2., end_y - start_y); let highlight_bounds = RectF::new(highlight_origin, highlight_size); - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: highlight_bounds, background: Some(color), border: Border::new(0., Color::transparent_black()), @@ -684,9 +693,11 @@ impl EditorElement { fn paint_text( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, layout: &mut LayoutState, + editor: &mut Editor, cx: &mut PaintContext, ) { let view = self.view(cx.app); @@ -700,9 +711,9 @@ impl EditorElement { let content_origin = bounds.origin() + vec2f(layout.gutter_margin, 0.); let line_end_overshoot = 0.15 * layout.position_map.line_height; - cx.scene.push_layer(Some(bounds)); + scene.push_layer(Some(bounds)); - cx.scene.push_cursor_region(CursorRegion { + scene.push_cursor_region(CursorRegion { bounds, style: if !view.link_go_to_definition_state.definitions.is_empty() { CursorStyle::PointingHand @@ -715,6 +726,7 @@ impl EditorElement { self.style.folds.ellipses.corner_radius_factor * layout.position_map.line_height; for (id, range, color) in layout.fold_ranges.iter() { self.paint_highlighted_range( + scene, range.clone(), *color, fold_corner_radius, @@ -736,7 +748,7 @@ impl EditorElement { line_end_overshoot, &layout.position_map, ) { - cx.scene.push_cursor_region(CursorRegion { + scene.push_cursor_region(CursorRegion { bounds: bound, style: CursorStyle::PointingHand, }); @@ -747,7 +759,7 @@ impl EditorElement { .to_point(&layout.position_map.snapshot.display_snapshot) .row; - cx.scene.push_mouse_region( + scene.push_mouse_region( MouseRegion::new::(self.view.id(), *id as usize, bound) .on_click(MouseButton::Left, move |_, cx| { cx.dispatch_action(UnfoldAt { buffer_row }) @@ -760,6 +772,7 @@ impl EditorElement { for (range, color) in &layout.highlighted_ranges { self.paint_highlighted_range( + scene, range.clone(), *color, 0., @@ -781,6 +794,7 @@ impl EditorElement { for selection in selections { self.paint_highlighted_range( + scene, selection.range.clone(), selection_style.selection, corner_radius, @@ -858,6 +872,7 @@ impl EditorElement { for (ix, line) in layout.position_map.line_layouts.iter().enumerate() { let row = start_row + ix as u32; line.paint( + scene, content_origin + vec2f( -scroll_left, @@ -870,14 +885,16 @@ impl EditorElement { } } - cx.scene.push_layer(Some(bounds)); - for cursor in cursors { - cursor.paint(content_origin, cx); - } - cx.scene.pop_layer(); + scene.push_layer(Some(bounds)); + + scene.paint_layer(Some(bounds), |scene| { + for cursor in cursors { + cursor.paint(scene, content_origin, cx); + } + }); if let Some((position, context_menu)) = layout.context_menu.as_mut() { - cx.scene.push_stacking_context(None, None); + scene.push_stacking_context(None, None); let cursor_row_layout = &layout.position_map.line_layouts[(position.row() - start_row) as usize]; let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left; @@ -897,16 +914,18 @@ impl EditorElement { } context_menu.paint( + scene, list_origin, RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor + editor, cx, ); - cx.scene.pop_stacking_context(); + scene.pop_stacking_context(); } if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() { - cx.scene.push_stacking_context(None, None); + scene.push_stacking_context(None, None); // This is safe because we check on layout whether the required row is available let hovered_row_layout = @@ -937,8 +956,10 @@ impl EditorElement { } hover_popover.paint( + scene, popover_origin, RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor + editor, cx, ); @@ -957,8 +978,10 @@ impl EditorElement { } hover_popover.paint( + scene, popover_origin, RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor + editor, cx, ); @@ -966,13 +989,19 @@ impl EditorElement { } } - cx.scene.pop_stacking_context(); + scene.pop_stacking_context(); } - cx.scene.pop_layer(); + scene.pop_layer(); } - fn paint_scrollbar(&mut self, bounds: RectF, layout: &mut LayoutState, cx: &mut PaintContext) { + fn paint_scrollbar( + &mut self, + scene: &mut SceneBuilder, + bounds: RectF, + layout: &mut LayoutState, + cx: &mut ViewContext, + ) { enum ScrollbarMouseHandlers {} if layout.mode != EditorMode::Full { return; @@ -1008,13 +1037,13 @@ impl EditorElement { let thumb_bounds = RectF::from_points(vec2f(left, thumb_top), vec2f(right, thumb_bottom)); if layout.show_scrollbars { - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: track_bounds, border: style.track.border, background: style.track.background_color, ..Default::default() }); - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: thumb_bounds, border: style.thumb.border, background: style.thumb.background_color, @@ -1022,11 +1051,11 @@ impl EditorElement { }); } - cx.scene.push_cursor_region(CursorRegion { + scene.push_cursor_region(CursorRegion { bounds: track_bounds, style: CursorStyle::Arrow, }); - cx.scene.push_mouse_region( + scene.push_mouse_region( MouseRegion::new::(view.id(), view.id(), track_bounds) .on_move({ let view = view.clone(); @@ -1088,6 +1117,7 @@ impl EditorElement { #[allow(clippy::too_many_arguments)] fn paint_highlighted_range( &self, + scene: &mut SceneBuilder, range: Range, color: Color, corner_radius: f32, @@ -1097,7 +1127,7 @@ impl EditorElement { scroll_top: f32, scroll_left: f32, bounds: RectF, - cx: &mut PaintContext, + cx: &mut ViewContext, ) { let start_row = layout.visible_display_row_range.start; let end_row = layout.visible_display_row_range.end; @@ -1141,15 +1171,17 @@ impl EditorElement { .collect(), }; - highlighted_range.paint(bounds, cx.scene); + highlighted_range.paint(bounds, scene); } } fn paint_blocks( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, layout: &mut LayoutState, + editor: &mut Editor, cx: &mut PaintContext, ) { let scroll_position = layout.position_map.snapshot.scroll_position(); @@ -1165,7 +1197,9 @@ impl EditorElement { if !matches!(block.style, BlockStyle::Sticky) { origin += vec2f(-scroll_left, 0.); } - block.element.paint(origin, visible_bounds, cx); + block + .element + .paint(scene, origin, visible_bounds, editor, cx); } } @@ -1384,14 +1418,9 @@ impl EditorElement { style: &EditorStyle, line_layouts: &[text_layout::Line], include_root: bool, + editor: &mut Editor, cx: &mut LayoutContext, ) -> (f32, Vec) { - let editor = if let Some(editor) = self.view.upgrade(cx) { - editor - } else { - return Default::default(); - }; - let tooltip_style = cx.global::().theme.tooltip.clone(); let scroll_x = snapshot.scroll_anchor.offset.x(); let (fixed_blocks, non_fixed_blocks) = snapshot @@ -1542,6 +1571,7 @@ impl EditorElement { min: Vector2F::zero(), max: vec2f(width, block.height() as f32 * line_height), }, + editor, cx, ); element @@ -1847,6 +1877,7 @@ impl Element for EditorElement { &style, &line_layouts, include_root, + editor, cx, ); @@ -1924,6 +1955,7 @@ impl Element for EditorElement { (12. * line_height).min((size.y() - line_height) / 2.), ), }, + editor, cx, ); } @@ -1934,6 +1966,7 @@ impl Element for EditorElement { Axis::Vertical, line_height * style.code_actions.vertical_scale, ), + editor, cx, ); } @@ -2014,7 +2047,7 @@ impl Element for EditorElement { cx: &mut PaintContext, ) -> Self::PaintState { let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); - cx.scene.push_layer(Some(visible_bounds)); + scene.push_layer(Some(visible_bounds)); let gutter_bounds = RectF::new(bounds.origin(), layout.gutter_size); let text_bounds = RectF::new( @@ -2033,20 +2066,20 @@ impl Element for EditorElement { cx, ); - self.paint_background(gutter_bounds, text_bounds, layout, cx); + self.paint_background(scene, gutter_bounds, text_bounds, layout, cx); if layout.gutter_size.x() > 0. { - self.paint_gutter(gutter_bounds, visible_bounds, layout, cx); + self.paint_gutter(scene, gutter_bounds, visible_bounds, layout, editor, cx); } - self.paint_text(text_bounds, visible_bounds, layout, cx); + self.paint_text(scene, text_bounds, visible_bounds, layout, editor, cx); - cx.scene.push_layer(Some(bounds)); + scene.push_layer(Some(bounds)); if !layout.blocks.is_empty() { - self.paint_blocks(bounds, visible_bounds, layout, cx); + self.paint_blocks(scene, bounds, visible_bounds, layout, editor, cx); } - self.paint_scrollbar(bounds, layout, cx); - cx.scene.pop_layer(); + self.paint_scrollbar(scene, bounds, layout, cx); + scene.pop_layer(); - cx.scene.pop_layer(); + scene.pop_layer(); } fn rect_for_text_range( @@ -2254,7 +2287,7 @@ impl Cursor { ) } - pub fn paint(&self, origin: Vector2F, cx: &mut PaintContext) { + pub fn paint(&self, scene: &mut SceneBuilder, origin: Vector2F, cx: &mut AppContext) { let bounds = match self.shape { CursorShape::Bar => RectF::new(self.origin + origin, vec2f(2.0, self.line_height)), CursorShape::Block | CursorShape::Hollow => RectF::new( @@ -2269,14 +2302,14 @@ impl Cursor { //Draw background or border quad if matches!(self.shape, CursorShape::Hollow) { - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds, background: None, border: Border::all(1., self.color), corner_radius: 0., }); } else { - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds, background: Some(self.color), border: Default::default(), @@ -2285,7 +2318,7 @@ impl Cursor { } if let Some(block_text) = &self.block_text { - block_text.paint(self.origin + origin, bounds, self.line_height, cx); + block_text.paint(scene, self.origin + origin, bounds, self.line_height, cx); } } diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index 76a7d41e10..23d1328fd4 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -4,7 +4,7 @@ use gpui::{ elements::{Flex, MouseEventHandler, Padding, Text}, impl_internal_actions, platform::{CursorStyle, MouseButton}, - AppContext, Axis, Element, ElementBox, ModelHandle, RenderContext, Task, ViewContext, + AppContext, Axis, Element, ElementBox, ModelHandle, Task, ViewContext, }; use language::{Bias, DiagnosticEntry, DiagnosticSeverity}; use project::{HoverBlock, Project}; @@ -282,7 +282,7 @@ impl HoverState { snapshot: &EditorSnapshot, style: &EditorStyle, visible_rows: Range, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Option<(DisplayPoint, Vec)> { // If there is a diagnostic, position the popovers based on that. // Otherwise use the start of the hover range @@ -323,7 +323,7 @@ pub struct InfoPopover { } impl InfoPopover { - pub fn render(&self, style: &EditorStyle, cx: &mut RenderContext) -> ElementBox { + pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext) -> ElementBox { MouseEventHandler::::new(0, cx, |_, cx| { let mut flex = Flex::new(Axis::Vertical).scrollable::(1, None, cx); flex.extend(self.contents.iter().map(|content| { @@ -378,7 +378,7 @@ pub struct DiagnosticPopover { } impl DiagnosticPopover { - pub fn render(&self, style: &EditorStyle, cx: &mut RenderContext) -> ElementBox { + pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext) -> ElementBox { enum PrimaryDiagnostic {} let mut text_style = style.hover_popover.prose.clone(); diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 0f2a98dfe9..83e1a4d7f6 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -7,8 +7,8 @@ use anyhow::{anyhow, Context, Result}; use collections::HashSet; use futures::future::try_join_all; use gpui::{ - elements::*, geometry::vector::vec2f, AppContext, Entity, ModelHandle, RenderContext, - Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, + elements::*, geometry::vector::vec2f, AppContext, Entity, ModelHandle, Subscription, Task, + View, ViewContext, ViewContext, ViewHandle, WeakViewHandle, }; use language::{ proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point, @@ -1078,7 +1078,7 @@ impl View for CursorPosition { "CursorPosition" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if let Some(position) = self.position { let theme = &cx.global::().theme.workspace.status_bar; let mut text = format!("{},{}", position.row + 1, position.column + 1); diff --git a/crates/feedback/src/deploy_feedback_button.rs b/crates/feedback/src/deploy_feedback_button.rs index 395ac54a61..aa900597d7 100644 --- a/crates/feedback/src/deploy_feedback_button.rs +++ b/crates/feedback/src/deploy_feedback_button.rs @@ -1,7 +1,7 @@ use gpui::{ elements::*, platform::{CursorStyle, MouseButton}, - Entity, RenderContext, View, ViewContext, + Entity, View, ViewContext, }; use settings::Settings; use workspace::{item::ItemHandle, StatusItemView}; @@ -27,7 +27,7 @@ impl View for DeployFeedbackButton { "DeployFeedbackButton" } - fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox { let active = self.active; let theme = cx.global::().theme.clone(); Stack::new() diff --git a/crates/feedback/src/feedback_editor.rs b/crates/feedback/src/feedback_editor.rs index 15334138db..bae006b8c6 100644 --- a/crates/feedback/src/feedback_editor.rs +++ b/crates/feedback/src/feedback_editor.rs @@ -12,8 +12,8 @@ use gpui::{ actions, elements::{ChildView, Flex, Label, ParentElement, Svg}, platform::PromptLevel, - serde_json, AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelHandle, RenderContext, - Task, View, ViewContext, ViewHandle, + serde_json, AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelHandle, Task, View, + ViewContext, ViewContext, ViewHandle, }; use isahc::Request; use language::Buffer; @@ -232,7 +232,7 @@ impl View for FeedbackEditor { "FeedbackEditor" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.editor, cx).boxed() } diff --git a/crates/feedback/src/feedback_info_text.rs b/crates/feedback/src/feedback_info_text.rs index afa9bd8fc1..fe1a4bc82c 100644 --- a/crates/feedback/src/feedback_info_text.rs +++ b/crates/feedback/src/feedback_info_text.rs @@ -1,7 +1,7 @@ use gpui::{ elements::{Flex, Label, MouseEventHandler, ParentElement, Text}, platform::{CursorStyle, MouseButton}, - Element, ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle, + Element, ElementBox, Entity, View, ViewContext, ViewHandle, }; use settings::Settings; use workspace::{item::ItemHandle, ToolbarItemLocation, ToolbarItemView}; @@ -29,7 +29,7 @@ impl View for FeedbackInfoText { "FeedbackInfoText" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); Flex::row() diff --git a/crates/feedback/src/submit_feedback_button.rs b/crates/feedback/src/submit_feedback_button.rs index 23f5885cb6..720f032c4d 100644 --- a/crates/feedback/src/submit_feedback_button.rs +++ b/crates/feedback/src/submit_feedback_button.rs @@ -1,7 +1,7 @@ use gpui::{ elements::{Label, MouseEventHandler}, platform::{CursorStyle, MouseButton}, - Element, ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle, + Element, ElementBox, Entity, View, ViewContext, ViewHandle, }; use settings::Settings; use workspace::{item::ItemHandle, ToolbarItemLocation, ToolbarItemView}; @@ -29,7 +29,7 @@ impl View for SubmitFeedbackButton { "SubmitFeedbackButton" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); enum SubmitFeedbackButton {} MouseEventHandler::::new(0, cx, |state, _| { diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 8e3490902e..0995578e7c 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -1,7 +1,7 @@ use fuzzy::PathMatch; use gpui::{ - actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, - RenderContext, Task, View, ViewContext, ViewHandle, + actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, Task, View, + ViewContext, ViewHandle, }; use picker::{Picker, PickerDelegate}; use project::{PathMatchCandidateSet, Project, ProjectPath, WorktreeId}; @@ -50,7 +50,7 @@ impl View for FileFinder { "FileFinder" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index 981f222744..af90f6b0c9 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use editor::{display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, DisplayPoint, Editor}; use gpui::{ actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, AppContext, Axis, Entity, - RenderContext, View, ViewContext, ViewHandle, + View, ViewContext, ViewHandle, }; use menu::{Cancel, Confirm}; use settings::Settings; @@ -156,7 +156,7 @@ impl View for GoToLine { "GoToLine" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = &cx.global::().theme.picker; let label = format!( diff --git a/crates/gpui/examples/text.rs b/crates/gpui/examples/text.rs index e16ac440fd..fa14dc2b0a 100644 --- a/crates/gpui/examples/text.rs +++ b/crates/gpui/examples/text.rs @@ -2,7 +2,7 @@ use gpui::{ color::Color, fonts::{Properties, Weight}, text_layout::RunStyle, - DebugContext, Element as _, MeasurementContext, Quad, + Element, ElementBox, Quad, SceneBuilder, View, ViewContext, }; use log::LevelFilter; use pathfinder_geometry::rect::RectF; @@ -30,12 +30,12 @@ impl gpui::View for TextView { "View" } - fn render(&mut self, _: &mut gpui::RenderContext) -> gpui::ElementBox { + fn render(&mut self, _: &mut gpui::ViewContext) -> ElementBox { TextElement.boxed() } } -impl gpui::Element for TextElement { +impl Element for TextElement { type LayoutState = (); type PaintState = (); @@ -43,17 +43,20 @@ impl gpui::Element for TextElement { fn layout( &mut self, constraint: gpui::SizeConstraint, - _: &mut gpui::LayoutContext, + _: &mut V, + _: &mut ViewContext, ) -> (pathfinder_geometry::vector::Vector2F, Self::LayoutState) { (constraint.max, ()) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut gpui::PaintContext, + _: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { let font_size = 12.; let family = cx @@ -84,7 +87,7 @@ impl gpui::Element for TextElement { }; let text = "Hello world!"; - let line = cx.text_layout_cache.layout_str( + let line = cx.text_layout_cache().layout_str( text, font_size, &[ @@ -96,12 +99,12 @@ impl gpui::Element for TextElement { ], ); - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds, background: Some(Color::white()), ..Default::default() }); - line.paint(bounds.origin(), visible_bounds, bounds.height(), cx); + line.paint(scene, bounds.origin(), visible_bounds, bounds.height(), cx); } fn rect_for_text_range( @@ -111,7 +114,8 @@ impl gpui::Element for TextElement { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &V, + _: &ViewContext, ) -> Option { None } @@ -121,7 +125,8 @@ impl gpui::Element for TextElement { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &DebugContext, + _: &V, + _: &ViewContext, ) -> gpui::json::Value { todo!() } diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 70307063e1..f30ab75663 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -69,7 +69,7 @@ pub trait Entity: 'static { pub trait View: Entity + Sized { fn ui_name() -> &'static str; - fn render(&mut self, cx: &mut ViewContext<'_, '_, Self>) -> ElementBox; + fn render(&mut self, cx: &mut ViewContext<'_, '_, '_, Self>) -> ElementBox; 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 { @@ -488,7 +488,7 @@ impl ReadViewWith for AsyncAppContext { } } -type ActionCallback = dyn FnMut(&mut dyn AnyView, &dyn Action, &mut AppContext, usize, usize); +type ActionCallback = dyn FnMut(&mut dyn AnyView, &dyn Action, &mut WindowContext, usize); type GlobalActionCallback = dyn FnMut(&dyn Action, &mut AppContext); type SubscriptionCallback = Box bool>; @@ -725,11 +725,10 @@ impl AppContext { let handler = Box::new( move |view: &mut dyn AnyView, action: &dyn Action, - cx: &mut AppContext, - window_id: usize, + cx: &mut WindowContext, view_id: usize| { let action = action.as_any().downcast_ref().unwrap(); - let mut cx = ViewContext::new(cx, view_id); + let mut cx = ViewContext::mutable(cx, view_id); handler( view.as_any_mut() .downcast_mut() @@ -842,6 +841,12 @@ impl AppContext { } } + fn focused_view_id(&self, window_id: usize) -> Option { + self.windows + .get(&window_id) + .and_then(|window| window.focused_view_id) + } + pub fn is_child_focused(&self, view: &AnyViewHandle) -> bool { if let Some(focused_view_id) = self.focused_view_id(view.window_id) { self.ancestors(view.window_id, focused_view_id) @@ -858,57 +863,59 @@ impl AppContext { self.active_labeled_tasks.values().cloned() } - // pub fn render_view(&mut self, params: RenderParams) -> Result> { - // let window_id = params.window_id; - // let view_id = params.view_id; - // let mut view = self - // .views - // .remove(&(window_id, view_id)) - // .ok_or_else(|| anyhow!("view not found"))?; - // let element = view.render(params, self); - // self.views.insert((window_id, view_id), view); - // Ok(element) - // } + pub fn render_view(&mut self, params: RenderParams) -> Result> { + todo!() + // let window_id = params.window_id; + // let view_id = params.view_id; + // let mut view = self + // .views + // .remove(&(window_id, view_id)) + // .ok_or_else(|| anyhow!("view not found"))?; + // let element = view.render(params, self); + // self.views.insert((window_id, view_id), view); + // Ok(element) + } - // pub fn render_views( - // &mut self, - // window_id: usize, - // titlebar_height: f32, - // appearance: Appearance, - // ) -> HashMap { - // self.start_frame(); - // #[allow(clippy::needless_collect)] - // let view_ids = self - // .views - // .keys() - // .filter_map(|(win_id, view_id)| { - // if *win_id == window_id { - // Some(*view_id) - // } else { - // None - // } - // }) - // .collect::>(); + pub fn render_views( + &mut self, + window_id: usize, + titlebar_height: f32, + appearance: Appearance, + ) -> HashMap> { + todo!() + // self.start_frame(); + // #[allow(clippy::needless_collect)] + // let view_ids = self + // .views + // .keys() + // .filter_map(|(win_id, view_id)| { + // if *win_id == window_id { + // Some(*view_id) + // } else { + // None + // } + // }) + // .collect::>(); - // view_ids - // .into_iter() - // .map(|view_id| { - // ( - // view_id, - // self.render_view(RenderParams { - // window_id, - // view_id, - // titlebar_height, - // hovered_region_ids: Default::default(), - // clicked_region_ids: None, - // refreshing: false, - // appearance, - // }) - // .unwrap(), - // ) - // }) - // .collect() - // } + // view_ids + // .into_iter() + // .map(|view_id| { + // ( + // view_id, + // self.render_view(RenderParams { + // window_id, + // view_id, + // titlebar_height, + // hovered_region_ids: Default::default(), + // clicked_region_ids: None, + // refreshing: false, + // appearance, + // }) + // .unwrap(), + // ) + // }) + // .collect() + } pub(crate) fn start_frame(&mut self) { self.frame_count += 1; @@ -932,6 +939,7 @@ impl AppContext { app_context, window: &mut window, window_id, + refreshing: false, }; let result = callback(&mut window_context); @@ -1510,25 +1518,22 @@ impl AppContext { }) } - pub fn add_window( + pub fn add_window( &mut self, window_options: WindowOptions, build_root_view: F, - ) -> (usize, ViewHandle) + ) -> (usize, ViewHandle) where - T: View, - F: FnOnce(&mut ViewContext) -> T, + V: View, + F: FnOnce(&mut ViewContext) -> V, { self.update(|this| { let window_id = post_inc(&mut this.next_window_id); - let root_view = this - .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx))) - .unwrap(); let platform_window = this.platform .open_window(window_id, window_options, this.foreground.clone()); - let window = - this.build_window(window_id, root_view.clone().into_any(), platform_window); + let window = this.build_window(window_id, platform_window, build_root_view); + let root_view = window.root_view().clone().downcast::().unwrap(); this.windows.insert(window_id, window); root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx)); @@ -1537,20 +1542,16 @@ impl AppContext { }) } - pub fn add_status_bar_item(&mut self, build_root_view: F) -> (usize, ViewHandle) + pub fn add_status_bar_item(&mut self, build_root_view: F) -> (usize, ViewHandle) where - T: View, - F: FnOnce(&mut ViewContext) -> T, + V: View, + F: FnOnce(&mut ViewContext) -> V, { self.update(|this| { let window_id = post_inc(&mut this.next_window_id); - let root_view = this - .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx))) - .unwrap(); - let platform_window = this.platform.add_status_item(); - let window = - this.build_window(window_id, root_view.clone().into_any(), platform_window); + let window = this.build_window(window_id, platform_window, build_root_view); + let root_view = window.root_view().clone().downcast::().unwrap(); this.windows.insert(window_id, window); root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx)); @@ -1563,33 +1564,21 @@ impl AppContext { self.remove_window(id); } - pub fn replace_root_view(&mut self, window_id: usize, build_root_view: F) -> ViewHandle - where - T: View, - F: FnOnce(&mut ViewContext) -> T, - { - self.update(|this| { - let root_view = this - .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx))) - .unwrap(); - let window = this.windows.get_mut(&window_id).unwrap(); - window.root_view = root_view.clone().into_any(); - window.focused_view_id = Some(root_view.id()); - root_view - }) - } - pub fn remove_window(&mut self, window_id: usize) { self.windows.remove(&window_id); self.flush_effects(); } - pub fn build_window( + pub fn build_window( &mut self, window_id: usize, - root_view: AnyViewHandle, mut platform_window: Box, - ) -> Window { + build_root_view: F, + ) -> Window + where + V: View, + F: FnOnce(&mut ViewContext) -> V, + { { let mut app = self.upgrade(); @@ -1653,73 +1642,22 @@ impl AppContext { window_id, })); - let mut window = Window::new(window_id, root_view, platform_window, self); + let mut window = Window::new(window_id, platform_window, self, build_root_view); let scene = WindowContext::new(self, &mut window, window_id).build_scene(); window.platform_window.present_scene(scene); window } - pub fn add_view(&mut self, parent_handle: &AnyViewHandle, build_view: F) -> ViewHandle + pub fn add_view(&mut self, parent: &AnyViewHandle, build_view: F) -> ViewHandle where - T: View, - F: FnOnce(&mut ViewContext) -> T, + S: View, + F: FnOnce(&mut ViewContext) -> S, { - self.build_and_insert_view( - parent_handle.window_id, - ParentId::View(parent_handle.view_id), - |cx| Some(build_view(cx)), - ) - .unwrap() - } - - pub fn add_option_view( - &mut self, - parent_handle: impl Into, - build_view: F, - ) -> Option> - where - T: View, - F: FnOnce(&mut ViewContext) -> Option, - { - let parent_handle = parent_handle.into(); - self.build_and_insert_view( - parent_handle.window_id, - ParentId::View(parent_handle.view_id), - build_view, - ) - } - - pub(crate) fn build_and_insert_view( - &mut self, - window_id: usize, - parent_id: ParentId, - build_view: F, - ) -> Option> - where - T: View, - F: FnOnce(&mut ViewContext) -> Option, - { - self.update(|this| { - let view_id = post_inc(&mut this.next_entity_id); - // Make sure we can tell child views about their parent - this.parents.insert((window_id, view_id), parent_id); - let mut cx = ViewContext::new(this, view_id); - let handle = if let Some(view) = build_view(&mut cx) { - this.views.insert((window_id, view_id), Box::new(view)); - if let Some(window) = this.windows.get_mut(&window_id) { - window - .invalidation - .get_or_insert_with(Default::default) - .updated - .insert(view_id); - } - Some(ViewHandle::new(window_id, view_id, &this.ref_counts)) - } else { - this.parents.remove(&(window_id, view_id)); - None - }; - handle + self.update_window(parent.window_id, |cx| { + cx.build_and_insert_view(ParentId::View(parent.view_id), |cx| Some(build_view(cx))) + .unwrap() }) + .unwrap() } fn remove_dropped_entities(&mut self) { @@ -1754,7 +1692,7 @@ impl AppContext { .removed .push(view_id); if window.focused_view_id == Some(view_id) { - Some(window.root_view.id()) + Some(window.root_view().id()) } else { None } @@ -2174,7 +2112,10 @@ impl AppContext { self.update(|cx| { cx.update_window(window_id, |cx| { - let focused_id = cx.window.focused_view_id?; + let Some(focused_id) = cx.window.focused_view_id else { + return; + }; + for view_id in cx.ancestors(window_id, focused_id).collect::>() { cx.update_any_view(focused_id, |view, cx| { if active { @@ -2254,29 +2195,28 @@ impl AppContext { if let Some(view_id) = view_id { this.halt_action_dispatch = false; this.visit_dispatch_path(window_id, view_id, |view_id, capture_phase, this| { - if let Some(mut view) = this.views.remove(&(window_id, view_id)) { - let type_id = view.as_any().type_id(); - - if let Some((name, mut handlers)) = this - .actions_mut(capture_phase) - .get_mut(&type_id) - .and_then(|h| h.remove_entry(&action.id())) - { - for handler in handlers.iter_mut().rev() { - this.halt_action_dispatch = true; - handler(view.as_mut(), action, this, window_id, view_id); - if this.halt_action_dispatch { - break; - } - } - this.actions_mut(capture_phase) + this.update_window(window_id, |cx| { + cx.update_any_view(view_id, |view, cx| { + let type_id = view.as_any().type_id(); + if let Some((name, mut handlers)) = cx + .actions_mut(capture_phase) .get_mut(&type_id) - .unwrap() - .insert(name, handlers); - } - - this.views.insert((window_id, view_id), view); - } + .and_then(|h| h.remove_entry(&action.id())) + { + for handler in handlers.iter_mut().rev() { + cx.halt_action_dispatch = true; + handler(view, action, cx, view_id); + if cx.halt_action_dispatch { + break; + } + } + cx.actions_mut(capture_phase) + .get_mut(&type_id) + .unwrap() + .insert(name, handlers); + } + }) + }); !this.halt_action_dispatch }); @@ -2523,22 +2463,19 @@ impl UpdateView for AppContext { where T: View, { - self.update(|this| { - let mut view = this - .views - .remove(&(handle.window_id, handle.view_id)) - .expect("circular view update"); - - let mut cx = ViewContext::new(this, handle.view_id); - let result = update( - view.as_any_mut() - .downcast_mut() - .expect("downcast is type safe"), - &mut cx, - ); - this.views.insert((handle.window_id, handle.view_id), view); - result + self.update_window(handle.window_id, |cx| { + cx.update_any_view(handle.view_id, |view, cx| { + let mut cx = ViewContext::mutable(cx, handle.view_id); + update( + view.as_any_mut() + .downcast_mut() + .expect("downcast is type safe"), + &mut cx, + ) + }) + .unwrap() // TODO: Are these unwraps safe? }) + .unwrap() } } @@ -2877,68 +2814,42 @@ pub trait AnyView { cx: &mut AppContext, ) -> Option>>>; fn ui_name(&self) -> &'static str; - fn render<'a, 'b>( - &mut self, - params: RenderParams, - cx: &'b mut WindowContext<'a, 'b>, - ) -> Box; + fn render(&mut self, params: RenderParams, cx: &mut WindowContext) -> Box; fn focus_in<'a, 'b>( &mut self, focused_id: usize, - cx: &'b mut WindowContext<'a, 'b>, + cx: &mut WindowContext<'a, 'b>, view_id: usize, ); - fn focus_out<'a, 'b>( - &mut self, - focused_id: usize, - cx: &'b mut WindowContext<'a, 'b>, - view_id: usize, - ); - fn key_down<'a, 'b>( - &mut self, - event: &KeyDownEvent, - cx: &'b mut WindowContext<'a, 'b>, - view_id: usize, - ) -> bool; - fn key_up<'a, 'b>( - &mut self, - event: &KeyUpEvent, - cx: &'b mut WindowContext<'a, 'b>, - view_id: usize, - ) -> bool; - fn modifiers_changed<'a, 'b>( + fn focus_out(&mut self, focused_id: usize, cx: &mut WindowContext, view_id: usize); + fn key_down(&mut self, event: &KeyDownEvent, cx: &mut WindowContext, view_id: usize) -> bool; + fn key_up(&mut self, event: &KeyUpEvent, cx: &mut WindowContext, view_id: usize) -> bool; + fn modifiers_changed( &mut self, event: &ModifiersChangedEvent, - cx: &'b mut WindowContext<'a, 'b>, + cx: &mut WindowContext, view_id: usize, ) -> bool; - fn keymap_context<'a, 'b>(&self, cx: &'b mut WindowContext<'a, 'b>) -> KeymapContext; - fn debug_json<'a, 'b>(&self, cx: &'b WindowContext<'a, 'b>) -> serde_json::Value; + fn keymap_context(&self, cx: &AppContext) -> KeymapContext; + fn debug_json(&self, cx: &WindowContext) -> serde_json::Value; - fn text_for_range<'a, 'b>( - &self, - range: Range, - cx: &'b mut WindowContext<'a, 'b>, - ) -> Option; - fn selected_text_range<'a, 'b>( - &self, - cx: &'b mut WindowContext<'a, 'b>, - ) -> Option>; - fn marked_text_range<'a, 'b>(&self, cx: &'b mut WindowContext<'a, 'b>) -> Option>; - fn unmark_text<'a, 'b>(&mut self, cx: &'b mut WindowContext<'a, 'b>, view_id: usize); - fn replace_text_in_range<'a, 'b>( + fn text_for_range(&self, range: Range, cx: &WindowContext) -> Option; + fn selected_text_range(&self, cx: &WindowContext) -> Option>; + fn marked_text_range(&self, cx: &WindowContext) -> Option>; + fn unmark_text(&mut self, cx: &mut WindowContext, view_id: usize); + fn replace_text_in_range( &mut self, range: Option>, text: &str, - cx: &'b mut WindowContext<'a, 'b>, + cx: &mut WindowContext, view_id: usize, ); - fn replace_and_mark_text_in_range<'a, 'b>( + fn replace_and_mark_text_in_range( &mut self, range: Option>, new_text: &str, new_selected_range: Option>, - cx: &'b mut WindowContext<'a, 'b>, + cx: &mut WindowContext, view_id: usize, ); fn any_handle(&self, window_id: usize, view_id: usize, cx: &AppContext) -> AnyViewHandle { @@ -2978,21 +2889,13 @@ where T::ui_name() } - fn render<'a, 'b>( - &mut self, - params: RenderParams, - cx: &mut WindowContext<'a, 'b>, - ) -> Box { - View::render(self, &mut ViewContext::new(params, cx)) + fn render(&mut self, params: RenderParams, cx: &mut WindowContext) -> Box { + todo!() + // Box::new(View::render(self, &mut ViewContext::new(params.view_id, cx))) } - fn focus_in<'a, 'b>( - &mut self, - cx: &mut WindowContext<'a, 'b>, - view_id: usize, - focused_id: usize, - ) { - let mut cx = ViewContext::new(cx, view_id); + fn focus_in(&mut self, focused_id: usize, cx: &mut WindowContext, view_id: usize) { + let mut cx = ViewContext::mutable(cx, view_id); let focused_view_handle: AnyViewHandle = if view_id == focused_id { cx.handle().into_any() } else { @@ -3012,13 +2915,8 @@ where View::focus_in(self, focused_view_handle, &mut cx); } - fn focus_out<'a, 'b>( - &mut self, - cx: &mut WindowContext<'a, 'b>, - view_id: usize, - blurred_id: usize, - ) { - let mut cx = ViewContext::new(cx, view_id); + fn focus_out(&mut self, blurred_id: usize, cx: &mut WindowContext, view_id: usize) { + let mut cx = ViewContext::mutable(cx, view_id); let blurred_view_handle: AnyViewHandle = if view_id == blurred_id { cx.handle().into_any() } else { @@ -3038,85 +2936,71 @@ where View::focus_out(self, blurred_view_handle, &mut cx); } - fn key_down<'a, 'b>( - &mut self, - event: &KeyDownEvent, - cx: &mut WindowContext<'a, 'b>, - view_id: usize, - ) -> bool { - let mut cx = ViewContext::new(cx, view_id); + fn key_down(&mut self, event: &KeyDownEvent, cx: &mut WindowContext, view_id: usize) -> bool { + let mut cx = ViewContext::mutable(cx, view_id); View::key_down(self, event, &mut cx) } - fn key_up<'a, 'b>( - &mut self, - event: &KeyUpEvent, - cx: &mut WindowContext<'a, 'b>, - view_id: usize, - ) -> bool { - let mut cx = ViewContext::new(cx, view_id); + fn key_up(&mut self, event: &KeyUpEvent, cx: &mut WindowContext, view_id: usize) -> bool { + let mut cx = ViewContext::mutable(cx, view_id); View::key_up(self, event, &mut cx) } - fn modifiers_changed<'a, 'b>( + fn modifiers_changed( &mut self, event: &ModifiersChangedEvent, - cx: &mut WindowContext<'a, 'b>, + cx: &mut WindowContext, view_id: usize, ) -> bool { - let mut cx = ViewContext::new(cx, view_id); + let mut cx = ViewContext::mutable(cx, view_id); View::modifiers_changed(self, event, &mut cx) } - fn keymap_context<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> KeymapContext { + fn keymap_context(&self, cx: &AppContext) -> KeymapContext { View::keymap_context(self, cx) } - fn debug_json<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> serde_json::Value { + fn debug_json(&self, cx: &WindowContext) -> serde_json::Value { View::debug_json(self, cx) } - fn text_for_range<'a, 'b>( - &self, - range: Range, - cx: &mut WindowContext<'a, 'b>, - ) -> Option { + fn text_for_range(&self, range: Range, cx: &WindowContext) -> Option { View::text_for_range(self, range, cx) } - fn selected_text_range<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> Option> { + fn selected_text_range(&self, cx: &WindowContext) -> Option> { View::selected_text_range(self, cx) } - fn marked_text_range<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> Option> { + fn marked_text_range(&self, cx: &WindowContext) -> Option> { View::marked_text_range(self, cx) } - fn unmark_text<'a, 'b>(&mut self, cx: &mut WindowContext<'a, 'b>, view_id: usize) { - let mut cx = ViewContext::new(cx, view_id); + fn unmark_text(&mut self, cx: &mut WindowContext, view_id: usize) { + let mut cx = ViewContext::mutable(cx, view_id); View::unmark_text(self, &mut cx) } - fn replace_text_in_range<'a, 'b>( + fn replace_text_in_range( &mut self, range: Option>, text: &str, - cx: &mut WindowContext<'a, 'b>, + cx: &mut WindowContext, view_id: usize, ) { - let mut cx = ViewContext::new(cx, view_id); + let mut cx = ViewContext::mutable(cx, view_id); View::replace_text_in_range(self, range, text, &mut cx) } - fn replace_and_mark_text_in_range<'a, 'b>( + fn replace_and_mark_text_in_range( &mut self, range: Option>, new_text: &str, new_selected_range: Option>, - cx: &mut WindowContext<'a, 'b>, + cx: &mut WindowContext, view_id: usize, ) { - let mut cx = ViewContext::new(cx, view_id); + let mut cx = ViewContext::mutable(cx, view_id); View::replace_and_mark_text_in_range(self, range, new_text, new_selected_range, &mut cx) } } @@ -3339,13 +3223,13 @@ impl DerefMut for ModelContext<'_, M> { } } -pub struct ViewContext<'a, 'b, T: ?Sized> { - window_context: WindowContext<'a, 'b>, +pub struct ViewContext<'a, 'b, 'c, T: ?Sized> { + window_context: WindowContextRef<'a, 'b, 'c>, view_id: usize, view_type: PhantomData, } -impl<'a, 'b, T: View> Deref for ViewContext<'a, 'b, T> { +impl<'a, 'b, 'c, T: View> Deref for ViewContext<'a, 'b, 'c, T> { type Target = WindowContext<'a, 'b>; fn deref(&self) -> &Self::Target { @@ -3353,16 +3237,24 @@ impl<'a, 'b, T: View> Deref for ViewContext<'a, 'b, T> { } } -impl<'a, 'b, T: View> DerefMut for ViewContext<'a, 'b, T> { +impl DerefMut for ViewContext<'_, '_, '_, T> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.window_context } } -impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { - fn new(window_context: &'b mut WindowContext<'a, 'b>, view_id: usize) -> Self { +impl<'a, 'b, 'c, V: View> ViewContext<'a, 'b, 'c, V> { + pub(crate) fn mutable(window_context: &'c mut WindowContext<'a, 'b>, view_id: usize) -> Self { Self { - window_context, + window_context: WindowContextRef::Mutable(window_context), + view_id, + view_type: PhantomData, + } + } + + pub(crate) fn immutable(window_context: &'c WindowContext<'a, 'b>, view_id: usize) -> Self { + Self { + window_context: WindowContextRef::Immutable(window_context), view_id, view_type: PhantomData, } @@ -3425,12 +3317,13 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { } pub fn focus_self(&mut self) { - self.window_context - .focus(self.window_id, Some(self.view_id)); + let window_id = self.window_id; + let view_id = self.view_id; + self.window_context.focus(window_id, Some(view_id)); } pub fn is_self_focused(&self) -> bool { - self.window.focused_view == Some(self.view_id) + self.window.focused_view_id == Some(self.view_id) } pub fn is_child(&self, view: impl Into) -> bool { @@ -3444,7 +3337,8 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { } pub fn blur(&mut self) { - self.window_context.focus(self.window_id, None); + let window_id = self.window_id; + self.window_context.focus(window_id, None); } pub fn on_window_should_close(&mut self, mut callback: F) @@ -3466,23 +3360,13 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { }); } - pub fn add_model(&mut self, build_model: F) -> ModelHandle - where - S: Entity, - F: FnOnce(&mut ModelContext) -> S, - { - self.window_context.add_model(build_model) - } - pub fn add_view(&mut self, build_view: F) -> ViewHandle where S: View, F: FnOnce(&mut ViewContext) -> S, { self.window_context - .build_and_insert_view(self.window_id, ParentId::View(self.view_id), |cx| { - Some(build_view(cx)) - }) + .build_and_insert_view(ParentId::View(self.view_id), |cx| Some(build_view(cx))) .unwrap() } @@ -3491,11 +3375,8 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { S: View, F: FnOnce(&mut ViewContext) -> Option, { - self.window_context.build_and_insert_view( - self.window_id, - ParentId::View(self.view_id), - build_view, - ) + self.window_context + .build_and_insert_view(ParentId::View(self.view_id), build_view) } pub fn reparent(&mut self, view_handle: &AnyViewHandle) { @@ -3511,23 +3392,6 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { ); } - pub fn replace_root_view(&mut self, build_root_view: F) -> ViewHandle - where - W: View, - F: FnOnce(&mut ViewContext) -> W, - { - let window_id = self.window_id; - self.update(|this| { - let root_view = this - .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx))) - .unwrap(); - let window = this.windows.get_mut(&window_id).unwrap(); - window.root_view = root_view.clone().into_any(); - window.focused_view_id = Some(root_view.id()); - root_view - }) - } - pub fn subscribe(&mut self, handle: &H, mut callback: F) -> Subscription where E: Entity, @@ -3637,8 +3501,9 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { F: 'static + FnMut(&mut V, bool, &mut ViewContext), { let observer = self.weak_handle(); + let window_id = self.window_id; self.window_context - .observe_window_activation(self.window_id(), move |active, cx| { + .observe_window_activation(window_id, move |active, cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { callback(observer, active, cx); @@ -3655,8 +3520,9 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { F: 'static + FnMut(&mut V, bool, &mut ViewContext), { let observer = self.weak_handle(); + let window_id = self.window_id; self.window_context - .observe_fullscreen(self.window_id(), move |active, cx| { + .observe_fullscreen(window_id, move |active, cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { callback(observer, active, cx); @@ -3680,8 +3546,9 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { ) -> bool, { let observer = self.weak_handle(); + let window_id = self.window_id; self.window_context.observe_keystrokes( - self.window_id(), + window_id, move |keystroke, result, handled_by, cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { @@ -3700,8 +3567,9 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { F: 'static + FnMut(&mut V, WindowBounds, Uuid, &mut ViewContext), { let observer = self.weak_handle(); + let window_id = self.window_id; self.window_context - .observe_window_bounds(self.window_id(), move |bounds, display, cx| { + .observe_window_bounds(window_id, move |bounds, display, cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { callback(observer, bounds, display, cx); @@ -3740,18 +3608,23 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { } pub fn notify(&mut self) { - self.window_context - .notify_view(self.window_id, self.view_id); + let window_id = self.window_id; + let view_id = self.view_id; + self.window_context.notify_view(window_id, view_id); } pub fn dispatch_action(&mut self, action: impl Action) { + let window_id = self.window_id; + let view_id = self.view_id; self.window_context - .dispatch_action_at(self.window_id, self.view_id, action) + .dispatch_action_at(window_id, view_id, action) } pub fn dispatch_any_action(&mut self, action: Box) { + let window_id = self.window_id; + let view_id = self.view_id; self.window_context - .dispatch_any_action_at(self.window_id, self.view_id, action) + .dispatch_any_action_at(window_id, view_id, action) } pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut V, &mut ViewContext)) { @@ -3813,14 +3686,12 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { pub fn mouse_state(&self, region_id: usize) -> MouseState { let region_id = MouseRegionId::new::(self.view_id, region_id); MouseState { - hovered: self.hovered_region_ids.contains(®ion_id), - clicked: self.clicked_region_ids.as_ref().and_then(|(ids, button)| { - if ids.contains(®ion_id) { - Some(*button) - } else { - None - } - }), + hovered: self.window.hovered_region_ids.contains(®ion_id), + clicked: self + .window + .clicked_region_ids + .get(®ion_id) + .and_then(|_| self.window.clicked_button), accessed_hovered: false, accessed_clicked: false, } @@ -3850,7 +3721,7 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { } } -impl UpgradeModelHandle for ViewContext<'_, '_, V> { +impl UpgradeModelHandle for ViewContext<'_, '_, '_, V> { fn upgrade_model_handle( &self, handle: &WeakModelHandle, @@ -3867,7 +3738,7 @@ impl UpgradeModelHandle for ViewContext<'_, '_, V> { } } -impl UpgradeViewHandle for ViewContext<'_, '_, V> { +impl UpgradeViewHandle for ViewContext<'_, '_, '_, V> { fn upgrade_view_handle(&self, handle: &WeakViewHandle) -> Option> { self.window_context.upgrade_view_handle(handle) } @@ -3877,7 +3748,13 @@ impl UpgradeViewHandle for ViewContext<'_, '_, V> { } } -impl UpdateModel for ViewContext<'_, '_, V> { +impl ReadModel for ViewContext<'_, '_, '_, V> { + fn read_model(&self, handle: &ModelHandle) -> &T { + self.window_context.read_model(handle) + } +} + +impl UpdateModel for ViewContext<'_, '_, '_, V> { fn update_model( &mut self, handle: &ModelHandle, @@ -3887,13 +3764,13 @@ impl UpdateModel for ViewContext<'_, '_, V> { } } -impl ReadView for ViewContext<'_, '_, V> { +impl ReadView for ViewContext<'_, '_, '_, V> { fn read_view(&self, handle: &ViewHandle) -> &T { self.window_context.read_view(handle) } } -impl UpdateView for ViewContext<'_, '_, V> { +impl UpdateView for ViewContext<'_, '_, '_, V> { fn update_view( &mut self, handle: &ViewHandle, @@ -3906,6 +3783,33 @@ impl UpdateView for ViewContext<'_, '_, V> { } } +enum WindowContextRef<'a, 'b, 'c> { + Immutable(&'c WindowContext<'a, 'b>), + Mutable(&'c mut WindowContext<'a, 'b>), +} + +impl<'a, 'b, 'c> Deref for WindowContextRef<'a, 'b, 'c> { + type Target = WindowContext<'a, 'b>; + + fn deref(&self) -> &Self::Target { + match self { + WindowContextRef::Immutable(window_context) => window_context, + WindowContextRef::Mutable(window_context) => window_context, + } + } +} + +impl<'a, 'b, 'c> DerefMut for WindowContextRef<'a, 'b, 'c> { + fn deref_mut(&mut self) -> &mut Self::Target { + match self { + WindowContextRef::Immutable(_) => { + panic!("cannot mutably deref an immutable WindowContext. this is a bug in GPUI."); + } + WindowContextRef::Mutable(window_context) => window_context, + } + } +} + pub struct RenderParams { pub window_id: usize, pub view_id: usize, @@ -4686,9 +4590,10 @@ impl ElementStateHandle { .unwrap() } - pub fn update(&self, cx: &mut C, f: impl FnOnce(&mut T, &mut C) -> R) -> R + pub fn update(&self, cx: &mut C, f: impl FnOnce(&mut T, &mut C) -> R) -> R where - C: DerefMut, + C: DerefMut, + D: DerefMut, { let mut element_state = cx.deref_mut().element_states.remove(&self.id).unwrap(); let result = f(element_state.downcast_mut().unwrap(), cx); @@ -5104,8 +5009,8 @@ mod tests { fn render(&mut self, cx: &mut ViewContext) -> ElementBox { enum Handler {} let mouse_down_count = self.mouse_down_count.clone(); - MouseEventHandler::::new(0, cx, |_, _| Empty::new().boxed()) - .on_down(MouseButton::Left, move |_, _| { + MouseEventHandler::::new(0, cx, |_, _| Empty::new().boxed()) + .on_down(MouseButton::Left, move |_, _, _| { mouse_down_count.fetch_add(1, SeqCst); }) .boxed() @@ -5504,8 +5409,8 @@ mod tests { }); view.update(cx, |_, c| { - c.observe(&model, |me, observed, c| { - me.events.push(observed.read(c).state.clone()) + c.observe(&model, |me, observed, cx| { + me.events.push(observed.read(cx).state.clone()) }) .detach(); }); diff --git a/crates/gpui/src/app/menu.rs b/crates/gpui/src/app/menu.rs index 24c8053906..c724f487b8 100644 --- a/crates/gpui/src/app/menu.rs +++ b/crates/gpui/src/app/menu.rs @@ -78,7 +78,11 @@ pub(crate) fn setup_menu_handlers(foreground_platform: &dyn ForegroundPlatform, move |action| { let mut cx = cx.borrow_mut(); if let Some(main_window_id) = cx.platform.main_window_id() { - if let Some(view_id) = cx.focused_view_id(main_window_id) { + if let Some(view_id) = cx + .windows + .get(&main_window_id) + .and_then(|w| w.focused_view_id) + { cx.handle_dispatch_action_from_effect(main_window_id, Some(view_id), action); return; } diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index 7816b42ac9..a6624b0a54 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -1,6 +1,5 @@ use std::{ cell::RefCell, - marker::PhantomData, mem, path::PathBuf, rc::Rc, @@ -21,7 +20,7 @@ use crate::{ geometry::vector::Vector2F, keymap_matcher::Keystroke, platform, - platform::{Appearance, Event, InputHandler, KeyDownEvent, Platform}, + platform::{Event, InputHandler, KeyDownEvent, Platform}, Action, AnyViewHandle, AppContext, Entity, FontCache, Handle, ModelContext, ModelHandle, ReadModelWith, ReadViewWith, Task, UpdateModel, UpdateView, View, ViewContext, ViewHandle, WeakHandle, @@ -74,7 +73,7 @@ impl TestAppContext { pub fn dispatch_action(&self, window_id: usize, action: A) { let mut cx = self.cx.borrow_mut(); - if let Some(view_id) = cx.focused_view_id { + if let Some(view_id) = cx.windows.get(&window_id).and_then(|w| w.focused_view_id) { cx.handle_dispatch_action_from_effect(window_id, Some(view_id), &action); } } @@ -149,7 +148,14 @@ impl TestAppContext { } pub fn root_view(&self, window_id: usize) -> Option { - self.cx.borrow().root_view(window_id) + Some( + self.cx + .borrow() + .windows + .get(&window_id)? + .root_view() + .clone(), + ) } pub fn read T>(&self, callback: F) -> T { @@ -172,20 +178,21 @@ impl TestAppContext { F: FnOnce(&mut V, &mut ViewContext) -> T, V: View, { - handle.update(&mut *self.cx.borrow_mut(), |view, cx| { - let mut render_cx = ViewContext { - app: cx, - window_id: handle.window_id(), - view_id: handle.id(), - view_type: PhantomData, - titlebar_height: 0., - hovered_region_ids: Default::default(), - clicked_region_ids: None, - refreshing: false, - appearance: Appearance::Light, - }; - f(view, &mut render_cx) - }) + todo!() + // handle.update(&mut *self.cx.borrow_mut(), |view, cx| { + // let mut render_cx = ViewContext { + // app: cx, + // window_id: handle.window_id(), + // view_id: handle.id(), + // view_type: PhantomData, + // titlebar_height: 0., + // hovered_region_ids: Default::default(), + // clicked_region_ids: None, + // refreshing: false, + // appearance: Appearance::Light, + // }; + // f(view, &mut render_cx) + // }) } pub fn to_async(&self) -> AsyncAppContext { diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index b7a9a0636a..36e0a6bfd2 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -1,6 +1,4 @@ use crate::{ - app::WindowInvalidation, - elements::Element, geometry::rect::RectF, json::{self, ToJson}, keymap_matcher::{Keystroke, MatchResult}, @@ -13,8 +11,9 @@ use crate::{ MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene, }, text_layout::TextLayoutCache, - Action, AnyView, AnyViewHandle, AnyWeakViewHandle, AppContext, ElementBox, MouseRegion, - MouseRegionId, RenderParams, SceneBuilder, View, + util::post_inc, + AnyView, AnyViewHandle, AppContext, Element, ElementBox, MouseRegion, MouseRegionId, ParentId, + RenderParams, SceneBuilder, View, ViewContext, ViewHandle, WindowInvalidation, }; use anyhow::bail; use collections::{HashMap, HashSet}; @@ -30,8 +29,7 @@ use std::ops::{Deref, DerefMut, Range}; use uuid::Uuid; pub struct Window { - window_id: usize, - pub(crate) root_view: AnyViewHandle, + pub(crate) root_view: Option, pub(crate) focused_view_id: Option, pub(crate) is_active: bool, pub(crate) is_fullscreen: bool, @@ -43,27 +41,29 @@ pub struct Window { cursor_regions: Vec, mouse_regions: Vec<(MouseRegion, usize)>, last_mouse_moved_event: Option, - hovered_region_ids: HashSet, - clicked_region_ids: HashSet, - clicked_button: Option, + pub(crate) hovered_region_ids: HashSet, + pub(crate) clicked_region_ids: HashSet, + pub(crate) clicked_button: Option, mouse_position: Vector2F, text_layout_cache: TextLayoutCache, } impl Window { - pub fn new( + pub fn new( window_id: usize, - root_view: AnyViewHandle, platform_window: Box, cx: &mut AppContext, - ) -> Self { - let focused_view_id = Some(root_view.id()); + build_view: F, + ) -> Self + where + F: FnOnce(&mut ViewContext) -> V, + V: View, + { let titlebar_height = platform_window.titlebar_height(); let appearance = platform_window.appearance(); - Self { - window_id, - root_view, - focused_view_id, + let mut window = Self { + root_view: None, + focused_view_id: None, is_active: false, invalidation: None, is_fullscreen: false, @@ -79,15 +79,30 @@ impl Window { mouse_position: vec2f(0., 0.), titlebar_height, appearance, - } + }; + + let mut window_context = WindowContext::new(cx, &mut window, window_id); + let root_view = window_context + .build_and_insert_view(ParentId::Root, |cx| Some(build_view(cx))) + .unwrap(); + window.focused_view_id = Some(root_view.id()); + window.root_view = Some(root_view.into_any()); + window + } + + pub fn root_view(&self) -> &AnyViewHandle { + &self + .root_view + .as_ref() + .expect("root_view called during window construction") } } pub struct WindowContext<'a: 'b, 'b> { - app_context: &'a mut AppContext, + pub(crate) app_context: &'a mut AppContext, pub(crate) window: &'b mut Window, // TODO: make this private? pub(crate) window_id: usize, - pub refreshing: bool, + pub(crate) refreshing: bool, } impl Deref for WindowContext<'_, '_> { @@ -110,16 +125,30 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { app_context, window, window_id, + refreshing: false, } } - pub fn update_any_view(&mut self, view_id: usize, f: F) -> Option + pub fn window_id(&self) -> usize { + self.window_id + } + + pub fn window_size(&self) -> Vector2F { + self.window.platform_window.content_size() + } + + pub fn text_layout_cache(&self) -> &TextLayoutCache { + &self.window.text_layout_cache + } + + pub(crate) fn update_any_view(&mut self, view_id: usize, f: F) -> Option where F: FnOnce(&mut dyn AnyView, &mut Self) -> T, { - let view = self.views.remove(&(self.window_id, view_id))?; - let result = f(view.as_any_mut(), self); - self.views.insert((self.window_id, view_id), view); + let window_id = self.window_id; + let mut view = self.views.remove(&(window_id, view_id))?; + let result = f(view.as_mut(), self); + self.views.insert((window_id, view_id), view); Some(result) } @@ -453,8 +482,7 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { //3. Fire region events let hovered_region_ids = self.window.hovered_region_ids.clone(); for valid_region in valid_regions.into_iter() { - let mut event_cx = self.build_event_context(&mut notified_views); - + let mut handled = false; mouse_event.set_region(valid_region.bounds); if let MouseEvent::Hover(e) = &mut mouse_event { e.started = hovered_region_ids.contains(&valid_region.id()) @@ -473,25 +501,25 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { .handlers .contains(MouseEvent::down_disc(), Some(e.button)); if !has_down && (has_click || has_drag) { - event_cx.handled = true; + handled = true; } } // `event_consumed` should only be true if there are any handlers for this event. - let mut event_consumed = event_cx.handled; + let mut event_consumed = handled; if let Some(callbacks) = valid_region.handlers.get(&mouse_event.handler_key()) { for callback in callbacks { - 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) + handled = true; + let view_id = valid_region.id().view_id(); + self.update_any_view(view_id, |view, cx| { + handled = callback(mouse_event.clone(), view.as_any_mut(), cx, view_id); }); - event_consumed |= event_cx.handled; - any_event_handled |= event_cx.handled; + event_consumed |= handled; + any_event_handled |= handled; } } - any_event_handled |= event_cx.handled; + any_event_handled |= handled; // For bubbling events, if the event was handled, don't continue dispatching. // This only makes sense for local events which return false from is_capturable. @@ -530,7 +558,7 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { } pub fn dispatch_key_up(&mut self, window_id: usize, event: &KeyUpEvent) -> bool { - if let Some(focused_view_id) = self.window.fo { + if let Some(focused_view_id) = self.window.focused_view_id { for view_id in self .ancestors(window_id, focused_view_id) .collect::>() @@ -645,18 +673,17 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { let window_size = self.window.platform_window.content_size(); let scale_factor = self.window.platform_window.scale_factor(); - let root_view_id = self.window.root_view.id(); - let rendered_root = self.window.rendered_views.remove(&root_view_id).unwrap(); - rendered_root.layout(root_view_id, SizeConstraint::strict(window_size), self); + let root_view_id = self.window.root_view().id(); + let mut rendered_root = self.window.rendered_views.remove(&root_view_id).unwrap(); + rendered_root.layout(SizeConstraint::strict(window_size), self, root_view_id); let mut scene_builder = SceneBuilder::new(scale_factor); - let paint_bounds = RectF::from_points(Vector2F::zero(), window_size); rendered_root.paint( - root_view_id, &mut scene_builder, - paint_bounds, - paint_bounds, + Vector2F::zero(), + RectF::from_points(Vector2F::zero(), window_size), self, + root_view_id, ); self.window.text_layout_cache.finish_frame(); @@ -719,14 +746,6 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { self.window.is_fullscreen } - pub fn root_view(&self, window_id: usize) -> &AnyViewHandle { - &self.window.root_view - } - - pub fn root_view_id(&self) -> usize { - self.window.root_view.id() - } - pub fn focused_view_id(&self) -> Option { self.window.focused_view_id } @@ -739,7 +758,7 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { self.window.platform_window.screen().display_uuid() } - fn show_character_palette(&self) { + pub fn show_character_palette(&self) { self.window.platform_window.show_character_palette(); } @@ -763,47 +782,162 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { ) -> oneshot::Receiver { self.window.platform_window.prompt(level, msg, answers) } + + fn add_view(&mut self, parent: &AnyViewHandle, build_view: F) -> ViewHandle + where + T: View, + F: FnOnce(&mut ViewContext) -> T, + { + if parent.window_id == self.window_id { + self.build_and_insert_view(ParentId::View(parent.view_id), |cx| Some(build_view(cx))) + .unwrap() + } else { + self.app_context.add_view(parent, build_view) + } + } + + fn add_option_view( + &mut self, + parent_handle: impl Into, + build_view: F, + ) -> Option> + where + T: View, + F: FnOnce(&mut ViewContext) -> Option, + { + let parent_handle = parent_handle.into(); + self.build_and_insert_view(ParentId::View(parent_handle.view_id), build_view) + } + + pub fn replace_root_view(&mut self, build_root_view: F) -> ViewHandle + where + V: View, + F: FnOnce(&mut ViewContext) -> V, + { + let root_view = self + .build_and_insert_view(ParentId::Root, |cx| Some(build_root_view(cx))) + .unwrap(); + self.window.root_view = Some(root_view.clone().into_any()); + self.window.focused_view_id = Some(root_view.id()); + root_view + } + + pub(crate) fn build_and_insert_view( + &mut self, + parent_id: ParentId, + build_view: F, + ) -> Option> + where + T: View, + F: FnOnce(&mut ViewContext) -> Option, + { + let window_id = self.window_id; + let view_id = post_inc(&mut self.next_entity_id); + // Make sure we can tell child views about their parentu + self.parents.insert((window_id, view_id), parent_id); + let mut cx = ViewContext::mutable(self, view_id); + let handle = if let Some(view) = build_view(&mut cx) { + self.views.insert((window_id, view_id), Box::new(view)); + self.window + .invalidation + .get_or_insert_with(Default::default) + .updated + .insert(view_id); + Some(ViewHandle::new(window_id, view_id, &self.ref_counts)) + } else { + self.parents.remove(&(window_id, view_id)); + None + }; + handle + } } pub trait RenderedView { fn layout( - &self, - view_id: usize, + &mut self, constraint: SizeConstraint, cx: &mut WindowContext, + view_id: usize, ) -> Vector2F; fn paint( - &self, - view_id: usize, + &mut self, scene: &mut SceneBuilder, - bounds: RectF, + origin: Vector2F, visible_bounds: RectF, cx: &mut WindowContext, + view_id: usize, ); + fn rect_for_text_range( + &self, + range_utf16: Range, + cx: &WindowContext, + view_id: usize, + ) -> Option; + fn debug(&self, cx: &WindowContext, view_id: usize) -> serde_json::Value; + fn name(&self) -> Option<&str>; } impl RenderedView for ElementBox { fn layout( - &self, - view_id: usize, + &mut self, constraint: SizeConstraint, cx: &mut WindowContext, + view_id: usize, ) -> Vector2F { - cx.update_view_for_id(view_id, |view, cx| self.layout(view, constraint, cx)) - .unwrap() + cx.update_any_view(view_id, |view, cx| { + let view = view.as_any_mut().downcast_mut::().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + ElementBox::layout(self, constraint, view, &mut cx) + }) + .unwrap() } fn paint( - &self, - view_id: usize, + &mut self, scene: &mut SceneBuilder, - bounds: RectF, + origin: Vector2F, visible_bounds: RectF, cx: &mut WindowContext, + view_id: usize, ) { - cx.update_view_for_id(view_id, |view, cx| { - self.paint(view, scene, bounds, visible_bounds, cx) - }) + cx.update_any_view(view_id, |view, cx| { + let view = view.as_any_mut().downcast_mut::().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + ElementBox::paint(self, scene, origin, visible_bounds, view, &mut cx) + }); + } + + fn rect_for_text_range( + &self, + range_utf16: Range, + cx: &WindowContext, + view_id: usize, + ) -> Option { + let view = cx + .views + .get(&(cx.window_id, view_id)) + .unwrap() + .as_any() + .downcast_ref::() + .unwrap(); + let cx = ViewContext::immutable(cx, view_id); + ElementBox::rect_for_text_range(self, range_utf16, view, &cx) + } + + fn debug(&self, cx: &WindowContext, view_id: usize) -> serde_json::Value { + let view = cx + .views + .get(&(cx.window_id, view_id)) + .unwrap() + .as_any() + .downcast_ref::() + .unwrap(); + let cx = ViewContext::immutable(cx, view_id); + ElementBox::debug(self, view, &cx) + } + + fn name(&self) -> Option<&str> { + ElementBox::name(self) } } @@ -950,7 +1084,7 @@ impl ToJson for SizeConstraint { } pub struct ChildView { - view: AnyWeakViewHandle, + view_id: usize, view_name: &'static str, } @@ -958,94 +1092,101 @@ impl ChildView { pub fn new(view: &AnyViewHandle, cx: &AppContext) -> Self { let view_name = cx.view_ui_name(view.window_id(), view.id()).unwrap(); Self { - view: view.downgrade(), + view_id: view.id(), view_name, } } } -// impl Element for ChildView { -// type LayoutState = bool; -// type PaintState = (); +impl Element for ChildView { + type LayoutState = (); + type PaintState = (); -// fn layout( -// &mut self, -// constraint: SizeConstraint, -// cx: &mut LayoutContext, -// ) -> (Vector2F, Self::LayoutState) { -// if cx.rendered_views.contains_key(&self.view.id()) { -// let size = cx.layout(self.view.id(), constraint); -// (size, true) -// } else { -// log::error!( -// "layout called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", -// self.view.id(), -// self.view_name -// ); -// (Vector2F::zero(), false) -// } -// } + fn layout( + &mut self, + constraint: SizeConstraint, + _: &mut V, + cx: &mut ViewContext, + ) -> (Vector2F, Self::LayoutState) { + if let Some(mut rendered_view) = cx.window.rendered_views.remove(&self.view_id) { + let size = rendered_view.layout(constraint, cx, self.view_id); + cx.window.rendered_views.insert(self.view_id, rendered_view); + (size, ()) + } else { + log::error!( + "layout called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", + self.view_id, + self.view_name + ); + (Vector2F::zero(), ()) + } + } -// fn paint( -// &mut self, -// bounds: RectF, -// visible_bounds: RectF, -// view_is_valid: &mut Self::LayoutState, -// cx: &mut PaintContext, -// ) { -// if *view_is_valid { -// cx.paint(self.view.id(), bounds.origin(), visible_bounds); -// } else { -// log::error!( -// "paint called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", -// self.view.id(), -// self.view_name -// ); -// } -// } + fn paint( + &mut self, + scene: &mut SceneBuilder, + bounds: RectF, + visible_bounds: RectF, + _: &mut Self::LayoutState, + _: &mut V, + cx: &mut ViewContext, + ) { + if let Some(mut rendered_view) = cx.window.rendered_views.remove(&self.view_id) { + rendered_view.paint(scene, bounds.origin(), visible_bounds, cx, self.view_id); + cx.window.rendered_views.insert(self.view_id, rendered_view); + } else { + log::error!( + "paint called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", + self.view_id, + self.view_name + ); + } + } -// fn rect_for_text_range( -// &self, -// range_utf16: Range, -// _: RectF, -// _: RectF, -// view_is_valid: &Self::LayoutState, -// _: &Self::PaintState, -// cx: &MeasurementContext, -// ) -> Option { -// if *view_is_valid { -// cx.rect_for_text_range(self.view.id(), range_utf16) -// } else { -// log::error!( -// "rect_for_text_range called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", -// self.view.id(), -// self.view_name -// ); -// None -// } -// } + fn rect_for_text_range( + &self, + range_utf16: Range, + _: RectF, + _: RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + _: &V, + cx: &ViewContext, + ) -> Option { + if let Some(rendered_view) = cx.window.rendered_views.get(&self.view_id) { + rendered_view.rect_for_text_range(range_utf16, &cx.window_context, self.view_id) + } else { + log::error!( + "rect_for_text_range called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})", + self.view_id, + self.view_name + ); + None + } + } -// fn debug( -// &self, -// bounds: RectF, -// _: &Self::LayoutState, -// _: &Self::PaintState, -// cx: &DebugContext, -// ) -> serde_json::Value { -// json!({ -// "type": "ChildView", -// "view_id": self.view.id(), -// "bounds": bounds.to_json(), -// "view": if let Some(view) = self.view.upgrade(cx.app) { -// view.debug_json(cx.app) -// } else { -// json!(null) -// }, -// "child": if let Some(view) = cx.rendered_views.get(&self.view.id()) { -// view.debug(cx) -// } else { -// json!(null) -// } -// }) -// } -// } + fn debug( + &self, + bounds: RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + _: &V, + cx: &ViewContext, + ) -> serde_json::Value { + json!({ + "type": "ChildView", + "view_id": self.view_id, + "bounds": bounds.to_json(), + "view": if let Some(view) = cx.views.get(&(cx.window_id, self.view_id)) { + view.debug_json(cx) + } else { + json!(null) + }, + "child": if let Some(element) = cx.window.rendered_views.get(&self.view_id) { + element.debug(&cx.window_context, self.view_id) + } else { + json!(null) + } + }) + } +} diff --git a/crates/gpui/src/app/window_input_handler.rs b/crates/gpui/src/app/window_input_handler.rs index db92dd0b47..938dbe1a03 100644 --- a/crates/gpui/src/app/window_input_handler.rs +++ b/crates/gpui/src/app/window_input_handler.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, ops::Range, rc::Rc}; use pathfinder_geometry::rect::RectF; -use crate::{platform::InputHandler, AnyView, AppContext}; +use crate::{platform::InputHandler, window::WindowContext, AnyView, AppContext}; pub struct WindowInputHandler { pub app: Rc>, @@ -12,7 +12,7 @@ pub struct WindowInputHandler { impl WindowInputHandler { fn read_focused_view(&self, f: F) -> Option where - F: FnOnce(&dyn AnyView, &AppContext) -> T, + F: FnOnce(&dyn AnyView, &WindowContext) -> T, { // Input-related application hooks are sometimes called by the OS during // a call to a window-manipulation API, like prompting the user for file @@ -20,26 +20,26 @@ impl WindowInputHandler { // InputHandler methods need to fail gracefully. // // See https://github.com/zed-industries/community/issues/444 - let app = self.app.try_borrow().ok()?; - - let view_id = app.focused_view_id(self.window_id)?; - let view = app.views.get(&(self.window_id, view_id))?; - let result = f(view.as_ref(), &app); - Some(result) + let mut app = self.app.try_borrow_mut().ok()?; + app.update_window(self.window_id, |cx| { + let view_id = cx.window.focused_view_id?; + let view = cx.views.get(&(self.window_id, view_id))?; + let result = f(view.as_ref(), &cx); + Some(result) + }) + .flatten() } fn update_focused_view(&mut self, f: F) -> Option where - F: FnOnce(usize, usize, &mut dyn AnyView, &mut AppContext) -> T, + F: FnOnce(&mut dyn AnyView, &mut WindowContext, usize) -> T, { let mut app = self.app.try_borrow_mut().ok()?; - app.update(|app| { - let view_id = app.focused_view_id(self.window_id)?; - let mut view = app.views.remove(&(self.window_id, view_id))?; - let result = f(self.window_id, view_id, view.as_mut(), &mut *app); - app.views.insert((self.window_id, view_id), view); - Some(result) + app.update_window(self.window_id, |cx| { + let view_id = cx.window.focused_view_id?; + cx.update_any_view(view_id, |view, cx| f(view, cx, view_id)) }) + .flatten() } } @@ -55,8 +55,8 @@ impl InputHandler for WindowInputHandler { } fn replace_text_in_range(&mut self, range: Option>, text: &str) { - self.update_focused_view(|window_id, view_id, view, cx| { - view.replace_text_in_range(range, text, cx, window_id, view_id); + self.update_focused_view(|view, cx, view_id| { + view.replace_text_in_range(range, text, cx, view_id); }); } @@ -66,8 +66,8 @@ impl InputHandler for WindowInputHandler { } fn unmark_text(&mut self) { - self.update_focused_view(|window_id, view_id, view, cx| { - view.unmark_text(cx, window_id, view_id); + self.update_focused_view(|view, cx, view_id| { + view.unmark_text(cx, view_id); }); } @@ -77,15 +77,8 @@ impl InputHandler for WindowInputHandler { new_text: &str, new_selected_range: Option>, ) { - self.update_focused_view(|window_id, view_id, view, cx| { - view.replace_and_mark_text_in_range( - range, - new_text, - new_selected_range, - cx, - window_id, - view_id, - ); + self.update_focused_view(|view, cx, view_id| { + view.replace_and_mark_text_in_range(range, new_text, new_selected_range, cx, view_id); }); } diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index d23134acaf..f1a5c8dffd 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -35,29 +35,29 @@ use crate::{ }; use core::panic; use json::ToJson; -use std::{any::Any, borrow::Cow, cell::RefCell, marker::PhantomData, mem, ops::Range}; +use std::{any::Any, borrow::Cow, marker::PhantomData, mem, ops::Range}; trait AnyElement { fn layout( &mut self, - view: &mut V, constraint: SizeConstraint, + view: &mut V, cx: &mut ViewContext, ) -> Vector2F; fn paint( &mut self, - view: &mut V, scene: &mut SceneBuilder, origin: Vector2F, visible_bounds: RectF, + view: &mut V, cx: &mut ViewContext, ); fn rect_for_text_range( &self, - view: &V, range_utf16: Range, + view: &V, cx: &ViewContext, ) -> Option; @@ -118,7 +118,8 @@ pub trait Element { Self: 'static + Sized, { ElementBox { - element: RefCell::new(Lifecycle::Init { element: self }), + element: Box::new(Lifecycle::Init { element: self }), + view_type: PhantomData, name: None, } } @@ -128,7 +129,8 @@ pub trait Element { Self: 'static + Sized, { ElementBox { - element: RefCell::new(Lifecycle::Init { element: self }), + element: Box::new(Lifecycle::Init { element: self }), + view_type: PhantomData, name: Some(name.into()), } } @@ -193,7 +195,7 @@ pub trait Element { where Self: 'static + Sized, { - Tooltip::new::(id, text, action, style, self.boxed(), cx) + Tooltip::new::(id, text, action, style, self.boxed(), cx) } fn with_resize_handle( @@ -207,7 +209,7 @@ pub trait Element { where Self: 'static + Sized, { - Resizable::new::( + Resizable::new::( self.boxed(), element_id, side, @@ -242,8 +244,8 @@ pub enum Lifecycle> { impl> AnyElement for Lifecycle { fn layout( &mut self, - view: &mut V, constraint: SizeConstraint, + view: &mut V, cx: &mut ViewContext, ) -> Vector2F { let result; @@ -252,7 +254,7 @@ impl> AnyElement for Lifecycle { Lifecycle::Init { mut element } | Lifecycle::PostLayout { mut element, .. } | Lifecycle::PostPaint { mut element, .. } => { - let (size, layout) = element.layout(view, constraint, cx); + let (size, layout) = element.layout(constraint, view, cx); debug_assert!(size.x().is_finite()); debug_assert!(size.y().is_finite()); @@ -271,9 +273,9 @@ impl> AnyElement for Lifecycle { fn paint( &mut self, scene: &mut SceneBuilder, - view: &mut V, origin: Vector2F, visible_bounds: RectF, + view: &mut V, cx: &mut ViewContext, ) { *self = match mem::take(self) { @@ -321,9 +323,9 @@ impl> AnyElement for Lifecycle { fn rect_for_text_range( &self, - view: &V, range_utf16: Range, - cx: &mut ViewContext, + view: &V, + cx: &ViewContext, ) -> Option { if let Lifecycle::PostPaint { element, @@ -404,41 +406,40 @@ impl> Default for Lifecycle { } pub struct ElementBox { - element: Box>>, + element: Box>, view_type: PhantomData, name: Option>, } impl ElementBox { pub fn name(&self) -> Option<&str> { - self.0.name.as_deref() + self.name.as_deref() } pub fn metadata(&self) -> Option<&T> { - // let element = unsafe { &*self.0.element.as_ptr() }; - // element.metadata().and_then(|m| m.downcast_ref()) + self.element + .metadata() + .and_then(|data| data.downcast_ref::()) } pub fn layout( - &self, + &mut self, constraint: SizeConstraint, view: &mut V, cx: &mut ViewContext, ) -> Vector2F { - self.element.borrow_mut().layout(view, constraint, cx) + self.element.layout(constraint, view, cx) } pub fn paint( - &self, + &mut self, scene: &mut SceneBuilder, origin: Vector2F, visible_bounds: RectF, view: &mut V, cx: &mut ViewContext, ) { - self.element - .borrow_mut() - .paint(view, scene, origin, visible_bounds, cx); + self.element.paint(scene, origin, visible_bounds, view, cx); } pub fn rect_for_text_range( @@ -447,17 +448,15 @@ impl ElementBox { view: &V, cx: &ViewContext, ) -> Option { - self.element - .borrow() - .rect_for_text_range(view, range_utf16, cx) + self.element.rect_for_text_range(range_utf16, view, cx) } pub fn size(&self) -> Vector2F { - self.element.borrow().size() + self.element.size() } pub fn debug(&self, view: &V, cx: &ViewContext) -> json::Value { - let mut value = self.element.borrow().debug(view, cx); + let mut value = self.element.debug(view, cx); if let Some(name) = &self.name { if let json::Value::Object(map) = &mut value { @@ -476,8 +475,7 @@ impl ElementBox { T: 'static, F: FnOnce(Option<&T>) -> R, { - let element = self.element.borrow(); - f(element.metadata().and_then(|m| m.downcast_ref())) + f(self.element.metadata().and_then(|m| m.downcast_ref())) } } diff --git a/crates/gpui/src/elements/align.rs b/crates/gpui/src/elements/align.rs index 8915dc2b4f..9745f0224f 100644 --- a/crates/gpui/src/elements/align.rs +++ b/crates/gpui/src/elements/align.rs @@ -46,13 +46,13 @@ impl Element for Align { fn layout( &mut self, - view: &mut V, mut constraint: SizeConstraint, + view: &mut V, cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.max; constraint.min = Vector2F::zero(); - let child_size = self.child.layout(view, constraint, cx); + let child_size = self.child.layout(constraint, view, cx); if size.x().is_infinite() { size.set_x(child_size.x()); } @@ -64,11 +64,11 @@ impl Element for Align { fn paint( &mut self, - view: &mut V, scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, + view: &mut V, cx: &mut ViewContext, ) -> Self::PaintState { let my_center = bounds.size() / 2.; @@ -78,33 +78,33 @@ impl Element for Align { let child_target = child_center + child_center * self.alignment; self.child.paint( - view, scene, bounds.origin() - (child_target - my_target), visible_bounds, + view, cx, ); } fn rect_for_text_range( &self, - view: &V, range_utf16: std::ops::Range, _: RectF, _: RectF, _: &Self::LayoutState, _: &Self::PaintState, + view: &V, cx: &ViewContext, ) -> Option { - self.child.rect_for_text_range(view, range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn debug( &self, - view: &V, bounds: pathfinder_geometry::rect::RectF, _: &Self::LayoutState, _: &Self::PaintState, + view: &V, cx: &ViewContext, ) -> json::Value { json!({ diff --git a/crates/gpui/src/elements/canvas.rs b/crates/gpui/src/elements/canvas.rs index fb842f92f7..24f180ea97 100644 --- a/crates/gpui/src/elements/canvas.rs +++ b/crates/gpui/src/elements/canvas.rs @@ -25,7 +25,7 @@ where impl Element for Canvas where - F: FnMut(RectF, RectF, &mut ViewContext), + F: FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext), { type LayoutState = (); type PaintState = (); @@ -58,7 +58,7 @@ where view: &mut V, cx: &mut ViewContext, ) -> Self::PaintState { - self.0(bounds, visible_bounds, cx) + self.0(scene, bounds, visible_bounds, view, cx) } fn rect_for_text_range( diff --git a/crates/gpui/src/elements/clipped.rs b/crates/gpui/src/elements/clipped.rs index 96c4f46f22..2a2d69a8ca 100644 --- a/crates/gpui/src/elements/clipped.rs +++ b/crates/gpui/src/elements/clipped.rs @@ -37,10 +37,10 @@ impl Element for Clipped { view: &mut V, cx: &mut ViewContext, ) -> Self::PaintState { - cx.scene.push_layer(Some(bounds)); - self.child - .paint(scene, bounds.origin(), visible_bounds, view, cx); - cx.scene.pop_layer(); + scene.paint_layer(Some(bounds), |scene| { + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx) + }) } fn rect_for_text_range( diff --git a/crates/gpui/src/elements/constrained_box.rs b/crates/gpui/src/elements/constrained_box.rs index 64d78e87a9..4fddd3c534 100644 --- a/crates/gpui/src/elements/constrained_box.rs +++ b/crates/gpui/src/elements/constrained_box.rs @@ -157,7 +157,7 @@ impl Element for ConstrainedBox { view: &mut V, cx: &mut ViewContext, ) -> Self::PaintState { - cx.paint_layer(Some(visible_bounds), |cx| { + scene.paint_layer(Some(visible_bounds), |scene| { self.child .paint(scene, bounds.origin(), visible_bounds, view, cx); }) diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index 5631c01bc0..42183af6b5 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -221,7 +221,7 @@ impl Element for Container { ); if let Some(shadow) = self.style.shadow.as_ref() { - cx.scene.push_shadow(scene::Shadow { + scene.push_shadow(scene::Shadow { bounds: quad_bounds + shadow.offset, corner_radius: self.style.corner_radius, sigma: shadow.blur, @@ -231,7 +231,7 @@ impl Element for Container { if let Some(hit_bounds) = quad_bounds.intersection(visible_bounds) { if let Some(style) = self.style.cursor { - cx.scene.push_cursor_region(CursorRegion { + scene.push_cursor_region(CursorRegion { bounds: hit_bounds, style, }); @@ -242,7 +242,7 @@ impl Element for Container { quad_bounds.origin() + vec2f(self.style.padding.left, self.style.padding.top); if self.style.border.overlay { - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: quad_bounds, background: self.style.background_color, border: Default::default(), @@ -252,16 +252,16 @@ impl Element for Container { self.child .paint(scene, child_origin, visible_bounds, view, cx); - cx.scene.push_layer(None); - cx.scene.push_quad(Quad { + scene.push_layer(None); + scene.push_quad(Quad { bounds: quad_bounds, background: self.style.overlay_color, border: self.style.border, corner_radius: self.style.corner_radius, }); - cx.scene.pop_layer(); + scene.pop_layer(); } else { - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: quad_bounds, background: self.style.background_color, border: self.style.border, @@ -277,14 +277,14 @@ impl Element for Container { .paint(scene, child_origin, visible_bounds, view, cx); if self.style.overlay_color.is_some() { - cx.scene.push_layer(None); - cx.scene.push_quad(Quad { + scene.push_layer(None); + scene.push_quad(Quad { bounds: quad_bounds, background: self.style.overlay_color, border: Default::default(), corner_radius: 0., }); - cx.scene.pop_layer(); + scene.pop_layer(); } } } diff --git a/crates/gpui/src/elements/empty.rs b/crates/gpui/src/elements/empty.rs index 98289128b5..d1a3cbafdb 100644 --- a/crates/gpui/src/elements/empty.rs +++ b/crates/gpui/src/elements/empty.rs @@ -33,7 +33,7 @@ impl Element for Empty { fn layout( &mut self, constraint: SizeConstraint, - _: &V, + _: &mut V, _: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let x = if constraint.max.x().is_finite() && !self.collapsed { @@ -56,6 +56,7 @@ impl Element for Empty { _: RectF, _: RectF, _: &mut Self::LayoutState, + _: &mut V, _: &mut ViewContext, ) -> Self::PaintState { } diff --git a/crates/gpui/src/elements/expanded.rs b/crates/gpui/src/elements/expanded.rs index 186ad0300e..60cf5a9bb9 100644 --- a/crates/gpui/src/elements/expanded.rs +++ b/crates/gpui/src/elements/expanded.rs @@ -42,7 +42,7 @@ impl Element for Expanded { &mut self, mut constraint: SizeConstraint, view: &mut V, - cx: &mut ViewContext, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { if self.full_width { constraint.min.set_x(constraint.max.x()); diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index 31e3f25308..1327ac054d 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -73,7 +73,7 @@ impl Flex { remaining_space: &mut f32, remaining_flex: &mut f32, cross_axis_max: &mut f32, - view: &V, + view: &mut V, cx: &mut ViewContext, ) { let cross_axis = self.axis.invert(); @@ -124,7 +124,7 @@ impl Element for Flex { fn layout( &mut self, constraint: SizeConstraint, - view: &V, + view: &mut V, cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let mut total_flex = None; @@ -253,7 +253,7 @@ impl Element for Flex { bounds: RectF, visible_bounds: RectF, remaining_space: &mut Self::LayoutState, - view: &V, + view: &mut V, cx: &mut ViewContext, ) -> Self::PaintState { let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); @@ -261,16 +261,16 @@ impl Element for Flex { let mut remaining_space = *remaining_space; let overflowing = remaining_space < 0.; if overflowing { - cx.scene.push_layer(Some(visible_bounds)); + scene.push_layer(Some(visible_bounds)); } if let Some(scroll_state) = &self.scroll_state { - cx.scene.push_mouse_region( + scene.push_mouse_region( crate::MouseRegion::new::(scroll_state.1, 0, bounds) .on_scroll({ let scroll_state = scroll_state.0.read(cx).clone(); let axis = self.axis; - move |e, cx| { + move |e, _: &mut V, cx| { if remaining_space < 0. { let scroll_delta = e.delta.raw(); @@ -298,7 +298,7 @@ impl Element for Flex { } } }) - .on_move(|_, _| { /* Capture move events */ }), + .on_move(|_, _: &mut V, _| { /* Capture move events */ }), ) } @@ -356,7 +356,7 @@ impl Element for Flex { } if overflowing { - cx.scene.pop_layer(); + scene.pop_layer(); } } @@ -372,7 +372,7 @@ impl Element for Flex { ) -> Option { self.children .iter() - .find_map(|child| child.rect_for_text_range(view, range_utf16.clone(), cx)) + .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx)) } fn debug( @@ -431,7 +431,7 @@ impl Element for FlexItem { fn layout( &mut self, constraint: SizeConstraint, - view: &V, + view: &mut V, cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let size = self.child.layout(constraint, view, cx); @@ -444,7 +444,7 @@ impl Element for FlexItem { bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - view: &V, + view: &mut V, cx: &mut ViewContext, ) -> Self::PaintState { self.child @@ -474,7 +474,6 @@ impl Element for FlexItem { _: &Self::LayoutState, _: &Self::PaintState, view: &V, - cx: &ViewContext, ) -> Value { json!({ diff --git a/crates/gpui/src/elements/hook.rs b/crates/gpui/src/elements/hook.rs index eec7b3aad3..0a310e6f74 100644 --- a/crates/gpui/src/elements/hook.rs +++ b/crates/gpui/src/elements/hook.rs @@ -35,7 +35,7 @@ impl Element for Hook { fn layout( &mut self, constraint: SizeConstraint, - view: &V, + view: &mut V, cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let size = self.child.layout(constraint, view, cx); diff --git a/crates/gpui/src/elements/image.rs b/crates/gpui/src/elements/image.rs index 479801a50c..162446c1f0 100644 --- a/crates/gpui/src/elements/image.rs +++ b/crates/gpui/src/elements/image.rs @@ -62,7 +62,7 @@ impl Element for Image { fn layout( &mut self, constraint: SizeConstraint, - view: &V, + _: &mut V, cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let data = match &self.source { @@ -94,8 +94,8 @@ impl Element for Image { bounds: RectF, _: RectF, layout: &mut Self::LayoutState, - _: &V, - cx: &mut ViewContext, + _: &mut V, + _: &mut ViewContext, ) -> Self::PaintState { if let Some(data) = layout { scene.push_image(scene::Image { diff --git a/crates/gpui/src/elements/keystroke_label.rs b/crates/gpui/src/elements/keystroke_label.rs index 5727a9f011..3d20930a5d 100644 --- a/crates/gpui/src/elements/keystroke_label.rs +++ b/crates/gpui/src/elements/keystroke_label.rs @@ -41,12 +41,11 @@ impl Element for KeystrokeLabel { fn layout( &mut self, constraint: SizeConstraint, - view: &V, + view: &mut V, cx: &mut ViewContext, ) -> (Vector2F, ElementBox) { let mut element = if let Some(keystrokes) = - cx.app - .keystrokes_for_action(self.window_id, self.view_id, self.action.as_ref()) + cx.keystrokes_for_action(self.window_id, self.view_id, self.action.as_ref()) { Flex::row() .with_children(keystrokes.iter().map(|keystroke| { @@ -70,7 +69,7 @@ impl Element for KeystrokeLabel { bounds: RectF, visible_bounds: RectF, element: &mut ElementBox, - view: &V, + view: &mut V, cx: &mut ViewContext, ) { element.paint(scene, bounds.origin(), visible_bounds, view, cx); diff --git a/crates/gpui/src/elements/label.rs b/crates/gpui/src/elements/label.rs index 2f68967a2f..2669f4d5f2 100644 --- a/crates/gpui/src/elements/label.rs +++ b/crates/gpui/src/elements/label.rs @@ -134,13 +134,15 @@ impl Element for Label { fn layout( &mut self, constraint: SizeConstraint, - view: &V, + _: &mut V, cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let runs = self.compute_runs(); - let line = - cx.text_layout_cache - .layout_str(&self.text, self.style.text.font_size, runs.as_slice()); + let line = cx.text_layout_cache().layout_str( + &self.text, + self.style.text.font_size, + runs.as_slice(), + ); let size = vec2f( line.width() @@ -159,8 +161,8 @@ impl Element for Label { bounds: RectF, visible_bounds: RectF, line: &mut Self::LayoutState, - _: &V, - cx: &mut ViewContext, + _: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { line.paint( scene, diff --git a/crates/gpui/src/elements/list.rs b/crates/gpui/src/elements/list.rs index ef9a202f1a..0cce90d022 100644 --- a/crates/gpui/src/elements/list.rs +++ b/crates/gpui/src/elements/list.rs @@ -13,7 +13,6 @@ pub struct List { state: ListState, } -#[derive(Clone)] pub struct ListState(Rc>>); #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -42,7 +41,7 @@ pub struct ListOffset { enum ListItem { Unrendered, - Rendered(Rc>), + Rendered(Rc>>), Removed(f32), } @@ -145,7 +144,7 @@ impl Element for List { view, cx, ) { - rendered_height += element.size().y(); + rendered_height += element.borrow().size().y(); rendered_items.push_back(ListItem::Rendered(element)); } } @@ -162,7 +161,7 @@ impl Element for List { if let Some(element) = state.render_item(cursor.start().0, None, item_constraint, view, cx) { - rendered_height += element.size().y(); + rendered_height += element.borrow().size().y(); rendered_items.push_front(ListItem::Rendered(element)); } } else { @@ -198,7 +197,7 @@ impl Element for List { if let Some(element) = state.render_item(cursor.start().0, Some(item), item_constraint, view, cx) { - leading_overdraw += element.size().y(); + leading_overdraw += element.borrow().size().y(); rendered_items.push_front(ListItem::Rendered(element)); } } else { @@ -264,12 +263,13 @@ impl Element for List { let state = self.state.clone(); let height = bounds.height(); let scroll_top = scroll_top.clone(); - move |e, cx| { + move |e, view, cx| { state.0.borrow_mut().scroll( &scroll_top, height, *e.platform_event.delta.raw(), e.platform_event.delta.precise(), + view, cx, ) } @@ -277,8 +277,10 @@ impl Element for List { ); let state = &mut *self.state.0.borrow_mut(); - for (mut element, origin) in state.visible_elements(bounds, scroll_top) { - element.paint(scene, origin, visible_bounds, view, cx); + for (element, origin) in state.visible_elements(bounds, scroll_top) { + element + .borrow_mut() + .paint(scene, origin, visible_bounds, view, cx); } scene.pop_layer(); @@ -304,11 +306,15 @@ impl Element for List { } if let ListItem::Rendered(element) = item { - if let Some(rect) = element.rect_for_text_range(range_utf16.clone(), view, cx) { + if let Some(rect) = + element + .borrow() + .rect_for_text_range(range_utf16.clone(), view, cx) + { return Some(rect); } - item_origin.set_y(item_origin.y() + element.size().y()); + item_origin.set_y(item_origin.y() + element.borrow().size().y()); cursor.next(&()); } else { unreachable!(); @@ -329,7 +335,7 @@ impl Element for List { let state = self.state.0.borrow_mut(); let visible_elements = state .visible_elements(bounds, scroll_top) - .map(|e| e.0.debug(view, cx)) + .map(|e| e.0.borrow().debug(view, cx)) .collect::>(); let visible_range = scroll_top.item_ix..(scroll_top.item_ix + visible_elements.len()); json!({ @@ -345,8 +351,7 @@ impl ListState { element_count: usize, orientation: Orientation, overdraw: f32, - cx: &mut ViewContext, - mut render_item: F, + render_item: F, ) -> Self where V: View, @@ -354,14 +359,9 @@ impl ListState { { let mut items = SumTree::new(); items.extend((0..element_count).map(|_| ListItem::Unrendered), &()); - let handle = cx.weak_handle(); Self(Rc::new(RefCell::new(StateInner { last_layout_width: None, - render_item: Box::new(move |ix, view, cx| { - render_item(view, ix, cx) - // let handle = handle.upgrade(cx)?; - // Some(cx.render(&handle, |view, cx| render_item(view, ix, cx))) - }), + render_item: Box::new(render_item), rendered_range: 0..0, items, logical_scroll_top: None, @@ -439,6 +439,12 @@ impl ListState { } } +impl Clone for ListState { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + impl StateInner { fn render_item( &mut self, @@ -447,13 +453,13 @@ impl StateInner { constraint: SizeConstraint, view: &mut V, cx: &mut ViewContext, - ) -> Option>> { + ) -> Option>>> { if let Some(ListItem::Rendered(element)) = existing_element { Some(element.clone()) } else { let mut element = (self.render_item)(view, ix, cx); element.layout(constraint, view, cx); - Some(element.into()) + Some(Rc::new(RefCell::new(element))) } } @@ -469,7 +475,7 @@ impl StateInner { &'a self, bounds: RectF, scroll_top: &ListOffset, - ) -> impl Iterator>, Vector2F)> + 'a { + ) -> impl Iterator>>, Vector2F)> + 'a { let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item); let mut cursor = self.items.cursor::(); cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &()); @@ -481,7 +487,7 @@ impl StateInner { if let ListItem::Rendered(element) = item { let result = (element.clone(), item_origin); - item_origin.set_y(item_origin.y() + element.size().y()); + item_origin.set_y(item_origin.y() + element.borrow().size().y()); cursor.next(&()); return Some(result); } @@ -526,7 +532,7 @@ impl StateInner { if self.scroll_handler.is_some() { let visible_range = self.visible_range(height, scroll_top); - self.scroll_handler.as_mut().unwrap()(visible_range, cx); + self.scroll_handler.as_mut().unwrap()(visible_range, view, cx); } cx.notify(); @@ -557,7 +563,7 @@ impl ListItem { fn remove(&self) -> Self { match self { ListItem::Unrendered => ListItem::Unrendered, - ListItem::Rendered(element) => ListItem::Removed(element.size().y()), + ListItem::Rendered(element) => ListItem::Removed(element.borrow().size().y()), ListItem::Removed(height) => ListItem::Removed(*height), } } @@ -578,7 +584,7 @@ impl sum_tree::Item for ListItem { count: 1, rendered_count: 1, unrendered_count: 0, - height: element.size().y(), + height: element.borrow().size().y(), }, ListItem::Removed(height) => ListItemSummary { count: 1, @@ -642,7 +648,6 @@ mod tests { use super::*; use crate::{elements::Empty, geometry::vector::vec2f, Entity}; use rand::prelude::*; - use std::env; #[crate::test(self)] fn test_layout(cx: &mut crate::AppContext) { diff --git a/crates/gpui/src/elements/mouse_event_handler.rs b/crates/gpui/src/elements/mouse_event_handler.rs index 93515bbc43..c2c53b8b15 100644 --- a/crates/gpui/src/elements/mouse_event_handler.rs +++ b/crates/gpui/src/elements/mouse_event_handler.rs @@ -7,8 +7,8 @@ use crate::{ platform::CursorStyle, platform::MouseButton, scene::{ - CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover, - MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, + CursorRegion, EventContext, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, + MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, }, Element, ElementBox, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View, ViewContext, }; @@ -31,13 +31,13 @@ pub struct MouseEventHandler { /// Element which provides a render_child callback with a MouseState and paints a mouse /// region under (or above) it for easy mouse event handling. impl MouseEventHandler { - pub fn new(region_id: usize, view: &mut V, cx: &mut ViewContext, render_child: F) -> Self + pub fn new(region_id: usize, cx: &mut ViewContext, render_child: F) -> Self where V: View, - F: FnOnce(&mut MouseState, &mut V, &mut ViewContext) -> ElementBox, + F: FnOnce(&mut MouseState, &mut ViewContext) -> ElementBox, { let mut mouse_state = cx.mouse_state::(region_id); - let child = render_child(&mut mouse_state, view, cx); + let child = render_child(&mut mouse_state, cx); let notify_on_hover = mouse_state.accessed_hovered(); let notify_on_click = mouse_state.accessed_clicked(); Self { @@ -57,17 +57,12 @@ impl MouseEventHandler { /// Modifies the MouseEventHandler to render the MouseRegion above the child element. Useful /// for drag and drop handling and similar events which should be captured before the child /// gets the opportunity - pub fn above( - region_id: usize, - view: &mut V, - cx: &mut ViewContext, - render_child: F, - ) -> Self + pub fn above(region_id: usize, cx: &mut ViewContext, render_child: F) -> Self where V: View, - F: FnOnce(&mut MouseState, &mut V, &mut ViewContext) -> ElementBox, + F: FnOnce(&mut MouseState, &mut ViewContext) -> ElementBox, { - let mut handler = Self::new(region_id, view, cx, render_child); + let mut handler = Self::new(region_id, cx, render_child); handler.above = true; handler } @@ -82,14 +77,17 @@ impl MouseEventHandler { self } - pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut ViewContext) + 'static) -> Self { + pub fn on_move( + mut self, + handler: impl Fn(MouseMove, &mut V, &mut EventContext) + 'static, + ) -> Self { self.handlers = self.handlers.on_move(handler); self } pub fn on_move_out( mut self, - handler: impl Fn(MouseMoveOut, &mut ViewContext) + 'static, + handler: impl Fn(MouseMoveOut, &mut V, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_move_out(handler); self @@ -98,7 +96,7 @@ impl MouseEventHandler { pub fn on_down( mut self, button: MouseButton, - handler: impl Fn(MouseDown, &mut ViewContext) + 'static, + handler: impl Fn(MouseDown, &mut V, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_down(button, handler); self @@ -107,7 +105,7 @@ impl MouseEventHandler { pub fn on_up( mut self, button: MouseButton, - handler: impl Fn(MouseUp, &mut ViewContext) + 'static, + handler: impl Fn(MouseUp, &mut V, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_up(button, handler); self @@ -116,7 +114,7 @@ impl MouseEventHandler { pub fn on_click( mut self, button: MouseButton, - handler: impl Fn(MouseClick, &mut ViewContext) + 'static, + handler: impl Fn(MouseClick, &mut V, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_click(button, handler); self @@ -125,7 +123,7 @@ impl MouseEventHandler { pub fn on_down_out( mut self, button: MouseButton, - handler: impl Fn(MouseDownOut, &mut ViewContext) + 'static, + handler: impl Fn(MouseDownOut, &mut V, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_down_out(button, handler); self @@ -134,7 +132,7 @@ impl MouseEventHandler { pub fn on_up_out( mut self, button: MouseButton, - handler: impl Fn(MouseUpOut, &mut ViewContext) + 'static, + handler: impl Fn(MouseUpOut, &mut V, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_up_out(button, handler); self @@ -143,20 +141,23 @@ impl MouseEventHandler { pub fn on_drag( mut self, button: MouseButton, - handler: impl Fn(MouseDrag, &mut ViewContext) + 'static, + handler: impl Fn(MouseDrag, &mut V, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_drag(button, handler); self } - pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut ViewContext) + 'static) -> Self { + pub fn on_hover( + mut self, + handler: impl Fn(MouseHover, &mut V, &mut EventContext) + 'static, + ) -> Self { self.handlers = self.handlers.on_hover(handler); self } pub fn on_scroll( mut self, - handler: impl Fn(MouseScrollWheel, &mut ViewContext) + 'static, + handler: impl Fn(MouseScrollWheel, &mut V, &mut EventContext) + 'static, ) -> Self { self.handlers = self.handlers.on_scroll(handler); self @@ -191,14 +192,14 @@ impl MouseEventHandler { let hit_bounds = self.hit_bounds(visible_bounds); if let Some(style) = self.cursor_style { - cx.scene.push_cursor_region(CursorRegion { + scene.push_cursor_region(CursorRegion { bounds: hit_bounds, style, }); } - cx.scene.push_mouse_region( + scene.push_mouse_region( MouseRegion::from_handlers::( - cx.current_view_id(), + cx.view_id(), self.region_id, hit_bounds, self.handlers.clone(), @@ -236,7 +237,7 @@ impl Element for MouseEventHandler { self.child .paint(scene, bounds.origin(), visible_bounds, view, cx); - cx.paint_layer(None, |cx| { + scene.paint_layer(None, |scene| { self.paint_regions(scene, bounds, visible_bounds, cx); }); } else { @@ -254,7 +255,7 @@ impl Element for MouseEventHandler { _: &Self::LayoutState, _: &Self::PaintState, view: &V, - cx: &ViewContext, + cx: &ViewContext, ) -> Option { self.child.rect_for_text_range(range_utf16, view, cx) } diff --git a/crates/gpui/src/elements/overlay.rs b/crates/gpui/src/elements/overlay.rs index a95667934b..7d9acfc3c5 100644 --- a/crates/gpui/src/elements/overlay.rs +++ b/crates/gpui/src/elements/overlay.rs @@ -127,7 +127,7 @@ impl Element for Overlay { cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let constraint = if self.anchor_position.is_some() { - SizeConstraint::new(Vector2F::zero(), cx.window_size) + SizeConstraint::new(Vector2F::zero(), cx.window_size()) } else { constraint }; @@ -137,7 +137,7 @@ impl Element for Overlay { fn paint( &mut self, - scene: SceneBuilder, + scene: &mut SceneBuilder, bounds: RectF, _: RectF, size: &mut Self::LayoutState, @@ -163,9 +163,9 @@ impl Element for Overlay { OverlayFitMode::SnapToWindow => { // Snap the horizontal edges of the overlay to the horizontal edges of the window if // its horizontal bounds overflow - if bounds.max_x() > cx.window_size.x() { + if bounds.max_x() > cx.window_size().x() { let mut lower_right = bounds.lower_right(); - lower_right.set_x(cx.window_size.x()); + lower_right.set_x(cx.window_size().x()); bounds = RectF::from_points(lower_right - *size, lower_right); } else if bounds.min_x() < 0. { let mut upper_left = bounds.origin(); @@ -175,9 +175,9 @@ impl Element for Overlay { // Snap the vertical edges of the overlay to the vertical edges of the window if // its vertical bounds overflow. - if bounds.max_y() > cx.window_size.y() { + if bounds.max_y() > cx.window_size().y() { let mut lower_right = bounds.lower_right(); - lower_right.set_y(cx.window_size.y()); + lower_right.set_y(cx.window_size().y()); bounds = RectF::from_points(lower_right - *size, lower_right); } else if bounds.min_y() < 0. { let mut upper_left = bounds.origin(); @@ -188,11 +188,11 @@ impl Element for Overlay { OverlayFitMode::SwitchAnchor => { let mut anchor_corner = self.anchor_corner; - if bounds.max_x() > cx.window_size.x() { + if bounds.max_x() > cx.window_size().x() { anchor_corner = anchor_corner.switch_axis(Axis::Horizontal); } - if bounds.max_y() > cx.window_size.y() { + if bounds.max_y() > cx.window_size().y() { anchor_corner = anchor_corner.switch_axis(Axis::Vertical); } @@ -212,22 +212,21 @@ impl Element for Overlay { OverlayFitMode::None => {} } - cx.paint_stacking_context(None, self.z_index, |cx| { + scene.paint_stacking_context(None, self.z_index, |scene| { if self.hoverable { enum OverlayHoverCapture {} // Block hovers in lower stacking contexts - cx.scene - .push_mouse_region(MouseRegion::new::( - cx.current_view_id(), - cx.current_view_id(), - bounds, - )); + scene.push_mouse_region(MouseRegion::new::( + cx.view_id(), + cx.view_id(), + bounds, + )); } self.child.paint( scene, bounds.origin(), - RectF::new(Vector2F::zero(), cx.window_size), + RectF::new(Vector2F::zero(), cx.window_size()), view, cx, ); diff --git a/crates/gpui/src/elements/resizable.rs b/crates/gpui/src/elements/resizable.rs index 33f885bf9b..cdbcedeea1 100644 --- a/crates/gpui/src/elements/resizable.rs +++ b/crates/gpui/src/elements/resizable.rs @@ -154,32 +154,28 @@ impl Element for Resizable { view: &mut V, cx: &mut ViewContext, ) -> Self::PaintState { - cx.scene.push_stacking_context(None, None); + scene.push_stacking_context(None, None); let handle_region = self.side.of_rect(bounds, self.handle_size); enum ResizeHandle {} - cx.scene.push_mouse_region( - MouseRegion::new::( - cx.current_view_id(), - self.side as usize, - handle_region, - ) - .on_down(MouseButton::Left, |_, _| {}) // This prevents the mouse down event from being propagated elsewhere - .on_drag(MouseButton::Left, { - let state = self.state.clone(); - let side = self.side; - move |e, cx| { - let prev_width = state.actual_dimension.get(); - state - .custom_dimension - .set(0f32.max(prev_width + side.compute_delta(e)).round()); - cx.notify(); - } - }), + scene.push_mouse_region( + MouseRegion::new::(cx.view_id(), self.side as usize, handle_region) + .on_down(MouseButton::Left, |_, _: &mut V, _| {}) // This prevents the mouse down event from being propagated elsewhere + .on_drag(MouseButton::Left, { + let state = self.state.clone(); + let side = self.side; + move |e, _: &mut V, cx| { + let prev_width = state.actual_dimension.get(); + state + .custom_dimension + .set(0f32.max(prev_width + side.compute_delta(e)).round()); + cx.notify(); + } + }), ); - cx.scene.push_cursor_region(crate::CursorRegion { + scene.push_cursor_region(crate::CursorRegion { bounds: handle_region, style: match self.side.axis() { Axis::Horizontal => CursorStyle::ResizeLeftRight, @@ -187,7 +183,7 @@ impl Element for Resizable { }, }); - cx.scene.pop_stacking_context(); + scene.pop_stacking_context(); self.child .paint(scene, bounds.origin(), visible_bounds, view, cx); diff --git a/crates/gpui/src/elements/stack.rs b/crates/gpui/src/elements/stack.rs index 175c5182a7..2de7d1433b 100644 --- a/crates/gpui/src/elements/stack.rs +++ b/crates/gpui/src/elements/stack.rs @@ -8,11 +8,18 @@ use crate::{ /// Element which renders it's children in a stack on top of each other. /// The first child determines the size of the others. -#[derive(Default)] pub struct Stack { children: Vec>, } +impl Default for Stack { + fn default() -> Self { + Self { + children: Vec::new(), + } + } +} + impl Stack { pub fn new() -> Self { Self::default() @@ -53,7 +60,7 @@ impl Element for Stack { cx: &mut ViewContext, ) -> Self::PaintState { for child in &mut self.children { - cx.paint_layer(None, |cx| { + scene.paint_layer(None, |scene| { child.paint(scene, bounds.origin(), visible_bounds, view, cx); }); } diff --git a/crates/gpui/src/elements/svg.rs b/crates/gpui/src/elements/svg.rs index ace6af7ffa..0f75be82fd 100644 --- a/crates/gpui/src/elements/svg.rs +++ b/crates/gpui/src/elements/svg.rs @@ -37,7 +37,7 @@ impl Element for Svg { fn layout( &mut self, constraint: SizeConstraint, - view: &mut V, + _: &mut V, cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { match cx.asset_cache.svg(&self.path) { diff --git a/crates/gpui/src/elements/text.rs b/crates/gpui/src/elements/text.rs index 6a6a217aee..927bc3df02 100644 --- a/crates/gpui/src/elements/text.rs +++ b/crates/gpui/src/elements/text.rs @@ -98,7 +98,7 @@ impl Element for Text { let shaped_lines = layout_highlighted_chunks( chunks, &self.style, - cx.text_layout_cache, + cx.text_layout_cache(), &cx.font_cache, usize::MAX, self.text.matches('\n').count() + 1, @@ -213,9 +213,9 @@ impl Element for Text { /// Perform text layout on a series of highlighted chunks of text. pub fn layout_highlighted_chunks<'a>( chunks: impl Iterator)>, - text_style: &'a TextStyle, - text_layout_cache: &'a TextLayoutCache, - font_cache: &'a Arc, + text_style: &TextStyle, + text_layout_cache: &TextLayoutCache, + font_cache: &Arc, max_line_len: usize, max_line_count: usize, ) -> Vec { @@ -276,26 +276,22 @@ pub fn layout_highlighted_chunks<'a>( #[cfg(test)] mod tests { use super::*; - use crate::{ - elements::Empty, fonts, platform, AppContext, ElementBox, Entity, View, ViewContext, - }; + use crate::{elements::Empty, fonts, AppContext, ElementBox, Entity, View, ViewContext}; #[crate::test(self)] fn test_soft_wrapping_with_carriage_returns(cx: &mut AppContext) { let (window_id, root_view) = cx.add_window(Default::default(), |_| TestView); - let mut presenter = cx.build_window( - window_id, - root_view.into_any(), - Box::new(platform::test::Window::new(Vector2F::new(800., 600.))), - ); fonts::with_font_cache(cx.font_cache().clone(), || { - let mut text = Text::new("Hello\r\n", Default::default()).with_soft_wrap(true); - let (_, state) = text.layout( - SizeConstraint::new(Default::default(), vec2f(f32::INFINITY, f32::INFINITY)), - &mut presenter.build_layout_context(Default::default(), false, cx), - ); - assert_eq!(state.shaped_lines.len(), 2); - assert_eq!(state.wrap_boundaries.len(), 2); + root_view.update(cx, |view, cx| { + let mut text = Text::new("Hello\r\n", Default::default()).with_soft_wrap(true); + let (_, state) = text.layout( + SizeConstraint::new(Default::default(), vec2f(f32::INFINITY, f32::INFINITY)), + view, + cx, + ); + assert_eq!(state.shaped_lines.len(), 2); + assert_eq!(state.wrap_boundaries.len(), 2); + }); }); } diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index 39a2a61288..2dff3fd4f9 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -55,7 +55,6 @@ impl Tooltip { action: Option>, style: TooltipStyle, child: ElementBox, - view: &mut V, cx: &mut ViewContext, ) -> Self { struct ElementState(Tag); @@ -78,10 +77,10 @@ impl Tooltip { Overlay::new( Self::render_tooltip(cx.window_id, focused_view_id, text, style, action, false) .constrained() - .dynamically(move |constraint, cx| { + .dynamically(move |constraint, view, cx| { SizeConstraint::strict_along( Axis::Vertical, - collapsed_tooltip.layout(constraint, cx).y(), + collapsed_tooltip.layout(constraint, view, cx).y(), ) }) .boxed(), @@ -93,36 +92,34 @@ impl Tooltip { } else { None }; - let child = - MouseEventHandler::>::new(id, view, cx, |_, _| child) - .on_hover(move |e, cx| { - let position = e.position; - let window_id = cx.window_id(); - if let Some(view_id) = cx.view_id() { - if e.started { - if !state.visible.get() { - state.position.set(position); + let child = MouseEventHandler::, _>::new(id, cx, |_, _| child) + .on_hover(move |e, _, cx| { + let position = e.position; + let window_id = cx.window_id(); + let view_id = cx.view_id(); + if e.started { + if !state.visible.get() { + state.position.set(position); - let mut debounce = state.debounce.borrow_mut(); - if debounce.is_none() { - *debounce = Some(cx.spawn({ - let state = state.clone(); - |mut cx| async move { - cx.background().timer(DEBOUNCE_TIMEOUT).await; - state.visible.set(true); - cx.update(|cx| cx.notify_view(window_id, view_id)); - } - })); + let mut debounce = state.debounce.borrow_mut(); + if debounce.is_none() { + *debounce = Some(cx.spawn({ + let state = state.clone(); + |_, mut cx| async move { + cx.background().timer(DEBOUNCE_TIMEOUT).await; + state.visible.set(true); + cx.update(|cx| cx.notify_view(window_id, view_id)); } - } - } else { - state.visible.set(false); - state.debounce.take(); - cx.notify(); + })); } } - }) - .boxed(); + } else { + state.visible.set(false); + state.debounce.take(); + cx.notify(); + } + }) + .boxed(); Self { child, tooltip, @@ -137,7 +134,7 @@ impl Tooltip { style: TooltipStyle, action: Option>, measure: bool, - ) -> impl Element { + ) -> impl Element { Flex::row() .with_child({ let text = Text::new(text, style.text) @@ -181,7 +178,7 @@ impl Element for Tooltip { let size = self.child.layout(constraint, view, cx); if let Some(tooltip) = self.tooltip.as_mut() { tooltip.layout( - SizeConstraint::new(Vector2F::zero(), cx.window_size), + SizeConstraint::new(Vector2F::zero(), cx.window_size()), view, cx, ); diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index d6eb4f01d1..b0c2e08125 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -6,7 +6,6 @@ use crate::{ }, json::{self, json}, platform::ScrollWheelEvent, - scene::MouseScrollWheel, ElementBox, MouseRegion, SceneBuilder, View, ViewContext, }; use json::ToJson; @@ -47,7 +46,7 @@ pub struct UniformList { state: UniformListState, item_count: usize, #[allow(clippy::type_complexity)] - append_items: Box, &mut Vec>, &mut V, &mut ViewContext)>, + append_items: Box, &mut Vec>, &mut ViewContext)>, padding_top: f32, padding_bottom: f32, get_width_from_item: Option, @@ -63,19 +62,12 @@ impl UniformList { ) -> Self where V: View, - F: 'static + Fn(&mut V, Range, &mut Vec>, &mut V, &mut ViewContext), + F: 'static + Fn(&mut V, Range, &mut Vec>, &mut ViewContext), { - let handle = cx.handle(); Self { state, item_count, - append_items: Box::new(move |range, items, cx| { - if let Some(handle) = handle.upgrade(cx) { - cx.render(&handle, |view, cx| { - append_items(view, range, items, cx); - }); - } - }), + append_items: Box::new(append_items), padding_top: 0., padding_bottom: 0., get_width_from_item: None, @@ -194,18 +186,18 @@ impl Element for UniformList { let sample_item_ix; let sample_item; if let Some(sample_ix) = self.get_width_from_item { - (self.append_items)(sample_ix..sample_ix + 1, &mut items, cx); + (self.append_items)(view, sample_ix..sample_ix + 1, &mut items, cx); sample_item_ix = sample_ix; if let Some(mut item) = items.pop() { - item_size = item.layout(constraint, cx); + item_size = item.layout(constraint, view, cx); size.set_x(item_size.x()); sample_item = item; } else { return no_items; } } else { - (self.append_items)(0..1, &mut items, cx); + (self.append_items)(view, 0..1, &mut items, cx); sample_item_ix = 0; if let Some(mut item) = items.pop() { item_size = item.layout( @@ -213,6 +205,7 @@ impl Element for UniformList { vec2f(constraint.max.x(), 0.0), vec2f(constraint.max.x(), f32::INFINITY), ), + view, cx, ); item_size.set_x(size.x()); @@ -249,16 +242,16 @@ impl Element for UniformList { if (start..end).contains(&sample_item_ix) { if sample_item_ix > start { - (self.append_items)(start..sample_item_ix, &mut items, cx); + (self.append_items)(view, start..sample_item_ix, &mut items, cx); } items.push(sample_item); if sample_item_ix < end { - (self.append_items)(sample_item_ix + 1..end, &mut items, cx); + (self.append_items)(view, sample_item_ix + 1..end, &mut items, cx); } } else { - (self.append_items)(start..end, &mut items, cx); + (self.append_items)(view, start..end, &mut items, cx); } for item in &mut items { @@ -289,20 +282,16 @@ impl Element for UniformList { ) -> Self::PaintState { let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default(); - cx.scene.push_layer(Some(visible_bounds)); + scene.push_layer(Some(visible_bounds)); - cx.scene.push_mouse_region( + scene.push_mouse_region( MouseRegion::new::(self.view_id, 0, visible_bounds).on_scroll({ let scroll_max = layout.scroll_max; let state = self.state.clone(); - move |MouseScrollWheel { - platform_event: - ScrollWheelEvent { - position, delta, .. - }, - .. - }, - cx| { + move |event, _, cx| { + let ScrollWheelEvent { + position, delta, .. + } = event.platform_event; if !Self::scroll( state.clone(), position, @@ -328,7 +317,7 @@ impl Element for UniformList { item_origin += vec2f(0.0, layout.item_height); } - cx.scene.pop_layer(); + scene.pop_layer(); } fn rect_for_text_range( diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 90a4357c5e..235b9c4288 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -15,7 +15,9 @@ pub use clipboard::ClipboardItem; pub mod fonts; pub mod geometry; pub mod scene; -pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder}; +pub use scene::{ + Border, CursorRegion, EventContext, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder, +}; pub mod text_layout; pub use text_layout::TextLayoutCache; mod util; diff --git a/crates/gpui/src/scene.rs b/crates/gpui/src/scene.rs index 032087c95a..96edee1757 100644 --- a/crates/gpui/src/scene.rs +++ b/crates/gpui/src/scene.rs @@ -236,6 +236,19 @@ impl SceneBuilder { self.scale_factor } + pub fn paint_stacking_context( + &mut self, + clip_bounds: Option, + z_index: Option, + f: F, + ) where + F: FnOnce(&mut Self), + { + self.push_stacking_context(clip_bounds, z_index); + f(self); + self.pop_stacking_context(); + } + pub fn push_stacking_context(&mut self, clip_bounds: Option, z_index: Option) { let z_index = z_index.unwrap_or_else(|| self.active_stacking_context().z_index + 1); self.active_stacking_context_stack @@ -249,6 +262,15 @@ impl SceneBuilder { assert!(!self.active_stacking_context_stack.is_empty()); } + pub fn paint_layer(&mut self, clip_bounds: Option, f: F) + where + F: FnOnce(&mut Self), + { + self.push_layer(clip_bounds); + f(self); + self.pop_layer(); + } + pub fn push_layer(&mut self, clip_bounds: Option) { self.active_stacking_context().push_layer(clip_bounds); } diff --git a/crates/gpui/src/scene/mouse_region.rs b/crates/gpui/src/scene/mouse_region.rs index ac945af38a..b3c05c4280 100644 --- a/crates/gpui/src/scene/mouse_region.rs +++ b/crates/gpui/src/scene/mouse_region.rs @@ -1,4 +1,10 @@ -use std::{any::TypeId, fmt::Debug, mem::Discriminant, rc::Rc}; +use std::{ + any::{Any, TypeId}, + fmt::Debug, + mem::Discriminant, + ops::{Deref, DerefMut}, + rc::Rc, +}; use collections::HashMap; @@ -63,7 +69,7 @@ impl MouseRegion { pub fn on_down(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseDown, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseDown, &mut V, &mut EventContext) + 'static, { self.handlers = self.handlers.on_down(button, handler); self @@ -72,7 +78,7 @@ impl MouseRegion { pub fn on_up(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseUp, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseUp, &mut V, &mut EventContext) + 'static, { self.handlers = self.handlers.on_up(button, handler); self @@ -81,7 +87,7 @@ impl MouseRegion { pub fn on_click(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseClick, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseClick, &mut V, &mut EventContext) + 'static, { self.handlers = self.handlers.on_click(button, handler); self @@ -90,7 +96,7 @@ impl MouseRegion { pub fn on_down_out(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseDownOut, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseDownOut, &mut V, &mut EventContext) + 'static, { self.handlers = self.handlers.on_down_out(button, handler); self @@ -99,7 +105,7 @@ impl MouseRegion { pub fn on_up_out(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseUpOut, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseUpOut, &mut V, &mut EventContext) + 'static, { self.handlers = self.handlers.on_up_out(button, handler); self @@ -108,7 +114,7 @@ impl MouseRegion { pub fn on_drag(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseDrag, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseDrag, &mut V, &mut EventContext) + 'static, { self.handlers = self.handlers.on_drag(button, handler); self @@ -117,7 +123,7 @@ impl MouseRegion { pub fn on_hover(mut self, handler: F) -> Self where V: View, - F: Fn(&mut V, &mut ViewContext) + 'static, + F: Fn(MouseHover, &mut V, &mut EventContext) + 'static, { self.handlers = self.handlers.on_hover(handler); self @@ -126,7 +132,7 @@ impl MouseRegion { pub fn on_move(mut self, handler: F) -> Self where V: View, - F: Fn(&mut V, &mut ViewContext) + 'static, + F: Fn(MouseMove, &mut V, &mut EventContext) + 'static, { self.handlers = self.handlers.on_move(handler); self @@ -135,7 +141,7 @@ impl MouseRegion { pub fn on_move_out(mut self, handler: F) -> Self where V: View, - F: Fn(&mut V, &mut ViewContext) + 'static, + F: Fn(MouseMoveOut, &mut V, &mut EventContext) + 'static, { self.handlers = self.handlers.on_move_out(handler); self @@ -144,7 +150,7 @@ impl MouseRegion { pub fn on_scroll(mut self, handler: F) -> Self where V: View, - F: Fn(&mut V, &mut ViewContext) + 'static, + F: Fn(MouseScrollWheel, &mut V, &mut EventContext) + 'static, { self.handlers = self.handlers.on_scroll(handler); self @@ -196,7 +202,39 @@ impl MouseRegionId { } } -pub type HandlerCallback = Rc; +pub struct EventContext<'a, 'b, 'c, 'd, V: View> { + view_context: &'d mut ViewContext<'a, 'b, 'c, V>, + handled: bool, +} + +impl<'a, 'b, 'c, 'd, V: View> EventContext<'a, 'b, 'c, 'd, V> { + fn new(view_context: &'d mut ViewContext<'a, 'b, 'c, V>) -> Self { + EventContext { + view_context, + handled: true, + } + } + + pub fn propagate_event(&mut self) { + self.handled = false; + } +} + +impl<'a, 'b, 'c, 'd, V: View> Deref for EventContext<'a, 'b, 'c, 'd, V> { + type Target = ViewContext<'a, 'b, 'c, V>; + + fn deref(&self) -> &Self::Target { + &self.view_context + } +} + +impl DerefMut for EventContext<'_, '_, '_, '_, V> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.view_context + } +} + +pub type HandlerCallback = Rc bool>; #[derive(Clone, PartialEq, Eq, Hash)] pub struct HandlerKey { @@ -221,41 +259,41 @@ impl HandlerSet { set.insert( HandlerKey::new(MouseEvent::move_disc(), None), - SmallVec::from_buf([Rc::new(|_, _| {})]), + SmallVec::from_buf([Rc::new(|_, _, _, _| false)]), ); set.insert( HandlerKey::new(MouseEvent::hover_disc(), None), - SmallVec::from_buf([Rc::new(|_, _| {})]), + SmallVec::from_buf([Rc::new(|_, _, _, _| false)]), ); for button in MouseButton::all() { set.insert( HandlerKey::new(MouseEvent::drag_disc(), Some(button)), - SmallVec::from_buf([Rc::new(|_, _| {})]), + SmallVec::from_buf([Rc::new(|_, _, _, _| false)]), ); set.insert( HandlerKey::new(MouseEvent::down_disc(), Some(button)), - SmallVec::from_buf([Rc::new(|_, _| {})]), + SmallVec::from_buf([Rc::new(|_, _, _, _| false)]), ); set.insert( HandlerKey::new(MouseEvent::up_disc(), Some(button)), - SmallVec::from_buf([Rc::new(|_, _| {})]), + SmallVec::from_buf([Rc::new(|_, _, _, _| false)]), ); set.insert( HandlerKey::new(MouseEvent::click_disc(), Some(button)), - SmallVec::from_buf([Rc::new(|_, _| {})]), + SmallVec::from_buf([Rc::new(|_, _, _, _| false)]), ); set.insert( HandlerKey::new(MouseEvent::down_out_disc(), Some(button)), - SmallVec::from_buf([Rc::new(|_, _| {})]), + SmallVec::from_buf([Rc::new(|_, _, _, _| false)]), ); set.insert( HandlerKey::new(MouseEvent::up_out_disc(), Some(button)), - SmallVec::from_buf([Rc::new(|_, _| {})]), + SmallVec::from_buf([Rc::new(|_, _, _, _| false)]), ); } set.insert( HandlerKey::new(MouseEvent::scroll_wheel_disc(), None), - SmallVec::from_buf([Rc::new(|_, _| {})]), + SmallVec::from_buf([Rc::new(|_, _, _, _| false)]), ); HandlerSet { set } @@ -296,12 +334,16 @@ impl HandlerSet { pub fn on_move(mut self, handler: F) -> Self where V: View, - F: Fn(MouseMove, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseMove, &mut V, &mut EventContext) + 'static, { self.insert(MouseEvent::move_disc(), None, - Rc::new(move |region_event, cx| { + Rc::new(move |region_event, view, cx, view_id| { if let MouseEvent::Move(e) = region_event { - handler(e, cx); + let view = view.downcast_mut().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + let mut cx = EventContext::new(&mut cx); + handler(e, view, &mut cx); + cx.handled } else { panic!( "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Move, found {:?}", @@ -314,12 +356,16 @@ impl HandlerSet { pub fn on_move_out(mut self, handler: F) -> Self where V: View, - F: Fn(MouseMoveOut, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseMoveOut, &mut V, &mut EventContext) + 'static, { self.insert(MouseEvent::move_out_disc(), None, - Rc::new(move |region_event, cx| { + Rc::new(move |region_event, view, cx, view_id| { if let MouseEvent::MoveOut(e) = region_event { - handler(e, cx); + let view = view.downcast_mut().unwrap(); + let mut cx = ViewContext::::mutable(cx, view_id); + let mut cx = EventContext::new(&mut cx); + handler(e, view, &mut cx); + cx.handled } else { panic!( "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::MoveOut, found {:?}", @@ -332,12 +378,16 @@ impl HandlerSet { pub fn on_down(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseDown, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseDown, &mut V, &mut EventContext) + 'static, { self.insert(MouseEvent::down_disc(), Some(button), - Rc::new(move |region_event, cx| { + Rc::new(move |region_event, view, cx, view_id| { if let MouseEvent::Down(e) = region_event { - handler(e, cx); + let view = view.downcast_mut().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + let mut cx = EventContext::new(&mut cx); + handler(e, view, &mut cx); + cx.handled } else { panic!( "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Down, found {:?}", @@ -350,12 +400,16 @@ impl HandlerSet { pub fn on_up(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseUp, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseUp, &mut V, &mut EventContext) + 'static, { self.insert(MouseEvent::up_disc(), Some(button), - Rc::new(move |region_event, cx| { + Rc::new(move |region_event, view, cx, view_id| { if let MouseEvent::Up(e) = region_event { - handler(e, cx); + let view = view.downcast_mut().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + let mut cx = EventContext::new(&mut cx); + handler(e, view, &mut cx); + cx.handled } else { panic!( "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Up, found {:?}", @@ -368,12 +422,16 @@ impl HandlerSet { pub fn on_click(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseClick, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseClick, &mut V, &mut EventContext) + 'static, { self.insert(MouseEvent::click_disc(), Some(button), - Rc::new(move |region_event, cx| { + Rc::new(move |region_event, view, cx, view_id| { if let MouseEvent::Click(e) = region_event { - handler(e, cx); + let view = view.downcast_mut().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + let mut cx = EventContext::new(&mut cx); + handler(e, view, &mut cx); + cx.handled } else { panic!( "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Click, found {:?}", @@ -386,12 +444,16 @@ impl HandlerSet { pub fn on_down_out(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseDownOut, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseDownOut, &mut V, &mut EventContext) + 'static, { self.insert(MouseEvent::down_out_disc(), Some(button), - Rc::new(move |region_event, cx| { + Rc::new(move |region_event, view, cx, view_id| { if let MouseEvent::DownOut(e) = region_event { - handler(e, cx); + let view = view.downcast_mut().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + let mut cx = EventContext::new(&mut cx); + handler(e, view, &mut cx); + cx.handled } else { panic!( "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::DownOut, found {:?}", @@ -404,12 +466,16 @@ impl HandlerSet { pub fn on_up_out(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseUpOut, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseUpOut, &mut V, &mut EventContext) + 'static, { self.insert(MouseEvent::up_out_disc(), Some(button), - Rc::new(move |region_event, cx| { + Rc::new(move |region_event, view, cx, view_id| { if let MouseEvent::UpOut(e) = region_event { - handler(e, cx); + let view = view.downcast_mut().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + let mut cx = EventContext::new(&mut cx); + handler(e, view, &mut cx); + cx.handled } else { panic!( "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::UpOut, found {:?}", @@ -422,12 +488,16 @@ impl HandlerSet { pub fn on_drag(mut self, button: MouseButton, handler: F) -> Self where V: View, - F: Fn(MouseDrag, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseDrag, &mut V, &mut EventContext) + 'static, { self.insert(MouseEvent::drag_disc(), Some(button), - Rc::new(move |region_event, cx| { + Rc::new(move |region_event, view, cx, view_id| { if let MouseEvent::Drag(e) = region_event { - handler(e, cx); + let view = view.downcast_mut().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + let mut cx = EventContext::new(&mut cx); + handler(e, view, &mut cx); + cx.handled } else { panic!( "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Drag, found {:?}", @@ -440,12 +510,16 @@ impl HandlerSet { pub fn on_hover(mut self, handler: F) -> Self where V: View, - F: Fn(MouseHover, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseHover, &mut V, &mut EventContext) + 'static, { self.insert(MouseEvent::hover_disc(), None, - Rc::new(move |region_event, cx| { + Rc::new(move |region_event, view, cx, view_id| { if let MouseEvent::Hover(e) = region_event { - handler(e, cx); + let view = view.downcast_mut().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + let mut cx = EventContext::new(&mut cx); + handler(e, view, &mut cx); + cx.handled } else { panic!( "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Hover, found {:?}", @@ -458,12 +532,16 @@ impl HandlerSet { pub fn on_scroll(mut self, handler: F) -> Self where V: View, - F: Fn(MouseScrollWheel, &mut V, &mut ViewContext) + 'static, + F: Fn(MouseScrollWheel, &mut V, &mut EventContext) + 'static, { self.insert(MouseEvent::scroll_wheel_disc(), None, - Rc::new(move |region_event, cx| { + Rc::new(move |region_event, view, cx, view_id| { if let MouseEvent::ScrollWheel(e) = region_event { - handler(e, cx); + let view = view.downcast_mut().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + let mut cx = EventContext::new(&mut cx); + handler(e, view, &mut cx); + cx.handled } else { panic!( "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::ScrollWheel, found {:?}", diff --git a/crates/gpui/src/text_layout.rs b/crates/gpui/src/text_layout.rs index 8f1b9190a8..e665859319 100644 --- a/crates/gpui/src/text_layout.rs +++ b/crates/gpui/src/text_layout.rs @@ -273,7 +273,7 @@ impl Line { pub fn paint( &self, - scene: &SceneBuilder, + scene: &mut SceneBuilder, origin: Vector2F, visible_bounds: RectF, line_height: f32, @@ -334,7 +334,7 @@ impl Line { } if let Some((underline_origin, underline_style)) = finished_underline { - cx.scene.push_underline(scene::Underline { + scene.push_underline(scene::Underline { origin: underline_origin, width: glyph_origin.x() - underline_origin.x(), thickness: underline_style.thickness.into(), @@ -344,14 +344,14 @@ impl Line { } if glyph.is_emoji { - cx.scene.push_image_glyph(scene::ImageGlyph { + scene.push_image_glyph(scene::ImageGlyph { font_id: run.font_id, font_size: self.layout.font_size, id: glyph.id, origin: glyph_origin, }); } else { - cx.scene.push_glyph(scene::Glyph { + scene.push_glyph(scene::Glyph { font_id: run.font_id, font_size: self.layout.font_size, id: glyph.id, @@ -364,7 +364,7 @@ impl Line { if let Some((underline_start, underline_style)) = underline.take() { let line_end_x = origin.x() + self.layout.width; - cx.scene.push_underline(scene::Underline { + scene.push_underline(scene::Underline { origin: underline_start, width: line_end_x - underline_start.x(), color: underline_style.color.unwrap(), @@ -376,7 +376,7 @@ impl Line { pub fn paint_wrapped( &self, - scene: &SceneBuilder, + scene: &mut SceneBuilder, origin: Vector2F, visible_bounds: RectF, line_height: f32, diff --git a/crates/gpui/src/views/select.rs b/crates/gpui/src/views/select.rs index 1bfaba4c3b..dba1b8023b 100644 --- a/crates/gpui/src/views/select.rs +++ b/crates/gpui/src/views/select.rs @@ -106,22 +106,17 @@ impl View for Select { Default::default() }; let mut result = Flex::column().with_child( - MouseEventHandler::
::new( - self.handle.id(), - self, - cx, - |mouse_state, this, cx| { - Container::new((self.render_item)( - self.selected_item_ix, - ItemType::Header, - mouse_state.hovered(), - cx, - )) - .with_style(style.header) - .boxed() - }, - ) - .on_click(MouseButton::Left, move |_, cx| { + MouseEventHandler::::new(self.handle.id(), cx, |mouse_state, cx| { + Container::new((self.render_item)( + self.selected_item_ix, + ItemType::Header, + mouse_state.hovered(), + cx, + )) + .with_style(style.header) + .boxed() + }) + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(ToggleSelect) }) .boxed(), @@ -139,11 +134,10 @@ impl View for Select { let selected_item_ix = this.selected_item_ix; range.end = range.end.min(this.item_count); items.extend(range.map(|ix| { - MouseEventHandler::::new( + MouseEventHandler::::new( ix, - self, cx, - |mouse_state, this, cx| { + |mouse_state, cx| { (this.render_item)( ix, if ix == selected_item_ix { @@ -156,7 +150,7 @@ impl View for Select { ) }, ) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(SelectItem(ix)) }) .boxed() diff --git a/crates/language_selector/src/active_buffer_language.rs b/crates/language_selector/src/active_buffer_language.rs index 1beccdca7a..87499664ae 100644 --- a/crates/language_selector/src/active_buffer_language.rs +++ b/crates/language_selector/src/active_buffer_language.rs @@ -2,7 +2,7 @@ use editor::Editor; use gpui::{ elements::*, platform::{CursorStyle, MouseButton}, - Entity, RenderContext, Subscription, View, ViewContext, ViewHandle, + Entity, Subscription, View, ViewContext, ViewHandle, }; use settings::Settings; use std::sync::Arc; @@ -50,7 +50,7 @@ impl View for ActiveBufferLanguage { "ActiveBufferLanguage" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if let Some(active_language) = self.active_language.as_ref() { let active_language_text = if let Some(active_language_text) = active_language { active_language_text.to_string() diff --git a/crates/language_selector/src/language_selector.rs b/crates/language_selector/src/language_selector.rs index b281d621ba..3269fafed0 100644 --- a/crates/language_selector/src/language_selector.rs +++ b/crates/language_selector/src/language_selector.rs @@ -4,8 +4,8 @@ pub use active_buffer_language::ActiveBufferLanguage; use editor::Editor; use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; use gpui::{ - actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, - RenderContext, View, ViewContext, ViewHandle, + actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, View, + ViewContext, ViewHandle, }; use language::{Buffer, LanguageRegistry}; use picker::{Picker, PickerDelegate}; @@ -120,7 +120,7 @@ impl View for LanguageSelector { "LanguageSelector" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index 2259570fa0..c7167b0eb4 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -5,7 +5,7 @@ use editor::{ use fuzzy::StringMatch; use gpui::{ actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, AppContext, Entity, - MouseState, RenderContext, Task, View, ViewContext, ViewHandle, + MouseState, Task, View, ViewContext, ViewHandle, }; use language::Outline; use ordered_float::OrderedFloat; @@ -48,7 +48,7 @@ impl View for OutlineView { "OutlineView" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index b17e61eddd..a5434359bc 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -4,8 +4,8 @@ use gpui::{ geometry::vector::{vec2f, Vector2F}, keymap_matcher::KeymapContext, platform::{CursorStyle, MouseButton}, - AnyViewHandle, AppContext, Axis, Entity, MouseState, RenderContext, Task, View, ViewContext, - ViewHandle, WeakViewHandle, + AnyViewHandle, AppContext, Axis, Entity, MouseState, Task, View, ViewContext, ViewHandle, + WeakViewHandle, }; use menu::{Cancel, Confirm, SelectFirst, SelectIndex, SelectLast, SelectNext, SelectPrev}; use parking_lot::Mutex; @@ -48,7 +48,7 @@ impl View for Picker { "Picker" } - fn render(&mut self, cx: &mut RenderContext) -> gpui::ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> gpui::ElementBox { let theme = (self.theme.lock())(&cx.global::().theme); let query = self.query(cx); let delegate = self.delegate.clone(); diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index ffe9ba065b..3128ec0d78 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -13,8 +13,8 @@ use gpui::{ impl_internal_actions, keymap_matcher::KeymapContext, platform::{CursorStyle, MouseButton, PromptLevel}, - AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, RenderContext, Task, View, - ViewContext, ViewHandle, + AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, Task, View, ViewContext, + ViewHandle, }; use menu::{Confirm, SelectNext, SelectPrev}; use project::{Entry, EntryKind, Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId}; @@ -1015,8 +1015,8 @@ impl ProjectPanel { fn for_each_visible_entry( &self, range: Range, - cx: &mut RenderContext, - mut callback: impl FnMut(ProjectEntryId, EntryDetails, &mut RenderContext), + cx: &mut ViewContext, + mut callback: impl FnMut(ProjectEntryId, EntryDetails, &mut ViewContext), ) { let mut ix = 0; for (worktree_id, visible_worktree_entries) in &self.visible_entries { @@ -1097,7 +1097,7 @@ impl ProjectPanel { padding: f32, row_container_style: ContainerStyle, style: &ProjectPanelEntry, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let kind = details.kind; let show_editor = details.is_editing && !details.is_processing; @@ -1154,7 +1154,7 @@ impl ProjectPanel { editor: &ViewHandle, dragged_entry_destination: &mut Option>, theme: &theme::ProjectPanel, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let this = cx.handle(); let kind = details.kind; @@ -1251,7 +1251,7 @@ impl ProjectPanel { .as_draggable(entry_id, { let row_container_style = theme.dragged_entry.container; - move |_, cx: &mut RenderContext| { + move |_, cx: &mut ViewContext| { let theme = cx.global::().theme.clone(); Self::render_entry_visual_element( &details, @@ -1273,7 +1273,7 @@ impl View for ProjectPanel { "ProjectPanel" } - fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox { enum ProjectPanel {} let theme = &cx.global::().theme.project_panel; let mut container_style = theme.container; diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index a2e8012b89..3586ff7726 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -4,8 +4,8 @@ use editor::{ }; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ - actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, - RenderContext, Task, View, ViewContext, ViewHandle, + actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, Task, View, + ViewContext, ViewHandle, }; use ordered_float::OrderedFloat; use picker::{Picker, PickerDelegate}; @@ -48,7 +48,7 @@ impl View for ProjectSymbolsView { "ProjectSymbolsView" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index 58369f4aa5..ed45b778dd 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -4,8 +4,7 @@ use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ actions, elements::{ChildView, Flex, ParentElement}, - AnyViewHandle, AppContext, Element, ElementBox, Entity, RenderContext, Task, View, ViewContext, - ViewHandle, + AnyViewHandle, AppContext, Element, ElementBox, Entity, Task, View, ViewContext, ViewHandle, }; use highlighted_workspace_location::HighlightedWorkspaceLocation; use ordered_float::OrderedFloat; @@ -102,7 +101,7 @@ impl View for RecentProjectsView { "RecentProjectsView" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index c0445ca9c1..ffef25872e 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -9,8 +9,7 @@ use gpui::{ elements::*, impl_actions, platform::{CursorStyle, MouseButton}, - Action, AnyViewHandle, AppContext, Entity, RenderContext, Subscription, Task, View, - ViewContext, ViewHandle, + Action, AnyViewHandle, AppContext, Entity, Subscription, Task, View, ViewContext, ViewHandle, }; use project::search::SearchQuery; use serde::Deserialize; @@ -92,7 +91,7 @@ impl View for BufferSearchBar { } } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); let editor_container = if self.query_contains_error { theme.search.invalid_editor @@ -324,7 +323,7 @@ impl BufferSearchBar { option_supported: bool, icon: &'static str, option: SearchOption, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Option { if !option_supported { return None; @@ -364,7 +363,7 @@ impl BufferSearchBar { &self, icon: &'static str, direction: Direction, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let action: Box; let tooltip; @@ -408,11 +407,7 @@ impl BufferSearchBar { .boxed() } - fn render_close_button( - &self, - theme: &theme::Search, - cx: &mut RenderContext, - ) -> ElementBox { + fn render_close_button(&self, theme: &theme::Search, cx: &mut ViewContext) -> ElementBox { let action = Box::new(Dismiss); let tooltip = "Dismiss Buffer Search"; let tooltip_style = cx.global::().theme.tooltip.clone(); diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index a47b1ec76d..1c8cf74125 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -12,9 +12,8 @@ use gpui::{ actions, elements::*, platform::{CursorStyle, MouseButton}, - Action, AnyViewHandle, AppContext, Entity, ModelContext, ModelHandle, RenderContext, - Subscription, Task, View, ViewContext, ElementBox, ViewHandle, WeakModelHandle, - WeakViewHandle, + Action, AnyViewHandle, AppContext, ElementBox, Entity, ModelContext, ModelHandle, Subscription, + Task, View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle, }; use menu::Confirm; use project::{search::SearchQuery, Project}; @@ -178,7 +177,7 @@ impl View for ProjectSearchView { "ProjectSearchView" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let model = &self.model.read(cx); if model.match_ranges.is_empty() { enum Status {} @@ -747,7 +746,7 @@ impl ProjectSearchBar { &self, icon: &'static str, direction: Direction, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let action: Box; let tooltip; @@ -795,7 +794,7 @@ impl ProjectSearchBar { &self, icon: &'static str, option: SearchOption, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let tooltip_style = cx.global::().theme.tooltip.clone(); let is_active = self.is_option_enabled(option, cx); @@ -848,7 +847,7 @@ impl View for ProjectSearchBar { "ProjectSearchBar" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if let Some(search) = self.active_project_search.as_ref() { let search = search.read(cx); let theme = cx.global::().theme.clone(); diff --git a/crates/terminal_view/src/terminal_button.rs b/crates/terminal_view/src/terminal_button.rs index 5964b90aa9..33738ff58f 100644 --- a/crates/terminal_view/src/terminal_button.rs +++ b/crates/terminal_view/src/terminal_button.rs @@ -3,8 +3,8 @@ use gpui::{ elements::*, impl_internal_actions, platform::{CursorStyle, MouseButton}, - AppContext, Element, ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle, - WeakModelHandle, WeakViewHandle, + AppContext, Element, ElementBox, Entity, View, ViewContext, ViewHandle, WeakModelHandle, + WeakViewHandle, }; use settings::Settings; use std::any::TypeId; @@ -42,14 +42,14 @@ impl View for TerminalButton { "TerminalButton" } - fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox { let workspace = self.workspace.upgrade(cx); let project = match workspace { Some(workspace) => workspace.read(cx).project().read(cx), None => return Empty::new().boxed(), }; - let focused_view = cx.focused_view_id(cx.window_id()); + let focused_view = cx.focused_view_id(); let active = focused_view .map(|view_id| { cx.view_type_id(cx.window_id(), view_id) == Some(TypeId::of::()) diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index 252ab128be..4864e13243 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -10,8 +10,8 @@ use gpui::{ platform::{CursorStyle, MouseButton}, serde_json::json, text_layout::{Line, RunStyle}, - Element, ElementBox, EventContext, FontCache, ModelContext, MouseRegion, PaintContext, Quad, - SizeConstraint, TextLayoutCache, WeakModelHandle, WeakViewHandle, + Element, ElementBox, EventContext, FontCache, ModelContext, MouseRegion, Quad, SceneBuilder, + SizeConstraint, TextLayoutCache, ViewContext, WeakModelHandle, WeakViewHandle, }; use itertools::Itertools; use language::CursorShape; @@ -45,7 +45,7 @@ pub struct LayoutState { size: TerminalSize, mode: TermMode, display_offset: usize, - hyperlink_tooltip: Option, + hyperlink_tooltip: Option>, } ///Helper struct for converting data between alacritty's cursor points, and displayed cursor points @@ -84,10 +84,12 @@ impl LayoutCell { fn paint( &self, + scene: &mut SceneBuilder, origin: Vector2F, layout: &LayoutState, visible_bounds: RectF, - cx: &mut PaintContext, + view: &mut TerminalView, + cx: &mut ViewContext, ) { let pos = { let point = self.point; @@ -98,7 +100,7 @@ impl LayoutCell { }; self.text - .paint(pos, visible_bounds, layout.size.line_height, cx); + .paint(pos, visible_bounds, layout.size.line_height, view, cx); } } @@ -139,7 +141,7 @@ impl LayoutRect { layout.size.line_height, ); - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: RectF::new(position, size), background: Some(self.color), border: Default::default(), @@ -380,7 +382,7 @@ impl TerminalElement { view_id: usize, visible_bounds: RectF, mode: TermMode, - cx: &mut PaintContext, + cx: &mut ViewContext, ) { let connection = self.terminal; @@ -501,7 +503,7 @@ impl TerminalElement { ) } - cx.scene.push_mouse_region(region); + scene.push_mouse_region(region); } ///Configures a text style from the current settings. @@ -553,7 +555,8 @@ impl Element for TerminalElement { fn layout( &mut self, constraint: gpui::SizeConstraint, - cx: &mut gpui::LayoutContext, + view: &mut TerminalView, + cx: &mut ViewContext, ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { let settings = cx.global::(); let font_cache = cx.font_cache(); @@ -717,23 +720,24 @@ impl Element for TerminalElement { fn paint( &mut self, - bounds: gpui::geometry::rect::RectF, - visible_bounds: gpui::geometry::rect::RectF, + scene: &mut SceneBuilder, + bounds: RectF, + visible_bounds: RectF, layout: &mut Self::LayoutState, - cx: &mut gpui::PaintContext, + cx: &mut ViewContext, ) -> Self::PaintState { let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); //Setup element stuff let clip_bounds = Some(visible_bounds); - cx.paint_layer(clip_bounds, |cx| { + scene.paint_layer(clip_bounds, |scene| { let origin = bounds.origin() + vec2f(layout.size.cell_width, 0.); // Elements are ephemeral, only at paint time do we know what could be clicked by a mouse self.attach_mouse_handlers(origin, self.view.id(), visible_bounds, layout.mode, cx); - cx.scene.push_cursor_region(gpui::CursorRegion { + scene.push_cursor_region(gpui::CursorRegion { bounds, style: if layout.hyperlink_tooltip.is_some() { CursorStyle::PointingHand @@ -742,9 +746,9 @@ impl Element for TerminalElement { }, }); - cx.paint_layer(clip_bounds, |cx| { + scene.paint_layer(clip_bounds, |scene| { //Start with a background color - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: RectF::new(bounds.origin(), bounds.size()), background: Some(layout.background_color), border: Default::default(), @@ -757,7 +761,7 @@ impl Element for TerminalElement { }); //Draw Highlighted Backgrounds - cx.paint_layer(clip_bounds, |cx| { + scene.paint_layer(clip_bounds, |scene| { for (relative_highlighted_range, color) in layout.relative_highlighted_ranges.iter() { if let Some((start_y, highlighted_range_lines)) = @@ -771,29 +775,29 @@ impl Element for TerminalElement { //Copied from editor. TODO: move to theme or something corner_radius: 0.15 * layout.size.line_height, }; - hr.paint(bounds, cx.scene); + hr.paint(bounds, scene); } } }); //Draw the text cells - cx.paint_layer(clip_bounds, |cx| { + scene.paint_layer(clip_bounds, |scene| { for cell in &layout.cells { - cell.paint(origin, layout, visible_bounds, cx); + cell.paint(scene, origin, layout, visible_bounds, view, cx); } }); //Draw cursor if self.cursor_visible { if let Some(cursor) = &layout.cursor { - cx.paint_layer(clip_bounds, |cx| { - cursor.paint(origin, cx); + scene.paint_layer(clip_bounds, |scene| { + cursor.paint(scene, origin, cx); }) } } if let Some(element) = &mut layout.hyperlink_tooltip { - element.paint(origin, visible_bounds, cx) + Element::paint(element, scene, origin, visible_bounds, view, cx) } }); } @@ -804,7 +808,7 @@ impl Element for TerminalElement { fn debug( &self, - _bounds: gpui::geometry::rect::RectF, + _bounds: RectF, _layout: &Self::LayoutState, _paint: &Self::PaintState, _cx: &gpui::DebugContext, diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 3af147b9ff..6f2ec00614 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -236,11 +236,7 @@ impl TerminalView { cx.notify(); } - pub fn should_show_cursor( - &self, - focused: bool, - cx: &mut gpui::RenderContext<'_, Self>, - ) -> bool { + pub fn should_show_cursor(&self, focused: bool, cx: &mut gpui::ViewContext<'_, Self>) -> bool { //Don't blink the cursor when not focused, blinking is disabled, or paused if !focused || !self.blinking_on @@ -388,12 +384,12 @@ impl View for TerminalView { "Terminal" } - fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> ElementBox { let terminal_handle = self.terminal.clone().downgrade(); let self_id = cx.view_id(); let focused = cx - .focused_view_id(cx.window_id()) + .focused_view_id() .filter(|view_id| *view_id == self_id) .is_some(); diff --git a/crates/theme/src/ui.rs b/crates/theme/src/ui.rs index 1013236dfa..093b990d7b 100644 --- a/crates/theme/src/ui.rs +++ b/crates/theme/src/ui.rs @@ -11,7 +11,7 @@ use gpui::{ platform, platform::MouseButton, scene::MouseClick, - Action, Element, ElementBox, EventContext, MouseState, RenderContext, View, + Action, Element, ElementBox, EventContext, MouseState, View, ViewContext, }; use serde::Deserialize; @@ -27,13 +27,13 @@ pub struct CheckboxStyle { pub hovered_and_checked: ContainerStyle, } -pub fn checkbox( +pub fn checkbox( label: &'static str, style: &CheckboxStyle, checked: bool, - cx: &mut RenderContext, - change: fn(checked: bool, cx: &mut EventContext) -> (), -) -> MouseEventHandler { + cx: &mut ViewContext, + change: fn(checked: bool, cx: &mut EventContext) -> (), +) -> MouseEventHandler { let label = Label::new(label, style.label.text.clone()) .contained() .with_style(style.label.container) @@ -42,14 +42,14 @@ pub fn checkbox( checkbox_with_label(label, style, checked, cx, change) } -pub fn checkbox_with_label( - label: ElementBox, +pub fn checkbox_with_label( + label: ElementBox, style: &CheckboxStyle, checked: bool, - cx: &mut RenderContext, - change: fn(checked: bool, cx: &mut EventContext) -> (), -) -> MouseEventHandler { - MouseEventHandler::::new(0, cx, |state, _| { + cx: &mut ViewContext, + change: fn(checked: bool, cx: &mut EventContext) -> (), +) -> MouseEventHandler { + MouseEventHandler::new(0, cx, |state, _| { let indicator = if checked { svg(&style.icon) } else { @@ -82,7 +82,7 @@ pub fn checkbox_with_label( .align_children_center() .boxed() }) - .on_click(platform::MouseButton::Left, move |_, cx| { + .on_click(platform::MouseButton::Left, move |_, _, cx| { change(!checked, cx) }) .with_cursor_style(platform::CursorStyle::PointingHand) @@ -107,7 +107,7 @@ impl Dimensions { } } -pub fn svg(style: &SvgStyle) -> ConstrainedBox { +pub fn svg(style: &SvgStyle) -> ConstrainedBox { Svg::new(style.asset.clone()) .with_color(style.color) .constrained() @@ -121,7 +121,7 @@ pub struct IconStyle { container: ContainerStyle, } -pub fn icon(style: &IconStyle) -> Container { +pub fn icon(style: &IconStyle) -> Container { svg(&style.icon).contained().with_style(style.container) } @@ -130,8 +130,8 @@ pub fn keystroke_label( label_style: &ContainedText, keystroke_style: &ContainedText, action: Box, - cx: &mut RenderContext, -) -> Container { + cx: &mut ViewContext, +) -> Container { // FIXME: Put the theme in it's own global so we can // query the keystroke style on our own keystroke_label_for( @@ -144,14 +144,14 @@ pub fn keystroke_label( ) } -pub fn keystroke_label_for( +pub fn keystroke_label_for( window_id: usize, view_id: usize, label_text: &'static str, label_style: &ContainedText, keystroke_style: &ContainedText, action: Box, -) -> Container { +) -> Container { Flex::row() .with_child( Label::new(label_text, label_style.text.clone()) @@ -175,37 +175,39 @@ pub fn keystroke_label_for( pub type ButtonStyle = Interactive; -pub fn cta_button( +pub fn cta_button( label: L, action: A, max_width: f32, style: &ButtonStyle, - cx: &mut RenderContext, -) -> ElementBox + cx: &mut ViewContext, +) -> ElementBox where + Tag: 'static, L: Into>, A: 'static + Action + Clone, V: View, { - cta_button_with_click(label, max_width, style, cx, move |_, cx| { + cta_button_with_click::(label, max_width, style, cx, move |_, _, cx| { cx.dispatch_action(action.clone()) }) .boxed() } -pub fn cta_button_with_click( +pub fn cta_button_with_click( label: L, max_width: f32, style: &ButtonStyle, - cx: &mut RenderContext, + cx: &mut ViewContext, f: F, -) -> MouseEventHandler +) -> MouseEventHandler where + Tag: 'static, L: Into>, V: View, - F: Fn(MouseClick, &mut EventContext) + 'static, + F: Fn(MouseClick, &mut V, &mut EventContext) + 'static, { - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = style.style_for(state, false); Label::new(label, style.text.to_owned()) .aligned() @@ -234,16 +236,17 @@ impl ModalStyle { } } -pub fn modal( +pub fn modal( title: I, style: &ModalStyle, - cx: &mut RenderContext, + cx: &mut ViewContext, build_modal: F, -) -> ElementBox +) -> ElementBox where + Tag: 'static, V: View, I: Into>, - F: FnOnce(&mut gpui::RenderContext) -> ElementBox, + F: FnOnce(&mut gpui::ViewContext) -> ElementBox, { const TITLEBAR_HEIGHT: f32 = 28.; // let active = cx.window_is_active(cx.window_id()); @@ -261,11 +264,11 @@ where ) .boxed(), // FIXME: Get a better tag type - MouseEventHandler::::new(999999, cx, |state, _cx| { + MouseEventHandler::::new(999999, cx, |state, _cx| { let style = style.close_icon.style_for(state, false); icon(style).boxed() }) - .on_click(platform::MouseButton::Left, move |_, cx| { + .on_click(platform::MouseButton::Left, move |_, _, cx| { let window_id = cx.window_id(); cx.remove_window(window_id); }) diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index f2bdc130bf..7ac5b27367 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -1,7 +1,7 @@ use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; use gpui::{ - actions, elements::*, AnyViewHandle, AppContext, Element, ElementBox, Entity, MouseState, - RenderContext, View, ViewContext, ViewHandle, + actions, elements::*, AnyViewHandle, AppContext, Element, ElementBox, Entity, MouseState, View, + ViewContext, ViewHandle, }; use picker::{Picker, PickerDelegate}; use settings::{settings_file::SettingsFile, Settings}; @@ -255,7 +255,7 @@ impl View for ThemeSelector { "ThemeSelector" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } diff --git a/crates/theme_testbench/src/theme_testbench.rs b/crates/theme_testbench/src/theme_testbench.rs index 9707b0a453..6d5f06d65e 100644 --- a/crates/theme_testbench/src/theme_testbench.rs +++ b/crates/theme_testbench/src/theme_testbench.rs @@ -2,12 +2,12 @@ use gpui::{ actions, color::Color, elements::{ - Canvas, Container, ContainerStyle, Flex, Label, Margin, MouseEventHandler, Padding, - ParentElement, ElementBox, + Canvas, Container, ContainerStyle, ElementBox, Flex, Label, Margin, MouseEventHandler, + Padding, ParentElement, }, fonts::TextStyle, - AppContext, Border, Element, Entity, ModelHandle, Quad, RenderContext, Task, View, ViewContext, - ViewHandle, WeakViewHandle, + AppContext, Border, Element, Entity, ModelHandle, Quad, Task, View, ViewContext, ViewHandle, + WeakViewHandle, }; use project::Project; use settings::Settings; @@ -39,7 +39,7 @@ impl ThemeTestbench { Flex::row() .with_children(ramp.iter().cloned().map(|color| { Canvas::new(move |bounds, _, cx| { - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds, background: Some(color), ..Default::default() @@ -67,7 +67,7 @@ impl ThemeTestbench { fn render_layer( layer_index: usize, layer: &Layer, - cx: &mut RenderContext<'_, Self>, + cx: &mut ViewContext<'_, Self>, ) -> Container { Flex::column() .with_child( @@ -123,7 +123,7 @@ impl ThemeTestbench { layer_index: usize, set_name: &'static str, style_set: &StyleSet, - cx: &mut RenderContext<'_, Self>, + cx: &mut ViewContext<'_, Self>, ) -> Flex { Flex::row() .with_child(Self::render_button( @@ -182,7 +182,7 @@ impl ThemeTestbench { text: &'static str, style_set: &StyleSet, style_override: Option &Style>, - cx: &mut RenderContext<'_, Self>, + cx: &mut ViewContext<'_, Self>, ) -> ElementBox { enum TestBenchButton {} MouseEventHandler::::new(layer_index + button_index, cx, |state, cx| { @@ -230,7 +230,7 @@ impl ThemeTestbench { .boxed() } - fn render_label(text: String, style: &Style, cx: &mut RenderContext<'_, Self>) -> Label { + fn render_label(text: String, style: &Style, cx: &mut ViewContext<'_, Self>) -> Label { let settings = cx.global::(); let font_cache = cx.font_cache(); let family_id = settings.buffer_font_family; @@ -262,7 +262,7 @@ impl View for ThemeTestbench { "ThemeTestbench" } - fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox { let color_scheme = &cx.global::().theme.clone().color_scheme; Flex::row() diff --git a/crates/welcome/src/base_keymap_picker.rs b/crates/welcome/src/base_keymap_picker.rs index 8c08a63dc6..07cfe037a4 100644 --- a/crates/welcome/src/base_keymap_picker.rs +++ b/crates/welcome/src/base_keymap_picker.rs @@ -74,7 +74,7 @@ impl View for BaseKeymapSelector { "BaseKeymapSelector" } - fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox { ChildView::new(&self.picker, cx).boxed() } diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 28b0e43c57..50e85a4f3a 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -55,7 +55,7 @@ impl View for WelcomePage { "WelcomePage" } - fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> ElementBox { let self_handle = cx.handle(); let settings = cx.global::(); let theme = settings.theme.clone(); diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 06782cd48c..888c1d2021 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -9,8 +9,7 @@ use gpui::{ geometry::vector::Vector2F, impl_internal_actions, platform::{CursorStyle, MouseButton}, - AppContext, Border, Element, ElementBox, RenderContext, SizeConstraint, ViewContext, - ViewHandle, + AppContext, Border, Element, ElementBox, SizeConstraint, ViewContext, ViewHandle, }; use settings::{DockAnchor, Settings}; use theme::Theme; @@ -315,7 +314,7 @@ impl Dock { &self, theme: &Theme, anchor: DockAnchor, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> Option { let style = &theme.workspace.dock; diff --git a/crates/workspace/src/dock/toggle_dock_button.rs b/crates/workspace/src/dock/toggle_dock_button.rs index 5b46b0e21f..55cafbea01 100644 --- a/crates/workspace/src/dock/toggle_dock_button.rs +++ b/crates/workspace/src/dock/toggle_dock_button.rs @@ -34,7 +34,7 @@ impl View for ToggleDockButton { "Dock Toggle" } - fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> ElementBox { let workspace = self.workspace.upgrade(cx); if workspace.is_none() { diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index f9b3550003..76cf874de8 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -740,8 +740,8 @@ pub(crate) mod test { use super::{Item, ItemEvent}; use crate::{sidebar::SidebarItem, ItemId, ItemNavHistory, Pane, Workspace, WorkspaceId}; use gpui::{ - elements::Empty, AppContext, Element, ElementBox, Entity, ModelHandle, RenderContext, Task, - View, ViewContext, ViewHandle, WeakViewHandle, + elements::Empty, AppContext, Element, ElementBox, Entity, ModelHandle, Task, View, + ViewContext, ViewHandle, WeakViewHandle, }; use project::{Project, ProjectEntryId, ProjectPath, WorktreeId}; use smallvec::SmallVec; @@ -899,7 +899,7 @@ pub(crate) mod test { "TestItem" } - fn render(&mut self, _: &mut RenderContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index 893f0ff0b4..8932c969f8 100644 --- a/crates/workspace/src/notifications.rs +++ b/crates/workspace/src/notifications.rs @@ -229,7 +229,7 @@ pub mod simple_message_notification { "MessageNotification" } - fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox { let theme = cx.global::().theme.clone(); let theme = &theme.simple_message_notification; diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 4d2ff32ef3..6015beddf7 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -24,8 +24,7 @@ use gpui::{ keymap_matcher::KeymapContext, platform::{CursorStyle, MouseButton, NavigationDirection, PromptLevel}, Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, EventContext, - ModelHandle, MouseRegion, Quad, RenderContext, Task, View, ViewContext, ViewHandle, - WeakViewHandle, + ModelHandle, MouseRegion, Quad, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; use project::{Project, ProjectEntryId, ProjectPath}; use serde::Deserialize; @@ -1221,7 +1220,7 @@ impl Pane { }); } - fn render_tabs(&mut self, cx: &mut RenderContext) -> impl Element { + fn render_tabs(&mut self, cx: &mut ViewContext) -> impl Element { let theme = cx.global::().theme.clone(); let pane = cx.handle(); @@ -1302,7 +1301,7 @@ impl Pane { let theme = cx.global::().theme.clone(); let detail = detail.clone(); - move |dragged_item, cx: &mut RenderContext| { + move |dragged_item, cx: &mut ViewContext| { let tab_style = &theme.workspace.tab_bar.dragged_tab; Self::render_tab( &dragged_item.item, @@ -1384,7 +1383,7 @@ impl Pane { detail: Option, hovered: bool, tab_style: &theme::Tab, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let title = item.tab_content(detail, &tab_style, cx); let mut container = tab_style.container.clone(); @@ -1408,7 +1407,7 @@ impl Pane { Canvas::new(move |bounds, _, cx| { if let Some(color) = icon_color { let square = RectF::new(bounds.origin(), vec2f(diameter, diameter)); - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: square, background: Some(color), border: Default::default(), @@ -1476,11 +1475,7 @@ impl Pane { .boxed() } - fn render_tab_bar_buttons( - &mut self, - theme: &Theme, - cx: &mut RenderContext, - ) -> ElementBox { + fn render_tab_bar_buttons(&mut self, theme: &Theme, cx: &mut ViewContext) -> ElementBox { Flex::row() // New menu .with_child(render_tab_bar_button( @@ -1529,7 +1524,7 @@ impl Pane { .boxed() } - fn render_blank_pane(&mut self, theme: &Theme, _cx: &mut RenderContext) -> ElementBox { + fn render_blank_pane(&mut self, theme: &Theme, _cx: &mut ViewContext) -> ElementBox { let background = theme.workspace.background; Empty::new() .contained() @@ -1547,7 +1542,7 @@ impl View for Pane { "Pane" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let this = cx.handle(); enum MouseNavigationHandler {} @@ -1705,7 +1700,7 @@ impl View for Pane { fn render_tab_bar_button( index: usize, icon: &'static str, - cx: &mut RenderContext, + cx: &mut ViewContext, action: A, context_menu: Option>, ) -> ElementBox { @@ -1853,7 +1848,7 @@ impl PaneBackdrop { } } -impl Element for PaneBackdrop { +impl Element for PaneBackdrop { type LayoutState = (); type PaintState = (); @@ -1861,31 +1856,34 @@ impl Element for PaneBackdrop { fn layout( &mut self, constraint: gpui::SizeConstraint, - cx: &mut gpui::LayoutContext, + view: &mut Pane, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { - let size = self.child.layout(constraint, cx); + let size = self.child.layout(constraint, view, cx); (size, ()) } fn paint( &mut self, + scene: &mut gpui::SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut gpui::PaintContext, + view: &mut Pane, + cx: &mut ViewContext, ) -> Self::PaintState { let background = cx.global::().theme.editor.background; let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); - cx.scene.push_quad(gpui::Quad { + scene.push_quad(gpui::Quad { bounds: RectF::new(bounds.origin(), bounds.size()), background: Some(background), ..Default::default() }); let child_view_id = self.child_view; - cx.scene.push_mouse_region( + scene.push_mouse_region( MouseRegion::new::(child_view_id, 0, visible_bounds).on_down( gpui::platform::MouseButton::Left, move |_, cx| { @@ -1895,8 +1893,9 @@ impl Element for PaneBackdrop { ), ); - cx.paint_layer(Some(bounds), |cx| { - self.child.paint(bounds.origin(), visible_bounds, cx) + scene.paint_layer(Some(bounds), |scene| { + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx) }) } @@ -1907,9 +1906,10 @@ impl Element for PaneBackdrop { _visible_bounds: RectF, _layout: &Self::LayoutState, _paint: &Self::PaintState, - cx: &gpui::MeasurementContext, + view: &V, + cx: &gpui::ViewContext, ) -> Option { - self.child.rect_for_text_range(range_utf16, cx) + self.child.rect_for_text_range(range_utf16, view, cx) } fn debug( @@ -1917,12 +1917,13 @@ impl Element for PaneBackdrop { _bounds: RectF, _layout: &Self::LayoutState, _paint: &Self::PaintState, - cx: &gpui::DebugContext, + view: &V, + cx: &gpui::ViewContext, ) -> serde_json::Value { gpui::json::json!({ "type": "Pane Back Drop", "view": self.child_view, - "child": self.child.debug(cx), + "child": self.child.debug(view, cx), }) } } diff --git a/crates/workspace/src/pane/dragged_item_receiver.rs b/crates/workspace/src/pane/dragged_item_receiver.rs index 7026cc043f..86db110529 100644 --- a/crates/workspace/src/pane/dragged_item_receiver.rs +++ b/crates/workspace/src/pane/dragged_item_receiver.rs @@ -5,7 +5,7 @@ use gpui::{ geometry::{rect::RectF, vector::Vector2F}, platform::MouseButton, scene::MouseUp, - AppContext, Element, ElementBox, EventContext, MouseState, Quad, RenderContext, WeakViewHandle, + AppContext, Element, ElementBox, EventContext, MouseState, Quad, ViewContext, WeakViewHandle, }; use project::ProjectEntryId; use settings::Settings; @@ -22,14 +22,14 @@ pub fn dragged_item_receiver( drop_index: usize, allow_same_pane: bool, split_margin: Option, - cx: &mut RenderContext, + cx: &mut ViewContext, render_child: F, ) -> MouseEventHandler where Tag: 'static, - F: FnOnce(&mut MouseState, &mut RenderContext) -> ElementBox, + F: FnOnce(&mut MouseState, &mut ViewContext) -> ElementBox, { - MouseEventHandler::::above(region_id, cx, |state, cx| { + MouseEventHandler::::above(region_id, cx, |state, _, cx| { // Observing hovered will cause a render when the mouse enters regardless // of if mouse position was accessed before let drag_position = if state.hovered() { @@ -59,7 +59,7 @@ where .unwrap_or(bounds); cx.paint_stacking_context(None, None, |cx| { - cx.scene.push_quad(Quad { + scene.push_quad(Quad { bounds: overlay_region, background: Some(overlay_color(cx)), border: Default::default(), @@ -102,7 +102,7 @@ pub fn handle_dropped_item( index: usize, allow_same_pane: bool, split_margin: Option, - cx: &mut EventContext, + cx: &mut ViewContext, ) { enum Action { Move(WeakViewHandle, usize), @@ -110,11 +110,11 @@ pub fn handle_dropped_item( } let drag_and_drop = cx.global::>(); let action = if let Some((_, dragged_item)) = - drag_and_drop.currently_dragged::(cx.window_id) + drag_and_drop.currently_dragged::(cx.window_id()) { Action::Move(dragged_item.pane.clone(), dragged_item.item.id()) } else if let Some((_, project_entry)) = - drag_and_drop.currently_dragged::(cx.window_id) + drag_and_drop.currently_dragged::(cx.window_id()) { Action::Open(*project_entry) } else { diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index 617c5b9a34..286d3cebbe 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -5,7 +5,7 @@ use gpui::{ elements::*, geometry::{rect::RectF, vector::Vector2F}, platform::{CursorStyle, MouseButton}, - Axis, Border, ModelHandle, RenderContext, ViewHandle, + Axis, Border, ModelHandle, ViewContext, ViewHandle, }; use project::Project; use serde::Deserialize; @@ -70,7 +70,7 @@ impl PaneGroup { follower_states: &FollowerStatesByLeader, active_call: Option<&ModelHandle>, active_pane: &ViewHandle, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { self.root.render( project, @@ -131,7 +131,7 @@ impl Member { follower_states: &FollowerStatesByLeader, active_call: Option<&ModelHandle>, active_pane: &ViewHandle, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { enum FollowIntoExternalProject {} @@ -366,7 +366,7 @@ impl PaneAxis { follower_state: &FollowerStatesByLeader, active_call: Option<&ModelHandle>, active_pane: &ViewHandle, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { let last_member_ix = self.members.len() - 1; Flex::new(self.axis) diff --git a/crates/workspace/src/shared_screen.rs b/crates/workspace/src/shared_screen.rs index 7f7bf3b25f..cad832a56d 100644 --- a/crates/workspace/src/shared_screen.rs +++ b/crates/workspace/src/shared_screen.rs @@ -9,7 +9,7 @@ use gpui::{ elements::*, geometry::{rect::RectF, vector::vec2f}, platform::MouseButton, - AppContext, Entity, RenderContext, Task, View, ViewContext, + AppContext, Entity, Task, View, ViewContext, }; use settings::Settings; use smallvec::SmallVec; @@ -64,7 +64,7 @@ impl View for SharedScreen { "SharedScreen" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { enum Focus {} let frame = self.frame.clone(); @@ -76,7 +76,7 @@ impl View for SharedScreen { vec2f(frame.width() as f32, frame.height() as f32), ); let origin = bounds.origin() + (bounds.size() / 2.) - size / 2.; - cx.scene.push_surface(gpui::platform::mac::Surface { + scene.push_surface(gpui::platform::mac::Surface { bounds: RectF::new(origin, size), image_buffer: frame.image(), }); diff --git a/crates/workspace/src/sidebar.rs b/crates/workspace/src/sidebar.rs index 8efee01c30..0a0d9339a3 100644 --- a/crates/workspace/src/sidebar.rs +++ b/crates/workspace/src/sidebar.rs @@ -1,7 +1,7 @@ use crate::StatusItemView; use gpui::{ elements::*, impl_actions, platform::CursorStyle, platform::MouseButton, AnyViewHandle, - AppContext, Entity, RenderContext, Subscription, View, ViewContext, ViewHandle, + AppContext, Entity, Subscription, View, ViewContext, ViewHandle, }; use serde::Deserialize; use settings::Settings; @@ -188,7 +188,7 @@ impl View for Sidebar { "Sidebar" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if let Some(active_item) = self.active_item() { enum ResizeHandleTag {} let style = &cx.global::().theme.workspace.sidebar; @@ -225,7 +225,7 @@ impl View for SidebarButtons { "SidebarToggleButton" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = &cx.global::().theme; let tooltip_style = theme.tooltip.clone(); let theme = &theme.workspace.status_bar.sidebar_buttons; diff --git a/crates/workspace/src/status_bar.rs b/crates/workspace/src/status_bar.rs index 355c327dfd..3c35b986d7 100644 --- a/crates/workspace/src/status_bar.rs +++ b/crates/workspace/src/status_bar.rs @@ -9,7 +9,7 @@ use gpui::{ }, json::{json, ToJson}, AnyViewHandle, AppContext, DebugContext, ElementBox, Entity, LayoutContext, MeasurementContext, - PaintContext, RenderContext, SizeConstraint, Subscription, View, ViewContext, ViewHandle, + PaintContext, SceneBuilder, SizeConstraint, Subscription, View, ViewContext, ViewHandle, }; use settings::Settings; @@ -42,7 +42,7 @@ impl View for StatusBar { "StatusBar" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = &cx.global::().theme.workspace.status_bar; StatusBarElement { @@ -143,44 +143,49 @@ struct StatusBarElement { right: ElementBox, } -impl Element for StatusBarElement { +impl Element for StatusBarElement { type LayoutState = (); type PaintState = (); fn layout( &mut self, mut constraint: SizeConstraint, - cx: &mut LayoutContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let max_width = constraint.max.x(); constraint.min = vec2f(0., constraint.min.y()); - let right_size = self.right.layout(constraint, cx); + let right_size = self.right.layout(constraint, view, cx); let constraint = SizeConstraint::new( vec2f(0., constraint.min.y()), vec2f(max_width - right_size.x(), constraint.max.y()), ); - self.left.layout(constraint, cx); + self.left.layout(constraint, view, cx); (vec2f(max_width, right_size.y()), ()) } fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { let origin_y = bounds.upper_right().y(); let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); let left_origin = vec2f(bounds.lower_left().x(), origin_y); - self.left.paint(left_origin, visible_bounds, cx); + self.left + .paint(scene, left_origin, visible_bounds, view, cx); let right_origin = vec2f(bounds.upper_right().x() - self.right.size().x(), origin_y); - self.right.paint(right_origin, visible_bounds, cx); + self.right + .paint(scene, right_origin, visible_bounds, view, cx); } fn rect_for_text_range( diff --git a/crates/workspace/src/toolbar.rs b/crates/workspace/src/toolbar.rs index 5df64bea1f..2ef45c0411 100644 --- a/crates/workspace/src/toolbar.rs +++ b/crates/workspace/src/toolbar.rs @@ -1,7 +1,7 @@ use crate::{ItemHandle, Pane}; use gpui::{ elements::*, platform::CursorStyle, platform::MouseButton, Action, AnyViewHandle, AppContext, - Entity, RenderContext, View, ViewContext, ElementBox, ViewHandle, WeakViewHandle, + ElementBox, Entity, View, ViewContext, ViewHandle, WeakViewHandle, }; use settings::Settings; @@ -59,7 +59,7 @@ impl View for Toolbar { "Toolbar" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = &cx.global::().theme.workspace.toolbar; let mut primary_left_items = Vec::new(); @@ -168,7 +168,7 @@ fn nav_button( action: A, tooltip_action: A, action_name: &str, - cx: &mut RenderContext, + cx: &mut ViewContext, ) -> ElementBox { MouseEventHandler::::new(0, cx, |state, _| { let style = if enabled { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 334578d67d..3253f9db6a 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -45,8 +45,7 @@ use gpui::{ WindowOptions, }, Action, AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelContext, - ModelHandle, RenderContext, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, - WeakViewHandle, + ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem}; use language::LanguageRegistry; @@ -2054,10 +2053,10 @@ impl Workspace { self.leader_state.followers.contains(&peer_id) } - fn render_titlebar(&self, theme: &Theme, cx: &mut RenderContext) -> ElementBox { + fn render_titlebar(&self, theme: &Theme, cx: &mut ViewContext) -> ElementBox { // TODO: There should be a better system in place for this // (https://github.com/zed-industries/zed/issues/1290) - let is_fullscreen = cx.window_is_fullscreen(cx.window_id()); + let is_fullscreen = cx.window_is_fullscreen(); let container_theme = if is_fullscreen { let mut container_theme = theme.workspace.titlebar.container; container_theme.padding.left = container_theme.padding.right; @@ -2154,7 +2153,7 @@ impl Workspace { } } - fn render_disconnected_overlay(&self, cx: &mut RenderContext) -> Option { + fn render_disconnected_overlay(&self, cx: &mut ViewContext) -> Option { if self.project.read(cx).is_read_only() { enum DisconnectedOverlay {} Some( @@ -2810,7 +2809,7 @@ impl View for Workspace { "Workspace" } - fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); Stack::new() .with_child( From e6cc132b192142b70f938055009f98ea7eee6f20 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 11 Apr 2023 18:48:00 -0600 Subject: [PATCH 07/58] WIP --- crates/copilot/src/sign_in.rs | 57 +++++++++++-------- crates/gpui/src/elements.rs | 2 + crates/workspace/src/dock.rs | 2 +- .../workspace/src/dock/toggle_dock_button.rs | 2 +- crates/workspace/src/item.rs | 33 +++++++---- crates/workspace/src/notifications.rs | 2 +- crates/workspace/src/pane.rs | 35 +++++++----- .../src/pane/dragged_item_receiver.rs | 12 ++-- crates/workspace/src/pane_group.rs | 6 +- crates/workspace/src/shared_screen.rs | 6 +- crates/workspace/src/sidebar.rs | 4 +- crates/workspace/src/status_bar.rs | 26 +++++---- crates/workspace/src/toolbar.rs | 4 +- crates/workspace/src/workspace.rs | 11 ++-- 14 files changed, 119 insertions(+), 83 deletions(-) diff --git a/crates/copilot/src/sign_in.rs b/crates/copilot/src/sign_in.rs index 74f9828598..0465563391 100644 --- a/crates/copilot/src/sign_in.rs +++ b/crates/copilot/src/sign_in.rs @@ -3,7 +3,8 @@ use gpui::{ elements::*, geometry::rect::RectF, platform::{WindowBounds, WindowKind, WindowOptions}, - AppContext, ClipboardItem, Element, Entity, View, ViewContext, ViewHandle, + AnyViewHandle, AppContext, ClipboardItem, Element, ElementBox, Entity, View, ViewContext, + ViewHandle, }; use settings::Settings; use theme::ui::modal; @@ -28,9 +29,9 @@ pub fn init(cx: &mut AppContext) { if let Some(code_verification_handle) = code_verification.as_mut() { if cx.has_window(code_verification_handle.window_id()) { code_verification_handle.update(cx, |code_verification_view, cx| { - code_verification_view.set_status(status, cx) + code_verification_view.set_status(status, cx); + cx.activate_window(); }); - cx.activate_window(code_verification_handle.window_id()); } else { create_copilot_auth_window(cx, &status, &mut code_verification); } @@ -41,11 +42,11 @@ pub fn init(cx: &mut AppContext) { Status::Authorized | Status::Unauthorized => { if let Some(code_verification) = code_verification.as_ref() { code_verification.update(cx, |code_verification, cx| { - code_verification.set_status(status, cx) + code_verification.set_status(status, cx); + cx.activate_window(); }); cx.platform().activate(true); - cx.activate_window(code_verification.window_id()); } } _ => { @@ -96,8 +97,8 @@ impl CopilotCodeVerification { fn render_device_code( data: &PromptUserDeviceFlow, style: &theme::Copilot, - cx: &mut gpui::ViewContext, - ) -> ElementBox { + cx: &mut ViewContext, + ) -> ElementBox { let copied = cx .read_from_clipboard() .map(|item| item.text() == &data.user_code) @@ -105,7 +106,7 @@ impl CopilotCodeVerification { let device_code_style = &style.auth.prompting.device_code; - MouseEventHandler::::new(0, cx, |state, _cx| { + MouseEventHandler::::new(0, cx, |state, _cx| { Flex::row() .with_children([ Label::new(data.user_code.clone(), device_code_style.text.clone()) @@ -132,7 +133,7 @@ impl CopilotCodeVerification { }) .on_click(gpui::platform::MouseButton::Left, { let user_code = data.user_code.clone(); - move |_, cx| { + move |_, _, cx| { cx.platform() .write_to_clipboard(ClipboardItem::new(user_code.clone())); cx.notify(); @@ -145,8 +146,10 @@ impl CopilotCodeVerification { fn render_prompting_modal( data: &PromptUserDeviceFlow, style: &theme::Copilot, - cx: &mut gpui::ViewContext, - ) -> ElementBox { + cx: &mut ViewContext, + ) -> ElementBox { + enum ConnectButton {} + Flex::column() .with_children([ Flex::column() @@ -188,14 +191,14 @@ impl CopilotCodeVerification { .contained() .with_style(style.auth.prompting.hint.container.clone()) .boxed(), - theme::ui::cta_button_with_click( + theme::ui::cta_button_with_click::( "Connect to GitHub", style.auth.content_width, &style.auth.cta_button, cx, { let verification_uri = data.verification_uri.clone(); - move |_, cx| cx.platform().open_url(&verification_uri) + move |_, _, cx| cx.platform().open_url(&verification_uri) }, ) .boxed(), @@ -205,8 +208,10 @@ impl CopilotCodeVerification { } fn render_enabled_modal( style: &theme::Copilot, - cx: &mut gpui::ViewContext, - ) -> ElementBox { + cx: &mut ViewContext, + ) -> ElementBox { + enum DoneButton {} + let enabled_style = &style.auth.authorized; Flex::column() .with_children([ @@ -237,12 +242,12 @@ impl CopilotCodeVerification { .contained() .with_style(enabled_style.hint.container) .boxed(), - theme::ui::cta_button_with_click( + theme::ui::cta_button_with_click::( "Done", style.auth.content_width, &style.auth.cta_button, cx, - |_, cx| { + |_, _, cx| { let window_id = cx.window_id(); cx.remove_window(window_id) }, @@ -254,8 +259,8 @@ impl CopilotCodeVerification { } fn render_unauthorized_modal( style: &theme::Copilot, - cx: &mut gpui::ViewContext, - ) -> ElementBox { + cx: &mut ViewContext, + ) -> ElementBox { let unauthorized_style = &style.auth.not_authorized; Flex::column() @@ -298,12 +303,12 @@ impl CopilotCodeVerification { .contained() .with_style(unauthorized_style.warning.container) .boxed(), - theme::ui::cta_button_with_click( + theme::ui::cta_button_with_click::( "Subscribe on GitHub", style.auth.content_width, &style.auth.cta_button, cx, - |_, cx| { + |_, _, cx| { let window_id = cx.window_id(); cx.remove_window(window_id); cx.platform().open_url(COPILOT_SIGN_UP_URL) @@ -325,18 +330,20 @@ impl View for CopilotCodeVerification { "CopilotCodeVerification" } - fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut gpui::ViewContext) { + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { cx.notify() } - fn focus_out(&mut self, _: gpui::AnyViewHandle, cx: &mut gpui::ViewContext) { + fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { cx.notify() } - fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + enum ConnectModal {} + let style = cx.global::().theme.clone(); - modal("Connect Copilot to Zed", &style.copilot.modal, cx, |cx| { + modal::("Connect Copilot to Zed", &style.copilot.modal, cx, |cx| { Flex::column() .with_children([ theme::ui::icon(&style.copilot.auth.header).boxed(), diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index f1a5c8dffd..ea00e155d0 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -25,6 +25,8 @@ pub use self::{ keystroke_label::*, label::*, list::*, mouse_event_handler::*, overlay::*, resizable::*, stack::*, svg::*, text::*, tooltip::*, uniform_list::*, }; +pub use crate::window::ChildView; + use self::{clipped::Clipped, expanded::Expanded}; use crate::{ geometry::{ diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 888c1d2021..87c6031a46 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -315,7 +315,7 @@ impl Dock { theme: &Theme, anchor: DockAnchor, cx: &mut ViewContext, - ) -> Option { + ) -> Option> { let style = &theme.workspace.dock; self.position diff --git a/crates/workspace/src/dock/toggle_dock_button.rs b/crates/workspace/src/dock/toggle_dock_button.rs index 55cafbea01..1db820ca1f 100644 --- a/crates/workspace/src/dock/toggle_dock_button.rs +++ b/crates/workspace/src/dock/toggle_dock_button.rs @@ -34,7 +34,7 @@ impl View for ToggleDockButton { "Dock Toggle" } - fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext) -> ElementBox { let workspace = self.workspace.upgrade(cx); if workspace.is_none() { diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 76cf874de8..f1b3f608e8 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -47,8 +47,12 @@ pub trait Item: View { fn tab_description<'a>(&'a self, _: usize, _: &'a AppContext) -> Option> { None } - fn tab_content(&self, detail: Option, style: &theme::Tab, cx: &AppContext) - -> ElementBox; + fn tab_content( + &self, + detail: Option, + style: &theme::Tab, + cx: &AppContext, + ) -> ElementBox; fn for_each_project_item(&self, _: &AppContext, _: &mut dyn FnMut(usize, &dyn project::Item)) {} fn is_singleton(&self, _cx: &AppContext) -> bool { false @@ -130,7 +134,7 @@ pub trait Item: View { ToolbarItemLocation::Hidden } - fn breadcrumbs(&self, _theme: &Theme, _cx: &AppContext) -> Option> { + fn breadcrumbs(&self, _theme: &Theme, _cx: &AppContext) -> Option>> { None } @@ -163,8 +167,12 @@ pub trait ItemHandle: 'static + fmt::Debug { handler: Box, ) -> gpui::Subscription; fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option>; - fn tab_content(&self, detail: Option, style: &theme::Tab, cx: &AppContext) - -> ElementBox; + fn tab_content( + &self, + detail: Option, + style: &theme::Tab, + cx: &AppContext, + ) -> ElementBox; fn project_path(&self, cx: &AppContext) -> Option; fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]>; fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[usize; 3]>; @@ -213,7 +221,7 @@ pub trait ItemHandle: 'static + fmt::Debug { ) -> gpui::Subscription; fn to_searchable_item_handle(&self, cx: &AppContext) -> Option>; fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation; - fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option>; + fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option>>; fn serialized_item_kind(&self) -> Option<&'static str>; fn show_toolbar(&self, cx: &AppContext) -> bool; } @@ -257,7 +265,7 @@ impl ItemHandle for ViewHandle { detail: Option, style: &theme::Tab, cx: &AppContext, - ) -> ElementBox { + ) -> ElementBox { self.read(cx).tab_content(detail, style, cx) } @@ -583,7 +591,7 @@ impl ItemHandle for ViewHandle { self.read(cx).breadcrumb_location() } - fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option> { + fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option>> { self.read(cx).breadcrumbs(theme, cx) } @@ -899,7 +907,7 @@ pub(crate) mod test { "TestItem" } - fn render(&mut self, _: &mut ViewContext) -> ElementBox { + fn render(&mut self, _: &mut ViewContext) -> ElementBox { Empty::new().boxed() } } @@ -912,7 +920,12 @@ pub(crate) mod test { }) } - fn tab_content(&self, detail: Option, _: &theme::Tab, _: &AppContext) -> ElementBox { + fn tab_content( + &self, + detail: Option, + _: &theme::Tab, + _: &AppContext, + ) -> ElementBox { self.tab_detail.set(detail); Empty::new().boxed() } diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index 8932c969f8..e071804186 100644 --- a/crates/workspace/src/notifications.rs +++ b/crates/workspace/src/notifications.rs @@ -229,7 +229,7 @@ pub mod simple_message_notification { "MessageNotification" } - fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext) -> gpui::ElementBox { let theme = cx.global::().theme.clone(); let theme = &theme.simple_message_notification; diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 6015beddf7..8c168e8ee2 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1383,8 +1383,8 @@ impl Pane { detail: Option, hovered: bool, tab_style: &theme::Tab, - cx: &mut ViewContext, - ) -> ElementBox { + cx: &mut ViewContext, + ) -> ElementBox { let title = item.tab_content(detail, &tab_style, cx); let mut container = tab_style.container.clone(); if first { @@ -1404,7 +1404,7 @@ impl Pane { }; ConstrainedBox::new( - Canvas::new(move |bounds, _, cx| { + Canvas::new(move |scene, bounds, _, cx| { if let Some(color) = icon_color { let square = RectF::new(bounds.origin(), vec2f(diameter, diameter)); scene.push_quad(Quad { @@ -1475,7 +1475,11 @@ impl Pane { .boxed() } - fn render_tab_bar_buttons(&mut self, theme: &Theme, cx: &mut ViewContext) -> ElementBox { + fn render_tab_bar_buttons( + &mut self, + theme: &Theme, + cx: &mut ViewContext, + ) -> ElementBox { Flex::row() // New menu .with_child(render_tab_bar_button( @@ -1524,7 +1528,11 @@ impl Pane { .boxed() } - fn render_blank_pane(&mut self, theme: &Theme, _cx: &mut ViewContext) -> ElementBox { + fn render_blank_pane( + &mut self, + theme: &Theme, + _cx: &mut ViewContext, + ) -> ElementBox { let background = theme.workspace.background; Empty::new() .contained() @@ -1542,7 +1550,7 @@ impl View for Pane { "Pane" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let this = cx.handle(); enum MouseNavigationHandler {} @@ -1703,7 +1711,7 @@ fn render_tab_bar_button( cx: &mut ViewContext, action: A, context_menu: Option>, -) -> ElementBox { +) -> ElementBox { enum TabBarButton {} Stack::new() @@ -1837,10 +1845,11 @@ impl NavHistory { pub struct PaneBackdrop { child_view: usize, - child: ElementBox, + child: ElementBox, } + impl PaneBackdrop { - pub fn new(pane_item_view: usize, child: ElementBox) -> Self { + pub fn new(pane_item_view: usize, child: ElementBox) -> Self { PaneBackdrop { child, child_view: pane_item_view, @@ -1906,8 +1915,8 @@ impl Element for PaneBackdrop { _visible_bounds: RectF, _layout: &Self::LayoutState, _paint: &Self::PaintState, - view: &V, - cx: &gpui::ViewContext, + view: &Pane, + cx: &gpui::ViewContext, ) -> Option { self.child.rect_for_text_range(range_utf16, view, cx) } @@ -1917,8 +1926,8 @@ impl Element for PaneBackdrop { _bounds: RectF, _layout: &Self::LayoutState, _paint: &Self::PaintState, - view: &V, - cx: &gpui::ViewContext, + view: &Pane, + cx: &gpui::ViewContext, ) -> serde_json::Value { gpui::json::json!({ "type": "Pane Back Drop", diff --git a/crates/workspace/src/pane/dragged_item_receiver.rs b/crates/workspace/src/pane/dragged_item_receiver.rs index 86db110529..2b529ac425 100644 --- a/crates/workspace/src/pane/dragged_item_receiver.rs +++ b/crates/workspace/src/pane/dragged_item_receiver.rs @@ -5,7 +5,7 @@ use gpui::{ geometry::{rect::RectF, vector::Vector2F}, platform::MouseButton, scene::MouseUp, - AppContext, Element, ElementBox, EventContext, MouseState, Quad, ViewContext, WeakViewHandle, + AppContext, Element, ElementBox, MouseState, Quad, ViewContext, WeakViewHandle, }; use project::ProjectEntryId; use settings::Settings; @@ -24,10 +24,10 @@ pub fn dragged_item_receiver( split_margin: Option, cx: &mut ViewContext, render_child: F, -) -> MouseEventHandler +) -> MouseEventHandler where Tag: 'static, - F: FnOnce(&mut MouseState, &mut ViewContext) -> ElementBox, + F: FnOnce(&mut MouseState, &mut ViewContext) -> ElementBox, { MouseEventHandler::::above(region_id, cx, |state, _, cx| { // Observing hovered will cause a render when the mouse enters regardless @@ -48,7 +48,7 @@ where Stack::new() .with_child(render_child(state, cx)) .with_children(drag_position.map(|drag_position| { - Canvas::new(move |bounds, _, cx| { + Canvas::new(move |scene, bounds, _, cx| { if bounds.contains_point(drag_position) { let overlay_region = split_margin .and_then(|split_margin| { @@ -58,7 +58,7 @@ where .map(|(dir, margin)| dir.along_edge(bounds, margin)) .unwrap_or(bounds); - cx.paint_stacking_context(None, None, |cx| { + scene.paint_stacking_context(None, None, |cx| { scene.push_quad(Quad { bounds: overlay_region, background: Some(overlay_color(cx)), @@ -102,7 +102,7 @@ pub fn handle_dropped_item( index: usize, allow_same_pane: bool, split_margin: Option, - cx: &mut ViewContext, + cx: &mut ViewContext, ) { enum Action { Move(WeakViewHandle, usize), diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index 286d3cebbe..048cb7150a 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -71,7 +71,7 @@ impl PaneGroup { active_call: Option<&ModelHandle>, active_pane: &ViewHandle, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { self.root.render( project, theme, @@ -132,7 +132,7 @@ impl Member { active_call: Option<&ModelHandle>, active_pane: &ViewHandle, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { enum FollowIntoExternalProject {} match self { @@ -367,7 +367,7 @@ impl PaneAxis { active_call: Option<&ModelHandle>, active_pane: &ViewHandle, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { let last_member_ix = self.members.len() - 1; Flex::new(self.axis) .with_children(self.members.iter().enumerate().map(|(ix, member)| { diff --git a/crates/workspace/src/shared_screen.rs b/crates/workspace/src/shared_screen.rs index cad832a56d..26db3edb01 100644 --- a/crates/workspace/src/shared_screen.rs +++ b/crates/workspace/src/shared_screen.rs @@ -64,12 +64,12 @@ impl View for SharedScreen { "SharedScreen" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { enum Focus {} let frame = self.frame.clone(); MouseEventHandler::::new(0, cx, |_, cx| { - Canvas::new(move |bounds, _, cx| { + Canvas::new(move |scene, bounds, _, cx| { if let Some(frame) = frame.clone() { let size = constrain_size_preserving_aspect_ratio( bounds.size(), @@ -103,7 +103,7 @@ impl Item for SharedScreen { _: Option, style: &theme::Tab, _: &AppContext, - ) -> gpui::ElementBox { + ) -> gpui::ElementBox { Flex::row() .with_child( Svg::new("icons/disable_screen_sharing_12.svg") diff --git a/crates/workspace/src/sidebar.rs b/crates/workspace/src/sidebar.rs index 0a0d9339a3..e9b6250a09 100644 --- a/crates/workspace/src/sidebar.rs +++ b/crates/workspace/src/sidebar.rs @@ -188,7 +188,7 @@ impl View for Sidebar { "Sidebar" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if let Some(active_item) = self.active_item() { enum ResizeHandleTag {} let style = &cx.global::().theme.workspace.sidebar; @@ -225,7 +225,7 @@ impl View for SidebarButtons { "SidebarToggleButton" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = &cx.global::().theme; let tooltip_style = theme.tooltip.clone(); let theme = &theme.workspace.status_bar.sidebar_buttons; diff --git a/crates/workspace/src/status_bar.rs b/crates/workspace/src/status_bar.rs index 3c35b986d7..ca919808ee 100644 --- a/crates/workspace/src/status_bar.rs +++ b/crates/workspace/src/status_bar.rs @@ -8,8 +8,8 @@ use gpui::{ vector::{vec2f, Vector2F}, }, json::{json, ToJson}, - AnyViewHandle, AppContext, DebugContext, ElementBox, Entity, LayoutContext, MeasurementContext, - PaintContext, SceneBuilder, SizeConstraint, Subscription, View, ViewContext, ViewHandle, + AnyViewHandle, AppContext, ElementBox, Entity, SceneBuilder, SizeConstraint, Subscription, + View, ViewContext, ViewHandle, }; use settings::Settings; @@ -42,7 +42,7 @@ impl View for StatusBar { "StatusBar" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = &cx.global::().theme.workspace.status_bar; StatusBarElement { @@ -139,19 +139,19 @@ impl From<&dyn StatusItemViewHandle> for AnyViewHandle { } struct StatusBarElement { - left: ElementBox, - right: ElementBox, + left: ElementBox, + right: ElementBox, } -impl Element for StatusBarElement { +impl Element for StatusBarElement { type LayoutState = (); type PaintState = (); fn layout( &mut self, mut constraint: SizeConstraint, - view: &mut V, - cx: &mut ViewContext, + view: &mut StatusBar, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let max_width = constraint.max.x(); constraint.min = vec2f(0., constraint.min.y()); @@ -173,8 +173,8 @@ impl Element for StatusBarElement { bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - view: &mut V, - cx: &mut ViewContext, + view: &mut StatusBar, + cx: &mut ViewContext, ) -> Self::PaintState { let origin_y = bounds.upper_right().y(); let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); @@ -195,7 +195,8 @@ impl Element for StatusBarElement { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &StatusBar, + _: &ViewContext, ) -> Option { None } @@ -205,7 +206,8 @@ impl Element for StatusBarElement { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &DebugContext, + _: &StatusBar, + _: &ViewContext, ) -> serde_json::Value { json!({ "type": "StatusBarElement", diff --git a/crates/workspace/src/toolbar.rs b/crates/workspace/src/toolbar.rs index 2ef45c0411..814abd30d4 100644 --- a/crates/workspace/src/toolbar.rs +++ b/crates/workspace/src/toolbar.rs @@ -59,7 +59,7 @@ impl View for Toolbar { "Toolbar" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = &cx.global::().theme.workspace.toolbar; let mut primary_left_items = Vec::new(); @@ -169,7 +169,7 @@ fn nav_button( tooltip_action: A, action_name: &str, cx: &mut ViewContext, -) -> ElementBox { +) -> ElementBox { MouseEventHandler::::new(0, cx, |state, _| { let style = if enabled { style.style_for(state, false) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 3253f9db6a..d107279c45 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -2053,7 +2053,7 @@ impl Workspace { self.leader_state.followers.contains(&peer_id) } - fn render_titlebar(&self, theme: &Theme, cx: &mut ViewContext) -> ElementBox { + fn render_titlebar(&self, theme: &Theme, cx: &mut ViewContext) -> ElementBox { // TODO: There should be a better system in place for this // (https://github.com/zed-industries/zed/issues/1290) let is_fullscreen = cx.window_is_fullscreen(); @@ -2153,7 +2153,10 @@ impl Workspace { } } - fn render_disconnected_overlay(&self, cx: &mut ViewContext) -> Option { + fn render_disconnected_overlay( + &self, + cx: &mut ViewContext, + ) -> Option> { if self.project.read(cx).is_read_only() { enum DisconnectedOverlay {} Some( @@ -2181,7 +2184,7 @@ impl Workspace { &self, theme: &theme::Workspace, cx: &AppContext, - ) -> Option { + ) -> Option> { if self.notifications.is_empty() { None } else { @@ -2809,7 +2812,7 @@ impl View for Workspace { "Workspace" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); Stack::new() .with_child( From d9e4136b02e36f1886bdec2705770eb38fce7df4 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 11 Apr 2023 21:56:37 -0600 Subject: [PATCH 08/58] WIP --- crates/gpui/src/app.rs | 36 +++++++ crates/gpui/src/app/window.rs | 56 +++++++--- crates/gpui/src/scene/mouse_region.rs | 8 +- crates/workspace/src/dock.rs | 22 ++-- .../workspace/src/dock/toggle_dock_button.rs | 16 +-- crates/workspace/src/item.rs | 8 +- crates/workspace/src/notifications.rs | 12 +-- crates/workspace/src/pane.rs | 78 ++++++++------ .../src/pane/dragged_item_receiver.rs | 19 ++-- crates/workspace/src/pane_group.rs | 4 +- crates/workspace/src/shared_screen.rs | 10 +- crates/workspace/src/sidebar.rs | 8 +- crates/workspace/src/toolbar.rs | 6 +- crates/workspace/src/workspace.rs | 102 ++++++++++-------- 14 files changed, 235 insertions(+), 150 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index f30ab75663..260aa5697d 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -802,6 +802,14 @@ impl AppContext { .is_some() } + pub fn window_is_active(&self, window_id: usize) -> bool { + self.windows.get(&window_id).map_or(false, |w| w.is_active) + } + + pub fn root_view(&self, window_id: usize) -> Option<&AnyViewHandle> { + self.windows.get(&window_id).map(|w| w.root_view()) + } + pub fn window_ids(&self) -> impl Iterator + '_ { self.windows.keys().copied() } @@ -1648,6 +1656,18 @@ impl AppContext { window } + pub fn replace_root_view( + &mut self, + window_id: usize, + build_root_view: F, + ) -> Option> + where + V: View, + F: FnOnce(&mut ViewContext) -> V, + { + self.update_window(window_id, |cx| cx.replace_root_view(build_root_view)) + } + pub fn add_view(&mut self, parent: &AnyViewHandle, build_view: F) -> ViewHandle where S: View, @@ -3326,6 +3346,22 @@ impl<'a, 'b, 'c, V: View> ViewContext<'a, 'b, 'c, V> { self.window.focused_view_id == Some(self.view_id) } + pub fn is_parent_view_focused(&self) -> bool { + if let Some(parent_view_id) = self.ancestors(self.window_id, self.view_id).next().clone() { + self.focused_view_id() == Some(parent_view_id) + } else { + false + } + } + + pub fn focus_parent_view(&mut self) { + let next = self.ancestors(self.window_id, self.view_id).next().clone(); + if let Some(parent_view_id) = next { + let window_id = self.window_id; + self.window_context.focus(window_id, Some(parent_view_id)); + } + } + pub fn is_child(&self, view: impl Into) -> bool { let view = view.into(); if self.window_id != view.window_id { diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 36e0a6bfd2..176ac3fd4b 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -12,8 +12,9 @@ use crate::{ }, text_layout::TextLayoutCache, util::post_inc, - AnyView, AnyViewHandle, AppContext, Element, ElementBox, MouseRegion, MouseRegionId, ParentId, - RenderParams, SceneBuilder, View, ViewContext, ViewHandle, WindowInvalidation, + AnyView, AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelContext, ModelHandle, + MouseRegion, MouseRegionId, ParentId, ReadView, RenderParams, SceneBuilder, UpdateModel, View, + ViewContext, ViewHandle, WindowInvalidation, }; use anyhow::bail; use collections::{HashMap, HashSet}; @@ -119,6 +120,22 @@ impl DerefMut for WindowContext<'_, '_> { } } +impl UpdateModel for WindowContext<'_, '_> { + fn update_model( + &mut self, + handle: &ModelHandle, + update: &mut dyn FnMut(&mut M, &mut ModelContext) -> R, + ) -> R { + self.app_context.update_model(handle, update) + } +} + +impl ReadView for WindowContext<'_, '_> { + fn read_view(&self, handle: &crate::ViewHandle) -> &W { + self.app_context.read_view(handle) + } +} + impl<'a: 'b, 'b> WindowContext<'a, 'b> { pub fn new(app_context: &'a mut AppContext, window: &'b mut Window, window_id: usize) -> Self { Self { @@ -133,6 +150,14 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { self.window_id } + pub fn app_context(&mut self) -> &mut AppContext { + self.app_context + } + + pub fn root_view(&self) -> &AnyViewHandle { + self.window.root_view() + } + pub fn window_size(&self) -> Vector2F { self.window.platform_window.content_size() } @@ -701,23 +726,22 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { } pub fn rect_for_text_range(&self, range_utf16: Range) -> Option { - todo!() + let root_view_id = self.window.root_view().id(); + self.window + .rendered_views + .get(&root_view_id)? + .rect_for_text_range(range_utf16, self, root_view_id) } pub fn debug_elements(&self) -> Option { - todo!() - // let view = self.root_view()?; - // Some(json!({ - // "root_view": view.debug_json(self), - // "root_element": self.window.rendered_views.get(&view.id()) - // .map(|root_element| { - // root_element.debug(&DebugContext { - // rendered_views: &self.window.rendered_views, - // font_cache: &self.window.font_cache, - // app: self, - // }) - // }) - // })) + let view = self.window.root_view(); + Some(json!({ + "root_view": view.debug_json(self), + "root_element": self.window.rendered_views.get(&view.id()) + .map(|root_element| { + root_element.debug(self, view.id()) + }) + })) } pub fn set_window_title(&mut self, title: &str) { diff --git a/crates/gpui/src/scene/mouse_region.rs b/crates/gpui/src/scene/mouse_region.rs index b3c05c4280..275a10ae31 100644 --- a/crates/gpui/src/scene/mouse_region.rs +++ b/crates/gpui/src/scene/mouse_region.rs @@ -11,7 +11,7 @@ use collections::HashMap; use pathfinder_geometry::rect::RectF; use smallvec::SmallVec; -use crate::{platform::MouseButton, window::WindowContext, View, ViewContext}; +use crate::{platform::MouseButton, window::WindowContext, ReadView, View, ViewContext}; use super::{ mouse_event::{ @@ -234,6 +234,12 @@ impl DerefMut for EventContext<'_, '_, '_, '_, V> { } } +impl ReadView for EventContext<'_, '_, '_, '_, V> { + fn read_view(&self, handle: &crate::ViewHandle) -> &W { + self.view_context.read_view(handle) + } +} + pub type HandlerCallback = Rc bool>; #[derive(Clone, PartialEq, Eq, Hash)] diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 87c6031a46..470125abdc 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -315,7 +315,7 @@ impl Dock { theme: &Theme, anchor: DockAnchor, cx: &mut ViewContext, - ) -> Option> { + ) -> Option> { let style = &theme.workspace.dock; self.position @@ -350,7 +350,7 @@ impl Dock { let resizable = Container::new(ChildView::new(&self.pane, cx).boxed()) .with_style(panel_style) - .with_resize_handle::( + .with_resize_handle::( resize_side as usize, resize_side, 4., @@ -362,8 +362,8 @@ impl Dock { ); let size = resizable.current_size(); - let workspace = cx.handle(); - cx.defer(move |cx| { + let workspace = cx.handle().downgrade(); + cx.defer(move |_, cx| { if let Some(workspace) = workspace.upgrade(cx) { workspace.update(cx, |workspace, _| { workspace.dock.panel_sizes.insert(anchor, size); @@ -374,20 +374,20 @@ impl Dock { if anchor == DockAnchor::Right { resizable .constrained() - .dynamically(|constraint, cx| { + .dynamically(|constraint, _, cx| { SizeConstraint::new( Vector2F::new(20., constraint.min.y()), - Vector2F::new(cx.window_size.x() * 0.8, constraint.max.y()), + Vector2F::new(cx.window_size().x() * 0.8, constraint.max.y()), ) }) .boxed() } else { resizable .constrained() - .dynamically(|constraint, cx| { + .dynamically(|constraint, _, cx| { SizeConstraint::new( Vector2F::new(constraint.min.x(), 50.), - Vector2F::new(constraint.max.x(), cx.window_size.y() * 0.8), + Vector2F::new(constraint.max.x(), cx.window_size().y() * 0.8), ) }) .boxed() @@ -399,21 +399,21 @@ impl Dock { Stack::new() .with_child( // Render wash under the dock which when clicked hides it - MouseEventHandler::::new(0, cx, |_, _| { + MouseEventHandler::::new(0, cx, |_, _| { Empty::new() .contained() .with_background_color(style.wash_color) .boxed() }) .capture_all() - .on_down(MouseButton::Left, |_, cx| { + .on_down(MouseButton::Left, |_, _, cx| { cx.dispatch_action(HideDock); }) .with_cursor_style(CursorStyle::Arrow) .boxed(), ) .with_child( - MouseEventHandler::::new(0, cx, |_state, cx| { + MouseEventHandler::::new(0, cx, |_state, cx| { ChildView::new(&self.pane, cx).boxed() }) // Make sure all events directly under the dock pane diff --git a/crates/workspace/src/dock/toggle_dock_button.rs b/crates/workspace/src/dock/toggle_dock_button.rs index 1db820ca1f..9f32048d42 100644 --- a/crates/workspace/src/dock/toggle_dock_button.rs +++ b/crates/workspace/src/dock/toggle_dock_button.rs @@ -43,11 +43,11 @@ impl View for ToggleDockButton { let workspace = workspace.unwrap(); let dock_position = workspace.read(cx).dock.position; - let dock_pane = workspace.read(cx.app).dock_pane().clone(); + let dock_pane = workspace.read(cx).dock_pane().clone(); let theme = cx.global::().theme.clone(); - let button = MouseEventHandler::::new(0, cx, { + let button = MouseEventHandler::::new(0, cx, { let theme = theme.clone(); move |state, _| { let style = theme @@ -68,17 +68,17 @@ impl View for ToggleDockButton { } }) .with_cursor_style(CursorStyle::PointingHand) - .on_up(MouseButton::Left, move |event, cx| { - let drop_index = dock_pane.read(cx.app).items_len() + 1; + .on_up(MouseButton::Left, move |event, _, cx| { + let drop_index = dock_pane.read(cx).items_len() + 1; handle_dropped_item(event, &dock_pane.downgrade(), drop_index, false, None, cx); }); if dock_position.is_visible() { button - .on_click(MouseButton::Left, |_, cx| { + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(HideDock); }) - .with_tooltip::( + .with_tooltip::( 0, "Hide Dock".into(), Some(Box::new(HideDock)), @@ -87,10 +87,10 @@ impl View for ToggleDockButton { ) } else { button - .on_click(MouseButton::Left, |_, cx| { + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(FocusDock); }) - .with_tooltip::( + .with_tooltip::( 0, "Focus Dock".into(), Some(Box::new(FocusDock)), diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index f1b3f608e8..da01686de7 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -52,7 +52,7 @@ pub trait Item: View { detail: Option, style: &theme::Tab, cx: &AppContext, - ) -> ElementBox; + ) -> ElementBox; fn for_each_project_item(&self, _: &AppContext, _: &mut dyn FnMut(usize, &dyn project::Item)) {} fn is_singleton(&self, _cx: &AppContext) -> bool { false @@ -134,7 +134,7 @@ pub trait Item: View { ToolbarItemLocation::Hidden } - fn breadcrumbs(&self, _theme: &Theme, _cx: &AppContext) -> Option>> { + fn breadcrumbs(&self, _theme: &Theme, _cx: &AppContext) -> Option>> { None } @@ -591,7 +591,7 @@ impl ItemHandle for ViewHandle { self.read(cx).breadcrumb_location() } - fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option>> { + fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option>> { self.read(cx).breadcrumbs(theme, cx) } @@ -925,7 +925,7 @@ pub(crate) mod test { detail: Option, _: &theme::Tab, _: &AppContext, - ) -> ElementBox { + ) -> ElementBox { self.tab_detail.set(detail); Empty::new().boxed() } diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index e071804186..bb91461375 100644 --- a/crates/workspace/src/notifications.rs +++ b/crates/workspace/src/notifications.rs @@ -244,7 +244,7 @@ pub mod simple_message_notification { let has_click_action = click_action.is_some(); - MouseEventHandler::::new(0, cx, |state, cx| { + MouseEventHandler::::new(0, cx, |state, cx| { Flex::column() .with_child( Flex::row() @@ -259,7 +259,7 @@ pub mod simple_message_notification { .boxed(), ) .with_child( - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = theme.dismiss_button.style_for(state, false); Svg::new("icons/x_mark_8.svg") .with_color(style.color) @@ -274,7 +274,7 @@ pub mod simple_message_notification { .boxed() }) .with_padding(Padding::uniform(5.)) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(CancelMessageNotification) }) .with_cursor_style(CursorStyle::PointingHand) @@ -312,9 +312,9 @@ pub mod simple_message_notification { .boxed() }) // Since we're not using a proper overlay, we have to capture these extra events - .on_down(MouseButton::Left, |_, _| {}) - .on_up(MouseButton::Left, |_, _| {}) - .on_click(MouseButton::Left, move |_, cx| { + .on_down(MouseButton::Left, |_, _, _| {}) + .on_up(MouseButton::Left, |_, _, _| {}) + .on_click(MouseButton::Left, move |_, _, cx| { if let Some(click_action) = click_action.as_ref() { cx.dispatch_any_action(click_action.boxed_clone()); cx.dispatch_action(CancelMessageNotification) diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 8c168e8ee2..df8290816c 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1220,10 +1220,10 @@ impl Pane { }); } - fn render_tabs(&mut self, cx: &mut ViewContext) -> impl Element { + fn render_tabs(&mut self, cx: &mut ViewContext) -> impl Element { let theme = cx.global::().theme.clone(); - let pane = cx.handle(); + let pane = cx.handle().downgrade(); let autoscroll = if mem::take(&mut self.autoscroll) { Some(self.active_item_index) } else { @@ -1233,7 +1233,7 @@ impl Pane { let pane_active = self.is_active; enum Tabs {} - let mut row = Flex::row().scrollable::(1, autoscroll, cx); + let mut row = Flex::row().scrollable::(1, autoscroll, cx); for (ix, (item, detail)) in self .items .iter() @@ -1260,8 +1260,8 @@ impl Pane { let hovered = mouse_state.hovered(); enum Tab {} - MouseEventHandler::::new(ix, cx, |_, cx| { - Self::render_tab( + MouseEventHandler::::new(ix, cx, |_, cx| { + Self::render_tab::( &item, pane.clone(), ix == 0, @@ -1271,12 +1271,12 @@ impl Pane { cx, ) }) - .on_down(MouseButton::Left, move |_, cx| { + .on_down(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(ActivateItem(ix)); }) .on_click(MouseButton::Middle, { let item = item.clone(); - move |_, cx: &mut EventContext| { + move |_, _, cx: &mut EventContext| { cx.dispatch_action(CloseItem { item_id: item.id(), pane: pane.clone(), @@ -1301,9 +1301,9 @@ impl Pane { let theme = cx.global::().theme.clone(); let detail = detail.clone(); - move |dragged_item, cx: &mut ViewContext| { + move |dragged_item: &DraggedItem, cx: &mut ViewContext| { let tab_style = &theme.workspace.tab_bar.dragged_tab; - Self::render_tab( + Self::render_tab::( &dragged_item.item, dragged_item.pane.clone(), false, @@ -1404,7 +1404,7 @@ impl Pane { }; ConstrainedBox::new( - Canvas::new(move |scene, bounds, _, cx| { + Canvas::new(move |scene, bounds, _, _, cx| { if let Some(color) = icon_color { let square = RectF::new(bounds.origin(), vec2f(diameter, diameter)); scene.push_quad(Quad { @@ -1441,18 +1441,22 @@ impl Pane { let item_id = item.id(); enum TabCloseButton {} let icon = Svg::new("icons/x_mark_8.svg"); - MouseEventHandler::::new(item_id, cx, |mouse_state, _| { - if mouse_state.hovered() { - icon.with_color(tab_style.icon_close_active).boxed() - } else { - icon.with_color(tab_style.icon_close).boxed() - } - }) + MouseEventHandler::::new( + item_id, + cx, + |mouse_state, _| { + if mouse_state.hovered() { + icon.with_color(tab_style.icon_close_active).boxed() + } else { + icon.with_color(tab_style.icon_close).boxed() + } + }, + ) .with_padding(Padding::uniform(4.)) .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, { let pane = pane.clone(); - move |_, cx| { + move |_, _, cx| { cx.dispatch_action(CloseItem { item_id, pane: pane.clone(), @@ -1551,13 +1555,13 @@ impl View for Pane { } fn render(&mut self, cx: &mut ViewContext) -> ElementBox { - let this = cx.handle(); + let this = cx.handle().downgrade(); enum MouseNavigationHandler {} Stack::new() .with_child( - MouseEventHandler::::new(0, cx, |_, cx| { + MouseEventHandler::::new(0, cx, |_, cx| { let active_item_index = self.active_item_index; if let Some(active_item) = self.active_item() { @@ -1569,13 +1573,17 @@ impl View for Pane { enum TabBarEventHandler {} stack.add_child( - MouseEventHandler::::new(0, cx, |_, _| { - Empty::new() - .contained() - .with_style(theme.workspace.tab_bar.container) - .boxed() - }) - .on_down(MouseButton::Left, move |_, cx| { + MouseEventHandler::::new( + 0, + cx, + |_, _| { + Empty::new() + .contained() + .with_style(theme.workspace.tab_bar.container) + .boxed() + }, + ) + .on_down(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(ActivateItem(active_item_index)); }) .boxed(), @@ -1635,7 +1643,7 @@ impl View for Pane { dragged_item_receiver::(0, 0, false, None, cx, |_, cx| { self.render_blank_pane(&theme, cx) }) - .on_down(MouseButton::Left, |_, cx| { + .on_down(MouseButton::Left, |_, _, cx| { cx.focus_parent_view(); }) .boxed() @@ -1643,7 +1651,7 @@ impl View for Pane { }) .on_down(MouseButton::Navigate(NavigationDirection::Back), { let this = this.clone(); - move |_, cx| { + move |_, _, cx| { cx.dispatch_action(GoBack { pane: Some(this.clone()), }); @@ -1651,7 +1659,7 @@ impl View for Pane { }) .on_down(MouseButton::Navigate(NavigationDirection::Forward), { let this = this.clone(); - move |_, cx| { + move |_, _, cx| { cx.dispatch_action(GoForward { pane: Some(this.clone()), }) @@ -1716,7 +1724,7 @@ fn render_tab_bar_button( Stack::new() .with_child( - MouseEventHandler::::new(index, cx, |mouse_state, cx| { + MouseEventHandler::::new(index, cx, |mouse_state, cx| { let theme = &cx.global::().theme.workspace.tab_bar; let style = theme.pane_button.style_for(mouse_state, false); Svg::new(icon) @@ -1730,7 +1738,7 @@ fn render_tab_bar_button( .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(action.clone()); }) .boxed(), @@ -1895,9 +1903,9 @@ impl Element for PaneBackdrop { scene.push_mouse_region( MouseRegion::new::(child_view_id, 0, visible_bounds).on_down( gpui::platform::MouseButton::Left, - move |_, cx| { - let window_id = cx.window_id; - cx.focus(window_id, Some(child_view_id)) + move |_, _: &mut Pane, cx| { + let window_id = cx.window_id(); + cx.app_context().focus(window_id, Some(child_view_id)) }, ), ); diff --git a/crates/workspace/src/pane/dragged_item_receiver.rs b/crates/workspace/src/pane/dragged_item_receiver.rs index 2b529ac425..f1117cd980 100644 --- a/crates/workspace/src/pane/dragged_item_receiver.rs +++ b/crates/workspace/src/pane/dragged_item_receiver.rs @@ -5,7 +5,8 @@ use gpui::{ geometry::{rect::RectF, vector::Vector2F}, platform::MouseButton, scene::MouseUp, - AppContext, Element, ElementBox, MouseState, Quad, ViewContext, WeakViewHandle, + AppContext, Element, ElementBox, EventContext, MouseState, Quad, View, ViewContext, + WeakViewHandle, }; use project::ProjectEntryId; use settings::Settings; @@ -29,7 +30,7 @@ where Tag: 'static, F: FnOnce(&mut MouseState, &mut ViewContext) -> ElementBox, { - MouseEventHandler::::above(region_id, cx, |state, _, cx| { + MouseEventHandler::::above(region_id, cx, |state, cx| { // Observing hovered will cause a render when the mouse enters regardless // of if mouse position was accessed before let drag_position = if state.hovered() { @@ -48,7 +49,7 @@ where Stack::new() .with_child(render_child(state, cx)) .with_children(drag_position.map(|drag_position| { - Canvas::new(move |scene, bounds, _, cx| { + Canvas::new(move |scene, bounds, _, _, cx| { if bounds.contains_point(drag_position) { let overlay_region = split_margin .and_then(|split_margin| { @@ -58,7 +59,7 @@ where .map(|(dir, margin)| dir.along_edge(bounds, margin)) .unwrap_or(bounds); - scene.paint_stacking_context(None, None, |cx| { + scene.paint_stacking_context(None, None, |scene| { scene.push_quad(Quad { bounds: overlay_region, background: Some(overlay_color(cx)), @@ -73,13 +74,13 @@ where .boxed() }) .on_up(MouseButton::Left, { - let pane = cx.handle(); - move |event, cx| { + let pane = cx.handle().downgrade(); + move |event, _, cx| { handle_dropped_item(event, &pane, drop_index, allow_same_pane, split_margin, cx); cx.notify(); } }) - .on_move(|_, cx| { + .on_move(|_, _, cx| { let drag_and_drop = cx.global::>(); if drag_and_drop @@ -96,13 +97,13 @@ where }) } -pub fn handle_dropped_item( +pub fn handle_dropped_item( event: MouseUp, pane: &WeakViewHandle, index: usize, allow_same_pane: bool, split_margin: Option, - cx: &mut ViewContext, + cx: &mut EventContext, ) { enum Action { Move(WeakViewHandle, usize), diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index 048cb7150a..96024c09e4 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -176,7 +176,7 @@ impl Member { let leader_user = leader.user.clone(); let leader_user_id = leader.user.id; Some( - MouseEventHandler::::new( + MouseEventHandler::::new( pane.id(), cx, |_, _| { @@ -199,7 +199,7 @@ impl Member { }, ) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(JoinProject { project_id: leader_project_id, follow_user_id: leader_user_id, diff --git a/crates/workspace/src/shared_screen.rs b/crates/workspace/src/shared_screen.rs index 26db3edb01..383651b991 100644 --- a/crates/workspace/src/shared_screen.rs +++ b/crates/workspace/src/shared_screen.rs @@ -1,6 +1,6 @@ use crate::{ item::{Item, ItemEvent}, - ItemNavHistory, WorkspaceId, + ItemNavHistory, Pane, WorkspaceId, }; use call::participant::{Frame, RemoteVideoTrack}; use client::{proto::PeerId, User}; @@ -68,8 +68,8 @@ impl View for SharedScreen { enum Focus {} let frame = self.frame.clone(); - MouseEventHandler::::new(0, cx, |_, cx| { - Canvas::new(move |scene, bounds, _, cx| { + MouseEventHandler::::new(0, cx, |_, cx| { + Canvas::new(move |scene, bounds, _, _, cx| { if let Some(frame) = frame.clone() { let size = constrain_size_preserving_aspect_ratio( bounds.size(), @@ -86,7 +86,7 @@ impl View for SharedScreen { .with_style(cx.global::().theme.shared_screen) .boxed() }) - .on_down(MouseButton::Left, |_, cx| cx.focus_parent_view()) + .on_down(MouseButton::Left, |_, _, cx| cx.focus_parent_view()) .boxed() } } @@ -103,7 +103,7 @@ impl Item for SharedScreen { _: Option, style: &theme::Tab, _: &AppContext, - ) -> gpui::ElementBox { + ) -> gpui::ElementBox { Flex::row() .with_child( Svg::new("icons/disable_screen_sharing_12.svg") diff --git a/crates/workspace/src/sidebar.rs b/crates/workspace/src/sidebar.rs index e9b6250a09..ad9af37ad6 100644 --- a/crates/workspace/src/sidebar.rs +++ b/crates/workspace/src/sidebar.rs @@ -195,7 +195,7 @@ impl View for Sidebar { ChildView::new(active_item.as_any(), cx) .contained() .with_style(style.container) - .with_resize_handle::( + .with_resize_handle::( self.sidebar_side as usize, self.sidebar_side.to_resizable_side(), 4., @@ -254,7 +254,7 @@ impl View for SidebarButtons { sidebar_side, item_index: ix, }; - MouseEventHandler::::new(ix, cx, |state, cx| { + MouseEventHandler::::new(ix, cx, |state, cx| { let is_active = is_open && ix == active_ix; let style = item_style.style_for(state, is_active); Stack::new() @@ -283,9 +283,9 @@ impl View for SidebarButtons { .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, { let action = action.clone(); - move |_, cx| cx.dispatch_action(action.clone()) + move |_, _, cx| cx.dispatch_action(action.clone()) }) - .with_tooltip::( + .with_tooltip::( ix, tooltip, Some(Box::new(action)), diff --git a/crates/workspace/src/toolbar.rs b/crates/workspace/src/toolbar.rs index 814abd30d4..8fb10737e1 100644 --- a/crates/workspace/src/toolbar.rs +++ b/crates/workspace/src/toolbar.rs @@ -170,7 +170,7 @@ fn nav_button( action_name: &str, cx: &mut ViewContext, ) -> ElementBox { - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = if enabled { style.style_for(state, false) } else { @@ -194,10 +194,10 @@ fn nav_button( } else { CursorStyle::default() }) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(action.clone()) }) - .with_tooltip::( + .with_tooltip::( 0, action_name.to_string(), Some(Box::new(tooltip_action)), diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index d107279c45..15987d647f 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -928,11 +928,7 @@ impl Workspace { workspace }; - let workspace = if let Some(window_id) = requesting_window_id { - cx.update(|cx| { - cx.replace_root_view(window_id, |cx| build_workspace(cx, serialized_workspace)) - }) - } else { + let workspace = { let (bounds, display) = if let Some(bounds) = window_bounds_override { (Some(bounds), None) } else { @@ -1133,7 +1129,14 @@ impl Workspace { let window_id = cx.window_id(); let workspace_count = cx .window_ids() - .filter_map(|window_id| cx.root_view(window_id)?.clone().downcast::()) + .collect::>() + .into_iter() + .filter_map(|window_id| { + cx.app_context() + .root_view(window_id)? + .clone() + .downcast::() + }) .count(); cx.spawn(|this, mut cx| async move { @@ -1142,23 +1145,22 @@ impl Workspace { && workspace_count == 1 && active_call.read_with(&cx, |call, _| call.room().is_some()) { - let answer = cx - .prompt( - window_id, - PromptLevel::Warning, - "Do you want to leave the current call?", - &["Close window and hang up", "Cancel"], - ) - .next() - .await; + let answer = cx.prompt( + window_id, + PromptLevel::Warning, + "Do you want to leave the current call?", + &["Close window and hang up", "Cancel"], + ); - if answer == Some(1) { - return anyhow::Ok(false); - } else { - active_call - .update(&mut cx, |call, cx| call.hang_up(cx)) - .await - .log_err(); + if let Some(mut answer) = answer { + if answer.next().await == Some(1) { + return anyhow::Ok(false); + } else { + active_call + .update(&mut cx, |call, cx| call.hang_up(cx)) + .await + .log_err(); + } } } } @@ -1621,7 +1623,7 @@ impl Workspace { > { let project = self.project().clone(); let project_item = project.update(cx, |project, cx| project.open_path(path, cx)); - cx.as_mut().spawn(|mut cx| async move { + cx.spawn(|_, mut cx| async move { let (project_entry_id, project_item) = project_item.await?; let build_item = cx.update(|cx| { cx.default_global::() @@ -1802,15 +1804,14 @@ impl Workspace { } let item = pane.read(cx).active_item()?; - let maybe_pane_handle = - if let Some(clone) = item.clone_on_split(self.database_id(), cx.as_mut()) { - let new_pane = self.add_pane(cx); - Pane::add_item(self, &new_pane, clone, true, true, None, cx); - self.center.split(&pane, &new_pane, direction).unwrap(); - Some(new_pane) - } else { - None - }; + let maybe_pane_handle = if let Some(clone) = item.clone_on_split(self.database_id(), cx) { + let new_pane = self.add_pane(cx); + Pane::add_item(self, &new_pane, clone, true, true, None, cx); + self.center.split(&pane, &new_pane, direction).unwrap(); + Some(new_pane) + } else { + None + }; cx.notify(); maybe_pane_handle } @@ -2067,7 +2068,7 @@ impl Workspace { enum TitleBar {} ConstrainedBox::new( - MouseEventHandler::::new(0, cx, |_, cx| { + MouseEventHandler::::new(0, cx, |_, cx| { Container::new( Stack::new() .with_children( @@ -2080,9 +2081,9 @@ impl Workspace { .with_style(container_theme) .boxed() }) - .on_click(MouseButton::Left, |event, cx| { + .on_click(MouseButton::Left, |event, _, cx| { if event.click_count == 2 { - cx.zoom_window(cx.window_id()); + cx.zoom_window(); } }) .boxed(), @@ -2160,7 +2161,7 @@ impl Workspace { if self.project.read(cx).is_read_only() { enum DisconnectedOverlay {} Some( - MouseEventHandler::::new(0, cx, |_, cx| { + MouseEventHandler::::new(0, cx, |_, cx| { let theme = &cx.global::().theme; Label::new( "Your connection to the remote project has been lost.", @@ -2828,11 +2829,11 @@ impl View for Workspace { Some( ChildView::new(&self.left_sidebar, cx) .constrained() - .dynamically(|constraint, cx| { + .dynamically(|constraint, _, cx| { SizeConstraint::new( Vector2F::new(20., constraint.min.y()), Vector2F::new( - cx.window_size.x() * 0.8, + cx.window_size().x() * 0.8, constraint.max.y(), ), ) @@ -2874,11 +2875,11 @@ impl View for Workspace { Some( ChildView::new(&self.right_sidebar, cx) .constrained() - .dynamically(|constraint, cx| { + .dynamically(|constraint, _, cx| { SizeConstraint::new( Vector2F::new(20., constraint.min.y()), Vector2F::new( - cx.window_size.x() * 0.8, + cx.window_size().x() * 0.8, constraint.max.y(), ), ) @@ -2998,12 +2999,21 @@ pub fn activate_workspace_for_project( predicate: impl Fn(&mut Project, &mut ModelContext) -> bool, ) -> Option> { for window_id in cx.window_ids().collect::>() { - if let Some(workspace_handle) = cx.root_view(window_id)?.downcast_ref::() { - let project = workspace_handle.read(cx).project.clone(); - if project.update(cx, &predicate) { - cx.activate_window(window_id); - return Some(workspace_handle.clone()); - } + let handle = cx + .update_window(window_id, |cx| { + if let Some(workspace_handle) = cx.root_view().clone().downcast::() { + let project = workspace_handle.read(cx).project.clone(); + if project.update(cx, &predicate) { + cx.activate_window(); + return Some(workspace_handle.clone()); + } + } + None + }) + .flatten(); + + if handle.is_some() { + return handle; } } None From b54f08db7761bf6e9bcea4ebfbf4902069797aad Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 12 Apr 2023 06:51:03 -0600 Subject: [PATCH 09/58] WIP --- .../src/activity_indicator.rs | 4 +- crates/auto_update/src/update_notification.rs | 12 +- crates/copilot_button/src/copilot_button.rs | 4 +- crates/diagnostics/src/diagnostics.rs | 8 +- crates/diagnostics/src/items.rs | 6 +- crates/editor/src/display_map/block_map.rs | 22 +- crates/editor/src/editor.rs | 40 +-- crates/editor/src/element.rs | 258 +++++++++--------- crates/editor/src/hover_popover.rs | 20 +- crates/editor/src/items.rs | 10 +- crates/go_to_line/src/go_to_line.rs | 2 +- crates/gpui/src/app/window.rs | 23 +- crates/gpui/src/gpui.rs | 2 +- crates/gpui/src/scene/mouse_region.rs | 33 ++- crates/picker/src/picker.rs | 18 +- crates/project_panel/src/project_panel.rs | 32 +-- crates/search/src/buffer_search.rs | 30 +- crates/search/src/project_search.rs | 33 ++- crates/terminal_view/src/terminal_button.rs | 8 +- crates/terminal_view/src/terminal_element.rs | 75 +++-- crates/terminal_view/src/terminal_view.rs | 8 +- crates/theme_testbench/src/theme_testbench.rs | 26 +- 22 files changed, 374 insertions(+), 300 deletions(-) diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index 99b0b9dc8b..fe77467ad1 100644 --- a/crates/activity_indicator/src/activity_indicator.rs +++ b/crates/activity_indicator/src/activity_indicator.rs @@ -314,14 +314,14 @@ impl View for ActivityIndicator { "ActivityIndicator" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let Content { icon, message, action, } = self.content_to_render(cx); - let mut element = MouseEventHandler::::new(0, cx, |state, cx| { + let mut element = MouseEventHandler::::new(0, cx, |state, cx| { let theme = &cx .global::() .theme diff --git a/crates/auto_update/src/update_notification.rs b/crates/auto_update/src/update_notification.rs index c3a8f9ed69..d911130797 100644 --- a/crates/auto_update/src/update_notification.rs +++ b/crates/auto_update/src/update_notification.rs @@ -26,13 +26,13 @@ impl View for UpdateNotification { "UpdateNotification" } - fn render(&mut self, cx: &mut gpui::ViewContext) -> gpui::ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext) -> gpui::ElementBox { let theme = cx.global::().theme.clone(); let theme = &theme.update_notification; let app_name = cx.global::().display_name(); - MouseEventHandler::::new(0, cx, |state, cx| { + MouseEventHandler::::new(0, cx, |state, cx| { Flex::column() .with_child( Flex::row() @@ -50,7 +50,7 @@ impl View for UpdateNotification { .boxed(), ) .with_child( - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = theme.dismiss_button.style_for(state, false); Svg::new("icons/x_mark_8.svg") .with_color(style.color) @@ -65,7 +65,9 @@ impl View for UpdateNotification { .boxed() }) .with_padding(Padding::uniform(5.)) - .on_click(MouseButton::Left, move |_, cx| cx.dispatch_action(Cancel)) + .on_click(MouseButton::Left, move |_, _, cx| { + cx.dispatch_action(Cancel) + }) .aligned() .constrained() .with_height(cx.font_cache().line_height(theme.message.text.font_size)) @@ -87,7 +89,7 @@ impl View for UpdateNotification { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, cx| { + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(ViewReleaseNotes) }) .boxed() diff --git a/crates/copilot_button/src/copilot_button.rs b/crates/copilot_button/src/copilot_button.rs index e9e83d4f0c..dd0d4e2e58 100644 --- a/crates/copilot_button/src/copilot_button.rs +++ b/crates/copilot_button/src/copilot_button.rs @@ -91,7 +91,7 @@ impl View for CopilotButton { "CopilotButton" } - fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let settings = cx.global::(); if !settings.enable_copilot_integration { @@ -111,7 +111,7 @@ impl View for CopilotButton { Stack::new() .with_child( - MouseEventHandler::::new(0, cx, { + MouseEventHandler::::new(0, cx, { let theme = theme.clone(); let status = status.clone(); move |state, _cx| { diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index a341ea4449..9b7445559f 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -86,7 +86,7 @@ impl View for ProjectDiagnosticsEditor { "ProjectDiagnosticsEditor" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if self.path_states.is_empty() { let theme = &cx.global::().theme.project_diagnostics; Label::new("No problems in workspace", theme.empty_message.clone()) @@ -509,7 +509,7 @@ impl Item for ProjectDiagnosticsEditor { _detail: Option, style: &theme::Tab, cx: &AppContext, - ) -> ElementBox { + ) -> ElementBox { render_summary( &self.summary, &style.label.text, @@ -691,7 +691,7 @@ pub(crate) fn render_summary( summary: &DiagnosticSummary, text_style: &TextStyle, theme: &theme::ProjectDiagnostics, -) -> ElementBox { +) -> ElementBox { if summary.error_count == 0 && summary.warning_count == 0 { Label::new("No problems", text_style.clone()).boxed() } else { @@ -1186,7 +1186,7 @@ mod tests { let name = match block { TransformBlock::Custom(block) => block .render(&mut BlockContext { - cx, + view_context: cx, anchor_x: 0., scroll_x: 0., gutter_padding: 0., diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index 5c8f91e32f..b6116eaec3 100644 --- a/crates/diagnostics/src/items.rs +++ b/crates/diagnostics/src/items.rs @@ -84,14 +84,14 @@ impl View for DiagnosticIndicator { "DiagnosticIndicator" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { enum Summary {} enum Message {} let tooltip_style = cx.global::().theme.tooltip.clone(); let in_progress = !self.in_progress_checks.is_empty(); let mut element = Flex::row().with_child( - MouseEventHandler::::new(0, cx, |state, cx| { + MouseEventHandler::::new(0, cx, |state, cx| { let style = cx .global::() .theme @@ -189,7 +189,7 @@ impl View for DiagnosticIndicator { } else if let Some(diagnostic) = &self.current_diagnostic { let message_style = style.diagnostic_message.clone(); element.add_child( - MouseEventHandler::::new(1, cx, |state, _| { + MouseEventHandler::::new(1, cx, |state, _| { Label::new( diagnostic.message.split('\n').next().unwrap().to_string(), message_style.style_for(state, false).text.clone(), diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index a88c96863b..190181be73 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -2,7 +2,7 @@ use super::{ wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot}, TextHighlights, }; -use crate::{Anchor, ExcerptId, ExcerptRange, ToPoint as _}; +use crate::{Anchor, Editor, ExcerptId, ExcerptRange, ToPoint as _}; use collections::{Bound, HashMap, HashSet}; use gpui::{fonts::HighlightStyle, ElementBox, ViewContext}; use language::{BufferSnapshot, Chunk, Patch, Point}; @@ -50,7 +50,7 @@ struct BlockRow(u32); #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] struct WrapRow(u32); -pub type RenderBlock = Arc ElementBox>; +pub type RenderBlock = Arc ElementBox>; pub struct Block { id: BlockId, @@ -69,7 +69,7 @@ where pub position: P, pub height: u8, pub style: BlockStyle, - pub render: Arc ElementBox>, + pub render: Arc ElementBox>, pub disposition: BlockDisposition, } @@ -80,8 +80,8 @@ pub enum BlockStyle { Sticky, } -pub struct BlockContext<'a, 'b> { - pub cx: &'b mut ViewContext<'a, crate::Editor>, +pub struct BlockContext<'a, 'b, 'c, 'd> { + pub view_context: &'d mut ViewContext<'a, 'b, 'c, Editor>, pub anchor_x: f32, pub scroll_x: f32, pub gutter_width: f32, @@ -932,22 +932,22 @@ impl BlockDisposition { } } -impl<'a, 'b> Deref for BlockContext<'a, 'b> { - type Target = ViewContext<'a, crate::Editor>; +impl<'a, 'b, 'c, 'd> Deref for BlockContext<'a, 'b, 'c, 'd> { + type Target = ViewContext<'a, 'b, 'c, Editor>; fn deref(&self) -> &Self::Target { - self.cx + self.view_context } } -impl<'a, 'b> DerefMut for BlockContext<'a, 'b> { +impl DerefMut for BlockContext<'_, '_, '_, '_> { fn deref_mut(&mut self) -> &mut Self::Target { - self.cx + self.view_context } } impl Block { - pub fn render(&self, cx: &mut BlockContext) -> ElementBox { + pub fn render(&self, cx: &mut BlockContext) -> ElementBox { self.render.lock()(cx) } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index fba189b709..5a2f5581d7 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -722,7 +722,7 @@ impl ContextMenu { cursor_position: DisplayPoint, style: EditorStyle, cx: &mut ViewContext, - ) -> (DisplayPoint, ElementBox) { + ) -> (DisplayPoint, ElementBox) { match self { ContextMenu::Completions(menu) => (cursor_position, menu.render(style, cx)), ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx), @@ -774,7 +774,7 @@ impl CompletionsMenu { !self.matches.is_empty() } - fn render(&self, style: EditorStyle, cx: &mut ViewContext) -> ElementBox { + fn render(&self, style: EditorStyle, cx: &mut ViewContext) -> ElementBox { enum CompletionTag {} let completions = self.completions.clone(); @@ -791,7 +791,7 @@ impl CompletionsMenu { let completion = &completions[mat.candidate_id]; let item_ix = start_ix + ix; items.push( - MouseEventHandler::::new( + MouseEventHandler::::new( mat.candidate_id, cx, |state, _| { @@ -820,7 +820,7 @@ impl CompletionsMenu { }, ) .with_cursor_style(CursorStyle::PointingHand) - .on_down(MouseButton::Left, move |_, cx| { + .on_down(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(ConfirmCompletion { item_ix: Some(item_ix), }); @@ -951,7 +951,7 @@ impl CodeActionsMenu { mut cursor_position: DisplayPoint, style: EditorStyle, cx: &mut ViewContext, - ) -> (DisplayPoint, ElementBox) { + ) -> (DisplayPoint, ElementBox) { enum ActionTag {} let container_style = style.autocomplete.container; @@ -966,7 +966,7 @@ impl CodeActionsMenu { for (ix, action) in actions[range].iter().enumerate() { let item_ix = start_ix + ix; items.push( - MouseEventHandler::::new(item_ix, cx, |state, _| { + MouseEventHandler::::new(item_ix, cx, |state, _| { let item_style = if item_ix == selected_item { style.autocomplete.selected_item } else if state.hovered() { @@ -982,7 +982,7 @@ impl CodeActionsMenu { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_down(MouseButton::Left, move |_, cx| { + .on_down(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(ConfirmCodeAction { item_ix: Some(item_ix), }); @@ -2929,18 +2929,18 @@ impl Editor { style: &EditorStyle, active: bool, cx: &mut ViewContext, - ) -> Option { + ) -> Option> { if self.available_code_actions.is_some() { enum CodeActions {} Some( - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { Svg::new("icons/bolt_8.svg") .with_color(style.code_actions.indicator.style_for(state, active).color) .boxed() }) .with_cursor_style(CursorStyle::PointingHand) .with_padding(Padding::uniform(3.)) - .on_down(MouseButton::Left, |_, cx| { + .on_down(MouseButton::Left, |_, _, cx| { cx.dispatch_action(ToggleCodeActions { deployed_from_indicator: true, }); @@ -2960,7 +2960,7 @@ impl Editor { line_height: f32, gutter_margin: f32, cx: &mut ViewContext, - ) -> Vec> { + ) -> Vec>> { enum FoldIndicators {} let style = style.folds.clone(); @@ -2972,10 +2972,10 @@ impl Editor { fold_data .map(|(fold_status, buffer_row, active)| { (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| { - MouseEventHandler::::new( + MouseEventHandler::::new( ix as usize, cx, - |mouse_state, _| -> ElementBox { + |mouse_state, _| -> ElementBox { Svg::new(match fold_status { FoldStatus::Folded => style.folded_icon.clone(), FoldStatus::Foldable => style.foldable_icon.clone(), @@ -3002,7 +3002,7 @@ impl Editor { .with_cursor_style(CursorStyle::PointingHand) .with_padding(Padding::uniform(3.)) .on_click(MouseButton::Left, { - move |_, cx| { + move |_, _, cx| { cx.dispatch_any_action(match fold_status { FoldStatus::Folded => Box::new(UnfoldAt { buffer_row }), FoldStatus::Foldable => Box::new(FoldAt { buffer_row }), @@ -3028,7 +3028,7 @@ impl Editor { cursor_position: DisplayPoint, style: EditorStyle, cx: &mut ViewContext, - ) -> Option<(DisplayPoint, ElementBox)> { + ) -> Option<(DisplayPoint, ElementBox)> { self.context_menu .as_ref() .map(|menu| menu.render(cursor_position, style, cx)) @@ -3911,7 +3911,7 @@ impl Editor { pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext) { self.transact(cx, |this, cx| { - if let Some(item) = cx.as_mut().read_from_clipboard() { + if let Some(item) = cx.read_from_clipboard() { let mut clipboard_text = Cow::Borrowed(item.text()); if let Some(mut clipboard_selections) = item.metadata::>() { let old_selections = this.selections.all::(cx); @@ -5793,7 +5793,7 @@ impl Editor { self.pending_rename.as_ref() } - fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option>> { + fn format(&mut self, _: &Format, cx: &mut ViewContext) -> Option>> { let project = match &self.project { Some(project) => project.clone(), None => return None, @@ -5806,7 +5806,7 @@ impl Editor { &mut self, project: ModelHandle, trigger: FormatTrigger, - cx: &mut ViewContext<'_, Self>, + cx: &mut ViewContext, ) -> Task> { let buffer = self.buffer().clone(); let buffers = buffer.read(cx).all_buffers(); @@ -6795,7 +6795,7 @@ impl Entity for Editor { } impl View for Editor { - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let style = self.style(cx); let font_changed = self.display_map.update(cx, |map, cx| { map.set_fold_ellipses_color(style.folds.ellipses.text_color); @@ -6804,7 +6804,7 @@ impl View for Editor { if font_changed { let handle = self.handle.clone(); - cx.defer(move |cx: &mut ViewContext| { + cx.defer(move |_, cx: &mut ViewContext| { if let Some(editor) = handle.upgrade(cx) { editor.update(cx, |editor, cx| { hide_hover(editor, &HideHover, cx); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 59fe561e48..d318ddd307 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -31,8 +31,8 @@ use gpui::{ json::{self, ToJson}, platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent}, text_layout::{self, Line, RunStyle, TextLayoutCache}, - AppContext, Axis, Border, CursorRegion, Element, ElementBox, MouseRegion, Quad, SceneBuilder, - SizeConstraint, ViewContext, WeakViewHandle, + AppContext, Axis, Border, CursorRegion, Element, ElementBox, EventContext, MouseRegion, Quad, + SceneBuilder, SizeConstraint, ViewContext, WeakViewHandle, WindowContext, }; use itertools::Itertools; use json::json; @@ -98,10 +98,6 @@ impl EditorElement { } } - fn view<'a>(&self, cx: &'a AppContext) -> &'a Editor { - self.view.upgrade(cx).unwrap().read(cx) - } - fn update_view(&self, cx: &mut AppContext, f: F) -> T where F: FnOnce(&mut Editor, &mut ViewContext) -> T, @@ -114,6 +110,7 @@ impl EditorElement { } fn attach_mouse_handlers( + scene: &mut SceneBuilder, view: &WeakViewHandle, position_map: &Arc, has_popovers: bool, @@ -121,14 +118,14 @@ impl EditorElement { text_bounds: RectF, gutter_bounds: RectF, bounds: RectF, - cx: &mut PaintContext, + cx: &mut ViewContext, ) { enum EditorElementMouseHandlers {} scene.push_mouse_region( MouseRegion::new::(view.id(), view.id(), visible_bounds) .on_down(MouseButton::Left, { let position_map = position_map.clone(); - move |e, cx| { + move |e, _, cx| { if !Self::mouse_down( e.platform_event, position_map.as_ref(), @@ -142,7 +139,7 @@ impl EditorElement { }) .on_down(MouseButton::Right, { let position_map = position_map.clone(); - move |e, cx| { + move |e, _, cx| { if !Self::mouse_right_down( e.position, position_map.as_ref(), @@ -156,7 +153,7 @@ impl EditorElement { .on_up(MouseButton::Left, { let view = view.clone(); let position_map = position_map.clone(); - move |e, cx| { + move |e, _, cx| { if !Self::mouse_up( view.clone(), e.position, @@ -173,7 +170,7 @@ impl EditorElement { .on_drag(MouseButton::Left, { let view = view.clone(); let position_map = position_map.clone(); - move |e, cx| { + move |e, _, cx| { if !Self::mouse_dragged( view.clone(), e.platform_event, @@ -187,20 +184,20 @@ impl EditorElement { }) .on_move({ let position_map = position_map.clone(); - move |e, cx| { + move |e, _, cx| { if !Self::mouse_moved(e.platform_event, &position_map, text_bounds, cx) { cx.propagate_event() } } }) - .on_move_out(move |_, cx| { + .on_move_out(move |_, _: &mut Editor, cx| { if has_popovers { cx.dispatch_action(HideHover); } }) .on_scroll({ let position_map = position_map.clone(); - move |e, cx| { + move |e, _, cx| { if !Self::scroll( e.position, *e.delta.raw(), @@ -218,7 +215,7 @@ impl EditorElement { enum GutterHandlers {} scene.push_mouse_region( MouseRegion::new::(view.id(), view.id() + 1, gutter_bounds).on_hover( - |hover, cx| { + |hover, _: &mut Editor, cx| { cx.dispatch_action(GutterHover { hovered: hover.started, }) @@ -244,7 +241,7 @@ impl EditorElement { position_map: &PositionMap, text_bounds: RectF, gutter_bounds: RectF, - cx: &mut EventContext, + cx: &mut EventContext, ) -> bool { if gutter_bounds.contains_point(position) { click_count = 3; // Simulate triple-click when clicking the gutter to select lines @@ -279,7 +276,7 @@ impl EditorElement { position: Vector2F, position_map: &PositionMap, text_bounds: RectF, - cx: &mut EventContext, + cx: &mut EventContext, ) -> bool { if !text_bounds.contains_point(position) { return false; @@ -298,9 +295,9 @@ impl EditorElement { shift: bool, position_map: &PositionMap, text_bounds: RectF, - cx: &mut EventContext, + cx: &mut EventContext, ) -> bool { - let view = view.upgrade(cx.app).unwrap().read(cx.app); + let view = view.upgrade(cx).unwrap().read(cx); let end_selection = view.has_pending_selection(); let pending_nonempty_selections = view.has_pending_nonempty_selection(); @@ -334,7 +331,7 @@ impl EditorElement { }: MouseMovedEvent, position_map: &PositionMap, text_bounds: RectF, - cx: &mut EventContext, + cx: &mut EventContext, ) -> bool { // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed // Don't trigger hover popover if mouse is hovering over context menu @@ -355,7 +352,7 @@ impl EditorElement { shift_held: shift, }); - let view = view.upgrade(cx.app).unwrap().read(cx.app); + let view = view.upgrade(cx).unwrap().read(cx); if view.has_pending_selection() { let mut scroll_delta = Vector2F::zero(); @@ -480,7 +477,7 @@ impl EditorElement { border: Border::new(0., Color::transparent_black()), corner_radius: 0., }); - c.push_quad(Quad { + scene.push_quad(Quad { bounds: text_bounds, background: Some(self.style.background), border: Border::new(0., Color::transparent_black()), @@ -545,7 +542,7 @@ impl EditorElement { visible_bounds: RectF, layout: &mut LayoutState, editor: &mut Editor, - cx: &mut PaintContext, + cx: &mut ViewContext, ) { let line_height = layout.position_map.line_height; @@ -561,7 +558,7 @@ impl EditorElement { ); if show_gutter { - Self::paint_diff_hunks(bounds, layout, cx); + Self::paint_diff_hunks(scene, bounds, layout, cx); } for (ix, line) in layout.line_number_layouts.iter().enumerate() { @@ -608,7 +605,12 @@ impl EditorElement { } } - fn paint_diff_hunks(bounds: RectF, layout: &mut LayoutState, cx: &mut PaintContext) { + fn paint_diff_hunks( + scene: &mut SceneBuilder, + bounds: RectF, + layout: &mut LayoutState, + cx: &mut ViewContext, + ) { let diff_style = &cx.global::().theme.editor.diff.clone(); let line_height = layout.position_map.line_height; @@ -698,11 +700,10 @@ impl EditorElement { visible_bounds: RectF, layout: &mut LayoutState, editor: &mut Editor, - cx: &mut PaintContext, + cx: &mut ViewContext, ) { - let view = self.view(cx.app); let style = &self.style; - let local_replica_id = view.replica_id(cx); + let local_replica_id = editor.replica_id(cx); let scroll_position = layout.position_map.snapshot.scroll_position(); let start_row = layout.visible_display_row_range.start; let scroll_top = scroll_position.y() * layout.position_map.line_height; @@ -715,7 +716,7 @@ impl EditorElement { scene.push_cursor_region(CursorRegion { bounds, - style: if !view.link_go_to_definition_state.definitions.is_empty() { + style: if !editor.link_go_to_definition_state.definitions.is_empty() { CursorStyle::PointingHand } else { CursorStyle::IBeam @@ -761,7 +762,7 @@ impl EditorElement { scene.push_mouse_region( MouseRegion::new::(self.view.id(), *id as usize, bound) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _: &mut Editor, cx| { cx.dispatch_action(UnfoldAt { buffer_row }) }) .with_notify_on_hover(true) @@ -807,7 +808,7 @@ impl EditorElement { cx, ); - if view.show_local_cursors(cx) || *replica_id != local_replica_id { + if editor.show_local_cursors(cx) || *replica_id != local_replica_id { let cursor_position = selection.head; if layout .visible_display_row_range @@ -834,7 +835,7 @@ impl EditorElement { cursor_row_layout.font_for_index(cursor_column)?; let text = character.to_string(); - Some(cx.text_layout_cache.layout_str( + Some(cx.text_layout_cache().layout_str( &text, cursor_row_layout.font_size(), &[( @@ -905,8 +906,8 @@ impl EditorElement { // Snap the right edge of the list to the right edge of the window if // its horizontal bounds overflow. - if list_origin.x() + list_width > cx.window_size.x() { - list_origin.set_x((cx.window_size.x() - list_width).max(0.)); + if list_origin.x() + list_width > cx.window_size().x() { + list_origin.set_x((cx.window_size().x() - list_width).max(0.)); } if list_origin.y() + list_height > bounds.max_y() { @@ -1059,7 +1060,7 @@ impl EditorElement { MouseRegion::new::(view.id(), view.id(), track_bounds) .on_move({ let view = view.clone(); - move |_, cx| { + move |_, _: &mut Editor, cx| { if let Some(view) = view.upgrade(cx.deref_mut()) { view.update(cx.deref_mut(), |view, cx| { view.scroll_manager.show_scrollbar(cx); @@ -1070,7 +1071,7 @@ impl EditorElement { .on_down(MouseButton::Left, { let view = view.clone(); let row_range = row_range.clone(); - move |e, cx| { + move |e, _: &mut Editor, cx| { let y = e.position.y(); if let Some(view) = view.upgrade(cx.deref_mut()) { view.update(cx.deref_mut(), |view, cx| { @@ -1092,7 +1093,7 @@ impl EditorElement { }) .on_drag(MouseButton::Left, { let view = view.clone(); - move |e, cx| { + move |e, _: &mut Editor, cx| { let y = e.prev_mouse_position.y(); let new_y = e.position.y(); if thumb_top < y && y < thumb_bottom { @@ -1127,7 +1128,7 @@ impl EditorElement { scroll_top: f32, scroll_left: f32, bounds: RectF, - cx: &mut ViewContext, + cx: &mut ViewContext, ) { let start_row = layout.visible_display_row_range.start; let end_row = layout.visible_display_row_range.end; @@ -1182,7 +1183,7 @@ impl EditorElement { visible_bounds: RectF, layout: &mut LayoutState, editor: &mut Editor, - cx: &mut PaintContext, + cx: &mut ViewContext, ) { let scroll_position = layout.position_map.snapshot.scroll_position(); let scroll_left = scroll_position.x() * layout.position_map.em_width; @@ -1203,11 +1204,11 @@ impl EditorElement { } } - fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &LayoutContext) -> f32 { + fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext) -> f32 { let digit_count = (snapshot.max_buffer_row() as f32).log10().floor() as usize + 1; let style = &self.style; - cx.text_layout_cache + cx.text_layout_cache() .layout_str( "1".repeat(digit_count).as_str(), style.text.font_size, @@ -1252,7 +1253,7 @@ impl EditorElement { active_rows: &BTreeMap, is_singleton: bool, snapshot: &EditorSnapshot, - cx: &LayoutContext, + cx: &ViewContext, ) -> ( Vec>, Vec>, @@ -1277,7 +1278,7 @@ impl EditorElement { if include_line_numbers { line_number.clear(); write!(&mut line_number, "{}", buffer_row + 1).unwrap(); - line_number_layouts.push(Some(cx.text_layout_cache.layout_str( + line_number_layouts.push(Some(cx.text_layout_cache().layout_str( &line_number, style.text.font_size, &[( @@ -1312,7 +1313,7 @@ impl EditorElement { &mut self, rows: Range, snapshot: &EditorSnapshot, - cx: &LayoutContext, + cx: &ViewContext, ) -> Vec { if rows.start >= rows.end { return Vec::new(); @@ -1335,7 +1336,7 @@ impl EditorElement { .take(rows.len()); placeholder_lines .map(|line| { - cx.text_layout_cache.layout_str( + cx.text_layout_cache().layout_str( line, placeholder_style.font_size, &[( @@ -1395,8 +1396,8 @@ impl EditorElement { layout_highlighted_chunks( chunks, &style.text, - cx.text_layout_cache, - cx.font_cache, + cx.text_layout_cache(), + cx.font_cache(), MAX_LINE_LEN, rows.len() as usize, ) @@ -1419,7 +1420,7 @@ impl EditorElement { line_layouts: &[text_layout::Line], include_root: bool, editor: &mut Editor, - cx: &mut LayoutContext, + cx: &mut ViewContext, ) -> (f32, Vec) { let tooltip_style = cx.global::().theme.tooltip.clone(); let scroll_x = snapshot.scroll_anchor.offset.x(); @@ -1441,20 +1442,18 @@ impl EditorElement { line_layouts[(align_to.row() - rows.start) as usize] .x_for_index(align_to.column() as usize) } else { - layout_line(align_to.row(), snapshot, style, cx.text_layout_cache) + layout_line(align_to.row(), snapshot, style, cx.text_layout_cache()) .x_for_index(align_to.column() as usize) }; - cx.render(&editor, |_, cx| { - block.render(&mut BlockContext { - cx, - anchor_x, - gutter_padding, - line_height, - scroll_x, - gutter_width, - em_width, - }) + block.render(&mut BlockContext { + view_context: cx, + anchor_x, + gutter_padding, + line_height, + scroll_x, + gutter_width, + em_width, }) } TransformBlock::ExcerptHeader { @@ -1480,36 +1479,34 @@ impl EditorElement { }; enum JumpIcon {} - cx.render(&editor, |_, cx| { - MouseEventHandler::::new(id.into(), cx, |state, _| { - let style = style.jump_icon.style_for(state, false); - Svg::new("icons/arrow_up_right_8.svg") - .with_color(style.color) - .constrained() - .with_width(style.icon_width) - .aligned() - .contained() - .with_style(style.container) - .constrained() - .with_width(style.button_width) - .with_height(style.button_width) - .boxed() - }) - .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { - cx.dispatch_action(jump_action.clone()) - }) - .with_tooltip::( - id.into(), - "Jump to Buffer".to_string(), - Some(Box::new(crate::OpenExcerpts)), - tooltip_style.clone(), - cx, - ) - .aligned() - .flex_float() - .boxed() + MouseEventHandler::::new(id.into(), cx, |state, _| { + let style = style.jump_icon.style_for(state, false); + Svg::new("icons/arrow_up_right_8.svg") + .with_color(style.color) + .constrained() + .with_width(style.icon_width) + .aligned() + .contained() + .with_style(style.container) + .constrained() + .with_width(style.button_width) + .with_height(style.button_width) + .boxed() }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, move |_, _, cx| { + cx.dispatch_action(jump_action.clone()) + }) + .with_tooltip::( + id.into(), + "Jump to Buffer".to_string(), + Some(Box::new(crate::OpenExcerpts)), + tooltip_style.clone(), + cx, + ) + .aligned() + .flex_float() + .boxed() }); if *starts_new_buffer { @@ -1614,31 +1611,32 @@ impl EditorElement { } } -impl Element for EditorElement { +impl Element for EditorElement { type LayoutState = LayoutState; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - cx: &mut LayoutContext, + editor: &mut Editor, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let mut size = constraint.max; if size.x().is_infinite() { unimplemented!("we don't yet handle an infinite width constraint on buffer elements"); } - let snapshot = self.snapshot(cx.app); + let snapshot = self.snapshot(cx); let style = self.style.clone(); - let line_height = style.text.line_height(cx.font_cache); + let line_height = style.text.line_height(cx.font_cache()); let gutter_padding; let gutter_width; let gutter_margin; if snapshot.mode == EditorMode::Full { - gutter_padding = style.text.em_width(cx.font_cache) * style.gutter_padding_factor; + gutter_padding = style.text.em_width(cx.font_cache()) * style.gutter_padding_factor; gutter_width = self.max_line_number_width(&snapshot, cx) + gutter_padding * 2.0; - gutter_margin = -style.text.descent(cx.font_cache); + gutter_margin = -style.text.descent(cx.font_cache()); } else { gutter_padding = 0.0; gutter_width = 0.0; @@ -1646,10 +1644,10 @@ impl Element for EditorElement { }; let text_width = size.x() - gutter_width; - let em_width = style.text.em_width(cx.font_cache); - let em_advance = style.text.em_advance(cx.font_cache); + let em_width = style.text.em_width(cx.font_cache()); + let em_advance = style.text.em_advance(cx.font_cache()); let overscroll = vec2f(em_width, 0.); - let snapshot = self.update_view(cx.app, |view, cx| { + let snapshot = self.update_view(cx, |view, cx| { view.set_visible_line_count(size.y() / line_height); let editor_width = text_width - gutter_margin - overscroll.x() - em_width; @@ -1686,7 +1684,7 @@ impl Element for EditorElement { let gutter_size = vec2f(gutter_width, size.y()); let text_size = vec2f(text_width, size.y()); - let (autoscroll_horizontally, mut snapshot) = self.update_view(cx.app, |view, cx| { + let (autoscroll_horizontally, mut snapshot) = self.update_view(cx, |view, cx| { let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, cx); let snapshot = view.snapshot(cx); (autoscroll_horizontally, snapshot) @@ -1728,7 +1726,7 @@ impl Element for EditorElement { let mut show_scrollbars = false; let mut include_root = false; let mut is_singleton = false; - self.update_view(cx.app, |view, cx| { + self.update_view(cx, |view, cx| { is_singleton = view.is_singleton(cx); let display_map = view.display_map.update(cx, |map, cx| map.snapshot(cx)); @@ -1859,11 +1857,11 @@ impl Element for EditorElement { snapshot.longest_row(), &snapshot, &style, - cx.text_layout_cache, + cx.text_layout_cache(), ) .width(); let scroll_width = longest_line_width.max(max_visible_line_width) + overscroll.x(); - let em_width = style.text.em_width(cx.font_cache); + let em_width = style.text.em_width(cx.font_cache()); let (scroll_width, blocks) = self.layout_blocks( start_row..end_row, &snapshot, @@ -1886,7 +1884,7 @@ impl Element for EditorElement { max_row as f32, ); - self.update_view(cx.app, |view, cx| { + self.update_view(cx, |view, cx| { let clamped = view.scroll_manager.clamp_scroll_left(scroll_max.x()); let autoscrolled = if autoscroll_horizontally { @@ -1911,47 +1909,52 @@ impl Element for EditorElement { let mut code_actions_indicator = None; let mut hover = None; let mut mode = EditorMode::Full; - let mut fold_indicators = cx.render(&self.view.upgrade(cx).unwrap(), |view, cx| { - let newest_selection_head = view + let mut fold_indicators = { + let newest_selection_head = editor .selections .newest::(cx) .head() .to_display_point(&snapshot); - let style = view.style(cx); + let style = editor.style(cx); if (start_row..end_row).contains(&newest_selection_head.row()) { - if view.context_menu_visible() { + if editor.context_menu_visible() { context_menu = - view.render_context_menu(newest_selection_head, style.clone(), cx); + editor.render_context_menu(newest_selection_head, style.clone(), cx); } - let active = matches!(view.context_menu, Some(crate::ContextMenu::CodeActions(_))); + let active = matches!( + editor.context_menu, + Some(crate::ContextMenu::CodeActions(_)) + ); - code_actions_indicator = view + code_actions_indicator = editor .render_code_actions_indicator(&style, active, cx) .map(|indicator| (newest_selection_head.row(), indicator)); } let visible_rows = start_row..start_row + line_layouts.len() as u32; - hover = view.hover_state.render(&snapshot, &style, visible_rows, cx); - mode = view.mode; + hover = editor + .hover_state + .render(&snapshot, &style, visible_rows, cx); + mode = editor.mode; - view.render_fold_indicators( + editor.render_fold_indicators( fold_statuses, &style, - view.gutter_hovered, + editor.gutter_hovered, line_height, gutter_margin, cx, ) - }); + }; if let Some((_, context_menu)) = context_menu.as_mut() { context_menu.layout( SizeConstraint { min: Vector2F::zero(), max: vec2f( - cx.window_size.x() * 0.7, + cx.window_size().x() * 0.7, (12. * line_height).min((size.y() - line_height) / 2.), ), }, @@ -1978,6 +1981,7 @@ impl Element for EditorElement { Axis::Vertical, line_height * style.code_actions.vertical_scale, ), + editor, cx, ); } @@ -1997,6 +2001,7 @@ impl Element for EditorElement { .max(MIN_POPOVER_LINE_HEIGHT * line_height), // Apply minimum height of 4 lines ), }, + editor, cx, ); } @@ -2041,10 +2046,12 @@ impl Element for EditorElement { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, layout: &mut Self::LayoutState, - cx: &mut PaintContext, + editor: &mut Editor, + cx: &mut ViewContext, ) -> Self::PaintState { let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); scene.push_layer(Some(visible_bounds)); @@ -2056,6 +2063,7 @@ impl Element for EditorElement { ); Self::attach_mouse_handlers( + scene, &self.view, &layout.position_map, layout.hover_popovers.is_some(), @@ -2089,7 +2097,8 @@ impl Element for EditorElement { _: RectF, layout: &Self::LayoutState, _: &Self::PaintState, - _: &gpui::MeasurementContext, + _: &Editor, + _: &ViewContext, ) -> Option { let text_bounds = RectF::new( bounds.origin() + vec2f(layout.gutter_size.x(), 0.0), @@ -2132,7 +2141,8 @@ impl Element for EditorElement { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &gpui::DebugContext, + _: &Editor, + _: &ViewContext, ) -> json::Value { json!({ "type": "BufferElement", @@ -2162,10 +2172,10 @@ pub struct LayoutState { scrollbar_row_range: Range, show_scrollbars: bool, max_row: u32, - context_menu: Option<(DisplayPoint, ElementBox)>, - code_actions_indicator: Option<(u32, ElementBox)>, - hover_popovers: Option<(DisplayPoint, Vec)>, - fold_indicators: Vec>, + context_menu: Option<(DisplayPoint, ElementBox)>, + code_actions_indicator: Option<(u32, ElementBox)>, + hover_popovers: Option<(DisplayPoint, Vec>)>, + fold_indicators: Vec>>, } pub struct PositionMap { @@ -2216,7 +2226,7 @@ impl PositionMap { struct BlockLayout { row: u32, - element: ElementBox, + element: ElementBox, style: BlockStyle, } @@ -2287,7 +2297,7 @@ impl Cursor { ) } - pub fn paint(&self, scene: &mut SceneBuilder, origin: Vector2F, cx: &mut AppContext) { + pub fn paint(&self, scene: &mut SceneBuilder, origin: Vector2F, cx: &mut WindowContext) { let bounds = match self.shape { CursorShape::Bar => RectF::new(self.origin + origin, vec2f(2.0, self.line_height)), CursorShape::Block | CursorShape::Hollow => RectF::new( diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index 23d1328fd4..ecdddb90fc 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -283,7 +283,7 @@ impl HoverState { style: &EditorStyle, visible_rows: Range, cx: &mut ViewContext, - ) -> Option<(DisplayPoint, Vec)> { + ) -> Option<(DisplayPoint, Vec>)> { // If there is a diagnostic, position the popovers based on that. // Otherwise use the start of the hover range let anchor = self @@ -323,9 +323,9 @@ pub struct InfoPopover { } impl InfoPopover { - pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext) -> ElementBox { - MouseEventHandler::::new(0, cx, |_, cx| { - let mut flex = Flex::new(Axis::Vertical).scrollable::(1, None, cx); + pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext) -> ElementBox { + MouseEventHandler::::new(0, cx, |_, cx| { + let mut flex = Flex::new(Axis::Vertical).scrollable::(1, None, cx); flex.extend(self.contents.iter().map(|content| { let languages = self.project.read(cx).languages(); if let Some(language) = content.language.clone().and_then(|language| { @@ -360,7 +360,7 @@ impl InfoPopover { .with_style(style.hover_popover.container) .boxed() }) - .on_move(|_, _| {}) // Consume move events so they don't reach regions underneath. + .on_move(|_, _, _| {}) // Consume move events so they don't reach regions underneath. .with_cursor_style(CursorStyle::Arrow) .with_padding(Padding { bottom: HOVER_POPOVER_GAP, @@ -378,7 +378,7 @@ pub struct DiagnosticPopover { } impl DiagnosticPopover { - pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext) -> ElementBox { + pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext) -> ElementBox { enum PrimaryDiagnostic {} let mut text_style = style.hover_popover.prose.clone(); @@ -394,7 +394,7 @@ impl DiagnosticPopover { let tooltip_style = cx.global::().theme.tooltip.clone(); - MouseEventHandler::::new(0, cx, |_, _| { + MouseEventHandler::::new(0, cx, |_, _| { Text::new(self.local_diagnostic.diagnostic.message.clone(), text_style) .with_soft_wrap(true) .contained() @@ -406,12 +406,12 @@ impl DiagnosticPopover { bottom: HOVER_POPOVER_GAP, ..Default::default() }) - .on_move(|_, _| {}) // Consume move events so they don't reach regions underneath. - .on_click(MouseButton::Left, |_, cx| { + .on_move(|_, _, _| {}) // Consume move events so they don't reach regions underneath. + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(GoToDiagnostic) }) .with_cursor_style(CursorStyle::PointingHand) - .with_tooltip::( + .with_tooltip::( 0, "Go To Diagnostic".to_string(), Some(Box::new(crate::GoToDiagnostic)), diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 83e1a4d7f6..906b567ccb 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -8,7 +8,7 @@ use collections::HashSet; use futures::future::try_join_all; use gpui::{ elements::*, geometry::vector::vec2f, AppContext, Entity, ModelHandle, Subscription, Task, - View, ViewContext, ViewContext, ViewHandle, WeakViewHandle, + View, ViewContext, ViewHandle, WeakViewHandle, }; use language::{ proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point, @@ -526,7 +526,7 @@ impl Item for Editor { detail: Option, style: &theme::Tab, cx: &AppContext, - ) -> ElementBox { + ) -> ElementBox { Flex::row() .with_child( Label::new(self.title(cx).to_string(), style.label.clone()) @@ -606,7 +606,7 @@ impl Item for Editor { self.report_event("save editor", cx); let format = self.perform_format(project.clone(), FormatTrigger::Save, cx); let buffers = self.buffer().clone().read(cx).all_buffers(); - cx.as_mut().spawn(|mut cx| async move { + cx.spawn(|_, mut cx| async move { format.await?; if buffers.len() == 1 { @@ -727,7 +727,7 @@ impl Item for Editor { ToolbarItemLocation::PrimaryLeft { flex: None } } - fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option> { + fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option>> { let cursor = self.selections.newest_anchor().head(); let multibuffer = &self.buffer().read(cx); let (buffer_id, symbols) = @@ -1078,7 +1078,7 @@ impl View for CursorPosition { "CursorPosition" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if let Some(position) = self.position { let theme = &cx.global::().theme.workspace.status_bar; let mut text = format!("{},{}", position.row + 1, position.column + 1); diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index af90f6b0c9..e50f69f6d7 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -156,7 +156,7 @@ impl View for GoToLine { "GoToLine" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = &cx.global::().theme.picker; let label = format!( diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 176ac3fd4b..244a8be446 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -12,9 +12,10 @@ use crate::{ }, text_layout::TextLayoutCache, util::post_inc, - AnyView, AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelContext, ModelHandle, - MouseRegion, MouseRegionId, ParentId, ReadView, RenderParams, SceneBuilder, UpdateModel, View, - ViewContext, ViewHandle, WindowInvalidation, + AnyView, AnyViewHandle, AnyWeakViewHandle, AppContext, Element, ElementBox, Entity, + ModelContext, ModelHandle, MouseRegion, MouseRegionId, ParentId, ReadView, RenderParams, + SceneBuilder, UpdateModel, UpgradeViewHandle, View, ViewContext, ViewHandle, WeakViewHandle, + WindowInvalidation, }; use anyhow::bail; use collections::{HashMap, HashSet}; @@ -121,10 +122,10 @@ impl DerefMut for WindowContext<'_, '_> { } impl UpdateModel for WindowContext<'_, '_> { - fn update_model( + fn update_model( &mut self, - handle: &ModelHandle, - update: &mut dyn FnMut(&mut M, &mut ModelContext) -> R, + handle: &ModelHandle, + update: &mut dyn FnMut(&mut T, &mut ModelContext) -> R, ) -> R { self.app_context.update_model(handle, update) } @@ -136,6 +137,16 @@ impl ReadView for WindowContext<'_, '_> { } } +impl UpgradeViewHandle for WindowContext<'_, '_> { + fn upgrade_view_handle(&self, handle: &WeakViewHandle) -> Option> { + self.app_context.upgrade_view_handle(handle) + } + + fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option { + self.app_context.upgrade_any_view_handle(handle) + } +} + impl<'a: 'b, 'b> WindowContext<'a, 'b> { pub fn new(app_context: &'a mut AppContext, window: &'b mut Window, window_id: usize) -> Self { Self { diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 235b9c4288..5e7ee19b5b 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -29,7 +29,7 @@ pub mod json; pub mod keymap_matcher; pub mod platform; pub use gpui_macros::test; -pub use window::{Axis, SizeConstraint, Vector2FExt}; +pub use window::{Axis, SizeConstraint, Vector2FExt, WindowContext}; pub use anyhow; pub use serde_json; diff --git a/crates/gpui/src/scene/mouse_region.rs b/crates/gpui/src/scene/mouse_region.rs index 275a10ae31..601634329c 100644 --- a/crates/gpui/src/scene/mouse_region.rs +++ b/crates/gpui/src/scene/mouse_region.rs @@ -11,7 +11,11 @@ use collections::HashMap; use pathfinder_geometry::rect::RectF; use smallvec::SmallVec; -use crate::{platform::MouseButton, window::WindowContext, ReadView, View, ViewContext}; +use crate::{ + platform::MouseButton, window::WindowContext, AnyModelHandle, AnyViewHandle, + AnyWeakModelHandle, AnyWeakViewHandle, Entity, ModelHandle, ReadView, UpgradeModelHandle, + UpgradeViewHandle, View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle, +}; use super::{ mouse_event::{ @@ -240,6 +244,33 @@ impl ReadView for EventContext<'_, '_, '_, '_, V> { } } +impl UpgradeModelHandle for EventContext<'_, '_, '_, '_, V> { + fn upgrade_model_handle( + &self, + handle: &WeakModelHandle, + ) -> Option> { + self.view_context.upgrade_model_handle(handle) + } + + fn model_handle_is_upgradable(&self, handle: &WeakModelHandle) -> bool { + self.view_context.model_handle_is_upgradable(handle) + } + + fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option { + self.view_context.upgrade_any_model_handle(handle) + } +} + +impl UpgradeViewHandle for EventContext<'_, '_, '_, '_, V> { + fn upgrade_view_handle(&self, handle: &WeakViewHandle) -> Option> { + self.view_context.upgrade_view_handle(handle) + } + + fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option { + self.view_context.upgrade_any_view_handle(handle) + } +} + pub type HandlerCallback = Rc bool>; #[derive(Clone, PartialEq, Eq, Hash)] diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index a5434359bc..5cdfdc654c 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -4,8 +4,8 @@ use gpui::{ geometry::vector::{vec2f, Vector2F}, keymap_matcher::KeymapContext, platform::{CursorStyle, MouseButton}, - AnyViewHandle, AppContext, Axis, Entity, MouseState, Task, View, ViewContext, ViewHandle, - WeakViewHandle, + AnyViewHandle, AppContext, Axis, ElementBox, Entity, MouseState, Task, View, ViewContext, + ViewHandle, WeakViewHandle, }; use menu::{Cancel, Confirm, SelectFirst, SelectIndex, SelectLast, SelectNext, SelectPrev}; use parking_lot::Mutex; @@ -33,7 +33,7 @@ pub trait PickerDelegate: View { state: &mut MouseState, selected: bool, cx: &AppContext, - ) -> ElementBox; + ) -> ElementBox; fn center_selection_after_match_updates(&self) -> bool { false } @@ -48,11 +48,11 @@ impl View for Picker { "Picker" } - fn render(&mut self, cx: &mut ViewContext) -> gpui::ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = (self.theme.lock())(&cx.global::().theme); let query = self.query(cx); let delegate = self.delegate.clone(); - let match_count = if let Some(delegate) = delegate.upgrade(cx.app) { + let match_count = if let Some(delegate) = delegate.upgrade(cx) { delegate.read(cx).match_count() } else { 0 @@ -97,15 +97,15 @@ impl View for Picker { let selected_ix = delegate.read(cx).selected_index(); range.end = cmp::min(range.end, delegate.read(cx).match_count()); items.extend(range.map(move |ix| { - MouseEventHandler::::new(ix, cx, |state, cx| { + MouseEventHandler::::new(ix, cx, |state, cx| { delegate .read(cx) .render_match(ix, state, ix == selected_ix, cx) }) // Capture mouse events - .on_down(MouseButton::Left, |_, _| {}) - .on_up(MouseButton::Left, |_, _| {}) - .on_click(MouseButton::Left, move |_, cx| { + .on_down(MouseButton::Left, |_, _, _| {}) + .on_up(MouseButton::Left, |_, _, _| {}) + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(SelectIndex(ix)) }) .with_cursor_style(CursorStyle::PointingHand) diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 3128ec0d78..609765cffb 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1098,7 +1098,7 @@ impl ProjectPanel { row_container_style: ContainerStyle, style: &ProjectPanelEntry, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { let kind = details.kind; let show_editor = details.is_editing && !details.is_processing; @@ -1155,8 +1155,8 @@ impl ProjectPanel { dragged_entry_destination: &mut Option>, theme: &theme::ProjectPanel, cx: &mut ViewContext, - ) -> ElementBox { - let this = cx.handle(); + ) -> ElementBox { + let this = cx.handle().downgrade(); let kind = details.kind; let path = details.path.clone(); let padding = theme.container.padding.left + details.depth as f32 * theme.indent_width; @@ -1171,7 +1171,7 @@ impl ProjectPanel { let show_editor = details.is_editing && !details.is_processing; - MouseEventHandler::::new(entry_id.to_usize(), cx, |state, cx| { + MouseEventHandler::::new(entry_id.to_usize(), cx, |state, cx| { let mut style = entry_style.style_for(state, details.is_selected).clone(); if cx @@ -1201,7 +1201,7 @@ impl ProjectPanel { cx, ) }) - .on_click(MouseButton::Left, move |e, cx| { + .on_click(MouseButton::Left, move |e, _, cx| { if !show_editor { if kind == EntryKind::Dir { cx.dispatch_action(ToggleExpanded(entry_id)) @@ -1213,13 +1213,13 @@ impl ProjectPanel { } } }) - .on_down(MouseButton::Right, move |e, cx| { + .on_down(MouseButton::Right, move |e, _, cx| { cx.dispatch_action(DeployContextMenu { entry_id, position: e.position, }) }) - .on_up(MouseButton::Left, move |_, cx| { + .on_up(MouseButton::Left, move |_, _, cx| { if let Some((_, dragged_entry)) = cx .global::>() .currently_dragged::(cx.window_id()) @@ -1231,14 +1231,14 @@ impl ProjectPanel { }); } }) - .on_move(move |_, cx| { + .on_move(move |_, _, cx| { if cx .global::>() .currently_dragged::(cx.window_id()) .is_some() { - if let Some(this) = this.upgrade(cx.app) { - this.update(cx.app, |this, _| { + if let Some(this) = this.upgrade(cx) { + this.update(cx, |this, _, _| { this.dragged_entry_destination = if matches!(kind, EntryKind::File(_)) { path.parent().map(|parent| Arc::from(parent)) } else { @@ -1251,7 +1251,7 @@ impl ProjectPanel { .as_draggable(entry_id, { let row_container_style = theme.dragged_entry.container; - move |_, cx: &mut ViewContext| { + move |_, _, cx: &mut ViewContext| { let theme = cx.global::().theme.clone(); Self::render_entry_visual_element( &details, @@ -1273,7 +1273,7 @@ impl View for ProjectPanel { "ProjectPanel" } - fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext) -> gpui::ElementBox { enum ProjectPanel {} let theme = &cx.global::().theme.project_panel; let mut container_style = theme.container; @@ -1285,7 +1285,7 @@ impl View for ProjectPanel { if has_worktree { Stack::new() .with_child( - MouseEventHandler::::new(0, cx, |_, cx| { + MouseEventHandler::::new(0, cx, |_, cx| { UniformList::new( self.list.clone(), self.visible_entries @@ -1317,7 +1317,7 @@ impl View for ProjectPanel { .expanded() .boxed() }) - .on_down(MouseButton::Right, move |e, cx| { + .on_down(MouseButton::Right, move |e, _, cx| { // When deploying the context menu anywhere below the last project entry, // act as if the user clicked the root of the last worktree. if let Some(entry_id) = last_worktree_root_id { @@ -1334,7 +1334,7 @@ impl View for ProjectPanel { } else { Flex::column() .with_child( - MouseEventHandler::::new(2, cx, { + MouseEventHandler::::new(2, cx, { let button_style = theme.open_project_button.clone(); let context_menu_item_style = cx.global::().theme.context_menu.item.clone(); @@ -1353,7 +1353,7 @@ impl View for ProjectPanel { .boxed() } }) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(workspace::Open) }) .with_cursor_style(CursorStyle::PointingHand) diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index ffef25872e..e36c60a825 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -91,7 +91,7 @@ impl View for BufferSearchBar { } } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); let editor_container = if self.query_contains_error { theme.search.invalid_editor @@ -324,7 +324,7 @@ impl BufferSearchBar { icon: &'static str, option: SearchOption, cx: &mut ViewContext, - ) -> Option { + ) -> Option> { if !option_supported { return None; } @@ -332,7 +332,7 @@ impl BufferSearchBar { let tooltip_style = cx.global::().theme.tooltip.clone(); let is_active = self.is_search_option_enabled(option); Some( - MouseEventHandler::::new(option as usize, cx, |state, cx| { + MouseEventHandler::::new(option as usize, cx, |state, cx| { let style = cx .global::() .theme @@ -344,11 +344,11 @@ impl BufferSearchBar { .with_style(style.container) .boxed() }) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_any_action(option.to_toggle_action()) }) .with_cursor_style(CursorStyle::PointingHand) - .with_tooltip::( + .with_tooltip::( option as usize, format!("Toggle {}", option.label()), Some(option.to_toggle_action()), @@ -364,7 +364,7 @@ impl BufferSearchBar { icon: &'static str, direction: Direction, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { let action: Box; let tooltip; match direction { @@ -380,7 +380,7 @@ impl BufferSearchBar { let tooltip_style = cx.global::().theme.tooltip.clone(); enum NavButton {} - MouseEventHandler::::new(direction as usize, cx, |state, cx| { + MouseEventHandler::::new(direction as usize, cx, |state, cx| { let style = cx .global::() .theme @@ -394,10 +394,10 @@ impl BufferSearchBar { }) .on_click(MouseButton::Left, { let action = action.boxed_clone(); - move |_, cx| cx.dispatch_any_action(action.boxed_clone()) + mov_, _, cx| cx.dispatch_any_action(action.boxed_clone()) }) .with_cursor_style(CursorStyle::PointingHand) - .with_tooltip::( + .with_tooltip::( direction as usize, tooltip.to_string(), Some(action), @@ -407,13 +407,17 @@ impl BufferSearchBar { .boxed() } - fn render_close_button(&self, theme: &theme::Search, cx: &mut ViewContext) -> ElementBox { + fn render_close_button( + &self, + theme: &theme::Search, + cx: &mut ViewContext, + ) -> ElementBox { let action = Box::new(Dismiss); let tooltip = "Dismiss Buffer Search"; let tooltip_style = cx.global::().theme.tooltip.clone(); enum CloseButton {} - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = theme.dismiss_button.style_for(state, false); Svg::new("icons/x_mark_8.svg") .with_color(style.color) @@ -428,10 +432,10 @@ impl BufferSearchBar { }) .on_click(MouseButton::Left, { let action = action.boxed_clone(); - move |_, cx| cx.dispatch_any_action(action.boxed_clone()) + move |_, _, _, cx| cx.dispatch_any_action(action.boxed_clone()) }) .with_cursor_style(CursorStyle::PointingHand) - .with_tooltip::(0, tooltip.to_string(), Some(action), tooltip_style, cx) + .with_tooltip::(0, tooltip.to_string(), Some(action), tooltip_style, cx) .boxed() } diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 1c8cf74125..586deee613 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -177,7 +177,7 @@ impl View for ProjectSearchView { "ProjectSearchView" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let model = &self.model.read(cx); if model.match_ranges.is_empty() { enum Status {} @@ -190,7 +190,7 @@ impl View for ProjectSearchView { } else { "No results" }; - MouseEventHandler::::new(0, cx, |_, _| { + MouseEventHandler::::new(0, cx, |_, _| { Label::new(text, theme.search.results_status.clone()) .aligned() .contained() @@ -198,7 +198,7 @@ impl View for ProjectSearchView { .flex(1., true) .boxed() }) - .on_down(MouseButton::Left, |_, cx| { + .on_down(MouseButton::Left, |_, _, _, cx| { cx.focus_parent_view(); }) .boxed() @@ -249,7 +249,7 @@ impl Item for ProjectSearchView { _detail: Option, tab_theme: &theme::Tab, cx: &AppContext, - ) -> ElementBox { + ) -> ElementBox { Flex::row() .with_child( Svg::new("icons/magnifying_glass_12.svg") @@ -364,7 +364,7 @@ impl Item for ProjectSearchView { } } - fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option> { + fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option>> { self.results_editor.breadcrumbs(theme, cx) } @@ -747,7 +747,7 @@ impl ProjectSearchBar { icon: &'static str, direction: Direction, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { let action: Box; let tooltip; match direction { @@ -763,7 +763,7 @@ impl ProjectSearchBar { let tooltip_style = cx.global::().theme.tooltip.clone(); enum NavButton {} - MouseEventHandler::::new(direction as usize, cx, |state, cx| { + MouseEventHandler::::new(direction as usize, cx, |state, cx| { let style = &cx .global::() .theme @@ -775,13 +775,12 @@ impl ProjectSearchBar { .with_style(style.container) .boxed() }) - .on_click(MouseButton::Left, { + .on_click(MouseButton::Le { let action = action.boxed_clone(); - move |_, cx| cx.dispatch_any_action(action.boxed_clone()) - }) + move |_, _, cx| cx.dispatch_any_action(action.boxed_clone()) + _, }) .with_cursor_style(CursorStyle::PointingHand) - .with_tooltip::( - direction as usize, + .with_tooltip::, - ) -> ElementBox { + ) -> ElementBox { let tooltip_style = cx.global::().theme.tooltip.clone(); let is_active = self.is_option_enabled(option, cx); - MouseEventHandler::::new(option as usize, cx, |state, cx| { + MouseEventHandler::::new(option as usize, cx, |state, cx| { let style = &cx .global::() .theme @@ -810,11 +809,11 @@ impl ProjectSearchBar { .with_style(style.container) .boxed() }) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_any_action(option.to_toggle_action()) }) .with_cursor_style(CursorStyle::PointingHand) - .with_tooltip::( + .with_tooltip::( option as usize, format!("Toggle {}", option.label()), Some(option.to_toggle_action()), @@ -847,7 +846,7 @@ impl View for ProjectSearchBar { "ProjectSearchBar" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if let Some(search) = self.active_project_search.as_ref() { let search = search.read(cx); let theme = cx.global::().theme.clone(); diff --git a/crates/terminal_view/src/terminal_button.rs b/crates/terminal_view/src/terminal_button.rs index 33738ff58f..bcd5c13429 100644 --- a/crates/terminal_view/src/terminal_button.rs +++ b/crates/terminal_view/src/terminal_button.rs @@ -42,7 +42,7 @@ impl View for TerminalButton { "TerminalButton" } - fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let workspace = self.workspace.upgrade(cx); let project = match workspace { Some(workspace) => workspace.read(cx).project().read(cx), @@ -62,7 +62,7 @@ impl View for TerminalButton { Stack::new() .with_child( - MouseEventHandler::::new(0, cx, { + MouseEventHandler::::new(0, cx, { let theme = theme.clone(); move |state, _cx| { let style = theme @@ -96,7 +96,7 @@ impl View for TerminalButton { } }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { if has_terminals { cx.dispatch_action(DeployTerminalMenu); } else { @@ -105,7 +105,7 @@ impl View for TerminalButton { } }; }) - .with_tooltip::( + .with_tooltip::( 0, "Show Terminal".into(), Some(Box::new(FocusDock)), diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index 4864e13243..9c13111da8 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -100,7 +100,7 @@ impl LayoutCell { }; self.text - .paint(pos, visible_bounds, layout.size.line_height, view, cx); + .paint(scene, pos, visible_bounds, layout.size.line_height, cx); } } @@ -128,7 +128,14 @@ impl LayoutRect { } } - fn paint(&self, origin: Vector2F, layout: &LayoutState, cx: &mut PaintContext) { + fn paint( + &self, + scene: &mut SceneBuilder, + origin: Vector2F, + layout: &LayoutState, + view: &mut TerminalView, + cx: &mut ViewContext, + ) { let position = { let point = self.point; vec2f( @@ -363,11 +370,11 @@ impl TerminalElement { connection: WeakModelHandle, origin: Vector2F, f: impl Fn(&mut Terminal, Vector2F, E, &mut ModelContext), - ) -> impl Fn(E, &mut EventContext) { - move |event, cx| { + ) -> impl Fn(E, &mut TerminalView, &mut EventContext) { + move |event, _: &mut TerminalView, cx| { cx.focus_parent_view(); - if let Some(conn_handle) = connection.upgrade(cx.app) { - conn_handle.update(cx.app, |terminal, cx| { + if let Some(conn_handle) = connection.upgrade(cx) { + conn_handle.update(cx, |terminal, cx| { f(terminal, origin, event, cx); cx.notify(); @@ -378,6 +385,7 @@ impl TerminalElement { fn attach_mouse_handlers( &self, + scene: &mut SceneBuilder, origin: Vector2F, view_id: usize, visible_bounds: RectF, @@ -402,10 +410,10 @@ impl TerminalElement { ), ) // Update drag selections - .on_drag(MouseButton::Left, move |event, cx| { + .on_drag(MouseButton::Left, move |event, _, cx| { if cx.is_parent_view_focused() { - if let Some(conn_handle) = connection.upgrade(cx.app) { - conn_handle.update(cx.app, |terminal, cx| { + if let Some(conn_handle) = connection.upgrade(cx) { + conn_handle.update(cx, |terminal, cx| { terminal.mouse_drag(event, origin); cx.notify(); }) @@ -424,9 +432,9 @@ impl TerminalElement { ), ) // Context menu - .on_click(MouseButton::Right, move |e, cx| { - let mouse_mode = if let Some(conn_handle) = connection.upgrade(cx.app) { - conn_handle.update(cx.app, |terminal, _cx| terminal.mouse_mode(e.shift)) + .on_click(MouseButton::Right, move |e, _, cx| { + let mouse_mode = if let Some(conn_handle) = connection.upgrade(cx) { + conn_handle.update(cx, |terminal, _cx| terminal.mouse_mode(e.shift)) } else { // If we can't get the model handle, probably can't deploy the context menu true @@ -437,20 +445,19 @@ impl TerminalElement { }); } }) - .on_move(move |event, cx| { + .on_move(move |event, _, cx| { if cx.is_parent_view_focused() { - if let Some(conn_handle) = connection.upgrade(cx.app) { - conn_handle.update(cx.app, |terminal, cx| { + if let Some(conn_handle) = connection.upgrade(cx) { + conn_handle.update(cx, |terminal, cx| { terminal.mouse_move(&event, origin); cx.notify(); }) } } }) - .on_scroll(move |event, cx| { - // cx.focus_parent_view(); - if let Some(conn_handle) = connection.upgrade(cx.app) { - conn_handle.update(cx.app, |terminal, cx| { + .on_scroll(move |event, _, cx| { + if let Some(conn_handle) = connection.upgrade(cx) { + conn_handle.update(cx, |terminal, cx| { terminal.scroll_wheel(event, origin); cx.notify(); }) @@ -548,7 +555,7 @@ impl TerminalElement { } } -impl Element for TerminalElement { +impl Element for TerminalElement { type LayoutState = LayoutState; type PaintState = (); @@ -584,7 +591,7 @@ impl Element for TerminalElement { let background_color = terminal_theme.background; let terminal_handle = self.terminal.upgrade(cx).unwrap(); - let last_hovered_hyperlink = terminal_handle.update(cx.app, |terminal, cx| { + let last_hovered_hyperlink = terminal_handle.update(cx, |terminal, cx| { terminal.set_size(dimensions); terminal.try_sync(cx); terminal.last_content.last_hovered_hyperlink.clone() @@ -724,6 +731,7 @@ impl Element for TerminalElement { bounds: RectF, visible_bounds: RectF, layout: &mut Self::LayoutState, + view: &mut TerminalView, cx: &mut ViewContext, ) -> Self::PaintState { let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); @@ -735,7 +743,14 @@ impl Element for TerminalElement { let origin = bounds.origin() + vec2f(layout.size.cell_width, 0.); // Elements are ephemeral, only at paint time do we know what could be clicked by a mouse - self.attach_mouse_handlers(origin, self.view.id(), visible_bounds, layout.mode, cx); + self.attach_mouse_handlers( + origin, + self.view.id(), + visible_bounds, + layout.mode, + view, + cx, + ); scene.push_cursor_region(gpui::CursorRegion { bounds, @@ -756,7 +771,7 @@ impl Element for TerminalElement { }); for rect in &layout.rects { - rect.paint(origin, layout, cx) + rect.paint(scene, origin, layout, view, cx) } }); @@ -797,7 +812,7 @@ impl Element for TerminalElement { } if let Some(element) = &mut layout.hyperlink_tooltip { - Element::paint(element, scene, origin, visible_bounds, view, cx) + Element::paint(element, scene, origin, visible_bounds, view, view, cx) } }); } @@ -808,10 +823,11 @@ impl Element for TerminalElement { fn debug( &self, - _bounds: RectF, - _layout: &Self::LayoutState, - _paint: &Self::PaintState, - _cx: &gpui::DebugContext, + _: RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + _: &TerminalView, + _: &gpui::ViewContext, ) -> gpui::serde_json::Value { json!({ "type": "TerminalElement", @@ -825,7 +841,8 @@ impl Element for TerminalElement { _: RectF, layout: &Self::LayoutState, _: &Self::PaintState, - _: &gpui::MeasurementContext, + _: &TerminalView, + _: &gpui::ViewContext, ) -> Option { // Use the same origin that's passed to `Cursor::paint` in the paint // method bove. diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 6f2ec00614..6a68bfc7dd 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -236,7 +236,7 @@ impl TerminalView { cx.notify(); } - pub fn should_show_cursor(&self, focused: bool, cx: &mut gpui::ViewContext<'_, Self>) -> bool { + pub fn should_show_cursor(&self, focused: bool, cx: &mut gpui::ViewContext) -> bool { //Don't blink the cursor when not focused, blinking is disabled, or paused if !focused || !self.blinking_on @@ -384,7 +384,7 @@ impl View for TerminalView { "Terminal" } - fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext) -> ElementBox { let terminal_handle = self.terminal.clone().downgrade(); let self_id = cx.view_id(); @@ -544,7 +544,7 @@ impl Item for TerminalView { _detail: Option, tab_theme: &theme::Tab, cx: &gpui::AppContext, - ) -> ElementBox { + ) -> ElementBox { let title = self.terminal().read(cx).title(); Flex::row() @@ -606,7 +606,7 @@ impl Item for TerminalView { ToolbarItemLocation::PrimaryLeft { flex: None } } - fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option> { + fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option>> { Some(vec![Text::new( self.terminal().read(cx).breadcrumb_text.clone(), theme.workspace.breadcrumbs.default.text.clone(), diff --git a/crates/theme_testbench/src/theme_testbench.rs b/crates/theme_testbench/src/theme_testbench.rs index 6d5f06d65e..3474fffdf3 100644 --- a/crates/theme_testbench/src/theme_testbench.rs +++ b/crates/theme_testbench/src/theme_testbench.rs @@ -34,11 +34,11 @@ impl ThemeTestbench { workspace.add_item(Box::new(view), cx); } - fn render_ramps(color_scheme: &ColorScheme) -> Flex { - fn display_ramp(ramp: &Vec) -> ElementBox { + fn render_ramps(color_scheme: &ColorScheme) -> Flex { + fn display_ramp(ramp: &Vec) -> ElementBox { Flex::row() .with_children(ramp.iter().cloned().map(|color| { - Canvas::new(move |bounds, _, cx| { + Canvas::new(move |scene, bounds, _, _, _| { scene.push_quad(Quad { bounds, background: Some(color), @@ -67,8 +67,8 @@ impl ThemeTestbench { fn render_layer( layer_index: usize, layer: &Layer, - cx: &mut ViewContext<'_, Self>, - ) -> Container { + cx: &mut ViewContext, + ) -> Container { Flex::column() .with_child( Self::render_button_set(0, layer_index, "base", &layer.base, cx) @@ -123,8 +123,8 @@ impl ThemeTestbench { layer_index: usize, set_name: &'static str, style_set: &StyleSet, - cx: &mut ViewContext<'_, Self>, - ) -> Flex { + cx: &mut ViewContext, + ) -> Flex { Flex::row() .with_child(Self::render_button( set_index * 6, @@ -182,10 +182,10 @@ impl ThemeTestbench { text: &'static str, style_set: &StyleSet, style_override: Option &Style>, - cx: &mut ViewContext<'_, Self>, - ) -> ElementBox { + cx: &mut ViewContext, + ) -> ElementBox { enum TestBenchButton {} - MouseEventHandler::::new(layer_index + button_index, cx, |state, cx| { + MouseEventHandler::::new(layer_index + button_index, cx, |state, cx| { let style = if let Some(style_override) = style_override { style_override(&style_set) } else if state.clicked().is_some() { @@ -230,7 +230,7 @@ impl ThemeTestbench { .boxed() } - fn render_label(text: String, style: &Style, cx: &mut ViewContext<'_, Self>) -> Label { + fn render_label(text: String, style: &Style, cx: &mut ViewContext) -> Label { let settings = cx.global::(); let font_cache = cx.font_cache(); let family_id = settings.buffer_font_family; @@ -262,7 +262,7 @@ impl View for ThemeTestbench { "ThemeTestbench" } - fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext) -> ElementBox { let color_scheme = &cx.global::().theme.clone().color_scheme; Flex::row() @@ -303,7 +303,7 @@ impl Item for ThemeTestbench { _: Option, style: &theme::Tab, _: &AppContext, - ) -> gpui::ElementBox { + ) -> ElementBox { Label::new("Theme Testbench", style.label.clone()) .aligned() .contained() From 83070a19c4fa7fe4afb1fa9d0af9a00738265ab8 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 12 Apr 2023 15:55:43 +0200 Subject: [PATCH 10/58] WIP --- .../src/activity_indicator.rs | 2 +- crates/collab/src/tests/integration_tests.rs | 11 ++-- .../src/collaborator_list_popover.rs | 1 - crates/collab_ui/src/contact_list.rs | 2 +- crates/command_palette/src/command_palette.rs | 26 ++++------ crates/copilot_button/src/copilot_button.rs | 12 ++--- crates/diagnostics/src/items.rs | 8 +-- crates/editor/src/element.rs | 25 +++++---- crates/feedback/src/deploy_feedback_button.rs | 2 +- crates/feedback/src/feedback_editor.rs | 13 +++-- crates/feedback/src/feedback_info_text.rs | 2 +- crates/feedback/src/submit_feedback_button.rs | 2 +- crates/file_finder/src/file_finder.rs | 4 +- crates/gpui/src/app.rs | 48 +++++++++-------- crates/gpui/src/app/test_app_context.rs | 51 +++++++------------ crates/gpui/src/app/window.rs | 38 ++++++++++---- crates/picker/src/picker.rs | 2 +- crates/project_panel/src/project_panel.rs | 2 +- crates/search/src/buffer_search.rs | 8 +-- crates/search/src/project_search.rs | 9 ++-- crates/terminal_view/src/terminal_element.rs | 2 +- crates/theme_selector/src/theme_selector.rs | 4 +- crates/vim/src/normal.rs | 34 ++++++------- crates/welcome/src/base_keymap_picker.rs | 2 +- crates/welcome/src/welcome.rs | 2 +- crates/workspace/src/pane.rs | 2 +- crates/workspace/src/shared_screen.rs | 2 +- 27 files changed, 154 insertions(+), 162 deletions(-) diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index fe77467ad1..a1677c355e 100644 --- a/crates/activity_indicator/src/activity_indicator.rs +++ b/crates/activity_indicator/src/activity_indicator.rs @@ -361,7 +361,7 @@ impl View for ActivityIndicator { if let Some(action) = action { element = element .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_any_action(action.boxed_clone()) }); } diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 82b542cb6b..1bf2604b12 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -1476,12 +1476,7 @@ async fn test_host_disconnect( .unwrap() .downcast::() .unwrap(); - cx_b.read(|cx| { - assert_eq!( - cx.focused_view_id(workspace_b.window_id()), - Some(editor_b.id()) - ); - }); + assert!(cx_b.read(|cx| editor_b.is_focused(cx))); editor_b.update(cx_b, |editor, cx| editor.insert("X", cx)); assert!(cx_b.is_window_edited(workspace_b.window_id())); @@ -1495,8 +1490,8 @@ async fn test_host_disconnect( assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared())); // Ensure client B's edited state is reset and that the whole window is blurred. - cx_b.read(|cx| { - assert_eq!(cx.focused_view_id(workspace_b.window_id()), None); + cx_b.read_window(|cx| { + assert_eq!(cx.focused_view_id(), None); }); assert!(!cx_b.is_window_edited(workspace_b.window_id())); diff --git a/crates/collab_ui/src/collaborator_list_popover.rs b/crates/collab_ui/src/collaborator_list_popover.rs index bfdcf69eeb..9fad335874 100644 --- a/crates/collab_ui/src/collaborator_list_popover.rs +++ b/crates/collab_ui/src/collaborator_list_popover.rs @@ -80,7 +80,6 @@ impl CollaboratorListPopover { collaborators.len(), Orientation::Top, 0., - cx, move |_, index, cx| match &collaborators[index] { Collaborator::SelfUser { username } => render_collaborator_list_entry( index, diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index 891db3d2ac..979dea717a 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -202,7 +202,7 @@ impl ContactList { }) .detach(); - let list_state = ListState::new(0, Orientation::Top, 1000., cx, move |this, ix, cx| { + let list_state = ListState::new(0, Orientation::Top, 1000., move |this, ix, cx| { let theme = cx.global::().theme.clone(); let is_selected = this.selection == Some(ix); let current_project_id = this.project.read(cx).remote_id(); diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index d7e2178302..1b54bf66b9 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -1,10 +1,8 @@ use collections::CommandPaletteFilter; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ - actions, - elements::{ChildView, Flex, Label, ParentElement}, - keymap_matcher::Keystroke, - Action, AnyViewHandle, AppContext, Element, Entity, MouseState, View, ViewContext, ViewHandle, + actions, elements::*, keymap_matcher::Keystroke, Action, AnyViewHandle, AppContext, Element, + Entity, MouseState, View, ViewContext, ViewHandle, }; use picker::{Picker, PickerDelegate}; use settings::Settings; @@ -78,16 +76,13 @@ impl CommandPalette { fn toggle(_: &mut Workspace, _: &Toggle, cx: &mut ViewContext) { let workspace = cx.handle(); - let window_id = cx.window_id(); let focused_view_id = cx.focused_view_id().unwrap_or_else(|| workspace.id()); - cx.as_mut().defer(move |cx| { - let this = cx.add_view(&workspace, |cx| Self::new(focused_view_id, cx)); - workspace.update(cx, |workspace, cx| { - workspace.toggle_modal(cx, |_, cx| { - cx.subscribe(&this, Self::on_event).detach(); - this - }); + cx.defer(move |workspace, cx| { + let this = cx.add_view(|cx| Self::new(focused_view_id, cx)); + workspace.toggle_modal(cx, |_, cx| { + cx.subscribe(&this, Self::on_event).detach(); + this }); }); } @@ -109,8 +104,7 @@ impl CommandPalette { let focused_view_id = *focused_view_id; let action = action.boxed_clone(); workspace.dismiss_modal(cx); - cx.as_mut() - .defer(move |cx| cx.dispatch_any_action_at(window_id, focused_view_id, action)) + cx.defer(move |_, cx| cx.dispatch_any_action_at(window_id, focused_view_id, action)) } } } @@ -125,7 +119,7 @@ impl View for CommandPalette { "CommandPalette" } - fn render(&mut self, cx: &mut ViewContext) -> gpui::ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } @@ -221,7 +215,7 @@ impl PickerDelegate for CommandPalette { mouse_state: &mut MouseState, selected: bool, cx: &gpui::AppContext, - ) -> gpui::ElementBox { + ) -> ElementBox> { let mat = &self.matches[ix]; let command = &self.actions[mat.candidate_id]; let settings = cx.global::(); diff --git a/crates/copilot_button/src/copilot_button.rs b/crates/copilot_button/src/copilot_button.rs index dd0d4e2e58..b497f79204 100644 --- a/crates/copilot_button/src/copilot_button.rs +++ b/crates/copilot_button/src/copilot_button.rs @@ -153,7 +153,7 @@ impl View for CopilotButton { .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, { let status = status.clone(); - move |_, cx| match status { + move |_, _, cx| match status { Status::Authorized => cx.dispatch_action(DeployCopilotMenu), Status::Starting { ref task } => { cx.dispatch_action(workspace::Toast::new( @@ -162,7 +162,7 @@ impl View for CopilotButton { )); let window_id = cx.window_id(); let task = task.to_owned(); - cx.spawn(|mut cx| async move { + cx.spawn(|this, mut cx| async move { task.await; cx.update(|cx| { if let Some(copilot) = Copilot::global(cx) { @@ -199,13 +199,7 @@ impl View for CopilotButton { _ => cx.dispatch_action(SignIn), } }) - .with_tooltip::( - 0, - "GitHub Copilot".into(), - None, - theme.tooltip.clone(), - cx, - ) + .with_tooltip::(0, "GitHub Copilot".into(), None, theme.tooltip.clone(), cx) .boxed(), ) .with_child( diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index b6116eaec3..c9f7006295 100644 --- a/crates/diagnostics/src/items.rs +++ b/crates/diagnostics/src/items.rs @@ -163,8 +163,10 @@ impl View for DiagnosticIndicator { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(crate::Deploy)) - .with_tooltip::( + .on_click(MouseButton::Left, |_, _, cx| { + cx.dispatch_action(crate::Deploy) + }) + .with_tooltip::( 0, "Project Diagnostics".to_string(), Some(Box::new(crate::Deploy)), @@ -200,7 +202,7 @@ impl View for DiagnosticIndicator { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, cx| { + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(GoToDiagnostic) }) .boxed(), diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index d318ddd307..7b8d89b8f8 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -2574,10 +2574,8 @@ mod tests { let layouts = editor.update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); - let mut presenter = cx.build_window(window_id, 30., Default::default()); - let layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx); element - .layout_line_numbers(0..6, &Default::default(), false, &snapshot, &layout_cx) + .layout_line_numbers(0..6, &Default::default(), false, &snapshot, cx) .0 }); assert_eq!(layouts.len(), 6); @@ -2609,14 +2607,13 @@ mod tests { }); let mut element = EditorElement::new(editor.downgrade(), editor.read(cx).style(cx)); - - let mut scene = SceneBuilder::new(1.0); - let mut presenter = cx.build_window(window_id, 30., Default::default()); - let mut layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx); - let (size, mut state) = element.layout( - SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)), - &mut layout_cx, - ); + let (size, mut state) = editor.update(cx, |editor, cx| { + element.layout( + SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)), + editor, + cx, + ) + }); assert_eq!(state.position_map.line_layouts.len(), 4); assert_eq!( @@ -2629,8 +2626,10 @@ mod tests { ); // Don't panic. + let mut scene = SceneBuilder::new(1.0); let bounds = RectF::new(Default::default(), size); - let mut paint_cx = presenter.build_paint_context(&mut scene, bounds.size(), cx); - element.paint(bounds, bounds, &mut state, &mut paint_cx); + editor.update(cx, |editor, cx| { + element.paint(&mut scene, bounds, bounds, &mut state, editor, cx); + }); } } diff --git a/crates/feedback/src/deploy_feedback_button.rs b/crates/feedback/src/deploy_feedback_button.rs index aa900597d7..a41abe6584 100644 --- a/crates/feedback/src/deploy_feedback_button.rs +++ b/crates/feedback/src/deploy_feedback_button.rs @@ -27,7 +27,7 @@ impl View for DeployFeedbackButton { "DeployFeedbackButton" } - fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let active = self.active; let theme = cx.global::().theme.clone(); Stack::new() diff --git a/crates/feedback/src/feedback_editor.rs b/crates/feedback/src/feedback_editor.rs index bae006b8c6..b24cdcb5e9 100644 --- a/crates/feedback/src/feedback_editor.rs +++ b/crates/feedback/src/feedback_editor.rs @@ -13,7 +13,7 @@ use gpui::{ elements::{ChildView, Flex, Label, ParentElement, Svg}, platform::PromptLevel, serde_json, AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelHandle, Task, View, - ViewContext, ViewContext, ViewHandle, + ViewContext, ViewHandle, }; use isahc::Request; use language::Buffer; @@ -25,7 +25,7 @@ use util::ResultExt; use workspace::{ item::{Item, ItemHandle}, searchable::{SearchableItem, SearchableItemHandle}, - AppState, Workspace, + AppState, Pane, Workspace, }; use crate::{submit_feedback_button::SubmitFeedbackButton, system_specs::SystemSpecs}; @@ -232,7 +232,7 @@ impl View for FeedbackEditor { "FeedbackEditor" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.editor, cx).boxed() } @@ -248,7 +248,12 @@ impl Entity for FeedbackEditor { } impl Item for FeedbackEditor { - fn tab_content(&self, _: Option, style: &theme::Tab, _: &AppContext) -> ElementBox { + fn tab_content( + &self, + _: Option, + style: &theme::Tab, + _: &AppContext, + ) -> ElementBox { Flex::row() .with_child( Svg::new("icons/feedback_16.svg") diff --git a/crates/feedback/src/feedback_info_text.rs b/crates/feedback/src/feedback_info_text.rs index fe1a4bc82c..78eb6864b4 100644 --- a/crates/feedback/src/feedback_info_text.rs +++ b/crates/feedback/src/feedback_info_text.rs @@ -29,7 +29,7 @@ impl View for FeedbackInfoText { "FeedbackInfoText" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); Flex::row() diff --git a/crates/feedback/src/submit_feedback_button.rs b/crates/feedback/src/submit_feedback_button.rs index 720f032c4d..562a0e76ed 100644 --- a/crates/feedback/src/submit_feedback_button.rs +++ b/crates/feedback/src/submit_feedback_button.rs @@ -29,7 +29,7 @@ impl View for SubmitFeedbackButton { "SubmitFeedbackButton" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); enum SubmitFeedbackButton {} MouseEventHandler::::new(0, cx, |state, _| { diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 0995578e7c..bc26ad3fa5 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -50,7 +50,7 @@ impl View for FileFinder { "FileFinder" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } @@ -267,7 +267,7 @@ impl PickerDelegate for FileFinder { mouse_state: &mut MouseState, selected: bool, cx: &AppContext, - ) -> ElementBox { + ) -> ElementBox> { let path_match = &self.matches[ix]; let settings = cx.global::(); let style = settings.theme.picker.item.style_for(mouse_state, selected); diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 260aa5697d..0a16042126 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -936,6 +936,16 @@ impl AppContext { result } + pub fn read_window T>( + &self, + window_id: usize, + callback: F, + ) -> Option { + let window = self.windows.get(&window_id)?; + let window_context = WindowContext::immutable(self, &window, window_id); + Some(callback(&window_context)) + } + pub fn update_window T>( &mut self, window_id: usize, @@ -943,13 +953,7 @@ impl AppContext { ) -> Option { self.update(|app_context| { let mut window = app_context.windows.remove(&window_id)?; - let mut window_context = WindowContext { - app_context, - window: &mut window, - window_id, - refreshing: false, - }; - + let mut window_context = WindowContext::mutable(app_context, &mut window, window_id); let result = callback(&mut window_context); app_context.windows.insert(window_id, window); Some(result) @@ -1651,7 +1655,7 @@ impl AppContext { })); let mut window = Window::new(window_id, platform_window, self, build_root_view); - let scene = WindowContext::new(self, &mut window, window_id).build_scene(); + let scene = WindowContext::mutable(self, &mut window, window_id).build_scene(); window.platform_window.present_scene(scene); window } @@ -3244,7 +3248,7 @@ impl DerefMut for ModelContext<'_, M> { } pub struct ViewContext<'a, 'b, 'c, T: ?Sized> { - window_context: WindowContextRef<'a, 'b, 'c>, + window_context: Reference<'c, WindowContext<'a, 'b>>, view_id: usize, view_type: PhantomData, } @@ -3266,7 +3270,7 @@ impl DerefMut for ViewContext<'_, '_, '_, T> { impl<'a, 'b, 'c, V: View> ViewContext<'a, 'b, 'c, V> { pub(crate) fn mutable(window_context: &'c mut WindowContext<'a, 'b>, view_id: usize) -> Self { Self { - window_context: WindowContextRef::Mutable(window_context), + window_context: Reference::Mutable(window_context), view_id, view_type: PhantomData, } @@ -3274,7 +3278,7 @@ impl<'a, 'b, 'c, V: View> ViewContext<'a, 'b, 'c, V> { pub(crate) fn immutable(window_context: &'c WindowContext<'a, 'b>, view_id: usize) -> Self { Self { - window_context: WindowContextRef::Immutable(window_context), + window_context: Reference::Immutable(window_context), view_id, view_type: PhantomData, } @@ -3819,29 +3823,29 @@ impl UpdateView for ViewContext<'_, '_, '_, V> { } } -enum WindowContextRef<'a, 'b, 'c> { - Immutable(&'c WindowContext<'a, 'b>), - Mutable(&'c mut WindowContext<'a, 'b>), +pub(crate) enum Reference<'a, T> { + Immutable(&'a T), + Mutable(&'a mut T), } -impl<'a, 'b, 'c> Deref for WindowContextRef<'a, 'b, 'c> { - type Target = WindowContext<'a, 'b>; +impl<'a, T> Deref for Reference<'a, T> { + type Target = T; fn deref(&self) -> &Self::Target { match self { - WindowContextRef::Immutable(window_context) => window_context, - WindowContextRef::Mutable(window_context) => window_context, + Reference::Immutable(target) => target, + Reference::Mutable(target) => target, } } } -impl<'a, 'b, 'c> DerefMut for WindowContextRef<'a, 'b, 'c> { +impl<'a, T> DerefMut for Reference<'a, T> { fn deref_mut(&mut self) -> &mut Self::Target { match self { - WindowContextRef::Immutable(_) => { - panic!("cannot mutably deref an immutable WindowContext. this is a bug in GPUI."); + Reference::Immutable(_) => { + panic!("cannot mutably deref an immutable reference. this is a bug in GPUI."); } - WindowContextRef::Mutable(window_context) => window_context, + Reference::Mutable(target) => target, } } } diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index a6624b0a54..6f3bf15f85 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -23,7 +23,7 @@ use crate::{ platform::{Event, InputHandler, KeyDownEvent, Platform}, Action, AnyViewHandle, AppContext, Entity, FontCache, Handle, ModelContext, ModelHandle, ReadModelWith, ReadViewWith, Task, UpdateModel, UpdateView, View, ViewContext, ViewHandle, - WeakHandle, + WeakHandle, WindowContext, }; use collections::BTreeMap; @@ -114,6 +114,22 @@ impl TestAppContext { } } + pub fn read_window T>( + &self, + window_id: usize, + callback: F, + ) -> Option { + self.cx.borrow().read_window(window_id, callback) + } + + pub fn update_window T>( + &mut self, + window_id: usize, + callback: F, + ) -> Option { + self.cx.borrow_mut().update_window(window_id, callback) + } + pub fn add_model(&mut self, build_model: F) -> ModelHandle where T: Entity, @@ -147,17 +163,6 @@ impl TestAppContext { self.cx.borrow().window_ids().collect() } - pub fn root_view(&self, window_id: usize) -> Option { - Some( - self.cx - .borrow() - .windows - .get(&window_id)? - .root_view() - .clone(), - ) - } - pub fn read T>(&self, callback: F) -> T { callback(&*self.cx.borrow()) } @@ -173,28 +178,6 @@ impl TestAppContext { result } - pub fn render(&mut self, handle: &ViewHandle, f: F) -> T - where - F: FnOnce(&mut V, &mut ViewContext) -> T, - V: View, - { - todo!() - // handle.update(&mut *self.cx.borrow_mut(), |view, cx| { - // let mut render_cx = ViewContext { - // app: cx, - // window_id: handle.window_id(), - // view_id: handle.id(), - // view_type: PhantomData, - // titlebar_height: 0., - // hovered_region_ids: Default::default(), - // clicked_region_ids: None, - // refreshing: false, - // appearance: Appearance::Light, - // }; - // f(view, &mut render_cx) - // }) - } - pub fn to_async(&self) -> AsyncAppContext { AsyncAppContext(self.cx.clone()) } diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 244a8be446..097d1bc562 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -30,6 +30,8 @@ use sqlez::{ use std::ops::{Deref, DerefMut, Range}; use uuid::Uuid; +use super::Reference; + pub struct Window { pub(crate) root_view: Option, pub(crate) focused_view_id: Option, @@ -83,7 +85,7 @@ impl Window { appearance, }; - let mut window_context = WindowContext::new(cx, &mut window, window_id); + let mut window_context = WindowContext::mutable(cx, &mut window, window_id); let root_view = window_context .build_and_insert_view(ParentId::Root, |cx| Some(build_view(cx))) .unwrap(); @@ -101,8 +103,8 @@ impl Window { } pub struct WindowContext<'a: 'b, 'b> { - pub(crate) app_context: &'a mut AppContext, - pub(crate) window: &'b mut Window, // TODO: make this private? + pub(crate) app_context: Reference<'a, AppContext>, + pub(crate) window: Reference<'b, Window>, pub(crate) window_id: usize, pub(crate) refreshing: bool, } @@ -111,7 +113,7 @@ impl Deref for WindowContext<'_, '_> { type Target = AppContext; fn deref(&self) -> &Self::Target { - self.app_context + &self.app_context } } @@ -148,10 +150,23 @@ impl UpgradeViewHandle for WindowContext<'_, '_> { } impl<'a: 'b, 'b> WindowContext<'a, 'b> { - pub fn new(app_context: &'a mut AppContext, window: &'b mut Window, window_id: usize) -> Self { + pub fn mutable( + app_context: &'a mut AppContext, + window: &'b mut Window, + window_id: usize, + ) -> Self { Self { - app_context, - window, + app_context: Reference::Mutable(app_context), + window: Reference::Mutable(window), + window_id, + refreshing: false, + } + } + + pub fn immutable(app_context: &'a AppContext, window: &'b Window, window_id: usize) -> Self { + Self { + app_context: Reference::Immutable(app_context), + window: Reference::Immutable(window), window_id, refreshing: false, } @@ -162,7 +177,7 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { } pub fn app_context(&mut self) -> &mut AppContext { - self.app_context + &mut self.app_context } pub fn root_view(&self) -> &AnyViewHandle { @@ -406,7 +421,8 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { MouseEvent::Hover(_) => { let mut highest_z_index = None; let mouse_position = self.window.mouse_position.clone(); - for (region, z_index) in self.window.mouse_regions.iter().rev() { + let window = &mut *self.window; + for (region, z_index) in window.mouse_regions.iter().rev() { // Allow mouse regions to appear transparent to hovers if !region.hoverable { continue; @@ -424,7 +440,7 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { // highest_z_index is set. if contains_mouse && z_index == highest_z_index.unwrap() { //Ensure that hover entrance events aren't sent twice - if self.window.hovered_region_ids.insert(region.id()) { + if window.hovered_region_ids.insert(region.id()) { valid_regions.push(region.clone()); if region.notify_on_hover { notified_views.insert(region.id().view_id()); @@ -432,7 +448,7 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> { } } else { // Ensure that hover exit events aren't sent twice - if self.window.hovered_region_ids.remove(®ion.id()) { + if window.hovered_region_ids.remove(®ion.id()) { valid_regions.push(region.clone()); if region.notify_on_hover { notified_views.insert(region.id().view_id()); diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index 5cdfdc654c..f533e886f7 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -33,7 +33,7 @@ pub trait PickerDelegate: View { state: &mut MouseState, selected: bool, cx: &AppContext, - ) -> ElementBox; + ) -> ElementBox>; fn center_selection_after_match_updates(&self) -> bool { false } diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 609765cffb..4cd75e94ec 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1238,7 +1238,7 @@ impl ProjectPanel { .is_some() { if let Some(this) = this.upgrade(cx) { - this.update(cx, |this, _, _| { + this.update(cx, |this, _| { this.dragged_entry_destination = if matches!(kind, EntryKind::File(_)) { path.parent().map(|parent| Arc::from(parent)) } else { diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index e36c60a825..4f434fc4d2 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -348,7 +348,7 @@ impl BufferSearchBar { cx.dispatch_any_action(option.to_toggle_action()) }) .with_cursor_style(CursorStyle::PointingHand) - .with_tooltip::( + .with_tooltip::( option as usize, format!("Toggle {}", option.label()), Some(option.to_toggle_action()), @@ -394,10 +394,10 @@ impl BufferSearchBar { }) .on_click(MouseButton::Left, { let action = action.boxed_clone(); - mov_, _, cx| cx.dispatch_any_action(action.boxed_clone()) + move |_, _, cx| cx.dispatch_any_action(action.boxed_clone()) }) .with_cursor_style(CursorStyle::PointingHand) - .with_tooltip::( + .with_tooltip::( direction as usize, tooltip.to_string(), Some(action), @@ -432,7 +432,7 @@ impl BufferSearchBar { }) .on_click(MouseButton::Left, { let action = action.boxed_clone(); - move |_, _, _, cx| cx.dispatch_any_action(action.boxed_clone()) + move |_, _, cx| cx.dispatch_any_action(action.boxed_clone()) }) .with_cursor_style(CursorStyle::PointingHand) .with_tooltip::(0, tooltip.to_string(), Some(action), tooltip_style, cx) diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 586deee613..3b947a67be 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -198,7 +198,7 @@ impl View for ProjectSearchView { .flex(1., true) .boxed() }) - .on_down(MouseButton::Left, |_, _, _, cx| { + .on_down(MouseButton::Left, |_, _, cx| { cx.focus_parent_view(); }) .boxed() @@ -775,12 +775,13 @@ impl ProjectSearchBar { .with_style(style.container) .boxed() }) - .on_click(MouseButton::Le { + .on_click(MouseButton::Left, { let action = action.boxed_clone(); move |_, _, cx| cx.dispatch_any_action(action.boxed_clone()) - _, }) + }) .with_cursor_style(CursorStyle::PointingHand) - .with_tooltip::( + direction as usize, tooltip.to_string(), Some(action), tooltip_style, diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index 9c13111da8..6506536842 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -812,7 +812,7 @@ impl Element for TerminalElement { } if let Some(element) = &mut layout.hyperlink_tooltip { - Element::paint(element, scene, origin, visible_bounds, view, view, cx) + element.paint(scene, origin, visible_bounds, view, cx) } }); } diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index 7ac5b27367..97e939410e 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -226,7 +226,7 @@ impl PickerDelegate for ThemeSelector { mouse_state: &mut MouseState, selected: bool, cx: &AppContext, - ) -> ElementBox { + ) -> ElementBox> { let settings = cx.global::(); let theme = &settings.theme; let theme_match = &self.matches[ix]; @@ -255,7 +255,7 @@ impl View for ThemeSelector { "ThemeSelector" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } diff --git a/crates/vim/src/normal.rs b/crates/vim/src/normal.rs index ef73f2e9b4..ad55c87576 100644 --- a/crates/vim/src/normal.rs +++ b/crates/vim/src/normal.rs @@ -570,18 +570,18 @@ mod test { cx.assert_all(indoc! {" The ˇquick - + brown fox jumps overˇ the lazy doˇg"}) .await; cx.assert(indoc! {" The quiˇck - + brown"}) .await; cx.assert(indoc! {" The quiˇck - + "}) .await; } @@ -611,16 +611,16 @@ mod test { let mut cx = NeovimBackedTestContext::new(cx).await.binding(["e"]); cx.assert_all(indoc! {" Thˇe quicˇkˇ-browˇn - - + + fox_jumpˇs oveˇr thˇe"}) .await; let mut cx = cx.binding(["shift-e"]); cx.assert_all(indoc! {" Thˇe quicˇkˇ-browˇn - - + + fox_jumpˇs oveˇr thˇe"}) .await; @@ -669,7 +669,7 @@ mod test { ["g", "g"], indoc! {" The qˇuick - + brown fox jumps over ˇthe laˇzy dog"}, ) @@ -677,8 +677,8 @@ mod test { cx.assert_binding_matches( ["g", "g"], indoc! {" - - + + brown fox jumps over the laˇzy dog"}, ) @@ -687,7 +687,7 @@ mod test { ["2", "g", "g"], indoc! {" ˇ - + brown fox jumps over the lazydog"}, ) @@ -701,7 +701,7 @@ mod test { ["shift-g"], indoc! {" The qˇuick - + brown fox jumps over ˇthe laˇzy dog"}, ) @@ -709,8 +709,8 @@ mod test { cx.assert_binding_matches( ["shift-g"], indoc! {" - - + + brown fox jumps over the laˇzy dog"}, ) @@ -719,7 +719,7 @@ mod test { ["2", "shift-g"], indoc! {" ˇ - + brown fox jumps over the lazydog"}, ) @@ -999,7 +999,7 @@ mod test { let test_case = indoc! {" ˇaaaˇbˇ ˇbˇ ˇbˇbˇ aˇaaˇbaaa ˇ ˇbˇaaˇa ˇbˇbˇb - ˇ + ˇ ˇb "}; @@ -1017,7 +1017,7 @@ mod test { let test_case = indoc! {" ˇaaaˇbˇ ˇbˇ ˇbˇbˇ aˇaaˇbaaa ˇ ˇbˇaaˇa ˇbˇbˇb - ˇ + ˇ ˇb "}; diff --git a/crates/welcome/src/base_keymap_picker.rs b/crates/welcome/src/base_keymap_picker.rs index 07cfe037a4..be516ed038 100644 --- a/crates/welcome/src/base_keymap_picker.rs +++ b/crates/welcome/src/base_keymap_picker.rs @@ -74,7 +74,7 @@ impl View for BaseKeymapSelector { "BaseKeymapSelector" } - fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext) -> gpui::ElementBox { ChildView::new(&self.picker, cx).boxed() } diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 50e85a4f3a..3505884fb2 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -55,7 +55,7 @@ impl View for WelcomePage { "WelcomePage" } - fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext) -> ElementBox { let self_handle = cx.handle(); let settings = cx.global::(); let theme = settings.theme.clone(); diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index df8290816c..9f67991f5e 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1404,7 +1404,7 @@ impl Pane { }; ConstrainedBox::new( - Canvas::new(move |scene, bounds, _, _, cx| { + Canvas::new(move |scene, bounds, _, _, _| { if let Some(color) = icon_color { let square = RectF::new(bounds.origin(), vec2f(diameter, diameter)); scene.push_quad(Quad { diff --git a/crates/workspace/src/shared_screen.rs b/crates/workspace/src/shared_screen.rs index 383651b991..60f7602f04 100644 --- a/crates/workspace/src/shared_screen.rs +++ b/crates/workspace/src/shared_screen.rs @@ -69,7 +69,7 @@ impl View for SharedScreen { let frame = self.frame.clone(); MouseEventHandler::::new(0, cx, |_, cx| { - Canvas::new(move |scene, bounds, _, _, cx| { + Canvas::new(move |scene, bounds, _, _, _| { if let Some(frame) = frame.clone() { let size = constrain_size_preserving_aspect_ratio( bounds.size(), From 868301bedb3b51623e09c38b9819d229e4cba515 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 12 Apr 2023 10:07:17 -0600 Subject: [PATCH 11/58] WIP --- crates/breadcrumbs/src/breadcrumbs.rs | 2 +- crates/collab_ui/src/face_pile.rs | 18 ++-- crates/diagnostics/src/diagnostics.rs | 4 +- crates/feedback/src/deploy_feedback_button.rs | 6 +- crates/feedback/src/feedback_info_text.rs | 4 +- crates/feedback/src/submit_feedback_button.rs | 6 +- crates/gpui/src/app.rs | 88 +++++++++++++++++++ .../gpui/src/elements/mouse_event_handler.rs | 7 +- crates/gpui/src/gpui.rs | 4 +- crates/gpui/src/scene/mouse_region.rs | 81 +---------------- crates/gpui/src/views/select.rs | 20 +++-- .../src/active_buffer_language.rs | 8 +- .../src/language_selector.rs | 4 +- crates/outline/src/outline.rs | 4 +- crates/project_panel/src/project_panel.rs | 2 +- crates/project_symbols/src/project_symbols.rs | 4 +- .../src/highlighted_workspace_location.rs | 4 +- crates/recent_projects/src/recent_projects.rs | 4 +- crates/terminal_view/src/terminal_element.rs | 52 ++++++----- crates/terminal_view/src/terminal_view.rs | 2 +- crates/theme/src/ui.rs | 5 +- crates/vim/src/normal.rs | 2 +- crates/vim/src/visual.rs | 2 +- crates/welcome/src/base_keymap_picker.rs | 2 +- crates/welcome/src/welcome.rs | 6 +- crates/workspace/src/pane.rs | 28 +++--- 26 files changed, 194 insertions(+), 175 deletions(-) diff --git a/crates/breadcrumbs/src/breadcrumbs.rs b/crates/breadcrumbs/src/breadcrumbs.rs index ecb5d8adaf..e53261d7a0 100644 --- a/crates/breadcrumbs/src/breadcrumbs.rs +++ b/crates/breadcrumbs/src/breadcrumbs.rs @@ -41,7 +41,7 @@ impl View for Breadcrumbs { "Breadcrumbs" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let active_item = match &self.active_item { Some(active_item) => active_item, None => return Empty::new().boxed(), diff --git a/crates/collab_ui/src/face_pile.rs b/crates/collab_ui/src/face_pile.rs index 9269a32fdb..f813cd34a9 100644 --- a/crates/collab_ui/src/face_pile.rs +++ b/crates/collab_ui/src/face_pile.rs @@ -7,7 +7,8 @@ use gpui::{ }, json::ToJson, serde_json::{self, json}, - Axis, DebugContext, Element, ElementBox, MeasurementContext, PaintContext, + Axis, DebugContext, Element, ElementBox, MeasurementContext, PaintContext, SceneBuilder, + ViewContext, }; pub(crate) struct FacePile { @@ -24,14 +25,15 @@ impl FacePile { } } -impl Element for FacePile { +impl Element for FacePile { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: gpui::SizeConstraint, - cx: &mut gpui::LayoutContext, + view: &mut Self, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { debug_assert!(constraint.max_along(Axis::Horizontal) == f32::INFINITY); @@ -46,10 +48,12 @@ impl Element for FacePile { fn paint( &mut self, + scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _layout: &mut Self::LayoutState, - cx: &mut PaintContext, + view: &mut Self, + cx: &mut ViewContext, ) -> Self::PaintState { let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); @@ -59,7 +63,7 @@ impl Element for FacePile { for face in self.faces.iter_mut().rev() { let size = face.size(); origin_x -= size.x(); - cx.paint_layer(None, |cx| { + scene.paint_layer(None, |scene| { face.paint(scene, vec2f(origin_x, origin_y), visible_bounds, view, cx); }); origin_x += self.overlap; @@ -94,8 +98,8 @@ impl Element for FacePile { } } -impl Extend for FacePile { - fn extend>(&mut self, children: T) { +impl Extend> for FacePile { + fn extend>>(&mut self, children: T) { self.faces.extend(children); } } diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 9b7445559f..fdf75ad69d 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -1176,9 +1176,7 @@ mod tests { } fn editor_blocks(editor: &ViewHandle, cx: &mut AppContext) -> Vec<(u32, String)> { - let mut presenter = cx.build_window(editor.id(), 0., Default::default()); - let mut cx = presenter.build_layout_context(Default::default(), false, cx); - cx.render(editor, |editor, cx| { + editor.update(cx, |editor, cx| { let snapshot = editor.snapshot(cx); snapshot .blocks_in_range(0..snapshot.max_point().row()) diff --git a/crates/feedback/src/deploy_feedback_button.rs b/crates/feedback/src/deploy_feedback_button.rs index a41abe6584..05985fc2c3 100644 --- a/crates/feedback/src/deploy_feedback_button.rs +++ b/crates/feedback/src/deploy_feedback_button.rs @@ -32,7 +32,7 @@ impl View for DeployFeedbackButton { let theme = cx.global::().theme.clone(); Stack::new() .with_child( - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = &theme .workspace .status_bar @@ -53,12 +53,12 @@ impl View for DeployFeedbackButton { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { if !active { cx.dispatch_action(GiveFeedback) } }) - .with_tooltip::( + .with_tooltip::( 0, "Send Feedback".into(), Some(Box::new(GiveFeedback)), diff --git a/crates/feedback/src/feedback_info_text.rs b/crates/feedback/src/feedback_info_text.rs index 78eb6864b4..fbe97e86cc 100644 --- a/crates/feedback/src/feedback_info_text.rs +++ b/crates/feedback/src/feedback_info_text.rs @@ -43,7 +43,7 @@ impl View for FeedbackInfoText { .boxed(), ) .with_child( - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let contained_text = if state.hovered() { &theme.feedback.link_text_hover } else { @@ -58,7 +58,7 @@ impl View for FeedbackInfoText { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, cx| { + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(OpenZedCommunityRepo) }) .boxed(), diff --git a/crates/feedback/src/submit_feedback_button.rs b/crates/feedback/src/submit_feedback_button.rs index 562a0e76ed..21cf9666fb 100644 --- a/crates/feedback/src/submit_feedback_button.rs +++ b/crates/feedback/src/submit_feedback_button.rs @@ -32,7 +32,7 @@ impl View for SubmitFeedbackButton { fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); enum SubmitFeedbackButton {} - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = theme.feedback.submit_button.style_for(state, false); Label::new("Submit as Markdown", style.text.clone()) .contained() @@ -40,13 +40,13 @@ impl View for SubmitFeedbackButton { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, cx| { + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(SubmitFeedback) }) .aligned() .contained() .with_margin_left(theme.feedback.button_margin) - .with_tooltip::( + .with_tooltip::( 0, "cmd-s".into(), Some(Box::new(SubmitFeedback)), diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 0a16042126..4caef6fa64 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -3823,6 +3823,94 @@ impl UpdateView for ViewContext<'_, '_, '_, V> { } } +pub struct EventContext<'a, 'b, 'c, 'd, V: View> { + view_context: &'d mut ViewContext<'a, 'b, 'c, V>, + pub(crate) handled: bool, +} + +impl<'a, 'b, 'c, 'd, V: View> EventContext<'a, 'b, 'c, 'd, V> { + pub(crate) fn new(view_context: &'d mut ViewContext<'a, 'b, 'c, V>) -> Self { + EventContext { + view_context, + handled: true, + } + } + + pub fn propagate_event(&mut self) { + self.handled = false; + } +} + +impl<'a, 'b, 'c, 'd, V: View> Deref for EventContext<'a, 'b, 'c, 'd, V> { + type Target = ViewContext<'a, 'b, 'c, V>; + + fn deref(&self) -> &Self::Target { + &self.view_context + } +} + +impl DerefMut for EventContext<'_, '_, '_, '_, V> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.view_context + } +} + +impl UpdateModel for EventContext<'_, '_, '_, '_, V> { + fn update_model( + &mut self, + handle: &ModelHandle, + update: &mut dyn FnMut(&mut T, &mut ModelContext) -> O, + ) -> O { + self.view_context.update_model(handle, update) + } +} + +impl ReadView for EventContext<'_, '_, '_, '_, V> { + fn read_view(&self, handle: &crate::ViewHandle) -> &W { + self.view_context.read_view(handle) + } +} + +impl UpdateView for EventContext<'_, '_, '_, '_, V> { + fn update_view( + &mut self, + handle: &ViewHandle, + update: &mut dyn FnMut(&mut T, &mut ViewContext) -> S, + ) -> S + where + T: View, + { + self.view_context.update_view(handle, update) + } +} + +impl UpgradeModelHandle for EventContext<'_, '_, '_, '_, V> { + fn upgrade_model_handle( + &self, + handle: &WeakModelHandle, + ) -> Option> { + self.view_context.upgrade_model_handle(handle) + } + + fn model_handle_is_upgradable(&self, handle: &WeakModelHandle) -> bool { + self.view_context.model_handle_is_upgradable(handle) + } + + fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option { + self.view_context.upgrade_any_model_handle(handle) + } +} + +impl UpgradeViewHandle for EventContext<'_, '_, '_, '_, V> { + fn upgrade_view_handle(&self, handle: &WeakViewHandle) -> Option> { + self.view_context.upgrade_view_handle(handle) + } + + fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option { + self.view_context.upgrade_any_view_handle(handle) + } +} + pub(crate) enum Reference<'a, T> { Immutable(&'a T), Mutable(&'a mut T), diff --git a/crates/gpui/src/elements/mouse_event_handler.rs b/crates/gpui/src/elements/mouse_event_handler.rs index c2c53b8b15..dc82648ef4 100644 --- a/crates/gpui/src/elements/mouse_event_handler.rs +++ b/crates/gpui/src/elements/mouse_event_handler.rs @@ -7,10 +7,11 @@ use crate::{ platform::CursorStyle, platform::MouseButton, scene::{ - CursorRegion, EventContext, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, - MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, + CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover, + MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, }, - Element, ElementBox, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View, ViewContext, + Element, ElementBox, EventContext, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View, + ViewContext, }; use serde_json::json; use std::{marker::PhantomData, ops::Range}; diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 5e7ee19b5b..147e71b0ce 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -15,9 +15,7 @@ pub use clipboard::ClipboardItem; pub mod fonts; pub mod geometry; pub mod scene; -pub use scene::{ - Border, CursorRegion, EventContext, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder, -}; +pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder}; pub mod text_layout; pub use text_layout::TextLayoutCache; mod util; diff --git a/crates/gpui/src/scene/mouse_region.rs b/crates/gpui/src/scene/mouse_region.rs index 601634329c..258583124f 100644 --- a/crates/gpui/src/scene/mouse_region.rs +++ b/crates/gpui/src/scene/mouse_region.rs @@ -1,22 +1,14 @@ +use crate::{platform::MouseButton, window::WindowContext, EventContext, View, ViewContext}; +use collections::HashMap; +use pathfinder_geometry::rect::RectF; +use smallvec::SmallVec; use std::{ any::{Any, TypeId}, fmt::Debug, mem::Discriminant, - ops::{Deref, DerefMut}, rc::Rc, }; -use collections::HashMap; - -use pathfinder_geometry::rect::RectF; -use smallvec::SmallVec; - -use crate::{ - platform::MouseButton, window::WindowContext, AnyModelHandle, AnyViewHandle, - AnyWeakModelHandle, AnyWeakViewHandle, Entity, ModelHandle, ReadView, UpgradeModelHandle, - UpgradeViewHandle, View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle, -}; - use super::{ mouse_event::{ MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover, MouseMove, MouseUp, @@ -206,71 +198,6 @@ impl MouseRegionId { } } -pub struct EventContext<'a, 'b, 'c, 'd, V: View> { - view_context: &'d mut ViewContext<'a, 'b, 'c, V>, - handled: bool, -} - -impl<'a, 'b, 'c, 'd, V: View> EventContext<'a, 'b, 'c, 'd, V> { - fn new(view_context: &'d mut ViewContext<'a, 'b, 'c, V>) -> Self { - EventContext { - view_context, - handled: true, - } - } - - pub fn propagate_event(&mut self) { - self.handled = false; - } -} - -impl<'a, 'b, 'c, 'd, V: View> Deref for EventContext<'a, 'b, 'c, 'd, V> { - type Target = ViewContext<'a, 'b, 'c, V>; - - fn deref(&self) -> &Self::Target { - &self.view_context - } -} - -impl DerefMut for EventContext<'_, '_, '_, '_, V> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.view_context - } -} - -impl ReadView for EventContext<'_, '_, '_, '_, V> { - fn read_view(&self, handle: &crate::ViewHandle) -> &W { - self.view_context.read_view(handle) - } -} - -impl UpgradeModelHandle for EventContext<'_, '_, '_, '_, V> { - fn upgrade_model_handle( - &self, - handle: &WeakModelHandle, - ) -> Option> { - self.view_context.upgrade_model_handle(handle) - } - - fn model_handle_is_upgradable(&self, handle: &WeakModelHandle) -> bool { - self.view_context.model_handle_is_upgradable(handle) - } - - fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option { - self.view_context.upgrade_any_model_handle(handle) - } -} - -impl UpgradeViewHandle for EventContext<'_, '_, '_, '_, V> { - fn upgrade_view_handle(&self, handle: &WeakViewHandle) -> Option> { - self.view_context.upgrade_view_handle(handle) - } - - fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option { - self.view_context.upgrade_any_view_handle(handle) - } -} - pub type HandlerCallback = Rc bool>; #[derive(Clone, PartialEq, Eq, Hash)] diff --git a/crates/gpui/src/views/select.rs b/crates/gpui/src/views/select.rs index dba1b8023b..3786a39d6c 100644 --- a/crates/gpui/src/views/select.rs +++ b/crates/gpui/src/views/select.rs @@ -1,8 +1,8 @@ use serde::Deserialize; use crate::{ - actions, elements::*, impl_actions, platform::MouseButton, AppContext, Entity, View, - ViewContext, WeakViewHandle, + actions, elements::*, impl_actions, platform::MouseButton, AppContext, Entity, EventContext, + View, ViewContext, WeakViewHandle, }; pub struct Select { @@ -116,9 +116,10 @@ impl View for Select { .with_style(style.header) .boxed() }) - .on_click(MouseButton::Left, move |_, _, cx| { - cx.dispatch_action(ToggleSelect) - }) + .on_click( + MouseButton::Left, + move |_, _, cx: &mut EventContext| cx.dispatch_action(ToggleSelect), + ) .boxed(), ); if self.is_open { @@ -150,9 +151,12 @@ impl View for Select { ) }, ) - .on_click(MouseButton::Left, move |_, _, cx| { - cx.dispatch_action(SelectItem(ix)) - }) + .on_click( + MouseButton::Left, + move |_, _, cx: &mut EventContext| { + cx.dispatch_action(SelectItem(ix)) + }, + ) .boxed() })) }, diff --git a/crates/language_selector/src/active_buffer_language.rs b/crates/language_selector/src/active_buffer_language.rs index 87499664ae..5689d9a909 100644 --- a/crates/language_selector/src/active_buffer_language.rs +++ b/crates/language_selector/src/active_buffer_language.rs @@ -50,7 +50,7 @@ impl View for ActiveBufferLanguage { "ActiveBufferLanguage" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { if let Some(active_language) = self.active_language.as_ref() { let active_language_text = if let Some(active_language_text) = active_language { active_language_text.to_string() @@ -58,7 +58,7 @@ impl View for ActiveBufferLanguage { "Unknown".to_string() }; - MouseEventHandler::::new(0, cx, |state, cx| { + MouseEventHandler::::new(0, cx, |state, cx| { let theme = &cx.global::().theme.workspace.status_bar; let style = theme.active_language.style_for(state, false); Label::new(active_language_text, style.text.clone()) @@ -67,7 +67,9 @@ impl View for ActiveBufferLanguage { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(crate::Toggle)) + .on_click(MouseButton::Left, |_, _, cx| { + cx.dispatch_action(crate::Toggle) + }) .boxed() } else { Empty::new().boxed() diff --git a/crates/language_selector/src/language_selector.rs b/crates/language_selector/src/language_selector.rs index 3269fafed0..1eb85a1a25 100644 --- a/crates/language_selector/src/language_selector.rs +++ b/crates/language_selector/src/language_selector.rs @@ -120,7 +120,7 @@ impl View for LanguageSelector { "LanguageSelector" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } @@ -210,7 +210,7 @@ impl PickerDelegate for LanguageSelector { mouse_state: &mut MouseState, selected: bool, cx: &AppContext, - ) -> ElementBox { + ) -> ElementBox> { let settings = cx.global::(); let theme = &settings.theme; let mat = &self.matches[ix]; diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index c7167b0eb4..f4397b6f1a 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -48,7 +48,7 @@ impl View for OutlineView { "OutlineView" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } @@ -238,7 +238,7 @@ impl PickerDelegate for OutlineView { mouse_state: &mut MouseState, selected: bool, cx: &AppContext, - ) -> ElementBox { + ) -> ElementBox> { let settings = cx.global::(); let string_match = &self.matches[ix]; let style = settings.theme.picker.item.style_for(mouse_state, selected); diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 4cd75e94ec..bfaa74a5ed 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1251,7 +1251,7 @@ impl ProjectPanel { .as_draggable(entry_id, { let row_container_style = theme.dragged_entry.container; - move |_, _, cx: &mut ViewContext| { + move |_, cx: &mut ViewContext| { let theme = cx.global::().theme.clone(); Self::render_entry_visual_element( &details, diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index 3586ff7726..6a5c677d8f 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -48,7 +48,7 @@ impl View for ProjectSymbolsView { "ProjectSymbolsView" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } @@ -238,7 +238,7 @@ impl PickerDelegate for ProjectSymbolsView { mouse_state: &mut MouseState, selected: bool, cx: &AppContext, - ) -> ElementBox { + ) -> ElementBox> { let string_match = &self.matches[ix]; let settings = cx.global::(); let style = &settings.theme.picker.item; diff --git a/crates/recent_projects/src/highlighted_workspace_location.rs b/crates/recent_projects/src/highlighted_workspace_location.rs index a71a7dd2d7..6a7064e35b 100644 --- a/crates/recent_projects/src/highlighted_workspace_location.rs +++ b/crates/recent_projects/src/highlighted_workspace_location.rs @@ -3,7 +3,7 @@ use std::path::Path; use fuzzy::StringMatch; use gpui::{ elements::{Label, LabelStyle}, - Element, ElementBox, + Element, ElementBox, View, }; use workspace::WorkspaceLocation; @@ -42,7 +42,7 @@ impl HighlightedText { } } - pub fn render(self, style: impl Into) -> ElementBox { + pub fn render(self, style: impl Into) -> ElementBox { Label::new(self.text, style) .with_highlights(self.highlight_positions) .boxed() diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index ed45b778dd..6e75babae5 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -101,7 +101,7 @@ impl View for RecentProjectsView { "RecentProjectsView" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } @@ -183,7 +183,7 @@ impl PickerDelegate for RecentProjectsView { mouse_state: &mut gpui::MouseState, selected: bool, cx: &gpui::AppContext, - ) -> ElementBox { + ) -> ElementBox> { let settings = cx.global::(); let string_match = &self.matches[ix]; let style = settings.theme.picker.item.style_for(mouse_state, selected); diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index 6506536842..3ce926409b 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -410,7 +410,7 @@ impl TerminalElement { ), ) // Update drag selections - .on_drag(MouseButton::Left, move |event, _, cx| { + .on_drag(MouseButton::Left, move |event, _: &mut TerminalView, cx| { if cx.is_parent_view_focused() { if let Some(conn_handle) = connection.upgrade(cx) { conn_handle.update(cx, |terminal, cx| { @@ -432,7 +432,7 @@ impl TerminalElement { ), ) // Context menu - .on_click(MouseButton::Right, move |e, _, cx| { + .on_click(MouseButton::Right, move |e, _: &mut TerminalView, cx| { let mouse_mode = if let Some(conn_handle) = connection.upgrade(cx) { conn_handle.update(cx, |terminal, _cx| terminal.mouse_mode(e.shift)) } else { @@ -445,7 +445,7 @@ impl TerminalElement { }); } }) - .on_move(move |event, _, cx| { + .on_move(move |event, _: &mut TerminalView, cx| { if cx.is_parent_view_focused() { if let Some(conn_handle) = connection.upgrade(cx) { conn_handle.update(cx, |terminal, cx| { @@ -455,7 +455,7 @@ impl TerminalElement { } } }) - .on_scroll(move |event, _, cx| { + .on_scroll(move |event, _: &mut TerminalView, cx| { if let Some(conn_handle) = connection.upgrade(cx) { conn_handle.update(cx, |terminal, cx| { terminal.scroll_wheel(event, origin); @@ -598,27 +598,25 @@ impl Element for TerminalElement { }); let view_handle = self.view.clone(); - let hyperlink_tooltip = last_hovered_hyperlink.and_then(|(uri, _, id)| { - // last_mouse.and_then(|_last_mouse| { - view_handle.upgrade(cx).map(|handle| { - let mut tooltip = cx.render(&handle, |_, cx| { - Overlay::new( - Empty::new() - .contained() - .constrained() - .with_width(dimensions.width()) - .with_height(dimensions.height()) - .with_tooltip::(id, uri, None, tooltip_style, cx) - .boxed(), - ) - .with_position_mode(gpui::elements::OverlayPositionMode::Local) - .boxed() - }); + let hyperlink_tooltip = last_hovered_hyperlink.map(|(uri, _, id)| { + let mut tooltip = Overlay::new( + Empty::new() + .contained() + .constrained() + .with_width(dimensions.width()) + .with_height(dimensions.height()) + .with_tooltip::(id, uri, None, tooltip_style, cx) + .boxed(), + ) + .with_position_mode(gpui::elements::OverlayPositionMode::Local) + .boxed(); - tooltip.layout(SizeConstraint::new(Vector2F::zero(), cx.window_size), cx); - tooltip - }) - // }) + tooltip.layout( + SizeConstraint::new(Vector2F::zero(), cx.window_size()), + view, + cx, + ); + tooltip }); let TerminalContent { @@ -647,7 +645,7 @@ impl Element for TerminalElement { cells, &text_style, &terminal_theme, - cx.text_layout_cache, + cx.text_layout_cache(), cx.font_cache(), last_hovered_hyperlink .as_ref() @@ -669,7 +667,7 @@ impl Element for TerminalElement { terminal_theme.foreground }; - cx.text_layout_cache.layout_str( + cx.text_layout_cache().layout_str( &str_trxt, text_style.font_size, &[( @@ -744,11 +742,11 @@ impl Element for TerminalElement { // Elements are ephemeral, only at paint time do we know what could be clicked by a mouse self.attach_mouse_handlers( + scene, origin, self.view.id(), visible_bounds, layout.mode, - view, cx, ); diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 6a68bfc7dd..5be91c9351 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -396,7 +396,7 @@ impl View for TerminalView { Stack::new() .with_child( TerminalElement::new( - cx.handle(), + cx.handle().downgrade(), terminal_handle, focused, self.should_show_cursor(focused, cx), diff --git a/crates/theme/src/ui.rs b/crates/theme/src/ui.rs index 093b990d7b..c1b420d5ac 100644 --- a/crates/theme/src/ui.rs +++ b/crates/theme/src/ui.rs @@ -175,7 +175,7 @@ pub fn keystroke_label_for( pub type ButtonStyle = Interactive; -pub fn cta_button( +pub fn cta_button( label: L, action: A, max_width: f32, @@ -183,12 +183,11 @@ pub fn cta_button( cx: &mut ViewContext, ) -> ElementBox where - Tag: 'static, L: Into>, A: 'static + Action + Clone, V: View, { - cta_button_with_click::(label, max_width, style, cx, move |_, _, cx| { + cta_button_with_click::(label, max_width, style, cx, move |_, _, cx| { cx.dispatch_action(action.clone()) }) .boxed() diff --git a/crates/vim/src/normal.rs b/crates/vim/src/normal.rs index ad55c87576..3147fb6cf9 100644 --- a/crates/vim/src/normal.rs +++ b/crates/vim/src/normal.rs @@ -251,7 +251,7 @@ fn paste(_: &mut Workspace, _: &Paste, cx: &mut ViewContext) { vim.update_active_editor(cx, |editor, cx| { editor.transact(cx, |editor, cx| { editor.set_clip_at_line_ends(false, cx); - if let Some(item) = cx.as_mut().read_from_clipboard() { + if let Some(item) = cx.read_from_clipboard() { let mut clipboard_text = Cow::Borrowed(item.text()); if let Some(mut clipboard_selections) = item.metadata::>() diff --git a/crates/vim/src/visual.rs b/crates/vim/src/visual.rs index cd4f956df1..1e8d02e063 100644 --- a/crates/vim/src/visual.rs +++ b/crates/vim/src/visual.rs @@ -209,7 +209,7 @@ pub fn paste(_: &mut Workspace, _: &VisualPaste, cx: &mut ViewContext Vim::update(cx, |vim, cx| { vim.update_active_editor(cx, |editor, cx| { editor.transact(cx, |editor, cx| { - if let Some(item) = cx.as_mut().read_from_clipboard() { + if let Some(item) = cx.read_from_clipboard() { copy_selections_content(editor, editor.selections.line_mode, cx); let mut clipboard_text = Cow::Borrowed(item.text()); if let Some(mut clipboard_selections) = diff --git a/crates/welcome/src/base_keymap_picker.rs b/crates/welcome/src/base_keymap_picker.rs index be516ed038..9ce36c49be 100644 --- a/crates/welcome/src/base_keymap_picker.rs +++ b/crates/welcome/src/base_keymap_picker.rs @@ -161,7 +161,7 @@ impl PickerDelegate for BaseKeymapSelector { mouse_state: &mut gpui::MouseState, selected: bool, cx: &gpui::AppContext, - ) -> gpui::ElementBox { + ) -> gpui::ElementBox> { let theme = &cx.global::().theme; let keymap_match = &self.matches[ix]; let style = theme.picker.item.style_for(mouse_state, selected); diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 3505884fb2..fc726db912 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -10,7 +10,7 @@ use gpui::{ use settings::{settings_file::SettingsFile, Settings}; use workspace::{ - item::Item, open_new, sidebar::SidebarSide, AppState, PaneBackdrop, Welcome, Workspace, + item::Item, open_new, sidebar::SidebarSide, AppState, Pane, PaneBackdrop, Welcome, Workspace, WorkspaceId, }; @@ -55,7 +55,7 @@ impl View for WelcomePage { "WelcomePage" } - fn render(&mut self, cx: &mut gpui::ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut gpui::ViewContext) -> ElementBox { let self_handle = cx.handle(); let settings = cx.global::(); let theme = settings.theme.clone(); @@ -203,7 +203,7 @@ impl Item for WelcomePage { _detail: Option, style: &theme::Tab, _cx: &gpui::AppContext, - ) -> gpui::ElementBox { + ) -> ElementBox { Flex::row() .with_child( Label::new("Welcome to Zed!", style.label.clone()) diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 9f67991f5e..2b12316a25 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1851,13 +1851,13 @@ impl NavHistory { } } -pub struct PaneBackdrop { +pub struct PaneBackdrop { child_view: usize, - child: ElementBox, + child: ElementBox, } -impl PaneBackdrop { - pub fn new(pane_item_view: usize, child: ElementBox) -> Self { +impl PaneBackdrop { + pub fn new(pane_item_view: usize, child: ElementBox) -> Self { PaneBackdrop { child, child_view: pane_item_view, @@ -1865,7 +1865,7 @@ impl PaneBackdrop { } } -impl Element for PaneBackdrop { +impl Element for PaneBackdrop { type LayoutState = (); type PaintState = (); @@ -1873,8 +1873,8 @@ impl Element for PaneBackdrop { fn layout( &mut self, constraint: gpui::SizeConstraint, - view: &mut Pane, - cx: &mut ViewContext, + view: &mut V, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { let size = self.child.layout(constraint, view, cx); (size, ()) @@ -1886,8 +1886,8 @@ impl Element for PaneBackdrop { bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, - view: &mut Pane, - cx: &mut ViewContext, + view: &mut V, + cx: &mut ViewContext, ) -> Self::PaintState { let background = cx.global::().theme.editor.background; @@ -1903,7 +1903,7 @@ impl Element for PaneBackdrop { scene.push_mouse_region( MouseRegion::new::(child_view_id, 0, visible_bounds).on_down( gpui::platform::MouseButton::Left, - move |_, _: &mut Pane, cx| { + move |_, _: &mut V, cx| { let window_id = cx.window_id(); cx.app_context().focus(window_id, Some(child_view_id)) }, @@ -1923,8 +1923,8 @@ impl Element for PaneBackdrop { _visible_bounds: RectF, _layout: &Self::LayoutState, _paint: &Self::PaintState, - view: &Pane, - cx: &gpui::ViewContext, + view: &V, + cx: &gpui::ViewContext, ) -> Option { self.child.rect_for_text_range(range_utf16, view, cx) } @@ -1934,8 +1934,8 @@ impl Element for PaneBackdrop { _bounds: RectF, _layout: &Self::LayoutState, _paint: &Self::PaintState, - view: &Pane, - cx: &gpui::ViewContext, + view: &V, + cx: &gpui::ViewContext, ) -> serde_json::Value { gpui::json::json!({ "type": "Pane Back Drop", From 40896352ff526fdd1e9a9e18cb9967b698ae6af7 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 12 Apr 2023 10:28:53 -0600 Subject: [PATCH 12/58] wip --- crates/breadcrumbs/src/breadcrumbs.rs | 6 +- crates/collab/src/tests/integration_tests.rs | 5 +- crates/collab_ui/src/collab_titlebar_item.rs | 132 ++++++++++-------- .../src/collaborator_list_popover.rs | 33 ++--- crates/collab_ui/src/contact_finder.rs | 4 +- crates/collab_ui/src/contact_list.rs | 66 ++++----- crates/collab_ui/src/contact_notification.rs | 2 +- crates/collab_ui/src/contacts_popover.rs | 6 +- crates/collab_ui/src/face_pile.rs | 27 ++-- .../src/incoming_call_notification.rs | 16 +-- crates/collab_ui/src/notifications.rs | 10 +- .../src/project_shared_notification.rs | 14 +- .../collab_ui/src/sharing_status_indicator.rs | 8 +- crates/gpui/src/app/window.rs | 4 + 14 files changed, 176 insertions(+), 157 deletions(-) diff --git a/crates/breadcrumbs/src/breadcrumbs.rs b/crates/breadcrumbs/src/breadcrumbs.rs index e53261d7a0..9ba0e1ac30 100644 --- a/crates/breadcrumbs/src/breadcrumbs.rs +++ b/crates/breadcrumbs/src/breadcrumbs.rs @@ -72,14 +72,14 @@ impl View for Breadcrumbs { .boxed(); } - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = style.style_for(state, false); crumbs.with_style(style.container).boxed() }) - .on_click(MouseButton::Left, |_, cx| { + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(outline::Toggle); }) - .with_tooltip::( + .with_tooltip::( 0, "Show symbol outline".to_owned(), Some(Box::new(outline::Toggle)), diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 1bf2604b12..f3fcd498cc 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -1467,7 +1467,8 @@ async fn test_host_disconnect( deterministic.run_until_parked(); assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared())); - let (_, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx)); + let (window_id_b, workspace_b) = + cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx)); let editor_b = workspace_b .update(cx_b, |workspace, cx| { workspace.open_path((worktree_id, "b.txt"), None, true, cx) @@ -1490,7 +1491,7 @@ async fn test_host_disconnect( assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared())); // Ensure client B's edited state is reset and that the whole window is blurred. - cx_b.read_window(|cx| { + cx_b.read_window(window_id_b, |cx| { assert_eq!(cx.focused_view_id(), None); }); assert!(!cx_b.is_window_edited(workspace_b.window_id())); diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 537c77a7e4..1a88dbe150 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -16,8 +16,8 @@ use gpui::{ impl_internal_actions, json::{self, ToJson}, platform::{CursorStyle, MouseButton}, - AppContext, Entity, ImageData, ModelHandle, Subscription, View, ViewContext, ViewHandle, - WeakViewHandle, + AppContext, Entity, ImageData, ModelHandle, SceneBuilder, Subscription, View, ViewContext, + ViewHandle, WeakViewHandle, }; use settings::Settings; use std::{ops::Range, sync::Arc}; @@ -68,7 +68,7 @@ impl View for CollabTitlebarItem { "CollabTitlebarItem" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let workspace = if let Some(workspace) = self.workspace.upgrade(cx) { workspace } else { @@ -326,7 +326,7 @@ impl CollabTitlebarItem { &self, theme: &Theme, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { let titlebar = &theme.workspace.titlebar; let badge = if self @@ -352,7 +352,7 @@ impl CollabTitlebarItem { Stack::new() .with_child( - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = titlebar .toggle_contacts_button .style_for(state, self.contacts_popover.is_some()); @@ -369,10 +369,10 @@ impl CollabTitlebarItem { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(ToggleContactsMenu); }) - .with_tooltip::( + .with_tooltip::( 0, "Show contacts menu".into(), Some(Box::new(ToggleContactsMenu)), @@ -391,7 +391,7 @@ impl CollabTitlebarItem { theme: &Theme, room: &ModelHandle, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { let icon; let tooltip; if room.read(cx).is_screen_sharing() { @@ -403,7 +403,7 @@ impl CollabTitlebarItem { } let titlebar = &theme.workspace.titlebar; - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = titlebar.call_control.style_for(state, false); Svg::new(icon) .with_color(style.color) @@ -418,10 +418,10 @@ impl CollabTitlebarItem { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(ToggleScreenSharing); }) - .with_tooltip::( + .with_tooltip::( 0, tooltip.into(), Some(Box::new(ToggleScreenSharing)), @@ -437,7 +437,7 @@ impl CollabTitlebarItem { workspace: &ViewHandle, theme: &Theme, cx: &mut ViewContext, - ) -> Option { + ) -> Option> { let project = workspace.read(cx).project(); if project.read(cx).is_remote() { return None; @@ -457,7 +457,7 @@ impl CollabTitlebarItem { Some( Stack::new() .with_child( - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { //TODO: Ensure this button has consistant width for both text variations let style = titlebar .share_button @@ -468,14 +468,14 @@ impl CollabTitlebarItem { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { if is_shared { cx.dispatch_action(UnshareProject); } else { cx.dispatch_action(ShareProject); } }) - .with_tooltip::( + .with_tooltip::( 0, tooltip.to_owned(), None, @@ -491,12 +491,16 @@ impl CollabTitlebarItem { ) } - fn render_user_menu_button(&self, theme: &Theme, cx: &mut ViewContext) -> ElementBox { + fn render_user_menu_button( + &self, + theme: &Theme, + cx: &mut ViewContext, + ) -> ElementBox { let titlebar = &theme.workspace.titlebar; Stack::new() .with_child( - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = titlebar.call_control.style_for(state, false); Svg::new("icons/ellipsis_14.svg") .with_color(style.color) @@ -511,10 +515,10 @@ impl CollabTitlebarItem { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(ToggleUserMenu); }) - .with_tooltip::( + .with_tooltip::( 0, "Toggle user menu".to_owned(), Some(Box::new(ToggleUserMenu)), @@ -535,9 +539,9 @@ impl CollabTitlebarItem { .boxed() } - fn render_sign_in_button(&self, theme: &Theme, cx: &mut ViewContext) -> ElementBox { + fn render_sign_in_button(&self, theme: &Theme, cx: &mut ViewContext) -> ElementBox { let titlebar = &theme.workspace.titlebar; - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = titlebar.sign_in_prompt.style_for(state, false); Label::new("Sign In", style.text.clone()) .contained() @@ -545,7 +549,7 @@ impl CollabTitlebarItem { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(SignIn); }) .boxed() @@ -555,7 +559,7 @@ impl CollabTitlebarItem { &'a self, _theme: &'a theme::Titlebar, cx: &'a ViewContext, - ) -> Option { + ) -> Option> { self.contacts_popover.as_ref().map(|popover| { Overlay::new(ChildView::new(popover, cx).boxed()) .with_fit_mode(OverlayFitMode::SwitchAnchor) @@ -574,7 +578,7 @@ impl CollabTitlebarItem { theme: &Theme, room: &ModelHandle, cx: &mut ViewContext, - ) -> Vec { + ) -> Vec> { let mut participants = room .read(cx) .remote_participants() @@ -616,7 +620,7 @@ impl CollabTitlebarItem { user: &Arc, peer_id: PeerId, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { let replica_id = workspace.read(cx).project().read(cx).replica_id(); Container::new(self.render_face_pile( user, @@ -640,7 +644,7 @@ impl CollabTitlebarItem { workspace: &ViewHandle, theme: &Theme, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { let project_id = workspace.read(cx).project().read(cx).remote_id(); let room = ActiveCall::global(cx).read(cx).room(); let is_being_followed = workspace.read(cx).is_being_followed(peer_id); @@ -753,41 +757,42 @@ impl CollabTitlebarItem { if let Some(location) = location { if let Some(replica_id) = replica_id { - content = - MouseEventHandler::::new(replica_id.into(), cx, move |_, _| { - content - }) - .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { - cx.dispatch_action(ToggleFollow(peer_id)) - }) - .with_tooltip::( - peer_id.as_u64() as usize, - if is_being_followed { - format!("Unfollow {}", user.github_login) - } else { - format!("Follow {}", user.github_login) - }, - Some(Box::new(FollowNextCollaborator)), - theme.tooltip.clone(), - cx, - ) - .boxed(); + content = MouseEventHandler::::new( + replica_id.into(), + cx, + move |_, _| content, + ) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, move |_, _, cx| { + cx.dispatch_action(ToggleFollow(peer_id)) + }) + .with_tooltip::( + peer_id.as_u64() as usize, + if is_being_followed { + format!("Unfollow {}", user.github_login) + } else { + format!("Follow {}", user.github_login) + }, + Some(Box::new(FollowNextCollaborator)), + theme.tooltip.clone(), + cx, + ) + .boxed(); } else if let ParticipantLocation::SharedProject { project_id } = location { let user_id = user.id; - content = MouseEventHandler::::new( + content = MouseEventHandler::::new( peer_id.as_u64() as usize, cx, move |_, _| content, ) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(JoinProject { project_id, follow_user_id: user_id, }) }) - .with_tooltip::( + .with_tooltip::( peer_id.as_u64() as usize, format!("Follow {} into external project", user.github_login), Some(Box::new(FollowNextCollaborator)), @@ -823,7 +828,7 @@ impl CollabTitlebarItem { avatar: Arc, avatar_style: AvatarStyle, background_color: Color, - ) -> ElementBox { + ) -> ElementBox { Image::from_data(avatar) .with_style(avatar_style.image) .aligned() @@ -841,7 +846,7 @@ impl CollabTitlebarItem { &self, status: &client::Status, cx: &mut ViewContext, - ) -> Option { + ) -> Option> { enum ConnectionStatusButton {} let theme = &cx.global::().theme.clone(); @@ -867,7 +872,7 @@ impl CollabTitlebarItem { .boxed(), ), client::Status::UpgradeRequired => Some( - MouseEventHandler::::new(0, cx, |_, _| { + MouseEventHandler::::new(0, cx, |_, _| { Label::new( "Please update Zed to collaborate", theme.workspace.titlebar.outdated_warning.text.clone(), @@ -878,7 +883,7 @@ impl CollabTitlebarItem { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, cx| { + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(auto_update::Check); }) .boxed(), @@ -898,7 +903,7 @@ impl AvatarRibbon { } } -impl Element for AvatarRibbon { +impl Element for AvatarRibbon { type LayoutState = (); type PaintState = (); @@ -906,17 +911,20 @@ impl Element for AvatarRibbon { fn layout( &mut self, constraint: gpui::SizeConstraint, - _: &mut gpui::LayoutContext, + _: &mut CollabTitlebarItem, + _: &mut ViewContext, ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { (constraint.max, ()) } fn paint( &mut self, - bounds: gpui::geometry::rect::RectF, - _: gpui::geometry::rect::RectF, + scene: &mut SceneBuilder, + bounds: RectF, + _: RectF, _: &mut Self::LayoutState, - cx: &mut gpui::PaintContext, + _: &mut CollabTitlebarItem, + _: &mut ViewContext, ) -> Self::PaintState { let mut path = PathBuilder::new(); path.reset(bounds.lower_left()); @@ -937,17 +945,19 @@ impl Element for AvatarRibbon { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &gpui::MeasurementContext, + _: &CollabTitlebarItem, + _: &ViewContext, ) -> Option { None } fn debug( &self, - bounds: gpui::geometry::rect::RectF, + bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &gpui::DebugContext, + _: &CollabTitlebarItem, + _: &ViewContext, ) -> gpui::json::Value { json::json!({ "type": "AvatarRibbon", diff --git a/crates/collab_ui/src/collaborator_list_popover.rs b/crates/collab_ui/src/collaborator_list_popover.rs index 9fad335874..654f45d3e7 100644 --- a/crates/collab_ui/src/collaborator_list_popover.rs +++ b/crates/collab_ui/src/collaborator_list_popover.rs @@ -30,10 +30,10 @@ impl View for CollaboratorListPopover { "CollaboratorListPopover" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); - MouseEventHandler::::new(0, cx, |_, _| { + MouseEventHandler::::new(0, cx, |_, _| { List::new(self.list_state.clone()) .contained() .with_style(theme.contacts_popover.container) //TODO: Change the name of this theme key @@ -42,7 +42,7 @@ impl View for CollaboratorListPopover { .with_height(theme.contacts_popover.height) .boxed() }) - .on_down_out(MouseButton::Left, move |_, cx| { + .on_down_out(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(ToggleCollaboratorList); }) .boxed() @@ -117,7 +117,7 @@ fn render_collaborator_list_entry( icon_action: IA, icon_tooltip: String, cx: &mut ViewContext, -) -> ElementBox { +) -> ElementBox { enum Username {} enum UsernameTooltip {} enum Icon {} @@ -127,19 +127,20 @@ fn render_collaborator_list_entry( let username_theme = theme.contact_list.contact_username.text.clone(); let tooltip_theme = theme.tooltip.clone(); - let username = MouseEventHandler::::new(index, cx, |_, _| { - Label::new(username.to_owned(), username_theme.clone()).boxed() - }) - .on_click(MouseButton::Left, move |_, cx| { - if let Some(username_action) = username_action.clone() { - cx.dispatch_action(username_action); - } - }); + let username = + MouseEventHandler::::new(index, cx, |_, _| { + Label::new(username.to_owned(), username_theme.clone()).boxed() + }) + .on_click(MouseButton::Left, move |_, _, cx| { + if let Some(username_action) = username_action.clone() { + cx.dispatch_action(username_action); + } + }); Flex::row() .with_child(if let Some(username_tooltip) = username_tooltip { username - .with_tooltip::( + .with_tooltip::( index, username_tooltip, None, @@ -151,11 +152,11 @@ fn render_collaborator_list_entry( username.boxed() }) .with_child( - MouseEventHandler::::new(index, cx, |_, _| icon.boxed()) - .on_click(MouseButton::Left, move |_, cx| { + MouseEventHandler::::new(index, cx, |_, _| icon.boxed()) + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(icon_action.clone()) }) - .with_tooltip::(index, icon_tooltip, None, tooltip_theme, cx) + .with_tooltip::(index, icon_tooltip, None, tooltip_theme, cx) .boxed(), ) .boxed() diff --git a/crates/collab_ui/src/contact_finder.rs b/crates/collab_ui/src/contact_finder.rs index 5d0f315400..ac87280af8 100644 --- a/crates/collab_ui/src/contact_finder.rs +++ b/crates/collab_ui/src/contact_finder.rs @@ -32,7 +32,7 @@ impl View for ContactFinder { "ContactFinder" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { ChildView::new(&self.picker, cx).boxed() } @@ -104,7 +104,7 @@ impl PickerDelegate for ContactFinder { mouse_state: &mut MouseState, selected: bool, cx: &gpui::AppContext, - ) -> ElementBox { + ) -> ElementBox> { let theme = &cx.global::().theme; let user = &self.potential_contacts[ix]; let request_status = self.user_store.read(cx).contact_request_status(user); diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index 979dea717a..cb4fc6371a 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -159,7 +159,7 @@ pub enum Event { pub struct ContactList { entries: Vec, match_candidates: Vec, - list_state: ListState, + list_state: ListState, project: ModelHandle, user_store: ModelHandle, filter_editor: ViewHandle, @@ -202,7 +202,7 @@ impl ContactList { }) .detach(); - let list_state = ListState::new(0, Orientation::Top, 1000., move |this, ix, cx| { + let list_state = ListState::::new(0, Orientation::Top, 1000., move |this, ix, cx| { let theme = cx.global::().theme.clone(); let is_selected = this.selection == Some(ix); let current_project_id = this.project.read(cx).remote_id(); @@ -748,7 +748,7 @@ impl ContactList { is_pending: bool, is_selected: bool, theme: &theme::ContactList, - ) -> ElementBox { + ) -> ElementBox { Flex::row() .with_children(user.avatar.clone().map(|avatar| { Image::from_data(avatar) @@ -800,7 +800,7 @@ impl ContactList { is_selected: bool, theme: &theme::ContactList, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { let font_cache = cx.font_cache(); let host_avatar_height = theme .contact_avatar @@ -819,7 +819,7 @@ impl ContactList { worktree_root_names.join(", ") }; - MouseEventHandler::::new(project_id as usize, cx, |mouse_state, _| { + MouseEventHandler::::new(project_id as usize, cx, |mouse_state, _| { let tree_branch = *tree_branch.style_for(mouse_state, is_selected); let row = theme.project_row.style_for(mouse_state, is_selected); @@ -827,7 +827,7 @@ impl ContactList { .with_child( Stack::new() .with_child( - Canvas::new(move |bounds, _, cx| { + Canvas::new(move |scene, bounds, _, _, cx| { let start_x = bounds.min_x() + (bounds.width() / 2.) - (tree_branch.width / 2.); let end_x = bounds.max_x(); @@ -882,7 +882,7 @@ impl ContactList { } else { CursorStyle::Arrow }) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { if !is_current { cx.dispatch_global_action(JoinProject { project_id, @@ -899,7 +899,7 @@ impl ContactList { is_selected: bool, theme: &theme::ContactList, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { let font_cache = cx.font_cache(); let host_avatar_height = theme .contact_avatar @@ -913,7 +913,7 @@ impl ContactList { let baseline_offset = row.name.text.baseline_offset(font_cache) + (theme.row_height - line_height) / 2.; - MouseEventHandler::::new( + MouseEventHandler::::new( peer_id.as_u64() as usize, cx, |mouse_state, _| { @@ -924,7 +924,7 @@ impl ContactList { .with_child( Stack::new() .with_child( - Canvas::new(move |bounds, _, cx| { + Canvas::new(move |scene, bounds, _, _, cx| { let start_x = bounds.min_x() + (bounds.width() / 2.) - (tree_branch.width / 2.); let end_x = bounds.max_x(); @@ -988,7 +988,7 @@ impl ContactList { }, ) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(OpenSharedScreen { peer_id }); }) .boxed() @@ -1000,7 +1000,7 @@ impl ContactList { is_selected: bool, is_collapsed: bool, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { enum Header {} enum LeaveCallContactList {} @@ -1015,14 +1015,14 @@ impl ContactList { }; let leave_call = if section == Section::ActiveCall { Some( - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = theme.leave_call.style_for(state, false); Label::new("Leave Call", style.text.clone()) .contained() .with_style(style.container) .boxed() }) - .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(LeaveCall)) + .on_click(MouseButton::Left, |_, _, cx| cx.dispatch_action(LeaveCall)) .aligned() .boxed(), ) @@ -1031,7 +1031,7 @@ impl ContactList { }; let icon_size = theme.section_icon_size; - MouseEventHandler::
::new(section as usize, cx, |_, _| { + MouseEventHandler::::new(section as usize, cx, |_, _| { Flex::row() .with_child( Svg::new(if is_collapsed { @@ -1065,7 +1065,7 @@ impl ContactList { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(ToggleExpanded(section)) }) .boxed() @@ -1078,14 +1078,14 @@ impl ContactList { theme: &theme::ContactList, is_selected: bool, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { let online = contact.online; let busy = contact.busy || calling; let user_id = contact.user.id; let github_login = contact.user.github_login.clone(); let initial_project = project.clone(); let mut element = - MouseEventHandler::::new(contact.user.id as usize, cx, |_, cx| { + MouseEventHandler::::new(contact.user.id as usize, cx, |_, cx| { Flex::row() .with_children(contact.user.avatar.clone().map(|avatar| { let status_badge = if contact.online { @@ -1128,7 +1128,7 @@ impl ContactList { .boxed(), ) .with_child( - MouseEventHandler::::new( + MouseEventHandler::::new( contact.user.id as usize, cx, |mouse_state, _| { @@ -1142,7 +1142,7 @@ impl ContactList { ) .with_padding(Padding::uniform(2.)) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(RemoveContact { user_id, github_login: github_login.clone(), @@ -1172,7 +1172,7 @@ impl ContactList { ) .boxed() }) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { if online && !busy { cx.dispatch_action(Call { recipient_user_id: user_id, @@ -1195,7 +1195,7 @@ impl ContactList { is_incoming: bool, is_selected: bool, cx: &mut ViewContext, - ) -> ElementBox { + ) -> ElementBox { enum Decline {} enum Accept {} enum Cancel {} @@ -1228,7 +1228,7 @@ impl ContactList { if is_incoming { row.add_children([ - MouseEventHandler::::new(user.id as usize, cx, |mouse_state, _| { + MouseEventHandler::::new(user.id as usize, cx, |mouse_state, _| { let button_style = if is_contact_request_pending { &theme.disabled_button } else { @@ -1239,7 +1239,7 @@ impl ContactList { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(RespondToContactRequest { user_id, accept: false, @@ -1248,7 +1248,7 @@ impl ContactList { .contained() .with_margin_right(button_spacing) .boxed(), - MouseEventHandler::::new(user.id as usize, cx, |mouse_state, _| { + MouseEventHandler::::new(user.id as usize, cx, |mouse_state, _| { let button_style = if is_contact_request_pending { &theme.disabled_button } else { @@ -1260,7 +1260,7 @@ impl ContactList { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(RespondToContactRequest { user_id, accept: true, @@ -1270,7 +1270,7 @@ impl ContactList { ]); } else { row.add_child( - MouseEventHandler::::new(user.id as usize, cx, |mouse_state, _| { + MouseEventHandler::::new(user.id as usize, cx, |mouse_state, _| { let button_style = if is_contact_request_pending { &theme.disabled_button } else { @@ -1283,7 +1283,7 @@ impl ContactList { }) .with_padding(Padding::uniform(2.)) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(RemoveContact { user_id, github_login: github_login.clone(), @@ -1331,7 +1331,7 @@ impl View for ContactList { cx } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { enum AddContact {} let theme = cx.global::().theme.clone(); @@ -1346,7 +1346,7 @@ impl View for ContactList { .boxed(), ) .with_child( - MouseEventHandler::::new(0, cx, |_, _| { + MouseEventHandler::::new(0, cx, |_, _| { render_icon_button( &theme.contact_list.add_contact_button, "icons/user_plus_16.svg", @@ -1354,10 +1354,10 @@ impl View for ContactList { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, cx| { + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(contacts_popover::ToggleContactFinder) }) - .with_tooltip::( + .with_tooltip::( 0, "Search for new contact".into(), None, @@ -1387,7 +1387,7 @@ impl View for ContactList { } } -fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Element { +fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Element { Svg::new(svg_path) .with_color(style.color) .constrained() diff --git a/crates/collab_ui/src/contact_notification.rs b/crates/collab_ui/src/contact_notification.rs index c504a5771b..c386336627 100644 --- a/crates/collab_ui/src/contact_notification.rs +++ b/crates/collab_ui/src/contact_notification.rs @@ -42,7 +42,7 @@ impl View for ContactNotification { "ContactNotification" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { match self.kind { ContactEventKind::Requested => render_user_notification( self.user.clone(), diff --git a/crates/collab_ui/src/contacts_popover.rs b/crates/collab_ui/src/contacts_popover.rs index ee900c285c..20c57cd41b 100644 --- a/crates/collab_ui/src/contacts_popover.rs +++ b/crates/collab_ui/src/contacts_popover.rs @@ -91,14 +91,14 @@ impl View for ContactsPopover { "ContactsPopover" } - fn render(&mut self, cx: &mut ViewContext) -> ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let theme = cx.global::().theme.clone(); let child = match &self.child { Child::ContactList(child) => ChildView::new(child, cx), Child::ContactFinder(child) => ChildView::new(child, cx), }; - MouseEventHandler::::new(0, cx, |_, _| { + MouseEventHandler::::new(0, cx, |_, _| { Flex::column() .with_child(child.flex(1., true).boxed()) .contained() @@ -108,7 +108,7 @@ impl View for ContactsPopover { .with_height(theme.contacts_popover.height) .boxed() }) - .on_down_out(MouseButton::Left, move |_, cx| { + .on_down_out(MouseButton::Left, move |_, _, cx| { cx.dispatch_action(ToggleContactsMenu); }) .boxed() diff --git a/crates/collab_ui/src/face_pile.rs b/crates/collab_ui/src/face_pile.rs index f813cd34a9..325a755be8 100644 --- a/crates/collab_ui/src/face_pile.rs +++ b/crates/collab_ui/src/face_pile.rs @@ -7,13 +7,14 @@ use gpui::{ }, json::ToJson, serde_json::{self, json}, - Axis, DebugContext, Element, ElementBox, MeasurementContext, PaintContext, SceneBuilder, - ViewContext, + Axis, Element, ElementBox, SceneBuilder, ViewContext, }; +use crate::CollabTitlebarItem; + pub(crate) struct FacePile { overlap: f32, - faces: Vec, + faces: Vec>, } impl FacePile { @@ -25,15 +26,15 @@ impl FacePile { } } -impl Element for FacePile { +impl Element for FacePile { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: gpui::SizeConstraint, - view: &mut Self, - cx: &mut ViewContext, + view: &mut CollabTitlebarItem, + cx: &mut ViewContext, ) -> (Vector2F, Self::LayoutState) { debug_assert!(constraint.max_along(Axis::Horizontal) == f32::INFINITY); @@ -52,8 +53,8 @@ impl Element for FacePile { bounds: RectF, visible_bounds: RectF, _layout: &mut Self::LayoutState, - view: &mut Self, - cx: &mut ViewContext, + view: &mut CollabTitlebarItem, + cx: &mut ViewContext, ) -> Self::PaintState { let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); @@ -79,7 +80,8 @@ impl Element for FacePile { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &MeasurementContext, + _: &CollabTitlebarItem, + _: &ViewContext, ) -> Option { None } @@ -89,7 +91,8 @@ impl Element for FacePile { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - _: &DebugContext, + _: &CollabTitlebarItem, + _: &ViewContext, ) -> serde_json::Value { json!({ "type": "FacePile", @@ -98,8 +101,8 @@ impl Element for FacePile { } } -impl Extend> for FacePile { - fn extend>>(&mut self, children: T) { +impl Extend> for FacePile { + fn extend>>(&mut self, children: T) { self.faces.extend(children); } } diff --git a/crates/collab_ui/src/incoming_call_notification.rs b/crates/collab_ui/src/incoming_call_notification.rs index ed60959413..5a001b217a 100644 --- a/crates/collab_ui/src/incoming_call_notification.rs +++ b/crates/collab_ui/src/incoming_call_notification.rs @@ -6,7 +6,7 @@ use gpui::{ geometry::{rect::RectF, vector::vec2f}, impl_internal_actions, platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions}, - AppContext, Entity, View, ViewContext, + AppContext, ElementBox, Entity, View, ViewContext, }; use settings::Settings; use util::ResultExt; @@ -99,7 +99,7 @@ impl IncomingCallNotification { } } - fn render_caller(&self, cx: &mut ViewContext) -> ElementBox { + fn render_caller(&self, cx: &mut ViewContext) -> ElementBox { let theme = &cx.global::().theme.incoming_call_notification; let default_project = proto::ParticipantProject::default(); let initial_project = self @@ -165,13 +165,13 @@ impl IncomingCallNotification { .boxed() } - fn render_buttons(&self, cx: &mut ViewContext) -> ElementBox { + fn render_buttons(&self, cx: &mut ViewContext) -> ElementBox { enum Accept {} enum Decline {} Flex::column() .with_child( - MouseEventHandler::::new(0, cx, |_, cx| { + MouseEventHandler::::new(0, cx, |_, cx| { let theme = &cx.global::().theme.incoming_call_notification; Label::new("Accept", theme.accept_button.text.clone()) .aligned() @@ -180,14 +180,14 @@ impl IncomingCallNotification { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, cx| { + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(RespondToCall { accept: true }); }) .flex(1., true) .boxed(), ) .with_child( - MouseEventHandler::::new(0, cx, |_, cx| { + MouseEventHandler::::new(0, cx, |_, cx| { let theme = &cx.global::().theme.incoming_call_notification; Label::new("Decline", theme.decline_button.text.clone()) .aligned() @@ -196,7 +196,7 @@ impl IncomingCallNotification { .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, cx| { + .on_click(MouseButton::Left, |_, _, cx| { cx.dispatch_action(RespondToCall { accept: false }); }) .flex(1., true) @@ -222,7 +222,7 @@ impl View for IncomingCallNotification { "IncomingCallNotification" } - fn render(&mut self, cx: &mut ViewContext) -> gpui::ElementBox { + fn render(&mut self, cx: &mut ViewContext) -> ElementBox { let background = cx .global::() .theme diff --git a/crates/collab_ui/src/notifications.rs b/crates/collab_ui/src/notifications.rs index 952c6777a3..73169b493a 100644 --- a/crates/collab_ui/src/notifications.rs +++ b/crates/collab_ui/src/notifications.rs @@ -17,7 +17,7 @@ pub fn render_user_notification( dismiss_action: A, buttons: Vec<(&'static str, Box)>, cx: &mut ViewContext, -) -> ElementBox { +) -> ElementBox { let theme = cx.global::().theme.clone(); let theme = &theme.contact_notification; @@ -51,7 +51,7 @@ pub fn render_user_notification( .boxed(), ) .with_child( - MouseEventHandler::::new(user.id as usize, cx, |state, _| { + MouseEventHandler::::new(user.id as usize, cx, |state, _| { let style = theme.dismiss_button.style_for(state, false); Svg::new("icons/x_mark_8.svg") .with_color(style.color) @@ -67,7 +67,7 @@ pub fn render_user_notification( }) .with_cursor_style(CursorStyle::PointingHand) .with_padding(Padding::uniform(5.)) - .on_click(MouseButton::Left, move |_, cx| { + .on_click(MouseButton::Left, move |_, _, cx| { cx.dispatch_any_action(dismiss_action.boxed_clone()) }) .aligned() @@ -96,7 +96,7 @@ pub fn render_user_notification( Flex::row() .with_children(buttons.into_iter().enumerate().map( |(ix, (message, action))| { - MouseEventHandler::