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 = >k::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 = >k::Image {
set_icon_name: Some("night-light-symbolic"),
},
},
#[name = "btn_go_homepage"]
gtk::Button {
#[wrap(Some)]
set_child = >k::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 = >k::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 = >k::Image {
set_icon_name: Some("night-light-symbolic"),
},
},
#[name = "btn_go_homepage"]
gtk::Button {
#[wrap(Some)]
set_child = >k::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() {}