1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
use Basalt;
use std::sync::Arc;
use super::bin::{KeepAlive,Bin,BinStyle};
use parking_lot::Mutex;
use std::thread;
use input::*;

/// Simple checkbox. Provides a change hook and the ability to get the state.
/// When checked, the inner box is set to being visible and vise versa.

impl KeepAlive for CheckBox {}

pub struct CheckBox {
	pub basalt: Arc<Basalt>,
	pub inner_box: Arc<Bin>,
	pub outer_box: Arc<Bin>,
	checked: Mutex<bool>,
	on_change: Mutex<Vec<Arc<dyn Fn(bool) + Send + Sync>>>,
}

impl CheckBox {
	pub fn is_checked(&self) -> bool {
		*self.checked.lock()
	}
	
	pub fn set(&self, check: bool) {
		*self.checked.lock() = check;
		self.update(Some(check));
		self.call_on_change(Some(check));
	}
	
	pub fn check(&self) {
		self.set(true);
	}
	
	pub fn uncheck(&self) {
		self.set(false);
	}
	
	pub fn toggle(&self) {
		let mut checked = self.checked.lock();
		*checked = !*checked;
		self.update(Some(*checked));
		self.call_on_change(Some(*checked));
	}
	
	pub fn on_change(&self, func: Arc<dyn Fn(bool) + Send + Sync>) {
		self.on_change.lock().push(func);
	}
	
	fn call_on_change(&self, checked_op: Option<bool>) {
		let checked = match checked_op {
			Some(some) => some,
			None => self.is_checked()
		};
	
		let on_change = self.on_change.lock().clone().into_iter();
		
		thread::spawn(move || {
			for func in on_change {
				func(checked);
			}
		});
	}
	
	fn update(&self, checked_op: Option<bool>) {
		let checked = match checked_op {
			Some(some) => some,
			None => self.is_checked()
		};
	
		self.inner_box.style_update(BinStyle {
			hidden: Some(!checked),
			.. self.inner_box.style_copy()
		});
	}
	
	pub fn new(basalt: Arc<Basalt>) -> Arc<Self> {
		let mut bins = basalt.interface_ref().new_bins(2);
		let checkbox = Arc::new(CheckBox {
			basalt: basalt,
			inner_box: bins.pop().unwrap(),
			outer_box: bins.pop().unwrap(),
			checked: Mutex::new(false),
			on_change: Mutex::new(Vec::new()),
		});
		
		checkbox.outer_box.add_child(checkbox.inner_box.clone());
		let checkbox_wk = Arc::downgrade(&checkbox);
		
		checkbox.outer_box.on_mouse_press(MouseButton::Left, Arc::new(move |_, _| {
			match checkbox_wk.upgrade() {
				Some(checkbox) => checkbox.toggle(),
				None => return
			}
		}));
		
		checkbox
	}
}