Checkpoint
This commit is contained in:
parent
0fb7364235
commit
eebbc807e5
4 changed files with 102 additions and 6 deletions
|
@ -68,6 +68,7 @@ impl App {
|
||||||
windows: SlotMap::with_key(),
|
windows: SlotMap::with_key(),
|
||||||
pending_effects: Default::default(),
|
pending_effects: Default::default(),
|
||||||
observers: Default::default(),
|
observers: Default::default(),
|
||||||
|
event_handlers: Default::default(),
|
||||||
layout_id_buffer: Default::default(),
|
layout_id_buffer: Default::default(),
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
|
@ -88,6 +89,8 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Handlers = SmallVec<[Arc<dyn Fn(&mut AppContext) -> bool + Send + Sync + 'static>; 2]>;
|
type Handlers = SmallVec<[Arc<dyn Fn(&mut AppContext) -> bool + Send + Sync + 'static>; 2]>;
|
||||||
|
type EventHandlers =
|
||||||
|
SmallVec<[Arc<dyn Fn(&dyn Any, &mut AppContext) -> bool + Send + Sync + 'static>; 2]>;
|
||||||
type FrameCallback = Box<dyn FnOnce(&mut WindowContext) + Send>;
|
type FrameCallback = Box<dyn FnOnce(&mut WindowContext) + Send>;
|
||||||
|
|
||||||
pub struct AppContext {
|
pub struct AppContext {
|
||||||
|
@ -107,6 +110,7 @@ pub struct AppContext {
|
||||||
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
|
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
|
||||||
pub(crate) pending_effects: VecDeque<Effect>,
|
pub(crate) pending_effects: VecDeque<Effect>,
|
||||||
pub(crate) observers: HashMap<EntityId, Handlers>,
|
pub(crate) observers: HashMap<EntityId, Handlers>,
|
||||||
|
pub(crate) event_handlers: HashMap<EntityId, EventHandlers>,
|
||||||
pub(crate) layout_id_buffer: Vec<LayoutId>, // We recycle this memory across layout requests.
|
pub(crate) layout_id_buffer: Vec<LayoutId>, // We recycle this memory across layout requests.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +153,7 @@ impl AppContext {
|
||||||
while let Some(effect) = self.pending_effects.pop_front() {
|
while let Some(effect) = self.pending_effects.pop_front() {
|
||||||
match effect {
|
match effect {
|
||||||
Effect::Notify(entity_id) => self.apply_notify_effect(entity_id),
|
Effect::Notify(entity_id) => self.apply_notify_effect(entity_id),
|
||||||
|
Effect::Emit { entity_id, event } => self.apply_emit_effect(entity_id, event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +185,16 @@ impl AppContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn apply_emit_effect(&mut self, updated_entity: EntityId, event: Box<dyn Any>) {
|
||||||
|
if let Some(mut handlers) = self.event_handlers.remove(&updated_entity) {
|
||||||
|
handlers.retain(|handler| handler(&event, self));
|
||||||
|
if let Some(new_handlers) = self.event_handlers.remove(&updated_entity) {
|
||||||
|
handlers.extend(new_handlers);
|
||||||
|
}
|
||||||
|
self.event_handlers.insert(updated_entity, handlers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_async(&self) -> AsyncAppContext {
|
pub fn to_async(&self) -> AsyncAppContext {
|
||||||
AsyncAppContext(unsafe { mem::transmute(self.this.clone()) })
|
AsyncAppContext(unsafe { mem::transmute(self.this.clone()) })
|
||||||
}
|
}
|
||||||
|
@ -367,6 +382,10 @@ impl MainThread<AppContext> {
|
||||||
|
|
||||||
pub(crate) enum Effect {
|
pub(crate) enum Effect {
|
||||||
Notify(EntityId),
|
Notify(EntityId),
|
||||||
|
Emit {
|
||||||
|
entity_id: EntityId,
|
||||||
|
event: Box<dyn Any + Send + Sync + 'static>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{AppContext, Context, Effect, EntityId, Handle, Reference, WeakHandle};
|
use crate::{AppContext, Context, Effect, EntityId, EventEmitter, Handle, Reference, WeakHandle};
|
||||||
use std::{marker::PhantomData, sync::Arc};
|
use std::{marker::PhantomData, sync::Arc};
|
||||||
|
|
||||||
pub struct ModelContext<'a, T> {
|
pub struct ModelContext<'a, T> {
|
||||||
|
@ -59,6 +59,31 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
|
||||||
|
&mut self,
|
||||||
|
handle: &Handle<E>,
|
||||||
|
on_event: impl Fn(&mut T, Handle<E>, &E::Event, &mut ModelContext<'_, T>)
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
) {
|
||||||
|
let this = self.handle();
|
||||||
|
let handle = handle.downgrade();
|
||||||
|
self.app
|
||||||
|
.event_handlers
|
||||||
|
.entry(handle.id)
|
||||||
|
.or_default()
|
||||||
|
.push(Arc::new(move |event, cx| {
|
||||||
|
let event = event.downcast_ref().expect("invalid event type");
|
||||||
|
if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
|
||||||
|
this.update(cx, |this, cx| on_event(this, handle, event, cx));
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn notify(&mut self) {
|
pub fn notify(&mut self) {
|
||||||
self.app
|
self.app
|
||||||
.pending_effects
|
.pending_effects
|
||||||
|
@ -66,6 +91,15 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T: EventEmitter + Send + Sync + 'static> ModelContext<'a, T> {
|
||||||
|
pub fn emit(&mut self, event: T::Event) {
|
||||||
|
self.app.pending_effects.push_back(Effect::Emit {
|
||||||
|
entity_id: self.entity_id,
|
||||||
|
event: Box::new(event),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, T: 'static> Context for ModelContext<'a, T> {
|
impl<'a, T: 'static> Context for ModelContext<'a, T> {
|
||||||
type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
|
type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
|
||||||
type Result<U> = U;
|
type Result<U> = U;
|
||||||
|
|
|
@ -152,6 +152,10 @@ pub trait BorrowAppContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait EventEmitter {
|
||||||
|
type Event: Any + Send + Sync + 'static;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Flatten<T> {
|
pub trait Flatten<T> {
|
||||||
fn flatten(self) -> Result<T>;
|
fn flatten(self) -> Result<T>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
px, size, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace, BorrowAppContext,
|
px, size, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace, BorrowAppContext,
|
||||||
Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, Edges, Effect, Element, EntityId,
|
Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, Edges, Effect, Element, EntityId,
|
||||||
Event, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, MainThread,
|
Event, EventEmitter, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData, IsZero,
|
||||||
MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, PlatformAtlas, PlatformWindow,
|
LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels,
|
||||||
Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams,
|
PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams,
|
||||||
RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style,
|
RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
|
||||||
TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions,
|
Style, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions,
|
||||||
SUBPIXEL_VARIANTS,
|
SUBPIXEL_VARIANTS,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -930,6 +930,35 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
|
||||||
|
&mut self,
|
||||||
|
handle: &Handle<E>,
|
||||||
|
on_event: impl Fn(&mut S, Handle<E>, &E::Event, &mut ViewContext<'_, '_, S>)
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
) {
|
||||||
|
let this = self.handle();
|
||||||
|
let handle = handle.downgrade();
|
||||||
|
let window_handle = self.window.handle;
|
||||||
|
self.app
|
||||||
|
.event_handlers
|
||||||
|
.entry(handle.id)
|
||||||
|
.or_default()
|
||||||
|
.push(Arc::new(move |event, cx| {
|
||||||
|
cx.update_window(window_handle.id, |cx| {
|
||||||
|
if let Some(handle) = handle.upgrade(cx) {
|
||||||
|
let event = event.downcast_ref().expect("invalid event type");
|
||||||
|
this.update(cx, |this, cx| on_event(this, handle, event, cx))
|
||||||
|
.is_ok()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or(false)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn notify(&mut self) {
|
pub fn notify(&mut self) {
|
||||||
self.window_cx.notify();
|
self.window_cx.notify();
|
||||||
self.window_cx
|
self.window_cx
|
||||||
|
@ -983,6 +1012,16 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, 'w, S: EventEmitter + Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||||
|
pub fn emit(&mut self, event: S::Event) {
|
||||||
|
let entity_id = self.entity_id;
|
||||||
|
self.app.pending_effects.push_back(Effect::Emit {
|
||||||
|
entity_id,
|
||||||
|
event: Box::new(event),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'w, S> Context for ViewContext<'a, 'w, S> {
|
impl<'a, 'w, S> Context for ViewContext<'a, 'w, S> {
|
||||||
type EntityContext<'b, 'c, U: 'static + Send + Sync> = ViewContext<'b, 'c, U>;
|
type EntityContext<'b, 'c, U: 'static + Send + Sync> = ViewContext<'b, 'c, U>;
|
||||||
type Result<U> = U;
|
type Result<U> = U;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue