mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-24 01:46:31 +00:00
163 lines
4.6 KiB
Rust
163 lines
4.6 KiB
Rust
|
use std::rc::Rc;
|
||
|
|
||
|
use With;
|
||
|
use {Cursive, Printer};
|
||
|
use theme::ColorStyle;
|
||
|
use event::{Callback, Event, EventResult, Key};
|
||
|
use vec::Vec2;
|
||
|
use view::View;
|
||
|
use direction::{Direction, Orientation};
|
||
|
|
||
|
/// A horizontal or vertical slider.
|
||
|
pub struct SliderView {
|
||
|
orientation: Orientation,
|
||
|
on_change: Option<Rc<Fn(&mut Cursive, usize)>>,
|
||
|
on_enter: Option<Rc<Fn(&mut Cursive, usize)>>,
|
||
|
value: usize,
|
||
|
max_value: usize,
|
||
|
}
|
||
|
|
||
|
impl SliderView {
|
||
|
/// Creates a new `SliderView` in the given orientation.
|
||
|
///
|
||
|
/// The view will have a fixed length of `max_value`,
|
||
|
/// with one tick per block.
|
||
|
pub fn new(orientation: Orientation, max_value: usize) -> Self {
|
||
|
SliderView {
|
||
|
orientation: orientation,
|
||
|
value: 0,
|
||
|
max_value: max_value,
|
||
|
on_change: None,
|
||
|
on_enter: None,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Creates a new vertical `SliderView`.
|
||
|
pub fn vertical(max_value: usize) -> Self {
|
||
|
Self::new(Orientation::Vertical, max_value)
|
||
|
}
|
||
|
|
||
|
/// Creates a new horizontal `SliderView`.
|
||
|
pub fn horizontal(max_value: usize) -> Self {
|
||
|
Self::new(Orientation::Horizontal, max_value)
|
||
|
}
|
||
|
|
||
|
/// Sets the current value.
|
||
|
///
|
||
|
/// Returns an event result with a possible callback,
|
||
|
/// if `on_change` was set..
|
||
|
pub fn set_value(&mut self, value: usize) -> EventResult {
|
||
|
self.value = value;
|
||
|
self.get_change_result()
|
||
|
}
|
||
|
|
||
|
/// Sets the current value.
|
||
|
///
|
||
|
/// Chainable variant.
|
||
|
pub fn value(self, value: usize) -> Self {
|
||
|
self.with(|s| {
|
||
|
s.set_value(value);
|
||
|
})
|
||
|
}
|
||
|
|
||
|
/// Sets a callback to be called when the slider is moved.
|
||
|
pub fn on_change<F>(mut self, callback: F) -> Self
|
||
|
where F: Fn(&mut Cursive, usize) + 'static
|
||
|
{
|
||
|
self.on_change = Some(Rc::new(callback));
|
||
|
self
|
||
|
}
|
||
|
|
||
|
/// Sets a callback to be called when the <Enter> key is pressed.
|
||
|
pub fn on_enter<F>(mut self, callback: F) -> Self
|
||
|
where F: Fn(&mut Cursive, usize) + 'static
|
||
|
{
|
||
|
self.on_enter = Some(Rc::new(callback));
|
||
|
self
|
||
|
}
|
||
|
|
||
|
fn get_change_result(&self) -> EventResult {
|
||
|
EventResult::Consumed(self.on_change.clone().map(|cb| {
|
||
|
let value = self.value;
|
||
|
Callback::from_fn(move |s| {
|
||
|
cb(s, value);
|
||
|
})
|
||
|
}))
|
||
|
}
|
||
|
|
||
|
fn slide_plus(&mut self) -> EventResult {
|
||
|
if self.value + 1 < self.max_value {
|
||
|
self.value += 1;
|
||
|
self.get_change_result()
|
||
|
} else {
|
||
|
EventResult::Ignored
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn slide_minus(&mut self) -> EventResult {
|
||
|
if self.value > 0 {
|
||
|
self.value -= 1;
|
||
|
self.get_change_result()
|
||
|
} else {
|
||
|
EventResult::Ignored
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl View for SliderView {
|
||
|
fn draw(&self, printer: &Printer) {
|
||
|
match self.orientation {
|
||
|
Orientation::Vertical => {
|
||
|
printer.print_vline((0, 0), self.max_value, "|")
|
||
|
}
|
||
|
Orientation::Horizontal => {
|
||
|
printer.print_hline((0, 0), self.max_value, "-")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let color = if printer.focused {
|
||
|
ColorStyle::Highlight
|
||
|
} else {
|
||
|
ColorStyle::HighlightInactive
|
||
|
};
|
||
|
printer.with_color(color, |printer| {
|
||
|
printer.print(self.orientation.make_vec(self.value, 0), " ");
|
||
|
});
|
||
|
}
|
||
|
|
||
|
fn get_min_size(&mut self, _: Vec2) -> Vec2 {
|
||
|
self.orientation.make_vec(self.max_value, 1)
|
||
|
}
|
||
|
|
||
|
fn on_event(&mut self, event: Event) -> EventResult {
|
||
|
match event {
|
||
|
Event::Key(Key::Left) if self.orientation ==
|
||
|
Orientation::Horizontal => {
|
||
|
self.slide_minus()
|
||
|
}
|
||
|
Event::Key(Key::Right) if self.orientation ==
|
||
|
Orientation::Horizontal => {
|
||
|
self.slide_plus()
|
||
|
}
|
||
|
Event::Key(Key::Up) if self.orientation ==
|
||
|
Orientation::Vertical => self.slide_minus(),
|
||
|
Event::Key(Key::Down) if self.orientation ==
|
||
|
Orientation::Vertical => {
|
||
|
self.slide_plus()
|
||
|
}
|
||
|
Event::Key(Key::Enter) if self.on_enter.is_some() => {
|
||
|
let value = self.value;
|
||
|
let cb = self.on_enter.clone().unwrap();
|
||
|
EventResult::with_cb(move |s| {
|
||
|
cb(s, value);
|
||
|
})
|
||
|
}
|
||
|
_ => EventResult::Ignored,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn take_focus(&mut self, _: Direction) -> bool {
|
||
|
true
|
||
|
}
|
||
|
}
|