appcui/ui/password/
password.rs1use crate::prelude::*;
2use crate::ui::password::events::EventData;
3
4#[CustomControl(overwrite=OnPaint+OnKeyPressed+OnMouseEvent, internal=true)]
5pub struct Password {
6 pass: String,
7 visible: bool,
8}
9impl Password {
10 pub fn new(layout: Layout) -> Self {
20 let mut p = Self {
21 base: ControlBase::with_status_flags(layout, StatusFlags::Visible | StatusFlags::Enabled | StatusFlags::AcceptInput),
22 pass: String::new(),
23 visible: false,
24 };
25 p.set_size_bounds(4, 1, u16::MAX, 1);
26 p
27 }
28
29 pub fn set_password(&mut self, password: &str) {
31 self.pass.clear();
32 self.pass.push_str(password);
33 }
34
35 #[inline(always)]
37 pub fn password(&self) -> &str {
38 &self.pass
39 }
40}
41impl OnPaint for Password {
42 fn on_paint(&self, surface: &mut Surface, theme: &Theme) {
43 let attr = match () {
44 _ if !self.is_enabled() => theme.editor.inactive,
45 _ if self.has_focus() => theme.editor.focused,
46 _ if self.is_mouse_over() => theme.editor.hovered,
47 _ => theme.editor.normal,
48 };
49 let mut sz = self.pass.len() as u32;
50 let w = self.size().width;
51 if (sz + 3) >= w {
52 sz = w - 3;
53 }
54 surface.fill_horizontal_line(0, 0, w as i32, Character::with_attributes(' ', attr));
55 if self.visible {
56 if sz > 0 {
57 let format = TextFormatBuilder::new()
58 .position(1, 0)
59 .attribute(attr)
60 .align(TextAlignment::Left)
61 .wrap_type(WrapType::SingleLineWrap(sz as u16))
62 .build();
63 surface.write_text(&self.pass, &format);
64 }
65 surface.write_char(
66 w as i32 - 1,
67 0,
68 Character::with_attributes(SpecialChar::CircleFilled, theme.symbol.checked),
69 );
70 } else {
71 surface.fill_horizontal_line_with_size(1, 0, sz, Character::with_attributes('*', attr));
72 surface.write_char(
73 w as i32 - 1,
74 0,
75 Character::with_attributes(SpecialChar::CircleEmpty, theme.symbol.unchecked),
76 );
77 }
78 if self.has_focus() {
79 surface.set_cursor(1 + sz as i32, 0);
80 }
81 }
82}
83impl OnKeyPressed for Password {
84 fn on_key_pressed(&mut self, key: Key, character: char) -> EventProcessStatus {
85 if character as u32 > 0 {
86 self.pass.push(character);
87 return EventProcessStatus::Processed;
88 }
89 match key.value() {
90 key!("Back") => {
91 self.pass.pop();
92 return EventProcessStatus::Processed;
93 }
94 key!("Enter") => {
95 self.raise_event(ControlEvent {
96 emitter: self.handle,
97 receiver: self.event_processor,
98 data: ControlEventData::Password(EventData { accept: true }),
99 });
100 return EventProcessStatus::Processed;
101 }
102 key!("Esc") => {
103 self.raise_event(ControlEvent {
104 emitter: self.handle,
105 receiver: self.event_processor,
106 data: ControlEventData::Password(EventData { accept: false }),
107 });
108 return EventProcessStatus::Processed;
109 }
110 _ => {}
111 }
112 EventProcessStatus::Ignored
113 }
114}
115impl OnMouseEvent for Password {
116 fn on_mouse_event(&mut self, event: &MouseEvent) -> EventProcessStatus {
117 match event {
118 MouseEvent::Enter => {
119 self.show_tooltip("Click and hold to see the password");
120 EventProcessStatus::Processed
121 }
122 MouseEvent::Leave => {
123 self.hide_tooltip();
124 EventProcessStatus::Processed
125 }
126 MouseEvent::Over(_) => EventProcessStatus::Ignored,
127 MouseEvent::Pressed(_) => {
128 self.visible = true;
129 EventProcessStatus::Processed
130 }
131 MouseEvent::Released(_) => {
132 self.visible = false;
133 EventProcessStatus::Processed
134 }
135 MouseEvent::DoubleClick(_) => EventProcessStatus::Ignored,
136 MouseEvent::Drag(_) => EventProcessStatus::Ignored,
137 MouseEvent::Wheel(_) => EventProcessStatus::Ignored,
138 }
139 }
140}