diff --git a/examples/list_view.rs b/examples/list_view.rs index 3ca0d70..cd9e32a 100644 --- a/examples/list_view.rs +++ b/examples/list_view.rs @@ -10,10 +10,15 @@ fn main() { siv.add_layer(Dialog::new(ListView::new() .child("Name", EditView::new().min_length(10)) .child("Email", LinearLayout::horizontal() - .child(EditView::new().min_length(15)) + .child(EditView::new().min_length(15).disabled().with_id("email1")) .child(TextView::new("@")) - .child(EditView::new().min_length(10))) - .child("Receive spam?", Checkbox::new()) + .child(EditView::new().min_length(10).disabled().with_id("email2"))) + .child("Receive spam?", Checkbox::new().on_change(|s, checked| { + for name in &["email1", "email2"] { + let view: &mut EditView = s.find_id(name).unwrap(); + view.set_enabled(checked); + } + })) .delimiter() .with(|list| { for i in 0..50 { diff --git a/src/view/checkbox.rs b/src/view/checkbox.rs index f0dce7d..fd72662 100644 --- a/src/view/checkbox.rs +++ b/src/view/checkbox.rs @@ -1,15 +1,19 @@ use With; +use Cursive; use Printer; use vec::Vec2; use view::View; use event::{Event, EventResult, Key}; use direction::Direction; +use std::rc::Rc; + /// Checkable box. -#[derive(Debug)] pub struct Checkbox { checked: bool, + + on_change: Option>, } new_default!(Checkbox); @@ -17,24 +21,40 @@ new_default!(Checkbox); impl Checkbox { /// Creates a new, unchecked checkbox. pub fn new() -> Self { - Checkbox { checked: false } + Checkbox { + checked: false, + on_change: None, + } + } + + /// Sets a callback to be used when the state changes. + pub fn set_on_change(&mut self, on_change: F) { + self.on_change = Some(Rc::new(on_change)); + } + + /// Sets a callback to be used when the state changes. + /// + /// Chainable variant. + pub fn on_change(self, on_change: F) -> Self { + self.with(|s| s.set_on_change(on_change)) } /// Toggles the checkbox state. - pub fn toggle(&mut self) { - self.checked = !self.checked; + pub fn toggle(&mut self) -> EventResult { + let checked = !self.checked; + self.set_checked(checked) } /// Check the checkbox. - pub fn check(&mut self) { - self.checked = true; + pub fn check(&mut self) -> EventResult { + self.set_checked(true) } /// Check the checkbox. /// /// Chainable variant. pub fn checked(self) -> Self { - self.with(Self::check) + self.with(|s| {s.check();}) } /// Returns `true` if the checkbox is checked. @@ -43,15 +63,26 @@ impl Checkbox { } /// Uncheck the checkbox. - pub fn uncheck(&mut self) { - self.checked = false; + pub fn uncheck(&mut self) -> EventResult { + self.set_checked(false) } /// Uncheck the checkbox. /// /// Chainable variant. pub fn unchecked(self) -> Self { - self.with(Self::uncheck) + self.with(|s| { s.uncheck(); }) + } + + /// Sets the checkbox state. + pub fn set_checked(&mut self, checked: bool) -> EventResult { + self.checked = checked; + if let Some(ref on_change) = self.on_change { + let on_change = on_change.clone(); + EventResult::with_cb(move |s| on_change(s, checked)) + } else { + EventResult::Consumed(None) + } } } @@ -78,9 +109,7 @@ impl View for Checkbox { match event { Event::Key(Key::Enter) | Event::Char(' ') => self.toggle(), - _ => return EventResult::Ignored, + _ => EventResult::Ignored, } - - EventResult::Consumed(None) } } diff --git a/src/view/edit_view.rs b/src/view/edit_view.rs index 889d2e9..6355b3d 100644 --- a/src/view/edit_view.rs +++ b/src/view/edit_view.rs @@ -1,6 +1,7 @@ use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; +use With; use direction::Direction; use theme::{ColorStyle, Effect}; use vec::Vec2; @@ -23,8 +24,9 @@ pub struct EditView { /// (When the content is too long for the display, we hide part of it) offset: usize, /// Last display length, to know the possible offset range - last_length: usize, /* scrollable: bool, - * TODO: add a max text length? */ + last_length: usize, + + enabled: bool, } new_default!(EditView); @@ -38,9 +40,39 @@ impl EditView { offset: 0, min_length: 1, last_length: 0, // scrollable: false, + enabled: true, } } + /// Disables this view. + /// + /// A disabled view cannot be selected. + pub fn disable(&mut self) { + self.enabled = false; + } + + /// Disables this view. + /// + /// Chainable variant. + pub fn disabled(self) -> Self { + self.with(Self::disable) + } + + /// Re-enables this view. + pub fn enable(&mut self) { + self.enabled = true; + } + + /// Enable or disable this view. + pub fn set_enabled(&mut self, enabled: bool) { + self.enabled = enabled; + } + + /// Returns `true` if this view is enabled. + pub fn is_enabled(&self) -> bool { + self.enabled + } + /// Replace the entire content of the view with the given one. pub fn set_content(&mut self, content: &str) { self.offset = 0; @@ -83,7 +115,12 @@ impl View for EditView { let width = self.content.width(); printer.with_color(ColorStyle::Secondary, |printer| { - printer.with_effect(Effect::Reverse, |printer| { + let effect = if self.enabled { + Effect::Reverse + } else { + Effect::Simple + }; + printer.with_effect(effect, |printer| { if width < self.last_length { // No problem, everything fits. printer.print((0, 0), &self.content); @@ -145,7 +182,7 @@ impl View for EditView { } fn take_focus(&mut self, _: Direction) -> bool { - true + self.enabled } fn on_event(&mut self, event: Event) -> EventResult { diff --git a/src/view/linear_layout.rs b/src/view/linear_layout.rs index ac58860..ace772c 100644 --- a/src/view/linear_layout.rs +++ b/src/view/linear_layout.rs @@ -1,11 +1,12 @@ use XY; use direction; use view::View; -use view::SizeCache; +use view::{Selector, SizeCache}; use vec::Vec2; use Printer; use event::{Event, EventResult, Key}; +use std::any::Any; use std::cmp::min; /// Arranges its children linearly according to its orientation. @@ -366,4 +367,8 @@ impl View for LinearLayout { res => res, } } + + fn find(&mut self, selector: &Selector) -> Option<&mut Any> { + self.children.iter_mut().filter_map(|c| c.view.find(selector)).next() + } } diff --git a/src/view/list_view.rs b/src/view/list_view.rs index ea4f435..db76a88 100644 --- a/src/view/list_view.rs +++ b/src/view/list_view.rs @@ -2,10 +2,13 @@ use Printer; use With; use vec::Vec2; use view::View; +use view::Selector; use direction; use view::scroll::ScrollBase; use event::{Event, EventResult, Key}; +use std::any::Any; + enum Child { Row(String, Box), Delimiter, @@ -261,4 +264,8 @@ impl View for ListView { self.scrollbase.scroll_to(self.focus); true } + + fn find(&mut self, selector: &Selector) -> Option<&mut Any> { + self.children.iter_mut().filter_map(Child::view).filter_map(|v| v.find(selector)).next() + } }