Detailed changes
@@ -23,10 +23,7 @@ use std::{
mem,
sync::{Arc, Weak},
};
-use util::{
- http::{self, HttpClient},
- ResultExt,
-};
+use util::http::{self, HttpClient};
#[derive(Clone)]
pub struct App(Arc<Mutex<AppContext>>);
@@ -169,9 +166,7 @@ impl AppContext {
.collect::<Vec<_>>();
for dirty_window_id in dirty_window_ids {
- self.update_window(dirty_window_id, |cx| cx.draw())
- .unwrap()
- .log_err();
+ self.update_window(dirty_window_id, |cx| cx.draw()).unwrap();
}
}
@@ -1,11 +1,10 @@
-use crate::{Bounds, Identified, LayoutId, Pixels, Point, Result, ViewContext};
+use crate::{BorrowWindow, Bounds, ElementId, Identified, LayoutId, Pixels, Point, ViewContext};
use derive_more::{Deref, DerefMut};
pub(crate) use smallvec::SmallVec;
-use util::arc_cow::ArcCow;
-pub trait Element: 'static {
- type State;
- type FrameState;
+pub trait Element: 'static + Send + Sync {
+ type ViewState: 'static + Send + Sync;
+ type ElementState: 'static + Send + Sync;
fn element_id(&self) -> Option<ElementId> {
None
@@ -13,17 +12,18 @@ pub trait Element: 'static {
fn layout(
&mut self,
- state: &mut Self::State,
- cx: &mut ViewContext<Self::State>,
- ) -> Result<(LayoutId, Self::FrameState)>;
+ state: &mut Self::ViewState,
+ element_state: Option<Self::ElementState>,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) -> (LayoutId, Self::ElementState);
fn paint(
&mut self,
bounds: Bounds<Pixels>,
- state: &mut Self::State,
- frame_state: &mut Self::FrameState,
- cx: &mut ViewContext<Self::State>,
- ) -> Result<()>;
+ state: &mut Self::ViewState,
+ element_state: &mut Self::ElementState,
+ cx: &mut ViewContext<Self::ViewState>,
+ );
fn id(self, id: ElementId) -> Identified<Self>
where
@@ -39,10 +39,7 @@ pub trait StatefulElement: Element {
}
}
-#[derive(Clone, Debug, Eq, PartialEq, Hash)]
-pub struct ElementId(ArcCow<'static, [u8]>);
-
-#[derive(Deref, DerefMut, Default, Clone, Debug)]
+#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
pub trait ParentElement {
@@ -68,19 +65,14 @@ pub trait ParentElement {
}
}
-trait ElementObject<S> {
- fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
- fn paint(
- &mut self,
- state: &mut S,
- offset: Option<Point<Pixels>>,
- cx: &mut ViewContext<S>,
- ) -> Result<()>;
+trait ElementObject<S>: 'static + Send + Sync {
+ fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId;
+ fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>);
}
struct RenderedElement<E: Element> {
element: E,
- phase: ElementRenderPhase<E::FrameState>,
+ phase: ElementRenderPhase<E::ElementState>,
}
#[derive(Default)]
@@ -89,15 +81,15 @@ enum ElementRenderPhase<S> {
Rendered,
LayoutRequested {
layout_id: LayoutId,
- frame_state: S,
+ frame_state: Option<S>,
},
Painted {
bounds: Bounds<Pixels>,
- frame_state: S,
+ frame_state: Option<S>,
},
}
-/// Internal struct that wraps an element to store Layout and FrameState after the element is rendered.
+/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
/// improved usability.
impl<E: Element> RenderedElement<E> {
@@ -107,24 +99,58 @@ impl<E: Element> RenderedElement<E> {
phase: ElementRenderPhase::Rendered,
}
}
+
+ fn paint_with_element_state(
+ &mut self,
+ bounds: Bounds<Pixels>,
+ view_state: &mut E::ViewState,
+ frame_state: &mut Option<E::ElementState>,
+ cx: &mut ViewContext<E::ViewState>,
+ ) {
+ if let Some(id) = self.element.element_id() {
+ cx.with_element_state(id, |element_state, cx| {
+ let mut element_state = element_state.unwrap();
+ self.element
+ .paint(bounds, view_state, &mut element_state, cx);
+ ((), element_state)
+ });
+ } else {
+ self.element
+ .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
+ }
+ }
}
-impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
- fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
- let (layout_id, frame_state) = self.element.layout(state, cx)?;
+impl<E, S> ElementObject<E::ViewState> for RenderedElement<E>
+where
+ E: Element<ElementState = S>,
+ S: 'static + Send + Sync,
+{
+ fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
+ let (layout_id, frame_state) = if let Some(id) = self.element.element_id() {
+ let layout_id = cx.with_element_state(id, |element_state, cx| {
+ self.element.layout(state, element_state, cx)
+ });
+ (layout_id, None)
+ } else {
+ let (layout_id, frame_state) = self.element.layout(state, None, cx);
+ (layout_id, Some(frame_state))
+ };
+
self.phase = ElementRenderPhase::LayoutRequested {
layout_id,
frame_state,
};
- Ok(layout_id)
+
+ layout_id
}
fn paint(
&mut self,
- state: &mut E::State,
+ view_state: &mut E::ViewState,
offset: Option<Point<Pixels>>,
- cx: &mut ViewContext<E::State>,
- ) -> Result<()> {
+ cx: &mut ViewContext<E::ViewState>,
+ ) {
self.phase = match std::mem::take(&mut self.phase) {
ElementRenderPhase::Rendered => panic!("must call layout before paint"),
@@ -132,9 +158,9 @@ impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
layout_id,
mut frame_state,
} => {
- let mut bounds = cx.layout_bounds(layout_id)?.clone();
+ let mut bounds = cx.layout_bounds(layout_id);
offset.map(|offset| bounds.origin += offset);
- self.element.paint(bounds, state, &mut frame_state, cx)?;
+ self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
ElementRenderPhase::Painted {
bounds,
frame_state,
@@ -145,32 +171,24 @@ impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
bounds,
mut frame_state,
} => {
- self.element
- .paint(bounds.clone(), state, &mut frame_state, cx)?;
+ self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
ElementRenderPhase::Painted {
bounds,
frame_state,
}
}
};
-
- Ok(())
}
}
pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
-impl<S> AnyElement<S> {
- pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
+impl<S: 'static + Send + Sync> AnyElement<S> {
+ pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId {
self.0.layout(state, cx)
}
- pub fn paint(
- &mut self,
- state: &mut S,
- offset: Option<Point<Pixels>>,
- cx: &mut ViewContext<S>,
- ) -> Result<()> {
+ pub fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>) {
self.0.paint(state, offset, cx)
}
}
@@ -179,8 +197,8 @@ pub trait IntoAnyElement<S> {
fn into_any(self) -> AnyElement<S>;
}
-impl<E: Element> IntoAnyElement<E::State> for E {
- fn into_any(self) -> AnyElement<E::State> {
+impl<E: Element> IntoAnyElement<E::ViewState> for E {
+ fn into_any(self) -> AnyElement<E::ViewState> {
AnyElement(Box::new(RenderedElement::new(self)))
}
}
@@ -1,12 +1,10 @@
use crate::{
AnyElement, Bounds, Element, Interactive, LayoutId, MouseEventListeners, Overflow,
- ParentElement, Pixels, Point, Refineable, RefinementCascade, Result, Style, Styled,
- ViewContext,
+ ParentElement, Pixels, Point, Refineable, RefinementCascade, Style, Styled, ViewContext,
};
use parking_lot::Mutex;
use smallvec::SmallVec;
use std::sync::Arc;
-use util::ResultExt;
pub struct Div<S: 'static> {
styles: RefinementCascade<Style>,
@@ -25,27 +23,28 @@ pub fn div<S>() -> Div<S> {
}
impl<S: 'static + Send + Sync> Element for Div<S> {
- type State = S;
- type FrameState = Vec<LayoutId>;
+ type ViewState = S;
+ type ElementState = Vec<LayoutId>;
fn layout(
&mut self,
view: &mut S,
+ _: Option<Self::ElementState>,
cx: &mut ViewContext<S>,
- ) -> Result<(LayoutId, Self::FrameState)> {
+ ) -> (LayoutId, Self::ElementState) {
let style = self.computed_style();
- let child_layout_ids = style.apply_text_style(cx, |cx| self.layout_children(view, cx))?;
- let layout_id = cx.request_layout(style.into(), child_layout_ids.clone())?;
- Ok((layout_id, child_layout_ids))
+ let child_layout_ids = style.apply_text_style(cx, |cx| self.layout_children(view, cx));
+ let layout_id = cx.request_layout(style.into(), child_layout_ids.clone());
+ (layout_id, child_layout_ids)
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
state: &mut S,
- child_layout_ids: &mut Self::FrameState,
+ child_layout_ids: &mut Self::ElementState,
cx: &mut ViewContext<S>,
- ) -> Result<()> {
+ ) {
let style = self.computed_style();
cx.stack(0, |cx| style.paint(bounds, cx));
@@ -57,7 +56,7 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
self.paint_children(overflow, state, cx)
})
})
- })?;
+ });
self.handle_scroll(bounds, style.overflow.clone(), child_layout_ids, cx);
// todo!("enable inspector")
@@ -65,12 +64,10 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
// self.paint_inspector(parent_origin, layout, cx);
// }
//
-
- Ok(())
}
}
-impl<S: 'static> Div<S> {
+impl<S: 'static + Send + Sync> Div<S> {
pub fn overflow_hidden(mut self) -> Self {
self.declared_style().overflow.x = Some(Overflow::Hidden);
self.declared_style().overflow.y = Some(Overflow::Hidden);
@@ -118,11 +115,11 @@ impl<S: 'static> Div<S> {
offset
}
- fn layout_children(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> Result<Vec<LayoutId>> {
+ fn layout_children(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> Vec<LayoutId> {
self.children
.iter_mut()
.map(|child| child.layout(view, cx))
- .collect::<Result<Vec<LayoutId>>>()
+ .collect()
}
fn paint_children(
@@ -130,12 +127,11 @@ impl<S: 'static> Div<S> {
overflow: &Point<Overflow>,
state: &mut S,
cx: &mut ViewContext<S>,
- ) -> Result<()> {
+ ) {
let scroll_offset = self.scroll_offset(overflow);
for child in &mut self.children {
- child.paint(state, Some(scroll_offset), cx)?;
+ child.paint(state, Some(scroll_offset), cx);
}
- Ok(())
}
fn handle_scroll(
@@ -148,9 +144,8 @@ impl<S: 'static> Div<S> {
if overflow.y == Overflow::Scroll || overflow.x == Overflow::Scroll {
let mut scroll_max = Point::default();
for child_layout_id in child_layout_ids {
- if let Some(child_bounds) = cx.layout_bounds(*child_layout_id).log_err() {
- scroll_max = scroll_max.max(&child_bounds.lower_right());
- }
+ let child_bounds = cx.layout_bounds(*child_layout_id);
+ scroll_max = scroll_max.max(&child_bounds.lower_right());
}
scroll_max -= bounds.size;
@@ -237,7 +232,7 @@ impl<S: 'static> Div<S> {
//
}
-impl<V> Styled for Div<V> {
+impl<V: 'static + Send + Sync> Styled for Div<V> {
type Style = Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
@@ -2,7 +2,6 @@ use crate::{
AnyElement, Bounds, DispatchPhase, Element, ElementId, Interactive, MouseEventListeners,
MouseMoveEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
};
-use anyhow::Result;
use refineable::{CascadeSlot, Refineable, RefinementCascade};
use smallvec::SmallVec;
use std::sync::{
@@ -10,7 +9,10 @@ use std::sync::{
Arc,
};
-pub struct Hoverable<E: Styled> {
+pub struct Hoverable<E: Styled>
+// where
+// <E::Style as Refineable>::Refinement: 'static + Send + Sync,
+{
hovered: Arc<AtomicBool>,
cascade_slot: CascadeSlot,
hovered_style: <E::Style as Refineable>::Refinement,
@@ -49,9 +51,14 @@ impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Ho
}
}
-impl<E: Element + Styled> Element for Hoverable<E> {
- type State = E::State;
- type FrameState = E::FrameState;
+impl<E> Element for Hoverable<E>
+where
+ E: Element + Styled,
+ <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
+ <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
+{
+ type ViewState = E::ViewState;
+ type ElementState = E::ElementState;
fn element_id(&self) -> Option<ElementId> {
self.child.element_id()
@@ -59,19 +66,20 @@ impl<E: Element + Styled> Element for Hoverable<E> {
fn layout(
&mut self,
- state: &mut Self::State,
- cx: &mut ViewContext<Self::State>,
- ) -> Result<(crate::LayoutId, Self::FrameState)> {
- Ok(self.child.layout(state, cx)?)
+ state: &mut Self::ViewState,
+ element_state: Option<Self::ElementState>,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) -> (crate::LayoutId, Self::ElementState) {
+ self.child.layout(state, element_state, cx)
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
- state: &mut Self::State,
- frame_state: &mut Self::FrameState,
- cx: &mut ViewContext<Self::State>,
- ) -> Result<()> {
+ state: &mut Self::ViewState,
+ element_state: &mut Self::ElementState,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) {
let hovered = bounds.contains_point(cx.mouse_position());
let slot = self.cascade_slot;
let style = hovered.then_some(self.hovered_style.clone());
@@ -79,7 +87,7 @@ impl<E: Element + Styled> Element for Hoverable<E> {
self.hovered.store(hovered, SeqCst);
let hovered = self.hovered.clone();
- cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
+ cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
if phase == DispatchPhase::Capture {
if bounds.contains_point(event.position) != hovered.load(SeqCst) {
cx.notify();
@@ -87,8 +95,7 @@ impl<E: Element + Styled> Element for Hoverable<E> {
}
});
- self.child.paint(bounds, state, frame_state, cx)?;
- Ok(())
+ self.child.paint(bounds, state, element_state, cx);
}
}
@@ -100,4 +107,10 @@ impl<E: ParentElement + Styled> ParentElement for Hoverable<E> {
}
}
-impl<E: StatefulElement + Styled> StatefulElement for Hoverable<E> {}
+impl<E> StatefulElement for Hoverable<E>
+where
+ E: StatefulElement + Styled,
+ <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
+ <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
+{
+}
@@ -1,5 +1,4 @@
use crate::{BorrowWindow, Bounds, Element, ElementId, LayoutId, StatefulElement, ViewContext};
-use anyhow::Result;
pub struct Identified<E> {
pub(crate) element: E,
@@ -7,8 +6,8 @@ pub struct Identified<E> {
}
impl<E: Element> Element for Identified<E> {
- type State = E::State;
- type FrameState = E::FrameState;
+ type ViewState = E::ViewState;
+ type ElementState = E::ElementState;
fn element_id(&self) -> Option<ElementId> {
Some(self.id.clone())
@@ -16,21 +15,22 @@ impl<E: Element> Element for Identified<E> {
fn layout(
&mut self,
- state: &mut Self::State,
- cx: &mut ViewContext<Self::State>,
- ) -> Result<(LayoutId, Self::FrameState)> {
- self.element.layout(state, cx)
+ state: &mut Self::ViewState,
+ element_state: Option<Self::ElementState>,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) -> (LayoutId, Self::ElementState) {
+ self.element.layout(state, element_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<()> {
+ state: &mut Self::ViewState,
+ element_state: &mut Self::ElementState,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) {
cx.with_element_id(self.id.clone(), |cx| {
- self.element.paint(bounds, state, frame_state, cx)
+ self.element.paint(bounds, state, element_state, cx)
})
}
}
@@ -1,6 +1,5 @@
use crate::{
- BorrowWindow, Bounds, Element, LayoutId, Pixels, Result, SharedString, Style, Styled,
- ViewContext,
+ BorrowWindow, Bounds, Element, LayoutId, Pixels, SharedString, Style, Styled, ViewContext,
};
use futures::FutureExt;
use refineable::RefinementCascade;
@@ -36,29 +35,30 @@ impl<S> Img<S> {
}
impl<S: Send + Sync + 'static> Element for Img<S> {
- type State = S;
- type FrameState = ();
+ type ViewState = S;
+ type ElementState = ();
fn layout(
&mut self,
- _: &mut Self::State,
- cx: &mut ViewContext<Self::State>,
- ) -> anyhow::Result<(LayoutId, Self::FrameState)>
+ _: &mut Self::ViewState,
+ _: Option<Self::ElementState>,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) -> (LayoutId, Self::ElementState)
where
Self: Sized,
{
let style = self.computed_style();
- let layout_id = cx.request_layout(style, [])?;
- Ok((layout_id, ()))
+ let layout_id = cx.request_layout(style, []);
+ (layout_id, ())
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
- _: &mut Self::State,
- _: &mut Self::FrameState,
- cx: &mut ViewContext<Self::State>,
- ) -> Result<()> {
+ _: &mut Self::ViewState,
+ _: &mut Self::ElementState,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) {
let style = self.computed_style();
style.paint(bounds, cx);
@@ -73,7 +73,8 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
cx.stack(1, |cx| {
cx.paint_image(bounds, corner_radii, data, self.grayscale)
- })?;
+ .log_err()
+ });
} else {
cx.spawn(|_, mut cx| async move {
if image_future.await.log_err().is_some() {
@@ -83,7 +84,6 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
.detach()
}
}
- Ok(())
}
}
@@ -1,211 +1,237 @@
+use crate::{
+ AnyElement, Bounds, DispatchPhase, Element, Interactive, MouseDownEvent, MouseEventListeners,
+ MouseUpEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
+};
+use refineable::{CascadeSlot, Refineable, RefinementCascade};
+use smallvec::SmallVec;
+use std::sync::{
+ atomic::{AtomicBool, Ordering::SeqCst},
+ Arc,
+};
+
+pub struct Pressable<E: Styled> {
+ cascade_slot: CascadeSlot,
+ pressed_style: <E::Style as Refineable>::Refinement,
+ child: E,
+}
+
+pub struct PressableState<S> {
+ pressed: Arc<AtomicBool>,
+ child_state: S,
+}
+
+impl<E: Styled> Pressable<E> {
+ pub fn new(mut child: E) -> Self {
+ Self {
+ 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 for Pressable<E>
+where
+ E: Styled + StatefulElement,
+ <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
+ <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
+{
+ type ViewState = E::ViewState;
+ type ElementState = PressableState<E::ElementState>;
+
+ fn layout(
+ &mut self,
+ state: &mut Self::ViewState,
+ element_state: Option<Self::ElementState>,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) -> (crate::LayoutId, Self::ElementState) {
+ if let Some(element_state) = element_state {
+ let (id, child_state) = self
+ .child
+ .layout(state, Some(element_state.child_state), cx);
+ let element_state = PressableState {
+ pressed: element_state.pressed,
+ child_state,
+ };
+ (id, element_state)
+ } else {
+ let (id, child_state) = self.child.layout(state, None, cx);
+ let element_state = PressableState {
+ pressed: Default::default(),
+ child_state,
+ };
+ (id, element_state)
+ }
+ }
+
+ fn paint(
+ &mut self,
+ bounds: Bounds<Pixels>,
+ state: &mut Self::ViewState,
+ element_state: &mut Self::ElementState,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) {
+ let slot = self.cascade_slot;
+ let style = element_state
+ .pressed
+ .load(SeqCst)
+ .then_some(self.pressed_style.clone());
+ self.style_cascade().set(slot, style);
+
+ let pressed = element_state.pressed.clone();
+ cx.on_mouse_event(move |_, event: &MouseDownEvent, phase, cx| {
+ if phase == DispatchPhase::Capture {
+ if bounds.contains_point(event.position) != pressed.load(SeqCst) {
+ cx.notify();
+ }
+ }
+ });
+ let hovered = element_state.pressed.clone();
+ 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, &mut element_state.child_state, cx);
+ }
+}
+
+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::{
-// AnyElement, Bounds, DispatchPhase, Element, Identified, Interactive, MouseDownEvent,
-// MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext,
+// 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::sync::{
-// atomic::{AtomicBool, Ordering::SeqCst},
-// Arc,
-// };
+// use std::{cell::Cell, rc::Rc};
-// pub struct Pressable<E: Styled> {
-// pressed: Arc<AtomicBool>,
-// cascade_slot: CascadeSlot,
+// pub struct Pressable<E: Styleable> {
+// pressed: Rc<Cell<bool>>,
// pressed_style: <E::Style as Refineable>::Refinement,
+// cascade_slot: CascadeSlot,
// 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,
-// }
+// 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> Styled for Pressable<E>
-// where
-// E: Styled,
-// {
+// impl<E: Styleable> Styleable for Pressable<E> {
// 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 {
+// fn declared_style(&mut self) -> &mut <Self::Style as 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()
+// fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
+// self.child.style_cascade()
// }
// }
-// impl<E: Element + Identified + Styled> Element for Pressable<E> {
-// type State = E::State;
-// type FrameState = E::FrameState;
+// impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
+// type PaintState = E::PaintState;
// fn layout(
// &mut self,
-// state: &mut Self::State,
-// cx: &mut ViewContext<Self::State>,
-// ) -> Result<(crate::LayoutId, Self::FrameState)> {
-// Ok(self.child.layout(state, cx)?)
+// view: &mut V,
+// cx: &mut ViewContext<V>,
+// ) -> Result<(LayoutId, Self::PaintState)>
+// where
+// Self: Sized,
+// {
+// self.child.layout(view, 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());
+// 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 = pressed.then_some(self.pressed_style.clone());
+// let style = self.pressed.get().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();
+// 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(bounds, state, frame_state, cx)?;
-// Ok(())
+// self.child
+// .paint(view, parent_origin, layout, paint_state, cx);
// }
// }
-// impl<E: ParentElement + Styled> ParentElement for Pressable<E> {
-// type State = E::State;
+// impl<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Pressable<E> {
+// fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
+// self.child.interaction_handlers()
+// }
+// }
-// fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
+// 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()
// }
// }
-// // 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
-// // }
-// // }
+// impl<V: 'static, E: Element<V> + Styleable> IntoElement<V> for Pressable<E> {
+// type Element = Self;
+
+// fn into_element(self) -> Self::Element {
+// self
+// }
+// }
@@ -1,6 +1,7 @@
-use crate::{Bounds, Element, LayoutId, Pixels, Result, SharedString, Style, Styled};
+use crate::{Bounds, Element, LayoutId, Pixels, SharedString, Style, Styled};
use refineable::RefinementCascade;
use std::marker::PhantomData;
+use util::ResultExt;
pub struct Svg<S> {
path: Option<SharedString>,
@@ -23,41 +24,40 @@ impl<S> Svg<S> {
}
}
-impl<S: 'static> Element for Svg<S> {
- type State = S;
- type FrameState = ();
+impl<S: 'static + Send + Sync> Element for Svg<S> {
+ type ViewState = S;
+ type ElementState = ();
fn layout(
&mut self,
_: &mut S,
+ _: Option<Self::ElementState>,
cx: &mut crate::ViewContext<S>,
- ) -> anyhow::Result<(LayoutId, Self::FrameState)>
+ ) -> (LayoutId, Self::ElementState)
where
Self: Sized,
{
let style = self.computed_style();
- Ok((cx.request_layout(style, [])?, ()))
+ (cx.request_layout(style, []), ())
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
- _: &mut Self::State,
- _: &mut Self::FrameState,
+ _: &mut Self::ViewState,
+ _: &mut Self::ElementState,
cx: &mut crate::ViewContext<S>,
- ) -> Result<()>
- where
+ ) where
Self: Sized,
{
let fill_color = self.computed_style().fill.and_then(|fill| fill.color());
if let Some((path, fill_color)) = self.path.as_ref().zip(fill_color) {
- cx.paint_svg(bounds, path.clone(), fill_color)?;
+ cx.paint_svg(bounds, path.clone(), fill_color).log_err();
}
- Ok(())
}
}
-impl<S> Styled for Svg<S> {
+impl<S: 'static + Send + Sync> Styled for Svg<S> {
type Style = Style;
fn style_cascade(&mut self) -> &mut refineable::RefinementCascade<Self::Style> {
@@ -1,11 +1,11 @@
use crate::{
- AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, Result, Size, ViewContext,
+ AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, Size, ViewContext,
};
use parking_lot::Mutex;
use std::{marker::PhantomData, sync::Arc};
use util::{arc_cow::ArcCow, ResultExt};
-impl<S: 'static> IntoAnyElement<S> for ArcCow<'static, str> {
+impl<S: 'static + Send + Sync> IntoAnyElement<S> for ArcCow<'static, str> {
fn into_any(self) -> AnyElement<S> {
Text {
text: self,
@@ -15,7 +15,7 @@ impl<S: 'static> IntoAnyElement<S> for ArcCow<'static, str> {
}
}
-impl<V: 'static> IntoAnyElement<V> for &'static str {
+impl<V: 'static + Send + Sync> IntoAnyElement<V> for &'static str {
fn into_any(self) -> AnyElement<V> {
Text {
text: ArcCow::from(self),
@@ -30,15 +30,16 @@ pub struct Text<S> {
state_type: PhantomData<S>,
}
-impl<S: 'static> Element for Text<S> {
- type State = S;
- type FrameState = Arc<Mutex<Option<TextFrameState>>>;
+impl<S: 'static + Send + Sync> Element for Text<S> {
+ type ViewState = S;
+ type ElementState = Arc<Mutex<Option<TextElementState>>>;
fn layout(
&mut self,
_view: &mut S,
+ _element_state: Option<Self::ElementState>,
cx: &mut ViewContext<S>,
- ) -> Result<(LayoutId, Self::FrameState)> {
+ ) -> (LayoutId, Self::ElementState) {
let text_system = cx.text_system().clone();
let text_style = cx.text_style();
let font_size = text_style.font_size * cx.rem_size();
@@ -46,11 +47,11 @@ impl<S: 'static> Element for Text<S> {
.line_height
.to_pixels(font_size.into(), cx.rem_size());
let text = self.text.clone();
- let frame_state = Arc::new(Mutex::new(None));
+ let element_state = Arc::new(Mutex::new(None));
let rem_size = cx.rem_size();
let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
- let frame_state = frame_state.clone();
+ let element_state = element_state.clone();
move |_, _| {
let Some(line_layout) = text_system
.layout_line(
@@ -68,7 +69,7 @@ impl<S: 'static> Element for Text<S> {
height: line_height,
};
- frame_state.lock().replace(TextFrameState {
+ element_state.lock().replace(TextElementState {
line: Arc::new(line_layout),
line_height,
});
@@ -77,35 +78,32 @@ impl<S: 'static> Element for Text<S> {
}
});
- Ok((layout_id?, frame_state))
+ (layout_id, element_state)
}
fn paint<'a>(
&mut self,
bounds: Bounds<Pixels>,
- _: &mut Self::State,
- frame_state: &mut Self::FrameState,
+ _: &mut Self::ViewState,
+ element_state: &mut Self::ElementState,
cx: &mut ViewContext<S>,
- ) -> Result<()> {
+ ) {
let line;
let line_height;
{
- let frame_state = frame_state.lock();
- let frame_state = frame_state
+ let element_state = element_state.lock();
+ let element_state = element_state
.as_ref()
.expect("measurement has not been performed");
- line = frame_state.line.clone();
- line_height = frame_state.line_height;
+ line = element_state.line.clone();
+ line_height = element_state.line_height;
}
- // todo!("We haven't added visible bounds to the new element system yet, so this is a placeholder.");
- line.paint(bounds, bounds, line_height, cx)?;
-
- Ok(())
+ line.paint(bounds, bounds, line_height, cx).log_err();
}
}
-pub struct TextFrameState {
+pub struct TextElementState {
line: Arc<Line>,
line_height: Pixels,
}
@@ -50,12 +50,15 @@ pub use view::*;
pub use window::*;
use std::{
+ any::Any,
mem,
ops::{Deref, DerefMut},
sync::Arc,
};
use taffy::TaffyLayoutEngine;
+type AnyBox = Box<dyn Any + Send + Sync + 'static>;
+
pub trait Context {
type EntityContext<'a, 'w, T: 'static + Send + Sync>;
type Result<T>;
@@ -1,7 +1,7 @@
use crate::{Hoverable, Refineable, RefinementCascade};
pub trait Styled {
- type Style: Refineable + Default;
+ type Style: 'static + Refineable + Send + Sync + Default;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style>;
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
@@ -12,7 +12,9 @@ pub trait Styled {
fn hover(self) -> Hoverable<Self>
where
- Self: Sized,
+ Self: 'static + Sized + Send + Sync,
+ Self::Style: 'static + Refineable + Default + Send + Sync,
+ <Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
{
Hoverable::new(self)
}
@@ -1,6 +1,4 @@
-use super::{
- AbsoluteLength, Bounds, DefiniteLength, Edges, Length, Pixels, Point, Result, Size, Style,
-};
+use super::{AbsoluteLength, Bounds, DefiniteLength, Edges, Length, Pixels, Point, Size, Style};
use collections::HashMap;
use std::fmt::Debug;
use taffy::{
@@ -16,6 +14,9 @@ pub struct TaffyLayoutEngine {
absolute_layout_bounds: HashMap<LayoutId, Bounds<Pixels>>,
}
+static EXPECT_MESSAGE: &'static str =
+ "we should avoid taffy layout errors by construction if possible";
+
impl TaffyLayoutEngine {
pub fn new() -> Self {
TaffyLayoutEngine {
@@ -30,20 +31,21 @@ impl TaffyLayoutEngine {
style: Style,
rem_size: Pixels,
children: &[LayoutId],
- ) -> Result<LayoutId> {
+ ) -> LayoutId {
let style = style.to_taffy(rem_size);
if children.is_empty() {
- Ok(self.taffy.new_leaf(style)?.into())
+ self.taffy.new_leaf(style).expect(EXPECT_MESSAGE).into()
} else {
let parent_id = self
.taffy
// This is safe because LayoutId is repr(transparent) to taffy::tree::NodeId.
- .new_with_children(style, unsafe { std::mem::transmute(children) })?
+ .new_with_children(style, unsafe { std::mem::transmute(children) })
+ .expect(EXPECT_MESSAGE)
.into();
for child_id in children {
self.children_to_parents.insert(*child_id, parent_id);
}
- Ok(parent_id)
+ parent_id
}
}
@@ -55,44 +57,40 @@ impl TaffyLayoutEngine {
+ Send
+ Sync
+ 'static,
- ) -> Result<LayoutId> {
+ ) -> LayoutId {
let style = style.to_taffy(rem_size);
let measurable = Box::new(Measureable(measure)) as Box<dyn Measurable>;
- Ok(self
- .taffy
- .new_leaf_with_measure(style, MeasureFunc::Boxed(measurable))?
- .into())
+ self.taffy
+ .new_leaf_with_measure(style, MeasureFunc::Boxed(measurable))
+ .expect(EXPECT_MESSAGE)
+ .into()
}
- pub fn compute_layout(
- &mut self,
- id: LayoutId,
- available_space: Size<AvailableSpace>,
- ) -> Result<()> {
+ pub fn compute_layout(&mut self, id: LayoutId, available_space: Size<AvailableSpace>) {
self.taffy
- .compute_layout(id.into(), available_space.into())?;
- Ok(())
+ .compute_layout(id.into(), available_space.into())
+ .expect(EXPECT_MESSAGE);
}
- pub fn layout_bounds(&mut self, id: LayoutId) -> Result<Bounds<Pixels>> {
+ pub fn layout_bounds(&mut self, id: LayoutId) -> Bounds<Pixels> {
if let Some(layout) = self.absolute_layout_bounds.get(&id).cloned() {
- return Ok(layout);
+ return layout;
}
- let layout = self.taffy.layout(id.into())?;
+ let layout = self.taffy.layout(id.into()).expect(EXPECT_MESSAGE);
let mut bounds = Bounds {
origin: layout.location.into(),
size: layout.size.into(),
};
if let Some(parent_id) = self.children_to_parents.get(&id).copied() {
- let parent_bounds = self.layout_bounds(parent_id)?;
+ let parent_bounds = self.layout_bounds(parent_id);
bounds.origin += parent_bounds.origin;
}
self.absolute_layout_bounds.insert(id, bounds);
- Ok(bounds)
+ bounds
}
}
@@ -1,7 +1,7 @@
use parking_lot::Mutex;
use crate::{
- AnyElement, Bounds, Element, Handle, IntoAnyElement, LayoutId, Pixels, Result, ViewContext,
+ AnyBox, AnyElement, Bounds, Element, Handle, IntoAnyElement, LayoutId, Pixels, ViewContext,
WindowContext,
};
use std::{any::Any, marker::PhantomData, sync::Arc};
@@ -40,7 +40,7 @@ pub fn view<S, P, E>(
where
S: 'static + Send + Sync,
P: 'static,
- E: Element<State = S>,
+ E: Element<ViewState = S>,
{
View {
state,
@@ -49,64 +49,55 @@ where
}
}
-impl<S: Send + Sync + 'static, P: Send + 'static> Element for View<S, P> {
- type State = P;
- type FrameState = AnyElement<S>;
+impl<S: 'static + Send + Sync, P: 'static + Send + Sync> Element for View<S, P> {
+ type ViewState = P;
+ type ElementState = AnyElement<S>;
fn layout(
&mut self,
- _: &mut Self::State,
- cx: &mut ViewContext<Self::State>,
- ) -> Result<(LayoutId, Self::FrameState)> {
+ _: &mut Self::ViewState,
+ _: Option<Self::ElementState>,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) -> (LayoutId, Self::ElementState) {
self.state.update(cx, |state, cx| {
let mut element = (self.render)(state, cx);
- let layout_id = element.layout(state, cx)?;
- Ok((layout_id, element))
+ let layout_id = element.layout(state, cx);
+ (layout_id, element)
})
}
fn paint(
&mut self,
_: Bounds<Pixels>,
- _: &mut Self::State,
- element: &mut Self::FrameState,
- cx: &mut ViewContext<Self::State>,
- ) -> Result<()> {
+ _: &mut Self::ViewState,
+ element: &mut Self::ElementState,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) {
self.state
.update(cx, |state, cx| element.paint(state, None, cx))
}
}
trait ViewObject: Send + 'static {
- fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)>;
- fn paint(
- &mut self,
- bounds: Bounds<Pixels>,
- element: &mut dyn Any,
- cx: &mut WindowContext,
- ) -> Result<()>;
+ fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox);
+ fn paint(&mut self, bounds: Bounds<Pixels>, element: &mut dyn Any, cx: &mut WindowContext);
}
impl<S: Send + Sync + 'static, P: Send + 'static> ViewObject for View<S, P> {
- fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)> {
+ fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) {
self.state.update(cx, |state, cx| {
let mut element = (self.render)(state, cx);
- let layout_id = element.layout(state, cx)?;
- let element = Box::new(element) as Box<dyn Any>;
- Ok((layout_id, element))
+ let layout_id = element.layout(state, cx);
+ let element = Box::new(element) as AnyBox;
+ (layout_id, element)
})
}
- fn paint(
- &mut self,
- _: Bounds<Pixels>,
- element: &mut dyn Any,
- cx: &mut WindowContext,
- ) -> Result<()> {
+ fn paint(&mut self, _: Bounds<Pixels>, element: &mut dyn Any, cx: &mut WindowContext) {
self.state.update(cx, |state, cx| {
let element = element.downcast_mut::<AnyElement<S>>().unwrap();
- element.paint(state, None, cx)
- })
+ element.paint(state, None, cx);
+ });
}
}
@@ -115,15 +106,16 @@ pub struct AnyView<S> {
parent_state_type: PhantomData<S>,
}
-impl<S: 'static> Element for AnyView<S> {
- type State = ();
- type FrameState = Box<dyn Any>;
+impl<S: 'static + Send + Sync> Element for AnyView<S> {
+ type ViewState = ();
+ type ElementState = AnyBox;
fn layout(
&mut self,
- _: &mut Self::State,
- cx: &mut ViewContext<Self::State>,
- ) -> Result<(LayoutId, Self::FrameState)> {
+ _: &mut Self::ViewState,
+ _: Option<Self::ElementState>,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) -> (LayoutId, Self::ElementState) {
self.view.lock().layout(cx)
}
@@ -131,9 +123,9 @@ impl<S: 'static> Element for AnyView<S> {
&mut self,
bounds: Bounds<Pixels>,
_: &mut (),
- element: &mut Box<dyn Any>,
- cx: &mut ViewContext<Self::State>,
- ) -> Result<()> {
+ element: &mut AnyBox,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) {
self.view.lock().paint(bounds, element.as_mut(), cx)
}
}
@@ -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, 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,
+ px, size, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace, BorrowAppContext,
+ Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, Edges, Effect, Element, EntityId,
+ Event, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, MainThread,
+ MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, PlatformAtlas, PlatformWindow,
+ Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams,
+ RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style,
+ TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions,
+ SUBPIXEL_VARIANTS,
};
use anyhow::Result;
use collections::HashMap;
@@ -21,7 +21,7 @@ use std::{
mem,
sync::Arc,
};
-use util::ResultExt;
+use util::{arc_cow::ArcCow, ResultExt};
#[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default)]
pub struct StackingOrder(pub(crate) SmallVec<[u32; 16]>);
@@ -52,6 +52,8 @@ pub struct Window {
layout_engine: TaffyLayoutEngine,
pub(crate) root_view: Option<AnyView<()>>,
pub(crate) element_id_stack: GlobalElementId,
+ prev_element_states: HashMap<GlobalElementId, AnyBox>,
+ element_states: HashMap<GlobalElementId, AnyBox>,
z_index_stack: StackingOrder,
content_mask_stack: Vec<ContentMask<Pixels>>,
mouse_event_handlers: HashMap<TypeId, Vec<(StackingOrder, MouseEventHandler)>>,
@@ -114,6 +116,8 @@ impl Window {
layout_engine: TaffyLayoutEngine::new(),
root_view: None,
element_id_stack: GlobalElementId::default(),
+ prev_element_states: HashMap::default(),
+ element_states: HashMap::default(),
z_index_stack: StackingOrder(SmallVec::new()),
content_mask_stack: Vec::new(),
mouse_event_handlers: HashMap::default(),
@@ -147,7 +151,7 @@ impl ContentMask<Pixels> {
pub struct WindowContext<'a, 'w> {
app: Reference<'a, AppContext>,
- window: Reference<'w, Window>,
+ pub(crate) window: Reference<'w, Window>,
}
impl<'a, 'w> WindowContext<'a, 'w> {
@@ -242,7 +246,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
&mut self,
style: Style,
children: impl IntoIterator<Item = LayoutId>,
- ) -> Result<LayoutId> {
+ ) -> LayoutId {
self.app.layout_id_buffer.clear();
self.app.layout_id_buffer.extend(children.into_iter());
let rem_size = self.rem_size();
@@ -259,18 +263,17 @@ impl<'a, 'w> WindowContext<'a, 'w> {
style: Style,
rem_size: Pixels,
measure: F,
- ) -> Result<LayoutId> {
+ ) -> LayoutId {
self.window
.layout_engine
.request_measured_layout(style, rem_size, measure)
}
- pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Result<Bounds<Pixels>> {
- Ok(self
- .window
+ pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
+ self.window
.layout_engine
.layout_bounds(layout_id)
- .map(Into::into)?)
+ .map(Into::into)
}
pub fn scale_factor(&self) -> f32 {
@@ -586,27 +589,25 @@ impl<'a, 'w> WindowContext<'a, 'w> {
Ok(())
}
- pub(crate) fn draw(&mut self) -> Result<()> {
+ pub(crate) fn draw(&mut self) {
let unit_entity = self.unit_entity.clone();
self.update_entity(&unit_entity, |view, cx| {
- cx.window
- .mouse_event_handlers
- .values_mut()
- .for_each(Vec::clear);
+ cx.start_frame();
let mut root_view = cx.window.root_view.take().unwrap();
- let (root_layout_id, mut frame_state) = root_view.layout(&mut (), cx)?;
- let available_space = cx.window.content_size.map(Into::into);
- cx.window
- .layout_engine
- .compute_layout(root_layout_id, available_space)?;
- let layout = cx.window.layout_engine.layout_bounds(root_layout_id)?;
+ if let Some(element_id) = root_view.element_id() {
+ cx.with_element_state(element_id, |element_state, cx| {
+ let element_state = draw_with_element_state(&mut root_view, element_state, cx);
+ ((), element_state)
+ });
+ } else {
+ draw_with_element_state(&mut root_view, None, cx);
+ };
- root_view.paint(layout, &mut (), &mut frame_state, cx)?;
cx.window.root_view = Some(root_view);
- let scene = cx.window.scene_builder.build();
+ let scene = cx.window.scene_builder.build();
cx.run_on_main(view, |_, cx| {
cx.window
.platform_window
@@ -615,9 +616,38 @@ impl<'a, 'w> WindowContext<'a, 'w> {
cx.window.dirty = false;
})
.detach();
+ });
- Ok(())
- })
+ fn draw_with_element_state(
+ root_view: &mut AnyView<()>,
+ element_state: Option<AnyBox>,
+ cx: &mut ViewContext<()>,
+ ) -> AnyBox {
+ let (layout_id, mut element_state) = root_view.layout(&mut (), element_state, cx);
+ let available_space = cx.window.content_size.map(Into::into);
+ cx.window
+ .layout_engine
+ .compute_layout(layout_id, available_space);
+ let bounds = cx.window.layout_engine.layout_bounds(layout_id);
+ root_view.paint(bounds, &mut (), &mut element_state, cx);
+ element_state
+ }
+ }
+
+ fn start_frame(&mut self) {
+ // Make the current element states the previous, and then clear the current.
+ // The empty element states map will be populated for any element states we
+ // reference during the upcoming frame.
+ let window = &mut *self.window;
+ mem::swap(&mut window.element_states, &mut window.prev_element_states);
+ self.window.element_states.clear();
+
+ // Clear mouse event listeners, because elements add new element listeners
+ // when the upcoming frame is painted.
+ self.window
+ .mouse_event_handlers
+ .values_mut()
+ .for_each(Vec::clear);
}
fn dispatch_event(&mut self, event: Event) -> bool {
@@ -753,6 +783,42 @@ pub trait BorrowWindow: BorrowAppContext {
result
}
+ fn with_element_state<S: 'static + Send + Sync, R>(
+ &mut self,
+ id: ElementId,
+ f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
+ ) -> R {
+ self.window_mut().element_id_stack.push(id);
+ let global_id = self.window_mut().element_id_stack.clone();
+
+ if let Some(any) = self
+ .window_mut()
+ .element_states
+ .remove(&global_id)
+ .or_else(|| self.window_mut().prev_element_states.remove(&global_id))
+ {
+ // Using the extra inner option to avoid needing to reallocate a new box.
+ let mut state_box = any
+ .downcast::<Option<S>>()
+ .expect("invalid element state type for id");
+ let state = state_box
+ .take()
+ .expect("element state is already on the stack");
+ let (result, state) = f(Some(state), self);
+ state_box.replace(state);
+ self.window_mut()
+ .element_states
+ .insert(global_id, state_box);
+ result
+ } else {
+ let (result, state) = f(None, self);
+ self.window_mut()
+ .element_states
+ .insert(global_id, Box::new(Some(state)));
+ result
+ }
+ }
+
fn content_mask(&self) -> ContentMask<Pixels> {
self.window()
.content_mask_stack
@@ -791,26 +857,6 @@ impl<S> BorrowAppContext for ViewContext<'_, '_, S> {
fn app_mut(&mut self) -> &mut AppContext {
&mut *self.window_cx.app
}
-
- fn with_text_style<F, R>(&mut self, style: crate::TextStyleRefinement, f: F) -> R
- where
- F: FnOnce(&mut Self) -> R,
- {
- self.window_cx.app.push_text_style(style);
- let result = f(self);
- self.window_cx.app.pop_text_style();
- result
- }
-
- fn with_state<T: Send + Sync + 'static, F, R>(&mut self, state: T, f: F) -> R
- where
- F: FnOnce(&mut Self) -> R,
- {
- self.window_cx.app.push_state(state);
- let result = f(self);
- self.window_cx.app.pop_state::<T>();
- result
- }
}
impl<S> BorrowWindow for ViewContext<'_, '_, S> {
@@ -1012,3 +1058,6 @@ impl From<SmallVec<[u32; 16]>> for StackingOrder {
StackingOrder(small_vec)
}
}
+
+#[derive(Clone, Debug, Eq, PartialEq, Hash)]
+pub struct ElementId(ArcCow<'static, [u8]>);
@@ -22,7 +22,7 @@ impl CollabPanel {
}
impl CollabPanel {
- fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<State = Self> {
+ fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<ViewState = Self> {
let theme = theme(cx);
// Panel
@@ -123,7 +123,7 @@ impl CollabPanel {
label: impl IntoAnyElement<Self>,
expanded: bool,
theme: &Theme,
- ) -> impl Element<State = Self> {
+ ) -> impl Element<ViewState = Self> {
div()
.h_7()
.px_2()
@@ -153,7 +153,7 @@ impl CollabPanel {
avatar_uri: impl Into<SharedString>,
label: impl IntoAnyElement<Self>,
theme: &Theme,
- ) -> impl Element<State = Self> {
+ ) -> impl Element<ViewState = Self> {
div()
.h_7()
.px_2()
@@ -129,10 +129,10 @@ where
deserializer.deserialize_map(SyntaxVisitor)
}
-pub fn themed<E, F>(theme: Theme, cx: &mut ViewContext<E::State>, build_child: F) -> Themed<E>
+pub fn themed<E, F>(theme: Theme, cx: &mut ViewContext<E::ViewState>, build_child: F) -> Themed<E>
where
E: Element,
- F: FnOnce(&mut ViewContext<E::State>) -> E,
+ F: FnOnce(&mut ViewContext<E::ViewState>) -> E,
{
let child = cx.with_state(theme.clone(), |cx| build_child(cx));
Themed { theme, child }
@@ -144,14 +144,14 @@ pub struct Themed<E> {
}
impl<E: Element> Element for Themed<E> {
- type State = E::State;
- type FrameState = E::FrameState;
+ type ViewState = E::ViewState;
+ type ElementState = E::ElementState;
fn layout(
&mut self,
- state: &mut E::State,
- cx: &mut ViewContext<E::State>,
- ) -> anyhow::Result<(LayoutId, Self::FrameState)>
+ state: &mut E::ViewState,
+ cx: &mut ViewContext<E::ViewState>,
+ ) -> anyhow::Result<(LayoutId, Self::ElementState)>
where
Self: Sized,
{
@@ -161,9 +161,9 @@ impl<E: Element> Element for Themed<E> {
fn paint(
&mut self,
bounds: Bounds<Pixels>,
- state: &mut Self::State,
- frame_state: &mut Self::FrameState,
- cx: &mut ViewContext<Self::State>,
+ state: &mut Self::ViewState,
+ frame_state: &mut Self::ElementState,
+ cx: &mut ViewContext<Self::ViewState>,
) -> Result<()>
where
Self: Sized,
@@ -25,7 +25,7 @@ impl Workspace {
}
}
- fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<State = Self> {
+ fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<ViewState = Self> {
themed(rose_pine_dawn(), cx, |cx| {
let theme = theme(cx);
div()
@@ -57,7 +57,7 @@ impl Workspace {
struct Titlebar;
-pub fn titlebar<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
+pub fn titlebar<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
let ref mut this = Titlebar;
let theme = theme(cx);
div()
@@ -75,7 +75,7 @@ impl Titlebar {
fn render<V: 'static + Send + Sync>(
&mut self,
cx: &mut ViewContext<V>,
- ) -> impl Element<State = V> {
+ ) -> impl Element<ViewState = V> {
let theme = theme(cx);
div()
.flex()
@@ -91,7 +91,7 @@ impl Titlebar {
fn left_group<S: 'static + Send + Sync>(
&mut self,
cx: &mut ViewContext<S>,
- ) -> impl Element<State = S> {
+ ) -> impl Element<ViewState = S> {
let theme = theme(cx);
div()
.flex()
@@ -174,7 +174,7 @@ impl Titlebar {
fn right_group<S: 'static + Send + Sync>(
&mut self,
cx: &mut ViewContext<S>,
- ) -> impl Element<State = S> {
+ ) -> impl Element<ViewState = S> {
let theme = theme(cx);
div()
.flex()
@@ -306,7 +306,9 @@ mod statusbar {
use super::*;
- pub fn statusbar<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ pub fn statusbar<S: 'static + Send + Sync>(
+ cx: &mut ViewContext<S>,
+ ) -> impl Element<ViewState = S> {
let theme = theme(cx);
div()
.flex()
@@ -319,7 +321,9 @@ mod statusbar {
// .child(right_group(cx))
}
- fn left_group<V: 'static + Send + Sync>(cx: &mut ViewContext<V>) -> impl Element<State = V> {
+ fn left_group<V: 'static + Send + Sync>(
+ cx: &mut ViewContext<V>,
+ ) -> impl Element<ViewState = V> {
let theme = theme(cx);
div()
.flex()
@@ -416,7 +420,9 @@ mod statusbar {
)
}
- fn right_group<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ fn right_group<S: 'static + Send + Sync>(
+ cx: &mut ViewContext<S>,
+ ) -> impl Element<ViewState = S> {
let theme = theme(cx);
div()
.flex()