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;