menu/
menu.rs

1use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt};
2use relm4::actions::{AccelsPlus, ActionablePlus, RelmAction, RelmActionGroup};
3use relm4::{ComponentParts, ComponentSender, RelmApp, RelmWidgetExt, SimpleComponent};
4
5#[derive(Default)]
6struct App {
7    counter: u8,
8}
9
10#[derive(Debug)]
11enum Msg {
12    Increment,
13    Decrement,
14}
15
16#[relm4::component]
17impl SimpleComponent for App {
18    type Init = u8;
19    type Input = Msg;
20    type Output = ();
21
22    view! {
23        #[root]
24        main_window = gtk::ApplicationWindow {
25            set_title: Some("Menu example"),
26            set_default_size: (300, 100),
27
28            gtk::Box {
29                set_orientation: gtk::Orientation::Vertical,
30                set_margin_all: 5,
31                set_spacing: 5,
32
33                gtk::Button {
34                    set_label: "Increment",
35                    connect_clicked => Msg::Increment,
36                    ActionablePlus::set_action::<ExampleU8Action>: 1,
37                },
38                gtk::Button {
39                    set_label: "Decrement",
40                    connect_clicked => Msg::Decrement,
41                },
42                gtk::Label {
43                    set_margin_all: 5,
44                    #[watch]
45                    set_label: &format!("Counter: {}", model.counter),
46                },
47                gtk::MenuButton {
48                    #[wrap(Some)]
49                    set_popover = &gtk::PopoverMenu::from_model(Some(&main_menu)) {
50                        add_child: (&popover_child, "my_widget"),
51                    }
52                }
53            },
54        },
55        popover_child = gtk::Spinner {
56            set_spinning: true,
57        }
58    }
59
60    menu! {
61        main_menu: {
62            custom: "my_widget",
63            "Example" => ExampleAction,
64            "Example2" => ExampleAction,
65            "Example toggle" => ExampleU8Action(1_u8),
66            section! {
67                "Section example" => ExampleAction,
68                "Example toggle" => ExampleU8Action(1_u8),
69            },
70            section! {
71                "Example" => ExampleAction,
72                "Example2" => ExampleAction,
73                "Example Value" => ExampleU8Action(1_u8),
74            },
75            "submenu1" {
76                "Example" => ExampleAction,
77                "Example2" => ExampleAction,
78                "Example toggle" => ExampleU8Action(1_u8),
79                "submenu2" {
80                    "Example" => ExampleAction,
81                    "Example2" => ExampleAction,
82                    "Example toggle" => ExampleU8Action(1_u8),
83                    "submenu3" {
84                        "Example" => ExampleAction,
85                        "Example2" => ExampleAction,
86                        "Example toggle" => ExampleU8Action(1_u8),
87                    }
88                }
89            }
90        }
91    }
92
93    fn init(
94        counter: Self::Init,
95        root: Self::Root,
96        sender: ComponentSender<Self>,
97    ) -> ComponentParts<Self> {
98        // ============================================================
99        //
100        // You can also use menu! outside of the widget macro.
101        // This is the manual equivalent to the the menu! macro above.
102        //
103        // ============================================================
104        //
105        // relm4::menu! {
106        //     main_menu: {
107        //         custom: "my_widget",
108        //         "Example" => ExampleAction,
109        //         "Example2" => ExampleAction,
110        //         "Example toggle" => ExampleU8Action(1_u8),
111        //         section! {
112        //             "Section example" => ExampleAction,
113        //             "Example toggle" => ExampleU8Action(1_u8),
114        //         },
115        //         section! {
116        //             "Example" => ExampleAction,
117        //             "Example2" => ExampleAction,
118        //             "Example Value" => ExampleU8Action(1_u8),
119        //         }
120        //     }
121        // };
122
123        let model = Self { counter };
124        let widgets = view_output!();
125
126        let app = relm4::main_application();
127        app.set_accelerators_for_action::<ExampleAction>(&["<primary>W"]);
128
129        let action: RelmAction<ExampleAction> = {
130            RelmAction::new_stateless(move |_| {
131                println!("Statelesss action!");
132                sender.input(Msg::Increment);
133            })
134        };
135
136        let action2: RelmAction<ExampleU8Action> =
137            RelmAction::new_stateful_with_target_value(&0, |_, state, _value| {
138                *state ^= 1;
139                dbg!(state);
140            });
141
142        let mut group = RelmActionGroup::<WindowActionGroup>::new();
143        group.add_action(action);
144        group.add_action(action2);
145        group.register_for_widget(&widgets.main_window);
146
147        ComponentParts { model, widgets }
148    }
149
150    fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
151        match msg {
152            Msg::Increment => {
153                self.counter = self.counter.wrapping_add(1);
154            }
155            Msg::Decrement => {
156                self.counter = self.counter.wrapping_sub(1);
157            }
158        }
159    }
160}
161
162relm4::new_action_group!(WindowActionGroup, "win");
163
164relm4::new_stateless_action!(ExampleAction, WindowActionGroup, "example");
165relm4::new_stateful_action!(ExampleU8Action, WindowActionGroup, "example2", u8, u8);
166
167fn main() {
168    let app = RelmApp::new("relm4.example.menu");
169    app.run::<App>(0);
170}