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 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 div()
38 .id("windows-window-controls")
39 .font_family(Self::get_font())
40 .flex()
41 .flex_row()
42 .justify_center()
43 .content_stretch()
44 .max_h(self.button_height)
45 .min_h(self.button_height)
46 .child(WindowsCaptionButton::Minimize)
47 .map(|this| {
48 this.child(if window.is_maximized() {
49 WindowsCaptionButton::Restore
50 } else {
51 WindowsCaptionButton::Maximize
52 })
53 })
54 .child(WindowsCaptionButton::Close)
55 }
56}
57
58#[derive(IntoElement)]
59enum WindowsCaptionButton {
60 Minimize,
61 Restore,
62 Maximize,
63 Close,
64}
65
66impl WindowsCaptionButton {
67 #[inline]
68 fn id(&self) -> &'static str {
69 match self {
70 Self::Minimize => "minimize",
71 Self::Restore => "restore",
72 Self::Maximize => "maximize",
73 Self::Close => "close",
74 }
75 }
76
77 #[inline]
78 fn icon(&self) -> &'static str {
79 match self {
80 Self::Minimize => "\u{e921}",
81 Self::Restore => "\u{e923}",
82 Self::Maximize => "\u{e922}",
83 Self::Close => "\u{e8bb}",
84 }
85 }
86
87 #[inline]
88 fn control_area(&self) -> WindowControlArea {
89 match self {
90 Self::Close => WindowControlArea::Close,
91 Self::Maximize | Self::Restore => WindowControlArea::Max,
92 Self::Minimize => WindowControlArea::Min,
93 }
94 }
95}
96
97impl RenderOnce for WindowsCaptionButton {
98 fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
99 let (hover_bg, hover_fg, active_bg, active_fg) = match self {
100 Self::Close => {
101 let color: Hsla = Rgba {
102 r: 232.0 / 255.0,
103 g: 17.0 / 255.0,
104 b: 32.0 / 255.0,
105 a: 1.0,
106 }
107 .into();
108
109 (
110 color,
111 gpui::white(),
112 color.opacity(0.8),
113 gpui::white().opacity(0.8),
114 )
115 }
116 _ => (
117 cx.theme().colors().ghost_element_hover,
118 cx.theme().colors().text,
119 cx.theme().colors().ghost_element_active,
120 cx.theme().colors().text,
121 ),
122 };
123
124 h_flex()
125 .id(self.id())
126 .justify_center()
127 .content_center()
128 .occlude()
129 .w(px(36.))
130 .h_full()
131 .text_size(px(10.0))
132 .hover(|style| style.bg(hover_bg).text_color(hover_fg))
133 .active(|style| style.bg(active_bg).text_color(active_fg))
134 .window_control_area(self.control_area())
135 .child(self.icon())
136 }
137}