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 /**   Widget Management (Widget)                                          */
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_utility.h"
29 #include "gx_widget.h"
30 #include "gx_window.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _gx_widget_front_move                               PORTABLE C      */
38 /*                                                           6.1          */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Kenneth Maxwell, Microsoft Corporation                              */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function moves the widget to the front.                        */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    widget                                Pointer to widget to move     */
50 /*    return_moved                          Pointer to destination for    */
51 /*                                            indication widget was moved */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    status                                Completion status             */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _gx_system_dirty_partial_add          Add dirty area                */
60 /*    _gx_utility_rectangle_combine         Combine rectangles            */
61 /*    _gx_utility_rectangle_define          Define rectangle              */
62 /*    _gx_utility_rectangle_overlap_detect  Check for overlap             */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    Application Code                                                    */
67 /*    GUIX Internal Code                                                  */
68 /*                                                                        */
69 /*  RELEASE HISTORY                                                       */
70 /*                                                                        */
71 /*    DATE              NAME                      DESCRIPTION             */
72 /*                                                                        */
73 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
74 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
75 /*                                            resulting in version 6.1    */
76 /*                                                                        */
77 /**************************************************************************/
_gx_widget_front_move(GX_WIDGET * widget,GX_BOOL * return_moved)78 UINT  _gx_widget_front_move(GX_WIDGET *widget, GX_BOOL *return_moved)
79 {
80 GX_WIDGET   *parent;
81 GX_WIDGET   *sibling;
82 GX_RECTANGLE dirty_area;
83 GX_RECTANGLE overlap;
84 
85     /* Pickup parent widget.  */
86     parent =  widget -> gx_widget_parent;
87 
88     /* Is parent valid?  */
89     if (!parent)
90     {
91 
92         /* Return error.  */
93         return(GX_PTR_ERROR);
94     }
95 
96     /* First check to see if the widget is already in front.  */
97     if (parent -> gx_widget_last_child == widget)
98     {
99 
100         /* Yes, widget is already in front, so nothing to do.  */
101 
102         /* Return no change.  */
103         return(GX_NO_CHANGE);
104     }
105 
106     /* Relink widget to the end
107         1) Determine what to dirty, all or partial
108         2) unlink and stitch linked list
109         3) relink to the end
110         4) call dirty so that I will get redraw
111      */
112     _gx_utility_rectangle_define(&dirty_area, GX_VALUE_MAX, GX_VALUE_MAX, -1, -1);
113 
114     /* Pickup sibling widget.  */
115     sibling =  widget -> gx_widget_next;
116 
117     /* Traverse the sibling list.  */
118     while (sibling)
119     {
120         /* Check for an overlap of siblings.  */
121         if (_gx_utility_rectangle_overlap_detect(&widget -> gx_widget_size, &sibling -> gx_widget_size, &overlap))
122         {
123             /* Yes, calculate the dirty area.  */
124             if (dirty_area.gx_rectangle_left > dirty_area.gx_rectangle_right)
125             {
126                 dirty_area = overlap;
127             }
128             else
129             {
130                 _gx_utility_rectangle_combine(&dirty_area, &overlap);
131             }
132         }
133 
134         /* Move to next sibling.  */
135         sibling =  sibling -> gx_widget_next;
136     }
137 
138 
139     if (dirty_area.gx_rectangle_left <= dirty_area.gx_rectangle_right)
140     {
141 
142         /* Add dirty area.  */
143         _gx_system_dirty_partial_add(widget, &dirty_area);
144     }
145 
146     /* Is widget the first child of it's parent?  */
147     if (parent -> gx_widget_first_child == widget)
148     {
149         /* Yes, the first child, easy remove the first child.  */
150         parent -> gx_widget_first_child =  widget -> gx_widget_next;
151         widget -> gx_widget_next -> gx_widget_previous =  NULL;
152     }
153     else
154     {
155         /* No, not the first child. Remove from the middle.  */
156         widget -> gx_widget_previous -> gx_widget_next =  widget -> gx_widget_next;
157         widget -> gx_widget_next -> gx_widget_previous =  widget -> gx_widget_previous;
158     }
159 
160     /* Link the widget to the end of the list.  */
161 
162     sibling  =  parent -> gx_widget_last_child;
163     sibling -> gx_widget_next =  widget;
164     widget  -> gx_widget_previous =  sibling;
165     widget  -> gx_widget_next =  NULL;
166     parent  -> gx_widget_last_child =  widget;
167 
168     if (widget -> gx_widget_type >= GX_TYPE_WINDOW)
169     {
170         /* if parent is root window, then viewports need to be updated */
171         _gx_window_view_update_detect((GX_WINDOW *)widget);
172 
173         /* if window accepts focus and parent has focus, focus should be moved */
174         if (parent -> gx_widget_status & GX_STATUS_HAS_FOCUS &&
175             (widget -> gx_widget_status & GX_STATUS_ACCEPTS_FOCUS) &&
176             !(widget -> gx_widget_status & GX_STATUS_HAS_FOCUS))
177         {
178             _gx_system_focus_claim(widget);
179         }
180     }
181 
182 
183     /* Indicate the widget was moved.  */
184 
185     if (return_moved)
186     {
187         *return_moved =  GX_TRUE;
188     }
189 
190     /* Return successful completion.  */
191     return(GX_SUCCESS);
192 }
193 
194