From ffffbbea1f3a6f3679acbdff2106db4d900b8518 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 11 Aug 2023 15:29:55 +0200 Subject: [PATCH 1/8] chore: use Cow instead of String for tooltips (#2838) A QoL change to align `Tooltip` with other elements like `Label` Release Notes: - N/A --- crates/ai/src/assistant.rs | 22 +++++-------------- crates/collab_ui/src/collab_titlebar_item.rs | 14 ++++++------ crates/collab_ui/src/contact_list.rs | 2 +- crates/copilot_button/src/copilot_button.rs | 2 +- crates/diagnostics/src/items.rs | 2 +- crates/editor/src/editor.rs | 2 +- crates/feedback/src/deploy_feedback_button.rs | 2 +- crates/feedback/src/submit_feedback_button.rs | 2 +- crates/gpui/src/elements.rs | 4 ++-- crates/gpui/src/elements/tooltip.rs | 9 +++++--- crates/terminal_view/src/terminal_panel.rs | 5 +---- crates/workspace/src/pane.rs | 6 ++--- crates/workspace/src/toolbar.rs | 4 ++-- 13 files changed, 33 insertions(+), 43 deletions(-) diff --git a/crates/ai/src/assistant.rs b/crates/ai/src/assistant.rs index 957c5e1c063aad3de12657448267d0f813f38887..0a18266d2af934b43ffb782068ed153ada9ccfbc 100644 --- a/crates/ai/src/assistant.rs +++ b/crates/ai/src/assistant.rs @@ -362,7 +362,7 @@ impl AssistantPanel { this.set_active_editor_index(this.prev_active_editor_index, cx); } }) - .with_tooltip::(1, "History".into(), None, tooltip_style, cx) + .with_tooltip::(1, "History", None, tooltip_style, cx) } fn render_editor_tools(&self, cx: &mut ViewContext) -> Vec> { @@ -394,7 +394,7 @@ impl AssistantPanel { }) .with_tooltip::( 1, - "Split Message".into(), + "Split Message", Some(Box::new(Split)), tooltip_style, cx, @@ -416,13 +416,7 @@ impl AssistantPanel { active_editor.update(cx, |editor, cx| editor.assist(&Default::default(), cx)); } }) - .with_tooltip::( - 1, - "Assist".into(), - Some(Box::new(Assist)), - tooltip_style, - cx, - ) + .with_tooltip::(1, "Assist", Some(Box::new(Assist)), tooltip_style, cx) } fn render_quote_button(cx: &mut ViewContext) -> impl Element { @@ -446,7 +440,7 @@ impl AssistantPanel { }) .with_tooltip::( 1, - "Quote Selection".into(), + "Quote Selection", Some(Box::new(QuoteSelection)), tooltip_style, cx, @@ -468,7 +462,7 @@ impl AssistantPanel { }) .with_tooltip::( 1, - "New Conversation".into(), + "New Conversation", Some(Box::new(NewConversation)), tooltip_style, cx, @@ -498,11 +492,7 @@ impl AssistantPanel { }) .with_tooltip::( 0, - if self.zoomed { - "Zoom Out".into() - } else { - "Zoom In".into() - }, + if self.zoomed { "Zoom Out" } else { "Zoom In" }, Some(Box::new(ToggleZoom)), tooltip_style, cx, diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index dbcbaf60724c6217872eee459d60fbe3af71e981..fefb1c608f2f8a3a2d5f5e571779467428f444d3 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -238,7 +238,7 @@ impl CollabTitlebarItem { .left() .with_tooltip::( 0, - "Recent projects".into(), + "Recent projects", Some(Box::new(recent_projects::OpenRecent)), theme.tooltip.clone(), cx, @@ -282,7 +282,7 @@ impl CollabTitlebarItem { .left() .with_tooltip::( 0, - "Recent branches".into(), + "Recent branches", Some(Box::new(ToggleVcsMenu)), theme.tooltip.clone(), cx, @@ -582,7 +582,7 @@ impl CollabTitlebarItem { }) .with_tooltip::( 0, - "Show contacts menu".into(), + "Show contacts menu", Some(Box::new(ToggleContactsMenu)), theme.tooltip.clone(), cx, @@ -633,7 +633,7 @@ impl CollabTitlebarItem { }) .with_tooltip::( 0, - tooltip.into(), + tooltip, Some(Box::new(ToggleScreenSharing)), theme.tooltip.clone(), cx, @@ -686,7 +686,7 @@ impl CollabTitlebarItem { }) .with_tooltip::( 0, - tooltip.into(), + tooltip, Some(Box::new(ToggleMute)), theme.tooltip.clone(), cx, @@ -734,7 +734,7 @@ impl CollabTitlebarItem { }) .with_tooltip::( 0, - tooltip.into(), + tooltip, Some(Box::new(ToggleDeafen)), theme.tooltip.clone(), cx, @@ -768,7 +768,7 @@ impl CollabTitlebarItem { }) .with_tooltip::( 0, - tooltip.into(), + tooltip, Some(Box::new(LeaveCall)), theme.tooltip.clone(), cx, diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index 49784523845918b601e2d856fc4fcec6ebe60550..24ecec08e70734a40764b7f167d446b65bb3ec8a 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -1345,7 +1345,7 @@ impl View for ContactList { }) .with_tooltip::( 0, - "Search for new contact".into(), + "Search for new contact", None, theme.tooltip.clone(), cx, diff --git a/crates/copilot_button/src/copilot_button.rs b/crates/copilot_button/src/copilot_button.rs index 5576451b1b0f1ac883ce0497f8df35a4fbcd245a..eae1746a01a01043a8c11da12e79f6ee91a34618 100644 --- a/crates/copilot_button/src/copilot_button.rs +++ b/crates/copilot_button/src/copilot_button.rs @@ -140,7 +140,7 @@ impl View for CopilotButton { }) .with_tooltip::( 0, - "GitHub Copilot".into(), + "GitHub Copilot", None, theme.tooltip.clone(), cx, diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index c106f042b5cf9328724eb72415cf8bea3fcceeff..0ae55e99d950ea5e44ab66787b8ebf86068876e3 100644 --- a/crates/diagnostics/src/items.rs +++ b/crates/diagnostics/src/items.rs @@ -173,7 +173,7 @@ impl View for DiagnosticIndicator { }) .with_tooltip::( 0, - "Project Diagnostics".to_string(), + "Project Diagnostics", Some(Box::new(crate::Deploy)), tooltip_style, cx, diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 02cd58524bb5e6b5b97a17b751d9a2304abbaf11..8d8b77ea9508f89c8edf7c6f15c276917541173c 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -8685,7 +8685,7 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend // We really need to rethink this ID system... .with_tooltip::( cx.block_id, - "Copy diagnostic message".to_string(), + "Copy diagnostic message", None, tooltip_style, cx, diff --git a/crates/feedback/src/deploy_feedback_button.rs b/crates/feedback/src/deploy_feedback_button.rs index beb5284031fc82e157b06240b7dadc04be08be93..d197f57fa529fa37e652194441d716f417fe1246 100644 --- a/crates/feedback/src/deploy_feedback_button.rs +++ b/crates/feedback/src/deploy_feedback_button.rs @@ -66,7 +66,7 @@ impl View for DeployFeedbackButton { }) .with_tooltip::( 0, - "Send Feedback".into(), + "Send Feedback", Some(Box::new(GiveFeedback)), theme.tooltip.clone(), cx, diff --git a/crates/feedback/src/submit_feedback_button.rs b/crates/feedback/src/submit_feedback_button.rs index 03a2cd51eddb94774d02438c2d4d23ff25b00806..2133296e25456e76db6453021d999154dbada199 100644 --- a/crates/feedback/src/submit_feedback_button.rs +++ b/crates/feedback/src/submit_feedback_button.rs @@ -80,7 +80,7 @@ impl View for SubmitFeedbackButton { .with_margin_left(theme.feedback.button_margin) .with_tooltip::( 0, - "cmd-s".into(), + "cmd-s", Some(Box::new(SubmitFeedback)), theme.tooltip.clone(), cx, diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index 5bed935319f6cb89dbdcb0955a66d404ee629e69..bc903fe74cef13f46fe475d0b5ed66211cd8b5a4 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -170,7 +170,7 @@ pub trait Element: 'static { fn with_tooltip( self, id: usize, - text: String, + text: impl Into>, action: Option>, style: TooltipStyle, cx: &mut ViewContext, @@ -178,7 +178,7 @@ pub trait Element: 'static { where Self: 'static + Sized, { - Tooltip::new::(id, text, action, style, self.into_any(), cx) + Tooltip::new::(id, text, action, style, self.into_any(), cx) } fn resizable( diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index 0510baa9e45e2da3764240d6406950f423e5ce0d..14f3809e67ba08995ac2153e48949d2c48397aad 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -12,6 +12,7 @@ use crate::{ use schemars::JsonSchema; use serde::Deserialize; use std::{ + borrow::Cow, cell::{Cell, RefCell}, ops::Range, rc::Rc, @@ -52,9 +53,9 @@ pub struct KeystrokeStyle { } impl Tooltip { - pub fn new( + pub fn new( id: usize, - text: String, + text: impl Into>, action: Option>, style: TooltipStyle, child: AnyElement, @@ -66,6 +67,8 @@ impl Tooltip { let state_handle = cx.default_element_state::, Rc>(id); let state = state_handle.read(cx).clone(); + let text = text.into(); + let tooltip = if state.visible.get() { let mut collapsed_tooltip = Self::render_tooltip( focused_view_id, @@ -127,7 +130,7 @@ impl Tooltip { pub fn render_tooltip( focused_view_id: Option, - text: String, + text: impl Into>, style: TooltipStyle, action: Option>, measure: bool, diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index 6be8a547cd37c8dc8c5fad225b06dd9fcbc6dafd..770cae907c16f6cb016acf1dc10253ab36873b3e 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -72,10 +72,7 @@ impl TerminalPanel { 0, "icons/plus_12.svg", false, - Some(( - "New Terminal".into(), - Some(Box::new(workspace::NewTerminal)), - )), + Some(("New Terminal", Some(Box::new(workspace::NewTerminal)))), cx, move |_, cx| { let this = this.clone(); diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 80644789643b835d6f16ccdb77bf13eb0e5143d0..1463ac2155922cbc8244a0b466e501fea93ef160 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -303,10 +303,10 @@ impl Pane { let tooltip_label; if pane.is_zoomed() { icon_path = "icons/minimize_8.svg"; - tooltip_label = "Zoom In".into(); + tooltip_label = "Zoom In"; } else { icon_path = "icons/maximize_8.svg"; - tooltip_label = "Zoom In".into(); + tooltip_label = "Zoom In"; } Pane::render_tab_bar_button( @@ -1477,7 +1477,7 @@ impl Pane { index: usize, icon: &'static str, is_active: bool, - tooltip: Option<(String, Option>)>, + tooltip: Option<(&'static str, Option>)>, cx: &mut ViewContext, on_click: F1, on_down: F2, diff --git a/crates/workspace/src/toolbar.rs b/crates/workspace/src/toolbar.rs index 69394b842132b61b6403537d76eacf3f6b0b484f..945ac7b0f51bc22f77d6049234c34cabf1d1f116 100644 --- a/crates/workspace/src/toolbar.rs +++ b/crates/workspace/src/toolbar.rs @@ -220,7 +220,7 @@ fn nav_button spacing: f32, on_click: F, tooltip_action: A, - action_name: &str, + action_name: &'static str, cx: &mut ViewContext, ) -> AnyElement { MouseEventHandler::::new(0, cx, |state, _| { @@ -252,7 +252,7 @@ fn nav_button }) .with_tooltip::( 0, - action_name.to_string(), + action_name, Some(Box::new(tooltip_action)), tooltip_style, cx, From 7970406694bb1e523fb582e8dbd00662887fcb33 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 11 Aug 2023 17:56:56 -0700 Subject: [PATCH 2/8] Add a compile test for the element derive --- Cargo.lock | 1 + crates/gpui/src/elements.rs | 4 ++++ crates/gpui_macros/Cargo.toml | 2 ++ crates/gpui_macros/src/gpui_macros.rs | 8 ++++++-- crates/gpui_macros/tests/test.rs | 14 ++++++++++++++ 5 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 crates/gpui_macros/tests/test.rs diff --git a/Cargo.lock b/Cargo.lock index a0be9756bfd4da7d747c07300a62bc5fb0ad226c..1ff9981a6a0bd52e9d1ac24169fbc428db1ff0ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3172,6 +3172,7 @@ dependencies = [ name = "gpui_macros" version = "0.1.0" dependencies = [ + "gpui", "proc-macro2", "quote", "syn 1.0.109", diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index bc903fe74cef13f46fe475d0b5ed66211cd8b5a4..56a712802b63cb432eef1718e04de3166293cd9d 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -201,6 +201,10 @@ pub trait Element: 'static { } } +pub trait RenderElement { + fn render(&mut self, view: &mut V, cx: &mut ViewContext) -> AnyElement; +} + trait AnyElementState { fn layout( &mut self, diff --git a/crates/gpui_macros/Cargo.toml b/crates/gpui_macros/Cargo.toml index 76daeae2a844fd5361d7014ce592d3df575e4beb..9ff340299b6730ea063f92f1c15c947739142511 100644 --- a/crates/gpui_macros/Cargo.toml +++ b/crates/gpui_macros/Cargo.toml @@ -14,3 +14,5 @@ syn = "1.0" quote = "1.0" proc-macro2 = "1.0" +[dev-dependencies] +gpui = { path = "../gpui" } diff --git a/crates/gpui_macros/src/gpui_macros.rs b/crates/gpui_macros/src/gpui_macros.rs index dbf57b83e5bececd63fd7c5963e8ea0514b81708..2e6c7258727fb306c91c1dc2d3ac22fc1d2e4490 100644 --- a/crates/gpui_macros/src/gpui_macros.rs +++ b/crates/gpui_macros/src/gpui_macros.rs @@ -283,8 +283,12 @@ pub fn element_derive(input: TokenStream) -> TokenStream { // The name of the struct/enum let name = input.ident; + let must_implement = format_ident!("{}MustImplementRenderElement", name); let expanded = quote! { + trait #must_implement : gpui::elements::RenderElement {} + impl #must_implement for #name {} + impl gpui::elements::Element for #name { type LayoutState = gpui::elements::AnyElement; type PaintState = (); @@ -307,7 +311,7 @@ pub fn element_derive(input: TokenStream) -> TokenStream { visible_bounds: gpui::geometry::rect::RectF, element: &mut gpui::elements::AnyElement, view: &mut V, - cx: &mut gpui::ViewContext, + cx: &mut gpui::PaintContext, ) { element.paint(scene, bounds.origin(), visible_bounds, view, cx); } @@ -332,7 +336,7 @@ pub fn element_derive(input: TokenStream) -> TokenStream { _: &(), view: &V, cx: &gpui::ViewContext, - ) -> serde_json::Value { + ) -> gpui::serde_json::Value { element.debug(view, cx) } } diff --git a/crates/gpui_macros/tests/test.rs b/crates/gpui_macros/tests/test.rs new file mode 100644 index 0000000000000000000000000000000000000000..b5a91a7e98017dbd05b0d78e80f500745b22c5fc --- /dev/null +++ b/crates/gpui_macros/tests/test.rs @@ -0,0 +1,14 @@ +use gpui::{elements::RenderElement, View, ViewContext}; +use gpui_macros::Element; + +#[test] +fn test_derive_render_element() { + #[derive(Element)] + struct TestElement {} + + impl RenderElement for TestElement { + fn render(&mut self, _: &mut V, _: &mut ViewContext) -> gpui::AnyElement { + unimplemented!() + } + } +} From 84dc4090bd2c738637022171c530cbb45ee8af7c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 12 Aug 2023 10:40:23 -0600 Subject: [PATCH 3/8] Wire up per corner radii for quad Still need to expose this in the styling layer and allow images to have per corner radii. --- crates/collab_ui/src/contact_list.rs | 8 +- crates/editor/src/element.rs | 26 ++-- crates/editor/src/hover_popover.rs | 2 +- crates/gpui/examples/quad.rs | 120 ++++++++++++++++++ crates/gpui/src/elements/container.rs | 8 +- crates/gpui/src/platform/mac/renderer.rs | 5 +- .../gpui/src/platform/mac/shaders/shaders.h | 5 +- .../src/platform/mac/shaders/shaders.metal | 36 +++++- crates/gpui/src/scene.rs | 21 ++- crates/terminal_view/src/terminal_element.rs | 4 +- crates/workspace/src/pane.rs | 2 +- .../src/pane/dragged_item_receiver.rs | 2 +- crates/workspace/src/workspace.rs | 2 +- 13 files changed, 205 insertions(+), 36 deletions(-) create mode 100644 crates/gpui/examples/quad.rs diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index 24ecec08e70734a40764b7f167d446b65bb3ec8a..b8024e2bfd59321925c2d5fe61650ab104b5d875 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -837,7 +837,7 @@ impl ContactList { ), background: Some(tree_branch.color), border: gpui::Border::default(), - corner_radius: 0., + corner_radii: Default::default(), }); scene.push_quad(gpui::Quad { bounds: RectF::from_points( @@ -846,7 +846,7 @@ impl ContactList { ), background: Some(tree_branch.color), border: gpui::Border::default(), - corner_radius: 0., + corner_radii: Default::default(), }); })) .constrained() @@ -934,7 +934,7 @@ impl ContactList { ), background: Some(tree_branch.color), border: gpui::Border::default(), - corner_radius: 0., + corner_radii: Default::default(), }); scene.push_quad(gpui::Quad { bounds: RectF::from_points( @@ -943,7 +943,7 @@ impl ContactList { ), background: Some(tree_branch.color), border: gpui::Border::default(), - corner_radius: 0., + corner_radii: Default::default(), }); })) .constrained() diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 0ea4ff758bd1edb040d56d1ad6b70656117c182f..24b4811b61dcb8df7396d479732cea5b6c3714c7 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -488,13 +488,13 @@ impl EditorElement { bounds: gutter_bounds, background: Some(self.style.gutter_background), border: Border::new(0., Color::transparent_black()), - corner_radius: 0., + corner_radii: Default::default(), }); scene.push_quad(Quad { bounds: text_bounds, background: Some(self.style.background), border: Border::new(0., Color::transparent_black()), - corner_radius: 0., + corner_radii: Default::default(), }); if let EditorMode::Full = layout.mode { @@ -522,7 +522,7 @@ impl EditorElement { bounds: RectF::new(origin, size), background: Some(self.style.active_line_background), border: Border::default(), - corner_radius: 0., + corner_radii: Default::default(), }); } } @@ -542,7 +542,7 @@ impl EditorElement { bounds: RectF::new(origin, size), background: Some(self.style.highlighted_line_background), border: Border::default(), - corner_radius: 0., + corner_radii: Default::default(), }); } @@ -572,7 +572,7 @@ impl EditorElement { ), background: Some(color), border: Border::new(0., Color::transparent_black()), - corner_radius: 0., + corner_radii: Default::default(), }); } } @@ -673,7 +673,7 @@ impl EditorElement { bounds: highlight_bounds, background: Some(diff_style.modified), border: Border::new(0., Color::transparent_black()), - corner_radius: 1. * line_height, + corner_radii: (1. * line_height).into(), }); continue; @@ -706,7 +706,7 @@ impl EditorElement { bounds: highlight_bounds, background: Some(diff_style.deleted), border: Border::new(0., Color::transparent_black()), - corner_radius: 1. * line_height, + corner_radii: (1. * line_height).into(), }); continue; @@ -728,7 +728,7 @@ impl EditorElement { bounds: highlight_bounds, background: Some(color), border: Border::new(0., Color::transparent_black()), - corner_radius: diff_style.corner_radius * line_height, + corner_radii: (diff_style.corner_radius * line_height).into(), }); } } @@ -1129,7 +1129,7 @@ impl EditorElement { bounds, background: Some(color), border, - corner_radius: style.thumb.corner_radius, + corner_radii: style.thumb.corner_radius.into(), }) }; let background_ranges = editor @@ -1189,7 +1189,7 @@ impl EditorElement { bounds, background: Some(color), border, - corner_radius: style.thumb.corner_radius, + corner_radii: style.thumb.corner_radius.into(), }) } } @@ -1198,7 +1198,7 @@ impl EditorElement { bounds: thumb_bounds, border: style.thumb.border, background: style.thumb.background_color, - corner_radius: style.thumb.corner_radius, + corner_radii: style.thumb.corner_radius.into(), }); } @@ -2725,14 +2725,14 @@ impl Cursor { bounds, background: None, border: Border::all(1., self.color), - corner_radius: 0., + corner_radii: Default::default(), }); } else { scene.push_quad(Quad { bounds, background: Some(self.color), border: Default::default(), - corner_radius: 0., + corner_radii: Default::default(), }); } diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index 92ed9ef77d52225eb60e1ff1c119bcefdb2f3385..afc13f983d30aacac863cbc8824ca47d71be79ef 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -599,7 +599,7 @@ impl InfoPopover { bounds, background: Some(code_span_background_color), border: Default::default(), - corner_radius: 2.0, + corner_radii: (2.0).into(), }); } }, diff --git a/crates/gpui/examples/quad.rs b/crates/gpui/examples/quad.rs new file mode 100644 index 0000000000000000000000000000000000000000..5d796111c68fe9da117b54d1d841d3f442ee6b13 --- /dev/null +++ b/crates/gpui/examples/quad.rs @@ -0,0 +1,120 @@ +use gpui::{color::Color, geometry::rect::RectF, AnyElement, App, Element, Entity, Quad, View}; +use log::LevelFilter; +use pathfinder_geometry::vector::vec2f; +use simplelog::SimpleLogger; + +fn main() { + SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); + + App::new(()).unwrap().run(|cx| { + cx.platform().activate(true); + cx.add_window(Default::default(), |_| QuadView); + }); +} + +struct QuadView; + +impl Entity for QuadView { + type Event = (); +} + +impl View for QuadView { + fn ui_name() -> &'static str { + "QuadView" + } + + fn render(&mut self, _: &mut gpui::ViewContext) -> AnyElement { + QuadElement.into_any() + } +} + +struct QuadElement; + +impl gpui::Element for QuadElement { + type LayoutState = (); + + type PaintState = (); + + fn layout( + &mut self, + constraint: gpui::SizeConstraint, + _: &mut V, + _: &mut gpui::LayoutContext, + ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { + (constraint.max, ()) + } + + fn paint( + &mut self, + scene: &mut gpui::SceneBuilder, + _: pathfinder_geometry::rect::RectF, + _: pathfinder_geometry::rect::RectF, + _: &mut Self::LayoutState, + _: &mut V, + _: &mut gpui::PaintContext, + ) -> Self::PaintState { + scene.push_quad(Quad { + bounds: RectF::new(vec2f(100., 100.), vec2f(100., 100.)), + background: Some(Color::red()), + border: Default::default(), + corner_radii: gpui::scene::CornerRadii { + top_left: 20., + ..Default::default() + }, + }); + + scene.push_quad(Quad { + bounds: RectF::new(vec2f(200., 100.), vec2f(100., 100.)), + background: Some(Color::green()), + border: Default::default(), + corner_radii: gpui::scene::CornerRadii { + top_right: 20., + ..Default::default() + }, + }); + + scene.push_quad(Quad { + bounds: RectF::new(vec2f(100., 200.), vec2f(100., 100.)), + background: Some(Color::blue()), + border: Default::default(), + corner_radii: gpui::scene::CornerRadii { + bottom_left: 20., + ..Default::default() + }, + }); + + scene.push_quad(Quad { + bounds: RectF::new(vec2f(200., 200.), vec2f(100., 100.)), + background: Some(Color::yellow()), + border: Default::default(), + corner_radii: gpui::scene::CornerRadii { + bottom_right: 20., + ..Default::default() + }, + }); + } + + fn rect_for_text_range( + &self, + _: std::ops::Range, + _: pathfinder_geometry::rect::RectF, + _: pathfinder_geometry::rect::RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + _: &V, + _: &gpui::ViewContext, + ) -> Option { + unimplemented!() + } + + fn debug( + &self, + _: pathfinder_geometry::rect::RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + _: &V, + _: &gpui::ViewContext, + ) -> serde_json::Value { + unimplemented!() + } +} diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index 656847980c9095c2dcfe0914e1d3b34c3a1556be..df6f35caaf6f6e77979e616aeeeb0cbf98c435cd 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -248,7 +248,7 @@ impl Element for Container { bounds: quad_bounds, background: self.style.background_color, border: Default::default(), - corner_radius: self.style.corner_radius, + corner_radii: self.style.corner_radius.into(), }); self.child @@ -259,7 +259,7 @@ impl Element for Container { bounds: quad_bounds, background: self.style.overlay_color, border: self.style.border, - corner_radius: self.style.corner_radius, + corner_radii: self.style.corner_radius.into(), }); scene.pop_layer(); } else { @@ -267,7 +267,7 @@ impl Element for Container { bounds: quad_bounds, background: self.style.background_color, border: self.style.border, - corner_radius: self.style.corner_radius, + corner_radii: self.style.corner_radius.into(), }); let child_origin = child_origin @@ -284,7 +284,7 @@ impl Element for Container { bounds: quad_bounds, background: self.style.overlay_color, border: Default::default(), - corner_radius: 0., + corner_radii: self.style.corner_radius.into(), }); scene.pop_layer(); } diff --git a/crates/gpui/src/platform/mac/renderer.rs b/crates/gpui/src/platform/mac/renderer.rs index 24c44bb69833a2454cc7b18701bbf5d789ed30fd..c743f00f92413aad3a0a4538a51723aa61435d1f 100644 --- a/crates/gpui/src/platform/mac/renderer.rs +++ b/crates/gpui/src/platform/mac/renderer.rs @@ -586,7 +586,10 @@ impl Renderer { border_bottom: border_width * (quad.border.bottom as usize as f32), border_left: border_width * (quad.border.left as usize as f32), border_color: quad.border.color.to_uchar4(), - corner_radius: quad.corner_radius * scale_factor, + corner_radius_top_left: quad.corner_radii.top_left * scale_factor, + corner_radius_top_right: quad.corner_radii.top_right * scale_factor, + corner_radius_bottom_right: quad.corner_radii.bottom_right * scale_factor, + corner_radius_bottom_left: quad.corner_radii.bottom_left * scale_factor, }; unsafe { *(buffer_contents.add(ix)) = shader_quad; diff --git a/crates/gpui/src/platform/mac/shaders/shaders.h b/crates/gpui/src/platform/mac/shaders/shaders.h index 6e0ed1a5f1b5ef89182e5fb46518b0801d5a9cb0..9e8ec538879c7db25b4f95ccf0712d66a62a1053 100644 --- a/crates/gpui/src/platform/mac/shaders/shaders.h +++ b/crates/gpui/src/platform/mac/shaders/shaders.h @@ -19,7 +19,10 @@ typedef struct { float border_bottom; float border_left; vector_uchar4 border_color; - float corner_radius; + float corner_radius_top_left; + float corner_radius_top_right; + float corner_radius_bottom_right; + float corner_radius_bottom_left; } GPUIQuad; typedef enum { diff --git a/crates/gpui/src/platform/mac/shaders/shaders.metal b/crates/gpui/src/platform/mac/shaders/shaders.metal index 397e7647c47107b5176880a0e0fd1ba2adbaecda..ac7b9ac20839ed85c3102659a9a57960309f5be1 100644 --- a/crates/gpui/src/platform/mac/shaders/shaders.metal +++ b/crates/gpui/src/platform/mac/shaders/shaders.metal @@ -43,7 +43,10 @@ struct QuadFragmentInput { float border_bottom; float border_left; float4 border_color; - float corner_radius; + float corner_radius_top_left; + float corner_radius_top_right; + float corner_radius_bottom_right; + float corner_radius_bottom_left; uchar grayscale; // only used in image shader }; @@ -51,12 +54,27 @@ float4 quad_sdf(QuadFragmentInput input) { float2 half_size = input.size / 2.; float2 center = input.origin + half_size; float2 center_to_point = input.position.xy - center; - float2 rounded_edge_to_point = abs(center_to_point) - half_size + input.corner_radius; - float distance = length(max(0., rounded_edge_to_point)) + min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) - input.corner_radius; + float corner_radius; + if (center_to_point.x < 0.) { + if (center_to_point.y < 0.) { + corner_radius = input.corner_radius_top_left; + } else { + corner_radius = input.corner_radius_bottom_left; + } + } else { + if (center_to_point.y < 0.) { + corner_radius = input.corner_radius_top_right; + } else { + corner_radius = input.corner_radius_bottom_right; + } + } + + float2 rounded_edge_to_point = abs(center_to_point) - half_size + corner_radius; + float distance = length(max(0., rounded_edge_to_point)) + min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) - corner_radius; float vertical_border = center_to_point.x <= 0. ? input.border_left : input.border_right; float horizontal_border = center_to_point.y <= 0. ? input.border_top : input.border_bottom; - float2 inset_size = half_size - input.corner_radius - float2(vertical_border, horizontal_border); + float2 inset_size = half_size - corner_radius - float2(vertical_border, horizontal_border); float2 point_to_inset_corner = abs(center_to_point) - inset_size; float border_width; if (point_to_inset_corner.x < 0. && point_to_inset_corner.y < 0.) { @@ -110,7 +128,10 @@ vertex QuadFragmentInput quad_vertex( quad.border_bottom, quad.border_left, coloru_to_colorf(quad.border_color), - quad.corner_radius, + quad.corner_radius_top_left, + quad.corner_radius_top_right, + quad.corner_radius_bottom_right, + quad.corner_radius_bottom_left, 0, }; } @@ -253,6 +274,9 @@ vertex QuadFragmentInput image_vertex( image.border_left, coloru_to_colorf(image.border_color), image.corner_radius, + image.corner_radius, + image.corner_radius, + image.corner_radius, image.grayscale, }; } @@ -266,7 +290,7 @@ fragment float4 image_fragment( if (input.grayscale) { float grayscale = 0.2126 * input.background_color.r + - 0.7152 * input.background_color.g + + 0.7152 * input.background_color.g + 0.0722 * input.background_color.b; input.background_color = float4(grayscale, grayscale, grayscale, input.background_color.a); } diff --git a/crates/gpui/src/scene.rs b/crates/gpui/src/scene.rs index 7793a28ee0d9dea61ae1f46f6df475b5a8824ce6..ac45e0eb94ae0458c3e0d7c70ada61f14c8d5de5 100644 --- a/crates/gpui/src/scene.rs +++ b/crates/gpui/src/scene.rs @@ -65,7 +65,26 @@ pub struct Quad { pub bounds: RectF, pub background: Option, pub border: Border, - pub corner_radius: f32, + pub corner_radii: CornerRadii, +} + +#[derive(Default, Debug)] +pub struct CornerRadii { + pub top_left: f32, + pub top_right: f32, + pub bottom_right: f32, + pub bottom_left: f32, +} + +impl From for CornerRadii { + fn from(radius: f32) -> Self { + Self { + top_left: radius, + top_right: radius, + bottom_right: radius, + bottom_left: radius, + } + } } #[derive(Debug)] diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index bf7b6e6aac49d299b0755dbf9eea34c182e5807d..232d3c5535bd76842ca3e0b16790ed7140bf2574 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -153,7 +153,7 @@ impl LayoutRect { bounds: RectF::new(position, size), background: Some(self.color), border: Default::default(), - corner_radius: 0., + corner_radii: Default::default(), }) } } @@ -763,7 +763,7 @@ impl Element for TerminalElement { bounds: RectF::new(bounds.origin(), bounds.size()), background: Some(layout.background_color), border: Default::default(), - corner_radius: 0., + corner_radii: Default::default(), }); for rect in &layout.rects { diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 1463ac2155922cbc8244a0b466e501fea93ef160..06f13cd52d1ad39f38bd8beee059d20e71ef17ff 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1397,7 +1397,7 @@ impl Pane { bounds: square, background: Some(color), border: Default::default(), - corner_radius: diameter / 2., + corner_radii: (diameter / 2.).into(), }); } }) diff --git a/crates/workspace/src/pane/dragged_item_receiver.rs b/crates/workspace/src/pane/dragged_item_receiver.rs index 2d3fe8ea8324411a7de5c2a70c1254648994652e..165537a1af48b2aab3612302dcef9cd191a67d69 100644 --- a/crates/workspace/src/pane/dragged_item_receiver.rs +++ b/crates/workspace/src/pane/dragged_item_receiver.rs @@ -61,7 +61,7 @@ where bounds: overlay_region, background: Some(overlay_color(cx)), border: Default::default(), - corner_radius: 0., + corner_radii: Default::default(), }); }); } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 1612aadc2f54c682ad17596d91a41ed2ee7f523d..ab4f7286dccbf57116efdd97abd0e98cb1233222 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -3614,7 +3614,7 @@ fn notify_of_new_dock(workspace: &WeakViewHandle, cx: &mut AsyncAppCo bounds, background: Some(code_span_background_color), border: Default::default(), - corner_radius: 2.0, + corner_radii: (2.0).into(), }) }) .into_any() From 40f478937edee69190771b0ceaeea993bdd10456 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 12 Aug 2023 10:50:04 -0600 Subject: [PATCH 4/8] Allow distinct corner radii for images --- crates/gpui/src/elements/image.rs | 2 +- crates/gpui/src/platform/mac/renderer.rs | 12 +++++++++--- crates/gpui/src/platform/mac/shaders/shaders.h | 5 ++++- crates/gpui/src/platform/mac/shaders/shaders.metal | 8 ++++---- crates/gpui/src/scene.rs | 5 +++-- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/crates/gpui/src/elements/image.rs b/crates/gpui/src/elements/image.rs index e87c06591756ccdbc463dbc03af88dd1adc3aa5f..034494221d88d520deabf947521d8a2364176e4b 100644 --- a/crates/gpui/src/elements/image.rs +++ b/crates/gpui/src/elements/image.rs @@ -103,7 +103,7 @@ impl Element for Image { scene.push_image(scene::Image { bounds, border: self.style.border, - corner_radius: self.style.corner_radius, + corner_radii: self.style.corner_radius.into(), grayscale: self.style.grayscale, data: data.clone(), }); diff --git a/crates/gpui/src/platform/mac/renderer.rs b/crates/gpui/src/platform/mac/renderer.rs index c743f00f92413aad3a0a4538a51723aa61435d1f..1cc3d33b2aa3838c80397fb61b7f20252c3a327e 100644 --- a/crates/gpui/src/platform/mac/renderer.rs +++ b/crates/gpui/src/platform/mac/renderer.rs @@ -741,7 +741,7 @@ impl Renderer { for image in images { let origin = image.bounds.origin() * scale_factor; let target_size = image.bounds.size() * scale_factor; - let corner_radius = image.corner_radius * 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 @@ -757,7 +757,10 @@ impl Renderer { border_bottom: border_width * (image.border.bottom as usize as f32), border_left: border_width * (image.border.left as usize as f32), border_color: image.border.color.to_uchar4(), - corner_radius, + corner_radius_top_left: corner_radii.top_left, + corner_radius_top_right: corner_radii.top_right, + corner_radius_bottom_right: corner_radii.bottom_right, + corner_radius_bottom_left: corner_radii.bottom_left, grayscale: image.grayscale as u8, }); } @@ -780,7 +783,10 @@ impl Renderer { border_bottom: 0., border_left: 0., border_color: Default::default(), - corner_radius: 0., + corner_radius_top_left: 0., + corner_radius_top_right: 0., + corner_radius_bottom_right: 0., + corner_radius_bottom_left: 0., grayscale: false as u8, }); } else { diff --git a/crates/gpui/src/platform/mac/shaders/shaders.h b/crates/gpui/src/platform/mac/shaders/shaders.h index 9e8ec538879c7db25b4f95ccf0712d66a62a1053..ac8389e1f616771714b6bec85b9b3d01c63f6971 100644 --- a/crates/gpui/src/platform/mac/shaders/shaders.h +++ b/crates/gpui/src/platform/mac/shaders/shaders.h @@ -92,7 +92,10 @@ typedef struct { float border_bottom; float border_left; vector_uchar4 border_color; - float corner_radius; + float corner_radius_top_left; + float corner_radius_top_right; + float corner_radius_bottom_right; + float corner_radius_bottom_left; uint8_t grayscale; } GPUIImage; diff --git a/crates/gpui/src/platform/mac/shaders/shaders.metal b/crates/gpui/src/platform/mac/shaders/shaders.metal index ac7b9ac20839ed85c3102659a9a57960309f5be1..cc38f3df7a56b628e16e5ded8ade218ed100d885 100644 --- a/crates/gpui/src/platform/mac/shaders/shaders.metal +++ b/crates/gpui/src/platform/mac/shaders/shaders.metal @@ -273,10 +273,10 @@ vertex QuadFragmentInput image_vertex( image.border_bottom, image.border_left, coloru_to_colorf(image.border_color), - image.corner_radius, - image.corner_radius, - image.corner_radius, - image.corner_radius, + image.corner_radius_top_left, + image.corner_radius_top_right, + image.corner_radius_bottom_right, + image.corner_radius_bottom_left, image.grayscale, }; } diff --git a/crates/gpui/src/scene.rs b/crates/gpui/src/scene.rs index ac45e0eb94ae0458c3e0d7c70ada61f14c8d5de5..abc763b73b72f863ba1fe8a058c7f8714abe457a 100644 --- a/crates/gpui/src/scene.rs +++ b/crates/gpui/src/scene.rs @@ -3,6 +3,7 @@ mod mouse_region; #[cfg(debug_assertions)] use collections::HashSet; +use derive_more::Mul; use schemars::JsonSchema; use serde::Deserialize; use serde_json::json; @@ -68,7 +69,7 @@ pub struct Quad { pub corner_radii: CornerRadii, } -#[derive(Default, Debug)] +#[derive(Default, Debug, Mul, Clone, Copy)] pub struct CornerRadii { pub top_left: f32, pub top_right: f32, @@ -196,7 +197,7 @@ pub struct PathVertex { pub struct Image { pub bounds: RectF, pub border: Border, - pub corner_radius: f32, + pub corner_radii: CornerRadii, pub grayscale: bool, pub data: Arc, } From 65123e6eedb75d780808e4281c48a6810c07d22b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 12 Aug 2023 10:58:04 -0600 Subject: [PATCH 5/8] Allow individual corner radii on drop shadows --- crates/editor/src/element.rs | 6 ++--- crates/gpui/src/elements/container.rs | 21 ++++++++------- crates/gpui/src/platform/mac/renderer.rs | 6 ++++- .../gpui/src/platform/mac/shaders/shaders.h | 5 +++- .../src/platform/mac/shaders/shaders.metal | 26 ++++++++++++++++--- crates/gpui/src/scene.rs | 5 ++-- 6 files changed, 50 insertions(+), 19 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 24b4811b61dcb8df7396d479732cea5b6c3714c7..13856cc8efac77132f3d51f25c56b69f93643068 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1129,7 +1129,7 @@ impl EditorElement { bounds, background: Some(color), border, - corner_radii: style.thumb.corner_radius.into(), + corner_radii: style.thumb.corner_radii.into(), }) }; let background_ranges = editor @@ -1189,7 +1189,7 @@ impl EditorElement { bounds, background: Some(color), border, - corner_radii: style.thumb.corner_radius.into(), + corner_radii: style.thumb.corner_radii.into(), }) } } @@ -1198,7 +1198,7 @@ impl EditorElement { bounds: thumb_bounds, border: style.thumb.border, background: style.thumb.background_color, - corner_radii: style.thumb.corner_radius.into(), + corner_radii: style.thumb.corner_radii.into(), }); } diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index df6f35caaf6f6e77979e616aeeeb0cbf98c435cd..984742e818f82cc9a5be8310d1139ebb84a82e34 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -9,7 +9,7 @@ use crate::{ }, json::ToJson, platform::CursorStyle, - scene::{self, Border, CursorRegion, Quad}, + scene::{self, Border, CornerRadii, CursorRegion, Quad}, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View, ViewContext, }; @@ -30,7 +30,7 @@ pub struct ContainerStyle { #[serde(default)] pub border: Border, #[serde(default)] - pub corner_radius: f32, + pub corner_radii: CornerRadii, #[serde(default)] pub shadow: Option, #[serde(default)] @@ -133,7 +133,10 @@ impl Container { } pub fn with_corner_radius(mut self, radius: f32) -> Self { - self.style.corner_radius = radius; + self.style.corner_radii.top_left = radius; + self.style.corner_radii.top_right = radius; + self.style.corner_radii.bottom_right = radius; + self.style.corner_radii.bottom_left = radius; self } @@ -225,7 +228,7 @@ impl Element for Container { if let Some(shadow) = self.style.shadow.as_ref() { scene.push_shadow(scene::Shadow { bounds: quad_bounds + shadow.offset, - corner_radius: self.style.corner_radius, + corner_radii: self.style.corner_radii, sigma: shadow.blur, color: shadow.color, }); @@ -248,7 +251,7 @@ impl Element for Container { bounds: quad_bounds, background: self.style.background_color, border: Default::default(), - corner_radii: self.style.corner_radius.into(), + corner_radii: self.style.corner_radii.into(), }); self.child @@ -259,7 +262,7 @@ impl Element for Container { bounds: quad_bounds, background: self.style.overlay_color, border: self.style.border, - corner_radii: self.style.corner_radius.into(), + corner_radii: self.style.corner_radii.into(), }); scene.pop_layer(); } else { @@ -267,7 +270,7 @@ impl Element for Container { bounds: quad_bounds, background: self.style.background_color, border: self.style.border, - corner_radii: self.style.corner_radius.into(), + corner_radii: self.style.corner_radii.into(), }); let child_origin = child_origin @@ -284,7 +287,7 @@ impl Element for Container { bounds: quad_bounds, background: self.style.overlay_color, border: Default::default(), - corner_radii: self.style.corner_radius.into(), + corner_radii: self.style.corner_radii.into(), }); scene.pop_layer(); } @@ -328,7 +331,7 @@ impl ToJson for ContainerStyle { "padding": self.padding.to_json(), "background_color": self.background_color.to_json(), "border": self.border.to_json(), - "corner_radius": self.corner_radius, + "corner_radius": self.corner_radii, "shadow": self.shadow.to_json(), }) } diff --git a/crates/gpui/src/platform/mac/renderer.rs b/crates/gpui/src/platform/mac/renderer.rs index 1cc3d33b2aa3838c80397fb61b7f20252c3a327e..5fe9e34ee484ba1b4285e430eeb6f519cbce7b9c 100644 --- a/crates/gpui/src/platform/mac/renderer.rs +++ b/crates/gpui/src/platform/mac/renderer.rs @@ -509,10 +509,14 @@ impl Renderer { }; for (ix, shadow) in shadows.iter().enumerate() { let shape_bounds = shadow.bounds * scale_factor; + let corner_radii = shadow.corner_radii * scale_factor; let shader_shadow = shaders::GPUIShadow { origin: shape_bounds.origin().to_float2(), size: shape_bounds.size().to_float2(), - corner_radius: shadow.corner_radius * scale_factor, + corner_radius_top_left: corner_radii.top_left, + corner_radius_top_right: corner_radii.top_right, + corner_radius_bottom_right: corner_radii.bottom_right, + corner_radius_bottom_left: corner_radii.bottom_left, sigma: shadow.sigma, color: shadow.color.to_uchar4(), }; diff --git a/crates/gpui/src/platform/mac/shaders/shaders.h b/crates/gpui/src/platform/mac/shaders/shaders.h index ac8389e1f616771714b6bec85b9b3d01c63f6971..b73e5f8e9890c558bc29e71dc70f6b8619a974c4 100644 --- a/crates/gpui/src/platform/mac/shaders/shaders.h +++ b/crates/gpui/src/platform/mac/shaders/shaders.h @@ -34,7 +34,10 @@ typedef enum { typedef struct { vector_float2 origin; vector_float2 size; - float corner_radius; + float corner_radius_top_left; + float corner_radius_top_right; + float corner_radius_bottom_right; + float corner_radius_bottom_left; float sigma; vector_uchar4 color; } GPUIShadow; diff --git a/crates/gpui/src/platform/mac/shaders/shaders.metal b/crates/gpui/src/platform/mac/shaders/shaders.metal index cc38f3df7a56b628e16e5ded8ade218ed100d885..b803094cf65d8bb7bf01cc8ee491715b63f47ce3 100644 --- a/crates/gpui/src/platform/mac/shaders/shaders.metal +++ b/crates/gpui/src/platform/mac/shaders/shaders.metal @@ -146,7 +146,10 @@ struct ShadowFragmentInput { float4 position [[position]]; vector_float2 origin; vector_float2 size; - float corner_radius; + float corner_radius_top_left; + float corner_radius_top_right; + float corner_radius_bottom_right; + float corner_radius_bottom_left; float sigma; vector_uchar4 color; }; @@ -169,7 +172,10 @@ vertex ShadowFragmentInput shadow_vertex( device_position, shadow.origin, shadow.size, - shadow.corner_radius, + shadow.corner_radius_top_left, + shadow.corner_radius_top_right, + shadow.corner_radius_bottom_right, + shadow.corner_radius_bottom_left, shadow.sigma, shadow.color, }; @@ -179,10 +185,24 @@ fragment float4 shadow_fragment( ShadowFragmentInput input [[stage_in]] ) { float sigma = input.sigma; - float corner_radius = input.corner_radius; float2 half_size = input.size / 2.; float2 center = input.origin + half_size; float2 point = input.position.xy - center; + float2 center_to_point = input.position.xy - center; + float corner_radius; + if (center_to_point.x < 0.) { + if (center_to_point.y < 0.) { + corner_radius = input.corner_radius_top_left; + } else { + corner_radius = input.corner_radius_bottom_left; + } + } else { + if (center_to_point.y < 0.) { + corner_radius = input.corner_radius_top_right; + } else { + corner_radius = input.corner_radius_bottom_right; + } + } // The signal is only non-zero in a limited range, so don't waste samples float low = point.y - half_size.y; diff --git a/crates/gpui/src/scene.rs b/crates/gpui/src/scene.rs index abc763b73b72f863ba1fe8a058c7f8714abe457a..48649c57918b4f9bdef7fc8ab6b3d88b1b7d509f 100644 --- a/crates/gpui/src/scene.rs +++ b/crates/gpui/src/scene.rs @@ -6,6 +6,7 @@ use collections::HashSet; use derive_more::Mul; use schemars::JsonSchema; use serde::Deserialize; +use serde_derive::Serialize; use serde_json::json; use std::{borrow::Cow, sync::Arc}; @@ -69,7 +70,7 @@ pub struct Quad { pub corner_radii: CornerRadii, } -#[derive(Default, Debug, Mul, Clone, Copy)] +#[derive(Default, Debug, Mul, Clone, Copy, Deserialize, Serialize, JsonSchema)] pub struct CornerRadii { pub top_left: f32, pub top_right: f32, @@ -91,7 +92,7 @@ impl From for CornerRadii { #[derive(Debug)] pub struct Shadow { pub bounds: RectF, - pub corner_radius: f32, + pub corner_radii: CornerRadii, pub sigma: f32, pub color: Color, } From fa7ebd08253379dbfab0ce08009446d80639720a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 12 Aug 2023 11:08:27 -0600 Subject: [PATCH 6/8] Include drop shadows with different corner radii in the example --- .../examples/{quad.rs => corner_radii.rs} | 57 +++++++++++++++---- 1 file changed, 46 insertions(+), 11 deletions(-) rename crates/gpui/examples/{quad.rs => corner_radii.rs} (67%) diff --git a/crates/gpui/examples/quad.rs b/crates/gpui/examples/corner_radii.rs similarity index 67% rename from crates/gpui/examples/quad.rs rename to crates/gpui/examples/corner_radii.rs index 5d796111c68fe9da117b54d1d841d3f442ee6b13..1f33917529e55545a2d290699b255b1587cf32c5 100644 --- a/crates/gpui/examples/quad.rs +++ b/crates/gpui/examples/corner_radii.rs @@ -1,4 +1,7 @@ -use gpui::{color::Color, geometry::rect::RectF, AnyElement, App, Element, Entity, Quad, View}; +use gpui::{ + color::Color, geometry::rect::RectF, scene::Shadow, AnyElement, App, Element, Entity, Quad, + View, +}; use log::LevelFilter; use pathfinder_geometry::vector::vec2f; use simplelog::SimpleLogger; @@ -8,29 +11,29 @@ fn main() { App::new(()).unwrap().run(|cx| { cx.platform().activate(true); - cx.add_window(Default::default(), |_| QuadView); + cx.add_window(Default::default(), |_| CornersView); }); } -struct QuadView; +struct CornersView; -impl Entity for QuadView { +impl Entity for CornersView { type Event = (); } -impl View for QuadView { +impl View for CornersView { fn ui_name() -> &'static str { - "QuadView" + "CornersView" } - fn render(&mut self, _: &mut gpui::ViewContext) -> AnyElement { - QuadElement.into_any() + fn render(&mut self, _: &mut gpui::ViewContext) -> AnyElement { + CornersElement.into_any() } } -struct QuadElement; +struct CornersElement; -impl gpui::Element for QuadElement { +impl gpui::Element for CornersElement { type LayoutState = (); type PaintState = (); @@ -47,12 +50,20 @@ impl gpui::Element for QuadElement { fn paint( &mut self, scene: &mut gpui::SceneBuilder, - _: pathfinder_geometry::rect::RectF, + bounds: pathfinder_geometry::rect::RectF, _: pathfinder_geometry::rect::RectF, _: &mut Self::LayoutState, _: &mut V, _: &mut gpui::PaintContext, ) -> Self::PaintState { + scene.push_quad(Quad { + bounds, + background: Some(Color::white()), + ..Default::default() + }); + + scene.push_layer(None); + scene.push_quad(Quad { bounds: RectF::new(vec2f(100., 100.), vec2f(100., 100.)), background: Some(Color::red()), @@ -92,6 +103,30 @@ impl gpui::Element for QuadElement { ..Default::default() }, }); + + scene.push_shadow(Shadow { + bounds: RectF::new(vec2f(400., 100.), vec2f(100., 100.)), + corner_radii: gpui::scene::CornerRadii { + bottom_right: 20., + ..Default::default() + }, + sigma: 20.0, + color: Color::black(), + }); + + scene.push_layer(None); + scene.push_quad(Quad { + bounds: RectF::new(vec2f(400., 100.), vec2f(100., 100.)), + background: Some(Color::red()), + border: Default::default(), + corner_radii: gpui::scene::CornerRadii { + bottom_right: 20., + ..Default::default() + }, + }); + + scene.pop_layer(); + scene.pop_layer(); } fn rect_for_text_range( From 563b25f26f2311e1294c105bbe66d84ff6a5011f Mon Sep 17 00:00:00 2001 From: Mikayla Date: Sat, 12 Aug 2023 12:21:44 -0700 Subject: [PATCH 7/8] Add deserialization helper --- crates/gpui/src/elements/container.rs | 1 + crates/gpui/src/scene.rs | 43 ++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/crates/gpui/src/elements/container.rs b/crates/gpui/src/elements/container.rs index 984742e818f82cc9a5be8310d1139ebb84a82e34..698100ab29647972ae37ec56ce2d3d7d114d8393 100644 --- a/crates/gpui/src/elements/container.rs +++ b/crates/gpui/src/elements/container.rs @@ -30,6 +30,7 @@ pub struct ContainerStyle { #[serde(default)] pub border: Border, #[serde(default)] + #[serde(alias = "corner_radius")] pub corner_radii: CornerRadii, #[serde(default)] pub shadow: Option, diff --git a/crates/gpui/src/scene.rs b/crates/gpui/src/scene.rs index 48649c57918b4f9bdef7fc8ab6b3d88b1b7d509f..d75a4bceff964206fe56fd31323fee07d9a055c8 100644 --- a/crates/gpui/src/scene.rs +++ b/crates/gpui/src/scene.rs @@ -70,7 +70,7 @@ pub struct Quad { pub corner_radii: CornerRadii, } -#[derive(Default, Debug, Mul, Clone, Copy, Deserialize, Serialize, JsonSchema)] +#[derive(Default, Debug, Mul, Clone, Copy, Serialize, JsonSchema)] pub struct CornerRadii { pub top_left: f32, pub top_right: f32, @@ -78,6 +78,47 @@ pub struct CornerRadii { pub bottom_left: f32, } +impl<'de> Deserialize<'de> for CornerRadii { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(Deserialize)] + pub struct CornerRadiiHelper { + pub top_left: f32, + pub top_right: f32, + pub bottom_right: f32, + pub bottom_left: f32, + } + + #[derive(Deserialize)] + #[serde(untagged)] + enum RadiusOrRadii { + Radius(f32), + Radii(CornerRadiiHelper), + } + + let json = RadiusOrRadii::deserialize(deserializer)?; + + let result = match json { + RadiusOrRadii::Radius(radius) => CornerRadii::from(radius), + RadiusOrRadii::Radii(CornerRadiiHelper { + top_left, + top_right, + bottom_right, + bottom_left, + }) => CornerRadii { + top_left, + top_right, + bottom_right, + bottom_left, + }, + }; + + Ok(result) + } +} + impl From for CornerRadii { fn from(radius: f32) -> Self { Self { From 29a85635eafd9eec06e2f6c244e6de5076549158 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Sat, 12 Aug 2023 12:23:46 -0700 Subject: [PATCH 8/8] Make each setting optional --- crates/gpui/src/scene.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/gpui/src/scene.rs b/crates/gpui/src/scene.rs index d75a4bceff964206fe56fd31323fee07d9a055c8..cbc0a9215122d925ac25951995d0835ddf29b13f 100644 --- a/crates/gpui/src/scene.rs +++ b/crates/gpui/src/scene.rs @@ -85,10 +85,10 @@ impl<'de> Deserialize<'de> for CornerRadii { { #[derive(Deserialize)] pub struct CornerRadiiHelper { - pub top_left: f32, - pub top_right: f32, - pub bottom_right: f32, - pub bottom_left: f32, + pub top_left: Option, + pub top_right: Option, + pub bottom_right: Option, + pub bottom_left: Option, } #[derive(Deserialize)] @@ -108,10 +108,10 @@ impl<'de> Deserialize<'de> for CornerRadii { bottom_right, bottom_left, }) => CornerRadii { - top_left, - top_right, - bottom_right, - bottom_left, + top_left: top_left.unwrap_or(0.0), + top_right: top_right.unwrap_or(0.0), + bottom_right: bottom_right.unwrap_or(0.0), + bottom_left: bottom_left.unwrap_or(0.0), }, };