Allow inserting optional values in row!() and column!() macros

like the title says. It would be less tedious than creating a row/column then using push_maybe() for every item.

Edit: here an example

row![
    Item1,
    None,
    Some(item2)
]

Edit 2: after some testing. it seems doing it like the example above is not possible.

I understand the need of such macro but I am not sure how to implement it.

On way would be to have a macro that accepts only options like this:

row_maybe![
    Some(Item1),
    Some(Item2)
]

But I feel like wrapping all items in a Some is as tedious as push_maybe.

I am not shure if it is possible to have a macro that can do something like this:

row![
    Item1,
    None,
    Some(item2)
]

How did you imagine the macro to look like?

1 Like

I tried to find a way to do that (my second example) but could not figure out how to create a macro that can work with such inputs (mostly asked chat gpt).

yeah macros are confusing for me too. but I am very confident it’s possible. (i could be wrong tho)

Do you know of any crate or example code that shows such macro? Maybe by looking at that code we can figure out how to do that.

no not really but let me give try i’ll get back to you if i manage to figure it out

after some testing, it’s seems it isn’t possible

If you have an iterator, you can simply use the fn column() helper instead of column![]. The function is effectively Column::with_children which takes an iterator of elements, so you can use .filter_map() to get only the values that are Some.

Here’s an example:

use iced::widget::{column, row, text, text_input};
use iced::{Element, Size, Task};

fn main() -> iced::Result {
    iced::application("iced • optional elements", App::update, App::view)
        .window_size(Size::new(400.0, 400.0))
        .centered()
        .run_with(App::new)
}

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

#[derive(Default)]
struct App {
    number: u16,
}

impl App {
    fn new() -> (Self, Task<Message>) {
        (Self::default(), iced::widget::focus_next())
    }

    fn update(&mut self, message: Message) -> Task<Message> {
        match message {
            Message::Input(value) => {
                self.number = value
                    .parse()
                    .ok()
                    .filter(|&num| num > 0 && num <= 100)
                    .unwrap_or(0);
                Task::none()
            }
        }
    }

    fn view(&self) -> Element<Message> {
        let input_value = if self.number == 0 {
            String::new()
        } else {
            self.number.to_string()
        };

        column![
            text_input("Enter a number from 1-100...", &input_value)
                .on_input(Message::Input)
                .padding(5),
            text("Has these multiples up to 100:").size(16),
            row(multiples(self.number).into_iter().filter_map(|opt| opt))
                .spacing(10)
                .wrap()
        ]
        .padding(20)
        .spacing(20)
        .into()
    }
}

fn multiples<'a>(divider: u16) -> impl Iterator<Item = Option<Element<'a, Message>>> {
    (1..=100).map(move |n| {
        if divider > 0 && n % divider == 0 {
            Some(
                text(format!("{:3}", n))
                    .size(14)
                    .font(iced::Font::MONOSPACE)
                    .into(),
            )
        } else {
            None
        }
    })
}
1 Like

I think I found a way to do something like my second code example. I will see if I find a way to implement it.

My code did not work and although I had very good help from the rust discord it did not work.