platform_windows.rs

  1use gpui::{Rgba, WindowAppearance, prelude::*};
  2
  3use ui::prelude::*;
  4
  5#[derive(IntoElement)]
  6pub struct WindowsWindowControls {
  7    button_height: Pixels,
  8}
  9
 10impl WindowsWindowControls {
 11    pub fn new(button_height: Pixels) -> Self {
 12        Self { button_height }
 13    }
 14
 15    #[cfg(not(target_os = "windows"))]
 16    fn get_font() -> &'static str {
 17        "Segoe Fluent Icons"
 18    }
 19
 20    #[cfg(target_os = "windows")]
 21    fn get_font() -> &'static str {
 22        use windows::Wdk::System::SystemServices::RtlGetVersion;
 23
 24        let mut version = unsafe { std::mem::zeroed() };
 25        let status = unsafe { RtlGetVersion(&mut version) };
 26
 27        if status.is_ok() && version.dwBuildNumber >= 22000 {
 28            "Segoe Fluent Icons"
 29        } else {
 30            "Segoe MDL2 Assets"
 31        }
 32    }
 33}
 34
 35impl RenderOnce for WindowsWindowControls {
 36    fn render(self, window: &mut Window, _: &mut App) -> impl IntoElement {
 37        let close_button_hover_color = Rgba {
 38            r: 232.0 / 255.0,
 39            g: 17.0 / 255.0,
 40            b: 32.0 / 255.0,
 41            a: 1.0,
 42        };
 43
 44        let button_hover_color = match window.appearance() {
 45            WindowAppearance::Light | WindowAppearance::VibrantLight => Rgba {
 46                r: 0.1,
 47                g: 0.1,
 48                b: 0.1,
 49                a: 0.2,
 50            },
 51            WindowAppearance::Dark | WindowAppearance::VibrantDark => Rgba {
 52                r: 0.9,
 53                g: 0.9,
 54                b: 0.9,
 55                a: 0.1,
 56            },
 57        };
 58
 59        div()
 60            .id("windows-window-controls")
 61            .font_family(Self::get_font())
 62            .flex()
 63            .flex_row()
 64            .justify_center()
 65            .content_stretch()
 66            .max_h(self.button_height)
 67            .min_h(self.button_height)
 68            .child(WindowsCaptionButton::new(
 69                "minimize",
 70                WindowsCaptionButtonIcon::Minimize,
 71                button_hover_color,
 72            ))
 73            .child(WindowsCaptionButton::new(
 74                "maximize-or-restore",
 75                if window.is_maximized() {
 76                    WindowsCaptionButtonIcon::Restore
 77                } else {
 78                    WindowsCaptionButtonIcon::Maximize
 79                },
 80                button_hover_color,
 81            ))
 82            .child(WindowsCaptionButton::new(
 83                "close",
 84                WindowsCaptionButtonIcon::Close,
 85                close_button_hover_color,
 86            ))
 87    }
 88}
 89
 90#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
 91enum WindowsCaptionButtonIcon {
 92    Minimize,
 93    Restore,
 94    Maximize,
 95    Close,
 96}
 97
 98#[derive(IntoElement)]
 99struct WindowsCaptionButton {
100    id: ElementId,
101    icon: WindowsCaptionButtonIcon,
102    hover_background_color: Rgba,
103}
104
105impl WindowsCaptionButton {
106    pub fn new(
107        id: impl Into<ElementId>,
108        icon: WindowsCaptionButtonIcon,
109        hover_background_color: Rgba,
110    ) -> Self {
111        Self {
112            id: id.into(),
113            icon,
114            hover_background_color,
115        }
116    }
117}
118
119impl RenderOnce for WindowsCaptionButton {
120    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
121        // todo(windows) report this width to the Windows platform API
122        // NOTE: this is intentionally hard coded. An option to use the 'native' size
123        //       could be added when the width is reported to the Windows platform API
124        //       as this could change between future Windows versions.
125        let width = px(36.);
126
127        h_flex()
128            .id(self.id)
129            .justify_center()
130            .content_center()
131            .w(width)
132            .h_full()
133            .text_size(px(10.0))
134            .hover(|style| style.bg(self.hover_background_color))
135            .active(|style| {
136                let mut active_color = self.hover_background_color;
137                active_color.a *= 0.2;
138
139                style.bg(active_color)
140            })
141            .child(match self.icon {
142                WindowsCaptionButtonIcon::Minimize => "\u{e921}",
143                WindowsCaptionButtonIcon::Restore => "\u{e923}",
144                WindowsCaptionButtonIcon::Maximize => "\u{e922}",
145                WindowsCaptionButtonIcon::Close => "\u{e8bb}",
146            })
147    }
148}