summaryrefslogtreecommitdiff
path: root/src/ui/mobile.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-09-07 22:10:29 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-09-07 22:10:29 +0300
commit4ce9a07bbd4a4a82ff0b310d9c9e0768febe8d61 (patch)
treeca8c41fa1d792fdc764c787cb343ddbb6cfbef5a /src/ui/mobile.c
parentc10fc7a058c05edcedeb23bdcc9faae635f1780d (diff)
Mobile: Redoing Preferences
Contents of the Preferences split panel view are created based on arrays of MenuItems. This removes the confusing indirection of trying to modify the desktop widget tree to fit mobile.
Diffstat (limited to 'src/ui/mobile.c')
-rw-r--r--src/ui/mobile.c205
1 files changed, 202 insertions, 3 deletions
diff --git a/src/ui/mobile.c b/src/ui/mobile.c
index 168a92b8..4ccbb0cb 100644
--- a/src/ui/mobile.c
+++ b/src/ui/mobile.c
@@ -57,7 +57,6 @@ static enum iFontId labelBoldFont_(void) {
57 57
58static void updatePanelSheetMetrics_(iWidget *sheet) { 58static void updatePanelSheetMetrics_(iWidget *sheet) {
59 iWidget *navi = findChild_Widget(sheet, "panel.navi"); 59 iWidget *navi = findChild_Widget(sheet, "panel.navi");
60// iWidget *naviPad = child_Widget(navi, 0);
61 int naviHeight = lineHeight_Text(labelFont_()) + 4 * gap_UI; 60 int naviHeight = lineHeight_Text(labelFont_()) + 4 * gap_UI;
62#if defined (iPlatformMobile) 61#if defined (iPlatformMobile)
63 float left = 0.0f, right = 0.0f, top = 0.0f, bottom = 0.0f; 62 float left = 0.0f, right = 0.0f, top = 0.0f, bottom = 0.0f;
@@ -339,7 +338,7 @@ static iWidget *makeValuePaddingWithHeading_(iLabelWidget *heading, iWidget *val
339 addChildFlags_Widget(div, iClob(new_Widget()), expand_WidgetFlag); 338 addChildFlags_Widget(div, iClob(new_Widget()), expand_WidgetFlag);
340 addChild_Widget(div, iClob(value)); 339 addChild_Widget(div, iClob(value));
341 } 340 }
342 printTree_Widget(div); 341// printTree_Widget(div);
343 return div; 342 return div;
344} 343}
345 344
@@ -369,6 +368,205 @@ static iWidget *addChildPanel_(iWidget *parent, iLabelWidget *panelButton,
369} 368}
370 369
371void finalizeSheet_Mobile(iWidget *sheet) { 370void finalizeSheet_Mobile(iWidget *sheet) {
371 arrange_Widget(sheet);
372// postRefresh_App();
373}
374
375static size_t countItems_(const iMenuItem *itemsNullTerminated) {
376 size_t num = 0;
377 for (; itemsNullTerminated->label; num++, itemsNullTerminated++) {}
378 return num;
379}
380
381void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) {
382 const char * spec = item->label;
383 const char * id = cstr_Rangecc(range_Command(spec, "id"));
384 const char * label = format_CStr("${%s}", id);
385 iWidget * widget = NULL;
386 iLabelWidget *heading = NULL;
387 if (hasLabel_Command(spec, "device") && deviceType_App() != argLabel_Command(spec, "device")) {
388 return;
389 }
390 if (equal_Command(spec, "title")) {
391 iLabelWidget *title = addChildFlags_Widget(panel,
392 iClob(new_LabelWidget(label, NULL)),
393 alignLeft_WidgetFlag | frameless_WidgetFlag);
394 setFont_LabelWidget(title, uiLabelLargeBold_FontId);
395 setTextColor_LabelWidget(title, uiHeading_ColorId);
396 setAllCaps_LabelWidget(title, iTrue);
397 }
398 else if (equal_Command(spec, "heading")) {
399 addChild_Widget(panel, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));
400 heading = makeHeading_Widget(label);
401 setAllCaps_LabelWidget(heading, iTrue);
402 setRemoveTrailingColon_LabelWidget(heading, iTrue);
403 addChild_Widget(panel, iClob(heading));
404 }
405 else if (equal_Command(spec, "toggle")) {
406 iLabelWidget *toggle = (iLabelWidget *) makeToggle_Widget(id);
407 setFont_LabelWidget(toggle, labelFont_());
408 widget = makeValuePaddingWithHeading_(heading = makeHeading_Widget(label),
409 as_Widget(toggle));
410 }
411 else if (equal_Command(spec, "dropdown")) {
412 const iMenuItem *dropItems = item->data;
413 iLabelWidget *drop = makeMenuButton_LabelWidget("", dropItems, countItems_(dropItems));
414 setFont_LabelWidget(drop, labelFont_());
415 setFlags_Widget(as_Widget(drop),
416 alignRight_WidgetFlag | noBackground_WidgetFlag |
417 frameless_WidgetFlag, iTrue);
418 setId_Widget(as_Widget(drop), id);
419 widget = makeValuePaddingWithHeading_(heading = makeHeading_Widget(label), as_Widget(drop));
420 }
421 else if (equal_Command(spec, "radio")) {
422 addChild_Widget(panel, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));
423 iLabelWidget *head = makeHeading_Widget(label);
424 setAllCaps_LabelWidget(head, iTrue);
425 setRemoveTrailingColon_LabelWidget(head, iTrue);
426 addChild_Widget(panel, iClob(head));
427 widget = new_Widget();
428 setBackgroundColor_Widget(widget, uiBackgroundSidebar_ColorId);
429 setPadding_Widget(widget, 4 * gap_UI, 2 * gap_UI, 4 * gap_UI, 2 * gap_UI);
430// setFlags_Widget(widget, arrangeWidth_WidgetFlag, iFalse);
431 setFlags_Widget(widget,
432 borderBottom_WidgetFlag |
433 arrangeHorizontal_WidgetFlag |
434 arrangeHeight_WidgetFlag |
435 resizeToParentWidth_WidgetFlag |
436 resizeWidthOfChildren_WidgetFlag,
437 iTrue);
438 setId_Widget(widget, id);
439 for (const iMenuItem *radioItem = item->data; radioItem->label; radioItem++) {
440 const char * radId = cstr_Rangecc(range_Command(radioItem->label, "id"));
441 const char * radLabel = hasLabel_Command(radioItem->label, "label")
442 ? format_CStr("${%s}", cstr_Rangecc(range_Command(radioItem->label, "label")))
443 : suffixPtr_Command(radioItem->label, "text");
444 iLabelWidget *radButton = new_LabelWidget(radLabel, radioItem->command);
445 setId_Widget(as_Widget(radButton), radId);
446 setFont_LabelWidget(radButton, defaultMedium_FontId);
447 addChildFlags_Widget(widget, iClob(radButton), radio_WidgetFlag | noBackground_WidgetFlag);
448 }
449 }
450 else if (equal_Command(spec, "input")) {
451 iInputWidget *input = new_InputWidget(argU32Label_Command(spec, "maxlen"));
452 setId_Widget(as_Widget(input), id);
453 setFont_InputWidget(input, labelFont_());
454 setContentPadding_InputWidget(input, 3 * gap_UI, 0);
455 setUrlContent_InputWidget(input, argLabel_Command(spec, "url"));
456 widget = makeValuePaddingWithHeading_(heading = makeHeading_Widget(label),
457 as_Widget(input));
458 }
459 else if (equal_Command(spec, "padding")) {
460 widget = makePadding_Widget(lineHeight_Text(labelFont_()) * 1.5f);
461 }
462 if (heading) {
463 setRemoveTrailingColon_LabelWidget(heading, iTrue);
464 const iChar icon = toInt_String(string_Command(item->label, "icon"));
465 if (icon) {
466 setIcon_LabelWidget(heading, icon);
467 }
468 }
469 if (widget) {
470 addChild_Widget(panel, iClob(widget));
471 }
472}
473
474void makePanelItems_Mobile(iWidget *panel, const iMenuItem *itemsNullTerminated) {
475 for (const iMenuItem *item = itemsNullTerminated; item->label; item++) {
476 makePanelItem_Mobile(panel, item);
477 }
478}
479
480iWidget *makeSplitMultiPanel_Mobile(const iMenuItem *itemsNullTerminated) {
481 /* A multipanel widget has a top panel and one or more detail panels. In a horizontal layout,
482 the detail panels slide in from the right and cover the top panel. In a landscape layout,
483 the detail panels are always visible on the side. */
484 iWidget *sheet = new_Widget();
485 setBackgroundColor_Widget(sheet, uiBackground_ColorId);
486 setFlags_Widget(sheet,
487 resizeToParentWidth_WidgetFlag |
488 resizeToParentHeight_WidgetFlag |
489 frameless_WidgetFlag | focusRoot_WidgetFlag | commandOnClick_WidgetFlag |
490 overflowScrollable_WidgetFlag | leftEdgeDraggable_WidgetFlag,
491 iTrue);
492 /* The top-level split between main and detail panels. */
493 iWidget *mainDetailSplit = makeHDiv_Widget(); {
494 setCommandHandler_Widget(mainDetailSplit, mainDetailSplitHandler_);
495 setFlags_Widget(mainDetailSplit, resizeHeightOfChildren_WidgetFlag, iFalse);
496 setId_Widget(mainDetailSplit, "mdsplit");
497 addChild_Widget(sheet, iClob(mainDetailSplit));
498 }
499 /* The panel roots. */
500 iWidget *topPanel = new_Widget(); {
501 setId_Widget(topPanel, "panel.top");
502 setCommandHandler_Widget(topPanel, topPanelHandler_);
503 setFlags_Widget(topPanel,
504 arrangeVertical_WidgetFlag | resizeWidthOfChildren_WidgetFlag |
505 arrangeHeight_WidgetFlag | overflowScrollable_WidgetFlag |
506 commandOnClick_WidgetFlag,
507 iTrue);
508 addChild_Widget(mainDetailSplit, iClob(topPanel));
509 setId_Widget(addChild_Widget(topPanel, iClob(makePadding_Widget(0))), "panel.toppad");
510 }
511 iWidget *detailStack = new_Widget(); {
512 setId_Widget(detailStack, "detailstack");
513 setFlags_Widget(detailStack, collapse_WidgetFlag | resizeWidthOfChildren_WidgetFlag, iTrue);
514 addChild_Widget(mainDetailSplit, iClob(detailStack));
515 }
516 addChild_Widget(topPanel, iClob(makePadding_Widget(lineHeight_Text(labelFont_()))));
517 /* Slide top panel with detail panels. */ {
518 setFlags_Widget(topPanel, refChildrenOffset_WidgetFlag, iTrue);
519 topPanel->offsetRef = detailStack;
520 }
521 /* Navigation bar at the top. */
522 iWidget *navi = new_Widget(); {
523 setId_Widget(navi, "panel.navi");
524 setBackgroundColor_Widget(navi, uiBackground_ColorId);
525 addChild_Widget(navi, iClob(makePadding_Widget(0)));
526 iLabelWidget *back = addChildFlags_Widget(
527 navi,
528 iClob(new_LabelWidget(leftAngle_Icon " ${panel.back}", "panel.close")),
529 noBackground_WidgetFlag | frameless_WidgetFlag | alignLeft_WidgetFlag |
530 extraPadding_WidgetFlag);
531 checkIcon_LabelWidget(back);
532 setId_Widget(as_Widget(back), "panel.back");
533 setFont_LabelWidget(back, labelFont_());
534 addChildFlags_Widget(sheet, iClob(navi),
535 drawBackgroundToVerticalSafeArea_WidgetFlag |
536 arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag |
537 resizeToParentWidth_WidgetFlag | arrangeVertical_WidgetFlag);
538 }
539 /* Create panel contents based on provided items. */
540 for (size_t i = 0; itemsNullTerminated[i].label; i++) {
541 const iMenuItem *item = &itemsNullTerminated[i];
542 if (equal_Command(item->label, "panel")) {
543 const char *id = cstr_Rangecc(range_Command(item->label, "id"));
544 const iString *label = collectNewFormat_String("${%s}", id);
545 iLabelWidget *button =
546 addChildFlags_Widget(topPanel,
547 iClob(makePanelButton_(cstr_String(label), "panel.open")),
548 chevron_WidgetFlag | borderTop_WidgetFlag);
549 const iChar icon = toInt_String(string_Command(item->label, "icon"));
550 if (icon) {
551 setIcon_LabelWidget(button, icon);
552 }
553 iWidget *panel = addChildPanel_(detailStack, button, NULL);
554 makePanelItems_Mobile(panel, item->data);
555 }
556 else {
557 makePanelItem_Mobile(topPanel, item);
558 }
559 }
560 /* Finalize the layout. */
561 addChild_Widget(sheet->root->widget, iClob(sheet));
562 mainDetailSplitHandler_(mainDetailSplit, "window.resized"); /* make it resize the split */
563 updatePanelSheetMetrics_(sheet);
564 arrange_Widget(sheet);
565 postCommand_App("widget.overflow"); /* with the correct dimensions */
566 return sheet;
567}
568
569#if 0
372 /* The sheet contents are completely rearranged and restyled on a phone. 570 /* The sheet contents are completely rearranged and restyled on a phone.
373 We'll set up a linear fullscreen arrangement of the widgets. Sheets are already 571 We'll set up a linear fullscreen arrangement of the widgets. Sheets are already
374 scrollable so they can be taller than the display. In hindsight, it may have been 572 scrollable so they can be taller than the display. In hindsight, it may have been
@@ -399,7 +597,7 @@ void finalizeSheet_Mobile(iWidget *sheet) {
399 │ │ └┤ ││ │ │└┤ ││ 597 │ │ └┤ ││ │ │└┤ ││
400 │ │ └───────────────────┘│ │ │ └──────┘ 598 │ │ └───────────────────┘│ │ │ └──────┘
401 └─────────┴───────────────────────┘ └─────────┴ ─ ─ ─ ─ ┘ 599 └─────────┴───────────────────────┘ └─────────┴ ─ ─ ─ ─ ┘
402 offscreen 600 underneath
403 */ 601 */
404 /* Modify the top sheet to act as a fullscreen background. */ 602 /* Modify the top sheet to act as a fullscreen background. */
405 setPadding1_Widget(sheet, 0); 603 setPadding1_Widget(sheet, 0);
@@ -774,6 +972,7 @@ void finalizeSheet_Mobile(iWidget *sheet) {
774 } 972 }
775 postRefresh_App(); 973 postRefresh_App();
776} 974}
975#endif
777 976
778void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) { 977void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) {
779 if (!useMobileSheetLayout_()) { 978 if (!useMobileSheetLayout_()) {