elevation.rs

  1use std::fmt::{self, Display, Formatter};
  2
  3use gpui::{App, BoxShadow, Hsla, hsla, point, px};
  4use smallvec::{SmallVec, smallvec};
  5use theme::{ActiveTheme, Appearance};
  6
  7/// Today, elevation is primarily used to add shadows to elements, and set the correct background for elements like buttons.
  8///
  9/// Elevation can be thought of as the physical closeness of an element to the
 10/// user. Elements with lower elevations are physically further away on the
 11/// z-axis and appear to be underneath elements with higher elevations.
 12///
 13/// In the future, a more complete approach to elevation may be added.
 14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 15pub enum ElevationIndex {
 16    /// On the layer of the app background. This is under panels, panes, and
 17    /// other surfaces.
 18    Background,
 19    /// The primary surface – Contains panels, panes, containers, etc.
 20    Surface,
 21    /// The same elevation as the primary surface, but used for the editable areas, like buffers
 22    EditorSurface,
 23    /// A surface that is elevated above the primary surface. but below washes, models, and dragged elements.
 24    ElevatedSurface,
 25    /// A surface above the [ElevationIndex::ElevatedSurface] that is used for dialogs, alerts, modals, etc.
 26    ModalSurface,
 27}
 28
 29impl Display for ElevationIndex {
 30    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
 31        match self {
 32            ElevationIndex::Background => write!(f, "Background"),
 33            ElevationIndex::Surface => write!(f, "Surface"),
 34            ElevationIndex::EditorSurface => write!(f, "Editor Surface"),
 35            ElevationIndex::ElevatedSurface => write!(f, "Elevated Surface"),
 36            ElevationIndex::ModalSurface => write!(f, "Modal Surface"),
 37        }
 38    }
 39}
 40
 41impl ElevationIndex {
 42    /// Returns an appropriate shadow for the given elevation index.
 43    pub fn shadow(self, cx: &App) -> SmallVec<[BoxShadow; 2]> {
 44        let is_light = cx.theme().appearance() == Appearance::Light;
 45
 46        match self {
 47            ElevationIndex::Surface => smallvec![],
 48            ElevationIndex::EditorSurface => smallvec![],
 49
 50            ElevationIndex::ElevatedSurface => smallvec![
 51                BoxShadow {
 52                    color: hsla(0., 0., 0., 0.12),
 53                    offset: point(px(0.), px(2.)),
 54                    blur_radius: px(3.),
 55                    spread_radius: px(0.),
 56                },
 57                BoxShadow {
 58                    color: hsla(0., 0., 0., if is_light { 0.03 } else { 0.06 }),
 59                    offset: point(px(1.), px(1.)),
 60                    blur_radius: px(0.),
 61                    spread_radius: px(0.),
 62                }
 63            ],
 64
 65            ElevationIndex::ModalSurface => smallvec![
 66                BoxShadow {
 67                    color: hsla(0., 0., 0., if is_light { 0.06 } else { 0.12 }),
 68                    offset: point(px(0.), px(2.)),
 69                    blur_radius: px(3.),
 70                    spread_radius: px(0.),
 71                },
 72                BoxShadow {
 73                    color: hsla(0., 0., 0., if is_light { 0.06 } else { 0.08 }),
 74                    offset: point(px(0.), px(3.)),
 75                    blur_radius: px(6.),
 76                    spread_radius: px(0.),
 77                },
 78                BoxShadow {
 79                    color: hsla(0., 0., 0., 0.04),
 80                    offset: point(px(0.), px(6.)),
 81                    blur_radius: px(12.),
 82                    spread_radius: px(0.),
 83                },
 84                BoxShadow {
 85                    color: hsla(0., 0., 0., if is_light { 0.04 } else { 0.12 }),
 86                    offset: point(px(1.), px(1.)),
 87                    blur_radius: px(0.),
 88                    spread_radius: px(0.),
 89                },
 90            ],
 91
 92            _ => smallvec![],
 93        }
 94    }
 95
 96    /// Returns the background color for the given elevation index.
 97    pub fn bg(&self, cx: &mut App) -> Hsla {
 98        match self {
 99            ElevationIndex::Background => cx.theme().colors().background,
100            ElevationIndex::Surface => cx.theme().colors().surface_background,
101            ElevationIndex::EditorSurface => cx.theme().colors().editor_background,
102            ElevationIndex::ElevatedSurface => cx.theme().colors().elevated_surface_background,
103            ElevationIndex::ModalSurface => cx.theme().colors().elevated_surface_background,
104        }
105    }
106
107    /// Returns a color that is appropriate a filled element on this elevation
108    pub fn on_elevation_bg(&self, cx: &App) -> Hsla {
109        match self {
110            ElevationIndex::Background => cx.theme().colors().surface_background,
111            ElevationIndex::Surface => cx.theme().colors().background,
112            ElevationIndex::EditorSurface => cx.theme().colors().surface_background,
113            ElevationIndex::ElevatedSurface => cx.theme().colors().background,
114            ElevationIndex::ModalSurface => cx.theme().colors().background,
115        }
116    }
117
118    /// Attempts to return a darker background color than the current elevation index's background.
119    ///
120    /// If the current background color is already dark, it will return a lighter color instead.
121    pub fn darker_bg(&self, cx: &App) -> Hsla {
122        match self {
123            ElevationIndex::Background => cx.theme().colors().surface_background,
124            ElevationIndex::Surface => cx.theme().colors().editor_background,
125            ElevationIndex::EditorSurface => cx.theme().colors().surface_background,
126            ElevationIndex::ElevatedSurface => cx.theme().colors().editor_background,
127            ElevationIndex::ModalSurface => cx.theme().colors().editor_background,
128        }
129    }
130}