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_utility.h"
29 #include "gx_canvas.h"
30 #include "gx_context.h"
31 #include "gx_widget.h"
32 #include "gx_single_line_text_input.h"
33 #include "gx_text_input_cursor.h"
34 
35 /**************************************************************************/
36 /*                                                                        */
37 /*  FUNCTION                                               RELEASE        */
38 /*                                                                        */
39 /*    _gx_single_line_text_input_draw                     PORTABLE C      */
40 /*                                                           6.1          */
41 /*  AUTHOR                                                                */
42 /*                                                                        */
43 /*    Kenneth Maxwell, Microsoft Corporation                              */
44 /*                                                                        */
45 /*  DESCRIPTION                                                           */
46 /*                                                                        */
47 /*    This service draws a text input widget. This service is normally    */
48 /*    called internally during canvas refresh, but can also be called from*/
49 /*    custom text input drawing functions.                                */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    text_input                            Single-line text input widget */
54 /*                                            control block.              */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    None                                                                */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _gx_widget_background_draw            Draw widget background        */
63 /*    _gx_widget_border_draw                Draw widget border            */
64 /*    _gx_widget_border_width_get           Get widget border width       */
65 /*    _gx_widget_client_get                 Get widget client rectangle   */
66 /*   _gx_widget_children_draw               Draw widget children          */
67 /*    _gx_context_line_color_set            Set the line color for the    */
68 /*                                            context                     */
69 /*    _gx_context_font_set                  Set the font in the context   */
70 /*    _gx_context_brush_width_set           Set the width of brush        */
71 /*    _gx_canvas_text_draw                  Draw the text                 */
72 /*    _gx_canvas_drawing_initiate           Initiate drawing on specified */
73 /*                                            canvas                      */
74 /*    _gx_canvas_drawing_complete           Complete drawing on specified */
75 /*                                            canvas                      */
76 /*    _gx_text_input_cursor_draw            Draw a text input cursor      */
77 /*    _gx_utility_rectangle_overlap_detect  Detect overlap of the         */
78 /*                                            supplied rectangles         */
79 /*    _gx_single_line_text_input_draw_position_get                        */
80 /*                                          Get text draw start position  */
81 /*                                                                        */
82 /*  CALLED BY                                                             */
83 /*                                                                        */
84 /*    Application Code                                                    */
85 /*    GUIX Internal Code                                                  */
86 /*                                                                        */
87 /*  RELEASE HISTORY                                                       */
88 /*                                                                        */
89 /*    DATE              NAME                      DESCRIPTION             */
90 /*                                                                        */
91 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
92 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
93 /*                                            resulting in version 6.1    */
94 /*                                                                        */
95 /**************************************************************************/
_gx_single_line_text_input_draw(GX_SINGLE_LINE_TEXT_INPUT * text_input)96 VOID  _gx_single_line_text_input_draw(GX_SINGLE_LINE_TEXT_INPUT *text_input)
97 {
98 UINT                  status = GX_SUCCESS;
99 GX_WIDGET            *widget = (GX_WIDGET *)text_input;
100 GX_TEXT_INPUT_CURSOR *cursor_ptr = &text_input -> gx_single_line_text_input_cursor_instance;
101 GX_RESOURCE_ID        fill_color;
102 GX_RESOURCE_ID        text_color;
103 GX_VALUE              border_width;
104 GX_VALUE              client_height;
105 GX_VALUE              x_pos;
106 GX_VALUE              y_pos;
107 GX_RECTANGLE          client;
108 GX_RECTANGLE          overlap;
109 GX_CANVAS            *canvas;
110 UINT                  start_mark = text_input -> gx_single_line_text_input_start_mark;
111 UINT                  end_mark = text_input -> gx_single_line_text_input_end_mark;
112 GX_VALUE              text_width;
113 GX_BRUSH             *brush;
114 GX_CHAR              *input_buffer = text_input -> gx_single_line_text_input_buffer;
115 GX_STRING             string;
116 
117     /* Draw text input background.  */
118     if (text_input -> gx_widget_style & GX_STYLE_ENABLED)
119     {
120         if (text_input -> gx_widget_style & GX_STYLE_TEXT_INPUT_READONLY)
121         {
122             fill_color = text_input -> gx_single_line_text_input_readonly_fill_color;
123             text_color = text_input -> gx_single_line_text_input_readonly_text_color;
124         }
125         else
126         {
127             fill_color = text_input -> gx_widget_normal_fill_color;
128             text_color = text_input -> gx_prompt_normal_text_color;
129         }
130     }
131     else
132     {
133         fill_color = text_input -> gx_widget_disabled_fill_color;
134         text_color = text_input -> gx_prompt_disabled_text_color;
135     }
136 
137     _gx_widget_border_draw(widget, GX_COLOR_ID_WINDOW_BORDER, fill_color, fill_color, GX_TRUE);
138 
139     _gx_context_font_set(text_input -> gx_prompt_font_id);
140 
141     /* Calculate text draw position. */
142     status = _gx_single_line_text_input_draw_position_get(text_input, &x_pos, &y_pos);
143 
144     if (status != GX_SUCCESS)
145     {
146         return;
147     }
148 
149     /* Pickup widget width. */
150     _gx_widget_border_width_get(widget, &border_width);
151 
152     /* Get client rectangle. */
153     _gx_widget_client_get(widget, border_width, &client);
154 
155     _gx_context_line_color_set(text_color);
156 
157     /* pick up current canvas */
158     canvas = _gx_system_current_draw_context -> gx_draw_context_canvas;
159     _gx_utility_rectangle_overlap_detect(&_gx_system_current_draw_context -> gx_draw_context_dirty, &client, &overlap);
160     _gx_canvas_drawing_initiate(canvas, widget, &overlap);
161 
162     /* Draw the cursor. */
163     if ((start_mark == end_mark) &&
164         (text_input -> gx_widget_status & GX_STATUS_CURSOR_SHOW) &&
165         (text_input -> gx_widget_status & GX_STATUS_CURSOR_DRAW))
166     {
167         client_height = (GX_VALUE)(client.gx_rectangle_bottom - client.gx_rectangle_top + 1);
168 
169         if (!(cursor_ptr -> gx_text_input_cursor_flags & GX_CURSOR_USE_CUSTOM_HEIGHT))
170         {
171             cursor_ptr -> gx_text_input_cursor_height = (GX_VALUE)(client_height - 4);
172         }
173         cursor_ptr -> gx_text_input_cursor_pos.gx_point_y = (GX_VALUE)(client.gx_rectangle_top + (client_height >> 1));
174 
175         _gx_text_input_cursor_draw(cursor_ptr);
176     }
177 
178     /* Is there a string?  */
179     if (input_buffer && (*input_buffer))
180     {
181         /* Draw the text.  */
182         if (start_mark == end_mark)
183         {
184             string.gx_string_ptr = input_buffer;
185             string.gx_string_length = text_input -> gx_single_line_text_input_string_size;
186             _gx_canvas_text_draw_ext(x_pos, y_pos, &string);
187         }
188         else
189         {
190             _gx_context_brush_get(&brush);
191 
192             if (start_mark > end_mark)
193             {
194                 GX_SWAP_VALS(start_mark, end_mark);
195             }
196 
197             if (start_mark > 0)
198             {
199                 /* Draw text[0:start_mark - 1] with normak text color. */
200                 string.gx_string_ptr = input_buffer;
201                 string.gx_string_length = start_mark;
202                 _gx_system_string_width_get_ext(brush -> gx_brush_font, &string, &text_width);
203                 _gx_canvas_text_draw_ext(x_pos, y_pos, &string);
204                 x_pos = (GX_VALUE)(x_pos + text_width);
205             }
206 
207             /* Draw text[start_mark:end_mark - 1] with highlight text color. */
208             _gx_context_line_color_set(text_input -> gx_prompt_selected_text_color);
209             _gx_context_fill_color_set(text_input -> gx_widget_selected_fill_color);
210             _gx_context_brush_width_set(0);
211 
212             string.gx_string_ptr = input_buffer + start_mark;
213             string.gx_string_length = (UINT)(end_mark - start_mark);
214             _gx_system_string_width_get_ext(brush -> gx_brush_font, &string, &text_width);
215 
216             client_height = (GX_VALUE)(client.gx_rectangle_bottom - client.gx_rectangle_top + 1);
217 
218             if (!(cursor_ptr -> gx_text_input_cursor_flags & GX_CURSOR_USE_CUSTOM_HEIGHT))
219             {
220                 cursor_ptr -> gx_text_input_cursor_height = (GX_VALUE)(client_height - 4);
221             }
222 
223             client.gx_rectangle_left = x_pos;
224             client.gx_rectangle_right = (GX_VALUE)(x_pos + text_width - 1);
225             client.gx_rectangle_top = (GX_VALUE)(client.gx_rectangle_top + ((client_height - cursor_ptr -> gx_text_input_cursor_height) >> 1));
226             client.gx_rectangle_bottom = (GX_VALUE)(client.gx_rectangle_top + cursor_ptr -> gx_text_input_cursor_height - 1);
227 
228             _gx_canvas_rectangle_draw(&client);
229             _gx_canvas_text_draw_ext(x_pos, y_pos, &string);
230             x_pos = (GX_VALUE)(x_pos + text_width);
231 
232             if (end_mark < text_input -> gx_single_line_text_input_string_size)
233             {
234                 /* Draw text[end_mark:] with normal text color. */
235                 _gx_context_line_color_set(text_color);
236 
237                 string.gx_string_ptr = input_buffer + end_mark;
238                 string.gx_string_length = text_input -> gx_single_line_text_input_string_size - end_mark;
239                 _gx_canvas_text_draw_ext(x_pos, y_pos, &string);
240             }
241         }
242     }
243 
244     _gx_canvas_drawing_complete(canvas, GX_FALSE);
245 
246     _gx_widget_children_draw(widget);
247 }
248 
249