Checkpoint
This commit is contained in:
parent
19c1a54fea
commit
deb0e57c49
14 changed files with 601 additions and 1491 deletions
|
@ -33,6 +33,26 @@ pub trait IdentifiedElement: Element {
|
|||
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
|
||||
|
||||
pub trait ElementKind: 'static + Send + Sync {
|
||||
fn id(&self) -> Option<ElementId>;
|
||||
}
|
||||
|
||||
pub struct IdentifiedElementKind(pub(crate) ElementId);
|
||||
pub struct AnonymousElementKind;
|
||||
|
||||
impl ElementKind for IdentifiedElementKind {
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
Some(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementKind for AnonymousElementKind {
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait ParentElement: Element {
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>;
|
||||
fn group_mut(&mut self) -> &mut Option<SharedString>;
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
mod clickable;
|
||||
mod div;
|
||||
mod hoverable;
|
||||
mod img;
|
||||
mod layout_node;
|
||||
mod svg;
|
||||
mod text;
|
||||
mod div2;
|
||||
|
||||
pub use clickable::*;
|
||||
pub use div::*;
|
||||
pub use hoverable::*;
|
||||
pub use img::*;
|
||||
pub use layout_node::*;
|
||||
pub use svg::*;
|
||||
pub use text::*;
|
||||
|
|
|
@ -1,230 +0,0 @@
|
|||
use crate::{
|
||||
AnyElement, Bounds, DispatchPhase, Element, ElementId, Hoverable, IdentifiedElement,
|
||||
IntoAnyElement, LayoutId, MouseDownEvent, MouseUpEvent, ParentElement, Pixels, SharedString,
|
||||
StyleRefinement, Styled, ViewContext,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use refineable::CascadeSlot;
|
||||
use smallvec::SmallVec;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait Clickable: Element + Sized {
|
||||
fn active_style(&mut self) -> &mut StyleRefinement;
|
||||
fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState>;
|
||||
|
||||
fn on_click(
|
||||
&mut self,
|
||||
f: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
|
||||
+ 'static
|
||||
+ Send
|
||||
+ Sync,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
self.listeners().push(Arc::new(f));
|
||||
}
|
||||
|
||||
fn active(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
f(self.active_style());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub type ClickListeners<V> =
|
||||
SmallVec<[Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync>; 1]>;
|
||||
|
||||
pub struct ClickableElementState<E: 'static + Send + Sync> {
|
||||
mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||
child_state: E,
|
||||
}
|
||||
|
||||
pub struct MouseClickEvent {
|
||||
pub down: MouseDownEvent,
|
||||
pub up: MouseUpEvent,
|
||||
}
|
||||
|
||||
pub struct ClickableElement<E: Element> {
|
||||
child: E,
|
||||
listeners: ClickListeners<E::ViewState>,
|
||||
active_style: StyleRefinement,
|
||||
cascade_slot: CascadeSlot,
|
||||
}
|
||||
|
||||
impl<E: Styled + Element> ClickableElement<E> {
|
||||
pub fn new(mut child: E) -> Self {
|
||||
let cascade_slot = child.style_cascade().reserve();
|
||||
ClickableElement {
|
||||
child,
|
||||
listeners: Default::default(),
|
||||
active_style: Default::default(),
|
||||
cascade_slot,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
|
||||
self,
|
||||
replace: impl FnOnce(E) -> E2,
|
||||
) -> ClickableElement<E2> {
|
||||
ClickableElement {
|
||||
child: replace(self.child),
|
||||
listeners: self.listeners,
|
||||
active_style: self.active_style,
|
||||
cascade_slot: self.cascade_slot,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> IntoAnyElement<E::ViewState> for ClickableElement<E>
|
||||
where
|
||||
E: Styled + Element,
|
||||
{
|
||||
fn into_any(self) -> AnyElement<E::ViewState> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Element for ClickableElement<E>
|
||||
where
|
||||
E: Styled + Element,
|
||||
{
|
||||
type ViewState = E::ViewState;
|
||||
type ElementState = ClickableElementState<E::ElementState>;
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
self.child.id()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
state: &mut Self::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState) {
|
||||
if let Some(element_state) = element_state {
|
||||
if element_state.mouse_down.lock().is_some() {
|
||||
self.child
|
||||
.style_cascade()
|
||||
.set(self.cascade_slot, Some(self.active_style.clone()));
|
||||
}
|
||||
|
||||
let (layout_id, child_state) =
|
||||
self.child
|
||||
.layout(state, Some(element_state.child_state), cx);
|
||||
(
|
||||
layout_id,
|
||||
ClickableElementState {
|
||||
mouse_down: element_state.mouse_down,
|
||||
child_state,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
let (layout_id, child_state) = self.child.layout(state, None, cx);
|
||||
(
|
||||
layout_id,
|
||||
ClickableElementState {
|
||||
mouse_down: Default::default(),
|
||||
child_state,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
state: &mut Self::ViewState,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) {
|
||||
if !self.listeners.is_empty() || self.active_style.is_some() {
|
||||
if let Some(mouse_down) = element_state.mouse_down.lock().clone() {
|
||||
self.child
|
||||
.style_cascade()
|
||||
.set(self.cascade_slot, Some(self.active_style.clone()));
|
||||
let listeners = self.listeners.clone();
|
||||
let mouse_down_mutex = element_state.mouse_down.clone();
|
||||
cx.on_mouse_event(move |view, up: &MouseUpEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(up.position) {
|
||||
for listener in &*listeners {
|
||||
listener(
|
||||
view,
|
||||
&MouseClickEvent {
|
||||
down: mouse_down.clone(),
|
||||
up: up.clone(),
|
||||
},
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mouse_down_mutex.lock().take();
|
||||
cx.notify();
|
||||
});
|
||||
} else {
|
||||
let mouse_down_mutex = element_state.mouse_down.clone();
|
||||
cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(down.position) {
|
||||
*mouse_down_mutex.lock() = Some(down.clone());
|
||||
cx.notify();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.child
|
||||
.paint(bounds, state, &mut element_state.child_state, cx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Styled + IdentifiedElement> IdentifiedElement for ClickableElement<E> {}
|
||||
|
||||
impl<E> ParentElement for ClickableElement<E>
|
||||
where
|
||||
E: Styled + ParentElement,
|
||||
{
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]> {
|
||||
self.child.children_mut()
|
||||
}
|
||||
|
||||
fn group_mut(&mut self) -> &mut Option<SharedString> {
|
||||
self.child.group_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Styled for ClickableElement<E>
|
||||
where
|
||||
E: Styled + Element,
|
||||
{
|
||||
fn style_cascade(&mut self) -> &mut crate::StyleCascade {
|
||||
self.child.style_cascade()
|
||||
}
|
||||
|
||||
fn computed_style(&mut self) -> &crate::Style {
|
||||
self.child.computed_style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Hoverable for ClickableElement<E>
|
||||
where
|
||||
E: Element + Hoverable,
|
||||
{
|
||||
fn hover_style(&mut self) -> &mut StyleRefinement {
|
||||
self.child.hover_style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Clickable for ClickableElement<E>
|
||||
where
|
||||
E: Styled + IdentifiedElement,
|
||||
{
|
||||
fn active_style(&mut self) -> &mut StyleRefinement {
|
||||
&mut self.active_style
|
||||
}
|
||||
|
||||
fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState> {
|
||||
&mut self.listeners
|
||||
}
|
||||
}
|
|
@ -1,14 +1,43 @@
|
|||
use crate::{
|
||||
AnonymousElementKind, AnyElement, Bounds, ClickListeners, Clickable, ClickableElement,
|
||||
ClickableElementState, Element, ElementId, ElementKind, Hoverable, HoverableElement,
|
||||
IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, LayoutNodeElement,
|
||||
Overflow, ParentElement, Pixels, Point, SharedString, Style, StyleCascade, StyleRefinement,
|
||||
Styled, ViewContext,
|
||||
AnonymousElementKind, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element,
|
||||
ElementId, ElementKind, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId,
|
||||
MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, Pixels, Point,
|
||||
ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled, ViewContext,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
use refineable::Refineable;
|
||||
use smallvec::SmallVec;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DivState {
|
||||
active_state: Arc<Mutex<ActiveState>>,
|
||||
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Eq, PartialEq)]
|
||||
struct ActiveState {
|
||||
group: bool,
|
||||
element: bool,
|
||||
}
|
||||
|
||||
impl ActiveState {
|
||||
pub fn is_none(&self) -> bool {
|
||||
!self.group && !self.element
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
|
||||
|
||||
pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
|
||||
cx.default_global::<GroupBounds>()
|
||||
.0
|
||||
.get(name)
|
||||
.and_then(|bounds_stack| bounds_stack.last().cloned())
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
|
||||
|
||||
|
@ -34,116 +63,459 @@ pub fn div<S>() -> Div<S, AnonymousElementKind>
|
|||
where
|
||||
S: 'static + Send + Sync,
|
||||
{
|
||||
Div(ClickableElement::new(HoverableElement::new(
|
||||
LayoutNodeElement::new(),
|
||||
)))
|
||||
Div {
|
||||
kind: AnonymousElementKind,
|
||||
children: SmallVec::new(),
|
||||
group: None,
|
||||
base_style: StyleRefinement::default(),
|
||||
hover_style: StyleRefinement::default(),
|
||||
group_hover: None,
|
||||
active_style: StyleRefinement::default(),
|
||||
group_active: None,
|
||||
listeners: MouseEventListeners::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Div<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind>(
|
||||
ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
|
||||
);
|
||||
pub struct Div<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
|
||||
kind: K,
|
||||
children: SmallVec<[AnyElement<V>; 2]>,
|
||||
group: Option<SharedString>,
|
||||
base_style: StyleRefinement,
|
||||
hover_style: StyleRefinement,
|
||||
group_hover: Option<GroupStyle>,
|
||||
active_style: StyleRefinement,
|
||||
group_active: Option<GroupStyle>,
|
||||
listeners: MouseEventListeners<V>,
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync, K: ElementKind> Div<V, K> {
|
||||
struct GroupStyle {
|
||||
group: SharedString,
|
||||
style: StyleRefinement,
|
||||
}
|
||||
|
||||
impl<V> Div<V, AnonymousElementKind>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Div<V, IdentifiedElementKind> {
|
||||
Div {
|
||||
kind: IdentifiedElementKind(id.into()),
|
||||
children: self.children,
|
||||
group: self.group,
|
||||
base_style: self.base_style,
|
||||
hover_style: self.hover_style,
|
||||
group_hover: self.group_hover,
|
||||
active_style: self.active_style,
|
||||
group_active: self.group_active,
|
||||
listeners: self.listeners,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Div<V, IdentifiedElementKind>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
pub fn on_mouse_down(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
self.listeners
|
||||
.mouse_down
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.contains_point(&event.position)
|
||||
{
|
||||
handler(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_mouse_up(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
self.listeners
|
||||
.mouse_up
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.contains_point(&event.position)
|
||||
{
|
||||
handler(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_mouse_down_out(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
self.listeners
|
||||
.mouse_down
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.contains_point(&event.position)
|
||||
{
|
||||
handler(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_mouse_up_out(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
self.listeners
|
||||
.mouse_up
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.contains_point(&event.position)
|
||||
{
|
||||
handler(view, event, cx);
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_mouse_move(
|
||||
mut self,
|
||||
handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
self.listeners
|
||||
.mouse_move
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx);
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_scroll_wheel(
|
||||
mut self,
|
||||
handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
self.listeners
|
||||
.scroll_wheel
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx);
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Div<V, K>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementKind,
|
||||
{
|
||||
pub fn group(mut self, group: impl Into<SharedString>) -> Self {
|
||||
*self.0.group_mut() = Some(group.into());
|
||||
self.group = Some(group.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn z_index(mut self, z_index: u32) -> Self {
|
||||
self.base_style().z_index = Some(z_index);
|
||||
self.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.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.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.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.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.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.base_style.overflow.y = Some(Overflow::Scroll);
|
||||
self
|
||||
}
|
||||
|
||||
fn base_style(&mut self) -> &mut StyleRefinement {
|
||||
self.style_cascade().base()
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_style(
|
||||
&self,
|
||||
bounds: Bounds<Pixels>,
|
||||
state: &DivState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Style {
|
||||
let mut computed_style = Style::default();
|
||||
computed_style.refine(&self.base_style);
|
||||
|
||||
let mouse_position = cx.mouse_position();
|
||||
|
||||
if let Some(group_hover) = self.group_hover.as_ref() {
|
||||
if let Some(group_bounds) = group_bounds(&group_hover.group, cx) {
|
||||
if group_bounds.contains_point(&mouse_position) {
|
||||
computed_style.refine(&group_hover.style);
|
||||
}
|
||||
}
|
||||
}
|
||||
if bounds.contains_point(&mouse_position) {
|
||||
computed_style.refine(&self.hover_style);
|
||||
}
|
||||
|
||||
let active_state = *state.active_state.lock();
|
||||
if active_state.group {
|
||||
if let Some(GroupStyle { style, .. }) = self.group_active.as_ref() {
|
||||
computed_style.refine(style);
|
||||
}
|
||||
}
|
||||
|
||||
if active_state.element {
|
||||
computed_style.refine(&self.active_style);
|
||||
}
|
||||
|
||||
computed_style
|
||||
}
|
||||
|
||||
fn paint_hover_listeners(
|
||||
&self,
|
||||
bounds: Bounds<Pixels>,
|
||||
group_bounds: Option<Bounds<Pixels>>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
if let Some(group_bounds) = group_bounds {
|
||||
paint_hover_listener(group_bounds, cx);
|
||||
}
|
||||
|
||||
if self.hover_style.is_some() {
|
||||
paint_hover_listener(bounds, cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_active_listener(
|
||||
&self,
|
||||
bounds: Bounds<Pixels>,
|
||||
group_bounds: Option<Bounds<Pixels>>,
|
||||
active_state: Arc<Mutex<ActiveState>>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
if active_state.lock().is_none() {
|
||||
cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
let group =
|
||||
group_bounds.map_or(false, |bounds| bounds.contains_point(&down.position));
|
||||
let element = bounds.contains_point(&down.position);
|
||||
if group || element {
|
||||
*active_state.lock() = ActiveState { group, element };
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
*active_state.lock() = ActiveState::default();
|
||||
cx.notify();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_event_listeners(
|
||||
&self,
|
||||
bounds: Bounds<Pixels>,
|
||||
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let click_listeners = self.listeners.mouse_click.clone();
|
||||
let mouse_down = pending_click.lock().clone();
|
||||
if let Some(mouse_down) = mouse_down {
|
||||
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
let mouse_click = MouseClickEvent {
|
||||
down: mouse_down.clone(),
|
||||
up: event.clone(),
|
||||
};
|
||||
for listener in &click_listeners {
|
||||
listener(state, &mouse_click, &bounds, cx);
|
||||
}
|
||||
}
|
||||
|
||||
*pending_click.lock() = None;
|
||||
});
|
||||
} else {
|
||||
cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
*pending_click.lock() = Some(event.clone());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for listener in self.listeners.mouse_down.iter().cloned() {
|
||||
cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.listeners.mouse_up.iter().cloned() {
|
||||
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.listeners.mouse_move.iter().cloned() {
|
||||
cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.listeners.scroll_wheel.iter().cloned() {
|
||||
cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync> Div<V, AnonymousElementKind> {
|
||||
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, K> Element for Div<V, K>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementKind,
|
||||
{
|
||||
type ViewState = V;
|
||||
type ElementState = DivState;
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
self.kind.id()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState) {
|
||||
self.with_element_id(cx, |this, cx| {
|
||||
let layout_ids = this
|
||||
.children
|
||||
.iter_mut()
|
||||
.map(|child| child.layout(view_state, cx))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let element_state = element_state.unwrap_or_default();
|
||||
let style = this.compute_style(Bounds::default(), &element_state, cx);
|
||||
let layout_id = cx.request_layout(&style, layout_ids);
|
||||
(layout_id, element_state)
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) {
|
||||
self.with_element_id(cx, |this, cx| {
|
||||
if let Some(group) = this.group.clone() {
|
||||
cx.default_global::<GroupBounds>()
|
||||
.0
|
||||
.entry(group)
|
||||
.or_default()
|
||||
.push(bounds);
|
||||
}
|
||||
|
||||
let hover_group_bounds = this
|
||||
.group_hover
|
||||
.as_ref()
|
||||
.and_then(|group_hover| group_bounds(&group_hover.group, cx));
|
||||
let active_group_bounds = this
|
||||
.group_active
|
||||
.as_ref()
|
||||
.and_then(|group_active| group_bounds(&group_active.group, cx));
|
||||
let style = this.compute_style(bounds, element_state, cx);
|
||||
let z_index = style.z_index.unwrap_or(0);
|
||||
|
||||
// Paint background and event handlers.
|
||||
cx.stack(z_index, |cx| {
|
||||
cx.stack(0, |cx| {
|
||||
style.paint(bounds, cx);
|
||||
this.paint_hover_listeners(bounds, hover_group_bounds, cx);
|
||||
this.paint_active_listener(
|
||||
bounds,
|
||||
active_group_bounds,
|
||||
element_state.active_state.clone(),
|
||||
cx,
|
||||
);
|
||||
this.paint_event_listeners(bounds, element_state.pending_click.clone(), cx);
|
||||
});
|
||||
});
|
||||
|
||||
style.apply_text_style(cx, |cx| {
|
||||
style.apply_overflow(bounds, cx, |cx| {
|
||||
cx.stack(z_index + 1, |cx| {
|
||||
for child in &mut this.children {
|
||||
child.paint(view_state, None, cx);
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(group) = this.group.as_ref() {
|
||||
cx.default_global::<GroupBounds>()
|
||||
.0
|
||||
.get_mut(group)
|
||||
.unwrap()
|
||||
.pop();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync> IdentifiedElement for Div<V, IdentifiedElementKind> {
|
||||
fn id(&self) -> ElementId {
|
||||
IdentifiedElement::id(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync, K: ElementKind> ParentElement for Div<V, K> {
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||
self.0.children_mut()
|
||||
}
|
||||
|
||||
fn group_mut(&mut self) -> &mut Option<SharedString> {
|
||||
self.0.group_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync, K: ElementKind> Styled for Div<V, K> {
|
||||
fn style_cascade(&mut self) -> &mut StyleCascade {
|
||||
self.0.style_cascade()
|
||||
}
|
||||
|
||||
fn computed_style(&mut self) -> &Style {
|
||||
self.0.computed_style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Div<V, K> {
|
||||
fn hover_style(&mut self) -> &mut StyleRefinement {
|
||||
self.0.hover_style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync> Clickable for Div<V, IdentifiedElementKind> {
|
||||
fn active_style(&mut self) -> &mut StyleRefinement {
|
||||
self.0.active_style()
|
||||
}
|
||||
|
||||
fn listeners(&mut self) -> &mut ClickListeners<V> {
|
||||
self.0.listeners()
|
||||
self.kind.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,34 +529,80 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<V, K> Element for Div<V, K>
|
||||
impl<V, K> Styled 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);
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
&mut self.base_style
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MouseClickEvent {
|
||||
pub down: MouseDownEvent,
|
||||
pub up: MouseUpEvent,
|
||||
}
|
||||
|
||||
type MouseDownHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
type MouseUpHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
type MouseClickHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseClickEvent, &Bounds<Pixels>, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||
>;
|
||||
|
||||
type MouseMoveHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
type ScrollWheelHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
pub struct MouseEventListeners<V: 'static> {
|
||||
mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
|
||||
mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
|
||||
mouse_click: SmallVec<[MouseClickHandler<V>; 2]>,
|
||||
mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
|
||||
scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
|
||||
}
|
||||
|
||||
impl<V> Default for MouseEventListeners<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mouse_down: SmallVec::new(),
|
||||
mouse_up: SmallVec::new(),
|
||||
mouse_click: SmallVec::new(),
|
||||
mouse_move: SmallVec::new(),
|
||||
scroll_wheel: SmallVec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
let hovered = bounds.contains_point(&cx.mouse_position());
|
||||
cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
if bounds.contains_point(&event.position) != hovered {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,498 +0,0 @@
|
|||
use crate::{
|
||||
AnonymousElementKind, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element,
|
||||
ElementId, ElementKind, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId,
|
||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, Pixels, Point, ScrollWheelEvent,
|
||||
SharedString, Style, StyleRefinement, ViewContext,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
use refineable::Refineable;
|
||||
use smallvec::SmallVec;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DivState {
|
||||
active_state: Arc<Mutex<ActiveState>>,
|
||||
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Eq, PartialEq)]
|
||||
struct ActiveState {
|
||||
group: bool,
|
||||
element: bool,
|
||||
}
|
||||
|
||||
impl ActiveState {
|
||||
pub fn is_none(&self) -> bool {
|
||||
!self.group && !self.element
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
|
||||
|
||||
pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
|
||||
cx.default_global::<GroupBounds>()
|
||||
.0
|
||||
.get(name)
|
||||
.and_then(|bounds_stack| bounds_stack.last().cloned())
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
|
||||
|
||||
impl ScrollState {
|
||||
pub fn x(&self) -> Pixels {
|
||||
self.0.lock().x
|
||||
}
|
||||
|
||||
pub fn set_x(&self, value: Pixels) {
|
||||
self.0.lock().x = value;
|
||||
}
|
||||
|
||||
pub fn y(&self) -> Pixels {
|
||||
self.0.lock().y
|
||||
}
|
||||
|
||||
pub fn set_y(&self, value: Pixels) {
|
||||
self.0.lock().y = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn div<S>() -> Div<S, AnonymousElementKind>
|
||||
where
|
||||
S: 'static + Send + Sync,
|
||||
{
|
||||
Div {
|
||||
kind: AnonymousElementKind,
|
||||
children: SmallVec::new(),
|
||||
group: None,
|
||||
base_style: StyleRefinement::default(),
|
||||
hover_style: StyleRefinement::default(),
|
||||
group_hover: None,
|
||||
active_style: StyleRefinement::default(),
|
||||
group_active: None,
|
||||
listeners: MouseEventListeners::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Div<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
|
||||
kind: K,
|
||||
children: SmallVec<[AnyElement<V>; 2]>,
|
||||
group: Option<SharedString>,
|
||||
base_style: StyleRefinement,
|
||||
hover_style: StyleRefinement,
|
||||
group_hover: Option<GroupStyle>,
|
||||
active_style: StyleRefinement,
|
||||
group_active: Option<GroupStyle>,
|
||||
listeners: MouseEventListeners<V>,
|
||||
}
|
||||
|
||||
struct GroupStyle {
|
||||
group: SharedString,
|
||||
style: StyleRefinement,
|
||||
}
|
||||
|
||||
impl<V> Div<V, AnonymousElementKind>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
pub fn id(self, id: ElementId) -> Div<V, IdentifiedElementKind> {
|
||||
Div {
|
||||
kind: IdentifiedElementKind(id),
|
||||
children: self.children,
|
||||
group: self.group,
|
||||
base_style: self.base_style,
|
||||
hover_style: self.hover_style,
|
||||
group_hover: self.group_hover,
|
||||
active_style: self.active_style,
|
||||
group_active: self.group_active,
|
||||
listeners: self.listeners,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Div<V, K>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementKind,
|
||||
{
|
||||
pub fn group(mut self, group: impl Into<SharedString>) -> Self {
|
||||
self.group = Some(group.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn z_index(mut self, z_index: u32) -> Self {
|
||||
self.base_style.z_index = Some(z_index);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overflow_hidden(mut self) -> Self {
|
||||
self.base_style.overflow.x = Some(Overflow::Hidden);
|
||||
self.base_style.overflow.y = Some(Overflow::Hidden);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overflow_hidden_x(mut self) -> Self {
|
||||
self.base_style.overflow.x = Some(Overflow::Hidden);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overflow_hidden_y(mut self) -> Self {
|
||||
self.base_style.overflow.y = Some(Overflow::Hidden);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overflow_scroll(mut self, _scroll_state: ScrollState) -> Self {
|
||||
// todo!("impl scrolling")
|
||||
// self.scroll_state = Some(scroll_state);
|
||||
self.base_style.overflow.x = Some(Overflow::Scroll);
|
||||
self.base_style.overflow.y = Some(Overflow::Scroll);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overflow_x_scroll(mut self, _scroll_state: ScrollState) -> Self {
|
||||
// todo!("impl scrolling")
|
||||
// self.scroll_state = Some(scroll_state);
|
||||
self.base_style.overflow.x = Some(Overflow::Scroll);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overflow_y_scroll(mut self, _scroll_state: ScrollState) -> Self {
|
||||
// todo!("impl scrolling")
|
||||
// self.scroll_state = Some(scroll_state);
|
||||
self.base_style.overflow.y = Some(Overflow::Scroll);
|
||||
self
|
||||
}
|
||||
|
||||
fn with_element_id<R>(
|
||||
&mut self,
|
||||
cx: &mut ViewContext<V>,
|
||||
f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
|
||||
) -> R {
|
||||
if let Some(id) = self.id() {
|
||||
cx.with_element_id(id, |cx| f(self, cx))
|
||||
} else {
|
||||
f(self, cx)
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_style(
|
||||
&self,
|
||||
bounds: Bounds<Pixels>,
|
||||
group_bounds: Option<Bounds<Pixels>>,
|
||||
active_state: ActiveState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Style {
|
||||
let mut computed_style = Style::default();
|
||||
computed_style.refine(&self.base_style);
|
||||
|
||||
let mouse_position = cx.mouse_position();
|
||||
if let Some(group_bounds) = group_bounds {
|
||||
if group_bounds.contains_point(mouse_position) {
|
||||
if let Some(GroupStyle { style, .. }) = self.group_hover.as_ref() {
|
||||
computed_style.refine(style);
|
||||
}
|
||||
}
|
||||
}
|
||||
if bounds.contains_point(mouse_position) {
|
||||
computed_style.refine(&self.hover_style);
|
||||
}
|
||||
|
||||
if active_state.group {
|
||||
if let Some(GroupStyle { style, .. }) = self.group_active.as_ref() {
|
||||
computed_style.refine(style);
|
||||
}
|
||||
}
|
||||
|
||||
if active_state.element {
|
||||
computed_style.refine(&self.active_style);
|
||||
}
|
||||
|
||||
computed_style
|
||||
}
|
||||
|
||||
fn paint_hover_listeners(
|
||||
&self,
|
||||
bounds: Bounds<Pixels>,
|
||||
group_bounds: Option<Bounds<Pixels>>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
if let Some(group_bounds) = group_bounds {
|
||||
paint_hover_listener(group_bounds, cx);
|
||||
}
|
||||
|
||||
if self.hover_style.is_some() {
|
||||
paint_hover_listener(bounds, cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_active_listener(
|
||||
&self,
|
||||
bounds: Bounds<Pixels>,
|
||||
group_bounds: Option<Bounds<Pixels>>,
|
||||
active_state: Arc<Mutex<ActiveState>>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
if active_state.lock().is_none() {
|
||||
cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
let group =
|
||||
group_bounds.map_or(false, |bounds| bounds.contains_point(down.position));
|
||||
let element = bounds.contains_point(down.position);
|
||||
if group || element {
|
||||
*active_state.lock() = ActiveState { group, element };
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
*active_state.lock() = ActiveState::default();
|
||||
cx.notify();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_event_listeners(
|
||||
&self,
|
||||
bounds: Bounds<Pixels>,
|
||||
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let click_listeners = self.listeners.mouse_click.clone();
|
||||
let mouse_down = pending_click.lock().clone();
|
||||
if let Some(mouse_down) = mouse_down {
|
||||
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
|
||||
let mouse_click = MouseClickEvent {
|
||||
down: mouse_down.clone(),
|
||||
up: event.clone(),
|
||||
};
|
||||
for listener in &click_listeners {
|
||||
listener(state, &mouse_click, &bounds, cx);
|
||||
}
|
||||
}
|
||||
|
||||
*pending_click.lock() = None;
|
||||
});
|
||||
} else {
|
||||
cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
|
||||
*pending_click.lock() = Some(event.clone());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for listener in self.listeners.mouse_down.iter().cloned() {
|
||||
cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.listeners.mouse_up.iter().cloned() {
|
||||
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.listeners.mouse_move.iter().cloned() {
|
||||
cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.listeners.scroll_wheel.iter().cloned() {
|
||||
cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Element for Div<V, K>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementKind,
|
||||
{
|
||||
type ViewState = V;
|
||||
type ElementState = DivState;
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
self.kind.id()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState) {
|
||||
self.with_element_id(cx, |this, cx| {
|
||||
let layout_ids = this
|
||||
.children
|
||||
.iter_mut()
|
||||
.map(|child| child.layout(view_state, cx))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let element_state = element_state.unwrap_or_default();
|
||||
let style = this.compute_style(
|
||||
Bounds::default(),
|
||||
None,
|
||||
*element_state.active_state.lock(),
|
||||
cx,
|
||||
);
|
||||
let layout_id = cx.request_layout(&style, layout_ids);
|
||||
(layout_id, element_state)
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) {
|
||||
self.with_element_id(cx, |this, cx| {
|
||||
if let Some(group) = this.group.clone() {
|
||||
cx.default_global::<GroupBounds>()
|
||||
.0
|
||||
.entry(group)
|
||||
.or_default()
|
||||
.push(bounds);
|
||||
}
|
||||
|
||||
let hover_group_bounds = this
|
||||
.group_hover
|
||||
.as_ref()
|
||||
.and_then(|group_hover| group_bounds(&group_hover.group, cx));
|
||||
let active_group_bounds = this
|
||||
.group_active
|
||||
.as_ref()
|
||||
.and_then(|group_active| group_bounds(&group_active.group, cx));
|
||||
let active_state = *element_state.active_state.lock();
|
||||
let style = this.compute_style(bounds, hover_group_bounds, active_state, cx);
|
||||
let z_index = style.z_index.unwrap_or(0);
|
||||
|
||||
// Paint background and event handlers.
|
||||
cx.stack(z_index, |cx| {
|
||||
cx.stack(0, |cx| {
|
||||
style.paint(bounds, cx);
|
||||
this.paint_hover_listeners(bounds, hover_group_bounds, cx);
|
||||
this.paint_active_listener(
|
||||
bounds,
|
||||
active_group_bounds,
|
||||
element_state.active_state.clone(),
|
||||
cx,
|
||||
);
|
||||
this.paint_event_listeners(bounds, element_state.pending_click.clone(), cx);
|
||||
});
|
||||
});
|
||||
|
||||
style.apply_text_style(cx, |cx| {
|
||||
style.apply_overflow(bounds, cx, |cx| {
|
||||
cx.stack(z_index + 1, |cx| {
|
||||
for child in &mut this.children {
|
||||
child.paint(view_state, None, cx);
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(group) = this.group.as_ref() {
|
||||
cx.default_global::<GroupBounds>()
|
||||
.0
|
||||
.get_mut(group)
|
||||
.unwrap()
|
||||
.pop();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync> IdentifiedElement for Div<V, IdentifiedElementKind> {
|
||||
fn id(&self) -> ElementId {
|
||||
self.kind.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> IntoAnyElement<V> for Div<V, K>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementKind,
|
||||
{
|
||||
fn into_any(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MouseClickEvent {
|
||||
pub down: MouseDownEvent,
|
||||
pub up: MouseUpEvent,
|
||||
}
|
||||
|
||||
type MouseDownHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
type MouseUpHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
type MouseClickHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseClickEvent, &Bounds<Pixels>, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||
>;
|
||||
|
||||
type MouseMoveHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
type ScrollWheelHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
pub struct MouseEventListeners<V: 'static> {
|
||||
mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
|
||||
mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
|
||||
mouse_click: SmallVec<[MouseClickHandler<V>; 2]>,
|
||||
mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
|
||||
scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
|
||||
}
|
||||
|
||||
impl<V> Default for MouseEventListeners<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mouse_down: SmallVec::new(),
|
||||
mouse_up: SmallVec::new(),
|
||||
mouse_click: SmallVec::new(),
|
||||
mouse_move: SmallVec::new(),
|
||||
scroll_wheel: SmallVec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
let hovered = bounds.contains_point(cx.mouse_position());
|
||||
cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
if bounds.contains_point(event.position) != hovered {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
use crate::{
|
||||
group_bounds, AnyElement, Bounds, DispatchPhase, Element, ElementId, IdentifiedElement,
|
||||
IntoAnyElement, LayoutId, MouseMoveEvent, ParentElement, Pixels, SharedString, Style,
|
||||
StyleCascade, StyleRefinement, Styled, ViewContext,
|
||||
};
|
||||
use refineable::CascadeSlot;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering::SeqCst},
|
||||
Arc,
|
||||
};
|
||||
|
||||
pub trait Hoverable {
|
||||
fn hover_style(&mut self) -> &mut StyleRefinement;
|
||||
|
||||
fn hover(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
f(self.hover_style());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HoverableElement<E> {
|
||||
hover_style: StyleRefinement,
|
||||
group: Option<SharedString>,
|
||||
cascade_slot: CascadeSlot,
|
||||
hovered: Arc<AtomicBool>,
|
||||
child: E,
|
||||
}
|
||||
|
||||
impl<E: Styled + Element> HoverableElement<E> {
|
||||
pub fn new(mut child: E) -> Self {
|
||||
let cascade_slot = child.style_cascade().reserve();
|
||||
HoverableElement {
|
||||
hover_style: StyleRefinement::default(),
|
||||
group: None,
|
||||
cascade_slot,
|
||||
hovered: Arc::new(AtomicBool::new(false)),
|
||||
child,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
|
||||
self,
|
||||
replace: impl FnOnce(E) -> E2,
|
||||
) -> HoverableElement<E2> {
|
||||
HoverableElement {
|
||||
hover_style: self.hover_style,
|
||||
group: self.group,
|
||||
cascade_slot: self.cascade_slot,
|
||||
hovered: self.hovered,
|
||||
child: replace(self.child),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> IntoAnyElement<E::ViewState> for HoverableElement<E>
|
||||
where
|
||||
E: Styled + Element,
|
||||
{
|
||||
fn into_any(self) -> AnyElement<E::ViewState> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Element for HoverableElement<E>
|
||||
where
|
||||
E: Styled + Element,
|
||||
{
|
||||
type ViewState = E::ViewState;
|
||||
type ElementState = E::ElementState;
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
self.child.id()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
state: &mut Self::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState) {
|
||||
self.child.layout(state, element_state, cx)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
state: &mut Self::ViewState,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) {
|
||||
let target_bounds = self
|
||||
.group
|
||||
.as_ref()
|
||||
.and_then(|group| group_bounds(group, cx))
|
||||
.unwrap_or(bounds);
|
||||
|
||||
let hovered = target_bounds.contains_point(cx.mouse_position());
|
||||
|
||||
let slot = self.cascade_slot;
|
||||
let style = hovered.then_some(self.hover_style.clone());
|
||||
self.child.style_cascade().set(slot, style);
|
||||
self.hovered.store(hovered, SeqCst);
|
||||
|
||||
let hovered = self.hovered.clone();
|
||||
cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
self.child.paint(bounds, state, element_state, cx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> ParentElement for HoverableElement<E>
|
||||
where
|
||||
E: Styled + ParentElement,
|
||||
{
|
||||
fn children_mut(&mut self) -> &mut smallvec::SmallVec<[AnyElement<E::ViewState>; 2]> {
|
||||
self.child.children_mut()
|
||||
}
|
||||
|
||||
fn group_mut(&mut self) -> &mut Option<SharedString> {
|
||||
self.child.group_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Styled + Element> Hoverable for HoverableElement<E> {
|
||||
fn hover_style(&mut self) -> &mut StyleRefinement {
|
||||
&mut self.hover_style
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Styled + Element> Styled for HoverableElement<E> {
|
||||
fn style_cascade(&mut self) -> &mut StyleCascade {
|
||||
self.child.style_cascade()
|
||||
}
|
||||
|
||||
fn computed_style(&mut self) -> &Style {
|
||||
self.child.computed_style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Styled + IdentifiedElement> IdentifiedElement for HoverableElement<E> {}
|
|
@ -1,15 +1,13 @@
|
|||
use crate::{
|
||||
AnonymousElementKind, AnyElement, BorrowWindow, Bounds, ClickListeners, Clickable,
|
||||
ClickableElement, ClickableElementState, Element, ElementId, ElementKind, Hoverable,
|
||||
HoverableElement, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId,
|
||||
LayoutNodeElement, Pixels, SharedString, Style, StyleRefinement, Styled, ViewContext,
|
||||
div, AnonymousElementKind, AnyElement, BorrowWindow, Bounds, Div, DivState, Element, ElementId,
|
||||
ElementKind, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, Pixels,
|
||||
SharedString, StyleRefinement, Styled, ViewContext,
|
||||
};
|
||||
use futures::FutureExt;
|
||||
use refineable::Cascade;
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct Img<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
|
||||
layout_node: ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
|
||||
base: Div<V, K>,
|
||||
uri: Option<SharedString>,
|
||||
grayscale: bool,
|
||||
}
|
||||
|
@ -19,7 +17,7 @@ where
|
|||
V: 'static + Send + Sync,
|
||||
{
|
||||
Img {
|
||||
layout_node: ClickableElement::new(HoverableElement::new(LayoutNodeElement::new())),
|
||||
base: div(),
|
||||
uri: None,
|
||||
grayscale: false,
|
||||
}
|
||||
|
@ -44,9 +42,7 @@ where
|
|||
impl<V: 'static + Send + Sync> Img<V, AnonymousElementKind> {
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Img<V, IdentifiedElementKind> {
|
||||
Img {
|
||||
layout_node: self.layout_node.replace_child(|hoverable| {
|
||||
hoverable.replace_child(|layout_node| layout_node.identify(id))
|
||||
}),
|
||||
base: self.base.id(id),
|
||||
uri: self.uri,
|
||||
grayscale: self.grayscale,
|
||||
}
|
||||
|
@ -69,10 +65,10 @@ where
|
|||
K: ElementKind,
|
||||
{
|
||||
type ViewState = V;
|
||||
type ElementState = ClickableElementState<()>;
|
||||
type ElementState = DivState;
|
||||
|
||||
fn id(&self) -> Option<crate::ElementId> {
|
||||
self.layout_node.id()
|
||||
self.base.id()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
|
@ -84,7 +80,7 @@ where
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.layout_node.layout(view_state, element_state, cx)
|
||||
self.base.layout(view_state, element_state, cx)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
|
@ -95,10 +91,10 @@ where
|
|||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) {
|
||||
cx.stack(1, |cx| {
|
||||
self.layout_node.paint(bounds, view, element_state, cx);
|
||||
self.base.paint(bounds, view, element_state, cx);
|
||||
});
|
||||
|
||||
let style = self.computed_style();
|
||||
let style = self.base.compute_style(bounds, element_state, cx);
|
||||
let corner_radii = style.corner_radii;
|
||||
|
||||
if let Some(uri) = self.uri.clone() {
|
||||
|
@ -127,7 +123,7 @@ where
|
|||
|
||||
impl<V: 'static + Send + Sync> IdentifiedElement for Img<V, IdentifiedElementKind> {
|
||||
fn id(&self) -> ElementId {
|
||||
IdentifiedElement::id(&self.layout_node)
|
||||
IdentifiedElement::id(&self.base)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,27 +132,7 @@ where
|
|||
V: 'static + Send + Sync,
|
||||
K: ElementKind,
|
||||
{
|
||||
fn style_cascade(&mut self) -> &mut Cascade<Style> {
|
||||
self.layout_node.style_cascade()
|
||||
}
|
||||
|
||||
fn computed_style(&mut self) -> &Style {
|
||||
self.layout_node.computed_style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Img<V, K> {
|
||||
fn hover_style(&mut self) -> &mut StyleRefinement {
|
||||
self.layout_node.hover_style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync> Clickable for Img<V, IdentifiedElementKind> {
|
||||
fn active_style(&mut self) -> &mut StyleRefinement {
|
||||
self.layout_node.active_style()
|
||||
}
|
||||
|
||||
fn listeners(&mut self) -> &mut ClickListeners<V> {
|
||||
self.layout_node.listeners()
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
self.base.style()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,193 +0,0 @@
|
|||
use crate::{
|
||||
AnyElement, AppContext, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement,
|
||||
IntoAnyElement, LayoutId, ParentElement, Pixels, SharedString, Style, StyleCascade, Styled,
|
||||
ViewContext,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use refineable::Refineable;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
#[derive(Default)]
|
||||
struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
|
||||
|
||||
pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
|
||||
cx.default_global::<GroupBounds>()
|
||||
.0
|
||||
.get(name)
|
||||
.and_then(|bounds_stack| bounds_stack.last().cloned())
|
||||
}
|
||||
|
||||
pub trait ElementKind: 'static + Send + Sync {
|
||||
fn id(&self) -> Option<ElementId>;
|
||||
}
|
||||
|
||||
pub struct IdentifiedElementKind(pub(crate) ElementId);
|
||||
pub struct AnonymousElementKind;
|
||||
|
||||
impl ElementKind for IdentifiedElementKind {
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
Some(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementKind for AnonymousElementKind {
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LayoutNodeElement<V: 'static + Send + Sync, K: ElementKind> {
|
||||
style_cascade: StyleCascade,
|
||||
computed_style: Option<Style>,
|
||||
children: SmallVec<[AnyElement<V>; 2]>,
|
||||
kind: K,
|
||||
group: Option<SharedString>,
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync> LayoutNodeElement<V, AnonymousElementKind> {
|
||||
pub fn new() -> LayoutNodeElement<V, AnonymousElementKind> {
|
||||
LayoutNodeElement {
|
||||
style_cascade: StyleCascade::default(),
|
||||
computed_style: None,
|
||||
children: SmallVec::new(),
|
||||
kind: AnonymousElementKind,
|
||||
group: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn identify(self, id: impl Into<ElementId>) -> LayoutNodeElement<V, IdentifiedElementKind> {
|
||||
LayoutNodeElement {
|
||||
style_cascade: self.style_cascade,
|
||||
computed_style: self.computed_style,
|
||||
children: self.children,
|
||||
kind: IdentifiedElementKind(id.into()),
|
||||
group: self.group,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync, E: ElementKind> LayoutNodeElement<V, E> {
|
||||
pub fn set_group(&mut self, group: impl Into<SharedString>) {
|
||||
self.group = Some(group.into());
|
||||
}
|
||||
|
||||
fn with_element_id<R>(
|
||||
&mut self,
|
||||
cx: &mut ViewContext<V>,
|
||||
f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
|
||||
) -> R {
|
||||
if let Some(id) = self.id() {
|
||||
cx.with_element_id(id, |cx| f(self, cx))
|
||||
} else {
|
||||
f(self, cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync, K: ElementKind> Styled for LayoutNodeElement<V, K> {
|
||||
fn style_cascade(&mut self) -> &mut StyleCascade {
|
||||
&mut self.style_cascade
|
||||
}
|
||||
|
||||
fn computed_style(&mut self) -> &Style {
|
||||
self.computed_style
|
||||
.get_or_insert_with(|| Style::default().refined(self.style_cascade.merged()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync> IdentifiedElement for LayoutNodeElement<V, IdentifiedElementKind> {
|
||||
fn id(&self) -> ElementId {
|
||||
self.kind.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> IntoAnyElement<V> for LayoutNodeElement<V, K>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementKind,
|
||||
{
|
||||
fn into_any(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync, K: ElementKind> Element for LayoutNodeElement<V, K> {
|
||||
type ViewState = V;
|
||||
type ElementState = ();
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
self.kind.id()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
state: &mut Self::ViewState,
|
||||
_: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState) {
|
||||
self.with_element_id(cx, |this, cx| {
|
||||
let layout_ids = this
|
||||
.children
|
||||
.iter_mut()
|
||||
.map(|child| child.layout(state, cx))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let style = this.computed_style();
|
||||
let layout_id = cx.request_layout(style, layout_ids);
|
||||
(layout_id, ())
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
state: &mut Self::ViewState,
|
||||
_: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) {
|
||||
self.with_element_id(cx, |this, cx| {
|
||||
if let Some(group) = this.group.clone() {
|
||||
cx.default_global::<GroupBounds>()
|
||||
.0
|
||||
.entry(group)
|
||||
.or_default()
|
||||
.push(bounds);
|
||||
}
|
||||
|
||||
let style = this.computed_style().clone();
|
||||
let z_index = style.z_index.unwrap_or(0);
|
||||
cx.stack(z_index, |cx| style.paint(bounds, cx));
|
||||
|
||||
// todo!("implement overflow")
|
||||
// let overflow = &style.overflow;
|
||||
|
||||
style.apply_text_style(cx, |cx| {
|
||||
cx.stack(z_index + 1, |cx| {
|
||||
style.apply_overflow(bounds, cx, |cx| {
|
||||
for child in &mut this.children {
|
||||
child.paint(state, None, cx);
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(group) = this.group.as_ref() {
|
||||
cx.default_global::<GroupBounds>()
|
||||
.0
|
||||
.get_mut(group)
|
||||
.unwrap()
|
||||
.pop();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync, K: ElementKind> ParentElement for LayoutNodeElement<V, K> {
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||
&mut self.children
|
||||
}
|
||||
|
||||
fn group_mut(&mut self) -> &mut Option<SharedString> {
|
||||
&mut self.group
|
||||
}
|
||||
}
|
|
@ -1,14 +1,12 @@
|
|||
use crate::{
|
||||
AnonymousElementKind, AnyElement, Bounds, ClickListeners, Clickable, ClickableElement,
|
||||
ClickableElementState, Element, ElementId, ElementKind, Hoverable, HoverableElement,
|
||||
IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, LayoutNodeElement, Pixels,
|
||||
SharedString, Style, StyleRefinement, Styled,
|
||||
div, AnonymousElementKind, AnyElement, Bounds, Div, DivState, Element, ElementId, ElementKind,
|
||||
IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, Pixels, SharedString,
|
||||
StyleRefinement, Styled,
|
||||
};
|
||||
use refineable::Cascade;
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct Svg<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
|
||||
layout_node: ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
|
||||
base: Div<V, K>,
|
||||
path: Option<SharedString>,
|
||||
}
|
||||
|
||||
|
@ -17,7 +15,7 @@ where
|
|||
V: 'static + Send + Sync,
|
||||
{
|
||||
Svg {
|
||||
layout_node: ClickableElement::new(HoverableElement::new(LayoutNodeElement::new())),
|
||||
base: div(),
|
||||
path: None,
|
||||
}
|
||||
}
|
||||
|
@ -36,9 +34,7 @@ where
|
|||
impl<V: 'static + Send + Sync> Svg<V, AnonymousElementKind> {
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, IdentifiedElementKind> {
|
||||
Svg {
|
||||
layout_node: self.layout_node.replace_child(|hoverable| {
|
||||
hoverable.replace_child(|layout_node| layout_node.identify(id))
|
||||
}),
|
||||
base: self.base.id(id),
|
||||
path: self.path,
|
||||
}
|
||||
}
|
||||
|
@ -60,10 +56,10 @@ where
|
|||
K: ElementKind,
|
||||
{
|
||||
type ViewState = V;
|
||||
type ElementState = ClickableElementState<()>;
|
||||
type ElementState = DivState;
|
||||
|
||||
fn id(&self) -> Option<crate::ElementId> {
|
||||
self.layout_node.id()
|
||||
self.base.id()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
|
@ -75,7 +71,7 @@ where
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.layout_node.layout(view, element_state, cx)
|
||||
self.base.layout(view, element_state, cx)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
|
@ -87,9 +83,10 @@ where
|
|||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
self.layout_node.paint(bounds, view, element_state, cx);
|
||||
self.base.paint(bounds, view, element_state, cx);
|
||||
let fill_color = self
|
||||
.computed_style()
|
||||
.base
|
||||
.compute_style(bounds, element_state, cx)
|
||||
.fill
|
||||
.as_ref()
|
||||
.and_then(|fill| fill.color());
|
||||
|
@ -101,7 +98,7 @@ where
|
|||
|
||||
impl<V: 'static + Send + Sync> IdentifiedElement for Svg<V, IdentifiedElementKind> {
|
||||
fn id(&self) -> ElementId {
|
||||
IdentifiedElement::id(&self.layout_node)
|
||||
IdentifiedElement::id(&self.base)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,27 +107,7 @@ where
|
|||
V: 'static + Send + Sync,
|
||||
K: ElementKind,
|
||||
{
|
||||
fn style_cascade(&mut self) -> &mut Cascade<Style> {
|
||||
self.layout_node.style_cascade()
|
||||
}
|
||||
|
||||
fn computed_style(&mut self) -> &Style {
|
||||
self.layout_node.computed_style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Svg<V, K> {
|
||||
fn hover_style(&mut self) -> &mut StyleRefinement {
|
||||
self.layout_node.hover_style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync> Clickable for Svg<V, IdentifiedElementKind> {
|
||||
fn active_style(&mut self) -> &mut StyleRefinement {
|
||||
self.layout_node.active_style()
|
||||
}
|
||||
|
||||
fn listeners(&mut self) -> &mut ClickListeners<V> {
|
||||
self.layout_node.listeners()
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
self.base.style()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -413,7 +413,7 @@ impl<T> Bounds<T>
|
|||
where
|
||||
T: Add<T, Output = T> + PartialOrd + Clone + Default + Debug,
|
||||
{
|
||||
pub fn contains_point(&self, point: Point<T>) -> bool {
|
||||
pub fn contains_point(&self, point: &Point<T>) -> bool {
|
||||
point.x >= self.origin.x
|
||||
&& point.x <= self.origin.x.clone() + self.size.width.clone()
|
||||
&& point.y >= self.origin.y
|
||||
|
|
|
@ -7,7 +7,6 @@ mod events;
|
|||
mod executor;
|
||||
mod geometry;
|
||||
mod image_cache;
|
||||
mod interactive;
|
||||
mod platform;
|
||||
mod scene;
|
||||
mod style;
|
||||
|
@ -31,7 +30,6 @@ pub use executor::*;
|
|||
pub use geometry::*;
|
||||
pub use gpui3_macros::*;
|
||||
pub use image_cache::*;
|
||||
pub use interactive::*;
|
||||
pub use platform::*;
|
||||
pub use refineable::*;
|
||||
pub use scene::*;
|
||||
|
|
|
@ -1,198 +0,0 @@
|
|||
use crate::{
|
||||
Bounds, DispatchPhase, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
|
||||
ScrollWheelEvent, ViewContext,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait Interactive<S: 'static + Send + Sync> {
|
||||
fn listeners(&mut self) -> &mut MouseEventListeners<S>;
|
||||
|
||||
fn on_mouse_down(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_down
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.contains_point(event.position)
|
||||
{
|
||||
handler(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_mouse_up(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_up
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.contains_point(event.position)
|
||||
{
|
||||
handler(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_mouse_down_out(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_down
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.contains_point(event.position)
|
||||
{
|
||||
handler(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_mouse_up_out(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_up
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.contains_point(event.position)
|
||||
{
|
||||
handler(view, event, cx);
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_mouse_move(
|
||||
mut self,
|
||||
handler: impl Fn(&mut S, &MouseMoveEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_move
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
|
||||
handler(view, event, cx);
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_scroll_wheel(
|
||||
mut self,
|
||||
handler: impl Fn(&mut S, &ScrollWheelEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.listeners()
|
||||
.scroll_wheel
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(event.position) {
|
||||
handler(view, event, cx);
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
type MouseDownHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
type MouseUpHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
type MouseMoveHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
type ScrollWheelHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
pub struct MouseEventListeners<V: 'static> {
|
||||
mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
|
||||
mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
|
||||
mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
|
||||
scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
|
||||
}
|
||||
|
||||
impl<S: Send + Sync + 'static> MouseEventListeners<S> {
|
||||
pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<S>) {
|
||||
for handler in self.mouse_down.iter().cloned() {
|
||||
cx.on_mouse_event(move |view, event: &MouseDownEvent, phase, cx| {
|
||||
handler(view, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
for handler in self.mouse_up.iter().cloned() {
|
||||
cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
|
||||
handler(view, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
for handler in self.mouse_move.iter().cloned() {
|
||||
cx.on_mouse_event(move |view, event: &MouseMoveEvent, phase, cx| {
|
||||
handler(view, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for handler in self.scroll_wheel.iter().cloned() {
|
||||
cx.on_mouse_event(move |view, event: &ScrollWheelEvent, phase, cx| {
|
||||
handler(view, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Default for MouseEventListeners<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mouse_down: Default::default(),
|
||||
mouse_up: Default::default(),
|
||||
mouse_move: Default::default(),
|
||||
scroll_wheel: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,12 @@
|
|||
use crate::{
|
||||
self as gpui3, hsla, point, px, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla,
|
||||
JustifyContent, Length, Position, SharedString, Style, StyleCascade, StyleRefinement,
|
||||
JustifyContent, Length, Position, SharedString, StyleRefinement,
|
||||
};
|
||||
use crate::{BoxShadow, TextStyleRefinement};
|
||||
use smallvec::smallvec;
|
||||
|
||||
pub trait Styled {
|
||||
fn style_cascade(&mut self) -> &mut StyleCascade;
|
||||
fn computed_style(&mut self) -> &Style;
|
||||
fn base_style(&mut self) -> &mut StyleRefinement {
|
||||
self.style_cascade().base()
|
||||
}
|
||||
fn style(&mut self) -> &mut StyleRefinement;
|
||||
|
||||
gpui3_macros::style_helpers!();
|
||||
|
||||
|
@ -18,8 +14,8 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().size.width = Some(relative(1.).into());
|
||||
self.base_style().size.height = Some(relative(1.).into());
|
||||
self.style().size.width = Some(relative(1.).into());
|
||||
self.style().size.height = Some(relative(1.).into());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -27,7 +23,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().position = Some(Position::Relative);
|
||||
self.style().position = Some(Position::Relative);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -35,7 +31,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().position = Some(Position::Absolute);
|
||||
self.style().position = Some(Position::Absolute);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -43,7 +39,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().display = Some(Display::Block);
|
||||
self.style().display = Some(Display::Block);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -51,7 +47,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().display = Some(Display::Flex);
|
||||
self.style().display = Some(Display::Flex);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -59,7 +55,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().flex_direction = Some(FlexDirection::Column);
|
||||
self.style().flex_direction = Some(FlexDirection::Column);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -67,7 +63,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().flex_direction = Some(FlexDirection::Row);
|
||||
self.style().flex_direction = Some(FlexDirection::Row);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -75,9 +71,9 @@ pub trait Styled {
|
|||
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.style().flex_grow = Some(1.);
|
||||
self.style().flex_shrink = Some(1.);
|
||||
self.style().flex_basis = Some(relative(0.).into());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -85,9 +81,9 @@ pub trait Styled {
|
|||
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.style().flex_grow = Some(1.);
|
||||
self.style().flex_shrink = Some(1.);
|
||||
self.style().flex_basis = Some(Length::Auto);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -95,9 +91,9 @@ pub trait Styled {
|
|||
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.style().flex_grow = Some(0.);
|
||||
self.style().flex_shrink = Some(1.);
|
||||
self.style().flex_basis = Some(Length::Auto);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -105,8 +101,8 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().flex_grow = Some(0.);
|
||||
self.base_style().flex_shrink = Some(0.);
|
||||
self.style().flex_grow = Some(0.);
|
||||
self.style().flex_shrink = Some(0.);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -114,7 +110,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().flex_grow = Some(1.);
|
||||
self.style().flex_grow = Some(1.);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -122,7 +118,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().align_items = Some(AlignItems::FlexStart);
|
||||
self.style().align_items = Some(AlignItems::FlexStart);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -130,7 +126,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().align_items = Some(AlignItems::FlexEnd);
|
||||
self.style().align_items = Some(AlignItems::FlexEnd);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -138,7 +134,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().align_items = Some(AlignItems::Center);
|
||||
self.style().align_items = Some(AlignItems::Center);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -146,7 +142,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().justify_content = Some(JustifyContent::SpaceBetween);
|
||||
self.style().justify_content = Some(JustifyContent::SpaceBetween);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -154,7 +150,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().justify_content = Some(JustifyContent::Center);
|
||||
self.style().justify_content = Some(JustifyContent::Center);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -162,7 +158,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().justify_content = Some(JustifyContent::Start);
|
||||
self.style().justify_content = Some(JustifyContent::Start);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -170,7 +166,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().justify_content = Some(JustifyContent::End);
|
||||
self.style().justify_content = Some(JustifyContent::End);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -178,7 +174,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().justify_content = Some(JustifyContent::SpaceAround);
|
||||
self.style().justify_content = Some(JustifyContent::SpaceAround);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -187,7 +183,7 @@ pub trait Styled {
|
|||
F: Into<Fill>,
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().fill = Some(fill.into());
|
||||
self.style().fill = Some(fill.into());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -196,7 +192,7 @@ pub trait Styled {
|
|||
C: Into<Hsla>,
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().border_color = Some(border_color.into());
|
||||
self.style().border_color = Some(border_color.into());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -204,7 +200,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().box_shadow = Some(smallvec![
|
||||
self.style().box_shadow = Some(smallvec![
|
||||
BoxShadow {
|
||||
color: hsla(0., 0., 0., 0.1),
|
||||
offset: point(px(0.), px(1.)),
|
||||
|
@ -225,7 +221,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().box_shadow = Some(Default::default());
|
||||
self.style().box_shadow = Some(Default::default());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -233,7 +229,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().box_shadow = Some(smallvec::smallvec![BoxShadow {
|
||||
self.style().box_shadow = Some(smallvec::smallvec![BoxShadow {
|
||||
color: hsla(0., 0., 0., 0.05),
|
||||
offset: point(px(0.), px(1.)),
|
||||
blur_radius: px(2.),
|
||||
|
@ -246,7 +242,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().box_shadow = Some(smallvec![
|
||||
self.style().box_shadow = Some(smallvec![
|
||||
BoxShadow {
|
||||
color: hsla(0.5, 0., 0., 0.1),
|
||||
offset: point(px(0.), px(4.)),
|
||||
|
@ -267,7 +263,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().box_shadow = Some(smallvec![
|
||||
self.style().box_shadow = Some(smallvec![
|
||||
BoxShadow {
|
||||
color: hsla(0., 0., 0., 0.1),
|
||||
offset: point(px(0.), px(10.)),
|
||||
|
@ -288,7 +284,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().box_shadow = Some(smallvec![
|
||||
self.style().box_shadow = Some(smallvec![
|
||||
BoxShadow {
|
||||
color: hsla(0., 0., 0., 0.1),
|
||||
offset: point(px(0.), px(20.)),
|
||||
|
@ -309,7 +305,7 @@ pub trait Styled {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base_style().box_shadow = Some(smallvec![BoxShadow {
|
||||
self.style().box_shadow = Some(smallvec![BoxShadow {
|
||||
color: hsla(0., 0., 0., 0.25),
|
||||
offset: point(px(0.), px(25.)),
|
||||
blur_radius: px(50.),
|
||||
|
@ -319,7 +315,7 @@ pub trait Styled {
|
|||
}
|
||||
|
||||
fn text_style(&mut self) -> &mut Option<TextStyleRefinement> {
|
||||
let style: &mut StyleRefinement = self.base_style();
|
||||
let style: &mut StyleRefinement = self.style();
|
||||
&mut style.text
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ fn generate_predefined_setter(
|
|||
let method = quote! {
|
||||
#[doc = #doc_string]
|
||||
fn #method_name(mut self) -> Self where Self: std::marker::Sized {
|
||||
let mut style = self.base_style();
|
||||
let style = self.style();
|
||||
#(#field_assignments)*
|
||||
self
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ fn generate_custom_value_setter(
|
|||
|
||||
let method = quote! {
|
||||
fn #method_name(mut self, length: impl std::clone::Clone + Into<gpui3::#length_type>) -> Self where Self: std::marker::Sized {
|
||||
let mut style = self.base_style();
|
||||
let style = self.style();
|
||||
#(#field_assignments)*
|
||||
self
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue