Store and synchronize Menu in application::State

This commit is contained in:
Héctor Ramón Jiménez 2021-07-12 22:28:18 +02:00
parent b3ff522c18
commit 31997d255f
No known key found for this signature in database
GPG key ID: 44B88EB52AB1EE8D
5 changed files with 64 additions and 13 deletions

View file

@ -4,11 +4,17 @@ use crate::keyboard::Hotkey;
/// Menu representation. /// Menu representation.
/// ///
/// This can be used by `shell` implementations to create a menu. /// This can be used by `shell` implementations to create a menu.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone)]
pub struct Menu<Message> { pub struct Menu<Message> {
entries: Vec<Entry<Message>>, entries: Vec<Entry<Message>>,
} }
impl<Message> PartialEq for Menu<Message> {
fn eq(&self, other: &Self) -> bool {
self.entries == other.entries
}
}
impl<Message> Menu<Message> { impl<Message> Menu<Message> {
/// Creates an empty [`Menu`]. /// Creates an empty [`Menu`].
pub fn new() -> Self { pub fn new() -> Self {
@ -27,13 +33,13 @@ impl<Message> Menu<Message> {
} }
/// Returns a [`MenuEntry`] iterator. /// Returns a [`MenuEntry`] iterator.
pub fn iter(self) -> impl Iterator<Item = Entry<Message>> { pub fn iter(&self) -> impl Iterator<Item = &Entry<Message>> {
self.entries.into_iter() self.entries.iter()
} }
} }
/// Represents one of the possible entries used to build a [`Menu`]. /// Represents one of the possible entries used to build a [`Menu`].
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone)]
pub enum Entry<Message> { pub enum Entry<Message> {
/// Item for a [`Menu`] /// Item for a [`Menu`]
Item { Item {
@ -82,3 +88,29 @@ impl<Message> Entry<Message> {
Entry::Dropdown { content, submenu } Entry::Dropdown { content, submenu }
} }
} }
impl<Message> PartialEq for Entry<Message> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(
Entry::Item {
content, hotkey, ..
},
Entry::Item {
content: other_content,
hotkey: other_hotkey,
..
},
) => content == other_content && hotkey == other_hotkey,
(
Entry::Dropdown { content, submenu },
Entry::Dropdown {
content: other_content,
submenu: other_submenu,
},
) => content == other_content && submenu == other_submenu,
(Entry::Separator, Entry::Separator) => true,
_ => false,
}
}
}

View file

@ -52,11 +52,14 @@ where
runtime.track(subscription); runtime.track(subscription);
let context = { let context = {
let builder = settings.window.into_builder( let builder = settings
&application.title(), .window
application.mode(), .into_builder(
event_loop.primary_monitor(), &application.title(),
); application.mode(),
event_loop.primary_monitor(),
)
.with_menu(Some(conversion::menu(&application.menu())));
let context = ContextBuilder::new() let context = ContextBuilder::new()
.with_vsync(true) .with_vsync(true)

View file

@ -151,6 +151,7 @@ where
application.mode(), application.mode(),
event_loop.primary_monitor(), event_loop.primary_monitor(),
) )
.with_menu(Some(conversion::menu(&application.menu())))
.build(&event_loop) .build(&event_loop)
.map_err(Error::WindowCreationFailed)?; .map_err(Error::WindowCreationFailed)?;

View file

@ -1,5 +1,5 @@
use crate::conversion; use crate::conversion;
use crate::{Application, Color, Debug, Mode, Point, Size, Viewport}; use crate::{Application, Color, Debug, Menu, Mode, Point, Size, Viewport};
use std::marker::PhantomData; use std::marker::PhantomData;
use winit::event::{Touch, WindowEvent}; use winit::event::{Touch, WindowEvent};
@ -9,6 +9,7 @@ use winit::window::Window;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct State<A: Application> { pub struct State<A: Application> {
title: String, title: String,
menu: Menu<A::Message>,
mode: Mode, mode: Mode,
background_color: Color, background_color: Color,
scale_factor: f64, scale_factor: f64,
@ -23,6 +24,7 @@ impl<A: Application> State<A> {
/// Creates a new [`State`] for the provided [`Application`] and window. /// Creates a new [`State`] for the provided [`Application`] and window.
pub fn new(application: &A, window: &Window) -> Self { pub fn new(application: &A, window: &Window) -> Self {
let title = application.title(); let title = application.title();
let menu = application.menu();
let mode = application.mode(); let mode = application.mode();
let background_color = application.background_color(); let background_color = application.background_color();
let scale_factor = application.scale_factor(); let scale_factor = application.scale_factor();
@ -36,10 +38,9 @@ impl<A: Application> State<A> {
) )
}; };
window.set_menu(Some(conversion::menu(application.menu())));
Self { Self {
title, title,
menu,
mode, mode,
background_color, background_color,
scale_factor, scale_factor,
@ -52,6 +53,11 @@ impl<A: Application> State<A> {
} }
} }
/// Returns the current [`Menu`] of the [`State`].
pub fn menu(&self) -> &Menu<A::Message> {
&self.menu
}
/// Returns the current background [`Color`] of the [`State`]. /// Returns the current background [`Color`] of the [`State`].
pub fn background_color(&self) -> Color { pub fn background_color(&self) -> Color {
self.background_color self.background_color
@ -205,5 +211,14 @@ impl<A: Application> State<A> {
self.scale_factor = new_scale_factor; self.scale_factor = new_scale_factor;
} }
// Update menu
let new_menu = application.menu();
if self.menu != new_menu {
window.set_menu(Some(conversion::menu(&new_menu)));
self.menu = new_menu;
}
} }
} }

View file

@ -177,7 +177,7 @@ fn hotkey(hotkey: keyboard::Hotkey) -> winit::window::Hotkey {
/// ///
/// [`winit`]: https://github.com/rust-windowing/winit /// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native /// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
pub fn menu<Message>(menu: Menu<Message>) -> winit::window::Menu { pub fn menu<Message>(menu: &Menu<Message>) -> winit::window::Menu {
let mut converted = winit::window::Menu::new(); let mut converted = winit::window::Menu::new();
for item in menu.iter() { for item in menu.iter() {