1use crate::renderer::DrawPass;
2use crate::types::Color;
3
4pub const TITLEBAR_HEIGHT: f32 = 32.0;
5const BUTTON_WIDTH: f32 = 46.0;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum TitleBarButton {
9 Minimize,
10 Maximize,
11 Close,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum TitleBarHit {
16 None,
17 Drag,
18 Button(TitleBarButton),
19}
20
21pub struct TitleBar {
22 pub hovered: Option<TitleBarButton>,
23 resizable: bool,
24}
25
26impl TitleBar {
27 pub fn new(resizable: bool) -> Self {
28 Self { hovered: None, resizable }
29 }
30
31 fn button_rect(button: TitleBarButton, screen_w: f32) -> (f32, f32, f32, f32) {
32 let index_from_right = match button {
33 TitleBarButton::Close => 0.0,
34 TitleBarButton::Maximize => 1.0,
35 TitleBarButton::Minimize => 2.0,
36 };
37 let x = screen_w - BUTTON_WIDTH * (index_from_right + 1.0);
38 (x, 0.0, BUTTON_WIDTH, TITLEBAR_HEIGHT)
39 }
40
41 pub fn hit_test(&self, x: f32, y: f32, screen_w: f32) -> TitleBarHit {
42 if y < 0.0 || y > TITLEBAR_HEIGHT {
43 return TitleBarHit::None;
44 }
45 for &button in &[TitleBarButton::Close, TitleBarButton::Maximize, TitleBarButton::Minimize] {
46 if button == TitleBarButton::Maximize && !self.resizable {
47 continue;
48 }
49 let (bx, by, bw, bh) = Self::button_rect(button, screen_w);
50 if x >= bx && x < bx + bw && y >= by && y < by + bh {
51 return TitleBarHit::Button(button);
52 }
53 }
54 TitleBarHit::Drag
55 }
56
57 pub fn update_hover(&mut self, x: f32, y: f32, screen_w: f32) {
58 self.hovered = match self.hit_test(x, y, screen_w) {
59 TitleBarHit::Button(button) => Some(button),
60 _ => None,
61 };
62 }
63
64 pub fn render(&self, pass: &mut DrawPass, screen_w: u32, maximized: bool) {
65 let w = screen_w as f32;
66
67 for &button in &[TitleBarButton::Minimize, TitleBarButton::Maximize, TitleBarButton::Close] {
68 let (bx, by, bw, bh) = Self::button_rect(button, w);
69
70 if self.hovered == Some(button) {
71 let bg = if button == TitleBarButton::Close {
72 Color::from_hex(0xff0000)
73 } else {
74 Color::new(1.0, 1.0, 1.0, 0.15)
75 };
76 pass.draw_rect(bx, by, bw, bh, 0.0, bg);
77 }
78
79 let cx = bx + bw * 0.5;
80 let cy = by + bh * 0.5;
81 let icon_color = if button == TitleBarButton::Maximize && !self.resizable {
82 Color::new(1.0, 1.0, 1.0, 0.35)
83 } else {
84 Color::new(1.0, 1.0, 1.0, 1.0)
85 };
86
87 match button {
88 TitleBarButton::Minimize => {
89 pass.draw_line(cx - 5.0, cy, cx + 5.0, cy, 1.0, icon_color);
90 }
91 TitleBarButton::Maximize => {
92 if maximized {
93 pass.draw_rect(cx - 4.0, cy - 5.0, 8.0, 8.0, 1.0, icon_color);
94 pass.draw_rect(cx - 6.0, cy - 3.0, 8.0, 8.0, 1.0, icon_color);
95 } else {
96 pass.draw_rect(cx - 5.0, cy - 5.0, 10.0, 10.0, 1.0, icon_color);
97 }
98 }
99 TitleBarButton::Close => {
100 pass.draw_line(cx - 5.0, cy - 5.0, cx + 5.0, cy + 5.0, 1.0, icon_color);
101 pass.draw_line(cx - 5.0, cy + 5.0, cx + 5.0, cy - 5.0, 1.0, icon_color);
102 }
103 }
104 }
105 }
106}