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

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

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