Pass a MutableAppContext to Element::layout and ::dispatch_event

We need to mutate the app in these cases to relay layout state, so this just makes things easier. We won't be able to perform layout in parallel but it's questionable whether we'll ever actually do that. If we do, we can revisit.

Co-Authored-By: Antonio Scandurra <me@as-cii.com>
Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Nathan Sobo
2021-07-23 10:52:08 -06:00
co-authored by Antonio Scandurra Max Brunsfeld
parent 61f45800d3
commit 11285f3762
7 changed files with 75 additions and 44 deletions
+42 -11
View File
@@ -5,7 +5,8 @@ use crate::{
platform::{self, Platform, PromptLevel, WindowOptions},
presenter::Presenter,
util::{post_inc, timeout},
AssetCache, AssetSource, ClipboardItem, FontCache, PathPromptOptions, TextLayoutCache,
AssetCache, AssetSource, ClipboardItem, EventContext, FontCache, PathPromptOptions,
TextLayoutCache,
};
use anyhow::{anyhow, Result};
use async_task::Task;
@@ -22,6 +23,7 @@ use std::{
fmt::{self, Debug},
hash::{Hash, Hasher},
marker::PhantomData,
ops::Deref,
path::{Path, PathBuf},
rc::{self, Rc},
sync::{Arc, Weak},
@@ -1476,6 +1478,14 @@ impl AsRef<AppContext> for MutableAppContext {
}
}
impl Deref for MutableAppContext {
type Target = AppContext;
fn deref(&self) -> &Self::Target {
&self.cx
}
}
pub struct AppContext {
models: HashMap<usize, Box<dyn AnyModel>>,
views: HashMap<(usize, usize), Box<dyn AnyView>>,
@@ -1534,8 +1544,10 @@ impl AppContext {
pub fn value<Tag: 'static, T: 'static + Default>(&self, id: usize) -> ValueHandle<T> {
let key = (TypeId::of::<Tag>(), id);
let mut values = self.values.write();
values.entry(key).or_insert_with(|| Box::new(T::default()));
self.values
.write()
.entry(key)
.or_insert_with(|| Box::new(T::default()));
ValueHandle::new(TypeId::of::<Tag>(), id, &self.ref_counts)
}
}
@@ -2090,6 +2102,14 @@ impl<M> AsRef<AppContext> for ViewContext<'_, M> {
}
}
impl<M> Deref for ViewContext<'_, M> {
type Target = MutableAppContext;
fn deref(&self) -> &Self::Target {
&self.app
}
}
impl<M> AsMut<MutableAppContext> for ViewContext<'_, M> {
fn as_mut(&mut self) -> &mut MutableAppContext {
self.app
@@ -2633,8 +2653,7 @@ impl<T: View> WeakViewHandle<T> {
}
}
pub fn upgrade(&self, cx: impl AsRef<AppContext>) -> Option<ViewHandle<T>> {
let cx = cx.as_ref();
pub fn upgrade(&self, cx: &AppContext) -> Option<ViewHandle<T>> {
if cx.ref_counts.lock().is_entity_alive(self.view_id) {
Some(ViewHandle::new(
self.window_id,
@@ -2684,13 +2703,25 @@ impl<T: 'static> ValueHandle<T> {
.unwrap())
}
pub fn update<R>(&self, cx: &AppContext, f: impl FnOnce(&mut T) -> R) -> R {
f(cx.values
pub fn update<R>(
&self,
cx: &mut EventContext,
f: impl FnOnce(&mut T, &mut EventContext) -> R,
) -> R {
let mut value = cx
.app
.cx
.values
.write()
.get_mut(&(self.tag_type_id, self.id))
.unwrap()
.downcast_mut()
.unwrap())
.remove(&(self.tag_type_id, self.id))
.unwrap();
let result = f(value.downcast_mut().unwrap(), cx);
cx.app
.cx
.values
.write()
.insert((self.tag_type_id, self.id), value);
result
}
}
+2 -2
View File
@@ -29,8 +29,8 @@ pub use uniform_list::*;
use crate::{
geometry::{rect::RectF, vector::Vector2F},
json, AfterLayoutContext, AppContext, DebugContext, Event, EventContext, LayoutContext,
PaintContext, SizeConstraint,
json, AfterLayoutContext, DebugContext, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
};
use core::panic;
use json::ToJson;
+2 -2
View File
@@ -24,7 +24,7 @@ impl MouseEventHandler {
F: FnOnce(MouseState) -> ElementBox,
{
let state_handle = cx.value::<Tag, _>(id);
let state = state_handle.read(cx, |state| *state);
let state = state_handle.read(cx.as_ref(), |state| *state);
let child = render_child(state);
Self {
state: state_handle,
@@ -81,7 +81,7 @@ impl Element for MouseEventHandler {
let handled_in_child = self.child.dispatch_event(event, cx);
self.state.update(cx.app, |state| match event {
self.state.update(cx, |state, cx| match event {
Event::MouseMoved { position } => {
let mouse_in = bounds.contains_point(*position);
if state.hovered != mouse_in {
+2 -3
View File
@@ -1,6 +1,5 @@
use super::{
AfterLayoutContext, AppContext, Element, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
AfterLayoutContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
};
use crate::{
geometry::{
@@ -8,7 +7,7 @@ use crate::{
vector::{vec2f, Vector2F},
},
json::{self, json},
ElementBox,
AppContext, ElementBox,
};
use json::ToJson;
use parking_lot::Mutex;
+5 -5
View File
@@ -76,7 +76,7 @@ impl Presenter {
let mut scene = Scene::new(scale_factor);
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
self.layout(window_size, cx.as_ref());
self.layout(window_size, cx);
self.after_layout(cx);
let mut paint_cx = PaintContext {
scene: &mut scene,
@@ -98,7 +98,7 @@ impl Presenter {
scene
}
fn layout(&mut self, size: Vector2F, cx: &AppContext) {
fn layout(&mut self, size: Vector2F, cx: &mut MutableAppContext) {
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
let mut layout_ctx = LayoutContext {
rendered_views: &mut self.rendered_views,
@@ -138,7 +138,7 @@ impl Presenter {
text_layout_cache: &self.text_layout_cache,
view_stack: Default::default(),
invalidated_views: Default::default(),
app: cx.as_ref(),
app: cx,
};
event_cx.dispatch_event(root_view_id, &event);
@@ -184,7 +184,7 @@ pub struct LayoutContext<'a> {
pub font_cache: &'a FontCache,
pub text_layout_cache: &'a TextLayoutCache,
pub asset_cache: &'a AssetCache,
pub app: &'a AppContext,
pub app: &'a mut MutableAppContext,
view_stack: Vec<usize>,
}
@@ -240,7 +240,7 @@ pub struct EventContext<'a> {
actions: Vec<ActionToDispatch>,
pub font_cache: &'a FontCache,
pub text_layout_cache: &'a TextLayoutCache,
pub app: &'a AppContext,
pub app: &'a mut MutableAppContext,
view_stack: Vec<usize>,
invalidated_views: HashSet<usize>,
}
+21 -21
View File
@@ -38,8 +38,9 @@ impl EditorElement {
cx: &mut EventContext,
) -> bool {
if paint.text_bounds.contains_point(position) {
let view = self.view(cx.app);
let position = paint.point_for_position(view, layout, position, cx.font_cache, cx.app);
let view = self.view(cx.app.as_ref());
let position =
paint.point_for_position(view, layout, position, cx.font_cache, cx.app.as_ref());
cx.dispatch_action("buffer:select", SelectAction::Begin { position, add: cmd });
true
} else {
@@ -48,7 +49,7 @@ impl EditorElement {
}
fn mouse_up(&self, _position: Vector2F, cx: &mut EventContext) -> bool {
if self.view(cx.app).is_selecting() {
if self.view(cx.app.as_ref()).is_selecting() {
cx.dispatch_action("buffer:select", SelectAction::End);
true
} else {
@@ -63,7 +64,7 @@ impl EditorElement {
paint: &mut PaintState,
cx: &mut EventContext,
) -> bool {
let view = self.view(cx.app);
let view = self.view(cx.app.as_ref());
if view.is_selecting() {
let rect = paint.text_bounds;
@@ -93,22 +94,21 @@ impl EditorElement {
))
}
cx.dispatch_action(
"buffer:select",
SelectAction::Update {
position: paint.point_for_position(
view,
layout,
position,
cx.font_cache,
cx.app,
),
scroll_position: (view.scroll_position() + scroll_delta).clamp(
Vector2F::zero(),
layout.scroll_max(view, cx.font_cache, cx.text_layout_cache, cx.app),
),
},
);
let action = SelectAction::Update {
position: paint.point_for_position(
view,
layout,
position,
cx.font_cache,
cx.app.as_ref(),
),
scroll_position: (view.scroll_position() + scroll_delta).clamp(
Vector2F::zero(),
layout.scroll_max(view, cx.font_cache, cx.text_layout_cache, cx.app),
),
};
cx.dispatch_action("buffer:select", action);
true
} else {
false
@@ -326,7 +326,7 @@ impl Element for EditorElement {
constraint: SizeConstraint,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let app = cx.app;
let app = &mut cx.app;
let mut size = constraint.max;
if size.y().is_infinite() {
let view = self.view(app);
+1
View File
@@ -124,6 +124,7 @@ impl FileFinder {
self.list_state.clone(),
self.matches.len(),
move |mut range, items, cx| {
let cx = cx.as_ref();
let finder = handle.upgrade(cx).unwrap();
let finder = finder.read(cx);
let start = range.start;