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 /**   Tree View Management (View)                                         */
18 /**                                                                       */
19 /**************************************************************************/
20 
21 #define GX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "gx_api.h"
27 #include "gx_tree_view.h"
28 #include "gx_widget.h"
29 #include "gx_window.h"
30 #include "gx_system.h"
31 #include "gx_utility.h"
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _tree_view_selected_detect                          PORTABLE C      */
38 /*                                                           6.1          */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Kenneth Maxwell, Microsoft Corporation                              */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    Internal helper function to test if a menu contain selected item.   */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    tree                                  Pointer to the tree view      */
50 /*                                            control block               */
51 /*    test_menu                             Menu for test                 */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    status                                Completion status             */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _tree_view_selected_detect            Detect if a menu contain      */
60 /*                                             selected item              */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    _gx_tree_menu_pen_down_event_process                                */
65 /*                                                                        */
66 /*  RELEASE HISTORY                                                       */
67 /*                                                                        */
68 /*    DATE              NAME                      DESCRIPTION             */
69 /*                                                                        */
70 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
71 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
72 /*                                            resulting in version 6.1    */
73 /*                                                                        */
74 /**************************************************************************/
_tree_view_selected_detect(GX_TREE_VIEW * tree,GX_MENU * test_menu)75 static GX_BOOL _tree_view_selected_detect(GX_TREE_VIEW *tree, GX_MENU *test_menu)
76 {
77 GX_MENU_LIST *list = &test_menu -> gx_menu_list;
78 GX_WIDGET    *child;
79 GX_BOOL       found = GX_FALSE;
80 
81     if (!tree -> gx_tree_view_selected)
82     {
83         return found;
84     }
85     child = list -> gx_widget_first_child;
86 
87     while (child)
88     {
89         if (child == tree -> gx_tree_view_selected)
90         {
91             found = GX_TRUE;
92             break;
93         }
94 
95         if (child -> gx_widget_type == GX_TYPE_MENU)
96         {
97             found = _tree_view_selected_detect(tree, (GX_MENU *)child);
98 
99             if (found)
100             {
101                 break;
102             }
103         }
104         child = child -> gx_widget_next;
105     }
106 
107     return found;
108 }
109 
110 /**************************************************************************/
111 /*                                                                        */
112 /*  FUNCTION                                               RELEASE        */
113 /*                                                                        */
114 /*    _gx_tree_view_item_find                             PORTABLE C      */
115 /*                                                           6.1          */
116 /*  AUTHOR                                                                */
117 /*                                                                        */
118 /*    Kenneth Maxwell, Microsoft Corporation                              */
119 /*                                                                        */
120 /*  DESCRIPTION                                                           */
121 /*                                                                        */
122 /*    Internal helper function to find a tree view item that is           */
123 /*    intersecting the specified horizontal line.                         */
124 /*                                                                        */
125 /*  INPUT                                                                 */
126 /*                                                                        */
127 /*    start                                  Widget to start searching    */
128 /*    line_y                                 Y coordinate of the          */
129 /*                                             horizontal line            */
130 /*    returned_item                          Pointer to retrieved item    */
131 /*                                                                        */
132 /*  OUTPUT                                                                */
133 /*                                                                        */
134 /*    status                                Completion status             */
135 /*                                                                        */
136 /*  CALLS                                                                 */
137 /*                                                                        */
138 /*    _gx_widget_first_client_child_get     Get the first client child    */
139 /*    _gx_widget_next_client_child_get      Get the next client child     */
140 /*    _gx_tree_view_item_find               Find tree view item with test */
141 /*                                            point                       */
142 /*                                                                        */
143 /*  CALLED BY                                                             */
144 /*                                                                        */
145 /*    _gx_tree_menu_pen_down_event_process                                */
146 /*                                                                        */
147 /*  RELEASE HISTORY                                                       */
148 /*                                                                        */
149 /*    DATE              NAME                      DESCRIPTION             */
150 /*                                                                        */
151 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
152 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
153 /*                                            resulting in version 6.1    */
154 /*                                                                        */
155 /**************************************************************************/
_gx_tree_view_item_find(GX_WIDGET * start,GX_VALUE line_y,GX_WIDGET ** returned_item)156 static UINT _gx_tree_view_item_find(GX_WIDGET *start, GX_VALUE line_y, GX_WIDGET **returned_item)
157 {
158 UINT          status = GX_SUCCESS;
159 GX_WIDGET    *child;
160 GX_WIDGET    *next;
161 GX_WIDGET    *found = NULL;
162 GX_MENU_LIST *list;
163 GX_BOOL       search_child;
164 
165     child = _gx_widget_first_client_child_get((GX_WIDGET *)start);
166 
167     while (child && child -> gx_widget_type == GX_TYPE_MENU_LIST)
168     {
169         child = _gx_widget_next_client_child_get(child);
170     }
171 
172     while (child)
173     {
174         /* Pick up next client child. */
175         next = _gx_widget_next_client_child_get(child);
176 
177         while (next && next -> gx_widget_type == GX_TYPE_MENU_LIST)
178         {
179             next = _gx_widget_next_client_child_get(next);
180         }
181 
182         /* Check if the widget if intersecting the specified horizontal line. */
183         if ((line_y >= child -> gx_widget_size.gx_rectangle_top) &&
184             (line_y <= child -> gx_widget_size.gx_rectangle_bottom))
185         {
186             /* Line y is in current item. */
187             found = child;
188             break;
189         }
190 
191         search_child = GX_FALSE;
192 
193         if (next)
194         {
195             if (line_y < next -> gx_widget_size.gx_rectangle_top)
196             {
197                 search_child = GX_TRUE;
198             }
199             else if (line_y <= next -> gx_widget_size.gx_rectangle_bottom)
200             {
201                 /* Line y is inside next item. */
202                 found = next;
203                 break;
204             }
205         }
206         else
207         {
208             search_child = GX_TRUE;
209         }
210 
211         if (search_child)
212         {
213             /* Line y is before next item. */
214             if (child -> gx_widget_type == GX_TYPE_MENU)
215             {
216                 list = &((GX_MENU *)child) -> gx_menu_list;
217 
218                 if (list -> gx_widget_status & GX_STATUS_VISIBLE)
219                 {
220                     child = list -> gx_widget_first_child;
221                     continue;
222                 }
223             }
224             else
225             {
226                 /* Not found. */
227                 break;
228             }
229         }
230 
231         child = next;
232     }
233 
234     *returned_item = found;
235 
236     return status;
237 }
238 
239 /**************************************************************************/
240 /*                                                                        */
241 /*  FUNCTION                                               RELEASE        */
242 /*                                                                        */
243 /*    _gx_tree_view_root_icon_rect_get                    PORTABLE C      */
244 /*                                                           6.1          */
245 /*  AUTHOR                                                                */
246 /*                                                                        */
247 /*    Kenneth Maxwell, Microsoft Corporation                              */
248 /*                                                                        */
249 /*  DESCRIPTION                                                           */
250 /*                                                                        */
251 /*    Internal helper function to get the root icon draw area of a tree   */
252 /*    view item.                                                          */
253 /*                                                                        */
254 /*  INPUT                                                                 */
255 /*                                                                        */
256 /*    tree                                  Pointer to the tree view      */
257 /*                                            control block               */
258 /*    item                                  Pointer to the tree view item */
259 /*                                            whose root icon draw area is*/
260 /*                                            retrieved                   */
261 /*    root_rect                             Retrieved root icon draw area */
262 /*                                                                        */
263 /*  OUTPUT                                                                */
264 /*                                                                        */
265 /*    status                                Completion status             */
266 /*                                                                        */
267 /*  CALLS                                                                 */
268 /*                                                                        */
269 /*    _gx_widget_pixelmap_get               Get pixelmap by supplied ID   */
270 /*                                                                        */
271 /*  CALLED BY                                                             */
272 /*                                                                        */
273 /*    _gx_tree_menu_pen_down_event_process                                */
274 /*                                                                        */
275 /*  RELEASE HISTORY                                                       */
276 /*                                                                        */
277 /*    DATE              NAME                      DESCRIPTION             */
278 /*                                                                        */
279 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
280 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
281 /*                                            resulting in version 6.1    */
282 /*                                                                        */
283 /**************************************************************************/
_gx_tree_view_root_icon_rect_get(GX_TREE_VIEW * tree,GX_WIDGET * item,GX_RECTANGLE * root_rect)284 static UINT _gx_tree_view_root_icon_rect_get(GX_TREE_VIEW *tree, GX_WIDGET *item, GX_RECTANGLE *root_rect)
285 {
286 GX_PIXELMAP *map;
287 
288     _gx_widget_pixelmap_get((GX_WIDGET *)tree, tree -> gx_tree_view_expand_pixelmap_id, &map);
289 
290     if (map)
291     {
292         root_rect -> gx_rectangle_left = (GX_VALUE)(item -> gx_widget_size.gx_rectangle_left - (tree -> gx_tree_view_indentation >> 1));
293         root_rect -> gx_rectangle_left = (GX_VALUE)(root_rect -> gx_rectangle_left - (map -> gx_pixelmap_width >> 1));
294         root_rect -> gx_rectangle_top = (GX_VALUE)(item -> gx_widget_size.gx_rectangle_top + item -> gx_widget_size.gx_rectangle_bottom - 1);
295         root_rect -> gx_rectangle_top = (GX_VALUE)(root_rect -> gx_rectangle_top >> 1);
296         root_rect -> gx_rectangle_top = (GX_VALUE)(root_rect -> gx_rectangle_top - (map -> gx_pixelmap_height >> 1));
297         root_rect -> gx_rectangle_right = (GX_VALUE)((root_rect -> gx_rectangle_left + map -> gx_pixelmap_width - 1));
298         root_rect -> gx_rectangle_bottom = (GX_VALUE)((root_rect -> gx_rectangle_top + map -> gx_pixelmap_height - 1));
299     }
300     else
301     {
302         memset(root_rect, 0, sizeof(GX_RECTANGLE));
303     }
304 
305     return GX_SUCCESS;
306 }
307 
308 /**************************************************************************/
309 /*                                                                        */
310 /*  FUNCTION                                               RELEASE        */
311 /*                                                                        */
312 /*    _gx_tree_menu_pen_down_event_process                PORTABLE C      */
313 /*                                                           6.1          */
314 /*  AUTHOR                                                                */
315 /*                                                                        */
316 /*    Kenneth Maxwell, Microsoft Corporation                              */
317 /*                                                                        */
318 /*  DESCRIPTION                                                           */
319 /*                                                                        */
320 /*    Internal helper function to process pen down event for the tree     */
321 /*    view.                                                               */
322 /*                                                                        */
323 /*  INPUT                                                                 */
324 /*                                                                        */
325 /*    tree                                  Pointer to tree view control  */
326 /*                                            block                       */
327 /*    event_ptr                             Pointer to event to process   */
328 /*                                                                        */
329 /*  OUTPUT                                                                */
330 /*                                                                        */
331 /*    status                                Completion status             */
332 /*                                                                        */
333 /*  CALLS                                                                 */
334 /*                                                                        */
335 /*    _gx_tree_view_item_find               Find tree view item with test */
336 /*                                            point                       */
337 /*    _gx_tree_view_root_icon_rect_get      Retrieve root icon rectangle  */
338 /*                                            of specified tree view item */
339 /*    _tree_view_selected_detect            Detect if a menu contain      */
340 /*                                            selected item               */
341 /*    _gx_tree_view_selected_set            Set new selected item         */
342 /*    _gx_tree_view_position                Position a tree view          */
343 /*    _gx_system_dirty_partial_add          Mark partial area of a widget */
344 /*                                            as dirty                    */
345 /*    _gx_system_top_widget_find            Find top widget that contain  */
346 /*                                            test point                  */
347 /*    _gx_utility_rectangle_point_detect    Test if the point is resides  */
348 /*                                            in the rectangle.           */
349 /*    _gx_window_event_process              Default window event process  */
350 /*                                                                        */
351 /*  CALLED BY                                                             */
352 /*                                                                        */
353 /*    _gx_tree_view_event_process                                         */
354 /*                                                                        */
355 /*  RELEASE HISTORY                                                       */
356 /*                                                                        */
357 /*    DATE              NAME                      DESCRIPTION             */
358 /*                                                                        */
359 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
360 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
361 /*                                            resulting in version 6.1    */
362 /*                                                                        */
363 /**************************************************************************/
_gx_tree_menu_pen_down_event_process(GX_TREE_VIEW * tree,GX_EVENT * event_ptr)364 static VOID _gx_tree_menu_pen_down_event_process(GX_TREE_VIEW *tree, GX_EVENT *event_ptr)
365 {
366 GX_WIDGET   *widget = (GX_WIDGET *)tree;
367 GX_WIDGET   *child = GX_NULL;
368 GX_RECTANGLE root_rect;
369 GX_POINT    *point;
370 GX_BOOL      check_selection = GX_FALSE;
371 
372     point = &event_ptr -> gx_event_payload.gx_event_pointdata;
373 
374     /* Find tree view item that is intersecting the horizontal line of the click point. */
375     _gx_tree_view_item_find((GX_WIDGET *)tree, point -> gx_point_y, &child);
376 
377     if (child && (child -> gx_widget_type == GX_TYPE_MENU) &&
378         ((GX_MENU *)child) -> gx_menu_list.gx_widget_first_child)
379     {
380         _gx_tree_view_root_icon_rect_get(tree, child, &root_rect);
381 
382         if (_gx_utility_rectangle_point_detect(&root_rect, *point))
383         {
384             if (child -> gx_widget_style & GX_STYLE_MENU_EXPANDED)
385             {
386                 child -> gx_widget_style &= (ULONG)(~GX_STYLE_MENU_EXPANDED);
387 
388                 if (_tree_view_selected_detect(tree, (GX_MENU *)child))
389                 {
390                     _gx_tree_view_selected_set(tree, child);
391                 }
392             }
393             else
394             {
395                 child -> gx_widget_style |= GX_STYLE_MENU_EXPANDED;
396             }
397 
398             _gx_tree_view_position(tree);
399 
400             root_rect = tree -> gx_window_client;
401             if (!(tree -> gx_widget_style & GX_STYLE_TREE_VIEW_SHOW_ROOT_LINES))
402             {
403                 root_rect.gx_rectangle_top = child -> gx_widget_size.gx_rectangle_top;
404             }
405 
406             _gx_system_dirty_partial_add((GX_WIDGET *)tree, &root_rect);
407         }
408         else
409         {
410             check_selection = GX_TRUE;
411         }
412     }
413     else
414     {
415         check_selection = GX_TRUE;
416         _gx_window_event_process((GX_WINDOW *)widget, event_ptr);
417     }
418 
419     if (check_selection)
420     {
421         child = _gx_system_top_widget_find((GX_WIDGET *)tree, *point, GX_STATUS_SELECTABLE);
422 
423         if (child)
424         {
425             if ((child -> gx_widget_type == GX_TYPE_MENU) ||
426                 (child -> gx_widget_parent -> gx_widget_type == GX_TYPE_MENU_LIST))
427             {
428                 _gx_tree_view_selected_set(tree, child);
429             }
430         }
431     }
432 }
433 
434 /**************************************************************************/
435 /*                                                                        */
436 /*  FUNCTION                                               RELEASE        */
437 /*                                                                        */
438 /*    _gx_tree_view_event_process                         PORTABLE C      */
439 /*                                                           6.1          */
440 /*  AUTHOR                                                                */
441 /*                                                                        */
442 /*    Kenneth Maxwell, Microsoft Corporation                              */
443 /*                                                                        */
444 /*  DESCRIPTION                                                           */
445 /*                                                                        */
446 /*    This function processes an event for the tree menu.                 */
447 /*                                                                        */
448 /*  INPUT                                                                 */
449 /*                                                                        */
450 /*    tree                                  Pointer to tree menu control  */
451 /*                                            block                       */
452 /*    event_ptr                             Pointer to event to process   */
453 /*                                                                        */
454 /*  OUTPUT                                                                */
455 /*                                                                        */
456 /*    status                                Completion status             */
457 /*                                                                        */
458 /*  CALLS                                                                 */
459 /*                                                                        */
460 /*    _gx_window_event_process              Default window event process  */
461 /*    _gx_tree_view_position                Position the children of the  */
462 /*                                            tree view                   */
463 /*    _gx_tree_menu_pen_down_event_process  Handle pen down event         */
464 /*    _gx_tree_view_scroll                  Scroll tree view client area  */
465 /*                                                                        */
466 /*  CALLED BY                                                             */
467 /*                                                                        */
468 /*    Application Code                                                    */
469 /*    GUIX Internal Code                                                  */
470 /*                                                                        */
471 /*  RELEASE HISTORY                                                       */
472 /*                                                                        */
473 /*    DATE              NAME                      DESCRIPTION             */
474 /*                                                                        */
475 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
476 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
477 /*                                            resulting in version 6.1    */
478 /*                                                                        */
479 /**************************************************************************/
_gx_tree_view_event_process(GX_TREE_VIEW * tree,GX_EVENT * event_ptr)480 UINT _gx_tree_view_event_process(GX_TREE_VIEW *tree, GX_EVENT *event_ptr)
481 {
482     switch (event_ptr -> gx_event_type)
483     {
484     case GX_EVENT_SHOW:
485         _gx_window_event_process((GX_WINDOW *)tree, event_ptr);
486         if (tree -> gx_widget_parent && (tree -> gx_widget_parent -> gx_widget_type != GX_TYPE_MENU_LIST))
487         {
488             _gx_tree_view_position(tree);
489         }
490         break;
491 
492     case GX_EVENT_PEN_DOWN:
493         _gx_tree_menu_pen_down_event_process(tree, event_ptr);
494         break;
495 
496     case GX_EVENT_VERTICAL_SCROLL:
497         _gx_tree_view_scroll(tree, 0, (GX_VALUE)(event_ptr -> gx_event_payload.gx_event_intdata[1] - event_ptr -> gx_event_payload.gx_event_intdata[0]));
498         break;
499 
500     case GX_EVENT_HORIZONTAL_SCROLL:
501         _gx_tree_view_scroll(tree, (GX_VALUE)(event_ptr -> gx_event_payload.gx_event_intdata[1] - event_ptr -> gx_event_payload.gx_event_intdata[0]), 0);
502         break;
503 
504     default:
505         return _gx_window_event_process((GX_WINDOW *)tree, event_ptr);
506     }
507 
508     return(GX_SUCCESS);
509 }
510 
511