Add start and with_task to ProgressBar

This commit is contained in:
Alexandre Bury 2016-07-26 12:10:13 -07:00
parent eb6b5d5728
commit 8eb61e0239
2 changed files with 53 additions and 28 deletions

View File

@ -4,8 +4,6 @@ use cursive::prelude::*;
use std::thread;
use std::time::Duration;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
fn main() {
let mut siv = Cursive::new();
@ -14,37 +12,36 @@ fn main() {
.title("Progress bar example")
.padding((0, 0, 1, 1))
.content(Button::new("Start", |s| {
// These two values will allow us to communicate.
let value = Arc::new(AtomicUsize::new(0));
// Number of ticks
let n_max = 1000;
s.pop_layer();
s.add_layer(Panel::new(FullView::full_width(ProgressBar::new()
.range(0, n_max)
.with_value(value.clone()))));
// This is the callback channel
let cb = s.cb_sink().clone();
// Spawn a thread to process things in the background.
thread::spawn(move || {
for _ in 0..n_max {
thread::sleep(Duration::from_millis(20));
value.fetch_add(1, Ordering::Relaxed);
}
cb.send(Box::new(move |s| {
s.pop_layer();
s.add_layer(Dialog::empty()
.title("Work done!")
.content(TextView::new("Phew, that was some \
work!"))
.button("Sure!", |s| s.quit()));
}))
.unwrap();
});
s.pop_layer();
s.add_layer(Panel::new(FullView::full_width(
ProgressBar::new()
.range(0, n_max)
.with_task(move |ticker| {
// This closure will be called in a separate thread.
for _ in 0..n_max {
thread::sleep(Duration::from_millis(5));
// The ticker method increases the progress value
ticker(1);
}
}))
.with_id("dialog"));
// When we're done, send a callback through the channel
cb.send(Box::new(move |s| {
s.pop_layer();
s.add_layer(Dialog::empty()
.title("Work done!")
.content(TextView::new("Phew!"))
.button("Finally!", |s| s.quit()));
}))
.unwrap();
})
)));
})));
siv.set_fps(30);

View File

@ -1,5 +1,6 @@
use std::sync::Arc;
use std::thread;
use std::sync::atomic::{AtomicUsize, Ordering};
use {Cursive, Printer};
@ -18,6 +19,8 @@ pub struct ProgressBar {
label_maker: Box<Fn(usize, (usize, usize)) -> String>,
}
pub type Ticker = Box<Fn(usize) + Send>;
fn make_percentage(value: usize, (min, max): (usize, usize)) -> String {
let percent = 101 * (value - min) / (1 + max - min);
format!("{} %", percent)
@ -43,11 +46,36 @@ impl ProgressBar {
}
/// Sets the value to follow.
///
/// Use this to manually control the progress to display
/// by directly modifying the value pointed to by `value`.
pub fn with_value(mut self, value: Arc<AtomicUsize>) -> Self {
self.value = value;
self
}
/// Starts a function in a separate thread, and monitor the progress.
///
/// `f` will be given a `Ticker` to increment the bar's progress.
pub fn start<F: FnOnce(Ticker) + Send + 'static>(&mut self, f: F) {
let value = self.value.clone();
let ticker: Ticker = Box::new(move |ticks| {
value.fetch_add(ticks, Ordering::Relaxed);
});
thread::spawn(move || {
f(ticker);
});
}
/// Starts a function in a separate thread, and monitor the progress.
///
/// Chainable variant.
pub fn with_task<F: FnOnce(Ticker) + Send + 'static>(mut self, task: F) -> Self {
self.start(task);
self
}
/// Sets the label generator.
///
/// The given function will be called with `(value, (min, max))`.