Add fluent quad API

This commit is contained in:
Mikayla 2023-12-13 13:21:48 -08:00
parent 5c8257585a
commit bfbbec0b01
No known key found for this signature in database
7 changed files with 196 additions and 151 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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