Merge branch 'main' into callback-handles

This commit is contained in:
Conrad Irwin 2023-11-20 12:21:42 -07:00
commit d0dd44faad
117 changed files with 3170 additions and 2027 deletions

View file

@ -14,7 +14,7 @@ use smallvec::SmallVec;
pub use test_context::*;
use crate::{
current_platform, image_cache::ImageCache, Action, ActionRegistry, AnyBox, AnyView,
current_platform, image_cache::ImageCache, Action, ActionRegistry, Any, AnyView,
AnyWindowHandle, AppMetadata, AssetSource, BackgroundExecutor, ClipboardItem, Context,
DispatchPhase, DisplayId, Entity, EventEmitter, FocusEvent, FocusHandle, FocusId,
ForegroundExecutor, KeyBinding, Keymap, LayoutId, PathPromptOptions, Pixels, Platform,
@ -28,7 +28,7 @@ use futures::{channel::oneshot, future::LocalBoxFuture, Future};
use parking_lot::Mutex;
use slotmap::SlotMap;
use std::{
any::{type_name, Any, TypeId},
any::{type_name, TypeId},
cell::{Ref, RefCell, RefMut},
marker::PhantomData,
mem,
@ -194,7 +194,7 @@ pub struct AppContext {
asset_source: Arc<dyn AssetSource>,
pub(crate) image_cache: ImageCache,
pub(crate) text_style_stack: Vec<TextStyleRefinement>,
pub(crate) globals_by_type: HashMap<TypeId, AnyBox>,
pub(crate) globals_by_type: HashMap<TypeId, Box<dyn Any>>,
pub(crate) entities: EntityMap,
pub(crate) new_view_observers: SubscriberSet<TypeId, NewViewListener>,
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
@ -424,7 +424,7 @@ impl AppContext {
/// Opens a new window with the given option and the root view returned by the given function.
/// The function is invoked with a `WindowContext`, which can be used to interact with window-specific
/// functionality.
pub fn open_window<V: Render>(
pub fn open_window<V: 'static + Render>(
&mut self,
options: crate::WindowOptions,
build_root_view: impl FnOnce(&mut WindowContext) -> View<V>,
@ -1104,12 +1104,12 @@ pub(crate) enum Effect {
/// Wraps a global variable value during `update_global` while the value has been moved to the stack.
pub(crate) struct GlobalLease<G: 'static> {
global: AnyBox,
global: Box<dyn Any>,
global_type: PhantomData<G>,
}
impl<G: 'static> GlobalLease<G> {
fn new(global: AnyBox) -> Self {
fn new(global: Box<dyn Any>) -> Self {
GlobalLease {
global,
global_type: PhantomData,

View file

@ -115,7 +115,7 @@ impl AsyncAppContext {
build_root_view: impl FnOnce(&mut WindowContext) -> View<V>,
) -> Result<WindowHandle<V>>
where
V: Render,
V: 'static + Render,
{
let app = self
.app
@ -306,7 +306,7 @@ impl VisualContext for AsyncWindowContext {
build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
) -> Self::Result<View<V>>
where
V: Render,
V: 'static + Render,
{
self.window
.update(self, |_, cx| cx.replace_root_view(build_view))

View file

@ -1,10 +1,10 @@
use crate::{private::Sealed, AnyBox, AppContext, Context, Entity, ModelContext};
use crate::{private::Sealed, AppContext, Context, Entity, ModelContext};
use anyhow::{anyhow, Result};
use derive_more::{Deref, DerefMut};
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
use slotmap::{SecondaryMap, SlotMap};
use std::{
any::{type_name, TypeId},
any::{type_name, Any, TypeId},
fmt::{self, Display},
hash::{Hash, Hasher},
marker::PhantomData,
@ -31,7 +31,7 @@ impl Display for EntityId {
}
pub(crate) struct EntityMap {
entities: SecondaryMap<EntityId, AnyBox>,
entities: SecondaryMap<EntityId, Box<dyn Any>>,
ref_counts: Arc<RwLock<EntityRefCounts>>,
}
@ -102,7 +102,7 @@ impl EntityMap {
);
}
pub fn take_dropped(&mut self) -> Vec<(EntityId, AnyBox)> {
pub fn take_dropped(&mut self) -> Vec<(EntityId, Box<dyn Any>)> {
let mut ref_counts = self.ref_counts.write();
let dropped_entity_ids = mem::take(&mut ref_counts.dropped_entity_ids);
@ -122,7 +122,7 @@ impl EntityMap {
}
pub struct Lease<'a, T> {
entity: Option<AnyBox>,
entity: Option<Box<dyn Any>>,
pub model: &'a Model<T>,
entity_type: PhantomData<T>,
}

View file

@ -126,7 +126,7 @@ impl TestAppContext {
pub fn add_window<F, V>(&mut self, build_window: F) -> WindowHandle<V>
where
F: FnOnce(&mut ViewContext<V>) -> V,
V: Render,
V: 'static + Render,
{
let mut cx = self.app.borrow_mut();
cx.open_window(WindowOptions::default(), |cx| cx.build_view(build_window))
@ -143,7 +143,7 @@ impl TestAppContext {
pub fn add_window_view<F, V>(&mut self, build_window: F) -> (View<V>, &mut VisualTestContext)
where
F: FnOnce(&mut ViewContext<V>) -> V,
V: Render,
V: 'static + Render,
{
let mut cx = self.app.borrow_mut();
let window = cx.open_window(WindowOptions::default(), |cx| cx.build_view(build_window));
@ -591,7 +591,7 @@ impl<'a> VisualContext for VisualTestContext<'a> {
build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
) -> Self::Result<View<V>>
where
V: Render,
V: 'static + Render,
{
self.window
.update(self.cx, |_, cx| cx.replace_root_view(build_view))

View file

@ -1,306 +1,63 @@
use crate::{
AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, WindowContext,
AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, ViewContext,
WindowContext,
};
use derive_more::{Deref, DerefMut};
pub(crate) use smallvec::SmallVec;
use std::{any::Any, fmt::Debug, mem};
use std::{any::Any, fmt::Debug};
pub trait Element {
type ElementState: 'static;
pub trait Render: 'static + Sized {
type Element: Element + 'static;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element;
}
pub trait RenderOnce: Sized {
type Element: Element + 'static;
fn element_id(&self) -> Option<ElementId>;
fn layout(
&mut self,
element_state: Option<Self::ElementState>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState);
fn render_once(self) -> Self::Element;
fn paint(
&mut self,
bounds: Bounds<Pixels>,
element_state: &mut Self::ElementState,
cx: &mut WindowContext,
);
fn render_into_any(self) -> AnyElement {
self.render_once().into_any()
}
fn draw<T, R>(
self,
origin: Point<Pixels>,
available_space: Size<T>,
cx: &mut WindowContext,
f: impl FnOnce(&Self::ElementState, &mut WindowContext) -> R,
f: impl FnOnce(&mut <Self::Element as Element>::State, &mut WindowContext) -> R,
) -> R
where
Self: Sized,
T: Clone + Default + Debug + Into<AvailableSpace>,
{
let mut element = RenderedElement {
element: self,
phase: ElementRenderPhase::Start,
let element = self.render_once();
let element_id = element.element_id();
let element = DrawableElement {
element: Some(element),
phase: ElementDrawPhase::Start,
};
element.draw(origin, available_space.map(Into::into), cx);
if let ElementRenderPhase::Painted { frame_state } = &element.phase {
if let Some(frame_state) = frame_state.as_ref() {
f(&frame_state, cx)
} else {
let element_id = element
.element
.element_id()
.expect("we either have some frame_state or some element_id");
cx.with_element_state(element_id, |element_state, cx| {
let element_state = element_state.unwrap();
let result = f(&element_state, cx);
(result, element_state)
})
}
let frame_state =
DrawableElement::draw(element, origin, available_space.map(Into::into), cx);
if let Some(mut frame_state) = frame_state {
f(&mut frame_state, cx)
} else {
unreachable!()
cx.with_element_state(element_id.unwrap(), |element_state, cx| {
let mut element_state = element_state.unwrap();
let result = f(&mut element_state, cx);
(result, element_state)
})
}
}
}
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
pub trait ParentComponent {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>;
fn child(mut self, child: impl Component) -> Self
where
Self: Sized,
{
self.children_mut().push(child.render());
self
}
fn children(mut self, iter: impl IntoIterator<Item = impl Component>) -> Self
where
Self: Sized,
{
self.children_mut()
.extend(iter.into_iter().map(|item| item.render()));
self
}
}
trait ElementObject {
fn element_id(&self) -> Option<ElementId>;
fn layout(&mut self, cx: &mut WindowContext) -> LayoutId;
fn paint(&mut self, cx: &mut WindowContext);
fn measure(
&mut self,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) -> Size<Pixels>;
fn draw(
&mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
);
}
struct RenderedElement<E: Element> {
element: E,
phase: ElementRenderPhase<E::ElementState>,
}
#[derive(Default)]
enum ElementRenderPhase<V> {
#[default]
Start,
LayoutRequested {
layout_id: LayoutId,
frame_state: Option<V>,
},
LayoutComputed {
layout_id: LayoutId,
available_space: Size<AvailableSpace>,
frame_state: Option<V>,
},
Painted {
frame_state: Option<V>,
},
}
/// 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
/// improved usability.
impl<E: Element> RenderedElement<E> {
fn new(element: E) -> Self {
RenderedElement {
element,
phase: ElementRenderPhase::Start,
}
}
}
impl<E> ElementObject for RenderedElement<E>
where
E: Element,
E::ElementState: 'static,
{
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
let (layout_id, frame_state) = match mem::take(&mut self.phase) {
ElementRenderPhase::Start => {
if let Some(id) = self.element.element_id() {
let layout_id = cx.with_element_state(id, |element_state, cx| {
self.element.layout(element_state, cx)
});
(layout_id, None)
} else {
let (layout_id, frame_state) = self.element.layout(None, cx);
(layout_id, Some(frame_state))
}
}
ElementRenderPhase::LayoutRequested { .. }
| ElementRenderPhase::LayoutComputed { .. }
| ElementRenderPhase::Painted { .. } => {
panic!("element rendered twice")
}
};
self.phase = ElementRenderPhase::LayoutRequested {
layout_id,
frame_state,
};
layout_id
}
fn paint(&mut self, cx: &mut WindowContext) {
self.phase = match mem::take(&mut self.phase) {
ElementRenderPhase::LayoutRequested {
layout_id,
mut frame_state,
}
| ElementRenderPhase::LayoutComputed {
layout_id,
mut frame_state,
..
} => {
let bounds = cx.layout_bounds(layout_id);
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, &mut element_state, cx);
((), element_state)
});
} else {
self.element
.paint(bounds, frame_state.as_mut().unwrap(), cx);
}
ElementRenderPhase::Painted { frame_state }
}
_ => panic!("must call layout before paint"),
};
}
fn measure(
&mut self,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) -> Size<Pixels> {
if matches!(&self.phase, ElementRenderPhase::Start) {
self.layout(cx);
}
let layout_id = match &mut self.phase {
ElementRenderPhase::LayoutRequested {
layout_id,
frame_state,
} => {
cx.compute_layout(*layout_id, available_space);
let layout_id = *layout_id;
self.phase = ElementRenderPhase::LayoutComputed {
layout_id,
available_space,
frame_state: frame_state.take(),
};
layout_id
}
ElementRenderPhase::LayoutComputed {
layout_id,
available_space: prev_available_space,
..
} => {
if available_space != *prev_available_space {
cx.compute_layout(*layout_id, available_space);
*prev_available_space = available_space;
}
*layout_id
}
_ => panic!("cannot measure after painting"),
};
cx.layout_bounds(layout_id).size
}
fn draw(
&mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) {
self.measure(available_space, cx);
cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
}
}
pub struct AnyElement(Box<dyn ElementObject>);
impl AnyElement {
pub fn new<E>(element: E) -> Self
where
E: 'static + Element,
E::ElementState: Any,
{
AnyElement(Box::new(RenderedElement::new(element)))
}
pub fn element_id(&self) -> Option<ElementId> {
self.0.element_id()
}
pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
self.0.layout(cx)
}
pub fn paint(&mut self, cx: &mut WindowContext) {
self.0.paint(cx)
}
/// Initializes this element and performs layout within the given available space to determine its size.
pub fn measure(
&mut self,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) -> Size<Pixels> {
self.0.measure(available_space, cx)
}
/// Initializes this element and performs layout in the available space, then paints it at the given origin.
pub fn draw(
&mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) {
self.0.draw(origin, available_space, cx)
}
}
pub trait Component {
fn render(self) -> AnyElement;
fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
where
Self: Sized,
U: Component,
U: RenderOnce,
{
f(self)
}
@ -326,60 +83,463 @@ pub trait Component {
}
}
impl Component for AnyElement {
fn render(self) -> AnyElement {
self
pub trait Element: 'static + RenderOnce {
type State: 'static;
fn layout(
&mut self,
state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State);
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext);
fn into_any(self) -> AnyElement {
AnyElement::new(self)
}
}
impl<E, F> Element for Option<F>
where
E: 'static + Component,
F: FnOnce(&mut WindowContext) -> E + 'static,
{
type ElementState = AnyElement;
pub trait Component: 'static {
type Rendered: RenderOnce;
fn render(self, cx: &mut WindowContext) -> Self::Rendered;
}
pub struct CompositeElement<C> {
component: Option<C>,
}
pub struct CompositeElementState<C: Component> {
rendered_element: Option<<C::Rendered as RenderOnce>::Element>,
rendered_element_state: <<C::Rendered as RenderOnce>::Element as Element>::State,
}
impl<C> CompositeElement<C> {
pub fn new(component: C) -> Self {
CompositeElement {
component: Some(component),
}
}
}
impl<C: Component> Element for CompositeElement<C> {
type State = CompositeElementState<C>;
fn layout(
&mut self,
state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
let mut element = self.component.take().unwrap().render(cx).render_once();
let (layout_id, state) = element.layout(state.map(|s| s.rendered_element_state), cx);
let state = CompositeElementState {
rendered_element: Some(element),
rendered_element_state: state,
};
(layout_id, state)
}
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
state
.rendered_element
.take()
.unwrap()
.paint(bounds, &mut state.rendered_element_state, cx);
}
}
impl<C: Component> RenderOnce for CompositeElement<C> {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
None
}
fn layout(
&mut self,
_: Option<Self::ElementState>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
let render = self.take().unwrap();
let mut rendered_element = (render)(cx).render();
let layout_id = rendered_element.layout(cx);
(layout_id, rendered_element)
}
fn paint(
&mut self,
_bounds: Bounds<Pixels>,
rendered_element: &mut Self::ElementState,
cx: &mut WindowContext,
) {
rendered_element.paint(cx)
fn render_once(self) -> Self::Element {
self
}
}
impl<E, F> Component for Option<F>
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
pub trait ParentElement {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>;
fn child(mut self, child: impl RenderOnce) -> Self
where
Self: Sized,
{
self.children_mut().push(child.render_once().into_any());
self
}
fn children(mut self, children: impl IntoIterator<Item = impl RenderOnce>) -> Self
where
Self: Sized,
{
self.children_mut().extend(
children
.into_iter()
.map(|child| child.render_once().into_any()),
);
self
}
}
trait ElementObject {
fn element_id(&self) -> Option<ElementId>;
fn layout(&mut self, cx: &mut WindowContext) -> LayoutId;
fn paint(&mut self, cx: &mut WindowContext);
fn measure(
&mut self,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) -> Size<Pixels>;
fn draw(
&mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
);
}
pub struct DrawableElement<E: Element> {
element: Option<E>,
phase: ElementDrawPhase<E::State>,
}
#[derive(Default)]
enum ElementDrawPhase<S> {
#[default]
Start,
LayoutRequested {
layout_id: LayoutId,
frame_state: Option<S>,
},
LayoutComputed {
layout_id: LayoutId,
available_space: Size<AvailableSpace>,
frame_state: Option<S>,
},
}
/// A wrapper around an implementer of [Element] that allows it to be drawn in a window.
impl<E: Element> DrawableElement<E> {
fn new(element: E) -> Self {
DrawableElement {
element: Some(element),
phase: ElementDrawPhase::Start,
}
}
fn element_id(&self) -> Option<ElementId> {
self.element.as_ref()?.element_id()
}
fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
{
let layout_id = cx.with_element_state(id, |element_state, cx| {
self.element.as_mut().unwrap().layout(element_state, cx)
});
(layout_id, None)
} else {
let (layout_id, frame_state) = self.element.as_mut().unwrap().layout(None, cx);
(layout_id, Some(frame_state))
};
self.phase = ElementDrawPhase::LayoutRequested {
layout_id,
frame_state,
};
layout_id
}
fn paint(mut self, cx: &mut WindowContext) -> Option<E::State> {
match self.phase {
ElementDrawPhase::LayoutRequested {
layout_id,
frame_state,
}
| ElementDrawPhase::LayoutComputed {
layout_id,
frame_state,
..
} => {
let bounds = cx.layout_bounds(layout_id);
if let Some(mut frame_state) = frame_state {
self.element
.take()
.unwrap()
.paint(bounds, &mut frame_state, cx);
Some(frame_state)
} else {
let element_id = self
.element
.as_ref()
.unwrap()
.element_id()
.expect("if we don't have frame state, we should have element state");
cx.with_element_state(element_id, |element_state, cx| {
let mut element_state = element_state.unwrap();
self.element
.take()
.unwrap()
.paint(bounds, &mut element_state, cx);
((), element_state)
});
None
}
}
_ => panic!("must call layout before paint"),
}
}
fn measure(
&mut self,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) -> Size<Pixels> {
if matches!(&self.phase, ElementDrawPhase::Start) {
self.layout(cx);
}
let layout_id = match &mut self.phase {
ElementDrawPhase::LayoutRequested {
layout_id,
frame_state,
} => {
cx.compute_layout(*layout_id, available_space);
let layout_id = *layout_id;
self.phase = ElementDrawPhase::LayoutComputed {
layout_id,
available_space,
frame_state: frame_state.take(),
};
layout_id
}
ElementDrawPhase::LayoutComputed {
layout_id,
available_space: prev_available_space,
..
} => {
if available_space != *prev_available_space {
cx.compute_layout(*layout_id, available_space);
*prev_available_space = available_space;
}
*layout_id
}
_ => panic!("cannot measure after painting"),
};
cx.layout_bounds(layout_id).size
}
fn draw(
mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) -> Option<E::State> {
self.measure(available_space, cx);
cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
}
}
// impl<V: 'static, E: Element> Element for DrawableElement<V, E> {
// type State = <E::Element as Element>::State;
// fn layout(
// &mut self,
// element_state: Option<Self::State>,
// cx: &mut WindowContext,
// ) -> (LayoutId, Self::State) {
// }
// fn paint(
// self,
// bounds: Bounds<Pixels>,
// element_state: &mut Self::State,
// cx: &mut WindowContext,
// ) {
// todo!()
// }
// }
// impl<V: 'static, E: 'static + Element> RenderOnce for DrawableElement<V, E> {
// type Element = Self;
// fn element_id(&self) -> Option<ElementId> {
// self.element.as_ref()?.element_id()
// }
// fn render_once(self) -> Self::Element {
// self
// }
// }
impl<E> ElementObject for Option<DrawableElement<E>>
where
E: 'static + Component,
F: FnOnce(&mut WindowContext) -> E + 'static,
E: Element,
E::State: 'static,
{
fn render(self) -> AnyElement {
fn element_id(&self) -> Option<ElementId> {
self.as_ref().unwrap().element_id()
}
fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
DrawableElement::layout(self.as_mut().unwrap(), cx)
}
fn paint(&mut self, cx: &mut WindowContext) {
DrawableElement::paint(self.take().unwrap(), cx);
}
fn measure(
&mut self,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) -> Size<Pixels> {
DrawableElement::measure(self.as_mut().unwrap(), available_space, cx)
}
fn draw(
&mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) {
DrawableElement::draw(self.take().unwrap(), origin, available_space, cx);
}
}
pub struct AnyElement(Box<dyn ElementObject>);
impl AnyElement {
pub fn new<E>(element: E) -> Self
where
E: 'static + Element,
E::State: Any,
{
AnyElement(Box::new(Some(DrawableElement::new(element))) as Box<dyn ElementObject>)
}
pub fn element_id(&self) -> Option<ElementId> {
self.0.element_id()
}
pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
self.0.layout(cx)
}
pub fn paint(mut self, cx: &mut WindowContext) {
self.0.paint(cx)
}
/// Initializes this element and performs layout within the given available space to determine its size.
pub fn measure(
&mut self,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) -> Size<Pixels> {
self.0.measure(available_space, cx)
}
/// Initializes this element and performs layout in the available space, then paints it at the given origin.
pub fn draw(
mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
cx: &mut WindowContext,
) {
self.0.draw(origin, available_space, cx)
}
/// Converts this `AnyElement` into a trait object that can be stored and manipulated.
pub fn into_any(self) -> AnyElement {
AnyElement::new(self)
}
}
impl<E, F> Component for F
where
E: 'static + Component,
F: FnOnce(&mut WindowContext) -> E + 'static,
{
fn render(self) -> AnyElement {
AnyElement::new(Some(self))
impl Element for AnyElement {
type State = ();
fn layout(
&mut self,
_: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
let layout_id = self.layout(cx);
(layout_id, ())
}
fn paint(self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut WindowContext) {
self.paint(cx);
}
}
impl RenderOnce for AnyElement {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
AnyElement::element_id(self)
}
fn render_once(self) -> Self::Element {
self
}
}
// impl<V, E, F> Element for Option<F>
// where
// V: 'static,
// E: Element,
// F: FnOnce(&mut V, &mut WindowContext<'_, V>) -> E + 'static,
// {
// type State = Option<AnyElement>;
// fn element_id(&self) -> Option<ElementId> {
// None
// }
// fn layout(
// &mut self,
// _: Option<Self::State>,
// cx: &mut WindowContext,
// ) -> (LayoutId, Self::State) {
// let render = self.take().unwrap();
// let mut element = (render)(view_state, cx).into_any();
// let layout_id = element.layout(view_state, cx);
// (layout_id, Some(element))
// }
// fn paint(
// self,
// _bounds: Bounds<Pixels>,
// rendered_element: &mut Self::State,
// cx: &mut WindowContext,
// ) {
// rendered_element.take().unwrap().paint(view_state, cx);
// }
// }
// impl<V, E, F> RenderOnce for Option<F>
// where
// V: 'static,
// E: Element,
// F: FnOnce(&mut V, &mut WindowContext) -> E + 'static,
// {
// type Element = Self;
// fn render(self) -> Self::Element {
// self
// }
// }

View file

@ -1,10 +1,10 @@
use crate::{
point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext,
BorrowWindow, Bounds, CallbackHandle, ClickEvent, Component, ConstructorHandle, DispatchPhase,
Element, ElementId, FocusEvent, FocusHandle, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId,
MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentComponent, Pixels, Point,
Render, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task, View,
Visibility, WindowContext,
BorrowWindow, Bounds, CallbackHandle, ClickEvent, ConstructorHandle, DispatchPhase, Element,
ElementId, FocusEvent, FocusHandle, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId,
MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point,
Render, RenderOnce, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task,
View, Visibility, WindowContext,
};
use collections::HashMap;
use refineable::Refineable;
@ -28,7 +28,7 @@ pub struct GroupStyle {
pub style: StyleRefinement,
}
pub trait InteractiveComponent: Sized + Element {
pub trait InteractiveElement: Sized + Element {
fn interactivity(&mut self) -> &mut Interactivity;
fn group(mut self, group: impl Into<SharedString>) -> Self {
@ -319,7 +319,7 @@ pub trait InteractiveComponent: Sized + Element {
}
}
pub trait StatefulInteractiveComponent: InteractiveComponent {
pub trait StatefulInteractiveElement: InteractiveElement {
fn focusable(mut self) -> Focusable<Self> {
self.interactivity().focusable = true;
Focusable { element: self }
@ -421,7 +421,7 @@ pub trait StatefulInteractiveComponent: InteractiveComponent {
}
}
pub trait FocusableComponent: InteractiveComponent {
pub trait FocusableElement: InteractiveElement {
fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
where
Self: Sized,
@ -563,30 +563,26 @@ impl Styled for Div {
}
}
impl InteractiveComponent for Div {
impl InteractiveElement for Div {
fn interactivity(&mut self) -> &mut Interactivity {
&mut self.interactivity
}
}
impl ParentComponent for Div {
impl ParentElement for Div {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
&mut self.children
}
}
impl Element for Div {
type ElementState = DivState;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
type State = DivState;
fn layout(
&mut self,
element_state: Option<Self::ElementState>,
element_state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
) -> (LayoutId, Self::State) {
let mut child_layout_ids = SmallVec::new();
let mut interactivity = mem::take(&mut self.interactivity);
let (layout_id, interactive_state) = interactivity.layout(
@ -614,9 +610,9 @@ impl Element for Div {
}
fn paint(
&mut self,
self,
bounds: Bounds<Pixels>,
element_state: &mut Self::ElementState,
element_state: &mut Self::State,
cx: &mut WindowContext,
) {
let mut child_min = point(Pixels::MAX, Pixels::MAX);
@ -632,8 +628,7 @@ impl Element for Div {
(child_max - child_min).into()
};
let mut interactivity = mem::take(&mut self.interactivity);
interactivity.paint(
self.interactivity.paint(
bounds,
content_size,
&mut element_state.interactive_state,
@ -653,7 +648,7 @@ impl Element for Div {
cx.with_text_style(style.text_style().cloned(), |cx| {
cx.with_content_mask(style.overflow_mask(bounds), |cx| {
cx.with_element_offset(scroll_offset, |cx| {
for child in &mut self.children {
for child in self.children {
child.paint(cx);
}
})
@ -663,13 +658,18 @@ impl Element for Div {
})
},
);
self.interactivity = interactivity;
}
}
impl Component for Div {
fn render(self) -> AnyElement {
AnyElement::new(self)
impl RenderOnce for Div {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
fn render_once(self) -> Self::Element {
self
}
}
@ -741,7 +741,7 @@ impl Interactivity {
}
pub fn paint(
&mut self,
mut self,
bounds: Bounds<Pixels>,
content_size: Size<Pixels>,
element_state: &mut InteractiveElementState,
@ -1045,12 +1045,12 @@ impl Interactivity {
})
}
for (action_type, listener) in self.action_listeners.drain(..) {
for (action_type, listener) in self.action_listeners {
cx.on_action(action_type, listener)
}
if let Some(focus_handle) = element_state.focus_handle.as_ref() {
for listener in self.focus_listeners.drain(..) {
for listener in self.focus_listeners {
let focus_handle = focus_handle.clone();
cx.on_focus_changed(move |event, cx| listener(&focus_handle, event, cx));
}
@ -1232,18 +1232,18 @@ pub struct Focusable<E> {
element: E,
}
impl<E: InteractiveComponent> FocusableComponent for Focusable<E> {}
impl<E: InteractiveElement> FocusableElement for Focusable<E> {}
impl<E> InteractiveComponent for Focusable<E>
impl<E> InteractiveElement for Focusable<E>
where
E: InteractiveComponent,
E: InteractiveElement,
{
fn interactivity(&mut self) -> &mut Interactivity {
self.element.interactivity()
}
}
impl<E: StatefulInteractiveComponent> StatefulInteractiveComponent for Focusable<E> {}
impl<E: StatefulInteractiveElement> StatefulInteractiveElement for Focusable<E> {}
impl<E> Styled for Focusable<E>
where
@ -1258,42 +1258,39 @@ impl<E> Element for Focusable<E>
where
E: Element,
{
type ElementState = E::ElementState;
type State = E::State;
fn layout(
&mut self,
state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
self.element.layout(state, cx)
}
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
self.element.paint(bounds, state, cx)
}
}
impl<E> RenderOnce for Focusable<E>
where
E: Element,
{
type Element = E;
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn layout(
&mut self,
element_state: Option<Self::ElementState>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
self.element.layout(element_state, cx)
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
element_state: &mut Self::ElementState,
cx: &mut WindowContext,
) {
self.element.paint(bounds, element_state, cx);
fn render_once(self) -> Self::Element {
self.element
}
}
impl<E> Component for Focusable<E>
impl<E> ParentElement for Focusable<E>
where
E: 'static + Element,
{
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl<E> ParentComponent for Focusable<E>
where
E: ParentComponent,
E: ParentElement,
{
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
self.element.children_mut()
@ -1313,64 +1310,61 @@ where
}
}
impl<E> StatefulInteractiveComponent for Stateful<E>
impl<E> StatefulInteractiveElement for Stateful<E>
where
E: Element,
Self: InteractiveComponent,
Self: InteractiveElement,
{
}
impl<E> InteractiveComponent for Stateful<E>
impl<E> InteractiveElement for Stateful<E>
where
E: InteractiveComponent,
E: InteractiveElement,
{
fn interactivity(&mut self) -> &mut Interactivity {
self.element.interactivity()
}
}
impl<E: FocusableComponent> FocusableComponent for Stateful<E> {}
impl<E: FocusableElement> FocusableElement for Stateful<E> {}
impl<E> Element for Stateful<E>
where
E: Element,
{
type ElementState = E::ElementState;
type State = E::State;
fn layout(
&mut self,
state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
self.element.layout(state, cx)
}
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
self.element.paint(bounds, state, cx)
}
}
impl<E> RenderOnce for Stateful<E>
where
E: Element,
{
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn layout(
&mut self,
element_state: Option<Self::ElementState>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
self.element.layout(element_state, cx)
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
element_state: &mut Self::ElementState,
cx: &mut WindowContext,
) {
self.element.paint(bounds, element_state, cx)
fn render_once(self) -> Self::Element {
self
}
}
impl<E> Component for Stateful<E>
impl<E> ParentElement for Stateful<E>
where
E: 'static + Element,
{
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl<E> ParentComponent for Stateful<E>
where
E: ParentComponent,
E: ParentElement,
{
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
self.element.children_mut()

View file

@ -1,6 +1,6 @@
use crate::{
AnyElement, Bounds, Component, Element, InteractiveComponent, InteractiveElementState,
Interactivity, LayoutId, Pixels, SharedString, StyleRefinement, Styled, WindowContext,
Bounds, Element, InteractiveElement, InteractiveElementState, Interactivity, LayoutId, Pixels,
RenderOnce, SharedString, StyleRefinement, Styled, WindowContext,
};
use futures::FutureExt;
use util::ResultExt;
@ -31,33 +31,23 @@ impl Img {
}
}
impl Component for Img {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl Element for Img {
type ElementState = InteractiveElementState;
fn element_id(&self) -> Option<crate::ElementId> {
self.interactivity.element_id.clone()
}
type State = InteractiveElementState;
fn layout(
&mut self,
element_state: Option<Self::ElementState>,
element_state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
) -> (LayoutId, Self::State) {
self.interactivity.layout(element_state, cx, |style, cx| {
cx.request_layout(&style, None)
})
}
fn paint(
&mut self,
self,
bounds: Bounds<Pixels>,
element_state: &mut Self::ElementState,
element_state: &mut Self::State,
cx: &mut WindowContext,
) {
self.interactivity.paint(
@ -96,13 +86,25 @@ impl Element for Img {
}
}
impl RenderOnce for Img {
type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
self.interactivity.element_id.clone()
}
fn render_once(self) -> Self::Element {
self
}
}
impl Styled for Img {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.interactivity.base_style
}
}
impl InteractiveComponent for Img {
impl InteractiveElement for Img {
fn interactivity(&mut self) -> &mut Interactivity {
&mut self.interactivity
}

View file

@ -2,8 +2,8 @@ use smallvec::SmallVec;
use taffy::style::{Display, Position};
use crate::{
point, AnyElement, BorrowWindow, Bounds, Component, Element, LayoutId, ParentComponent, Pixels,
Point, Size, Style, WindowContext,
point, AnyElement, BorrowWindow, Bounds, Element, LayoutId, ParentElement, Pixels, Point,
RenderOnce, Size, Style, WindowContext,
};
pub struct OverlayState {
@ -51,30 +51,20 @@ impl Overlay {
}
}
impl ParentComponent for Overlay {
impl ParentElement for Overlay {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
&mut self.children
}
}
impl Component for Overlay {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl Element for Overlay {
type ElementState = OverlayState;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
type State = OverlayState;
fn layout(
&mut self,
_: Option<Self::ElementState>,
_: Option<Self::State>,
cx: &mut WindowContext,
) -> (crate::LayoutId, Self::ElementState) {
) -> (crate::LayoutId, Self::State) {
let child_layout_ids = self
.children
.iter_mut()
@ -91,9 +81,9 @@ impl Element for Overlay {
}
fn paint(
&mut self,
self,
bounds: crate::Bounds<crate::Pixels>,
element_state: &mut Self::ElementState,
element_state: &mut Self::State,
cx: &mut WindowContext,
) {
if element_state.child_layout_ids.is_empty() {
@ -154,13 +144,25 @@ impl Element for Overlay {
}
cx.with_element_offset(desired.origin - bounds.origin, |cx| {
for child in &mut self.children {
for child in self.children {
child.paint(cx);
}
})
}
}
impl RenderOnce for Overlay {
type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
fn render_once(self) -> Self::Element {
self
}
}
enum Axis {
Horizontal,
Vertical,

View file

@ -1,7 +1,6 @@
use crate::{
AnyElement, Bounds, Component, Element, ElementId, InteractiveComponent,
InteractiveElementState, Interactivity, LayoutId, Pixels, SharedString, StyleRefinement,
Styled, WindowContext,
Bounds, Element, ElementId, InteractiveElement, InteractiveElementState, Interactivity,
LayoutId, Pixels, RenderOnce, SharedString, StyleRefinement, Styled, WindowContext,
};
use util::ResultExt;
@ -24,35 +23,21 @@ impl Svg {
}
}
impl Component for Svg {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl Element for Svg {
type ElementState = InteractiveElementState;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
type State = InteractiveElementState;
fn layout(
&mut self,
element_state: Option<Self::ElementState>,
element_state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
) -> (LayoutId, Self::State) {
self.interactivity.layout(element_state, cx, |style, cx| {
cx.request_layout(&style, None)
})
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
element_state: &mut Self::ElementState,
cx: &mut WindowContext,
) where
fn paint(self, bounds: Bounds<Pixels>, element_state: &mut Self::State, cx: &mut WindowContext)
where
Self: Sized,
{
self.interactivity
@ -64,13 +49,25 @@ impl Element for Svg {
}
}
impl RenderOnce for Svg {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
fn render_once(self) -> Self::Element {
self
}
}
impl Styled for Svg {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.interactivity.base_style
}
}
impl InteractiveComponent for Svg {
impl InteractiveElement for Svg {
fn interactivity(&mut self) -> &mut Interactivity {
&mut self.interactivity
}

View file

@ -1,68 +1,163 @@
use crate::{
AnyElement, Bounds, Component, Element, ElementId, LayoutId, Pixels, SharedString, Size,
TextRun, WindowContext, WrappedLine,
Bounds, Element, ElementId, LayoutId, Pixels, RenderOnce, SharedString, Size, TextRun,
WindowContext, WrappedLine,
};
use anyhow::anyhow;
use parking_lot::{Mutex, MutexGuard};
use smallvec::SmallVec;
use std::{cell::Cell, rc::Rc, sync::Arc};
use util::ResultExt;
pub struct Text {
impl Element for &'static str {
type State = TextState;
fn layout(
&mut self,
_: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
let mut state = TextState::default();
let layout_id = state.layout(SharedString::from(*self), None, cx);
(layout_id, state)
}
fn paint(self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
state.paint(bounds, self, cx)
}
}
impl RenderOnce for &'static str {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
None
}
fn render_once(self) -> Self::Element {
self
}
}
impl Element for SharedString {
type State = TextState;
fn layout(
&mut self,
_: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
let mut state = TextState::default();
let layout_id = state.layout(self.clone(), None, cx);
(layout_id, state)
}
fn paint(self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
let text_str: &str = self.as_ref();
state.paint(bounds, text_str, cx)
}
}
impl RenderOnce for SharedString {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
None
}
fn render_once(self) -> Self::Element {
self
}
}
pub struct StyledText {
text: SharedString,
runs: Option<Vec<TextRun>>,
}
impl Text {
impl StyledText {
/// Renders text with runs of different styles.
///
/// Callers are responsible for setting the correct style for each run.
/// For text with a uniform style, you can usually avoid calling this constructor
/// and just pass text directly.
pub fn styled(text: SharedString, runs: Vec<TextRun>) -> Self {
Text {
pub fn new(text: SharedString, runs: Vec<TextRun>) -> Self {
StyledText {
text,
runs: Some(runs),
}
}
}
impl Component for Text {
fn render(self) -> AnyElement {
AnyElement::new(self)
impl Element for StyledText {
type State = TextState;
fn layout(
&mut self,
_: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
let mut state = TextState::default();
let layout_id = state.layout(self.text.clone(), self.runs.take(), cx);
(layout_id, state)
}
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
state.paint(bounds, &self.text, cx)
}
}
impl Element for Text {
type ElementState = TextState;
impl RenderOnce for StyledText {
type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
fn render_once(self) -> Self::Element {
self
}
}
#[derive(Default, Clone)]
pub struct TextState(Arc<Mutex<Option<TextStateInner>>>);
struct TextStateInner {
lines: SmallVec<[WrappedLine; 1]>,
line_height: Pixels,
wrap_width: Option<Pixels>,
size: Option<Size<Pixels>>,
}
impl TextState {
fn lock(&self) -> MutexGuard<Option<TextStateInner>> {
self.0.lock()
}
fn layout(
&mut self,
element_state: Option<Self::ElementState>,
text: SharedString,
runs: Option<Vec<TextRun>>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
let element_state = element_state.unwrap_or_default();
) -> LayoutId {
let text_system = cx.text_system().clone();
let text_style = cx.text_style();
let font_size = text_style.font_size.to_pixels(cx.rem_size());
let line_height = text_style
.line_height
.to_pixels(font_size.into(), cx.rem_size());
let text = self.text.clone();
let text = SharedString::from(text);
let rem_size = cx.rem_size();
let runs = if let Some(runs) = self.runs.take() {
let runs = if let Some(runs) = runs {
runs
} else {
vec![text_style.to_run(text.len())]
};
let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
let element_state = element_state.clone();
let element_state = self.clone();
move |known_dimensions, available_space| {
let wrap_width = known_dimensions.width.or(match available_space.width {
crate::AvailableSpace::Definite(x) => Some(x),
@ -113,19 +208,14 @@ impl Element for Text {
}
});
(layout_id, element_state)
layout_id
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
element_state: &mut Self::ElementState,
cx: &mut WindowContext,
) {
let element_state = element_state.lock();
fn paint(&mut self, bounds: Bounds<Pixels>, text: &str, cx: &mut WindowContext) {
let element_state = self.lock();
let element_state = element_state
.as_ref()
.ok_or_else(|| anyhow::anyhow!("measurement has not been performed on {}", &self.text))
.ok_or_else(|| anyhow!("measurement has not been performed on {}", text))
.unwrap();
let line_height = element_state.line_height;
@ -137,25 +227,9 @@ impl Element for Text {
}
}
#[derive(Default, Clone)]
pub struct TextState(Arc<Mutex<Option<TextStateInner>>>);
impl TextState {
fn lock(&self) -> MutexGuard<Option<TextStateInner>> {
self.0.lock()
}
}
struct TextStateInner {
lines: SmallVec<[WrappedLine; 1]>,
line_height: Pixels,
wrap_width: Option<Pixels>,
size: Option<Size<Pixels>>,
}
struct InteractiveText {
id: ElementId,
text: Text,
element_id: ElementId,
text: StyledText,
}
struct InteractiveTextState {
@ -164,21 +238,17 @@ struct InteractiveTextState {
}
impl Element for InteractiveText {
type ElementState = InteractiveTextState;
fn element_id(&self) -> Option<ElementId> {
Some(self.id.clone())
}
type State = InteractiveTextState;
fn layout(
&mut self,
element_state: Option<Self::ElementState>,
state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
) -> (LayoutId, Self::State) {
if let Some(InteractiveTextState {
text_state,
clicked_range_ixs,
}) = element_state
}) = state
{
let (layout_id, text_state) = self.text.layout(Some(text_state), cx);
let element_state = InteractiveTextState {
@ -196,44 +266,19 @@ impl Element for InteractiveText {
}
}
fn paint(
&mut self,
bounds: Bounds<Pixels>,
element_state: &mut Self::ElementState,
cx: &mut WindowContext,
) {
self.text.paint(bounds, &mut element_state.text_state, cx)
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
self.text.paint(bounds, &mut state.text_state, cx)
}
}
impl Component for SharedString {
fn render(self) -> AnyElement {
Text {
text: self,
runs: None,
}
.render()
}
}
impl RenderOnce for InteractiveText {
type Element = Self;
impl Component for &'static str {
fn render(self) -> AnyElement {
Text {
text: self.into(),
runs: None,
}
.render()
fn element_id(&self) -> Option<ElementId> {
Some(self.element_id.clone())
}
}
// TODO: Figure out how to pass `String` to `child` without this.
// This impl doesn't exist in the `gpui2` crate.
impl Component for String {
fn render(self) -> AnyElement {
Text {
text: self.into(),
runs: None,
}
.render()
fn render_once(self) -> Self::Element {
self
}
}

View file

@ -1,23 +1,23 @@
use crate::{
point, px, size, AnyElement, AvailableSpace, Bounds, Component, Element, ElementId,
InteractiveComponent, InteractiveElementState, Interactivity, LayoutId, Pixels, Point, Size,
point, px, size, AnyElement, AvailableSpace, Bounds, Element, ElementId, InteractiveElement,
InteractiveElementState, Interactivity, LayoutId, Pixels, Point, RenderOnce, Size,
StyleRefinement, Styled, WindowContext,
};
use smallvec::SmallVec;
use std::{cell::RefCell, cmp, mem, ops::Range, rc::Rc};
use std::{cell::RefCell, cmp, ops::Range, rc::Rc};
use taffy::style::Overflow;
/// uniform_list provides lazy rendering for a set of items that are of uniform height.
/// When rendered into a container with overflow-y: hidden and a fixed (or max) height,
/// uniform_list will only render the visibile subset of items.
pub fn uniform_list<I, C>(
pub fn uniform_list<I, R>(
id: I,
item_count: usize,
f: impl 'static + Fn(Range<usize>, &mut WindowContext) -> Vec<C>,
f: impl 'static + Fn(Range<usize>, &mut WindowContext) -> Vec<R>,
) -> UniformList
where
I: Into<ElementId>,
C: Component,
R: RenderOnce,
{
let id = id.into();
let mut style = StyleRefinement::default();
@ -31,7 +31,7 @@ where
render_items: Box::new(move |visible_range, cx| {
f(visible_range, cx)
.into_iter()
.map(|component| component.render())
.map(|component| component.render_into_any())
.collect()
}),
interactivity: Interactivity {
@ -96,27 +96,23 @@ pub struct UniformListState {
}
impl Element for UniformList {
type ElementState = UniformListState;
fn element_id(&self) -> Option<crate::ElementId> {
Some(self.id.clone())
}
type State = UniformListState;
fn layout(
&mut self,
element_state: Option<Self::ElementState>,
state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
) -> (LayoutId, Self::State) {
let max_items = self.item_count;
let rem_size = cx.rem_size();
let item_size = element_state
let item_size = state
.as_ref()
.map(|s| s.item_size)
.unwrap_or_else(|| self.measure_item(None, cx));
let (layout_id, interactive) =
self.interactivity
.layout(element_state.map(|s| s.interactive), cx, |style, cx| {
.layout(state.map(|s| s.interactive), cx, |style, cx| {
cx.request_measured_layout(
style,
rem_size,
@ -152,9 +148,9 @@ impl Element for UniformList {
}
fn paint(
&mut self,
self,
bounds: Bounds<crate::Pixels>,
element_state: &mut Self::ElementState,
element_state: &mut Self::State,
cx: &mut WindowContext,
) {
let style =
@ -175,14 +171,15 @@ impl Element for UniformList {
height: item_size.height * self.item_count,
};
let mut interactivity = mem::take(&mut self.interactivity);
let shared_scroll_offset = element_state
.interactive
.scroll_offset
.get_or_insert_with(Rc::default)
.clone();
interactivity.paint(
let item_height = self.measure_item(Some(padded_bounds.size.width), cx).height;
self.interactivity.paint(
bounds,
content_size,
&mut element_state.interactive,
@ -201,8 +198,6 @@ impl Element for UniformList {
style.paint(bounds, cx);
if self.item_count > 0 {
let item_height =
self.measure_item(Some(padded_bounds.size.width), cx).height;
if let Some(scroll_handle) = self.scroll_handle.clone() {
scroll_handle.0.borrow_mut().replace(ScrollHandleState {
item_height,
@ -224,9 +219,9 @@ impl Element for UniformList {
self.item_count,
);
let mut items = (self.render_items)(visible_range.clone(), cx);
let items = (self.render_items)(visible_range.clone(), cx);
cx.with_z_index(1, |cx| {
for (item, ix) in items.iter_mut().zip(visible_range) {
for (item, ix) in items.into_iter().zip(visible_range) {
let item_origin = padded_bounds.origin
+ point(px(0.), item_height * ix + scroll_offset.y);
let available_space = size(
@ -240,7 +235,18 @@ impl Element for UniformList {
})
},
);
self.interactivity = interactivity;
}
}
impl RenderOnce for UniformList {
type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
Some(self.id.clone())
}
fn render_once(self) -> Self::Element {
self
}
}
@ -273,14 +279,8 @@ impl UniformList {
}
}
impl InteractiveComponent for UniformList {
impl InteractiveElement for UniformList {
fn interactivity(&mut self) -> &mut crate::Interactivity {
&mut self.interactivity
}
}
impl Component for UniformList {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}

View file

@ -78,8 +78,6 @@ use std::{
};
use taffy::TaffyLayoutEngine;
type AnyBox = Box<dyn Any>;
pub trait Context {
type Result<T>;
@ -136,7 +134,7 @@ pub trait VisualContext: Context {
build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
) -> Self::Result<View<V>>
where
V: Render;
V: 'static + Render;
fn focus_view<V>(&mut self, view: &View<V>) -> Self::Result<()>
where

View file

@ -1,8 +1,9 @@
use crate::{
div, point, Div, FocusHandle, Keystroke, Modifiers, Pixels, Point, Render, ViewContext,
div, point, Div, Element, FocusHandle, Keystroke, Modifiers, Pixels, Point, Render, RenderOnce,
ViewContext,
};
use smallvec::SmallVec;
use std::{any::Any, fmt::Debug, ops::Deref, path::PathBuf};
use std::{any::Any, fmt::Debug, marker::PhantomData, ops::Deref, path::PathBuf};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct KeyDownEvent {
@ -59,6 +60,32 @@ pub struct ClickEvent {
pub up: MouseUpEvent,
}
pub struct Drag<S, R, V, E>
where
R: Fn(&mut V, &mut ViewContext<V>) -> E,
V: 'static,
E: RenderOnce,
{
pub state: S,
pub render_drag_handle: R,
view_element_types: PhantomData<(V, E)>,
}
impl<S, R, V, E> Drag<S, R, V, E>
where
R: Fn(&mut V, &mut ViewContext<V>) -> E,
V: 'static,
E: Element,
{
pub fn new(state: S, render_drag_handle: R) -> Self {
Drag {
state,
render_drag_handle,
view_element_types: Default::default(),
}
}
}
#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
pub enum MouseButton {
Left,
@ -259,8 +286,8 @@ pub struct FocusEvent {
#[cfg(test)]
mod test {
use crate::{
self as gpui, div, Component, Div, FocusHandle, InteractiveComponent, KeyBinding,
Keystroke, ParentComponent, Render, Stateful, TestAppContext, VisualContext,
self as gpui, div, Div, FocusHandle, InteractiveElement, KeyBinding, Keystroke,
ParentElement, Render, RenderOnce, Stateful, TestAppContext, VisualContext,
};
struct TestView {
@ -288,7 +315,7 @@ mod test {
div()
.key_context("nested")
.track_focus(&self.focus_handle)
.render(),
.render_once(),
),
)
}

View file

@ -1,4 +1,5 @@
pub use crate::{
BorrowAppContext, BorrowWindow, Component, Context, FocusableComponent, InteractiveComponent,
ParentComponent, Refineable, Render, StatefulInteractiveComponent, Styled, VisualContext,
BorrowAppContext, BorrowWindow, Component, Context, Element, FocusableElement,
InteractiveElement, ParentElement, Refineable, Render, RenderOnce, StatefulInteractiveElement,
Styled, VisualContext,
};

View file

@ -1,23 +1,17 @@
use crate::{
private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
BorrowWindow, Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, FocusHandle,
FocusableView, LayoutId, Model, Pixels, Point, Size, ViewContext, VisualContext, WeakModel,
private::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, BorrowWindow,
Bounds, Element, ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView, LayoutId,
Model, Pixels, Point, Render, RenderOnce, Size, ViewContext, VisualContext, WeakModel,
WindowContext,
};
use anyhow::{Context, Result};
use std::{
any::{Any, TypeId},
any::TypeId,
hash::{Hash, Hasher},
};
pub trait Render: 'static + Sized {
type Element: Element + 'static;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element;
}
pub struct View<V> {
pub(crate) model: Model<V>,
pub model: Model<V>,
}
impl<V> Sealed for View<V> {}
@ -65,15 +59,15 @@ impl<V: 'static> View<V> {
self.model.read(cx)
}
pub fn render_with<C>(&self, component: C) -> RenderViewWith<C, V>
where
C: 'static + Component,
{
RenderViewWith {
view: self.clone(),
component: Some(component),
}
}
// pub fn render_with<E>(&self, component: E) -> RenderViewWith<E, V>
// where
// E: 'static + Element,
// {
// RenderViewWith {
// view: self.clone(),
// element: Some(component),
// }
// }
pub fn focus_handle(&self, cx: &AppContext) -> FocusHandle
where
@ -83,6 +77,26 @@ impl<V: 'static> View<V> {
}
}
impl<V: Render> Element for View<V> {
type State = Option<AnyElement>;
fn layout(
&mut self,
_state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
self.update(cx, |view, cx| {
let mut element = view.render(cx).into_any();
let layout_id = element.layout(cx);
(layout_id, Some(element))
})
}
fn paint(self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
element.take().unwrap().paint(cx);
}
}
impl<V> Clone for View<V> {
fn clone(&self) -> Self {
Self {
@ -105,12 +119,6 @@ impl<V> PartialEq for View<V> {
impl<V> Eq for View<V> {}
impl<V: Render> Component for View<V> {
fn render(self) -> AnyElement {
AnyElement::new(AnyView::from(self))
}
}
pub struct WeakView<V> {
pub(crate) model: WeakModel<V>,
}
@ -163,8 +171,8 @@ impl<V> Eq for WeakView<V> {}
#[derive(Clone, Debug)]
pub struct AnyView {
model: AnyModel,
layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
paint: fn(&AnyView, AnyElement, &mut WindowContext),
}
impl AnyView {
@ -202,21 +210,15 @@ impl AnyView {
cx: &mut WindowContext,
) {
cx.with_absolute_element_offset(origin, |cx| {
let (layout_id, mut rendered_element) = (self.layout)(self, cx);
let (layout_id, rendered_element) = (self.layout)(self, cx);
cx.window
.layout_engine
.compute_layout(layout_id, available_space);
(self.paint)(self, &mut rendered_element, cx);
(self.paint)(self, rendered_element, cx);
})
}
}
impl Component for AnyView {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl<V: Render> From<View<V>> for AnyView {
fn from(value: View<V>) -> Self {
AnyView {
@ -228,34 +230,50 @@ impl<V: Render> From<View<V>> for AnyView {
}
impl Element for AnyView {
type ElementState = Box<dyn Any>;
type State = Option<AnyElement>;
fn layout(
&mut self,
_state: Option<Self::State>,
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
let (layout_id, state) = (self.layout)(self, cx);
(layout_id, Some(state))
}
fn paint(self, _: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
(self.paint)(&self, state.take().unwrap(), cx)
}
}
impl<V: 'static + Render> RenderOnce for View<V> {
type Element = View<V>;
fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into())
}
fn layout(
&mut self,
_element_state: Option<Self::ElementState>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
(self.layout)(self, cx)
fn render_once(self) -> Self::Element {
self
}
}
impl RenderOnce for AnyView {
type Element = Self;
fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into())
}
fn paint(
&mut self,
_bounds: Bounds<Pixels>,
rendered_element: &mut Self::ElementState,
cx: &mut WindowContext,
) {
(self.paint)(self, rendered_element, cx)
fn render_once(self) -> Self::Element {
self
}
}
pub struct AnyWeakView {
model: AnyWeakModel,
layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
paint: fn(&AnyView, &mut AnyBox, &mut WindowContext),
layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
paint: fn(&AnyView, AnyElement, &mut WindowContext),
}
impl AnyWeakView {
@ -269,7 +287,7 @@ impl AnyWeakView {
}
}
impl<V: Render> From<WeakView<V>> for AnyWeakView {
impl<V: 'static + Render> From<WeakView<V>> for AnyWeakView {
fn from(view: WeakView<V>) -> Self {
Self {
model: view.model.into(),
@ -291,77 +309,73 @@ where
}
}
pub struct RenderViewWith<C, V> {
view: View<V>,
component: Option<C>,
}
// pub struct RenderViewWith<E, V> {
// view: View<V>,
// element: Option<E>,
// }
impl<C, V> Component for RenderViewWith<C, V>
where
V: 'static + Render,
C: 'static + Component,
{
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
// impl<E> Element for RenderViewWith<E>
// where
// E: 'static + Element,
// {
// type State = Option<AnyElement>;
impl<C, V> Element for RenderViewWith<C, V>
where
V: 'static + Render,
C: 'static + Component,
{
type ElementState = AnyElement;
// fn layout(
// &mut self,
// _: Option<Self::State>,
// cx: &mut WindowContext,
// ) -> (LayoutId, Self::State) {
// self.view.update(cx, |view, cx| {
// let mut element = self.element.take().unwrap().into_any();
// let layout_id = element.layout(view, cx);
// (layout_id, Some(element))
// })
// }
fn element_id(&self) -> Option<ElementId> {
Some(self.view.entity_id().into())
}
// fn paint(self, _: Bounds<Pixels>, element: &mut Self::ElementState, cx: &mut WindowContext) {
// element.paint(cx)
// }
// }
fn layout(
&mut self,
_: Option<Self::ElementState>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
let mut element = self.component.take().unwrap().render();
let layout_id = element.layout(cx);
(layout_id, element)
}
// impl<E> RenderOnce for RenderViewWith<E>
// where
// E: 'static + Element<V>,
// ParentV: 'static,
// {
// type Element = Self;
fn paint(
&mut self,
_: Bounds<Pixels>,
element: &mut Self::ElementState,
cx: &mut WindowContext,
) {
element.paint(cx)
}
}
// fn element_id(&self) -> Option<ElementId> {
// self.element.as_ref().unwrap().element_id()
// }
// fn render_once(self) -> Self::Element {
// self
// }
// }
mod any_view {
use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
use std::any::Any;
use crate::{AnyElement, AnyView, BorrowWindow, Element, LayoutId, Render, WindowContext};
pub(crate) fn layout<V: Render>(
pub(crate) fn layout<V: 'static + Render>(
view: &AnyView,
cx: &mut WindowContext,
) -> (LayoutId, Box<dyn Any>) {
) -> (LayoutId, AnyElement) {
cx.with_element_id(Some(view.model.entity_id), |cx| {
let view = view.clone().downcast::<V>().unwrap();
view.update(cx, |view, cx| {
let mut element = AnyElement::new(view.render(cx));
let mut element = view.render(cx).into_any();
let layout_id = element.layout(cx);
(layout_id, Box::new(element) as Box<dyn Any>)
(layout_id, element)
})
})
}
pub(crate) fn paint<V: Render>(
pub(crate) fn paint<V: 'static + Render>(
view: &AnyView,
element: &mut Box<dyn Any>,
element: AnyElement,
cx: &mut WindowContext,
) {
cx.with_element_id(Some(view.model.entity_id), |cx| {
let element = element.downcast_mut::<AnyElement>().unwrap();
element.paint(cx);
})
}

View file

@ -1,5 +1,5 @@
use crate::{
key_dispatch::DispatchActionListener, px, size, Action, AnyBox, AnyDrag, AnyView, AppContext,
key_dispatch::DispatchActionListener, px, size, Action, AnyDrag, AnyView, AppContext,
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, CallbackHandle, ConstructorHandle,
Context, Corners, CursorStyle, DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges,
Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FocusEvent, FontId,
@ -187,7 +187,7 @@ impl Drop for FocusHandle {
/// FocusableView allows users of your view to easily
/// focus it (using cx.focus_view(view))
pub trait FocusableView: Render {
pub trait FocusableView: 'static + Render {
fn focus_handle(&self, cx: &AppContext) -> FocusHandle;
}
@ -232,7 +232,7 @@ pub struct Window {
// #[derive(Default)]
pub(crate) struct Frame {
pub(crate) element_states: HashMap<GlobalElementId, AnyBox>,
pub(crate) element_states: HashMap<GlobalElementId, Box<dyn Any>>,
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyMouseListener)>>,
pub(crate) dispatch_tree: DispatchTree,
pub(crate) focus_listeners: Vec<AnyFocusListener>,
@ -1600,7 +1600,7 @@ impl VisualContext for WindowContext<'_> {
build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
) -> Self::Result<View<V>>
where
V: Render,
V: 'static + Render,
{
let slot = self.app.entities.reserve();
let view = View {
@ -2372,7 +2372,7 @@ impl<V: 'static> VisualContext for ViewContext<'_, V> {
build_view: impl FnOnce(&mut ViewContext<'_, W>) -> W,
) -> Self::Result<View<W>>
where
W: Render,
W: 'static + Render,
{
self.window_cx.replace_root_view(build_view)
}