antoyo / relm

Idiomatic, GTK+-based, GUI library, inspired by Elm, written in Rust
MIT License
2.41k stars 79 forks source link

Nested view! macros use inner view as outer root #305

Open msrd0 opened 1 year ago

msrd0 commented 1 year ago

I have the following code:

#[widget]
impl Widget for MyWidget {
    // ...
    view! {
        gtk::Box {
            orientation: Orientation::Horizontal,
            spacing: 10,

            // ...

            gtk::ToolButton {
                hexpand: false,
                clicked => Msg::Delete,
                icon_widget: view! {
                    gtk::Image {
                        icon_name: Some("edit-delete"),
                        icon_size: IconSize::Button
                    }
                }
            }
        }
    }
}

At runtime, the entire widget is not rendered, and instead I see this message on the terminal:

(myapp:104508): Gtk-WARNING **: 19:28:54.676: Attempting to add a widget with type GtkImage to a container of type GtkBox, but the widget is already inside a container of type GtkButton, please remove the widget from its existing container first.

The macro outputs the following code, which I believe is wrong:

impl Widget for MyWidget {
    // ...
    type Root = gtk::Image;
    fn root(&self) -> Self::Root {
        self.widgets.gtkimage1.clone()
    }
}

The widget is added inside a gtk::Box in another widget, but what I believe is happening is that only the image in the inner view! macro is being added, instead of the outer view! macro.

antoyo commented 1 year ago

Sorry, I forgot this.

I have the following example that works:

use gtk::{
    IconSize,
    Inhibit,
    prelude::{ImageExt, ImageExtManual},
    prelude::OrientableExt,
    prelude::ToolButtonExt,
    prelude::WidgetExt,
};
use gtk::Orientation::Vertical;
use relm::{Relm, Widget};
use relm_derive::{Msg, widget};

use self::Msg::*;

#[derive(Clone, Msg)]
pub enum Msg {
    Quit,
}

#[widget]
impl Widget for Win {
    fn model(_relm: &Relm<Self>, _: ()) -> () {
    }

    fn update(&mut self, event: Msg) {
        match event {
            Quit => gtk::main_quit(),
        }
    }

    view! {
        gtk::Window {
            gtk::Box {
                gtk::Toolbar {
                    gtk::ToolButton {
                        icon_widget: view! {
                            gtk::Image {
                                icon_name: Some("edit-delete"),
                                icon_size: IconSize::Button
                            }
                        }
                    },
                },
                orientation: Vertical,
            },
            delete_event(_, _) => (Quit, Inhibit(false)),
        }
    }
}

fn main() {
    Win::run(()).expect("Win::run failed");
}

Does it work for you?