settings_ui: Add theme settings controls (#15115)

This PR adds settings controls for the theme settings.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-07-24 16:25:52 -04:00 committed by GitHub
parent 325e6b9fef
commit 740c444089
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 392 additions and 156 deletions

View file

@ -0,0 +1,257 @@
use gpui::{AppContext, FontWeight};
use settings::{EditableSettingControl, Settings};
use theme::{SystemAppearance, ThemeMode, ThemeRegistry, ThemeSettings};
use ui::{
prelude::*, ContextMenu, DropdownMenu, NumericStepper, SettingsContainer, SettingsGroup,
ToggleButton,
};
#[derive(IntoElement)]
pub struct AppearanceSettingsControls {}
impl AppearanceSettingsControls {
pub fn new() -> Self {
Self {}
}
}
impl RenderOnce for AppearanceSettingsControls {
fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
SettingsContainer::new()
.child(
SettingsGroup::new("Theme").child(
h_flex()
.gap_2()
.justify_between()
.child(ThemeControl)
.child(ThemeModeControl),
),
)
.child(
SettingsGroup::new("Font")
.child(UiFontSizeControl)
.child(UiFontWeightControl),
)
}
}
#[derive(IntoElement)]
struct ThemeControl;
impl EditableSettingControl for ThemeControl {
type Value = String;
type Settings = ThemeSettings;
fn name(&self) -> SharedString {
"Theme".into()
}
fn read(cx: &AppContext) -> Self::Value {
let settings = ThemeSettings::get_global(cx);
let appearance = SystemAppearance::global(cx);
settings
.theme_selection
.as_ref()
.map(|selection| selection.theme(appearance.0).to_string())
.unwrap_or_else(|| ThemeSettings::default_theme(*appearance).to_string())
}
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
cx: &AppContext,
) {
let appearance = SystemAppearance::global(cx);
settings.set_theme(value, appearance.0);
}
}
impl RenderOnce for ThemeControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let value = Self::read(cx);
DropdownMenu::new(
"theme",
value.clone(),
ContextMenu::build(cx, |mut menu, cx| {
let theme_registry = ThemeRegistry::global(cx);
for theme in theme_registry.list_names(false) {
menu = menu.custom_entry(
{
let theme = theme.clone();
move |_cx| Label::new(theme.clone()).into_any_element()
},
{
let theme = theme.clone();
move |cx| {
Self::write(theme.to_string(), cx);
}
},
)
}
menu
}),
)
.full_width(true)
}
}
#[derive(IntoElement)]
struct ThemeModeControl;
impl EditableSettingControl for ThemeModeControl {
type Value = ThemeMode;
type Settings = ThemeSettings;
fn name(&self) -> SharedString {
"Theme Mode".into()
}
fn read(cx: &AppContext) -> Self::Value {
let settings = ThemeSettings::get_global(cx);
settings
.theme_selection
.as_ref()
.and_then(|selection| selection.mode())
.unwrap_or_default()
}
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
_cx: &AppContext,
) {
settings.set_mode(value);
}
}
impl RenderOnce for ThemeModeControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let value = Self::read(cx);
h_flex()
.child(
ToggleButton::new("light", "Light")
.style(ButtonStyle::Filled)
.size(ButtonSize::Large)
.selected(value == ThemeMode::Light)
.on_click(|_, cx| Self::write(ThemeMode::Light, cx))
.first(),
)
.child(
ToggleButton::new("system", "System")
.style(ButtonStyle::Filled)
.size(ButtonSize::Large)
.selected(value == ThemeMode::System)
.on_click(|_, cx| Self::write(ThemeMode::System, cx))
.middle(),
)
.child(
ToggleButton::new("dark", "Dark")
.style(ButtonStyle::Filled)
.size(ButtonSize::Large)
.selected(value == ThemeMode::Dark)
.on_click(|_, cx| Self::write(ThemeMode::Dark, cx))
.last(),
)
}
}
#[derive(IntoElement)]
struct UiFontSizeControl;
impl EditableSettingControl for UiFontSizeControl {
type Value = Pixels;
type Settings = ThemeSettings;
fn name(&self) -> SharedString {
"UI Font Size".into()
}
fn read(cx: &AppContext) -> Self::Value {
let settings = ThemeSettings::get_global(cx);
settings.ui_font_size
}
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
_cx: &AppContext,
) {
settings.ui_font_size = Some(value.into());
}
}
impl RenderOnce for UiFontSizeControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let value = Self::read(cx);
h_flex()
.gap_2()
.child(Icon::new(IconName::FontSize))
.child(NumericStepper::new(
value.to_string(),
move |_, cx| {
Self::write(value - px(1.), cx);
},
move |_, cx| {
Self::write(value + px(1.), cx);
},
))
}
}
#[derive(IntoElement)]
struct UiFontWeightControl;
impl EditableSettingControl for UiFontWeightControl {
type Value = FontWeight;
type Settings = ThemeSettings;
fn name(&self) -> SharedString {
"UI Font Weight".into()
}
fn read(cx: &AppContext) -> Self::Value {
let settings = ThemeSettings::get_global(cx);
settings.ui_font.weight
}
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
_cx: &AppContext,
) {
settings.ui_font_weight = Some(value.0);
}
}
impl RenderOnce for UiFontWeightControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let value = Self::read(cx);
h_flex()
.gap_2()
.child(Icon::new(IconName::FontWeight))
.child(DropdownMenu::new(
"ui-font-weight",
value.0.to_string(),
ContextMenu::build(cx, |mut menu, _cx| {
for weight in FontWeight::ALL {
menu = menu.custom_entry(
move |_cx| Label::new(weight.0.to_string()).into_any_element(),
{
move |cx| {
Self::write(weight, cx);
}
},
)
}
menu
}),
))
}
}

