mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Add ProgressBar
Also make Callback its own NewType to add comversion methods.
This commit is contained in:
parent
10e072c140
commit
e29511e757
51
examples/progress.rs
Normal file
51
examples/progress.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
extern crate cursive;
|
||||||
|
|
||||||
|
use cursive::prelude::*;
|
||||||
|
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut siv = Cursive::new();
|
||||||
|
|
||||||
|
siv.add_layer(Dialog::new(Button::new("Start", |s| {
|
||||||
|
// These two values will allow us to communicate.
|
||||||
|
let value = Arc::new(AtomicUsize::new(0));
|
||||||
|
let cb = Arc::new(Mutex::new(None));
|
||||||
|
|
||||||
|
let n_max = 1000;
|
||||||
|
|
||||||
|
s.find_id::<Dialog>("dialog")
|
||||||
|
.unwrap()
|
||||||
|
.set_content(ProgressBar::new()
|
||||||
|
.range(0, n_max)
|
||||||
|
.with_value(value.clone())
|
||||||
|
.with_callback(cb.clone()));
|
||||||
|
|
||||||
|
// Spawn a thread to process things in the background.
|
||||||
|
thread::spawn(move || {
|
||||||
|
for _ in 0..n_max {
|
||||||
|
thread::sleep(Duration::from_millis(3));
|
||||||
|
value.fetch_add(1, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
*cb.lock().unwrap() = Some(Box::new(move |s| {
|
||||||
|
s.pop_layer();
|
||||||
|
s.add_layer(Dialog::new(TextView::new("Phew, that was \
|
||||||
|
a lot of work!"))
|
||||||
|
.title("Work done!")
|
||||||
|
.button("Sure!", |s| s.quit()));
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
}))
|
||||||
|
.title("Progress bar example")
|
||||||
|
.padding_top(1)
|
||||||
|
.padding_bottom(1)
|
||||||
|
.with_id("dialog"));
|
||||||
|
|
||||||
|
siv.set_fps(10);
|
||||||
|
|
||||||
|
siv.run();
|
||||||
|
}
|
@ -105,6 +105,9 @@ impl backend::Backend for NcursesBackend {
|
|||||||
fn parse_ncurses_char(ch: i32) -> Event {
|
fn parse_ncurses_char(ch: i32) -> Event {
|
||||||
|
|
||||||
match ch {
|
match ch {
|
||||||
|
// Value sent by ncurses when nothing happens
|
||||||
|
-1 => Event::Refresh,
|
||||||
|
|
||||||
// Values under 256 are chars and control values
|
// Values under 256 are chars and control values
|
||||||
//
|
//
|
||||||
// Tab is '\t'
|
// Tab is '\t'
|
||||||
|
66
src/event.rs
66
src/event.rs
@ -14,12 +14,47 @@
|
|||||||
//! table is checked.
|
//! table is checked.
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use Cursive;
|
use Cursive;
|
||||||
|
|
||||||
/// Callback is a function that can be triggered by an event.
|
/// Callback is a function that can be triggered by an event.
|
||||||
/// It has a mutable access to the cursive root.
|
/// It has a mutable access to the cursive root.
|
||||||
pub type Callback = Rc<Fn(&mut Cursive)>;
|
#[derive(Clone)]
|
||||||
|
pub struct Callback(Rc<Box<Fn(&mut Cursive)>>);
|
||||||
|
// TODO: remove the Box when Box<T: Sized> -> Rc<T> is possible
|
||||||
|
|
||||||
|
impl Callback {
|
||||||
|
/// Wraps the given function into a `Callback` object.
|
||||||
|
pub fn from_fn<F: Fn(&mut Cursive) + 'static>(f: F) -> Self {
|
||||||
|
Callback(Rc::new(Box::new(f)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Callback {
|
||||||
|
type Target = Box<Fn(&mut Cursive)>;
|
||||||
|
fn deref<'a>(&'a self) -> &'a Box<Fn(&mut Cursive)> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Rc<Box<Fn(&mut Cursive)>>> for Callback {
|
||||||
|
fn from(f: Rc<Box<Fn(&mut Cursive)>>) -> Self {
|
||||||
|
Callback(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<Fn(&mut Cursive) + Send>> for Callback {
|
||||||
|
fn from(f: Box<Fn(&mut Cursive) + Send>) -> Self {
|
||||||
|
Callback(Rc::new(f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<Fn(&mut Cursive)>> for Callback {
|
||||||
|
fn from(f: Box<Fn(&mut Cursive)>) -> Self {
|
||||||
|
Callback(Rc::new(f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Answer to an event notification.
|
/// Answer to an event notification.
|
||||||
/// The event can be consumed or ignored.
|
/// The event can be consumed or ignored.
|
||||||
@ -27,13 +62,13 @@ pub enum EventResult {
|
|||||||
/// The event was ignored. The parent can keep handling it.
|
/// The event was ignored. The parent can keep handling it.
|
||||||
Ignored,
|
Ignored,
|
||||||
/// The event was consumed. An optionnal callback to run is attached.
|
/// The event was consumed. An optionnal callback to run is attached.
|
||||||
Consumed(Option<Callback>),
|
Consumed(Option<Callback>), // TODO: make this a FnOnce?
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventResult {
|
impl EventResult {
|
||||||
/// Convenient method to create `Consumed(Some(f))`
|
/// Convenient method to create `Consumed(Some(f))`
|
||||||
pub fn with_cb<F: 'static + Fn(&mut Cursive)>(f: F) -> Self {
|
pub fn with_cb<F: 'static + Fn(&mut Cursive)>(f: F) -> Self {
|
||||||
EventResult::Consumed(Some(Rc::new(f)))
|
EventResult::Consumed(Some(Callback::from_fn(f)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if `self` is `EventResult::Consumed`.
|
/// Returns `true` if `self` is `EventResult::Consumed`.
|
||||||
@ -138,29 +173,32 @@ impl Key {
|
|||||||
/// Represents an event as seen by the application.
|
/// Represents an event as seen by the application.
|
||||||
#[derive(PartialEq,Eq,Clone,Copy,Hash,Debug)]
|
#[derive(PartialEq,Eq,Clone,Copy,Hash,Debug)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
/// Event fired when the window is resized
|
/// Event fired when the window is resized.
|
||||||
WindowResize,
|
WindowResize,
|
||||||
|
|
||||||
/// A character was entered (includes numbers, punctuation, ...)
|
/// Event fired regularly when a auto-refresh is set.
|
||||||
|
Refresh,
|
||||||
|
|
||||||
|
/// A character was entered (includes numbers, punctuation, ...).
|
||||||
Char(char),
|
Char(char),
|
||||||
/// A character was entered with the Ctrl key pressed
|
/// A character was entered with the Ctrl key pressed.
|
||||||
CtrlChar(char),
|
CtrlChar(char),
|
||||||
/// A character was entered with the Alt key pressed
|
/// A character was entered with the Alt key pressed.
|
||||||
AltChar(char),
|
AltChar(char),
|
||||||
|
|
||||||
/// A non-character key was pressed
|
/// A non-character key was pressed.
|
||||||
Key(Key),
|
Key(Key),
|
||||||
/// A non-character key was pressed with the Shift key pressed
|
/// A non-character key was pressed with the Shift key pressed.
|
||||||
Shift(Key),
|
Shift(Key),
|
||||||
/// A non-character key was pressed with the Alt key pressed
|
/// A non-character key was pressed with the Alt key pressed.
|
||||||
Alt(Key),
|
Alt(Key),
|
||||||
/// A non-character key was pressed with the Shift and Alt keys pressed
|
/// A non-character key was pressed with the Shift and Alt keys pressed.
|
||||||
AltShift(Key),
|
AltShift(Key),
|
||||||
/// A non-character key was pressed with the Ctrl key pressed
|
/// A non-character key was pressed with the Ctrl key pressed.
|
||||||
Ctrl(Key),
|
Ctrl(Key),
|
||||||
/// A non-character key was pressed with the Ctrl and Shift keys pressed
|
/// A non-character key was pressed with the Ctrl and Shift keys pressed.
|
||||||
CtrlShift(Key),
|
CtrlShift(Key),
|
||||||
/// A non-character key was pressed with the Ctrl and Alt keys pressed
|
/// A non-character key was pressed with the Ctrl and Alt keys pressed.
|
||||||
CtrlAlt(Key),
|
CtrlAlt(Key),
|
||||||
|
|
||||||
/// An unknown event was received.
|
/// An unknown event was received.
|
||||||
|
@ -97,7 +97,6 @@ pub use printer::Printer;
|
|||||||
use backend::{Backend, NcursesBackend};
|
use backend::{Backend, NcursesBackend};
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@ -364,7 +363,7 @@ impl Cursive {
|
|||||||
pub fn add_global_callback<F, E: Into<Event>>(&mut self, event: E, cb: F)
|
pub fn add_global_callback<F, E: Into<Event>>(&mut self, event: E, cb: F)
|
||||||
where F: Fn(&mut Cursive) + 'static
|
where F: Fn(&mut Cursive) + 'static
|
||||||
{
|
{
|
||||||
self.global_callbacks.insert(event.into(), Rc::new(cb));
|
self.global_callbacks.insert(event.into(), Callback::from_fn(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenient method to add a layer to the current screen.
|
/// Convenient method to add a layer to the current screen.
|
||||||
|
@ -98,7 +98,7 @@ impl MenuTree {
|
|||||||
pub fn add_leaf<F: 'static + Fn(&mut Cursive)>(&mut self, title: &str,
|
pub fn add_leaf<F: 'static + Fn(&mut Cursive)>(&mut self, title: &str,
|
||||||
cb: F) {
|
cb: F) {
|
||||||
self.children
|
self.children
|
||||||
.push(MenuItem::Leaf(title.to_string(), Rc::new(cb)));
|
.push(MenuItem::Leaf(title.to_string(), Callback::from_fn(cb)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a actionnable leaf to the end of this tree - chainable variant.
|
/// Adds a actionnable leaf to the end of this tree - chainable variant.
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
pub use {Cursive, Printer, With};
|
pub use {Cursive, Printer, With};
|
||||||
pub use event::{Event, Key};
|
pub use event::{Event, Key};
|
||||||
pub use view::{BoxView, Button, Checkbox, Dialog, EditView, FullView, IdView,
|
pub use view::{BoxView, Button, Checkbox, Dialog, EditView, FullView, IdView,
|
||||||
KeyEventView, LinearLayout, ListView, SelectView, Selector,
|
Identifiable, KeyEventView, LinearLayout, ListView,
|
||||||
TextView, View};
|
ProgressBar, SelectView, Selector, TextView, View};
|
||||||
pub use vec::Vec2;
|
pub use vec::Vec2;
|
||||||
pub use menu::MenuTree;
|
pub use menu::MenuTree;
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
use std::rc::Rc;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
|
use {Cursive, Printer, With};
|
||||||
|
use align::HAlign;
|
||||||
|
use event::*;
|
||||||
use direction::Direction;
|
use direction::Direction;
|
||||||
use theme::ColorStyle;
|
use theme::ColorStyle;
|
||||||
use Cursive;
|
|
||||||
use With;
|
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use view::View;
|
use view::View;
|
||||||
use event::*;
|
|
||||||
use Printer;
|
|
||||||
use unicode_width::UnicodeWidthStr;
|
|
||||||
|
|
||||||
/// Simple text label with a callback when <Enter> is pressed.
|
/// Simple text label with a callback when <Enter> is pressed.
|
||||||
///
|
///
|
||||||
@ -33,7 +31,7 @@ impl Button {
|
|||||||
{
|
{
|
||||||
Button {
|
Button {
|
||||||
label: label.to_string(),
|
label: label.to_string(),
|
||||||
callback: Rc::new(cb),
|
callback: Callback::from_fn(cb),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,12 +80,12 @@ impl View for Button {
|
|||||||
} else {
|
} else {
|
||||||
ColorStyle::Highlight
|
ColorStyle::Highlight
|
||||||
};
|
};
|
||||||
let x = printer.size.x - 1;
|
|
||||||
|
let offset =
|
||||||
|
HAlign::Center.get_offset(self.label.len() + 2, printer.size.x);
|
||||||
|
|
||||||
printer.with_color(style, |printer| {
|
printer.with_color(style, |printer| {
|
||||||
printer.print((1, 0), &self.label);
|
printer.print((offset, 0), &format!("<{}>", self.label));
|
||||||
printer.print((0, 0), "<");
|
|
||||||
printer.print((x, 0), ">");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,13 @@ impl Dialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the content for this dialog.
|
||||||
|
///
|
||||||
|
/// Previous content will be dropped.
|
||||||
|
pub fn set_content<V: View + 'static>(&mut self, view: V) {
|
||||||
|
self.content = Box::new(view);
|
||||||
|
}
|
||||||
|
|
||||||
/// Convenient method to create an infobox.
|
/// Convenient method to create an infobox.
|
||||||
///
|
///
|
||||||
/// It will contain the given text and a `Ok` dismiss button.
|
/// It will contain the given text and a `Ok` dismiss button.
|
||||||
@ -108,6 +115,30 @@ impl Dialog {
|
|||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the top padding in the dialog (under the title).
|
||||||
|
pub fn padding_top(mut self, padding: usize) -> Self {
|
||||||
|
self.padding.top = padding;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the bottom padding in the dialog (under buttons).
|
||||||
|
pub fn padding_bottom(mut self, padding: usize) -> Self {
|
||||||
|
self.padding.bottom = padding;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the left padding in the dialog.
|
||||||
|
pub fn padding_left(mut self, padding: usize) -> Self {
|
||||||
|
self.padding.left = padding;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the right padding in the dialog.
|
||||||
|
pub fn padding_right(mut self, padding: usize) -> Self {
|
||||||
|
self.padding.right = padding;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for Dialog {
|
impl View for Dialog {
|
||||||
|
@ -5,7 +5,7 @@ use With;
|
|||||||
use direction::Direction;
|
use direction::Direction;
|
||||||
use theme::{ColorStyle, Effect};
|
use theme::{ColorStyle, Effect};
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use view::{IdView, View};
|
use view::View;
|
||||||
use event::*;
|
use event::*;
|
||||||
use Printer;
|
use Printer;
|
||||||
|
|
||||||
@ -135,11 +135,6 @@ impl EditView {
|
|||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps this view into an IdView with the given id.
|
|
||||||
pub fn with_id(self, label: &str) -> IdView<Self> {
|
|
||||||
IdView::new(label, self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for EditView {
|
impl View for EditView {
|
||||||
|
@ -28,3 +28,14 @@ impl<T: View + Any> ViewWrapper for IdView<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a view wrappable in an `IdView`.
|
||||||
|
pub trait Identifiable: View + Sized {
|
||||||
|
|
||||||
|
/// Wraps this view into an IdView with the given id.
|
||||||
|
fn with_id(self, id: &str) -> IdView<Self> {
|
||||||
|
IdView::new(id, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <T: View> Identifiable for T {}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use Cursive;
|
use Cursive;
|
||||||
use event::{Callback, Event, EventResult};
|
use event::{Callback, Event, EventResult};
|
||||||
@ -35,7 +34,7 @@ impl KeyEventView {
|
|||||||
pub fn register<F, E: Into<Event>>(mut self, event: E, cb: F) -> Self
|
pub fn register<F, E: Into<Event>>(mut self, event: E, cb: F) -> Self
|
||||||
where F: Fn(&mut Cursive) + 'static
|
where F: Fn(&mut Cursive) + 'static
|
||||||
{
|
{
|
||||||
self.callbacks.insert(event.into(), Rc::new(cb));
|
self.callbacks.insert(event.into(), Callback::from_fn(cb));
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ impl MenuPopup {
|
|||||||
///
|
///
|
||||||
/// (When the user hits <ESC>)
|
/// (When the user hits <ESC>)
|
||||||
pub fn on_dismiss<F: 'static + Fn(&mut Cursive)>(mut self, f: F) -> Self {
|
pub fn on_dismiss<F: 'static + Fn(&mut Cursive)>(mut self, f: F) -> Self {
|
||||||
self.on_dismiss = Some(Rc::new(f));
|
self.on_dismiss = Some(Callback::from_fn(f));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ impl MenuPopup {
|
|||||||
///
|
///
|
||||||
/// Usually used to hide the parent view.
|
/// Usually used to hide the parent view.
|
||||||
pub fn on_action<F: 'static + Fn(&mut Cursive)>(mut self, f: F) -> Self {
|
pub fn on_action<F: 'static + Fn(&mut Cursive)>(mut self, f: F) -> Self {
|
||||||
self.on_action = Some(Rc::new(f));
|
self.on_action = Some(Callback::from_fn(f));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ mod linear_layout;
|
|||||||
mod list_view;
|
mod list_view;
|
||||||
mod menubar;
|
mod menubar;
|
||||||
mod menu_popup;
|
mod menu_popup;
|
||||||
|
mod progress_bar;
|
||||||
mod shadow_view;
|
mod shadow_view;
|
||||||
mod select_view;
|
mod select_view;
|
||||||
mod sized_view;
|
mod sized_view;
|
||||||
@ -78,7 +79,7 @@ pub use self::position::{Offset, Position};
|
|||||||
|
|
||||||
pub use self::scroll::ScrollBase;
|
pub use self::scroll::ScrollBase;
|
||||||
|
|
||||||
pub use self::id_view::IdView;
|
pub use self::id_view::{IdView, Identifiable};
|
||||||
pub use self::box_view::BoxView;
|
pub use self::box_view::BoxView;
|
||||||
pub use self::button::Button;
|
pub use self::button::Button;
|
||||||
pub use self::checkbox::Checkbox;
|
pub use self::checkbox::Checkbox;
|
||||||
@ -91,12 +92,13 @@ pub use self::list_view::ListView;
|
|||||||
pub use self::menubar::Menubar;
|
pub use self::menubar::Menubar;
|
||||||
pub use self::menu_popup::MenuPopup;
|
pub use self::menu_popup::MenuPopup;
|
||||||
pub use self::view_path::ViewPath;
|
pub use self::view_path::ViewPath;
|
||||||
|
pub use self::progress_bar::ProgressBar;
|
||||||
pub use self::select_view::SelectView;
|
pub use self::select_view::SelectView;
|
||||||
pub use self::shadow_view::ShadowView;
|
pub use self::shadow_view::ShadowView;
|
||||||
|
pub use self::sized_view::SizedView;
|
||||||
pub use self::stack_view::StackView;
|
pub use self::stack_view::StackView;
|
||||||
pub use self::text_view::TextView;
|
pub use self::text_view::TextView;
|
||||||
pub use self::tracked_view::TrackedView;
|
pub use self::tracked_view::TrackedView;
|
||||||
pub use self::sized_view::SizedView;
|
|
||||||
pub use self::view_wrapper::ViewWrapper;
|
pub use self::view_wrapper::ViewWrapper;
|
||||||
|
|
||||||
|
|
||||||
|
107
src/view/progress_bar.rs
Normal file
107
src/view/progress_bar.rs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
use {Cursive, Printer};
|
||||||
|
use event::*;
|
||||||
|
use theme::ColorStyle;
|
||||||
|
use view::View;
|
||||||
|
|
||||||
|
/// Display progress.
|
||||||
|
pub struct ProgressBar {
|
||||||
|
min: usize,
|
||||||
|
max: usize,
|
||||||
|
value: Arc<AtomicUsize>,
|
||||||
|
// TODO: use a Promise instead?
|
||||||
|
callback: Option<Arc<Mutex<Option<Box<Fn(&mut Cursive) + Send>>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProgressBar {
|
||||||
|
/// Creates a new progress bar.
|
||||||
|
///
|
||||||
|
/// Default values:
|
||||||
|
///
|
||||||
|
/// * `min`: 0
|
||||||
|
/// * `max`: 100
|
||||||
|
/// * `value`: 0
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ProgressBar {
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
value: Arc::new(AtomicUsize::new(0)),
|
||||||
|
callback: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the value to follow.
|
||||||
|
pub fn with_value(mut self, value: Arc<AtomicUsize>) -> Self {
|
||||||
|
self.value = value;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the callback to follow.
|
||||||
|
///
|
||||||
|
/// Whenever `callback` is set, it will be called on the next event loop.
|
||||||
|
pub fn with_callback(mut self,
|
||||||
|
callback: Arc<Mutex<Option<Box<Fn(&mut Cursive) + Send>>>>)
|
||||||
|
-> Self {
|
||||||
|
self.callback = Some(callback);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the minimum value.
|
||||||
|
///
|
||||||
|
/// When `value` equals `min`, the bar is at the minimum level.
|
||||||
|
pub fn min(mut self, min: usize) -> Self {
|
||||||
|
self.min = min;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum value.
|
||||||
|
///
|
||||||
|
/// When `value` equals `max`, the bar is at the maximum level.
|
||||||
|
pub fn max(mut self, max: usize) -> Self {
|
||||||
|
self.max = max;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the `min` and `max` range for the value.
|
||||||
|
pub fn range(self, min: usize, max: usize) -> Self {
|
||||||
|
self.min(min).max(max)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the current value.
|
||||||
|
///
|
||||||
|
/// Value is clamped between `min` and `max`.
|
||||||
|
pub fn set_value(&mut self, value: usize) {
|
||||||
|
self.value.store(value, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for ProgressBar {
|
||||||
|
fn draw(&self, printer: &Printer) {
|
||||||
|
// TODO: make the brackets an option
|
||||||
|
// (Or a theme property? Or both?)
|
||||||
|
printer.print((0, 0), "[");
|
||||||
|
printer.print((printer.size.x - 1, 0), "]");
|
||||||
|
|
||||||
|
// Now, the bar itself...
|
||||||
|
let available = printer.size.x - 2;
|
||||||
|
|
||||||
|
let value = self.value.load(Ordering::Relaxed);
|
||||||
|
let length = (available * (value - self.min)) / (self.max - self.min);
|
||||||
|
printer.with_color(ColorStyle::Highlight, |printer| {
|
||||||
|
printer.print_hline((1, 0), length, " ");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_event(&mut self, _: Event) -> EventResult {
|
||||||
|
if let Some(ref cb) = self.callback {
|
||||||
|
if let Some(cb) = cb.lock().unwrap().take() {
|
||||||
|
return EventResult::Consumed(Some(cb.into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EventResult::Ignored
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ use view::position::Position;
|
|||||||
use view::{IdView, View};
|
use view::{IdView, View};
|
||||||
use align::{Align, HAlign, VAlign};
|
use align::{Align, HAlign, VAlign};
|
||||||
use view::scroll::ScrollBase;
|
use view::scroll::ScrollBase;
|
||||||
use event::{Event, EventResult, Key};
|
use event::{Callback, Event, EventResult, Key};
|
||||||
use theme::ColorStyle;
|
use theme::ColorStyle;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use Printer;
|
use Printer;
|
||||||
@ -387,7 +387,7 @@ impl<T: 'static> View for SelectView<T> {
|
|||||||
let cb = self.select_cb.as_ref().unwrap().clone();
|
let cb = self.select_cb.as_ref().unwrap().clone();
|
||||||
let v = self.selection();
|
let v = self.selection();
|
||||||
// We return a Callback Rc<|s| cb(s, &*v)>
|
// We return a Callback Rc<|s| cb(s, &*v)>
|
||||||
return EventResult::Consumed(Some(Rc::new(move |s| {
|
return EventResult::Consumed(Some(Callback::from_fn(move |s| {
|
||||||
cb(s, &*v)
|
cb(s, &*v)
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user