diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-21 14:29:51 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-21 14:29:51 +0200 |
commit | 2f9e203058df442921fc0151ddc5fe9b68b87935 (patch) | |
tree | 5441025fcf4e974e82128f65376650bec7a941bb /src/ui | |
parent | b93ba1bfb860c2a4b5bf46c77f3f0d11b4eb1282 (diff) |
iOS: Save to Files; hide toolbar on scroll
There is no downloads directory on mobile. Instead, the downloaded file is temporarily cached and given to the iOS document picker to export.
Added an option to hide the bottom toolbar while scrolling down.
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/documentwidget.c | 63 | ||||
-rw-r--r-- | src/ui/util.c | 5 | ||||
-rw-r--r-- | src/ui/widget.c | 33 | ||||
-rw-r--r-- | src/ui/widget.h | 3 | ||||
-rw-r--r-- | src/ui/window.c | 33 | ||||
-rw-r--r-- | src/ui/window.h | 1 |
6 files changed, 98 insertions, 40 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index d9b78a4d..0b9757d4 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -48,6 +48,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
48 | #include "visbuf.h" | 48 | #include "visbuf.h" |
49 | #include "visited.h" | 49 | #include "visited.h" |
50 | 50 | ||
51 | #if defined (iPlatformAppleMobile) | ||
52 | # include "ios.h" | ||
53 | #endif | ||
54 | |||
51 | #include <the_Foundation/file.h> | 55 | #include <the_Foundation/file.h> |
52 | #include <the_Foundation/fileinfo.h> | 56 | #include <the_Foundation/fileinfo.h> |
53 | #include <the_Foundation/objectlist.h> | 57 | #include <the_Foundation/objectlist.h> |
@@ -220,6 +224,7 @@ struct Impl_DocumentWidget { | |||
220 | SDL_Texture * sideIconBuf; | 224 | SDL_Texture * sideIconBuf; |
221 | iTextBuf * timestampBuf; | 225 | iTextBuf * timestampBuf; |
222 | iTranslation * translation; | 226 | iTranslation * translation; |
227 | iWidget * phoneToolbar; | ||
223 | }; | 228 | }; |
224 | 229 | ||
225 | iDefineObjectConstruction(DocumentWidget) | 230 | iDefineObjectConstruction(DocumentWidget) |
@@ -231,6 +236,7 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
231 | setFlags_Widget(w, hover_WidgetFlag, iTrue); | 236 | setFlags_Widget(w, hover_WidgetFlag, iTrue); |
232 | init_PersistentDocumentState(&d->mod); | 237 | init_PersistentDocumentState(&d->mod); |
233 | d->flags = 0; | 238 | d->flags = 0; |
239 | d->phoneToolbar = NULL; | ||
234 | iZap(d->certExpiry); | 240 | iZap(d->certExpiry); |
235 | d->certFingerprint = new_Block(0); | 241 | d->certFingerprint = new_Block(0); |
236 | d->certFlags = 0; | 242 | d->certFlags = 0; |
@@ -440,8 +446,13 @@ static float normScrollPos_DocumentWidget_(const iDocumentWidget *d) { | |||
440 | } | 446 | } |
441 | 447 | ||
442 | static int scrollMax_DocumentWidget_(const iDocumentWidget *d) { | 448 | static int scrollMax_DocumentWidget_(const iDocumentWidget *d) { |
443 | return size_GmDocument(d->doc).y - height_Rect(bounds_Widget(constAs_Widget(d))) + | 449 | int sm = size_GmDocument(d->doc).y - height_Rect(bounds_Widget(constAs_Widget(d))) + |
444 | (hasSiteBanner_GmDocument(d->doc) ? 1 : 2) * d->pageMargin * gap_UI; | 450 | (hasSiteBanner_GmDocument(d->doc) ? 1 : 2) * d->pageMargin * gap_UI; |
451 | if (d->phoneToolbar) { | ||
452 | sm += rootSize_Window(get_Window()).y - | ||
453 | top_Rect(boundsWithoutVisualOffset_Widget(d->phoneToolbar)); | ||
454 | } | ||
455 | return sm; | ||
445 | } | 456 | } |
446 | 457 | ||
447 | static void invalidateLink_DocumentWidget_(iDocumentWidget *d, iGmLinkId id) { | 458 | static void invalidateLink_DocumentWidget_(iDocumentWidget *d, iGmLinkId id) { |
@@ -815,9 +826,10 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode | |||
815 | appendFormat_String(src, | 826 | appendFormat_String(src, |
816 | "\n```\n%s\n```\n" | 827 | "\n```\n%s\n```\n" |
817 | "You can save it as a file to your Downloads folder, though. " | 828 | "You can save it as a file to your Downloads folder, though. " |
818 | "Press %s or select \"Save to Downloads\" from the menu.", | 829 | "Press %s or select \"%s\" from the menu.", |
819 | cstr_String(meta), | 830 | cstr_String(meta), |
820 | cstr_String(key)); | 831 | cstr_String(key), |
832 | saveToDownloads_Label); | ||
821 | break; | 833 | break; |
822 | } | 834 | } |
823 | case slowDown_GmStatusCode: | 835 | case slowDown_GmStatusCode: |
@@ -1085,6 +1097,14 @@ static void smoothScroll_DocumentWidget_(iDocumentWidget *d, int offset, int dur | |||
1085 | const int scrollMax = scrollMax_DocumentWidget_(d); | 1097 | const int scrollMax = scrollMax_DocumentWidget_(d); |
1086 | if (scrollMax > 0) { | 1098 | if (scrollMax > 0) { |
1087 | destY = iMin(destY, scrollMax); | 1099 | destY = iMin(destY, scrollMax); |
1100 | if (deviceType_App() == phone_AppDeviceType) { | ||
1101 | if (destY == scrollMax) { | ||
1102 | showToolbars_Window(get_Window(), iTrue); | ||
1103 | } | ||
1104 | else if (prefs_App()->hideToolbarOnScroll && iAbs(offset) > 5) { | ||
1105 | showToolbars_Window(get_Window(), offset < 0); | ||
1106 | } | ||
1107 | } | ||
1088 | } | 1108 | } |
1089 | else { | 1109 | else { |
1090 | destY = 0; | 1110 | destY = 0; |
@@ -1443,12 +1463,17 @@ static void saveToDownloads_(const iString *url, const iString *mime, const iBlo | |||
1443 | iFile *f = new_File(savePath); | 1463 | iFile *f = new_File(savePath); |
1444 | if (open_File(f, writeOnly_FileMode)) { | 1464 | if (open_File(f, writeOnly_FileMode)) { |
1445 | write_File(f, content); | 1465 | write_File(f, content); |
1466 | close_File(f); | ||
1446 | const size_t size = size_Block(content); | 1467 | const size_t size = size_Block(content); |
1447 | const iBool isMega = size >= 1000000; | 1468 | const iBool isMega = size >= 1000000; |
1469 | #if defined (iPlatformAppleMobile) | ||
1470 | exportDownloadedFile_iOS(savePath); | ||
1471 | #else | ||
1448 | makeMessage_Widget(uiHeading_ColorEscape "FILE SAVED", | 1472 | makeMessage_Widget(uiHeading_ColorEscape "FILE SAVED", |
1449 | format_CStr("%s\nSize: %.3f %s", cstr_String(path_File(f)), | 1473 | format_CStr("%s\nSize: %.3f %s", cstr_String(path_File(f)), |
1450 | isMega ? size / 1.0e6f : (size / 1.0e3f), | 1474 | isMega ? size / 1.0e6f : (size / 1.0e3f), |
1451 | isMega ? "MB" : "KB")); | 1475 | isMega ? "MB" : "KB")); |
1476 | #endif | ||
1452 | } | 1477 | } |
1453 | else { | 1478 | else { |
1454 | makeMessage_Widget(uiTextCaution_ColorEscape "ERROR SAVING FILE", | 1479 | makeMessage_Widget(uiTextCaution_ColorEscape "ERROR SAVING FILE", |
@@ -1496,8 +1521,8 @@ static const int homeRowKeys_[] = { | |||
1496 | static iBool updateDocumentWidthRetainingScrollPosition_DocumentWidget_(iDocumentWidget *d, | 1521 | static iBool updateDocumentWidthRetainingScrollPosition_DocumentWidget_(iDocumentWidget *d, |
1497 | iBool keepCenter) { | 1522 | iBool keepCenter) { |
1498 | const int newWidth = documentWidth_DocumentWidget_(d); | 1523 | const int newWidth = documentWidth_DocumentWidget_(d); |
1499 | if (newWidth == size_GmDocument(d->doc).x) { | 1524 | if (newWidth == size_GmDocument(d->doc).x && !keepCenter /* not a font change */) { |
1500 | return iFalse; /* hasn't changed */ | 1525 | return iFalse; |
1501 | } | 1526 | } |
1502 | /* Font changes (i.e., zooming) will keep the view centered, otherwise keep the top | 1527 | /* Font changes (i.e., zooming) will keep the view centered, otherwise keep the top |
1503 | of the visible area fixed. */ | 1528 | of the visible area fixed. */ |
@@ -1526,6 +1551,7 @@ static iBool updateDocumentWidthRetainingScrollPosition_DocumentWidget_(iDocumen | |||
1526 | scrollTo_DocumentWidget_(d, mid_Rect(run->bounds).y, iTrue); | 1551 | scrollTo_DocumentWidget_(d, mid_Rect(run->bounds).y, iTrue); |
1527 | } | 1552 | } |
1528 | } | 1553 | } |
1554 | return iTrue; | ||
1529 | } | 1555 | } |
1530 | 1556 | ||
1531 | static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | 1557 | static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { |
@@ -1533,6 +1559,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1533 | if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed")) { | 1559 | if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed")) { |
1534 | /* Alt/Option key may be involved in window size changes. */ | 1560 | /* Alt/Option key may be involved in window size changes. */ |
1535 | iChangeFlags(d->flags, showLinkNumbers_DocumentWidgetFlag, iFalse); | 1561 | iChangeFlags(d->flags, showLinkNumbers_DocumentWidgetFlag, iFalse); |
1562 | d->phoneToolbar = findWidget_App("toolbar"); | ||
1536 | const iBool keepCenter = equal_Command(cmd, "font.changed"); | 1563 | const iBool keepCenter = equal_Command(cmd, "font.changed"); |
1537 | updateDocumentWidthRetainingScrollPosition_DocumentWidget_(d, keepCenter); | 1564 | updateDocumentWidthRetainingScrollPosition_DocumentWidget_(d, keepCenter); |
1538 | updateSideIconBuf_DocumentWidget_(d); | 1565 | updateSideIconBuf_DocumentWidget_(d); |
@@ -2361,36 +2388,16 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2361 | } | 2388 | } |
2362 | } | 2389 | } |
2363 | else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { | 2390 | else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { |
2364 | /* TODO: Maybe clean this up a bit? Wheel events are used for scrolling | ||
2365 | but they are calculated differently based on device/mouse/trackpad. */ | ||
2366 | const iInt2 mouseCoord = mouseCoord_Window(get_Window()); | 2391 | const iInt2 mouseCoord = mouseCoord_Window(get_Window()); |
2367 | if (isPerPixel_MouseWheelEvent(&ev->wheel)) { | 2392 | if (isPerPixel_MouseWheelEvent(&ev->wheel)) { |
2368 | stop_Anim(&d->scrollY); | 2393 | stop_Anim(&d->scrollY); |
2369 | iInt2 wheel = init_I2(ev->wheel.x, ev->wheel.y); | 2394 | iInt2 wheel = init_I2(ev->wheel.x, ev->wheel.y); |
2370 | //# if defined (iPlatformAppleMobile) | ||
2371 | // wheel.x = -wheel.x; | ||
2372 | //# else | ||
2373 | // /* Wheel mounts are in points. */ | ||
2374 | // mulfv_I2(&wheel, get_Window()->pixelRatio); | ||
2375 | // /* Only scroll on one axis at a time. */ | ||
2376 | // if (iAbs(wheel.x) > iAbs(wheel.y)) { | ||
2377 | // wheel.y = 0; | ||
2378 | // } | ||
2379 | // else { | ||
2380 | // wheel.x = 0; | ||
2381 | // } | ||
2382 | //# endif | ||
2383 | scroll_DocumentWidget_(d, -wheel.y); | 2395 | scroll_DocumentWidget_(d, -wheel.y); |
2384 | scrollWideBlock_DocumentWidget_(d, mouseCoord, -wheel.x, 0); | 2396 | scrollWideBlock_DocumentWidget_(d, mouseCoord, -wheel.x, 0); |
2385 | } | 2397 | } |
2386 | else { | 2398 | else { |
2387 | /* Traditional mouse wheel. */ | 2399 | /* Traditional mouse wheel. */ |
2388 | //#if defined (iPlatformApple) | ||
2389 | // /* Disregard wheel acceleration applied by the OS. */ | ||
2390 | // const int amount = iSign(ev->wheel.y); | ||
2391 | //#else | ||
2392 | const int amount = ev->wheel.y; | 2400 | const int amount = ev->wheel.y; |
2393 | //#endif | ||
2394 | if (keyMods_Sym(modState_Keys()) == KMOD_PRIMARY) { | 2401 | if (keyMods_Sym(modState_Keys()) == KMOD_PRIMARY) { |
2395 | postCommandf_App("zoom.delta arg:%d", amount > 0 ? 10 : -10); | 2402 | postCommandf_App("zoom.delta arg:%d", amount > 0 ? 10 : -10); |
2396 | return iTrue; | 2403 | return iTrue; |
@@ -2513,7 +2520,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2513 | d->contextLink->mediaType != download_GmRunMediaType) { | 2520 | d->contextLink->mediaType != download_GmRunMediaType) { |
2514 | if (isFinished_GmRequest(mediaReq->req)) { | 2521 | if (isFinished_GmRequest(mediaReq->req)) { |
2515 | pushBack_Array(&items, | 2522 | pushBack_Array(&items, |
2516 | &(iMenuItem){ download_Icon " Save to Downloads", | 2523 | &(iMenuItem){ download_Icon " " saveToDownloads_Label, |
2517 | 0, | 2524 | 0, |
2518 | 0, | 2525 | 0, |
2519 | format_CStr("document.media.save link:%u", | 2526 | format_CStr("document.media.save link:%u", |
@@ -2558,7 +2565,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2558 | &items, | 2565 | &items, |
2559 | (iMenuItem[]){ | 2566 | (iMenuItem[]){ |
2560 | { "Copy Page Source", 'c', KMOD_PRIMARY, "copy" }, | 2567 | { "Copy Page Source", 'c', KMOD_PRIMARY, "copy" }, |
2561 | { download_Icon " Save to Downloads", SDLK_s, KMOD_PRIMARY, "document.save" } }, | 2568 | { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" } }, |
2562 | 2); | 2569 | 2); |
2563 | } | 2570 | } |
2564 | } | 2571 | } |
diff --git a/src/ui/util.c b/src/ui/util.c index 8fbe5d41..d68ae738 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -986,7 +986,6 @@ static iBool isTwoColumnPage_(iWidget *d) { | |||
986 | 986 | ||
987 | static iBool isOmittedPref_(const iString *id) { | 987 | static iBool isOmittedPref_(const iString *id) { |
988 | static const char *omittedPrefs[] = { | 988 | static const char *omittedPrefs[] = { |
989 | "prefs.downloads", | ||
990 | "prefs.smoothscroll", | 989 | "prefs.smoothscroll", |
991 | "prefs.imageloadscroll", | 990 | "prefs.imageloadscroll", |
992 | "prefs.retainwindow", | 991 | "prefs.retainwindow", |
@@ -1812,6 +1811,10 @@ iWidget *makePreferences_Widget(void) { | |||
1812 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.smoothscroll"))); | 1811 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.smoothscroll"))); |
1813 | addChild_Widget(headings, iClob(makeHeading_Widget("Load image on scroll:"))); | 1812 | addChild_Widget(headings, iClob(makeHeading_Widget("Load image on scroll:"))); |
1814 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.imageloadscroll"))); | 1813 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.imageloadscroll"))); |
1814 | if (deviceType_App() == phone_AppDeviceType) { | ||
1815 | addChild_Widget(headings, iClob(makeHeading_Widget("Hide toolbar on scroll:"))); | ||
1816 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.hidetoolbarscroll"))); | ||
1817 | } | ||
1815 | } | 1818 | } |
1816 | /* Window. */ { | 1819 | /* Window. */ { |
1817 | appendTwoColumnPage_(tabs, "Interface", '2', &headings, &values); | 1820 | appendTwoColumnPage_(tabs, "Interface", '2', &headings, &values); |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 81853c2a..23891999 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -223,6 +223,9 @@ void setVisualOffset_Widget(iWidget *d, int value, uint32_t span, int animFlags) | |||
223 | setFlags_Widget(d, visualOffset_WidgetFlag, iTrue); | 223 | setFlags_Widget(d, visualOffset_WidgetFlag, iTrue); |
224 | if (span == 0) { | 224 | if (span == 0) { |
225 | init_Anim(&d->visualOffset, value); | 225 | init_Anim(&d->visualOffset, value); |
226 | if (value == 0) { | ||
227 | setFlags_Widget(d, visualOffset_WidgetFlag, iFalse); /* offset is being reset */ | ||
228 | } | ||
226 | } | 229 | } |
227 | else { | 230 | else { |
228 | setValue_Anim(&d->visualOffset, value, span); | 231 | setValue_Anim(&d->visualOffset, value, span); |
@@ -346,6 +349,9 @@ void arrange_Widget(iWidget *d) { | |||
346 | else if (d->flags & moveToParentRightEdge_WidgetFlag) { | 349 | else if (d->flags & moveToParentRightEdge_WidgetFlag) { |
347 | d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); | 350 | d->rect.pos.x = width_Rect(innerRect_Widget_(d->parent)) - width_Rect(d->rect); |
348 | } | 351 | } |
352 | else if (d->flags & moveToParentBottomEdge_WidgetFlag) { | ||
353 | d->rect.pos.y = height_Rect(innerRect_Widget_(d->parent)) - height_Rect(d->rect); | ||
354 | } | ||
349 | else if (d->flags & centerHorizontal_WidgetFlag) { | 355 | else if (d->flags & centerHorizontal_WidgetFlag) { |
350 | centerHorizontal_Widget_(d); | 356 | centerHorizontal_Widget_(d); |
351 | } | 357 | } |
@@ -455,8 +461,12 @@ void arrange_Widget(iWidget *d) { | |||
455 | iForEach(ObjectList, i, d->children) { | 461 | iForEach(ObjectList, i, d->children) { |
456 | iWidget *child = as_Widget(i.object); | 462 | iWidget *child = as_Widget(i.object); |
457 | if (isArranged_Widget_(child) && ~child->flags & parentCannotResize_WidgetFlag) { | 463 | if (isArranged_Widget_(child) && ~child->flags & parentCannotResize_WidgetFlag) { |
458 | if (dirs.x) setWidth_Widget_(child, child->flags & unpadded_WidgetFlag ? unpaddedChildSize.x : childSize.x); | 464 | if (dirs.x) { |
459 | if (dirs.y) setHeight_Widget_(child, child->flags & unpadded_WidgetFlag ? unpaddedChildSize.y : childSize.y); | 465 | setWidth_Widget_(child, child->flags & unpadded_WidgetFlag ? unpaddedChildSize.x : childSize.x); |
466 | } | ||
467 | if (dirs.y && ~child->flags & parentCannotResizeHeight_WidgetFlag) { | ||
468 | setHeight_Widget_(child, child->flags & unpadded_WidgetFlag ? unpaddedChildSize.y : childSize.y); | ||
469 | } | ||
460 | } | 470 | } |
461 | } | 471 | } |
462 | } | 472 | } |
@@ -493,7 +503,8 @@ void arrange_Widget(iWidget *d) { | |||
493 | pos.y += child->rect.size.y; | 503 | pos.y += child->rect.size.y; |
494 | } | 504 | } |
495 | } | 505 | } |
496 | else if ((d->flags & resizeChildren_WidgetFlag) == resizeChildren_WidgetFlag) { | 506 | else if ((d->flags & resizeChildren_WidgetFlag) == resizeChildren_WidgetFlag && |
507 | ~child->flags & moveToParentBottomEdge_WidgetFlag) { | ||
497 | child->rect.pos = pos; | 508 | child->rect.pos = pos; |
498 | } | 509 | } |
499 | else if (d->flags & resizeWidthOfChildren_WidgetFlag) { | 510 | else if (d->flags & resizeWidthOfChildren_WidgetFlag) { |
@@ -522,7 +533,9 @@ void arrange_Widget(iWidget *d) { | |||
522 | iForEach(ObjectList, j, d->children) { | 533 | iForEach(ObjectList, j, d->children) { |
523 | iWidget *child = as_Widget(j.object); | 534 | iWidget *child = as_Widget(j.object); |
524 | if (child->flags & | 535 | if (child->flags & |
525 | (resizeToParentWidth_WidgetFlag | moveToParentLeftEdge_WidgetFlag | | 536 | (resizeToParentWidth_WidgetFlag | |
537 | moveToParentLeftEdge_WidgetFlag | | ||
538 | moveToParentBottomEdge_WidgetFlag | | ||
526 | moveToParentRightEdge_WidgetFlag)) { | 539 | moveToParentRightEdge_WidgetFlag)) { |
527 | arrange_Widget(child); | 540 | arrange_Widget(child); |
528 | } | 541 | } |
@@ -542,6 +555,10 @@ void arrange_Widget(iWidget *d) { | |||
542 | } | 555 | } |
543 | } | 556 | } |
544 | } | 557 | } |
558 | // if (d->flags & moveToParentBottomEdge_WidgetFlag) { | ||
559 | // /* TODO: Fix this: not DRY. See beginning of method. */ | ||
560 | // d->rect.pos.y = height_Rect(innerRect_Widget_(d->parent)) - height_Rect(d->rect); | ||
561 | // } | ||
545 | if (d->flags & centerHorizontal_WidgetFlag) { | 562 | if (d->flags & centerHorizontal_WidgetFlag) { |
546 | centerHorizontal_Widget_(d); | 563 | centerHorizontal_Widget_(d); |
547 | } | 564 | } |
@@ -574,6 +591,14 @@ iRect bounds_Widget(const iWidget *d) { | |||
574 | return bounds; | 591 | return bounds; |
575 | } | 592 | } |
576 | 593 | ||
594 | iRect boundsWithoutVisualOffset_Widget(const iWidget *d) { | ||
595 | iRect bounds = d->rect; | ||
596 | for (const iWidget *w = d->parent; w; w = w->parent) { | ||
597 | addv_I2(&bounds.pos, w->rect.pos); | ||
598 | } | ||
599 | return bounds; | ||
600 | } | ||
601 | |||
577 | iInt2 localCoord_Widget(const iWidget *d, iInt2 coord) { | 602 | iInt2 localCoord_Widget(const iWidget *d, iInt2 coord) { |
578 | for (const iWidget *w = d; w; w = w->parent) { | 603 | for (const iWidget *w = d; w; w = w->parent) { |
579 | subv_I2(&coord, w->rect.pos); | 604 | subv_I2(&coord, w->rect.pos); |
diff --git a/src/ui/widget.h b/src/ui/widget.h index 90ccac8e..ad7ce168 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h | |||
@@ -110,6 +110,8 @@ enum iWidgetFlag { | |||
110 | #define dragged_WidgetFlag iBit64(54) | 110 | #define dragged_WidgetFlag iBit64(54) |
111 | #define hittable_WidgetFlag iBit64(55) | 111 | #define hittable_WidgetFlag iBit64(55) |
112 | #define safePadding_WidgetFlag iBit64(56) /* padded using safe area insets */ | 112 | #define safePadding_WidgetFlag iBit64(56) /* padded using safe area insets */ |
113 | #define moveToParentBottomEdge_WidgetFlag iBit64(57) | ||
114 | #define parentCannotResizeHeight_WidgetFlag iBit64(58) | ||
113 | 115 | ||
114 | enum iWidgetAddPos { | 116 | enum iWidgetAddPos { |
115 | back_WidgetAddPos, | 117 | back_WidgetAddPos, |
@@ -165,6 +167,7 @@ const iString *id_Widget (const iWidget *); | |||
165 | int64_t flags_Widget (const iWidget *); | 167 | int64_t flags_Widget (const iWidget *); |
166 | iRect bounds_Widget (const iWidget *); /* outer bounds */ | 168 | iRect bounds_Widget (const iWidget *); /* outer bounds */ |
167 | iRect innerBounds_Widget (const iWidget *); | 169 | iRect innerBounds_Widget (const iWidget *); |
170 | iRect boundsWithoutVisualOffset_Widget(const iWidget *); | ||
168 | iInt2 localCoord_Widget (const iWidget *, iInt2 coord); | 171 | iInt2 localCoord_Widget (const iWidget *, iInt2 coord); |
169 | iBool contains_Widget (const iWidget *, iInt2 coord); | 172 | iBool contains_Widget (const iWidget *, iInt2 coord); |
170 | iBool containsExpanded_Widget (const iWidget *, iInt2 coord, int expand); | 173 | iBool containsExpanded_Widget (const iWidget *, iInt2 coord, int expand); |
diff --git a/src/ui/window.c b/src/ui/window.c index 1249a0b4..bd2b1493 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -191,7 +191,7 @@ static const iMenuItem navMenuItems_[] = { | |||
191 | { add_Icon " New Tab", 't', KMOD_PRIMARY, "tabs.new" }, | 191 | { add_Icon " New Tab", 't', KMOD_PRIMARY, "tabs.new" }, |
192 | { "Open Location...", SDLK_l, KMOD_PRIMARY, "navigate.focus" }, | 192 | { "Open Location...", SDLK_l, KMOD_PRIMARY, "navigate.focus" }, |
193 | { "---", 0, 0, NULL }, | 193 | { "---", 0, 0, NULL }, |
194 | { download_Icon " Save to Downloads", SDLK_s, KMOD_PRIMARY, "document.save" }, | 194 | { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" }, |
195 | { "Copy Source Text", SDLK_c, KMOD_PRIMARY, "copy" }, | 195 | { "Copy Source Text", SDLK_c, KMOD_PRIMARY, "copy" }, |
196 | { "---", 0, 0, NULL }, | 196 | { "---", 0, 0, NULL }, |
197 | { leftHalf_Icon " Toggle Left Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, | 197 | { leftHalf_Icon " Toggle Left Sidebar", SDLK_l, KMOD_PRIMARY | KMOD_SHIFT, "sidebar.toggle" }, |
@@ -259,7 +259,7 @@ static const iMenuItem fileMenuItems_[] = { | |||
259 | { "New Tab", SDLK_t, KMOD_PRIMARY, "tabs.new" }, | 259 | { "New Tab", SDLK_t, KMOD_PRIMARY, "tabs.new" }, |
260 | { "Open Location...", SDLK_l, KMOD_PRIMARY, "navigate.focus" }, | 260 | { "Open Location...", SDLK_l, KMOD_PRIMARY, "navigate.focus" }, |
261 | { "---", 0, 0, NULL }, | 261 | { "---", 0, 0, NULL }, |
262 | { "Save to Downloads", SDLK_s, KMOD_PRIMARY, "document.save" }, | 262 | { saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" }, |
263 | }; | 263 | }; |
264 | 264 | ||
265 | static const iMenuItem editMenuItems_[] = { | 265 | static const iMenuItem editMenuItems_[] = { |
@@ -576,7 +576,9 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) { | |||
576 | if (isPhone) { | 576 | if (isPhone) { |
577 | static const char *buttons[] = { "navbar.back", "navbar.forward", "navbar.sidebar", | 577 | static const char *buttons[] = { "navbar.back", "navbar.forward", "navbar.sidebar", |
578 | "navbar.ident", "navbar.home", "navbar.menu" }; | 578 | "navbar.ident", "navbar.home", "navbar.menu" }; |
579 | setFlags_Widget(findWidget_App("toolbar"), hidden_WidgetFlag, isLandscape_App()); | 579 | iWidget *toolBar = findWidget_App("toolbar"); |
580 | setVisualOffset_Widget(toolBar, 0, 0, 0); | ||
581 | setFlags_Widget(toolBar, hidden_WidgetFlag, isLandscape_App()); | ||
580 | iForIndices(i, buttons) { | 582 | iForIndices(i, buttons) { |
581 | iLabelWidget *btn = findChild_Widget(navBar, buttons[i]); | 583 | iLabelWidget *btn = findChild_Widget(navBar, buttons[i]); |
582 | setFlags_Widget(as_Widget(btn), hidden_WidgetFlag, isPortrait_App()); | 584 | setFlags_Widget(as_Widget(btn), hidden_WidgetFlag, isPortrait_App()); |
@@ -936,7 +938,6 @@ static void setupUserInterface_Window(iWindow *d) { | |||
936 | setBackgroundColor_Widget(winBar, uiBackground_ColorId); | 938 | setBackgroundColor_Widget(winBar, uiBackground_ColorId); |
937 | } | 939 | } |
938 | #endif | 940 | #endif |
939 | |||
940 | /* Navigation bar. */ { | 941 | /* Navigation bar. */ { |
941 | iWidget *navBar = new_Widget(); | 942 | iWidget *navBar = new_Widget(); |
942 | setId_Widget(navBar, "navbar"); | 943 | setId_Widget(navBar, "navbar"); |
@@ -1119,8 +1120,9 @@ static void setupUserInterface_Window(iWindow *d) { | |||
1119 | setBackgroundColor_Widget(searchBar, uiBackground_ColorId); | 1120 | setBackgroundColor_Widget(searchBar, uiBackground_ColorId); |
1120 | setCommandHandler_Widget(searchBar, handleSearchBarCommands_); | 1121 | setCommandHandler_Widget(searchBar, handleSearchBarCommands_); |
1121 | addChildFlags_Widget( | 1122 | addChildFlags_Widget( |
1122 | searchBar, iClob(new_LabelWidget(magnifyingGlass_Icon " Text", NULL)), frameless_WidgetFlag); | 1123 | searchBar, iClob(new_LabelWidget(magnifyingGlass_Icon, NULL)), frameless_WidgetFlag); |
1123 | iInputWidget *input = new_InputWidget(0); | 1124 | iInputWidget *input = new_InputWidget(0); |
1125 | setHint_InputWidget(input, "Find text on page"); | ||
1124 | setSelectAllOnFocus_InputWidget(input, iTrue); | 1126 | setSelectAllOnFocus_InputWidget(input, iTrue); |
1125 | setEatEscape_InputWidget(input, iFalse); /* unfocus and close with one keypress */ | 1127 | setEatEscape_InputWidget(input, iFalse); /* unfocus and close with one keypress */ |
1126 | setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag), | 1128 | setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag), |
@@ -1133,10 +1135,12 @@ static void setupUserInterface_Window(iWindow *d) { | |||
1133 | /* Bottom toolbar. */ | 1135 | /* Bottom toolbar. */ |
1134 | if (isPhone_iOS()) { | 1136 | if (isPhone_iOS()) { |
1135 | iWidget *toolBar = new_Widget(); | 1137 | iWidget *toolBar = new_Widget(); |
1136 | addChild_Widget(div, iClob(toolBar)); | 1138 | addChild_Widget(d->root, iClob(toolBar)); |
1137 | setId_Widget(toolBar, "toolbar"); | 1139 | setId_Widget(toolBar, "toolbar"); |
1138 | setCommandHandler_Widget(toolBar, handleToolBarCommands_); | 1140 | setCommandHandler_Widget(toolBar, handleToolBarCommands_); |
1139 | setFlags_Widget(toolBar, collapse_WidgetFlag | resizeWidthOfChildren_WidgetFlag | | 1141 | setFlags_Widget(toolBar, moveToParentBottomEdge_WidgetFlag | |
1142 | parentCannotResizeHeight_WidgetFlag | | ||
1143 | resizeWidthOfChildren_WidgetFlag | | ||
1140 | arrangeHeight_WidgetFlag | arrangeHorizontal_WidgetFlag, iTrue); | 1144 | arrangeHeight_WidgetFlag | arrangeHorizontal_WidgetFlag, iTrue); |
1141 | setBackgroundColor_Widget(toolBar, tmBannerBackground_ColorId); | 1145 | setBackgroundColor_Widget(toolBar, tmBannerBackground_ColorId); |
1142 | addChildFlags_Widget(toolBar, iClob(newLargeIcon_LabelWidget("\U0001f870", "navigate.back")), frameless_WidgetFlag); | 1146 | addChildFlags_Widget(toolBar, iClob(newLargeIcon_LabelWidget("\U0001f870", "navigate.back")), frameless_WidgetFlag); |
@@ -1214,6 +1218,21 @@ static void setupUserInterface_Window(iWindow *d) { | |||
1214 | updateMetrics_Window_(d); | 1218 | updateMetrics_Window_(d); |
1215 | } | 1219 | } |
1216 | 1220 | ||
1221 | void showToolbars_Window(iWindow *d, iBool show) { | ||
1222 | if (isLandscape_App()) return; | ||
1223 | iWidget *toolBar = findChild_Widget(d->root, "toolbar"); | ||
1224 | if (!toolBar) return; | ||
1225 | const int height = rootSize_Window(d).y - top_Rect(boundsWithoutVisualOffset_Widget(toolBar)); | ||
1226 | if (show && !isVisible_Widget(toolBar)) { | ||
1227 | setFlags_Widget(toolBar, hidden_WidgetFlag, iFalse); | ||
1228 | setVisualOffset_Widget(toolBar, 0, 200, easeOut_AnimFlag); | ||
1229 | } | ||
1230 | else if (!show && isVisible_Widget(toolBar)) { | ||
1231 | setFlags_Widget(toolBar, hidden_WidgetFlag, iTrue); | ||
1232 | setVisualOffset_Widget(toolBar, height, 200, easeOut_AnimFlag); | ||
1233 | } | ||
1234 | } | ||
1235 | |||
1217 | static void updateRootSize_Window_(iWindow *d, iBool notifyAlways) { | 1236 | static void updateRootSize_Window_(iWindow *d, iBool notifyAlways) { |
1218 | iInt2 *size = &d->root->rect.size; | 1237 | iInt2 *size = &d->root->rect.size; |
1219 | const iInt2 oldSize = *size; | 1238 | const iInt2 oldSize = *size; |
diff --git a/src/ui/window.h b/src/ui/window.h index cd2e3814..7303acb2 100644 --- a/src/ui/window.h +++ b/src/ui/window.h | |||
@@ -91,6 +91,7 @@ void setCursor_Window (iWindow *, int cursor); | |||
91 | void setSnap_Window (iWindow *, int snapMode); | 91 | void setSnap_Window (iWindow *, int snapMode); |
92 | void setKeyboardHeight_Window(iWindow *, int height); | 92 | void setKeyboardHeight_Window(iWindow *, int height); |
93 | void dismissPortraitPhoneSidebars_Window (iWindow *); | 93 | void dismissPortraitPhoneSidebars_Window (iWindow *); |
94 | void showToolbars_Window (iWindow *, iBool show); | ||
94 | iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *); | 95 | iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *); |
95 | 96 | ||
96 | uint32_t id_Window (const iWindow *); | 97 | uint32_t id_Window (const iWindow *); |