mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-13 20:53:07 +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.
|
/// 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();
|
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
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,6 @@ pub use event::{Event, Key};
|
|||||||
pub use view::{Boxable, Identifiable, Selector, View};
|
pub use view::{Boxable, Identifiable, Selector, View};
|
||||||
pub use views::{BoxView, Button, Checkbox, Dialog, EditView, IdView,
|
pub use views::{BoxView, Button, Checkbox, Dialog, EditView, IdView,
|
||||||
KeyEventView, LinearLayout, ListView, Panel, ProgressBar,
|
KeyEventView, LinearLayout, ListView, Panel, ProgressBar,
|
||||||
SelectView, TextArea, TextView};
|
SelectView, SliderView, TextArea, TextView};
|
||||||
pub use vec::Vec2;
|
pub use vec::Vec2;
|
||||||
pub use menu::MenuTree;
|
pub use menu::MenuTree;
|
||||||
|
@ -102,6 +102,7 @@ impl Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the horizontal alignment for the buttons, if any.
|
/// Sets the horizontal alignment for the buttons, if any.
|
||||||
|
///
|
||||||
/// Only works if the buttons are as a row at the bottom of the dialog.
|
/// Only works if the buttons are as a row at the bottom of the dialog.
|
||||||
pub fn h_align(mut self, h: HAlign) -> Self {
|
pub fn h_align(mut self, h: HAlign) -> Self {
|
||||||
self.align.h = h;
|
self.align.h = h;
|
||||||
@ -110,6 +111,7 @@ impl Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the vertical alignment for the buttons, if any.
|
/// Sets the vertical alignment for the buttons, if any.
|
||||||
|
///
|
||||||
/// Only works if the buttons are as a column to the right of the dialog.
|
/// Only works if the buttons are as a column to the right of the dialog.
|
||||||
pub fn v_align(mut self, v: VAlign) -> Self {
|
pub fn v_align(mut self, v: VAlign) -> Self {
|
||||||
self.align.v = v;
|
self.align.v = v;
|
||||||
@ -123,10 +125,15 @@ impl Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the title of the dialog.
|
/// Sets the title of the dialog.
|
||||||
|
///
|
||||||
/// If not empty, it will be visible at the top.
|
/// 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.title = label.into();
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the padding in the dialog (around content and buttons).
|
/// Sets the padding in the dialog (around content and buttons).
|
||||||
|
@ -137,9 +137,9 @@ impl EditView {
|
|||||||
///
|
///
|
||||||
/// `callback` will be called with the view
|
/// `callback` will be called with the view
|
||||||
/// content and the current cursor position.
|
/// content and the current cursor position.
|
||||||
pub fn on_edit<F: Fn(&mut Cursive, &str, usize) + 'static>(mut self,
|
pub fn on_edit<F>(mut self, callback: F) -> Self
|
||||||
callback: F)
|
where F: Fn(&mut Cursive, &str, usize) + 'static
|
||||||
-> Self {
|
{
|
||||||
self.on_edit = Some(Rc::new(callback));
|
self.on_edit = Some(Rc::new(callback));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -147,9 +147,9 @@ impl EditView {
|
|||||||
/// Sets a callback to be called when `<Enter>` is pressed.
|
/// Sets a callback to be called when `<Enter>` is pressed.
|
||||||
///
|
///
|
||||||
/// `callback` will be given the content of the view.
|
/// `callback` will be given the content of the view.
|
||||||
pub fn on_submit<F: Fn(&mut Cursive, &str) + 'static>(mut self,
|
pub fn on_submit<F>(mut self, callback: F) -> Self
|
||||||
callback: F)
|
where F: Fn(&mut Cursive, &str) + 'static
|
||||||
-> Self {
|
{
|
||||||
self.on_submit = Some(Rc::new(callback));
|
self.on_submit = Some(Rc::new(callback));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ mod menu_popup;
|
|||||||
mod panel;
|
mod panel;
|
||||||
mod progress_bar;
|
mod progress_bar;
|
||||||
mod select_view;
|
mod select_view;
|
||||||
|
mod slider_view;
|
||||||
mod shadow_view;
|
mod shadow_view;
|
||||||
mod sized_view;
|
mod sized_view;
|
||||||
mod stack_view;
|
mod stack_view;
|
||||||
@ -37,6 +38,7 @@ pub use self::menu_popup::MenuPopup;
|
|||||||
pub use self::panel::Panel;
|
pub use self::panel::Panel;
|
||||||
pub use self::progress_bar::{Counter, ProgressBar};
|
pub use self::progress_bar::{Counter, ProgressBar};
|
||||||
pub use self::select_view::SelectView;
|
pub use self::select_view::SelectView;
|
||||||
|
pub use self::slider_view::SliderView;
|
||||||
pub use self::shadow_view::ShadowView;
|
pub use self::shadow_view::ShadowView;
|
||||||
pub use self::sized_view::SizedView;
|
pub use self::sized_view::SizedView;
|
||||||
pub use self::stack_view::StackView;
|
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