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 /** Accordion Menu Management (Menu) */
18 /** */
19 /**************************************************************************/
20
21 #define GX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "gx_api.h"
27 #include "gx_menu.h"
28 #include "gx_widget.h"
29 #include "gx_system.h"
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _gx_accordion_menu_one_level_position PORTABLE C */
36 /* 6.1 */
37 /* AUTHOR */
38 /* */
39 /* Kenneth Maxwell, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function positions first level items for an accordion menu. */
44 /* */
45 /* INPUT */
46 /* */
47 /* accordion Accordion menu control block */
48 /* */
49 /* OUTPUT */
50 /* */
51 /* status Completion status */
52 /* */
53 /* CALLS */
54 /* */
55 /* _gx_widget_border_width_get Get widget border width */
56 /* _gx_widget_client_get Get widget client rectangle */
57 /* _gx_widget_height_get Get widget height */
58 /* _gx_widget_shift Shift a widget */
59 /* _gx_widget_resize Resize a widget */
60 /* */
61 /* CALLED BY */
62 /* */
63 /* _gx_accordion_menu_position */
64 /* */
65 /* RELEASE HISTORY */
66 /* */
67 /* DATE NAME DESCRIPTION */
68 /* */
69 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
70 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
71 /* resulting in version 6.1 */
72 /* */
73 /**************************************************************************/
_gx_accordion_menu_one_level_position(GX_ACCORDION_MENU * accordion)74 static UINT _gx_accordion_menu_one_level_position(GX_ACCORDION_MENU *accordion)
75 {
76 GX_WIDGET *child = accordion -> gx_widget_first_child;
77 GX_RECTANGLE size;
78 GX_RECTANGLE client;
79 GX_VALUE height;
80 GX_VALUE bottom;
81 GX_VALUE border_width;
82 GX_MENU_LIST *list;
83
84 _gx_widget_border_width_get((GX_WIDGET *)accordion, &border_width);
85 _gx_widget_client_get((GX_WIDGET *)accordion, border_width, &client);
86
87 size.gx_rectangle_left = client.gx_rectangle_left;
88 size.gx_rectangle_right = client.gx_rectangle_right;
89 size.gx_rectangle_top = client.gx_rectangle_top;
90 size.gx_rectangle_bottom = (GX_VALUE)(size.gx_rectangle_top - 1);
91
92 bottom = size.gx_rectangle_bottom;
93 accordion -> gx_accordion_menu_expand_item = GX_NULL;
94
95 /* Reposition accordion menu items. */
96 while (child)
97 {
98 switch (child -> gx_widget_type)
99 {
100 case GX_TYPE_MENU:
101 list = &((GX_MENU *)child) -> gx_menu_list;
102
103 if (child -> gx_widget_style & GX_STYLE_MENU_EXPANDED)
104 {
105 if (!accordion -> gx_accordion_menu_expand_item && list -> gx_widget_first_child)
106 {
107 accordion -> gx_accordion_menu_expand_item = child;
108 }
109 else
110 {
111 child -> gx_widget_style &= (ULONG)(~GX_STYLE_MENU_EXPANDED);
112 _gx_widget_detach((GX_WIDGET *)list);
113
114 list -> gx_widget_size.gx_rectangle_bottom = (GX_VALUE)(list -> gx_widget_size.gx_rectangle_top - 1);
115 }
116 }
117
118 _gx_widget_height_get(child, &height);
119
120 size.gx_rectangle_top = (GX_VALUE)(bottom + 1);
121 size.gx_rectangle_bottom = (GX_VALUE)(size.gx_rectangle_top + height - 1);
122
123 _gx_widget_resize(child, &size);
124
125 if (list -> gx_widget_parent)
126 {
127 _gx_widget_shift((GX_WIDGET *)list,
128 (GX_VALUE)(size.gx_rectangle_left - list -> gx_widget_size.gx_rectangle_left),
129 (GX_VALUE)(size.gx_rectangle_bottom + 1 - list -> gx_widget_size.gx_rectangle_top), GX_FALSE);
130
131 bottom = list -> gx_widget_size.gx_rectangle_bottom;
132 }
133 else
134 {
135 bottom = size.gx_rectangle_bottom;
136 }
137 break;
138
139 case GX_TYPE_MENU_LIST:
140 break;
141
142 default:
143 _gx_widget_height_get(child, &height);
144 size.gx_rectangle_top = (GX_VALUE)(bottom + 1);
145 size.gx_rectangle_bottom = (GX_VALUE)(size.gx_rectangle_top + height - 1);
146
147 _gx_widget_resize(child, &size);
148 bottom = size.gx_rectangle_bottom;
149 break;
150 }
151
152 child -> gx_widget_status &= ~GX_STATUS_ACCEPTS_FOCUS;
153 child = child -> gx_widget_next;
154 }
155
156 size = accordion -> gx_widget_size;
157 size.gx_rectangle_bottom = (GX_VALUE)(bottom + border_width);
158
159 /* Resize accordion menu. */
160 _gx_widget_resize((GX_WIDGET *)accordion, &size);
161
162 /* Return completion status code. */
163 return GX_SUCCESS;
164 }
165
166 /**************************************************************************/
167 /* */
168 /* FUNCTION RELEASE */
169 /* */
170 /* _gx_accordion_menu_position PORTABLE C */
171 /* 6.1 */
172 /* AUTHOR */
173 /* */
174 /* Kenneth Maxwell, Microsoft Corporation */
175 /* */
176 /* DESCRIPTION */
177 /* */
178 /* This function positions an accordion menu and its items. */
179 /* */
180 /* INPUT */
181 /* */
182 /* accordion Accordion menu control block */
183 /* */
184 /* OUTPUT */
185 /* */
186 /* status Completion status */
187 /* */
188 /* CALLS */
189 /* */
190 /* _gx_menu_one_level_position Position a menu widget */
191 /* _gx_accordion_one_levelmenu_position Position an accordion menu */
192 /* */
193 /* CALLED BY */
194 /* */
195 /* Application Code */
196 /* */
197 /* RELEASE HISTORY */
198 /* */
199 /* DATE NAME DESCRIPTION */
200 /* */
201 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
202 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
203 /* resulting in version 6.1 */
204 /* */
205 /**************************************************************************/
_gx_accordion_menu_position(GX_ACCORDION_MENU * accordion)206 UINT _gx_accordion_menu_position(GX_ACCORDION_MENU *accordion)
207 {
208 GX_WIDGET *parent = (GX_WIDGET *)accordion;
209 GX_WIDGET *child;
210 GX_MENU_LIST *child_list;
211
212 child = accordion -> gx_widget_first_child;
213
214 /* Reposition items of menu list. */
215 while (child)
216 {
217 if (child -> gx_widget_type == GX_TYPE_MENU)
218 {
219 child_list = &((GX_MENU *)child) -> gx_menu_list;
220
221 if (child_list -> gx_widget_first_child)
222 {
223 child = child_list -> gx_widget_first_child;
224 continue;
225 }
226 else if (child_list -> gx_widget_parent)
227 {
228 _gx_widget_detach((GX_WIDGET *)child_list);
229 }
230 }
231 else if (child -> gx_widget_type == GX_TYPE_ACCORDION_MENU)
232 {
233 if (child -> gx_widget_first_child)
234 {
235 child = child -> gx_widget_first_child;
236 continue;
237 }
238 }
239
240 while ((child -> gx_widget_next == GX_NULL) && (child != parent))
241 {
242 child = child -> gx_widget_parent;
243
244 if (child -> gx_widget_type == GX_TYPE_MENU_LIST)
245 {
246 child_list = (GX_MENU_LIST *)child;
247 child = child_list -> gx_menu_list_owner;
248 }
249
250 if ((child -> gx_widget_type == GX_TYPE_MENU))
251 {
252 _gx_menu_one_level_position((GX_MENU *)child, 0);
253 }
254 else
255 {
256 _gx_accordion_menu_one_level_position((GX_ACCORDION_MENU *)child);
257 }
258 }
259
260 if (child == parent)
261 {
262 break;
263 }
264
265 child = child -> gx_widget_next;
266 }
267
268 /* Return completion status code. */
269 return(GX_SUCCESS);
270 }
271
272