Iced Gui Menu Implementation rephrased

I feel as though my last posing of this question was poorly stated. I need help understanding how to implement an iced menu for my application.
There are four parameters total for the Menu::new() function.

  • state: &'a mut State
  • options: &'a [T]
  • hovered_option: &'a mut Option usize
  • last_selection: &'a mut Option T

I am confused as to how to implement this. For the state I am simply creating a new state, line 44, but am not sure if this is correct. I am fairly sure I have options correct, though could be wrong. I understand what types are expected for hovered_option and last_selection, though I do not understand what those parameters pertain to, and in effect what to pass.
The below code is my attempt to just create a menu in some bogus application but I get an error on line 57. This is where I get clueless. I do not understand how to place an overlay on top of a widget.

Cargo.toml

[dependencies]
iced = { version = "0.9.0" }

main.rs

use iced::{Settings, Application, executor, Command, Theme, Element, overlay::menu::{self, Menu}, widget::{container, row}, Length};

fn main() -> iced::Result {
    Example::run(Settings::default())
}

#[derive(Debug)]
struct Example {
    service: Option<Service>
}

#[derive(Debug, Clone)]
enum Message {
    ServiceSelected(Service)
}

impl Application for Example {
    type Executor = executor::Default;
    type Message = Message;
    type Theme = Theme;
    type Flags = ();

    fn new(_flags: ()) -> (Self, Command<Message>) {
        (
            Self { service: None },
            Command::none()
        )
    }

    fn title(&self) -> String {
        String::from("Example")
    }

    fn update(&mut self, message: Self::Message) -> iced::Command<Self::Message> {
        match message {
            Message::ServiceSelected(service) => {
                self.service = Some(service);
            },
        }
        Command::none()
    }

    fn view(&self) -> Element<Message> {
        let mut menu_state = menu::State::new();
        let menu = Menu::new(
            &mut menu_state,
            &Service::ALL[..],
            &mut Some(0),
            &mut Some(Service::Login)
        )
        .padding(10)
        .text_size(8)
        .width(20.0);

        let mut content = row![];

        content = content.push(menu);

        container(content)
        .width(Length::Fill)
        .height(Length::Fill)
        .padding(10)
        .into()
    }
}

#[derive(Debug, Clone)]
enum Service {
    Account,
    Chat,
    Login,
    Test,
}

impl<'a> Service {
    pub const ALL: [Service; 4] = [
        Service::Account,
        Service::Chat,
        Service::Login,
        Service::Test
    ];
}

impl<'a> std::fmt::Display for Service {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Service::Account => "Account",
                Service::Chat => "Chat",
                Service::Login => "Login",
                Service::Test => "Test",
            }
        )
    }
}

I'm not familiar with this library, but at a glance it's not clear that Menu is meant to stand alone as its own widget; it looks to be an implementation detail of PickList. To use it on its own, I think you would need to create a custom widget and return the newly-constructed menu from its implementation of overlay, like PickList does. Alternatively, if you just want a simple drop-down, you could use PickList instead:

let options = &Service::ALL[..];
let selected = self.service.clone();
fn on_selected(option: Service) -> Message {
    Message::ServiceSelected(option)
}
let mut content = row![iced::widget::PickList::new(
    options,
    selected,
    on_selected
)];

Making Menu public seems to have been mostly for theming purposes, based on my reading of this pull request:

1 Like

Thank you, I have been using a pick_list instead just to get past this point. I realized once I was creating this help ticket that menu wasn't actually a widget but an overlay. Didn't think of it in terms of being a style for another widget, primarily a pick_list, so I will look into that and read through the resource you shared!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.