From 1410bbde7779efe3a20f603523547c8b8f55b6a1 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 11 Sep 2021 07:43:57 +0300 Subject: Mobile: Many UI improvements; Upload UI --- src/app.c | 7 +- src/ui/certimportwidget.c | 120 +++++++++++++++++------------ src/ui/documentwidget.c | 9 +-- src/ui/labelwidget.c | 17 +++-- src/ui/mobile.c | 134 +++++++++++++++++++++++++-------- src/ui/mobile.h | 19 ++++- src/ui/root.c | 10 +-- src/ui/uploadwidget.c | 188 +++++++++++++++++++++++++++------------------- src/ui/util.c | 15 ++-- src/ui/widget.c | 4 +- 10 files changed, 328 insertions(+), 195 deletions(-) (limited to 'src') 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) { setUrl_UploadWidget(upload, url); setResponseViewer_UploadWidget(upload, document_App()); addChild_Widget(get_Root()->widget, iClob(upload)); - finalizeSheet_Mobile(as_Widget(upload)); +// finalizeSheet_Mobile(as_Widget(upload)); + setupSheetTransition_Mobile(as_Widget(upload), iTrue); postRefresh_App(); return iTrue; } @@ -2761,7 +2762,9 @@ iBool handleCommand_App(const char *cmd) { iCertImportWidget *imp = new_CertImportWidget(); setPageContent_CertImportWidget(imp, sourceContent_DocumentWidget(document_App())); addChild_Widget(get_Root()->widget, iClob(imp)); - finalizeSheet_Mobile(as_Widget(imp)); +// finalizeSheet_Mobile(as_Widget(imp)); + arrange_Widget(as_Widget(imp)); + setupSheetTransition_Mobile(as_Widget(imp), iTrue); postRefresh_App(); return iTrue; } 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 void init_CertImportWidget(iCertImportWidget *d) { iWidget *w = as_Widget(d); + const iMenuItem actions[] = { +#if defined (iPlatformAppleMobile) + { "${dlg.certimport.pickfile}", 0, 0, "certimport.pickfile" }, + { "---" }, +#endif + { "${cancel}" }, + { uiTextAction_ColorEscape "${dlg.certimport.import}", + SDLK_RETURN, KMOD_PRIMARY, + "certimport.accept" } + }; init_Widget(w); setId_Widget(w, "certimport"); d->cert = NULL; - /* This should behave similar to sheets. */ - useSheetStyle_Widget(w); - addChildFlags_Widget( - w, - iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.certimport}", NULL)), - frameless_WidgetFlag); - d->info = addChildFlags_Widget(w, iClob(new_LabelWidget(infoText_, NULL)), frameless_WidgetFlag); - addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); - d->crtLabel = new_LabelWidget("", NULL); { - setFont_LabelWidget(d->crtLabel, uiContent_FontId); - addChildFlags_Widget(w, iClob(d->crtLabel), 0); - setFrameColor_Widget(as_Widget(d->crtLabel), uiTextCaution_ColorId); + if (isUsingPanelLayout_Mobile()) { + initPanels_Mobile(w, NULL, (iMenuItem[]){ + { "title id:heading.certimport" }, + { format_CStr("label id:certimport.info text:%s", infoText_) }, + //{ "padding" }, + { "label id:certimport.crt nowrap:1 frame:1" }, + { "padding arg:0.25" }, + { "label id:certimport.key nowrap:1 frame:1" }, + { "heading text:${dlg.certimport.notes}" }, + { "input id:certimport.notes hint:hint.certimport.description noheading:1" }, + { NULL } + }, actions, iElemCount(actions)); + d->info = findChild_Widget(w, "certimport.info"); + d->crtLabel = findChild_Widget(w, "certimport.crt"); + d->keyLabel = findChild_Widget(w, "certimport.key"); + d->notes = findChild_Widget(w, "certimport.notes"); + setFixedSize_Widget(as_Widget(d->crtLabel), init_I2(-1, gap_UI * 12)); + setFixedSize_Widget(as_Widget(d->keyLabel), init_I2(-1, gap_UI * 12)); } - d->keyLabel = new_LabelWidget("", NULL); { - setFont_LabelWidget(d->keyLabel, uiContent_FontId); + else { + /* This should behave similar to sheets. */ + useSheetStyle_Widget(w); + addChildFlags_Widget( + w, + iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.certimport}", NULL)), + frameless_WidgetFlag); + d->info = addChildFlags_Widget(w, iClob(new_LabelWidget(infoText_, NULL)), frameless_WidgetFlag); addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); - addChildFlags_Widget(w, iClob(d->keyLabel), 0); - setFrameColor_Widget(as_Widget(d->keyLabel), uiTextCaution_ColorId); - } - addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); - /* TODO: Use makeTwoColumnWidget_() */ - iWidget *page = new_Widget(); { - setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue); - iWidget *headings = addChildFlags_Widget( - page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); - iWidget *values = addChildFlags_Widget( - page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); -// addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.certimport.notes}"))); -// addChild_Widget(values, iClob(d->notes = new_InputWidget(0))); -// setHint_InputWidget(d->notes, "${hint.certimport.description}"); - addTwoColumnDialogInputField_Widget( - headings, - values, - "${dlg.certimport.notes}", - "", - iClob(d->notes = newHint_InputWidget(0, "${hint.certimport.description}"))); - as_Widget(d->notes)->rect.size.x = gap_UI * 70; + d->crtLabel = new_LabelWidget("", NULL); { + setFont_LabelWidget(d->crtLabel, uiContent_FontId); + addChildFlags_Widget(w, iClob(d->crtLabel), 0); + } + d->keyLabel = new_LabelWidget("", NULL); { + setFont_LabelWidget(d->keyLabel, uiContent_FontId); + addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); + addChildFlags_Widget(w, iClob(d->keyLabel), 0); + } + addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); + /* TODO: Use makeTwoColumnWidget_() */ + iWidget *page = new_Widget(); { + setFlags_Widget(page, arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag, iTrue); + iWidget *headings = addChildFlags_Widget( + page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); + iWidget *values = addChildFlags_Widget( + page, iClob(new_Widget()), arrangeVertical_WidgetFlag | arrangeSize_WidgetFlag); + addTwoColumnDialogInputField_Widget( + headings, + values, + "${dlg.certimport.notes}", + "", + iClob(d->notes = newHint_InputWidget(0, "${hint.certimport.description}"))); + as_Widget(d->notes)->rect.size.x = gap_UI * 70; + } + addChild_Widget(w, iClob(page)); + arrange_Widget(w); + setFixedSize_Widget(as_Widget(d->crtLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12)); + setFixedSize_Widget(as_Widget(d->keyLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12)); + /* Buttons. */ + addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); + iWidget *buttons = makeDialogButtons_Widget(actions, iElemCount(actions)); + addChild_Widget(w, iClob(buttons)); } - addChild_Widget(w, iClob(page)); - arrange_Widget(w); - setFixedSize_Widget(as_Widget(d->crtLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12)); - setFixedSize_Widget(as_Widget(d->keyLabel), init_I2(width_Widget(w) - 6.5 * gap_UI, gap_UI * 12)); - /* Buttons. */ - addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); - iWidget *buttons = makeDialogButtons_Widget( - (iMenuItem[]){ { "${cancel}" }, - { uiTextAction_ColorEscape "${dlg.certimport.import}", - SDLK_RETURN, - KMOD_PRIMARY, - "certimport.accept" } }, - 2); - addChild_Widget(w, iClob(buttons)); + setFrameColor_Widget(as_Widget(d->crtLabel), uiTextCaution_ColorId); + setFrameColor_Widget(as_Widget(d->keyLabel), uiTextCaution_ColorId); if (deviceType_App() != desktop_AppDeviceType) { /* Try auto-pasting. */ 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) setUrl_UploadWidget(upload, d->mod.url); setResponseViewer_UploadWidget(upload, d); addChild_Widget(get_Root()->widget, iClob(upload)); - finalizeSheet_Mobile(as_Widget(upload)); +// finalizeSheet_Mobile(as_Widget(upload)); + setupSheetTransition_Mobile(as_Widget(upload), iTrue); postRefresh_App(); } return iTrue; @@ -3679,16 +3680,10 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e { "---" }, { book_Icon " ${menu.page.import}", 0, 0, "bookmark.links confirm:1" }, { globe_Icon " ${menu.page.translate}", 0, 0, "document.translate" }, -#if defined (iPlatformMobile) - { "---" }, - { "${menu.page.copyurl}", 0, 0, "document.copylink" } }, - 14); -#else { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" }, { "---" }, { "${menu.page.copyurl}", 0, 0, "document.copylink" } }, 15); -#endif if (isEmpty_Range(&d->selectMark)) { pushBackN_Array( &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 } } } + if (d->forceFg >= 0) { + *fg = d->forceFg; + } if (isPress) { *bg = uiBackgroundPressed_ColorId | permanent_ColorId; if (isButton) { @@ -257,9 +260,6 @@ static void getColors_LabelWidget_(const iLabelWidget *d, int *bg, int *fg, int *fg = isDark_ColorTheme(colorTheme_App()) ? white_ColorId : black_ColorId; } } - if (d->forceFg >= 0) { - *fg = d->forceFg; - } } iLocalDef int iconPadding_LabelWidget_(const iLabelWidget *d) { @@ -318,6 +318,10 @@ static void draw_LabelWidget_(const iLabelWidget *d) { } setClip_Paint(&p, rect); const int iconPad = iconPadding_LabelWidget_(d); + const int iconColor = isCaution ? uiTextCaution_ColorId + : flags & (disabled_WidgetFlag | pressed_WidgetFlag) ? fg + : isHover ? uiIconHover_ColorId + : uiIcon_ColorId; if (d->icon && d->icon != 0x20) { /* no need to draw an empty icon */ iString str; initUnicodeN_String(&str, &d->icon, 1); @@ -331,10 +335,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { -gap_UI / 8)), init_I2(iconPad, lineHeight_Text(d->font)) }, iTrue, - isCaution ? uiTextCaution_ColorId - : flags & (disabled_WidgetFlag | pressed_WidgetFlag) ? fg - : isHover ? uiIconHover_ColorId - : uiIcon_ColorId, + iconColor, "%s", cstr_String(&str)); deinit_String(&str); @@ -387,7 +388,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { drawCentered_Text(d->font, (iRect){ addX_I2(topRight_Rect(chRect), -iconPad), init_I2(chSize, height_Rect(chRect)) }, - iTrue, uiSeparator_ColorId, rightAngle_Icon); + iTrue, iconColor /*uiSeparator_ColorId*/, rightAngle_Icon); } unsetClip_Paint(&p); } 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) { static iBool mainDetailSplitHandler_(iWidget *mainDetailSplit, const char *cmd) { if (equal_Command(cmd, "window.resized")) { - const iBool isPortrait = (deviceType_App() == phone_AppDeviceType && isPortrait_App()); - const iRect safeRoot = safeRect_Root(mainDetailSplit->root); - setPos_Widget(mainDetailSplit, topLeft_Rect(safeRoot)); - setFixedSize_Widget(mainDetailSplit, safeRoot.size); + const iBool isPortrait = (deviceType_App() == phone_AppDeviceType && isPortrait_App()); + const iRect safeRoot = safeRect_Root(mainDetailSplit->root); iWidget * sheet = parent_Widget(mainDetailSplit); iWidget * navi = findChild_Widget(sheet, "panel.navi"); iWidget * detailStack = findChild_Widget(mainDetailSplit, "detailstack"); const size_t numPanels = childCount_Widget(detailStack); const iBool isSideBySide = isSideBySideLayout_() && numPanels > 0; + setPos_Widget(mainDetailSplit, topLeft_Rect(safeRoot)); + setFixedSize_Widget(mainDetailSplit, safeRoot.size); setFlags_Widget(mainDetailSplit, arrangeHorizontal_WidgetFlag, isSideBySide); setFlags_Widget(detailStack, expand_WidgetFlag, isSideBySide); setFlags_Widget(detailStack, hidden_WidgetFlag, numPanels == 0); @@ -172,7 +172,16 @@ static iBool topPanelHandler_(iWidget *topPanel, const char *cmd) { } unselectAllPanelButtons_(topPanel); if (!wasClosed) { - postCommand_App("prefs.dismiss"); + /* TODO: Should come up with a more general-purpose approach here. */ + if (findWidget_App("prefs")) { + postCommand_App("prefs.dismiss"); + } + else if (findWidget_App("upload")) { + postCommand_App("upload.cancel"); + } + else { + postCommand_App("cancel"); + } } return iTrue; } @@ -503,11 +512,19 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { else if (equal_Command(spec, "label")) { iLabelWidget *lab = new_LabelWidget(label, NULL); widget = as_Widget(lab); - setWrap_LabelWidget(lab, iTrue); - setFlags_Widget(widget, fixedHeight_WidgetFlag | frameless_WidgetFlag, iTrue); + setId_Widget(widget, id); + setWrap_LabelWidget(lab, !argLabel_Command(spec, "nowrap")); + setFlags_Widget(widget, + fixedHeight_WidgetFlag | + (!argLabel_Command(spec, "frame") ? frameless_WidgetFlag : 0), + iTrue); } else if (equal_Command(spec, "padding")) { - widget = makePadding_Widget(lineHeight_Text(labelFont_()) * 1.5f); + float height = 1.5f; + if (hasLabel_Command(spec, "arg")) { + height *= argfLabel_Command(spec, "arg"); + } + widget = makePadding_Widget(lineHeight_Text(labelFont_()) * height); } /* Apply common styling to the heading. */ if (heading) { @@ -539,7 +556,7 @@ static const iMenuItem *findDialogCancelAction_(const iMenuItem *items, size_t n return NULL; } for (size_t i = 0; i < n; i++) { - if (!iCmpStr(items[i].label, "${cancel}")) { + if (!iCmpStr(items[i].label, "${cancel}") || !iCmpStr(items[i].label, "${close}")) { return &items[i]; } } @@ -556,13 +573,20 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget, const char *id, const iMenuItem *itemsNullTerminated, const iMenuItem *actions, size_t numActions) { + iWidget *panels = new_Widget(); + setId_Widget(panels, id); + initPanels_Mobile(panels, parentWidget, itemsNullTerminated, actions, numActions); + return panels; +} + +void initPanels_Mobile(iWidget *panels, iWidget *parentWidget, + const iMenuItem *itemsNullTerminated, + const iMenuItem *actions, size_t numActions) { /* A multipanel widget has a top panel and one or more detail panels. In a horizontal layout, the detail panels slide in from the right and cover the top panel. In a landscape layout, the detail panels are always visible on the side. */ - iWidget *sheet = new_Widget(); - setId_Widget(sheet, id); - setBackgroundColor_Widget(sheet, uiBackground_ColorId); - setFlags_Widget(sheet, + setBackgroundColor_Widget(panels, uiBackground_ColorId); + setFlags_Widget(panels, resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag | frameless_WidgetFlag | focusRoot_WidgetFlag | commandOnClick_WidgetFlag | overflowScrollable_WidgetFlag | leftEdgeDraggable_WidgetFlag, @@ -572,7 +596,7 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget, setCommandHandler_Widget(mainDetailSplit, mainDetailSplitHandler_); setFlags_Widget(mainDetailSplit, resizeHeightOfChildren_WidgetFlag, iFalse); setId_Widget(mainDetailSplit, "mdsplit"); - addChild_Widget(sheet, iClob(mainDetailSplit)); + addChild_Widget(panels, iClob(mainDetailSplit)); } /* The panel roots. */ iWidget *topPanel = new_Widget(); { @@ -591,7 +615,6 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget, setFlags_Widget(detailStack, collapse_WidgetFlag | resizeWidthOfChildren_WidgetFlag, iTrue); addChild_Widget(mainDetailSplit, iClob(detailStack)); } - addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); /* Slide top panel with detail panels. */ { setFlags_Widget(topPanel, refChildrenOffset_WidgetFlag, iTrue); topPanel->offsetRef = detailStack; @@ -612,15 +635,17 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget, checkIcon_LabelWidget(naviBack); setId_Widget(as_Widget(naviBack), "panel.back"); setFont_LabelWidget(naviBack, labelFont_()); - addChildFlags_Widget(sheet, iClob(navi), + addChildFlags_Widget(panels, iClob(navi), drawBackgroundToVerticalSafeArea_WidgetFlag | arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag | resizeToParentWidth_WidgetFlag | arrangeVertical_WidgetFlag); } + iBool haveDetailPanels = iFalse; /* Create panel contents based on provided items. */ for (size_t i = 0; itemsNullTerminated[i].label; i++) { const iMenuItem *item = &itemsNullTerminated[i]; if (equal_Command(item->label, "panel")) { + haveDetailPanels = iTrue; const char *id = cstr_Rangecc(range_Command(item->label, "id")); const iString *label = hasLabel_Command(item->label, "text") ? collect_String(suffix_Command(item->label, "text")) @@ -655,10 +680,12 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget, setFont_LabelWidget(naviBack, labelBoldFont_()); } else if (defaultItem && defaultItem != cancelItem) { - updateTextCStr_LabelWidget(naviBack, cancelItem->label); - setCommand_LabelWidget(naviBack, collectNewCStr_String(cancelItem->command - ? cancelItem->command - : "cancel")); + if (!haveDetailPanels) { + updateTextCStr_LabelWidget(naviBack, cancelItem->label); + setCommand_LabelWidget(naviBack, collectNewCStr_String(cancelItem->command + ? cancelItem->command + : "cancel")); + } iLabelWidget *defaultButton = new_LabelWidget(defaultItem->label, defaultItem->command); setFont_LabelWidget(defaultButton, labelBoldFont_()); setFlags_Widget(as_Widget(defaultButton), @@ -689,16 +716,21 @@ iWidget *makePanelsParent_Mobile(iWidget *parentWidget, } makePanelItem_Mobile( topPanel, - &(iMenuItem){ format_CStr("button text:%s", act->label), 0, 0, act->command }); + &(iMenuItem){ format_CStr("button text:" uiTextAction_ColorEscape "%s", act->label), + 0, + 0, + act->command }); } } /* Finalize the layout. */ - addChild_Widget(parentWidget, iClob(sheet)); + if (parentWidget) { + addChild_Widget(parentWidget, iClob(panels)); + } mainDetailSplitHandler_(mainDetailSplit, "window.resized"); /* make it resize the split */ - updatePanelSheetMetrics_(sheet); - arrange_Widget(sheet); + updatePanelSheetMetrics_(panels); + arrange_Widget(panels); postCommand_App("widget.overflow"); /* with the correct dimensions */ - return sheet; + printTree_Widget(panels); } #if 0 @@ -1130,7 +1162,9 @@ void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) { } } -void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) { +void setupSheetTransition_Mobile(iWidget *sheet, int flags) { + const iBool isIncoming = (flags & incoming_TransitionFlag) != 0; + const int dir = flags & dirMask_TransitionFlag; if (!isUsingPanelLayout_Mobile()) { if (prefs_App()->uiAnimations) { setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iFalse); @@ -1144,17 +1178,51 @@ void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) { } return; } - if(isSideBySideLayout_()) { + if (isSideBySideLayout_()) { + /* TODO: Landscape transitions? */ return; } - setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iTrue); + setFlags_Widget(sheet, + horizontalOffset_WidgetFlag, + dir == right_TransitionDir || dir == left_TransitionDir); if (isIncoming) { - setVisualOffset_Widget(sheet, size_Root(sheet->root).x, 0, 0); + switch (dir) { + case right_TransitionDir: + setVisualOffset_Widget(sheet, size_Root(sheet->root).x, 0, 0); + break; + case left_TransitionDir: + setVisualOffset_Widget(sheet, -size_Root(sheet->root).x, 0, 0); + break; + case top_TransitionDir: + setVisualOffset_Widget( + sheet, -bottom_Rect(boundsWithoutVisualOffset_Widget(sheet)), 0, 0); + break; + case bottom_TransitionDir: + setVisualOffset_Widget(sheet, height_Widget(sheet), 0, 0); + break; + } setVisualOffset_Widget(sheet, 0, 200, easeOut_AnimFlag); - } + } else { - const iBool wasDragged = iAbs(value_Anim(&sheet->visualOffset)) > 0; - setVisualOffset_Widget(sheet, size_Root(sheet->root).x, wasDragged ? 100 : 200, - wasDragged ? 0 : easeIn_AnimFlag); + switch (dir) { + case right_TransitionDir: { + const iBool wasDragged = iAbs(value_Anim(&sheet->visualOffset)) > 0; + setVisualOffset_Widget(sheet, size_Root(sheet->root).x, wasDragged ? 100 : 200, + wasDragged ? 0 : easeIn_AnimFlag); + break; + } + case left_TransitionDir: + setVisualOffset_Widget(sheet, -size_Root(sheet->root).x, 200, easeIn_AnimFlag); + break; + case top_TransitionDir: + setVisualOffset_Widget(sheet, + -bottom_Rect(boundsWithoutVisualOffset_Widget(sheet)), + 200, + easeIn_AnimFlag); + break; + case bottom_TransitionDir: + setVisualOffset_Widget(sheet, height_Widget(sheet), 200, easeIn_AnimFlag); + break; + } } } 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, const char *id, const iMenuItem *itemsNullTerminated, const iMenuItem *actions, size_t numActions); +void initPanels_Mobile (iWidget *panels, iWidget *parentWidget, + const iMenuItem *itemsNullTerminated, + const iMenuItem *actions, size_t numActions); + +enum iTransitionFlags { + incoming_TransitionFlag = iBit(1), + dirMask_TransitionFlag = iBit(2) | iBit(3), +}; + +enum iTransitionDir { + right_TransitionDir = 0, + bottom_TransitionDir = 2, + left_TransitionDir = 4, + top_TransitionDir = 6, +}; -void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming); -void setupSheetTransition_Mobile (iWidget *sheet, iBool isIncoming); +void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming); +void setupSheetTransition_Mobile (iWidget *sheet, int flags); void 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_[] = { { "${menu.downloads}", 0, 0, "downloads.open" }, { "${menu.feeds.entrylist}", 0, 0, "!open url:about:feeds" }, { "---" }, - { gear_Icon " Settings...", SDLK_COMMA, KMOD_PRIMARY, "preferences" }, + { gear_Icon " ${menu.settings}", SDLK_COMMA, KMOD_PRIMARY, "preferences" }, }; #endif /* Mobile */ @@ -1163,20 +1163,12 @@ void createUserInterface_Root(iRoot *d) { { star_Icon " ${menu.page.subscribe}", subscribeToPage_KeyModifier, "feeds.subscribe" }, { book_Icon " ${menu.page.import}", 0, 0, "bookmark.links confirm:1" }, { globe_Icon " ${menu.page.translate}", 0, 0, "document.translate" }, -#if defined (iPlatformMobile) - { "---" }, - { "${menu.page.copyurl}", 0, 0, "document.copylink" }, - { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" }, - { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } }, - 11); -#else { upload_Icon " ${menu.page.upload}", 0, 0, "document.upload" }, { "---" }, { "${menu.page.copyurl}", 0, 0, "document.copylink" }, { "${menu.page.copysource}", 'c', KMOD_PRIMARY, "copy" }, { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } }, 12); -#endif setId_Widget(as_Widget(pageMenuButton), "pagemenubutton"); setFont_LabelWidget(pageMenuButton, uiContentBold_FontId); 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) { iWidget *w = as_Widget(d); init_Widget(w); setId_Widget(w, "upload"); - useSheetStyle_Widget(w); init_String(&d->originalUrl); init_String(&d->url); d->viewer = NULL; d->request = NULL; init_String(&d->filePath); d->fileSize = 0; - addChildFlags_Widget(w, - iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.upload}", NULL)), - frameless_WidgetFlag); - d->info = addChildFlags_Widget(w, iClob(new_LabelWidget("", NULL)), - frameless_WidgetFlag | resizeToParentWidth_WidgetFlag | - fixedHeight_WidgetFlag); - setWrap_LabelWidget(d->info, iTrue); - /* Tabs for input data. */ - iWidget *tabs = makeTabs_Widget(w); - /* Make the tabs support vertical expansion based on content. */ { - setFlags_Widget(tabs, resizeHeightOfChildren_WidgetFlag, iFalse); - setFlags_Widget(tabs, arrangeHeight_WidgetFlag, iTrue); - iWidget *tabPages = findChild_Widget(tabs, "tabs.pages"); - setFlags_Widget(tabPages, resizeHeightOfChildren_WidgetFlag, iFalse); - setFlags_Widget(tabPages, arrangeHeight_WidgetFlag, iTrue); + const iMenuItem actions[] = { + { "${upload.port}", 0, 0, "upload.setport" }, + { "---" }, + { "${close}", SDLK_ESCAPE, 0, "upload.cancel" }, + { uiTextAction_ColorEscape "${dlg.upload.send}", SDLK_RETURN, KMOD_PRIMARY, "upload.accept" } + }; + if (isUsingPanelLayout_Mobile()) { + const iMenuItem textItems[] = { + { "title id:heading.upload.text" }, + { "input id:upload.text noheading:1" }, + { NULL } + }; + const iMenuItem fileItems[] = { + { "title id:heading.upload.file" }, + { "button text:" uiTextAction_ColorEscape "${dlg.upload.pickfile}", 0, 0, "upload.pickfile" }, + { "heading id:upload.file.name" }, + { "label id:upload.filepathlabel" }, + { "heading id:upload.file.size" }, + { "label id:upload.filesizelabel" }, + { "padding" }, + { "input id:upload.mime" }, + { "label id:upload.counter text:" }, + { NULL } + }; + initPanels_Mobile(w, NULL, (iMenuItem[]){ + { "title id:heading.upload" }, + { "label id:upload.info" }, +// { "padding" }, + { "panel id:dlg.upload.text icon:0x1f5b9", 0, 0, (const void *) textItems }, + { "panel id:dlg.upload.file icon:0x1f4c1", 0, 0, (const void *) fileItems }, + { "padding" }, + { "input id:upload.token hint:hint.upload.token" }, + { NULL } + }, actions, iElemCount(actions)); + d->info = findChild_Widget(w, "upload.info"); + d->input = findChild_Widget(w, "upload.text"); + d->filePathLabel = findChild_Widget(w, "upload.file.name"); + d->fileSizeLabel = findChild_Widget(w, "upload.file.size"); + d->mime = findChild_Widget(w, "upload.mime"); + d->token = findChild_Widget(w, "upload.token"); + d->counter = findChild_Widget(w, "upload.counter"); } - iWidget *headings, *values; - setBackgroundColor_Widget(findChild_Widget(tabs, "tabs.buttons"), uiBackgroundSidebar_ColorId); - setId_Widget(tabs, "upload.tabs"); -// const int bigGap = lineHeight_Text(uiLabel_FontId) * 3 / 4; - /* Text input. */ { - //appendTwoColumnTabPage_Widget(tabs, "${heading.upload.text}", '1', &headings, &values); - iWidget *page = new_Widget(); - setFlags_Widget(page, arrangeSize_WidgetFlag, iTrue); - d->input = new_InputWidget(0); - setId_Widget(as_Widget(d->input), "upload.text"); - setFont_InputWidget(d->input, monospace_FontId); - setLineLimits_InputWidget(d->input, 7, 20); - setUseReturnKeyBehavior_InputWidget(d->input, iFalse); /* traditional text editor */ - setHint_InputWidget(d->input, "${hint.upload.text}"); - setFixedSize_Widget(as_Widget(d->input), init_I2(120 * gap_UI, -1)); - addChild_Widget(page, iClob(d->input)); - appendFramelessTabPage_Widget(tabs, iClob(page), "${heading.upload.text}", '1', 0); - } - /* File content. */ { - appendTwoColumnTabPage_Widget(tabs, "${heading.upload.file}", '2', &headings, &values); -// iWidget *pad = addChild_Widget(headings, iClob(makePadding_Widget(0))); -// iWidget *hint = addChild_Widget(values, iClob(new_LabelWidget("${upload.file.drophint}", NULL))); -// pad->sizeRef = hint; - addChildFlags_Widget(headings, iClob(new_LabelWidget("${upload.file.name}", NULL)), frameless_WidgetFlag); - d->filePathLabel = addChildFlags_Widget(values, iClob(new_LabelWidget(uiTextAction_ColorEscape "${upload.file.drophere}", NULL)), frameless_WidgetFlag); - addChildFlags_Widget(headings, iClob(new_LabelWidget("${upload.file.size}", NULL)), frameless_WidgetFlag); - d->fileSizeLabel = addChildFlags_Widget(values, iClob(new_LabelWidget("\u2014", NULL)), frameless_WidgetFlag); - d->mime = new_InputWidget(0); - setFixedSize_Widget(as_Widget(d->mime), init_I2(70 * gap_UI, -1)); - addTwoColumnDialogInputField_Widget(headings, values, "${upload.mime}", "upload.mime", iClob(d->mime)); - } - /* Token. */ { - addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); - iWidget *page = makeTwoColumns_Widget(&headings, &values); - d->token = addTwoColumnDialogInputField_Widget( - headings, values, "${upload.token}", "upload.token", iClob(new_InputWidget(0))); - setHint_InputWidget(d->token, "${hint.upload.token}"); - setFixedSize_Widget(as_Widget(d->token), init_I2(50 * gap_UI, -1)); - addChild_Widget(w, iClob(page)); - } - /* Buttons. */ { - addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); - iWidget *buttons = - makeDialogButtons_Widget((iMenuItem[]){ { "${upload.port}", 0, 0, "upload.setport" }, - { "---" }, - { "${close}", SDLK_ESCAPE, 0, "upload.cancel" }, - { uiTextAction_ColorEscape "${dlg.upload.send}", - SDLK_RETURN, - KMOD_PRIMARY, - "upload.accept" } }, - 4); - setId_Widget(insertChildAfterFlags_Widget(buttons, - iClob(d->counter = new_LabelWidget("", NULL)), - 0, frameless_WidgetFlag), - "upload.counter"); - addChild_Widget(w, iClob(buttons)); + else { + useSheetStyle_Widget(w); + addChildFlags_Widget(w, + iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.upload}", NULL)), + frameless_WidgetFlag); + d->info = addChildFlags_Widget(w, iClob(new_LabelWidget("", NULL)), + frameless_WidgetFlag | resizeToParentWidth_WidgetFlag | + fixedHeight_WidgetFlag); + setWrap_LabelWidget(d->info, iTrue); + /* Tabs for input data. */ + iWidget *tabs = makeTabs_Widget(w); + /* Make the tabs support vertical expansion based on content. */ { + setFlags_Widget(tabs, resizeHeightOfChildren_WidgetFlag, iFalse); + setFlags_Widget(tabs, arrangeHeight_WidgetFlag, iTrue); + iWidget *tabPages = findChild_Widget(tabs, "tabs.pages"); + setFlags_Widget(tabPages, resizeHeightOfChildren_WidgetFlag, iFalse); + setFlags_Widget(tabPages, arrangeHeight_WidgetFlag, iTrue); + } + iWidget *headings, *values; + setBackgroundColor_Widget(findChild_Widget(tabs, "tabs.buttons"), uiBackgroundSidebar_ColorId); + setId_Widget(tabs, "upload.tabs"); + /* Text input. */ { + iWidget *page = new_Widget(); + setFlags_Widget(page, arrangeSize_WidgetFlag, iTrue); + d->input = new_InputWidget(0); + setId_Widget(as_Widget(d->input), "upload.text"); + setFixedSize_Widget(as_Widget(d->input), init_I2(120 * gap_UI, -1)); + addChild_Widget(page, iClob(d->input)); + appendFramelessTabPage_Widget(tabs, iClob(page), "${heading.upload.text}", '1', 0); + } + /* File content. */ { + appendTwoColumnTabPage_Widget(tabs, "${heading.upload.file}", '2', &headings, &values); + addChildFlags_Widget(headings, iClob(new_LabelWidget("${upload.file.name}", NULL)), frameless_WidgetFlag); + d->filePathLabel = addChildFlags_Widget(values, iClob(new_LabelWidget(uiTextAction_ColorEscape "${upload.file.drophere}", NULL)), frameless_WidgetFlag); + addChildFlags_Widget(headings, iClob(new_LabelWidget("${upload.file.size}", NULL)), frameless_WidgetFlag); + d->fileSizeLabel = addChildFlags_Widget(values, iClob(new_LabelWidget("\u2014", NULL)), frameless_WidgetFlag); + d->mime = new_InputWidget(0); + setFixedSize_Widget(as_Widget(d->mime), init_I2(70 * gap_UI, -1)); + addTwoColumnDialogInputField_Widget(headings, values, "${upload.mime}", "upload.mime", iClob(d->mime)); + } + /* Token. */ { + addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); + iWidget *page = makeTwoColumns_Widget(&headings, &values); + d->token = addTwoColumnDialogInputField_Widget( + headings, values, "${upload.token}", "upload.token", iClob(new_InputWidget(0))); + setHint_InputWidget(d->token, "${hint.upload.token}"); + setFixedSize_Widget(as_Widget(d->token), init_I2(50 * gap_UI, -1)); + addChild_Widget(w, iClob(page)); + } + /* Buttons. */ { + addChild_Widget(w, iClob(makePadding_Widget(gap_UI))); + iWidget *buttons = makeDialogButtons_Widget(actions, iElemCount(actions)); + setId_Widget(insertChildAfterFlags_Widget(buttons, + iClob(d->counter = new_LabelWidget("", NULL)), + 0, frameless_WidgetFlag), + "upload.counter"); + addChild_Widget(w, iClob(buttons)); + } + resizeToLargestPage_Widget(tabs); + arrange_Widget(w); + setFixedSize_Widget(as_Widget(d->token), init_I2(width_Widget(tabs) - left_Rect(parent_Widget(d->token)->rect), -1)); + setFlags_Widget(as_Widget(d->token), expand_WidgetFlag, iTrue); + setFocus_Widget(as_Widget(d->input)); } - resizeToLargestPage_Widget(tabs); - arrange_Widget(w); - setFixedSize_Widget(as_Widget(d->token), init_I2(width_Widget(tabs) - left_Rect(parent_Widget(d->token)->rect), -1)); - setFlags_Widget(as_Widget(d->token), expand_WidgetFlag, iTrue); - setFocus_Widget(as_Widget(d->input)); + setFont_InputWidget(d->input, monospace_FontId); + setUseReturnKeyBehavior_InputWidget(d->input, iFalse); /* traditional text editor */ + setLineLimits_InputWidget(d->input, 7, 20); + setHint_InputWidget(d->input, "${hint.upload.text}"); setBackupFileName_InputWidget(d->input, "uploadbackup.txt"); updateInputMaxHeight_UploadWidget_(d); } @@ -201,6 +232,7 @@ static void setUrlPort_UploadWidget_(iUploadWidget *d, const iString *url, uint1 appendFormat_String(&d->url, ":%u", overridePort ? overridePort : titanPortForUrl_(url)); appendRange_String(&d->url, (iRangecc){ parts.path.start, constEnd_String(url) }); setText_LabelWidget(d->info, &d->url); + arrange_Widget(as_Widget(d)); } void setUrl_UploadWidget(iUploadWidget *d, const iString *url) { @@ -233,7 +265,7 @@ static iBool processEvent_UploadWidget_(iUploadWidget *d, const SDL_Event *ev) { if (isResize_UserEvent(ev)) { updateInputMaxHeight_UploadWidget_(d); } - if (isCommand_Widget(w, ev, "upload.cancel")) { + if (equal_Command(cmd, "upload.cancel")) { setupSheetTransition_Mobile(w, iFalse); destroy_Widget(w); 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) { } void resizeToLargestPage_Widget(iWidget *tabs) { + if (!tabs) return; // puts("RESIZE TO LARGEST PAGE ..."); iWidget *pages = findChild_Widget(tabs, "tabs.pages"); iForEach(ObjectList, i, children_Widget(pages)) { @@ -1216,7 +1217,7 @@ iBool valueInputHandler_(iWidget *dlg, const char *cmd) { postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg))); setId_Widget(dlg, ""); /* no further commands to emit */ } - setupSheetTransition_Mobile(dlg, iFalse); + setupSheetTransition_Mobile(dlg, top_TransitionDir); destroy_Widget(dlg); return iTrue; } @@ -1225,13 +1226,13 @@ iBool valueInputHandler_(iWidget *dlg, const char *cmd) { else if (equal_Command(cmd, "valueinput.cancel")) { postCommandf_App("valueinput.cancelled id:%s", cstr_String(id_Widget(dlg))); setId_Widget(dlg, ""); /* no further commands to emit */ - setupSheetTransition_Mobile(dlg, iFalse); + setupSheetTransition_Mobile(dlg, top_TransitionDir); destroy_Widget(dlg); return iTrue; } else if (equal_Command(cmd, "valueinput.accept")) { acceptValueInput_(dlg); - setupSheetTransition_Mobile(dlg, iFalse); + setupSheetTransition_Mobile(dlg, top_TransitionDir); destroy_Widget(dlg); return iTrue; } @@ -1345,7 +1346,9 @@ iWidget *makeValueInput_Widget(iWidget *parent, const iString *initialValue, con acceptKeyMod_ReturnKeyBehavior(prefs_App()->returnKey), "valueinput.accept" } }, 2))); - finalizeSheet_Mobile(dlg); +// finalizeSheet_Mobile(dlg); + arrange_Widget(dlg); + setupSheetTransition_Mobile(dlg, incoming_TransitionFlag | top_TransitionDir); if (parent) { setFocus_Widget(as_Widget(input)); } @@ -1915,6 +1918,7 @@ iWidget *makePreferences_Widget(void) { { NULL } }; iWidget *dlg = makePanels_Mobile("prefs", (iMenuItem[]){ + { "title id:heading.settings" }, { "panel text:" gear_Icon " ${heading.prefs.general}", 0, 0, (const void *) generalPanelItems }, { "panel icon:0x1f5a7 id:heading.prefs.network", 0, 0, (const void *) networkPanelItems }, { "panel text:" person_Icon " ${sidebar.identities}", 0, 0, (const void *) identityPanelItems }, @@ -2405,7 +2409,7 @@ iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) { arrange_Widget(dlg); as_Widget(input)->rect.size.x = 100 * gap_UI - headings->rect.size.x; addChild_Widget(get_Root()->widget, iClob(dlg)); - finalizeSheet_Mobile(dlg); +// finalizeSheet_Mobile(dlg); } /* Initialize. */ { const iBookmark *bm = bookmarkId ? get_Bookmarks(bookmarks_App(), bookmarkId) : NULL; @@ -2419,6 +2423,7 @@ iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) { iTrue); setCommandHandler_Widget(dlg, handleFeedSettingCommands_); } + setupSheetTransition_Mobile(dlg, incoming_TransitionFlag); return dlg; } 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) { else if (d->flags & centerHorizontal_WidgetFlag) { centerHorizontal_Widget_(d); } - if (d->flags & resizeToParentWidth_WidgetFlag) { + if (d->flags & resizeToParentWidth_WidgetFlag && d->parent) { iRect childBounds = zero_Rect(); if (flags_Widget(d->parent) & arrangeWidth_WidgetFlag) { /* Can't go narrower than what the children require, though. */ @@ -462,7 +462,7 @@ static void arrange_Widget_(iWidget *d) { setWidth_Widget_(d, iMaxi(width_Rect(innerRect_Widget_(d->parent)), width_Rect(childBounds))); } - if (d->flags & resizeToParentHeight_WidgetFlag) { + if (d->flags & resizeToParentHeight_WidgetFlag && d->parent) { TRACE(d, "resize to parent height"); setHeight_Widget_(d, height_Rect(innerRect_Widget_(d->parent))); } -- cgit v1.2.3