1use gtk::prelude::*;
2use relm4::factory::FactoryVecDeque;
3use relm4::prelude::*;
4
5#[derive(Debug)]
6enum AppMsg {
7 AddCounters,
8 Clicked(DynamicIndex),
9}
10
11struct Counter {
12 value: u8,
13}
14
15struct App {
16 counters: FactoryVecDeque<Counter>,
17 created_counters: u8,
18 entry: gtk::EntryBuffer,
20}
21
22#[relm4::factory]
23impl FactoryComponent for Counter {
24 type Init = u8;
25 type Input = ();
26 type Output = AppMsg;
27 type CommandOutput = ();
28 type ParentWidget = gtk::Box;
29
30 view! {
31 gtk::Button {
32 #[watch]
33 set_label: &self.value.to_string(),
34 connect_clicked[index] => move |_| {
35 sender.output(AppMsg::Clicked(index.clone())).unwrap();
36 },
37 }
38 }
39
40 fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
41 Self { value }
42 }
43}
44
45#[relm4::component]
46impl SimpleComponent for App {
47 type Init = ();
48 type Input = AppMsg;
49 type Output = ();
50
51 view! {
52 gtk::ApplicationWindow {
53 set_title: Some("Entry example"),
54 set_default_size: (300, 200),
55
56 gtk::Box {
57 set_orientation: gtk::Orientation::Vertical,
58 set_margin_all: 5,
59 set_spacing: 5,
60
61 gtk::Entry {
62 set_buffer: &model.entry,
63 set_tooltip_text: Some("How many counters shall be added/removed?"),
64 connect_activate => AppMsg::AddCounters,
65 },
66
67 #[local]
68 factory_box -> gtk::Box {
69 set_orientation: gtk::Orientation::Vertical,
70 set_margin_all: 5,
71 set_spacing: 5,
72 },
73 }
74 }
75 }
76
77 fn init(
78 _init: Self::Init,
79 root: Self::Root,
80 sender: ComponentSender<Self>,
81 ) -> ComponentParts<Self> {
82 let factory_box = gtk::Box::default();
83
84 let counters = FactoryVecDeque::builder()
85 .launch(factory_box.clone())
86 .forward(sender.input_sender(), |output| output);
87
88 let model = App {
89 counters,
90 created_counters: 0,
91 entry: gtk::EntryBuffer::default(),
92 };
93
94 let widgets = view_output!();
95
96 ComponentParts { model, widgets }
97 }
98
99 fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
100 match message {
101 AppMsg::AddCounters => {
102 let text = self.entry.text();
103 if let Ok(v) = text.parse::<i32>() {
104 let mut guard = self.counters.guard();
105 if v.is_positive() {
106 for _ in 0..v {
108 guard.push_back(self.created_counters);
109 self.created_counters += 1;
110 }
111 } else if v.is_negative() {
112 for _ in v..0 {
114 guard.pop_front();
115 }
116 }
117
118 self.entry.set_text("");
120 }
121 }
122 AppMsg::Clicked(index) => {
123 if let Some(counter) = self.counters.guard().get_mut(index.current_index()) {
124 counter.value = counter.value.wrapping_sub(1);
125 }
126 }
127 }
128 }
129}
130
131fn main() {
132 let app = RelmApp::new("relm4.example.entry");
133 app.run::<App>(());
134}