# HG changeset patch # User bsmith@81767d24-ef19-dc11-ae90-00e081727c95 # Date 1658344926 0 # Node ID 975df4680ff7e2575b2f4a2068a8b8de9beb6a4e # Parent d7b6e19e44d2cd4891fa205be6d8448361d4fda4 iOS: Need to trigger window menu rebuilds if a menu item changes. Currently if code changes the checked or enabled state of a menu item it triggers a repopulation of all menus on all windows. We may be able to reduce this by attempting to detect which window the menu item is a descendant of and only repopulate that menu... however this will do for now. diff -r d7b6e19e44d2 -r 975df4680ff7 ios/dw.m --- a/ios/dw.m Wed Jul 20 09:30:33 2022 +0000 +++ b/ios/dw.m Wed Jul 20 19:22:06 2022 +0000 @@ -715,6 +715,7 @@ NSMutableArray *children; NSString *title; unsigned long tag; + UIWindow *window; } -(id)initWithTag:(unsigned long)newtag; -(void)setTitle:(NSString *)input; @@ -813,6 +814,7 @@ -(void)setPopupMenu:(DWMenu *)input; -(DWMenu *)menu; -(DWMenu *)popupMenu; +-(void)updateMenu; -(void *)userdata; -(void)setUserdata:(void *)input; @end @@ -834,6 +836,29 @@ -(void)layoutSubviews { } -(void)setMenu:(DWMenu *)input { [windowmenu release]; windowmenu = input; [windowmenu retain]; } -(void)setPopupMenu:(DWMenu *)input { [popupmenu release]; popupmenu = input; [popupmenu retain]; } +-(void)updateMenu +{ + if(windowmenu) + { + NSArray *array = [[[self rootViewController] view] subviews]; + UINavigationBar *nav = nil; + + for(id obj in array) + { + if([obj isMemberOfClass:[UINavigationBar class]]) + nav = obj; + } + if(nav) + { + UINavigationItem *item = [[nav items] firstObject]; + + if (@available(iOS 14.0, *)) { + if(item && item.rightBarButtonItem && item.rightBarButtonItem.menu) + [item.rightBarButtonItem setMenu:[windowmenu menu]]; + } + } + } +} -(DWMenu *)menu { return windowmenu; } -(DWMenu *)popupMenu { return popupmenu; } -(void)closeWindow:(id)sender @@ -1845,6 +1870,7 @@ else menu = [UIMenu menuWithTitle:@"" children:menuchildren]; } + [menu retain]; if(oldmenu) [oldmenu release]; return menu; @@ -1870,7 +1896,12 @@ } return nil; } --(void)dealloc { [super dealloc]; } +-(void)dealloc +{ + if(menu) + [menu release]; + [super dealloc]; +} @end @implementation DWImage @@ -8593,7 +8624,17 @@ item = [DWMenuItem actionWithTitle:nstr image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) { + if(check) + { + UIMenuElementState state = [item state] == UIMenuElementStateOn ? UIMenuElementStateOff : UIMenuElementStateOn; + [item setState:state]; + } [DWObj menuHandler:item]; + if(check) + { + for(id obj in _dw_toplevel_windows) + [obj updateMenu]; + } }]; /* Don't set the tag if the ID is 0 or -1 */ if(itemid != DW_MENU_AUTO && itemid != DW_MENU_POPUP) @@ -8635,10 +8676,15 @@ if(menuitem != nil) { - if(check) - [menuitem setState:UIMenuElementStateOn]; - else - [menuitem setState:UIMenuElementStateOff]; + UIMenuElementState newstate = check ? UIMenuElementStateOn : UIMenuElementStateOff; + + /* Only force the menus to repopulate if something changed */ + if(newstate != [menuitem state]) + { + [menuitem setState:newstate]; + for(id obj in _dw_toplevel_windows) + [obj updateMenu]; + } } } @@ -8678,21 +8724,23 @@ if(menuitem != nil) { + UIMenuElementState oldstate = [menuitem state]; + BOOL oldenabled = [menuitem enabled]; + if(state & DW_MIS_CHECKED) - { [menuitem setState:UIMenuElementStateOn]; - } else if(state & DW_MIS_UNCHECKED) - { [menuitem setState:UIMenuElementStateOff]; - } if(state & DW_MIS_ENABLED) - { [menuitem setEnabled:YES]; - } else if(state & DW_MIS_DISABLED) - { [menuitem setEnabled:NO]; + + /* Only force the menus to repopulate if something changed */ + if(oldstate != [menuitem state] || oldenabled != [menuitem enabled]) + { + for(id obj in _dw_toplevel_windows) + [obj updateMenu]; } } } @@ -9197,6 +9245,8 @@ else if([object isMemberOfClass:[DWMenuItem class]]) { DWMenuItem *menuitem = object; + UIMenuElementState oldstate = [menuitem state]; + BOOL oldenabled = [menuitem enabled]; if(mask & (DW_MIS_CHECKED | DW_MIS_UNCHECKED)) { @@ -9212,6 +9262,12 @@ else if(style & DW_MIS_DISABLED) [menuitem setEnabled:NO]; } + /* Only force the menus to repopulate if something changed */ + if(oldstate != [menuitem state] || oldenabled != [menuitem enabled]) + { + for(id obj in _dw_toplevel_windows) + [obj updateMenu]; + } } DW_FUNCTION_RETURN_NOTHING; }