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)> {
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, ..

View file

@ -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
}
}

View file

@ -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);
.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);
}
})
}
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()

View file

@ -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();

View file

@ -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();

View file

@ -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,
) {
}
}

View file

@ -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)
});

View file

@ -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)
}
}

View file

@ -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(

View file

@ -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();

View file

@ -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;

View file

@ -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,
{

View file

@ -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) {

View file

@ -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();
}

View file

@ -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)
}

View file

@ -1,6 +1,6 @@
use crate::{
Action, ActionRegistry, DispatchPhase, EntityId, FocusId, KeyBinding, KeyContext, KeyMatch,
Keymap, Keystroke, KeystrokeMatcher, WindowContext,
Action, ActionRegistry, DispatchPhase, ElementContext, EntityId, FocusId, KeyBinding,
KeyContext, KeyMatch, Keymap, 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 {

View file

@ -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 {

View file

@ -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);

View file

@ -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());

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 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);

View file

@ -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);

View file

@ -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);

View file

@ -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::*;

View file

@ -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();

View file

@ -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);