=> 0c9806529bc33f02431570ba0cc2d48039b8afe1
[1mdiff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c[m [1mindex 11d84414..9dea6cbb 100644[m [1m--- a/src/ui/documentwidget.c[m [1m+++ b/src/ui/documentwidget.c[m [36m@@ -144,7 +144,7 @@[m [mstruct Impl_OutlineItem {[m [m static void animatePlayers_DocumentWidget_(iDocumentWidget *d);[m [m [31m-static const int smoothSpeed_DocumentWidget_ = 120; /* unit: gap_Text per second */[m [32m+[m[32mstatic const int smoothDuration_DocumentWidget_ = 600; /* milliseconds */[m static const int outlineMinWidth_DocumentWdiget_ = 45; /* times gap_UI */[m static const int outlineMaxWidth_DocumentWidget_ = 65; /* times gap_UI */[m static const int outlinePadding_DocumentWidget_ = 3; /* times gap_UI */[m [36m@@ -156,6 +156,12 @@[m [menum iRequestState {[m ready_RequestState,[m };[m [m [32m+[m[32menum iDocumentWidgetFlag {[m [32m+[m[32m selecting_DocumentWidgetFlag = iBit(1),[m [32m+[m[32m noHoverWhileScrolling_DocumentWidgetFlag = iBit(2),[m [32m+[m[32m showLinkNumbers_DocumentWidgetFlag = iBit(3),[m [32m+[m[32m};[m [32m+[m struct Impl_DocumentWidget {[m iWidget widget;[m enum iRequestState state;[m [36m@@ -172,7 +178,8 @@[m [mstruct Impl_DocumentWidget {[m iDate certExpiry;[m iString * certSubject;[m int redirectCount;[m [31m- iBool selecting;[m [32m+[m[32m int flags;[m [32m+[m[32m// iBool selecting;[m iRangecc selectMark;[m iRangecc foundMark;[m int pageMargin;[m [36m@@ -183,21 +190,22 @@[m [mstruct Impl_DocumentWidget {[m int playerTimer;[m const iGmRun * hoverLink;[m const iGmRun * contextLink;[m [31m- iBool noHoverWhileScrolling;[m [31m- iBool showLinkNumbers;[m [32m+[m[32m// iBool noHoverWhileScrolling;[m [32m+[m[32m// iBool showLinkNumbers;[m const iGmRun * firstVisibleRun;[m const iGmRun * lastVisibleRun;[m iClick click;[m float initNormScrollY;[m [31m- int scrollY;[m [31m- iScrollWidget *scroll;[m [31m- int smoothScroll;[m [31m- int smoothSpeed;[m [31m- int smoothLastOffset;[m [31m- iBool smoothContinue;[m [32m+[m[32m// int scrollY;[m [32m+[m[32m// int smoothScroll;[m [32m+[m[32m// int smoothSpeed;[m [32m+[m[32m// int smoothLastOffset;[m [32m+[m[32m// iBool smoothContinue;[m [32m+[m[32m iAnim scrollY;[m iAnim sideOpacity;[m iAnim outlineOpacity;[m iArray outline;[m [32m+[m[32m iScrollWidget *scroll;[m iWidget * menu;[m iWidget * playerMenu;[m iVisBuf * visBuf;[m [36m@@ -223,19 +231,20 @@[m [mvoid init_DocumentWidget(iDocumentWidget *d) {[m d->doc = new_GmDocument();[m d->redirectCount = 0;[m d->initNormScrollY = 0;[m [31m- d->scrollY = 0;[m [31m- d->smoothScroll = 0;[m [31m- d->smoothSpeed = 0;[m [31m- d->smoothLastOffset = 0;[m [31m- d->smoothContinue = iFalse;[m [31m- d->selecting = iFalse;[m [32m+[m[32m init_Anim(&d->scrollY, 0);[m [32m+[m[32m// d->scrollY = 0;[m [32m+[m[32m// d->smoothScroll = 0;[m [32m+[m[32m// d->smoothSpeed = 0;[m [32m+[m[32m// d->smoothLastOffset = 0;[m [32m+[m[32m// d->smoothContinue = iFalse;[m [32m+[m[32m d->flags = 0;[m d->selectMark = iNullRange;[m d->foundMark = iNullRange;[m d->pageMargin = 5;[m d->hoverLink = NULL;[m d->contextLink = NULL;[m [31m- d->noHoverWhileScrolling = iFalse;[m [31m- d->showLinkNumbers = iFalse;[m [32m+[m[32m// d->noHoverWhileScrolling = iFalse;[m [32m+[m[32m// d->showLinkNumbers = iFalse;[m d->firstVisibleRun = NULL;[m d->lastVisibleRun = NULL;[m d->visBuf = new_VisBuf();[m [36m@@ -298,13 +307,6 @@[m [mstatic void requestFinished_DocumentWidget_(iAnyObject *obj) {[m postCommand_Widget(obj, "document.request.finished doc:%p request:%p", d, d->request);[m }[m [m [31m-static void resetSmoothScroll_DocumentWidget_(iDocumentWidget *d) {[m [31m- d->smoothSpeed = 0;[m [31m- d->smoothScroll = 0;[m [31m- d->smoothLastOffset = 0;[m [31m- d->smoothContinue = iFalse;[m [31m-}[m [31m-[m static int documentWidth_DocumentWidget_(const iDocumentWidget *d) {[m const iWidget *w = constAs_Widget(d);[m const iRect bounds = bounds_Widget(w);[m [36m@@ -345,13 +347,15 @@[m [mstatic int forceBreakWidth_DocumentWidget_(const iDocumentWidget *d) {[m }[m [m static iInt2 documentPos_DocumentWidget_(const iDocumentWidget *d, iInt2 pos) {[m [31m- return addY_I2(sub_I2(pos, topLeft_Rect(documentBounds_DocumentWidget_(d))), d->scrollY);[m [32m+[m[32m return addY_I2(sub_I2(pos, topLeft_Rect(documentBounds_DocumentWidget_(d))),[m [32m+[m[32m value_Anim(&d->scrollY));[m }[m [m static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) {[m const int margin = !hasSiteBanner_GmDocument(d->doc) ? gap_UI * d->pageMargin : 0;[m [31m- return (iRangei){ d->scrollY - margin,[m [31m- d->scrollY + height_Rect(bounds_Widget(constAs_Widget(d))) - margin };[m [32m+[m[32m return (iRangei){ value_Anim(&d->scrollY) - margin,[m [32m+[m[32m value_Anim(&d->scrollY) + height_Rect(bounds_Widget(constAs_Widget(d))) -[m [32m+[m[32m margin };[m }[m [m static void addVisible_DocumentWidget_(void *context, const iGmRun *run) {[m [36m@@ -373,7 +377,7 @@[m [mstatic void addVisible_DocumentWidget_(void *context, const iGmRun *run) {[m static float normScrollPos_DocumentWidget_(const iDocumentWidget *d) {[m const int docSize = size_GmDocument(d->doc).y;[m if (docSize) {[m [31m- return (float) d->scrollY / (float) docSize;[m [32m+[m[32m return value_Anim(&d->scrollY) / (float) docSize;[m }[m return 0;[m }[m [36m@@ -398,8 +402,8 @@[m [mstatic void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) {[m const iRect docBounds = documentBounds_DocumentWidget_(d);[m const iGmRun * oldHoverLink = d->hoverLink;[m d->hoverLink = NULL;[m [31m- const iInt2 hoverPos = addY_I2(sub_I2(mouse, topLeft_Rect(docBounds)), d->scrollY);[m [31m- if (isHover_Widget(w) && !d->noHoverWhileScrolling &&[m [32m+[m[32m const iInt2 hoverPos = addY_I2(sub_I2(mouse, topLeft_Rect(docBounds)), value_Anim(&d->scrollY));[m [32m+[m[32m if (isHover_Widget(w) && (~d->flags & noHoverWhileScrolling_DocumentWidgetFlag) &&[m (d->state == ready_RequestState || d->state == receivedPartialResponse_RequestState)) {[m iConstForEach(PtrArray, i, &d->visibleLinks) {[m const iGmRun *run = i.ptr;[m [36m@@ -438,7 +442,7 @@[m [mstatic void animate_DocumentWidget_(void *ticker) {[m static void updateSideOpacity_DocumentWidget_(iDocumentWidget *d, iBool isAnimated) {[m float opacity = 0.0f;[m const iGmRun *banner = siteBanner_GmDocument(d->doc);[m [31m- if (banner && bottom_Rect(banner->visBounds) < d->scrollY) {[m [32m+[m[32m if (banner && bottom_Rect(banner->visBounds) < value_Anim(&d->scrollY)) {[m opacity = 1.0f;[m }[m setValue_Anim(&d->sideOpacity, opacity, isAnimated ? (opacity < 0.5f ? 100 : 200) : 0);[m [36m@@ -519,7 +523,7 @@[m [mstatic void updateVisible_DocumentWidget_(iDocumentWidget *d) {[m setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_DocumentWidget_(d) });[m const int docSize = size_GmDocument(d->doc).y;[m setThumb_ScrollWidget(d->scroll,[m [31m- d->scrollY,[m [32m+[m[32m value_Anim(&d->scrollY),[m docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0);[m clear_PtrArray(&d->visibleLinks);[m clear_PtrArray(&d->visiblePlayers);[m [36m@@ -709,8 +713,7 @@[m [mstatic void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode[m }[m }[m setSource_DocumentWidget_(d, src);[m [31m- resetSmoothScroll_DocumentWidget_(d);[m [31m- d->scrollY = 0;[m [32m+[m[32m init_Anim(&d->scrollY, 0);[m init_Anim(&d->sideOpacity, 0);[m d->state = ready_RequestState;[m }[m [36m@@ -912,7 +915,7 @@[m [mstatic iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) {[m d->sourceTime = resp->when;[m set_Block(&d->sourceContent, &resp->body);[m updateDocument_DocumentWidget_(d, resp, iTrue);[m [31m- d->scrollY = d->initNormScrollY * size_GmDocument(d->doc).y;[m [32m+[m[32m init_Anim(&d->scrollY, d->initNormScrollY * size_GmDocument(d->doc).y);[m d->state = ready_RequestState;[m updateSideOpacity_DocumentWidget_(d, iFalse);[m updateOutline_DocumentWidget_(d);[m [36m@@ -926,62 +929,72 @@[m [mstatic iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) {[m return iFalse;[m }[m [m [31m-static void scroll_DocumentWidget_(iDocumentWidget *d, int offset) {[m [31m- d->scrollY += offset;[m [31m- if (d->scrollY < 0) {[m [31m- d->scrollY = 0;[m [32m+[m[32mstatic void refreshWhileScrolling_DocumentWidget_(iAny *ptr) {[m [32m+[m[32m iDocumentWidget *d = ptr;[m [32m+[m[32m// if (isFinished_Anim(&d-> isSmoothScrolling_DocumentWidget_(d)) {[m [32m+[m[32m// return; /* was cancelled */[m [32m+[m[32m// }[m [32m+[m[32m// const double elapsed = (double) elapsedSinceLastTicker_App() / 1000.0;[m [32m+[m[32m// int delta = d->smoothSpeed * elapsed * iSign(d->smoothScroll);[m [32m+[m[32m// if (iAbs(d->smoothScroll) <= iAbs(delta)) {[m [32m+[m[32m// if (d->smoothContinue) {[m [32m+[m[32m// d->smoothScroll += d->smoothLastOffset;[m [32m+[m[32m// }[m [32m+[m[32m// else {[m [32m+[m[32m// delta = d->smoothScroll;[m [32m+[m[32m// }[m [32m+[m[32m// }[m [32m+[m[32m updateVisible_DocumentWidget_(d);[m [32m+[m[32m refresh_Widget(d);[m [32m+[m[32m// scroll_DocumentWidget_(d, delta);[m [32m+[m[32m// d->smoothScroll -= delta;[m [32m+[m[32m if (!isFinished_Anim(&d->scrollY)) {[m [32m+[m[32m addTicker_App(refreshWhileScrolling_DocumentWidget_, d);[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void smoothScroll_DocumentWidget_(iDocumentWidget *d, int offset, int duration) {[m [32m+[m[32m int destY = targetValue_Anim(&d->scrollY) + offset;[m [32m+[m[32m// d->scrollY += offset;[m [32m+[m[32m if (destY < 0) {[m [32m+[m[32m destY = 0;[m }[m const int scrollMax = scrollMax_DocumentWidget_(d);[m if (scrollMax > 0) {[m [31m- d->scrollY = iMin(d->scrollY, scrollMax);[m [32m+[m[32m destY = iMin(destY, scrollMax);[m }[m else {[m [31m- d->scrollY = 0;[m [32m+[m[32m destY = 0;[m }[m [32m+[m[32m setValueEased_Anim(&d->scrollY, destY, duration);[m updateVisible_DocumentWidget_(d);[m refresh_Widget(as_Widget(d));[m [31m-}[m [31m-[m [31m-static iBool isSmoothScrolling_DocumentWidget_(const iDocumentWidget *d) {[m [31m- return d->smoothScroll != 0;[m [31m-}[m [m [31m-static void doScroll_DocumentWidget_(iAny *ptr) {[m [31m- iDocumentWidget *d = ptr;[m [31m- if (!isSmoothScrolling_DocumentWidget_(d)) {[m [31m- return; /* was cancelled */[m [31m- }[m [31m- const double elapsed = (double) elapsedSinceLastTicker_App() / 1000.0;[m [31m- int delta = d->smoothSpeed * elapsed * iSign(d->smoothScroll);[m [31m- if (iAbs(d->smoothScroll) <= iAbs(delta)) {[m [31m- if (d->smoothContinue) {[m [31m- d->smoothScroll += d->smoothLastOffset;[m [31m- }[m [31m- else {[m [31m- delta = d->smoothScroll;[m [31m- }[m [31m- }[m [31m- scroll_DocumentWidget_(d, delta);[m [31m- d->smoothScroll -= delta;[m [31m- if (isSmoothScrolling_DocumentWidget_(d)) {[m [31m- addTicker_App(doScroll_DocumentWidget_, d);[m [32m+[m[32m // if (speed == 0) {[m [32m+[m[32m// scroll_DocumentWidget_(d, offset);[m [32m+[m[32m// return;[m [32m+[m[32m// }[m [32m+[m[32m// d->smoothSpeed = speed;[m [32m+[m[32m// d->smoothScroll += offset;[m [32m+[m[32m// d->smoothLastOffset = offset;[m [32m+[m[32m if (duration > 0) {[m [32m+[m[32m iChangeFlags(d->flags, noHoverWhileScrolling_DocumentWidgetFlag, iTrue);[m [32m+[m[32m addTicker_App(refreshWhileScrolling_DocumentWidget_, d);[m }[m }[m [m [31m-static void smoothScroll_DocumentWidget_(iDocumentWidget *d, int offset, int speed) {[m [31m- if (speed == 0) {[m [31m- scroll_DocumentWidget_(d, offset);[m [31m- return;[m [31m- }[m [31m- d->smoothSpeed = speed;[m [31m- d->smoothScroll += offset;[m [31m- d->smoothLastOffset = offset;[m [31m- addTicker_App(doScroll_DocumentWidget_, d);[m [32m+[m[32mstatic void scroll_DocumentWidget_(iDocumentWidget *d, int offset) {[m [32m+[m[32m smoothScroll_DocumentWidget_(d, offset, 0 /* instant */);[m }[m [m [32m+[m[32m//static iBool isSmoothScrolling_DocumentWidget_(const iDocumentWidget *d) {[m [32m+[m[32m// return d->smoothScroll != 0;[m [32m+[m[32m//}[m [32m+[m static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY, iBool centered) {[m [31m- d->scrollY = documentY - (centered ? documentBounds_DocumentWidget_(d).size.y / 2 :[m [31m- lineHeight_Text(paragraph_FontId));[m [32m+[m[32m init_Anim(&d->scrollY,[m [32m+[m[32m documentY - (centered ? documentBounds_DocumentWidget_(d).size.y / 2[m [32m+[m[32m : lineHeight_Text(paragraph_FontId)));[m scroll_DocumentWidget_(d, 0); /* clamp it */[m }[m [m [36m@@ -1016,8 +1029,7 @@[m [mstatic void checkResponse_DocumentWidget_(iDocumentWidget *d) {[m break;[m }[m case categorySuccess_GmStatusCode:[m [31m- d->scrollY = 0;[m [31m- resetSmoothScroll_DocumentWidget_(d);[m [32m+[m[32m init_Anim(&d->scrollY, 0);[m reset_GmDocument(d->doc); /* new content incoming */[m updateDocument_DocumentWidget_(d, response_GmRequest(d->request), iTrue);[m break;[m [36m@@ -1212,6 +1224,8 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed")) {[m const iGmRun *mid = middleRun_DocumentWidget_(d);[m const char *midLoc = (mid ? mid->text.start : NULL);[m [32m+[m[32m /* Alt/Option key may be involved in window size changes. */[m [32m+[m[32m iChangeFlags(d->flags, showLinkNumbers_DocumentWidgetFlag, iFalse);[m setWidth_GmDocument([m d->doc, documentWidth_DocumentWidget_(d), forceBreakWidth_DocumentWidget_(d));[m scroll_DocumentWidget_(d, 0);[m [36m@@ -1240,7 +1254,7 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m updateSize_DocumentWidget(d);[m }[m else if (equal_Command(cmd, "tabs.changed")) {[m [31m- d->showLinkNumbers = iFalse;[m [32m+[m[32m iChangeFlags(d->flags, showLinkNumbers_DocumentWidgetFlag, iFalse);[m if (cmp_String(id_Widget(w), suffixPtr_Command(cmd, "id")) == 0) {[m /* Set palette for our document. */[m updateTheme_DocumentWidget_(d);[m [36m@@ -1345,8 +1359,7 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m set_Block(&d->sourceContent, body_GmRequest(d->request));[m updateFetchProgress_DocumentWidget_(d);[m checkResponse_DocumentWidget_(d);[m [31m- resetSmoothScroll_DocumentWidget_(d);[m [31m- d->scrollY = d->initNormScrollY * size_GmDocument(d->doc).y;[m [32m+[m[32m init_Anim(&d->scrollY, d->initNormScrollY * size_GmDocument(d->doc).y);[m d->state = ready_RequestState;[m /* The response may be cached. */ {[m if (!equal_Rangecc(urlScheme_String(d->mod.url), "about") &&[m [36m@@ -1496,25 +1509,24 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m return iTrue;[m }[m else if (equalWidget_Command(cmd, w, "scroll.moved")) {[m [31m- d->scrollY = arg_Command(cmd);[m [31m- resetSmoothScroll_DocumentWidget_(d);[m [32m+[m[32m init_Anim(&d->scrollY, arg_Command(cmd));[m updateVisible_DocumentWidget_(d);[m return iTrue;[m }[m else if (equalWidget_Command(cmd, w, "scroll.page")) {[m if (argLabel_Command(cmd, "repeat")) {[m [31m- if (!d->smoothContinue) {[m [31m- d->smoothContinue = iTrue;[m [31m- }[m [31m- else {[m [31m- return iTrue;[m [31m- }[m [32m+[m[32m// if (!d->smoothContinue) {[m [32m+[m[32m// d->smoothContinue = iTrue;[m [32m+[m[32m// }[m [32m+[m[32m// else {[m [32m+[m[32m// return iTrue;[m [32m+[m[32m// }[m }[m smoothScroll_DocumentWidget_(d,[m arg_Command(cmd) *[m (0.5f * height_Rect(documentBounds_DocumentWidget_(d)) -[m 0 * lineHeight_Text(paragraph_FontId)),[m [31m- 25 * smoothSpeed_DocumentWidget_);[m [32m+[m[32m smoothDuration_DocumentWidget_);[m return iTrue;[m }[m else if (equal_Command(cmd, "document.goto") && document_App() == d) {[m [36m@@ -1584,7 +1596,7 @@[m [mstatic size_t visibleLinkOrdinal_DocumentWidget_(const iDocumentWidget *d, iGmLi[m [m static iRect playerRect_DocumentWidget_(const iDocumentWidget *d, const iGmRun *run) {[m const iRect docBounds = documentBounds_DocumentWidget_(d);[m [31m- return moved_Rect(run->bounds, addY_I2(topLeft_Rect(docBounds), -d->scrollY));[m [32m+[m[32m return moved_Rect(run->bounds, addY_I2(topLeft_Rect(docBounds), -value_Anim(&d->scrollY)));[m }[m [m static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) {[m [36m@@ -1707,7 +1719,7 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m case SDLK_LALT:[m case SDLK_RALT:[m if (document_App() == d) {[m [31m- d->showLinkNumbers = iFalse;[m [32m+[m[32m iChangeFlags(d->flags, showLinkNumbers_DocumentWidgetFlag, iFalse);[m invalidate_DocumentWidget_(d);[m refresh_Widget(w);[m }[m [36m@@ -1717,15 +1729,15 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m case SDLK_SPACE:[m case SDLK_UP:[m case SDLK_DOWN:[m [31m- d->smoothContinue = iFalse;[m [32m+[m[32m// d->smoothContinue = iFalse;[m break;[m }[m }[m if (ev->type == SDL_KEYDOWN) {[m const int mods = keyMods_Sym(ev->key.keysym.mod);[m [31m- const int key = ev->key.keysym.sym;[m [31m- if (d->showLinkNumbers && ((key >= '1' && key <= '9') ||[m [31m- (key >= 'a' && key <= 'z'))) {[m [32m+[m[32m const int key = ev->key.keysym.sym;[m [32m+[m[32m if ((d->flags & showLinkNumbers_DocumentWidgetFlag) &&[m [32m+[m[32m ((key >= '1' && key <= '9') || (key >= 'a' && key <= 'z'))) {[m const size_t ord = isdigit(key) ? key - SDLK_1 : (key - 'a' + 9);[m iConstForEach(PtrArray, i, &d->visibleLinks) {[m const iGmRun *run = i.ptr;[m [36m@@ -1742,23 +1754,21 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m case SDLK_LALT:[m case SDLK_RALT:[m if (document_App() == d) {[m [31m- d->showLinkNumbers = iTrue;[m [32m+[m[32m iChangeFlags(d->flags, showLinkNumbers_DocumentWidgetFlag, iTrue);[m invalidate_DocumentWidget_(d);[m refresh_Widget(w);[m }[m break;[m case SDLK_HOME:[m [31m- d->scrollY = 0;[m [32m+[m[32m init_Anim(&d->scrollY, 0);[m invalidate_VisBuf(d->visBuf);[m [31m- resetSmoothScroll_DocumentWidget_(d);[m scroll_DocumentWidget_(d, 0);[m updateVisible_DocumentWidget_(d);[m refresh_Widget(w);[m return iTrue;[m case SDLK_END:[m [31m- d->scrollY = scrollMax_DocumentWidget_(d);[m [32m+[m[32m init_Anim(&d->scrollY, scrollMax_DocumentWidget_(d));[m invalidate_VisBuf(d->visBuf);[m [31m- resetSmoothScroll_DocumentWidget_(d);[m scroll_DocumentWidget_(d, 0);[m updateVisible_DocumentWidget_(d);[m refresh_Widget(w);[m [36m@@ -1767,15 +1777,15 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m case SDLK_DOWN:[m if (mods == 0) {[m if (ev->key.repeat) {[m [31m- if (!d->smoothContinue) {[m [31m- d->smoothContinue = iTrue;[m [31m- }[m [31m- else return iTrue;[m [32m+[m[32m// if (!d->smoothContinue) {[m [32m+[m[32m// d->smoothContinue = iTrue;[m [32m+[m[32m// }[m [32m+[m[32m// else return iTrue;[m }[m smoothScroll_DocumentWidget_(d,[m 3 * lineHeight_Text(paragraph_FontId) *[m (key == SDLK_UP ? -1 : 1),[m [31m- gap_Text * smoothSpeed_DocumentWidget_);[m [32m+[m[32m /*gap_Text * */smoothDuration_DocumentWidget_);[m return iTrue;[m }[m break;[m [36m@@ -1825,6 +1835,7 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m }[m #if defined (iPlatformApple)[m /* Momentum scrolling. */[m [32m+[m[32m stop_Anim(&d->scrollY);[m scroll_DocumentWidget_(d, -ev->wheel.y * get_Window()->pixelRatio * acceleration);[m #else[m if (keyMods_Sym(SDL_GetModState()) == KMOD_PRIMARY) {[m [36m@@ -1834,14 +1845,14 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m smoothScroll_DocumentWidget_([m d,[m -3 * ev->wheel.y * lineHeight_Text(paragraph_FontId) * acceleration,[m [31m- gap_Text * smoothSpeed_DocumentWidget_ +[m [31m- (isSmoothScrolling_DocumentWidget_(d) ? d->smoothSpeed : 0));[m [32m+[m[32m smoothDuration_DocumentWidget_); /* +[m [32m+[m[32m (isSmoothScrolling_DocumentWidget_(d) ? d->smoothSpeed : 0)); */[m #endif[m [31m- d->noHoverWhileScrolling = iTrue;[m [32m+[m[32m iChangeFlags(d->flags, noHoverWhileScrolling_DocumentWidgetFlag, iTrue);[m return iTrue;[m }[m else if (ev->type == SDL_MOUSEMOTION) {[m [31m- d->noHoverWhileScrolling = iFalse;[m [32m+[m[32m iChangeFlags(d->flags, noHoverWhileScrolling_DocumentWidgetFlag, iFalse);[m if (isVisible_Widget(d->menu)) {[m setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW);[m }[m [36m@@ -1926,7 +1937,7 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m }[m switch (processEvent_Click(&d->click, ev)) {[m case started_ClickResult:[m [31m- d->selecting = iFalse;[m [32m+[m[32m iChangeFlags(d->flags, selecting_DocumentWidgetFlag, iFalse);[m return iTrue;[m case drag_ClickResult: {[m if (d->grabbedPlayer) {[m [36m@@ -1940,9 +1951,9 @@[m [mstatic iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e[m return iTrue;[m }[m /* Begin selecting a range of text. */[m [31m- if (!d->selecting) {[m [32m+[m[32m if (~d->flags & selecting_DocumentWidgetFlag) {[m setFocus_Widget(NULL); /* TODO: Focus this document? */[m [31m- d->selecting = iTrue;[m [32m+[m[32m iChangeFlags(d->flags, selecting_DocumentWidgetFlag, iTrue);[m d->selectMark.start = d->selectMark.end =[m sourceLoc_DocumentWidget_(d, d->click.startPos);[m refresh_Widget(w);[m [36m@@ -2086,7 +2097,8 @@[m [mstatic void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol[m if (w > width_Rect(run->visBounds) - x) {[m w = width_Rect(run->visBounds) - x;[m }[m [31m- const iInt2 visPos = add_I2(run->bounds.pos, addY_I2(d->viewPos, -d->widget->scrollY));[m [32m+[m[32m const iInt2 visPos =[m [32m+[m[32m add_I2(run->bounds.pos, addY_I2(d->viewPos, -value_Anim(&d->widget->scrollY)));[m fillRect_Paint(&d->paint, (iRect){ addX_I2(visPos, x),[m init_I2(w, height_Rect(run->bounds)) }, color);[m }[m [36m@@ -2383,13 +2395,15 @@[m [mstatic void drawSideElements_DocumentWidget_(const iDocumentWidget *d) {[m collect_String(format_Time(&d->sourceTime, "Received at %I:%M %p\non %b %d, %Y"));[m const iInt2 size = advanceRange_Text(font, range_String(recv));[m if (size.x <= avail) {[m [31m- drawString_Text(font,[m [31m- add_I2(bottomLeft_Rect(bounds),[m [31m- init_I2(margin,[m [31m- -margin + -size.y +[m [31m- iMax(0, scrollMax_DocumentWidget_(d) - d->scrollY))),[m [31m- tmQuoteIcon_ColorId,[m [31m- recv);[m [32m+[m[32m drawString_Text([m [32m+[m[32m font,[m [32m+[m[32m add_I2([m [32m+[m[32m bottomLeft_Rect(bounds),[m [32m+[m[32m init_I2(margin,[m [32m+[m[32m -margin + -size.y +[m [32m+[m[32m iMax(0, scrollMax_DocumentWidget_(d) - value_Anim(&d->scrollY)))),[m [32m+[m[32m tmQuoteIcon_ColorId,[m [32m+[m[32m recv);[m }[m }[m /* Outline on the right side. */[m [36m@@ -2402,9 +2416,9 @@[m [mstatic void drawSideElements_DocumentWidget_(const iDocumentWidget *d) {[m const int scrollMax = scrollMax_DocumentWidget_(d);[m const int outHeight = outlineHeight_DocumentWidget_(d);[m const int oversize = outHeight - height_Rect(bounds) + topMargin + bottomMargin;[m [31m- const int scroll =[m [31m- (oversize > 0 && scrollMax > 0 ? oversize * d->scrollY / scrollMax_DocumentWidget_(d)[m [31m- : 0);[m [32m+[m[32m const int scroll = (oversize > 0 && scrollMax > 0[m [32m+[m[32m ? oversize * value_Anim(&d->scrollY) / scrollMax_DocumentWidget_(d)[m [32m+[m[32m : 0);[m iInt2 pos =[m add_I2(topRight_Rect(bounds), init_I2(-outWidth - width_Widget(d->scroll), topMargin));[m /* Center short outlines vertically. */[m [36m@@ -2471,7 +2485,7 @@[m [mstatic void draw_DocumentWidget_(const iDocumentWidget *d) {[m const iRect docBounds = documentBounds_DocumentWidget_(d);[m iDrawContext ctx = {[m .widget = d,[m [31m- .showLinkNumbers = d->showLinkNumbers,[m [32m+[m[32m .showLinkNumbers = (d->flags & showLinkNumbers_DocumentWidgetFlag) != 0,[m };[m /* Currently visible region. */[m const iRangei vis = visibleRange_DocumentWidget_(d);[m [36m@@ -2524,7 +2538,7 @@[m [mstatic void draw_DocumentWidget_(const iDocumentWidget *d) {[m clear_PtrSet(d->invalidRuns);[m }[m setClip_Paint(&ctx.paint, bounds);[m [31m- const int yTop = docBounds.pos.y - d->scrollY;[m [32m+[m[32m const int yTop = docBounds.pos.y - value_Anim(&d->scrollY);[m draw_VisBuf(visBuf, init_I2(bounds.pos.x, yTop));[m /* Text markers. */[m if (!isEmpty_Range(&d->foundMark) || !isEmpty_Range(&d->selectMark)) {[m [1mdiff --git a/src/ui/util.c b/src/ui/util.c[m [1mindex bef839dc..38124b22 100644[m [1m--- a/src/ui/util.c[m [1m+++ b/src/ui/util.c[m [36m@@ -135,8 +135,9 @@[m [miBool isFinished_Anim(const iAnim *d) {[m }[m [m void init_Anim(iAnim *d, float value) {[m [31m- d->due = d->when = frameTime_Window(get_Window());[m [32m+[m[32m d->due = d->when = SDL_GetTicks(); // frameTime_Window(get_Window());[m d->from = d->to = value;[m [32m+[m[32m d->flags = 0;[m }[m [m void setValue_Anim(iAnim *d, float to, uint32_t span) {[m [36m@@ -149,6 +150,54 @@[m [mvoid setValue_Anim(iAnim *d, float to, uint32_t span) {[m }[m }[m [m [32m+[m[32miLocalDef float pos_Anim_(const iAnim *d, uint32_t now) {[m [32m+[m[32m return (float) (now - d->when) / (float) (d->due - d->when);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mvoid setValueEased_Anim(iAnim *d, float to, uint32_t span) {[m [32m+[m[32m if (fabsf(to - d->to) <= 0.00001f) {[m [32m+[m[32m d->to = to; /* Pretty much unchanged. */[m [32m+[m[32m return;[m [32m+[m[32m }[m [32m+[m[32m const uint32_t now = SDL_GetTicks();[m [32m+[m[32m if (isFinished_Anim(d)) {[m [32m+[m[32m d->from = d->to;[m [32m+[m[32m d->when = now;[m [32m+[m[32m d->flags = easeBoth_AnimFlag;[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m d->from = value_Anim(d);[m [32m+[m[32m d->when = frameTime_Window(get_Window()); /* to match the timing of value_Anim */[m [32m+[m[32m d->flags = easeOut_AnimFlag;[m [32m+[m[32m }[m [32m+[m[32m d->to = to;[m [32m+[m[32m d->due = now + span;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mvoid setFlags_Anim(iAnim *d, int flags, iBool set) {[m [32m+[m[32m iChangeFlags(d->flags, flags, set);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mvoid stop_Anim(iAnim *d) {[m [32m+[m[32m d->from = d->to = value_Anim(d);[m [32m+[m[32m d->when = d->due = SDL_GetTicks();[m [32m+[m[32m}[m [32m+[m [32m+[m[32miLocalDef float easeIn_(float t) {[m [32m+[m[32m return t * t;[m [32m+[m[32m}[m [32m+[m [32m+[m[32miLocalDef float easeOut_(float t) {[m [32m+[m[32m return t * (2.0f - t);[m [32m+[m[32m}[m [32m+[m [32m+[m[32miLocalDef float easeBoth_(float t) {[m [32m+[m[32m if (t < 0.5f) {[m [32m+[m[32m return easeIn_(t * 2.0f) * 0.5f;[m [32m+[m[32m }[m [32m+[m[32m return 0.5f + easeOut_((t - 0.5f) * 2.0f) * 0.5f;[m [32m+[m[32m}[m [32m+[m float value_Anim(const iAnim *d) {[m const uint32_t now = frameTime_Window(get_Window());[m if (now >= d->due) {[m [36m@@ -157,8 +206,17 @@[m [mfloat value_Anim(const iAnim *d) {[m if (now <= d->when) {[m return d->from;[m }[m [31m- const float pos = (float) (now - d->when) / (float) (d->due - d->when);[m [31m- return d->from * (1.0f - pos) + d->to * pos;[m [32m+[m[32m float t = pos_Anim_(d, now);[m [32m+[m[32m if ((d->flags & easeBoth_AnimFlag) == easeBoth_AnimFlag) {[m [32m+[m[32m t = easeBoth_(t);[m [32m+[m[32m }[m [32m+[m[32m else if (d->flags & easeIn_AnimFlag) {[m [32m+[m[32m t = easeIn_(t);[m [32m+[m[32m }[m [32m+[m[32m else if (d->flags & easeOut_AnimFlag) {[m [32m+[m[32m t = easeOut_(t);[m [32m+[m[32m }[m [32m+[m[32m return d->from * (1.0f - t) + d->to * t;[m }[m [m /*-----------------------------------------------------------------------------------------------*/[m [1mdiff --git a/src/ui/util.h b/src/ui/util.h[m [1mindex a33bf713..c342c095 100644[m [1m--- a/src/ui/util.h[m [1m+++ b/src/ui/util.h[m [36m@@ -68,15 +68,35 @@[m [miLocalDef iBool isOverlapping_Rangei(iRangei a, iRangei b) {[m [m iDeclareType(Anim)[m [m [32m+[m[32menum iAnimFlag {[m [32m+[m[32m indefinite_AnimFlag = iBit(1), /* does not end; must be linear */[m [32m+[m[32m easeIn_AnimFlag = iBit(2),[m [32m+[m[32m easeOut_AnimFlag = iBit(3),[m [32m+[m[32m easeBoth_AnimFlag = easeIn_AnimFlag | easeOut_AnimFlag,[m [32m+[m[32m};[m [32m+[m struct Impl_Anim {[m float from, to;[m uint32_t when, due;[m [32m+[m[32m int flags;[m };[m [m [31m-void init_Anim (iAnim *, float value);[m [31m-void setValue_Anim (iAnim *, float to, uint32_t span);[m [31m-float value_Anim (const iAnim *);[m [31m-iBool isFinished_Anim (const iAnim *);[m [32m+[m[32mvoid init_Anim (iAnim *, float value);[m [32m+[m[32mvoid setValue_Anim (iAnim *, float to, uint32_t span);[m [32m+[m[32mvoid setValueLinear_Anim (iAnim *, float to, uint32_t span);[m [32m+[m[32mvoid setValueEased_Anim (iAnim *, float to, uint32_t span);[m [32m+[m[32mvoid setFlags_Anim (iAnim *, int flags, iBool set);[m [32m+[m[32mvoid stop_Anim (iAnim *);[m [32m+[m [32m+[m[32miBool isFinished_Anim (const iAnim *);[m [32m+[m[32mfloat value_Anim (const iAnim *);[m [32m+[m [32m+[m[32miLocalDef float targetValue_Anim(const iAnim *d) {[m [32m+[m[32m return d->to;[m [32m+[m[32m}[m [32m+[m[32miLocalDef iBool isLinear_Anim(const iAnim *d) {[m [32m+[m[32m return (d->flags & (easeIn_AnimFlag | easeOut_AnimFlag)) == 0;[m [32m+[m[32m}[m [m /*-----------------------------------------------------------------------------------------------*/[m [m
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).