1use azul_core::{
2 callbacks::{CoreCallbackData, Update},
3 dom::{Dom, IdOrClass, IdOrClass::Class, IdOrClassVec, TabIndex},
4 refany::RefAny,
5};
6use azul_css::dynamic_selector::{CssPropertyWithConditions, CssPropertyWithConditionsVec};
7use azul_css::{
8 props::{
9 basic::{color::ColorU, *},
10 layout::*,
11 property::{CssProperty, *},
12 style::*,
13 },
14 *,
15};
16
17use crate::callbacks::{Callback, CallbackInfo};
18
19static CHECKBOX_CONTAINER_CLASS: &[IdOrClass] = &[Class(AzString::from_const_str(
20 "__azul-native-checkbox-container",
21))];
22static CHECKBOX_CONTENT_CLASS: &[IdOrClass] = &[Class(AzString::from_const_str(
23 "__azul-native-checkbox-content",
24))];
25
26pub type CheckBoxOnToggleCallbackType =
27 extern "C" fn(RefAny, CallbackInfo, CheckBoxState) -> Update;
28impl_widget_callback!(
29 CheckBoxOnToggle,
30 OptionCheckBoxOnToggle,
31 CheckBoxOnToggleCallback,
32 CheckBoxOnToggleCallbackType
33);
34
35#[derive(Debug, Clone, PartialEq)]
36#[repr(C)]
37pub struct CheckBox {
38 pub check_box_state: CheckBoxStateWrapper,
39 pub container_style: CssPropertyWithConditionsVec,
41 pub content_style: CssPropertyWithConditionsVec,
43}
44
45#[derive(Debug, Default, Clone, PartialEq)]
46#[repr(C)]
47pub struct CheckBoxStateWrapper {
48 pub inner: CheckBoxState,
50 pub on_toggle: OptionCheckBoxOnToggle,
52}
53
54#[derive(Debug, Default, Clone, PartialEq)]
55#[repr(C)]
56pub struct CheckBoxState {
57 pub checked: bool,
58}
59
60const BACKGROUND_COLOR: ColorU = ColorU {
61 r: 255,
62 g: 255,
63 b: 255,
64 a: 255,
65}; const BACKGROUND_THEME_LIGHT: &[StyleBackgroundContent] =
67 &[StyleBackgroundContent::Color(BACKGROUND_COLOR)];
68const BACKGROUND_COLOR_LIGHT: StyleBackgroundContentVec =
69 StyleBackgroundContentVec::from_const_slice(BACKGROUND_THEME_LIGHT);
70const COLOR_9B9B9B: ColorU = ColorU {
71 r: 155,
72 g: 155,
73 b: 155,
74 a: 255,
75}; const FILL_COLOR: ColorU = ColorU {
78 r: 155,
79 g: 155,
80 b: 155,
81 a: 255,
82}; const FILL_THEME: &[StyleBackgroundContent] = &[StyleBackgroundContent::Color(FILL_COLOR)];
84const FILL_COLOR_BACKGROUND: StyleBackgroundContentVec =
85 StyleBackgroundContentVec::from_const_slice(FILL_THEME);
86
87static DEFAULT_CHECKBOX_CONTAINER_STYLE: &[CssPropertyWithConditions] = &[
88 CssPropertyWithConditions::simple(CssProperty::const_background_content(
89 BACKGROUND_COLOR_LIGHT,
90 )),
91 CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::Block)),
92 CssPropertyWithConditions::simple(CssProperty::const_width(LayoutWidth::const_px(14))),
93 CssPropertyWithConditions::simple(CssProperty::const_height(LayoutHeight::const_px(14))),
94 CssPropertyWithConditions::simple(CssProperty::const_padding_left(
96 LayoutPaddingLeft::const_px(2),
97 )),
98 CssPropertyWithConditions::simple(CssProperty::const_padding_right(
99 LayoutPaddingRight::const_px(2),
100 )),
101 CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
102 2,
103 ))),
104 CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
105 LayoutPaddingBottom::const_px(2),
106 )),
107 CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
109 LayoutBorderTopWidth::const_px(1),
110 )),
111 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
112 LayoutBorderBottomWidth::const_px(1),
113 )),
114 CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
115 LayoutBorderLeftWidth::const_px(1),
116 )),
117 CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
118 LayoutBorderRightWidth::const_px(1),
119 )),
120 CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
121 inner: BorderStyle::Inset,
122 })),
123 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
124 StyleBorderBottomStyle {
125 inner: BorderStyle::Inset,
126 },
127 )),
128 CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
129 inner: BorderStyle::Inset,
130 })),
131 CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
132 StyleBorderRightStyle {
133 inner: BorderStyle::Inset,
134 },
135 )),
136 CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
137 inner: COLOR_9B9B9B,
138 })),
139 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
140 StyleBorderBottomColor {
141 inner: COLOR_9B9B9B,
142 },
143 )),
144 CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
145 inner: COLOR_9B9B9B,
146 })),
147 CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
148 StyleBorderRightColor {
149 inner: COLOR_9B9B9B,
150 },
151 )),
152 CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Pointer)),
153];
154
155static DEFAULT_CHECKBOX_CONTENT_STYLE_CHECKED: &[CssPropertyWithConditions] = &[
156 CssPropertyWithConditions::simple(CssProperty::const_width(LayoutWidth::const_px(8))),
157 CssPropertyWithConditions::simple(CssProperty::const_height(LayoutHeight::const_px(8))),
158 CssPropertyWithConditions::simple(CssProperty::const_background_content(FILL_COLOR_BACKGROUND)),
159 CssPropertyWithConditions::simple(CssProperty::const_opacity(StyleOpacity::const_new(100))),
160 ];
162
163static DEFAULT_CHECKBOX_CONTENT_STYLE_UNCHECKED: &[CssPropertyWithConditions] = &[
164 CssPropertyWithConditions::simple(CssProperty::const_width(LayoutWidth::const_px(8))),
165 CssPropertyWithConditions::simple(CssProperty::const_height(LayoutHeight::const_px(8))),
166 CssPropertyWithConditions::simple(CssProperty::const_background_content(FILL_COLOR_BACKGROUND)),
167 CssPropertyWithConditions::simple(CssProperty::const_opacity(StyleOpacity::const_new(0))),
168 ];
170
171impl CheckBox {
172 pub fn create(checked: bool) -> Self {
173 Self {
174 check_box_state: CheckBoxStateWrapper {
175 inner: CheckBoxState { checked },
176 ..Default::default()
177 },
178 container_style: CssPropertyWithConditionsVec::from_const_slice(
179 DEFAULT_CHECKBOX_CONTAINER_STYLE,
180 ),
181 content_style: if checked {
182 CssPropertyWithConditionsVec::from_const_slice(
183 DEFAULT_CHECKBOX_CONTENT_STYLE_CHECKED,
184 )
185 } else {
186 CssPropertyWithConditionsVec::from_const_slice(
187 DEFAULT_CHECKBOX_CONTENT_STYLE_UNCHECKED,
188 )
189 },
190 }
191 }
192
193 #[inline]
194 pub fn swap_with_default(&mut self) -> Self {
195 let mut s = Self::create(false);
196 core::mem::swap(&mut s, self);
197 s
198 }
199
200 #[inline]
201 pub fn set_on_toggle<C: Into<CheckBoxOnToggleCallback>>(&mut self, data: RefAny, on_toggle: C) {
202 self.check_box_state.on_toggle = Some(CheckBoxOnToggle {
203 callback: on_toggle.into(),
204 refany: data,
205 })
206 .into();
207 }
208
209 #[inline]
210 pub fn with_on_toggle<C: Into<CheckBoxOnToggleCallback>>(
211 mut self,
212 data: RefAny,
213 on_toggle: C,
214 ) -> Self {
215 self.set_on_toggle(data, on_toggle);
216 self
217 }
218
219 #[inline]
220 pub fn dom(self) -> Dom {
221 use azul_core::{
222 callbacks::{CoreCallback, CoreCallbackData},
223 dom::{Dom, EventFilter, HoverEventFilter},
224 };
225
226 Dom::create_div()
227 .with_ids_and_classes(IdOrClassVec::from(CHECKBOX_CONTAINER_CLASS))
228 .with_css_props(self.container_style)
229 .with_callbacks(
230 vec![CoreCallbackData {
231 event: EventFilter::Hover(HoverEventFilter::MouseUp),
232 callback: CoreCallback {
233 cb: self::input::default_on_checkbox_clicked as usize,
234 ctx: azul_core::refany::OptionRefAny::None,
235 },
236 refany: RefAny::new(self.check_box_state),
237 }]
238 .into(),
239 )
240 .with_tab_index(TabIndex::Auto)
241 .with_children(
242 vec![Dom::create_div()
243 .with_ids_and_classes(IdOrClassVec::from(CHECKBOX_CONTENT_CLASS))
244 .with_css_props(self.content_style)]
245 .into(),
246 )
247 }
248}
249
250mod input {
252
253 use azul_core::{callbacks::Update, refany::RefAny};
254 use azul_css::props::{property::CssProperty, style::effects::StyleOpacity};
255
256 use super::{CheckBoxOnToggle, CheckBoxStateWrapper};
257 use crate::callbacks::CallbackInfo;
258
259 pub(super) extern "C" fn default_on_checkbox_clicked(
260 mut check_box: RefAny,
261 mut info: CallbackInfo,
262 ) -> Update {
263 let mut check_box = match check_box.downcast_mut::<CheckBoxStateWrapper>() {
264 Some(s) => s,
265 None => return Update::DoNothing,
266 };
267
268 let checkbox_content_id = match info.get_first_child(info.get_hit_node()) {
269 Some(s) => s,
270 None => return Update::DoNothing,
271 };
272
273 check_box.inner.checked = !check_box.inner.checked;
274
275 let result = {
276 let check_box = &mut *check_box;
278 let ontoggle = &mut check_box.on_toggle;
279 let inner = check_box.inner.clone();
280
281 match ontoggle.as_mut() {
282 Some(CheckBoxOnToggle {
283 callback,
284 refany: data,
285 }) => (callback.cb)(data.clone(), info.clone(), inner),
286 None => Update::DoNothing,
287 }
288 };
289
290 if check_box.inner.checked {
291 info.set_css_property(
292 checkbox_content_id,
293 CssProperty::const_opacity(StyleOpacity::const_new(100)),
294 );
295 } else {
296 info.set_css_property(
297 checkbox_content_id,
298 CssProperty::const_opacity(StyleOpacity::const_new(0)),
299 );
300 }
301
302 result
303 }
304}
305
306impl From<CheckBox> for Dom {
307 fn from(b: CheckBox) -> Dom {
308 b.dom()
309 }
310}