1use std::collections::HashMap;
2
3use macroquad::prelude::*;
4
5pub use megaui;
6
7struct UiContext {
8 ui: megaui::Ui,
9 ui_draw_list: Vec<megaui::DrawList>,
10 font_texture: Texture2D,
11 megaui_textures: HashMap<u32, Texture2D>,
12 input_processed_this_frame: bool,
13}
14
15static mut UI_CONTEXT: Option<UiContext> = None;
16
17impl UiContext {
18 fn new(ctx: &mut miniquad::Context) -> UiContext {
19 let mut ui = megaui::Ui::new();
20
21 ui.set_clipboard_object(ClipboardObject);
22
23 let texture_data = &ui.font_atlas.texture;
24 let font_texture = Texture2D::from_rgba8(
25 ctx,
26 texture_data.width as u16,
27 texture_data.height as u16,
28 &texture_data.data,
29 );
30 font_texture.set_filter(ctx, FilterMode::Nearest);
31
32 UiContext {
33 ui,
34 ui_draw_list: vec![],
35 font_texture,
36 megaui_textures: HashMap::new(),
37 input_processed_this_frame: false,
38 }
39 }
40
41 fn get() -> &'static mut UiContext {
42 unsafe {
43 if UI_CONTEXT.is_none() {
44 let InternalGlContext {
45 quad_context: ctx, ..
46 } = get_internal_gl();
47
48 UI_CONTEXT = Some(UiContext::new(ctx));
49 }
50
51 UI_CONTEXT.as_mut().unwrap()
52 }
53 }
54}
55
56pub struct ClipboardObject;
57
58impl megaui::ClipboardObject for ClipboardObject {
59 fn get(&self) -> Option<String> {
60 let InternalGlContext {
61 quad_context: ctx, ..
62 } = unsafe { get_internal_gl() };
63
64 miniquad::clipboard::get(ctx)
65 }
66
67 fn set(&mut self, data: &str) {
68 let InternalGlContext {
69 quad_context: ctx, ..
70 } = unsafe { get_internal_gl() };
71
72 miniquad::clipboard::set(ctx, data)
73 }
74}
75
76pub struct WindowParams {
77 pub label: String,
78 pub movable: bool,
79 pub close_button: bool,
80 pub titlebar: bool,
81}
82
83impl Default for WindowParams {
84 fn default() -> WindowParams {
85 WindowParams {
86 label: "".to_string(),
87 movable: true,
88 close_button: false,
89 titlebar: true,
90 }
91 }
92}
93
94pub fn set_ui_style(style: megaui::Style) {
95 let ctx = UiContext::get();
96
97 ctx.ui.set_style(style);
98}
99
100pub fn set_megaui_texture(id: u32, texture: Texture2D) {
101 let ctx = UiContext::get();
102
103 ctx.megaui_textures.insert(id, texture);
104}
105
106pub fn draw_window<F: FnOnce(&mut megaui::Ui)>(
107 id: megaui::Id,
108 position: glam::Vec2,
109 size: glam::Vec2,
110 params: impl Into<Option<WindowParams>>,
111 f: F,
112) -> bool {
113 let ctx = UiContext::get();
114
115 process_input();
116
117 let ui = &mut ctx.ui;
118 let params = params.into();
119
120 megaui::widgets::Window::new(
121 id,
122 megaui::Vector2::new(position.x(), position.y()),
123 megaui::Vector2::new(size.x(), size.y()),
124 )
125 .label(params.as_ref().map_or("", |params| ¶ms.label))
126 .titlebar(params.as_ref().map_or(true, |params| params.titlebar))
127 .movable(params.as_ref().map_or(true, |params| params.movable))
128 .close_button(params.as_ref().map_or(false, |params| params.close_button))
129 .ui(ui, f)
130}
131
132pub fn mouse_over_ui() -> bool {
134 let mouse_position = mouse_position();
135
136 UiContext::get()
137 .ui
138 .is_mouse_over(megaui::Vector2::new(mouse_position.0, mouse_position.1))
139}
140
141pub fn mouse_captured() -> bool {
143 UiContext::get().ui.is_mouse_captured()
144}
145
146fn process_input() {
147 use megaui::InputHandler;
148
149 let mut ctx = UiContext::get();
150
151 if ctx.input_processed_this_frame {
152 return;
153 }
154 let mouse_position = mouse_position();
155
156 ctx.ui.mouse_move(mouse_position);
157
158 if is_mouse_button_pressed(MouseButton::Left) {
159 ctx.ui.mouse_down(mouse_position);
160 }
161 if is_mouse_button_released(MouseButton::Left) {
162 ctx.ui.mouse_up(mouse_position);
163 }
164
165 let shift = is_key_down(KeyCode::LeftShift) || is_key_down(KeyCode::RightShift);
166 let ctrl = is_key_down(KeyCode::LeftControl) || is_key_down(KeyCode::RightControl);
167
168 while let Some(c) = get_char_pressed() {
169 if ctrl == false {
170 ctx.ui.char_event(c, false, false);
171 }
172 }
173
174 if is_key_down(KeyCode::Up) {
175 ctx.ui.key_down(megaui::KeyCode::Up, shift, ctrl);
176 }
177 if is_key_down(KeyCode::Down) {
178 ctx.ui.key_down(megaui::KeyCode::Down, shift, ctrl);
179 }
180 if is_key_down(KeyCode::Right) {
181 ctx.ui.key_down(megaui::KeyCode::Right, shift, ctrl);
182 }
183 if is_key_down(KeyCode::Left) {
184 ctx.ui.key_down(megaui::KeyCode::Left, shift, ctrl);
185 }
186 if is_key_down(KeyCode::Home) {
187 ctx.ui.key_down(megaui::KeyCode::Home, shift, ctrl);
188 }
189 if is_key_down(KeyCode::End) {
190 ctx.ui.key_down(megaui::KeyCode::End, shift, ctrl);
191 }
192 if is_key_down(KeyCode::Delete) {
193 ctx.ui.key_down(megaui::KeyCode::Delete, shift, ctrl);
194 }
195 if is_key_down(KeyCode::Backspace) {
196 ctx.ui.key_down(megaui::KeyCode::Backspace, shift, ctrl);
197 }
198 if is_key_down(KeyCode::Enter) {
199 ctx.ui.key_down(megaui::KeyCode::Enter, shift, ctrl);
200 }
201 if is_key_down(KeyCode::Tab) {
202 ctx.ui.key_down(megaui::KeyCode::Tab, shift, ctrl);
203 }
204 if is_key_down(KeyCode::Z) {
205 ctx.ui.key_down(megaui::KeyCode::Z, shift, ctrl);
206 }
207 if is_key_down(KeyCode::Y) {
208 ctx.ui.key_down(megaui::KeyCode::Y, shift, ctrl);
209 }
210 if is_key_down(KeyCode::C) {
211 ctx.ui.key_down(megaui::KeyCode::C, shift, ctrl);
212 }
213 if is_key_down(KeyCode::X) {
214 ctx.ui.key_down(megaui::KeyCode::X, shift, ctrl);
215 }
216 if is_key_down(KeyCode::V) {
217 ctx.ui.key_down(megaui::KeyCode::V, shift, ctrl);
218 }
219 if is_key_down(KeyCode::A) {
220 ctx.ui.key_down(megaui::KeyCode::A, shift, ctrl);
221 }
222 if is_key_down(KeyCode::Escape) {
223 ctx.ui.key_down(megaui::KeyCode::Escape, shift, ctrl);
224 }
225 if is_key_down(KeyCode::Enter) {
226 ctx.ui.key_down(megaui::KeyCode::Enter, shift, ctrl);
227 }
228 if is_key_down(KeyCode::LeftControl) || is_key_down(KeyCode::RightControl) {
229 ctx.ui.key_down(megaui::KeyCode::Control, shift, ctrl);
230 }
231 let (wheel_x, wheel_y) = mouse_wheel();
232 ctx.ui.mouse_wheel(wheel_x, -wheel_y);
233
234 ctx.input_processed_this_frame = true;
235}
236
237pub fn draw_megaui() {
240 let mut ctx = UiContext::get();
241
242 ctx.input_processed_this_frame = false;
243
244 let InternalGlContext { quad_gl, .. } = unsafe { get_internal_gl() };
245
246 ctx.ui_draw_list.clear();
247
248 ctx.ui.render(&mut ctx.ui_draw_list);
249 let mut ui_draw_list = vec![];
250
251 std::mem::swap(&mut ui_draw_list, &mut ctx.ui_draw_list);
252
253 quad_gl.texture(Some(ctx.font_texture));
254
255 for draw_command in &ui_draw_list {
256 if let Some(texture) = draw_command.texture {
257 quad_gl.texture(Some(ctx.megaui_textures[&texture]));
258 } else {
259 quad_gl.texture(Some(ctx.font_texture));
260 }
261 quad_gl.scissor(
262 draw_command
263 .clipping_zone
264 .map(|rect| (rect.x as i32, rect.y as i32, rect.w as i32, rect.h as i32)),
265 );
266 quad_gl.draw_mode(DrawMode::Triangles);
267 quad_gl.geometry(&draw_command.vertices, &draw_command.indices);
268 }
269 quad_gl.texture(None);
270
271 std::mem::swap(&mut ui_draw_list, &mut ctx.ui_draw_list);
272
273 ctx.ui.new_frame(get_frame_time());
274}