fyrox_ui/message.rs
1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Message and events module contains all possible widget messages and OS events. See [`UiMessage`] docs for more info and
22//! examples.
23
24#![warn(missing_docs)]
25
26use crate::{
27 core::{algebra::Vector2, pool::Handle, reflect::prelude::*, visitor::prelude::*},
28 UiNode, UserInterface,
29};
30use fyrox_core::pool::ObjectOrVariant;
31use fyrox_core::uuid_provider;
32use serde::{Deserialize, Serialize};
33use std::{any::Any, cell::Cell, fmt::Debug};
34use strum_macros::{AsRefStr, EnumString, VariantNames};
35
36/// Message direction allows you to distinguish from where the message has come from. Often there is a need to find out who
37/// created a message to respond properly. Imagine that we have a NumericUpDown input field for a property, and we're using
38/// some data source to feed data into the input field. When we change something in the input field by typing, it creates a
39/// message with new value. On the other hand, we often need to put new value in the input field from some code, in this case
40/// we're again creating a message. But how to understand from which "side" message has come from? Was it filled in by user,
41/// and we should create a command to change value in the data source, or it was created from syncing code just to pass
42/// new value to UI? This problem is solved by setting a direction to a message. Also, it solves another problem: often we
43/// need to respond to a message only if it did some changes. In this case, at first we fire a message with ToWidget direction,
44/// widget catches it and checks if changes are needed, and if so, it "rethrows" message with direction FromWidget. Listeners
45/// are "subscribed" to FromWidget messages only and won't respond to ToWidget messages.
46#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Hash, Eq)]
47pub enum MessageDirection {
48 /// Used to indicate a request for changes in a widget.
49 ToWidget,
50
51 /// Used to indicate response from the widget if anything has actually changed.
52 FromWidget,
53}
54
55impl MessageDirection {
56 /// Reverses direction.
57 pub fn reverse(self) -> Self {
58 match self {
59 Self::ToWidget => Self::FromWidget,
60 Self::FromWidget => Self::ToWidget,
61 }
62 }
63}
64
65/// A trait, that is used by every messages used in the user interface. It contains utility methods that are used
66/// for downcasting and equality comparison.
67pub trait BaseMessageData: 'static + Debug + Any + Send {
68 /// Casts `self` as [`Any`] reference.
69 fn as_any(&self) -> &dyn Any;
70
71 /// Compares this message data with some other.
72 fn compare(&self, other: &dyn BaseMessageData) -> bool;
73
74 /// Clones self as boxed value.
75 fn clone_box(&self) -> Box<dyn MessageData>;
76}
77
78impl<T> BaseMessageData for T
79where
80 T: 'static + Debug + PartialEq + Any + Send + Clone + MessageData,
81{
82 fn as_any(&self) -> &dyn Any {
83 self
84 }
85
86 fn compare(&self, other: &dyn BaseMessageData) -> bool {
87 other
88 .as_any()
89 .downcast_ref::<T>()
90 .map(|other| other == self)
91 .unwrap_or_default()
92 }
93
94 fn clone_box(&self) -> Box<dyn MessageData> {
95 Box::new(self.clone())
96 }
97}
98
99/// A trait for any message that can be put to the UI message queue.
100pub trait MessageData: BaseMessageData {
101 /// Returns `true` when the message starts a new layout pass before being passed to its
102 /// destination.
103 fn need_perform_layout(&self) -> bool {
104 false
105 }
106}
107
108/// Defines a way of how the message will behave in the widget tree after it was delivered to
109/// the destination node.
110#[derive(Default, Copy, Clone, Debug, PartialEq)]
111pub enum RoutingStrategy {
112 /// A message will be passed to every ancestor widget in the hierarchy until the root.
113 #[default]
114 BubbleUp,
115 /// A message will be passed directly to a widget directly and won't be passed to any other
116 /// widget (message preview mechanism will still be used).
117 Direct,
118}
119
120/// Delivery mode
121#[derive(Default, Copy, Clone, Debug, PartialEq)]
122pub enum DeliveryMode {
123 /// The message will be at first processed by the widgets (via [`crate::control::Control::handle_routed_message`] and [`crate::control::Control::preview_message`]
124 /// methods) and then will be returned to the caller of [`UserInterface::poll_message_queue`] for further
125 /// processing. This is the default mode.
126 #[default]
127 FullCycle,
128
129 /// The message will never escape the internal message queue. The [`UserInterface::poll_message_queue`]
130 /// will never return such message, and the message will only be processed by the widgets (via
131 /// [`crate::control::Control::handle_routed_message`] and [`crate::control::Control::preview_message`] methods).
132 /// This mode is used to break message loops at the synchronization stage when the UI state is
133 /// synchronized with a data.
134 SyncOnly,
135}
136
137/// Message is a basic communication element that is used to deliver information to widget or to user code.
138///
139/// ## Motivation
140///
141/// This UI library uses message passing mechanism to communicate with widgets. This is a very simple
142/// and reliable mechanism that effectively decouples widgets from each other. There is no direct
143/// way of modifying something during runtime, you have to use messages to change the state of ui elements.
144///
145/// ## Direction
146///
147/// Each message marked with "Direction" field, which means supported routes for message. For example
148/// [`crate::button::ButtonMessage::Click`] has "Direction: To/From UI" which means that it can be
149/// sent either from internals of library or from user code. However [`crate::widget::WidgetMessage::Focus`]
150/// has "Direction: From UI" which means that only internal library code can send such messages without
151/// a risk of breaking anything.
152///
153/// ## Threading
154///
155/// UiMessage is [`Send`], it can be sent from another thread to a user interface.
156///
157/// ## Examples
158///
159/// ```rust
160/// use fyrox_ui::{
161/// core::pool::Handle, message::MessageDirection, message::UiMessage, UiNode,
162/// UserInterface, message::MessageData,
163/// };
164///
165/// // Message must be debuggable and comparable.
166/// #[derive(Debug, PartialEq, Clone)]
167/// enum MyWidgetMessage {
168/// DoSomething,
169/// Foo(u32),
170/// Bar { foo: u32, baz: u8 },
171/// }
172/// impl MessageData for MyWidgetMessage{}
173///
174/// fn using_messages(my_widget: Handle<UiNode>, ui: &UserInterface) {
175/// // Send MyWidgetMessage::DoSomething
176/// ui.send(my_widget, MyWidgetMessage::DoSomething);
177/// // Send MyWidgetMessage::Foo
178/// ui.send(my_widget, MyWidgetMessage::Foo(5));
179/// // Send MyWidgetMessage::Bar
180/// ui.send(my_widget, MyWidgetMessage::Bar {foo: 1, baz: 2});
181/// }
182/// ```
183///
184pub struct UiMessage {
185 /// Useful flag to check if a message was already handled. It could be used to mark messages as "handled" to prevent
186 /// any further responses to them. It is especially useful in bubble message routing, when a message is passed through
187 /// the entire chain of parent nodes starting from current. In this, you can mark a message as "handled" and also check
188 /// if it is handled or not. For example, this is used in [`crate::tree::Tree`] implementation, to prevent double-click
189 /// to close all the parent trees from current.
190 pub handled: Cell<bool>,
191
192 /// Actual message data. Use [`UiMessage::data`] method to try to downcast the internal data to a specific type.
193 pub data: Box<dyn MessageData>,
194
195 /// Handle of node that will receive message. Please note that **all** nodes in hierarchy will also receive this message,
196 /// order is "up-on-tree" (so-called "bubble" message routing).
197 pub destination: Handle<UiNode>,
198
199 /// Indicates the direction of the message. See [`MessageDirection`] docs for more info.
200 pub direction: MessageDirection,
201
202 /// Defines a way of how the message will behave in the widget tree after it was delivered to
203 /// the destination node. Default is bubble routing. See [`RoutingStrategy`] for more info.
204 pub routing_strategy: RoutingStrategy,
205
206 /// Message delivery mode. See [`DeliveryMode`] docs for more info.
207 pub delivery_mode: DeliveryMode,
208
209 /// A custom user flags. Use it if `handled` flag is not enough.
210 pub flags: u64,
211}
212
213/// Compares the new value with the existing one, and if they do not match, sets the new value to it
214/// and sends the given message back to the message queue with the opposite direction. This function
215/// is useful to reduce boilerplate code when reacting to widget messages.
216pub fn compare_and_set<T>(
217 value: &mut T,
218 new_value: &T,
219 message: &UiMessage,
220 ui: &UserInterface,
221) -> bool
222where
223 T: PartialEq + Clone,
224{
225 if value != new_value {
226 *value = new_value.clone();
227 ui.send_message(message.reverse());
228 true
229 } else {
230 false
231 }
232}
233
234impl Debug for UiMessage {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 write!(
237 f,
238 "UiMessage({}:({})",
239 match self.direction {
240 MessageDirection::ToWidget => "To",
241 MessageDirection::FromWidget => "From",
242 },
243 self.destination
244 )?;
245 if self.handled.get() {
246 write!(f, ",handled")?;
247 }
248 if self.flags != 0 {
249 write!(f, ",flags:{}", self.flags)?;
250 }
251 match self.delivery_mode {
252 DeliveryMode::FullCycle => {
253 write!(f, ",full cycle")?;
254 }
255 DeliveryMode::SyncOnly => {
256 write!(f, ",sync only")?;
257 }
258 }
259 write!(f, "):{:?}", self.data)
260 }
261}
262
263impl Clone for UiMessage {
264 fn clone(&self) -> Self {
265 Self {
266 handled: self.handled.clone(),
267 data: self.data.clone_box(),
268 destination: self.destination,
269 direction: self.direction,
270 routing_strategy: self.routing_strategy,
271 delivery_mode: Default::default(),
272 flags: self.flags,
273 }
274 }
275}
276
277impl PartialEq for UiMessage {
278 fn eq(&self, other: &Self) -> bool {
279 self.handled == other.handled
280 && self.data.compare(&*other.data)
281 && self.destination == other.destination
282 && self.routing_strategy == other.routing_strategy
283 && self.direction == other.direction
284 && self.flags == other.flags
285 }
286}
287
288impl UiMessage {
289 /// Creates new UI message with desired data.
290 pub fn with_data<T: MessageData>(data: T) -> Self {
291 Self {
292 handled: Cell::new(false),
293 data: Box::new(data),
294 destination: Default::default(),
295 direction: MessageDirection::ToWidget,
296 routing_strategy: Default::default(),
297 delivery_mode: Default::default(),
298 flags: 0,
299 }
300 }
301
302 /// Creates a new UI message with the given data for the specified widget.
303 pub fn for_widget(
304 handle: Handle<impl ObjectOrVariant<UiNode>>,
305 data: impl MessageData,
306 ) -> Self {
307 Self::with_data(data)
308 .with_destination(handle.transmute())
309 .with_direction(MessageDirection::ToWidget)
310 }
311
312 /// Creates a new UI message with the given data to be posted from the name of the specified
313 /// widget.
314 pub fn from_widget(
315 handle: Handle<impl ObjectOrVariant<UiNode>>,
316 data: impl MessageData,
317 ) -> Self {
318 Self::with_data(data)
319 .with_destination(handle.transmute())
320 .with_direction(MessageDirection::FromWidget)
321 }
322
323 /// Sets the desired destination of the message.
324 pub fn with_destination(mut self, destination: Handle<UiNode>) -> Self {
325 self.destination = destination;
326 self
327 }
328
329 /// Sets the desired direction of the message.
330 pub fn with_direction(mut self, direction: MessageDirection) -> Self {
331 self.direction = direction;
332 self
333 }
334
335 /// Sets the desired handled flag of the message.
336 pub fn with_handled(self, handled: bool) -> Self {
337 self.handled.set(handled);
338 self
339 }
340
341 /// Sets the desired routing strategy.
342 pub fn with_routing_strategy(mut self, routing_strategy: RoutingStrategy) -> Self {
343 self.routing_strategy = routing_strategy;
344 self
345 }
346
347 /// Sets the desired delivery mode for the message.
348 pub fn with_delivery_mode(mut self, delivery_mode: DeliveryMode) -> Self {
349 self.delivery_mode = delivery_mode;
350 self
351 }
352
353 /// Sets the desired flags of the message.
354 pub fn with_flags(mut self, flags: u64) -> Self {
355 self.flags = flags;
356 self
357 }
358
359 /// Creates a new copy of the message with reversed direction. Typical use case is to re-send messages to create "response"
360 /// in a widget. For example, you have a float input field, and it has a Value message. When the input field receives a Value message
361 /// with [`MessageDirection::ToWidget`] it checks if value needs to be changed and if it does, it re-sends the same message, but with
362 /// reversed direction back to message queue so every "listener" can reach properly. The input field won't react at
363 /// [`MessageDirection::FromWidget`] message so there will be no infinite message loop.
364 #[must_use = "method creates new value which must be used"]
365 pub fn reverse(&self) -> Self {
366 Self {
367 handled: self.handled.clone(),
368 data: self.data.clone_box(),
369 destination: self.destination,
370 direction: self.direction.reverse(),
371 routing_strategy: self.routing_strategy,
372 delivery_mode: self.delivery_mode,
373 flags: self.flags,
374 }
375 }
376
377 /// Checks if the message comes from the specified widget (via [`Self::is_from`]) and the data
378 /// type matches the given type and returns a reference to the data.
379 ///
380 /// ## Example
381 ///
382 /// ```rust
383 /// # use fyrox_core::pool::Handle;
384 /// # use fyrox_ui::message::{MessageDirection, MessageData, UiMessage};
385 /// # use fyrox_ui::UiNode;
386 /// # let widget_handle = Handle::<UiNode>::NONE;
387 /// # #[derive(Debug, Clone, PartialEq)]
388 /// # struct MyMessage;
389 /// # impl MessageData for MyMessage {}
390 /// # let message = UiMessage::with_data(MyMessage);
391 /// if let Some(data) = message.data_from::<MyMessage>(widget_handle) {
392 /// // Do something
393 /// }
394 /// ```
395 ///
396 /// This method call is essentially a shortcut for:
397 ///
398 /// ```rust
399 /// # use fyrox_core::pool::Handle;
400 /// # use fyrox_ui::message::{MessageData, MessageDirection, UiMessage};
401 /// # use fyrox_ui::UiNode;
402 /// # let widget_handle = Handle::<UiNode>::NONE;
403 /// # #[derive(Debug, Clone, PartialEq)]
404 /// # struct MyMessage;
405 /// # impl MessageData for MyMessage {}
406 /// # let message = UiMessage::with_data(MyMessage);
407 /// if message.destination() == widget_handle && message.direction() == MessageDirection::FromWidget {
408 /// if let Some(data) = message.data::<MyMessage>() {
409 /// // Do something
410 /// }
411 /// }
412 /// ```
413 pub fn data_from<T: MessageData>(
414 &self,
415 handle: Handle<impl ObjectOrVariant<UiNode>>,
416 ) -> Option<&T> {
417 if self.is_from(handle) {
418 self.data()
419 } else {
420 None
421 }
422 }
423
424 /// Checks if the message was sent to the specified widget (via [`Self::is_for`]) and the data
425 /// type matches the given type and returns a reference to the data.
426 ///
427 /// ## Example
428 ///
429 /// ```rust
430 /// # use fyrox_core::pool::Handle;
431 /// # use fyrox_ui::message::{MessageDirection, MessageData, UiMessage};
432 /// # use fyrox_ui::UiNode;
433 /// # let widget_handle = Handle::<UiNode>::NONE;
434 /// # #[derive(Debug, Clone, PartialEq)]
435 /// # struct MyMessage;
436 /// # impl MessageData for MyMessage {}
437 /// # let message = UiMessage::with_data(MyMessage);
438 /// if let Some(data) = message.data_for::<MyMessage>(widget_handle) {
439 /// // Do something
440 /// }
441 /// ```
442 ///
443 /// This method call is essentially a shortcut for:
444 ///
445 /// ```rust
446 /// # use fyrox_core::pool::Handle;
447 /// # use fyrox_ui::message::{MessageData, MessageDirection, UiMessage};
448 /// # use fyrox_ui::UiNode;
449 /// # let widget_handle = Handle::<UiNode>::NONE;
450 /// # #[derive(Debug, Clone, PartialEq)]
451 /// # struct MyMessage;
452 /// # impl MessageData for MyMessage {}
453 /// # let message = UiMessage::with_data(MyMessage);
454 /// if message.destination() == widget_handle && message.direction() == MessageDirection::ToWidget {
455 /// if let Some(data) = message.data::<MyMessage>() {
456 /// // Do something
457 /// }
458 /// }
459 /// ```
460 pub fn data_for<T: MessageData>(
461 &self,
462 handle: Handle<impl ObjectOrVariant<UiNode>>,
463 ) -> Option<&T> {
464 if self.is_for(handle) {
465 self.data()
466 } else {
467 None
468 }
469 }
470
471 /// Checks whether the message destination node handle matches the given one and the message
472 /// direction is [`MessageDirection::FromWidget`].
473 pub fn is_from(&self, handle: Handle<impl ObjectOrVariant<UiNode>>) -> bool {
474 self.destination == handle && self.direction == MessageDirection::FromWidget
475 }
476
477 /// Checks whether the message destination node handle matches the given one and the message
478 /// direction is [`MessageDirection::ToWidget`].
479 pub fn is_for(&self, handle: Handle<impl ObjectOrVariant<UiNode>>) -> bool {
480 self.destination == handle && self.direction == MessageDirection::ToWidget
481 }
482
483 /// Returns destination widget handle of the message.
484 pub fn destination(&self) -> Handle<UiNode> {
485 self.destination
486 }
487
488 /// Tries to downcast current data of the message to a particular type.
489 pub fn data<T: MessageData>(&self) -> Option<&T> {
490 (*self.data).as_any().downcast_ref::<T>()
491 }
492
493 /// Sets handled flag.
494 pub fn set_handled(&self, handled: bool) {
495 self.handled.set(handled);
496 }
497
498 /// Returns handled flag.
499 pub fn handled(&self) -> bool {
500 self.handled.get()
501 }
502
503 /// Returns direction of the message.
504 pub fn direction(&self) -> MessageDirection {
505 self.direction
506 }
507
508 /// Returns perform layout flag.
509 pub fn need_perform_layout(&self) -> bool {
510 self.data.need_perform_layout()
511 }
512
513 /// Checks if the message has particular flags.
514 pub fn has_flags(&self, flags: u64) -> bool {
515 self.flags & flags != 0
516 }
517}
518
519/// Mouse button state.
520#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy, Visit, Reflect)]
521pub enum ButtonState {
522 /// Pressed state.
523 Pressed,
524 /// Released state.
525 Released,
526}
527
528/// A set of possible mouse buttons.
529#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy, Default, Visit, Reflect)]
530pub enum MouseButton {
531 /// Left mouse button.
532 #[default]
533 Left,
534 /// Right mouse button.
535 Right,
536 /// Middle mouse button.
537 Middle,
538 /// Back mouse button.
539 Back,
540 /// Forward mouse button.
541 Forward,
542 /// Any other mouse button.
543 Other(u16),
544}
545
546/// A set of possible touch phases
547#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy, Visit, Reflect)]
548pub enum TouchPhase {
549 /// Touch started
550 Started,
551 /// Touch and drag
552 Moved,
553 /// Touch ended
554 Ended,
555 /// Touch cancelled
556 Cancelled,
557}
558
559/// Describes the force of a touch event
560#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy, Visit, Reflect)]
561pub enum Force {
562 /// On iOS, the force is calibrated so that the same number corresponds to
563 /// roughly the same amount of pressure on the screen regardless of the
564 /// device.
565 Calibrated {
566 /// The force of the touch, where a value of 1.0 represents the force of
567 /// an average touch (predetermined by the system, not user-specific).
568 ///
569 /// The force reported by Apple Pencil is measured along the axis of the
570 /// pencil. If you want a force perpendicular to the device, you need to
571 /// calculate this value using the `altitude_angle` value.
572 force: [u8; 8],
573 /// The maximum possible force for a touch.
574 ///
575 /// The value of this field is sufficiently high to provide a wide
576 /// dynamic range for values of the `force` field.
577 max_possible_force: [u8; 8],
578 /// The altitude (in radians) of the stylus.
579 ///
580 /// A value of 0 radians indicates that the stylus is parallel to the
581 /// surface. The value of this property is Pi/2 when the stylus is
582 /// perpendicular to the surface.
583 altitude_angle: Option<[u8; 8]>,
584 },
585 /// If the platform reports the force as normalized, we have no way of
586 /// knowing how much pressure 1.0 corresponds to – we know it's the maximum
587 /// amount of force, but as to how much force, you might either have to
588 /// press really, really hard, or not hard at all, depending on the device.
589 Normalized([u8; 8]),
590}
591
592impl Force {
593 /// Returns the force normalized to the range between 0.0 and 1.0 inclusive.
594 ///
595 /// Instead of normalizing the force, you should prefer to handle
596 /// [`Force::Calibrated`] so that the amount of force the user has to apply is
597 /// consistent across devices.
598 pub fn normalized(&self) -> f64 {
599 match self {
600 Force::Calibrated {
601 force,
602 max_possible_force,
603 altitude_angle,
604 } => {
605 let force = match altitude_angle {
606 Some(altitude_angle) => {
607 f64::from_be_bytes(*force) / f64::from_be_bytes(*altitude_angle).sin()
608 }
609 None => f64::from_be_bytes(*force),
610 };
611 force / f64::from_be_bytes(*max_possible_force)
612 }
613 Force::Normalized(force) => f64::from_be_bytes(*force),
614 }
615 }
616}
617
618/// An event that an OS sends to a window, that is then can be used to "feed" the user interface so it can do some actions.
619#[derive(Debug)]
620pub enum OsEvent {
621 /// Mouse input event.
622 MouseInput {
623 /// Mouse button.
624 button: MouseButton,
625 /// Mouse button state.
626 state: ButtonState,
627 },
628 /// Cursor event.
629 CursorMoved {
630 /// New position of the cursor.
631 position: Vector2<f32>,
632 },
633 /// Keyboard input event.
634 KeyboardInput {
635 /// Code of a key.
636 button: KeyCode,
637 /// Key state.
638 state: ButtonState,
639 /// Text of the key.
640 text: String,
641 },
642 /// Keyboard modifier event (used for key combinations such as Ctrl+A, Ctrl+C, etc).
643 KeyboardModifiers(KeyboardModifiers),
644 /// Mouse wheel event, with a tuple that stores the (x, y) offsets.
645 MouseWheel(f32, f32),
646 /// Touch event.
647 Touch {
648 /// Phase of the touch event
649 phase: TouchPhase,
650 /// Screen location of touch event
651 location: Vector2<f32>,
652 /// Pressure exerted during force event
653 force: Option<Force>,
654 /// Unique touch event identifier to distinguish between fingers, for example
655 id: u64,
656 },
657}
658
659/// A set of possible keyboard modifiers.
660#[derive(
661 Debug,
662 Hash,
663 Ord,
664 PartialOrd,
665 PartialEq,
666 Eq,
667 Clone,
668 Copy,
669 Default,
670 Serialize,
671 Deserialize,
672 Reflect,
673 Visit,
674)]
675pub struct KeyboardModifiers {
676 /// `Alt` key is pressed.
677 pub alt: bool,
678 /// `Shift` key is pressed.
679 pub shift: bool,
680 /// `Ctrl` key is pressed.
681 pub control: bool,
682 /// `System` key is pressed.
683 pub system: bool,
684}
685
686impl KeyboardModifiers {
687 /// Checks if the modifiers is empty (nothing is pressed).
688 pub fn is_none(self) -> bool {
689 !self.shift && !self.control && !self.alt && !self.system
690 }
691}
692
693/// Code of a key on keyboard. Shamelessly taken from `winit` source code to match their key codes with
694/// `fyrox-ui`'s.
695#[derive(
696 Debug,
697 Hash,
698 Ord,
699 PartialOrd,
700 PartialEq,
701 Eq,
702 Clone,
703 Copy,
704 AsRefStr,
705 EnumString,
706 VariantNames,
707 Serialize,
708 Deserialize,
709 Reflect,
710 Visit,
711 Default,
712)]
713#[repr(u32)]
714#[allow(missing_docs)]
715pub enum KeyCode {
716 /// This variant is used when the key cannot be translated to any other variant.
717 #[default]
718 Unknown,
719 /// <kbd>`</kbd> on a US keyboard. This is also called a backtick or grave.
720 /// This is the <kbd>半角</kbd>/<kbd>全角</kbd>/<kbd>漢字</kbd>
721 /// (hankaku/zenkaku/kanji) key on Japanese keyboards
722 Backquote,
723 /// Used for both the US <kbd>\\</kbd> (on the 101-key layout) and also for the key
724 /// located between the <kbd>"</kbd> and <kbd>Enter</kbd> keys on row C of the 102-,
725 /// 104- and 106-key layouts.
726 /// Labeled <kbd>#</kbd> on a UK (102) keyboard.
727 Backslash,
728 /// <kbd>[</kbd> on a US keyboard.
729 BracketLeft,
730 /// <kbd>]</kbd> on a US keyboard.
731 BracketRight,
732 /// <kbd>,</kbd> on a US keyboard.
733 Comma,
734 /// <kbd>0</kbd> on a US keyboard.
735 Digit0,
736 /// <kbd>1</kbd> on a US keyboard.
737 Digit1,
738 /// <kbd>2</kbd> on a US keyboard.
739 Digit2,
740 /// <kbd>3</kbd> on a US keyboard.
741 Digit3,
742 /// <kbd>4</kbd> on a US keyboard.
743 Digit4,
744 /// <kbd>5</kbd> on a US keyboard.
745 Digit5,
746 /// <kbd>6</kbd> on a US keyboard.
747 Digit6,
748 /// <kbd>7</kbd> on a US keyboard.
749 Digit7,
750 /// <kbd>8</kbd> on a US keyboard.
751 Digit8,
752 /// <kbd>9</kbd> on a US keyboard.
753 Digit9,
754 /// <kbd>=</kbd> on a US keyboard.
755 Equal,
756 /// Located between the left <kbd>Shift</kbd> and <kbd>Z</kbd> keys.
757 /// Labeled <kbd>\\</kbd> on a UK keyboard.
758 IntlBackslash,
759 /// Located between the <kbd>/</kbd> and right <kbd>Shift</kbd> keys.
760 /// Labeled <kbd>\\</kbd> (ro) on a Japanese keyboard.
761 IntlRo,
762 /// Located between the <kbd>=</kbd> and <kbd>Backspace</kbd> keys.
763 /// Labeled <kbd>¥</kbd> (yen) on a Japanese keyboard. <kbd>\\</kbd> on a
764 /// Russian keyboard.
765 IntlYen,
766 /// <kbd>a</kbd> on a US keyboard.
767 /// Labeled <kbd>q</kbd> on an AZERTY (e.g., French) keyboard.
768 KeyA,
769 /// <kbd>b</kbd> on a US keyboard.
770 KeyB,
771 /// <kbd>c</kbd> on a US keyboard.
772 KeyC,
773 /// <kbd>d</kbd> on a US keyboard.
774 KeyD,
775 /// <kbd>e</kbd> on a US keyboard.
776 KeyE,
777 /// <kbd>f</kbd> on a US keyboard.
778 KeyF,
779 /// <kbd>g</kbd> on a US keyboard.
780 KeyG,
781 /// <kbd>h</kbd> on a US keyboard.
782 KeyH,
783 /// <kbd>i</kbd> on a US keyboard.
784 KeyI,
785 /// <kbd>j</kbd> on a US keyboard.
786 KeyJ,
787 /// <kbd>k</kbd> on a US keyboard.
788 KeyK,
789 /// <kbd>l</kbd> on a US keyboard.
790 KeyL,
791 /// <kbd>m</kbd> on a US keyboard.
792 KeyM,
793 /// <kbd>n</kbd> on a US keyboard.
794 KeyN,
795 /// <kbd>o</kbd> on a US keyboard.
796 KeyO,
797 /// <kbd>p</kbd> on a US keyboard.
798 KeyP,
799 /// <kbd>q</kbd> on a US keyboard.
800 /// Labeled <kbd>a</kbd> on an AZERTY (e.g., French) keyboard.
801 KeyQ,
802 /// <kbd>r</kbd> on a US keyboard.
803 KeyR,
804 /// <kbd>s</kbd> on a US keyboard.
805 KeyS,
806 /// <kbd>t</kbd> on a US keyboard.
807 KeyT,
808 /// <kbd>u</kbd> on a US keyboard.
809 KeyU,
810 /// <kbd>v</kbd> on a US keyboard.
811 KeyV,
812 /// <kbd>w</kbd> on a US keyboard.
813 /// Labeled <kbd>z</kbd> on an AZERTY (e.g., French) keyboard.
814 KeyW,
815 /// <kbd>x</kbd> on a US keyboard.
816 KeyX,
817 /// <kbd>y</kbd> on a US keyboard.
818 /// Labeled <kbd>z</kbd> on a QWERTZ (e.g., German) keyboard.
819 KeyY,
820 /// <kbd>z</kbd> on a US keyboard.
821 /// Labeled <kbd>w</kbd> on an AZERTY (e.g., French) keyboard, and <kbd>y</kbd> on a
822 /// QWERTZ (e.g., German) keyboard.
823 KeyZ,
824 /// <kbd>-</kbd> on a US keyboard.
825 Minus,
826 /// <kbd>.</kbd> on a US keyboard.
827 Period,
828 /// <kbd>'</kbd> on a US keyboard.
829 Quote,
830 /// <kbd>;</kbd> on a US keyboard.
831 Semicolon,
832 /// <kbd>/</kbd> on a US keyboard.
833 Slash,
834 /// <kbd>Alt</kbd>, <kbd>Option</kbd>, or <kbd>⌥</kbd>.
835 AltLeft,
836 /// <kbd>Alt</kbd>, <kbd>Option</kbd>, or <kbd>⌥</kbd>.
837 /// This is labeled <kbd>AltGr</kbd> on many keyboard layouts.
838 AltRight,
839 /// <kbd>Backspace</kbd> or <kbd>⌫</kbd>.
840 /// Labeled <kbd>Delete</kbd> on Apple keyboards.
841 Backspace,
842 /// <kbd>CapsLock</kbd> or <kbd>⇪</kbd>
843 CapsLock,
844 /// The application context menu key, which is typically found between the right
845 /// <kbd>Super</kbd> key and the right <kbd>Control</kbd> key.
846 ContextMenu,
847 /// <kbd>Control</kbd> or <kbd>⌃</kbd>
848 ControlLeft,
849 /// <kbd>Control</kbd> or <kbd>⌃</kbd>
850 ControlRight,
851 /// <kbd>Enter</kbd> or <kbd>↵</kbd>. Labeled <kbd>Return</kbd> on Apple keyboards.
852 Enter,
853 /// The Windows, <kbd>⌘</kbd>, <kbd>Command</kbd>, or other OS symbol key.
854 SuperLeft,
855 /// The Windows, <kbd>⌘</kbd>, <kbd>Command</kbd>, or other OS symbol key.
856 SuperRight,
857 /// <kbd>Shift</kbd> or <kbd>⇧</kbd>
858 ShiftLeft,
859 /// <kbd>Shift</kbd> or <kbd>⇧</kbd>
860 ShiftRight,
861 /// <kbd> </kbd> (space)
862 Space,
863 /// <kbd>Tab</kbd> or <kbd>⇥</kbd>
864 Tab,
865 /// Japanese: <kbd>変</kbd> (henkan)
866 Convert,
867 /// Japanese: <kbd>カタカナ</kbd>/<kbd>ひらがな</kbd>/<kbd>ローマ字</kbd> (katakana/hiragana/romaji)
868 KanaMode,
869 /// Korean: HangulMode <kbd>한/영</kbd> (han/yeong)
870 ///
871 /// Japanese (Mac keyboard): <kbd>か</kbd> (kana)
872 Lang1,
873 /// Korean: Hanja <kbd>한</kbd> (hanja)
874 ///
875 /// Japanese (Mac keyboard): <kbd>英</kbd> (eisu)
876 Lang2,
877 /// Japanese (word-processing keyboard): Katakana
878 Lang3,
879 /// Japanese (word-processing keyboard): Hiragana
880 Lang4,
881 /// Japanese (word-processing keyboard): Zenkaku/Hankaku
882 Lang5,
883 /// Japanese: <kbd>無変換</kbd> (muhenkan)
884 NonConvert,
885 /// <kbd>⌦</kbd>. The forward delete key.
886 /// Note that on Apple keyboards, the key labelled <kbd>Delete</kbd> on the main part of
887 /// the keyboard is encoded as [`Backspace`].
888 ///
889 /// [`Backspace`]: Self::Backspace
890 Delete,
891 /// <kbd>Page Down</kbd>, <kbd>End</kbd>, or <kbd>↘</kbd>
892 End,
893 /// <kbd>Help</kbd>. Not present on standard PC keyboards.
894 Help,
895 /// <kbd>Home</kbd> or <kbd>↖</kbd>
896 Home,
897 /// <kbd>Insert</kbd> or <kbd>Ins</kbd>. Not present on Apple keyboards.
898 Insert,
899 /// <kbd>Page Down</kbd>, <kbd>PgDn</kbd>, or <kbd>⇟</kbd>
900 PageDown,
901 /// <kbd>Page Up</kbd>, <kbd>PgUp</kbd>, or <kbd>⇞</kbd>
902 PageUp,
903 /// <kbd>↓</kbd>
904 ArrowDown,
905 /// <kbd>←</kbd>
906 ArrowLeft,
907 /// <kbd>→</kbd>
908 ArrowRight,
909 /// <kbd>↑</kbd>
910 ArrowUp,
911 /// On the Mac, this is used for the numpad <kbd>Clear</kbd> key.
912 NumLock,
913 /// <kbd>0 Ins</kbd> on a keyboard. <kbd>0</kbd> on a phone or remote control
914 Numpad0,
915 /// <kbd>1 End</kbd> on a keyboard. <kbd>1</kbd> or <kbd>1 QZ</kbd> on a phone or remote control
916 Numpad1,
917 /// <kbd>2 ↓</kbd> on a keyboard. <kbd>2 ABC</kbd> on a phone or remote control
918 Numpad2,
919 /// <kbd>3 PgDn</kbd> on a keyboard. <kbd>3 DEF</kbd> on a phone or remote control
920 Numpad3,
921 /// <kbd>4 ←</kbd> on a keyboard. <kbd>4 GHI</kbd> on a phone or remote control
922 Numpad4,
923 /// <kbd>5</kbd> on a keyboard. <kbd>5 JKL</kbd> on a phone or remote control
924 Numpad5,
925 /// <kbd>6 →</kbd> on a keyboard. <kbd>6 MNO</kbd> on a phone or remote control
926 Numpad6,
927 /// <kbd>7 Home</kbd> on a keyboard. <kbd>7 PQRS</kbd> or <kbd>7 PRS</kbd> on a phone
928 /// or remote control
929 Numpad7,
930 /// <kbd>8 ↑</kbd> on a keyboard. <kbd>8 TUV</kbd> on a phone or remote control
931 Numpad8,
932 /// <kbd>9 PgUp</kbd> on a keyboard. <kbd>9 WXYZ</kbd> or <kbd>9 WXY</kbd> on a phone
933 /// or remote control
934 Numpad9,
935 /// <kbd>+</kbd>
936 NumpadAdd,
937 /// Found on the Microsoft Natural Keyboard.
938 NumpadBackspace,
939 /// <kbd>C</kbd> or <kbd>A</kbd> (All Clear). Also for use with numpads that have a
940 /// <kbd>Clear</kbd> key that is separate from the <kbd>NumLock</kbd> key. On the Mac, the
941 /// numpad <kbd>Clear</kbd> key is encoded as [`NumLock`].
942 ///
943 /// [`NumLock`]: Self::NumLock
944 NumpadClear,
945 /// <kbd>C</kbd> (Clear Entry)
946 NumpadClearEntry,
947 /// <kbd>,</kbd> (thousands separator). For locales where the thousands separator
948 /// is a "." (e.g., Brazil), this key may generate a <kbd>.</kbd>.
949 NumpadComma,
950 /// <kbd>. Del</kbd>. For locales where the decimal separator is "," (e.g.,
951 /// Brazil), this key may generate a <kbd>,</kbd>.
952 NumpadDecimal,
953 /// <kbd>/</kbd>
954 NumpadDivide,
955 NumpadEnter,
956 /// <kbd>=</kbd>
957 NumpadEqual,
958 /// <kbd>#</kbd> on a phone or remote control device. This key is typically found
959 /// below the <kbd>9</kbd> key and to the right of the <kbd>0</kbd> key.
960 NumpadHash,
961 /// <kbd>M</kbd> Add current entry to the value stored in memory.
962 NumpadMemoryAdd,
963 /// <kbd>M</kbd> Clear the value stored in memory.
964 NumpadMemoryClear,
965 /// <kbd>M</kbd> Replace the current entry with the value stored in memory.
966 NumpadMemoryRecall,
967 /// <kbd>M</kbd> Replace the value stored in memory with the current entry.
968 NumpadMemoryStore,
969 /// <kbd>M</kbd> Subtract current entry from the value stored in memory.
970 NumpadMemorySubtract,
971 /// <kbd>*</kbd> on a keyboard. For use with numpads that provide mathematical
972 /// operations (<kbd>+</kbd>, <kbd>-</kbd> <kbd>*</kbd> and <kbd>/</kbd>).
973 ///
974 /// Use `NumpadStar` for the <kbd>*</kbd> key on phones and remote controls.
975 NumpadMultiply,
976 /// <kbd>(</kbd> Found on the Microsoft Natural Keyboard.
977 NumpadParenLeft,
978 /// <kbd>)</kbd> Found on the Microsoft Natural Keyboard.
979 NumpadParenRight,
980 /// <kbd>*</kbd> on a phone or remote control device.
981 ///
982 /// This key is typically found below the <kbd>7</kbd> key and to the left of
983 /// the <kbd>0</kbd> key.
984 ///
985 /// Use <kbd>"NumpadMultiply"</kbd> for the <kbd>*</kbd> key on
986 /// numeric keypads.
987 NumpadStar,
988 /// <kbd>-</kbd>
989 NumpadSubtract,
990 /// <kbd>Esc</kbd> or <kbd>⎋</kbd>
991 Escape,
992 /// <kbd>Fn</kbd> This is typically a hardware key that does not generate a separate code.
993 Fn,
994 /// <kbd>FLock</kbd> or <kbd>FnLock</kbd>. Function Lock key. Found on the Microsoft
995 /// Natural Keyboard.
996 FnLock,
997 /// <kbd>PrtScr SysRq</kbd> or <kbd>Print Screen</kbd>
998 PrintScreen,
999 /// <kbd>Scroll Lock</kbd>
1000 ScrollLock,
1001 /// <kbd>Pause Break</kbd>
1002 Pause,
1003 /// Some laptops place this key to the left of the <kbd>↑</kbd> key.
1004 ///
1005 /// This also the "back" button (triangle) on Android.
1006 BrowserBack,
1007 BrowserFavorites,
1008 /// Some laptops place this key to the right of the <kbd>↑</kbd> key.
1009 BrowserForward,
1010 /// The "home" button on Android.
1011 BrowserHome,
1012 BrowserRefresh,
1013 BrowserSearch,
1014 BrowserStop,
1015 /// <kbd>Eject</kbd> or <kbd>⏏</kbd>. This key is placed in the function section on some Apple
1016 /// keyboards.
1017 Eject,
1018 /// Sometimes labelled <kbd>My Computer</kbd> on the keyboard
1019 LaunchApp1,
1020 /// Sometimes labelled <kbd>Calculator</kbd> on the keyboard
1021 LaunchApp2,
1022 LaunchMail,
1023 MediaPlayPause,
1024 MediaSelect,
1025 MediaStop,
1026 MediaTrackNext,
1027 MediaTrackPrevious,
1028 /// This key is placed in the function section on some Apple keyboards, replacing the
1029 /// <kbd>Eject</kbd> key.
1030 Power,
1031 Sleep,
1032 AudioVolumeDown,
1033 AudioVolumeMute,
1034 AudioVolumeUp,
1035 WakeUp,
1036 // Legacy modifier key. Also called "Super" in certain places.
1037 Meta,
1038 // Legacy modifier key.
1039 Hyper,
1040 Turbo,
1041 Abort,
1042 Resume,
1043 Suspend,
1044 /// Found on Sun’s USB keyboard.
1045 Again,
1046 /// Found on Sun’s USB keyboard.
1047 Copy,
1048 /// Found on Sun’s USB keyboard.
1049 Cut,
1050 /// Found on Sun’s USB keyboard.
1051 Find,
1052 /// Found on Sun’s USB keyboard.
1053 Open,
1054 /// Found on Sun’s USB keyboard.
1055 Paste,
1056 /// Found on Sun’s USB keyboard.
1057 Props,
1058 /// Found on Sun’s USB keyboard.
1059 Select,
1060 /// Found on Sun’s USB keyboard.
1061 Undo,
1062 /// Use for dedicated <kbd>ひらがな</kbd> key found on some Japanese word processing keyboards.
1063 Hiragana,
1064 /// Use for dedicated <kbd>カタカナ</kbd> key found on some Japanese word processing keyboards.
1065 Katakana,
1066 /// General-purpose function key.
1067 /// Usually found at the top of the keyboard.
1068 F1,
1069 /// General-purpose function key.
1070 /// Usually found at the top of the keyboard.
1071 F2,
1072 /// General-purpose function key.
1073 /// Usually found at the top of the keyboard.
1074 F3,
1075 /// General-purpose function key.
1076 /// Usually found at the top of the keyboard.
1077 F4,
1078 /// General-purpose function key.
1079 /// Usually found at the top of the keyboard.
1080 F5,
1081 /// General-purpose function key.
1082 /// Usually found at the top of the keyboard.
1083 F6,
1084 /// General-purpose function key.
1085 /// Usually found at the top of the keyboard.
1086 F7,
1087 /// General-purpose function key.
1088 /// Usually found at the top of the keyboard.
1089 F8,
1090 /// General-purpose function key.
1091 /// Usually found at the top of the keyboard.
1092 F9,
1093 /// General-purpose function key.
1094 /// Usually found at the top of the keyboard.
1095 F10,
1096 /// General-purpose function key.
1097 /// Usually found at the top of the keyboard.
1098 F11,
1099 /// General-purpose function key.
1100 /// Usually found at the top of the keyboard.
1101 F12,
1102 /// General-purpose function key.
1103 /// Usually found at the top of the keyboard.
1104 F13,
1105 /// General-purpose function key.
1106 /// Usually found at the top of the keyboard.
1107 F14,
1108 /// General-purpose function key.
1109 /// Usually found at the top of the keyboard.
1110 F15,
1111 /// General-purpose function key.
1112 /// Usually found at the top of the keyboard.
1113 F16,
1114 /// General-purpose function key.
1115 /// Usually found at the top of the keyboard.
1116 F17,
1117 /// General-purpose function key.
1118 /// Usually found at the top of the keyboard.
1119 F18,
1120 /// General-purpose function key.
1121 /// Usually found at the top of the keyboard.
1122 F19,
1123 /// General-purpose function key.
1124 /// Usually found at the top of the keyboard.
1125 F20,
1126 /// General-purpose function key.
1127 /// Usually found at the top of the keyboard.
1128 F21,
1129 /// General-purpose function key.
1130 /// Usually found at the top of the keyboard.
1131 F22,
1132 /// General-purpose function key.
1133 /// Usually found at the top of the keyboard.
1134 F23,
1135 /// General-purpose function key.
1136 /// Usually found at the top of the keyboard.
1137 F24,
1138 /// General-purpose function key.
1139 F25,
1140 /// General-purpose function key.
1141 F26,
1142 /// General-purpose function key.
1143 F27,
1144 /// General-purpose function key.
1145 F28,
1146 /// General-purpose function key.
1147 F29,
1148 /// General-purpose function key.
1149 F30,
1150 /// General-purpose function key.
1151 F31,
1152 /// General-purpose function key.
1153 F32,
1154 /// General-purpose function key.
1155 F33,
1156 /// General-purpose function key.
1157 F34,
1158 /// General-purpose function key.
1159 F35,
1160}
1161
1162impl KeyCode {
1163 /// Attempts to convert the key code to its respective character.
1164 pub fn to_char(self) -> Option<char> {
1165 match self {
1166 KeyCode::Backquote => Some('`'),
1167 KeyCode::Backslash => Some('\\'),
1168 KeyCode::BracketLeft => Some('['),
1169 KeyCode::BracketRight => Some(']'),
1170 KeyCode::Comma => Some(','),
1171 KeyCode::Digit0 => Some('0'),
1172 KeyCode::Digit1 => Some('1'),
1173 KeyCode::Digit2 => Some('2'),
1174 KeyCode::Digit3 => Some('3'),
1175 KeyCode::Digit4 => Some('4'),
1176 KeyCode::Digit5 => Some('5'),
1177 KeyCode::Digit6 => Some('6'),
1178 KeyCode::Digit7 => Some('7'),
1179 KeyCode::Digit8 => Some('8'),
1180 KeyCode::Digit9 => Some('9'),
1181 KeyCode::Equal => Some('='),
1182 KeyCode::KeyA => Some('A'),
1183 KeyCode::KeyB => Some('B'),
1184 KeyCode::KeyC => Some('C'),
1185 KeyCode::KeyD => Some('D'),
1186 KeyCode::KeyE => Some('E'),
1187 KeyCode::KeyF => Some('F'),
1188 KeyCode::KeyG => Some('G'),
1189 KeyCode::KeyH => Some('H'),
1190 KeyCode::KeyI => Some('I'),
1191 KeyCode::KeyJ => Some('J'),
1192 KeyCode::KeyK => Some('K'),
1193 KeyCode::KeyL => Some('L'),
1194 KeyCode::KeyM => Some('M'),
1195 KeyCode::KeyN => Some('N'),
1196 KeyCode::KeyO => Some('O'),
1197 KeyCode::KeyP => Some('P'),
1198 KeyCode::KeyQ => Some('Q'),
1199 KeyCode::KeyR => Some('R'),
1200 KeyCode::KeyS => Some('S'),
1201 KeyCode::KeyT => Some('T'),
1202 KeyCode::KeyU => Some('U'),
1203 KeyCode::KeyV => Some('V'),
1204 KeyCode::KeyW => Some('W'),
1205 KeyCode::KeyX => Some('X'),
1206 KeyCode::KeyY => Some('Y'),
1207 KeyCode::KeyZ => Some('Z'),
1208 KeyCode::Minus => Some('-'),
1209 KeyCode::Period => Some('.'),
1210 KeyCode::Quote => Some('\''),
1211 KeyCode::Semicolon => Some(';'),
1212 KeyCode::Slash => Some('/'),
1213 KeyCode::Enter => Some('\n'),
1214 KeyCode::Space => Some(' '),
1215 KeyCode::Tab => Some('\t'),
1216 KeyCode::Numpad0 => Some('0'),
1217 KeyCode::Numpad1 => Some('1'),
1218 KeyCode::Numpad2 => Some('2'),
1219 KeyCode::Numpad3 => Some('3'),
1220 KeyCode::Numpad4 => Some('4'),
1221 KeyCode::Numpad5 => Some('5'),
1222 KeyCode::Numpad6 => Some('6'),
1223 KeyCode::Numpad7 => Some('7'),
1224 KeyCode::Numpad8 => Some('8'),
1225 KeyCode::Numpad9 => Some('9'),
1226 KeyCode::NumpadAdd => Some('+'),
1227 KeyCode::NumpadComma => Some('.'),
1228 KeyCode::NumpadDecimal => Some(','),
1229 KeyCode::NumpadDivide => Some('/'),
1230 KeyCode::NumpadEnter => Some('\n'),
1231 KeyCode::NumpadEqual => Some('='),
1232 KeyCode::NumpadHash => Some('#'),
1233 KeyCode::NumpadMultiply => Some('*'),
1234 KeyCode::NumpadParenLeft => Some('('),
1235 KeyCode::NumpadParenRight => Some(')'),
1236 KeyCode::NumpadStar => Some('*'),
1237 KeyCode::NumpadSubtract => Some('-'),
1238 _ => None,
1239 }
1240 }
1241}
1242
1243impl TryFrom<char> for KeyCode {
1244 type Error = &'static str;
1245
1246 fn try_from(value: char) -> Result<Self, Self::Error> {
1247 match value {
1248 '-' | '_' => Ok(Self::Minus),
1249 '+' | '=' => Ok(Self::NumpadAdd),
1250 ' ' => Ok(Self::Space),
1251 '\\' | '|' => Ok(Self::Backslash),
1252 '/' | '?' => Ok(Self::Slash),
1253 '.' | '>' => Ok(Self::Period),
1254 ',' | '<' => Ok(Self::Comma),
1255 '\'' | '"' => Ok(Self::Quote),
1256 ';' | ':' => Ok(Self::Semicolon),
1257 '`' | '~' => Ok(Self::Backquote),
1258 '0' | ')' => Ok(Self::Digit0),
1259 '1' | '!' => Ok(Self::Digit1),
1260 '2' | '@' => Ok(Self::Digit2),
1261 '3' | '#' => Ok(Self::Digit3),
1262 '4' | '$' => Ok(Self::Digit4),
1263 '5' | '%' => Ok(Self::Digit5),
1264 '6' | '^' => Ok(Self::Digit6),
1265 '7' | '&' => Ok(Self::Digit7),
1266 '8' | '*' => Ok(Self::Digit8),
1267 '9' | '(' => Ok(Self::Digit9),
1268 'a' | 'A' => Ok(Self::KeyA),
1269 'b' | 'B' => Ok(Self::KeyB),
1270 'c' | 'C' => Ok(Self::KeyC),
1271 'd' | 'D' => Ok(Self::KeyD),
1272 'e' | 'E' => Ok(Self::KeyE),
1273 'f' | 'F' => Ok(Self::KeyF),
1274 'g' | 'G' => Ok(Self::KeyG),
1275 'h' | 'H' => Ok(Self::KeyH),
1276 'i' | 'I' => Ok(Self::KeyI),
1277 'j' | 'J' => Ok(Self::KeyJ),
1278 'k' | 'K' => Ok(Self::KeyK),
1279 'l' | 'L' => Ok(Self::KeyL),
1280 'm' | 'M' => Ok(Self::KeyM),
1281 'n' | 'N' => Ok(Self::KeyN),
1282 'o' | 'O' => Ok(Self::KeyO),
1283 'p' | 'P' => Ok(Self::KeyP),
1284 'q' | 'Q' => Ok(Self::KeyQ),
1285 'r' | 'R' => Ok(Self::KeyR),
1286 's' | 'S' => Ok(Self::KeyS),
1287 't' | 'T' => Ok(Self::KeyT),
1288 'u' | 'U' => Ok(Self::KeyU),
1289 'v' | 'V' => Ok(Self::KeyV),
1290 'w' | 'W' => Ok(Self::KeyW),
1291 'x' | 'X' => Ok(Self::KeyX),
1292 'y' | 'Y' => Ok(Self::KeyY),
1293 'z' | 'Z' => Ok(Self::KeyZ),
1294 '[' | '{' => Ok(Self::BracketLeft),
1295 ']' | '}' => Ok(Self::BracketRight),
1296 _ => Err("unsupported"),
1297 }
1298 }
1299}
1300
1301/// A fixed set of cursor icons that available on most OSes.
1302#[derive(
1303 Debug,
1304 Copy,
1305 Clone,
1306 PartialEq,
1307 Eq,
1308 Hash,
1309 Default,
1310 Visit,
1311 Reflect,
1312 AsRefStr,
1313 EnumString,
1314 VariantNames,
1315)]
1316pub enum CursorIcon {
1317 /// The platform-dependent default cursor. Often rendered as arrow.
1318 #[default]
1319 Default,
1320
1321 /// A context menu is available for the object under the cursor. Often
1322 /// rendered as an arrow with a small menu-like graphic next to it.
1323 ContextMenu,
1324
1325 /// Help is available for the object under the cursor. Often rendered as a
1326 /// question mark or a balloon.
1327 Help,
1328
1329 /// The cursor is a pointer that indicates a link. Often rendered as the
1330 /// backside of a hand with the index finger extended.
1331 Pointer,
1332
1333 /// A progress indicator. The program is performing some processing, but is
1334 /// different from [`CursorIcon::Wait`] in that the user may still interact
1335 /// with the program.
1336 Progress,
1337
1338 /// Indicates that the program is busy and the user should wait. Often
1339 /// rendered as a watch or hourglass.
1340 Wait,
1341
1342 /// Indicates that a cell or set of cells may be selected. Often rendered as
1343 /// a thick plus-sign with a dot in the middle.
1344 Cell,
1345
1346 /// A simple crosshair (e.g., short line segments resembling a "+" sign).
1347 /// Often used to indicate a two-dimensional bitmap selection mode.
1348 Crosshair,
1349
1350 /// Indicates text that may be selected. Often rendered as an I-beam.
1351 Text,
1352
1353 /// Indicates vertical-text that may be selected. Often rendered as a
1354 /// horizontal I-beam.
1355 VerticalText,
1356
1357 /// Indicates an alias of/shortcut to something is to be created. Often
1358 /// rendered as an arrow with a small curved arrow next to it.
1359 Alias,
1360
1361 /// Indicates something is to be copied. Often rendered as an arrow with a
1362 /// small plus sign next to it.
1363 Copy,
1364
1365 /// Indicates something is to be moved.
1366 Move,
1367
1368 /// Indicates that the dragged item cannot be dropped at the current cursor
1369 /// location. Often rendered as a hand or pointer with a small circle with a
1370 /// line through it.
1371 NoDrop,
1372
1373 /// Indicates that the requested action will not be carried out. Often
1374 /// rendered as a circle with a line through it.
1375 NotAllowed,
1376
1377 /// Indicates that something can be grabbed (dragged to be moved). Often
1378 /// rendered as the backside of an open hand.
1379 Grab,
1380
1381 /// Indicates that something is being grabbed (dragged to be moved). Often
1382 /// rendered as the backside of a hand with fingers closed mostly out of
1383 /// view.
1384 Grabbing,
1385
1386 /// The east border to be moved.
1387 EResize,
1388
1389 /// The north border to be moved.
1390 NResize,
1391
1392 /// The north-east corner to be moved.
1393 NeResize,
1394
1395 /// The north-west corner to be moved.
1396 NwResize,
1397
1398 /// The south border to be moved.
1399 SResize,
1400
1401 /// The south-east corner to be moved.
1402 SeResize,
1403
1404 /// The south-west corner to be moved.
1405 SwResize,
1406
1407 /// The west border to be moved.
1408 WResize,
1409
1410 /// The east and west borders to be moved.
1411 EwResize,
1412
1413 /// The south and north borders to be moved.
1414 NsResize,
1415
1416 /// The north-east and south-west corners to be moved.
1417 NeswResize,
1418
1419 /// The north-west and south-east corners to be moved.
1420 NwseResize,
1421
1422 /// Indicates that the item/column can be resized horizontally. Often
1423 /// rendered as arrows pointing left and right with a vertical bar
1424 /// separating them.
1425 ColResize,
1426
1427 /// Indicates that the item/row can be resized vertically. Often rendered as
1428 /// arrows pointing up and down with a horizontal bar separating them.
1429 RowResize,
1430
1431 /// Indicates that the something can be scrolled in any direction. Often
1432 /// rendered as arrows pointing up, down, left, and right with a dot in the
1433 /// middle.
1434 AllScroll,
1435
1436 /// Indicates that something can be zoomed in. Often rendered as a
1437 /// magnifying glass with a "+" in the center of the glass.
1438 ZoomIn,
1439
1440 /// Indicates that something can be zoomed in. Often rendered as a
1441 /// magnifying glass with a "-" in the center of the glass.
1442 ZoomOut,
1443}
1444
1445uuid_provider!(CursorIcon = "da7f3a5f-9d26-460a-8e46-38da25f8a8db");