GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_single_line_text_input_event_process.c Lines: 153 153 100.0 %
Date: 2026-03-06 19:21:09 Branches: 83 83 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
/**   Text Input Management (Single Line Text Input)                      */
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_widget.h"
30
#include "gx_single_line_text_input.h"
31
#include "gx_text_input_cursor.h"
32
33
34
/**************************************************************************/
35
/*                                                                        */
36
/*  FUNCTION                                               RELEASE        */
37
/*                                                                        */
38
/*    _gx_single_line_text_input_pen_down_process         PORTABLE C      */
39
/*                                                           6.1          */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    Kenneth Maxwell, Microsoft Corporation                              */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    This function handles pen down event for single line text input     */
47
/*    widget.                                                             */
48
/*                                                                        */
49
/*  INPUT                                                                 */
50
/*                                                                        */
51
/*    text_input                            Single-line text input widget */
52
/*                                            control block               */
53
/*    event_ptr                             Pointer to GX_EVENT structure */
54
/*                                                                        */
55
/*  OUTPUT                                                                */
56
/*                                                                        */
57
/*    status                                Completion status             */
58
/*                                                                        */
59
/*  CALLS                                                                 */
60
/*                                                                        */
61
/*    _gx_single_line_text_input_text_rectangle_get                       */
62
/*                                          Retrieve rectangle from cursor*/
63
/*                                            to specified offset position*/
64
/*    _gx_single_line_text_input_position_get                             */
65
/*                                          Update text insert position   */
66
/*    _gx_system_dirty_partial_add          Mark the partial area of a    */
67
/*                                            widget as dirty             */
68
/*    _gx_widget_event_process              Default widget event process  */
69
/*                                                                        */
70
/*  CALLED BY                                                             */
71
/*                                                                        */
72
/*    _gx_single_line_text_input_event_process                            */
73
/*                                                                        */
74
/**************************************************************************/
75
1842
static UINT _gx_single_line_text_input_pen_down_process(GX_SINGLE_LINE_TEXT_INPUT *text_input, GX_EVENT *event_ptr)
76
{
77
GX_RECTANGLE dirty_area;
78
1842
UINT         start_mark = text_input -> gx_single_line_text_input_start_mark;
79
1842
UINT         end_mark = text_input -> gx_single_line_text_input_end_mark;
80
81
1842
    _gx_system_input_capture((GX_WIDGET *)text_input);
82
83
1842
    if (start_mark != end_mark)
84
    {
85
        /* Retrieve highlight text bounding rectangle. */
86
15
        _gx_single_line_text_input_text_rectangle_get(text_input, (INT)(start_mark - end_mark), &dirty_area);
87
88
        /* Mark highlight area as dirty. */
89
15
        _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &dirty_area);
90
    }
91
92
    /* Calculate insert position according to click position. */
93
1842
    _gx_single_line_text_input_position_get(text_input, (UINT)((*event_ptr).gx_event_payload.gx_event_pointdata.gx_point_x));
94
95
    /* Set highlight start/end mark to insert position. */
96
1842
    text_input -> gx_single_line_text_input_start_mark = text_input -> gx_single_line_text_input_insert_pos;
97
1842
    text_input -> gx_single_line_text_input_end_mark = text_input -> gx_single_line_text_input_insert_pos;
98
99
    /* Call the widget default processing.  */
100
1842
    return _gx_widget_event_process((GX_WIDGET *)text_input, event_ptr);
