Lagrange [work/v1.7]

Disabling items in native menus

=> 2ed9d1bbd3b92b8d39a368963c3fd5d0fbcdc974

diff --git a/src/macos.m b/src/macos.m
index d9ee71e7..24c83aec 100644
--- a/src/macos.m
+++ b/src/macos.m
@@ -553,10 +553,15 @@ static void makeMenuItems_(NSMenu *menu, MenuCommands *commands, const iMenuItem
         else {
             const iBool hasCommand = (items[i].command && items[i].command[0]);
             iBool isChecked = iFalse;
+            iBool isDisabled = iFalse;
             if (startsWith_CStr(label, "###")) {
                 isChecked = iTrue;
                 label += 3;
             }
+            else if (startsWith_CStr(label, "///")) {
+                isDisabled = iTrue;
+                label += 3;
+            }
             iString itemTitle;
             initCStr_String(&itemTitle, label);
             removeIconPrefix_String(&itemTitle);
@@ -571,6 +576,7 @@ static void makeMenuItems_(NSMenu *menu, MenuCommands *commands, const iMenuItem
             if (isChecked) {
                 [item setState:NSControlStateValueOn];
             }
+            [item setEnabled:!isDisabled];
             int key   = items[i].key;
             int kmods = items[i].kmods;
             if (hasCommand) {
@@ -653,11 +659,22 @@ void showPopupMenu_MacOS(iWidget *source, iInt2 windowCoord, const iMenuItem *it
     iWindow *     window       = as_Window(mainWindow_App());
     NSWindow *    nsWindow     = nsWindow_(window->win);
     /* View coordinates are flipped. */
+    iBool isCentered = iFalse;
+    if (isEqual_I2(windowCoord, zero_I2())) {
+        windowCoord = divi_I2(window->size, 2);
+        isCentered = iTrue;
+    }
     windowCoord.y = window->size.y - windowCoord.y;
     windowCoord = divf_I2(windowCoord, window->pixelRatio);
     NSPoint screenPoint = [nsWindow convertPointToScreen:(CGPoint){ windowCoord.x, windowCoord.y }];
     makeMenuItems_(menu, menuCommands, items, n);
     [menuCommands setSource:source];
+    if (isCentered) {
+        NSSize menuSize = [menu size];
+        screenPoint.x -= menuSize.width / 2;
+        screenPoint.y += menuSize.height / 2;
+    }
+    [menu setAutoenablesItems:NO];
     [menu popUpMenuPositioningItem:nil atLocation:screenPoint inView:nil];
     [menu release];
     [menuCommands release];
diff --git a/src/ui/root.c b/src/ui/root.c
index 595184cc..6a98b261 100644
--- a/src/ui/root.c
+++ b/src/ui/root.c
@@ -430,20 +430,18 @@ static void updateNavBarIdentity_(iWidget *navBar) {
     const iGmIdentity *ident =
         identityForUrl_GmCerts(certs_App(), url_DocumentWidget(document_App()));
     iWidget *button = findChild_Widget(navBar, "navbar.ident");
-    iLabelWidget *toolButton = findWidget_App("toolbar.ident");
+    iWidget *menu   = findChild_Widget(button, "menu");
     setFlags_Widget(button, selected_WidgetFlag, ident != NULL);
-    setOutline_LabelWidget(toolButton, ident == NULL);
     /* Update menu. */
-    iLabelWidget *idItem = child_Widget(findChild_Widget(button, "menu"), 0);
-    if (!idItem) return;
     const iString *subjectName = ident ? name_GmIdentity(ident) : NULL;
-    setTextCStr_LabelWidget(
-        idItem,
-        subjectName ? format_CStr(uiTextAction_ColorEscape "%s", cstr_String(subjectName))
-                    : "${menu.identity.notactive}");
-    setFlags_Widget(as_Widget(idItem), disabled_WidgetFlag, !ident);
+    const char *   idLabel     = subjectName
+                                     ? format_CStr(uiTextAction_ColorEscape "%s", cstr_String(subjectName))
+                                     : "///${menu.identity.notactive}";
+    setMenuItemLabelByIndex_Widget(menu, 0, idLabel);
+    iLabelWidget *toolButton = findWidget_App("toolbar.ident");
     iLabelWidget *toolName = findWidget_App("toolbar.name");
     if (toolName) {
+        setOutline_LabelWidget(toolButton, ident == NULL);
         updateTextCStr_LabelWidget(toolName, subjectName ? cstr_String(subjectName) : "");
         setFont_LabelWidget(toolButton, subjectName ? defaultMedium_FontId : uiLabelLarge_FontId);
         arrange_Widget(parent_Widget(toolButton));
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index fdfb5300..ffedfeeb 100644
--- a/src/ui/sidebarwidget.c
+++ b/src/ui/sidebarwidget.c
@@ -1457,25 +1457,29 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
                 if (d->mode == bookmarks_SidebarMode && d->contextItem) {
                     const iBookmark *bm = get_Bookmarks(bookmarks_App(), d->contextItem->id);
                     if (bm) {
-                        updateMenuItemLabel_Widget(d->menu, "bookmark.tag tag:homepage",
-                                                   hasTag_Bookmark(bm, homepage_BookmarkTag)
-                                                       ? home_Icon " ${bookmark.untag.home}"
-                                                       : home_Icon " ${bookmark.tag.home}");
-                        updateMenuItemLabel_Widget(d->menu, "bookmark.tag tag:subscribed",
-                                                   hasTag_Bookmark(bm, subscribed_BookmarkTag)
-                                                        ? star_Icon " ${bookmark.untag.sub}"
-                                                        : star_Icon " ${bookmark.tag.sub}");
-                        updateMenuItemLabel_Widget(d->menu, "bookmark.tag tag:remotesource",
-                                                   hasTag_Bookmark(bm, remoteSource_BookmarkTag)
-                                                        ? downArrowBar_Icon " ${bookmark.untag.remote}"
-                                                        : downArrowBar_Icon " ${bookmark.tag.remote}");
+                        setMenuItemLabel_Widget(d->menu,
+                                                "bookmark.tag tag:homepage",
+                                                hasTag_Bookmark(bm, homepage_BookmarkTag)
+                                                    ? home_Icon " ${bookmark.untag.home}"
+                                                    : home_Icon " ${bookmark.tag.home}");
+                        setMenuItemLabel_Widget(d->menu,
+                                                "bookmark.tag tag:subscribed",
+                                                hasTag_Bookmark(bm, subscribed_BookmarkTag)
+                                                    ? star_Icon " ${bookmark.untag.sub}"
+                                                    : star_Icon " ${bookmark.tag.sub}");
+                        setMenuItemLabel_Widget(d->menu,
+                                                "bookmark.tag tag:remotesource",
+                                                hasTag_Bookmark(bm, remoteSource_BookmarkTag)
+                                                    ? downArrowBar_Icon " ${bookmark.untag.remote}"
+                                                    : downArrowBar_Icon " ${bookmark.tag.remote}");
                     }
                 }
                 else if (d->mode == feeds_SidebarMode && d->contextItem) {
                     const iBool   isRead   = d->contextItem->indent == 0;
-                    updateMenuItemLabel_Widget(d->menu, "feed.entry.toggleread",
-                                               isRead ? circle_Icon " ${feeds.entry.markunread}"
-                                                      : circleWhite_Icon " ${feeds.entry.markread}");
+                    setMenuItemLabel_Widget(d->menu,
+                                            "feed.entry.toggleread",
+                                            isRead ? circle_Icon " ${feeds.entry.markunread}"
+                                                   : circleWhite_Icon " ${feeds.entry.markread}");
                 }
                 else if (d->mode == identities_SidebarMode) {
                     const iGmIdentity *ident  = constHoverIdentity_SidebarWidget_(d);
diff --git a/src/ui/util.c b/src/ui/util.c
index a5b1cfb3..6d518282 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -709,6 +709,7 @@ void makeMenuItems_Widget(iWidget *menu, const iMenuItem *items, size_t n) {
         }
         else {
             iBool isInfo = iFalse;
+            iBool isDisabled = iFalse;
             if (startsWith_CStr(labelText, ">>>")) {
                 labelText += 3;
                 if (!horizGroup) {
@@ -722,6 +723,10 @@ void makeMenuItems_Widget(iWidget *menu, const iMenuItem *items, size_t n) {
                 labelText += 3;
                 isInfo = iTrue;
             }
+            if (startsWith_CStr(labelText, "///")) {
+                labelText += 3;
+                isDisabled = iTrue;
+            }
             iLabelWidget *label = addChildFlags_Widget(
                 horizGroup ? horizGroup : menu,
                 iClob(newKeyMods_LabelWidget(labelText, item->key, item->kmods, item->command)),
@@ -730,6 +735,7 @@ void makeMenuItems_Widget(iWidget *menu, const iMenuItem *items, size_t n) {
             setWrap_LabelWidget(label, isInfo);
             haveIcons |= checkIcon_LabelWidget(label);
             updateSize_LabelWidget(label); /* drawKey was set */
+            setFlags_Widget(as_Widget(label), disabled_WidgetFlag, isDisabled);
             if (isInfo) {
                 setFlags_Widget(as_Widget(label), fixedHeight_WidgetFlag, iTrue); /* wrap changes height */
                 setTextColor_LabelWidget(label, uiTextAction_ColorId);
@@ -784,10 +790,10 @@ static iArray *deepCopyMenuItems_(iWidget *menu, const iMenuItem *items, size_t
         }
 #endif
         pushBack_Array(array, &(iMenuItem){
-            item->label ? strdup(item->label) : NULL,
+            item->label ? iDupStr(item->label) : NULL,
             item->key,
             item->kmods,
-            itemCommand ? strdup(itemCommand) : NULL /* NOTE: Only works with string commands. */
+            itemCommand ? iDupStr(itemCommand) : NULL /* NOTE: Only works with string commands. */
         });
     }
     deinit_String(&cmd);
@@ -883,45 +889,78 @@ iMenuItem *findNativeMenuItem_Widget(iWidget *menu, const char *commandSuffix) {
     return NULL;
 }
 
-void setSelected_NativeMenuItem(iMenuItem *item, iBool isSelected) {
+void setPrefix_NativeMenuItem(iMenuItem *item, const char *prefix, iBool set) {
     if (!item->label) {
         return;
     }
-    const iBool hasPrefix = startsWith_CStr(item->label, "###");
-    if (hasPrefix && !isSelected) {
-        char *label = strdup(item->label + 3);
+    const iBool hasPrefix = startsWith_CStr(item->label, prefix);
+    if (hasPrefix && !set) {
+        char *label = iDupStr(item->label + 3);
         free((char *) item->label);
         item->label = label;
     }
-    else if (!hasPrefix && isSelected) {
+    else if (!hasPrefix && set) {
         char *label = malloc(strlen(item->label) + 4);
-        memcpy(label, "###", 3);
+        memcpy(label, prefix, 3);
         strcpy(label + 3, item->label);
         free((char *) item->label);
         item->label = label;
     }
 }
 
-void updateMenuItemLabel_Widget(iWidget *menu, const char *command, const char *newLabel) {
-    if (~flags_Widget(menu) & nativeMenu_WidgetFlag) {
-        iLabelWidget *menuItem = findMenuItem_Widget(menu, command);
-        if (menuItem) {
-            setTextCStr_LabelWidget(menuItem, newLabel);
-            checkIcon_LabelWidget(menuItem);
-        }
+void setSelected_NativeMenuItem(iMenuItem *item, iBool isSelected) {
+    if (item) {
+        setPrefix_NativeMenuItem(item, "///", iFalse);
+        setPrefix_NativeMenuItem(item, "###", isSelected);
     }
-    else {
+}
+
+void setDisabled_NativeMenuItem(iMenuItem *item, iBool isDisabled) {
+    if (item) {
+        setPrefix_NativeMenuItem(item, "###", iFalse);
+        setPrefix_NativeMenuItem(item, "///", isDisabled);
+    }
+}
+
+void setLabel_NativeMenuItem(iMenuItem *item, const char *label) {
+    free((char *) item->label);
+    item->label = iDupStr(label);
+}
+
+void setMenuItemLabel_Widget(iWidget *menu, const char *command, const char *newLabel) {
+    if (flags_Widget(menu) & nativeMenu_WidgetFlag) {
         iArray *items = userData_Object(menu);
         iAssert(items);
         iForEach(Array, i, items) {
             iMenuItem *item = i.value;
             if (item->command && !iCmpStr(item->command, command)) {
-                free((void *) item->label);
-                item->label = strdup(newLabel);
+                setLabel_NativeMenuItem(item, newLabel);
                 break;
             }
         }
     }
+    else {
+        iLabelWidget *menuItem = findMenuItem_Widget(menu, command);
+        if (menuItem) {
+            setTextCStr_LabelWidget(menuItem, newLabel);
+            checkIcon_LabelWidget(menuItem);
+        }
+    }
+}
+
+void setMenuItemLabelByIndex_Widget(iWidget *menu, size_t index, const char *newLabel) {
+    if (flags_Widget(menu) & nativeMenu_WidgetFlag) {
+        iArray *items = userData_Object(menu);
+        iAssert(items);
+        iAssert(index < size_Array(items));
+        setLabel_NativeMenuItem(at_Array(items, index), newLabel);
+    }
+    else {
+        iLabelWidget *menuItem = child_Widget(menu, index);
+        iAssert(isInstance_Object(menuItem, &Class_LabelWidget));
+        setTextCStr_LabelWidget(menuItem, newLabel);
+        checkIcon_LabelWidget(menuItem);
+    }
 }
 
 void unselectAllNativeMenuItems_Widget(iWidget *menu) {
@@ -953,8 +992,7 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, iBool postCommands) {
     const iArray *items = userData_Object(d);
     iAssert(flags_Widget(d) & nativeMenu_WidgetFlag);
     iAssert(items);
-    showPopupMenu_MacOS(d, windowCoord, //mouseCoord_Window(get_Window(), 0),
-                        constData_Array(items), size_Array(items));
+    showPopupMenu_MacOS(d, windowCoord, constData_Array(items), size_Array(items));
 #else
     const iRect rootRect        = rect_Root(d->root);
     const iInt2 rootSize        = rootRect.size;
@@ -1085,9 +1123,14 @@ iLabelWidget *findMenuItem_Widget(iWidget *menu, const char *command) {
 }
 
 void setMenuItemDisabled_Widget(iWidget *menu, const char *command, iBool disable) {
-    iLabelWidget *item = findMenuItem_Widget(menu, command);
-    if (item) {
-        setFlags_Widget(as_Widget(item), disabled_WidgetFlag, disable);
+    if (flags_Widget(menu) & nativeMenu_WidgetFlag) {
+        setDisabled_NativeMenuItem(findNativeMenuItem_Widget(menu, command), disable);
+    }
+    else {
+        iLabelWidget *item = findMenuItem_Widget(menu, command);
+        if (item) {
+            setFlags_Widget(as_Widget(item), disabled_WidgetFlag, disable);
+        }
     }
 }
 
@@ -1120,6 +1163,10 @@ const iString *removeMenuItemLabelPrefixes_String(const iString *d) {
             remove_Block(&str->chars, 0, 3);
             continue;
         }
+        if (startsWith_String(str, "///")) {
+            remove_Block(&str->chars, 0, 3);
+            continue;
+        }
         if (startsWith_String(str, "```")) {
             remove_Block(&str->chars, 0, 3);
             continue;
@@ -2823,10 +2870,17 @@ static const iMenuItem languages[] = {
 static iBool translationHandler_(iWidget *dlg, const char *cmd) {
     iUnused(dlg);
     if (equal_Command(cmd, "xlt.lang")) {
-        iLabelWidget *menuItem = pointer_Command(cmd);
-        iWidget *button = parent_Widget(parent_Widget(menuItem));
-        iAssert(isInstance_Object(button, &Class_LabelWidget));
-        updateText_LabelWidget((iLabelWidget *) button, text_LabelWidget(menuItem));
+        const iMenuItem *langItem = &languages[languageIndex_CStr(cstr_Rangecc(range_Command(cmd, "id")))];
+        iWidget *widget = pointer_Command(cmd);
+        iLabelWidget *drop;
+        if (flags_Widget(widget) & nativeMenu_WidgetFlag) {
+            drop = (iLabelWidget *) parent_Widget(widget);
+        }
+        else {
+            drop = (iLabelWidget *) parent_Widget(parent_Widget(widget));
+        }
+        iAssert(isInstance_Object(drop, &Class_LabelWidget));
+        updateDropdownSelection_LabelWidget(drop, langItem->command);
         return iTrue;
     }
     return iFalse;
@@ -2880,25 +2934,25 @@ iWidget *makeTranslation_Widget(iWidget *parent) {
         addChild_Widget(dlg, iClob(page = makeTwoColumns_Widget(&headings, &values)));
         setId_Widget(page, "xlt.langs");
         iLabelWidget *fromLang, *toLang;
+        const size_t numLangs = iElemCount(languages) - 1;
+        const char *widestLabel = languages[findWidestLabel_MenuItem(languages, numLangs)].label;
         /* Source language. */ {
             addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.translate.from}")));
-            setId_Widget(
-                addChildFlags_Widget(values,
-                                     iClob(fromLang = makeMenuButton_LabelWidget(
-                                               "${lang.pt}", languages, iElemCount(languages) - 1)),
-                                     alignLeft_WidgetFlag),
-                "xlt.from");
+            setId_Widget(addChildFlags_Widget(values,
+                                              iClob(fromLang = makeMenuButton_LabelWidget(
+                                                        widestLabel, languages, numLangs)),
+                                              alignLeft_WidgetFlag),
+                         "xlt.from");
             setBackgroundColor_Widget(findChild_Widget(as_Widget(fromLang), "menu"),
                                       uiBackgroundMenu_ColorId);
         }
         /* Target language. */ {
             addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.translate.to}")));
-            setId_Widget(
-                addChildFlags_Widget(values,
-                                     iClob(toLang = makeMenuButton_LabelWidget(
-                                               "${lang.pt}", languages, iElemCount(languages) - 1)),
-                                     alignLeft_WidgetFlag),
-                "xlt.to");
+            setId_Widget(addChildFlags_Widget(values,
+                                              iClob(toLang = makeMenuButton_LabelWidget(
+                                                        widestLabel, languages, numLangs)),
+                                              alignLeft_WidgetFlag),
+                         "xlt.to");
             setBackgroundColor_Widget(findChild_Widget(as_Widget(toLang), "menu"),
                                       uiBackgroundMenu_ColorId);
         }
@@ -2908,14 +2962,18 @@ iWidget *makeTranslation_Widget(iWidget *parent) {
         arrange_Widget(dlg);
     }
     /* Update choices. */
-    updateText_LabelWidget(
-        findChild_Widget(dlg, "xlt.from"),
-        text_LabelWidget(child_Widget(findChild_Widget(findChild_Widget(dlg, "xlt.from"), "menu"),
-                                      prefs_App()->langFrom)));
-    updateText_LabelWidget(
-        findChild_Widget(dlg, "xlt.to"),
-        text_LabelWidget(child_Widget(findChild_Widget(findChild_Widget(dlg, "xlt.to"), "menu"),
-                                      prefs_App()->langTo)));
+    updateDropdownSelection_LabelWidget(findChild_Widget(dlg, "xlt.from"),
+                                        languages[prefs_App()->langFrom].command);
+    updateDropdownSelection_LabelWidget(findChild_Widget(dlg, "xlt.to"),
+                                        languages[prefs_App()->langTo].command);
+//    updateText_LabelWidget(
+//        findChild_Widget(dlg, "xlt.from"),
+//        text_LabelWidget(child_Widget(findChild_Widget(findChild_Widget(dlg, "xlt.from"), "menu"),
+//                                      prefs_App()->langFrom)));
+//    updateText_LabelWidget(
+//        findChild_Widget(dlg, "xlt.to"),
+//        text_LabelWidget(child_Widget(findChild_Widget(findChild_Widget(dlg, "xlt.to"), "menu"),
+//                                      prefs_App()->langTo)));
     setCommandHandler_Widget(dlg, translationHandler_);
     setupSheetTransition_Mobile(dlg, iTrue);
     return dlg;
diff --git a/src/ui/util.h b/src/ui/util.h
index a1914e2a..574a255f 100644
--- a/src/ui/util.h
+++ b/src/ui/util.h
@@ -226,24 +226,25 @@ struct Impl_MenuItem {
     };
 };
 
-iWidget *   makeMenu_Widget         (iWidget *parent, const iMenuItem *items, size_t n); /* returns no ref */
-void        makeMenuItems_Widget    (iWidget *menu, const iMenuItem *items, size_t n);
-void        openMenu_Widget         (iWidget *, iInt2 windowCoord);
-void        openMenuFlags_Widget    (iWidget *, iInt2 windowCoord, iBool postCommands);
-void        closeMenu_Widget        (iWidget *);
-void        releaseNativeMenu_Widget(iWidget *);
+iWidget *       makeMenu_Widget                 (iWidget *parent, const iMenuItem *items, size_t n); /* returns no ref */
+void            makeMenuItems_Widget            (iWidget *menu, const iMenuItem *items, size_t n);
+void            openMenu_Widget                 (iWidget *, iInt2 windowCoord);
+void            openMenuFlags_Widget            (iWidget *, iInt2 windowCoord, iBool postCommands);
+void            closeMenu_Widget                (iWidget *);
+void            releaseNativeMenu_Widget        (iWidget *);
 
-size_t      findWidestLabel_MenuItem        (const iMenuItem *items, size_t num);
-void        setSelected_NativeMenuItem      (iMenuItem *item, iBool isSelected);
+size_t          findWidestLabel_MenuItem        (const iMenuItem *items, size_t num);
+void            setSelected_NativeMenuItem      (iMenuItem *item, iBool isSelected);
 
-iChar       removeIconPrefix_String (iString *);
+iChar           removeIconPrefix_String         (iString *);
 
-iLabelWidget *  findMenuItem_Widget         (iWidget *menu, const char *command);
-iMenuItem *     findNativeMenuItem_Widget   (iWidget *menu, const char *commandSuffix);
-void            setMenuItemDisabled_Widget  (iWidget *menu, const char *command, iBool disable);
-void            updateMenuItemLabel_Widget  (iWidget *menu, const char *command, const char *newLabel);
+iLabelWidget *  findMenuItem_Widget             (iWidget *menu, const char *command);
+iMenuItem *     findNativeMenuItem_Widget       (iWidget *menu, const char *commandSuffix);
+void            setMenuItemDisabled_Widget      (iWidget *menu, const char *command, iBool disable);
+void            setMenuItemLabel_Widget         (iWidget *menu, const char *command, const char *newLabel);
+void            setMenuItemLabelByIndex_Widget  (iWidget *menu, size_t index, const char *newLabel);
 
-int         checkContextMenu_Widget (iWidget *, const SDL_Event *ev); /* see macro below */
+int             checkContextMenu_Widget         (iWidget *, const SDL_Event *ev); /* see macro below */
 
 #define processContextMenuEvent_Widget(menu, sdlEvent, stmtEaten) \
     for (const int result = checkContextMenu_Widget((menu), (sdlEvent));;) { \
Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.7/cdiff/2ed9d1bbd3b92b8d39a368963c3fd5d0fbcdc974
Status Code
Success (20)
Meta
text/gemini; charset=utf-8
Capsule Response Time
77.421187 milliseconds
Gemini-to-HTML Time
1.16755 milliseconds

This content has been proxied by September (3851b).