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 /**   Drop List Management (List)                                         */
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_display.h"
29 #include "gx_context.h"
30 #include "gx_widget.h"
31 #include "gx_window.h"
32 #include "gx_utility.h"
33 #include "gx_drop_list.h"
34 
35 /**************************************************************************/
36 /*                                                                        */
37 /*  FUNCTION                                               RELEASE        */
38 /*                                                                        */
39 /*    _gx_drop_list_selected_children_draw                PORTABLE C      */
40 /*                                                           6.3.0        */
41 /*  AUTHOR                                                                */
42 /*                                                                        */
43 /*    Ting Zhu, Microsoft Corporation                                     */
44 /*                                                                        */
45 /*  DESCRIPTION                                                           */
46 /*                                                                        */
47 /*    This function draws the children of the selected item to the drop   */
48 /*    list client area with the specified shift values.                   */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    drop_list                             Pointer to drop list widget   */
53 /*    widget                                Widget to be drawn            */
54 /*    xshift                                Shift value in x coordinate   */
55 /*    yshift                                Shift value in y coordinate   */
56 /*                                                                        */
57 /*  OUTPUT                                                                */
58 /*                                                                        */
59 /*    None                                                                */
60 /*                                                                        */
61 /*  CALLS                                                                 */
62 /*                                                                        */
63 /*    _gx_utility_rectangle_shift           Shift rectangle               */
64 /*                                                                        */
65 /*  CALLED BY                                                             */
66 /*                                                                        */
67 /*    _gx_drop_list_draw                                                  */
68 /*                                                                        */
69 /*  RELEASE HISTORY                                                       */
70 /*                                                                        */
71 /*    DATE              NAME                      DESCRIPTION             */
72 /*                                                                        */
73 /*  10-31-2023     Ting Zhu                 Initial Version 6.3.0         */
74 /*                                                                        */
75 /**************************************************************************/
_gx_drop_list_selected_children_draw(GX_DROP_LIST * drop_list,GX_WIDGET * widget,GX_VALUE xshift,GX_VALUE yshift)76 static VOID _gx_drop_list_selected_children_draw(GX_DROP_LIST *drop_list, GX_WIDGET *widget, GX_VALUE xshift, GX_VALUE yshift)
77 {
78 GX_WIDGET   *child;
79 GX_WIDGET   *child_child;
80 GX_RECTANGLE old_size;
81 GX_RECTANGLE old_clip;
82 ULONG        old_style;
83 
84     /* Save the first child.  */
85     child = widget -> gx_widget_first_child;
86 
87     /* Draw the children.  */
88     while (child)
89     {
90         /* Save the widget size.  */
91         old_size = child -> gx_widget_size;
92 
93         /* Save the widget clip size.  */
94         old_clip = child -> gx_widget_clip;
95 
96         /* Save the widget style.  */
97         old_style = child -> gx_widget_style;
98 
99         /* Update the widget style temporarily.  */
100         if (drop_list -> gx_widget_status & GX_STATUS_HAS_FOCUS)
101         {
102             child -> gx_widget_style |= ~GX_STYLE_DRAW_SELECTED;
103         }
104         else
105         {
106             child -> gx_widget_style &= ~GX_STYLE_DRAW_SELECTED;
107         }
108 
109         /* Shift the widget size and clip with the specified shift values temporarily.  */
110         _gx_utility_rectangle_shift(&child -> gx_widget_size, xshift, yshift);
111         _gx_utility_rectangle_shift(&child -> gx_widget_clip, xshift, yshift);
112 
113         child_child = child -> gx_widget_first_child;
114 
115         /* Set the first child to NULL temporarily.  */
116         child -> gx_widget_first_child = GX_NULL;
117 
118         /* Draw the widget.  */
119         child -> gx_widget_draw_function(child);
120 
121         if (child_child)
122         {
123             child -> gx_widget_first_child = child_child;
124 
125             _gx_drop_list_selected_children_draw(drop_list, child, xshift, yshift);
126         }
127 
128         /* Recover the widget properties.  */
129         child -> gx_widget_size = old_size;
130         child -> gx_widget_clip = old_clip;
131         child -> gx_widget_style = old_style;
132 
133         child = child -> gx_widget_next;
134     }
135 }
136 
137 /**************************************************************************/
138 /*                                                                        */
139 /*  FUNCTION                                               RELEASE        */
140 /*                                                                        */
141 /*    _gx_drop_list_draw                                  PORTABLE C      */
142 /*                                                           6.3.0        */
143 /*  AUTHOR                                                                */
144 /*                                                                        */
145 /*    Kenneth Maxwell, Microsoft Corporation                              */
146 /*                                                                        */
147 /*  DESCRIPTION                                                           */
148 /*                                                                        */
149 /*    This function draws the specified widget.                           */
150 /*                                                                        */
151 /*  INPUT                                                                 */
152 /*                                                                        */
153 /*    drop_list                             Pointer to drop list widget   */
154 /*                                                                        */
155 /*  OUTPUT                                                                */
156 /*                                                                        */
157 /*    None                                                                */
158 /*                                                                        */
159 /*  CALLS                                                                 */
160 /*                                                                        */
161 /*    _gx_drop_list_background_draw         Draw the widget background    */
162 /*    _gx_widget_children_draw              Draw children widgets         */
163 /*    _gx_vertical_list_selected_widget_get Get selected child item of    */
164 /*                                            popup list                  */
165 /*    _gx_widget_client_get                 Find the client area of a     */
166 /*                                            widget                      */
167 /*                                                                        */
168 /*  CALLED BY                                                             */
169 /*                                                                        */
170 /*    Application Code                                                    */
171 /*    GUIX Internal Code                                                  */
172 /*                                                                        */
173 /*  RELEASE HISTORY                                                       */
174 /*                                                                        */
175 /*    DATE              NAME                      DESCRIPTION             */
176 /*                                                                        */
177 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
178 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
179 /*                                            resulting in version 6.1    */
180 /*  10-31-2023     Ting Zhu                 Modified comment(s),          */
181 /*                                            improved drawing of the     */
182 /*                                            selected item,              */
183 /*                                            resulting in version 6.3.0  */
184 /*                                                                        */
185 /**************************************************************************/
_gx_drop_list_draw(GX_DROP_LIST * drop_list)186 VOID _gx_drop_list_draw(GX_DROP_LIST *drop_list)
187 {
188 GX_RECTANGLE      client;
189 GX_WIDGET        *selected;
190 GX_VALUE          xshift;
191 GX_VALUE          yshift;
192 INT               selected_index;
193 GX_VERTICAL_LIST *list = &drop_list -> gx_drop_list_popup.gx_popup_list_list;
194 GX_RECTANGLE      size;
195 GX_RECTANGLE      clip;
196 ULONG             style;
197 GX_WIDGET        *child = GX_NULL;
198 GX_BOOL           reuse_list_item = GX_FALSE;
199 
200     /* Draw the background.  */
201     _gx_drop_list_background_draw(drop_list);
202 
203     /* Pick the selected item.  */
204     _gx_vertical_list_selected_widget_get(list, &selected);
205 
206     if (!selected && list -> gx_vertical_list_callback)
207     {
208         /* If not be able to retrieve the selected widget, its possible that the selcted item
209            has been reused for displaying the other list items during the scrolling.
210            In this case, try to get the selected index first, then reuse the list child to draw the selected item. */
211 
212         /* Get the selected index.  */
213         _gx_vertical_list_selected_index_get(list, &selected_index);
214 
215         if((selected_index >= 0) && (selected_index < list -> gx_vertical_list_total_rows))
216         {
217             /* Make the first list child as the selected widget temporarily.  */
218             selected = _gx_widget_first_client_child_get((GX_WIDGET *)list);
219 
220             /* Call the list callback function to create the selected widget.  */
221             list -> gx_vertical_list_callback(list, selected, selected_index);
222 
223             reuse_list_item = GX_TRUE;
224         }
225     }
226 
227     if (selected)
228     {
229 
230         _gx_widget_client_get((GX_WIDGET *)drop_list, -1, &client);
231 
232         size = selected -> gx_widget_size;
233         clip = selected -> gx_widget_clip;
234 
235         if (selected -> gx_widget_first_child)
236         {
237             child = selected -> gx_widget_first_child;
238             selected -> gx_widget_first_child = GX_NULL;
239 
240             /* Calculate the distance from the selected widget to the client area.  */
241             xshift = (GX_VALUE)(client.gx_rectangle_left - size.gx_rectangle_left);
242             yshift = (GX_VALUE)((client.gx_rectangle_bottom + client.gx_rectangle_top - size.gx_rectangle_bottom - size.gx_rectangle_top) >> 1);
243         }
244 
245         selected -> gx_widget_size = client;
246         selected -> gx_widget_clip = client;
247 
248 
249         /* Save the widget style.  */
250         style = selected -> gx_widget_style;
251 
252         /* Update the widget style temporarily.  */
253         if (drop_list -> gx_widget_status & GX_STATUS_HAS_FOCUS)
254         {
255             selected -> gx_widget_style |= ~GX_STYLE_DRAW_SELECTED;
256         }
257         else
258         {
259             selected -> gx_widget_style &= ~GX_STYLE_DRAW_SELECTED;
260         }
261 
262         selected -> gx_widget_draw_function(selected);
263 
264         if (child)
265         {
266             selected -> gx_widget_first_child = child;
267 
268             /* Draw the selected widget into my client area: */
269             _gx_drop_list_selected_children_draw(drop_list, selected, xshift, yshift);
270         }
271 
272         selected -> gx_widget_size = size;
273         selected -> gx_widget_clip = clip;
274         selected -> gx_widget_style = style;
275     }
276 
277     if (reuse_list_item)
278     {
279         /* Call the list callback funtion to create the widget with its original index. */
280         list -> gx_vertical_list_callback(list, selected, list -> gx_vertical_list_top_index);
281     }
282 
283     /* Draw the children.  */
284     _gx_widget_children_draw((GX_WIDGET *)drop_list);
285 }
286 
287