Update UI elements and implement user settings for customization

This commit is contained in:
Nate Butler 2023-10-18 15:42:10 -04:00
parent 6e3393c93f
commit 289255d67a
9 changed files with 163 additions and 32 deletions

View file

@ -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,

View file

@ -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<S: 'static + Send + Sync + Clone> ListHeader<S> {
fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
let theme = theme(cx);
let token = token();
let system_color = SystemColor::new();
let color = ThemeColor::new(cx);
@ -166,7 +165,6 @@ impl<S: 'static + Send + Sync + Clone> ListSubHeader<S> {
fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
let theme = theme(cx);
let token = token();
h_stack().flex_1().w_full().relative().py_1().child(
div()
@ -351,7 +349,6 @@ impl<S: 'static + Send + Sync + Clone> ListEntry<S> {
cx: &mut ViewContext<S>,
) -> Option<impl Element<ViewState = S>> {
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<S: 'static + Send + Sync + Clone> ListEntry<S> {
fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
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<S: 'static + Send + Sync + Clone> ListEntry<S> {
// .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<S: 'static + Send + Sync + Clone> List<S> {
fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
let theme = theme(cx);
let token = token();
let is_toggleable = self.toggleable != Toggleable::NotToggleable;
let is_toggled = Toggleable::is_toggled(&self.toggleable);

View file

@ -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<S: 'static + Send + Sync> {
impl<S: 'static + Send + Sync> Panel<S> {
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<S: 'static + Send + Sync> Panel<S> {
}
fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
let token = token();
let theme = theme(cx);
let panel_base;

View file

@ -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<Self>) -> impl Element<ViewState = Self> {
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")),
)

View file

@ -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<S: 'static + Send + Sync> TrafficLights<S> {
fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
let theme = theme(cx);
let token = token();
div()
.flex()

View file

@ -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<S: 'static + Send + Sync + Clone> Button<S> {
fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
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)

View file

@ -4,6 +4,7 @@ mod components;
mod element_ext;
mod elements;
pub mod prelude;
mod settings;
mod static_data;
mod theme;

View file

@ -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::<Hsla>(0xEC695E),
mac_os_traffic_light_yellow: rgb::<Hsla>(0xF4BF4F),
mac_os_traffic_light_green: rgb::<Hsla>(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]

102
crates/ui2/src/settings.rs Normal file
View file

@ -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<bool>,
pub show_git_status: Option<bool>,
pub show_git_controls: Option<bool>,
}
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<AbsoluteLength>,
pub list_disclosure_style: Option<DisclosureControlStyle>,
pub list_indent_depth: Option<AbsoluteLength>,
pub titlebar: TitlebarSettings,
pub ui_scale: Option<f32>,
}
// 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.),
}
}
}