diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-11-06 09:47:03 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-11-06 09:47:03 +0200 |
commit | 3bbbd1399373755cec95e9685d18ecebec3b9c24 (patch) | |
tree | fe987e205dd7b40f4dab61074a98e143d0ca4e46 /src | |
parent | 9df0c10c915b504a9f6dcca88608d702e4548bb6 (diff) |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/lookupwidget.c | 3 | ||||
-rw-r--r-- | src/ui/root.c | 33 | ||||
-rw-r--r-- | src/ui/root.h | 2 | ||||
-rw-r--r-- | src/ui/util.c | 4 | ||||
-rw-r--r-- | src/ui/widget.c | 34 | ||||
-rw-r--r-- | 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) { | |||
665 | (bottom_Rect(rect_Root(root)) - bottom_Rect(navBarBounds)) / 2)); | 665 | (bottom_Rect(rect_Root(root)) - bottom_Rect(navBarBounds)) / 2)); |
666 | setPos_Widget(w, windowToLocal_Widget(w, bottomLeft_Rect(bounds_Widget(url)))); | 666 | setPos_Widget(w, windowToLocal_Widget(w, bottomLeft_Rect(bounds_Widget(url)))); |
667 | #if defined (iPlatformAppleMobile) | 667 | #if defined (iPlatformAppleMobile) |
668 | /* TODO: Check this again. */ | ||
668 | /* Adjust height based on keyboard size. */ { | 669 | /* Adjust height based on keyboard size. */ { |
669 | w->rect.size.y = visibleSize_Root(root).y - top_Rect(bounds_Widget(w)); | 670 | w->rect.size.y = bottom_Rect(visibleRect_Root(root)) - top_Rect(bounds_Widget(w)); |
670 | if (deviceType_App() == phone_AppDeviceType) { | 671 | if (deviceType_App() == phone_AppDeviceType) { |
671 | float l, r; | 672 | float l, r; |
672 | safeAreaInsets_iOS(&l, NULL, &r, NULL); | 673 | 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) { | |||
1529 | return rect; | 1529 | return rect; |
1530 | } | 1530 | } |
1531 | 1531 | ||
1532 | iInt2 visibleSize_Root(const iRoot *d) { | 1532 | iRect visibleRect_Root(const iRoot *d) { |
1533 | return addY_I2(size_Root(d), -get_MainWindow()->keyboardHeight); | 1533 | iRect visRect = rect_Root(d); |
1534 | #if defined (iPlatformAppleMobile) | ||
1535 | /* TODO: Check this on device... Maybe DisplayUsableBounds would be good here, too? */ | ||
1536 | float left, top, right, bottom; | ||
1537 | safeAreaInsets_iOS(&left, &top, &right, &bottom); | ||
1538 | visRect.pos.x = (int) left; | ||
1539 | visRect.size.x -= (int) (left + right); | ||
1540 | visRect.pos.y = (int) top; | ||
1541 | visRect.size.y -= (int) (top + bottom); | ||
1542 | #endif | ||
1543 | #if defined (iPlatformDesktop) | ||
1544 | /* Apply the usable bounds of the display. */ | ||
1545 | SDL_Rect usable; { | ||
1546 | const float ratio = d->window->pixelRatio; | ||
1547 | SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->window->win), &usable); | ||
1548 | iInt2 winPos; | ||
1549 | SDL_GetWindowPosition(d->window->win, &winPos.x, &winPos.y); | ||
1550 | mulfv_I2(&winPos, ratio); | ||
1551 | usable.x *= ratio; | ||
1552 | usable.y *= ratio; | ||
1553 | usable.w *= ratio; | ||
1554 | usable.h *= ratio; | ||
1555 | /* Make it relative to the window. */ | ||
1556 | usable.x -= winPos.x; | ||
1557 | usable.y -= winPos.y; | ||
1558 | visRect = intersect_Rect(visRect, init_Rect(usable.x, usable.y, usable.w, usable.h)); | ||
1559 | } | ||
1560 | #endif | ||
1561 | adjustEdges_Rect(&visRect, 0, 0, -get_MainWindow()->keyboardHeight, 0); | ||
1562 | return visRect; | ||
1534 | } | 1563 | } |
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 *); | |||
40 | iInt2 size_Root (const iRoot *); | 40 | iInt2 size_Root (const iRoot *); |
41 | iRect rect_Root (const iRoot *); | 41 | iRect rect_Root (const iRoot *); |
42 | iRect safeRect_Root (const iRoot *); | 42 | iRect safeRect_Root (const iRoot *); |
43 | iInt2 visibleSize_Root (const iRoot *); /* may be obstructed by software keyboard */ | 43 | iRect visibleRect_Root (const iRoot *); /* may be obstructed by software keyboard */ |
44 | iBool isNarrow_Root (const iRoot *); | 44 | iBool isNarrow_Root (const iRoot *); |
45 | int appIconSize_Root (void); | 45 | 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) { | |||
1038 | iRect displayRect = zero_Rect(); | 1038 | iRect displayRect = zero_Rect(); |
1039 | for (int i = 0; i < SDL_GetNumVideoDisplays(); i++) { | 1039 | for (int i = 0; i < SDL_GetNumVideoDisplays(); i++) { |
1040 | SDL_Rect dispBounds; | 1040 | SDL_Rect dispBounds; |
1041 | SDL_GetDisplayBounds(i, &dispBounds); | 1041 | SDL_GetDisplayUsableBounds(i, &dispBounds); |
1042 | displayRect = union_Rect( | 1042 | displayRect = union_Rect( |
1043 | displayRect, init_Rect(dispBounds.x, dispBounds.y, dispBounds.w, dispBounds.h)); | 1043 | displayRect, init_Rect(dispBounds.x, dispBounds.y, dispBounds.w, dispBounds.h)); |
1044 | } | 1044 | } |
@@ -1070,7 +1070,7 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) { | |||
1070 | iInt2 menuPos = add_I2(winPos, | 1070 | iInt2 menuPos = add_I2(winPos, |
1071 | divf_I2(sub_I2(windowCoord, divi_I2(gap2_UI, 2)), pixelRatio)); | 1071 | divf_I2(sub_I2(windowCoord, divi_I2(gap2_UI, 2)), pixelRatio)); |
1072 | /* Check display bounds. */ { | 1072 | /* Check display bounds. */ { |
1073 | const iInt2 menuSize = divf_I2(d->rect.size, pixelRatio); | 1073 | iInt2 menuSize = divf_I2(d->rect.size, pixelRatio); |
1074 | if (menuOpenFlags & center_MenuOpenFlags) { | 1074 | if (menuOpenFlags & center_MenuOpenFlags) { |
1075 | iInt2 winSize; | 1075 | iInt2 winSize; |
1076 | SDL_GetWindowSize(sdlWin, &winSize.x, &winSize.y); | 1076 | 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) { | |||
1142 | return iFalse; | 1142 | return iFalse; |
1143 | } | 1143 | } |
1144 | iRect bounds = boundsWithoutVisualOffset_Widget(d); | 1144 | iRect bounds = boundsWithoutVisualOffset_Widget(d); |
1145 | const iRect winRect = adjusted_Rect(safeRect_Root(d->root), | 1145 | const iRect winRect = visibleRect_Root(d->root); |
1146 | zero_I2(), | 1146 | const int yTop = top_Rect(winRect); |
1147 | init_I2(0, -get_MainWindow()->keyboardHeight)); | 1147 | const int yBottom = bottom_Rect(winRect); |
1148 | const int yTop = top_Rect(winRect); | ||
1149 | const int yBottom = bottom_Rect(winRect); | ||
1150 | if (delta == 0) { | 1148 | if (delta == 0) { |
1151 | if (top_Rect(bounds) >= yTop && bottom_Rect(bounds) <= yBottom) { | 1149 | if (top_Rect(bounds) >= yTop && bottom_Rect(bounds) <= yBottom) { |
1152 | return iFalse; /* fits inside just fine */ | 1150 | return iFalse; /* fits inside just fine */ |
@@ -1162,11 +1160,9 @@ iBool scrollOverflow_Widget(iWidget *d, int delta) { | |||
1162 | if (!isOverflowScrollPossible_Widget_(d, delta)) { | 1160 | if (!isOverflowScrollPossible_Widget_(d, delta)) { |
1163 | return iFalse; | 1161 | return iFalse; |
1164 | } | 1162 | } |
1165 | iRect bounds = boundsWithoutVisualOffset_Widget(d); | 1163 | iRect bounds = boundsWithoutVisualOffset_Widget(d); |
1166 | const iRect winRect = adjusted_Rect(safeRect_Root(d->root), | 1164 | const iRect winRect = visibleRect_Root(d->root); |
1167 | zero_I2(), | 1165 | iRangei validPosRange = { bottom_Rect(winRect) - height_Rect(bounds), top_Rect(winRect) }; |
1168 | init_I2(0, -get_MainWindow()->keyboardHeight)); | ||
1169 | iRangei validPosRange = { bottom_Rect(winRect) - height_Rect(bounds), top_Rect(winRect) }; | ||
1170 | if (validPosRange.start > validPosRange.end) { | 1166 | if (validPosRange.start > validPosRange.end) { |
1171 | validPosRange.start = validPosRange.end; /* no room to scroll */ | 1167 | validPosRange.start = validPosRange.end; /* no room to scroll */ |
1172 | } | 1168 | } |
@@ -1244,18 +1240,28 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) { | |||
1244 | /* TODO: Motion events occur frequently. Maybe it would help if these were handled | 1240 | /* TODO: Motion events occur frequently. Maybe it would help if these were handled |
1245 | via audiences that specifically register to listen for motion, to minimize the | 1241 | via audiences that specifically register to listen for motion, to minimize the |
1246 | number of widgets that need to process them. */ | 1242 | number of widgets that need to process them. */ |
1247 | const int hoverScrollLimit = 2 * lineHeight_Text(default_FontId); | 1243 | const int hoverScrollLimit = 1.5f * lineHeight_Text(default_FontId); |
1248 | float speed = 0.0f; | 1244 | float speed = 0.0f; |
1249 | if (ev->motion.y < hoverScrollLimit) { | 1245 | if (ev->motion.y < hoverScrollLimit) { |
1250 | speed = (hoverScrollLimit - ev->motion.y) / (float) hoverScrollLimit; | 1246 | speed = (hoverScrollLimit - ev->motion.y) / (float) hoverScrollLimit; |
1251 | } | 1247 | } |
1252 | else { | 1248 | else { |
1253 | const int bottomLimit = bottom_Rect(rect_Root(d->root)) - hoverScrollLimit; | 1249 | const iWindow *win = window_Widget(d); |
1254 | if (ev->motion.y > bottomLimit ) { | 1250 | SDL_Rect usable; |
1251 | SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(win->win), | ||
1252 | &usable); | ||
1253 | const int bottomLimit = | ||
1254 | iMin(bottom_Rect(rect_Root(d->root)), usable.h * win->pixelRatio) - | ||
1255 | hoverScrollLimit; | ||
1256 | if (ev->motion.y > bottomLimit) { | ||
1255 | speed = -(ev->motion.y - bottomLimit) / (float) hoverScrollLimit; | 1257 | speed = -(ev->motion.y - bottomLimit) / (float) hoverScrollLimit; |
1256 | } | 1258 | } |
1259 | printf("my:%d bottomLimit:%d => %f (%d)\n", ev->motion.y, bottomLimit, speed | ||
1260 | ,isOverflowScrollPossible_Widget_(d, speed)); fflush(stdout); | ||
1257 | } | 1261 | } |
1258 | if (speed != 0.0f && isOverflowScrollPossible_Widget_(d, speed > 0 ? 1 : -1)) { | 1262 | const int dir = speed > 0 ? 1 : -1; |
1263 | if (speed != 0.0f && isOverflowScrollPossible_Widget_(d, dir)) { | ||
1264 | // speed = dir * powf(speed, 1.5f); | ||
1259 | const uint32_t nowTime = SDL_GetTicks(); | 1265 | const uint32_t nowTime = SDL_GetTicks(); |
1260 | uint32_t elapsed = nowTime - lastHoverOverflowMotionTime_; | 1266 | uint32_t elapsed = nowTime - lastHoverOverflowMotionTime_; |
1261 | if (elapsed > 100) { | 1267 | 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) { | |||
1676 | #if !defined (iPlatformApple) | 1676 | #if !defined (iPlatformApple) |
1677 | setForceSoftwareRender_App(iTrue); | 1677 | setForceSoftwareRender_App(iTrue); |
1678 | #endif | 1678 | #endif |
1679 | SDL_Rect usableRect; | ||
1680 | SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(get_MainWindow()->base.win), | ||
1681 | &usableRect); | ||
1679 | iWindow *win = | 1682 | iWindow *win = |
1680 | new_Window(popup_WindowType, | 1683 | new_Window(popup_WindowType, |
1681 | (iRect){ screenPos, divf_I2(rootWidget->rect.size, get_Window()->pixelRatio) }, | 1684 | (iRect){ screenPos, min_I2(divf_I2(rootWidget->rect.size, get_Window()->pixelRatio), |
1685 | init_I2(usableRect.w, usableRect.h)) }, | ||
1682 | SDL_WINDOW_ALWAYS_ON_TOP | | 1686 | SDL_WINDOW_ALWAYS_ON_TOP | |
1683 | #if !defined (iPlatformAppleDesktop) | 1687 | #if !defined (iPlatformAppleDesktop) |
1684 | SDL_WINDOW_BORDERLESS | | 1688 | SDL_WINDOW_BORDERLESS | |