Switch action dispatch to use MutableAppContext parent utilities and delete parent map from presenter
This commit is contained in:
parent
4271eb3624
commit
6442ec59e7
6 changed files with 100 additions and 52 deletions
|
@ -230,7 +230,7 @@ impl App {
|
||||||
let mut cx = cx.borrow_mut();
|
let mut cx = cx.borrow_mut();
|
||||||
if let Some(key_window_id) = cx.cx.platform.key_window_id() {
|
if let Some(key_window_id) = cx.cx.platform.key_window_id() {
|
||||||
if let Some(view_id) = cx.focused_view_id(key_window_id) {
|
if let Some(view_id) = cx.focused_view_id(key_window_id) {
|
||||||
cx.handle_dispatch_action_any_effect(key_window_id, Some(view_id), action);
|
cx.handle_dispatch_action_from_effect(key_window_id, Some(view_id), action);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,7 +457,7 @@ impl TestAppContext {
|
||||||
pub fn dispatch_action<A: Action>(&self, window_id: usize, action: A) {
|
pub fn dispatch_action<A: Action>(&self, window_id: usize, action: A) {
|
||||||
let mut cx = self.cx.borrow_mut();
|
let mut cx = self.cx.borrow_mut();
|
||||||
if let Some(view_id) = cx.focused_view_id(window_id) {
|
if let Some(view_id) = cx.focused_view_id(window_id) {
|
||||||
cx.handle_dispatch_action_any_effect(window_id, Some(view_id), &action);
|
cx.handle_dispatch_action_from_effect(window_id, Some(view_id), &action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,6 +477,7 @@ impl TestAppContext {
|
||||||
if cx.dispatch_keystroke(window_id, &keystroke) {
|
if cx.dispatch_keystroke(window_id, &keystroke) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if presenter.borrow_mut().dispatch_event(
|
if presenter.borrow_mut().dispatch_event(
|
||||||
Event::KeyDown(KeyDownEvent {
|
Event::KeyDown(KeyDownEvent {
|
||||||
keystroke: keystroke.clone(),
|
keystroke: keystroke.clone(),
|
||||||
|
@ -1606,6 +1607,12 @@ impl MutableAppContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn name_for_view(&self, window_id: usize, view_id: usize) -> Option<&str> {
|
||||||
|
self.views
|
||||||
|
.get(&(window_id, view_id))
|
||||||
|
.map(|view| view.ui_name())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn all_action_names<'a>(&'a self) -> impl Iterator<Item = &'static str> + 'a {
|
pub fn all_action_names<'a>(&'a self) -> impl Iterator<Item = &'static str> + 'a {
|
||||||
self.action_deserializers.keys().copied()
|
self.action_deserializers.keys().copied()
|
||||||
}
|
}
|
||||||
|
@ -1685,29 +1692,6 @@ impl MutableAppContext {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn dispatch_action_at(&mut self, window_id: usize, view_id: usize, action: &dyn Action) {
|
|
||||||
// let presenter = self
|
|
||||||
// .presenters_and_platform_windows
|
|
||||||
// .get(&window_id)
|
|
||||||
// .unwrap()
|
|
||||||
// .0
|
|
||||||
// .clone();
|
|
||||||
// let mut dispatch_path = Vec::new();
|
|
||||||
// presenter
|
|
||||||
// .borrow()
|
|
||||||
// .compute_dispatch_path_from(view_id, &mut dispatch_path);
|
|
||||||
// self.dispatch_action_any(window_id, &dispatch_path, action);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn dispatch_action<A: Action>(
|
|
||||||
// &mut self,
|
|
||||||
// window_id: usize,
|
|
||||||
// dispatch_path: Vec<usize>,
|
|
||||||
// action: &A,
|
|
||||||
// ) {
|
|
||||||
// self.dispatch_action_any(window_id, &dispatch_path, action);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Traverses the parent tree. Walks down the tree toward the passed
|
// Traverses the parent tree. Walks down the tree toward the passed
|
||||||
// view calling visit with true. Then walks back up the tree calling visit with false.
|
// view calling visit with true. Then walks back up the tree calling visit with false.
|
||||||
// If `visit` returns false this function will immediately return.
|
// If `visit` returns false this function will immediately return.
|
||||||
|
@ -1719,12 +1703,7 @@ impl MutableAppContext {
|
||||||
mut visit: impl FnMut(usize, bool, &mut MutableAppContext) -> bool,
|
mut visit: impl FnMut(usize, bool, &mut MutableAppContext) -> bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// List of view ids from the leaf to the root of the window
|
// List of view ids from the leaf to the root of the window
|
||||||
let mut path = vec![view_id];
|
let path = self.parents(window_id, view_id).collect::<Vec<_>>();
|
||||||
let mut current_view = view_id;
|
|
||||||
while let Some(ParentId::View(parent_id)) = self.parents.get(&(window_id, current_view)) {
|
|
||||||
current_view = *parent_id;
|
|
||||||
path.push(current_view);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Walk down from the root to the leaf calling visit with capture_phase = true
|
// Walk down from the root to the leaf calling visit with capture_phase = true
|
||||||
for view_id in path.iter().rev() {
|
for view_id in path.iter().rev() {
|
||||||
|
@ -1746,15 +1725,18 @@ impl MutableAppContext {
|
||||||
// Returns an iterator over all of the view ids from the passed view up to the root of the window
|
// Returns an iterator over all of the view ids from the passed view up to the root of the window
|
||||||
// Includes the passed view itself
|
// Includes the passed view itself
|
||||||
fn parents(&self, window_id: usize, mut view_id: usize) -> impl Iterator<Item = usize> + '_ {
|
fn parents(&self, window_id: usize, mut view_id: usize) -> impl Iterator<Item = usize> + '_ {
|
||||||
std::iter::from_fn(move || {
|
std::iter::once(view_id)
|
||||||
|
.into_iter()
|
||||||
|
.chain(std::iter::from_fn(move || {
|
||||||
if let Some(ParentId::View(parent_id)) = self.parents.get(&(window_id, view_id)) {
|
if let Some(ParentId::View(parent_id)) = self.parents.get(&(window_id, view_id)) {
|
||||||
view_id = *parent_id;
|
view_id = *parent_id;
|
||||||
Some(view_id)
|
Some(view_id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn actions_mut(
|
fn actions_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
capture_phase: bool,
|
capture_phase: bool,
|
||||||
|
@ -1793,8 +1775,8 @@ impl MutableAppContext {
|
||||||
pub fn dispatch_keystroke(&mut self, window_id: usize, keystroke: &Keystroke) -> bool {
|
pub fn dispatch_keystroke(&mut self, window_id: usize, keystroke: &Keystroke) -> bool {
|
||||||
let mut pending = false;
|
let mut pending = false;
|
||||||
|
|
||||||
if let Some(view_id) = self.focused_view_id(window_id) {
|
if let Some(focused_view_id) = self.focused_view_id(window_id) {
|
||||||
for view_id in self.parents(window_id, view_id).collect::<Vec<_>>() {
|
for view_id in self.parents(window_id, focused_view_id).collect::<Vec<_>>() {
|
||||||
let keymap_context = self
|
let keymap_context = self
|
||||||
.cx
|
.cx
|
||||||
.views
|
.views
|
||||||
|
@ -1810,7 +1792,7 @@ impl MutableAppContext {
|
||||||
MatchResult::None => {}
|
MatchResult::None => {}
|
||||||
MatchResult::Pending => pending = true,
|
MatchResult::Pending => pending = true,
|
||||||
MatchResult::Action(action) => {
|
MatchResult::Action(action) => {
|
||||||
if self.handle_dispatch_action_any_effect(
|
if self.handle_dispatch_action_from_effect(
|
||||||
window_id,
|
window_id,
|
||||||
Some(view_id),
|
Some(view_id),
|
||||||
action.as_ref(),
|
action.as_ref(),
|
||||||
|
@ -2303,7 +2285,7 @@ impl MutableAppContext {
|
||||||
view_id,
|
view_id,
|
||||||
action,
|
action,
|
||||||
} => {
|
} => {
|
||||||
self.handle_dispatch_action_any_effect(
|
self.handle_dispatch_action_from_effect(
|
||||||
window_id,
|
window_id,
|
||||||
Some(view_id),
|
Some(view_id),
|
||||||
action.as_ref(),
|
action.as_ref(),
|
||||||
|
@ -2579,7 +2561,7 @@ impl MutableAppContext {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_dispatch_action_any_effect(
|
fn handle_dispatch_action_from_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
window_id: usize,
|
window_id: usize,
|
||||||
view_id: Option<usize>,
|
view_id: Option<usize>,
|
||||||
|
@ -2587,6 +2569,7 @@ impl MutableAppContext {
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.update(|this| {
|
self.update(|this| {
|
||||||
if let Some(view_id) = view_id {
|
if let Some(view_id) = view_id {
|
||||||
|
this.halt_action_dispatch = false;
|
||||||
this.visit_dispatch_path(window_id, view_id, |view_id, capture_phase, this| {
|
this.visit_dispatch_path(window_id, view_id, |view_id, capture_phase, this| {
|
||||||
if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) {
|
if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) {
|
||||||
let type_id = view.as_any().type_id();
|
let type_id = view.as_any().type_id();
|
||||||
|
@ -2809,6 +2792,7 @@ impl Deref for MutableAppContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ParentId {
|
pub enum ParentId {
|
||||||
View(usize),
|
View(usize),
|
||||||
Root,
|
Root,
|
||||||
|
@ -2817,7 +2801,7 @@ pub enum ParentId {
|
||||||
pub struct AppContext {
|
pub struct AppContext {
|
||||||
models: HashMap<usize, Box<dyn AnyModel>>,
|
models: HashMap<usize, Box<dyn AnyModel>>,
|
||||||
views: HashMap<(usize, usize), Box<dyn AnyView>>,
|
views: HashMap<(usize, usize), Box<dyn AnyView>>,
|
||||||
parents: HashMap<(usize, usize), ParentId>,
|
pub(crate) parents: HashMap<(usize, usize), ParentId>,
|
||||||
windows: HashMap<usize, Window>,
|
windows: HashMap<usize, Window>,
|
||||||
globals: HashMap<TypeId, Box<dyn Any>>,
|
globals: HashMap<TypeId, Box<dyn Any>>,
|
||||||
element_states: HashMap<ElementStateId, Box<dyn Any>>,
|
element_states: HashMap<ElementStateId, Box<dyn Any>>,
|
||||||
|
@ -3733,6 +3717,21 @@ impl<'a, T: View> ViewContext<'a, T> {
|
||||||
.build_and_insert_view(self.window_id, ParentId::View(self.view_id), build_view)
|
.build_and_insert_view(self.window_id, ParentId::View(self.view_id), build_view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reparent(&mut self, view_handle: impl Into<AnyViewHandle>) {
|
||||||
|
let view_handle = view_handle.into();
|
||||||
|
if self.window_id != view_handle.window_id {
|
||||||
|
panic!("Can't reparent view to a view from a different window");
|
||||||
|
}
|
||||||
|
self.cx
|
||||||
|
.parents
|
||||||
|
.remove(&(view_handle.window_id, view_handle.view_id));
|
||||||
|
let new_parent_id = self.view_id;
|
||||||
|
self.cx.parents.insert(
|
||||||
|
(view_handle.window_id, view_handle.view_id),
|
||||||
|
ParentId::View(new_parent_id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn replace_root_view<V, F>(&mut self, build_root_view: F) -> ViewHandle<V>
|
pub fn replace_root_view<V, F>(&mut self, build_root_view: F) -> ViewHandle<V>
|
||||||
where
|
where
|
||||||
V: View,
|
V: View,
|
||||||
|
@ -6914,7 +6913,7 @@ mod tests {
|
||||||
let view_3 = cx.add_view(&view_2, |_| ViewA { id: 3 });
|
let view_3 = cx.add_view(&view_2, |_| ViewA { id: 3 });
|
||||||
let view_4 = cx.add_view(&view_3, |_| ViewB { id: 4 });
|
let view_4 = cx.add_view(&view_3, |_| ViewB { id: 4 });
|
||||||
|
|
||||||
cx.handle_dispatch_action_any_effect(
|
cx.handle_dispatch_action_from_effect(
|
||||||
window_id,
|
window_id,
|
||||||
Some(view_4.id()),
|
Some(view_4.id()),
|
||||||
&Action("bar".to_string()),
|
&Action("bar".to_string()),
|
||||||
|
@ -6938,12 +6937,12 @@ mod tests {
|
||||||
|
|
||||||
// Remove view_1, which doesn't propagate the action
|
// Remove view_1, which doesn't propagate the action
|
||||||
|
|
||||||
let (window_id, view_2) = cx.add_window(Default::default(), |_| ViewA { id: 1 });
|
let (window_id, view_2) = cx.add_window(Default::default(), |_| ViewB { id: 2 });
|
||||||
let view_3 = cx.add_view(&view_2, |_| ViewA { id: 3 });
|
let view_3 = cx.add_view(&view_2, |_| ViewA { id: 3 });
|
||||||
let view_4 = cx.add_view(&view_3, |_| ViewB { id: 4 });
|
let view_4 = cx.add_view(&view_3, |_| ViewB { id: 4 });
|
||||||
|
|
||||||
actions.borrow_mut().clear();
|
actions.borrow_mut().clear();
|
||||||
cx.handle_dispatch_action_any_effect(
|
cx.handle_dispatch_action_from_effect(
|
||||||
window_id,
|
window_id,
|
||||||
Some(view_4.id()),
|
Some(view_4.id()),
|
||||||
&Action("bar".to_string()),
|
&Action("bar".to_string()),
|
||||||
|
@ -7019,8 +7018,10 @@ mod tests {
|
||||||
|
|
||||||
let (window_id, view_1) = cx.add_window(Default::default(), |_| view_1);
|
let (window_id, view_1) = cx.add_window(Default::default(), |_| view_1);
|
||||||
let view_2 = cx.add_view(&view_1, |_| view_2);
|
let view_2 = cx.add_view(&view_1, |_| view_2);
|
||||||
let view_3 = cx.add_view(&view_2, |_| view_3);
|
let view_3 = cx.add_view(&view_2, |cx| {
|
||||||
cx.focus(window_id, Some(view_3.id()));
|
cx.focus_self();
|
||||||
|
view_3
|
||||||
|
});
|
||||||
|
|
||||||
// This keymap's only binding dispatches an action on view 2 because that view will have
|
// This keymap's only binding dispatches an action on view 2 because that view will have
|
||||||
// "a" and "b" in its context, but not "c".
|
// "a" and "b" in its context, but not "c".
|
||||||
|
|
|
@ -10,8 +10,8 @@ use crate::{
|
||||||
text_layout::TextLayoutCache,
|
text_layout::TextLayoutCache,
|
||||||
Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AssetCache, ElementBox, Entity,
|
Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AssetCache, ElementBox, Entity,
|
||||||
FontSystem, ModelHandle, MouseButtonEvent, MouseMovedEvent, MouseRegion, MouseRegionId,
|
FontSystem, ModelHandle, MouseButtonEvent, MouseMovedEvent, MouseRegion, MouseRegionId,
|
||||||
ReadModel, ReadView, RenderContext, RenderParams, Scene, UpgradeModelHandle, UpgradeViewHandle,
|
ParentId, ReadModel, ReadView, RenderContext, RenderParams, Scene, UpgradeModelHandle,
|
||||||
View, ViewHandle, WeakModelHandle, WeakViewHandle,
|
UpgradeViewHandle, View, ViewHandle, WeakModelHandle, WeakViewHandle,
|
||||||
};
|
};
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||||
|
@ -482,6 +482,43 @@ impl<'a> LayoutContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(&mut self, view_id: usize, constraint: SizeConstraint) -> Vector2F {
|
fn layout(&mut self, view_id: usize, constraint: SizeConstraint) -> Vector2F {
|
||||||
|
let print_error = |view_id| {
|
||||||
|
format!(
|
||||||
|
"{} with id {}",
|
||||||
|
self.app.name_for_view(self.window_id, view_id).unwrap(),
|
||||||
|
view_id,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
match (
|
||||||
|
self.view_stack.last(),
|
||||||
|
self.app.parents.get(&(self.window_id, view_id)),
|
||||||
|
) {
|
||||||
|
(Some(layout_parent), Some(ParentId::View(app_parent))) => {
|
||||||
|
if layout_parent != app_parent {
|
||||||
|
panic!(
|
||||||
|
"View {} was laid out with parent {} when it was constructed with parent {}",
|
||||||
|
print_error(view_id),
|
||||||
|
print_error(*layout_parent),
|
||||||
|
print_error(*app_parent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(None, Some(ParentId::View(app_parent))) => panic!(
|
||||||
|
"View {} was laid out without a parent when it was constructed with parent {}",
|
||||||
|
print_error(view_id),
|
||||||
|
print_error(*app_parent)
|
||||||
|
),
|
||||||
|
(Some(layout_parent), Some(ParentId::Root)) => panic!(
|
||||||
|
"View {} was laid out with parent {} when it was constructed as a window root",
|
||||||
|
print_error(view_id),
|
||||||
|
print_error(*layout_parent),
|
||||||
|
),
|
||||||
|
(_, None) => panic!(
|
||||||
|
"View {} did not have a registered parent in the app context",
|
||||||
|
print_error(view_id),
|
||||||
|
),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
self.view_stack.push(view_id);
|
self.view_stack.push(view_id);
|
||||||
let mut rendered_view = self.rendered_views.remove(&view_id).unwrap();
|
let mut rendered_view = self.rendered_views.remove(&view_id).unwrap();
|
||||||
let size = rendered_view.layout(constraint, self);
|
let size = rendered_view.layout(constraint, self);
|
||||||
|
|
|
@ -441,6 +441,7 @@ impl Pane {
|
||||||
pane.active_item_index = usize::MAX;
|
pane.active_item_index = usize::MAX;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
cx.reparent(&item);
|
||||||
pane.items.insert(item_ix, item);
|
pane.items.insert(item_ix, item);
|
||||||
pane.activate_item(item_ix, activate_pane, focus_item, false, cx);
|
pane.activate_item(item_ix, activate_pane, focus_item, false, cx);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
|
@ -140,6 +140,7 @@ impl Sidebar {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
cx.reparent(&view);
|
||||||
self.items.push(Item {
|
self.items.push(Item {
|
||||||
icon_path,
|
icon_path,
|
||||||
tooltip,
|
tooltip,
|
||||||
|
|
|
@ -81,6 +81,7 @@ impl StatusBar {
|
||||||
where
|
where
|
||||||
T: 'static + StatusItemView,
|
T: 'static + StatusItemView,
|
||||||
{
|
{
|
||||||
|
cx.reparent(&item);
|
||||||
self.left_items.push(Box::new(item));
|
self.left_items.push(Box::new(item));
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
@ -89,6 +90,7 @@ impl StatusBar {
|
||||||
where
|
where
|
||||||
T: 'static + StatusItemView,
|
T: 'static + StatusItemView,
|
||||||
{
|
{
|
||||||
|
cx.reparent(&item);
|
||||||
self.right_items.push(Box::new(item));
|
self.right_items.push(Box::new(item));
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
|
@ -708,6 +708,12 @@ impl Into<AnyViewHandle> for Box<dyn ItemHandle> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<AnyViewHandle> for &Box<dyn ItemHandle> {
|
||||||
|
fn into(self) -> AnyViewHandle {
|
||||||
|
self.to_any()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Clone for Box<dyn ItemHandle> {
|
impl Clone for Box<dyn ItemHandle> {
|
||||||
fn clone(&self) -> Box<dyn ItemHandle> {
|
fn clone(&self) -> Box<dyn ItemHandle> {
|
||||||
self.boxed_clone()
|
self.boxed_clone()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue