diff --git a/crates/gpui3/src/arc_cow.rs b/crates/gpui3/src/arc_cow.rs deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/crates/gpui3/src/element.rs b/crates/gpui3/src/element.rs index 3a60a9fa6e33be6837cf63bc7db1a61d04644bb1..eef90f4f2d3017a6f09125e2bf7881f22fcc128d 100644 --- a/crates/gpui3/src/element.rs +++ b/crates/gpui3/src/element.rs @@ -1,12 +1,16 @@ -use crate::Bounds; - -use super::{LayoutId, Pixels, Point, Result, ViewContext}; +use crate::{Bounds, Identified, LayoutId, Pixels, Point, Result, ViewContext}; +use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; +use util::arc_cow::ArcCow; pub trait Element: 'static { type State; type FrameState; + fn element_id(&self) -> Option { + None + } + fn layout( &mut self, state: &mut Self::State, @@ -20,8 +24,27 @@ pub trait Element: 'static { frame_state: &mut Self::FrameState, cx: &mut ViewContext, ) -> Result<()>; + + fn id(self, id: ElementId) -> Identified + where + Self: Sized, + { + Identified { element: self, id } + } +} + +pub trait StatefulElement: Element { + fn element_id(&self) -> ElementId { + Element::element_id(self).unwrap() + } } +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct ElementId(ArcCow<'static, [u8]>); + +#[derive(Deref, DerefMut, Default, Clone, Debug)] +pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>); + pub trait ParentElement { type State; diff --git a/crates/gpui3/src/elements.rs b/crates/gpui3/src/elements.rs index d879153488566220e7164d5137f63110911929ab..5ee517b6e913ff16361dcc4d2acddb3e4212f83f 100644 --- a/crates/gpui3/src/elements.rs +++ b/crates/gpui3/src/elements.rs @@ -1,13 +1,15 @@ mod div; mod hoverable; +mod identified; mod img; -mod stateless; +mod pressable; mod svg; mod text; pub use div::*; pub use hoverable::*; +pub use identified::*; pub use img::*; -pub use stateless::*; +pub use pressable::*; pub use svg::*; pub use text::*; diff --git a/crates/gpui3/src/elements/hoverable.rs b/crates/gpui3/src/elements/hoverable.rs index fc43c895cecb1fc1b183dfe6fb49b07d173950c1..ddd6782afc46cd364c4ba77715e846df649f141a 100644 --- a/crates/gpui3/src/elements/hoverable.rs +++ b/crates/gpui3/src/elements/hoverable.rs @@ -1,6 +1,6 @@ use crate::{ - AnyElement, Bounds, DispatchPhase, Element, Interactive, MouseEventListeners, MouseMoveEvent, - ParentElement, Pixels, Styled, ViewContext, + AnyElement, Bounds, DispatchPhase, Element, ElementId, Interactive, MouseEventListeners, + MouseMoveEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext, }; use anyhow::Result; use refineable::{CascadeSlot, Refineable, RefinementCascade}; @@ -53,6 +53,10 @@ impl Element for Hoverable { type State = E::State; type FrameState = E::FrameState; + fn element_id(&self) -> Option { + self.child.element_id() + } + fn layout( &mut self, state: &mut Self::State, @@ -95,3 +99,5 @@ impl ParentElement for Hoverable { self.child.children_mut() } } + +impl StatefulElement for Hoverable {} diff --git a/crates/gpui3/src/elements/identified.rs b/crates/gpui3/src/elements/identified.rs new file mode 100644 index 0000000000000000000000000000000000000000..1cbbbb99ce7c84d3a8683a96f2b59b2dedba6710 --- /dev/null +++ b/crates/gpui3/src/elements/identified.rs @@ -0,0 +1,38 @@ +use crate::{BorrowWindow, Bounds, Element, ElementId, LayoutId, StatefulElement, ViewContext}; +use anyhow::Result; + +pub struct Identified { + pub(crate) element: E, + pub(crate) id: ElementId, +} + +impl Element for Identified { + type State = E::State; + type FrameState = E::FrameState; + + fn element_id(&self) -> Option { + Some(self.id.clone()) + } + + fn layout( + &mut self, + state: &mut Self::State, + cx: &mut ViewContext, + ) -> Result<(LayoutId, Self::FrameState)> { + self.element.layout(state, cx) + } + + fn paint( + &mut self, + bounds: Bounds, + state: &mut Self::State, + frame_state: &mut Self::FrameState, + cx: &mut ViewContext, + ) -> Result<()> { + cx.with_element_id(self.id.clone(), |cx| { + self.element.paint(bounds, state, frame_state, cx) + }) + } +} + +impl StatefulElement for Identified {} diff --git a/crates/gpui3/src/elements/pressable.rs b/crates/gpui3/src/elements/pressable.rs index 6e9b031edae0905541d14bcd6b232589936bb3cd..d9e52066eb1b81b4a48a2a15506603e771df67e0 100644 --- a/crates/gpui3/src/elements/pressable.rs +++ b/crates/gpui3/src/elements/pressable.rs @@ -1,106 +1,211 @@ -use crate::{ - element::{AnyElement, Element, IntoElement, Layout, ParentElement}, - interactive::{InteractionHandlers, Interactive}, - style::{Style, StyleHelpers, Styleable}, - ViewContext, -}; -use anyhow::Result; -use gpui::{geometry::vector::Vector2F, platform::MouseButtonEvent, LayoutId}; -use refineable::{CascadeSlot, Refineable, RefinementCascade}; -use smallvec::SmallVec; -use std::{cell::Cell, rc::Rc}; - -pub struct Pressable { - pressed: Rc>, - pressed_style: ::Refinement, - cascade_slot: CascadeSlot, - child: E, -} - -pub fn pressable(mut child: E) -> Pressable { - Pressable { - pressed: Rc::new(Cell::new(false)), - pressed_style: Default::default(), - cascade_slot: child.style_cascade().reserve(), - child, - } -} - -impl Styleable for Pressable { - type Style = E::Style; - - fn declared_style(&mut self) -> &mut ::Refinement { - &mut self.pressed_style - } - - fn style_cascade(&mut self) -> &mut RefinementCascade { - self.child.style_cascade() - } -} - -impl + Styleable> Element for Pressable { - type PaintState = E::PaintState; - - fn layout( - &mut self, - view: &mut V, - cx: &mut ViewContext, - ) -> Result<(LayoutId, Self::PaintState)> - where - Self: Sized, - { - self.child.layout(view, cx) - } - - fn paint( - &mut self, - view: &mut V, - parent_origin: Vector2F, - layout: &Layout, - paint_state: &mut Self::PaintState, - cx: &mut ViewContext, - ) where - Self: Sized, - { - let slot = self.cascade_slot; - let style = self.pressed.get().then_some(self.pressed_style.clone()); - self.style_cascade().set(slot, style); - - let pressed = self.pressed.clone(); - let bounds = layout.bounds + parent_origin; - cx.on_event(layout.order, move |_view, event: &MouseButtonEvent, cx| { - if event.is_down { - if bounds.contains_point(event.position) { - pressed.set(true); - cx.repaint(); - } - } else if pressed.get() { - pressed.set(false); - cx.repaint(); - } - }); - - self.child - .paint(view, parent_origin, layout, paint_state, cx); - } -} - -impl + Styleable> Interactive for Pressable { - fn interaction_handlers(&mut self) -> &mut InteractionHandlers { - self.child.interaction_handlers() - } -} - -impl + Styleable> ParentElement for Pressable { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { - self.child.children_mut() - } -} - -impl + Styleable> IntoElement for Pressable { - type Element = Self; - - fn into_element(self) -> Self::Element { - self - } -} +// use crate::{ +// AnyElement, Bounds, DispatchPhase, Element, Identified, Interactive, MouseDownEvent, +// MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext, +// }; +// use anyhow::Result; +// use refineable::{CascadeSlot, Refineable, RefinementCascade}; +// use smallvec::SmallVec; +// use std::sync::{ +// atomic::{AtomicBool, Ordering::SeqCst}, +// Arc, +// }; + +// pub struct Pressable { +// pressed: Arc, +// cascade_slot: CascadeSlot, +// pressed_style: ::Refinement, +// child: E, +// } + +// impl Pressable { +// pub fn new(mut child: E) -> Self { +// Self { +// pressed: Arc::new(AtomicBool::new(false)), +// cascade_slot: child.style_cascade().reserve(), +// pressed_style: Default::default(), +// child, +// } +// } +// } + +// impl Styled for Pressable +// where +// E: Styled, +// { +// type Style = E::Style; + +// fn style_cascade(&mut self) -> &mut RefinementCascade { +// self.child.style_cascade() +// } + +// fn declared_style(&mut self) -> &mut ::Refinement { +// &mut self.pressed_style +// } +// } + +// impl + Styled> Interactive for Pressable { +// fn listeners(&mut self) -> &mut MouseEventListeners { +// self.child.listeners() +// } +// } + +// impl Element for Pressable { +// type State = E::State; +// type FrameState = E::FrameState; + +// fn layout( +// &mut self, +// state: &mut Self::State, +// cx: &mut ViewContext, +// ) -> Result<(crate::LayoutId, Self::FrameState)> { +// Ok(self.child.layout(state, cx)?) +// } + +// fn paint( +// &mut self, +// bounds: Bounds, +// state: &mut Self::State, +// frame_state: &mut Self::FrameState, +// cx: &mut ViewContext, +// ) -> Result<()> { +// let pressed = bounds.contains_point(cx.mouse_position()); +// let slot = self.cascade_slot; +// let style = pressed.then_some(self.pressed_style.clone()); +// self.style_cascade().set(slot, style); +// self.pressed.store(pressed, SeqCst); + +// let hovered = self.pressed.clone(); +// cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| { +// if phase == DispatchPhase::Capture { +// if bounds.contains_point(event.position) != hovered.load(SeqCst) { +// cx.notify(); +// } +// } +// }); +// cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| { +// if phase == DispatchPhase::Capture { +// if bounds.contains_point(event.position) != hovered.load(SeqCst) { +// cx.notify(); +// } +// } +// }); + +// self.child.paint(bounds, state, frame_state, cx)?; +// Ok(()) +// } +// } + +// impl ParentElement for Pressable { +// type State = E::State; + +// fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { +// self.child.children_mut() +// } +// } + +// // use crate::{ +// // element::{AnyElement, Element, IntoElement, Layout, ParentElement}, +// // interactive::{InteractionHandlers, Interactive}, +// // style::{Style, StyleHelpers, Styleable}, +// // ViewContext, +// // }; +// // use anyhow::Result; +// // use gpui::{geometry::vector::Vector2F, platform::MouseButtonEvent, LayoutId}; +// // use refineable::{CascadeSlot, Refineable, RefinementCascade}; +// // use smallvec::SmallVec; +// // use std::{cell::Cell, rc::Rc}; + +// // pub struct Pressable { +// // pressed: Rc>, +// // pressed_style: ::Refinement, +// // cascade_slot: CascadeSlot, +// // child: E, +// // } + +// // pub fn pressable(mut child: E) -> Pressable { +// // Pressable { +// // pressed: Rc::new(Cell::new(false)), +// // pressed_style: Default::default(), +// // cascade_slot: child.style_cascade().reserve(), +// // child, +// // } +// // } + +// // impl Styleable for Pressable { +// // type Style = E::Style; + +// // fn declared_style(&mut self) -> &mut ::Refinement { +// // &mut self.pressed_style +// // } + +// // fn style_cascade(&mut self) -> &mut RefinementCascade { +// // self.child.style_cascade() +// // } +// // } + +// // impl + Styleable> Element for Pressable { +// // type PaintState = E::PaintState; + +// // fn layout( +// // &mut self, +// // view: &mut V, +// // cx: &mut ViewContext, +// // ) -> Result<(LayoutId, Self::PaintState)> +// // where +// // Self: Sized, +// // { +// // self.child.layout(view, cx) +// // } + +// // fn paint( +// // &mut self, +// // view: &mut V, +// // parent_origin: Vector2F, +// // layout: &Layout, +// // paint_state: &mut Self::PaintState, +// // cx: &mut ViewContext, +// // ) where +// // Self: Sized, +// // { +// // let slot = self.cascade_slot; +// // let style = self.pressed.get().then_some(self.pressed_style.clone()); +// // self.style_cascade().set(slot, style); + +// // let pressed = self.pressed.clone(); +// // let bounds = layout.bounds + parent_origin; +// // cx.on_event(layout.order, move |_view, event: &MouseButtonEvent, cx| { +// // if event.is_down { +// // if bounds.contains_point(event.position) { +// // pressed.set(true); +// // cx.repaint(); +// // } +// // } else if pressed.get() { +// // pressed.set(false); +// // cx.repaint(); +// // } +// // }); + +// // self.child +// // .paint(view, parent_origin, layout, paint_state, cx); +// // } +// // } + +// // impl + Styleable> Interactive for Pressable { +// // fn interaction_handlers(&mut self) -> &mut InteractionHandlers { +// // self.child.interaction_handlers() +// // } +// // } + +// // impl + Styleable> ParentElement for Pressable { +// // fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { +// // self.child.children_mut() +// // } +// // } + +// // impl + Styleable> IntoElement for Pressable { +// // type Element = Self; + +// // fn into_element(self) -> Self::Element { +// // self +// // } +// // } diff --git a/crates/gpui3/src/elements/stateless.rs b/crates/gpui3/src/elements/stateless.rs deleted file mode 100644 index b1cd31a146bd61a4cc7cdabe2f78a595df5b332d..0000000000000000000000000000000000000000 --- a/crates/gpui3/src/elements/stateless.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::{Bounds, Element, Pixels}; -use std::marker::PhantomData; - -pub struct Stateless, S> { - element: E, - parent_state_type: PhantomData, -} - -impl, S: Send + Sync + 'static> Element for Stateless { - type State = S; - type FrameState = E::FrameState; - - fn layout( - &mut self, - _: &mut Self::State, - cx: &mut crate::ViewContext, - ) -> anyhow::Result<(crate::LayoutId, Self::FrameState)> { - cx.erase_state(|cx| self.element.layout(&mut (), cx)) - } - - fn paint( - &mut self, - bounds: Bounds, - _: &mut Self::State, - frame_state: &mut Self::FrameState, - cx: &mut crate::ViewContext, - ) -> anyhow::Result<()> { - cx.erase_state(|cx| self.element.paint(bounds, &mut (), frame_state, cx)) - } -} diff --git a/crates/gpui3/src/gpui3.rs b/crates/gpui3/src/gpui3.rs index 1b0de7498080ce105f706bc5aae798389609b82b..d3b5145c4e4e3ce46e21f5eecb5d9702bc5217c1 100644 --- a/crates/gpui3/src/gpui3.rs +++ b/crates/gpui3/src/gpui3.rs @@ -39,22 +39,23 @@ pub use serde; pub use serde_json; pub use smallvec; pub use smol::Timer; -use std::{ - mem, - ops::{Deref, DerefMut}, - sync::Arc, -}; pub use style::*; pub use style_helpers::*; pub use styled::*; pub use svg_renderer::*; -use taffy::TaffyLayoutEngine; pub use taffy::{AvailableSpace, LayoutId}; pub use text_system::*; pub use util::arc_cow::ArcCow; pub use view::*; pub use window::*; +use std::{ + mem, + ops::{Deref, DerefMut}, + sync::Arc, +}; +use taffy::TaffyLayoutEngine; + pub trait Context { type EntityContext<'a, 'w, T: 'static + Send + Sync>; type Result; diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 47aa7b7b5fbb6f82e72b3ab2b823d519a55a7e6d..8c71284cc93730d0919834e4ddd04e920a9d8eeb 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -1,12 +1,12 @@ use crate::{ image_cache::RenderImageParams, px, size, AnyView, AppContext, AsyncWindowContext, AvailableSpace, BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, - Edges, Effect, Element, EntityId, Event, FontId, GlyphId, Handle, Hsla, ImageData, IsZero, - LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, - PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, - RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, - TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions, - SUBPIXEL_VARIANTS, + Edges, Effect, Element, ElementId, EntityId, Event, FontId, GlobalElementId, GlyphId, Handle, + Hsla, ImageData, IsZero, LayoutId, MainThread, MainThreadOnly, MonochromeSprite, + MouseMoveEvent, Path, Pixels, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, + Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, + SharedString, Size, Style, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, + WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::Result; use collections::HashMap; @@ -51,7 +51,8 @@ pub struct Window { content_size: Size, layout_engine: TaffyLayoutEngine, pub(crate) root_view: Option>, - current_stacking_order: StackingOrder, + pub(crate) element_id_stack: GlobalElementId, + z_index_stack: StackingOrder, content_mask_stack: Vec>, mouse_event_handlers: HashMap>, propagate_event: bool, @@ -112,7 +113,8 @@ impl Window { content_size, layout_engine: TaffyLayoutEngine::new(), root_view: None, - current_stacking_order: StackingOrder(SmallVec::new()), + element_id_stack: GlobalElementId::default(), + z_index_stack: StackingOrder(SmallVec::new()), content_mask_stack: Vec::new(), mouse_event_handlers: HashMap::default(), propagate_event: true, @@ -287,7 +289,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { &mut self, handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + Send + Sync + 'static, ) { - let order = self.window.current_stacking_order.clone(); + let order = self.window.z_index_stack.clone(); self.window .mouse_event_handlers .entry(TypeId::of::()) @@ -305,9 +307,9 @@ impl<'a, 'w> WindowContext<'a, 'w> { } pub fn stack(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R { - self.window.current_stacking_order.push(order); + self.window.z_index_stack.push(order); let result = f(self); - self.window.current_stacking_order.pop(); + self.window.z_index_stack.pop(); result } @@ -325,7 +327,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { shadow_bounds.origin += shadow.offset; shadow_bounds.dilate(shadow.spread_radius); window.scene_builder.insert( - &window.current_stacking_order, + &window.z_index_stack, Shadow { order: 0, bounds: shadow_bounds.scale(scale_factor), @@ -351,7 +353,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { let window = &mut *self.window; window.scene_builder.insert( - &window.current_stacking_order, + &window.z_index_stack, Quad { order: 0, bounds: bounds.scale(scale_factor), @@ -372,7 +374,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { let window = &mut *self.window; window .scene_builder - .insert(&window.current_stacking_order, path.scale(scale_factor)); + .insert(&window.z_index_stack, path.scale(scale_factor)); } pub fn paint_underline( @@ -394,7 +396,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { let content_mask = self.content_mask(); let window = &mut *self.window; window.scene_builder.insert( - &window.current_stacking_order, + &window.z_index_stack, Underline { order: 0, bounds: bounds.scale(scale_factor), @@ -446,7 +448,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { let content_mask = self.content_mask().scale(scale_factor); let window = &mut *self.window; window.scene_builder.insert( - &window.current_stacking_order, + &window.z_index_stack, MonochromeSprite { order: 0, bounds, @@ -495,7 +497,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { let window = &mut *self.window; window.scene_builder.insert( - &window.current_stacking_order, + &window.z_index_stack, PolychromeSprite { order: 0, bounds, @@ -536,7 +538,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { let window = &mut *self.window; window.scene_builder.insert( - &window.current_stacking_order, + &window.z_index_stack, MonochromeSprite { order: 0, bounds, @@ -571,7 +573,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { let window = &mut *self.window; window.scene_builder.insert( - &window.current_stacking_order, + &window.z_index_stack, PolychromeSprite { order: 0, bounds, @@ -728,6 +730,17 @@ pub trait BorrowWindow: BorrowAppContext { fn window(&self) -> &Window; fn window_mut(&mut self) -> &mut Window; + fn with_element_id( + &mut self, + id: impl Into, + f: impl FnOnce(&mut Self) -> R, + ) -> R { + self.window_mut().element_id_stack.push(id.into()); + let result = f(self); + self.window_mut().element_id_stack.pop(); + result + } + fn with_content_mask( &mut self, mask: ContentMask, @@ -824,9 +837,9 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> { } pub fn stack(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R { - self.window.current_stacking_order.push(order); + self.window.z_index_stack.push(order); let result = f(self); - self.window.current_stacking_order.pop(); + self.window.z_index_stack.pop(); result } @@ -913,16 +926,6 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> { }) }); } - - pub(crate) fn erase_state(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R { - let entity_id = self.unit_entity.id; - let mut cx = ViewContext::mutable( - &mut *self.window_cx.app, - &mut *self.window_cx.window, - entity_id, - ); - f(&mut cx) - } } impl<'a, 'w, S> Context for ViewContext<'a, 'w, S> {