diff options
Diffstat (limited to 'src/ui/mobile.c')
-rw-r--r-- | src/ui/mobile.c | 106 |
1 files changed, 96 insertions, 10 deletions
diff --git a/src/ui/mobile.c b/src/ui/mobile.c index 7e359a84..f3e23e06 100644 --- a/src/ui/mobile.c +++ b/src/ui/mobile.c | |||
@@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
36 | # include "ios.h" | 36 | # include "ios.h" |
37 | #endif | 37 | #endif |
38 | 38 | ||
39 | static iBool useMobileSheetLayout_(void) { | 39 | iBool isUsingPanelLayout_Mobile(void) { |
40 | return deviceType_App() != desktop_AppDeviceType; | 40 | return deviceType_App() != desktop_AppDeviceType; |
41 | } | 41 | } |
42 | 42 | ||
@@ -381,6 +381,7 @@ static size_t countItems_(const iMenuItem *itemsNullTerminated) { | |||
381 | void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { | 381 | void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { |
382 | iWidget * widget = NULL; | 382 | iWidget * widget = NULL; |
383 | iLabelWidget *heading = NULL; | 383 | iLabelWidget *heading = NULL; |
384 | iWidget * value = NULL; | ||
384 | const char * spec = item->label; | 385 | const char * spec = item->label; |
385 | const char * id = cstr_Rangecc(range_Command(spec, "id")); | 386 | const char * id = cstr_Rangecc(range_Command(spec, "id")); |
386 | const char * label = hasLabel_Command(spec, "text") | 387 | const char * label = hasLabel_Command(spec, "text") |
@@ -396,6 +397,7 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { | |||
396 | setFont_LabelWidget(title, uiLabelLargeBold_FontId); | 397 | setFont_LabelWidget(title, uiLabelLargeBold_FontId); |
397 | setTextColor_LabelWidget(title, uiHeading_ColorId); | 398 | setTextColor_LabelWidget(title, uiHeading_ColorId); |
398 | setAllCaps_LabelWidget(title, iTrue); | 399 | setAllCaps_LabelWidget(title, iTrue); |
400 | setId_Widget(as_Widget(title), id); | ||
399 | } | 401 | } |
400 | else if (equal_Command(spec, "heading")) { | 402 | else if (equal_Command(spec, "heading")) { |
401 | addChild_Widget(panel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); | 403 | addChild_Widget(panel, iClob(makePadding_Widget(lineHeight_Text(labelFont_())))); |
@@ -403,6 +405,7 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { | |||
403 | setAllCaps_LabelWidget(heading, iTrue); | 405 | setAllCaps_LabelWidget(heading, iTrue); |
404 | setRemoveTrailingColon_LabelWidget(heading, iTrue); | 406 | setRemoveTrailingColon_LabelWidget(heading, iTrue); |
405 | addChild_Widget(panel, iClob(heading)); | 407 | addChild_Widget(panel, iClob(heading)); |
408 | setId_Widget(as_Widget(heading), id); | ||
406 | } | 409 | } |
407 | else if (equal_Command(spec, "toggle")) { | 410 | else if (equal_Command(spec, "toggle")) { |
408 | iLabelWidget *toggle = (iLabelWidget *) makeToggle_Widget(id); | 411 | iLabelWidget *toggle = (iLabelWidget *) makeToggle_Widget(id); |
@@ -412,7 +415,9 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { | |||
412 | } | 415 | } |
413 | else if (equal_Command(spec, "dropdown")) { | 416 | else if (equal_Command(spec, "dropdown")) { |
414 | const iMenuItem *dropItems = item->data; | 417 | const iMenuItem *dropItems = item->data; |
415 | iLabelWidget *drop = makeMenuButton_LabelWidget("", dropItems, countItems_(dropItems)); | 418 | iLabelWidget *drop = makeMenuButton_LabelWidget(dropItems[0].label, |
419 | dropItems, countItems_(dropItems)); | ||
420 | value = as_Widget(drop); | ||
416 | setFont_LabelWidget(drop, labelFont_()); | 421 | setFont_LabelWidget(drop, labelFont_()); |
417 | setFlags_Widget(as_Widget(drop), | 422 | setFlags_Widget(as_Widget(drop), |
418 | alignRight_WidgetFlag | noBackground_WidgetFlag | | 423 | alignRight_WidgetFlag | noBackground_WidgetFlag | |
@@ -465,6 +470,9 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { | |||
465 | } | 470 | } |
466 | else if (equal_Command(spec, "input")) { | 471 | else if (equal_Command(spec, "input")) { |
467 | iInputWidget *input = new_InputWidget(argU32Label_Command(spec, "maxlen")); | 472 | iInputWidget *input = new_InputWidget(argU32Label_Command(spec, "maxlen")); |
473 | if (hasLabel_Command(spec, "hint")) { | ||
474 | setHint_InputWidget(input, cstr_Lang(cstr_Rangecc(range_Command(spec, "hint")))); | ||
475 | } | ||
468 | setId_Widget(as_Widget(input), id); | 476 | setId_Widget(as_Widget(input), id); |
469 | setUrlContent_InputWidget(input, argLabel_Command(spec, "url")); | 477 | setUrlContent_InputWidget(input, argLabel_Command(spec, "url")); |
470 | setSelectAllOnFocus_InputWidget(input, argLabel_Command(spec, "selectall")); | 478 | setSelectAllOnFocus_InputWidget(input, argLabel_Command(spec, "selectall")); |
@@ -491,6 +499,12 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { | |||
491 | else if (equal_Command(spec, "button")) { | 499 | else if (equal_Command(spec, "button")) { |
492 | widget = as_Widget(heading = makePanelButton_(label, item->command)); | 500 | widget = as_Widget(heading = makePanelButton_(label, item->command)); |
493 | } | 501 | } |
502 | else if (equal_Command(spec, "label")) { | ||
503 | iLabelWidget *lab = new_LabelWidget(label, NULL); | ||
504 | widget = as_Widget(lab); | ||
505 | setWrap_LabelWidget(lab, iTrue); | ||
506 | setFlags_Widget(widget, frameless_WidgetFlag, iTrue); | ||
507 | } | ||
494 | else if (equal_Command(spec, "padding")) { | 508 | else if (equal_Command(spec, "padding")) { |
495 | widget = makePadding_Widget(lineHeight_Text(labelFont_()) * 1.5f); | 509 | widget = makePadding_Widget(lineHeight_Text(labelFont_()) * 1.5f); |
496 | } | 510 | } |
@@ -500,8 +514,14 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { | |||
500 | if (icon) { | 514 | if (icon) { |
501 | setIcon_LabelWidget(heading, icon); | 515 | setIcon_LabelWidget(heading, icon); |
502 | } | 516 | } |
517 | if (value && as_Widget(heading) != value) { | ||
518 | as_Widget(heading)->sizeRef = value; /* heading height matches value widget */ | ||
519 | } | ||
503 | } | 520 | } |
504 | if (widget) { | 521 | if (widget) { |
522 | setFlags_Widget(widget, | ||
523 | collapse_WidgetFlag | hidden_WidgetFlag, | ||
524 | argLabel_Command(spec, "collapse") != 0); | ||
505 | addChild_Widget(panel, iClob(widget)); | 525 | addChild_Widget(panel, iClob(widget)); |
506 | } | 526 | } |
507 | } | 527 | } |
@@ -512,11 +532,26 @@ void makePanelItems_Mobile(iWidget *panel, const iMenuItem *itemsNullTerminated) | |||
512 | } | 532 | } |
513 | } | 533 | } |
514 | 534 | ||
515 | iWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) { | 535 | static const iMenuItem *findDialogCancelAction_(const iMenuItem *items, size_t n) { |
536 | if (n <= 1) { | ||
537 | return NULL; | ||
538 | } | ||
539 | for (size_t i = 0; i < n - 1; i++) { | ||
540 | if (!iCmpStr(items[i].label, "${cancel}")) { | ||
541 | return &items[i]; | ||
542 | } | ||
543 | } | ||
544 | return NULL; | ||
545 | } | ||
546 | |||
547 | iWidget *makePanels_Mobile(const char *id, | ||
548 | const iMenuItem *itemsNullTerminated, | ||
549 | const iMenuItem *actions, size_t numActions) { | ||
516 | /* A multipanel widget has a top panel and one or more detail panels. In a horizontal layout, | 550 | /* A multipanel widget has a top panel and one or more detail panels. In a horizontal layout, |
517 | the detail panels slide in from the right and cover the top panel. In a landscape layout, | 551 | the detail panels slide in from the right and cover the top panel. In a landscape layout, |
518 | the detail panels are always visible on the side. */ | 552 | the detail panels are always visible on the side. */ |
519 | iWidget *sheet = new_Widget(); | 553 | iWidget *sheet = new_Widget(); |
554 | setId_Widget(sheet, id); | ||
520 | setBackgroundColor_Widget(sheet, uiBackground_ColorId); | 555 | setBackgroundColor_Widget(sheet, uiBackground_ColorId); |
521 | setFlags_Widget(sheet, | 556 | setFlags_Widget(sheet, |
522 | resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag | | 557 | resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag | |
@@ -553,18 +588,21 @@ iWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) { | |||
553 | topPanel->offsetRef = detailStack; | 588 | topPanel->offsetRef = detailStack; |
554 | } | 589 | } |
555 | /* Navigation bar at the top. */ | 590 | /* Navigation bar at the top. */ |
591 | iLabelWidget *naviBack; | ||
556 | iWidget *navi = new_Widget(); { | 592 | iWidget *navi = new_Widget(); { |
557 | setId_Widget(navi, "panel.navi"); | 593 | setId_Widget(navi, "panel.navi"); |
558 | setBackgroundColor_Widget(navi, uiBackground_ColorId); | 594 | setBackgroundColor_Widget(navi, uiBackground_ColorId); |
559 | addChild_Widget(navi, iClob(makePadding_Widget(0))); | 595 | addChild_Widget(navi, iClob(makePadding_Widget(0))); |
560 | iLabelWidget *back = addChildFlags_Widget( | 596 | naviBack = addChildFlags_Widget( |
561 | navi, | 597 | navi, |
562 | iClob(new_LabelWidget(leftAngle_Icon " ${panel.back}", "panel.close")), | 598 | iClob(newKeyMods_LabelWidget(leftAngle_Icon " ${panel.back}", |
599 | SDLK_ESCAPE, 0, | ||
600 | "panel.close")), | ||
563 | noBackground_WidgetFlag | frameless_WidgetFlag | alignLeft_WidgetFlag | | 601 | noBackground_WidgetFlag | frameless_WidgetFlag | alignLeft_WidgetFlag | |
564 | extraPadding_WidgetFlag); | 602 | extraPadding_WidgetFlag); |
565 | checkIcon_LabelWidget(back); | 603 | checkIcon_LabelWidget(naviBack); |
566 | setId_Widget(as_Widget(back), "panel.back"); | 604 | setId_Widget(as_Widget(naviBack), "panel.back"); |
567 | setFont_LabelWidget(back, labelFont_()); | 605 | setFont_LabelWidget(naviBack, labelFont_()); |
568 | addChildFlags_Widget(sheet, iClob(navi), | 606 | addChildFlags_Widget(sheet, iClob(navi), |
569 | drawBackgroundToVerticalSafeArea_WidgetFlag | | 607 | drawBackgroundToVerticalSafeArea_WidgetFlag | |
570 | arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag | | 608 | arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag | |
@@ -593,6 +631,54 @@ iWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) { | |||
593 | makePanelItem_Mobile(topPanel, item); | 631 | makePanelItem_Mobile(topPanel, item); |
594 | } | 632 | } |
595 | } | 633 | } |
634 | /* Actions. */ | ||
635 | if (numActions) { | ||
636 | /* Some actions go in the navigation bar and some go on the top panel. */ | ||
637 | const iMenuItem *cancelItem = findDialogCancelAction_(actions, numActions); | ||
638 | const iMenuItem *defaultItem = &actions[numActions - 1]; | ||
639 | iAssert(defaultItem); | ||
640 | if (!cancelItem) { | ||
641 | updateTextCStr_LabelWidget(naviBack, defaultItem->label); | ||
642 | setCommand_LabelWidget(naviBack, collectNewCStr_String(defaultItem->command)); | ||
643 | setFlags_Widget(as_Widget(naviBack), alignLeft_WidgetFlag, iFalse); | ||
644 | setFlags_Widget(as_Widget(naviBack), alignRight_WidgetFlag, iTrue); | ||
645 | setIcon_LabelWidget(naviBack, 0); | ||
646 | setFont_LabelWidget(naviBack, labelBoldFont_()); | ||
647 | } | ||
648 | else { | ||
649 | updateTextCStr_LabelWidget(naviBack, cancelItem->label); | ||
650 | setCommand_LabelWidget(naviBack, collectNewCStr_String(cancelItem->command | ||
651 | ? cancelItem->command | ||
652 | : "cancel")); | ||
653 | iLabelWidget *defaultButton = new_LabelWidget(defaultItem->label, defaultItem->command); | ||
654 | setFont_LabelWidget(defaultButton, labelBoldFont_()); | ||
655 | setFlags_Widget(as_Widget(defaultButton), | ||
656 | frameless_WidgetFlag | extraPadding_WidgetFlag | | ||
657 | noBackground_WidgetFlag, | ||
658 | iTrue); | ||
659 | addChildFlags_Widget(as_Widget(naviBack), iClob(defaultButton), | ||
660 | moveToParentRightEdge_WidgetFlag); | ||
661 | updateSize_LabelWidget(defaultButton); | ||
662 | } | ||
663 | /* All other actions are added as buttons. */ | ||
664 | iBool needPadding = iTrue; | ||
665 | for (size_t i = 0; i < numActions; i++) { | ||
666 | const iMenuItem *act = &actions[i]; | ||
667 | if (act == cancelItem || act == defaultItem) { | ||
668 | continue; | ||
669 | } | ||
670 | if (!iCmpStr(act->label, "---")) { | ||
671 | continue; | ||
672 | } | ||
673 | if (needPadding) { | ||
674 | makePanelItem_Mobile(topPanel, &(iMenuItem){ "padding" }); | ||
675 | needPadding = iFalse; | ||
676 | } | ||
677 | makePanelItem_Mobile( | ||
678 | topPanel, | ||
679 | &(iMenuItem){ format_CStr("button text:%s", act->label), 0, 0, act->command }); | ||
680 | } | ||
681 | } | ||
596 | /* Finalize the layout. */ | 682 | /* Finalize the layout. */ |
597 | addChild_Widget(sheet->root->widget, iClob(sheet)); | 683 | addChild_Widget(sheet->root->widget, iClob(sheet)); |
598 | mainDetailSplitHandler_(mainDetailSplit, "window.resized"); /* make it resize the split */ | 684 | mainDetailSplitHandler_(mainDetailSplit, "window.resized"); /* make it resize the split */ |
@@ -1011,7 +1097,7 @@ iWidget *makePanels_Mobile(const iMenuItem *itemsNullTerminated) { | |||
1011 | #endif | 1097 | #endif |
1012 | 1098 | ||
1013 | void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) { | 1099 | void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) { |
1014 | if (!useMobileSheetLayout_()) { | 1100 | if (!isUsingPanelLayout_Mobile()) { |
1015 | return; | 1101 | return; |
1016 | } | 1102 | } |
1017 | const iBool isSlidePanel = (flags_Widget(sheet) & horizontalOffset_WidgetFlag) != 0; | 1103 | const iBool isSlidePanel = (flags_Widget(sheet) & horizontalOffset_WidgetFlag) != 0; |
@@ -1032,7 +1118,7 @@ void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) { | |||
1032 | } | 1118 | } |
1033 | 1119 | ||
1034 | void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) { | 1120 | void setupSheetTransition_Mobile(iWidget *sheet, iBool isIncoming) { |
1035 | if (!useMobileSheetLayout_()) { | 1121 | if (!isUsingPanelLayout_Mobile()) { |
1036 | if (prefs_App()->uiAnimations) { | 1122 | if (prefs_App()->uiAnimations) { |
1037 | setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iFalse); | 1123 | setFlags_Widget(sheet, horizontalOffset_WidgetFlag, iFalse); |
1038 | if (isIncoming) { | 1124 | if (isIncoming) { |