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 /** Widget Management (Widget) */
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_canvas.h"
29 #include "gx_context.h"
30 #include "gx_widget.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _gx_widget_border_draw PORTABLE C */
38 /* 6.1 */
39 /* AUTHOR */
40 /* */
41 /* Kenneth Maxwell, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function draws the specified widget. */
46 /* */
47 /* INPUT */
48 /* */
49 /* widget Pointer to widget */
50 /* border_color Color of border */
51 /* upper_color Color of upper fill */
52 /* lower_color Color of lower fill */
53 /* fill flag to request fill */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* None */
58 /* */
59 /* CALLS */
60 /* */
61 /* _gx_widget_border_width_get Get border width */
62 /* _gx_context_raw_line_color_set Set line color in context */
63 /* _gx_context_brush_define Define the brush of the */
64 /* context */
65 /* _gx_context_brush_width_set Set brush width in context */
66 /* _gx_canvas_line_draw Draw a line */
67 /* _gx_widget_client_get Get widget client */
68 /* _gx_canvas_rectangle_draw Draw rectangle */
69
70 /* _gx_context_fill_color_set Set the fill color */
71 /* _gx_canvas_pixel_draw Draw a pixel */
72 /* _gx_context_line_color_set Set line color */
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_widget_border_draw(GX_WIDGET * widget,GX_RESOURCE_ID border_color,GX_RESOURCE_ID upper_color,GX_RESOURCE_ID lower_color,GX_BOOL fill)88 VOID _gx_widget_border_draw(GX_WIDGET *widget,
89 GX_RESOURCE_ID border_color,
90 GX_RESOURCE_ID upper_color,
91 GX_RESOURCE_ID lower_color, GX_BOOL fill)
92 {
93 GX_POINT corner;
94 GX_RECTANGLE fillrect;
95 GX_VALUE widget_height;
96 INT left;
97 INT right;
98 INT top;
99 GX_VALUE border_width;
100 GX_BOOL rounded = GX_FALSE;
101
102 _gx_widget_border_width_get(widget, &border_width);
103
104 if (border_width > 0)
105 {
106 /* Pick up the current brush. */
107
108 _gx_context_line_color_set(border_color);
109 top = widget -> gx_widget_size.gx_rectangle_top;
110
111 if (widget -> gx_widget_style & GX_STYLE_BORDER_THICK)
112 {
113 _gx_context_brush_width_set((UINT)border_width);
114 top += border_width / 2;
115 }
116 else
117 {
118 _gx_context_brush_width_set(1);
119 }
120
121 /* Draw line across the top. */
122 left = widget -> gx_widget_size.gx_rectangle_left;
123 right = widget -> gx_widget_size.gx_rectangle_right;
124
125 if (widget -> gx_widget_parent)
126 {
127 if (widget -> gx_widget_parent -> gx_widget_type != GX_TYPE_ROOT_WINDOW ||
128 (widget -> gx_widget_status & GX_STATUS_TRANSPARENT))
129 {
130 rounded = GX_TRUE;
131 left += 2;
132 right -= 2;
133 }
134 }
135
136 _gx_canvas_line_draw((GX_VALUE)left, (GX_VALUE)top, (GX_VALUE)right, (GX_VALUE)top);
137
138 /* Draw line across the bottom. */
139 if (widget -> gx_widget_style & GX_STYLE_BORDER_THICK)
140 {
141 top = widget -> gx_widget_size.gx_rectangle_bottom - border_width + 1;
142 top += border_width / 2;
143 _gx_canvas_line_draw((GX_VALUE)left, (GX_VALUE)top, (GX_VALUE)right, (GX_VALUE)top);
144 }
145 else
146 {
147 _gx_canvas_line_draw((GX_VALUE)left,
148 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom),
149 (GX_VALUE)right,
150 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom));
151 }
152
153 /* Draw line down left side. */
154 left = widget -> gx_widget_size.gx_rectangle_left;
155
156 if (widget -> gx_widget_style & GX_STYLE_BORDER_THICK)
157 {
158 left += border_width / 2;
159 }
160
161 if (rounded)
162 {
163 _gx_canvas_line_draw((GX_VALUE)left, (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 2),
164 (GX_VALUE)left, (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 2));
165 }
166 else
167 {
168 _gx_canvas_line_draw((GX_VALUE)left, (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + border_width - 1),
169 (GX_VALUE)left, (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - border_width + 1));
170 }
171
172 /* Draw line down right side. */
173 right = widget -> gx_widget_size.gx_rectangle_right - border_width + 1;
174 right += border_width / 2;
175
176 if (widget -> gx_widget_style & GX_STYLE_BORDER_THICK)
177 {
178 _gx_canvas_line_draw((GX_VALUE)right, (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + border_width - 1),
179 (GX_VALUE)right, (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - border_width + 1));
180
181 /* draw highlight along top border */
182 _gx_context_line_color_set(GX_COLOR_ID_SHINE);
183 _gx_context_brush_width_set(1);
184
185 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 2),
186 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 1),
187 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 2),
188 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 1));
189
190 /* draw higtlight along left border */
191 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 1),
192 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 2),
193 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 1),
194 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 2));
195
196
197 /* draw shadow along right border */
198 _gx_context_line_color_set(GX_COLOR_ID_SHADOW);
199
200 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 1),
201 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 2),
202 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 1),
203 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 2));
204
205 /* draw shadow along bottom border */
206 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 2),
207 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 1),
208 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 2),
209 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 1));
210 }
211 else
212 {
213 if (rounded)
214 {
215 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right),
216 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 2),
217 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right),
218 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 2));
219 }
220 else
221 {
222 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right),
223 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + border_width - 1),
224 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right),
225 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - border_width + 1));
226 }
227 }
228 }
229
230 if (fill && !(widget -> gx_widget_style & GX_STYLE_TRANSPARENT))
231 {
232 _gx_widget_client_get(widget, border_width, &fillrect);
233
234 /* Pickup widget width and height. */
235 _gx_widget_height_get(widget, &widget_height);
236
237 /* fill my client area */
238 /* first setup the brush color and style */
239 _gx_context_brush_define(upper_color, upper_color, GX_BRUSH_SOLID_FILL);
240 _gx_context_brush_width_set(0);
241
242 if (upper_color != lower_color)
243 {
244 fillrect.gx_rectangle_bottom = (GX_VALUE)(fillrect.gx_rectangle_top + (widget_height / 2) - 1);
245 _gx_canvas_rectangle_draw(&fillrect);
246
247 _gx_context_fill_color_set(lower_color);
248 fillrect.gx_rectangle_top = (GX_VALUE)(fillrect.gx_rectangle_bottom + 1);
249 fillrect.gx_rectangle_bottom = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 1);
250 }
251 _gx_canvas_rectangle_draw(&fillrect);
252 }
253
254 if ((widget -> gx_widget_style & GX_STYLE_BORDER_MASK) == GX_STYLE_BORDER_NONE)
255 {
256 return;
257 }
258
259 if (rounded)
260 {
261 _gx_context_line_color_set(border_color);
262
263 /* the top-left corner */
264 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 2);
265 corner.gx_point_y = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 1);
266 _gx_canvas_pixel_draw(corner);
267 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 1);
268 _gx_canvas_pixel_draw(corner);
269 corner.gx_point_y = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 2);
270 _gx_canvas_pixel_draw(corner);
271
272 /* the top-right corner */
273 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 2);
274 corner.gx_point_y = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 1);
275 _gx_canvas_pixel_draw(corner);
276 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 1);
277 _gx_canvas_pixel_draw(corner);
278 corner.gx_point_y = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 2);
279 _gx_canvas_pixel_draw(corner);
280
281 /* the bottom-right corner */
282 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 2);
283 corner.gx_point_y = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 1);
284 _gx_canvas_pixel_draw(corner);
285 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 1);
286 _gx_canvas_pixel_draw(corner);
287 corner.gx_point_y = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 2);
288 _gx_canvas_pixel_draw(corner);
289
290 /* the bottom-left corner */
291 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 2);
292 corner.gx_point_y = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 1);
293 _gx_canvas_pixel_draw(corner);
294 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 1);
295 _gx_canvas_pixel_draw(corner);
296 corner.gx_point_y = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 2);
297 _gx_canvas_pixel_draw(corner);
298 }
299
300 if (border_width != 2)
301 {
302 return;
303 }
304
305 /* check for raised or recessed border style. */
306
307 _gx_context_brush_width_set(1);
308
309 if (widget -> gx_widget_style & GX_STYLE_BORDER_RECESSED)
310 {
311 /* pick up the shadow color */
312 _gx_context_line_color_set(GX_COLOR_ID_SHADOW);
313 }
314 else
315 {
316 _gx_context_line_color_set(GX_COLOR_ID_SHINE);
317 }
318
319 if (rounded)
320 {
321 /* line down left edge */
322 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 1),
323 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 3),
324 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 1),
325 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 3));
326
327 /* line across the top */
328 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 3),
329 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 1),
330 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 3),
331 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 1));
332
333 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 2);
334 corner.gx_point_y = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 2);
335 _gx_canvas_pixel_draw(corner);
336 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 2);
337 _gx_canvas_pixel_draw(corner);
338 }
339 else
340 {
341 /* line down left edge */
342 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 1),
343 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + border_width),
344 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 1),
345 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 1));
346
347 /* line across the top */
348 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 1),
349 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 1),
350 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 1),
351 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 1));
352 }
353
354 if (widget -> gx_widget_style & GX_STYLE_BORDER_RECESSED)
355 {
356 _gx_context_line_color_set(GX_COLOR_ID_SHINE);
357 }
358 else
359 {
360 /* pick up the shadow color */
361 _gx_context_line_color_set(GX_COLOR_ID_SHADOW);
362 }
363
364 if (rounded)
365 {
366 /* line down right edge */
367 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 1),
368 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 3),
369 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 1),
370 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 3));
371
372 /* line across the bottom */
373 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 3),
374 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 1),
375 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 3),
376 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 1));
377
378 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 2);
379 corner.gx_point_y = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 2);
380 _gx_canvas_pixel_draw(corner);
381 corner.gx_point_x = (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 2);
382 _gx_canvas_pixel_draw(corner);
383 }
384 else
385 {
386 /* line down right edge */
387 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 1),
388 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_top + 2),
389 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 1),
390 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 1));
391
392 /* line across the bottom */
393 _gx_canvas_line_draw((GX_VALUE)(widget -> gx_widget_size.gx_rectangle_left + 2),
394 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 1),
395 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_right - 2),
396 (GX_VALUE)(widget -> gx_widget_size.gx_rectangle_bottom - 1));
397 }
398 }
399
400