summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c92
1 files changed, 73 insertions, 19 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 4de25b58..a1b26e7f 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -157,6 +157,8 @@ struct Impl_DocumentWidget {
157 iRangecc foundMark; 157 iRangecc foundMark;
158 int pageMargin; 158 int pageMargin;
159 iPtrArray visibleLinks; 159 iPtrArray visibleLinks;
160 iPtrArray visibleWideRuns; /* scrollable blocks */
161 iArray wideRunOffsets;
160 iPtrArray visiblePlayers; /* currently playing audio */ 162 iPtrArray visiblePlayers; /* currently playing audio */
161 const iGmRun * grabbedPlayer; /* currently adjusting volume in a player */ 163 const iGmRun * grabbedPlayer; /* currently adjusting volume in a player */
162 float grabbedStartVolume; 164 float grabbedStartVolume;
@@ -218,6 +220,8 @@ void init_DocumentWidget(iDocumentWidget *d) {
218 init_Block(&d->sourceContent, 0); 220 init_Block(&d->sourceContent, 0);
219 iZap(d->sourceTime); 221 iZap(d->sourceTime);
220 init_PtrArray(&d->visibleLinks); 222 init_PtrArray(&d->visibleLinks);
223 init_PtrArray(&d->visibleWideRuns);
224 init_Array(&d->wideRunOffsets, sizeof(int));
221 init_PtrArray(&d->visiblePlayers); 225 init_PtrArray(&d->visiblePlayers);
222 d->grabbedPlayer = NULL; 226 d->grabbedPlayer = NULL;
223 d->playerTimer = 0; 227 d->playerTimer = 0;
@@ -256,7 +260,9 @@ void deinit_DocumentWidget(iDocumentWidget *d) {
256 if (d->playerTimer) { 260 if (d->playerTimer) {
257 SDL_RemoveTimer(d->playerTimer); 261 SDL_RemoveTimer(d->playerTimer);
258 } 262 }
263 deinit_Array(&d->wideRunOffsets);
259 deinit_PtrArray(&d->visiblePlayers); 264 deinit_PtrArray(&d->visiblePlayers);
265 deinit_PtrArray(&d->visibleWideRuns);
260 deinit_PtrArray(&d->visibleLinks); 266 deinit_PtrArray(&d->visibleLinks);
261 delete_Block(d->certFingerprint); 267 delete_Block(d->certFingerprint);
262 delete_String(d->certSubject); 268 delete_String(d->certSubject);
@@ -317,20 +323,6 @@ static iRect siteBannerRect_DocumentWidget_(const iDocumentWidget *d) {
317 return moved_Rect(banner->visBounds, origin); 323 return moved_Rect(banner->visBounds, origin);
318} 324}
319 325
320#if 0
321static int forceBreakWidth_DocumentWidget_(const iDocumentWidget *d) {
322 if (equalCase_Rangecc(urlScheme_String(d->mod.url), "gopher")) {
323 return documentWidth_DocumentWidget_(d);
324 }
325 if (forceLineWrap_App()) {
326 const iRect bounds = bounds_Widget(constAs_Widget(d));
327 const iRect docBounds = documentBounds_DocumentWidget_(d);
328 return right_Rect(bounds) - left_Rect(docBounds) - gap_UI * d->pageMargin;
329 }
330 return 0;
331}
332#endif
333
334static iInt2 documentPos_DocumentWidget_(const iDocumentWidget *d, iInt2 pos) { 326static iInt2 documentPos_DocumentWidget_(const iDocumentWidget *d, iInt2 pos) {
335 return addY_I2(sub_I2(pos, topLeft_Rect(documentBounds_DocumentWidget_(d))), 327 return addY_I2(sub_I2(pos, topLeft_Rect(documentBounds_DocumentWidget_(d))),
336 value_Anim(&d->scrollY)); 328 value_Anim(&d->scrollY));
@@ -351,6 +343,9 @@ static void addVisible_DocumentWidget_(void *context, const iGmRun *run) {
351 } 343 }
352 d->lastVisibleRun = run; 344 d->lastVisibleRun = run;
353 } 345 }
346 if (run->preId && run->flags & wide_GmRunFlag) {
347 pushBack_PtrArray(&d->visibleWideRuns, run);
348 }
354 if (run->audioId) { 349 if (run->audioId) {
355 pushBack_PtrArray(&d->visiblePlayers, run); 350 pushBack_PtrArray(&d->visiblePlayers, run);
356 } 351 }
@@ -538,6 +533,7 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
538 value_Anim(&d->scrollY), 533 value_Anim(&d->scrollY),
539 docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0); 534 docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0);
540 clear_PtrArray(&d->visibleLinks); 535 clear_PtrArray(&d->visibleLinks);
536 clear_PtrArray(&d->visibleWideRuns);
541 clear_PtrArray(&d->visiblePlayers); 537 clear_PtrArray(&d->visiblePlayers);
542 const iRangecc oldHeading = currentHeading_DocumentWidget_(d); 538 const iRangecc oldHeading = currentHeading_DocumentWidget_(d);
543 /* Scan for visible runs. */ { 539 /* Scan for visible runs. */ {
@@ -766,6 +762,7 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
766 updateTheme_DocumentWidget_(d); 762 updateTheme_DocumentWidget_(d);
767 init_Anim(&d->scrollY, 0); 763 init_Anim(&d->scrollY, 0);
768 init_Anim(&d->sideOpacity, 0); 764 init_Anim(&d->sideOpacity, 0);
765 clear_Array(&d->wideRunOffsets);
769 d->state = ready_RequestState; 766 d->state = ready_RequestState;
770} 767}
771 768
@@ -903,7 +900,6 @@ static void fetch_DocumentWidget_(iDocumentWidget *d) {
903 d->request = new_GmRequest(certs_App()); 900 d->request = new_GmRequest(certs_App());
904 setUrl_GmRequest(d->request, d->mod.url); 901 setUrl_GmRequest(d->request, d->mod.url);
905 iConnect(GmRequest, d->request, updated, d, requestUpdated_DocumentWidget_); 902 iConnect(GmRequest, d->request, updated, d, requestUpdated_DocumentWidget_);
906// iConnect(GmRequest, d->request, timeout, d, requestTimedOut_DocumentWidget_);
907 iConnect(GmRequest, d->request, finished, d, requestFinished_DocumentWidget_); 903 iConnect(GmRequest, d->request, finished, d, requestFinished_DocumentWidget_);
908 submit_GmRequest(d->request); 904 submit_GmRequest(d->request);
909} 905}
@@ -955,6 +951,7 @@ static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) {
955 reset_GmDocument(d->doc); 951 reset_GmDocument(d->doc);
956 d->state = fetching_RequestState; 952 d->state = fetching_RequestState;
957 d->initNormScrollY = recent->normScrollY; 953 d->initNormScrollY = recent->normScrollY;
954 clear_Array(&d->wideRunOffsets);
958 /* Use the cached response data. */ 955 /* Use the cached response data. */
959 updateTrust_DocumentWidget_(d, resp); 956 updateTrust_DocumentWidget_(d, resp);
960 d->sourceTime = resp->when; 957 d->sourceTime = resp->when;
@@ -986,6 +983,9 @@ static void refreshWhileScrolling_DocumentWidget_(iAny *ptr) {
986} 983}
987 984
988static void smoothScroll_DocumentWidget_(iDocumentWidget *d, int offset, int duration) { 985static void smoothScroll_DocumentWidget_(iDocumentWidget *d, int offset, int duration) {
986 if (offset == 0) {
987 return;
988 }
989 /* Get rid of link numbers when scrolling. */ 989 /* Get rid of link numbers when scrolling. */
990 if (offset && d->flags & showLinkNumbers_DocumentWidgetFlag) { 990 if (offset && d->flags & showLinkNumbers_DocumentWidgetFlag) {
991 d->flags &= ~showLinkNumbers_DocumentWidgetFlag; 991 d->flags &= ~showLinkNumbers_DocumentWidgetFlag;
@@ -1030,6 +1030,39 @@ static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY, iBool ce
1030 scroll_DocumentWidget_(d, 0); /* clamp it */ 1030 scroll_DocumentWidget_(d, 0); /* clamp it */
1031} 1031}
1032 1032
1033static void scrollWideBlock_DocumentWidget_(iDocumentWidget *d, iInt2 mousePos, int delta) {
1034 if (delta == 0) {
1035 return;
1036 }
1037 const iInt2 docPos = documentPos_DocumentWidget_(d, mousePos);
1038 iConstForEach(PtrArray, i, &d->visibleWideRuns) {
1039 const iGmRun *run = i.ptr;
1040 if (docPos.y >= top_Rect(run->bounds) && docPos.y <= bottom_Rect(run->bounds)) {
1041 /* We can scroll this run. First find out how much is allowed. */
1042 const iGmRunRange range = findPreformattedRange_GmDocument(d->doc, run);
1043 int maxWidth = 0;
1044 for (const iGmRun *r = range.start; r != range.end; r++) {
1045 maxWidth = iMax(maxWidth, width_Rect(r->visBounds));
1046 }
1047 const int maxOffset = maxWidth - documentWidth_DocumentWidget_(d) + d->pageMargin * gap_UI;
1048 if (size_Array(&d->wideRunOffsets) <= run->preId) {
1049 resize_Array(&d->wideRunOffsets, run->preId + 1);
1050 }
1051 int *offset = at_Array(&d->wideRunOffsets, run->preId - 1);
1052 const int oldOffset = *offset;
1053 *offset = iClamp(*offset + delta, 0, maxOffset);
1054 /* Make sure the whole block gets redraw. */
1055 if (oldOffset != *offset) {
1056 for (const iGmRun *r = range.start; r != range.end; r++) {
1057 insert_PtrSet(d->invalidRuns, r);
1058 }
1059 refresh_Widget(d);
1060 }
1061 break;
1062 }
1063 }
1064}
1065
1033static void checkResponse_DocumentWidget_(iDocumentWidget *d) { 1066static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
1034 if (!d->request) { 1067 if (!d->request) {
1035 return; 1068 return;
@@ -1064,6 +1097,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
1064 case categorySuccess_GmStatusCode: 1097 case categorySuccess_GmStatusCode:
1065 init_Anim(&d->scrollY, 0); 1098 init_Anim(&d->scrollY, 0);
1066 reset_GmDocument(d->doc); /* new content incoming */ 1099 reset_GmDocument(d->doc); /* new content incoming */
1100 clear_Array(&d->wideRunOffsets);
1067 updateDocument_DocumentWidget_(d, resp, iTrue); 1101 updateDocument_DocumentWidget_(d, resp, iTrue);
1068 break; 1102 break;
1069 case categoryRedirect_GmStatusCode: 1103 case categoryRedirect_GmStatusCode:
@@ -2015,8 +2049,9 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2015 } 2049 }
2016 else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { 2050 else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) {
2017 float acceleration = 1.0f; 2051 float acceleration = 1.0f;
2052 const iInt2 mouseCoord = mouseCoord_Window(get_Window());
2018 if (prefs_App()->hoverOutline && 2053 if (prefs_App()->hoverOutline &&
2019 contains_Widget(constAs_Widget(d->scroll), mouseCoord_Window(get_Window()))) { 2054 contains_Widget(constAs_Widget(d->scroll), mouseCoord)) {
2020 const int outHeight = outlineHeight_DocumentWidget_(d); 2055 const int outHeight = outlineHeight_DocumentWidget_(d);
2021 if (outHeight > height_Rect(bounds_Widget(w))) { 2056 if (outHeight > height_Rect(bounds_Widget(w))) {
2022 acceleration = (float) size_GmDocument(d->doc).y / (float) outHeight; 2057 acceleration = (float) size_GmDocument(d->doc).y / (float) outHeight;
@@ -2027,7 +2062,15 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2027 which device is sending the event. */ 2062 which device is sending the event. */
2028 if (ev->wheel.which == 0) { /* Trackpad with precise scrolling w/inertia. */ 2063 if (ev->wheel.which == 0) { /* Trackpad with precise scrolling w/inertia. */
2029 stop_Anim(&d->scrollY); 2064 stop_Anim(&d->scrollY);
2030 scroll_DocumentWidget_(d, -ev->wheel.y * get_Window()->pixelRatio * acceleration); 2065 iInt2 wheel = init_I2(ev->wheel.x, ev->wheel.y);
2066 if (iAbs(wheel.x) > iAbs(wheel.y)) {
2067 wheel.y = 0;
2068 }
2069 else {
2070 wheel.x = 0;
2071 }
2072 scroll_DocumentWidget_(d, -wheel.y * get_Window()->pixelRatio * acceleration);
2073 scrollWideBlock_DocumentWidget_(d, mouseCoord, wheel.x * get_Window()->pixelRatio);
2031 } 2074 }
2032 else 2075 else
2033#endif 2076#endif
@@ -2046,8 +2089,10 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2046 d, 2089 d,
2047 -3 * amount * lineHeight_Text(paragraph_FontId) * acceleration, 2090 -3 * amount * lineHeight_Text(paragraph_FontId) * acceleration,
2048 smoothDuration_DocumentWidget_ * 2091 smoothDuration_DocumentWidget_ *
2092 /* accelerated speed for repeated wheelings */
2049 (!isFinished_Anim(&d->scrollY) && pos_Anim(&d->scrollY) < 0.25f ? 0.5f : 1.0f)); 2093 (!isFinished_Anim(&d->scrollY) && pos_Anim(&d->scrollY) < 0.25f ? 0.5f : 1.0f));
2050 /* accelerated speed for repeated wheelings */ 2094 scrollWideBlock_DocumentWidget_(
2095 d, mouseCoord, ev->wheel.x * lineHeight_Text(paragraph_FontId));
2051 } 2096 }
2052 iChangeFlags(d->flags, noHoverWhileScrolling_DocumentWidgetFlag, iTrue); 2097 iChangeFlags(d->flags, noHoverWhileScrolling_DocumentWidgetFlag, iTrue);
2053 return iTrue; 2098 return iTrue;
@@ -2399,7 +2444,15 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
2399 const iBool isHover = 2444 const iBool isHover =
2400 (run->linkId && d->widget->hoverLink && run->linkId == d->widget->hoverLink->linkId && 2445 (run->linkId && d->widget->hoverLink && run->linkId == d->widget->hoverLink->linkId &&
2401 ~run->flags & decoration_GmRunFlag); 2446 ~run->flags & decoration_GmRunFlag);
2402 const iInt2 visPos = add_I2(run->visBounds.pos, origin); 2447 iInt2 visPos = add_I2(run->visBounds.pos, origin);
2448 /* Preformatted runs can be scrolled. */
2449 if (run->preId && run->flags & wide_GmRunFlag) {
2450 const size_t numOffsets = size_Array(&d->widget->wideRunOffsets);
2451 const int *offsets = constData_Array(&d->widget->wideRunOffsets);
2452 if (run->preId <= numOffsets) {
2453 visPos.x -= offsets[run->preId - 1];
2454 }
2455 }
2403 fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmBackground_ColorId); 2456 fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmBackground_ColorId);
2404 if (run->linkId && ~run->flags & decoration_GmRunFlag) { 2457 if (run->linkId && ~run->flags & decoration_GmRunFlag) {
2405 fg = linkColor_GmDocument(doc, run->linkId, isHover ? textHover_GmLinkPart : text_GmLinkPart); 2458 fg = linkColor_GmDocument(doc, run->linkId, isHover ? textHover_GmLinkPart : text_GmLinkPart);
@@ -2962,6 +3015,7 @@ iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) {
2962 3015
2963void updateSize_DocumentWidget(iDocumentWidget *d) { 3016void updateSize_DocumentWidget(iDocumentWidget *d) {
2964 setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d)); 3017 setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d));
3018 clear_Array(&d->wideRunOffsets);
2965 updateSideIconBuf_DocumentWidget_(d); 3019 updateSideIconBuf_DocumentWidget_(d);
2966 updateOutline_DocumentWidget_(d); 3020 updateOutline_DocumentWidget_(d);
2967 updateVisible_DocumentWidget_(d); 3021 updateVisible_DocumentWidget_(d);