summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-11-06 09:47:03 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-11-06 09:47:03 +0200
commit3bbbd1399373755cec95e9685d18ecebec3b9c24 (patch)
treefe987e205dd7b40f4dab61074a98e143d0ca4e46
parent9df0c10c915b504a9f6dcca88608d702e4548bb6 (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.
-rw-r--r--src/ui/lookupwidget.c3
-rw-r--r--src/ui/root.c33
-rw-r--r--src/ui/root.h2
-rw-r--r--src/ui/util.c4
-rw-r--r--src/ui/widget.c34
-rw-r--r--src/ui/window.c6
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
1532iInt2 visibleSize_Root(const iRoot *d) { 1532iRect 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 *);
40iInt2 size_Root (const iRoot *); 40iInt2 size_Root (const iRoot *);
41iRect rect_Root (const iRoot *); 41iRect rect_Root (const iRoot *);
42iRect safeRect_Root (const iRoot *); 42iRect safeRect_Root (const iRoot *);
43iInt2 visibleSize_Root (const iRoot *); /* may be obstructed by software keyboard */ 43iRect visibleRect_Root (const iRoot *); /* may be obstructed by software keyboard */
44iBool isNarrow_Root (const iRoot *); 44iBool isNarrow_Root (const iRoot *);
45int appIconSize_Root (void); 45int 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 |