Compare commits
16 Commits
debug-view
...
before-pai
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2205430814 | ||
|
|
fa410ec150 | ||
|
|
504ea1aaea | ||
|
|
d75f1e64b8 | ||
|
|
1358758226 | ||
|
|
9de4dc12dd | ||
|
|
7ae13c9753 | ||
|
|
d4bae0475f | ||
|
|
72a4e525d7 | ||
|
|
15f4e93102 | ||
|
|
dbfb588e3e | ||
|
|
8ead209099 | ||
|
|
eb14932950 | ||
|
|
d3756cdab3 | ||
|
|
d4c54f3479 | ||
|
|
c024526db2 |
@@ -1094,31 +1094,37 @@ impl AssistantPanel {
|
|||||||
let view = cx.view().clone();
|
let view = cx.view().clone();
|
||||||
let scroll_handle = self.saved_conversations_scroll_handle.clone();
|
let scroll_handle = self.saved_conversations_scroll_handle.clone();
|
||||||
let conversation_count = self.saved_conversations.len();
|
let conversation_count = self.saved_conversations.len();
|
||||||
canvas(
|
todo!("replace canvas")
|
||||||
move |bounds, cx| {
|
// canvas(
|
||||||
let mut saved_conversations = uniform_list(
|
// move |_, cx| {
|
||||||
view,
|
// let saved_conversations = uniform_list(
|
||||||
"saved_conversations",
|
// view.clone(),
|
||||||
conversation_count,
|
// "saved_conversations",
|
||||||
|this, range, cx| {
|
// conversation_count,
|
||||||
range
|
// |this, range, cx| {
|
||||||
.map(|ix| this.render_saved_conversation(ix, cx))
|
// range
|
||||||
.collect()
|
// .map(|ix| this.render_saved_conversation(ix, cx))
|
||||||
},
|
// .collect()
|
||||||
)
|
// },
|
||||||
.track_scroll(scroll_handle)
|
// )
|
||||||
.into_any_element();
|
// .track_scroll(scroll_handle.clone())
|
||||||
saved_conversations.layout(
|
// .into_any_element();
|
||||||
bounds.origin,
|
// saved_conversations.layout(absolute_offset, available_space, cx)
|
||||||
bounds.size.map(AvailableSpace::Definite),
|
// // compute layout for saved conversations
|
||||||
cx,
|
// saved_conversations
|
||||||
);
|
// },
|
||||||
saved_conversations
|
// move |bounds, saved_conversations, cx| {
|
||||||
},
|
// saved_conversations.layout(
|
||||||
|_bounds, mut saved_conversations, cx| saved_conversations.paint(cx),
|
// bounds.origin,
|
||||||
)
|
// bounds.size.map(AvailableSpace::Definite),
|
||||||
.size_full()
|
// cx,
|
||||||
.into_any_element()
|
// );
|
||||||
|
// saved_conversations
|
||||||
|
// },
|
||||||
|
// |_bounds, mut saved_conversations, cx| saved_conversations.paint(cx),
|
||||||
|
// )
|
||||||
|
// .size_full()
|
||||||
|
// .into_any_element()
|
||||||
} else if let Some(editor) = self.active_conversation_editor() {
|
} else if let Some(editor) = self.active_conversation_editor() {
|
||||||
let editor = editor.clone();
|
let editor = editor.clone();
|
||||||
let conversation = editor.read(cx).conversation.clone();
|
let conversation = editor.read(cx).conversation.clone();
|
||||||
|
|||||||
@@ -2834,34 +2834,31 @@ fn render_tree_branch(is_last: bool, overdraw: bool, cx: &mut WindowContext) ->
|
|||||||
let thickness = px(1.);
|
let thickness = px(1.);
|
||||||
let color = cx.theme().colors().text;
|
let color = cx.theme().colors().text;
|
||||||
|
|
||||||
canvas(
|
canvas(move |bounds, cx| {
|
||||||
|_, _| {},
|
let start_x = (bounds.left() + bounds.right() - thickness) / 2.;
|
||||||
move |bounds, _, cx| {
|
let start_y = (bounds.top() + bounds.bottom() - thickness) / 2.;
|
||||||
let start_x = (bounds.left() + bounds.right() - thickness) / 2.;
|
let right = bounds.right();
|
||||||
let start_y = (bounds.top() + bounds.bottom() - thickness) / 2.;
|
let top = bounds.top();
|
||||||
let right = bounds.right();
|
|
||||||
let top = bounds.top();
|
|
||||||
|
|
||||||
cx.paint_quad(fill(
|
cx.paint_quad(fill(
|
||||||
Bounds::from_corners(
|
Bounds::from_corners(
|
||||||
point(start_x, top),
|
point(start_x, top),
|
||||||
point(
|
point(
|
||||||
start_x + thickness,
|
start_x + thickness,
|
||||||
if is_last {
|
if is_last {
|
||||||
start_y
|
start_y
|
||||||
} else {
|
} else {
|
||||||
bounds.bottom() + if overdraw { px(1.) } else { px(0.) }
|
bounds.bottom() + if overdraw { px(1.) } else { px(0.) }
|
||||||
},
|
},
|
||||||
),
|
|
||||||
),
|
),
|
||||||
color,
|
),
|
||||||
));
|
color,
|
||||||
cx.paint_quad(fill(
|
));
|
||||||
Bounds::from_corners(point(start_x, start_y), point(right, start_y + thickness)),
|
cx.paint_quad(fill(
|
||||||
color,
|
Bounds::from_corners(point(start_x, start_y), point(right, start_y + thickness)),
|
||||||
));
|
color,
|
||||||
},
|
));
|
||||||
)
|
})
|
||||||
.w(width)
|
.w(width)
|
||||||
.h(line_height)
|
.h(line_height)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -318,26 +318,23 @@ impl Render for CollabTitlebarItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_color_ribbon(color: Hsla) -> impl Element {
|
fn render_color_ribbon(color: Hsla) -> impl Element {
|
||||||
canvas(
|
canvas(move |bounds, cx| {
|
||||||
move |_, _| {},
|
let height = bounds.size.height;
|
||||||
move |bounds, _, cx| {
|
let horizontal_offset = height;
|
||||||
let height = bounds.size.height;
|
let vertical_offset = px(height.0 / 2.0);
|
||||||
let horizontal_offset = height;
|
let mut path = Path::new(bounds.lower_left());
|
||||||
let vertical_offset = px(height.0 / 2.0);
|
path.curve_to(
|
||||||
let mut path = Path::new(bounds.lower_left());
|
bounds.origin + point(horizontal_offset, vertical_offset),
|
||||||
path.curve_to(
|
bounds.origin + point(px(0.0), vertical_offset),
|
||||||
bounds.origin + point(horizontal_offset, vertical_offset),
|
);
|
||||||
bounds.origin + point(px(0.0), vertical_offset),
|
path.line_to(bounds.upper_right() + point(-horizontal_offset, vertical_offset));
|
||||||
);
|
path.curve_to(
|
||||||
path.line_to(bounds.upper_right() + point(-horizontal_offset, vertical_offset));
|
bounds.lower_right(),
|
||||||
path.curve_to(
|
bounds.upper_right() + point(px(0.0), vertical_offset),
|
||||||
bounds.lower_right(),
|
);
|
||||||
bounds.upper_right() + point(px(0.0), vertical_offset),
|
path.line_to(bounds.lower_left());
|
||||||
);
|
cx.paint_path(path, color);
|
||||||
path.line_to(bounds.lower_left());
|
})
|
||||||
cx.paint_path(path, color);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.h_1()
|
.h_1()
|
||||||
.w_full()
|
.w_full()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -476,8 +476,8 @@ pub struct Editor {
|
|||||||
+ Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
|
+ Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
last_bounds: Option<Bounds<Pixels>>,
|
last_layout_bounds: Option<Bounds<Pixels>>,
|
||||||
expect_bounds_change: Option<Bounds<Pixels>>,
|
expect_layout_bounds_change: Option<Bounds<Pixels>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -1492,8 +1492,8 @@ impl Editor {
|
|||||||
inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
|
inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
|
||||||
gutter_hovered: false,
|
gutter_hovered: false,
|
||||||
pixel_position_of_newest_cursor: None,
|
pixel_position_of_newest_cursor: None,
|
||||||
last_bounds: None,
|
last_layout_bounds: None,
|
||||||
expect_bounds_change: None,
|
expect_layout_bounds_change: None,
|
||||||
gutter_width: Default::default(),
|
gutter_width: Default::default(),
|
||||||
style: None,
|
style: None,
|
||||||
show_cursor_names: false,
|
show_cursor_names: false,
|
||||||
@@ -10778,7 +10778,8 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, _is_valid: bool) -> Ren
|
|||||||
|
|
||||||
let icon_size = buttons(&diagnostic, cx.block_id)
|
let icon_size = buttons(&diagnostic, cx.block_id)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
.measure(AvailableSpace::min_size(), cx);
|
.layout(AvailableSpace::min_size(), cx)
|
||||||
|
.size;
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.id(cx.block_id)
|
.id(cx.block_id)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1173,7 +1173,7 @@ impl SearchableItem for Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_bar_visibility_changed(&mut self, _visible: bool, _cx: &mut ViewContext<Self>) {
|
fn search_bar_visibility_changed(&mut self, _visible: bool, _cx: &mut ViewContext<Self>) {
|
||||||
self.expect_bounds_change = self.last_bounds;
|
self.expect_layout_bounds_change = self.last_layout_bounds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ impl Editor {
|
|||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
let mut scroll_position = self.scroll_manager.scroll_position(&display_map);
|
let mut scroll_position = self.scroll_manager.scroll_position(&display_map);
|
||||||
let original_y = scroll_position.y;
|
let original_y = scroll_position.y;
|
||||||
if let Some(last_bounds) = self.expect_bounds_change.take() {
|
if let Some(last_bounds) = self.expect_layout_bounds_change.take() {
|
||||||
if scroll_position.y != 0. {
|
if scroll_position.y != 0. {
|
||||||
scroll_position.y += (bounds.top() - last_bounds.top()) / line_height;
|
scroll_position.y += (bounds.top() - last_bounds.top()) / line_height;
|
||||||
if scroll_position.y < 0. {
|
if scroll_position.y < 0. {
|
||||||
|
|||||||
@@ -936,24 +936,25 @@ impl Render for ExtensionsPage {
|
|||||||
let view = cx.view().clone();
|
let view = cx.view().clone();
|
||||||
let scroll_handle = self.list.clone();
|
let scroll_handle = self.list.clone();
|
||||||
this.child(
|
this.child(
|
||||||
canvas(
|
// canvas(
|
||||||
move |bounds, cx| {
|
// move |bounds, cx| {
|
||||||
let mut list = uniform_list::<_, ExtensionCard, _>(
|
// let mut list = uniform_list::<_, ExtensionCard, _>(
|
||||||
view,
|
// view,
|
||||||
"entries",
|
// "entries",
|
||||||
count,
|
// count,
|
||||||
Self::render_extensions,
|
// Self::render_extensions,
|
||||||
)
|
// )
|
||||||
.size_full()
|
// .size_full()
|
||||||
.pb_4()
|
// .pb_4()
|
||||||
.track_scroll(scroll_handle)
|
// .track_scroll(scroll_handle)
|
||||||
.into_any_element();
|
// .into_any_element();
|
||||||
list.layout(bounds.origin, bounds.size.into(), cx);
|
// list.layout(bounds.origin, bounds.size.into(), cx);
|
||||||
list
|
// list
|
||||||
},
|
// },
|
||||||
|_bounds, mut list, cx| list.paint(cx),
|
// |_bounds, mut list, cx| list.paint(cx),
|
||||||
)
|
// )
|
||||||
.size_full(),
|
// .size_full(),
|
||||||
|
todo!("replace canvas"),
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -734,7 +734,8 @@ impl VisualTestContext {
|
|||||||
self.update(|cx| {
|
self.update(|cx| {
|
||||||
cx.with_element_context(|cx| {
|
cx.with_element_context(|cx| {
|
||||||
let mut element = f(cx);
|
let mut element = f(cx);
|
||||||
element.layout(origin, space, cx);
|
element.layout(space, cx);
|
||||||
|
cx.with_element_offset(origin, |cx| element.before_paint(cx));
|
||||||
element.paint(cx);
|
element.paint(cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
util::FluentBuilder, ArenaBox, AvailableSpace, Bounds, DispatchNodeId, ElementContext,
|
util::FluentBuilder, ArenaBox, AvailableSpace, Bounds, DispatchNodeId, ElementContext,
|
||||||
ElementId, LayoutId, Pixels, Point, Size, ViewContext, WindowContext, ELEMENT_ARENA,
|
ElementId, LayoutId, Pixels, Size, ViewContext, WindowContext, ELEMENT_ARENA,
|
||||||
};
|
};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
pub(crate) use smallvec::SmallVec;
|
pub(crate) use smallvec::SmallVec;
|
||||||
@@ -45,33 +45,46 @@ use std::{any::Any, fmt::Debug, mem, ops::DerefMut};
|
|||||||
/// for more details.
|
/// for more details.
|
||||||
pub trait Element: 'static + IntoElement {
|
pub trait Element: 'static + IntoElement {
|
||||||
/// The type of state returned from [`Element::before_layout`]. A mutable reference to this state is subsequently
|
/// The type of state returned from [`Element::before_layout`]. A mutable reference to this state is subsequently
|
||||||
/// provided to [`Element::after_layout`] and [`Element::paint`].
|
/// provided to [`Element::after_layout`], [`Element::before_paint`] and [`Element::paint`].
|
||||||
type BeforeLayout: 'static;
|
type BeforeLayout: 'static;
|
||||||
|
|
||||||
/// The type of state returned from [`Element::after_layout`]. A mutable reference to this state is subsequently
|
/// The type of state returned from [`Element::after_layout`]. A mutable reference to this state is subsequently
|
||||||
/// provided to [`Element::paint`].
|
/// provided to [`Element::before_paint`] and [`Element::paint`].
|
||||||
type AfterLayout: 'static;
|
type AfterLayout: 'static;
|
||||||
|
|
||||||
|
/// The type of state returned from [`Element::before_paint`]. A mutable reference to this state is subsequently
|
||||||
|
/// provided to [`Element::paint`].
|
||||||
|
type BeforePaint: 'static;
|
||||||
|
|
||||||
/// 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 before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout);
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout);
|
||||||
|
|
||||||
/// After laying out an element, we need to commit its bounds to the current frame for hitbox
|
/// todo!()
|
||||||
/// purposes. The state argument is the same state that was returned from [`Element::before_layout()`].
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Self::AfterLayout;
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout);
|
||||||
|
|
||||||
|
/// Before painting an element, we need to commit its bounds to the current frame for hitbox
|
||||||
|
/// purposes.
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
before_layout: &mut Self::BeforeLayout,
|
||||||
|
after_layout: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> Self::BeforePaint;
|
||||||
|
|
||||||
/// Once layout has been completed, this method will be called to paint the element to the screen.
|
/// Once layout has been completed, this method will be called to paint the element to the screen.
|
||||||
/// The state argument is the same state that was returned from [`Element::before_layout()`].
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
after_layout: &mut Self::AfterLayout,
|
after_layout: &mut Self::AfterLayout,
|
||||||
|
before_paint: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -163,6 +176,7 @@ impl<C: RenderOnce> Component<C> {
|
|||||||
impl<C: RenderOnce> Element for Component<C> {
|
impl<C: RenderOnce> Element for Component<C> {
|
||||||
type BeforeLayout = AnyElement;
|
type BeforeLayout = AnyElement;
|
||||||
type AfterLayout = ();
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
let mut element = self
|
let mut element = self
|
||||||
@@ -176,12 +190,23 @@ impl<C: RenderOnce> Element for Component<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
element: &mut Self::BeforeLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
let bounds = element.after_layout(cx);
|
||||||
|
(bounds, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
element: &mut AnyElement,
|
element: &mut AnyElement,
|
||||||
|
_: &mut Self::AfterLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
element.after_layout(cx);
|
element.before_paint(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
@@ -189,6 +214,7 @@ impl<C: RenderOnce> Element for Component<C> {
|
|||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
element: &mut Self::BeforeLayout,
|
element: &mut Self::BeforeLayout,
|
||||||
_: &mut Self::AfterLayout,
|
_: &mut Self::AfterLayout,
|
||||||
|
_: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
element.paint(cx)
|
element.paint(cx)
|
||||||
@@ -212,46 +238,59 @@ trait ElementObject {
|
|||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> LayoutId;
|
fn before_layout(&mut self, cx: &mut ElementContext) -> LayoutId;
|
||||||
|
|
||||||
fn after_layout(&mut self, cx: &mut ElementContext);
|
fn after_layout(&mut self, cx: &mut ElementContext) -> Option<Bounds<Pixels>>;
|
||||||
|
|
||||||
|
fn before_paint(&mut self, cx: &mut ElementContext);
|
||||||
|
|
||||||
fn paint(&mut self, cx: &mut ElementContext);
|
fn paint(&mut self, cx: &mut ElementContext);
|
||||||
|
|
||||||
fn measure(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
available_space: Size<AvailableSpace>,
|
available_space: Size<AvailableSpace>,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Size<Pixels>;
|
) -> ElementMeasurement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around an implementer of [`Element`] that allows it to be drawn in a window.
|
/// A wrapper around an implementer of [`Element`] that allows it to be drawn in a window.
|
||||||
pub struct Drawable<E: Element> {
|
pub struct Drawable<E: Element> {
|
||||||
/// The drawn element.
|
/// The drawn element.
|
||||||
pub element: E,
|
pub element: E,
|
||||||
phase: ElementDrawPhase<E::BeforeLayout, E::AfterLayout>,
|
phase: ElementDrawPhase<E::BeforeLayout, E::AfterLayout, E::BeforePaint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
enum ElementDrawPhase<BeforeLayout, AfterLayout> {
|
enum ElementDrawPhase<BeforeLayout, AfterLayout, BeforePaint> {
|
||||||
#[default]
|
#[default]
|
||||||
Start,
|
Start,
|
||||||
BeforeLayout {
|
BeforeLayout {
|
||||||
layout_id: LayoutId,
|
layout_id: LayoutId,
|
||||||
before_layout: BeforeLayout,
|
before_layout: BeforeLayout,
|
||||||
},
|
},
|
||||||
LayoutComputed {
|
|
||||||
layout_id: LayoutId,
|
|
||||||
available_space: Size<AvailableSpace>,
|
|
||||||
before_layout: BeforeLayout,
|
|
||||||
},
|
|
||||||
AfterLayout {
|
AfterLayout {
|
||||||
|
layout_id: LayoutId,
|
||||||
|
available_space: Option<Size<AvailableSpace>>,
|
||||||
|
before_layout: BeforeLayout,
|
||||||
|
after_layout: AfterLayout,
|
||||||
|
},
|
||||||
|
BeforePaint {
|
||||||
node_id: DispatchNodeId,
|
node_id: DispatchNodeId,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
before_layout: BeforeLayout,
|
before_layout: BeforeLayout,
|
||||||
after_layout: AfterLayout,
|
after_layout: AfterLayout,
|
||||||
|
before_paint: BeforePaint,
|
||||||
},
|
},
|
||||||
Painted,
|
Painted,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// todo!()
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ElementMeasurement {
|
||||||
|
/// The size of the element.
|
||||||
|
pub size: Size<Pixels>,
|
||||||
|
/// The bounds for the focus target inside of the measured element.
|
||||||
|
pub focus_target_bounds: Option<Bounds<Pixels>>,
|
||||||
|
}
|
||||||
|
|
||||||
/// A wrapper around an implementer of [`Element`] that allows it to be drawn in a window.
|
/// A wrapper around an implementer of [`Element`] that allows it to be drawn in a window.
|
||||||
impl<E: Element> Drawable<E> {
|
impl<E: Element> Drawable<E> {
|
||||||
fn new(element: E) -> Self {
|
fn new(element: E) -> Self {
|
||||||
@@ -275,92 +314,133 @@ impl<E: Element> Drawable<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(&mut self, cx: &mut ElementContext) {
|
fn after_layout(&mut self, cx: &mut ElementContext) -> Option<Bounds<Pixels>> {
|
||||||
match mem::take(&mut self.phase) {
|
match mem::take(&mut self.phase) {
|
||||||
ElementDrawPhase::BeforeLayout {
|
ElementDrawPhase::BeforeLayout {
|
||||||
layout_id,
|
layout_id,
|
||||||
mut before_layout,
|
mut before_layout,
|
||||||
}
|
|
||||||
| ElementDrawPhase::LayoutComputed {
|
|
||||||
layout_id,
|
|
||||||
mut before_layout,
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
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 (focus_target_bounds, after_layout) =
|
||||||
let after_layout = self.element.after_layout(bounds, &mut before_layout, cx);
|
self.element.after_layout(bounds, &mut before_layout, cx);
|
||||||
self.phase = ElementDrawPhase::AfterLayout {
|
self.phase = ElementDrawPhase::AfterLayout {
|
||||||
node_id,
|
layout_id,
|
||||||
bounds,
|
available_space: None,
|
||||||
before_layout,
|
before_layout,
|
||||||
after_layout,
|
after_layout,
|
||||||
};
|
};
|
||||||
cx.window.next_frame.dispatch_tree.pop_node();
|
|
||||||
|
focus_target_bounds
|
||||||
}
|
}
|
||||||
_ => panic!("must call before_layout before after_layout"),
|
_ => panic!("must call before_layout before after_layout"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(&mut self, cx: &mut ElementContext) -> E::BeforeLayout {
|
fn before_paint(&mut self, cx: &mut ElementContext) {
|
||||||
match mem::take(&mut self.phase) {
|
match mem::take(&mut self.phase) {
|
||||||
ElementDrawPhase::AfterLayout {
|
ElementDrawPhase::AfterLayout {
|
||||||
node_id,
|
layout_id,
|
||||||
bounds,
|
|
||||||
mut before_layout,
|
mut before_layout,
|
||||||
mut after_layout,
|
mut after_layout,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
cx.window.next_frame.dispatch_tree.set_active_node(node_id);
|
let bounds = cx.layout_bounds(layout_id);
|
||||||
self.element
|
let node_id = cx.window.next_frame.dispatch_tree.push_node();
|
||||||
.paint(bounds, &mut before_layout, &mut after_layout, cx);
|
let before_paint =
|
||||||
self.phase = ElementDrawPhase::Painted;
|
self.element
|
||||||
before_layout
|
.before_paint(bounds, &mut before_layout, &mut after_layout, cx);
|
||||||
|
self.phase = ElementDrawPhase::BeforePaint {
|
||||||
|
node_id,
|
||||||
|
bounds,
|
||||||
|
before_layout,
|
||||||
|
after_layout,
|
||||||
|
before_paint,
|
||||||
|
};
|
||||||
|
cx.window.next_frame.dispatch_tree.pop_node();
|
||||||
}
|
}
|
||||||
_ => panic!("must call after_layout before paint"),
|
_ => panic!("must call after_layout before before_paint"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(
|
fn paint(&mut self, cx: &mut ElementContext) -> E::BeforeLayout {
|
||||||
|
match mem::take(&mut self.phase) {
|
||||||
|
ElementDrawPhase::BeforePaint {
|
||||||
|
node_id,
|
||||||
|
bounds,
|
||||||
|
mut before_layout,
|
||||||
|
mut after_layout,
|
||||||
|
mut before_paint,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
cx.window.next_frame.dispatch_tree.set_active_node(node_id);
|
||||||
|
self.element.paint(
|
||||||
|
bounds,
|
||||||
|
&mut before_layout,
|
||||||
|
&mut after_layout,
|
||||||
|
&mut before_paint,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
self.phase = ElementDrawPhase::Painted;
|
||||||
|
before_layout
|
||||||
|
}
|
||||||
|
_ => panic!("must call before_paint before paint"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
available_space: Size<AvailableSpace>,
|
available_space: Size<AvailableSpace>,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Size<Pixels> {
|
) -> ElementMeasurement {
|
||||||
if matches!(&self.phase, ElementDrawPhase::Start) {
|
if matches!(&self.phase, ElementDrawPhase::Start) {
|
||||||
self.before_layout(cx);
|
self.before_layout(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout_id = match mem::take(&mut self.phase) {
|
match mem::take(&mut self.phase) {
|
||||||
ElementDrawPhase::BeforeLayout {
|
ElementDrawPhase::BeforeLayout {
|
||||||
layout_id,
|
layout_id,
|
||||||
before_layout,
|
mut before_layout,
|
||||||
} => {
|
} => {
|
||||||
cx.compute_layout(layout_id, available_space);
|
cx.compute_layout(layout_id, available_space);
|
||||||
self.phase = ElementDrawPhase::LayoutComputed {
|
let bounds = cx.layout_bounds(layout_id);
|
||||||
|
let (focus_target_bounds, after_layout) =
|
||||||
|
self.element.after_layout(bounds, &mut before_layout, cx);
|
||||||
|
self.phase = ElementDrawPhase::AfterLayout {
|
||||||
layout_id,
|
layout_id,
|
||||||
available_space,
|
available_space: Some(available_space),
|
||||||
before_layout,
|
before_layout,
|
||||||
|
after_layout,
|
||||||
};
|
};
|
||||||
layout_id
|
ElementMeasurement {
|
||||||
|
size: bounds.size,
|
||||||
|
focus_target_bounds,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ElementDrawPhase::LayoutComputed {
|
ElementDrawPhase::AfterLayout {
|
||||||
layout_id,
|
layout_id,
|
||||||
available_space: prev_available_space,
|
available_space: prev_available_space,
|
||||||
before_layout,
|
mut before_layout,
|
||||||
|
..
|
||||||
} => {
|
} => {
|
||||||
if available_space != prev_available_space {
|
if Some(available_space) != prev_available_space {
|
||||||
cx.compute_layout(layout_id, available_space);
|
cx.compute_layout(layout_id, available_space);
|
||||||
}
|
}
|
||||||
self.phase = ElementDrawPhase::LayoutComputed {
|
let bounds = cx.layout_bounds(layout_id);
|
||||||
|
let (focus_target_bounds, after_layout) =
|
||||||
|
self.element.after_layout(bounds, &mut before_layout, cx);
|
||||||
|
self.phase = ElementDrawPhase::AfterLayout {
|
||||||
layout_id,
|
layout_id,
|
||||||
available_space,
|
available_space: Some(available_space),
|
||||||
before_layout,
|
before_layout,
|
||||||
|
after_layout,
|
||||||
};
|
};
|
||||||
layout_id
|
ElementMeasurement {
|
||||||
|
size: bounds.size,
|
||||||
|
focus_target_bounds,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("cannot measure after painting"),
|
_ => panic!("cannot layout after painting"),
|
||||||
};
|
}
|
||||||
|
|
||||||
cx.layout_bounds(layout_id).size
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,20 +457,24 @@ where
|
|||||||
Drawable::before_layout(self, cx)
|
Drawable::before_layout(self, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(&mut self, cx: &mut ElementContext) {
|
fn after_layout(&mut self, cx: &mut ElementContext) -> Option<Bounds<Pixels>> {
|
||||||
Drawable::after_layout(self, cx);
|
Drawable::after_layout(self, cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(&mut self, cx: &mut ElementContext) {
|
||||||
|
Drawable::before_paint(self, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(&mut self, cx: &mut ElementContext) {
|
fn paint(&mut self, cx: &mut ElementContext) {
|
||||||
Drawable::paint(self, cx);
|
Drawable::paint(self, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
available_space: Size<AvailableSpace>,
|
available_space: Size<AvailableSpace>,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Size<Pixels> {
|
) -> ElementMeasurement {
|
||||||
Drawable::measure(self, available_space, cx)
|
Drawable::layout(self, available_space, cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,41 +504,35 @@ impl AnyElement {
|
|||||||
self.0.before_layout(cx)
|
self.0.before_layout(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commits the element bounds of this [AnyElement] for hitbox purposes.
|
/// todo!()
|
||||||
pub fn after_layout(&mut self, cx: &mut ElementContext) {
|
pub fn after_layout(&mut self, cx: &mut ElementContext) -> Option<Bounds<Pixels>> {
|
||||||
self.0.after_layout(cx)
|
self.0.after_layout(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Commits the element bounds of this [AnyElement] for hitbox purposes.
|
||||||
|
pub fn before_paint(&mut self, cx: &mut ElementContext) {
|
||||||
|
self.0.before_paint(cx)
|
||||||
|
}
|
||||||
|
|
||||||
/// Paints the element stored in this `AnyElement`.
|
/// Paints the element stored in this `AnyElement`.
|
||||||
pub fn paint(&mut self, cx: &mut ElementContext) {
|
pub fn paint(&mut self, cx: &mut ElementContext) {
|
||||||
self.0.paint(cx)
|
self.0.paint(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes this element and performs layout within the given available space to determine its size.
|
/// Initializes this element and performs layout within the given available space to determine its size.
|
||||||
pub fn measure(
|
|
||||||
&mut self,
|
|
||||||
available_space: Size<AvailableSpace>,
|
|
||||||
cx: &mut ElementContext,
|
|
||||||
) -> Size<Pixels> {
|
|
||||||
self.0.measure(available_space, cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes this element, performs layout if needed and commits its bounds for hitbox purposes.
|
|
||||||
pub fn layout(
|
pub fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
absolute_offset: Point<Pixels>,
|
|
||||||
available_space: Size<AvailableSpace>,
|
available_space: Size<AvailableSpace>,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Size<Pixels> {
|
) -> ElementMeasurement {
|
||||||
let size = self.measure(available_space, cx);
|
self.0.layout(available_space, cx)
|
||||||
cx.with_absolute_element_offset(absolute_offset, |cx| self.after_layout(cx));
|
|
||||||
size
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element for AnyElement {
|
impl Element for AnyElement {
|
||||||
type BeforeLayout = ();
|
type BeforeLayout = ();
|
||||||
type AfterLayout = ();
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
let layout_id = self.before_layout(cx);
|
let layout_id = self.before_layout(cx);
|
||||||
@@ -466,8 +544,19 @@ impl Element for AnyElement {
|
|||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
_: &mut Self::BeforeLayout,
|
_: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
let bounds = self.after_layout(cx);
|
||||||
|
(bounds, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
_: Bounds<Pixels>,
|
||||||
|
_: &mut Self::BeforeLayout,
|
||||||
|
_: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
self.after_layout(cx)
|
self.before_paint(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
@@ -475,6 +564,7 @@ impl Element for AnyElement {
|
|||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
_: &mut Self::BeforeLayout,
|
_: &mut Self::BeforeLayout,
|
||||||
_: &mut Self::AfterLayout,
|
_: &mut Self::AfterLayout,
|
||||||
|
_: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
self.paint(cx)
|
self.paint(cx)
|
||||||
@@ -507,6 +597,7 @@ impl IntoElement for Empty {
|
|||||||
impl Element for Empty {
|
impl Element for Empty {
|
||||||
type BeforeLayout = ();
|
type BeforeLayout = ();
|
||||||
type AfterLayout = ();
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
(cx.request_layout(&crate::Style::default(), None), ())
|
(cx.request_layout(&crate::Style::default(), None), ())
|
||||||
@@ -515,7 +606,17 @@ impl Element for Empty {
|
|||||||
fn after_layout(
|
fn after_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_state: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
(None, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
_cx: &mut ElementContext,
|
_cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -525,6 +626,7 @@ impl Element for Empty {
|
|||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_before_layout: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
_after_layout: &mut Self::AfterLayout,
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
_before_paint: &mut Self::BeforePaint,
|
||||||
_cx: &mut ElementContext,
|
_cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ impl ParentElement for Anchored {
|
|||||||
impl Element for Anchored {
|
impl Element for Anchored {
|
||||||
type BeforeLayout = AnchoredState;
|
type BeforeLayout = AnchoredState;
|
||||||
type AfterLayout = ();
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (crate::LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (crate::LayoutId, Self::BeforeLayout) {
|
||||||
let child_layout_ids = self
|
let child_layout_ids = self
|
||||||
@@ -91,9 +92,27 @@ impl Element for Anchored {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
let mut focus_target_bounds = None;
|
||||||
|
for child in &mut self.children {
|
||||||
|
if let Some(child_focus_target_bounds) = child.after_layout(cx) {
|
||||||
|
if focus_target_bounds.is_none() {
|
||||||
|
focus_target_bounds = Some(child_focus_target_bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(focus_target_bounds, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
if before_layout.child_layout_ids.is_empty() {
|
if before_layout.child_layout_ids.is_empty() {
|
||||||
@@ -167,7 +186,7 @@ impl Element for Anchored {
|
|||||||
|
|
||||||
cx.with_element_offset(offset, |cx| {
|
cx.with_element_offset(offset, |cx| {
|
||||||
for child in &mut self.children {
|
for child in &mut self.children {
|
||||||
child.after_layout(cx);
|
child.before_paint(cx);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -177,6 +196,7 @@ impl Element for Anchored {
|
|||||||
_bounds: crate::Bounds<crate::Pixels>,
|
_bounds: crate::Bounds<crate::Pixels>,
|
||||||
_before_layout: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
_after_layout: &mut Self::AfterLayout,
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
_before_paint: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
for child in &mut self.children {
|
for child in &mut self.children {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use crate::{AnyElement, Element, ElementId, IntoElement};
|
use crate::{AnyElement, Bounds, Element, ElementId, IntoElement, Pixels};
|
||||||
|
|
||||||
pub use easing::*;
|
pub use easing::*;
|
||||||
|
|
||||||
@@ -86,8 +86,8 @@ struct AnimationState {
|
|||||||
|
|
||||||
impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
||||||
type BeforeLayout = AnyElement;
|
type BeforeLayout = AnyElement;
|
||||||
|
|
||||||
type AfterLayout = ();
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(
|
fn before_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -136,18 +136,29 @@ impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
|||||||
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
_bounds: crate::Bounds<crate::Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
element: &mut Self::BeforeLayout,
|
element: &mut Self::BeforeLayout,
|
||||||
cx: &mut crate::ElementContext,
|
cx: &mut crate::ElementContext,
|
||||||
) -> Self::AfterLayout {
|
) -> (Option<Bounds<Pixels>>, ()) {
|
||||||
element.after_layout(cx);
|
(element.after_layout(cx), ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
element: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
cx: &mut crate::ElementContext,
|
||||||
|
) -> Self::BeforePaint {
|
||||||
|
element.before_paint(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
_bounds: crate::Bounds<crate::Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
element: &mut Self::BeforeLayout,
|
element: &mut Self::BeforeLayout,
|
||||||
_: &mut Self::AfterLayout,
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
_before_paint: &mut Self::BeforePaint,
|
||||||
cx: &mut crate::ElementContext,
|
cx: &mut crate::ElementContext,
|
||||||
) {
|
) {
|
||||||
element.paint(cx);
|
element.paint(cx);
|
||||||
|
|||||||
@@ -4,12 +4,8 @@ use crate::{Bounds, Element, ElementContext, IntoElement, Pixels, Style, StyleRe
|
|||||||
|
|
||||||
/// 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.
|
||||||
pub fn canvas<T>(
|
pub fn canvas(paint: impl 'static + FnOnce(Bounds<Pixels>, &mut ElementContext)) -> Canvas {
|
||||||
after_layout: impl 'static + FnOnce(Bounds<Pixels>, &mut ElementContext) -> T,
|
|
||||||
paint: impl 'static + FnOnce(Bounds<Pixels>, T, &mut ElementContext),
|
|
||||||
) -> Canvas<T> {
|
|
||||||
Canvas {
|
Canvas {
|
||||||
after_layout: Some(Box::new(after_layout)),
|
|
||||||
paint: Some(Box::new(paint)),
|
paint: Some(Box::new(paint)),
|
||||||
style: StyleRefinement::default(),
|
style: StyleRefinement::default(),
|
||||||
}
|
}
|
||||||
@@ -17,13 +13,12 @@ pub fn canvas<T>(
|
|||||||
|
|
||||||
/// A canvas element, meant for accessing the low level paint API without defining a whole
|
/// A canvas element, meant for accessing the low level paint API without defining a whole
|
||||||
/// custom element
|
/// custom element
|
||||||
pub struct Canvas<T> {
|
pub struct Canvas {
|
||||||
after_layout: Option<Box<dyn FnOnce(Bounds<Pixels>, &mut ElementContext) -> T>>,
|
paint: Option<Box<dyn FnOnce(Bounds<Pixels>, &mut ElementContext)>>,
|
||||||
paint: Option<Box<dyn FnOnce(Bounds<Pixels>, T, &mut ElementContext)>>,
|
|
||||||
style: StyleRefinement,
|
style: StyleRefinement,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> IntoElement for Canvas<T> {
|
impl IntoElement for Canvas {
|
||||||
type Element = Self;
|
type Element = Self;
|
||||||
|
|
||||||
fn into_element(self) -> Self::Element {
|
fn into_element(self) -> Self::Element {
|
||||||
@@ -31,9 +26,10 @@ impl<T: 'static> IntoElement for Canvas<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> Element for Canvas<T> {
|
impl Element for Canvas {
|
||||||
type BeforeLayout = Style;
|
type BeforeLayout = Style;
|
||||||
type AfterLayout = Option<T>;
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (crate::LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (crate::LayoutId, Self::BeforeLayout) {
|
||||||
let mut style = Style::default();
|
let mut style = Style::default();
|
||||||
@@ -44,28 +40,35 @@ impl<T: 'static> Element for Canvas<T> {
|
|||||||
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
(None, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
_before_layout: &mut Style,
|
_before_layout: &mut Style,
|
||||||
cx: &mut ElementContext,
|
_after_layout: &mut Self::AfterLayout,
|
||||||
) -> Option<T> {
|
_cx: &mut ElementContext,
|
||||||
Some(self.after_layout.take().unwrap()(bounds, cx))
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
style: &mut Style,
|
style: &mut Style,
|
||||||
after_layout: &mut Self::AfterLayout,
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
_before_paint: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
let after_layout = after_layout.take().unwrap();
|
style.paint(bounds, cx, |cx| (self.paint.take().unwrap())(bounds, cx));
|
||||||
style.paint(bounds, cx, |cx| {
|
|
||||||
(self.paint.take().unwrap())(bounds, after_layout, cx)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Styled for Canvas<T> {
|
impl Styled for Canvas {
|
||||||
fn style(&mut self) -> &mut crate::StyleRefinement {
|
fn style(&mut self) -> &mut crate::StyleRefinement {
|
||||||
&mut self.style
|
&mut self.style
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ impl Deferred {
|
|||||||
impl Element for Deferred {
|
impl Element for Deferred {
|
||||||
type BeforeLayout = ();
|
type BeforeLayout = ();
|
||||||
type AfterLayout = ();
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, ()) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, ()) {
|
||||||
let layout_id = self.child.as_mut().unwrap().before_layout(cx);
|
let layout_id = self.child.as_mut().unwrap().before_layout(cx);
|
||||||
@@ -39,6 +40,17 @@ impl Element for Deferred {
|
|||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_before_layout: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
let bounds = self.child.as_mut().unwrap().after_layout(cx);
|
||||||
|
(bounds, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
let child = self.child.take().unwrap();
|
let child = self.child.take().unwrap();
|
||||||
let element_offset = cx.element_offset();
|
let element_offset = cx.element_offset();
|
||||||
@@ -50,6 +62,7 @@ impl Element for Deferred {
|
|||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_before_layout: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
_after_layout: &mut Self::AfterLayout,
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
_before_paint: &mut Self::BeforePaint,
|
||||||
_cx: &mut ElementContext,
|
_cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1121,7 +1121,8 @@ impl ParentElement for Div {
|
|||||||
|
|
||||||
impl Element for Div {
|
impl Element for Div {
|
||||||
type BeforeLayout = DivFrameState;
|
type BeforeLayout = DivFrameState;
|
||||||
type AfterLayout = Option<Hitbox>;
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = Option<Hitbox>;
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
let mut child_layout_ids = SmallVec::new();
|
let mut child_layout_ids = SmallVec::new();
|
||||||
@@ -1143,7 +1144,7 @@ impl Element for Div {
|
|||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Option<Hitbox> {
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
let mut child_min = point(Pixels::MAX, Pixels::MAX);
|
let mut child_min = point(Pixels::MAX, Pixels::MAX);
|
||||||
let mut child_max = Point::default();
|
let mut child_max = Point::default();
|
||||||
let content_size = if before_layout.child_layout_ids.is_empty() {
|
let content_size = if before_layout.child_layout_ids.is_empty() {
|
||||||
@@ -1177,25 +1178,49 @@ impl Element for Div {
|
|||||||
(child_max - child_min).into()
|
(child_max - child_min).into()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.interactivity.after_layout(
|
let focus_target_bounds = self.interactivity.after_layout(
|
||||||
bounds,
|
bounds,
|
||||||
content_size,
|
content_size,
|
||||||
cx,
|
cx,
|
||||||
|_style, scroll_offset, hitbox, cx| {
|
|_, scroll_offset, mut focus_target_bounds, cx| {
|
||||||
cx.with_element_offset(scroll_offset, |cx| {
|
cx.with_element_offset(scroll_offset, |cx| {
|
||||||
for child in &mut self.children {
|
for child in &mut self.children {
|
||||||
child.after_layout(cx);
|
if let Some(child_focus_bounds) = child.after_layout(cx) {
|
||||||
|
focus_target_bounds = Some(child_focus_bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
focus_target_bounds
|
||||||
|
})
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
(focus_target_bounds, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> Option<Hitbox> {
|
||||||
|
self.interactivity
|
||||||
|
.before_paint(bounds, cx, |_style, scroll_offset, hitbox, cx| {
|
||||||
|
cx.with_element_offset(scroll_offset, |cx| {
|
||||||
|
for child in &mut self.children {
|
||||||
|
child.before_paint(cx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
hitbox
|
hitbox
|
||||||
},
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_before_layout: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
hitbox: &mut Option<Hitbox>,
|
hitbox: &mut Option<Hitbox>,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
@@ -1336,13 +1361,13 @@ impl Interactivity {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commit the bounds of this element according to this interactivity state's configured styles.
|
/// todo!()
|
||||||
pub fn after_layout<R>(
|
pub fn after_layout<R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
content_size: Size<Pixels>,
|
content_size: Size<Pixels>,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
f: impl FnOnce(&Style, Point<Pixels>, Option<Hitbox>, &mut ElementContext) -> R,
|
f: impl FnOnce(&Style, Point<Pixels>, Option<Bounds<Pixels>>, &mut ElementContext) -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
self.content_size = content_size;
|
self.content_size = content_size;
|
||||||
cx.with_element_state::<InteractiveElementState, _>(
|
cx.with_element_state::<InteractiveElementState, _>(
|
||||||
@@ -1367,6 +1392,40 @@ impl Interactivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cx.with_text_style(style.text_style().cloned(), |cx| {
|
||||||
|
cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
|
||||||
|
let scroll_offset = self.clamp_scroll_position(bounds, &style, cx);
|
||||||
|
let focus_target_bounds =
|
||||||
|
self.tracked_focus_handle.as_ref().and_then(|focus_handle| {
|
||||||
|
if focus_handle.is_focused(cx) {
|
||||||
|
Some(bounds)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = f(&style, scroll_offset, focus_target_bounds, cx);
|
||||||
|
(result, element_state)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Commit the bounds of this element according to this interactivity state's configured styles.
|
||||||
|
pub fn before_paint<R>(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
f: impl FnOnce(&Style, Point<Pixels>, Option<Hitbox>, &mut ElementContext) -> R,
|
||||||
|
) -> R {
|
||||||
|
cx.with_element_state::<InteractiveElementState, _>(
|
||||||
|
self.element_id.clone(),
|
||||||
|
|element_state, cx| {
|
||||||
|
let mut element_state =
|
||||||
|
element_state.map(|element_state| element_state.unwrap_or_default());
|
||||||
|
let style = self.compute_style_internal(None, element_state.as_mut(), cx);
|
||||||
|
|
||||||
cx.with_text_style(style.text_style().cloned(), |cx| {
|
cx.with_text_style(style.text_style().cloned(), |cx| {
|
||||||
cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
|
cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
|
||||||
let hitbox = if self.should_insert_hitbox(&style) {
|
let hitbox = if self.should_insert_hitbox(&style) {
|
||||||
@@ -1375,7 +1434,11 @@ impl Interactivity {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let scroll_offset = self.clamp_scroll_position(bounds, &style, cx);
|
let scroll_offset = self
|
||||||
|
.scroll_offset
|
||||||
|
.as_ref()
|
||||||
|
.map(|scroll_offset| *scroll_offset.borrow())
|
||||||
|
.unwrap_or_default();
|
||||||
let result = f(&style, scroll_offset, hitbox, cx);
|
let result = f(&style, scroll_offset, hitbox, cx);
|
||||||
(result, element_state)
|
(result, element_state)
|
||||||
})
|
})
|
||||||
@@ -2263,6 +2326,7 @@ where
|
|||||||
{
|
{
|
||||||
type BeforeLayout = E::BeforeLayout;
|
type BeforeLayout = E::BeforeLayout;
|
||||||
type AfterLayout = E::AfterLayout;
|
type AfterLayout = E::AfterLayout;
|
||||||
|
type BeforePaint = E::BeforePaint;
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
self.element.before_layout(cx)
|
self.element.before_layout(cx)
|
||||||
@@ -2271,10 +2335,21 @@ where
|
|||||||
fn after_layout(
|
fn after_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
state: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> E::AfterLayout {
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
self.element.after_layout(bounds, state, cx)
|
self.element.after_layout(bounds, before_layout, cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
before_layout: &mut Self::BeforeLayout,
|
||||||
|
after_layout: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> E::BeforePaint {
|
||||||
|
self.element
|
||||||
|
.before_paint(bounds, before_layout, after_layout, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
@@ -2282,9 +2357,11 @@ where
|
|||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
after_layout: &mut Self::AfterLayout,
|
after_layout: &mut Self::AfterLayout,
|
||||||
|
before_paint: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
self.element.paint(bounds, before_layout, after_layout, cx)
|
self.element
|
||||||
|
.paint(bounds, before_layout, after_layout, before_paint, cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2346,6 +2423,7 @@ where
|
|||||||
{
|
{
|
||||||
type BeforeLayout = E::BeforeLayout;
|
type BeforeLayout = E::BeforeLayout;
|
||||||
type AfterLayout = E::AfterLayout;
|
type AfterLayout = E::AfterLayout;
|
||||||
|
type BeforePaint = E::BeforePaint;
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
self.element.before_layout(cx)
|
self.element.before_layout(cx)
|
||||||
@@ -2354,10 +2432,21 @@ where
|
|||||||
fn after_layout(
|
fn after_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
state: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> E::AfterLayout {
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
self.element.after_layout(bounds, state, cx)
|
self.element.after_layout(bounds, before_layout, cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
before_layout: &mut Self::BeforeLayout,
|
||||||
|
after_layout: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> E::BeforePaint {
|
||||||
|
self.element
|
||||||
|
.before_paint(bounds, before_layout, after_layout, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
@@ -2365,9 +2454,11 @@ where
|
|||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
after_layout: &mut Self::AfterLayout,
|
after_layout: &mut Self::AfterLayout,
|
||||||
|
before_paint: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
self.element.paint(bounds, before_layout, after_layout, cx);
|
self.element
|
||||||
|
.paint(bounds, before_layout, after_layout, before_paint, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -230,7 +230,8 @@ impl Img {
|
|||||||
|
|
||||||
impl Element for Img {
|
impl Element for Img {
|
||||||
type BeforeLayout = ();
|
type BeforeLayout = ();
|
||||||
type AfterLayout = Option<Hitbox>;
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = Option<Hitbox>;
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
let layout_id = self.interactivity.before_layout(cx, |mut style, cx| {
|
let layout_id = self.interactivity.before_layout(cx, |mut style, cx| {
|
||||||
@@ -261,16 +262,29 @@ impl Element for Img {
|
|||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_before_layout: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
self.interactivity
|
||||||
|
.after_layout(bounds, bounds.size, cx, |_, _, _, _| {});
|
||||||
|
(None, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
) -> Option<Hitbox> {
|
) -> Option<Hitbox> {
|
||||||
self.interactivity
|
self.interactivity
|
||||||
.after_layout(bounds, bounds.size, cx, |_, _, hitbox, _| hitbox)
|
.before_paint(bounds, cx, |_, _, hitbox, _| hitbox)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
hitbox: &mut Self::AfterLayout,
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
hitbox: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
let source = self.source.clone();
|
let source = self.source.clone();
|
||||||
|
|||||||
@@ -89,17 +89,28 @@ pub enum ListSizingBehavior {
|
|||||||
Auto,
|
Auto,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LayoutItemsResponse {
|
/// Layout information computed by the [List] element during `after_layout`.
|
||||||
|
pub struct ListLayout {
|
||||||
max_item_width: Pixels,
|
max_item_width: Pixels,
|
||||||
scroll_top: ListOffset,
|
scroll_top: ListOffset,
|
||||||
available_item_space: Size<AvailableSpace>,
|
items: VecDeque<MeasuredItem>,
|
||||||
item_elements: VecDeque<AnyElement>,
|
focus_target: Option<FocusTarget>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Frame state used by the [List] element after layout.
|
struct MeasuredItem {
|
||||||
pub struct ListAfterLayoutState {
|
element: AnyElement,
|
||||||
|
size: Size<Pixels>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FocusTarget {
|
||||||
|
item_index: usize,
|
||||||
|
bounds_in_item: Bounds<Pixels>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Frame state used by the [List] element during paint.
|
||||||
|
pub struct ListBeforePaintState {
|
||||||
hitbox: Hitbox,
|
hitbox: Hitbox,
|
||||||
layout: LayoutItemsResponse,
|
layout: ListLayout,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -376,13 +387,14 @@ impl StateInner {
|
|||||||
available_height: Pixels,
|
available_height: Pixels,
|
||||||
padding: &Edges<Pixels>,
|
padding: &Edges<Pixels>,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> LayoutItemsResponse {
|
) -> ListLayout {
|
||||||
let old_items = self.items.clone();
|
let old_items = self.items.clone();
|
||||||
let mut measured_items = VecDeque::new();
|
let mut measured_items = VecDeque::new();
|
||||||
let mut item_elements = VecDeque::new();
|
let mut items = VecDeque::new();
|
||||||
let mut rendered_height = padding.top;
|
let mut rendered_height = padding.top;
|
||||||
let mut max_item_width = px(0.);
|
let mut max_item_width = px(0.);
|
||||||
let mut scroll_top = self.logical_scroll_top();
|
let mut scroll_top = self.logical_scroll_top();
|
||||||
|
let mut focus_target = None;
|
||||||
|
|
||||||
let available_item_space = size(
|
let available_item_space = size(
|
||||||
available_width.map_or(AvailableSpace::MinContent, |width| {
|
available_width.map_or(AvailableSpace::MinContent, |width| {
|
||||||
@@ -411,10 +423,20 @@ impl StateInner {
|
|||||||
// If we're within the visible area or the height wasn't cached, render and measure the item's element
|
// If we're within the visible area or the height wasn't cached, render and measure the item's element
|
||||||
if visible_height < available_height || size.is_none() {
|
if visible_height < available_height || size.is_none() {
|
||||||
let mut element = (self.render_item)(scroll_top.item_ix + ix, cx);
|
let mut element = (self.render_item)(scroll_top.item_ix + ix, cx);
|
||||||
let element_size = element.measure(available_item_space, cx);
|
let element_measurement = element.layout(available_item_space, cx);
|
||||||
size = Some(element_size);
|
size = Some(element_measurement.size);
|
||||||
if visible_height < available_height {
|
if visible_height < available_height {
|
||||||
item_elements.push_back(element);
|
if let Some(focus_target_bounds) = element_measurement.focus_target_bounds {
|
||||||
|
focus_target = Some(FocusTarget {
|
||||||
|
item_index: items.len(),
|
||||||
|
bounds_in_item: focus_target_bounds,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push_back(MeasuredItem {
|
||||||
|
element,
|
||||||
|
size: element_measurement.size,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,11 +457,26 @@ impl StateInner {
|
|||||||
cursor.prev(&());
|
cursor.prev(&());
|
||||||
if cursor.item().is_some() {
|
if cursor.item().is_some() {
|
||||||
let mut element = (self.render_item)(cursor.start().0, cx);
|
let mut element = (self.render_item)(cursor.start().0, cx);
|
||||||
let element_size = element.measure(available_item_space, cx);
|
let element_measurement = element.layout(available_item_space, cx);
|
||||||
|
|
||||||
rendered_height += element_size.height;
|
rendered_height += element_measurement.size.height;
|
||||||
measured_items.push_front(ListItem::Rendered { size: element_size });
|
measured_items.push_front(ListItem::Rendered {
|
||||||
item_elements.push_front(element)
|
size: element_measurement.size,
|
||||||
|
});
|
||||||
|
|
||||||
|
items.push_front(MeasuredItem {
|
||||||
|
element,
|
||||||
|
size: element_measurement.size,
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(focus_target_bounds) = element_measurement.focus_target_bounds {
|
||||||
|
focus_target = Some(FocusTarget {
|
||||||
|
item_index: 0,
|
||||||
|
bounds_in_item: focus_target_bounds,
|
||||||
|
});
|
||||||
|
} else if let Some(focus_target) = focus_target.as_mut() {
|
||||||
|
focus_target.item_index += 1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -474,7 +511,7 @@ impl StateInner {
|
|||||||
*size
|
*size
|
||||||
} else {
|
} else {
|
||||||
let mut element = (self.render_item)(cursor.start().0, cx);
|
let mut element = (self.render_item)(cursor.start().0, cx);
|
||||||
element.measure(available_item_space, cx)
|
element.layout(available_item_space, cx).size
|
||||||
};
|
};
|
||||||
|
|
||||||
leading_overdraw += size.height;
|
leading_overdraw += size.height;
|
||||||
@@ -493,11 +530,11 @@ impl StateInner {
|
|||||||
|
|
||||||
self.items = new_items;
|
self.items = new_items;
|
||||||
|
|
||||||
LayoutItemsResponse {
|
ListLayout {
|
||||||
max_item_width,
|
max_item_width,
|
||||||
scroll_top,
|
scroll_top,
|
||||||
available_item_space,
|
items,
|
||||||
item_elements,
|
focus_target,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -523,7 +560,8 @@ pub struct ListOffset {
|
|||||||
|
|
||||||
impl Element for List {
|
impl Element for List {
|
||||||
type BeforeLayout = ();
|
type BeforeLayout = ();
|
||||||
type AfterLayout = ListAfterLayoutState;
|
type AfterLayout = Option<ListLayout>;
|
||||||
|
type BeforePaint = ListBeforePaintState;
|
||||||
|
|
||||||
fn before_layout(
|
fn before_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -592,17 +630,15 @@ impl Element for List {
|
|||||||
fn after_layout(
|
fn after_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> ListAfterLayoutState {
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
let state = &mut *self.state.0.borrow_mut();
|
let state = &mut *self.state.0.borrow_mut();
|
||||||
state.reset = false;
|
state.reset = false;
|
||||||
|
|
||||||
let mut style = Style::default();
|
let mut style = Style::default();
|
||||||
style.refine(&self.style);
|
style.refine(&self.style);
|
||||||
|
|
||||||
let hitbox = cx.insert_hitbox(bounds, false);
|
|
||||||
|
|
||||||
// If the width of the list has changed, invalidate all cached item heights
|
// If the width of the list has changed, invalidate all cached item heights
|
||||||
if state.last_layout_bounds.map_or(true, |last_bounds| {
|
if state.last_layout_bounds.map_or(true, |last_bounds| {
|
||||||
last_bounds.size.width != bounds.size.width
|
last_bounds.size.width != bounds.size.width
|
||||||
@@ -614,48 +650,77 @@ impl Element for List {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
|
let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
|
||||||
let mut layout_response =
|
let layout = state.layout_items(Some(bounds.size.width), bounds.size.height, &padding, cx);
|
||||||
state.layout_items(Some(bounds.size.width), bounds.size.height, &padding, cx);
|
let focus_target_bounds = layout.focus_target.as_ref().map(|focus_target| {
|
||||||
|
let mut item_origin =
|
||||||
|
bounds.origin + Point::new(px(0.), padding.top - layout.scroll_top.offset_in_item);
|
||||||
|
item_origin.y -= layout.scroll_top.offset_in_item;
|
||||||
|
for item in layout.items.iter().take(focus_target.item_index) {
|
||||||
|
item_origin.y += item.size.height;
|
||||||
|
}
|
||||||
|
Bounds::new(
|
||||||
|
item_origin + focus_target.bounds_in_item.origin,
|
||||||
|
focus_target.bounds_in_item.size,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
(focus_target_bounds, Some(layout))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
_: &mut Self::BeforeLayout,
|
||||||
|
layout: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> ListBeforePaintState {
|
||||||
|
let mut layout = layout.take().unwrap();
|
||||||
|
let state = &mut *self.state.0.borrow_mut();
|
||||||
|
state.reset = false;
|
||||||
|
|
||||||
|
let mut style = Style::default();
|
||||||
|
style.refine(&self.style);
|
||||||
|
let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
|
||||||
|
|
||||||
|
let hitbox = cx.insert_hitbox(bounds, false);
|
||||||
|
|
||||||
// Only paint the visible items, if there is actually any space for them (taking padding into account)
|
// Only paint the visible items, if there is actually any space for them (taking padding into account)
|
||||||
if bounds.size.height > padding.top + padding.bottom {
|
if bounds.size.height > padding.top + padding.bottom {
|
||||||
// Paint the visible items
|
// Paint the visible items
|
||||||
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
||||||
let mut item_origin = bounds.origin + Point::new(px(0.), padding.top);
|
let mut item_origin = bounds.origin + Point::new(px(0.), padding.top);
|
||||||
item_origin.y -= layout_response.scroll_top.offset_in_item;
|
item_origin.y -= layout.scroll_top.offset_in_item;
|
||||||
for mut item_element in &mut layout_response.item_elements {
|
for item in &mut layout.items {
|
||||||
let item_size = item_element.measure(layout_response.available_item_space, cx);
|
cx.with_absolute_element_offset(item_origin, |cx| {
|
||||||
item_element.layout(item_origin, layout_response.available_item_space, cx);
|
item.element.before_paint(cx)
|
||||||
item_origin.y += item_size.height;
|
});
|
||||||
|
item_origin.y += item.size.height;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
state.last_layout_bounds = Some(bounds);
|
state.last_layout_bounds = Some(bounds);
|
||||||
state.last_padding = Some(padding);
|
state.last_padding = Some(padding);
|
||||||
ListAfterLayoutState {
|
ListBeforePaintState { hitbox, layout }
|
||||||
hitbox,
|
|
||||||
layout: layout_response,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<crate::Pixels>,
|
bounds: Bounds<crate::Pixels>,
|
||||||
_: &mut Self::BeforeLayout,
|
_: &mut Self::BeforeLayout,
|
||||||
after_layout: &mut Self::AfterLayout,
|
_: &mut Self::AfterLayout,
|
||||||
|
before_paint: &mut Self::BeforePaint,
|
||||||
cx: &mut crate::ElementContext,
|
cx: &mut crate::ElementContext,
|
||||||
) {
|
) {
|
||||||
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
||||||
for item in &mut after_layout.layout.item_elements {
|
for item in &mut before_paint.layout.items {
|
||||||
item.paint(cx);
|
item.element.paint(cx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let list_state = self.state.clone();
|
let list_state = self.state.clone();
|
||||||
let height = bounds.size.height;
|
let height = bounds.size.height;
|
||||||
let scroll_top = after_layout.layout.scroll_top;
|
let scroll_top = before_paint.layout.scroll_top;
|
||||||
let hitbox_id = after_layout.hitbox.id;
|
let hitbox_id = before_paint.hitbox.id;
|
||||||
cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
|
cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble && hitbox_id.is_hovered(cx) {
|
if phase == DispatchPhase::Bubble && hitbox_id.is_hovered(cx) {
|
||||||
list_state.0.borrow_mut().scroll(
|
list_state.0.borrow_mut().scroll(
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ impl Svg {
|
|||||||
|
|
||||||
impl Element for Svg {
|
impl Element for Svg {
|
||||||
type BeforeLayout = ();
|
type BeforeLayout = ();
|
||||||
type AfterLayout = Option<Hitbox>;
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = Option<Hitbox>;
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
let layout_id = self
|
let layout_id = self
|
||||||
@@ -52,15 +53,28 @@ impl Element for Svg {
|
|||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_before_layout: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
self.interactivity
|
||||||
|
.after_layout(bounds, bounds.size, cx, |_, _, _, _| {});
|
||||||
|
(None, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
) -> Option<Hitbox> {
|
) -> Option<Hitbox> {
|
||||||
self.interactivity
|
self.interactivity
|
||||||
.after_layout(bounds, bounds.size, cx, |_, _, hitbox, _| hitbox)
|
.before_paint(bounds, cx, |_, _, hitbox, _| hitbox)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_before_layout: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
hitbox: &mut Option<Hitbox>,
|
hitbox: &mut Option<Hitbox>,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) where
|
) where
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use util::ResultExt;
|
|||||||
impl Element for &'static str {
|
impl Element for &'static str {
|
||||||
type BeforeLayout = TextState;
|
type BeforeLayout = TextState;
|
||||||
type AfterLayout = ();
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
let mut state = TextState::default();
|
let mut state = TextState::default();
|
||||||
@@ -27,9 +28,19 @@ impl Element for &'static str {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
(None, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_text_state: &mut Self::BeforeLayout,
|
_text_state: &mut Self::BeforeLayout,
|
||||||
|
_: &mut Self::AfterLayout,
|
||||||
_cx: &mut ElementContext,
|
_cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -38,6 +49,7 @@ impl Element for &'static str {
|
|||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
text_state: &mut TextState,
|
text_state: &mut TextState,
|
||||||
|
_: &mut Self::AfterLayout,
|
||||||
_: &mut (),
|
_: &mut (),
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
@@ -64,6 +76,7 @@ impl IntoElement for String {
|
|||||||
impl Element for SharedString {
|
impl Element for SharedString {
|
||||||
type BeforeLayout = TextState;
|
type BeforeLayout = TextState;
|
||||||
type AfterLayout = ();
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
let mut state = TextState::default();
|
let mut state = TextState::default();
|
||||||
@@ -72,9 +85,19 @@ impl Element for SharedString {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
(None, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_text_state: &mut Self::BeforeLayout,
|
_text_state: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
_cx: &mut ElementContext,
|
_cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -83,7 +106,8 @@ impl Element for SharedString {
|
|||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
text_state: &mut Self::BeforeLayout,
|
text_state: &mut Self::BeforeLayout,
|
||||||
_: &mut Self::AfterLayout,
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
_: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
let text_str: &str = self.as_ref();
|
let text_str: &str = self.as_ref();
|
||||||
@@ -150,6 +174,7 @@ impl StyledText {
|
|||||||
impl Element for StyledText {
|
impl Element for StyledText {
|
||||||
type BeforeLayout = TextState;
|
type BeforeLayout = TextState;
|
||||||
type AfterLayout = ();
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
let mut state = TextState::default();
|
let mut state = TextState::default();
|
||||||
@@ -158,9 +183,19 @@ impl Element for StyledText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
(None, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_state: &mut Self::BeforeLayout,
|
_state: &mut Self::BeforeLayout,
|
||||||
|
_: &mut Self::AfterLayout,
|
||||||
_cx: &mut ElementContext,
|
_cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -170,6 +205,7 @@ impl Element for StyledText {
|
|||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
text_state: &mut Self::BeforeLayout,
|
text_state: &mut Self::BeforeLayout,
|
||||||
_: &mut Self::AfterLayout,
|
_: &mut Self::AfterLayout,
|
||||||
|
_: &mut (),
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
text_state.paint(bounds, &self.text, cx)
|
text_state.paint(bounds, &self.text, cx)
|
||||||
@@ -403,16 +439,27 @@ impl InteractiveText {
|
|||||||
|
|
||||||
impl Element for InteractiveText {
|
impl Element for InteractiveText {
|
||||||
type BeforeLayout = TextState;
|
type BeforeLayout = TextState;
|
||||||
type AfterLayout = Hitbox;
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = Hitbox;
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
self.text.before_layout(cx)
|
self.text.before_layout(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
_cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
(None, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
state: &mut Self::BeforeLayout,
|
state: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Hitbox {
|
) -> Hitbox {
|
||||||
cx.with_element_state::<InteractiveTextState, _>(
|
cx.with_element_state::<InteractiveTextState, _>(
|
||||||
@@ -430,7 +477,7 @@ impl Element for InteractiveText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.text.after_layout(bounds, state, cx);
|
self.text.before_paint(bounds, state, &mut (), cx);
|
||||||
let hitbox = cx.insert_hitbox(bounds, false);
|
let hitbox = cx.insert_hitbox(bounds, false);
|
||||||
(hitbox, interactive_state)
|
(hitbox, interactive_state)
|
||||||
},
|
},
|
||||||
@@ -441,6 +488,7 @@ impl Element for InteractiveText {
|
|||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
text_state: &mut Self::BeforeLayout,
|
text_state: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
hitbox: &mut Hitbox,
|
hitbox: &mut Hitbox,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
@@ -577,7 +625,7 @@ impl Element for InteractiveText {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.text.paint(bounds, text_state, &mut (), cx);
|
self.text.paint(bounds, text_state, &mut (), &mut (), cx);
|
||||||
|
|
||||||
((), Some(interactive_state))
|
((), Some(interactive_state))
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,8 +6,9 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, size, AnyElement, AvailableSpace, Bounds, ContentMask, Element, ElementContext,
|
point, px, size, AnyElement, AvailableSpace, Bounds, ContentMask, Element, ElementContext,
|
||||||
ElementId, Hitbox, InteractiveElement, Interactivity, IntoElement, LayoutId, Pixels, Render,
|
ElementId, ElementMeasurement, Hitbox, InteractiveElement, Interactivity, IntoElement,
|
||||||
ScrollHandle, Size, StyleRefinement, Styled, View, ViewContext, WindowContext,
|
LayoutId, Pixels, 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};
|
||||||
@@ -70,8 +71,9 @@ pub struct UniformList {
|
|||||||
|
|
||||||
/// Frame state used by the [UniformList].
|
/// Frame state used by the [UniformList].
|
||||||
pub struct UniformListFrameState {
|
pub struct UniformListFrameState {
|
||||||
item_size: Size<Pixels>,
|
item_height: Pixels,
|
||||||
items: SmallVec<[AnyElement; 32]>,
|
items: SmallVec<[AnyElement; 32]>,
|
||||||
|
visible_range: Range<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A handle for controlling the scroll position of a uniform list.
|
/// A handle for controlling the scroll position of a uniform list.
|
||||||
@@ -105,19 +107,22 @@ impl Styled for UniformList {
|
|||||||
|
|
||||||
impl Element for UniformList {
|
impl Element for UniformList {
|
||||||
type BeforeLayout = UniformListFrameState;
|
type BeforeLayout = UniformListFrameState;
|
||||||
type AfterLayout = Option<Hitbox>;
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = Option<Hitbox>;
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
let max_items = self.item_count;
|
let max_items = self.item_count;
|
||||||
let item_size = self.measure_item(None, cx);
|
let item_measurement = self.measure_item(None, cx);
|
||||||
let layout_id = self.interactivity.before_layout(cx, |style, cx| {
|
let layout_id = self.interactivity.before_layout(cx, |style, cx| {
|
||||||
cx.request_measured_layout(style, move |known_dimensions, available_space, _cx| {
|
cx.request_measured_layout(style, move |known_dimensions, available_space, _cx| {
|
||||||
let desired_height = item_size.height * max_items;
|
let desired_height = item_measurement.size.height * max_items;
|
||||||
let width = known_dimensions
|
let width = known_dimensions
|
||||||
.width
|
.width
|
||||||
.unwrap_or(match available_space.width {
|
.unwrap_or(match available_space.width {
|
||||||
AvailableSpace::Definite(x) => x,
|
AvailableSpace::Definite(x) => x,
|
||||||
AvailableSpace::MinContent | AvailableSpace::MaxContent => item_size.width,
|
AvailableSpace::MinContent | AvailableSpace::MaxContent => {
|
||||||
|
item_measurement.size.width
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let height = match available_space.height {
|
let height = match available_space.height {
|
||||||
@@ -131,8 +136,9 @@ impl Element for UniformList {
|
|||||||
(
|
(
|
||||||
layout_id,
|
layout_id,
|
||||||
UniformListFrameState {
|
UniformListFrameState {
|
||||||
item_size,
|
item_height: Pixels::default(),
|
||||||
items: SmallVec::new(),
|
items: SmallVec::new(),
|
||||||
|
visible_range: 0..0,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -140,28 +146,26 @@ impl Element for UniformList {
|
|||||||
fn after_layout(
|
fn after_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
state: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Option<Hitbox> {
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
let style = self.interactivity.compute_style(None, cx);
|
let style = self.interactivity.compute_style(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());
|
||||||
|
|
||||||
let padded_bounds = Bounds::from_corners(
|
let padded_size = size(
|
||||||
bounds.origin + point(border.left + padding.left, border.top + padding.top),
|
bounds.size.width - border.left - padding.left - border.right - padding.right,
|
||||||
bounds.lower_right()
|
bounds.size.height - border.top - padding.top - border.bottom - padding.bottom,
|
||||||
- point(border.right + padding.right, border.bottom + padding.bottom),
|
|
||||||
);
|
);
|
||||||
|
let item_height = self.measure_item(Some(padded_size.width), cx).size.height;
|
||||||
let content_size = Size {
|
let content_size = Size {
|
||||||
width: padded_bounds.size.width,
|
width: padded_size.width,
|
||||||
height: before_layout.item_size.height * self.item_count + padding.top + padding.bottom,
|
height: item_height * self.item_count + padding.top + padding.bottom,
|
||||||
};
|
};
|
||||||
|
|
||||||
let shared_scroll_offset = self.interactivity.scroll_offset.clone().unwrap();
|
let shared_scroll_offset = self.interactivity.scroll_offset.clone().unwrap();
|
||||||
|
// todo!("add support for scrolling to the focused element?");
|
||||||
let item_height = self.measure_item(Some(padded_bounds.size.width), cx).height;
|
let deferred_scroll_to_item = self
|
||||||
let shared_scroll_to_item = self
|
|
||||||
.scroll_handle
|
.scroll_handle
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.and_then(|handle| handle.deferred_scroll_to_item.take());
|
.and_then(|handle| handle.deferred_scroll_to_item.take());
|
||||||
@@ -170,73 +174,103 @@ impl Element for UniformList {
|
|||||||
bounds,
|
bounds,
|
||||||
content_size,
|
content_size,
|
||||||
cx,
|
cx,
|
||||||
|style, mut scroll_offset, hitbox, cx| {
|
|style, mut scroll_offset, mut focus_target_bounds, cx| {
|
||||||
|
if self.item_count == 0 {
|
||||||
|
return (focus_target_bounds, ());
|
||||||
|
}
|
||||||
|
|
||||||
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());
|
||||||
|
|
||||||
|
let padded_size = size(
|
||||||
|
bounds.size.width - border.left - padding.left - border.right - padding.right,
|
||||||
|
bounds.size.height - border.top - padding.top - border.bottom - padding.bottom,
|
||||||
|
);
|
||||||
|
|
||||||
|
let content_height = item_height * self.item_count + padding.top + padding.bottom;
|
||||||
|
let min_scroll_offset = padded_size.height - content_height;
|
||||||
|
let is_scrolled = scroll_offset.y != px(0.);
|
||||||
|
|
||||||
|
if is_scrolled && scroll_offset.y < min_scroll_offset {
|
||||||
|
shared_scroll_offset.borrow_mut().y = min_scroll_offset;
|
||||||
|
scroll_offset.y = min_scroll_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ix) = deferred_scroll_to_item {
|
||||||
|
let list_height = padded_size.height;
|
||||||
|
let mut updated_scroll_offset = shared_scroll_offset.borrow_mut();
|
||||||
|
let item_top = item_height * ix + padding.top;
|
||||||
|
let item_bottom = item_top + item_height;
|
||||||
|
let scroll_top = -updated_scroll_offset.y;
|
||||||
|
if item_top < scroll_top + padding.top {
|
||||||
|
updated_scroll_offset.y = -(item_top) + padding.top;
|
||||||
|
} else if item_bottom > scroll_top + list_height - padding.bottom {
|
||||||
|
updated_scroll_offset.y = -(item_bottom - list_height) - padding.bottom;
|
||||||
|
}
|
||||||
|
scroll_offset = *updated_scroll_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
let first_visible_element_ix =
|
||||||
|
(-(scroll_offset.y + padding.top) / item_height).floor() as usize;
|
||||||
|
let last_visible_element_ix =
|
||||||
|
((-scroll_offset.y + padded_size.height) / item_height).ceil() as usize;
|
||||||
|
let visible_range =
|
||||||
|
first_visible_element_ix..cmp::min(last_visible_element_ix, self.item_count);
|
||||||
|
|
||||||
|
let mut items = (self.render_items)(visible_range.clone(), cx);
|
||||||
|
let available_space = size(
|
||||||
|
AvailableSpace::Definite(padded_size.width),
|
||||||
|
AvailableSpace::Definite(item_height),
|
||||||
|
);
|
||||||
|
for mut item in items {
|
||||||
|
let measurement = item.layout(available_space, cx);
|
||||||
|
if measurement.focus_target_bounds.is_some() {
|
||||||
|
focus_target_bounds = measurement.focus_target_bounds;
|
||||||
|
}
|
||||||
|
state.items.push(item);
|
||||||
|
}
|
||||||
|
state.item_height = item_height;
|
||||||
|
state.visible_range = visible_range;
|
||||||
|
|
||||||
|
(focus_target_bounds, ())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
state: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> Option<Hitbox> {
|
||||||
|
self.interactivity
|
||||||
|
.before_paint(bounds, cx, |style, scroll_offset, hitbox, cx| {
|
||||||
|
let border = style.border_widths.to_pixels(cx.rem_size());
|
||||||
|
let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
|
||||||
let padded_bounds = Bounds::from_corners(
|
let padded_bounds = Bounds::from_corners(
|
||||||
bounds.origin + point(border.left + padding.left, border.top),
|
bounds.origin + point(border.left + padding.left, border.top),
|
||||||
bounds.lower_right() - point(border.right + padding.right, border.bottom),
|
bounds.lower_right() - point(border.right + padding.right, border.bottom),
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.item_count > 0 {
|
let content_mask = ContentMask { bounds };
|
||||||
let content_height =
|
cx.with_content_mask(Some(content_mask), |cx| {
|
||||||
item_height * self.item_count + padding.top + padding.bottom;
|
for (item, ix) in state.items.iter_mut().zip(state.visible_range.clone()) {
|
||||||
let min_scroll_offset = padded_bounds.size.height - content_height;
|
let item_y = state.item_height * ix + scroll_offset.y + padding.top;
|
||||||
let is_scrolled = scroll_offset.y != px(0.);
|
let item_origin = padded_bounds.origin + point(px(0.), item_y);
|
||||||
|
cx.with_absolute_element_offset(item_origin, |cx| item.before_paint(cx));
|
||||||
if is_scrolled && scroll_offset.y < min_scroll_offset {
|
|
||||||
shared_scroll_offset.borrow_mut().y = min_scroll_offset;
|
|
||||||
scroll_offset.y = min_scroll_offset;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
if let Some(ix) = shared_scroll_to_item {
|
|
||||||
let list_height = padded_bounds.size.height;
|
|
||||||
let mut updated_scroll_offset = shared_scroll_offset.borrow_mut();
|
|
||||||
let item_top = item_height * ix + padding.top;
|
|
||||||
let item_bottom = item_top + item_height;
|
|
||||||
let scroll_top = -updated_scroll_offset.y;
|
|
||||||
if item_top < scroll_top + padding.top {
|
|
||||||
updated_scroll_offset.y = -(item_top) + padding.top;
|
|
||||||
} else if item_bottom > scroll_top + list_height - padding.bottom {
|
|
||||||
updated_scroll_offset.y = -(item_bottom - list_height) - padding.bottom;
|
|
||||||
}
|
|
||||||
scroll_offset = *updated_scroll_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
let first_visible_element_ix =
|
|
||||||
(-(scroll_offset.y + padding.top) / item_height).floor() as usize;
|
|
||||||
let last_visible_element_ix = ((-scroll_offset.y + padded_bounds.size.height)
|
|
||||||
/ item_height)
|
|
||||||
.ceil() as usize;
|
|
||||||
let visible_range = first_visible_element_ix
|
|
||||||
..cmp::min(last_visible_element_ix, self.item_count);
|
|
||||||
|
|
||||||
let mut items = (self.render_items)(visible_range.clone(), cx);
|
|
||||||
let content_mask = ContentMask { bounds };
|
|
||||||
cx.with_content_mask(Some(content_mask), |cx| {
|
|
||||||
for (mut item, ix) in items.into_iter().zip(visible_range) {
|
|
||||||
let item_origin = padded_bounds.origin
|
|
||||||
+ point(px(0.), item_height * ix + scroll_offset.y + padding.top);
|
|
||||||
let available_space = size(
|
|
||||||
AvailableSpace::Definite(padded_bounds.size.width),
|
|
||||||
AvailableSpace::Definite(item_height),
|
|
||||||
);
|
|
||||||
item.layout(item_origin, available_space, cx);
|
|
||||||
before_layout.items.push(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
hitbox
|
hitbox
|
||||||
},
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<crate::Pixels>,
|
bounds: Bounds<crate::Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
hitbox: &mut Option<Hitbox>,
|
hitbox: &mut Option<Hitbox>,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
@@ -264,9 +298,13 @@ impl UniformList {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure_item(&self, list_width: Option<Pixels>, cx: &mut ElementContext) -> Size<Pixels> {
|
fn measure_item(
|
||||||
|
&self,
|
||||||
|
list_width: Option<Pixels>,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> ElementMeasurement {
|
||||||
if self.item_count == 0 {
|
if self.item_count == 0 {
|
||||||
return Size::default();
|
return ElementMeasurement::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
let item_ix = cmp::min(self.item_to_measure_index, self.item_count - 1);
|
let item_ix = cmp::min(self.item_to_measure_index, self.item_count - 1);
|
||||||
@@ -278,7 +316,7 @@ impl UniformList {
|
|||||||
}),
|
}),
|
||||||
AvailableSpace::MinContent,
|
AvailableSpace::MinContent,
|
||||||
);
|
);
|
||||||
item_to_measure.measure(available_space, cx)
|
item_to_measure.layout(available_space, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Track and render scroll state of this list with reference to the given scroll handle.
|
/// Track and render scroll state of this list with reference to the given scroll handle.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
seal::Sealed, AfterLayoutIndex, AnyElement, AnyModel, AnyWeakModel, AppContext, Bounds,
|
seal::Sealed, AfterLayoutIndex, AnyElement, AnyModel, AnyWeakModel, AppContext,
|
||||||
ContentMask, Element, ElementContext, ElementId, Entity, EntityId, Flatten, FocusHandle,
|
BeforePaintIndex, Bounds, ContentMask, Element, ElementContext, ElementId, Entity, EntityId,
|
||||||
FocusableView, IntoElement, LayoutId, Model, PaintIndex, Pixels, Render, Style,
|
Flatten, FocusHandle, FocusableView, IntoElement, LayoutId, Model, PaintIndex, Pixels, Render,
|
||||||
StyleRefinement, TextStyle, ViewContext, VisualContext, WeakModel,
|
Style, StyleRefinement, TextStyle, ViewContext, VisualContext, WeakModel,
|
||||||
};
|
};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
@@ -24,13 +24,16 @@ impl<V> Sealed for View<V> {}
|
|||||||
|
|
||||||
struct AnyViewState {
|
struct AnyViewState {
|
||||||
after_layout_range: Range<AfterLayoutIndex>,
|
after_layout_range: Range<AfterLayoutIndex>,
|
||||||
|
before_paint_range: Range<BeforePaintIndex>,
|
||||||
paint_range: Range<PaintIndex>,
|
paint_range: Range<PaintIndex>,
|
||||||
|
focus_target_bounds: Option<Bounds<Pixels>>,
|
||||||
cache_key: ViewCacheKey,
|
cache_key: ViewCacheKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ViewCacheKey {
|
struct ViewCacheKey {
|
||||||
bounds: Bounds<Pixels>,
|
after_layout_bounds: Bounds<Pixels>,
|
||||||
|
before_paint_bounds: Bounds<Pixels>,
|
||||||
content_mask: ContentMask<Pixels>,
|
content_mask: ContentMask<Pixels>,
|
||||||
text_style: TextStyle,
|
text_style: TextStyle,
|
||||||
}
|
}
|
||||||
@@ -92,6 +95,7 @@ impl<V: 'static> View<V> {
|
|||||||
impl<V: Render> Element for View<V> {
|
impl<V: Render> Element for View<V> {
|
||||||
type BeforeLayout = AnyElement;
|
type BeforeLayout = AnyElement;
|
||||||
type AfterLayout = ();
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||||
@@ -102,14 +106,24 @@ impl<V: Render> Element for View<V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
element: &mut Self::BeforeLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
(element.after_layout(cx), ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
element: &mut Self::BeforeLayout,
|
element: &mut Self::BeforeLayout,
|
||||||
|
_: &mut Self::AfterLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
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| {
|
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||||
element.after_layout(cx)
|
element.before_paint(cx)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +132,7 @@ impl<V: Render> Element for View<V> {
|
|||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
element: &mut Self::BeforeLayout,
|
element: &mut Self::BeforeLayout,
|
||||||
_: &mut Self::AfterLayout,
|
_: &mut Self::AfterLayout,
|
||||||
|
_: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||||
@@ -277,7 +292,8 @@ impl<V: Render> From<View<V>> for AnyView {
|
|||||||
|
|
||||||
impl Element for AnyView {
|
impl Element for AnyView {
|
||||||
type BeforeLayout = Option<AnyElement>;
|
type BeforeLayout = Option<AnyElement>;
|
||||||
type AfterLayout = Option<AnyElement>;
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
if let Some(style) = self.cached_style.as_ref() {
|
if let Some(style) = self.cached_style.as_ref() {
|
||||||
@@ -299,20 +315,16 @@ impl Element for AnyView {
|
|||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
element: &mut Self::BeforeLayout,
|
element: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Option<AnyElement> {
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
cx.set_view_id(self.entity_id());
|
|
||||||
if self.cached_style.is_some() {
|
if self.cached_style.is_some() {
|
||||||
cx.with_element_state::<AnyViewState, _>(
|
let focus_target_bounds = cx.with_element_state::<AnyViewState, _>(
|
||||||
Some(ElementId::View(self.entity_id())),
|
Some(ElementId::View(self.entity_id())),
|
||||||
|element_state, cx| {
|
|element_state, cx| {
|
||||||
let mut element_state = element_state.unwrap();
|
let mut element_state = element_state.unwrap();
|
||||||
|
|
||||||
let content_mask = cx.content_mask();
|
|
||||||
let text_style = cx.text_style();
|
let text_style = cx.text_style();
|
||||||
|
|
||||||
if let Some(mut element_state) = element_state {
|
if let Some(mut element_state) = element_state {
|
||||||
if element_state.cache_key.bounds == bounds
|
if element_state.cache_key.after_layout_bounds == bounds
|
||||||
&& element_state.cache_key.content_mask == content_mask
|
|
||||||
&& element_state.cache_key.text_style == text_style
|
&& element_state.cache_key.text_style == text_style
|
||||||
&& !cx.window.dirty_views.contains(&self.entity_id())
|
&& !cx.window.dirty_views.contains(&self.entity_id())
|
||||||
&& !cx.window.refreshing
|
&& !cx.window.refreshing
|
||||||
@@ -321,34 +333,106 @@ impl Element for AnyView {
|
|||||||
cx.reuse_after_layout(element_state.after_layout_range.clone());
|
cx.reuse_after_layout(element_state.after_layout_range.clone());
|
||||||
let after_layout_end = cx.after_layout_index();
|
let after_layout_end = cx.after_layout_index();
|
||||||
element_state.after_layout_range = after_layout_start..after_layout_end;
|
element_state.after_layout_range = after_layout_start..after_layout_end;
|
||||||
return (None, Some(element_state));
|
return (element_state.focus_target_bounds, Some(element_state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let after_layout_start = cx.after_layout_index();
|
let after_layout_start = cx.after_layout_index();
|
||||||
let mut element = (self.render)(self, cx);
|
let mut rendered_element = (self.render)(self, cx);
|
||||||
element.layout(bounds.origin, bounds.size.into(), cx);
|
let element_measurement = rendered_element.layout(bounds.size.into(), cx);
|
||||||
|
*element = Some(rendered_element);
|
||||||
|
let focus_target_bounds =
|
||||||
|
element_measurement
|
||||||
|
.focus_target_bounds
|
||||||
|
.map(|focus_target_bounds| {
|
||||||
|
Bounds::new(
|
||||||
|
bounds.origin + focus_target_bounds.origin,
|
||||||
|
focus_target_bounds.size,
|
||||||
|
)
|
||||||
|
});
|
||||||
let after_layout_end = cx.after_layout_index();
|
let after_layout_end = cx.after_layout_index();
|
||||||
|
|
||||||
(
|
let view_state = AnyViewState {
|
||||||
Some(element),
|
after_layout_range: after_layout_start..after_layout_end,
|
||||||
Some(AnyViewState {
|
before_paint_range: BeforePaintIndex::default()
|
||||||
after_layout_range: after_layout_start..after_layout_end,
|
..BeforePaintIndex::default(),
|
||||||
paint_range: PaintIndex::default()..PaintIndex::default(),
|
paint_range: PaintIndex::default()..PaintIndex::default(),
|
||||||
cache_key: ViewCacheKey {
|
focus_target_bounds,
|
||||||
bounds,
|
cache_key: ViewCacheKey {
|
||||||
content_mask,
|
after_layout_bounds: bounds,
|
||||||
text_style,
|
text_style,
|
||||||
},
|
..Default::default()
|
||||||
}),
|
},
|
||||||
)
|
};
|
||||||
|
|
||||||
|
(focus_target_bounds, Some(view_state))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
(focus_target_bounds, ())
|
||||||
|
} else {
|
||||||
|
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||||
|
let bounds = element.as_mut().unwrap().after_layout(cx);
|
||||||
|
(bounds, ())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
element: &mut Self::BeforeLayout,
|
||||||
|
_: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) {
|
||||||
|
cx.set_view_id(self.entity_id());
|
||||||
|
if self.cached_style.is_some() {
|
||||||
|
cx.with_element_state::<AnyViewState, _>(
|
||||||
|
Some(ElementId::View(self.entity_id())),
|
||||||
|
|element_state, cx| {
|
||||||
|
let mut element_state = element_state.unwrap().unwrap();
|
||||||
|
let content_mask = cx.content_mask();
|
||||||
|
|
||||||
|
if let Some(element) = element {
|
||||||
|
let before_paint_start = cx.before_paint_index();
|
||||||
|
cx.with_absolute_element_offset(bounds.origin, |cx| {
|
||||||
|
element.before_paint(cx)
|
||||||
|
});
|
||||||
|
let before_paint_end = cx.before_paint_index();
|
||||||
|
element_state.before_paint_range = before_paint_start..before_paint_end;
|
||||||
|
element_state.cache_key.before_paint_bounds = bounds;
|
||||||
|
element_state.cache_key.content_mask = content_mask;
|
||||||
|
} else if element_state.cache_key.before_paint_bounds == bounds
|
||||||
|
&& element_state.cache_key.content_mask == content_mask
|
||||||
|
{
|
||||||
|
let before_paint_start = cx.before_paint_index();
|
||||||
|
cx.reuse_before_paint(element_state.before_paint_range.clone());
|
||||||
|
let before_paint_end = cx.before_paint_index();
|
||||||
|
element_state.before_paint_range = before_paint_start..before_paint_end;
|
||||||
|
} else {
|
||||||
|
let mut rendered_element = (self.render)(self, cx);
|
||||||
|
let after_layout_start = cx.after_layout_index();
|
||||||
|
rendered_element.layout(bounds.size.into(), cx);
|
||||||
|
let after_layout_end = cx.after_layout_index();
|
||||||
|
|
||||||
|
let before_paint_start = cx.before_paint_index();
|
||||||
|
cx.with_absolute_element_offset(bounds.origin, |cx| {
|
||||||
|
rendered_element.before_paint(cx)
|
||||||
|
});
|
||||||
|
let before_paint_end = cx.before_paint_index();
|
||||||
|
element_state.after_layout_range = after_layout_start..after_layout_end;
|
||||||
|
element_state.before_paint_range = before_paint_start..before_paint_end;
|
||||||
|
element_state.cache_key.before_paint_bounds = bounds;
|
||||||
|
element_state.cache_key.content_mask = content_mask;
|
||||||
|
|
||||||
|
*element = Some(rendered_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
((), Some(element_state))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||||
let mut element = element.take().unwrap();
|
element.as_mut().unwrap().before_paint(cx)
|
||||||
element.after_layout(cx);
|
|
||||||
Some(element)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,8 +440,9 @@ impl Element for AnyView {
|
|||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::BeforeLayout,
|
element: &mut Self::BeforeLayout,
|
||||||
element: &mut Self::AfterLayout,
|
_: &mut Self::AfterLayout,
|
||||||
|
_: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
if self.cached_style.is_some() {
|
if self.cached_style.is_some() {
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ pub(crate) struct DeferredDraw {
|
|||||||
text_style_stack: Vec<TextStyleRefinement>,
|
text_style_stack: Vec<TextStyleRefinement>,
|
||||||
element: Option<AnyElement>,
|
element: Option<AnyElement>,
|
||||||
absolute_offset: Point<Pixels>,
|
absolute_offset: Point<Pixels>,
|
||||||
layout_range: Range<AfterLayoutIndex>,
|
before_paint_range: Range<BeforePaintIndex>,
|
||||||
paint_range: Range<PaintIndex>,
|
paint_range: Range<PaintIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +146,12 @@ pub(crate) struct Frame {
|
|||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub(crate) struct AfterLayoutIndex {
|
pub(crate) struct AfterLayoutIndex {
|
||||||
|
accessed_element_states_index: usize,
|
||||||
|
line_layout_index: LineLayoutIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub(crate) struct BeforePaintIndex {
|
||||||
hitboxes_index: usize,
|
hitboxes_index: usize,
|
||||||
tooltips_index: usize,
|
tooltips_index: usize,
|
||||||
deferred_draws_index: usize,
|
deferred_draws_index: usize,
|
||||||
@@ -399,7 +405,8 @@ impl<'a> ElementContext<'a> {
|
|||||||
|
|
||||||
// Layout all root elements.
|
// Layout all root elements.
|
||||||
let mut root_element = self.window.root_view.as_ref().unwrap().clone().into_any();
|
let mut root_element = self.window.root_view.as_ref().unwrap().clone().into_any();
|
||||||
root_element.layout(Point::default(), self.window.viewport_size.into(), self);
|
root_element.layout(self.window.viewport_size.into(), self);
|
||||||
|
root_element.before_paint(self);
|
||||||
|
|
||||||
let mut sorted_deferred_draws =
|
let mut sorted_deferred_draws =
|
||||||
(0..self.window.next_frame.deferred_draws.len()).collect::<SmallVec<[_; 8]>>();
|
(0..self.window.next_frame.deferred_draws.len()).collect::<SmallVec<[_; 8]>>();
|
||||||
@@ -411,13 +418,15 @@ impl<'a> ElementContext<'a> {
|
|||||||
let mut tooltip_element = None;
|
let mut tooltip_element = None;
|
||||||
if let Some(prompt) = self.window.prompt.take() {
|
if let Some(prompt) = self.window.prompt.take() {
|
||||||
let mut element = prompt.view.any_view().into_any();
|
let mut element = prompt.view.any_view().into_any();
|
||||||
element.layout(Point::default(), self.window.viewport_size.into(), self);
|
element.layout(self.window.viewport_size.into(), self);
|
||||||
|
element.before_paint(self);
|
||||||
prompt_element = Some(element);
|
prompt_element = Some(element);
|
||||||
self.window.prompt = Some(prompt);
|
self.window.prompt = Some(prompt);
|
||||||
} else if let Some(active_drag) = self.app.active_drag.take() {
|
} else if let Some(active_drag) = self.app.active_drag.take() {
|
||||||
let mut element = active_drag.view.clone().into_any();
|
let mut element = active_drag.view.clone().into_any();
|
||||||
|
element.layout(AvailableSpace::min_size(), self);
|
||||||
let offset = self.mouse_position() - active_drag.cursor_offset;
|
let offset = self.mouse_position() - active_drag.cursor_offset;
|
||||||
element.layout(offset, AvailableSpace::min_size(), self);
|
self.with_element_offset(offset, |cx| element.before_paint(cx));
|
||||||
active_drag_element = Some(element);
|
active_drag_element = Some(element);
|
||||||
self.app.active_drag = Some(active_drag);
|
self.app.active_drag = Some(active_drag);
|
||||||
} else {
|
} else {
|
||||||
@@ -446,7 +455,7 @@ impl<'a> ElementContext<'a> {
|
|||||||
let tooltip_request = tooltip_request.unwrap();
|
let tooltip_request = tooltip_request.unwrap();
|
||||||
let mut element = tooltip_request.tooltip.view.clone().into_any();
|
let mut element = tooltip_request.tooltip.view.clone().into_any();
|
||||||
let mouse_position = tooltip_request.tooltip.mouse_position;
|
let mouse_position = tooltip_request.tooltip.mouse_position;
|
||||||
let tooltip_size = element.measure(AvailableSpace::min_size(), self);
|
let tooltip_size = element.layout(AvailableSpace::min_size(), self).size;
|
||||||
|
|
||||||
let mut tooltip_bounds = Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
|
let mut tooltip_bounds = Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
|
||||||
let window_bounds = Bounds {
|
let window_bounds = Bounds {
|
||||||
@@ -478,7 +487,7 @@ impl<'a> ElementContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.with_absolute_element_offset(tooltip_bounds.origin, |cx| element.after_layout(cx));
|
self.with_absolute_element_offset(tooltip_bounds.origin, |cx| element.before_paint(cx));
|
||||||
|
|
||||||
self.window.tooltip_bounds = Some(TooltipBounds {
|
self.window.tooltip_bounds = Some(TooltipBounds {
|
||||||
id: tooltip_request.id,
|
id: tooltip_request.id,
|
||||||
@@ -500,16 +509,16 @@ impl<'a> ElementContext<'a> {
|
|||||||
.dispatch_tree
|
.dispatch_tree
|
||||||
.set_active_node(deferred_draw.parent_node);
|
.set_active_node(deferred_draw.parent_node);
|
||||||
|
|
||||||
let layout_start = self.after_layout_index();
|
let layout_start = self.before_paint_index();
|
||||||
if let Some(element) = deferred_draw.element.as_mut() {
|
if let Some(element) = deferred_draw.element.as_mut() {
|
||||||
self.with_absolute_element_offset(deferred_draw.absolute_offset, |cx| {
|
self.with_absolute_element_offset(deferred_draw.absolute_offset, |cx| {
|
||||||
element.after_layout(cx)
|
element.before_paint(cx)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.reuse_after_layout(deferred_draw.layout_range.clone());
|
self.reuse_before_paint(deferred_draw.before_paint_range.clone());
|
||||||
}
|
}
|
||||||
let layout_end = self.after_layout_index();
|
let layout_end = self.before_paint_index();
|
||||||
deferred_draw.layout_range = layout_start..layout_end;
|
deferred_draw.before_paint_range = layout_start..layout_end;
|
||||||
}
|
}
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
self.window.next_frame.deferred_draws.len(),
|
self.window.next_frame.deferred_draws.len(),
|
||||||
@@ -548,6 +557,26 @@ impl<'a> ElementContext<'a> {
|
|||||||
|
|
||||||
pub(crate) fn after_layout_index(&self) -> AfterLayoutIndex {
|
pub(crate) fn after_layout_index(&self) -> AfterLayoutIndex {
|
||||||
AfterLayoutIndex {
|
AfterLayoutIndex {
|
||||||
|
accessed_element_states_index: self.window.next_frame.accessed_element_states.len(),
|
||||||
|
line_layout_index: self.window.text_system.layout_index(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn reuse_after_layout(&mut self, range: Range<AfterLayoutIndex>) {
|
||||||
|
let window = &mut self.window;
|
||||||
|
window.next_frame.accessed_element_states.extend(
|
||||||
|
window.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
|
||||||
|
..range.end.accessed_element_states_index]
|
||||||
|
.iter()
|
||||||
|
.cloned(),
|
||||||
|
);
|
||||||
|
window
|
||||||
|
.text_system
|
||||||
|
.reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn before_paint_index(&self) -> BeforePaintIndex {
|
||||||
|
BeforePaintIndex {
|
||||||
hitboxes_index: self.window.next_frame.hitboxes.len(),
|
hitboxes_index: self.window.next_frame.hitboxes.len(),
|
||||||
tooltips_index: self.window.next_frame.tooltip_requests.len(),
|
tooltips_index: self.window.next_frame.tooltip_requests.len(),
|
||||||
deferred_draws_index: self.window.next_frame.deferred_draws.len(),
|
deferred_draws_index: self.window.next_frame.deferred_draws.len(),
|
||||||
@@ -557,7 +586,7 @@ impl<'a> ElementContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reuse_after_layout(&mut self, range: Range<AfterLayoutIndex>) {
|
pub(crate) fn reuse_before_paint(&mut self, range: Range<BeforePaintIndex>) {
|
||||||
let window = &mut self.window;
|
let window = &mut self.window;
|
||||||
window.next_frame.hitboxes.extend(
|
window.next_frame.hitboxes.extend(
|
||||||
window.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
|
window.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
|
||||||
@@ -595,7 +624,7 @@ impl<'a> ElementContext<'a> {
|
|||||||
priority: deferred_draw.priority,
|
priority: deferred_draw.priority,
|
||||||
element: None,
|
element: None,
|
||||||
absolute_offset: deferred_draw.absolute_offset,
|
absolute_offset: deferred_draw.absolute_offset,
|
||||||
layout_range: deferred_draw.layout_range.clone(),
|
before_paint_range: deferred_draw.before_paint_range.clone(),
|
||||||
paint_range: deferred_draw.paint_range.clone(),
|
paint_range: deferred_draw.paint_range.clone(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -974,7 +1003,7 @@ impl<'a> ElementContext<'a> {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
window.draw_phase,
|
window.draw_phase,
|
||||||
DrawPhase::Layout,
|
DrawPhase::Layout,
|
||||||
"defer_draw can only be called during before_layout or after_layout"
|
"defer_draw can only be called during before_layout or before_paint"
|
||||||
);
|
);
|
||||||
let parent_node = window.next_frame.dispatch_tree.active_node_id().unwrap();
|
let parent_node = window.next_frame.dispatch_tree.active_node_id().unwrap();
|
||||||
window.next_frame.deferred_draws.push(DeferredDraw {
|
window.next_frame.deferred_draws.push(DeferredDraw {
|
||||||
@@ -984,7 +1013,7 @@ impl<'a> ElementContext<'a> {
|
|||||||
priority,
|
priority,
|
||||||
element: Some(element),
|
element: Some(element),
|
||||||
absolute_offset,
|
absolute_offset,
|
||||||
layout_range: AfterLayoutIndex::default()..AfterLayoutIndex::default(),
|
before_paint_range: BeforePaintIndex::default()..BeforePaintIndex::default(),
|
||||||
paint_range: PaintIndex::default()..PaintIndex::default(),
|
paint_range: PaintIndex::default()..PaintIndex::default(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1397,7 +1426,7 @@ impl<'a> ElementContext<'a> {
|
|||||||
bounds
|
bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method should be called during `after_layout`. You can use
|
/// This method should be called during `before_paint`. You can use
|
||||||
/// the returned [Hitbox] during `paint` or in an event handler
|
/// the returned [Hitbox] during `paint` or in an event handler
|
||||||
/// to determine whether the inserted hitbox was the topmost.
|
/// to determine whether the inserted hitbox was the topmost.
|
||||||
pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, opaque: bool) -> Hitbox {
|
pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, opaque: bool) -> Hitbox {
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ impl FocusableView for ImageView {
|
|||||||
|
|
||||||
impl Render for ImageView {
|
impl Render for ImageView {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
let checkered_background = |bounds: Bounds<Pixels>, _, cx: &mut ElementContext| {
|
let checkered_background = |bounds: Bounds<Pixels>, cx: &mut ElementContext| {
|
||||||
let square_size = 32.0;
|
let square_size = 32.0;
|
||||||
|
|
||||||
let start_y = bounds.origin.y.0;
|
let start_y = bounds.origin.y.0;
|
||||||
@@ -190,7 +190,7 @@ impl Render for ImageView {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let checkered_background = canvas(|_, _| (), checkered_background)
|
let checkered_background = canvas(checkered_background)
|
||||||
.border_2()
|
.border_2()
|
||||||
.border_color(cx.theme().styles.colors.border)
|
.border_color(cx.theme().styles.colors.border)
|
||||||
.size_full()
|
.size_full()
|
||||||
|
|||||||
@@ -363,14 +363,15 @@ impl Render for SyntaxTreeView {
|
|||||||
.text_bg(cx.theme().colors().background).into_any_element();
|
.text_bg(cx.theme().colors().background).into_any_element();
|
||||||
|
|
||||||
rendered = rendered.child(
|
rendered = rendered.child(
|
||||||
canvas(
|
// canvas(
|
||||||
move |bounds, cx| {
|
// move |bounds, cx| {
|
||||||
list.layout(bounds.origin, bounds.size.into(), cx);
|
// list.layout(bounds.origin, bounds.size.into(), cx);
|
||||||
list
|
// list
|
||||||
},
|
// },
|
||||||
|_, mut list, cx| list.paint(cx),
|
// |_, mut list, cx| list.paint(cx),
|
||||||
)
|
// )
|
||||||
.size_full(),
|
// .size_full(),
|
||||||
|
todo!("replace canvas"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -542,7 +542,7 @@ impl TerminalElement {
|
|||||||
|
|
||||||
impl Element for TerminalElement {
|
impl Element for TerminalElement {
|
||||||
type BeforeLayout = ();
|
type BeforeLayout = ();
|
||||||
type AfterLayout = LayoutState;
|
type BeforePaint = LayoutState;
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
self.interactivity.occlude_mouse();
|
self.interactivity.occlude_mouse();
|
||||||
@@ -556,14 +556,14 @@ impl Element for TerminalElement {
|
|||||||
(layout_id, ())
|
(layout_id, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(
|
fn before_paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::BeforeLayout,
|
_: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Self::AfterLayout {
|
) -> Self::BeforePaint {
|
||||||
self.interactivity
|
self.interactivity
|
||||||
.after_layout(bounds, bounds.size, cx, |_, _, hitbox, cx| {
|
.before_paint(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();
|
||||||
|
|
||||||
@@ -776,7 +776,7 @@ impl Element for TerminalElement {
|
|||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_: &mut Self::BeforeLayout,
|
_: &mut Self::BeforeLayout,
|
||||||
layout: &mut Self::AfterLayout,
|
layout: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext<'_>,
|
cx: &mut ElementContext<'_>,
|
||||||
) {
|
) {
|
||||||
cx.paint_quad(fill(bounds, layout.background_color));
|
cx.paint_quad(fill(bounds, layout.background_color));
|
||||||
|
|||||||
@@ -169,7 +169,8 @@ pub struct PopoverMenuFrameState {
|
|||||||
|
|
||||||
impl<M: ManagedView> Element for PopoverMenu<M> {
|
impl<M: ManagedView> Element for PopoverMenu<M> {
|
||||||
type BeforeLayout = PopoverMenuFrameState;
|
type BeforeLayout = PopoverMenuFrameState;
|
||||||
type AfterLayout = Option<HitboxId>;
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = Option<HitboxId>;
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (gpui::LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (gpui::LayoutId, Self::BeforeLayout) {
|
||||||
self.with_element_state(cx, |this, element_state, cx| {
|
self.with_element_state(cx, |this, element_state, cx| {
|
||||||
@@ -219,14 +220,40 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
|
|||||||
_bounds: Bounds<Pixels>,
|
_bounds: Bounds<Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Option<HitboxId> {
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
self.with_element_state(cx, |_this, element_state, cx| {
|
cx.with_element_id(Some(self.id.clone()), |cx| {
|
||||||
|
let mut focus_target_bounds = None;
|
||||||
|
|
||||||
if let Some(child) = before_layout.child_element.as_mut() {
|
if let Some(child) = before_layout.child_element.as_mut() {
|
||||||
child.after_layout(cx);
|
if let Some(child_focus_target_bounds) = child.after_layout(cx) {
|
||||||
|
focus_target_bounds = Some(child_focus_target_bounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(menu) = before_layout.menu_element.as_mut() {
|
if let Some(menu) = before_layout.menu_element.as_mut() {
|
||||||
menu.after_layout(cx);
|
if let Some(menu_focus_target_bounds) = menu.after_layout(cx) {
|
||||||
|
focus_target_bounds = Some(menu_focus_target_bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(focus_target_bounds, ())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> Option<HitboxId> {
|
||||||
|
self.with_element_state(cx, |_this, element_state, cx| {
|
||||||
|
if let Some(child) = before_layout.child_element.as_mut() {
|
||||||
|
child.before_paint(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(menu) = before_layout.menu_element.as_mut() {
|
||||||
|
menu.before_paint(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
before_layout.child_layout_id.map(|layout_id| {
|
before_layout.child_layout_id.map(|layout_id| {
|
||||||
@@ -241,6 +268,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
_: Bounds<gpui::Pixels>,
|
_: Bounds<gpui::Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
child_hitbox: &mut Option<HitboxId>,
|
child_hitbox: &mut Option<HitboxId>,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ pub struct MenuHandleFrameState {
|
|||||||
|
|
||||||
impl<M: ManagedView> Element for RightClickMenu<M> {
|
impl<M: ManagedView> Element for RightClickMenu<M> {
|
||||||
type BeforeLayout = MenuHandleFrameState;
|
type BeforeLayout = MenuHandleFrameState;
|
||||||
type AfterLayout = Hitbox;
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = Hitbox;
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (gpui::LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (gpui::LayoutId, Self::BeforeLayout) {
|
||||||
self.with_element_state(cx, |this, element_state, cx| {
|
self.with_element_state(cx, |this, element_state, cx| {
|
||||||
@@ -144,20 +145,46 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
before_layout: &mut Self::BeforeLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
cx.with_element_id(Some(self.id.clone()), |cx| {
|
||||||
|
let mut focus_target_bounds = None;
|
||||||
|
|
||||||
|
if let Some(child) = before_layout.child_element.as_mut() {
|
||||||
|
if let Some(child_focus_target_bounds) = child.after_layout(cx) {
|
||||||
|
focus_target_bounds = Some(child_focus_target_bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(menu) = before_layout.menu_element.as_mut() {
|
||||||
|
if let Some(menu_focus_target_bounds) = menu.after_layout(cx) {
|
||||||
|
focus_target_bounds = Some(menu_focus_target_bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(focus_target_bounds, ())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> Hitbox {
|
) -> Hitbox {
|
||||||
cx.with_element_id(Some(self.id.clone()), |cx| {
|
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) = before_layout.child_element.as_mut() {
|
if let Some(child) = before_layout.child_element.as_mut() {
|
||||||
child.after_layout(cx);
|
child.before_paint(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(menu) = before_layout.menu_element.as_mut() {
|
if let Some(menu) = before_layout.menu_element.as_mut() {
|
||||||
menu.after_layout(cx);
|
menu.before_paint(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
hitbox
|
hitbox
|
||||||
@@ -168,7 +195,8 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
_bounds: Bounds<gpui::Pixels>,
|
_bounds: Bounds<gpui::Pixels>,
|
||||||
before_layout: &mut Self::BeforeLayout,
|
before_layout: &mut Self::BeforeLayout,
|
||||||
hitbox: &mut Self::AfterLayout,
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
hitbox: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
self.with_element_state(cx, |this, element_state, cx| {
|
self.with_element_state(cx, |this, element_state, cx| {
|
||||||
|
|||||||
@@ -649,7 +649,7 @@ mod element {
|
|||||||
children: Vec<PaneAxisChildLayout>,
|
children: Vec<PaneAxisChildLayout>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PaneAxisChildLayout {
|
pub struct PaneAxisChildLayout {
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
element: AnyElement,
|
element: AnyElement,
|
||||||
handle: Option<PaneAxisHandleLayout>,
|
handle: Option<PaneAxisHandleLayout>,
|
||||||
@@ -793,7 +793,8 @@ mod element {
|
|||||||
|
|
||||||
impl Element for PaneAxisElement {
|
impl Element for PaneAxisElement {
|
||||||
type BeforeLayout = ();
|
type BeforeLayout = ();
|
||||||
type AfterLayout = PaneAxisLayout;
|
type AfterLayout = Vec<PaneAxisChildLayout>;
|
||||||
|
type BeforePaint = PaneAxisLayout;
|
||||||
|
|
||||||
fn before_layout(
|
fn before_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -811,18 +812,9 @@ mod element {
|
|||||||
fn after_layout(
|
fn after_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
_state: &mut Self::BeforeLayout,
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) -> PaneAxisLayout {
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
let dragged_handle = cx.with_element_state::<Rc<RefCell<Option<usize>>>, _>(
|
|
||||||
Some(self.basis.into()),
|
|
||||||
|state, _cx| {
|
|
||||||
let state = state
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_or_else(|| Rc::new(RefCell::new(None)));
|
|
||||||
(state.clone(), Some(state))
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let flexes = self.flexes.lock().clone();
|
let flexes = self.flexes.lock().clone();
|
||||||
let len = self.children.len();
|
let len = self.children.len();
|
||||||
debug_assert!(flexes.len() == len);
|
debug_assert!(flexes.len() == len);
|
||||||
@@ -844,13 +836,9 @@ mod element {
|
|||||||
let mut origin = bounds.origin;
|
let mut origin = bounds.origin;
|
||||||
let space_per_flex = bounds.size.along(self.axis) / total_flex;
|
let space_per_flex = bounds.size.along(self.axis) / total_flex;
|
||||||
|
|
||||||
let mut bounding_boxes = self.bounding_boxes.lock();
|
let mut focus_target_bounds = None;
|
||||||
bounding_boxes.clear();
|
|
||||||
|
|
||||||
let mut layout = PaneAxisLayout {
|
let mut children = Vec::new();
|
||||||
dragged_handle: dragged_handle.clone(),
|
|
||||||
children: Vec::new(),
|
|
||||||
};
|
|
||||||
for (ix, mut child) in mem::take(&mut self.children).into_iter().enumerate() {
|
for (ix, mut child) in mem::take(&mut self.children).into_iter().enumerate() {
|
||||||
let child_flex = active_pane_magnification
|
let child_flex = active_pane_magnification
|
||||||
.map(|magnification| {
|
.map(|magnification| {
|
||||||
@@ -866,25 +854,76 @@ mod element {
|
|||||||
.size
|
.size
|
||||||
.apply_along(self.axis, |_| space_per_flex * child_flex)
|
.apply_along(self.axis, |_| space_per_flex * child_flex)
|
||||||
.map(|d| d.round());
|
.map(|d| d.round());
|
||||||
|
let child_bounds = Bounds::new(origin, child_size);
|
||||||
|
|
||||||
let child_bounds = Bounds {
|
let child_measurement = child.layout(child_size.into(), cx);
|
||||||
origin,
|
if let Some(child_focus_target_bounds) = child_measurement.focus_target_bounds {
|
||||||
size: child_size,
|
focus_target_bounds = Some(Bounds::new(
|
||||||
};
|
child_bounds.origin + child_focus_target_bounds.origin,
|
||||||
bounding_boxes.push(Some(child_bounds));
|
child_focus_target_bounds.size,
|
||||||
child.layout(origin, child_size.into(), cx);
|
));
|
||||||
|
}
|
||||||
|
|
||||||
origin = origin.apply_along(self.axis, |val| val + child_size.along(self.axis));
|
origin = origin.apply_along(self.axis, |val| val + child_size.along(self.axis));
|
||||||
layout.children.push(PaneAxisChildLayout {
|
children.push(PaneAxisChildLayout {
|
||||||
bounds: child_bounds,
|
bounds: child_bounds,
|
||||||
element: child,
|
element: child,
|
||||||
handle: None,
|
handle: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ix, child_layout) in layout.children.iter_mut().enumerate() {
|
(focus_target_bounds, children)
|
||||||
if active_pane_magnification.is_none() {
|
}
|
||||||
if ix < len - 1 {
|
|
||||||
|
fn before_paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
_before_layout: &mut Self::BeforeLayout,
|
||||||
|
children: &mut Self::AfterLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> PaneAxisLayout {
|
||||||
|
let dragged_handle = cx.with_element_state::<Rc<RefCell<Option<usize>>>, _>(
|
||||||
|
Some(self.basis.into()),
|
||||||
|
|state, _cx| {
|
||||||
|
let state = state
|
||||||
|
.unwrap()
|
||||||
|
.unwrap_or_else(|| Rc::new(RefCell::new(None)));
|
||||||
|
(state.clone(), Some(state))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let magnification_value = WorkspaceSettings::get(None, cx).active_pane_magnification;
|
||||||
|
let active_pane_magnification = if magnification_value == 1. {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(magnification_value)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut origin = bounds.origin;
|
||||||
|
|
||||||
|
let mut bounding_boxes = self.bounding_boxes.lock();
|
||||||
|
bounding_boxes.clear();
|
||||||
|
|
||||||
|
let mut layout = PaneAxisLayout {
|
||||||
|
dragged_handle: dragged_handle.clone(),
|
||||||
|
children: Vec::new(),
|
||||||
|
};
|
||||||
|
for child in children {
|
||||||
|
let child_bounds = Bounds {
|
||||||
|
origin,
|
||||||
|
size: child.bounds.size,
|
||||||
|
};
|
||||||
|
bounding_boxes.push(Some(child_bounds));
|
||||||
|
cx.with_absolute_element_offset(origin, |cx| child.element.before_paint(cx));
|
||||||
|
origin =
|
||||||
|
origin.apply_along(self.axis, |val| val + child_bounds.size.along(self.axis));
|
||||||
|
child.bounds = child_bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if active_pane_magnification.is_none() {
|
||||||
|
let mut child_layouts = layout.children.iter_mut().peekable();
|
||||||
|
while let Some(child_layout) = child_layouts.next() {
|
||||||
|
if child_layouts.peek().is_some() {
|
||||||
child_layout.handle =
|
child_layout.handle =
|
||||||
Some(Self::layout_handle(self.axis, child_layout.bounds, cx));
|
Some(Self::layout_handle(self.axis, child_layout.bounds, cx));
|
||||||
}
|
}
|
||||||
@@ -898,7 +937,8 @@ mod element {
|
|||||||
&mut self,
|
&mut self,
|
||||||
bounds: gpui::Bounds<ui::prelude::Pixels>,
|
bounds: gpui::Bounds<ui::prelude::Pixels>,
|
||||||
_: &mut Self::BeforeLayout,
|
_: &mut Self::BeforeLayout,
|
||||||
layout: &mut Self::AfterLayout,
|
_: &mut Self::AfterLayout,
|
||||||
|
layout: &mut Self::BeforePaint,
|
||||||
cx: &mut ui::prelude::ElementContext,
|
cx: &mut ui::prelude::ElementContext,
|
||||||
) {
|
) {
|
||||||
for child in &mut layout.children {
|
for child in &mut layout.children {
|
||||||
|
|||||||
@@ -4007,12 +4007,9 @@ impl Render for Workspace {
|
|||||||
.border_color(colors.border)
|
.border_color(colors.border)
|
||||||
.child({
|
.child({
|
||||||
let this = cx.view().clone();
|
let this = cx.view().clone();
|
||||||
canvas(
|
canvas(move |bounds, cx| this.update(cx, |this, _cx| this.bounds = bounds))
|
||||||
move |bounds, cx| this.update(cx, |this, _cx| this.bounds = bounds),
|
.absolute()
|
||||||
|_, _, _| {},
|
.size_full()
|
||||||
)
|
|
||||||
.absolute()
|
|
||||||
.size_full()
|
|
||||||
})
|
})
|
||||||
.when(self.zoomed.is_none(), |this| {
|
.when(self.zoomed.is_none(), |this| {
|
||||||
this.on_drag_move(cx.listener(
|
this.on_drag_move(cx.listener(
|
||||||
@@ -4973,6 +4970,7 @@ struct DisconnectedOverlay;
|
|||||||
impl Element for DisconnectedOverlay {
|
impl Element for DisconnectedOverlay {
|
||||||
type BeforeLayout = AnyElement;
|
type BeforeLayout = AnyElement;
|
||||||
type AfterLayout = ();
|
type AfterLayout = ();
|
||||||
|
type BeforePaint = ();
|
||||||
|
|
||||||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||||
let mut background = cx.theme().colors().elevated_surface_background;
|
let mut background = cx.theme().colors().elevated_surface_background;
|
||||||
@@ -4996,20 +4994,31 @@ impl Element for DisconnectedOverlay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn after_layout(
|
fn after_layout(
|
||||||
|
&mut self,
|
||||||
|
_bounds: Bounds<Pixels>,
|
||||||
|
overlay: &mut Self::BeforeLayout,
|
||||||
|
cx: &mut ElementContext,
|
||||||
|
) -> (Option<Bounds<Pixels>>, Self::AfterLayout) {
|
||||||
|
(overlay.after_layout(cx), ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
overlay: &mut Self::BeforeLayout,
|
overlay: &mut Self::BeforeLayout,
|
||||||
|
_after_layout: &mut Self::AfterLayout,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
cx.insert_hitbox(bounds, true);
|
cx.insert_hitbox(bounds, true);
|
||||||
overlay.after_layout(cx);
|
overlay.before_paint(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: Bounds<Pixels>,
|
_: Bounds<Pixels>,
|
||||||
overlay: &mut Self::BeforeLayout,
|
overlay: &mut Self::BeforeLayout,
|
||||||
_: &mut Self::AfterLayout,
|
_after_layout: &mut Self::AfterLayout,
|
||||||
|
_: &mut Self::BeforePaint,
|
||||||
cx: &mut ElementContext,
|
cx: &mut ElementContext,
|
||||||
) {
|
) {
|
||||||
overlay.paint(cx)
|
overlay.paint(cx)
|
||||||
|
|||||||
Reference in New Issue
Block a user