use std::iter::repeat;
use super::{InterfaceItem, InterfaceItemBase};
use crate::text_processing::{ProcessedChar, TextProcessor};
use crate::{Events, MouseButton, TextBuffer, TextStyle, VirtualKeyCode};
#[derive(Default)]
pub struct CheckboxGroup {
selected_idx: Option<u32>,
force_one_checked: Option<u32>,
}
impl CheckboxGroup {
pub fn new() -> CheckboxGroup {
CheckboxGroup {
selected_idx: None,
force_one_checked: None,
}
}
pub fn with_force_one_checked(mut self, force_one_checked: Option<u32>) -> CheckboxGroup {
self.force_one_checked = force_one_checked;
self
}
pub fn update(&mut self, checkboxes: &mut [&mut Checkbox]) {
let mut selection_changed = false;
let mut any_selected = false;
for idx in 0..checkboxes.len() {
let curr_is_checked;
if let Some(checkbox) = checkboxes.get(idx) {
curr_is_checked = checkbox.is_checked();
} else {
curr_is_checked = false;
}
if curr_is_checked {
any_selected = true;
}
if let Some(selected_idx) = self.selected_idx {
if curr_is_checked && idx as u32 != selected_idx {
if !selection_changed {
if let Some(checkbox) = checkboxes.get_mut(selected_idx as usize) {
checkbox.set_checked(false);
}
self.selected_idx = Some(idx as u32);
selection_changed = true;
} else if let Some(checkbox) = checkboxes.get_mut(idx) {
checkbox.set_checked(false);
}
}
} else if curr_is_checked {
self.selected_idx = Some(idx as u32);
selection_changed = true;
}
}
if !any_selected {
if let Some(forced_idx) = self.force_one_checked {
if let Some(idx) = self.selected_idx {
if let Some(checkbox) = checkboxes.get_mut(idx as usize) {
checkbox.set_checked(true);
}
} else {
if checkboxes.len() > forced_idx as usize {
let checkbox = &mut checkboxes[forced_idx as usize];
checkbox.set_checked(true);
self.selected_idx = Some(forced_idx);
} else if let Some(checkbox) = checkboxes.get_mut(0) {
checkbox.set_checked(true);
self.selected_idx = Some(0);
}
self.selected_idx = None;
}
} else {
self.selected_idx = None;
}
}
}
pub fn get_selection_idx(&self) -> Option<u32> {
self.selected_idx
}
}
#[derive(Debug, Clone)]
pub struct Checkbox {
pub unfocused_style: TextStyle,
pub focused_style: TextStyle,
pub button_press_inputs: Vec<VirtualKeyCode>,
pub mouse_button_press_inputs: Vec<MouseButton>,
base: InterfaceItemBase,
text: String,
prefix: String,
suffix: String,
checked_text: String,
processed_text: Vec<ProcessedChar>,
needs_processing: bool,
checked: bool,
was_just_pressed: bool,
}
impl Checkbox {
pub fn new<T: Into<String>>(text: T) -> Checkbox {
Checkbox {
unfocused_style: TextStyle {
bg_color: [0.0, 0.0, 0.0, 0.0],
fg_color: [0.8, 0.8, 0.8, 1.0],
..Default::default()
},
focused_style: TextStyle {
bg_color: [0.8, 0.8, 0.8, 1.0],
fg_color: [0.2, 0.2, 0.2, 1.0],
..Default::default()
},
base: InterfaceItemBase::new(true),
text: text.into(),
prefix: "[".to_owned(),
suffix: "]".to_owned(),
checked_text: "X".to_owned(),
processed_text: Vec::new(),
needs_processing: true,
checked: false,
was_just_pressed: false,
button_press_inputs: vec![VirtualKeyCode::Return],
mouse_button_press_inputs: Vec::new(),
}
}
with_base!(Checkbox);
with_set_pressable!(Checkbox);
with_style!(Checkbox);
pub fn with_text<T: Into<String>>(mut self, text: T) -> Checkbox {
self.text = text.into();
self
}
pub fn with_prefix<T: Into<String>>(mut self, prefix: T) -> Checkbox {
self.prefix = prefix.into();
self
}
pub fn with_suffix<T: Into<String>>(mut self, suffix: T) -> Checkbox {
self.suffix = suffix.into();
self
}
pub fn with_checked_text<T: Into<String>>(mut self, checked_text: T) -> Checkbox {
self.checked_text = checked_text.into();
self
}
pub fn with_checked(mut self, checked: bool) -> Checkbox {
self.checked = checked;
self
}
pub fn set_text<T: Into<String>>(&mut self, text: T) {
self.text = text.into();
self.base.dirty = true;
self.needs_processing = true;
}
pub fn set_prefix<T: Into<String>>(&mut self, prefix: T) {
self.prefix = prefix.into();
self.base.dirty = true;
self.needs_processing = true;
}
pub fn set_suffix<T: Into<String>>(&mut self, suffix: T) {
self.suffix = suffix.into();
self.base.dirty = true;
self.needs_processing = true;
}
pub fn set_checked_text<T: Into<String>>(mut self, checked_text: T) {
self.checked_text = checked_text.into();
self.needs_processing = true;
}
pub fn get_text(&self) -> String {
self.text.clone()
}
pub fn get_prefix(&self) -> String {
self.prefix.clone()
}
pub fn get_suffix(&self) -> String {
self.suffix.clone()
}
pub fn set_checked(&mut self, checked: bool) {
if self.checked != checked {
self.base.dirty = true;
self.needs_processing = true;
}
self.checked = checked;
}
pub fn is_checked(&self) -> bool {
self.checked
}
}
impl InterfaceItem for Checkbox {
fn get_base(&self) -> &InterfaceItemBase {
&self.base
}
fn get_mut_base(&mut self) -> &mut InterfaceItemBase {
&mut self.base
}
fn get_total_width(&self) -> u32 {
(self.text.chars().count()
+ self.prefix.chars().count()
+ self.checked_text.chars().count()
+ self.suffix.chars().count()) as u32
}
fn get_total_height(&self) -> u32 {
1
}
fn draw(&mut self, text_buffer: &mut TextBuffer) {
self.base.dirty = false;
text_buffer.cursor.style = if self.base.is_focused() {
self.focused_style
} else {
self.unfocused_style
};
text_buffer.cursor.move_to(self.base.x, self.base.y);
text_buffer.write_processed(&self.processed_text);
}
fn handle_events(&mut self, events: &Events) -> bool {
self.was_just_pressed = false;
for curr in &self.button_press_inputs {
if events.keyboard.was_just_pressed(*curr) {
self.was_just_pressed = true;
self.set_checked(!self.checked);
return true;
}
}
for curr in &self.mouse_button_press_inputs {
if events.mouse.was_just_pressed(*curr) {
self.was_just_pressed = true;
self.set_checked(!self.checked);
return true;
}
}
false
}
fn update(&mut self, _: f32, processor: &TextProcessor) {
if self.needs_processing {
let checked_text = if self.checked {
(&self.checked_text).to_owned()
} else {
repeat(" ")
.take(self.checked_text.chars().count())
.collect()
};
let text = (&self.text).to_owned() + &self.prefix + &checked_text + &self.suffix;
self.processed_text = processor.process(vec![text.into()]);
self.needs_processing = false;
}
}
}