WIP
This commit is contained in:
parent
18abb068b1
commit
488d08b43c
16 changed files with 1093 additions and 1591 deletions
|
@ -1,9 +1,4 @@
|
||||||
use std::sync::Arc;
|
use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, ViewContext};
|
||||||
|
|
||||||
use crate::{
|
|
||||||
BorrowWindow, Bounds, Clickable, ElementId, Group, LayoutId, MouseDownEvent, MouseUpEvent,
|
|
||||||
Pixels, Point, SharedString, ViewContext,
|
|
||||||
};
|
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
pub(crate) use smallvec::SmallVec;
|
pub(crate) use smallvec::SmallVec;
|
||||||
|
|
||||||
|
@ -27,35 +22,12 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
|
||||||
element_state: &mut Self::ElementState,
|
element_state: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<Self::ViewState>,
|
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 {
|
pub trait IdentifiedElement: Element {
|
||||||
fn element_id(&self) -> ElementId {
|
fn id(&self) -> ElementId {
|
||||||
Element::id(self).unwrap()
|
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)]
|
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
|
|
@ -1,20 +1,15 @@
|
||||||
mod clickable;
|
mod clickable;
|
||||||
mod div;
|
mod div;
|
||||||
mod group;
|
|
||||||
mod hoverable;
|
mod hoverable;
|
||||||
mod identified;
|
|
||||||
mod img;
|
mod img;
|
||||||
mod nested;
|
mod layout_node;
|
||||||
mod pressable;
|
|
||||||
mod svg;
|
mod svg;
|
||||||
mod text;
|
mod text;
|
||||||
|
|
||||||
pub use clickable::*;
|
pub use clickable::*;
|
||||||
pub use div::*;
|
pub use div::*;
|
||||||
pub use group::*;
|
|
||||||
pub use hoverable::*;
|
pub use hoverable::*;
|
||||||
pub use identified::*;
|
|
||||||
pub use img::*;
|
pub use img::*;
|
||||||
pub use pressable::*;
|
pub use layout_node::*;
|
||||||
pub use svg::*;
|
pub use svg::*;
|
||||||
pub use text::*;
|
pub use text::*;
|
||||||
|
|
|
@ -1,71 +1,90 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, Bounds, DispatchPhase, Element, IdentifiedElement, Interactive, IntoAnyElement,
|
AnyElement, Bounds, DispatchPhase, Element, ElementId, ElementKind, Hoverable,
|
||||||
MouseDownEvent, MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext,
|
IdentifiedElement, IntoAnyElement, LayoutId, LayoutNode, MouseDownEvent, MouseUpEvent, Pixels,
|
||||||
|
SharedString, StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use refineable::Cascade;
|
use refineable::CascadeSlot;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub type ClickListener<S> =
|
pub trait Clickable: Element + Sized {
|
||||||
dyn Fn(&mut S, (&MouseDownEvent, &MouseUpEvent), &mut ViewContext<S>) + Send + Sync + 'static;
|
fn active_style(&mut self) -> &mut StyleRefinement;
|
||||||
|
fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState>;
|
||||||
|
|
||||||
pub struct Clickable<E: Element> {
|
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,
|
child: E,
|
||||||
listener: Arc<ClickListener<E::ViewState>>,
|
listeners: ClickListeners<E::ViewState>,
|
||||||
|
active_style: StyleRefinement,
|
||||||
|
cascade_slot: CascadeSlot,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClickableState<S> {
|
impl<E: Element> ClickableElement<E> {
|
||||||
last_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
|
pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
|
||||||
child_state: S,
|
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: Element> Clickable<E> {
|
|
||||||
pub fn new(child: E, listener: Arc<ClickListener<E::ViewState>>) -> Self {
|
|
||||||
Self { child, listener }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> Styled for Clickable<E>
|
impl<E> IntoAnyElement<E::ViewState> for ClickableElement<E>
|
||||||
where
|
where
|
||||||
E: Styled + IdentifiedElement,
|
E: Styled + Element,
|
||||||
{
|
{
|
||||||
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, E> Interactive<S> for Clickable<E>
|
|
||||||
where
|
|
||||||
S: 'static + Send + Sync,
|
|
||||||
E: IdentifiedElement + Interactive<S>,
|
|
||||||
{
|
|
||||||
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> {
|
fn into_any(self) -> AnyElement<E::ViewState> {
|
||||||
AnyElement::new(self)
|
AnyElement::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> Element for Clickable<E>
|
impl<E> Element for ClickableElement<E>
|
||||||
where
|
where
|
||||||
E: IdentifiedElement,
|
E: Styled + Element,
|
||||||
{
|
{
|
||||||
type ViewState = E::ViewState;
|
type ViewState = E::ViewState;
|
||||||
type ElementState = ClickableState<E::ElementState>;
|
type ElementState = ClickableElementState<E::ElementState>;
|
||||||
|
|
||||||
fn id(&self) -> Option<crate::ElementId> {
|
fn id(&self) -> Option<ElementId> {
|
||||||
Some(IdentifiedElement::element_id(&self.child))
|
self.child.id()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
|
@ -73,24 +92,33 @@ where
|
||||||
state: &mut Self::ViewState,
|
state: &mut Self::ViewState,
|
||||||
element_state: Option<Self::ElementState>,
|
element_state: Option<Self::ElementState>,
|
||||||
cx: &mut ViewContext<Self::ViewState>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) -> (crate::LayoutId, Self::ElementState) {
|
) -> (LayoutId, Self::ElementState) {
|
||||||
if let Some(element_state) = element_state {
|
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) =
|
let (layout_id, child_state) =
|
||||||
self.child
|
self.child
|
||||||
.layout(state, Some(element_state.child_state), cx);
|
.layout(state, Some(element_state.child_state), cx);
|
||||||
|
(
|
||||||
let element_state = ClickableState {
|
layout_id,
|
||||||
last_mouse_down: element_state.last_mouse_down,
|
ClickableElementState {
|
||||||
|
mouse_down: element_state.mouse_down,
|
||||||
child_state,
|
child_state,
|
||||||
};
|
},
|
||||||
(layout_id, element_state)
|
)
|
||||||
} else {
|
} else {
|
||||||
let (layout_id, child_state) = self.child.layout(state, None, cx);
|
let (layout_id, child_state) = self.child.layout(state, None, cx);
|
||||||
let element_state = ClickableState {
|
(
|
||||||
last_mouse_down: Default::default(),
|
layout_id,
|
||||||
|
ClickableElementState {
|
||||||
|
mouse_down: Default::default(),
|
||||||
child_state,
|
child_state,
|
||||||
};
|
},
|
||||||
(layout_id, element_state)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,31 +129,39 @@ where
|
||||||
element_state: &mut Self::ElementState,
|
element_state: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<Self::ViewState>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) {
|
) {
|
||||||
let last_mouse_down = element_state.last_mouse_down.clone();
|
if !self.listeners.is_empty() || self.active_style.is_some() {
|
||||||
let is_some = last_mouse_down.lock().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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if is_some {
|
mouse_down_mutex.lock().take();
|
||||||
let listener = self.listener.clone();
|
cx.notify();
|
||||||
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 {
|
} else {
|
||||||
log::error!("No mouse down event found for click event");
|
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();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
|
||||||
} 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.child
|
self.child
|
||||||
|
@ -133,12 +169,53 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: IdentifiedElement + ParentElement> ParentElement for Clickable<E> {
|
impl<E: Styled + IdentifiedElement> IdentifiedElement for ClickableElement<E> {}
|
||||||
type State = E::State;
|
|
||||||
|
|
||||||
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()
|
self.child.children_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn group_mut(&mut self) -> &mut Option<SharedString> {
|
||||||
|
self.child.group_mut()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> IdentifiedElement for Clickable<E> where E: IdentifiedElement + Styled {}
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,228 +1,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, BorrowWindow, Bounds, Cascade, Element, ElementId, IdentifiedElement, Interactive,
|
AnonymousElementKind, AnyElement, Bounds, Clickable, ClickableElement, ClickableElementState,
|
||||||
IntoAnyElement, LayoutId, MouseEventListeners, Overflow, ParentElement, Pixels, Point,
|
Element, ElementId, ElementKind, Hoverable, HoverableElement, IdentifiedElementKind,
|
||||||
Refineable, Style, Styled, ViewContext,
|
IntoAnyElement, LayoutId, LayoutNode, LayoutNodeElement, Overflow, Pixels, Point, SharedString,
|
||||||
|
Style, StyleCascade, StyleRefinement, Styled, ViewContext, ClickListeners,
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use smallvec::SmallVec;
|
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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<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()
|
|
||||||
}
|
|
||||||
|
|
||||||
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, ())
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
});
|
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn overflow_hidden(mut self) -> Self {
|
|
||||||
self.declared_style().overflow.x = Some(Overflow::Hidden);
|
|
||||||
self.declared_style().overflow.y = Some(Overflow::Hidden);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn overflow_hidden_x(mut self) -> Self {
|
|
||||||
self.declared_style().overflow.x = Some(Overflow::Hidden);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn overflow_hidden_y(mut self) -> Self {
|
|
||||||
self.declared_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);
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
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 layout_children(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> Vec<LayoutId> {
|
|
||||||
self.children
|
|
||||||
.iter_mut()
|
|
||||||
.map(|child| child.layout(view, cx))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
|
|
||||||
self.styles.base()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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, Marker: 'static + Send + Sync> ParentElement for Div<V, Marker> {
|
|
||||||
type State = V;
|
|
||||||
|
|
||||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
|
||||||
&mut self.children
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
|
pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
|
||||||
|
@ -244,3 +28,147 @@ impl ScrollState {
|
||||||
self.0.lock().y = value;
|
self.0.lock().y = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 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))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>,
|
||||||
|
) -> (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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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::{
|
use crate::{
|
||||||
group_bounds, AnyElement, Bounds, DispatchPhase, Element, ElementId, IdentifiedElement,
|
group_bounds, AnyElement, Bounds, DispatchPhase, Element, ElementId, ElementKind,
|
||||||
Interactive, IntoAnyElement, MouseEventListeners, MouseMoveEvent, ParentElement, Pixels,
|
IdentifiedElement, IntoAnyElement, LayoutId, LayoutNode, MouseMoveEvent, Pixels, SharedString,
|
||||||
SharedString, Styled, ViewContext,
|
Style, StyleCascade, StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use refineable::{Cascade, CascadeSlot, Refineable};
|
use refineable::CascadeSlot;
|
||||||
use smallvec::SmallVec;
|
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicBool, Ordering::SeqCst},
|
atomic::{AtomicBool, Ordering::SeqCst},
|
||||||
Arc,
|
Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Hoverable<E: Styled> {
|
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>,
|
group: Option<SharedString>,
|
||||||
hovered: Arc<AtomicBool>,
|
|
||||||
cascade_slot: CascadeSlot,
|
cascade_slot: CascadeSlot,
|
||||||
hovered_style: <E::Style as Refineable>::Refinement,
|
hovered: Arc<AtomicBool>,
|
||||||
child: E,
|
child: E,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Styled> Hoverable<E> {
|
impl<E: Styled + Element> HoverableElement<E> {
|
||||||
pub fn new(mut child: E, hover_group: Option<SharedString>) -> Self {
|
pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
|
||||||
Self {
|
self,
|
||||||
group: hover_group,
|
replace: impl FnOnce(E) -> E2,
|
||||||
hovered: Arc::new(AtomicBool::new(false)),
|
) -> HoverableElement<E2> {
|
||||||
cascade_slot: child.style_cascade().reserve(),
|
HoverableElement {
|
||||||
hovered_style: Default::default(),
|
hover_style: self.hover_style,
|
||||||
child,
|
group: self.group,
|
||||||
|
cascade_slot: self.cascade_slot,
|
||||||
|
hovered: self.hovered,
|
||||||
|
child: replace(self.child),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> Styled for Hoverable<E>
|
impl<E> IntoAnyElement<E::ViewState> for HoverableElement<E>
|
||||||
where
|
where
|
||||||
E: Styled,
|
E: Styled + Element,
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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> IntoAnyElement<E::ViewState> for Hoverable<E>
|
|
||||||
where
|
|
||||||
E: Element + Styled,
|
|
||||||
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
|
|
||||||
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
|
|
||||||
{
|
{
|
||||||
fn into_any(self) -> AnyElement<E::ViewState> {
|
fn into_any(self) -> AnyElement<E::ViewState> {
|
||||||
AnyElement::new(self)
|
AnyElement::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> Element for Hoverable<E>
|
impl<E> Element for HoverableElement<E>
|
||||||
where
|
where
|
||||||
E: Element + Styled,
|
E: Styled + Element,
|
||||||
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
|
|
||||||
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
|
|
||||||
{
|
{
|
||||||
type ViewState = E::ViewState;
|
type ViewState = E::ViewState;
|
||||||
type ElementState = E::ElementState;
|
type ElementState = E::ElementState;
|
||||||
|
@ -80,7 +69,7 @@ where
|
||||||
state: &mut Self::ViewState,
|
state: &mut Self::ViewState,
|
||||||
element_state: Option<Self::ElementState>,
|
element_state: Option<Self::ElementState>,
|
||||||
cx: &mut ViewContext<Self::ViewState>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) -> (crate::LayoutId, Self::ElementState) {
|
) -> (LayoutId, Self::ElementState) {
|
||||||
self.child.layout(state, element_state, cx)
|
self.child.layout(state, element_state, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,19 +89,15 @@ where
|
||||||
let hovered = target_bounds.contains_point(cx.mouse_position());
|
let hovered = target_bounds.contains_point(cx.mouse_position());
|
||||||
|
|
||||||
let slot = self.cascade_slot;
|
let slot = self.cascade_slot;
|
||||||
let style = hovered.then_some(self.hovered_style.clone());
|
let style = hovered.then_some(self.hover_style.clone());
|
||||||
self.style_cascade().set(slot, style);
|
self.child.style_cascade().set(slot, style);
|
||||||
self.hovered.store(hovered, SeqCst);
|
self.hovered.store(hovered, SeqCst);
|
||||||
|
|
||||||
cx.on_mouse_event({
|
|
||||||
let hovered = self.hovered.clone();
|
let hovered = self.hovered.clone();
|
||||||
|
cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
|
||||||
move |_, event: &MouseMoveEvent, phase, cx| {
|
if phase == DispatchPhase::Capture {
|
||||||
if phase == DispatchPhase::Bubble {
|
|
||||||
if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
|
if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
cx.stop_propagation();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -121,18 +106,35 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: ParentElement + Styled> ParentElement for Hoverable<E> {
|
impl<E, K, V> LayoutNode<V, K> for HoverableElement<E>
|
||||||
type State = E::State;
|
where
|
||||||
|
E: LayoutNode<V, K>,
|
||||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
|
K: ElementKind,
|
||||||
|
V: 'static + Send + Sync,
|
||||||
|
{
|
||||||
|
fn children_mut(&mut self) -> &mut smallvec::SmallVec<[AnyElement<V>; 2]> {
|
||||||
self.child.children_mut()
|
self.child.children_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn group_mut(&mut self) -> &mut Option<SharedString> {
|
||||||
|
self.child.group_mut()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> IdentifiedElement for Hoverable<E>
|
impl<E: Styled + Element> Hoverable for HoverableElement<E> {
|
||||||
where
|
fn hover_style(&mut self) -> &mut StyleRefinement {
|
||||||
E: IdentifiedElement + Styled,
|
&mut self.hover_style
|
||||||
<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> 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>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) {
|
) {
|
||||||
let style = self.computed_style();
|
let style = self.computed_style();
|
||||||
|
let corner_radii = style.corner_radii;
|
||||||
style.paint(bounds, cx);
|
style.paint(bounds, cx);
|
||||||
|
|
||||||
if let Some(uri) = self.uri.clone() {
|
if let Some(uri) = self.uri.clone() {
|
||||||
|
@ -84,7 +84,7 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
|
||||||
.now_or_never()
|
.now_or_never()
|
||||||
.and_then(ResultExt::log_err)
|
.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.stack(1, |cx| {
|
||||||
cx.paint_image(bounds, corner_radii, data, self.grayscale)
|
cx.paint_image(bounds, corner_radii, data, self.grayscale)
|
||||||
.log_err()
|
.log_err()
|
||||||
|
@ -102,13 +102,13 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Styled for Img<S> {
|
impl<S> Styled for Img<S> {
|
||||||
type Style = Style;
|
fn style_cascade(&mut self) -> &mut Cascade<Style> {
|
||||||
|
todo!("use layout node")
|
||||||
fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
|
// &mut self.style
|
||||||
&mut self.style
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
|
fn computed_style(&mut self) -> &Style {
|
||||||
self.style.base()
|
todo!("use layout node")
|
||||||
|
// self.style.compute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
207
crates/gpui3/src/elements/layout_node.rs
Normal file
207
crates/gpui3/src/elements/layout_node.rs
Normal file
|
@ -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
|
) where
|
||||||
Self: Sized,
|
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) {
|
if let Some((path, fill_color)) = self.path.as_ref().zip(fill_color) {
|
||||||
cx.paint_svg(bounds, path.clone(), fill_color).log_err();
|
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> {
|
impl<S: 'static + Send + Sync> Styled for Svg<S> {
|
||||||
type Style = Style;
|
fn style_cascade(&mut self) -> &mut crate::StyleCascade {
|
||||||
|
todo!("use layout node")
|
||||||
fn style_cascade(&mut self) -> &mut refineable::Cascade<Self::Style> {
|
|
||||||
&mut self.style
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
|
fn computed_style(&mut self) -> &Style {
|
||||||
self.style.base()
|
todo!("use layout node")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ mod interactive;
|
||||||
mod platform;
|
mod platform;
|
||||||
mod scene;
|
mod scene;
|
||||||
mod style;
|
mod style;
|
||||||
mod style_helpers;
|
|
||||||
mod styled;
|
mod styled;
|
||||||
mod subscription;
|
mod subscription;
|
||||||
mod svg_renderer;
|
mod svg_renderer;
|
||||||
|
@ -41,7 +40,6 @@ pub use serde_json;
|
||||||
pub use smallvec;
|
pub use smallvec;
|
||||||
pub use smol::Timer;
|
pub use smol::Timer;
|
||||||
pub use style::*;
|
pub use style::*;
|
||||||
pub use style_helpers::*;
|
|
||||||
pub use styled::*;
|
pub use styled::*;
|
||||||
pub use subscription::*;
|
pub use subscription::*;
|
||||||
pub use svg_renderer::*;
|
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 {
|
pub trait Styled {
|
||||||
type Style: 'static + Refineable + Send + Sync + Default;
|
fn style_cascade(&mut self) -> &mut StyleCascade;
|
||||||
|
fn computed_style(&mut self) -> &Style;
|
||||||
fn style_cascade(&mut self) -> &mut Cascade<Self::Style>;
|
fn base_style(&mut self) -> &mut StyleRefinement {
|
||||||
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
|
self.style_cascade().base()
|
||||||
|
|
||||||
fn computed_style(&mut self) -> Self::Style {
|
|
||||||
Self::Style::default().refined(self.style_cascade().merged())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hover(self) -> Hoverable<Self>
|
gpui3_macros::style_helpers!();
|
||||||
|
|
||||||
|
fn full(mut self) -> Self
|
||||||
where
|
where
|
||||||
Self: 'static + Sized + Send + Sync,
|
Self: Sized,
|
||||||
Self::Style: 'static + Refineable + Default + Send + Sync,
|
|
||||||
<Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
|
|
||||||
{
|
{
|
||||||
Hoverable::new(self, None)
|
self.base_style().size.width = Some(relative(1.).into());
|
||||||
|
self.base_style().size.height = Some(relative(1.).into());
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn group_hover(self, group_name: impl Into<SharedString>) -> Hoverable<Self>
|
fn relative(mut self) -> Self
|
||||||
where
|
where
|
||||||
Self: 'static + Sized + Send + Sync,
|
Self: Sized,
|
||||||
Self::Style: 'static + Refineable + Default + Send + Sync,
|
|
||||||
<Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
|
|
||||||
{
|
{
|
||||||
Hoverable::new(self, Some(group_name.into()))
|
self.base_style().position = Some(Position::Relative);
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn active(self) -> Pressable<Self>
|
fn absolute(mut self) -> Self
|
||||||
where
|
where
|
||||||
Self: 'static + Sized + Send + Sync,
|
Self: Sized,
|
||||||
Self::Style: 'static + Refineable + Default + Send + Sync,
|
|
||||||
<Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
|
|
||||||
{
|
{
|
||||||
Pressable::new(self, None)
|
self.base_style().position = Some(Position::Absolute);
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn group_active(self, group_name: impl Into<SharedString>) -> Pressable<Self>
|
fn block(mut self) -> Self
|
||||||
where
|
where
|
||||||
Self: 'static + Sized + Send + Sync,
|
Self: Sized,
|
||||||
Self::Style: 'static + Refineable + Default + Send + Sync,
|
|
||||||
<Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
|
|
||||||
{
|
{
|
||||||
Pressable::new(self, Some(group_name.into()))
|
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 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 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 text_decoration_2(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(2.);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_decoration_4(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(4.);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_decoration_8(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(8.);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn font(mut self, family_name: impl Into<SharedString>) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
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) {
|
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| {
|
self.state.update(cx, |state, cx| {
|
||||||
let mut element = (self.render)(state, cx);
|
let mut element = (self.render)(state, cx);
|
||||||
let layout_id = element.layout(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) {
|
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| {
|
self.state.update(cx, |state, cx| {
|
||||||
let element = element.downcast_mut::<AnyElement<S>>().unwrap();
|
let element = element.downcast_mut::<AnyElement<S>>().unwrap();
|
||||||
element.paint(state, None, cx);
|
element.paint(state, None, cx);
|
||||||
|
|
|
@ -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.declared_style();
|
let mut style = self.base_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.declared_style();
|
let mut style = self.base_style();
|
||||||
#(#field_assignments)*
|
#(#field_assignments)*
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue