summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-08-25 16:50:30 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-08-25 16:50:30 +0300
commit327e2fd4229bf14ef61b0aeace9c8503b183f7e9 (patch)
tree616510056dc1c91a21fe8c45204110e59fdc94a6 /src/ui/documentwidget.c
parent37d93f50a1e4c2c1d95246e2110c7bafb5ff5c89 (diff)
DocumentWidget: Smooth scrolling for keyboard
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c95
1 files changed, 89 insertions, 6 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index a36fe761..5292d3f5 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -162,6 +162,8 @@ iDefineTypeConstruction(VisBuffer)
162 162
163/*----------------------------------------------------------------------------------------------*/ 163/*----------------------------------------------------------------------------------------------*/
164 164
165static const int smoothSpeed_DocumentWidget_ = 150; /* unit: gap_Text per second */
166
165enum iRequestState { 167enum iRequestState {
166 blank_RequestState, 168 blank_RequestState,
167 fetching_RequestState, 169 fetching_RequestState,
@@ -193,6 +195,10 @@ struct Impl_DocumentWidget {
193 iClick click; 195 iClick click;
194 float initNormScrollY; 196 float initNormScrollY;
195 int scrollY; 197 int scrollY;
198 int smoothScroll;
199 int smoothSpeed;
200 int lastSmoothOffset;
201 iBool keepScrolling;
196 iScrollWidget *scroll; 202 iScrollWidget *scroll;
197 iWidget * menu; 203 iWidget * menu;
198 iVisBuffer * visBuffer; 204 iVisBuffer * visBuffer;
@@ -217,6 +223,10 @@ void init_DocumentWidget(iDocumentWidget *d) {
217 d->doc = new_GmDocument(); 223 d->doc = new_GmDocument();
218 d->initNormScrollY = 0; 224 d->initNormScrollY = 0;
219 d->scrollY = 0; 225 d->scrollY = 0;
226 d->smoothScroll = 0;
227 d->smoothSpeed = 0;
228 d->lastSmoothOffset = 0;
229 d->keepScrolling = iFalse;
220 d->selecting = iFalse; 230 d->selecting = iFalse;
221 d->selectMark = iNullRange; 231 d->selectMark = iNullRange;
222 d->foundMark = iNullRange; 232 d->foundMark = iNullRange;
@@ -254,6 +264,13 @@ void deinit_DocumentWidget(iDocumentWidget *d) {
254 deinit_Model(&d->mod); 264 deinit_Model(&d->mod);
255} 265}
256 266
267static void resetSmoothScroll_DocumentWidget_(iDocumentWidget *d) {
268 d->smoothSpeed = 0;
269 d->smoothScroll = 0;
270 d->lastSmoothOffset = 0;
271 d->keepScrolling = iFalse;
272}
273
257static int documentWidth_DocumentWidget_(const iDocumentWidget *d) { 274static int documentWidth_DocumentWidget_(const iDocumentWidget *d) {
258 const iWidget *w = constAs_Widget(d); 275 const iWidget *w = constAs_Widget(d);
259 const iRect bounds = bounds_Widget(w); 276 const iRect bounds = bounds_Widget(w);
@@ -287,9 +304,11 @@ iLocalDef int documentToWindowY_DocumentWidget_(const iDocumentWidget *d, int do
287 return docY - d->scrollY + documentBounds_DocumentWidget_(d).pos.y; 304 return docY - d->scrollY + documentBounds_DocumentWidget_(d).pos.y;
288} 305}
289 306
307#if 0
290iLocalDef int windowToDocumentY_DocumentWidget_(const iDocumentWidget *d, int localY) { 308iLocalDef int windowToDocumentY_DocumentWidget_(const iDocumentWidget *d, int localY) {
291 return localY + d->scrollY - documentBounds_DocumentWidget_(d).pos.y; 309 return localY + d->scrollY - documentBounds_DocumentWidget_(d).pos.y;
292} 310}
311#endif
293 312
294static iInt2 documentPos_DocumentWidget_(const iDocumentWidget *d, iInt2 pos) { 313static iInt2 documentPos_DocumentWidget_(const iDocumentWidget *d, iInt2 pos) {
295 return addY_I2(sub_I2(pos, topLeft_Rect(documentBounds_DocumentWidget_(d))), d->scrollY); 314 return addY_I2(sub_I2(pos, topLeft_Rect(documentBounds_DocumentWidget_(d))), d->scrollY);
@@ -500,6 +519,7 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
500 break; 519 break;
501 } 520 }
502 setSource_DocumentWidget_(d, src); 521 setSource_DocumentWidget_(d, src);
522 resetSmoothScroll_DocumentWidget_(d);
503 d->scrollY = 0; 523 d->scrollY = 0;
504 d->state = ready_RequestState; 524 d->state = ready_RequestState;
505} 525}
@@ -743,6 +763,37 @@ static void scroll_DocumentWidget_(iDocumentWidget *d, int offset) {
743 refresh_Widget(as_Widget(d)); 763 refresh_Widget(as_Widget(d));
744} 764}
745 765
766static void doScroll_DocumentWidget_(iAny *ptr) {
767 iDocumentWidget *d = ptr;
768 if (!d->smoothScroll) return; /* was cancelled */
769 const double elapsed = (double) elapsedSinceLastTicker_App() / 1000.0;
770 int delta = d->smoothSpeed * elapsed * iSign(d->smoothScroll);
771 if (iAbs(d->smoothScroll) <= iAbs(delta)) {
772 if (d->keepScrolling) {
773 d->smoothScroll += d->lastSmoothOffset;
774 }
775 else {
776 delta = d->smoothScroll;
777 }
778 }
779 scroll_DocumentWidget_(d, delta);
780 d->smoothScroll -= delta;
781 if (d->smoothScroll != 0) {
782 addTicker_App(doScroll_DocumentWidget_, d);
783 }
784}
785
786static void smoothScroll_DocumentWidget_(iDocumentWidget *d, int offset, int speed) {
787 if (speed == 0) {
788 scroll_DocumentWidget_(d, offset);
789 return;
790 }
791 d->smoothSpeed = speed;
792 d->smoothScroll += offset;
793 d->lastSmoothOffset = offset;
794 addTicker_App(doScroll_DocumentWidget_, d);
795}
796
746static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY, iBool centered) { 797static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY, iBool centered) {
747 d->scrollY = documentY - (centered ? documentBounds_DocumentWidget_(d).size.y / 2 : 798 d->scrollY = documentY - (centered ? documentBounds_DocumentWidget_(d).size.y / 2 :
748 lineHeight_Text(paragraph_FontId)); 799 lineHeight_Text(paragraph_FontId));
@@ -780,6 +831,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
780 } 831 }
781 case categorySuccess_GmStatusCode: 832 case categorySuccess_GmStatusCode:
782 d->scrollY = 0; 833 d->scrollY = 0;
834 resetSmoothScroll_DocumentWidget_(d);
783 reset_GmDocument(d->doc); /* new content incoming */ 835 reset_GmDocument(d->doc); /* new content incoming */
784 updateDocument_DocumentWidget_(d, response_GmRequest(d->request)); 836 updateDocument_DocumentWidget_(d, response_GmRequest(d->request));
785 break; 837 break;
@@ -1076,6 +1128,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1076 else if (equalWidget_Command(cmd, w, "document.request.finished") && 1128 else if (equalWidget_Command(cmd, w, "document.request.finished") &&
1077 pointerLabel_Command(cmd, "request") == d->request) { 1129 pointerLabel_Command(cmd, "request") == d->request) {
1078 checkResponse_DocumentWidget_(d); 1130 checkResponse_DocumentWidget_(d);
1131 resetSmoothScroll_DocumentWidget_(d);
1079 d->scrollY = d->initNormScrollY * size_GmDocument(d->doc).y; 1132 d->scrollY = d->initNormScrollY * size_GmDocument(d->doc).y;
1080 d->state = ready_RequestState; 1133 d->state = ready_RequestState;
1081 /* The response may be cached. */ { 1134 /* The response may be cached. */ {
@@ -1123,12 +1176,24 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1123 } 1176 }
1124 else if (equalWidget_Command(cmd, w, "scroll.moved")) { 1177 else if (equalWidget_Command(cmd, w, "scroll.moved")) {
1125 d->scrollY = arg_Command(cmd); 1178 d->scrollY = arg_Command(cmd);
1179 resetSmoothScroll_DocumentWidget_(d);
1126 updateVisible_DocumentWidget_(d); 1180 updateVisible_DocumentWidget_(d);
1127 return iTrue; 1181 return iTrue;
1128 } 1182 }
1129 else if (equalWidget_Command(cmd, w, "scroll.page")) { 1183 else if (equalWidget_Command(cmd, w, "scroll.page")) {
1130 scroll_DocumentWidget_(d, 1184 if (argLabel_Command(cmd, "repeat")) {
1131 arg_Command(cmd) * height_Rect(documentBounds_DocumentWidget_(d))); 1185 if (!d->keepScrolling) {
1186 d->keepScrolling = iTrue;
1187 }
1188 else {
1189 return iTrue;
1190 }
1191 }
1192 smoothScroll_DocumentWidget_(d,
1193 arg_Command(cmd) *
1194 (0.5f * height_Rect(documentBounds_DocumentWidget_(d)) -
1195 0 * lineHeight_Text(paragraph_FontId)),
1196 15 * smoothSpeed_DocumentWidget_);
1132 return iTrue; 1197 return iTrue;
1133 } 1198 }
1134 else if (equal_Command(cmd, "document.goto") && document_App() == d) { 1199 else if (equal_Command(cmd, "document.goto") && document_App() == d) {
@@ -1211,6 +1276,13 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
1211 refresh_Widget(w); 1276 refresh_Widget(w);
1212 } 1277 }
1213 break; 1278 break;
1279 case SDLK_PAGEUP:
1280 case SDLK_PAGEDOWN:
1281 case SDLK_SPACE:
1282 case SDLK_UP:
1283 case SDLK_DOWN:
1284 d->keepScrolling = iFalse;
1285 break;
1214 } 1286 }
1215 } 1287 }
1216 if (ev->type == SDL_KEYDOWN) { 1288 if (ev->type == SDL_KEYDOWN) {
@@ -1241,12 +1313,14 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
1241 break; 1313 break;
1242 case SDLK_HOME: 1314 case SDLK_HOME:
1243 d->scrollY = 0; 1315 d->scrollY = 0;
1316 resetSmoothScroll_DocumentWidget_(d);
1244 scroll_DocumentWidget_(d, 0); 1317 scroll_DocumentWidget_(d, 0);
1245 updateVisible_DocumentWidget_(d); 1318 updateVisible_DocumentWidget_(d);
1246 refresh_Widget(w); 1319 refresh_Widget(w);
1247 return iTrue; 1320 return iTrue;
1248 case SDLK_END: 1321 case SDLK_END:
1249 d->scrollY = scrollMax_DocumentWidget_(d); 1322 d->scrollY = scrollMax_DocumentWidget_(d);
1323 resetSmoothScroll_DocumentWidget_(d);
1250 scroll_DocumentWidget_(d, 0); 1324 scroll_DocumentWidget_(d, 0);
1251 updateVisible_DocumentWidget_(d); 1325 updateVisible_DocumentWidget_(d);
1252 refresh_Widget(w); 1326 refresh_Widget(w);
@@ -1254,8 +1328,16 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
1254 case SDLK_UP: 1328 case SDLK_UP:
1255 case SDLK_DOWN: 1329 case SDLK_DOWN:
1256 if (mods == 0) { 1330 if (mods == 0) {
1257 scroll_DocumentWidget_(d, 2 * lineHeight_Text(default_FontId) * 1331 if (ev->key.repeat) {
1258 (key == SDLK_UP ? -1 : 1)); 1332 if (!d->keepScrolling) {
1333 d->keepScrolling = iTrue;
1334 }
1335 else return iTrue;
1336 }
1337 smoothScroll_DocumentWidget_(d,
1338 3 * lineHeight_Text(paragraph_FontId) *
1339 (key == SDLK_UP ? -1 : 1),
1340 gap_Text * smoothSpeed_DocumentWidget_);
1259 return iTrue; 1341 return iTrue;
1260 } 1342 }
1261 break; 1343 break;
@@ -1264,8 +1346,9 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
1264 case SDLK_SPACE: 1346 case SDLK_SPACE:
1265 postCommand_Widget( 1347 postCommand_Widget(
1266 w, 1348 w,
1267 "scroll.page arg:%d", 1349 "scroll.page arg:%d repeat:%d",
1268 (key == SDLK_SPACE && mods & KMOD_SHIFT) || key == SDLK_PAGEUP ? -1 : +1); 1350 (key == SDLK_SPACE && mods & KMOD_SHIFT) || key == SDLK_PAGEUP ? -1 : +1,
1351 ev->key.repeat != 0);
1269 return iTrue; 1352 return iTrue;
1270#if 1 1353#if 1
1271 case SDLK_KP_1: { 1354 case SDLK_KP_1: {