rat_salsa/
control.rs

1use rat_event::{ConsumedEvent, Outcome};
2use std::cmp::Ordering;
3use std::mem;
4
5/// Result enum for event handling.
6///
7/// The result of an event is processed immediately after the
8/// function returns, before polling new events. This way an action
9/// can trigger another action which triggers the repaint without
10/// other events intervening.
11///
12/// If you ever need to return more than one result from event-handling,
13/// you can hand it to AppContext/RenderContext::queue(). Events
14/// in the queue are processed in order, and the return value of
15/// the event-handler comes last. If an error is returned, everything
16/// send to the queue will be executed nonetheless.
17///
18/// __See__
19///
20/// - [flow!](rat_event::flow)
21/// - [try_flow!](rat_event::try_flow)
22/// - [ConsumedEvent]
23#[derive(Debug, Clone, Copy)]
24#[must_use]
25#[non_exhaustive]
26pub enum Control<Event> {
27    /// Continue with event-handling.
28    /// In the event-loop this waits for the next event.
29    Continue,
30    /// Break event-handling without repaint.
31    /// In the event-loop this waits for the next event.
32    Unchanged,
33    /// Break event-handling and repaints/renders the application.
34    /// In the event-loop this calls `render`.
35    Changed,
36    /// Eventhandling can cause secondary application specific events.
37    /// One common way is to return this `Control::Message(my_event)`
38    /// to reenter the event-loop with your own secondary event.
39    ///
40    /// This acts quite like a message-queue to communicate between
41    /// disconnected parts of your application. And indeed there is
42    /// a hidden message-queue as part of the event-loop.
43    ///
44    /// The other way is to call [SalsaAppContext::queue] to initiate such
45    /// events.
46    Event(Event),
47    /// A dialog close event. In the main loop it will be handled
48    /// just like [Control::Event]. But the DialogStack can react
49    /// separately and close the window.
50    #[cfg(feature = "dialog")]
51    Close(Event),
52    /// Quit the application.
53    Quit,
54}
55
56impl<Event> Eq for Control<Event> {}
57
58impl<Event> PartialEq for Control<Event> {
59    fn eq(&self, other: &Self) -> bool {
60        mem::discriminant(self) == mem::discriminant(other)
61    }
62}
63
64impl<Event> Ord for Control<Event> {
65    fn cmp(&self, other: &Self) -> Ordering {
66        match self {
67            Control::Continue => match other {
68                Control::Continue => Ordering::Equal,
69                Control::Unchanged => Ordering::Less,
70                Control::Changed => Ordering::Less,
71                Control::Event(_) => Ordering::Less,
72                #[cfg(feature = "dialog")]
73                Control::Close(_) => Ordering::Less,
74                Control::Quit => Ordering::Less,
75            },
76            Control::Unchanged => match other {
77                Control::Continue => Ordering::Greater,
78                Control::Unchanged => Ordering::Equal,
79                Control::Changed => Ordering::Less,
80                Control::Event(_) => Ordering::Less,
81                #[cfg(feature = "dialog")]
82                Control::Close(_) => Ordering::Less,
83                Control::Quit => Ordering::Less,
84            },
85            Control::Changed => match other {
86                Control::Continue => Ordering::Greater,
87                Control::Unchanged => Ordering::Greater,
88                Control::Changed => Ordering::Equal,
89                Control::Event(_) => Ordering::Less,
90                #[cfg(feature = "dialog")]
91                Control::Close(_) => Ordering::Less,
92                Control::Quit => Ordering::Less,
93            },
94            Control::Event(_) => match other {
95                Control::Continue => Ordering::Greater,
96                Control::Unchanged => Ordering::Greater,
97                Control::Changed => Ordering::Greater,
98                Control::Event(_) => Ordering::Equal,
99                #[cfg(feature = "dialog")]
100                Control::Close(_) => Ordering::Less,
101                Control::Quit => Ordering::Less,
102            },
103            #[cfg(feature = "dialog")]
104            Control::Close(_) => match other {
105                Control::Continue => Ordering::Greater,
106                Control::Unchanged => Ordering::Greater,
107                Control::Changed => Ordering::Greater,
108                Control::Event(_) => Ordering::Greater,
109                Control::Close(_) => Ordering::Equal,
110                Control::Quit => Ordering::Less,
111            },
112            Control::Quit => match other {
113                Control::Continue => Ordering::Greater,
114                Control::Unchanged => Ordering::Greater,
115                Control::Changed => Ordering::Greater,
116                Control::Event(_) => Ordering::Greater,
117                #[cfg(feature = "dialog")]
118                Control::Close(_) => Ordering::Greater,
119                Control::Quit => Ordering::Equal,
120            },
121        }
122    }
123}
124
125impl<Event> PartialOrd for Control<Event> {
126    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
127        Some(self.cmp(other))
128    }
129}
130
131impl<Event> ConsumedEvent for Control<Event> {
132    fn is_consumed(&self) -> bool {
133        !matches!(self, Control::Continue)
134    }
135}
136
137impl<Event, T: Into<Outcome>> From<T> for Control<Event> {
138    fn from(value: T) -> Self {
139        let r = value.into();
140        match r {
141            Outcome::Continue => Control::Continue,
142            Outcome::Unchanged => Control::Unchanged,
143            Outcome::Changed => Control::Changed,
144        }
145    }
146}