diff --git a/Cargo.lock b/Cargo.lock index a71a04ca94..672aefb0ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9586,7 +9586,11 @@ version = "0.1.0" dependencies = [ "command_palette_hooks", "feature_flags", + "fs", "gpui", + "project", + "settings", + "theme", "ui", "workspace", ] diff --git a/crates/settings_ui/Cargo.toml b/crates/settings_ui/Cargo.toml index 348f9f104b..8f6a33fe42 100644 --- a/crates/settings_ui/Cargo.toml +++ b/crates/settings_ui/Cargo.toml @@ -14,6 +14,10 @@ path = "src/settings_ui.rs" [dependencies] command_palette_hooks.workspace = true feature_flags.workspace = true +fs.workspace = true gpui.workspace = true +project.workspace = true +settings.workspace = true +theme.workspace = true ui.workspace = true workspace.workspace = true diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index 14d7ba5654..a166af53b0 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -1,3 +1,5 @@ +mod theme_settings_ui; + use std::any::TypeId; use command_palette_hooks::CommandPaletteFilter; @@ -7,6 +9,10 @@ use ui::prelude::*; use workspace::item::{Item, ItemEvent}; use workspace::Workspace; +use crate::theme_settings_ui::{ + BufferFontSizeSetting, EditableSetting, InlineGitBlameSetting, UiFontSizeSetting, +}; + pub struct SettingsUiFeatureFlag; impl FeatureFlag for SettingsUiFeatureFlag { @@ -95,7 +101,7 @@ impl Item for SettingsPage { } impl Render for SettingsPage { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { v_flex() .p_4() .size_full() @@ -103,5 +109,8 @@ impl Render for SettingsPage { .child(Label::new( "Nothing to see here yet. Feature-flagged for staff.", )) + .child(UiFontSizeSetting::new(cx)) + .child(BufferFontSizeSetting::new(cx)) + .child(InlineGitBlameSetting::new(cx)) } } diff --git a/crates/settings_ui/src/theme_settings_ui.rs b/crates/settings_ui/src/theme_settings_ui.rs new file mode 100644 index 0000000000..d8cc8cd311 --- /dev/null +++ b/crates/settings_ui/src/theme_settings_ui.rs @@ -0,0 +1,190 @@ +use fs::Fs; +use gpui::AppContext; +use project::project_settings::{InlineBlameSettings, ProjectSettings}; +use settings::{update_settings_file, Settings}; +use theme::ThemeSettings; +use ui::{prelude::*, CheckboxWithLabel, NumericStepper}; + +pub trait EditableSetting: RenderOnce { + /// The type of the setting value. + type Value: Send; + + /// The settings type to which this setting belongs. + type Settings: Settings; + + /// Returns the name of this setting. + fn name(&self) -> SharedString; + + /// Returns the icon to be displayed in place of the setting name. + fn icon(&self) -> Option { + None + } + + /// Returns a new instance of this setting. + fn new(cx: &AppContext) -> Self; + + /// Applies the given setting file to the settings file contents. + /// + /// This will be called when writing the setting value back to the settings file. + fn apply(settings: &mut ::FileContent, value: Self::Value); + + /// Writes the given setting value to the settings files. + fn write(value: Self::Value, cx: &AppContext) { + let fs = ::global(cx); + + update_settings_file::(fs, cx, move |settings, _cx| { + Self::apply(settings, value); + }); + } +} + +#[derive(IntoElement)] +pub struct UiFontSizeSetting(Pixels); + +impl EditableSetting for UiFontSizeSetting { + type Value = Pixels; + type Settings = ThemeSettings; + + fn name(&self) -> SharedString { + "UI Font Size".into() + } + + fn icon(&self) -> Option { + Some(IconName::FontSize) + } + + fn new(cx: &AppContext) -> Self { + let settings = ThemeSettings::get_global(cx); + + Self(settings.ui_font_size) + } + + fn apply(settings: &mut ::FileContent, value: Self::Value) { + settings.ui_font_size = Some(value.into()); + } +} + +impl RenderOnce for UiFontSizeSetting { + fn render(self, _cx: &mut WindowContext) -> impl IntoElement { + let value = self.0; + + h_flex() + .gap_2() + .map(|el| { + if let Some(icon) = self.icon() { + el.child(Icon::new(icon)) + } else { + el.child(Label::new(self.name())) + } + }) + .child(NumericStepper::new( + self.0.to_string(), + move |_, cx| { + Self::write(value - px(1.), cx); + }, + move |_, cx| { + Self::write(value + px(1.), cx); + }, + )) + } +} + +#[derive(IntoElement)] +pub struct BufferFontSizeSetting(Pixels); + +impl EditableSetting for BufferFontSizeSetting { + type Value = Pixels; + type Settings = ThemeSettings; + + fn name(&self) -> SharedString { + "Buffer Font Size".into() + } + + fn icon(&self) -> Option { + Some(IconName::FontSize) + } + + fn new(cx: &AppContext) -> Self { + let settings = ThemeSettings::get_global(cx); + + Self(settings.buffer_font_size) + } + + fn apply(settings: &mut ::FileContent, value: Self::Value) { + settings.buffer_font_size = Some(value.into()); + } +} + +impl RenderOnce for BufferFontSizeSetting { + fn render(self, _cx: &mut WindowContext) -> impl IntoElement { + let value = self.0; + + h_flex() + .gap_2() + .map(|el| { + if let Some(icon) = self.icon() { + el.child(Icon::new(icon)) + } else { + el.child(Label::new(self.name())) + } + }) + .child(NumericStepper::new( + self.0.to_string(), + move |_, cx| { + Self::write(value - px(1.), cx); + }, + move |_, cx| { + Self::write(value + px(1.), cx); + }, + )) + } +} + +#[derive(IntoElement)] +pub struct InlineGitBlameSetting(bool); + +impl EditableSetting for InlineGitBlameSetting { + type Value = bool; + type Settings = ProjectSettings; + + fn name(&self) -> SharedString { + "Inline Git Blame".into() + } + + fn new(cx: &AppContext) -> Self { + let settings = ProjectSettings::get_global(cx); + Self(settings.git.inline_blame_enabled()) + } + + fn apply(settings: &mut ::FileContent, value: Self::Value) { + if let Some(inline_blame) = settings.git.inline_blame.as_mut() { + inline_blame.enabled = value; + } else { + settings.git.inline_blame = Some(InlineBlameSettings { + enabled: false, + ..Default::default() + }); + } + } +} + +impl RenderOnce for InlineGitBlameSetting { + fn render(self, _cx: &mut WindowContext) -> impl IntoElement { + let value = self.0; + + CheckboxWithLabel::new( + "inline-git-blame", + Label::new(self.name()), + value.into(), + |selection, cx| { + Self::write( + match selection { + Selection::Selected => true, + Selection::Unselected | Selection::Indeterminate => false, + }, + cx, + ); + }, + ) + } +}