1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4TestCase := Window {
5
6
7 width: 500phx;
8 height: 500phx;
9 no-frame: false;
10
11 f := Flickable {
12 x: 10phx;
13 y: 10phx;
14 width: parent.width - 20phx;
15 height: parent.height - 20phx;
16 viewport_width: 2100phx;
17 viewport_height: 2100phx;
18
19 flicked => {
20 root.flicked += viewport_x/1phx * 100000 + viewport_y/1phx;
21 }
22
23 inner_ta := TouchArea {
24 x: 150phx;
25 y: 150phx;
26 width: 50phx;
27 height: 50phx;
28 Rectangle {
29 background: parent.pressed ? blue : parent.has_hover ? green : red;
30 }
31 clicked => {
32 root.clicked = mouse_x/1phx * 100000 + mouse_y/1phx;
33 }
34 double-clicked => {
35 root.double-clicked = mouse_x/1phx * 100000 + mouse_y/1phx;
36 }
37 }
38
39 }
40
41 property<length> offset_x: -f.viewport_x;
42 property<length> offset_y: -f.viewport_y;
43 property<bool> inner_ta_pressed: inner_ta.pressed;
44 property<bool> inner_ta_has_hover: inner_ta.has_hover;
45 property<int> clicked;
46 property<int> double-clicked;
47 property <int> flicked;
48}
49
50/*
51
52```rust
53// Test that basic scrolling works, and that releasing the mouse animates
54use slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};
55let instance = TestCase::new().unwrap();
56instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(300.0, 100.0) });
57slint_testing::mock_elapsed_time(5000);
58instance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(300.0, 100.0), button: PointerEventButton::Left });
59assert_eq!(instance.get_offset_x(), 0.);
60assert_eq!(instance.get_offset_y(), 0.);
61instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(200.0, 50.0) });
62assert_eq!(instance.get_offset_x(), 100.);
63assert_eq!(instance.get_offset_y(), 50.);
64slint_testing::mock_elapsed_time(200);
65assert_eq!(instance.get_offset_x(), 100.);
66assert_eq!(instance.get_offset_y(), 50.);
67instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 50.0) });
68assert_eq!(instance.get_offset_x(), 200.);
69assert_eq!(instance.get_offset_y(), 50.);
70instance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(100.0, 50.0), button: PointerEventButton::Left });
71// Start of the animation, the position is still unchanged
72assert_eq!(instance.get_offset_x(), 200.);
73assert_eq!(instance.get_offset_y(), 50.);
74slint_testing::mock_elapsed_time(50);
75// middle of the animation
76assert!(instance.get_offset_x() > 210.);
77assert!(instance.get_offset_y() > 60.);
78assert!(instance.get_offset_x() < 290.);
79assert!(instance.get_offset_y() < 70.);
80
81slint_testing::mock_elapsed_time(200);
82// end of the animation
83assert_eq!(instance.get_offset_x(), 450.);
84assert_eq!(instance.get_offset_y(), 112.5);
85slint_testing::mock_elapsed_time(50);
86assert_eq!(instance.get_offset_x(), 450.);
87assert_eq!(instance.get_offset_y(), 112.5);
88
89assert!(!instance.get_inner_ta_pressed());
90assert!(!instance.get_inner_ta_has_hover());
91assert_eq!(instance.get_clicked(), 0);
92assert_eq!(instance.get_double_clicked(), 0);
93```
94
95```rust
96// Test interaction with inner mouse area
97use slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};
98let instance = TestCase::new().unwrap();
99instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(175.0, 175.0) });
100assert!(!instance.get_inner_ta_pressed());
101assert!(instance.get_inner_ta_has_hover());
102assert_eq!(instance.get_clicked(), 0);
103assert_eq!(instance.get_double_clicked(), 0);
104slint_testing::mock_elapsed_time(5000);
105assert!(!instance.get_inner_ta_pressed());
106assert!(instance.get_inner_ta_has_hover());
107assert_eq!(instance.get_clicked(), 0);
108assert_eq!(instance.get_double_clicked(), 0);
109
110// Start a press
111instance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(175.0, 175.0), button: PointerEventButton::Left });
112//assert!(!instance.get_inner_ta_pressed());
113assert!(instance.get_inner_ta_has_hover());
114assert_eq!(instance.get_clicked(), 0);
115assert_eq!(instance.get_double_clicked(), 0);
116// Release almost immediately
117instance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(178.0, 173.0), button: PointerEventButton::Left });
118assert!(!instance.get_inner_ta_pressed());
119assert!(instance.get_inner_ta_has_hover());
120assert_eq!(instance.get_clicked(), 18_00013);
121assert_eq!(instance.get_double_clicked(), 0);
122assert_eq!(instance.get_offset_x(), 0.);
123assert_eq!(instance.get_offset_y(), 0.);
124
125instance.set_clicked(-1);
126
127slint_testing::mock_elapsed_time(1000);
128
129// - Press, move a triny, then release quickly: should click
130// Start a press
131instance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(165.0, 175.0), button: PointerEventButton::Left });
132assert!(!instance.get_inner_ta_pressed());
133assert!(instance.get_inner_ta_has_hover());
134assert_eq!(instance.get_clicked(), -1);
135// make a small move
136instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(166.0, 174.0) });
137assert!(!instance.get_inner_ta_pressed());
138assert!(instance.get_inner_ta_has_hover());
139slint_testing::mock_elapsed_time(30);
140instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(167.0, 175.0) });
141assert!(!instance.get_inner_ta_pressed());
142// and release
143instance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(165.0, 174.0), button: PointerEventButton::Left });
144assert!(!instance.get_inner_ta_pressed());
145assert!(instance.get_inner_ta_has_hover());
146assert_eq!(instance.get_clicked(), 5_00014);
147assert_eq!(instance.get_double_clicked(), 0);
148assert_eq!(instance.get_offset_x(), 0.);
149assert_eq!(instance.get_offset_y(), 0.);
150
151instance.set_clicked(-1);
152// - Same but over a longer period (long press) so it should be pressed
153
154// Start a press
155instance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(165.0, 175.0), button: PointerEventButton::Left });
156assert!(!instance.get_inner_ta_pressed());
157assert!(instance.get_inner_ta_has_hover());
158assert_eq!(instance.get_clicked(), -1);
159// make a small move
160instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(166.0, 174.0) });
161assert!(!instance.get_inner_ta_pressed());
162assert!(instance.get_inner_ta_has_hover());
163slint_testing::mock_elapsed_time(30);
164instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(167.0, 175.0) });
165assert!(!instance.get_inner_ta_pressed());
166slint_testing::mock_elapsed_time(300);
167assert!(instance.get_inner_ta_pressed(), "now we should be marked as pressed");
168instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(166.0, 175.0) });
169assert!(instance.get_inner_ta_pressed(), "still pressed");
170slint_testing::mock_elapsed_time(30);
171assert!(instance.get_inner_ta_pressed(), "still pressed");
172// and release
173instance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(167.0, 174.0), button: PointerEventButton::Left });
174assert!(!instance.get_inner_ta_pressed());
175assert!(instance.get_inner_ta_has_hover());
176assert_eq!(instance.get_clicked(), 7_00014);
177assert_eq!(instance.get_double_clicked(), 7_00014);
178assert_eq!(instance.get_offset_x(), 0.);
179assert_eq!(instance.get_offset_y(), 0.);
180
181instance.set_double_clicked(0);
182instance.set_clicked(-1);
183
184// Start a press
185instance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(175.0, 175.0), button: PointerEventButton::Left });
186assert!(!instance.get_inner_ta_pressed());
187assert!(instance.get_inner_ta_has_hover());
188assert_eq!(instance.get_clicked(), -1);
189assert_eq!(instance.get_double_clicked(), 0);
190assert_eq!(instance.get_offset_x(), 0.);
191assert_eq!(instance.get_offset_y(), 0.);
192
193//wait a delay
194slint_testing::mock_elapsed_time(300);
195assert!(instance.get_inner_ta_pressed()); // only now we are pressed
196assert!(instance.get_inner_ta_has_hover());
197assert_eq!(instance.get_clicked(), -1);
198assert_eq!(instance.get_double_clicked(), 0);
199assert_eq!(instance.get_offset_x(), 0.);
200assert_eq!(instance.get_offset_y(), 0.);
201
202instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 120.0) });
203assert!(!instance.get_inner_ta_pressed()); // We should no longer be pressed
204// no hover when the flickable is flicking
205assert!(!instance.get_inner_ta_has_hover());
206assert_eq!(instance.get_clicked(), -1); // not clicked
207assert_eq!(instance.get_offset_x(), 75.);
208assert_eq!(instance.get_offset_y(), 55.);
209
210slint_testing::mock_elapsed_time(10000);
211
212instance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(100.0, 120.0), button: PointerEventButton::Left });
213assert!(!instance.get_inner_ta_pressed());
214assert!(instance.get_inner_ta_has_hover());
215assert_eq!(instance.get_clicked(), -1); // not clicked
216assert_eq!(instance.get_double_clicked(), 0);
217assert_eq!(instance.get_offset_x(), 75.);
218assert_eq!(instance.get_offset_y(), 55.);
219
220instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(200.0, 50.0) });
221slint_testing::mock_elapsed_time(1000);
222
223assert!(!instance.get_inner_ta_pressed());
224assert!(!instance.get_inner_ta_has_hover());
225assert_eq!(instance.get_clicked(), -1);
226assert_eq!(instance.get_double_clicked(), 0);
227assert!((instance.get_offset_x() - 75.).abs() < 5.); // only small animation on release
228assert!((instance.get_offset_y() - 55.).abs() < 5.);
229```
230
231```rust
232// Test wheel events
233use slint::{LogicalPosition, platform::{WindowEvent, Key} };
234let instance = TestCase::new().unwrap();
235instance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(175.0, 175.0), delta_x: -30.0, delta_y: -50.0 });
236assert_eq!(instance.get_offset_x(), 30.);
237assert_eq!(instance.get_offset_y(), 50.);
238
239// When shift is pressed, it invert the direction
240// (this test don't work on macos because on macos the backend does the inversion, not the core lib)
241if !cfg!(target_os = "macos") {
242 slint_testing::send_keyboard_char(&instance, Key::Shift.into(), true);
243 instance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(175.0, 175.0), delta_x: 15.0, delta_y: -60.0 });
244 slint_testing::send_keyboard_char(&instance, Key::Shift.into(), false);
245 assert_eq!(instance.get_offset_x(), 30. + 60.);
246 assert_eq!(instance.get_offset_y(), 50. - 15.);
247}
248```
249
250```rust
251// Test flicked-Callback behaviour
252use slint::{LogicalPosition, platform::{WindowEvent, PointerEventButton} };
253let instance = TestCase::new().unwrap();
254assert_eq!(instance.get_flicked(), 0);
255
256// test scrolling behaviour
257instance.window().dispatch_event(WindowEvent::PointerScrolled { position: LogicalPosition::new(175.0, 175.0), delta_x: -30.0, delta_y: -50.0 });
258dbg!(instance.get_flicked());
259assert_eq!(instance.get_flicked(), -3000050); //flicked got called after scrolling
260instance.set_flicked(0);
261
262// test dragging bevaviour
263instance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(175.0, 175.0), button: PointerEventButton::Left });
264slint_testing::mock_elapsed_time(300);
265assert_eq!(instance.get_flicked(), 0); //flicked didn't get called by just pressing
266instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 120.0) });
267slint_testing::mock_elapsed_time(10000);
268assert_eq!(instance.get_flicked(), -10500105); //flicked got called during drag
269instance.set_flicked(0);
270instance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(100.0, 120.0), button: PointerEventButton::Left });
271assert_eq!(instance.get_flicked(), -10500105); //flicked got called after drag
272instance.set_flicked(0);
273
274```
275
276```rust
277// Test double click
278// Test interaction with inner mouse area
279use slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};
280let instance = TestCase::new().unwrap();
281instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(175.0, 175.0) });
282assert!(instance.get_inner_ta_has_hover());
283assert_eq!(instance.get_clicked(), 0);
284assert_eq!(instance.get_double_clicked(), 0);
285slint_testing::mock_elapsed_time(5000);
286assert!(!instance.get_inner_ta_pressed());
287assert!(instance.get_inner_ta_has_hover());
288assert_eq!(instance.get_clicked(), 0);
289assert_eq!(instance.get_double_clicked(), 0);
290
291// Start a press
292instance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(175.0, 175.0), button: PointerEventButton::Left });
293assert_eq!(instance.get_clicked(), 0);
294assert_eq!(instance.get_double_clicked(), 0);
295slint_testing::mock_elapsed_time(50);
296instance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(178.0, 173.0), button: PointerEventButton::Left });
297assert!(!instance.get_inner_ta_pressed());
298assert!(instance.get_inner_ta_has_hover());
299assert_eq!(instance.get_clicked(), 18_00013);
300assert_eq!(instance.get_double_clicked(), 0);
301assert_eq!(instance.get_offset_x(), 0.);
302assert_eq!(instance.get_offset_y(), 0.);
303instance.set_clicked(0);
304
305// second press after 50ms
306slint_testing::mock_elapsed_time(50);
307instance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(176.0, 174.0), button: PointerEventButton::Left });
308assert_eq!(instance.get_clicked(), 0);
309assert_eq!(instance.get_double_clicked(), 0);
310slint_testing::mock_elapsed_time(50);
311instance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(175.0, 176.0), button: PointerEventButton::Left });
312assert!(!instance.get_inner_ta_pressed());
313assert!(instance.get_inner_ta_has_hover());
314assert_eq!(instance.get_clicked(), 15_00016);
315assert_eq!(instance.get_double_clicked(), 15_00016);
316assert_eq!(instance.get_offset_x(), 0.);
317assert_eq!(instance.get_offset_y(), 0.);
318```
319
320```rust
321// Same as first test, but wait a bit before moving the mouse, and move only a tiny ()
322use slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};
323let instance = TestCase::new().unwrap();
324instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(300.0, 100.0) });
325slint_testing::mock_elapsed_time(5000);
326instance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(300.0, 100.0), button: PointerEventButton::Left });
327assert_eq!(instance.get_offset_x(), 0.);
328assert_eq!(instance.get_offset_y(), 0.);
329slint_testing::mock_elapsed_time(500);
330instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(299.0, 99.0) });
331slint_testing::mock_elapsed_time(500);
332assert_eq!(instance.get_offset_x(), 0.);
333assert_eq!(instance.get_offset_y(), 0.);
334instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(200.0, 50.0) });
335assert_eq!(instance.get_offset_x(), 100.);
336assert_eq!(instance.get_offset_y(), 50.);
337slint_testing::mock_elapsed_time(200);
338assert_eq!(instance.get_offset_x(), 100.);
339assert_eq!(instance.get_offset_y(), 50.);
340instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(100.0, 50.0) });
341assert_eq!(instance.get_offset_x(), 200.);
342assert_eq!(instance.get_offset_y(), 50.);
343instance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(100.0, 50.0), button: PointerEventButton::Left });
344// Start of the animation, the position is still unchanged
345assert_eq!(instance.get_offset_x(), 200.);
346assert_eq!(instance.get_offset_y(), 50.);
347slint_testing::mock_elapsed_time(50);
348// middle of the animation
349// NOTE: the value were changed compared to the first test because the timing is different
350assert!(instance.get_offset_x() > 201.);
351assert!(instance.get_offset_y() > 41.);
352assert!(instance.get_offset_x() < 290.);
353assert!(instance.get_offset_y() < 70.);
354
355// end of the animation
356slint_testing::mock_elapsed_time(300);
357
358assert!(!instance.get_inner_ta_pressed());
359assert!(!instance.get_inner_ta_has_hover());
360assert_eq!(instance.get_clicked(), 0);
361assert_eq!(instance.get_double_clicked(), 0);
362```
363
364*/
365
366