crates/gpui3/src/arc_cow.rs 🔗
Marshall Bowers created
crates/gpui3/src/arc_cow.rs | 0
crates/gpui3/src/element.rs | 29 ++
crates/gpui3/src/elements.rs | 6
crates/gpui3/src/elements/hoverable.rs | 10
crates/gpui3/src/elements/identified.rs | 38 +++
crates/gpui3/src/elements/pressable.rs | 317 +++++++++++++++++---------
crates/gpui3/src/elements/stateless.rs | 30 --
crates/gpui3/src/gpui3.rs | 13
crates/gpui3/src/window.rs | 65 ++--
9 files changed, 328 insertions(+), 180 deletions(-)
@@ -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<ElementId> {
+ 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<Self::State>,
) -> Result<()>;
+
+ fn id(self, id: ElementId) -> Identified<Self>
+ 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;
@@ -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::*;
@@ -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<E: Element + Styled> Element for Hoverable<E> {
type State = E::State;
type FrameState = E::FrameState;
+ fn element_id(&self) -> Option<ElementId> {
+ self.child.element_id()
+ }
+
fn layout(
&mut self,
state: &mut Self::State,
@@ -95,3 +99,5 @@ impl<E: ParentElement + Styled> ParentElement for Hoverable<E> {
self.child.children_mut()
}
}
+
+impl<E: StatefulElement + Styled> StatefulElement for Hoverable<E> {}
@@ -0,0 +1,38 @@
+use crate::{BorrowWindow, Bounds, Element, ElementId, LayoutId, StatefulElement, ViewContext};
+use anyhow::Result;
+
+pub struct Identified<E> {
+ pub(crate) element: E,
+ pub(crate) id: ElementId,
+}
+
+impl<E: Element> Element for Identified<E> {
+ type State = E::State;
+ type FrameState = E::FrameState;
+
+ fn element_id(&self) -> Option<ElementId> {
+ Some(self.id.clone())
+ }
+
+ fn layout(
+ &mut self,
+ state: &mut Self::State,
+ cx: &mut ViewContext<Self::State>,
+ ) -> Result<(LayoutId, Self::FrameState)> {
+ self.element.layout(state, cx)
+ }
+
+ fn paint(
+ &mut self,
+ bounds: Bounds<crate::Pixels>,
+ state: &mut Self::State,
+ frame_state: &mut Self::FrameState,
+ cx: &mut ViewContext<Self::State>,
+ ) -> Result<()> {
+ cx.with_element_id(self.id.clone(), |cx| {
+ self.element.paint(bounds, state, frame_state, cx)
+ })
+ }
+}
+
+impl<E: Element> StatefulElement for Identified<E> {}
@@ -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<E: Styleable> {
- pressed: Rc<Cell<bool>>,
- pressed_style: <E::Style as Refineable>::Refinement,
- cascade_slot: CascadeSlot,
- child: E,
-}
-
-pub fn pressable<E: Styleable>(mut child: E) -> Pressable<E> {
- Pressable {
- pressed: Rc::new(Cell::new(false)),
- pressed_style: Default::default(),
- cascade_slot: child.style_cascade().reserve(),
- child,
- }
-}
-
-impl<E: Styleable> Styleable for Pressable<E> {
- type Style = E::Style;
-
- fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
- &mut self.pressed_style
- }
-
- fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
- self.child.style_cascade()
- }
-}
-
-impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
- type PaintState = E::PaintState;
-
- fn layout(
- &mut self,
- view: &mut V,
- cx: &mut ViewContext<V>,
- ) -> 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<V>,
- ) 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<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Pressable<E> {
- fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
- self.child.interaction_handlers()
- }
-}
-
-impl<V: 'static, E: ParentElement<V> + Styleable> ParentElement<V> for Pressable<E> {
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
- self.child.children_mut()
- }
-}
-
-impl<V: 'static, E: Element<V> + Styleable> IntoElement<V> for Pressable<E> {
- 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<E: Styled> {
+// pressed: Arc<AtomicBool>,
+// cascade_slot: CascadeSlot,
+// pressed_style: <E::Style as Refineable>::Refinement,
+// child: E,
+// }
+
+// impl<E: Identified + Styled> Pressable<E> {
+// 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<E> Styled for Pressable<E>
+// where
+// E: Styled,
+// {
+// type Style = E::Style;
+
+// fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
+// self.child.style_cascade()
+// }
+
+// fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
+// &mut self.pressed_style
+// }
+// }
+
+// impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Pressable<E> {
+// fn listeners(&mut self) -> &mut MouseEventListeners<S> {
+// self.child.listeners()
+// }
+// }
+
+// impl<E: Element + Identified + Styled> Element for Pressable<E> {
+// type State = E::State;
+// type FrameState = E::FrameState;
+
+// fn layout(
+// &mut self,
+// state: &mut Self::State,
+// cx: &mut ViewContext<Self::State>,
+// ) -> Result<(crate::LayoutId, Self::FrameState)> {
+// Ok(self.child.layout(state, cx)?)
+// }
+
+// fn paint(
+// &mut self,
+// bounds: Bounds<Pixels>,
+// state: &mut Self::State,
+// frame_state: &mut Self::FrameState,
+// cx: &mut ViewContext<Self::State>,
+// ) -> 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<E: ParentElement + Styled> ParentElement for Pressable<E> {
+// type State = E::State;
+
+// fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 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<E: Styleable> {
+// // pressed: Rc<Cell<bool>>,
+// // pressed_style: <E::Style as Refineable>::Refinement,
+// // cascade_slot: CascadeSlot,
+// // child: E,
+// // }
+
+// // pub fn pressable<E: Styleable>(mut child: E) -> Pressable<E> {
+// // Pressable {
+// // pressed: Rc::new(Cell::new(false)),
+// // pressed_style: Default::default(),
+// // cascade_slot: child.style_cascade().reserve(),
+// // child,
+// // }
+// // }
+
+// // impl<E: Styleable> Styleable for Pressable<E> {
+// // type Style = E::Style;
+
+// // fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
+// // &mut self.pressed_style
+// // }
+
+// // fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
+// // self.child.style_cascade()
+// // }
+// // }
+
+// // impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
+// // type PaintState = E::PaintState;
+
+// // fn layout(
+// // &mut self,
+// // view: &mut V,
+// // cx: &mut ViewContext<V>,
+// // ) -> 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<V>,
+// // ) 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<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Pressable<E> {
+// // fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
+// // self.child.interaction_handlers()
+// // }
+// // }
+
+// // impl<V: 'static, E: ParentElement<V> + Styleable> ParentElement<V> for Pressable<E> {
+// // fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+// // self.child.children_mut()
+// // }
+// // }
+
+// // impl<V: 'static, E: Element<V> + Styleable> IntoElement<V> for Pressable<E> {
+// // type Element = Self;
+
+// // fn into_element(self) -> Self::Element {
+// // self
+// // }
+// // }
@@ -1,30 +0,0 @@
-use crate::{Bounds, Element, Pixels};
-use std::marker::PhantomData;
-
-pub struct Stateless<E: Element<State = ()>, S> {
- element: E,
- parent_state_type: PhantomData<S>,
-}
-
-impl<E: Element<State = ()>, S: Send + Sync + 'static> Element for Stateless<E, S> {
- type State = S;
- type FrameState = E::FrameState;
-
- fn layout(
- &mut self,
- _: &mut Self::State,
- cx: &mut crate::ViewContext<Self::State>,
- ) -> anyhow::Result<(crate::LayoutId, Self::FrameState)> {
- cx.erase_state(|cx| self.element.layout(&mut (), cx))
- }
-
- fn paint(
- &mut self,
- bounds: Bounds<Pixels>,
- _: &mut Self::State,
- frame_state: &mut Self::FrameState,
- cx: &mut crate::ViewContext<Self::State>,
- ) -> anyhow::Result<()> {
- cx.erase_state(|cx| self.element.paint(bounds, &mut (), frame_state, cx))
- }
-}
@@ -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<T>;
@@ -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<Pixels>,
layout_engine: TaffyLayoutEngine,
pub(crate) root_view: Option<AnyView<()>>,
- current_stacking_order: StackingOrder,
+ pub(crate) element_id_stack: GlobalElementId,
+ z_index_stack: StackingOrder,
content_mask_stack: Vec<ContentMask<Pixels>>,
mouse_event_handlers: HashMap<TypeId, Vec<(StackingOrder, MouseEventHandler)>>,
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::<Event>())
@@ -305,9 +307,9 @@ impl<'a, 'w> WindowContext<'a, 'w> {
}
pub fn stack<R>(&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<R>(
+ &mut self,
+ id: impl Into<ElementId>,
+ 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<R>(
&mut self,
mask: ContentMask<Pixels>,
@@ -824,9 +837,9 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
}
pub fn stack<R>(&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<R>(&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> {