use azul_core::{
callbacks::{CoreCallbackData, Update},
dom::{Dom, IdOrClass, IdOrClass::Class, IdOrClassVec, TabIndex},
refany::RefAny,
};
use azul_css::dynamic_selector::{CssPropertyWithConditions, CssPropertyWithConditionsVec};
use azul_css::{
props::{
basic::{color::ColorU, *},
layout::*,
property::{CssProperty, *},
style::*,
},
*,
};
use crate::callbacks::{Callback, CallbackInfo};
static CHECKBOX_CONTAINER_CLASS: &[IdOrClass] = &[Class(AzString::from_const_str(
"__azul-native-checkbox-container",
))];
static CHECKBOX_CONTENT_CLASS: &[IdOrClass] = &[Class(AzString::from_const_str(
"__azul-native-checkbox-content",
))];
pub type CheckBoxOnToggleCallbackType =
extern "C" fn(RefAny, CallbackInfo, CheckBoxState) -> Update;
impl_widget_callback!(
CheckBoxOnToggle,
OptionCheckBoxOnToggle,
CheckBoxOnToggleCallback,
CheckBoxOnToggleCallbackType
);
#[derive(Debug, Clone, PartialEq)]
#[repr(C)]
pub struct CheckBox {
pub check_box_state: CheckBoxStateWrapper,
pub container_style: CssPropertyWithConditionsVec,
pub content_style: CssPropertyWithConditionsVec,
}
#[derive(Debug, Default, Clone, PartialEq)]
#[repr(C)]
pub struct CheckBoxStateWrapper {
pub inner: CheckBoxState,
pub on_toggle: OptionCheckBoxOnToggle,
}
#[derive(Debug, Default, Clone, PartialEq)]
#[repr(C)]
pub struct CheckBoxState {
pub checked: bool,
}
const BACKGROUND_COLOR: ColorU = ColorU {
r: 255,
g: 255,
b: 255,
a: 255,
}; const BACKGROUND_THEME_LIGHT: &[StyleBackgroundContent] =
&[StyleBackgroundContent::Color(BACKGROUND_COLOR)];
const BACKGROUND_COLOR_LIGHT: StyleBackgroundContentVec =
StyleBackgroundContentVec::from_const_slice(BACKGROUND_THEME_LIGHT);
const COLOR_9B9B9B: ColorU = ColorU {
r: 155,
g: 155,
b: 155,
a: 255,
};
const FILL_COLOR: ColorU = ColorU {
r: 155,
g: 155,
b: 155,
a: 255,
}; const FILL_THEME: &[StyleBackgroundContent] = &[StyleBackgroundContent::Color(FILL_COLOR)];
const FILL_COLOR_BACKGROUND: StyleBackgroundContentVec =
StyleBackgroundContentVec::from_const_slice(FILL_THEME);
static DEFAULT_CHECKBOX_CONTAINER_STYLE: &[CssPropertyWithConditions] = &[
CssPropertyWithConditions::simple(CssProperty::const_background_content(
BACKGROUND_COLOR_LIGHT,
)),
CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::Block)),
CssPropertyWithConditions::simple(CssProperty::const_width(LayoutWidth::const_px(14))),
CssPropertyWithConditions::simple(CssProperty::const_height(LayoutHeight::const_px(14))),
CssPropertyWithConditions::simple(CssProperty::const_padding_left(
LayoutPaddingLeft::const_px(2),
)),
CssPropertyWithConditions::simple(CssProperty::const_padding_right(
LayoutPaddingRight::const_px(2),
)),
CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
2,
))),
CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
LayoutPaddingBottom::const_px(2),
)),
CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
LayoutBorderTopWidth::const_px(1),
)),
CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
LayoutBorderBottomWidth::const_px(1),
)),
CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
LayoutBorderLeftWidth::const_px(1),
)),
CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
LayoutBorderRightWidth::const_px(1),
)),
CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
inner: BorderStyle::Inset,
})),
CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
StyleBorderBottomStyle {
inner: BorderStyle::Inset,
},
)),
CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
inner: BorderStyle::Inset,
})),
CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
StyleBorderRightStyle {
inner: BorderStyle::Inset,
},
)),
CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
inner: COLOR_9B9B9B,
})),
CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
StyleBorderBottomColor {
inner: COLOR_9B9B9B,
},
)),
CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
inner: COLOR_9B9B9B,
})),
CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
StyleBorderRightColor {
inner: COLOR_9B9B9B,
},
)),
CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Pointer)),
];
static DEFAULT_CHECKBOX_CONTENT_STYLE_CHECKED: &[CssPropertyWithConditions] = &[
CssPropertyWithConditions::simple(CssProperty::const_width(LayoutWidth::const_px(8))),
CssPropertyWithConditions::simple(CssProperty::const_height(LayoutHeight::const_px(8))),
CssPropertyWithConditions::simple(CssProperty::const_background_content(FILL_COLOR_BACKGROUND)),
CssPropertyWithConditions::simple(CssProperty::const_opacity(StyleOpacity::const_new(100))),
];
static DEFAULT_CHECKBOX_CONTENT_STYLE_UNCHECKED: &[CssPropertyWithConditions] = &[
CssPropertyWithConditions::simple(CssProperty::const_width(LayoutWidth::const_px(8))),
CssPropertyWithConditions::simple(CssProperty::const_height(LayoutHeight::const_px(8))),
CssPropertyWithConditions::simple(CssProperty::const_background_content(FILL_COLOR_BACKGROUND)),
CssPropertyWithConditions::simple(CssProperty::const_opacity(StyleOpacity::const_new(0))),
];
impl CheckBox {
pub fn create(checked: bool) -> Self {
Self {
check_box_state: CheckBoxStateWrapper {
inner: CheckBoxState { checked },
..Default::default()
},
container_style: CssPropertyWithConditionsVec::from_const_slice(
DEFAULT_CHECKBOX_CONTAINER_STYLE,
),
content_style: if checked {
CssPropertyWithConditionsVec::from_const_slice(
DEFAULT_CHECKBOX_CONTENT_STYLE_CHECKED,
)
} else {
CssPropertyWithConditionsVec::from_const_slice(
DEFAULT_CHECKBOX_CONTENT_STYLE_UNCHECKED,
)
},
}
}
#[inline]
pub fn swap_with_default(&mut self) -> Self {
let mut s = Self::create(false);
core::mem::swap(&mut s, self);
s
}
#[inline]
pub fn set_on_toggle<C: Into<CheckBoxOnToggleCallback>>(&mut self, data: RefAny, on_toggle: C) {
self.check_box_state.on_toggle = Some(CheckBoxOnToggle {
callback: on_toggle.into(),
refany: data,
})
.into();
}
#[inline]
pub fn with_on_toggle<C: Into<CheckBoxOnToggleCallback>>(
mut self,
data: RefAny,
on_toggle: C,
) -> Self {
self.set_on_toggle(data, on_toggle);
self
}
#[inline]
pub fn dom(self) -> Dom {
use azul_core::{
callbacks::{CoreCallback, CoreCallbackData},
dom::{Dom, EventFilter, HoverEventFilter},
};
Dom::create_div()
.with_ids_and_classes(IdOrClassVec::from(CHECKBOX_CONTAINER_CLASS))
.with_css_props(self.container_style)
.with_callbacks(
vec![CoreCallbackData {
event: EventFilter::Hover(HoverEventFilter::MouseUp),
callback: CoreCallback {
cb: self::input::default_on_checkbox_clicked as usize,
ctx: azul_core::refany::OptionRefAny::None,
},
refany: RefAny::new(self.check_box_state),
}]
.into(),
)
.with_tab_index(TabIndex::Auto)
.with_children(
vec![Dom::create_div()
.with_ids_and_classes(IdOrClassVec::from(CHECKBOX_CONTENT_CLASS))
.with_css_props(self.content_style)]
.into(),
)
}
}
mod input {
use azul_core::{callbacks::Update, refany::RefAny};
use azul_css::props::{property::CssProperty, style::effects::StyleOpacity};
use super::{CheckBoxOnToggle, CheckBoxStateWrapper};
use crate::callbacks::CallbackInfo;
pub(super) extern "C" fn default_on_checkbox_clicked(
mut check_box: RefAny,
mut info: CallbackInfo,
) -> Update {
let mut check_box = match check_box.downcast_mut::<CheckBoxStateWrapper>() {
Some(s) => s,
None => return Update::DoNothing,
};
let checkbox_content_id = match info.get_first_child(info.get_hit_node()) {
Some(s) => s,
None => return Update::DoNothing,
};
check_box.inner.checked = !check_box.inner.checked;
let result = {
let check_box = &mut *check_box;
let ontoggle = &mut check_box.on_toggle;
let inner = check_box.inner.clone();
match ontoggle.as_mut() {
Some(CheckBoxOnToggle {
callback,
refany: data,
}) => (callback.cb)(data.clone(), info.clone(), inner),
None => Update::DoNothing,
}
};
if check_box.inner.checked {
info.set_css_property(
checkbox_content_id,
CssProperty::const_opacity(StyleOpacity::const_new(100)),
);
} else {
info.set_css_property(
checkbox_content_id,
CssProperty::const_opacity(StyleOpacity::const_new(0)),
);
}
result
}
}
impl From<CheckBox> for Dom {
fn from(b: CheckBox) -> Dom {
b.dom()
}
}