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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
// event.rs

// *************************************************************************
// * Copyright (C) 2018-2019 Daniel Mueller (deso@posteo.net)              *
// *                                                                       *
// * This program is free software: you can redistribute it and/or modify  *
// * it under the terms of the GNU General Public License as published by  *
// * the Free Software Foundation, either version 3 of the License, or     *
// * (at your option) any later version.                                   *
// *                                                                       *
// * This program is distributed in the hope that it will be useful,       *
// * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
// * GNU General Public License for more details.                          *
// *                                                                       *
// * You should have received a copy of the GNU General Public License     *
// * along with this program.  If not, see <http://www.gnu.org/licenses/>. *
// *************************************************************************

use std::any::Any;

use crate::Id;


/// An event type containing custom and arbitrary data.
///
/// Custom events are the means for transferring arbitrary data between
/// widgets.
#[derive(Debug)]
pub(crate) enum CustomEvent<'evnt> {
  /// An event that is sent in full to another widget.
  ///
  /// Ownership of the event is transferred to a widget. Custom events
  /// of this type are considered the safe default. They represent a
  /// unidirectional message from one widget to another.
  Owned(Box<dyn Any>),
  /// A mutable reference to an event that is sent to another widget.
  ///
  /// Ownership of an event of this type will eventually be transferred
  /// back to the originating widget. Custom events of this type are
  /// used for messages for which a response is expected or which
  /// transfer state that eventually has to end up back at the sender.
  /// The callee is free to modify the event in any way, but the `Ui`
  /// proper ensures that it will be returned to the sender.
  Borrowed(&'evnt mut dyn Any),
}


/// An event that the `Ui` can process.
#[derive(Debug)]
pub enum UiEvent<E> {
  /// An `Event` that can be handled by a `Handleable`.
  Event(E),
  /// A custom event that can contain arbitrary data.
  Custom(Box<dyn Any>),
  /// A custom event directed to a certain widget.
  ///
  /// This custom event is destined for a particular widget, described
  /// by the given `Id`. That is the only widget that will receive the
  /// event.
  Directed(Id, Box<dyn Any>),
  /// A custom event that is guaranteed to be returned back to the
  /// issuer. The first `Id` represents the source (i.e., the widget the
  /// event will be returned to), while the second one identifies the
  /// destination (the widget actually "handling" the event).
  Returnable(Id, Id, Box<dyn Any>),
  /// A request to quit the application has been made.
  Quit,
}

/// A convenience conversion from `Event` to `UiEvent`.
impl<E> From<E> for UiEvent<E> {
  fn from(event: E) -> Self {
    UiEvent::Event(event)
  }
}


/// An event that the `Ui` did not process.
///
/// An unhandled event comprises the variants of a `UiEvent` that are
/// not concerned with addressing.
// Note that we do not provide a conversion from `UiEvent` because
// conversion should only happen from within the `Ui` proper and after
// making sure that `UiEvent` variants dealing solely with addressing
// are no longer present.
#[derive(Debug)]
pub enum UnhandledEvent<E> {
  /// An `Event` that can be handled by a `Handleable`.
  Event(E),
  /// A custom event that can contain arbitrary data.
  Custom(Box<dyn Any>),
  /// A request to quit the application has been made.
  Quit,
}

/// A convenience conversion from a single event into an `UnhandledEvent`.
impl<E> From<E> for UnhandledEvent<E> {
  fn from(event: E) -> Self {
    UnhandledEvent::Event(event)
  }
}


/// An event potentially comprising multiple event objects.
#[derive(Debug)]
pub enum ChainEvent<E> {
  /// An arbitrary event.
  Event(E),
  /// A chain of events.
  ///
  /// The events will be processed in the order they are chained.
  Chain(E, Box<ChainEvent<E>>),
}

impl<E> ChainEvent<E> {
  /// Convert this `ChainEvent` into the last event it comprises.
  pub fn into_last(self) -> E {
    match self {
      ChainEvent::Event(event) => event,
      ChainEvent::Chain(_, chain) => chain.into_last(),
    }
  }
}

/// A convenience conversion from a single event into a `ChainEvent`.
impl<E> From<E> for ChainEvent<E> {
  fn from(event: E) -> Self {
    ChainEvent::Event(event)
  }
}


/// An event potentially comprising multiple `UiEvent` objects.
pub type UiEvents<E> = ChainEvent<UiEvent<E>>;

/// A convenience conversion from a single event into a chain of `UiEvent` objects.
impl<E> From<E> for UiEvents<E> {
  fn from(event: E) -> Self {
    ChainEvent::Event(event.into())
  }
}


/// An event potentially comprising multiple `UnhandledEvent` objects.
pub type UnhandledEvents<E> = ChainEvent<UnhandledEvent<E>>;

/// A convenience conversion from a single event into a chain of `UnhandledEvent` objects.
impl<E> From<E> for UnhandledEvents<E> {
  fn from(event: E) -> Self {
    ChainEvent::Event(event.into())
  }
}


/// A trait for chaining of events.
pub trait EventChain<ED> {
  /// Chain together two events.
  ///
  /// The given event will effectively be appended to the current one
  /// and, hence, be handled after the first one got processed.
  fn chain<ES>(self, event: ES) -> ChainEvent<ED>
  where
    ES: Into<ChainEvent<ED>>;

  /// Chain together an event with an optional event.
  ///
  /// This method returns the chain of the first event with the second
  /// one, if present, or otherwise just returns the first one.
  fn chain_opt<ES>(self, event: Option<ES>) -> ChainEvent<ED>
  where
    ES: Into<ChainEvent<ED>>;
}

impl<ES, ED> EventChain<ED> for ES
where
  ES: Into<ChainEvent<ED>>,
{
  fn chain<E>(self, event: E) -> ChainEvent<ED>
  where
    E: Into<ChainEvent<ED>>,
  {
    match self.into() {
      ChainEvent::Event(e) => ChainEvent::Chain(e, Box::new(event.into())),
      ChainEvent::Chain(e, chain) => ChainEvent::Chain(e, Box::new((*chain).chain(event))),
    }
  }

  fn chain_opt<E>(self, event: Option<E>) -> ChainEvent<ED>
  where
    E: Into<ChainEvent<ED>>,
  {
    match event {
      Some(event) => self.chain(event),
      None => self.into(),
    }
  }
}


/// A trait for chaining of optional events.
pub trait OptionChain<ES, ED>
where
  ES: Into<ChainEvent<ED>>,
{
  /// Chain an optional event with another optional event.
  fn chain<E>(self, event: Option<E>) -> Option<ChainEvent<ED>>
  where
    E: Into<ChainEvent<ED>>;

  /// Chain an optional event with the given event.
  fn opt_chain<E>(self, event: E) -> ChainEvent<ED>
  where
    E: Into<ChainEvent<ED>>;
}

impl<ES, ED> OptionChain<ES, ED> for Option<ES>
where
  ES: Into<ChainEvent<ED>>,
{
  fn chain<E>(self, event: Option<E>) -> Option<ChainEvent<ED>>
  where
    E: Into<ChainEvent<ED>>,
  {
    match self {
      Some(e1) => Some(e1.chain_opt(event)),
      None => {
        match event {
          Some(e2) => Some(e2.into()),
          None => None,
        }
      },
    }
  }

  fn opt_chain<E>(self, event: E) -> ChainEvent<ED>
  where
    E: Into<ChainEvent<ED>>,
  {
    match self {
      Some(e1) => e1.chain(event),
      None => event.into(),
    }
  }
}