1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#![doc = include_str!("../readme.md")]

use std::cmp::max;
use std::ops::{BitOr, BitOrAssign};

pub mod crossterm;
pub mod util;

/// Default key bindings when focused.
/// Also handles all events that are MouseOnly.
#[derive(Debug, Default)]
pub struct FocusKeys;

/// Handler for mouse events only.
/// * Useful when writing a new key binding.
/// * FocusKeys should only be handled by the focused widget,
///   while mouse events are not bound by the focus.
#[derive(Debug, Default)]
pub struct MouseOnly;

///
/// A very broad trait for an event handler for widgets.
///
/// As widget types are only short-lived, this trait should be implemented
/// for the state type. Thereby it can modify any state, and it can
/// return an arbitrary result, that fits the widget.
///
pub trait HandleEvent<Event, Qualifier, R: ConsumedEvent> {
    /// Handle an event.
    ///
    /// * self - Should be the widget state.
    /// * event - Event
    /// * qualifier - Allows specifying/restricting the behaviour of the
    ///   event-handler.
    ///
    ///   This library defines two possible types:
    ///   * FocusKeys - The event-handler does all the interactions for
    ///     a focused widget. This calls the event-handler for MouseOnly too.
    ///   * MouseOnly - Interactions for a non-focused widget. Mostly only
    ///     reacting to mouse-events. But might check for hotkeys or the like.
    ///
    /// Further ideas:
    /// * ReadOnly
    /// * Additional special behaviour like DoubleClick, HotKeyAlt, HotKeyCtrl.
    /// * Opt-in behaviour like different key-bindings.
    /// * Configurable key-map.
    /// * Other context or configuration parameters.
    ///
    fn handle(&mut self, event: &Event, qualifier: Qualifier) -> R;
}

/// When composing several widgets, the minimum information from the outcome
/// of the inner widget is, whether it used & consumed the event.
///
/// This allows shortcutting the event-handling and prevents double
/// interactions with the event. The inner widget can special case an event,
/// and the fallback behaviour on the outer layer should not run too.
pub trait ConsumedEvent {
    fn is_consumed(&self) -> bool;

    /// Or-Else chaining with `is_consumed()` as the split.
    fn or_else<F>(self, f: F) -> Self
    where
        F: FnOnce() -> Self,
        Self: Sized,
    {
        if self.is_consumed() {
            self
        } else {
            f()
        }
    }
}

impl<V, E> ConsumedEvent for Result<V, E>
where
    V: ConsumedEvent,
{
    fn is_consumed(&self) -> bool {
        match self {
            Ok(v) => v.is_consumed(),
            Err(_) => true,
        }
    }
}

impl<V> ConsumedEvent for Option<V>
where
    V: ConsumedEvent,
{
    fn is_consumed(&self) -> bool {
        match self {
            Some(v) => v.is_consumed(),
            None => true,
        }
    }
}

/// A baseline Outcome for event-handling.
///
/// A widget can define its own, if it has more things to report.
/// It would be nice of the widget though, if its outcome would be
/// convertible to this baseline.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Outcome {
    /// The given event has not been used at all.
    NotUsed,
    /// The event has been recognized, but the result was nil.
    /// Further processing for this event may stop.
    Unchanged,
    /// The event has been recognized and there is some change
    /// due to it.
    /// Further processing for this event may stop.
    /// Rendering the ui is advised.
    Changed,
}

impl ConsumedEvent for Outcome {
    fn is_consumed(&self) -> bool {
        !matches!(self, Outcome::NotUsed)
    }
}

impl BitOr for Outcome {
    type Output = Outcome;

    /// Returns max(left, right).
    ///
    /// That means
    /// `Outcome::NotUsed | Outcome::Changed == Outcome::Changed`,
    /// which should be the expected result.
    fn bitor(self, rhs: Self) -> Self::Output {
        max(self, rhs)
    }
}

impl BitOrAssign for Outcome {
    fn bitor_assign(&mut self, rhs: Self) {
        *self = self.bitor(rhs);
    }
}

/// Event functions in widgets often return bool to indicate
/// a meaningful change occured. This converts `true / false` to
///` Outcome::Changed / Outcome::Unchanged`.
impl From<bool> for Outcome {
    fn from(value: bool) -> Self {
        if value {
            Outcome::Changed
        } else {
            Outcome::Unchanged
        }
    }
}

/// Breaks the control-flow if the block returns a value
/// for with [ConsumedEvent::is_consumed] is true.
///
/// It then does the classic `into()`-conversion and returns.
///
/// Special widget result-types are encourage to map down to Outcome
/// as a baseline.
///
/// *The difference to [flow] is that this one Ok-wraps the result.*
///
/// Extras: If you add a marker as in `flow_ok!(log ident: {...});`
/// the result of the operation is written to the log.
#[macro_export]
macro_rules! flow {
    (log $n:ident: $x:expr) => {{
        use $crate::ConsumedEvent;
        let r = $x;
        if r.is_consumed() {
            debug!("{} {:#?}", stringify!($n), r);
            return r.into();
        } else {
            debug!("{} continue", stringify!($n));
            _ = r;
        }
    }};
    ($x:expr) => {{
        use $crate::ConsumedEvent;
        let r = $x;
        if r.is_consumed() {
            return r.into();
        } else {
            _ = r;
        }
    }};
}

/// Breaks and Ok-wraps the control-flow if the block
/// returns a value for with [ConsumedEvent::is_consumed] is true.
///
/// It then does the classic `into()`-conversion and wraps the
/// result in `Ok()`.
///
/// Special widget result-types are encourage to map down to Outcome
/// as a baseline.
///
/// *The difference to [flow] is that this one Ok-wraps the result.*
///
/// Extras: If you add a marker as in `flow_ok!(log ident: {...});`
/// the result of the operation is written to the log.
#[macro_export]
macro_rules! flow_ok {
    (log $n:ident: $x:expr) => {{
        use $crate::ConsumedEvent;
        let r = $x;
        if r.is_consumed() {
            debug!("{} {:#?}", stringify!($n), r);
            return Ok(r.into());
        } else {
            debug!("{} continue", stringify!($n));
            _ = r;
        }
    }};
    ($x:expr) => {{
        use $crate::ConsumedEvent;
        let r = $x;
        if r.is_consumed() {
            return Ok(r.into());
        } else {
            _ = r;
        }
    }};
}