diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index b9eb20bada..b1d08dcb53 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -5,10 +5,11 @@ mod model_context; pub use async_context::*; pub use entity_map::*; pub use model_context::*; +use refineable::Refineable; use crate::{ - current_platform, Context, LayoutId, MainThreadOnly, Platform, RootView, TextSystem, Window, - WindowContext, WindowHandle, WindowId, + current_platform, Context, LayoutId, MainThreadOnly, Platform, RootView, TextStyle, + TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId, }; use anyhow::{anyhow, Result}; use collections::{HashMap, VecDeque}; @@ -16,7 +17,10 @@ use futures::{future, Future}; use parking_lot::Mutex; use slotmap::SlotMap; use smallvec::SmallVec; -use std::sync::{Arc, Weak}; +use std::{ + any::{type_name, Any, TypeId}, + sync::{Arc, Weak}, +}; use util::ResultExt; #[derive(Clone)] @@ -42,10 +46,12 @@ impl App { this: this.clone(), platform: MainThreadOnly::new(platform, dispatcher), text_system, + pending_updates: 0, + text_style_stack: Vec::new(), + state_stacks_by_type: HashMap::default(), unit_entity, entities, windows: SlotMap::with_key(), - pending_updates: 0, pending_effects: Default::default(), observers: Default::default(), layout_id_buffer: Default::default(), @@ -73,6 +79,8 @@ pub struct AppContext { platform: MainThreadOnly, text_system: Arc, pending_updates: usize, + pub(crate) text_style_stack: Vec, + pub(crate) state_stacks_by_type: HashMap>>, pub(crate) unit_entity: Handle<()>, pub(crate) entities: EntityMap, pub(crate) windows: SlotMap>, @@ -121,6 +129,54 @@ impl AppContext { }) } + pub fn text_style(&self) -> TextStyle { + let mut style = TextStyle::default(); + for refinement in &self.text_style_stack { + style.refine(refinement); + } + style + } + + pub fn state(&self) -> &S { + self.state_stacks_by_type + .get(&TypeId::of::()) + .and_then(|stack| stack.last()) + .and_then(|any_state| any_state.downcast_ref::()) + .ok_or_else(|| anyhow!("no state of type {} exists", type_name::())) + .unwrap() + } + + pub fn state_mut(&mut self) -> &mut S { + self.state_stacks_by_type + .get_mut(&TypeId::of::()) + .and_then(|stack| stack.last_mut()) + .and_then(|any_state| any_state.downcast_mut::()) + .ok_or_else(|| anyhow!("no state of type {} exists", type_name::())) + .unwrap() + } + + pub(crate) fn push_text_style(&mut self, text_style: TextStyleRefinement) { + self.text_style_stack.push(text_style); + } + + pub(crate) fn pop_text_style(&mut self) { + self.text_style_stack.pop(); + } + + pub(crate) fn push_state(&mut self, state: T) { + self.state_stacks_by_type + .entry(TypeId::of::()) + .or_default() + .push(Box::new(state)); + } + + pub(crate) fn pop_state(&mut self) { + self.state_stacks_by_type + .get_mut(&TypeId::of::()) + .and_then(|stack| stack.pop()) + .expect("state stack underflow"); + } + pub(crate) fn update_window( &mut self, id: WindowId, diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 9582ad769d..c763619de1 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -1,6 +1,6 @@ use crate::{ AnyElement, Bounds, Element, Layout, LayoutId, Overflow, ParentElement, Pixels, Point, - Refineable, RefinementCascade, Result, Style, StyleHelpers, Styled, ViewContext, + Refineable, RefinementCascade, Result, StackContext, Style, StyleHelpers, Styled, ViewContext, }; use parking_lot::Mutex; use smallvec::SmallVec; diff --git a/crates/gpui3/src/elements/text.rs b/crates/gpui3/src/elements/text.rs index e188370a6f..699b7ddfa2 100644 --- a/crates/gpui3/src/elements/text.rs +++ b/crates/gpui3/src/elements/text.rs @@ -3,7 +3,7 @@ use crate::{ }; use parking_lot::Mutex; use std::{marker::PhantomData, sync::Arc}; -use util::arc_cow::ArcCow; +use util::{arc_cow::ArcCow, ResultExt}; impl IntoAnyElement for ArcCow<'static, str> { fn into_any(self) -> AnyElement { @@ -52,11 +52,16 @@ impl Element for Text { let layout_id = cx.request_measured_layout(Default::default(), rem_size, { let frame_state = paint_state.clone(); move |_, _| { - let line_layout = text_system.layout_str( - text.as_ref(), - font_size, - &[(text.len(), text_style.to_run())], - ); + let Some(line_layout) = text_system + .layout_line( + text.as_ref(), + font_size, + &[(text.len(), text_style.to_run())], + ) + .log_err() + else { + return Size::default(); + }; let size = Size { width: line_layout.width(), diff --git a/crates/gpui3/src/gpui3.rs b/crates/gpui3/src/gpui3.rs index 1010812953..8c8e64589f 100644 --- a/crates/gpui3/src/gpui3.rs +++ b/crates/gpui3/src/gpui3.rs @@ -61,6 +61,30 @@ pub trait Context { ) -> Self::Result; } +pub trait StackContext { + fn app(&mut self) -> &mut AppContext; + + fn with_text_style(&mut self, style: TextStyleRefinement, f: F) -> R + where + F: FnOnce(&mut Self) -> R, + { + self.app().push_text_style(style); + let result = f(self); + self.app().pop_text_style(); + result + } + + fn with_state(&mut self, state: T, f: F) -> R + where + F: FnOnce(&mut Self) -> R, + { + self.app().push_state(state); + let result = f(self); + self.app().pop_state::(); + result + } +} + pub trait Flatten { fn flatten(self) -> Result; } diff --git a/crates/gpui3/src/platform.rs b/crates/gpui3/src/platform.rs index fbf880bbc9..be407702fd 100644 --- a/crates/gpui3/src/platform.rs +++ b/crates/gpui3/src/platform.rs @@ -7,7 +7,7 @@ mod test; use crate::{ AnyWindowHandle, Bounds, Font, FontId, FontMetrics, GlyphId, LineLayout, Pixels, Point, Result, - RunStyle, Scene, SharedString, Size, + Scene, SharedString, Size, }; use anyhow::anyhow; use async_task::Runnable; @@ -170,7 +170,7 @@ pub trait PlatformTextSystem: Send + Sync { scale_factor: f32, options: RasterizationOptions, ) -> Option<(Bounds, Vec)>; - fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, RunStyle)]) -> LineLayout; + fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, FontId)]) -> LineLayout; fn wrap_line( &self, text: &str, diff --git a/crates/gpui3/src/platform/mac/text_system.rs b/crates/gpui3/src/platform/mac/text_system.rs index 7904e40e64..2682ff86de 100644 --- a/crates/gpui3/src/platform/mac/text_system.rs +++ b/crates/gpui3/src/platform/mac/text_system.rs @@ -1,7 +1,7 @@ use crate::{ point, px, size, Bounds, Font, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight, Glyph, GlyphId, LineLayout, Pixels, PlatformTextSystem, Point, RasterizationOptions, Result, Run, - RunStyle, SharedString, Size, + SharedString, Size, }; use cocoa::appkit::{CGFloat, CGPoint}; use collections::HashMap; @@ -33,7 +33,7 @@ use pathfinder_geometry::{ vector::{Vector2F, Vector2I}, }; use smallvec::SmallVec; -use std::{cell::RefCell, char, cmp, convert::TryFrom, ffi::c_void, sync::Arc}; +use std::{char, cmp, convert::TryFrom, ffi::c_void, sync::Arc}; use super::open_type; @@ -156,8 +156,13 @@ impl PlatformTextSystem for MacTextSystem { ) } - fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, RunStyle)]) -> LineLayout { - self.0.write().layout_line(text, font_size, runs) + fn layout_line( + &self, + text: &str, + font_size: Pixels, + font_runs: &[(usize, FontId)], + ) -> LineLayout { + self.0.write().layout_line(text, font_size, font_runs) } fn wrap_line( @@ -342,7 +347,7 @@ impl MacTextSystemState { &mut self, text: &str, font_size: Pixels, - runs: &[(usize, RunStyle)], + font_runs: &[(usize, FontId)], ) -> LineLayout { // Construct the attributed string, converting UTF8 ranges to UTF16 ranges. let mut string = CFMutableAttributedString::new(); @@ -350,30 +355,8 @@ impl MacTextSystemState { string.replace_str(&CFString::new(text), CFRange::init(0, 0)); let utf16_line_len = string.char_len() as usize; - let last_run: RefCell> = Default::default(); - let font_runs = runs - .iter() - .filter_map(|(len, style)| { - let mut last_run = last_run.borrow_mut(); - if let Some((last_len, last_font)) = last_run.as_mut() { - if style.font == *last_font { - *last_len += *len; - None - } else { - let result = (*last_len, last_font.clone()); - *last_len = *len; - *last_font = style.font.clone(); - Some(result) - } - } else { - *last_run = Some((*len, style.font.clone())); - None - } - }) - .chain(std::iter::from_fn(|| last_run.borrow_mut().take())); - let mut ix_converter = StringIndexConverter::new(text); - for (run_len, font_descriptor) in font_runs { + for (run_len, font_id) in font_runs { let utf8_end = ix_converter.utf8_ix + run_len; let utf16_start = ix_converter.utf16_ix; @@ -387,7 +370,6 @@ impl MacTextSystemState { let cf_range = CFRange::init(utf16_start as isize, (utf16_end - utf16_start) as isize); - let font_id = self.font_selections[&font_descriptor]; let font: &FontKitFont = &self.fonts[font_id.0]; unsafe { string.set_attribute( diff --git a/crates/gpui3/src/text_system.rs b/crates/gpui3/src/text_system.rs index c65331a8da..d2ea53ab49 100644 --- a/crates/gpui3/src/text_system.rs +++ b/crates/gpui3/src/text_system.rs @@ -32,7 +32,8 @@ pub struct TextSystem { font_ids_by_font: RwLock>, fonts_by_font_id: RwLock>, font_metrics: RwLock>, - wrapper_pool: Mutex>>, + wrapper_pool: Mutex>>, + font_runs_pool: Mutex>>, } impl TextSystem { @@ -44,6 +45,7 @@ impl TextSystem { font_ids_by_font: RwLock::new(HashMap::default()), fonts_by_font_id: RwLock::new(HashMap::default()), wrapper_pool: Mutex::new(HashMap::default()), + font_runs_pool: Default::default(), } } @@ -147,41 +149,67 @@ impl TextSystem { } } - pub fn layout_str<'a>( - &'a self, - text: &'a str, + pub fn layout_line( + &self, + text: &str, font_size: Pixels, - runs: &'a [(usize, RunStyle)], - ) -> Line { - self.text_layout_cache.layout_str(text, font_size, runs) + runs: &[(usize, RunStyle)], + ) -> Result { + let mut font_runs = self.font_runs_pool.lock().pop().unwrap_or_default(); + let mut last_font: Option<&Font> = None; + for (len, style) in runs { + if let Some(last_font) = last_font.as_ref() { + if **last_font == style.font { + font_runs.last_mut().unwrap().0 += len; + continue; + } + } + last_font = Some(&style.font); + font_runs.push((*len, self.font_id(&style.font)?)); + } + + let layout = self + .text_layout_cache + .layout_line(text, font_size, &font_runs); + + font_runs.clear(); + self.font_runs_pool.lock().push(font_runs); + + Ok(Line::new(layout.clone(), runs)) } pub fn finish_frame(&self) { self.text_layout_cache.finish_frame() } - pub fn line_wrapper(self: &Arc, font: Font, font_size: Pixels) -> LineWrapperHandle { + pub fn line_wrapper( + self: &Arc, + font: Font, + font_size: Pixels, + ) -> Result { let lock = &mut self.wrapper_pool.lock(); + let font_id = self.font_id(&font)?; let wrappers = lock - .entry(FontWithSize { - font: font.clone(), - font_size, - }) + .entry(FontIdWithSize { font_id, font_size }) .or_default(); - let wrapper = wrappers.pop().unwrap_or_else(|| { - LineWrapper::new(font, font_size, self.platform_text_system.clone()) - }); + let wrapper = wrappers.pop().map(anyhow::Ok).unwrap_or_else(|| { + Ok(LineWrapper::new( + font_id, + font_size, + self.platform_text_system.clone(), + )) + })?; - LineWrapperHandle { + Ok(LineWrapperHandle { wrapper: Some(wrapper), text_system: self.clone(), - } + }) } } #[derive(Hash, Eq, PartialEq)] -struct FontWithSize { - font: Font, +struct FontIdWithSize { + font_id: FontId, font_size: Pixels, } @@ -195,8 +223,8 @@ impl Drop for LineWrapperHandle { let mut state = self.text_system.wrapper_pool.lock(); let wrapper = self.wrapper.take().unwrap(); state - .get_mut(&FontWithSize { - font: wrapper.font.clone(), + .get_mut(&FontIdWithSize { + font_id: wrapper.font_id.clone(), font_size: wrapper.font_size, }) .unwrap() diff --git a/crates/gpui3/src/text_system/line_wrapper.rs b/crates/gpui3/src/text_system/line_wrapper.rs index 3bed4789d4..87c75cc9ac 100644 --- a/crates/gpui3/src/text_system/line_wrapper.rs +++ b/crates/gpui3/src/text_system/line_wrapper.rs @@ -1,10 +1,10 @@ -use crate::{px, Font, Line, Pixels, PlatformTextSystem, RunStyle, ShapedBoundary}; +use crate::{px, FontId, Line, Pixels, PlatformTextSystem, ShapedBoundary}; use collections::HashMap; use std::{iter, sync::Arc}; pub struct LineWrapper { - text_system: Arc, - pub(crate) font: Font, + platform_text_system: Arc, + pub(crate) font_id: FontId, pub(crate) font_size: Pixels, cached_ascii_char_widths: [Option; 128], cached_other_char_widths: HashMap, @@ -13,10 +13,14 @@ pub struct LineWrapper { impl LineWrapper { pub const MAX_INDENT: u32 = 256; - pub fn new(font: Font, font_size: Pixels, text_system: Arc) -> Self { + pub fn new( + font_id: FontId, + font_size: Pixels, + text_system: Arc, + ) -> Self { Self { - text_system, - font, + platform_text_system: text_system, + font_id, font_size, cached_ascii_char_widths: [None; 128], cached_other_char_widths: HashMap::default(), @@ -178,19 +182,8 @@ impl LineWrapper { } fn compute_width_for_char(&self, c: char) -> Pixels { - self.text_system - .layout_line( - &c.to_string(), - self.font_size, - &[( - 1, - RunStyle { - font: self.font.clone(), - color: Default::default(), - underline: Default::default(), - }, - )], - ) + self.platform_text_system + .layout_line(&c.to_string(), self.font_size, &[(1, self.font_id)]) .width } } @@ -210,14 +203,14 @@ impl Boundary { #[cfg(test)] mod tests { use super::*; - use crate::{font, App}; + use crate::{font, App, RunStyle}; #[test] fn test_wrap_line() { App::test().run(|cx| { let text_system = cx.text_system().clone(); let mut wrapper = LineWrapper::new( - font("Courier"), + text_system.font_id(&font("Courier")).unwrap(), px(16.), text_system.platform_text_system.clone(), ); @@ -293,20 +286,22 @@ mod tests { }; let text = "aa bbb cccc ddddd eeee"; - let line = text_system.layout_str( - text, - px(16.), - &[ - (4, normal.clone()), - (5, bold.clone()), - (6, normal.clone()), - (1, bold.clone()), - (7, normal.clone()), - ], - ); + let line = text_system + .layout_line( + text, + px(16.), + &[ + (4, normal.clone()), + (5, bold.clone()), + (6, normal.clone()), + (1, bold.clone()), + (7, normal.clone()), + ], + ) + .unwrap(); let mut wrapper = LineWrapper::new( - normal.font, + text_system.font_id(&normal.font).unwrap(), px(16.), text_system.platform_text_system.clone(), ); diff --git a/crates/gpui3/src/text_system/text_layout_cache.rs b/crates/gpui3/src/text_system/text_layout_cache.rs index 455e8bf741..138b73eb23 100644 --- a/crates/gpui3/src/text_system/text_layout_cache.rs +++ b/crates/gpui3/src/text_system/text_layout_cache.rs @@ -15,7 +15,7 @@ use std::{ pub(crate) struct TextLayoutCache { prev_frame: Mutex>>, curr_frame: RwLock>>, - fonts: Arc, + platform_text_system: Arc, } impl TextLayoutCache { @@ -23,7 +23,7 @@ impl TextLayoutCache { Self { prev_frame: Mutex::new(HashMap::new()), curr_frame: RwLock::new(HashMap::new()), - fonts, + platform_text_system: fonts, } } @@ -34,12 +34,12 @@ impl TextLayoutCache { curr_frame.clear(); } - pub fn layout_str<'a>( + pub fn layout_line<'a>( &'a self, text: &'a str, font_size: Pixels, - runs: &'a [(usize, RunStyle)], - ) -> Line { + runs: &[(usize, FontId)], + ) -> Arc { let key = &CacheKeyRef { text, font_size, @@ -47,22 +47,22 @@ impl TextLayoutCache { } as &dyn CacheKey; let curr_frame = self.curr_frame.upgradable_read(); if let Some(layout) = curr_frame.get(key) { - return Line::new(layout.clone(), runs); + return layout.clone(); } let mut curr_frame = RwLockUpgradableReadGuard::upgrade(curr_frame); if let Some((key, layout)) = self.prev_frame.lock().remove_entry(key) { curr_frame.insert(key, layout.clone()); - Line::new(layout, runs) + layout } else { - let layout = Arc::new(self.fonts.layout_line(text, font_size, runs)); + let layout = Arc::new(self.platform_text_system.layout_line(text, font_size, runs)); let key = CacheKeyValue { text: text.into(), font_size, runs: SmallVec::from(runs), }; curr_frame.insert(key, layout.clone()); - Line::new(layout, runs) + layout } } } @@ -89,7 +89,7 @@ impl<'a> Hash for (dyn CacheKey + 'a) { struct CacheKeyValue { text: String, font_size: Pixels, - runs: SmallVec<[(usize, RunStyle); 1]>, + runs: SmallVec<[(usize, FontId); 1]>, } impl CacheKey for CacheKeyValue { @@ -120,11 +120,11 @@ impl<'a> Borrow for CacheKeyValue { } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq, Eq)] struct CacheKeyRef<'a> { text: &'a str, font_size: Pixels, - runs: &'a [(usize, RunStyle)], + runs: &'a [(usize, FontId)], } impl<'a> CacheKey for CacheKeyRef<'a> { @@ -133,26 +133,13 @@ impl<'a> CacheKey for CacheKeyRef<'a> { } } -impl<'a> PartialEq for CacheKeyRef<'a> { - fn eq(&self, other: &Self) -> bool { - self.text == other.text - && self.font_size == other.font_size - && self.runs.len() == other.runs.len() - && self.runs.iter().zip(other.runs.iter()).all( - |((len_a, style_a), (len_b, style_b))| { - len_a == len_b && style_a.font == style_b.font - }, - ) - } -} - impl<'a> Hash for CacheKeyRef<'a> { fn hash(&self, state: &mut H) { self.text.hash(state); self.font_size.hash(state); - for (len, style_id) in self.runs { + for (len, font_id) in self.runs { len.hash(state); - style_id.font.hash(state); + font_id.hash(state); } } } diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index a0f880f47d..37e37716a4 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -1,18 +1,11 @@ use crate::{ px, AnyView, AppContext, AvailableSpace, Bounds, Context, Effect, Element, EntityId, Handle, LayoutId, MainThreadOnly, Pixels, Platform, PlatformWindow, Point, Reference, Scene, Size, - Style, TaffyLayoutEngine, TextStyle, TextStyleRefinement, WeakHandle, WindowOptions, + StackContext, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, }; use anyhow::Result; -use collections::HashMap; use derive_more::{Deref, DerefMut}; -use refineable::Refineable; -use std::{ - any::{Any, TypeId}, - future, - marker::PhantomData, - sync::Arc, -}; +use std::{any::TypeId, future, marker::PhantomData, sync::Arc}; use util::ResultExt; pub struct AnyWindow {} @@ -23,8 +16,6 @@ pub struct Window { rem_size: Pixels, content_size: Size, layout_engine: TaffyLayoutEngine, - text_style_stack: Vec, - state_stacks_by_type: HashMap>>, pub(crate) root_view: Option>, mouse_position: Point, pub(crate) scene: Scene, @@ -63,8 +54,6 @@ impl Window { rem_size: px(16.), content_size, layout_engine: TaffyLayoutEngine::new(), - text_style_stack: Vec::new(), - state_stacks_by_type: HashMap::default(), root_view: None, mouse_position, scene: Scene::new(scale_factor), @@ -89,13 +78,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { } } - // pub(crate) fn immutable(app: &'a AppContext, window: &'w Window) -> Self { - // Self { - // app: Reference::Immutable(app), - // window: Reference::Immutable(window), - // } - // } - pub(crate) fn draw(&mut self) -> Result<()> { let unit_entity = self.unit_entity.clone(); self.update_entity(&unit_entity, |_, cx| { @@ -158,41 +140,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { self.window.rem_size } - pub fn push_cascading_state(&mut self, theme: T) { - self.window - .state_stacks_by_type - .entry(TypeId::of::()) - .or_default() - .push(Box::new(theme)); - } - - pub fn pop_cascading_state(&mut self) { - self.window - .state_stacks_by_type - .get_mut(&TypeId::of::()) - .and_then(|stack| stack.pop()) - .expect("cascading state not found"); - } - - pub fn cascading_state(&self) -> &T { - let type_id = TypeId::of::(); - self.window - .state_stacks_by_type - .get(&type_id) - .and_then(|stack| stack.last()) - .expect("no cascading state of the specified type has been pushed") - .downcast_ref::() - .unwrap() - } - - pub fn text_style(&self) -> TextStyle { - let mut style = TextStyle::default(); - for refinement in &self.window.text_style_stack { - style.refine(refinement); - } - style - } - pub fn mouse_position(&self) -> Point { self.window.mouse_position } @@ -230,6 +177,32 @@ impl Context for WindowContext<'_, '_> { } } +impl StackContext for ViewContext<'_, '_, S> { + fn app(&mut self) -> &mut AppContext { + &mut *self.app + } + + fn with_text_style(&mut self, style: crate::TextStyleRefinement, f: F) -> R + where + F: FnOnce(&mut Self) -> R, + { + self.push_text_style(style); + let result = f(self); + self.pop_text_style(); + result + } + + fn with_state(&mut self, state: T, f: F) -> R + where + F: FnOnce(&mut Self) -> R, + { + self.push_state(state); + let result = f(self); + self.pop_state::(); + result + } +} + #[derive(Deref, DerefMut)] pub struct ViewContext<'a, 'w, S> { #[deref] @@ -252,17 +225,6 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> { self.entities.weak_handle(self.entity_id) } - pub fn with_text_style( - &mut self, - style: TextStyleRefinement, - f: impl FnOnce(&mut Self) -> R, - ) -> R { - self.window.text_style_stack.push(style); - let result = f(self); - self.window.text_style_stack.pop(); - result - } - pub fn observe( &mut self, handle: &Handle, diff --git a/crates/storybook2/src/collab_panel.rs b/crates/storybook2/src/collab_panel.rs index 0828abd903..415598d0cb 100644 --- a/crates/storybook2/src/collab_panel.rs +++ b/crates/storybook2/src/collab_panel.rs @@ -9,9 +9,7 @@ pub struct CollabPanel { } pub fn collab_panel(cx: &mut WindowContext) -> View { - view(cx.entity(|cx| CollabPanel::new(cx)), |panel, cx| { - panel.render(cx) - }) + view(cx.entity(|cx| CollabPanel::new(cx)), CollabPanel::render) } impl CollabPanel { diff --git a/crates/storybook2/src/element_ext.rs b/crates/storybook2/src/element_ext.rs deleted file mode 100644 index d7c5e3d1af..0000000000 --- a/crates/storybook2/src/element_ext.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::theme::{Theme, Themed}; -use gpui3::Element; - -pub trait ElementExt: Element { - fn themed(self, theme: Theme) -> Themed - where - Self: Sized; -} - -impl ElementExt for E { - fn themed(self, theme: Theme) -> Themed - where - Self: Sized, - { - Themed { child: self, theme } - } -} diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index 0bb87d2a13..bc927b78fa 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -1,15 +1,9 @@ #![allow(dead_code, unused_variables)] -use crate::theme::Theme; -use element_ext::ElementExt; -use gpui3::{Element, ViewContext}; - use log::LevelFilter; use simplelog::SimpleLogger; mod collab_panel; -// mod components; -mod element_ext; mod theme; mod themes; mod workspace; @@ -25,53 +19,6 @@ fn main() { gpui3::App::production().run(|cx| { let window = cx.open_window(Default::default(), |cx| workspace(cx)); }); - - // gpui3::App::new(Assets).unwrap().run(|cx| { - // let mut store = SettingsStore::default(); - // store - // .set_default_settings(default_settings().as_ref(), cx) - // .unwrap(); - // cx.set_global(store); - // legacy_theme::init(Assets, cx); - // // load_embedded_fonts(cx.platform().as_ref()); - - // cx.add_window( - // gpui2::WindowOptions { - // bounds: WindowBounds::Fixed(RectF::new(vec2f(0., 0.), vec2f(1400., 900.))), - // center: true, - // ..Default::default() - // }, - // |cx| { - // view(|cx| { - // cx.enable_inspector(); - // storybook(&mut ViewContext::new(cx)) - // }) - // }, - // ); - // cx.platform().activate(true); - // }); -} - -fn storybook(cx: &mut ViewContext) -> impl Element { - workspace(cx).themed(current_theme(cx)) -} - -// Nathan: During the transition to gpui2, we will include the base theme on the legacy Theme struct. -fn current_theme(cx: &mut ViewContext) -> Theme { - todo!() - // settings::get::(cx) - // .theme - // .deserialized_base_theme - // .lock() - // .get_or_insert_with(|| { - // let theme: Theme = - // serde_json::from_value(settings::get::(cx).theme.base_theme.clone()) - // .unwrap(); - // Box::new(theme) - // }) - // .downcast_ref::() - // .unwrap() - // .clone() } use rust_embed::RustEmbed; diff --git a/crates/storybook2/src/theme.rs b/crates/storybook2/src/theme.rs index f8b555f82a..88bc21775c 100644 --- a/crates/storybook2/src/theme.rs +++ b/crates/storybook2/src/theme.rs @@ -1,4 +1,4 @@ -use gpui3::{Element, Hsla, Layout, LayoutId, Result, ViewContext, WindowContext}; +use gpui3::{Element, Hsla, Layout, LayoutId, Result, StackContext, ViewContext, WindowContext}; use serde::{de::Visitor, Deserialize, Deserializer}; use std::{collections::HashMap, fmt}; @@ -127,6 +127,15 @@ where deserializer.deserialize_map(SyntaxVisitor) } +pub fn themed(theme: Theme, cx: &mut ViewContext, build_child: F) -> Themed +where + E: Element, + F: FnOnce(&mut ViewContext) -> E, +{ + let child = cx.with_state(theme.clone(), |cx| build_child(cx)); + Themed { theme, child } +} + pub struct Themed { pub(crate) theme: Theme, pub(crate) child: E, @@ -144,10 +153,7 @@ impl Element for Themed { where Self: Sized, { - cx.push_cascading_state(self.theme.clone()); - let result = self.child.layout(state, cx); - cx.pop_cascading_state::(); - result + cx.with_state(self.theme.clone(), |cx| self.child.layout(state, cx)) } fn paint( @@ -160,10 +166,9 @@ impl Element for Themed { where Self: Sized, { - cx.push_cascading_state(self.theme.clone()); - self.child.paint(layout, state, frame_state, cx)?; - cx.pop_cascading_state::(); - Ok(()) + cx.with_state(self.theme.clone(), |cx| { + self.child.paint(layout, state, frame_state, cx) + }) } } @@ -184,5 +189,5 @@ impl Element for Themed { // } pub fn theme<'a>(cx: &'a WindowContext) -> &'a Theme { - cx.cascading_state() + cx.state() } diff --git a/crates/storybook2/src/workspace.rs b/crates/storybook2/src/workspace.rs index c614af490d..4ed5bbf879 100644 --- a/crates/storybook2/src/workspace.rs +++ b/crates/storybook2/src/workspace.rs @@ -1,7 +1,6 @@ use crate::{ collab_panel::{collab_panel, CollabPanel}, - element_ext::ElementExt, - theme::theme, + theme::{theme, themed}, themes::rose_pine_dawn, }; use gpui3::{ @@ -15,9 +14,7 @@ pub struct Workspace { } pub fn workspace(cx: &mut WindowContext) -> RootView { - view(cx.entity(|cx| Workspace::new(cx)), |workspace, cx| { - workspace.render(cx) - }) + view(cx.entity(|cx| Workspace::new(cx)), Workspace::render) } impl Workspace { @@ -31,36 +28,37 @@ impl Workspace { fn render(&mut self, cx: &mut ViewContext) -> impl Element { let theme = rose_pine_dawn(); - div::() - .size_full() - .flex() - .flex_col() - .font("Zed Sans Extended") - .gap_0() - .justify_start() - .items_start() - .text_color(theme.lowest.base.default.foreground) - .fill(theme.middle.base.default.background) - .child(titlebar(cx)) - .child( - div::() - .flex_1() - .w_full() - .flex() - .flex_row() - .overflow_hidden() - .child(self.left_panel.clone()) - .child(div().h_full().flex_1()) - .child(self.right_panel.clone()), - ) - .child(statusbar::statusbar(cx)) - .themed(theme) + themed(rose_pine_dawn(), cx, |cx| { + div() + .size_full() + .flex() + .flex_col() + .font("Zed Sans Extended") + .gap_0() + .justify_start() + .items_start() + .text_color(theme.lowest.base.default.foreground) + .fill(theme.middle.base.default.background) + .child(titlebar(cx)) + .child( + div() + .flex_1() + .w_full() + .flex() + .flex_row() + .overflow_hidden() + .child(self.left_panel.clone()) + .child(div().h_full().flex_1()) + .child(self.right_panel.clone()), + ) + .child(statusbar::statusbar(cx)) + }) } } struct Titlebar; -pub fn titlebar(cx: &mut ViewContext) -> impl Element { +pub fn titlebar(cx: &mut ViewContext) -> impl Element { let ref mut this = Titlebar; let theme = theme(cx); div() @@ -75,7 +73,10 @@ pub fn titlebar(cx: &mut ViewContext) -> impl Element } impl Titlebar { - fn render(&mut self, cx: &mut ViewContext) -> impl Element { + fn render( + &mut self, + cx: &mut ViewContext, + ) -> impl Element { let theme = theme(cx); div() .flex() @@ -88,7 +89,10 @@ impl Titlebar { .child(self.right_group(cx)) } - fn left_group(&mut self, cx: &mut ViewContext) -> impl Element { + fn left_group( + &mut self, + cx: &mut ViewContext, + ) -> impl Element { let theme = theme(cx); div() .flex() @@ -162,7 +166,10 @@ impl Titlebar { ) } - fn right_group(&mut self, cx: &mut ViewContext) -> impl Element { + fn right_group( + &mut self, + cx: &mut ViewContext, + ) -> impl Element { let theme = theme(cx); div() .flex() @@ -294,7 +301,7 @@ mod statusbar { use super::*; - pub fn statusbar(cx: &mut ViewContext) -> impl Element { + pub fn statusbar(cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div() .flex() @@ -307,7 +314,7 @@ mod statusbar { // .child(right_group(cx)) } - fn left_group(cx: &mut ViewContext) -> impl Element { + fn left_group(cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div() .flex() @@ -404,7 +411,7 @@ mod statusbar { ) } - fn right_group(cx: &mut ViewContext) -> impl Element { + fn right_group(cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div() .flex()