tuix_widgets/buttons/
checkbox.rs

1#![allow(dead_code)]
2
3use crate::common::*;
4use crate::ButtonEvent;
5
6const ICON_CHECK: &str = "\u{2713}";
7
8//TODO
9const CHECKBOX_STYLE: &str = r#"
10    checkbox {
11        font: icons,
12        width: 20px;
13        height: 20px;
14        background-color: white;
15        border-width: 1px;
16        border-color: black;
17        border-radius: 3px;
18        transition: background-color 0.1 0.0;
19    }
20
21    checkbox:checked {
22        background-color: #ff5e1a;
23        border-color: #ff5e1a;
24        transition: background-color 0.1 0.0;
25    }
26"#;
27
28#[derive(Clone, Copy, Debug, PartialEq)]
29pub enum CheckboxEvent {
30    Check,
31    Uncheck,
32    Switch,
33    Checked,
34    Unchecked,
35}
36
37pub struct Atom<T> {
38    key: &'static str,
39    default: T,
40}
41
42impl<T> Atom<T> {
43    pub const fn new(key: &'static str, default: T) -> Self {
44        Self {
45            key,
46            default,
47        }
48    }
49}
50
51#[derive(Default)]
52pub struct Checkbox {
53    icon_unchecked: Option<String>,
54    icon_checked: Option<String>,
55
56    checked: bool,
57
58    on_checked: Option<Box<dyn Fn(&mut Self, &mut State, Entity)>>,
59    on_unchecked: Option<Box<dyn Fn(&mut Self, &mut State, Entity)>>,
60
61    key: Code,
62}
63
64impl Checkbox {
65    pub fn new(checked: bool) -> Self {
66        Self {
67            icon_unchecked: Some(String::new()),
68            icon_checked: Some(ICON_CHECK.to_string()),
69        
70            on_checked: None,
71            on_unchecked: None,
72
73            checked,
74
75            key: Code::Space,
76        }
77    }
78
79    pub fn with_icon_checked(mut self, icon_checked: &str) -> Self {
80        self.icon_checked = Some(icon_checked.to_string());
81
82        self
83    }
84
85    pub fn with_icon_unchecked(mut self, icon_unchecked: &str) -> Self {
86        self.icon_unchecked = Some(icon_unchecked.to_string());
87
88        self
89    }
90
91    pub fn on_checked<F>(mut self, callback: F) -> Self 
92    where
93        F: 'static + Fn(&mut Self, &mut State, Entity)
94    {
95        self.on_checked = Some(Box::new(callback));
96
97        self
98    }
99
100    pub fn on_unchecked<F>(mut self, callback: F) -> Self 
101    where
102        F: 'static + Fn(&mut Self, &mut State, Entity)
103    {
104        self.on_unchecked = Some(Box::new(callback));
105
106        self
107    }
108}
109
110impl Widget for Checkbox {
111    type Ret = Entity;
112    type Data = bool;
113    fn on_build(&mut self, state: &mut State, entity: Entity) -> Self::Ret {
114        entity
115            .set_font(state, "icons")
116            .set_child_space(state, Stretch(1.0));
117
118        if self.checked {
119            entity.set_checked(state, true);
120
121            if let Some(icon_checked) = &self.icon_checked {
122                entity.set_text(state, &icon_checked);
123            }
124
125            state.insert_event(
126                Event::new(CheckboxEvent::Checked)
127                    .target(entity)
128                    .origin(entity),
129            );
130
131        } else {
132            entity.set_checked(state, false);
133
134            if let Some(icon_unchecked) = &self.icon_unchecked {
135                entity.set_text(state, &icon_unchecked);
136            }
137
138            state.insert_event(
139                Event::new(CheckboxEvent::Unchecked)
140                    .target(entity)
141                    .origin(entity),
142            );
143        }
144
145        entity.set_element(state, "checkbox")
146    }
147
148    fn on_event(&mut self, state: &mut State, entity: Entity, event: &mut Event) {
149        
150        if let Some(checkbox_event) = event.message.downcast::<CheckboxEvent>() {
151            match checkbox_event {
152                CheckboxEvent::Switch => {
153                    if event.target == entity {
154                        if self.checked {
155
156                            entity.set_checked(state, false);
157
158                            if let Some(icon_unchecked) = &self.icon_unchecked {
159                                entity.set_text(state, &icon_unchecked);
160                            }
161
162                            state.insert_event(
163                                Event::new(CheckboxEvent::Unchecked)
164                                    .target(entity)
165                                    .origin(entity),
166                            );
167                        } else {
168
169                            entity.set_checked(state, true);
170
171                            if let Some(icon_checked) = &self.icon_checked {
172                                entity.set_text(state, &icon_checked);
173                            }
174
175                            state.insert_event(
176                                Event::new(CheckboxEvent::Checked)
177                                    .target(entity)
178                                    .origin(entity),
179                            );
180                        }
181                    }
182                }
183
184                CheckboxEvent::Check => {
185                    self.checked = true;
186                    entity.set_checked(state, true);
187                }
188
189                CheckboxEvent::Uncheck => {
190                    self.checked = false;
191                    entity.set_checked(state, false);
192                }
193
194                CheckboxEvent::Checked => {
195                    self.checked = true;
196
197                    entity.set_checked(state, true);
198
199                    if let Some(callback) = self.on_checked.take() {
200                        (callback)(self, state, entity);
201                        self.on_checked = Some(callback);
202                    }
203                }
204
205                CheckboxEvent::Unchecked => {
206                    self.checked = false;
207
208                    entity.set_checked(state, false);
209
210                    if let Some(callback) = self.on_unchecked.take() {
211                        (callback)(self, state, entity);
212                        self.on_unchecked = Some(callback);
213                    }
214                }
215            }
216        }
217        
218        if let Some(window_event) = event.message.downcast::<WindowEvent>() {
219            match window_event {
220                WindowEvent::MouseDown(button) if *button == MouseButton::Left => {
221                    if entity == event.target && !entity.is_disabled(state) {
222                        state.capture(entity);
223                    }
224                }
225
226                WindowEvent::MouseUp(button) if *button == MouseButton::Left => {
227                    if entity == event.target && state.mouse.left.pressed == entity {
228                        state.release(entity);
229                        entity.set_active(state, false);
230                        if !entity.is_disabled(state) {
231                            if state.hovered == entity {
232                                state.insert_event(
233                                    Event::new(CheckboxEvent::Switch)
234                                        .target(entity)
235                                        .origin(entity),
236                                );
237                            }
238                        }
239                    }
240                }
241
242                WindowEvent::KeyDown(code, _) if *code == self.key => {
243                    if state.focused == entity && !entity.is_disabled(state) {
244                        state.insert_event(
245                            Event::new(ButtonEvent::Pressed)
246                                .target(entity)
247                                .origin(entity),
248                        );
249                    }
250                }
251
252                WindowEvent::KeyUp(code, _) if *code == self.key => {
253                    state.insert_event(
254                        Event::new(ButtonEvent::Released)
255                            .target(entity)
256                            .origin(entity),
257                    );
258                }
259
260                _ => {}
261            }
262        }
263    
264    }
265}
266
267/*
268pub struct CheckItem {
269    name: String,
270    checked: bool,
271
272    button: Button,
273
274    checkbox: Entity,
275    label: Entity,
276}
277
278impl CheckItem {
279    pub fn new(label: &str, checked: bool) -> Self {
280        Self {
281            name: label.to_string(),
282            checked,
283
284            button: Button::default(),
285
286            checkbox: Entity::null(),
287            label: Entity::null(),
288        }
289    }
290}
291
292impl Widget for CheckItem {
293    type Ret = Entity;
294    fn on_build(&mut self, state: &mut State, entity: Entity) -> Self::Ret {
295        self.checkbox = Checkbox::new(self.checked).build(state, entity, |builder| {
296            builder.set_hoverable(false).set_focusable(false)
297        });
298        self.label = Label::new(&self.name).build(state, entity, |builder| {
299            builder
300                .set_hoverable(false)
301                .set_focusable(false)
302                .set_left(Pixels(5.0))
303        });
304
305        let checkbox = self.checkbox;
306        self.button =
307            Button::new().on_release(move |_, state, entity|
308                state.insert_event(
309                    Event::new(CheckboxEvent::Switch).target(checkbox).target(entity)
310                )
311            );
312
313        //let checkbox = self.checkbox;
314        // self.button.on_test(move |button, state, entity| {
315        //     println!("Send message to checkbox");
316        //     state.insert_event(Event::new(CheckboxEvent::Switch).target(checkbox))
317        // });
318
319        entity.set_layout_type(state, LayoutType::Row);
320
321        entity.set_element(state, "check_item")
322    }
323
324    fn on_event(&mut self, state: &mut State, entity: Entity, event: &mut Event) {
325        self.button.on_event(state, entity, event);
326    }
327}
328*/