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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use gtk::glib::Sender;
use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt};
use relm4::factory::{FactoryPrototype, FactoryVec};
use relm4::{gtk, send, AppUpdate, Model, RelmApp, WidgetPlus, Widgets};
#[derive(Debug)]
enum AppMsg {
Add,
Remove,
Clicked(usize),
}
struct Counter {
value: u8,
}
struct AppModel {
counters: FactoryVec<Counter>,
created_counters: u8,
}
impl Model for AppModel {
type Msg = AppMsg;
type Widgets = AppWidgets;
type Components = ();
}
impl AppUpdate for AppModel {
fn update(&mut self, msg: AppMsg, _components: &(), _sender: Sender<AppMsg>) -> bool {
match msg {
AppMsg::Add => {
self.counters.push(Counter {
value: self.created_counters,
});
self.created_counters += 1;
}
AppMsg::Remove => {
self.counters.pop();
}
AppMsg::Clicked(index) => {
if let Some(counter) = self.counters.get_mut(index) {
counter.value = counter.value.wrapping_sub(1);
}
}
}
true
}
}
#[derive(Debug)]
struct FactoryWidgets {
button: gtk::Button,
}
impl FactoryPrototype for Counter {
type Factory = FactoryVec<Self>;
type Widgets = FactoryWidgets;
type Root = gtk::Button;
type View = gtk::Box;
type Msg = AppMsg;
fn init_view(&self, index: &usize, sender: Sender<AppMsg>) -> FactoryWidgets {
let button = gtk::Button::with_label(&self.value.to_string());
let index = *index;
button.connect_clicked(move |_| {
sender.send(AppMsg::Clicked(index)).unwrap();
});
FactoryWidgets { button }
}
fn position(&self, _index: &usize) {}
fn view(&self, _index: &usize, widgets: &FactoryWidgets) {
widgets.button.set_label(&self.value.to_string());
}
fn root_widget(widgets: &FactoryWidgets) -> >k::Button {
&widgets.button
}
}
#[relm4::widget]
impl Widgets<AppModel, ()> for AppWidgets {
view! {
gtk::ApplicationWindow {
set_default_width: 300,
set_default_height: 200,
set_child = Some(>k::Box) {
set_orientation: gtk::Orientation::Vertical,
set_margin_all: 5,
set_spacing: 5,
append = >k::Button {
set_label: "Add",
connect_clicked(sender) => move |_| {
send!(sender, AppMsg::Add);
}
},
append = >k::Button {
set_label: "Remove",
connect_clicked(sender) => move |_| {
send!(sender, AppMsg::Remove);
}
},
append = >k::Box {
set_orientation: gtk::Orientation::Vertical,
set_margin_all: 5,
set_spacing: 5,
factory!(model.counters),
}
}
}
}
}
fn main() {
let model = AppModel {
counters: FactoryVec::new(),
created_counters: 0,
};
let relm = RelmApp::new(model);
relm.run();
}