Can I add/remove widgets to/from a Row at runtime?

Hi! Iced n00b here. I am developing a program for managing sound samples. The main window will be more or less like a file browser that displays the contents of a directory as a grid of icons. There will be some differences in the details, but I think in terms of the layout that’s close enough. In any case, I’m at a very early stage, so many things will change.

I have created an initial prototype with GTK-RS, using a FlowBox for the layout. But in so doing, I realized I would really prefer not to work with GTK-RS, so I decided to try out Iced.

Anyway, I’ve created a minimal experiment to test the layout (code attached at end). It appears that a wrapped Row has the layout behavior I want, but there’s a problem. My application requires the ability to add and remove items at runtime (e.g. using drag & drop). From the API docs, it doesn’t appear to be possible to manipulate the contents of a Row once it is displayed. So, is the answer simply to maintain the collection separately in the application state, and replace the whole Row when it needs to be updated? Or is there some trick I haven’t discovered?

use iced::widget::{Text, text, button, Row, row, mouse_area};
use iced::application;
use iced::Element;
use iced::Task;
use iced::Length;

#[derive(Debug, Clone)]
enum Message {
    Set(String),
}

#[derive(Debug, Clone)]
struct LayoutTest {
    content: Option,
}

impl LayoutTest {
    fn new() → Self {
        LayoutTest { content: None }
    }

    fn view(&self) -> Element<'_, Message> {
        let mut texts = vec![];
        for n in 1..10 {
            for c in 'A'..'K' {
                let tw = mouse_area(
                    text(format!("{}{}", c, n))
                        .size(28)
                        .width(Length::Fixed(44.0))
                        .height(Length::Fixed(37.0))
                        .center()
                ).on_press(Message::Set(format!("{}{}", c, n)));
                texts.push(tw.into())
            }
        }
        Row::from_vec(texts).wrap().into()
    }

    fn update(&mut self, msg: Message) -> Task<Message> {
        match msg {
            Message::Set(s) => {
                self.content = Some(s.clone());
                println!("Set: {}", s)
            }
        }
        Task::none()
    }
}

fn main() → iced::Result {
    application(“Wrapped Row Layout”, LayoutTest::update, LayoutTest::view)
        .run_with(|| (LayoutTest::new(), Task::none()))
}

You display your app based on you app state. Lets say you have a list of samples in the state. In the view code, you create the row items based on that. You can change displayed row by mutating that list in your state (in the update function that gets called after a message is fired). After the update function, the view is called again and the ui changes.

For a full example, you might want to look at the todos example