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