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