changeset 2807:975df4680ff7

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.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Wed, 20 Jul 2022 19:22:06 +0000
parents d7b6e19e44d2
children 965c3c6ed1ed
files ios/dw.m
diffstat 1 files changed, 68 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- 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;
 }