Merge branch 'main' into collab-panel

This commit is contained in:
Mikayla 2023-08-12 12:44:22 -07:00
commit a90c0e0326
No known key found for this signature in database
30 changed files with 410 additions and 100 deletions

1
Cargo.lock generated
View file

@ -3175,6 +3175,7 @@ dependencies = [
name = "gpui_macros" name = "gpui_macros"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"gpui",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn 1.0.109",

View file

@ -363,7 +363,7 @@ impl AssistantPanel {
this.set_active_editor_index(this.prev_active_editor_index, cx); this.set_active_editor_index(this.prev_active_editor_index, cx);
} }
}) })
.with_tooltip::<History>(1, "History".into(), None, tooltip_style, cx) .with_tooltip::<History>(1, "History", None, tooltip_style, cx)
} }
fn render_editor_tools(&self, cx: &mut ViewContext<Self>) -> Vec<AnyElement<Self>> { fn render_editor_tools(&self, cx: &mut ViewContext<Self>) -> Vec<AnyElement<Self>> {
@ -395,7 +395,7 @@ impl AssistantPanel {
}) })
.with_tooltip::<Split>( .with_tooltip::<Split>(
1, 1,
"Split Message".into(), "Split Message",
Some(Box::new(Split)), Some(Box::new(Split)),
tooltip_style, tooltip_style,
cx, cx,
@ -417,13 +417,7 @@ impl AssistantPanel {
active_editor.update(cx, |editor, cx| editor.assist(&Default::default(), cx)); active_editor.update(cx, |editor, cx| editor.assist(&Default::default(), cx));
} }
}) })
.with_tooltip::<Assist>( .with_tooltip::<Assist>(1, "Assist", Some(Box::new(Assist)), tooltip_style, cx)
1,
"Assist".into(),
Some(Box::new(Assist)),
tooltip_style,
cx,
)
} }
fn render_quote_button(cx: &mut ViewContext<Self>) -> impl Element<Self> { fn render_quote_button(cx: &mut ViewContext<Self>) -> impl Element<Self> {
@ -447,7 +441,7 @@ impl AssistantPanel {
}) })
.with_tooltip::<QuoteSelection>( .with_tooltip::<QuoteSelection>(
1, 1,
"Quote Selection".into(), "Quote Selection",
Some(Box::new(QuoteSelection)), Some(Box::new(QuoteSelection)),
tooltip_style, tooltip_style,
cx, cx,
@ -469,7 +463,7 @@ impl AssistantPanel {
}) })
.with_tooltip::<NewConversation>( .with_tooltip::<NewConversation>(
1, 1,
"New Conversation".into(), "New Conversation",
Some(Box::new(NewConversation)), Some(Box::new(NewConversation)),
tooltip_style, tooltip_style,
cx, cx,
@ -499,11 +493,7 @@ impl AssistantPanel {
}) })
.with_tooltip::<ToggleZoom>( .with_tooltip::<ToggleZoom>(
0, 0,
if self.zoomed { if self.zoomed { "Zoom Out" } else { "Zoom In" },
"Zoom Out".into()
} else {
"Zoom In".into()
},
Some(Box::new(ToggleZoom)), Some(Box::new(ToggleZoom)),
tooltip_style, tooltip_style,
cx, cx,

View file

@ -988,7 +988,7 @@ impl CollabPanel {
), ),
background: Some(tree_branch.color), background: Some(tree_branch.color),
border: gpui::Border::default(), border: gpui::Border::default(),
corner_radius: 0., corner_radii: (0.).into(),
}); });
scene.push_quad(gpui::Quad { scene.push_quad(gpui::Quad {
bounds: RectF::from_points( bounds: RectF::from_points(
@ -997,7 +997,7 @@ impl CollabPanel {
), ),
background: Some(tree_branch.color), background: Some(tree_branch.color),
border: gpui::Border::default(), border: gpui::Border::default(),
corner_radius: 0., corner_radii: (0.).into(),
}); });
})) }))
.constrained() .constrained()
@ -1085,7 +1085,7 @@ impl CollabPanel {
), ),
background: Some(tree_branch.color), background: Some(tree_branch.color),
border: gpui::Border::default(), border: gpui::Border::default(),
corner_radius: 0., corner_radii: (0.).into(),
}); });
scene.push_quad(gpui::Quad { scene.push_quad(gpui::Quad {
bounds: RectF::from_points( bounds: RectF::from_points(
@ -1094,7 +1094,7 @@ impl CollabPanel {
), ),
background: Some(tree_branch.color), background: Some(tree_branch.color),
border: gpui::Border::default(), border: gpui::Border::default(),
corner_radius: 0., corner_radii: (0.).into(),
}); });
})) }))
.constrained() .constrained()
@ -1188,7 +1188,7 @@ impl CollabPanel {
}) })
.with_tooltip::<AddContact>( .with_tooltip::<AddContact>(
0, 0,
"Leave call".into(), "Leave call",
None, None,
tooltip_style.clone(), tooltip_style.clone(),
cx, cx,
@ -1210,7 +1210,7 @@ impl CollabPanel {
}) })
.with_tooltip::<LeaveCallContactList>( .with_tooltip::<LeaveCallContactList>(
0, 0,
"Search for new contact".into(), "Search for new contact",
None, None,
tooltip_style.clone(), tooltip_style.clone(),
cx, cx,
@ -1230,7 +1230,7 @@ impl CollabPanel {
.on_click(MouseButton::Left, |_, this, cx| this.new_root_channel(cx)) .on_click(MouseButton::Left, |_, this, cx| this.new_root_channel(cx))
.with_tooltip::<AddChannel>( .with_tooltip::<AddChannel>(
0, 0,
"Add or join a channel".into(), "Add or join a channel",
None, None,
tooltip_style.clone(), tooltip_style.clone(),
cx, cx,

View file

@ -231,7 +231,7 @@ impl CollabTitlebarItem {
.left() .left()
.with_tooltip::<RecentProjectsTooltip>( .with_tooltip::<RecentProjectsTooltip>(
0, 0,
"Recent projects".into(), "Recent projects",
Some(Box::new(recent_projects::OpenRecent)), Some(Box::new(recent_projects::OpenRecent)),
theme.tooltip.clone(), theme.tooltip.clone(),
cx, cx,
@ -275,7 +275,7 @@ impl CollabTitlebarItem {
.left() .left()
.with_tooltip::<BranchPopoverTooltip>( .with_tooltip::<BranchPopoverTooltip>(
0, 0,
"Recent branches".into(), "Recent branches",
Some(Box::new(ToggleVcsMenu)), Some(Box::new(ToggleVcsMenu)),
theme.tooltip.clone(), theme.tooltip.clone(),
cx, cx,
@ -528,7 +528,7 @@ impl CollabTitlebarItem {
}) })
.with_tooltip::<ToggleScreenSharing>( .with_tooltip::<ToggleScreenSharing>(
0, 0,
tooltip.into(), tooltip,
Some(Box::new(ToggleScreenSharing)), Some(Box::new(ToggleScreenSharing)),
theme.tooltip.clone(), theme.tooltip.clone(),
cx, cx,
@ -581,7 +581,7 @@ impl CollabTitlebarItem {
}) })
.with_tooltip::<ToggleMute>( .with_tooltip::<ToggleMute>(
0, 0,
tooltip.into(), tooltip,
Some(Box::new(ToggleMute)), Some(Box::new(ToggleMute)),
theme.tooltip.clone(), theme.tooltip.clone(),
cx, cx,
@ -629,7 +629,7 @@ impl CollabTitlebarItem {
}) })
.with_tooltip::<ToggleDeafen>( .with_tooltip::<ToggleDeafen>(
0, 0,
tooltip.into(), tooltip,
Some(Box::new(ToggleDeafen)), Some(Box::new(ToggleDeafen)),
theme.tooltip.clone(), theme.tooltip.clone(),
cx, cx,
@ -663,7 +663,7 @@ impl CollabTitlebarItem {
}) })
.with_tooltip::<LeaveCall>( .with_tooltip::<LeaveCall>(
0, 0,
tooltip.into(), tooltip,
Some(Box::new(LeaveCall)), Some(Box::new(LeaveCall)),
theme.tooltip.clone(), theme.tooltip.clone(),
cx, cx,

View file

@ -140,7 +140,7 @@ impl View for CopilotButton {
}) })
.with_tooltip::<Self>( .with_tooltip::<Self>(
0, 0,
"GitHub Copilot".into(), "GitHub Copilot",
None, None,
theme.tooltip.clone(), theme.tooltip.clone(),
cx, cx,

View file

@ -173,7 +173,7 @@ impl View for DiagnosticIndicator {
}) })
.with_tooltip::<Summary>( .with_tooltip::<Summary>(
0, 0,
"Project Diagnostics".to_string(), "Project Diagnostics",
Some(Box::new(crate::Deploy)), Some(Box::new(crate::Deploy)),
tooltip_style, tooltip_style,
cx, cx,

View file

@ -8685,7 +8685,7 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend
// We really need to rethink this ID system... // We really need to rethink this ID system...
.with_tooltip::<BlockContextToolip>( .with_tooltip::<BlockContextToolip>(
cx.block_id, cx.block_id,
"Copy diagnostic message".to_string(), "Copy diagnostic message",
None, None,
tooltip_style, tooltip_style,
cx, cx,

View file

@ -488,13 +488,13 @@ impl EditorElement {
bounds: gutter_bounds, bounds: gutter_bounds,
background: Some(self.style.gutter_background), background: Some(self.style.gutter_background),
border: Border::new(0., Color::transparent_black()), border: Border::new(0., Color::transparent_black()),
corner_radius: 0., corner_radii: Default::default(),
}); });
scene.push_quad(Quad { scene.push_quad(Quad {
bounds: text_bounds, bounds: text_bounds,
background: Some(self.style.background), background: Some(self.style.background),
border: Border::new(0., Color::transparent_black()), border: Border::new(0., Color::transparent_black()),
corner_radius: 0., corner_radii: Default::default(),
}); });
if let EditorMode::Full = layout.mode { if let EditorMode::Full = layout.mode {
@ -522,7 +522,7 @@ impl EditorElement {
bounds: RectF::new(origin, size), bounds: RectF::new(origin, size),
background: Some(self.style.active_line_background), background: Some(self.style.active_line_background),
border: Border::default(), border: Border::default(),
corner_radius: 0., corner_radii: Default::default(),
}); });
} }
} }
@ -542,7 +542,7 @@ impl EditorElement {
bounds: RectF::new(origin, size), bounds: RectF::new(origin, size),
background: Some(self.style.highlighted_line_background), background: Some(self.style.highlighted_line_background),
border: Border::default(), border: Border::default(),
corner_radius: 0., corner_radii: Default::default(),
}); });
} }
@ -572,7 +572,7 @@ impl EditorElement {
), ),
background: Some(color), background: Some(color),
border: Border::new(0., Color::transparent_black()), border: Border::new(0., Color::transparent_black()),
corner_radius: 0., corner_radii: Default::default(),
}); });
} }
} }
@ -673,7 +673,7 @@ impl EditorElement {
bounds: highlight_bounds, bounds: highlight_bounds,
background: Some(diff_style.modified), background: Some(diff_style.modified),
border: Border::new(0., Color::transparent_black()), border: Border::new(0., Color::transparent_black()),
corner_radius: 1. * line_height, corner_radii: (1. * line_height).into(),
}); });
continue; continue;
@ -706,7 +706,7 @@ impl EditorElement {
bounds: highlight_bounds, bounds: highlight_bounds,
background: Some(diff_style.deleted), background: Some(diff_style.deleted),
border: Border::new(0., Color::transparent_black()), border: Border::new(0., Color::transparent_black()),
corner_radius: 1. * line_height, corner_radii: (1. * line_height).into(),
}); });
continue; continue;
@ -728,7 +728,7 @@ impl EditorElement {
bounds: highlight_bounds, bounds: highlight_bounds,
background: Some(color), background: Some(color),
border: Border::new(0., Color::transparent_black()), 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, bounds,
background: Some(color), background: Some(color),
border, border,
corner_radius: style.thumb.corner_radius, corner_radii: style.thumb.corner_radii.into(),
}) })
}; };
let background_ranges = editor let background_ranges = editor
@ -1189,7 +1189,7 @@ impl EditorElement {
bounds, bounds,
background: Some(color), background: Some(color),
border, border,
corner_radius: style.thumb.corner_radius, corner_radii: style.thumb.corner_radii.into(),
}) })
} }
} }
@ -1198,7 +1198,7 @@ impl EditorElement {
bounds: thumb_bounds, bounds: thumb_bounds,
border: style.thumb.border, border: style.thumb.border,
background: style.thumb.background_color, background: style.thumb.background_color,
corner_radius: style.thumb.corner_radius, corner_radii: style.thumb.corner_radii.into(),
}); });
} }
@ -2725,14 +2725,14 @@ impl Cursor {
bounds, bounds,
background: None, background: None,
border: Border::all(1., self.color), border: Border::all(1., self.color),
corner_radius: 0., corner_radii: Default::default(),
}); });
} else { } else {
scene.push_quad(Quad { scene.push_quad(Quad {
bounds, bounds,
background: Some(self.color), background: Some(self.color),
border: Default::default(), border: Default::default(),
corner_radius: 0., corner_radii: Default::default(),
}); });
} }

