summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-09-11 07:43:57 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-09-11 07:43:57 +0300
commit1410bbde7779efe3a20f603523547c8b8f55b6a1 (patch)
tree54e8ab43ea6d3dc35d7993b6909096c6c8429e50
parent61c23be799956615ceeeda10aaeccc2bb11e9c94 (diff)
Mobile: Many UI improvements; Upload UI
-rw-r--r--po/en.po22
-rw-r--r--res/lang/de.binbin24008 -> 24162 bytes
-rw-r--r--res/lang/en.binbin22609 -> 22763 bytes
-rw-r--r--res/lang/es.binbin25135 -> 25286 bytes
-rw-r--r--res/lang/fi.binbin25140 -> 25291 bytes
-rw-r--r--res/lang/fr.binbin26109 -> 26260 bytes
-rw-r--r--res/lang/ia.binbin24736 -> 24890 bytes
-rw-r--r--res/lang/ie.binbin24494 -> 24645 bytes
-rw-r--r--res/lang/pl.binbin25669 -> 25823 bytes
-rw-r--r--res/lang/ru.binbin37391 -> 37542 bytes
-rw-r--r--res/lang/sr.binbin37048 -> 37199 bytes
-rw-r--r--res/lang/tok.binbin22930 -> 23081 bytes
-rw-r--r--res/lang/zh_Hans.binbin21688 -> 21842 bytes
-rw-r--r--res/lang/zh_Hant.binbin21873 -> 22027 bytes
-rw-r--r--src/app.c7
-rw-r--r--src/ui/certimportwidget.c120
-rw-r--r--src/ui/documentwidget.c9
-rw-r--r--src/ui/labelwidget.c17
-rw-r--r--src/ui/mobile.c134
-rw-r--r--src/ui/mobile.h19
-rw-r--r--src/ui/root.c10
-rw-r--r--src/ui/uploadwidget.c188
-rw-r--r--src/ui/util.c15
-rw-r--r--src/ui/widget.c4
24 files changed, 349 insertions, 196 deletions
diff --git a/po/en.po b/po/en.po
index dd3af388..546a9489 100644
--- a/po/en.po
+++ b/po/en.po
@@ -251,6 +251,10 @@ msgstr "Show Feed Entries"
251msgid "menu.preferences" 251msgid "menu.preferences"
252msgstr "Preferences…" 252msgstr "Preferences…"
253 253
254# used for Preferences on mobile
255msgid "menu.settings"
256msgstr "Settings…"
257
254msgid "menu.help" 258msgid "menu.help"
255msgstr "Help" 259msgstr "Help"
256 260
@@ -906,7 +910,7 @@ msgid "heading.lookup.other"
906msgstr "OTHER" 910msgstr "OTHER"
907 911
908msgid "menu.page.upload" 912msgid "menu.page.upload"
909msgstr "Upload Page with Titan" 913msgstr "Upload Page with Titan"
910 914
911msgid "heading.upload" 915msgid "heading.upload"
912msgstr "UPLOAD WITH TITAN" 916msgstr "UPLOAD WITH TITAN"
@@ -953,6 +957,18 @@ msgstr "Set the Titan server port to use for this URL.\nThe port is saved in the
953msgid "dlg.uploadport.set" 957msgid "dlg.uploadport.set"
954msgstr "Set Port" 958msgstr "Set Port"
955 959
960# used on mobile
961msgid "dlg.upload.text"
962msgstr "Upload Plain Text"
963
964# used on mobile
965msgid "dlg.upload.file"
966msgstr "Upload a File"
967
968# used on mobile
969msgid "dlg.upload.pickfile"
970msgstr "Select File…"
971
956msgid "heading.translate" 972msgid "heading.translate"
957msgstr "TRANSLATE PAGE" 973msgstr "TRANSLATE PAGE"
958 974
@@ -1151,6 +1167,10 @@ msgstr "SPECIAL TAGS"
1151msgid "heading.prefs" 1167msgid "heading.prefs"
1152msgstr "PREFERENCES" 1168msgstr "PREFERENCES"
1153 1169
1170# used on mobile
1171msgid "heading.settings"
1172msgstr "SETTINGS"
1173
1154msgid "heading.prefs.certs" 1174msgid "heading.prefs.certs"
1155msgstr "CERTIFICATES" 1175msgstr "CERTIFICATES"
1156 1176
diff --git a/res/lang/de.bin b/res/lang/de.bin
index 9d87657f..ba87d002 100644
--- a/res/lang/de.bin
+++ b/res/lang/de.bin
Binary files differ
diff --git a/res/lang/en.bin b/res/lang/en.bin
index 9fe4cfb3..a7dfb866 100644
--- a/res/lang/en.bin
+++ b/res/lang/en.bin
Binary files differ
diff --git a/res/lang/es.bin b/res/lang/es.bin
index 1effaf3d..7e7398d6 100644
--- a/res/lang/es.bin
+++ b/res/lang/es.bin
Binary files differ
diff --git a/res/lang/fi.bin b/res/lang/fi.bin
index fcaa8cc6..607e52fd 100644
--- a/res/lang/fi.bin
+++ b/res/lang/fi.bin
Binary files differ
diff --git a/res/lang/fr.bin b/res/lang/fr.bin
index 32104f44..955695ed 100644
--- a/res/lang/fr.bin
+++ b/res/lang/fr.bin
Binary files differ
diff --git a/res/lang/ia.bin b/res/lang/ia.bin
index 5b64a182..61a18efc 100644
--- a/res/lang/ia.bin
+++ b/res/lang/ia.bin
Binary files differ
diff --git a/res/lang/ie.bin b/res/lang/ie.bin
index 6d568972..06ea7979 100644
--- a/res/lang/ie.bin
+++ b/res/lang/ie.bin
Binary files differ
diff --git a/res/lang/pl.bin b/res/lang/pl.bin
index 69ad06f8..5fc5e24a 100644
--- a/res/lang/pl.bin
+++ b/res/lang/pl.bin
Binary files differ
diff --git a/res/lang/ru.bin b/res/lang/ru.bin
index 67babbcd..1718f647 100644
--- a/res/lang/ru.bin
+++ b/res/lang/ru.bin
Binary files differ
diff --git a/res/lang/sr.bin b/res/lang/sr.bin
index a7f7639b..60b7b600 100644
--- a/res/lang/sr.bin
+++ b/res/lang/sr.bin
Binary files differ
diff --git a/res/lang/tok.bin b/res/lang/tok.bin
index b7476101..3298f0e8 100644
--- a/res/lang/tok.bin
+++ b/res/lang/tok.bin
Binary files differ
diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin
index 03eb8b43..8c32a0c5 100644
--- a/res/lang/zh_Hans.bin
+++ b/res/lang/zh_Hans.bin
Binary files differ
diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin
index c0378db8..68f7d3bc 100644
--- a/res/lang/zh_Hant.bin
+++ b/res/lang/zh_Hant.bin
Binary files differ
diff --git a/src/app.c b/src/app.c
index a52552c0..e597edbe 100644
--- a/src/app.c
+++ b/src/app.c
@@ -2382,7 +2382,8 @@ iBool handleCommand_App(const char *cmd) {
2382 setUrl_UploadWidget(upload, url); 2382 setUrl_UploadWidget(upload, url);
2383 setResponseViewer_UploadWidget(upload, document_App()); 2383 setResponseViewer_UploadWidget(upload, document_App());
2384 addChild_Widget(get_Root()->widget, iClob(upload)); 2384 addChild_Widget(get_Root()->widget, iClob(upload));
2385 finalizeSheet_Mobile(as_Widget(upload)); 2385// finalizeSheet_Mobile(as_Widget(upload));
2386 setupSheetTransition_Mobile(as_Widget(upload), iTrue);
2386 postRefresh_App(); 2387 postRefresh_App();
2387 return iTrue; 2388 return iTrue;
2388 } 2389 }
@@ -2761,7 +2762,9 @@ iBool handleCommand_App(const char *cmd) {
2761 iCertImportWidget *imp = new_CertImportWidget(); 2762 iCertImportWidget *imp = new_CertImportWidget();
2762 setPageContent_CertImportWidget(imp, sourceContent_DocumentWidget(document_App())); 2763 setPageContent_CertImportWidget(imp, sourceContent_DocumentWidget(document_App()));
2763 addChild_Widget(get_Root()->widget, iClob(imp)); 2764 addChild_Widget(get_Root()->widget, iClob(imp));
2764 finalizeSheet_Mobile(as_Widget(imp)); 2765// finalizeSheet_Mobile(as_Widget(imp));
2766 arrange_Widget(as_Widget(imp));
2767 setupSheetTransition_Mobile(as_Widget(imp), iTrue);
2765 postRefresh_App(); 2768 postRefresh_App();
2766 return iTrue; 2769 return iTrue;
2767 } 2770 }
diff --git a/src/ui/certimportwidget.c b/src/ui/certimportwidget.c
index 2e60c71f..65cb6654 100644
--- a/src/ui/certimportwidget.c
+++ b/src/ui/certimportwidget.c
@@ -104,61 +104,83 @@ static iBool tryImport_CertImportWidget_(iCertImportWidget *d, const iBlock *dat
104 104
105void init_CertImportWidget(iCertImportWidget *d) { 105void init_CertImportWidget(iCertImportWidget *d) {
106 iWidget *w = as_Widget(d); 106 iWidget *w = as_Widget(d);
107 const iMenuItem actions[] = {
108#if defined (iPlatformAppleMobile)
109 { "${dlg.certimport.pickfile}", 0, 0, "certimport.pickfile" },
110 { "---" },
111#endif
112 { "${cancel}" },
113 { uiTextAction_ColorEscape "${dlg.certimport.import}",
114 SDLK_RETURN, KMOD_PRIMARY,
115 "certimport.accept" }
116 };
107 init_Widget(w); 117 init_Widget(w);
108 setId_Widget(w, "certimport"); 118 setId_Widget(w, "certimport");
109 d->cert = NULL; 119 d->cert = NULL;
110 /* This should behave similar to sheets. */ 120 if (isUsingPanelLayout_Mobile()) {
111 useSheetStyle_Widget(w); 121 initPanels_Mobile(w, NULL, (iMenuItem[]){
112 addChildFlags_Widget( 122 { "title id:heading.certimport" },
113 w, 123 { format_CStr("label id:certimport.info text:%s", infoText_) },
114 iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.certimport}", NULL)), 124 //{ "padding" },
115 frameless_WidgetFlag); 125 { "label id:certimport.crt nowrap:1 frame:1" },
116 d->info = addChildFlags_Widget(w, iClob(new_LabelWidget(infoText_, NULL)), frameless_WidgetFlag); 126 { "padding arg:0.25" },
117 addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); 127 { "label id:certimport.key nowrap:1 frame:1" },
118 d->crtLabel = new_LabelWidget("", NULL); { 128 { "heading text:${dlg.certimport.notes}" },
119 setFont_LabelWidget(d->crtLabel, uiContent_FontId); 129 { "input id:certimport.notes hint:hint.certimport.description noheading:1" },
120 addChildFlags_Widget(w, iClob(d->crtLabel), 0); 130 { NULL }
121 setFrameColor_Widget(as_Widget(d->crtLabel), uiTextCaution_ColorId); 131 }, actions, iElemCount(actions));
132 d->info = findChild_Widget(w, "certimport.info");
133 d->crtLabel = findChild_Widget(w, "certimport.crt");
134 d->keyLabel = findChild_Widget(w, "certimport.key");
135 d->notes = findChild_Widget(w, "certimport.notes");
136 setFixedSize_Widget(as_Widget(d->crtLabel), init_I2(-1, gap_UI * 12));
137 setFixedSize_Widget(as_Widget(d->keyLabel), init_I2(-1, gap_UI * 12));
122 } 138 }
123 d->keyLabel = new_LabelWidget("", NULL); { 139 else {
124 setFont_LabelWidget(d->keyLabel, uiContent_FontId); 140 /* This should behave similar to sheets. */
141 useSheetStyle_Widget(w);
142 addChildFlags_Widget(
143 w,
144 iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.certimport}", NULL)),
145 frameless_WidgetFlag);
146 d->info = addChildFlags_Widget(w, iClob(new_LabelWidget(infoText_, NULL)), frameless_WidgetFlag);
125 addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); 147 addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));
126 addChildFlags_Widget(w, iClob(d->keyLabel), 0); 148 d->crtLabel = new_LabelWidget("", NULL); {
127 setFrameColor_Widget(as_Widget(d->keyLabel), uiTextCaution_ColorId); 149 setFont_LabelWidget(d->crtLabel, uiContent_FontId);
128 } 150 addChildFlags_Widget(w, iClob(d->crtLabel), 0);
129 addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); 151 }
130 /* TODO: Use makeTwoColumnWidget_() */ 152 d->keyLabel = new_LabelWidget("", NULL); {
131 iWidget *page = new_Widget(); { 153 setFont_LabelWidget(d->keyLabel, uiContent_FontId);
132 setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue); 154 addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));
133 iWidget *headings = addChildFlags_Widget( 155 addChildFlags_Widget(w, iClob(d->keyLabel), 0);
134 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); 156 }
135 iWidget *values = addChildFlags_Widget( 157 addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));
136 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); 158 /* TODO: Use makeTwoColumnWidget_() */
137// addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.certimport.notes}"))); 159 iWidget *page = new_Widget(); {
138// addChild_Widget(values, iClob(d->notes = new_InputWidget(0))); 160 setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue);
139// setHint_InputWidget(d->notes, "${hint.certimport.description}"); 161 iWidget *headings = addChildFlags_Widget(
140 addTwoColumnDialogInputField_Widget( 162 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
141 headings, 163 iWidget *values = addChildFlags_Widget(
142 values, 164 page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag);
143 "${dlg.certimport.notes}", 165 addTwoColumnDialogInputField_Widget(
144 "", 166 headings,
145 iClob(d->notes = newHint_InputWidget(0, "${hint.certimport.description}"))); 167 values,
146 as_Widget(d->notes)->rect.size.x = gap_UI * 70; 168 "${dlg.certimport.notes}",
169 "",
170 iClob(d->notes = newHint_InputWidget(0, "${hint.certimport.description}")));
171 as_Widget(d->notes)->rect.size.x = gap_UI * 70;
172 }
173 addChild_Widget(w, iClob(page));
174 arrange_Widget(w);
175 setFixedSize_Widget(as_Widget(d->crtLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12));
176 setFixedSize_Widget(as_Widget(d->keyLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12));
177 /* Buttons. */
178 addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));
179 iWidget *buttons = makeDialogButtons_Widget(actions, iElemCount(actions));
180 addChild_Widget(w, iClob(buttons));
147 } 181 }
148 addChild_Widget(w, iClob(page)); 182 setFrameColor_Widget(as_Widget(d->crtLabel), uiTextCaution_ColorId);
149 arrange_Widget(w); 183 setFrameColor_Widget(as_Widget(d->keyLabel), uiTextCaution_ColorId);
150 setFixedSize_Widget(as_Widget(d->crtLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12));
151 setFixedSize_Widget(as_Widget(d->keyLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12));
152 /* Buttons. */
153 addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));
154 iWidget *buttons = makeDialogButtons_Widget(
155 (iMenuItem[]){ { "${cancel}" },
156 { uiTextAction_ColorEscape "${dlg.certimport.import}",
157 SDLK_RETURN,
158 KMOD_PRIMARY,
159 "certimport.accept" } },
160 2);
161 addChild_Widget(w, iClob(buttons));
162 if (deviceType_App() != desktop_AppDeviceType) { 184 if (deviceType_App() != desktop_AppDeviceType) {
163 /* Try auto-pasting. */ 185 /* Try auto-pasting. */
164 postCommand_App("certimport.paste"); 186 postCommand_App("certimport.paste");
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 83f2ea6a..4b3c2db0 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -2852,7 +2852,8 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2852 setUrl_UploadWidget(upload, d->mod.url); 2852 setUrl_UploadWidget(upload, d->mod.url);
2853 setResponseViewer_UploadWidget(upload, d); 2853 setResponseViewer_UploadWidget(upload, d);
2854 addChild_Widget(get_Root()->widget, iClob(upload)); 2854 addChild_Widget(get_Root()->widget, iClob(upload));
2855 finalizeSheet_Mobile(as_Widget(upload)); 2855// finalizeSheet_Mobile(as_Widget(upload));
2856 setupSheetTransition_Mobile(as_Widget(upload), iTrue);
2856 postRefresh_App(); 2857 postRefresh_App();
2857 } 2858 }
2858 return iTrue; 2859 return iTrue;
@@ -3679,16 +3680,10 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
3679 { "---" }, 3680 { "---" },
3680 { book_Icon " ${menu.page.import}", 0, 0, "bookmark.links confirm:1" }, 3681 { book_Icon " ${menu.page.import}", 0, 0, "bookmark.links confirm:1" },
3681 { globe_Icon " ${menu.page.translate}", 0, 0, "document.translate" }, 3682 { globe_Icon " ${menu.page.translate}", 0, 0, "document.translate" },
3682#if defined (iPlatformMobile)
3683 { "---" },
3684 { "${menu.page.copyurl}", 0, 0, "document.copylink" } },
3685 14);
3686#else
3687 { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" }, 3683 { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" },
3688 { "---" }, 3684 { "---" },
3689 { "${menu.page.copyurl}", 0, 0, "document.copylink" } }, 3685 { "${menu.page.copyurl}", 0, 0, "document.copylink" } },
3690 15); 3686 15);
3691#endif
3692 if (isEmpty_Range(&d->selectMark)) { 3687 if (isEmpty_Range(&d->selectMark)) {
3693 pushBackN_Array( 3688 pushBackN_Array(
3694 &items, 3689 &items,
diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c
index 03595d1a..ec324d02 100644
--- a/src/ui/labelwidget.c
+++ b/src/ui/labelwidget.c
@@ -244,6 +244,9 @@ static void getColors_LabelWidget_(const iLabelWidget *d, int *bg, int *fg, int
244 } 244 }
245 } 245 }
246 } 246 }
247 if (d->forceFg >= 0) {
248 *fg = d->forceFg;
249 }
247 if (isPress) { 250 if (isPress) {
248 *bg = uiBackgroundPressed_ColorId | permanent_ColorId; 251 *bg = uiBackgroundPressed_ColorId | permanent_ColorId;
249 if (isButton) { 252 if (isButton) {
@@ -257,9 +260,6 @@ static void getColors_LabelWidget_(const iLabelWidget *d, int *bg, int *fg, int
257 *fg = isDark_ColorTheme(colorTheme_App()) ? white_ColorId : black_ColorId; 260 *fg = isDark_ColorTheme(colorTheme_App()) ? white_ColorId : black_ColorId;
258 } 261 }
259 } 262 }
260 if (d->forceFg >= 0) {
261 *fg = d->forceFg;
262 }
263} 263}
264 264
265iLocalDef int iconPadding_LabelWidget_(const iLabelWidget *d) { 265iLocalDef int iconPadding_LabelWidget_(const iLabelWidget *d) {
@@ -318,6 +318,10 @@ static void draw_LabelWidget_(const iLabelWidget *d) {
318 } 318 }
319 setClip_Paint(&p, rect); 319 setClip_Paint(&p, rect);
320 const int iconPad = iconPadding_LabelWidget_(d); 320 const int iconPad = iconPadding_LabelWidget_(d);
321 const int iconColor = isCaution ? uiTextCaution_ColorId
322 : flags & (disabled_WidgetFlag | pressed_WidgetFlag) ? fg
323 : isHover ? uiIconHover_ColorId
324 : uiIcon_ColorId;
321 if (d->icon && d->icon != 0x20) { /* no need to draw an empty icon */ 325 if (d->icon && d->icon != 0x20) { /* no need to draw an empty icon */
322 iString str; 326 iString str;
323 initUnicodeN_String(&str, &d->icon, 1); 327 initUnicodeN_String(&str, &d->icon, 1);
@@ -331,10 +335,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) {
331 -gap_UI / 8)), 335 -gap_UI / 8)),
332 init_I2(iconPad, lineHeight_Text(d->font)) }, 336 init_I2(iconPad, lineHeight_Text(d->font)) },
333 iTrue, 337 iTrue,
334 isCaution ? uiTextCaution_ColorId 338 iconColor,
335 : flags & (disabled_WidgetFlag | pressed_WidgetFlag) ? fg
336 : isHover ? uiIconHover_ColorId
337 : uiIcon_ColorId,
338 "%s", 339 "%s",
339 cstr_String(&str)); 340 cstr_String(&str));
340 deinit_String(&str); 341 deinit_String(&str);
@@ -387,7 +388,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) {
387 drawCentered_Text(d->font, 388 drawCentered_Text(d->font,
388 (iRect){ addX_I2(topRight_Rect(chRect), -iconPad), 389 (iRect){ addX_I2(topRight_Rect(chRect), -iconPad),
389 init_I2(chSize, height_Rect(chRect)) }, 390 init_I2(chSize, height_Rect(chRect)) },
390 iTrue, uiSeparator_ColorId, rightAngle_Icon); 391 iTrue, iconColor /*uiSeparator_ColorId*/, rightAngle_Icon);
391 } 392 }
392 unsetClip_Paint(&p); 393 unsetClip_Paint(&p);
393} 394}
diff --git a/src/ui/mobile.c b/src/ui/mobile.c
index daa1fa1a..6ea672e6 100644
--- a/src/ui/mobile.c
+++ b/src/ui/mobile.c
@@ -90,15 +90,15 @@ static void unselectAllPanelButtons_(iWidget *topPanel) {
90 90
91static iBool mainDetailSplitHandler_(iWidget *mainDetailSplit, const char *cmd) { 91static iBool mainDetailSplitHandler_(iWidget *mainDetailSplit, const char *cmd) {
92 if (equal_Command(cmd, "window.resized")) { 92 if (equal_Command(cmd, "window.resized")) {
93 const iBool isPortrait = (deviceType_App() == phone_AppDeviceType && isPortrait_App()); 93 const iBool isPortrait = (deviceType_App() == phone_AppDeviceType && isPortrait_App());
94 const iRect safeRoot = safeRect_Root(mainDetailSplit->root); 94 const iRect safeRoot = safeRect_Root(mainDetailSplit->root);
95 setPos_Widget(mainDetailSplit, topLeft_Rect(safeRoot));
96 setFixedSize_Widget(mainDetailSplit, safeRoot.size);
97 iWidget * sheet = parent_Widget(mainDetailSplit); 95 iWidget * sheet = parent_Widget(mainDetailSplit);
98 iWidget * navi = findChild_Widget(sheet, "panel.navi"); 96 iWidget * navi = findChild_Widget(sheet, "panel.navi");
99 iWidget * detailStack = findChild_Widget(mainDetailSplit, "detailstack"); 97 iWidget * detailStack = findChild_Widget(mainDetailSplit, "detailstack");
100 const size_t numPanels = childCount_Widget(detailStack); 98 const size_t numPanels = childCount_Widget(detailStack);
101 const iBool isSideBySide = isSideBySideLayout_() && numPanels > 0; 99 const iBool isSideBySide = isSideBySideLayout_() && numPanels > 0;
100 setPos_Widget(mainDetailSplit, topLeft_Rect(safeRoot));
101 setFixedSize_Widget(mainDetailSplit, safeRoot.size);
102 setFlags_Widget(mainDetailSplit, arrangeHorizontal_WidgetFlag, isSideBySide); 102 setFlags_Widget(mainDetailSplit, arrangeHorizontal_WidgetFlag, isSideBySide);
103 setFlags_Widget(detailStack, expand_WidgetFlag, isSideBySide); 103 setFlags_Widget(detailStack, expand_WidgetFlag, isSideBySide);
104 setFlags_Widget(detailStack, hidden_WidgetFlag, numPanels == 0); 104 setFlags_Widget(detailStack, hidden_WidgetFlag, numPanels == 0);
@@ -172,7 +172,16 @@ static iBool topPanelHandler_(iWidget *topPanel, const char *cmd) {
172 } 172 }
173 unselectAllPanelButtons_(topPanel); 173 unselectAllPanelButtons_(topPanel);
174 if (!wasClosed) { 174 if (!wasClosed) {
175 postCommand_App("prefs.dismiss"); 175 /* TODO: Should come up with a more general-purpose approach here. */
176 if (findWidget_App("prefs")) {
177 postCommand_App("prefs.dismiss");
178 }
179 else if (findWidget_App("upload")) {
180 postCommand_App("upload.cancel");
181 }
182 else {
183 postCommand_App("cancel");
184 }
176 } 185 }
177 return iTrue; 186 return iTrue;
178 } 187 }
@@ -503,11 +512,19 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {
503 else if (equal_Command(spec, "label")) { 512 else if (equal_Command(spec, "label")) {
504 iLabelWidget *lab = new_LabelWidget(label, NULL); 513 iLabelWidget *lab = new_LabelWidget(label, NULL);
505 widget = as_Widget(lab); 514 widget = as_Widget(lab);
506 setWrap_LabelWidget(lab, iTrue); 515 setId_Widget(widget, id);
507 setFlags_Widget(widget, fixedHeight_WidgetFlag | frameless_WidgetFlag, iTrue); 516 setWrap_LabelWidget(lab, !argLabel_Command(spec, "nowrap"));
517 setFlags_Widget(widget,
518 fixedHeight_WidgetFlag |
519 (!argLabel_Command(spec, "frame") ? frameless_WidgetFlag : 0),
520 iTrue);
508 } 521 }
509 else if (equal_Command(spec, "padding")) { 522 else if (equal_Command(spec, "padding")) {
510 widget = makePadding_Widget(lineHeight_Text(labelFont_()) * 1.5f); 523 float height = 1.5f;
524 if (hasLabel_Command(spec, "arg")) {
525 height *= argfLabel_Command(spec, "arg");
526 }
527 widget = makePadding_Widget(lineHeight_Text(labelFont_()) * height);
511 } 528 }
512 /* Apply common styling to the heading. */ 529 /* Apply common styling to the heading. */
513 if (heading) { 530 if (heading) {
@@ -539,7 +556,7 @@ static const iMenuItem *findDialogCancelAction_(const iMenuItem *items, size_t n
539 return NULL; 556 return NULL;
540 } 557 }
541 for (size_t i = 0; i < n; i++) { 558 for (size_t i = 0; i < n; i++) {
542 if (!iCmpStr(items[i].label, "${cancel}")) { 559 if (!iCmpStr(items[i].label, "${cancel}") || !iCmpStr(items[i].label, "${close}")) {
543 return &items[i]; 560 return &items[i];
544 } 561 }
545 } 562 }
@@ -556,13 +573,20 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget,
556 const char *id, 573 const char *id,
557 const iMenuItem *itemsNullTerminated, 574 const iMenuItem *itemsNullTerminated,
558 const iMenuItem *actions, size_t numActions) { 575 const iMenuItem *actions, size_t numActions) {
576 iWidget *panels = new_Widget();
577 setId_Widget(panels, id);
578 initPanels_Mobile(panels, parentWidget, itemsNullTerminated, actions, numActions);
579 return panels;
580}
581
582void initPanels_Mobile(iWidget *panels, iWidget *parentWidget,
583 const iMenuItem *itemsNullTerminated,
584 const iMenuItem *actions, size_t numActions) {
559 /* A multipanel widget has a top panel and one or more detail panels. In a horizontal layout, 585 /* A multipanel widget has a top panel and one or more detail panels. In a horizontal layout,
560 the detail panels slide in from the right and cover the top panel. In a landscape layout, 586 the detail panels slide in from the right and cover the top panel. In a landscape layout,
561 the detail panels are always visible on the side. */ 587 the detail panels are always visible on the side. */
562 iWidget *sheet = new_Widget(); 588 setBackgroundColor_Widget(panels, uiBackground_ColorId);
563 setId_Widget(sheet, id); 589 setFlags_Widget(panels,
564 setBackgroundColor_Widget(sheet, uiBackground_ColorId);
565 setFlags_Widget(sheet,
566 resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag | 590 resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag |
567 frameless_WidgetFlag | focusRoot_WidgetFlag | commandOnClick_WidgetFlag | 591 frameless_WidgetFlag | focusRoot_WidgetFlag | commandOnClick_WidgetFlag |
568 overflowScrollable_WidgetFlag | leftEdgeDraggable_WidgetFlag, 592 overflowScrollable_WidgetFlag | leftEdgeDraggable_WidgetFlag,
@@ -572,7 +596,7 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget,
572 setCommandHandler_Widget(mainDetailSplit, mainDetailSplitHandler_); 596 setCommandHandler_Widget(mainDetailSplit, mainDetailSplitHandler_);
573 setFlags_Widget(mainDetailSplit, resizeHeightOfChildren_WidgetFlag, iFalse); 597 setFlags_Widget(mainDetailSplit, resizeHeightOfChildren_WidgetFlag, iFalse);
574 setId_Widget(mainDetailSplit, "mdsplit"); 598 setId_Widget(mainDetailSplit, "mdsplit");
575 addChild_Widget(sheet, iClob(mainDetailSplit)); 599 addChild_Widget(panels, iClob(mainDetailSplit));
576 } 600 }
577 /* The panel roots. */ 601 /* The panel roots. */
578 iWidget *topPanel = new_Widget(); { 602 iWidget *topPanel = new_Widget(); {
@@ -591,7 +615,6 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget,
591 setFlags_Widget(detailStack, collapse_WidgetFlag | resizeWidthOfChildren_WidgetFlag, iTrue); 615 setFlags_Widget(detailStack, collapse_WidgetFlag | resizeWidthOfChildren_WidgetFlag, iTrue);
592 addChild_Widget(mainDetailSplit, iClob(detailStack)); 616 addChild_Widget(mainDetailSplit, iClob(detailStack));
593 } 617 }
594 addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));
595 /* Slide top panel with detail panels. */ { 618 /* Slide top panel with detail panels. */ {
596 setFlags_Widget(topPanel, refChildrenOffset_WidgetFlag, iTrue); 619 setFlags_Widget(topPanel, refChildrenOffset_WidgetFlag, iTrue);
597 topPanel->offsetRef = detailStack; 620 topPanel->offsetRef = detailStack;
@@ -612,15 +635,17 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget,
612 checkIcon_LabelWidget(naviBack); 635 checkIcon_LabelWidget(naviBack);
613 setId_Widget(as_Widget(naviBack), "panel.back"); 636 setId_Widget(as_Widget(naviBack), "panel.back");
614 setFont_LabelWidget(naviBack, labelFont_()); 637 setFont_LabelWidget(naviBack, labelFont_());
615 addChildFlags_Widget(sheet, iClob(navi), 638 addChildFlags_Widget(panels, iClob(navi),
616 drawBackgroundToVerticalSafeArea_WidgetFlag | 639 drawBackgroundToVerticalSafeArea_WidgetFlag |
617 arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag | 640 arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag |
618 resizeToParentWidth_WidgetFlag | arrangeVertical_WidgetFlag); 641 resizeToParentWidth_WidgetFlag | arrangeVertical_WidgetFlag);
619 } 642 }
643 iBool haveDetailPanels = iFalse;
620 /* Create panel contents based on provided items. */ 644 /* Create panel contents based on provided items. */
621 for (size_t i = 0; itemsNullTerminated[i].label; i++) { 645 for (size_t i = 0; itemsNullTerminated[i].label; i++) {
622 const iMenuItem *item = &itemsNullTerminated[i]; 646 const iMenuItem *item = &itemsNullTerminated[i];
623 if (equal_Command(item->label, "panel")) { 647 if (equal_Command(item->label, "panel")) {
648 haveDetailPanels = iTrue;
624 const char *id = cstr_Rangecc(range_Command(item->label, "id")); 649 const char *id = cstr_Rangecc(range_Command(item->label, "id"));
625 const iString *label = hasLabel_Command(item->label, "text") 650 const iString *label = hasLabel_Command(item->label, "text")
626 ? collect_String(suffix_Command(item->label, "text")) 651 ? collect_String(suffix_Command(item->label, "text"))
@@ -655,10 +680,12 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget,
655 setFont_LabelWidget(naviBack, labelBoldFont_()); 680 setFont_LabelWidget(naviBack, labelBoldFont_());
656 } 681 }
657 else if (defaultItem && defaultItem != cancelItem) { 682 else if (defaultItem && defaultItem != cancelItem) {
658 updateTextCStr_LabelWidget(naviBack, cancelItem->label); 683 if (!haveDetailPanels) {
659 setCommand_LabelWidget(naviBack, collectNewCStr_String(cancelItem->command 684 updateTextCStr_LabelWidget(naviBack, cancelItem->label);
660 ? cancelItem->command 685 setCommand_LabelWidget(naviBack, collectNewCStr_String(cancelItem->command
661 : "cancel")); 686 ? cancelItem->command
687 : "cancel"));
688 }
662 iLabelWidget *defaultButton = new_LabelWidget(defaultItem->label, defaultItem->command); 689 iLabelWidget *defaultButton = new_LabelWidget(defaultItem->label, defaultItem->command);
663 setFont_LabelWidget(defaultButton, labelBoldFont_()); 690 setFont_LabelWidget(defaultButton, labelBoldFont_());
664 setFlags_Widget(as_Widget(defaultButton), 691 setFlags_Widget(as_Widget(defaultButton),
@@ -689,16 +716,21 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget,
689 } 716 }
690 makePanelItem_Mobile( 717 makePanelItem_Mobile(
691 topPanel, 718 topPanel,
692 &(iMenuItem){ format_CStr("button text:%s", act->label), 0, 0, act->command }); 719 &(iMenuItem){ format_CStr("button text:" uiTextAction_ColorEscape "%s", act->label),
720 0,
721 0,
722 act->command });
693 } 723 }
694 } 724 }
695 /* Finalize the layout. */ 725 /* Finalize the layout. */
696 addChild_Widget(parentWidget, iClob(sheet)); 726 if (parentWidget) {
727 addChild_Widget(parentWidget, iClob(panels));
728 }
697 mainDetailSplitHandler_(mainDetailSplit, "window.resized"); /* make it resize the split */ 729 mainDetailSplitHandler_(mainDetailSplit, "window.resized"); /* make it resize the split */
698 updatePanelSheetMetrics_(sheet); 730 updatePanelSheetMetrics_(panels);
699 arrange_Widget(sheet); 731 arrange_Widget(panels);
700 postCommand_App("widget.overflow"); /* with the correct dimensions */ 732 postCommand_App("widget.overflow"); /* with the correct dimensions */
701 return sheet; 733 printTree_Widget(panels);
702} 734}
703 735
704#if 0 736#if 0
@@ -1130,7 +1162,9 @@ void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) {
1130 } 1162 }
1131} 1163}
1132 1164
1133void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) { 1165void setupSheetTransition_Mobile(iWidget *sheet, int flags) {
1166 const iBool isIncoming = (flags & incoming_TransitionFlag) != 0;
1167 const int dir = flags & dirMask_TransitionFlag;
1134 if (!isUsingPanelLayout_Mobile()) { 1168 if (!isUsingPanelLayout_Mobile()) {
1135 if (prefs_App()->uiAnimations) { 1169 if (prefs_App()->uiAnimations) {
1136 setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iFalse); 1170 setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iFalse);
@@ -1144,17 +1178,51 @@ void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) {
1144 } 1178 }
1145 return; 1179 return;
1146 } 1180 }
1147 if(isSideBySideLayout_()) { 1181 if (isSideBySideLayout_()) {
1182 /* TODO: Landscape transitions? */
1148 return; 1183 return;
1149 } 1184 }
1150 setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iTrue); 1185 setFlags_Widget(sheet,
1186 horizontalOffset_WidgetFlag,
1187 dir == right_TransitionDir || dir == left_TransitionDir);
1151 if (isIncoming) { 1188 if (isIncoming) {
1152 setVisualOffset_Widget(sheet, size_Root(sheet->root).x, 0, 0); 1189 switch (dir) {
1190 case right_TransitionDir:
1191 setVisualOffset_Widget(sheet, size_Root(sheet->root).x, 0, 0);
1192 break;
1193 case left_TransitionDir:
1194 setVisualOffset_Widget(sheet, -size_Root(sheet->root).x, 0, 0);
1195 break;
1196 case top_TransitionDir:
1197 setVisualOffset_Widget(
1198 sheet, -bottom_Rect(boundsWithoutVisualOffset_Widget(sheet)), 0, 0);
1199 break;
1200 case bottom_TransitionDir:
1201 setVisualOffset_Widget(sheet, height_Widget(sheet), 0, 0);
1202 break;
1203 }
1153 setVisualOffset_Widget(sheet, 0, 200, easeOut_AnimFlag); 1204 setVisualOffset_Widget(sheet, 0, 200, easeOut_AnimFlag);
1154 } 1205 }
1155 else { 1206 else {
1156 const iBool wasDragged = iAbs(value_Anim(&sheet->visualOffset)) > 0; 1207 switch (dir) {
1157 setVisualOffset_Widget(sheet, size_Root(sheet->root).x, wasDragged ? 100 : 200, 1208 case right_TransitionDir: {
1158 wasDragged ? 0 : easeIn_AnimFlag); 1209 const iBool wasDragged = iAbs(value_Anim(&sheet->visualOffset)) > 0;
1210 setVisualOffset_Widget(sheet, size_Root(sheet->root).x, wasDragged ? 100 : 200,
1211 wasDragged ? 0 : easeIn_AnimFlag);
1212 break;
1213 }
1214 case left_TransitionDir:
1215 setVisualOffset_Widget(sheet, -size_Root(sheet->root).x, 200, easeIn_AnimFlag);
1216 break;
1217 case top_TransitionDir:
1218 setVisualOffset_Widget(sheet,
1219 -bottom_Rect(boundsWithoutVisualOffset_Widget(sheet)),
1220 200,
1221 easeIn_AnimFlag);
1222 break;
1223 case bottom_TransitionDir:
1224 setVisualOffset_Widget(sheet, height_Widget(sheet), 200, easeIn_AnimFlag);
1225 break;
1226 }
1159 } 1227 }
1160} 1228}
diff --git a/src/ui/mobile.h b/src/ui/mobile.h
index 30679c7c..e1131953 100644
--- a/src/ui/mobile.h
+++ b/src/ui/mobile.h
@@ -35,8 +35,23 @@ iWidget * makePanelsParent_Mobile (iWidget *parent,
35 const char *id, 35 const char *id,
36 const iMenuItem *itemsNullTerminated, 36 const iMenuItem *itemsNullTerminated,
37 const iMenuItem *actions, size_t numActions); 37 const iMenuItem *actions, size_t numActions);
38void initPanels_Mobile (iWidget *panels, iWidget *parentWidget,
39 const iMenuItem *itemsNullTerminated,
40 const iMenuItem *actions, size_t numActions);
41
42enum iTransitionFlags {
43 incoming_TransitionFlag = iBit(1),
44 dirMask_TransitionFlag = iBit(2) | iBit(3),
45};
46
47enum iTransitionDir {
48 right_TransitionDir = 0,
49 bottom_TransitionDir = 2,
50 left_TransitionDir = 4,
51 top_TransitionDir = 6,
52};
38 53
39void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming); 54void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming);
40void setupSheetTransition_Mobile (iWidget *sheet, iBool isIncoming); 55void setupSheetTransition_Mobile (iWidget *sheet, int flags);
41 56
42void finalizeSheet_Mobile (iWidget *sheet); 57void finalizeSheet_Mobile (iWidget *sheet);
diff --git a/src/ui/root.c b/src/ui/root.c
index eae8e4bb..a792e93d 100644
--- a/src/ui/root.c
+++ b/src/ui/root.c
@@ -118,7 +118,7 @@ static const iMenuItem phoneNavMenuItems_[] = {
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 { "---" }, 120 { "---" },
121 { gear_Icon " Settings...", SDLK_COMMA, KMOD_PRIMARY, "preferences" }, 121 { gear_Icon " ${menu.settings}", SDLK_COMMA, KMOD_PRIMARY, "preferences" },
122}; 122};
123#endif /* Mobile */ 123#endif /* Mobile */
124 124
@@ -1163,20 +1163,12 @@ void createUserInterface_Root(iRoot *d) {
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)
1167 { "---" },
1168 { "${menu.page.copyurl}", 0, 0, "document.copylink" },
1169 { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" },
1170 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } },
1171 11);
1172#else
1173 { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" }, 1166 { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" },
1174 { "---" }, 1167 { "---" },
1175 { "${menu.page.copyurl}", 0, 0, "document.copylink" }, 1168 { "${menu.page.copyurl}", 0, 0, "document.copylink" },
1176 { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" }, 1169 { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" },
1177 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } }, 1170 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } },
1178 12); 1171 12);
1179#endif
1180 setId_Widget(as_Widget(pageMenuButton), "pagemenubutton"); 1172 setId_Widget(as_Widget(pageMenuButton), "pagemenubutton");
1181 setFont_LabelWidget(pageMenuButton, uiContentBold_FontId); 1173 setFont_LabelWidget(pageMenuButton, uiContentBold_FontId);
1182 setAlignVisually_LabelWidget(pageMenuButton, iTrue); 1174 setAlignVisually_LabelWidget(pageMenuButton, iTrue);
diff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c
index 4c72c60a..fb8aaf0a 100644
--- a/src/ui/uploadwidget.c
+++ b/src/ui/uploadwidget.c
@@ -81,91 +81,122 @@ void init_UploadWidget(iUploadWidget *d) {
81 iWidget *w = as_Widget(d); 81 iWidget *w = as_Widget(d);
82 init_Widget(w); 82 init_Widget(w);
83 setId_Widget(w, "upload"); 83 setId_Widget(w, "upload");
84 useSheetStyle_Widget(w);
85 init_String(&d->originalUrl); 84 init_String(&d->originalUrl);
86 init_String(&d->url); 85 init_String(&d->url);
87 d->viewer = NULL; 86 d->viewer = NULL;
88 d->request = NULL; 87 d->request = NULL;
89 init_String(&d->filePath); 88 init_String(&d->filePath);
90 d->fileSize = 0; 89 d->fileSize = 0;
91 addChildFlags_Widget(w, 90 const iMenuItem actions[] = {
92 iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.upload}", NULL)), 91 { "${upload.port}", 0, 0, "upload.setport" },
93 frameless_WidgetFlag); 92 { "---" },
94 d->info = addChildFlags_Widget(w, iClob(new_LabelWidget("", NULL)), 93 { "${close}", SDLK_ESCAPE, 0, "upload.cancel" },
95 frameless_WidgetFlag | resizeToParentWidth_WidgetFlag | 94 { uiTextAction_ColorEscape "${dlg.upload.send}", SDLK_RETURN, KMOD_PRIMARY, "upload.accept" }
96 fixedHeight_WidgetFlag); 95 };
97 setWrap_LabelWidget(d->info, iTrue); 96 if (isUsingPanelLayout_Mobile()) {
98 /* Tabs for input data. */ 97 const iMenuItem textItems[] = {
99 iWidget *tabs = makeTabs_Widget(w); 98 { "title id:heading.upload.text" },
100 /* Make the tabs support vertical expansion based on content. */ { 99 { "input id:upload.text noheading:1" },
101 setFlags_Widget(tabs, resizeHeightOfChildren_WidgetFlag, iFalse); 100 { NULL }
102 setFlags_Widget(tabs, arrangeHeight_WidgetFlag, iTrue); 101 };
103 iWidget *tabPages = findChild_Widget(tabs, "tabs.pages"); 102 const iMenuItem fileItems[] = {
104 setFlags_Widget(tabPages, resizeHeightOfChildren_WidgetFlag, iFalse); 103 { "title id:heading.upload.file" },
105 setFlags_Widget(tabPages, arrangeHeight_WidgetFlag, iTrue); 104 { "button text:" uiTextAction_ColorEscape "${dlg.upload.pickfile}", 0, 0, "upload.pickfile" },
105 { "heading id:upload.file.name" },
106 { "label id:upload.filepathlabel" },
107 { "heading id:upload.file.size" },
108 { "label id:upload.filesizelabel" },
109 { "padding" },
110 { "input id:upload.mime" },
111 { "label id:upload.counter text:" },
112 { NULL }
113 };
114 initPanels_Mobile(w, NULL, (iMenuItem[]){
115 { "title id:heading.upload" },
116 { "label id:upload.info" },
117// { "padding" },
118 { "panel id:dlg.upload.text icon:0x1f5b9", 0, 0, (const void *) textItems },
119 { "panel id:dlg.upload.file icon:0x1f4c1", 0, 0, (const void *) fileItems },
120 { "padding" },
121 { "input id:upload.token hint:hint.upload.token" },
122 { NULL }
123 }, actions, iElemCount(actions));
124 d->info = findChild_Widget(w, "upload.info");
125 d->input = findChild_Widget(w, "upload.text");
126 d->filePathLabel = findChild_Widget(w, "upload.file.name");
127 d->fileSizeLabel = findChild_Widget(w, "upload.file.size");
128 d->mime = findChild_Widget(w, "upload.mime");
129 d->token = findChild_Widget(w, "upload.token");
130 d->counter = findChild_Widget(w, "upload.counter");
106 } 131 }
107 iWidget *headings, *values; 132 else {
108 setBackgroundColor_Widget(findChild_Widget(tabs, "tabs.buttons"), uiBackgroundSidebar_ColorId); 133 useSheetStyle_Widget(w);
109 setId_Widget(tabs, "upload.tabs"); 134 addChildFlags_Widget(w,
110// const int bigGap = lineHeight_Text(uiLabel_FontId) * 3 / 4; 135 iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.upload}", NULL)),
111 /* Text input. */ { 136 frameless_WidgetFlag);
112 //appendTwoColumnTabPage_Widget(tabs, "${heading.upload.text}", '1', &headings, &values); 137 d->info = addChildFlags_Widget(w, iClob(new_LabelWidget("", NULL)),
113 iWidget *page = new_Widget(); 138 frameless_WidgetFlag | resizeToParentWidth_WidgetFlag |
114 setFlags_Widget(page, arrangeSize_WidgetFlag, iTrue); 139 fixedHeight_WidgetFlag);
115 d->input = new_InputWidget(0); 140 setWrap_LabelWidget(d->info, iTrue);
116 setId_Widget(as_Widget(d->input), "upload.text"); 141 /* Tabs for input data. */
117 setFont_InputWidget(d->input, monospace_FontId); 142 iWidget *tabs = makeTabs_Widget(w);
118 setLineLimits_InputWidget(d->input, 7, 20); 143 /* Make the tabs support vertical expansion based on content. */ {
119 setUseReturnKeyBehavior_InputWidget(d->input, iFalse); /* traditional text editor */ 144 setFlags_Widget(tabs, resizeHeightOfChildren_WidgetFlag, iFalse);
120 setHint_InputWidget(d->input, "${hint.upload.text}"); 145 setFlags_Widget(tabs, arrangeHeight_WidgetFlag, iTrue);
121 setFixedSize_Widget(as_Widget(d->input), init_I2(120 * gap_UI, -1)); 146 iWidget *tabPages = findChild_Widget(tabs, "tabs.pages");
122 addChild_Widget(page, iClob(d->input)); 147 setFlags_Widget(tabPages, resizeHeightOfChildren_WidgetFlag, iFalse);
123 appendFramelessTabPage_Widget(tabs, iClob(page), "${heading.upload.text}", '1', 0); 148 setFlags_Widget(tabPages, arrangeHeight_WidgetFlag, iTrue);
124 } 149 }
125 /* File content. */ { 150 iWidget *headings, *values;
126 appendTwoColumnTabPage_Widget(tabs, "${heading.upload.file}", '2', &headings, &values); 151 setBackgroundColor_Widget(findChild_Widget(tabs, "tabs.buttons"), uiBackgroundSidebar_ColorId);
127// iWidget *pad = addChild_Widget(headings, iClob(makePadding_Widget(0))); 152 setId_Widget(tabs, "upload.tabs");
128// iWidget *hint = addChild_Widget(values, iClob(new_LabelWidget("${upload.file.drophint}", NULL))); 153 /* Text input. */ {
129// pad->sizeRef = hint; 154 iWidget *page = new_Widget();
130 addChildFlags_Widget(headings, iClob(new_LabelWidget("${upload.file.name}", NULL)), frameless_WidgetFlag); 155 setFlags_Widget(page, arrangeSize_WidgetFlag, iTrue);
131 d->filePathLabel = addChildFlags_Widget(values, iClob(new_LabelWidget(uiTextAction_ColorEscape "${upload.file.drophere}", NULL)), frameless_WidgetFlag); 156 d->input = new_InputWidget(0);
132 addChildFlags_Widget(headings, iClob(new_LabelWidget("${upload.file.size}", NULL)), frameless_WidgetFlag); 157 setId_Widget(as_Widget(d->input), "upload.text");
133 d->fileSizeLabel = addChildFlags_Widget(values, iClob(new_LabelWidget("\u2014", NULL)), frameless_WidgetFlag); 158 setFixedSize_Widget(as_Widget(d->input), init_I2(120 * gap_UI, -1));
134 d->mime = new_InputWidget(0); 159 addChild_Widget(page, iClob(d->input));
135 setFixedSize_Widget(as_Widget(d->mime), init_I2(70 * gap_UI, -1)); 160 appendFramelessTabPage_Widget(tabs, iClob(page), "${heading.upload.text}", '1', 0);
136 addTwoColumnDialogInputField_Widget(headings, values, "${upload.mime}", "upload.mime", iClob(d->mime)); 161 }
137 } 162 /* File content. */ {
138 /* Token. */ { 163 appendTwoColumnTabPage_Widget(tabs, "${heading.upload.file}", '2', &headings, &values);
139 addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); 164 addChildFlags_Widget(headings, iClob(new_LabelWidget("${upload.file.name}", NULL)), frameless_WidgetFlag);
140 iWidget *page = makeTwoColumns_Widget(&headings, &values); 165 d->filePathLabel = addChildFlags_Widget(values, iClob(new_LabelWidget(uiTextAction_ColorEscape "${upload.file.drophere}", NULL)), frameless_WidgetFlag);
141 d->token = addTwoColumnDialogInputField_Widget( 166 addChildFlags_Widget(headings, iClob(new_LabelWidget("${upload.file.size}", NULL)), frameless_WidgetFlag);
142 headings, values, "${upload.token}", "upload.token", iClob(new_InputWidget(0))); 167 d->fileSizeLabel = addChildFlags_Widget(values, iClob(new_LabelWidget("\u2014", NULL)), frameless_WidgetFlag);
143 setHint_InputWidget(d->token, "${hint.upload.token}"); 168 d->mime = new_InputWidget(0);
144 setFixedSize_Widget(as_Widget(d->token), init_I2(50 * gap_UI, -1)); 169 setFixedSize_Widget(as_Widget(d->mime), init_I2(70 * gap_UI, -1));
145 addChild_Widget(w, iClob(page)); 170 addTwoColumnDialogInputField_Widget(headings, values, "${upload.mime}", "upload.mime", iClob(d->mime));
146 } 171 }
147 /* Buttons. */ { 172 /* Token. */ {
148 addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); 173 addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));
149 iWidget *buttons = 174 iWidget *page = makeTwoColumns_Widget(&headings, &values);
150 makeDialogButtons_Widget((iMenuItem[]){ { "${upload.port}", 0, 0, "upload.setport" }, 175 d->token = addTwoColumnDialogInputField_Widget(
151 { "---" }, 176 headings, values, "${upload.token}", "upload.token", iClob(new_InputWidget(0)));
152 { "${close}", SDLK_ESCAPE, 0, "upload.cancel" }, 177 setHint_InputWidget(d->token, "${hint.upload.token}");
153 { uiTextAction_ColorEscape "${dlg.upload.send}", 178 setFixedSize_Widget(as_Widget(d->token), init_I2(50 * gap_UI, -1));
154 SDLK_RETURN, 179 addChild_Widget(w, iClob(page));
155 KMOD_PRIMARY, 180 }
156 "upload.accept" } }, 181 /* Buttons. */ {
157 4); 182 addChild_Widget(w, iClob(makePadding_Widget(gap_UI)));
158 setId_Widget(insertChildAfterFlags_Widget(buttons, 183 iWidget *buttons = makeDialogButtons_Widget(actions, iElemCount(actions));
159 iClob(d->counter = new_LabelWidget("", NULL)), 184 setId_Widget(insertChildAfterFlags_Widget(buttons,
160 0, frameless_WidgetFlag), 185 iClob(d->counter = new_LabelWidget("", NULL)),
161 "upload.counter"); 186 0, frameless_WidgetFlag),
162 addChild_Widget(w, iClob(buttons)); 187 "upload.counter");
188 addChild_Widget(w, iClob(buttons));
189 }
190 resizeToLargestPage_Widget(tabs);
191 arrange_Widget(w);
192 setFixedSize_Widget(as_Widget(d->token), init_I2(width_Widget(tabs) - left_Rect(parent_Widget(d->token)->rect), -1));
193 setFlags_Widget(as_Widget(d->token), expand_WidgetFlag, iTrue);
194 setFocus_Widget(as_Widget(d->input));
163 } 195 }
164 resizeToLargestPage_Widget(tabs); 196 setFont_InputWidget(d->input, monospace_FontId);
165 arrange_Widget(w); 197 setUseReturnKeyBehavior_InputWidget(d->input, iFalse); /* traditional text editor */
166 setFixedSize_Widget(as_Widget(d->token), init_I2(width_Widget(tabs) - left_Rect(parent_Widget(d->token)->rect), -1)); 198 setLineLimits_InputWidget(d->input, 7, 20);
167 setFlags_Widget(as_Widget(d->token), expand_WidgetFlag, iTrue); 199 setHint_InputWidget(d->input, "${hint.upload.text}");
168 setFocus_Widget(as_Widget(d->input));
169 setBackupFileName_InputWidget(d->input, "uploadbackup.txt"); 200 setBackupFileName_InputWidget(d->input, "uploadbackup.txt");
170 updateInputMaxHeight_UploadWidget_(d); 201 updateInputMaxHeight_UploadWidget_(d);
171} 202}
@@ -201,6 +232,7 @@ static void setUrlPort_UploadWidget_(iUploadWidget *d, const iString *url, uint1
201 appendFormat_String(&d->url, ":%u", overridePort ? overridePort : titanPortForUrl_(url)); 232 appendFormat_String(&d->url, ":%u", overridePort ? overridePort : titanPortForUrl_(url));
202 appendRange_String(&d->url, (iRangecc){ parts.path.start, constEnd_String(url) }); 233 appendRange_String(&d->url, (iRangecc){ parts.path.start, constEnd_String(url) });
203 setText_LabelWidget(d->info, &d->url); 234 setText_LabelWidget(d->info, &d->url);
235 arrange_Widget(as_Widget(d));
204} 236}
205 237
206void setUrl_UploadWidget(iUploadWidget *d, const iString *url) { 238void setUrl_UploadWidget(iUploadWidget *d, const iString *url) {
@@ -233,7 +265,7 @@ static iBool processEvent_UploadWidget_(iUploadWidget *d, const SDL_Event *ev) {
233 if (isResize_UserEvent(ev)) { 265 if (isResize_UserEvent(ev)) {
234 updateInputMaxHeight_UploadWidget_(d); 266 updateInputMaxHeight_UploadWidget_(d);
235 } 267 }
236 if (isCommand_Widget(w, ev, "upload.cancel")) { 268 if (equal_Command(cmd, "upload.cancel")) {
237 setupSheetTransition_Mobile(w, iFalse); 269 setupSheetTransition_Mobile(w, iFalse);
238 destroy_Widget(w); 270 destroy_Widget(w);
239 return iTrue; 271 return iTrue;
diff --git a/src/ui/util.c b/src/ui/util.c
index b875e260..6069e800 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -1061,6 +1061,7 @@ iWidget *removeTabPage_Widget(iWidget *tabs, size_t index) {
1061} 1061}
1062 1062
1063void resizeToLargestPage_Widget(iWidget *tabs) { 1063void resizeToLargestPage_Widget(iWidget *tabs) {
1064 if (!tabs) return;
1064// puts("RESIZE TO LARGEST PAGE ..."); 1065// puts("RESIZE TO LARGEST PAGE ...");
1065 iWidget *pages = findChild_Widget(tabs, "tabs.pages"); 1066 iWidget *pages = findChild_Widget(tabs, "tabs.pages");
1066 iForEach(ObjectList, i, children_Widget(pages)) { 1067 iForEach(ObjectList, i, children_Widget(pages)) {
@@ -1216,7 +1217,7 @@ iBool valueInputHandler_(iWidget *dlg, const char *cmd) {
1216 postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg))); 1217 postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg)));
1217 setId_Widget(dlg, ""); /* no further commands to emit */ 1218 setId_Widget(dlg, ""); /* no further commands to emit */
1218 } 1219 }
1219 setupSheetTransition_Mobile(dlg, iFalse); 1220 setupSheetTransition_Mobile(dlg, top_TransitionDir);
1220 destroy_Widget(dlg); 1221 destroy_Widget(dlg);
1221 return iTrue; 1222 return iTrue;
1222 } 1223 }
@@ -1225,13 +1226,13 @@ iBool valueInputHandler_(iWidget *dlg, const char *cmd) {
1225 else if (equal_Command(cmd, "valueinput.cancel")) { 1226 else if (equal_Command(cmd, "valueinput.cancel")) {
1226 postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg))); 1227 postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg)));
1227 setId_Widget(dlg, ""); /* no further commands to emit */ 1228 setId_Widget(dlg, ""); /* no further commands to emit */
1228 setupSheetTransition_Mobile(dlg, iFalse); 1229 setupSheetTransition_Mobile(dlg, top_TransitionDir);
1229 destroy_Widget(dlg); 1230 destroy_Widget(dlg);
1230 return iTrue; 1231 return iTrue;
1231 } 1232 }
1232 else if (equal_Command(cmd, "valueinput.accept")) { 1233 else if (equal_Command(cmd, "valueinput.accept")) {
1233 acceptValueInput_(dlg); 1234 acceptValueInput_(dlg);
1234 setupSheetTransition_Mobile(dlg, iFalse); 1235 setupSheetTransition_Mobile(dlg, top_TransitionDir);
1235 destroy_Widget(dlg); 1236 destroy_Widget(dlg);
1236 return iTrue; 1237 return iTrue;
1237 } 1238 }
@@ -1345,7 +1346,9 @@ iWidget *makeValueInput_Widget(iWidget *parent, const iString *initialValue, con
1345 acceptKeyMod_ReturnKeyBehavior(prefs_App()->returnKey), 1346 acceptKeyMod_ReturnKeyBehavior(prefs_App()->returnKey),
1346 "valueinput.accept" } }, 1347 "valueinput.accept" } },
1347 2))); 1348 2)));
1348 finalizeSheet_Mobile(dlg); 1349// finalizeSheet_Mobile(dlg);
1350 arrange_Widget(dlg);
1351 setupSheetTransition_Mobile(dlg, incoming_TransitionFlag | top_TransitionDir);
1349 if (parent) { 1352 if (parent) {
1350 setFocus_Widget(as_Widget(input)); 1353 setFocus_Widget(as_Widget(input));
1351 } 1354 }
@@ -1915,6 +1918,7 @@ iWidget *makePreferences_Widget(void) {
1915 { NULL } 1918 { NULL }
1916 }; 1919 };
1917 iWidget *dlg = makePanels_Mobile("prefs", (iMenuItem[]){ 1920 iWidget *dlg = makePanels_Mobile("prefs", (iMenuItem[]){
1921 { "title id:heading.settings" },
1918 { "panel text:" gear_Icon " ${heading.prefs.general}", 0, 0, (const void *) generalPanelItems }, 1922 { "panel text:" gear_Icon " ${heading.prefs.general}", 0, 0, (const void *) generalPanelItems },
1919 { "panel icon:0x1f5a7 id:heading.prefs.network", 0, 0, (const void *) networkPanelItems }, 1923 { "panel icon:0x1f5a7 id:heading.prefs.network", 0, 0, (const void *) networkPanelItems },
1920 { "panel text:" person_Icon " ${sidebar.identities}", 0, 0, (const void *) identityPanelItems }, 1924 { "panel text:" person_Icon " ${sidebar.identities}", 0, 0, (const void *) identityPanelItems },
@@ -2405,7 +2409,7 @@ iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {
2405 arrange_Widget(dlg); 2409 arrange_Widget(dlg);
2406 as_Widget(input)->rect.size.x = 100 * gap_UI - headings->rect.size.x; 2410 as_Widget(input)->rect.size.x = 100 * gap_UI - headings->rect.size.x;
2407 addChild_Widget(get_Root()->widget, iClob(dlg)); 2411 addChild_Widget(get_Root()->widget, iClob(dlg));
2408 finalizeSheet_Mobile(dlg); 2412// finalizeSheet_Mobile(dlg);
2409 } 2413 }
2410 /* Initialize. */ { 2414 /* Initialize. */ {
2411 const iBookmark *bm = bookmarkId ? get_Bookmarks(bookmarks_App(), bookmarkId) : NULL; 2415 const iBookmark *bm = bookmarkId ? get_Bookmarks(bookmarks_App(), bookmarkId) : NULL;
@@ -2419,6 +2423,7 @@ iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {
2419 iTrue); 2423 iTrue);
2420 setCommandHandler_Widget(dlg, handleFeedSettingCommands_); 2424 setCommandHandler_Widget(dlg, handleFeedSettingCommands_);
2421 } 2425 }
2426 setupSheetTransition_Mobile(dlg, incoming_TransitionFlag);
2422 return dlg; 2427 return dlg;
2423} 2428}
2424 2429
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 4fd8f066..659a00cc 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -452,7 +452,7 @@ static void arrange_Widget_(iWidget *d) {
452 else if (d->flags & centerHorizontal_WidgetFlag) { 452 else if (d->flags & centerHorizontal_WidgetFlag) {
453 centerHorizontal_Widget_(d); 453 centerHorizontal_Widget_(d);
454 } 454 }
455 if (d->flags & resizeToParentWidth_WidgetFlag) { 455 if (d->flags & resizeToParentWidth_WidgetFlag && d->parent) {
456 iRect childBounds = zero_Rect(); 456 iRect childBounds = zero_Rect();
457 if (flags_Widget(d->parent) & arrangeWidth_WidgetFlag) { 457 if (flags_Widget(d->parent) & arrangeWidth_WidgetFlag) {
458 /* Can't go narrower than what the children require, though. */ 458 /* Can't go narrower than what the children require, though. */
@@ -462,7 +462,7 @@ static void arrange_Widget_(iWidget *d) {
462 setWidth_Widget_(d, iMaxi(width_Rect(innerRect_Widget_(d->parent)), 462 setWidth_Widget_(d, iMaxi(width_Rect(innerRect_Widget_(d->parent)),
463 width_Rect(childBounds))); 463 width_Rect(childBounds)));
464 } 464 }
465 if (d->flags & resizeToParentHeight_WidgetFlag) { 465 if (d->flags & resizeToParentHeight_WidgetFlag && d->parent) {
466 TRACE(d, "resize to parent height"); 466 TRACE(d, "resize to parent height");
467 setHeight_Widget_(d, height_Rect(innerRect_Widget_(d->parent))); 467 setHeight_Widget_(d, height_Rect(innerRect_Widget_(d->parent)));
468 } 468 }