Skip to main content

kas_core/
messages.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! # Standard messages
7//!
8//! These are pre-defined message types which may be sent to a widget via
9//! [`EventCx::push`] or [`EventState::send`] in order to trigger some action.
10//!
11//! [`Erased`] is the type-erasure container allowing any type supporting
12//! [`Any`] + [`Debug`] to be sent or placed on the message stack.
13
14use crate::event::PhysicalKey;
15#[allow(unused)] use crate::event::{EventCx, EventState};
16use crate::geom::Offset;
17use crate::window::icon::Icon;
18use std::any::{Any, TypeId};
19use std::fmt::Debug;
20
21/// Synthetically trigger a "click" action
22///
23/// This message may be used to trigger a "click" action, for example to press a
24/// button or toggle a check box state.
25///
26/// Payload: the key press which caused this message to be emitted, if any.
27/// (This allows a visual state change to be bound to the key's release.)
28#[derive(Copy, Clone, Debug)]
29pub struct Activate(pub Option<PhysicalKey>);
30
31/// Increment value by one step
32#[derive(Copy, Clone, Debug)]
33pub struct IncrementStep;
34
35/// Decrement value by one step
36#[derive(Copy, Clone, Debug)]
37pub struct DecrementStep;
38
39/// Set an input value from `f64`
40///
41/// This message may be used to set a numeric value to an input field.
42#[derive(Copy, Clone, Debug)]
43pub struct SetValueF64(pub f64);
44
45/// Set an input value from a `String`
46///
47/// This message may be used to set a text value to an input field.
48///
49/// For targets with undo support this message commits a new undo state.
50#[derive(Clone, Debug)]
51pub struct SetValueText(pub String);
52
53/// Replace selected text in an input value
54///
55/// This acts the same as typing or pasting the text: replace an existing
56/// selection or insert at the cursor position.
57///
58/// For targets with undo support this message commits a new undo state.
59#[derive(Clone, Debug)]
60pub struct ReplaceSelectedText(pub String);
61
62/// Set an index
63#[derive(Clone, Debug)]
64pub struct SetIndex(pub usize);
65
66/// Expand a collapsible list or open a menu
67#[derive(Clone, Debug)]
68pub struct Expand;
69
70/// Collapse a collapsible list or close a menu
71#[derive(Clone, Debug)]
72pub struct Collapse;
73
74/// Request selection of the sender
75///
76/// This is only useful when pushed by a child widget or sent to a child widget
77/// for usage by a parent container supporting selection. The recipient must use
78/// [`EventCx::last_child`] to determine the selection target.
79///
80/// Example: a list supports selection; a child emits this to cause itself to be selected.
81#[derive(Clone, Debug)]
82pub struct Select;
83
84/// Set the scroll offset
85#[derive(Clone, Debug)]
86pub struct SetScrollOffset(pub Offset);
87
88/// Change the window's title
89#[derive(Clone, Debug)]
90pub struct SetWindowTitle(pub String);
91/// Change the window's icon
92#[derive(Clone, Debug)]
93pub struct SetWindowIcon(pub Option<Icon>);
94
95trait AnyDebug: Any + Debug {}
96impl<T: Any + Debug> AnyDebug for T {}
97
98/// A type-erased message
99///
100/// This is vaguely a wrapper over `Box<dyn (Any + Debug)>`, except that Rust
101/// doesn't (yet) support multi-trait objects.
102#[derive(Debug)]
103pub struct Erased(Box<dyn AnyDebug>, bool);
104
105impl Erased {
106    /// Construct
107    pub fn new<V: Any + Debug>(v: V) -> Self {
108        Erased(Box::new(v), false)
109    }
110
111    /// Returns `true` if the inner type is the same as `T`.
112    pub fn is<T: 'static>(&self) -> bool {
113        (&*self.0 as &dyn Any).is::<T>()
114    }
115
116    /// Returns the [`TypeId`] of the erased message
117    pub fn type_id(&self) -> TypeId {
118        (&*self.0 as &dyn Any).type_id()
119    }
120
121    /// Attempt to downcast self to a concrete type.
122    pub fn downcast<T: 'static>(self) -> Result<Box<T>, Box<dyn Any>> {
123        (self.0 as Box<dyn Any>).downcast::<T>()
124    }
125
126    /// Returns some reference to the inner value if it is of type `T`, or `None` if it isn’t.
127    pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
128        (&*self.0 as &dyn Any).downcast_ref::<T>()
129    }
130
131    pub(crate) fn debug(&self) -> &dyn Debug {
132        &self.0
133    }
134
135    pub(crate) fn set_sent(&mut self) {
136        self.1 = true;
137    }
138
139    pub(crate) fn is_sent(&self) -> bool {
140        self.1
141    }
142}
143
144trait AnySendDebug: AnyDebug + Send {}
145impl<T: Any + Send + Debug> AnySendDebug for T {}
146
147/// Like Erased, but supporting Send
148#[derive(Debug)]
149pub(crate) struct SendErased(Box<dyn AnySendDebug>);
150
151impl SendErased {
152    /// Construct
153    pub fn new<V: Any + Send + Debug>(v: V) -> Self {
154        SendErased(Box::new(v))
155    }
156
157    /// Convert to [`Erased`]
158    pub fn into_erased(self) -> Erased {
159        Erased(self.0, false)
160    }
161}