use super::cluster::{Cluster, ClusterState};
use super::view::View;
use crate::core::event::Event;
use crate::core::geometry::Rect;
use crate::core::state::StateFlags;
use crate::terminal::Terminal;
#[derive(Debug)]
pub struct CheckBox {
bounds: Rect,
label: String,
cluster_state: ClusterState,
state: StateFlags,
palette_chain: Option<crate::core::palette_chain::PaletteChainNode>,
}
impl CheckBox {
pub fn new(bounds: Rect, label: &str) -> Self {
CheckBox {
bounds,
label: label.to_string(),
cluster_state: ClusterState::new(),
state: 0,
palette_chain: None,
}
}
pub fn set_checked(&mut self, checked: bool) {
self.cluster_state.set_value(if checked { 1 } else { 0 });
}
pub fn is_checked(&self) -> bool {
self.cluster_state.value != 0
}
pub fn toggle(&mut self) {
self.cluster_state.toggle();
}
}
impl View for CheckBox {
fn bounds(&self) -> Rect {
self.bounds
}
fn set_bounds(&mut self, bounds: Rect) {
self.bounds = bounds;
}
fn handle_event(&mut self, event: &mut Event) {
self.handle_cluster_event(event);
}
fn draw(&mut self, terminal: &mut Terminal) {
self.draw_cluster(terminal);
}
fn can_focus(&self) -> bool {
true
}
fn state(&self) -> StateFlags {
self.state
}
fn set_state(&mut self, state: StateFlags) {
self.state = state;
}
fn set_palette_chain(&mut self, node: Option<crate::core::palette_chain::PaletteChainNode>) {
self.palette_chain = node;
}
fn get_palette_chain(&self) -> Option<&crate::core::palette_chain::PaletteChainNode> {
self.palette_chain.as_ref()
}
fn get_palette(&self) -> Option<crate::core::palette::Palette> {
use crate::core::palette::{Palette, palettes};
Some(Palette::from_slice(palettes::CP_CLUSTER))
}
}
impl Cluster for CheckBox {
fn cluster_state(&self) -> &ClusterState {
&self.cluster_state
}
fn cluster_state_mut(&mut self) -> &mut ClusterState {
&mut self.cluster_state
}
fn get_label(&self) -> &str {
&self.label
}
fn get_marker(&self) -> &str {
if self.is_checked() { "[X] " } else { "[ ] " }
}
fn on_space_pressed(&mut self) {
self.toggle();
}
}
pub struct CheckBoxBuilder {
bounds: Option<Rect>,
label: Option<String>,
checked: bool,
}
impl CheckBoxBuilder {
pub fn new() -> Self {
Self {
bounds: None,
label: None,
checked: false,
}
}
#[must_use]
pub fn bounds(mut self, bounds: Rect) -> Self {
self.bounds = Some(bounds);
self
}
#[must_use]
pub fn label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
#[must_use]
pub fn checked(mut self, checked: bool) -> Self {
self.checked = checked;
self
}
pub fn build(self) -> CheckBox {
let bounds = self.bounds.expect("CheckBox bounds must be set");
let label = self.label.expect("CheckBox label must be set");
let mut checkbox = CheckBox::new(bounds, &label);
if self.checked {
checkbox.set_checked(true);
}
checkbox
}
pub fn build_boxed(self) -> Box<CheckBox> {
Box::new(self.build())
}
}
impl Default for CheckBoxBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_checkbox_creation() {
let checkbox = CheckBox::new(Rect::new(0, 0, 20, 1), "Test option");
assert!(!checkbox.is_checked());
assert_eq!(checkbox.label, "Test option");
}
#[test]
fn test_checkbox_toggle() {
let mut checkbox = CheckBox::new(Rect::new(0, 0, 20, 1), "Test");
assert!(!checkbox.is_checked());
checkbox.toggle();
assert!(checkbox.is_checked());
checkbox.toggle();
assert!(!checkbox.is_checked());
}
#[test]
fn test_checkbox_set_checked() {
let mut checkbox = CheckBox::new(Rect::new(0, 0, 20, 1), "Test");
checkbox.set_checked(true);
assert!(checkbox.is_checked());
checkbox.set_checked(false);
assert!(!checkbox.is_checked());
}
#[test]
fn test_checkbox_builder() {
let checkbox = CheckBoxBuilder::new()
.bounds(Rect::new(3, 5, 30, 6))
.label("Test Feature")
.build();
assert_eq!(checkbox.label, "Test Feature");
assert!(!checkbox.is_checked());
}
#[test]
fn test_checkbox_builder_checked() {
let checkbox = CheckBoxBuilder::new()
.bounds(Rect::new(3, 5, 30, 6))
.label("Auto-save")
.checked(true)
.build();
assert!(checkbox.is_checked());
}
#[test]
fn mouse_click_toggles_checkbox() {
use crate::core::event::{Event, EventType, MB_LEFT_BUTTON};
use crate::core::geometry::Point;
let mut cb = CheckBox::new(Rect::new(0, 0, 20, 1), "Check me");
let mut ev = Event::mouse(
EventType::MouseDown,
Point::new(2, 0),
MB_LEFT_BUTTON,
false,
);
cb.handle_event(&mut ev);
assert!(cb.is_checked());
assert_eq!(ev.what, EventType::Nothing);
let mut ev = Event::mouse(
EventType::MouseDown,
Point::new(2, 0),
MB_LEFT_BUTTON,
false,
);
cb.handle_event(&mut ev);
assert!(!cb.is_checked());
}
}