freya_components/
checkbox.rs1use freya_core::prelude::*;
2use torin::prelude::*;
3
4use crate::{
5 get_theme,
6 icons::tick::TickIcon,
7 theming::component_themes::{
8 CheckboxTheme,
9 CheckboxThemePartial,
10 },
11};
12
13#[cfg_attr(feature = "docs",
49 doc = embed_doc_image::embed_image!("checkbox", "images/gallery_checkbox.png")
50)]
51#[derive(Clone, PartialEq)]
52pub struct Checkbox {
53 pub(crate) theme: Option<CheckboxThemePartial>,
54 selected: bool,
55 key: DiffKey,
56 size: f32,
57}
58
59impl Default for Checkbox {
60 fn default() -> Self {
61 Self::new()
62 }
63}
64
65impl Checkbox {
66 pub fn new() -> Self {
67 Self {
68 selected: false,
69 theme: None,
70 key: DiffKey::None,
71 size: 20.,
72 }
73 }
74
75 pub fn selected(mut self, selected: bool) -> Self {
76 self.selected = selected;
77 self
78 }
79
80 pub fn theme(mut self, theme: CheckboxThemePartial) -> Self {
81 self.theme = Some(theme);
82 self
83 }
84
85 pub fn key(mut self, key: impl Into<DiffKey>) -> Self {
86 self.key = key.into();
87 self
88 }
89
90 pub fn size(mut self, size: impl Into<f32>) -> Self {
91 self.size = size.into();
92 self
93 }
94}
95
96impl Render for Checkbox {
97 fn render(&self) -> impl IntoElement {
98 let focus = use_focus();
99 let focus_status = use_focus_status(focus);
100 let CheckboxTheme {
101 border_fill,
102 unselected_fill,
103 selected_fill,
104 selected_icon_fill,
105 } = get_theme!(&self.theme, checkbox);
106
107 let (background, fill) = if self.selected {
108 (selected_fill, selected_fill)
109 } else {
110 (Color::TRANSPARENT, unselected_fill)
111 };
112
113 let border = Border::new()
114 .fill(fill)
115 .width(2.)
116 .alignment(BorderAlignment::Inner);
117
118 let focused_border = (focus_status() == FocusStatus::Keyboard).then(|| {
119 Border::new()
120 .fill(border_fill)
121 .width((self.size * 0.15).ceil())
122 .alignment(BorderAlignment::Outer)
123 });
124
125 rect()
126 .a11y_id(focus.a11y_id())
127 .a11y_focusable(Focusable::Enabled)
128 .width(Size::px(self.size))
129 .height(Size::px(self.size))
130 .padding(Gaps::new_all(4.0))
131 .main_align(Alignment::center())
132 .cross_align(Alignment::center())
133 .corner_radius(CornerRadius::new_all(self.size * 0.24))
134 .border(border)
135 .border(focused_border)
136 .background(background)
137 .on_key_down({
138 move |e: Event<KeyboardEventData>| {
139 if !Focus::is_pressed(&e) {
140 e.stop_propagation();
141 }
142 }
143 })
144 .maybe_child(self.selected.then(|| {
145 TickIcon::new()
146 .width(Size::px(self.size * 0.7))
147 .height(Size::px(self.size * 0.7))
148 .fill(selected_icon_fill)
149 }))
150 }
151
152 fn render_key(&self) -> DiffKey {
153 self.key.clone().or(self.default_key())
154 }
155}