1package cef
2
3import (
4 "testing"
5
6 "github.com/bnema/dumber/internal/domain/entity"
7 cef2gtk "github.com/bnema/purego-cef2gtk"
8 "github.com/bnema/puregotk/v4/gdk"
9 "github.com/stretchr/testify/require"
10)
11
12func TestTouchpadNavigationRecognizer_ReportsProgressAndNavigatesOnReleaseAfterThreshold(t *testing.T) {
13 recognizer := newTouchpadNavigationRecognizer()
14 cfg := RuntimeInputConfig{
15 TouchpadNavigationEnabled: true,
16 TouchpadNavigationMinDelta: 200,
17 TouchpadNavigationMaxVerticalRatio: 0.5,
18 }
19
20 begin := recognizer.Handle(touchpadNavigationInput{
21 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseBegin, 0, 0),
22 Config: cfg,
23 CanGoBack: true,
24 CanGoForward: true,
25 ViewWidth: 1000,
26 })
27 require.False(t, begin.HasIndicator)
28 require.False(t, begin.HasAction)
29
30 ordinaryScroll := recognizer.Handle(touchpadNavigationInput{
31 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -80, 0),
32 Config: cfg,
33 CanGoBack: true,
34 CanGoForward: true,
35 })
36 require.False(t, ordinaryScroll.HasIndicator, "ordinary horizontal scrolling below the activation distance should not show navigation UI")
37 require.False(t, ordinaryScroll.HasAction)
38
39 progress := recognizer.Handle(touchpadNavigationInput{
40 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -40, 0),
41 Config: cfg,
42 CanGoBack: true,
43 CanGoForward: true,
44 })
45 require.True(t, progress.HasIndicator)
46 require.Equal(t, entity.TouchpadNavigationBack, progress.Indicator.Action)
47 require.True(t, progress.Indicator.Active)
48 require.InDelta(t, 0.6, progress.Indicator.Progress, 0.001)
49 require.False(t, progress.Indicator.ThresholdReached)
50 require.False(t, progress.HasAction)
51
52 armed := recognizer.Handle(touchpadNavigationInput{
53 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -100, 0),
54 Config: cfg,
55 CanGoBack: true,
56 CanGoForward: true,
57 })
58 require.True(t, armed.HasIndicator)
59 require.Equal(t, entity.TouchpadNavigationBack, armed.Indicator.Action)
60 require.True(t, armed.Indicator.Active)
61 require.InDelta(t, 1.0, armed.Indicator.Progress, 0.001)
62 require.True(t, armed.Indicator.ThresholdReached)
63 require.False(t, armed.HasAction, "navigation waits for gesture release so the indicator is visible first")
64
65 end := recognizer.Handle(touchpadNavigationInput{
66 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseEnd, 0, 0),
67 Config: cfg,
68 CanGoBack: true,
69 CanGoForward: true,
70 })
71 require.True(t, end.HasIndicator)
72 require.False(t, end.Indicator.Active)
73 require.True(t, end.HasAction)
74 require.Equal(t, cef2gtk.NavigationSwipeBack, end.Action)
75}
76
77func TestTouchpadNavigationRecognizer_ReportsForwardProgressAndNavigatesOnReleaseAfterThreshold(t *testing.T) {
78 recognizer := newTouchpadNavigationRecognizer()
79 cfg := RuntimeInputConfig{
80 TouchpadNavigationEnabled: true,
81 TouchpadNavigationMinDelta: 200,
82 TouchpadNavigationMaxVerticalRatio: 0.5,
83 }
84
85 begin := recognizer.Handle(touchpadNavigationInput{
86 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseBegin, 976, 0, 0),
87 Config: cfg,
88 CanGoBack: true,
89 CanGoForward: true,
90 ViewWidth: 1000,
91 })
92 require.False(t, begin.HasIndicator)
93 require.False(t, begin.HasAction)
94
95 armed := recognizer.Handle(touchpadNavigationInput{
96 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseUpdate, 976, 240, 0),
97 Config: cfg,
98 CanGoBack: true,
99 CanGoForward: true,
100 })
101 require.True(t, armed.HasIndicator)
102 require.Equal(t, entity.TouchpadNavigationForward, armed.Indicator.Action)
103 require.True(t, armed.Indicator.Active)
104 require.InDelta(t, 1.0, armed.Indicator.Progress, 0.001)
105 require.True(t, armed.Indicator.ThresholdReached)
106 require.False(t, armed.HasAction)
107
108 end := recognizer.Handle(touchpadNavigationInput{
109 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseEnd, 976, 0, 0),
110 Config: cfg,
111 CanGoBack: true,
112 CanGoForward: true,
113 })
114 require.True(t, end.HasIndicator)
115 require.False(t, end.Indicator.Active)
116 require.True(t, end.HasAction)
117 require.Equal(t, cef2gtk.NavigationSwipeForward, end.Action)
118}
119
120func TestTouchpadNavigationRecognizer_DoesNotNavigateAtExactThreshold(t *testing.T) {
121 recognizer := newTouchpadNavigationRecognizer()
122 cfg := RuntimeInputConfig{
123 TouchpadNavigationEnabled: true,
124 TouchpadNavigationMinDelta: 200,
125 TouchpadNavigationMaxVerticalRatio: 0.5,
126 }
127
128 _ = recognizer.Handle(touchpadNavigationInput{
129 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseBegin, 0, 0),
130 Config: cfg,
131 CanGoBack: true,
132 ViewWidth: 1000,
133 })
134 exact := recognizer.Handle(touchpadNavigationInput{
135 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -200, 0),
136 Config: cfg,
137 CanGoBack: true,
138 })
139 require.True(t, exact.HasIndicator)
140 require.InDelta(t, 1.0, exact.Indicator.Progress, 0.001)
141 require.False(t, exact.Indicator.ThresholdReached)
142
143 end := recognizer.Handle(touchpadNavigationInput{
144 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseEnd, 0, 0),
145 Config: cfg,
146 CanGoBack: true,
147 })
148 require.True(t, end.HasIndicator)
149 require.False(t, end.Indicator.Active)
150 require.False(t, end.Indicator.ThresholdReached)
151 require.False(t, end.HasAction)
152}
153
154func TestTouchpadNavigationRecognizer_DoesNotShowIndicatorBelowActivationDistance(t *testing.T) {
155 recognizer := newTouchpadNavigationRecognizer()
156 cfg := RuntimeInputConfig{
157 TouchpadNavigationEnabled: true,
158 TouchpadNavigationMinDelta: 200,
159 TouchpadNavigationMaxVerticalRatio: 0.5,
160 }
161
162 _ = recognizer.Handle(touchpadNavigationInput{
163 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseBegin, 0, 0),
164 Config: cfg,
165 CanGoBack: true,
166 ViewWidth: 1000,
167 })
168 ordinaryScroll := recognizer.Handle(touchpadNavigationInput{
169 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -80, 0),
170 Config: cfg,
171 CanGoBack: true,
172 })
173 require.False(t, ordinaryScroll.HasIndicator)
174 require.False(t, ordinaryScroll.HasAction)
175
176 end := recognizer.Handle(touchpadNavigationInput{
177 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseEnd, 0, 0),
178 Config: cfg,
179 CanGoBack: true,
180 })
181 require.False(t, end.HasAction)
182 require.False(t, end.HasIndicator)
183}
184
185func TestTouchpadNavigationRecognizer_AllowsIntentionalEdgeSwipeWithViewWidth(t *testing.T) {
186 recognizer := newTouchpadNavigationRecognizer()
187 cfg := RuntimeInputConfig{
188 TouchpadNavigationEnabled: true,
189 TouchpadNavigationMinDelta: 200,
190 TouchpadNavigationMaxVerticalRatio: 0.5,
191 }
192
193 _ = recognizer.Handle(touchpadNavigationInput{
194 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseBegin, 24, 0, 0),
195 Config: cfg,
196 CanGoBack: true,
197 ViewWidth: 1000,
198 })
199 armed := recognizer.Handle(touchpadNavigationInput{
200 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseUpdate, 24, -240, 0),
201 Config: cfg,
202 CanGoBack: true,
203 })
204 require.True(t, armed.HasIndicator)
205 require.True(t, armed.Indicator.ThresholdReached)
206
207 end := recognizer.Handle(touchpadNavigationInput{
208 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseEnd, 24, 0, 0),
209 Config: cfg,
210 CanGoBack: true,
211 })
212 require.True(t, end.HasAction)
213 require.Equal(t, cef2gtk.NavigationSwipeBack, end.Action)
214}
215
216func TestTouchpadNavigationRecognizer_DoesNotTreatInContentHorizontalScrollAsNavigation(t *testing.T) {
217 recognizer := newTouchpadNavigationRecognizer()
218 cfg := RuntimeInputConfig{
219 TouchpadNavigationEnabled: true,
220 TouchpadNavigationMinDelta: 200,
221 TouchpadNavigationMaxVerticalRatio: 0.5,
222 }
223
224 _ = recognizer.Handle(touchpadNavigationInput{
225 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseBegin, 500, 0, 0),
226 Config: cfg,
227 CanGoBack: true,
228 ViewWidth: 1000,
229 })
230 ordinaryScroll := recognizer.Handle(touchpadNavigationInput{
231 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseUpdate, 500, -240, 0),
232 Config: cfg,
233 CanGoBack: true,
234 ViewWidth: 1000,
235 })
236 require.False(t, ordinaryScroll.HasIndicator)
237 require.False(t, ordinaryScroll.HasAction)
238
239 end := recognizer.Handle(touchpadNavigationInput{
240 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseEnd, 500, 0, 0),
241 Config: cfg,
242 CanGoBack: true,
243 ViewWidth: 1000,
244 })
245 require.False(t, end.HasIndicator)
246 require.False(t, end.HasAction)
247}
248
249func TestTouchpadNavigationRecognizer_IgnoresNonPreciseScrollEvents(t *testing.T) {
250 tests := []struct {
251 name string
252 event cef2gtk.ScrollEvent
253 }{
254 {
255 name: "unknown unit",
256 event: cef2gtk.ScrollEvent{
257 Phase: cef2gtk.ScrollPhaseUpdate,
258 DX: -240,
259 Unit: gdk.ScrollUnitSurfaceValue,
260 UnitKnown: false,
261 },
262 },
263 {
264 name: "wheel unit",
265 event: cef2gtk.ScrollEvent{
266 Phase: cef2gtk.ScrollPhaseUpdate,
267 DX: -240,
268 Unit: gdk.ScrollUnitWheelValue,
269 UnitKnown: true,
270 },
271 },
272 }
273
274 for _, tt := range tests {
275 t.Run(tt.name, func(t *testing.T) {
276 recognizer := newTouchpadNavigationRecognizer()
277 cfg := RuntimeInputConfig{
278 TouchpadNavigationEnabled: true,
279 TouchpadNavigationMinDelta: 200,
280 TouchpadNavigationMaxVerticalRatio: 0.5,
281 }
282
283 _ = recognizer.Handle(touchpadNavigationInput{
284 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseBegin, 0, 0),
285 Config: cfg,
286 CanGoBack: true,
287 ViewWidth: 1000,
288 })
289 result := recognizer.Handle(touchpadNavigationInput{
290 Event: tt.event,
291 Config: cfg,
292 CanGoBack: true,
293 })
294 require.False(t, result.HasIndicator)
295 require.False(t, result.HasAction)
296 })
297 }
298}
299
300func TestTouchpadNavigationRecognizer_DisabledConfigSuppressesGestureRecognition(t *testing.T) {
301 recognizer := newTouchpadNavigationRecognizer()
302 cfg := RuntimeInputConfig{
303 TouchpadNavigationEnabled: false,
304 TouchpadNavigationMinDelta: 200,
305 TouchpadNavigationMaxVerticalRatio: 0.5,
306 }
307
308 begin := recognizer.Handle(touchpadNavigationInput{
309 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseBegin, 0, 0),
310 Config: cfg,
311 CanGoBack: true,
312 ViewWidth: 1000,
313 })
314 require.False(t, begin.HasIndicator)
315 require.False(t, begin.HasAction)
316
317 update := recognizer.Handle(touchpadNavigationInput{
318 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -240, 0),
319 Config: cfg,
320 CanGoBack: true,
321 })
322 require.False(t, update.HasIndicator)
323 require.False(t, update.HasAction)
324
325 end := recognizer.Handle(touchpadNavigationInput{
326 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseEnd, 0, 0),
327 Config: cfg,
328 CanGoBack: true,
329 })
330 require.False(t, end.HasIndicator)
331 require.False(t, end.HasAction)
332}
333
334func TestTouchpadNavigationRecognizer_BackCapabilitySuppressesBackGesture(t *testing.T) {
335 recognizer := newTouchpadNavigationRecognizer()
336 cfg := RuntimeInputConfig{
337 TouchpadNavigationEnabled: true,
338 TouchpadNavigationMinDelta: 200,
339 TouchpadNavigationMaxVerticalRatio: 0.5,
340 }
341
342 _ = recognizer.Handle(touchpadNavigationInput{
343 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseBegin, 0, 0),
344 Config: cfg,
345 CanGoBack: false,
346 ViewWidth: 1000,
347 })
348 update := recognizer.Handle(touchpadNavigationInput{
349 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -240, 0),
350 Config: cfg,
351 CanGoBack: false,
352 })
353 require.False(t, update.HasIndicator)
354 require.False(t, update.HasAction)
355
356 end := recognizer.Handle(touchpadNavigationInput{
357 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseEnd, 0, 0),
358 Config: cfg,
359 CanGoBack: false,
360 })
361 require.False(t, end.HasIndicator)
362 require.False(t, end.HasAction)
363}
364
365func TestTouchpadNavigationRecognizer_ForwardCapabilitySuppressesForwardGesture(t *testing.T) {
366 recognizer := newTouchpadNavigationRecognizer()
367 cfg := RuntimeInputConfig{
368 TouchpadNavigationEnabled: true,
369 TouchpadNavigationMinDelta: 200,
370 TouchpadNavigationMaxVerticalRatio: 0.5,
371 }
372
373 _ = recognizer.Handle(touchpadNavigationInput{
374 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseBegin, 976, 0, 0),
375 Config: cfg,
376 CanGoForward: false,
377 ViewWidth: 1000,
378 })
379 update := recognizer.Handle(touchpadNavigationInput{
380 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseUpdate, 976, 240, 0),
381 Config: cfg,
382 CanGoForward: false,
383 })
384 require.False(t, update.HasIndicator)
385 require.False(t, update.HasAction)
386
387 end := recognizer.Handle(touchpadNavigationInput{
388 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseEnd, 976, 0, 0),
389 Config: cfg,
390 CanGoForward: false,
391 })
392 require.False(t, end.HasIndicator)
393 require.False(t, end.HasAction)
394}
395
396func TestTouchpadNavigationRecognizer_HidesIndicatorWithoutNavigatingWhenReleasedAfterActivationBelowThreshold(t *testing.T) {
397 recognizer := newTouchpadNavigationRecognizer()
398 cfg := RuntimeInputConfig{
399 TouchpadNavigationEnabled: true,
400 TouchpadNavigationMinDelta: 200,
401 TouchpadNavigationMaxVerticalRatio: 0.5,
402 }
403
404 _ = recognizer.Handle(touchpadNavigationInput{
405 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseBegin, 0, 0),
406 Config: cfg,
407 CanGoBack: true,
408 ViewWidth: 1000,
409 })
410 progress := recognizer.Handle(touchpadNavigationInput{
411 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -120, 0),
412 Config: cfg,
413 CanGoBack: true,
414 })
415 require.True(t, progress.HasIndicator)
416 require.InDelta(t, 0.6, progress.Indicator.Progress, 0.001)
417 require.False(t, progress.Indicator.ThresholdReached)
418
419 end := recognizer.Handle(touchpadNavigationInput{
420 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseEnd, 0, 0),
421 Config: cfg,
422 CanGoBack: true,
423 })
424 require.False(t, end.HasAction)
425 require.True(t, end.HasIndicator)
426 require.False(t, end.Indicator.Active)
427}
428
429func TestTouchpadNavigationRecognizer_ResetsBetweenConsecutiveGestures(t *testing.T) {
430 recognizer := newTouchpadNavigationRecognizer()
431 cfg := RuntimeInputConfig{
432 TouchpadNavigationEnabled: true,
433 TouchpadNavigationMinDelta: 200,
434 TouchpadNavigationMaxVerticalRatio: 0.5,
435 }
436
437 _ = recognizer.Handle(touchpadNavigationInput{
438 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseBegin, 0, 0),
439 Config: cfg,
440 CanGoBack: true,
441 ViewWidth: 1000,
442 })
443 firstUpdate := recognizer.Handle(touchpadNavigationInput{
444 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -240, 0),
445 Config: cfg,
446 CanGoBack: true,
447 })
448 require.True(t, firstUpdate.HasIndicator)
449 firstEnd := recognizer.Handle(touchpadNavigationInput{
450 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseEnd, 0, 0),
451 Config: cfg,
452 CanGoBack: true,
453 })
454 require.True(t, firstEnd.HasAction)
455 require.Equal(t, cef2gtk.NavigationSwipeBack, firstEnd.Action)
456
457 _ = recognizer.Handle(touchpadNavigationInput{
458 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseBegin, 976, 0, 0),
459 Config: cfg,
460 CanGoForward: true,
461 ViewWidth: 1000,
462 })
463 secondUpdate := recognizer.Handle(touchpadNavigationInput{
464 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseUpdate, 976, 240, 0),
465 Config: cfg,
466 CanGoForward: true,
467 })
468 require.True(t, secondUpdate.HasIndicator)
469 require.Equal(t, entity.TouchpadNavigationForward, secondUpdate.Indicator.Action)
470 secondEnd := recognizer.Handle(touchpadNavigationInput{
471 Event: touchpadNavigationScrollEventAt(cef2gtk.ScrollPhaseEnd, 976, 0, 0),
472 Config: cfg,
473 CanGoForward: true,
474 })
475 require.True(t, secondEnd.HasAction)
476 require.Equal(t, cef2gtk.NavigationSwipeForward, secondEnd.Action)
477}
478
479func TestTouchpadNavigationRecognizer_CancelsVerticalGestures(t *testing.T) {
480 recognizer := newTouchpadNavigationRecognizer()
481 cfg := RuntimeInputConfig{
482 TouchpadNavigationEnabled: true,
483 TouchpadNavigationMinDelta: 200,
484 TouchpadNavigationMaxVerticalRatio: 0.5,
485 }
486
487 _ = recognizer.Handle(touchpadNavigationInput{
488 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseBegin, 0, 0),
489 Config: cfg,
490 CanGoBack: true,
491 ViewWidth: 1000,
492 })
493 vertical := recognizer.Handle(touchpadNavigationInput{
494 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -60, 80),
495 Config: cfg,
496 CanGoBack: true,
497 })
498 require.False(t, vertical.HasIndicator)
499 require.False(t, vertical.HasAction)
500
501 continued := recognizer.Handle(touchpadNavigationInput{
502 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -400, 0),
503 Config: cfg,
504 CanGoBack: true,
505 })
506 require.False(t, continued.HasIndicator)
507 require.False(t, continued.HasAction)
508
509 end := recognizer.Handle(touchpadNavigationInput{
510 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseEnd, 0, 0),
511 Config: cfg,
512 CanGoBack: true,
513 })
514 require.False(t, end.HasAction)
515}
516
517func TestTouchpadNavigationRecognizer_HidesVisibleIndicatorOnVerticalCancelAndResets(t *testing.T) {
518 recognizer := newTouchpadNavigationRecognizer()
519 cfg := RuntimeInputConfig{
520 TouchpadNavigationEnabled: true,
521 TouchpadNavigationMinDelta: 200,
522 TouchpadNavigationMaxVerticalRatio: 0.5,
523 }
524
525 _ = recognizer.Handle(touchpadNavigationInput{
526 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseBegin, 0, 0),
527 Config: cfg,
528 CanGoBack: true,
529 ViewWidth: 1000,
530 })
531 shown := recognizer.Handle(touchpadNavigationInput{
532 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -120, 0),
533 Config: cfg,
534 CanGoBack: true,
535 })
536 require.True(t, shown.HasIndicator)
537 require.True(t, shown.Indicator.Active)
538
539 canceled := recognizer.Handle(touchpadNavigationInput{
540 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, 0, 80),
541 Config: cfg,
542 CanGoBack: true,
543 })
544 require.True(t, canceled.HasIndicator)
545 require.False(t, canceled.Indicator.Active)
546 require.False(t, canceled.HasAction)
547
548 end := recognizer.Handle(touchpadNavigationInput{
549 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseEnd, 0, 0),
550 Config: cfg,
551 CanGoBack: true,
552 })
553 require.False(t, end.HasIndicator)
554 require.False(t, end.HasAction)
555
556 _ = recognizer.Handle(touchpadNavigationInput{
557 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseBegin, 0, 0),
558 Config: cfg,
559 CanGoBack: true,
560 ViewWidth: 1000,
561 })
562 valid := recognizer.Handle(touchpadNavigationInput{
563 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseUpdate, -240, 0),
564 Config: cfg,
565 CanGoBack: true,
566 })
567 require.True(t, valid.HasIndicator)
568 validEnd := recognizer.Handle(touchpadNavigationInput{
569 Event: touchpadNavigationScrollEvent(cef2gtk.ScrollPhaseEnd, 0, 0),
570 Config: cfg,
571 CanGoBack: true,
572 })
573 require.True(t, validEnd.HasAction)
574 require.Equal(t, cef2gtk.NavigationSwipeBack, validEnd.Action)
575}
576
577func touchpadNavigationScrollEvent(phase cef2gtk.ScrollPhase, dx, dy float64) cef2gtk.ScrollEvent {
578 return touchpadNavigationScrollEventAt(phase, 0, dx, dy)
579}
580
581// ViewWidth is provided separately on touchpadNavigationInput; the recognizer
582// caches it from the initial Begin event for subsequent Update and End phases.
583func touchpadNavigationScrollEventAt(phase cef2gtk.ScrollPhase, x, dx, dy float64) cef2gtk.ScrollEvent {
584 return cef2gtk.ScrollEvent{
585 Phase: phase,
586 X: x,
587 DX: dx,
588 DY: dy,
589 Unit: gdk.ScrollUnitSurfaceValue,
590 UnitKnown: true,
591 }
592}