spacing.rs

  1use gpui::{px, rems, Pixels, Rems, WindowContext};
  2use settings::Settings;
  3use theme::{ThemeSettings, UiDensity};
  4
  5use crate::{rems_from_px, BASE_REM_SIZE_IN_PX};
  6
  7/// A dynamic spacing system that adjusts spacing based on
  8/// [UiDensity].
  9///
 10/// When possible, [Spacing] should be used over manual
 11/// or built-in spacing values in places dynamic spacing is needed.
 12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 13pub enum Spacing {
 14    /// No spacing
 15    None,
 16    /// Usually a one pixel spacing. Grows to 2px in comfortable density.
 17    /// @16px/rem: `1px`|`1px`|`2px`
 18    XXSmall,
 19    /// Extra small spacing - @16px/rem: `1px`|`2px`|`4px`
 20    ///
 21    /// Relative to the user's `ui_font_size` and [UiDensity] setting.
 22    XSmall,
 23    /// Small spacing - @16px/rem: `2px`|`4px`|`6px`
 24    ///
 25    /// Relative to the user's `ui_font_size` and [UiDensity] setting.
 26    Small,
 27    /// Medium spacing - @16px/rem: `3px`|`6px`|`8px`
 28    ///
 29    /// Relative to the user's `ui_font_size` and [UiDensity] setting.
 30    Medium,
 31    /// Large spacing - @16px/rem: `4px`|`8px`|`10px`
 32    ///
 33    /// Relative to the user's `ui_font_size` and [UiDensity] setting.
 34    Large,
 35    /// Extra Large spacing - @16px/rem: `8px`|`12px`|`16px`
 36    ///
 37    /// Relative to the user's `ui_font_size` and [UiDensity] setting.
 38    XLarge,
 39    /// 2X Large spacing - @16px/rem: `12px`|`16px`|`20px`
 40    ///
 41    /// Relative to the user's `ui_font_size` and [UiDensity] setting.
 42    XXLarge,
 43}
 44
 45impl Spacing {
 46    /// Returns the spacing's scaling ratio in pixels.
 47    pub fn spacing_ratio(self, cx: &WindowContext) -> f32 {
 48        match ThemeSettings::get_global(cx).ui_density {
 49            UiDensity::Compact => match self {
 50                Spacing::None => 0.,
 51                Spacing::XXSmall => 1. / BASE_REM_SIZE_IN_PX,
 52                Spacing::XSmall => 1. / BASE_REM_SIZE_IN_PX,
 53                Spacing::Small => 2. / BASE_REM_SIZE_IN_PX,
 54                Spacing::Medium => 3. / BASE_REM_SIZE_IN_PX,
 55                Spacing::Large => 4. / BASE_REM_SIZE_IN_PX,
 56                Spacing::XLarge => 8. / BASE_REM_SIZE_IN_PX,
 57                Spacing::XXLarge => 12. / BASE_REM_SIZE_IN_PX,
 58            },
 59            UiDensity::Default => match self {
 60                Spacing::None => 0.,
 61                Spacing::XXSmall => 1. / BASE_REM_SIZE_IN_PX,
 62                Spacing::XSmall => 2. / BASE_REM_SIZE_IN_PX,
 63                Spacing::Small => 4. / BASE_REM_SIZE_IN_PX,
 64                Spacing::Medium => 6. / BASE_REM_SIZE_IN_PX,
 65                Spacing::Large => 8. / BASE_REM_SIZE_IN_PX,
 66                Spacing::XLarge => 12. / BASE_REM_SIZE_IN_PX,
 67                Spacing::XXLarge => 16. / BASE_REM_SIZE_IN_PX,
 68            },
 69            UiDensity::Comfortable => match self {
 70                Spacing::None => 0.,
 71                Spacing::XXSmall => 2. / BASE_REM_SIZE_IN_PX,
 72                Spacing::XSmall => 3. / BASE_REM_SIZE_IN_PX,
 73                Spacing::Small => 6. / BASE_REM_SIZE_IN_PX,
 74                Spacing::Medium => 8. / BASE_REM_SIZE_IN_PX,
 75                Spacing::Large => 10. / BASE_REM_SIZE_IN_PX,
 76                Spacing::XLarge => 16. / BASE_REM_SIZE_IN_PX,
 77                Spacing::XXLarge => 20. / BASE_REM_SIZE_IN_PX,
 78            },
 79        }
 80    }
 81
 82    /// Returns the spacing's value in rems.
 83    pub fn rems(self, cx: &WindowContext) -> Rems {
 84        rems(self.spacing_ratio(cx))
 85    }
 86
 87    /// Returns the spacing's value in pixels.
 88    pub fn px(self, cx: &WindowContext) -> Pixels {
 89        let ui_font_size_f32: f32 = ThemeSettings::get_global(cx).ui_font_size.into();
 90
 91        px(ui_font_size_f32 * self.spacing_ratio(cx))
 92    }
 93}
 94
 95fn user_spacing_style(cx: &WindowContext) -> UiDensity {
 96    ThemeSettings::get_global(cx).ui_density
 97}
 98
 99/// Returns a custom spacing value based on the current [`UiDensity`].
100///
101/// If you use this, talk to @iamnbutler and let me know what you're doing
102/// that needs custom spacing– I'd love to understand so we can extend the system further and remove the need for this.
103pub fn custom_spacing(cx: &WindowContext, size: f32) -> Rems {
104    rems_from_px(size * user_spacing_style(cx).spacing_ratio())
105}