Checkpoint

This commit is contained in:
Antonio Scandurra 2023-10-17 21:11:52 +02:00
parent 19c1a54fea
commit deb0e57c49
14 changed files with 601 additions and 1491 deletions

View file

@ -33,6 +33,26 @@ pub trait IdentifiedElement: Element {
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)] #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>); pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
pub trait ElementKind: 'static + Send + Sync {
fn id(&self) -> Option<ElementId>;
}
pub struct IdentifiedElementKind(pub(crate) 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 trait ParentElement: Element { pub trait ParentElement: Element {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>; fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>;
fn group_mut(&mut self) -> &mut Option<SharedString>; fn group_mut(&mut self) -> &mut Option<SharedString>;

View file

@ -1,16 +1,9 @@
mod clickable;
mod div; mod div;
mod hoverable;
mod img; mod img;
mod layout_node;
mod svg; mod svg;
mod text; mod text;
mod div2;
pub use clickable::*;
pub use div::*; pub use div::*;
pub use hoverable::*;
pub use img::*; pub use img::*;
pub use layout_node::*;
pub use svg::*; pub use svg::*;
pub use text::*; pub use text::*;

View file

@ -1,230 +0,0 @@
use crate::{
AnyElement, Bounds, DispatchPhase, Element, ElementId, Hoverable, IdentifiedElement,
IntoAnyElement, LayoutId, MouseDownEvent, MouseUpEvent, ParentElement, Pixels, SharedString,
StyleRefinement, Styled, ViewContext,
};
use parking_lot::Mutex;
use refineable::CascadeSlot;
use smallvec::SmallVec;
use std::sync::Arc;
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
}
}
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,
}
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: Styled + Element> ClickableElement<E> {
pub fn new(mut child: E) -> Self {
let cascade_slot = child.style_cascade().reserve();
ClickableElement {
child,
listeners: Default::default(),
active_style: Default::default(),
cascade_slot,
}
}
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>,
) -> (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<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> ParentElement for ClickableElement<E>
where
E: Styled + ParentElement,
{
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::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> 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
}
}

View file

