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
use gtk::prelude::*;
use relm4::actions::*;
use relm4::prelude::*;

#[derive(Default)]
struct App {
    counter: u8,
}

#[derive(Debug)]
enum Msg {
    Increment,
    Decrement,
}

#[relm4::component]
impl SimpleComponent for App {
    type Init = ();
    type Input = Msg;
    type Output = ();

    view! {
        main_window = gtk::ApplicationWindow {
            set_title: Some("Action example"),
            set_default_size: (300, 100),

            gtk::Box {
                set_orientation: gtk::Orientation::Vertical,
                set_margin_all: 5,
                set_spacing: 5,

                gtk::Button {
                    set_label: "Increment",
                    connect_clicked => Msg::Increment,
                    ActionablePlus::set_action::<ExampleU8Action>: 1,
                },

                gtk::Button::with_label("Decrement") {
                    connect_clicked => Msg::Decrement,
                },

                gtk::Label {
                    set_margin_all: 5,
                    #[watch]
                    set_label: &format!("Counter: {}", model.counter),
                },

                gtk::MenuButton {
                    set_menu_model: Some(&menu_model),
                }
            },
        }
    }

    fn init(
        _init: Self::Init,
        root: &Self::Root,
        sender: ComponentSender<Self>,
    ) -> ComponentParts<Self> {
        let menu_model = gtk::gio::Menu::new();
        menu_model.append(Some("Stateless"), Some(&ExampleAction::action_name()));

        let model = Self { counter: 0 };

        let widgets = view_output!();

        let app = relm4::main_application();
        app.set_accelerators_for_action::<ExampleAction>(&["<primary>W"]);

        let group = RelmActionGroup::<WindowActionGroup>::new();

        let action: RelmAction<ExampleAction> = RelmAction::new_stateless(move |_| {
            println!("Statelesss action!");
            sender.input(Msg::Increment);
        });

        let action2: RelmAction<ExampleU8Action> =
            RelmAction::new_stateful_with_target_value(&0, |_, state, value| {
                println!("Stateful action -> state: {state}, value: {value}");
                *state += value;
            });

        group.add_action(&action);
        group.add_action(&action2);

        let actions = group.into_action_group();
        widgets
            .main_window
            .insert_action_group(WindowActionGroup::NAME, Some(&actions));

        ComponentParts { model, widgets }
    }

    fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
        match message {
            Msg::Increment => {
                self.counter = self.counter.wrapping_add(1);
            }
            Msg::Decrement => {
                self.counter = self.counter.wrapping_sub(1);
            }
        }
    }
}

relm4::new_action_group!(WindowActionGroup, "win");
relm4::new_stateless_action!(ExampleAction, WindowActionGroup, "example");
relm4::new_stateful_action!(ExampleU8Action, WindowActionGroup, "example2", u8, u8);

fn main() {
    let app = RelmApp::new("relm4.example.actions");
    app.run::<App>(());
}