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(),
|
||||
pending_effects: Default::default(),
|
||||
observers: Default::default(),
|
||||
event_handlers: 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 EventHandlers =
|
||||
SmallVec<[Arc<dyn Fn(&dyn Any, &mut AppContext) -> bool + Send + Sync + 'static>; 2]>;
|
||||
type FrameCallback = Box<dyn FnOnce(&mut WindowContext) + Send>;
|
||||
|
||||
pub struct AppContext {
|
||||
|
@ -107,6 +110,7 @@ pub struct AppContext {
|
|||
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
|
||||
pub(crate) pending_effects: VecDeque<Effect>,
|
||||
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.
|
||||
}
|
||||
|
||||
|
@ -149,6 +153,7 @@ impl AppContext {
|
|||
while let Some(effect) = self.pending_effects.pop_front() {
|
||||
match effect {
|
||||
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 {
|
||||
AsyncAppContext(unsafe { mem::transmute(self.this.clone()) })
|
||||
}
|
||||
|
@ -367,6 +382,10 @@ impl MainThread<AppContext> {
|
|||
|
||||
pub(crate) enum Effect {
|
||||
Notify(EntityId),
|
||||
Emit {
|
||||
entity_id: EntityId,
|
||||
event: Box<dyn Any + Send + Sync + 'static>,
|
||||
},
|
||||
}
|
||||
|
||||
#[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};
|
||||
|
||||
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) {
|
||||
self.app
|
||||
.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> {
|
||||
type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, 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> {
|
||||
fn flatten(self) -> Result<T>;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use crate::{
|
||||
px, size, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace, BorrowAppContext,
|
||||
Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, Edges, Effect, Element, EntityId,
|
||||
Event, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, MainThread,
|
||||
MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, PlatformAtlas, PlatformWindow,
|
||||
Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams,
|
||||
RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style,
|
||||
TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions,
|
||||
Event, EventEmitter, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData, IsZero,
|
||||
LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels,
|
||||
PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams,
|
||||
RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
|
||||
Style, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions,
|
||||
SUBPIXEL_VARIANTS,
|
||||
};
|
||||
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) {
|
||||
self.window_cx.notify();
|
||||
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> {
|
||||
type EntityContext<'b, 'c, U: 'static + Send + Sync> = ViewContext<'b, 'c, U>;
|
||||
type Result<U> = U;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue