summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/documentwidget.c103
-rw-r--r--src/ui/documentwidget.h8
-rw-r--r--src/ui/sidebarwidget.c14
-rw-r--r--src/ui/text.c4
-rw-r--r--src/ui/touch.c49
-rw-r--r--src/ui/widget.c55
-rw-r--r--src/ui/widget.h9
7 files changed, 146 insertions, 96 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index eae5d713..3fc22bdf 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -130,7 +130,8 @@ void deinit_PersistentDocumentState(iPersistentDocumentState *d) {
130 130
131void serialize_PersistentDocumentState(const iPersistentDocumentState *d, iStream *outs) { 131void serialize_PersistentDocumentState(const iPersistentDocumentState *d, iStream *outs) {
132 serialize_String(d->url, outs); 132 serialize_String(d->url, outs);
133 writeU16_Stream(outs, d->reloadInterval & 7); 133 uint16_t params = d->reloadInterval & 7;
134 writeU16_Stream(outs, params);
134 serialize_History(d->history, outs); 135 serialize_History(d->history, outs);
135} 136}
136 137
@@ -223,6 +224,7 @@ enum iDocumentWidgetFlag {
223 movingSelectMarkEnd_DocumentWidgetFlag = iBit(11), 224 movingSelectMarkEnd_DocumentWidgetFlag = iBit(11),
224 otherRootByDefault_DocumentWidgetFlag = iBit(12), /* links open to other root by default */ 225 otherRootByDefault_DocumentWidgetFlag = iBit(12), /* links open to other root by default */
225 urlChanged_DocumentWidgetFlag = iBit(13), 226 urlChanged_DocumentWidgetFlag = iBit(13),
227 openedFromSidebar_DocumentWidgetFlag = iBit(14),
226}; 228};
227 229
228enum iDocumentLinkOrdinalMode { 230enum iDocumentLinkOrdinalMode {
@@ -1606,7 +1608,8 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n
1606 format_String(&d->sourceHeader, cstr_Lang("pageinfo.header.cached")); 1608 format_String(&d->sourceHeader, cstr_Lang("pageinfo.header.cached"));
1607 set_Block(&d->sourceContent, &resp->body); 1609 set_Block(&d->sourceContent, &resp->body);
1608 updateDocument_DocumentWidget_(d, resp, cachedDoc, iTrue); 1610 updateDocument_DocumentWidget_(d, resp, cachedDoc, iTrue);
1609 setCachedDocument_History(d->mod.history, d->doc); 1611 setCachedDocument_History(d->mod.history, d->doc,
1612 (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0);
1610 } 1613 }
1611 d->state = ready_RequestState; 1614 d->state = ready_RequestState;
1612 postProcessRequestContent_DocumentWidget_(d, iTrue); 1615 postProcessRequestContent_DocumentWidget_(d, iTrue);
@@ -1626,6 +1629,9 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n
1626static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { 1629static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) {
1627 const iRecentUrl *recent = findUrl_History(d->mod.history, withSpacesEncoded_String(d->mod.url)); 1630 const iRecentUrl *recent = findUrl_History(d->mod.history, withSpacesEncoded_String(d->mod.url));
1628 if (recent && recent->cachedResponse) { 1631 if (recent && recent->cachedResponse) {
1632 iChangeFlags(d->flags,
1633 openedFromSidebar_DocumentWidgetFlag,
1634 recent->flags.openedFromSidebar);
1629 updateFromCachedResponse_DocumentWidget_( 1635 updateFromCachedResponse_DocumentWidget_(
1630 d, recent->normScrollY, recent->cachedResponse, recent->cachedDoc); 1636 d, recent->normScrollY, recent->cachedResponse, recent->cachedDoc);
1631 return iTrue; 1637 return iTrue;
@@ -2282,6 +2288,9 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
2282 /* The temporary "swipeIn" will display the previous page until the finger is lifted. */ 2288 /* The temporary "swipeIn" will display the previous page until the finger is lifted. */
2283 iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein"); 2289 iDocumentWidget *swipeIn = findChild_Widget(swipeParent, "swipein");
2284 if (!swipeIn) { 2290 if (!swipeIn) {
2291 const iBool sidebarSwipe = (isPortraitPhone_App() &&
2292 d->flags & openedFromSidebar_DocumentWidgetFlag &&
2293 !isVisible_Widget(findWidget_App("sidebar")));
2285 swipeIn = new_DocumentWidget(); 2294 swipeIn = new_DocumentWidget();
2286 setId_Widget(as_Widget(swipeIn), "swipein"); 2295 setId_Widget(as_Widget(swipeIn), "swipein");
2287 setFlags_Widget(as_Widget(swipeIn), 2296 setFlags_Widget(as_Widget(swipeIn),
@@ -2290,16 +2299,18 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
2290 swipeIn->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos)); 2299 swipeIn->widget.rect.pos = windowToInner_Widget(swipeParent, localToWindow_Widget(w, w->rect.pos));
2291 swipeIn->widget.rect.size = d->widget.rect.size; 2300 swipeIn->widget.rect.size = d->widget.rect.size;
2292 swipeIn->widget.offsetRef = parent_Widget(w); 2301 swipeIn->widget.offsetRef = parent_Widget(w);
2293 iRecentUrl *recent = new_RecentUrl(); 2302 if (!sidebarSwipe) {
2294 preceding_History(d->mod.history, recent); 2303 iRecentUrl *recent = new_RecentUrl();
2295 if (recent->cachedDoc) { 2304 preceding_History(d->mod.history, recent);
2296 iChangeRef(swipeIn->doc, recent->cachedDoc); 2305 if (recent->cachedDoc) {
2297 updateScrollMax_DocumentWidget_(d); 2306 iChangeRef(swipeIn->doc, recent->cachedDoc);
2298 setValue_Anim(&swipeIn->scrollY.pos, size_GmDocument(swipeIn->doc).y * recent->normScrollY, 0); 2307 updateScrollMax_DocumentWidget_(d);
2299 updateVisible_DocumentWidget_(swipeIn); 2308 setValue_Anim(&swipeIn->scrollY.pos, size_GmDocument(swipeIn->doc).y * recent->normScrollY, 0);
2300 swipeIn->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag; 2309 updateVisible_DocumentWidget_(swipeIn);
2310 swipeIn->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag | updateSideBuf_DrawBufsFlag;
2311 }
2312 delete_RecentUrl(recent);
2301 } 2313 }
2302 delete_RecentUrl(recent);
2303 addChildPos_Widget(swipeParent, iClob(swipeIn), front_WidgetAddPos); 2314 addChildPos_Widget(swipeParent, iClob(swipeIn), front_WidgetAddPos);
2304 } 2315 }
2305 } 2316 }
@@ -2326,7 +2337,9 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
2326 destroy_Widget(as_Widget(target)); /* will be actually deleted after animation finishes */ 2337 destroy_Widget(as_Widget(target)); /* will be actually deleted after animation finishes */
2327 } 2338 }
2328 if (flags_Widget(w) & dragged_WidgetFlag) { 2339 if (flags_Widget(w) & dragged_WidgetFlag) {
2329 setVisualOffset_Widget(w, width_Widget(w) + offset, animSpan, 0); 2340 setVisualOffset_Widget(w, width_Widget(w) +
2341 width_Widget(d) * offset / size_Root(w->root).x,
2342 animSpan, 0);
2330 } 2343 }
2331 else { 2344 else {
2332 setVisualOffset_Widget(w, offset / 4, animSpan, 0); 2345 setVisualOffset_Widget(w, offset / 4, animSpan, 0);
@@ -2426,6 +2439,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2426 return iFalse; 2439 return iFalse;
2427 } 2440 }
2428 else if (equal_Command(cmd, "theme.changed") && document_App() == d) { 2441 else if (equal_Command(cmd, "theme.changed") && document_App() == d) {
2442// invalidateTheme_History(d->mod.history); /* cached colors */
2429 updateTheme_DocumentWidget_(d); 2443 updateTheme_DocumentWidget_(d);
2430 updateVisible_DocumentWidget_(d); 2444 updateVisible_DocumentWidget_(d);
2431 updateTrust_DocumentWidget_(d, NULL); 2445 updateTrust_DocumentWidget_(d, NULL);
@@ -2691,7 +2705,8 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2691 (startsWithCase_String(meta_GmRequest(d->request), "text/") || 2705 (startsWithCase_String(meta_GmRequest(d->request), "text/") ||
2692 !cmp_String(&d->sourceMime, mimeType_Gempub))) { 2706 !cmp_String(&d->sourceMime, mimeType_Gempub))) {
2693 setCachedResponse_History(d->mod.history, lockResponse_GmRequest(d->request)); 2707 setCachedResponse_History(d->mod.history, lockResponse_GmRequest(d->request));
2694 setCachedDocument_History(d->mod.history, d->doc); /* keeps a ref */ 2708 setCachedDocument_History(d->mod.history, d->doc, /* keeps a ref */
2709 (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0);
2695 unlockResponse_GmRequest(d->request); 2710 unlockResponse_GmRequest(d->request);
2696 } 2711 }
2697 } 2712 }
@@ -2821,6 +2836,15 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2821 return iTrue; 2836 return iTrue;
2822 } 2837 }
2823 else if (equal_Command(cmd, "navigate.back") && document_App() == d) { 2838 else if (equal_Command(cmd, "navigate.back") && document_App() == d) {
2839 if (isPortraitPhone_App()) {
2840 if (d->flags & openedFromSidebar_DocumentWidgetFlag &&
2841 !isVisible_Widget(findWidget_App("sidebar"))) {
2842 postCommand_App("sidebar.toggle");
2843 showToolbars_Root(get_Root(), iTrue);
2844 return iTrue;
2845 }
2846 d->flags &= ~openedFromSidebar_DocumentWidgetFlag;
2847 }
2824 if (d->request) { 2848 if (d->request) {
2825 postCommandf_Root(w->root, 2849 postCommandf_Root(w->root,
2826 "document.request.cancelled doc:%p url:%s", d, cstr_String(d->mod.url)); 2850 "document.request.cancelled doc:%p url:%s", d, cstr_String(d->mod.url));
@@ -3499,7 +3523,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
3499 pushBack_Array( 3523 pushBack_Array(
3500 &items, 3524 &items,
3501 &(iMenuItem){ delete_Icon " " uiTextCaution_ColorEscape 3525 &(iMenuItem){ delete_Icon " " uiTextCaution_ColorEscape
3502 " ${link.file.delete}", 3526 "${link.file.delete}",
3503 0, 3527 0,
3504 0, 3528 0,
3505 format_CStr("!file.delete confirm:1 path:%s", 3529 format_CStr("!file.delete confirm:1 path:%s",
@@ -4366,7 +4390,7 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) {
4366 iDrawBufs * dbuf = d->drawBufs; 4390 iDrawBufs * dbuf = d->drawBufs;
4367 iPaint p; 4391 iPaint p;
4368 init_Paint(&p); 4392 init_Paint(&p);
4369 setClip_Paint(&p, bounds); 4393 setClip_Paint(&p, boundsWithoutVisualOffset_Widget(w));
4370 /* Side icon and current heading. */ 4394 /* Side icon and current heading. */
4371 if (prefs_App()->sideIcon && opacity > 0 && dbuf->sideIconBuf) { 4395 if (prefs_App()->sideIcon && opacity > 0 && dbuf->sideIconBuf) {
4372 const iInt2 texSize = size_SDLTexture(dbuf->sideIconBuf); 4396 const iInt2 texSize = size_SDLTexture(dbuf->sideIconBuf);
@@ -4616,12 +4640,17 @@ static void prerender_DocumentWidget_(iAny *context) {
4616} 4640}
4617 4641
4618static void draw_DocumentWidget_(const iDocumentWidget *d) { 4642static void draw_DocumentWidget_(const iDocumentWidget *d) {
4619 const iWidget *w = constAs_Widget(d); 4643 const iWidget *w = constAs_Widget(d);
4620 const iRect bounds = bounds_Widget(w); 4644 const iRect bounds = bounds_Widget(w);
4645 const iRect boundsWithoutVisOff = boundsWithoutVisualOffset_Widget(w);
4646 const iRect clipBounds = intersect_Rect(bounds, boundsWithoutVisOff);
4621 if (width_Rect(bounds) <= 0) { 4647 if (width_Rect(bounds) <= 0) {
4622 return; 4648 return;
4623 } 4649 }
4624// draw_Widget(w); 4650 /* TODO: Come up with a better palette caching system.
4651 It should be able to recompute cached colors in `History` when the theme has changed.
4652 Cache the theme seed in `GmDocument`? */
4653// makePaletteGlobal_GmDocument(d->doc);
4625 if (d->drawBufs->flags & updateTimestampBuf_DrawBufsFlag) { 4654 if (d->drawBufs->flags & updateTimestampBuf_DrawBufsFlag) {
4626 updateTimestampBuf_DocumentWidget_(d); 4655 updateTimestampBuf_DocumentWidget_(d);
4627 } 4656 }
@@ -4638,7 +4667,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
4638 }; 4667 };
4639 init_Paint(&ctx.paint); 4668 init_Paint(&ctx.paint);
4640 render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */); 4669 render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */);
4641 setClip_Paint(&ctx.paint, bounds); 4670 setClip_Paint(&ctx.paint, clipBounds);
4642 int yTop = docBounds.pos.y - pos_SmoothScroll(&d->scrollY); 4671 int yTop = docBounds.pos.y - pos_SmoothScroll(&d->scrollY);
4643 draw_VisBuf(d->visBuf, init_I2(bounds.pos.x, yTop), ySpan_Rect(bounds)); 4672 draw_VisBuf(d->visBuf, init_I2(bounds.pos.x, yTop), ySpan_Rect(bounds));
4644 /* Text markers. */ 4673 /* Text markers. */
@@ -4673,7 +4702,6 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
4673 } 4702 }
4674 } 4703 }
4675 drawMedia_DocumentWidget_(d, &ctx.paint); 4704 drawMedia_DocumentWidget_(d, &ctx.paint);
4676 unsetClip_Paint(&ctx.paint);
4677 /* Fill the top and bottom, in case the document is short. */ 4705 /* Fill the top and bottom, in case the document is short. */
4678 if (yTop > top_Rect(bounds)) { 4706 if (yTop > top_Rect(bounds)) {
4679 fillRect_Paint(&ctx.paint, 4707 fillRect_Paint(&ctx.paint,
@@ -4687,6 +4715,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
4687 init_Rect(bounds.pos.x, yBottom, bounds.size.x, bottom_Rect(bounds) - yBottom), 4715 init_Rect(bounds.pos.x, yBottom, bounds.size.x, bottom_Rect(bounds) - yBottom),
4688 tmBackground_ColorId); 4716 tmBackground_ColorId);
4689 } 4717 }
4718 unsetClip_Paint(&ctx.paint);
4690 drawSideElements_DocumentWidget_(d); 4719 drawSideElements_DocumentWidget_(d);
4691 if (prefs_App()->hoverLink && d->hoverLink) { 4720 if (prefs_App()->hoverLink && d->hoverLink) {
4692 const int font = uiLabel_FontId; 4721 const int font = uiLabel_FontId;
@@ -4748,6 +4777,23 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
4748 drawCentered_Text(uiLabelBold_FontId, rect, iFalse, uiBackground_ColorId, "%zu bytes selected", 4777 drawCentered_Text(uiLabelBold_FontId, rect, iFalse, uiBackground_ColorId, "%zu bytes selected",
4749 size_Range(&mark)); 4778 size_Range(&mark));
4750 } 4779 }
4780 if (w->offsetRef) {
4781 const int offX = visualOffsetByReference_Widget(w);
4782 if (offX) {
4783 setClip_Paint(&ctx.paint, clipBounds);
4784 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND);
4785 ctx.paint.alpha = iAbs(offX) / (float) get_Window()->size.x * 300;
4786 fillRect_Paint(&ctx.paint, bounds, backgroundFadeColor_Widget());
4787 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE);
4788 unsetClip_Paint(&ctx.paint);
4789 }
4790 else {
4791 /* TODO: Should have a better place to do this; drawing is supposed to be immutable. */
4792 iWidget *mut = iConstCast(iWidget *, w);
4793 mut->offsetRef = NULL;
4794 mut->flags &= ~refChildrenOffset_WidgetFlag;
4795 }
4796 }
4751} 4797}
4752 4798
4753/*----------------------------------------------------------------------------------------------*/ 4799/*----------------------------------------------------------------------------------------------*/
@@ -4814,10 +4860,13 @@ static void setUrl_DocumentWidget_(iDocumentWidget *d, const iString *url) {
4814 if (!equal_String(d->mod.url, url)) { 4860 if (!equal_String(d->mod.url, url)) {
4815 d->flags |= urlChanged_DocumentWidgetFlag; 4861 d->flags |= urlChanged_DocumentWidgetFlag;
4816 set_String(d->mod.url, url); 4862 set_String(d->mod.url, url);
4817} 4863 }
4818} 4864}
4819 4865
4820void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBool isFromCache) { 4866void setUrlFlags_DocumentWidget(iDocumentWidget *d, const iString *url, int setUrlFlags) {
4867 iChangeFlags(d->flags, openedFromSidebar_DocumentWidgetFlag,
4868 (setUrlFlags & openedFromSidebar_DocumentWidgetSetUrlFlag) != 0);
4869 const iBool isFromCache = (setUrlFlags & useCachedContentIfAvailable_DocumentWidgetSetUrlFlag) != 0;
4821 setLinkNumberMode_DocumentWidget_(d, iFalse); 4870 setLinkNumberMode_DocumentWidget_(d, iFalse);
4822 setUrl_DocumentWidget_(d, urlFragmentStripped_String(url)); 4871 setUrl_DocumentWidget_(d, urlFragmentStripped_String(url));
4823 /* See if there a username in the URL. */ 4872 /* See if there a username in the URL. */
@@ -4829,6 +4878,7 @@ void setUrlFromCache_DocumentWidget(iDocumentWidget *d, const iString *url, iBoo
4829 4878
4830void setUrlAndSource_DocumentWidget(iDocumentWidget *d, const iString *url, const iString *mime, 4879void setUrlAndSource_DocumentWidget(iDocumentWidget *d, const iString *url, const iString *mime,
4831 const iBlock *source) { 4880 const iBlock *source) {
4881 d->flags &= ~openedFromSidebar_DocumentWidgetFlag;
4832 setLinkNumberMode_DocumentWidget_(d, iFalse); 4882 setLinkNumberMode_DocumentWidget_(d, iFalse);
4833 setUrl_DocumentWidget_(d, url); 4883 setUrl_DocumentWidget_(d, url);
4834 parseUser_DocumentWidget_(d); 4884 parseUser_DocumentWidget_(d);
@@ -4846,12 +4896,12 @@ iDocumentWidget *duplicate_DocumentWidget(const iDocumentWidget *orig) {
4846 delete_History(d->mod.history); 4896 delete_History(d->mod.history);
4847 d->initNormScrollY = normScrollPos_DocumentWidget_(d); 4897 d->initNormScrollY = normScrollPos_DocumentWidget_(d);
4848 d->mod.history = copy_History(orig->mod.history); 4898 d->mod.history = copy_History(orig->mod.history);
4849 setUrlFromCache_DocumentWidget(d, orig->mod.url, iTrue); 4899 setUrlFlags_DocumentWidget(d, orig->mod.url, useCachedContentIfAvailable_DocumentWidgetSetUrlFlag);
4850 return d; 4900 return d;
4851} 4901}
4852 4902
4853void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) { 4903void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) {
4854 setUrlFromCache_DocumentWidget(d, url, iFalse); 4904 setUrlFlags_DocumentWidget(d, url, 0);
4855} 4905}
4856 4906
4857void setInitialScroll_DocumentWidget(iDocumentWidget *d, float normScrollY) { 4907void setInitialScroll_DocumentWidget(iDocumentWidget *d, float normScrollY) {
@@ -4862,6 +4912,11 @@ void setRedirectCount_DocumentWidget(iDocumentWidget *d, int count) {
4862 d->redirectCount = count; 4912 d->redirectCount = count;
4863} 4913}
4864 4914
4915void setOpenedFromSidebar_DocumentWidget(iDocumentWidget *d, iBool fromSidebar) {
4916 iChangeFlags(d->flags, openedFromSidebar_DocumentWidgetFlag, fromSidebar);
4917 setCachedDocument_History(d->mod.history, d->doc, fromSidebar);
4918}
4919
4865iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) { 4920iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) {
4866 return d->request != NULL; 4921 return d->request != NULL;
4867} 4922}
diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h
index c038f981..1921b25a 100644
--- a/src/ui/documentwidget.h
+++ b/src/ui/documentwidget.h
@@ -45,11 +45,17 @@ const iString * bookmarkTitle_DocumentWidget (const iDocumentWidget *);
45const iString * feedTitle_DocumentWidget (const iDocumentWidget *); 45const iString * feedTitle_DocumentWidget (const iDocumentWidget *);
46int documentWidth_DocumentWidget (const iDocumentWidget *); 46int documentWidth_DocumentWidget (const iDocumentWidget *);
47 47
48enum iDocumentWidgetSetUrlFlags {
49 useCachedContentIfAvailable_DocumentWidgetSetUrlFlag = iBit(1),
50 openedFromSidebar_DocumentWidgetSetUrlFlag = iBit(2),
51};
52
48void setUrl_DocumentWidget (iDocumentWidget *, const iString *url); 53void setUrl_DocumentWidget (iDocumentWidget *, const iString *url);
49void setUrlFromCache_DocumentWidget (iDocumentWidget *, const iString *url, iBool isFromCache); 54void setUrlFlags_DocumentWidget (iDocumentWidget *, const iString *url, int setUrlFlags);
50void setUrlAndSource_DocumentWidget (iDocumentWidget *, const iString *url, const iString *mime, const iBlock *source); 55void setUrlAndSource_DocumentWidget (iDocumentWidget *, const iString *url, const iString *mime, const iBlock *source);
51void setInitialScroll_DocumentWidget (iDocumentWidget *, float normScrollY); /* set after content received */ 56void setInitialScroll_DocumentWidget (iDocumentWidget *, float normScrollY); /* set after content received */
52void setRedirectCount_DocumentWidget (iDocumentWidget *, int count); 57void setRedirectCount_DocumentWidget (iDocumentWidget *, int count);
53void setSource_DocumentWidget (iDocumentWidget *, const iString *sourceText); 58void setSource_DocumentWidget (iDocumentWidget *, const iString *sourceText);
59void setOpenedFromSidebar_DocumentWidget(iDocumentWidget *, iBool fromSidebar);
54 60
55void updateSize_DocumentWidget (iDocumentWidget *); 61void updateSize_DocumentWidget (iDocumentWidget *);
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index 4f3ea637..f7181037 100644
--- a/src/ui/sidebarwidget.c
+++ b/src/ui/sidebarwidget.c
@@ -773,6 +773,7 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si
773 const iGmHeading *head = constAt_Array(headings_GmDocument(doc), item->id); 773 const iGmHeading *head = constAt_Array(headings_GmDocument(doc), item->id);
774 postCommandf_App("document.goto loc:%p", head->text.start); 774 postCommandf_App("document.goto loc:%p", head->text.start);
775 dismissPortraitPhoneSidebars_Root(as_Widget(d)->root); 775 dismissPortraitPhoneSidebars_Root(as_Widget(d)->root);
776 setOpenedFromSidebar_DocumentWidget(document_App(), iTrue);
776 break; 777 break;
777 } 778 }
778 case feeds_SidebarMode: { 779 case feeds_SidebarMode: {
@@ -783,7 +784,7 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si
783 case bookmarks_SidebarMode: 784 case bookmarks_SidebarMode:
784 case history_SidebarMode: { 785 case history_SidebarMode: {
785 if (!isEmpty_String(&item->url)) { 786 if (!isEmpty_String(&item->url)) {
786 postCommandf_Root(get_Root(), "open newtab:%d url:%s", 787 postCommandf_Root(get_Root(), "open fromsidebar:1 newtab:%d url:%s",
787 openTabMode_Sym(modState_Keys()), 788 openTabMode_Sym(modState_Keys()),
788 cstr_String(&item->url)); 789 cstr_String(&item->url));
789 } 790 }
@@ -944,13 +945,16 @@ static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char *
944 visX = left_Rect(bounds_Widget(w)) - left_Rect(w->root->widget->rect); 945 visX = left_Rect(bounds_Widget(w)) - left_Rect(w->root->widget->rect);
945 } 946 }
946 setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w)); 947 setFlags_Widget(w, hidden_WidgetFlag, isVisible_Widget(w));
948 /* Safe area inset for mobile. */
949 const int safePad = (d->side == left_SidebarSide ? left_Rect(safeRect_Root(w->root)) : 0);
947 if (isVisible_Widget(w)) { 950 if (isVisible_Widget(w)) {
948 setFlags_Widget(w, keepOnTop_WidgetFlag, iFalse); 951 setFlags_Widget(w, keepOnTop_WidgetFlag, iFalse);
949 w->rect.size.x = d->widthAsGaps * gap_UI; 952 w->rect.size.x = d->widthAsGaps * gap_UI;
950 invalidate_ListWidget(d->list); 953 invalidate_ListWidget(d->list);
951 if (isAnimated) { 954 if (isAnimated) {
952 setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); 955 setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue);
953 setVisualOffset_Widget(w, (d->side == left_SidebarSide ? -1 : 1) * w->rect.size.x, 0, 0); 956 setVisualOffset_Widget(
957 w, (d->side == left_SidebarSide ? -1 : 1) * (w->rect.size.x + safePad), 0, 0);
954 setVisualOffset_Widget(w, 0, 300, easeOut_AnimFlag | softer_AnimFlag); 958 setVisualOffset_Widget(w, 0, 300, easeOut_AnimFlag | softer_AnimFlag);
955 } 959 }
956 } 960 }
@@ -958,11 +962,13 @@ static iBool handleSidebarCommand_SidebarWidget_(iSidebarWidget *d, const char *
958 setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue); 962 setFlags_Widget(w, horizontalOffset_WidgetFlag, iTrue);
959 if (d->side == right_SidebarSide) { 963 if (d->side == right_SidebarSide) {
960 setVisualOffset_Widget(w, visX, 0, 0); 964 setVisualOffset_Widget(w, visX, 0, 0);
961 setVisualOffset_Widget(w, visX + w->rect.size.x, 300, easeOut_AnimFlag | softer_AnimFlag); 965 setVisualOffset_Widget(
966 w, visX + w->rect.size.x + safePad, 300, easeOut_AnimFlag | softer_AnimFlag);
962 } 967 }
963 else { 968 else {
964 setFlags_Widget(w, keepOnTop_WidgetFlag, iTrue); 969 setFlags_Widget(w, keepOnTop_WidgetFlag, iTrue);
965 setVisualOffset_Widget(w, -w->rect.size.x, 300, easeOut_AnimFlag | softer_AnimFlag); 970 setVisualOffset_Widget(
971 w, -w->rect.size.x - safePad, 300, easeOut_AnimFlag | softer_AnimFlag);
966 } 972 }
967 } 973 }
968 arrange_Widget(w->parent); 974 arrange_Widget(w->parent);
diff --git a/src/ui/text.c b/src/ui/text.c
index ffe08fca..8a2a9ff8 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -389,7 +389,9 @@ static void initCache_Text_(iText *d) {
389 d->cacheRowAllocStep = iMax(2, textSize / 6); 389 d->cacheRowAllocStep = iMax(2, textSize / 6);
390 /* Allocate initial (empty) rows. These will be assigned actual locations in the cache 390 /* Allocate initial (empty) rows. These will be assigned actual locations in the cache
391 once at least one glyph is stored. */ 391 once at least one glyph is stored. */
392 for (int h = d->cacheRowAllocStep; h <= 2 * textSize + d->cacheRowAllocStep; h += d->cacheRowAllocStep) { 392 for (int h = d->cacheRowAllocStep;
393 h <= 2.5 * textSize + d->cacheRowAllocStep;
394 h += d->cacheRowAllocStep) {
393 pushBack_Array(&d->cacheRows, &(iCacheRow){ .height = 0 }); 395 pushBack_Array(&d->cacheRows, &(iCacheRow){ .height = 0 });
394 } 396 }
395 d->cacheBottom = 0; 397 d->cacheBottom = 0;
diff --git a/src/ui/touch.c b/src/ui/touch.c
index 36bac267..dac1152e 100644
--- a/src/ui/touch.c
+++ b/src/ui/touch.c
@@ -65,6 +65,7 @@ struct Impl_Touch {
65 iBool isLeftDown; 65 iBool isLeftDown;
66 iBool isTouchDrag; 66 iBool isTouchDrag;
67 iBool isTapAndHold; 67 iBool isTapAndHold;
68 iBool didPostEdgeMove;
68 iBool didBeginOnTouchDrag; 69 iBool didBeginOnTouchDrag;
69 int pinchId; 70 int pinchId;
70 enum iTouchEdge edge; 71 enum iTouchEdge edge;
@@ -391,6 +392,12 @@ static void checkNewPinch_TouchState_(iTouchState *d, iTouch *newTouch) {
391 pinch.touchIds[1] = other->id; 392 pinch.touchIds[1] = other->id;
392 newTouch->pinchId = other->pinchId = pinch.id; 393 newTouch->pinchId = other->pinchId = pinch.id;
393 clearWidgetMomentum_TouchState_(d, affinity); 394 clearWidgetMomentum_TouchState_(d, affinity);
395 if (other->edge && other->didPostEdgeMove) {
396 postCommandf_App("edgeswipe.ended abort:1 side:%d id:%llu", other->edge, other->id);
397 other->didPostEdgeMove = iFalse;
398 }
399 other->edge = none_TouchEdge;
400 newTouch->edge = none_TouchEdge;
394 /* Remember current positions to determine pinch amount. */ 401 /* Remember current positions to determine pinch amount. */
395 newTouch->startPos = newTouch->pos[0]; 402 newTouch->startPos = newTouch->pos[0];
396 other->startPos = other->pos[0]; 403 other->startPos = other->pos[0];
@@ -476,7 +483,6 @@ iBool processEvent_Touch(const SDL_Event *ev) {
476 } 483 }
477 else if (x > rootSize.x - edgeWidth) { 484 else if (x > rootSize.x - edgeWidth) {
478 edge = right_TouchEdge; 485 edge = right_TouchEdge;
479// puts("DOWN on right edge");
480 } 486 }
481 iWidget *aff = hitChild_Window(window, init_I2(iRound(x), iRound(y_F3(pos)))); 487 iWidget *aff = hitChild_Window(window, init_I2(iRound(x), iRound(y_F3(pos))));
482#if 0 488#if 0
@@ -523,6 +529,7 @@ iBool processEvent_Touch(const SDL_Event *ev) {
523 (int) (x_F3(pos) - x_F3(touch->startPos)), 529 (int) (x_F3(pos) - x_F3(touch->startPos)),
524 touch->edge, 530 touch->edge,
525 touch->id); 531 touch->id);
532 touch->didPostEdgeMove = iTrue;
526 return iTrue; 533 return iTrue;
527 } 534 }
528 if (touch && touch->affinity) { 535 if (touch && touch->affinity) {
@@ -595,39 +602,6 @@ iBool processEvent_Touch(const SDL_Event *ev) {
595 } 602 }
596 } 603 }
597 iAssert(touch->edge == none_TouchEdge); 604 iAssert(touch->edge == none_TouchEdge);
598#if 0
599 /* Edge swipe aborted? */
600 if (touch->edge == left_TouchEdge) {
601 if (fing->dx < 0 && x_F3(touch->pos[0]) < tapRadiusPt_ * window->pixelRatio) {
602 touch->edge = none_TouchEdge;
603 if (touch->edgeDragging) {
604 setFlags_Widget(touch->edgeDragging, dragged_WidgetFlag, iFalse);
605 setVisualOffset_Widget(touch->edgeDragging, 0, 200, easeOut_AnimFlag);
606 touch->edgeDragging = NULL;
607 }
608 }
609 else if (touch->edgeDragging) {
610 setVisualOffset_Widget(touch->edgeDragging, x_F3(pos) - x_F3(touch->startPos), 10, 0);
611 }
612 }
613 if (touch->edge == right_TouchEdge) {
614 if (fing->dx > 0 && x_F3(touch->pos[0]) > window->size.x - tapRadiusPt_ * window->pixelRatio) {
615 puts("touch->edge==right returned to right edge, aborted");
616 touch->edge = none_TouchEdge;
617 if (touch->edgeDragging) {
618 setFlags_Widget(touch->edgeDragging, dragged_WidgetFlag, iFalse);
619 setVisualOffset_Widget(touch->edgeDragging, 0, 200, easeOut_AnimFlag);
620 touch->edgeDragging = NULL;
621 }
622 }
623 else if (touch->edgeDragging) {
624 setVisualOffset_Widget(touch->edgeDragging, x_F3(pos) - x_F3(touch->startPos), 10, 0);
625 }
626 }
627 if (touch->edge) {
628 pixels.y = 0;
629 }
630#endif
631 if (touch->axis == x_TouchAxis) { 605 if (touch->axis == x_TouchAxis) {
632 pixels.y = 0; 606 pixels.y = 0;
633 } 607 }
@@ -671,7 +645,12 @@ iBool processEvent_Touch(const SDL_Event *ev) {
671 } 645 }
672#endif 646#endif
673 if (touch->edge && !isStationary_Touch_(touch)) { 647 if (touch->edge && !isStationary_Touch_(touch)) {
674 postCommandf_App("edgeswipe.ended side:%d id:%llu", touch->edge, touch->id); 648 const iFloat3 gesture = gestureVector_Touch_(touch);
649 const float pixel = window->pixelRatio;
650 const int moveDir = x_F3(gesture) < -pixel ? -1 : x_F3(gesture) > pixel ? +1 : 0;
651 const int didAbort = (touch->edge == left_TouchEdge && moveDir < 0) ||
652 (touch->edge == right_TouchEdge && moveDir > 0);
653 postCommandf_App("edgeswipe.ended abort:%d side:%d id:%llu", didAbort, touch->edge, touch->id);
675 remove_ArrayIterator(&i); 654 remove_ArrayIterator(&i);
676 continue; 655 continue;
677 } 656 }
diff --git a/src/ui/widget.c b/src/ui/widget.c
index 11ec1b07..85672c04 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -760,16 +760,24 @@ void arrange_Widget(iWidget *d) {
760} 760}
761 761
762iBool isBeingVisuallyOffsetByReference_Widget(const iWidget *d) { 762iBool isBeingVisuallyOffsetByReference_Widget(const iWidget *d) {
763 if (d->flags & refChildrenOffset_WidgetFlag) { 763 return visualOffsetByReference_Widget(d) != 0;
764}
765
766int visualOffsetByReference_Widget(const iWidget *d) {
767 if (d->offsetRef && d->flags & refChildrenOffset_WidgetFlag) {
768 int offX = 0;
764 iConstForEach(ObjectList, i, children_Widget(d->offsetRef)) { 769 iConstForEach(ObjectList, i, children_Widget(d->offsetRef)) {
765 const iWidget *child = i.object; 770 const iWidget *child = i.object;
766 if (child == d) continue; 771 if (child == d) continue;
767 if (child->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) { 772 if (child->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) {
768 return iTrue; 773// const float factor = width_Widget(d) / (float) size_Root(d->root).x;
774 const int invOff = width_Widget(d) - iRound(value_Anim(&child->visualOffset));
775 offX -= invOff / 4;
769 } 776 }
770 } 777 }
778 return offX;
771 } 779 }
772 return iFalse; 780 return 0;
773} 781}
774 782
775static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) { 783static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) {
@@ -786,14 +794,7 @@ static void applyVisualOffset_Widget_(const iWidget *d, iInt2 *pos) {
786 pos->y -= value_Anim(d->animOffsetRef); 794 pos->y -= value_Anim(d->animOffsetRef);
787 } 795 }
788 if (d->flags & refChildrenOffset_WidgetFlag) { 796 if (d->flags & refChildrenOffset_WidgetFlag) {
789 iConstForEach(ObjectList, i, children_Widget(d->offsetRef)) { 797 pos->x += visualOffsetByReference_Widget(d);
790 const iWidget *child = i.object;
791 if (child == d) continue;
792 if (child->flags & (visualOffset_WidgetFlag | dragged_WidgetFlag)) {
793 const int invOff = size_Root(d->root).x - iRound(value_Anim(&child->visualOffset));
794 pos->x -= invOff / 4;
795 }
796 }
797 } 798 }
798} 799}
799 800
@@ -1081,7 +1082,9 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) {
1081 if (~d->flags & dragged_WidgetFlag) { 1082 if (~d->flags & dragged_WidgetFlag) {
1082 setFlags_Widget(d, dragged_WidgetFlag, iTrue); 1083 setFlags_Widget(d, dragged_WidgetFlag, iTrue);
1083 } 1084 }
1084 setVisualOffset_Widget(d, arg_Command(command_UserEvent(ev)), 10, 0); 1085 setVisualOffset_Widget(d, arg_Command(command_UserEvent(ev)) *
1086 width_Widget(d) / size_Root(d->root).x,
1087 10, 0);
1085 return iTrue; 1088 return iTrue;
1086 } 1089 }
1087 } 1090 }
@@ -1129,6 +1132,17 @@ iBool processEvent_Widget(iWidget *d, const SDL_Event *ev) {
1129 return iFalse; 1132 return iFalse;
1130} 1133}
1131 1134
1135int backgroundFadeColor_Widget(void) {
1136 switch (colorTheme_App()) {
1137 case light_ColorTheme:
1138 return gray25_ColorId;
1139 case pureWhite_ColorTheme:
1140 return gray50_ColorId;
1141 default:
1142 return black_ColorId;
1143 }
1144}
1145
1132void drawBackground_Widget(const iWidget *d) { 1146void drawBackground_Widget(const iWidget *d) {
1133 if (d->flags & noBackground_WidgetFlag) { 1147 if (d->flags & noBackground_WidgetFlag) {
1134 return; 1148 return;
@@ -1151,8 +1165,7 @@ void drawBackground_Widget(const iWidget *d) {
1151 drawSoftShadow_Paint(&p, bounds_Widget(d), 12 * gap_UI, black_ColorId, 30); 1165 drawSoftShadow_Paint(&p, bounds_Widget(d), 12 * gap_UI, black_ColorId, 30);
1152 } 1166 }
1153 const iBool isFaded = fadeBackground && 1167 const iBool isFaded = fadeBackground &&
1154 ~d->flags & noFadeBackground_WidgetFlag;/* && 1168 ~d->flags & noFadeBackground_WidgetFlag;
1155 ~d->flags & destroyPending_WidgetFlag;*/
1156 if (isFaded) { 1169 if (isFaded) {
1157 iPaint p; 1170 iPaint p;
1158 init_Paint(&p); 1171 init_Paint(&p);
@@ -1163,19 +1176,7 @@ void drawBackground_Widget(const iWidget *d) {
1163 p.alpha *= (area > 0 ? visibleArea / area : 0.0f); 1176 p.alpha *= (area > 0 ? visibleArea / area : 0.0f);
1164 } 1177 }
1165 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); 1178 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND);
1166 int fadeColor; 1179 fillRect_Paint(&p, rect_Root(d->root), backgroundFadeColor_Widget());
1167 switch (colorTheme_App()) {
1168 default:
1169 fadeColor = black_ColorId;
1170 break;
1171 case light_ColorTheme:
1172 fadeColor = gray25_ColorId;
1173 break;
1174 case pureWhite_ColorTheme:
1175 fadeColor = gray50_ColorId;
1176 break;
1177 }
1178 fillRect_Paint(&p, rect_Root(d->root), fadeColor);
1179 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); 1180 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE);
1180 } 1181 }
1181 if (d->bgColor >= 0 || d->frameColor >= 0) { 1182 if (d->bgColor >= 0 || d->frameColor >= 0) {
diff --git a/src/ui/widget.h b/src/ui/widget.h
index b2310f21..acb8fa9d 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -242,10 +242,9 @@ iBool isSelected_Widget (const iAnyObject *);
242iBool isUnderKeyRoot_Widget (const iAnyObject *); 242iBool isUnderKeyRoot_Widget (const iAnyObject *);
243iBool isCommand_Widget (const iWidget *d, const SDL_Event *ev, const char *cmd); 243iBool isCommand_Widget (const iWidget *d, const SDL_Event *ev, const char *cmd);
244iBool hasParent_Widget (const iWidget *d, const iWidget *someParent); 244iBool hasParent_Widget (const iWidget *d, const iWidget *someParent);
245iBool isAffectedByVisualOffset_Widget 245iBool isAffectedByVisualOffset_Widget (const iWidget *);
246 (const iWidget *); 246iBool isBeingVisuallyOffsetByReference_Widget (const iWidget *);
247iBool isBeingVisuallyOffsetByReference_Widget 247int visualOffsetByReference_Widget (const iWidget *);
248 (const iWidget *);
249void setId_Widget (iWidget *, const char *id); 248void setId_Widget (iWidget *, const char *id);
250void setFlags_Widget (iWidget *, int64_t flags, iBool set); 249void setFlags_Widget (iWidget *, int64_t flags, iBool set);
251void setPos_Widget (iWidget *, iInt2 pos); 250void setPos_Widget (iWidget *, iInt2 pos);
@@ -278,6 +277,8 @@ void refresh_Widget (const iAnyObject *);
278 277
279iBool equalWidget_Command (const char *cmd, const iWidget *widget, const char *checkCommand); 278iBool equalWidget_Command (const char *cmd, const iWidget *widget, const char *checkCommand);
280 279
280int backgroundFadeColor_Widget (void);
281
281void setFocus_Widget (iWidget *); 282void setFocus_Widget (iWidget *);
282iWidget * focus_Widget (void); 283iWidget * focus_Widget (void);
283void setHover_Widget (iWidget *); 284void setHover_Widget (iWidget *);