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