View file

@ -1,4 +1,4 @@
mod theme_settings_controls;
mod appearance_settings_controls;
use std::any::TypeId;
@ -10,7 +10,7 @@ use ui::prelude::*;
use workspace::item::{Item, ItemEvent};
use workspace::Workspace;
use crate::theme_settings_controls::ThemeSettingsControls;
use crate::appearance_settings_controls::AppearanceSettingsControls;
pub struct SettingsUiFeatureFlag;
@ -110,7 +110,7 @@ impl Render for SettingsPage {
v_flex()
.gap_1()
.child(Label::new("Appearance"))
.child(ThemeSettingsControls::new()),
.child(AppearanceSettingsControls::new()),
)
.child(
v_flex()

View file

@ -1,112 +0,0 @@
use gpui::{AppContext, FontWeight};
use settings::{EditableSettingControl, Settings};
use theme::ThemeSettings;
use ui::{prelude::*, ContextMenu, DropdownMenu, NumericStepper, SettingsContainer, SettingsGroup};
#[derive(IntoElement)]
pub struct ThemeSettingsControls {}
impl ThemeSettingsControls {
pub fn new() -> Self {
Self {}
}
}
impl RenderOnce for ThemeSettingsControls {
fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
SettingsContainer::new().child(
SettingsGroup::new("Font")
.child(UiFontSizeControl)
.child(UiFontWeightControl),
)
}
}
#[derive(IntoElement)]
struct UiFontSizeControl;
impl EditableSettingControl for UiFontSizeControl {
type Value = Pixels;
type Settings = ThemeSettings;
fn name(&self) -> SharedString {
"UI Font Size".into()
}
fn read(cx: &AppContext) -> Self::Value {
let settings = ThemeSettings::get_global(cx);
settings.ui_font_size
}
fn apply(settings: &mut <Self::Settings as Settings>::FileContent, value: Self::Value) {
settings.ui_font_size = Some(value.into());
}
}
impl RenderOnce for UiFontSizeControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let value = Self::read(cx);
h_flex()
.gap_2()
.child(Icon::new(IconName::FontSize))
.child(NumericStepper::new(
value.to_string(),
move |_, cx| {
Self::write(value - px(1.), cx);
},
move |_, cx| {
Self::write(value + px(1.), cx);
},
))
}
}
#[derive(IntoElement)]
struct UiFontWeightControl;
impl EditableSettingControl for UiFontWeightControl {
type Value = FontWeight;
type Settings = ThemeSettings;
fn name(&self) -> SharedString {
"UI Font Weight".into()
}
fn read(cx: &AppContext) -> Self::Value {
let settings = ThemeSettings::get_global(cx);
settings.ui_font.weight
}
fn apply(settings: &mut <Self::Settings as Settings>::FileContent, value: Self::Value) {
settings.ui_font_weight = Some(value.0);
}
}
impl RenderOnce for UiFontWeightControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let value = Self::read(cx);
h_flex()
.gap_2()
.child(Icon::new(IconName::FontWeight))
.child(DropdownMenu::new(
"ui-font-weight",
value.0.to_string(),
ContextMenu::build(cx, |mut menu, _cx| {
for weight in FontWeight::ALL {
menu = menu.custom_entry(
move |_cx| Label::new(weight.0.to_string()).into_any_element(),
{
move |cx| {
Self::write(weight, cx);
}
},
)
}
menu
}),
))
}
}