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