teksilo_data/check_state.rs
1// SPDX-License-Identifier: MPL-2.0
2// SPDX-FileCopyrightText: 2026 FernTech
3
4//! `CheckState` — tri-state checkbox value shared by the data layer and widgets.
5//!
6//! Represents the three visual states of a checkbox: unchecked, checked, and
7//! indeterminate (partial — some but not all descendants are checked). Lives in
8//! `teksilo-data` rather than `teksilo-widgets` so that [`crate::TreeCheckedModel`]
9//! can produce `Signal<CheckState>` values without inverting the dependency graph.
10//!
11//! `From<bool>` converts a plain two-state boolean (e.g. from a filter predicate)
12//! into `Unchecked` or `Checked`, making it easy to bridge non-tristate sources.
13//!
14//! ```rust
15//! # use teksilo_data::CheckState;
16//! let state = CheckState::Indeterminate;
17//! assert!(state.is_filled());
18//! assert_eq!(state.next_tristate(), CheckState::Unchecked);
19//! assert_eq!(CheckState::from(true), CheckState::Checked);
20//! ```
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub enum CheckState {
24 /// The checkbox is unchecked (no fill, no mark).
25 Unchecked,
26 /// The checkbox is fully checked (filled with a check mark).
27 Checked,
28 /// Some but not all descendants are checked; shown as a dash or partial fill.
29 Indeterminate,
30}
31
32impl CheckState {
33 /// Whether the box shows a filled background (checked or indeterminate).
34 pub fn is_filled(self) -> bool {
35 self != CheckState::Unchecked
36 }
37
38 /// Cycle to the next state: Unchecked → Checked → Indeterminate → Unchecked.
39 pub fn next_tristate(self) -> Self {
40 match self {
41 CheckState::Unchecked => CheckState::Checked,
42 CheckState::Checked => CheckState::Indeterminate,
43 CheckState::Indeterminate => CheckState::Unchecked,
44 }
45 }
46}
47
48impl From<bool> for CheckState {
49 fn from(checked: bool) -> Self {
50 if checked {
51 CheckState::Checked
52 } else {
53 CheckState::Unchecked
54 }
55 }
56}