cgl_rs/
window.rs

1//! The window manager module is responsible for creating and managing windows. It is also responsible for handling input events and passing them to the appropriate window.
2
3#![allow(non_camel_case_types)]
4use libc::{c_void, c_int, c_char, c_double};
5
6/// The internal window handle used by CGL
7#[repr(C)]
8pub(crate) struct CGL_window {
9    pub(crate) _private: c_void
10}
11
12/// The internal window handle used by GLFW
13#[repr(C)]
14pub struct GLFWwindow {
15    _private: c_void
16}
17
18type CGL_window_key_callback = extern "C" fn(window: *mut CGL_window, key: c_int, scancode: c_int, action: c_int, mods: c_int) -> c_void;
19type CGL_window_mouse_button_callback = extern "C" fn(window: *mut CGL_window, button: c_int, action: c_int, mods: c_int) -> c_void;
20type CGL_window_mouse_position_callback = extern "C" fn(window: *mut CGL_window, x: c_double, y: c_double) -> c_void;
21type CGL_window_mouse_scroll_callback = extern "C" fn(window: *mut CGL_window, x: c_double, y: c_double) -> c_void;
22type CGL_window_framebuffer_size_callback = extern "C" fn(window: *mut CGL_window, width: c_int, height: c_int) -> c_void;
23type CGL_window_close_callback = extern "C" fn(window: *mut CGL_window) -> c_void;
24type CGL_window_drag_n_drop_callback = extern "C" fn(window: *mut CGL_window, paths: *const *const c_char, count: c_int) -> c_void;
25
26
27
28
29extern {
30    fn CGL_window_create(width: c_int, height: c_int, title: *const c_char) -> *mut CGL_window;
31    fn CGL_window_create_undecorated(width: c_int, height: c_int, title: *const c_char) -> *mut CGL_window;
32    fn CGL_window_destroy(window: *mut CGL_window) -> c_void;
33    fn CGL_window_poll_events(window: *mut CGL_window) -> c_void;
34    fn CGL_window_swap_buffers(window: *mut CGL_window) -> c_void;
35    fn CGL_window_should_close(window: *mut CGL_window) -> c_int;
36    fn CGL_window_set_title(window: *mut CGL_window, title: *const c_char) -> c_void;
37    fn CGL_window_set_size(window: *mut CGL_window, width: c_int, height: c_int) -> c_void;
38    fn CGL_window_set_position(window: *mut CGL_window, x: c_int, y: c_int) -> c_void;
39    fn CGL_window_set_hidden(window: *mut CGL_window, hidden: c_int) -> c_void;
40    fn CGL_window_set_user_data(window: *mut CGL_window, user_data: *mut c_void) -> c_void;
41    fn CGL_window_get_user_data(window: *mut CGL_window) -> *mut c_void;
42    fn CGL_window_get_size(window: *mut CGL_window, width: *mut c_int, height: *mut c_int) -> c_void;
43    fn CGL_window_get_position(window: *mut CGL_window, x: *mut c_int, y: *mut c_int) -> c_void;
44    fn CGL_window_get_framebuffer_size(window: *mut CGL_window, width: *mut c_int, height: *mut c_int) -> c_void;
45    
46    fn CGL_window_set_key_callback(window: *mut CGL_window, callback: CGL_window_key_callback) -> c_void;
47    fn CGL_window_set_mouse_button_callback(window: *mut CGL_window, callback: CGL_window_mouse_button_callback) -> c_void;
48    fn CGL_window_set_mouse_position_callback(window: *mut CGL_window, callback: CGL_window_mouse_position_callback) -> c_void;
49    fn CGL_window_set_mouse_scroll_callback(window: *mut CGL_window, callback: CGL_window_mouse_scroll_callback) -> c_void;
50    fn CGL_window_set_framebuffer_size_callback(window: *mut CGL_window, callback: CGL_window_framebuffer_size_callback) -> c_void;
51    fn CGL_window_set_close_callback(window: *mut CGL_window, callback: CGL_window_close_callback) -> c_void;
52    fn CGL_window_set_drag_n_drop_callback(window: *mut CGL_window, callback: CGL_window_drag_n_drop_callback) -> c_void;
53
54    fn CGL_window_resecure_callbacks(window: *mut CGL_window) -> c_void;
55    fn CGL_window_make_context_current(window: *mut CGL_window) -> c_void;
56    fn CGL_window_get_glfw_handle(window: *mut CGL_window) -> *mut GLFWwindow;
57
58    fn CGL_window_get_key(window: *mut CGL_window, key: c_int) -> c_int;
59    fn CGL_window_is_key_pressed(window: *mut CGL_window, key: c_int) -> c_int;
60    fn CGL_window_get_mouse_button(window: *mut CGL_window, button: c_int) -> c_int;
61    fn CGL_window_get_mouse_position(window: *mut CGL_window, x: *mut c_double, y: *mut c_double) -> c_void;
62
63    fn CGL_utils_sleep(duration: usize) -> c_void; // temporary
64}
65
66
67/// Represents a keyboard key, with each variant corresponding to a specific key code.
68#[repr(C)] #[derive(Debug)]
69pub enum Key {
70    Unknown            = -1,
71    Space              = 32,
72    Apostrophe         = 39,
73    Comma              = 44,
74    Minus              = 45,
75    Period             = 46,
76    Slash              = 47,
77    K0                 = 48,
78    K1                 = 49,
79    K2                 = 50,
80    K3                 = 51,
81    K4                 = 52,
82    K5                 = 53,
83    K6                 = 54,
84    K7                 = 55,
85    K8                 = 56,
86    K9                 = 57,
87    Semicolon          = 59,
88    Equal              = 61,
89    A                  = 65,
90    B                  = 66,
91    C                  = 67,
92    D                  = 68,
93    E                  = 69,
94    F                  = 70,
95    G                  = 71,
96    H                  = 72,
97    I                  = 73,
98    J                  = 74,
99    K                  = 75,
100    L                  = 76,
101    M                  = 77,
102    N                  = 78,
103    O                  = 79,
104    P                  = 80,
105    Q                  = 81,
106    R                  = 82,
107    S                  = 83,
108    T                  = 84,
109    U                  = 85,
110    V                  = 86,
111    W                  = 87,
112    X                  = 88,
113    Y                  = 89,
114    Z                  = 90,
115    LeftBracket        = 91,
116    Backslash          = 92,
117    RightBracket       = 93,
118    GraveAccent        = 96,
119    Escape             = 256,
120    Enter              = 257,
121    Tab                = 258,
122    Backspace          = 259,
123    Insert             = 260,
124    Delete             = 261,
125    Right              = 262,
126    Left               = 263,
127    Down               = 264,
128    Up                 = 265,
129    PageUp             = 266,
130    PageDown           = 267,
131    Home               = 268,
132    End                = 269,
133    CapsLock           = 280,
134    ScrollLock         = 281,
135    NumLock            = 282,
136    PrintScreen        = 283,
137    Pause              = 284,
138    F1                 = 290,
139    F2                 = 291,
140    F3                 = 292,
141    F4                 = 293,
142    F5                 = 294,
143    F6                 = 295,
144    F7                 = 296,
145    F8                 = 297,
146    F9                 = 298,
147    F10                = 299,
148    F11                = 300,
149    F12                = 301,
150    F13                = 302,
151    F14                = 303,
152    F15                = 304,
153    F16                = 305,
154    F17                = 306,
155    F18                = 307,
156    F19                = 308,
157    F20                = 309,
158    F21                = 310,
159    F22                = 311,
160    F23                = 312,
161    F24                = 313,
162    F25                = 314,
163    KeyPad0            = 320,
164    KeyPad1            = 321,
165    KeyPad2            = 322,
166    KeyPad3            = 323,
167    KeyPad4            = 324,
168    KeyPad5            = 325,
169    KeyPad6            = 326,
170    KeyPad7            = 327,
171    KeyPad8            = 328,
172    KeyPad9            = 329,
173    KeyPadDecimal      = 330,
174    KeyPadDivide       = 331,
175    KeyPadMultiply     = 332,
176    KeyPadSubtract     = 333,
177    KeyPadAdd          = 334,
178    KeyPadEnter        = 335,
179    KeyPadEqual        = 336,
180    LeftShift          = 340,
181    LeftControl        = 341,
182    LeftAlt            = 342,
183    LeftSuper          = 343,
184    RightShift         = 344,
185    RightControl       = 345,
186    RightAlt           = 346,
187    RightSuper         = 347,
188    Menu               = 348
189}
190
191/// Represents a mouse button, with each variant corresponding to a specific button code.
192#[derive(Debug)]
193pub enum MouseButton {
194    Left       = 0,
195    Right      = 1,
196    Middle     = 2,
197    B4         = 3,
198    B5         = 4,
199    B6         = 5,
200    B7         = 6,
201    B8         = 7,
202    Last       = 8
203}
204
205/// Represents an action, with each variant corresponding to a specific action code.
206#[derive(Debug, PartialEq)]
207pub enum Action {
208    Release        = 0,
209    Press          = 1,
210    Repeat         = 2
211}
212
213/// Represents an event that can be received by a window, with each variant corresponding to a specific type of event.
214#[derive(Debug)]
215pub enum Event {
216    Key(Key, Action, i32, i32),
217    MouseButton(MouseButton, Action, i32),
218    MousePosition(f64, f64),
219    MouseScroll(f64, f64),
220    FramebufferSize(i32, i32),
221    WindowClose,
222    DragNDrop(Vec<String>)
223}
224
225/// Represents a function that handles a window event.
226/// Takes a reference to the window and the event, and returns a boolean indicating whether the event was handled successfully.
227/// If this function returns false, the event will be passed to the next handler in the chain, or if there are no more handlers, the event will be ignored.
228/// If this function returns true, the event will not be passed to any more handlers.
229pub type EventFunction = dyn Fn(&Window, &Event) -> bool;
230
231/// Represents a window, with a handle to the underlying CGL window and a flag indicating whether it has been destroyed.
232pub struct Window {
233    handle: *mut CGL_window,
234    has_been_destroyed: bool,
235    event_handlers: std::collections::HashMap<String, Box<EventFunction>>
236}
237
238const MAX_ACTIVE_WINDOWS: usize = 1024;
239static mut ACTIVE_WINDOWS: [*const Window; MAX_ACTIVE_WINDOWS] = [0 as *const Window; MAX_ACTIVE_WINDOWS];
240
241// this is just a temporary hack, will be replaced with a proper solution later
242extern "C" fn fn_returning_c_void() -> c_void {
243    unsafe { CGL_utils_sleep(1) }
244}
245
246fn cgl_window_i32_to_action(action: i32) -> Action {
247    match action {
248        0 => Action::Release,
249        1 => Action::Press,
250        2 => Action::Repeat,
251        _ => panic!("Invalid action code")
252    }
253}
254
255fn cgl_window_i32_to_key(key: i32) -> Key {
256    match key {
257        32 => Key::Space,
258        39 => Key::Apostrophe,
259        44 => Key::Comma,
260        45 => Key::Minus,
261        46 => Key::Period,
262        47 => Key::Slash,
263        48 => Key::K0,
264        49 => Key::K1,
265        50 => Key::K2,
266        51 => Key::K3,
267        52 => Key::K4,
268        53 => Key::K5,
269        54 => Key::K6,
270        55 => Key::K7,
271        56 => Key::K8,
272        57 => Key::K9,
273        59 => Key::Semicolon,
274        61 => Key::Equal,
275        65 => Key::A,
276        66 => Key::B,
277        67 => Key::C,
278        68 => Key::D,
279        69 => Key::E,
280        70 => Key::F,
281        71 => Key::G,
282        72 => Key::H,
283        73 => Key::I,
284        74 => Key::J,
285        75 => Key::K,
286        76 => Key::L,
287        77 => Key::M,
288        78 => Key::N,
289        79 => Key::O,
290        80 => Key::P,
291        81 => Key::Q,
292        82 => Key::R,
293        83 => Key::S,
294        84 => Key::T,
295        85 => Key::U,
296        86 => Key::V,
297        87 => Key::W,
298        88 => Key::X,
299        89 => Key::Y,
300        90 => Key::Z,
301        91 => Key::LeftBracket,
302        92 => Key::Backslash,
303        93 => Key::RightBracket,
304        96 => Key::GraveAccent,
305        256 => Key::Escape,
306        257 => Key::Enter,
307        258 => Key::Tab,
308        259 => Key::Backspace,
309        260 => Key::Insert,
310        261 => Key::Delete,
311        262 => Key::Right,
312        263 => Key::Left,
313        264 => Key::Down,
314        265 => Key::Up,
315        266 => Key::PageUp,
316        267 => Key::PageDown,
317        268 => Key::Home,
318        269 => Key::End,
319        280 => Key::CapsLock,
320        281 => Key::ScrollLock,
321        282 => Key::NumLock,
322        283 => Key::PrintScreen,
323        284 => Key::Pause,
324        290 => Key::F1,
325        291 => Key::F2,
326        292 => Key::F3,
327        293 => Key::F4,
328        294 => Key::F5,
329        295 => Key::F6,
330        296 => Key::F7,
331        297 => Key::F8,
332        298 => Key::F9,
333        299 => Key::F10,
334        300 => Key::F11,
335        301 => Key::F12,
336        302 => Key::F13,
337        303 => Key::F14,
338        304 => Key::F15,
339        305 => Key::F16,
340        306 => Key::F17,
341        307 => Key::F18,
342        308 => Key::F19,
343        309 => Key::F20,
344        310 => Key::F21,
345        311 => Key::F22,
346        312 => Key::F23,
347        313 => Key::F24,
348        314 => Key::F25,
349        320 => Key::KeyPad0,
350        321 => Key::KeyPad1,
351        322 => Key::KeyPad2,
352        323 => Key::KeyPad3,
353        324 => Key::KeyPad4,
354        325 => Key::KeyPad5,
355        326 => Key::KeyPad6,
356        327 => Key::KeyPad7,
357        328 => Key::KeyPad8,
358        329 => Key::KeyPad9,
359        330 => Key::KeyPadDecimal,
360        331 => Key::KeyPadDivide,
361        332 => Key::KeyPadMultiply,
362        333 => Key::KeyPadSubtract,
363        334 => Key::KeyPadAdd,
364        335 => Key::KeyPadEnter,
365        336 => Key::KeyPadEqual,
366        340 => Key::LeftShift,
367        341 => Key::LeftControl,
368        342 => Key::LeftAlt,
369        343 => Key::LeftSuper,
370        344 => Key::RightShift,
371        345 => Key::RightControl,
372        346 => Key::RightAlt,
373        347 => Key::RightSuper,
374        348 => Key::Menu,
375        _ => panic!("Invalid key code")
376    }
377}
378
379fn cgl_window_i32_to_mouse_button(button: i32) -> MouseButton {
380    match button {
381        0 => MouseButton::Left,
382        1 => MouseButton::Right,
383        2 => MouseButton::Middle,
384        3 => MouseButton::B4,
385        4 => MouseButton::B5,
386        5 => MouseButton::B6,
387        6 => MouseButton::B7,
388        7 => MouseButton::B8,
389        _ => panic!("Invalid mouse button code")
390    }
391}
392
393fn cgl_window_dispatch_event(window: *mut CGL_window, event: Event) {
394    unsafe {
395        let window_id = (window as usize) % MAX_ACTIVE_WINDOWS;
396        if ACTIVE_WINDOWS[window_id].is_null() {
397            return;
398        }
399        let window = &*ACTIVE_WINDOWS[window_id];
400        for (_, handler) in &window.event_handlers {
401            if handler(window, &event) {
402                break;
403            }
404        }
405    }    
406}
407
408extern "C" fn cgl_window_key_callback(window: *mut CGL_window, key: i32, scancode: i32, action: i32, mods: i32) -> c_void {
409    cgl_window_dispatch_event(window, Event::Key(cgl_window_i32_to_key(key), cgl_window_i32_to_action(action), scancode, mods));
410    fn_returning_c_void()
411}
412
413extern "C" fn cgl_window_mouse_button_callback(window: *mut CGL_window, button: i32, action: i32, mods: i32) -> c_void {
414    cgl_window_dispatch_event(window, Event::MouseButton(cgl_window_i32_to_mouse_button(button), cgl_window_i32_to_action(action), mods));
415    fn_returning_c_void()
416}
417
418extern "C" fn cgl_window_mouse_position_callback(window: *mut CGL_window, xpos: f64, ypos: f64) -> c_void {
419    cgl_window_dispatch_event(window, Event::MousePosition(xpos, ypos));
420    fn_returning_c_void()
421}
422
423extern "C" fn cgl_window_mouse_scroll_callback(window: *mut CGL_window, xoffset: f64, yoffset: f64) -> c_void {
424    cgl_window_dispatch_event(window, Event::MouseScroll(xoffset, yoffset));
425    fn_returning_c_void()
426}
427
428extern "C" fn cgl_window_framebuffer_size_callback(window: *mut CGL_window, width: i32, height: i32) -> c_void {
429    cgl_window_dispatch_event(window, Event::FramebufferSize(width, height));
430    fn_returning_c_void()
431}
432
433extern "C" fn cgl_window_close_callback(window: *mut CGL_window) -> c_void {
434    cgl_window_dispatch_event(window, Event::WindowClose);
435    fn_returning_c_void()
436}
437
438extern "C" fn cgl_window_drag_n_drop_callback(window: *mut CGL_window, paths: *const *const c_char, count: i32) -> c_void {
439    let mut paths_vec = Vec::new();
440    for i in 0..count {
441        unsafe {
442            let path = std::ffi::CStr::from_ptr(*paths.offset(i as isize)).to_str().unwrap();
443            paths_vec.push(path.to_string());
444        }
445    }
446    cgl_window_dispatch_event(window, Event::DragNDrop(paths_vec));
447    fn_returning_c_void()
448}
449
450impl Window {
451    /// Creates a new window with the given title, width, and height.
452    ///
453    /// # Arguments
454    ///
455    /// * `title` - The title of the window.
456    /// * `width` - The width of the window.
457    /// * `height` - The height of the window.
458    ///
459    /// # Returns
460    ///
461    /// Returns a `Result` containing the created `Window` if successful, or an error message if the window creation failed.
462    ///
463    /// # Panics
464    ///
465    /// Panics if the width or height is not positive.
466    ///
467    ///
468    /// # Example
469    ///
470    /// ```
471    /// cgl_rs::init();
472    /// let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
473    /// window.destroy(); // we must destroy the window before shutting down
474    /// cgl_rs::shutdown();
475    /// ```
476    pub fn new(title: &str, width: i32, height: i32) -> Result<Window, &'static str> {
477        assert!(width > 0 && height > 0, "Window dimensions must be positive");
478        let title = std::ffi::CString::new(title).unwrap();
479        let handle = unsafe {
480            let created_window = CGL_window_create(width, height, title.as_ptr());
481            created_window
482        };
483        if handle.is_null() {
484            Err("Failed to create window")
485        } else {
486            unsafe { CGL_window_make_context_current(handle); }
487            Ok(Window {
488                handle: handle,
489                has_been_destroyed: false,
490                event_handlers: std::collections::HashMap::new()
491            })
492        }
493    }
494
495    /// Creates a new undecorated window with the given title, width, and height.
496    ///
497    /// An undecorated window is a window without any borders or title bar.
498    ///
499    /// # Arguments
500    ///
501    /// * `title` - The title of the window.
502    /// * `width` - The width of the window.
503    /// * `height` - The height of the window.
504    ///
505    /// # Returns
506    ///
507    /// Returns a `Result` containing the created `Window` if successful, or an error message if the window creation failed.
508    ///
509    /// # Panics
510    ///
511    /// Panics if the width or height is not positive.
512    ///
513    ///
514    /// # Example
515    ///
516    /// ```
517    /// cgl_rs::init();
518    /// {
519    ///     let mut window = cgl_rs::Window::new_undecorated("My Window", 800, 600).unwrap();
520    ///     // window.destroy(); // optional
521    /// }
522    /// cgl_rs::shutdown();
523    /// ```
524    pub fn new_undecorated(title: &str, width: i32, height: i32) -> Result<Window, &'static str> {
525        assert!(width > 0 && height > 0, "Window dimensions must be positive");
526        let title = std::ffi::CString::new(title).unwrap();
527        let handle = unsafe {
528            let created_window = CGL_window_create_undecorated(width, height, title.as_ptr());
529            created_window
530        };
531        if handle.is_null() {
532            Err("Failed to create window")
533        } else {
534            unsafe { CGL_window_make_context_current(handle); }
535            Ok(Window {
536                handle: handle,
537                has_been_destroyed: false,
538                event_handlers: std::collections::HashMap::new()
539            })
540        }
541    }
542
543    /// Destroys the window, freeing any resources associated with it.
544    ///
545    /// NOTE: This is called automatically when the `Window` goes out of scope, so it is not necessary to call this manually.
546    ///       However, it is safe to call this multiple times, and the subsequent calls will have no effect.
547    ///       But one thing to be noted is that this function must be called before `cgl_rs::shutdown()` is called.
548    ///
549    /// # Example
550    ///
551    /// ```
552    /// cgl_rs::init();
553    /// {
554    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
555    ///     window.destroy(); // optional
556    /// }
557    /// cgl_rs::shutdown();
558    /// ```
559    pub fn destroy(&mut self) {
560        if !self.has_been_destroyed {
561            unsafe {
562                CGL_window_destroy(self.handle);
563                ACTIVE_WINDOWS[(self.handle as usize) % MAX_ACTIVE_WINDOWS] = 0 as *const Window;
564                self.has_been_destroyed = true;
565            }
566        }
567    }
568
569
570    /// Registers the window to receive events by setting the appropriate callbacks.
571    ///
572    /// This function should be called after creating the window and before entering the event loop.
573    ///
574    /// # Example
575    ///
576    /// ```
577    /// cgl_rs::init();
578    /// {
579    ///     // window inside scope so that it is dropped before shutdown is called
580    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
581    ///     window.register_for_events();
582    /// }
583    /// cgl_rs::shutdown();
584    /// ```
585    pub fn register_for_events(&self) {
586        unsafe {
587            let window_id = (self.handle as usize) % MAX_ACTIVE_WINDOWS;
588            ACTIVE_WINDOWS[window_id] = self as *const Window;
589            CGL_window_set_key_callback(self.handle, cgl_window_key_callback);
590            CGL_window_set_mouse_button_callback(self.handle, cgl_window_mouse_button_callback);
591            CGL_window_set_mouse_position_callback(self.handle, cgl_window_mouse_position_callback);
592            CGL_window_set_mouse_scroll_callback(self.handle, cgl_window_mouse_scroll_callback);
593            CGL_window_set_framebuffer_size_callback(self.handle, cgl_window_framebuffer_size_callback);
594            CGL_window_set_close_callback(self.handle, cgl_window_close_callback);
595            CGL_window_set_drag_n_drop_callback(self.handle, cgl_window_drag_n_drop_callback);   
596        }
597    }
598
599
600    /// Attaches an named event handler to the window.
601    ///
602    /// The `name` parameter is a string that identifies the event handler. This can be any string that is unique to the event handler.
603    ///
604    /// The `handler` parameter is a reference to a function that will be called when the event occurs. The function must have the following signature:
605    ///
606    /// ```no_run
607    /// fn my_event_handler(window: &cgl_rs::Window, event: &cgl_rs::Event) {
608    ///     println!("Event occurred!");
609    /// }
610    ///
611    /// ```
612    /// # Example
613    ///
614    /// ```no_run
615    /// cgl_rs::init();
616    /// {
617    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
618    ///
619    ///     // window.attach_event_handler("my_event", &my_event_handler);
620    /// }
621    /// cgl_rs::shutdown();
622    /// ```
623    pub fn attach_event_handler(&mut self, name: &str, handler: &'static EventFunction) {
624        self.event_handlers.insert(name.to_string(), Box::new(handler));
625    }
626
627
628    /// Detaches a named event handler from the window.
629    ///
630    /// The `name` parameter is a string that identifies the event handler. This should be the same string that was used to attach the event handler.
631    ///
632    /// # Example
633    ///
634    /// ```no_run
635    /// cgl_rs::init();
636    /// {
637    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
638    ///     
639    ///     window.detach_event_handler("my_event");
640    /// }
641    /// cgl_rs::shutdown();
642    /// ```
643    pub fn detach_event_handler(&mut self, name: &str) {
644        self.event_handlers.remove(name);
645    }
646
647    /// Polls for events on the window.
648    ///
649    /// This function should be called in a loop to continuously poll for events on the window.
650    ///
651    /// # Example
652    ///
653    /// ```
654    /// cgl_rs::init();
655    /// {
656    ///     // window inside scope so that it is dropped before shutdown is called
657    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
658    ///
659    ///     while true {
660    ///         window.poll_events();
661    ///         // Handle events here
662    ///         // ...
663    ///         break; // break out of the loop for testing purposes
664    ///     }
665    ///
666    /// }
667    /// cgl_rs::shutdown();
668    /// ```
669    pub fn poll_events(&self) {
670        unsafe {
671            CGL_window_poll_events(self.handle);
672        }
673    }
674
675    /// Swaps the front and back buffers of the window.
676    ///
677    /// This function should be called after rendering to the back buffer to display the rendered image on the screen.
678    ///
679    /// # Example
680    ///
681    /// ```
682    /// cgl_rs::init();
683    /// {
684    ///     // window inside scope so that it is dropped before shutdown is called
685    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
686    ///
687    ///     while true {
688    ///         window.swap_buffers();
689    ///         // Handle events here
690    ///         // ...
691    ///         break; // break out of the loop for testing purposes
692    ///     }
693    ///
694    /// }
695    /// cgl_rs::shutdown();
696    /// ```
697    pub fn swap_buffers(&self) {
698        unsafe {
699            CGL_window_swap_buffers(self.handle);
700        }
701    }
702
703    /// Returns whether or not the window should be closed.
704    ///
705    /// This function should be called in a loop to continuously check if the window should be closed.
706    ///
707    /// # Returns
708    ///
709    /// A boolean value indicating whether or not the window should be closed.
710    ///
711    /// # Example
712    ///
713    /// ```
714    /// cgl_rs::init();
715    /// {
716    ///     // window inside scope so that it is dropped before shutdown is called
717    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
718    ///
719    ///     while !window.should_close() {
720    ///         // ...
721    ///         break; // break out of the loop for testing purposes
722    ///     }
723    ///
724    /// }
725    /// cgl_rs::shutdown();
726    /// ```
727    pub fn should_close(&self) -> bool {
728        unsafe {
729            CGL_window_should_close(self.handle) != 0
730        } 
731    }
732
733    /// Sets the title of the window.
734    ///
735    /// # Arguments
736    ///
737    /// * `title` - A string slice containing the new title of the window.
738    ///
739    /// # Example
740    ///
741    /// ```
742    /// cgl_rs::init();
743    /// {
744    ///     // window inside scope so that it is dropped before shutdown is called
745    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
746    ///     window.set_title("New Title");
747    /// }
748    /// cgl_rs::shutdown();
749    /// ```
750    pub fn set_title(&self, title: &str) {
751        let title = std::ffi::CString::new(title).unwrap();
752        unsafe {
753            CGL_window_set_title(self.handle, title.as_ptr());
754        }
755    }
756    
757    /// Sets the size of the window.
758    ///
759    /// # Arguments
760    ///
761    /// * `width` - The new width of the window.
762    /// * `height` - The new height of the window.
763    ///
764    /// # Example
765    ///
766    /// ```
767    /// cgl_rs::init();
768    /// {
769    ///     // window inside scope so that it is dropped before shutdown is called
770    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
771    ///     window.set_size(1024, 768);
772    /// }
773    /// cgl_rs::shutdown();
774    /// ```
775    pub fn set_size(&self, width: i32, height: i32) {
776        unsafe {
777            CGL_window_set_size(self.handle, width, height);
778        }
779    }
780
781    /// Sets the position of the window.
782    ///
783    /// # Arguments
784    ///
785    /// * `x` - The new x position of the window.
786    /// * `y` - The new y position of the window.
787    ///
788    /// # Example
789    ///
790    /// ```
791    /// cgl_rs::init();
792    /// {
793    ///     // window inside scope so that it is dropped before shutdown is called
794    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
795    ///     window.set_position(100, 100);
796    /// }
797    /// cgl_rs::shutdown();
798    /// ```
799    pub fn set_position(&self, x: i32, y: i32) {
800        unsafe {
801            CGL_window_set_position(self.handle, x, y);
802        }
803    }
804
805    /// Sets the visibility of the window.
806    ///
807    /// # Arguments
808    ///
809    /// * `hidden` - A boolean indicating whether the window should be hidden or not.
810    ///
811    /// # Example
812    ///
813    /// ```
814    /// cgl_rs::init();
815    /// {
816    ///     // window inside scope so that it is dropped before shutdown is called
817    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
818    ///     window.set_hidden(true);
819    /// }
820    /// cgl_rs::shutdown();
821    /// ```
822    pub fn set_hidden(&mut self, hidden: bool) {
823        unsafe {
824            CGL_window_set_hidden(self.handle, hidden as i32);
825        }
826    }
827
828    /// Sets the user data associated with the window.
829    ///
830    /// # Arguments
831    ///
832    /// * `user_data` - A pointer to the user data to associate with the window.
833    ///
834    /// # Example
835    ///
836    /// ```
837    /// cgl_rs::init();
838    /// {
839    ///     // window inside scope so that it is dropped before shutdown is called
840    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
841    ///     let user_data = Box::into_raw(Box::new(42));
842    ///     window.set_user_data(user_data);
843    /// }
844    /// cgl_rs::shutdown();
845    /// ```
846    pub fn set_user_data<T>(&self, user_data: *mut T) {
847        unsafe {
848            CGL_window_set_user_data(self.handle, user_data as *mut c_void);
849        }
850    }
851
852    /// Gets the user data associated with the window.
853    ///
854    /// # Example
855    ///
856    /// ```
857    /// cgl_rs::init();
858    /// {
859    ///     // window inside scope so that it is dropped before shutdown is called
860    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
861    ///     let user_data = Box::into_raw(Box::new(42));
862    ///     window.set_user_data(user_data);
863    ///     let retrieved_user_data = window.get_user_data();
864    ///     assert_eq!(retrieved_user_data, user_data);
865    /// }
866    /// cgl_rs::shutdown();
867    /// ```
868    pub fn get_user_data<T>(&self) -> *mut T {
869        unsafe {
870            CGL_window_get_user_data(self.handle) as *mut T
871        }
872    }
873
874    /// Gets the size of the window.
875    ///
876    /// # Example
877    ///
878    /// ```
879    /// cgl_rs::init();
880    /// {
881    ///     // window inside scope so that it is dropped before shutdown is called
882    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
883    ///     let (width, height) = window.get_size();
884    ///     assert_eq!(width, 800);
885    ///     assert_eq!(height, 600);
886    /// }
887    /// cgl_rs::shutdown();
888    /// ```
889    pub fn get_size(&self) -> (i32, i32) {
890        unsafe {
891            let (mut width, mut height) = (0, 0);
892            CGL_window_get_size(self.handle, &mut width, &mut height);
893            (width, height)
894        }
895    }
896
897    // Gets the position of the window.
898    ///
899    /// # Example
900    ///
901    /// ```
902    /// cgl_rs::init();
903    /// {
904    ///     // window inside scope so that it is dropped before shutdown is called
905    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
906    ///     let (x, y) = window.get_position();
907    /// }
908    /// cgl_rs::shutdown();
909    /// ```
910    pub fn get_position(&self) -> (i32, i32) {
911        unsafe {
912            let (mut x, mut y) = (0, 0);
913            CGL_window_get_position(self.handle, &mut x, &mut y);
914            (x, y)
915        }
916    }
917
918    // Gets the size of the framebuffer of the window.
919    ///
920    /// # Example
921    ///
922    /// ```
923    /// cgl_rs::init();
924    /// {
925    ///     // window inside scope so that it is dropped before shutdown is called
926    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
927    ///     let (width, height) = window.get_framebuffer_size();
928    ///     assert_eq!(width, 800);
929    ///     assert_eq!(height, 600);
930    /// }
931    /// cgl_rs::shutdown();
932    /// ```
933    pub fn get_framebuffer_size(&self) -> (i32, i32) {
934        unsafe {
935            let (mut width, mut height) = (0, 0);
936            CGL_window_get_framebuffer_size(self.handle, &mut width, &mut height);
937            (width, height)
938        }
939    }
940
941    /// Rescues the callbacks of the window.
942    /// This is usefule whn usiong cgl::window along with any third party library
943    /// that internally uses glfw with cgl::window.
944    ///
945    /// # Example
946    ///
947    /// ```
948    /// cgl_rs::init();
949    /// {
950    ///     // window inside scope so that it is dropped before shutdown is called
951    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
952    ///     window.rescure_callbacks();
953    /// }
954    /// cgl_rs::shutdown();
955    /// ```
956    pub fn rescure_callbacks(&self) {
957        unsafe {
958            CGL_window_resecure_callbacks(self.handle);
959        }
960    }
961
962
963    /// Makes the OpenGL context of the window current.
964    ///
965    /// # Example
966    ///
967    /// ```
968    /// cgl_rs::init();
969    /// {
970    ///     // window inside scope so that it is dropped before shutdown is called
971    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
972    ///     window.make_context_current();
973    /// }
974    /// cgl_rs::shutdown();
975    /// ```
976    pub fn make_context_current(&self) {
977        unsafe {
978            CGL_window_make_context_current(self.handle);
979        }
980    }
981
982    // Gets the GLFW handle of the window.
983    ///
984    /// # Example
985    ///
986    /// ```
987    /// cgl_rs::init();
988    /// {
989    ///     // window inside scope so that it is dropped before shutdown is called
990    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
991    ///     let handle = window.get_glfw_handle();
992    /// }
993    /// cgl_rs::shutdown();
994    /// ```
995    pub fn get_glfw_handle(&self) -> *mut GLFWwindow {
996        unsafe {
997            CGL_window_get_glfw_handle(self.handle)
998        }
999    }
1000
1001    // Gets the state of a keyboard key of the window.
1002    ///
1003    /// # Arguments
1004    ///
1005    /// * `key` - A `Key` enum value representing the key to get the state of.
1006    ///
1007    /// # Returns
1008    ///
1009    /// An `Action` enum value representing the state of the key.
1010    ///
1011    /// # Example
1012    ///
1013    /// ```
1014    /// cgl_rs::init();
1015    /// {
1016    ///     // window inside scope so that it is dropped before shutdown is called
1017    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
1018    ///     let action = window.get_key(cgl_rs::Key::A);
1019    ///     match action {
1020    ///         cgl_rs::Action::Release => println!("Key A was released"),
1021    ///         cgl_rs::Action::Press => println!("Key A was pressed"),
1022    ///         cgl_rs::Action::Repeat => println!("Key A was repeated"),
1023    ///     }
1024    /// }
1025    /// cgl_rs::shutdown();
1026    /// ```
1027    pub fn get_key(&self, key: Key) -> Action {
1028        unsafe {
1029            cgl_window_i32_to_action(CGL_window_get_key(self.handle, key as i32))
1030        }
1031    }
1032
1033    /// Checks if a keyboard key of the window is pressed.
1034    /// 
1035    /// # Arguments
1036    /// 
1037    /// * `key` - A `Key` enum value representing the key to check.
1038    /// 
1039    /// # Returns
1040    /// 
1041    /// A `bool` value representing if the key is pressed.
1042    /// 
1043    /// # Example
1044    /// 
1045    /// ```
1046    /// cgl_rs::init();
1047    /// {
1048    ///     // window inside scope so that it is dropped before shutdown is called
1049    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
1050    ///     if window.is_key_pressed(cgl_rs::Key::A) {
1051    ///         println!("Key A is pressed");
1052    ///     }
1053    /// }
1054    /// cgl_rs::shutdown();
1055    /// ```
1056    pub fn is_key_pressed(&self, key: Key) -> bool {
1057        unsafe {
1058            CGL_window_is_key_pressed(self.handle, key as i32) == 1
1059        }
1060    }
1061
1062    /// Gets the state of a mouse button of the window.
1063    /// 
1064    /// # Arguments
1065    ///
1066    /// * `button` - A `MouseButton` enum value representing the mouse button to get the state of.
1067    /// 
1068    /// # Returns
1069    /// 
1070    /// An `Action` enum value representing the state of the mouse button.
1071    /// 
1072    /// # Example
1073    /// 
1074    /// ```
1075    /// cgl_rs::init();
1076    /// {
1077    ///     // window inside scope so that it is dropped before shutdown is called
1078    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
1079    ///     let action = window.get_mouse_button(cgl_rs::MouseButton::Left);
1080    ///     match action {
1081    ///        cgl_rs::Action::Release => println!("Left mouse button was released"),
1082    ///        cgl_rs::Action::Press => println!("Left mouse button was pressed"),
1083    ///        cgl_rs::Action::Repeat => println!("Left mouse button was repeated"),
1084    ///     }
1085    /// }
1086    /// cgl_rs::shutdown();
1087    /// ```
1088    pub fn get_mouse_button(&self, button: MouseButton) -> Action {
1089        unsafe {
1090            cgl_window_i32_to_action(CGL_window_get_mouse_button(self.handle, button as i32))               
1091        }
1092    }
1093
1094    /// Checks if a mouse button of the window is pressed.
1095    /// 
1096    /// # Arguments
1097    ///
1098    /// * `button` - A `MouseButton` enum value representing the mouse button to check.
1099    /// 
1100    /// # Returns
1101    /// 
1102    /// A `bool` value representing if the mouse button is pressed.
1103    /// 
1104    /// # Example
1105    /// 
1106    /// ```
1107    /// cgl_rs::init();
1108    /// {
1109    ///     // window inside scope so that it is dropped before shutdown is called
1110    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
1111    ///     if window.is_mouse_button_pressed(cgl_rs::MouseButton::Left) {
1112    ///         println!("Left mouse button is pressed");
1113    ///     }
1114    /// }
1115    /// cgl_rs::shutdown();
1116    /// ```
1117    pub fn is_mouse_button_pressed(&self, button: MouseButton) -> bool {
1118        match self.get_mouse_button(button) {
1119            Action::Press => true,
1120            _ => false
1121        }
1122    }
1123
1124    /// Gets the position of the mouse cursor relative to the top-left corner of the window.
1125    /// 
1126    /// # Returns
1127    /// 
1128    /// A tuple containing the x and y coordinates of the mouse cursor.
1129    /// 
1130    /// # Example
1131    /// 
1132    /// ```
1133    /// cgl_rs::init();
1134    /// {
1135    ///     // window inside scope so that it is dropped before shutdown is called
1136    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
1137    ///     let (x, y) = window.get_mouse_position();
1138    ///     println!("Mouse position: ({}, {})", x, y);
1139    /// }
1140    /// cgl_rs::shutdown();
1141    /// ```
1142    pub fn get_mouse_position(&self) -> (f64, f64) {
1143        unsafe {
1144            let (mut x, mut y) = (0.0, 0.0);
1145            CGL_window_get_mouse_position(self.handle, &mut x, &mut y);
1146            (x, y)
1147        }
1148    }
1149
1150    /// Gets the internal handle of the window.
1151    /// 
1152    /// # Returns
1153    /// 
1154    /// A pointer to the internal handle of the window.
1155    pub(crate) fn get_cgl_handle(&self) -> *mut CGL_window {
1156        self.handle
1157    }
1158
1159}
1160
1161impl Drop for Window {
1162    fn drop(&mut self) {
1163        self.destroy();
1164    }
1165}
1166
1167impl Clone for Window {
1168    /// Clones the current window instance.
1169    /// 
1170    /// NOTE: The new instance will have the same handle, `has_been_destroyed` flag and empty `event_handlers` map.
1171    ///       This means that the new instance will not be able to receive events nor will the internal window handle be
1172    ///       destroyed when the new instance is dropped. The internal window handle will be destroyed when the original
1173    ///       instance is dropped.
1174    /// 
1175    /// # Returns
1176    /// 
1177    /// A new `Window` instance with the same handle, `has_been_destroyed` flag and empty `event_handlers` map.
1178    /// 
1179    /// # Example
1180    /// 
1181    /// ```
1182    /// cgl_rs::init();
1183    /// {
1184    ///     // window inside scope so that it is dropped before shutdown is called
1185    ///     let mut window = cgl_rs::Window::new("My Window", 800, 600).unwrap();
1186    ///     let mut window_clone = window.clone();
1187    /// }
1188    /// cgl_rs::shutdown();
1189    fn clone(&self) -> Self {
1190        Window {
1191            handle: self.handle,
1192            has_been_destroyed: true,
1193            event_handlers: std::collections::HashMap::new()
1194        }
1195    }
1196}