summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-03-05 13:14:02 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-03-05 13:15:20 +0200
commit71f3f34782aa6050ede4bf143fa6028653adae6d (patch)
tree1465b155b6c99ca48596263c2929da48b8795e23
parent8417c4fb637351587e1527b94c69b752d9988323 (diff)
Restructuring dialogs for mobile
On a phone, dialogs are restructured to be more vertical and full-width.
m---------lib/the_Foundation0
-rw-r--r--src/app.c10
-rw-r--r--src/ui/inputwidget.c5
-rw-r--r--src/ui/util.c130
-rw-r--r--src/ui/util.h2
5 files changed, 129 insertions, 18 deletions
diff --git a/lib/the_Foundation b/lib/the_Foundation
Subproject 7784fb08a3d99b629545cc852f7869bd470646d Subproject 0b40f677e2c738a0cede4d4a4bc5849f9fa0e5c
diff --git a/src/app.c b/src/app.c
index 3b62cd87..a7539203 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1231,8 +1231,10 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
1231 postCommandf_App("proxy.http address:%s", 1231 postCommandf_App("proxy.http address:%s",
1232 cstr_String(text_InputWidget(findChild_Widget(d, "prefs.proxy.http")))); 1232 cstr_String(text_InputWidget(findChild_Widget(d, "prefs.proxy.http"))));
1233 const iWidget *tabs = findChild_Widget(d, "prefs.tabs"); 1233 const iWidget *tabs = findChild_Widget(d, "prefs.tabs");
1234 postCommandf_App("prefs.dialogtab arg:%u", 1234 if (tabs) {
1235 tabPageIndex_Widget(tabs, currentTabPage_Widget(tabs))); 1235 postCommandf_App("prefs.dialogtab arg:%u",
1236 tabPageIndex_Widget(tabs, currentTabPage_Widget(tabs)));
1237 }
1236 destroy_Widget(d); 1238 destroy_Widget(d);
1237 postCommand_App("prefs.changed"); 1239 postCommand_App("prefs.changed");
1238 return iTrue; 1240 return iTrue;
@@ -1800,7 +1802,9 @@ iBool handleCommand_App(const char *cmd) {
1800 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gopher"), &d->prefs.gopherProxy); 1802 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gopher"), &d->prefs.gopherProxy);
1801 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.http"), &d->prefs.httpProxy); 1803 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.http"), &d->prefs.httpProxy);
1802 iWidget *tabs = findChild_Widget(dlg, "prefs.tabs"); 1804 iWidget *tabs = findChild_Widget(dlg, "prefs.tabs");
1803 showTabPage_Widget(tabs, tabPage_Widget(tabs, d->prefs.dialogTab)); 1805 if (tabs) {
1806 showTabPage_Widget(tabs, tabPage_Widget(tabs, d->prefs.dialogTab));
1807 }
1804 setCommandHandler_Widget(dlg, handlePrefsCommands_); 1808 setCommandHandler_Widget(dlg, handlePrefsCommands_);
1805 } 1809 }
1806 else if (equal_Command(cmd, "navigate.home")) { 1810 else if (equal_Command(cmd, "navigate.home")) {
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index 4b5cd623..11ea0674 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -193,7 +193,10 @@ void setMode_InputWidget(iInputWidget *d, enum iInputMode mode) {
193} 193}
194 194
195const iString *text_InputWidget(const iInputWidget *d) { 195const iString *text_InputWidget(const iInputWidget *d) {
196 return collect_String(newUnicodeN_String(constData_Array(&d->text), size_Array(&d->text))); 196 if (d) {
197 return collect_String(newUnicodeN_String(constData_Array(&d->text), size_Array(&d->text)));
198 }
199 return collectNew_String();
197} 200}
198 201
199void setMaxLen_InputWidget(iInputWidget *d, size_t maxLen) { 202void setMaxLen_InputWidget(iInputWidget *d, size_t maxLen) {
diff --git a/src/ui/util.c b/src/ui/util.c
index a36eb1a7..e8bb95d8 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -500,7 +500,8 @@ iWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) {
500 } 500 }
501 } 501 }
502 } 502 }
503 addChild_Widget(parent, iClob(menu)); 503 addChild_Widget(parent, menu);
504 iRelease(menu); /* owned by parent now */
504 setCommandHandler_Widget(menu, menuHandler_); 505 setCommandHandler_Widget(menu, menuHandler_);
505 iWidget *cancel = addAction_Widget(menu, SDLK_ESCAPE, 0, "cancel"); 506 iWidget *cancel = addAction_Widget(menu, SDLK_ESCAPE, 0, "cancel");
506 setId_Widget(cancel, "menu.cancel"); 507 setId_Widget(cancel, "menu.cancel");
@@ -756,6 +757,9 @@ iLabelWidget *tabButtonForPage_Widget_(iWidget *tabs, const iWidget *page) {
756} 757}
757 758
758void showTabPage_Widget(iWidget *tabs, const iWidget *page) { 759void showTabPage_Widget(iWidget *tabs, const iWidget *page) {
760 if (!page) {
761 return;
762 }
759 /* Select the corresponding button. */ { 763 /* Select the corresponding button. */ {
760 iWidget *buttons = findChild_Widget(tabs, "tabs.buttons"); 764 iWidget *buttons = findChild_Widget(tabs, "tabs.buttons");
761 iForEach(ObjectList, i, buttons->children) { 765 iForEach(ObjectList, i, buttons->children) {
@@ -870,8 +874,107 @@ iWidget *makeSheet_Widget(const char *id) {
870 return sheet; 874 return sheet;
871} 875}
872 876
873void centerSheet_Widget(iWidget *sheet) { 877static iBool isTwoColumnPage_(iWidget *d) {
874 arrange_Widget(sheet); 878 if (class_Widget(d) == &Class_Widget && childCount_Widget(d) == 2) {
879 return class_Widget(child_Widget(d, 0)) == &Class_Widget &&
880 class_Widget(child_Widget(d, 1)) == &Class_Widget;
881 }
882 return iFalse;
883}
884
885void finalizeSheet_Widget(iWidget *sheet) {
886 if (deviceType_App() == phone_AppDeviceType) {
887 /* The sheet contents are completely rearranged on a phone. We'll set up a linear
888 fullscreen arrangement of the widgets. Sheets are already scrollable so they
889 can be taller than the display. */
890#if defined (iPlatformAppleMobile)
891 /* Safe area insets. */ {
892 /* TODO: Must be updated when orientation changes; use a widget flag? */
893 float l, t, r, b;
894 safeAreaInsets_iOS(&l, &t, &r, &b);
895 setPadding_Widget(sheet, l, t, r, b);
896 }
897#endif
898 setFlags_Widget(sheet,
899 parentCannotResize_WidgetFlag | arrangeWidth_WidgetFlag |
900 centerHorizontal_WidgetFlag,
901 iFalse);
902 setFlags_Widget(sheet, frameless_WidgetFlag | resizeWidthOfChildren_WidgetFlag, iTrue);
903 iPtrArray *contents = collect_PtrArray(new_PtrArray()); /* two-column pages */
904 iWidget *tabs = findChild_Widget(sheet, "prefs.tabs");
905 if (tabs) {
906 /* Pull out the pages and make them sequential. */
907 iWidget *pages = findChild_Widget(tabs, "tabs.pages");
908 size_t pageCount = tabCount_Widget(tabs);
909 for (size_t i = 0; i < pageCount; i++) {
910 iWidget *page = removeTabPage_Widget(tabs, 0);
911 iWidget *pageContent = child_Widget(page, 1); /* surrounded by padding widgets */
912 pushBack_PtrArray(contents, ref_Object(pageContent));
913 iRelease(page);
914 }
915 destroy_Widget(tabs);
916 }
917 else {
918 iForEach(ObjectList, i, children_Widget(sheet)) {
919 iWidget *child = i.object;
920 if (isTwoColumnPage_(child)) {
921 pushBack_PtrArray(contents, removeChild_Widget(sheet, child));
922 }
923 }
924 }
925 iForEach(PtrArray, j, contents) {
926 iWidget *pageContent = j.ptr;
927 iWidget *headings = child_Widget(pageContent, 0);
928 iWidget *values = child_Widget(pageContent, 1);
929 while (!isEmpty_ObjectList(children_Widget(headings))) {
930 iWidget *heading = child_Widget(headings, 0);
931 iWidget *value = child_Widget(values, 0);
932 removeChild_Widget(headings, heading);
933 removeChild_Widget(values, value);
934 iLabelWidget *valueLabel = NULL;
935 if (isInstance_Object(value, &Class_LabelWidget)) {
936 valueLabel = (iLabelWidget *) value;
937 }
938 /* Toggles have the button on the right. */
939 if (valueLabel && cmp_String(command_LabelWidget(valueLabel), "toggle") == 0) {
940 iWidget *div = new_Widget();
941 addChildFlags_Widget(div, iClob(heading), 0);
942 addChildFlags_Widget(div, iClob(new_Widget()), expand_WidgetFlag);
943 addChild_Widget(div, iClob(value));
944 addChildFlags_Widget(sheet,
945 iClob(div),
946 arrangeHeight_WidgetFlag |
947 resizeWidthOfChildren_WidgetFlag |
948 arrangeHorizontal_WidgetFlag);
949 }
950 else {
951 if (valueLabel && isEmpty_String(text_LabelWidget(valueLabel))) {
952 /* Subheading padding goes above. */
953 addChild_Widget(sheet, iClob(value));
954 addChild_Widget(sheet, iClob(heading));
955 }
956 else {
957 addChild_Widget(sheet, iClob(heading));
958 addChild_Widget(sheet, iClob(value));
959 /* Align radio buttons to the right. */
960 if (childCount_Widget(value)) {
961 setFlags_Widget(value,
962 resizeToParentWidth_WidgetFlag |
963 resizeWidthOfChildren_WidgetFlag,
964 iTrue);
965 }
966 }
967 }
968 }
969 destroy_Widget(pageContent);
970 }
971 destroyPending_Widget();
972 arrange_Widget(sheet->parent);
973 printTree_Widget(sheet);
974 }
975 else {
976 arrange_Widget(sheet);
977 }
875 postRefresh_App(); 978 postRefresh_App();
876} 979}
877 980
@@ -899,7 +1002,7 @@ void makeFilePath_Widget(iWidget * parent,
899 addChild_Widget(div, iClob(newKeyMods_LabelWidget(acceptLabel, SDLK_RETURN, 0, "filepath.accept"))); 1002 addChild_Widget(div, iClob(newKeyMods_LabelWidget(acceptLabel, SDLK_RETURN, 0, "filepath.accept")));
900 } 1003 }
901 addChild_Widget(dlg, iClob(div)); 1004 addChild_Widget(dlg, iClob(div));
902 centerSheet_Widget(dlg); 1005 finalizeSheet_Widget(dlg);
903 setFocus_Widget(as_Widget(input)); 1006 setFocus_Widget(as_Widget(input));
904} 1007}
905 1008
@@ -920,7 +1023,7 @@ static void updateValueInputWidth_(iWidget *dlg) {
920 iWidget * prompt = findChild_Widget(dlg, "valueinput.prompt"); 1023 iWidget * prompt = findChild_Widget(dlg, "valueinput.prompt");
921 dlg->rect.size.x = iMaxi(iMaxi(rootSize.x / 2, title->rect.size.x), prompt->rect.size.x); 1024 dlg->rect.size.x = iMaxi(iMaxi(rootSize.x / 2, title->rect.size.x), prompt->rect.size.x);
922 as_Widget(findChild_Widget(dlg, "input"))->rect.size.x = dlg->rect.size.x; 1025 as_Widget(findChild_Widget(dlg, "input"))->rect.size.x = dlg->rect.size.x;
923 centerSheet_Widget(dlg); 1026 finalizeSheet_Widget(dlg);
924} 1027}
925 1028
926iBool valueInputHandler_(iWidget *dlg, const char *cmd) { 1029iBool valueInputHandler_(iWidget *dlg, const char *cmd) {
@@ -1039,7 +1142,7 @@ iWidget *makeValueInput_Widget(iWidget *parent, const iString *initialValue, con
1039 iClob(makeDialogButtons_Widget( 1142 iClob(makeDialogButtons_Widget(
1040 (iMenuItem[]){ { "Cancel", 0, 0, NULL }, { acceptLabel, 0, 0, "valueinput.accept" } }, 1143 (iMenuItem[]){ { "Cancel", 0, 0, NULL }, { acceptLabel, 0, 0, "valueinput.accept" } },
1041 2))); 1144 2)));
1042 centerSheet_Widget(dlg); 1145 finalizeSheet_Widget(dlg);
1043 if (parent) { 1146 if (parent) {
1044 setFocus_Widget(as_Widget(input)); 1147 setFocus_Widget(as_Widget(input));
1045 } 1148 }
@@ -1086,7 +1189,7 @@ iWidget *makeQuestion_Widget(const char *title, const char *msg,
1086 addChild_Widget(get_Window()->root, iClob(dlg)); 1189 addChild_Widget(get_Window()->root, iClob(dlg));
1087 arrange_Widget(dlg); /* BUG: This extra arrange shouldn't be needed but the dialog won't 1190 arrange_Widget(dlg); /* BUG: This extra arrange shouldn't be needed but the dialog won't
1088 be arranged correctly unless it's here. */ 1191 be arranged correctly unless it's here. */
1089 centerSheet_Widget(dlg); 1192 finalizeSheet_Widget(dlg);
1090 return dlg; 1193 return dlg;
1091} 1194}
1092 1195
@@ -1148,7 +1251,7 @@ static iWidget *appendTwoColumnPage_(iWidget *tabs, const char *title, int short
1148 *values = addChildFlags_Widget( 1251 *values = addChildFlags_Widget(
1149 columns, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); 1252 columns, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
1150 addChildFlags_Widget(page, iClob(new_Widget()), expand_WidgetFlag); 1253 addChildFlags_Widget(page, iClob(new_Widget()), expand_WidgetFlag);
1151 appendFramelessTabPage_(tabs, page, title, shortcut, shortcut ? KMOD_PRIMARY : 0); 1254 appendFramelessTabPage_(tabs, iClob(page), title, shortcut, shortcut ? KMOD_PRIMARY : 0);
1152 return page; 1255 return page;
1153} 1256}
1154 1257
@@ -1349,7 +1452,8 @@ iWidget *makePreferences_Widget(void) {
1349 addChild_Widget(headings, iClob(makeHeading_Widget("HTTP proxy:"))); 1452 addChild_Widget(headings, iClob(makeHeading_Widget("HTTP proxy:")));
1350 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.http"); 1453 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.http");
1351 } 1454 }
1352 /* Keybindings. */ { 1455 /* Keybindings. */
1456 if (deviceType_App() == desktop_AppDeviceType) {
1353 iBindingsWidget *bind = new_BindingsWidget(); 1457 iBindingsWidget *bind = new_BindingsWidget();
1354 setFlags_Widget(as_Widget(bind), borderTop_WidgetFlag, iTrue); 1458 setFlags_Widget(as_Widget(bind), borderTop_WidgetFlag, iTrue);
1355 appendFramelessTabPage_(tabs, iClob(bind), "Keys", '6', KMOD_PRIMARY); 1459 appendFramelessTabPage_(tabs, iClob(bind), "Keys", '6', KMOD_PRIMARY);
@@ -1370,7 +1474,7 @@ iWidget *makePreferences_Widget(void) {
1370 iClob(makeDialogButtons_Widget( 1474 iClob(makeDialogButtons_Widget(
1371 (iMenuItem[]){ { "Dismiss", SDLK_ESCAPE, 0, "prefs.dismiss" } }, 1))); 1475 (iMenuItem[]){ { "Dismiss", SDLK_ESCAPE, 0, "prefs.dismiss" } }, 1)));
1372 addChild_Widget(get_Window()->root, iClob(dlg)); 1476 addChild_Widget(get_Window()->root, iClob(dlg));
1373 centerSheet_Widget(dlg); 1477 finalizeSheet_Widget(dlg);
1374 return dlg; 1478 return dlg;
1375} 1479}
1376 1480
@@ -1411,7 +1515,7 @@ iWidget *makeBookmarkEditor_Widget(void) {
1411 "bmed.accept" } }, 1515 "bmed.accept" } },
1412 2))); 1516 2)));
1413 addChild_Widget(get_Window()->root, iClob(dlg)); 1517 addChild_Widget(get_Window()->root, iClob(dlg));
1414 centerSheet_Widget(dlg); 1518 finalizeSheet_Widget(dlg);
1415 return dlg; 1519 return dlg;
1416} 1520}
1417 1521
@@ -1550,7 +1654,7 @@ iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {
1550 arrange_Widget(dlg); 1654 arrange_Widget(dlg);
1551 as_Widget(input)->rect.size.x = 100 * gap_UI - headings->rect.size.x; 1655 as_Widget(input)->rect.size.x = 100 * gap_UI - headings->rect.size.x;
1552 addChild_Widget(get_Window()->root, iClob(dlg)); 1656 addChild_Widget(get_Window()->root, iClob(dlg));
1553 centerSheet_Widget(dlg); 1657 finalizeSheet_Widget(dlg);
1554 /* Initialize. */ { 1658 /* Initialize. */ {
1555 const iBookmark *bm = bookmarkId ? get_Bookmarks(bookmarks_App(), bookmarkId) : NULL; 1659 const iBookmark *bm = bookmarkId ? get_Bookmarks(bookmarks_App(), bookmarkId) : NULL;
1556 setText_InputWidget(findChild_Widget(dlg, "feedcfg.title"), 1660 setText_InputWidget(findChild_Widget(dlg, "feedcfg.title"),
@@ -1627,6 +1731,6 @@ iWidget *makeIdentityCreation_Widget(void) {
1627 "ident.accept" } }, 1731 "ident.accept" } },
1628 2))); 1732 2)));
1629 addChild_Widget(get_Window()->root, iClob(dlg)); 1733 addChild_Widget(get_Window()->root, iClob(dlg));
1630 centerSheet_Widget(dlg); 1734 finalizeSheet_Widget(dlg);
1631 return dlg; 1735 return dlg;
1632} 1736}
diff --git a/src/ui/util.h b/src/ui/util.h
index 40fd0c69..122cbb97 100644
--- a/src/ui/util.h
+++ b/src/ui/util.h
@@ -193,7 +193,7 @@ size_t tabCount_Widget (const iWidget *tabs);
193/*-----------------------------------------------------------------------------------------------*/ 193/*-----------------------------------------------------------------------------------------------*/
194 194
195iWidget * makeSheet_Widget (const char *id); 195iWidget * makeSheet_Widget (const char *id);
196void centerSheet_Widget (iWidget *sheet); 196void finalizeSheet_Widget (iWidget *sheet);
197iWidget * makeDialogButtons_Widget(const iMenuItem *actions, size_t numActions); 197iWidget * makeDialogButtons_Widget(const iMenuItem *actions, size_t numActions);
198 198
199void makeFilePath_Widget (iWidget *parent, const iString *initialPath, const char *title, 199void makeFilePath_Widget (iWidget *parent, const iString *initialPath, const char *title,