-
Notifications
You must be signed in to change notification settings - Fork 17
/
invalidation-batch.rs
82 lines (77 loc) · 3.83 KB
/
invalidation-batch.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! This example shows how to use a [`InvalidationBatch`] in a background task
//! to synchronize when the user interface is updated/invalidated.
//!
//! This does not prevent the user interface from displaying the intermediate
//! state if it is redrawn for other reasons or by other threads. For example,
//! if the user resizes the window, the window will be redrawn during the
//! resize, and the current values of the dynamic values will be used.
use std::time::Duration;
use cushy::value::{Destination, Dynamic, InvalidationBatch, Source};
use cushy::widget::MakeWidget;
use cushy::widgets::grid::{GridDimension, GridWidgets};
use cushy::widgets::progress::Progressable;
use cushy::widgets::Grid;
use cushy::Run;
// This task will update both `progress_a` and `progress_b` at varying times,
// but the user interface will only be refreshed when the `InvalidationBatch` is
// dropped.
fn background_task(progress_a: Dynamic<u8>, progress_b: Dynamic<u8>) {
loop {
InvalidationBatch::batch(|_batch| {
// This set of operations has a net effect of incrementing
// progress_a, and adding 5 to progress_b. But the operations are
// are done by incrementing by ones and twos over the course of
// 200ms.
//
// This is a convoluted way to simulate having a complex operation
// in a background thread that a user wishes to synchronize the user
// interface updates to. The specific operations here aren't
// important. The important part is that all invalidation related to
// the changes to these widgets is delayed until this batch is
// executed, which happens when dropped or by using the batch
// parameter to this function to invoke them when desired.
progress_a.set(progress_a.get().wrapping_add(1));
progress_b.set(progress_b.get().wrapping_add(2));
std::thread::sleep(Duration::from_millis(100));
progress_b.set(progress_b.get().wrapping_add(2));
std::thread::sleep(Duration::from_millis(100));
progress_a.set(progress_a.get().wrapping_add(1));
progress_b.set(progress_b.get().wrapping_add(1));
});
// We sleep for 300 additional milliseconds to make the average loop
// take half a second. The progress will only ever be refreshed by this
// thread when the `progress_a` has been incremented by 2, and
// `progress_b` has been incremented by 5.
std::thread::sleep(Duration::from_millis(300));
}
}
fn main() -> cushy::Result {
const EXPLANATION: &str = "This example uses a background task that updates these progress values in such a way that it only requests this window be redrawn when the first has been incremented by 2 and the second has been incremented by 5. For fun, try resizing the window to force the window to redraw and observing that the intermediate states can still be seen.";
let progress_a = Dynamic::new(0);
let progress_a_text = progress_a.map_each(ToString::to_string);
let progress_b = Dynamic::new(0);
let progress_b_text = progress_b.map_each(ToString::to_string);
std::thread::spawn({
let progress_a = progress_a.clone();
let progress_b = progress_b.clone();
move || background_task(progress_a, progress_b)
});
EXPLANATION
.and(
Grid::from_rows(
GridWidgets::new()
.and((progress_a.progress_bar(), progress_a_text))
.and((progress_b.progress_bar(), progress_b_text)),
)
.dimensions([
GridDimension::Fractional { weight: 1 },
GridDimension::FitContent,
]),
)
.into_rows()
.contain()
.pad()
.expand_horizontally()
.centered()
.run()
}