diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-09-07 22:10:29 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-09-07 22:10:29 +0300 |
commit | 4ce9a07bbd4a4a82ff0b310d9c9e0768febe8d61 (patch) | |
tree | ca8c41fa1d792fdc764c787cb343ddbb6cfbef5a /src | |
parent | c10fc7a058c05edcedeb23bdcc9faae635f1780d (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')
-rw-r--r-- | src/gmdocument.h | 1 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 3 | ||||
-rw-r--r-- | src/ui/labelwidget.c | 38 | ||||
-rw-r--r-- | src/ui/labelwidget.h | 4 | ||||
-rw-r--r-- | src/ui/mobile.c | 205 | ||||
-rw-r--r-- | src/ui/mobile.h | 11 | ||||
-rw-r--r-- | src/ui/util.c | 247 | ||||
-rw-r--r-- | src/ui/util.h | 5 | ||||
-rw-r--r-- | src/ui/widget.c | 1 | ||||
-rw-r--r-- | src/ui/window.c | 3 |
10 files changed, 426 insertions, 92 deletions
diff --git a/src/gmdocument.h b/src/gmdocument.h index 9f8ee2ef..332c3e00 100644 --- a/src/gmdocument.h +++ b/src/gmdocument.h | |||
@@ -59,6 +59,7 @@ enum iGmDocumentTheme { | |||
59 | white_GmDocumentTheme, | 59 | white_GmDocumentTheme, |
60 | sepia_GmDocumentTheme, | 60 | sepia_GmDocumentTheme, |
61 | highContrast_GmDocumentTheme, | 61 | highContrast_GmDocumentTheme, |
62 | max_GmDocumentTheme | ||
62 | }; | 63 | }; |
63 | 64 | ||
64 | iBool isDark_GmDocumentTheme(enum iGmDocumentTheme); | 65 | iBool isDark_GmDocumentTheme(enum iGmDocumentTheme); |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index e280bc84..6ca4fd8d 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -1010,6 +1010,9 @@ static void documentRunsInvalidated_DocumentWidget_(iDocumentWidget *d) { | |||
1010 | } | 1010 | } |
1011 | 1011 | ||
1012 | iBool isPinned_DocumentWidget_(const iDocumentWidget *d) { | 1012 | iBool isPinned_DocumentWidget_(const iDocumentWidget *d) { |
1013 | if (deviceType_App() == phone_AppDeviceType) { | ||
1014 | return iFalse; | ||
1015 | } | ||
1013 | if (d->flags & otherRootByDefault_DocumentWidgetFlag) { | 1016 | if (d->flags & otherRootByDefault_DocumentWidgetFlag) { |
1014 | return iTrue; | 1017 | return iTrue; |
1015 | } | 1018 | } |
diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c index 3bfa600b..b84e17f4 100644 --- a/src/ui/labelwidget.c +++ b/src/ui/labelwidget.c | |||
@@ -44,11 +44,13 @@ struct Impl_LabelWidget { | |||
44 | iString command; | 44 | iString command; |
45 | iClick click; | 45 | iClick click; |
46 | struct { | 46 | struct { |
47 | uint8_t alignVisual : 1; /* align according to visible bounds, not font metrics */ | 47 | uint8_t alignVisual : 1; /* align according to visible bounds, not font metrics */ |
48 | uint8_t noAutoMinHeight : 1; /* minimum height is not set automatically */ | 48 | uint8_t noAutoMinHeight : 1; /* minimum height is not set automatically */ |
49 | uint8_t drawAsOutline : 1; /* draw as outline, filled with background color */ | 49 | uint8_t drawAsOutline : 1; /* draw as outline, filled with background color */ |
50 | uint8_t noTopFrame : 1; | 50 | uint8_t noTopFrame : 1; |
51 | uint8_t wrap : 1; | 51 | uint8_t wrap : 1; |
52 | uint8_t allCaps : 1; | ||
53 | uint8_t removeTrailingColon : 1; | ||
52 | } flags; | 54 | } flags; |
53 | }; | 55 | }; |
54 | 56 | ||
@@ -442,11 +444,18 @@ void updateSize_LabelWidget(iLabelWidget *d) { | |||
442 | 444 | ||
443 | static void replaceVariables_LabelWidget_(iLabelWidget *d) { | 445 | static void replaceVariables_LabelWidget_(iLabelWidget *d) { |
444 | translate_Lang(&d->label); | 446 | translate_Lang(&d->label); |
447 | if (d->flags.allCaps) { | ||
448 | set_String(&d->label, collect_String(upper_String(&d->label))); | ||
449 | } | ||
450 | if (d->flags.removeTrailingColon && endsWith_String(&d->label, ":")) { | ||
451 | removeEnd_String(&d->label, 1); | ||
452 | } | ||
445 | } | 453 | } |
446 | 454 | ||
447 | void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { | 455 | void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { |
448 | iWidget *w = &d->widget; | 456 | iWidget *w = &d->widget; |
449 | init_Widget(w); | 457 | init_Widget(w); |
458 | iZap(d->flags); | ||
450 | d->font = uiLabel_FontId; | 459 | d->font = uiLabel_FontId; |
451 | d->forceFg = none_ColorId; | 460 | d->forceFg = none_ColorId; |
452 | d->icon = 0; | 461 | d->icon = 0; |
@@ -464,11 +473,6 @@ void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { | |||
464 | d->kmods = 0; | 473 | d->kmods = 0; |
465 | init_Click(&d->click, d, !isEmpty_String(&d->command) ? SDL_BUTTON_LEFT : 0); | 474 | init_Click(&d->click, d, !isEmpty_String(&d->command) ? SDL_BUTTON_LEFT : 0); |
466 | setFlags_Widget(w, hover_WidgetFlag, d->click.button != 0); | 475 | setFlags_Widget(w, hover_WidgetFlag, d->click.button != 0); |
467 | d->flags.alignVisual = iFalse; | ||
468 | d->flags.noAutoMinHeight = iFalse; | ||
469 | d->flags.drawAsOutline = iFalse; | ||
470 | d->flags.noTopFrame = iFalse; | ||
471 | d->flags.wrap = iFalse; | ||
472 | updateSize_LabelWidget(d); | 476 | updateSize_LabelWidget(d); |
473 | updateKey_LabelWidget_(d); /* could be bound to another key */ | 477 | updateKey_LabelWidget_(d); /* could be bound to another key */ |
474 | } | 478 | } |
@@ -525,6 +529,20 @@ void setOutline_LabelWidget(iLabelWidget *d, iBool drawAsOutline) { | |||
525 | } | 529 | } |
526 | } | 530 | } |
527 | 531 | ||
532 | void setAllCaps_LabelWidget(iLabelWidget *d, iBool allCaps) { | ||
533 | if (d) { | ||
534 | d->flags.allCaps = allCaps; | ||
535 | replaceVariables_LabelWidget_(d); | ||
536 | } | ||
537 | } | ||
538 | |||
539 | void setRemoveTrailingColon_LabelWidget(iLabelWidget *d, iBool removeTrailingColon) { | ||
540 | if (d) { | ||
541 | d->flags.removeTrailingColon = removeTrailingColon; | ||
542 | replaceVariables_LabelWidget_(d); | ||
543 | } | ||
544 | } | ||
545 | |||
528 | void updateText_LabelWidget(iLabelWidget *d, const iString *text) { | 546 | void updateText_LabelWidget(iLabelWidget *d, const iString *text) { |
529 | set_String(&d->label, text); | 547 | set_String(&d->label, text); |
530 | set_String(&d->srcLabel, text); | 548 | set_String(&d->srcLabel, text); |
diff --git a/src/ui/labelwidget.h b/src/ui/labelwidget.h index b8b6fd87..6275d2c8 100644 --- a/src/ui/labelwidget.h +++ b/src/ui/labelwidget.h | |||
@@ -30,10 +30,12 @@ iDeclareWidgetClass(LabelWidget) | |||
30 | iDeclareObjectConstructionArgs(LabelWidget, const char *label, const char *command) | 30 | iDeclareObjectConstructionArgs(LabelWidget, const char *label, const char *command) |
31 | 31 | ||
32 | void setAlignVisually_LabelWidget(iLabelWidget *, iBool alignVisual); | 32 | void setAlignVisually_LabelWidget(iLabelWidget *, iBool alignVisual); |
33 | void setNoAutoMinHeight_LabelWidget(iLabelWidget *, iBool noAutoMinHeight); | 33 | void setNoAutoMinHeight_LabelWidget (iLabelWidget *, iBool noAutoMinHeight); |
34 | void setNoTopFrame_LabelWidget (iLabelWidget *, iBool noTopFrame); | 34 | void setNoTopFrame_LabelWidget (iLabelWidget *, iBool noTopFrame); |
35 | void setWrap_LabelWidget (iLabelWidget *, iBool wrap); | 35 | void setWrap_LabelWidget (iLabelWidget *, iBool wrap); |
36 | void setOutline_LabelWidget (iLabelWidget *, iBool drawAsOutline); | 36 | void setOutline_LabelWidget (iLabelWidget *, iBool drawAsOutline); |
37 | void setAllCaps_LabelWidget (iLabelWidget *, iBool allCaps); | ||
38 | void setRemoveTrailingColon_LabelWidget (iLabelWidget *, iBool removeTrailingColon); | ||
37 | void setFont_LabelWidget (iLabelWidget *, int fontId); | 39 | void setFont_LabelWidget (iLabelWidget *, int fontId); |
38 | void setTextColor_LabelWidget (iLabelWidget *, int color); | 40 | void setTextColor_LabelWidget (iLabelWidget *, int color); |
39 | void setText_LabelWidget (iLabelWidget *, const iString *text); /* resizes widget */ | 41 | void setText_LabelWidget (iLabelWidget *, const iString *text); /* resizes widget */ |
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_()) { |
diff --git a/src/ui/mobile.h b/src/ui/mobile.h index 44134389..50b89e32 100644 --- a/src/ui/mobile.h +++ b/src/ui/mobile.h | |||
@@ -22,11 +22,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
22 | 22 | ||
23 | #pragma once | 23 | #pragma once |
24 | 24 | ||
25 | #include <the_Foundation/defs.h> | 25 | #include <the_Foundation/rect.h> |
26 | 26 | ||
27 | iDeclareType(Widget) | 27 | iDeclareType(Widget) |
28 | 28 | iDeclareType(MenuItem) | |
29 | void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming); | 29 | |
30 | void setupSheetTransition_Mobile (iWidget *sheet, iBool isIncoming); | 30 | iWidget * makeSplitMultiPanel_Mobile (const iMenuItem *itemsNullTerminated); |
31 | |||
32 | void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming); | ||
33 | void setupSheetTransition_Mobile (iWidget *sheet, iBool isIncoming); | ||
31 | 34 | ||
32 | void finalizeSheet_Mobile (iWidget *sheet); | 35 | void finalizeSheet_Mobile (iWidget *sheet); |
diff --git a/src/ui/util.c b/src/ui/util.c index 906d30ae..995b730e 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -707,6 +707,9 @@ iWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) { | |||
707 | iBool haveIcons = iFalse; | 707 | iBool haveIcons = iFalse; |
708 | for (size_t i = 0; i < n; ++i) { | 708 | for (size_t i = 0; i < n; ++i) { |
709 | const iMenuItem *item = &items[i]; | 709 | const iMenuItem *item = &items[i]; |
710 | if (!item->label) { | ||
711 | break; | ||
712 | } | ||
710 | if (equal_CStr(item->label, "---")) { | 713 | if (equal_CStr(item->label, "---")) { |
711 | addChild_Widget(menu, iClob(makeMenuSeparator_())); | 714 | addChild_Widget(menu, iClob(makeMenuSeparator_())); |
712 | } | 715 | } |
@@ -1506,7 +1509,7 @@ static void addRadioButton_(iWidget *parent, const char *id, const char *label, | |||
1506 | id); | 1509 | id); |
1507 | } | 1510 | } |
1508 | 1511 | ||
1509 | static void addFontButtons_(iWidget *parent, const char *id) { | 1512 | static const iArray *makeFontItems_(const char *id) { |
1510 | const struct { | 1513 | const struct { |
1511 | const char * name; | 1514 | const char * name; |
1512 | enum iTextFont cfgId; | 1515 | enum iTextFont cfgId; |
@@ -1518,7 +1521,7 @@ static void addFontButtons_(iWidget *parent, const char *id) { | |||
1518 | { "Tinos", tinos_TextFont }, | 1521 | { "Tinos", tinos_TextFont }, |
1519 | { "---", -1 }, | 1522 | { "---", -1 }, |
1520 | { "Iosevka", iosevka_TextFont } }; | 1523 | { "Iosevka", iosevka_TextFont } }; |
1521 | iArray *items = new_Array(sizeof(iMenuItem)); | 1524 | iArray *items = collectNew_Array(sizeof(iMenuItem)); |
1522 | iForIndices(i, fonts) { | 1525 | iForIndices(i, fonts) { |
1523 | pushBack_Array(items, | 1526 | pushBack_Array(items, |
1524 | &(iMenuItem){ fonts[i].name, | 1527 | &(iMenuItem){ fonts[i].name, |
@@ -1528,11 +1531,18 @@ static void addFontButtons_(iWidget *parent, const char *id) { | |||
1528 | ? format_CStr("!%s.set arg:%d", id, fonts[i].cfgId) | 1531 | ? format_CStr("!%s.set arg:%d", id, fonts[i].cfgId) |
1529 | : NULL }); | 1532 | : NULL }); |
1530 | } | 1533 | } |
1531 | iLabelWidget *button = makeMenuButton_LabelWidget("Source Sans 3", data_Array(items), size_Array(items)); | 1534 | pushBack_Array(items, &(iMenuItem){ NULL }); /* terminator */ |
1532 | setBackgroundColor_Widget(findChild_Widget(as_Widget(button), "menu"), uiBackgroundMenu_ColorId); | 1535 | return items; |
1536 | } | ||
1537 | |||
1538 | static void addFontButtons_(iWidget *parent, const char *id) { | ||
1539 | const iArray *items = makeFontItems_(id); | ||
1540 | iLabelWidget *button = makeMenuButton_LabelWidget("Source Sans 3", | ||
1541 | constData_Array(items), size_Array(items)); | ||
1542 | setBackgroundColor_Widget(findChild_Widget(as_Widget(button), "menu"), | ||
1543 | uiBackgroundMenu_ColorId); | ||
1533 | setId_Widget(as_Widget(button), format_CStr("prefs.%s", id)); | 1544 | setId_Widget(as_Widget(button), format_CStr("prefs.%s", id)); |
1534 | addChildFlags_Widget(parent, iClob(button), alignLeft_WidgetFlag); | 1545 | addChildFlags_Widget(parent, iClob(button), alignLeft_WidgetFlag); |
1535 | delete_Array(items); | ||
1536 | } | 1546 | } |
1537 | 1547 | ||
1538 | #if 0 | 1548 | #if 0 |
@@ -1615,7 +1625,7 @@ static void addPrefsInputWithHeading_(iWidget *headings, iWidget *values, | |||
1615 | static size_t findWidestItemLabel_(const iMenuItem *items, size_t num) { | 1625 | static size_t findWidestItemLabel_(const iMenuItem *items, size_t num) { |
1616 | int widest = 0; | 1626 | int widest = 0; |
1617 | size_t widestPos = iInvalidPos; | 1627 | size_t widestPos = iInvalidPos; |
1618 | for (size_t i = 0; i < num; i++) { | 1628 | for (size_t i = 0; i < num && items[i].label; i++) { |
1619 | const int width = | 1629 | const int width = |
1620 | measure_Text(uiLabel_FontId, | 1630 | measure_Text(uiLabel_FontId, |
1621 | translateCStr_Lang(items[i].label)) | 1631 | translateCStr_Lang(items[i].label)) |
@@ -1629,6 +1639,153 @@ static size_t findWidestItemLabel_(const iMenuItem *items, size_t num) { | |||
1629 | } | 1639 | } |
1630 | 1640 | ||
1631 | iWidget *makePreferences_Widget(void) { | 1641 | iWidget *makePreferences_Widget(void) { |
1642 | /* Common items. */ | ||
1643 | const iMenuItem langItems[] = { { "${lang.de} - de", 0, 0, "uilang id:de" }, | ||
1644 | { "${lang.en} - en", 0, 0, "uilang id:en" }, | ||
1645 | { "${lang.es} - es", 0, 0, "uilang id:es" }, | ||
1646 | { "${lang.fi} - fi", 0, 0, "uilang id:fi" }, | ||
1647 | { "${lang.fr} - fr", 0, 0, "uilang id:fr" }, | ||
1648 | { "${lang.ia} - ia", 0, 0, "uilang id:ia" }, | ||
1649 | { "${lang.ie} - ie", 0, 0, "uilang id:ie" }, | ||
1650 | { "${lang.pl} - pl", 0, 0, "uilang id:pl" }, | ||
1651 | { "${lang.ru} - ru", 0, 0, "uilang id:ru" }, | ||
1652 | { "${lang.sr} - sr", 0, 0, "uilang id:sr" }, | ||
1653 | { "${lang.tok} - tok", 0, 0, "uilang id:tok" }, | ||
1654 | { "${lang.zh.hans} - zh", 0, 0, "uilang id:zh_Hans" }, | ||
1655 | { "${lang.zh.hant} - zh", 0, 0, "uilang id:zh_Hant" }, | ||
1656 | { NULL } }; | ||
1657 | const iMenuItem returnKeyBehaviors[] = { | ||
1658 | { "${prefs.returnkey.linebreak} " uiTextAction_ColorEscape shift_Icon return_Icon | ||
1659 | restore_ColorEscape | ||
1660 | " ${prefs.returnkey.accept} " uiTextAction_ColorEscape return_Icon, | ||
1661 | 0, | ||
1662 | 0, | ||
1663 | format_CStr("returnkey.set arg:%d", default_ReturnKeyBehavior) }, | ||
1664 | { "${prefs.returnkey.linebreak} " uiTextAction_ColorEscape return_Icon restore_ColorEscape | ||
1665 | " ${prefs.returnkey.accept} " uiTextAction_ColorEscape shift_Icon return_Icon, | ||
1666 | 0, | ||
1667 | 0, | ||
1668 | format_CStr("returnkey.set arg:%d", acceptWithShift_ReturnKeyBehavior) }, | ||
1669 | { "${prefs.returnkey.linebreak} " uiTextAction_ColorEscape return_Icon restore_ColorEscape | ||
1670 | " ${prefs.returnkey.accept} " uiTextAction_ColorEscape | ||
1671 | #if defined (iPlatformApple) | ||
1672 | "\u2318" return_Icon, | ||
1673 | #else | ||
1674 | "Ctrl" return_Icon, | ||
1675 | #endif | ||
1676 | 0, | ||
1677 | 0, | ||
1678 | format_CStr("returnkey.set arg:%d", acceptWithPrimaryMod_ReturnKeyBehavior) }, | ||
1679 | { NULL } | ||
1680 | }; | ||
1681 | iMenuItem docThemes[2][max_GmDocumentTheme + 1]; | ||
1682 | for (int i = 0; i < 2; ++i) { | ||
1683 | const iBool isDark = (i == 0); | ||
1684 | const char *mode = isDark ? "dark" : "light"; | ||
1685 | const iMenuItem items[max_GmDocumentTheme + 1] = { | ||
1686 | { "${prefs.doctheme.name.colorfuldark}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, colorfulDark_GmDocumentTheme) }, | ||
1687 | { "${prefs.doctheme.name.colorfullight}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, colorfulLight_GmDocumentTheme) }, | ||
1688 | { "${prefs.doctheme.name.black}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, black_GmDocumentTheme) }, | ||
1689 | { "${prefs.doctheme.name.gray}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, gray_GmDocumentTheme) }, | ||
1690 | { "${prefs.doctheme.name.white}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, white_GmDocumentTheme) }, | ||
1691 | { "${prefs.doctheme.name.sepia}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, sepia_GmDocumentTheme) }, | ||
1692 | { "${prefs.doctheme.name.highcontrast}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, highContrast_GmDocumentTheme) }, | ||
1693 | { NULL } | ||
1694 | }; | ||
1695 | memcpy(docThemes[i], items, sizeof(items)); | ||
1696 | } | ||
1697 | const iMenuItem imgStyles[] = { | ||
1698 | { "${prefs.imagestyle.original}", 0, 0, format_CStr("imagestyle.set arg:%d", original_ImageStyle) }, | ||
1699 | { "${prefs.imagestyle.grayscale}", 0, 0, format_CStr("imagestyle.set arg:%d", grayscale_ImageStyle) }, | ||
1700 | { "${prefs.imagestyle.bgfg}", 0, 0, format_CStr("imagestyle.set arg:%d", bgFg_ImageStyle) }, | ||
1701 | { "${prefs.imagestyle.text}", 0, 0, format_CStr("imagestyle.set arg:%d", textColorized_ImageStyle) }, | ||
1702 | { "${prefs.imagestyle.preformat}", 0, 0, format_CStr("imagestyle.set arg:%d", preformatColorized_ImageStyle) }, | ||
1703 | { NULL } | ||
1704 | }; | ||
1705 | /* Create the Preferences UI. */ | ||
1706 | if (deviceType_App() != desktop_AppDeviceType) { | ||
1707 | const iMenuItem pinSplit[] = { | ||
1708 | { "button id:prefs.pinsplit.0 label:prefs.pinsplit.none", 0, 0, "pinsplit.set arg:0" }, | ||
1709 | { "button id:prefs.pinsplit.1 label:prefs.pinsplit.left", 0, 0, "pinsplit.set arg:1" }, | ||
1710 | { "button id:prefs.pinsplit.2 label:prefs.pinsplit.right", 0, 0, "pinsplit.set arg:2" }, | ||
1711 | { NULL } | ||
1712 | }; | ||
1713 | const iMenuItem themeItems[] = { | ||
1714 | { "button id:prefs.theme.0 label:prefs.theme.black", 0, 0, "theme.set arg:0" }, | ||
1715 | { "button id:prefs.theme.1 label:prefs.theme.dark", 0, 0, "theme.set arg:1" }, | ||
1716 | { "button id:prefs.theme.2 label:prefs.theme.light", 0, 0, "theme.set arg:2" }, | ||
1717 | { "button id:prefs.theme.3 label:prefs.theme.white", 0, 0, "theme.set arg:3" }, | ||
1718 | { NULL } | ||
1719 | }; | ||
1720 | const iMenuItem accentItems[] = { | ||
1721 | { "button id:prefs.accent.0 label:prefs.accent.teal", 0, 0, "accent.set arg:0" }, | ||
1722 | { "button id:prefs.accent.1 label:prefs.accent.orange", 0, 0, "accent.set arg:1" }, | ||
1723 | { NULL } | ||
1724 | }; | ||
1725 | const iMenuItem satItems[] = { | ||
1726 | { "button id:prefs.saturation.3 text:100 %", 0, 0, "saturation.set arg:100" }, | ||
1727 | { "button id:prefs.saturation.2 text:66 %", 0, 0, "saturation.set arg:66" }, | ||
1728 | { "button id:prefs.saturation.1 text:33 %", 0, 0, "saturation.set arg:33" }, | ||
1729 | { "button id:prefs.saturation.0 text:0 %", 0, 0, "saturation.set arg:0" }, | ||
1730 | { NULL } | ||
1731 | }; | ||
1732 | const iMenuItem generalItems[] = { | ||
1733 | { "title id:heading.prefs.general", 0, 0, NULL }, | ||
1734 | { "input id:prefs.searchurl url:1", 0, 0, NULL }, | ||
1735 | { "padding", 0, 0, NULL }, | ||
1736 | { "toggle id:prefs.hoverlink", 0, 0, NULL }, | ||
1737 | { "toggle id:prefs.archive.openindex", 0, 0, NULL }, | ||
1738 | { "radio device:1 id:prefs.pinsplit", 0, 0, (const void *) pinSplit }, | ||
1739 | { "padding", 0, 0, NULL }, | ||
1740 | { "dropdown id:prefs.uilang", 0, 0, (const void *) langItems }, | ||
1741 | { NULL } | ||
1742 | }; | ||
1743 | const iMenuItem uiItems[] = { | ||
1744 | { "title id:heading.prefs.interface", 0, 0, NULL }, | ||
1745 | { "dropdown device:1 id:prefs.returnkey", 0, 0, (const void *) returnKeyBehaviors }, | ||
1746 | { "padding device:1", 0, 0, NULL }, | ||
1747 | { "toggle device:2 id:prefs.hidetoolbarscroll", 0, 0, NULL }, | ||
1748 | { "heading id:heading.prefs.sizing", 0, 0, NULL }, | ||
1749 | { "input id:prefs.uiscale maxlen:8", 0, 0, NULL }, | ||
1750 | { NULL } | ||
1751 | }; | ||
1752 | const iMenuItem colorItems[] = { | ||
1753 | { "title id:heading.prefs.colors", 0, 0, NULL }, | ||
1754 | { "heading id:heading.prefs.uitheme", 0, 0, NULL }, | ||
1755 | { "toggle id:prefs.ostheme", 0, 0, NULL }, | ||
1756 | { "radio id:prefs.theme", 0, 0, (const void *) themeItems }, | ||
1757 | { "radio id:prefs.accent", 0, 0, (const void *) accentItems }, | ||
1758 | { "heading id:heading.prefs.pagecontent", 0, 0, NULL }, | ||
1759 | { "dropdown id:prefs.doctheme.dark", 0, 0, (const void *) docThemes[0] }, | ||
1760 | { "dropdown id:prefs.doctheme.light", 0, 0, (const void *) docThemes[1] }, | ||
1761 | { "radio id:prefs.saturation", 0, 0, (const void *) satItems }, | ||
1762 | { "padding", 0, 0, NULL }, | ||
1763 | { "dropdown id:prefs.imagestyle", 0, 0, (const void *) imgStyles }, | ||
1764 | { NULL } | ||
1765 | }; | ||
1766 | const iMenuItem fontItems[] = { | ||
1767 | { "title id:heading.prefs.fonts", 0, 0, NULL }, | ||
1768 | { "dropdown id:prefs.headingfont", 0, 0, (const void *) constData_Array(makeFontItems_("headingfont")) }, | ||
1769 | { "dropdown id:prefs.font", 0, 0, (const void *) constData_Array(makeFontItems_("font")) }, | ||
1770 | { NULL } | ||
1771 | }; | ||
1772 | const iMenuItem items[] = { { "panel icon:0x2699 id:heading.prefs.general", | ||
1773 | '1', 0, | ||
1774 | (const void *) generalItems }, | ||
1775 | { "panel icon:0x1f4f1 id:heading.prefs.interface", | ||
1776 | '2', 0, | ||
1777 | (const void *) uiItems }, | ||
1778 | { "panel icon:0x1f3a8 id:heading.prefs.colors", | ||
1779 | '3', 0, | ||
1780 | (const void *) colorItems }, | ||
1781 | { "panel icon:0x1f5da id:heading.prefs.fonts", | ||
1782 | '4', 0, | ||
1783 | (const void *) fontItems }, | ||
1784 | { NULL } }; | ||
1785 | iWidget *dlg = makeSplitMultiPanel_Mobile(items); | ||
1786 | setupSheetTransition_Mobile(dlg, iTrue); | ||
1787 | return dlg; | ||
1788 | } | ||
1632 | iWidget *dlg = makeSheet_Widget("prefs"); | 1789 | iWidget *dlg = makeSheet_Widget("prefs"); |
1633 | addChildFlags_Widget(dlg, | 1790 | addChildFlags_Widget(dlg, |
1634 | iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.prefs}", NULL)), | 1791 | iClob(new_LabelWidget(uiHeading_ColorEscape "${heading.prefs}", NULL)), |
@@ -1666,22 +1823,7 @@ iWidget *makePreferences_Widget(void) { | |||
1666 | addChild_Widget(values, iClob(makePadding_Widget(bigGap))); | 1823 | addChild_Widget(values, iClob(makePadding_Widget(bigGap))); |
1667 | /* UI languages. */ { | 1824 | /* UI languages. */ { |
1668 | iArray *uiLangs = collectNew_Array(sizeof(iMenuItem)); | 1825 | iArray *uiLangs = collectNew_Array(sizeof(iMenuItem)); |
1669 | const iMenuItem langItems[] = { | 1826 | pushBackN_Array(uiLangs, langItems, iElemCount(langItems) - 1); |
1670 | { "${lang.de} - de", 0, 0, "uilang id:de" }, | ||
1671 | { "${lang.en} - en", 0, 0, "uilang id:en" }, | ||
1672 | { "${lang.es} - es", 0, 0, "uilang id:es" }, | ||
1673 | { "${lang.fi} - fi", 0, 0, "uilang id:fi" }, | ||
1674 | { "${lang.fr} - fr", 0, 0, "uilang id:fr" }, | ||
1675 | { "${lang.ia} - ia", 0, 0, "uilang id:ia" }, | ||
1676 | { "${lang.ie} - ie", 0, 0, "uilang id:ie" }, | ||
1677 | { "${lang.pl} - pl", 0, 0, "uilang id:pl" }, | ||
1678 | { "${lang.ru} - ru", 0, 0, "uilang id:ru" }, | ||
1679 | { "${lang.sr} - sr", 0, 0, "uilang id:sr" }, | ||
1680 | { "${lang.tok} - tok", 0, 0, "uilang id:tok" }, | ||
1681 | { "${lang.zh.hans} - zh", 0, 0, "uilang id:zh_Hans" }, | ||
1682 | { "${lang.zh.hant} - zh", 0, 0, "uilang id:zh_Hant" }, | ||
1683 | }; | ||
1684 | pushBackN_Array(uiLangs, langItems, iElemCount(langItems)); | ||
1685 | /* TODO: Add an arrange flag for resizing parent to widest child. */ | 1827 | /* TODO: Add an arrange flag for resizing parent to widest child. */ |
1686 | size_t widestPos = findWidestItemLabel_(data_Array(uiLangs), size_Array(uiLangs)); | 1828 | size_t widestPos = findWidestItemLabel_(data_Array(uiLangs), size_Array(uiLangs)); |
1687 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.uilang}"))); | 1829 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.uilang}"))); |
@@ -1702,39 +1844,12 @@ iWidget *makePreferences_Widget(void) { | |||
1702 | #endif | 1844 | #endif |
1703 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.returnkey}"))); | 1845 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.returnkey}"))); |
1704 | /* Return key behaviors. */ { | 1846 | /* Return key behaviors. */ { |
1705 | const iMenuItem returnKeyBehaviors[] = { | ||
1706 | { "${prefs.returnkey.linebreak} " | ||
1707 | uiTextAction_ColorEscape shift_Icon return_Icon restore_ColorEscape | ||
1708 | " ${prefs.returnkey.accept} " | ||
1709 | uiTextAction_ColorEscape return_Icon, | ||
1710 | 0, | ||
1711 | 0, | ||
1712 | format_CStr("returnkey.set arg:%d", default_ReturnKeyBehavior) }, | ||
1713 | { "${prefs.returnkey.linebreak} " | ||
1714 | uiTextAction_ColorEscape return_Icon restore_ColorEscape | ||
1715 | " ${prefs.returnkey.accept} " | ||
1716 | uiTextAction_ColorEscape shift_Icon return_Icon, | ||
1717 | 0, | ||
1718 | 0, | ||
1719 | format_CStr("returnkey.set arg:%d", acceptWithShift_ReturnKeyBehavior) }, | ||
1720 | { "${prefs.returnkey.linebreak} " | ||
1721 | uiTextAction_ColorEscape return_Icon restore_ColorEscape | ||
1722 | " ${prefs.returnkey.accept} " uiTextAction_ColorEscape | ||
1723 | #if defined (iPlatformApple) | ||
1724 | "\u2318" return_Icon, | ||
1725 | #else | ||
1726 | "Ctrl" return_Icon, | ||
1727 | #endif | ||
1728 | 0, | ||
1729 | 0, | ||
1730 | format_CStr("returnkey.set arg:%d", acceptWithPrimaryMod_ReturnKeyBehavior) }, | ||
1731 | }; | ||
1732 | iLabelWidget *returnKey = makeMenuButton_LabelWidget( | 1847 | iLabelWidget *returnKey = makeMenuButton_LabelWidget( |
1733 | returnKeyBehaviors[findWidestItemLabel_(returnKeyBehaviors, | 1848 | returnKeyBehaviors[findWidestItemLabel_(returnKeyBehaviors, |
1734 | iElemCount(returnKeyBehaviors))] | 1849 | iElemCount(returnKeyBehaviors) - 1)] |
1735 | .label, | 1850 | .label, |
1736 | returnKeyBehaviors, | 1851 | returnKeyBehaviors, |
1737 | iElemCount(returnKeyBehaviors)); | 1852 | iElemCount(returnKeyBehaviors) - 1); |
1738 | setBackgroundColor_Widget(findChild_Widget(as_Widget(returnKey), "menu"), | 1853 | setBackgroundColor_Widget(findChild_Widget(as_Widget(returnKey), "menu"), |
1739 | uiBackgroundMenu_ColorId); | 1854 | uiBackgroundMenu_ColorId); |
1740 | setId_Widget(addChildFlags_Widget(values, iClob(returnKey), alignLeft_WidgetFlag), | 1855 | setId_Widget(addChildFlags_Widget(values, iClob(returnKey), alignLeft_WidgetFlag), |
@@ -1804,20 +1919,13 @@ iWidget *makePreferences_Widget(void) { | |||
1804 | for (int i = 0; i < 2; ++i) { | 1919 | for (int i = 0; i < 2; ++i) { |
1805 | const iBool isDark = (i == 0); | 1920 | const iBool isDark = (i == 0); |
1806 | const char *mode = isDark ? "dark" : "light"; | 1921 | const char *mode = isDark ? "dark" : "light"; |
1807 | const iMenuItem themes[] = { | ||
1808 | { "${prefs.doctheme.name.colorfuldark}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, colorfulDark_GmDocumentTheme) }, | ||
1809 | { "${prefs.doctheme.name.colorfullight}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, colorfulLight_GmDocumentTheme) }, | ||
1810 | { "${prefs.doctheme.name.black}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, black_GmDocumentTheme) }, | ||
1811 | { "${prefs.doctheme.name.gray}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, gray_GmDocumentTheme) }, | ||
1812 | { "${prefs.doctheme.name.white}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, white_GmDocumentTheme) }, | ||
1813 | { "${prefs.doctheme.name.sepia}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, sepia_GmDocumentTheme) }, | ||
1814 | { "${prefs.doctheme.name.highcontrast}", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, highContrast_GmDocumentTheme) }, | ||
1815 | }; | ||
1816 | addChild_Widget(headings, iClob(makeHeading_Widget(isDark ? "${prefs.doctheme.dark}" : "${prefs.doctheme.light}"))); | 1922 | addChild_Widget(headings, iClob(makeHeading_Widget(isDark ? "${prefs.doctheme.dark}" : "${prefs.doctheme.light}"))); |
1817 | iLabelWidget *button = | 1923 | iLabelWidget *button = makeMenuButton_LabelWidget( |
1818 | makeMenuButton_LabelWidget(themes[1].label, themes, iElemCount(themes)); | 1924 | docThemes[i][findWidestItemLabel_(docThemes[i], max_GmDocumentTheme)].label, |
1819 | // setFrameColor_Widget(findChild_Widget(as_Widget(button), "menu"), | 1925 | docThemes[i], |
1820 | // uiBackgroundSelected_ColorId); | 1926 | max_GmDocumentTheme); |
1927 | // setFrameColor_Widget(findChild_Widget(as_Widget(button), "menu"), | ||
1928 | // uiBackgroundSelected_ColorId); | ||
1821 | setBackgroundColor_Widget(findChild_Widget(as_Widget(button), "menu"), uiBackgroundMenu_ColorId); | 1929 | setBackgroundColor_Widget(findChild_Widget(as_Widget(button), "menu"), uiBackgroundMenu_ColorId); |
1822 | setId_Widget(addChildFlags_Widget(values, iClob(button), alignLeft_WidgetFlag), | 1930 | setId_Widget(addChildFlags_Widget(values, iClob(button), alignLeft_WidgetFlag), |
1823 | format_CStr("prefs.doctheme.%s", mode)); | 1931 | format_CStr("prefs.doctheme.%s", mode)); |
@@ -1833,17 +1941,10 @@ iWidget *makePreferences_Widget(void) { | |||
1833 | addChildFlags_Widget(values, iClob(sats), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | 1941 | addChildFlags_Widget(values, iClob(sats), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); |
1834 | /* Colorize images. */ { | 1942 | /* Colorize images. */ { |
1835 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.imagestyle}"))); | 1943 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.imagestyle}"))); |
1836 | const iMenuItem imgStyles[] = { | ||
1837 | { "${prefs.imagestyle.original}", 0, 0, format_CStr("imagestyle.set arg:%d", original_ImageStyle) }, | ||
1838 | { "${prefs.imagestyle.grayscale}", 0, 0, format_CStr("imagestyle.set arg:%d", grayscale_ImageStyle) }, | ||
1839 | { "${prefs.imagestyle.bgfg}", 0, 0, format_CStr("imagestyle.set arg:%d", bgFg_ImageStyle) }, | ||
1840 | { "${prefs.imagestyle.text}", 0, 0, format_CStr("imagestyle.set arg:%d", textColorized_ImageStyle) }, | ||
1841 | { "${prefs.imagestyle.preformat}", 0, 0, format_CStr("imagestyle.set arg:%d", preformatColorized_ImageStyle) }, | ||
1842 | }; | ||
1843 | iLabelWidget *button = makeMenuButton_LabelWidget( | 1944 | iLabelWidget *button = makeMenuButton_LabelWidget( |
1844 | imgStyles[findWidestItemLabel_(imgStyles, iElemCount(imgStyles))].label, | 1945 | imgStyles[findWidestItemLabel_(imgStyles, iElemCount(imgStyles) - 1)].label, |
1845 | imgStyles, | 1946 | imgStyles, |
1846 | iElemCount(imgStyles)); | 1947 | iElemCount(imgStyles) - 1); |
1847 | setBackgroundColor_Widget(findChild_Widget(as_Widget(button), "menu"), | 1948 | setBackgroundColor_Widget(findChild_Widget(as_Widget(button), "menu"), |
1848 | uiBackgroundMenu_ColorId); | 1949 | uiBackgroundMenu_ColorId); |
1849 | setId_Widget(addChildFlags_Widget(values, iClob(button), alignLeft_WidgetFlag), | 1950 | setId_Widget(addChildFlags_Widget(values, iClob(button), alignLeft_WidgetFlag), |
diff --git a/src/ui/util.h b/src/ui/util.h index 2423f834..87b72394 100644 --- a/src/ui/util.h +++ b/src/ui/util.h | |||
@@ -220,7 +220,10 @@ struct Impl_MenuItem { | |||
220 | const char *label; | 220 | const char *label; |
221 | int key; | 221 | int key; |
222 | int kmods; | 222 | int kmods; |
223 | const char *command; | 223 | union { |
224 | const char *command; | ||
225 | const void *data; | ||
226 | }; | ||
224 | }; | 227 | }; |
225 | 228 | ||
226 | iWidget * makeMenu_Widget (iWidget *parent, const iMenuItem *items, size_t n); /* returns no ref */ | 229 | iWidget * makeMenu_Widget (iWidget *parent, const iMenuItem *items, size_t n); /* returns no ref */ |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 4f567989..0d6787ce 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -1402,6 +1402,7 @@ iAny *hitChild_Widget(const iWidget *d, iInt2 coord) { | |||
1402 | } | 1402 | } |
1403 | 1403 | ||
1404 | iAny *findChild_Widget(const iWidget *d, const char *id) { | 1404 | iAny *findChild_Widget(const iWidget *d, const char *id) { |
1405 | if (!d) return NULL; | ||
1405 | if (cmp_String(id_Widget(d), id) == 0) { | 1406 | if (cmp_String(id_Widget(d), id) == 0) { |
1406 | return iConstCast(iAny *, d); | 1407 | return iConstCast(iAny *, d); |
1407 | } | 1408 | } |
diff --git a/src/ui/window.c b/src/ui/window.c index 3ac02495..096853cc 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -1136,6 +1136,9 @@ void setTitle_Window(iWindow *d, const iString *title) { | |||
1136 | } | 1136 | } |
1137 | 1137 | ||
1138 | void setUiScale_Window(iWindow *d, float uiScale) { | 1138 | void setUiScale_Window(iWindow *d, float uiScale) { |
1139 | if (uiScale <= 0.0f) { | ||
1140 | uiScale = 1.0f; | ||
1141 | } | ||
1139 | uiScale = iClamp(uiScale, 0.5f, 4.0f); | 1142 | uiScale = iClamp(uiScale, 0.5f, 4.0f); |
1140 | if (d) { | 1143 | if (d) { |
1141 | if (iAbs(d->uiScale - uiScale) > 0.0001f) { | 1144 | if (iAbs(d->uiScale - uiScale) > 0.0001f) { |