Detailed changes
@@ -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)
@@ -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);
@@ -1592,6 +1592,17 @@ impl Edges<Pixels> {
}
}
+impl Into<Edges<Pixels>> for f32 {
+ fn into(self) -> Edges<Pixels> {
+ 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<T> Copy for Corners<T> where T: Copy + Clone + Default + Debug {}
+impl Into<Corners<Pixels>> for f32 {
+ fn into(self) -> Corners<Pixels> {
+ Corners {
+ top_left: self.into(),
+ top_right: self.into(),
+ bottom_right: self.into(),
+ bottom_left: self.into(),
+ }
+ }
+}
+
+impl Into<Corners<Pixels>> for Pixels {
+ fn into(self) -> Corners<Pixels> {
+ 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
@@ -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(),
- );
+ ));
});
}
}
@@ -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() {
@@ -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<Pixels>,
- corner_radii: Corners<Pixels>,
- background: impl Into<Hsla>,
- border_widths: Edges<Pixels>,
- border_color: impl Into<Hsla>,
- ) {
+ /// 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<Pixels>,
+ corner_radii: Corners<Pixels>,
+ background: Hsla,
+ border_widths: Edges<Pixels>,
+ border_color: Hsla,
+}
+
+impl PaintQuad {
+ /// Set the corner radii of the quad.
+ pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
+ PaintQuad {
+ corner_radii: corner_radii.into(),
+ ..self
+ }
+ }
+
+ /// Set the border widths of the quad.
+ pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
+ PaintQuad {
+ border_widths: border_widths.into(),
+ ..self
+ }
+ }
+
+ /// Set the border color of the quad.
+ pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
+ PaintQuad {
+ border_color: border_color.into(),
+ ..self
+ }
+ }
+
+ /// Set the background color of the quad.
+ pub fn background(self, background: impl Into<Hsla>) -> Self {
+ PaintQuad {
+ background: background.into(),
+ ..self
+ }
+ }
+}
+
+/// Create a quad with the given parameters.
+pub fn quad(
+ bounds: Bounds<Pixels>,
+ corner_radii: impl Into<Corners<Pixels>>,
+ background: impl Into<Hsla>,
+ border_widths: impl Into<Edges<Pixels>>,
+ border_color: impl Into<Hsla>,
+) -> 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<Bounds<Pixels>>, background: impl Into<Hsla>) -> 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<Bounds<Pixels>>, border_color: impl Into<Hsla>) -> PaintQuad {
+ PaintQuad {
+ bounds: bounds.into(),
+ corner_radii: (0.).into(),
+ background: transparent_black(),
+ border_widths: (1.).into(),
+ border_color: border_color.into(),
+ }
+}
@@ -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 {