diff options
Diffstat (limited to 'src/ui/mobile.c')
-rw-r--r-- | src/ui/mobile.c | 134 |
1 files changed, 101 insertions, 33 deletions
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 | ||
91 | static iBool mainDetailSplitHandler_(iWidget *mainDetailSplit, const char *cmd) { | 91 | static 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 | |||
582 | void 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 | ||
1133 | void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) { | 1165 | void 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 | } |