Detailed changes
@@ -1,9 +1,4 @@
-use std::sync::Arc;
-
-use crate::{
- BorrowWindow, Bounds, Clickable, ElementId, Group, LayoutId, MouseDownEvent, MouseUpEvent,
- Pixels, Point, SharedString, ViewContext,
-};
+use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, ViewContext};
use derive_more::{Deref, DerefMut};
pub(crate) use smallvec::SmallVec;
@@ -27,35 +22,12 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
element_state: &mut Self::ElementState,
cx: &mut ViewContext<Self::ViewState>,
);
-
- fn group(self, name: impl Into<SharedString>) -> Group<Self>
- where
- Self: Sized,
- {
- Group::new(name.into(), self)
- }
}
pub trait IdentifiedElement: Element {
- fn element_id(&self) -> ElementId {
+ fn id(&self) -> ElementId {
Element::id(self).unwrap()
}
-
- fn on_click(
- self,
- listener: impl Fn(
- &mut Self::ViewState,
- (&MouseDownEvent, &MouseUpEvent),
- &mut ViewContext<Self::ViewState>,
- ) + Send
- + Sync
- + 'static,
- ) -> Clickable<Self>
- where
- Self: Sized,
- {
- Clickable::new(self, Arc::from(listener))
- }
}
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
@@ -1,20 +1,15 @@
mod clickable;
mod div;
-mod group;
mod hoverable;
-mod identified;
mod img;
-mod nested;
-mod pressable;
+mod layout_node;
mod svg;
mod text;
pub use clickable::*;
pub use div::*;
-pub use group::*;
pub use hoverable::*;
-pub use identified::*;
pub use img::*;
-pub use pressable::*;
+pub use layout_node::*;
pub use svg::*;
pub use text::*;
@@ -1,71 +1,90 @@
use crate::{
- AnyElement, Bounds, DispatchPhase, Element, IdentifiedElement, Interactive, IntoAnyElement,
- MouseDownEvent, MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext,
+ AnyElement, Bounds, DispatchPhase, Element, ElementId, ElementKind, Hoverable,
+ IdentifiedElement, IntoAnyElement, LayoutId, LayoutNode, MouseDownEvent, MouseUpEvent, Pixels,
+ SharedString, StyleRefinement, Styled, ViewContext,
};
use parking_lot::Mutex;
-use refineable::Cascade;
+use refineable::CascadeSlot;
use smallvec::SmallVec;
use std::sync::Arc;
-pub type ClickListener<S> =
- dyn Fn(&mut S, (&MouseDownEvent, &MouseUpEvent), &mut ViewContext<S>) + Send + Sync + 'static;
+pub trait Clickable: Element + Sized {
+ fn active_style(&mut self) -> &mut StyleRefinement;
+ fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState>;
-pub struct Clickable<E: Element> {
- child: E,
- listener: Arc<ClickListener<E::ViewState>>,
-}
+ fn on_click(
+ &mut self,
+ f: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
+ + 'static
+ + Send
+ + Sync,
+ ) where
+ Self: Sized,
+ {
+ self.listeners().push(Arc::new(f));
+ }
-pub struct ClickableState<S> {
- last_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
- child_state: S,
+ fn active(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
+ where
+ Self: Sized,
+ {
+ f(self.active_style());
+ self
+ }
}
-impl<E: Element> Clickable<E> {
- pub fn new(child: E, listener: Arc<ClickListener<E::ViewState>>) -> Self {
- Self { child, listener }
- }
+pub type ClickListeners<V> =
+ SmallVec<[Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync>; 1]>;
+
+pub struct ClickableElementState<E: 'static + Send + Sync> {
+ mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
+ child_state: E,
}
-impl<E> Styled for Clickable<E>
-where
- E: Styled + IdentifiedElement,
-{
- type Style = E::Style;
+pub struct MouseClickEvent {
+ pub down: MouseDownEvent,
+ pub up: MouseUpEvent,
+}
- fn style_cascade(&mut self) -> &mut Cascade<E::Style> {
- self.child.style_cascade()
- }
+pub struct ClickableElement<E: Element> {
+ child: E,
+ listeners: ClickListeners<E::ViewState>,
+ active_style: StyleRefinement,
+ cascade_slot: CascadeSlot,
+}
- fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
- self.child.declared_style()
+impl<E: Element> ClickableElement<E> {
+ pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
+ self,
+ replace: impl FnOnce(E) -> E2,
+ ) -> ClickableElement<E2> {
+ ClickableElement {
+ child: replace(self.child),
+ listeners: self.listeners,
+ active_style: self.active_style,
+ cascade_slot: self.cascade_slot,
+ }
}
}
-impl<S, E> Interactive<S> for Clickable<E>
+impl<E> IntoAnyElement<E::ViewState> for ClickableElement<E>
where
- S: 'static + Send + Sync,
- E: IdentifiedElement + Interactive<S>,
+ E: Styled + Element,
{
- fn listeners(&mut self) -> &mut MouseEventListeners<S> {
- self.child.listeners()
- }
-}
-
-impl<E: IdentifiedElement> IntoAnyElement<E::ViewState> for Clickable<E> {
fn into_any(self) -> AnyElement<E::ViewState> {
AnyElement::new(self)
}
}
-impl<E> Element for Clickable<E>
+impl<E> Element for ClickableElement<E>
where
- E: IdentifiedElement,
+ E: Styled + Element,
{
type ViewState = E::ViewState;
- type ElementState = ClickableState<E::ElementState>;
+ type ElementState = ClickableElementState<E::ElementState>;
- fn id(&self) -> Option<crate::ElementId> {
- Some(IdentifiedElement::element_id(&self.child))
+ fn id(&self) -> Option<ElementId> {
+ self.child.id()
}
fn layout(
@@ -73,24 +92,33 @@ where
state: &mut Self::ViewState,
element_state: Option<Self::ElementState>,
cx: &mut ViewContext<Self::ViewState>,
- ) -> (crate::LayoutId, Self::ElementState) {
+ ) -> (LayoutId, Self::ElementState) {
if let Some(element_state) = element_state {
+ if element_state.mouse_down.lock().is_some() {
+ self.child
+ .style_cascade()
+ .set(self.cascade_slot, Some(self.active_style.clone()));
+ }
+
let (layout_id, child_state) =
self.child
.layout(state, Some(element_state.child_state), cx);
-
- let element_state = ClickableState {
- last_mouse_down: element_state.last_mouse_down,
- child_state,
- };
- (layout_id, element_state)
+ (
+ layout_id,
+ ClickableElementState {
+ mouse_down: element_state.mouse_down,
+ child_state,
+ },
+ )
} else {
let (layout_id, child_state) = self.child.layout(state, None, cx);
- let element_state = ClickableState {
- last_mouse_down: Default::default(),
- child_state,
- };
- (layout_id, element_state)
+ (
+ layout_id,
+ ClickableElementState {
+ mouse_down: Default::default(),
+ child_state,
+ },
+ )
}
}
@@ -101,31 +129,39 @@ where
element_state: &mut Self::ElementState,
cx: &mut ViewContext<Self::ViewState>,
) {
- let last_mouse_down = element_state.last_mouse_down.clone();
- let is_some = last_mouse_down.lock().is_some();
-
- if is_some {
- let listener = self.listener.clone();
- cx.on_mouse_event(move |view, up_event: &MouseUpEvent, phase, cx| {
- if phase == DispatchPhase::Capture && !bounds.contains_point(up_event.position) {
- *last_mouse_down.lock() = None;
- } else if phase == DispatchPhase::Bubble && bounds.contains_point(up_event.position)
- {
- if let Some(down_event) = last_mouse_down.lock().take() {
- listener(view, (&down_event, up_event), cx);
- } else {
- log::error!("No mouse down event found for click event");
+ if !self.listeners.is_empty() || self.active_style.is_some() {
+ if let Some(mouse_down) = element_state.mouse_down.lock().clone() {
+ self.child
+ .style_cascade()
+ .set(self.cascade_slot, Some(self.active_style.clone()));
+ let listeners = self.listeners.clone();
+ let mouse_down_mutex = element_state.mouse_down.clone();
+ cx.on_mouse_event(move |view, up: &MouseUpEvent, phase, cx| {
+ if phase == DispatchPhase::Bubble && bounds.contains_point(up.position) {
+ for listener in &*listeners {
+ listener(
+ view,
+ &MouseClickEvent {
+ down: mouse_down.clone(),
+ up: up.clone(),
+ },
+ cx,
+ );
+ }
}
- }
- })
- } else {
- cx.on_mouse_event(move |_, event: &MouseDownEvent, phase, _| {
- if phase == DispatchPhase::Bubble {
- if bounds.contains_point(event.position) {
- *last_mouse_down.lock() = Some(event.clone());
+
+ mouse_down_mutex.lock().take();
+ cx.notify();
+ });
+ } else {
+ let mouse_down_mutex = element_state.mouse_down.clone();
+ cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
+ if phase == DispatchPhase::Bubble && bounds.contains_point(down.position) {
+ *mouse_down_mutex.lock() = Some(down.clone());
+ cx.notify();
}
- }
- })
+ });
+ }
}
self.child
@@ -133,12 +169,53 @@ where
}
}
-impl<E: IdentifiedElement + ParentElement> ParentElement for Clickable<E> {
- type State = E::State;
+impl<E: Styled + IdentifiedElement> IdentifiedElement for ClickableElement<E> {}
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
+impl<E, K> LayoutNode<E::ViewState, K> for ClickableElement<E>
+where
+ E: Element + LayoutNode<E::ViewState, K>,
+ K: ElementKind,
+{
+ fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<E::ViewState>; 2]> {
self.child.children_mut()
}
+
+ fn group_mut(&mut self) -> &mut Option<SharedString> {
+ self.child.group_mut()
+ }
+}
+
+impl<E> Styled for ClickableElement<E>
+where
+ E: Styled + Element,
+{
+ fn style_cascade(&mut self) -> &mut crate::StyleCascade {
+ self.child.style_cascade()
+ }
+
+ fn computed_style(&mut self) -> &crate::Style {
+ self.child.computed_style()
+ }
}
-impl<E> IdentifiedElement for Clickable<E> where E: IdentifiedElement + Styled {}
+impl<E> Hoverable for ClickableElement<E>
+where
+ E: Element + Hoverable,
+{
+ fn hover_style(&mut self) -> &mut StyleRefinement {
+ self.child.hover_style()
+ }
+}
+
+impl<E> Clickable for ClickableElement<E>
+where
+ E: Styled + IdentifiedElement,
+{
+ fn active_style(&mut self) -> &mut StyleRefinement {
+ &mut self.active_style
+ }
+
+ fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState> {
+ &mut self.listeners
+ }
+}
@@ -1,246 +1,174 @@
use crate::{
- AnyElement, BorrowWindow, Bounds, Cascade, Element, ElementId, IdentifiedElement, Interactive,
- IntoAnyElement, LayoutId, MouseEventListeners, Overflow, ParentElement, Pixels, Point,
- Refineable, Style, Styled, ViewContext,
+ AnonymousElementKind, AnyElement, Bounds, Clickable, ClickableElement, ClickableElementState,
+ Element, ElementId, ElementKind, Hoverable, HoverableElement, IdentifiedElementKind,
+ IntoAnyElement, LayoutId, LayoutNode, LayoutNodeElement, Overflow, Pixels, Point, SharedString,
+ Style, StyleCascade, StyleRefinement, Styled, ViewContext, ClickListeners,
};
use parking_lot::Mutex;
use smallvec::SmallVec;
-use std::{marker::PhantomData, sync::Arc};
+use std::sync::Arc;
-pub enum HasId {}
-
-pub struct Div<S: 'static, I = ()> {
- styles: Cascade<Style>,
- id: Option<ElementId>,
- listeners: MouseEventListeners<S>,
- children: SmallVec<[AnyElement<S>; 2]>,
- scroll_state: Option<ScrollState>,
- identified: PhantomData<I>,
-}
-
-pub fn div<S>() -> Div<S> {
- Div {
- styles: Default::default(),
- id: None,
- listeners: Default::default(),
- children: Default::default(),
- scroll_state: None,
- identified: PhantomData,
- }
-}
+#[derive(Default, Clone)]
+pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
-impl<S, Marker> IntoAnyElement<S> for Div<S, Marker>
-where
- S: 'static + Send + Sync,
- Marker: 'static + Send + Sync,
-{
- fn into_any(self) -> AnyElement<S> {
- AnyElement::new(self)
+impl ScrollState {
+ pub fn x(&self) -> Pixels {
+ self.0.lock().x
}
-}
-impl<S, Marker> Element for Div<S, Marker>
-where
- S: 'static + Send + Sync,
- Marker: 'static + Send + Sync,
-{
- type ViewState = S;
- type ElementState = ();
-
- fn id(&self) -> Option<ElementId> {
- self.id.clone()
+ pub fn set_x(&self, value: Pixels) {
+ self.0.lock().x = value;
}
- fn layout(
- &mut self,
- view: &mut S,
- _: Option<Self::ElementState>,
- cx: &mut ViewContext<S>,
- ) -> (LayoutId, Self::ElementState) {
- let style = self.computed_style();
- let child_layout_ids = style.apply_text_style(cx, |cx| {
- self.with_element_id(cx, |this, cx| this.layout_children(view, cx))
- });
- let layout_id = cx.request_layout(&style, child_layout_ids.clone());
- (layout_id, ())
+ pub fn y(&self) -> Pixels {
+ self.0.lock().y
}
- fn paint(
- &mut self,
- bounds: Bounds<Pixels>,
- state: &mut S,
- _: &mut (),
- cx: &mut ViewContext<S>,
- ) {
- let style = self.computed_style();
- let z_index = style.z_index.unwrap_or(0);
- cx.stack(z_index, |cx| style.paint(bounds, cx));
-
- let overflow = &style.overflow;
-
- style.apply_text_style(cx, |cx| {
- cx.stack(z_index + 1, |cx| {
- style.apply_overflow(bounds, cx, |cx| {
- self.with_element_id(cx, |this, cx| {
- this.listeners.paint(bounds, cx);
- this.paint_children(overflow, state, cx)
- });
- })
- })
- });
+ pub fn set_y(&self, value: Pixels) {
+ self.0.lock().y = value;
}
}
-impl<S> Div<S, ()>
-where
- S: 'static + Send + Sync,
-{
- pub fn id(self, id: impl Into<ElementId>) -> Div<S, HasId> {
- Div {
- styles: self.styles,
- id: Some(id.into()),
- listeners: self.listeners,
- children: self.children,
- scroll_state: self.scroll_state,
- identified: PhantomData,
- }
+pub struct Div<V: 'static + Send + Sync, K: ElementKind>(
+ ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
+);
+
+impl<V: 'static + Send + Sync, K: ElementKind> Div<V, K> {
+ pub fn group(mut self, group: impl Into<SharedString>) -> Self {
+ *self.0.group_mut() = Some(group.into());
+ self
}
-}
-impl<S, Marker> Div<S, Marker>
-where
- S: 'static + Send + Sync,
- Marker: 'static + Send + Sync,
-{
pub fn z_index(mut self, z_index: u32) -> Self {
- self.declared_style().z_index = Some(z_index);
+ self.base_style().z_index = Some(z_index);
self
}
pub fn overflow_hidden(mut self) -> Self {
- self.declared_style().overflow.x = Some(Overflow::Hidden);
- self.declared_style().overflow.y = Some(Overflow::Hidden);
+ self.base_style().overflow.x = Some(Overflow::Hidden);
+ self.base_style().overflow.y = Some(Overflow::Hidden);
self
}
pub fn overflow_hidden_x(mut self) -> Self {
- self.declared_style().overflow.x = Some(Overflow::Hidden);
+ self.base_style().overflow.x = Some(Overflow::Hidden);
self
}
pub fn overflow_hidden_y(mut self) -> Self {
- self.declared_style().overflow.y = Some(Overflow::Hidden);
+ self.base_style().overflow.y = Some(Overflow::Hidden);
self
}
- pub fn overflow_scroll(mut self, scroll_state: ScrollState) -> Self {
- self.scroll_state = Some(scroll_state);
- self.declared_style().overflow.x = Some(Overflow::Scroll);
- self.declared_style().overflow.y = Some(Overflow::Scroll);
+ pub fn overflow_scroll(mut self, _scroll_state: ScrollState) -> Self {
+ // todo!("impl scrolling")
+ // self.scroll_state = Some(scroll_state);
+ self.base_style().overflow.x = Some(Overflow::Scroll);
+ self.base_style().overflow.y = Some(Overflow::Scroll);
self
}
- pub fn overflow_x_scroll(mut self, scroll_state: ScrollState) -> Self {
- self.scroll_state = Some(scroll_state);
- self.declared_style().overflow.x = Some(Overflow::Scroll);
+ pub fn overflow_x_scroll(mut self, _scroll_state: ScrollState) -> Self {
+ // todo!("impl scrolling")
+ // self.scroll_state = Some(scroll_state);
+ self.base_style().overflow.x = Some(Overflow::Scroll);
self
}
- pub fn overflow_y_scroll(mut self, scroll_state: ScrollState) -> Self {
- self.scroll_state = Some(scroll_state);
- self.declared_style().overflow.y = Some(Overflow::Scroll);
+ pub fn overflow_y_scroll(mut self, _scroll_state: ScrollState) -> Self {
+ // todo!("impl scrolling")
+ // self.scroll_state = Some(scroll_state);
+ self.base_style().overflow.y = Some(Overflow::Scroll);
self
}
- fn scroll_offset(&self, overflow: &Point<Overflow>) -> Point<Pixels> {
- let mut offset = Point::default();
- if overflow.y == Overflow::Scroll {
- offset.y = self.scroll_state.as_ref().unwrap().y();
- }
- if overflow.x == Overflow::Scroll {
- offset.x = self.scroll_state.as_ref().unwrap().x();
- }
-
- offset
+ fn base_style(&mut self) -> &mut StyleRefinement {
+ self.style_cascade().base()
}
+}
- 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()
+impl<V: 'static + Send + Sync> Div<V, AnonymousElementKind> {
+ pub fn id(self, id: impl Into<ElementId>) -> Div<V, IdentifiedElementKind> {
+ Div(self.0.replace_child(|hoverable| {
+ hoverable.replace_child(|layout_node| layout_node.identify(id))
+ }))
}
+}
- fn paint_children(
- &mut self,
- overflow: &Point<Overflow>,
- state: &mut S,
- cx: &mut ViewContext<S>,
- ) {
- let scroll_offset = self.scroll_offset(overflow);
- for child in &mut self.children {
- child.paint(state, Some(scroll_offset), cx);
- }
+impl<V: 'static + Send + Sync, K: ElementKind> LayoutNode<V, K> for Div<V, K> {
+ fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+ self.0.children_mut()
}
- fn with_element_id<R>(
- &mut self,
- cx: &mut ViewContext<S>,
- f: impl FnOnce(&mut Self, &mut ViewContext<S>) -> R,
- ) -> R {
- if let Some(element_id) = self.id() {
- cx.with_element_id(element_id, |cx| f(self, cx))
- } else {
- f(self, cx)
- }
+ fn group_mut(&mut self) -> &mut Option<SharedString> {
+ self.0.group_mut()
}
}
-impl<V: 'static + Send + Sync, Marker: 'static + Send + Sync> Styled for Div<V, Marker> {
- type Style = Style;
-
- fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
- &mut self.styles
+impl<V: 'static + Send + Sync, K: ElementKind> Styled for Div<V, K> {
+ fn style_cascade(&mut self) -> &mut StyleCascade {
+ self.0.style_cascade()
}
- fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
- self.styles.base()
+ fn computed_style(&mut self) -> &Style {
+ self.0.computed_style()
}
}
-impl<V: Send + Sync + 'static> IdentifiedElement for Div<V, HasId> {}
-
-impl<V: Send + Sync + 'static, Marker: 'static + Send + Sync> Interactive<V> for Div<V, Marker> {
- fn listeners(&mut self) -> &mut MouseEventListeners<V> {
- &mut self.listeners
+impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Div<V, K> {
+ fn hover_style(&mut self) -> &mut StyleRefinement {
+ self.0.hover_style()
}
}
-impl<V: 'static, Marker: 'static + Send + Sync> ParentElement for Div<V, Marker> {
- type State = V;
+impl<V: 'static + Send + Sync> Clickable for Div<V, IdentifiedElementKind> {
+ fn active_style(&mut self) -> &mut StyleRefinement {
+ self.0.active_style()
+ }
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
- &mut self.children
+ fn listeners(&mut self) -> &mut ClickListeners<V> {
+ self.0.listeners()
}
}
-#[derive(Default, Clone)]
-pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
-
-impl ScrollState {
- pub fn x(&self) -> Pixels {
- self.0.lock().x
+impl<V, K> IntoAnyElement<V> for Div<V, K>
+where
+ V: 'static + Send + Sync,
+ K: ElementKind,
+{
+ fn into_any(self) -> AnyElement<V> {
+ AnyElement::new(self)
}
+}
- pub fn set_x(&self, value: Pixels) {
- self.0.lock().x = value;
+impl<V, K> Element for Div<V, K>
+where
+ V: 'static + Send + Sync,
+ K: ElementKind,
+{
+ type ViewState = V;
+ type ElementState = ClickableElementState<()>;
+
+ fn id(&self) -> Option<ElementId> {
+ self.0.id()
}
- pub fn y(&self) -> Pixels {
- self.0.lock().y
+ fn layout(
+ &mut self,
+ state: &mut Self::ViewState,
+ element_state: Option<Self::ElementState>,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) -> (LayoutId, Self::ElementState) {
+ self.0.layout(state, element_state, cx)
}
- pub fn set_y(&self, value: Pixels) {
- self.0.lock().y = value;
+ fn paint(
+ &mut self,
+ bounds: Bounds<Pixels>,
+ state: &mut Self::ViewState,
+ element_state: &mut Self::ElementState,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) {
+ self.0.paint(bounds, state, element_state, cx);
}
}
@@ -1,103 +0,0 @@
-use crate::{
- AnyElement, AppContext, Bounds, Element, ElementId, IdentifiedElement, Interactive,
- IntoAnyElement, MouseEventListeners, ParentElement, Pixels, SharedString, Styled, ViewContext,
-};
-use collections::HashMap;
-use refineable::Cascade;
-use smallvec::SmallVec;
-
-#[derive(Default)]
-struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
-
-pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
- cx.default_global::<GroupBounds>()
- .0
- .get(name)
- .and_then(|bounds_stack| bounds_stack.last().cloned())
-}
-
-pub struct Group<E> {
- name: SharedString,
- child: E,
-}
-
-impl<E> Group<E> {
- pub fn new(name: SharedString, child: E) -> Self {
- Group { name, child }
- }
-}
-
-impl<E: Element> IntoAnyElement<E::ViewState> for Group<E> {
- fn into_any(self) -> AnyElement<E::ViewState> {
- AnyElement::new(self)
- }
-}
-
-impl<E: Element> Element for Group<E> {
- type ViewState = E::ViewState;
- type ElementState = E::ElementState;
-
- fn id(&self) -> Option<ElementId> {
- self.child.id()
- }
-
- fn layout(
- &mut self,
- 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::ViewState,
- element_state: &mut Self::ElementState,
- cx: &mut ViewContext<Self::ViewState>,
- ) {
- cx.default_global::<GroupBounds>()
- .0
- .entry(self.name.clone())
- .or_default()
- .push(bounds);
- self.child.paint(bounds, state, element_state, cx);
- cx.default_global::<GroupBounds>()
- .0
- .get_mut(&self.name)
- .unwrap()
- .pop();
- }
-}
-
-impl<E: ParentElement> ParentElement for Group<E> {
- type State = E::State;
-
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
- self.child.children_mut()
- }
-}
-
-impl<E> IdentifiedElement for Group<E> where E: IdentifiedElement {}
-
-impl<E> Styled for Group<E>
-where
- E: Styled,
-{
- type Style = E::Style;
-
- fn style_cascade(&mut self) -> &mut Cascade<E::Style> {
- self.child.style_cascade()
- }
-
- fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
- self.child.declared_style()
- }
-}
-
-impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Group<E> {
- fn listeners(&mut self) -> &mut MouseEventListeners<S> {
- self.child.listeners()
- }
-}
@@ -1,72 +1,61 @@
use crate::{
- group_bounds, AnyElement, Bounds, DispatchPhase, Element, ElementId, IdentifiedElement,
- Interactive, IntoAnyElement, MouseEventListeners, MouseMoveEvent, ParentElement, Pixels,
- SharedString, Styled, ViewContext,
+ group_bounds, AnyElement, Bounds, DispatchPhase, Element, ElementId, ElementKind,
+ IdentifiedElement, IntoAnyElement, LayoutId, LayoutNode, MouseMoveEvent, Pixels, SharedString,
+ Style, StyleCascade, StyleRefinement, Styled, ViewContext,
};
-use refineable::{Cascade, CascadeSlot, Refineable};
-use smallvec::SmallVec;
+use refineable::CascadeSlot;
use std::sync::{
atomic::{AtomicBool, Ordering::SeqCst},
Arc,
};
-pub struct Hoverable<E: Styled> {
- group: Option<SharedString>,
- hovered: Arc<AtomicBool>,
- cascade_slot: CascadeSlot,
- hovered_style: <E::Style as Refineable>::Refinement,
- child: E,
-}
+pub trait Hoverable {
+ fn hover_style(&mut self) -> &mut StyleRefinement;
-impl<E: Styled> Hoverable<E> {
- pub fn new(mut child: E, hover_group: Option<SharedString>) -> Self {
- Self {
- group: hover_group,
- hovered: Arc::new(AtomicBool::new(false)),
- cascade_slot: child.style_cascade().reserve(),
- hovered_style: Default::default(),
- child,
- }
+ fn hover(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
+ where
+ Self: Sized,
+ {
+ f(self.hover_style());
+ self
}
}
-impl<E> Styled for Hoverable<E>
-where
- E: Styled,
-{
- type Style = E::Style;
-
- fn style_cascade(&mut self) -> &mut Cascade<E::Style> {
- self.child.style_cascade()
- }
-
- fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
- &mut self.hovered_style
- }
+pub struct HoverableElement<E> {
+ hover_style: StyleRefinement,
+ group: Option<SharedString>,
+ cascade_slot: CascadeSlot,
+ hovered: Arc<AtomicBool>,
+ child: E,
}
-impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Hoverable<E> {
- fn listeners(&mut self) -> &mut MouseEventListeners<S> {
- self.child.listeners()
+impl<E: Styled + Element> HoverableElement<E> {
+ pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
+ self,
+ replace: impl FnOnce(E) -> E2,
+ ) -> HoverableElement<E2> {
+ HoverableElement {
+ hover_style: self.hover_style,
+ group: self.group,
+ cascade_slot: self.cascade_slot,
+ hovered: self.hovered,
+ child: replace(self.child),
+ }
}
}
-impl<E> IntoAnyElement<E::ViewState> for Hoverable<E>
+impl<E> IntoAnyElement<E::ViewState> for HoverableElement<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,
+ E: Styled + Element,
{
fn into_any(self) -> AnyElement<E::ViewState> {
AnyElement::new(self)
}
}
-impl<E> Element for Hoverable<E>
+impl<E> Element for HoverableElement<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,
+ E: Styled + Element,
{
type ViewState = E::ViewState;
type ElementState = E::ElementState;
@@ -80,7 +69,7 @@ where
state: &mut Self::ViewState,
element_state: Option<Self::ElementState>,
cx: &mut ViewContext<Self::ViewState>,
- ) -> (crate::LayoutId, Self::ElementState) {
+ ) -> (LayoutId, Self::ElementState) {
self.child.layout(state, element_state, cx)
}
@@ -100,19 +89,15 @@ where
let hovered = target_bounds.contains_point(cx.mouse_position());
let slot = self.cascade_slot;
- let style = hovered.then_some(self.hovered_style.clone());
- self.style_cascade().set(slot, style);
+ let style = hovered.then_some(self.hover_style.clone());
+ self.child.style_cascade().set(slot, style);
self.hovered.store(hovered, SeqCst);
- cx.on_mouse_event({
- let hovered = self.hovered.clone();
-
- move |_, event: &MouseMoveEvent, phase, cx| {
- if phase == DispatchPhase::Bubble {
- if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
- cx.notify();
- cx.stop_propagation();
- }
+ let hovered = self.hovered.clone();
+ cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
+ if phase == DispatchPhase::Capture {
+ if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
+ cx.notify();
}
}
});
@@ -121,18 +106,35 @@ where
}
}
-impl<E: ParentElement + Styled> ParentElement for Hoverable<E> {
- type State = E::State;
-
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
+impl<E, K, V> LayoutNode<V, K> for HoverableElement<E>
+where
+ E: LayoutNode<V, K>,
+ K: ElementKind,
+ V: 'static + Send + Sync,
+{
+ fn children_mut(&mut self) -> &mut smallvec::SmallVec<[AnyElement<V>; 2]> {
self.child.children_mut()
}
+
+ fn group_mut(&mut self) -> &mut Option<SharedString> {
+ self.child.group_mut()
+ }
}
-impl<E> IdentifiedElement for Hoverable<E>
-where
- E: IdentifiedElement + Styled,
- <E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
- <<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
-{
+impl<E: Styled + Element> Hoverable for HoverableElement<E> {
+ fn hover_style(&mut self) -> &mut StyleRefinement {
+ &mut self.hover_style
+ }
+}
+
+impl<E: Styled + Element> Styled for HoverableElement<E> {
+ fn style_cascade(&mut self) -> &mut StyleCascade {
+ self.child.style_cascade()
+ }
+
+ fn computed_style(&mut self) -> &Style {
+ self.child.computed_style()
+ }
}
+
+impl<E: Styled + IdentifiedElement> IdentifiedElement for HoverableElement<E> {}
@@ -1,69 +0,0 @@
-use refineable::{Cascade, Refineable};
-use smallvec::SmallVec;
-
-use crate::{
- AnyElement, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement, IntoAnyElement,
- LayoutId, ParentElement, Styled, ViewContext,
-};
-
-pub struct Identified<E> {
- pub(crate) element: E,
- pub(crate) id: ElementId,
-}
-
-impl<E: Element> IntoAnyElement<E::ViewState> for Identified<E> {
- fn into_any(self) -> AnyElement<E::ViewState> {
- AnyElement::new(self)
- }
-}
-
-impl<E: Element> Element for Identified<E> {
- type ViewState = E::ViewState;
- type ElementState = E::ElementState;
-
- fn id(&self) -> Option<ElementId> {
- Some(self.id.clone())
- }
-
- fn layout(
- &mut self,
- 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::ViewState,
- element_state: &mut Self::ElementState,
- cx: &mut ViewContext<Self::ViewState>,
- ) {
- cx.with_element_id(self.id.clone(), |cx| {
- self.element.paint(bounds, state, element_state, cx)
- })
- }
-}
-
-impl<E: Element> IdentifiedElement for Identified<E> {}
-
-impl<E: Styled> Styled for Identified<E> {
- type Style = E::Style;
-
- fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
- self.element.style_cascade()
- }
- fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
- self.element.declared_style()
- }
-}
-
-impl<E: ParentElement> ParentElement for Identified<E> {
- type State = E::State;
-
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
- self.element.children_mut()
- }
-}
@@ -74,7 +74,7 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
cx: &mut ViewContext<Self::ViewState>,
) {
let style = self.computed_style();
-
+ let corner_radii = style.corner_radii;
style.paint(bounds, cx);
if let Some(uri) = self.uri.clone() {
@@ -84,7 +84,7 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
.now_or_never()
.and_then(ResultExt::log_err)
{
- let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
+ let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
cx.stack(1, |cx| {
cx.paint_image(bounds, corner_radii, data, self.grayscale)
.log_err()
@@ -102,13 +102,13 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
}
impl<S> Styled for Img<S> {
- type Style = Style;
-
- fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
- &mut self.style
+ fn style_cascade(&mut self) -> &mut Cascade<Style> {
+ todo!("use layout node")
+ // &mut self.style
}
- fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
- self.style.base()
+ fn computed_style(&mut self) -> &Style {
+ todo!("use layout node")
+ // self.style.compute()
}
}
@@ -0,0 +1,207 @@
+use crate::{
+ AnyElement, AppContext, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement,
+ IntoAnyElement, LayoutId, Pixels, SharedString, Style, StyleCascade, Styled, ViewContext,
+};
+use collections::HashMap;
+use refineable::Refineable;
+use smallvec::SmallVec;
+
+#[derive(Default)]
+struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
+
+pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
+ cx.default_global::<GroupBounds>()
+ .0
+ .get(name)
+ .and_then(|bounds_stack| bounds_stack.last().cloned())
+}
+
+pub trait LayoutNode<V: 'static + Send + Sync, K: ElementKind> {
+ fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
+ fn group_mut(&mut self) -> &mut Option<SharedString>;
+
+ fn child(mut self, child: impl IntoAnyElement<V>) -> Self
+ where
+ Self: Sized,
+ {
+ self.children_mut().push(child.into_any());
+ self
+ }
+
+ fn children<C, E>(mut self, children: C) -> Self
+ where
+ C: IntoIterator<Item = E>,
+ E: IntoAnyElement<V>,
+ Self: Sized,
+ {
+ for child in children {
+ self.children_mut().push(child.into_any());
+ }
+ self
+ }
+}
+
+pub trait ElementKind: 'static + Send + Sync {
+ fn id(&self) -> Option<ElementId>;
+}
+
+pub struct IdentifiedElementKind(ElementId);
+pub struct AnonymousElementKind;
+
+impl ElementKind for IdentifiedElementKind {
+ fn id(&self) -> Option<ElementId> {
+ Some(self.0.clone())
+ }
+}
+
+impl ElementKind for AnonymousElementKind {
+ fn id(&self) -> Option<ElementId> {
+ None
+ }
+}
+
+pub struct LayoutNodeElement<V: 'static + Send + Sync, K: ElementKind> {
+ style_cascade: StyleCascade,
+ computed_style: Option<Style>,
+ children: SmallVec<[AnyElement<V>; 2]>,
+ kind: K,
+ group: Option<SharedString>,
+}
+
+impl<V: 'static + Send + Sync> LayoutNodeElement<V, AnonymousElementKind> {
+ pub fn identify(self, id: impl Into<ElementId>) -> LayoutNodeElement<V, IdentifiedElementKind> {
+ LayoutNodeElement {
+ style_cascade: self.style_cascade,
+ computed_style: self.computed_style,
+ children: self.children,
+ kind: IdentifiedElementKind(id.into()),
+ group: self.group,
+ }
+ }
+}
+
+impl<V: 'static + Send + Sync, E: ElementKind> LayoutNodeElement<V, E> {
+ pub fn set_group(&mut self, group: impl Into<SharedString>) {
+ self.group = Some(group.into());
+ }
+
+ fn with_element_id<R>(
+ &mut self,
+ cx: &mut ViewContext<V>,
+ f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
+ ) -> R {
+ if let Some(id) = self.id() {
+ cx.with_element_id(id, |cx| f(self, cx))
+ } else {
+ f(self, cx)
+ }
+ }
+}
+
+impl<V: 'static + Send + Sync, K: ElementKind> Styled for LayoutNodeElement<V, K> {
+ fn style_cascade(&mut self) -> &mut StyleCascade {
+ &mut self.style_cascade
+ }
+
+ fn computed_style(&mut self) -> &Style {
+ self.computed_style
+ .get_or_insert_with(|| Style::default().refined(self.style_cascade.merged()))
+ }
+}
+
+impl<V: 'static + Send + Sync> IdentifiedElement for LayoutNodeElement<V, IdentifiedElementKind> {
+ fn id(&self) -> ElementId {
+ self.kind.0.clone()
+ }
+}
+
+impl<V, K> IntoAnyElement<V> for LayoutNodeElement<V, K>
+where
+ V: 'static + Send + Sync,
+ K: ElementKind,
+{
+ fn into_any(self) -> AnyElement<V> {
+ AnyElement::new(self)
+ }
+}
+
+impl<V: 'static + Send + Sync, K: ElementKind> Element for LayoutNodeElement<V, K> {
+ type ViewState = V;
+ type ElementState = ();
+
+ fn id(&self) -> Option<ElementId> {
+ self.kind.id()
+ }
+
+ fn layout(
+ &mut self,
+ state: &mut Self::ViewState,
+ _: Option<Self::ElementState>,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) -> (LayoutId, Self::ElementState) {
+ self.with_element_id(cx, |this, cx| {
+ let layout_ids = this
+ .children
+ .iter_mut()
+ .map(|child| child.layout(state, cx))
+ .collect::<Vec<_>>();
+
+ let style = this.computed_style();
+ let layout_id = cx.request_layout(style, layout_ids);
+ (layout_id, ())
+ })
+ }
+
+ fn paint(
+ &mut self,
+ bounds: Bounds<Pixels>,
+ state: &mut Self::ViewState,
+ _: &mut Self::ElementState,
+ cx: &mut ViewContext<Self::ViewState>,
+ ) {
+ self.with_element_id(cx, |this, cx| {
+ if let Some(group) = this.group.clone() {
+ cx.default_global::<GroupBounds>()
+ .0
+ .entry(group)
+ .or_default()
+ .push(bounds);
+ }
+
+ let style = this.computed_style().clone();
+ let z_index = style.z_index.unwrap_or(0);
+ cx.stack(z_index, |cx| style.paint(bounds, cx));
+
+ // todo!("implement overflow")
+ // let overflow = &style.overflow;
+
+ style.apply_text_style(cx, |cx| {
+ cx.stack(z_index + 1, |cx| {
+ style.apply_overflow(bounds, cx, |cx| {
+ for child in &mut this.children {
+ child.paint(state, None, cx);
+ }
+ })
+ })
+ });
+
+ if let Some(group) = this.group.as_ref() {
+ cx.default_global::<GroupBounds>()
+ .0
+ .get_mut(group)
+ .unwrap()
+ .pop();
+ }
+ })
+ }
+}
+
+impl<V: 'static + Send + Sync, K: ElementKind> LayoutNode<V, K> for LayoutNodeElement<V, K> {
+ fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+ &mut self.children
+ }
+
+ fn group_mut(&mut self) -> &mut Option<SharedString> {
+ &mut self.group
+ }
+}
@@ -1,598 +0,0 @@
-use crate::{
- group_bounds, AnyElement, BorrowWindow, Bounds, DispatchPhase, Element, ElementId,
- IdentifiedElement, IntoAnyElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow,
- ScrollState, SharedString, Style, StyleCascade, StyleRefinement, ViewContext,
-};
-use parking_lot::Mutex;
-use refineable::{CascadeSlot, Refineable};
-use smallvec::SmallVec;
-use std::sync::{
- atomic::{AtomicBool, Ordering::SeqCst},
- Arc,
-};
-
-trait LayoutNode<V: 'static + Send + Sync, K: ElementKind> {
- fn state(&mut self) -> &mut LayoutNodeElement<V, K>;
-
- fn child(mut self, child: impl IntoAnyElement<V>) -> Self
- where
- Self: Sized,
- {
- self.state().children.push(child.into_any());
- self
- }
-
- fn children<C, E>(mut self, children: C) -> Self
- where
- C: IntoIterator<Item = E>,
- E: IntoAnyElement<V>,
- Self: Sized,
- {
- for child in children {
- self.state().children.push(child.into_any());
- }
- self
- }
-}
-
-pub trait ElementKind: 'static + Send + Sync {
- fn id(&self) -> Option<ElementId>;
-}
-
-pub struct Identified(ElementId);
-pub struct Anonymous;
-
-impl ElementKind for Identified {
- fn id(&self) -> Option<ElementId> {
- Some(self.0.clone())
- }
-}
-
-impl ElementKind for Anonymous {
- fn id(&self) -> Option<ElementId> {
- None
- }
-}
-
-struct LayoutNodeElement<V: 'static + Send + Sync, K: ElementKind> {
- style_cascade: StyleCascade,
- computed_style: Option<Style>,
- children: SmallVec<[AnyElement<V>; 2]>,
- kind: K,
-}
-
-impl<V: 'static + Send + Sync> LayoutNodeElement<V, Anonymous> {
- pub fn identify(self, id: impl Into<ElementId>) -> LayoutNodeElement<V, Identified> {
- LayoutNodeElement {
- style_cascade: self.style_cascade,
- computed_style: self.computed_style,
- children: self.children,
- kind: Identified(id.into()),
- }
- }
-}
-
-impl<V: 'static + Send + Sync, E: ElementKind> LayoutNodeElement<V, E> {
- fn with_element_id<R>(
- &mut self,
- cx: &mut ViewContext<V>,
- f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
- ) -> R {
- if let Some(id) = self.id() {
- cx.with_element_id(id, |cx| f(self, cx))
- } else {
- f(self, cx)
- }
- }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> Styled for LayoutNodeElement<V, K> {
- fn style_cascade(&mut self) -> &mut StyleCascade {
- &mut self.style_cascade
- }
-
- fn computed_style(&mut self) -> &Style {
- self.computed_style
- .get_or_insert_with(|| Style::default().refined(self.style_cascade.merged()))
- }
-}
-
-impl<V: 'static + Send + Sync> IdentifiedElement for LayoutNodeElement<V, Identified> {
- fn element_id(&self) -> ElementId {
- self.kind.0.clone()
- }
-}
-
-impl<V, K> IntoAnyElement<V> for LayoutNodeElement<V, K>
-where
- V: 'static + Send + Sync,
- K: ElementKind,
-{
- fn into_any(self) -> AnyElement<V> {
- AnyElement::new(self)
- }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> Element for LayoutNodeElement<V, K> {
- type ViewState = V;
- type ElementState = ();
-
- fn id(&self) -> Option<ElementId> {
- self.kind.id()
- }
-
- fn layout(
- &mut self,
- state: &mut Self::ViewState,
- _: Option<Self::ElementState>,
- cx: &mut ViewContext<Self::ViewState>,
- ) -> (crate::LayoutId, Self::ElementState) {
- self.with_element_id(cx, |this, cx| {
- let layout_ids = this
- .children
- .iter_mut()
- .map(|child| child.layout(state, cx))
- .collect::<Vec<_>>();
-
- let style = this.computed_style();
- let layout_id = cx.request_layout(style, layout_ids);
- (layout_id, ())
- })
- }
-
- fn paint(
- &mut self,
- bounds: Bounds<crate::Pixels>,
- state: &mut Self::ViewState,
- _: &mut Self::ElementState,
- cx: &mut ViewContext<Self::ViewState>,
- ) {
- self.with_element_id(cx, |this, cx| {
- let style = this.computed_style().clone();
- let z_index = style.z_index.unwrap_or(0);
- cx.stack(z_index, |cx| style.paint(bounds, cx));
-
- // todo!("implement overflow")
- // let overflow = &style.overflow;
-
- style.apply_text_style(cx, |cx| {
- cx.stack(z_index + 1, |cx| {
- style.apply_overflow(bounds, cx, |cx| {
- for child in &mut this.children {
- child.paint(state, None, cx);
- }
- })
- })
- });
- })
- }
-}
-
-pub trait Styled {
- fn style_cascade(&mut self) -> &mut StyleCascade;
- fn computed_style(&mut self) -> &Style;
-}
-
-pub trait Hoverable {
- fn hover_style(&mut self) -> &mut StyleRefinement;
-
- fn hover(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
- where
- Self: Sized,
- {
- f(self.hover_style());
- self
- }
-}
-
-struct HoverableElement<E> {
- hover_style: StyleRefinement,
- group: Option<SharedString>,
- cascade_slot: CascadeSlot,
- hovered: Arc<AtomicBool>,
- child: E,
-}
-
-impl<E: Styled + Element> HoverableElement<E> {
- pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
- self,
- replace: impl FnOnce(E) -> E2,
- ) -> HoverableElement<E2> {
- HoverableElement {
- hover_style: self.hover_style,
- group: self.group,
- cascade_slot: self.cascade_slot,
- hovered: self.hovered,
- child: replace(self.child),
- }
- }
-
- fn hover_style(&mut self) -> &mut StyleRefinement {
- &mut self.hover_style
- }
-}
-
-impl<E> IntoAnyElement<E::ViewState> for HoverableElement<E>
-where
- E: Styled + Element,
-{
- fn into_any(self) -> AnyElement<E::ViewState> {
- AnyElement::new(self)
- }
-}
-
-impl<E> Element for HoverableElement<E>
-where
- E: Styled + Element,
-{
- type ViewState = E::ViewState;
- type ElementState = E::ElementState;
-
- fn id(&self) -> Option<ElementId> {
- self.child.id()
- }
-
- fn layout(
- &mut self,
- 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<crate::Pixels>,
- state: &mut Self::ViewState,
- element_state: &mut Self::ElementState,
- cx: &mut ViewContext<Self::ViewState>,
- ) {
- let target_bounds = self
- .group
- .as_ref()
- .and_then(|group| group_bounds(group, cx))
- .unwrap_or(bounds);
-
- let hovered = target_bounds.contains_point(cx.mouse_position());
-
- let slot = self.cascade_slot;
- let style = hovered.then_some(self.hover_style.clone());
- self.child.style_cascade().set(slot, style);
- self.hovered.store(hovered, SeqCst);
-
- let hovered = self.hovered.clone();
- cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
- if phase == DispatchPhase::Capture {
- if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
- cx.notify();
- }
- }
- });
-
- self.child.paint(bounds, state, element_state, cx);
- }
-}
-
-impl<E: Styled + Element> Styled for HoverableElement<E> {
- fn style_cascade(&mut self) -> &mut StyleCascade {
- self.child.style_cascade()
- }
-
- fn computed_style(&mut self) -> &Style {
- self.child.computed_style()
- }
-}
-
-impl<E: Styled + IdentifiedElement> IdentifiedElement for HoverableElement<E> {}
-
-pub trait Clickable: Element + Sized {
- fn active_style(&mut self) -> &mut StyleRefinement;
- fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState>;
-
- fn on_click(
- &mut self,
- f: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
- + 'static
- + Send
- + Sync,
- ) where
- Self: Sized,
- {
- self.listeners().push(Arc::new(f));
- }
-
- fn active(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
- where
- Self: Sized,
- {
- f(self.active_style());
- self
- }
-}
-
-type ClickListeners<V> =
- SmallVec<[Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync>; 1]>;
-
-pub struct ClickableElementState<E: 'static + Send + Sync> {
- mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
- child_state: E,
-}
-
-pub struct MouseClickEvent {
- pub down: MouseDownEvent,
- pub up: MouseUpEvent,
-}
-
-pub struct ClickableElement<E: Element> {
- child: E,
- listeners: ClickListeners<E::ViewState>,
- active_style: StyleRefinement,
- cascade_slot: CascadeSlot,
-}
-
-impl<E: Element> ClickableElement<E> {
- pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
- self,
- replace: impl FnOnce(E) -> E2,
- ) -> ClickableElement<E2> {
- ClickableElement {
- child: replace(self.child),
- listeners: self.listeners,
- active_style: self.active_style,
- cascade_slot: self.cascade_slot,
- }
- }
-}
-
-impl<E> IntoAnyElement<E::ViewState> for ClickableElement<E>
-where
- E: Styled + Element,
-{
- fn into_any(self) -> AnyElement<E::ViewState> {
- AnyElement::new(self)
- }
-}
-
-impl<E> Element for ClickableElement<E>
-where
- E: Styled + Element,
-{
- type ViewState = E::ViewState;
- type ElementState = ClickableElementState<E::ElementState>;
-
- fn id(&self) -> Option<ElementId> {
- self.child.id()
- }
-
- 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 {
- if element_state.mouse_down.lock().is_some() {
- self.child
- .style_cascade()
- .set(self.cascade_slot, Some(self.active_style.clone()));
- }
-
- let (layout_id, child_state) =
- self.child
- .layout(state, Some(element_state.child_state), cx);
- (
- layout_id,
- ClickableElementState {
- mouse_down: element_state.mouse_down,
- child_state,
- },
- )
- } else {
- let (layout_id, child_state) = self.child.layout(state, None, cx);
- (
- layout_id,
- ClickableElementState {
- mouse_down: Default::default(),
- child_state,
- },
- )
- }
- }
-
- fn paint(
- &mut self,
- bounds: Bounds<crate::Pixels>,
- state: &mut Self::ViewState,
- element_state: &mut Self::ElementState,
- cx: &mut ViewContext<Self::ViewState>,
- ) {
- if !self.listeners.is_empty() || self.active_style.is_some() {
- if let Some(mouse_down) = element_state.mouse_down.lock().clone() {
- self.child
- .style_cascade()
- .set(self.cascade_slot, Some(self.active_style.clone()));
- let listeners = self.listeners.clone();
- let mouse_down_mutex = element_state.mouse_down.clone();
- cx.on_mouse_event(move |view, up: &MouseUpEvent, phase, cx| {
- if phase == DispatchPhase::Bubble && bounds.contains_point(up.position) {
- for listener in &*listeners {
- listener(
- view,
- &MouseClickEvent {
- down: mouse_down.clone(),
- up: up.clone(),
- },
- cx,
- );
- }
- }
-
- mouse_down_mutex.lock().take();
- cx.notify();
- });
- } else {
- let mouse_down_mutex = element_state.mouse_down.clone();
- cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
- if phase == DispatchPhase::Bubble && bounds.contains_point(down.position) {
- *mouse_down_mutex.lock() = Some(down.clone());
- cx.notify();
- }
- });
- }
- }
-
- self.child
- .paint(bounds, state, &mut element_state.child_state, cx);
- }
-}
-
-impl<E: Styled + IdentifiedElement> IdentifiedElement for ClickableElement<E> {}
-
-impl<E> Clickable for ClickableElement<E>
-where
- E: Styled + IdentifiedElement,
-{
- fn active_style(&mut self) -> &mut StyleRefinement {
- &mut self.active_style
- }
-
- fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState> {
- &mut self.listeners
- }
-}
-
-pub struct Div<V: 'static + Send + Sync, K: ElementKind>(
- ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
-);
-
-impl<V: 'static + Send + Sync, K: ElementKind> Div<V, K> {
- pub fn z_index(mut self, z_index: u32) -> Self {
- self.base_style().z_index = Some(z_index);
- self
- }
-
- pub fn overflow_hidden(mut self) -> Self {
- self.base_style().overflow.x = Some(Overflow::Hidden);
- self.base_style().overflow.y = Some(Overflow::Hidden);
- self
- }
-
- pub fn overflow_hidden_x(mut self) -> Self {
- self.base_style().overflow.x = Some(Overflow::Hidden);
- self
- }
-
- pub fn overflow_hidden_y(mut self) -> Self {
- self.base_style().overflow.y = Some(Overflow::Hidden);
- self
- }
-
- pub fn overflow_scroll(mut self, scroll_state: ScrollState) -> Self {
- // todo!("impl scrolling")
- // self.scroll_state = Some(scroll_state);
- self.base_style().overflow.x = Some(Overflow::Scroll);
- self.base_style().overflow.y = Some(Overflow::Scroll);
- self
- }
-
- pub fn overflow_x_scroll(mut self, scroll_state: ScrollState) -> Self {
- // todo!("impl scrolling")
- // self.scroll_state = Some(scroll_state);
- self.base_style().overflow.x = Some(Overflow::Scroll);
- self
- }
-
- pub fn overflow_y_scroll(mut self, scroll_state: ScrollState) -> Self {
- // todo!("impl scrolling")
- // self.scroll_state = Some(scroll_state);
- self.base_style().overflow.y = Some(Overflow::Scroll);
- self
- }
-
- fn base_style(&mut self) -> &mut StyleRefinement {
- self.style_cascade().base()
- }
-}
-
-impl<V: 'static + Send + Sync> Div<V, Anonymous> {
- pub fn id(self, id: impl Into<ElementId>) -> Div<V, Identified> {
- Div(self.0.replace_child(|hoverable| {
- hoverable.replace_child(|layout_node| layout_node.identify(id))
- }))
- }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> LayoutNode<V, K> for Div<V, K> {
- fn state(&mut self) -> &mut LayoutNodeElement<V, K> {
- &mut self.0.child.child
- }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> Styled for Div<V, K> {
- fn style_cascade(&mut self) -> &mut StyleCascade {
- self.0.child.child.style_cascade()
- }
-
- fn computed_style(&mut self) -> &Style {
- self.0.child.child.computed_style()
- }
-}
-
-impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Div<V, K> {
- fn hover_style(&mut self) -> &mut StyleRefinement {
- self.0.child.hover_style()
- }
-}
-
-impl<V: 'static + Send + Sync> Clickable for Div<V, Identified> {
- fn active_style(&mut self) -> &mut StyleRefinement {
- self.0.active_style()
- }
-
- fn listeners(&mut self) -> &mut ClickListeners<V> {
- self.0.listeners()
- }
-}
-
-impl<V, K> IntoAnyElement<V> for Div<V, K>
-where
- V: 'static + Send + Sync,
- K: ElementKind,
-{
- fn into_any(self) -> AnyElement<V> {
- AnyElement::new(self)
- }
-}
-
-impl<V, K> Element for Div<V, K>
-where
- V: 'static + Send + Sync,
- K: ElementKind,
-{
- type ViewState = V;
- type ElementState = ClickableElementState<()>;
-
- fn id(&self) -> Option<ElementId> {
- self.0.id()
- }
-
- fn layout(
- &mut self,
- state: &mut Self::ViewState,
- element_state: Option<Self::ElementState>,
- cx: &mut ViewContext<Self::ViewState>,
- ) -> (crate::LayoutId, Self::ElementState) {
- self.0.layout(state, element_state, cx)
- }
-
- fn paint(
- &mut self,
- bounds: Bounds<crate::Pixels>,
- state: &mut Self::ViewState,
- element_state: &mut Self::ElementState,
- cx: &mut ViewContext<Self::ViewState>,
- ) {
- self.0.paint(bounds, state, element_state, cx);
- }
-}
@@ -65,7 +65,11 @@ impl<S: 'static + Send + Sync> Element for Svg<S> {
) where
Self: Sized,
{
- let fill_color = self.computed_style().fill.and_then(|fill| fill.color());
+ let fill_color = self
+ .computed_style()
+ .fill
+ .as_ref()
+ .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).log_err();
}
@@ -73,13 +77,11 @@ impl<S: 'static + Send + Sync> Element for Svg<S> {
}
impl<S: 'static + Send + Sync> Styled for Svg<S> {
- type Style = Style;
-
- fn style_cascade(&mut self) -> &mut refineable::Cascade<Self::Style> {
- &mut self.style
+ fn style_cascade(&mut self) -> &mut crate::StyleCascade {
+ todo!("use layout node")
}
- fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
- self.style.base()
+ fn computed_style(&mut self) -> &Style {
+ todo!("use layout node")
}
}
@@ -11,7 +11,6 @@ mod interactive;
mod platform;
mod scene;
mod style;
-mod style_helpers;
mod styled;
mod subscription;
mod svg_renderer;
@@ -41,7 +40,6 @@ pub use serde_json;
pub use smallvec;
pub use smol::Timer;
pub use style::*;
-pub use style_helpers::*;
pub use styled::*;
pub use subscription::*;
pub use svg_renderer::*;
@@ -1,364 +0,0 @@
-use crate::{
- self as gpui3, hsla, point, px, relative, rems, AlignItems, BoxShadow, Display, Fill,
- FlexDirection, Hsla, JustifyContent, Length, Position, SharedString, Style, StyleRefinement,
- Styled, TextStyleRefinement,
-};
-use smallvec::smallvec;
-
-pub trait StyleHelpers: Sized + Styled<Style = Style> {
- gpui3_macros::style_helpers!();
-
- fn full(mut self) -> Self {
- self.declared_style().size.width = Some(relative(1.).into());
- self.declared_style().size.height = Some(relative(1.).into());
- self
- }
-
- fn relative(mut self) -> Self {
- self.declared_style().position = Some(Position::Relative);
- self
- }
-
- fn absolute(mut self) -> Self {
- self.declared_style().position = Some(Position::Absolute);
- self
- }
-
- fn block(mut self) -> Self {
- self.declared_style().display = Some(Display::Block);
- self
- }
-
- fn flex(mut self) -> Self {
- self.declared_style().display = Some(Display::Flex);
- self
- }
-
- fn flex_col(mut self) -> Self {
- self.declared_style().flex_direction = Some(FlexDirection::Column);
- self
- }
-
- fn flex_row(mut self) -> Self {
- self.declared_style().flex_direction = Some(FlexDirection::Row);
- self
- }
-
- fn flex_1(mut self) -> Self {
- self.declared_style().flex_grow = Some(1.);
- self.declared_style().flex_shrink = Some(1.);
- self.declared_style().flex_basis = Some(relative(0.).into());
- self
- }
-
- fn flex_auto(mut self) -> Self {
- self.declared_style().flex_grow = Some(1.);
- self.declared_style().flex_shrink = Some(1.);
- self.declared_style().flex_basis = Some(Length::Auto);
- self
- }
-
- fn flex_initial(mut self) -> Self {
- self.declared_style().flex_grow = Some(0.);
- self.declared_style().flex_shrink = Some(1.);
- self.declared_style().flex_basis = Some(Length::Auto);
- self
- }
-
- fn flex_none(mut self) -> Self {
- self.declared_style().flex_grow = Some(0.);
- self.declared_style().flex_shrink = Some(0.);
- self
- }
-
- fn grow(mut self) -> Self {
- self.declared_style().flex_grow = Some(1.);
- self
- }
-
- fn items_start(mut self) -> Self {
- self.declared_style().align_items = Some(AlignItems::FlexStart);
- self
- }
-
- fn items_end(mut self) -> Self {
- self.declared_style().align_items = Some(AlignItems::FlexEnd);
- self
- }
-
- fn items_center(mut self) -> Self {
- self.declared_style().align_items = Some(AlignItems::Center);
- self
- }
-
- fn justify_between(mut self) -> Self {
- self.declared_style().justify_content = Some(JustifyContent::SpaceBetween);
- self
- }
-
- fn justify_center(mut self) -> Self {
- self.declared_style().justify_content = Some(JustifyContent::Center);
- self
- }
-
- fn justify_start(mut self) -> Self {
- self.declared_style().justify_content = Some(JustifyContent::Start);
- self
- }
-
- fn justify_end(mut self) -> Self {
- self.declared_style().justify_content = Some(JustifyContent::End);
- self
- }
-
- fn justify_around(mut self) -> Self {
- self.declared_style().justify_content = Some(JustifyContent::SpaceAround);
- self
- }
-
- fn fill<F>(mut self, fill: F) -> Self
- where
- F: Into<Fill>,
- Self: Sized,
- {
- self.declared_style().fill = Some(fill.into());
- self
- }
-
- fn border_color<C>(mut self, border_color: C) -> Self
- where
- C: Into<Hsla>,
- Self: Sized,
- {
- self.declared_style().border_color = Some(border_color.into());
- self
- }
-
- fn shadow(mut self) -> Self {
- self.declared_style().box_shadow = Some(smallvec![
- BoxShadow {
- color: hsla(0., 0., 0., 0.1),
- offset: point(px(0.), px(1.)),
- blur_radius: px(3.),
- spread_radius: px(0.),
- },
- BoxShadow {
- color: hsla(0., 0., 0., 0.1),
- offset: point(px(0.), px(1.)),
- blur_radius: px(2.),
- spread_radius: px(-1.),
- }
- ]);
- self
- }
-
- fn shadow_none(mut self) -> Self {
- self.declared_style().box_shadow = Some(Default::default());
- self
- }
-
- fn shadow_sm(mut self) -> Self {
- self.declared_style().box_shadow = Some(smallvec![BoxShadow {
- color: hsla(0., 0., 0., 0.05),
- offset: point(px(0.), px(1.)),
- blur_radius: px(2.),
- spread_radius: px(0.),
- }]);
- self
- }
-
- fn shadow_md(mut self) -> Self {
- self.declared_style().box_shadow = Some(smallvec![
- BoxShadow {
- color: hsla(0.5, 0., 0., 0.1),
- offset: point(px(0.), px(4.)),
- blur_radius: px(6.),
- spread_radius: px(-1.),
- },
- BoxShadow {
- color: hsla(0., 0., 0., 0.1),
- offset: point(px(0.), px(2.)),
- blur_radius: px(4.),
- spread_radius: px(-2.),
- }
- ]);
- self
- }
-
- fn shadow_lg(mut self) -> Self {
- self.declared_style().box_shadow = Some(smallvec![
- BoxShadow {
- color: hsla(0., 0., 0., 0.1),
- offset: point(px(0.), px(10.)),
- blur_radius: px(15.),
- spread_radius: px(-3.),
- },
- BoxShadow {
- color: hsla(0., 0., 0., 0.1),
- offset: point(px(0.), px(4.)),
- blur_radius: px(6.),
- spread_radius: px(-4.),
- }
- ]);
- self
- }
-
- fn shadow_xl(mut self) -> Self {
- self.declared_style().box_shadow = Some(smallvec![
- BoxShadow {
- color: hsla(0., 0., 0., 0.1),
- offset: point(px(0.), px(20.)),
- blur_radius: px(25.),
- spread_radius: px(-5.),
- },
- BoxShadow {
- color: hsla(0., 0., 0., 0.1),
- offset: point(px(0.), px(8.)),
- blur_radius: px(10.),
- spread_radius: px(-6.),
- }
- ]);
- self
- }
-
- fn shadow_2xl(mut self) -> Self {
- self.declared_style().box_shadow = Some(smallvec![BoxShadow {
- color: hsla(0., 0., 0., 0.25),
- offset: point(px(0.), px(25.)),
- blur_radius: px(50.),
- spread_radius: px(-12.),
- }]);
- self
- }
-
- fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
- let style: &mut StyleRefinement = self.declared_style();
- &mut style.text
- }
-
- fn text_color(mut self, color: impl Into<Hsla>) -> Self {
- self.text_style().get_or_insert_with(Default::default).color = Some(color.into());
- self
- }
-
- fn text_xs(mut self) -> Self {
- self.text_style()
- .get_or_insert_with(Default::default)
- .font_size = Some(rems(0.75));
- self
- }
-
- fn text_sm(mut self) -> Self {
- self.text_style()
- .get_or_insert_with(Default::default)
- .font_size = Some(rems(0.875));
- self
- }
-
- fn text_base(mut self) -> Self {
- self.text_style()
- .get_or_insert_with(Default::default)
- .font_size = Some(rems(1.0));
- self
- }
-
- fn text_lg(mut self) -> Self {
- self.text_style()
- .get_or_insert_with(Default::default)
- .font_size = Some(rems(1.125));
- self
- }
-
- fn text_xl(mut self) -> Self {
- self.text_style()
- .get_or_insert_with(Default::default)
- .font_size = Some(rems(1.25));
- self
- }
-
- fn text_2xl(mut self) -> Self {
- self.text_style()
- .get_or_insert_with(Default::default)
- .font_size = Some(rems(1.5));
- self
- }
-
- fn text_3xl(mut self) -> Self {
- self.text_style()
- .get_or_insert_with(Default::default)
- .font_size = Some(rems(1.875));
- self
- }
-
- fn text_decoration_none(mut self) -> Self {
- self.text_style()
- .get_or_insert_with(Default::default)
- .underline = None;
- self
- }
-
- fn text_decoration_color(mut self, color: impl Into<Hsla>) -> Self {
- let style = self.text_style().get_or_insert_with(Default::default);
- let underline = style.underline.get_or_insert_with(Default::default);
- underline.color = Some(color.into());
- self
- }
-
- fn text_decoration_solid(mut self) -> Self {
- let style = self.text_style().get_or_insert_with(Default::default);
- let underline = style.underline.get_or_insert_with(Default::default);
- underline.wavy = false;
- self
- }
-
- fn text_decoration_wavy(mut self) -> Self {
- let style = self.text_style().get_or_insert_with(Default::default);
- let underline = style.underline.get_or_insert_with(Default::default);
- underline.wavy = true;
- self
- }
-
- fn text_decoration_0(mut self) -> Self {
- let style = self.text_style().get_or_insert_with(Default::default);
- let underline = style.underline.get_or_insert_with(Default::default);
- underline.thickness = px(0.);
- self
- }
-
- fn text_decoration_1(mut self) -> Self {
- let style = self.text_style().get_or_insert_with(Default::default);
- let underline = style.underline.get_or_insert_with(Default::default);
- underline.thickness = px(1.);
- self
- }
-
- fn text_decoration_2(mut self) -> Self {
- let style = self.text_style().get_or_insert_with(Default::default);
- let underline = style.underline.get_or_insert_with(Default::default);
- underline.thickness = px(2.);
- self
- }
-
- fn text_decoration_4(mut self) -> Self {
- let style = self.text_style().get_or_insert_with(Default::default);
- let underline = style.underline.get_or_insert_with(Default::default);
- underline.thickness = px(4.);
- self
- }
-
- fn text_decoration_8(mut self) -> Self {
- let style = self.text_style().get_or_insert_with(Default::default);
- let underline = style.underline.get_or_insert_with(Default::default);
- underline.thickness = px(8.);
- self
- }
-
- fn font(mut self, family_name: impl Into<SharedString>) -> Self {
- self.text_style()
- .get_or_insert_with(Default::default)
- .font_family = Some(family_name.into());
- self
- }
-}
-
-impl<E: Styled<Style = Style>> StyleHelpers for E {}
@@ -1,48 +1,503 @@
-use crate::{Cascade, Hoverable, Pressable, Refineable, SharedString};
+use crate::{
+ self as gpui3, hsla, point, px, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla,
+ JustifyContent, Length, Position, SharedString, Style, StyleCascade, StyleRefinement,
+};
+use crate::{BoxShadow, TextStyleRefinement};
+use smallvec::smallvec;
pub trait Styled {
- type Style: 'static + Refineable + Send + Sync + Default;
+ fn style_cascade(&mut self) -> &mut StyleCascade;
+ fn computed_style(&mut self) -> &Style;
+ fn base_style(&mut self) -> &mut StyleRefinement {
+ self.style_cascade().base()
+ }
+
+ gpui3_macros::style_helpers!();
+
+ fn full(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().size.width = Some(relative(1.).into());
+ self.base_style().size.height = Some(relative(1.).into());
+ self
+ }
+
+ fn relative(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().position = Some(Position::Relative);
+ self
+ }
+
+ fn absolute(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().position = Some(Position::Absolute);
+ self
+ }
+
+ fn block(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().display = Some(Display::Block);
+ self
+ }
+
+ fn flex(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().display = Some(Display::Flex);
+ self
+ }
- fn style_cascade(&mut self) -> &mut Cascade<Self::Style>;
- fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
+ fn flex_col(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().flex_direction = Some(FlexDirection::Column);
+ self
+ }
+
+ fn flex_row(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().flex_direction = Some(FlexDirection::Row);
+ self
+ }
+
+ fn flex_1(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().flex_grow = Some(1.);
+ self.base_style().flex_shrink = Some(1.);
+ self.base_style().flex_basis = Some(relative(0.).into());
+ self
+ }
- fn computed_style(&mut self) -> Self::Style {
- Self::Style::default().refined(self.style_cascade().merged())
+ fn flex_auto(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().flex_grow = Some(1.);
+ self.base_style().flex_shrink = Some(1.);
+ self.base_style().flex_basis = Some(Length::Auto);
+ self
+ }
+
+ fn flex_initial(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().flex_grow = Some(0.);
+ self.base_style().flex_shrink = Some(1.);
+ self.base_style().flex_basis = Some(Length::Auto);
+ self
+ }
+
+ fn flex_none(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().flex_grow = Some(0.);
+ self.base_style().flex_shrink = Some(0.);
+ self
+ }
+
+ fn grow(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().flex_grow = Some(1.);
+ self
+ }
+
+ fn items_start(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().align_items = Some(AlignItems::FlexStart);
+ self
+ }
+
+ fn items_end(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().align_items = Some(AlignItems::FlexEnd);
+ self
+ }
+
+ fn items_center(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().align_items = Some(AlignItems::Center);
+ self
+ }
+
+ fn justify_between(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().justify_content = Some(JustifyContent::SpaceBetween);
+ self
+ }
+
+ fn justify_center(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().justify_content = Some(JustifyContent::Center);
+ self
+ }
+
+ fn justify_start(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().justify_content = Some(JustifyContent::Start);
+ self
+ }
+
+ fn justify_end(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().justify_content = Some(JustifyContent::End);
+ self
+ }
+
+ fn justify_around(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().justify_content = Some(JustifyContent::SpaceAround);
+ self
+ }
+
+ fn fill<F>(mut self, fill: F) -> Self
+ where
+ F: Into<Fill>,
+ Self: Sized,
+ {
+ self.base_style().fill = Some(fill.into());
+ self
+ }
+
+ fn border_color<C>(mut self, border_color: C) -> Self
+ where
+ C: Into<Hsla>,
+ Self: Sized,
+ {
+ self.base_style().border_color = Some(border_color.into());
+ self
+ }
+
+ fn shadow(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().box_shadow = Some(smallvec![
+ BoxShadow {
+ color: hsla(0., 0., 0., 0.1),
+ offset: point(px(0.), px(1.)),
+ blur_radius: px(3.),
+ spread_radius: px(0.),
+ },
+ BoxShadow {
+ color: hsla(0., 0., 0., 0.1),
+ offset: point(px(0.), px(1.)),
+ blur_radius: px(2.),
+ spread_radius: px(-1.),
+ }
+ ]);
+ self
+ }
+
+ fn shadow_none(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().box_shadow = Some(Default::default());
+ self
+ }
+
+ fn shadow_sm(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().box_shadow = Some(smallvec::smallvec![BoxShadow {
+ color: hsla(0., 0., 0., 0.05),
+ offset: point(px(0.), px(1.)),
+ blur_radius: px(2.),
+ spread_radius: px(0.),
+ }]);
+ self
+ }
+
+ fn shadow_md(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().box_shadow = Some(smallvec![
+ BoxShadow {
+ color: hsla(0.5, 0., 0., 0.1),
+ offset: point(px(0.), px(4.)),
+ blur_radius: px(6.),
+ spread_radius: px(-1.),
+ },
+ BoxShadow {
+ color: hsla(0., 0., 0., 0.1),
+ offset: point(px(0.), px(2.)),
+ blur_radius: px(4.),
+ spread_radius: px(-2.),
+ }
+ ]);
+ self
+ }
+
+ fn shadow_lg(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().box_shadow = Some(smallvec![
+ BoxShadow {
+ color: hsla(0., 0., 0., 0.1),
+ offset: point(px(0.), px(10.)),
+ blur_radius: px(15.),
+ spread_radius: px(-3.),
+ },
+ BoxShadow {
+ color: hsla(0., 0., 0., 0.1),
+ offset: point(px(0.), px(4.)),
+ blur_radius: px(6.),
+ spread_radius: px(-4.),
+ }
+ ]);
+ self
+ }
+
+ fn shadow_xl(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().box_shadow = Some(smallvec![
+ BoxShadow {
+ color: hsla(0., 0., 0., 0.1),
+ offset: point(px(0.), px(20.)),
+ blur_radius: px(25.),
+ spread_radius: px(-5.),
+ },
+ BoxShadow {
+ color: hsla(0., 0., 0., 0.1),
+ offset: point(px(0.), px(8.)),
+ blur_radius: px(10.),
+ spread_radius: px(-6.),
+ }
+ ]);
+ self
+ }
+
+ fn shadow_2xl(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.base_style().box_shadow = Some(smallvec![BoxShadow {
+ color: hsla(0., 0., 0., 0.25),
+ offset: point(px(0.), px(25.)),
+ blur_radius: px(50.),
+ spread_radius: px(-12.),
+ }]);
+ self
+ }
+
+ fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
+ let style: &mut StyleRefinement = self.base_style();
+ &mut style.text
+ }
+
+ fn text_color(mut self, color: impl Into<Hsla>) -> Self
+ where
+ Self: Sized,
+ {
+ self.text_style().get_or_insert_with(Default::default).color = Some(color.into());
+ self
+ }
+
+ fn text_xs(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.text_style()
+ .get_or_insert_with(Default::default)
+ .font_size = Some(rems(0.75));
+ self
+ }
+
+ fn text_sm(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.text_style()
+ .get_or_insert_with(Default::default)
+ .font_size = Some(rems(0.875));
+ self
+ }
+
+ fn text_base(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.text_style()
+ .get_or_insert_with(Default::default)
+ .font_size = Some(rems(1.0));
+ self
+ }
+
+ fn text_lg(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.text_style()
+ .get_or_insert_with(Default::default)
+ .font_size = Some(rems(1.125));
+ self
+ }
+
+ fn text_xl(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.text_style()
+ .get_or_insert_with(Default::default)
+ .font_size = Some(rems(1.25));
+ self
+ }
+
+ fn text_2xl(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.text_style()
+ .get_or_insert_with(Default::default)
+ .font_size = Some(rems(1.5));
+ self
+ }
+
+ fn text_3xl(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.text_style()
+ .get_or_insert_with(Default::default)
+ .font_size = Some(rems(1.875));
+ self
+ }
+
+ fn text_decoration_none(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.text_style()
+ .get_or_insert_with(Default::default)
+ .underline = None;
+ self
+ }
+
+ fn text_decoration_color(mut self, color: impl Into<Hsla>) -> Self
+ where
+ Self: Sized,
+ {
+ let style = self.text_style().get_or_insert_with(Default::default);
+ let underline = style.underline.get_or_insert_with(Default::default);
+ underline.color = Some(color.into());
+ self
+ }
+
+ fn text_decoration_solid(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ let style = self.text_style().get_or_insert_with(Default::default);
+ let underline = style.underline.get_or_insert_with(Default::default);
+ underline.wavy = false;
+ self
+ }
+
+ fn text_decoration_wavy(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ let style = self.text_style().get_or_insert_with(Default::default);
+ let underline = style.underline.get_or_insert_with(Default::default);
+ underline.wavy = true;
+ self
+ }
+
+ fn text_decoration_0(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ let style = self.text_style().get_or_insert_with(Default::default);
+ let underline = style.underline.get_or_insert_with(Default::default);
+ underline.thickness = px(0.);
+ self
+ }
+
+ fn text_decoration_1(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ let style = self.text_style().get_or_insert_with(Default::default);
+ let underline = style.underline.get_or_insert_with(Default::default);
+ underline.thickness = px(1.);
+ self
}
- fn hover(self) -> Hoverable<Self>
+ fn text_decoration_2(mut self) -> Self
where
- Self: 'static + Sized + Send + Sync,
- Self::Style: 'static + Refineable + Default + Send + Sync,
- <Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
+ Self: Sized,
{
- Hoverable::new(self, None)
+ let style = self.text_style().get_or_insert_with(Default::default);
+ let underline = style.underline.get_or_insert_with(Default::default);
+ underline.thickness = px(2.);
+ self
}
- fn group_hover(self, group_name: impl Into<SharedString>) -> Hoverable<Self>
+ fn text_decoration_4(mut self) -> Self
where
- Self: 'static + Sized + Send + Sync,
- Self::Style: 'static + Refineable + Default + Send + Sync,
- <Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
+ Self: Sized,
{
- Hoverable::new(self, Some(group_name.into()))
+ let style = self.text_style().get_or_insert_with(Default::default);
+ let underline = style.underline.get_or_insert_with(Default::default);
+ underline.thickness = px(4.);
+ self
}
- fn active(self) -> Pressable<Self>
+ fn text_decoration_8(mut self) -> Self
where
- Self: 'static + Sized + Send + Sync,
- Self::Style: 'static + Refineable + Default + Send + Sync,
- <Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
+ Self: Sized,
{
- Pressable::new(self, None)
+ let style = self.text_style().get_or_insert_with(Default::default);
+ let underline = style.underline.get_or_insert_with(Default::default);
+ underline.thickness = px(8.);
+ self
}
- fn group_active(self, group_name: impl Into<SharedString>) -> Pressable<Self>
+ fn font(mut self, family_name: impl Into<SharedString>) -> Self
where
- Self: 'static + Sized + Send + Sync,
- Self::Style: 'static + Refineable + Default + Send + Sync,
- <Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
+ Self: Sized,
{
- Pressable::new(self, Some(group_name.into()))
+ self.text_style()
+ .get_or_insert_with(Default::default)
+ .font_family = Some(family_name.into());
+ self
}
}
@@ -148,7 +148,7 @@ impl<S: Send + Sync + 'static> ViewObject for View<S> {
}
fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) {
- cx.with_element_id(IdentifiedElement::element_id(self), |cx| {
+ cx.with_element_id(IdentifiedElement::id(self), |cx| {
self.state.update(cx, |state, cx| {
let mut element = (self.render)(state, cx);
let layout_id = element.layout(state, cx);
@@ -159,7 +159,7 @@ impl<S: Send + Sync + 'static> ViewObject for View<S> {
}
fn paint(&mut self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
- cx.with_element_id(IdentifiedElement::element_id(self), |cx| {
+ cx.with_element_id(IdentifiedElement::id(self), |cx| {
self.state.update(cx, |state, cx| {
let element = element.downcast_mut::<AnyElement<S>>().unwrap();
element.paint(state, None, cx);
@@ -129,7 +129,7 @@ fn generate_predefined_setter(
let method = quote! {
#[doc = #doc_string]
fn #method_name(mut self) -> Self where Self: std::marker::Sized {
- let mut style = self.declared_style();
+ let mut style = self.base_style();
#(#field_assignments)*
self
}
@@ -160,7 +160,7 @@ fn generate_custom_value_setter(
let method = quote! {
fn #method_name(mut self, length: impl std::clone::Clone + Into<gpui3::#length_type>) -> Self where Self: std::marker::Sized {
- let mut style = self.declared_style();
+ let mut style = self.base_style();
#(#field_assignments)*
self
}