View file

@ -599,7 +599,7 @@ impl InfoPopover {
bounds, bounds,
background: Some(code_span_background_color), background: Some(code_span_background_color),
border: Default::default(), border: Default::default(),
corner_radius: 2.0, corner_radii: (2.0).into(),
}); });
} }
}, },

View file

@ -66,7 +66,7 @@ impl View for DeployFeedbackButton {
}) })
.with_tooltip::<Self>( .with_tooltip::<Self>(
0, 0,
"Send Feedback".into(), "Send Feedback",
Some(Box::new(GiveFeedback)), Some(Box::new(GiveFeedback)),
theme.tooltip.clone(), theme.tooltip.clone(),
cx, cx,

View file

@ -80,7 +80,7 @@ impl View for SubmitFeedbackButton {
.with_margin_left(theme.feedback.button_margin) .with_margin_left(theme.feedback.button_margin)
.with_tooltip::<Self>( .with_tooltip::<Self>(
0, 0,
"cmd-s".into(), "cmd-s",
Some(Box::new(SubmitFeedback)), Some(Box::new(SubmitFeedback)),
theme.tooltip.clone(), theme.tooltip.clone(),
cx, cx,

View file

@ -0,0 +1,155 @@
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;
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(), |_| CornersView);
});
}
struct CornersView;
impl Entity for CornersView {
type Event = ();
}
impl View for CornersView {
fn ui_name() -> &'static str {
"CornersView"
}
fn render(&mut self, _: &mut gpui::ViewContext<Self>) -> AnyElement<CornersView> {
CornersElement.into_any()
}
}
struct CornersElement;
impl<V: View> gpui::Element<V> for CornersElement {
type LayoutState = ();
type PaintState = ();
fn layout(
&mut self,
constraint: gpui::SizeConstraint,
_: &mut V,
_: &mut gpui::LayoutContext<V>,
) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) {
(constraint.max, ())
}
fn paint(
&mut self,
scene: &mut gpui::SceneBuilder,
bounds: pathfinder_geometry::rect::RectF,
_: pathfinder_geometry::rect::RectF,
_: &mut Self::LayoutState,
_: &mut V,
_: &mut gpui::PaintContext<V>,
) -> 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()),
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()
},
});
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(
&self,
_: std::ops::Range<usize>,
_: pathfinder_geometry::rect::RectF,
_: pathfinder_geometry::rect::RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
_: &V,
_: &gpui::ViewContext<V>,
) -> Option<pathfinder_geometry::rect::RectF> {
unimplemented!()
}
fn debug(
&self,
_: pathfinder_geometry::rect::RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
_: &V,
_: &gpui::ViewContext<V>,
) -> serde_json::Value {
unimplemented!()
}
}

View file

@ -174,7 +174,7 @@ pub trait Element<V: View>: 'static {
fn with_tooltip<Tag: 'static>( fn with_tooltip<Tag: 'static>(
self, self,
id: usize, id: usize,
text: String, text: impl Into<Cow<'static, str>>,
action: Option<Box<dyn Action>>, action: Option<Box<dyn Action>>,
style: TooltipStyle, style: TooltipStyle,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
@ -182,7 +182,7 @@ pub trait Element<V: View>: 'static {
where where
Self: 'static + Sized, Self: 'static + Sized,
{ {
Tooltip::new::<Tag, V>(id, text, action, style, self.into_any(), cx) Tooltip::new::<Tag>(id, text, action, style, self.into_any(), cx)
} }
fn resizable( fn resizable(
@ -205,6 +205,10 @@ pub trait Element<V: View>: 'static {
} }
} }
pub trait RenderElement {
fn render<V: View>(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
}
trait AnyElementState<V: View> { trait AnyElementState<V: View> {
fn layout( fn layout(
&mut self, &mut self,

View file

@ -9,7 +9,7 @@ use crate::{
}, },
json::ToJson, json::ToJson,
platform::CursorStyle, platform::CursorStyle,
scene::{self, Border, CursorRegion, Quad}, scene::{self, Border, CornerRadii, CursorRegion, Quad},
AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
ViewContext, ViewContext,
}; };
@ -30,7 +30,8 @@ pub struct ContainerStyle {
#[serde(default)] #[serde(default)]
pub border: Border, pub border: Border,
#[serde(default)] #[serde(default)]
pub corner_radius: f32, #[serde(alias = "corner_radius")]
pub corner_radii: CornerRadii,
#[serde(default)] #[serde(default)]
pub shadow: Option<Shadow>, pub shadow: Option<Shadow>,
#[serde(default)] #[serde(default)]
@ -133,7 +134,10 @@ impl<V: View> Container<V> {
} }
pub fn with_corner_radius(mut self, radius: f32) -> Self { 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 self
} }
@ -225,7 +229,7 @@ impl<V: View> Element<V> for Container<V> {
if let Some(shadow) = self.style.shadow.as_ref() { if let Some(shadow) = self.style.shadow.as_ref() {
scene.push_shadow(scene::Shadow { scene.push_shadow(scene::Shadow {
bounds: quad_bounds + shadow.offset, bounds: quad_bounds + shadow.offset,
corner_radius: self.style.corner_radius, corner_radii: self.style.corner_radii,
sigma: shadow.blur, sigma: shadow.blur,
color: shadow.color, color: shadow.color,
}); });
@ -248,7 +252,7 @@ impl<V: View> Element<V> for Container<V> {
bounds: quad_bounds, bounds: quad_bounds,
background: self.style.background_color, background: self.style.background_color,
border: Default::default(), border: Default::default(),
corner_radius: self.style.corner_radius, corner_radii: self.style.corner_radii.into(),
}); });
self.child self.child
@ -259,7 +263,7 @@ impl<V: View> Element<V> for Container<V> {
bounds: quad_bounds, bounds: quad_bounds,
background: self.style.overlay_color, background: self.style.overlay_color,
border: self.style.border, border: self.style.border,
corner_radius: self.style.corner_radius, corner_radii: self.style.corner_radii.into(),
}); });
scene.pop_layer(); scene.pop_layer();
} else { } else {
@ -267,7 +271,7 @@ impl<V: View> Element<V> for Container<V> {
bounds: quad_bounds, bounds: quad_bounds,
background: self.style.background_color, background: self.style.background_color,
border: self.style.border, border: self.style.border,
corner_radius: self.style.corner_radius, corner_radii: self.style.corner_radii.into(),
}); });
let child_origin = child_origin let child_origin = child_origin
@ -284,7 +288,7 @@ impl<V: View> Element<V> for Container<V> {
bounds: quad_bounds, bounds: quad_bounds,
background: self.style.overlay_color, background: self.style.overlay_color,
border: Default::default(), border: Default::default(),
corner_radius: 0., corner_radii: self.style.corner_radii.into(),
}); });
scene.pop_layer(); scene.pop_layer();
} }
@ -328,7 +332,7 @@ impl ToJson for ContainerStyle {
"padding": self.padding.to_json(), "padding": self.padding.to_json(),
"background_color": self.background_color.to_json(), "background_color": self.background_color.to_json(),
"border": self.border.to_json(), "border": self.border.to_json(),
"corner_radius": self.corner_radius, "corner_radius": self.corner_radii,
"shadow": self.shadow.to_json(), "shadow": self.shadow.to_json(),
}) })
} }

View file

@ -103,7 +103,7 @@ impl<V: View> Element<V> for Image {
scene.push_image(scene::Image { scene.push_image(scene::Image {
bounds, bounds,
border: self.style.border, border: self.style.border,
corner_radius: self.style.corner_radius, corner_radii: self.style.corner_radius.into(),
grayscale: self.style.grayscale, grayscale: self.style.grayscale,
data: data.clone(), data: data.clone(),
}); });

View file

@ -12,6 +12,7 @@ use crate::{
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::Deserialize; use serde::Deserialize;
use std::{ use std::{
borrow::Cow,
cell::{Cell, RefCell}, cell::{Cell, RefCell},
ops::Range, ops::Range,
rc::Rc, rc::Rc,
@ -52,9 +53,9 @@ pub struct KeystrokeStyle {
} }
impl<V: View> Tooltip<V> { impl<V: View> Tooltip<V> {
pub fn new<Tag: 'static, T: View>( pub fn new<Tag: 'static>(
id: usize, id: usize,
text: String, text: impl Into<Cow<'static, str>>,
action: Option<Box<dyn Action>>, action: Option<Box<dyn Action>>,
style: TooltipStyle, style: TooltipStyle,
child: AnyElement<V>, child: AnyElement<V>,
@ -66,6 +67,8 @@ impl<V: View> Tooltip<V> {
let state_handle = cx.default_element_state::<ElementState<Tag>, Rc<TooltipState>>(id); let state_handle = cx.default_element_state::<ElementState<Tag>, Rc<TooltipState>>(id);
let state = state_handle.read(cx).clone(); let state = state_handle.read(cx).clone();
let text = text.into();
let tooltip = if state.visible.get() { let tooltip = if state.visible.get() {
let mut collapsed_tooltip = Self::render_tooltip( let mut collapsed_tooltip = Self::render_tooltip(
focused_view_id, focused_view_id,
@ -127,7 +130,7 @@ impl<V: View> Tooltip<V> {
pub fn render_tooltip( pub fn render_tooltip(
focused_view_id: Option<usize>, focused_view_id: Option<usize>,
text: String, text: impl Into<Cow<'static, str>>,
style: TooltipStyle, style: TooltipStyle,
action: Option<Box<dyn Action>>, action: Option<Box<dyn Action>>,
measure: bool, measure: bool,

View file

@ -509,10 +509,14 @@ impl Renderer {
}; };
for (ix, shadow) in shadows.iter().enumerate() { for (ix, shadow) in shadows.iter().enumerate() {
let shape_bounds = shadow.bounds * scale_factor; let shape_bounds = shadow.bounds * scale_factor;
let corner_radii = shadow.corner_radii * scale_factor;
let shader_shadow = shaders::GPUIShadow { let shader_shadow = shaders::GPUIShadow {
origin: shape_bounds.origin().to_float2(), origin: shape_bounds.origin().to_float2(),
size: shape_bounds.size().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, sigma: shadow.sigma,
color: shadow.color.to_uchar4(), color: shadow.color.to_uchar4(),
}; };
@ -586,7 +590,10 @@ impl Renderer {
border_bottom: border_width * (quad.border.bottom 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_left: border_width * (quad.border.left as usize as f32),
border_color: quad.border.color.to_uchar4(), 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 { unsafe {
*(buffer_contents.add(ix)) = shader_quad; *(buffer_contents.add(ix)) = shader_quad;
@ -738,7 +745,7 @@ impl Renderer {
for image in images { for image in images {
let origin = image.bounds.origin() * scale_factor; let origin = image.bounds.origin() * scale_factor;
let target_size = image.bounds.size() * 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 border_width = image.border.width * scale_factor;
let (alloc_id, atlas_bounds) = self.image_cache.render(&image.data); let (alloc_id, atlas_bounds) = self.image_cache.render(&image.data);
images_by_atlas images_by_atlas
@ -754,7 +761,10 @@ impl Renderer {
border_bottom: border_width * (image.border.bottom 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_left: border_width * (image.border.left as usize as f32),
border_color: image.border.color.to_uchar4(), 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, grayscale: image.grayscale as u8,
}); });
} }
@ -777,7 +787,10 @@ impl Renderer {
border_bottom: 0., border_bottom: 0.,
border_left: 0., border_left: 0.,
border_color: Default::default(), 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, grayscale: false as u8,
}); });
} else { } else {

View file

@ -19,7 +19,10 @@ typedef struct {
float border_bottom; float border_bottom;
float border_left; float border_left;
vector_uchar4 border_color; 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; } GPUIQuad;
typedef enum { typedef enum {
@ -31,7 +34,10 @@ typedef enum {
typedef struct { typedef struct {
vector_float2 origin; vector_float2 origin;
vector_float2 size; 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; float sigma;
vector_uchar4 color; vector_uchar4 color;
} GPUIShadow; } GPUIShadow;
@ -89,7 +95,10 @@ typedef struct {
float border_bottom; float border_bottom;
float border_left; float border_left;
vector_uchar4 border_color; 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; uint8_t grayscale;
} GPUIImage; } GPUIImage;

View file

@ -43,7 +43,10 @@ struct QuadFragmentInput {
float border_bottom; float border_bottom;
float border_left; float border_left;
float4 border_color; 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 uchar grayscale; // only used in image shader
}; };
@ -51,12 +54,27 @@ float4 quad_sdf(QuadFragmentInput input) {
float2 half_size = input.size / 2.; float2 half_size = input.size / 2.;
float2 center = input.origin + half_size; float2 center = input.origin + half_size;
float2 center_to_point = input.position.xy - center; float2 center_to_point = input.position.xy - center;
float2 rounded_edge_to_point = abs(center_to_point) - half_size + input.corner_radius; float 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; 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 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; 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; float2 point_to_inset_corner = abs(center_to_point) - inset_size;
float border_width; float border_width;
if (point_to_inset_corner.x < 0. && point_to_inset_corner.y < 0.) { 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_bottom,
quad.border_left, quad.border_left,
coloru_to_colorf(quad.border_color), 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, 0,
}; };
} }
@ -125,7 +146,10 @@ struct ShadowFragmentInput {
float4 position [[position]]; float4 position [[position]];
vector_float2 origin; vector_float2 origin;
vector_float2 size; 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; float sigma;
vector_uchar4 color; vector_uchar4 color;
}; };
@ -148,7 +172,10 @@ vertex ShadowFragmentInput shadow_vertex(
device_position, device_position,
shadow.origin, shadow.origin,
shadow.size, 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.sigma,
shadow.color, shadow.color,
}; };
@ -158,10 +185,24 @@ fragment float4 shadow_fragment(
ShadowFragmentInput input [[stage_in]] ShadowFragmentInput input [[stage_in]]
) { ) {
float sigma = input.sigma; float sigma = input.sigma;
float corner_radius = input.corner_radius;
float2 half_size = input.size / 2.; float2 half_size = input.size / 2.;
float2 center = input.origin + half_size; float2 center = input.origin + half_size;
float2 point = input.position.xy - center; 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 // The signal is only non-zero in a limited range, so don't waste samples
float low = point.y - half_size.y; float low = point.y - half_size.y;
@ -252,7 +293,10 @@ vertex QuadFragmentInput image_vertex(
image.border_bottom, image.border_bottom,
image.border_left, image.border_left,
coloru_to_colorf(image.border_color), coloru_to_colorf(image.border_color),
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, image.grayscale,
}; };
} }
@ -266,7 +310,7 @@ fragment float4 image_fragment(
if (input.grayscale) { if (input.grayscale) {
float grayscale = float grayscale =
0.2126 * input.background_color.r + 0.2126 * input.background_color.r +
0.7152 * input.background_color.g + 0.7152 * input.background_color.g +
0.0722 * input.background_color.b; 0.0722 * input.background_color.b;
input.background_color = float4(grayscale, grayscale, grayscale, input.background_color.a); input.background_color = float4(grayscale, grayscale, grayscale, input.background_color.a);
} }

View file

@ -3,8 +3,10 @@ mod mouse_region;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
use collections::HashSet; use collections::HashSet;
use derive_more::Mul;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::Deserialize; use serde::Deserialize;
use serde_derive::Serialize;
use serde_json::json; use serde_json::json;
use std::{borrow::Cow, sync::Arc}; use std::{borrow::Cow, sync::Arc};
@ -65,13 +67,73 @@ pub struct Quad {
pub bounds: RectF, pub bounds: RectF,
pub background: Option<Color>, pub background: Option<Color>,
pub border: Border, pub border: Border,
pub corner_radius: f32, pub corner_radii: CornerRadii,
}
#[derive(Default, Debug, Mul, Clone, Copy, Serialize, JsonSchema)]
pub struct CornerRadii {
pub top_left: f32,
pub top_right: f32,
pub bottom_right: f32,
pub bottom_left: f32,
}
impl<'de> Deserialize<'de> for CornerRadii {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
pub struct CornerRadiiHelper {
pub top_left: Option<f32>,
pub top_right: Option<f32>,
pub bottom_right: Option<f32>,
pub bottom_left: Option<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_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),
},
};
Ok(result)
}
}
impl From<f32> for CornerRadii {
fn from(radius: f32) -> Self {
Self {
top_left: radius,
top_right: radius,
bottom_right: radius,
bottom_left: radius,
}
}
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Shadow { pub struct Shadow {
pub bounds: RectF, pub bounds: RectF,
pub corner_radius: f32, pub corner_radii: CornerRadii,
pub sigma: f32, pub sigma: f32,
pub color: Color, pub color: Color,
} }
@ -177,7 +239,7 @@ pub struct PathVertex {
pub struct Image { pub struct Image {
pub bounds: RectF, pub bounds: RectF,
pub border: Border, pub border: Border,
pub corner_radius: f32, pub corner_radii: CornerRadii,
pub grayscale: bool, pub grayscale: bool,
pub data: Arc<ImageData>, pub data: Arc<ImageData>,
} }

View file

@ -14,3 +14,5 @@ syn = "1.0"
quote = "1.0" quote = "1.0"
proc-macro2 = "1.0" proc-macro2 = "1.0"
[dev-dependencies]
gpui = { path = "../gpui" }

View file

@ -283,8 +283,12 @@ pub fn element_derive(input: TokenStream) -> TokenStream {
// The name of the struct/enum // The name of the struct/enum
let name = input.ident; let name = input.ident;
let must_implement = format_ident!("{}MustImplementRenderElement", name);
let expanded = quote! { let expanded = quote! {
trait #must_implement : gpui::elements::RenderElement {}
impl #must_implement for #name {}
impl<V: gpui::View> gpui::elements::Element<V> for #name { impl<V: gpui::View> gpui::elements::Element<V> for #name {
type LayoutState = gpui::elements::AnyElement<V>; type LayoutState = gpui::elements::AnyElement<V>;
type PaintState = (); type PaintState = ();
@ -307,7 +311,7 @@ pub fn element_derive(input: TokenStream) -> TokenStream {
visible_bounds: gpui::geometry::rect::RectF, visible_bounds: gpui::geometry::rect::RectF,
element: &mut gpui::elements::AnyElement<V>, element: &mut gpui::elements::AnyElement<V>,
view: &mut V, view: &mut V,
cx: &mut gpui::ViewContext<V>, cx: &mut gpui::PaintContext<V>,
) { ) {
element.paint(scene, bounds.origin(), visible_bounds, view, cx); element.paint(scene, bounds.origin(), visible_bounds, view, cx);
} }
@ -332,7 +336,7 @@ pub fn element_derive(input: TokenStream) -> TokenStream {
_: &(), _: &(),
view: &V, view: &V,
cx: &gpui::ViewContext<V>, cx: &gpui::ViewContext<V>,
) -> serde_json::Value { ) -> gpui::serde_json::Value {
element.debug(view, cx) element.debug(view, cx)
} }
} }

View file

@ -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<V: View>(&mut self, _: &mut V, _: &mut ViewContext<V>) -> gpui::AnyElement<V> {
unimplemented!()
}
}
}

View file

@ -153,7 +153,7 @@ impl LayoutRect {
bounds: RectF::new(position, size), bounds: RectF::new(position, size),
background: Some(self.color), background: Some(self.color),
border: Default::default(), border: Default::default(),
corner_radius: 0., corner_radii: Default::default(),
}) })
} }
} }
@ -763,7 +763,7 @@ impl Element<TerminalView> for TerminalElement {
bounds: RectF::new(bounds.origin(), bounds.size()), bounds: RectF::new(bounds.origin(), bounds.size()),
background: Some(layout.background_color), background: Some(layout.background_color),
border: Default::default(), border: Default::default(),
corner_radius: 0., corner_radii: Default::default(),
}); });
for rect in &layout.rects { for rect in &layout.rects {

View file

@ -72,10 +72,7 @@ impl TerminalPanel {
0, 0,
"icons/plus_12.svg", "icons/plus_12.svg",
false, false,
Some(( Some(("New Terminal", Some(Box::new(workspace::NewTerminal)))),
"New Terminal".into(),
Some(Box::new(workspace::NewTerminal)),
)),
cx, cx,
move |_, cx| { move |_, cx| {
let this = this.clone(); let this = this.clone();

View file

@ -303,10 +303,10 @@ impl Pane {
let tooltip_label; let tooltip_label;
if pane.is_zoomed() { if pane.is_zoomed() {
icon_path = "icons/minimize_8.svg"; icon_path = "icons/minimize_8.svg";
tooltip_label = "Zoom In".into(); tooltip_label = "Zoom In";
} else { } else {
icon_path = "icons/maximize_8.svg"; icon_path = "icons/maximize_8.svg";
tooltip_label = "Zoom In".into(); tooltip_label = "Zoom In";
} }
Pane::render_tab_bar_button( Pane::render_tab_bar_button(
@ -1397,7 +1397,7 @@ impl Pane {
bounds: square, bounds: square,
background: Some(color), background: Some(color),
border: Default::default(), border: Default::default(),
corner_radius: diameter / 2., corner_radii: (diameter / 2.).into(),
}); });
} }
}) })
@ -1477,7 +1477,7 @@ impl Pane {
index: usize, index: usize,
icon: &'static str, icon: &'static str,
is_active: bool, is_active: bool,
tooltip: Option<(String, Option<Box<dyn Action>>)>, tooltip: Option<(&'static str, Option<Box<dyn Action>>)>,
cx: &mut ViewContext<Pane>, cx: &mut ViewContext<Pane>,
on_click: F1, on_click: F1,
on_down: F2, on_down: F2,

View file

@ -61,7 +61,7 @@ where
bounds: overlay_region, bounds: overlay_region,
background: Some(overlay_color(cx)), background: Some(overlay_color(cx)),
border: Default::default(), border: Default::default(),
corner_radius: 0., corner_radii: Default::default(),
}); });
}); });
} }

View file

@ -220,7 +220,7 @@ fn nav_button<A: Action, F: 'static + Fn(&mut Toolbar, &mut ViewContext<Toolbar>
spacing: f32, spacing: f32,
on_click: F, on_click: F,
tooltip_action: A, tooltip_action: A,
action_name: &str, action_name: &'static str,
cx: &mut ViewContext<Toolbar>, cx: &mut ViewContext<Toolbar>,
) -> AnyElement<Toolbar> { ) -> AnyElement<Toolbar> {
MouseEventHandler::<A, _>::new(0, cx, |state, _| { MouseEventHandler::<A, _>::new(0, cx, |state, _| {
@ -252,7 +252,7 @@ fn nav_button<A: Action, F: 'static + Fn(&mut Toolbar, &mut ViewContext<Toolbar>
}) })
.with_tooltip::<A>( .with_tooltip::<A>(
0, 0,
action_name.to_string(), action_name,
Some(Box::new(tooltip_action)), Some(Box::new(tooltip_action)),
tooltip_style, tooltip_style,
cx, cx,

View file

@ -3624,7 +3624,7 @@ fn notify_of_new_dock(workspace: &WeakViewHandle<Workspace>, cx: &mut AsyncAppCo
bounds, bounds,
background: Some(code_span_background_color), background: Some(code_span_background_color),
border: Default::default(), border: Default::default(),
corner_radius: 2.0, corner_radii: (2.0).into(),
}) })
}) })
.into_any() .into_any()

View file

@ -27,9 +27,17 @@ export default function channel_modal(): any {
header: { header: {
background: background(theme.middle, "accent"), background: background(theme.middle, "accent"),
border: border(theme.middle, { "bottom": true, "top": false, left: false, right: false }), border: border(theme.middle, { "bottom": true, "top": false, left: false, right: false }),
corner_radii: {
top_right: 12,
top_left: 12,
}
}, },
body: { body: {
background: background(theme.middle), background: background(theme.middle),
corner_radii: {
bottom_right: 12,
bottom_left: 12,
}
}, },
modal: { modal: {
background: background(theme.middle), background: background(theme.middle),