Use RefinementCascade to compose pressability and hoverability
Co-Authored-By: Conrad Irwin <conrad@zed.dev>
This commit is contained in:
parent
569d99a5a1
commit
5996b6b46b
10 changed files with 202 additions and 68 deletions
|
@ -3,21 +3,22 @@ use crate::{
|
||||||
interactive::{InteractionHandlers, Interactive},
|
interactive::{InteractionHandlers, Interactive},
|
||||||
layout_context::LayoutContext,
|
layout_context::LayoutContext,
|
||||||
paint_context::PaintContext,
|
paint_context::PaintContext,
|
||||||
style::{Style, StyleHelpers, StyleRefinement, Styleable},
|
style::{Style, StyleHelpers, Styleable},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gpui::LayoutId;
|
use gpui::LayoutId;
|
||||||
|
use refineable::{Refineable, RefinementCascade};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
pub struct Div<V: 'static> {
|
pub struct Div<V: 'static> {
|
||||||
style: StyleRefinement,
|
styles: RefinementCascade<Style>,
|
||||||
handlers: InteractionHandlers<V>,
|
handlers: InteractionHandlers<V>,
|
||||||
children: SmallVec<[AnyElement<V>; 2]>,
|
children: SmallVec<[AnyElement<V>; 2]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn div<V>() -> Div<V> {
|
pub fn div<V>() -> Div<V> {
|
||||||
Div {
|
Div {
|
||||||
style: Default::default(),
|
styles: Default::default(),
|
||||||
handlers: Default::default(),
|
handlers: Default::default(),
|
||||||
children: Default::default(),
|
children: Default::default(),
|
||||||
}
|
}
|
||||||
|
@ -36,16 +37,16 @@ impl<V: 'static> Element<V> for Div<V> {
|
||||||
.map(|child| child.layout(view, cx))
|
.map(|child| child.layout(view, cx))
|
||||||
.collect::<Result<Vec<LayoutId>>>()?;
|
.collect::<Result<Vec<LayoutId>>>()?;
|
||||||
|
|
||||||
cx.add_layout_node(self.style(), (), children)
|
let style = Style::from_refinement(&self.style_cascade().merged());
|
||||||
|
cx.add_layout_node(style.clone(), (), children)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(&mut self, view: &mut V, layout: &mut Layout<V, ()>, cx: &mut PaintContext<V>)
|
fn paint(&mut self, view: &mut V, layout: &mut Layout<V, ()>, cx: &mut PaintContext<V>)
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let style = self.style();
|
self.computed_style()
|
||||||
|
.paint_background(layout.bounds(cx), cx);
|
||||||
style.paint_background::<V, Self>(layout, cx);
|
|
||||||
for child in &mut self.children {
|
for child in &mut self.children {
|
||||||
child.paint(view, cx);
|
child.paint(view, cx);
|
||||||
}
|
}
|
||||||
|
@ -55,8 +56,12 @@ impl<V: 'static> Element<V> for Div<V> {
|
||||||
impl<V> Styleable for Div<V> {
|
impl<V> Styleable for Div<V> {
|
||||||
type Style = Style;
|
type Style = Style;
|
||||||
|
|
||||||
fn declared_style(&mut self) -> &mut StyleRefinement {
|
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
|
||||||
&mut self.style
|
&mut self.styles
|
||||||
|
}
|
||||||
|
|
||||||
|
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
|
||||||
|
self.styles.base()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
use derive_more::{Deref, DerefMut};
|
|
||||||
use gpui::{geometry::rect::RectF, EngineLayout};
|
use gpui::{geometry::rect::RectF, EngineLayout};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -83,13 +82,10 @@ impl<V> AnyElement<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deref, DerefMut)]
|
|
||||||
pub struct Layout<V, D> {
|
pub struct Layout<V, D> {
|
||||||
id: LayoutId,
|
id: LayoutId,
|
||||||
engine_layout: Option<EngineLayout>,
|
engine_layout: Option<EngineLayout>,
|
||||||
#[deref]
|
element_data: Option<D>,
|
||||||
#[deref_mut]
|
|
||||||
element_data: D,
|
|
||||||
view_type: PhantomData<V>,
|
view_type: PhantomData<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +94,7 @@ impl<V: 'static, D> Layout<V, D> {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
engine_layout: None,
|
engine_layout: None,
|
||||||
element_data: element_data,
|
element_data: Some(element_data),
|
||||||
view_type: PhantomData,
|
view_type: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,20 +107,26 @@ impl<V: 'static, D> Layout<V, D> {
|
||||||
self.engine_layout(cx).order
|
self.engine_layout(cx).order
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update<F, T>(&mut self, update: F) -> Result<T>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Self, &mut D) -> T,
|
||||||
|
{
|
||||||
|
self.element_data
|
||||||
|
.take()
|
||||||
|
.map(|mut element_data| {
|
||||||
|
let result = update(self, &mut element_data);
|
||||||
|
self.element_data = Some(element_data);
|
||||||
|
result
|
||||||
|
})
|
||||||
|
.ok_or_else(|| anyhow!("reentrant calls to Layout::update are not allowed"))
|
||||||
|
}
|
||||||
|
|
||||||
fn engine_layout(&mut self, cx: &mut PaintContext<'_, '_, '_, '_, V>) -> &mut EngineLayout {
|
fn engine_layout(&mut self, cx: &mut PaintContext<'_, '_, '_, '_, V>) -> &mut EngineLayout {
|
||||||
self.engine_layout
|
self.engine_layout
|
||||||
.get_or_insert_with(|| cx.computed_layout(self.id).log_err().unwrap_or_default())
|
.get_or_insert_with(|| cx.computed_layout(self.id).log_err().unwrap_or_default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> Layout<V, Option<AnyElement<V>>> {
|
|
||||||
pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
|
|
||||||
let mut element = self.element_data.take().unwrap();
|
|
||||||
element.paint(view, cx);
|
|
||||||
self.element_data = Some(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ParentElement<V: 'static> {
|
pub trait ParentElement<V: 'static> {
|
||||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
|
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
|
||||||
|
|
||||||
|
|
|
@ -2,24 +2,24 @@ use crate::{
|
||||||
element::{Element, Layout},
|
element::{Element, Layout},
|
||||||
layout_context::LayoutContext,
|
layout_context::LayoutContext,
|
||||||
paint_context::PaintContext,
|
paint_context::PaintContext,
|
||||||
style::{Style, StyleHelpers, StyleRefinement, Styleable},
|
style::{Style, StyleHelpers, Styleable},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gpui::platform::MouseMovedEvent;
|
use gpui::platform::MouseMovedEvent;
|
||||||
use refineable::Refineable;
|
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
||||||
use std::cell::Cell;
|
use std::{cell::Cell, rc::Rc};
|
||||||
|
|
||||||
pub struct Hoverable<E: Styleable> {
|
pub struct Hoverable<E: Styleable> {
|
||||||
hovered: Cell<bool>,
|
hovered: Rc<Cell<bool>>,
|
||||||
child_style: StyleRefinement,
|
cascade_slot: CascadeSlot,
|
||||||
hovered_style: StyleRefinement,
|
hovered_style: <E::Style as Refineable>::Refinement,
|
||||||
child: E,
|
child: E,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hoverable<E: Styleable>(mut child: E) -> Hoverable<E> {
|
pub fn hoverable<E: Styleable>(mut child: E) -> Hoverable<E> {
|
||||||
Hoverable {
|
Hoverable {
|
||||||
hovered: Cell::new(false),
|
hovered: Rc::new(Cell::new(false)),
|
||||||
child_style: child.declared_style().clone(),
|
cascade_slot: child.style_cascade().reserve(),
|
||||||
hovered_style: Default::default(),
|
hovered_style: Default::default(),
|
||||||
child,
|
child,
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,11 @@ pub fn hoverable<E: Styleable>(mut child: E) -> Hoverable<E> {
|
||||||
impl<E: Styleable> Styleable for Hoverable<E> {
|
impl<E: Styleable> Styleable for Hoverable<E> {
|
||||||
type Style = E::Style;
|
type Style = E::Style;
|
||||||
|
|
||||||
fn declared_style(&mut self) -> &mut crate::style::StyleRefinement {
|
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
|
||||||
|
self.child.style_cascade()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
|
||||||
&mut self.hovered_style
|
&mut self.hovered_style
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,13 +59,10 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<E> {
|
||||||
let order = layout.order(cx);
|
let order = layout.order(cx);
|
||||||
|
|
||||||
self.hovered.set(bounds.contains_point(cx.mouse_position()));
|
self.hovered.set(bounds.contains_point(cx.mouse_position()));
|
||||||
if self.hovered.get() {
|
|
||||||
// If hovered, refine the child's style with this element's style.
|
let slot = self.cascade_slot;
|
||||||
self.child.declared_style().refine(&self.hovered_style);
|
let style = self.hovered.get().then_some(self.hovered_style.clone());
|
||||||
} else {
|
self.style_cascade().set(slot, style);
|
||||||
// Otherwise, set the child's style back to its original style.
|
|
||||||
*self.child.declared_style() = self.child_style.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
let hovered = self.hovered.clone();
|
let hovered = self.hovered.clone();
|
||||||
cx.on_event(order, move |view, event: &MouseMovedEvent, cx| {
|
cx.on_event(order, move |view, event: &MouseMovedEvent, cx| {
|
||||||
|
|
|
@ -22,6 +22,7 @@ mod hoverable;
|
||||||
mod interactive;
|
mod interactive;
|
||||||
mod layout_context;
|
mod layout_context;
|
||||||
mod paint_context;
|
mod paint_context;
|
||||||
|
mod pressable;
|
||||||
mod style;
|
mod style;
|
||||||
mod text;
|
mod text;
|
||||||
mod themes;
|
mod themes;
|
||||||
|
@ -54,8 +55,10 @@ fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
||||||
.h_full()
|
.h_full()
|
||||||
.w_1_2()
|
.w_1_2()
|
||||||
.fill(theme.success(0.5))
|
.fill(theme.success(0.5))
|
||||||
.hoverable()
|
.hovered()
|
||||||
.fill(theme.error(0.5))
|
.fill(theme.error(0.5))
|
||||||
|
.pressed()
|
||||||
|
.fill(theme.warning(0.5))
|
||||||
// .child(button().label("Hello").click(|_, _, _| println!("click!")))
|
// .child(button().label("Hello").click(|_, _, _| println!("click!")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
81
crates/gpui/playground/src/pressable.rs
Normal file
81
crates/gpui/playground/src/pressable.rs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
use crate::{
|
||||||
|
element::{Element, Layout},
|
||||||
|
layout_context::LayoutContext,
|
||||||
|
paint_context::PaintContext,
|
||||||
|
style::{Style, StyleHelpers, Styleable},
|
||||||
|
};
|
||||||
|
use anyhow::Result;
|
||||||
|
use gpui::platform::MouseButtonEvent;
|
||||||
|
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
||||||
|
use std::{cell::Cell, rc::Rc};
|
||||||
|
|
||||||
|
pub struct Pressable<E: Styleable> {
|
||||||
|
pressed: Rc<Cell<bool>>,
|
||||||
|
pressed_style: <E::Style as Refineable>::Refinement,
|
||||||
|
cascade_slot: CascadeSlot,
|
||||||
|
child: E,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pressable<E: Styleable>(mut child: E) -> Pressable<E> {
|
||||||
|
Pressable {
|
||||||
|
pressed: Rc::new(Cell::new(false)),
|
||||||
|
pressed_style: Default::default(),
|
||||||
|
cascade_slot: child.style_cascade().reserve(),
|
||||||
|
child,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Styleable> Styleable for Pressable<E> {
|
||||||
|
type Style = E::Style;
|
||||||
|
|
||||||
|
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
|
||||||
|
&mut self.pressed_style
|
||||||
|
}
|
||||||
|
|
||||||
|
fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
|
||||||
|
self.child.style_cascade()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
|
||||||
|
type Layout = E::Layout;
|
||||||
|
|
||||||
|
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<Layout<V, Self::Layout>>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.child.layout(view, cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint(
|
||||||
|
&mut self,
|
||||||
|
view: &mut V,
|
||||||
|
layout: &mut Layout<V, Self::Layout>,
|
||||||
|
cx: &mut PaintContext<V>,
|
||||||
|
) where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let slot = self.cascade_slot;
|
||||||
|
let style = self.pressed.get().then_some(self.pressed_style.clone());
|
||||||
|
self.style_cascade().set(slot, style);
|
||||||
|
|
||||||
|
let bounds = layout.bounds(cx);
|
||||||
|
let order = layout.order(cx);
|
||||||
|
let pressed = self.pressed.clone();
|
||||||
|
cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
|
||||||
|
if event.is_down {
|
||||||
|
if bounds.contains_point(event.position) {
|
||||||
|
pressed.set(true);
|
||||||
|
cx.repaint();
|
||||||
|
}
|
||||||
|
} else if pressed.get() {
|
||||||
|
pressed.set(false);
|
||||||
|
cx.repaint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.child.paint(view, layout, cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Styleable<Style = Style>> StyleHelpers for Pressable<E> {}
|
|
@ -1,18 +1,18 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
color::Hsla,
|
color::Hsla,
|
||||||
element::{Element, Layout},
|
|
||||||
hoverable::{hoverable, Hoverable},
|
hoverable::{hoverable, Hoverable},
|
||||||
paint_context::PaintContext,
|
paint_context::PaintContext,
|
||||||
|
pressable::{pressable, Pressable},
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
fonts::TextStyleRefinement,
|
fonts::TextStyleRefinement,
|
||||||
geometry::{
|
geometry::{
|
||||||
AbsoluteLength, DefiniteLength, Edges, EdgesRefinement, Length, Point, PointRefinement,
|
rect::RectF, AbsoluteLength, DefiniteLength, Edges, EdgesRefinement, Length, Point,
|
||||||
Size, SizeRefinement,
|
PointRefinement, Size, SizeRefinement,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use playground_macros::styleable_helpers;
|
use playground_macros::styleable_helpers;
|
||||||
use refineable::Refineable;
|
use refineable::{Refineable, RefinementCascade};
|
||||||
pub use taffy::style::{
|
pub use taffy::style::{
|
||||||
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
|
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
|
||||||
Overflow, Position,
|
Overflow, Position,
|
||||||
|
@ -126,12 +126,7 @@ impl Style {
|
||||||
|
|
||||||
/// Paints the background of an element styled with this style.
|
/// Paints the background of an element styled with this style.
|
||||||
/// Return the bounds in which to paint the content.
|
/// Return the bounds in which to paint the content.
|
||||||
pub fn paint_background<V: 'static, E: Element<V>>(
|
pub fn paint_background<V: 'static>(&self, bounds: RectF, cx: &mut PaintContext<V>) {
|
||||||
&self,
|
|
||||||
layout: &mut Layout<V, E::Layout>,
|
|
||||||
cx: &mut PaintContext<V>,
|
|
||||||
) {
|
|
||||||
let bounds = layout.bounds(cx);
|
|
||||||
let rem_size = cx.rem_pixels();
|
let rem_size = cx.rem_pixels();
|
||||||
if let Some(color) = self.fill.as_ref().and_then(Fill::color) {
|
if let Some(color) = self.fill.as_ref().and_then(Fill::color) {
|
||||||
cx.scene.push_quad(gpui::Quad {
|
cx.scene.push_quad(gpui::Quad {
|
||||||
|
@ -202,7 +197,7 @@ impl OptionalTextStyle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Fill {
|
pub enum Fill {
|
||||||
Color(Hsla),
|
Color(Hsla),
|
||||||
}
|
}
|
||||||
|
@ -247,22 +242,28 @@ impl CornerRadii {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Styleable {
|
pub trait Styleable {
|
||||||
type Style: refineable::Refineable;
|
type Style: Refineable + Default;
|
||||||
|
|
||||||
fn declared_style(&mut self) -> &mut playground::style::StyleRefinement;
|
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style>;
|
||||||
|
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
|
||||||
|
|
||||||
fn style(&mut self) -> playground::style::Style {
|
fn computed_style(&mut self) -> Self::Style {
|
||||||
let mut style = playground::style::Style::default();
|
Self::Style::from_refinement(&self.style_cascade().merged())
|
||||||
style.refine(self.declared_style());
|
|
||||||
style
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hoverable(self) -> Hoverable<Self>
|
fn hovered(self) -> Hoverable<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
hoverable(self)
|
hoverable(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pressed(self) -> Pressable<Self>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
pressable(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers methods that take and return mut self. This includes tailwind style methods for standard sizes etc.
|
// Helpers methods that take and return mut self. This includes tailwind style methods for standard sizes etc.
|
||||||
|
@ -270,7 +271,6 @@ pub trait Styleable {
|
||||||
// Example:
|
// Example:
|
||||||
// // Sets the padding to 0.5rem, just like class="p-2" in Tailwind.
|
// // Sets the padding to 0.5rem, just like class="p-2" in Tailwind.
|
||||||
// fn p_2(mut self) -> Self where Self: Sized;
|
// fn p_2(mut self) -> Self where Self: Sized;
|
||||||
use crate as playground; // Macro invocation references this crate as playground.
|
|
||||||
pub trait StyleHelpers: Styleable<Style = Style> {
|
pub trait StyleHelpers: Styleable<Style = Style> {
|
||||||
styleable_helpers!();
|
styleable_helpers!();
|
||||||
|
|
||||||
|
|
|
@ -62,16 +62,16 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
|
||||||
impl #impl_generics playground::element::Element<#view_type_name> for #type_name #type_generics
|
impl #impl_generics playground::element::Element<#view_type_name> for #type_name #type_generics
|
||||||
#where_clause
|
#where_clause
|
||||||
{
|
{
|
||||||
type Layout = Option<playground::element::AnyElement<#view_type_name #lifetimes>>;
|
type Layout = playground::element::AnyElement<#view_type_name #lifetimes>;
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
cx: &mut playground::element::LayoutContext<V>,
|
cx: &mut playground::element::LayoutContext<V>,
|
||||||
) -> anyhow::Result<playground::element::Layout<V, Self::Layout>> {
|
) -> anyhow::Result<playground::element::Layout<V, Self::Layout>> {
|
||||||
let mut element = self.render(view, cx).into_any();
|
let mut rendered_element = self.render(view, cx).into_any();
|
||||||
let layout_id = element.layout(view, cx)?;
|
let layout_id = rendered_element.layout(view, cx)?;
|
||||||
Ok(playground::element::Layout::new(layout_id, Some(element)))
|
Ok(playground::element::Layout::new(layout_id, rendered_element))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
|
@ -80,7 +80,7 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
|
||||||
layout: &mut playground::element::Layout<V, Self::Layout>,
|
layout: &mut playground::element::Layout<V, Self::Layout>,
|
||||||
cx: &mut playground::element::PaintContext<V>,
|
cx: &mut playground::element::PaintContext<V>,
|
||||||
) {
|
) {
|
||||||
layout.paint(view, cx);
|
layout.update(|_, rendered_element| rendered_element.paint(view, cx)).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub fn styleable_helpers(input: TokenStream) -> TokenStream {
|
||||||
let output = quote! {
|
let output = quote! {
|
||||||
#(#methods)*
|
#(#methods)*
|
||||||
};
|
};
|
||||||
|
|
||||||
output.into()
|
output.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1905,7 +1905,6 @@ impl AppContext {
|
||||||
|
|
||||||
fn handle_repaint_window_effect(&mut self, window: AnyWindowHandle) {
|
fn handle_repaint_window_effect(&mut self, window: AnyWindowHandle) {
|
||||||
self.update_window(window, |cx| {
|
self.update_window(window, |cx| {
|
||||||
cx.layout(false).log_err();
|
|
||||||
if let Some(scene) = cx.paint().log_err() {
|
if let Some(scene) = cx.paint().log_err() {
|
||||||
cx.window.platform_window.present_scene(scene);
|
cx.window.platform_window.present_scene(scene);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
pub use derive_refineable::Refineable;
|
pub use derive_refineable::Refineable;
|
||||||
|
|
||||||
pub trait Refineable {
|
pub trait Refineable: Clone {
|
||||||
type Refinement: Default;
|
type Refinement: Refineable<Refinement = Self::Refinement> + Default;
|
||||||
|
|
||||||
fn refine(&mut self, refinement: &Self::Refinement);
|
fn refine(&mut self, refinement: &Self::Refinement);
|
||||||
fn refined(mut self, refinement: &Self::Refinement) -> Self
|
fn refined(mut self, refinement: &Self::Refinement) -> Self
|
||||||
|
@ -11,4 +11,46 @@ pub trait Refineable {
|
||||||
self.refine(refinement);
|
self.refine(refinement);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
fn from_refinement(refinement: &Self::Refinement) -> Self
|
||||||
|
where
|
||||||
|
Self: Default + Sized,
|
||||||
|
{
|
||||||
|
Self::default().refined(refinement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RefinementCascade<S: Refineable>(Vec<Option<S::Refinement>>);
|
||||||
|
|
||||||
|
impl<S: Refineable + Default> Default for RefinementCascade<S> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(vec![Some(Default::default())])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct CascadeSlot(usize);
|
||||||
|
|
||||||
|
impl<S: Refineable + Default> RefinementCascade<S> {
|
||||||
|
pub fn reserve(&mut self) -> CascadeSlot {
|
||||||
|
self.0.push(None);
|
||||||
|
return CascadeSlot(self.0.len() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn base(&mut self) -> &mut S::Refinement {
|
||||||
|
self.0[0].as_mut().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, slot: CascadeSlot, refinement: Option<S::Refinement>) {
|
||||||
|
self.0[slot.0] = refinement
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn merged(&self) -> S::Refinement {
|
||||||
|
let mut merged = self.0[0].clone().unwrap();
|
||||||
|
for refinement in self.0.iter().skip(1) {
|
||||||
|
if let Some(refinement) = refinement {
|
||||||
|
merged.refine(refinement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
merged
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue