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
125
126
127
use adw::{prelude::AdwApplicationWindowExt, CenteringPolicy, ViewStackPage};
use gtk::{
prelude::{
BoxExt, ButtonExt, GtkWindowExt, ObjectExt, OrientableExt, ToggleButtonExt, WidgetExt,
},
Orientation,
};
use relm4::{adw, gtk, send, AppUpdate, Model, RelmApp, Sender, Widgets};
#[derive(Default)]
struct AppModel {
counter: u8,
attention: bool,
}
enum AppMsg {
Increment,
Decrement,
Attention(bool),
}
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::Increment => {
self.counter = self.counter.wrapping_add(1);
}
AppMsg::Decrement => {
self.counter = self.counter.wrapping_sub(1);
}
AppMsg::Attention(v) => {
self.attention = v;
}
}
true
}
}
#[relm4::widget]
impl Widgets<AppModel, ()> for AppWidgets {
view! {
main_window = adw::ApplicationWindow {
set_default_width: 450,
set_default_height: 200,
set_content = Some(>k::Box) {
set_orientation: gtk::Orientation::Vertical,
append = &adw::HeaderBar {
set_title_widget: title = Some(&adw::ViewSwitcherTitle) {
set_title: "A stack switcher App",
set_stack: Some(&stack),
},
set_centering_policy: CenteringPolicy::Strict,
},
append: stack = &adw::ViewStack {
set_vexpand: true,
add_titled(Some("First"), "First Page") = >k::Box {
set_orientation: Orientation::Vertical,
set_hexpand: false,
append = >k::Label {
set_label: "This is the start page",
},
append = >k::Button {
set_label: "Increase",
connect_clicked(sender) => move |_| {
send!(sender, AppMsg::Increment)
}
},
append = >k::Button {
set_label: "Decrease",
connect_clicked(sender) => move |_| {
send!(sender, AppMsg::Decrement)
}
},
append = >k::ToggleButton {
set_label: "Needs Attention",
set_active: model.attention,
connect_clicked(sender) => move |v| {
send!(sender, AppMsg::Attention(v.is_active()))
}
},
} -> first_page: ViewStackPage {
set_icon_name: Some("document-print-symbolic"),
set_needs_attention: watch!(model.attention),
set_badge_number: watch!(model.counter as u32),
},
add_titled(Some("Second"), "Second Page") = >k::Label {
set_label: "This is the second page"
} -> {
set_icon_name: Some("media-playback-start-symbolic"),
set_badge_number: 3,
},
add_titled(Some("Third"), "Third Page") = >k::Label {
set_label: "This is the last page"
} -> {
set_icon_name: Some("mypaint-brushes-symbolic")
},
},
append: bottom_bar = &adw::ViewSwitcherBar {
set_stack: Some(&stack),
}
},
}
}
fn post_init() {
title
.bind_property("title-visible", &bottom_bar, "reveal")
.flags(gtk::glib::BindingFlags::SYNC_CREATE)
.build();
}
}
fn main() {
let model = AppModel {
counter: 5,
attention: true,
};
let app = RelmApp::new(model);
app.run();
}