message_from_grid_view/
message_from_grid_view.rs1use glib::SignalHandlerId;
2use gtk::prelude::*;
3use rand::seq::IteratorRandom;
4use relm4::gtk::glib;
5use relm4::{
6 prelude::*,
7 typed_view::grid::{RelmGridItem, TypedGridView},
8};
9
10const CONTRIBUTORS: &[&str] = &[
11 "AaronErhardt",
12 "MaksymShcherbak",
13 "mmstick",
14 "tronta",
15 "zekefast",
16 "M23SNEZ3",
17];
18
19fn random_name() -> &'static str {
20 CONTRIBUTORS
21 .iter()
22 .choose(&mut rand::rng())
23 .expect("Could not choose a random name")
24}
25
26#[derive(Debug)]
27struct MyGridItem {
28 name: &'static str,
29 sender: ComponentSender<App>,
30 button_click_handler_id: Option<SignalHandlerId>,
31}
32
33impl MyGridItem {
34 fn new(sender: ComponentSender<App>) -> Self {
35 Self {
36 name: random_name(),
37 sender,
38 button_click_handler_id: Default::default(),
39 }
40 }
41}
42
43struct Widgets {
44 button: gtk::Button,
45 label: gtk::Label,
46}
47
48impl RelmGridItem for MyGridItem {
49 type Root = gtk::Box;
50 type Widgets = Widgets;
51
52 fn setup(item: >k::ListItem) -> (gtk::Box, Widgets) {
53 item.set_activatable(false);
54 item.set_focusable(false);
55 relm4::view! {
56 my_box = gtk::Box {
57 set_orientation: gtk::Orientation::Horizontal,
58 set_margin_all: 2,
59 set_spacing: 5,
60
61 #[name = "button"]
62 gtk::Button {
63 set_hexpand: true,
64 #[name = "label"]
65 gtk::Label {
66 set_halign: gtk::Align::Center,
67 }
68 }
69 }
70 }
71
72 let widgets = Widgets { label, button };
73
74 (my_box, widgets)
75 }
76
77 fn bind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) {
78 widgets.label.set_label(self.name);
79 let name = self.name;
80 let button_click_handler_id = widgets.button.connect_clicked(glib::clone!(
81 #[strong(rename_to = sender)]
82 self.sender,
83 move |_btn| {
84 sender.input(Msg::Print(name));
86 }
87 ));
88 self.button_click_handler_id
89 .replace(button_click_handler_id);
90 }
91
92 fn unbind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) {
93 if let Some(id) = self.button_click_handler_id.take() {
94 widgets.button.disconnect(id)
95 }
96 }
97}
98
99#[derive(Debug)]
100struct App {
101 grid_view: TypedGridView<MyGridItem, gtk::NoSelection>,
102}
103
104#[derive(Debug)]
105enum Msg<'a> {
106 Add,
107 Print(&'a str),
108}
109
110#[relm4::component]
111impl SimpleComponent for App {
112 type Init = u8;
113 type Input = Msg<'static>;
114 type Output = ();
115
116 view! {
117 gtk::Window {
118 set_title: Some("Is it really possible to send messages from an item in a grid?"),
119 set_default_size: (650, 300),
120
121 gtk::Box {
122 set_orientation: gtk::Orientation::Vertical,
123 set_spacing: 5,
124 set_margin_all: 5,
125
126 gtk::Button {
127 set_label: "Append 10 items",
128 connect_clicked => Msg::Add,
129 },
130
131 gtk::ScrolledWindow {
132 set_vexpand: true,
133
134 #[local_ref]
135 my_view -> gtk::GridView {
136 set_orientation: gtk::Orientation::Vertical,
137 set_max_columns: 3,
138 }
139 }
140 }
141 }
142 }
143
144 fn init(
145 _: Self::Init,
146 root: Self::Root,
147 sender: ComponentSender<Self>,
148 ) -> ComponentParts<Self> {
149 let grid_view: TypedGridView<MyGridItem, gtk::NoSelection> = TypedGridView::new();
151
152 let model = App { grid_view };
153
154 let my_view = &model.grid_view.view;
155
156 let widgets = view_output!();
157
158 ComponentParts { model, widgets }
159 }
160
161 fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) {
162 match msg {
163 Msg::Add => {
164 for _ in 0..10 {
165 self.grid_view.append(MyGridItem::new(sender.clone()));
166 }
167 }
168 Msg::Print(name) => {
169 println!("Name: {:?}", name)
170 }
171 }
172 }
173}
174
175fn main() {
176 let app = RelmApp::new("relm4.example.message_from_grid_view");
177 app.run::<App>(0);
178}