Skip to main content

ferroui_controls/
window_closing_event_args.rs

1use std::cell::Cell;
2use std::rc::Rc;
3
4/// Specifies the reason that a window was closed.
5#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
6#[repr(i32)]
7pub enum WindowCloseReason {
8    /// The cause of the closure was not provided by the underlying platform.
9    #[default]
10    Undefined = 0,
11
12    /// The window itself was requested to close.
13    WindowClosing = 1,
14
15    /// The window is closing due to a parent/owner window closing.
16    OwnerWindowClosing = 2,
17
18    /// The window is closing due to the application shutting down.
19    ApplicationShutdown = 3,
20
21    /// The window is closing due to the operating system shutting down.
22    OSShutdown = 4,
23}
24
25/// Provides data for the window closing event.
26///
27/// The args are a reference object: a copy shares the cancel flag with the
28/// args it was made from, so that a handler given a copy cancels the
29/// closing, and copies compare by identity.
30#[derive(Clone, Debug)]
31pub struct WindowClosingEventArgs {
32    cancel: Rc<Cell<bool>>,
33    close_reason: WindowCloseReason,
34    is_programmatic: bool,
35}
36
37impl PartialEq for WindowClosingEventArgs {
38    fn eq(&self, other: &Self) -> bool {
39        Rc::ptr_eq(&self.cancel, &other.cancel)
40    }
41}
42
43impl WindowClosingEventArgs {
44    /// Creates the event args. Only the windowing classes raise the event.
45    pub fn new(reason: WindowCloseReason, is_programmatic: bool) -> Self {
46        Self { cancel: Rc::new(Cell::new(false)), close_reason: reason, is_programmatic }
47    }
48
49    /// Whether the event should be canceled.
50    pub fn cancel(&self) -> bool {
51        self.cancel.get()
52    }
53
54    /// Sets whether the event should be canceled.
55    pub fn set_cancel(&self, value: bool) {
56        self.cancel.set(value);
57    }
58
59    /// Gets a value that indicates why the window is being closed.
60    pub fn close_reason(&self) -> WindowCloseReason {
61        self.close_reason
62    }
63
64    /// Gets a value indicating whether the window is being closed
65    /// programmatically.
66    pub fn is_programmatic(&self) -> bool {
67        self.is_programmatic
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn carries_the_reason_and_can_be_canceled() {
77        let e = WindowClosingEventArgs::new(WindowCloseReason::OwnerWindowClosing, true);
78        assert_eq!(e.close_reason(), WindowCloseReason::OwnerWindowClosing);
79        assert!(e.is_programmatic());
80        assert!(!e.cancel());
81        e.set_cancel(true);
82        assert!(e.cancel());
83    }
84
85    #[test]
86    fn a_copy_shares_the_cancel_flag_and_the_identity() {
87        let e = WindowClosingEventArgs::new(WindowCloseReason::WindowClosing, false);
88        let copy = e.clone();
89        copy.set_cancel(true);
90        assert!(e.cancel());
91        assert!(e == copy);
92        assert!(e != WindowClosingEventArgs::new(WindowCloseReason::WindowClosing, false));
93
94        let boxed: ferroui_base::BoxedValue = Rc::new(e.clone());
95        let unboxed = boxed.downcast_ref::<WindowClosingEventArgs>().expect("the args");
96        unboxed.set_cancel(false);
97        assert!(!e.cancel());
98    }
99
100    #[test]
101    fn close_reason_values_match_the_reference_values() {
102        assert_eq!(WindowCloseReason::Undefined as i32, 0);
103        assert_eq!(WindowCloseReason::WindowClosing as i32, 1);
104        assert_eq!(WindowCloseReason::OwnerWindowClosing as i32, 2);
105        assert_eq!(WindowCloseReason::ApplicationShutdown as i32, 3);
106        assert_eq!(WindowCloseReason::OSShutdown as i32, 4);
107    }
108}