101
}
102
103
/**************************************************************************/
104
/*                                                                        */
105
/*  FUNCTION                                               RELEASE        */
106
/*                                                                        */
107
/*    _gx_single_line_text_input_pen_drag_process         PORTABLE C      */
108
/*                                                           6.1          */
109
/*  AUTHOR                                                                */
110
/*                                                                        */
111
/*    Kenneth Maxwell, Microsoft Corporation                              */
112
/*                                                                        */
113
/*  DESCRIPTION                                                           */
114
/*                                                                        */
115
/*    This function handles pen drag event for single line text input     */
116
/*    widget.                                                             */
117
/*                                                                        */
118
/*  INPUT                                                                 */
119
/*                                                                        */
120
/*    text_input                            Single-line text input widget */
121
/*                                            control block               */
122
/*    event_ptr                             Pointer to GX_EVENT structure */
123
/*                                                                        */
124
/*  OUTPUT                                                                */
125
/*                                                                        */
126
/*    status                                Completion status             */
127
/*                                                                        */
128
/*  CALLS                                                                 */
129
/*                                                                        */
130
/*    _gx_text_input_cursor_dirty_rectangle_get                           */
131
/*                                          Retrieve cursor rectangle     */
132
/*    _gx_single_line_text_input_text_rectangle_get                       */
133
/*                                          Retrieve rectangle from cursor*/
134
/*                                            to specified offset position*/
135
/*    _gx_single_line_text_input_position_get                             */
136
/*                                          Update text insert position   */
137
/*    _gx_system_dirty_partial_add          Mark the partial area of a    */
138
/*                                            widget as dirty             */
139
/*    _gx_widget_event_process              Default widget event process  */
140
/*                                                                        */
141
/*  CALLED BY                                                             */
142
/*                                                                        */
143
/*    _gx_single_line_text_input_event_process                            */
144
/*                                                                        */
145
/**************************************************************************/
146
24
static UINT _gx_single_line_text_input_pen_drag_process(GX_SINGLE_LINE_TEXT_INPUT *text_input, GX_EVENT *event_ptr)
147
{
148
GX_RECTANGLE dirty_area;
149
24
UINT         start_mark = text_input -> gx_single_line_text_input_start_mark;
150
24
UINT         end_mark = text_input -> gx_single_line_text_input_end_mark;
151
GX_VALUE     border_width;
152
GX_RECTANGLE client;
153
GX_VALUE     click_x;
154
155
24
    if (text_input -> gx_widget_status & GX_STATUS_OWNS_INPUT)
156
    {
157
23
        click_x = event_ptr -> gx_event_payload.gx_event_pointdata.gx_point_x;
158
159
        /* Calculate client rectangle. */
160
23
        _gx_widget_border_width_get((GX_WIDGET *)text_input, &border_width);
161
23
        _gx_widget_client_get((GX_WIDGET *)text_input, border_width, &client);
162
163
        /* Calculate insert position. */
164
23
        _gx_single_line_text_input_position_get(text_input, (UINT)click_x);
165
166
        /* Update end mark. */
167
23
        text_input -> gx_single_line_text_input_end_mark = text_input -> gx_single_line_text_input_insert_pos;
168
169

23
        if ((click_x < client.gx_rectangle_left) && (text_input -> gx_single_line_text_input_end_mark > 0))
170
        {
171
4
            if (!(text_input -> gx_widget_status & (GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS)))
172
            {
173
                /* Start a timer to move text right. */
174
3
                _gx_system_timer_start((GX_WIDGET *)text_input, GX_MARK_TIMER,
175
                                       GX_MARK_INTERVAL, GX_MARK_INTERVAL);
176
            }
177
178
4
            text_input -> gx_widget_status &= ~GX_STATUS_MARK_NEXT;
179
4
            text_input -> gx_widget_status |= GX_STATUS_MARK_PREVIOUS;
180
        }
181
19
        else if ((click_x > client.gx_rectangle_right) &&
182
5
                 (text_input -> gx_single_line_text_input_end_mark < text_input -> gx_single_line_text_input_string_size))
183
        {
184
4
            if (!(text_input -> gx_widget_status & (GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS)))
185
            {
186
                /* Start a timer to move text left. */
187
3
                _gx_system_timer_start((GX_WIDGET *)text_input, GX_MARK_TIMER,
188
                                       GX_MARK_INTERVAL, GX_MARK_INTERVAL);
189
            }
190
191
4
            text_input -> gx_widget_status &= ~GX_STATUS_MARK_PREVIOUS;
192
4
            text_input -> gx_widget_status |= GX_STATUS_MARK_NEXT;
193
        }
194
        else
195
        {
196
15
            if (text_input -> gx_widget_status & (GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS))
197
            {
198
2
                _gx_system_timer_stop((GX_WIDGET *)text_input, GX_MARK_TIMER);
199
2
                text_input -> gx_widget_status &= ~(GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS);
200
            }
201
        }
202
203

23
        if ((start_mark != text_input -> gx_single_line_text_input_end_mark) ||
204
            (start_mark != end_mark))
205
        {
206
            /* Retrieve text bounding rectangle between old and new end mark. */
207
21
            _gx_single_line_text_input_text_rectangle_get(text_input, (INT)(end_mark - text_input -> gx_single_line_text_input_end_mark), &dirty_area);
208
209
21
            _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &dirty_area);
210
        }
211
    }
