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