Merge branch 'main' into implicit-ancestry
This commit is contained in:
commit
da19edc3e3
33 changed files with 746 additions and 392 deletions
|
@ -84,14 +84,15 @@ pub trait View: Entity + Sized {
|
|||
false
|
||||
}
|
||||
|
||||
fn keymap_context(&self, _: &AppContext) -> keymap_matcher::KeymapContext {
|
||||
Self::default_keymap_context()
|
||||
fn update_keymap_context(&self, keymap: &mut keymap_matcher::KeymapContext, _: &AppContext) {
|
||||
Self::reset_to_default_keymap_context(keymap);
|
||||
}
|
||||
fn default_keymap_context() -> keymap_matcher::KeymapContext {
|
||||
let mut cx = keymap_matcher::KeymapContext::default();
|
||||
cx.add_identifier(Self::ui_name());
|
||||
cx
|
||||
|
||||
fn reset_to_default_keymap_context(keymap: &mut keymap_matcher::KeymapContext) {
|
||||
keymap.clear();
|
||||
keymap.add_identifier(Self::ui_name());
|
||||
}
|
||||
|
||||
fn debug_json(&self, _: &AppContext) -> serde_json::Value {
|
||||
serde_json::Value::Null
|
||||
}
|
||||
|
@ -450,6 +451,7 @@ type WindowShouldCloseSubscriptionCallback = Box<dyn FnMut(&mut AppContext) -> b
|
|||
pub struct AppContext {
|
||||
models: HashMap<usize, Box<dyn AnyModel>>,
|
||||
views: HashMap<(usize, usize), Box<dyn AnyView>>,
|
||||
views_metadata: HashMap<(usize, usize), ViewMetadata>,
|
||||
windows: HashMap<usize, Window>,
|
||||
globals: HashMap<TypeId, Box<dyn Any>>,
|
||||
element_states: HashMap<ElementStateId, Box<dyn Any>>,
|
||||
|
@ -511,6 +513,7 @@ impl AppContext {
|
|||
Self {
|
||||
models: Default::default(),
|
||||
views: Default::default(),
|
||||
views_metadata: Default::default(),
|
||||
windows: Default::default(),
|
||||
globals: Default::default(),
|
||||
element_states: Default::default(),
|
||||
|
@ -735,9 +738,9 @@ impl AppContext {
|
|||
}
|
||||
|
||||
pub fn view_type_id(&self, window_id: usize, view_id: usize) -> Option<TypeId> {
|
||||
self.views
|
||||
self.views_metadata
|
||||
.get(&(window_id, view_id))
|
||||
.map(|view| view.as_any().type_id())
|
||||
.map(|metadata| metadata.type_id)
|
||||
}
|
||||
|
||||
pub fn active_labeled_tasks<'a>(
|
||||
|
@ -1053,9 +1056,10 @@ impl AppContext {
|
|||
.read_window(window_id, |cx| {
|
||||
if let Some(focused_view_id) = cx.focused_view_id() {
|
||||
for view_id in cx.ancestors(focused_view_id) {
|
||||
if let Some(view) = cx.views.get(&(window_id, view_id)) {
|
||||
let view_type = view.as_any().type_id();
|
||||
if let Some(actions) = cx.actions.get(&view_type) {
|
||||
if let Some(view_metadata) =
|
||||
cx.views_metadata.get(&(window_id, view_id))
|
||||
{
|
||||
if let Some(actions) = cx.actions.get(&view_metadata.type_id) {
|
||||
if actions.contains_key(&action_type) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1444,6 +1448,7 @@ impl AppContext {
|
|||
for (window_id, view_id) in dropped_views {
|
||||
self.subscriptions.remove(view_id);
|
||||
self.observations.remove(view_id);
|
||||
self.views_metadata.remove(&(window_id, view_id));
|
||||
let mut view = self.views.remove(&(window_id, view_id)).unwrap();
|
||||
view.release(self);
|
||||
let change_focus_to = self.windows.get_mut(&window_id).and_then(|window| {
|
||||
|
@ -1775,9 +1780,11 @@ impl AppContext {
|
|||
observed_window_id: usize,
|
||||
observed_view_id: usize,
|
||||
) {
|
||||
if self
|
||||
let view_key = (observed_window_id, observed_view_id);
|
||||
if let Some((view, mut view_metadata)) = self
|
||||
.views
|
||||
.contains_key(&(observed_window_id, observed_view_id))
|
||||
.remove(&view_key)
|
||||
.zip(self.views_metadata.remove(&view_key))
|
||||
{
|
||||
if let Some(window) = self.windows.get_mut(&observed_window_id) {
|
||||
window
|
||||
|
@ -1787,6 +1794,10 @@ impl AppContext {
|
|||
.insert(observed_view_id);
|
||||
}
|
||||
|
||||
view.update_keymap_context(&mut view_metadata.keymap_context, self);
|
||||
self.views.insert(view_key, view);
|
||||
self.views_metadata.insert(view_key, view_metadata);
|
||||
|
||||
let mut observations = self.observations.clone();
|
||||
observations.emit(observed_view_id, |callback| callback(self));
|
||||
}
|
||||
|
@ -2033,6 +2044,11 @@ pub enum ParentId {
|
|||
Root,
|
||||
}
|
||||
|
||||
struct ViewMetadata {
|
||||
type_id: TypeId,
|
||||
keymap_context: KeymapContext,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct WindowInvalidation {
|
||||
pub updated: HashSet<usize>,
|
||||
|
@ -2361,7 +2377,7 @@ pub trait AnyView {
|
|||
cx: &mut WindowContext,
|
||||
view_id: usize,
|
||||
) -> bool;
|
||||
fn keymap_context(&self, cx: &AppContext) -> KeymapContext;
|
||||
fn update_keymap_context(&self, keymap: &mut KeymapContext, cx: &AppContext);
|
||||
fn debug_json(&self, cx: &WindowContext) -> serde_json::Value;
|
||||
|
||||
fn text_for_range(&self, range: Range<usize>, cx: &WindowContext) -> Option<String>;
|
||||
|
@ -2433,11 +2449,10 @@ where
|
|||
cx.handle().into_any()
|
||||
} else {
|
||||
let focused_type = cx
|
||||
.views
|
||||
.views_metadata
|
||||
.get(&(cx.window_id, focused_id))
|
||||
.unwrap()
|
||||
.as_any()
|
||||
.type_id();
|
||||
.type_id;
|
||||
AnyViewHandle::new(
|
||||
cx.window_id,
|
||||
focused_id,
|
||||
|
@ -2454,11 +2469,10 @@ where
|
|||
cx.handle().into_any()
|
||||
} else {
|
||||
let blurred_type = cx
|
||||
.views
|
||||
.views_metadata
|
||||
.get(&(cx.window_id, blurred_id))
|
||||
.unwrap()
|
||||
.as_any()
|
||||
.type_id();
|
||||
.type_id;
|
||||
AnyViewHandle::new(
|
||||
cx.window_id,
|
||||
blurred_id,
|
||||
|
@ -2489,8 +2503,8 @@ where
|
|||
View::modifiers_changed(self, event, &mut cx)
|
||||
}
|
||||
|
||||
fn keymap_context(&self, cx: &AppContext) -> KeymapContext {
|
||||
View::keymap_context(self, cx)
|
||||
fn update_keymap_context(&self, keymap: &mut KeymapContext, cx: &AppContext) {
|
||||
View::update_keymap_context(self, keymap, cx)
|
||||
}
|
||||
|
||||
fn debug_json(&self, cx: &WindowContext) -> serde_json::Value {
|
||||
|
@ -3234,7 +3248,6 @@ impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> {
|
|||
/// Return keystrokes that would dispatch the given action on the given view.
|
||||
pub(crate) fn keystrokes_for_action(
|
||||
&mut self,
|
||||
view: &V,
|
||||
view_id: usize,
|
||||
action: &dyn Action,
|
||||
) -> Option<SmallVec<[Keystroke; 2]>> {
|
||||
|
@ -3244,21 +3257,13 @@ impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> {
|
|||
let mut contexts = Vec::new();
|
||||
let mut handler_depth = None;
|
||||
for (i, view_id) in self.ancestors(view_id).enumerate() {
|
||||
let view = if view_id == self.view_id {
|
||||
Some(view as _)
|
||||
} else {
|
||||
self.views
|
||||
.get(&(window_id, view_id))
|
||||
.map(|view| view.as_ref())
|
||||
};
|
||||
|
||||
if let Some(view) = view {
|
||||
if let Some(actions) = self.actions.get(&view.as_any().type_id()) {
|
||||
if let Some(view_metadata) = self.views_metadata.get(&(window_id, view_id)) {
|
||||
if let Some(actions) = self.actions.get(&view_metadata.type_id) {
|
||||
if actions.contains_key(&action.as_any().type_id()) {
|
||||
handler_depth = Some(i);
|
||||
}
|
||||
}
|
||||
contexts.push(view.keymap_context(self));
|
||||
contexts.push(view_metadata.keymap_context.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5687,8 +5692,8 @@ mod tests {
|
|||
"View"
|
||||
}
|
||||
|
||||
fn keymap_context(&self, _: &AppContext) -> KeymapContext {
|
||||
self.keymap_context.clone()
|
||||
fn update_keymap_context(&self, keymap: &mut KeymapContext, _: &AppContext) {
|
||||
*keymap = self.keymap_context.clone();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5852,52 +5857,51 @@ mod tests {
|
|||
});
|
||||
|
||||
let view_1_id = view_1.id();
|
||||
view_1.update(cx, |view_1, cx| {
|
||||
// Sanity check
|
||||
let mut new_parents = Default::default();
|
||||
let mut notify_views_if_parents_change = Default::default();
|
||||
let mut layout_cx = LayoutContext::new(
|
||||
cx,
|
||||
&mut new_parents,
|
||||
&mut notify_views_if_parents_change,
|
||||
false,
|
||||
);
|
||||
assert_eq!(
|
||||
layout_cx
|
||||
.keystrokes_for_action(view_1, view_1_id, &Action1)
|
||||
.unwrap()
|
||||
.as_slice(),
|
||||
&[Keystroke::parse("a").unwrap()]
|
||||
);
|
||||
assert_eq!(
|
||||
layout_cx
|
||||
.keystrokes_for_action(view_1, view_2.id(), &Action2)
|
||||
.unwrap()
|
||||
.as_slice(),
|
||||
&[Keystroke::parse("b").unwrap()]
|
||||
);
|
||||
view_1.update(cx, |_, cx| {
|
||||
view_2.update(cx, |_, cx| {
|
||||
// Sanity check
|
||||
let mut new_parents = Default::default();
|
||||
let mut notify_views_if_parents_change = Default::default();
|
||||
let mut layout_cx = LayoutContext::new(
|
||||
cx,
|
||||
&mut new_parents,
|
||||
&mut notify_views_if_parents_change,
|
||||
false,
|
||||
);
|
||||
assert_eq!(
|
||||
layout_cx
|
||||
.keystrokes_for_action(view_1_id, &Action1)
|
||||
.unwrap()
|
||||
.as_slice(),
|
||||
&[Keystroke::parse("a").unwrap()]
|
||||
);
|
||||
assert_eq!(
|
||||
layout_cx
|
||||
.keystrokes_for_action(view_2.id(), &Action2)
|
||||
.unwrap()
|
||||
.as_slice(),
|
||||
&[Keystroke::parse("b").unwrap()]
|
||||
);
|
||||
|
||||
// The 'a' keystroke propagates up the view tree from view_2
|
||||
// to view_1. The action, Action1, is handled by view_1.
|
||||
assert_eq!(
|
||||
layout_cx
|
||||
.keystrokes_for_action(view_1, view_2.id(), &Action1)
|
||||
.unwrap()
|
||||
.as_slice(),
|
||||
&[Keystroke::parse("a").unwrap()]
|
||||
);
|
||||
// The 'a' keystroke propagates up the view tree from view_2
|
||||
// to view_1. The action, Action1, is handled by view_1.
|
||||
assert_eq!(
|
||||
layout_cx
|
||||
.keystrokes_for_action(view_2.id(), &Action1)
|
||||
.unwrap()
|
||||
.as_slice(),
|
||||
&[Keystroke::parse("a").unwrap()]
|
||||
);
|
||||
|
||||
// Actions that are handled below the current view don't have bindings
|
||||
assert_eq!(
|
||||
layout_cx.keystrokes_for_action(view_1, view_1_id, &Action2),
|
||||
None
|
||||
);
|
||||
// Actions that are handled below the current view don't have bindings
|
||||
assert_eq!(layout_cx.keystrokes_for_action(view_1_id, &Action2), None);
|
||||
|
||||
// Actions that are handled in other branches of the tree should not have a binding
|
||||
assert_eq!(
|
||||
layout_cx.keystrokes_for_action(view_1, view_2.id(), &GlobalAction),
|
||||
None
|
||||
);
|
||||
// Actions that are handled in other branches of the tree should not have a binding
|
||||
assert_eq!(
|
||||
layout_cx.keystrokes_for_action(view_2.id(), &GlobalAction),
|
||||
None
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// Check that global actions do not have a binding, even if a binding does exist in another view
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
elements::AnyRootElement,
|
||||
geometry::rect::RectF,
|
||||
json::ToJson,
|
||||
keymap_matcher::{Binding, Keystroke, MatchResult},
|
||||
keymap_matcher::{Binding, KeymapContext, Keystroke, MatchResult},
|
||||
platform::{
|
||||
self, Appearance, CursorStyle, Event, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent,
|
||||
MouseButton, MouseMovedEvent, PromptLevel, WindowBounds,
|
||||
|
@ -34,7 +34,7 @@ use std::{
|
|||
use util::ResultExt;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::Reference;
|
||||
use super::{Reference, ViewMetadata};
|
||||
|
||||
pub struct Window {
|
||||
pub(crate) root_view: Option<AnyViewHandle>,
|
||||
|
@ -364,10 +364,9 @@ impl<'a> WindowContext<'a> {
|
|||
let mut contexts = Vec::new();
|
||||
let mut handler_depths_by_action_type = HashMap::<TypeId, usize>::default();
|
||||
for (depth, view_id) in self.ancestors(view_id).enumerate() {
|
||||
if let Some(view) = self.views.get(&(window_id, view_id)) {
|
||||
contexts.push(view.keymap_context(self));
|
||||
let view_type = view.as_any().type_id();
|
||||
if let Some(actions) = self.actions.get(&view_type) {
|
||||
if let Some(view_metadata) = self.views_metadata.get(&(window_id, view_id)) {
|
||||
contexts.push(view_metadata.keymap_context.clone());
|
||||
if let Some(actions) = self.actions.get(&view_metadata.type_id) {
|
||||
handler_depths_by_action_type.extend(
|
||||
actions
|
||||
.keys()
|
||||
|
@ -418,9 +417,9 @@ impl<'a> WindowContext<'a> {
|
|||
let dispatch_path = self
|
||||
.ancestors(focused_view_id)
|
||||
.filter_map(|view_id| {
|
||||
self.views
|
||||
self.views_metadata
|
||||
.get(&(window_id, view_id))
|
||||
.map(|view| (view_id, view.keymap_context(self)))
|
||||
.map(|view| (view_id, view.keymap_context.clone()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -1149,6 +1148,15 @@ impl<'a> WindowContext<'a> {
|
|||
let view_id = post_inc(&mut self.next_entity_id);
|
||||
let mut cx = ViewContext::mutable(self, view_id);
|
||||
let handle = if let Some(view) = build_view(&mut cx) {
|
||||
let mut keymap_context = KeymapContext::default();
|
||||
view.update_keymap_context(&mut keymap_context, cx.app_context());
|
||||
self.views_metadata.insert(
|
||||
(window_id, view_id),
|
||||
ViewMetadata {
|
||||
type_id: TypeId::of::<T>(),
|
||||
keymap_context,
|
||||
},
|
||||
);
|
||||
self.views.insert((window_id, view_id), Box::new(view));
|
||||
self.window
|
||||
.invalidation
|
||||
|
|
|
@ -42,7 +42,7 @@ impl<V: View> Element<V> for KeystrokeLabel {
|
|||
cx: &mut LayoutContext<V>,
|
||||
) -> (Vector2F, AnyElement<V>) {
|
||||
let mut element = if let Some(keystrokes) =
|
||||
cx.keystrokes_for_action(view, self.view_id, self.action.as_ref())
|
||||
cx.keystrokes_for_action(self.view_id, self.action.as_ref())
|
||||
{
|
||||
Flex::row()
|
||||
.with_children(keystrokes.iter().map(|keystroke| {
|
||||
|
|
|
@ -17,6 +17,11 @@ impl KeymapContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.set.clear();
|
||||
self.map.clear();
|
||||
}
|
||||
|
||||
pub fn extend(&mut self, other: &Self) {
|
||||
for v in &other.set {
|
||||
self.set.insert(v.clone());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue