diff --git a/crates/gpui3/src/styled.rs b/crates/gpui3/src/styled.rs index 56a1b68c75d56754d61b28d62a9e979df92e7eb4..4d54ebb5addc4a59d26ed35c393405eef485e266 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 d4aba32f36544ea30cd91d8b9a532033106c4dcd..b3a54118b77402556e878f8355b6b75081ab909a 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 7aeb31aa37a54cfb8c38b4bd1c8339633972d620..7aaf98598f6fa0b13ee6e0148125eff4baf9619b 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 06139144769e6ef5a0524d8b8d0ac414c01be803..b13982f2a76669f9966e1c7d897b04f0aad6fd68 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 cacc82bc08b3abe5c01b3fdd909b8acb952f275e..0a2b769bca61db89da45ac79a0b707ad5842db2b 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 ce7edd2a780bc450337a7389cb6dc33768a9c9b8..5fe901aa6c9201217b1a705c8331700e73586d29 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 51489173add9baa31063c180143ad3c62bb9739a..417a77fabe59b1e89794765b06ce9531c679ad10 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 44ca262470bd0de354a07f0323a94e37ee80b47e..015aeadcf45956dfd2cbb5c7092bcf596ec6fb96 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 0000000000000000000000000000000000000000..4c105f66e10d07ed074f6735e34eb3a797f5a459 --- /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.), + } + } +}