1use crate::{
2 types::{Rect, Vector2},
3 ui::WindowContext,
4 Id, Ui,
5};
6
7#[derive(Debug, Clone)]
8pub struct Window {
9 id: Id,
10 position: Vector2,
11 size: Vector2,
12 close_button: bool,
13 enabled: bool,
14 movable: bool,
15 titlebar: bool,
16 label: Option<String>,
17}
18
19impl Window {
20 pub fn new(id: Id, position: Vector2, size: Vector2) -> Window {
21 Window {
22 id,
23 position,
24 size,
25 close_button: false,
26 enabled: true,
27 movable: true,
28 titlebar: true,
29 label: None,
30 }
31 }
32
33 pub fn label(self, label: &str) -> Window {
34 Window {
35 label: Some(label.to_string()),
36 ..self
37 }
38 }
39
40 pub fn movable(self, movable: bool) -> Window {
41 Window { movable, ..self }
42 }
43
44 pub fn close_button(self, close_button: bool) -> Window {
45 Window {
46 close_button,
47 ..self
48 }
49 }
50
51 pub fn titlebar(self, titlebar: bool) -> Window {
52 Window { titlebar, ..self }
53 }
54
55 pub fn enabled(self, enabled: bool) -> Window {
56 Window { enabled, ..self }
57 }
58
59 pub fn ui<F: FnOnce(&mut Ui)>(self, ui: &mut Ui, f: F) -> bool {
60 let token = self.begin(ui);
61 f(ui);
62 token.end(ui)
63 }
64
65 pub fn begin(self, ui: &mut Ui) -> WindowToken {
66 let title_height = if self.titlebar {
67 ui.style.title_height
68 } else {
69 0.
70 };
71
72 let context = ui.begin_window(
73 self.id,
74 None,
75 self.position,
76 self.size,
77 title_height,
78 self.movable,
79 );
80
81 if context.window.was_active == false {
84 ui.focus_window(self.id);
85 }
86
87 let mut context = ui.get_active_window_context();
88
89 self.draw_window_frame(&mut context);
90 if self.close_button && self.draw_close_button(&mut context) {
91 context.close();
92 }
93
94 let clip_rect = context.window.content_rect();
95 context.scroll_area();
96
97 context.window.draw_commands.clip(clip_rect);
98
99 WindowToken
100 }
101
102 fn draw_close_button(&self, context: &mut WindowContext) -> bool {
103 let button_rect = Rect::new(
104 context.window.position.x + context.window.size.x - 15.,
105 context.window.position.y,
106 20.,
107 20.,
108 );
109 context.window.draw_commands.draw_label(
110 "X",
111 Vector2::new(
112 context.window.position.x + context.window.size.x - 10.,
113 context.window.position.y + 3.,
114 ),
115 Some(context.global_style.title(context.focused)),
116 );
117 context.focused
118 && button_rect.contains(context.input.mouse_position)
119 && context.input.click_up
120 }
121
122 fn draw_window_frame(&self, context: &mut WindowContext) {
123 let focused = context.focused;
124 let style = context.global_style;
125 let position = context.window.position;
126 let size = context.window.size;
127
128 context.window.draw_commands.draw_rect(
129 Rect::new(position.x, position.y, size.x, size.y),
130 style.window_border(focused),
131 style.background(focused),
132 );
133
134 if self.titlebar {
135 if let Some(label) = &self.label {
136 context.window.draw_commands.draw_label(
137 &label,
138 Vector2::new(position.x + style.margin, position.y + style.margin),
139 context.global_style.title(focused),
140 );
141 }
142 context.window.draw_commands.draw_line(
143 Vector2::new(position.x, position.y + style.title_height),
144 Vector2::new(position.x + size.x, position.y + style.title_height),
145 style.window_border(focused),
146 );
147 }
148 }
149}
150
151#[must_use = "Must call `.end()` to finish Window"]
152pub struct WindowToken;
153
154impl WindowToken {
155 pub fn end(self, ui: &mut Ui) -> bool {
156 let context = ui.get_active_window_context();
157 context.window.draw_commands.clip(None);
158
159 let opened = context.window.want_close == false;
160
161 ui.end_window();
162
163 opened
164 }
165}
166
167impl Ui {
168 pub fn window<F: FnOnce(&mut Ui)>(
169 &mut self,
170 id: Id,
171 position: Vector2,
172 size: Vector2,
173 f: F,
174 ) -> bool {
175 Window::new(id, position, size).ui(self, f)
176 }
177}