summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-03-07 10:24:58 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-03-07 10:25:42 +0200
commit892094fa91f064e24d9017d84228f6c781add428 (patch)
tree45c21fa52f4742578947339f810e56036b306216
parent237ea3e1a66b792c2258eebd39e7771002c5584b (diff)
Processing per-pixel scroll events
Do platform-specific processing of scroll events up front so widgets can support both types of scrolls everywhere. IssueID #166
-rw-r--r--src/app.c38
-rw-r--r--src/ui/documentwidget.c55
-rw-r--r--src/ui/listwidget.c11
-rw-r--r--src/ui/text.c13
-rw-r--r--src/ui/touch.c14
-rw-r--r--src/ui/util.h12
6 files changed, 84 insertions, 59 deletions
diff --git a/src/app.c b/src/app.c
index ada142f0..6a3dc00b 100644
--- a/src/app.c
+++ b/src/app.c
@@ -901,14 +901,40 @@ void processEvents_App(enum iAppEventMode eventMode) {
901 d->isIdling = iFalse; 901 d->isIdling = iFalse;
902#endif 902#endif
903 gotEvents = iTrue; 903 gotEvents = iTrue;
904 /* Keyboard modifier mapping. */ { 904 /* Keyboard modifier mapping. */
905 if (ev.type == SDL_KEYDOWN || ev.type == SDL_KEYUP) { 905 if (ev.type == SDL_KEYDOWN || ev.type == SDL_KEYUP) {
906 /* Track Caps Lock state as a modifier. */ 906 /* Track Caps Lock state as a modifier. */
907 if (ev.key.keysym.sym == SDLK_CAPSLOCK) { 907 if (ev.key.keysym.sym == SDLK_CAPSLOCK) {
908 setCapsLockDown_Keys(ev.key.state == SDL_PRESSED); 908 setCapsLockDown_Keys(ev.key.state == SDL_PRESSED);
909 }
910 ev.key.keysym.mod = mapMods_Keys(ev.key.keysym.mod & ~KMOD_CAPS);
911 }
912 /* Scroll events may be per-pixel or mouse wheel steps. */
913 if (ev.type == SDL_MOUSEWHEEL) {
914#if defined (iPlatformAppleDesktop)
915 /* On macOS, we handle both trackpad and mouse events. We expect SDL to identify
916 which device is sending the event. */
917 if (ev.wheel.which == 0) {
918 /* Trackpad with precise scrolling w/inertia (points). */
919 setPerPixel_MouseWheelEvent(&ev.wheel, iTrue);
920 ev.wheel.x *= -d->window->pixelRatio;
921 ev.wheel.y *= d->window->pixelRatio;
922 /* Only scroll on one axis at a time. */
923 if (iAbs(ev.wheel.x) > iAbs(ev.wheel.y)) {
924 ev.wheel.y = 0;
925 }
926 else {
927 ev.wheel.x = 0;
909 } 928 }
910 ev.key.keysym.mod = mapMods_Keys(ev.key.keysym.mod & ~KMOD_CAPS);
911 } 929 }
930 else {
931 /* Disregard wheel acceleration applied by the OS. */
932 ev.wheel.y = iSign(ev.wheel.y);
933 }
934#endif
935#if defined (iPlatformMsys)
936// ev.wheel.x = -ev.wheel.x;
937#endif
912 } 938 }
913 iBool wasUsed = processEvent_Window(d->window, &ev); 939 iBool wasUsed = processEvent_Window(d->window, &ev);
914 if (!wasUsed) { 940 if (!wasUsed) {
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 9b412783..f3083207 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -2324,37 +2324,33 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2324 /* TODO: Maybe clean this up a bit? Wheel events are used for scrolling 2324 /* TODO: Maybe clean this up a bit? Wheel events are used for scrolling
2325 but they are calculated differently based on device/mouse/trackpad. */ 2325 but they are calculated differently based on device/mouse/trackpad. */
2326 const iInt2 mouseCoord = mouseCoord_Window(get_Window()); 2326 const iInt2 mouseCoord = mouseCoord_Window(get_Window());
2327#if defined (iPlatformApple) 2327 if (isPerPixel_MouseWheelEvent(&ev->wheel)) {
2328 /* On macOS, we handle both trackpad and mouse events. We expect SDL to identify
2329 which device is sending the event. */
2330 if (ev->wheel.which == 0) { /* Trackpad with precise scrolling w/inertia. */
2331 stop_Anim(&d->scrollY); 2328 stop_Anim(&d->scrollY);
2332 iInt2 wheel = init_I2(ev->wheel.x, ev->wheel.y); 2329 iInt2 wheel = init_I2(ev->wheel.x, ev->wheel.y);
2333# if defined (iPlatformAppleMobile) 2330//# if defined (iPlatformAppleMobile)
2334 wheel.x = -wheel.x; 2331// wheel.x = -wheel.x;
2335# else 2332//# else
2336 /* Wheel mounts are in points. */ 2333// /* Wheel mounts are in points. */
2337 mulfv_I2(&wheel, get_Window()->pixelRatio); 2334// mulfv_I2(&wheel, get_Window()->pixelRatio);
2338 /* Only scroll on one axis at a time. */ 2335// /* Only scroll on one axis at a time. */
2339 if (iAbs(wheel.x) > iAbs(wheel.y)) { 2336// if (iAbs(wheel.x) > iAbs(wheel.y)) {
2340 wheel.y = 0; 2337// wheel.y = 0;
2341 } 2338// }
2342 else { 2339// else {
2343 wheel.x = 0; 2340// wheel.x = 0;
2344 } 2341// }
2345# endif 2342//# endif
2346 scroll_DocumentWidget_(d, -wheel.y); 2343 scroll_DocumentWidget_(d, -wheel.y);
2347 scrollWideBlock_DocumentWidget_(d, mouseCoord, wheel.x, 0); 2344 scrollWideBlock_DocumentWidget_(d, mouseCoord, -wheel.x, 0);
2348 } 2345 }
2349 else 2346 else {
2350#endif 2347 /* Traditional mouse wheel. */
2351 /* Traditional mouse wheel. */ { 2348//#if defined (iPlatformApple)
2352#if defined (iPlatformApple) 2349// /* Disregard wheel acceleration applied by the OS. */
2353 /* Disregard wheel acceleration applied by the OS. */ 2350// const int amount = iSign(ev->wheel.y);
2354 const int amount = iSign(ev->wheel.y); 2351//#else
2355#else
2356 const int amount = ev->wheel.y; 2352 const int amount = ev->wheel.y;
2357#endif 2353//#endif
2358 if (keyMods_Sym(modState_Keys()) == KMOD_PRIMARY) { 2354 if (keyMods_Sym(modState_Keys()) == KMOD_PRIMARY) {
2359 postCommandf_App("zoom.delta arg:%d", amount > 0 ? 10 : -10); 2355 postCommandf_App("zoom.delta arg:%d", amount > 0 ? 10 : -10);
2360 return iTrue; 2356 return iTrue;
@@ -2365,13 +2361,8 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
2365 smoothDuration_DocumentWidget_ * 2361 smoothDuration_DocumentWidget_ *
2366 /* accelerated speed for repeated wheelings */ 2362 /* accelerated speed for repeated wheelings */
2367 (!isFinished_Anim(&d->scrollY) && pos_Anim(&d->scrollY) < 0.25f ? 0.5f : 1.0f)); 2363 (!isFinished_Anim(&d->scrollY) && pos_Anim(&d->scrollY) < 0.25f ? 0.5f : 1.0f));
2368#if defined (iPlatformMsys)
2369 const int horizStep = ev->wheel.x * 3;
2370#else
2371 const int horizStep = ev->wheel.x * -3;
2372#endif
2373 scrollWideBlock_DocumentWidget_( 2364 scrollWideBlock_DocumentWidget_(
2374 d, mouseCoord, horizStep * lineHeight_Text(paragraph_FontId), 167); 2365 d, mouseCoord, -3 * ev->wheel.x * lineHeight_Text(paragraph_FontId), 167);
2375 } 2366 }
2376 iChangeFlags(d->flags, noHoverWhileScrolling_DocumentWidgetFlag, iTrue); 2367 iChangeFlags(d->flags, noHoverWhileScrolling_DocumentWidgetFlag, iTrue);
2377 return iTrue; 2368 return iTrue;
diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c
index e7b4fc22..237562ca 100644
--- a/src/ui/listwidget.c
+++ b/src/ui/listwidget.c
@@ -303,14 +303,9 @@ static iBool processEvent_ListWidget_(iListWidget *d, const SDL_Event *ev) {
303 } 303 }
304 if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { 304 if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) {
305 int amount = -ev->wheel.y; 305 int amount = -ev->wheel.y;
306#if defined (iPlatformApple) 306 if (!isPerPixel_MouseWheelEvent(&ev->wheel)) {
307# if defined (iPlatformAppleDesktop) 307 amount *= 3 * d->itemHeight;
308 /* Momentum scrolling (in points). */ 308 }
309 amount *= get_Window()->pixelRatio;
310# endif
311#else
312 amount *= 3 * d->itemHeight;
313#endif
314 scrollOffset_ListWidget(d, amount); 309 scrollOffset_ListWidget(d, amount);
315 return iTrue; 310 return iTrue;
316 } 311 }
diff --git a/src/ui/text.c b/src/ui/text.c
index f380b67b..d9ddf2b2 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -708,12 +708,13 @@ void rasterizeSomePendingGlyphs_Text(void) {
708} 708}
709 709
710enum iRunMode { 710enum iRunMode {
711 measure_RunMode = 0, 711 measure_RunMode = 0,
712 draw_RunMode = 1, 712 draw_RunMode = 1,
713 modeMask_RunMode = 0x00ff, 713 modeMask_RunMode = 0x00ff,
714 flagsMask_RunMode = 0xff00, 714 flagsMask_RunMode = 0xff00,
715 noWrapFlag_RunMode = iBit(9), 715 noWrapFlag_RunMode = iBit(9),
716 visualFlag_RunMode = iBit(10), /* actual visible bounding box of the glyph, e.g., for icons */ 716 visualFlag_RunMode = iBit(10), /* actual visible bounding box of the glyph,
717 e.g., for icons */
717 permanentColorFlag_RunMode = iBit(11), 718 permanentColorFlag_RunMode = iBit(11),
718 alwaysVariableWidthFlag_RunMode = iBit(12), 719 alwaysVariableWidthFlag_RunMode = iBit(12),
719}; 720};
diff --git a/src/ui/touch.c b/src/ui/touch.c
index 136457a5..6201b4b6 100644
--- a/src/ui/touch.c
+++ b/src/ui/touch.c
@@ -205,15 +205,15 @@ static void update_TouchState_(void *ptr) {
205 mulvf_F3(&mom->velocity, momFriction); 205 mulvf_F3(&mom->velocity, momFriction);
206 addv_F3(&mom->accum, mulf_F3(mom->velocity, stepDurationMs / 1000.0f)); 206 addv_F3(&mom->accum, mulf_F3(mom->velocity, stepDurationMs / 1000.0f));
207 } 207 }
208 const iInt2 points = initF3_I2(mom->accum); 208 const iInt2 pixels = initF3_I2(mom->accum);
209 if (points.x || points.y) { 209 if (pixels.x || pixels.y) {
210 subv_F3(&mom->accum, initI2_F3(points)); 210 subv_F3(&mom->accum, initI2_F3(pixels));
211 dispatchEvent_Widget(mom->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){ 211 dispatchEvent_Widget(mom->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){
212 .type = SDL_MOUSEWHEEL, 212 .type = SDL_MOUSEWHEEL,
213 .timestamp = nowTime, 213 .timestamp = nowTime,
214 .which = 0, /* means "precise scrolling" in DocumentWidget */ 214 .x = pixels.x,
215 .x = points.x, 215 .y = pixels.y,
216 .y = points.y 216 .direction = perPixel_MouseWheelFlag
217 }); 217 });
218 } 218 }
219 if (length_F3(mom->velocity) < minSpeed) { 219 if (length_F3(mom->velocity) < minSpeed) {
@@ -405,9 +405,9 @@ iBool processEvent_Touch(const SDL_Event *ev) {
405 dispatchEvent_Widget(touch->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){ 405 dispatchEvent_Widget(touch->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){
406 .type = SDL_MOUSEWHEEL, 406 .type = SDL_MOUSEWHEEL,
407 .timestamp = SDL_GetTicks(), 407 .timestamp = SDL_GetTicks(),
408 .which = 0, /* means "precise scrolling" in DocumentWidget */
409 .x = pixels.x, 408 .x = pixels.x,
410 .y = pixels.y, 409 .y = pixels.y,
410 .direction = perPixel_MouseWheelFlag
411 }); 411 });
412 dispatchMotion_Touch_(zero_F3(), 0); 412 dispatchMotion_Touch_(zero_F3(), 0);
413 /* TODO: Keep increasing movement if the direction is the same. */ 413 /* TODO: Keep increasing movement if the direction is the same. */
diff --git a/src/ui/util.h b/src/ui/util.h
index 122cbb97..7a66ebb3 100644
--- a/src/ui/util.h
+++ b/src/ui/util.h
@@ -43,6 +43,18 @@ iLocalDef iBool isMetricsChange_UserEvent(const SDL_Event *d) {
43 return isCommand_UserEvent(d, "metrics.changed"); 43 return isCommand_UserEvent(d, "metrics.changed");
44} 44}
45 45
46enum iMouseWheelFlag {
47 perPixel_MouseWheelFlag = iBit(9), /* e.g., trackpad or finger scroll; applied to `direction` */
48};
49
50/* Note: A future version of SDL may support per-pixel scrolling, but 2.0.x doesn't. */
51iLocalDef void setPerPixel_MouseWheelEvent(SDL_MouseWheelEvent *ev, iBool set) {
52 iChangeFlags(ev->direction, perPixel_MouseWheelFlag, set);
53}
54iLocalDef iBool isPerPixel_MouseWheelEvent(const SDL_MouseWheelEvent *ev) {
55 return (ev->direction & perPixel_MouseWheelFlag) != 0;
56}
57
46#if defined (iPlatformApple) 58#if defined (iPlatformApple)
47# define KMOD_PRIMARY KMOD_GUI 59# define KMOD_PRIMARY KMOD_GUI
48# define KMOD_SECONDARY KMOD_CTRL 60# define KMOD_SECONDARY KMOD_CTRL