window_controls.rs

  1use gpui::{Action, Hsla, svg};
  2use ui::prelude::*;
  3
  4#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
  5pub enum WindowControlType {
  6    Minimize,
  7    Restore,
  8    Maximize,
  9    Close,
 10}
 11
 12impl WindowControlType {
 13    /// Returns the icon name for the window control type.
 14    ///
 15    /// Will take a [PlatformStyle] in the future to return a different
 16    /// icon name based on the platform.
 17    pub fn icon(&self) -> IconName {
 18        match self {
 19            WindowControlType::Minimize => IconName::GenericMinimize,
 20            WindowControlType::Restore => IconName::GenericRestore,
 21            WindowControlType::Maximize => IconName::GenericMaximize,
 22            WindowControlType::Close => IconName::GenericClose,
 23        }
 24    }
 25}
 26
 27#[allow(unused)]
 28pub struct WindowControlStyle {
 29    background: Hsla,
 30    background_hover: Hsla,
 31    icon: Hsla,
 32    icon_hover: Hsla,
 33}
 34
 35impl WindowControlStyle {
 36    pub fn default(cx: &mut App) -> Self {
 37        let colors = cx.theme().colors();
 38
 39        Self {
 40            background: colors.ghost_element_background,
 41            background_hover: colors.ghost_element_hover,
 42            icon: colors.icon,
 43            icon_hover: colors.icon_muted,
 44        }
 45    }
 46
 47    #[allow(unused)]
 48    /// Sets the background color of the control.
 49    pub fn background(mut self, color: impl Into<Hsla>) -> Self {
 50        self.background = color.into();
 51        self
 52    }
 53
 54    #[allow(unused)]
 55    /// Sets the background color of the control when hovered.
 56    pub fn background_hover(mut self, color: impl Into<Hsla>) -> Self {
 57        self.background_hover = color.into();
 58        self
 59    }
 60
 61    #[allow(unused)]
 62    /// Sets the color of the icon.
 63    pub fn icon(mut self, color: impl Into<Hsla>) -> Self {
 64        self.icon = color.into();
 65        self
 66    }
 67
 68    #[allow(unused)]
 69    /// Sets the color of the icon when hovered.
 70    pub fn icon_hover(mut self, color: impl Into<Hsla>) -> Self {
 71        self.icon_hover = color.into();
 72        self
 73    }
 74}
 75
 76#[derive(IntoElement)]
 77pub struct WindowControl {
 78    id: ElementId,
 79    icon: WindowControlType,
 80    style: WindowControlStyle,
 81    close_action: Option<Box<dyn Action>>,
 82}
 83
 84impl WindowControl {
 85    pub fn new(id: impl Into<ElementId>, icon: WindowControlType, cx: &mut App) -> Self {
 86        let style = WindowControlStyle::default(cx);
 87
 88        Self {
 89            id: id.into(),
 90            icon,
 91            style,
 92            close_action: None,
 93        }
 94    }
 95
 96    pub fn new_close(
 97        id: impl Into<ElementId>,
 98        icon: WindowControlType,
 99        close_action: Box<dyn Action>,
100        cx: &mut App,
101    ) -> Self {
102        let style = WindowControlStyle::default(cx);
103
104        Self {
105            id: id.into(),
106            icon,
107            style,
108            close_action: Some(close_action.boxed_clone()),
109        }
110    }
111
112    #[allow(unused)]
113    pub fn custom_style(
114        id: impl Into<ElementId>,
115        icon: WindowControlType,
116        style: WindowControlStyle,
117    ) -> Self {
118        Self {
119            id: id.into(),
120            icon,
121            style,
122            close_action: None,
123        }
124    }
125}
126
127impl RenderOnce for WindowControl {
128    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
129        let icon = svg()
130            .size_4()
131            .flex_none()
132            .path(self.icon.icon().path())
133            .text_color(self.style.icon)
134            .group_hover("", |this| this.text_color(self.style.icon_hover));
135
136        h_flex()
137            .id(self.id)
138            .group("")
139            .cursor_pointer()
140            .justify_center()
141            .content_center()
142            .rounded_2xl()
143            .w_5()
144            .h_5()
145            .hover(|this| this.bg(self.style.background_hover))
146            .active(|this| this.bg(self.style.background_hover))
147            .child(icon)
148            .on_mouse_move(|_, _, cx| cx.stop_propagation())
149            .on_click(move |_, window, cx| {
150                cx.stop_propagation();
151                match self.icon {
152                    WindowControlType::Minimize => window.minimize_window(),
153                    WindowControlType::Restore => window.zoom_window(),
154                    WindowControlType::Maximize => window.zoom_window(),
155                    WindowControlType::Close => window.dispatch_action(
156                        self.close_action
157                            .as_ref()
158                            .expect("Use WindowControl::new_close() for close control.")
159                            .boxed_clone(),
160                        cx,
161                    ),
162                }
163            })
164    }
165}