Skip to main content

appcui/ui/keyselector/
keyselector.rs

1use crate::prelude::*;
2use crate::ui::keyselector::{events::EventData, Flags};
3
4#[CustomControl(overwrite=OnPaint+OnKeyPressed+OnMouseEvent, internal=true)]
5pub struct KeySelector {
6    flags: Flags,
7    key: Key,
8}
9impl KeySelector {
10
11    /// Creates a new KeySelector object with the specified key, layout and flags.
12    /// The flags can be a combination of the following values:
13    /// * `keyselector::Flags::AcceptEnter` - if set, the Enter key will be accepted
14    /// * `keyselector::Flags::AcceptEscape` - if set, the Escape key will be accepted
15    /// * `keyselector::Flags::AcceptTab` - if set, the Tab key will be accepted
16    /// * `keyselector::Flags::ReadOnly` - if set, the KeySelector will be read-only and will not accept any key
17    /// 
18    /// # Example
19    /// ```rust, no_run
20    /// use appcui::prelude::*;
21    /// 
22    /// let mut keyselector = KeySelector::new(Key::from(KeyCode::F1), 
23    ///                                        layout!("x:1,y:1,w:30"), 
24    ///                                        keyselector::Flags::AcceptEnter | 
25    ///                                        keyselector::Flags::AcceptEscape);
26    /// ```
27    pub fn new(key: Key, layout: Layout, flags: Flags) -> Self {
28        let mut obj = Self {
29            base: ControlBase::with_status_flags(layout, StatusFlags::Visible | StatusFlags::Enabled | StatusFlags::AcceptInput),
30            flags,
31            key,
32        };
33        obj.set_size_bounds(5, 1, u16::MAX, 1);
34        obj
35    }
36
37    /// Returns the current key selected by the KeySelector.
38    #[inline(always)]
39    pub fn key(&self) -> Key {
40        self.key
41    }
42
43    /// Manually sets the key selected by the KeySelector.
44    #[inline(always)]
45    pub fn set_key(&mut self, key: Key) {
46        self.key = key;
47    }
48}
49impl OnPaint for KeySelector {
50    fn on_paint(&self, surface: &mut Surface, theme: &Theme) {
51        let attr = match () {
52            _ if !self.is_enabled() => theme.editor.inactive,
53            _ if self.has_focus() => theme.editor.focused,
54            _ if self.is_mouse_over() => theme.editor.hovered,
55            _ => theme.editor.normal,
56        };
57        let right = self.size().width as i32;
58        surface.fill_horizontal_line(0, 0, right, Character::with_attributes(' ', attr));
59        surface.reduce_clip_by(1, 0, 1, 0);
60        let m = self.key.modifier.name();
61        let k = self.key.code.name();
62        if !m.is_empty() {
63            surface.write_string(1, 0, m, attr, false);
64            surface.write_string(1 + m.len() as i32, 0, k, attr, false);
65        } else if self.key == Key::None {
66            if self.has_focus() {
67                surface.write_string(1, 0, "None", attr, false);
68            } else {
69                surface.write_string(1, 0, "None", theme.editor.inactive, false);
70            }
71        } else {
72            surface.write_string(1, 0, k, attr, false);
73        }
74        if self.has_focus() {
75            surface.set_cursor(1, 0);
76        }
77    }
78}
79impl OnKeyPressed for KeySelector {
80    fn on_key_pressed(&mut self, key: Key, _: char) -> EventProcessStatus {
81        match key.code {
82            KeyCode::Enter => {
83                if (!self.flags.contains(Flags::AcceptEnter)) || (self.flags.contains(Flags::ReadOnly)) {
84                    return EventProcessStatus::Ignored;
85                }
86            }
87            KeyCode::Escape => {
88                if (!self.flags.contains(Flags::AcceptEscape)) || (self.flags.contains(Flags::ReadOnly)) {
89                    return EventProcessStatus::Ignored;
90                }
91            }
92            KeyCode::Tab => {
93                if (!self.flags.contains(Flags::AcceptTab)) || (self.flags.contains(Flags::ReadOnly)) {
94                    return EventProcessStatus::Ignored;
95                }
96            }
97            _ => {}
98        }
99        if !self.flags.contains(Flags::ReadOnly) && self.key != key {
100            let old = self.key;
101            self.key = key;
102            self.raise_event(ControlEvent {
103                emitter: self.handle,
104                receiver: self.event_processor,
105                data: ControlEventData::KeySelector(EventData { new_key: key, old_key: old }),
106            });
107        }
108        EventProcessStatus::Processed
109    }
110}
111impl OnMouseEvent for KeySelector {
112    fn on_mouse_event(&mut self, event: &MouseEvent) -> EventProcessStatus {
113        match event {
114            MouseEvent::Enter | MouseEvent::Leave => EventProcessStatus::Processed,
115            _ => EventProcessStatus::Ignored,
116        }
117    }
118}