Accessing Nested Template Elements

Starting from the version 0.6.2, you can access nested elements on templates.

Imagine a template called "MainWindow" which contains pages as Widget Templates:

#[relm4::widget_template] impl WidgetTemplate for MainWindow { view! { gtk::Window { set_title: Some("Nested Widget template"), set_default_width: 300, set_default_height: 100, gtk::Box { set_orientation: gtk::Orientation::Vertical, #[name(stk_pages)] gtk::Stack { set_margin_all: 7, #[template] #[name = "home_page"] add_child = &HomePage {} -> { set_name: "main", }, #[template] #[name = "settings_page"] add_child = &SettingsPage {} -> { set_name: "settings", }, }, }, } } }

SettingsPage and HomePage are also a widget template:

#[relm4::widget_template] impl WidgetTemplate for HomePage { view! { gtk::Box { set_orientation: gtk::Orientation::Vertical, set_spacing: 3, #[name = "btn_go_settings"] gtk::Button { #[wrap(Some)] set_child = &gtk::Image { set_icon_name: Some("emblem-system-symbolic"), }, }, } } }
#[relm4::widget_template] impl WidgetTemplate for SettingsPage { view! { gtk::Box { set_orientation: gtk::Orientation::Vertical, set_spacing: 3, #[name = "btn_dark_mode"] gtk::Button { #[wrap(Some)] set_child = &gtk::Image { set_icon_name: Some("night-light-symbolic"), }, }, #[name = "btn_go_homepage"] gtk::Button { #[wrap(Some)] set_child = &gtk::Image { set_icon_name: Some("user-home-symbolic"), }, }, } } }

If you want to handle MainWindow->SettingsPage->btn_dark_mode's clicked event, you can simply do it like this:

#[derive(Default)] struct AppModel { current_page: &'static str, } #[derive(Debug)] enum Message { PageHome, PageSettings, DarkMode, } #[relm4::component] impl SimpleComponent for AppModel { type Init = (); type Input = Message; type Output = (); view! { #[template] MainWindow { #[template_child] settings_page.btn_dark_mode { connect_clicked => Message::DarkMode }, #[template_child] settings_page.btn_go_homepage { connect_clicked => Message::PageHome }, #[template_child] home_page.btn_go_settings { connect_clicked => Message::PageSettings }, #[template_child] stk_pages { #[watch] set_visible_child_name: model.current_page, } }, }

The complete code

use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt}; use relm4::{gtk, ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent, WidgetTemplate}; #[relm4::widget_template] impl WidgetTemplate for HomePage { view! { gtk::Box { set_orientation: gtk::Orientation::Vertical, set_spacing: 3, #[name = "btn_go_settings"] gtk::Button { #[wrap(Some)] set_child = &gtk::Image { set_icon_name: Some("emblem-system-symbolic"), }, }, } } } #[relm4::widget_template] impl WidgetTemplate for SettingsPage { view! { gtk::Box { set_orientation: gtk::Orientation::Vertical, set_spacing: 3, #[name = "btn_dark_mode"] gtk::Button { #[wrap(Some)] set_child = &gtk::Image { set_icon_name: Some("night-light-symbolic"), }, }, #[name = "btn_go_homepage"] gtk::Button { #[wrap(Some)] set_child = &gtk::Image { set_icon_name: Some("user-home-symbolic"), }, }, } } } #[relm4::widget_template] impl WidgetTemplate for MainWindow { view! { gtk::Window { set_title: Some("Nested Widget template"), set_default_width: 300, set_default_height: 100, gtk::Box { set_orientation: gtk::Orientation::Vertical, #[name(stk_pages)] gtk::Stack { set_margin_all: 7, #[template] #[name = "home_page"] add_child = &HomePage {} -> { set_name: "main", }, #[template] #[name = "settings_page"] add_child = &SettingsPage {} -> { set_name: "settings", }, }, }, } } } #[derive(Default)] struct AppModel { current_page: &'static str, } #[derive(Debug)] enum Message { PageHome, PageSettings, DarkMode, } #[relm4::component] impl SimpleComponent for AppModel { type Init = (); type Input = Message; type Output = (); view! { #[template] MainWindow { #[template_child] settings_page.btn_dark_mode { connect_clicked => Message::DarkMode }, #[template_child] settings_page.btn_go_homepage { connect_clicked => Message::PageHome }, #[template_child] home_page.btn_go_settings { connect_clicked => Message::PageSettings }, #[template_child] stk_pages { #[watch] set_visible_child_name: model.current_page, } }, } fn init( _init_param: Self::Init, root: Self::Root, sender: ComponentSender<Self>, ) -> ComponentParts<Self> { let model = Self { current_page: "main", }; let widgets = view_output!(); ComponentParts { model, widgets } } fn update(&mut self, msg: Message, _sender: ComponentSender<Self>) { match msg { Message::DarkMode => { println!("Mode changed"); } Message::PageHome => { self.current_page = "main"; } Message::PageSettings => { self.current_page = "settings"; } } } } fn main() {}