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