summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-03-21 14:29:51 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-03-21 14:29:51 +0200
commit2f9e203058df442921fc0151ddc5fe9b68b87935 (patch)
tree5441025fcf4e974e82128f65376650bec7a941bb /src/ui
parentb93ba1bfb860c2a4b5bf46c77f3f0d11b4eb1282 (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.c63
-rw-r--r--src/ui/util.c5
-rw-r--r--src/ui/widget.c33
-rw-r--r--src/ui/widget.h3
-rw-r--r--src/ui/window.c33
-rw-r--r--src/ui/window.h1
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
225iDefineObjectConstruction(DocumentWidget) 230iDefineObjectConstruction(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
442static int scrollMax_DocumentWidget_(const iDocumentWidget *d) { 448static 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
447static void invalidateLink_DocumentWidget_(iDocumentWidget *d, iGmLinkId id) { 458static 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_[] = {
1496static iBool updateDocumentWidthRetainingScrollPosition_DocumentWidget_(iDocumentWidget *d, 1521static 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
1531static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { 1557static 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
987static iBool isOmittedPref_(const iString *id) { 987static 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
594iRect 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
577iInt2 localCoord_Widget(const iWidget *d, iInt2 coord) { 602iInt2 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
114enum iWidgetAddPos { 116enum iWidgetAddPos {
115 back_WidgetAddPos, 117 back_WidgetAddPos,
@@ -165,6 +167,7 @@ const iString *id_Widget (const iWidget *);
165int64_t flags_Widget (const iWidget *); 167int64_t flags_Widget (const iWidget *);
166iRect bounds_Widget (const iWidget *); /* outer bounds */ 168iRect bounds_Widget (const iWidget *); /* outer bounds */
167iRect innerBounds_Widget (const iWidget *); 169iRect innerBounds_Widget (const iWidget *);
170iRect boundsWithoutVisualOffset_Widget(const iWidget *);
168iInt2 localCoord_Widget (const iWidget *, iInt2 coord); 171iInt2 localCoord_Widget (const iWidget *, iInt2 coord);
169iBool contains_Widget (const iWidget *, iInt2 coord); 172iBool contains_Widget (const iWidget *, iInt2 coord);
170iBool containsExpanded_Widget (const iWidget *, iInt2 coord, int expand); 173iBool 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
265static const iMenuItem editMenuItems_[] = { 265static 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
1221void 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
1217static void updateRootSize_Window_(iWindow *d, iBool notifyAlways) { 1236static 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);
91void setSnap_Window (iWindow *, int snapMode); 91void setSnap_Window (iWindow *, int snapMode);
92void setKeyboardHeight_Window(iWindow *, int height); 92void setKeyboardHeight_Window(iWindow *, int height);
93void dismissPortraitPhoneSidebars_Window (iWindow *); 93void dismissPortraitPhoneSidebars_Window (iWindow *);
94void showToolbars_Window (iWindow *, iBool show);
94iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *); 95iBool postContextClick_Window (iWindow *, const SDL_MouseButtonEvent *);
95 96
96uint32_t id_Window (const iWindow *); 97uint32_t id_Window (const iWindow *);