1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** GUIX Component */
17 /** */
18 /** Scroll Wheel Management (Scroll Wheel) */
19 /** */
20 /**************************************************************************/
21
22 #define GX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "gx_api.h"
28 #include "gx_system.h"
29 #include "gx_window.h"
30 #include "gx_widget.h"
31 #include "gx_utility.h"
32 #include "gx_scroll_wheel.h"
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _gx_scroll_wheel_timer_event_handler PORTABLE C */
39 /* 6.1.7 */
40 /* AUTHOR */
41 /* */
42 /* Kenneth Maxwell, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* Internal helper function to handle timer event for scroll wheel */
47 /* widget. */
48 /* */
49 /* INPUT */
50 /* */
51 /* wheel Scroll wheel control block */
52 /* timer_id Id of the handled timer */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* status Completion status */
57 /* */
58 /* CALLS */
59 /* */
60 /* _gx_system_timer_start Start a timer for a widget */
61 /* _gx_system_timer_stop Stop a timer for a widget */
62 /* _gx_system_dirty_mark Mark a widget as dirty */
63 /* _gx_scroll_wheel_scroll Scroll a scroll wheel widget */
64 /* _gx_widget_event_generate Create an event and send it */
65 /* to parent */
66 /* */
67 /* CALLED BY */
68 /* */
69 /* _gx_scroll_wheel_event_process */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
76 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
77 /* resulting in version 6.1 */
78 /* 06-02-2021 Ting Zhu Modified comment(s), */
79 /* updated with scroll wheel */
80 /* control block members, */
81 /* resulting in version 6.1.7 */
82 /* */
83 /**************************************************************************/
_gx_scroll_wheel_timer_event_handler(GX_SCROLL_WHEEL * wheel,UINT timer_id)84 static UINT _gx_scroll_wheel_timer_event_handler(GX_SCROLL_WHEEL *wheel, UINT timer_id)
85 {
86 GX_WIDGET *widget = (GX_WIDGET *)wheel;
87 INT shift;
88 INT increment;
89 GX_BOOL generate_event = GX_FALSE;
90
91 switch(timer_id)
92 {
93 case GX_SNAP_TIMER:
94 /* Handle snap timer. */
95 if (GX_ABS(wheel -> gx_scroll_wheel_selected_yshift) < GX_ABS(wheel -> gx_scroll_wheel_row_height) / 3)
96 {
97 _gx_system_timer_stop(widget, GX_SNAP_TIMER);
98 generate_event = GX_TRUE;
99 shift = wheel -> gx_scroll_wheel_selected_yshift;
100 }
101 else
102 {
103 if (wheel -> gx_scroll_wheel_selected_yshift > 0)
104 {
105 shift = wheel -> gx_scroll_wheel_row_height / 3;
106 }
107 else
108 {
109 shift = (GX_VALUE)(-wheel -> gx_scroll_wheel_row_height / 3);
110 }
111 }
112
113 wheel -> gx_scroll_wheel_scroll(wheel, (GX_VALUE)(-shift));
114 break;
115
116 case GX_FLICK_TIMER:
117 /* Handle flick timer. */
118
119 wheel -> gx_scroll_wheel_animation_steps--;
120 shift = wheel -> gx_scroll_wheel_animation_speed;
121
122 if (wheel -> gx_scroll_wheel_shift_error)
123 {
124 shift += wheel -> gx_scroll_wheel_shift_error;
125 wheel -> gx_scroll_wheel_shift_error = 0;
126 }
127
128 wheel -> gx_scroll_wheel_scroll(wheel, (GX_VALUE)shift);
129
130 if (wheel -> gx_scroll_wheel_animation_steps > 0)
131 {
132 increment = (wheel -> gx_scroll_wheel_animation_end_speed - wheel -> gx_scroll_wheel_animation_speed) /
133 wheel -> gx_scroll_wheel_animation_steps;
134
135 wheel -> gx_scroll_wheel_animation_speed = (GX_VALUE)(wheel -> gx_scroll_wheel_animation_speed + increment);
136 }
137
138 if (!wheel -> gx_scroll_wheel_wrap_style_check(wheel))
139 {
140 if ((wheel -> gx_scroll_wheel_selected_row == 0 && wheel -> gx_scroll_wheel_selected_yshift > 0) ||
141 (wheel -> gx_scroll_wheel_selected_row == wheel -> gx_scroll_wheel_total_rows - 1 &&
142 wheel -> gx_scroll_wheel_selected_yshift < 0))
143 {
144 wheel -> gx_scroll_wheel_animation_steps = 0;
145 }
146 }
147
148 if (wheel -> gx_scroll_wheel_animation_steps == 0)
149 {
150 _gx_system_timer_stop(widget, GX_FLICK_TIMER);
151
152 if (wheel -> gx_scroll_wheel_selected_yshift)
153 {
154 _gx_system_timer_start((GX_WIDGET *)wheel, GX_SNAP_TIMER, 1, 1);
155 }
156 else
157 {
158 generate_event = GX_TRUE;
159 }
160 }
161 break;
162
163 case GX_ANIMATION_TIMER:
164 /* Handle animation timer. */
165 wheel -> gx_scroll_wheel_animation_steps--;
166
167 if (wheel -> gx_scroll_wheel_shift_error)
168 {
169 wheel -> gx_scroll_wheel_scroll(wheel, wheel -> gx_scroll_wheel_shift_error);
170 wheel -> gx_scroll_wheel_shift_error = 0;
171 }
172
173 wheel -> gx_scroll_wheel_scroll(wheel, wheel -> gx_scroll_wheel_animation_speed);
174
175 if (wheel -> gx_scroll_wheel_animation_steps == 0)
176 {
177 _gx_system_timer_stop(widget, GX_ANIMATION_TIMER);
178
179 if (wheel -> gx_scroll_wheel_selected_yshift)
180 {
181 _gx_system_timer_start((GX_WIDGET *)wheel, GX_SNAP_TIMER, 1, 1);
182 }
183 else
184 {
185 generate_event = GX_TRUE;
186 }
187 }
188 break;
189 }
190
191 if (wheel -> gx_widget_id && generate_event)
192 {
193 _gx_widget_event_generate((GX_WIDGET *)wheel, GX_EVENT_LIST_SELECT, wheel -> gx_scroll_wheel_selected_row);
194 }
195
196 return GX_SUCCESS;
197 }
198
199 /**************************************************************************/
200 /* */
201 /* FUNCTION RELEASE */
202 /* */
203 /* _gx_scroll_wheel_flick_event_handler PORTABLE C */
204 /* 6.1 */
205 /* AUTHOR */
206 /* */
207 /* Kenneth Maxwell, Microsoft Corporation */
208 /* */
209 /* DESCRIPTION */
210 /* */
211 /* Internal helper function to handle flick event for scrol wheel */
212 /* widget. */
213 /* */
214 /* INPUT */
215 /* */
216 /* wheel Scroll wheel control block */
217 /* flick_speed Flick speed */
218 /* */
219 /* OUTPUT */
220 /* */
221 /* status Completion status */
222 /* */
223 /* CALLS */
224 /* */
225 /* _gx_system_timer_start Start a timer for a widget */
226 /* _gx_system_timer_stop Stop a timer for a widget */
227 /* */
228 /* CALLED BY */
229 /* */
230 /* _gx_scroll_wheel_event_process */
231 /* */
232 /* RELEASE HISTORY */
233 /* */
234 /* DATE NAME DESCRIPTION */
235 /* */
236 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
237 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
238 /* resulting in version 6.1 */
239 /* */
240 /**************************************************************************/
_gx_scroll_wheel_flick_event_handler(GX_SCROLL_WHEEL * wheel,INT flick_speed)241 static UINT _gx_scroll_wheel_flick_event_handler(GX_SCROLL_WHEEL *wheel, INT flick_speed)
242 {
243 INT shift;
244 INT start_speed;
245 INT end_speed;
246 INT total_steps;
247 INT speed;
248
249 shift = flick_speed / GX_FIXED_VAL_HALF;
250
251 if ((GX_ABS(shift) > 5) &&
252 (wheel -> gx_scroll_wheel_total_rows))
253 {
254 _gx_system_timer_stop((GX_WIDGET *)wheel, GX_SNAP_TIMER);
255
256 if (GX_ABS(shift) < wheel -> gx_scroll_wheel_row_height / 3)
257 {
258 shift /= GX_ABS(shift);
259 shift *= wheel -> gx_scroll_wheel_row_height / 3;
260 }
261 start_speed = (wheel -> gx_scroll_wheel_animation_start_speed_rate * shift) >> GX_FIXED_VAL_SHIFT;
262 end_speed = (wheel -> gx_scroll_wheel_animation_end_speed_rate * shift) >> GX_FIXED_VAL_SHIFT;
263
264 if (GX_ABS(end_speed) < wheel -> gx_scroll_wheel_row_height / 10)
265 {
266 end_speed = wheel -> gx_scroll_wheel_row_height / 10;
267
268 if (shift < 0)
269 {
270 end_speed = -end_speed;
271 }
272 }
273
274 total_steps = GX_ABS(shift) / 2;
275
276 if (total_steps > wheel -> gx_scroll_wheel_animation_max_steps)
277 {
278 total_steps = wheel -> gx_scroll_wheel_animation_max_steps;
279 }
280
281 wheel -> gx_scroll_wheel_animation_speed = (GX_VALUE)start_speed;
282 wheel -> gx_scroll_wheel_animation_end_speed = (GX_VALUE)end_speed;
283 wheel -> gx_scroll_wheel_animation_steps = (GX_VALUE)total_steps;
284
285 speed = start_speed;
286 shift = start_speed;
287 while (total_steps > 1)
288 {
289 total_steps--;
290 speed += (end_speed - speed) / total_steps;
291
292 shift += speed;
293
294 if (GX_ABS(shift) > wheel -> gx_scroll_wheel_row_height)
295 {
296 shift %= wheel -> gx_scroll_wheel_row_height;
297 }
298 }
299
300 if (start_speed > 0)
301 {
302 shift += wheel -> gx_scroll_wheel_selected_yshift;
303 shift %= wheel -> gx_scroll_wheel_row_height;
304 if (shift < 0)
305 {
306 wheel -> gx_scroll_wheel_shift_error = (GX_VALUE)(-shift);
307 }
308 else if (shift > 0)
309 {
310 wheel -> gx_scroll_wheel_shift_error = (GX_VALUE)(wheel -> gx_scroll_wheel_row_height - shift);
311 }
312 }
313 else if (start_speed < 0)
314 {
315 shift += wheel -> gx_scroll_wheel_selected_yshift;
316 shift %= wheel -> gx_scroll_wheel_row_height;
317
318 if (shift < 0)
319 {
320 wheel -> gx_scroll_wheel_shift_error = (GX_VALUE)(-shift - wheel -> gx_scroll_wheel_row_height);
321 }
322 else if (shift > 0)
323 {
324 wheel -> gx_scroll_wheel_shift_error = (GX_VALUE)(-shift);
325 }
326 }
327
328 /* Start flick timer. */
329 _gx_system_timer_start((GX_WIDGET *) wheel, GX_FLICK_TIMER,
330 (UINT)wheel -> gx_scroll_wheel_animation_delay,
331 (UINT)wheel -> gx_scroll_wheel_animation_delay);
332 }
333
334 return GX_SUCCESS;
335 }
336
337 /**************************************************************************/
338 /* */
339 /* FUNCTION RELEASE */
340 /* */
341 /* _gx_scroll_wheel_pen_up_event_handler PORTABLE C */
342 /* 6.1.4 */
343 /* AUTHOR */
344 /* */
345 /* Kenneth Maxwell, Microsoft Corporation */
346 /* */
347 /* DESCRIPTION */
348 /* */
349 /* Internal helper function to handle pen up event for scroll wheel */
350 /* widget. */
351 /* */
352 /* INPUT */
353 /* */
354 /* wheel Scroll wheel control block */
355 /* */
356 /* OUTPUT */
357 /* */
358 /* status Completion status */
359 /* */
360 /* CALLS */
361 /* */
362 /* _gx_system_timer_start Start a timer for a widget */
363 /* _gx_system_dirty_partial_add Mark partial area of a widget */
364 /* as dirty */
365 /* _gx_widget_event_generate Create an event and send it to*/
366 /* parent */
367 /* */
368 /* CALLED BY */
369 /* */
370 /* _gx_scroll_wheel_event_process */
371 /* */
372 /* RELEASE HISTORY */
373 /* */
374 /* DATE NAME DESCRIPTION */
375 /* */
376 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
377 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
378 /* resulting in version 6.1 */
379 /* 02-02-2021 Kenneth Maxwell Modified comment(s), */
380 /* renamed */
381 /* GX_STYLE_SCROLL_WHEEL_DRAG */
382 /* to GX_STATUS_TRACKING_PEN, */
383 /* resulting in version 6.1.4 */
384 /* */
385 /**************************************************************************/
_gx_scroll_wheel_pen_up_event_handler(GX_SCROLL_WHEEL * wheel)386 static UINT _gx_scroll_wheel_pen_up_event_handler(GX_SCROLL_WHEEL *wheel)
387 {
388 GX_RECTANGLE dirty;
389
390 wheel -> gx_widget_status &= (ULONG)(~GX_STATUS_TRACKING_PEN);
391
392 if (wheel -> gx_scroll_wheel_selected_yshift)
393 {
394 /* Start a timer to move selected item to center. */
395 _gx_system_timer_start((GX_WIDGET *)wheel, GX_SNAP_TIMER, 1, 1);
396 }
397 else
398 {
399 /* Mark center area dirty. */
400 dirty = wheel -> gx_window_client;
401 dirty.gx_rectangle_top = (GX_VALUE)(dirty.gx_rectangle_top + (dirty.gx_rectangle_bottom - dirty.gx_rectangle_top + 1) / 2);
402 dirty.gx_rectangle_top = (GX_VALUE)(dirty.gx_rectangle_top - (wheel -> gx_scroll_wheel_row_height >> 1));
403 dirty.gx_rectangle_bottom = (GX_VALUE)(dirty.gx_rectangle_top + wheel -> gx_scroll_wheel_row_height - 1);
404 _gx_system_dirty_partial_add((GX_WIDGET *)wheel, &dirty);
405
406 if (wheel -> gx_widget_id)
407 {
408 /* Generate a list selected event. */
409 _gx_widget_event_generate((GX_WIDGET *)wheel, GX_EVENT_LIST_SELECT, wheel -> gx_scroll_wheel_selected_row);
410 }
411 }
412
413 return GX_SUCCESS;
414 }
415
416 /**************************************************************************/
417 /* */
418 /* FUNCTION RELEASE */
419 /* */
420 /* _gx_scroll_wheel_event_process PORTABLE C */
421 /* 6.1.7 */
422 /* AUTHOR */
423 /* */
424 /* Kenneth Maxwell, Microsoft Corporation */
425 /* */
426 /* DESCRIPTION */
427 /* */
428 /* This function processes the comming events for a scroll wheel */
429 /* widget. */
430 /* */
431 /* INPUT */
432 /* */
433 /* wheel Text scroll wheel control */
434 /* block */
435 /* event_ptr Event to be processed */
436 /* */
437 /* OUTPUT */
438 /* */
439 /* status Completion status */
440 /* */
441 /* CALLS */
442 /* */
443 /* _gx_system_input_capture Temporarily direct all inputs */
444 /* to specified widget */
445 /* _gx_system_input_release Release captured input events */
446 /* _gx_window_event_process Default window event process */
447 /* _gx_widget_event_to_parent Send event to widget's parent */
448 /* _gx_scroll_wheel_scroll Scroll a scroll wheel widget */
449 /* _gx_scroll_wheel_pen_up_event_handler Handle pen up event */
450 /* _gx_scroll_wheel_flick_event_handler Handle flick event */
451 /* _gx_scroll_wheel_timer_event_handler Handle timer event */
452 /* _gx_scroll_wheel_gradient_create Create a gradient pixelmap */
453 /* _gx_utility_gradient_delete Delete a gradient */
454 /* CALLED BY */
455 /* */
456 /* Application Code */
457 /* GUIX Internal Code */
458 /* */
459 /* RELEASE HISTORY */
460 /* */
461 /* DATE NAME DESCRIPTION */
462 /* */
463 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
464 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
465 /* resulting in version 6.1 */
466 /* 02-02-2021 Kenneth Maxwell Modified comment(s), */
467 /* renamed */
468 /* GX_STYLE_SCROLL_WHEEL_DRAG */
469 /* to GX_STATUS_TRACKING_PEN, */
470 /* resulting in version 6.1.4 */
471 /* 06-02-2021 Ting Zhu Modified comment(s), */
472 /* updated with scroll wheel */
473 /* control block change, */
474 /* resulting in version 6.1.7 */
475 /* */
476 /**************************************************************************/
_gx_scroll_wheel_event_process(GX_SCROLL_WHEEL * wheel,GX_EVENT * event_ptr)477 UINT _gx_scroll_wheel_event_process(GX_SCROLL_WHEEL *wheel, GX_EVENT *event_ptr)
478 {
479 GX_VALUE shift;
480
481 switch (event_ptr -> gx_event_type)
482 {
483 case GX_EVENT_PEN_DOWN:
484 if (wheel -> gx_scroll_wheel_total_rows)
485 {
486 _gx_system_input_capture((GX_WIDGET *)wheel);
487 wheel -> gx_window_move_start = event_ptr -> gx_event_payload.gx_event_pointdata;
488 wheel -> gx_scroll_wheel_shift_error = 0;
489 }
490 break;
491
492 case GX_EVENT_PEN_DRAG:
493 if (wheel -> gx_widget_status & GX_STATUS_OWNS_INPUT)
494 {
495 wheel -> gx_widget_status |= GX_STATUS_TRACKING_PEN;
496 shift = (GX_VALUE)(event_ptr -> gx_event_payload.gx_event_pointdata.gx_point_y - wheel -> gx_window_move_start.gx_point_y);
497 if (shift)
498 {
499 wheel -> gx_scroll_wheel_scroll(wheel, shift);
500
501 wheel -> gx_window_move_start = event_ptr -> gx_event_payload.gx_event_pointdata;
502 }
503 }
504 else
505 {
506 _gx_widget_event_to_parent((GX_WIDGET *)wheel, event_ptr);
507 }
508 break;
509
510 case GX_EVENT_PEN_UP:
511 if (wheel -> gx_widget_status & GX_STATUS_OWNS_INPUT)
512 {
513 _gx_system_input_release((GX_WIDGET *)wheel);
514 _gx_scroll_wheel_pen_up_event_handler(wheel);
515 }
516 else
517 {
518 _gx_widget_event_to_parent((GX_WIDGET *)wheel, event_ptr);
519 }
520 break;
521
522 case GX_EVENT_VERTICAL_FLICK:
523 _gx_scroll_wheel_flick_event_handler(wheel, event_ptr -> gx_event_payload.gx_event_intdata[0]);
524 break;
525
526 case GX_EVENT_TIMER:
527 _gx_scroll_wheel_timer_event_handler(wheel, event_ptr -> gx_event_payload.gx_event_timer_id);
528 break;
529
530 case GX_EVENT_SHOW:
531 _gx_window_event_process((GX_WINDOW *)wheel, event_ptr);
532 _gx_scroll_wheel_gradient_create(wheel);
533 break;
534
535 case GX_EVENT_DELETE:
536 _gx_utility_gradient_delete(&wheel -> gx_scroll_wheel_gradient);
537 break;
538
539 default:
540 return _gx_window_event_process((GX_WINDOW *)wheel, event_ptr);
541 }
542
543 return GX_SUCCESS;
544 }
545
546