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
|
@ -25,10 +25,11 @@ use gpui::{
|
||||||
anchored, deferred, div, fill, outline, point, px, quad, relative, size, svg,
|
anchored, deferred, div, fill, outline, point, px, quad, relative, size, svg,
|
||||||
transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ClipboardItem,
|
transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ClipboardItem,
|
||||||
ContentMask, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity,
|
ContentMask, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity,
|
||||||
Hitbox, Hsla, InteractiveElement, IntoElement, ModifiersChangedEvent, MouseButton,
|
GlobalElementId, Hitbox, Hsla, InteractiveElement, IntoElement, ModifiersChangedEvent,
|
||||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, ParentElement, Pixels, ScrollDelta,
|
MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, ParentElement, Pixels,
|
||||||
ScrollWheelEvent, ShapedLine, SharedString, Size, Stateful, StatefulInteractiveElement, Style,
|
ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size, Stateful,
|
||||||
Styled, TextRun, TextStyle, TextStyleRefinement, View, ViewContext, WeakView, WindowContext,
|
StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, TextStyleRefinement, View,
|
||||||
|
ViewContext, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use language::language_settings::ShowWhitespaceSetting;
|
use language::language_settings::ShowWhitespaceSetting;
|
||||||
|
@ -2270,7 +2271,7 @@ impl EditorElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.paint_layer(layout.gutter_hitbox.bounds, |cx| {
|
cx.paint_layer(layout.gutter_hitbox.bounds, |cx| {
|
||||||
cx.with_element_id(Some("gutter_fold_indicators"), |cx| {
|
cx.with_element_namespace("gutter_fold_indicators", |cx| {
|
||||||
for fold_indicator in layout.fold_indicators.iter_mut().flatten() {
|
for fold_indicator in layout.fold_indicators.iter_mut().flatten() {
|
||||||
fold_indicator.paint(cx);
|
fold_indicator.paint(cx);
|
||||||
}
|
}
|
||||||
|
@ -2419,7 +2420,7 @@ impl EditorElement {
|
||||||
};
|
};
|
||||||
cx.set_cursor_style(cursor_style, &layout.text_hitbox);
|
cx.set_cursor_style(cursor_style, &layout.text_hitbox);
|
||||||
|
|
||||||
cx.with_element_id(Some("folds"), |cx| self.paint_folds(layout, cx));
|
cx.with_element_namespace("folds", |cx| self.paint_folds(layout, cx));
|
||||||
let invisible_display_ranges = self.paint_highlights(layout, cx);
|
let invisible_display_ranges = self.paint_highlights(layout, cx);
|
||||||
self.paint_lines(&invisible_display_ranges, layout, cx);
|
self.paint_lines(&invisible_display_ranges, layout, cx);
|
||||||
self.paint_redactions(layout, cx);
|
self.paint_redactions(layout, cx);
|
||||||
|
@ -3446,7 +3447,15 @@ impl Element for EditorElement {
|
||||||
type RequestLayoutState = ();
|
type RequestLayoutState = ();
|
||||||
type PrepaintState = EditorLayout;
|
type PrepaintState = EditorLayout;
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (gpui::LayoutId, ()) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
_: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (gpui::LayoutId, ()) {
|
||||||
self.editor.update(cx, |editor, cx| {
|
self.editor.update(cx, |editor, cx| {
|
||||||
editor.set_style(self.style.clone(), cx);
|
editor.set_style(self.style.clone(), cx);
|
||||||
|
|
||||||
|
@ -3490,6 +3499,7 @@ impl Element for EditorElement {
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
|
@ -3666,19 +3676,22 @@ impl Element for EditorElement {
|
||||||
.width;
|
.width;
|
||||||
let mut scroll_width =
|
let mut scroll_width =
|
||||||
longest_line_width.max(max_visible_line_width) + overscroll.width;
|
longest_line_width.max(max_visible_line_width) + overscroll.width;
|
||||||
let mut blocks = self.build_blocks(
|
|
||||||
start_row..end_row,
|
let mut blocks = cx.with_element_namespace("blocks", |cx| {
|
||||||
&snapshot,
|
self.build_blocks(
|
||||||
&hitbox,
|
start_row..end_row,
|
||||||
&text_hitbox,
|
&snapshot,
|
||||||
&mut scroll_width,
|
&hitbox,
|
||||||
&gutter_dimensions,
|
&text_hitbox,
|
||||||
em_width,
|
&mut scroll_width,
|
||||||
gutter_dimensions.width + gutter_dimensions.margin,
|
&gutter_dimensions,
|
||||||
line_height,
|
em_width,
|
||||||
&line_layouts,
|
gutter_dimensions.width + gutter_dimensions.margin,
|
||||||
cx,
|
line_height,
|
||||||
);
|
&line_layouts,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let scroll_pixel_position = point(
|
let scroll_pixel_position = point(
|
||||||
scroll_position.x * em_width,
|
scroll_position.x * em_width,
|
||||||
|
@ -3740,7 +3753,7 @@ impl Element for EditorElement {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.with_element_id(Some("blocks"), |cx| {
|
cx.with_element_namespace("blocks", |cx| {
|
||||||
self.layout_blocks(
|
self.layout_blocks(
|
||||||
&mut blocks,
|
&mut blocks,
|
||||||
&hitbox,
|
&hitbox,
|
||||||
|
@ -3776,7 +3789,7 @@ impl Element for EditorElement {
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
let folds = cx.with_element_id(Some("folds"), |cx| {
|
let folds = cx.with_element_namespace("folds", |cx| {
|
||||||
self.layout_folds(
|
self.layout_folds(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
content_origin,
|
content_origin,
|
||||||
|
@ -3837,7 +3850,7 @@ impl Element for EditorElement {
|
||||||
let mouse_context_menu = self.layout_mouse_context_menu(cx);
|
let mouse_context_menu = self.layout_mouse_context_menu(cx);
|
||||||
|
|
||||||
let fold_indicators = if gutter_settings.folds {
|
let fold_indicators = if gutter_settings.folds {
|
||||||
cx.with_element_id(Some("gutter_fold_indicators"), |cx| {
|
cx.with_element_namespace("gutter_fold_indicators", |cx| {
|
||||||
self.layout_gutter_fold_indicators(
|
self.layout_gutter_fold_indicators(
|
||||||
fold_statuses,
|
fold_statuses,
|
||||||
line_height,
|
line_height,
|
||||||
|
@ -3930,6 +3943,7 @@ impl Element for EditorElement {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<gpui::Pixels>,
|
bounds: Bounds<gpui::Pixels>,
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
layout: &mut Self::PrepaintState,
|
layout: &mut Self::PrepaintState,
|
||||||
|
@ -3962,7 +3976,7 @@ impl Element for EditorElement {
|
||||||
self.paint_text(layout, cx);
|
self.paint_text(layout, cx);
|
||||||
|
|
||||||
if !layout.blocks.is_empty() {
|
if !layout.blocks.is_empty() {
|
||||||
cx.with_element_id(Some("blocks"), |cx| {
|
cx.with_element_namespace("blocks", |cx| {
|
||||||
self.paint_blocks(layout, cx);
|
self.paint_blocks(layout, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub trait AssetSource: 'static + Send + Sync {
|
||||||
impl AssetSource for () {
|
impl AssetSource for () {
|
||||||
fn load(&self, path: &str) -> Result<Cow<'static, [u8]>> {
|
fn load(&self, path: &str) -> Result<Cow<'static, [u8]>> {
|
||||||
Err(anyhow!(
|
Err(anyhow!(
|
||||||
"get called on empty asset provider with \"{}\"",
|
"load called on empty asset provider with \"{}\"",
|
||||||
path
|
path
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,14 +52,26 @@ pub trait Element: 'static + IntoElement {
|
||||||
/// provided to [`Element::paint`].
|
/// provided to [`Element::paint`].
|
||||||
type PrepaintState: 'static;
|
type PrepaintState: 'static;
|
||||||
|
|
||||||
|
/// If this element has a unique identifier, return it here. This is used to track elements across frames, and
|
||||||
|
/// will cause a GlobalElementId to be passed to the request_layout, prepaint, and paint methods.
|
||||||
|
///
|
||||||
|
/// The global id can in turn be used to access state that's connected to an element with the same id across
|
||||||
|
/// frames. This id must be unique among children of the first containing element with an id.
|
||||||
|
fn id(&self) -> Option<ElementId>;
|
||||||
|
|
||||||
/// Before an element can be painted, we need to know where it's going to be and how big it is.
|
/// Before an element can be painted, we need to know where it's going to be and how big it is.
|
||||||
/// Use this method to request a layout from Taffy and initialize the element's state.
|
/// Use this method to request a layout from Taffy and initialize the element's state.
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState);
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState);
|
||||||
|
|
||||||
/// After laying out an element, we need to commit its bounds to the current frame for hitbox
|
/// After laying out an element, we need to commit its bounds to the current frame for hitbox
|
||||||
/// purposes. The state argument is the same state that was returned from [`Element::request_layout()`].
|
/// purposes. The state argument is the same state that was returned from [`Element::request_layout()`].
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
|
@ -69,6 +81,7 @@ pub trait Element: 'static + IntoElement {
|
||||||
/// The state argument is the same state that was returned from [`Element::request_layout()`].
|
/// The state argument is the same state that was returned from [`Element::request_layout()`].
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
prepaint: &mut Self::PrepaintState,
|
prepaint: &mut Self::PrepaintState,
|
||||||
|
@ -164,18 +177,33 @@ impl<C: RenderOnce> Element for Component<C> {
|
||||||
type RequestLayoutState = AnyElement;
|
type RequestLayoutState = AnyElement;
|
||||||
type PrepaintState = ();
|
type PrepaintState = ();
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
let mut element = self.0.take().unwrap().render(cx).into_any_element();
|
let mut element = self.0.take().unwrap().render(cx).into_any_element();
|
||||||
let layout_id = element.request_layout(cx);
|
let layout_id = element.request_layout(cx);
|
||||||
(layout_id, element)
|
(layout_id, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(&mut self, _: Bounds<Pixels>, element: &mut AnyElement, cx: &mut WindowContext) {
|
fn prepaint(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
|
_: Bounds<Pixels>,
|
||||||
|
element: &mut AnyElement,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) {
|
||||||
element.prepaint(cx);
|
element.prepaint(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
element: &mut Self::RequestLayoutState,
|
element: &mut Self::RequestLayoutState,
|
||||||
_: &mut Self::PrepaintState,
|
_: &mut Self::PrepaintState,
|
||||||
|
@ -194,8 +222,8 @@ impl<C: RenderOnce> IntoElement for Component<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A globally unique identifier for an element, used to track state across frames.
|
/// A globally unique identifier for an element, used to track state across frames.
|
||||||
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Deref, DerefMut, Default, Debug, Eq, PartialEq, Hash)]
|
||||||
pub(crate) struct GlobalElementId(SmallVec<[ElementId; 32]>);
|
pub struct GlobalElementId(pub(crate) SmallVec<[ElementId; 32]>);
|
||||||
|
|
||||||
trait ElementObject {
|
trait ElementObject {
|
||||||
fn inner_element(&mut self) -> &mut dyn Any;
|
fn inner_element(&mut self) -> &mut dyn Any;
|
||||||
|
@ -224,17 +252,20 @@ pub struct Drawable<E: Element> {
|
||||||
enum ElementDrawPhase<RequestLayoutState, PrepaintState> {
|
enum ElementDrawPhase<RequestLayoutState, PrepaintState> {
|
||||||
#[default]
|
#[default]
|
||||||
Start,
|
Start,
|
||||||
RequestLayoutState {
|
RequestLayout {
|
||||||
layout_id: LayoutId,
|
layout_id: LayoutId,
|
||||||
|
global_id: Option<GlobalElementId>,
|
||||||
request_layout: RequestLayoutState,
|
request_layout: RequestLayoutState,
|
||||||
},
|
},
|
||||||
LayoutComputed {
|
LayoutComputed {
|
||||||
layout_id: LayoutId,
|
layout_id: LayoutId,
|
||||||
|
global_id: Option<GlobalElementId>,
|
||||||
available_space: Size<AvailableSpace>,
|
available_space: Size<AvailableSpace>,
|
||||||
request_layout: RequestLayoutState,
|
request_layout: RequestLayoutState,
|
||||||
},
|
},
|
||||||
PrepaintState {
|
Prepaint {
|
||||||
node_id: DispatchNodeId,
|
node_id: DispatchNodeId,
|
||||||
|
global_id: Option<GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
request_layout: RequestLayoutState,
|
request_layout: RequestLayoutState,
|
||||||
prepaint: PrepaintState,
|
prepaint: PrepaintState,
|
||||||
|
@ -254,9 +285,21 @@ impl<E: Element> Drawable<E> {
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> LayoutId {
|
fn request_layout(&mut self, cx: &mut WindowContext) -> LayoutId {
|
||||||
match mem::take(&mut self.phase) {
|
match mem::take(&mut self.phase) {
|
||||||
ElementDrawPhase::Start => {
|
ElementDrawPhase::Start => {
|
||||||
let (layout_id, request_layout) = self.element.request_layout(cx);
|
let global_id = self.element.id().map(|element_id| {
|
||||||
self.phase = ElementDrawPhase::RequestLayoutState {
|
cx.window.element_id_stack.push(element_id);
|
||||||
|
GlobalElementId(cx.window.element_id_stack.clone())
|
||||||
|
});
|
||||||
|
|
||||||
|
let (layout_id, request_layout) =
|
||||||
|
self.element.request_layout(global_id.as_ref(), cx);
|
||||||
|
|
||||||
|
if global_id.is_some() {
|
||||||
|
cx.window.element_id_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.phase = ElementDrawPhase::RequestLayout {
|
||||||
layout_id,
|
layout_id,
|
||||||
|
global_id,
|
||||||
request_layout,
|
request_layout,
|
||||||
};
|
};
|
||||||
layout_id
|
layout_id
|
||||||
|
@ -267,25 +310,40 @@ impl<E: Element> Drawable<E> {
|
||||||
|
|
||||||
pub(crate) fn prepaint(&mut self, cx: &mut WindowContext) {
|
pub(crate) fn prepaint(&mut self, cx: &mut WindowContext) {
|
||||||
match mem::take(&mut self.phase) {
|
match mem::take(&mut self.phase) {
|
||||||
ElementDrawPhase::RequestLayoutState {
|
ElementDrawPhase::RequestLayout {
|
||||||
layout_id,
|
layout_id,
|
||||||
|
global_id,
|
||||||
mut request_layout,
|
mut request_layout,
|
||||||
}
|
}
|
||||||
| ElementDrawPhase::LayoutComputed {
|
| ElementDrawPhase::LayoutComputed {
|
||||||
layout_id,
|
layout_id,
|
||||||
|
global_id,
|
||||||
mut request_layout,
|
mut request_layout,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
if let Some(element_id) = self.element.id() {
|
||||||
|
cx.window.element_id_stack.push(element_id);
|
||||||
|
debug_assert_eq!(global_id.as_ref().unwrap().0, cx.window.element_id_stack);
|
||||||
|
}
|
||||||
|
|
||||||
let bounds = cx.layout_bounds(layout_id);
|
let bounds = cx.layout_bounds(layout_id);
|
||||||
let node_id = cx.window.next_frame.dispatch_tree.push_node();
|
let node_id = cx.window.next_frame.dispatch_tree.push_node();
|
||||||
let prepaint = self.element.prepaint(bounds, &mut request_layout, cx);
|
let prepaint =
|
||||||
self.phase = ElementDrawPhase::PrepaintState {
|
self.element
|
||||||
|
.prepaint(global_id.as_ref(), bounds, &mut request_layout, cx);
|
||||||
|
cx.window.next_frame.dispatch_tree.pop_node();
|
||||||
|
|
||||||
|
if global_id.is_some() {
|
||||||
|
cx.window.element_id_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.phase = ElementDrawPhase::Prepaint {
|
||||||
node_id,
|
node_id,
|
||||||
|
global_id,
|
||||||
bounds,
|
bounds,
|
||||||
request_layout,
|
request_layout,
|
||||||
prepaint,
|
prepaint,
|
||||||
};
|
};
|
||||||
cx.window.next_frame.dispatch_tree.pop_node();
|
|
||||||
}
|
}
|
||||||
_ => panic!("must call request_layout before prepaint"),
|
_ => panic!("must call request_layout before prepaint"),
|
||||||
}
|
}
|
||||||
|
@ -296,16 +354,32 @@ impl<E: Element> Drawable<E> {
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> (E::RequestLayoutState, E::PrepaintState) {
|
) -> (E::RequestLayoutState, E::PrepaintState) {
|
||||||
match mem::take(&mut self.phase) {
|
match mem::take(&mut self.phase) {
|
||||||
ElementDrawPhase::PrepaintState {
|
ElementDrawPhase::Prepaint {
|
||||||
node_id,
|
node_id,
|
||||||
|
global_id,
|
||||||
bounds,
|
bounds,
|
||||||
mut request_layout,
|
mut request_layout,
|
||||||
mut prepaint,
|
mut prepaint,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
if let Some(element_id) = self.element.id() {
|
||||||
|
cx.window.element_id_stack.push(element_id);
|
||||||
|
debug_assert_eq!(global_id.as_ref().unwrap().0, cx.window.element_id_stack);
|
||||||
|
}
|
||||||
|
|
||||||
cx.window.next_frame.dispatch_tree.set_active_node(node_id);
|
cx.window.next_frame.dispatch_tree.set_active_node(node_id);
|
||||||
self.element
|
self.element.paint(
|
||||||
.paint(bounds, &mut request_layout, &mut prepaint, cx);
|
global_id.as_ref(),
|
||||||
|
bounds,
|
||||||
|
&mut request_layout,
|
||||||
|
&mut prepaint,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
|
||||||
|
if global_id.is_some() {
|
||||||
|
cx.window.element_id_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
self.phase = ElementDrawPhase::Painted;
|
self.phase = ElementDrawPhase::Painted;
|
||||||
(request_layout, prepaint)
|
(request_layout, prepaint)
|
||||||
}
|
}
|
||||||
|
@ -323,13 +397,15 @@ impl<E: Element> Drawable<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout_id = match mem::take(&mut self.phase) {
|
let layout_id = match mem::take(&mut self.phase) {
|
||||||
ElementDrawPhase::RequestLayoutState {
|
ElementDrawPhase::RequestLayout {
|
||||||
layout_id,
|
layout_id,
|
||||||
|
global_id,
|
||||||
request_layout,
|
request_layout,
|
||||||
} => {
|
} => {
|
||||||
cx.compute_layout(layout_id, available_space);
|
cx.compute_layout(layout_id, available_space);
|
||||||
self.phase = ElementDrawPhase::LayoutComputed {
|
self.phase = ElementDrawPhase::LayoutComputed {
|
||||||
layout_id,
|
layout_id,
|
||||||
|
global_id,
|
||||||
available_space,
|
available_space,
|
||||||
request_layout,
|
request_layout,
|
||||||
};
|
};
|
||||||
|
@ -337,6 +413,7 @@ impl<E: Element> Drawable<E> {
|
||||||
}
|
}
|
||||||
ElementDrawPhase::LayoutComputed {
|
ElementDrawPhase::LayoutComputed {
|
||||||
layout_id,
|
layout_id,
|
||||||
|
global_id,
|
||||||
available_space: prev_available_space,
|
available_space: prev_available_space,
|
||||||
request_layout,
|
request_layout,
|
||||||
} => {
|
} => {
|
||||||
|
@ -345,6 +422,7 @@ impl<E: Element> Drawable<E> {
|
||||||
}
|
}
|
||||||
self.phase = ElementDrawPhase::LayoutComputed {
|
self.phase = ElementDrawPhase::LayoutComputed {
|
||||||
layout_id,
|
layout_id,
|
||||||
|
global_id,
|
||||||
available_space,
|
available_space,
|
||||||
request_layout,
|
request_layout,
|
||||||
};
|
};
|
||||||
|
@ -454,13 +532,22 @@ impl Element for AnyElement {
|
||||||
type RequestLayoutState = ();
|
type RequestLayoutState = ();
|
||||||
type PrepaintState = ();
|
type PrepaintState = ();
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
_: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
let layout_id = self.request_layout(cx);
|
let layout_id = self.request_layout(cx);
|
||||||
(layout_id, ())
|
(layout_id, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_: Option<&GlobalElementId>,
|
||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
|
@ -470,6 +557,7 @@ impl Element for AnyElement {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_: Option<&GlobalElementId>,
|
||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
_: &mut Self::PrepaintState,
|
_: &mut Self::PrepaintState,
|
||||||
|
@ -506,12 +594,21 @@ impl Element for Empty {
|
||||||
type RequestLayoutState = ();
|
type RequestLayoutState = ();
|
||||||
type PrepaintState = ();
|
type PrepaintState = ();
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
(cx.request_layout(&Style::default(), None), ())
|
(cx.request_layout(&Style::default(), None), ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_state: &mut Self::RequestLayoutState,
|
_state: &mut Self::RequestLayoutState,
|
||||||
_cx: &mut WindowContext,
|
_cx: &mut WindowContext,
|
||||||
|
@ -520,6 +617,7 @@ impl Element for Empty {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_request_layout: &mut Self::RequestLayoutState,
|
_request_layout: &mut Self::RequestLayoutState,
|
||||||
_prepaint: &mut Self::PrepaintState,
|
_prepaint: &mut Self::PrepaintState,
|
||||||
|
|
|
@ -2,8 +2,8 @@ use smallvec::SmallVec;
|
||||||
use taffy::style::{Display, Position};
|
use taffy::style::{Display, Position};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
point, AnyElement, Bounds, Element, IntoElement, LayoutId, ParentElement, Pixels, Point, Size,
|
point, AnyElement, Bounds, Element, GlobalElementId, IntoElement, LayoutId, ParentElement,
|
||||||
Style, WindowContext,
|
Pixels, Point, Size, Style, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The state that the anchored element element uses to track its children.
|
/// The state that the anchored element element uses to track its children.
|
||||||
|
@ -72,8 +72,13 @@ impl Element for Anchored {
|
||||||
type RequestLayoutState = AnchoredState;
|
type RequestLayoutState = AnchoredState;
|
||||||
type PrepaintState = ();
|
type PrepaintState = ();
|
||||||
|
|
||||||
|
fn id(&self) -> Option<crate::ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn request_layout(
|
fn request_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
||||||
let child_layout_ids = self
|
let child_layout_ids = self
|
||||||
|
@ -95,6 +100,7 @@ impl Element for Anchored {
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
|
@ -177,6 +183,7 @@ impl Element for Anchored {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_bounds: crate::Bounds<crate::Pixels>,
|
_bounds: crate::Bounds<crate::Pixels>,
|
||||||
_request_layout: &mut Self::RequestLayoutState,
|
_request_layout: &mut Self::RequestLayoutState,
|
||||||
_prepaint: &mut Self::PrepaintState,
|
_prepaint: &mut Self::PrepaintState,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use crate::{AnyElement, Element, ElementId, IntoElement};
|
use crate::{AnyElement, Element, ElementId, GlobalElementId, IntoElement};
|
||||||
|
|
||||||
pub use easing::*;
|
pub use easing::*;
|
||||||
|
|
||||||
|
@ -86,15 +86,19 @@ struct AnimationState {
|
||||||
|
|
||||||
impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
||||||
type RequestLayoutState = AnyElement;
|
type RequestLayoutState = AnyElement;
|
||||||
|
|
||||||
type PrepaintState = ();
|
type PrepaintState = ();
|
||||||
|
|
||||||
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
Some(self.id.clone())
|
||||||
|
}
|
||||||
|
|
||||||
fn request_layout(
|
fn request_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
cx: &mut crate::WindowContext,
|
cx: &mut crate::WindowContext,
|
||||||
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
||||||
cx.with_element_state(Some(self.id.clone()), |state, cx| {
|
cx.with_element_state(global_id.unwrap(), |state, cx| {
|
||||||
let state = state.unwrap().unwrap_or_else(|| AnimationState {
|
let state = state.unwrap_or_else(|| AnimationState {
|
||||||
start: Instant::now(),
|
start: Instant::now(),
|
||||||
});
|
});
|
||||||
let mut delta =
|
let mut delta =
|
||||||
|
@ -130,12 +134,13 @@ impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
((element.request_layout(cx), element), Some(state))
|
((element.request_layout(cx), element), state)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_bounds: crate::Bounds<crate::Pixels>,
|
_bounds: crate::Bounds<crate::Pixels>,
|
||||||
element: &mut Self::RequestLayoutState,
|
element: &mut Self::RequestLayoutState,
|
||||||
cx: &mut crate::WindowContext,
|
cx: &mut crate::WindowContext,
|
||||||
|
@ -145,6 +150,7 @@ impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_bounds: crate::Bounds<crate::Pixels>,
|
_bounds: crate::Bounds<crate::Pixels>,
|
||||||
element: &mut Self::RequestLayoutState,
|
element: &mut Self::RequestLayoutState,
|
||||||
_: &mut Self::PrepaintState,
|
_: &mut Self::PrepaintState,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use refineable::Refineable as _;
|
use refineable::Refineable as _;
|
||||||
|
|
||||||
use crate::{Bounds, Element, IntoElement, Pixels, Style, StyleRefinement, Styled, WindowContext};
|
use crate::{
|
||||||
|
Bounds, Element, ElementId, GlobalElementId, IntoElement, Pixels, Style, StyleRefinement,
|
||||||
|
Styled, WindowContext,
|
||||||
|
};
|
||||||
|
|
||||||
/// Construct a canvas element with the given paint callback.
|
/// Construct a canvas element with the given paint callback.
|
||||||
/// Useful for adding short term custom drawing to a view.
|
/// Useful for adding short term custom drawing to a view.
|
||||||
|
@ -35,8 +38,13 @@ impl<T: 'static> Element for Canvas<T> {
|
||||||
type RequestLayoutState = Style;
|
type RequestLayoutState = Style;
|
||||||
type PrepaintState = Option<T>;
|
type PrepaintState = Option<T>;
|
||||||
|
|
||||||
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn request_layout(
|
fn request_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
||||||
let mut style = Style::default();
|
let mut style = Style::default();
|
||||||
|
@ -47,6 +55,7 @@ impl<T: 'static> Element for Canvas<T> {
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_request_layout: &mut Style,
|
_request_layout: &mut Style,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
|
@ -56,6 +65,7 @@ impl<T: 'static> Element for Canvas<T> {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
style: &mut Style,
|
style: &mut Style,
|
||||||
prepaint: &mut Self::PrepaintState,
|
prepaint: &mut Self::PrepaintState,
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::{AnyElement, Bounds, Element, IntoElement, LayoutId, Pixels, WindowContext};
|
use crate::{
|
||||||
|
AnyElement, Bounds, Element, GlobalElementId, IntoElement, LayoutId, Pixels, WindowContext,
|
||||||
|
};
|
||||||
|
|
||||||
/// Builds a `Deferred` element, which delays the layout and paint of its child.
|
/// Builds a `Deferred` element, which delays the layout and paint of its child.
|
||||||
pub fn deferred(child: impl IntoElement) -> Deferred {
|
pub fn deferred(child: impl IntoElement) -> Deferred {
|
||||||
|
@ -29,13 +31,22 @@ impl Element for Deferred {
|
||||||
type RequestLayoutState = ();
|
type RequestLayoutState = ();
|
||||||
type PrepaintState = ();
|
type PrepaintState = ();
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, ()) {
|
fn id(&self) -> Option<crate::ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, ()) {
|
||||||
let layout_id = self.child.as_mut().unwrap().request_layout(cx);
|
let layout_id = self.child.as_mut().unwrap().request_layout(cx);
|
||||||
(layout_id, ())
|
(layout_id, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_request_layout: &mut Self::RequestLayoutState,
|
_request_layout: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
|
@ -47,6 +58,7 @@ impl Element for Deferred {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_request_layout: &mut Self::RequestLayoutState,
|
_request_layout: &mut Self::RequestLayoutState,
|
||||||
_prepaint: &mut Self::PrepaintState,
|
_prepaint: &mut Self::PrepaintState,
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, size, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, Bounds,
|
point, px, size, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, Bounds,
|
||||||
ClickEvent, DispatchPhase, Element, ElementId, FocusHandle, Global, Hitbox, HitboxId,
|
ClickEvent, DispatchPhase, Element, ElementId, FocusHandle, Global, GlobalElementId, Hitbox,
|
||||||
IntoElement, IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, ModifiersChangedEvent,
|
HitboxId, IntoElement, IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId,
|
||||||
MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point,
|
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
|
||||||
Render, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task, TooltipId,
|
ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style,
|
||||||
View, Visibility, WindowContext,
|
StyleRefinement, Styled, Task, TooltipId, View, Visibility, WindowContext,
|
||||||
};
|
};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
|
@ -1123,23 +1123,34 @@ impl Element for Div {
|
||||||
type RequestLayoutState = DivFrameState;
|
type RequestLayoutState = DivFrameState;
|
||||||
type PrepaintState = Option<Hitbox>;
|
type PrepaintState = Option<Hitbox>;
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
self.interactivity.element_id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
let mut child_layout_ids = SmallVec::new();
|
let mut child_layout_ids = SmallVec::new();
|
||||||
let layout_id = self.interactivity.request_layout(cx, |style, cx| {
|
let layout_id = self
|
||||||
cx.with_text_style(style.text_style().cloned(), |cx| {
|
.interactivity
|
||||||
child_layout_ids = self
|
.request_layout(global_id, cx, |style, cx| {
|
||||||
.children
|
cx.with_text_style(style.text_style().cloned(), |cx| {
|
||||||
.iter_mut()
|
child_layout_ids = self
|
||||||
.map(|child| child.request_layout(cx))
|
.children
|
||||||
.collect::<SmallVec<_>>();
|
.iter_mut()
|
||||||
cx.request_layout(&style, child_layout_ids.iter().copied())
|
.map(|child| child.request_layout(cx))
|
||||||
})
|
.collect::<SmallVec<_>>();
|
||||||
});
|
cx.request_layout(&style, child_layout_ids.iter().copied())
|
||||||
|
})
|
||||||
|
});
|
||||||
(layout_id, DivFrameState { child_layout_ids })
|
(layout_id, DivFrameState { child_layout_ids })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
|
@ -1178,6 +1189,7 @@ impl Element for Div {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.interactivity.prepaint(
|
self.interactivity.prepaint(
|
||||||
|
global_id,
|
||||||
bounds,
|
bounds,
|
||||||
content_size,
|
content_size,
|
||||||
cx,
|
cx,
|
||||||
|
@ -1194,13 +1206,14 @@ impl Element for Div {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_request_layout: &mut Self::RequestLayoutState,
|
_request_layout: &mut Self::RequestLayoutState,
|
||||||
hitbox: &mut Option<Hitbox>,
|
hitbox: &mut Option<Hitbox>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) {
|
) {
|
||||||
self.interactivity
|
self.interactivity
|
||||||
.paint(bounds, hitbox.as_ref(), cx, |_style, cx| {
|
.paint(global_id, bounds, hitbox.as_ref(), cx, |_style, cx| {
|
||||||
for child in &mut self.children {
|
for child in &mut self.children {
|
||||||
child.paint(cx);
|
child.paint(cx);
|
||||||
}
|
}
|
||||||
|
@ -1220,7 +1233,7 @@ impl IntoElement for Div {
|
||||||
/// interactivity in the `Div` element.
|
/// interactivity in the `Div` element.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Interactivity {
|
pub struct Interactivity {
|
||||||
/// The element ID of the element
|
/// The element ID of the element. In id is required to support a stateful subset of the interactivity such as on_click.
|
||||||
pub element_id: Option<ElementId>,
|
pub element_id: Option<ElementId>,
|
||||||
/// Whether the element was clicked. This will only be present after layout.
|
/// Whether the element was clicked. This will only be present after layout.
|
||||||
pub active: Option<bool>,
|
pub active: Option<bool>,
|
||||||
|
@ -1276,11 +1289,12 @@ impl Interactivity {
|
||||||
/// Layout this element according to this interactivity state's configured styles
|
/// Layout this element according to this interactivity state's configured styles
|
||||||
pub fn request_layout(
|
pub fn request_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
f: impl FnOnce(Style, &mut WindowContext) -> LayoutId,
|
f: impl FnOnce(Style, &mut WindowContext) -> LayoutId,
|
||||||
) -> LayoutId {
|
) -> LayoutId {
|
||||||
cx.with_element_state::<InteractiveElementState, _>(
|
cx.with_optional_element_state::<InteractiveElementState, _>(
|
||||||
self.element_id.clone(),
|
global_id,
|
||||||
|element_state, cx| {
|
|element_state, cx| {
|
||||||
let mut element_state =
|
let mut element_state =
|
||||||
element_state.map(|element_state| element_state.unwrap_or_default());
|
element_state.map(|element_state| element_state.unwrap_or_default());
|
||||||
|
@ -1339,14 +1353,15 @@ impl Interactivity {
|
||||||
/// Commit the bounds of this element according to this interactivity state's configured styles.
|
/// Commit the bounds of this element according to this interactivity state's configured styles.
|
||||||
pub fn prepaint<R>(
|
pub fn prepaint<R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
content_size: Size<Pixels>,
|
content_size: Size<Pixels>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
f: impl FnOnce(&Style, Point<Pixels>, Option<Hitbox>, &mut WindowContext) -> R,
|
f: impl FnOnce(&Style, Point<Pixels>, Option<Hitbox>, &mut WindowContext) -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
self.content_size = content_size;
|
self.content_size = content_size;
|
||||||
cx.with_element_state::<InteractiveElementState, _>(
|
cx.with_optional_element_state::<InteractiveElementState, _>(
|
||||||
self.element_id.clone(),
|
global_id,
|
||||||
|element_state, cx| {
|
|element_state, cx| {
|
||||||
let mut element_state =
|
let mut element_state =
|
||||||
element_state.map(|element_state| element_state.unwrap_or_default());
|
element_state.map(|element_state| element_state.unwrap_or_default());
|
||||||
|
@ -1454,14 +1469,15 @@ impl Interactivity {
|
||||||
/// with the current scroll offset
|
/// with the current scroll offset
|
||||||
pub fn paint(
|
pub fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
hitbox: Option<&Hitbox>,
|
hitbox: Option<&Hitbox>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
f: impl FnOnce(&Style, &mut WindowContext),
|
f: impl FnOnce(&Style, &mut WindowContext),
|
||||||
) {
|
) {
|
||||||
self.hovered = hitbox.map(|hitbox| hitbox.is_hovered(cx));
|
self.hovered = hitbox.map(|hitbox| hitbox.is_hovered(cx));
|
||||||
cx.with_element_state::<InteractiveElementState, _>(
|
cx.with_optional_element_state::<InteractiveElementState, _>(
|
||||||
self.element_id.clone(),
|
global_id,
|
||||||
|element_state, cx| {
|
|element_state, cx| {
|
||||||
let mut element_state =
|
let mut element_state =
|
||||||
element_state.map(|element_state| element_state.unwrap_or_default());
|
element_state.map(|element_state| element_state.unwrap_or_default());
|
||||||
|
@ -1487,7 +1503,7 @@ impl Interactivity {
|
||||||
cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
|
cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
|
||||||
if let Some(hitbox) = hitbox {
|
if let Some(hitbox) = hitbox {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
self.paint_debug_info(hitbox, &style, cx);
|
self.paint_debug_info(global_id, hitbox, &style, cx);
|
||||||
|
|
||||||
if !cx.has_active_drag() {
|
if !cx.has_active_drag() {
|
||||||
if let Some(mouse_cursor) = style.mouse_cursor {
|
if let Some(mouse_cursor) = style.mouse_cursor {
|
||||||
|
@ -1521,13 +1537,19 @@ impl Interactivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fn paint_debug_info(&mut self, hitbox: &Hitbox, style: &Style, cx: &mut WindowContext) {
|
fn paint_debug_info(
|
||||||
if self.element_id.is_some()
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
|
hitbox: &Hitbox,
|
||||||
|
style: &Style,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) {
|
||||||
|
if global_id.is_some()
|
||||||
&& (style.debug || style.debug_below || cx.has_global::<crate::DebugBelow>())
|
&& (style.debug || style.debug_below || cx.has_global::<crate::DebugBelow>())
|
||||||
&& hitbox.is_hovered(cx)
|
&& hitbox.is_hovered(cx)
|
||||||
{
|
{
|
||||||
const FONT_SIZE: crate::Pixels = crate::Pixels(10.);
|
const FONT_SIZE: crate::Pixels = crate::Pixels(10.);
|
||||||
let element_id = format!("{:?}", self.element_id.as_ref().unwrap());
|
let element_id = format!("{:?}", global_id.unwrap());
|
||||||
let str_len = element_id.len();
|
let str_len = element_id.len();
|
||||||
|
|
||||||
let render_debug_text = |cx: &mut WindowContext| {
|
let render_debug_text = |cx: &mut WindowContext| {
|
||||||
|
@ -2064,8 +2086,13 @@ impl Interactivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the visual style for this element, based on the current bounds and the element's state.
|
/// Compute the visual style for this element, based on the current bounds and the element's state.
|
||||||
pub fn compute_style(&self, hitbox: Option<&Hitbox>, cx: &mut WindowContext) -> Style {
|
pub fn compute_style(
|
||||||
cx.with_element_state(self.element_id.clone(), |element_state, cx| {
|
&self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
|
hitbox: Option<&Hitbox>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> Style {
|
||||||
|
cx.with_optional_element_state(global_id, |element_state, cx| {
|
||||||
let mut element_state =
|
let mut element_state =
|
||||||
element_state.map(|element_state| element_state.unwrap_or_default());
|
element_state.map(|element_state| element_state.unwrap_or_default());
|
||||||
let style = self.compute_style_internal(hitbox, element_state.as_mut(), cx);
|
let style = self.compute_style_internal(hitbox, element_state.as_mut(), cx);
|
||||||
|
@ -2264,27 +2291,37 @@ where
|
||||||
type RequestLayoutState = E::RequestLayoutState;
|
type RequestLayoutState = E::RequestLayoutState;
|
||||||
type PrepaintState = E::PrepaintState;
|
type PrepaintState = E::PrepaintState;
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
self.element.request_layout(cx)
|
self.element.id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
|
self.element.request_layout(id, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
state: &mut Self::RequestLayoutState,
|
state: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> E::PrepaintState {
|
) -> E::PrepaintState {
|
||||||
self.element.prepaint(bounds, state, cx)
|
self.element.prepaint(id, bounds, state, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
prepaint: &mut Self::PrepaintState,
|
prepaint: &mut Self::PrepaintState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) {
|
) {
|
||||||
self.element.paint(bounds, request_layout, prepaint, cx)
|
self.element.paint(id, bounds, request_layout, prepaint, cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2347,27 +2384,37 @@ where
|
||||||
type RequestLayoutState = E::RequestLayoutState;
|
type RequestLayoutState = E::RequestLayoutState;
|
||||||
type PrepaintState = E::PrepaintState;
|
type PrepaintState = E::PrepaintState;
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
self.element.request_layout(cx)
|
self.element.id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
|
self.element.request_layout(id, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
state: &mut Self::RequestLayoutState,
|
state: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> E::PrepaintState {
|
) -> E::PrepaintState {
|
||||||
self.element.prepaint(bounds, state, cx)
|
self.element.prepaint(id, bounds, state, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
prepaint: &mut Self::PrepaintState,
|
prepaint: &mut Self::PrepaintState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) {
|
) {
|
||||||
self.element.paint(bounds, request_layout, prepaint, cx);
|
self.element.paint(id, bounds, request_layout, prepaint, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,10 @@ use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, size, AbsoluteLength, Asset, Bounds, DefiniteLength, DevicePixels, Element, Hitbox,
|
point, px, size, AbsoluteLength, Asset, Bounds, DefiniteLength, DevicePixels, Element,
|
||||||
ImageData, InteractiveElement, Interactivity, IntoElement, LayoutId, Length, Pixels, SharedUri,
|
ElementId, GlobalElementId, Hitbox, ImageData, InteractiveElement, Interactivity, IntoElement,
|
||||||
Size, StyleRefinement, Styled, SvgSize, UriOrPath, WindowContext,
|
LayoutId, Length, Pixels, SharedUri, Size, StyleRefinement, Styled, SvgSize, UriOrPath,
|
||||||
|
WindowContext,
|
||||||
};
|
};
|
||||||
use futures::{AsyncReadExt, Future};
|
use futures::{AsyncReadExt, Future};
|
||||||
use image::{ImageBuffer, ImageError};
|
use image::{ImageBuffer, ImageError};
|
||||||
|
@ -232,42 +233,54 @@ impl Element for Img {
|
||||||
type RequestLayoutState = ();
|
type RequestLayoutState = ();
|
||||||
type PrepaintState = Option<Hitbox>;
|
type PrepaintState = Option<Hitbox>;
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
let layout_id = self.interactivity.request_layout(cx, |mut style, cx| {
|
self.interactivity.element_id.clone()
|
||||||
if let Some(data) = self.source.data(cx) {
|
}
|
||||||
let image_size = data.size();
|
|
||||||
match (style.size.width, style.size.height) {
|
|
||||||
(Length::Auto, Length::Auto) => {
|
|
||||||
style.size = Size {
|
|
||||||
width: Length::Definite(DefiniteLength::Absolute(
|
|
||||||
AbsoluteLength::Pixels(px(image_size.width.0 as f32)),
|
|
||||||
)),
|
|
||||||
height: Length::Definite(DefiniteLength::Absolute(
|
|
||||||
AbsoluteLength::Pixels(px(image_size.height.0 as f32)),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.request_layout(&style, [])
|
fn request_layout(
|
||||||
});
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
|
let layout_id = self
|
||||||
|
.interactivity
|
||||||
|
.request_layout(global_id, cx, |mut style, cx| {
|
||||||
|
if let Some(data) = self.source.data(cx) {
|
||||||
|
let image_size = data.size();
|
||||||
|
match (style.size.width, style.size.height) {
|
||||||
|
(Length::Auto, Length::Auto) => {
|
||||||
|
style.size = Size {
|
||||||
|
width: Length::Definite(DefiniteLength::Absolute(
|
||||||
|
AbsoluteLength::Pixels(px(image_size.width.0 as f32)),
|
||||||
|
)),
|
||||||
|
height: Length::Definite(DefiniteLength::Absolute(
|
||||||
|
AbsoluteLength::Pixels(px(image_size.height.0 as f32)),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.request_layout(&style, [])
|
||||||
|
});
|
||||||
(layout_id, ())
|
(layout_id, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_request_layout: &mut Self::RequestLayoutState,
|
_request_layout: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Option<Hitbox> {
|
) -> Option<Hitbox> {
|
||||||
self.interactivity
|
self.interactivity
|
||||||
.prepaint(bounds, bounds.size, cx, |_, _, hitbox, _| hitbox)
|
.prepaint(global_id, bounds, bounds.size, cx, |_, _, hitbox, _| hitbox)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
hitbox: &mut Self::PrepaintState,
|
hitbox: &mut Self::PrepaintState,
|
||||||
|
@ -275,7 +288,7 @@ impl Element for Img {
|
||||||
) {
|
) {
|
||||||
let source = self.source.clone();
|
let source = self.source.clone();
|
||||||
self.interactivity
|
self.interactivity
|
||||||
.paint(bounds, hitbox.as_ref(), cx, |style, cx| {
|
.paint(global_id, bounds, hitbox.as_ref(), cx, |style, cx| {
|
||||||
let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
|
let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
|
||||||
|
|
||||||
if let Some(data) = source.data(cx) {
|
if let Some(data) = source.data(cx) {
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, size, AnyElement, AvailableSpace, Bounds, ContentMask, DispatchPhase, Edges,
|
point, px, size, AnyElement, AvailableSpace, Bounds, ContentMask, DispatchPhase, Edges,
|
||||||
Element, FocusHandle, Hitbox, IntoElement, Pixels, Point, ScrollWheelEvent, Size, Style,
|
Element, FocusHandle, GlobalElementId, Hitbox, IntoElement, Pixels, Point, ScrollWheelEvent,
|
||||||
StyleRefinement, Styled, WindowContext,
|
Size, Style, StyleRefinement, Styled, WindowContext,
|
||||||
};
|
};
|
||||||
use collections::VecDeque;
|
use collections::VecDeque;
|
||||||
use refineable::Refineable as _;
|
use refineable::Refineable as _;
|
||||||
|
@ -704,8 +704,13 @@ impl Element for List {
|
||||||
type RequestLayoutState = ();
|
type RequestLayoutState = ();
|
||||||
type PrepaintState = ListPrepaintState;
|
type PrepaintState = ListPrepaintState;
|
||||||
|
|
||||||
|
fn id(&self) -> Option<crate::ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn request_layout(
|
fn request_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
cx: &mut crate::WindowContext,
|
cx: &mut crate::WindowContext,
|
||||||
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
||||||
let layout_id = match self.sizing_behavior {
|
let layout_id = match self.sizing_behavior {
|
||||||
|
@ -770,6 +775,7 @@ impl Element for List {
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
|
@ -812,6 +818,7 @@ impl Element for List {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<crate::Pixels>,
|
bounds: Bounds<crate::Pixels>,
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
prepaint: &mut Self::PrepaintState,
|
prepaint: &mut Self::PrepaintState,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::Negate as _, point, px, radians, size, Bounds, Element, Hitbox, InteractiveElement,
|
geometry::Negate as _, point, px, radians, size, Bounds, Element, GlobalElementId, Hitbox,
|
||||||
Interactivity, IntoElement, LayoutId, Pixels, Point, Radians, SharedString, Size,
|
InteractiveElement, Interactivity, IntoElement, LayoutId, Pixels, Point, Radians, SharedString,
|
||||||
StyleRefinement, Styled, TransformationMatrix, WindowContext,
|
Size, StyleRefinement, Styled, TransformationMatrix, WindowContext,
|
||||||
};
|
};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
|
@ -40,25 +40,35 @@ impl Element for Svg {
|
||||||
type RequestLayoutState = ();
|
type RequestLayoutState = ();
|
||||||
type PrepaintState = Option<Hitbox>;
|
type PrepaintState = Option<Hitbox>;
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<crate::ElementId> {
|
||||||
|
self.interactivity.element_id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
let layout_id = self
|
let layout_id = self
|
||||||
.interactivity
|
.interactivity
|
||||||
.request_layout(cx, |style, cx| cx.request_layout(&style, None));
|
.request_layout(global_id, cx, |style, cx| cx.request_layout(&style, None));
|
||||||
(layout_id, ())
|
(layout_id, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_request_layout: &mut Self::RequestLayoutState,
|
_request_layout: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Option<Hitbox> {
|
) -> Option<Hitbox> {
|
||||||
self.interactivity
|
self.interactivity
|
||||||
.prepaint(bounds, bounds.size, cx, |_, _, hitbox, _| hitbox)
|
.prepaint(global_id, bounds, bounds.size, cx, |_, _, hitbox, _| hitbox)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_request_layout: &mut Self::RequestLayoutState,
|
_request_layout: &mut Self::RequestLayoutState,
|
||||||
hitbox: &mut Option<Hitbox>,
|
hitbox: &mut Option<Hitbox>,
|
||||||
|
@ -67,7 +77,7 @@ impl Element for Svg {
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interactivity
|
self.interactivity
|
||||||
.paint(bounds, hitbox.as_ref(), cx, |style, cx| {
|
.paint(global_id, bounds, hitbox.as_ref(), cx, |style, cx| {
|
||||||
if let Some((path, color)) = self.path.as_ref().zip(style.text.color) {
|
if let Some((path, color)) = self.path.as_ref().zip(style.text.color) {
|
||||||
let transformation = self
|
let transformation = self
|
||||||
.transformation
|
.transformation
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
ActiveTooltip, AnyTooltip, AnyView, Bounds, DispatchPhase, Element, ElementId, HighlightStyle,
|
ActiveTooltip, AnyTooltip, AnyView, Bounds, DispatchPhase, Element, ElementId, GlobalElementId,
|
||||||
Hitbox, IntoElement, LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point,
|
HighlightStyle, Hitbox, IntoElement, LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
|
||||||
SharedString, Size, TextRun, TextStyle, WhiteSpace, WindowContext, WrappedLine, TOOLTIP_DELAY,
|
Pixels, Point, SharedString, Size, TextRun, TextStyle, WhiteSpace, WindowContext, WrappedLine,
|
||||||
|
TOOLTIP_DELAY,
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use parking_lot::{Mutex, MutexGuard};
|
use parking_lot::{Mutex, MutexGuard};
|
||||||
|
@ -19,7 +20,15 @@ impl Element for &'static str {
|
||||||
type RequestLayoutState = TextState;
|
type RequestLayoutState = TextState;
|
||||||
type PrepaintState = ();
|
type PrepaintState = ();
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
let mut state = TextState::default();
|
let mut state = TextState::default();
|
||||||
let layout_id = state.layout(SharedString::from(*self), None, cx);
|
let layout_id = state.layout(SharedString::from(*self), None, cx);
|
||||||
(layout_id, state)
|
(layout_id, state)
|
||||||
|
@ -27,6 +36,7 @@ impl Element for &'static str {
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_text_state: &mut Self::RequestLayoutState,
|
_text_state: &mut Self::RequestLayoutState,
|
||||||
_cx: &mut WindowContext,
|
_cx: &mut WindowContext,
|
||||||
|
@ -35,6 +45,7 @@ impl Element for &'static str {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
text_state: &mut TextState,
|
text_state: &mut TextState,
|
||||||
_: &mut (),
|
_: &mut (),
|
||||||
|
@ -64,7 +75,17 @@ impl Element for SharedString {
|
||||||
type RequestLayoutState = TextState;
|
type RequestLayoutState = TextState;
|
||||||
type PrepaintState = ();
|
type PrepaintState = ();
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
|
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
let mut state = TextState::default();
|
let mut state = TextState::default();
|
||||||
let layout_id = state.layout(self.clone(), None, cx);
|
let layout_id = state.layout(self.clone(), None, cx);
|
||||||
(layout_id, state)
|
(layout_id, state)
|
||||||
|
@ -72,6 +93,7 @@ impl Element for SharedString {
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_text_state: &mut Self::RequestLayoutState,
|
_text_state: &mut Self::RequestLayoutState,
|
||||||
_cx: &mut WindowContext,
|
_cx: &mut WindowContext,
|
||||||
|
@ -80,6 +102,7 @@ impl Element for SharedString {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
text_state: &mut Self::RequestLayoutState,
|
text_state: &mut Self::RequestLayoutState,
|
||||||
_: &mut Self::PrepaintState,
|
_: &mut Self::PrepaintState,
|
||||||
|
@ -150,7 +173,17 @@ impl Element for StyledText {
|
||||||
type RequestLayoutState = TextState;
|
type RequestLayoutState = TextState;
|
||||||
type PrepaintState = ();
|
type PrepaintState = ();
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
|
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
let mut state = TextState::default();
|
let mut state = TextState::default();
|
||||||
let layout_id = state.layout(self.text.clone(), self.runs.take(), cx);
|
let layout_id = state.layout(self.text.clone(), self.runs.take(), cx);
|
||||||
(layout_id, state)
|
(layout_id, state)
|
||||||
|
@ -158,6 +191,7 @@ impl Element for StyledText {
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_state: &mut Self::RequestLayoutState,
|
_state: &mut Self::RequestLayoutState,
|
||||||
_cx: &mut WindowContext,
|
_cx: &mut WindowContext,
|
||||||
|
@ -166,6 +200,7 @@ impl Element for StyledText {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
text_state: &mut Self::RequestLayoutState,
|
text_state: &mut Self::RequestLayoutState,
|
||||||
_: &mut Self::PrepaintState,
|
_: &mut Self::PrepaintState,
|
||||||
|
@ -404,18 +439,27 @@ impl Element for InteractiveText {
|
||||||
type RequestLayoutState = TextState;
|
type RequestLayoutState = TextState;
|
||||||
type PrepaintState = Hitbox;
|
type PrepaintState = Hitbox;
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
self.text.request_layout(cx)
|
Some(self.element_id.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
|
self.text.request_layout(None, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
state: &mut Self::RequestLayoutState,
|
state: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Hitbox {
|
) -> Hitbox {
|
||||||
cx.with_element_state::<InteractiveTextState, _>(
|
cx.with_optional_element_state::<InteractiveTextState, _>(
|
||||||
Some(self.element_id.clone()),
|
global_id,
|
||||||
|interactive_state, cx| {
|
|interactive_state, cx| {
|
||||||
let interactive_state = interactive_state
|
let interactive_state = interactive_state
|
||||||
.map(|interactive_state| interactive_state.unwrap_or_default());
|
.map(|interactive_state| interactive_state.unwrap_or_default());
|
||||||
|
@ -429,7 +473,7 @@ impl Element for InteractiveText {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.text.prepaint(bounds, state, cx);
|
self.text.prepaint(None, bounds, state, cx);
|
||||||
let hitbox = cx.insert_hitbox(bounds, false);
|
let hitbox = cx.insert_hitbox(bounds, false);
|
||||||
(hitbox, interactive_state)
|
(hitbox, interactive_state)
|
||||||
},
|
},
|
||||||
|
@ -438,15 +482,16 @@ impl Element for InteractiveText {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
text_state: &mut Self::RequestLayoutState,
|
text_state: &mut Self::RequestLayoutState,
|
||||||
hitbox: &mut Hitbox,
|
hitbox: &mut Hitbox,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) {
|
) {
|
||||||
cx.with_element_state::<InteractiveTextState, _>(
|
cx.with_element_state::<InteractiveTextState, _>(
|
||||||
Some(self.element_id.clone()),
|
global_id.unwrap(),
|
||||||
|interactive_state, cx| {
|
|interactive_state, cx| {
|
||||||
let mut interactive_state = interactive_state.unwrap().unwrap_or_default();
|
let mut interactive_state = interactive_state.unwrap_or_default();
|
||||||
if let Some(click_listener) = self.click_listener.take() {
|
if let Some(click_listener) = self.click_listener.take() {
|
||||||
let mouse_position = cx.mouse_position();
|
let mouse_position = cx.mouse_position();
|
||||||
if let Some(ix) = text_state.index_for_position(bounds, mouse_position) {
|
if let Some(ix) = text_state.index_for_position(bounds, mouse_position) {
|
||||||
|
@ -576,9 +621,9 @@ impl Element for InteractiveText {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.text.paint(bounds, text_state, &mut (), cx);
|
self.text.paint(None, bounds, text_state, &mut (), cx);
|
||||||
|
|
||||||
((), Some(interactive_state))
|
((), interactive_state)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
//! elements with uniform height.
|
//! elements with uniform height.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, size, AnyElement, AvailableSpace, Bounds, ContentMask, Element, ElementId, Hitbox,
|
point, px, size, AnyElement, AvailableSpace, Bounds, ContentMask, Element, ElementId,
|
||||||
InteractiveElement, Interactivity, IntoElement, LayoutId, Pixels, Render, ScrollHandle, Size,
|
GlobalElementId, Hitbox, InteractiveElement, Interactivity, IntoElement, LayoutId, Pixels,
|
||||||
StyleRefinement, Styled, View, ViewContext, WindowContext,
|
Render, ScrollHandle, Size, StyleRefinement, Styled, View, ViewContext, WindowContext,
|
||||||
};
|
};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{cell::RefCell, cmp, ops::Range, rc::Rc};
|
use std::{cell::RefCell, cmp, ops::Range, rc::Rc};
|
||||||
|
@ -107,26 +107,38 @@ impl Element for UniformList {
|
||||||
type RequestLayoutState = UniformListFrameState;
|
type RequestLayoutState = UniformListFrameState;
|
||||||
type PrepaintState = Option<Hitbox>;
|
type PrepaintState = Option<Hitbox>;
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
self.interactivity.element_id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
let max_items = self.item_count;
|
let max_items = self.item_count;
|
||||||
let item_size = self.measure_item(None, cx);
|
let item_size = self.measure_item(None, cx);
|
||||||
let layout_id = self.interactivity.request_layout(cx, |style, cx| {
|
let layout_id = self
|
||||||
cx.request_measured_layout(style, move |known_dimensions, available_space, _cx| {
|
.interactivity
|
||||||
let desired_height = item_size.height * max_items;
|
.request_layout(global_id, cx, |style, cx| {
|
||||||
let width = known_dimensions
|
cx.request_measured_layout(style, move |known_dimensions, available_space, _cx| {
|
||||||
.width
|
let desired_height = item_size.height * max_items;
|
||||||
.unwrap_or(match available_space.width {
|
let width = known_dimensions
|
||||||
AvailableSpace::Definite(x) => x,
|
.width
|
||||||
AvailableSpace::MinContent | AvailableSpace::MaxContent => item_size.width,
|
.unwrap_or(match available_space.width {
|
||||||
});
|
AvailableSpace::Definite(x) => x,
|
||||||
|
AvailableSpace::MinContent | AvailableSpace::MaxContent => {
|
||||||
|
item_size.width
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let height = match available_space.height {
|
let height = match available_space.height {
|
||||||
AvailableSpace::Definite(height) => desired_height.min(height),
|
AvailableSpace::Definite(height) => desired_height.min(height),
|
||||||
AvailableSpace::MinContent | AvailableSpace::MaxContent => desired_height,
|
AvailableSpace::MinContent | AvailableSpace::MaxContent => desired_height,
|
||||||
};
|
};
|
||||||
size(width, height)
|
size(width, height)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
(
|
(
|
||||||
layout_id,
|
layout_id,
|
||||||
|
@ -139,11 +151,12 @@ impl Element for UniformList {
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
frame_state: &mut Self::RequestLayoutState,
|
frame_state: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Option<Hitbox> {
|
) -> Option<Hitbox> {
|
||||||
let style = self.interactivity.compute_style(None, cx);
|
let style = self.interactivity.compute_style(global_id, None, cx);
|
||||||
let border = style.border_widths.to_pixels(cx.rem_size());
|
let border = style.border_widths.to_pixels(cx.rem_size());
|
||||||
let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
|
let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
|
||||||
|
|
||||||
|
@ -167,6 +180,7 @@ impl Element for UniformList {
|
||||||
.and_then(|handle| handle.deferred_scroll_to_item.take());
|
.and_then(|handle| handle.deferred_scroll_to_item.take());
|
||||||
|
|
||||||
self.interactivity.prepaint(
|
self.interactivity.prepaint(
|
||||||
|
global_id,
|
||||||
bounds,
|
bounds,
|
||||||
content_size,
|
content_size,
|
||||||
cx,
|
cx,
|
||||||
|
@ -236,13 +250,14 @@ impl Element for UniformList {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<crate::Pixels>,
|
bounds: Bounds<crate::Pixels>,
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
hitbox: &mut Option<Hitbox>,
|
hitbox: &mut Option<Hitbox>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) {
|
) {
|
||||||
self.interactivity
|
self.interactivity
|
||||||
.paint(bounds, hitbox.as_ref(), cx, |_, cx| {
|
.paint(global_id, bounds, hitbox.as_ref(), cx, |_, cx| {
|
||||||
for item in &mut request_layout.items {
|
for item in &mut request_layout.items {
|
||||||
item.paint(cx);
|
item.paint(cx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
seal::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, Bounds, ContentMask, Element,
|
seal::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, Bounds, ContentMask, Element,
|
||||||
ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView, IntoElement, LayoutId, Model,
|
ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView, GlobalElementId, IntoElement,
|
||||||
PaintIndex, Pixels, PrepaintStateIndex, Render, Style, StyleRefinement, TextStyle, ViewContext,
|
LayoutId, Model, PaintIndex, Pixels, PrepaintStateIndex, Render, Style, StyleRefinement,
|
||||||
VisualContext, WeakModel, WindowContext,
|
TextStyle, ViewContext, VisualContext, WeakModel, WindowContext,
|
||||||
};
|
};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
|
@ -93,36 +93,40 @@ impl<V: Render> Element for View<V> {
|
||||||
type RequestLayoutState = AnyElement;
|
type RequestLayoutState = AnyElement;
|
||||||
type PrepaintState = ();
|
type PrepaintState = ();
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
Some(ElementId::View(self.entity_id()))
|
||||||
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 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(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
element: &mut Self::RequestLayoutState,
|
element: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) {
|
) {
|
||||||
cx.set_view_id(self.entity_id());
|
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(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
element: &mut Self::RequestLayoutState,
|
element: &mut Self::RequestLayoutState,
|
||||||
_: &mut Self::PrepaintState,
|
_: &mut Self::PrepaintState,
|
||||||
cx: &mut WindowContext,
|
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 RequestLayoutState = Option<AnyElement>;
|
||||||
type PrepaintState = 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() {
|
if let Some(style) = self.cached_style.as_ref() {
|
||||||
let mut root_style = Style::default();
|
let mut root_style = Style::default();
|
||||||
root_style.refine(style);
|
root_style.refine(style);
|
||||||
let layout_id = cx.request_layout(&root_style, None);
|
let layout_id = cx.request_layout(&root_style, None);
|
||||||
(layout_id, None)
|
(layout_id, None)
|
||||||
} else {
|
} else {
|
||||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
let mut element = (self.render)(self, cx);
|
||||||
let mut element = (self.render)(self, cx);
|
let layout_id = element.request_layout(cx);
|
||||||
let layout_id = element.request_layout(cx);
|
(layout_id, Some(element))
|
||||||
(layout_id, Some(element))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
element: &mut Self::RequestLayoutState,
|
element: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Option<AnyElement> {
|
) -> Option<AnyElement> {
|
||||||
cx.set_view_id(self.entity_id());
|
cx.set_view_id(self.entity_id());
|
||||||
if self.cached_style.is_some() {
|
if self.cached_style.is_some() {
|
||||||
cx.with_element_state::<AnyViewState, _>(
|
cx.with_element_state::<AnyViewState, _>(global_id.unwrap(), |element_state, cx| {
|
||||||
Some(ElementId::View(self.entity_id())),
|
let content_mask = cx.content_mask();
|
||||||
|element_state, cx| {
|
let text_style = cx.text_style();
|
||||||
let mut element_state = element_state.unwrap();
|
|
||||||
|
|
||||||
let content_mask = cx.content_mask();
|
if let Some(mut element_state) = element_state {
|
||||||
let text_style = cx.text_style();
|
if element_state.cache_key.bounds == bounds
|
||||||
|
&& element_state.cache_key.content_mask == content_mask
|
||||||
if let Some(mut element_state) = element_state {
|
&& element_state.cache_key.text_style == text_style
|
||||||
if element_state.cache_key.bounds == bounds
|
&& !cx.window.dirty_views.contains(&self.entity_id())
|
||||||
&& element_state.cache_key.content_mask == content_mask
|
&& !cx.window.refreshing
|
||||||
&& element_state.cache_key.text_style == text_style
|
{
|
||||||
&& !cx.window.dirty_views.contains(&self.entity_id())
|
let prepaint_start = cx.prepaint_index();
|
||||||
&& !cx.window.refreshing
|
cx.reuse_prepaint(element_state.prepaint_range.clone());
|
||||||
{
|
let prepaint_end = cx.prepaint_index();
|
||||||
let prepaint_start = cx.prepaint_index();
|
element_state.prepaint_range = prepaint_start..prepaint_end;
|
||||||
cx.reuse_prepaint(element_state.prepaint_range.clone());
|
return (None, element_state);
|
||||||
let prepaint_end = cx.prepaint_index();
|
|
||||||
element_state.prepaint_range = prepaint_start..prepaint_end;
|
|
||||||
return (None, Some(element_state));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let prepaint_start = cx.prepaint_index();
|
let prepaint_start = cx.prepaint_index();
|
||||||
let mut element = (self.render)(self, cx);
|
let mut element = (self.render)(self, cx);
|
||||||
element.layout_as_root(bounds.size.into(), cx);
|
element.layout_as_root(bounds.size.into(), cx);
|
||||||
element.prepaint_at(bounds.origin, cx);
|
element.prepaint_at(bounds.origin, cx);
|
||||||
let prepaint_end = cx.prepaint_index();
|
let prepaint_end = cx.prepaint_index();
|
||||||
|
|
||||||
(
|
(
|
||||||
Some(element),
|
Some(element),
|
||||||
Some(AnyViewState {
|
AnyViewState {
|
||||||
prepaint_range: prepaint_start..prepaint_end,
|
prepaint_range: prepaint_start..prepaint_end,
|
||||||
paint_range: PaintIndex::default()..PaintIndex::default(),
|
paint_range: PaintIndex::default()..PaintIndex::default(),
|
||||||
cache_key: ViewCacheKey {
|
cache_key: ViewCacheKey {
|
||||||
bounds,
|
bounds,
|
||||||
content_mask,
|
content_mask,
|
||||||
text_style,
|
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)
|
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
let mut element = element.take().unwrap();
|
||||||
|
element.prepaint(cx);
|
||||||
|
Some(element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
element: &mut Self::PrepaintState,
|
element: &mut Self::PrepaintState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) {
|
) {
|
||||||
if self.cached_style.is_some() {
|
if self.cached_style.is_some() {
|
||||||
cx.with_element_state::<AnyViewState, _>(
|
cx.with_element_state::<AnyViewState, _>(global_id.unwrap(), |element_state, cx| {
|
||||||
Some(ElementId::View(self.entity_id())),
|
let mut element_state = element_state.unwrap();
|
||||||
|element_state, cx| {
|
|
||||||
let mut element_state = element_state.unwrap().unwrap();
|
|
||||||
|
|
||||||
let paint_start = cx.paint_index();
|
let paint_start = cx.paint_index();
|
||||||
|
|
||||||
if let Some(element) = element {
|
if let Some(element) = element {
|
||||||
element.paint(cx);
|
element.paint(cx);
|
||||||
} else {
|
} else {
|
||||||
cx.reuse_paint(element_state.paint_range.clone());
|
cx.reuse_paint(element_state.paint_range.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let paint_end = cx.paint_index();
|
let paint_end = cx.paint_index();
|
||||||
element_state.paint_range = paint_start..paint_end;
|
element_state.paint_range = paint_start..paint_end;
|
||||||
|
|
||||||
((), Some(element_state))
|
((), element_state)
|
||||||
},
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
|
||||||
element.as_mut().unwrap().paint(cx);
|
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
element.as_mut().unwrap().paint(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -353,7 +353,7 @@ pub(crate) struct TooltipRequest {
|
||||||
pub(crate) struct DeferredDraw {
|
pub(crate) struct DeferredDraw {
|
||||||
priority: usize,
|
priority: usize,
|
||||||
parent_node: DispatchNodeId,
|
parent_node: DispatchNodeId,
|
||||||
element_id_stack: GlobalElementId,
|
element_id_stack: SmallVec<[ElementId; 32]>,
|
||||||
text_style_stack: Vec<TextStyleRefinement>,
|
text_style_stack: Vec<TextStyleRefinement>,
|
||||||
element: Option<AnyElement>,
|
element: Option<AnyElement>,
|
||||||
absolute_offset: Point<Pixels>,
|
absolute_offset: Point<Pixels>,
|
||||||
|
@ -454,9 +454,10 @@ impl Frame {
|
||||||
|
|
||||||
pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
|
pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
|
||||||
for element_state_key in &self.accessed_element_states {
|
for element_state_key in &self.accessed_element_states {
|
||||||
if let Some(element_state) = prev_frame.element_states.remove(element_state_key) {
|
if let Some((element_state_key, element_state)) =
|
||||||
self.element_states
|
prev_frame.element_states.remove_entry(element_state_key)
|
||||||
.insert(element_state_key.clone(), element_state);
|
{
|
||||||
|
self.element_states.insert(element_state_key, element_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +478,7 @@ pub struct Window {
|
||||||
pub(crate) viewport_size: Size<Pixels>,
|
pub(crate) viewport_size: Size<Pixels>,
|
||||||
layout_engine: Option<TaffyLayoutEngine>,
|
layout_engine: Option<TaffyLayoutEngine>,
|
||||||
pub(crate) root_view: Option<AnyView>,
|
pub(crate) root_view: Option<AnyView>,
|
||||||
pub(crate) element_id_stack: GlobalElementId,
|
pub(crate) element_id_stack: SmallVec<[ElementId; 32]>,
|
||||||
pub(crate) text_style_stack: Vec<TextStyleRefinement>,
|
pub(crate) text_style_stack: Vec<TextStyleRefinement>,
|
||||||
pub(crate) element_offset_stack: Vec<Point<Pixels>>,
|
pub(crate) element_offset_stack: Vec<Point<Pixels>>,
|
||||||
pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
|
pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||||
|
@ -745,7 +746,7 @@ impl Window {
|
||||||
viewport_size: content_size,
|
viewport_size: content_size,
|
||||||
layout_engine: Some(TaffyLayoutEngine::new()),
|
layout_engine: Some(TaffyLayoutEngine::new()),
|
||||||
root_view: None,
|
root_view: None,
|
||||||
element_id_stack: GlobalElementId::default(),
|
element_id_stack: SmallVec::default(),
|
||||||
text_style_stack: Vec::new(),
|
text_style_stack: Vec::new(),
|
||||||
element_offset_stack: Vec::new(),
|
element_offset_stack: Vec::new(),
|
||||||
content_mask_stack: Vec::new(),
|
content_mask_stack: Vec::new(),
|
||||||
|
@ -1499,7 +1500,7 @@ impl<'a> WindowContext<'a> {
|
||||||
window.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
|
window.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
|
||||||
..range.end.accessed_element_states_index]
|
..range.end.accessed_element_states_index]
|
||||||
.iter()
|
.iter()
|
||||||
.cloned(),
|
.map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)),
|
||||||
);
|
);
|
||||||
window
|
window
|
||||||
.text_system
|
.text_system
|
||||||
|
@ -1562,7 +1563,7 @@ impl<'a> WindowContext<'a> {
|
||||||
window.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
|
window.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
|
||||||
..range.end.accessed_element_states_index]
|
..range.end.accessed_element_states_index]
|
||||||
.iter()
|
.iter()
|
||||||
.cloned(),
|
.map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)),
|
||||||
);
|
);
|
||||||
window
|
window
|
||||||
.text_system
|
.text_system
|
||||||
|
@ -1630,35 +1631,6 @@ impl<'a> WindowContext<'a> {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes the given element id onto the global stack and invokes the given closure
|
|
||||||
/// with a `GlobalElementId`, which disambiguates the given id in the context of its ancestor
|
|
||||||
/// ids. Because elements are discarded and recreated on each frame, the `GlobalElementId` is
|
|
||||||
/// used to associate state with identified elements across separate frames. This method should
|
|
||||||
/// only be called as part of element drawing.
|
|
||||||
pub fn with_element_id<R>(
|
|
||||||
&mut self,
|
|
||||||
id: Option<impl Into<ElementId>>,
|
|
||||||
f: impl FnOnce(&mut Self) -> R,
|
|
||||||
) -> R {
|
|
||||||
debug_assert!(
|
|
||||||
matches!(
|
|
||||||
self.window.draw_phase,
|
|
||||||
DrawPhase::Prepaint | DrawPhase::Paint
|
|
||||||
),
|
|
||||||
"this method can only be called during request_layout, prepaint, or paint"
|
|
||||||
);
|
|
||||||
if let Some(id) = id.map(Into::into) {
|
|
||||||
let window = self.window_mut();
|
|
||||||
window.element_id_stack.push(id);
|
|
||||||
let result = f(self);
|
|
||||||
let window: &mut Window = self.borrow_mut();
|
|
||||||
window.element_id_stack.pop();
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
f(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invoke the given function with the given content mask after intersecting it
|
/// Invoke the given function with the given content mask after intersecting it
|
||||||
/// with the current mask. This method should only be called during element drawing.
|
/// with the current mask. This method should only be called during element drawing.
|
||||||
pub fn with_content_mask<R>(
|
pub fn with_content_mask<R>(
|
||||||
|
@ -1903,13 +1875,114 @@ impl<'a> WindowContext<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provide elements in the called function with a new namespace in which their identiers must be unique.
|
||||||
|
/// This can be used within a custom element to distinguish multiple sets of child elements.
|
||||||
|
pub fn with_element_namespace<R>(
|
||||||
|
&mut self,
|
||||||
|
element_id: impl Into<ElementId>,
|
||||||
|
f: impl FnOnce(&mut Self) -> R,
|
||||||
|
) -> R {
|
||||||
|
self.window.element_id_stack.push(element_id.into());
|
||||||
|
let result = f(self);
|
||||||
|
self.window.element_id_stack.pop();
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
/// Updates or initializes state for an element with the given id that lives across multiple
|
/// Updates or initializes state for an element with the given id that lives across multiple
|
||||||
/// frames. If an element with this ID existed in the rendered frame, its state will be passed
|
/// frames. If an element with this ID existed in the rendered frame, its state will be passed
|
||||||
/// to the given closure. The state returned by the closure will be stored so it can be referenced
|
/// to the given closure. The state returned by the closure will be stored so it can be referenced
|
||||||
/// when drawing the next frame. This method should only be called as part of element drawing.
|
/// when drawing the next frame. This method should only be called as part of element drawing.
|
||||||
pub fn with_element_state<S, R>(
|
pub fn with_element_state<S, R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
element_id: Option<ElementId>,
|
global_id: &GlobalElementId,
|
||||||
|
f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
|
||||||
|
) -> R
|
||||||
|
where
|
||||||
|
S: 'static,
|
||||||
|
{
|
||||||
|
debug_assert!(
|
||||||
|
matches!(
|
||||||
|
self.window.draw_phase,
|
||||||
|
DrawPhase::Prepaint | DrawPhase::Paint
|
||||||
|
),
|
||||||
|
"this method can only be called during request_layout, prepaint, or paint"
|
||||||
|
);
|
||||||
|
|
||||||
|
let key = (GlobalElementId(global_id.0.clone()), TypeId::of::<S>());
|
||||||
|
self.window
|
||||||
|
.next_frame
|
||||||
|
.accessed_element_states
|
||||||
|
.push((GlobalElementId(key.0.clone()), TypeId::of::<S>()));
|
||||||
|
|
||||||
|
if let Some(any) = self
|
||||||
|
.window
|
||||||
|
.next_frame
|
||||||
|
.element_states
|
||||||
|
.remove(&key)
|
||||||
|
.or_else(|| self.window.rendered_frame.element_states.remove(&key))
|
||||||
|
{
|
||||||
|
let ElementStateBox {
|
||||||
|
inner,
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
type_name,
|
||||||
|
} = any;
|
||||||
|
// Using the extra inner option to avoid needing to reallocate a new box.
|
||||||
|
let mut state_box = inner
|
||||||
|
.downcast::<Option<S>>()
|
||||||
|
.map_err(|_| {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
anyhow::anyhow!(
|
||||||
|
"invalid element state type for id, requested {:?}, actual: {:?}",
|
||||||
|
std::any::type_name::<S>(),
|
||||||
|
type_name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
{
|
||||||
|
anyhow::anyhow!(
|
||||||
|
"invalid element state type for id, requested {:?}",
|
||||||
|
std::any::type_name::<S>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let state = state_box.take().expect(
|
||||||
|
"reentrant call to with_element_state for the same state type and element id",
|
||||||
|
);
|
||||||
|
let (result, state) = f(Some(state), self);
|
||||||
|
state_box.replace(state);
|
||||||
|
self.window.next_frame.element_states.insert(
|
||||||
|
key,
|
||||||
|
ElementStateBox {
|
||||||
|
inner: state_box,
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
type_name,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
let (result, state) = f(None, self);
|
||||||
|
self.window.next_frame.element_states.insert(
|
||||||
|
key,
|
||||||
|
ElementStateBox {
|
||||||
|
inner: Box::new(Some(state)),
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
type_name: std::any::type_name::<S>(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of `with_element_state` that allows the element's id to be optional. This is a convenience
|
||||||
|
/// method for elements where the element id may or may not be assigned. Prefer using `with_element_state`
|
||||||
|
/// when the element is guaranteed to have an id.
|
||||||
|
pub fn with_optional_element_state<S, R>(
|
||||||
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
|
f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
|
||||||
) -> R
|
) -> R
|
||||||
where
|
where
|
||||||
|
@ -1922,90 +1995,22 @@ impl<'a> WindowContext<'a> {
|
||||||
),
|
),
|
||||||
"this method can only be called during request_layout, prepaint, or paint"
|
"this method can only be called during request_layout, prepaint, or paint"
|
||||||
);
|
);
|
||||||
let id_is_none = element_id.is_none();
|
|
||||||
self.with_element_id(element_id, |cx| {
|
|
||||||
if id_is_none {
|
|
||||||
let (result, state) = f(None, cx);
|
|
||||||
debug_assert!(state.is_none(), "you must not return an element state when passing None for the element id");
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
let global_id = cx.window().element_id_stack.clone();
|
|
||||||
let key = (global_id, TypeId::of::<S>());
|
|
||||||
cx.window.next_frame.accessed_element_states.push(key.clone());
|
|
||||||
|
|
||||||
if let Some(any) = cx
|
if let Some(global_id) = global_id {
|
||||||
.window_mut()
|
self.with_element_state(global_id, |state, cx| {
|
||||||
.next_frame
|
let (result, state) = f(Some(state), cx);
|
||||||
.element_states
|
let state =
|
||||||
.remove(&key)
|
state.expect("you must return some state when you pass some element id");
|
||||||
.or_else(|| {
|
(result, state)
|
||||||
cx.window_mut()
|
|
||||||
.rendered_frame
|
|
||||||
.element_states
|
|
||||||
.remove(&key)
|
|
||||||
})
|
|
||||||
{
|
|
||||||
let ElementStateBox {
|
|
||||||
inner,
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
type_name
|
|
||||||
} = any;
|
|
||||||
// Using the extra inner option to avoid needing to reallocate a new box.
|
|
||||||
let mut state_box = inner
|
|
||||||
.downcast::<Option<S>>()
|
|
||||||
.map_err(|_| {
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
{
|
|
||||||
anyhow::anyhow!(
|
|
||||||
"invalid element state type for id, requested_type {:?}, actual type: {:?}",
|
|
||||||
std::any::type_name::<S>(),
|
|
||||||
type_name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
{
|
|
||||||
anyhow::anyhow!(
|
|
||||||
"invalid element state type for id, requested_type {:?}",
|
|
||||||
std::any::type_name::<S>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Actual: Option<AnyElement> <- View
|
|
||||||
// Requested: () <- AnyElement
|
|
||||||
let state = state_box
|
|
||||||
.take()
|
|
||||||
.expect("reentrant call to with_element_state for the same state type and element id");
|
|
||||||
let (result, state) = f(Some(Some(state)), cx);
|
|
||||||
state_box.replace(state.expect("you must return "));
|
|
||||||
cx.window_mut()
|
|
||||||
.next_frame
|
|
||||||
.element_states
|
|
||||||
.insert(key, ElementStateBox {
|
|
||||||
inner: state_box,
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
type_name
|
|
||||||
});
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
let (result, state) = f(Some(None), cx);
|
|
||||||
cx.window_mut()
|
|
||||||
.next_frame
|
|
||||||
.element_states
|
|
||||||
.insert(key,
|
|
||||||
ElementStateBox {
|
|
||||||
inner: Box::new(Some(state.expect("you must return Some<State> when you pass some element id"))),
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
type_name: std::any::type_name::<S>()
|
|
||||||
}
|
|
||||||
|
|
||||||
);
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
let (result, state) = f(None, self);
|
||||||
|
debug_assert!(
|
||||||
|
state.is_none(),
|
||||||
|
"you must not return an element state when passing None for the global id"
|
||||||
|
);
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defers the drawing of the given element, scheduling it to be painted on top of the currently-drawn tree
|
/// Defers the drawing of the given element, scheduling it to be painted on top of the currently-drawn tree
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use editor::{CursorLayout, HighlightedRange, HighlightedRangeLine};
|
use editor::{CursorLayout, HighlightedRange, HighlightedRangeLine};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, fill, point, px, relative, AnyElement, Bounds, DispatchPhase, Element, FocusHandle, Font,
|
div, fill, point, px, relative, AnyElement, Bounds, DispatchPhase, Element, ElementId,
|
||||||
FontStyle, FontWeight, HighlightStyle, Hitbox, Hsla, InputHandler, InteractiveElement,
|
FocusHandle, Font, FontStyle, FontWeight, GlobalElementId, HighlightStyle, Hitbox, Hsla,
|
||||||
Interactivity, IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton,
|
InputHandler, InteractiveElement, Interactivity, IntoElement, LayoutId, Model, ModelContext,
|
||||||
MouseMoveEvent, Pixels, Point, ShapedLine, StatefulInteractiveElement, StrikethroughStyle,
|
ModifiersChangedEvent, MouseButton, MouseMoveEvent, Pixels, Point, ShapedLine,
|
||||||
Styled, TextRun, TextStyle, UnderlineStyle, WeakView, WhiteSpace, WindowContext,
|
StatefulInteractiveElement, StrikethroughStyle, Styled, TextRun, TextStyle, UnderlineStyle,
|
||||||
WindowTextSystem,
|
WeakView, WhiteSpace, WindowContext, WindowTextSystem,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use language::CursorShape;
|
use language::CursorShape;
|
||||||
|
@ -544,26 +544,37 @@ impl Element for TerminalElement {
|
||||||
type RequestLayoutState = ();
|
type RequestLayoutState = ();
|
||||||
type PrepaintState = LayoutState;
|
type PrepaintState = LayoutState;
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
self.interactivity.occlude_mouse();
|
self.interactivity.element_id.clone()
|
||||||
let layout_id = self.interactivity.request_layout(cx, |mut style, cx| {
|
}
|
||||||
style.size.width = relative(1.).into();
|
|
||||||
style.size.height = relative(1.).into();
|
|
||||||
let layout_id = cx.request_layout(&style, None);
|
|
||||||
|
|
||||||
layout_id
|
fn request_layout(
|
||||||
});
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
|
self.interactivity.occlude_mouse();
|
||||||
|
let layout_id = self
|
||||||
|
.interactivity
|
||||||
|
.request_layout(global_id, cx, |mut style, cx| {
|
||||||
|
style.size.width = relative(1.).into();
|
||||||
|
style.size.height = relative(1.).into();
|
||||||
|
let layout_id = cx.request_layout(&style, None);
|
||||||
|
|
||||||
|
layout_id
|
||||||
|
});
|
||||||
(layout_id, ())
|
(layout_id, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Self::PrepaintState {
|
) -> Self::PrepaintState {
|
||||||
self.interactivity
|
self.interactivity
|
||||||
.prepaint(bounds, bounds.size, cx, |_, _, hitbox, cx| {
|
.prepaint(global_id, bounds, bounds.size, cx, |_, _, hitbox, cx| {
|
||||||
let hitbox = hitbox.unwrap();
|
let hitbox = hitbox.unwrap();
|
||||||
let settings = ThemeSettings::get_global(cx).clone();
|
let settings = ThemeSettings::get_global(cx).clone();
|
||||||
|
|
||||||
|
@ -775,6 +786,7 @@ impl Element for TerminalElement {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
layout: &mut Self::PrepaintState,
|
layout: &mut Self::PrepaintState,
|
||||||
|
@ -802,7 +814,7 @@ impl Element for TerminalElement {
|
||||||
let cursor = layout.cursor.take();
|
let cursor = layout.cursor.take();
|
||||||
let hyperlink_tooltip = layout.hyperlink_tooltip.take();
|
let hyperlink_tooltip = layout.hyperlink_tooltip.take();
|
||||||
self.interactivity
|
self.interactivity
|
||||||
.paint(bounds, Some(&layout.hitbox), cx, |_, cx| {
|
.paint(global_id, bounds, Some(&layout.hitbox), cx, |_, cx| {
|
||||||
cx.handle_input(&self.focus, terminal_input_handler);
|
cx.handle_input(&self.focus, terminal_input_handler);
|
||||||
|
|
||||||
cx.on_key_event({
|
cx.on_key_event({
|
||||||
|
|
|
@ -2,9 +2,9 @@ use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
anchored, deferred, div, point, prelude::FluentBuilder, px, AnchorCorner, AnyElement, Bounds,
|
anchored, deferred, div, point, prelude::FluentBuilder, px, AnchorCorner, AnyElement, Bounds,
|
||||||
DismissEvent, DispatchPhase, Element, ElementId, HitboxId, InteractiveElement, IntoElement,
|
DismissEvent, DispatchPhase, Element, ElementId, GlobalElementId, HitboxId, InteractiveElement,
|
||||||
LayoutId, ManagedView, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext,
|
IntoElement, LayoutId, ManagedView, MouseDownEvent, ParentElement, Pixels, Point, View,
|
||||||
WindowContext,
|
VisualContext, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
@ -109,21 +109,6 @@ impl<M: ManagedView> PopoverMenu<M> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_element_state<R>(
|
|
||||||
&mut self,
|
|
||||||
cx: &mut WindowContext,
|
|
||||||
f: impl FnOnce(&mut Self, &mut PopoverMenuElementState<M>, &mut WindowContext) -> R,
|
|
||||||
) -> R {
|
|
||||||
cx.with_element_state::<PopoverMenuElementState<M>, _>(
|
|
||||||
Some(self.id.clone()),
|
|
||||||
|element_state, cx| {
|
|
||||||
let mut element_state = element_state.unwrap().unwrap_or_default();
|
|
||||||
let result = f(self, &mut element_state, cx);
|
|
||||||
(result, Some(element_state))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`PopoverMenu`]
|
/// Creates a [`PopoverMenu`]
|
||||||
|
@ -171,101 +156,118 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
|
||||||
type RequestLayoutState = PopoverMenuFrameState;
|
type RequestLayoutState = PopoverMenuFrameState;
|
||||||
type PrepaintState = Option<HitboxId>;
|
type PrepaintState = Option<HitboxId>;
|
||||||
|
|
||||||
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
Some(self.id.clone())
|
||||||
|
}
|
||||||
|
|
||||||
fn request_layout(
|
fn request_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> (gpui::LayoutId, Self::RequestLayoutState) {
|
) -> (gpui::LayoutId, Self::RequestLayoutState) {
|
||||||
self.with_element_state(cx, |this, element_state, cx| {
|
cx.with_element_state(
|
||||||
let mut menu_layout_id = None;
|
global_id.unwrap(),
|
||||||
|
|element_state: Option<PopoverMenuElementState<M>>, cx| {
|
||||||
|
let element_state = element_state.unwrap_or_default();
|
||||||
|
let mut menu_layout_id = None;
|
||||||
|
|
||||||
let menu_element = element_state.menu.borrow_mut().as_mut().map(|menu| {
|
let menu_element = element_state.menu.borrow_mut().as_mut().map(|menu| {
|
||||||
let mut anchored = anchored().snap_to_window().anchor(this.anchor);
|
let mut anchored = anchored().snap_to_window().anchor(self.anchor);
|
||||||
if let Some(child_bounds) = element_state.child_bounds {
|
if let Some(child_bounds) = element_state.child_bounds {
|
||||||
anchored = anchored.position(
|
anchored = anchored.position(
|
||||||
this.resolved_attach().corner(child_bounds) + this.resolved_offset(cx),
|
self.resolved_attach().corner(child_bounds) + self.resolved_offset(cx),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let mut element = deferred(anchored.child(div().occlude().child(menu.clone())))
|
let mut element = deferred(anchored.child(div().occlude().child(menu.clone())))
|
||||||
.with_priority(1)
|
.with_priority(1)
|
||||||
.into_any();
|
.into_any();
|
||||||
|
|
||||||
menu_layout_id = Some(element.request_layout(cx));
|
menu_layout_id = Some(element.request_layout(cx));
|
||||||
element
|
element
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut child_element = this.child_builder.take().map(|child_builder| {
|
let mut child_element = self.child_builder.take().map(|child_builder| {
|
||||||
(child_builder)(element_state.menu.clone(), this.menu_builder.clone())
|
(child_builder)(element_state.menu.clone(), self.menu_builder.clone())
|
||||||
});
|
});
|
||||||
|
|
||||||
let child_layout_id = child_element
|
let child_layout_id = child_element
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.map(|child_element| child_element.request_layout(cx));
|
.map(|child_element| child_element.request_layout(cx));
|
||||||
|
|
||||||
let layout_id = cx.request_layout(
|
let layout_id = cx.request_layout(
|
||||||
&gpui::Style::default(),
|
&gpui::Style::default(),
|
||||||
menu_layout_id.into_iter().chain(child_layout_id),
|
menu_layout_id.into_iter().chain(child_layout_id),
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
(
|
||||||
layout_id,
|
(
|
||||||
PopoverMenuFrameState {
|
layout_id,
|
||||||
child_element,
|
PopoverMenuFrameState {
|
||||||
child_layout_id,
|
child_element,
|
||||||
menu_element,
|
child_layout_id,
|
||||||
},
|
menu_element,
|
||||||
)
|
},
|
||||||
})
|
),
|
||||||
|
element_state,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Option<HitboxId> {
|
) -> Option<HitboxId> {
|
||||||
self.with_element_state(cx, |_this, element_state, cx| {
|
if let Some(child) = request_layout.child_element.as_mut() {
|
||||||
if let Some(child) = request_layout.child_element.as_mut() {
|
child.prepaint(cx);
|
||||||
child.prepaint(cx);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(menu) = request_layout.menu_element.as_mut() {
|
if let Some(menu) = request_layout.menu_element.as_mut() {
|
||||||
menu.prepaint(cx);
|
menu.prepaint(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
request_layout.child_layout_id.map(|layout_id| {
|
let hitbox_id = request_layout.child_layout_id.map(|layout_id| {
|
||||||
let bounds = cx.layout_bounds(layout_id);
|
let bounds = cx.layout_bounds(layout_id);
|
||||||
|
cx.with_element_state(global_id.unwrap(), |element_state, _cx| {
|
||||||
|
let mut element_state: PopoverMenuElementState<M> = element_state.unwrap();
|
||||||
element_state.child_bounds = Some(bounds);
|
element_state.child_bounds = Some(bounds);
|
||||||
cx.insert_hitbox(bounds, false).id
|
((), element_state)
|
||||||
})
|
});
|
||||||
})
|
|
||||||
|
cx.insert_hitbox(bounds, false).id
|
||||||
|
});
|
||||||
|
|
||||||
|
hitbox_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_: Bounds<gpui::Pixels>,
|
_: Bounds<gpui::Pixels>,
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
child_hitbox: &mut Option<HitboxId>,
|
child_hitbox: &mut Option<HitboxId>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) {
|
) {
|
||||||
self.with_element_state(cx, |_this, _element_state, cx| {
|
if let Some(mut child) = request_layout.child_element.take() {
|
||||||
if let Some(mut child) = request_layout.child_element.take() {
|
child.paint(cx);
|
||||||
child.paint(cx);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(mut menu) = request_layout.menu_element.take() {
|
if let Some(mut menu) = request_layout.menu_element.take() {
|
||||||
menu.paint(cx);
|
menu.paint(cx);
|
||||||
|
|
||||||
if let Some(child_hitbox) = *child_hitbox {
|
if let Some(child_hitbox) = *child_hitbox {
|
||||||
// Mouse-downing outside the menu dismisses it, so we don't
|
// Mouse-downing outside the menu dismisses it, so we don't
|
||||||
// want a click on the toggle to re-open it.
|
// want a click on the toggle to re-open it.
|
||||||
cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
|
cx.on_mouse_event(move |_: &MouseDownEvent, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble && child_hitbox.is_hovered(cx) {
|
if phase == DispatchPhase::Bubble && child_hitbox.is_hovered(cx) {
|
||||||
cx.stop_propagation()
|
cx.stop_propagation()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@ use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
anchored, deferred, div, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase,
|
anchored, deferred, div, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase,
|
||||||
Element, ElementId, Hitbox, InteractiveElement, IntoElement, LayoutId, ManagedView,
|
Element, ElementId, GlobalElementId, Hitbox, InteractiveElement, IntoElement, LayoutId,
|
||||||
MouseButton, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext, WindowContext,
|
ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext,
|
||||||
|
WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct RightClickMenu<M: ManagedView> {
|
pub struct RightClickMenu<M: ManagedView> {
|
||||||
|
@ -40,11 +41,12 @@ impl<M: ManagedView> RightClickMenu<M> {
|
||||||
|
|
||||||
fn with_element_state<R>(
|
fn with_element_state<R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: &GlobalElementId,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
f: impl FnOnce(&mut Self, &mut MenuHandleElementState<M>, &mut WindowContext) -> R,
|
f: impl FnOnce(&mut Self, &mut MenuHandleElementState<M>, &mut WindowContext) -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
cx.with_element_state::<MenuHandleElementState<M>, _>(
|
cx.with_optional_element_state::<MenuHandleElementState<M>, _>(
|
||||||
Some(self.id.clone()),
|
Some(global_id),
|
||||||
|element_state, cx| {
|
|element_state, cx| {
|
||||||
let mut element_state = element_state.unwrap().unwrap_or_default();
|
let mut element_state = element_state.unwrap().unwrap_or_default();
|
||||||
let result = f(self, &mut element_state, cx);
|
let result = f(self, &mut element_state, cx);
|
||||||
|
@ -103,11 +105,16 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
|
||||||
type RequestLayoutState = RequestLayoutState;
|
type RequestLayoutState = RequestLayoutState;
|
||||||
type PrepaintState = PrepaintState;
|
type PrepaintState = PrepaintState;
|
||||||
|
|
||||||
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
Some(self.id.clone())
|
||||||
|
}
|
||||||
|
|
||||||
fn request_layout(
|
fn request_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
id: Option<&GlobalElementId>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> (gpui::LayoutId, Self::RequestLayoutState) {
|
) -> (gpui::LayoutId, Self::RequestLayoutState) {
|
||||||
self.with_element_state(cx, |this, element_state, cx| {
|
self.with_element_state(id.unwrap(), cx, |this, element_state, cx| {
|
||||||
let mut menu_layout_id = None;
|
let mut menu_layout_id = None;
|
||||||
|
|
||||||
let menu_element = element_state.menu.borrow_mut().as_mut().map(|menu| {
|
let menu_element = element_state.menu.borrow_mut().as_mut().map(|menu| {
|
||||||
|
@ -152,38 +159,38 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> PrepaintState {
|
) -> PrepaintState {
|
||||||
cx.with_element_id(Some(self.id.clone()), |cx| {
|
let hitbox = cx.insert_hitbox(bounds, false);
|
||||||
let hitbox = cx.insert_hitbox(bounds, false);
|
|
||||||
|
|
||||||
if let Some(child) = request_layout.child_element.as_mut() {
|
if let Some(child) = request_layout.child_element.as_mut() {
|
||||||
child.prepaint(cx);
|
child.prepaint(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(menu) = request_layout.menu_element.as_mut() {
|
if let Some(menu) = request_layout.menu_element.as_mut() {
|
||||||
menu.prepaint(cx);
|
menu.prepaint(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrepaintState {
|
PrepaintState {
|
||||||
hitbox,
|
hitbox,
|
||||||
child_bounds: request_layout
|
child_bounds: request_layout
|
||||||
.child_layout_id
|
.child_layout_id
|
||||||
.map(|layout_id| cx.layout_bounds(layout_id)),
|
.map(|layout_id| cx.layout_bounds(layout_id)),
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
id: Option<&GlobalElementId>,
|
||||||
_bounds: Bounds<gpui::Pixels>,
|
_bounds: Bounds<gpui::Pixels>,
|
||||||
request_layout: &mut Self::RequestLayoutState,
|
request_layout: &mut Self::RequestLayoutState,
|
||||||
prepaint_state: &mut Self::PrepaintState,
|
prepaint_state: &mut Self::PrepaintState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) {
|
) {
|
||||||
self.with_element_state(cx, |this, element_state, cx| {
|
self.with_element_state(id.unwrap(), cx, |this, element_state, cx| {
|
||||||
if let Some(mut child) = request_layout.child_element.take() {
|
if let Some(mut child) = request_layout.child_element.take() {
|
||||||
child.paint(cx);
|
child.paint(cx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -597,9 +597,9 @@ mod element {
|
||||||
use std::{cell::RefCell, iter, rc::Rc, sync::Arc};
|
use std::{cell::RefCell, iter, rc::Rc, sync::Arc};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
px, relative, Along, AnyElement, Axis, Bounds, Element, IntoElement, MouseDownEvent,
|
px, relative, Along, AnyElement, Axis, Bounds, Element, GlobalElementId, IntoElement,
|
||||||
MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Size, Style, WeakView,
|
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Size, Style,
|
||||||
WindowContext,
|
WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use gpui::{CursorStyle, Hitbox};
|
use gpui::{CursorStyle, Hitbox};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
@ -795,8 +795,13 @@ mod element {
|
||||||
type RequestLayoutState = ();
|
type RequestLayoutState = ();
|
||||||
type PrepaintState = PaneAxisLayout;
|
type PrepaintState = PaneAxisLayout;
|
||||||
|
|
||||||
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
Some(self.basis.into())
|
||||||
|
}
|
||||||
|
|
||||||
fn request_layout(
|
fn request_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_global_id: Option<&GlobalElementId>,
|
||||||
cx: &mut ui::prelude::WindowContext,
|
cx: &mut ui::prelude::WindowContext,
|
||||||
) -> (gpui::LayoutId, Self::RequestLayoutState) {
|
) -> (gpui::LayoutId, Self::RequestLayoutState) {
|
||||||
let mut style = Style::default();
|
let mut style = Style::default();
|
||||||
|
@ -810,17 +815,16 @@ mod element {
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_state: &mut Self::RequestLayoutState,
|
_state: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> PaneAxisLayout {
|
) -> PaneAxisLayout {
|
||||||
let dragged_handle = cx.with_element_state::<Rc<RefCell<Option<usize>>>, _>(
|
let dragged_handle = cx.with_element_state::<Rc<RefCell<Option<usize>>>, _>(
|
||||||
Some(self.basis.into()),
|
global_id.unwrap(),
|
||||||
|state, _cx| {
|
|state, _cx| {
|
||||||
let state = state
|
let state = state.unwrap_or_else(|| Rc::new(RefCell::new(None)));
|
||||||
.unwrap()
|
(state.clone(), state)
|
||||||
.unwrap_or_else(|| Rc::new(RefCell::new(None)));
|
|
||||||
(state.clone(), Some(state))
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let flexes = self.flexes.lock().clone();
|
let flexes = self.flexes.lock().clone();
|
||||||
|
@ -897,6 +901,7 @@ mod element {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
bounds: gpui::Bounds<ui::prelude::Pixels>,
|
bounds: gpui::Bounds<ui::prelude::Pixels>,
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
layout: &mut Self::PrepaintState,
|
layout: &mut Self::PrepaintState,
|
||||||
|
|
|
@ -158,8 +158,10 @@ impl Toolbar {
|
||||||
{
|
{
|
||||||
let location = item.set_active_pane_item(self.active_item.as_deref(), cx);
|
let location = item.set_active_pane_item(self.active_item.as_deref(), cx);
|
||||||
cx.subscribe(&item, |this, item, event, cx| {
|
cx.subscribe(&item, |this, item, event, cx| {
|
||||||
if let Some((_, current_location)) =
|
if let Some((_, current_location)) = this
|
||||||
this.items.iter_mut().find(|(i, _)| i.id() == item.id())
|
.items
|
||||||
|
.iter_mut()
|
||||||
|
.find(|(i, _)| i.id() == item.entity_id())
|
||||||
{
|
{
|
||||||
match event {
|
match event {
|
||||||
ToolbarItemEvent::ChangeLocation(new_location) => {
|
ToolbarItemEvent::ChangeLocation(new_location) => {
|
||||||
|
|
|
@ -28,9 +28,10 @@ use futures::{
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, canvas, impl_actions, point, relative, size, Action, AnyElement, AnyView, AnyWeakView,
|
actions, canvas, impl_actions, point, relative, size, Action, AnyElement, AnyView, AnyWeakView,
|
||||||
AppContext, AsyncAppContext, AsyncWindowContext, Bounds, DevicePixels, DragMoveEvent,
|
AppContext, AsyncAppContext, AsyncWindowContext, Bounds, DevicePixels, DragMoveEvent,
|
||||||
Entity as _, EntityId, EventEmitter, FocusHandle, FocusableView, Global, KeyContext, Keystroke,
|
ElementId, Entity as _, EntityId, EventEmitter, FocusHandle, FocusableView, Global,
|
||||||
LayoutId, ManagedView, Model, ModelContext, PathPromptOptions, Point, PromptLevel, Render,
|
GlobalElementId, KeyContext, Keystroke, LayoutId, ManagedView, Model, ModelContext,
|
||||||
Size, Subscription, Task, View, WeakView, WindowHandle, WindowOptions,
|
PathPromptOptions, Point, PromptLevel, Render, Size, Subscription, Task, View, WeakView,
|
||||||
|
WindowHandle, WindowOptions,
|
||||||
};
|
};
|
||||||
use item::{
|
use item::{
|
||||||
FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, PreviewTabsSettings,
|
FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, PreviewTabsSettings,
|
||||||
|
@ -5060,7 +5061,15 @@ impl Element for DisconnectedOverlay {
|
||||||
type RequestLayoutState = AnyElement;
|
type RequestLayoutState = AnyElement;
|
||||||
type PrepaintState = ();
|
type PrepaintState = ();
|
||||||
|
|
||||||
fn request_layout(&mut self, cx: &mut WindowContext) -> (LayoutId, Self::RequestLayoutState) {
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (LayoutId, Self::RequestLayoutState) {
|
||||||
let mut background = cx.theme().colors().elevated_surface_background;
|
let mut background = cx.theme().colors().elevated_surface_background;
|
||||||
background.fade_out(0.2);
|
background.fade_out(0.2);
|
||||||
let mut overlay = div()
|
let mut overlay = div()
|
||||||
|
@ -5083,6 +5092,7 @@ impl Element for DisconnectedOverlay {
|
||||||
|
|
||||||
fn prepaint(
|
fn prepaint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
overlay: &mut Self::RequestLayoutState,
|
overlay: &mut Self::RequestLayoutState,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
|
@ -5093,6 +5103,7 @@ impl Element for DisconnectedOverlay {
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_id: Option<&GlobalElementId>,
|
||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
overlay: &mut Self::RequestLayoutState,
|
overlay: &mut Self::RequestLayoutState,
|
||||||
_: &mut Self::PrepaintState,
|
_: &mut Self::PrepaintState,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue