Incorporate ElementId as part of the Element::id trait method and expose GlobalId (#11101)
We're planning to associate "selection sources" with global element ids to allow arbitrary UI text to be selected in GPUI. Previously, global ids were not exposed outside the framework and we entangled management of the element id stack with element state access. This was more acceptable when element state was the only place we used global element ids, but now that we're planning to use them more places, it makes sense to deal with element identity as a first-class part of the element system. We now ensure that the stack of element ids which forms the current global element id is correctly managed in every phase of element layout and paint and make the global id available to each element method. In a subsequent PR, we'll use the global element id as part of implementing arbitrary selection for UI text. Release Notes: - N/A --------- Co-authored-by: Antonio Scandurra <me@as-cii.com>
This commit is contained in:
parent
8b55494351
commit
39fb1d567d
21 changed files with 825 additions and 497 deletions
|
@ -1,8 +1,8 @@
|
|||
use crate::{
|
||||
seal::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, Bounds, ContentMask, Element,
|
||||
ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView, IntoElement, LayoutId, Model,
|
||||
PaintIndex, Pixels, PrepaintStateIndex, Render, Style, StyleRefinement, TextStyle, ViewContext,
|
||||
VisualContext, WeakModel, WindowContext,
|
||||
ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView, GlobalElementId, IntoElement,
|
||||
LayoutId, Model, PaintIndex, Pixels, PrepaintStateIndex, Render, Style, StyleRefinement,
|
||||
TextStyle, ViewContext, VisualContext, WeakModel, WindowContext,
|
||||
};
|
||||
use anyhow::{Context, Result};
|
||||
use refineable::Refineable;
|
||||
|
@ -93,36 +93,40 @@ impl<V: Render> Element for View<V> {
|
|||
type RequestLayoutState = AnyElement;
|
||||
type PrepaintState = ();
|
||||
|
||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||
let mut element = self.update(cx, |view, cx| view.render(cx).into_any_element());
|
||||
let layout_id = element.request_layout(cx);
|
||||
(layout_id, element)
|
||||
})
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
Some(ElementId::View(self.entity_id()))
|
||||
}
|
||||
|
||||
fn request_layout(
|
||||
&mut self,
|
||||
_id: Option<&GlobalElementId>,
|
||||
cx: &mut WindowContext,
|
||||
) -> (LayoutId, Self::RequestLayoutState) {
|
||||
let mut element = self.update(cx, |view, cx| view.render(cx).into_any_element());
|
||||
let layout_id = element.request_layout(cx);
|
||||
(layout_id, element)
|
||||
}
|
||||
|
||||
fn prepaint(
|
||||
&mut self,
|
||||
_id: Option<&GlobalElementId>,
|
||||
_: Bounds<Pixels>,
|
||||
element: &mut Self::RequestLayoutState,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
cx.set_view_id(self.entity_id());
|
||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||
element.prepaint(cx)
|
||||
})
|
||||
element.prepaint(cx);
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
_id: Option<&GlobalElementId>,
|
||||
_: Bounds<Pixels>,
|
||||
element: &mut Self::RequestLayoutState,
|
||||
_: &mut Self::PrepaintState,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||
element.paint(cx)
|
||||
})
|
||||
element.paint(cx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,112 +283,108 @@ impl Element for AnyView {
|
|||
type RequestLayoutState = Option<AnyElement>;
|
||||
type PrepaintState = Option<AnyElement>;
|
||||
|
||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
Some(ElementId::View(self.entity_id()))
|
||||
}
|
||||
|
||||
fn request_layout(
|
||||
&mut self,
|
||||
_id: Option<&GlobalElementId>,
|
||||
cx: &mut WindowContext,
|
||||
) -> (LayoutId, Self::RequestLayoutState) {
|
||||
if let Some(style) = self.cached_style.as_ref() {
|
||||
let mut root_style = Style::default();
|
||||
root_style.refine(style);
|
||||
let layout_id = cx.request_layout(&root_style, None);
|
||||
(layout_id, None)
|
||||
} else {
|
||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||
let mut element = (self.render)(self, cx);
|
||||
let layout_id = element.request_layout(cx);
|
||||
(layout_id, Some(element))
|
||||
})
|
||||
let mut element = (self.render)(self, cx);
|
||||
let layout_id = element.request_layout(cx);
|
||||
(layout_id, Some(element))
|
||||
}
|
||||
}
|
||||
|
||||
fn prepaint(
|
||||
&mut self,
|
||||
global_id: Option<&GlobalElementId>,
|
||||
bounds: Bounds<Pixels>,
|
||||
element: &mut Self::RequestLayoutState,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<AnyElement> {
|
||||
cx.set_view_id(self.entity_id());
|
||||
if self.cached_style.is_some() {
|
||||
cx.with_element_state::<AnyViewState, _>(
|
||||
Some(ElementId::View(self.entity_id())),
|
||||
|element_state, cx| {
|
||||
let mut element_state = element_state.unwrap();
|
||||
cx.with_element_state::<AnyViewState, _>(global_id.unwrap(), |element_state, cx| {
|
||||
let content_mask = cx.content_mask();
|
||||
let text_style = cx.text_style();
|
||||
|
||||
let content_mask = cx.content_mask();
|
||||
let text_style = cx.text_style();
|
||||
|
||||
if let Some(mut element_state) = element_state {
|
||||
if element_state.cache_key.bounds == bounds
|
||||
&& element_state.cache_key.content_mask == content_mask
|
||||
&& element_state.cache_key.text_style == text_style
|
||||
&& !cx.window.dirty_views.contains(&self.entity_id())
|
||||
&& !cx.window.refreshing
|
||||
{
|
||||
let prepaint_start = cx.prepaint_index();
|
||||
cx.reuse_prepaint(element_state.prepaint_range.clone());
|
||||
let prepaint_end = cx.prepaint_index();
|
||||
element_state.prepaint_range = prepaint_start..prepaint_end;
|
||||
return (None, Some(element_state));
|
||||
}
|
||||
if let Some(mut element_state) = element_state {
|
||||
if element_state.cache_key.bounds == bounds
|
||||
&& element_state.cache_key.content_mask == content_mask
|
||||
&& element_state.cache_key.text_style == text_style
|
||||
&& !cx.window.dirty_views.contains(&self.entity_id())
|
||||
&& !cx.window.refreshing
|
||||
{
|
||||
let prepaint_start = cx.prepaint_index();
|
||||
cx.reuse_prepaint(element_state.prepaint_range.clone());
|
||||
let prepaint_end = cx.prepaint_index();
|
||||
element_state.prepaint_range = prepaint_start..prepaint_end;
|
||||
return (None, element_state);
|
||||
}
|
||||
}
|
||||
|
||||
let prepaint_start = cx.prepaint_index();
|
||||
let mut element = (self.render)(self, cx);
|
||||
element.layout_as_root(bounds.size.into(), cx);
|
||||
element.prepaint_at(bounds.origin, cx);
|
||||
let prepaint_end = cx.prepaint_index();
|
||||
let prepaint_start = cx.prepaint_index();
|
||||
let mut element = (self.render)(self, cx);
|
||||
element.layout_as_root(bounds.size.into(), cx);
|
||||
element.prepaint_at(bounds.origin, cx);
|
||||
let prepaint_end = cx.prepaint_index();
|
||||
|
||||
(
|
||||
Some(element),
|
||||
Some(AnyViewState {
|
||||
prepaint_range: prepaint_start..prepaint_end,
|
||||
paint_range: PaintIndex::default()..PaintIndex::default(),
|
||||
cache_key: ViewCacheKey {
|
||||
bounds,
|
||||
content_mask,
|
||||
text_style,
|
||||
},
|
||||
}),
|
||||
)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||
let mut element = element.take().unwrap();
|
||||
element.prepaint(cx);
|
||||
Some(element)
|
||||
(
|
||||
Some(element),
|
||||
AnyViewState {
|
||||
prepaint_range: prepaint_start..prepaint_end,
|
||||
paint_range: PaintIndex::default()..PaintIndex::default(),
|
||||
cache_key: ViewCacheKey {
|
||||
bounds,
|
||||
content_mask,
|
||||
text_style,
|
||||
},
|
||||
},
|
||||
)
|
||||
})
|
||||
} else {
|
||||
let mut element = element.take().unwrap();
|
||||
element.prepaint(cx);
|
||||
Some(element)
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
global_id: Option<&GlobalElementId>,
|
||||
_bounds: Bounds<Pixels>,
|
||||
_: &mut Self::RequestLayoutState,
|
||||
element: &mut Self::PrepaintState,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
if self.cached_style.is_some() {
|
||||
cx.with_element_state::<AnyViewState, _>(
|
||||
Some(ElementId::View(self.entity_id())),
|
||||
|element_state, cx| {
|
||||
let mut element_state = element_state.unwrap().unwrap();
|
||||
cx.with_element_state::<AnyViewState, _>(global_id.unwrap(), |element_state, cx| {
|
||||
let mut element_state = element_state.unwrap();
|
||||
|
||||
let paint_start = cx.paint_index();
|
||||
let paint_start = cx.paint_index();
|
||||
|
||||
if let Some(element) = element {
|
||||
element.paint(cx);
|
||||
} else {
|
||||
cx.reuse_paint(element_state.paint_range.clone());
|
||||
}
|
||||
if let Some(element) = element {
|
||||
element.paint(cx);
|
||||
} else {
|
||||
cx.reuse_paint(element_state.paint_range.clone());
|
||||
}
|
||||
|
||||
let paint_end = cx.paint_index();
|
||||
element_state.paint_range = paint_start..paint_end;
|
||||
let paint_end = cx.paint_index();
|
||||
element_state.paint_range = paint_start..paint_end;
|
||||
|
||||
((), Some(element_state))
|
||||
},
|
||||
)
|
||||
} else {
|
||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||
element.as_mut().unwrap().paint(cx);
|
||||
((), element_state)
|
||||
})
|
||||
} else {
|
||||
element.as_mut().unwrap().paint(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue