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 /**   Progress Bar Management (Radial Progress Bar)                       */
18 /**                                                                       */
19 /**************************************************************************/
20 
21 #define GX_SOURCE_CODE
22 
23 /* Include necessary system files.  */
24 
25 #include "gx_api.h"
26 #include "gx_context.h"
27 #include "gx_widget.h"
28 #include "gx_canvas.h"
29 #include "gx_utility.h"
30 #include "gx_radial_progress_bar.h"
31 #include "gx_system.h"
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _gx_radial_progress_bar_background_draw             PORTABLE C      */
38 /*                                                           6.1.8        */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Kenneth Maxwell, Microsoft Corporation                              */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This service draws a radial progress bar background.                */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    progress_bar                          Radial Progress Bar control   */
50 /*                                            block                       */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    None                                                                */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    _gx_widget_background_draw                                          */
59 /*    _gx_context_brush_get                                               */
60 /*    _gx_context_line_color_set                                          */
61 /*    _gx_context_brush_width_set                                         */
62 /*    _gx_canvas_circle_draw                                              */
63 /*    _gx_canvas_arc_draw                                                 */
64 /*                                                                        */
65 /*  CALLED BY                                                             */
66 /*                                                                        */
67 /*    Application Code                                                    */
68 /*    GUIX Internal Code                                                  */
69 /*                                                                        */
70 /*  RELEASE HISTORY                                                       */
71 /*                                                                        */
72 /*    DATE              NAME                      DESCRIPTION             */
73 /*                                                                        */
74 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
75 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
76 /*                                            resulting in version 6.1    */
77 /*  08-02-2021     Ting Zhu                 Modified comment(s),          */
78 /*                                            supported no background     */
79 /*                                            radial track mode,          */
80 /*                                            resulting in version 6.1.8  */
81 /*                                                                        */
82 /**************************************************************************/
_gx_radial_progress_bar_background_draw(GX_RADIAL_PROGRESS_BAR * progress_bar)83 VOID  _gx_radial_progress_bar_background_draw(GX_RADIAL_PROGRESS_BAR *progress_bar)
84 {
85 GX_RADIAL_PROGRESS_BAR_INFO *info;
86 GX_VALUE                     xcenter;
87 GX_VALUE                     ycenter;
88 GX_BRUSH                    *brush;
89 GX_RECTANGLE                *size;
90 
91 #if defined(GX_BRUSH_ALPHA_SUPPORT)
92 GX_UBYTE     brush_alpha;
93 GX_RECTANGLE dirty;
94 GX_PIXELMAP  map;
95 VOID        *canvas_memory;
96 INT          canvas_size;
97 GX_DISPLAY  *display;
98 GX_CANVAS   *canvas;
99 GX_VALUE     old_xpos = 0;
100 GX_VALUE     old_ypos = 0;
101 #endif
102 
103     _gx_context_brush_get(&brush);
104 
105 #if defined(GX_BRUSH_ALPHA_SUPPORT)
106     brush_alpha = brush -> gx_brush_alpha;
107     if (brush_alpha == 0)
108     {
109         return;
110     }
111 
112     if (brush_alpha != GX_ALPHA_VALUE_OPAQUE)
113     {
114         size = &progress_bar -> gx_widget_size;
115         map.gx_pixelmap_width = (GX_VALUE)(size -> gx_rectangle_right - size -> gx_rectangle_left + 1);
116         map.gx_pixelmap_height = (GX_VALUE)(size -> gx_rectangle_bottom - size -> gx_rectangle_top + 1);
117 
118         display = _gx_system_current_draw_context -> gx_draw_context_display;
119 
120         if ((progress_bar -> gx_radial_progress_bar_canvas.gx_canvas_id != GX_CANVAS_ID) &&
121             _gx_system_memory_allocator)
122         {
123 
124             /* Pixelmap width and height is GX_VALUE type, overflow cannot occur. */
125             canvas_size = display -> gx_display_driver_row_pitch_get((USHORT)map.gx_pixelmap_width);
126             canvas_size *= map.gx_pixelmap_height;
127 
128             canvas_memory = _gx_system_memory_allocator((ULONG)canvas_size);
129 
130             if (canvas_memory)
131             {
132                 _gx_canvas_create(&progress_bar -> gx_radial_progress_bar_canvas, "progress_bar_canvas",
133                                   display, GX_CANVAS_SIMPLE, (UINT)map.gx_pixelmap_width,
134                                   (UINT)map.gx_pixelmap_height, (GX_COLOR *)canvas_memory, (ULONG)canvas_size);
135             }
136         }
137 
138         if (progress_bar -> gx_radial_progress_bar_canvas.gx_canvas_id == GX_CANVAS_ID)
139         {
140             /* Remove resize notify temporary. */
141             progress_bar -> gx_widget_status &= ~GX_STATUS_RESIZE_NOTIFY;
142 
143             old_xpos = size -> gx_rectangle_left;
144             old_ypos = size -> gx_rectangle_top;
145 
146             if (old_xpos || old_ypos)
147             {
148                 _gx_widget_shift((GX_WIDGET *)progress_bar, (GX_VALUE)(-old_xpos), (GX_VALUE)(-old_ypos), GX_FALSE);
149             }
150 
151             canvas = _gx_system_current_draw_context -> gx_draw_context_canvas;
152             dirty = canvas -> gx_canvas_dirty_area;
153             _gx_utility_rectangle_shift(&dirty, (GX_VALUE)(-old_xpos), (GX_VALUE)(-old_ypos));
154             _gx_utility_rectangle_overlap_detect(&dirty, &progress_bar -> gx_widget_size, &dirty);
155 
156             _gx_canvas_drawing_initiate(&progress_bar -> gx_radial_progress_bar_canvas, GX_NULL, &dirty);
157 
158             if (progress_bar -> gx_widget_status & GX_STATUS_TRANSPARENT)
159             {
160                 xcenter = canvas -> gx_canvas_display_offset_x;
161                 ycenter = canvas -> gx_canvas_display_offset_y;
162                 _gx_canvas_offset_set(canvas, (GX_VALUE)(-old_xpos), (GX_VALUE)(-old_ypos));
163                 display -> gx_display_driver_canvas_copy(canvas, &progress_bar -> gx_radial_progress_bar_canvas);
164                 _gx_canvas_offset_set(canvas, xcenter, ycenter);
165             }
166 
167             _gx_context_brush_get(&brush);
168         }
169     }
170 
171 #endif
172 
173     /* Draw progress bar background.  */
174     _gx_widget_background_draw((GX_WIDGET *)progress_bar);
175 
176     /* Draw circular track.  */
177     info = &progress_bar -> gx_radial_progress_bar_info;
178 
179     size = &progress_bar -> gx_widget_size;
180 
181     xcenter = (GX_VALUE)(size -> gx_rectangle_right + size -> gx_rectangle_left);
182     xcenter >>= 1;
183 
184     ycenter = (GX_VALUE)(size -> gx_rectangle_bottom + size -> gx_rectangle_top);
185     ycenter >>= 1;
186 
187     brush -> gx_brush_style &= (ULONG)(~GX_BRUSH_SOLID_FILL);
188 
189     if (progress_bar -> gx_widget_style & GX_STYLE_RADIAL_PROGRESS_ALIAS)
190     {
191         brush -> gx_brush_style |= GX_BRUSH_ALIAS;
192     }
193 
194     if (progress_bar -> gx_widget_style & GX_STYLE_RADIAL_PROGRESS_ROUND)
195     {
196         brush -> gx_brush_style |= GX_BRUSH_ROUND;
197     }
198 
199     if (!(progress_bar -> gx_widget_style & GX_STYLE_RADIAL_PROGRESS_NO_BACKTRACK))
200     {
201         _gx_context_line_color_set(info -> gx_radial_progress_bar_info_normal_brush_color);
202         _gx_context_brush_width_set((UINT)(info -> gx_radial_progress_bar_info_normal_brush_width));
203 
204         _gx_canvas_circle_draw(xcenter, ycenter, (UINT)(info -> gx_radial_progress_bar_info_radius));
205     }
206 
207     if (info -> gx_radial_progress_bar_info_current_val != 0)
208     {
209         _gx_context_line_color_set(info -> gx_radial_progress_bar_info_selected_brush_color);
210         brush -> gx_brush_width = info -> gx_radial_progress_bar_info_selected_brush_width;
211 
212         if (info -> gx_radial_progress_bar_info_current_val > 0)
213         {
214             _gx_canvas_arc_draw(xcenter, ycenter,
215                                 (UINT)(info -> gx_radial_progress_bar_info_radius),
216                                 info -> gx_radial_progress_bar_info_anchor_val,
217                                 info -> gx_radial_progress_bar_info_current_val + info -> gx_radial_progress_bar_info_anchor_val);
218         }
219         else
220         {
221             _gx_canvas_arc_draw(xcenter, ycenter,
222                                 (UINT)(info -> gx_radial_progress_bar_info_radius),
223                                 info -> gx_radial_progress_bar_info_current_val + info -> gx_radial_progress_bar_info_anchor_val,
224                                 info -> gx_radial_progress_bar_info_anchor_val);
225         }
226     }
227 
228 #if defined(GX_BRUSH_ALPHA_SUPPORT)
229     if ((brush_alpha != GX_ALPHA_VALUE_OPAQUE) &&
230         (progress_bar -> gx_radial_progress_bar_canvas.gx_canvas_id == GX_CANVAS_ID))
231     {
232         if (old_xpos || old_ypos)
233         {
234             _gx_widget_shift((GX_WIDGET *)progress_bar, old_xpos, old_ypos, GX_FALSE);
235         }
236 
237         _gx_canvas_pixelmap_get(&map);
238         _gx_canvas_drawing_complete(&progress_bar -> gx_radial_progress_bar_canvas, GX_FALSE);
239         _gx_canvas_pixelmap_blend(old_xpos, old_ypos, &map, brush_alpha);
240 
241         /* Added resize notification back. */
242         progress_bar -> gx_widget_status |= GX_STATUS_RESIZE_NOTIFY;
243     }
244 #endif
245 }
246 
247