diff options
Diffstat (limited to 'src/ui/mobile.c')
-rw-r--r-- | src/ui/mobile.c | 205 |
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 | ||
58 | static void updatePanelSheetMetrics_(iWidget *sheet) { | 58 | static 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 | ||
371 | void finalizeSheet_Mobile(iWidget *sheet) { | 370 | void finalizeSheet_Mobile(iWidget *sheet) { |
371 | arrange_Widget(sheet); | ||
372 | // postRefresh_App(); | ||
373 | } | ||
374 | |||
375 | static size_t countItems_(const iMenuItem *itemsNullTerminated) { | ||
376 | size_t num = 0; | ||
377 | for (; itemsNullTerminated->label; num++, itemsNullTerminated++) {} | ||
378 | return num; | ||
379 | } | ||
380 | |||
381 | void 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 | |||
474 | void makePanelItems_Mobile(iWidget *panel, const iMenuItem *itemsNullTerminated) { | ||
475 | for (const iMenuItem *item = itemsNullTerminated; item->label; item++) { | ||
476 | makePanelItem_Mobile(panel, item); | ||
477 | } | ||
478 | } | ||
479 | |||
480 | iWidget *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 | ||
778 | void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) { | 977 | void setupMenuTransition_Mobile(iWidget *sheet, iBool isIncoming) { |
779 | if (!useMobileSheetLayout_()) { | 978 | if (!useMobileSheetLayout_()) { |