GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_multi_line_text_input_cursor_pos_update.c Lines: 109 109 100.0 %
Date: 2024-12-05 08:52:37 Branches: 61 61 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_widget.h"
29
#include "gx_window.h"
30
#include "gx_scrollbar.h"
31
#include "gx_utility.h"
32
#include "gx_multi_line_text_view.h"
33
#include "gx_multi_line_text_input.h"
34
35
/**************************************************************************/
36
/*                                                                        */
37
/*  FUNCTION                                               RELEASE        */
38
/*                                                                        */
39
/*    _gx_multi_line_text_input_cursor_pos_update         PORTABLE C      */
40
/*                                                           6.1          */
41
/*  AUTHOR                                                                */
42
/*                                                                        */
43
/*    Kenneth Maxwell, Microsoft Corporation                              */
44
/*                                                                        */
45
/*  DESCRIPTION                                                           */
46
/*                                                                        */
47
/*    This function gets the position of the cursor according to insert   */
48
/*      index.                                                            */
49
/*                                                                        */
50
/*  INPUT                                                                 */
51
/*                                                                        */
52
/*    text_input                            Multi line text input         */
53
/*                                            control block               */
54
/*                                                                        */
55
/*  OUTPUT                                                                */
56
/*                                                                        */
57
/*    None                                                                */
58
/*                                                                        */
59
/*  CALLS                                                                 */
60
/*                                                                        */
61
/*    _gx_widget_font_get                   Retrieve font                 */
62
/*    _gx_window_scrollbar_find             Find scrollbar for a window   */
63
/*    _gx_scrollbar_reset                   Reset scrollbar information   */
64
/*    _gx_system_string_width_get           Get the width of a string     */
65
/*    _gx_utility_rectangle_resize          Increase/Shrink rectangle by  */
66
/*                                            specified value             */
67
/*                                                                        */
68
/*  CALLED BY                                                             */
69
/*                                                                        */
70
/*    GUIX Intercal Code                                                  */
71
/*                                                                        */
72
/*  RELEASE HISTORY                                                       */
73
/*                                                                        */
74
/*    DATE              NAME                      DESCRIPTION             */
75
/*                                                                        */
76
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
77
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
78
/*                                            resulting in version 6.1    */
79
/*                                                                        */
80
/**************************************************************************/
81
82
6791
UINT _gx_multi_line_text_input_cursor_pos_update(GX_MULTI_LINE_TEXT_INPUT *text_input, GX_BOOL make_cursor_visible)
83
{
84
6791
GX_TEXT_INPUT_CURSOR    *cursor_ptr = &text_input -> gx_multi_line_text_input_cursor_instance;
85
6791
GX_MULTI_LINE_TEXT_VIEW *view = (GX_MULTI_LINE_TEXT_VIEW *)text_input;
86
GX_FONT                 *font;
87
GX_VALUE                 line_height;
88
UINT                     insert_pos;
89
UINT                     cur_line;
90
USHORT                   cache_index;
91
GX_CHAR                 *string_buffer;
92
GX_POINT                 cur_pos;
93
GX_RECTANGLE             client;
94
INT                      y_pos;
95
GX_VALUE                 text_width;
96
GX_VALUE                 space_width;
97
GX_VALUE                 client_width;
98
UINT                     start_index;
99
UINT                     end_index;
100
GX_STRING                string;
101
GX_MULTI_LINE_TEXT_INFO  text_info;
102
103
6791
    _gx_widget_font_get((GX_WIDGET *)text_input, text_input -> gx_multi_line_text_view_font_id, &font);
104
105
6791
    if (!font)
106
    {
107
15
        return GX_FAILURE;
108
    }
109
110
6776
    line_height = (GX_VALUE)(font -> gx_font_line_height +
111
6776
                             text_input -> gx_multi_line_text_view_line_space);
112
6776
    text_width = 0;
113
114
6776
    if (!line_height)
115
    {
116
10
        return GX_FAILURE;
117
    }
118
119
    /* Get the y position where the text displayed from. */
120
6766
    client = text_input -> gx_window_client;
121
122
6766
    if (text_input -> gx_multi_line_text_view_whitespace)
123
    {
124
        /* Offset client bounding box.  */
125
4017
        _gx_utility_rectangle_resize(&client, (GX_VALUE)(-text_input -> gx_multi_line_text_view_whitespace));
126
    }
127
128
6766
    client_width = (GX_VALUE)(client.gx_rectangle_right - client.gx_rectangle_left + 1);
129
130
6766
    string_buffer = (GX_CHAR *)text_input -> gx_multi_line_text_view_text.gx_string_ptr;
131
132
6766
    insert_pos = text_input -> gx_multi_line_text_input_text_insert_position;
133
134
6766
    cache_index = 0;
135
6766
    cur_line = 0;
136
137
6766
    if ((cache_index < view -> gx_multi_line_text_view_cache_size) &&
138
6544
        (view -> gx_multi_line_text_view_line_index[0] > insert_pos))
139
    {
140
        /* Insert position is before cached lines. Search from start. */
141
6
        start_index = 0;
142
6
        end_index = text_input -> gx_multi_line_text_view_text.gx_string_length;
143
6
        cur_line = 1;
144
145
        while (1)
146
        {
147
            /* Calculate some information used to draw the text. */
148
8
            _gx_multi_line_text_view_display_info_get((GX_MULTI_LINE_TEXT_VIEW *)text_input, start_index, end_index, &text_info, (GX_VALUE)(client_width - 2));
149
150
8
            start_index += text_info.gx_text_display_number;
151
152
8
            if (start_index >= insert_pos)
153
            {
154
6
                end_index = start_index;
155
6
                start_index -= text_info.gx_text_display_number;
156
6
                break;
157
            }
158
159
2
            cur_line++;
160
        }
161
162
6
        if (insert_pos)
163
        {
164
5
            if ((string_buffer[insert_pos - 1] == GX_KEY_CARRIAGE_RETURN) ||
165
4
                (string_buffer[insert_pos - 1] == GX_KEY_LINE_FEED))
166
            {
167
2
                cur_line++;
168
            }
169
        }
170
    }
171
    else
172
    {
173
        /* Find the cursor line. */
174
110155
        while (cache_index < view -> gx_multi_line_text_view_cache_size)
175
        {
176
107674
            if (view -> gx_multi_line_text_view_line_index[cache_index] >= insert_pos)
177
            {
178
4279
                break;
179
            }
180
103395
            cache_index++;
181
        }
182
183
6760
        if (cache_index < view -> gx_multi_line_text_view_cache_size)
184
        {
185
            /* Found insert position. */
186
4279
            if (insert_pos &&
187
4045
                (string_buffer[insert_pos - 1] != GX_KEY_CARRIAGE_RETURN) &&
188

2468
                (string_buffer[insert_pos - 1] != GX_KEY_LINE_FEED) && cache_index)
189
            {
190
2191
                cache_index--;
191
            }
192
193
            /* cursor line is started from 1. */
194
4279
            cur_line = cache_index + view -> gx_multi_line_text_view_first_cache_line + 1;
195
196
            /* get x coordinate of cursor postition */
197
4279
            start_index = text_input -> gx_multi_line_text_view_line_index[cache_index];
198
199
4279
            if (cache_index >= view -> gx_multi_line_text_view_cache_size - 1)
200
            {
201
381
                end_index = text_input -> gx_multi_line_text_view_text.gx_string_length;
202
            }
203
            else
204
            {
205
3898
                end_index = text_input -> gx_multi_line_text_view_line_index[cache_index + 1];
206
            }
207
        }
208
2481
        else if (view -> gx_multi_line_text_view_cache_size)
209
        {
210
            /* Insert position is after cached lines, search from last cached line. */
211
2259
            cache_index = (USHORT)(view -> gx_multi_line_text_view_cache_size - 1);
212
2259
            cur_line = cache_index + view -> gx_multi_line_text_view_first_cache_line + 1;
213
2259
            start_index = text_input -> gx_multi_line_text_view_line_index[cache_index];
214
2259
            end_index = text_input -> gx_multi_line_text_view_text.gx_string_length;
215
216
3375
            while (start_index < end_index)
217
            {
218
                /* Calculate some information used to draw the text. */
219
3374
                _gx_multi_line_text_view_display_info_get((GX_MULTI_LINE_TEXT_VIEW *)text_input, start_index, end_index, &text_info, (GX_VALUE)(client_width - 2));
220
221
3374
                start_index += text_info.gx_text_display_number;
222
223
3374
                if (start_index >= insert_pos)
224
                {
225
2258
                    end_index = start_index;
226
2258
                    start_index -= text_info.gx_text_display_number;
227
2258
                    break;
228
                }
229
230
1116
                cur_line++;
231
            }
232
233
2259
            if ((string_buffer[insert_pos - 1] == GX_KEY_CARRIAGE_RETURN) ||
234
2257
                (string_buffer[insert_pos - 1] == GX_KEY_LINE_FEED))
235
            {
236
6
                cur_line++;
237
            }
238
        }
239
        else
240
        {
241
            /* No character. */
242
222
            start_index = 0;
243
222
            end_index = 0;
244
222
            cur_line = 1;
245
        }
246
    }
247
248
6766
    string.gx_string_ptr = " ";
249
6766
    string.gx_string_length = 1;
250
6766
    _gx_system_string_width_get_ext(font, &string, &space_width);
251
252
6766
    switch (text_input -> gx_widget_style & GX_STYLE_TEXT_ALIGNMENT_MASK)
253
    {
254
1536
    case GX_STYLE_TEXT_RIGHT:
255
1536
        string.gx_string_ptr = (GX_CHAR *)text_input -> gx_multi_line_text_view_text.gx_string_ptr + start_index;
256
1536
        string.gx_string_length = end_index - start_index;
257
1536
        _gx_system_string_width_get_ext(font, &string, &text_width);
258
1704
        while (text_width > (client.gx_rectangle_right - client.gx_rectangle_left - 2))
259
        {
260
168
            text_width = (GX_VALUE)(text_width - space_width);
261
        }
262
1536
        cur_pos.gx_point_x = (GX_VALUE)(client.gx_rectangle_right - 1);
263
1536
        cur_pos.gx_point_x = (GX_VALUE)(cur_pos.gx_point_x - text_width);
264
1536
        break;
265
266
3675
    case GX_STYLE_TEXT_LEFT:
267
3675
        cur_pos.gx_point_x = (GX_VALUE)(client.gx_rectangle_left + 1);
268
3675
        break;
269
270
1555
    case GX_STYLE_TEXT_CENTER:
271
    default:
272
1555
        string.gx_string_ptr = (GX_CHAR *)text_input -> gx_multi_line_text_view_text.gx_string_ptr + start_index;
273
1555
        string.gx_string_length = end_index - start_index;
274
1555
        _gx_system_string_width_get_ext(font, &string, &text_width);
275
1824
        while (text_width > (client.gx_rectangle_right - client.gx_rectangle_left - 2))
276
        {
277
269
            text_width = (GX_VALUE)(text_width - space_width);
278
        }
279
280
1555
        cur_pos.gx_point_x = (GX_VALUE)(client.gx_rectangle_left + ((client_width - text_width) / 2));
281
1555
        break;
282
    }
283
284
6766
    if (insert_pos &&
285
6310
        (string_buffer[insert_pos - 1] != GX_KEY_CARRIAGE_RETURN) &&
286
4730
        (string_buffer[insert_pos - 1] != GX_KEY_LINE_FEED))
287
    {
288
4449
        string.gx_string_ptr = string_buffer + start_index;
289
4449
        string.gx_string_length = insert_pos - start_index;
290
4449
        _gx_system_string_width_get_ext(font, &string, &text_width);
291
4449
        cur_pos.gx_point_x = (GX_VALUE)(cur_pos.gx_point_x + text_width);
292
    }
293
294
    /* make cursor position inside client area. */
295
7022
    while (cur_pos.gx_point_x > client.gx_rectangle_right - 1)
296
    {
297
256
        cur_pos.gx_point_x = (GX_VALUE)(cur_pos.gx_point_x - space_width);
298
    }
299
300
    /* Update cursor line. */
301
6766
    text_input -> gx_multi_line_text_input_text_cursor_line = cur_line;
302
303
    /* get y coordinate of cursor postition */
304
6766
    y_pos = (INT)client.gx_rectangle_top + text_input -> gx_multi_line_text_view_text_scroll_shift;
305
306
6766
    cur_pos.gx_point_y = (GX_VALUE)(y_pos + (INT)(cur_line - 1) * line_height);
307
6766
    cur_pos.gx_point_y = (GX_VALUE)(cur_pos.gx_point_y + (line_height >> 1));
308
309
6766
    cursor_ptr -> gx_text_input_cursor_pos = cur_pos;
310
311
6766
    if (make_cursor_visible)
312
    {
313
5916
        _gx_multi_line_text_input_cursor_visible(text_input);
314
    }
315
6766
    return GX_SUCCESS;
316
}
317