elevation.rs

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