@ -1,14 +1,43 @@
use crate::{ use crate::{
AnonymousElementKind, AnyElement, Bounds, ClickListeners, Clickable, ClickableElement, AnonymousElementKind, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element,
ClickableElementState, Element, ElementId, ElementKind, Hoverable, HoverableElement, ElementId, ElementKind, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId,
IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, LayoutNodeElement, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, Pixels, Point,
Overflow, ParentElement, Pixels, Point, SharedString, Style, StyleCascade, StyleRefinement, ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled, ViewContext,
Styled, ViewContext,
}; };
use collections::HashMap;
use parking_lot::Mutex; use parking_lot::Mutex;
use refineable::Refineable;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::sync::Arc; use std::sync::Arc;
#[derive(Default)]
pub struct DivState {
active_state: Arc<Mutex<ActiveState>>,
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
}
#[derive(Copy, Clone, Default, Eq, PartialEq)]
struct ActiveState {
group: bool,
element: bool,
}
impl ActiveState {
pub fn is_none(&self) -> bool {
!self.group && !self.element
}
}
#[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())
}
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct ScrollState(Arc<Mutex<Point<Pixels>>>); pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
@ -34,116 +63,459 @@ pub fn div<S>() -> Div<S, AnonymousElementKind>
where where
S: 'static + Send + Sync, S: 'static + Send + Sync,
{ {
Div(ClickableElement::new(HoverableElement::new( Div {
LayoutNodeElement::new(), kind: AnonymousElementKind,
))) children: SmallVec::new(),
group: None,
base_style: StyleRefinement::default(),
hover_style: StyleRefinement::default(),
group_hover: None,
active_style: StyleRefinement::default(),
group_active: None,
listeners: MouseEventListeners::default(),
}
} }
pub struct Div<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind>( pub struct Div<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>, kind: K,
); children: SmallVec<[AnyElement<V>; 2]>,
group: Option<SharedString>,
base_style: StyleRefinement,
hover_style: StyleRefinement,
group_hover: Option<GroupStyle>,
active_style: StyleRefinement,
group_active: Option<GroupStyle>,
listeners: MouseEventListeners<V>,
}
impl<V: 'static + Send + Sync, K: ElementKind> Div<V, K> { struct GroupStyle {
group: SharedString,
style: StyleRefinement,
}
impl<V> Div<V, AnonymousElementKind>
where
V: 'static + Send + Sync,
{
pub fn id(self, id: impl Into<ElementId>) -> Div<V, IdentifiedElementKind> {
Div {
kind: IdentifiedElementKind(id.into()),
children: self.children,
group: self.group,
base_style: self.base_style,
hover_style: self.hover_style,
group_hover: self.group_hover,
active_style: self.active_style,
group_active: self.group_active,
listeners: self.listeners,
}
}
}
impl<V> Div<V, IdentifiedElementKind>
where
V: 'static + Send + Sync,
{
pub fn on_mouse_down(
mut self,
button: MouseButton,
handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + Send + Sync + 'static,
) -> Self {
self.listeners
.mouse_down
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble
&& event.button == button
&& bounds.contains_point(&event.position)
{
handler(view, event, cx)
}
}));
self
}
pub fn on_mouse_up(
mut self,
button: MouseButton,
handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + Send + Sync + 'static,
) -> Self {
self.listeners
.mouse_up
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble
&& event.button == button
&& bounds.contains_point(&event.position)
{
handler(view, event, cx)
}
}));
self
}
pub fn on_mouse_down_out(
mut self,
button: MouseButton,
handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + Send + Sync + 'static,
) -> Self {
self.listeners
.mouse_down
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Capture
&& event.button == button
&& !bounds.contains_point(&event.position)
{
handler(view, event, cx)
}
}));
self
}
pub fn on_mouse_up_out(
mut self,
button: MouseButton,
handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + Send + Sync + 'static,
) -> Self {
self.listeners
.mouse_up
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Capture
&& event.button == button
&& !bounds.contains_point(&event.position)
{
handler(view, event, cx);
}
}));
self
}
pub fn on_mouse_move(
mut self,
handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext<V>) + Send + Sync + 'static,
) -> Self {
self.listeners
.mouse_move
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
handler(view, event, cx);
}
}));
self
}
pub fn on_scroll_wheel(
mut self,
handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext<V>) + Send + Sync + 'static,
) -> Self {
self.listeners
.scroll_wheel
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
handler(view, event, cx);
}
}));
self
}
}
impl<V, K> Div<V, K>
where
V: 'static + Send + Sync,
K: ElementKind,
{
pub fn group(mut self, group: impl Into<SharedString>) -> Self { pub fn group(mut self, group: impl Into<SharedString>) -> Self {
*self.0.group_mut() = Some(group.into()); self.group = Some(group.into());
self self
} }
pub fn z_index(mut self, z_index: u32) -> Self { pub fn z_index(mut self, z_index: u32) -> Self {
self.base_style().z_index = Some(z_index); self.base_style.z_index = Some(z_index);
self self
} }
pub fn overflow_hidden(mut self) -> Self { pub fn overflow_hidden(mut self) -> Self {
self.base_style().overflow.x = Some(Overflow::Hidden); self.base_style.overflow.x = Some(Overflow::Hidden);
self.base_style().overflow.y = Some(Overflow::Hidden); self.base_style.overflow.y = Some(Overflow::Hidden);
self self
} }
pub fn overflow_hidden_x(mut self) -> Self { pub fn overflow_hidden_x(mut self) -> Self {
self.base_style().overflow.x = Some(Overflow::Hidden); self.base_style.overflow.x = Some(Overflow::Hidden);
self self
} }
pub fn overflow_hidden_y(mut self) -> Self { pub fn overflow_hidden_y(mut self) -> Self {
self.base_style().overflow.y = Some(Overflow::Hidden); self.base_style.overflow.y = Some(Overflow::Hidden);
self self
} }
pub fn overflow_scroll(mut self, _scroll_state: ScrollState) -> Self { pub fn overflow_scroll(mut self, _scroll_state: ScrollState) -> Self {
// todo!("impl scrolling") // todo!("impl scrolling")
// self.scroll_state = Some(scroll_state); // self.scroll_state = Some(scroll_state);
self.base_style().overflow.x = Some(Overflow::Scroll); self.base_style.overflow.x = Some(Overflow::Scroll);
self.base_style().overflow.y = Some(Overflow::Scroll); self.base_style.overflow.y = Some(Overflow::Scroll);
self self
} }
pub fn overflow_x_scroll(mut self, _scroll_state: ScrollState) -> Self { pub fn overflow_x_scroll(mut self, _scroll_state: ScrollState) -> Self {
// todo!("impl scrolling") // todo!("impl scrolling")
// self.scroll_state = Some(scroll_state); // self.scroll_state = Some(scroll_state);
self.base_style().overflow.x = Some(Overflow::Scroll); self.base_style.overflow.x = Some(Overflow::Scroll);
self self
} }
pub fn overflow_y_scroll(mut self, _scroll_state: ScrollState) -> Self { pub fn overflow_y_scroll(mut self, _scroll_state: ScrollState) -> Self {
// todo!("impl scrolling") // todo!("impl scrolling")
// self.scroll_state = Some(scroll_state); // self.scroll_state = Some(scroll_state);
self.base_style().overflow.y = Some(Overflow::Scroll); self.base_style.overflow.y = Some(Overflow::Scroll);
self self
} }
fn base_style(&mut self) -> &mut StyleRefinement { fn with_element_id<R>(
self.style_cascade().base() &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)
}
}
pub fn compute_style(
&self,
bounds: Bounds<Pixels>,
state: &DivState,
cx: &mut ViewContext<V>,
) -> Style {
let mut computed_style = Style::default();
computed_style.refine(&self.base_style);
let mouse_position = cx.mouse_position();
if let Some(group_hover) = self.group_hover.as_ref() {
if let Some(group_bounds) = group_bounds(&group_hover.group, cx) {
if group_bounds.contains_point(&mouse_position) {
computed_style.refine(&group_hover.style);
}
}
}
if bounds.contains_point(&mouse_position) {
computed_style.refine(&self.hover_style);
}
let active_state = *state.active_state.lock();
if active_state.group {
if let Some(GroupStyle { style, .. }) = self.group_active.as_ref() {
computed_style.refine(style);
}
}
if active_state.element {
computed_style.refine(&self.active_style);
}
computed_style
}
fn paint_hover_listeners(
&self,
bounds: Bounds<Pixels>,
group_bounds: Option<Bounds<Pixels>>,
cx: &mut ViewContext<V>,
) {
if let Some(group_bounds) = group_bounds {
paint_hover_listener(group_bounds, cx);
}
if self.hover_style.is_some() {
paint_hover_listener(bounds, cx);
}
}
fn paint_active_listener(
&self,
bounds: Bounds<Pixels>,
group_bounds: Option<Bounds<Pixels>>,
active_state: Arc<Mutex<ActiveState>>,
cx: &mut ViewContext<V>,
) {
if active_state.lock().is_none() {
cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble {
let group =
group_bounds.map_or(false, |bounds| bounds.contains_point(&down.position));
let element = bounds.contains_point(&down.position);
if group || element {
*active_state.lock() = ActiveState { group, element };
cx.notify();
}
}
});
} else {
cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
if phase == DispatchPhase::Capture {
*active_state.lock() = ActiveState::default();
cx.notify();
}
});
}
}
fn paint_event_listeners(
&self,
bounds: Bounds<Pixels>,
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
cx: &mut ViewContext<V>,
) {
let click_listeners = self.listeners.mouse_click.clone();
let mouse_down = pending_click.lock().clone();
if let Some(mouse_down) = mouse_down {
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
let mouse_click = MouseClickEvent {
down: mouse_down.clone(),
up: event.clone(),
};
for listener in &click_listeners {
listener(state, &mouse_click, &bounds, cx);
}
}
*pending_click.lock() = None;
});
} else {
cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
*pending_click.lock() = Some(event.clone());
}
});
}
for listener in self.listeners.mouse_down.iter().cloned() {
cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
}
for listener in self.listeners.mouse_up.iter().cloned() {
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
}
for listener in self.listeners.mouse_move.iter().cloned() {
cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
}
for listener in self.listeners.scroll_wheel.iter().cloned() {
cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
}
} }
} }
impl<V: 'static + Send + Sync> Div<V, AnonymousElementKind> { impl<V, K> Element for Div<V, K>
pub fn id(self, id: impl Into<ElementId>) -> Div<V, IdentifiedElementKind> { where
Div(self.0.replace_child(|hoverable| { V: 'static + Send + Sync,
hoverable.replace_child(|layout_node| layout_node.identify(id)) K: ElementKind,
})) {
type ViewState = V;
type ElementState = DivState;
fn id(&self) -> Option<ElementId> {
self.kind.id()
}
fn layout(
&mut self,
view_state: &mut Self::ViewState,
element_state: 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(view_state, cx))
.collect::<Vec<_>>();
let element_state = element_state.unwrap_or_default();
let style = this.compute_style(Bounds::default(), &element_state, cx);
let layout_id = cx.request_layout(&style, layout_ids);
(layout_id, element_state)
})
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
view_state: &mut Self::ViewState,
element_state: &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 hover_group_bounds = this
.group_hover
.as_ref()
.and_then(|group_hover| group_bounds(&group_hover.group, cx));
let active_group_bounds = this
.group_active
.as_ref()
.and_then(|group_active| group_bounds(&group_active.group, cx));
let style = this.compute_style(bounds, element_state, cx);
let z_index = style.z_index.unwrap_or(0);
// Paint background and event handlers.
cx.stack(z_index, |cx| {
cx.stack(0, |cx| {
style.paint(bounds, cx);
this.paint_hover_listeners(bounds, hover_group_bounds, cx);
this.paint_active_listener(
bounds,
active_group_bounds,
element_state.active_state.clone(),
cx,
);
this.paint_event_listeners(bounds, element_state.pending_click.clone(), cx);
});
});
style.apply_text_style(cx, |cx| {
style.apply_overflow(bounds, cx, |cx| {
cx.stack(z_index + 1, |cx| {
for child in &mut this.children {
child.paint(view_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> IdentifiedElement for Div<V, IdentifiedElementKind> { impl<V: 'static + Send + Sync> IdentifiedElement for Div<V, IdentifiedElementKind> {
fn id(&self) -> ElementId { fn id(&self) -> ElementId {
IdentifiedElement::id(&self.0) self.kind.0.clone()
}
}
impl<V: 'static + Send + Sync, K: ElementKind> ParentElement for Div<V, K> {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
self.0.children_mut()
}
fn group_mut(&mut self) -> &mut Option<SharedString> {
self.0.group_mut()
}
}
impl<V: 'static + Send + Sync, K: ElementKind> Styled for Div<V, K> {
fn style_cascade(&mut self) -> &mut StyleCascade {
self.0.style_cascade()
}
fn computed_style(&mut self) -> &Style {
self.0.computed_style()
}
}
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 + Send + Sync> Clickable for Div<V, IdentifiedElementKind> {
fn active_style(&mut self) -> &mut StyleRefinement {
self.0.active_style()
}
fn listeners(&mut self) -> &mut ClickListeners<V> {
self.0.listeners()
} }
} }
@ -157,34 +529,80 @@ where
} }
} }
impl<V, K> Element for Div<V, K> impl<V, K> Styled for Div<V, K>
where where
V: 'static + Send + Sync, V: 'static + Send + Sync,
K: ElementKind, K: ElementKind,
{ {
type ViewState = V; fn style(&mut self) -> &mut StyleRefinement {
type ElementState = ClickableElementState<()>; &mut self.base_style
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>,
) -> (LayoutId, Self::ElementState) {
self.0.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>,
) {
self.0.paint(bounds, state, element_state, cx);
} }
} }
pub struct MouseClickEvent {
pub down: MouseDownEvent,
pub up: MouseUpEvent,
}
type MouseDownHandler<V> = Arc<
dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
type MouseUpHandler<V> = Arc<
dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
type MouseClickHandler<V> = Arc<
dyn Fn(&mut V, &MouseClickEvent, &Bounds<Pixels>, &mut ViewContext<V>) + Send + Sync + 'static,
>;
type MouseMoveHandler<V> = Arc<
dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
type ScrollWheelHandler<V> = Arc<
dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
pub struct MouseEventListeners<V: 'static> {
mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
mouse_click: SmallVec<[MouseClickHandler<V>; 2]>,
mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
}
impl<V> Default for MouseEventListeners<V> {
fn default() -> Self {
Self {
mouse_down: SmallVec::new(),
mouse_up: SmallVec::new(),
mouse_click: SmallVec::new(),
mouse_move: SmallVec::new(),
scroll_wheel: SmallVec::new(),
}
}
}
fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
where
V: 'static + Send + Sync,
{
let hovered = bounds.contains_point(&cx.mouse_position());
cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
if phase == DispatchPhase::Capture {
if bounds.contains_point(&event.position) != hovered {
cx.notify();
}
}
});
}