212
    else
213
    {
214
1
        _gx_widget_event_process((GX_WIDGET *)text_input, event_ptr);
215
    }
216
217
24
    return GX_SUCCESS;
218
}
219
220
/**************************************************************************/
221
/*                                                                        */
222
/*  FUNCTION                                               RELEASE        */
223
/*                                                                        */
224
/*    _gx_single_line_text_input_event_process            PORTABLE C      */
225
/*                                                           6.4.0        */
226
/*  AUTHOR                                                                */
227
/*                                                                        */
228
/*    Kenneth Maxwell, Microsoft Corporation                              */
229
/*                                                                        */
230
/*  DESCRIPTION                                                           */
231
/*                                                                        */
232
/*    This service processes a single line text input event. This function*/
233
/*    is internally referenced by the gx_single_line_text_input_create    */
234
/*    function, but is exposed for use by the application in those cases  */
235
/*    where the application defines a custom single line text input event */
236
/*    processing function.                                                */
237
/*                                                                        */
238
/*  INPUT                                                                 */
239
/*                                                                        */
240
/*    text_input                            Single-line text input widget */
241
/*                                            control block               */
242
/*    event_ptr                             Pointer to GX_EVENT structure */
243
/*                                                                        */
244
/*  OUTPUT                                                                */
245
/*                                                                        */
246
/*    status                                Completion status             */
247
/*                                                                        */
248
/*  CALLS                                                                 */
249
/*                                                                        */
250
/*    _gx_widget_event_process              Default widget event process  */
251
/*    _gx_widget_event_generate             Create a event and send it to */
252
/*                                            parent                      */
253
/*    _gx_system_timer_start                Start the system timer        */
254
/*    _gx_system_timer_stop                 Stop the system timer         */
255
/*    _gx_system_dirty_partial_add          Mark the partial area of a    */
256
/*                                            widget as dirty             */
257
/*    _gx_text_input_cursor_dirty_rectangle_get                           */
258
/*                                          Get cursor rectangle          */
259
/*    _gx_single_line_text_input_keydown_process                          */
260
/*                                          Keydown event process function*/
261
/*    _gx_single_line_text_input_position_update                          */
262
/*                                          Update cursor position by     */
263
/*                                            insert position             */
264
/*                                                                        */
265
/*  CALLED BY                                                             */
266
/*                                                                        */
267
/*    Application Code                                                    */
268
/*    GUIX Internal Code                                                  */
269
/*                                                                        */
270
/**************************************************************************/
271
18144
UINT  _gx_single_line_text_input_event_process(GX_SINGLE_LINE_TEXT_INPUT *text_input, GX_EVENT *event_ptr)
272
{
273
UINT         status;
274
18144
GX_WIDGET   *widget = (GX_WIDGET *)text_input;
275
GX_RECTANGLE dirty_area;
276
GX_VALUE     blink_interval;
277
ULONG        old_style;
278
279
    /* Default status to success.  */
280
18144
    status =  GX_SUCCESS;
281
282
    /* Process relative to the type of event.  */
283




18144
    switch (event_ptr -> gx_event_type)
284
    {
285
338
    case GX_EVENT_SHOW:
286
338
        _gx_widget_event_process(widget, event_ptr);
287
288
338
        if ((text_input -> gx_widget_style & GX_STYLE_CURSOR_ALWAYS) &&
289
4
            (text_input -> gx_widget_style & GX_STYLE_CURSOR_BLINK))
290
        {
291
3
            _gx_system_timer_start((GX_WIDGET *)text_input, ID_TEXT_INPUT_TIMER, GX_CURSOR_BLINK_INTERVAL, GX_CURSOR_BLINK_INTERVAL);
292
        }
293
294
        /* Update cursor position. */
295
338
        _gx_single_line_text_input_position_update(text_input);
296
338
        break;
297
298
1
    case GX_EVENT_RESIZED:
299
1
        _gx_single_line_text_input_position_update(text_input);
300
1
        break;
301
302
110
    case GX_EVENT_STYLE_CHANGED:
303
110
        if (widget -> gx_widget_status & GX_STATUS_VISIBLE)
304
        {
305
105
            old_style = event_ptr -> gx_event_payload.gx_event_ulongdata;
306
105
            if ((old_style & (GX_STYLE_BORDER_MASK | GX_STYLE_TEXT_ALIGNMENT_MASK)) !=
307
105
                (widget -> gx_widget_style & (GX_STYLE_BORDER_MASK | GX_STYLE_TEXT_ALIGNMENT_MASK)))
308
            {
309
43
                _gx_single_line_text_input_position_update(text_input);
310
            }
311
        }
312
110
        break;
313
314
12077
    case GX_EVENT_KEY_DOWN:
315
12077
        _gx_single_line_text_input_keydown_process(text_input, event_ptr);
316
317
        /*If input was done, send event to parent.  */
318
12077
        if (widget -> gx_widget_style & GX_STYLE_TEXT_INPUT_NOTIFY_ALL)
319
        {
320
3
            _gx_widget_event_generate(widget, GX_EVENT_TEXT_EDITED, 0);
321
        }
322
12077
        break;
323
324
103
    case GX_EVENT_FOCUS_GAINED:
325
103
        if (!(text_input -> gx_widget_style & GX_STYLE_CURSOR_ALWAYS))
326
        {
327
100
            text_input -> gx_widget_status |= (GX_STATUS_CURSOR_SHOW | GX_STATUS_CURSOR_DRAW);
328
329
100
            if (text_input -> gx_widget_style & GX_STYLE_CURSOR_BLINK)
330
            {
331
63
                blink_interval = text_input -> gx_single_line_text_input_cursor_instance.gx_text_input_cursor_blink_interval;
332
63
                _gx_system_timer_start(widget, ID_TEXT_INPUT_TIMER, (UINT)blink_interval, (UINT)blink_interval);
333
            }
334
        }
335
336
        /* Select all text. */
337
103
        _gx_single_line_text_input_text_select(text_input, 0, text_input -> gx_single_line_text_input_string_size - 1);
338
339
        /* this widget wants to be notified if it is moved or re-sized */
340
103
        text_input -> gx_widget_status |= GX_STATUS_RESIZE_NOTIFY;
341
342
        /* Call the widget default processing.  */
343
103
        status = _gx_widget_event_process(widget, event_ptr);
344
103
        break;
345
346
1842
    case GX_EVENT_PEN_DOWN:
347
1842
        _gx_single_line_text_input_pen_down_process(text_input, event_ptr);
348
1842
        break;
349
350
24
    case GX_EVENT_PEN_DRAG:
351
24
        _gx_single_line_text_input_pen_drag_process(text_input, event_ptr);
352
24
        break;
353
354
1834
    case GX_EVENT_PEN_UP:
355
1834
        if (text_input -> gx_widget_status & GX_STATUS_OWNS_INPUT)
356
        {
357
1833
            _gx_system_input_release((GX_WIDGET *)text_input);
358
359
1833
            if (text_input -> gx_widget_status & (GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS))
360
            {
361
4
                _gx_system_timer_stop((GX_WIDGET *)text_input, GX_MARK_TIMER);
362
4
                text_input -> gx_widget_status &= ~(GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS);
363
            }
364
        }
365
366
1834
        _gx_widget_event_process(widget, event_ptr);
367
1834
        break;
368
369
234
    case GX_EVENT_TIMER:
370
234
        if (event_ptr -> gx_event_payload.gx_event_timer_id == GX_MARK_TIMER)
371
        {
372
226
            if (text_input -> gx_widget_status & GX_STATUS_MARK_PREVIOUS)
373
            {
374
204
                _gx_single_line_text_input_mark_previous(text_input);
375
            }
376
            else
377
            {
378
22
                _gx_single_line_text_input_mark_next(text_input);
379
            }
380
        }
381
8
        else if ((event_ptr -> gx_event_payload.gx_event_timer_id == ID_TEXT_INPUT_TIMER) &&
382
7
                 (text_input -> gx_widget_status & GX_STATUS_CURSOR_SHOW))
383
        {
384
6
            if (text_input -> gx_widget_status & GX_STATUS_CURSOR_DRAW)
385
            {
386
3
                text_input -> gx_widget_status &= (ULONG)(~GX_STATUS_CURSOR_DRAW);
387
            }
388
            else
389
            {
390
3
                text_input -> gx_widget_status |= GX_STATUS_CURSOR_DRAW;
391
            }
392
393
6
            _gx_text_input_cursor_dirty_rectangle_get(&text_input -> gx_single_line_text_input_cursor_instance, &dirty_area);
394
6
            _gx_system_dirty_partial_add(widget, &dirty_area);
395
        }
396
234
        break;
397
398
63
    case GX_EVENT_FOCUS_LOST:
399
63
        if (!(text_input -> gx_widget_style & GX_STYLE_CURSOR_ALWAYS))
400
        {
401
61
            if (text_input -> gx_widget_style & GX_STYLE_CURSOR_BLINK)
402
            {
403
34
                _gx_system_timer_stop(widget, ID_TEXT_INPUT_TIMER);
404
            }
405
61
            text_input -> gx_widget_status &= (ULONG)(~GX_STATUS_CURSOR_SHOW);
406
407
61
            if (text_input -> gx_single_line_text_input_start_mark == text_input -> gx_single_line_text_input_end_mark)
408
            {
409
57
                _gx_text_input_cursor_dirty_rectangle_get(&text_input -> gx_single_line_text_input_cursor_instance, &dirty_area);
410
57
                _gx_system_dirty_partial_add(widget, &dirty_area);
411
            }
412
413
            /* If cursor always is not set, do-not receive resize notify when lose focus */
414
61
            text_input -> gx_widget_status &= ~GX_STATUS_RESIZE_NOTIFY;
415
        }
416
417
63
        if (text_input -> gx_single_line_text_input_start_mark != text_input -> gx_single_line_text_input_end_mark)
418
        {
419
4
            _gx_single_line_text_input_text_rectangle_get(text_input,
420
4
                                                          (INT)(text_input -> gx_single_line_text_input_start_mark - text_input -> gx_single_line_text_input_end_mark), &dirty_area);
421
422
4
            text_input -> gx_single_line_text_input_start_mark = 0;
423
4
            text_input -> gx_single_line_text_input_end_mark = 0;
424
425
4
            _gx_system_dirty_partial_add(widget, &dirty_area);
426
        }
427
428
        /*If string was modified, send event to parent.  */
429
63
        if (text_input -> gx_single_line_text_input_was_modified)
430
        {
431
1
            _gx_widget_event_generate(widget, GX_EVENT_TEXT_EDITED, 0);
432
1
            text_input -> gx_single_line_text_input_was_modified = GX_FALSE;
433
        }
434
435
        /* Call the widget default processing.  */
436
63
        status = _gx_widget_event_process(widget, event_ptr);
437
63
        break;
438
439
4
    case GX_EVENT_COPY:
440
4
        _gx_single_line_text_input_copy(text_input);
441
4
        break;
442
443
10
    case GX_EVENT_CUT:
444
10
        _gx_single_line_text_input_cut(text_input);
445
10
        break;
446
447
23
    case GX_EVENT_PASTE:
448
23
        _gx_single_line_text_input_paste(text_input);
449
23
        break;
450
451
614
    case GX_EVENT_MARK_NEXT:
452
614
        _gx_single_line_text_input_mark_next(text_input);
453
614
        break;
454
455
601
    case GX_EVENT_MARK_PREVIOUS:
456
601
        _gx_single_line_text_input_mark_previous(text_input);
457
601
        break;
458
459
41
    case GX_EVENT_MARK_HOME:
460
41
        _gx_single_line_text_input_mark_home(text_input);
461
41
        break;
462
463
40
    case GX_EVENT_MARK_END:
464
40
        _gx_single_line_text_input_mark_end(text_input);
465
40
        break;
466
467
4
    case GX_EVENT_DELETE:
468
4
        if (text_input -> gx_widget_status & GX_STATUS_DYNAMIC_BUFFER)
469
        {
470
2
            if (!_gx_system_memory_free)
471
            {
472
1
                return GX_SYSTEM_MEMORY_ERROR;
473
            }
474
475
1
            _gx_system_memory_free(text_input -> gx_single_line_text_input_buffer);
476
1
            text_input -> gx_single_line_text_input_buffer = GX_NULL;
477
        }
478
3
        break;
479
480
181
    default:
481
        /* Call the widget default processing.  */
482
181
        status = _gx_widget_event_process(widget, event_ptr);
483
    }
484
485
    /* Return completion status.  */
486
18143
    return(status);
487
}
488