2016-07-25 06:00:13 +00:00
|
|
|
extern crate cursive;
|
2016-07-28 06:51:54 +00:00
|
|
|
extern crate rand;
|
|
|
|
|
2016-09-29 05:45:27 +00:00
|
|
|
use cursive::Cursive;
|
2017-10-12 23:38:55 +00:00
|
|
|
use cursive::traits::*;
|
2016-09-29 05:45:27 +00:00
|
|
|
use cursive::views::{Button, Dialog, LinearLayout, ProgressBar, TextView};
|
2018-04-10 19:50:40 +00:00
|
|
|
use cursive::utils::Counter;
|
2017-10-12 23:38:55 +00:00
|
|
|
use rand::Rng;
|
2016-07-28 06:51:54 +00:00
|
|
|
use std::cmp::min;
|
2017-10-12 23:38:55 +00:00
|
|
|
use std::thread;
|
2016-07-25 06:00:13 +00:00
|
|
|
use std::time::Duration;
|
|
|
|
|
2018-01-16 02:55:27 +00:00
|
|
|
// This example shows a ProgressBar reporting the status from an asynchronous
|
|
|
|
// job.
|
|
|
|
//
|
|
|
|
// It works by sharing a counter with the job thread. This counter can be
|
|
|
|
// "ticked" to indicate progress.
|
|
|
|
|
2016-07-25 06:00:13 +00:00
|
|
|
fn main() {
|
2018-04-01 23:39:03 +00:00
|
|
|
let mut siv = Cursive::default();
|
2016-07-25 06:00:13 +00:00
|
|
|
|
2016-07-28 06:51:54 +00:00
|
|
|
// We'll start slowly with a simple start button...
|
2017-10-12 23:38:55 +00:00
|
|
|
siv.add_layer(
|
|
|
|
Dialog::new()
|
|
|
|
.title("Progress bar example")
|
|
|
|
.padding((0, 0, 1, 1))
|
|
|
|
.content(Button::new("Start", phase_1)),
|
|
|
|
);
|
2016-07-25 06:00:13 +00:00
|
|
|
|
2018-05-20 16:59:35 +00:00
|
|
|
// Auto-refresh is required for animated views
|
2016-07-25 20:35:46 +00:00
|
|
|
siv.set_fps(30);
|
2016-07-25 06:00:13 +00:00
|
|
|
|
|
|
|
siv.run();
|
|
|
|
}
|
2016-07-28 06:51:54 +00:00
|
|
|
|
|
|
|
fn phase_1(s: &mut Cursive) {
|
|
|
|
// Phase 1 is easy: a simple pre-loading.
|
|
|
|
|
|
|
|
// Number of ticks
|
|
|
|
let n_max = 500;
|
|
|
|
|
|
|
|
// This is the callback channel
|
|
|
|
let cb = s.cb_sink().clone();
|
|
|
|
|
|
|
|
s.pop_layer();
|
2017-10-12 23:38:55 +00:00
|
|
|
s.add_layer(Dialog::around(
|
|
|
|
ProgressBar::new()
|
2018-01-16 02:55:27 +00:00
|
|
|
// We need to know how many ticks represent a full bar.
|
2017-10-12 23:38:55 +00:00
|
|
|
.range(0, n_max)
|
|
|
|
.with_task(move |counter| {
|
|
|
|
// This closure will be called in a separate thread.
|
|
|
|
fake_load(n_max, &counter);
|
|
|
|
|
|
|
|
// When we're done, send a callback through the channel
|
2018-05-20 16:59:35 +00:00
|
|
|
cb.send(Box::new(coffee_break));
|
2017-10-12 23:38:55 +00:00
|
|
|
})
|
|
|
|
.full_width(),
|
|
|
|
));
|
2016-07-28 06:51:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn coffee_break(s: &mut Cursive) {
|
|
|
|
// A little break before things get serious.
|
|
|
|
s.pop_layer();
|
2017-10-12 23:38:55 +00:00
|
|
|
s.add_layer(
|
|
|
|
Dialog::new()
|
|
|
|
.title("Preparation complete")
|
|
|
|
.content(TextView::new("Now, the real deal!").center())
|
|
|
|
.button("Again??", phase_2),
|
|
|
|
);
|
2016-07-28 06:51:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn phase_2(s: &mut Cursive) {
|
|
|
|
// Now, we'll run N tasks
|
|
|
|
// (It could be downloading a file, extracting an archive,
|
|
|
|
// reticulating sprites, ...)
|
|
|
|
let n_bars = 10;
|
|
|
|
// Each task will have its own shiny counter
|
|
|
|
let counters: Vec<_> = (0..n_bars).map(|_| Counter::new(0)).collect();
|
|
|
|
// To make things more interesting, we'll give a random speed to each bar
|
2017-10-12 23:38:55 +00:00
|
|
|
let speeds: Vec<_> = (0..n_bars)
|
|
|
|
.map(|_| rand::thread_rng().gen_range(50, 150))
|
|
|
|
.collect();
|
2016-07-28 06:51:54 +00:00
|
|
|
|
2017-10-11 16:09:49 +00:00
|
|
|
let n_max = 100_000;
|
2016-07-28 06:51:54 +00:00
|
|
|
let cb = s.cb_sink().clone();
|
|
|
|
|
|
|
|
// Let's prepare the progress bars...
|
|
|
|
let mut linear = LinearLayout::vertical();
|
|
|
|
for c in &counters {
|
2017-10-12 23:38:55 +00:00
|
|
|
linear.add_child(ProgressBar::new().max(n_max).with_value(c.clone()));
|
2016-07-28 06:51:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
s.pop_layer();
|
2016-10-02 22:15:30 +00:00
|
|
|
s.add_layer(Dialog::around(linear.full_width()).title("Just a moment..."));
|
2016-07-28 06:51:54 +00:00
|
|
|
|
|
|
|
// And we start the worker thread.
|
|
|
|
thread::spawn(move || {
|
|
|
|
loop {
|
|
|
|
thread::sleep(Duration::from_millis(5));
|
|
|
|
let mut done = true;
|
|
|
|
for (c, s) in counters.iter().zip(&speeds) {
|
|
|
|
let ticks = min(n_max - c.get(), *s);
|
|
|
|
c.tick(ticks);
|
|
|
|
if c.get() < n_max {
|
|
|
|
done = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if done {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-20 16:59:35 +00:00
|
|
|
cb.send(Box::new(final_step));
|
2016-07-28 06:51:54 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn final_step(s: &mut Cursive) {
|
|
|
|
// A little break before things get serious.
|
|
|
|
s.pop_layer();
|
2017-10-12 23:38:55 +00:00
|
|
|
s.add_layer(
|
|
|
|
Dialog::new()
|
|
|
|
.title("Report")
|
|
|
|
.content(
|
|
|
|
TextView::new(
|
|
|
|
"Time travel was a success!\n\
|
|
|
|
We went forward a few seconds!!",
|
|
|
|
).center(),
|
|
|
|
)
|
|
|
|
.button("That's it?", |s| s.quit()),
|
|
|
|
);
|
2016-07-28 06:51:54 +00:00
|
|
|
}
|
2018-01-16 02:55:27 +00:00
|
|
|
|
|
|
|
// Function to simulate a long process.
|
|
|
|
fn fake_load(n_max: usize, counter: &Counter) {
|
|
|
|
for _ in 0..n_max {
|
|
|
|
thread::sleep(Duration::from_millis(5));
|
|
|
|
// The `counter.tick()` method increases the progress value
|
|
|
|
counter.tick(1);
|
|
|
|
}
|
|
|
|
}
|