Skip to main content

megaui/widgets/
window.rs

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        // TODO: this will make each new window focused(appeared on the top) always
82        // consider adding some configuration to be able to spawn background windows
83        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}