Detailed changes
@@ -1584,27 +1584,34 @@ mod tests {
}
fn editor_blocks(editor: &View<Editor>, cx: &mut WindowContext) -> Vec<(u32, SharedString)> {
+ let editor_view = editor.clone();
editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(cx);
snapshot
.blocks_in_range(0..snapshot.max_point().row())
.enumerate()
.filter_map(|(ix, (row, block))| {
- let name = match block {
- TransformBlock::Custom(block) => block
- .render(&mut BlockContext {
- view_context: cx,
- anchor_x: px(0.),
- gutter_padding: px(0.),
- gutter_width: px(0.),
- line_height: px(0.),
- em_width: px(0.),
- block_id: ix,
- editor_style: &editor::EditorStyle::default(),
- })
- .inner_id()?
- .try_into()
- .ok()?,
+ let name: SharedString = match block {
+ TransformBlock::Custom(block) => cx.with_element_context({
+ let editor_view = editor_view.clone();
+ |cx| -> Option<SharedString> {
+ block
+ .render(&mut BlockContext {
+ context: cx,
+ anchor_x: px(0.),
+ gutter_padding: px(0.),
+ gutter_width: px(0.),
+ line_height: px(0.),
+ em_width: px(0.),
+ block_id: ix,
+ view: editor_view,
+ editor_style: &editor::EditorStyle::default(),
+ })
+ .inner_id()?
+ .try_into()
+ .ok()
+ }
+ })?,
TransformBlock::ExcerptHeader {
starts_new_buffer, ..
@@ -4,7 +4,7 @@ use super::{
};
use crate::{Anchor, Editor, EditorStyle, ExcerptId, ExcerptRange, ToPoint as _};
use collections::{Bound, HashMap, HashSet};
-use gpui::{AnyElement, Pixels, ViewContext};
+use gpui::{AnyElement, ElementContext, Pixels, View};
use language::{BufferSnapshot, Chunk, Patch, Point};
use parking_lot::Mutex;
use std::{
@@ -81,7 +81,8 @@ pub enum BlockStyle {
}
pub struct BlockContext<'a, 'b> {
- pub view_context: &'b mut ViewContext<'a, Editor>,
+ pub context: &'b mut ElementContext<'a>,
+ pub view: View<Editor>,
pub anchor_x: Pixels,
pub gutter_width: Pixels,
pub gutter_padding: Pixels,
@@ -933,16 +934,16 @@ impl BlockDisposition {
}
impl<'a> Deref for BlockContext<'a, '_> {
- type Target = ViewContext<'a, Editor>;
+ type Target = ElementContext<'a>;
fn deref(&self) -> &Self::Target {
- self.view_context
+ self.context
}
}
impl DerefMut for BlockContext<'_, '_> {
fn deref_mut(&mut self) -> &mut Self::Target {
- self.view_context
+ self.context
}
}
@@ -3912,7 +3912,7 @@ impl Editor {
gutter_hovered: bool,
_line_height: Pixels,
_gutter_margin: Pixels,
- cx: &mut ViewContext<Self>,
+ editor_view: View<Editor>,
) -> Vec<Option<IconButton>> {
fold_data
.iter()
@@ -3922,14 +3922,19 @@ impl Editor {
.map(|(fold_status, buffer_row, active)| {
(active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
IconButton::new(ix as usize, ui::IconName::ChevronDown)
- .on_click(cx.listener(move |editor, _e, cx| match fold_status {
- FoldStatus::Folded => {
- editor.unfold_at(&UnfoldAt { buffer_row }, cx);
- }
- FoldStatus::Foldable => {
- editor.fold_at(&FoldAt { buffer_row }, cx);
+ .on_click({
+ let view = editor_view.clone();
+ move |_e, cx| {
+ view.update(cx, |editor, cx| match fold_status {
+ FoldStatus::Folded => {
+ editor.unfold_at(&UnfoldAt { buffer_row }, cx);
+ }
+ FoldStatus::Foldable => {
+ editor.fold_at(&FoldAt { buffer_row }, cx);
+ }
+ })
}
- }))
+ })
.icon_color(ui::Color::Muted)
.icon_size(ui::IconSize::Small)
.selected(fold_status == FoldStatus::Folded)
@@ -9575,10 +9580,10 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, _is_valid: bool) -> Ren
.size(ButtonSize::Compact)
.style(ButtonStyle::Transparent)
.visible_on_hover(group_id)
- .on_click(cx.listener({
+ .on_click({
let message = diagnostic.message.clone();
- move |_, _, cx| cx.write_to_clipboard(ClipboardItem::new(message.clone()))
- }))
+ move |_click, cx| cx.write_to_clipboard(ClipboardItem::new(message.clone()))
+ })
.tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)),
)
.into_any_element()
@@ -25,12 +25,12 @@ use collections::{BTreeMap, HashMap};
use git::diff::DiffHunkStatus;
use gpui::{
div, fill, outline, overlay, point, px, quad, relative, size, transparent_black, Action,
- AnchorCorner, AnyElement, AvailableSpace, BorrowWindow, Bounds, ContentMask, Corners,
- CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Hsla,
- InteractiveBounds, InteractiveElement, IntoElement, ModifiersChangedEvent, MouseButton,
- MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, ScrollDelta,
- ScrollWheelEvent, ShapedLine, SharedString, Size, StackingOrder, StatefulInteractiveElement,
- Style, Styled, TextRun, TextStyle, View, ViewContext, WindowContext,
+ AnchorCorner, AnyElement, AvailableSpace, Bounds, ContentMask, Corners, CursorStyle,
+ DispatchPhase, Edges, Element, ElementInputHandler, Entity, Hsla, InteractiveBounds,
+ InteractiveElement, IntoElement, ModifiersChangedEvent, MouseButton, MouseDownEvent,
+ MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine,
+ SharedString, Size, StackingOrder, StatefulInteractiveElement, Style, Styled, TextRun,
+ TextStyle, View, ViewContext, WindowContext,
};
use itertools::Itertools;
use language::language_settings::ShowWhitespaceSetting;
@@ -330,7 +330,7 @@ impl EditorElement {
register_action(view, cx, Editor::display_cursor_names);
}
- fn register_key_listeners(&self, cx: &mut WindowContext) {
+ fn register_key_listeners(&self, cx: &mut ElementContext) {
cx.on_key_event({
let editor = self.editor.clone();
move |event: &ModifiersChangedEvent, phase, cx| {
@@ -628,7 +628,7 @@ impl EditorElement {
gutter_bounds: Bounds<Pixels>,
text_bounds: Bounds<Pixels>,
layout: &LayoutState,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let bounds = gutter_bounds.union(&text_bounds);
let scroll_top =
@@ -711,7 +711,7 @@ impl EditorElement {
&mut self,
bounds: Bounds<Pixels>,
layout: &mut LayoutState,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let line_height = layout.position_map.line_height;
@@ -782,7 +782,7 @@ impl EditorElement {
});
}
- fn paint_diff_hunks(bounds: Bounds<Pixels>, layout: &LayoutState, cx: &mut WindowContext) {
+ fn paint_diff_hunks(bounds: Bounds<Pixels>, layout: &LayoutState, cx: &mut ElementContext) {
let line_height = layout.position_map.line_height;
let scroll_position = layout.position_map.snapshot.scroll_position();
@@ -886,7 +886,7 @@ impl EditorElement {
&mut self,
text_bounds: Bounds<Pixels>,
layout: &mut LayoutState,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let start_row = layout.visible_display_row_range.start;
let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
@@ -1153,7 +1153,7 @@ impl EditorElement {
&mut self,
text_bounds: Bounds<Pixels>,
layout: &mut LayoutState,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
let start_row = layout.visible_display_row_range.start;
@@ -1268,7 +1268,7 @@ impl EditorElement {
&mut self,
bounds: Bounds<Pixels>,
layout: &mut LayoutState,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
if layout.mode != EditorMode::Full {
return;
@@ -1512,7 +1512,7 @@ impl EditorElement {
layout: &LayoutState,
content_origin: gpui::Point<Pixels>,
bounds: Bounds<Pixels>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let start_row = layout.visible_display_row_range.start;
let end_row = layout.visible_display_row_range.end;
@@ -1564,7 +1564,7 @@ impl EditorElement {
&mut self,
bounds: Bounds<Pixels>,
layout: &mut LayoutState,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let scroll_position = layout.position_map.snapshot.scroll_position();
let scroll_left = scroll_position.x * layout.position_map.em_width;
@@ -1814,7 +1814,7 @@ impl EditorElement {
}
}
- fn compute_layout(&mut self, bounds: Bounds<Pixels>, cx: &mut WindowContext) -> LayoutState {
+ fn compute_layout(&mut self, bounds: Bounds<Pixels>, cx: &mut ElementContext) -> LayoutState {
self.editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(cx);
let style = self.style.clone();
@@ -2083,7 +2083,9 @@ impl EditorElement {
.width;
let scroll_width = longest_line_width.max(max_visible_line_width) + overscroll.width;
- let (scroll_width, blocks) = cx.with_element_id(Some("editor_blocks"), |cx| {
+ let editor_view = cx.view().clone();
+ let (scroll_width, blocks) = cx.with_element_context(|cx| {
+ cx.with_element_id(Some("editor_blocks"), |cx| {
self.layout_blocks(
start_row..end_row,
&snapshot,
@@ -2097,8 +2099,10 @@ impl EditorElement {
&style,
&line_layouts,
editor,
+ editor_view,
cx,
)
+ })
});
let scroll_max = point(
@@ -2174,15 +2178,19 @@ impl EditorElement {
cx,
);
- let fold_indicators = cx.with_element_id(Some("gutter_fold_indicators"), |cx| {
+ let editor_view = cx.view().clone();
+ let fold_indicators = cx.with_element_context(|cx| {
+
+ cx.with_element_id(Some("gutter_fold_indicators"), |_cx| {
editor.render_fold_indicators(
fold_statuses,
&style,
editor.gutter_hovered,
line_height,
gutter_margin,
- cx,
+ editor_view,
)
+ })
});
let invisible_symbol_font_size = font_size / 2.;
@@ -2273,7 +2281,8 @@ impl EditorElement {
style: &EditorStyle,
line_layouts: &[LineWithInvisibles],
editor: &mut Editor,
- cx: &mut ViewContext<Editor>,
+ editor_view: View<Editor>,
+ cx: &mut ElementContext,
) -> (Pixels, Vec<BlockLayout>) {
let mut block_id = 0;
let (fixed_blocks, non_fixed_blocks) = snapshot
@@ -2287,7 +2296,7 @@ impl EditorElement {
available_space: Size<AvailableSpace>,
block_id: usize,
editor: &mut Editor,
- cx: &mut ViewContext<Editor>| {
+ cx: &mut ElementContext| {
let mut element = match block {
TransformBlock::Custom(block) => {
let align_to = block
@@ -2306,13 +2315,14 @@ impl EditorElement {
};
block.render(&mut BlockContext {
- view_context: cx,
+ context: cx,
anchor_x,
gutter_padding,
line_height,
gutter_width,
em_width,
block_id,
+ view: editor_view.clone(),
editor_style: &self.style,
})
}
@@ -2504,7 +2514,7 @@ impl EditorElement {
&mut self,
interactive_bounds: &InteractiveBounds,
layout: &LayoutState,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
cx.on_mouse_event({
let position_map = layout.position_map.clone();
@@ -2564,7 +2574,7 @@ impl EditorElement {
gutter_bounds: Bounds<Pixels>,
text_bounds: Bounds<Pixels>,
layout: &LayoutState,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let interactive_bounds = InteractiveBounds {
bounds: bounds.intersect(&cx.content_mask().bounds),
@@ -2787,7 +2797,7 @@ impl LineWithInvisibles {
content_origin: gpui::Point<Pixels>,
whitespace_setting: ShowWhitespaceSetting,
selection_ranges: &[Range<DisplayPoint>],
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let line_height = layout.position_map.line_height;
let line_y = line_height * row as f32 - layout.position_map.scroll_position.y;
@@ -2821,7 +2831,7 @@ impl LineWithInvisibles {
row: u32,
line_height: Pixels,
whitespace_setting: ShowWhitespaceSetting,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let allowed_invisibles_regions = match whitespace_setting {
ShowWhitespaceSetting::None => return,
@@ -2870,7 +2880,7 @@ impl Element for EditorElement {
fn request_layout(
&mut self,
_element_state: Option<Self::State>,
- cx: &mut gpui::WindowContext,
+ cx: &mut gpui::ElementContext,
) -> (gpui::LayoutId, Self::State) {
cx.with_view_id(self.editor.entity_id(), |cx| {
self.editor.update(cx, |editor, cx| {
@@ -2882,34 +2892,36 @@ impl Element for EditorElement {
let mut style = Style::default();
style.size.width = relative(1.).into();
style.size.height = self.style.text.line_height_in_pixels(rem_size).into();
- cx.request_layout(&style, None)
+ cx.with_element_context(|cx| cx.request_layout(&style, None))
}
EditorMode::AutoHeight { max_lines } => {
let editor_handle = cx.view().clone();
let max_line_number_width =
self.max_line_number_width(&editor.snapshot(cx), cx);
- cx.request_measured_layout(
- Style::default(),
- move |known_dimensions, _, cx| {
- editor_handle
- .update(cx, |editor, cx| {
- compute_auto_height_layout(
- editor,
- max_lines,
- max_line_number_width,
- known_dimensions,
- cx,
- )
- })
- .unwrap_or_default()
- },
- )
+ cx.with_element_context(|cx| {
+ cx.request_measured_layout(
+ Style::default(),
+ move |known_dimensions, _, cx| {
+ editor_handle
+ .update(cx, |editor, cx| {
+ compute_auto_height_layout(
+ editor,
+ max_lines,
+ max_line_number_width,
+ known_dimensions,
+ cx,
+ )
+ })
+ .unwrap_or_default()
+ },
+ )
+ })
}
EditorMode::Full => {
let mut style = Style::default();
style.size.width = relative(1.).into();
style.size.height = relative(1.).into();
- cx.request_layout(&style, None)
+ cx.with_element_context(|cx| cx.request_layout(&style, None))
}
};
@@ -2922,7 +2934,7 @@ impl Element for EditorElement {
&mut self,
bounds: Bounds<gpui::Pixels>,
_element_state: &mut Self::State,
- cx: &mut gpui::WindowContext,
+ cx: &mut gpui::ElementContext,
) {
let editor = self.editor.clone();
@@ -3204,7 +3216,7 @@ impl Cursor {
}
}
- pub fn paint(&self, origin: gpui::Point<Pixels>, cx: &mut WindowContext) {
+ pub fn paint(&self, origin: gpui::Point<Pixels>, cx: &mut ElementContext) {
let bounds = match self.shape {
CursorShape::Bar => Bounds {
origin: self.origin + origin,
@@ -3284,7 +3296,7 @@ pub struct HighlightedRangeLine {
}
impl HighlightedRange {
- pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
+ pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut ElementContext) {
if self.lines.len() >= 2 && self.lines[0].start_x > self.lines[1].end_x {
self.paint_lines(self.start_y, &self.lines[0..1], bounds, cx);
self.paint_lines(
@@ -3303,7 +3315,7 @@ impl HighlightedRange {
start_y: Pixels,
lines: &[HighlightedRangeLine],
_bounds: Bounds<Pixels>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
if lines.is_empty() {
return;
@@ -3521,14 +3533,16 @@ mod tests {
.unwrap();
let state = cx
.update_window(window.into(), |view, cx| {
- cx.with_view_id(view.entity_id(), |cx| {
- element.compute_layout(
- Bounds {
- origin: point(px(500.), px(500.)),
- size: size(px(500.), px(500.)),
- },
- cx,
- )
+ cx.with_element_context(|cx| {
+ cx.with_view_id(view.entity_id(), |cx| {
+ element.compute_layout(
+ Bounds {
+ origin: point(px(500.), px(500.)),
+ size: size(px(500.), px(500.)),
+ },
+ cx,
+ )
+ })
})
})
.unwrap();
@@ -3615,14 +3629,16 @@ mod tests {
let state = cx
.update_window(window.into(), |view, cx| {
- cx.with_view_id(view.entity_id(), |cx| {
- element.compute_layout(
- Bounds {
- origin: point(px(500.), px(500.)),
- size: size(px(500.), px(500.)),
- },
- cx,
- )
+ cx.with_element_context(|cx| {
+ cx.with_view_id(view.entity_id(), |cx| {
+ element.compute_layout(
+ Bounds {
+ origin: point(px(500.), px(500.)),
+ size: size(px(500.), px(500.)),
+ },
+ cx,
+ )
+ })
})
})
.unwrap();
@@ -3679,14 +3695,16 @@ mod tests {
let mut element = EditorElement::new(&editor, style);
let state = cx
.update_window(window.into(), |view, cx| {
- cx.with_view_id(view.entity_id(), |cx| {
- element.compute_layout(
- Bounds {
- origin: point(px(500.), px(500.)),
- size: size(px(500.), px(500.)),
- },
- cx,
- )
+ cx.with_element_context(|cx| {
+ cx.with_view_id(view.entity_id(), |cx| {
+ element.compute_layout(
+ Bounds {
+ origin: point(px(500.), px(500.)),
+ size: size(px(500.), px(500.)),
+ },
+ cx,
+ )
+ })
})
})
.unwrap();
@@ -3704,8 +3722,10 @@ mod tests {
// Don't panic.
let bounds = Bounds::<Pixels>::new(Default::default(), size);
- cx.update_window(window.into(), |_, cx| element.paint(bounds, &mut (), cx))
- .unwrap()
+ cx.update_window(window.into(), |_, cx| {
+ cx.with_element_context(|cx| element.paint(bounds, &mut (), cx))
+ })
+ .unwrap()
}
#[gpui::test]
@@ -3880,13 +3900,15 @@ mod tests {
.unwrap();
let layout_state = cx
.update_window(window.into(), |_, cx| {
- element.compute_layout(
- Bounds {
- origin: point(px(500.), px(500.)),
- size: size(px(500.), px(500.)),
- },
- cx,
- )
+ cx.with_element_context(|cx| {
+ element.compute_layout(
+ Bounds {
+ origin: point(px(500.), px(500.)),
+ size: size(px(500.), px(500.)),
+ },
+ cx,
+ )
+ })
})
.unwrap();
@@ -640,8 +640,11 @@ impl<'a> VisualTestContext {
.as_ref()
.expect("Can't draw to this window without a root view")
.entity_id();
- cx.with_view_id(entity_id, |cx| {
- f(cx).draw(origin, space, cx);
+
+ cx.with_element_context(|cx| {
+ cx.with_view_id(entity_id, |cx| {
+ f(cx).draw(origin, space, cx);
+ })
});
cx.refresh();
@@ -35,12 +35,12 @@
//! your own custom layout algorithm or rendering a code editor.
use crate::{
- util::FluentBuilder, ArenaBox, AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId,
+ util::FluentBuilder, ArenaBox, AvailableSpace, Bounds, ElementContext, ElementId, LayoutId,
Pixels, Point, Size, ViewContext, WindowContext, ELEMENT_ARENA,
};
use derive_more::{Deref, DerefMut};
pub(crate) use smallvec::SmallVec;
-use std::{any::Any, fmt::Debug};
+use std::{any::Any, fmt::Debug, ops::DerefMut};
/// Implemented by types that participate in laying out and painting the contents of a window.
/// Elements form a tree and are laid out according to web-based layout rules, as implemented by Taffy.
@@ -56,12 +56,12 @@ pub trait Element: 'static + IntoElement {
fn request_layout(
&mut self,
state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State);
/// 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::request_layout()`].
- fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext);
+ fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext);
/// Convert this element into a dynamically-typed [`AnyElement`].
fn into_any(self) -> AnyElement {
@@ -95,8 +95,8 @@ pub trait IntoElement: Sized {
self,
origin: Point<Pixels>,
available_space: Size<T>,
- cx: &mut WindowContext,
- f: impl FnOnce(&mut <Self::Element as Element>::State, &mut WindowContext) -> R,
+ cx: &mut ElementContext,
+ f: impl FnOnce(&mut <Self::Element as Element>::State, &mut ElementContext) -> R,
) -> R
where
T: Clone + Default + Debug + Into<AvailableSpace>,
@@ -193,14 +193,19 @@ impl<C: RenderOnce> Element for Component<C> {
fn request_layout(
&mut self,
_: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
- let mut element = self.0.take().unwrap().render(cx).into_any_element();
+ let mut element = self
+ .0
+ .take()
+ .unwrap()
+ .render(cx.deref_mut())
+ .into_any_element();
let layout_id = element.request_layout(cx);
(layout_id, element)
}
- fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
+ fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut ElementContext) {
element.paint(cx)
}
}
@@ -224,21 +229,21 @@ pub(crate) struct GlobalElementId(SmallVec<[ElementId; 32]>);
trait ElementObject {
fn element_id(&self) -> Option<ElementId>;
- fn request_layout(&mut self, cx: &mut WindowContext) -> LayoutId;
+ fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId;
- fn paint(&mut self, cx: &mut WindowContext);
+ fn paint(&mut self, cx: &mut ElementContext);
fn measure(
&mut self,
available_space: Size<AvailableSpace>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> Size<Pixels>;
fn draw(
&mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
);
}
@@ -276,7 +281,7 @@ impl<E: Element> DrawableElement<E> {
self.element.as_ref()?.element_id()
}
- fn request_layout(&mut self, cx: &mut WindowContext) -> LayoutId {
+ fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
{
let layout_id = cx.with_element_state(id, |element_state, cx| {
@@ -298,7 +303,7 @@ impl<E: Element> DrawableElement<E> {
layout_id
}
- fn paint(mut self, cx: &mut WindowContext) -> Option<E::State> {
+ fn paint(mut self, cx: &mut ElementContext) -> Option<E::State> {
match self.phase {
ElementDrawPhase::LayoutRequested {
layout_id,
@@ -343,7 +348,7 @@ impl<E: Element> DrawableElement<E> {
fn measure(
&mut self,
available_space: Size<AvailableSpace>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> Size<Pixels> {
if matches!(&self.phase, ElementDrawPhase::Start) {
self.request_layout(cx);
@@ -384,7 +389,7 @@ impl<E: Element> DrawableElement<E> {
mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> Option<E::State> {
self.measure(available_space, cx);
cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
@@ -400,18 +405,18 @@ where
self.as_ref().unwrap().element_id()
}
- fn request_layout(&mut self, cx: &mut WindowContext) -> LayoutId {
+ fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
DrawableElement::request_layout(self.as_mut().unwrap(), cx)
}
- fn paint(&mut self, cx: &mut WindowContext) {
+ fn paint(&mut self, cx: &mut ElementContext) {
DrawableElement::paint(self.take().unwrap(), cx);
}
fn measure(
&mut self,
available_space: Size<AvailableSpace>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> Size<Pixels> {
DrawableElement::measure(self.as_mut().unwrap(), available_space, cx)
}
@@ -420,7 +425,7 @@ where
&mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
DrawableElement::draw(self.take().unwrap(), origin, available_space, cx);
}
@@ -443,12 +448,12 @@ impl AnyElement {
/// Request the layout ID of the element stored in this `AnyElement`.
/// Used for laying out child elements in a parent element.
- pub fn request_layout(&mut self, cx: &mut WindowContext) -> LayoutId {
+ pub fn request_layout(&mut self, cx: &mut ElementContext) -> LayoutId {
self.0.request_layout(cx)
}
/// Paints the element stored in this `AnyElement`.
- pub fn paint(&mut self, cx: &mut WindowContext) {
+ pub fn paint(&mut self, cx: &mut ElementContext) {
self.0.paint(cx)
}
@@ -456,7 +461,7 @@ impl AnyElement {
pub fn measure(
&mut self,
available_space: Size<AvailableSpace>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> Size<Pixels> {
self.0.measure(available_space, cx)
}
@@ -466,7 +471,7 @@ impl AnyElement {
&mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
self.0.draw(origin, available_space, cx)
}
@@ -483,13 +488,13 @@ impl Element for AnyElement {
fn request_layout(
&mut self,
_: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
let layout_id = self.request_layout(cx);
(layout_id, ())
}
- fn paint(&mut self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut WindowContext) {
+ fn paint(&mut self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut ElementContext) {
self.paint(cx)
}
}
@@ -531,7 +536,7 @@ impl Element for () {
fn request_layout(
&mut self,
_state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
(cx.request_layout(&crate::Style::default(), None), ())
}
@@ -540,7 +545,7 @@ impl Element for () {
&mut self,
_bounds: Bounds<Pixels>,
_state: &mut Self::State,
- _cx: &mut WindowContext,
+ _cx: &mut ElementContext,
) {
}
}
@@ -1,10 +1,10 @@
use refineable::Refineable as _;
-use crate::{Bounds, Element, IntoElement, Pixels, Style, StyleRefinement, Styled, WindowContext};
+use crate::{Bounds, Element, ElementContext, IntoElement, Pixels, Style, StyleRefinement, Styled};
/// Construct a canvas element with the given paint callback.
/// Useful for adding short term custom drawing to a view.
-pub fn canvas(callback: impl 'static + FnOnce(&Bounds<Pixels>, &mut WindowContext)) -> Canvas {
+pub fn canvas(callback: impl 'static + FnOnce(&Bounds<Pixels>, &mut ElementContext)) -> Canvas {
Canvas {
paint_callback: Some(Box::new(callback)),
style: StyleRefinement::default(),
@@ -14,7 +14,7 @@ pub fn canvas(callback: impl 'static + FnOnce(&Bounds<Pixels>, &mut WindowContex
/// A canvas element, meant for accessing the low level paint API without defining a whole
/// custom element
pub struct Canvas {
- paint_callback: Option<Box<dyn FnOnce(&Bounds<Pixels>, &mut WindowContext)>>,
+ paint_callback: Option<Box<dyn FnOnce(&Bounds<Pixels>, &mut ElementContext)>>,
style: StyleRefinement,
}
@@ -36,7 +36,7 @@ impl Element for Canvas {
fn request_layout(
&mut self,
_: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (crate::LayoutId, Self::State) {
let mut style = Style::default();
style.refine(&self.style);
@@ -44,7 +44,7 @@ impl Element for Canvas {
(layout_id, style)
}
- fn paint(&mut self, bounds: Bounds<Pixels>, style: &mut Style, cx: &mut WindowContext) {
+ fn paint(&mut self, bounds: Bounds<Pixels>, style: &mut Style, cx: &mut ElementContext) {
style.paint(bounds, cx, |cx| {
(self.paint_callback.take().unwrap())(&bounds, cx)
});
@@ -23,12 +23,11 @@
//!
use crate::{
- point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext,
- BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId, FocusHandle, IntoElement,
- IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent,
- MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Render, ScrollWheelEvent,
- SharedString, Size, StackingOrder, Style, StyleRefinement, Styled, Task, View, Visibility,
- WindowContext,
+ point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, Bounds, ClickEvent,
+ DispatchPhase, Element, ElementContext, ElementId, FocusHandle, IntoElement, IsZero,
+ KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent,
+ MouseUpEvent, ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size,
+ StackingOrder, Style, StyleRefinement, Styled, Task, View, Visibility, WindowContext,
};
use collections::HashMap;
@@ -41,6 +40,7 @@ use std::{
fmt::Debug,
marker::PhantomData,
mem,
+ ops::DerefMut,
rc::Rc,
time::Duration,
};
@@ -1052,7 +1052,7 @@ impl Element for Div {
fn request_layout(
&mut self,
element_state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
let mut child_layout_ids = SmallVec::new();
let (layout_id, interactive_state) = self.interactivity.layout(
@@ -1082,7 +1082,7 @@ impl Element for Div {
&mut self,
bounds: Bounds<Pixels>,
element_state: &mut Self::State,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let mut child_min = point(Pixels::MAX, Pixels::MAX);
let mut child_max = Point::default();
@@ -1233,8 +1233,8 @@ impl Interactivity {
pub fn layout(
&mut self,
element_state: Option<InteractiveElementState>,
- cx: &mut WindowContext,
- f: impl FnOnce(Style, &mut WindowContext) -> LayoutId,
+ cx: &mut ElementContext,
+ f: impl FnOnce(Style, &mut ElementContext) -> LayoutId,
) -> (LayoutId, InteractiveElementState) {
let mut element_state = element_state.unwrap_or_default();
@@ -1281,8 +1281,8 @@ impl Interactivity {
bounds: Bounds<Pixels>,
content_size: Size<Pixels>,
element_state: &mut InteractiveElementState,
- cx: &mut WindowContext,
- f: impl FnOnce(&Style, Point<Pixels>, &mut WindowContext),
+ cx: &mut ElementContext,
+ f: impl FnOnce(&Style, Point<Pixels>, &mut ElementContext),
) {
let style = self.compute_style(Some(bounds), element_state, cx);
let z_index = style.z_index.unwrap_or(0);
@@ -1295,7 +1295,7 @@ impl Interactivity {
.insert(debug_selector.clone(), bounds);
}
- let paint_hover_group_handler = |cx: &mut WindowContext| {
+ let paint_hover_group_handler = |cx: &mut ElementContext| {
let hover_group_bounds = self
.group_hover_style
.as_ref()
@@ -1319,7 +1319,7 @@ impl Interactivity {
}
cx.with_z_index(z_index, |cx| {
- style.paint(bounds, cx, |cx| {
+ style.paint(bounds, cx, |cx: &mut ElementContext| {
cx.with_text_style(style.text_style().cloned(), |cx| {
cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
#[cfg(debug_assertions)]
@@ -1333,7 +1333,7 @@ impl Interactivity {
let element_id = format!("{:?}", self.element_id.as_ref().unwrap());
let str_len = element_id.len();
- let render_debug_text = |cx: &mut WindowContext| {
+ let render_debug_text = |cx: &mut ElementContext| {
if let Some(text) = cx
.text_system()
.shape_text(
@@ -1540,12 +1540,17 @@ impl Interactivity {
let mut can_drop = true;
if let Some(predicate) = &can_drop_predicate {
- can_drop =
- predicate(drag.value.as_ref(), cx);
+ can_drop = predicate(
+ drag.value.as_ref(),
+ cx.deref_mut(),
+ );
}
if can_drop {
- listener(drag.value.as_ref(), cx);
+ listener(
+ drag.value.as_ref(),
+ cx.deref_mut(),
+ );
cx.refresh();
cx.stop_propagation();
}
@@ -1676,7 +1681,7 @@ impl Interactivity {
*was_hovered = is_hovered;
drop(was_hovered);
- hover_listener(&is_hovered, cx);
+ hover_listener(&is_hovered, cx.deref_mut());
}
});
}
@@ -1897,7 +1902,7 @@ impl Interactivity {
&self,
bounds: Option<Bounds<Pixels>>,
element_state: &mut InteractiveElementState,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> Style {
let mut style = Style::default();
style.refine(&self.base_style);
@@ -1921,7 +1926,9 @@ impl Interactivity {
let mouse_position = cx.mouse_position();
if !cx.has_active_drag() {
if let Some(group_hover) = self.group_hover_style.as_ref() {
- if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
+ if let Some(group_bounds) =
+ GroupBounds::get(&group_hover.group, cx.deref_mut())
+ {
if group_bounds.contains(&mouse_position)
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
{
@@ -1944,13 +1951,13 @@ impl Interactivity {
if let Some(drag) = cx.active_drag.take() {
let mut can_drop = true;
if let Some(can_drop_predicate) = &self.can_drop_predicate {
- can_drop = can_drop_predicate(drag.value.as_ref(), cx);
+ can_drop = can_drop_predicate(drag.value.as_ref(), cx.deref_mut());
}
if can_drop {
for (state_type, group_drag_style) in &self.group_drag_over_styles {
if let Some(group_bounds) =
- GroupBounds::get(&group_drag_style.group, cx)
+ GroupBounds::get(&group_drag_style.group, cx.deref_mut())
{
if *state_type == drag.value.as_ref().type_id()
&& group_bounds.contains(&mouse_position)
@@ -2096,12 +2103,12 @@ where
fn request_layout(
&mut self,
state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
self.element.request_layout(state, cx)
}
- fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
+ fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext) {
self.element.paint(bounds, state, cx)
}
}
@@ -2171,12 +2178,12 @@ where
fn request_layout(
&mut self,
state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
self.element.request_layout(state, cx)
}
- fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
+ fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext) {
self.element.paint(bounds, state, cx)
}
}
@@ -1,9 +1,9 @@
use std::sync::Arc;
use crate::{
- point, size, BorrowWindow, Bounds, DevicePixels, Element, ImageData, InteractiveElement,
+ point, size, Bounds, DevicePixels, Element, ElementContext, ImageData, InteractiveElement,
InteractiveElementState, Interactivity, IntoElement, LayoutId, Pixels, SharedUrl, Size,
- StyleRefinement, Styled, WindowContext,
+ StyleRefinement, Styled,
};
use futures::FutureExt;
use media::core_video::CVImageBuffer;
@@ -81,7 +81,7 @@ impl Element for Img {
fn request_layout(
&mut self,
element_state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
self.interactivity
.layout(element_state, cx, |style, cx| cx.request_layout(&style, []))
@@ -91,7 +91,7 @@ impl Element for Img {
&mut self,
bounds: Bounds<Pixels>,
element_state: &mut Self::State,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let source = self.source.clone();
self.interactivity.paint(
@@ -7,9 +7,9 @@
//! If all of your elements are the same height, see [`UniformList`] for a simpler API
use crate::{
- point, px, AnyElement, AvailableSpace, BorrowAppContext, BorrowWindow, Bounds, ContentMask,
- DispatchPhase, Element, IntoElement, Pixels, Point, ScrollWheelEvent, Size, Style,
- StyleRefinement, Styled, WindowContext,
+ point, px, AnyElement, AvailableSpace, Bounds, ContentMask, DispatchPhase, Element,
+ IntoElement, Pixels, Point, ScrollWheelEvent, Size, Style, StyleRefinement, Styled,
+ WindowContext,
};
use collections::VecDeque;
use refineable::Refineable as _;
@@ -359,7 +359,7 @@ impl Element for List {
fn request_layout(
&mut self,
_state: Option<Self::State>,
- cx: &mut crate::WindowContext,
+ cx: &mut crate::ElementContext,
) -> (crate::LayoutId, Self::State) {
let mut style = Style::default();
style.refine(&self.style);
@@ -373,7 +373,7 @@ impl Element for List {
&mut self,
bounds: Bounds<crate::Pixels>,
_state: &mut Self::State,
- cx: &mut crate::WindowContext,
+ cx: &mut crate::ElementContext,
) {
let state = &mut *self.state.0.borrow_mut();
@@ -2,8 +2,8 @@ use smallvec::SmallVec;
use taffy::style::{Display, Position};
use crate::{
- point, AnyElement, BorrowWindow, Bounds, Element, IntoElement, LayoutId, ParentElement, Pixels,
- Point, Size, Style, WindowContext,
+ point, AnyElement, Bounds, Element, ElementContext, IntoElement, LayoutId, ParentElement,
+ Pixels, Point, Size, Style,
};
/// The state that the overlay element uses to track its children.
@@ -74,7 +74,7 @@ impl Element for Overlay {
fn request_layout(
&mut self,
_: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (crate::LayoutId, Self::State) {
let child_layout_ids = self
.children
@@ -97,7 +97,7 @@ impl Element for Overlay {
&mut self,
bounds: crate::Bounds<crate::Pixels>,
element_state: &mut Self::State,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
if element_state.child_layout_ids.is_empty() {
return;
@@ -1,6 +1,6 @@
use crate::{
- Bounds, Element, ElementId, InteractiveElement, InteractiveElementState, Interactivity,
- IntoElement, LayoutId, Pixels, SharedString, StyleRefinement, Styled, WindowContext,
+ Bounds, Element, ElementContext, ElementId, InteractiveElement, InteractiveElementState,
+ Interactivity, IntoElement, LayoutId, Pixels, SharedString, StyleRefinement, Styled,
};
use util::ResultExt;
@@ -32,7 +32,7 @@ impl Element for Svg {
fn request_layout(
&mut self,
element_state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
self.interactivity.layout(element_state, cx, |style, cx| {
cx.request_layout(&style, None)
@@ -43,7 +43,7 @@ impl Element for Svg {
&mut self,
bounds: Bounds<Pixels>,
element_state: &mut Self::State,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) where
Self: Sized,
{
@@ -1,7 +1,8 @@
use crate::{
- ActiveTooltip, AnyTooltip, AnyView, Bounds, DispatchPhase, Element, ElementId, HighlightStyle,
- IntoElement, LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point,
- SharedString, Size, TextRun, TextStyle, WhiteSpace, WindowContext, WrappedLine, TOOLTIP_DELAY,
+ ActiveTooltip, AnyTooltip, AnyView, Bounds, DispatchPhase, Element, ElementContext, ElementId,
+ HighlightStyle, IntoElement, LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
+ Point, SharedString, Size, TextRun, TextStyle, WhiteSpace, WindowContext, WrappedLine,
+ TOOLTIP_DELAY,
};
use anyhow::anyhow;
use parking_lot::{Mutex, MutexGuard};
@@ -21,14 +22,14 @@ impl Element for &'static str {
fn request_layout(
&mut self,
_: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
let mut state = TextState::default();
let layout_id = state.layout(SharedString::from(*self), None, cx);
(layout_id, state)
}
- fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
+ fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut ElementContext) {
state.paint(bounds, self, cx)
}
}
@@ -51,14 +52,14 @@ impl Element for SharedString {
fn request_layout(
&mut self,
_: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
let mut state = TextState::default();
let layout_id = state.layout(self.clone(), None, cx);
(layout_id, state)
}
- fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
+ fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut ElementContext) {
let text_str: &str = self.as_ref();
state.paint(bounds, text_str, cx)
}
@@ -130,14 +131,14 @@ impl Element for StyledText {
fn request_layout(
&mut self,
_: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
let mut state = TextState::default();
let layout_id = state.layout(self.text.clone(), self.runs.take(), cx);
(layout_id, state)
}
- fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
+ fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext) {
state.paint(bounds, &self.text, cx)
}
}
@@ -174,7 +175,7 @@ impl TextState {
&mut self,
text: SharedString,
runs: Option<Vec<TextRun>>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> LayoutId {
let text_style = cx.text_style();
let font_size = text_style.font_size.to_pixels(cx.rem_size());
@@ -249,7 +250,7 @@ impl TextState {
layout_id
}
- fn paint(&mut self, bounds: Bounds<Pixels>, text: &str, cx: &mut WindowContext) {
+ fn paint(&mut self, bounds: Bounds<Pixels>, text: &str, cx: &mut ElementContext) {
let element_state = self.lock();
let element_state = element_state
.as_ref()
@@ -377,7 +378,7 @@ impl Element for InteractiveText {
fn request_layout(
&mut self,
state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
if let Some(InteractiveTextState {
mouse_down_index,
@@ -406,7 +407,7 @@ impl Element for InteractiveText {
}
}
- fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
+ fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext) {
if let Some(click_listener) = self.click_listener.take() {
let mouse_position = cx.mouse_position();
if let Some(ix) = state.text_state.index_for_position(bounds, mouse_position) {
@@ -5,7 +5,7 @@
//! elements with uniform height.
use crate::{
- point, px, size, AnyElement, AvailableSpace, BorrowWindow, Bounds, ContentMask, Element,
+ point, px, size, AnyElement, AvailableSpace, Bounds, ContentMask, Element, ElementContext,
ElementId, InteractiveElement, InteractiveElementState, Interactivity, IntoElement, LayoutId,
Pixels, Render, Size, StyleRefinement, Styled, View, ViewContext, WindowContext,
};
@@ -110,7 +110,7 @@ impl Element for UniformList {
fn request_layout(
&mut self,
state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
let max_items = self.item_count;
let item_size = state
@@ -158,7 +158,7 @@ impl Element for UniformList {
&mut self,
bounds: Bounds<crate::Pixels>,
element_state: &mut Self::State,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let style =
self.interactivity
@@ -280,7 +280,7 @@ impl UniformList {
self
}
- fn measure_item(&self, list_width: Option<Pixels>, cx: &mut WindowContext) -> Size<Pixels> {
+ fn measure_item(&self, list_width: Option<Pixels>, cx: &mut ElementContext) -> Size<Pixels> {
if self.item_count == 0 {
return Size::default();
}
@@ -220,11 +220,6 @@ pub trait EventEmitter<E: Any>: 'static {}
/// A helper trait for auto-implementing certain methods on contexts that
/// can be used interchangeably.
pub trait BorrowAppContext {
- /// Run a closure with a text style pushed onto the context.
- fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
- where
- F: FnOnce(&mut Self) -> R;
-
/// Set a global value on the context.
fn set_global<T: 'static>(&mut self, global: T);
}
@@ -233,20 +228,6 @@ impl<C> BorrowAppContext for C
where
C: BorrowMut<AppContext>,
{
- fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
- where
- F: FnOnce(&mut Self) -> R,
- {
- if let Some(style) = style {
- self.borrow_mut().push_text_style(style);
- let result = f(self);
- self.borrow_mut().pop_text_style();
- result
- } else {
- f(self)
- }
- }
-
fn set_global<G: 'static>(&mut self, global: G) {
self.borrow_mut().set_global(global)
}
@@ -1,6 +1,6 @@
use crate::{
- Action, ActionRegistry, DispatchPhase, EntityId, FocusId, KeyBinding, KeyContext, Keymap,
- KeymatchResult, Keystroke, KeystrokeMatcher, WindowContext,
+ Action, ActionRegistry, DispatchPhase, ElementContext, EntityId, FocusId, KeyBinding,
+ KeyContext, Keymap, KeymatchResult, Keystroke, KeystrokeMatcher, WindowContext,
};
use collections::FxHashMap;
use parking_lot::Mutex;
@@ -36,7 +36,7 @@ pub(crate) struct DispatchNode {
parent: Option<DispatchNodeId>,
}
-type KeyListener = Rc<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>;
+type KeyListener = Rc<dyn Fn(&dyn Any, DispatchPhase, &mut ElementContext)>;
#[derive(Clone)]
pub(crate) struct DispatchActionListener {
@@ -1,10 +1,10 @@
use std::{iter, mem, ops::Range};
use crate::{
- black, phi, point, quad, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds,
- ContentMask, Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement,
- Font, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba,
- SharedString, Size, SizeRefinement, Styled, TextRun, WindowContext,
+ black, phi, point, quad, rems, AbsoluteLength, BorrowAppContext, Bounds, ContentMask, Corners,
+ CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, ElementContext, Font,
+ FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba,
+ SharedString, Size, SizeRefinement, Styled, TextRun,
};
use collections::HashSet;
use refineable::{Cascade, Refineable};
@@ -308,61 +308,12 @@ impl Style {
}
}
- pub fn apply_text_style<C, F, R>(&self, cx: &mut C, f: F) -> R
- where
- C: BorrowAppContext,
- F: FnOnce(&mut C) -> R,
- {
- if self.text.is_some() {
- cx.with_text_style(Some(self.text.clone()), f)
- } else {
- f(cx)
- }
- }
-
- /// Apply overflow to content mask
- pub fn apply_overflow<C, F, R>(&self, bounds: Bounds<Pixels>, cx: &mut C, f: F) -> R
- where
- C: BorrowWindow,
- F: FnOnce(&mut C) -> R,
- {
- let current_mask = cx.content_mask();
-
- let min = current_mask.bounds.origin;
- let max = current_mask.bounds.lower_right();
-
- let mask_bounds = match (
- self.overflow.x == Overflow::Visible,
- self.overflow.y == Overflow::Visible,
- ) {
- // x and y both visible
- (true, true) => return f(cx),
- // x visible, y hidden
- (true, false) => Bounds::from_corners(
- point(min.x, bounds.origin.y),
- point(max.x, bounds.lower_right().y),
- ),
- // x hidden, y visible
- (false, true) => Bounds::from_corners(
- point(bounds.origin.x, min.y),
- point(bounds.lower_right().x, max.y),
- ),
- // both hidden
- (false, false) => bounds,
- };
- let mask = ContentMask {
- bounds: mask_bounds,
- };
-
- cx.with_content_mask(Some(mask), f)
- }
-
/// Paints the background of an element styled with this style.
pub fn paint(
&self,
bounds: Bounds<Pixels>,
- cx: &mut WindowContext,
- continuation: impl FnOnce(&mut WindowContext),
+ cx: &mut ElementContext,
+ continuation: impl FnOnce(&mut ElementContext),
) {
#[cfg(debug_assertions)]
if self.debug_below {
@@ -1,6 +1,6 @@
use crate::{
- black, fill, point, px, size, BorrowWindow, Bounds, Hsla, LineLayout, Pixels, Point, Result,
- SharedString, UnderlineStyle, WindowContext, WrapBoundary, WrappedLineLayout,
+ black, fill, point, px, size, Bounds, ElementContext, Hsla, LineLayout, Pixels, Point, Result,
+ SharedString, UnderlineStyle, WrapBoundary, WrappedLineLayout,
};
use derive_more::{Deref, DerefMut};
use smallvec::SmallVec;
@@ -33,7 +33,7 @@ impl ShapedLine {
&self,
origin: Point<Pixels>,
line_height: Pixels,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> Result<()> {
paint_line(
origin,
@@ -66,7 +66,7 @@ impl WrappedLine {
&self,
origin: Point<Pixels>,
line_height: Pixels,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> Result<()> {
paint_line(
origin,
@@ -87,7 +87,7 @@ fn paint_line(
line_height: Pixels,
decoration_runs: &[DecorationRun],
wrap_boundaries: &[WrapBoundary],
- cx: &mut WindowContext<'_>,
+ cx: &mut ElementContext<'_>,
) -> Result<()> {
let padding_top = (line_height - layout.ascent - layout.descent) / 2.;
let baseline_offset = point(px(0.), padding_top + layout.ascent);
@@ -1,8 +1,8 @@
use crate::{
- seal::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, BorrowWindow,
- Bounds, ContentMask, Element, ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView,
- IntoElement, LayoutId, Model, Pixels, Point, Render, Size, StackingOrder, Style, TextStyle,
- ViewContext, VisualContext, WeakModel, WindowContext,
+ seal::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, Bounds,
+ ContentMask, Element, ElementContext, ElementId, Entity, EntityId, Flatten, FocusHandle,
+ FocusableView, IntoElement, LayoutId, Model, Pixels, Point, Render, Size, StackingOrder, Style,
+ TextStyle, ViewContext, VisualContext, WeakModel,
};
use anyhow::{Context, Result};
use std::{
@@ -94,7 +94,7 @@ impl<V: Render> Element for View<V> {
fn request_layout(
&mut self,
_state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
cx.with_view_id(self.entity_id(), |cx| {
let mut element = self.update(cx, |view, cx| view.render(cx).into_any_element());
@@ -103,7 +103,7 @@ impl<V: Render> Element for View<V> {
})
}
- fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
+ fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut ElementContext) {
cx.paint_view(self.entity_id(), |cx| element.take().unwrap().paint(cx));
}
}
@@ -202,7 +202,7 @@ impl<V> Eq for WeakView<V> {}
#[derive(Clone, Debug)]
pub struct AnyView {
model: AnyModel,
- request_layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
+ request_layout: fn(&AnyView, &mut ElementContext) -> (LayoutId, AnyElement),
cache: bool,
}
@@ -250,7 +250,7 @@ impl AnyView {
&self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
cx.paint_view(self.entity_id(), |cx| {
cx.with_absolute_element_offset(origin, |cx| {
@@ -278,7 +278,7 @@ impl Element for AnyView {
fn request_layout(
&mut self,
state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
cx.with_view_id(self.entity_id(), |cx| {
if self.cache {
@@ -299,7 +299,7 @@ impl Element for AnyView {
})
}
- fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
+ fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut ElementContext) {
cx.paint_view(self.entity_id(), |cx| {
if !self.cache {
state.element.take().unwrap().paint(cx);
@@ -363,7 +363,7 @@ impl IntoElement for AnyView {
/// A weak, dynamically-typed view handle that does not prevent the view from being released.
pub struct AnyWeakView {
model: AnyWeakModel,
- layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
+ layout: fn(&AnyView, &mut ElementContext) -> (LayoutId, AnyElement),
}
impl AnyWeakView {
@@ -402,11 +402,11 @@ impl std::fmt::Debug for AnyWeakView {
}
mod any_view {
- use crate::{AnyElement, AnyView, IntoElement, LayoutId, Render, WindowContext};
+ use crate::{AnyElement, AnyView, ElementContext, IntoElement, LayoutId, Render};
pub(crate) fn request_layout<V: 'static + Render>(
view: &AnyView,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, AnyElement) {
let view = view.clone().downcast::<V>().unwrap();
let mut element = view.update(cx, |view, cx| view.render(cx).into_any_element());
@@ -1,31 +1,26 @@
use crate::{
- px, size, transparent_black, Action, AnyDrag, AnyTooltip, AnyView, AppContext, Arena,
- AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
- DevicePixels, DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect,
- Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla,
- ImageData, InputHandler, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent,
- KeymatchResult, KeystrokeEvent, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite,
- MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas,
- PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite,
- PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels,
- Scene, Shadow, SharedString, Size, Style, SubscriberSet, Subscription, Surface,
- TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakView,
- WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
+ px, size, transparent_black, Action, AnyDrag, AnyView, AppContext, Arena, AsyncWindowContext,
+ AvailableSpace, Bounds, Context, Corners, CursorStyle, DispatchActionListener, DispatchNodeId,
+ DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten,
+ GlobalElementId, Hsla, KeyBinding, KeyContext, KeyDownEvent, KeymatchResult, KeystrokeEvent,
+ Model, ModelContext, Modifiers, MouseButton, MouseMoveEvent, MouseUpEvent, Pixels,
+ PlatformAtlas, PlatformDisplay, PlatformInput, PlatformWindow, Point, PromptLevel, Render,
+ ScaledPixels, SharedString, Size, SubscriberSet, Subscription, TaffyLayoutEngine, Task, View,
+ VisualContext, WeakView, WindowBounds, WindowOptions,
};
use anyhow::{anyhow, Context as _, Result};
-use collections::{FxHashMap, FxHashSet};
+use collections::FxHashSet;
use derive_more::{Deref, DerefMut};
use futures::{
channel::{mpsc, oneshot},
StreamExt,
};
-use media::core_video::CVImageBuffer;
use parking_lot::RwLock;
use slotmap::SlotMap;
use smallvec::SmallVec;
use std::{
any::{Any, TypeId},
- borrow::{Borrow, BorrowMut, Cow},
+ borrow::{Borrow, BorrowMut},
cell::RefCell,
collections::hash_map::Entry,
fmt::{Debug, Display},
@@ -40,7 +35,10 @@ use std::{
},
time::Duration,
};
-use util::{post_inc, ResultExt};
+use util::ResultExt;
+
+mod element_cx;
+pub use element_cx::*;
const ACTIVE_DRAG_Z_INDEX: u8 = 1;
@@ -51,7 +49,7 @@ pub struct StackingOrder {
#[deref]
#[deref_mut]
context_stack: SmallVec<[u8; 64]>,
- id: u32,
+ pub(crate) id: u32,
}
impl std::fmt::Debug for StackingOrder {
@@ -99,7 +97,7 @@ impl DispatchPhase {
}
type AnyObserver = Box<dyn FnMut(&mut WindowContext) -> bool + 'static>;
-type AnyMouseListener = Box<dyn FnMut(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
+
type AnyWindowFocusListener = Box<dyn FnMut(&FocusEvent, &mut WindowContext) -> bool + 'static>;
struct FocusEvent {
@@ -259,8 +257,8 @@ pub struct Window {
pub(crate) platform_window: Box<dyn PlatformWindow>,
display_id: DisplayId,
sprite_atlas: Arc<dyn PlatformAtlas>,
- rem_size: Pixels,
- viewport_size: Size<Pixels>,
+ pub(crate) rem_size: Pixels,
+ pub(crate) viewport_size: Size<Pixels>,
layout_engine: Option<TaffyLayoutEngine>,
pub(crate) root_view: Option<AnyView>,
pub(crate) element_id_stack: GlobalElementId,
@@ -298,130 +296,10 @@ struct PendingInput {
}
pub(crate) struct ElementStateBox {
- inner: Box<dyn Any>,
- parent_view_id: EntityId,
+ pub(crate) inner: Box<dyn Any>,
+ pub(crate) parent_view_id: EntityId,
#[cfg(debug_assertions)]
- type_name: &'static str,
-}
-
-struct RequestedInputHandler {
- view_id: EntityId,
- handler: Option<PlatformInputHandler>,
-}
-
-struct TooltipRequest {
- view_id: EntityId,
- tooltip: AnyTooltip,
-}
-
-pub(crate) struct Frame {
- focus: Option<FocusId>,
- window_active: bool,
- pub(crate) element_states: FxHashMap<GlobalElementId, ElementStateBox>,
- mouse_listeners: FxHashMap<TypeId, Vec<(StackingOrder, EntityId, AnyMouseListener)>>,
- pub(crate) dispatch_tree: DispatchTree,
- pub(crate) scene: Scene,
- pub(crate) depth_map: Vec<(StackingOrder, EntityId, Bounds<Pixels>)>,
- pub(crate) z_index_stack: StackingOrder,
- pub(crate) next_stacking_order_id: u32,
- next_root_z_index: u8,
- content_mask_stack: Vec<ContentMask<Pixels>>,
- element_offset_stack: Vec<Point<Pixels>>,
- requested_input_handler: Option<RequestedInputHandler>,
- tooltip_request: Option<TooltipRequest>,
- cursor_styles: FxHashMap<EntityId, CursorStyle>,
- requested_cursor_style: Option<CursorStyle>,
- pub(crate) view_stack: Vec<EntityId>,
- pub(crate) reused_views: FxHashSet<EntityId>,
-
- #[cfg(any(test, feature = "test-support"))]
- pub(crate) debug_bounds: collections::FxHashMap<String, Bounds<Pixels>>,
-}
-
-impl Frame {
- fn new(dispatch_tree: DispatchTree) -> Self {
- Frame {
- focus: None,
- window_active: false,
- element_states: FxHashMap::default(),
- mouse_listeners: FxHashMap::default(),
- dispatch_tree,
- scene: Scene::default(),
- depth_map: Vec::new(),
- z_index_stack: StackingOrder::default(),
- next_stacking_order_id: 0,
- next_root_z_index: 0,
- content_mask_stack: Vec::new(),
- element_offset_stack: Vec::new(),
- requested_input_handler: None,
- tooltip_request: None,
- cursor_styles: FxHashMap::default(),
- requested_cursor_style: None,
- view_stack: Vec::new(),
- reused_views: FxHashSet::default(),
-
- #[cfg(any(test, feature = "test-support"))]
- debug_bounds: FxHashMap::default(),
- }
- }
-
- fn clear(&mut self) {
- self.element_states.clear();
- self.mouse_listeners.values_mut().for_each(Vec::clear);
- self.dispatch_tree.clear();
- self.depth_map.clear();
- self.next_stacking_order_id = 0;
- self.next_root_z_index = 0;
- self.reused_views.clear();
- self.scene.clear();
- self.requested_input_handler.take();
- self.tooltip_request.take();
- self.cursor_styles.clear();
- self.requested_cursor_style.take();
- debug_assert_eq!(self.view_stack.len(), 0);
- }
-
- fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
- self.focus
- .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
- .unwrap_or_default()
- }
-
- fn finish(&mut self, prev_frame: &mut Self) {
- // Reuse mouse listeners that didn't change since the last frame.
- for (type_id, listeners) in &mut prev_frame.mouse_listeners {
- let next_listeners = self.mouse_listeners.entry(*type_id).or_default();
- for (order, view_id, listener) in listeners.drain(..) {
- if self.reused_views.contains(&view_id) {
- next_listeners.push((order, view_id, listener));
- }
- }
- }
-
- // Reuse entries in the depth map that didn't change since the last frame.
- for (order, view_id, bounds) in prev_frame.depth_map.drain(..) {
- if self.reused_views.contains(&view_id) {
- match self
- .depth_map
- .binary_search_by(|(level, _, _)| order.cmp(level))
- {
- Ok(i) | Err(i) => self.depth_map.insert(i, (order, view_id, bounds)),
- }
- }
- }
-
- // Retain element states for views that didn't change since the last frame.
- for (element_id, state) in prev_frame.element_states.drain() {
- if self.reused_views.contains(&state.parent_view_id) {
- self.element_states.entry(element_id).or_insert(state);
- }
- }
-
- // Reuse geometry that didn't change since the last frame.
- self.scene
- .reuse_views(&self.reused_views, &mut prev_frame.scene);
- self.scene.finish();
- }
+ pub(crate) type_name: &'static str,
}
impl Window {
@@ -815,80 +693,6 @@ impl<'a> WindowContext<'a> {
result
}
- #[must_use]
- /// Add a node to the layout tree for the current frame. Takes the `Style` of the element for which
- /// layout is being requested, along with the layout ids of any children. This method is called during
- /// calls to the `Element::layout` trait method and enables any element to participate in layout.
- pub fn request_layout(
- &mut self,
- style: &Style,
- children: impl IntoIterator<Item = LayoutId>,
- ) -> LayoutId {
- self.app.layout_id_buffer.clear();
- self.app.layout_id_buffer.extend(children);
- let rem_size = self.rem_size();
-
- self.window.layout_engine.as_mut().unwrap().request_layout(
- style,
- rem_size,
- &self.app.layout_id_buffer,
- )
- }
-
- /// Add a node to the layout tree for the current frame. Instead of taking a `Style` and children,
- /// this variant takes a function that is invoked during layout so you can use arbitrary logic to
- /// determine the element's size. One place this is used internally is when measuring text.
- ///
- /// The given closure is invoked at layout time with the known dimensions and available space and
- /// returns a `Size`.
- pub fn request_measured_layout<
- F: FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut WindowContext) -> Size<Pixels>
- + 'static,
- >(
- &mut self,
- style: Style,
- measure: F,
- ) -> LayoutId {
- let rem_size = self.rem_size();
- self.window
- .layout_engine
- .as_mut()
- .unwrap()
- .request_measured_layout(style, rem_size, measure)
- }
-
- pub(crate) fn layout_style(&self, layout_id: LayoutId) -> Option<&Style> {
- self.window
- .layout_engine
- .as_ref()
- .unwrap()
- .requested_style(layout_id)
- }
-
- /// Compute the layout for the given id within the given available space.
- /// This method is called for its side effect, typically by the framework prior to painting.
- /// After calling it, you can request the bounds of the given layout node id or any descendant.
- pub fn compute_layout(&mut self, layout_id: LayoutId, available_space: Size<AvailableSpace>) {
- let mut layout_engine = self.window.layout_engine.take().unwrap();
- layout_engine.compute_layout(layout_id, available_space, self);
- self.window.layout_engine = Some(layout_engine);
- }
-
- /// Obtain the bounds computed for the given LayoutId relative to the window. This method should not
- /// be invoked until the paint phase begins, and will usually be invoked by GPUI itself automatically
- /// in order to pass your element its `Bounds` automatically.
- pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
- let mut bounds = self
- .window
- .layout_engine
- .as_mut()
- .unwrap()
- .layout_bounds(layout_id)
- .map(Into::into);
- bounds.origin += self.element_offset();
- bounds
- }
-
fn window_bounds_changed(&mut self) {
self.window.scale_factor = self.window.platform_window.scale_factor();
self.window.viewport_size = self.window.platform_window.content_size();
@@ -984,67 +788,6 @@ impl<'a> WindowContext<'a> {
self.window.default_prevented
}
- /// Register a mouse event listener on the window for the next frame. The type of event
- /// is determined by the first parameter of the given listener. When the next frame is rendered
- /// the listener will be cleared.
- pub fn on_mouse_event<Event: MouseEvent>(
- &mut self,
- mut handler: impl FnMut(&Event, DispatchPhase, &mut WindowContext) + 'static,
- ) {
- let view_id = self.parent_view_id();
- let order = self.window.next_frame.z_index_stack.clone();
- self.window
- .next_frame
- .mouse_listeners
- .entry(TypeId::of::<Event>())
- .or_default()
- .push((
- order,
- view_id,
- Box::new(
- move |event: &dyn Any, phase: DispatchPhase, cx: &mut WindowContext<'_>| {
- handler(event.downcast_ref().unwrap(), phase, cx)
- },
- ),
- ))
- }
-
- /// Register a key event listener on the window for the next frame. The type of event
- /// is determined by the first parameter of the given listener. When the next frame is rendered
- /// the listener will be cleared.
- ///
- /// This is a fairly low-level method, so prefer using event handlers on elements unless you have
- /// a specific need to register a global listener.
- pub fn on_key_event<Event: KeyEvent>(
- &mut self,
- listener: impl Fn(&Event, DispatchPhase, &mut WindowContext) + 'static,
- ) {
- self.window.next_frame.dispatch_tree.on_key_event(Rc::new(
- move |event: &dyn Any, phase, cx: &mut WindowContext<'_>| {
- if let Some(event) = event.downcast_ref::<Event>() {
- listener(event, phase, cx)
- }
- },
- ));
- }
-
- /// Register an action listener on the window for the next frame. The type of action
- /// is determined by the first parameter of the given listener. When the next frame is rendered
- /// the listener will be cleared.
- ///
- /// This is a fairly low-level method, so prefer using action handlers on elements unless you have
- /// a specific need to register a global listener.
- pub fn on_action(
- &mut self,
- action_type: TypeId,
- listener: impl Fn(&dyn Any, DispatchPhase, &mut WindowContext) + 'static,
- ) {
- self.window
- .next_frame
- .dispatch_tree
- .on_action(action_type, Rc::new(listener));
- }
-
/// Determine whether the given action is available along the dispatch path to the currently focused element.
pub fn is_action_available(&self, action: &dyn Action) -> bool {
let target = self
@@ -1072,29 +815,6 @@ impl<'a> WindowContext<'a> {
self.window.modifiers
}
- /// Updates the cursor style at the platform level.
- pub fn set_cursor_style(&mut self, style: CursorStyle) {
- let view_id = self.parent_view_id();
- self.window.next_frame.cursor_styles.insert(view_id, style);
- self.window.next_frame.requested_cursor_style = Some(style);
- }
-
- /// Sets a tooltip to be rendered for the upcoming frame
- pub fn set_tooltip(&mut self, tooltip: AnyTooltip) {
- let view_id = self.parent_view_id();
- self.window.next_frame.tooltip_request = Some(TooltipRequest { view_id, tooltip });
- }
-
- /// Called during painting to track which z-index is on top at each pixel position
- pub fn add_opaque_layer(&mut self, bounds: Bounds<Pixels>) {
- let stacking_order = self.window.next_frame.z_index_stack.clone();
- let view_id = self.parent_view_id();
- let depth_map = &mut self.window.next_frame.depth_map;
- match depth_map.binary_search_by(|(level, _, _)| stacking_order.cmp(level)) {
- Ok(i) | Err(i) => depth_map.insert(i, (stacking_order, view_id, bounds)),
- }
- }
-
/// Returns true if there is no opaque layer containing the given point
/// on top of the given level. Layers whose level is an extension of the
/// level are not considered to be on top of the level.
@@ -1136,371 +856,6 @@ impl<'a> WindowContext<'a> {
&self.window.next_frame.z_index_stack
}
- /// Paint one or more drop shadows into the scene for the next frame at the current z-index.
- pub fn paint_shadows(
- &mut self,
- bounds: Bounds<Pixels>,
- corner_radii: Corners<Pixels>,
- shadows: &[BoxShadow],
- ) {
- let scale_factor = self.scale_factor();
- let content_mask = self.content_mask();
- let view_id = self.parent_view_id();
- let window = &mut *self.window;
- for shadow in shadows {
- let mut shadow_bounds = bounds;
- shadow_bounds.origin += shadow.offset;
- shadow_bounds.dilate(shadow.spread_radius);
- window.next_frame.scene.insert(
- &window.next_frame.z_index_stack,
- Shadow {
- view_id: view_id.into(),
- layer_id: 0,
- order: 0,
- bounds: shadow_bounds.scale(scale_factor),
- content_mask: content_mask.scale(scale_factor),
- corner_radii: corner_radii.scale(scale_factor),
- color: shadow.color,
- blur_radius: shadow.blur_radius.scale(scale_factor),
- },
- );
- }
- }
-
- /// Paint one or more quads into the scene for the next frame at the current stacking context.
- /// Quads are colored rectangular regions with an optional background, border, and corner radius.
- /// see [`fill`], [`outline`], and [`quad`] to construct this type.
- pub fn paint_quad(&mut self, quad: PaintQuad) {
- let scale_factor = self.scale_factor();
- let content_mask = self.content_mask();
- let view_id = self.parent_view_id();
-
- let window = &mut *self.window;
- window.next_frame.scene.insert(
- &window.next_frame.z_index_stack,
- Quad {
- view_id: view_id.into(),
- layer_id: 0,
- order: 0,
- bounds: quad.bounds.scale(scale_factor),
- content_mask: content_mask.scale(scale_factor),
- background: quad.background,
- border_color: quad.border_color,
- corner_radii: quad.corner_radii.scale(scale_factor),
- border_widths: quad.border_widths.scale(scale_factor),
- },
- );
- }
-
- /// Paint the given `Path` into the scene for the next frame at the current z-index.
- pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Hsla>) {
- let scale_factor = self.scale_factor();
- let content_mask = self.content_mask();
- let view_id = self.parent_view_id();
-
- path.content_mask = content_mask;
- path.color = color.into();
- path.view_id = view_id.into();
- let window = &mut *self.window;
- window
- .next_frame
- .scene
- .insert(&window.next_frame.z_index_stack, path.scale(scale_factor));
- }
-
- /// Paint an underline into the scene for the next frame at the current z-index.
- pub fn paint_underline(
- &mut self,
- origin: Point<Pixels>,
- width: Pixels,
- style: &UnderlineStyle,
- ) {
- let scale_factor = self.scale_factor();
- let height = if style.wavy {
- style.thickness * 3.
- } else {
- style.thickness
- };
- let bounds = Bounds {
- origin,
- size: size(width, height),
- };
- let content_mask = self.content_mask();
- let view_id = self.parent_view_id();
-
- let window = &mut *self.window;
- window.next_frame.scene.insert(
- &window.next_frame.z_index_stack,
- Underline {
- view_id: view_id.into(),
- layer_id: 0,
- order: 0,
- bounds: bounds.scale(scale_factor),
- content_mask: content_mask.scale(scale_factor),
- thickness: style.thickness.scale(scale_factor),
- color: style.color.unwrap_or_default(),
- wavy: style.wavy,
- },
- );
- }
-
- /// Paint a monochrome (non-emoji) glyph into the scene for the next frame at the current z-index.
- /// The y component of the origin is the baseline of the glyph.
- pub fn paint_glyph(
- &mut self,
- origin: Point<Pixels>,
- font_id: FontId,
- glyph_id: GlyphId,
- font_size: Pixels,
- color: Hsla,
- ) -> Result<()> {
- let scale_factor = self.scale_factor();
- let glyph_origin = origin.scale(scale_factor);
- let subpixel_variant = Point {
- x: (glyph_origin.x.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
- y: (glyph_origin.y.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
- };
- let params = RenderGlyphParams {
- font_id,
- glyph_id,
- font_size,
- subpixel_variant,
- scale_factor,
- is_emoji: false,
- };
-
- let raster_bounds = self.text_system().raster_bounds(¶ms)?;
- if !raster_bounds.is_zero() {
- let tile =
- self.window
- .sprite_atlas
- .get_or_insert_with(¶ms.clone().into(), &mut || {
- let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
- Ok((size, Cow::Owned(bytes)))
- })?;
- let bounds = Bounds {
- origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
- size: tile.bounds.size.map(Into::into),
- };
- let content_mask = self.content_mask().scale(scale_factor);
- let view_id = self.parent_view_id();
- let window = &mut *self.window;
- window.next_frame.scene.insert(
- &window.next_frame.z_index_stack,
- MonochromeSprite {
- view_id: view_id.into(),
- layer_id: 0,
- order: 0,
- bounds,
- content_mask,
- color,
- tile,
- },
- );
- }
- Ok(())
- }
-
- /// Paint an emoji glyph into the scene for the next frame at the current z-index.
- /// The y component of the origin is the baseline of the glyph.
- pub fn paint_emoji(
- &mut self,
- origin: Point<Pixels>,
- font_id: FontId,
- glyph_id: GlyphId,
- font_size: Pixels,
- ) -> Result<()> {
- let scale_factor = self.scale_factor();
- let glyph_origin = origin.scale(scale_factor);
- let params = RenderGlyphParams {
- font_id,
- glyph_id,
- font_size,
- // We don't render emojis with subpixel variants.
- subpixel_variant: Default::default(),
- scale_factor,
- is_emoji: true,
- };
-
- let raster_bounds = self.text_system().raster_bounds(¶ms)?;
- if !raster_bounds.is_zero() {
- let tile =
- self.window
- .sprite_atlas
- .get_or_insert_with(¶ms.clone().into(), &mut || {
- let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
- Ok((size, Cow::Owned(bytes)))
- })?;
- let bounds = Bounds {
- origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
- size: tile.bounds.size.map(Into::into),
- };
- let content_mask = self.content_mask().scale(scale_factor);
- let view_id = self.parent_view_id();
- let window = &mut *self.window;
-
- window.next_frame.scene.insert(
- &window.next_frame.z_index_stack,
- PolychromeSprite {
- view_id: view_id.into(),
- layer_id: 0,
- order: 0,
- bounds,
- corner_radii: Default::default(),
- content_mask,
- tile,
- grayscale: false,
- },
- );
- }
- Ok(())
- }
-
- /// Paint a monochrome SVG into the scene for the next frame at the current stacking context.
- pub fn paint_svg(
- &mut self,
- bounds: Bounds<Pixels>,
- path: SharedString,
- color: Hsla,
- ) -> Result<()> {
- let scale_factor = self.scale_factor();
- let bounds = bounds.scale(scale_factor);
- // Render the SVG at twice the size to get a higher quality result.
- let params = RenderSvgParams {
- path,
- size: bounds
- .size
- .map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)),
- };
-
- let tile =
- self.window
- .sprite_atlas
- .get_or_insert_with(¶ms.clone().into(), &mut || {
- let bytes = self.svg_renderer.render(¶ms)?;
- Ok((params.size, Cow::Owned(bytes)))
- })?;
- let content_mask = self.content_mask().scale(scale_factor);
- let view_id = self.parent_view_id();
-
- let window = &mut *self.window;
- window.next_frame.scene.insert(
- &window.next_frame.z_index_stack,
- MonochromeSprite {
- view_id: view_id.into(),
- layer_id: 0,
- order: 0,
- bounds,
- content_mask,
- color,
- tile,
- },
- );
-
- Ok(())
- }
-
- /// Paint an image into the scene for the next frame at the current z-index.
- pub fn paint_image(
- &mut self,
- bounds: Bounds<Pixels>,
- corner_radii: Corners<Pixels>,
- data: Arc<ImageData>,
- grayscale: bool,
- ) -> Result<()> {
- let scale_factor = self.scale_factor();
- let bounds = bounds.scale(scale_factor);
- let params = RenderImageParams { image_id: data.id };
-
- let tile = self
- .window
- .sprite_atlas
- .get_or_insert_with(¶ms.clone().into(), &mut || {
- Ok((data.size(), Cow::Borrowed(data.as_bytes())))
- })?;
- let content_mask = self.content_mask().scale(scale_factor);
- let corner_radii = corner_radii.scale(scale_factor);
- let view_id = self.parent_view_id();
-
- let window = &mut *self.window;
- window.next_frame.scene.insert(
- &window.next_frame.z_index_stack,
- PolychromeSprite {
- view_id: view_id.into(),
- layer_id: 0,
- order: 0,
- bounds,
- content_mask,
- corner_radii,
- tile,
- grayscale,
- },
- );
- Ok(())
- }
-
- /// Paint a surface into the scene for the next frame at the current z-index.
- pub fn paint_surface(&mut self, bounds: Bounds<Pixels>, image_buffer: CVImageBuffer) {
- let scale_factor = self.scale_factor();
- let bounds = bounds.scale(scale_factor);
- let content_mask = self.content_mask().scale(scale_factor);
- let view_id = self.parent_view_id();
- let window = &mut *self.window;
- window.next_frame.scene.insert(
- &window.next_frame.z_index_stack,
- Surface {
- view_id: view_id.into(),
- layer_id: 0,
- order: 0,
- bounds,
- content_mask,
- image_buffer,
- },
- );
- }
-
- pub(crate) fn reuse_view(&mut self) {
- let view_id = self.parent_view_id();
- let grafted_view_ids = self
- .window
- .next_frame
- .dispatch_tree
- .reuse_view(view_id, &mut self.window.rendered_frame.dispatch_tree);
- for view_id in grafted_view_ids {
- assert!(self.window.next_frame.reused_views.insert(view_id));
-
- // Reuse the previous input handler requested during painting of the reused view.
- if self
- .window
- .rendered_frame
- .requested_input_handler
- .as_ref()
- .map_or(false, |requested| requested.view_id == view_id)
- {
- self.window.next_frame.requested_input_handler =
- self.window.rendered_frame.requested_input_handler.take();
- }
-
- // Reuse the tooltip previously requested during painting of the reused view.
- if self
- .window
- .rendered_frame
- .tooltip_request
- .as_ref()
- .map_or(false, |requested| requested.view_id == view_id)
- {
- self.window.next_frame.tooltip_request =
- self.window.rendered_frame.tooltip_request.take();
- }
-
- // Reuse the cursor styles previously requested during painting of the reused view.
- if let Some(style) = self.window.rendered_frame.cursor_styles.remove(&view_id) {
- self.window.next_frame.cursor_styles.insert(view_id, style);
- self.window.next_frame.requested_cursor_style = Some(style);
- }
- }
- }
-
/// Draw pixels to the display for this window based on the contents of its scene.
pub(crate) fn draw(&mut self) {
self.window.dirty = false;
@@ -1513,44 +868,55 @@ impl<'a> WindowContext<'a> {
if let Some(requested_handler) = self.window.rendered_frame.requested_input_handler.as_mut()
{
- requested_handler.handler = self.window.platform_window.take_input_handler();
+ let input_handler = self.window.platform_window.take_input_handler();
+ requested_handler.handler = input_handler;
}
let root_view = self.window.root_view.take().unwrap();
-
- self.with_z_index(0, |cx| {
- cx.with_key_dispatch(Some(KeyContext::default()), None, |_, cx| {
- for (action_type, action_listeners) in &cx.app.global_action_listeners {
- for action_listener in action_listeners.iter().cloned() {
- cx.window.next_frame.dispatch_tree.on_action(
- *action_type,
- Rc::new(move |action: &dyn Any, phase, cx: &mut WindowContext<'_>| {
- action_listener(action, phase, cx)
- }),
- )
+ self.with_element_context(|cx| {
+ cx.with_z_index(0, |cx| {
+ cx.with_key_dispatch(Some(KeyContext::default()), None, |_, cx| {
+ // We need to use cx.cx here so we can utilize borrow splitting
+ for (action_type, action_listeners) in &cx.cx.app.global_action_listeners {
+ for action_listener in action_listeners.iter().cloned() {
+ cx.cx.window.next_frame.dispatch_tree.on_action(
+ *action_type,
+ Rc::new(
+ move |action: &dyn Any, phase, cx: &mut WindowContext<'_>| {
+ action_listener(action, phase, cx)
+ },
+ ),
+ )
+ }
}
- }
- let available_space = cx.window.viewport_size.map(Into::into);
- root_view.draw(Point::default(), available_space, cx);
+ let available_space = cx.window.viewport_size.map(Into::into);
+ root_view.draw(Point::default(), available_space, cx);
+ })
})
});
if let Some(active_drag) = self.app.active_drag.take() {
- self.with_z_index(ACTIVE_DRAG_Z_INDEX, |cx| {
- let offset = cx.mouse_position() - active_drag.cursor_offset;
- let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent);
- active_drag.view.draw(offset, available_space, cx);
+ self.with_element_context(|cx| {
+ cx.with_z_index(ACTIVE_DRAG_Z_INDEX, |cx| {
+ let offset = cx.mouse_position() - active_drag.cursor_offset;
+ let available_space =
+ size(AvailableSpace::MinContent, AvailableSpace::MinContent);
+ active_drag.view.draw(offset, available_space, cx);
+ })
});
self.active_drag = Some(active_drag);
} else if let Some(tooltip_request) = self.window.next_frame.tooltip_request.take() {
- self.with_z_index(1, |cx| {
- let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent);
- tooltip_request.tooltip.view.draw(
- tooltip_request.tooltip.cursor_offset,
- available_space,
- cx,
- );
+ self.with_element_context(|cx| {
+ cx.with_z_index(1, |cx| {
+ let available_space =
+ size(AvailableSpace::MinContent, AvailableSpace::MinContent);
+ tooltip_request.tooltip.view.draw(
+ tooltip_request.tooltip.cursor_offset,
+ available_space,
+ cx,
+ );
+ })
});
self.window.next_frame.tooltip_request = Some(tooltip_request);
}
@@ -1741,7 +1107,9 @@ impl<'a> WindowContext<'a> {
// Capture phase, events bubble from back to front. Handlers for this phase are used for
// special purposes, such as detecting events outside of a given Bounds.
for (_, _, handler) in &mut handlers {
- handler(event, DispatchPhase::Capture, self);
+ self.with_element_context(|cx| {
+ handler(event, DispatchPhase::Capture, cx);
+ });
if !self.app.propagate_event {
break;
}
@@ -1750,7 +1118,9 @@ impl<'a> WindowContext<'a> {
// Bubble phase, where most normal handlers do their work.
if self.app.propagate_event {
for (_, _, handler) in handlers.iter_mut().rev() {
- handler(event, DispatchPhase::Bubble, self);
+ self.with_element_context(|cx| {
+ handler(event, DispatchPhase::Bubble, cx);
+ });
if !self.app.propagate_event {
break;
}
@@ -1866,7 +1236,9 @@ impl<'a> WindowContext<'a> {
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
for key_listener in node.key_listeners.clone() {
- key_listener(event, DispatchPhase::Capture, self);
+ self.with_element_context(|cx| {
+ key_listener(event, DispatchPhase::Capture, cx);
+ });
if !self.propagate_event {
return;
}
@@ -1878,7 +1250,9 @@ impl<'a> WindowContext<'a> {
// Handle low level key events
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
for key_listener in node.key_listeners.clone() {
- key_listener(event, DispatchPhase::Bubble, self);
+ self.with_element_context(|cx| {
+ key_listener(event, DispatchPhase::Bubble, cx);
+ });
if !self.propagate_event {
return;
}
@@ -1945,7 +1319,10 @@ impl<'a> WindowContext<'a> {
{
let any_action = action.as_any();
if action_type == any_action.type_id() {
- listener(any_action, DispatchPhase::Capture, self);
+ self.with_element_context(|cx| {
+ listener(any_action, DispatchPhase::Capture, cx);
+ });
+
if !self.propagate_event {
return;
}
@@ -1963,7 +1340,11 @@ impl<'a> WindowContext<'a> {
let any_action = action.as_any();
if action_type == any_action.type_id() {
self.propagate_event = false; // Actions stop propagation by default during the bubble phase
- listener(any_action, DispatchPhase::Bubble, self);
+
+ self.with_element_context(|cx| {
+ listener(any_action, DispatchPhase::Bubble, cx);
+ });
+
if !self.propagate_event {
return;
}
@@ -2087,186 +1468,6 @@ impl<'a> WindowContext<'a> {
}
}
- /// Invoke the given function with the given focus handle present on the key dispatch stack.
- /// If you want an element to participate in key dispatch, use this method to push its key context and focus handle into the stack during paint.
- pub fn with_key_dispatch<R>(
- &mut self,
- context: Option<KeyContext>,
- focus_handle: Option<FocusHandle>,
- f: impl FnOnce(Option<FocusHandle>, &mut Self) -> R,
- ) -> R {
- let window = &mut self.window;
- let focus_id = focus_handle.as_ref().map(|handle| handle.id);
- window
- .next_frame
- .dispatch_tree
- .push_node(context.clone(), focus_id, None);
-
- let result = f(focus_handle, self);
-
- self.window.next_frame.dispatch_tree.pop_node();
-
- result
- }
-
- /// Invoke the given function with the given view id present on the view stack.
- /// This is a fairly low-level method used to layout views.
- pub fn with_view_id<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
- let text_system = self.text_system().clone();
- text_system.with_view(view_id, || {
- if self.window.next_frame.view_stack.last() == Some(&view_id) {
- return f(self);
- } else {
- self.window.next_frame.view_stack.push(view_id);
- let result = f(self);
- self.window.next_frame.view_stack.pop();
- result
- }
- })
- }
-
- /// Invoke the given function with the given view id present on the view stack.
- /// This is a fairly low-level method used to paint views.
- pub fn paint_view<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
- let text_system = self.text_system().clone();
- text_system.with_view(view_id, || {
- if self.window.next_frame.view_stack.last() == Some(&view_id) {
- return f(self);
- } else {
- self.window.next_frame.view_stack.push(view_id);
- self.window
- .next_frame
- .dispatch_tree
- .push_node(None, None, Some(view_id));
- let result = f(self);
- self.window.next_frame.dispatch_tree.pop_node();
- self.window.next_frame.view_stack.pop();
- result
- }
- })
- }
-
- /// Updates or initializes state for an element with the given id that lives across multiple
- /// frames. If an element with this ID existed in the rendered frame, its state will be passed
- /// to the given closure. The state returned by the closure will be stored so it can be referenced
- /// when drawing the next frame.
- pub(crate) fn with_element_state<S, R>(
- &mut self,
- id: ElementId,
- f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
- ) -> R
- where
- S: 'static,
- {
- self.with_element_id(Some(id), |cx| {
- let global_id = cx.window().element_id_stack.clone();
-
- if let Some(any) = cx
- .window_mut()
- .next_frame
- .element_states
- .remove(&global_id)
- .or_else(|| {
- cx.window_mut()
- .rendered_frame
- .element_states
- .remove(&global_id)
- })
- {
- let ElementStateBox {
- inner,
- parent_view_id,
- #[cfg(debug_assertions)]
- type_name
- } = any;
- // Using the extra inner option to avoid needing to reallocate a new box.
- let mut state_box = inner
- .downcast::<Option<S>>()
- .map_err(|_| {
- #[cfg(debug_assertions)]
- {
- anyhow!(
- "invalid element state type for id, requested_type {:?}, actual type: {:?}",
- std::any::type_name::<S>(),
- type_name
- )
- }
-
- #[cfg(not(debug_assertions))]
- {
- anyhow!(
- "invalid element state type for id, requested_type {:?}",
- std::any::type_name::<S>(),
- )
- }
- })
- .unwrap();
-
- // Actual: Option<AnyElement> <- View
- // Requested: () <- AnyElement
- let state = state_box
- .take()
- .expect("element state is already on the stack");
- let (result, state) = f(Some(state), cx);
- state_box.replace(state);
- cx.window_mut()
- .next_frame
- .element_states
- .insert(global_id, ElementStateBox {
- inner: state_box,
- parent_view_id,
- #[cfg(debug_assertions)]
- type_name
- });
- result
- } else {
- let (result, state) = f(None, cx);
- let parent_view_id = cx.parent_view_id();
- cx.window_mut()
- .next_frame
- .element_states
- .insert(global_id,
- ElementStateBox {
- inner: Box::new(Some(state)),
- parent_view_id,
- #[cfg(debug_assertions)]
- type_name: std::any::type_name::<S>()
- }
-
- );
- result
- }
- })
- }
-
- fn parent_view_id(&self) -> EntityId {
- *self
- .window
- .next_frame
- .view_stack
- .last()
- .expect("a view should always be on the stack while drawing")
- }
-
- /// Sets an input handler, such as [`ElementInputHandler`][element_input_handler], which interfaces with the
- /// platform to receive textual input with proper integration with concerns such
- /// as IME interactions. This handler will be active for the upcoming frame until the following frame is
- /// rendered.
- ///
- /// [element_input_handler]: crate::ElementInputHandler
- pub fn handle_input(&mut self, focus_handle: &FocusHandle, input_handler: impl InputHandler) {
- if focus_handle.is_focused(self) {
- let view_id = self.parent_view_id();
- self.window.next_frame.requested_input_handler = Some(RequestedInputHandler {
- view_id,
- handler: Some(PlatformInputHandler::new(
- self.to_async(),
- Box::new(input_handler),
- )),
- })
- }
- }
-
/// Register a callback that can interrupt the closing of the current window based the returned boolean.
/// If the callback returns false, the window won't be closed.
pub fn on_window_should_close(&mut self, f: impl Fn(&mut WindowContext) -> bool + 'static) {
@@ -0,0 +1,1129 @@
+use std::{
+ any::{Any, TypeId},
+ borrow::{Borrow, BorrowMut, Cow},
+ mem,
+ rc::Rc,
+ sync::Arc,
+};
+
+use anyhow::Result;
+use collections::{FxHashMap, FxHashSet};
+use derive_more::{Deref, DerefMut};
+use media::core_video::CVImageBuffer;
+use smallvec::SmallVec;
+use util::post_inc;
+
+use crate::{
+ prelude::*, size, AnyTooltip, AppContext, AvailableSpace, Bounds, BoxShadow, ContentMask,
+ Corners, CursorStyle, DevicePixels, DispatchPhase, DispatchTree, ElementId, ElementStateBox,
+ EntityId, FocusHandle, FocusId, FontId, GlobalElementId, GlyphId, Hsla, ImageData,
+ InputHandler, IsZero, KeyContext, KeyEvent, LayoutId, MonochromeSprite, MouseEvent, PaintQuad,
+ Path, Pixels, PlatformInputHandler, Point, PolychromeSprite, Quad, RenderGlyphParams,
+ RenderImageParams, RenderSvgParams, Scene, Shadow, SharedString, Size, StackingOrder, Style,
+ Surface, TextStyleRefinement, Underline, UnderlineStyle, Window, WindowContext,
+ SUBPIXEL_VARIANTS,
+};
+
+type AnyMouseListener = Box<dyn FnMut(&dyn Any, DispatchPhase, &mut ElementContext) + 'static>;
+
+pub(crate) struct RequestedInputHandler {
+ pub(crate) view_id: EntityId,
+ pub(crate) handler: Option<PlatformInputHandler>,
+}
+
+pub(crate) struct TooltipRequest {
+ pub(crate) view_id: EntityId,
+ pub(crate) tooltip: AnyTooltip,
+}
+
+pub(crate) struct Frame {
+ pub(crate) focus: Option<FocusId>,
+ pub(crate) window_active: bool,
+ pub(crate) element_states: FxHashMap<GlobalElementId, ElementStateBox>,
+ pub(crate) mouse_listeners: FxHashMap<TypeId, Vec<(StackingOrder, EntityId, AnyMouseListener)>>,
+ pub(crate) dispatch_tree: DispatchTree,
+ pub(crate) scene: Scene,
+ pub(crate) depth_map: Vec<(StackingOrder, EntityId, Bounds<Pixels>)>,
+ pub(crate) z_index_stack: StackingOrder,
+ pub(crate) next_stacking_order_id: u32,
+ pub(crate) next_root_z_index: u8,
+ pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
+ pub(crate) element_offset_stack: Vec<Point<Pixels>>,
+ pub(crate) requested_input_handler: Option<RequestedInputHandler>,
+ pub(crate) tooltip_request: Option<TooltipRequest>,
+ pub(crate) cursor_styles: FxHashMap<EntityId, CursorStyle>,
+ pub(crate) requested_cursor_style: Option<CursorStyle>,
+ pub(crate) view_stack: Vec<EntityId>,
+ pub(crate) reused_views: FxHashSet<EntityId>,
+
+ #[cfg(any(test, feature = "test-support"))]
+ pub(crate) debug_bounds: collections::FxHashMap<String, Bounds<Pixels>>,
+}
+
+impl Frame {
+ pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
+ Frame {
+ focus: None,
+ window_active: false,
+ element_states: FxHashMap::default(),
+ mouse_listeners: FxHashMap::default(),
+ dispatch_tree,
+ scene: Scene::default(),
+ depth_map: Vec::new(),
+ z_index_stack: StackingOrder::default(),
+ next_stacking_order_id: 0,
+ next_root_z_index: 0,
+ content_mask_stack: Vec::new(),
+ element_offset_stack: Vec::new(),
+ requested_input_handler: None,
+ tooltip_request: None,
+ cursor_styles: FxHashMap::default(),
+ requested_cursor_style: None,
+ view_stack: Vec::new(),
+ reused_views: FxHashSet::default(),
+
+ #[cfg(any(test, feature = "test-support"))]
+ debug_bounds: FxHashMap::default(),
+ }
+ }
+
+ pub(crate) fn clear(&mut self) {
+ self.element_states.clear();
+ self.mouse_listeners.values_mut().for_each(Vec::clear);
+ self.dispatch_tree.clear();
+ self.depth_map.clear();
+ self.next_stacking_order_id = 0;
+ self.next_root_z_index = 0;
+ self.reused_views.clear();
+ self.scene.clear();
+ self.requested_input_handler.take();
+ self.tooltip_request.take();
+ self.cursor_styles.clear();
+ self.requested_cursor_style.take();
+ debug_assert_eq!(self.view_stack.len(), 0);
+ }
+
+ pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
+ self.focus
+ .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
+ .unwrap_or_default()
+ }
+
+ pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
+ // Reuse mouse listeners that didn't change since the last frame.
+ for (type_id, listeners) in &mut prev_frame.mouse_listeners {
+ let next_listeners = self.mouse_listeners.entry(*type_id).or_default();
+ for (order, view_id, listener) in listeners.drain(..) {
+ if self.reused_views.contains(&view_id) {
+ next_listeners.push((order, view_id, listener));
+ }
+ }
+ }
+
+ // Reuse entries in the depth map that didn't change since the last frame.
+ for (order, view_id, bounds) in prev_frame.depth_map.drain(..) {
+ if self.reused_views.contains(&view_id) {
+ match self
+ .depth_map
+ .binary_search_by(|(level, _, _)| order.cmp(level))
+ {
+ Ok(i) | Err(i) => self.depth_map.insert(i, (order, view_id, bounds)),
+ }
+ }
+ }
+
+ // Retain element states for views that didn't change since the last frame.
+ for (element_id, state) in prev_frame.element_states.drain() {
+ if self.reused_views.contains(&state.parent_view_id) {
+ self.element_states.entry(element_id).or_insert(state);
+ }
+ }
+
+ // Reuse geometry that didn't change since the last frame.
+ self.scene
+ .reuse_views(&self.reused_views, &mut prev_frame.scene);
+ self.scene.finish();
+ }
+}
+
+/// This context is used for assisting in the implementation of the element trait
+#[derive(Deref, DerefMut)]
+pub struct ElementContext<'a> {
+ pub(crate) cx: WindowContext<'a>,
+}
+
+impl<'a> WindowContext<'a> {
+ pub fn with_element_context<R>(&mut self, f: impl FnOnce(&mut ElementContext) -> R) -> R {
+ f(&mut ElementContext {
+ cx: WindowContext::new(self.app, self.window),
+ })
+ }
+}
+
+impl<'a> Borrow<AppContext> for ElementContext<'a> {
+ fn borrow(&self) -> &AppContext {
+ self.cx.app
+ }
+}
+
+impl<'a> BorrowMut<AppContext> for ElementContext<'a> {
+ fn borrow_mut(&mut self) -> &mut AppContext {
+ self.cx.borrow_mut()
+ }
+}
+
+impl<'a> Borrow<WindowContext<'a>> for ElementContext<'a> {
+ fn borrow(&self) -> &WindowContext<'a> {
+ &self.cx
+ }
+}
+
+impl<'a> BorrowMut<WindowContext<'a>> for ElementContext<'a> {
+ fn borrow_mut(&mut self) -> &mut WindowContext<'a> {
+ &mut self.cx
+ }
+}
+
+impl<'a> Borrow<Window> for ElementContext<'a> {
+ fn borrow(&self) -> &Window {
+ self.cx.window
+ }
+}
+
+impl<'a> BorrowMut<Window> for ElementContext<'a> {
+ fn borrow_mut(&mut self) -> &mut Window {
+ self.cx.borrow_mut()
+ }
+}
+
+impl<'a> Context for ElementContext<'a> {
+ type Result<T> = <WindowContext<'a> as Context>::Result<T>;
+
+ fn new_model<T: 'static>(
+ &mut self,
+ build_model: impl FnOnce(&mut crate::ModelContext<'_, T>) -> T,
+ ) -> Self::Result<crate::Model<T>> {
+ self.cx.new_model(build_model)
+ }
+
+ fn update_model<T, R>(
+ &mut self,
+ handle: &crate::Model<T>,
+ update: impl FnOnce(&mut T, &mut crate::ModelContext<'_, T>) -> R,
+ ) -> Self::Result<R>
+ where
+ T: 'static,
+ {
+ self.cx.update_model(handle, update)
+ }
+
+ fn read_model<T, R>(
+ &self,
+ handle: &crate::Model<T>,
+ read: impl FnOnce(&T, &AppContext) -> R,
+ ) -> Self::Result<R>
+ where
+ T: 'static,
+ {
+ self.cx.read_model(handle, read)
+ }
+
+ fn update_window<T, F>(&mut self, window: crate::AnyWindowHandle, f: F) -> Result<T>
+ where
+ F: FnOnce(crate::AnyView, &mut WindowContext<'_>) -> T,
+ {
+ self.cx.update_window(window, f)
+ }
+
+ fn read_window<T, R>(
+ &self,
+ window: &crate::WindowHandle<T>,
+ read: impl FnOnce(crate::View<T>, &AppContext) -> R,
+ ) -> Result<R>
+ where
+ T: 'static,
+ {
+ self.cx.read_window(window, read)
+ }
+}
+
+impl<'a> VisualContext for ElementContext<'a> {
+ fn new_view<V>(
+ &mut self,
+ build_view: impl FnOnce(&mut crate::ViewContext<'_, V>) -> V,
+ ) -> Self::Result<crate::View<V>>
+ where
+ V: 'static + Render,
+ {
+ self.cx.new_view(build_view)
+ }
+
+ fn update_view<V: 'static, R>(
+ &mut self,
+ view: &crate::View<V>,
+ update: impl FnOnce(&mut V, &mut crate::ViewContext<'_, V>) -> R,
+ ) -> Self::Result<R> {
+ self.cx.update_view(view, update)
+ }
+
+ fn replace_root_view<V>(
+ &mut self,
+ build_view: impl FnOnce(&mut crate::ViewContext<'_, V>) -> V,
+ ) -> Self::Result<crate::View<V>>
+ where
+ V: 'static + Render,
+ {
+ self.cx.replace_root_view(build_view)
+ }
+
+ fn focus_view<V>(&mut self, view: &crate::View<V>) -> Self::Result<()>
+ where
+ V: crate::FocusableView,
+ {
+ self.cx.focus_view(view)
+ }
+
+ fn dismiss_view<V>(&mut self, view: &crate::View<V>) -> Self::Result<()>
+ where
+ V: crate::ManagedView,
+ {
+ self.cx.dismiss_view(view)
+ }
+}
+
+impl<'a> ElementContext<'a> {
+ pub(crate) fn reuse_view(&mut self) {
+ let view_id = self.parent_view_id();
+ let grafted_view_ids = self
+ .cx
+ .window
+ .next_frame
+ .dispatch_tree
+ .reuse_view(view_id, &mut self.cx.window.rendered_frame.dispatch_tree);
+ for view_id in grafted_view_ids {
+ assert!(self.window.next_frame.reused_views.insert(view_id));
+
+ // Reuse the previous input handler requested during painting of the reused view.
+ if self
+ .window
+ .rendered_frame
+ .requested_input_handler
+ .as_ref()
+ .map_or(false, |requested| requested.view_id == view_id)
+ {
+ self.window.next_frame.requested_input_handler =
+ self.window.rendered_frame.requested_input_handler.take();
+ }
+
+ // Reuse the tooltip previously requested during painting of the reused view.
+ if self
+ .window
+ .rendered_frame
+ .tooltip_request
+ .as_ref()
+ .map_or(false, |requested| requested.view_id == view_id)
+ {
+ self.window.next_frame.tooltip_request =
+ self.window.rendered_frame.tooltip_request.take();
+ }
+
+ // Reuse the cursor styles previously requested during painting of the reused view.
+ if let Some(style) = self.window.rendered_frame.cursor_styles.remove(&view_id) {
+ self.window.next_frame.cursor_styles.insert(view_id, style);
+ self.window.next_frame.requested_cursor_style = Some(style);
+ }
+ }
+ }
+
+ pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
+ where
+ F: FnOnce(&mut Self) -> R,
+ {
+ if let Some(style) = style {
+ self.push_text_style(style);
+ let result = f(self);
+ self.pop_text_style();
+ result
+ } else {
+ f(self)
+ }
+ }
+
+ /// Updates the cursor style at the platform level.
+ pub fn set_cursor_style(&mut self, style: CursorStyle) {
+ let view_id = self.parent_view_id();
+ self.window.next_frame.cursor_styles.insert(view_id, style);
+ self.window.next_frame.requested_cursor_style = Some(style);
+ }
+
+ /// Sets a tooltip to be rendered for the upcoming frame
+ pub fn set_tooltip(&mut self, tooltip: AnyTooltip) {
+ let view_id = self.parent_view_id();
+ self.window.next_frame.tooltip_request = Some(TooltipRequest { view_id, tooltip });
+ }
+
+ /// Pushes the given element id onto the global stack and invokes the given closure
+ /// with a `GlobalElementId`, which disambiguates the given id in the context of its ancestor
+ /// ids. Because elements are discarded and recreated on each frame, the `GlobalElementId` is
+ /// used to associate state with identified elements across separate frames.
+ pub fn with_element_id<R>(
+ &mut self,
+ id: Option<impl Into<ElementId>>,
+ f: impl FnOnce(&mut Self) -> R,
+ ) -> R {
+ if let Some(id) = id.map(Into::into) {
+ let window = self.window_mut();
+ window.element_id_stack.push(id);
+ let result = f(self);
+ let window: &mut Window = self.borrow_mut();
+ window.element_id_stack.pop();
+ result
+ } else {
+ f(self)
+ }
+ }
+
+ /// Invoke the given function with the given content mask after intersecting it
+ /// with the current mask.
+ pub fn with_content_mask<R>(
+ &mut self,
+ mask: Option<ContentMask<Pixels>>,
+ f: impl FnOnce(&mut Self) -> R,
+ ) -> R {
+ if let Some(mask) = mask {
+ let mask = mask.intersect(&self.content_mask());
+ self.window_mut().next_frame.content_mask_stack.push(mask);
+ let result = f(self);
+ self.window_mut().next_frame.content_mask_stack.pop();
+ result
+ } else {
+ f(self)
+ }
+ }
+
+ /// Invoke the given function with the content mask reset to that
+ /// of the window.
+ pub fn break_content_mask<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
+ let mask = ContentMask {
+ bounds: Bounds {
+ origin: Point::default(),
+ size: self.window().viewport_size,
+ },
+ };
+ let new_stacking_order_id =
+ post_inc(&mut self.window_mut().next_frame.next_stacking_order_id);
+ let new_root_z_index = post_inc(&mut self.window_mut().next_frame.next_root_z_index);
+ let old_stacking_order = mem::take(&mut self.window_mut().next_frame.z_index_stack);
+ self.window_mut().next_frame.z_index_stack.id = new_stacking_order_id;
+ self.window_mut()
+ .next_frame
+ .z_index_stack
+ .push(new_root_z_index);
+ self.window_mut().next_frame.content_mask_stack.push(mask);
+ let result = f(self);
+ self.window_mut().next_frame.content_mask_stack.pop();
+ self.window_mut().next_frame.z_index_stack = old_stacking_order;
+ result
+ }
+
+ /// Called during painting to invoke the given closure in a new stacking context. The given
+ /// z-index is interpreted relative to the previous call to `stack`.
+ pub fn with_z_index<R>(&mut self, z_index: u8, f: impl FnOnce(&mut Self) -> R) -> R {
+ let new_stacking_order_id =
+ post_inc(&mut self.window_mut().next_frame.next_stacking_order_id);
+ let old_stacking_order_id = mem::replace(
+ &mut self.window_mut().next_frame.z_index_stack.id,
+ new_stacking_order_id,
+ );
+ self.window_mut().next_frame.z_index_stack.id = new_stacking_order_id;
+ self.window_mut().next_frame.z_index_stack.push(z_index);
+ let result = f(self);
+ self.window_mut().next_frame.z_index_stack.id = old_stacking_order_id;
+ self.window_mut().next_frame.z_index_stack.pop();
+ result
+ }
+
+ /// Updates the global element offset relative to the current offset. This is used to implement
+ /// scrolling.
+ pub fn with_element_offset<R>(
+ &mut self,
+ offset: Point<Pixels>,
+ f: impl FnOnce(&mut Self) -> R,
+ ) -> R {
+ if offset.is_zero() {
+ return f(self);
+ };
+
+ let abs_offset = self.element_offset() + offset;
+ self.with_absolute_element_offset(abs_offset, f)
+ }
+
+ /// Updates the global element offset based on the given offset. This is used to implement
+ /// drag handles and other manual painting of elements.
+ pub fn with_absolute_element_offset<R>(
+ &mut self,
+ offset: Point<Pixels>,
+ f: impl FnOnce(&mut Self) -> R,
+ ) -> R {
+ self.window_mut()
+ .next_frame
+ .element_offset_stack
+ .push(offset);
+ let result = f(self);
+ self.window_mut().next_frame.element_offset_stack.pop();
+ result
+ }
+
+ /// Obtain the current element offset.
+ pub fn element_offset(&self) -> Point<Pixels> {
+ self.window()
+ .next_frame
+ .element_offset_stack
+ .last()
+ .copied()
+ .unwrap_or_default()
+ }
+
+ /// Obtain the current content mask.
+ pub fn content_mask(&self) -> ContentMask<Pixels> {
+ self.window()
+ .next_frame
+ .content_mask_stack
+ .last()
+ .cloned()
+ .unwrap_or_else(|| ContentMask {
+ bounds: Bounds {
+ origin: Point::default(),
+ size: self.window().viewport_size,
+ },
+ })
+ }
+
+ /// The size of an em for the base font of the application. Adjusting this value allows the
+ /// UI to scale, just like zooming a web page.
+ pub fn rem_size(&self) -> Pixels {
+ self.window().rem_size
+ }
+
+ /// Updates or initializes state for an element with the given id that lives across multiple
+ /// frames. If an element with this ID existed in the rendered frame, its state will be passed
+ /// to the given closure. The state returned by the closure will be stored so it can be referenced
+ /// when drawing the next frame.
+ pub fn with_element_state<S, R>(
+ &mut self,
+ id: ElementId,
+ f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
+ ) -> R
+ where
+ S: 'static,
+ {
+ self.with_element_id(Some(id), |cx| {
+ let global_id = cx.window().element_id_stack.clone();
+
+ if let Some(any) = cx
+ .window_mut()
+ .next_frame
+ .element_states
+ .remove(&global_id)
+ .or_else(|| {
+ cx.window_mut()
+ .rendered_frame
+ .element_states
+ .remove(&global_id)
+ })
+ {
+ let ElementStateBox {
+ inner,
+ parent_view_id,
+ #[cfg(debug_assertions)]
+ type_name
+ } = any;
+ // Using the extra inner option to avoid needing to reallocate a new box.
+ let mut state_box = inner
+ .downcast::<Option<S>>()
+ .map_err(|_| {
+ #[cfg(debug_assertions)]
+ {
+ anyhow::anyhow!(
+ "invalid element state type for id, requested_type {:?}, actual type: {:?}",
+ std::any::type_name::<S>(),
+ type_name
+ )
+ }
+
+ #[cfg(not(debug_assertions))]
+ {
+ anyhow::anyhow!(
+ "invalid element state type for id, requested_type {:?}",
+ std::any::type_name::<S>(),
+ )
+ }
+ })
+ .unwrap();
+
+ // Actual: Option<AnyElement> <- View
+ // Requested: () <- AnyElement
+ let state = state_box
+ .take()
+ .expect("element state is already on the stack");
+ let (result, state) = f(Some(state), cx);
+ state_box.replace(state);
+ cx.window_mut()
+ .next_frame
+ .element_states
+ .insert(global_id, ElementStateBox {
+ inner: state_box,
+ parent_view_id,
+ #[cfg(debug_assertions)]
+ type_name
+ });
+ result
+ } else {
+ let (result, state) = f(None, cx);
+ let parent_view_id = cx.parent_view_id();
+ cx.window_mut()
+ .next_frame
+ .element_states
+ .insert(global_id,
+ ElementStateBox {
+ inner: Box::new(Some(state)),
+ parent_view_id,
+ #[cfg(debug_assertions)]
+ type_name: std::any::type_name::<S>()
+ }
+
+ );
+ result
+ }
+ })
+ }
+ /// Paint one or more drop shadows into the scene for the next frame at the current z-index.
+ pub fn paint_shadows(
+ &mut self,
+ bounds: Bounds<Pixels>,
+ corner_radii: Corners<Pixels>,
+ shadows: &[BoxShadow],
+ ) {
+ let scale_factor = self.scale_factor();
+ let content_mask = self.content_mask();
+ let view_id = self.parent_view_id();
+ let window = &mut *self.window;
+ for shadow in shadows {
+ let mut shadow_bounds = bounds;
+ shadow_bounds.origin += shadow.offset;
+ shadow_bounds.dilate(shadow.spread_radius);
+ window.next_frame.scene.insert(
+ &window.next_frame.z_index_stack,
+ Shadow {
+ view_id: view_id.into(),
+ layer_id: 0,
+ order: 0,
+ bounds: shadow_bounds.scale(scale_factor),
+ content_mask: content_mask.scale(scale_factor),
+ corner_radii: corner_radii.scale(scale_factor),
+ color: shadow.color,
+ blur_radius: shadow.blur_radius.scale(scale_factor),
+ },
+ );
+ }
+ }
+
+ /// Paint one or more quads into the scene for the next frame at the current stacking context.
+ /// Quads are colored rectangular regions with an optional background, border, and corner radius.
+ /// see [`fill`], [`outline`], and [`quad`] to construct this type.
+ pub fn paint_quad(&mut self, quad: PaintQuad) {
+ let scale_factor = self.scale_factor();
+ let content_mask = self.content_mask();
+ let view_id = self.parent_view_id();
+
+ let window = &mut *self.window;
+ window.next_frame.scene.insert(
+ &window.next_frame.z_index_stack,
+ Quad {
+ view_id: view_id.into(),
+ layer_id: 0,
+ order: 0,
+ bounds: quad.bounds.scale(scale_factor),
+ content_mask: content_mask.scale(scale_factor),
+ background: quad.background,
+ border_color: quad.border_color,
+ corner_radii: quad.corner_radii.scale(scale_factor),
+ border_widths: quad.border_widths.scale(scale_factor),
+ },
+ );
+ }
+
+ /// Paint the given `Path` into the scene for the next frame at the current z-index.
+ pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Hsla>) {
+ let scale_factor = self.scale_factor();
+ let content_mask = self.content_mask();
+ let view_id = self.parent_view_id();
+
+ path.content_mask = content_mask;
+ path.color = color.into();
+ path.view_id = view_id.into();
+ let window = &mut *self.window;
+ window
+ .next_frame
+ .scene
+ .insert(&window.next_frame.z_index_stack, path.scale(scale_factor));
+ }
+
+ /// Paint an underline into the scene for the next frame at the current z-index.
+ pub fn paint_underline(
+ &mut self,
+ origin: Point<Pixels>,
+ width: Pixels,
+ style: &UnderlineStyle,
+ ) {
+ let scale_factor = self.scale_factor();
+ let height = if style.wavy {
+ style.thickness * 3.
+ } else {
+ style.thickness
+ };
+ let bounds = Bounds {
+ origin,
+ size: size(width, height),
+ };
+ let content_mask = self.content_mask();
+ let view_id = self.parent_view_id();
+
+ let window = &mut *self.window;
+ window.next_frame.scene.insert(
+ &window.next_frame.z_index_stack,
+ Underline {
+ view_id: view_id.into(),
+ layer_id: 0,
+ order: 0,
+ bounds: bounds.scale(scale_factor),
+ content_mask: content_mask.scale(scale_factor),
+ thickness: style.thickness.scale(scale_factor),
+ color: style.color.unwrap_or_default(),
+ wavy: style.wavy,
+ },
+ );
+ }
+
+ /// Paint a monochrome (non-emoji) glyph into the scene for the next frame at the current z-index.
+ /// The y component of the origin is the baseline of the glyph.
+ pub fn paint_glyph(
+ &mut self,
+ origin: Point<Pixels>,
+ font_id: FontId,
+ glyph_id: GlyphId,
+ font_size: Pixels,
+ color: Hsla,
+ ) -> Result<()> {
+ let scale_factor = self.scale_factor();
+ let glyph_origin = origin.scale(scale_factor);
+ let subpixel_variant = Point {
+ x: (glyph_origin.x.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
+ y: (glyph_origin.y.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
+ };
+ let params = RenderGlyphParams {
+ font_id,
+ glyph_id,
+ font_size,
+ subpixel_variant,
+ scale_factor,
+ is_emoji: false,
+ };
+
+ let raster_bounds = self.text_system().raster_bounds(¶ms)?;
+ if !raster_bounds.is_zero() {
+ let tile =
+ self.window
+ .sprite_atlas
+ .get_or_insert_with(¶ms.clone().into(), &mut || {
+ let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
+ Ok((size, Cow::Owned(bytes)))
+ })?;
+ let bounds = Bounds {
+ origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
+ size: tile.bounds.size.map(Into::into),
+ };
+ let content_mask = self.content_mask().scale(scale_factor);
+ let view_id = self.parent_view_id();
+ let window = &mut *self.window;
+ window.next_frame.scene.insert(
+ &window.next_frame.z_index_stack,
+ MonochromeSprite {
+ view_id: view_id.into(),
+ layer_id: 0,
+ order: 0,
+ bounds,
+ content_mask,
+ color,
+ tile,
+ },
+ );
+ }
+ Ok(())
+ }
+
+ /// Paint an emoji glyph into the scene for the next frame at the current z-index.
+ /// The y component of the origin is the baseline of the glyph.
+ pub fn paint_emoji(
+ &mut self,
+ origin: Point<Pixels>,
+ font_id: FontId,
+ glyph_id: GlyphId,
+ font_size: Pixels,
+ ) -> Result<()> {
+ let scale_factor = self.scale_factor();
+ let glyph_origin = origin.scale(scale_factor);
+ let params = RenderGlyphParams {
+ font_id,
+ glyph_id,
+ font_size,
+ // We don't render emojis with subpixel variants.
+ subpixel_variant: Default::default(),
+ scale_factor,
+ is_emoji: true,
+ };
+
+ let raster_bounds = self.text_system().raster_bounds(¶ms)?;
+ if !raster_bounds.is_zero() {
+ let tile =
+ self.window
+ .sprite_atlas
+ .get_or_insert_with(¶ms.clone().into(), &mut || {
+ let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
+ Ok((size, Cow::Owned(bytes)))
+ })?;
+ let bounds = Bounds {
+ origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
+ size: tile.bounds.size.map(Into::into),
+ };
+ let content_mask = self.content_mask().scale(scale_factor);
+ let view_id = self.parent_view_id();
+ let window = &mut *self.window;
+
+ window.next_frame.scene.insert(
+ &window.next_frame.z_index_stack,
+ PolychromeSprite {
+ view_id: view_id.into(),
+ layer_id: 0,
+ order: 0,
+ bounds,
+ corner_radii: Default::default(),
+ content_mask,
+ tile,
+ grayscale: false,
+ },
+ );
+ }
+ Ok(())
+ }
+
+ /// Paint a monochrome SVG into the scene for the next frame at the current stacking context.
+ pub fn paint_svg(
+ &mut self,
+ bounds: Bounds<Pixels>,
+ path: SharedString,
+ color: Hsla,
+ ) -> Result<()> {
+ let scale_factor = self.scale_factor();
+ let bounds = bounds.scale(scale_factor);
+ // Render the SVG at twice the size to get a higher quality result.
+ let params = RenderSvgParams {
+ path,
+ size: bounds
+ .size
+ .map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)),
+ };
+
+ let tile =
+ self.window
+ .sprite_atlas
+ .get_or_insert_with(¶ms.clone().into(), &mut || {
+ let bytes = self.svg_renderer.render(¶ms)?;
+ Ok((params.size, Cow::Owned(bytes)))
+ })?;
+ let content_mask = self.content_mask().scale(scale_factor);
+ let view_id = self.parent_view_id();
+
+ let window = &mut *self.window;
+ window.next_frame.scene.insert(
+ &window.next_frame.z_index_stack,
+ MonochromeSprite {
+ view_id: view_id.into(),
+ layer_id: 0,
+ order: 0,
+ bounds,
+ content_mask,
+ color,
+ tile,
+ },
+ );
+
+ Ok(())
+ }
+
+ /// Paint an image into the scene for the next frame at the current z-index.
+ pub fn paint_image(
+ &mut self,
+ bounds: Bounds<Pixels>,
+ corner_radii: Corners<Pixels>,
+ data: Arc<ImageData>,
+ grayscale: bool,
+ ) -> Result<()> {
+ let scale_factor = self.scale_factor();
+ let bounds = bounds.scale(scale_factor);
+ let params = RenderImageParams { image_id: data.id };
+
+ let tile = self
+ .window
+ .sprite_atlas
+ .get_or_insert_with(¶ms.clone().into(), &mut || {
+ Ok((data.size(), Cow::Borrowed(data.as_bytes())))
+ })?;
+ let content_mask = self.content_mask().scale(scale_factor);
+ let corner_radii = corner_radii.scale(scale_factor);
+ let view_id = self.parent_view_id();
+
+ let window = &mut *self.window;
+ window.next_frame.scene.insert(
+ &window.next_frame.z_index_stack,
+ PolychromeSprite {
+ view_id: view_id.into(),
+ layer_id: 0,
+ order: 0,
+ bounds,
+ content_mask,
+ corner_radii,
+ tile,
+ grayscale,
+ },
+ );
+ Ok(())
+ }
+
+ /// Paint a surface into the scene for the next frame at the current z-index.
+ pub fn paint_surface(&mut self, bounds: Bounds<Pixels>, image_buffer: CVImageBuffer) {
+ let scale_factor = self.scale_factor();
+ let bounds = bounds.scale(scale_factor);
+ let content_mask = self.content_mask().scale(scale_factor);
+ let view_id = self.parent_view_id();
+ let window = &mut *self.window;
+ window.next_frame.scene.insert(
+ &window.next_frame.z_index_stack,
+ Surface {
+ view_id: view_id.into(),
+ layer_id: 0,
+ order: 0,
+ bounds,
+ content_mask,
+ image_buffer,
+ },
+ );
+ }
+
+ #[must_use]
+ /// Add a node to the layout tree for the current frame. Takes the `Style` of the element for which
+ /// layout is being requested, along with the layout ids of any children. This method is called during
+ /// calls to the `Element::layout` trait method and enables any element to participate in layout.
+ pub fn request_layout(
+ &mut self,
+ style: &Style,
+ children: impl IntoIterator<Item = LayoutId>,
+ ) -> LayoutId {
+ self.app.layout_id_buffer.clear();
+ self.app.layout_id_buffer.extend(children);
+ let rem_size = self.rem_size();
+
+ self.cx
+ .window
+ .layout_engine
+ .as_mut()
+ .unwrap()
+ .request_layout(style, rem_size, &self.cx.app.layout_id_buffer)
+ }
+
+ /// Add a node to the layout tree for the current frame. Instead of taking a `Style` and children,
+ /// this variant takes a function that is invoked during layout so you can use arbitrary logic to
+ /// determine the element's size. One place this is used internally is when measuring text.
+ ///
+ /// The given closure is invoked at layout time with the known dimensions and available space and
+ /// returns a `Size`.
+ pub fn request_measured_layout<
+ F: FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut WindowContext) -> Size<Pixels>
+ + 'static,
+ >(
+ &mut self,
+ style: Style,
+ measure: F,
+ ) -> LayoutId {
+ let rem_size = self.rem_size();
+ self.window
+ .layout_engine
+ .as_mut()
+ .unwrap()
+ .request_measured_layout(style, rem_size, measure)
+ }
+
+ /// Compute the layout for the given id within the given available space.
+ /// This method is called for its side effect, typically by the framework prior to painting.
+ /// After calling it, you can request the bounds of the given layout node id or any descendant.
+ pub fn compute_layout(&mut self, layout_id: LayoutId, available_space: Size<AvailableSpace>) {
+ let mut layout_engine = self.window.layout_engine.take().unwrap();
+ layout_engine.compute_layout(layout_id, available_space, self);
+ self.window.layout_engine = Some(layout_engine);
+ }
+
+ /// Obtain the bounds computed for the given LayoutId relative to the window. This method should not
+ /// be invoked until the paint phase begins, and will usually be invoked by GPUI itself automatically
+ /// in order to pass your element its `Bounds` automatically.
+ pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
+ let mut bounds = self
+ .window
+ .layout_engine
+ .as_mut()
+ .unwrap()
+ .layout_bounds(layout_id)
+ .map(Into::into);
+ bounds.origin += self.element_offset();
+ bounds
+ }
+
+ pub(crate) fn layout_style(&self, layout_id: LayoutId) -> Option<&Style> {
+ self.window
+ .layout_engine
+ .as_ref()
+ .unwrap()
+ .requested_style(layout_id)
+ }
+
+ /// Called during painting to track which z-index is on top at each pixel position
+ pub fn add_opaque_layer(&mut self, bounds: Bounds<Pixels>) {
+ let stacking_order = self.window.next_frame.z_index_stack.clone();
+ let view_id = self.parent_view_id();
+ let depth_map = &mut self.window.next_frame.depth_map;
+ match depth_map.binary_search_by(|(level, _, _)| stacking_order.cmp(level)) {
+ Ok(i) | Err(i) => depth_map.insert(i, (stacking_order, view_id, bounds)),
+ }
+ }
+
+ /// Invoke the given function with the given focus handle present on the key dispatch stack.
+ /// If you want an element to participate in key dispatch, use this method to push its key context and focus handle into the stack during paint.
+ pub fn with_key_dispatch<R>(
+ &mut self,
+ context: Option<KeyContext>,
+ focus_handle: Option<FocusHandle>,
+ f: impl FnOnce(Option<FocusHandle>, &mut Self) -> R,
+ ) -> R {
+ let window = &mut self.window;
+ let focus_id = focus_handle.as_ref().map(|handle| handle.id);
+ window
+ .next_frame
+ .dispatch_tree
+ .push_node(context.clone(), focus_id, None);
+
+ let result = f(focus_handle, self);
+
+ self.window.next_frame.dispatch_tree.pop_node();
+
+ result
+ }
+
+ /// Invoke the given function with the given view id present on the view stack.
+ /// This is a fairly low-level method used to layout views.
+ pub fn with_view_id<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
+ let text_system = self.text_system().clone();
+ text_system.with_view(view_id, || {
+ if self.window.next_frame.view_stack.last() == Some(&view_id) {
+ return f(self);
+ } else {
+ self.window.next_frame.view_stack.push(view_id);
+ let result = f(self);
+ self.window.next_frame.view_stack.pop();
+ result
+ }
+ })
+ }
+
+ /// Invoke the given function with the given view id present on the view stack.
+ /// This is a fairly low-level method used to paint views.
+ pub fn paint_view<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
+ let text_system = self.text_system().clone();
+ text_system.with_view(view_id, || {
+ if self.window.next_frame.view_stack.last() == Some(&view_id) {
+ return f(self);
+ } else {
+ self.window.next_frame.view_stack.push(view_id);
+ self.window
+ .next_frame
+ .dispatch_tree
+ .push_node(None, None, Some(view_id));
+ let result = f(self);
+ self.window.next_frame.dispatch_tree.pop_node();
+ self.window.next_frame.view_stack.pop();
+ result
+ }
+ })
+ }
+
+ /// Sets an input handler, such as [`ElementInputHandler`][element_input_handler], which interfaces with the
+ /// platform to receive textual input with proper integration with concerns such
+ /// as IME interactions. This handler will be active for the upcoming frame until the following frame is
+ /// rendered.
+ ///
+ /// [element_input_handler]: crate::ElementInputHandler
+ pub fn handle_input(&mut self, focus_handle: &FocusHandle, input_handler: impl InputHandler) {
+ if focus_handle.is_focused(self) {
+ let view_id = self.parent_view_id();
+ self.window.next_frame.requested_input_handler = Some(RequestedInputHandler {
+ view_id,
+ handler: Some(PlatformInputHandler::new(
+ self.to_async(),
+ Box::new(input_handler),
+ )),
+ })
+ }
+ }
+
+ /// Register a mouse event listener on the window for the next frame. The type of event
+ /// is determined by the first parameter of the given listener. When the next frame is rendered
+ /// the listener will be cleared.
+ pub fn on_mouse_event<Event: MouseEvent>(
+ &mut self,
+ mut handler: impl FnMut(&Event, DispatchPhase, &mut ElementContext) + 'static,
+ ) {
+ let view_id = self.parent_view_id();
+ let order = self.window.next_frame.z_index_stack.clone();
+ self.window
+ .next_frame
+ .mouse_listeners
+ .entry(TypeId::of::<Event>())
+ .or_default()
+ .push((
+ order,
+ view_id,
+ Box::new(
+ move |event: &dyn Any, phase: DispatchPhase, cx: &mut ElementContext<'_>| {
+ handler(event.downcast_ref().unwrap(), phase, cx)
+ },
+ ),
+ ))
+ }
+
+ /// Register a key event listener on the window for the next frame. The type of event
+ /// is determined by the first parameter of the given listener. When the next frame is rendered
+ /// the listener will be cleared.
+ ///
+ /// This is a fairly low-level method, so prefer using event handlers on elements unless you have
+ /// a specific need to register a global listener.
+ pub fn on_key_event<Event: KeyEvent>(
+ &mut self,
+ listener: impl Fn(&Event, DispatchPhase, &mut ElementContext) + 'static,
+ ) {
+ self.window.next_frame.dispatch_tree.on_key_event(Rc::new(
+ move |event: &dyn Any, phase, cx: &mut ElementContext<'_>| {
+ if let Some(event) = event.downcast_ref::<Event>() {
+ listener(event, phase, cx)
+ }
+ },
+ ));
+ }
+}
@@ -1,11 +1,11 @@
use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
use gpui::{
- div, fill, point, px, relative, AnyElement, AvailableSpace, BorrowWindow, Bounds,
- DispatchPhase, Element, ElementId, FocusHandle, Font, FontStyle, FontWeight, HighlightStyle,
- Hsla, InputHandler, InteractiveBounds, InteractiveElement, InteractiveElementState,
- Interactivity, IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton,
- MouseMoveEvent, Pixels, Point, ShapedLine, StatefulInteractiveElement, Styled, TextRun,
- TextStyle, TextSystem, UnderlineStyle, WeakView, WhiteSpace, WindowContext,
+ div, fill, point, px, relative, AnyElement, AvailableSpace, Bounds, DispatchPhase, Element,
+ ElementContext, ElementId, FocusHandle, Font, FontStyle, FontWeight, HighlightStyle, Hsla,
+ InputHandler, InteractiveBounds, InteractiveElement, InteractiveElementState, Interactivity,
+ IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, MouseMoveEvent,
+ Pixels, Point, ShapedLine, StatefulInteractiveElement, Styled, TextRun, TextStyle, TextSystem,
+ UnderlineStyle, WeakView, WhiteSpace, WindowContext,
};
use itertools::Itertools;
use language::CursorShape;
@@ -81,7 +81,7 @@ impl LayoutCell {
origin: Point<Pixels>,
layout: &LayoutState,
_visible_bounds: Bounds<Pixels>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let pos = {
let point = self.point;
@@ -120,7 +120,7 @@ impl LayoutRect {
}
}
- fn paint(&self, origin: Point<Pixels>, layout: &LayoutState, cx: &mut WindowContext) {
+ fn paint(&self, origin: Point<Pixels>, layout: &LayoutState, cx: &mut ElementContext) {
let position = {
let alac_point = self.point;
point(
@@ -365,7 +365,7 @@ impl TerminalElement {
result
}
- fn compute_layout(&self, bounds: Bounds<gpui::Pixels>, cx: &mut WindowContext) -> LayoutState {
+ fn compute_layout(&self, bounds: Bounds<gpui::Pixels>, cx: &mut ElementContext) -> LayoutState {
let settings = ThemeSettings::get_global(cx).clone();
let buffer_font_size = settings.buffer_font_size(cx);
@@ -590,7 +590,7 @@ impl TerminalElement {
origin: Point<Pixels>,
mode: TermMode,
bounds: Bounds<Pixels>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let focus = self.focus.clone();
let terminal = self.terminal.clone();
@@ -722,7 +722,7 @@ impl Element for TerminalElement {
fn request_layout(
&mut self,
element_state: Option<Self::State>,
- cx: &mut WindowContext<'_>,
+ cx: &mut ElementContext<'_>,
) -> (LayoutId, Self::State) {
let (layout_id, interactive_state) =
self.interactivity
@@ -741,7 +741,7 @@ impl Element for TerminalElement {
&mut self,
bounds: Bounds<Pixels>,
state: &mut Self::State,
- cx: &mut WindowContext<'_>,
+ cx: &mut ElementContext<'_>,
) {
let mut layout = self.compute_layout(bounds, cx);
@@ -2,8 +2,9 @@ use std::{cell::RefCell, rc::Rc};
use gpui::{
overlay, point, prelude::FluentBuilder, px, rems, AnchorCorner, AnyElement, Bounds,
- DismissEvent, DispatchPhase, Element, ElementId, InteractiveBounds, IntoElement, LayoutId,
- ManagedView, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext, WindowContext,
+ DismissEvent, DispatchPhase, Element, ElementContext, ElementId, InteractiveBounds,
+ IntoElement, LayoutId, ManagedView, MouseDownEvent, ParentElement, Pixels, Point, View,
+ VisualContext, WindowContext,
};
use crate::{Clickable, Selectable};
@@ -134,7 +135,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
fn request_layout(
&mut self,
element_state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (gpui::LayoutId, Self::State) {
let mut menu_layout_id = None;
@@ -188,7 +189,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
&mut self,
_: Bounds<gpui::Pixels>,
element_state: &mut Self::State,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
if let Some(mut child) = element_state.child_element.take() {
child.paint(cx);
@@ -1,9 +1,9 @@
use std::{cell::RefCell, rc::Rc};
use gpui::{
- overlay, AnchorCorner, AnyElement, BorrowWindow, Bounds, DismissEvent, DispatchPhase, Element,
- ElementId, InteractiveBounds, IntoElement, LayoutId, ManagedView, MouseButton, MouseDownEvent,
- ParentElement, Pixels, Point, View, VisualContext, WindowContext,
+ overlay, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase, Element,
+ ElementContext, ElementId, InteractiveBounds, IntoElement, LayoutId, ManagedView, MouseButton,
+ MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext, WindowContext,
};
pub struct RightClickMenu<M: ManagedView> {
@@ -64,7 +64,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
fn request_layout(
&mut self,
element_state: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (gpui::LayoutId, Self::State) {
let (menu, position) = if let Some(element_state) = element_state {
(element_state.menu, element_state.position)
@@ -116,7 +116,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
&mut self,
bounds: Bounds<gpui::Pixels>,
element_state: &mut Self::State,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
if let Some(mut child) = element_state.child_element.take() {
child.paint(cx);
@@ -2,9 +2,9 @@
pub use gpui::prelude::*;
pub use gpui::{
- div, px, relative, rems, AbsoluteLength, DefiniteLength, Div, Element, ElementId,
- InteractiveElement, ParentElement, Pixels, Rems, RenderOnce, SharedString, Styled, ViewContext,
- WindowContext,
+ div, px, relative, rems, AbsoluteLength, DefiniteLength, Div, Element, ElementContext,
+ ElementId, InteractiveElement, ParentElement, Pixels, Rems, RenderOnce, SharedString, Styled,
+ ViewContext, WindowContext,
};
pub use crate::clickable::*;
@@ -7,7 +7,7 @@ use std::time::Duration;
use command_palette::CommandPalette;
use editor::DisplayPoint;
-use gpui::{Action, KeyBinding};
+use gpui::KeyBinding;
pub use neovim_backed_binding_test_context::*;
pub use neovim_backed_test_context::*;
pub use vim_test_context::*;
@@ -15,7 +15,7 @@ pub use vim_test_context::*;
use indoc::indoc;
use search::BufferSearchBar;
-use crate::{insert::NormalBefore, motion, normal::InsertLineBelow, state::Mode, ModeIndicator};
+use crate::{insert::NormalBefore, motion, state::Mode, ModeIndicator};
#[gpui::test]
async fn test_initially_disabled(cx: &mut gpui::TestAppContext) {
@@ -710,7 +710,7 @@ mod element {
pane_bounds: Bounds<Pixels>,
axis_bounds: Bounds<Pixels>,
workspace: WeakView<Workspace>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) {
let handle_bounds = Bounds {
origin: pane_bounds.origin.apply_along(axis, |origin| {
@@ -803,7 +803,7 @@ mod element {
fn request_layout(
&mut self,
state: Option<Self::State>,
- cx: &mut ui::prelude::WindowContext,
+ cx: &mut ui::prelude::ElementContext,
) -> (gpui::LayoutId, Self::State) {
let mut style = Style::default();
style.flex_grow = 1.;
@@ -820,7 +820,7 @@ mod element {
&mut self,
bounds: gpui::Bounds<ui::prelude::Pixels>,
state: &mut Self::State,
- cx: &mut ui::prelude::WindowContext,
+ cx: &mut ui::prelude::ElementContext,
) {
let flexes = self.flexes.lock().clone();
let len = self.children.len();
@@ -26,12 +26,12 @@ use futures::{
};
use gpui::{
actions, canvas, div, impl_actions, point, px, size, Action, AnyElement, AnyModel, AnyView,
- AnyWeakView, AppContext, AsyncAppContext, AsyncWindowContext, BorrowWindow, Bounds, Context,
- Div, DragMoveEvent, Element, Entity, EntityId, EventEmitter, FocusHandle, FocusableView,
- GlobalPixels, InteractiveElement, IntoElement, KeyContext, LayoutId, ManagedView, Model,
- ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel, Render, Size,
- Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds,
- WindowContext, WindowHandle, WindowOptions,
+ AnyWeakView, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Context, Div,
+ DragMoveEvent, Element, ElementContext, Entity, EntityId, EventEmitter, FocusHandle,
+ FocusableView, GlobalPixels, InteractiveElement, IntoElement, KeyContext, LayoutId,
+ ManagedView, Model, ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel,
+ Render, Size, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView,
+ WindowBounds, WindowContext, WindowHandle, WindowOptions,
};
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
use itertools::Itertools;
@@ -3539,9 +3539,14 @@ impl Render for Workspace {
.border_b()
.border_color(colors.border)
.child(
- canvas(cx.listener(|workspace, bounds, _| {
- workspace.bounds = *bounds;
- }))
+ canvas({
+ let this = cx.view().clone();
+ move |bounds, cx| {
+ this.update(cx, |this, _cx| {
+ this.bounds = *bounds;
+ })
+ }
+ })
.absolute()
.size_full(),
)
@@ -4293,7 +4298,7 @@ impl Element for DisconnectedOverlay {
fn request_layout(
&mut self,
_: Option<Self::State>,
- cx: &mut WindowContext,
+ cx: &mut ElementContext,
) -> (LayoutId, Self::State) {
let mut background = cx.theme().colors().elevated_surface_background;
background.fade_out(0.2);
@@ -4315,7 +4320,12 @@ impl Element for DisconnectedOverlay {
(overlay.request_layout(cx), overlay)
}
- fn paint(&mut self, bounds: Bounds<Pixels>, overlay: &mut Self::State, cx: &mut WindowContext) {
+ fn paint(
+ &mut self,
+ bounds: Bounds<Pixels>,
+ overlay: &mut Self::State,
+ cx: &mut ElementContext,
+ ) {
cx.with_z_index(u8::MAX, |cx| {
cx.add_opaque_layer(bounds);
overlay.paint(cx);