summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
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 *);