GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_multi_line_text_input_cursor_pos_calculate.c Lines: 86 86 100.0 %
Date: 2026-03-06 19:21:09 Branches: 39 39 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
/**   Multi Line Text Input Management (Multi 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_window.h"
30
#include "gx_widget.h"
31
#include "gx_scrollbar.h"
32
#include "gx_multi_line_text_view.h"
33
#include "gx_multi_line_text_input.h"
34
#include "gx_utility.h"
35
36
/**************************************************************************/
37
/*                                                                        */
38
/*  FUNCTION                                               RELEASE        */
39
/*                                                                        */
40
/*    _gx_multi_line_text_input_cursor_pos_calculate      PORTABLE C      */
41
/*                                                           6.1          */
42
/*  AUTHOR                                                                */
43
/*                                                                        */
44
/*    Kenneth Maxwell, Microsoft Corporation                              */
45
/*                                                                        */
46
/*  DESCRIPTION                                                           */
47
/*                                                                        */
48
/*    This function gets the position of the cursor according to click    */
49
/*    position.                                                           */
50
/*                                                                        */
51
/*  INPUT                                                                 */
52
/*                                                                        */
53
/*    text_input                            Multi line text input         */
54
/*                                            control block               */
55
/*    click_pos                             Click down position           */
56
/*                                                                        */
57
/*  OUTPUT                                                                */
58
/*                                                                        */
59
/*    None                                                                */
60
/*                                                                        */
61
/*  CALLS                                                                 */
62
/*                                                                        */
63
/*    _gx_wiget_font_get                    Retrieve font                 */
64
/*    _gx_window_client_width_get           Get the client width          */
65
/*    _gx_window_scrollbar_find             Find scrollbar for a window   */
66
/*    _gx_scrollbar_reset                   Reset scrollbar information   */
67
/*    _gx_utility_rectangle_resize          Increase/Shrink rectangle by  */
68
/*                                            specified value             */
69
/*    _gx_utility_utf8_string_character_get Parses utf8 string to         */
70
/*                                            multi-byte glyph            */
71
/*    _gx_system_string_width_get           Get the width of a string     */
72
/*    _gx_multi_line_text_view_string_total_rows_compute                  */
73
/*                                          Calculate total rows of input */
74
/*                                            string                      */
75
/*    _gx_multi_line_text_view_line_cache_update                          */
76
/*                                          Update line cache             */
77
/*                                                                        */
78
/*  CALLED BY                                                             */
79
/*                                                                        */
80
/*    GUIX Internal Code                                                  */
81
/*                                                                        */
82
/**************************************************************************/
83
84
2468
UINT _gx_multi_line_text_input_cursor_pos_calculate(GX_MULTI_LINE_TEXT_INPUT *text_input, GX_POINT click_pos)
85
{
86
2468
GX_TEXT_INPUT_CURSOR *cursor_ptr = &text_input -> gx_multi_line_text_input_cursor_instance;
87
GX_FONT              *font;
88
INT                   line_height;
89
GX_RECTANGLE          client;
90
INT                   y_pos;
91
GX_POINT              cursor_pos;
92
UINT                  total_rows;
93
INT                   shift;
94
2468
UINT                  cursor_line = 0;
95
2468
UINT                  index = 0;
96
UINT                  end_index;
97
GX_STRING             string;
98
GX_VALUE              char_width;
99
GX_SCROLLBAR         *scroll;
100
2468
UINT                  glyph_len = 1;
101
GX_VALUE              text_width;
102
GX_VALUE              client_width;
103
GX_VALUE              space_width;
104
105
2468
    _gx_widget_font_get((GX_WIDGET *)text_input, text_input -> gx_multi_line_text_view_font_id, &font);
106
107
2468
    if (!font)
108
    {
109
1
        return GX_FAILURE;
110
    }
111
112
2467
    line_height = font -> gx_font_line_height + text_input -> gx_multi_line_text_view_line_space;
113
114
2467
    if (!line_height)
115
    {
116
2
        return GX_FAILURE;
117
    }
118
119
    /* Initialize the x, y position where the text displayed from. */
120
2465
    client = text_input -> gx_window_client;
121
122
    /* Offset client area by length of whitespace.  */
123
2465
    _gx_utility_rectangle_resize(&client, (GX_VALUE)(-text_input -> gx_multi_line_text_view_whitespace));
124
125
2465
    y_pos = (INT)client.gx_rectangle_top + text_input -> gx_multi_line_text_view_text_scroll_shift;
126
127
2465
    total_rows = text_input -> gx_multi_line_text_view_text_total_rows;
128
129

2465
    if ((click_pos.gx_point_y < y_pos + line_height) || (total_rows == 0))
130
    {
131
260
        cursor_line = 1;
132
    }
133
    else
134
    {
135
2205
        cursor_line = (UINT)((click_pos.gx_point_y - y_pos) / line_height + 1);
136
137
2205
        if (cursor_line > total_rows)
138
        {
139
86
            cursor_line = total_rows;
140
        }
141
    }
142
143
    /* get y coordinate of cursor postition */
144
2465
    shift = 0;
145
2465
    cursor_pos.gx_point_y = (GX_VALUE)(y_pos + (INT)(cursor_line - 1) * line_height);
146
147
2465
    if (cursor_pos.gx_point_y + line_height - 1 > client.gx_rectangle_bottom)
148
    {
149
128
        shift = client.gx_rectangle_bottom - (cursor_pos.gx_point_y + line_height - 1);
150
    }
151
2337
    else if (cursor_pos.gx_point_y < client.gx_rectangle_top)
152
    {
153
118
        shift = client.gx_rectangle_top - cursor_pos.gx_point_y;
154
    }
155
156
2465
    if (shift)
157
    {
158
246
        text_input -> gx_multi_line_text_view_text_scroll_shift += shift;
159
246
        cursor_pos.gx_point_y = (GX_VALUE)(cursor_pos.gx_point_y + shift);
160
161
246
        _gx_window_scrollbar_find((GX_WINDOW *)text_input, GX_TYPE_VERTICAL_SCROLL, &scroll);
162
246
        if (scroll)
163
        {
164
            /* Reset scrollbar.  */
165
227
            _gx_scrollbar_reset(scroll, GX_NULL);
166
        }
167
        else
168
        {
169
170
19
            if (text_input -> gx_multi_line_text_view_text_total_rows >
171
19
                text_input -> gx_multi_line_text_view_cache_size)
172
            {
173
13
                _gx_multi_line_text_view_line_cache_update((GX_MULTI_LINE_TEXT_VIEW *)text_input);
174
            }
175
        }
176
    }
177
178
    /* get x coordinate of cursor position. */
179
2465
    cursor_pos.gx_point_x = (GX_VALUE)(client.gx_rectangle_left + 1);
180
2465
    text_input -> gx_multi_line_text_input_text_cursor_line = cursor_line;
181
182
2465
    cursor_line = (UINT)(cursor_line - 1);
183
2465
    cursor_line = (UINT)(cursor_line - text_input -> gx_multi_line_text_view_first_cache_line);
184
185
2465
    index = (text_input -> gx_multi_line_text_view_line_index[cursor_line]);
186
187
2465
    if (cursor_line >= (UINT)(text_input -> gx_multi_line_text_view_cache_size - 1))
188
    {
189
204
        end_index = text_input -> gx_multi_line_text_view_text.gx_string_length;
190
    }
191
    else
192
    {
193
2261
        end_index = text_input -> gx_multi_line_text_view_line_index[cursor_line + 1];
194
    }
195
196
2465
    string.gx_string_ptr = " ";
197
2465
    string.gx_string_length = 1;
198
199
2465
    _gx_system_string_width_get_ext(font, &string, &space_width);
200
201
2465
    switch (text_input -> gx_widget_style & GX_STYLE_TEXT_ALIGNMENT_MASK)
202
    {
203
491
    case GX_STYLE_TEXT_RIGHT:
204
491
        string.gx_string_ptr = text_input -> gx_multi_line_text_view_text.gx_string_ptr + index;
205
491
        string.gx_string_length = end_index - index;
206
491
        _gx_system_string_width_get_ext(font, &string, &text_width);
207
501
        while (text_width > (client.gx_rectangle_right - client.gx_rectangle_left - 2))
208
        {
209
10
            text_width = (GX_VALUE)(text_width - space_width);
210
        }
211
491
        cursor_pos.gx_point_x = (GX_VALUE)(client.gx_rectangle_right - 1);
212
491
        cursor_pos.gx_point_x = (GX_VALUE)(cursor_pos.gx_point_x - text_width);
213
491
        break;
214
215
1483
    case GX_STYLE_TEXT_LEFT:
216
1483
        cursor_pos.gx_point_x = (GX_VALUE)(client.gx_rectangle_left + 1);
217
1483
        break;
218
219
491
    case GX_STYLE_TEXT_CENTER:
220
    default:
221
491
        string.gx_string_ptr = text_input -> gx_multi_line_text_view_text.gx_string_ptr + index;
222
491
        string.gx_string_length = end_index - index;
223
491
        _gx_system_string_width_get_ext(font, &string, &text_width);
224
491
        client_width = (GX_VALUE)(client.gx_rectangle_right - client.gx_rectangle_left + 1);
225
504
        while (text_width > (client_width - 3))
226
        {
227
13
            text_width = (GX_VALUE)(text_width - space_width);
228
        }
229
491
        cursor_pos.gx_point_x = (GX_VALUE)(client.gx_rectangle_left + ((client_width - text_width) / 2));
230
491
        break;
231
    }
232
233
8172
    while (index < end_index)
234
    {
235
8016
        string.gx_string_ptr = text_input -> gx_multi_line_text_view_text.gx_string_ptr + index;
236
8016
        string.gx_string_length = end_index - index;
237

8016
        if ((string.gx_string_ptr[0] == GX_KEY_CARRIAGE_RETURN) || (string.gx_string_ptr[0] == GX_KEY_LINE_FEED))
238
        {
239
            break;
240
        }
241
#ifdef GX_UTF8_SUPPORT
242
243
7247
        _gx_utility_utf8_string_character_get(&string, GX_NULL, &glyph_len);
244
#else
245
        string.gx_string_ptr += glyph_len;
246
#endif
247
7247
        string.gx_string_ptr -= glyph_len;
248
7247
        string.gx_string_length = glyph_len;
249
7247
        _gx_system_string_width_get_ext(font, &string, &char_width);
250
7247
        if ((cursor_pos.gx_point_x + char_width / 2) > click_pos.gx_point_x)
251
        {
252
1541
            while (cursor_pos.gx_point_x > client.gx_rectangle_right - 1)
253
            {
254
1
                cursor_pos.gx_point_x = (GX_VALUE)(cursor_pos.gx_point_x - space_width);
255
            }
256
1540
            break;
257
        }
258
5707
        cursor_pos.gx_point_x = (GX_VALUE)(cursor_pos.gx_point_x + char_width);
259
5707
        index += glyph_len;
260
    }
261
262
2465
    cursor_ptr -> gx_text_input_cursor_pos = cursor_pos;
263
2465
    cursor_ptr -> gx_text_input_cursor_pos.gx_point_y = (GX_VALUE)(cursor_ptr -> gx_text_input_cursor_pos.gx_point_y + (line_height >> 1));
264
265
    /* record text insert position. */
266
2465
    text_input -> gx_multi_line_text_input_text_insert_position = index;
267
268
2465
    return GX_SUCCESS;
269
}
270