WIP: Refactor out ElementContext from WindowContext (#4166)

During the doc parties, I've sometimes struggled with how and where to
describe the high level intention behind various APIs that are available
in GPUI. Fortunately, rust doc has a tool for this: Module level
documentation. However, writing this kind of documentation for the
`WindowContext` is difficult, as it bundles up the nice, high level GPUI
APIs for entity management and view rendering, with all of the low level
imperative APIs that `Element`s use to draw to the screen. Splitting
these apart into an `ElementContext`, which contains a `WindowContext`,
gives us a way to corral the element systems into their own API and
module, allowing us to document the Element system on it's own terms,
and enforce the correct usage of our APIs, and helps people who are
exploring our APIs through autocomplete to not be overloaded with
non-applicable methods.

Release Notes:

- N/A
This commit is contained in:
Mikayla Maki 2024-01-21 20:59:59 -08:00 committed by GitHub
commit 9bcf27b05b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 1571 additions and 1392 deletions

View file

@ -1584,27 +1584,34 @@ mod tests {
} }
fn editor_blocks(editor: &View<Editor>, cx: &mut WindowContext) -> Vec<(u32, SharedString)> { fn editor_blocks(editor: &View<Editor>, cx: &mut WindowContext) -> Vec<(u32, SharedString)> {
let editor_view = editor.clone();
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(cx); let snapshot = editor.snapshot(cx);
snapshot snapshot
.blocks_in_range(0..snapshot.max_point().row()) .blocks_in_range(0..snapshot.max_point().row())
.enumerate() .enumerate()
.filter_map(|(ix, (row, block))| { .filter_map(|(ix, (row, block))| {
let name = match block { let name: SharedString = match block {
TransformBlock::Custom(block) => block TransformBlock::Custom(block) => cx.with_element_context({
.render(&mut BlockContext { let editor_view = editor_view.clone();
view_context: cx, |cx| -> Option<SharedString> {
anchor_x: px(0.), block
gutter_padding: px(0.), .render(&mut BlockContext {
gutter_width: px(0.), context: cx,
line_height: px(0.), anchor_x: px(0.),
em_width: px(0.), gutter_padding: px(0.),
block_id: ix, gutter_width: px(0.),
editor_style: &editor::EditorStyle::default(), line_height: px(0.),
}) em_width: px(0.),
.inner_id()? block_id: ix,
.try_into() view: editor_view,
.ok()?, editor_style: &editor::EditorStyle::default(),
})
.inner_id()?
.try_into()
.ok()
}
})?,
TransformBlock::ExcerptHeader { TransformBlock::ExcerptHeader {
starts_new_buffer, .. starts_new_buffer, ..

View file

@ -4,7 +4,7 @@ use super::{
}; };
use crate::{Anchor, Editor, EditorStyle, ExcerptId, ExcerptRange, ToPoint as _}; use crate::{Anchor, Editor, EditorStyle, ExcerptId, ExcerptRange, ToPoint as _};
use collections::{Bound, HashMap, HashSet}; use collections::{Bound, HashMap, HashSet};
use gpui::{AnyElement, Pixels, ViewContext}; use gpui::{AnyElement, ElementContext, Pixels, View};
use language::{BufferSnapshot, Chunk, Patch, Point}; use language::{BufferSnapshot, Chunk, Patch, Point};
use parking_lot::Mutex; use parking_lot::Mutex;
use std::{ use std::{
@ -81,7 +81,8 @@ pub enum BlockStyle {
} }
pub struct BlockContext<'a, 'b> { 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 anchor_x: Pixels,
pub gutter_width: Pixels, pub gutter_width: Pixels,
pub gutter_padding: Pixels, pub gutter_padding: Pixels,
@ -933,16 +934,16 @@ impl BlockDisposition {
} }
impl<'a> Deref for BlockContext<'a, '_> { impl<'a> Deref for BlockContext<'a, '_> {
type Target = ViewContext<'a, Editor>; type Target = ElementContext<'a>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
self.view_context self.context
} }
} }
impl DerefMut for BlockContext<'_, '_> { impl DerefMut for BlockContext<'_, '_> {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
self.view_context self.context
} }
} }

View file

@ -3912,7 +3912,7 @@ impl Editor {
gutter_hovered: bool, gutter_hovered: bool,
_line_height: Pixels, _line_height: Pixels,
_gutter_margin: Pixels, _gutter_margin: Pixels,
cx: &mut ViewContext<Self>, editor_view: View<Editor>,
) -> Vec<Option<IconButton>> { ) -> Vec<Option<IconButton>> {
fold_data fold_data
.iter() .iter()
@ -3922,14 +3922,19 @@ impl Editor {
.map(|(fold_status, buffer_row, active)| { .map(|(fold_status, buffer_row, active)| {
(active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| { (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
IconButton::new(ix as usize, ui::IconName::ChevronDown) IconButton::new(ix as usize, ui::IconName::ChevronDown)
.on_click(cx.listener(move |editor, _e, cx| match fold_status { .on_click({
FoldStatus::Folded => { let view = editor_view.clone();
editor.unfold_at(&UnfoldAt { buffer_row }, cx); 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);
}
})
} }
FoldStatus::Foldable => { })
editor.fold_at(&FoldAt { buffer_row }, cx);
}
}))
.icon_color(ui::Color::Muted) .icon_color(ui::Color::Muted)
.icon_size(ui::IconSize::Small) .icon_size(ui::IconSize::Small)
.selected(fold_status == FoldStatus::Folded) .selected(fold_status == FoldStatus::Folded)
@ -9575,10 +9580,10 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, _is_valid: bool) -> Ren
.size(ButtonSize::Compact) .size(ButtonSize::Compact)
.style(ButtonStyle::Transparent) .style(ButtonStyle::Transparent)
.visible_on_hover(group_id) .visible_on_hover(group_id)
.on_click(cx.listener({ .on_click({
let message = diagnostic.message.clone(); 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)), .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)),
) )
.into_any_element() .into_any_element()

View file

@ -25,12 +25,12 @@ use collections::{BTreeMap, HashMap};
use git::diff::DiffHunkStatus; use git::diff::DiffHunkStatus;
use gpui::{ use gpui::{
div, fill, outline, overlay, point, px, quad, relative, size, transparent_black, Action, div, fill, outline, overlay, point, px, quad, relative, size, transparent_black, Action,
AnchorCorner, AnyElement, AvailableSpace, BorrowWindow, Bounds, ContentMask, Corners, AnchorCorner, AnyElement, AvailableSpace, Bounds, ContentMask, Corners, CursorStyle,
CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Hsla, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Hsla, InteractiveBounds,
InteractiveBounds, InteractiveElement, IntoElement, ModifiersChangedEvent, MouseButton, InteractiveElement, IntoElement, ModifiersChangedEvent, MouseButton, MouseDownEvent,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, ScrollDelta, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine,
ScrollWheelEvent, ShapedLine, SharedString, Size, StackingOrder, StatefulInteractiveElement, SharedString, Size, StackingOrder, StatefulInteractiveElement, Style, Styled, TextRun,
Style, Styled, TextRun, TextStyle, View, ViewContext, WindowContext, TextStyle, View, ViewContext, WindowContext,
}; };
use itertools::Itertools; use itertools::Itertools;
use language::language_settings::ShowWhitespaceSetting; use language::language_settings::ShowWhitespaceSetting;
@ -330,7 +330,7 @@ impl EditorElement {
register_action(view, cx, Editor::display_cursor_names); 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({ cx.on_key_event({
let editor = self.editor.clone(); let editor = self.editor.clone();
move |event: &ModifiersChangedEvent, phase, cx| { move |event: &ModifiersChangedEvent, phase, cx| {
@ -628,7 +628,7 @@ impl EditorElement {
gutter_bounds: Bounds<Pixels>, gutter_bounds: Bounds<Pixels>,
text_bounds: Bounds<Pixels>, text_bounds: Bounds<Pixels>,
layout: &LayoutState, layout: &LayoutState,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let bounds = gutter_bounds.union(&text_bounds); let bounds = gutter_bounds.union(&text_bounds);
let scroll_top = let scroll_top =
@ -711,7 +711,7 @@ impl EditorElement {
&mut self, &mut self,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
layout: &mut LayoutState, layout: &mut LayoutState,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let line_height = layout.position_map.line_height; 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 line_height = layout.position_map.line_height;
let scroll_position = layout.position_map.snapshot.scroll_position(); let scroll_position = layout.position_map.snapshot.scroll_position();
@ -886,7 +886,7 @@ impl EditorElement {
&mut self, &mut self,
text_bounds: Bounds<Pixels>, text_bounds: Bounds<Pixels>,
layout: &mut LayoutState, layout: &mut LayoutState,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let start_row = layout.visible_display_row_range.start; let start_row = layout.visible_display_row_range.start;
let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO); let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
@ -1153,7 +1153,7 @@ impl EditorElement {
&mut self, &mut self,
text_bounds: Bounds<Pixels>, text_bounds: Bounds<Pixels>,
layout: &mut LayoutState, layout: &mut LayoutState,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO); let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
let start_row = layout.visible_display_row_range.start; let start_row = layout.visible_display_row_range.start;
@ -1268,7 +1268,7 @@ impl EditorElement {
&mut self, &mut self,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
layout: &mut LayoutState, layout: &mut LayoutState,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
if layout.mode != EditorMode::Full { if layout.mode != EditorMode::Full {
return; return;
@ -1512,7 +1512,7 @@ impl EditorElement {
layout: &LayoutState, layout: &LayoutState,
content_origin: gpui::Point<Pixels>, content_origin: gpui::Point<Pixels>,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let start_row = layout.visible_display_row_range.start; let start_row = layout.visible_display_row_range.start;
let end_row = layout.visible_display_row_range.end; let end_row = layout.visible_display_row_range.end;
@ -1564,7 +1564,7 @@ impl EditorElement {
&mut self, &mut self,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
layout: &mut LayoutState, layout: &mut LayoutState,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let scroll_position = layout.position_map.snapshot.scroll_position(); let scroll_position = layout.position_map.snapshot.scroll_position();
let scroll_left = scroll_position.x * layout.position_map.em_width; 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| { self.editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(cx); let snapshot = editor.snapshot(cx);
let style = self.style.clone(); let style = self.style.clone();
@ -2083,7 +2083,9 @@ impl EditorElement {
.width; .width;
let scroll_width = longest_line_width.max(max_visible_line_width) + overscroll.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( self.layout_blocks(
start_row..end_row, start_row..end_row,
&snapshot, &snapshot,
@ -2097,8 +2099,10 @@ impl EditorElement {
&style, &style,
&line_layouts, &line_layouts,
editor, editor,
editor_view,
cx, cx,
) )
})
}); });
let scroll_max = point( let scroll_max = point(
@ -2174,15 +2178,19 @@ impl EditorElement {
cx, 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( editor.render_fold_indicators(
fold_statuses, fold_statuses,
&style, &style,
editor.gutter_hovered, editor.gutter_hovered,
line_height, line_height,
gutter_margin, gutter_margin,
cx, editor_view,
) )
})
}); });
let invisible_symbol_font_size = font_size / 2.; let invisible_symbol_font_size = font_size / 2.;
@ -2273,7 +2281,8 @@ impl EditorElement {
style: &EditorStyle, style: &EditorStyle,
line_layouts: &[LineWithInvisibles], line_layouts: &[LineWithInvisibles],
editor: &mut Editor, editor: &mut Editor,
cx: &mut ViewContext<Editor>, editor_view: View<Editor>,
cx: &mut ElementContext,
) -> (Pixels, Vec<BlockLayout>) { ) -> (Pixels, Vec<BlockLayout>) {
let mut block_id = 0; let mut block_id = 0;
let (fixed_blocks, non_fixed_blocks) = snapshot let (fixed_blocks, non_fixed_blocks) = snapshot
@ -2287,7 +2296,7 @@ impl EditorElement {
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
block_id: usize, block_id: usize,
editor: &mut Editor, editor: &mut Editor,
cx: &mut ViewContext<Editor>| { cx: &mut ElementContext| {
let mut element = match block { let mut element = match block {
TransformBlock::Custom(block) => { TransformBlock::Custom(block) => {
let align_to = block let align_to = block
@ -2306,13 +2315,14 @@ impl EditorElement {
}; };
block.render(&mut BlockContext { block.render(&mut BlockContext {
view_context: cx, context: cx,
anchor_x, anchor_x,
gutter_padding, gutter_padding,
line_height, line_height,
gutter_width, gutter_width,
em_width, em_width,
block_id, block_id,
view: editor_view.clone(),
editor_style: &self.style, editor_style: &self.style,
}) })
} }
@ -2504,7 +2514,7 @@ impl EditorElement {
&mut self, &mut self,
interactive_bounds: &InteractiveBounds, interactive_bounds: &InteractiveBounds,
layout: &LayoutState, layout: &LayoutState,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
cx.on_mouse_event({ cx.on_mouse_event({
let position_map = layout.position_map.clone(); let position_map = layout.position_map.clone();
@ -2564,7 +2574,7 @@ impl EditorElement {
gutter_bounds: Bounds<Pixels>, gutter_bounds: Bounds<Pixels>,
text_bounds: Bounds<Pixels>, text_bounds: Bounds<Pixels>,
layout: &LayoutState, layout: &LayoutState,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let interactive_bounds = InteractiveBounds { let interactive_bounds = InteractiveBounds {
bounds: bounds.intersect(&cx.content_mask().bounds), bounds: bounds.intersect(&cx.content_mask().bounds),
@ -2787,7 +2797,7 @@ impl LineWithInvisibles {
content_origin: gpui::Point<Pixels>, content_origin: gpui::Point<Pixels>,
whitespace_setting: ShowWhitespaceSetting, whitespace_setting: ShowWhitespaceSetting,
selection_ranges: &[Range<DisplayPoint>], selection_ranges: &[Range<DisplayPoint>],
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let line_height = layout.position_map.line_height; let line_height = layout.position_map.line_height;
let line_y = line_height * row as f32 - layout.position_map.scroll_position.y; let line_y = line_height * row as f32 - layout.position_map.scroll_position.y;
@ -2821,7 +2831,7 @@ impl LineWithInvisibles {
row: u32, row: u32,
line_height: Pixels, line_height: Pixels,
whitespace_setting: ShowWhitespaceSetting, whitespace_setting: ShowWhitespaceSetting,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let allowed_invisibles_regions = match whitespace_setting { let allowed_invisibles_regions = match whitespace_setting {
ShowWhitespaceSetting::None => return, ShowWhitespaceSetting::None => return,
@ -2870,7 +2880,7 @@ impl Element for EditorElement {
fn request_layout( fn request_layout(
&mut self, &mut self,
_element_state: Option<Self::State>, _element_state: Option<Self::State>,
cx: &mut gpui::WindowContext, cx: &mut gpui::ElementContext,
) -> (gpui::LayoutId, Self::State) { ) -> (gpui::LayoutId, Self::State) {
cx.with_view_id(self.editor.entity_id(), |cx| { cx.with_view_id(self.editor.entity_id(), |cx| {
self.editor.update(cx, |editor, cx| { self.editor.update(cx, |editor, cx| {
@ -2882,34 +2892,36 @@ impl Element for EditorElement {
let mut style = Style::default(); let mut style = Style::default();
style.size.width = relative(1.).into(); style.size.width = relative(1.).into();
style.size.height = self.style.text.line_height_in_pixels(rem_size).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 } => { EditorMode::AutoHeight { max_lines } => {
let editor_handle = cx.view().clone(); let editor_handle = cx.view().clone();
let max_line_number_width = let max_line_number_width =
self.max_line_number_width(&editor.snapshot(cx), cx); self.max_line_number_width(&editor.snapshot(cx), cx);
cx.request_measured_layout( cx.with_element_context(|cx| {
Style::default(), cx.request_measured_layout(
move |known_dimensions, _, cx| { Style::default(),
editor_handle move |known_dimensions, _, cx| {
.update(cx, |editor, cx| { editor_handle
compute_auto_height_layout( .update(cx, |editor, cx| {
editor, compute_auto_height_layout(
max_lines, editor,
max_line_number_width, max_lines,
known_dimensions, max_line_number_width,
cx, known_dimensions,
) cx,
}) )
.unwrap_or_default() })
}, .unwrap_or_default()
) },
)
})
} }
EditorMode::Full => { EditorMode::Full => {
let mut style = Style::default(); let mut style = Style::default();
style.size.width = relative(1.).into(); style.size.width = relative(1.).into();
style.size.height = 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, &mut self,
bounds: Bounds<gpui::Pixels>, bounds: Bounds<gpui::Pixels>,
_element_state: &mut Self::State, _element_state: &mut Self::State,
cx: &mut gpui::WindowContext, cx: &mut gpui::ElementContext,
) { ) {
let editor = self.editor.clone(); 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 { let bounds = match self.shape {
CursorShape::Bar => Bounds { CursorShape::Bar => Bounds {
origin: self.origin + origin, origin: self.origin + origin,
@ -3284,7 +3296,7 @@ pub struct HighlightedRangeLine {
} }
impl HighlightedRange { 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 { 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(self.start_y, &self.lines[0..1], bounds, cx);
self.paint_lines( self.paint_lines(
@ -3303,7 +3315,7 @@ impl HighlightedRange {
start_y: Pixels, start_y: Pixels,
lines: &[HighlightedRangeLine], lines: &[HighlightedRangeLine],
_bounds: Bounds<Pixels>, _bounds: Bounds<Pixels>,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
if lines.is_empty() { if lines.is_empty() {
return; return;
@ -3521,14 +3533,16 @@ mod tests {
.unwrap(); .unwrap();
let state = cx let state = cx
.update_window(window.into(), |view, cx| { .update_window(window.into(), |view, cx| {
cx.with_view_id(view.entity_id(), |cx| { cx.with_element_context(|cx| {
element.compute_layout( cx.with_view_id(view.entity_id(), |cx| {
Bounds { element.compute_layout(
origin: point(px(500.), px(500.)), Bounds {
size: size(px(500.), px(500.)), origin: point(px(500.), px(500.)),
}, size: size(px(500.), px(500.)),
cx, },
) cx,
)
})
}) })
}) })
.unwrap(); .unwrap();
@ -3615,14 +3629,16 @@ mod tests {
let state = cx let state = cx
.update_window(window.into(), |view, cx| { .update_window(window.into(), |view, cx| {
cx.with_view_id(view.entity_id(), |cx| { cx.with_element_context(|cx| {
element.compute_layout( cx.with_view_id(view.entity_id(), |cx| {
Bounds { element.compute_layout(
origin: point(px(500.), px(500.)), Bounds {
size: size(px(500.), px(500.)), origin: point(px(500.), px(500.)),
}, size: size(px(500.), px(500.)),
cx, },
) cx,
)
})
}) })
}) })
.unwrap(); .unwrap();
@ -3679,14 +3695,16 @@ mod tests {
let mut element = EditorElement::new(&editor, style); let mut element = EditorElement::new(&editor, style);
let state = cx let state = cx
.update_window(window.into(), |view, cx| { .update_window(window.into(), |view, cx| {
cx.with_view_id(view.entity_id(), |cx| { cx.with_element_context(|cx| {
element.compute_layout( cx.with_view_id(view.entity_id(), |cx| {
Bounds { element.compute_layout(
origin: point(px(500.), px(500.)), Bounds {
size: size(px(500.), px(500.)), origin: point(px(500.), px(500.)),
}, size: size(px(500.), px(500.)),
cx, },
) cx,
)
})
}) })
}) })
.unwrap(); .unwrap();
@ -3704,8 +3722,10 @@ mod tests {
// Don't panic. // Don't panic.
let bounds = Bounds::<Pixels>::new(Default::default(), size); let bounds = Bounds::<Pixels>::new(Default::default(), size);
cx.update_window(window.into(), |_, cx| element.paint(bounds, &mut (), cx)) cx.update_window(window.into(), |_, cx| {
.unwrap() cx.with_element_context(|cx| element.paint(bounds, &mut (), cx))
})
.unwrap()
} }
#[gpui::test] #[gpui::test]
@ -3880,13 +3900,15 @@ mod tests {
.unwrap(); .unwrap();
let layout_state = cx let layout_state = cx
.update_window(window.into(), |_, cx| { .update_window(window.into(), |_, cx| {
element.compute_layout( cx.with_element_context(|cx| {
Bounds { element.compute_layout(
origin: point(px(500.), px(500.)), Bounds {
size: size(px(500.), px(500.)), origin: point(px(500.), px(500.)),
}, size: size(px(500.), px(500.)),
cx, },
) cx,
)
})
}) })
.unwrap(); .unwrap();

View file

@ -640,8 +640,11 @@ impl<'a> VisualTestContext {
.as_ref() .as_ref()
.expect("Can't draw to this window without a root view") .expect("Can't draw to this window without a root view")
.entity_id(); .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(); cx.refresh();

View file

@ -35,12 +35,12 @@
//! your own custom layout algorithm or rendering a code editor. //! your own custom layout algorithm or rendering a code editor.
use crate::{ 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, Pixels, Point, Size, ViewContext, WindowContext, ELEMENT_ARENA,
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
pub(crate) use smallvec::SmallVec; pub(crate) use smallvec::SmallVec;
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. /// 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. /// 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( fn request_layout(
&mut self, &mut self,
state: Option<Self::State>, state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State); ) -> (LayoutId, Self::State);
/// Once layout has been completed, this method will be called to paint the element to the screen. /// Once layout has been completed, this method will be called to paint the element to the screen.
/// The state argument is the same state that was returned from [`Element::request_layout()`]. /// 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`]. /// Convert this element into a dynamically-typed [`AnyElement`].
fn into_any(self) -> AnyElement { fn into_any(self) -> AnyElement {
@ -95,8 +95,8 @@ pub trait IntoElement: Sized {
self, self,
origin: Point<Pixels>, origin: Point<Pixels>,
available_space: Size<T>, available_space: Size<T>,
cx: &mut WindowContext, cx: &mut ElementContext,
f: impl FnOnce(&mut <Self::Element as Element>::State, &mut WindowContext) -> R, f: impl FnOnce(&mut <Self::Element as Element>::State, &mut ElementContext) -> R,
) -> R ) -> R
where where
T: Clone + Default + Debug + Into<AvailableSpace>, T: Clone + Default + Debug + Into<AvailableSpace>,
@ -193,14 +193,19 @@ impl<C: RenderOnce> Element for Component<C> {
fn request_layout( fn request_layout(
&mut self, &mut self,
_: Option<Self::State>, _: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (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); let layout_id = element.request_layout(cx);
(layout_id, element) (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) element.paint(cx)
} }
} }
@ -224,21 +229,21 @@ pub(crate) struct GlobalElementId(SmallVec<[ElementId; 32]>);
trait ElementObject { trait ElementObject {
fn element_id(&self) -> Option<ElementId>; 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( fn measure(
&mut self, &mut self,
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> Size<Pixels>; ) -> Size<Pixels>;
fn draw( fn draw(
&mut self, &mut self,
origin: Point<Pixels>, origin: Point<Pixels>,
available_space: Size<AvailableSpace>, 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() 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, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
{ {
let layout_id = cx.with_element_state(id, |element_state, cx| { let layout_id = cx.with_element_state(id, |element_state, cx| {
@ -298,7 +303,7 @@ impl<E: Element> DrawableElement<E> {
layout_id 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 { match self.phase {
ElementDrawPhase::LayoutRequested { ElementDrawPhase::LayoutRequested {
layout_id, layout_id,
@ -343,7 +348,7 @@ impl<E: Element> DrawableElement<E> {
fn measure( fn measure(
&mut self, &mut self,
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> Size<Pixels> { ) -> Size<Pixels> {
if matches!(&self.phase, ElementDrawPhase::Start) { if matches!(&self.phase, ElementDrawPhase::Start) {
self.request_layout(cx); self.request_layout(cx);
@ -384,7 +389,7 @@ impl<E: Element> DrawableElement<E> {
mut self, mut self,
origin: Point<Pixels>, origin: Point<Pixels>,
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> Option<E::State> { ) -> Option<E::State> {
self.measure(available_space, cx); self.measure(available_space, cx);
cx.with_absolute_element_offset(origin, |cx| self.paint(cx)) cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
@ -400,18 +405,18 @@ where
self.as_ref().unwrap().element_id() 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) 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); DrawableElement::paint(self.take().unwrap(), cx);
} }
fn measure( fn measure(
&mut self, &mut self,
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> Size<Pixels> { ) -> Size<Pixels> {
DrawableElement::measure(self.as_mut().unwrap(), available_space, cx) DrawableElement::measure(self.as_mut().unwrap(), available_space, cx)
} }
@ -420,7 +425,7 @@ where
&mut self, &mut self,
origin: Point<Pixels>, origin: Point<Pixels>,
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
DrawableElement::draw(self.take().unwrap(), origin, available_space, cx); 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`. /// Request the layout ID of the element stored in this `AnyElement`.
/// Used for laying out child elements in a parent element. /// 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) self.0.request_layout(cx)
} }
/// Paints the element stored in this `AnyElement`. /// 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) self.0.paint(cx)
} }
@ -456,7 +461,7 @@ impl AnyElement {
pub fn measure( pub fn measure(
&mut self, &mut self,
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> Size<Pixels> { ) -> Size<Pixels> {
self.0.measure(available_space, cx) self.0.measure(available_space, cx)
} }
@ -466,7 +471,7 @@ impl AnyElement {
&mut self, &mut self,
origin: Point<Pixels>, origin: Point<Pixels>,
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
self.0.draw(origin, available_space, cx) self.0.draw(origin, available_space, cx)
} }
@ -483,13 +488,13 @@ impl Element for AnyElement {
fn request_layout( fn request_layout(
&mut self, &mut self,
_: Option<Self::State>, _: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
let layout_id = self.request_layout(cx); let layout_id = self.request_layout(cx);
(layout_id, ()) (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) self.paint(cx)
} }
} }
@ -531,7 +536,7 @@ impl Element for () {
fn request_layout( fn request_layout(
&mut self, &mut self,
_state: Option<Self::State>, _state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
(cx.request_layout(&crate::Style::default(), None), ()) (cx.request_layout(&crate::Style::default(), None), ())
} }
@ -540,7 +545,7 @@ impl Element for () {
&mut self, &mut self,
_bounds: Bounds<Pixels>, _bounds: Bounds<Pixels>,
_state: &mut Self::State, _state: &mut Self::State,
_cx: &mut WindowContext, _cx: &mut ElementContext,
) { ) {
} }
} }

View file

@ -1,10 +1,10 @@
use refineable::Refineable as _; 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. /// Construct a canvas element with the given paint callback.
/// Useful for adding short term custom drawing to a view. /// Useful for adding short term custom drawing to a view.
pub fn canvas(callback: impl 'static + FnOnce(&Bounds<Pixels>, &mut WindowContext)) -> Canvas { pub fn canvas(callback: impl 'static + FnOnce(&Bounds<Pixels>, &mut ElementContext)) -> Canvas {
Canvas { Canvas {
paint_callback: Some(Box::new(callback)), paint_callback: Some(Box::new(callback)),
style: StyleRefinement::default(), 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 /// A canvas element, meant for accessing the low level paint API without defining a whole
/// custom element /// custom element
pub struct Canvas { 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, style: StyleRefinement,
} }
@ -36,7 +36,7 @@ impl Element for Canvas {
fn request_layout( fn request_layout(
&mut self, &mut self,
_: Option<Self::State>, _: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (crate::LayoutId, Self::State) { ) -> (crate::LayoutId, Self::State) {
let mut style = Style::default(); let mut style = Style::default();
style.refine(&self.style); style.refine(&self.style);
@ -44,7 +44,7 @@ impl Element for Canvas {
(layout_id, style) (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| { style.paint(bounds, cx, |cx| {
(self.paint_callback.take().unwrap())(&bounds, cx) (self.paint_callback.take().unwrap())(&bounds, cx)
}); });

View file

@ -23,12 +23,11 @@
//! //!
use crate::{ use crate::{
point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext, point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, Bounds, ClickEvent,
BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId, FocusHandle, IntoElement, DispatchPhase, Element, ElementContext, ElementId, FocusHandle, IntoElement, IsZero,
IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent,
MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Render, ScrollWheelEvent, MouseUpEvent, ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size,
SharedString, Size, StackingOrder, Style, StyleRefinement, Styled, Task, View, Visibility, StackingOrder, Style, StyleRefinement, Styled, Task, View, Visibility, WindowContext,
WindowContext,
}; };
use collections::HashMap; use collections::HashMap;
@ -41,6 +40,7 @@ use std::{
fmt::Debug, fmt::Debug,
marker::PhantomData, marker::PhantomData,
mem, mem,
ops::DerefMut,
rc::Rc, rc::Rc,
time::Duration, time::Duration,
}; };
@ -1052,7 +1052,7 @@ impl Element for Div {
fn request_layout( fn request_layout(
&mut self, &mut self,
element_state: Option<Self::State>, element_state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
let mut child_layout_ids = SmallVec::new(); let mut child_layout_ids = SmallVec::new();
let (layout_id, interactive_state) = self.interactivity.layout( let (layout_id, interactive_state) = self.interactivity.layout(
@ -1082,7 +1082,7 @@ impl Element for Div {
&mut self, &mut self,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
element_state: &mut Self::State, element_state: &mut Self::State,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let mut child_min = point(Pixels::MAX, Pixels::MAX); let mut child_min = point(Pixels::MAX, Pixels::MAX);
let mut child_max = Point::default(); let mut child_max = Point::default();
@ -1233,8 +1233,8 @@ impl Interactivity {
pub fn layout( pub fn layout(
&mut self, &mut self,
element_state: Option<InteractiveElementState>, element_state: Option<InteractiveElementState>,
cx: &mut WindowContext, cx: &mut ElementContext,
f: impl FnOnce(Style, &mut WindowContext) -> LayoutId, f: impl FnOnce(Style, &mut ElementContext) -> LayoutId,
) -> (LayoutId, InteractiveElementState) { ) -> (LayoutId, InteractiveElementState) {
let mut element_state = element_state.unwrap_or_default(); let mut element_state = element_state.unwrap_or_default();
@ -1281,8 +1281,8 @@ impl Interactivity {
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
content_size: Size<Pixels>, content_size: Size<Pixels>,
element_state: &mut InteractiveElementState, element_state: &mut InteractiveElementState,
cx: &mut WindowContext, cx: &mut ElementContext,
f: impl FnOnce(&Style, Point<Pixels>, &mut WindowContext), f: impl FnOnce(&Style, Point<Pixels>, &mut ElementContext),
) { ) {
let style = self.compute_style(Some(bounds), element_state, cx); let style = self.compute_style(Some(bounds), element_state, cx);
let z_index = style.z_index.unwrap_or(0); let z_index = style.z_index.unwrap_or(0);
@ -1295,7 +1295,7 @@ impl Interactivity {
.insert(debug_selector.clone(), bounds); .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 let hover_group_bounds = self
.group_hover_style .group_hover_style
.as_ref() .as_ref()
@ -1319,7 +1319,7 @@ impl Interactivity {
} }
cx.with_z_index(z_index, |cx| { 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_text_style(style.text_style().cloned(), |cx| {
cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| { cx.with_content_mask(style.overflow_mask(bounds, cx.rem_size()), |cx| {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -1333,7 +1333,7 @@ impl Interactivity {
let element_id = format!("{:?}", self.element_id.as_ref().unwrap()); let element_id = format!("{:?}", self.element_id.as_ref().unwrap());
let str_len = element_id.len(); let str_len = element_id.len();
let render_debug_text = |cx: &mut WindowContext| { let render_debug_text = |cx: &mut ElementContext| {
if let Some(text) = cx if let Some(text) = cx
.text_system() .text_system()
.shape_text( .shape_text(
@ -1540,12 +1540,17 @@ impl Interactivity {
let mut can_drop = true; let mut can_drop = true;
if let Some(predicate) = &can_drop_predicate { if let Some(predicate) = &can_drop_predicate {
can_drop = can_drop = predicate(
predicate(drag.value.as_ref(), cx); drag.value.as_ref(),
cx.deref_mut(),
);
} }
if can_drop { if can_drop {
listener(drag.value.as_ref(), cx); listener(
drag.value.as_ref(),
cx.deref_mut(),
);
cx.refresh(); cx.refresh();
cx.stop_propagation(); cx.stop_propagation();
} }
@ -1676,7 +1681,7 @@ impl Interactivity {
*was_hovered = is_hovered; *was_hovered = is_hovered;
drop(was_hovered); drop(was_hovered);
hover_listener(&is_hovered, cx); hover_listener(&is_hovered, cx.deref_mut());
} }
}); });
} }
@ -1897,7 +1902,7 @@ impl Interactivity {
&self, &self,
bounds: Option<Bounds<Pixels>>, bounds: Option<Bounds<Pixels>>,
element_state: &mut InteractiveElementState, element_state: &mut InteractiveElementState,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> Style { ) -> Style {
let mut style = Style::default(); let mut style = Style::default();
style.refine(&self.base_style); style.refine(&self.base_style);
@ -1921,7 +1926,9 @@ impl Interactivity {
let mouse_position = cx.mouse_position(); let mouse_position = cx.mouse_position();
if !cx.has_active_drag() { if !cx.has_active_drag() {
if let Some(group_hover) = self.group_hover_style.as_ref() { 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) if group_bounds.contains(&mouse_position)
&& cx.was_top_layer(&mouse_position, cx.stacking_order()) && cx.was_top_layer(&mouse_position, cx.stacking_order())
{ {
@ -1944,13 +1951,13 @@ impl Interactivity {
if let Some(drag) = cx.active_drag.take() { if let Some(drag) = cx.active_drag.take() {
let mut can_drop = true; let mut can_drop = true;
if let Some(can_drop_predicate) = &self.can_drop_predicate { 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 { if can_drop {
for (state_type, group_drag_style) in &self.group_drag_over_styles { for (state_type, group_drag_style) in &self.group_drag_over_styles {
if let Some(group_bounds) = 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() if *state_type == drag.value.as_ref().type_id()
&& group_bounds.contains(&mouse_position) && group_bounds.contains(&mouse_position)
@ -2096,12 +2103,12 @@ where
fn request_layout( fn request_layout(
&mut self, &mut self,
state: Option<Self::State>, state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
self.element.request_layout(state, cx) 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) self.element.paint(bounds, state, cx)
} }
} }
@ -2171,12 +2178,12 @@ where
fn request_layout( fn request_layout(
&mut self, &mut self,
state: Option<Self::State>, state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
self.element.request_layout(state, cx) 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) self.element.paint(bounds, state, cx)
} }
} }

View file

@ -1,9 +1,9 @@
use std::sync::Arc; use std::sync::Arc;
use crate::{ 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, InteractiveElementState, Interactivity, IntoElement, LayoutId, Pixels, SharedUrl, Size,
StyleRefinement, Styled, WindowContext, StyleRefinement, Styled,
}; };
use futures::FutureExt; use futures::FutureExt;
use media::core_video::CVImageBuffer; use media::core_video::CVImageBuffer;
@ -81,7 +81,7 @@ impl Element for Img {
fn request_layout( fn request_layout(
&mut self, &mut self,
element_state: Option<Self::State>, element_state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
self.interactivity self.interactivity
.layout(element_state, cx, |style, cx| cx.request_layout(&style, [])) .layout(element_state, cx, |style, cx| cx.request_layout(&style, []))
@ -91,7 +91,7 @@ impl Element for Img {
&mut self, &mut self,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
element_state: &mut Self::State, element_state: &mut Self::State,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let source = self.source.clone(); let source = self.source.clone();
self.interactivity.paint( self.interactivity.paint(

View file

@ -7,9 +7,9 @@
//! If all of your elements are the same height, see [`UniformList`] for a simpler API //! If all of your elements are the same height, see [`UniformList`] for a simpler API
use crate::{ use crate::{
point, px, AnyElement, AvailableSpace, BorrowAppContext, BorrowWindow, Bounds, ContentMask, point, px, AnyElement, AvailableSpace, Bounds, ContentMask, DispatchPhase, Element,
DispatchPhase, Element, IntoElement, Pixels, Point, ScrollWheelEvent, Size, Style, IntoElement, Pixels, Point, ScrollWheelEvent, Size, Style, StyleRefinement, Styled,
StyleRefinement, Styled, WindowContext, WindowContext,
}; };
use collections::VecDeque; use collections::VecDeque;
use refineable::Refineable as _; use refineable::Refineable as _;
@ -359,7 +359,7 @@ impl Element for List {
fn request_layout( fn request_layout(
&mut self, &mut self,
_state: Option<Self::State>, _state: Option<Self::State>,
cx: &mut crate::WindowContext, cx: &mut crate::ElementContext,
) -> (crate::LayoutId, Self::State) { ) -> (crate::LayoutId, Self::State) {
let mut style = Style::default(); let mut style = Style::default();
style.refine(&self.style); style.refine(&self.style);
@ -373,7 +373,7 @@ impl Element for List {
&mut self, &mut self,
bounds: Bounds<crate::Pixels>, bounds: Bounds<crate::Pixels>,
_state: &mut Self::State, _state: &mut Self::State,
cx: &mut crate::WindowContext, cx: &mut crate::ElementContext,
) { ) {
let state = &mut *self.state.0.borrow_mut(); let state = &mut *self.state.0.borrow_mut();

View file

@ -2,8 +2,8 @@ use smallvec::SmallVec;
use taffy::style::{Display, Position}; use taffy::style::{Display, Position};
use crate::{ use crate::{
point, AnyElement, BorrowWindow, Bounds, Element, IntoElement, LayoutId, ParentElement, Pixels, point, AnyElement, Bounds, Element, ElementContext, IntoElement, LayoutId, ParentElement,
Point, Size, Style, WindowContext, Pixels, Point, Size, Style,
}; };
/// The state that the overlay element uses to track its children. /// The state that the overlay element uses to track its children.
@ -74,7 +74,7 @@ impl Element for Overlay {
fn request_layout( fn request_layout(
&mut self, &mut self,
_: Option<Self::State>, _: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (crate::LayoutId, Self::State) { ) -> (crate::LayoutId, Self::State) {
let child_layout_ids = self let child_layout_ids = self
.children .children
@ -97,7 +97,7 @@ impl Element for Overlay {
&mut self, &mut self,
bounds: crate::Bounds<crate::Pixels>, bounds: crate::Bounds<crate::Pixels>,
element_state: &mut Self::State, element_state: &mut Self::State,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
if element_state.child_layout_ids.is_empty() { if element_state.child_layout_ids.is_empty() {
return; return;

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
Bounds, Element, ElementId, InteractiveElement, InteractiveElementState, Interactivity, Bounds, Element, ElementContext, ElementId, InteractiveElement, InteractiveElementState,
IntoElement, LayoutId, Pixels, SharedString, StyleRefinement, Styled, WindowContext, Interactivity, IntoElement, LayoutId, Pixels, SharedString, StyleRefinement, Styled,
}; };
use util::ResultExt; use util::ResultExt;
@ -32,7 +32,7 @@ impl Element for Svg {
fn request_layout( fn request_layout(
&mut self, &mut self,
element_state: Option<Self::State>, element_state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
self.interactivity.layout(element_state, cx, |style, cx| { self.interactivity.layout(element_state, cx, |style, cx| {
cx.request_layout(&style, None) cx.request_layout(&style, None)
@ -43,7 +43,7 @@ impl Element for Svg {
&mut self, &mut self,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
element_state: &mut Self::State, element_state: &mut Self::State,
cx: &mut WindowContext, cx: &mut ElementContext,
) where ) where
Self: Sized, Self: Sized,
{ {

View file

@ -1,7 +1,8 @@
use crate::{ use crate::{
ActiveTooltip, AnyTooltip, AnyView, Bounds, DispatchPhase, Element, ElementId, HighlightStyle, ActiveTooltip, AnyTooltip, AnyView, Bounds, DispatchPhase, Element, ElementContext, ElementId,
IntoElement, LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, HighlightStyle, IntoElement, LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
SharedString, Size, TextRun, TextStyle, WhiteSpace, WindowContext, WrappedLine, TOOLTIP_DELAY, Point, SharedString, Size, TextRun, TextStyle, WhiteSpace, WindowContext, WrappedLine,
TOOLTIP_DELAY,
}; };
use anyhow::anyhow; use anyhow::anyhow;
use parking_lot::{Mutex, MutexGuard}; use parking_lot::{Mutex, MutexGuard};
@ -21,14 +22,14 @@ impl Element for &'static str {
fn request_layout( fn request_layout(
&mut self, &mut self,
_: Option<Self::State>, _: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
let mut state = TextState::default(); let mut state = TextState::default();
let layout_id = state.layout(SharedString::from(*self), None, cx); let layout_id = state.layout(SharedString::from(*self), None, cx);
(layout_id, state) (layout_id, state)
} }
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) state.paint(bounds, self, cx)
} }
} }
@ -51,14 +52,14 @@ impl Element for SharedString {
fn request_layout( fn request_layout(
&mut self, &mut self,
_: Option<Self::State>, _: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
let mut state = TextState::default(); let mut state = TextState::default();
let layout_id = state.layout(self.clone(), None, cx); let layout_id = state.layout(self.clone(), None, cx);
(layout_id, state) (layout_id, state)
} }
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(); let text_str: &str = self.as_ref();
state.paint(bounds, text_str, cx) state.paint(bounds, text_str, cx)
} }
@ -130,14 +131,14 @@ impl Element for StyledText {
fn request_layout( fn request_layout(
&mut self, &mut self,
_: Option<Self::State>, _: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
let mut state = TextState::default(); let mut state = TextState::default();
let layout_id = state.layout(self.text.clone(), self.runs.take(), cx); let layout_id = state.layout(self.text.clone(), self.runs.take(), cx);
(layout_id, state) (layout_id, state)
} }
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) state.paint(bounds, &self.text, cx)
} }
} }
@ -174,7 +175,7 @@ impl TextState {
&mut self, &mut self,
text: SharedString, text: SharedString,
runs: Option<Vec<TextRun>>, runs: Option<Vec<TextRun>>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> LayoutId { ) -> LayoutId {
let text_style = cx.text_style(); let text_style = cx.text_style();
let font_size = text_style.font_size.to_pixels(cx.rem_size()); let font_size = text_style.font_size.to_pixels(cx.rem_size());
@ -249,7 +250,7 @@ impl TextState {
layout_id 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 = self.lock();
let element_state = element_state let element_state = element_state
.as_ref() .as_ref()
@ -377,7 +378,7 @@ impl Element for InteractiveText {
fn request_layout( fn request_layout(
&mut self, &mut self,
state: Option<Self::State>, state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
if let Some(InteractiveTextState { if let Some(InteractiveTextState {
mouse_down_index, 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() { if let Some(click_listener) = self.click_listener.take() {
let mouse_position = cx.mouse_position(); let mouse_position = cx.mouse_position();
if let Some(ix) = state.text_state.index_for_position(bounds, mouse_position) { if let Some(ix) = state.text_state.index_for_position(bounds, mouse_position) {

View file

@ -5,7 +5,7 @@
//! elements with uniform height. //! elements with uniform height.
use crate::{ 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, ElementId, InteractiveElement, InteractiveElementState, Interactivity, IntoElement, LayoutId,
Pixels, Render, Size, StyleRefinement, Styled, View, ViewContext, WindowContext, Pixels, Render, Size, StyleRefinement, Styled, View, ViewContext, WindowContext,
}; };
@ -110,7 +110,7 @@ impl Element for UniformList {
fn request_layout( fn request_layout(
&mut self, &mut self,
state: Option<Self::State>, state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
let max_items = self.item_count; let max_items = self.item_count;
let item_size = state let item_size = state
@ -158,7 +158,7 @@ impl Element for UniformList {
&mut self, &mut self,
bounds: Bounds<crate::Pixels>, bounds: Bounds<crate::Pixels>,
element_state: &mut Self::State, element_state: &mut Self::State,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let style = let style =
self.interactivity self.interactivity
@ -280,7 +280,7 @@ impl UniformList {
self 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 { if self.item_count == 0 {
return Size::default(); return Size::default();
} }

View file

@ -220,11 +220,6 @@ pub trait EventEmitter<E: Any>: 'static {}
/// A helper trait for auto-implementing certain methods on contexts that /// A helper trait for auto-implementing certain methods on contexts that
/// can be used interchangeably. /// can be used interchangeably.
pub trait BorrowAppContext { 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. /// Set a global value on the context.
fn set_global<T: 'static>(&mut self, global: T); fn set_global<T: 'static>(&mut self, global: T);
} }
@ -233,20 +228,6 @@ impl<C> BorrowAppContext for C
where where
C: BorrowMut<AppContext>, 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) { fn set_global<G: 'static>(&mut self, global: G) {
self.borrow_mut().set_global(global) self.borrow_mut().set_global(global)
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
Action, ActionRegistry, DispatchPhase, EntityId, FocusId, KeyBinding, KeyContext, KeyMatch, Action, ActionRegistry, DispatchPhase, ElementContext, EntityId, FocusId, KeyBinding,
Keymap, Keystroke, KeystrokeMatcher, WindowContext, KeyContext, KeyMatch, Keymap, Keystroke, KeystrokeMatcher, WindowContext,
}; };
use collections::FxHashMap; use collections::FxHashMap;
use parking_lot::Mutex; use parking_lot::Mutex;
@ -36,7 +36,7 @@ pub(crate) struct DispatchNode {
parent: Option<DispatchNodeId>, 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)] #[derive(Clone)]
pub(crate) struct DispatchActionListener { pub(crate) struct DispatchActionListener {

View file

@ -1,10 +1,10 @@
use std::{iter, mem, ops::Range}; use std::{iter, mem, ops::Range};
use crate::{ use crate::{
black, phi, point, quad, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, black, phi, point, quad, rems, AbsoluteLength, BorrowAppContext, Bounds, ContentMask, Corners,
ContentMask, Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, ElementContext, Font,
Font, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba,
SharedString, Size, SizeRefinement, Styled, TextRun, WindowContext, SharedString, Size, SizeRefinement, Styled, TextRun,
}; };
use collections::HashSet; use collections::HashSet;
use refineable::{Cascade, Refineable}; 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. /// Paints the background of an element styled with this style.
pub fn paint( pub fn paint(
&self, &self,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
cx: &mut WindowContext, cx: &mut ElementContext,
continuation: impl FnOnce(&mut WindowContext), continuation: impl FnOnce(&mut ElementContext),
) { ) {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
if self.debug_below { if self.debug_below {

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
black, fill, point, px, size, BorrowWindow, Bounds, Hsla, LineLayout, Pixels, Point, Result, black, fill, point, px, size, Bounds, ElementContext, Hsla, LineLayout, Pixels, Point, Result,
SharedString, UnderlineStyle, WindowContext, WrapBoundary, WrappedLineLayout, SharedString, UnderlineStyle, WrapBoundary, WrappedLineLayout,
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -33,7 +33,7 @@ impl ShapedLine {
&self, &self,
origin: Point<Pixels>, origin: Point<Pixels>,
line_height: Pixels, line_height: Pixels,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> Result<()> { ) -> Result<()> {
paint_line( paint_line(
origin, origin,
@ -66,7 +66,7 @@ impl WrappedLine {
&self, &self,
origin: Point<Pixels>, origin: Point<Pixels>,
line_height: Pixels, line_height: Pixels,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> Result<()> { ) -> Result<()> {
paint_line( paint_line(
origin, origin,
@ -87,7 +87,7 @@ fn paint_line(
line_height: Pixels, line_height: Pixels,
decoration_runs: &[DecorationRun], decoration_runs: &[DecorationRun],
wrap_boundaries: &[WrapBoundary], wrap_boundaries: &[WrapBoundary],
cx: &mut WindowContext<'_>, cx: &mut ElementContext<'_>,
) -> Result<()> { ) -> Result<()> {
let padding_top = (line_height - layout.ascent - layout.descent) / 2.; let padding_top = (line_height - layout.ascent - layout.descent) / 2.;
let baseline_offset = point(px(0.), padding_top + layout.ascent); let baseline_offset = point(px(0.), padding_top + layout.ascent);

View file

@ -1,8 +1,8 @@
use crate::{ use crate::{
seal::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, BorrowWindow, seal::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace, Bounds,
Bounds, ContentMask, Element, ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView, ContentMask, Element, ElementContext, ElementId, Entity, EntityId, Flatten, FocusHandle,
IntoElement, LayoutId, Model, Pixels, Point, Render, Size, StackingOrder, Style, TextStyle, FocusableView, IntoElement, LayoutId, Model, Pixels, Point, Render, Size, StackingOrder, Style,
ViewContext, VisualContext, WeakModel, WindowContext, TextStyle, ViewContext, VisualContext, WeakModel,
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use std::{ use std::{
@ -94,7 +94,7 @@ impl<V: Render> Element for View<V> {
fn request_layout( fn request_layout(
&mut self, &mut self,
_state: Option<Self::State>, _state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
cx.with_view_id(self.entity_id(), |cx| { cx.with_view_id(self.entity_id(), |cx| {
let mut element = self.update(cx, |view, cx| view.render(cx).into_any_element()); 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)); 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)] #[derive(Clone, Debug)]
pub struct AnyView { pub struct AnyView {
model: AnyModel, model: AnyModel,
request_layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement), request_layout: fn(&AnyView, &mut ElementContext) -> (LayoutId, AnyElement),
cache: bool, cache: bool,
} }
@ -250,7 +250,7 @@ impl AnyView {
&self, &self,
origin: Point<Pixels>, origin: Point<Pixels>,
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
cx.paint_view(self.entity_id(), |cx| { cx.paint_view(self.entity_id(), |cx| {
cx.with_absolute_element_offset(origin, |cx| { cx.with_absolute_element_offset(origin, |cx| {
@ -278,7 +278,7 @@ impl Element for AnyView {
fn request_layout( fn request_layout(
&mut self, &mut self,
state: Option<Self::State>, state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
cx.with_view_id(self.entity_id(), |cx| { cx.with_view_id(self.entity_id(), |cx| {
if self.cache { 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| { cx.paint_view(self.entity_id(), |cx| {
if !self.cache { if !self.cache {
state.element.take().unwrap().paint(cx); 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. /// A weak, dynamically-typed view handle that does not prevent the view from being released.
pub struct AnyWeakView { pub struct AnyWeakView {
model: AnyWeakModel, model: AnyWeakModel,
layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement), layout: fn(&AnyView, &mut ElementContext) -> (LayoutId, AnyElement),
} }
impl AnyWeakView { impl AnyWeakView {
@ -402,11 +402,11 @@ impl std::fmt::Debug for AnyWeakView {
} }
mod any_view { 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>( pub(crate) fn request_layout<V: 'static + Render>(
view: &AnyView, view: &AnyView,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, AnyElement) { ) -> (LayoutId, AnyElement) {
let view = view.clone().downcast::<V>().unwrap(); let view = view.clone().downcast::<V>().unwrap();
let mut element = view.update(cx, |view, cx| view.render(cx).into_any_element()); let mut element = view.update(cx, |view, cx| view.render(cx).into_any_element());

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,11 @@
use editor::{Cursor, HighlightedRange, HighlightedRangeLine}; use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
use gpui::{ use gpui::{
div, fill, point, px, relative, AnyElement, AvailableSpace, BorrowWindow, Bounds, div, fill, point, px, relative, AnyElement, AvailableSpace, Bounds, DispatchPhase, Element,
DispatchPhase, Element, ElementId, FocusHandle, Font, FontStyle, FontWeight, HighlightStyle, ElementContext, ElementId, FocusHandle, Font, FontStyle, FontWeight, HighlightStyle, Hsla,
Hsla, InputHandler, InteractiveBounds, InteractiveElement, InteractiveElementState, InputHandler, InteractiveBounds, InteractiveElement, InteractiveElementState, Interactivity,
Interactivity, IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, MouseMoveEvent,
MouseMoveEvent, Pixels, Point, ShapedLine, StatefulInteractiveElement, Styled, TextRun, Pixels, Point, ShapedLine, StatefulInteractiveElement, Styled, TextRun, TextStyle, TextSystem,
TextStyle, TextSystem, UnderlineStyle, WeakView, WhiteSpace, WindowContext, UnderlineStyle, WeakView, WhiteSpace, WindowContext,
}; };
use itertools::Itertools; use itertools::Itertools;
use language::CursorShape; use language::CursorShape;
@ -81,7 +81,7 @@ impl LayoutCell {
origin: Point<Pixels>, origin: Point<Pixels>,
layout: &LayoutState, layout: &LayoutState,
_visible_bounds: Bounds<Pixels>, _visible_bounds: Bounds<Pixels>,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let pos = { let pos = {
let point = self.point; 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 position = {
let alac_point = self.point; let alac_point = self.point;
point( point(
@ -365,7 +365,7 @@ impl TerminalElement {
result 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 settings = ThemeSettings::get_global(cx).clone();
let buffer_font_size = settings.buffer_font_size(cx); let buffer_font_size = settings.buffer_font_size(cx);
@ -590,7 +590,7 @@ impl TerminalElement {
origin: Point<Pixels>, origin: Point<Pixels>,
mode: TermMode, mode: TermMode,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let focus = self.focus.clone(); let focus = self.focus.clone();
let terminal = self.terminal.clone(); let terminal = self.terminal.clone();
@ -722,7 +722,7 @@ impl Element for TerminalElement {
fn request_layout( fn request_layout(
&mut self, &mut self,
element_state: Option<Self::State>, element_state: Option<Self::State>,
cx: &mut WindowContext<'_>, cx: &mut ElementContext<'_>,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
let (layout_id, interactive_state) = let (layout_id, interactive_state) =
self.interactivity self.interactivity
@ -741,7 +741,7 @@ impl Element for TerminalElement {
&mut self, &mut self,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
state: &mut Self::State, state: &mut Self::State,
cx: &mut WindowContext<'_>, cx: &mut ElementContext<'_>,
) { ) {
let mut layout = self.compute_layout(bounds, cx); let mut layout = self.compute_layout(bounds, cx);

View file

@ -2,8 +2,9 @@ use std::{cell::RefCell, rc::Rc};
use gpui::{ use gpui::{
overlay, point, prelude::FluentBuilder, px, rems, AnchorCorner, AnyElement, Bounds, overlay, point, prelude::FluentBuilder, px, rems, AnchorCorner, AnyElement, Bounds,
DismissEvent, DispatchPhase, Element, ElementId, InteractiveBounds, IntoElement, LayoutId, DismissEvent, DispatchPhase, Element, ElementContext, ElementId, InteractiveBounds,
ManagedView, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext, WindowContext, IntoElement, LayoutId, ManagedView, MouseDownEvent, ParentElement, Pixels, Point, View,
VisualContext, WindowContext,
}; };
use crate::{Clickable, Selectable}; use crate::{Clickable, Selectable};
@ -134,7 +135,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
fn request_layout( fn request_layout(
&mut self, &mut self,
element_state: Option<Self::State>, element_state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (gpui::LayoutId, Self::State) { ) -> (gpui::LayoutId, Self::State) {
let mut menu_layout_id = None; let mut menu_layout_id = None;
@ -188,7 +189,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
&mut self, &mut self,
_: Bounds<gpui::Pixels>, _: Bounds<gpui::Pixels>,
element_state: &mut Self::State, element_state: &mut Self::State,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
if let Some(mut child) = element_state.child_element.take() { if let Some(mut child) = element_state.child_element.take() {
child.paint(cx); child.paint(cx);

View file

@ -1,9 +1,9 @@
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use gpui::{ use gpui::{
overlay, AnchorCorner, AnyElement, BorrowWindow, Bounds, DismissEvent, DispatchPhase, Element, overlay, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase, Element,
ElementId, InteractiveBounds, IntoElement, LayoutId, ManagedView, MouseButton, MouseDownEvent, ElementContext, ElementId, InteractiveBounds, IntoElement, LayoutId, ManagedView, MouseButton,
ParentElement, Pixels, Point, View, VisualContext, WindowContext, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext, WindowContext,
}; };
pub struct RightClickMenu<M: ManagedView> { pub struct RightClickMenu<M: ManagedView> {
@ -64,7 +64,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
fn request_layout( fn request_layout(
&mut self, &mut self,
element_state: Option<Self::State>, element_state: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (gpui::LayoutId, Self::State) { ) -> (gpui::LayoutId, Self::State) {
let (menu, position) = if let Some(element_state) = element_state { let (menu, position) = if let Some(element_state) = element_state {
(element_state.menu, element_state.position) (element_state.menu, element_state.position)
@ -116,7 +116,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
&mut self, &mut self,
bounds: Bounds<gpui::Pixels>, bounds: Bounds<gpui::Pixels>,
element_state: &mut Self::State, element_state: &mut Self::State,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
if let Some(mut child) = element_state.child_element.take() { if let Some(mut child) = element_state.child_element.take() {
child.paint(cx); child.paint(cx);

View file

@ -2,9 +2,9 @@
pub use gpui::prelude::*; pub use gpui::prelude::*;
pub use gpui::{ pub use gpui::{
div, px, relative, rems, AbsoluteLength, DefiniteLength, Div, Element, ElementId, div, px, relative, rems, AbsoluteLength, DefiniteLength, Div, Element, ElementContext,
InteractiveElement, ParentElement, Pixels, Rems, RenderOnce, SharedString, Styled, ViewContext, ElementId, InteractiveElement, ParentElement, Pixels, Rems, RenderOnce, SharedString, Styled,
WindowContext, ViewContext, WindowContext,
}; };
pub use crate::clickable::*; pub use crate::clickable::*;

View file

@ -710,7 +710,7 @@ mod element {
pane_bounds: Bounds<Pixels>, pane_bounds: Bounds<Pixels>,
axis_bounds: Bounds<Pixels>, axis_bounds: Bounds<Pixels>,
workspace: WeakView<Workspace>, workspace: WeakView<Workspace>,
cx: &mut WindowContext, cx: &mut ElementContext,
) { ) {
let handle_bounds = Bounds { let handle_bounds = Bounds {
origin: pane_bounds.origin.apply_along(axis, |origin| { origin: pane_bounds.origin.apply_along(axis, |origin| {
@ -803,7 +803,7 @@ mod element {
fn request_layout( fn request_layout(
&mut self, &mut self,
state: Option<Self::State>, state: Option<Self::State>,
cx: &mut ui::prelude::WindowContext, cx: &mut ui::prelude::ElementContext,
) -> (gpui::LayoutId, Self::State) { ) -> (gpui::LayoutId, Self::State) {
let mut style = Style::default(); let mut style = Style::default();
style.flex_grow = 1.; style.flex_grow = 1.;
@ -820,7 +820,7 @@ mod element {
&mut self, &mut self,
bounds: gpui::Bounds<ui::prelude::Pixels>, bounds: gpui::Bounds<ui::prelude::Pixels>,
state: &mut Self::State, state: &mut Self::State,
cx: &mut ui::prelude::WindowContext, cx: &mut ui::prelude::ElementContext,
) { ) {
let flexes = self.flexes.lock().clone(); let flexes = self.flexes.lock().clone();
let len = self.children.len(); let len = self.children.len();

View file

@ -26,12 +26,12 @@ use futures::{
}; };
use gpui::{ use gpui::{
actions, canvas, div, impl_actions, point, px, size, Action, AnyElement, AnyModel, AnyView, actions, canvas, div, impl_actions, point, px, size, Action, AnyElement, AnyModel, AnyView,
AnyWeakView, AppContext, AsyncAppContext, AsyncWindowContext, BorrowWindow, Bounds, Context, AnyWeakView, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Context, Div,
Div, DragMoveEvent, Element, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, DragMoveEvent, Element, ElementContext, Entity, EntityId, EventEmitter, FocusHandle,
GlobalPixels, InteractiveElement, IntoElement, KeyContext, LayoutId, ManagedView, Model, FocusableView, GlobalPixels, InteractiveElement, IntoElement, KeyContext, LayoutId,
ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel, Render, Size, ManagedView, Model, ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel,
Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds, Render, Size, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView,
WindowContext, WindowHandle, WindowOptions, WindowBounds, WindowContext, WindowHandle, WindowOptions,
}; };
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem}; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
use itertools::Itertools; use itertools::Itertools;
@ -3539,9 +3539,14 @@ impl Render for Workspace {
.border_b() .border_b()
.border_color(colors.border) .border_color(colors.border)
.child( .child(
canvas(cx.listener(|workspace, bounds, _| { canvas({
workspace.bounds = *bounds; let this = cx.view().clone();
})) move |bounds, cx| {
this.update(cx, |this, _cx| {
this.bounds = *bounds;
})
}
})
.absolute() .absolute()
.size_full(), .size_full(),
) )
@ -4293,7 +4298,7 @@ impl Element for DisconnectedOverlay {
fn request_layout( fn request_layout(
&mut self, &mut self,
_: Option<Self::State>, _: Option<Self::State>,
cx: &mut WindowContext, cx: &mut ElementContext,
) -> (LayoutId, Self::State) { ) -> (LayoutId, Self::State) {
let mut background = cx.theme().colors().elevated_surface_background; let mut background = cx.theme().colors().elevated_surface_background;
background.fade_out(0.2); background.fade_out(0.2);
@ -4315,7 +4320,12 @@ impl Element for DisconnectedOverlay {
(overlay.request_layout(cx), overlay) (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.with_z_index(u8::MAX, |cx| {
cx.add_opaque_layer(bounds); cx.add_opaque_layer(bounds);
overlay.paint(cx); overlay.paint(cx);