From bfbbec0b019c26d73ab03b4cb363c3d44aa23e63 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 13 Dec 2023 13:21:48 -0800 Subject: [PATCH 1/8] Add fluent quad API --- crates/collab_ui2/src/collab_panel.rs | 26 ++-- crates/editor2/src/element.rs | 104 +++++---------- crates/gpui2/src/geometry.rs | 33 +++++ crates/gpui2/src/style.rs | 10 +- crates/gpui2/src/text_system/line.rs | 26 ++-- crates/gpui2/src/window.rs | 124 ++++++++++++++---- crates/terminal_view2/src/terminal_element.rs | 24 +--- 7 files changed, 196 insertions(+), 151 deletions(-) diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index ac7457abe087954b918e6253428223837b0ca828..cd7b2b9e9de061857f9e4f4ee6878da9acfecfeb 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -175,12 +175,12 @@ use editor::Editor; use feature_flags::{ChannelsAlpha, FeatureFlagAppExt, FeatureFlagViewExt}; use fuzzy::{match_strings, StringMatchCandidate}; use gpui::{ - actions, canvas, div, img, impl_actions, overlay, point, prelude::*, px, rems, serde_json, - size, Action, AppContext, AsyncWindowContext, Bounds, ClipboardItem, DismissEvent, Div, - EventEmitter, FocusHandle, Focusable, FocusableView, Hsla, InteractiveElement, IntoElement, - Length, Model, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Quad, Render, - RenderOnce, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, View, - ViewContext, VisualContext, WeakView, + actions, canvas, div, fill, img, impl_actions, overlay, point, prelude::*, px, rems, + serde_json, size, Action, AppContext, AsyncWindowContext, Bounds, ClipboardItem, DismissEvent, + Div, EventEmitter, FocusHandle, Focusable, FocusableView, Hsla, InteractiveElement, + IntoElement, Length, Model, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Quad, + Render, RenderOnce, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, + View, ViewContext, VisualContext, WeakView, }; use project::{Fs, Project}; use serde_derive::{Deserialize, Serialize}; @@ -2994,7 +2994,7 @@ fn render_tree_branch(is_last: bool, cx: &mut WindowContext) -> impl IntoElement let right = bounds.right(); let top = bounds.top(); - cx.paint_quad( + cx.paint_quad(fill( Bounds::from_corners( point(start_x, top), point( @@ -3002,18 +3002,12 @@ fn render_tree_branch(is_last: bool, cx: &mut WindowContext) -> impl IntoElement if is_last { start_y } else { bounds.bottom() }, ), ), - Default::default(), color, - Default::default(), - Hsla::transparent_black(), - ); - cx.paint_quad( + )); + cx.paint_quad(fill( Bounds::from_corners(point(start_x, start_y), point(right, start_y + thickness)), - Default::default(), color, - Default::default(), - Hsla::transparent_black(), - ); + )); }) .w(width) .h(line_height) diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index 307a95b70ac72ca7cb8062a3d892c5ecfb647555..2b6db125daed950c21536d876d0b22add51a5ec0 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -23,13 +23,14 @@ use anyhow::Result; use collections::{BTreeMap, HashMap}; use git::diff::DiffHunkStatus; use gpui::{ - div, overlay, point, px, relative, size, transparent_black, Action, AnchorCorner, AnyElement, - AsyncWindowContext, AvailableSpace, BorrowWindow, Bounds, ContentMask, Corners, CursorStyle, - DispatchPhase, Edges, Element, ElementId, ElementInputHandler, Entity, EntityId, Hsla, - InteractiveBounds, InteractiveElement, IntoElement, LineLayout, ModifiersChangedEvent, - MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, RenderOnce, - ScrollWheelEvent, ShapedLine, SharedString, Size, StackingOrder, StatefulInteractiveElement, - Style, Styled, TextRun, TextStyle, View, ViewContext, WeakView, WindowContext, WrappedLine, + div, fill, outline, overlay, point, px, quad, relative, size, transparent_black, Action, + AnchorCorner, AnyElement, AsyncWindowContext, AvailableSpace, BorrowWindow, Bounds, + ContentMask, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementId, + ElementInputHandler, Entity, EntityId, Hsla, InteractiveBounds, InteractiveElement, + IntoElement, LineLayout, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, + MouseUpEvent, ParentElement, Pixels, RenderOnce, ScrollWheelEvent, ShapedLine, SharedString, + Size, StackingOrder, StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, View, + ViewContext, WeakView, WindowContext, WrappedLine, }; use itertools::Itertools; use language::{language_settings::ShowWhitespaceSetting, Language}; @@ -620,20 +621,8 @@ impl EditorElement { let scroll_top = layout.position_map.snapshot.scroll_position().y * layout.position_map.line_height; let gutter_bg = cx.theme().colors().editor_gutter_background; - cx.paint_quad( - gutter_bounds, - Corners::default(), - gutter_bg, - Edges::default(), - transparent_black(), - ); - cx.paint_quad( - text_bounds, - Corners::default(), - self.style.background, - Edges::default(), - transparent_black(), - ); + cx.paint_quad(fill(gutter_bounds, gutter_bg)); + cx.paint_quad(fill(text_bounds, self.style.background)); if let EditorMode::Full = layout.mode { let mut active_rows = layout.active_rows.iter().peekable(); @@ -657,13 +646,7 @@ impl EditorElement { layout.position_map.line_height * (end_row - start_row + 1) as f32, ); let active_line_bg = cx.theme().colors().editor_active_line_background; - cx.paint_quad( - Bounds { origin, size }, - Corners::default(), - active_line_bg, - Edges::default(), - transparent_black(), - ); + cx.paint_quad(fill(Bounds { origin, size }, active_line_bg)); } } @@ -679,13 +662,7 @@ impl EditorElement { layout.position_map.line_height * highlighted_rows.len() as f32, ); let highlighted_line_bg = cx.theme().colors().editor_highlighted_line_background; - cx.paint_quad( - Bounds { origin, size }, - Corners::default(), - highlighted_line_bg, - Edges::default(), - transparent_black(), - ); + cx.paint_quad(fill(Bounds { origin, size }, highlighted_line_bg)); } let scroll_left = @@ -706,16 +683,13 @@ impl EditorElement { } else { cx.theme().colors().editor_wrap_guide }; - cx.paint_quad( + cx.paint_quad(fill( Bounds { origin: point(x, text_bounds.origin.y), size: size(px(1.), text_bounds.size.height), }, - Corners::default(), color, - Edges::default(), - transparent_black(), - ); + )); } } } @@ -812,13 +786,13 @@ impl EditorElement { let highlight_origin = bounds.origin + point(-width, start_y); let highlight_size = size(width * 2., end_y - start_y); let highlight_bounds = Bounds::new(highlight_origin, highlight_size); - cx.paint_quad( + cx.paint_quad(quad( highlight_bounds, Corners::all(1. * line_height), gpui::yellow(), // todo!("use the right color") Edges::default(), transparent_black(), - ); + )); continue; } @@ -845,13 +819,13 @@ impl EditorElement { let highlight_origin = bounds.origin + point(-width, start_y); let highlight_size = size(width * 2., end_y - start_y); let highlight_bounds = Bounds::new(highlight_origin, highlight_size); - cx.paint_quad( + cx.paint_quad(quad( highlight_bounds, Corners::all(1. * line_height), cx.theme().status().deleted, Edges::default(), transparent_black(), - ); + )); continue; } @@ -867,13 +841,13 @@ impl EditorElement { let highlight_origin = bounds.origin + point(-width, start_y); let highlight_size = size(width * 2., end_y - start_y); let highlight_bounds = Bounds::new(highlight_origin, highlight_size); - cx.paint_quad( + cx.paint_quad(quad( highlight_bounds, Corners::all(0.05 * line_height), color, // todo!("use the right color") Edges::default(), transparent_black(), - ); + )); } } @@ -1278,7 +1252,7 @@ impl EditorElement { let thumb_bounds = Bounds::from_corners(point(left, thumb_top), point(right, thumb_bottom)); if layout.show_scrollbars { - cx.paint_quad( + cx.paint_quad(quad( track_bounds, Corners::default(), cx.theme().colors().scrollbar_track_background, @@ -1289,7 +1263,7 @@ impl EditorElement { left: px(1.), }, cx.theme().colors().scrollbar_track_border, - ); + )); let scrollbar_settings = EditorSettings::get_global(cx).scrollbar; if layout.is_singleton && scrollbar_settings.selections { let start_anchor = Anchor::min(); @@ -1309,7 +1283,7 @@ impl EditorElement { end_y = start_y + px(1.); } let bounds = Bounds::from_corners(point(left, start_y), point(right, end_y)); - cx.paint_quad( + cx.paint_quad(quad( bounds, Corners::default(), cx.theme().status().info, @@ -1320,7 +1294,7 @@ impl EditorElement { left: px(1.), }, cx.theme().colors().scrollbar_thumb_border, - ); + )); } } @@ -1352,7 +1326,7 @@ impl EditorElement { DiffHunkStatus::Modified => cx.theme().status().modified, DiffHunkStatus::Removed => cx.theme().status().deleted, }; - cx.paint_quad( + cx.paint_quad(quad( bounds, Corners::default(), color, @@ -1363,11 +1337,11 @@ impl EditorElement { left: px(1.), }, cx.theme().colors().scrollbar_thumb_border, - ); + )); } } - cx.paint_quad( + cx.paint_quad(quad( thumb_bounds, Corners::default(), cx.theme().colors().scrollbar_thumb_background, @@ -1378,7 +1352,7 @@ impl EditorElement { left: px(1.), }, cx.theme().colors().scrollbar_thumb_border, - ); + )); } let mouse_position = cx.mouse_position(); @@ -3085,23 +3059,13 @@ impl Cursor { }; //Draw background or border quad - if matches!(self.shape, CursorShape::Hollow) { - cx.paint_quad( - bounds, - Corners::default(), - transparent_black(), - Edges::all(px(1.)), - self.color, - ); + let cursor = if matches!(self.shape, CursorShape::Hollow) { + outline(bounds, self.color) } else { - cx.paint_quad( - bounds, - Corners::default(), - self.color, - Edges::default(), - transparent_black(), - ); - } + fill(bounds, self.color) + }; + + cx.paint_quad(cursor); if let Some(block_text) = &self.block_text { block_text.paint(self.origin + origin, self.line_height, cx); diff --git a/crates/gpui2/src/geometry.rs b/crates/gpui2/src/geometry.rs index ee2f42d2a284e47e1f35b1f826383e8e889f0708..f58435d7b9a2e9b3fa48062d2e28ed21502c1ca1 100644 --- a/crates/gpui2/src/geometry.rs +++ b/crates/gpui2/src/geometry.rs @@ -1592,6 +1592,17 @@ impl Edges { } } +impl Into> for f32 { + fn into(self) -> Edges { + Edges { + top: self.into(), + right: self.into(), + bottom: self.into(), + left: self.into(), + } + } +} + /// Represents the corners of a box in a 2D space, such as border radius. /// /// Each field represents the size of the corner on one side of the box: `top_left`, `top_right`, `bottom_right`, and `bottom_left`. @@ -1808,6 +1819,28 @@ where impl Copy for Corners where T: Copy + Clone + Default + Debug {} +impl Into> for f32 { + fn into(self) -> Corners { + Corners { + top_left: self.into(), + top_right: self.into(), + bottom_right: self.into(), + bottom_left: self.into(), + } + } +} + +impl Into> for Pixels { + fn into(self) -> Corners { + Corners { + top_left: self, + top_right: self, + bottom_right: self, + bottom_left: self, + } + } +} + /// Represents a length in pixels, the base unit of measurement in the UI framework. /// /// `Pixels` is a value type that represents an absolute length in pixels, which is used diff --git a/crates/gpui2/src/style.rs b/crates/gpui2/src/style.rs index 04f247d07627ac6572fe55724f1eb7b29c76463a..4031a35f75048f980558ab4ce7bf2d09f6049436 100644 --- a/crates/gpui2/src/style.rs +++ b/crates/gpui2/src/style.rs @@ -1,9 +1,9 @@ use std::{iter, mem, ops::Range}; use crate::{ - black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, - Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font, - FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba, + 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, }; use collections::HashSet; @@ -348,13 +348,13 @@ impl Style { let background_color = self.background.as_ref().and_then(Fill::color); if background_color.is_some() || self.is_border_visible() { cx.with_z_index(1, |cx| { - cx.paint_quad( + cx.paint_quad(quad( bounds, self.corner_radii.to_pixels(bounds.size, rem_size), background_color.unwrap_or_default(), self.border_widths.to_pixels(rem_size), self.border_color.unwrap_or_default(), - ); + )); }); } } diff --git a/crates/gpui2/src/text_system/line.rs b/crates/gpui2/src/text_system/line.rs index d62bee69c095139114ecf45561287d6ac218da2a..a58d77f585ef79485fa264d4e57f69c1ee4cb0c8 100644 --- a/crates/gpui2/src/text_system/line.rs +++ b/crates/gpui2/src/text_system/line.rs @@ -1,7 +1,6 @@ use crate::{ - black, point, px, size, transparent_black, BorrowWindow, Bounds, Corners, Edges, Hsla, - LineLayout, Pixels, Point, Result, SharedString, UnderlineStyle, WindowContext, WrapBoundary, - WrappedLineLayout, + black, fill, point, px, size, BorrowWindow, Bounds, Hsla, LineLayout, Pixels, Point, Result, + SharedString, UnderlineStyle, WindowContext, WrapBoundary, WrappedLineLayout, }; use derive_more::{Deref, DerefMut}; use smallvec::SmallVec; @@ -109,16 +108,13 @@ fn paint_line( if wraps.peek() == Some(&&WrapBoundary { run_ix, glyph_ix }) { wraps.next(); if let Some((background_origin, background_color)) = current_background.as_mut() { - cx.paint_quad( + cx.paint_quad(fill( Bounds { origin: *background_origin, size: size(glyph_origin.x - background_origin.x, line_height), }, - Corners::default(), *background_color, - Edges::default(), - transparent_black(), - ); + )); background_origin.x = origin.x; background_origin.y += line_height; } @@ -180,16 +176,13 @@ fn paint_line( } if let Some((background_origin, background_color)) = finished_background { - cx.paint_quad( + cx.paint_quad(fill( Bounds { origin: background_origin, size: size(glyph_origin.x - background_origin.x, line_height), }, - Corners::default(), background_color, - Edges::default(), - transparent_black(), - ); + )); } if let Some((underline_origin, underline_style)) = finished_underline { @@ -235,16 +228,13 @@ fn paint_line( } if let Some((background_origin, background_color)) = current_background.take() { - cx.paint_quad( + cx.paint_quad(fill( Bounds { origin: background_origin, size: size(last_line_end_x - background_origin.x, line_height), }, - Corners::default(), background_color, - Edges::default(), - transparent_black(), - ); + )); } if let Some((underline_start, underline_style)) = current_underline.take() { diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 77eb4e27be20bd734c27258a00fd05eaeff35caf..554a6d6e6bf0ad17b137323a3ab8ddb920927433 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1,15 +1,15 @@ use crate::{ - key_dispatch::DispatchActionListener, px, size, Action, AnyDrag, AnyView, AppContext, - AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle, - DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, - EventEmitter, FileDropEvent, Flatten, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla, - ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, LayoutId, - Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseMoveEvent, MouseUpEvent, - Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, - PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams, - RenderSvgParams, ScaledPixels, Scene, SceneBuilder, Shadow, SharedString, Size, Style, - SubscriberSet, Subscription, Surface, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, - VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS, + key_dispatch::DispatchActionListener, px, size, transparent_black, Action, AnyDrag, AnyView, + AppContext, AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, + CursorStyle, DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, + EntityId, EventEmitter, FileDropEvent, Flatten, FocusEvent, FontId, GlobalElementId, GlyphId, + Hsla, ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, + LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseMoveEvent, + MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, + PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, + RenderImageParams, RenderSvgParams, ScaledPixels, Scene, SceneBuilder, Shadow, SharedString, + Size, Style, SubscriberSet, Subscription, Surface, TaffyLayoutEngine, Task, Underline, + UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::{anyhow, Context as _, Result}; use collections::HashMap; @@ -963,14 +963,8 @@ impl<'a> WindowContext<'a> { /// Paint one or more quads into the scene for the next frame at the current stacking context. /// Quads are colored rectangular regions with an optional background, border, and corner radius. - pub fn paint_quad( - &mut self, - bounds: Bounds, - corner_radii: Corners, - background: impl Into, - border_widths: Edges, - border_color: impl Into, - ) { + /// see [`fill`], [`outline`], and [`quad`] to construct this type. + pub fn paint_quad(&mut self, quad: PaintQuad) { let scale_factor = self.scale_factor(); let content_mask = self.content_mask(); @@ -979,12 +973,12 @@ impl<'a> WindowContext<'a> { &window.next_frame.z_index_stack, Quad { order: 0, - bounds: bounds.scale(scale_factor), + bounds: quad.bounds.scale(scale_factor), content_mask: content_mask.scale(scale_factor), - background: background.into(), - border_color: border_color.into(), - corner_radii: corner_radii.scale(scale_factor), - border_widths: border_widths.scale(scale_factor), + background: quad.background, + border_color: quad.border_color, + corner_radii: quad.corner_radii.scale(scale_factor), + border_widths: quad.border_widths.scale(scale_factor), }, ); } @@ -2962,3 +2956,85 @@ impl From<(&'static str, u64)> for ElementId { ElementId::NamedInteger(name.into(), id as usize) } } + +/// A rectangle, to be rendered on the screen by GPUI at the given position and size. +pub struct PaintQuad { + bounds: Bounds, + corner_radii: Corners, + background: Hsla, + border_widths: Edges, + border_color: Hsla, +} + +impl PaintQuad { + /// Set the corner radii of the quad. + pub fn corner_radii(self, corner_radii: impl Into>) -> Self { + PaintQuad { + corner_radii: corner_radii.into(), + ..self + } + } + + /// Set the border widths of the quad. + pub fn border_widths(self, border_widths: impl Into>) -> Self { + PaintQuad { + border_widths: border_widths.into(), + ..self + } + } + + /// Set the border color of the quad. + pub fn border_color(self, border_color: impl Into) -> Self { + PaintQuad { + border_color: border_color.into(), + ..self + } + } + + /// Set the background color of the quad. + pub fn background(self, background: impl Into) -> Self { + PaintQuad { + background: background.into(), + ..self + } + } +} + +/// Create a quad with the given parameters. +pub fn quad( + bounds: Bounds, + corner_radii: impl Into>, + background: impl Into, + border_widths: impl Into>, + border_color: impl Into, +) -> PaintQuad { + PaintQuad { + bounds, + corner_radii: corner_radii.into(), + background: background.into(), + border_widths: border_widths.into(), + border_color: border_color.into(), + } +} + +/// Create a filled quad with the given bounds and background color. +pub fn fill(bounds: impl Into>, background: impl Into) -> PaintQuad { + PaintQuad { + bounds: bounds.into(), + corner_radii: (0.).into(), + background: background.into(), + border_widths: (0.).into(), + border_color: transparent_black(), + } +} + +/// Create a rectangle outline with the given bounds, border color, and a 1px border width +pub fn outline(bounds: impl Into>, border_color: impl Into) -> PaintQuad { + PaintQuad { + bounds: bounds.into(), + corner_radii: (0.).into(), + background: transparent_black(), + border_widths: (1.).into(), + border_color: border_color.into(), + } +} diff --git a/crates/terminal_view2/src/terminal_element.rs b/crates/terminal_view2/src/terminal_element.rs index 56b5920aecf14c64616dadc6147f7f919372494e..7358f2e1d735bd9170ab2815035d4232c3e4f933 100644 --- a/crates/terminal_view2/src/terminal_element.rs +++ b/crates/terminal_view2/src/terminal_element.rs @@ -1,9 +1,9 @@ use editor::{Cursor, HighlightedRange, HighlightedRangeLine}; use gpui::{ - black, div, point, px, red, relative, transparent_black, AnyElement, AsyncWindowContext, - AvailableSpace, Bounds, DispatchPhase, Element, ElementId, ExternalPaths, FocusHandle, Font, - FontStyle, FontWeight, HighlightStyle, Hsla, InteractiveElement, InteractiveElementState, - IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, Pixels, + black, div, fill, point, px, red, relative, AnyElement, AsyncWindowContext, AvailableSpace, + Bounds, DispatchPhase, Element, ElementId, ExternalPaths, FocusHandle, Font, FontStyle, + FontWeight, HighlightStyle, Hsla, InteractiveElement, InteractiveElementState, IntoElement, + LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, Pixels, PlatformInputHandler, Point, Rgba, ShapedLine, Size, StatefulInteractiveElement, Styled, TextRun, TextStyle, TextSystem, UnderlineStyle, WhiteSpace, WindowContext, }; @@ -133,13 +133,7 @@ impl LayoutRect { ) .into(); - cx.paint_quad( - Bounds::new(position, size), - Default::default(), - self.color, - Default::default(), - transparent_black(), - ); + cx.paint_quad(fill(Bounds::new(position, size), self.color)); } } @@ -775,13 +769,7 @@ impl Element for TerminalElement { let theme = cx.theme(); - cx.paint_quad( - bounds, - Default::default(), - layout.background_color, - Default::default(), - Hsla::default(), - ); + cx.paint_quad(fill(bounds, layout.background_color)); let origin = bounds.origin + Point::new(layout.gutter, px(0.)); let terminal_input_handler = TerminalInputHandler { From a807e798ecb640b53a85a589c3ca344ae028f2bd Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 13 Dec 2023 13:40:19 -0800 Subject: [PATCH 2/8] Add new drag API --- crates/gpui2/src/app.rs | 4 ++ crates/gpui2/src/element.rs | 73 +++++++++--------------- crates/gpui2/src/elements/canvas.rs | 6 +- crates/gpui2/src/elements/div.rs | 37 +++++++++++- crates/gpui2_macros/src/derive_render.rs | 23 ++++++++ crates/gpui2_macros/src/gpui2_macros.rs | 6 ++ crates/workspace2/src/dock.rs | 25 ++------ crates/workspace2/src/workspace2.rs | 51 +++++++---------- 8 files changed, 124 insertions(+), 101 deletions(-) create mode 100644 crates/gpui2_macros/src/derive_render.rs diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 62ce6305ea7303362a5b6fb8889e63e18ca3fd68..18f688f179e34c6a272351a7bcf7cae9e5dc7bd3 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -1138,6 +1138,10 @@ impl AppContext { pub fn has_active_drag(&self) -> bool { self.active_drag.is_some() } + + pub fn active_drag(&self) -> Option { + self.active_drag.as_ref().map(|drag| drag.view.clone()) + } } impl Context for AppContext { diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index 226a477012a025474df2a58c70be56c10ef37fc3..e5ecd195baa14694bc65a15e9102d5cbd56be10a 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -482,48 +482,31 @@ impl IntoElement for AnyElement { } } -// impl Element for Option -// where -// V: 'static, -// E: Element, -// F: FnOnce(&mut V, &mut WindowContext<'_, V>) -> E + 'static, -// { -// type State = Option; - -// fn element_id(&self) -> Option { -// None -// } - -// fn layout( -// &mut self, -// _: Option, -// cx: &mut WindowContext, -// ) -> (LayoutId, Self::State) { -// let render = self.take().unwrap(); -// let mut element = (render)(view_state, cx).into_any(); -// let layout_id = element.layout(view_state, cx); -// (layout_id, Some(element)) -// } - -// fn paint( -// self, -// _bounds: Bounds, -// rendered_element: &mut Self::State, -// cx: &mut WindowContext, -// ) { -// rendered_element.take().unwrap().paint(view_state, cx); -// } -// } - -// impl RenderOnce for Option -// where -// V: 'static, -// E: Element, -// F: FnOnce(&mut V, &mut WindowContext) -> E + 'static, -// { -// type Element = Self; - -// fn render(self) -> Self::Element { -// self -// } -// } +/// The empty element, which renders nothing. +pub type Empty = (); + +impl IntoElement for () { + type Element = Self; + + fn element_id(&self) -> Option { + None + } + + fn into_element(self) -> Self::Element { + self + } +} + +impl Element for () { + type State = (); + + fn layout( + &mut self, + _state: Option, + cx: &mut WindowContext, + ) -> (LayoutId, Self::State) { + (cx.request_layout(&crate::Style::default(), None), ()) + } + + fn paint(self, _bounds: Bounds, _state: &mut Self::State, _cx: &mut WindowContext) {} +} diff --git a/crates/gpui2/src/elements/canvas.rs b/crates/gpui2/src/elements/canvas.rs index 287a3b4b5a38fdc0c7c90c75763bb9a0921dfb7e..b3afd335d41d4544267a9453e8ffedea5c990b18 100644 --- a/crates/gpui2/src/elements/canvas.rs +++ b/crates/gpui2/src/elements/canvas.rs @@ -2,7 +2,7 @@ use refineable::Refineable as _; use crate::{Bounds, Element, IntoElement, Pixels, Style, StyleRefinement, Styled, WindowContext}; -pub fn canvas(callback: impl 'static + FnOnce(Bounds, &mut WindowContext)) -> Canvas { +pub fn canvas(callback: impl 'static + FnOnce(&Bounds, &mut WindowContext)) -> Canvas { Canvas { paint_callback: Box::new(callback), style: StyleRefinement::default(), @@ -10,7 +10,7 @@ pub fn canvas(callback: impl 'static + FnOnce(Bounds, &mut WindowContext } pub struct Canvas { - paint_callback: Box, &mut WindowContext)>, + paint_callback: Box, &mut WindowContext)>, style: StyleRefinement, } @@ -41,7 +41,7 @@ impl Element for Canvas { } fn paint(self, bounds: Bounds, _: &mut (), cx: &mut WindowContext) { - (self.paint_callback)(bounds, cx) + (self.paint_callback)(&bounds, cx) } } diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index a102c71a6fbc1d8d0dbc0b2d984efcbdbc677276..7dfc9bae6a7648f74502387ac041e3c83d61c79b 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -29,6 +29,11 @@ pub struct GroupStyle { pub style: Box, } +pub struct DragMoveEvent { + pub event: MouseMoveEvent, + pub drag: View, +} + pub trait InteractiveElement: Sized { fn interactivity(&mut self) -> &mut Interactivity; @@ -192,6 +197,34 @@ pub trait InteractiveElement: Sized { self } + fn on_drag_move( + mut self, + listener: impl Fn(&DragMoveEvent, &mut WindowContext) + 'static, + ) -> Self + where + W: Render, + { + self.interactivity().mouse_move_listeners.push(Box::new( + move |event, bounds, phase, cx| { + if phase == DispatchPhase::Capture + && bounds.drag_target_contains(&event.position, cx) + { + if let Some(view) = cx.active_drag().and_then(|view| view.downcast::().ok()) + { + (listener)( + &DragMoveEvent { + event: event.clone(), + drag: view, + }, + cx, + ); + } + } + }, + )); + self + } + fn on_scroll_wheel( mut self, listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static, @@ -403,7 +436,7 @@ pub trait StatefulInteractiveElement: InteractiveElement { self } - fn on_drag(mut self, listener: impl Fn(&mut WindowContext) -> View + 'static) -> Self + fn on_drag(mut self, constructor: impl Fn(&mut WindowContext) -> View + 'static) -> Self where Self: Sized, W: 'static + Render, @@ -413,7 +446,7 @@ pub trait StatefulInteractiveElement: InteractiveElement { "calling on_drag more than once on the same element is not supported" ); self.interactivity().drag_listener = Some(Box::new(move |cursor_offset, cx| AnyDrag { - view: listener(cx).into(), + view: constructor(cx).into(), cursor_offset, })); self diff --git a/crates/gpui2_macros/src/derive_render.rs b/crates/gpui2_macros/src/derive_render.rs new file mode 100644 index 0000000000000000000000000000000000000000..3983a572f06ae66bbff7686851bb369840213309 --- /dev/null +++ b/crates/gpui2_macros/src/derive_render.rs @@ -0,0 +1,23 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, DeriveInput}; + +pub fn derive_render(input: TokenStream) -> TokenStream { + let ast = parse_macro_input!(input as DeriveInput); + let type_name = &ast.ident; + let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl(); + + let gen = quote! { + impl #impl_generics gpui::Render for #type_name #type_generics + #where_clause + { + type Element = (); + + fn render(&mut self, _cx: &mut ViewContext) -> Self::Element { + () + } + } + }; + + gen.into() +} diff --git a/crates/gpui2_macros/src/gpui2_macros.rs b/crates/gpui2_macros/src/gpui2_macros.rs index a56d80b86d0ec92c523eb9dcbcb185f4b2d11049..f0cd59908dc6967d3b00e1b0991d2390b61a59e1 100644 --- a/crates/gpui2_macros/src/gpui2_macros.rs +++ b/crates/gpui2_macros/src/gpui2_macros.rs @@ -1,4 +1,5 @@ mod derive_into_element; +mod derive_render; mod register_action; mod style_helpers; mod test; @@ -15,6 +16,11 @@ pub fn derive_into_element(input: TokenStream) -> TokenStream { derive_into_element::derive_into_element(input) } +#[proc_macro_derive(Render)] +pub fn derive_render(input: TokenStream) -> TokenStream { + derive_render::derive_render(input) +} + #[proc_macro] pub fn style_helpers(input: TokenStream) -> TokenStream { style_helpers::style_helpers(input) diff --git a/crates/workspace2/src/dock.rs b/crates/workspace2/src/dock.rs index b656a79a8d32860993b5b65287cb318e30659104..a71b8b4d6f9b652b29ef55f6d32a7ebf2897442a 100644 --- a/crates/workspace2/src/dock.rs +++ b/crates/workspace2/src/dock.rs @@ -1,5 +1,5 @@ +use crate::DraggedDock; use crate::{status_bar::StatusItemView, Workspace}; -use crate::{DockClickReset, DockDragState}; use gpui::{ div, px, Action, AnchorCorner, AnyView, AppContext, Axis, ClickEvent, Div, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, IntoElement, MouseButton, ParentElement, Render, @@ -493,27 +493,10 @@ impl Render for Dock { let handler = div() .id("resize-handle") .bg(cx.theme().colors().border) - .on_mouse_down(gpui::MouseButton::Left, move |_, cx| { - cx.update_global(|drag: &mut DockDragState, cx| drag.0 = Some(position)) - }) + .on_drag(move |cx| cx.build_view(|_| DraggedDock(position))) .on_click(cx.listener(|v, e: &ClickEvent, cx| { - if e.down.button == MouseButton::Left { - cx.update_global(|state: &mut DockClickReset, cx| { - if state.0.is_some() { - state.0 = None; - v.resize_active_panel(None, cx) - } else { - let double_click = cx.double_click_interval(); - let timer = cx.background_executor().timer(double_click); - state.0 = Some(cx.spawn(|_, mut cx| async move { - timer.await; - cx.update_global(|state: &mut DockClickReset, cx| { - state.0 = None; - }) - .ok(); - })); - } - }) + if e.down.button == MouseButton::Left && e.down.click_count == 2 { + v.resize_active_panel(None, cx) } })); diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index a7dc76f41da49fe4bf9139ed2bf7b0ae8b6f4b23..fb465b2637d40ab45d9be7ebf2923611f5a8c996 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -30,11 +30,11 @@ use futures::{ }; use gpui::{ actions, canvas, div, impl_actions, point, size, Action, AnyModel, AnyView, AnyWeakView, - AnyWindowHandle, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Context, Div, Entity, - EntityId, EventEmitter, FocusHandle, FocusableView, GlobalPixels, InteractiveElement, - KeyContext, ManagedView, Model, ModelContext, MouseMoveEvent, ParentElement, PathPromptOptions, - Pixels, Point, PromptLevel, Render, Size, Styled, Subscription, Task, View, ViewContext, - VisualContext, WeakView, WindowBounds, WindowContext, WindowHandle, WindowOptions, + AnyWindowHandle, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Context, Div, + DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, GlobalPixels, + InteractiveElement, KeyContext, 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; @@ -227,9 +227,6 @@ pub fn init_settings(cx: &mut AppContext) { } pub fn init(app_state: Arc, cx: &mut AppContext) { - cx.default_global::(); - cx.default_global::(); - init_settings(cx); notifications::init(cx); @@ -466,6 +463,7 @@ pub struct Workspace { _observe_current_user: Task>, _schedule_serialize: Option>, pane_history_timestamp: Arc, + bounds: Bounds, } impl EventEmitter for Workspace {} @@ -708,6 +706,8 @@ impl Workspace { subscriptions, pane_history_timestamp, workspace_actions: Default::default(), + // This data will be incorrect, but it will be overwritten by the time it needs to be used. + bounds: Default::default(), } } @@ -3580,13 +3580,8 @@ impl FocusableView for Workspace { struct WorkspaceBounds(Bounds); -//todo!("remove this when better drag APIs are in GPUI2") -#[derive(Default)] -struct DockDragState(Option); - -//todo!("remove this when better double APIs are in GPUI2") -#[derive(Default)] -struct DockClickReset(Option>); +#[derive(Render)] +struct DraggedDock(DockPosition); impl Render for Workspace { type Element = Div; @@ -3632,37 +3627,33 @@ impl Render for Workspace { .border_t() .border_b() .border_color(cx.theme().colors().border) - .on_mouse_up(gpui::MouseButton::Left, |_, cx| { - cx.update_global(|drag: &mut DockDragState, cx| { - drag.0 = None; - }) - }) - .on_mouse_move(cx.listener(|workspace, e: &MouseMoveEvent, cx| { - if let Some(types) = &cx.global::().0 { - let workspace_bounds = cx.global::().0; - match types { + .child(canvas( + cx.listener(|workspace, bounds, cx| workspace.bounds = *bounds), + )) + .on_drag_move( + cx.listener(|workspace, e: &DragMoveEvent, cx| { + match e.drag.read(cx).0 { DockPosition::Left => { - let size = e.position.x; + let size = e.event.position.x; workspace.left_dock.update(cx, |left_dock, cx| { left_dock.resize_active_panel(Some(size.0), cx); }); } DockPosition::Right => { - let size = workspace_bounds.size.width - e.position.x; + let size = workspace.bounds.size.width - e.event.position.x; workspace.right_dock.update(cx, |right_dock, cx| { right_dock.resize_active_panel(Some(size.0), cx); }); } DockPosition::Bottom => { - let size = workspace_bounds.size.height - e.position.y; + let size = workspace.bounds.size.height - e.event.position.y; workspace.bottom_dock.update(cx, |bottom_dock, cx| { bottom_dock.resize_active_panel(Some(size.0), cx); }); } } - } - })) - .child(canvas(|bounds, cx| cx.set_global(WorkspaceBounds(bounds)))) + }), + ) .child(self.modal_layer.clone()) .child( div() From e2bfd464555bfc3e9a9403c42ce5c348e49145ca Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 13 Dec 2023 15:14:51 -0800 Subject: [PATCH 3/8] Fix dock split resizin --- crates/workspace2/src/dock.rs | 35 ++++++++++++++++++++--------- crates/workspace2/src/workspace2.rs | 25 +++++++++++++-------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/crates/workspace2/src/dock.rs b/crates/workspace2/src/dock.rs index a71b8b4d6f9b652b29ef55f6d32a7ebf2897442a..495fa014235bdd95b6308dcd0ccb8dd10bad16a2 100644 --- a/crates/workspace2/src/dock.rs +++ b/crates/workspace2/src/dock.rs @@ -1,9 +1,10 @@ use crate::DraggedDock; use crate::{status_bar::StatusItemView, Workspace}; use gpui::{ - div, px, Action, AnchorCorner, AnyView, AppContext, Axis, ClickEvent, Div, Entity, EntityId, - EventEmitter, FocusHandle, FocusableView, IntoElement, MouseButton, ParentElement, Render, - SharedString, Styled, Subscription, View, ViewContext, VisualContext, WeakView, WindowContext, + div, px, red, Action, AnchorCorner, AnyView, AppContext, Axis, ClickEvent, Div, Entity, + EntityId, EventEmitter, FocusHandle, FocusableView, IntoElement, MouseButton, ParentElement, + Render, SharedString, Styled, Subscription, View, ViewContext, VisualContext, WeakView, + WindowContext, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -492,7 +493,8 @@ impl Render for Dock { let position = self.position; let handler = div() .id("resize-handle") - .bg(cx.theme().colors().border) + // .bg(cx.theme().colors().border) + .bg(red()) .on_drag(move |cx| cx.build_view(|_| DraggedDock(position))) .on_click(cx.listener(|v, e: &ClickEvent, cx| { if e.down.button == MouseButton::Left && e.down.click_count == 2 { @@ -500,23 +502,29 @@ impl Render for Dock { } })); + const HANDLE_SIZE: Pixels = Pixels(4. * 3.); + match self.position() { DockPosition::Left => { - post_resize_handle = Some(handler.w_1().h_full().cursor_col_resize()) + post_resize_handle = + Some(handler.min_w(HANDLE_SIZE).h_full().cursor_col_resize()) } DockPosition::Bottom => { - pre_resize_handle = Some(handler.w_full().h_1().cursor_row_resize()) + pre_resize_handle = + Some(handler.w_full().min_h(HANDLE_SIZE).cursor_row_resize()) } DockPosition::Right => { - pre_resize_handle = Some(handler.w_full().h_1().cursor_col_resize()) + pre_resize_handle = + Some(handler.min_w(HANDLE_SIZE).h_full().cursor_col_resize()) } } div() + .flex() .border_color(cx.theme().colors().border) .map(|this| match self.position().axis() { - Axis::Horizontal => this.w(px(size)).h_full(), - Axis::Vertical => this.h(px(size)).w_full(), + Axis::Horizontal => this.w(px(size)).h_full().flex_row(), + Axis::Vertical => this.h(px(size)).w_full().flex_col(), }) .map(|this| match self.position() { DockPosition::Left => this.border_r(), @@ -524,7 +532,14 @@ impl Render for Dock { DockPosition::Bottom => this.border_t(), }) .children(pre_resize_handle) - .child(entry.panel.to_any()) + .child( + div() + .map(|this| match self.position().axis() { + Axis::Horizontal => this.min_w(px(size) - HANDLE_SIZE).h_full(), + Axis::Vertical => this.min_h(px(size) - HANDLE_SIZE).w_full(), + }) + .child(entry.panel.to_any()), + ) .children(post_resize_handle) } else { div() diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index fb465b2637d40ab45d9be7ebf2923611f5a8c996..c070bdfad2d20f746a6a52568131ed4939097bf0 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -29,9 +29,9 @@ use futures::{ Future, FutureExt, StreamExt, }; use gpui::{ - actions, canvas, div, impl_actions, point, size, Action, AnyModel, AnyView, AnyWeakView, - AnyWindowHandle, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Context, Div, - DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, GlobalPixels, + actions, canvas, div, impl_actions, outline, point, size, Action, AnyModel, AnyView, + AnyWeakView, AnyWindowHandle, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Context, + Div, DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, GlobalPixels, InteractiveElement, KeyContext, ManagedView, Model, ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel, Render, Size, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds, WindowContext, WindowHandle, WindowOptions, @@ -3627,26 +3627,33 @@ impl Render for Workspace { .border_t() .border_b() .border_color(cx.theme().colors().border) - .child(canvas( - cx.listener(|workspace, bounds, cx| workspace.bounds = *bounds), - )) + .child( + canvas(cx.listener(|workspace, bounds, cx| { + cx.with_z_index(100, |cx| { + cx.paint_quad(outline(*bounds, gpui::green())); + }); + workspace.bounds = *bounds; + })) + .absolute() + .size_full(), + ) .on_drag_move( cx.listener(|workspace, e: &DragMoveEvent, cx| { match e.drag.read(cx).0 { DockPosition::Left => { - let size = e.event.position.x; + let size = workspace.bounds.left() + e.event.position.x; workspace.left_dock.update(cx, |left_dock, cx| { left_dock.resize_active_panel(Some(size.0), cx); }); } DockPosition::Right => { - let size = workspace.bounds.size.width - e.event.position.x; + let size = workspace.bounds.right() - e.event.position.x; workspace.right_dock.update(cx, |right_dock, cx| { right_dock.resize_active_panel(Some(size.0), cx); }); } DockPosition::Bottom => { - let size = workspace.bounds.size.height - e.event.position.y; + let size = workspace.bounds.bottom() - e.event.position.y; workspace.bottom_dock.update(cx, |bottom_dock, cx| { bottom_dock.resize_active_panel(Some(size.0), cx); }); From 416bb455318f97d3c07a8bb37875c1af309cf848 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 13 Dec 2023 16:35:25 -0800 Subject: [PATCH 4/8] Tidy up workspace resizing --- crates/workspace2/src/dock.rs | 15 +++++++-------- crates/workspace2/src/workspace2.rs | 9 +++------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/crates/workspace2/src/dock.rs b/crates/workspace2/src/dock.rs index 495fa014235bdd95b6308dcd0ccb8dd10bad16a2..f9e294763b3314cfb0b01930c0d4581c76be000e 100644 --- a/crates/workspace2/src/dock.rs +++ b/crates/workspace2/src/dock.rs @@ -1,10 +1,9 @@ use crate::DraggedDock; use crate::{status_bar::StatusItemView, Workspace}; use gpui::{ - div, px, red, Action, AnchorCorner, AnyView, AppContext, Axis, ClickEvent, Div, Entity, - EntityId, EventEmitter, FocusHandle, FocusableView, IntoElement, MouseButton, ParentElement, - Render, SharedString, Styled, Subscription, View, ViewContext, VisualContext, WeakView, - WindowContext, + div, px, Action, AnchorCorner, AnyView, AppContext, Axis, ClickEvent, Div, Entity, EntityId, + EventEmitter, FocusHandle, FocusableView, IntoElement, MouseButton, ParentElement, Render, + SharedString, Styled, Subscription, View, ViewContext, VisualContext, WeakView, WindowContext, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -493,16 +492,16 @@ impl Render for Dock { let position = self.position; let handler = div() .id("resize-handle") - // .bg(cx.theme().colors().border) - .bg(red()) + .bg(cx.theme().colors().border) .on_drag(move |cx| cx.build_view(|_| DraggedDock(position))) .on_click(cx.listener(|v, e: &ClickEvent, cx| { if e.down.button == MouseButton::Left && e.down.click_count == 2 { v.resize_active_panel(None, cx) } - })); + })) + .z_index(1); - const HANDLE_SIZE: Pixels = Pixels(4. * 3.); + const HANDLE_SIZE: Pixels = Pixels(6.); match self.position() { DockPosition::Left => { diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index c070bdfad2d20f746a6a52568131ed4939097bf0..629e151372f1d00a00570e8810d8e0bc9d54ee15 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -29,9 +29,9 @@ use futures::{ Future, FutureExt, StreamExt, }; use gpui::{ - actions, canvas, div, impl_actions, outline, point, size, Action, AnyModel, AnyView, - AnyWeakView, AnyWindowHandle, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Context, - Div, DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, GlobalPixels, + actions, canvas, div, impl_actions, point, size, Action, AnyModel, AnyView, AnyWeakView, + AnyWindowHandle, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Context, Div, + DragMoveEvent, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, GlobalPixels, InteractiveElement, KeyContext, ManagedView, Model, ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel, Render, Size, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds, WindowContext, WindowHandle, WindowOptions, @@ -3629,9 +3629,6 @@ impl Render for Workspace { .border_color(cx.theme().colors().border) .child( canvas(cx.listener(|workspace, bounds, cx| { - cx.with_z_index(100, |cx| { - cx.paint_quad(outline(*bounds, gpui::green())); - }); workspace.bounds = *bounds; })) .absolute() From 04389939d3e09d82839333b7964873dee57e2326 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Wed, 13 Dec 2023 16:36:12 -0800 Subject: [PATCH 5/8] Add debug and debug below methods for observing the bounds of divs --- crates/gpui2/src/elements/div.rs | 7 +-- crates/gpui2/src/elements/uniform_list.rs | 66 +++++++++++------------ crates/gpui2/src/style.rs | 39 +++++++++++++- crates/gpui2/src/styled.rs | 12 +++++ 4 files changed, 85 insertions(+), 39 deletions(-) diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index 7dfc9bae6a7648f74502387ac041e3c83d61c79b..85b172687a8d23830d75b47672695a5cf32c4b25 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -640,10 +640,7 @@ impl Element for Div { let z_index = style.z_index.unwrap_or(0); cx.with_z_index(z_index, |cx| { - cx.with_z_index(0, |cx| { - style.paint(bounds, cx); - }); - cx.with_z_index(1, |cx| { + style.paint(bounds, cx, |cx| { cx.with_text_style(style.text_style().cloned(), |cx| { cx.with_content_mask(style.overflow_mask(bounds), |cx| { cx.with_element_offset(scroll_offset, |cx| { @@ -653,7 +650,7 @@ impl Element for Div { }) }) }) - }) + }); }) }, ); diff --git a/crates/gpui2/src/elements/uniform_list.rs b/crates/gpui2/src/elements/uniform_list.rs index d27b3bdb772ca7c382b3eb91ac6ba56ff4e23622..bddfc8c9a19e70d7649b6fc3f2338fd666ecb2d3 100644 --- a/crates/gpui2/src/elements/uniform_list.rs +++ b/crates/gpui2/src/elements/uniform_list.rs @@ -197,41 +197,41 @@ impl Element for UniformList { ); cx.with_z_index(style.z_index.unwrap_or(0), |cx| { - style.paint(bounds, cx); - - if self.item_count > 0 { - if let Some(scroll_handle) = self.scroll_handle.clone() { - scroll_handle.0.borrow_mut().replace(ScrollHandleState { - item_height, - list_height: padded_bounds.size.height, - scroll_offset: shared_scroll_offset, + style.paint(bounds, cx, |cx| { + if self.item_count > 0 { + if let Some(scroll_handle) = self.scroll_handle.clone() { + scroll_handle.0.borrow_mut().replace(ScrollHandleState { + item_height, + list_height: padded_bounds.size.height, + scroll_offset: shared_scroll_offset, + }); + } + + let first_visible_element_ix = + (-scroll_offset.y / item_height).floor() as usize; + let last_visible_element_ix = + ((-scroll_offset.y + padded_bounds.size.height) / item_height) + .ceil() as usize; + let visible_range = first_visible_element_ix + ..cmp::min(last_visible_element_ix, self.item_count); + + let items = (self.render_items)(visible_range.clone(), cx); + cx.with_z_index(1, |cx| { + let content_mask = ContentMask { bounds }; + cx.with_content_mask(Some(content_mask), |cx| { + for (item, ix) in items.into_iter().zip(visible_range) { + let item_origin = padded_bounds.origin + + point(px(0.), item_height * ix + scroll_offset.y); + let available_space = size( + AvailableSpace::Definite(padded_bounds.size.width), + AvailableSpace::Definite(item_height), + ); + item.draw(item_origin, available_space, cx); + } + }); }); } - - let first_visible_element_ix = - (-scroll_offset.y / item_height).floor() as usize; - let last_visible_element_ix = - ((-scroll_offset.y + padded_bounds.size.height) / item_height).ceil() - as usize; - let visible_range = first_visible_element_ix - ..cmp::min(last_visible_element_ix, self.item_count); - - let items = (self.render_items)(visible_range.clone(), cx); - cx.with_z_index(1, |cx| { - let content_mask = ContentMask { bounds }; - cx.with_content_mask(Some(content_mask), |cx| { - for (item, ix) in items.into_iter().zip(visible_range) { - let item_origin = padded_bounds.origin - + point(px(0.), item_height * ix + scroll_offset.y); - let available_space = size( - AvailableSpace::Definite(padded_bounds.size.width), - AvailableSpace::Definite(item_height), - ); - item.draw(item_origin, available_space, cx); - } - }); - }); - } + }); }) }, ); diff --git a/crates/gpui2/src/style.rs b/crates/gpui2/src/style.rs index 4031a35f75048f980558ab4ce7bf2d09f6049436..115db997843fe3b94e3b31ec292cab02c599dc96 100644 --- a/crates/gpui2/src/style.rs +++ b/crates/gpui2/src/style.rs @@ -14,6 +14,9 @@ pub use taffy::style::{ Overflow, Position, }; +#[cfg(debug_assertions)] +pub struct DebugBelow; + pub type StyleCascade = Cascade