=> b85471a5b84f0837611fb47be35ee713139f702f
[1mdiff --git a/src/app.c b/src/app.c[m [1mindex fa8cc105..0d0f2ffd 100644[m [1m--- a/src/app.c[m [1m+++ b/src/app.c[m [36m@@ -1653,34 +1653,20 @@[m [mstatic void updateScrollSpeedButtons_(iWidget *d, enum iScrollType type, const i[m }[m }[m [m [31m-static void updateDropdownSelection_(iLabelWidget *dropButton, const char *selectedCommand) {[m [31m- iWidget *menu = findChild_Widget(as_Widget(dropButton), "menu");[m [31m- iForEach(ObjectList, i, children_Widget(menu)) {[m [31m- if (isInstance_Object(i.object, &Class_LabelWidget)) {[m [31m- iLabelWidget *item = i.object;[m [31m- const iBool isSelected = endsWith_String(command_LabelWidget(item), selectedCommand);[m [31m- setFlags_Widget(as_Widget(item), selected_WidgetFlag, isSelected);[m [31m- if (isSelected) {[m [31m- updateText_LabelWidget(dropButton, sourceText_LabelWidget(item));[m [31m- }[m [31m- }[m [31m- }[m [31m-}[m [31m-[m static void updateColorThemeButton_(iLabelWidget *button, int theme) {[m /* TODO: These three functions are all the same? Cleanup? */[m if (!button) return;[m [31m- updateDropdownSelection_(button, format_CStr(".set arg:%d", theme));[m [32m+[m[32m updateDropdownSelection_LabelWidget(button, format_CStr(".set arg:%d", theme));[m }[m [m static void updateFontButton_(iLabelWidget *button, int font) {[m if (!button) return;[m [31m- updateDropdownSelection_(button, format_CStr(".set arg:%d", font));[m [32m+[m[32m updateDropdownSelection_LabelWidget(button, format_CStr(".set arg:%d", font));[m }[m [m static void updateImageStyleButton_(iLabelWidget *button, int style) {[m if (!button) return;[m [31m- updateDropdownSelection_(button, format_CStr(".set arg:%d", style));[m [32m+[m[32m updateDropdownSelection_LabelWidget(button, format_CStr(".set arg:%d", style));[m }[m [m static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {[m [36m@@ -1733,8 +1719,8 @@[m [mstatic iBool handlePrefsCommands_(iWidget *d, const char *cmd) {[m return iTrue;[m }[m else if (equal_Command(cmd, "uilang")) {[m [31m- updateDropdownSelection_(findChild_Widget(d, "prefs.uilang"),[m [31m- cstr_String(string_Command(cmd, "id")));[m [32m+[m[32m updateDropdownSelection_LabelWidget(findChild_Widget(d, "prefs.uilang"),[m [32m+[m[32m cstr_String(string_Command(cmd, "id")));[m return iFalse;[m }[m else if (equal_Command(cmd, "quoteicon.set")) {[m [36m@@ -1744,8 +1730,8 @@[m [mstatic iBool handlePrefsCommands_(iWidget *d, const char *cmd) {[m return iFalse;[m }[m else if (equal_Command(cmd, "returnkey.set")) {[m [31m- updateDropdownSelection_(findChild_Widget(d, "prefs.returnkey"),[m [31m- format_CStr("returnkey.set arg:%d", arg_Command(cmd)));[m [32m+[m[32m updateDropdownSelection_LabelWidget(findChild_Widget(d, "prefs.returnkey"),[m [32m+[m[32m format_CStr("returnkey.set arg:%d", arg_Command(cmd)));[m return iFalse;[m }[m else if (equal_Command(cmd, "pinsplit.set")) {[m [36m@@ -1849,7 +1835,8 @@[m [miDocumentWidget *newTab_App(const iDocumentWidget *duplicateOf, iBool switchToNe[m static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) {[m iApp *d = &app_;[m if (equal_Command(cmd, "ident.showmore")) {[m [31m- iForEach(ObjectList, i, children_Widget(findChild_Widget(dlg, "headings"))) {[m [32m+[m[32m iForEach(ObjectList, i,[m [32m+[m[32m children_Widget(findChild_Widget(dlg, isUsingPanelLayout_Mobile() ? "panel.top" : "headings"))) {[m if (flags_Widget(i.object) & collapse_WidgetFlag) {[m setFlags_Widget(i.object, hidden_WidgetFlag, iFalse);[m }[m [36m@@ -1859,8 +1846,7 @@[m [mstatic iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) {[m setFlags_Widget(j.object, hidden_WidgetFlag, iFalse);[m }[m }[m [31m- setFlags_Widget(child_Widget(findChild_Widget(dlg, "dialogbuttons"), 0), disabled_WidgetFlag,[m [31m- iTrue);[m [32m+[m[32m setFlags_Widget(pointer_Command(cmd), disabled_WidgetFlag, iTrue);[m arrange_Widget(dlg);[m refresh_Widget(dlg); [m return iTrue;[m [36m@@ -1870,6 +1856,7 @@[m [mstatic iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) {[m setText_LabelWidget(scope,[m text_LabelWidget(child_Widget([m findChild_Widget(as_Widget(scope), "menu"), arg_Command(cmd))));[m [32m+[m[32m arrange_Widget(findWidget_App("ident"));[m return iTrue;[m }[m if (equal_Command(cmd, "ident.temp.changed")) {[m [36m@@ -2596,9 +2583,10 @@[m [miBool handleCommand_App(const char *cmd) {[m updatePrefsPinSplitButtons_(dlg, d->prefs.pinSplit);[m updateScrollSpeedButtons_(dlg, mouse_ScrollType, d->prefs.smoothScrollSpeed[mouse_ScrollType]);[m updateScrollSpeedButtons_(dlg, keyboard_ScrollType, d->prefs.smoothScrollSpeed[keyboard_ScrollType]);[m [31m- updateDropdownSelection_(findChild_Widget(dlg, "prefs.uilang"), cstr_String(&d->prefs.uiLanguage));[m [31m- updateDropdownSelection_(findChild_Widget(dlg, "prefs.returnkey"),[m [31m- format_CStr("returnkey.set arg:%d", d->prefs.returnKey));[m [32m+[m[32m updateDropdownSelection_LabelWidget(findChild_Widget(dlg, "prefs.uilang"), cstr_String(&d->prefs.uiLanguage));[m [32m+[m[32m updateDropdownSelection_LabelWidget([m [32m+[m[32m findChild_Widget(dlg, "prefs.returnkey"),[m [32m+[m[32m format_CStr("returnkey.set arg:%d", d->prefs.returnKey));[m setToggle_Widget(findChild_Widget(dlg, "prefs.retainwindow"), d->prefs.retainWindowSize);[m setText_InputWidget(findChild_Widget(dlg, "prefs.uiscale"),[m collectNewFormat_String("%g", uiScale_Window(d->window)));[m [1mdiff --git a/src/ui/certimportwidget.c b/src/ui/certimportwidget.c[m [1mindex a8346e19..2e60c71f 100644[m [1m--- a/src/ui/certimportwidget.c[m [1m+++ b/src/ui/certimportwidget.c[m [36m@@ -152,7 +152,7 @@[m [mvoid init_CertImportWidget(iCertImportWidget *d) {[m /* Buttons. */[m addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));[m iWidget *buttons = makeDialogButtons_Widget([m [31m- (iMenuItem[]){ { "${cancel}", 0, 0, NULL },[m [32m+[m[32m (iMenuItem[]){ { "${cancel}" },[m { uiTextAction_ColorEscape "${dlg.certimport.import}",[m SDLK_RETURN,[m KMOD_PRIMARY,[m [1mdiff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c[m [1mindex 6ca4fd8d..83f2ea6a 100644[m [1m--- a/src/ui/documentwidget.c[m [1m+++ b/src/ui/documentwidget.c[m [36m@@ -3127,7 +3127,7 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m makeQuestion_Widget([m uiHeading_ColorEscape "${heading.import.bookmarks}",[m formatCStrs_Lang("dlg.import.found.n", count),[m [31m- (iMenuItem[]){ { "${cancel}", 0, 0, NULL },[m [32m+[m[32m (iMenuItem[]){ { "${cancel}" },[m { format_CStr(cstrCount_Lang("dlg.import.add.n", (int) count),[m uiTextAction_ColorEscape,[m count),[m [36m@@ -3299,7 +3299,7 @@[m [mstatic iBool processMediaEvents_DocumentWidget_(iDocumentWidget *d, const SDL_Ev[m d->playerMenu = makeMenu_Widget([m as_Widget(d),[m (iMenuItem[]){[m [31m- { cstrCollect_String(metadataLabel_Player(plr)), 0, 0, NULL },[m [32m+[m[32m { cstrCollect_String(metadataLabel_Player(plr)) },[m },[m 1);[m openMenu_Widget(d->playerMenu, bottomLeft_Rect(ui.menuRect));[m [36m@@ -3604,7 +3604,7 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m pushBackN_Array([m &items,[m (iMenuItem[]){[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { isGemini ? "${link.noproxy}" : openExt_Icon " ${link.browser}",[m 0,[m 0,[m [36m@@ -3615,7 +3615,7 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m linkLabel_GmDocument(d->doc, d->contextLink->linkId));[m urlEncodeSpaces_String(linkLabel);[m pushBackN_Array(&items,[m [31m- (iMenuItem[]){ { "---", 0, 0, NULL },[m [32m+[m[32m (iMenuItem[]){ { "---" },[m { "${link.copy}", 0, 0, "document.copylink" },[m { bookmark_Icon " ${link.bookmark}",[m 0,[m [36m@@ -3627,7 +3627,7 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m 3);[m if (isNative && d->contextLink->mediaType != download_GmRunMediaType) {[m pushBackN_Array(&items, (iMenuItem[]){[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { download_Icon " ${link.download}", 0, 0, "document.downloadlink" },[m }, 2);[m }[m [36m@@ -3670,22 +3670,22 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m { "${menu.forward}", navigateForward_KeyShortcut, "navigate.forward" },[m { upArrow_Icon " ${menu.parent}", navigateParent_KeyShortcut, "navigate.parent" },[m { upArrowBar_Icon " ${menu.root}", navigateRoot_KeyShortcut, "navigate.root" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { reload_Icon " ${menu.reload}", reload_KeyShortcut, "navigate.reload" },[m { timer_Icon " ${menu.autoreload}", 0, 0, "document.autoreload.menu" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { bookmark_Icon " ${menu.page.bookmark}", SDLK_d, KMOD_PRIMARY, "bookmark.add" },[m { star_Icon " ${menu.page.subscribe}", subscribeToPage_KeyModifier, "feeds.subscribe" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { book_Icon " ${menu.page.import}", 0, 0, "bookmark.links confirm:1" },[m { globe_Icon " ${menu.page.translate}", 0, 0, "document.translate" },[m #if defined (iPlatformMobile)[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { "${menu.page.copyurl}", 0, 0, "document.copylink" } },[m 14);[m #else[m { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { "${menu.page.copyurl}", 0, 0, "document.copylink" } },[m 15);[m #endif[m [36m@@ -3862,7 +3862,7 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m }[m d->copyMenu = makeMenu_Widget(w, (iMenuItem[]){[m { clipCopy_Icon " ${menu.copy}", 0, 0, "copy" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { close_Icon " ${menu.select.clear}", 0, 0, "document.select arg:0" },[m }, 3);[m setFlags_Widget(d->copyMenu, noFadeBackground_WidgetFlag, iTrue);[m [36m@@ -3955,7 +3955,7 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m uiTextAction_ColorEscape,[m cstr_String(url)),[m (iMenuItem[]){[m [31m- { "${cancel}", 0, 0, NULL },[m [32m+[m[32m { "${cancel}" },[m { uiTextCaution_ColorEscape "${dlg.openlink}",[m 0, 0, format_CStr("!open default:1 url:%s", cstr_String(url)) } },[m 2);[m [1mdiff --git a/src/ui/mobile.c b/src/ui/mobile.c[m [1mindex 7e359a84..f3e23e06 100644[m [1m--- a/src/ui/mobile.c[m [1m+++ b/src/ui/mobile.c[m [36m@@ -36,7 +36,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m # include "ios.h"[m #endif[m [m [31m-static iBool useMobileSheetLayout_(void) {[m [32m+[m[32miBool isUsingPanelLayout_Mobile(void) {[m return deviceType_App() != desktop_AppDeviceType;[m }[m [m [36m@@ -381,6 +381,7 @@[m [mstatic size_t countItems_(const iMenuItem *itemsNullTerminated) {[m void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {[m iWidget * widget = NULL;[m iLabelWidget *heading = NULL;[m [32m+[m[32m iWidget * value = NULL;[m const char * spec = item->label;[m const char * id = cstr_Rangecc(range_Command(spec, "id"));[m const char * label = hasLabel_Command(spec, "text")[m [36m@@ -396,6 +397,7 @@[m [mvoid makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {[m setFont_LabelWidget(title, uiLabelLargeBold_FontId);[m setTextColor_LabelWidget(title, uiHeading_ColorId);[m setAllCaps_LabelWidget(title, iTrue);[m [32m+[m[32m setId_Widget(as_Widget(title), id);[m }[m else if (equal_Command(spec, "heading")) {[m addChild_Widget(panel, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));[m [36m@@ -403,6 +405,7 @@[m [mvoid makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {[m setAllCaps_LabelWidget(heading, iTrue);[m setRemoveTrailingColon_LabelWidget(heading, iTrue);[m addChild_Widget(panel, iClob(heading));[m [32m+[m[32m setId_Widget(as_Widget(heading), id);[m } [m else if (equal_Command(spec, "toggle")) {[m iLabelWidget *toggle = (iLabelWidget *) makeToggle_Widget(id);[m [36m@@ -412,7 +415,9 @@[m [mvoid makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {[m }[m else if (equal_Command(spec, "dropdown")) {[m const iMenuItem *dropItems = item->data;[m [31m- iLabelWidget *drop = makeMenuButton_LabelWidget("", dropItems, countItems_(dropItems));[m [32m+[m[32m iLabelWidget *drop = makeMenuButton_LabelWidget(dropItems[0].label,[m [32m+[m[32m dropItems, countItems_(dropItems));[m [32m+[m[32m value = as_Widget(drop);[m setFont_LabelWidget(drop, labelFont_());[m setFlags_Widget(as_Widget(drop),[m alignRight_WidgetFlag | noBackground_WidgetFlag |[m [36m@@ -465,6 +470,9 @@[m [mvoid makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {[m }[m else if (equal_Command(spec, "input")) {[m iInputWidget *input = new_InputWidget(argU32Label_Command(spec, "maxlen"));[m [32m+[m[32m if (hasLabel_Command(spec, "hint")) {[m [32m+[m[32m setHint_InputWidget(input, cstr_Lang(cstr_Rangecc(range_Command(spec, "hint"))));[m [32m+[m[32m }[m setId_Widget(as_Widget(input), id);[m setUrlContent_InputWidget(input, argLabel_Command(spec, "url"));[m setSelectAllOnFocus_InputWidget(input, argLabel_Command(spec, "selectall")); [m [36m@@ -491,6 +499,12 @@[m [mvoid makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {[m else if (equal_Command(spec, "button")) {[m widget = as_Widget(heading = makePanelButton_(label, item->command));[m }[m [32m+[m[32m else if (equal_Command(spec, "label")) {[m [32m+[m[32m iLabelWidget *lab = new_LabelWidget(label, NULL);[m [32m+[m[32m widget = as_Widget(lab);[m [32m+[m[32m setWrap_LabelWidget(lab, iTrue);[m [32m+[m[32m setFlags_Widget(widget, frameless_WidgetFlag, iTrue);[m [32m+[m[32m }[m else if (equal_Command(spec, "padding")) {[m widget = makePadding_Widget(lineHeight_Text(labelFont_()) * 1.5f);[m }[m [36m@@ -500,8 +514,14 @@[m [mvoid makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {[m if (icon) {[m setIcon_LabelWidget(heading, icon);[m }[m [32m+[m[32m if (value && as_Widget(heading) != value) {[m [32m+[m[32m as_Widget(heading)->sizeRef = value; /* heading height matches value widget */[m [32m+[m[32m }[m }[m if (widget) {[m [32m+[m[32m setFlags_Widget(widget,[m [32m+[m[32m collapse_WidgetFlag | hidden_WidgetFlag,[m [32m+[m[32m argLabel_Command(spec, "collapse") != 0);[m addChild_Widget(panel, iClob(widget));[m }[m }[m [36m@@ -512,11 +532,26 @@[m [mvoid makePanelItems_Mobile(iWidget *panel, const iMenuItem *itemsNullTerminated)[m }[m }[m [m [31m-iWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) {[m [32m+[m[32mstatic const iMenuItem *findDialogCancelAction_(const iMenuItem *items, size_t n) {[m [32m+[m[32m if (n <= 1) {[m [32m+[m[32m return NULL;[m [32m+[m[32m }[m [32m+[m[32m for (size_t i = 0; i < n - 1; i++) {[m [32m+[m[32m if (!iCmpStr(items[i].label, "${cancel}")) {[m [32m+[m[32m return &items[i];[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m return NULL;[m [32m+[m[32m}[m [32m+[m [32m+[m[32miWidget *makePanels_Mobile(const char *id,[m [32m+[m[32m const iMenuItem *itemsNullTerminated,[m [32m+[m[32m const iMenuItem *actions, size_t numActions) {[m /* A multipanel widget has a top panel and one or more detail panels. In a horizontal layout,[m the detail panels slide in from the right and cover the top panel. In a landscape layout,[m the detail panels are always visible on the side. */[m iWidget *sheet = new_Widget();[m [32m+[m[32m setId_Widget(sheet, id);[m setBackgroundColor_Widget(sheet, uiBackground_ColorId);[m setFlags_Widget(sheet,[m resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag |[m [36m@@ -553,18 +588,21 @@[m [miWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) {[m topPanel->offsetRef = detailStack;[m }[m /* Navigation bar at the top. */[m [32m+[m[32m iLabelWidget *naviBack;[m iWidget *navi = new_Widget(); {[m setId_Widget(navi, "panel.navi");[m setBackgroundColor_Widget(navi, uiBackground_ColorId);[m addChild_Widget(navi, iClob(makePadding_Widget(0)));[m [31m- iLabelWidget *back = addChildFlags_Widget([m [32m+[m[32m naviBack = addChildFlags_Widget([m navi,[m [31m- iClob(new_LabelWidget(leftAngle_Icon " ${panel.back}", "panel.close")),[m [32m+[m[32m iClob(newKeyMods_LabelWidget(leftAngle_Icon " ${panel.back}",[m [32m+[m[32m SDLK_ESCAPE, 0,[m [32m+[m[32m "panel.close")),[m noBackground_WidgetFlag | frameless_WidgetFlag | alignLeft_WidgetFlag |[m extraPadding_WidgetFlag);[m [31m- checkIcon_LabelWidget(back);[m [31m- setId_Widget(as_Widget(back), "panel.back");[m [31m- setFont_LabelWidget(back, labelFont_());[m [32m+[m[32m checkIcon_LabelWidget(naviBack);[m [32m+[m[32m setId_Widget(as_Widget(naviBack), "panel.back");[m [32m+[m[32m setFont_LabelWidget(naviBack, labelFont_());[m addChildFlags_Widget(sheet, iClob(navi),[m drawBackgroundToVerticalSafeArea_WidgetFlag |[m arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag |[m [36m@@ -593,6 +631,54 @@[m [miWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) {[m makePanelItem_Mobile(topPanel, item);[m }[m }[m [32m+[m[32m /* Actions. */[m [32m+[m[32m if (numActions) {[m [32m+[m[32m /* Some actions go in the navigation bar and some go on the top panel. */[m [32m+[m[32m const iMenuItem *cancelItem = findDialogCancelAction_(actions, numActions);[m [32m+[m[32m const iMenuItem *defaultItem = &actions[numActions - 1];[m [32m+[m[32m iAssert(defaultItem);[m [32m+[m[32m if (!cancelItem) {[m [32m+[m[32m updateTextCStr_LabelWidget(naviBack, defaultItem->label);[m [32m+[m[32m setCommand_LabelWidget(naviBack, collectNewCStr_String(defaultItem->command));[m [32m+[m[32m setFlags_Widget(as_Widget(naviBack), alignLeft_WidgetFlag, iFalse);[m [32m+[m[32m setFlags_Widget(as_Widget(naviBack), alignRight_WidgetFlag, iTrue);[m [32m+[m[32m setIcon_LabelWidget(naviBack, 0);[m [32m+[m[32m setFont_LabelWidget(naviBack, labelBoldFont_());[m[41m [m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m updateTextCStr_LabelWidget(naviBack, cancelItem->label);[m [32m+[m[32m setCommand_LabelWidget(naviBack, collectNewCStr_String(cancelItem->command[m [32m+[m[32m ? cancelItem->command[m [32m+[m[32m : "cancel"));[m [32m+[m[32m iLabelWidget *defaultButton = new_LabelWidget(defaultItem->label, defaultItem->command);[m [32m+[m[32m setFont_LabelWidget(defaultButton, labelBoldFont_());[m [32m+[m[32m setFlags_Widget(as_Widget(defaultButton),[m [32m+[m[32m frameless_WidgetFlag | extraPadding_WidgetFlag |[m [32m+[m[32m noBackground_WidgetFlag,[m [32m+[m[32m iTrue);[m [32m+[m[32m addChildFlags_Widget(as_Widget(naviBack), iClob(defaultButton),[m [32m+[m[32m moveToParentRightEdge_WidgetFlag);[m [32m+[m[32m updateSize_LabelWidget(defaultButton);[m [32m+[m[32m }[m [32m+[m[32m /* All other actions are added as buttons. */[m [32m+[m[32m iBool needPadding = iTrue;[m [32m+[m[32m for (size_t i = 0; i < numActions; i++) {[m [32m+[m[32m const iMenuItem *act = &actions[i];[m [32m+[m[32m if (act == cancelItem || act == defaultItem) {[m [32m+[m[32m continue;[m [32m+[m[32m }[m [32m+[m[32m if (!iCmpStr(act->label, "---")) {[m [32m+[m[32m continue;[m [32m+[m[32m }[m [32m+[m[32m if (needPadding) {[m [32m+[m[32m makePanelItem_Mobile(topPanel, &(iMenuItem){ "padding" });[m [32m+[m[32m needPadding = iFalse;[m [32m+[m[32m }[m [32m+[m[32m makePanelItem_Mobile([m [32m+[m[32m topPanel,[m [32m+[m[32m &(iMenuItem){ format_CStr("button text:%s", act->label), 0, 0, act->command });[m [32m+[m[32m }[m [32m+[m[32m }[m /* Finalize the layout. */[m addChild_Widget(sheet->root->widget, iClob(sheet));[m mainDetailSplitHandler_(mainDetailSplit, "window.resized"); /* make it resize the split */[m [36m@@ -1011,7 +1097,7 @@[m [miWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) {[m #endif[m [m void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) {[m [31m- if (!useMobileSheetLayout_()) {[m [32m+[m[32m if (!isUsingPanelLayout_Mobile()) {[m return; [m }[m const iBool isSlidePanel = (flags_Widget(sheet) & horizontalOffset_WidgetFlag) != 0;[m [36m@@ -1032,7 +1118,7 @@[m [mvoid setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) {[m }[m [m void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) {[m [31m- if (!useMobileSheetLayout_()) {[m [32m+[m[32m if (!isUsingPanelLayout_Mobile()) {[m if (prefs_App()->uiAnimations) {[m setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iFalse);[m if (isIncoming) {[m [1mdiff --git a/src/ui/mobile.h b/src/ui/mobile.h[m [1mindex 5e2d8957..4d742a0a 100644[m [1m--- a/src/ui/mobile.h[m [1m+++ b/src/ui/mobile.h[m [36m@@ -27,7 +27,10 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m iDeclareType(Widget)[m iDeclareType(MenuItem)[m [m [31m-iWidget * makePanels_Mobile (const iMenuItem *itemsNullTerminated);[m [32m+[m[32miBool isUsingPanelLayout_Mobile (void);[m [32m+[m[32miWidget * makePanels_Mobile (const char *id,[m [32m+[m[32m const iMenuItem *itemsNullTerminated,[m [32m+[m[32m const iMenuItem *actions, size_t numActions);[m [m void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming);[m void setupSheetTransition_Mobile (iWidget *sheet, iBool isIncoming);[m [1mdiff --git a/src/ui/root.c b/src/ui/root.c[m [1mindex 0b55d250..eae8e4bb 100644[m [1m--- a/src/ui/root.c[m [1m+++ b/src/ui/root.c[m [36m@@ -57,28 +57,28 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m static const iMenuItem navMenuItems_[] = {[m { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" },[m { "${menu.openlocation}", SDLK_l, KMOD_PRIMARY, "navigate.focus" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" },[m { "${menu.page.copysource}", SDLK_c, KMOD_PRIMARY, "copy" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { leftHalf_Icon " ${menu.sidebar.left}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },[m { rightHalf_Icon " ${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },[m { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" },[m { "${menu.zoom.in}", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" },[m { "${menu.zoom.out}", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" },[m { "${menu.zoom.reset}", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" },[m { "${menu.bookmarks.bytag}", 0, 0, "!open url:about:bookmarks?tags" },[m { "${menu.bookmarks.bytime}", 0, 0, "!open url:about:bookmarks?created" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { "${menu.downloads}", 0, 0, "downloads.open" },[m { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { gear_Icon " ${menu.preferences}", SDLK_COMMA, KMOD_PRIMARY, "preferences" },[m { "${menu.help}", SDLK_F1, 0, "!open url:about:help" },[m { "${menu.releasenotes}", 0, 0, "!open url:about:version" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { "${menu.quit}", 'q', KMOD_PRIMARY, "quit" }[m };[m #endif[m [36m@@ -89,17 +89,17 @@[m [mstatic const iMenuItem tabletNavMenuItems_[] = {[m { folder_Icon " ${menu.openfile}", SDLK_o, KMOD_PRIMARY, "file.open" },[m { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" },[m { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { magnifyingGlass_Icon " ${menu.find}", 0, 0, "focus.set id:find.input" },[m { leftHalf_Icon " ${menu.sidebar.left}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },[m { rightHalf_Icon " ${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },[m { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" },[m { "${menu.bookmarks.bytag}", 0, 0, "!open url:about:bookmarks?tags" },[m { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" },[m { "${menu.downloads}", 0, 0, "downloads.open" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { gear_Icon " ${menu.preferences}", SDLK_COMMA, KMOD_PRIMARY, "preferences" },[m { "${menu.help}", SDLK_F1, 0, "!open url:about:help" },[m { "${menu.releasenotes}", 0, 0, "!open url:about:version" },[m [36m@@ -110,14 +110,14 @@[m [mstatic const iMenuItem phoneNavMenuItems_[] = {[m { folder_Icon " ${menu.openfile}", SDLK_o, KMOD_PRIMARY, "file.open" },[m { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" },[m { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { magnifyingGlass_Icon " ${menu.find}", 0, 0, "focus.set id:find.input" },[m { leftHalf_Icon " ${menu.sidebar}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" },[m { "${menu.downloads}", 0, 0, "downloads.open" },[m { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { gear_Icon " Settings...", SDLK_COMMA, KMOD_PRIMARY, "preferences" },[m };[m #endif /* Mobile */[m [36m@@ -125,24 +125,24 @@[m [mstatic const iMenuItem phoneNavMenuItems_[] = {[m #if defined (iPlatformMobile)[m static const iMenuItem identityButtonMenuItems_[] = {[m { "${menu.identity.notactive}", 0, 0, "ident.showactive" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { add_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" },[m { "${menu.identity.import}", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { person_Icon " ${menu.show.identities}", 0, 0, "toolbar.showident" },[m };[m #else /* desktop */[m static const iMenuItem identityButtonMenuItems_[] = {[m { "${menu.identity.notactive}", 0, 0, "ident.showactive" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m # if !defined (iPlatformAppleDesktop)[m { add_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" },[m { "${menu.identity.import}", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { person_Icon " ${menu.show.identities}", '4', KMOD_PRIMARY, "sidebar.mode arg:3 show:1" },[m # else[m { add_Icon " ${menu.identity.new}", 0, 0, "ident.new" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { person_Icon " ${menu.show.identities}", 0, 0, "sidebar.mode arg:3 show:1" },[m # endif[m };[m [36m@@ -1158,20 +1158,20 @@[m [mvoid createUserInterface_Root(iRoot *d) {[m { upArrow_Icon " ${menu.parent}", navigateParent_KeyShortcut, "navigate.parent" },[m { upArrowBar_Icon " ${menu.root}", navigateRoot_KeyShortcut, "navigate.root" },[m { timer_Icon " ${menu.autoreload}", 0, 0, "document.autoreload.menu" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { bookmark_Icon " ${menu.page.bookmark}", SDLK_d, KMOD_PRIMARY, "bookmark.add" },[m { star_Icon " ${menu.page.subscribe}", subscribeToPage_KeyModifier, "feeds.subscribe" },[m { book_Icon " ${menu.page.import}", 0, 0, "bookmark.links confirm:1" },[m { globe_Icon " ${menu.page.translate}", 0, 0, "document.translate" },[m #if defined (iPlatformMobile)[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { "${menu.page.copyurl}", 0, 0, "document.copylink" },[m { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" },[m { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } },[m 11);[m #else[m { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { "${menu.page.copyurl}", 0, 0, "document.copylink" },[m { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" },[m { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } },[m [36m@@ -1355,7 +1355,7 @@[m [mvoid createUserInterface_Root(iRoot *d) {[m (iMenuItem[]){[m { close_Icon " ${menu.closetab}", 0, 0, "tabs.close" },[m { copy_Icon " ${menu.duptab}", 0, 0, "tabs.new duplicate:1" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { "${menu.closetab.other}", 0, 0, "tabs.close toleft:1 toright:1" },[m { barLeftArrow_Icon " ${menu.closetab.left}", 0, 0, "tabs.close toleft:1" },[m { barRightArrow_Icon " ${menu.closetab.right}", 0, 0, "tabs.close toright:1" },[m [36m@@ -1372,18 +1372,18 @@[m [mvoid createUserInterface_Root(iRoot *d) {[m (iMenuItem[]){[m { scissor_Icon " ${menu.cut}", 0, 0, "input.copy cut:1" },[m { clipCopy_Icon " ${menu.copy}", 0, 0, "input.copy" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { clipboard_Icon " ${menu.paste}", 0, 0, "input.paste" },[m },[m 4);[m iWidget *splitMenu = makeMenu_Widget(root, (iMenuItem[]){[m { "${menu.split.merge}", '1', 0, "ui.split arg:0" },[m { "${menu.split.swap}", SDLK_x, 0, "ui.split swap:1" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { "${menu.split.horizontal}", '3', 0, "ui.split arg:3 axis:0" },[m { "${menu.split.horizontal} 1:2", SDLK_d, 0, "ui.split arg:1 axis:0" },[m { "${menu.split.horizontal} 2:1", SDLK_e, 0, "ui.split arg:2 axis:0" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { "${menu.split.vertical}", '2', 0, "ui.split arg:3 axis:1" },[m { "${menu.split.vertical} 1:2", SDLK_f, 0, "ui.split arg:1 axis:1" },[m { "${menu.split.vertical} 2:1", SDLK_r, 0, "ui.split arg:2 axis:1" },[m [1mdiff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c[m [1mindex 5e1ee493..4c72c60a 100644[m [1m--- a/src/ui/uploadwidget.c[m [1m+++ b/src/ui/uploadwidget.c[m [36m@@ -148,7 +148,7 @@[m [mvoid init_UploadWidget(iUploadWidget *d) {[m addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));[m iWidget *buttons =[m makeDialogButtons_Widget((iMenuItem[]){ { "${upload.port}", 0, 0, "upload.setport" },[m [31m- { "---", 0, 0, NULL },[m [32m+[m[32m { "---" },[m { "${close}", SDLK_ESCAPE, 0, "upload.cancel" },[m { uiTextAction_ColorEscape "${dlg.upload.send}",[m SDLK_RETURN,[m [1mdiff --git a/src/ui/util.c b/src/ui/util.c[m [1mindex 22d8bce4..abe6f22e 100644[m [1m--- a/src/ui/util.c[m [1m+++ b/src/ui/util.c[m [36m@@ -907,6 +907,20 @@[m [miLabelWidget *makeMenuButton_LabelWidget(const char *label, const iMenuItem *ite[m return button;[m }[m [m [32m+[m[32mvoid updateDropdownSelection_LabelWidget(iLabelWidget *dropButton, const char *selectedCommand) {[m [32m+[m[32m iWidget *menu = findChild_Widget(as_Widget(dropButton), "menu");[m [32m+[m[32m iForEach(ObjectList, i, children_Widget(menu)) {[m [32m+[m[32m if (isInstance_Object(i.object, &Class_LabelWidget)) {[m [32m+[m[32m iLabelWidget *item = i.object;[m [32m+[m[32m const iBool isSelected = endsWith_String(command_LabelWidget(item), selectedCommand);[m [32m+[m[32m setFlags_Widget(as_Widget(item), selected_WidgetFlag, isSelected);[m [32m+[m[32m if (isSelected) {[m [32m+[m[32m updateText_LabelWidget(dropButton, sourceText_LabelWidget(item));[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m /*-----------------------------------------------------------------------------------------------*/[m [m static iBool isTabPage_Widget_(const iWidget *tabs, const iWidget *page) {[m [36m@@ -1650,6 +1664,19 @@[m [mstatic size_t findWidestItemLabel_(const iMenuItem *items, size_t num) {[m return widestPos;[m }[m [m [32m+[m[32miWidget *makeDialog_Widget(const char *id,[m [32m+[m[32m const iMenuItem *itemsNullTerminated,[m [32m+[m[32m const iMenuItem *actions, size_t numActions) {[m [32m+[m[32m iWidget *dlg = makeSheet_Widget(id);[m [32m+[m[32m /* TODO: Construct desktop dialogs using NULL-terminated item arrays, like mobile panels. */[m [32m+[m[32m addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI)));[m [32m+[m[32m addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, numActions)));[m [32m+[m[32m addChild_Widget(dlg->root->widget, iClob(dlg));[m [32m+[m[32m arrange_Widget(dlg);[m [32m+[m[32m setupSheetTransition_Mobile(dlg, iTrue);[m [32m+[m[32m return dlg;[m [32m+[m[32m}[m [32m+[m iWidget *makePreferences_Widget(void) {[m /* Common items. */[m const iMenuItem langItems[] = { { "${lang.de} - de", 0, 0, "uilang id:de" },[m [36m@@ -1715,7 +1742,7 @@[m [miWidget *makePreferences_Widget(void) {[m { NULL }[m };[m /* Create the Preferences UI. */[m [31m- if (deviceType_App() != desktop_AppDeviceType) {[m [32m+[m[32m if (isUsingPanelLayout_Mobile()) {[m const iMenuItem pinSplitItems[] = {[m { "button id:prefs.pinsplit.0 label:prefs.pinsplit.none", 0, 0, "pinsplit.set arg:0" },[m { "button id:prefs.pinsplit.1 label:prefs.pinsplit.left", 0, 0, "pinsplit.set arg:1" },[m [36m@@ -1767,7 +1794,7 @@[m [miWidget *makePreferences_Widget(void) {[m };[m const iMenuItem generalPanelItems[] = {[m { "title id:heading.prefs.general" },[m [31m- { "heading id:prefs.searchurl" },[m [32m+[m[32m { "heading text:${prefs.searchurl}" },[m { "input id:prefs.searchurl url:1 noheading:1" },[m { "padding" },[m { "toggle id:prefs.archive.openindex" },[m [36m@@ -1828,11 +1855,11 @@[m [miWidget *makePreferences_Widget(void) {[m { "padding" },[m { "input id:prefs.cachesize maxlen:4 selectall:1 unit:mb" },[m { "input id:prefs.memorysize maxlen:4 selectall:1 unit:mb" },[m [31m- { "heading id:prefs.proxy.gemini" },[m [32m+[m[32m { "heading text:${prefs.proxy.gemini}" },[m { "input id:prefs.proxy.gemini noheading:1" },[m [31m- { "heading id:prefs.proxy.gemini" },[m [32m+[m[32m { "heading text:${prefs.proxy.gopher}" },[m { "input id:prefs.proxy.gopher noheading:1" },[m [31m- { "heading id:prefs.proxy.gemini" },[m [32m+[m[32m { "heading text:${prefs.proxy.http}" },[m { "input id:prefs.proxy.http noheading:1" },[m { NULL }[m };[m [36m@@ -1855,8 +1882,8 @@[m [miWidget *makePreferences_Widget(void) {[m { "button text:" bug_Icon " ${menu.debug}", 0, 0, "!open url:about:debug" },[m { NULL }[m };[m [31m- iWidget *dlg = makePanels_Mobile((iMenuItem[]){[m [31m- { "panel icon:0x2699 id:heading.prefs.general", 0, 0, (const void *) generalPanelItems },[m [32m+[m[32m iWidget *dlg = makePanels_Mobile("prefs", (iMenuItem[]){[m [32m+[m[32m { "panel text:" gear_Icon " ${heading.prefs.general}", 0, 0, (const void *) generalPanelItems },[m { "panel icon:0x1f5a7 id:heading.prefs.network", 0, 0, (const void *) networkPanelItems },[m { "panel text:" person_Icon " ${sidebar.identities}", 0, 0, (const void *) identityPanelItems },[m { "padding" },[m [36m@@ -1869,7 +1896,7 @@[m [miWidget *makePreferences_Widget(void) {[m { "padding" },[m { "panel text:" planet_Icon " ${menu.about}", 0, 0, (const void *) aboutPanelItems },[m { NULL }[m [31m- });[m [32m+[m[32m }, NULL, 0);[m setupSheetTransition_Mobile(dlg, iTrue);[m return dlg;[m }[m [36m@@ -2153,6 +2180,29 @@[m [miWidget *makePreferences_Widget(void) {[m }[m [m iWidget *makeBookmarkEditor_Widget(void) {[m [32m+[m[32m const iMenuItem actions[] = {[m [32m+[m[32m { "${cancel}" },[m [32m+[m[32m { uiTextCaution_ColorEscape "${dlg.bookmark.save}", SDLK_RETURN, KMOD_PRIMARY, "bmed.accept" }[m [32m+[m[32m };[m [32m+[m[32m if (isUsingPanelLayout_Mobile()) {[m [32m+[m[32m const iMenuItem items[] = {[m [32m+[m[32m { "title id:bmed.heading text:${heading.bookmark.edit}" },[m [32m+[m[32m { "heading id:dlg.bookmark.url" },[m [32m+[m[32m { "input id:bmed.url url:1 noheading:1" },[m [32m+[m[32m { "padding" },[m [32m+[m[32m { "input id:bmed.title text:${dlg.bookmark.title}" },[m [32m+[m[32m { "input id:bmed.tags text:${dlg.bookmark.tags}" },[m [32m+[m[32m { "input id:bmed.icon maxlen:1 text:${dlg.bookmark.icon}" },[m [32m+[m[32m { "heading text:${heading.bookmark.tags}" },[m [32m+[m[32m { "toggle id:bmed.tag.home text:${bookmark.tag.home}" },[m [32m+[m[32m { "toggle id:bmed.tag.remote text:${bookmark.tag.remote}" },[m [32m+[m[32m { "toggle id:bmed.tag.linksplit text:${bookmark.tag.linksplit}" },[m [32m+[m[32m { NULL }[m [32m+[m[32m };[m [32m+[m[32m iWidget *dlg = makePanels_Mobile("bmed", items, actions, iElemCount(actions));[m [32m+[m[32m setupSheetTransition_Mobile(dlg, iTrue);[m [32m+[m[32m return dlg;[m [32m+[m[32m }[m iWidget *dlg = makeSheet_Widget("bmed");[m setId_Widget(addChildFlags_Widget([m dlg,[m [36m@@ -2179,14 +2229,7 @@[m [miWidget *makeBookmarkEditor_Widget(void) {[m as_Widget(inputs[i])->rect.size.x = 100 * gap_UI - headings->rect.size.x;[m }[m addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI)));[m [31m- addChild_Widget([m [31m- dlg,[m [31m- iClob(makeDialogButtons_Widget((iMenuItem[]){ { "${cancel}" },[m [31m- { uiTextCaution_ColorEscape "${dlg.bookmark.save}",[m [31m- SDLK_RETURN,[m [31m- KMOD_PRIMARY,[m [31m- "bmed.accept" } },[m [31m- 2)));[m [32m+[m[32m addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, iElemCount(actions))));[m addChild_Widget(get_Root()->widget, iClob(dlg));[m finalizeSheet_Mobile(dlg);[m return dlg;[m [36m@@ -2242,7 +2285,6 @@[m [miWidget *makeBookmarkCreation_Widget(const iString *url, const iString *title, i[m return dlg;[m }[m [m [31m-[m static iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) {[m if (equal_Command(cmd, "cancel")) {[m setupSheetTransition_Mobile(dlg, iFalse);[m [36m@@ -2288,46 +2330,59 @@[m [mstatic iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) {[m }[m [m iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {[m [31m- iWidget *dlg = makeSheet_Widget("feedcfg");[m [31m- setId_Widget(addChildFlags_Widget([m [31m- dlg,[m [31m- iClob(new_LabelWidget(bookmarkId ? uiHeading_ColorEscape "${heading.feedcfg}"[m [31m- : uiHeading_ColorEscape "${heading.subscribe}",[m [31m- NULL)),[m [31m- frameless_WidgetFlag),[m [31m- "feedcfg.heading");[m [31m- iWidget *headings, *values;[m [31m- addChild_Widget(dlg, iClob(makeTwoColumns_Widget(&headings, &values)));[m [31m- iInputWidget *input = new_InputWidget(0);[m [31m- addDialogInputWithHeading_(headings, values, "${dlg.feed.title}", "feedcfg.title", iClob(input));[m [31m- addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.feed.entrytype}")));[m [31m- iWidget *types = new_Widget(); {[m [31m- addRadioButton_(types, "feedcfg.type.gemini", "${dlg.feed.type.gemini}", "feedcfg.type arg:0");[m [31m- addRadioButton_(types, "feedcfg.type.headings", "${dlg.feed.type.headings}", "feedcfg.type arg:1");[m [31m- }[m [31m- addChildFlags_Widget(values, iClob(types), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);[m [31m- iWidget *buttons =[m [31m- addChild_Widget(dlg,[m [31m- iClob(makeDialogButtons_Widget([m [31m- (iMenuItem[]){ { "${cancel}" },[m [31m- { bookmarkId ? uiTextCaution_ColorEscape "${dlg.feed.save}"[m [31m- : uiTextCaution_ColorEscape "${dlg.feed.sub}",[m [31m- SDLK_RETURN,[m [31m- KMOD_PRIMARY,[m [31m- format_CStr("feedcfg.accept bmid:%d", bookmarkId) } },[m [31m- 2)));[m [31m- setId_Widget(child_Widget(buttons, childCount_Widget(buttons) - 1), "feedcfg.save");[m [31m- arrange_Widget(dlg);[m [31m- as_Widget(input)->rect.size.x = 100 * gap_UI - headings->rect.size.x;[m [31m- addChild_Widget(get_Root()->widget, iClob(dlg));[m [31m- finalizeSheet_Mobile(dlg);[m [32m+[m[32m const char *headingText = bookmarkId ? uiHeading_ColorEscape "${heading.feedcfg}"[m [32m+[m[32m : uiHeading_ColorEscape "${heading.subscribe}";[m [32m+[m[32m const iMenuItem actions[] = { { "${cancel}" },[m [32m+[m[32m { bookmarkId ? uiTextCaution_ColorEscape "${dlg.feed.save}"[m [32m+[m[32m : uiTextCaution_ColorEscape "${dlg.feed.sub}",[m [32m+[m[32m SDLK_RETURN,[m [32m+[m[32m KMOD_PRIMARY,[m [32m+[m[32m format_CStr("feedcfg.accept bmid:%d", bookmarkId) } };[m [32m+[m[32m iWidget *dlg;[m [32m+[m[32m if (isUsingPanelLayout_Mobile()) {[m [32m+[m[32m const iMenuItem typeItems[] = {[m [32m+[m[32m { "button id:feedcfg.type.gemini label:dlg.feed.type.gemini", 0, 0, "feedcfg.type arg:0" },[m [32m+[m[32m { "button id:feedcfg.type.headings label:dlg.feed.type.headings", 0, 0, "feedcfg.type arg:1" },[m [32m+[m[32m { NULL }[m [32m+[m[32m };[m [32m+[m[32m dlg = makePanels_Mobile("feedcfg", (iMenuItem[]){[m [32m+[m[32m { format_CStr("title id:feedcfg.heading text:%s", headingText) },[m [32m+[m[32m { "input id:feedcfg.title text:${dlg.feed.title}" },[m [32m+[m[32m { "radio id:dlg.feed.entrytype", 0, 0, (const void *) typeItems },[m [32m+[m[32m { NULL }[m [32m+[m[32m }, actions, iElemCount(actions));[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m dlg = makeSheet_Widget("feedcfg");[m [32m+[m[32m setId_Widget([m [32m+[m[32m addChildFlags_Widget(dlg, iClob(new_LabelWidget(headingText, NULL)), frameless_WidgetFlag),[m [32m+[m[32m "feedcfg.heading");[m [32m+[m[32m iWidget *headings, *values;[m [32m+[m[32m addChild_Widget(dlg, iClob(makeTwoColumns_Widget(&headings, &values)));[m [32m+[m[32m iInputWidget *input = new_InputWidget(0);[m [32m+[m[32m addDialogInputWithHeading_(headings, values, "${dlg.feed.title}", "feedcfg.title", iClob(input));[m [32m+[m[32m addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.feed.entrytype}")));[m [32m+[m[32m iWidget *types = new_Widget(); {[m [32m+[m[32m addRadioButton_(types, "feedcfg.type.gemini", "${dlg.feed.type.gemini}", "feedcfg.type arg:0");[m [32m+[m[32m addRadioButton_(types, "feedcfg.type.headings", "${dlg.feed.type.headings}", "feedcfg.type arg:1");[m [32m+[m[32m }[m [32m+[m[32m addChildFlags_Widget(values, iClob(types), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);[m [32m+[m[32m iWidget *buttons =[m [32m+[m[32m addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, iElemCount(actions))));[m [32m+[m[32m setId_Widget(child_Widget(buttons, childCount_Widget(buttons) - 1), "feedcfg.save");[m [32m+[m[32m arrange_Widget(dlg);[m [32m+[m[32m as_Widget(input)->rect.size.x = 100 * gap_UI - headings->rect.size.x;[m [32m+[m[32m addChild_Widget(get_Root()->widget, iClob(dlg));[m [32m+[m[32m finalizeSheet_Mobile(dlg);[m [32m+[m[32m }[m /* Initialize. */ {[m const iBookmark *bm = bookmarkId ? get_Bookmarks(bookmarks_App(), bookmarkId) : NULL;[m setText_InputWidget(findChild_Widget(dlg, "feedcfg.title"),[m bm ? &bm->title : feedTitle_DocumentWidget(document_App()));[m setFlags_Widget(findChild_Widget(dlg,[m [31m- hasTag_Bookmark(bm, headings_BookmarkTag) ? "feedcfg.type.headings"[m [31m- : "feedcfg.type.gemini"),[m [32m+[m[32m hasTag_Bookmark(bm, headings_BookmarkTag)[m [32m+[m[32m ? "feedcfg.type.headings"[m [32m+[m[32m : "feedcfg.type.gemini"),[m selected_WidgetFlag,[m iTrue);[m setCommandHandler_Widget(dlg, handleFeedSettingCommands_);[m [36m@@ -2336,84 +2391,113 @@[m [miWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {[m }[m [m iWidget *makeIdentityCreation_Widget(void) {[m [31m- iWidget *dlg = makeSheet_Widget("ident");[m [31m- setId_Widget(addChildFlags_Widget([m [31m- dlg,[m [31m- iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.newident}", NULL)),[m [31m- frameless_WidgetFlag),[m [31m- "ident.heading");[m [31m- iWidget *page = new_Widget();[m [31m- addChildFlags_Widget([m [31m- dlg, iClob(new_LabelWidget("${dlg.newident.rsa.selfsign}", NULL)), frameless_WidgetFlag);[m [31m- /* TODO: Use makeTwoColumnWidget_? */[m [31m- addChild_Widget(dlg, iClob(page));[m [31m- setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue);[m [31m- iWidget *headings = addChildFlags_Widget([m [31m- page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);[m [31m- iWidget *values = addChildFlags_Widget([m [31m- page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);[m [31m- setId_Widget(headings, "headings");[m [31m- setId_Widget(values, "values");[m [31m- iInputWidget *inputs[6];[m [31m- /* Where will the new identity be active on? */ {[m [31m- addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.newident.scope}")));[m [31m- const iMenuItem items[] = {[m [31m- { "${dlg.newident.scope.domain}", 0, 0, "ident.scope arg:0" },[m [31m- { "${dlg.newident.scope.page}", 0, 0, "ident.scope arg:1" },[m [31m- { "${dlg.newident.scope.none}", 0, 0, "ident.scope arg:2" },[m [31m- };[m [31m- setId_Widget(addChild_Widget(values,[m [31m- iClob(makeMenuButton_LabelWidget([m [31m- items[0].label, items, iElemCount(items)))),[m [31m- "ident.scope");[m [31m- }[m [31m- addDialogInputWithHeading_(headings,[m [31m- values,[m [31m- "${dlg.newident.until}",[m [31m- "ident.until",[m [31m- iClob(newHint_InputWidget(19, "${hint.newident.date}")));[m [31m- addDialogInputWithHeading_(headings,[m [31m- values,[m [31m- "${dlg.newident.commonname}",[m [31m- "ident.common",[m [31m- iClob(inputs[0] = new_InputWidget(0)));[m [31m- /* Temporary? */ {[m [31m- addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.newident.temp}")));[m [31m- iWidget *tmpGroup = new_Widget();[m [31m- setFlags_Widget(tmpGroup, arrangeSize_WidgetFlag | arrangeHorizontal_WidgetFlag, iTrue);[m [31m- addChild_Widget(tmpGroup, iClob(makeToggle_Widget("ident.temp")));[m [31m- setId_Widget([m [31m- addChildFlags_Widget(tmpGroup,[m [31m- iClob(new_LabelWidget(uiTextCaution_ColorEscape warning_Icon[m [31m- " ${dlg.newident.notsaved}",[m [31m- NULL)),[m [31m- hidden_WidgetFlag | frameless_WidgetFlag),[m [31m- "ident.temp.note");[m [31m- addChild_Widget(values, iClob(tmpGroup));[m [31m- }[m [31m- addChildFlags_Widget(headings, iClob(makePadding_Widget(gap_UI)), collapse_WidgetFlag | hidden_WidgetFlag);[m [31m- addChildFlags_Widget(values, iClob(makePadding_Widget(gap_UI)), collapse_WidgetFlag | hidden_WidgetFlag);[m [31m- addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.email}", "ident.email", iClob(inputs[1] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);[m [31m- addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.userid}", "ident.userid", iClob(inputs[2] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);[m [31m- addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.domain}", "ident.domain", iClob(inputs[3] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);[m [31m- addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.org}", "ident.org", iClob(inputs[4] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);[m [31m- addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.country}", "ident.country", iClob(inputs[5] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);[m [31m- arrange_Widget(dlg);[m [31m- for (size_t i = 0; i < iElemCount(inputs); ++i) {[m [31m- as_Widget(inputs[i])->rect.size.x = 100 * gap_UI - headings->rect.size.x;[m [32m+[m[32m const iMenuItem actions[] = { { "${dlg.newident.more}", 0, 0, "ident.showmore" },[m [32m+[m[32m { "---" },[m [32m+[m[32m { "${cancel}", SDLK_ESCAPE, 0, "ident.cancel" },[m [32m+[m[32m { uiTextAction_ColorEscape "${dlg.newident.create}",[m [32m+[m[32m SDLK_RETURN,[m [32m+[m[32m KMOD_PRIMARY,[m [32m+[m[32m "ident.accept" } };[m [32m+[m[32m iUrl url;[m [32m+[m[32m init_Url(&url, url_DocumentWidget(document_App()));[m [32m+[m[32m const iMenuItem scopeItems[] = {[m [32m+[m[32m { format_CStr("${dlg.newident.scope.domain}:\n%s", cstr_Rangecc(url.host)), 0, 0, "ident.scope arg:0" },[m [32m+[m[32m { format_CStr("${dlg.newident.scope.page}:\n%s", cstr_Rangecc(url.path)), 0, 0, "ident.scope arg:1" },[m [32m+[m[32m { "${dlg.newident.scope.none}", 0, 0, "ident.scope arg:2" },[m [32m+[m[32m { NULL }[m [32m+[m[32m };[m [32m+[m[32m iWidget *dlg;[m [32m+[m[32m if (isUsingPanelLayout_Mobile()) {[m [32m+[m[32m dlg = makePanels_Mobile("ident",[m [32m+[m[32m (iMenuItem[]){ { "title id:ident.heading text:${heading.newident}" },[m [32m+[m[32m { "label text:${dlg.newident.rsa.selfsign}" },[m [32m+[m[32m { "dropdown id:ident.scope text:${dlg.newident.scope}", 0, 0,[m [32m+[m[32m (const void *) scopeItems },[m [32m+[m[32m { "input id:ident.until hint:hint.newident.date maxlen:19 text:${dlg.newident.until}" },[m [32m+[m[32m //{ "padding" },[m [32m+[m[32m //{ "toggle id:ident.temp text:${dlg.newident.temp}" },[m [32m+[m[32m //{ "label text:${help.ident.temp}" },[m [32m+[m[32m { "heading id:dlg.newident.commonname" },[m [32m+[m[32m { "input id:ident.common noheading:1" },[m [32m+[m[32m { "padding collapse:1" },[m [32m+[m[32m { "input collapse:1 id:ident.email hint:hint.newident.optional text:${dlg.newident.email}" },[m [32m+[m[32m { "input collapse:1 id:ident.userid hint:hint.newident.optional text:${dlg.newident.userid}" },[m [32m+[m[32m { "input collapse:1 id:ident.domain hint:hint.newident.optional text:${dlg.newident.domain}" },[m [32m+[m[32m { "input collapse:1 id:ident.org hint:hint.newident.optional text:${dlg.newident.org}" },[m [32m+[m[32m { "input collapse:1 id:ident.country hint:hint.newident.optional text:${dlg.newident.country}" },[m [32m+[m[32m { NULL }[m [32m+[m[32m }, actions, iElemCount(actions));[m [32m+[m[32m setupSheetTransition_Mobile(dlg, iTrue);[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m dlg = makeSheet_Widget("ident");[m [32m+[m[32m setId_Widget(addChildFlags_Widget([m [32m+[m[32m dlg,[m [32m+[m[32m iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.newident}", NULL)),[m [32m+[m[32m frameless_WidgetFlag),[m [32m+[m[32m "ident.heading");[m [32m+[m[32m iWidget *page = new_Widget();[m [32m+[m[32m addChildFlags_Widget([m [32m+[m[32m dlg, iClob(new_LabelWidget("${dlg.newident.rsa.selfsign}", NULL)), frameless_WidgetFlag);[m [32m+[m[32m /* TODO: Use makeTwoColumnWidget_? */[m [32m+[m[32m addChild_Widget(dlg, iClob(page));[m [32m+[m[32m setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue);[m [32m+[m[32m iWidget *headings = addChildFlags_Widget([m [32m+[m[32m page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);[m [32m+[m[32m iWidget *values = addChildFlags_Widget([m [32m+[m[32m page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);[m [32m+[m[32m setId_Widget(headings, "headings");[m [32m+[m[32m setId_Widget(values, "values");[m [32m+[m[32m iInputWidget *inputs[6];[m [32m+[m[32m /* Where will the new identity be active on? */ {[m [32m+[m[32m iWidget *head = addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.newident.scope}")));[m [32m+[m[32m iWidget *val;[m [32m+[m[32m setId_Widget([m [32m+[m[32m addChild_Widget(values,[m [32m+[m[32m val = iClob(makeMenuButton_LabelWidget([m [32m+[m[32m scopeItems[0].label, scopeItems, iElemCount(scopeItems)))),[m [32m+[m[32m "ident.scope");[m [32m+[m[32m head->sizeRef = val;[m [32m+[m[32m }[m [32m+[m[32m addDialogInputWithHeading_(headings,[m [32m+[m[32m values,[m [32m+[m[32m "${dlg.newident.until}",[m [32m+[m[32m "ident.until",[m [32m+[m[32m iClob(newHint_InputWidget(19, "${hint.newident.date}")));[m [32m+[m[32m addDialogInputWithHeading_(headings,[m [32m+[m[32m values,[m [32m+[m[32m "${dlg.newident.commonname}",[m [32m+[m[32m "ident.common",[m [32m+[m[32m iClob(inputs[0] = new_InputWidget(0)));[m [32m+[m[32m /* Temporary? */ {[m [32m+[m[32m addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.newident.temp}")));[m [32m+[m[32m iWidget *tmpGroup = new_Widget();[m [32m+[m[32m setFlags_Widget(tmpGroup, arrangeSize_WidgetFlag | arrangeHorizontal_WidgetFlag, iTrue);[m [32m+[m[32m addChild_Widget(tmpGroup, iClob(makeToggle_Widget("ident.temp")));[m [32m+[m[32m setId_Widget([m [32m+[m[32m addChildFlags_Widget(tmpGroup,[m [32m+[m[32m iClob(new_LabelWidget(uiTextCaution_ColorEscape warning_Icon[m [32m+[m[32m " ${dlg.newident.notsaved}",[m [32m+[m[32m NULL)),[m [32m+[m[32m hidden_WidgetFlag | frameless_WidgetFlag),[m [32m+[m[32m "ident.temp.note");[m [32m+[m[32m addChild_Widget(values, iClob(tmpGroup));[m [32m+[m[32m }[m [32m+[m[32m addChildFlags_Widget(headings, iClob(makePadding_Widget(gap_UI)), collapse_WidgetFlag | hidden_WidgetFlag);[m [32m+[m[32m addChildFlags_Widget(values, iClob(makePadding_Widget(gap_UI)), collapse_WidgetFlag | hidden_WidgetFlag);[m [32m+[m[32m addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.email}", "ident.email", iClob(inputs[1] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);[m [32m+[m[32m addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.userid}", "ident.userid", iClob(inputs[2] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);[m [32m+[m[32m addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.domain}", "ident.domain", iClob(inputs[3] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);[m [32m+[m[32m addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.org}", "ident.org", iClob(inputs[4] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);[m [32m+[m[32m addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.country}", "ident.country", iClob(inputs[5] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);[m [32m+[m[32m arrange_Widget(dlg);[m [32m+[m[32m for (size_t i = 0; i < iElemCount(inputs); ++i) {[m [32m+[m[32m as_Widget(inputs[i])->rect.size.x = 100 * gap_UI - headings->rect.size.x;[m [32m+[m[32m }[m [32m+[m[32m addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, iElemCount(actions))));[m [32m+[m[32m addChild_Widget(get_Root()->widget, iClob(dlg));[m [32m+[m[32m finalizeSheet_Mobile(dlg);[m }[m [31m- addChild_Widget(dlg,[m [31m- iClob(makeDialogButtons_Widget([m [31m- (iMenuItem[]){ { "${dlg.newident.more}", 0, 0, "ident.showmore" },[m [31m- { "---" },[m [31m- { "${cancel}", SDLK_ESCAPE, 0, "ident.cancel" },[m [31m- { uiTextAction_ColorEscape "${dlg.newident.create}",[m [31m- SDLK_RETURN,[m [31m- KMOD_PRIMARY,[m [31m- "ident.accept" } },[m [31m- 4)));[m [31m- addChild_Widget(get_Root()->widget, iClob(dlg));[m [31m- finalizeSheet_Mobile(dlg);[m return dlg;[m }[m [m [1mdiff --git a/src/ui/util.h b/src/ui/util.h[m [1mindex 87b72394..0dff8978 100644[m [1m--- a/src/ui/util.h[m [1m+++ b/src/ui/util.h[m [36m@@ -242,7 +242,8 @@[m [mint checkContextMenu_Widget (iWidget *, const SDL_Event *ev); /* see mac[m break; \[m }[m [m [31m-iLabelWidget * makeMenuButton_LabelWidget (const char *label, const iMenuItem *items, size_t n);[m [32m+[m[32miLabelWidget * makeMenuButton_LabelWidget (const char *label, const iMenuItem *items, size_t n);[m [32m+[m[32mvoid updateDropdownSelection_LabelWidget (iLabelWidget *dropButton, const char *selectedCommand);[m [m /*-----------------------------------------------------------------------------------------------*/[m [m
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).