GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_scroll_wheel_event_process.c Lines: 148 148 100.0 %
Date: 2026-03-06 19:21:09 Branches: 86 86 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
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
/**************************************************************************/
72
451
static UINT _gx_scroll_wheel_timer_event_handler(GX_SCROLL_WHEEL *wheel, UINT timer_id)
73
{
74
451
GX_WIDGET *widget = (GX_WIDGET *)wheel;
75
INT        shift;
76
INT        increment;
77
451
GX_BOOL    generate_event = GX_FALSE;
78
79

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

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

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


1065
    switch (event_ptr -> gx_event_type)
432
    {
433
55
    case GX_EVENT_PEN_DOWN:
434
55
        if (wheel -> gx_scroll_wheel_total_rows)
435
        {
436
54
            _gx_system_input_capture((GX_WIDGET *)wheel);
437
54
            wheel -> gx_window_move_start = event_ptr -> gx_event_payload.gx_event_pointdata;
438
54
            wheel -> gx_scroll_wheel_shift_error = 0;
439
        }
440
55
        break;
441
442
55
    case GX_EVENT_PEN_DRAG:
443
55
        if (wheel -> gx_widget_status & GX_STATUS_OWNS_INPUT)
444
        {
445
54
            wheel -> gx_widget_status |= GX_STATUS_TRACKING_PEN;
446
54
            shift = (GX_VALUE)(event_ptr -> gx_event_payload.gx_event_pointdata.gx_point_y - wheel -> gx_window_move_start.gx_point_y);
447
54
            if (shift)
448
            {
449
53
                wheel -> gx_scroll_wheel_scroll(wheel, shift);
450
451
53
                wheel -> gx_window_move_start = event_ptr -> gx_event_payload.gx_event_pointdata;
452
            }
453
        }
454
        else
455
        {
456
1
            _gx_widget_event_to_parent((GX_WIDGET *)wheel, event_ptr);
457
        }
458
55
        break;
459
460
46
    case GX_EVENT_PEN_UP:
461
46
        if (wheel -> gx_widget_status & GX_STATUS_OWNS_INPUT)
462
        {
463
45
            _gx_system_input_release((GX_WIDGET *)wheel);
464
45
            _gx_scroll_wheel_pen_up_event_handler(wheel);
465
        }
466
        else
467
        {
468
1
            _gx_widget_event_to_parent((GX_WIDGET *)wheel, event_ptr);
469
        }
470
46
        break;
471
472
20
    case GX_EVENT_VERTICAL_FLICK:
473
20
        _gx_scroll_wheel_flick_event_handler(wheel, event_ptr -> gx_event_payload.gx_event_intdata[0]);
474
20
        break;
475
476
451
    case GX_EVENT_TIMER:
477
451
        _gx_scroll_wheel_timer_event_handler(wheel, event_ptr -> gx_event_payload.gx_event_timer_id);
478
451
        break;
479
480
187
    case GX_EVENT_SHOW:
481
187
        _gx_window_event_process((GX_WINDOW *)wheel, event_ptr);
482
187
        _gx_scroll_wheel_gradient_create(wheel);
483
187
        break;
484
485
9
    case GX_EVENT_DELETE:
486
9
        _gx_utility_gradient_delete(&wheel -> gx_scroll_wheel_gradient);
487
9
        break;
488
489
242
    default:
490
242
        return _gx_window_event_process((GX_WINDOW *)wheel, event_ptr);
491
    }
492
493
823
    return GX_SUCCESS;
494
}
495