1use gpui::{Hsla, Rgba, WindowControlArea, prelude::*};
2
3use ui::prelude::*;
4
5#[derive(IntoElement)]
6pub struct WindowsWindowControls {
7 button_height: Pixels,
8}
9
10impl WindowsWindowControls {
11 pub const fn new(button_height: Pixels) -> Self {
12 Self { button_height }
13 }
14
15 #[cfg(not(target_os = "windows"))]
16 const 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, cx: &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 = cx.theme().colors().ghost_element_hover;
45 let button_active_color = cx.theme().colors().ghost_element_active;
46
47 div()
48 .id("windows-window-controls")
49 .font_family(Self::get_font())
50 .flex()
51 .flex_row()
52 .justify_center()
53 .content_stretch()
54 .max_h(self.button_height)
55 .min_h(self.button_height)
56 .child(WindowsCaptionButton::new(
57 "minimize",
58 WindowsCaptionButtonIcon::Minimize,
59 button_hover_color,
60 button_active_color,
61 ))
62 .child(WindowsCaptionButton::new(
63 "maximize-or-restore",
64 if window.is_maximized() {
65 WindowsCaptionButtonIcon::Restore
66 } else {
67 WindowsCaptionButtonIcon::Maximize
68 },
69 button_hover_color,
70 button_active_color,
71 ))
72 .child(WindowsCaptionButton::new(
73 "close",
74 WindowsCaptionButtonIcon::Close,
75 close_button_hover_color,
76 button_active_color,
77 ))
78 }
79}
80
81#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
82enum WindowsCaptionButtonIcon {
83 Minimize,
84 Restore,
85 Maximize,
86 Close,
87}
88
89#[derive(IntoElement)]
90struct WindowsCaptionButton {
91 id: ElementId,
92 icon: WindowsCaptionButtonIcon,
93 hover_background_color: Hsla,
94 active_background_color: Hsla,
95}
96
97impl WindowsCaptionButton {
98 pub fn new(
99 id: impl Into<ElementId>,
100 icon: WindowsCaptionButtonIcon,
101 hover_background_color: impl Into<Hsla>,
102 active_background_color: impl Into<Hsla>,
103 ) -> Self {
104 Self {
105 id: id.into(),
106 icon,
107 hover_background_color: hover_background_color.into(),
108 active_background_color: active_background_color.into(),
109 }
110 }
111}
112
113impl RenderOnce for WindowsCaptionButton {
114 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
115 h_flex()
116 .id(self.id)
117 .justify_center()
118 .content_center()
119 .occlude()
120 .w(px(36.))
121 .h_full()
122 .text_size(px(10.0))
123 .hover(|style| style.bg(self.hover_background_color))
124 .active(|style| style.bg(self.active_background_color))
125 .map(|this| match self.icon {
126 WindowsCaptionButtonIcon::Close => {
127 this.window_control_area(WindowControlArea::Close)
128 }
129 WindowsCaptionButtonIcon::Maximize | WindowsCaptionButtonIcon::Restore => {
130 this.window_control_area(WindowControlArea::Max)
131 }
132 WindowsCaptionButtonIcon::Minimize => {
133 this.window_control_area(WindowControlArea::Min)
134 }
135 })
136 .child(match self.icon {
137 WindowsCaptionButtonIcon::Minimize => "\u{e921}",
138 WindowsCaptionButtonIcon::Restore => "\u{e923}",
139 WindowsCaptionButtonIcon::Maximize => "\u{e922}",
140 WindowsCaptionButtonIcon::Close => "\u{e8bb}",
141 })
142 }
143}