Detailed changes
@@ -32,8 +32,8 @@ use gpui::{
json::{self, ToJson},
platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent},
text_layout::{self, Line, RunStyle, TextLayoutCache},
- AnyElement, Axis, Border, CursorRegion, Element, EventContext, FontCache, LayoutContext,
- MouseRegion, PaintContext, Quad, SceneBuilder, SizeConstraint, ViewContext, WindowContext,
+ AnyElement, Axis, CursorRegion, Element, EventContext, FontCache, LayoutContext, MouseRegion,
+ PaintContext, Quad, SceneBuilder, SizeConstraint, ViewContext, WindowContext,
};
use itertools::Itertools;
use json::json;
@@ -539,13 +539,13 @@ impl EditorElement {
scene.push_quad(Quad {
bounds: gutter_bounds,
background: Some(self.style.gutter_background),
- border: Border::new(0., Color::transparent_black()),
+ border: Border::new(0., Color::transparent_black()).into(),
corner_radii: Default::default(),
});
scene.push_quad(Quad {
bounds: text_bounds,
background: Some(self.style.background),
- border: Border::new(0., Color::transparent_black()),
+ border: Border::new(0., Color::transparent_black()).into(),
corner_radii: Default::default(),
});
@@ -573,7 +573,7 @@ impl EditorElement {
scene.push_quad(Quad {
bounds: RectF::new(origin, size),
background: Some(self.style.active_line_background),
- border: Border::default(),
+ border: Border::default().into(),
corner_radii: Default::default(),
});
}
@@ -593,7 +593,7 @@ impl EditorElement {
scene.push_quad(Quad {
bounds: RectF::new(origin, size),
background: Some(self.style.highlighted_line_background),
- border: Border::default(),
+ border: Border::default().into(),
corner_radii: Default::default(),
});
}
@@ -623,7 +623,7 @@ impl EditorElement {
vec2f(1., text_bounds.height()),
),
background: Some(color),
- border: Border::new(0., Color::transparent_black()),
+ border: Border::new(0., Color::transparent_black()).into(),
corner_radii: Default::default(),
});
}
@@ -724,7 +724,7 @@ impl EditorElement {
scene.push_quad(Quad {
bounds: highlight_bounds,
background: Some(diff_style.modified),
- border: Border::new(0., Color::transparent_black()),
+ border: Border::new(0., Color::transparent_black()).into(),
corner_radii: (1. * line_height).into(),
});
@@ -757,7 +757,7 @@ impl EditorElement {
scene.push_quad(Quad {
bounds: highlight_bounds,
background: Some(diff_style.deleted),
- border: Border::new(0., Color::transparent_black()),
+ border: Border::new(0., Color::transparent_black()).into(),
corner_radii: (1. * line_height).into(),
});
@@ -779,7 +779,7 @@ impl EditorElement {
scene.push_quad(Quad {
bounds: highlight_bounds,
background: Some(color),
- border: Border::new(0., Color::transparent_black()),
+ border: Border::new(0., Color::transparent_black()).into(),
corner_radii: (diff_style.corner_radius * line_height).into(),
});
}
@@ -1149,7 +1149,7 @@ impl EditorElement {
if layout.show_scrollbars {
scene.push_quad(Quad {
bounds: track_bounds,
- border: style.track.border,
+ border: style.track.border.into(),
background: style.track.background_color,
..Default::default()
});
@@ -1180,7 +1180,7 @@ impl EditorElement {
scene.push_quad(Quad {
bounds,
background: Some(color),
- border,
+ border: border.into(),
corner_radii: style.thumb.corner_radii.into(),
})
};
@@ -1240,7 +1240,7 @@ impl EditorElement {
scene.push_quad(Quad {
bounds,
background: Some(color),
- border,
+ border: border.into(),
corner_radii: style.thumb.corner_radii.into(),
})
}
@@ -1248,7 +1248,7 @@ impl EditorElement {
scene.push_quad(Quad {
bounds: thumb_bounds,
- border: style.thumb.border,
+ border: style.thumb.border.into(),
background: style.thumb.background_color,
corner_radii: style.thumb.corner_radii.into(),
});
@@ -2891,7 +2891,7 @@ impl Cursor {
scene.push_quad(Quad {
bounds,
background: None,
- border: Border::all(1., self.color),
+ border: Border::all(1., self.color).into(),
corner_radii: Default::default(),
});
} else {
@@ -9,7 +9,7 @@ use crate::{
},
json::ToJson,
platform::CursorStyle,
- scene::{self, Border, CornerRadii, CursorRegion, Quad},
+ scene::{self, CornerRadii, CursorRegion, Quad},
AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, ViewContext,
};
use schemars::JsonSchema;
@@ -206,6 +206,163 @@ impl<V> Container<V> {
}
}
+#[derive(Copy, Clone, Debug, Default, JsonSchema)]
+pub struct Border {
+ pub color: Color,
+ pub width: f32,
+ pub overlay: bool,
+ pub top: bool,
+ pub bottom: bool,
+ pub left: bool,
+ pub right: bool,
+}
+
+impl Into<scene::Border> for Border {
+ fn into(self) -> scene::Border {
+ scene::Border {
+ color: self.color,
+ left: if self.left { self.width } else { 0.0 },
+ right: if self.right { self.width } else { 0.0 },
+ top: if self.top { self.width } else { 0.0 },
+ bottom: if self.bottom { self.width } else { 0.0 },
+ }
+ }
+}
+
+impl Border {
+ pub fn new(width: f32, color: Color) -> Self {
+ Self {
+ width,
+ color,
+ overlay: false,
+ top: false,
+ left: false,
+ bottom: false,
+ right: false,
+ }
+ }
+
+ pub fn all(width: f32, color: Color) -> Self {
+ Self {
+ width,
+ color,
+ overlay: false,
+ top: true,
+ left: true,
+ bottom: true,
+ right: true,
+ }
+ }
+
+ pub fn top(width: f32, color: Color) -> Self {
+ let mut border = Self::new(width, color);
+ border.top = true;
+ border
+ }
+
+ pub fn left(width: f32, color: Color) -> Self {
+ let mut border = Self::new(width, color);
+ border.left = true;
+ border
+ }
+
+ pub fn bottom(width: f32, color: Color) -> Self {
+ let mut border = Self::new(width, color);
+ border.bottom = true;
+ border
+ }
+
+ pub fn right(width: f32, color: Color) -> Self {
+ let mut border = Self::new(width, color);
+ border.right = true;
+ border
+ }
+
+ pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
+ self.top = top;
+ self.left = left;
+ self.bottom = bottom;
+ self.right = right;
+ self
+ }
+
+ pub fn top_width(&self) -> f32 {
+ if self.top {
+ self.width
+ } else {
+ 0.0
+ }
+ }
+
+ pub fn left_width(&self) -> f32 {
+ if self.left {
+ self.width
+ } else {
+ 0.0
+ }
+ }
+}
+
+impl<'de> Deserialize<'de> for Border {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ #[derive(Deserialize)]
+ struct BorderData {
+ pub width: f32,
+ pub color: Color,
+ #[serde(default)]
+ pub overlay: bool,
+ #[serde(default)]
+ pub top: bool,
+ #[serde(default)]
+ pub right: bool,
+ #[serde(default)]
+ pub bottom: bool,
+ #[serde(default)]
+ pub left: bool,
+ }
+
+ let data = BorderData::deserialize(deserializer)?;
+ let mut border = Border {
+ width: data.width,
+ color: data.color,
+ overlay: data.overlay,
+ top: data.top,
+ bottom: data.bottom,
+ left: data.left,
+ right: data.right,
+ };
+ if !border.top && !border.bottom && !border.left && !border.right {
+ border.top = true;
+ border.bottom = true;
+ border.left = true;
+ border.right = true;
+ }
+ Ok(border)
+ }
+}
+
+impl ToJson for Border {
+ fn to_json(&self) -> serde_json::Value {
+ let mut value = json!({});
+ if self.top {
+ value["top"] = json!(self.width);
+ }
+ if self.right {
+ value["right"] = json!(self.width);
+ }
+ if self.bottom {
+ value["bottom"] = json!(self.width);
+ }
+ if self.left {
+ value["left"] = json!(self.width);
+ }
+ value
+ }
+}
+
impl<V: 'static> Element<V> for Container<V> {
type LayoutState = ();
type PaintState = ();
@@ -278,7 +435,7 @@ impl<V: 'static> Element<V> for Container<V> {
scene.push_quad(Quad {
bounds: quad_bounds,
background: self.style.overlay_color,
- border: self.style.border,
+ border: self.style.border.into(),
corner_radii: self.style.corner_radii.into(),
});
scene.pop_layer();
@@ -286,7 +443,7 @@ impl<V: 'static> Element<V> for Container<V> {
scene.push_quad(Quad {
bounds: quad_bounds,
background: self.style.background_color,
- border: self.style.border,
+ border: self.style.border.into(),
corner_radii: self.style.corner_radii.into(),
});
@@ -1,11 +1,11 @@
-use super::constrain_size_preserving_aspect_ratio;
+use super::{constrain_size_preserving_aspect_ratio, Border};
use crate::{
geometry::{
rect::RectF,
vector::{vec2f, Vector2F},
},
json::{json, ToJson},
- scene, Border, Element, ImageData, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
+ scene, Element, ImageData, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
ViewContext,
};
use schemars::JsonSchema;
@@ -102,7 +102,7 @@ impl<V: 'static> Element<V> for Image {
if let Some(data) = layout {
scene.push_image(scene::Image {
bounds,
- border: self.style.border,
+ border: self.style.border.into(),
corner_radii: self.style.corner_radius.into(),
grayscale: self.style.grayscale,
data: data.clone(),
@@ -230,7 +230,16 @@ pub struct Edges<T: Clone + Default> {
pub left: T,
}
-impl Edges<DefiniteLength> {
+impl Edges<Length> {
+ pub fn auto() -> Self {
+ Self {
+ top: Length::Auto,
+ right: Length::Auto,
+ bottom: Length::Auto,
+ left: Length::Auto,
+ }
+ }
+
pub fn zero() -> Self {
Self {
top: pixels(0.),
@@ -240,7 +249,10 @@ impl Edges<DefiniteLength> {
}
}
- pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
+ pub fn to_taffy(
+ &self,
+ rem_size: f32,
+ ) -> taffy::geometry::Rect<taffy::style::LengthPercentageAuto> {
taffy::geometry::Rect {
top: self.top.to_taffy(rem_size),
right: self.right.to_taffy(rem_size),
@@ -250,16 +262,27 @@ impl Edges<DefiniteLength> {
}
}
-impl Edges<Length> {
- pub fn auto() -> Self {
+impl Edges<DefiniteLength> {
+ pub fn zero() -> Self {
Self {
- top: Length::Auto,
- right: Length::Auto,
- bottom: Length::Auto,
- left: Length::Auto,
+ top: pixels(0.),
+ right: pixels(0.),
+ bottom: pixels(0.),
+ left: pixels(0.),
}
}
+ pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
+ taffy::geometry::Rect {
+ top: self.top.to_taffy(rem_size),
+ right: self.right.to_taffy(rem_size),
+ bottom: self.bottom.to_taffy(rem_size),
+ left: self.left.to_taffy(rem_size),
+ }
+ }
+}
+
+impl Edges<AbsoluteLength> {
pub fn zero() -> Self {
Self {
top: pixels(0.),
@@ -269,10 +292,7 @@ impl Edges<Length> {
}
}
- pub fn to_taffy(
- &self,
- rem_size: f32,
- ) -> taffy::geometry::Rect<taffy::style::LengthPercentageAuto> {
+ pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
taffy::geometry::Rect {
top: self.top.to_taffy(rem_size),
right: self.right.to_taffy(rem_size),
@@ -280,6 +300,21 @@ impl Edges<Length> {
left: self.left.to_taffy(rem_size),
}
}
+
+ pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
+ Edges {
+ top: self.top.to_pixels(rem_size),
+ right: self.right.to_pixels(rem_size),
+ bottom: self.bottom.to_pixels(rem_size),
+ left: self.left.to_pixels(rem_size),
+ }
+ }
+}
+
+impl Edges<f32> {
+ pub fn is_empty(&self) -> bool {
+ self.top == 0.0 && self.right == 0.0 && self.bottom == 0.0 && self.left == 0.0
+ }
}
#[derive(Clone, Copy)]
@@ -295,6 +330,13 @@ impl AbsoluteLength {
AbsoluteLength::Rems(rems) => rems * rem_size,
}
}
+
+ pub fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
+ match self {
+ AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
+ AbsoluteLength::Rems(rems) => taffy::style::LengthPercentage::Length(rems * rem_size),
+ }
+ }
}
impl Default for AbsoluteLength {
@@ -577,7 +577,6 @@ impl Renderer {
};
for (ix, quad) in quads.iter().enumerate() {
let bounds = quad.bounds * scale_factor;
- let border_width = quad.border.width * scale_factor;
let shader_quad = shaders::GPUIQuad {
origin: bounds.origin().round().to_float2(),
size: bounds.size().round().to_float2(),
@@ -585,10 +584,10 @@ impl Renderer {
.background
.unwrap_or_else(Color::transparent_black)
.to_uchar4(),
- border_top: border_width * (quad.border.top as usize as f32),
- border_right: border_width * (quad.border.right as usize as f32),
- border_bottom: border_width * (quad.border.bottom as usize as f32),
- border_left: border_width * (quad.border.left as usize as f32),
+ border_top: quad.border.top * scale_factor,
+ border_right: quad.border.right * scale_factor,
+ border_bottom: quad.border.bottom * scale_factor,
+ border_left: quad.border.left * scale_factor,
border_color: quad.border.color.to_uchar4(),
corner_radius_top_left: quad.corner_radii.top_left * scale_factor,
corner_radius_top_right: quad.corner_radii.top_right * scale_factor,
@@ -746,7 +745,6 @@ impl Renderer {
let origin = image.bounds.origin() * scale_factor;
let target_size = image.bounds.size() * scale_factor;
let corner_radii = image.corner_radii * scale_factor;
- let border_width = image.border.width * scale_factor;
let (alloc_id, atlas_bounds) = self.image_cache.render(&image.data);
images_by_atlas
.entry(alloc_id.atlas_id)
@@ -756,10 +754,10 @@ impl Renderer {
target_size: target_size.to_float2(),
source_size: atlas_bounds.size().to_float2(),
atlas_origin: atlas_bounds.origin().to_float2(),
- border_top: border_width * (image.border.top as usize as f32),
- border_right: border_width * (image.border.right as usize as f32),
- border_bottom: border_width * (image.border.bottom as usize as f32),
- border_left: border_width * (image.border.left as usize as f32),
+ border_top: image.border.top * scale_factor,
+ border_right: image.border.right * scale_factor,
+ border_bottom: image.border.bottom * scale_factor,
+ border_left: image.border.left * scale_factor,
border_color: image.border.color.to_uchar4(),
corner_radius_top_left: corner_radii.top_left,
corner_radius_top_right: corner_radii.top_right,
@@ -8,7 +8,6 @@ use derive_more::Mul;
use schemars::JsonSchema;
use serde::Deserialize;
use serde_derive::Serialize;
-use serde_json::json;
use std::{
any::{Any, TypeId},
borrow::Cow,
@@ -20,7 +19,6 @@ use crate::{
color::Color,
fonts::{FontId, GlyphId},
geometry::{rect::RectF, vector::Vector2F},
- json::ToJson,
platform::{current::Surface, CursorStyle},
ImageData, WindowContext,
};
@@ -171,15 +169,13 @@ pub struct Icon {
pub color: Color,
}
-#[derive(Clone, Copy, Default, Debug, JsonSchema)]
+#[derive(Clone, Copy, Default, Debug)]
pub struct Border {
- pub width: f32,
pub color: Color,
- pub overlay: bool,
- pub top: bool,
- pub right: bool,
- pub bottom: bool,
- pub left: bool,
+ pub top: f32,
+ pub right: f32,
+ pub bottom: f32,
+ pub left: f32,
}
#[derive(Clone, Copy, Default, Debug)]
@@ -191,47 +187,6 @@ pub struct Underline {
pub squiggly: bool,
}
-impl<'de> Deserialize<'de> for Border {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: serde::Deserializer<'de>,
- {
- #[derive(Deserialize)]
- struct BorderData {
- pub width: f32,
- pub color: Color,
- #[serde(default)]
- pub overlay: bool,
- #[serde(default)]
- pub top: bool,
- #[serde(default)]
- pub right: bool,
- #[serde(default)]
- pub bottom: bool,
- #[serde(default)]
- pub left: bool,
- }
-
- let data = BorderData::deserialize(deserializer)?;
- let mut border = Border {
- width: data.width,
- color: data.color,
- overlay: data.overlay,
- top: data.top,
- bottom: data.bottom,
- left: data.left,
- right: data.right,
- };
- if !border.top && !border.bottom && !border.left && !border.right {
- border.top = true;
- border.bottom = true;
- border.left = true;
- border.right = true;
- }
- Ok(border)
- }
-}
-
#[derive(Debug)]
pub struct Path {
pub bounds: RectF,
@@ -606,99 +561,6 @@ impl Layer {
}
}
-impl Border {
- pub fn new(width: f32, color: Color) -> Self {
- Self {
- width,
- color,
- overlay: false,
- top: false,
- left: false,
- bottom: false,
- right: false,
- }
- }
-
- pub fn all(width: f32, color: Color) -> Self {
- Self {
- width,
- color,
- overlay: false,
- top: true,
- left: true,
- bottom: true,
- right: true,
- }
- }
-
- pub fn top(width: f32, color: Color) -> Self {
- let mut border = Self::new(width, color);
- border.top = true;
- border
- }
-
- pub fn left(width: f32, color: Color) -> Self {
- let mut border = Self::new(width, color);
- border.left = true;
- border
- }
-
- pub fn bottom(width: f32, color: Color) -> Self {
- let mut border = Self::new(width, color);
- border.bottom = true;
- border
- }
-
- pub fn right(width: f32, color: Color) -> Self {
- let mut border = Self::new(width, color);
- border.right = true;
- border
- }
-
- pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
- self.top = top;
- self.left = left;
- self.bottom = bottom;
- self.right = right;
- self
- }
-
- pub fn top_width(&self) -> f32 {
- if self.top {
- self.width
- } else {
- 0.0
- }
- }
-
- pub fn left_width(&self) -> f32 {
- if self.left {
- self.width
- } else {
- 0.0
- }
- }
-}
-
-impl ToJson for Border {
- fn to_json(&self) -> serde_json::Value {
- let mut value = json!({});
- if self.top {
- value["top"] = json!(self.width);
- }
- if self.right {
- value["right"] = json!(self.width);
- }
- if self.bottom {
- value["bottom"] = json!(self.width);
- }
- if self.left {
- value["left"] = json!(self.width);
- }
- value
- }
-}
-
impl MouseRegion {
pub fn id(&self) -> MouseRegionId {
self.id
@@ -16,7 +16,7 @@ use gpui::{
rect::RectF, relative, AbsoluteLength, DefiniteLength, Edges, EdgesRefinement, Length,
Point, PointRefinement, Size, SizeRefinement,
},
- taffy, WindowContext,
+ scene, taffy, WindowContext,
};
use gpui2_macros::styleable_helpers;
use refineable::{Refineable, RefinementCascade};
@@ -63,7 +63,7 @@ pub struct Style {
pub padding: Edges<DefiniteLength>,
/// How large should the border be on each side?
#[refineable]
- pub border: Edges<DefiniteLength>,
+ pub border_widths: Edges<AbsoluteLength>,
// Alignment properties
/// How this node's children aligned in the cross/block axis?
@@ -92,6 +92,10 @@ pub struct Style {
/// The fill color of this element
pub fill: Option<Fill>,
+
+ /// The border color of this element
+ pub border_color: Option<Hsla>,
+
/// The radius of the corners of this element
#[refineable]
pub corner_radii: CornerRadii,
@@ -143,7 +147,7 @@ impl Style {
aspect_ratio: self.aspect_ratio,
margin: self.margin.to_taffy(rem_size),
padding: self.padding.to_taffy(rem_size),
- border: self.border.to_taffy(rem_size),
+ border: self.border_widths.to_taffy(rem_size),
align_items: self.align_items,
align_self: self.align_self,
align_content: self.align_content,
@@ -159,7 +163,6 @@ impl Style {
}
/// Paints the background of an element styled with this style.
- /// Return the bounds in which to paint the content.
pub fn paint_background<V: 'static>(&self, bounds: RectF, cx: &mut PaintContext<V>) {
let rem_size = cx.rem_size();
if let Some(color) = self.fill.as_ref().and_then(Fill::color) {
@@ -171,6 +174,29 @@ impl Style {
});
}
}
+
+ /// Paints the foreground of an element styled with this style.
+ pub fn paint_foreground<V: 'static>(&self, bounds: RectF, cx: &mut PaintContext<V>) {
+ let rem_size = cx.rem_size();
+
+ if let Some(color) = self.border_color {
+ let border = self.border_widths.to_pixels(rem_size);
+ if !border.is_empty() {
+ cx.scene.push_quad(gpui::Quad {
+ bounds,
+ background: None,
+ corner_radii: self.corner_radii.to_gpui(rem_size),
+ border: scene::Border {
+ color: color.into(),
+ top: border.top,
+ right: border.right,
+ bottom: border.bottom,
+ left: border.left,
+ },
+ });
+ }
+ }
+ }
}
impl Default for Style {
@@ -186,7 +212,7 @@ impl Default for Style {
inset: Edges::auto(),
margin: Edges::<Length>::zero(),
padding: Edges::<DefiniteLength>::zero(),
- border: Edges::<DefiniteLength>::zero(),
+ border_widths: Edges::<AbsoluteLength>::zero(),
size: Size::auto(),
min_size: Size::auto(),
max_size: Size::auto(),
@@ -204,6 +230,7 @@ impl Default for Style {
flex_shrink: 1.0,
flex_basis: Length::Auto,
fill: None,
+ border_color: None,
corner_radii: CornerRadii::default(),
text_color: None,
font_size: Some(1.),
@@ -6,9 +6,9 @@ pub mod ui;
use components::{action_button::ButtonStyle, disclosure::DisclosureStyle, ToggleIconButtonStyle};
use gpui::{
color::Color,
- elements::{ContainerStyle, ImageStyle, LabelStyle, Shadow, SvgStyle, TooltipStyle},
+ elements::{Border, ContainerStyle, ImageStyle, LabelStyle, Shadow, SvgStyle, TooltipStyle},
fonts::{HighlightStyle, TextStyle},
- platform, AppContext, AssetSource, Border, MouseState,
+ platform, AppContext, AssetSource, MouseState,
};
use parking_lot::Mutex;
use schemars::JsonSchema;
@@ -9,7 +9,7 @@ use gpui::{
elements::*,
geometry::{rect::RectF, vector::Vector2F},
platform::{CursorStyle, MouseButton},
- AnyViewHandle, Axis, Border, ModelHandle, ViewContext, ViewHandle,
+ AnyViewHandle, Axis, ModelHandle, ViewContext, ViewHandle,
};
use project::Project;
use serde::Deserialize;