WIP
This commit is contained in:
parent
bc4f8fbf4e
commit
0128079de0
5 changed files with 61 additions and 61 deletions
|
@ -15,7 +15,7 @@ pub use test_context::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AppMetadata, AssetSource,
|
current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AppMetadata, AssetSource,
|
||||||
ClipboardItem, Context, DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId,
|
ClipboardItem, Context, DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId,
|
||||||
KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly, Pixels, Platform, Point,
|
KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly, Pixels, Platform, Point, Render,
|
||||||
SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement,
|
SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement,
|
||||||
TextSystem, View, Window, WindowContext, WindowHandle, WindowId,
|
TextSystem, View, Window, WindowContext, WindowHandle, WindowId,
|
||||||
};
|
};
|
||||||
|
@ -815,7 +815,7 @@ impl MainThread<AppContext> {
|
||||||
/// Opens a new window with the given option and the root view returned by the given function.
|
/// 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
|
/// The function is invoked with a `WindowContext`, which can be used to interact with window-specific
|
||||||
/// functionality.
|
/// functionality.
|
||||||
pub fn open_window<V: 'static>(
|
pub fn open_window<V: Render>(
|
||||||
&mut self,
|
&mut self,
|
||||||
options: crate::WindowOptions,
|
options: crate::WindowOptions,
|
||||||
build_root_view: impl FnOnce(&mut WindowContext) -> View<V> + Send + 'static,
|
build_root_view: impl FnOnce(&mut WindowContext) -> View<V> + Send + 'static,
|
||||||
|
@ -898,6 +898,7 @@ impl<G: 'static> DerefMut for GlobalLease<G> {
|
||||||
/// Contains state associated with an active drag operation, started by dragging an element
|
/// Contains state associated with an active drag operation, started by dragging an element
|
||||||
/// within the window or by dragging into the app from the underlying platform.
|
/// within the window or by dragging into the app from the underlying platform.
|
||||||
pub(crate) struct AnyDrag {
|
pub(crate) struct AnyDrag {
|
||||||
|
pub render: Box<dyn FnOnce(&mut WindowContext) -> AnyElement<()>>,
|
||||||
pub drag_handle_view: Option<AnyView>,
|
pub drag_handle_view: Option<AnyView>,
|
||||||
pub cursor_offset: Point<Pixels>,
|
pub cursor_offset: Point<Pixels>,
|
||||||
pub state: AnyBox,
|
pub state: AnyBox,
|
||||||
|
|
|
@ -4,7 +4,7 @@ pub(crate) use smallvec::SmallVec;
|
||||||
use std::{any::Any, mem};
|
use std::{any::Any, mem};
|
||||||
|
|
||||||
pub trait Element<V: 'static> {
|
pub trait Element<V: 'static> {
|
||||||
type ElementState: 'static;
|
type ElementState: 'static + Send;
|
||||||
|
|
||||||
fn id(&self) -> Option<ElementId>;
|
fn id(&self) -> Option<ElementId>;
|
||||||
|
|
||||||
|
|
|
@ -333,12 +333,19 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
||||||
Some(Box::new(move |view_state, cursor_offset, cx| {
|
Some(Box::new(move |view_state, cursor_offset, cx| {
|
||||||
let drag = listener(view_state, cx);
|
let drag = listener(view_state, cx);
|
||||||
let drag_handle_view = Some(
|
let drag_handle_view = Some(
|
||||||
View::for_handle(cx.model().upgrade().unwrap(), move |view_state, cx| {
|
cx.build_view(|cx| DragView {
|
||||||
(drag.render_drag_handle)(view_state, cx)
|
model: cx.model().upgrade().unwrap(),
|
||||||
|
drag,
|
||||||
})
|
})
|
||||||
.into_any(),
|
.into_any(),
|
||||||
);
|
);
|
||||||
AnyDrag {
|
AnyDrag {
|
||||||
|
render: {
|
||||||
|
let view = cx.view();
|
||||||
|
Box::new(move |cx| {
|
||||||
|
view.update(cx, |view, cx| drag.render_drag_handle(view, cx))
|
||||||
|
})
|
||||||
|
},
|
||||||
drag_handle_view,
|
drag_handle_view,
|
||||||
cursor_offset,
|
cursor_offset,
|
||||||
state: Box::new(drag.state),
|
state: Box::new(drag.state),
|
||||||
|
@ -888,6 +895,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// impl<S, R, V, E> Render for Drag<S, R, V, E> {
|
||||||
|
// // fn render(&mut self, cx: ViewContext<Self>) ->
|
||||||
|
// }
|
||||||
|
|
||||||
#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
|
#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
|
||||||
pub enum MouseButton {
|
pub enum MouseButton {
|
||||||
Left,
|
Left,
|
||||||
|
|
|
@ -3,48 +3,31 @@ use crate::{
|
||||||
EntityId, LayoutId, Model, Pixels, Size, ViewContext, VisualContext, WeakModel, WindowContext,
|
EntityId, LayoutId, Model, Pixels, Size, ViewContext, VisualContext, WeakModel, WindowContext,
|
||||||
};
|
};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use parking_lot::Mutex;
|
use std::{marker::PhantomData, sync::Arc};
|
||||||
use std::{
|
|
||||||
marker::PhantomData,
|
pub trait Render: 'static + Sized {
|
||||||
sync::{Arc, Weak},
|
type Element: Element<Self> + 'static + Send;
|
||||||
};
|
|
||||||
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element;
|
||||||
|
}
|
||||||
|
|
||||||
pub struct View<V> {
|
pub struct View<V> {
|
||||||
pub(crate) state: Model<V>,
|
pub(crate) model: Model<V>,
|
||||||
render: Arc<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> View<V> {
|
impl<V: Render> View<V> {
|
||||||
pub fn for_handle<E>(
|
|
||||||
state: Model<V>,
|
|
||||||
render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
|
|
||||||
) -> View<V>
|
|
||||||
where
|
|
||||||
E: Component<V>,
|
|
||||||
{
|
|
||||||
View {
|
|
||||||
state,
|
|
||||||
render: Arc::new(Mutex::new(
|
|
||||||
move |state: &mut V, cx: &mut ViewContext<'_, '_, V>| render(state, cx).render(),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V: 'static> View<V> {
|
|
||||||
pub fn into_any(self) -> AnyView {
|
pub fn into_any(self) -> AnyView {
|
||||||
AnyView(Arc::new(self))
|
AnyView(Arc::new(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn downgrade(&self) -> WeakView<V> {
|
|
||||||
WeakView {
|
|
||||||
state: self.state.downgrade(),
|
|
||||||
render: Arc::downgrade(&self.render),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> View<V> {
|
impl<V: 'static> View<V> {
|
||||||
|
pub fn downgrade(&self) -> WeakView<V> {
|
||||||
|
WeakView {
|
||||||
|
model: self.model.downgrade(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update<C, R>(
|
pub fn update<C, R>(
|
||||||
&self,
|
&self,
|
||||||
cx: &mut C,
|
cx: &mut C,
|
||||||
|
@ -60,13 +43,12 @@ impl<V: 'static> View<V> {
|
||||||
impl<V> Clone for View<V> {
|
impl<V> Clone for View<V> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: self.state.clone(),
|
model: self.model.clone(),
|
||||||
render: self.render.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static, ParentViewState: 'static> Component<ParentViewState> for View<V> {
|
impl<V: Render, ParentViewState: 'static> Component<ParentViewState> for View<V> {
|
||||||
fn render(self) -> AnyElement<ParentViewState> {
|
fn render(self) -> AnyElement<ParentViewState> {
|
||||||
AnyElement::new(EraseViewState {
|
AnyElement::new(EraseViewState {
|
||||||
view: self,
|
view: self,
|
||||||
|
@ -75,11 +57,14 @@ impl<V: 'static, ParentViewState: 'static> Component<ParentViewState> for View<V
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> Element<()> for View<V> {
|
impl<V> Element<()> for View<V>
|
||||||
|
where
|
||||||
|
V: Render,
|
||||||
|
{
|
||||||
type ElementState = AnyElement<V>;
|
type ElementState = AnyElement<V>;
|
||||||
|
|
||||||
fn id(&self) -> Option<crate::ElementId> {
|
fn id(&self) -> Option<crate::ElementId> {
|
||||||
Some(ElementId::View(self.state.entity_id))
|
Some(ElementId::View(self.model.entity_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize(
|
fn initialize(
|
||||||
|
@ -89,7 +74,7 @@ impl<V: 'static> Element<()> for View<V> {
|
||||||
cx: &mut ViewContext<()>,
|
cx: &mut ViewContext<()>,
|
||||||
) -> Self::ElementState {
|
) -> Self::ElementState {
|
||||||
self.update(cx, |state, cx| {
|
self.update(cx, |state, cx| {
|
||||||
let mut any_element = (self.render.lock())(state, cx);
|
let mut any_element = AnyElement::new(state.render(cx));
|
||||||
any_element.initialize(state, cx);
|
any_element.initialize(state, cx);
|
||||||
any_element
|
any_element
|
||||||
})
|
})
|
||||||
|
@ -116,15 +101,13 @@ impl<V: 'static> Element<()> for View<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WeakView<V> {
|
pub struct WeakView<V> {
|
||||||
pub(crate) state: WeakModel<V>,
|
pub(crate) model: WeakModel<V>,
|
||||||
render: Weak<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> WeakView<V> {
|
impl<V: 'static> WeakView<V> {
|
||||||
pub fn upgrade(&self) -> Option<View<V>> {
|
pub fn upgrade(&self) -> Option<View<V>> {
|
||||||
let state = self.state.upgrade()?;
|
let model = self.model.upgrade()?;
|
||||||
let render = self.render.upgrade()?;
|
Some(View { model })
|
||||||
Some(View { state, render })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update<R>(
|
pub fn update<R>(
|
||||||
|
@ -140,8 +123,7 @@ impl<V: 'static> WeakView<V> {
|
||||||
impl<V> Clone for WeakView<V> {
|
impl<V> Clone for WeakView<V> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: self.state.clone(),
|
model: self.model.clone(),
|
||||||
render: self.render.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,13 +135,13 @@ struct EraseViewState<V, ParentV> {
|
||||||
|
|
||||||
unsafe impl<V, ParentV> Send for EraseViewState<V, ParentV> {}
|
unsafe impl<V, ParentV> Send for EraseViewState<V, ParentV> {}
|
||||||
|
|
||||||
impl<V: 'static, ParentV: 'static> Component<ParentV> for EraseViewState<V, ParentV> {
|
impl<V: Render, ParentV: 'static> Component<ParentV> for EraseViewState<V, ParentV> {
|
||||||
fn render(self) -> AnyElement<ParentV> {
|
fn render(self) -> AnyElement<ParentV> {
|
||||||
AnyElement::new(self)
|
AnyElement::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static, ParentV: 'static> Element<ParentV> for EraseViewState<V, ParentV> {
|
impl<V: Render, ParentV: 'static> Element<ParentV> for EraseViewState<V, ParentV> {
|
||||||
type ElementState = AnyBox;
|
type ElementState = AnyBox;
|
||||||
|
|
||||||
fn id(&self) -> Option<crate::ElementId> {
|
fn id(&self) -> Option<crate::ElementId> {
|
||||||
|
@ -202,17 +184,20 @@ trait ViewObject: Send + Sync {
|
||||||
fn paint(&self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
|
fn paint(&self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> ViewObject for View<V> {
|
impl<V> ViewObject for View<V>
|
||||||
|
where
|
||||||
|
V: Render,
|
||||||
|
{
|
||||||
fn entity_id(&self) -> EntityId {
|
fn entity_id(&self) -> EntityId {
|
||||||
self.state.entity_id
|
self.model.entity_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
|
fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
|
||||||
cx.with_element_id(self.entity_id(), |_global_id, cx| {
|
cx.with_element_id(self.entity_id(), |_global_id, cx| {
|
||||||
self.update(cx, |state, cx| {
|
self.update(cx, |state, cx| {
|
||||||
let mut any_element = Box::new((self.render.lock())(state, cx));
|
let mut any_element = Box::new(AnyElement::new(state.render(cx)));
|
||||||
any_element.initialize(state, cx);
|
any_element.initialize(state, cx);
|
||||||
any_element as AnyBox
|
any_element
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -900,6 +900,9 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
if let Some(drag_handle_view) = &mut active_drag.drag_handle_view {
|
if let Some(drag_handle_view) = &mut active_drag.drag_handle_view {
|
||||||
drag_handle_view.draw(available_space, cx);
|
drag_handle_view.draw(available_space, cx);
|
||||||
}
|
}
|
||||||
|
if let Some(render) = &mut active_drag.render {
|
||||||
|
(render)()
|
||||||
|
}
|
||||||
cx.active_drag = Some(active_drag);
|
cx.active_drag = Some(active_drag);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1300,7 +1303,7 @@ impl VisualContext for WindowContext<'_, '_> {
|
||||||
view: &View<T>,
|
view: &View<T>,
|
||||||
update: impl FnOnce(&mut T, &mut Self::ViewContext<'_, '_, T>) -> R,
|
update: impl FnOnce(&mut T, &mut Self::ViewContext<'_, '_, T>) -> R,
|
||||||
) -> Self::Result<R> {
|
) -> Self::Result<R> {
|
||||||
let mut lease = self.app.entities.lease(&view.state);
|
let mut lease = self.app.entities.lease(&view.model);
|
||||||
let mut cx = ViewContext::mutable(&mut *self.app, &mut *self.window, view.downgrade());
|
let mut cx = ViewContext::mutable(&mut *self.app, &mut *self.window, view.downgrade());
|
||||||
let result = update(&mut *lease, &mut cx);
|
let result = update(&mut *lease, &mut cx);
|
||||||
cx.app.entities.end_lease(lease);
|
cx.app.entities.end_lease(lease);
|
||||||
|
@ -1556,7 +1559,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn model(&self) -> WeakModel<V> {
|
pub fn model(&self) -> WeakModel<V> {
|
||||||
self.view.state.clone()
|
self.view.model.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
|
pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||||
|
@ -1635,7 +1638,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
|
||||||
) -> Subscription {
|
) -> Subscription {
|
||||||
let window_handle = self.window.handle;
|
let window_handle = self.window.handle;
|
||||||
self.app.release_listeners.insert(
|
self.app.release_listeners.insert(
|
||||||
self.view.state.entity_id,
|
self.view.model.entity_id,
|
||||||
Box::new(move |this, cx| {
|
Box::new(move |this, cx| {
|
||||||
let this = this.downcast_mut().expect("invalid entity type");
|
let this = this.downcast_mut().expect("invalid entity type");
|
||||||
// todo!("are we okay with silently swallowing the error?")
|
// todo!("are we okay with silently swallowing the error?")
|
||||||
|
@ -1668,7 +1671,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
|
||||||
pub fn notify(&mut self) {
|
pub fn notify(&mut self) {
|
||||||
self.window_cx.notify();
|
self.window_cx.notify();
|
||||||
self.window_cx.app.push_effect(Effect::Notify {
|
self.window_cx.app.push_effect(Effect::Notify {
|
||||||
emitter: self.view.state.entity_id,
|
emitter: self.view.model.entity_id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1848,7 +1851,7 @@ where
|
||||||
V::Event: Any + Send,
|
V::Event: Any + Send,
|
||||||
{
|
{
|
||||||
pub fn emit(&mut self, event: V::Event) {
|
pub fn emit(&mut self, event: V::Event) {
|
||||||
let emitter = self.view.state.entity_id;
|
let emitter = self.view.model.entity_id;
|
||||||
self.app.push_effect(Effect::Emit {
|
self.app.push_effect(Effect::Emit {
|
||||||
emitter,
|
emitter,
|
||||||
event: Box::new(event),
|
event: Box::new(event),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue