use ribir_core::prelude::*;
use crate::prelude::*;
#[derive(Debug, Clone, Copy, Declare, PartialEq, Eq)]
pub struct Checkbox {
#[declare(default, event = Checkbox.checked)]
pub checked: bool,
#[declare(default, event = Checkbox.indeterminate)]
pub indeterminate: bool,
}
pub type CheckboxChanged = CustomEvent<Checkbox>;
class_names! {
CHECKBOX_CHECKED,
CHECKBOX_UNCHECKED,
CHECKBOX_INDETERMINATE,
CHECKBOX,
CHECKBOX_UNCHECKED_ICON,
CHECKBOX_CHECKED_ICON,
CHECKBOX_INDETERMINATE_ICON
}
impl Checkbox {
fn state_class_name(&self) -> ClassName {
match (self.indeterminate, self.checked) {
(true, _) => CHECKBOX_INDETERMINATE,
(_, true) => CHECKBOX_CHECKED,
_ => CHECKBOX_UNCHECKED,
}
}
fn icon_class_name(&self) -> ClassName {
match (self.indeterminate, self.checked) {
(true, _) => CHECKBOX_INDETERMINATE_ICON,
(_, true) => CHECKBOX_CHECKED_ICON,
_ => CHECKBOX_UNCHECKED_ICON,
}
}
fn request_toggle(&self, e: &CommonEvent) {
let mut new_state = *self;
new_state.switch_check();
e.window()
.bubble_custom_event(e.target(), new_state);
}
pub fn switch_check(&mut self) {
if self.indeterminate {
self.indeterminate = false;
self.checked = false;
} else {
self.checked = !self.checked;
}
}
}
impl ComposeChild<'static> for Checkbox {
type Child = Option<PositionChild<TextValue>>;
fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'static> {
fn_widget! {
let icon = @Icon {
class: class_list![
CHECKBOX,
distinct_pipe!($read(this).state_class_name())
],
@Void { class: distinct_pipe!($read(this).icon_class_name())}
};
let icon_with_label = icon_with_label(icon.into_widget(), child);
@FatObj {
on_action: move |e| $read(this).request_toggle(e),
@{ icon_with_label }
}
}
.into_widget()
}
}
#[cfg(test)]
mod tests {
use ribir_core::test_helper::*;
use ribir_dev_helper::*;
use super::*;
widget_image_tests!(
checkbox,
WidgetTester::new(self::column! {
@Checkbox { checked: true, @ { "checked" } }
@Checkbox { indeterminate: true, @Leading::new("indeterminate") }
@Checkbox { @Trailing::new("unchecked") }
})
.with_wnd_size(Size::new(240., 160.)),
);
}