GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_scroll_wheel_event_process.c Lines: 148 148 100.0 %
Date: 2024-12-05 08:52:37 Branches: 86 86 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 *
4
 * This program and the accompanying materials are made available under the
5
 * terms of the MIT License which is available at
6
 * https://opensource.org/licenses/MIT.
7
 *
8
 * SPDX-License-Identifier: MIT
9
 **************************************************************************/
10
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** GUIX Component                                                        */
16
/**                                                                       */
17
/**   Scroll Wheel Management (Scroll Wheel)                              */
18
/**                                                                       */
19
/**************************************************************************/
20
21
#define GX_SOURCE_CODE
22
23
24
/* Include necessary system files.  */
25
26
#include "gx_api.h"
27
#include "gx_system.h"
28
#include "gx_window.h"
29
#include "gx_widget.h"
30
#include "gx_utility.h"
31
#include "gx_scroll_wheel.h"
32
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _gx_scroll_wheel_timer_event_handler                PORTABLE C      */
38
/*                                                           6.1.7        */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    Kenneth Maxwell, Microsoft Corporation                              */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    Internal helper function to handle timer event for scroll wheel     */
46
/*    widget.                                                             */
47
/*                                                                        */
48
/*  INPUT                                                                 */
49
/*                                                                        */
50
/*    wheel                                 Scroll wheel control block    */
51
/*    timer_id                              Id of the handled timer       */
52
/*                                                                        */
53
/*  OUTPUT                                                                */
54
/*                                                                        */
55
/*    status                                Completion status             */
56
/*                                                                        */
57
/*  CALLS                                                                 */
58
/*                                                                        */
59
/*    _gx_system_timer_start                Start a timer for a widget    */
60
/*    _gx_system_timer_stop                 Stop a timer for a widget     */
61
/*    _gx_system_dirty_mark                 Mark a widget as dirty        */
62
/*    _gx_scroll_wheel_scroll               Scroll a scroll wheel widget  */
63
/*    _gx_widget_event_generate             Create an event and send it   */
64
/*                                            to parent                   */
65
/*                                                                        */
66
/*  CALLED BY                                                             */
67
/*                                                                        */
68
/*    _gx_scroll_wheel_event_process                                      */
69
/*                                                                        */
70
/*  RELEASE HISTORY                                                       */
71
/*                                                                        */
72
/*    DATE              NAME                      DESCRIPTION             */
73
/*                                                                        */
74
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
75
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
76
/*                                            resulting in version 6.1    */
77
/*  06-02-2021     Ting Zhu                 Modified comment(s),          */
78
/*                                            updated with scroll wheel   */
79
/*                                            control block members,      */
80
/*                                            resulting in version 6.1.7  */
81
/*                                                                        */
82
/**************************************************************************/
83
451
static UINT _gx_scroll_wheel_timer_event_handler(GX_SCROLL_WHEEL *wheel, UINT timer_id)
84
{
85
451
GX_WIDGET *widget = (GX_WIDGET *)wheel;
86
INT        shift;
87
INT        increment;
88
451
GX_BOOL    generate_event = GX_FALSE;
89
90

451
    switch(timer_id)
91
    {
92
89
    case GX_SNAP_TIMER:
93
        /* Handle snap timer. */
94
89
        if (GX_ABS(wheel -> gx_scroll_wheel_selected_yshift) < GX_ABS(wheel -> gx_scroll_wheel_row_height) / 3)
95
        {
96
51
            _gx_system_timer_stop(widget, GX_SNAP_TIMER);
97
51
            generate_event = GX_TRUE;
98
51
            shift = wheel -> gx_scroll_wheel_selected_yshift;
99
        }
100
        else
101
        {
102
38
            if (wheel -> gx_scroll_wheel_selected_yshift > 0)
103
            {
104
22
                shift = wheel -> gx_scroll_wheel_row_height / 3;
105
            }
106
            else
107
            {
108
16
                shift = (GX_VALUE)(-wheel -> gx_scroll_wheel_row_height / 3);
109
            }
110
        }
111
112
89
        wheel -> gx_scroll_wheel_scroll(wheel, (GX_VALUE)(-shift));
113
89
        break;
114
115
121
    case GX_FLICK_TIMER:
116
        /* Handle flick timer. */
117
118
121
        wheel -> gx_scroll_wheel_animation_steps--;
119
121
        shift = wheel -> gx_scroll_wheel_animation_speed;
120
121
121
        if (wheel -> gx_scroll_wheel_shift_error)
122
        {
123
13
            shift += wheel -> gx_scroll_wheel_shift_error;
124
13
            wheel -> gx_scroll_wheel_shift_error = 0;
125
        }
126
127
121
        wheel -> gx_scroll_wheel_scroll(wheel, (GX_VALUE)shift);
128
129
121
        if (wheel -> gx_scroll_wheel_animation_steps > 0)
130
        {
131
105
            increment = (wheel -> gx_scroll_wheel_animation_end_speed - wheel -> gx_scroll_wheel_animation_speed) /
132
105
                wheel -> gx_scroll_wheel_animation_steps;
133
134
105
            wheel -> gx_scroll_wheel_animation_speed = (GX_VALUE)(wheel -> gx_scroll_wheel_animation_speed + increment);
135
        }
136
137
121
        if (!wheel -> gx_scroll_wheel_wrap_style_check(wheel))
138
        {
139

113
            if ((wheel -> gx_scroll_wheel_selected_row == 0 && wheel -> gx_scroll_wheel_selected_yshift > 0) ||
140
112
                (wheel -> gx_scroll_wheel_selected_row == wheel -> gx_scroll_wheel_total_rows - 1 &&
141
2
                 wheel -> gx_scroll_wheel_selected_yshift < 0))
142
            {
143
2
                wheel -> gx_scroll_wheel_animation_steps = 0;
144
            }
145
        }
146
147
121
        if (wheel -> gx_scroll_wheel_animation_steps == 0)
148
        {
149
18
            _gx_system_timer_stop(widget, GX_FLICK_TIMER);
150
151
18
            if (wheel -> gx_scroll_wheel_selected_yshift)
152
            {
153
3
                _gx_system_timer_start((GX_WIDGET *)wheel, GX_SNAP_TIMER, 1, 1);
154
            }
155
            else
156
            {
157
15
                generate_event = GX_TRUE;
158
            }
159
        }
160
121
        break;
161
162
240
    case GX_ANIMATION_TIMER:
163
        /* Handle animation timer. */
164
240
        wheel -> gx_scroll_wheel_animation_steps--;
165
166
240
        if (wheel -> gx_scroll_wheel_shift_error)
167
        {
168
18
            wheel -> gx_scroll_wheel_scroll(wheel, wheel -> gx_scroll_wheel_shift_error);
169
18
            wheel -> gx_scroll_wheel_shift_error = 0;
170
        }
171
172
240
        wheel -> gx_scroll_wheel_scroll(wheel, wheel -> gx_scroll_wheel_animation_speed);
173
174
240
        if (wheel -> gx_scroll_wheel_animation_steps == 0)
175
        {
176
24
            _gx_system_timer_stop(widget, GX_ANIMATION_TIMER);
177
178
24
            if (wheel -> gx_scroll_wheel_selected_yshift)
179
            {
180
13
                _gx_system_timer_start((GX_WIDGET *)wheel, GX_SNAP_TIMER, 1, 1);
181
            }
182
            else
183
            {
184
11
                generate_event = GX_TRUE;
185
            }
186
        }
187
240
        break;
188
    }
189
190

451
    if (wheel -> gx_widget_id && generate_event)
191
    {
192
74
        _gx_widget_event_generate((GX_WIDGET *)wheel, GX_EVENT_LIST_SELECT, wheel -> gx_scroll_wheel_selected_row);
193
    }
194
195
451
    return GX_SUCCESS;
196
}
197
198
/**************************************************************************/
199
/*                                                                        */
200
/*  FUNCTION                                               RELEASE        */
201
/*                                                                        */
202
/*    _gx_scroll_wheel_flick_event_handler                PORTABLE C      */
203
/*                                                           6.1          */
204
/*  AUTHOR                                                                */
205
/*                                                                        */
206
/*    Kenneth Maxwell, Microsoft Corporation                              */
207
/*                                                                        */
208
/*  DESCRIPTION                                                           */
209
/*                                                                        */
210
/*    Internal helper function to handle flick event for scrol wheel      */
211
/*    widget.                                                             */
212
/*                                                                        */
213
/*  INPUT                                                                 */
214
/*                                                                        */
215
/*    wheel                                 Scroll wheel control block    */
216
/*    flick_speed                           Flick speed                   */
217
/*                                                                        */
218
/*  OUTPUT                                                                */
219
/*                                                                        */
220
/*    status                                Completion status             */
221
/*                                                                        */
222
/*  CALLS                                                                 */
223
/*                                                                        */
224
/*    _gx_system_timer_start                Start a timer for a widget    */
225
/*    _gx_system_timer_stop                 Stop a timer for a widget     */
226
/*                                                                        */
227
/*  CALLED BY                                                             */
228
/*                                                                        */
229
/*    _gx_scroll_wheel_event_process                                      */
230
/*                                                                        */
231
/*  RELEASE HISTORY                                                       */
232
/*                                                                        */
233
/*    DATE              NAME                      DESCRIPTION             */
234
/*                                                                        */
235
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
236
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
237
/*                                            resulting in version 6.1    */
238
/*                                                                        */
239
/**************************************************************************/
240
20
static UINT _gx_scroll_wheel_flick_event_handler(GX_SCROLL_WHEEL *wheel, INT flick_speed)
241
{
242
INT shift;
243
INT start_speed;
244
INT end_speed;
245
INT total_steps;
246
INT speed;
247
248
20
    shift = flick_speed / GX_FIXED_VAL_HALF;
249
250
20
    if ((GX_ABS(shift) > 5) &&
251
19
        (wheel -> gx_scroll_wheel_total_rows))
252
    {
253
18
        _gx_system_timer_stop((GX_WIDGET *)wheel, GX_SNAP_TIMER);
254
255
18
        if (GX_ABS(shift) < wheel -> gx_scroll_wheel_row_height / 3)
256
        {
257
6
            shift /= GX_ABS(shift);
258
6
            shift *= wheel -> gx_scroll_wheel_row_height / 3;
259
        }
260
18
        start_speed = (wheel -> gx_scroll_wheel_animation_start_speed_rate * shift) >> GX_FIXED_VAL_SHIFT;
261
18
        end_speed = (wheel -> gx_scroll_wheel_animation_end_speed_rate * shift) >> GX_FIXED_VAL_SHIFT;
262
263
18
        if (GX_ABS(end_speed) < wheel -> gx_scroll_wheel_row_height / 10)
264
        {
265
15
            end_speed = wheel -> gx_scroll_wheel_row_height / 10;
266
267
15
            if (shift < 0)
268
            {
269
8
                end_speed = -end_speed;
270
            }
271
        }
272
273
18
        total_steps = GX_ABS(shift) / 2;
274
275
18
        if (total_steps > wheel -> gx_scroll_wheel_animation_max_steps)
276
        {
277
5
            total_steps = wheel -> gx_scroll_wheel_animation_max_steps;
278
        }
279
280
18
        wheel -> gx_scroll_wheel_animation_speed = (GX_VALUE)start_speed;
281
18
        wheel -> gx_scroll_wheel_animation_end_speed = (GX_VALUE)end_speed;
282
18
        wheel -> gx_scroll_wheel_animation_steps = (GX_VALUE)total_steps;
283
284
18
        speed = start_speed;
285
18
        shift = start_speed;
286
134
        while (total_steps > 1)
287
        {
288
116
            total_steps--;
289
116
            speed += (end_speed - speed) / total_steps;
290
291
116
            shift += speed;
292
293
116
            if (GX_ABS(shift) > wheel -> gx_scroll_wheel_row_height)
294
            {
295
14
                shift %= wheel -> gx_scroll_wheel_row_height;
296
            }
297
        }
298
299
18
        if (start_speed > 0)
300
        {
301
8
            shift += wheel -> gx_scroll_wheel_selected_yshift;
302
8
            shift %= wheel -> gx_scroll_wheel_row_height;
303
8
            if (shift < 0)
304
            {
305
1
                wheel -> gx_scroll_wheel_shift_error = (GX_VALUE)(-shift);
306
            }
307
7
            else if (shift > 0)
308
            {
309
5
                wheel -> gx_scroll_wheel_shift_error = (GX_VALUE)(wheel -> gx_scroll_wheel_row_height - shift);
310
            }
311
        }
312
10
        else if (start_speed < 0)
313
        {
314
9
            shift += wheel -> gx_scroll_wheel_selected_yshift;
315
9
            shift %= wheel -> gx_scroll_wheel_row_height;
316
317
9
            if (shift < 0)
318
            {
319
5
                wheel -> gx_scroll_wheel_shift_error = (GX_VALUE)(-shift - wheel -> gx_scroll_wheel_row_height);
320
            }
321
4
            else if (shift > 0)
322
            {
323
2
                wheel -> gx_scroll_wheel_shift_error = (GX_VALUE)(-shift);
324
            }
325
        }
326
327
        /* Start flick timer. */
328
18
        _gx_system_timer_start((GX_WIDGET *) wheel, GX_FLICK_TIMER,
329
18
                               (UINT)wheel -> gx_scroll_wheel_animation_delay,
330
18
                               (UINT)wheel -> gx_scroll_wheel_animation_delay);
331
    }
332
333
20
    return GX_SUCCESS;
334
}
335
336
/**************************************************************************/
337
/*                                                                        */
338
/*  FUNCTION                                               RELEASE        */
339
/*                                                                        */
340
/*    _gx_scroll_wheel_pen_up_event_handler               PORTABLE C      */
341
/*                                                           6.1.4        */
342
/*  AUTHOR                                                                */
343
/*                                                                        */
344
/*    Kenneth Maxwell, Microsoft Corporation                              */
345
/*                                                                        */
346
/*  DESCRIPTION                                                           */
347
/*                                                                        */
348
/*    Internal helper function to handle pen up event for scroll wheel    */
349
/*    widget.                                                             */
350
/*                                                                        */
351
/*  INPUT                                                                 */
352
/*                                                                        */
353
/*    wheel                                 Scroll wheel control block    */
354
/*                                                                        */
355
/*  OUTPUT                                                                */
356
/*                                                                        */
357
/*    status                                Completion status             */
358
/*                                                                        */
359
/*  CALLS                                                                 */
360
/*                                                                        */
361
/*    _gx_system_timer_start                Start a timer for a widget    */
362
/*    _gx_system_dirty_partial_add          Mark partial area of a widget */
363
/*                                            as dirty                    */
364
/*    _gx_widget_event_generate             Create an event and send it to*/
365
/*                                            parent                      */
366
/*                                                                        */
367
/*  CALLED BY                                                             */
368
/*                                                                        */
369
/*    _gx_scroll_wheel_event_process                                      */
370
/*                                                                        */
371
/*  RELEASE HISTORY                                                       */
372
/*                                                                        */
373
/*    DATE              NAME                      DESCRIPTION             */
374
/*                                                                        */
375
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
376
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
377
/*                                            resulting in version 6.1    */
378
/*  02-02-2021     Kenneth Maxwell          Modified comment(s),          */
379
/*                                            renamed                     */
380
/*                                            GX_STYLE_SCROLL_WHEEL_DRAG  */
381
/*                                            to GX_STATUS_TRACKING_PEN,  */
382
/*                                            resulting in version 6.1.4  */
383
/*                                                                        */
384
/**************************************************************************/
385
45
static UINT _gx_scroll_wheel_pen_up_event_handler(GX_SCROLL_WHEEL *wheel)
386
{
387
GX_RECTANGLE dirty;
388
389
45
    wheel -> gx_widget_status &= (ULONG)(~GX_STATUS_TRACKING_PEN);
390
391
45
    if (wheel -> gx_scroll_wheel_selected_yshift)
392
    {
393
        /* Start a timer to move selected item to center. */
394
35
        _gx_system_timer_start((GX_WIDGET *)wheel, GX_SNAP_TIMER, 1, 1);
395
    }
396
    else
397
    {
398
        /* Mark center area dirty. */
399
10
        dirty = wheel -> gx_window_client;
400
10
        dirty.gx_rectangle_top = (GX_VALUE)(dirty.gx_rectangle_top + (dirty.gx_rectangle_bottom - dirty.gx_rectangle_top + 1) / 2);
401
10
        dirty.gx_rectangle_top = (GX_VALUE)(dirty.gx_rectangle_top - (wheel -> gx_scroll_wheel_row_height >> 1));
402
10
        dirty.gx_rectangle_bottom = (GX_VALUE)(dirty.gx_rectangle_top + wheel -> gx_scroll_wheel_row_height - 1);
403
10
        _gx_system_dirty_partial_add((GX_WIDGET *)wheel, &dirty);
404
405
10
        if (wheel -> gx_widget_id)
406
        {
407
            /* Generate a list selected event. */
408
9
            _gx_widget_event_generate((GX_WIDGET *)wheel, GX_EVENT_LIST_SELECT, wheel -> gx_scroll_wheel_selected_row);
409
        }
410
    }
411
412
45
    return GX_SUCCESS;
413
}
414
415
/**************************************************************************/
416
/*                                                                        */
417
/*  FUNCTION                                               RELEASE        */
418
/*                                                                        */
419
/*    _gx_scroll_wheel_event_process                      PORTABLE C      */
420
/*                                                           6.1.7        */
421
/*  AUTHOR                                                                */
422
/*                                                                        */
423
/*    Kenneth Maxwell, Microsoft Corporation                              */
424
/*                                                                        */
425
/*  DESCRIPTION                                                           */
426
/*                                                                        */
427
/*    This function processes the comming events for a scroll wheel       */
428
/*    widget.                                                             */
429
/*                                                                        */
430
/*  INPUT                                                                 */
431
/*                                                                        */
432
/*    wheel                                 Text scroll wheel control     */
433
/*                                            block                       */
434
/*    event_ptr                             Event to be processed         */
435
/*                                                                        */
436
/*  OUTPUT                                                                */
437
/*                                                                        */
438
/*    status                                Completion status             */
439
/*                                                                        */
440
/*  CALLS                                                                 */
441
/*                                                                        */
442
/*    _gx_system_input_capture              Temporarily direct all inputs */
443
/*                                            to specified widget         */
444
/*    _gx_system_input_release              Release captured input events */
445
/*    _gx_window_event_process              Default window event process  */
446
/*    _gx_widget_event_to_parent            Send event to widget's parent */
447
/*    _gx_scroll_wheel_scroll               Scroll a scroll wheel widget  */
448
/*    _gx_scroll_wheel_pen_up_event_handler Handle pen up event           */
449
/*    _gx_scroll_wheel_flick_event_handler  Handle flick event            */
450
/*    _gx_scroll_wheel_timer_event_handler  Handle timer event            */
451
/*    _gx_scroll_wheel_gradient_create      Create a gradient pixelmap    */
452
/*    _gx_utility_gradient_delete           Delete a gradient             */
453
/*  CALLED BY                                                             */
454
/*                                                                        */
455
/*    Application Code                                                    */
456
/*    GUIX Internal Code                                                  */
457
/*                                                                        */
458
/*  RELEASE HISTORY                                                       */
459
/*                                                                        */
460
/*    DATE              NAME                      DESCRIPTION             */
461
/*                                                                        */
462
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
463
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
464
/*                                            resulting in version 6.1    */
465
/*  02-02-2021     Kenneth Maxwell          Modified comment(s),          */
466
/*                                            renamed                     */
467
/*                                            GX_STYLE_SCROLL_WHEEL_DRAG  */
468
/*                                            to GX_STATUS_TRACKING_PEN,  */
469
/*                                            resulting in version 6.1.4  */
470
/*  06-02-2021     Ting Zhu                 Modified comment(s),          */
471
/*                                            updated with scroll wheel   */
472
/*                                            control block change,       */
473
/*                                            resulting in version 6.1.7  */
474
/*                                                                        */
475
/**************************************************************************/
476
1065
UINT _gx_scroll_wheel_event_process(GX_SCROLL_WHEEL *wheel, GX_EVENT *event_ptr)
477
{
478
GX_VALUE shift;
479
480


1065
    switch (event_ptr -> gx_event_type)
481
    {
482
55
    case GX_EVENT_PEN_DOWN:
483
55
        if (wheel -> gx_scroll_wheel_total_rows)
484
        {
485
54
            _gx_system_input_capture((GX_WIDGET *)wheel);
486
54
            wheel -> gx_window_move_start = event_ptr -> gx_event_payload.gx_event_pointdata;
487
54
            wheel -> gx_scroll_wheel_shift_error = 0;
488
        }
489
55
        break;
490
491
55
    case GX_EVENT_PEN_DRAG:
492
55
        if (wheel -> gx_widget_status & GX_STATUS_OWNS_INPUT)
493
        {
494
54
            wheel -> gx_widget_status |= GX_STATUS_TRACKING_PEN;
495
54
            shift = (GX_VALUE)(event_ptr -> gx_event_payload.gx_event_pointdata.gx_point_y - wheel -> gx_window_move_start.gx_point_y);
496
54
            if (shift)
497
            {
498
53
                wheel -> gx_scroll_wheel_scroll(wheel, shift);
499
500
53
                wheel -> gx_window_move_start = event_ptr -> gx_event_payload.gx_event_pointdata;
501
            }
502
        }
503
        else
504
        {
505
1
            _gx_widget_event_to_parent((GX_WIDGET *)wheel, event_ptr);
506
        }
507
55
        break;
508
509
46
    case GX_EVENT_PEN_UP:
510
46
        if (wheel -> gx_widget_status & GX_STATUS_OWNS_INPUT)
511
        {
512
45
            _gx_system_input_release((GX_WIDGET *)wheel);
513
45
            _gx_scroll_wheel_pen_up_event_handler(wheel);
514
        }
515
        else
516
        {
517
1
            _gx_widget_event_to_parent((GX_WIDGET *)wheel, event_ptr);
518
        }
519
46
        break;
520
521
20
    case GX_EVENT_VERTICAL_FLICK:
522
20
        _gx_scroll_wheel_flick_event_handler(wheel, event_ptr -> gx_event_payload.gx_event_intdata[0]);
523
20
        break;
524
525
451
    case GX_EVENT_TIMER:
526
451
        _gx_scroll_wheel_timer_event_handler(wheel, event_ptr -> gx_event_payload.gx_event_timer_id);
527
451
        break;
528
529
187
    case GX_EVENT_SHOW:
530
187
        _gx_window_event_process((GX_WINDOW *)wheel, event_ptr);
531
187
        _gx_scroll_wheel_gradient_create(wheel);
532
187
        break;
533
534
9
    case GX_EVENT_DELETE:
535
9
        _gx_utility_gradient_delete(&wheel -> gx_scroll_wheel_gradient);
536
9
        break;
537
538
242
    default:
539
242
        return _gx_window_event_process((GX_WINDOW *)wheel, event_ptr);
540
    }
541
542
823
    return GX_SUCCESS;
543
}
544