mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Add SliderView
This commit is contained in:
parent
921e4a451e
commit
ce6992a8c5
25
examples/slider.rs
Normal file
25
examples/slider.rs
Normal file
@ -0,0 +1,25 @@
|
||||
extern crate cursive;
|
||||
|
||||
use cursive::prelude::*;
|
||||
|
||||
fn main() {
|
||||
let mut siv = Cursive::new();
|
||||
|
||||
// Let's add a simple slider in a dialog.
|
||||
// Moving the slider will update the dialog's title.
|
||||
// And pressing "Enter" will show a new dialog.
|
||||
siv.add_layer(Dialog::new(SliderView::horizontal(15)
|
||||
.value(7)
|
||||
.on_change(|s, v| {
|
||||
let title = format!("[ {} ]", v);
|
||||
s.find_id::<Dialog>("dialog").unwrap().set_title(title);
|
||||
})
|
||||
.on_enter(|s, v| {
|
||||
s.pop_layer();
|
||||
s.add_layer(Dialog::text(format!("Lucky number {}!", v))
|
||||
.button("Ok", Cursive::quit));
|
||||
}))
|
||||
.with_id("dialog"));
|
||||
|
||||
siv.run();
|
||||
}
|
@ -69,9 +69,10 @@ impl Orientation {
|
||||
}
|
||||
|
||||
/// Creates a new `Vec2` with `value` in `self`'s axis.
|
||||
pub fn make_vec(&self, value: usize) -> Vec2 {
|
||||
pub fn make_vec(&self, main_axis: usize, second_axis: usize) -> Vec2 {
|
||||
let mut result = Vec2::zero();
|
||||
*self.get_ref(&mut result) = value;
|
||||
*self.get_ref(&mut result) = main_axis;
|
||||
*self.swap().get_ref(&mut result) = second_axis;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,6 @@ pub use event::{Event, Key};
|
||||
pub use view::{Boxable, Identifiable, Selector, View};
|
||||
pub use views::{BoxView, Button, Checkbox, Dialog, EditView, IdView,
|
||||
KeyEventView, LinearLayout, ListView, Panel, ProgressBar,
|
||||
SelectView, TextArea, TextView};
|
||||
SelectView, SliderView, TextArea, TextView};
|
||||
pub use vec::Vec2;
|
||||
pub use menu::MenuTree;
|
||||
|
@ -102,6 +102,7 @@ impl Dialog {
|
||||
}
|
||||
|
||||
/// Sets the horizontal alignment for the buttons, if any.
|
||||
///
|
||||
/// Only works if the buttons are as a row at the bottom of the dialog.
|
||||
pub fn h_align(mut self, h: HAlign) -> Self {
|
||||
self.align.h = h;
|
||||
@ -110,6 +111,7 @@ impl Dialog {
|
||||
}
|
||||
|
||||
/// Sets the vertical alignment for the buttons, if any.
|
||||
///
|
||||
/// Only works if the buttons are as a column to the right of the dialog.
|
||||
pub fn v_align(mut self, v: VAlign) -> Self {
|
||||
self.align.v = v;
|
||||
@ -123,10 +125,15 @@ impl Dialog {
|
||||
}
|
||||
|
||||
/// Sets the title of the dialog.
|
||||
///
|
||||
/// If not empty, it will be visible at the top.
|
||||
pub fn title<S: Into<String>>(mut self, label: S) -> Self {
|
||||
pub fn title<S: Into<String>>(self, label: S) -> Self {
|
||||
self.with(|s| s.set_title(label))
|
||||
}
|
||||
|
||||
/// Sets the title of the dialog.
|
||||
pub fn set_title<S: Into<String>>(&mut self, label: S) {
|
||||
self.title = label.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the padding in the dialog (around content and buttons).
|
||||
|
@ -137,9 +137,9 @@ impl EditView {
|
||||
///
|
||||
/// `callback` will be called with the view
|
||||
/// content and the current cursor position.
|
||||
pub fn on_edit<F: Fn(&mut Cursive, &str, usize) + 'static>(mut self,
|
||||
callback: F)
|
||||
-> Self {
|
||||
pub fn on_edit<F>(mut self, callback: F) -> Self
|
||||
where F: Fn(&mut Cursive, &str, usize) + 'static
|
||||
{
|
||||
self.on_edit = Some(Rc::new(callback));
|
||||
self
|
||||
}
|
||||
@ -147,9 +147,9 @@ impl EditView {
|
||||
/// Sets a callback to be called when `<Enter>` is pressed.
|
||||
///
|
||||
/// `callback` will be given the content of the view.
|
||||
pub fn on_submit<F: Fn(&mut Cursive, &str) + 'static>(mut self,
|
||||
callback: F)
|
||||
-> Self {
|
||||
pub fn on_submit<F>(mut self, callback: F) -> Self
|
||||
where F: Fn(&mut Cursive, &str) + 'static
|
||||
{
|
||||
self.on_submit = Some(Rc::new(callback));
|
||||
self
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ mod menu_popup;
|
||||
mod panel;
|
||||
mod progress_bar;
|
||||
mod select_view;
|
||||
mod slider_view;
|
||||
mod shadow_view;
|
||||
mod sized_view;
|
||||
mod stack_view;
|
||||
@ -37,6 +38,7 @@ pub use self::menu_popup::MenuPopup;
|
||||
pub use self::panel::Panel;
|
||||
pub use self::progress_bar::{Counter, ProgressBar};
|
||||
pub use self::select_view::SelectView;
|
||||
pub use self::slider_view::SliderView;
|
||||
pub use self::shadow_view::ShadowView;
|
||||
pub use self::sized_view::SizedView;
|
||||
pub use self::stack_view::StackView;
|
||||
|
162
src/views/slider_view.rs
Normal file
162
src/views/slider_view.rs
Normal file
@ -0,0 +1,162 @@
|
||||
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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user