diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-16 09:33:49 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-16 09:33:49 +0200 |
commit | 49bc5bba5df94f2bcbe12b513255b92599c052c2 (patch) | |
tree | 80faf1f591fb7498dc512d5826457b52c56fc5f3 /src/ui/widget.c | |
parent | 63d1b8562c655d5f482846c99ec95ba666587e81 (diff) |
Mobile: Dialog layout fixes
Orientation and safe inset changes are now applied to phone dialogs.
There is still the occasional unscrollable dialog, but it seems random?
Diffstat (limited to 'src/ui/widget.c')
-rw-r--r-- | src/ui/widget.c | 80 |
1 files changed, 74 insertions, 6 deletions
diff --git a/src/ui/widget.c b/src/ui/widget.c index 8641dd61..385eb7e0 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -102,7 +102,7 @@ static void visualOffsetAnimation_Widget_(void *ptr) { | |||
102 | addTicker_App(visualOffsetAnimation_Widget_, ptr); | 102 | addTicker_App(visualOffsetAnimation_Widget_, ptr); |
103 | } | 103 | } |
104 | else { | 104 | else { |
105 | setFlags_Widget(d, visualOffset_WidgetFlag, iFalse); | 105 | d->flags &= ~visualOffset_WidgetFlag; |
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
@@ -341,7 +341,7 @@ void arrange_Widget(iWidget *d) { | |||
341 | return; | 341 | return; |
342 | } | 342 | } |
343 | if (d->flags & moveToParentLeftEdge_WidgetFlag) { | 343 | if (d->flags & moveToParentLeftEdge_WidgetFlag) { |
344 | d->rect.pos.x = d->padding[0]; | 344 | d->rect.pos.x = d->padding[0]; /* FIXME: Shouldn't this be d->parent->padding[0]? */ |
345 | } | 345 | } |
346 | else if (d->flags & moveToParentRightEdge_WidgetFlag) { | 346 | else if (d->flags & moveToParentRightEdge_WidgetFlag) { |
347 | d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); | 347 | d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); |
@@ -355,6 +355,13 @@ void arrange_Widget(iWidget *d) { | |||
355 | if (d->flags & resizeToParentHeight_WidgetFlag) { | 355 | if (d->flags & resizeToParentHeight_WidgetFlag) { |
356 | setHeight_Widget_(d, height_Rect(innerRect_Widget_(d->parent))); | 356 | setHeight_Widget_(d, height_Rect(innerRect_Widget_(d->parent))); |
357 | } | 357 | } |
358 | if (d->flags & safePadding_WidgetFlag) { | ||
359 | #if defined (iPlatformAppleMobile) | ||
360 | float left, top, right, bottom; | ||
361 | safeAreaInsets_iOS(&left, &top, &right, &bottom); | ||
362 | setPadding_Widget(d, left, top, right, bottom); | ||
363 | #endif | ||
364 | } | ||
358 | /* The rest of the arrangement depends on child widgets. */ | 365 | /* The rest of the arrangement depends on child widgets. */ |
359 | if (!d->children) { | 366 | if (!d->children) { |
360 | return; | 367 | return; |
@@ -489,6 +496,9 @@ void arrange_Widget(iWidget *d) { | |||
489 | else if ((d->flags & resizeChildren_WidgetFlag) == resizeChildren_WidgetFlag) { | 496 | else if ((d->flags & resizeChildren_WidgetFlag) == resizeChildren_WidgetFlag) { |
490 | child->rect.pos = pos; | 497 | child->rect.pos = pos; |
491 | } | 498 | } |
499 | else if (d->flags & resizeWidthOfChildren_WidgetFlag) { | ||
500 | child->rect.pos.x = pos.x; | ||
501 | } | ||
492 | } | 502 | } |
493 | /* Update the size of the widget according to the arrangement. */ | 503 | /* Update the size of the widget according to the arrangement. */ |
494 | if (d->flags & arrangeSize_WidgetFlag) { | 504 | if (d->flags & arrangeSize_WidgetFlag) { |
@@ -667,10 +677,10 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
667 | } | 677 | } |
668 | #endif | 678 | #endif |
669 | #if 0 | 679 | #if 0 |
670 | if (ev->type == SDL_MOUSEBUTTONDOWN) { | 680 | if (ev->type == SDL_MOUSEWHEEL) { |
671 | printf("[%p] %s:'%s' ate the button %d\n", | 681 | printf("[%p] %s:'%s' ate the wheel\n", |
672 | child, class_Widget(child)->name, | 682 | child, class_Widget(child)->name, |
673 | cstr_String(id_Widget(child)), ev->button.button); | 683 | cstr_String(id_Widget(child))); |
674 | fflush(stdout); | 684 | fflush(stdout); |
675 | } | 685 | } |
676 | #endif | 686 | #endif |
@@ -692,6 +702,36 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
692 | return iFalse; | 702 | return iFalse; |
693 | } | 703 | } |
694 | 704 | ||
705 | static iBool scrollOverflow_Widget_(iWidget *d, int delta) { | ||
706 | iRect bounds = bounds_Widget(d); | ||
707 | const iInt2 rootSize = rootSize_Window(get_Window()); | ||
708 | const iRect winRect = safeRootRect_Window(get_Window()); | ||
709 | const int yTop = top_Rect(winRect); | ||
710 | const int yBottom = bottom_Rect(winRect); | ||
711 | //const int safeBottom = rootSize.y - yBottom; | ||
712 | bounds.pos.y += delta; | ||
713 | const iRangei range = { bottom_Rect(winRect) - height_Rect(bounds), yTop }; | ||
714 | // printf("range: %d ... %d\n", range.start, range.end); | ||
715 | if (range.start >= range.end) { | ||
716 | bounds.pos.y = range.end; | ||
717 | } | ||
718 | else { | ||
719 | bounds.pos.y = iClamp(bounds.pos.y, range.start, range.end); | ||
720 | } | ||
721 | // if (delta >= 0) { | ||
722 | // bounds.pos.y = iMin(bounds.pos.y, yTop); | ||
723 | // } | ||
724 | // else { | ||
725 | // bounds.pos.y = iMax(bounds.pos.y, ); | ||
726 | // } | ||
727 | const iInt2 newPos = localCoord_Widget(d->parent, bounds.pos); | ||
728 | if (!isEqual_I2(newPos, d->rect.pos)) { | ||
729 | d->rect.pos = newPos; | ||
730 | refresh_Widget(d); | ||
731 | } | ||
732 | return height_Rect(bounds) > height_Rect(winRect); | ||
733 | } | ||
734 | |||
695 | iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { | 735 | iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { |
696 | if (ev->type == SDL_KEYDOWN) { | 736 | if (ev->type == SDL_KEYDOWN) { |
697 | if (ev->key.keysym.sym == SDLK_TAB) { | 737 | if (ev->key.keysym.sym == SDLK_TAB) { |
@@ -720,6 +760,14 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
720 | } | 760 | } |
721 | else if (d->flags & overflowScrollable_WidgetFlag && ev->type == SDL_MOUSEWHEEL && | 761 | else if (d->flags & overflowScrollable_WidgetFlag && ev->type == SDL_MOUSEWHEEL && |
722 | ~d->flags & visualOffset_WidgetFlag) { | 762 | ~d->flags & visualOffset_WidgetFlag) { |
763 | int step = ev->wheel.y; | ||
764 | if (!isPerPixel_MouseWheelEvent(&ev->wheel)) { | ||
765 | step *= lineHeight_Text(uiLabel_FontId); | ||
766 | } | ||
767 | if (scrollOverflow_Widget_(d, step)) { | ||
768 | return iTrue; | ||
769 | } | ||
770 | #if 0 | ||
723 | iRect bounds = bounds_Widget(d); | 771 | iRect bounds = bounds_Widget(d); |
724 | const iInt2 rootSize = rootSize_Window(get_Window()); | 772 | const iInt2 rootSize = rootSize_Window(get_Window()); |
725 | const iRect winRect = safeRootRect_Window(get_Window()); | 773 | const iRect winRect = safeRootRect_Window(get_Window()); |
@@ -736,15 +784,20 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
736 | bounds.pos.y = iMin(bounds.pos.y, yTop); | 784 | bounds.pos.y = iMin(bounds.pos.y, yTop); |
737 | } | 785 | } |
738 | else { | 786 | else { |
739 | bounds.pos.y = iMax(bounds.pos.y, rootSize.y + safeBottom - height_Rect(bounds)); | 787 | bounds.pos.y = iMax(bounds.pos.y, rootSize.y /*+ safeBottom*/ - height_Rect(bounds)); |
740 | } | 788 | } |
741 | d->rect.pos = localCoord_Widget(d->parent, bounds.pos); | 789 | d->rect.pos = localCoord_Widget(d->parent, bounds.pos); |
742 | refresh_Widget(d); | 790 | refresh_Widget(d); |
743 | return iTrue; | 791 | return iTrue; |
744 | } | 792 | } |
793 | #endif | ||
745 | } | 794 | } |
746 | switch (ev->type) { | 795 | switch (ev->type) { |
747 | case SDL_USEREVENT: { | 796 | case SDL_USEREVENT: { |
797 | if (d->flags & overflowScrollable_WidgetFlag && | ||
798 | isCommand_UserEvent(ev, "widget.overflow")) { | ||
799 | scrollOverflow_Widget_(d, 0); /* check bounds */ | ||
800 | } | ||
748 | if (ev->user.code == command_UserEventCode && d->commandHandler && | 801 | if (ev->user.code == command_UserEventCode && d->commandHandler && |
749 | d->commandHandler(d, ev->user.data1)) { | 802 | d->commandHandler(d, ev->user.data1)) { |
750 | return iTrue; | 803 | return iTrue; |
@@ -1041,6 +1094,21 @@ iAny *findChild_Widget(const iWidget *d, const char *id) { | |||
1041 | return NULL; | 1094 | return NULL; |
1042 | } | 1095 | } |
1043 | 1096 | ||
1097 | static void addMatchingToArray_Widget_(const iWidget *d, const char *id, iPtrArray *found) { | ||
1098 | if (cmp_String(id_Widget(d), id) == 0) { | ||
1099 | pushBack_PtrArray(found, d); | ||
1100 | } | ||
1101 | iForEach(ObjectList, i, d->children) { | ||
1102 | addMatchingToArray_Widget_(i.object, id, found); | ||
1103 | } | ||
1104 | } | ||
1105 | |||
1106 | const iPtrArray *findChildren_Widget(const iWidget *d, const char *id) { | ||
1107 | iPtrArray *found = new_PtrArray(); | ||
1108 | addMatchingToArray_Widget_(d, id, found); | ||
1109 | return collect_PtrArray(found); | ||
1110 | } | ||
1111 | |||
1044 | iAny *findParentClass_Widget(const iWidget *d, const iAnyClass *class) { | 1112 | iAny *findParentClass_Widget(const iWidget *d, const iAnyClass *class) { |
1045 | if (!d) return NULL; | 1113 | if (!d) return NULL; |
1046 | iWidget *i = d->parent; | 1114 | iWidget *i = d->parent; |