Disable menu item key equivalents while there are pending keystrokes
This commit is contained in:
parent
21862faa58
commit
b72d97ce78
5 changed files with 43 additions and 5 deletions
|
@ -192,11 +192,18 @@ impl App {
|
||||||
cx.borrow_mut().quit();
|
cx.borrow_mut().quit();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
foreground_platform.on_will_open_menu(Box::new({
|
||||||
|
let cx = app.0.clone();
|
||||||
|
move || {
|
||||||
|
let mut cx = cx.borrow_mut();
|
||||||
|
cx.keystroke_matcher.clear_pending();
|
||||||
|
}
|
||||||
|
}));
|
||||||
foreground_platform.on_validate_menu_command(Box::new({
|
foreground_platform.on_validate_menu_command(Box::new({
|
||||||
let cx = app.0.clone();
|
let cx = app.0.clone();
|
||||||
move |action| {
|
move |action| {
|
||||||
let cx = cx.borrow_mut();
|
let cx = cx.borrow_mut();
|
||||||
cx.is_action_available(action)
|
!cx.keystroke_matcher.has_pending_keystrokes() && cx.is_action_available(action)
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
foreground_platform.on_menu_command(Box::new({
|
foreground_platform.on_menu_command(Box::new({
|
||||||
|
|
|
@ -123,6 +123,10 @@ impl Matcher {
|
||||||
self.pending.clear();
|
self.pending.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_pending_keystrokes(&self) -> bool {
|
||||||
|
!self.pending.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push_keystroke(
|
pub fn push_keystroke(
|
||||||
&mut self,
|
&mut self,
|
||||||
keystroke: Keystroke,
|
keystroke: Keystroke,
|
||||||
|
|
|
@ -74,6 +74,7 @@ pub(crate) trait ForegroundPlatform {
|
||||||
|
|
||||||
fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>);
|
fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>);
|
||||||
fn on_validate_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>);
|
fn on_validate_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>);
|
||||||
|
fn on_will_open_menu(&self, callback: Box<dyn FnMut()>);
|
||||||
fn set_menus(&self, menus: Vec<Menu>, matcher: &keymap::Matcher);
|
fn set_menus(&self, menus: Vec<Menu>, matcher: &keymap::Matcher);
|
||||||
fn prompt_for_paths(
|
fn prompt_for_paths(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -93,6 +93,10 @@ unsafe fn build_classes() {
|
||||||
sel!(validateMenuItem:),
|
sel!(validateMenuItem:),
|
||||||
validate_menu_item as extern "C" fn(&mut Object, Sel, id) -> bool,
|
validate_menu_item as extern "C" fn(&mut Object, Sel, id) -> bool,
|
||||||
);
|
);
|
||||||
|
decl.add_method(
|
||||||
|
sel!(menuWillOpen:),
|
||||||
|
menu_will_open as extern "C" fn(&mut Object, Sel, id),
|
||||||
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(application:openURLs:),
|
sel!(application:openURLs:),
|
||||||
open_urls as extern "C" fn(&mut Object, Sel, id, id),
|
open_urls as extern "C" fn(&mut Object, Sel, id, id),
|
||||||
|
@ -112,14 +116,21 @@ pub struct MacForegroundPlatformState {
|
||||||
event: Option<Box<dyn FnMut(crate::Event) -> bool>>,
|
event: Option<Box<dyn FnMut(crate::Event) -> bool>>,
|
||||||
menu_command: Option<Box<dyn FnMut(&dyn Action)>>,
|
menu_command: Option<Box<dyn FnMut(&dyn Action)>>,
|
||||||
validate_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>,
|
validate_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>,
|
||||||
|
will_open_menu: Option<Box<dyn FnMut()>>,
|
||||||
open_urls: Option<Box<dyn FnMut(Vec<String>)>>,
|
open_urls: Option<Box<dyn FnMut(Vec<String>)>>,
|
||||||
finish_launching: Option<Box<dyn FnOnce() -> ()>>,
|
finish_launching: Option<Box<dyn FnOnce() -> ()>>,
|
||||||
menu_actions: Vec<Box<dyn Action>>,
|
menu_actions: Vec<Box<dyn Action>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MacForegroundPlatform {
|
impl MacForegroundPlatform {
|
||||||
unsafe fn create_menu_bar(&self, menus: Vec<Menu>, keystroke_matcher: &keymap::Matcher) -> id {
|
unsafe fn create_menu_bar(
|
||||||
|
&self,
|
||||||
|
menus: Vec<Menu>,
|
||||||
|
delegate: id,
|
||||||
|
keystroke_matcher: &keymap::Matcher,
|
||||||
|
) -> id {
|
||||||
let menu_bar = NSMenu::new(nil).autorelease();
|
let menu_bar = NSMenu::new(nil).autorelease();
|
||||||
|
menu_bar.setDelegate_(delegate);
|
||||||
let mut state = self.0.borrow_mut();
|
let mut state = self.0.borrow_mut();
|
||||||
|
|
||||||
state.menu_actions.clear();
|
state.menu_actions.clear();
|
||||||
|
@ -130,6 +141,7 @@ impl MacForegroundPlatform {
|
||||||
let menu_name = menu_config.name;
|
let menu_name = menu_config.name;
|
||||||
|
|
||||||
menu.setTitle_(ns_string(menu_name));
|
menu.setTitle_(ns_string(menu_name));
|
||||||
|
menu.setDelegate_(delegate);
|
||||||
|
|
||||||
for item_config in menu_config.items {
|
for item_config in menu_config.items {
|
||||||
let item;
|
let item;
|
||||||
|
@ -242,6 +254,10 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
|
||||||
self.0.borrow_mut().menu_command = Some(callback);
|
self.0.borrow_mut().menu_command = Some(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_will_open_menu(&self, callback: Box<dyn FnMut()>) {
|
||||||
|
self.0.borrow_mut().will_open_menu = Some(callback);
|
||||||
|
}
|
||||||
|
|
||||||
fn on_validate_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>) {
|
fn on_validate_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>) {
|
||||||
self.0.borrow_mut().validate_menu_command = Some(callback);
|
self.0.borrow_mut().validate_menu_command = Some(callback);
|
||||||
}
|
}
|
||||||
|
@ -249,7 +265,7 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
|
||||||
fn set_menus(&self, menus: Vec<Menu>, keystroke_matcher: &keymap::Matcher) {
|
fn set_menus(&self, menus: Vec<Menu>, keystroke_matcher: &keymap::Matcher) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let app: id = msg_send![APP_CLASS, sharedApplication];
|
let app: id = msg_send![APP_CLASS, sharedApplication];
|
||||||
app.setMainMenu_(self.create_menu_bar(menus, keystroke_matcher));
|
app.setMainMenu_(self.create_menu_bar(menus, app.delegate(), keystroke_matcher));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,6 +780,17 @@ extern "C" fn validate_menu_item(this: &mut Object, _: Sel, item: id) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" fn menu_will_open(this: &mut Object, _: Sel, _: id) {
|
||||||
|
unsafe {
|
||||||
|
let platform = get_foreground_platform(this);
|
||||||
|
let mut platform = platform.0.borrow_mut();
|
||||||
|
if let Some(mut callback) = platform.will_open_menu.take() {
|
||||||
|
callback();
|
||||||
|
platform.will_open_menu = Some(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn ns_string(string: &str) -> id {
|
unsafe fn ns_string(string: &str) -> id {
|
||||||
NSString::alloc(nil).init_str(string).autorelease()
|
NSString::alloc(nil).init_str(string).autorelease()
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,9 +73,8 @@ impl super::ForegroundPlatform for ForegroundPlatform {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_menu_command(&self, _: Box<dyn FnMut(&dyn Action)>) {}
|
fn on_menu_command(&self, _: Box<dyn FnMut(&dyn Action)>) {}
|
||||||
|
|
||||||
fn on_validate_menu_command(&self, _: Box<dyn FnMut(&dyn Action) -> bool>) {}
|
fn on_validate_menu_command(&self, _: Box<dyn FnMut(&dyn Action) -> bool>) {}
|
||||||
|
fn on_will_open_menu(&self, _: Box<dyn FnMut()>) {}
|
||||||
fn set_menus(&self, _: Vec<crate::Menu>, _: &keymap::Matcher) {}
|
fn set_menus(&self, _: Vec<crate::Menu>, _: &keymap::Matcher) {}
|
||||||
|
|
||||||
fn prompt_for_paths(
|
fn prompt_for_paths(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue