Merge branch 'main' into callback-handles
This commit is contained in:
commit
d0dd44faad
117 changed files with 3170 additions and 2027 deletions
|
@ -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,
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue