From 289255d67aa67ee77490f8e2130e0be103ae16d8 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Wed, 18 Oct 2023 15:42:10 -0400 Subject: [PATCH 1/2] Update UI elements and implement user settings for customization --- crates/gpui3/src/styled.rs | 14 ++- crates/ui2/src/components/list.rs | 12 +-- crates/ui2/src/components/panel.rs | 8 +- crates/ui2/src/components/title_bar.rs | 10 +- crates/ui2/src/components/traffic_lights.rs | 3 +- crates/ui2/src/elements/button.rs | 9 +- crates/ui2/src/lib.rs | 1 + crates/ui2/src/prelude.rs | 36 +++++-- crates/ui2/src/settings.rs | 102 ++++++++++++++++++++ 9 files changed, 163 insertions(+), 32 deletions(-) create mode 100644 crates/ui2/src/settings.rs diff --git a/crates/gpui3/src/styled.rs b/crates/gpui3/src/styled.rs index 56a1b68c75..4d54ebb5ad 100644 --- a/crates/gpui3/src/styled.rs +++ b/crates/gpui3/src/styled.rs @@ -1,6 +1,6 @@ use crate::{ - self as gpui3, hsla, point, px, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla, - JustifyContent, Length, Position, SharedString, StyleRefinement, + self as gpui3, hsla, point, px, relative, rems, AbsoluteLength, AlignItems, Display, Fill, + FlexDirection, Hsla, JustifyContent, Length, Position, Rems, SharedString, StyleRefinement, }; use crate::{BoxShadow, TextStyleRefinement}; use smallvec::smallvec; @@ -350,6 +350,16 @@ pub trait Styled { self } + fn text_size(mut self, size: Rems) -> Self + where + Self: Sized, + { + self.text_style() + .get_or_insert_with(Default::default) + .font_size = Some(size); + self + } + fn text_xs(mut self) -> Self where Self: Sized, diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index d4aba32f36..b3a54118b7 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -3,10 +3,10 @@ use std::marker::PhantomData; use gpui3::{div, Div}; use crate::prelude::*; +use crate::settings::user_settings; use crate::theme::theme; use crate::{ - h_stack, token, v_stack, Avatar, Icon, IconColor, IconElement, IconSize, Label, LabelColor, - LabelSize, + h_stack, v_stack, Avatar, Icon, IconColor, IconElement, IconSize, Label, LabelColor, LabelSize, }; #[derive(Clone, Copy, Default, Debug, PartialEq)] @@ -94,7 +94,6 @@ impl ListHeader { fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); - let token = token(); let system_color = SystemColor::new(); let color = ThemeColor::new(cx); @@ -166,7 +165,6 @@ impl ListSubHeader { fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); - let token = token(); h_stack().flex_1().w_full().relative().py_1().child( div() @@ -351,7 +349,6 @@ impl ListEntry { cx: &mut ViewContext, ) -> Option> { let theme = theme(cx); - let token = token(); let disclosure_control_icon = if let Some(ToggleState::Toggled) = self.toggle { IconElement::new(Icon::ChevronDown) @@ -374,9 +371,9 @@ impl ListEntry { fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); - let token = token(); let system_color = SystemColor::new(); let color = ThemeColor::new(cx); + let setting = user_settings(); let left_content = match self.left_content { Some(LeftContent::Icon(i)) => Some( @@ -408,7 +405,7 @@ impl ListEntry { // .ml(rems(0.75 * self.indent_level as f32)) .children((0..self.indent_level).map(|_| { div() - .w(token.list_indent_depth) + .w(setting.list_indent_depth()) .h_full() .flex() .justify_center() @@ -484,7 +481,6 @@ impl List { fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); - let token = token(); let is_toggleable = self.toggleable != Toggleable::NotToggleable; let is_toggled = Toggleable::is_toggled(&self.toggleable); diff --git a/crates/ui2/src/components/panel.rs b/crates/ui2/src/components/panel.rs index 7aeb31aa37..7aaf98598f 100644 --- a/crates/ui2/src/components/panel.rs +++ b/crates/ui2/src/components/panel.rs @@ -3,8 +3,9 @@ use std::marker::PhantomData; use gpui3::{AbsoluteLength, AnyElement}; use smallvec::SmallVec; +use crate::settings::user_settings; +use crate::v_stack; use crate::{prelude::*, theme}; -use crate::{token, v_stack}; #[derive(Default, Debug, PartialEq, Eq, Hash, Clone, Copy)] pub enum PanelAllowedSides { @@ -53,14 +54,14 @@ pub struct Panel { impl Panel { pub fn new(scroll_state: ScrollState) -> Self { - let token = token(); + let setting = user_settings(); Self { state_type: PhantomData, scroll_state, current_side: PanelSide::default(), allowed_sides: PanelAllowedSides::default(), - initial_width: token.default_panel_size, + initial_width: setting.default_panel_size(), width: None, children: SmallVec::new(), } @@ -96,7 +97,6 @@ impl Panel { } fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { - let token = token(); let theme = theme(cx); let panel_base; diff --git a/crates/ui2/src/components/title_bar.rs b/crates/ui2/src/components/title_bar.rs index 0613914476..b13982f2a7 100644 --- a/crates/ui2/src/components/title_bar.rs +++ b/crates/ui2/src/components/title_bar.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use gpui3::{view, Context, View}; use crate::prelude::*; +use crate::settings::user_settings; use crate::{ random_players_with_call_status, theme, Avatar, Button, Icon, IconButton, IconColor, MicStatus, PlayerStack, PlayerWithCallStatus, ScreenShareStatus, ToolDivider, TrafficLights, @@ -93,6 +94,9 @@ impl TitleBar { fn render(&mut self, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); + let color = ThemeColor::new(cx); + let setting = user_settings(); + // let has_focus = cx.window_is_active(); let has_focus = true; @@ -107,8 +111,7 @@ impl TitleBar { .items_center() .justify_between() .w_full() - .h_8() - .bg(theme.lowest.base.default.background) + .bg(color.background) .child( div() .flex() @@ -123,6 +126,9 @@ impl TitleBar { .flex() .items_center() .gap_1() + .when(setting.titlebar_show_project_owner(), |this| { + this.child(Button::new("iamnbutler")) + }) .child(Button::new("zed")) .child(Button::new("nate/gpui2-ui-components")), ) diff --git a/crates/ui2/src/components/traffic_lights.rs b/crates/ui2/src/components/traffic_lights.rs index cacc82bc08..0a2b769bca 100644 --- a/crates/ui2/src/components/traffic_lights.rs +++ b/crates/ui2/src/components/traffic_lights.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use crate::prelude::*; -use crate::{theme, token, SystemColor}; +use crate::{theme, SystemColor}; #[derive(Clone, Copy)] enum TrafficLightColor { @@ -62,7 +62,6 @@ impl TrafficLights { fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); - let token = token(); div() .flex() diff --git a/crates/ui2/src/elements/button.rs b/crates/ui2/src/elements/button.rs index ce7edd2a78..5fe901aa6c 100644 --- a/crates/ui2/src/elements/button.rs +++ b/crates/ui2/src/elements/button.rs @@ -1,9 +1,10 @@ use std::marker::PhantomData; use std::sync::Arc; -use gpui3::{DefiniteLength, Hsla, Interactive, MouseButton, WindowContext}; +use gpui3::{rems, DefiniteLength, Hsla, Interactive, MouseButton, WindowContext}; use crate::prelude::*; +use crate::settings::user_settings; use crate::{h_stack, Icon, IconColor, IconElement, Label, LabelColor, LabelSize}; #[derive(Default, PartialEq, Clone, Copy)] @@ -148,11 +149,11 @@ impl Button { fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let icon_color = self.icon_color(); let border_color = self.border_color(cx); + let setting = user_settings(); let mut el = h_stack() - .h_6() - .px_1() - .items_center() + .p_1() + .text_size(rems(1.125 * setting.ui_scale())) .rounded_md() .border() .border_color(border_color) diff --git a/crates/ui2/src/lib.rs b/crates/ui2/src/lib.rs index 51489173ad..417a77fabe 100644 --- a/crates/ui2/src/lib.rs +++ b/crates/ui2/src/lib.rs @@ -4,6 +4,7 @@ mod components; mod element_ext; mod elements; pub mod prelude; +mod settings; mod static_data; mod theme; diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index 44ca262470..015aeadcf4 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -9,34 +9,28 @@ use gpui3::{hsla, rems, rgb, AbsoluteLength, Hsla}; use strum::EnumIter; #[derive(Clone, Copy)] -pub struct Token { +pub struct FakeSettings { pub list_indent_depth: AbsoluteLength, pub default_panel_size: AbsoluteLength, - pub state_hover_background: Hsla, - pub state_active_background: Hsla, } -impl Default for Token { +impl Default for FakeSettings { fn default() -> Self { Self { list_indent_depth: rems(0.3).into(), default_panel_size: AbsoluteLength::Rems(rems(16.)), - state_hover_background: hsla(0.0, 0.0, 0.0, 0.08), - state_active_background: hsla(0.0, 0.0, 0.0, 0.16), } } } -pub fn token() -> Token { - Token::default() -} - #[derive(Default)] pub struct SystemColor { pub transparent: Hsla, pub mac_os_traffic_light_red: Hsla, pub mac_os_traffic_light_yellow: Hsla, pub mac_os_traffic_light_green: Hsla, + pub state_hover_background: Hsla, + pub state_active_background: Hsla, } impl SystemColor { @@ -46,6 +40,8 @@ impl SystemColor { mac_os_traffic_light_red: rgb::(0xEC695E), mac_os_traffic_light_yellow: rgb::(0xF4BF4F), mac_os_traffic_light_green: rgb::(0x62C554), + state_hover_background: hsla(0.0, 0.0, 0.0, 0.08), + state_active_background: hsla(0.0, 0.0, 0.0, 0.16), } } pub fn color(&self) -> Hsla { @@ -62,6 +58,8 @@ pub struct ThemeColor { /// The background color of an elevated surface, like a modal, tooltip or toast. pub elevated_surface: Hsla, pub surface: Hsla, + /// Window background color + pub background: Hsla, /// Default background for elements like filled buttons, /// text fields, checkboxes, radio buttons, etc. /// - TODO: Map to step 3. @@ -99,6 +97,7 @@ impl ThemeColor { border_transparent: system_color.transparent, elevated_surface: theme.middle.base.default.background, surface: theme.middle.base.default.background, + background: theme.lowest.base.default.background, filled_element: theme.lowest.base.default.background, filled_element_hover: theme.lowest.base.hovered.background, filled_element_active: theme.lowest.base.active.background, @@ -251,6 +250,23 @@ pub enum DisclosureControlVisibility { Always, } +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)] +pub enum DisclosureControlStyle { + /// Shows the disclosure control only when hovered where possible. + /// + /// More compact, but not available everywhere. + ChevronOnHover, + /// Shows an icon where possible, otherwise shows a chevron. + /// + /// For example, in a file tree a folder or file icon is shown + /// instead of a chevron + Icon, + /// Always shows a chevron. + Chevron, + /// Completely hides the disclosure control where possible. + None, +} + #[derive(Default, PartialEq, Copy, Clone, EnumIter, strum::Display)] pub enum InteractionState { #[default] diff --git a/crates/ui2/src/settings.rs b/crates/ui2/src/settings.rs new file mode 100644 index 0000000000..4c105f66e1 --- /dev/null +++ b/crates/ui2/src/settings.rs @@ -0,0 +1,102 @@ +use gpui3::{rems, AbsoluteLength}; + +use crate::DisclosureControlStyle; + +// This is a fake static example of user settings overriding the default settings +pub fn user_settings() -> Settings { + let mut settings = Settings::new(); + settings.list_indent_depth = Some(rems(0.5).into()); + settings +} + +#[derive(Clone, Copy)] +pub struct TitlebarSettings { + pub show_project_owner: Option, + pub show_git_status: Option, + pub show_git_controls: Option, +} + +impl Default for TitlebarSettings { + fn default() -> Self { + Self { + show_project_owner: Some(true), + show_git_status: Some(true), + show_git_controls: Some(true), + } + } +} + +#[derive(Clone, Copy)] +pub struct Settings { + pub default_panel_size: Option, + pub list_disclosure_style: Option, + pub list_indent_depth: Option, + pub titlebar: TitlebarSettings, + pub ui_scale: Option, +} + +// These should be merged into settings +impl Settings { + pub fn new() -> Self { + Self { + titlebar: TitlebarSettings::default(), + list_disclosure_style: None, + list_indent_depth: None, + default_panel_size: None, + ui_scale: None, + } + } + + pub fn titlebar_show_project_owner(&self) -> bool { + self.titlebar.show_project_owner.unwrap_or( + Settings::default() + .titlebar + .show_project_owner + .expect("titlebar_show_project_owner default not set."), + ) + } + + pub fn list_disclosure_style(&self) -> DisclosureControlStyle { + self.list_disclosure_style.unwrap_or( + Settings::default() + .list_disclosure_style + .expect("list_disclosure_style default not set."), + ) + } + + pub fn list_indent_depth(&self) -> AbsoluteLength { + self.list_indent_depth.unwrap_or( + Settings::default() + .list_indent_depth + .expect("list_indent_depth default not set."), + ) + } + + pub fn default_panel_size(&self) -> AbsoluteLength { + self.default_panel_size.unwrap_or( + Settings::default() + .default_panel_size + .expect("default_panel_size default not set."), + ) + } + + pub fn ui_scale(&self) -> f32 { + self.ui_scale.unwrap_or( + Settings::default() + .ui_scale + .expect("ui_scale default not set."), + ) + } +} + +impl Default for Settings { + fn default() -> Self { + Self { + titlebar: TitlebarSettings::default(), + list_disclosure_style: Some(DisclosureControlStyle::ChevronOnHover), + list_indent_depth: Some(rems(0.3).into()), + default_panel_size: Some(rems(16.).into()), + ui_scale: Some(1.), + } + } +} From 8b637e194e096d0fc824c1fe23f9bc7221e467db Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Wed, 18 Oct 2023 16:16:58 -0400 Subject: [PATCH 2/2] Update approach to settings Co-Authored-By: Marshall Bowers <1486634+maxdeviant@users.noreply.github.com> --- crates/gpui3/src/styled.rs | 8 +- crates/ui2/src/components/list.rs | 2 +- crates/ui2/src/components/panel.rs | 2 +- crates/ui2/src/components/title_bar.rs | 2 +- crates/ui2/src/elements/button.rs | 5 +- crates/ui2/src/prelude.rs | 9 +- crates/ui2/src/settings.rs | 114 +++++++++---------------- 7 files changed, 59 insertions(+), 83 deletions(-) diff --git a/crates/gpui3/src/styled.rs b/crates/gpui3/src/styled.rs index 4d54ebb5ad..d511198c65 100644 --- a/crates/gpui3/src/styled.rs +++ b/crates/gpui3/src/styled.rs @@ -1,6 +1,6 @@ use crate::{ - self as gpui3, hsla, point, px, relative, rems, AbsoluteLength, AlignItems, Display, Fill, - FlexDirection, Hsla, JustifyContent, Length, Position, Rems, SharedString, StyleRefinement, + self as gpui3, hsla, point, px, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla, + JustifyContent, Length, Position, Rems, SharedString, StyleRefinement, }; use crate::{BoxShadow, TextStyleRefinement}; use smallvec::smallvec; @@ -350,13 +350,13 @@ pub trait Styled { self } - fn text_size(mut self, size: Rems) -> Self + fn text_size(mut self, size: impl Into) -> Self where Self: Sized, { self.text_style() .get_or_insert_with(Default::default) - .font_size = Some(size); + .font_size = Some(size.into()); self } diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index b3a54118b7..8ab1c64e86 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -405,7 +405,7 @@ impl ListEntry { // .ml(rems(0.75 * self.indent_level as f32)) .children((0..self.indent_level).map(|_| { div() - .w(setting.list_indent_depth()) + .w(*setting.list_indent_depth) .h_full() .flex() .justify_center() diff --git a/crates/ui2/src/components/panel.rs b/crates/ui2/src/components/panel.rs index 7aaf98598f..52e36b2f14 100644 --- a/crates/ui2/src/components/panel.rs +++ b/crates/ui2/src/components/panel.rs @@ -61,7 +61,7 @@ impl Panel { scroll_state, current_side: PanelSide::default(), allowed_sides: PanelAllowedSides::default(), - initial_width: setting.default_panel_size(), + initial_width: *setting.default_panel_size, width: None, children: SmallVec::new(), } diff --git a/crates/ui2/src/components/title_bar.rs b/crates/ui2/src/components/title_bar.rs index b13982f2a7..f1d7d42711 100644 --- a/crates/ui2/src/components/title_bar.rs +++ b/crates/ui2/src/components/title_bar.rs @@ -126,7 +126,7 @@ impl TitleBar { .flex() .items_center() .gap_1() - .when(setting.titlebar_show_project_owner(), |this| { + .when(*setting.titlebar.show_project_owner, |this| { this.child(Button::new("iamnbutler")) }) .child(Button::new("zed")) diff --git a/crates/ui2/src/elements/button.rs b/crates/ui2/src/elements/button.rs index 5fe901aa6c..b4d9d8afa6 100644 --- a/crates/ui2/src/elements/button.rs +++ b/crates/ui2/src/elements/button.rs @@ -1,7 +1,8 @@ use std::marker::PhantomData; use std::sync::Arc; -use gpui3::{rems, DefiniteLength, Hsla, Interactive, MouseButton, WindowContext}; +use gpui3::rems; +use gpui3::{DefiniteLength, Hsla, Interactive, MouseButton, WindowContext}; use crate::prelude::*; use crate::settings::user_settings; @@ -153,7 +154,7 @@ impl Button { let mut el = h_stack() .p_1() - .text_size(rems(1.125 * setting.ui_scale())) + .text_size(ui_size(1.125)) .rounded_md() .border() .border_color(border_color) diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index 015aeadcf4..db484b6cfa 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -3,9 +3,10 @@ pub use gpui3::{ ViewContext, WindowContext, }; +use crate::settings::user_settings; pub use crate::{theme, ButtonVariant, ElementExt, Theme}; -use gpui3::{hsla, rems, rgb, AbsoluteLength, Hsla}; +use gpui3::{hsla, rems, rgb, AbsoluteLength, Hsla, Rems}; use strum::EnumIter; #[derive(Clone, Copy)] @@ -156,6 +157,12 @@ impl HighlightColor { } } +pub fn ui_size(size: f32) -> Rems { + let setting = user_settings(); + + rems(*setting.ui_scale * size) +} + #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)] pub enum FileSystemStatus { #[default] diff --git a/crates/ui2/src/settings.rs b/crates/ui2/src/settings.rs index 4c105f66e1..a387b8ddd9 100644 --- a/crates/ui2/src/settings.rs +++ b/crates/ui2/src/settings.rs @@ -1,102 +1,70 @@ +use std::ops::Deref; + use gpui3::{rems, AbsoluteLength}; use crate::DisclosureControlStyle; // This is a fake static example of user settings overriding the default settings pub fn user_settings() -> Settings { - let mut settings = Settings::new(); - settings.list_indent_depth = Some(rems(0.5).into()); + let mut settings = Settings::default(); + settings.list_indent_depth = SettingValue::UserDefined(rems(0.5).into()); settings } -#[derive(Clone, Copy)] +#[derive(Clone)] +pub enum SettingValue { + UserDefined(T), + Default(T), +} + +impl Deref for SettingValue { + type Target = T; + + fn deref(&self) -> &Self::Target { + match self { + Self::UserDefined(value) => value, + Self::Default(value) => value, + } + } +} + +#[derive(Clone)] pub struct TitlebarSettings { - pub show_project_owner: Option, - pub show_git_status: Option, - pub show_git_controls: Option, + pub show_project_owner: SettingValue, + pub show_git_status: SettingValue, + pub show_git_controls: SettingValue, } impl Default for TitlebarSettings { fn default() -> Self { Self { - show_project_owner: Some(true), - show_git_status: Some(true), - show_git_controls: Some(true), + show_project_owner: SettingValue::Default(true), + show_git_status: SettingValue::Default(true), + show_git_controls: SettingValue::Default(true), } } } -#[derive(Clone, Copy)] -pub struct Settings { - pub default_panel_size: Option, - pub list_disclosure_style: Option, - pub list_indent_depth: Option, - pub titlebar: TitlebarSettings, - pub ui_scale: Option, -} - // These should be merged into settings -impl Settings { - pub fn new() -> Self { - Self { - titlebar: TitlebarSettings::default(), - list_disclosure_style: None, - list_indent_depth: None, - default_panel_size: None, - ui_scale: None, - } - } - - pub fn titlebar_show_project_owner(&self) -> bool { - self.titlebar.show_project_owner.unwrap_or( - Settings::default() - .titlebar - .show_project_owner - .expect("titlebar_show_project_owner default not set."), - ) - } - - pub fn list_disclosure_style(&self) -> DisclosureControlStyle { - self.list_disclosure_style.unwrap_or( - Settings::default() - .list_disclosure_style - .expect("list_disclosure_style default not set."), - ) - } - - pub fn list_indent_depth(&self) -> AbsoluteLength { - self.list_indent_depth.unwrap_or( - Settings::default() - .list_indent_depth - .expect("list_indent_depth default not set."), - ) - } - - pub fn default_panel_size(&self) -> AbsoluteLength { - self.default_panel_size.unwrap_or( - Settings::default() - .default_panel_size - .expect("default_panel_size default not set."), - ) - } - - pub fn ui_scale(&self) -> f32 { - self.ui_scale.unwrap_or( - Settings::default() - .ui_scale - .expect("ui_scale default not set."), - ) - } +#[derive(Clone)] +pub struct Settings { + pub default_panel_size: SettingValue, + pub list_disclosure_style: SettingValue, + pub list_indent_depth: SettingValue, + pub titlebar: TitlebarSettings, + pub ui_scale: SettingValue, } impl Default for Settings { fn default() -> Self { Self { titlebar: TitlebarSettings::default(), - list_disclosure_style: Some(DisclosureControlStyle::ChevronOnHover), - list_indent_depth: Some(rems(0.3).into()), - default_panel_size: Some(rems(16.).into()), - ui_scale: Some(1.), + list_disclosure_style: SettingValue::Default(DisclosureControlStyle::ChevronOnHover), + list_indent_depth: SettingValue::Default(rems(0.3).into()), + default_panel_size: SettingValue::Default(rems(16.).into()), + ui_scale: SettingValue::Default(1.), } } } + +impl Settings {}