summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-09-09 20:22:33 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-09-09 20:22:33 +0300
commitb85471a5b84f0837611fb47be35ee713139f702f (patch)
treee2d2ae695279f14c2e559595a3129151e574fbe2 /src
parent55cd303c52a8fe524e15bd618bfcb02b8ff7dcb7 (diff)
Mobile: Working on dialogs
The new panels maker offers a declarative solution for creating consistent UIs.
Diffstat (limited to 'src')
-rw-r--r--src/app.c42
-rw-r--r--src/ui/certimportwidget.c2
-rw-r--r--src/ui/documentwidget.c24
-rw-r--r--src/ui/mobile.c106
-rw-r--r--src/ui/mobile.h5
-rw-r--r--src/ui/root.c48
-rw-r--r--src/ui/uploadwidget.c2
-rw-r--r--src/ui/util.c342
-rw-r--r--src/ui/util.h3
9 files changed, 368 insertions, 206 deletions
diff --git a/src/app.c b/src/app.c
index fa8cc105..0d0f2ffd 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1653,34 +1653,20 @@ static void updateScrollSpeedButtons_(iWidget *d, enum iScrollType type, const i
1653 } 1653 }
1654} 1654}
1655 1655
1656static void updateDropdownSelection_(iLabelWidget *dropButton, const char *selectedCommand) {
1657 iWidget *menu = findChild_Widget(as_Widget(dropButton), "menu");
1658 iForEach(ObjectList, i, children_Widget(menu)) {
1659 if (isInstance_Object(i.object, &Class_LabelWidget)) {
1660 iLabelWidget *item = i.object;
1661 const iBool isSelected = endsWith_String(command_LabelWidget(item), selectedCommand);
1662 setFlags_Widget(as_Widget(item), selected_WidgetFlag, isSelected);
1663 if (isSelected) {
1664 updateText_LabelWidget(dropButton, sourceText_LabelWidget(item));
1665 }
1666 }
1667 }
1668}
1669
1670static void updateColorThemeButton_(iLabelWidget *button, int theme) { 1656static void updateColorThemeButton_(iLabelWidget *button, int theme) {
1671 /* TODO: These three functions are all the same? Cleanup? */ 1657 /* TODO: These three functions are all the same? Cleanup? */
1672 if (!button) return; 1658 if (!button) return;
1673 updateDropdownSelection_(button, format_CStr(".set arg:%d", theme)); 1659 updateDropdownSelection_LabelWidget(button, format_CStr(".set arg:%d", theme));
1674} 1660}
1675 1661
1676static void updateFontButton_(iLabelWidget *button, int font) { 1662static void updateFontButton_(iLabelWidget *button, int font) {
1677 if (!button) return; 1663 if (!button) return;
1678 updateDropdownSelection_(button, format_CStr(".set arg:%d", font)); 1664 updateDropdownSelection_LabelWidget(button, format_CStr(".set arg:%d", font));
1679} 1665}
1680 1666
1681static void updateImageStyleButton_(iLabelWidget *button, int style) { 1667static void updateImageStyleButton_(iLabelWidget *button, int style) {
1682 if (!button) return; 1668 if (!button) return;
1683 updateDropdownSelection_(button, format_CStr(".set arg:%d", style)); 1669 updateDropdownSelection_LabelWidget(button, format_CStr(".set arg:%d", style));
1684} 1670}
1685 1671
1686static iBool handlePrefsCommands_(iWidget *d, const char *cmd) { 1672static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
@@ -1733,8 +1719,8 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
1733 return iTrue; 1719 return iTrue;
1734 } 1720 }
1735 else if (equal_Command(cmd, "uilang")) { 1721 else if (equal_Command(cmd, "uilang")) {
1736 updateDropdownSelection_(findChild_Widget(d, "prefs.uilang"), 1722 updateDropdownSelection_LabelWidget(findChild_Widget(d, "prefs.uilang"),
1737 cstr_String(string_Command(cmd, "id"))); 1723 cstr_String(string_Command(cmd, "id")));
1738 return iFalse; 1724 return iFalse;
1739 } 1725 }
1740 else if (equal_Command(cmd, "quoteicon.set")) { 1726 else if (equal_Command(cmd, "quoteicon.set")) {
@@ -1744,8 +1730,8 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
1744 return iFalse; 1730 return iFalse;
1745 } 1731 }
1746 else if (equal_Command(cmd, "returnkey.set")) { 1732 else if (equal_Command(cmd, "returnkey.set")) {
1747 updateDropdownSelection_(findChild_Widget(d, "prefs.returnkey"), 1733 updateDropdownSelection_LabelWidget(findChild_Widget(d, "prefs.returnkey"),
1748 format_CStr("returnkey.set arg:%d", arg_Command(cmd))); 1734 format_CStr("returnkey.set arg:%d", arg_Command(cmd)));
1749 return iFalse; 1735 return iFalse;
1750 } 1736 }
1751 else if (equal_Command(cmd, "pinsplit.set")) { 1737 else if (equal_Command(cmd, "pinsplit.set")) {
@@ -1849,7 +1835,8 @@ iDocumentWidget *newTab_App(const iDocumentWidget *duplicateOf, iBool switchToNe
1849static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) { 1835static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) {
1850 iApp *d = &app_; 1836 iApp *d = &app_;
1851 if (equal_Command(cmd, "ident.showmore")) { 1837 if (equal_Command(cmd, "ident.showmore")) {
1852 iForEach(ObjectList, i, children_Widget(findChild_Widget(dlg, "headings"))) { 1838 iForEach(ObjectList, i,
1839 children_Widget(findChild_Widget(dlg, isUsingPanelLayout_Mobile() ? "panel.top" : "headings"))) {
1853 if (flags_Widget(i.object) & collapse_WidgetFlag) { 1840 if (flags_Widget(i.object) & collapse_WidgetFlag) {
1854 setFlags_Widget(i.object, hidden_WidgetFlag, iFalse); 1841 setFlags_Widget(i.object, hidden_WidgetFlag, iFalse);
1855 } 1842 }
@@ -1859,8 +1846,7 @@ static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) {
1859 setFlags_Widget(j.object, hidden_WidgetFlag, iFalse); 1846 setFlags_Widget(j.object, hidden_WidgetFlag, iFalse);
1860 } 1847 }
1861 } 1848 }
1862 setFlags_Widget(child_Widget(findChild_Widget(dlg, "dialogbuttons"), 0), disabled_WidgetFlag, 1849 setFlags_Widget(pointer_Command(cmd), disabled_WidgetFlag, iTrue);
1863 iTrue);
1864 arrange_Widget(dlg); 1850 arrange_Widget(dlg);
1865 refresh_Widget(dlg); 1851 refresh_Widget(dlg);
1866 return iTrue; 1852 return iTrue;
@@ -1870,6 +1856,7 @@ static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) {
1870 setText_LabelWidget(scope, 1856 setText_LabelWidget(scope,
1871 text_LabelWidget(child_Widget( 1857 text_LabelWidget(child_Widget(
1872 findChild_Widget(as_Widget(scope), "menu"), arg_Command(cmd)))); 1858 findChild_Widget(as_Widget(scope), "menu"), arg_Command(cmd))));
1859 arrange_Widget(findWidget_App("ident"));
1873 return iTrue; 1860 return iTrue;
1874 } 1861 }
1875 if (equal_Command(cmd, "ident.temp.changed")) { 1862 if (equal_Command(cmd, "ident.temp.changed")) {
@@ -2596,9 +2583,10 @@ iBool handleCommand_App(const char *cmd) {
2596 updatePrefsPinSplitButtons_(dlg, d->prefs.pinSplit); 2583 updatePrefsPinSplitButtons_(dlg, d->prefs.pinSplit);
2597 updateScrollSpeedButtons_(dlg, mouse_ScrollType, d->prefs.smoothScrollSpeed[mouse_ScrollType]); 2584 updateScrollSpeedButtons_(dlg, mouse_ScrollType, d->prefs.smoothScrollSpeed[mouse_ScrollType]);
2598 updateScrollSpeedButtons_(dlg, keyboard_ScrollType, d->prefs.smoothScrollSpeed[keyboard_ScrollType]); 2585 updateScrollSpeedButtons_(dlg, keyboard_ScrollType, d->prefs.smoothScrollSpeed[keyboard_ScrollType]);
2599 updateDropdownSelection_(findChild_Widget(dlg, "prefs.uilang"), cstr_String(&d->prefs.uiLanguage)); 2586 updateDropdownSelection_LabelWidget(findChild_Widget(dlg, "prefs.uilang"), cstr_String(&d->prefs.uiLanguage));
2600 updateDropdownSelection_(findChild_Widget(dlg, "prefs.returnkey"), 2587 updateDropdownSelection_LabelWidget(
2601 format_CStr("returnkey.set arg:%d", d->prefs.returnKey)); 2588 findChild_Widget(dlg, "prefs.returnkey"),
2589 format_CStr("returnkey.set arg:%d", d->prefs.returnKey));
2602 setToggle_Widget(findChild_Widget(dlg, "prefs.retainwindow"), d->prefs.retainWindowSize); 2590 setToggle_Widget(findChild_Widget(dlg, "prefs.retainwindow"), d->prefs.retainWindowSize);
2603 setText_InputWidget(findChild_Widget(dlg, "prefs.uiscale"), 2591 setText_InputWidget(findChild_Widget(dlg, "prefs.uiscale"),
2604 collectNewFormat_String("%g", uiScale_Window(d->window))); 2592 collectNewFormat_String("%g", uiScale_Window(d->window)));
diff --git a/src/ui/certimportwidget.c b/src/ui/certimportwidget.c
index a8346e19..2e60c71f 100644
--- a/src/ui/certimportwidget.c
+++ b/src/ui/certimportwidget.c
@@ -152,7 +152,7 @@ void init_CertImportWidget(iCertImportWidget *d) {
152 /* Buttons. */ 152 /* Buttons. */
153 addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); 153 addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));
154 iWidget *buttons = makeDialogButtons_Widget( 154 iWidget *buttons = makeDialogButtons_Widget(
155 (iMenuItem[]){ { "${cancel}", 0, 0, NULL }, 155 (iMenuItem[]){ { "${cancel}" },
156 { uiTextAction_ColorEscape "${dlg.certimport.import}", 156 { uiTextAction_ColorEscape "${dlg.certimport.import}",
157 SDLK_RETURN, 157 SDLK_RETURN,
158 KMOD_PRIMARY, 158 KMOD_PRIMARY,
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 6ca4fd8d..83f2ea6a 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -3127,7 +3127,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
3127 makeQuestion_Widget( 3127 makeQuestion_Widget(
3128 uiHeading_ColorEscape "${heading.import.bookmarks}", 3128 uiHeading_ColorEscape "${heading.import.bookmarks}",
3129 formatCStrs_Lang("dlg.import.found.n", count), 3129 formatCStrs_Lang("dlg.import.found.n", count),
3130 (iMenuItem[]){ { "${cancel}", 0, 0, NULL }, 3130 (iMenuItem[]){ { "${cancel}" },
3131 { format_CStr(cstrCount_Lang("dlg.import.add.n", (int) count), 3131 { format_CStr(cstrCount_Lang("dlg.import.add.n", (int) count),
3132 uiTextAction_ColorEscape, 3132 uiTextAction_ColorEscape,
3133 count), 3133 count),
@@ -3299,7 +3299,7 @@ static iBool processMediaEvents_DocumentWidget_(iDocumentWidget *d, const SDL_Ev
3299 d->playerMenu = makeMenu_Widget( 3299 d->playerMenu = makeMenu_Widget(
3300 as_Widget(d), 3300 as_Widget(d),
3301 (iMenuItem[]){ 3301 (iMenuItem[]){
3302 { cstrCollect_String(metadataLabel_Player(plr)), 0, 0, NULL }, 3302 { cstrCollect_String(metadataLabel_Player(plr)) },
3303 }, 3303 },
3304 1); 3304 1);
3305 openMenu_Widget(d->playerMenu, bottomLeft_Rect(ui.menuRect)); 3305 openMenu_Widget(d->playerMenu, bottomLeft_Rect(ui.menuRect));
@@ -3604,7 +3604,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
3604 pushBackN_Array( 3604 pushBackN_Array(
3605 &items, 3605 &items,
3606 (iMenuItem[]){ 3606 (iMenuItem[]){
3607 { "---", 0, 0, NULL }, 3607 { "---" },
3608 { isGemini ? "${link.noproxy}" : openExt_Icon " ${link.browser}", 3608 { isGemini ? "${link.noproxy}" : openExt_Icon " ${link.browser}",
3609 0, 3609 0,
3610 0, 3610 0,
@@ -3615,7 +3615,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
3615 linkLabel_GmDocument(d->doc, d->contextLink->linkId)); 3615 linkLabel_GmDocument(d->doc, d->contextLink->linkId));
3616 urlEncodeSpaces_String(linkLabel); 3616 urlEncodeSpaces_String(linkLabel);
3617 pushBackN_Array(&items, 3617 pushBackN_Array(&items,
3618 (iMenuItem[]){ { "---", 0, 0, NULL }, 3618 (iMenuItem[]){ { "---" },
3619 { "${link.copy}", 0, 0, "document.copylink" }, 3619 { "${link.copy}", 0, 0, "document.copylink" },
3620 { bookmark_Icon " ${link.bookmark}", 3620 { bookmark_Icon " ${link.bookmark}",
3621 0, 3621 0,
@@ -3627,7 +3627,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
3627 3); 3627 3);
3628 if (isNative && d->contextLink->mediaType != download_GmRunMediaType) { 3628 if (isNative && d->contextLink->mediaType != download_GmRunMediaType) {
3629 pushBackN_Array(&items, (iMenuItem[]){ 3629 pushBackN_Array(&items, (iMenuItem[]){
3630 { "---", 0, 0, NULL }, 3630 { "---" },
3631 { download_Icon " ${link.download}", 0, 0, "document.downloadlink" }, 3631 { download_Icon " ${link.download}", 0, 0, "document.downloadlink" },
3632 }, 2); 3632 }, 2);
3633 } 3633 }
@@ -3670,22 +3670,22 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
3670 { "${menu.forward}", navigateForward_KeyShortcut, "navigate.forward" }, 3670 { "${menu.forward}", navigateForward_KeyShortcut, "navigate.forward" },
3671 { upArrow_Icon " ${menu.parent}", navigateParent_KeyShortcut, "navigate.parent" }, 3671 { upArrow_Icon " ${menu.parent}", navigateParent_KeyShortcut, "navigate.parent" },
3672 { upArrowBar_Icon " ${menu.root}", navigateRoot_KeyShortcut, "navigate.root" }, 3672 { upArrowBar_Icon " ${menu.root}", navigateRoot_KeyShortcut, "navigate.root" },
3673 { "---", 0, 0, NULL }, 3673 { "---" },
3674 { reload_Icon " ${menu.reload}", reload_KeyShortcut, "navigate.reload" }, 3674 { reload_Icon " ${menu.reload}", reload_KeyShortcut, "navigate.reload" },
3675 { timer_Icon " ${menu.autoreload}", 0, 0, "document.autoreload.menu" }, 3675 { timer_Icon " ${menu.autoreload}", 0, 0, "document.autoreload.menu" },
3676 { "---", 0, 0, NULL }, 3676 { "---" },
3677 { bookmark_Icon " ${menu.page.bookmark}", SDLK_d, KMOD_PRIMARY, "bookmark.add" }, 3677 { bookmark_Icon " ${menu.page.bookmark}", SDLK_d, KMOD_PRIMARY, "bookmark.add" },
3678 { star_Icon " ${menu.page.subscribe}", subscribeToPage_KeyModifier, "feeds.subscribe" }, 3678 { star_Icon " ${menu.page.subscribe}", subscribeToPage_KeyModifier, "feeds.subscribe" },
3679 { "---", 0, 0, NULL }, 3679 { "---" },
3680 { book_Icon " ${menu.page.import}", 0, 0, "bookmark.links confirm:1" }, 3680 { book_Icon " ${menu.page.import}", 0, 0, "bookmark.links confirm:1" },
3681 { globe_Icon " ${menu.page.translate}", 0, 0, "document.translate" }, 3681 { globe_Icon " ${menu.page.translate}", 0, 0, "document.translate" },
3682#if defined (iPlatformMobile) 3682#if defined (iPlatformMobile)
3683 { "---", 0, 0, NULL }, 3683 { "---" },
3684 { "${menu.page.copyurl}", 0, 0, "document.copylink" } }, 3684 { "${menu.page.copyurl}", 0, 0, "document.copylink" } },
3685 14); 3685 14);
3686#else 3686#else
3687 { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" }, 3687 { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" },
3688 { "---", 0, 0, NULL }, 3688 { "---" },
3689 { "${menu.page.copyurl}", 0, 0, "document.copylink" } }, 3689 { "${menu.page.copyurl}", 0, 0, "document.copylink" } },
3690 15); 3690 15);
3691#endif 3691#endif
@@ -3862,7 +3862,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
3862 } 3862 }
3863 d->copyMenu = makeMenu_Widget(w, (iMenuItem[]){ 3863 d->copyMenu = makeMenu_Widget(w, (iMenuItem[]){
3864 { clipCopy_Icon " ${menu.copy}", 0, 0, "copy" }, 3864 { clipCopy_Icon " ${menu.copy}", 0, 0, "copy" },
3865 { "---", 0, 0, NULL }, 3865 { "---" },
3866 { close_Icon " ${menu.select.clear}", 0, 0, "document.select arg:0" }, 3866 { close_Icon " ${menu.select.clear}", 0, 0, "document.select arg:0" },
3867 }, 3); 3867 }, 3);
3868 setFlags_Widget(d->copyMenu, noFadeBackground_WidgetFlag, iTrue); 3868 setFlags_Widget(d->copyMenu, noFadeBackground_WidgetFlag, iTrue);
@@ -3955,7 +3955,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
3955 uiTextAction_ColorEscape, 3955 uiTextAction_ColorEscape,
3956 cstr_String(url)), 3956 cstr_String(url)),
3957 (iMenuItem[]){ 3957 (iMenuItem[]){
3958 { "${cancel}", 0, 0, NULL }, 3958 { "${cancel}" },
3959 { uiTextCaution_ColorEscape "${dlg.openlink}", 3959 { uiTextCaution_ColorEscape "${dlg.openlink}",
3960 0, 0, format_CStr("!open default:1 url:%s", cstr_String(url)) } }, 3960 0, 0, format_CStr("!open default:1 url:%s", cstr_String(url)) } },
3961 2); 3961 2);
diff --git a/src/ui/mobile.c b/src/ui/mobile.c
index 7e359a84..f3e23e06 100644
--- a/src/ui/mobile.c
+++ b/src/ui/mobile.c
@@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36# include "ios.h" 36# include "ios.h"
37#endif 37#endif
38 38
39static iBool useMobileSheetLayout_(void) { 39iBool isUsingPanelLayout_Mobile(void) {
40 return deviceType_App() != desktop_AppDeviceType; 40 return deviceType_App() != desktop_AppDeviceType;
41} 41}
42 42
@@ -381,6 +381,7 @@ static size_t countItems_(const iMenuItem *itemsNullTerminated) {
381void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { 381void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {
382 iWidget * widget = NULL; 382 iWidget * widget = NULL;
383 iLabelWidget *heading = NULL; 383 iLabelWidget *heading = NULL;
384 iWidget * value = NULL;
384 const char * spec = item->label; 385 const char * spec = item->label;
385 const char * id = cstr_Rangecc(range_Command(spec, "id")); 386 const char * id = cstr_Rangecc(range_Command(spec, "id"));
386 const char * label = hasLabel_Command(spec, "text") 387 const char * label = hasLabel_Command(spec, "text")
@@ -396,6 +397,7 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {
396 setFont_LabelWidget(title, uiLabelLargeBold_FontId); 397 setFont_LabelWidget(title, uiLabelLargeBold_FontId);
397 setTextColor_LabelWidget(title, uiHeading_ColorId); 398 setTextColor_LabelWidget(title, uiHeading_ColorId);
398 setAllCaps_LabelWidget(title, iTrue); 399 setAllCaps_LabelWidget(title, iTrue);
400 setId_Widget(as_Widget(title), id);
399 } 401 }
400 else if (equal_Command(spec, "heading")) { 402 else if (equal_Command(spec, "heading")) {
401 addChild_Widget(panel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); 403 addChild_Widget(panel, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));
@@ -403,6 +405,7 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {
403 setAllCaps_LabelWidget(heading, iTrue); 405 setAllCaps_LabelWidget(heading, iTrue);
404 setRemoveTrailingColon_LabelWidget(heading, iTrue); 406 setRemoveTrailingColon_LabelWidget(heading, iTrue);
405 addChild_Widget(panel, iClob(heading)); 407 addChild_Widget(panel, iClob(heading));
408 setId_Widget(as_Widget(heading), id);
406 } 409 }
407 else if (equal_Command(spec, "toggle")) { 410 else if (equal_Command(spec, "toggle")) {
408 iLabelWidget *toggle = (iLabelWidget *) makeToggle_Widget(id); 411 iLabelWidget *toggle = (iLabelWidget *) makeToggle_Widget(id);
@@ -412,7 +415,9 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {
412 } 415 }
413 else if (equal_Command(spec, "dropdown")) { 416 else if (equal_Command(spec, "dropdown")) {
414 const iMenuItem *dropItems = item->data; 417 const iMenuItem *dropItems = item->data;
415 iLabelWidget *drop = makeMenuButton_LabelWidget("", dropItems, countItems_(dropItems)); 418 iLabelWidget *drop = makeMenuButton_LabelWidget(dropItems[0].label,
419 dropItems, countItems_(dropItems));
420 value = as_Widget(drop);
416 setFont_LabelWidget(drop, labelFont_()); 421 setFont_LabelWidget(drop, labelFont_());
417 setFlags_Widget(as_Widget(drop), 422 setFlags_Widget(as_Widget(drop),
418 alignRight_WidgetFlag | noBackground_WidgetFlag | 423 alignRight_WidgetFlag | noBackground_WidgetFlag |
@@ -465,6 +470,9 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {
465 } 470 }
466 else if (equal_Command(spec, "input")) { 471 else if (equal_Command(spec, "input")) {
467 iInputWidget *input = new_InputWidget(argU32Label_Command(spec, "maxlen")); 472 iInputWidget *input = new_InputWidget(argU32Label_Command(spec, "maxlen"));
473 if (hasLabel_Command(spec, "hint")) {
474 setHint_InputWidget(input, cstr_Lang(cstr_Rangecc(range_Command(spec, "hint"))));
475 }
468 setId_Widget(as_Widget(input), id); 476 setId_Widget(as_Widget(input), id);
469 setUrlContent_InputWidget(input, argLabel_Command(spec, "url")); 477 setUrlContent_InputWidget(input, argLabel_Command(spec, "url"));
470 setSelectAllOnFocus_InputWidget(input, argLabel_Command(spec, "selectall")); 478 setSelectAllOnFocus_InputWidget(input, argLabel_Command(spec, "selectall"));
@@ -491,6 +499,12 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {
491 else if (equal_Command(spec, "button")) { 499 else if (equal_Command(spec, "button")) {
492 widget = as_Widget(heading = makePanelButton_(label, item->command)); 500 widget = as_Widget(heading = makePanelButton_(label, item->command));
493 } 501 }
502 else if (equal_Command(spec, "label")) {
503 iLabelWidget *lab = new_LabelWidget(label, NULL);
504 widget = as_Widget(lab);
505 setWrap_LabelWidget(lab, iTrue);
506 setFlags_Widget(widget, frameless_WidgetFlag, iTrue);
507 }
494 else if (equal_Command(spec, "padding")) { 508 else if (equal_Command(spec, "padding")) {
495 widget = makePadding_Widget(lineHeight_Text(labelFont_()) * 1.5f); 509 widget = makePadding_Widget(lineHeight_Text(labelFont_()) * 1.5f);
496 } 510 }
@@ -500,8 +514,14 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {
500 if (icon) { 514 if (icon) {
501 setIcon_LabelWidget(heading, icon); 515 setIcon_LabelWidget(heading, icon);
502 } 516 }
517 if (value && as_Widget(heading) != value) {
518 as_Widget(heading)->sizeRef = value; /* heading height matches value widget */
519 }
503 } 520 }
504 if (widget) { 521 if (widget) {
522 setFlags_Widget(widget,
523 collapse_WidgetFlag | hidden_WidgetFlag,
524 argLabel_Command(spec, "collapse") != 0);
505 addChild_Widget(panel, iClob(widget)); 525 addChild_Widget(panel, iClob(widget));
506 } 526 }
507} 527}
@@ -512,11 +532,26 @@ void makePanelItems_Mobile(iWidget *panel, const iMenuItem *itemsNullTerminated)
512 } 532 }
513} 533}
514 534
515iWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) { 535static const iMenuItem *findDialogCancelAction_(const iMenuItem *items, size_t n) {
536 if (n <= 1) {
537 return NULL;
538 }
539 for (size_t i = 0; i < n - 1; i++) {
540 if (!iCmpStr(items[i].label, "${cancel}")) {
541 return &items[i];
542 }
543 }
544 return NULL;
545}
546
547iWidget *makePanels_Mobile(const char *id,
548 const iMenuItem *itemsNullTerminated,
549 const iMenuItem *actions, size_t numActions) {
516 /* A multipanel widget has a top panel and one or more detail panels. In a horizontal layout, 550 /* A multipanel widget has a top panel and one or more detail panels. In a horizontal layout,
517 the detail panels slide in from the right and cover the top panel. In a landscape layout, 551 the detail panels slide in from the right and cover the top panel. In a landscape layout,
518 the detail panels are always visible on the side. */ 552 the detail panels are always visible on the side. */
519 iWidget *sheet = new_Widget(); 553 iWidget *sheet = new_Widget();
554 setId_Widget(sheet, id);
520 setBackgroundColor_Widget(sheet, uiBackground_ColorId); 555 setBackgroundColor_Widget(sheet, uiBackground_ColorId);
521 setFlags_Widget(sheet, 556 setFlags_Widget(sheet,
522 resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag | 557 resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag |
@@ -553,18 +588,21 @@ iWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) {
553 topPanel->offsetRef = detailStack; 588 topPanel->offsetRef = detailStack;
554 } 589 }
555 /* Navigation bar at the top. */ 590 /* Navigation bar at the top. */
591 iLabelWidget *naviBack;
556 iWidget *navi = new_Widget(); { 592 iWidget *navi = new_Widget(); {
557 setId_Widget(navi, "panel.navi"); 593 setId_Widget(navi, "panel.navi");
558 setBackgroundColor_Widget(navi, uiBackground_ColorId); 594 setBackgroundColor_Widget(navi, uiBackground_ColorId);
559 addChild_Widget(navi, iClob(makePadding_Widget(0))); 595 addChild_Widget(navi, iClob(makePadding_Widget(0)));
560 iLabelWidget *back = addChildFlags_Widget( 596 naviBack = addChildFlags_Widget(
561 navi, 597 navi,
562 iClob(new_LabelWidget(leftAngle_Icon " ${panel.back}", "panel.close")), 598 iClob(newKeyMods_LabelWidget(leftAngle_Icon " ${panel.back}",
599 SDLK_ESCAPE, 0,
600 "panel.close")),
563 noBackground_WidgetFlag | frameless_WidgetFlag | alignLeft_WidgetFlag | 601 noBackground_WidgetFlag | frameless_WidgetFlag | alignLeft_WidgetFlag |
564 extraPadding_WidgetFlag); 602 extraPadding_WidgetFlag);
565 checkIcon_LabelWidget(back); 603 checkIcon_LabelWidget(naviBack);
566 setId_Widget(as_Widget(back), "panel.back"); 604 setId_Widget(as_Widget(naviBack), "panel.back");
567 setFont_LabelWidget(back, labelFont_()); 605 setFont_LabelWidget(naviBack, labelFont_());
568 addChildFlags_Widget(sheet, iClob(navi), 606 addChildFlags_Widget(sheet, iClob(navi),
569 drawBackgroundToVerticalSafeArea_WidgetFlag | 607 drawBackgroundToVerticalSafeArea_WidgetFlag |
570 arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag | 608 arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag |
@@ -593,6 +631,54 @@ iWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) {
593 makePanelItem_Mobile(topPanel, item); 631 makePanelItem_Mobile(topPanel, item);
594 } 632 }
595 } 633 }
634 /* Actions. */
635 if (numActions) {
636 /* Some actions go in the navigation bar and some go on the top panel. */
637 const iMenuItem *cancelItem = findDialogCancelAction_(actions, numActions);
638 const iMenuItem *defaultItem = &actions[numActions - 1];
639 iAssert(defaultItem);
640 if (!cancelItem) {
641 updateTextCStr_LabelWidget(naviBack, defaultItem->label);
642 setCommand_LabelWidget(naviBack, collectNewCStr_String(defaultItem->command));
643 setFlags_Widget(as_Widget(naviBack), alignLeft_WidgetFlag, iFalse);
644 setFlags_Widget(as_Widget(naviBack), alignRight_WidgetFlag, iTrue);
645 setIcon_LabelWidget(naviBack, 0);
646 setFont_LabelWidget(naviBack, labelBoldFont_());
647 }
648 else {
649 updateTextCStr_LabelWidget(naviBack, cancelItem->label);
650 setCommand_LabelWidget(naviBack, collectNewCStr_String(cancelItem->command
651 ? cancelItem->command
652 : "cancel"));
653 iLabelWidget *defaultButton = new_LabelWidget(defaultItem->label, defaultItem->command);
654 setFont_LabelWidget(defaultButton, labelBoldFont_());
655 setFlags_Widget(as_Widget(defaultButton),
656 frameless_WidgetFlag | extraPadding_WidgetFlag |
657 noBackground_WidgetFlag,
658 iTrue);
659 addChildFlags_Widget(as_Widget(naviBack), iClob(defaultButton),
660 moveToParentRightEdge_WidgetFlag);
661 updateSize_LabelWidget(defaultButton);
662 }
663 /* All other actions are added as buttons. */
664 iBool needPadding = iTrue;
665 for (size_t i = 0; i < numActions; i++) {
666 const iMenuItem *act = &actions[i];
667 if (act == cancelItem || act == defaultItem) {
668 continue;
669 }
670 if (!iCmpStr(act->label, "---")) {
671 continue;
672 }
673 if (needPadding) {
674 makePanelItem_Mobile(topPanel, &(iMenuItem){ "padding" });
675 needPadding = iFalse;
676 }
677 makePanelItem_Mobile(
678 topPanel,
679 &(iMenuItem){ format_CStr("button text:%s", act->label), 0, 0, act->command });
680 }
681 }
596 /* Finalize the layout. */ 682 /* Finalize the layout. */
597 addChild_Widget(sheet->root->widget, iClob(sheet)); 683 addChild_Widget(sheet->root->widget, iClob(sheet));
598 mainDetailSplitHandler_(mainDetailSplit, "window.resized"); /* make it resize the split */ 684 mainDetailSplitHandler_(mainDetailSplit, "window.resized"); /* make it resize the split */
@@ -1011,7 +1097,7 @@ iWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) {
1011#endif 1097#endif
1012 1098
1013void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) { 1099void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) {
1014 if (!useMobileSheetLayout_()) { 1100 if (!isUsingPanelLayout_Mobile()) {
1015 return; 1101 return;
1016 } 1102 }
1017 const iBool isSlidePanel = (flags_Widget(sheet) & horizontalOffset_WidgetFlag) != 0; 1103 const iBool isSlidePanel = (flags_Widget(sheet) & horizontalOffset_WidgetFlag) != 0;
@@ -1032,7 +1118,7 @@ void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) {
1032} 1118}
1033 1119
1034void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) { 1120void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) {
1035 if (!useMobileSheetLayout_()) { 1121 if (!isUsingPanelLayout_Mobile()) {
1036 if (prefs_App()->uiAnimations) { 1122 if (prefs_App()->uiAnimations) {
1037 setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iFalse); 1123 setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iFalse);
1038 if (isIncoming) { 1124 if (isIncoming) {
diff --git a/src/ui/mobile.h b/src/ui/mobile.h
index 5e2d8957..4d742a0a 100644
--- a/src/ui/mobile.h
+++ b/src/ui/mobile.h
@@ -27,7 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
27iDeclareType(Widget) 27iDeclareType(Widget)
28iDeclareType(MenuItem) 28iDeclareType(MenuItem)
29 29
30iWidget * makePanels_Mobile (const iMenuItem *itemsNullTerminated); 30iBool isUsingPanelLayout_Mobile (void);
31iWidget * makePanels_Mobile (const char *id,
32 const iMenuItem *itemsNullTerminated,
33 const iMenuItem *actions, size_t numActions);
31 34
32void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming); 35void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming);
33void setupSheetTransition_Mobile (iWidget *sheet, iBool isIncoming); 36void setupSheetTransition_Mobile (iWidget *sheet, iBool isIncoming);
diff --git a/src/ui/root.c b/src/ui/root.c
index 0b55d250..eae8e4bb 100644
--- a/src/ui/root.c
+++ b/src/ui/root.c
@@ -57,28 +57,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
57static const iMenuItem navMenuItems_[] = { 57static const iMenuItem navMenuItems_[] = {
58 { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" }, 58 { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" },
59 { "${menu.openlocation}", SDLK_l, KMOD_PRIMARY, "navigate.focus" }, 59 { "${menu.openlocation}", SDLK_l, KMOD_PRIMARY, "navigate.focus" },
60 { "---", 0, 0, NULL }, 60 { "---" },
61 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" }, 61 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" },
62 { "${menu.page.copysource}", SDLK_c, KMOD_PRIMARY, "copy" }, 62 { "${menu.page.copysource}", SDLK_c, KMOD_PRIMARY, "copy" },
63 { "---", 0, 0, NULL }, 63 { "---" },
64 { leftHalf_Icon " ${menu.sidebar.left}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, 64 { leftHalf_Icon " ${menu.sidebar.left}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },
65 { rightHalf_Icon " ${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" }, 65 { rightHalf_Icon " ${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },
66 { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" }, 66 { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" },
67 { "${menu.zoom.in}", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" }, 67 { "${menu.zoom.in}", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" },
68 { "${menu.zoom.out}", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" }, 68 { "${menu.zoom.out}", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" },
69 { "${menu.zoom.reset}", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" }, 69 { "${menu.zoom.reset}", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" },
70 { "---", 0, 0, NULL }, 70 { "---" },
71 { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" }, 71 { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" },
72 { "${menu.bookmarks.bytag}", 0, 0, "!open url:about:bookmarks?tags" }, 72 { "${menu.bookmarks.bytag}", 0, 0, "!open url:about:bookmarks?tags" },
73 { "${menu.bookmarks.bytime}", 0, 0, "!open url:about:bookmarks?created" }, 73 { "${menu.bookmarks.bytime}", 0, 0, "!open url:about:bookmarks?created" },
74 { "---", 0, 0, NULL }, 74 { "---" },
75 { "${menu.downloads}", 0, 0, "downloads.open" }, 75 { "${menu.downloads}", 0, 0, "downloads.open" },
76 { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" }, 76 { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" },
77 { "---", 0, 0, NULL }, 77 { "---" },
78 { gear_Icon " ${menu.preferences}", SDLK_COMMA, KMOD_PRIMARY, "preferences" }, 78 { gear_Icon " ${menu.preferences}", SDLK_COMMA, KMOD_PRIMARY, "preferences" },
79 { "${menu.help}", SDLK_F1, 0, "!open url:about:help" }, 79 { "${menu.help}", SDLK_F1, 0, "!open url:about:help" },
80 { "${menu.releasenotes}", 0, 0, "!open url:about:version" }, 80 { "${menu.releasenotes}", 0, 0, "!open url:about:version" },
81 { "---", 0, 0, NULL }, 81 { "---" },
82 { "${menu.quit}", 'q', KMOD_PRIMARY, "quit" } 82 { "${menu.quit}", 'q', KMOD_PRIMARY, "quit" }
83}; 83};
84#endif 84#endif
@@ -89,17 +89,17 @@ static const iMenuItem tabletNavMenuItems_[] = {
89 { folder_Icon " ${menu.openfile}", SDLK_o, KMOD_PRIMARY, "file.open" }, 89 { folder_Icon " ${menu.openfile}", SDLK_o, KMOD_PRIMARY, "file.open" },
90 { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" }, 90 { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" },
91 { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" }, 91 { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" },
92 { "---", 0, 0, NULL }, 92 { "---" },
93 { magnifyingGlass_Icon " ${menu.find}", 0, 0, "focus.set id:find.input" }, 93 { magnifyingGlass_Icon " ${menu.find}", 0, 0, "focus.set id:find.input" },
94 { leftHalf_Icon " ${menu.sidebar.left}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, 94 { leftHalf_Icon " ${menu.sidebar.left}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },
95 { rightHalf_Icon " ${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" }, 95 { rightHalf_Icon " ${menu.sidebar.right}", SDLK_p, KMOD_PRIMARY | KMOD_SHIFT, "sidebar2.toggle" },
96 { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" }, 96 { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" },
97 { "---", 0, 0, NULL }, 97 { "---" },
98 { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" }, 98 { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" },
99 { "${menu.bookmarks.bytag}", 0, 0, "!open url:about:bookmarks?tags" }, 99 { "${menu.bookmarks.bytag}", 0, 0, "!open url:about:bookmarks?tags" },
100 { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" }, 100 { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" },
101 { "${menu.downloads}", 0, 0, "downloads.open" }, 101 { "${menu.downloads}", 0, 0, "downloads.open" },
102 { "---", 0, 0, NULL }, 102 { "---" },
103 { gear_Icon " ${menu.preferences}", SDLK_COMMA, KMOD_PRIMARY, "preferences" }, 103 { gear_Icon " ${menu.preferences}", SDLK_COMMA, KMOD_PRIMARY, "preferences" },
104 { "${menu.help}", SDLK_F1, 0, "!open url:about:help" }, 104 { "${menu.help}", SDLK_F1, 0, "!open url:about:help" },
105 { "${menu.releasenotes}", 0, 0, "!open url:about:version" }, 105 { "${menu.releasenotes}", 0, 0, "!open url:about:version" },
@@ -110,14 +110,14 @@ static const iMenuItem phoneNavMenuItems_[] = {
110 { folder_Icon " ${menu.openfile}", SDLK_o, KMOD_PRIMARY, "file.open" }, 110 { folder_Icon " ${menu.openfile}", SDLK_o, KMOD_PRIMARY, "file.open" },
111 { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" }, 111 { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" },
112 { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" }, 112 { close_Icon " ${menu.closetab}", 'w', KMOD_PRIMARY, "tabs.close" },
113 { "---", 0, 0, NULL }, 113 { "---" },
114 { magnifyingGlass_Icon " ${menu.find}", 0, 0, "focus.set id:find.input" }, 114 { magnifyingGlass_Icon " ${menu.find}", 0, 0, "focus.set id:find.input" },
115 { leftHalf_Icon " ${menu.sidebar}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, 115 { leftHalf_Icon " ${menu.sidebar}", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" },
116 { "---", 0, 0, NULL }, 116 { "---" },
117 { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" }, 117 { book_Icon " ${menu.bookmarks.list}", 0, 0, "!open url:about:bookmarks" },
118 { "${menu.downloads}", 0, 0, "downloads.open" }, 118 { "${menu.downloads}", 0, 0, "downloads.open" },
119 { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" }, 119 { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" },
120 { "---", 0, 0, NULL }, 120 { "---" },
121 { gear_Icon " Settings...", SDLK_COMMA, KMOD_PRIMARY, "preferences" }, 121 { gear_Icon " Settings...", SDLK_COMMA, KMOD_PRIMARY, "preferences" },
122}; 122};
123#endif /* Mobile */ 123#endif /* Mobile */
@@ -125,24 +125,24 @@ static const iMenuItem phoneNavMenuItems_[] = {
125#if defined (iPlatformMobile) 125#if defined (iPlatformMobile)
126static const iMenuItem identityButtonMenuItems_[] = { 126static const iMenuItem identityButtonMenuItems_[] = {
127 { "${menu.identity.notactive}", 0, 0, "ident.showactive" }, 127 { "${menu.identity.notactive}", 0, 0, "ident.showactive" },
128 { "---", 0, 0, NULL }, 128 { "---" },
129 { add_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" }, 129 { add_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" },
130 { "${menu.identity.import}", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" }, 130 { "${menu.identity.import}", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" },
131 { "---", 0, 0, NULL }, 131 { "---" },
132 { person_Icon " ${menu.show.identities}", 0, 0, "toolbar.showident" }, 132 { person_Icon " ${menu.show.identities}", 0, 0, "toolbar.showident" },
133}; 133};
134#else /* desktop */ 134#else /* desktop */
135static const iMenuItem identityButtonMenuItems_[] = { 135static const iMenuItem identityButtonMenuItems_[] = {
136 { "${menu.identity.notactive}", 0, 0, "ident.showactive" }, 136 { "${menu.identity.notactive}", 0, 0, "ident.showactive" },
137 { "---", 0, 0, NULL }, 137 { "---" },
138# if !defined (iPlatformAppleDesktop) 138# if !defined (iPlatformAppleDesktop)
139 { add_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" }, 139 { add_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" },
140 { "${menu.identity.import}", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" }, 140 { "${menu.identity.import}", SDLK_i, KMOD_PRIMARY | KMOD_SHIFT, "ident.import" },
141 { "---", 0, 0, NULL }, 141 { "---" },
142 { person_Icon " ${menu.show.identities}", '4', KMOD_PRIMARY, "sidebar.mode arg:3 show:1" }, 142 { person_Icon " ${menu.show.identities}", '4', KMOD_PRIMARY, "sidebar.mode arg:3 show:1" },
143# else 143# else
144 { add_Icon " ${menu.identity.new}", 0, 0, "ident.new" }, 144 { add_Icon " ${menu.identity.new}", 0, 0, "ident.new" },
145 { "---", 0, 0, NULL }, 145 { "---" },
146 { person_Icon " ${menu.show.identities}", 0, 0, "sidebar.mode arg:3 show:1" }, 146 { person_Icon " ${menu.show.identities}", 0, 0, "sidebar.mode arg:3 show:1" },
147# endif 147# endif
148}; 148};
@@ -1158,20 +1158,20 @@ void createUserInterface_Root(iRoot *d) {
1158 { upArrow_Icon " ${menu.parent}", navigateParent_KeyShortcut, "navigate.parent" }, 1158 { upArrow_Icon " ${menu.parent}", navigateParent_KeyShortcut, "navigate.parent" },
1159 { upArrowBar_Icon " ${menu.root}", navigateRoot_KeyShortcut, "navigate.root" }, 1159 { upArrowBar_Icon " ${menu.root}", navigateRoot_KeyShortcut, "navigate.root" },
1160 { timer_Icon " ${menu.autoreload}", 0, 0, "document.autoreload.menu" }, 1160 { timer_Icon " ${menu.autoreload}", 0, 0, "document.autoreload.menu" },
1161 { "---", 0, 0, NULL }, 1161 { "---" },
1162 { bookmark_Icon " ${menu.page.bookmark}", SDLK_d, KMOD_PRIMARY, "bookmark.add" }, 1162 { bookmark_Icon " ${menu.page.bookmark}", SDLK_d, KMOD_PRIMARY, "bookmark.add" },
1163 { star_Icon " ${menu.page.subscribe}", subscribeToPage_KeyModifier, "feeds.subscribe" }, 1163 { star_Icon " ${menu.page.subscribe}", subscribeToPage_KeyModifier, "feeds.subscribe" },
1164 { book_Icon " ${menu.page.import}", 0, 0, "bookmark.links confirm:1" }, 1164 { book_Icon " ${menu.page.import}", 0, 0, "bookmark.links confirm:1" },
1165 { globe_Icon " ${menu.page.translate}", 0, 0, "document.translate" }, 1165 { globe_Icon " ${menu.page.translate}", 0, 0, "document.translate" },
1166#if defined (iPlatformMobile) 1166#if defined (iPlatformMobile)
1167 { "---", 0, 0, NULL }, 1167 { "---" },
1168 { "${menu.page.copyurl}", 0, 0, "document.copylink" }, 1168 { "${menu.page.copyurl}", 0, 0, "document.copylink" },
1169 { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" }, 1169 { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" },
1170 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } }, 1170 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } },
1171 11); 1171 11);
1172#else 1172#else
1173 { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" }, 1173 { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" },
1174 { "---", 0, 0, NULL }, 1174 { "---" },
1175 { "${menu.page.copyurl}", 0, 0, "document.copylink" }, 1175 { "${menu.page.copyurl}", 0, 0, "document.copylink" },
1176 { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" }, 1176 { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" },
1177 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } }, 1177 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } },
@@ -1355,7 +1355,7 @@ void createUserInterface_Root(iRoot *d) {
1355 (iMenuItem[]){ 1355 (iMenuItem[]){
1356 { close_Icon " ${menu.closetab}", 0, 0, "tabs.close" }, 1356 { close_Icon " ${menu.closetab}", 0, 0, "tabs.close" },
1357 { copy_Icon " ${menu.duptab}", 0, 0, "tabs.new duplicate:1" }, 1357 { copy_Icon " ${menu.duptab}", 0, 0, "tabs.new duplicate:1" },
1358 { "---", 0, 0, NULL }, 1358 { "---" },
1359 { "${menu.closetab.other}", 0, 0, "tabs.close toleft:1 toright:1" }, 1359 { "${menu.closetab.other}", 0, 0, "tabs.close toleft:1 toright:1" },
1360 { barLeftArrow_Icon " ${menu.closetab.left}", 0, 0, "tabs.close toleft:1" }, 1360 { barLeftArrow_Icon " ${menu.closetab.left}", 0, 0, "tabs.close toleft:1" },
1361 { barRightArrow_Icon " ${menu.closetab.right}", 0, 0, "tabs.close toright:1" }, 1361 { barRightArrow_Icon " ${menu.closetab.right}", 0, 0, "tabs.close toright:1" },
@@ -1372,18 +1372,18 @@ void createUserInterface_Root(iRoot *d) {
1372 (iMenuItem[]){ 1372 (iMenuItem[]){
1373 { scissor_Icon " ${menu.cut}", 0, 0, "input.copy cut:1" }, 1373 { scissor_Icon " ${menu.cut}", 0, 0, "input.copy cut:1" },
1374 { clipCopy_Icon " ${menu.copy}", 0, 0, "input.copy" }, 1374 { clipCopy_Icon " ${menu.copy}", 0, 0, "input.copy" },
1375 { "---", 0, 0, NULL }, 1375 { "---" },
1376 { clipboard_Icon " ${menu.paste}", 0, 0, "input.paste" }, 1376 { clipboard_Icon " ${menu.paste}", 0, 0, "input.paste" },
1377 }, 1377 },
1378 4); 1378 4);
1379 iWidget *splitMenu = makeMenu_Widget(root, (iMenuItem[]){ 1379 iWidget *splitMenu = makeMenu_Widget(root, (iMenuItem[]){
1380 { "${menu.split.merge}", '1', 0, "ui.split arg:0" }, 1380 { "${menu.split.merge}", '1', 0, "ui.split arg:0" },
1381 { "${menu.split.swap}", SDLK_x, 0, "ui.split swap:1" }, 1381 { "${menu.split.swap}", SDLK_x, 0, "ui.split swap:1" },
1382 { "---", 0, 0, NULL }, 1382 { "---" },
1383 { "${menu.split.horizontal}", '3', 0, "ui.split arg:3 axis:0" }, 1383 { "${menu.split.horizontal}", '3', 0, "ui.split arg:3 axis:0" },
1384 { "${menu.split.horizontal} 1:2", SDLK_d, 0, "ui.split arg:1 axis:0" }, 1384 { "${menu.split.horizontal} 1:2", SDLK_d, 0, "ui.split arg:1 axis:0" },
1385 { "${menu.split.horizontal} 2:1", SDLK_e, 0, "ui.split arg:2 axis:0" }, 1385 { "${menu.split.horizontal} 2:1", SDLK_e, 0, "ui.split arg:2 axis:0" },
1386 { "---", 0, 0, NULL }, 1386 { "---" },
1387 { "${menu.split.vertical}", '2', 0, "ui.split arg:3 axis:1" }, 1387 { "${menu.split.vertical}", '2', 0, "ui.split arg:3 axis:1" },
1388 { "${menu.split.vertical} 1:2", SDLK_f, 0, "ui.split arg:1 axis:1" }, 1388 { "${menu.split.vertical} 1:2", SDLK_f, 0, "ui.split arg:1 axis:1" },
1389 { "${menu.split.vertical} 2:1", SDLK_r, 0, "ui.split arg:2 axis:1" }, 1389 { "${menu.split.vertical} 2:1", SDLK_r, 0, "ui.split arg:2 axis:1" },
diff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c
index 5e1ee493..4c72c60a 100644
--- a/src/ui/uploadwidget.c
+++ b/src/ui/uploadwidget.c
@@ -148,7 +148,7 @@ void init_UploadWidget(iUploadWidget *d) {
148 addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); 148 addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));
149 iWidget *buttons = 149 iWidget *buttons =
150 makeDialogButtons_Widget((iMenuItem[]){ { "${upload.port}", 0, 0, "upload.setport" }, 150 makeDialogButtons_Widget((iMenuItem[]){ { "${upload.port}", 0, 0, "upload.setport" },
151 { "---", 0, 0, NULL }, 151 { "---" },
152 { "${close}", SDLK_ESCAPE, 0, "upload.cancel" }, 152 { "${close}", SDLK_ESCAPE, 0, "upload.cancel" },
153 { uiTextAction_ColorEscape "${dlg.upload.send}", 153 { uiTextAction_ColorEscape "${dlg.upload.send}",
154 SDLK_RETURN, 154 SDLK_RETURN,
diff --git a/src/ui/util.c b/src/ui/util.c
index 22d8bce4..abe6f22e 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -907,6 +907,20 @@ iLabelWidget *makeMenuButton_LabelWidget(const char *label, const iMenuItem *ite
907 return button; 907 return button;
908} 908}
909 909
910void updateDropdownSelection_LabelWidget(iLabelWidget *dropButton, const char *selectedCommand) {
911 iWidget *menu = findChild_Widget(as_Widget(dropButton), "menu");
912 iForEach(ObjectList, i, children_Widget(menu)) {
913 if (isInstance_Object(i.object, &Class_LabelWidget)) {
914 iLabelWidget *item = i.object;
915 const iBool isSelected = endsWith_String(command_LabelWidget(item), selectedCommand);
916 setFlags_Widget(as_Widget(item), selected_WidgetFlag, isSelected);
917 if (isSelected) {
918 updateText_LabelWidget(dropButton, sourceText_LabelWidget(item));
919 }
920 }
921 }
922}
923
910/*-----------------------------------------------------------------------------------------------*/ 924/*-----------------------------------------------------------------------------------------------*/
911 925
912static iBool isTabPage_Widget_(const iWidget *tabs, const iWidget *page) { 926static iBool isTabPage_Widget_(const iWidget *tabs, const iWidget *page) {
@@ -1650,6 +1664,19 @@ static size_t findWidestItemLabel_(const iMenuItem *items, size_t num) {
1650 return widestPos; 1664 return widestPos;
1651} 1665}
1652 1666
1667iWidget *makeDialog_Widget(const char *id,
1668 const iMenuItem *itemsNullTerminated,
1669 const iMenuItem *actions, size_t numActions) {
1670 iWidget *dlg = makeSheet_Widget(id);
1671 /* TODO: Construct desktop dialogs using NULL-terminated item arrays, like mobile panels. */
1672 addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI)));
1673 addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, numActions)));
1674 addChild_Widget(dlg->root->widget, iClob(dlg));
1675 arrange_Widget(dlg);
1676 setupSheetTransition_Mobile(dlg, iTrue);
1677 return dlg;
1678}
1679
1653iWidget *makePreferences_Widget(void) { 1680iWidget *makePreferences_Widget(void) {
1654 /* Common items. */ 1681 /* Common items. */
1655 const iMenuItem langItems[] = { { "${lang.de} - de", 0, 0, "uilang id:de" }, 1682 const iMenuItem langItems[] = { { "${lang.de} - de", 0, 0, "uilang id:de" },
@@ -1715,7 +1742,7 @@ iWidget *makePreferences_Widget(void) {
1715 { NULL } 1742 { NULL }
1716 }; 1743 };
1717 /* Create the Preferences UI. */ 1744 /* Create the Preferences UI. */
1718 if (deviceType_App() != desktop_AppDeviceType) { 1745 if (isUsingPanelLayout_Mobile()) {
1719 const iMenuItem pinSplitItems[] = { 1746 const iMenuItem pinSplitItems[] = {
1720 { "button id:prefs.pinsplit.0 label:prefs.pinsplit.none", 0, 0, "pinsplit.set arg:0" }, 1747 { "button id:prefs.pinsplit.0 label:prefs.pinsplit.none", 0, 0, "pinsplit.set arg:0" },
1721 { "button id:prefs.pinsplit.1 label:prefs.pinsplit.left", 0, 0, "pinsplit.set arg:1" }, 1748 { "button id:prefs.pinsplit.1 label:prefs.pinsplit.left", 0, 0, "pinsplit.set arg:1" },
@@ -1767,7 +1794,7 @@ iWidget *makePreferences_Widget(void) {
1767 }; 1794 };
1768 const iMenuItem generalPanelItems[] = { 1795 const iMenuItem generalPanelItems[] = {
1769 { "title id:heading.prefs.general" }, 1796 { "title id:heading.prefs.general" },
1770 { "heading id:prefs.searchurl" }, 1797 { "heading text:${prefs.searchurl}" },
1771 { "input id:prefs.searchurl url:1 noheading:1" }, 1798 { "input id:prefs.searchurl url:1 noheading:1" },
1772 { "padding" }, 1799 { "padding" },
1773 { "toggle id:prefs.archive.openindex" }, 1800 { "toggle id:prefs.archive.openindex" },
@@ -1828,11 +1855,11 @@ iWidget *makePreferences_Widget(void) {
1828 { "padding" }, 1855 { "padding" },
1829 { "input id:prefs.cachesize maxlen:4 selectall:1 unit:mb" }, 1856 { "input id:prefs.cachesize maxlen:4 selectall:1 unit:mb" },
1830 { "input id:prefs.memorysize maxlen:4 selectall:1 unit:mb" }, 1857 { "input id:prefs.memorysize maxlen:4 selectall:1 unit:mb" },
1831 { "heading id:prefs.proxy.gemini" }, 1858 { "heading text:${prefs.proxy.gemini}" },
1832 { "input id:prefs.proxy.gemini noheading:1" }, 1859 { "input id:prefs.proxy.gemini noheading:1" },
1833 { "heading id:prefs.proxy.gemini" }, 1860 { "heading text:${prefs.proxy.gopher}" },
1834 { "input id:prefs.proxy.gopher noheading:1" }, 1861 { "input id:prefs.proxy.gopher noheading:1" },
1835 { "heading id:prefs.proxy.gemini" }, 1862 { "heading text:${prefs.proxy.http}" },
1836 { "input id:prefs.proxy.http noheading:1" }, 1863 { "input id:prefs.proxy.http noheading:1" },
1837 { NULL } 1864 { NULL }
1838 }; 1865 };
@@ -1855,8 +1882,8 @@ iWidget *makePreferences_Widget(void) {
1855 { "button text:" bug_Icon " ${menu.debug}", 0, 0, "!open url:about:debug" }, 1882 { "button text:" bug_Icon " ${menu.debug}", 0, 0, "!open url:about:debug" },
1856 { NULL } 1883 { NULL }
1857 }; 1884 };
1858 iWidget *dlg = makePanels_Mobile((iMenuItem[]){ 1885 iWidget *dlg = makePanels_Mobile("prefs", (iMenuItem[]){
1859 { "panel icon:0x2699 id:heading.prefs.general", 0, 0, (const void *) generalPanelItems }, 1886 { "panel text:" gear_Icon " ${heading.prefs.general}", 0, 0, (const void *) generalPanelItems },
1860 { "panel icon:0x1f5a7 id:heading.prefs.network", 0, 0, (const void *) networkPanelItems }, 1887 { "panel icon:0x1f5a7 id:heading.prefs.network", 0, 0, (const void *) networkPanelItems },
1861 { "panel text:" person_Icon " ${sidebar.identities}", 0, 0, (const void *) identityPanelItems }, 1888 { "panel text:" person_Icon " ${sidebar.identities}", 0, 0, (const void *) identityPanelItems },
1862 { "padding" }, 1889 { "padding" },
@@ -1869,7 +1896,7 @@ iWidget *makePreferences_Widget(void) {
1869 { "padding" }, 1896 { "padding" },
1870 { "panel text:" planet_Icon " ${menu.about}", 0, 0, (const void *) aboutPanelItems }, 1897 { "panel text:" planet_Icon " ${menu.about}", 0, 0, (const void *) aboutPanelItems },
1871 { NULL } 1898 { NULL }
1872 }); 1899 }, NULL, 0);
1873 setupSheetTransition_Mobile(dlg, iTrue); 1900 setupSheetTransition_Mobile(dlg, iTrue);
1874 return dlg; 1901 return dlg;
1875 } 1902 }
@@ -2153,6 +2180,29 @@ iWidget *makePreferences_Widget(void) {
2153} 2180}
2154 2181
2155iWidget *makeBookmarkEditor_Widget(void) { 2182iWidget *makeBookmarkEditor_Widget(void) {
2183 const iMenuItem actions[] = {
2184 { "${cancel}" },
2185 { uiTextCaution_ColorEscape "${dlg.bookmark.save}", SDLK_RETURN, KMOD_PRIMARY, "bmed.accept" }
2186 };
2187 if (isUsingPanelLayout_Mobile()) {
2188 const iMenuItem items[] = {
2189 { "title id:bmed.heading text:${heading.bookmark.edit}" },
2190 { "heading id:dlg.bookmark.url" },
2191 { "input id:bmed.url url:1 noheading:1" },
2192 { "padding" },
2193 { "input id:bmed.title text:${dlg.bookmark.title}" },
2194 { "input id:bmed.tags text:${dlg.bookmark.tags}" },
2195 { "input id:bmed.icon maxlen:1 text:${dlg.bookmark.icon}" },
2196 { "heading text:${heading.bookmark.tags}" },
2197 { "toggle id:bmed.tag.home text:${bookmark.tag.home}" },
2198 { "toggle id:bmed.tag.remote text:${bookmark.tag.remote}" },
2199 { "toggle id:bmed.tag.linksplit text:${bookmark.tag.linksplit}" },
2200 { NULL }
2201 };
2202 iWidget *dlg = makePanels_Mobile("bmed", items, actions, iElemCount(actions));
2203 setupSheetTransition_Mobile(dlg, iTrue);
2204 return dlg;
2205 }
2156 iWidget *dlg = makeSheet_Widget("bmed"); 2206 iWidget *dlg = makeSheet_Widget("bmed");
2157 setId_Widget(addChildFlags_Widget( 2207 setId_Widget(addChildFlags_Widget(
2158 dlg, 2208 dlg,
@@ -2179,14 +2229,7 @@ iWidget *makeBookmarkEditor_Widget(void) {
2179 as_Widget(inputs[i])->rect.size.x = 100 * gap_UI - headings->rect.size.x; 2229 as_Widget(inputs[i])->rect.size.x = 100 * gap_UI - headings->rect.size.x;
2180 } 2230 }
2181 addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI))); 2231 addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI)));
2182 addChild_Widget( 2232 addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, iElemCount(actions))));
2183 dlg,
2184 iClob(makeDialogButtons_Widget((iMenuItem[]){ { "${cancel}" },
2185 { uiTextCaution_ColorEscape "${dlg.bookmark.save}",
2186 SDLK_RETURN,
2187 KMOD_PRIMARY,
2188 "bmed.accept" } },
2189 2)));
2190 addChild_Widget(get_Root()->widget, iClob(dlg)); 2233 addChild_Widget(get_Root()->widget, iClob(dlg));
2191 finalizeSheet_Mobile(dlg); 2234 finalizeSheet_Mobile(dlg);
2192 return dlg; 2235 return dlg;
@@ -2242,7 +2285,6 @@ iWidget *makeBookmarkCreation_Widget(const iString *url, const iString *title, i
2242 return dlg; 2285 return dlg;
2243} 2286}
2244 2287
2245
2246static iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) { 2288static iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) {
2247 if (equal_Command(cmd, "cancel")) { 2289 if (equal_Command(cmd, "cancel")) {
2248 setupSheetTransition_Mobile(dlg, iFalse); 2290 setupSheetTransition_Mobile(dlg, iFalse);
@@ -2288,46 +2330,59 @@ static iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) {
2288} 2330}
2289 2331
2290iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) { 2332iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {
2291 iWidget *dlg = makeSheet_Widget("feedcfg"); 2333 const char *headingText = bookmarkId ? uiHeading_ColorEscape "${heading.feedcfg}"
2292 setId_Widget(addChildFlags_Widget( 2334 : uiHeading_ColorEscape "${heading.subscribe}";
2293 dlg, 2335 const iMenuItem actions[] = { { "${cancel}" },
2294 iClob(new_LabelWidget(bookmarkId ? uiHeading_ColorEscape "${heading.feedcfg}" 2336 { bookmarkId ? uiTextCaution_ColorEscape "${dlg.feed.save}"
2295 : uiHeading_ColorEscape "${heading.subscribe}", 2337 : uiTextCaution_ColorEscape "${dlg.feed.sub}",
2296 NULL)), 2338 SDLK_RETURN,
2297 frameless_WidgetFlag), 2339 KMOD_PRIMARY,
2298 "feedcfg.heading"); 2340 format_CStr("feedcfg.accept bmid:%d", bookmarkId) } };
2299 iWidget *headings, *values; 2341 iWidget *dlg;
2300 addChild_Widget(dlg, iClob(makeTwoColumns_Widget(&headings, &values))); 2342 if (isUsingPanelLayout_Mobile()) {
2301 iInputWidget *input = new_InputWidget(0); 2343 const iMenuItem typeItems[] = {
2302 addDialogInputWithHeading_(headings, values, "${dlg.feed.title}", "feedcfg.title", iClob(input)); 2344 { "button id:feedcfg.type.gemini label:dlg.feed.type.gemini", 0, 0, "feedcfg.type arg:0" },
2303 addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.feed.entrytype}"))); 2345 { "button id:feedcfg.type.headings label:dlg.feed.type.headings", 0, 0, "feedcfg.type arg:1" },
2304 iWidget *types = new_Widget(); { 2346 { NULL }
2305 addRadioButton_(types, "feedcfg.type.gemini", "${dlg.feed.type.gemini}", "feedcfg.type arg:0"); 2347 };
2306 addRadioButton_(types, "feedcfg.type.headings", "${dlg.feed.type.headings}", "feedcfg.type arg:1"); 2348 dlg = makePanels_Mobile("feedcfg", (iMenuItem[]){
2307 } 2349 { format_CStr("title id:feedcfg.heading text:%s", headingText) },
2308 addChildFlags_Widget(values, iClob(types), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); 2350 { "input id:feedcfg.title text:${dlg.feed.title}" },
2309 iWidget *buttons = 2351 { "radio id:dlg.feed.entrytype", 0, 0, (const void *) typeItems },
2310 addChild_Widget(dlg, 2352 { NULL }
2311 iClob(makeDialogButtons_Widget( 2353 }, actions, iElemCount(actions));
2312 (iMenuItem[]){ { "${cancel}" }, 2354 }
2313 { bookmarkId ? uiTextCaution_ColorEscape "${dlg.feed.save}" 2355 else {
2314 : uiTextCaution_ColorEscape "${dlg.feed.sub}", 2356 dlg = makeSheet_Widget("feedcfg");
2315 SDLK_RETURN, 2357 setId_Widget(
2316 KMOD_PRIMARY, 2358 addChildFlags_Widget(dlg, iClob(new_LabelWidget(headingText, NULL)), frameless_WidgetFlag),
2317 format_CStr("feedcfg.accept bmid:%d", bookmarkId) } }, 2359 "feedcfg.heading");
2318 2))); 2360 iWidget *headings, *values;
2319 setId_Widget(child_Widget(buttons, childCount_Widget(buttons) - 1), "feedcfg.save"); 2361 addChild_Widget(dlg, iClob(makeTwoColumns_Widget(&headings, &values)));
2320 arrange_Widget(dlg); 2362 iInputWidget *input = new_InputWidget(0);
2321 as_Widget(input)->rect.size.x = 100 * gap_UI - headings->rect.size.x; 2363 addDialogInputWithHeading_(headings, values, "${dlg.feed.title}", "feedcfg.title", iClob(input));
2322 addChild_Widget(get_Root()->widget, iClob(dlg)); 2364 addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.feed.entrytype}")));
2323 finalizeSheet_Mobile(dlg); 2365 iWidget *types = new_Widget(); {
2366 addRadioButton_(types, "feedcfg.type.gemini", "${dlg.feed.type.gemini}", "feedcfg.type arg:0");
2367 addRadioButton_(types, "feedcfg.type.headings", "${dlg.feed.type.headings}", "feedcfg.type arg:1");
2368 }
2369 addChildFlags_Widget(values, iClob(types), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
2370 iWidget *buttons =
2371 addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, iElemCount(actions))));
2372 setId_Widget(child_Widget(buttons, childCount_Widget(buttons) - 1), "feedcfg.save");
2373 arrange_Widget(dlg);
2374 as_Widget(input)->rect.size.x = 100 * gap_UI - headings->rect.size.x;
2375 addChild_Widget(get_Root()->widget, iClob(dlg));
2376 finalizeSheet_Mobile(dlg);
2377 }
2324 /* Initialize. */ { 2378 /* Initialize. */ {
2325 const iBookmark *bm = bookmarkId ? get_Bookmarks(bookmarks_App(), bookmarkId) : NULL; 2379 const iBookmark *bm = bookmarkId ? get_Bookmarks(bookmarks_App(), bookmarkId) : NULL;
2326 setText_InputWidget(findChild_Widget(dlg, "feedcfg.title"), 2380 setText_InputWidget(findChild_Widget(dlg, "feedcfg.title"),
2327 bm ? &bm->title : feedTitle_DocumentWidget(document_App())); 2381 bm ? &bm->title : feedTitle_DocumentWidget(document_App()));
2328 setFlags_Widget(findChild_Widget(dlg, 2382 setFlags_Widget(findChild_Widget(dlg,
2329 hasTag_Bookmark(bm, headings_BookmarkTag) ? "feedcfg.type.headings" 2383 hasTag_Bookmark(bm, headings_BookmarkTag)
2330 : "feedcfg.type.gemini"), 2384 ? "feedcfg.type.headings"
2385 : "feedcfg.type.gemini"),
2331 selected_WidgetFlag, 2386 selected_WidgetFlag,
2332 iTrue); 2387 iTrue);
2333 setCommandHandler_Widget(dlg, handleFeedSettingCommands_); 2388 setCommandHandler_Widget(dlg, handleFeedSettingCommands_);
@@ -2336,84 +2391,113 @@ iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {
2336} 2391}
2337 2392
2338iWidget *makeIdentityCreation_Widget(void) { 2393iWidget *makeIdentityCreation_Widget(void) {
2339 iWidget *dlg = makeSheet_Widget("ident"); 2394 const iMenuItem actions[] = { { "${dlg.newident.more}", 0, 0, "ident.showmore" },
2340 setId_Widget(addChildFlags_Widget( 2395 { "---" },
2341 dlg, 2396 { "${cancel}", SDLK_ESCAPE, 0, "ident.cancel" },
2342 iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.newident}", NULL)), 2397 { uiTextAction_ColorEscape "${dlg.newident.create}",
2343 frameless_WidgetFlag), 2398 SDLK_RETURN,
2344 "ident.heading"); 2399 KMOD_PRIMARY,
2345 iWidget *page = new_Widget(); 2400 "ident.accept" } };
2346 addChildFlags_Widget( 2401 iUrl url;
2347 dlg, iClob(new_LabelWidget("${dlg.newident.rsa.selfsign}", NULL)), frameless_WidgetFlag); 2402 init_Url(&url, url_DocumentWidget(document_App()));
2348 /* TODO: Use makeTwoColumnWidget_? */ 2403 const iMenuItem scopeItems[] = {
2349 addChild_Widget(dlg, iClob(page)); 2404 { format_CStr("${dlg.newident.scope.domain}:\n%s", cstr_Rangecc(url.host)), 0, 0, "ident.scope arg:0" },
2350 setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue); 2405 { format_CStr("${dlg.newident.scope.page}:\n%s", cstr_Rangecc(url.path)), 0, 0, "ident.scope arg:1" },
2351 iWidget *headings = addChildFlags_Widget( 2406 { "${dlg.newident.scope.none}", 0, 0, "ident.scope arg:2" },
2352 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); 2407 { NULL }
2353 iWidget *values = addChildFlags_Widget( 2408 };
2354 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); 2409 iWidget *dlg;
2355 setId_Widget(headings, "headings"); 2410 if (isUsingPanelLayout_Mobile()) {
2356 setId_Widget(values, "values"); 2411 dlg = makePanels_Mobile("ident",
2357 iInputWidget *inputs[6]; 2412 (iMenuItem[]){ { "title id:ident.heading text:${heading.newident}" },
2358 /* Where will the new identity be active on? */ { 2413 { "label text:${dlg.newident.rsa.selfsign}" },
2359 addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.newident.scope}"))); 2414 { "dropdown id:ident.scope text:${dlg.newident.scope}", 0, 0,
2360 const iMenuItem items[] = { 2415 (const void *) scopeItems },
2361 { "${dlg.newident.scope.domain}", 0, 0, "ident.scope arg:0" }, 2416 { "input id:ident.until hint:hint.newident.date maxlen:19 text:${dlg.newident.until}" },
2362 { "${dlg.newident.scope.page}", 0, 0, "ident.scope arg:1" }, 2417 //{ "padding" },
2363 { "${dlg.newident.scope.none}", 0, 0, "ident.scope arg:2" }, 2418 //{ "toggle id:ident.temp text:${dlg.newident.temp}" },
2364 }; 2419 //{ "label text:${help.ident.temp}" },
2365 setId_Widget(addChild_Widget(values, 2420 { "heading id:dlg.newident.commonname" },
2366 iClob(makeMenuButton_LabelWidget( 2421 { "input id:ident.common noheading:1" },
2367 items[0].label, items, iElemCount(items)))), 2422 { "padding collapse:1" },
2368 "ident.scope"); 2423 { "input collapse:1 id:ident.email hint:hint.newident.optional text:${dlg.newident.email}" },
2369 } 2424 { "input collapse:1 id:ident.userid hint:hint.newident.optional text:${dlg.newident.userid}" },
2370 addDialogInputWithHeading_(headings, 2425 { "input collapse:1 id:ident.domain hint:hint.newident.optional text:${dlg.newident.domain}" },
2371 values, 2426 { "input collapse:1 id:ident.org hint:hint.newident.optional text:${dlg.newident.org}" },
2372 "${dlg.newident.until}", 2427 { "input collapse:1 id:ident.country hint:hint.newident.optional text:${dlg.newident.country}" },
2373 "ident.until", 2428 { NULL }
2374 iClob(newHint_InputWidget(19, "${hint.newident.date}"))); 2429 }, actions, iElemCount(actions));
2375 addDialogInputWithHeading_(headings, 2430 setupSheetTransition_Mobile(dlg, iTrue);
2376 values, 2431 }
2377 "${dlg.newident.commonname}", 2432 else {
2378 "ident.common", 2433 dlg = makeSheet_Widget("ident");
2379 iClob(inputs[0] = new_InputWidget(0))); 2434 setId_Widget(addChildFlags_Widget(
2380 /* Temporary? */ { 2435 dlg,
2381 addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.newident.temp}"))); 2436 iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.newident}", NULL)),
2382 iWidget *tmpGroup = new_Widget(); 2437 frameless_WidgetFlag),
2383 setFlags_Widget(tmpGroup, arrangeSize_WidgetFlag | arrangeHorizontal_WidgetFlag, iTrue); 2438 "ident.heading");
2384 addChild_Widget(tmpGroup, iClob(makeToggle_Widget("ident.temp"))); 2439 iWidget *page = new_Widget();
2385 setId_Widget( 2440 addChildFlags_Widget(
2386 addChildFlags_Widget(tmpGroup, 2441 dlg, iClob(new_LabelWidget("${dlg.newident.rsa.selfsign}", NULL)), frameless_WidgetFlag);
2387 iClob(new_LabelWidget(uiTextCaution_ColorEscape warning_Icon 2442 /* TODO: Use makeTwoColumnWidget_? */
2388 " ${dlg.newident.notsaved}", 2443 addChild_Widget(dlg, iClob(page));
2389 NULL)), 2444 setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue);
2390 hidden_WidgetFlag | frameless_WidgetFlag), 2445 iWidget *headings = addChildFlags_Widget(
2391 "ident.temp.note"); 2446 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
2392 addChild_Widget(values, iClob(tmpGroup)); 2447 iWidget *values = addChildFlags_Widget(
2393 } 2448 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
2394 addChildFlags_Widget(headings, iClob(makePadding_Widget(gap_UI)), collapse_WidgetFlag | hidden_WidgetFlag); 2449 setId_Widget(headings, "headings");
2395 addChildFlags_Widget(values, iClob(makePadding_Widget(gap_UI)), collapse_WidgetFlag | hidden_WidgetFlag); 2450 setId_Widget(values, "values");
2396 addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.email}", "ident.email", iClob(inputs[1] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag); 2451 iInputWidget *inputs[6];
2397 addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.userid}", "ident.userid", iClob(inputs[2] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag); 2452 /* Where will the new identity be active on? */ {
2398 addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.domain}", "ident.domain", iClob(inputs[3] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag); 2453 iWidget *head = addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.newident.scope}")));
2399 addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.org}", "ident.org", iClob(inputs[4] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag); 2454 iWidget *val;
2400 addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.country}", "ident.country", iClob(inputs[5] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag); 2455 setId_Widget(
2401 arrange_Widget(dlg); 2456 addChild_Widget(values,
2402 for (size_t i = 0; i < iElemCount(inputs); ++i) { 2457 val = iClob(makeMenuButton_LabelWidget(
2403 as_Widget(inputs[i])->rect.size.x = 100 * gap_UI - headings->rect.size.x; 2458 scopeItems[0].label, scopeItems, iElemCount(scopeItems)))),
2459 "ident.scope");
2460 head->sizeRef = val;
2461 }
2462 addDialogInputWithHeading_(headings,
2463 values,
2464 "${dlg.newident.until}",
2465 "ident.until",
2466 iClob(newHint_InputWidget(19, "${hint.newident.date}")));
2467 addDialogInputWithHeading_(headings,
2468 values,
2469 "${dlg.newident.commonname}",
2470 "ident.common",
2471 iClob(inputs[0] = new_InputWidget(0)));
2472 /* Temporary? */ {
2473 addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.newident.temp}")));
2474 iWidget *tmpGroup = new_Widget();
2475 setFlags_Widget(tmpGroup, arrangeSize_WidgetFlag | arrangeHorizontal_WidgetFlag, iTrue);
2476 addChild_Widget(tmpGroup, iClob(makeToggle_Widget("ident.temp")));
2477 setId_Widget(
2478 addChildFlags_Widget(tmpGroup,
2479 iClob(new_LabelWidget(uiTextCaution_ColorEscape warning_Icon
2480 " ${dlg.newident.notsaved}",
2481 NULL)),
2482 hidden_WidgetFlag | frameless_WidgetFlag),
2483 "ident.temp.note");
2484 addChild_Widget(values, iClob(tmpGroup));
2485 }
2486 addChildFlags_Widget(headings, iClob(makePadding_Widget(gap_UI)), collapse_WidgetFlag | hidden_WidgetFlag);
2487 addChildFlags_Widget(values, iClob(makePadding_Widget(gap_UI)), collapse_WidgetFlag | hidden_WidgetFlag);
2488 addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.email}", "ident.email", iClob(inputs[1] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);
2489 addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.userid}", "ident.userid", iClob(inputs[2] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);
2490 addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.domain}", "ident.domain", iClob(inputs[3] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);
2491 addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.org}", "ident.org", iClob(inputs[4] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);
2492 addDialogInputWithHeadingAndFlags_(headings, values, "${dlg.newident.country}", "ident.country", iClob(inputs[5] = newHint_InputWidget(0, "${hint.newident.optional}")), collapse_WidgetFlag | hidden_WidgetFlag);
2493 arrange_Widget(dlg);
2494 for (size_t i = 0; i < iElemCount(inputs); ++i) {
2495 as_Widget(inputs[i])->rect.size.x = 100 * gap_UI - headings->rect.size.x;
2496 }
2497 addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, iElemCount(actions))));
2498 addChild_Widget(get_Root()->widget, iClob(dlg));
2499 finalizeSheet_Mobile(dlg);
2404 } 2500 }
2405 addChild_Widget(dlg,
2406 iClob(makeDialogButtons_Widget(
2407 (iMenuItem[]){ { "${dlg.newident.more}", 0, 0, "ident.showmore" },
2408 { "---" },
2409 { "${cancel}", SDLK_ESCAPE, 0, "ident.cancel" },
2410 { uiTextAction_ColorEscape "${dlg.newident.create}",
2411 SDLK_RETURN,
2412 KMOD_PRIMARY,
2413 "ident.accept" } },
2414 4)));
2415 addChild_Widget(get_Root()->widget, iClob(dlg));
2416 finalizeSheet_Mobile(dlg);
2417 return dlg; 2501 return dlg;
2418} 2502}
2419 2503
diff --git a/src/ui/util.h b/src/ui/util.h
index 87b72394..0dff8978 100644
--- a/src/ui/util.h
+++ b/src/ui/util.h
@@ -242,7 +242,8 @@ int checkContextMenu_Widget (iWidget *, const SDL_Event *ev); /* see mac
242 break; \ 242 break; \
243 } 243 }
244 244
245iLabelWidget * makeMenuButton_LabelWidget (const char *label, const iMenuItem *items, size_t n); 245iLabelWidget * makeMenuButton_LabelWidget (const char *label, const iMenuItem *items, size_t n);
246void updateDropdownSelection_LabelWidget (iLabelWidget *dropButton, const char *selectedCommand);
246 247
247/*-----------------------------------------------------------------------------------------------*/ 248/*-----------------------------------------------------------------------------------------------*/
248 249