diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-09 22:44:45 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-09 22:44:45 +0200 |
commit | 2002543dbedcc1666d02d11fbde55f794d692bb7 (patch) | |
tree | 853412e7593d4a1ca3f0ccdc5ca31466a3400463 /src/ui/widget.c | |
parent | 5ccb0e0096dff6c2bbdfa959610620a14fdc918d (diff) |
Mobile: Revising phone-style dialogs
Sliding panels and left-edge swipes.
Diffstat (limited to 'src/ui/widget.c')
-rw-r--r-- | src/ui/widget.c | 92 |
1 files changed, 68 insertions, 24 deletions
diff --git a/src/ui/widget.c b/src/ui/widget.c index d7543615..ec229b86 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -153,11 +153,13 @@ void setFlags_Widget(iWidget *d, int64_t flags, iBool set) { | |||
153 | } | 153 | } |
154 | iChangeFlags(d->flags, flags, set); | 154 | iChangeFlags(d->flags, flags, set); |
155 | if (flags & keepOnTop_WidgetFlag) { | 155 | if (flags & keepOnTop_WidgetFlag) { |
156 | iPtrArray *onTop = onTop_RootData_(); | ||
156 | if (set) { | 157 | if (set) { |
157 | pushBack_PtrArray(onTop_RootData_(), d); | 158 | iAssert(indexOf_PtrArray(onTop, d) == iInvalidPos); |
159 | pushBack_PtrArray(onTop, d); | ||
158 | } | 160 | } |
159 | else { | 161 | else { |
160 | removeOne_PtrArray(onTop_RootData_(), d); | 162 | removeOne_PtrArray(onTop, d); |
161 | } | 163 | } |
162 | } | 164 | } |
163 | } | 165 | } |
@@ -169,10 +171,17 @@ void setPos_Widget(iWidget *d, iInt2 pos) { | |||
169 | } | 171 | } |
170 | 172 | ||
171 | void setSize_Widget(iWidget *d, iInt2 size) { | 173 | void setSize_Widget(iWidget *d, iInt2 size) { |
172 | if (size.x < 0) size.x = d->rect.size.x; | 174 | int flags = fixedSize_WidgetFlag; |
173 | if (size.y < 0) size.y = d->rect.size.y; | 175 | if (size.x < 0) { |
176 | size.x = d->rect.size.x; | ||
177 | flags &= ~fixedWidth_WidgetFlag; | ||
178 | } | ||
179 | if (size.y < 0) { | ||
180 | size.y = d->rect.size.y; | ||
181 | flags &= ~fixedHeight_WidgetFlag; | ||
182 | } | ||
174 | d->rect.size = size; | 183 | d->rect.size = size; |
175 | setFlags_Widget(d, fixedSize_WidgetFlag, iTrue); | 184 | setFlags_Widget(d, flags, iTrue); |
176 | } | 185 | } |
177 | 186 | ||
178 | void setPadding_Widget(iWidget *d, int left, int top, int right, int bottom) { | 187 | void setPadding_Widget(iWidget *d, int left, int top, int right, int bottom) { |
@@ -498,16 +507,24 @@ void arrange_Widget(iWidget *d) { | |||
498 | } | 507 | } |
499 | } | 508 | } |
500 | 509 | ||
501 | iRect bounds_Widget(const iWidget *d) { | 510 | static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { |
502 | iRect bounds = d->rect; | ||
503 | if (d->flags & visualOffset_WidgetFlag) { | 511 | if (d->flags & visualOffset_WidgetFlag) { |
504 | bounds.pos.y += iRound(value_Anim(&d->visualOffset)); | 512 | const int off = iRound(value_Anim(&d->visualOffset)); |
513 | if (d->flags & horizontalOffset_WidgetFlag) { | ||
514 | pos->x += off; | ||
515 | } | ||
516 | else { | ||
517 | pos->y += off; | ||
518 | } | ||
505 | } | 519 | } |
520 | } | ||
521 | |||
522 | iRect bounds_Widget(const iWidget *d) { | ||
523 | iRect bounds = d->rect; | ||
524 | applyVisualOffset_Widget_(d, &bounds.pos); | ||
506 | for (const iWidget *w = d->parent; w; w = w->parent) { | 525 | for (const iWidget *w = d->parent; w; w = w->parent) { |
507 | iInt2 pos = w->rect.pos; | 526 | iInt2 pos = w->rect.pos; |
508 | if (w->flags & visualOffset_WidgetFlag) { | 527 | applyVisualOffset_Widget_(w, &pos); |
509 | pos.y += iRound(value_Anim(&w->visualOffset)); | ||
510 | } | ||
511 | addv_I2(&bounds.pos, pos); | 528 | addv_I2(&bounds.pos, pos); |
512 | } | 529 | } |
513 | #if defined (iPlatformMobile) | 530 | #if defined (iPlatformMobile) |
@@ -595,6 +612,14 @@ iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
595 | if (dispatchEvent_Widget(child, ev)) { | 612 | if (dispatchEvent_Widget(child, ev)) { |
596 | #if 0 | 613 | #if 0 |
597 | if (ev->type == SDL_MOUSEBUTTONDOWN) { | 614 | if (ev->type == SDL_MOUSEBUTTONDOWN) { |
615 | printf("[%p] %s:'%s' ate the button %d\n", | ||
616 | child, class_Widget(child)->name, | ||
617 | cstr_String(id_Widget(child)), ev->button.button); | ||
618 | fflush(stdout); | ||
619 | } | ||
620 | #endif | ||
621 | #if 0 | ||
622 | if (ev->type == SDL_MOUSEBUTTONDOWN) { | ||
598 | printf("widget %p ('%s' class:%s) ate the mouse down\n", | 623 | printf("widget %p ('%s' class:%s) ate the mouse down\n", |
599 | child, cstr_String(id_Widget(child)), | 624 | child, cstr_String(id_Widget(child)), |
600 | class_Widget(child)->name); | 625 | class_Widget(child)->name); |
@@ -637,20 +662,25 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
637 | postCommand_Widget(d, "mouse.moved coord:%d %d", ev->motion.x, ev->motion.y); | 662 | postCommand_Widget(d, "mouse.moved coord:%d %d", ev->motion.x, ev->motion.y); |
638 | return iTrue; | 663 | return iTrue; |
639 | } | 664 | } |
640 | else if (d->flags & overflowScrollable_WidgetFlag && ev->type == SDL_MOUSEWHEEL) { | 665 | else if (d->flags & overflowScrollable_WidgetFlag && ev->type == SDL_MOUSEWHEEL && |
666 | ~d->flags & visualOffset_WidgetFlag) { | ||
641 | iRect bounds = bounds_Widget(d); | 667 | iRect bounds = bounds_Widget(d); |
642 | const iInt2 winSize = rootSize_Window(get_Window()); | 668 | const iInt2 rootSize = rootSize_Window(get_Window()); |
643 | if (height_Rect(bounds) > winSize.y) { | 669 | const iRect winRect = safeRootRect_Window(get_Window()); |
670 | const int yTop = top_Rect(winRect); | ||
671 | const int yBottom = bottom_Rect(winRect); | ||
672 | const int safeBottom = rootSize.y - yBottom; | ||
673 | if (height_Rect(bounds) > height_Rect(winRect)) { | ||
644 | int step = ev->wheel.y; | 674 | int step = ev->wheel.y; |
645 | #if !defined (iPlatformApple) | 675 | if (!isPerPixel_MouseWheelEvent(&ev->wheel)) { |
646 | step *= lineHeight_Text(uiLabel_FontId); | 676 | step *= lineHeight_Text(uiLabel_FontId); |
647 | #endif | 677 | } |
648 | bounds.pos.y += step; | 678 | bounds.pos.y += step; |
649 | if (step > 0) { | 679 | if (step > 0) { |
650 | bounds.pos.y = iMin(bounds.pos.y, 0); | 680 | bounds.pos.y = iMin(bounds.pos.y, yTop); |
651 | } | 681 | } |
652 | else { | 682 | else { |
653 | bounds.pos.y = iMax(bounds.pos.y, winSize.y - height_Rect(bounds)); | 683 | bounds.pos.y = iMax(bounds.pos.y, rootSize.y + safeBottom - height_Rect(bounds)); |
654 | } | 684 | } |
655 | d->rect.pos = localCoord_Widget(d->parent, bounds.pos); | 685 | d->rect.pos = localCoord_Widget(d->parent, bounds.pos); |
656 | refresh_Widget(d); | 686 | refresh_Widget(d); |
@@ -676,6 +706,15 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
676 | ev->button.y); | 706 | ev->button.y); |
677 | } | 707 | } |
678 | if (d->flags & mouseModal_WidgetFlag && isMouseEvent_(ev)) { | 708 | if (d->flags & mouseModal_WidgetFlag && isMouseEvent_(ev)) { |
709 | if ((ev->type == SDL_MOUSEBUTTONDOWN || ev->type == SDL_MOUSEBUTTONUP) && | ||
710 | d->flags & commandOnClick_WidgetFlag) { | ||
711 | postCommand_Widget(d, | ||
712 | "mouse.clicked arg:%d button:%d coord:%d %d", | ||
713 | ev->type == SDL_MOUSEBUTTONDOWN ? 1 : 0, | ||
714 | ev->button.button, | ||
715 | ev->button.x, | ||
716 | ev->button.y); | ||
717 | } | ||
679 | setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW); | 718 | setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW); |
680 | return iTrue; | 719 | return iTrue; |
681 | } | 720 | } |
@@ -801,14 +840,15 @@ void drawChildren_Widget(const iWidget *d) { | |||
801 | /* Root draws the on-top widgets on top of everything else. */ | 840 | /* Root draws the on-top widgets on top of everything else. */ |
802 | if (!d->parent) { | 841 | if (!d->parent) { |
803 | iConstForEach(PtrArray, i, onTop_RootData_()) { | 842 | iConstForEach(PtrArray, i, onTop_RootData_()) { |
804 | draw_Widget(*i.value); | 843 | const iWidget *top = *i.value; |
844 | draw_Widget(top); | ||
805 | } | 845 | } |
806 | } | 846 | } |
807 | } | 847 | } |
808 | 848 | ||
809 | void draw_Widget(const iWidget *d) { | 849 | void draw_Widget(const iWidget *d) { |
810 | drawBackground_Widget(d); | 850 | drawBackground_Widget(d); |
811 | drawChildren_Widget(d); | 851 | drawChildren_Widget(d); |
812 | } | 852 | } |
813 | 853 | ||
814 | iAny *addChild_Widget(iWidget *d, iAnyObject *child) { | 854 | iAny *addChild_Widget(iWidget *d, iAnyObject *child) { |
@@ -903,7 +943,7 @@ iAny *hitChild_Widget(const iWidget *d, iInt2 coord) { | |||
903 | } | 943 | } |
904 | /* Check for on-top widgets first. */ | 944 | /* Check for on-top widgets first. */ |
905 | if (!d->parent) { | 945 | if (!d->parent) { |
906 | iForEach(PtrArray, i, onTop_RootData_()) { | 946 | iReverseForEach(PtrArray, i, onTop_RootData_()) { |
907 | iWidget *child = i.ptr; | 947 | iWidget *child = i.ptr; |
908 | // printf("ontop: %s (%s) hidden:%d hittable:%d\n", cstr_String(id_Widget(child)), | 948 | // printf("ontop: %s (%s) hidden:%d hittable:%d\n", cstr_String(id_Widget(child)), |
909 | // class_Widget(child)->name, | 949 | // class_Widget(child)->name, |
@@ -920,8 +960,8 @@ iAny *hitChild_Widget(const iWidget *d, iInt2 coord) { | |||
920 | if (found) return found; | 960 | if (found) return found; |
921 | } | 961 | } |
922 | } | 962 | } |
923 | if ((d->flags & overflowScrollable_WidgetFlag || class_Widget(d) != &Class_Widget) && | 963 | if ((d->flags & overflowScrollable_WidgetFlag || class_Widget(d) != &Class_Widget || |
924 | ~d->flags & unhittable_WidgetFlag && | 964 | d->flags & mouseModal_WidgetFlag) && ~d->flags & unhittable_WidgetFlag && |
925 | contains_Widget(d, coord)) { | 965 | contains_Widget(d, coord)) { |
926 | return iConstCast(iWidget *, d); | 966 | return iConstCast(iWidget *, d); |
927 | } | 967 | } |
@@ -1168,6 +1208,10 @@ iBool hasVisibleChildOnTop_Widget(const iWidget *parent) { | |||
1168 | } | 1208 | } |
1169 | 1209 | ||
1170 | void printTree_Widget(const iWidget *d) { | 1210 | void printTree_Widget(const iWidget *d) { |
1211 | if (!d) { | ||
1212 | printf("[NULL]\n"); | ||
1213 | return; | ||
1214 | } | ||
1171 | printTree_Widget_(d, 0); | 1215 | printTree_Widget_(d, 0); |
1172 | } | 1216 | } |
1173 | 1217 | ||