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