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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use fltk::{prelude::*, *};
use std::collections::HashMap;
use std::sync::Mutex;
use std::any::Any;
use once_cell::sync::Lazy;
static WIDGET_MAP: Lazy<Mutex<HashMap<&'static str, Box<dyn Any + Send + Sync + 'static>>>> = Lazy::new(|| Mutex::new(HashMap::default()));
pub trait WidgetId<W>
where
W: WidgetExt,
{
fn set_id(&mut self, id: &'static str);
fn with_id(self, id: &'static str) -> Self
where
Self: Sized;
}
impl<W> WidgetId<W> for W
where
W: WidgetExt + Send + Sync + Clone + 'static,
{
fn set_id(&mut self, id: &'static str) {
WIDGET_MAP
.lock()
.unwrap()
.insert(id, Box::new(self.clone()));
}
fn with_id(mut self, id: &'static str) -> Self {
self.set_id(id);
self
}
}
pub fn from_id<T: 'static + Clone>(id: &'static str) -> Option<T> {
if let Some(w) = WIDGET_MAP.lock().unwrap().get(&id) {
w.downcast_ref::<T>().map(|w| (*w).clone())
} else {
None
}
}
trait OnTrigger<W>
where
W: WidgetExt,
{
fn on_trigger<F: 'static + FnMut(&mut Self)>(self, cb: F) -> Self
where
Self: Sized;
}
impl<W> OnTrigger<W> for W
where
W: WidgetExt,
{
fn on_trigger<F: 'static + FnMut(&mut Self)>(mut self, mut cb: F) -> Self {
self.set_callback(move |s| cb(s));
self
}
}
struct Counter {
count: i32,
}
fn increment_by(step: i32) {
let mut frame: frame::Frame = from_id("my_frame").unwrap();
let state = app::GlobalState::<Counter>::get();
let count = state.with(move |c| {
c.count += step;
c.count
});
frame.set_label(&count.to_string());
}
fn increment(_w: &mut impl WidgetExt) {
let mut frame: frame::Frame = from_id("my_frame").unwrap();
let state = app::GlobalState::<Counter>::get();
let count = state.with(|c| {
c.count += 1;
c.count
});
frame.set_label(&count.to_string());
}
fn main() {
let counter = Counter { count: 0 };
let _state = app::GlobalState::new(counter);
let app = app::App::default().with_scheme(app::Scheme::Gtk);
let mut wind = window::Window::default()
.with_size(160, 200)
.with_label("Counter");
let col = group::Flex::default_fill().column();
button::Button::default()
.with_label("+")
.on_trigger(increment);
frame::Frame::default().with_label("0").with_id("my_frame");
button::Button::default()
.with_label("-")
.on_trigger(|_| increment_by(-1));
col.end();
wind.make_resizable(true);
wind.end();
wind.show();
app.run().unwrap();
}