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

23
        if ((click_x < client.gx_rectangle_left) && (text_input -> gx_single_line_text_input_end_mark > 0))
185
        {
186
4
            if (!(text_input -> gx_widget_status & (GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS)))
187
            {
188
                /* Start a timer to move text right. */
189
3
                _gx_system_timer_start((GX_WIDGET *)text_input, GX_MARK_TIMER,
190
                                       GX_MARK_INTERVAL, GX_MARK_INTERVAL);
191
            }
192
193
4
            text_input -> gx_widget_status &= ~GX_STATUS_MARK_NEXT;
194
4
            text_input -> gx_widget_status |= GX_STATUS_MARK_PREVIOUS;
195
        }
196
19
        else if ((click_x > client.gx_rectangle_right) &&
197
5
                 (text_input -> gx_single_line_text_input_end_mark < text_input -> gx_single_line_text_input_string_size))
198
        {
199
4
            if (!(text_input -> gx_widget_status & (GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS)))
200
            {
201
                /* Start a timer to move text left. */
202
3
                _gx_system_timer_start((GX_WIDGET *)text_input, GX_MARK_TIMER,
203
                                       GX_MARK_INTERVAL, GX_MARK_INTERVAL);
204
            }
205
206
4
            text_input -> gx_widget_status &= ~GX_STATUS_MARK_PREVIOUS;
207
4
            text_input -> gx_widget_status |= GX_STATUS_MARK_NEXT;
208
        }
209
        else
210
        {
211
15
            if (text_input -> gx_widget_status & (GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS))
212
            {
213
2
                _gx_system_timer_stop((GX_WIDGET *)text_input, GX_MARK_TIMER);
214
2
                text_input -> gx_widget_status &= ~(GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS);
215
            }
216
        }
217
218

23
        if ((start_mark != text_input -> gx_single_line_text_input_end_mark) ||
219
            (start_mark != end_mark))
220
        {
221
            /* Retrieve text bounding rectangle between old and new end mark. */
222
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);
223
224
21
            _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &dirty_area);
225
        }
226
    }
227
    else
228
    {
229
1
        _gx_widget_event_process((GX_WIDGET *)text_input, event_ptr);
230
    }
231
232
24
    return GX_SUCCESS;
233
}
234
235
/**************************************************************************/
236
/*                                                                        */
237
/*  FUNCTION                                               RELEASE        */
238
/*                                                                        */
239
/*    _gx_single_line_text_input_event_process            PORTABLE C      */
240
/*                                                           6.4.0        */
241
/*  AUTHOR                                                                */
242
/*                                                                        */
243
/*    Kenneth Maxwell, Microsoft Corporation                              */
244
/*                                                                        */
245
/*  DESCRIPTION                                                           */
246
/*                                                                        */
247
/*    This service processes a single line text input event. This function*/
248
/*    is internally referenced by the gx_single_line_text_input_create    */
249
/*    function, but is exposed for use by the application in those cases  */
250
/*    where the application defines a custom single line text input event */
251
/*    processing function.                                                */
252
/*                                                                        */
253
/*  INPUT                                                                 */
254
/*                                                                        */
255
/*    text_input                            Single-line text input widget */
256
/*                                            control block               */
257
/*    event_ptr                             Pointer to GX_EVENT structure */
258
/*                                                                        */
259
/*  OUTPUT                                                                */
260
/*                                                                        */
261
/*    status                                Completion status             */
262
/*                                                                        */
263
/*  CALLS                                                                 */
264
/*                                                                        */
265
/*    _gx_widget_event_process              Default widget event process  */
266
/*    _gx_widget_event_generate             Create a event and send it to */
267
/*                                            parent                      */
268
/*    _gx_system_timer_start                Start the system timer        */
269
/*    _gx_system_timer_stop                 Stop the system timer         */
270
/*    _gx_system_dirty_partial_add          Mark the partial area of a    */
271
/*                                            widget as dirty             */
272
/*    _gx_text_input_cursor_dirty_rectangle_get                           */
273
/*                                          Get cursor rectangle          */
274
/*    _gx_single_line_text_input_keydown_process                          */
275
/*                                          Keydown event process function*/
276
/*    _gx_single_line_text_input_position_update                          */
277
/*                                          Update cursor position by     */
278
/*                                            insert position             */
279
/*                                                                        */
280
/*  CALLED BY                                                             */
281
/*                                                                        */
282
/*    Application Code                                                    */
283
/*    GUIX Internal Code                                                  */
284
/*                                                                        */
285
/*  RELEASE HISTORY                                                       */
286
/*                                                                        */
287
/*    DATE              NAME                      DESCRIPTION             */
288
/*                                                                        */
289
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
290
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
291
/*                                            resulting in version 6.1    */
292
/*  12-31-2020     Kenneth Maxwell          Modified comment(s),          */
293
/*                                            added logic to release      */
294
/*                                            dynamic input buffer,       */
295
/*                                            resulting in version 6.1.3  */
296
/*  12-31-2023     Ting Zhu                 Modified comment(s),          */
297
/*                                            modified to always call     */
298
/*                                            default widget event        */
299
/*                                            process on a pen up event,  */
300
/*                                            resulting in version 6.4.0  */
301
/*                                                                        */
302
/**************************************************************************/
303
18144
UINT  _gx_single_line_text_input_event_process(GX_SINGLE_LINE_TEXT_INPUT *text_input, GX_EVENT *event_ptr)
304
{
305
UINT         status;
306
18144
GX_WIDGET   *widget = (GX_WIDGET *)text_input;
307
GX_RECTANGLE dirty_area;
308
GX_VALUE     blink_interval;
309
ULONG        old_style;
310
311
    /* Default status to success.  */
312
18144
    status =  GX_SUCCESS;
313
314
    /* Process relative to the type of event.  */
315




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