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 | |
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')
-rw-r--r-- | src/ui/documentwidget.c | 4 | ||||
-rw-r--r-- | src/ui/util.c | 85 | ||||
-rw-r--r-- | src/ui/widget.c | 80 | ||||
-rw-r--r-- | src/ui/widget.h | 3 | ||||
-rw-r--r-- | src/ui/window.c | 1 |
5 files changed, 135 insertions, 38 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 6df25433..02358597 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -1653,7 +1653,9 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1653 | setSize_Widget(sizer, init_I2(gap_UI * 90, 1)); | 1653 | setSize_Widget(sizer, init_I2(gap_UI * 90, 1)); |
1654 | addChildFlags_Widget(dlg, iClob(sizer), frameless_WidgetFlag); | 1654 | addChildFlags_Widget(dlg, iClob(sizer), frameless_WidgetFlag); |
1655 | setFlags_Widget(dlg, centerHorizontal_WidgetFlag, iFalse); | 1655 | setFlags_Widget(dlg, centerHorizontal_WidgetFlag, iFalse); |
1656 | setPos_Widget(dlg, bottomLeft_Rect(bounds_Widget(findWidget_App("navbar.lock")))); | 1656 | if (deviceType_App() != phone_AppDeviceType) { |
1657 | setPos_Widget(dlg, bottomLeft_Rect(bounds_Widget(findWidget_App("navbar.lock")))); | ||
1658 | } | ||
1657 | arrange_Widget(dlg); | 1659 | arrange_Widget(dlg); |
1658 | addAction_Widget(dlg, SDLK_ESCAPE, 0, "message.ok"); | 1660 | addAction_Widget(dlg, SDLK_ESCAPE, 0, "message.ok"); |
1659 | addAction_Widget(dlg, SDLK_SPACE, 0, "message.ok"); | 1661 | addAction_Widget(dlg, SDLK_SPACE, 0, "message.ok"); |
diff --git a/src/ui/util.c b/src/ui/util.c index 18ed7ba2..c1e27751 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -403,6 +403,7 @@ static iBool isCommandIgnoredByMenus_(const char *cmd) { | |||
403 | equal_Command(cmd, "document.changed") || | 403 | equal_Command(cmd, "document.changed") || |
404 | equal_Command(cmd, "visited.changed") || | 404 | equal_Command(cmd, "visited.changed") || |
405 | (deviceType_App() == desktop_AppDeviceType && equal_Command(cmd, "window.resized")) || | 405 | (deviceType_App() == desktop_AppDeviceType && equal_Command(cmd, "window.resized")) || |
406 | equal_Command(cmd, "widget.overflow") || | ||
406 | equal_Command(cmd, "window.reload.update") || | 407 | equal_Command(cmd, "window.reload.update") || |
407 | equal_Command(cmd, "window.mouse.exited") || | 408 | equal_Command(cmd, "window.mouse.exited") || |
408 | equal_Command(cmd, "window.mouse.entered") || | 409 | equal_Command(cmd, "window.mouse.entered") || |
@@ -909,6 +910,23 @@ iWidget *makeSheet_Widget(const char *id) { | |||
909 | return sheet; | 910 | return sheet; |
910 | } | 911 | } |
911 | 912 | ||
913 | static void updateSheetPanelMetrics_(iWidget *sheet) { | ||
914 | iWidget *navi = findChild_Widget(sheet, "panel.navi"); | ||
915 | iWidget *naviPad = child_Widget(navi, 0); | ||
916 | int naviHeight = lineHeight_Text(defaultBig_FontId) + 4 * gap_UI; | ||
917 | #if defined (iPlatformAppleMobile) | ||
918 | float left, right, top, bottom; | ||
919 | safeAreaInsets_iOS(&left, &top, &right, &bottom); | ||
920 | setPadding_Widget(sheet, left, 0, right, 0); | ||
921 | navi->rect.pos = init_I2(left, top); | ||
922 | iConstForEach(PtrArray, i, findChildren_Widget(sheet, "panel.toppad")) { | ||
923 | iWidget *pad = *i.value; | ||
924 | setSize_Widget(pad, init1_I2(naviHeight)); | ||
925 | } | ||
926 | #endif | ||
927 | setSize_Widget(navi, init_I2(-1, naviHeight)); | ||
928 | } | ||
929 | |||
912 | static iBool slidePanelHandler_(iWidget *d, const char *cmd) { | 930 | static iBool slidePanelHandler_(iWidget *d, const char *cmd) { |
913 | if (equal_Command(cmd, "panel.open")) { | 931 | if (equal_Command(cmd, "panel.open")) { |
914 | iWidget *button = pointer_Command(cmd); | 932 | iWidget *button = pointer_Command(cmd); |
@@ -944,19 +962,9 @@ static iBool slidePanelHandler_(iWidget *d, const char *cmd) { | |||
944 | return iTrue; | 962 | return iTrue; |
945 | } | 963 | } |
946 | if (equal_Command(cmd, "window.resized")) { | 964 | if (equal_Command(cmd, "window.resized")) { |
947 | iWidget *sheet = parent_Widget(d); | 965 | updateSheetPanelMetrics_(parent_Widget(d)); |
948 | #if defined (iPlatformAppleMobile) | 966 | } |
949 | float left, top, right, bottom; | 967 | return iFalse; |
950 | safeAreaInsets_iOS(&left, &top, &right, &bottom); | ||
951 | /* TODO: incorrect */ | ||
952 | if (isLandscape_App()) { | ||
953 | setPadding_Widget(sheet, left, 0, right, 0); | ||
954 | } | ||
955 | else { | ||
956 | setPadding1_Widget(sheet, 0); | ||
957 | } | ||
958 | #endif | ||
959 | } return iFalse; | ||
960 | } | 968 | } |
961 | 969 | ||
962 | static iBool isTwoColumnPage_(iWidget *d) { | 970 | static iBool isTwoColumnPage_(iWidget *d) { |
@@ -1082,19 +1090,6 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1082 | can be taller than the display. In hindsight, it may have been easier to | 1090 | can be taller than the display. In hindsight, it may have been easier to |
1083 | create phone versions of each dialog, but at least this works with any future | 1091 | create phone versions of each dialog, but at least this works with any future |
1084 | changes to the UI (..."works"). */ | 1092 | changes to the UI (..."works"). */ |
1085 | int topSafe = 0; | ||
1086 | int navBarHeight = lineHeight_Text(defaultBig_FontId) + 4 * gap_UI; | ||
1087 | #if defined (iPlatformAppleMobile) | ||
1088 | /* Safe area insets. */ { | ||
1089 | /* TODO: Must be updated when orientation changes; use a widget flag? */ | ||
1090 | float l, t, r, b; | ||
1091 | safeAreaInsets_iOS(&l, &t, &r, &b); | ||
1092 | // setPadding_Widget(sheet, l, t, r, b); | ||
1093 | setPadding1_Widget(sheet, 0); | ||
1094 | topSafe = t; | ||
1095 | navBarHeight += t; | ||
1096 | } | ||
1097 | #endif | ||
1098 | setFlags_Widget(sheet, | 1093 | setFlags_Widget(sheet, |
1099 | keepOnTop_WidgetFlag | | 1094 | keepOnTop_WidgetFlag | |
1100 | parentCannotResize_WidgetFlag | | 1095 | parentCannotResize_WidgetFlag | |
@@ -1110,6 +1105,7 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1110 | resizeWidthOfChildren_WidgetFlag, | 1105 | resizeWidthOfChildren_WidgetFlag, |
1111 | iTrue); | 1106 | iTrue); |
1112 | setBackgroundColor_Widget(sheet, uiBackground_ColorId); | 1107 | setBackgroundColor_Widget(sheet, uiBackground_ColorId); |
1108 | setPadding1_Widget(sheet, 0); | ||
1113 | iPtrArray *contents = collect_PtrArray(new_PtrArray()); /* two-column pages */ | 1109 | iPtrArray *contents = collect_PtrArray(new_PtrArray()); /* two-column pages */ |
1114 | iPtrArray *panelButtons = collect_PtrArray(new_PtrArray()); | 1110 | iPtrArray *panelButtons = collect_PtrArray(new_PtrArray()); |
1115 | iWidget *tabs = findChild_Widget(sheet, "prefs.tabs"); | 1111 | iWidget *tabs = findChild_Widget(sheet, "prefs.tabs"); |
@@ -1166,7 +1162,6 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1166 | } | 1162 | } |
1167 | } | 1163 | } |
1168 | const iBool useSlidePanels = (size_PtrArray(contents) == size_PtrArray(panelButtons)); | 1164 | const iBool useSlidePanels = (size_PtrArray(contents) == size_PtrArray(panelButtons)); |
1169 | topPanel->rect.pos = init_I2(0, navBarHeight); | ||
1170 | addChildFlags_Widget(sheet, iClob(topPanel), | 1165 | addChildFlags_Widget(sheet, iClob(topPanel), |
1171 | arrangeVertical_WidgetFlag | | 1166 | arrangeVertical_WidgetFlag | |
1172 | resizeWidthOfChildren_WidgetFlag | arrangeHeight_WidgetFlag | | 1167 | resizeWidthOfChildren_WidgetFlag | arrangeHeight_WidgetFlag | |
@@ -1182,7 +1177,7 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1182 | setId_Widget(owner, "panel"); | 1177 | setId_Widget(owner, "panel"); |
1183 | setUserData_Object(button, owner); | 1178 | setUserData_Object(button, owner); |
1184 | setBackgroundColor_Widget(owner, uiBackground_ColorId); | 1179 | setBackgroundColor_Widget(owner, uiBackground_ColorId); |
1185 | addChild_Widget(owner, iClob(makePadding_Widget(navBarHeight - topSafe))); | 1180 | setId_Widget(addChild_Widget(owner, iClob(makePadding_Widget(0))), "panel.toppad"); |
1186 | iLabelWidget *title = addChildFlags_Widget(owner, | 1181 | iLabelWidget *title = addChildFlags_Widget(owner, |
1187 | iClob(new_LabelWidget(cstrCollect_String(upper_String(text_LabelWidget(button))), NULL)), alignLeft_WidgetFlag | frameless_WidgetFlag); | 1182 | iClob(new_LabelWidget(cstrCollect_String(upper_String(text_LabelWidget(button))), NULL)), alignLeft_WidgetFlag | frameless_WidgetFlag); |
1188 | setFont_LabelWidget(title, uiLabelLargeBold_FontId); | 1183 | setFont_LabelWidget(title, uiLabelLargeBold_FontId); |
@@ -1192,6 +1187,7 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1192 | focusRoot_WidgetFlag | | 1187 | focusRoot_WidgetFlag | |
1193 | hidden_WidgetFlag | | 1188 | hidden_WidgetFlag | |
1194 | disabled_WidgetFlag | | 1189 | disabled_WidgetFlag | |
1190 | //safePadding_WidgetFlag | | ||
1195 | arrangeVertical_WidgetFlag | | 1191 | arrangeVertical_WidgetFlag | |
1196 | resizeWidthOfChildren_WidgetFlag | | 1192 | resizeWidthOfChildren_WidgetFlag | |
1197 | arrangeHeight_WidgetFlag | | 1193 | arrangeHeight_WidgetFlag | |
@@ -1337,6 +1333,7 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1337 | chevron_WidgetFlag); | 1333 | chevron_WidgetFlag); |
1338 | } | 1334 | } |
1339 | else { | 1335 | else { |
1336 | setFlags_Widget(topPanel, overflowScrollable_WidgetFlag, iTrue); | ||
1340 | /* Update heading style. */ | 1337 | /* Update heading style. */ |
1341 | setFont_LabelWidget((iLabelWidget *) dialogHeading, uiLabelLargeBold_FontId); | 1338 | setFont_LabelWidget((iLabelWidget *) dialogHeading, uiLabelLargeBold_FontId); |
1342 | setFlags_Widget(dialogHeading, alignLeft_WidgetFlag, iTrue); | 1339 | setFlags_Widget(dialogHeading, alignLeft_WidgetFlag, iTrue); |
@@ -1348,11 +1345,16 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1348 | removeChild_Widget(parent_Widget(input), input); | 1345 | removeChild_Widget(parent_Widget(input), input); |
1349 | addChild_Widget(topPanel, iClob(makeValuePadding_(as_Widget(input)))); | 1346 | addChild_Widget(topPanel, iClob(makeValuePadding_(as_Widget(input)))); |
1350 | } | 1347 | } |
1348 | /* Top padding for each panel, to account for the overlaid navbar. */ { | ||
1349 | setId_Widget(addChildPos_Widget(topPanel, | ||
1350 | iClob(makePadding_Widget(0)), front_WidgetAddPos), | ||
1351 | "panel.toppad"); | ||
1352 | } | ||
1351 | /* Navbar. */ { | 1353 | /* Navbar. */ { |
1352 | iWidget *navi = new_Widget(); | 1354 | iWidget *navi = new_Widget(); |
1353 | setSize_Widget(navi, init_I2(-1, navBarHeight)); | 1355 | setId_Widget(navi, "panel.navi"); |
1354 | setBackgroundColor_Widget(navi, uiBackground_ColorId); | 1356 | setBackgroundColor_Widget(navi, uiBackground_ColorId); |
1355 | addChild_Widget(navi, iClob(makePadding_Widget(topSafe))); | 1357 | addChild_Widget(navi, iClob(makePadding_Widget(0))); |
1356 | iLabelWidget *back = addChildFlags_Widget(navi, | 1358 | iLabelWidget *back = addChildFlags_Widget(navi, |
1357 | iClob(new_LabelWidget(leftAngle_Icon " Back", "panel.close")), | 1359 | iClob(new_LabelWidget(leftAngle_Icon " Back", "panel.close")), |
1358 | noBackground_WidgetFlag | frameless_WidgetFlag | | 1360 | noBackground_WidgetFlag | frameless_WidgetFlag | |
@@ -1361,6 +1363,7 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1361 | setId_Widget(as_Widget(back), "panel.back"); | 1363 | setId_Widget(as_Widget(back), "panel.back"); |
1362 | setFont_LabelWidget(back, defaultBig_FontId); | 1364 | setFont_LabelWidget(back, defaultBig_FontId); |
1363 | if (!isPrefs) { | 1365 | if (!isPrefs) { |
1366 | /* Pick up the dialog buttons for the navbar. */ | ||
1364 | iWidget *buttons = findChild_Widget(sheet, "dialogbuttons"); | 1367 | iWidget *buttons = findChild_Widget(sheet, "dialogbuttons"); |
1365 | iLabelWidget *cancel = findMenuItem_Widget(buttons, "cancel"); | 1368 | iLabelWidget *cancel = findMenuItem_Widget(buttons, "cancel"); |
1366 | if (cancel) { | 1369 | if (cancel) { |
@@ -1385,7 +1388,22 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1385 | addChildFlags_Widget(as_Widget(back), iClob(def), moveToParentRightEdge_WidgetFlag); | 1388 | addChildFlags_Widget(as_Widget(back), iClob(def), moveToParentRightEdge_WidgetFlag); |
1386 | updateSize_LabelWidget(def); | 1389 | updateSize_LabelWidget(def); |
1387 | } | 1390 | } |
1388 | /* TODO: Action buttons should be added in the bottom as extra buttons. */ | 1391 | /* Action buttons are added in the bottom as extra buttons. */ { |
1392 | iBool isFirstAction = iTrue; | ||
1393 | iForEach(ObjectList, i, children_Widget(buttons)) { | ||
1394 | if (isInstance_Object(i.object, &Class_LabelWidget) && | ||
1395 | i.object != cancel && i.object != def) { | ||
1396 | iLabelWidget *item = i.object; | ||
1397 | setBackgroundColor_Widget(i.object, uiBackgroundSidebar_ColorId); | ||
1398 | setFont_LabelWidget(item, defaultBig_FontId); | ||
1399 | removeChild_Widget(buttons, item); | ||
1400 | addChildFlags_Widget(topPanel, iClob(item), panelButtonFlags | | ||
1401 | (isFirstAction ? borderTop_WidgetFlag : 0)); | ||
1402 | updateSize_LabelWidget(item); | ||
1403 | isFirstAction = iFalse; | ||
1404 | } | ||
1405 | } | ||
1406 | } | ||
1389 | iRelease(removeChild_Widget(parent_Widget(buttons), buttons)); | 1407 | iRelease(removeChild_Widget(parent_Widget(buttons), buttons)); |
1390 | /* Styling for remaining elements. */ | 1408 | /* Styling for remaining elements. */ |
1391 | iForEach(ObjectList, i, children_Widget(topPanel)) { | 1409 | iForEach(ObjectList, i, children_Widget(topPanel)) { |
@@ -1400,10 +1418,14 @@ void finalizeSheet_Widget(iWidget *sheet) { | |||
1400 | } | 1418 | } |
1401 | } | 1419 | } |
1402 | addChildFlags_Widget(sheet, iClob(navi), | 1420 | addChildFlags_Widget(sheet, iClob(navi), |
1421 | drawBackgroundToVerticalSafeArea_WidgetFlag | | ||
1403 | arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag | | 1422 | arrangeHeight_WidgetFlag | resizeWidthOfChildren_WidgetFlag | |
1404 | resizeToParentWidth_WidgetFlag | arrangeVertical_WidgetFlag); | 1423 | resizeToParentWidth_WidgetFlag | arrangeVertical_WidgetFlag); |
1405 | } | 1424 | } |
1425 | updateSheetPanelMetrics_(sheet); | ||
1406 | arrange_Widget(sheet->parent); | 1426 | arrange_Widget(sheet->parent); |
1427 | postCommand_App("widget.overflow"); /* with the correct dimensions */ | ||
1428 | // printTree_Widget(sheet); | ||
1407 | } | 1429 | } |
1408 | else { | 1430 | else { |
1409 | arrange_Widget(sheet); | 1431 | arrange_Widget(sheet); |
@@ -1613,6 +1635,7 @@ static iBool messageHandler_(iWidget *msg, const char *cmd) { | |||
1613 | equal_Command(cmd, "document.autoreload") || | 1635 | equal_Command(cmd, "document.autoreload") || |
1614 | equal_Command(cmd, "document.reload") || | 1636 | equal_Command(cmd, "document.reload") || |
1615 | equal_Command(cmd, "document.request.updated") || | 1637 | equal_Command(cmd, "document.request.updated") || |
1638 | equal_Command(cmd, "widget.overflow") || | ||
1616 | startsWith_CStr(cmd, "window."))) { | 1639 | startsWith_CStr(cmd, "window."))) { |
1617 | destroy_Widget(msg); | 1640 | destroy_Widget(msg); |
1618 | } | 1641 | } |
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; |
diff --git a/src/ui/widget.h b/src/ui/widget.h index 8dc51a1f..88d75b62 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h | |||
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
29 | 29 | ||
30 | #include <the_Foundation/object.h> | 30 | #include <the_Foundation/object.h> |
31 | #include <the_Foundation/objectlist.h> | 31 | #include <the_Foundation/objectlist.h> |
32 | #include <the_Foundation/ptrarray.h> | ||
32 | #include <the_Foundation/rect.h> | 33 | #include <the_Foundation/rect.h> |
33 | #include <the_Foundation/string.h> | 34 | #include <the_Foundation/string.h> |
34 | #include <SDL_events.h> | 35 | #include <SDL_events.h> |
@@ -108,6 +109,7 @@ enum iWidgetFlag { | |||
108 | #define drawBackgroundToBottom_WidgetFlag iBit64(53) | 109 | #define drawBackgroundToBottom_WidgetFlag iBit64(53) |
109 | #define dragged_WidgetFlag iBit64(54) | 110 | #define dragged_WidgetFlag iBit64(54) |
110 | #define hittable_WidgetFlag iBit64(55) | 111 | #define hittable_WidgetFlag iBit64(55) |
112 | #define safePadding_WidgetFlag iBit64(56) /* padded using safe area insets */ | ||
111 | 113 | ||
112 | enum iWidgetAddPos { | 114 | enum iWidgetAddPos { |
113 | back_WidgetAddPos, | 115 | back_WidgetAddPos, |
@@ -167,6 +169,7 @@ iInt2 localCoord_Widget (const iWidget *, iInt2 coord); | |||
167 | iBool contains_Widget (const iWidget *, iInt2 coord); | 169 | iBool contains_Widget (const iWidget *, iInt2 coord); |
168 | iAny * hitChild_Widget (const iWidget *, iInt2 coord); | 170 | iAny * hitChild_Widget (const iWidget *, iInt2 coord); |
169 | iAny * findChild_Widget (const iWidget *, const char *id); | 171 | iAny * findChild_Widget (const iWidget *, const char *id); |
172 | const iPtrArray *findChildren_Widget (const iWidget *, const char *id); | ||
170 | iAny * findParentClass_Widget(const iWidget *, const iAnyClass *class); | 173 | iAny * findParentClass_Widget(const iWidget *, const iAnyClass *class); |
171 | iAny * findFocusable_Widget(const iWidget *startFrom, enum iWidgetFocusDir focusDir); | 174 | iAny * findFocusable_Widget(const iWidget *startFrom, enum iWidgetFocusDir focusDir); |
172 | size_t childCount_Widget (const iWidget *); | 175 | size_t childCount_Widget (const iWidget *); |
diff --git a/src/ui/window.c b/src/ui/window.c index 2ef67142..6e81c14c 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -1210,6 +1210,7 @@ static void updateRootSize_Window_(iWindow *d, iBool notifyAlways) { | |||
1210 | size->y, | 1210 | size->y, |
1211 | isHoriz, | 1211 | isHoriz, |
1212 | isVert); | 1212 | isVert); |
1213 | postCommand_App("widget.overflow"); /* check bounds with updated sizes */ | ||
1213 | postRefresh_App(); | 1214 | postRefresh_App(); |
1214 | d->place.lastNotifiedSize = *size; | 1215 | d->place.lastNotifiedSize = *size; |
1215 | } | 1216 | } |