GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_multi_line_text_input_char_insert.c Lines: 74 74 100.0 %
Date: 2024-12-05 08:52:37 Branches: 36 36 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
/**   Multi Line Text Input Management (Multi 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_utility.h"
29
#include "gx_scrollbar.h"
30
#include "gx_multi_line_text_input.h"
31
#include "gx_multi_line_text_view.h"
32
#include "gx_window.h"
33
#include "gx_widget.h"
34
35
/**************************************************************************/
36
/*                                                                        */
37
/*  FUNCTION                                               RELEASE        */
38
/*                                                                        */
39
/*    _gx_multi_line_text_input_char_insert               PORTABLE C      */
40
/*                                                           6.1          */
41
/*  AUTHOR                                                                */
42
/*                                                                        */
43
/*    Kenneth Maxwell, Microsoft Corporation                              */
44
/*                                                                        */
45
/*  DESCRIPTION (deprecated)                                              */
46
/*                                                                        */
47
/*    This function inserts a character into the input buffer.            */
48
/*                                                                        */
49
/*  INPUT                                                                 */
50
/*                                                                        */
51
/*    text_input                            Multi line text input widget  */
52
/*                                            control block               */
53
/*    str                                   Utf8 string to be inserted    */
54
/*    str_size                              Inserted string size in bytes */
55
/*                                                                        */
56
/*  OUTPUT                                                                */
57
/*                                                                        */
58
/*    None                                                                */
59
/*                                                                        */
60
/*  CALLS                                                                 */
61
/*                                                                        */
62
/*    _gx_multi_line_text_input_char_insert_ext                           */
63
/*                                                                        */
64
/*  CALLED BY                                                             */
65
/*                                                                        */
66
/*    _gx_multi_line_text_input_keydown_process                           */
67
/*                                                                        */
68
/*  RELEASE HISTORY                                                       */
69
/*                                                                        */
70
/*    DATE              NAME                      DESCRIPTION             */
71
/*                                                                        */
72
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
73
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
74
/*                                            resulting in version 6.1    */
75
/*                                                                        */
76
/**************************************************************************/
77
#if defined(GX_ENABLE_DEPRECATED_STRING_API)
78
1
UINT _gx_multi_line_text_input_char_insert(GX_MULTI_LINE_TEXT_INPUT *text_input, GX_UBYTE *str, UINT str_size)
79
{
80
UINT      status;
81
GX_STRING string;
82
83
1
    string.gx_string_ptr = (GX_CHAR *)str;
84
1
    string.gx_string_length = str_size;
85
1
    status = _gx_multi_line_text_input_char_insert_ext(text_input, &string);
86
87
1
    return status;
88
}
89
#endif
90
91
/**************************************************************************/
92
/*                                                                        */
93
/*  FUNCTION                                               RELEASE        */
94
/*                                                                        */
95
/*    _gx_multi_line_text_input_char_insert_ext           PORTABLE C      */
96
/*                                                           6.1          */
97
/*  AUTHOR                                                                */
98
/*                                                                        */
99
/*    Kenneth Maxwell, Microsoft Corporation                              */
100
/*                                                                        */
101
/*  DESCRIPTION                                                           */
102
/*                                                                        */
103
/*    This function inserts a character into the input buffer.            */
104
/*                                                                        */
105
/*  INPUT                                                                 */
106
/*                                                                        */
107
/*    text_input                            Multi line text input widget  */
108
/*                                            control block               */
109
/*    str                                   Utf8 string to be inserted    */
110
/*    str_size                              Inserted string size in bytes */
111
/*                                                                        */
112
/*  OUTPUT                                                                */
113
/*                                                                        */
114
/*    None                                                                */
115
/*                                                                        */
116
/*  CALLS                                                                 */
117
/*                                                                        */
118
/*    memmove                               Move block of memory          */
119
/*    _gx_widget_font_get                   Retrieve font                 */
120
/*    _gx_window_scrollbar_find             Find scrollbar for a window   */
121
/*    _gx_scrollbar_reset                   Reset scrollbar information   */
122
/*    _gx_multi_line_text_view_string_total_rows_compute                  */
123
/*                                          Calculate total rows          */
124
/*    _gx_multi_line_text_view_line_cache_update                          */
125
/*                                          Update line cache             */
126
/*    _gx_multi_line_text_input_cursor_pos_update                         */
127
/*                                          Update cursor position        */
128
/*                                            according to insert index   */
129
/*    _gx_utility_rectangle_resize          Increase/Shrink rectangle by  */
130
/*                                            specified value             */
131
/*    _gx_utility_string_length_check       Test string length            */
132
/*    _gx_system_dirty_partial_add          Add one dirty area to dirty   */
133
/*                                            list                        */
134
/*                                                                        */
135
/*  CALLED BY                                                             */
136
/*                                                                        */
137
/*    _gx_multi_line_text_input_keydown_process                           */
138
/*                                                                        */
139
/*  RELEASE HISTORY                                                       */
140
/*                                                                        */
141
/*    DATE              NAME                      DESCRIPTION             */
142
/*                                                                        */
143
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
144
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
145
/*                                            resulting in version 6.1    */
146
/*                                                                        */
147
/**************************************************************************/
148
1825
UINT _gx_multi_line_text_input_char_insert_ext(GX_MULTI_LINE_TEXT_INPUT *text_input, GX_CONST GX_STRING *str)
149
{
150
1825
GX_TEXT_INPUT_CURSOR *cursor_ptr = &text_input -> gx_multi_line_text_input_cursor_instance;
151
UINT                  string_size;
152
UINT                  buffer_size;
153
GX_CHAR              *input_buffer;
154
GX_UBYTE             *insert_char;
155
UINT                  index;
156
INT                   shift;
157
INT                   last_visible_line;
158
GX_RECTANGLE          client;
159
GX_RECTANGLE          dirty_rect;
160
GX_FONT              *font;
161
GX_VALUE              line_height;
162
GX_VALUE              old_cur_y;
163
GX_SCROLLBAR         *scroll;
164
UINT                  text_rows;
165
UINT                  glyph_len;
166
UINT                  handled_size;
167
GX_STRING             insert_str;
168
169
1825
    if (text_input -> gx_multi_line_text_input_start_mark != text_input -> gx_multi_line_text_input_end_mark)
170
    {
171
142
        if (text_input -> gx_multi_line_text_input_end_mark < text_input -> gx_multi_line_text_input_start_mark)
172
        {
173
68
            _gx_multi_line_text_input_delete(text_input);
174
        }
175
        else
176
        {
177
74
            _gx_multi_line_text_input_backspace(text_input);
178
        }
179
    }
180
181
1825
    string_size = text_input -> gx_multi_line_text_view_text.gx_string_length;
182
1825
    buffer_size = text_input -> gx_multi_line_text_input_buffer_size;
183
1825
    insert_str = *str;
184
185
1825
    _gx_widget_font_get((GX_WIDGET *)text_input, text_input -> gx_multi_line_text_view_font_id, &font);
186
187
1825
    if (!font)
188
    {
189
1
        return GX_FAILURE;
190
    }
191
192
    /* Check if the insert string size is bigger than the remaining buffer size.  */
193
1824
    if (buffer_size < string_size + insert_str.gx_string_length + 1)
194
    {
195
14
        return GX_FAILURE;
196
    }
197
198
    /* Insert a character. */
199
200
1810
    input_buffer = (GX_CHAR *)text_input -> gx_multi_line_text_view_text.gx_string_ptr;
201
1810
    glyph_len = 1;
202
203
4690
    while (insert_str.gx_string_length)
204
    {
205

2881
        if (insert_str.gx_string_ptr[0] == GX_KEY_CARRIAGE_RETURN || insert_str.gx_string_ptr[0] == GX_KEY_LINE_FEED)
206
        {
207
            /* If the inserted character is a new line character,
208
               exchange it with current used new line character. */
209
827
            insert_char = text_input -> gx_multi_line_text_input_new_line_character;
210
827
            glyph_len = text_input -> gx_multi_line_text_input_new_line_character_size;
211
212
827
            if (insert_str.gx_string_ptr[0] == GX_KEY_CARRIAGE_RETURN)
213
            {
214

825
                if ((insert_str.gx_string_length > 1) && insert_str.gx_string_ptr[1] == GX_KEY_LINE_FEED)
215
                {
216
2
                    handled_size = 2;
217
                }
218
                else
219
                {
220
823
                    handled_size = 1;
221
                }
222
            }
223
            else
224
            {
225
2
                handled_size = 1;
226
            }
227
228
827
            insert_str.gx_string_ptr += handled_size;
229
827
            insert_str.gx_string_length -= handled_size;
230
        }
231
        else
232
        {
233
2054
            insert_char = (GX_UBYTE *)insert_str.gx_string_ptr;
234
#if defined GX_UTF8_SUPPORT
235
2054
            _gx_utility_utf8_string_character_get(&insert_str, GX_NULL, &glyph_len);
236
#else
237
            glyph_len = 1;
238
            insert_str.gx_string_ptr++;
239
            insert_str.gx_string_length--;
240
#endif
241
        }
242
243
2881
        string_size = text_input -> gx_multi_line_text_view_text.gx_string_length;
244
245
2881
        if (buffer_size < string_size + glyph_len + 1)
246
        {
247
1
            break;
248
        }
249
2880
        index = text_input -> gx_multi_line_text_input_text_insert_position;
250
2880
        memmove(input_buffer + index + glyph_len, input_buffer + index, string_size - index + 1);
251
2880
        memmove(input_buffer + index, insert_char, glyph_len);
252
253
        /* Update insert position and string size. */
254
2880
        text_input -> gx_multi_line_text_input_text_insert_position += glyph_len;
255
2880
        text_input -> gx_multi_line_text_view_text.gx_string_length += glyph_len;
256
    }
257
258
    /* Save old text rows.  */
259
1810
    text_rows = text_input -> gx_multi_line_text_view_text_total_rows;
260
261
    /* Calculate new text rows. */
262
1810
    _gx_multi_line_text_view_string_total_rows_compute((GX_MULTI_LINE_TEXT_VIEW *)text_input);
263
264
1810
    if (text_rows != text_input -> gx_multi_line_text_view_text_total_rows)
265
    {
266
607
        _gx_window_scrollbar_find((GX_WINDOW *)text_input, GX_TYPE_VERTICAL_SCROLL, &scroll);
267
607
        if (scroll)
268
        {
269
            /* Reset scrollbar.  */
270
369
            _gx_scrollbar_reset(scroll, GX_NULL);
271
        }
272
        else
273
        {
274
275
238
            if (text_input -> gx_multi_line_text_view_text_total_rows >
276
238
                text_input -> gx_multi_line_text_view_cache_size)
277
            {
278
5
                _gx_multi_line_text_view_line_cache_update((GX_MULTI_LINE_TEXT_VIEW *)text_input);
279
            }
280
        }
281
    }
282
283
    /* Save old shift value. */
284
1810
    shift = text_input -> gx_multi_line_text_view_text_scroll_shift;
285
286
    /* Record old y coordinate of cursor position. */
287
1810
    old_cur_y = cursor_ptr -> gx_text_input_cursor_pos.gx_point_y;
288
289
    /* Update cursor position. */
290
1810
    _gx_multi_line_text_input_cursor_pos_update(text_input, GX_TRUE);
291
292
    /* Set the text modified flag to GX_TRUE. */
293
1810
    text_input -> gx_multi_line_text_input_text_was_modified = GX_TRUE;
294
295
1810
    if (shift == text_input -> gx_multi_line_text_view_text_scroll_shift)
296
    {
297
1505
        line_height = (GX_VALUE)(font -> gx_font_line_height +
298
1505
                                 text_input -> gx_multi_line_text_view_line_space);
299
300
1505
        if (line_height)
301
        {
302
            /* Calculate dirty area. */
303
1504
            client = text_input -> gx_window_client;
304
305
            /* Offset client area by length of whitespace.  */
306
1504
            _gx_utility_rectangle_resize(&client, (GX_VALUE)(-text_input -> gx_multi_line_text_view_whitespace));
307
308
1504
            dirty_rect = client;
309
310
            /* Calculate dirty area. */
311
1504
            dirty_rect.gx_rectangle_top = (GX_VALUE)(old_cur_y - line_height - (line_height >> 1));
312
313
            /* Calculate last visible line. */
314
1504
            last_visible_line = (-text_input -> gx_multi_line_text_view_text_scroll_shift) / line_height;
315
1504
            last_visible_line = last_visible_line + (INT)text_input -> gx_multi_line_text_view_text_visible_rows + 1;
316
317
1504
            if (last_visible_line > (INT)text_input -> gx_multi_line_text_view_text_total_rows)
318
            {
319
1371
                last_visible_line = (INT)text_input -> gx_multi_line_text_view_text_total_rows;
320
            }
321
322
1504
            shift = last_visible_line * line_height + shift;
323
1504
            shift += client.gx_rectangle_top;
324
325
1504
            if (shift < dirty_rect.gx_rectangle_bottom)
326
            {
327
954
                dirty_rect.gx_rectangle_bottom = (GX_VALUE)shift;
328
            }
329
330
1504
            _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &dirty_rect);
331
        }
332
    }
333
    else
334
    {
335
305
        _gx_system_dirty_mark((GX_WIDGET *)text_input);
336
    }
337
338
1810
    return GX_SUCCESS;
339
}
340