diff --git a/crates/theme/src/settings.rs b/crates/theme/src/settings.rs index d1b329dfb4..bd590ba533 100644 --- a/crates/theme/src/settings.rs +++ b/crates/theme/src/settings.rs @@ -381,6 +381,10 @@ pub fn adjust_buffer_font_size(cx: &mut AppContext, f: fn(&mut Pixels)) { cx.refresh(); } +pub fn has_adjusted_buffer_font_size(cx: &mut AppContext) -> bool { + cx.has_global::() +} + pub fn reset_buffer_font_size(cx: &mut AppContext) { if cx.has_global::() { cx.remove_global::(); @@ -417,6 +421,10 @@ pub fn adjust_ui_font_size(cx: &mut WindowContext, f: fn(&mut Pixels)) { cx.refresh(); } +pub fn has_adjusted_ui_font_size(cx: &mut AppContext) -> bool { + cx.has_global::() +} + pub fn reset_ui_font_size(cx: &mut WindowContext) { if cx.has_global::() { cx.remove_global::(); diff --git a/crates/title_bar/Cargo.toml b/crates/title_bar/Cargo.toml index 5e5bd754e5..919d738bd2 100644 --- a/crates/title_bar/Cargo.toml +++ b/crates/title_bar/Cargo.toml @@ -42,7 +42,6 @@ project.workspace = true recent_projects.workspace = true rpc.workspace = true serde.workspace = true -settings.workspace = true smallvec.workspace = true story = { workspace = true, optional = true } theme.workspace = true diff --git a/crates/title_bar/src/application_menu.rs b/crates/title_bar/src/application_menu.rs index a55b0d600b..44d8f8b53c 100644 --- a/crates/title_bar/src/application_menu.rs +++ b/crates/title_bar/src/application_menu.rs @@ -1,6 +1,4 @@ -use settings::Settings; -use theme::ThemeSettings; -use ui::{prelude::*, ContextMenu, PopoverMenu, Tooltip}; +use ui::{prelude::*, ContextMenu, NumericStepper, PopoverMenu, Tooltip}; #[derive(IntoElement)] pub struct ApplicationMenu; @@ -12,128 +10,77 @@ impl ApplicationMenu { } impl RenderOnce for ApplicationMenu { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { - let ui_font_size = ThemeSettings::get_global(cx).ui_font_size; - let font = cx.text_style().font(); - let font_id = cx.text_system().resolve_font(&font); - let width = cx - .text_system() - .typographic_bounds(font_id, ui_font_size, 'm') - .unwrap() - .size - .width - * 3.0; - + fn render(self, _cx: &mut WindowContext) -> impl IntoElement { PopoverMenu::new("application-menu") .menu(move |cx| { - let width = width; ContextMenu::build(cx, move |menu, _cx| { - let width = width; menu.header("Workspace") .action("Open Command Palette", Box::new(command_palette::Toggle)) .custom_row(move |cx| { - div() + h_flex() + .gap_2() .w_full() - .flex() - .flex_row() .justify_between() .cursor(gpui::CursorStyle::Arrow) .child(Label::new("Buffer Font Size")) .child( - div() - .flex() - .flex_row() - .child(div().w(px(16.0))) - .child( - IconButton::new( - "reset-buffer-zoom", - IconName::RotateCcw, - ) - .on_click( - |_, cx| { - cx.dispatch_action(Box::new( - zed_actions::ResetBufferFontSize, - )) - }, - ), - ) - .child( - IconButton::new("--buffer-zoom", IconName::Dash) - .on_click(|_, cx| { - cx.dispatch_action(Box::new( - zed_actions::DecreaseBufferFontSize, - )) - }), - ) - .child( - div() - .w(width) - .flex() - .flex_row() - .justify_around() - .child(Label::new( - theme::get_buffer_font_size(cx).to_string(), - )), - ) - .child( - IconButton::new("+-buffer-zoom", IconName::Plus) - .on_click(|_, cx| { - cx.dispatch_action(Box::new( - zed_actions::IncreaseBufferFontSize, - )) - }), - ), + NumericStepper::new( + theme::get_buffer_font_size(cx).to_string(), + |_, cx| { + cx.dispatch_action(Box::new( + zed_actions::DecreaseBufferFontSize, + )) + }, + |_, cx| { + cx.dispatch_action(Box::new( + zed_actions::IncreaseBufferFontSize, + )) + }, + ) + .when( + theme::has_adjusted_buffer_font_size(cx), + |stepper| { + stepper.on_reset(|_, cx| { + cx.dispatch_action(Box::new( + zed_actions::ResetBufferFontSize, + )) + }) + }, + ), ) .into_any_element() }) .custom_row(move |cx| { - div() + h_flex() + .gap_2() .w_full() - .flex() - .flex_row() .justify_between() .cursor(gpui::CursorStyle::Arrow) .child(Label::new("UI Font Size")) .child( - div() - .flex() - .flex_row() - .child( - IconButton::new("reset-ui-zoom", IconName::RotateCcw) - .on_click(|_, cx| { - cx.dispatch_action(Box::new( - zed_actions::ResetUiFontSize, - )) - }), - ) - .child( - IconButton::new("--ui-zoom", IconName::Dash).on_click( - |_, cx| { - cx.dispatch_action(Box::new( - zed_actions::DecreaseUiFontSize, - )) - }, - ), - ) - .child( - div() - .w(width) - .flex() - .flex_row() - .justify_around() - .child(Label::new( - theme::get_ui_font_size(cx).to_string(), - )), - ) - .child( - IconButton::new("+-ui-zoom", IconName::Plus).on_click( - |_, cx| { - cx.dispatch_action(Box::new( - zed_actions::IncreaseUiFontSize, - )) - }, - ), - ), + NumericStepper::new( + theme::get_ui_font_size(cx).to_string(), + |_, cx| { + cx.dispatch_action(Box::new( + zed_actions::DecreaseUiFontSize, + )) + }, + |_, cx| { + cx.dispatch_action(Box::new( + zed_actions::IncreaseUiFontSize, + )) + }, + ) + .when( + theme::has_adjusted_ui_font_size(cx), + |stepper| { + stepper.on_reset(|_, cx| { + cx.dispatch_action(Box::new( + zed_actions::ResetUiFontSize, + )) + }) + }, + ), ) .into_any_element() }) diff --git a/crates/ui/src/components.rs b/crates/ui/src/components.rs index 1ceaf43487..d987a99d1c 100644 --- a/crates/ui/src/components.rs +++ b/crates/ui/src/components.rs @@ -12,6 +12,7 @@ mod keybinding; mod label; mod list; mod modal; +mod numeric_stepper; mod popover; mod popover_menu; mod radio; @@ -40,6 +41,7 @@ pub use keybinding::*; pub use label::*; pub use list::*; pub use modal::*; +pub use numeric_stepper::*; pub use popover::*; pub use popover_menu::*; pub use radio::*; diff --git a/crates/ui/src/components/button/icon_button.rs b/crates/ui/src/components/button/icon_button.rs index cb88793240..03a5c3a22d 100644 --- a/crates/ui/src/components/button/icon_button.rs +++ b/crates/ui/src/components/button/icon_button.rs @@ -1,6 +1,6 @@ use gpui::{AnyView, DefiniteLength}; -use crate::{prelude::*, ElevationIndex, SelectableButton, Spacing}; +use crate::{prelude::*, ElevationIndex, SelectableButton}; use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, IconName, IconSize}; use super::button_icon::ButtonIcon; @@ -147,16 +147,8 @@ impl RenderOnce for IconButton { self.base .map(|this| match self.shape { IconButtonShape::Square => { - let icon_size = self.icon_size.rems() * cx.rem_size(); - let padding = match self.icon_size { - IconSize::Indicator => Spacing::None.px(cx), - IconSize::XSmall => Spacing::XSmall.px(cx), - IconSize::Small => Spacing::XSmall.px(cx), - IconSize::Medium => Spacing::XSmall.px(cx), - }; - - this.width((icon_size + padding * 2.).into()) - .height((icon_size + padding * 2.).into()) + let size = self.icon_size.square(cx); + this.width(size.into()).height(size.into()) } IconButtonShape::Wide => this, }) diff --git a/crates/ui/src/components/icon.rs b/crates/ui/src/components/icon.rs index c9135c2883..332e30a14d 100644 --- a/crates/ui/src/components/icon.rs +++ b/crates/ui/src/components/icon.rs @@ -75,6 +75,19 @@ impl IconSize { IconSize::Medium => rems_from_px(16.), } } + + /// Returns the length of a side of the square that contains this [`IconSize`], with padding. + pub(crate) fn square(&self, cx: &mut WindowContext) -> Pixels { + let icon_size = self.rems() * cx.rem_size(); + let padding = match self { + IconSize::Indicator => Spacing::None.px(cx), + IconSize::XSmall => Spacing::XSmall.px(cx), + IconSize::Small => Spacing::XSmall.px(cx), + IconSize::Medium => Spacing::XSmall.px(cx), + }; + + icon_size + padding * 2. + } } #[derive(Debug, PartialEq, Copy, Clone, EnumIter, Serialize, Deserialize)] diff --git a/crates/ui/src/components/numeric_stepper.rs b/crates/ui/src/components/numeric_stepper.rs new file mode 100644 index 0000000000..027ff89008 --- /dev/null +++ b/crates/ui/src/components/numeric_stepper.rs @@ -0,0 +1,81 @@ +use gpui::ClickEvent; + +use crate::{prelude::*, IconButtonShape}; + +#[derive(IntoElement)] +pub struct NumericStepper { + value: SharedString, + on_decrement: Box, + on_increment: Box, + on_reset: Option>, +} + +impl NumericStepper { + pub fn new( + value: impl Into, + on_decrement: impl Fn(&ClickEvent, &mut WindowContext) + 'static, + on_increment: impl Fn(&ClickEvent, &mut WindowContext) + 'static, + ) -> Self { + Self { + value: value.into(), + on_decrement: Box::new(on_decrement), + on_increment: Box::new(on_increment), + on_reset: None, + } + } + + pub fn on_reset( + mut self, + on_reset: impl Fn(&ClickEvent, &mut WindowContext) + 'static, + ) -> Self { + self.on_reset = Some(Box::new(on_reset)); + self + } +} + +impl RenderOnce for NumericStepper { + fn render(self, cx: &mut WindowContext) -> impl IntoElement { + let shape = IconButtonShape::Square; + let icon_size = IconSize::Small; + + h_flex() + .gap_1() + .map(|element| { + if let Some(on_reset) = self.on_reset { + element.child( + IconButton::new("reset", IconName::RotateCcw) + .shape(shape) + .icon_size(icon_size) + .on_click(on_reset), + ) + } else { + element.child( + h_flex() + .size(icon_size.square(cx)) + .flex_none() + .into_any_element(), + ) + } + }) + .child( + h_flex() + .gap_1() + .px_1() + .rounded_sm() + .bg(cx.theme().colors().editor_background) + .child( + IconButton::new("decrement", IconName::Dash) + .shape(shape) + .icon_size(icon_size) + .on_click(self.on_decrement), + ) + .child(Label::new(self.value)) + .child( + IconButton::new("increment", IconName::Plus) + .shape(shape) + .icon_size(icon_size) + .on_click(self.on_increment), + ), + ) + } +} diff --git a/crates/ui/src/components/title_bar.rs b/crates/ui/src/components/title_bar.rs deleted file mode 100644 index 28aac32c73..0000000000 --- a/crates/ui/src/components/title_bar.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod linux_window_controls; -mod title_bar; -mod windows_window_controls; - -pub use title_bar::*;