rg3d_ui/
message.rs

1//! Message and events module contains all possible widget messages and OS events.
2//!
3//! This UI library uses message passing mechanism to communicate with widgets.
4//! This is very simple and reliable mechanism that effectively decouples widgets
5//! from each other. There is no direct way of modify something during runtime,
6//! you have to use messages to change state of ui elements.
7//!
8//! # Direction
9//!
10//! Each message marked with "Direction" field, which means supported routes for
11//! message. For example [ButtonMessage::Click](enum.ButtonMessage.html) has "Direction: To/From UI" which
12//! means that it can be sent either from internals of library or from user code.
13//! However [WidgetMessage::GotFocus](enum.WidgetMessage.html) has "Direction: From UI" which means that only
14//! internal library code can send such messages without a risk of breaking anything.
15
16use crate::{
17    core::{algebra::Vector2, pool::Handle},
18    UiNode,
19};
20use std::{
21    any::Any,
22    cell::Cell,
23    fmt::Debug,
24    ops::{Deref, DerefMut},
25    rc::Rc,
26};
27
28#[macro_export]
29macro_rules! define_constructor {
30    ($inner:ident : $inner_var:tt => fn $name:ident(), layout: $perform_layout:expr) => {
31        pub fn $name(destination: Handle<UiNode>, direction: MessageDirection) -> UiMessage {
32            UiMessage {
33                handled: std::cell::Cell::new(false),
34                data: std::rc::Rc::new($inner::$inner_var),
35                destination,
36                direction,
37                perform_layout: std::cell::Cell::new($perform_layout),
38                flags: 0
39            }
40        }
41    };
42
43    ($inner:ident : $inner_var:tt => fn $name:ident($typ:ty), layout: $perform_layout:expr) => {
44        pub fn $name(destination: Handle<UiNode>, direction: MessageDirection, value:$typ) -> UiMessage {
45            UiMessage {
46                handled: std::cell::Cell::new(false),
47                data: std::rc::Rc::new($inner::$inner_var(value)),
48                destination,
49                direction,
50                perform_layout: std::cell::Cell::new($perform_layout),
51                flags: 0
52            }
53        }
54    };
55
56    ($inner:ident : $inner_var:tt => fn $name:ident( $($params:ident : $types:ty),+ ), layout: $perform_layout:expr) => {
57        pub fn $name(destination: Handle<UiNode>, direction: MessageDirection, $($params : $types),+) -> UiMessage {
58            UiMessage {
59                handled: std::cell::Cell::new(false),
60                data: std::rc::Rc::new($inner::$inner_var { $($params),+ }),
61                destination,
62                direction,
63                perform_layout: std::cell::Cell::new($perform_layout),
64                flags: 0
65            }
66        }
67    }
68}
69
70#[derive(Debug)]
71pub struct UserMessageData(pub Box<dyn MessageData>);
72
73impl Deref for UserMessageData {
74    type Target = dyn MessageData;
75
76    fn deref(&self) -> &Self::Target {
77        &*self.0
78    }
79}
80
81impl DerefMut for UserMessageData {
82    fn deref_mut(&mut self) -> &mut Self::Target {
83        &mut *self.0
84    }
85}
86
87impl PartialEq for UserMessageData {
88    fn eq(&self, other: &Self) -> bool {
89        self.0.compare(&*other.0)
90    }
91}
92
93/// Message direction allows you to distinguish from where message has came from.
94/// Often there is a need to find out who created a message to respond properly.
95/// Imagine that we have a NumericUpDown input field for a property and we using
96/// some data source to feed data into input field. When we change something in
97/// the input field by typing, it creates a message with new value. On other
98/// hand we often need to put new value in the input field from some code, in this
99/// case we again creating a message. But how to understand from which "side"
100/// message has came from? Was it filled in by user and we should create a command
101/// to change value in the data source, or it was created from syncing code just to
102/// pass new value to UI? This problem solved by setting a direction to a message.
103/// Also it solves another problem: often we need to respond to a message only if
104/// it did some changes. In this case at first we fire a message with ToWidget
105/// direction, widget catches it and checks if changes are needed and if so, it
106/// "rethrows" message with direction FromWidget. Listeners are "subscribed" to
107/// FromWidget messages only and won't respond to ToWidget messages.
108#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Hash)]
109pub enum MessageDirection {
110    /// Used to indicate a request for changes in a widget.
111    ToWidget,
112
113    /// Used to indicate response from widget if anything has actually changed.
114    FromWidget,
115}
116
117impl MessageDirection {
118    /// Reverses direction.
119    pub fn reverse(self) -> Self {
120        match self {
121            Self::ToWidget => Self::FromWidget,
122            Self::FromWidget => Self::ToWidget,
123        }
124    }
125}
126
127pub trait MessageData: 'static + Debug + Any {
128    fn as_any(&self) -> &dyn Any;
129
130    fn compare(&self, other: &dyn MessageData) -> bool;
131}
132
133impl<T> MessageData for T
134where
135    T: 'static + Debug + PartialEq + Any,
136{
137    fn as_any(&self) -> &dyn Any {
138        self
139    }
140
141    fn compare(&self, other: &dyn MessageData) -> bool {
142        other
143            .as_any()
144            .downcast_ref::<T>()
145            .map(|other| other == self)
146            .unwrap_or_default()
147    }
148}
149
150/// Message is basic communication element that is used to deliver information to UI nodes
151/// or to user code.
152///
153/// # Threading
154///
155/// UiMessage is nor Send or Sync. User interface is a single-thread thing, as well as its messages.
156#[derive(Debug, Clone)]
157pub struct UiMessage {
158    /// Useful flag to check if a message was already handled.
159    pub handled: Cell<bool>,
160
161    /// Actual message data.
162    pub data: Rc<dyn MessageData>,
163
164    /// Handle of node that will receive message. Please note that all nodes in hierarchy will
165    /// also receive this message, order is "up-on-tree".
166    pub destination: Handle<UiNode>,
167
168    /// Indicates the direction of the message.
169    ///
170    /// See [MessageDirection](enum.MessageDirection.html) for details.
171    pub direction: MessageDirection,
172
173    /// Whether or not message requires layout to be calculated first.
174    ///
175    /// Some of message handling routines uses layout info, but message loop
176    /// performed right after layout pass, but some of messages may change
177    /// layout and this flag tells UI to perform layout before passing message
178    /// further. In ideal case we'd perform layout after **each** message, but
179    /// since layout pass is super heavy we should do it **only** when it is
180    /// actually needed.
181    pub perform_layout: Cell<bool>,
182
183    /// A custom user flags.
184    pub flags: u64,
185}
186
187impl PartialEq for UiMessage {
188    fn eq(&self, other: &Self) -> bool {
189        self.handled == other.handled
190            && self.data.compare(&*other.data)
191            && self.destination == other.destination
192            && self.direction == other.direction
193            && self.perform_layout == other.perform_layout
194            && self.flags == other.flags
195    }
196}
197
198impl UiMessage {
199    pub fn with_data<T: MessageData>(data: T) -> Self {
200        Self {
201            handled: Cell::new(false),
202            data: Rc::new(data),
203            destination: Default::default(),
204            direction: MessageDirection::ToWidget,
205            perform_layout: Cell::new(false),
206            flags: 0,
207        }
208    }
209
210    pub fn with_destination(mut self, destination: Handle<UiNode>) -> Self {
211        self.destination = destination;
212        self
213    }
214
215    pub fn with_direction(mut self, direction: MessageDirection) -> Self {
216        self.direction = direction;
217        self
218    }
219
220    pub fn with_perform_layout(self, perform_layout: bool) -> Self {
221        self.perform_layout.set(perform_layout);
222        self
223    }
224
225    /// Creates a new copy of the message with reversed direction. Typical use case is
226    /// to re-send messages to create "response" in widget. For example you have a float
227    /// input field and it has Value message. When the input field receives Value message
228    /// with [MessageDirection::ToWidget](enum.MessageDirection.html#variant.ToWidget)
229    /// it checks if value needs to be changed and if it does, it re-sends same message
230    /// but with reversed direction back to message queue so every "listener" can reach
231    /// properly. The input field won't react at
232    /// [MessageDirection::FromWidget](enum.MessageDirection.html#variant.FromWidget)
233    /// message so there will be no infinite message loop.
234    #[must_use = "method creates new value which must be used"]
235    pub fn reverse(&self) -> Self {
236        Self {
237            handled: self.handled.clone(),
238            data: self.data.clone(),
239            destination: self.destination,
240            direction: self.direction.reverse(),
241            perform_layout: self.perform_layout.clone(),
242            flags: self.flags,
243        }
244    }
245
246    pub fn destination(&self) -> Handle<UiNode> {
247        self.destination
248    }
249
250    pub fn data<T: MessageData>(&self) -> Option<&T> {
251        (*self.data).as_any().downcast_ref::<T>()
252    }
253
254    pub fn set_handled(&self, handled: bool) {
255        self.handled.set(handled);
256    }
257
258    pub fn handled(&self) -> bool {
259        self.handled.get()
260    }
261
262    pub fn direction(&self) -> MessageDirection {
263        self.direction
264    }
265
266    pub fn set_perform_layout(&self, value: bool) {
267        self.perform_layout.set(value);
268    }
269
270    pub fn need_perform_layout(&self) -> bool {
271        self.perform_layout.get()
272    }
273
274    pub fn has_flags(&self, flags: u64) -> bool {
275        self.flags & flags != 0
276    }
277}
278
279#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
280pub enum ButtonState {
281    Pressed,
282    Released,
283}
284
285#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
286pub enum MouseButton {
287    Left,
288    Right,
289    Middle,
290    Other(u16),
291}
292
293pub enum OsEvent {
294    MouseInput {
295        button: MouseButton,
296        state: ButtonState,
297    },
298    CursorMoved {
299        position: Vector2<f32>,
300    },
301    KeyboardInput {
302        button: KeyCode,
303        state: ButtonState,
304    },
305    Character(char),
306    KeyboardModifiers(KeyboardModifiers),
307    MouseWheel(f32, f32),
308}
309
310#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy, Default)]
311pub struct KeyboardModifiers {
312    pub alt: bool,
313    pub shift: bool,
314    pub control: bool,
315    pub system: bool,
316}
317
318impl KeyboardModifiers {
319    pub fn is_none(self) -> bool {
320        !self.shift && !self.control && !self.alt && !self.system
321    }
322}
323
324#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
325#[repr(u32)]
326pub enum KeyCode {
327    Key1,
328    Key2,
329    Key3,
330    Key4,
331    Key5,
332    Key6,
333    Key7,
334    Key8,
335    Key9,
336    Key0,
337    A,
338    B,
339    C,
340    D,
341    E,
342    F,
343    G,
344    H,
345    I,
346    J,
347    K,
348    L,
349    M,
350    N,
351    O,
352    P,
353    Q,
354    R,
355    S,
356    T,
357    U,
358    V,
359    W,
360    X,
361    Y,
362    Z,
363
364    Escape,
365
366    F1,
367    F2,
368    F3,
369    F4,
370    F5,
371    F6,
372    F7,
373    F8,
374    F9,
375    F10,
376    F11,
377    F12,
378    F13,
379    F14,
380    F15,
381    F16,
382    F17,
383    F18,
384    F19,
385    F20,
386    F21,
387    F22,
388    F23,
389    F24,
390
391    Snapshot,
392    Scroll,
393    Pause,
394
395    Insert,
396    Home,
397    Delete,
398    End,
399    PageDown,
400    PageUp,
401
402    Left,
403    Up,
404    Right,
405    Down,
406
407    Backspace,
408    Return,
409    Space,
410
411    Compose,
412
413    Caret,
414
415    Numlock,
416    Numpad0,
417    Numpad1,
418    Numpad2,
419    Numpad3,
420    Numpad4,
421    Numpad5,
422    Numpad6,
423    Numpad7,
424    Numpad8,
425    Numpad9,
426
427    AbntC1,
428    AbntC2,
429    NumpadAdd,
430    Apostrophe,
431    Apps,
432    At,
433    Ax,
434    Backslash,
435    Calculator,
436    Capital,
437    Colon,
438    Comma,
439    Convert,
440    NumpadDecimal,
441    NumpadDivide,
442    Equals,
443    Grave,
444    Kana,
445    Kanji,
446    LAlt,
447    LBracket,
448    LControl,
449    LShift,
450    LWin,
451    Mail,
452    MediaSelect,
453    MediaStop,
454    Minus,
455    NumpadMultiply,
456    Mute,
457    MyComputer,
458    NavigateForward,
459    NavigateBackward,
460    NextTrack,
461    NoConvert,
462    NumpadComma,
463    NumpadEnter,
464    NumpadEquals,
465    OEM102,
466    Period,
467    PlayPause,
468    Power,
469    PrevTrack,
470    RAlt,
471    RBracket,
472    RControl,
473    RShift,
474    RWin,
475    Semicolon,
476    Slash,
477    Sleep,
478    Stop,
479    NumpadSubtract,
480    Sysrq,
481    Tab,
482    Underline,
483    Unlabeled,
484    VolumeDown,
485    VolumeUp,
486    Wake,
487    WebBack,
488    WebFavorites,
489    WebForward,
490    WebHome,
491    WebRefresh,
492    WebSearch,
493    WebStop,
494    Yen,
495    Copy,
496    Paste,
497    Cut,
498    Asterisk,
499    Plus,
500}
501
502#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
503pub enum CursorIcon {
504    Default,
505    Crosshair,
506    Hand,
507    Arrow,
508    Move,
509    Text,
510    Wait,
511    Help,
512    Progress,
513    NotAllowed,
514    ContextMenu,
515    Cell,
516    VerticalText,
517    Alias,
518    Copy,
519    NoDrop,
520    Grab,
521    Grabbing,
522    AllScroll,
523    ZoomIn,
524    ZoomOut,
525    EResize,
526    NResize,
527    NeResize,
528    NwResize,
529    SResize,
530    SeResize,
531    SwResize,
532    WResize,
533    EwResize,
534    NsResize,
535    NeswResize,
536    NwseResize,
537    ColResize,
538    RowResize,
539}
540
541impl Default for CursorIcon {
542    fn default() -> Self {
543        CursorIcon::Default
544    }
545}