Checkpoint
This commit is contained in:
parent
61b8ad38bd
commit
f53b63eaf6
17 changed files with 567 additions and 472 deletions
|
@ -23,10 +23,7 @@ use std::{
|
||||||
mem,
|
mem,
|
||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
};
|
};
|
||||||
use util::{
|
use util::http::{self, HttpClient};
|
||||||
http::{self, HttpClient},
|
|
||||||
ResultExt,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct App(Arc<Mutex<AppContext>>);
|
pub struct App(Arc<Mutex<AppContext>>);
|
||||||
|
@ -169,9 +166,7 @@ impl AppContext {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
for dirty_window_id in dirty_window_ids {
|
for dirty_window_id in dirty_window_ids {
|
||||||
self.update_window(dirty_window_id, |cx| cx.draw())
|
self.update_window(dirty_window_id, |cx| cx.draw()).unwrap();
|
||||||
.unwrap()
|
|
||||||
.log_err();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::{Bounds, Identified, LayoutId, Pixels, Point, Result, ViewContext};
|
use crate::{BorrowWindow, Bounds, ElementId, Identified, LayoutId, Pixels, Point, ViewContext};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
pub(crate) use smallvec::SmallVec;
|
pub(crate) use smallvec::SmallVec;
|
||||||
use util::arc_cow::ArcCow;
|
|
||||||
|
|
||||||
pub trait Element: 'static {
|
pub trait Element: 'static + Send + Sync {
|
||||||
type State;
|
type ViewState: 'static + Send + Sync;
|
||||||
type FrameState;
|
type ElementState: 'static + Send + Sync;
|
||||||
|
|
||||||
fn element_id(&self) -> Option<ElementId> {
|
fn element_id(&self) -> Option<ElementId> {
|
||||||
None
|
None
|
||||||
|
@ -13,17 +12,18 @@ pub trait Element: 'static {
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut Self::State,
|
state: &mut Self::ViewState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
element_state: Option<Self::ElementState>,
|
||||||
) -> Result<(LayoutId, Self::FrameState)>;
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
|
) -> (LayoutId, Self::ElementState);
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
state: &mut Self::State,
|
state: &mut Self::ViewState,
|
||||||
frame_state: &mut Self::FrameState,
|
element_state: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) -> Result<()>;
|
);
|
||||||
|
|
||||||
fn id(self, id: ElementId) -> Identified<Self>
|
fn id(self, id: ElementId) -> Identified<Self>
|
||||||
where
|
where
|
||||||
|
@ -39,10 +39,7 @@ pub trait StatefulElement: Element {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub struct ElementId(ArcCow<'static, [u8]>);
|
|
||||||
|
|
||||||
#[derive(Deref, DerefMut, Default, Clone, Debug)]
|
|
||||||
pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
|
pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
|
||||||
|
|
||||||
pub trait ParentElement {
|
pub trait ParentElement {
|
||||||
|
@ -68,19 +65,14 @@ pub trait ParentElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait ElementObject<S> {
|
trait ElementObject<S>: 'static + Send + Sync {
|
||||||
fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
|
fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId;
|
||||||
fn paint(
|
fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>);
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
|
||||||
offset: Option<Point<Pixels>>,
|
|
||||||
cx: &mut ViewContext<S>,
|
|
||||||
) -> Result<()>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RenderedElement<E: Element> {
|
struct RenderedElement<E: Element> {
|
||||||
element: E,
|
element: E,
|
||||||
phase: ElementRenderPhase<E::FrameState>,
|
phase: ElementRenderPhase<E::ElementState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -89,15 +81,15 @@ enum ElementRenderPhase<S> {
|
||||||
Rendered,
|
Rendered,
|
||||||
LayoutRequested {
|
LayoutRequested {
|
||||||
layout_id: LayoutId,
|
layout_id: LayoutId,
|
||||||
frame_state: S,
|
frame_state: Option<S>,
|
||||||
},
|
},
|
||||||
Painted {
|
Painted {
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
frame_state: S,
|
frame_state: Option<S>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal struct that wraps an element to store Layout and FrameState after the element is rendered.
|
/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
|
||||||
/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
|
/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
|
||||||
/// improved usability.
|
/// improved usability.
|
||||||
impl<E: Element> RenderedElement<E> {
|
impl<E: Element> RenderedElement<E> {
|
||||||
|
@ -107,24 +99,58 @@ impl<E: Element> RenderedElement<E> {
|
||||||
phase: ElementRenderPhase::Rendered,
|
phase: ElementRenderPhase::Rendered,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn paint_with_element_state(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
view_state: &mut E::ViewState,
|
||||||
|
frame_state: &mut Option<E::ElementState>,
|
||||||
|
cx: &mut ViewContext<E::ViewState>,
|
||||||
|
) {
|
||||||
|
if let Some(id) = self.element.element_id() {
|
||||||
|
cx.with_element_state(id, |element_state, cx| {
|
||||||
|
let mut element_state = element_state.unwrap();
|
||||||
|
self.element
|
||||||
|
.paint(bounds, view_state, &mut element_state, cx);
|
||||||
|
((), element_state)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.element
|
||||||
|
.paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
|
impl<E, S> ElementObject<E::ViewState> for RenderedElement<E>
|
||||||
fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
|
where
|
||||||
let (layout_id, frame_state) = self.element.layout(state, cx)?;
|
E: Element<ElementState = S>,
|
||||||
|
S: 'static + Send + Sync,
|
||||||
|
{
|
||||||
|
fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
|
||||||
|
let (layout_id, frame_state) = if let Some(id) = self.element.element_id() {
|
||||||
|
let layout_id = cx.with_element_state(id, |element_state, cx| {
|
||||||
|
self.element.layout(state, element_state, cx)
|
||||||
|
});
|
||||||
|
(layout_id, None)
|
||||||
|
} else {
|
||||||
|
let (layout_id, frame_state) = self.element.layout(state, None, cx);
|
||||||
|
(layout_id, Some(frame_state))
|
||||||
|
};
|
||||||
|
|
||||||
self.phase = ElementRenderPhase::LayoutRequested {
|
self.phase = ElementRenderPhase::LayoutRequested {
|
||||||
layout_id,
|
layout_id,
|
||||||
frame_state,
|
frame_state,
|
||||||
};
|
};
|
||||||
Ok(layout_id)
|
|
||||||
|
layout_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut E::State,
|
view_state: &mut E::ViewState,
|
||||||
offset: Option<Point<Pixels>>,
|
offset: Option<Point<Pixels>>,
|
||||||
cx: &mut ViewContext<E::State>,
|
cx: &mut ViewContext<E::ViewState>,
|
||||||
) -> Result<()> {
|
) {
|
||||||
self.phase = match std::mem::take(&mut self.phase) {
|
self.phase = match std::mem::take(&mut self.phase) {
|
||||||
ElementRenderPhase::Rendered => panic!("must call layout before paint"),
|
ElementRenderPhase::Rendered => panic!("must call layout before paint"),
|
||||||
|
|
||||||
|
@ -132,9 +158,9 @@ impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
|
||||||
layout_id,
|
layout_id,
|
||||||
mut frame_state,
|
mut frame_state,
|
||||||
} => {
|
} => {
|
||||||
let mut bounds = cx.layout_bounds(layout_id)?.clone();
|
let mut bounds = cx.layout_bounds(layout_id);
|
||||||
offset.map(|offset| bounds.origin += offset);
|
offset.map(|offset| bounds.origin += offset);
|
||||||
self.element.paint(bounds, state, &mut frame_state, cx)?;
|
self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
|
||||||
ElementRenderPhase::Painted {
|
ElementRenderPhase::Painted {
|
||||||
bounds,
|
bounds,
|
||||||
frame_state,
|
frame_state,
|
||||||
|
@ -145,32 +171,24 @@ impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
|
||||||
bounds,
|
bounds,
|
||||||
mut frame_state,
|
mut frame_state,
|
||||||
} => {
|
} => {
|
||||||
self.element
|
self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
|
||||||
.paint(bounds.clone(), state, &mut frame_state, cx)?;
|
|
||||||
ElementRenderPhase::Painted {
|
ElementRenderPhase::Painted {
|
||||||
bounds,
|
bounds,
|
||||||
frame_state,
|
frame_state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
|
pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
|
||||||
|
|
||||||
impl<S> AnyElement<S> {
|
impl<S: 'static + Send + Sync> AnyElement<S> {
|
||||||
pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
|
pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId {
|
||||||
self.0.layout(state, cx)
|
self.0.layout(state, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paint(
|
pub fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>) {
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
|
||||||
offset: Option<Point<Pixels>>,
|
|
||||||
cx: &mut ViewContext<S>,
|
|
||||||
) -> Result<()> {
|
|
||||||
self.0.paint(state, offset, cx)
|
self.0.paint(state, offset, cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,8 +197,8 @@ pub trait IntoAnyElement<S> {
|
||||||
fn into_any(self) -> AnyElement<S>;
|
fn into_any(self) -> AnyElement<S>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Element> IntoAnyElement<E::State> for E {
|
impl<E: Element> IntoAnyElement<E::ViewState> for E {
|
||||||
fn into_any(self) -> AnyElement<E::State> {
|
fn into_any(self) -> AnyElement<E::ViewState> {
|
||||||
AnyElement(Box::new(RenderedElement::new(self)))
|
AnyElement(Box::new(RenderedElement::new(self)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, Bounds, Element, Interactive, LayoutId, MouseEventListeners, Overflow,
|
AnyElement, Bounds, Element, Interactive, LayoutId, MouseEventListeners, Overflow,
|
||||||
ParentElement, Pixels, Point, Refineable, RefinementCascade, Result, Style, Styled,
|
ParentElement, Pixels, Point, Refineable, RefinementCascade, Style, Styled, ViewContext,
|
||||||
ViewContext,
|
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use util::ResultExt;
|
|
||||||
|
|
||||||
pub struct Div<S: 'static> {
|
pub struct Div<S: 'static> {
|
||||||
styles: RefinementCascade<Style>,
|
styles: RefinementCascade<Style>,
|
||||||
|
@ -25,27 +23,28 @@ pub fn div<S>() -> Div<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static + Send + Sync> Element for Div<S> {
|
impl<S: 'static + Send + Sync> Element for Div<S> {
|
||||||
type State = S;
|
type ViewState = S;
|
||||||
type FrameState = Vec<LayoutId>;
|
type ElementState = Vec<LayoutId>;
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
view: &mut S,
|
view: &mut S,
|
||||||
|
_: Option<Self::ElementState>,
|
||||||
cx: &mut ViewContext<S>,
|
cx: &mut ViewContext<S>,
|
||||||
) -> Result<(LayoutId, Self::FrameState)> {
|
) -> (LayoutId, Self::ElementState) {
|
||||||
let style = self.computed_style();
|
let style = self.computed_style();
|
||||||
let child_layout_ids = style.apply_text_style(cx, |cx| self.layout_children(view, cx))?;
|
let child_layout_ids = style.apply_text_style(cx, |cx| self.layout_children(view, cx));
|
||||||
let layout_id = cx.request_layout(style.into(), child_layout_ids.clone())?;
|
let layout_id = cx.request_layout(style.into(), child_layout_ids.clone());
|
||||||
Ok((layout_id, child_layout_ids))
|
(layout_id, child_layout_ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
child_layout_ids: &mut Self::FrameState,
|
child_layout_ids: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<S>,
|
cx: &mut ViewContext<S>,
|
||||||
) -> Result<()> {
|
) {
|
||||||
let style = self.computed_style();
|
let style = self.computed_style();
|
||||||
cx.stack(0, |cx| style.paint(bounds, cx));
|
cx.stack(0, |cx| style.paint(bounds, cx));
|
||||||
|
|
||||||
|
@ -57,7 +56,7 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
|
||||||
self.paint_children(overflow, state, cx)
|
self.paint_children(overflow, state, cx)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})?;
|
});
|
||||||
self.handle_scroll(bounds, style.overflow.clone(), child_layout_ids, cx);
|
self.handle_scroll(bounds, style.overflow.clone(), child_layout_ids, cx);
|
||||||
|
|
||||||
// todo!("enable inspector")
|
// todo!("enable inspector")
|
||||||
|
@ -65,12 +64,10 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
|
||||||
// self.paint_inspector(parent_origin, layout, cx);
|
// self.paint_inspector(parent_origin, layout, cx);
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> Div<S> {
|
impl<S: 'static + Send + Sync> Div<S> {
|
||||||
pub fn overflow_hidden(mut self) -> Self {
|
pub fn overflow_hidden(mut self) -> Self {
|
||||||
self.declared_style().overflow.x = Some(Overflow::Hidden);
|
self.declared_style().overflow.x = Some(Overflow::Hidden);
|
||||||
self.declared_style().overflow.y = Some(Overflow::Hidden);
|
self.declared_style().overflow.y = Some(Overflow::Hidden);
|
||||||
|
@ -118,11 +115,11 @@ impl<S: 'static> Div<S> {
|
||||||
offset
|
offset
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_children(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> Result<Vec<LayoutId>> {
|
fn layout_children(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> Vec<LayoutId> {
|
||||||
self.children
|
self.children
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|child| child.layout(view, cx))
|
.map(|child| child.layout(view, cx))
|
||||||
.collect::<Result<Vec<LayoutId>>>()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_children(
|
fn paint_children(
|
||||||
|
@ -130,12 +127,11 @@ impl<S: 'static> Div<S> {
|
||||||
overflow: &Point<Overflow>,
|
overflow: &Point<Overflow>,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
cx: &mut ViewContext<S>,
|
cx: &mut ViewContext<S>,
|
||||||
) -> Result<()> {
|
) {
|
||||||
let scroll_offset = self.scroll_offset(overflow);
|
let scroll_offset = self.scroll_offset(overflow);
|
||||||
for child in &mut self.children {
|
for child in &mut self.children {
|
||||||
child.paint(state, Some(scroll_offset), cx)?;
|
child.paint(state, Some(scroll_offset), cx);
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll(
|
fn handle_scroll(
|
||||||
|
@ -148,9 +144,8 @@ impl<S: 'static> Div<S> {
|
||||||
if overflow.y == Overflow::Scroll || overflow.x == Overflow::Scroll {
|
if overflow.y == Overflow::Scroll || overflow.x == Overflow::Scroll {
|
||||||
let mut scroll_max = Point::default();
|
let mut scroll_max = Point::default();
|
||||||
for child_layout_id in child_layout_ids {
|
for child_layout_id in child_layout_ids {
|
||||||
if let Some(child_bounds) = cx.layout_bounds(*child_layout_id).log_err() {
|
let child_bounds = cx.layout_bounds(*child_layout_id);
|
||||||
scroll_max = scroll_max.max(&child_bounds.lower_right());
|
scroll_max = scroll_max.max(&child_bounds.lower_right());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
scroll_max -= bounds.size;
|
scroll_max -= bounds.size;
|
||||||
|
|
||||||
|
@ -237,7 +232,7 @@ impl<S: 'static> Div<S> {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Styled for Div<V> {
|
impl<V: 'static + Send + Sync> Styled for Div<V> {
|
||||||
type Style = Style;
|
type Style = Style;
|
||||||
|
|
||||||
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
|
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
|
||||||
|
|
|
@ -2,7 +2,6 @@ use crate::{
|
||||||
AnyElement, Bounds, DispatchPhase, Element, ElementId, Interactive, MouseEventListeners,
|
AnyElement, Bounds, DispatchPhase, Element, ElementId, Interactive, MouseEventListeners,
|
||||||
MouseMoveEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
|
MouseMoveEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
|
||||||
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
|
@ -10,7 +9,10 @@ use std::sync::{
|
||||||
Arc,
|
Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Hoverable<E: Styled> {
|
pub struct Hoverable<E: Styled>
|
||||||
|
// where
|
||||||
|
// <E::Style as Refineable>::Refinement: 'static + Send + Sync,
|
||||||
|
{
|
||||||
hovered: Arc<AtomicBool>,
|
hovered: Arc<AtomicBool>,
|
||||||
cascade_slot: CascadeSlot,
|
cascade_slot: CascadeSlot,
|
||||||
hovered_style: <E::Style as Refineable>::Refinement,
|
hovered_style: <E::Style as Refineable>::Refinement,
|
||||||
|
@ -49,9 +51,14 @@ impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Ho
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Element + Styled> Element for Hoverable<E> {
|
impl<E> Element for Hoverable<E>
|
||||||
type State = E::State;
|
where
|
||||||
type FrameState = E::FrameState;
|
E: Element + Styled,
|
||||||
|
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
|
||||||
|
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
|
||||||
|
{
|
||||||
|
type ViewState = E::ViewState;
|
||||||
|
type ElementState = E::ElementState;
|
||||||
|
|
||||||
fn element_id(&self) -> Option<ElementId> {
|
fn element_id(&self) -> Option<ElementId> {
|
||||||
self.child.element_id()
|
self.child.element_id()
|
||||||
|
@ -59,19 +66,20 @@ impl<E: Element + Styled> Element for Hoverable<E> {
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut Self::State,
|
state: &mut Self::ViewState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
element_state: Option<Self::ElementState>,
|
||||||
) -> Result<(crate::LayoutId, Self::FrameState)> {
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
Ok(self.child.layout(state, cx)?)
|
) -> (crate::LayoutId, Self::ElementState) {
|
||||||
|
self.child.layout(state, element_state, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
state: &mut Self::State,
|
state: &mut Self::ViewState,
|
||||||
frame_state: &mut Self::FrameState,
|
element_state: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) -> Result<()> {
|
) {
|
||||||
let hovered = bounds.contains_point(cx.mouse_position());
|
let hovered = bounds.contains_point(cx.mouse_position());
|
||||||
let slot = self.cascade_slot;
|
let slot = self.cascade_slot;
|
||||||
let style = hovered.then_some(self.hovered_style.clone());
|
let style = hovered.then_some(self.hovered_style.clone());
|
||||||
|
@ -79,7 +87,7 @@ impl<E: Element + Styled> Element for Hoverable<E> {
|
||||||
self.hovered.store(hovered, SeqCst);
|
self.hovered.store(hovered, SeqCst);
|
||||||
|
|
||||||
let hovered = self.hovered.clone();
|
let hovered = self.hovered.clone();
|
||||||
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
|
cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
|
||||||
if phase == DispatchPhase::Capture {
|
if phase == DispatchPhase::Capture {
|
||||||
if bounds.contains_point(event.position) != hovered.load(SeqCst) {
|
if bounds.contains_point(event.position) != hovered.load(SeqCst) {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -87,8 +95,7 @@ impl<E: Element + Styled> Element for Hoverable<E> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.child.paint(bounds, state, frame_state, cx)?;
|
self.child.paint(bounds, state, element_state, cx);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,4 +107,10 @@ impl<E: ParentElement + Styled> ParentElement for Hoverable<E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: StatefulElement + Styled> StatefulElement for Hoverable<E> {}
|
impl<E> StatefulElement for Hoverable<E>
|
||||||
|
where
|
||||||
|
E: StatefulElement + Styled,
|
||||||
|
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
|
||||||
|
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::{BorrowWindow, Bounds, Element, ElementId, LayoutId, StatefulElement, ViewContext};
|
use crate::{BorrowWindow, Bounds, Element, ElementId, LayoutId, StatefulElement, ViewContext};
|
||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
pub struct Identified<E> {
|
pub struct Identified<E> {
|
||||||
pub(crate) element: E,
|
pub(crate) element: E,
|
||||||
|
@ -7,8 +6,8 @@ pub struct Identified<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Element> Element for Identified<E> {
|
impl<E: Element> Element for Identified<E> {
|
||||||
type State = E::State;
|
type ViewState = E::ViewState;
|
||||||
type FrameState = E::FrameState;
|
type ElementState = E::ElementState;
|
||||||
|
|
||||||
fn element_id(&self) -> Option<ElementId> {
|
fn element_id(&self) -> Option<ElementId> {
|
||||||
Some(self.id.clone())
|
Some(self.id.clone())
|
||||||
|
@ -16,21 +15,22 @@ impl<E: Element> Element for Identified<E> {
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut Self::State,
|
state: &mut Self::ViewState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
element_state: Option<Self::ElementState>,
|
||||||
) -> Result<(LayoutId, Self::FrameState)> {
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
self.element.layout(state, cx)
|
) -> (LayoutId, Self::ElementState) {
|
||||||
|
self.element.layout(state, element_state, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<crate::Pixels>,
|
bounds: Bounds<crate::Pixels>,
|
||||||
state: &mut Self::State,
|
state: &mut Self::ViewState,
|
||||||
frame_state: &mut Self::FrameState,
|
element_state: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) -> Result<()> {
|
) {
|
||||||
cx.with_element_id(self.id.clone(), |cx| {
|
cx.with_element_id(self.id.clone(), |cx| {
|
||||||
self.element.paint(bounds, state, frame_state, cx)
|
self.element.paint(bounds, state, element_state, cx)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
BorrowWindow, Bounds, Element, LayoutId, Pixels, Result, SharedString, Style, Styled,
|
BorrowWindow, Bounds, Element, LayoutId, Pixels, SharedString, Style, Styled, ViewContext,
|
||||||
ViewContext,
|
|
||||||
};
|
};
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use refineable::RefinementCascade;
|
use refineable::RefinementCascade;
|
||||||
|
@ -36,29 +35,30 @@ impl<S> Img<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Send + Sync + 'static> Element for Img<S> {
|
impl<S: Send + Sync + 'static> Element for Img<S> {
|
||||||
type State = S;
|
type ViewState = S;
|
||||||
type FrameState = ();
|
type ElementState = ();
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &mut Self::State,
|
_: &mut Self::ViewState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
_: Option<Self::ElementState>,
|
||||||
) -> anyhow::Result<(LayoutId, Self::FrameState)>
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
|
) -> (LayoutId, Self::ElementState)
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let style = self.computed_style();
|
let style = self.computed_style();
|
||||||
let layout_id = cx.request_layout(style, [])?;
|
let layout_id = cx.request_layout(style, []);
|
||||||
Ok((layout_id, ()))
|
(layout_id, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::State,
|
_: &mut Self::ViewState,
|
||||||
_: &mut Self::FrameState,
|
_: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) -> Result<()> {
|
) {
|
||||||
let style = self.computed_style();
|
let style = self.computed_style();
|
||||||
|
|
||||||
style.paint(bounds, cx);
|
style.paint(bounds, cx);
|
||||||
|
@ -73,7 +73,8 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
|
||||||
let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
|
let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
|
||||||
cx.stack(1, |cx| {
|
cx.stack(1, |cx| {
|
||||||
cx.paint_image(bounds, corner_radii, data, self.grayscale)
|
cx.paint_image(bounds, corner_radii, data, self.grayscale)
|
||||||
})?;
|
.log_err()
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
cx.spawn(|_, mut cx| async move {
|
cx.spawn(|_, mut cx| async move {
|
||||||
if image_future.await.log_err().is_some() {
|
if image_future.await.log_err().is_some() {
|
||||||
|
@ -83,7 +84,6 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
|
||||||
.detach()
|
.detach()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,211 +1,237 @@
|
||||||
|
use crate::{
|
||||||
|
AnyElement, Bounds, DispatchPhase, Element, Interactive, MouseDownEvent, MouseEventListeners,
|
||||||
|
MouseUpEvent, ParentElement, Pixels, StatefulElement, Styled, ViewContext,
|
||||||
|
};
|
||||||
|
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicBool, Ordering::SeqCst},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Pressable<E: Styled> {
|
||||||
|
cascade_slot: CascadeSlot,
|
||||||
|
pressed_style: <E::Style as Refineable>::Refinement,
|
||||||
|
child: E,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PressableState<S> {
|
||||||
|
pressed: Arc<AtomicBool>,
|
||||||
|
child_state: S,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Styled> Pressable<E> {
|
||||||
|
pub fn new(mut child: E) -> Self {
|
||||||
|
Self {
|
||||||
|
cascade_slot: child.style_cascade().reserve(),
|
||||||
|
pressed_style: Default::default(),
|
||||||
|
child,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> Styled for Pressable<E>
|
||||||
|
where
|
||||||
|
E: Styled,
|
||||||
|
{
|
||||||
|
type Style = E::Style;
|
||||||
|
|
||||||
|
fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
|
||||||
|
self.child.style_cascade()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
|
||||||
|
&mut self.pressed_style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Pressable<E> {
|
||||||
|
fn listeners(&mut self) -> &mut MouseEventListeners<S> {
|
||||||
|
self.child.listeners()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> Element for Pressable<E>
|
||||||
|
where
|
||||||
|
E: Styled + StatefulElement,
|
||||||
|
<E as Styled>::Style: 'static + Refineable + Send + Sync + Default,
|
||||||
|
<<E as Styled>::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default,
|
||||||
|
{
|
||||||
|
type ViewState = E::ViewState;
|
||||||
|
type ElementState = PressableState<E::ElementState>;
|
||||||
|
|
||||||
|
fn layout(
|
||||||
|
&mut self,
|
||||||
|
state: &mut Self::ViewState,
|
||||||
|
element_state: Option<Self::ElementState>,
|
||||||
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
|
) -> (crate::LayoutId, Self::ElementState) {
|
||||||
|
if let Some(element_state) = element_state {
|
||||||
|
let (id, child_state) = self
|
||||||
|
.child
|
||||||
|
.layout(state, Some(element_state.child_state), cx);
|
||||||
|
let element_state = PressableState {
|
||||||
|
pressed: element_state.pressed,
|
||||||
|
child_state,
|
||||||
|
};
|
||||||
|
(id, element_state)
|
||||||
|
} else {
|
||||||
|
let (id, child_state) = self.child.layout(state, None, cx);
|
||||||
|
let element_state = PressableState {
|
||||||
|
pressed: Default::default(),
|
||||||
|
child_state,
|
||||||
|
};
|
||||||
|
(id, element_state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
state: &mut Self::ViewState,
|
||||||
|
element_state: &mut Self::ElementState,
|
||||||
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
|
) {
|
||||||
|
let slot = self.cascade_slot;
|
||||||
|
let style = element_state
|
||||||
|
.pressed
|
||||||
|
.load(SeqCst)
|
||||||
|
.then_some(self.pressed_style.clone());
|
||||||
|
self.style_cascade().set(slot, style);
|
||||||
|
|
||||||
|
let pressed = element_state.pressed.clone();
|
||||||
|
cx.on_mouse_event(move |_, event: &MouseDownEvent, phase, cx| {
|
||||||
|
if phase == DispatchPhase::Capture {
|
||||||
|
if bounds.contains_point(event.position) != pressed.load(SeqCst) {
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let hovered = element_state.pressed.clone();
|
||||||
|
cx.on_mouse_event(move |_, event: &MouseUpEvent, phase, cx| {
|
||||||
|
if phase == DispatchPhase::Capture {
|
||||||
|
if bounds.contains_point(event.position) != hovered.load(SeqCst) {
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.child
|
||||||
|
.paint(bounds, state, &mut element_state.child_state, cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: ParentElement + Styled> ParentElement for Pressable<E> {
|
||||||
|
type State = E::State;
|
||||||
|
|
||||||
|
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
|
||||||
|
self.child.children_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// use crate::{
|
// use crate::{
|
||||||
// AnyElement, Bounds, DispatchPhase, Element, Identified, Interactive, MouseDownEvent,
|
// element::{AnyElement, Element, IntoElement, Layout, ParentElement},
|
||||||
// MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext,
|
// interactive::{InteractionHandlers, Interactive},
|
||||||
|
// style::{Style, StyleHelpers, Styleable},
|
||||||
|
// ViewContext,
|
||||||
// };
|
// };
|
||||||
// use anyhow::Result;
|
// use anyhow::Result;
|
||||||
|
// use gpui::{geometry::vector::Vector2F, platform::MouseButtonEvent, LayoutId};
|
||||||
// use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
// use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
||||||
// use smallvec::SmallVec;
|
// use smallvec::SmallVec;
|
||||||
// use std::sync::{
|
// use std::{cell::Cell, rc::Rc};
|
||||||
// atomic::{AtomicBool, Ordering::SeqCst},
|
|
||||||
// Arc,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// pub struct Pressable<E: Styled> {
|
// pub struct Pressable<E: Styleable> {
|
||||||
// pressed: Arc<AtomicBool>,
|
// pressed: Rc<Cell<bool>>,
|
||||||
// cascade_slot: CascadeSlot,
|
|
||||||
// pressed_style: <E::Style as Refineable>::Refinement,
|
// pressed_style: <E::Style as Refineable>::Refinement,
|
||||||
|
// cascade_slot: CascadeSlot,
|
||||||
// child: E,
|
// child: E,
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// impl<E: Identified + Styled> Pressable<E> {
|
// pub fn pressable<E: Styleable>(mut child: E) -> Pressable<E> {
|
||||||
// pub fn new(mut child: E) -> Self {
|
// Pressable {
|
||||||
// Self {
|
// pressed: Rc::new(Cell::new(false)),
|
||||||
// pressed: Arc::new(AtomicBool::new(false)),
|
// pressed_style: Default::default(),
|
||||||
// cascade_slot: child.style_cascade().reserve(),
|
// cascade_slot: child.style_cascade().reserve(),
|
||||||
// pressed_style: Default::default(),
|
// child,
|
||||||
// child,
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// impl<E> Styled for Pressable<E>
|
// impl<E: Styleable> Styleable for Pressable<E> {
|
||||||
// where
|
|
||||||
// E: Styled,
|
|
||||||
// {
|
|
||||||
// type Style = E::Style;
|
// 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> {
|
// fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
|
||||||
// self.child.style_cascade()
|
// self.child.style_cascade()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
|
|
||||||
// &mut self.pressed_style
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Pressable<E> {
|
// impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
|
||||||
// fn listeners(&mut self) -> &mut MouseEventListeners<S> {
|
// type PaintState = E::PaintState;
|
||||||
// self.child.listeners()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<E: Element + Identified + Styled> Element for Pressable<E> {
|
|
||||||
// type State = E::State;
|
|
||||||
// type FrameState = E::FrameState;
|
|
||||||
|
|
||||||
// fn layout(
|
// fn layout(
|
||||||
// &mut self,
|
// &mut self,
|
||||||
// state: &mut Self::State,
|
// view: &mut V,
|
||||||
// cx: &mut ViewContext<Self::State>,
|
// cx: &mut ViewContext<V>,
|
||||||
// ) -> Result<(crate::LayoutId, Self::FrameState)> {
|
// ) -> Result<(LayoutId, Self::PaintState)>
|
||||||
// Ok(self.child.layout(state, cx)?)
|
// where
|
||||||
|
// Self: Sized,
|
||||||
|
// {
|
||||||
|
// self.child.layout(view, cx)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// fn paint(
|
// fn paint(
|
||||||
// &mut self,
|
// &mut self,
|
||||||
// bounds: Bounds<Pixels>,
|
// view: &mut V,
|
||||||
// state: &mut Self::State,
|
// parent_origin: Vector2F,
|
||||||
// frame_state: &mut Self::FrameState,
|
// layout: &Layout,
|
||||||
// cx: &mut ViewContext<Self::State>,
|
// paint_state: &mut Self::PaintState,
|
||||||
// ) -> Result<()> {
|
// cx: &mut ViewContext<V>,
|
||||||
// let pressed = bounds.contains_point(cx.mouse_position());
|
// ) where
|
||||||
|
// Self: Sized,
|
||||||
|
// {
|
||||||
// let slot = self.cascade_slot;
|
// let slot = self.cascade_slot;
|
||||||
// let style = pressed.then_some(self.pressed_style.clone());
|
// let style = self.pressed.get().then_some(self.pressed_style.clone());
|
||||||
// self.style_cascade().set(slot, style);
|
// self.style_cascade().set(slot, style);
|
||||||
// self.pressed.store(pressed, SeqCst);
|
|
||||||
|
|
||||||
// let hovered = self.pressed.clone();
|
// let pressed = self.pressed.clone();
|
||||||
// cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
|
// let bounds = layout.bounds + parent_origin;
|
||||||
// if phase == DispatchPhase::Capture {
|
// cx.on_event(layout.order, move |_view, event: &MouseButtonEvent, cx| {
|
||||||
// if bounds.contains_point(event.position) != hovered.load(SeqCst) {
|
// if event.is_down {
|
||||||
// cx.notify();
|
// if bounds.contains_point(event.position) {
|
||||||
// }
|
// pressed.set(true);
|
||||||
// }
|
// cx.repaint();
|
||||||
// });
|
|
||||||
// cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
|
|
||||||
// if phase == DispatchPhase::Capture {
|
|
||||||
// if bounds.contains_point(event.position) != hovered.load(SeqCst) {
|
|
||||||
// cx.notify();
|
|
||||||
// }
|
// }
|
||||||
|
// } else if pressed.get() {
|
||||||
|
// pressed.set(false);
|
||||||
|
// cx.repaint();
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// self.child.paint(bounds, state, frame_state, cx)?;
|
// self.child
|
||||||
// Ok(())
|
// .paint(view, parent_origin, layout, paint_state, cx);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// impl<E: ParentElement + Styled> ParentElement for Pressable<E> {
|
// impl<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Pressable<E> {
|
||||||
// type State = E::State;
|
// fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
|
||||||
|
// self.child.interaction_handlers()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
|
// impl<V: 'static, E: ParentElement<V> + Styleable> ParentElement<V> for Pressable<E> {
|
||||||
|
// fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||||
// self.child.children_mut()
|
// self.child.children_mut()
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// // use crate::{
|
// impl<V: 'static, E: Element<V> + Styleable> IntoElement<V> for Pressable<E> {
|
||||||
// // element::{AnyElement, Element, IntoElement, Layout, ParentElement},
|
// type Element = Self;
|
||||||
// // interactive::{InteractionHandlers, Interactive},
|
|
||||||
// // style::{Style, StyleHelpers, Styleable},
|
|
||||||
// // ViewContext,
|
|
||||||
// // };
|
|
||||||
// // use anyhow::Result;
|
|
||||||
// // use gpui::{geometry::vector::Vector2F, platform::MouseButtonEvent, LayoutId};
|
|
||||||
// // use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
|
||||||
// // use smallvec::SmallVec;
|
|
||||||
// // use std::{cell::Cell, rc::Rc};
|
|
||||||
|
|
||||||
// // pub struct Pressable<E: Styleable> {
|
// fn into_element(self) -> Self::Element {
|
||||||
// // pressed: Rc<Cell<bool>>,
|
// self
|
||||||
// // 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 PaintState = E::PaintState;
|
|
||||||
|
|
||||||
// // fn layout(
|
|
||||||
// // &mut self,
|
|
||||||
// // view: &mut V,
|
|
||||||
// // cx: &mut ViewContext<V>,
|
|
||||||
// // ) -> Result<(LayoutId, Self::PaintState)>
|
|
||||||
// // where
|
|
||||||
// // Self: Sized,
|
|
||||||
// // {
|
|
||||||
// // self.child.layout(view, cx)
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // fn paint(
|
|
||||||
// // &mut self,
|
|
||||||
// // view: &mut V,
|
|
||||||
// // parent_origin: Vector2F,
|
|
||||||
// // layout: &Layout,
|
|
||||||
// // paint_state: &mut Self::PaintState,
|
|
||||||
// // cx: &mut ViewContext<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 pressed = self.pressed.clone();
|
|
||||||
// // let bounds = layout.bounds + parent_origin;
|
|
||||||
// // cx.on_event(layout.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, parent_origin, layout, paint_state, cx);
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // impl<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Pressable<E> {
|
|
||||||
// // fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
|
|
||||||
// // self.child.interaction_handlers()
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // impl<V: 'static, E: ParentElement<V> + Styleable> ParentElement<V> for Pressable<E> {
|
|
||||||
// // fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
|
||||||
// // self.child.children_mut()
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // impl<V: 'static, E: Element<V> + Styleable> IntoElement<V> for Pressable<E> {
|
|
||||||
// // type Element = Self;
|
|
||||||
|
|
||||||
// // fn into_element(self) -> Self::Element {
|
|
||||||
// // self
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::{Bounds, Element, LayoutId, Pixels, Result, SharedString, Style, Styled};
|
use crate::{Bounds, Element, LayoutId, Pixels, SharedString, Style, Styled};
|
||||||
use refineable::RefinementCascade;
|
use refineable::RefinementCascade;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
use util::ResultExt;
|
||||||
|
|
||||||
pub struct Svg<S> {
|
pub struct Svg<S> {
|
||||||
path: Option<SharedString>,
|
path: Option<SharedString>,
|
||||||
|
@ -23,41 +24,40 @@ impl<S> Svg<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> Element for Svg<S> {
|
impl<S: 'static + Send + Sync> Element for Svg<S> {
|
||||||
type State = S;
|
type ViewState = S;
|
||||||
type FrameState = ();
|
type ElementState = ();
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &mut S,
|
_: &mut S,
|
||||||
|
_: Option<Self::ElementState>,
|
||||||
cx: &mut crate::ViewContext<S>,
|
cx: &mut crate::ViewContext<S>,
|
||||||
) -> anyhow::Result<(LayoutId, Self::FrameState)>
|
) -> (LayoutId, Self::ElementState)
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let style = self.computed_style();
|
let style = self.computed_style();
|
||||||
Ok((cx.request_layout(style, [])?, ()))
|
(cx.request_layout(style, []), ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::State,
|
_: &mut Self::ViewState,
|
||||||
_: &mut Self::FrameState,
|
_: &mut Self::ElementState,
|
||||||
cx: &mut crate::ViewContext<S>,
|
cx: &mut crate::ViewContext<S>,
|
||||||
) -> Result<()>
|
) where
|
||||||
where
|
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let fill_color = self.computed_style().fill.and_then(|fill| fill.color());
|
let fill_color = self.computed_style().fill.and_then(|fill| fill.color());
|
||||||
if let Some((path, fill_color)) = self.path.as_ref().zip(fill_color) {
|
if let Some((path, fill_color)) = self.path.as_ref().zip(fill_color) {
|
||||||
cx.paint_svg(bounds, path.clone(), fill_color)?;
|
cx.paint_svg(bounds, path.clone(), fill_color).log_err();
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Styled for Svg<S> {
|
impl<S: 'static + Send + Sync> Styled for Svg<S> {
|
||||||
type Style = Style;
|
type Style = Style;
|
||||||
|
|
||||||
fn style_cascade(&mut self) -> &mut refineable::RefinementCascade<Self::Style> {
|
fn style_cascade(&mut self) -> &mut refineable::RefinementCascade<Self::Style> {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, Result, Size, ViewContext,
|
AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, Size, ViewContext,
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{marker::PhantomData, sync::Arc};
|
use std::{marker::PhantomData, sync::Arc};
|
||||||
use util::{arc_cow::ArcCow, ResultExt};
|
use util::{arc_cow::ArcCow, ResultExt};
|
||||||
|
|
||||||
impl<S: 'static> IntoAnyElement<S> for ArcCow<'static, str> {
|
impl<S: 'static + Send + Sync> IntoAnyElement<S> for ArcCow<'static, str> {
|
||||||
fn into_any(self) -> AnyElement<S> {
|
fn into_any(self) -> AnyElement<S> {
|
||||||
Text {
|
Text {
|
||||||
text: self,
|
text: self,
|
||||||
|
@ -15,7 +15,7 @@ impl<S: 'static> IntoAnyElement<S> for ArcCow<'static, str> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> IntoAnyElement<V> for &'static str {
|
impl<V: 'static + Send + Sync> IntoAnyElement<V> for &'static str {
|
||||||
fn into_any(self) -> AnyElement<V> {
|
fn into_any(self) -> AnyElement<V> {
|
||||||
Text {
|
Text {
|
||||||
text: ArcCow::from(self),
|
text: ArcCow::from(self),
|
||||||
|
@ -30,15 +30,16 @@ pub struct Text<S> {
|
||||||
state_type: PhantomData<S>,
|
state_type: PhantomData<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> Element for Text<S> {
|
impl<S: 'static + Send + Sync> Element for Text<S> {
|
||||||
type State = S;
|
type ViewState = S;
|
||||||
type FrameState = Arc<Mutex<Option<TextFrameState>>>;
|
type ElementState = Arc<Mutex<Option<TextElementState>>>;
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
_view: &mut S,
|
_view: &mut S,
|
||||||
|
_element_state: Option<Self::ElementState>,
|
||||||
cx: &mut ViewContext<S>,
|
cx: &mut ViewContext<S>,
|
||||||
) -> Result<(LayoutId, Self::FrameState)> {
|
) -> (LayoutId, Self::ElementState) {
|
||||||
let text_system = cx.text_system().clone();
|
let text_system = cx.text_system().clone();
|
||||||
let text_style = cx.text_style();
|
let text_style = cx.text_style();
|
||||||
let font_size = text_style.font_size * cx.rem_size();
|
let font_size = text_style.font_size * cx.rem_size();
|
||||||
|
@ -46,11 +47,11 @@ impl<S: 'static> Element for Text<S> {
|
||||||
.line_height
|
.line_height
|
||||||
.to_pixels(font_size.into(), cx.rem_size());
|
.to_pixels(font_size.into(), cx.rem_size());
|
||||||
let text = self.text.clone();
|
let text = self.text.clone();
|
||||||
let frame_state = Arc::new(Mutex::new(None));
|
let element_state = Arc::new(Mutex::new(None));
|
||||||
|
|
||||||
let rem_size = cx.rem_size();
|
let rem_size = cx.rem_size();
|
||||||
let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
|
let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
|
||||||
let frame_state = frame_state.clone();
|
let element_state = element_state.clone();
|
||||||
move |_, _| {
|
move |_, _| {
|
||||||
let Some(line_layout) = text_system
|
let Some(line_layout) = text_system
|
||||||
.layout_line(
|
.layout_line(
|
||||||
|
@ -68,7 +69,7 @@ impl<S: 'static> Element for Text<S> {
|
||||||
height: line_height,
|
height: line_height,
|
||||||
};
|
};
|
||||||
|
|
||||||
frame_state.lock().replace(TextFrameState {
|
element_state.lock().replace(TextElementState {
|
||||||
line: Arc::new(line_layout),
|
line: Arc::new(line_layout),
|
||||||
line_height,
|
line_height,
|
||||||
});
|
});
|
||||||
|
@ -77,35 +78,32 @@ impl<S: 'static> Element for Text<S> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok((layout_id?, frame_state))
|
(layout_id, element_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint<'a>(
|
fn paint<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::State,
|
_: &mut Self::ViewState,
|
||||||
frame_state: &mut Self::FrameState,
|
element_state: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<S>,
|
cx: &mut ViewContext<S>,
|
||||||
) -> Result<()> {
|
) {
|
||||||
let line;
|
let line;
|
||||||
let line_height;
|
let line_height;
|
||||||
{
|
{
|
||||||
let frame_state = frame_state.lock();
|
let element_state = element_state.lock();
|
||||||
let frame_state = frame_state
|
let element_state = element_state
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("measurement has not been performed");
|
.expect("measurement has not been performed");
|
||||||
line = frame_state.line.clone();
|
line = element_state.line.clone();
|
||||||
line_height = frame_state.line_height;
|
line_height = element_state.line_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo!("We haven't added visible bounds to the new element system yet, so this is a placeholder.");
|
line.paint(bounds, bounds, line_height, cx).log_err();
|
||||||
line.paint(bounds, bounds, line_height, cx)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextFrameState {
|
pub struct TextElementState {
|
||||||
line: Arc<Line>,
|
line: Arc<Line>,
|
||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,12 +50,15 @@ pub use view::*;
|
||||||
pub use window::*;
|
pub use window::*;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
any::Any,
|
||||||
mem,
|
mem,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use taffy::TaffyLayoutEngine;
|
use taffy::TaffyLayoutEngine;
|
||||||
|
|
||||||
|
type AnyBox = Box<dyn Any + Send + Sync + 'static>;
|
||||||
|
|
||||||
pub trait Context {
|
pub trait Context {
|
||||||
type EntityContext<'a, 'w, T: 'static + Send + Sync>;
|
type EntityContext<'a, 'w, T: 'static + Send + Sync>;
|
||||||
type Result<T>;
|
type Result<T>;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{Hoverable, Refineable, RefinementCascade};
|
use crate::{Hoverable, Refineable, RefinementCascade};
|
||||||
|
|
||||||
pub trait Styled {
|
pub trait Styled {
|
||||||
type Style: Refineable + Default;
|
type Style: 'static + Refineable + Send + Sync + Default;
|
||||||
|
|
||||||
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style>;
|
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style>;
|
||||||
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
|
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
|
||||||
|
@ -12,7 +12,9 @@ pub trait Styled {
|
||||||
|
|
||||||
fn hover(self) -> Hoverable<Self>
|
fn hover(self) -> Hoverable<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: 'static + Sized + Send + Sync,
|
||||||
|
Self::Style: 'static + Refineable + Default + Send + Sync,
|
||||||
|
<Self::Style as Refineable>::Refinement: 'static + Default + Send + Sync,
|
||||||
{
|
{
|
||||||
Hoverable::new(self)
|
Hoverable::new(self)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use super::{
|
use super::{AbsoluteLength, Bounds, DefiniteLength, Edges, Length, Pixels, Point, Size, Style};
|
||||||
AbsoluteLength, Bounds, DefiniteLength, Edges, Length, Pixels, Point, Result, Size, Style,
|
|
||||||
};
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use taffy::{
|
use taffy::{
|
||||||
|
@ -16,6 +14,9 @@ pub struct TaffyLayoutEngine {
|
||||||
absolute_layout_bounds: HashMap<LayoutId, Bounds<Pixels>>,
|
absolute_layout_bounds: HashMap<LayoutId, Bounds<Pixels>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EXPECT_MESSAGE: &'static str =
|
||||||
|
"we should avoid taffy layout errors by construction if possible";
|
||||||
|
|
||||||
impl TaffyLayoutEngine {
|
impl TaffyLayoutEngine {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
TaffyLayoutEngine {
|
TaffyLayoutEngine {
|
||||||
|
@ -30,20 +31,21 @@ impl TaffyLayoutEngine {
|
||||||
style: Style,
|
style: Style,
|
||||||
rem_size: Pixels,
|
rem_size: Pixels,
|
||||||
children: &[LayoutId],
|
children: &[LayoutId],
|
||||||
) -> Result<LayoutId> {
|
) -> LayoutId {
|
||||||
let style = style.to_taffy(rem_size);
|
let style = style.to_taffy(rem_size);
|
||||||
if children.is_empty() {
|
if children.is_empty() {
|
||||||
Ok(self.taffy.new_leaf(style)?.into())
|
self.taffy.new_leaf(style).expect(EXPECT_MESSAGE).into()
|
||||||
} else {
|
} else {
|
||||||
let parent_id = self
|
let parent_id = self
|
||||||
.taffy
|
.taffy
|
||||||
// This is safe because LayoutId is repr(transparent) to taffy::tree::NodeId.
|
// This is safe because LayoutId is repr(transparent) to taffy::tree::NodeId.
|
||||||
.new_with_children(style, unsafe { std::mem::transmute(children) })?
|
.new_with_children(style, unsafe { std::mem::transmute(children) })
|
||||||
|
.expect(EXPECT_MESSAGE)
|
||||||
.into();
|
.into();
|
||||||
for child_id in children {
|
for child_id in children {
|
||||||
self.children_to_parents.insert(*child_id, parent_id);
|
self.children_to_parents.insert(*child_id, parent_id);
|
||||||
}
|
}
|
||||||
Ok(parent_id)
|
parent_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,44 +57,40 @@ impl TaffyLayoutEngine {
|
||||||
+ Send
|
+ Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
) -> Result<LayoutId> {
|
) -> LayoutId {
|
||||||
let style = style.to_taffy(rem_size);
|
let style = style.to_taffy(rem_size);
|
||||||
|
|
||||||
let measurable = Box::new(Measureable(measure)) as Box<dyn Measurable>;
|
let measurable = Box::new(Measureable(measure)) as Box<dyn Measurable>;
|
||||||
Ok(self
|
|
||||||
.taffy
|
|
||||||
.new_leaf_with_measure(style, MeasureFunc::Boxed(measurable))?
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compute_layout(
|
|
||||||
&mut self,
|
|
||||||
id: LayoutId,
|
|
||||||
available_space: Size<AvailableSpace>,
|
|
||||||
) -> Result<()> {
|
|
||||||
self.taffy
|
self.taffy
|
||||||
.compute_layout(id.into(), available_space.into())?;
|
.new_leaf_with_measure(style, MeasureFunc::Boxed(measurable))
|
||||||
Ok(())
|
.expect(EXPECT_MESSAGE)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout_bounds(&mut self, id: LayoutId) -> Result<Bounds<Pixels>> {
|
pub fn compute_layout(&mut self, id: LayoutId, available_space: Size<AvailableSpace>) {
|
||||||
|
self.taffy
|
||||||
|
.compute_layout(id.into(), available_space.into())
|
||||||
|
.expect(EXPECT_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn layout_bounds(&mut self, id: LayoutId) -> Bounds<Pixels> {
|
||||||
if let Some(layout) = self.absolute_layout_bounds.get(&id).cloned() {
|
if let Some(layout) = self.absolute_layout_bounds.get(&id).cloned() {
|
||||||
return Ok(layout);
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout = self.taffy.layout(id.into())?;
|
let layout = self.taffy.layout(id.into()).expect(EXPECT_MESSAGE);
|
||||||
let mut bounds = Bounds {
|
let mut bounds = Bounds {
|
||||||
origin: layout.location.into(),
|
origin: layout.location.into(),
|
||||||
size: layout.size.into(),
|
size: layout.size.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(parent_id) = self.children_to_parents.get(&id).copied() {
|
if let Some(parent_id) = self.children_to_parents.get(&id).copied() {
|
||||||
let parent_bounds = self.layout_bounds(parent_id)?;
|
let parent_bounds = self.layout_bounds(parent_id);
|
||||||
bounds.origin += parent_bounds.origin;
|
bounds.origin += parent_bounds.origin;
|
||||||
}
|
}
|
||||||
self.absolute_layout_bounds.insert(id, bounds);
|
self.absolute_layout_bounds.insert(id, bounds);
|
||||||
|
|
||||||
Ok(bounds)
|
bounds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, Bounds, Element, Handle, IntoAnyElement, LayoutId, Pixels, Result, ViewContext,
|
AnyBox, AnyElement, Bounds, Element, Handle, IntoAnyElement, LayoutId, Pixels, ViewContext,
|
||||||
WindowContext,
|
WindowContext,
|
||||||
};
|
};
|
||||||
use std::{any::Any, marker::PhantomData, sync::Arc};
|
use std::{any::Any, marker::PhantomData, sync::Arc};
|
||||||
|
@ -40,7 +40,7 @@ pub fn view<S, P, E>(
|
||||||
where
|
where
|
||||||
S: 'static + Send + Sync,
|
S: 'static + Send + Sync,
|
||||||
P: 'static,
|
P: 'static,
|
||||||
E: Element<State = S>,
|
E: Element<ViewState = S>,
|
||||||
{
|
{
|
||||||
View {
|
View {
|
||||||
state,
|
state,
|
||||||
|
@ -49,64 +49,55 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Send + Sync + 'static, P: Send + 'static> Element for View<S, P> {
|
impl<S: 'static + Send + Sync, P: 'static + Send + Sync> Element for View<S, P> {
|
||||||
type State = P;
|
type ViewState = P;
|
||||||
type FrameState = AnyElement<S>;
|
type ElementState = AnyElement<S>;
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &mut Self::State,
|
_: &mut Self::ViewState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
_: Option<Self::ElementState>,
|
||||||
) -> Result<(LayoutId, Self::FrameState)> {
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
|
) -> (LayoutId, Self::ElementState) {
|
||||||
self.state.update(cx, |state, cx| {
|
self.state.update(cx, |state, cx| {
|
||||||
let mut element = (self.render)(state, cx);
|
let mut element = (self.render)(state, cx);
|
||||||
let layout_id = element.layout(state, cx)?;
|
let layout_id = element.layout(state, cx);
|
||||||
Ok((layout_id, element))
|
(layout_id, element)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
_: &mut Self::State,
|
_: &mut Self::ViewState,
|
||||||
element: &mut Self::FrameState,
|
element: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) -> Result<()> {
|
) {
|
||||||
self.state
|
self.state
|
||||||
.update(cx, |state, cx| element.paint(state, None, cx))
|
.update(cx, |state, cx| element.paint(state, None, cx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait ViewObject: Send + 'static {
|
trait ViewObject: Send + 'static {
|
||||||
fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)>;
|
fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox);
|
||||||
fn paint(
|
fn paint(&mut self, bounds: Bounds<Pixels>, element: &mut dyn Any, cx: &mut WindowContext);
|
||||||
&mut self,
|
|
||||||
bounds: Bounds<Pixels>,
|
|
||||||
element: &mut dyn Any,
|
|
||||||
cx: &mut WindowContext,
|
|
||||||
) -> Result<()>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Send + Sync + 'static, P: Send + 'static> ViewObject for View<S, P> {
|
impl<S: Send + Sync + 'static, P: Send + 'static> ViewObject for View<S, P> {
|
||||||
fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)> {
|
fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) {
|
||||||
self.state.update(cx, |state, cx| {
|
self.state.update(cx, |state, cx| {
|
||||||
let mut element = (self.render)(state, cx);
|
let mut element = (self.render)(state, cx);
|
||||||
let layout_id = element.layout(state, cx)?;
|
let layout_id = element.layout(state, cx);
|
||||||
let element = Box::new(element) as Box<dyn Any>;
|
let element = Box::new(element) as AnyBox;
|
||||||
Ok((layout_id, element))
|
(layout_id, element)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(&mut self, _: Bounds<Pixels>, element: &mut dyn Any, cx: &mut WindowContext) {
|
||||||
&mut self,
|
|
||||||
_: Bounds<Pixels>,
|
|
||||||
element: &mut dyn Any,
|
|
||||||
cx: &mut WindowContext,
|
|
||||||
) -> Result<()> {
|
|
||||||
self.state.update(cx, |state, cx| {
|
self.state.update(cx, |state, cx| {
|
||||||
let element = element.downcast_mut::<AnyElement<S>>().unwrap();
|
let element = element.downcast_mut::<AnyElement<S>>().unwrap();
|
||||||
element.paint(state, None, cx)
|
element.paint(state, None, cx);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,15 +106,16 @@ pub struct AnyView<S> {
|
||||||
parent_state_type: PhantomData<S>,
|
parent_state_type: PhantomData<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> Element for AnyView<S> {
|
impl<S: 'static + Send + Sync> Element for AnyView<S> {
|
||||||
type State = ();
|
type ViewState = ();
|
||||||
type FrameState = Box<dyn Any>;
|
type ElementState = AnyBox;
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &mut Self::State,
|
_: &mut Self::ViewState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
_: Option<Self::ElementState>,
|
||||||
) -> Result<(LayoutId, Self::FrameState)> {
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
|
) -> (LayoutId, Self::ElementState) {
|
||||||
self.view.lock().layout(cx)
|
self.view.lock().layout(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,9 +123,9 @@ impl<S: 'static> Element for AnyView<S> {
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut (),
|
_: &mut (),
|
||||||
element: &mut Box<dyn Any>,
|
element: &mut AnyBox,
|
||||||
cx: &mut ViewContext<Self::State>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) -> Result<()> {
|
) {
|
||||||
self.view.lock().paint(bounds, element.as_mut(), cx)
|
self.view.lock().paint(bounds, element.as_mut(), cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
image_cache::RenderImageParams, px, size, AnyView, AppContext, AsyncWindowContext,
|
px, size, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace, BorrowAppContext,
|
||||||
AvailableSpace, BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId,
|
Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, Edges, Effect, Element, EntityId,
|
||||||
Edges, Effect, Element, ElementId, EntityId, Event, FontId, GlobalElementId, GlyphId, Handle,
|
Event, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, MainThread,
|
||||||
Hsla, ImageData, IsZero, LayoutId, MainThread, MainThreadOnly, MonochromeSprite,
|
MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, PlatformAtlas, PlatformWindow,
|
||||||
MouseMoveEvent, Path, Pixels, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad,
|
Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams,
|
||||||
Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow,
|
RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style,
|
||||||
SharedString, Size, Style, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle,
|
TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions,
|
||||||
WindowOptions, SUBPIXEL_VARIANTS,
|
SUBPIXEL_VARIANTS,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
|
@ -21,7 +21,7 @@ use std::{
|
||||||
mem,
|
mem,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use util::ResultExt;
|
use util::{arc_cow::ArcCow, ResultExt};
|
||||||
|
|
||||||
#[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default)]
|
#[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default)]
|
||||||
pub struct StackingOrder(pub(crate) SmallVec<[u32; 16]>);
|
pub struct StackingOrder(pub(crate) SmallVec<[u32; 16]>);
|
||||||
|
@ -52,6 +52,8 @@ pub struct Window {
|
||||||
layout_engine: TaffyLayoutEngine,
|
layout_engine: TaffyLayoutEngine,
|
||||||
pub(crate) root_view: Option<AnyView<()>>,
|
pub(crate) root_view: Option<AnyView<()>>,
|
||||||
pub(crate) element_id_stack: GlobalElementId,
|
pub(crate) element_id_stack: GlobalElementId,
|
||||||
|
prev_element_states: HashMap<GlobalElementId, AnyBox>,
|
||||||
|
element_states: HashMap<GlobalElementId, AnyBox>,
|
||||||
z_index_stack: StackingOrder,
|
z_index_stack: StackingOrder,
|
||||||
content_mask_stack: Vec<ContentMask<Pixels>>,
|
content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||||
mouse_event_handlers: HashMap<TypeId, Vec<(StackingOrder, MouseEventHandler)>>,
|
mouse_event_handlers: HashMap<TypeId, Vec<(StackingOrder, MouseEventHandler)>>,
|
||||||
|
@ -114,6 +116,8 @@ impl Window {
|
||||||
layout_engine: TaffyLayoutEngine::new(),
|
layout_engine: TaffyLayoutEngine::new(),
|
||||||
root_view: None,
|
root_view: None,
|
||||||
element_id_stack: GlobalElementId::default(),
|
element_id_stack: GlobalElementId::default(),
|
||||||
|
prev_element_states: HashMap::default(),
|
||||||
|
element_states: HashMap::default(),
|
||||||
z_index_stack: StackingOrder(SmallVec::new()),
|
z_index_stack: StackingOrder(SmallVec::new()),
|
||||||
content_mask_stack: Vec::new(),
|
content_mask_stack: Vec::new(),
|
||||||
mouse_event_handlers: HashMap::default(),
|
mouse_event_handlers: HashMap::default(),
|
||||||
|
@ -147,7 +151,7 @@ impl ContentMask<Pixels> {
|
||||||
|
|
||||||
pub struct WindowContext<'a, 'w> {
|
pub struct WindowContext<'a, 'w> {
|
||||||
app: Reference<'a, AppContext>,
|
app: Reference<'a, AppContext>,
|
||||||
window: Reference<'w, Window>,
|
pub(crate) window: Reference<'w, Window>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'w> WindowContext<'a, 'w> {
|
impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
|
@ -242,7 +246,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
&mut self,
|
&mut self,
|
||||||
style: Style,
|
style: Style,
|
||||||
children: impl IntoIterator<Item = LayoutId>,
|
children: impl IntoIterator<Item = LayoutId>,
|
||||||
) -> Result<LayoutId> {
|
) -> LayoutId {
|
||||||
self.app.layout_id_buffer.clear();
|
self.app.layout_id_buffer.clear();
|
||||||
self.app.layout_id_buffer.extend(children.into_iter());
|
self.app.layout_id_buffer.extend(children.into_iter());
|
||||||
let rem_size = self.rem_size();
|
let rem_size = self.rem_size();
|
||||||
|
@ -259,18 +263,17 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
style: Style,
|
style: Style,
|
||||||
rem_size: Pixels,
|
rem_size: Pixels,
|
||||||
measure: F,
|
measure: F,
|
||||||
) -> Result<LayoutId> {
|
) -> LayoutId {
|
||||||
self.window
|
self.window
|
||||||
.layout_engine
|
.layout_engine
|
||||||
.request_measured_layout(style, rem_size, measure)
|
.request_measured_layout(style, rem_size, measure)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Result<Bounds<Pixels>> {
|
pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
|
||||||
Ok(self
|
self.window
|
||||||
.window
|
|
||||||
.layout_engine
|
.layout_engine
|
||||||
.layout_bounds(layout_id)
|
.layout_bounds(layout_id)
|
||||||
.map(Into::into)?)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scale_factor(&self) -> f32 {
|
pub fn scale_factor(&self) -> f32 {
|
||||||
|
@ -586,27 +589,25 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn draw(&mut self) -> Result<()> {
|
pub(crate) fn draw(&mut self) {
|
||||||
let unit_entity = self.unit_entity.clone();
|
let unit_entity = self.unit_entity.clone();
|
||||||
self.update_entity(&unit_entity, |view, cx| {
|
self.update_entity(&unit_entity, |view, cx| {
|
||||||
cx.window
|
cx.start_frame();
|
||||||
.mouse_event_handlers
|
|
||||||
.values_mut()
|
|
||||||
.for_each(Vec::clear);
|
|
||||||
|
|
||||||
let mut root_view = cx.window.root_view.take().unwrap();
|
let mut root_view = cx.window.root_view.take().unwrap();
|
||||||
let (root_layout_id, mut frame_state) = root_view.layout(&mut (), cx)?;
|
|
||||||
let available_space = cx.window.content_size.map(Into::into);
|
|
||||||
|
|
||||||
cx.window
|
if let Some(element_id) = root_view.element_id() {
|
||||||
.layout_engine
|
cx.with_element_state(element_id, |element_state, cx| {
|
||||||
.compute_layout(root_layout_id, available_space)?;
|
let element_state = draw_with_element_state(&mut root_view, element_state, cx);
|
||||||
let layout = cx.window.layout_engine.layout_bounds(root_layout_id)?;
|
((), element_state)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
draw_with_element_state(&mut root_view, None, cx);
|
||||||
|
};
|
||||||
|
|
||||||
root_view.paint(layout, &mut (), &mut frame_state, cx)?;
|
|
||||||
cx.window.root_view = Some(root_view);
|
cx.window.root_view = Some(root_view);
|
||||||
let scene = cx.window.scene_builder.build();
|
|
||||||
|
|
||||||
|
let scene = cx.window.scene_builder.build();
|
||||||
cx.run_on_main(view, |_, cx| {
|
cx.run_on_main(view, |_, cx| {
|
||||||
cx.window
|
cx.window
|
||||||
.platform_window
|
.platform_window
|
||||||
|
@ -615,9 +616,38 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
cx.window.dirty = false;
|
cx.window.dirty = false;
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
});
|
||||||
|
|
||||||
Ok(())
|
fn draw_with_element_state(
|
||||||
})
|
root_view: &mut AnyView<()>,
|
||||||
|
element_state: Option<AnyBox>,
|
||||||
|
cx: &mut ViewContext<()>,
|
||||||
|
) -> AnyBox {
|
||||||
|
let (layout_id, mut element_state) = root_view.layout(&mut (), element_state, cx);
|
||||||
|
let available_space = cx.window.content_size.map(Into::into);
|
||||||
|
cx.window
|
||||||
|
.layout_engine
|
||||||
|
.compute_layout(layout_id, available_space);
|
||||||
|
let bounds = cx.window.layout_engine.layout_bounds(layout_id);
|
||||||
|
root_view.paint(bounds, &mut (), &mut element_state, cx);
|
||||||
|
element_state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_frame(&mut self) {
|
||||||
|
// Make the current element states the previous, and then clear the current.
|
||||||
|
// The empty element states map will be populated for any element states we
|
||||||
|
// reference during the upcoming frame.
|
||||||
|
let window = &mut *self.window;
|
||||||
|
mem::swap(&mut window.element_states, &mut window.prev_element_states);
|
||||||
|
self.window.element_states.clear();
|
||||||
|
|
||||||
|
// Clear mouse event listeners, because elements add new element listeners
|
||||||
|
// when the upcoming frame is painted.
|
||||||
|
self.window
|
||||||
|
.mouse_event_handlers
|
||||||
|
.values_mut()
|
||||||
|
.for_each(Vec::clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispatch_event(&mut self, event: Event) -> bool {
|
fn dispatch_event(&mut self, event: Event) -> bool {
|
||||||
|
@ -753,6 +783,42 @@ pub trait BorrowWindow: BorrowAppContext {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn with_element_state<S: 'static + Send + Sync, R>(
|
||||||
|
&mut self,
|
||||||
|
id: ElementId,
|
||||||
|
f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
|
||||||
|
) -> R {
|
||||||
|
self.window_mut().element_id_stack.push(id);
|
||||||
|
let global_id = self.window_mut().element_id_stack.clone();
|
||||||
|
|
||||||
|
if let Some(any) = self
|
||||||
|
.window_mut()
|
||||||
|
.element_states
|
||||||
|
.remove(&global_id)
|
||||||
|
.or_else(|| self.window_mut().prev_element_states.remove(&global_id))
|
||||||
|
{
|
||||||
|
// Using the extra inner option to avoid needing to reallocate a new box.
|
||||||
|
let mut state_box = any
|
||||||
|
.downcast::<Option<S>>()
|
||||||
|
.expect("invalid element state type for id");
|
||||||
|
let state = state_box
|
||||||
|
.take()
|
||||||
|
.expect("element state is already on the stack");
|
||||||
|
let (result, state) = f(Some(state), self);
|
||||||
|
state_box.replace(state);
|
||||||
|
self.window_mut()
|
||||||
|
.element_states
|
||||||
|
.insert(global_id, state_box);
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
let (result, state) = f(None, self);
|
||||||
|
self.window_mut()
|
||||||
|
.element_states
|
||||||
|
.insert(global_id, Box::new(Some(state)));
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn content_mask(&self) -> ContentMask<Pixels> {
|
fn content_mask(&self) -> ContentMask<Pixels> {
|
||||||
self.window()
|
self.window()
|
||||||
.content_mask_stack
|
.content_mask_stack
|
||||||
|
@ -791,26 +857,6 @@ impl<S> BorrowAppContext for ViewContext<'_, '_, S> {
|
||||||
fn app_mut(&mut self) -> &mut AppContext {
|
fn app_mut(&mut self) -> &mut AppContext {
|
||||||
&mut *self.window_cx.app
|
&mut *self.window_cx.app
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_text_style<F, R>(&mut self, style: crate::TextStyleRefinement, f: F) -> R
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut Self) -> R,
|
|
||||||
{
|
|
||||||
self.window_cx.app.push_text_style(style);
|
|
||||||
let result = f(self);
|
|
||||||
self.window_cx.app.pop_text_style();
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn with_state<T: Send + Sync + 'static, F, R>(&mut self, state: T, f: F) -> R
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut Self) -> R,
|
|
||||||
{
|
|
||||||
self.window_cx.app.push_state(state);
|
|
||||||
let result = f(self);
|
|
||||||
self.window_cx.app.pop_state::<T>();
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> BorrowWindow for ViewContext<'_, '_, S> {
|
impl<S> BorrowWindow for ViewContext<'_, '_, S> {
|
||||||
|
@ -1012,3 +1058,6 @@ impl From<SmallVec<[u32; 16]>> for StackingOrder {
|
||||||
StackingOrder(small_vec)
|
StackingOrder(small_vec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
pub struct ElementId(ArcCow<'static, [u8]>);
|
||||||
|
|
|
@ -22,7 +22,7 @@ impl CollabPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CollabPanel {
|
impl CollabPanel {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<State = Self> {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<ViewState = Self> {
|
||||||
let theme = theme(cx);
|
let theme = theme(cx);
|
||||||
|
|
||||||
// Panel
|
// Panel
|
||||||
|
@ -123,7 +123,7 @@ impl CollabPanel {
|
||||||
label: impl IntoAnyElement<Self>,
|
label: impl IntoAnyElement<Self>,
|
||||||
expanded: bool,
|
expanded: bool,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
) -> impl Element<State = Self> {
|
) -> impl Element<ViewState = Self> {
|
||||||
div()
|
div()
|
||||||
.h_7()
|
.h_7()
|
||||||
.px_2()
|
.px_2()
|
||||||
|
@ -153,7 +153,7 @@ impl CollabPanel {
|
||||||
avatar_uri: impl Into<SharedString>,
|
avatar_uri: impl Into<SharedString>,
|
||||||
label: impl IntoAnyElement<Self>,
|
label: impl IntoAnyElement<Self>,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
) -> impl Element<State = Self> {
|
) -> impl Element<ViewState = Self> {
|
||||||
div()
|
div()
|
||||||
.h_7()
|
.h_7()
|
||||||
.px_2()
|
.px_2()
|
||||||
|
|
|
@ -129,10 +129,10 @@ where
|
||||||
deserializer.deserialize_map(SyntaxVisitor)
|
deserializer.deserialize_map(SyntaxVisitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn themed<E, F>(theme: Theme, cx: &mut ViewContext<E::State>, build_child: F) -> Themed<E>
|
pub fn themed<E, F>(theme: Theme, cx: &mut ViewContext<E::ViewState>, build_child: F) -> Themed<E>
|
||||||
where
|
where
|
||||||
E: Element,
|
E: Element,
|
||||||
F: FnOnce(&mut ViewContext<E::State>) -> E,
|
F: FnOnce(&mut ViewContext<E::ViewState>) -> E,
|
||||||
{
|
{
|
||||||
let child = cx.with_state(theme.clone(), |cx| build_child(cx));
|
let child = cx.with_state(theme.clone(), |cx| build_child(cx));
|
||||||
Themed { theme, child }
|
Themed { theme, child }
|
||||||
|
@ -144,14 +144,14 @@ pub struct Themed<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Element> Element for Themed<E> {
|
impl<E: Element> Element for Themed<E> {
|
||||||
type State = E::State;
|
type ViewState = E::ViewState;
|
||||||
type FrameState = E::FrameState;
|
type ElementState = E::ElementState;
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut E::State,
|
state: &mut E::ViewState,
|
||||||
cx: &mut ViewContext<E::State>,
|
cx: &mut ViewContext<E::ViewState>,
|
||||||
) -> anyhow::Result<(LayoutId, Self::FrameState)>
|
) -> anyhow::Result<(LayoutId, Self::ElementState)>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
@ -161,9 +161,9 @@ impl<E: Element> Element for Themed<E> {
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
state: &mut Self::State,
|
state: &mut Self::ViewState,
|
||||||
frame_state: &mut Self::FrameState,
|
frame_state: &mut Self::ElementState,
|
||||||
cx: &mut ViewContext<Self::State>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) -> Result<()>
|
) -> Result<()>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
|
|
@ -25,7 +25,7 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<State = Self> {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<ViewState = Self> {
|
||||||
themed(rose_pine_dawn(), cx, |cx| {
|
themed(rose_pine_dawn(), cx, |cx| {
|
||||||
let theme = theme(cx);
|
let theme = theme(cx);
|
||||||
div()
|
div()
|
||||||
|
@ -57,7 +57,7 @@ impl Workspace {
|
||||||
|
|
||||||
struct Titlebar;
|
struct Titlebar;
|
||||||
|
|
||||||
pub fn titlebar<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
|
pub fn titlebar<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
|
||||||
let ref mut this = Titlebar;
|
let ref mut this = Titlebar;
|
||||||
let theme = theme(cx);
|
let theme = theme(cx);
|
||||||
div()
|
div()
|
||||||
|
@ -75,7 +75,7 @@ impl Titlebar {
|
||||||
fn render<V: 'static + Send + Sync>(
|
fn render<V: 'static + Send + Sync>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut ViewContext<V>,
|
cx: &mut ViewContext<V>,
|
||||||
) -> impl Element<State = V> {
|
) -> impl Element<ViewState = V> {
|
||||||
let theme = theme(cx);
|
let theme = theme(cx);
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
|
@ -91,7 +91,7 @@ impl Titlebar {
|
||||||
fn left_group<S: 'static + Send + Sync>(
|
fn left_group<S: 'static + Send + Sync>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut ViewContext<S>,
|
cx: &mut ViewContext<S>,
|
||||||
) -> impl Element<State = S> {
|
) -> impl Element<ViewState = S> {
|
||||||
let theme = theme(cx);
|
let theme = theme(cx);
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
|
@ -174,7 +174,7 @@ impl Titlebar {
|
||||||
fn right_group<S: 'static + Send + Sync>(
|
fn right_group<S: 'static + Send + Sync>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut ViewContext<S>,
|
cx: &mut ViewContext<S>,
|
||||||
) -> impl Element<State = S> {
|
) -> impl Element<ViewState = S> {
|
||||||
let theme = theme(cx);
|
let theme = theme(cx);
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
|
@ -306,7 +306,9 @@ mod statusbar {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn statusbar<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
|
pub fn statusbar<S: 'static + Send + Sync>(
|
||||||
|
cx: &mut ViewContext<S>,
|
||||||
|
) -> impl Element<ViewState = S> {
|
||||||
let theme = theme(cx);
|
let theme = theme(cx);
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
|
@ -319,7 +321,9 @@ mod statusbar {
|
||||||
// .child(right_group(cx))
|
// .child(right_group(cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn left_group<V: 'static + Send + Sync>(cx: &mut ViewContext<V>) -> impl Element<State = V> {
|
fn left_group<V: 'static + Send + Sync>(
|
||||||
|
cx: &mut ViewContext<V>,
|
||||||
|
) -> impl Element<ViewState = V> {
|
||||||
let theme = theme(cx);
|
let theme = theme(cx);
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
|
@ -416,7 +420,9 @@ mod statusbar {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn right_group<S: 'static + Send + Sync>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
|
fn right_group<S: 'static + Send + Sync>(
|
||||||
|
cx: &mut ViewContext<S>,
|
||||||
|
) -> impl Element<ViewState = S> {
|
||||||
let theme = theme(cx);
|
let theme = theme(cx);
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue