This commit is contained in:
David Lemarier
2021-04-30 11:06:25 -04:00
parent 3e7df4dbb6
commit 1a693ce1d8
4 changed files with 39 additions and 84 deletions

View File

@@ -18,12 +18,10 @@ fn main() {
.with_title("A fantastic window!")
.with_menu(vec![
Menu::new(
"",
// on macOS first menu is always app name
"my custom app",
vec![
MenuItem::About("Todos".to_string()),
MenuItem::Separator,
MenuItem::new("preferences".to_string(), "Preferences".to_string()).key(","),
MenuItem::Separator,
MenuItem::Services,
MenuItem::Separator,
MenuItem::Hide,
@@ -34,9 +32,9 @@ fn main() {
],
),
Menu::new(
"Custom menu",
"File",
vec![
MenuItem::new("add_todo".to_string(), "Add Todo".to_string()).key("+"),
MenuItem::new("change_menu".to_string(), "Change menu".to_string()).key("+"),
MenuItem::Separator,
MenuItem::CloseWindow,
],
@@ -56,7 +54,10 @@ fn main() {
),
Menu::new("View", vec![MenuItem::EnterFullScreen]),
Menu::new("Window", vec![MenuItem::Minimize, MenuItem::Zoom]),
Menu::new("Help", vec![]),
Menu::new(
"Help",
vec![MenuItem::new("help_me".to_string(), "Custom help".to_string()).key("-")],
),
])
.build(&event_loop)
.unwrap();
@@ -72,7 +73,21 @@ fn main() {
Event::MainEventsCleared => {
window.request_redraw();
}
// not sure if we should add a new event type?
// or try to re-use the UserEvent::<T>
Event::MenuEvent(menu_id) => {
if menu_id == "change_menu" {
// update menu
window.set_menu(Some(vec![Menu::new(
"File",
vec![
MenuItem::new("add_todo".to_string(), "Add Todo".to_string()).key("+"),
MenuItem::Separator,
MenuItem::CloseWindow,
],
)]))
}
println!("Clicked on {}", menu_id);
window.set_title("New window title!");
}

View File

@@ -1,64 +0,0 @@
use std::collections::HashMap;
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, KeyboardInput, WindowEvent},
event_loop::{ControlFlow, EventLoop},
menu::{Menu, MenuItem},
window::{Window, WindowBuilder},
};
fn main() {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new();
let mut windows = HashMap::new();
for _ in 0..3 {
let window = WindowBuilder::new()
.with_menu(vec![Menu::new(
"asf",
vec![
MenuItem::About("My app!".to_string()),
MenuItem::Separator,
MenuItem::ShowAll,
],
)])
.build(&event_loop)
.unwrap();
windows.insert(window.id(), window);
}
event_loop.run(move |event, event_loop, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent { event, window_id } => {
match event {
WindowEvent::CloseRequested => {
println!("Window {:?} has received the signal to close", window_id);
// This drops the window, causing it to close.
windows.remove(&window_id);
if windows.is_empty() {
*control_flow = ControlFlow::Exit;
}
}
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
..
},
..
} => {
let window = Window::new(&event_loop).unwrap();
windows.insert(window.id(), window);
}
_ => (),
}
}
_ => (),
}
})
}

View File

@@ -15,6 +15,10 @@ impl Menu {
#[derive(Debug, Clone)]
pub struct CustomMenu {
// todo: replace id by a type that
// we can send from the with_menu::<T>()
// or we could check to use the UserEvent::<T> but
// my latest test failed
pub id: String,
pub name: String,
pub key: Option<String>,
@@ -22,15 +26,10 @@ pub struct CustomMenu {
#[derive(Debug, Clone)]
pub enum MenuItem {
/// A custom MenuItem. This type functions as a builder, so you can customize it easier.
/// You can (and should) create this variant via the `new(title)` method, but if you need to do
/// something crazier, then wrap it in this and you can hook into the Cacao menu system
/// accordingly.
/// A custom MenuItem
Custom(CustomMenu),
/// Shows a standard "About" item, which will bring up the necessary window when clicked
/// (include a `credits.html` in your App to make use of here). The argument baked in here
/// should be your app name.
/// Shows a standard "About" item
About(String),
/// A standard "hide the app" menu item.
@@ -77,18 +76,17 @@ pub enum MenuItem {
/// An item for minimizing the window with the standard system controls.
Minimize,
/// An item for instructing the app to zoom. Your app must react to this with necessary window
/// lifecycle events.
/// An item for instructing the app to zoom
Zoom,
/// Represents a Separator. It's useful nonetheless for
/// separating out pieces of the `NSMenu` structure.
/// Represents a Separator
Separator,
}
impl MenuItem {
pub fn new(unique_menu_id: String, title: String) -> Self {
MenuItem::Custom(CustomMenu {
// todo: would be great if we could pass a type?
id: unique_menu_id,
key: None,
name: title,

View File

@@ -15,7 +15,7 @@ use objc::runtime::NO;
use crate::{
dpi::LogicalSize,
menu::Menu,
platform_impl::platform::{ffi, util::IdRef, window::SharedState},
platform_impl::platform::{ffi, menu, util::IdRef, window::SharedState},
};
// Unsafe wrapper type that allows us to dispatch things that aren't Send.
@@ -208,7 +208,13 @@ pub unsafe fn set_title_async(ns_window: id, title: String) {
// `setMenu:` isn't thread-safe.
pub unsafe fn set_menu_async(_ns_window: id, menu: Option<Vec<Menu>>) {
dbg!(menu);
// todo: if None we should set an empty menu maybe?
// on windows we can remove it, in macOS we can't
if let Some(menu) = menu {
Queue::main().exec_async(move || {
menu::initialize(menu);
});
}
}
// `close:` is thread-safe, but we want the event to be triggered from the main