ori_core/views/
checkbox.rs

1use glam::Vec2;
2use ori_graphics::{TextAlign, TextSection};
3use ori_macro::Build;
4
5use crate::{
6    BoxConstraints, Context, DrawContext, Event, EventContext, LayoutContext, PointerEvent, Scope,
7    SharedSignal, Signal, Style, View,
8};
9
10#[derive(Default, Build)]
11pub struct Checkbox {
12    #[bind]
13    checked: SharedSignal<bool>,
14}
15
16impl Checkbox {
17    const CHECKMARK: &'static str = "\u{e876}";
18
19    pub fn new() -> Self {
20        Self::default()
21    }
22
23    pub fn checked(self, checked: bool) -> Self {
24        self.checked.set(checked);
25        self
26    }
27
28    pub fn bind_checked<'a>(self, cx: Scope<'a>, binding: &'a Signal<bool>) -> Self {
29        let signal = cx.alloc(self.checked.clone());
30        cx.bind(signal, binding);
31        self
32    }
33}
34
35impl View for Checkbox {
36    type State = ();
37
38    fn build(&self) -> Self::State {}
39
40    fn style(&self) -> Style {
41        Style::new("checkbox")
42    }
43
44    fn event(&self, _: &mut Self::State, cx: &mut EventContext, event: &Event) {
45        cx.state.active = self.checked.cloned_untracked();
46
47        if event.is_handled() || !cx.hovered() {
48            return;
49        }
50
51        if let Some(pointer_event) = event.get::<PointerEvent>() {
52            if pointer_event.is_press() {
53                self.checked.set(!self.checked.cloned());
54                event.handle();
55                cx.request_redraw();
56            }
57        }
58    }
59
60    fn layout(&self, _state: &mut Self::State, cx: &mut LayoutContext, bc: BoxConstraints) -> Vec2 {
61        cx.state.active = self.checked.cloned_untracked();
62
63        let width = cx.style_range("width", bc.width());
64        let height = cx.style_range("height", bc.height());
65        bc.constrain(Vec2::new(width, height))
66    }
67
68    fn draw(&self, _state: &mut Self::State, cx: &mut DrawContext) {
69        cx.state.active = self.checked.cloned_untracked();
70
71        cx.draw_quad();
72
73        if *self.checked.get() {
74            let section = TextSection {
75                rect: cx.rect(),
76                scale: cx.rect().size().min_element() * 0.8,
77                h_align: TextAlign::Center,
78                v_align: TextAlign::Center,
79                text: String::from(Self::CHECKMARK),
80                font: Some(String::from("icon")),
81                color: cx.style("color"),
82                ..Default::default()
83            };
84
85            cx.draw(section);
86        }
87    }
88}