View file

@ -1,498 +0,0 @@
use crate::{
AnonymousElementKind, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element,
ElementId, ElementKind, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, Pixels, Point, ScrollWheelEvent,
SharedString, Style, StyleRefinement, ViewContext,
};
use collections::HashMap;
use parking_lot::Mutex;
use refineable::Refineable;
use smallvec::SmallVec;
use std::sync::Arc;
#[derive(Default)]
pub struct DivState {
active_state: Arc<Mutex<ActiveState>>,
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
}
#[derive(Copy, Clone, Default, Eq, PartialEq)]
struct ActiveState {
group: bool,
element: bool,
}
impl ActiveState {
pub fn is_none(&self) -> bool {
!self.group && !self.element
}
}
#[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())
}
#[derive(Default, Clone)]
pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
impl ScrollState {
pub fn x(&self) -> Pixels {
self.0.lock().x
}
pub fn set_x(&self, value: Pixels) {
self.0.lock().x = value;
}
pub fn y(&self) -> Pixels {
self.0.lock().y
}
pub fn set_y(&self, value: Pixels) {
self.0.lock().y = value;
}
}
pub fn div<S>() -> Div<S, AnonymousElementKind>
where
S: 'static + Send + Sync,
{
Div {
kind: AnonymousElementKind,
children: SmallVec::new(),
group: None,
base_style: StyleRefinement::default(),
hover_style: StyleRefinement::default(),
group_hover: None,
active_style: StyleRefinement::default(),
group_active: None,
listeners: MouseEventListeners::default(),
}
}
pub struct Div<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
kind: K,
children: SmallVec<[AnyElement<V>; 2]>,
group: Option<SharedString>,
base_style: StyleRefinement,
hover_style: StyleRefinement,
group_hover: Option<GroupStyle>,
active_style: StyleRefinement,
group_active: Option<GroupStyle>,
listeners: MouseEventListeners<V>,
}
struct GroupStyle {
group: SharedString,
style: StyleRefinement,
}
impl<V> Div<V, AnonymousElementKind>
where
V: 'static + Send + Sync,
{
pub fn id(self, id: ElementId) -> Div<V, IdentifiedElementKind> {
Div {
kind: IdentifiedElementKind(id),
children: self.children,
group: self.group,
base_style: self.base_style,
hover_style: self.hover_style,
group_hover: self.group_hover,
active_style: self.active_style,
group_active: self.group_active,
listeners: self.listeners,
}
}
}
impl<V, K> Div<V, K>
where
V: 'static + Send + Sync,
K: ElementKind,
{
pub fn group(mut self, group: impl Into<SharedString>) -> Self {
self.group = Some(group.into());
self
}
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 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)
}
}
fn compute_style(
&self,
bounds: Bounds<Pixels>,
group_bounds: Option<Bounds<Pixels>>,
active_state: ActiveState,
cx: &mut ViewContext<V>,
) -> Style {
let mut computed_style = Style::default();
computed_style.refine(&self.base_style);
let mouse_position = cx.mouse_position();
if let Some(group_bounds) = group_bounds {
if group_bounds.contains_point(mouse_position) {
if let Some(GroupStyle { style, .. }) = self.group_hover.as_ref() {
computed_style.refine(style);
}
}
}
if bounds.contains_point(mouse_position) {
computed_style.refine(&self.hover_style);
}
if active_state.group {
if let Some(GroupStyle { style, .. }) = self.group_active.as_ref() {
computed_style.refine(style);
}
}
if active_state.element {
computed_style.refine(&self.active_style);
}
computed_style
}
fn paint_hover_listeners(
&self,
bounds: Bounds<Pixels>,
group_bounds: Option<Bounds<Pixels>>,
cx: &mut ViewContext<V>,
) {
if let Some(group_bounds) = group_bounds {
paint_hover_listener(group_bounds, cx);
}
if self.hover_style.is_some() {
paint_hover_listener(bounds, cx);
}
}
fn paint_active_listener(
&self,
bounds: Bounds<Pixels>,
group_bounds: Option<Bounds<Pixels>>,
active_state: Arc<Mutex<ActiveState>>,
cx: &mut ViewContext<V>,
) {
if active_state.lock().is_none() {
cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble {
let group =
group_bounds.map_or(false, |bounds| bounds.contains_point(down.position));
let element = bounds.contains_point(down.position);
if group || element {
*active_state.lock() = ActiveState { group, element };
cx.notify();
}
}
});
} else {
cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
if phase == DispatchPhase::Capture {
*active_state.lock() = ActiveState::default();
cx.notify();
}
});
}
}
fn paint_event_listeners(
&self,
bounds: Bounds<Pixels>,
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
cx: &mut ViewContext<V>,
) {
let click_listeners = self.listeners.mouse_click.clone();
let mouse_down = pending_click.lock().clone();
if let Some(mouse_down) = mouse_down {
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
let mouse_click = MouseClickEvent {
down: mouse_down.clone(),
up: event.clone(),
};
for listener in &click_listeners {
listener(state, &mouse_click, &bounds, cx);
}
}
*pending_click.lock() = None;
});
} else {
cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
*pending_click.lock() = Some(event.clone());
}
});
}
for listener in self.listeners.mouse_down.iter().cloned() {
cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
}
for listener in self.listeners.mouse_up.iter().cloned() {
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
}
for listener in self.listeners.mouse_move.iter().cloned() {
cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
}
for listener in self.listeners.scroll_wheel.iter().cloned() {
cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
}
}
}
impl<V, K> Element for Div<V, K>
where
V: 'static + Send + Sync,
K: ElementKind,
{
type ViewState = V;
type ElementState = DivState;
fn id(&self) -> Option<ElementId> {
self.kind.id()
}
fn layout(
&mut self,
view_state: &mut Self::ViewState,
element_state: 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(view_state, cx))
.collect::<Vec<_>>();
let element_state = element_state.unwrap_or_default();
let style = this.compute_style(
Bounds::default(),
None,
*element_state.active_state.lock(),
cx,
);
let layout_id = cx.request_layout(&style, layout_ids);
(layout_id, element_state)
})
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
view_state: &mut Self::ViewState,
element_state: &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 hover_group_bounds = this
.group_hover
.as_ref()
.and_then(|group_hover| group_bounds(&group_hover.group, cx));
let active_group_bounds = this
.group_active
.as_ref()
.and_then(|group_active| group_bounds(&group_active.group, cx));
let active_state = *element_state.active_state.lock();
let style = this.compute_style(bounds, hover_group_bounds, active_state, cx);
let z_index = style.z_index.unwrap_or(0);
// Paint background and event handlers.
cx.stack(z_index, |cx| {
cx.stack(0, |cx| {
style.paint(bounds, cx);
this.paint_hover_listeners(bounds, hover_group_bounds, cx);
this.paint_active_listener(
bounds,
active_group_bounds,
element_state.active_state.clone(),
cx,
);
this.paint_event_listeners(bounds, element_state.pending_click.clone(), cx);
});
});
style.apply_text_style(cx, |cx| {
style.apply_overflow(bounds, cx, |cx| {
cx.stack(z_index + 1, |cx| {
for child in &mut this.children {
child.paint(view_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> IdentifiedElement for Div<V, IdentifiedElementKind> {
fn id(&self) -> ElementId {
self.kind.0.clone()
}
}
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 struct MouseClickEvent {
pub down: MouseDownEvent,
pub up: MouseUpEvent,
}
type MouseDownHandler<V> = Arc<
dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
type MouseUpHandler<V> = Arc<
dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
type MouseClickHandler<V> = Arc<
dyn Fn(&mut V, &MouseClickEvent, &Bounds<Pixels>, &mut ViewContext<V>) + Send + Sync + 'static,
>;
type MouseMoveHandler<V> = Arc<
dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
type ScrollWheelHandler<V> = Arc<
dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
pub struct MouseEventListeners<V: 'static> {
mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
mouse_click: SmallVec<[MouseClickHandler<V>; 2]>,
mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
}
impl<V> Default for MouseEventListeners<V> {
fn default() -> Self {
Self {
mouse_down: SmallVec::new(),
mouse_up: SmallVec::new(),
mouse_click: SmallVec::new(),
mouse_move: SmallVec::new(),
scroll_wheel: SmallVec::new(),
}
}
}
fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
where
V: 'static + Send + Sync,
{
let hovered = bounds.contains_point(cx.mouse_position());
cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
if phase == DispatchPhase::Capture {
if bounds.contains_point(event.position) != hovered {
cx.notify();
}
}
});
}

View file

@ -1,149 +0,0 @@
use crate::{
group_bounds, AnyElement, Bounds, DispatchPhase, Element, ElementId, IdentifiedElement,
IntoAnyElement, LayoutId, MouseMoveEvent, ParentElement, Pixels, SharedString, Style,
StyleCascade, StyleRefinement, Styled, ViewContext,
};
use refineable::CascadeSlot;
use std::sync::{
atomic::{AtomicBool, Ordering::SeqCst},
Arc,
};
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
}
}
pub 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 new(mut child: E) -> Self {
let cascade_slot = child.style_cascade().reserve();
HoverableElement {
hover_style: StyleRefinement::default(),
group: None,
cascade_slot,
hovered: Arc::new(AtomicBool::new(false)),
child,
}
}
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 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>,
) -> (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>,
) {
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> ParentElement for HoverableElement<E>
where
E: Styled + ParentElement,
{
fn children_mut(&mut self) -> &mut smallvec::SmallVec<[AnyElement<E::ViewState>; 2]> {
self.child.children_mut()
}
fn group_mut(&mut self) -> &mut Option<SharedString> {
self.child.group_mut()
}
}
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> {}

View file

@ -1,15 +1,13 @@
use crate::{ use crate::{
AnonymousElementKind, AnyElement, BorrowWindow, Bounds, ClickListeners, Clickable, div, AnonymousElementKind, AnyElement, BorrowWindow, Bounds, Div, DivState, Element, ElementId,
ClickableElement, ClickableElementState, Element, ElementId, ElementKind, Hoverable, ElementKind, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, Pixels,
HoverableElement, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, SharedString, StyleRefinement, Styled, ViewContext,
LayoutNodeElement, Pixels, SharedString, Style, StyleRefinement, Styled, ViewContext,
}; };
use futures::FutureExt; use futures::FutureExt;
use refineable::Cascade;
use util::ResultExt; use util::ResultExt;
pub struct Img<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> { pub struct Img<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
layout_node: ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>, base: Div<V, K>,
uri: Option<SharedString>, uri: Option<SharedString>,
grayscale: bool, grayscale: bool,
} }
@ -19,7 +17,7 @@ where
V: 'static + Send + Sync, V: 'static + Send + Sync,
{ {
Img { Img {
layout_node: ClickableElement::new(HoverableElement::new(LayoutNodeElement::new())), base: div(),
uri: None, uri: None,
grayscale: false, grayscale: false,
} }
@ -44,9 +42,7 @@ where
impl<V: 'static + Send + Sync> Img<V, AnonymousElementKind> { impl<V: 'static + Send + Sync> Img<V, AnonymousElementKind> {
pub fn id(self, id: impl Into<ElementId>) -> Img<V, IdentifiedElementKind> { pub fn id(self, id: impl Into<ElementId>) -> Img<V, IdentifiedElementKind> {
Img { Img {
layout_node: self.layout_node.replace_child(|hoverable| { base: self.base.id(id),
hoverable.replace_child(|layout_node| layout_node.identify(id))
}),
uri: self.uri, uri: self.uri,
grayscale: self.grayscale, grayscale: self.grayscale,
} }
@ -69,10 +65,10 @@ where
K: ElementKind, K: ElementKind,
{ {
type ViewState = V; type ViewState = V;
type ElementState = ClickableElementState<()>; type ElementState = DivState;
fn id(&self) -> Option<crate::ElementId> { fn id(&self) -> Option<crate::ElementId> {
self.layout_node.id() self.base.id()
} }
fn layout( fn layout(
@ -84,7 +80,7 @@ where
where where
Self: Sized, Self: Sized,
{ {
self.layout_node.layout(view_state, element_state, cx) self.base.layout(view_state, element_state, cx)
} }
fn paint( fn paint(
@ -95,10 +91,10 @@ where
cx: &mut ViewContext<Self::ViewState>, cx: &mut ViewContext<Self::ViewState>,
) { ) {
cx.stack(1, |cx| { cx.stack(1, |cx| {
self.layout_node.paint(bounds, view, element_state, cx); self.base.paint(bounds, view, element_state, cx);
}); });
let style = self.computed_style(); let style = self.base.compute_style(bounds, element_state, cx);
let corner_radii = style.corner_radii; let corner_radii = style.corner_radii;
if let Some(uri) = self.uri.clone() { if let Some(uri) = self.uri.clone() {
@ -127,7 +123,7 @@ where
impl<V: 'static + Send + Sync> IdentifiedElement for Img<V, IdentifiedElementKind> { impl<V: 'static + Send + Sync> IdentifiedElement for Img<V, IdentifiedElementKind> {
fn id(&self) -> ElementId { fn id(&self) -> ElementId {
IdentifiedElement::id(&self.layout_node) IdentifiedElement::id(&self.base)
} }
} }
@ -136,27 +132,7 @@ where
V: 'static + Send + Sync, V: 'static + Send + Sync,
K: ElementKind, K: ElementKind,
{ {
fn style_cascade(&mut self) -> &mut Cascade<Style> { fn style(&mut self) -> &mut StyleRefinement {
self.layout_node.style_cascade() self.base.style()
}
fn computed_style(&mut self) -> &Style {
self.layout_node.computed_style()
}
}
impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Img<V, K> {
fn hover_style(&mut self) -> &mut StyleRefinement {
self.layout_node.hover_style()
}
}
impl<V: 'static + Send + Sync> Clickable for Img<V, IdentifiedElementKind> {
fn active_style(&mut self) -> &mut StyleRefinement {
self.layout_node.active_style()
}
fn listeners(&mut self) -> &mut ClickListeners<V> {
self.layout_node.listeners()
} }
} }

View file

@ -1,193 +0,0 @@
use crate::{
AnyElement, AppContext, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement,
IntoAnyElement, LayoutId, ParentElement, 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 ElementKind: 'static + Send + Sync {
fn id(&self) -> Option<ElementId>;
}
pub struct IdentifiedElementKind(pub(crate) 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 new() -> LayoutNodeElement<V, AnonymousElementKind> {
LayoutNodeElement {
style_cascade: StyleCascade::default(),
computed_style: None,
children: SmallVec::new(),
kind: AnonymousElementKind,
group: None,
}
}
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> ParentElement 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
}
}

View file

@ -1,14 +1,12 @@
use crate::{ use crate::{
AnonymousElementKind, AnyElement, Bounds, ClickListeners, Clickable, ClickableElement, div, AnonymousElementKind, AnyElement, Bounds, Div, DivState, Element, ElementId, ElementKind,
ClickableElementState, Element, ElementId, ElementKind, Hoverable, HoverableElement, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, Pixels, SharedString,
IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, LayoutNodeElement, Pixels, StyleRefinement, Styled,
SharedString, Style, StyleRefinement, Styled,
}; };
use refineable::Cascade;
use util::ResultExt; use util::ResultExt;
pub struct Svg<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> { pub struct Svg<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
layout_node: ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>, base: Div<V, K>,
path: Option<SharedString>, path: Option<SharedString>,
} }
@ -17,7 +15,7 @@ where
V: 'static + Send + Sync, V: 'static + Send + Sync,
{ {
Svg { Svg {
layout_node: ClickableElement::new(HoverableElement::new(LayoutNodeElement::new())), base: div(),
path: None, path: None,
} }
} }
@ -36,9 +34,7 @@ where
impl<V: 'static + Send + Sync> Svg<V, AnonymousElementKind> { impl<V: 'static + Send + Sync> Svg<V, AnonymousElementKind> {
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, IdentifiedElementKind> { pub fn id(self, id: impl Into<ElementId>) -> Svg<V, IdentifiedElementKind> {
Svg { Svg {
layout_node: self.layout_node.replace_child(|hoverable| { base: self.base.id(id),
hoverable.replace_child(|layout_node| layout_node.identify(id))
}),
path: self.path, path: self.path,
} }
} }
@ -60,10 +56,10 @@ where
K: ElementKind, K: ElementKind,
{ {
type ViewState = V; type ViewState = V;
type ElementState = ClickableElementState<()>; type ElementState = DivState;
fn id(&self) -> Option<crate::ElementId> { fn id(&self) -> Option<crate::ElementId> {
self.layout_node.id() self.base.id()
} }
fn layout( fn layout(
@ -75,7 +71,7 @@ where
where where
Self: Sized, Self: Sized,
{ {
self.layout_node.layout(view, element_state, cx) self.base.layout(view, element_state, cx)
} }
fn paint( fn paint(
@ -87,9 +83,10 @@ where
) where ) where
Self: Sized, Self: Sized,
{ {
self.layout_node.paint(bounds, view, element_state, cx); self.base.paint(bounds, view, element_state, cx);
let fill_color = self let fill_color = self
.computed_style() .base
.compute_style(bounds, element_state, cx)
.fill .fill
.as_ref() .as_ref()
.and_then(|fill| fill.color()); .and_then(|fill| fill.color());
@ -101,7 +98,7 @@ where
impl<V: 'static + Send + Sync> IdentifiedElement for Svg<V, IdentifiedElementKind> { impl<V: 'static + Send + Sync> IdentifiedElement for Svg<V, IdentifiedElementKind> {
fn id(&self) -> ElementId { fn id(&self) -> ElementId {
IdentifiedElement::id(&self.layout_node) IdentifiedElement::id(&self.base)
} }
} }
@ -110,27 +107,7 @@ where
V: 'static + Send + Sync, V: 'static + Send + Sync,
K: ElementKind, K: ElementKind,
{ {
fn style_cascade(&mut self) -> &mut Cascade<Style> { fn style(&mut self) -> &mut StyleRefinement {
self.layout_node.style_cascade() self.base.style()
}
fn computed_style(&mut self) -> &Style {
self.layout_node.computed_style()
}
}
impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Svg<V, K> {
fn hover_style(&mut self) -> &mut StyleRefinement {
self.layout_node.hover_style()
}
}
impl<V: 'static + Send + Sync> Clickable for Svg<V, IdentifiedElementKind> {
fn active_style(&mut self) -> &mut StyleRefinement {
self.layout_node.active_style()
}
fn listeners(&mut self) -> &mut ClickListeners<V> {
self.layout_node.listeners()
} }
} }

View file

@ -413,7 +413,7 @@ impl<T> Bounds<T>
where where
T: Add<T, Output = T> + PartialOrd + Clone + Default + Debug, T: Add<T, Output = T> + PartialOrd + Clone + Default + Debug,
{ {
pub fn contains_point(&self, point: Point<T>) -> bool { pub fn contains_point(&self, point: &Point<T>) -> bool {
point.x >= self.origin.x point.x >= self.origin.x
&& point.x <= self.origin.x.clone() + self.size.width.clone() && point.x <= self.origin.x.clone() + self.size.width.clone()
&& point.y >= self.origin.y && point.y >= self.origin.y

View file

@ -7,7 +7,6 @@ mod events;
mod executor; mod executor;
mod geometry; mod geometry;
mod image_cache; mod image_cache;
mod interactive;
mod platform; mod platform;
mod scene; mod scene;
mod style; mod style;
@ -31,7 +30,6 @@ pub use executor::*;
pub use geometry::*; pub use geometry::*;
pub use gpui3_macros::*; pub use gpui3_macros::*;
pub use image_cache::*; pub use image_cache::*;
pub use interactive::*;
pub use platform::*; pub use platform::*;
pub use refineable::*; pub use refineable::*;
pub use scene::*; pub use scene::*;

View file

@ -1,198 +0,0 @@
use crate::{
Bounds, DispatchPhase, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
ScrollWheelEvent, ViewContext,
};
use smallvec::SmallVec;
use std::sync::Arc;
pub trait Interactive<S: 'static + Send + Sync> {
fn listeners(&mut self) -> &mut MouseEventListeners<S>;
fn on_mouse_down(
mut self,
button: MouseButton,
handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
) -> Self
where
Self: Sized,
{
self.listeners()
.mouse_down
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble
&& event.button == button
&& bounds.contains_point(event.position)
{
handler(view, event, cx)
}
}));
self
}
fn on_mouse_up(
mut self,
button: MouseButton,
handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
) -> Self
where
Self: Sized,
{
self.listeners()
.mouse_up
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble
&& event.button == button
&& bounds.contains_point(event.position)
{
handler(view, event, cx)
}
}));
self
}
fn on_mouse_down_out(
mut self,
button: MouseButton,
handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
) -> Self
where
Self: Sized,
{
self.listeners()
.mouse_down
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Capture
&& event.button == button
&& !bounds.contains_point(event.position)
{
handler(view, event, cx)
}
}));
self
}
fn on_mouse_up_out(
mut self,
button: MouseButton,
handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
) -> Self
where
Self: Sized,
{
self.listeners()
.mouse_up
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Capture
&& event.button == button
&& !bounds.contains_point(event.position)
{
handler(view, event, cx);
}
}));
self
}
fn on_mouse_move(
mut self,
handler: impl Fn(&mut S, &MouseMoveEvent, &mut ViewContext<S>) + Send + Sync + 'static,
) -> Self
where
Self: Sized,
{
self.listeners()
.mouse_move
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
handler(view, event, cx);
}
}));
self
}
fn on_scroll_wheel(
mut self,
handler: impl Fn(&mut S, &ScrollWheelEvent, &mut ViewContext<S>) + Send + Sync + 'static,
) -> Self
where
Self: Sized,
{
self.listeners()
.scroll_wheel
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
handler(view, event, cx);
}
}));
self
}
}
type MouseDownHandler<V> = Arc<
dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
type MouseUpHandler<V> = Arc<
dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
type MouseMoveHandler<V> = Arc<
dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
type ScrollWheelHandler<V> = Arc<
dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ Send
+ Sync
+ 'static,
>;
pub struct MouseEventListeners<V: 'static> {
mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
}
impl<S: Send + Sync + 'static> MouseEventListeners<S> {
pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<S>) {
for handler in self.mouse_down.iter().cloned() {
cx.on_mouse_event(move |view, event: &MouseDownEvent, phase, cx| {
handler(view, event, &bounds, phase, cx);
})
}
for handler in self.mouse_up.iter().cloned() {
cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
handler(view, event, &bounds, phase, cx);
})
}
for handler in self.mouse_move.iter().cloned() {
cx.on_mouse_event(move |view, event: &MouseMoveEvent, phase, cx| {
handler(view, event, &bounds, phase, cx);
})
}
for handler in self.scroll_wheel.iter().cloned() {
cx.on_mouse_event(move |view, event: &ScrollWheelEvent, phase, cx| {
handler(view, event, &bounds, phase, cx);
})
}
}
}
impl<V> Default for MouseEventListeners<V> {
fn default() -> Self {
Self {
mouse_down: Default::default(),
mouse_up: Default::default(),
mouse_move: Default::default(),
scroll_wheel: Default::default(),
}
}
}

