appcui/ui/checkbox/
checkbox.rs1use super::Type;
2use crate::prelude::*;
3use crate::ui::checkbox::events::EventData;
4
5#[CustomControl(overwrite=OnPaint+OnDefaultAction+OnKeyPressed+OnMouseEvent,internal=true)]
6pub struct CheckBox {
7 caption: Caption,
8 checked: bool,
9 check_symbol: Symbol,
10 uncheck_symbol: Symbol,
11 symbol_width: u8,
12}
13
14impl CheckBox {
15 pub fn new(caption: &str, layout: Layout, checked: bool) -> Self {
24 Self::with_type(caption, layout, checked, Type::Standard)
25 }
26
27 pub fn with_type(caption: &str, layout: Layout, checked: bool, checkbox_type: Type) -> Self {
28 let cs = Symbol::new(checkbox_type.check_symbol());
29 let us = Symbol::new(checkbox_type.uncheck_symbol());
30 if cs.width() != us.width() {
31 panic!("CheckBox: check and uncheck symbols must have the same width (1, 2 or 3 characters)");
32 }
33 if cs.width() == 0 {
34 panic!("CheckBox: check and uncheck symbols must have at least one character");
35 }
36 let symbol_width = cs.width() + 1;
37 let mut cb = CheckBox {
38 base: ControlBase::with_status_flags(layout, StatusFlags::Visible | StatusFlags::Enabled | StatusFlags::AcceptInput),
39 caption: Caption::new(caption, ExtractHotKeyMethod::AltPlusKey),
40 checked,
41 check_symbol: cs,
42 uncheck_symbol: us,
43 symbol_width,
44 };
45 cb.set_size_bounds(5, 1, u16::MAX, u16::MAX);
46 let hotkey = cb.caption.hotkey();
47 cb.set_hotkey(hotkey);
48 cb
49 }
50
51 #[inline(always)]
53 pub fn is_checked(&self) -> bool {
54 self.checked
55 }
56
57 #[inline(always)]
59 pub fn set_checked(&mut self, checked: bool) {
60 self.checked = checked;
61 }
62
63 pub fn set_caption(&mut self, caption: &str) {
65 self.caption.set_text(caption, ExtractHotKeyMethod::AltPlusKey);
66 let hotkey = self.caption.hotkey();
67 self.set_hotkey(hotkey);
68 }
69 #[inline(always)]
71 pub fn caption(&self) -> &str {
72 self.caption.text()
73 }
74}
75impl OnPaint for CheckBox {
76 fn on_paint(&self, surface: &mut Surface, theme: &Theme) {
77 let attr_text = match () {
78 _ if !self.is_enabled() => theme.text.inactive,
79 _ if self.has_focus() => theme.text.focused,
80 _ if self.is_mouse_over() => theme.text.hovered,
81 _ => theme.text.normal,
82 };
83
84 let enabled = self.is_enabled();
85 let col_hot_key = if enabled { theme.text.hot_key } else { theme.text.inactive };
86 let sz = self.size();
87
88 if sz.width > self.symbol_width as u32 {
89 let mut format = TextFormatBuilder::new()
90 .position(self.symbol_width as i32, 0)
91 .attribute(attr_text)
92 .align(TextAlignment::Left)
93 .chars_count(self.caption.chars_count() as u16)
94 .build();
95 if sz.height > 1 {
96 format.set_wrap_type(WrapType::WordWrap(sz.width as u16 - self.symbol_width as u16));
97 }
98 if self.caption.has_hotkey() {
99 format.set_hotkey(col_hot_key, self.caption.hotkey_pos().unwrap() as u32);
100 }
101 surface.write_text(self.caption.text(), &format);
102 }
103 if self.checked {
104 let attr_symbol = if enabled { theme.symbol.checked } else { theme.symbol.inactive };
105 let attr_margin = if self.symbol_width == 4 { attr_text } else { attr_symbol };
106 self.check_symbol.paint(surface, 0, 0, attr_margin, attr_symbol, attr_margin);
107 } else {
108 let attr_symbol = if enabled { theme.symbol.unchecked } else { theme.symbol.inactive };
109 let attr_margin = if self.symbol_width == 4 { attr_text } else { attr_symbol };
110 self.uncheck_symbol.paint(surface, 0, 0, attr_margin, attr_symbol, attr_margin);
111 }
112 if self.has_focus() {
113 surface.set_cursor(if self.symbol_width == 4 { 1 } else { 0 }, 0);
114 }
115 }
116}
117impl OnDefaultAction for CheckBox {
118 fn on_default_action(&mut self) {
119 self.checked = !self.checked;
120 self.raise_event(ControlEvent {
121 emitter: self.handle,
122 receiver: self.event_processor,
123 data: ControlEventData::CheckBox(EventData { checked: self.checked }),
124 });
125 }
126}
127impl OnKeyPressed for CheckBox {
128 fn on_key_pressed(&mut self, key: Key, _character: char) -> EventProcessStatus {
129 if (key.modifier == KeyModifier::None) && ((key.code == KeyCode::Space) || (key.code == KeyCode::Enter)) {
130 self.on_default_action();
131 return EventProcessStatus::Processed;
132 }
133 EventProcessStatus::Ignored
134 }
135}
136impl OnMouseEvent for CheckBox {
137 fn on_mouse_event(&mut self, event: &MouseEvent) -> EventProcessStatus {
138 match event {
139 MouseEvent::Enter => {
140 if self.caption.chars_count() > (self.size().width - 4) as usize {
141 self.show_tooltip(self.caption.text());
142 }
143 EventProcessStatus::Processed
144 }
145 MouseEvent::Leave => EventProcessStatus::Processed,
146 MouseEvent::Released(data) => {
147 if self.is_coord_in_control(data.x, data.y) {
148 self.on_default_action();
149 }
150 EventProcessStatus::Processed
151 }
152 _ => EventProcessStatus::Ignored,
153 }
154 }
155}