diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-12-17 05:59:38 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-12-17 05:59:38 +0200 |
commit | 80e64189df25aafe461fb9fce107025fee2594dc (patch) | |
tree | 2a6f719932a4513f861b959ad90acc37b445be7d | |
parent | 16d6b6199d580d581f5bdb3c51ab92d1a973d31c (diff) |
macOS: Trackpad swipe navigation
Work in progress. Something breaks down when swiping forward twice...
-rw-r--r-- | src/app.c | 22 | ||||
-rw-r--r-- | src/macos.m | 103 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 144 | ||||
-rw-r--r-- | src/ui/util.h | 19 |
4 files changed, 255 insertions, 33 deletions
@@ -1315,28 +1315,6 @@ void processEvents_App(enum iAppEventMode eventMode) { | |||
1315 | } | 1315 | } |
1316 | /* Scroll events may be per-pixel or mouse wheel steps. */ | 1316 | /* Scroll events may be per-pixel or mouse wheel steps. */ |
1317 | if (ev.type == SDL_MOUSEWHEEL) { | 1317 | if (ev.type == SDL_MOUSEWHEEL) { |
1318 | #if defined (iPlatformAppleDesktop) | ||
1319 | /* On macOS, we handle both trackpad and mouse events. We expect SDL to identify | ||
1320 | which device is sending the event. */ | ||
1321 | if (ev.wheel.which == 0) { | ||
1322 | /* Trackpad with precise scrolling w/inertia (points). */ | ||
1323 | setPerPixel_MouseWheelEvent(&ev.wheel, iTrue); | ||
1324 | ev.wheel.x *= -d->window->base.pixelRatio; | ||
1325 | ev.wheel.y *= d->window->base.pixelRatio; | ||
1326 | /* Only scroll on one axis at a time. */ | ||
1327 | if (iAbs(ev.wheel.x) > iAbs(ev.wheel.y)) { | ||
1328 | ev.wheel.y = 0; | ||
1329 | } | ||
1330 | else { | ||
1331 | ev.wheel.x = 0; | ||
1332 | } | ||
1333 | } | ||
1334 | else { | ||
1335 | /* Disregard wheel acceleration applied by the OS. */ | ||
1336 | ev.wheel.x = -ev.wheel.x; | ||
1337 | ev.wheel.y = iSign(ev.wheel.y); | ||
1338 | } | ||
1339 | #endif | ||
1340 | #if defined (iPlatformMsys) | 1318 | #if defined (iPlatformMsys) |
1341 | ev.wheel.x = -ev.wheel.x; | 1319 | ev.wheel.x = -ev.wheel.x; |
1342 | #endif | 1320 | #endif |
diff --git a/src/macos.m b/src/macos.m index 5fd76bb9..2d082d28 100644 --- a/src/macos.m +++ b/src/macos.m | |||
@@ -403,6 +403,94 @@ void registerURLHandler_MacOS(void) { | |||
403 | [handler release]; | 403 | [handler release]; |
404 | } | 404 | } |
405 | 405 | ||
406 | #if 0 | ||
407 | static iBool isTracking_; | ||
408 | |||
409 | static void trackSwipe_(NSEvent *event) { | ||
410 | if (isTracking_) { | ||
411 | return; | ||
412 | } | ||
413 | isTracking_ = iTrue; | ||
414 | [event trackSwipeEventWithOptions:NSEventSwipeTrackingLockDirection | ||
415 | dampenAmountThresholdMin:-1.0 | ||
416 | max:1.0 | ||
417 | usingHandler:^(CGFloat gestureAmount, NSEventPhase phase, | ||
418 | BOOL isComplete, BOOL *stop) { | ||
419 | printf("TRACK: amount:%f phase:%lu complete:%d\n", | ||
420 | gestureAmount, (unsigned long) phase, isComplete); | ||
421 | fflush(stdout); | ||
422 | if (isComplete) { | ||
423 | isTracking_ = iFalse; | ||
424 | } | ||
425 | } | ||
426 | ]; | ||
427 | } | ||
428 | #endif | ||
429 | |||
430 | static int swipeDir_ = 0; | ||
431 | |||
432 | static iBool processScrollWheelEvent_(NSEvent *event) { | ||
433 | const iBool isPerPixel = (event.hasPreciseScrollingDeltas != 0); | ||
434 | const iBool isInertia = (event.momentumPhase & (NSEventPhaseBegan | NSEventPhaseChanged)) != 0; | ||
435 | const iBool isEnded = event.scrollingDeltaX == 0.0f && event.scrollingDeltaY == 0.0f && !isInertia; | ||
436 | const iWindow *win = &get_MainWindow()->base; | ||
437 | /* Post corresponding MOUSEWHEEL events. */ | ||
438 | SDL_MouseWheelEvent e = { .type = SDL_MOUSEWHEEL }; | ||
439 | e.timestamp = SDL_GetTicks(); | ||
440 | e.which = isPerPixel ? 0 : 1; /* Distinction between trackpad and regular mouse. TODO: Still needed? */ | ||
441 | setPerPixel_MouseWheelEvent(&e, isPerPixel); | ||
442 | if (isPerPixel) { | ||
443 | setInertia_MouseWheelEvent(&e, isInertia); | ||
444 | setScrollFinished_MouseWheelEvent(&e, isEnded); | ||
445 | e.x = -event.scrollingDeltaX * win->pixelRatio; | ||
446 | e.y = event.scrollingDeltaY * win->pixelRatio; | ||
447 | /* Only scroll on one axis at a time. */ | ||
448 | if (swipeDir_ == 0) { | ||
449 | swipeDir_ = iAbs(e.x) > iAbs(e.y) ? 1 : 2; | ||
450 | } | ||
451 | if (swipeDir_ == 1) { | ||
452 | e.y = 0; | ||
453 | } | ||
454 | else if (swipeDir_ == 2) { | ||
455 | e.x = 0; | ||
456 | } | ||
457 | if (isEnded) { | ||
458 | swipeDir_ = 0; | ||
459 | } | ||
460 | } | ||
461 | else { | ||
462 | /* Disregard wheel acceleration applied by the OS. */ | ||
463 | e.x = -event.scrollingDeltaX; | ||
464 | e.y = iSign(event.scrollingDeltaY); | ||
465 | } | ||
466 | // printf("#### dx:%d dy:%d phase:%ld end:%d\n", e.x, e.y, (long) event.momentumPhase, isEnded); fflush(stdout); | ||
467 | SDL_PushEvent((SDL_Event *) &e); | ||
468 | #if 0 | ||
469 | /* On macOS, we handle both trackpad and mouse events. We expect SDL to identify | ||
470 | which device is sending the event. */ | ||
471 | if (ev.wheel.which == 0) { | ||
472 | /* Trackpad with precise scrolling w/inertia (points). */ | ||
473 | setPerPixel_MouseWheelEvent(&ev.wheel, iTrue); | ||
474 | ev.wheel.x *= -d->window->base.pixelRatio; | ||
475 | ev.wheel.y *= d->window->base.pixelRatio; | ||
476 | /* Only scroll on one axis at a time. */ | ||
477 | if (iAbs(ev.wheel.x) > iAbs(ev.wheel.y)) { | ||
478 | ev.wheel.y = 0; | ||
479 | } | ||
480 | else { | ||
481 | ev.wheel.x = 0; | ||
482 | } | ||
483 | } | ||
484 | else { | ||
485 | /* Disregard wheel acceleration applied by the OS. */ | ||
486 | ev.wheel.x = -ev.wheel.x; | ||
487 | ev.wheel.y = iSign(ev.wheel.y); | ||
488 | } | ||
489 | #endif | ||
490 | |||
491 | return iTrue; | ||
492 | } | ||
493 | |||
406 | void setupApplication_MacOS(void) { | 494 | void setupApplication_MacOS(void) { |
407 | NSApplication *app = [NSApplication sharedApplication]; | 495 | NSApplication *app = [NSApplication sharedApplication]; |
408 | [app setActivationPolicy:NSApplicationActivationPolicyRegular]; | 496 | [app setActivationPolicy:NSApplicationActivationPolicyRegular]; |
@@ -424,6 +512,21 @@ void setupApplication_MacOS(void) { | |||
424 | NSMenuItem *windowCloseItem = [windowMenu itemWithTitle:@"Close"]; | 512 | NSMenuItem *windowCloseItem = [windowMenu itemWithTitle:@"Close"]; |
425 | windowCloseItem.target = myDel; | 513 | windowCloseItem.target = myDel; |
426 | windowCloseItem.action = @selector(closeTab); | 514 | windowCloseItem.action = @selector(closeTab); |
515 | [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskScrollWheel | ||
516 | handler:^NSEvent*(NSEvent *event){ | ||
517 | // printf("event type: %lu\n", (unsigned long) event.type); | ||
518 | // fflush(stdout); | ||
519 | // if (event.type == NSEventTypeGesture) { | ||
520 | // trackSwipe_(event); | ||
521 | // printf("GESTURE phase:%lu\n", (unsigned long) event.phase); | ||
522 | //fflush(stdout); | ||
523 | // } | ||
524 | if (event.type == NSEventTypeScrollWheel && | ||
525 | processScrollWheelEvent_(event)) { | ||
526 | return nil; /* was eaten */ | ||
527 | } | ||
528 | return event; | ||
529 | }]; | ||
427 | } | 530 | } |
428 | 531 | ||
429 | void hideTitleBar_MacOS(iWindow *window) { | 532 | void hideTitleBar_MacOS(iWindow *window) { |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 0a24f7e5..9f6cdc45 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -234,6 +234,10 @@ enum iDocumentWidgetFlag { | |||
234 | fromCache_DocumentWidgetFlag = iBit(16), /* don't write anything to cache */ | 234 | fromCache_DocumentWidgetFlag = iBit(16), /* don't write anything to cache */ |
235 | animationPlaceholder_DocumentWidgetFlag = iBit(17), /* avoid slow operations */ | 235 | animationPlaceholder_DocumentWidgetFlag = iBit(17), /* avoid slow operations */ |
236 | invalidationPending_DocumentWidgetFlag = iBit(18), /* invalidate as soon as convenient */ | 236 | invalidationPending_DocumentWidgetFlag = iBit(18), /* invalidate as soon as convenient */ |
237 | leftWheelSwipe_DocumentWidgetFlag = iBit(19), /* swipe state flags are used on desktop */ | ||
238 | rightWheelSwipe_DocumentWidgetFlag = iBit(20), | ||
239 | eitherWheelSwipe_DocumentWidgetFlag = leftWheelSwipe_DocumentWidgetFlag | rightWheelSwipe_DocumentWidgetFlag, | ||
240 | // wheelSwipeFinished_DocumentWidgetFlag = iBit(21), | ||
237 | }; | 241 | }; |
238 | 242 | ||
239 | enum iDocumentLinkOrdinalMode { | 243 | enum iDocumentLinkOrdinalMode { |
@@ -241,6 +245,12 @@ enum iDocumentLinkOrdinalMode { | |||
241 | homeRow_DocumentLinkOrdinalMode, | 245 | homeRow_DocumentLinkOrdinalMode, |
242 | }; | 246 | }; |
243 | 247 | ||
248 | enum iWheelSwipeState { | ||
249 | none_WheelSwipeState, | ||
250 | direct_WheelSwipeState, | ||
251 | //inertia_WheelSwipeState, | ||
252 | }; | ||
253 | |||
244 | struct Impl_DocumentWidget { | 254 | struct Impl_DocumentWidget { |
245 | iWidget widget; | 255 | iWidget widget; |
246 | int flags; /* internal behavior, see enum iDocumentWidgetFlag */ | 256 | int flags; /* internal behavior, see enum iDocumentWidgetFlag */ |
@@ -263,6 +273,9 @@ struct Impl_DocumentWidget { | |||
263 | int pinchZoomInitial; | 273 | int pinchZoomInitial; |
264 | int pinchZoomPosted; | 274 | int pinchZoomPosted; |
265 | float swipeSpeed; /* points/sec */ | 275 | float swipeSpeed; /* points/sec */ |
276 | uint32_t lastSwipeTime; | ||
277 | int wheelSwipeDistance; | ||
278 | enum iWheelSwipeState wheelSwipeState; | ||
266 | iString pendingGotoHeading; | 279 | iString pendingGotoHeading; |
267 | iString linePrecedingLink; | 280 | iString linePrecedingLink; |
268 | 281 | ||
@@ -329,7 +342,12 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
329 | init_Widget(w); | 342 | init_Widget(w); |
330 | setId_Widget(w, format_CStr("document%03d", ++docEnum_)); | 343 | setId_Widget(w, format_CStr("document%03d", ++docEnum_)); |
331 | setFlags_Widget(w, hover_WidgetFlag | noBackground_WidgetFlag, iTrue); | 344 | setFlags_Widget(w, hover_WidgetFlag | noBackground_WidgetFlag, iTrue); |
332 | if (deviceType_App() != desktop_AppDeviceType) { | 345 | #if defined (iPlatformAppleDesktop) |
346 | iBool enableSwipeNavigation = iTrue; /* swipes on the trackpad */ | ||
347 | #else | ||
348 | iBool enableSwipeNavigation = (deviceType_App() != desktop_AppDeviceType); | ||
349 | #endif | ||
350 | if (enableSwipeNavigation) { | ||
333 | setFlags_Widget(w, leftEdgeDraggable_WidgetFlag | rightEdgeDraggable_WidgetFlag | | 351 | setFlags_Widget(w, leftEdgeDraggable_WidgetFlag | rightEdgeDraggable_WidgetFlag | |
334 | horizontalOffset_WidgetFlag, iTrue); | 352 | horizontalOffset_WidgetFlag, iTrue); |
335 | } | 353 | } |
@@ -358,6 +376,7 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
358 | } | 376 | } |
359 | d->animWideRunId = 0; | 377 | d->animWideRunId = 0; |
360 | init_Anim(&d->animWideRunOffset, 0); | 378 | init_Anim(&d->animWideRunOffset, 0); |
379 | d->wheelSwipeState = none_WheelSwipeState; | ||
361 | d->selectMark = iNullRange; | 380 | d->selectMark = iNullRange; |
362 | d->foundMark = iNullRange; | 381 | d->foundMark = iNullRange; |
363 | d->pageMargin = 5; | 382 | d->pageMargin = 5; |
@@ -1942,8 +1961,7 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n | |||
1942 | 1961 | ||
1943 | static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { | 1962 | static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { |
1944 | const iRecentUrl *recent = constMostRecentUrl_History(d->mod.history); | 1963 | const iRecentUrl *recent = constMostRecentUrl_History(d->mod.history); |
1945 | iAssert(equalCase_String(&recent->url, d->mod.url)); | 1964 | if (recent && recent->cachedResponse && equalCase_String(&recent->url, d->mod.url)) { |
1946 | if (recent && recent->cachedResponse) { | ||
1947 | iChangeFlags(d->flags, | 1965 | iChangeFlags(d->flags, |
1948 | openedFromSidebar_DocumentWidgetFlag, | 1966 | openedFromSidebar_DocumentWidgetFlag, |
1949 | recent->flags.openedFromSidebar); | 1967 | recent->flags.openedFromSidebar); |
@@ -2043,10 +2061,10 @@ static void scrollToHeading_DocumentWidget_(iDocumentWidget *d, const char *head | |||
2043 | } | 2061 | } |
2044 | } | 2062 | } |
2045 | 2063 | ||
2046 | static void scrollWideBlock_DocumentWidget_(iDocumentWidget *d, iInt2 mousePos, int delta, | 2064 | static iBool scrollWideBlock_DocumentWidget_(iDocumentWidget *d, iInt2 mousePos, int delta, |
2047 | int duration) { | 2065 | int duration) { |
2048 | if (delta == 0) { | 2066 | if (delta == 0 || d->flags & eitherWheelSwipe_DocumentWidgetFlag) { |
2049 | return; | 2067 | return iFalse; |
2050 | } | 2068 | } |
2051 | const iInt2 docPos = documentPos_DocumentWidget_(d, mousePos); | 2069 | const iInt2 docPos = documentPos_DocumentWidget_(d, mousePos); |
2052 | iConstForEach(PtrArray, i, &d->visibleWideRuns) { | 2070 | iConstForEach(PtrArray, i, &d->visibleWideRuns) { |
@@ -2087,9 +2105,10 @@ static void scrollWideBlock_DocumentWidget_(iDocumentWidget *d, iInt2 mousePos, | |||
2087 | d->animWideRunId = 0; | 2105 | d->animWideRunId = 0; |
2088 | init_Anim(&d->animWideRunOffset, 0); | 2106 | init_Anim(&d->animWideRunOffset, 0); |
2089 | } | 2107 | } |
2090 | break; | 2108 | return iTrue; |
2091 | } | 2109 | } |
2092 | } | 2110 | } |
2111 | return iFalse; | ||
2093 | } | 2112 | } |
2094 | 2113 | ||
2095 | static void togglePreFold_DocumentWidget_(iDocumentWidget *d, uint16_t preId) { | 2114 | static void togglePreFold_DocumentWidget_(iDocumentWidget *d, uint16_t preId) { |
@@ -2691,7 +2710,7 @@ static void setupSwipeOverlay_DocumentWidget_(iDocumentWidget *d, iWidget *overl | |||
2691 | const int toPos = width_Widget(overlay); | 2710 | const int toPos = width_Widget(overlay); |
2692 | setVisualOffset_Widget(overlay, fromPos, 0, 0); | 2711 | setVisualOffset_Widget(overlay, fromPos, 0, 0); |
2693 | /* Bigger screen, faster swipes. */ | 2712 | /* Bigger screen, faster swipes. */ |
2694 | const float devFactor = (deviceType_App() == tablet_AppDeviceType ? 2.0f : 1.0f); | 2713 | const float devFactor = (deviceType_App() == phone_AppDeviceType ? 1.0f : 2.0f); |
2695 | float swipe = iClamp(d->swipeSpeed, devFactor * 400, devFactor * 1000) * gap_UI; | 2714 | float swipe = iClamp(d->swipeSpeed, devFactor * 400, devFactor * 1000) * gap_UI; |
2696 | uint32_t span = ((toPos - fromPos) / swipe) * 1000; | 2715 | uint32_t span = ((toPos - fromPos) / swipe) * 1000; |
2697 | // printf("from:%d to:%d swipe:%f span:%u\n", fromPos, toPos, d->swipeSpeed, span); | 2716 | // printf("from:%d to:%d swipe:%f span:%u\n", fromPos, toPos, d->swipeSpeed, span); |
@@ -2841,6 +2860,7 @@ static iBool handleSwipe_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | |||
2841 | target->flags |= animationPlaceholder_DocumentWidgetFlag; | 2860 | target->flags |= animationPlaceholder_DocumentWidgetFlag; |
2842 | addChildPos_Widget(swipeParent, iClob(target), back_WidgetAddPos); | 2861 | addChildPos_Widget(swipeParent, iClob(target), back_WidgetAddPos); |
2843 | setId_Widget(as_Widget(target), "swipeout"); | 2862 | setId_Widget(as_Widget(target), "swipeout"); |
2863 | setFlags_Widget(as_Widget(target), disabled_WidgetFlag, iTrue); | ||
2844 | swap_DocumentWidget_(target, d->doc, d); | 2864 | swap_DocumentWidget_(target, d->doc, d); |
2845 | setUrlAndSource_DocumentWidget(d, | 2865 | setUrlAndSource_DocumentWidget(d, |
2846 | swipeIn->mod.url, | 2866 | swipeIn->mod.url, |
@@ -3870,6 +3890,105 @@ static void interactingWithLink_DocumentWidget_(iDocumentWidget *d, iGmLinkId id | |||
3870 | setRange_String(&d->linePrecedingLink, loc); | 3890 | setRange_String(&d->linePrecedingLink, loc); |
3871 | } | 3891 | } |
3872 | 3892 | ||
3893 | iLocalDef int wheelSwipeSide_DocumentWidget_(const iDocumentWidget *d) { | ||
3894 | return (d->flags & rightWheelSwipe_DocumentWidgetFlag ? 2 | ||
3895 | : d->flags & leftWheelSwipe_DocumentWidgetFlag ? 1 | ||
3896 | : 0); | ||
3897 | } | ||
3898 | |||
3899 | static void finishWheelSwipe_DocumentWidget_(iDocumentWidget *d) { | ||
3900 | if (d->flags & eitherWheelSwipe_DocumentWidgetFlag && | ||
3901 | d->wheelSwipeState == direct_WheelSwipeState) { | ||
3902 | // ~d->flags & wheelSwipeFinished_DocumentWidgetFlag) { | ||
3903 | // d->wheelSwipeState = inertia_WheelSwipeState; | ||
3904 | const int side = wheelSwipeSide_DocumentWidget_(d); | ||
3905 | // d->flags |= wheelSwipeFinished_DocumentWidgetFlag; | ||
3906 | int abort = (side == 1 && d->swipeSpeed < 0 || side == 2 && d->swipeSpeed > 0); | ||
3907 | printf("speed:%f\n", d->swipeSpeed / gap_UI); | ||
3908 | if (iAbs(d->wheelSwipeDistance) < width_Widget(d) / 4 && iAbs(d->swipeSpeed) < 4 * gap_UI) { | ||
3909 | abort = 1; | ||
3910 | } | ||
3911 | postCommand_Widget(d, "edgeswipe.ended side:%d abort:%d", side, abort); | ||
3912 | d->flags &= ~eitherWheelSwipe_DocumentWidgetFlag; | ||
3913 | } | ||
3914 | } | ||
3915 | |||
3916 | static iBool handleWheelSwipe_DocumentWidget_(iDocumentWidget *d, const SDL_MouseWheelEvent *ev) { | ||
3917 | iWidget *w = as_Widget(d); | ||
3918 | if (~flags_Widget(w) & horizontalOffset_WidgetFlag) { | ||
3919 | return iFalse; | ||
3920 | } | ||
3921 | iAssert(~d->flags & animationPlaceholder_DocumentWidgetFlag); | ||
3922 | // printf("STATE:%d wheel x:%d inert:%d end:%d\n", d->wheelSwipeState, | ||
3923 | // ev->x, isInertia_MouseWheelEvent(ev), | ||
3924 | // isScrollFinished_MouseWheelEvent(ev)); | ||
3925 | // fflush(stdout); | ||
3926 | switch (d->wheelSwipeState) { | ||
3927 | case none_WheelSwipeState: | ||
3928 | /* A new swipe starts. */ | ||
3929 | if (!isInertia_MouseWheelEvent(ev) && !isScrollFinished_MouseWheelEvent(ev)) { | ||
3930 | int side = ev->x < 0 ? 1 : 2; | ||
3931 | d->wheelSwipeDistance = -ev->x; | ||
3932 | d->flags &= ~eitherWheelSwipe_DocumentWidgetFlag; | ||
3933 | d->flags |= (side == 1 ? leftWheelSwipe_DocumentWidgetFlag | ||
3934 | : rightWheelSwipe_DocumentWidgetFlag); | ||
3935 | // printf("swipe starts at %d, side %d\n", d->wheelSwipeDistance, side); | ||
3936 | d->wheelSwipeState = direct_WheelSwipeState; | ||
3937 | d->swipeSpeed = 0; | ||
3938 | postCommand_Widget(d, "edgeswipe.moved arg:%d side:%d", d->wheelSwipeDistance, side); | ||
3939 | return iTrue; | ||
3940 | } | ||
3941 | break; | ||
3942 | case direct_WheelSwipeState: | ||
3943 | if (isInertia_MouseWheelEvent(ev) || isScrollFinished_MouseWheelEvent(ev)) { | ||
3944 | finishWheelSwipe_DocumentWidget_(d); | ||
3945 | d->wheelSwipeState = none_WheelSwipeState; | ||
3946 | } | ||
3947 | // else if (isInertia_MouseWheelEvent(ev)) { | ||
3948 | // finishWheelSwipe_DocumentWidget_(d); | ||
3949 | // d->wheelSwipeState = inertia_WheelSwipeState; | ||
3950 | // } | ||
3951 | else { | ||
3952 | int step = -ev->x * 2; | ||
3953 | d->wheelSwipeDistance += step; | ||
3954 | /* Remember the maximum speed. */ | ||
3955 | if (d->swipeSpeed < 0 && step < 0) { | ||
3956 | d->swipeSpeed = iMin(d->swipeSpeed, step); | ||
3957 | } | ||
3958 | else if (d->swipeSpeed > 0 && step > 0) { | ||
3959 | d->swipeSpeed = iMax(d->swipeSpeed, step); | ||
3960 | } | ||
3961 | else { | ||
3962 | d->swipeSpeed = step; | ||
3963 | } | ||
3964 | switch (wheelSwipeSide_DocumentWidget_(d)) { | ||
3965 | case 1: | ||
3966 | d->wheelSwipeDistance = iMax(0, d->wheelSwipeDistance); | ||
3967 | d->wheelSwipeDistance = iMin(width_Widget(d), d->wheelSwipeDistance); | ||
3968 | break; | ||
3969 | case 2: | ||
3970 | d->wheelSwipeDistance = iMin(0, d->wheelSwipeDistance); | ||
3971 | d->wheelSwipeDistance = iMax(-width_Widget(d), d->wheelSwipeDistance); | ||
3972 | break; | ||
3973 | } | ||
3974 | /* TODO: calculate speed, rememeber direction */ | ||
3975 | //printf("swipe moved to %d, side %d\n", d->wheelSwipeDistance, side); | ||
3976 | postCommand_Widget(d, "edgeswipe.moved arg:%d side:%d", d->wheelSwipeDistance, | ||
3977 | wheelSwipeSide_DocumentWidget_(d)); | ||
3978 | } | ||
3979 | return iTrue; | ||
3980 | // case inertia_WheelSwipeState: | ||
3981 | // if (isScrollFinished_MouseWheelEvent(ev)) { | ||
3982 | // d->wheelSwipeState = none_WheelSwipeState; | ||
3983 | // } | ||
3984 | // else if (!isInertia_MouseWheelEvent(ev)) { | ||
3985 | // d->wheelSwipeState = none_WheelSwipeState; | ||
3986 | // } | ||
3987 | // return iTrue; | ||
3988 | } | ||
3989 | return iFalse; | ||
3990 | } | ||
3991 | |||
3873 | static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *ev) { | 3992 | static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *ev) { |
3874 | iWidget *w = as_Widget(d); | 3993 | iWidget *w = as_Widget(d); |
3875 | if (isMetricsChange_UserEvent(ev)) { | 3994 | if (isMetricsChange_UserEvent(ev)) { |
@@ -3967,13 +4086,20 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3967 | #endif | 4086 | #endif |
3968 | } | 4087 | } |
3969 | } | 4088 | } |
4089 | else if (ev->type == SDL_MOUSEWHEEL && ev->wheel.y == 0 && | ||
4090 | handleWheelSwipe_DocumentWidget_(d, &ev->wheel)) { | ||
4091 | return iTrue; | ||
4092 | } | ||
3970 | else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { | 4093 | else if (ev->type == SDL_MOUSEWHEEL && isHover_Widget(w)) { |
3971 | const iInt2 mouseCoord = coord_MouseWheelEvent(&ev->wheel); | 4094 | const iInt2 mouseCoord = coord_MouseWheelEvent(&ev->wheel); |
3972 | if (isPerPixel_MouseWheelEvent(&ev->wheel)) { | 4095 | if (isPerPixel_MouseWheelEvent(&ev->wheel)) { |
3973 | const iInt2 wheel = init_I2(ev->wheel.x, ev->wheel.y); | 4096 | const iInt2 wheel = init_I2(ev->wheel.x, ev->wheel.y); |
3974 | stop_Anim(&d->scrollY.pos); | 4097 | stop_Anim(&d->scrollY.pos); |
3975 | immediateScroll_DocumentWidget_(d, -wheel.y); | 4098 | immediateScroll_DocumentWidget_(d, -wheel.y); |
3976 | scrollWideBlock_DocumentWidget_(d, mouseCoord, -wheel.x, 0); | 4099 | if (!scrollWideBlock_DocumentWidget_(d, mouseCoord, -wheel.x, 0) && |
4100 | wheel.x) { | ||
4101 | handleWheelSwipe_DocumentWidget_(d, &ev->wheel); | ||
4102 | } | ||
3977 | } | 4103 | } |
3978 | else { | 4104 | else { |
3979 | /* Traditional mouse wheel. */ | 4105 | /* Traditional mouse wheel. */ |
diff --git a/src/ui/util.h b/src/ui/util.h index b9109aee..4fedd083 100644 --- a/src/ui/util.h +++ b/src/ui/util.h | |||
@@ -47,16 +47,31 @@ iLocalDef iBool isMetricsChange_UserEvent(const SDL_Event *d) { | |||
47 | } | 47 | } |
48 | 48 | ||
49 | enum iMouseWheelFlag { | 49 | enum iMouseWheelFlag { |
50 | perPixel_MouseWheelFlag = iBit(9), /* e.g., trackpad or finger scroll; applied to `direction` */ | 50 | /* Note: A future version of SDL may support per-pixel scrolling, but 2.0.x doesn't. */ |
51 | perPixel_MouseWheelFlag = iBit(9), /* e.g., trackpad or finger scroll; applied to `direction` */ | ||
52 | inertia_MouseWheelFlag = iBit(10), | ||
53 | scrollFinished_MouseWheelFlag = iBit(11), | ||
51 | }; | 54 | }; |
52 | 55 | ||
53 | /* Note: A future version of SDL may support per-pixel scrolling, but 2.0.x doesn't. */ | ||
54 | iLocalDef void setPerPixel_MouseWheelEvent(SDL_MouseWheelEvent *ev, iBool set) { | 56 | iLocalDef void setPerPixel_MouseWheelEvent(SDL_MouseWheelEvent *ev, iBool set) { |
55 | iChangeFlags(ev->direction, perPixel_MouseWheelFlag, set); | 57 | iChangeFlags(ev->direction, perPixel_MouseWheelFlag, set); |
56 | } | 58 | } |
59 | iLocalDef void setInertia_MouseWheelEvent(SDL_MouseWheelEvent *ev, iBool set) { | ||
60 | iChangeFlags(ev->direction, inertia_MouseWheelFlag, set); | ||
61 | } | ||
62 | iLocalDef void setScrollFinished_MouseWheelEvent(SDL_MouseWheelEvent *ev, iBool set) { | ||
63 | iChangeFlags(ev->direction, scrollFinished_MouseWheelFlag, set); | ||
64 | } | ||
65 | |||
57 | iLocalDef iBool isPerPixel_MouseWheelEvent(const SDL_MouseWheelEvent *ev) { | 66 | iLocalDef iBool isPerPixel_MouseWheelEvent(const SDL_MouseWheelEvent *ev) { |
58 | return (ev->direction & perPixel_MouseWheelFlag) != 0; | 67 | return (ev->direction & perPixel_MouseWheelFlag) != 0; |
59 | } | 68 | } |
69 | iLocalDef iBool isInertia_MouseWheelEvent(const SDL_MouseWheelEvent *ev) { | ||
70 | return (ev->direction & inertia_MouseWheelFlag) != 0; | ||
71 | } | ||
72 | iLocalDef iBool isScrollFinished_MouseWheelEvent(const SDL_MouseWheelEvent *ev) { | ||
73 | return (ev->direction & scrollFinished_MouseWheelFlag) != 0; | ||
74 | } | ||
60 | 75 | ||
61 | iInt2 coord_MouseWheelEvent (const SDL_MouseWheelEvent *); | 76 | iInt2 coord_MouseWheelEvent (const SDL_MouseWheelEvent *); |
62 | 77 | ||