diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/documentwidget.c | 263 |
1 files changed, 173 insertions, 90 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 87c724de..eff18f39 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -195,12 +195,123 @@ static void animate_DocumentWidget_ (void *ticker); | |||
195 | static void animateMedia_DocumentWidget_ (iDocumentWidget *d); | 195 | static void animateMedia_DocumentWidget_ (iDocumentWidget *d); |
196 | static void updateSideIconBuf_DocumentWidget_ (const iDocumentWidget *d); | 196 | static void updateSideIconBuf_DocumentWidget_ (const iDocumentWidget *d); |
197 | static void prerender_DocumentWidget_ (iAny *); | 197 | static void prerender_DocumentWidget_ (iAny *); |
198 | static void scrollBegan_DocumentWidget_ (iAnyObject *, int, uint32_t); | ||
198 | 199 | ||
199 | static const int smoothDuration_DocumentWidget_ = 600; /* milliseconds */ | 200 | static const int smoothDuration_DocumentWidget_ = 600; /* milliseconds */ |
200 | static const int outlineMinWidth_DocumentWdiget_ = 45; /* times gap_UI */ | 201 | static const int outlineMinWidth_DocumentWdiget_ = 45; /* times gap_UI */ |
201 | static const int outlineMaxWidth_DocumentWidget_ = 65; /* times gap_UI */ | 202 | static const int outlineMaxWidth_DocumentWidget_ = 65; /* times gap_UI */ |
202 | static const int outlinePadding_DocumentWidget_ = 3; /* times gap_UI */ | 203 | static const int outlinePadding_DocumentWidget_ = 3; /* times gap_UI */ |
203 | 204 | ||
205 | |||
206 | iDeclareType(SmoothScroll) | ||
207 | |||
208 | typedef void (*iSmoothScrollNotifyFunc)(iAnyObject *, int offset, uint32_t span); | ||
209 | |||
210 | struct Impl_SmoothScroll { | ||
211 | iWidget *widget; | ||
212 | iSmoothScrollNotifyFunc notify; | ||
213 | iAnim pos; | ||
214 | int max; | ||
215 | int overscroll; | ||
216 | }; | ||
217 | |||
218 | void reset_SmoothScroll(iSmoothScroll *d) { | ||
219 | init_Anim(&d->pos, 0); | ||
220 | d->max = 0; | ||
221 | d->overscroll = (deviceType_App() != desktop_AppDeviceType ? 100 * gap_UI : 0); | ||
222 | } | ||
223 | |||
224 | void init_SmoothScroll(iSmoothScroll *d, iWidget *owner, iSmoothScrollNotifyFunc notify) { | ||
225 | d->widget = owner; | ||
226 | d->notify = notify; | ||
227 | reset_SmoothScroll(d); | ||
228 | } | ||
229 | |||
230 | void setMax_SmoothScroll(iSmoothScroll *d, int max) { | ||
231 | max = iMax(0, max); | ||
232 | if (max != d->max) { | ||
233 | d->max = max; | ||
234 | if (targetValue_Anim(&d->pos) > d->max) { | ||
235 | d->pos.to = d->max; | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
240 | static int overscroll_SmoothScroll_(const iSmoothScroll *d) { | ||
241 | if (d->overscroll) { | ||
242 | const int y = value_Anim(&d->pos); | ||
243 | if (y <= 0) { | ||
244 | return y; | ||
245 | } | ||
246 | if (y >= d->max) { | ||
247 | return y - d->max; | ||
248 | } | ||
249 | } | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | float pos_SmoothScroll(const iSmoothScroll *d) { | ||
254 | return value_Anim(&d->pos) - overscroll_SmoothScroll_(d) * 0.667f; | ||
255 | } | ||
256 | |||
257 | iBool isFinished_SmoothScroll(const iSmoothScroll *d) { | ||
258 | return isFinished_Anim(&d->pos); | ||
259 | } | ||
260 | |||
261 | void move_SmoothScroll(iSmoothScroll *d, int offset, uint32_t duration) { | ||
262 | #if !defined (iPlatformMobile) | ||
263 | if (!prefs_App()->smoothScrolling) { | ||
264 | duration = 0; /* always instant */ | ||
265 | } | ||
266 | #endif | ||
267 | int destY = targetValue_Anim(&d->pos) + offset; | ||
268 | if (destY < -d->overscroll) { | ||
269 | destY = -d->overscroll; | ||
270 | } | ||
271 | if (d->max > 0) { | ||
272 | if (destY >= d->max + d->overscroll) { | ||
273 | destY = d->max + d->overscroll; | ||
274 | } | ||
275 | } | ||
276 | else { | ||
277 | destY = 0; | ||
278 | } | ||
279 | if (duration) { | ||
280 | setValueEased_Anim(&d->pos, destY, duration); | ||
281 | } | ||
282 | else { | ||
283 | setValue_Anim(&d->pos, destY, 0); | ||
284 | } | ||
285 | if (d->overscroll && widgetMode_Touch(d->widget) == momentum_WidgetTouchMode) { | ||
286 | const int osDelta = overscroll_SmoothScroll_(d); | ||
287 | if (osDelta) { | ||
288 | const float remaining = stopWidgetMomentum_Touch(d->widget); | ||
289 | duration = iMini(1000, 50 * sqrt(remaining / gap_UI)); | ||
290 | setValue_Anim(&d->pos, osDelta < 0 ? 0 : d->max, duration); | ||
291 | d->pos.flags = bounce_AnimFlag | easeOut_AnimFlag | softer_AnimFlag; | ||
292 | // printf("remaining: %f dur: %d\n", remaining, duration); | ||
293 | d->pos.bounce = (osDelta < 0 ? -1 : 1) * | ||
294 | iMini(5 * d->overscroll, remaining * remaining * 0.00005f); | ||
295 | } | ||
296 | } | ||
297 | if (d->notify) { | ||
298 | d->notify(d->widget, offset, duration); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | iBool processEvent_SmoothScroll(iSmoothScroll *d, const SDL_Event *ev) { | ||
303 | if (ev->type == SDL_USEREVENT && ev->user.code == widgetTouchEnds_UserEventCode) { | ||
304 | const int osDelta = overscroll_SmoothScroll_(d); | ||
305 | if (osDelta) { | ||
306 | move_SmoothScroll(d, -osDelta, 100 * sqrt(iAbs(osDelta) / gap_UI)); | ||
307 | d->pos.flags = easeOut_AnimFlag | muchSofter_AnimFlag; | ||
308 | } | ||
309 | return iTrue; | ||
310 | } | ||
311 | return iFalse; | ||
312 | } | ||
313 | |||
314 | |||
204 | enum iRequestState { | 315 | enum iRequestState { |
205 | blank_RequestState, | 316 | blank_RequestState, |
206 | fetching_RequestState, | 317 | fetching_RequestState, |
@@ -274,7 +385,9 @@ struct Impl_DocumentWidget { | |||
274 | iInt2 contextPos; /* coordinates of latest right click */ | 385 | iInt2 contextPos; /* coordinates of latest right click */ |
275 | iString pendingGotoHeading; | 386 | iString pendingGotoHeading; |
276 | float initNormScrollY; | 387 | float initNormScrollY; |
277 | iAnim scrollY; | 388 | // iAnim scrollY; |
389 | // int overscroll; | ||
390 | iSmoothScroll scrollY; | ||
278 | iAnim sideOpacity; | 391 | iAnim sideOpacity; |
279 | iAnim altTextOpacity; | 392 | iAnim altTextOpacity; |
280 | iScrollWidget *scroll; | 393 | iScrollWidget *scroll; |
@@ -287,7 +400,6 @@ struct Impl_DocumentWidget { | |||
287 | iDrawBufs * drawBufs; /* dynamic state for drawing */ | 400 | iDrawBufs * drawBufs; /* dynamic state for drawing */ |
288 | iTranslation * translation; | 401 | iTranslation * translation; |
289 | iWidget * phoneToolbar; | 402 | iWidget * phoneToolbar; |
290 | int overscroll; | ||
291 | int pinchZoomInitial; | 403 | int pinchZoomInitial; |
292 | int pinchZoomPosted; | 404 | int pinchZoomPosted; |
293 | }; | 405 | }; |
@@ -302,7 +414,6 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
302 | init_PersistentDocumentState(&d->mod); | 414 | init_PersistentDocumentState(&d->mod); |
303 | d->flags = 0; | 415 | d->flags = 0; |
304 | d->phoneToolbar = NULL; | 416 | d->phoneToolbar = NULL; |
305 | d->overscroll = deviceType_App() != desktop_AppDeviceType ? 50 * gap_UI : 0; | ||
306 | iZap(d->certExpiry); | 417 | iZap(d->certExpiry); |
307 | d->certFingerprint = new_Block(0); | 418 | d->certFingerprint = new_Block(0); |
308 | d->certFlags = 0; | 419 | d->certFlags = 0; |
@@ -316,7 +427,8 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
316 | d->redirectCount = 0; | 427 | d->redirectCount = 0; |
317 | d->ordinalBase = 0; | 428 | d->ordinalBase = 0; |
318 | d->initNormScrollY = 0; | 429 | d->initNormScrollY = 0; |
319 | init_Anim(&d->scrollY, 0); | 430 | //init_Anim(&d->scrollY, 0); |
431 | init_SmoothScroll(&d->scrollY, w, scrollBegan_DocumentWidget_); | ||
320 | d->animWideRunId = 0; | 432 | d->animWideRunId = 0; |
321 | init_Anim(&d->animWideRunOffset, 0); | 433 | init_Anim(&d->animWideRunOffset, 0); |
322 | d->selectMark = iNullRange; | 434 | d->selectMark = iNullRange; |
@@ -497,19 +609,19 @@ static iRect siteBannerRect_DocumentWidget_(const iDocumentWidget *d) { | |||
497 | return zero_Rect(); | 609 | return zero_Rect(); |
498 | } | 610 | } |
499 | const iRect docBounds = documentBounds_DocumentWidget_(d); | 611 | const iRect docBounds = documentBounds_DocumentWidget_(d); |
500 | const iInt2 origin = addY_I2(topLeft_Rect(docBounds), -value_Anim(&d->scrollY)); | 612 | const iInt2 origin = addY_I2(topLeft_Rect(docBounds), -pos_SmoothScroll(&d->scrollY)); |
501 | return moved_Rect(banner->visBounds, origin); | 613 | return moved_Rect(banner->visBounds, origin); |
502 | } | 614 | } |
503 | 615 | ||
504 | static iInt2 documentPos_DocumentWidget_(const iDocumentWidget *d, iInt2 pos) { | 616 | static iInt2 documentPos_DocumentWidget_(const iDocumentWidget *d, iInt2 pos) { |
505 | return addY_I2(sub_I2(pos, topLeft_Rect(documentBounds_DocumentWidget_(d))), | 617 | return addY_I2(sub_I2(pos, topLeft_Rect(documentBounds_DocumentWidget_(d))), |
506 | value_Anim(&d->scrollY)); | 618 | pos_SmoothScroll(&d->scrollY)); |
507 | } | 619 | } |
508 | 620 | ||
509 | static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) { | 621 | static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) { |
510 | const int margin = !hasSiteBanner_GmDocument(d->doc) ? gap_UI * d->pageMargin : 0; | 622 | const int margin = !hasSiteBanner_GmDocument(d->doc) ? gap_UI * d->pageMargin : 0; |
511 | return (iRangei){ value_Anim(&d->scrollY) - margin, | 623 | return (iRangei){ pos_SmoothScroll(&d->scrollY) - margin, |
512 | value_Anim(&d->scrollY) + height_Rect(bounds_Widget(constAs_Widget(d))) - | 624 | pos_SmoothScroll(&d->scrollY) + height_Rect(bounds_Widget(constAs_Widget(d))) - |
513 | margin }; | 625 | margin }; |
514 | } | 626 | } |
515 | 627 | ||
@@ -549,7 +661,7 @@ static const iGmRun *lastVisibleLink_DocumentWidget_(const iDocumentWidget *d) { | |||
549 | static float normScrollPos_DocumentWidget_(const iDocumentWidget *d) { | 661 | static float normScrollPos_DocumentWidget_(const iDocumentWidget *d) { |
550 | const int docSize = size_GmDocument(d->doc).y; | 662 | const int docSize = size_GmDocument(d->doc).y; |
551 | if (docSize) { | 663 | if (docSize) { |
552 | return value_Anim(&d->scrollY) / (float) docSize; | 664 | return pos_SmoothScroll(&d->scrollY) / (float) docSize; |
553 | } | 665 | } |
554 | return 0; | 666 | return 0; |
555 | } | 667 | } |
@@ -642,7 +754,7 @@ static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) { | |||
642 | const iGmRun * oldHoverLink = d->hoverLink; | 754 | const iGmRun * oldHoverLink = d->hoverLink; |
643 | d->hoverPre = NULL; | 755 | d->hoverPre = NULL; |
644 | d->hoverLink = NULL; | 756 | d->hoverLink = NULL; |
645 | const iInt2 hoverPos = addY_I2(sub_I2(mouse, topLeft_Rect(docBounds)), value_Anim(&d->scrollY)); | 757 | const iInt2 hoverPos = addY_I2(sub_I2(mouse, topLeft_Rect(docBounds)), pos_SmoothScroll(&d->scrollY)); |
646 | if (isHoverAllowed_DocumentWidget_(d)) { | 758 | if (isHoverAllowed_DocumentWidget_(d)) { |
647 | iConstForEach(PtrArray, i, &d->visibleLinks) { | 759 | iConstForEach(PtrArray, i, &d->visibleLinks) { |
648 | const iGmRun *run = i.ptr; | 760 | const iGmRun *run = i.ptr; |
@@ -701,7 +813,7 @@ static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) { | |||
701 | static void updateSideOpacity_DocumentWidget_(iDocumentWidget *d, iBool isAnimated) { | 813 | static void updateSideOpacity_DocumentWidget_(iDocumentWidget *d, iBool isAnimated) { |
702 | float opacity = 0.0f; | 814 | float opacity = 0.0f; |
703 | const iGmRun *banner = siteBanner_GmDocument(d->doc); | 815 | const iGmRun *banner = siteBanner_GmDocument(d->doc); |
704 | if (banner && bottom_Rect(banner->visBounds) < value_Anim(&d->scrollY)) { | 816 | if (banner && bottom_Rect(banner->visBounds) < pos_SmoothScroll(&d->scrollY)) { |
705 | opacity = 1.0f; | 817 | opacity = 1.0f; |
706 | } | 818 | } |
707 | setValue_Anim(&d->sideOpacity, opacity, isAnimated ? (opacity < 0.5f ? 100 : 200) : 0); | 819 | setValue_Anim(&d->sideOpacity, opacity, isAnimated ? (opacity < 0.5f ? 100 : 200) : 0); |
@@ -797,12 +909,14 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | |||
797 | centerVertically_DocumentWidgetFlag, | 909 | centerVertically_DocumentWidgetFlag, |
798 | prefs_App()->centerShortDocs || startsWithCase_String(d->mod.url, "about:") || | 910 | prefs_App()->centerShortDocs || startsWithCase_String(d->mod.url, "about:") || |
799 | !isSuccess_GmStatusCode(d->sourceStatus)); | 911 | !isSuccess_GmStatusCode(d->sourceStatus)); |
800 | const iRangei visRange = visibleRange_DocumentWidget_(d); | 912 | const iRangei visRange = visibleRange_DocumentWidget_(d); |
801 | const iRect bounds = bounds_Widget(as_Widget(d)); | 913 | const iRect bounds = bounds_Widget(as_Widget(d)); |
802 | setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_DocumentWidget_(d) }); | 914 | const int scrollMax = scrollMax_DocumentWidget_(d); |
915 | setMax_SmoothScroll(&d->scrollY, scrollMax); | ||
916 | setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax }); | ||
803 | const int docSize = size_GmDocument(d->doc).y; | 917 | const int docSize = size_GmDocument(d->doc).y; |
804 | setThumb_ScrollWidget(d->scroll, | 918 | setThumb_ScrollWidget(d->scroll, |
805 | value_Anim(&d->scrollY), | 919 | pos_SmoothScroll(&d->scrollY), |
806 | docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0); | 920 | docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0); |
807 | clear_PtrArray(&d->visibleLinks); | 921 | clear_PtrArray(&d->visibleLinks); |
808 | clear_PtrArray(&d->visibleWideRuns); | 922 | clear_PtrArray(&d->visibleWideRuns); |
@@ -1016,7 +1130,7 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode | |||
1016 | translate_Lang(src); | 1130 | translate_Lang(src); |
1017 | setSource_DocumentWidget(d, src); | 1131 | setSource_DocumentWidget(d, src); |
1018 | updateTheme_DocumentWidget_(d); | 1132 | updateTheme_DocumentWidget_(d); |
1019 | init_Anim(&d->scrollY, 0); | 1133 | reset_SmoothScroll(&d->scrollY); |
1020 | init_Anim(&d->sideOpacity, 0); | 1134 | init_Anim(&d->sideOpacity, 0); |
1021 | init_Anim(&d->altTextOpacity, 0); | 1135 | init_Anim(&d->altTextOpacity, 0); |
1022 | resetWideRuns_DocumentWidget_(d); | 1136 | resetWideRuns_DocumentWidget_(d); |
@@ -1224,12 +1338,14 @@ static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { | |||
1224 | d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag; | 1338 | d->drawBufs->flags |= updateTimestampBuf_DrawBufsFlag; |
1225 | set_Block(&d->sourceContent, &resp->body); | 1339 | set_Block(&d->sourceContent, &resp->body); |
1226 | updateDocument_DocumentWidget_(d, resp, iTrue); | 1340 | updateDocument_DocumentWidget_(d, resp, iTrue); |
1227 | init_Anim(&d->scrollY, d->initNormScrollY * size_GmDocument(d->doc).y); | ||
1228 | init_Anim(&d->altTextOpacity, 0); | 1341 | init_Anim(&d->altTextOpacity, 0); |
1229 | d->state = ready_RequestState; | 1342 | d->state = ready_RequestState; |
1343 | reset_SmoothScroll(&d->scrollY); | ||
1344 | init_Anim(&d->scrollY.pos, d->initNormScrollY * size_GmDocument(d->doc).y); | ||
1230 | updateSideOpacity_DocumentWidget_(d, iFalse); | 1345 | updateSideOpacity_DocumentWidget_(d, iFalse); |
1231 | d->drawBufs->flags |= updateSideBuf_DrawBufsFlag; | 1346 | d->drawBufs->flags |= updateSideBuf_DrawBufsFlag; |
1232 | updateVisible_DocumentWidget_(d); | 1347 | updateVisible_DocumentWidget_(d); |
1348 | move_SmoothScroll(&d->scrollY, 0, 0); /* clamp position to new max */ | ||
1233 | cacheDocumentGlyphs_DocumentWidget_(d); | 1349 | cacheDocumentGlyphs_DocumentWidget_(d); |
1234 | postCommandf_App("document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); | 1350 | postCommandf_App("document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); |
1235 | return iTrue; | 1351 | return iTrue; |
@@ -1252,26 +1368,13 @@ static void refreshWhileScrolling_DocumentWidget_(iAny *ptr) { | |||
1252 | if (isFinished_Anim(&d->animWideRunOffset)) { | 1368 | if (isFinished_Anim(&d->animWideRunOffset)) { |
1253 | d->animWideRunId = 0; | 1369 | d->animWideRunId = 0; |
1254 | } | 1370 | } |
1255 | if (!isFinished_Anim(&d->scrollY) || !isFinished_Anim(&d->animWideRunOffset)) { | 1371 | if (!isFinished_SmoothScroll(&d->scrollY) || !isFinished_Anim(&d->animWideRunOffset)) { |
1256 | addTicker_App(refreshWhileScrolling_DocumentWidget_, d); | 1372 | addTicker_App(refreshWhileScrolling_DocumentWidget_, d); |
1257 | } | 1373 | } |
1258 | } | 1374 | } |
1259 | 1375 | ||
1260 | static int overscroll_DocumentWidget_(const iDocumentWidget *d) { | 1376 | static void scrollBegan_DocumentWidget_(iAnyObject *any, int offset, uint32_t duration) { |
1261 | if (d->overscroll) { | 1377 | iDocumentWidget *d = any; |
1262 | const int y = value_Anim(&d->scrollY); | ||
1263 | if (y <= 0) { | ||
1264 | return y; | ||
1265 | } | ||
1266 | const int scrollMax = scrollMax_DocumentWidget_(d); | ||
1267 | if (y >= scrollMax) { | ||
1268 | return y - scrollMax; | ||
1269 | } | ||
1270 | } | ||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | static void smoothScroll_DocumentWidget_(iDocumentWidget *d, int offset, int duration) { | ||
1275 | /* Get rid of link numbers when scrolling. */ | 1378 | /* Get rid of link numbers when scrolling. */ |
1276 | if (offset && d->flags & showLinkNumbers_DocumentWidgetFlag) { | 1379 | if (offset && d->flags & showLinkNumbers_DocumentWidgetFlag) { |
1277 | setLinkNumberMode_DocumentWidget_(d, iFalse); | 1380 | setLinkNumberMode_DocumentWidget_(d, iFalse); |
@@ -1283,42 +1386,6 @@ static void smoothScroll_DocumentWidget_(iDocumentWidget *d, int offset, int dur | |||
1283 | showToolbars_Window(get_Window(), offset < 0); | 1386 | showToolbars_Window(get_Window(), offset < 0); |
1284 | } | 1387 | } |
1285 | } | 1388 | } |
1286 | #if !defined (iPlatformMobile) | ||
1287 | if (!prefs_App()->smoothScrolling) { | ||
1288 | duration = 0; /* always instant */ | ||
1289 | } | ||
1290 | #endif | ||
1291 | int destY = targetValue_Anim(&d->scrollY) + offset; | ||
1292 | if (destY < -2 * d->overscroll) { | ||
1293 | destY = -2 * d->overscroll; | ||
1294 | } | ||
1295 | const int scrollMax = scrollMax_DocumentWidget_(d); | ||
1296 | if (scrollMax > 0) { | ||
1297 | if (destY >= scrollMax + 2 * d->overscroll) { | ||
1298 | destY = scrollMax + 2 * d->overscroll; | ||
1299 | } | ||
1300 | } | ||
1301 | else { | ||
1302 | destY = 0; | ||
1303 | } | ||
1304 | if (duration) { | ||
1305 | setValueEased_Anim(&d->scrollY, destY, duration); | ||
1306 | } | ||
1307 | else { | ||
1308 | setValue_Anim(&d->scrollY, destY, 0); | ||
1309 | } | ||
1310 | if (d->overscroll && widgetMode_Touch(as_Widget(d)) == momentum_WidgetTouchMode) { | ||
1311 | const int osDelta = overscroll_DocumentWidget_(d); | ||
1312 | if (osDelta) { | ||
1313 | const float remaining = stopWidgetMomentum_Touch(as_Widget(d)); | ||
1314 | duration = iMini(1000, 50 * sqrt(remaining / gap_UI)); | ||
1315 | setValue_Anim(&d->scrollY, osDelta < 0 ? 0 : scrollMax, duration); | ||
1316 | d->scrollY.flags = bounce_AnimFlag | easeOut_AnimFlag | softer_AnimFlag; | ||
1317 | printf("remaining: %f dur: %d\n", remaining, duration); | ||
1318 | d->scrollY.bounce = (osDelta < 0 ? -1 : 1) * | ||
1319 | iMini(10 * d->overscroll, remaining * remaining * 0.00005f); | ||
1320 | } | ||
1321 | } | ||
1322 | updateVisible_DocumentWidget_(d); | 1389 | updateVisible_DocumentWidget_(d); |
1323 | refresh_Widget(as_Widget(d)); | 1390 | refresh_Widget(as_Widget(d)); |
1324 | if (duration > 0) { | 1391 | if (duration > 0) { |
@@ -1327,6 +1394,27 @@ static void smoothScroll_DocumentWidget_(iDocumentWidget *d, int offset, int dur | |||
1327 | } | 1394 | } |
1328 | } | 1395 | } |
1329 | 1396 | ||
1397 | static void smoothScroll_DocumentWidget_(iDocumentWidget *d, int offset, int duration) { | ||
1398 | // /* Get rid of link numbers when scrolling. */ | ||
1399 | // if (offset && d->flags & showLinkNumbers_DocumentWidgetFlag) { | ||
1400 | // setLinkNumberMode_DocumentWidget_(d, iFalse); | ||
1401 | // invalidateVisibleLinks_DocumentWidget_(d); | ||
1402 | // } | ||
1403 | // /* Show and hide toolbar on scroll. */ | ||
1404 | // if (deviceType_App() == phone_AppDeviceType) { | ||
1405 | // if (prefs_App()->hideToolbarOnScroll && iAbs(offset) > 5) { | ||
1406 | // showToolbars_Window(get_Window(), offset < 0); | ||
1407 | // } | ||
1408 | // } | ||
1409 | move_SmoothScroll(&d->scrollY, offset, duration); | ||
1410 | // updateVisible_DocumentWidget_(d); | ||
1411 | // refresh_Widget(as_Widget(d)); | ||
1412 | // if (duration > 0) { | ||
1413 | // iChangeFlags(d->flags, noHoverWhileScrolling_DocumentWidgetFlag, iTrue); | ||
1414 | // addTicker_App(refreshWhileScrolling_DocumentWidget_, d); | ||
1415 | // } | ||
1416 | } | ||
1417 | |||
1330 | static void scroll_DocumentWidget_(iDocumentWidget *d, int offset) { | 1418 | static void scroll_DocumentWidget_(iDocumentWidget *d, int offset) { |
1331 | smoothScroll_DocumentWidget_(d, offset, 0 /* instantly */); | 1419 | smoothScroll_DocumentWidget_(d, offset, 0 /* instantly */); |
1332 | } | 1420 | } |
@@ -1335,7 +1423,7 @@ static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY, iBool ce | |||
1335 | if (!hasSiteBanner_GmDocument(d->doc)) { | 1423 | if (!hasSiteBanner_GmDocument(d->doc)) { |
1336 | documentY += d->pageMargin * gap_UI; | 1424 | documentY += d->pageMargin * gap_UI; |
1337 | } | 1425 | } |
1338 | init_Anim(&d->scrollY, | 1426 | init_Anim(&d->scrollY.pos, |
1339 | documentY - (centered ? documentBounds_DocumentWidget_(d).size.y / 2 | 1427 | documentY - (centered ? documentBounds_DocumentWidget_(d).size.y / 2 |
1340 | : lineHeight_Text(paragraph_FontId))); | 1428 | : lineHeight_Text(paragraph_FontId))); |
1341 | scroll_DocumentWidget_(d, 0); /* clamp it */ | 1429 | scroll_DocumentWidget_(d, 0); /* clamp it */ |
@@ -1449,7 +1537,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { | |||
1449 | break; | 1537 | break; |
1450 | } | 1538 | } |
1451 | case categorySuccess_GmStatusCode: | 1539 | case categorySuccess_GmStatusCode: |
1452 | init_Anim(&d->scrollY, 0); | 1540 | reset_SmoothScroll(&d->scrollY); |
1453 | reset_GmDocument(d->doc); /* new content incoming */ | 1541 | reset_GmDocument(d->doc); /* new content incoming */ |
1454 | resetWideRuns_DocumentWidget_(d); | 1542 | resetWideRuns_DocumentWidget_(d); |
1455 | updateDocument_DocumentWidget_(d, resp, iTrue); | 1543 | updateDocument_DocumentWidget_(d, resp, iTrue); |
@@ -2084,7 +2172,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2084 | } | 2172 | } |
2085 | updateFetchProgress_DocumentWidget_(d); | 2173 | updateFetchProgress_DocumentWidget_(d); |
2086 | checkResponse_DocumentWidget_(d); | 2174 | checkResponse_DocumentWidget_(d); |
2087 | init_Anim(&d->scrollY, d->initNormScrollY * size_GmDocument(d->doc).y); | 2175 | init_Anim(&d->scrollY.pos, d->initNormScrollY * size_GmDocument(d->doc).y); /* TODO: unless user already scrolled! */ |
2088 | d->state = ready_RequestState; | 2176 | d->state = ready_RequestState; |
2089 | /* The response may be cached. */ { | 2177 | /* The response may be cached. */ { |
2090 | if (!equal_Rangecc(urlScheme_String(d->mod.url), "about") && | 2178 | if (!equal_Rangecc(urlScheme_String(d->mod.url), "about") && |
@@ -2249,7 +2337,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2249 | return iTrue; | 2337 | return iTrue; |
2250 | } | 2338 | } |
2251 | else if (equalWidget_Command(cmd, w, "scroll.moved")) { | 2339 | else if (equalWidget_Command(cmd, w, "scroll.moved")) { |
2252 | init_Anim(&d->scrollY, arg_Command(cmd)); | 2340 | init_Anim(&d->scrollY.pos, arg_Command(cmd)); |
2253 | updateVisible_DocumentWidget_(d); | 2341 | updateVisible_DocumentWidget_(d); |
2254 | return iTrue; | 2342 | return iTrue; |
2255 | } | 2343 | } |
@@ -2267,7 +2355,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2267 | return iTrue; | 2355 | return iTrue; |
2268 | } | 2356 | } |
2269 | else if (equal_Command(cmd, "scroll.top") && document_App() == d) { | 2357 | else if (equal_Command(cmd, "scroll.top") && document_App() == d) { |
2270 | init_Anim(&d->scrollY, 0); | 2358 | init_Anim(&d->scrollY.pos, 0); |
2271 | invalidate_VisBuf(d->visBuf); | 2359 | invalidate_VisBuf(d->visBuf); |
2272 | scroll_DocumentWidget_(d, 0); | 2360 | scroll_DocumentWidget_(d, 0); |
2273 | updateVisible_DocumentWidget_(d); | 2361 | updateVisible_DocumentWidget_(d); |
@@ -2275,7 +2363,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2275 | return iTrue; | 2363 | return iTrue; |
2276 | } | 2364 | } |
2277 | else if (equal_Command(cmd, "scroll.bottom") && document_App() == d) { | 2365 | else if (equal_Command(cmd, "scroll.bottom") && document_App() == d) { |
2278 | init_Anim(&d->scrollY, scrollMax_DocumentWidget_(d)); | 2366 | init_Anim(&d->scrollY.pos, d->scrollY.max); |
2279 | invalidate_VisBuf(d->visBuf); | 2367 | invalidate_VisBuf(d->visBuf); |
2280 | scroll_DocumentWidget_(d, 0); | 2368 | scroll_DocumentWidget_(d, 0); |
2281 | updateVisible_DocumentWidget_(d); | 2369 | updateVisible_DocumentWidget_(d); |
@@ -2438,7 +2526,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2438 | 2526 | ||
2439 | static iRect runRect_DocumentWidget_(const iDocumentWidget *d, const iGmRun *run) { | 2527 | static iRect runRect_DocumentWidget_(const iDocumentWidget *d, const iGmRun *run) { |
2440 | const iRect docBounds = documentBounds_DocumentWidget_(d); | 2528 | const iRect docBounds = documentBounds_DocumentWidget_(d); |
2441 | return moved_Rect(run->bounds, addY_I2(topLeft_Rect(docBounds), -value_Anim(&d->scrollY))); | 2529 | return moved_Rect(run->bounds, addY_I2(topLeft_Rect(docBounds), -pos_SmoothScroll(&d->scrollY))); |
2442 | } | 2530 | } |
2443 | 2531 | ||
2444 | static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) { | 2532 | static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) { |
@@ -2622,12 +2710,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2622 | if (isMetricsChange_UserEvent(ev)) { | 2710 | if (isMetricsChange_UserEvent(ev)) { |
2623 | updateSize_DocumentWidget(d); | 2711 | updateSize_DocumentWidget(d); |
2624 | } | 2712 | } |
2625 | else if (ev->type == SDL_USEREVENT && ev->user.code == widgetTouchEnds_UserEventCode) { | 2713 | else if (processEvent_SmoothScroll(&d->scrollY, ev)) { |
2626 | const int osDelta = overscroll_DocumentWidget_(d); | ||
2627 | if (osDelta) { | ||
2628 | smoothScroll_DocumentWidget_(d, -osDelta, 100 * sqrt(iAbs(osDelta) / gap_UI)); | ||
2629 | d->scrollY.flags = easeOut_AnimFlag | muchSofter_AnimFlag; | ||
2630 | } | ||
2631 | return iTrue; | 2714 | return iTrue; |
2632 | } | 2715 | } |
2633 | else if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) { | 2716 | else if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) { |
@@ -2715,8 +2798,8 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2715 | else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { | 2798 | else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { |
2716 | const iInt2 mouseCoord = mouseCoord_Window(get_Window()); | 2799 | const iInt2 mouseCoord = mouseCoord_Window(get_Window()); |
2717 | if (isPerPixel_MouseWheelEvent(&ev->wheel)) { | 2800 | if (isPerPixel_MouseWheelEvent(&ev->wheel)) { |
2718 | stop_Anim(&d->scrollY); | 2801 | const iInt2 wheel = init_I2(ev->wheel.x, ev->wheel.y); |
2719 | iInt2 wheel = init_I2(ev->wheel.x, ev->wheel.y); | 2802 | stop_Anim(&d->scrollY.pos); |
2720 | scroll_DocumentWidget_(d, -wheel.y); | 2803 | scroll_DocumentWidget_(d, -wheel.y); |
2721 | scrollWideBlock_DocumentWidget_(d, mouseCoord, -wheel.x, 0); | 2804 | scrollWideBlock_DocumentWidget_(d, mouseCoord, -wheel.x, 0); |
2722 | } | 2805 | } |
@@ -2732,7 +2815,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
2732 | -3 * amount * lineHeight_Text(paragraph_FontId), | 2815 | -3 * amount * lineHeight_Text(paragraph_FontId), |
2733 | smoothDuration_DocumentWidget_ * | 2816 | smoothDuration_DocumentWidget_ * |
2734 | /* accelerated speed for repeated wheelings */ | 2817 | /* accelerated speed for repeated wheelings */ |
2735 | (!isFinished_Anim(&d->scrollY) && pos_Anim(&d->scrollY) < 0.25f ? 0.5f : 1.0f)); | 2818 | (!isFinished_SmoothScroll(&d->scrollY) && pos_Anim(&d->scrollY.pos) < 0.25f ? 0.5f : 1.0f)); |
2736 | scrollWideBlock_DocumentWidget_( | 2819 | scrollWideBlock_DocumentWidget_( |
2737 | d, mouseCoord, -3 * ev->wheel.x * lineHeight_Text(paragraph_FontId), 167); | 2820 | d, mouseCoord, -3 * ev->wheel.x * lineHeight_Text(paragraph_FontId), 167); |
2738 | } | 2821 | } |
@@ -3239,7 +3322,7 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol | |||
3239 | } | 3322 | } |
3240 | if (~run->flags & decoration_GmRunFlag) { | 3323 | if (~run->flags & decoration_GmRunFlag) { |
3241 | const iInt2 visPos = | 3324 | const iInt2 visPos = |
3242 | add_I2(run->bounds.pos, addY_I2(d->viewPos, -value_Anim(&d->widget->scrollY))); | 3325 | add_I2(run->bounds.pos, addY_I2(d->viewPos, -pos_SmoothScroll(&d->widget->scrollY))); |
3243 | const iRect rangeRect = { addX_I2(visPos, x), init_I2(w, height_Rect(run->bounds)) }; | 3326 | const iRect rangeRect = { addX_I2(visPos, x), init_I2(w, height_Rect(run->bounds)) }; |
3244 | if (rangeRect.size.x) { | 3327 | if (rangeRect.size.x) { |
3245 | fillRect_Paint(&d->paint, rangeRect, color); | 3328 | fillRect_Paint(&d->paint, rangeRect, color); |
@@ -3259,7 +3342,7 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol | |||
3259 | (contains_Range(&url, mark.end) || url.end == mark.end)) { | 3342 | (contains_Range(&url, mark.end) || url.end == mark.end)) { |
3260 | fillRect_Paint( | 3343 | fillRect_Paint( |
3261 | &d->paint, | 3344 | &d->paint, |
3262 | moved_Rect(run->visBounds, addY_I2(d->viewPos, -value_Anim(&d->widget->scrollY))), | 3345 | moved_Rect(run->visBounds, addY_I2(d->viewPos, -pos_SmoothScroll(&d->widget->scrollY))), |
3263 | color); | 3346 | color); |
3264 | } | 3347 | } |
3265 | } | 3348 | } |
@@ -3704,7 +3787,7 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | |||
3704 | bottomLeft_Rect(bounds), | 3787 | bottomLeft_Rect(bounds), |
3705 | init_I2(margin, | 3788 | init_I2(margin, |
3706 | -margin + -dbuf->timestampBuf->size.y + | 3789 | -margin + -dbuf->timestampBuf->size.y + |
3707 | iMax(0, scrollMax_DocumentWidget_(d) - value_Anim(&d->scrollY)))), | 3790 | iMax(0, d->scrollY.max - pos_SmoothScroll(&d->scrollY)))), |
3708 | tmQuoteIcon_ColorId); | 3791 | tmQuoteIcon_ColorId); |
3709 | } | 3792 | } |
3710 | unsetClip_Paint(&p); | 3793 | unsetClip_Paint(&p); |
@@ -3949,7 +4032,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
3949 | }; | 4032 | }; |
3950 | render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */); | 4033 | render_DocumentWidget_(d, &ctx, iFalse /* just the mandatory parts */); |
3951 | setClip_Paint(&ctx.paint, bounds); | 4034 | setClip_Paint(&ctx.paint, bounds); |
3952 | int yTop = docBounds.pos.y - value_Anim(&d->scrollY) + overscroll_DocumentWidget_(d) * 0.667f; | 4035 | int yTop = docBounds.pos.y - pos_SmoothScroll(&d->scrollY); |
3953 | draw_VisBuf(d->visBuf, init_I2(bounds.pos.x, yTop), ySpan_Rect(bounds)); | 4036 | draw_VisBuf(d->visBuf, init_I2(bounds.pos.x, yTop), ySpan_Rect(bounds)); |
3954 | /* Text markers. */ | 4037 | /* Text markers. */ |
3955 | const iBool isTouchSelecting = (flags_Widget(w) & touchDrag_WidgetFlag) != 0; | 4038 | const iBool isTouchSelecting = (flags_Widget(w) & touchDrag_WidgetFlag) != 0; |
@@ -4021,7 +4104,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
4021 | const int altFont = uiLabel_FontId; | 4104 | const int altFont = uiLabel_FontId; |
4022 | const int wrap = docBounds.size.x - 2 * margin; | 4105 | const int wrap = docBounds.size.x - 2 * margin; |
4023 | iInt2 pos = addY_I2(add_I2(docBounds.pos, meta->pixelRect.pos), | 4106 | iInt2 pos = addY_I2(add_I2(docBounds.pos, meta->pixelRect.pos), |
4024 | -value_Anim(&d->scrollY)); | 4107 | -pos_SmoothScroll(&d->scrollY)); |
4025 | const iInt2 textSize = advanceWrapRange_Text(altFont, wrap, meta->altText); | 4108 | const iInt2 textSize = advanceWrapRange_Text(altFont, wrap, meta->altText); |
4026 | pos.y -= textSize.y + gap_UI; | 4109 | pos.y -= textSize.y + gap_UI; |
4027 | pos.y = iMax(pos.y, top_Rect(bounds)); | 4110 | pos.y = iMax(pos.y, top_Rect(bounds)); |