View file

@ -1,16 +1,12 @@
use crate::{ use crate::{
self as gpui3, hsla, point, px, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla, self as gpui3, hsla, point, px, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla,
JustifyContent, Length, Position, SharedString, Style, StyleCascade, StyleRefinement, JustifyContent, Length, Position, SharedString, StyleRefinement,
}; };
use crate::{BoxShadow, TextStyleRefinement}; use crate::{BoxShadow, TextStyleRefinement};
use smallvec::smallvec; use smallvec::smallvec;
pub trait Styled { pub trait Styled {
fn style_cascade(&mut self) -> &mut StyleCascade; fn style(&mut self) -> &mut StyleRefinement;
fn computed_style(&mut self) -> &Style;
fn base_style(&mut self) -> &mut StyleRefinement {
self.style_cascade().base()
}
gpui3_macros::style_helpers!(); gpui3_macros::style_helpers!();
@ -18,8 +14,8 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().size.width = Some(relative(1.).into()); self.style().size.width = Some(relative(1.).into());
self.base_style().size.height = Some(relative(1.).into()); self.style().size.height = Some(relative(1.).into());
self self
} }
@ -27,7 +23,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().position = Some(Position::Relative); self.style().position = Some(Position::Relative);
self self
} }
@ -35,7 +31,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().position = Some(Position::Absolute); self.style().position = Some(Position::Absolute);
self self
} }
@ -43,7 +39,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().display = Some(Display::Block); self.style().display = Some(Display::Block);
self self
} }
@ -51,7 +47,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().display = Some(Display::Flex); self.style().display = Some(Display::Flex);
self self
} }
@ -59,7 +55,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().flex_direction = Some(FlexDirection::Column); self.style().flex_direction = Some(FlexDirection::Column);
self self
} }
@ -67,7 +63,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().flex_direction = Some(FlexDirection::Row); self.style().flex_direction = Some(FlexDirection::Row);
self self
} }
@ -75,9 +71,9 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().flex_grow = Some(1.); self.style().flex_grow = Some(1.);
self.base_style().flex_shrink = Some(1.); self.style().flex_shrink = Some(1.);
self.base_style().flex_basis = Some(relative(0.).into()); self.style().flex_basis = Some(relative(0.).into());
self self
} }
@ -85,9 +81,9 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().flex_grow = Some(1.); self.style().flex_grow = Some(1.);
self.base_style().flex_shrink = Some(1.); self.style().flex_shrink = Some(1.);
self.base_style().flex_basis = Some(Length::Auto); self.style().flex_basis = Some(Length::Auto);
self self
} }
@ -95,9 +91,9 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().flex_grow = Some(0.); self.style().flex_grow = Some(0.);
self.base_style().flex_shrink = Some(1.); self.style().flex_shrink = Some(1.);
self.base_style().flex_basis = Some(Length::Auto); self.style().flex_basis = Some(Length::Auto);
self self
} }
@ -105,8 +101,8 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().flex_grow = Some(0.); self.style().flex_grow = Some(0.);
self.base_style().flex_shrink = Some(0.); self.style().flex_shrink = Some(0.);
self self
} }
@ -114,7 +110,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().flex_grow = Some(1.); self.style().flex_grow = Some(1.);
self self
} }
@ -122,7 +118,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().align_items = Some(AlignItems::FlexStart); self.style().align_items = Some(AlignItems::FlexStart);
self self
} }
@ -130,7 +126,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().align_items = Some(AlignItems::FlexEnd); self.style().align_items = Some(AlignItems::FlexEnd);
self self
} }
@ -138,7 +134,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().align_items = Some(AlignItems::Center); self.style().align_items = Some(AlignItems::Center);
self self
} }
@ -146,7 +142,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().justify_content = Some(JustifyContent::SpaceBetween); self.style().justify_content = Some(JustifyContent::SpaceBetween);
self self
} }
@ -154,7 +150,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().justify_content = Some(JustifyContent::Center); self.style().justify_content = Some(JustifyContent::Center);
self self
} }
@ -162,7 +158,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().justify_content = Some(JustifyContent::Start); self.style().justify_content = Some(JustifyContent::Start);
self self
} }
@ -170,7 +166,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().justify_content = Some(JustifyContent::End); self.style().justify_content = Some(JustifyContent::End);
self self
} }
@ -178,7 +174,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().justify_content = Some(JustifyContent::SpaceAround); self.style().justify_content = Some(JustifyContent::SpaceAround);
self self
} }
@ -187,7 +183,7 @@ pub trait Styled {
F: Into<Fill>, F: Into<Fill>,
Self: Sized, Self: Sized,
{ {
self.base_style().fill = Some(fill.into()); self.style().fill = Some(fill.into());
self self
} }
@ -196,7 +192,7 @@ pub trait Styled {
C: Into<Hsla>, C: Into<Hsla>,
Self: Sized, Self: Sized,
{ {
self.base_style().border_color = Some(border_color.into()); self.style().border_color = Some(border_color.into());
self self
} }
@ -204,7 +200,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().box_shadow = Some(smallvec![ self.style().box_shadow = Some(smallvec![
BoxShadow { BoxShadow {
color: hsla(0., 0., 0., 0.1), color: hsla(0., 0., 0., 0.1),
offset: point(px(0.), px(1.)), offset: point(px(0.), px(1.)),
@ -225,7 +221,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().box_shadow = Some(Default::default()); self.style().box_shadow = Some(Default::default());
self self
} }
@ -233,7 +229,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().box_shadow = Some(smallvec::smallvec![BoxShadow { self.style().box_shadow = Some(smallvec::smallvec![BoxShadow {
color: hsla(0., 0., 0., 0.05), color: hsla(0., 0., 0., 0.05),
offset: point(px(0.), px(1.)), offset: point(px(0.), px(1.)),
blur_radius: px(2.), blur_radius: px(2.),
@ -246,7 +242,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().box_shadow = Some(smallvec![ self.style().box_shadow = Some(smallvec![
BoxShadow { BoxShadow {
color: hsla(0.5, 0., 0., 0.1), color: hsla(0.5, 0., 0., 0.1),
offset: point(px(0.), px(4.)), offset: point(px(0.), px(4.)),
@ -267,7 +263,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().box_shadow = Some(smallvec![ self.style().box_shadow = Some(smallvec![
BoxShadow { BoxShadow {
color: hsla(0., 0., 0., 0.1), color: hsla(0., 0., 0., 0.1),
offset: point(px(0.), px(10.)), offset: point(px(0.), px(10.)),
@ -288,7 +284,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().box_shadow = Some(smallvec![ self.style().box_shadow = Some(smallvec![
BoxShadow { BoxShadow {
color: hsla(0., 0., 0., 0.1), color: hsla(0., 0., 0., 0.1),
offset: point(px(0.), px(20.)), offset: point(px(0.), px(20.)),
@ -309,7 +305,7 @@ pub trait Styled {
where where
Self: Sized, Self: Sized,
{ {
self.base_style().box_shadow = Some(smallvec![BoxShadow { self.style().box_shadow = Some(smallvec![BoxShadow {
color: hsla(0., 0., 0., 0.25), color: hsla(0., 0., 0., 0.25),
offset: point(px(0.), px(25.)), offset: point(px(0.), px(25.)),
blur_radius: px(50.), blur_radius: px(50.),
@ -319,7 +315,7 @@ pub trait Styled {
} }
fn text_style(&mut self) -> &mut Option<TextStyleRefinement> { fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
let style: &mut StyleRefinement = self.base_style(); let style: &mut StyleRefinement = self.style();
&mut style.text &mut style.text
} }

View file

@ -129,7 +129,7 @@ fn generate_predefined_setter(
let method = quote! { let method = quote! {
#[doc = #doc_string] #[doc = #doc_string]
fn #method_name(mut self) -> Self where Self: std::marker::Sized { fn #method_name(mut self) -> Self where Self: std::marker::Sized {
let mut style = self.base_style(); let style = self.style();
#(#field_assignments)* #(#field_assignments)*
self self
} }
@ -160,7 +160,7 @@ fn generate_custom_value_setter(
let method = quote! { let method = quote! {
fn #method_name(mut self, length: impl std::clone::Clone + Into<gpui3::#length_type>) -> Self where Self: std::marker::Sized { fn #method_name(mut self, length: impl std::clone::Clone + Into<gpui3::#length_type>) -> Self where Self: std::marker::Sized {
let mut style = self.base_style(); let style = self.style();
#(#field_assignments)* #(#field_assignments)*
self self
} }