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_context.h"
29 #include "gx_widget.h"
30 #include "gx_single_line_text_input.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _gx_single_line_text_input_character_insert PORTABLE C */
38 /* 6.1 */
39 /* AUTHOR */
40 /* */
41 /* Kenneth Maxwell, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This services inserts a character into the text input string at the */
46 /* current cursor position. */
47 /* */
48 /* INPUT */
49 /* */
50 /* text_input Single-line text input widget */
51 /* control block */
52 /* insert_str Byte string of insert */
53 /* character */
54 /* insert_size String size of insert */
55 /* character */
56 /* */
57 /* OUTPUT */
58 /* */
59 /* None */
60 /* */
61 /* CALLS */
62 /* */
63 /* memmove Move a block of memory */
64 /* _gx_widget_font_get Get font by specified ID */
65 /* _gx_widget_border_width_get Get the widget border width */
66 /* _gx_widget_client_get Get widget client rectangle */
67 /* _gx_system_string_width_get Get the width of a string */
68 /* _gx_system_dirty_partial_add Mark the partial area of a */
69 /* widget as dirty */
70 /* _gx_single_line_text_input_backspace Remove text before the cursor */
71 /* _gx_single_line_text_input_character_delete */
72 /* Remove text after the cursor */
73 /* */
74 /* CALLED BY */
75 /* */
76 /* Application Code */
77 /* GUIX Internal Code */
78 /* */
79 /* RELEASE HISTORY */
80 /* */
81 /* DATE NAME DESCRIPTION */
82 /* */
83 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
84 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
85 /* resulting in version 6.1 */
86 /* */
87 /**************************************************************************/
_gx_single_line_text_input_character_insert(GX_SINGLE_LINE_TEXT_INPUT * text_input,GX_UBYTE * insert_str,UINT insert_size)88 UINT _gx_single_line_text_input_character_insert(GX_SINGLE_LINE_TEXT_INPUT *text_input, GX_UBYTE *insert_str, UINT insert_size)
89 {
90 GX_TEXT_INPUT_CURSOR *cursor_ptr;
91 UINT buffer_size;
92 GX_CHAR *string_buffer;
93 UINT string_size;
94 GX_VALUE new_cursor_pos;
95 UINT insert_pos;
96 GX_VALUE border_width;
97 GX_VALUE client_right;
98 GX_VALUE client_width;
99 GX_VALUE insert_width;
100 GX_VALUE text_width;
101 GX_FONT *gx_font;
102 GX_RECTANGLE dirty_area;
103 GX_STRING string;
104
105 /* Delete hightlight text. */
106 if (text_input -> gx_single_line_text_input_start_mark != text_input -> gx_single_line_text_input_end_mark)
107 {
108 if (text_input -> gx_single_line_text_input_end_mark > text_input -> gx_single_line_text_input_start_mark)
109 {
110 _gx_single_line_text_input_backspace(text_input);
111 }
112 else
113 {
114 _gx_single_line_text_input_character_delete(text_input);
115 }
116 }
117
118 cursor_ptr = &text_input -> gx_single_line_text_input_cursor_instance;
119
120 buffer_size = text_input -> gx_single_line_text_input_buffer_size;
121 string_size = text_input -> gx_single_line_text_input_string_size;
122
123 /* Judge whether there have remaining buffer size. */
124 if (buffer_size < string_size + insert_size + 1)
125 {
126 return GX_FAILURE;
127 }
128
129 string_buffer = text_input -> gx_single_line_text_input_buffer;
130
131 _gx_widget_font_get((GX_WIDGET *)text_input, text_input -> gx_prompt_font_id, &gx_font);
132
133 /* Pick up text witth. */
134 string.gx_string_ptr = string_buffer;
135 string.gx_string_length = text_input -> gx_single_line_text_input_string_size;
136 _gx_system_string_width_get_ext(gx_font, &string, &text_width);
137
138 /* Insert a char to the string buffer. */
139 insert_pos = text_input -> gx_single_line_text_input_insert_pos;
140 memmove(string_buffer + insert_pos + insert_size, string_buffer + insert_pos, string_size - insert_pos);
141 memmove(string_buffer + insert_pos, insert_str, insert_size);
142 string_buffer[string_size + insert_size] = '\0';
143
144 /* Update the input string size and cursor position. */
145 text_input -> gx_single_line_text_input_string_size += insert_size;
146 text_input -> gx_single_line_text_input_insert_pos += insert_size;
147
148 /* Calculate inside widget right. */
149 _gx_widget_border_width_get((GX_WIDGET *)text_input, &border_width);
150 _gx_widget_client_get((GX_WIDGET *)text_input, border_width, &dirty_area);
151 client_right = dirty_area.gx_rectangle_right;
152
153 /* Get inset character width. */
154 string.gx_string_ptr = (GX_CONST GX_CHAR *)insert_str;
155 string.gx_string_length = insert_size;
156 _gx_system_string_width_get_ext(gx_font, &string, &insert_width);
157
158 switch (text_input -> gx_widget_style & GX_STYLE_TEXT_ALIGNMENT_MASK)
159 {
160 case GX_STYLE_TEXT_RIGHT:
161 text_input -> gx_single_line_text_input_xoffset = (GX_VALUE)(text_input -> gx_single_line_text_input_xoffset + insert_width);
162
163 dirty_area.gx_rectangle_right = cursor_ptr -> gx_text_input_cursor_pos.gx_point_x;
164 break;
165
166 case GX_STYLE_TEXT_CENTER:
167 /* Calculate the cursor position. */
168 client_width = (GX_VALUE)(dirty_area.gx_rectangle_right - dirty_area.gx_rectangle_left + 1);
169 text_width = (GX_VALUE)(text_width + insert_width);
170 new_cursor_pos = (GX_VALUE)(cursor_ptr -> gx_text_input_cursor_pos.gx_point_x -
171 (((text_width + 1) >> 1) - text_input -> gx_single_line_text_input_xoffset) +
172 insert_width);
173 /* Update offset in x axis. */
174 text_input -> gx_single_line_text_input_xoffset = (GX_VALUE)((text_width + 1) >> 1);
175
176 /* Update offset in x axis. */
177 if (new_cursor_pos < client_right - 1)
178 {
179 dirty_area.gx_rectangle_left = (GX_VALUE)(dirty_area.gx_rectangle_left + 1 + (client_width >> 1) - text_input -> gx_single_line_text_input_xoffset);
180 dirty_area.gx_rectangle_right = (GX_VALUE)(dirty_area.gx_rectangle_left + text_width);
181 dirty_area.gx_rectangle_left = (GX_VALUE)(dirty_area.gx_rectangle_left - (cursor_ptr -> gx_text_input_cursor_width >> 1));
182 dirty_area.gx_rectangle_right = (GX_VALUE)(dirty_area.gx_rectangle_right + ((cursor_ptr -> gx_text_input_cursor_width + 1) >> 1) - 1);
183 }
184
185 cursor_ptr -> gx_text_input_cursor_pos.gx_point_x = new_cursor_pos;
186 break;
187
188 case GX_STYLE_TEXT_LEFT:
189 default:
190 /* Calculate cursor position. */
191 new_cursor_pos = (GX_VALUE)(cursor_ptr -> gx_text_input_cursor_pos.gx_point_x + insert_width);
192
193 /* Update offset in x axis. */
194 if (new_cursor_pos > client_right - 1)
195 {
196 text_input -> gx_single_line_text_input_xoffset = (GX_VALUE)(text_input -> gx_single_line_text_input_xoffset + new_cursor_pos - client_right + 1);
197
198 new_cursor_pos = (GX_VALUE)(client_right - 1);
199 }
200 else
201 {
202 dirty_area.gx_rectangle_left = (GX_VALUE)(cursor_ptr -> gx_text_input_cursor_pos.gx_point_x - (cursor_ptr -> gx_text_input_cursor_width >> 1));
203 dirty_area.gx_rectangle_right = (GX_VALUE)(new_cursor_pos + text_width + cursor_ptr -> gx_text_input_cursor_width - 1);
204 }
205
206 /* Update x coordinate of cursor position. */
207 cursor_ptr -> gx_text_input_cursor_pos.gx_point_x = new_cursor_pos;
208 break;
209 }
210
211 /* Mark the text input widget be changed. */
212 text_input -> gx_single_line_text_input_was_modified = GX_TRUE;
213
214 _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &dirty_area);
215
216 return GX_SUCCESS;
217 }
218
219