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_window.h"
29 #include "gx_widget.h"
30 #include "gx_utility.h"
31 #include "gx_system.h"
32 #include "gx_context.h"
33 #include "gx_canvas.h"
34
35 /**************************************************************************/
36 /* */
37 /* FUNCTION RELEASE */
38 /* */
39 /* _gx_tree_view_root_draw_helper PORTABLE C */
40 /* 6.1 */
41 /* AUTHOR */
42 /* */
43 /* Kenneth Maxwell, Microsoft Corporation */
44 /* */
45 /* DESCRIPTION */
46 /* */
47 /* Internal helper function to draw the expand/collapse icons and root */
48 /* lines for one level menu items. */
49 /* */
50 /* INPUT */
51 /* */
52 /* tree Pointer the to tree view */
53 /* control block */
54 /* start Pointer to start widget */
55 /* owner Parent of the menu item */
56 /* */
57 /* OUTPUT */
58 /* */
59 /* status Compoletion status */
60 /* */
61 /* CALLS */
62 /* */
63 /* _gx_context_pixelmap_get Get pixelmap associate with */
64 /* the supplied id */
65 /* _gx_context_brush_get Get brush */
66 /* _gx_canvas_pixelmap_draw Draw a pixelmap to canvas */
67 /* _gx_canvas_line_draw Draw a line to canvas */
68 /* _gx_widget_first_client_child_get Get the first client child */
69 /* _gx_widget_next_client_child_get Get the next chilent child */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* _gx_tree_view_root_draw */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
80 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
81 /* resulting in version 6.1 */
82 /* */
83 /**************************************************************************/
_gx_tree_view_root_draw_helper(GX_TREE_VIEW * tree,GX_WIDGET * start,GX_WIDGET * owner)84 static VOID _gx_tree_view_root_draw_helper(GX_TREE_VIEW *tree, GX_WIDGET *start, GX_WIDGET *owner)
85 {
86 GX_PIXELMAP *map;
87 GX_PIXELMAP *collapse_map;
88 GX_PIXELMAP *expand_map;
89 GX_WIDGET *child;
90 GX_MENU_LIST *list;
91 GX_VALUE xpos;
92 GX_VALUE ypos;
93 GX_VALUE yend;
94 GX_VALUE map_width = 0;
95 GX_VALUE map_height = 0;
96 ULONG vertical_mask = 0x80000000;
97 GX_BRUSH *brush;
98 GX_WIDGET *pre = GX_NULL;
99
100 _gx_context_pixelmap_get(tree -> gx_tree_view_collapse_pixelmap_id, &collapse_map);
101 _gx_context_pixelmap_get(tree -> gx_tree_view_expand_pixelmap_id, &expand_map);
102
103 if (collapse_map)
104 {
105 map_width = collapse_map -> gx_pixelmap_width;
106 map_height = collapse_map -> gx_pixelmap_height;
107 }
108
109 child = _gx_widget_first_client_child_get(start);
110
111 while (child)
112 {
113 if (child -> gx_widget_type == GX_TYPE_MENU_LIST)
114 {
115 /* Not a valid item type. */
116 child = _gx_widget_next_client_child_get(child);
117 continue;
118 }
119
120 map = GX_NULL;
121 xpos = (GX_VALUE)(child -> gx_widget_size.gx_rectangle_left - (tree -> gx_tree_view_indentation >> 1));
122 ypos = (GX_VALUE)(child -> gx_widget_size.gx_rectangle_top + child -> gx_widget_size.gx_rectangle_bottom - 1);
123 ypos = (GX_VALUE)(ypos >> 1);
124
125 if (child -> gx_widget_type == GX_TYPE_MENU)
126 {
127 list = &((GX_MENU *)child) -> gx_menu_list;
128
129 if (list -> gx_widget_first_child)
130 {
131 if (child -> gx_widget_style & GX_STYLE_MENU_EXPANDED)
132 {
133 map = collapse_map;
134 }
135 else
136 {
137 map = expand_map;
138 }
139
140 if (map)
141 {
142 /* Calculate collapse/expand icon draw area. */
143 xpos = (GX_VALUE)(xpos - (map_width >> 1));
144 ypos = (GX_VALUE)(ypos - (map_height >> 1));
145
146 /* Draw collapse/expand icons. */
147 _gx_canvas_pixelmap_draw(xpos, ypos, map);
148 }
149 }
150 }
151
152 if (tree -> gx_widget_style & GX_STYLE_TREE_VIEW_SHOW_ROOT_LINES)
153 {
154 /* Draw root lines.*/
155 _gx_context_brush_get(&brush);
156 brush -> gx_brush_pattern_mask = 0x80000000;
157
158 if (map)
159 {
160 /* Get right center of the collapse/expand icon. */
161 xpos = (GX_VALUE)(xpos + map_width);
162 ypos = (GX_VALUE)(ypos + (map_height >> 1));
163 }
164 else
165 {
166 xpos = (GX_VALUE)(child -> gx_widget_size.gx_rectangle_left - (tree -> gx_tree_view_indentation >> 1) + 1);
167 ypos = (GX_VALUE)((child -> gx_widget_size.gx_rectangle_top + child -> gx_widget_size.gx_rectangle_bottom) >> 1);
168 }
169
170 /* Draw horizontal root line that connection collapse/expand icon with the menu item. */
171 _gx_canvas_line_draw(xpos, ypos, (GX_VALUE)(child -> gx_widget_size.gx_rectangle_left - 1), ypos);
172
173 if (pre || owner)
174 {
175 if (map)
176 {
177 /* Get top center of the collapse/expand icon. */
178 xpos = (GX_VALUE)(xpos - (map_width >> 1));
179 ypos = (GX_VALUE)(ypos - (map_height >> 1) - 1);
180 }
181 else
182 {
183 xpos = (GX_VALUE)(xpos - 1);
184 }
185
186 if (pre)
187 {
188 if ((pre -> gx_widget_type == GX_TYPE_MENU) &&
189 ((GX_MENU *)pre) -> gx_menu_list.gx_widget_first_child)
190 {
191 yend = (GX_VALUE)((pre -> gx_widget_size.gx_rectangle_top + pre -> gx_widget_size.gx_rectangle_bottom) >> 1);
192 yend = (GX_VALUE)(yend - (map_height >> 1) + map_height);
193 }
194 else
195 {
196 yend = (GX_VALUE)((pre -> gx_widget_size.gx_rectangle_top + pre -> gx_widget_size.gx_rectangle_bottom) >> 1);
197 yend = (GX_VALUE)(yend + 1);
198 }
199 }
200 else
201 {
202 yend = owner -> gx_widget_size.gx_rectangle_bottom;
203 }
204
205 brush -> gx_brush_pattern_mask = vertical_mask;
206
207 /* Draw vertical root line that connect to the previous or parent item. */
208 _gx_canvas_line_draw(xpos, yend, xpos, ypos);
209
210 vertical_mask = brush -> gx_brush_pattern_mask;
211 }
212 }
213
214 pre = child;
215
216 /* Pick next client child. */
217 child = _gx_widget_next_client_child_get(child);
218 }
219 }
220
221 /**************************************************************************/
222 /* */
223 /* FUNCTION RELEASE */
224 /* */
225 /* _gx_tree_view_root_draw PORTABLE C */
226 /* 6.1 */
227 /* AUTHOR */
228 /* */
229 /* Kenneth Maxwell, Microsoft Corporation */
230 /* */
231 /* DESCRIPTION */
232 /* */
233 /* Internal helper function to draw the expand/collapse icons and root */
234 /* lines. */
235 /* */
236 /* INPUT */
237 /* */
238 /* tree Pointer the to tree view */
239 /* control block */
240 /* */
241 /* OUTPUT */
242 /* */
243 /* status Compoletion status */
244 /* */
245 /* CALLS */
246 /* */
247 /* _gx_widget_first_client_child_get Get the first client child */
248 /* _gx_widget_next_client_child_get Get the next chilent child */
249 /* _gx_tree_view_root_draw_helper Draw tree view root */
250 /* */
251 /* CALLED BY */
252 /* */
253 /* _gx_tree_view_draw */
254 /* */
255 /* RELEASE HISTORY */
256 /* */
257 /* DATE NAME DESCRIPTION */
258 /* */
259 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
260 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
261 /* resulting in version 6.1 */
262 /* */
263 /**************************************************************************/
_gx_tree_view_root_draw(GX_TREE_VIEW * tree)264 static VOID _gx_tree_view_root_draw(GX_TREE_VIEW *tree)
265 {
266 GX_WIDGET *child;
267 GX_WIDGET *next;
268 GX_MENU_LIST *list;
269 GX_WIDGET *parent = (GX_WIDGET *)tree;
270 GX_WIDGET *owner;
271
272 child = _gx_widget_first_client_child_get(parent);
273
274 while (child)
275 {
276 if (child -> gx_widget_type == GX_TYPE_MENU)
277 {
278 list = &((GX_MENU *)child) -> gx_menu_list;
279
280 if ((list -> gx_widget_first_child) &&
281 (list -> gx_widget_status & GX_STATUS_VISIBLE))
282 {
283 child = list -> gx_widget_first_child;
284 continue;
285 }
286 }
287
288 /* Pick next client child. */
289 next = _gx_widget_next_client_child_get(child);
290
291 while ((next == GX_NULL) && (child != parent))
292 {
293 child = child -> gx_widget_parent;
294
295 if (child -> gx_widget_type == GX_TYPE_MENU_LIST)
296 {
297 owner = ((GX_MENU_LIST *)child) -> gx_menu_list_owner;
298 next = owner;
299 }
300 else
301 {
302 owner = GX_NULL;
303 next = child;
304 }
305
306 _gx_tree_view_root_draw_helper(tree, child, owner);
307
308 child = next;
309 next = _gx_widget_next_client_child_get(next);
310 }
311
312 if (child == parent)
313 {
314 break;
315 }
316
317 child = next;
318 }
319 }
320
321 /**************************************************************************/
322 /* */
323 /* FUNCTION RELEASE */
324 /* */
325 /* _gx_tree_view_draw PORTABLE C */
326 /* 6.1 */
327 /* AUTHOR */
328 /* */
329 /* Kenneth Maxwell, Microsoft Corporation */
330 /* */
331 /* DESCRIPTION */
332 /* */
333 /* This function draws the specified tree view, which is a special type*/
334 /* of widget. */
335 /* */
336 /* INPUT */
337 /* */
338 /* tree Pointer the to tree view */
339 /* control block */
340 /* */
341 /* OUTPUT */
342 /* */
343 /* None */
344 /* */
345 /* CALLS */
346 /* */
347 /* _gx_window_background_draw Draw window background */
348 /* _gx_context_brush_pattern_set Set brush pattern */
349 /* _gx_context_brush_width_set Set brush width */
350 /* _gx_context_line_color_set Set line color */
351 /* _gx_utility_rectangle_overlap_detect Detect overlap of supplied */
352 /* rectangles */
353 /* _gx_tree_view_root_draw Draw root lines and icons */
354 /* _gx_widget_children_draw Draw widget children */
355 /* */
356 /* CALLED BY */
357 /* */
358 /* Application Code */
359 /* GUIX Internal Code */
360 /* */
361 /* RELEASE HISTORY */
362 /* */
363 /* DATE NAME DESCRIPTION */
364 /* */
365 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
366 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
367 /* resulting in version 6.1 */
368 /* */
369 /**************************************************************************/
_gx_tree_view_draw(GX_TREE_VIEW * tree)370 VOID _gx_tree_view_draw(GX_TREE_VIEW *tree)
371 {
372 GX_DRAW_CONTEXT *context;
373 GX_RECTANGLE dirty_area;
374
375 /* Draw tree menu background. */
376 _gx_window_background_draw((GX_WINDOW *)tree);
377
378 _gx_context_brush_pattern_set(GX_TREE_VIEW_ROOT_LINE_PATTERN);
379
380 _gx_context_brush_width_set(1);
381 _gx_context_line_color_set(tree -> gx_tree_view_root_line_color);
382
383 /* pick up the current context */
384 context = _gx_system_current_draw_context;
385 dirty_area = context -> gx_draw_context_dirty;
386
387 _gx_utility_rectangle_overlap_detect(&tree -> gx_window_client,
388 &context -> gx_draw_context_dirty,
389 &context -> gx_draw_context_dirty);
390
391 /* Draw collapse/expand icons and root lines. */
392 _gx_tree_view_root_draw(tree);
393
394 context -> gx_draw_context_dirty = dirty_area;
395
396 _gx_context_brush_pattern_set(0);
397
398 /* Draw all the child widgets. */
399 _gx_widget_children_draw((GX_WIDGET *)tree);
400 }
401
402