1use super::*;
54use std::cell::{Ref, RefMut};
55
56#[derive(Clone, Copy, Debug)]
57pub enum WindowState {
59 Open,
61 Closed,
63}
64
65#[derive(Clone, Copy, Debug)]
66pub(crate) enum Type {
67 Dialog,
68 Window,
69 Popup,
70}
71
72pub(crate) struct Window {
73 pub(crate) ty: Type,
74 pub(crate) win_state: WindowState,
75 pub(crate) main: Container,
76 pub(crate) title_state: Internal,
78 pub(crate) close_state: Internal,
80 pub(crate) resize_state: Internal,
82}
83
84impl Window {
85 pub fn dialog(name: &str, atlas: AtlasHandle, style: Rc<Style>, input: Rc<RefCell<Input>>, initial_rect: Recti) -> Self {
87 let mut main = Container::new(name, atlas, style, input);
88 main.rect = initial_rect;
89
90 Self {
91 ty: Type::Dialog,
92 win_state: WindowState::Closed,
93 main,
94 title_state: Internal::new("!title"),
95 close_state: Internal::new("!close"),
96 resize_state: Internal::new("!resize"),
97 }
98 }
99
100 pub fn window(name: &str, atlas: AtlasHandle, style: Rc<Style>, input: Rc<RefCell<Input>>, initial_rect: Recti) -> Self {
102 let mut main = Container::new(name, atlas, style, input);
103 main.rect = initial_rect;
104
105 Self {
106 ty: Type::Window,
107 win_state: WindowState::Open,
108 main,
109 title_state: Internal::new("!title"),
110 close_state: Internal::new("!close"),
111 resize_state: Internal::new("!resize"),
112 }
113 }
114
115 pub fn popup(name: &str, atlas: AtlasHandle, style: Rc<Style>, input: Rc<RefCell<Input>>, initial_rect: Recti) -> Self {
117 let mut main = Container::new(name, atlas, style, input);
118 main.rect = initial_rect;
119
120 Self {
121 ty: Type::Popup,
122 win_state: WindowState::Closed,
123 main,
124 title_state: Internal::new("!title"),
125 close_state: Internal::new("!close"),
126 resize_state: Internal::new("!resize"),
127 }
128 }
129
130 pub fn is_popup(&self) -> bool {
132 match self.ty {
133 Type::Popup => true,
134 _ => false,
135 }
136 }
137
138 #[inline(never)]
139 fn begin_window(&mut self, opt: ContainerOption, bopt: WidgetBehaviourOption) {
140 let is_popup = self.is_popup();
141 let Window {
142 win_state,
143 main: container,
144 title_state,
145 close_state,
146 resize_state,
147 ..
148 } = self;
149 let mut body = container.rect;
150 let r = body;
151 if !opt.has_no_frame() {
152 container.draw_frame(r, ControlColor::WindowBG);
153 }
154 if !opt.has_no_title() {
155 let mut tr: Recti = r;
156 let (font, padding, title_height, title_text_color) = {
159 let style = container.style.as_ref();
160 (
161 style.font,
162 style.padding.max(0),
163 style.title_height,
164 style.colors[ControlColor::TitleText as usize],
165 )
166 };
167 let font_height = container.atlas.get_font_height(font) as i32;
168 let min_title_h = font_height + (padding / 2).max(1) * 2;
169 tr.height = title_height.max(min_title_h);
170 container.draw_frame(tr, ControlColor::TitleBG);
171
172 if !opt.has_no_title() {
174 let title_id = widget_id_of(title_state);
175 let control_state = (title_state.opt, title_state.bopt);
176 let control = container.update_control(title_id, tr, &control_state);
177 {
178 let mut ctx = container.widget_ctx(title_id, tr, None);
179 let _ = title_state.handle(&mut ctx, &control);
180 }
181 let name = container.name.clone(); container.draw_control_text(&name, tr, ControlColor::TitleText, WidgetOption::NONE);
183 if control.active {
184 container.rect.x += container.input.borrow().mouse_delta.x;
185 container.rect.y += container.input.borrow().mouse_delta.y;
186 }
187 body.y += tr.height;
188 body.height -= tr.height;
189 }
190 if !opt.has_no_close() {
191 let close_id = widget_id_of(close_state);
192 let r: Recti = rect(tr.x + tr.width - tr.height, tr.y, tr.height, tr.height);
193 tr.width -= r.width;
194 let color = title_text_color;
195 container.draw_icon(CLOSE_ICON, r, color);
196 let control_state = (close_state.opt, close_state.bopt);
197 let control = container.update_control(close_id, r, &control_state);
198 {
199 let mut ctx = container.widget_ctx(close_id, r, None);
200 let _ = close_state.handle(&mut ctx, &control);
201 }
202 if control.clicked {
203 *win_state = WindowState::Closed;
204 }
205 }
206 }
207 container.push_container_body(body, opt, bopt);
208 if !opt.is_auto_sizing() {
209 let sz = container.style.as_ref().title_height;
210 let resize_id = widget_id_of(resize_state);
211 let r_0 = rect(r.x + r.width - sz, r.y + r.height - sz, sz, sz);
212 let control_state = (resize_state.opt, resize_state.bopt);
213 let control = container.update_control(resize_id, r_0, &control_state);
214 {
215 let mut ctx = container.widget_ctx(resize_id, r_0, None);
216 let _ = resize_state.handle(&mut ctx, &control);
217 }
218 if control.active {
219 container.rect.width = if 96 > container.rect.width + container.input.borrow().mouse_delta.x {
220 96
221 } else {
222 container.rect.width + container.input.borrow().mouse_delta.x
223 };
224 container.rect.height = if 64 > container.rect.height + container.input.borrow().mouse_delta.y {
225 64
226 } else {
227 container.rect.height + container.input.borrow().mouse_delta.y
228 };
229 }
230 }
231 if opt.is_auto_sizing() && (container.content_size.x > 0 || container.content_size.y > 0) {
232 let r_1 = container.layout.current_body();
233 container.rect.width = container.content_size.x + (container.rect.width - r_1.width);
234 container.rect.height = container.content_size.y + (container.rect.height - r_1.height);
235 }
236
237 if is_popup && container.popup_just_opened {
238 container.popup_just_opened = false;
240 } else if is_popup && !container.input.borrow().mouse_pressed.is_none() && !container.in_hover_root {
241 *win_state = WindowState::Closed;
242 }
243 let body = container.body;
244 container.push_clip_rect(body);
245 }
246
247 fn end_window(&mut self) {
248 let container = &mut self.main;
249 container.pop_clip_rect();
250 }
251}
252
253#[derive(Clone)]
254pub struct WindowHandle(Rc<RefCell<Window>>);
256
257impl WindowHandle {
258 pub(crate) fn window(name: &str, atlas: AtlasHandle, style: Rc<Style>, input: Rc<RefCell<Input>>, initial_rect: Recti) -> Self {
259 Self(Rc::new(RefCell::new(Window::window(name, atlas, style, input, initial_rect))))
260 }
261
262 pub(crate) fn dialog(name: &str, atlas: AtlasHandle, style: Rc<Style>, input: Rc<RefCell<Input>>, initial_rect: Recti) -> Self {
263 Self(Rc::new(RefCell::new(Window::dialog(name, atlas, style, input, initial_rect))))
264 }
265
266 pub(crate) fn popup(name: &str, atlas: AtlasHandle, style: Rc<Style>, input: Rc<RefCell<Input>>) -> Self {
267 Self(Rc::new(RefCell::new(Window::popup(name, atlas, style, input, Recti::new(0, 0, 0, 0)))))
268 }
269
270 pub fn is_open(&self) -> bool {
272 match self.0.borrow().win_state {
273 WindowState::Open => true,
274 _ => false,
275 }
276 }
277
278 pub(crate) fn inner_mut<'a>(&'a mut self) -> RefMut<'a, Window> {
279 self.0.borrow_mut()
280 }
281
282 pub(crate) fn inner<'a>(&'a self) -> Ref<'a, Window> {
283 self.0.borrow()
284 }
285
286 pub(crate) fn prepare(&mut self) {
287 self.inner_mut().main.prepare()
288 }
289
290 pub(crate) fn render<R: Renderer>(&mut self, canvas: &mut Canvas<R>) {
291 self.0.borrow_mut().main.render(canvas)
292 }
293
294 pub(crate) fn finish(&mut self) {
295 self.inner_mut().main.finish()
296 }
297
298 pub(crate) fn zindex(&self) -> i32 {
299 self.0.borrow().main.zindex
300 }
301
302 pub(crate) fn begin_window(&mut self, opt: ContainerOption, bopt: WidgetBehaviourOption) {
303 self.0.borrow_mut().begin_window(opt, bopt)
304 }
305
306 pub(crate) fn end_window(&mut self) {
307 self.inner_mut().end_window()
308 }
309
310 pub fn set_size(&mut self, size: &Dimensioni) {
312 self.inner_mut().main.rect.width = size.width;
313 self.inner_mut().main.rect.height = size.height;
314 }
315}