From 3bbbd1399373755cec95e9685d18ecebec3b9c24 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 6 Nov 2021 09:47:03 +0200 Subject: Fixed issues with tall popup menus A tall popup menu needs to use overflow scrolling, but the size of the display wasn't considered. Now a popup window is fit to the usable bounds of the display. --- src/ui/lookupwidget.c | 3 ++- src/ui/root.c | 33 +++++++++++++++++++++++++++++++-- src/ui/root.h | 2 +- src/ui/util.c | 4 ++-- src/ui/widget.c | 34 ++++++++++++++++++++-------------- src/ui/window.c | 6 +++++- 6 files changed, 61 insertions(+), 21 deletions(-) diff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c index e57a5fdc..da0113ce 100644 --- a/src/ui/lookupwidget.c +++ b/src/ui/lookupwidget.c @@ -665,8 +665,9 @@ static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) { (bottom_Rect(rect_Root(root)) - bottom_Rect(navBarBounds)) / 2)); setPos_Widget(w, windowToLocal_Widget(w, bottomLeft_Rect(bounds_Widget(url)))); #if defined (iPlatformAppleMobile) + /* TODO: Check this again. */ /* Adjust height based on keyboard size. */ { - w->rect.size.y = visibleSize_Root(root).y - top_Rect(bounds_Widget(w)); + w->rect.size.y = bottom_Rect(visibleRect_Root(root)) - top_Rect(bounds_Widget(w)); if (deviceType_App() == phone_AppDeviceType) { float l, r; safeAreaInsets_iOS(&l, NULL, &r, NULL); diff --git a/src/ui/root.c b/src/ui/root.c index d847480f..95126654 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -1529,6 +1529,35 @@ iRect safeRect_Root(const iRoot *d) { return rect; } -iInt2 visibleSize_Root(const iRoot *d) { - return addY_I2(size_Root(d), -get_MainWindow()->keyboardHeight); +iRect visibleRect_Root(const iRoot *d) { + iRect visRect = rect_Root(d); +#if defined (iPlatformAppleMobile) + /* TODO: Check this on device... Maybe DisplayUsableBounds would be good here, too? */ + float left, top, right, bottom; + safeAreaInsets_iOS(&left, &top, &right, &bottom); + visRect.pos.x = (int) left; + visRect.size.x -= (int) (left + right); + visRect.pos.y = (int) top; + visRect.size.y -= (int) (top + bottom); +#endif +#if defined (iPlatformDesktop) + /* Apply the usable bounds of the display. */ + SDL_Rect usable; { + const float ratio = d->window->pixelRatio; + SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->window->win), &usable); + iInt2 winPos; + SDL_GetWindowPosition(d->window->win, &winPos.x, &winPos.y); + mulfv_I2(&winPos, ratio); + usable.x *= ratio; + usable.y *= ratio; + usable.w *= ratio; + usable.h *= ratio; + /* Make it relative to the window. */ + usable.x -= winPos.x; + usable.y -= winPos.y; + visRect = intersect_Rect(visRect, init_Rect(usable.x, usable.y, usable.w, usable.h)); + } +#endif + adjustEdges_Rect(&visRect, 0, 0, -get_MainWindow()->keyboardHeight, 0); + return visRect; } diff --git a/src/ui/root.h b/src/ui/root.h index 04dd5e16..851d927d 100644 --- a/src/ui/root.h +++ b/src/ui/root.h @@ -40,6 +40,6 @@ void updateToolbarColors_Root (iRoot *); iInt2 size_Root (const iRoot *); iRect rect_Root (const iRoot *); iRect safeRect_Root (const iRoot *); -iInt2 visibleSize_Root (const iRoot *); /* may be obstructed by software keyboard */ +iRect visibleRect_Root (const iRoot *); /* may be obstructed by software keyboard */ iBool isNarrow_Root (const iRoot *); int appIconSize_Root (void); diff --git a/src/ui/util.c b/src/ui/util.c index 760bf48f..88348ff8 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -1038,7 +1038,7 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) { iRect displayRect = zero_Rect(); for (int i = 0; i < SDL_GetNumVideoDisplays(); i++) { SDL_Rect dispBounds; - SDL_GetDisplayBounds(i, &dispBounds); + SDL_GetDisplayUsableBounds(i, &dispBounds); displayRect = union_Rect( displayRect, init_Rect(dispBounds.x, dispBounds.y, dispBounds.w, dispBounds.h)); } @@ -1070,7 +1070,7 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) { iInt2 menuPos = add_I2(winPos, divf_I2(sub_I2(windowCoord, divi_I2(gap2_UI, 2)), pixelRatio)); /* Check display bounds. */ { - const iInt2 menuSize = divf_I2(d->rect.size, pixelRatio); + iInt2 menuSize = divf_I2(d->rect.size, pixelRatio); if (menuOpenFlags & center_MenuOpenFlags) { iInt2 winSize; SDL_GetWindowSize(sdlWin, &winSize.x, &winSize.y); diff --git a/src/ui/widget.c b/src/ui/widget.c index b509cbe2..6ce5e02a 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -1142,11 +1142,9 @@ static iBool isOverflowScrollPossible_Widget_(const iWidget *d, int delta) { return iFalse; } iRect bounds = boundsWithoutVisualOffset_Widget(d); - const iRect winRect = adjusted_Rect(safeRect_Root(d->root), - zero_I2(), - init_I2(0, -get_MainWindow()->keyboardHeight)); - const int yTop = top_Rect(winRect); - const int yBottom = bottom_Rect(winRect); + const iRect winRect = visibleRect_Root(d->root); + const int yTop = top_Rect(winRect); + const int yBottom = bottom_Rect(winRect); if (delta == 0) { if (top_Rect(bounds) >= yTop && bottom_Rect(bounds) <= yBottom) { return iFalse; /* fits inside just fine */ @@ -1162,11 +1160,9 @@ iBool scrollOverflow_Widget(iWidget *d, int delta) { if (!isOverflowScrollPossible_Widget_(d, delta)) { return iFalse; } - iRect bounds = boundsWithoutVisualOffset_Widget(d); - const iRect winRect = adjusted_Rect(safeRect_Root(d->root), - zero_I2(), - init_I2(0, -get_MainWindow()->keyboardHeight)); - iRangei validPosRange = { bottom_Rect(winRect) - height_Rect(bounds), top_Rect(winRect) }; + iRect bounds = boundsWithoutVisualOffset_Widget(d); + const iRect winRect = visibleRect_Root(d->root); + iRangei validPosRange = { bottom_Rect(winRect) - height_Rect(bounds), top_Rect(winRect) }; if (validPosRange.start > validPosRange.end) { validPosRange.start = validPosRange.end; /* no room to scroll */ } @@ -1244,18 +1240,28 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { /* TODO: Motion events occur frequently. Maybe it would help if these were handled via audiences that specifically register to listen for motion, to minimize the number of widgets that need to process them. */ - const int hoverScrollLimit = 2 * lineHeight_Text(default_FontId); + const int hoverScrollLimit = 1.5f * lineHeight_Text(default_FontId); float speed = 0.0f; if (ev->motion.y < hoverScrollLimit) { speed = (hoverScrollLimit - ev->motion.y) / (float) hoverScrollLimit; } else { - const int bottomLimit = bottom_Rect(rect_Root(d->root)) - hoverScrollLimit; - if (ev->motion.y > bottomLimit ) { + const iWindow *win = window_Widget(d); + SDL_Rect usable; + SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(win->win), + &usable); + const int bottomLimit = + iMin(bottom_Rect(rect_Root(d->root)), usable.h * win->pixelRatio) - + hoverScrollLimit; + if (ev->motion.y > bottomLimit) { speed = -(ev->motion.y - bottomLimit) / (float) hoverScrollLimit; } + printf("my:%d bottomLimit:%d => %f (%d)\n", ev->motion.y, bottomLimit, speed + ,isOverflowScrollPossible_Widget_(d, speed)); fflush(stdout); } - if (speed != 0.0f && isOverflowScrollPossible_Widget_(d, speed > 0 ? 1 : -1)) { + const int dir = speed > 0 ? 1 : -1; + if (speed != 0.0f && isOverflowScrollPossible_Widget_(d, dir)) { +// speed = dir * powf(speed, 1.5f); const uint32_t nowTime = SDL_GetTicks(); uint32_t elapsed = nowTime - lastHoverOverflowMotionTime_; if (elapsed > 100) { diff --git a/src/ui/window.c b/src/ui/window.c index c63ad76a..fa364cff 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -1676,9 +1676,13 @@ iWindow *newPopup_Window(iInt2 screenPos, iWidget *rootWidget) { #if !defined (iPlatformApple) setForceSoftwareRender_App(iTrue); #endif + SDL_Rect usableRect; + SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(get_MainWindow()->base.win), + &usableRect); iWindow *win = new_Window(popup_WindowType, - (iRect){ screenPos, divf_I2(rootWidget->rect.size, get_Window()->pixelRatio) }, + (iRect){ screenPos, min_I2(divf_I2(rootWidget->rect.size, get_Window()->pixelRatio), + init_I2(usableRect.w, usableRect.h)) }, SDL_WINDOW_ALWAYS_ON_TOP | #if !defined (iPlatformAppleDesktop) SDL_WINDOW_BORDERLESS | -- cgit v1.2.3