mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 11:16:03 +00:00
Add async-callback channel to Cursive
And remove it from ProgressBar
This commit is contained in:
parent
04f961657f
commit
0643c50bd5
@ -4,7 +4,7 @@ use cursive::prelude::*;
|
|||||||
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -16,15 +16,15 @@ fn main() {
|
|||||||
.content(Button::new("Start", |s| {
|
.content(Button::new("Start", |s| {
|
||||||
// These two values will allow us to communicate.
|
// These two values will allow us to communicate.
|
||||||
let value = Arc::new(AtomicUsize::new(0));
|
let value = Arc::new(AtomicUsize::new(0));
|
||||||
let cb = Arc::new(Mutex::new(None));
|
|
||||||
|
|
||||||
let n_max = 1000;
|
let n_max = 1000;
|
||||||
|
|
||||||
s.pop_layer();
|
s.pop_layer();
|
||||||
s.add_layer(Panel::new(FullView::full_width(ProgressBar::new()
|
s.add_layer(Panel::new(FullView::full_width(ProgressBar::new()
|
||||||
.range(0, n_max)
|
.range(0, n_max)
|
||||||
.with_value(value.clone())
|
.with_value(value.clone()))));
|
||||||
.with_callback(cb.clone()))));
|
|
||||||
|
let cb = s.cb_sink().clone();
|
||||||
|
|
||||||
// Spawn a thread to process things in the background.
|
// Spawn a thread to process things in the background.
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
@ -32,13 +32,15 @@ fn main() {
|
|||||||
thread::sleep(Duration::from_millis(20));
|
thread::sleep(Duration::from_millis(20));
|
||||||
value.fetch_add(1, Ordering::Relaxed);
|
value.fetch_add(1, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
*cb.lock().unwrap() = Some(Box::new(move |s| {
|
cb.send(Box::new(move |s| {
|
||||||
s.pop_layer();
|
s.pop_layer();
|
||||||
s.add_layer(Dialog::empty()
|
s.add_layer(Dialog::empty()
|
||||||
.title("Work done!")
|
.title("Work done!")
|
||||||
.content(TextView::new("Phew, that was some work!"))
|
.content(TextView::new("Phew, that was some \
|
||||||
.button("Sure!", |s| s.quit()));
|
work!"))
|
||||||
}));
|
.button("Sure!", |s| s.quit()));
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
});
|
});
|
||||||
|
|
||||||
}))
|
}))
|
||||||
|
23
src/lib.rs
23
src/lib.rs
@ -97,6 +97,7 @@ pub use printer::Printer;
|
|||||||
|
|
||||||
use backend::{Backend, NcursesBackend};
|
use backend::{Backend, NcursesBackend};
|
||||||
|
|
||||||
|
use std::sync::mpsc;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@ -126,6 +127,9 @@ pub struct Cursive {
|
|||||||
active_screen: ScreenId,
|
active_screen: ScreenId,
|
||||||
|
|
||||||
running: bool,
|
running: bool,
|
||||||
|
|
||||||
|
cb_source: mpsc::Receiver<Box<Fn(&mut Cursive) + Send>>,
|
||||||
|
cb_sink: mpsc::Sender<Box<Fn(&mut Cursive) + Send>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
new_default!(Cursive);
|
new_default!(Cursive);
|
||||||
@ -143,6 +147,8 @@ impl Cursive {
|
|||||||
let theme = theme::load_default();
|
let theme = theme::load_default();
|
||||||
// let theme = theme::load_theme("assets/style.toml").unwrap();
|
// let theme = theme::load_theme("assets/style.toml").unwrap();
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
let mut res = Cursive {
|
let mut res = Cursive {
|
||||||
theme: theme,
|
theme: theme,
|
||||||
screens: Vec::new(),
|
screens: Vec::new(),
|
||||||
@ -150,6 +156,8 @@ impl Cursive {
|
|||||||
menubar: view::Menubar::new(),
|
menubar: view::Menubar::new(),
|
||||||
active_screen: 0,
|
active_screen: 0,
|
||||||
running: true,
|
running: true,
|
||||||
|
cb_source: rx,
|
||||||
|
cb_sink: tx,
|
||||||
};
|
};
|
||||||
|
|
||||||
res.screens.push(StackView::new());
|
res.screens.push(StackView::new());
|
||||||
@ -157,6 +165,17 @@ impl Cursive {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a sink for asynchronous callbacks.
|
||||||
|
///
|
||||||
|
/// Returns the sender part of a channel, that allows to send
|
||||||
|
/// callbacks to `self` from other threads.
|
||||||
|
///
|
||||||
|
/// Callbacks will be executed in the order
|
||||||
|
/// of arrival on the next event cycle.
|
||||||
|
pub fn cb_sink(&self) -> &mpsc::Sender<Box<Fn(&mut Cursive) + Send>> {
|
||||||
|
&self.cb_sink
|
||||||
|
}
|
||||||
|
|
||||||
/// Selects the menubar
|
/// Selects the menubar
|
||||||
pub fn select_menubar(&mut self) {
|
pub fn select_menubar(&mut self) {
|
||||||
self.menubar.take_focus(direction::Direction::none());
|
self.menubar.take_focus(direction::Direction::none());
|
||||||
@ -454,6 +473,10 @@ impl Cursive {
|
|||||||
|
|
||||||
// And the big event loop begins!
|
// And the big event loop begins!
|
||||||
while self.running {
|
while self.running {
|
||||||
|
if let Ok(cb) = self.cb_source.try_recv() {
|
||||||
|
cb(self);
|
||||||
|
}
|
||||||
|
|
||||||
// Do we need to redraw everytime?
|
// Do we need to redraw everytime?
|
||||||
// Probably, actually.
|
// Probably, actually.
|
||||||
// TODO: Do we need to re-layout everytime?
|
// TODO: Do we need to re-layout everytime?
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
@ -6,7 +6,6 @@ use {Cursive, Printer};
|
|||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use align::HAlign;
|
use align::HAlign;
|
||||||
use direction::Orientation;
|
use direction::Orientation;
|
||||||
use event::*;
|
|
||||||
use theme::{ColorStyle, Effect};
|
use theme::{ColorStyle, Effect};
|
||||||
use view::View;
|
use view::View;
|
||||||
|
|
||||||
@ -18,7 +17,6 @@ pub struct ProgressBar {
|
|||||||
max: usize,
|
max: usize,
|
||||||
value: Arc<AtomicUsize>,
|
value: Arc<AtomicUsize>,
|
||||||
// TODO: use a Promise instead?
|
// TODO: use a Promise instead?
|
||||||
callback: Option<Arc<Mutex<CbPromise>>>,
|
|
||||||
label_maker: Box<Fn(usize, (usize, usize)) -> String>,
|
label_maker: Box<Fn(usize, (usize, usize)) -> String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +40,6 @@ impl ProgressBar {
|
|||||||
min: 0,
|
min: 0,
|
||||||
max: 100,
|
max: 100,
|
||||||
value: Arc::new(AtomicUsize::new(0)),
|
value: Arc::new(AtomicUsize::new(0)),
|
||||||
callback: None,
|
|
||||||
label_maker: Box::new(make_percentage),
|
label_maker: Box::new(make_percentage),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,14 +50,6 @@ impl ProgressBar {
|
|||||||
self
|
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<CbPromise>>) -> Self {
|
|
||||||
self.callback = Some(callback);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the label generator.
|
/// Sets the label generator.
|
||||||
///
|
///
|
||||||
/// The given function will be called with `(value, (min, max))`.
|
/// The given function will be called with `(value, (min, max))`.
|
||||||
@ -132,16 +121,6 @@ impl View for ProgressBar {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_min_size(&mut self, size: Vec2) -> Vec2 {
|
fn get_min_size(&mut self, size: Vec2) -> Vec2 {
|
||||||
size.with_axis(Orientation::Vertical, 1)
|
size.with_axis(Orientation::Vertical, 1)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user