GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/treeviews.c
Date: 2026-03-20 22:56:14
Exec Total Coverage
Lines: 284 324 87.7%
Functions: 26 29 89.7%
Branches: 73 127 57.5%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/ui/treeviews.h"
30 #include "gate/results.h"
31 #include "gate/debugging.h"
32
33 #if defined(GATE_UI_WINAPI)
34
35 #include "gate/ui/gateui_winapi.h"
36 #include "gate/platforms.h"
37 #ifdef _WIN32_IE
38 # undef _WIN32_IE
39 # if defined(GATE_COMPILER_TCC)
40 # define _WIN32_IE 0x0501
41 # else
42 # define _WIN32_IE 0x0400
43 # endif
44 #endif
45
46 #if defined(GATE_SYS_WIN16)
47
48 typedef struct tagNMHDR
49 {
50 HWND hwndFrom;
51 UINT_PTR idFrom;
52 UINT code;
53 } NMHDR;
54
55 #define TV_HITTESTINFO TVHITTESTINFO
56
57 struct _TREEITEM;
58 typedef struct _TREEITEM* HTREEITEM;
59
60 typedef struct tagTVHITTESTINFO {
61 POINT pt;
62 UINT flags;
63 HTREEITEM hItem;
64 } TVHITTESTINFO, * LPTVHITTESTINFO;
65
66 #define LPTV_ITEM LPTVITEM
67 #define TV_ITEM TVITEM
68
69 typedef struct tagTVITEM {
70 UINT mask;
71 HTREEITEM hItem;
72 UINT state;
73 UINT stateMask;
74 LPSTR pszText;
75 int cchTextMax;
76 int iImage;
77 int iSelectedImage;
78 int cChildren;
79 LPARAM lParam;
80 } TVITEM, * LPTVITEM;
81
82 typedef struct tagNMTREEVIEW {
83 NMHDR hdr;
84 UINT action;
85 TVITEM itemOld;
86 TVITEM itemNew;
87 POINT ptDrag;
88 } NMTREEVIEW, * LPNMTREEVIEW;
89
90 #define WM_NOTIFY 0x004E
91 #define TV_FIRST 0x1100 // TreeView messages
92 #define TVHT_NOWHERE 0x0001
93 #define TVHT_ONITEMICON 0x0002
94 #define TVHT_ONITEMLABEL 0x0004
95 #define TVHT_ONITEMSTATEICON 0x0040
96 #define TVHT_ONITEM (TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON)
97 #define TVHT_ONITEMINDENT 0x0008
98 #define TVHT_ONITEMBUTTON 0x0010
99 #define TVHT_ONITEMRIGHT 0x0020
100 #define TVHT_ONITEMSTATEICON 0x0040
101
102 #define TVHT_ABOVE 0x0100
103 #define TVHT_BELOW 0x0200
104 #define TVHT_TORIGHT 0x0400
105 #define TVHT_TOLEFT 0x0800
106
107 #define TVGN_ROOT 0x0000
108 #define TVGN_NEXT 0x0001
109 #define TVGN_PREVIOUS 0x0002
110 #define TVGN_PARENT 0x0003
111 #define TVGN_CHILD 0x0004
112 #define TVGN_FIRSTVISIBLE 0x0005
113 #define TVGN_NEXTVISIBLE 0x0006
114 #define TVGN_PREVIOUSVISIBLE 0x0007
115 #define TVGN_DROPHILITE 0x0008
116 #define TVGN_CARET 0x0009
117 #define TVGN_LASTVISIBLE 0x000A
118
119 #define TVS_HASBUTTONS 0x0001
120 #define TVS_HASLINES 0x0002
121 #define TVS_LINESATROOT 0x0004
122 #define TVS_EDITLABELS 0x0008
123 #define TVS_DISABLEDRAGDROP 0x0010
124 #define TVS_SHOWSELALWAYS 0x0020
125 #define TVS_RTLREADING 0x0040
126
127 #define TVS_NOTOOLTIPS 0x0080
128 #define TVS_CHECKBOXES 0x0100
129 #define TVS_TRACKSELECT 0x0200
130 #define TVS_SINGLEEXPAND 0x0400
131 #define TVS_INFOTIP 0x0800
132 #define TVS_FULLROWSELECT 0x1000
133 #define TVS_NOSCROLL 0x2000
134 #define TVS_NONEVENHEIGHT 0x4000
135 #define TVS_NOHSCROLL 0x8000
136
137 #define TVE_COLLAPSE 0x0001
138 #define TVE_EXPAND 0x0002
139 #define TVE_TOGGLE 0x0003
140 #define TVE_EXPANDPARTIAL 0x4000
141 #define TVE_COLLAPSERESET 0x8000
142
143 #define TVN_FIRST (0U-400U) // treeview
144 #define TVN_LAST (0U-499U)
145 #define TVN_SELCHANGED (TVN_FIRST-2)
146
147 #define WC_TREEVIEW "SysTreeView"
148
149
150
151 #define TVM_SELECTITEM (TV_FIRST + 11)
152 #define TreeView_Select(hwnd, hitem, code) \
153 (BOOL)SendMessage((hwnd), TVM_SELECTITEM, (WPARAM)(code), (LPARAM)(HTREEITEM)(hitem))
154
155
156 #define TreeView_SelectItem(hwnd, hitem) TreeView_Select(hwnd, hitem, TVGN_CARET)
157 #define TreeView_SelectDropTarget(hwnd, hitem) TreeView_Select(hwnd, hitem, TVGN_DROPHILITE)
158 #define TreeView_SelectSetFirstVisible(hwnd, hitem) TreeView_Select(hwnd, hitem, TVGN_FIRSTVISIBLE)
159
160 #define TVM_HITTEST (TV_FIRST + 17)
161 #define TreeView_HitTest(hwnd, lpht) \
162 (HTREEITEM)SendMessage((hwnd), TVM_HITTEST, 0, (LPARAM)(LPTV_HITTESTINFO)(lpht))
163
164 #define LPTV_HITTESTINFO LPTVHITTESTINFO
165
166 #define TVM_INSERTITEM (TV_FIRST + 0)
167 #define TreeView_InsertItem(hwnd, lpis) \
168 (HTREEITEM)SendMessage((hwnd), TVM_INSERTITEM, 0, (LPARAM)(LPTV_INSERTSTRUCT)(lpis))
169
170
171 #define TVM_DELETEITEM (TV_FIRST + 1)
172 #define TreeView_DeleteItem(hwnd, hitem) \
173 (BOOL)SendMessage((hwnd), TVM_DELETEITEM, 0, (LPARAM)(HTREEITEM)(hitem))
174
175
176 #define TreeView_DeleteAllItems(hwnd) \
177 (BOOL)SendMessage((hwnd), TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT)
178
179
180 #define TVM_EXPAND (TV_FIRST + 2)
181 #define TreeView_Expand(hwnd, hitem, code) \
182 (BOOL)SendMessage((hwnd), TVM_EXPAND, (WPARAM)(code), (LPARAM)(HTREEITEM)(hitem))
183
184 #define TVM_GETNEXTITEM (TV_FIRST + 10)
185 #define TreeView_GetNextItem(hwnd, hitem, code) \
186 (HTREEITEM)SendMessage((hwnd), TVM_GETNEXTITEM, (WPARAM)(code), (LPARAM)(HTREEITEM)(hitem))
187
188 #define TVM_GETITEM (TV_FIRST + 12)
189 #define TreeView_GetItem(hwnd, pitem) \
190 (BOOL)SendMessage((hwnd), TVM_GETITEM, 0, (LPARAM)(TV_ITEM *)(pitem))
191
192 #define TVM_SETITEM (TV_FIRST + 13)
193 #define TreeView_SetItem(hwnd, pitem) \
194 (BOOL)SendMessage((hwnd), TVM_SETITEM, 0, (LPARAM)(const TV_ITEM *)(pitem))
195
196 #define TVM_GETITEMRECT (TV_FIRST + 4)
197 #define TreeView_GetItemRect(hwnd, hitem, prc, code) \
198 (*(HTREEITEM *)(prc) = (hitem), (BOOL)SendMessage((hwnd), TVM_GETITEMRECT, (WPARAM)(code), (LPARAM)(RECT *)(prc)))
199
200 #define TreeView_GetChild(hwnd, hitem) TreeView_GetNextItem(hwnd, hitem, TVGN_CHILD)
201 #define TreeView_GetNextSibling(hwnd, hitem) TreeView_GetNextItem(hwnd, hitem, TVGN_NEXT)
202 #define TreeView_GetPrevSibling(hwnd, hitem) TreeView_GetNextItem(hwnd, hitem, TVGN_PREVIOUS)
203 #define TreeView_GetParent(hwnd, hitem) TreeView_GetNextItem(hwnd, hitem, TVGN_PARENT)
204 #define TreeView_GetFirstVisible(hwnd) TreeView_GetNextItem(hwnd, NULL, TVGN_FIRSTVISIBLE)
205 #define TreeView_GetNextVisible(hwnd, hitem) TreeView_GetNextItem(hwnd, hitem, TVGN_NEXTVISIBLE)
206 #define TreeView_GetPrevVisible(hwnd, hitem) TreeView_GetNextItem(hwnd, hitem, TVGN_PREVIOUSVISIBLE)
207 #define TreeView_GetSelection(hwnd) TreeView_GetNextItem(hwnd, NULL, TVGN_CARET)
208 #define TreeView_GetDropHilight(hwnd) TreeView_GetNextItem(hwnd, NULL, TVGN_DROPHILITE)
209 #define TreeView_GetRoot(hwnd) TreeView_GetNextItem(hwnd, NULL, TVGN_ROOT)
210 #define TreeView_GetLastVisible(hwnd) TreeView_GetNextItem(hwnd, NULL, TVGN_LASTVISIBLE)
211
212
213 typedef struct tagTVINSERTSTRUCT {
214 HTREEITEM hParent;
215 HTREEITEM hInsertAfter;
216 TV_ITEM item;
217 } TVINSERTSTRUCT, * LPTVINSERTSTRUCT;
218
219 #define TV_INSERTSTRUCT TVINSERTSTRUCT
220 #define LPTV_INSERTSTRUCT LPTVINSERTSTRUCT
221
222 #define TVIF_TEXT 0x0001
223 #define TVIF_IMAGE 0x0002
224 #define TVIF_PARAM 0x0004
225 #define TVIF_STATE 0x0008
226 #define TVIF_HANDLE 0x0010
227 #define TVIF_SELECTEDIMAGE 0x0020
228 #define TVIF_CHILDREN 0x0040
229 #define TVIF_INTEGRAL 0x0080
230
231 #define TVIS_SELECTED 0x0002
232 #define TVIS_CUT 0x0004
233 #define TVIS_DROPHILITED 0x0008
234 #define TVIS_BOLD 0x0010
235 #define TVIS_EXPANDED 0x0020
236 #define TVIS_EXPANDEDONCE 0x0040
237 #define TVIS_EXPANDPARTIAL 0x0080
238
239 #define TVIS_OVERLAYMASK 0x0F00
240 #define TVIS_STATEIMAGEMASK 0xF000
241 #define TVIS_USERMASK 0xF000
242
243 #define TVI_ROOT ((HTREEITEM)(ULONG_PTR)-0x10000)
244 #define TVI_FIRST ((HTREEITEM)(ULONG_PTR)-0x0FFFF)
245 #define TVI_LAST ((HTREEITEM)(ULONG_PTR)-0x0FFFE)
246 #define TVI_SORT ((HTREEITEM)(ULONG_PTR)-0x0FFFD)
247
248
249 #else /* GATE_SYS_WIN16 */
250 #include <commctrl.h>
251 #endif
252
253
254
255 static COLORREF gate_ui_treeview_get_bk_color(gate_ui_ctrl_t* ctrl)
256 {
257 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(ctrl);
258 gate_color_t color;
259 gate_ui_host_default_color(host, GATE_UI_COLOR_CONTENTBACKGROUND, &color);
260 return RGB(color.r, color.g, color.b);
261 }
262
263 static COLORREF gate_ui_treeview_get_text_color(gate_ui_ctrl_t* ctrl)
264 {
265 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(ctrl);
266 gate_color_t color;
267 gate_ui_host_default_color(host, GATE_UI_COLOR_CONTENTTEXT, &color);
268 return RGB(color.r, color.g, color.b);
269 }
270
271
272 static void gate_ui_treeview_update_colors(gate_ui_ctrl_t* ctrl)
273 {
274 #if !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WIN16)
275 HWND hwnd = GATE_UI_WINAPI_GET_HWND(ctrl);
276 COLORREF colref_bk = gate_ui_treeview_get_bk_color(ctrl);
277 COLORREF colref_text = gate_ui_treeview_get_text_color(ctrl);
278
279 if ((TreeView_GetBkColor(hwnd) != colref_bk) || (TreeView_GetTextColor(hwnd) != colref_text))
280 {
281 TreeView_SetBkColor(hwnd, colref_bk);
282 TreeView_SetTextColor(hwnd, colref_text);
283 }
284 #endif /* !GATE_SYS_WINCE */
285 }
286
287 static gate_bool_t gate_ui_treeview_events(void* hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult)
288 {
289 HWND hwndCtrl;
290 gate_ui_treeview_t* trvw;
291
292 if ((ctrl) && (hwnd))
293 {
294 trvw = (gate_ui_treeview_t*)ctrl;
295 hwndCtrl = GATE_UI_WINAPI_GET_HWND(ctrl);
296
297 if (hwndCtrl)
298 {
299 switch (msg)
300 {
301 case WM_ERASEBKGND:
302 {
303 HDC hdc = (HDC)wParam;
304 RECT rect;
305 BOOL succeeded = TRUE;
306 gate_ui_treeview_update_colors(ctrl);
307 #if !defined(GATE_SYS_WIN16)
308 succeeded =
309 #endif
310 GetClientRect(hwndCtrl, &rect);
311 if (succeeded)
312 {
313 HBRUSH hbrush = CreateSolidBrush(gate_ui_treeview_get_bk_color(ctrl));
314 if (hbrush)
315 {
316 FillRect(hdc, &rect, hbrush);
317 DeleteObject((HGDIOBJ)hbrush);
318 }
319 }
320 *lresult = 1;
321 return true;
322 }
323 case WM_LBUTTONDBLCLK:
324 {
325 HTREEITEM hItem;
326 TV_HITTESTINFO hti;
327 hti.flags = TVHT_ONITEM;
328 hti.hItem = NULL;
329 hti.pt.x = (LONG)LOWORD(lParam);
330 hti.pt.y = (LONG)HIWORD(lParam);
331 hItem = TreeView_HitTest(hwndCtrl, &hti);
332 if (hItem != NULL)
333 {
334 if (trvw->on_dblclick != NULL)
335 {
336 trvw->on_dblclick(&trvw->ctrl, (gate_ui_treeview_item_t)hItem);
337 }
338 }
339 *lresult = 0;
340 return true;
341 }
342 case WM_RBUTTONDOWN:
343 {
344 HTREEITEM hItem;
345 TV_HITTESTINFO hti;
346 hti.flags = TVHT_ONITEM;
347 hti.hItem = NULL;
348 hti.pt.x = (LONG)LOWORD(lParam);
349 hti.pt.y = (LONG)HIWORD(lParam);
350 hItem = TreeView_HitTest(hwndCtrl, &hti);
351 if (hItem != NULL)
352 {
353 if (trvw->on_contextmenu != NULL)
354 {
355 TreeView_SelectDropTarget(hwndCtrl, hItem);
356 trvw->on_contextmenu(&trvw->ctrl, (gate_ui_treeview_item_t)hItem);
357 TreeView_SelectDropTarget(hwndCtrl, NULL);
358 }
359 }
360 *lresult = 0;
361 return true;
362 }
363 case WM_NOTIFY:
364 {
365 NMHDR* nmhdr = (NMHDR*)lParam;
366 if (nmhdr->hwndFrom == hwndCtrl)
367 {
368 switch (nmhdr->code)
369 {
370 case TVN_SELCHANGED:
371 {
372 NMTREEVIEW* nmtv = (NMTREEVIEW*)nmhdr;
373 trvw->on_select(&trvw->ctrl, (gate_ui_treeview_item_t)nmtv->itemNew.hItem);
374 *lresult = 0;
375 return true;
376 }
377 }
378 }
379 break;
380 }
381 default:
382 {
383 break;
384 }
385 }
386 }
387 }
388 return false;
389 }
390
391 gate_result_t gate_ui_treeview_create(
392 gate_ui_treeview_t* trvw, gate_ui_ctrl_t* parent,
393 gate_ui_position_t const* position,
394 gate_uint32_t flags,
395 void* userparam
396 )
397 {
398 gate_result_t ret;
399
400 do
401 {
402 gate_uint32_t styles = WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS;
403 gate_uint32_t exstyles = 0;
404 HWND hwndParent;
405 gate_ui_host_t* host = gate_ui_ctrl_get_host(parent);
406
407 if (host == NULL)
408 {
409 ret = GATE_RESULT_INVALIDSTATE;
410 break;
411 }
412 hwndParent = GATE_UI_WINAPI_GET_HWND(parent);
413 if (hwndParent == NULL)
414 {
415 ret = GATE_RESULT_INVALIDSTATE;
416 break;
417 }
418
419 gate_mem_clear(trvw, sizeof(gate_ui_treeview_t));
420
421 #if !defined(GATE_SYS_WIN16)
422 exstyles |= WS_EX_CLIENTEDGE;
423 #endif
424
425 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
426 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
427
428 ret = gate_ui_winapi_create(&trvw->ctrl, host, hwndParent, WC_TREEVIEW, position, styles, exstyles, NULL, userparam, true);
429 if (GATE_SUCCEEDED(ret))
430 {
431 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
432
433 #if !defined(GATE_SYS_WIN16)
434 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_TREEVIEW_ICONS))
435 {
436 ret = gate_ui_iconlist_create(&trvw->icons, host, 16, 16);
437 if (GATE_FAILED(ret))
438 {
439 gate_ui_winapi_destroy(&trvw->ctrl);
440 break;
441 }
442 TreeView_SetImageList(hwnd, (HIMAGELIST)trvw->icons.resources[0], TVSIL_NORMAL);
443 }
444 #endif
445 gate_ui_winapi_register_event(host, hwndParent, WM_NOTIFY, &gate_ui_treeview_events, &trvw->ctrl);
446 gate_ui_winapi_register_event(host, hwnd, WM_RBUTTONDOWN, &gate_ui_treeview_events, &trvw->ctrl);
447 gate_ui_winapi_register_event(host, hwnd, WM_LBUTTONDBLCLK, &gate_ui_treeview_events, &trvw->ctrl);
448 gate_ui_winapi_register_event(host, hwnd, WM_ERASEBKGND, &gate_ui_treeview_events, &trvw->ctrl);
449
450 gate_ui_treeview_update_colors(&trvw->ctrl);
451 gate_ui_winapi_refresh(&trvw->ctrl);
452 }
453 } while (0);
454
455 return ret;
456 }
457
458 gate_result_t gate_ui_treeview_add_icon(gate_ui_treeview_t* trvw, gate_ui_icon_t const* icon, gate_intptr_t* icon_key)
459 {
460 return gate_ui_iconlist_add_icon(&trvw->icons, icon, icon_key);
461 }
462
463 gate_result_t gate_ui_treeview_add_icon_image(gate_ui_treeview_t* trvw, gate_rasterimage_t const* image, gate_intptr_t* icon_key)
464 {
465 return gate_ui_iconlist_add_image(&trvw->icons, image, icon_key);
466 }
467
468 gate_result_t gate_ui_treeview_add(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t const* parent, gate_string_t const* text,
469 gate_intptr_t iconkey, void* itemparam, gate_ui_treeview_item_t* newitem)
470 {
471 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
472 TVINSERTSTRUCT insert;
473 HTREEITEM newtreeitem;
474 TCHAR txtbuffer[4096];
475 gate_size_t txtbufferused = gate_win32_utf8_2_winstr(text->str, text->length, txtbuffer, sizeof(txtbuffer) / sizeof(txtbuffer[0]));
476 gate_mem_clear(&insert, sizeof(insert));
477 insert.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_STATE;
478 insert.item.pszText = &txtbuffer[0];
479 insert.item.cchTextMax = (int)txtbufferused;
480 insert.item.stateMask = TVIS_SELECTED;
481 insert.item.lParam = (LPARAM)(gate_intptr_t)itemparam;
482 if (parent == NULL)
483 {
484 insert.hParent = NULL;
485 insert.hInsertAfter = TVI_ROOT;
486 }
487 else
488 {
489 insert.hParent = (HTREEITEM)*parent;
490 insert.hInsertAfter = TVI_LAST;
491 }
492 if (trvw->icons.resources[0] != NULL)
493 {
494 if (iconkey != GATE_UI_TREEVIEW_INVALID_ICON)
495 {
496 insert.item.iImage = (int)iconkey;
497 insert.item.iSelectedImage = (int)iconkey;
498 insert.item.mask |= (TVIF_IMAGE | TVIF_SELECTEDIMAGE);
499 }
500 }
501
502 newtreeitem = TreeView_InsertItem(hwnd, &insert);
503 if (newtreeitem)
504 {
505 *newitem = (gate_ui_treeview_item_t)newtreeitem;
506 return GATE_RESULT_OK;
507 }
508 else
509 {
510 return GATE_RESULT_FAILED;
511 }
512 }
513
514 gate_result_t gate_ui_treeview_remove(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
515 {
516 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
517 if (TreeView_DeleteItem(hwnd, (HTREEITEM)item))
518 {
519 return GATE_RESULT_OK;
520 }
521 else
522 {
523 return GATE_RESULT_FAILED;
524 }
525 }
526
527 gate_result_t gate_ui_treeview_clear(gate_ui_treeview_t* trvw)
528 {
529 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
530 if (TreeView_DeleteAllItems(hwnd))
531 {
532 return GATE_RESULT_OK;
533 }
534 else
535 {
536 return GATE_RESULT_FAILED;
537 }
538 }
539
540 void* gate_ui_treeview_get_itemparam(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
541 {
542 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
543 TVITEM tvitem;
544 gate_mem_clear(&tvitem, sizeof(tvitem));
545 tvitem.hItem = (HTREEITEM)item;
546 tvitem.mask = TVIF_PARAM;
547 if (TreeView_GetItem(hwnd, &tvitem))
548 {
549 return (void*)(gate_intptr_t)tvitem.lParam;
550 }
551 return NULL;
552 }
553
554
555 gate_result_t gate_ui_treeview_get_parent(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_ui_treeview_item_t* parent)
556 {
557 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
558 HTREEITEM parentItem = TreeView_GetParent(hwnd, (HTREEITEM)item);
559 if (parentItem == NULL)
560 {
561 return GATE_RESULT_NOTAVAILABLE;
562 }
563 else
564 {
565 *parent = (gate_ui_treeview_item_t)parentItem;
566 return GATE_RESULT_OK;
567 }
568 }
569 gate_result_t gate_ui_treeview_get_children(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_array_t* children)
570 {
571 gate_result_t ret;
572 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
573 HTREEITEM child = TreeView_GetChild(hwnd, (HTREEITEM)item);
574 TVITEM itemdata;
575 gate_arraylist_t itemlist;
576 gate_size_t prealloc = 0;
577 gate_ui_treeview_item_t nextitem;
578 if (child != NULL)
579 {
580 gate_mem_clear(&itemdata, sizeof(itemdata));
581 itemdata.hItem = (HTREEITEM)item;
582 itemdata.mask = TVIF_CHILDREN;
583 if (TreeView_GetItem(hwnd, &itemdata))
584 {
585 prealloc = itemdata.cChildren;
586 }
587 }
588 itemlist = gate_arraylist_create(sizeof(gate_ui_treeview_item_t), NULL, prealloc, NULL, NULL);
589 if (!itemlist)
590 {
591 ret = GATE_RESULT_OUTOFMEMORY;
592 }
593 else
594 {
595 ret = GATE_RESULT_OK;
596 while (child != NULL)
597 {
598 nextitem = (gate_ui_treeview_item_t)child;
599 if (NULL == gate_arraylist_add(itemlist, &nextitem))
600 {
601 ret = GATE_RESULT_OUTOFMEMORY;
602 break;
603 }
604 child = TreeView_GetNextItem(hwnd, child, TVGN_NEXT);
605 }
606 if (GATE_SUCCEEDED(ret))
607 {
608 if (NULL == gate_array_create(children, itemlist))
609 {
610 ret = GATE_RESULT_FAILED;
611 }
612 }
613 gate_arraylist_release(itemlist);
614 }
615 return ret;
616 }
617 gate_result_t gate_ui_treeview_get_text(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_string_t* text)
618 {
619 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
620 TCHAR buffer[4096];
621 TVITEM tvitem;
622 gate_mem_clear(&tvitem, sizeof(tvitem));
623 tvitem.hItem = (HTREEITEM)item;
624 tvitem.mask = TVIF_TEXT;
625 tvitem.pszText = &buffer[0];
626 tvitem.cchTextMax = sizeof(buffer) / sizeof(buffer[0]);
627 if (TreeView_GetItem(hwnd, &tvitem))
628 {
629 if (NULL != gate_win32_winstr_2_utf8_string(buffer, tvitem.cchTextMax, text))
630 {
631 return GATE_RESULT_OK;
632 }
633 }
634 return GATE_RESULT_FAILED;
635 }
636 gate_result_t gate_ui_treeview_set_text(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_string_t const* text)
637 {
638 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
639 TCHAR buffer[4096];
640 TVITEM tvitem;
641 gate_mem_clear(&tvitem, sizeof(tvitem));
642 tvitem.hItem = (HTREEITEM)item;
643 tvitem.mask = TVIF_TEXT;
644 tvitem.pszText = &buffer[0];
645 tvitem.cchTextMax = (int)gate_win32_utf8_2_winstr(text->str, text->length, buffer, sizeof(buffer) / sizeof(buffer[0]));
646 if (TreeView_SetItem(hwnd, &tvitem))
647 {
648 return GATE_RESULT_OK;
649 }
650 return GATE_RESULT_FAILED;
651 }
652
653 gate_bool_t gate_ui_treeview_is_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
654 {
655 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
656 TVITEM tvitem;
657 gate_mem_clear(&tvitem, sizeof(tvitem));
658 tvitem.hItem = (HTREEITEM)item;
659 tvitem.mask = TVIF_STATE;
660 tvitem.stateMask = TVIS_EXPANDED;
661 tvitem.state = 0;
662 if (TreeView_GetItem(hwnd, &tvitem))
663 {
664 return (tvitem.state & TVIS_EXPANDED) == TVIS_EXPANDED;
665 }
666 return false;
667 }
668 gate_result_t gate_ui_treeview_set_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_bool_t expanded)
669 {
670 if (gate_ui_treeview_is_expanded(trvw, item) != expanded)
671 {
672 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
673 if (TreeView_Expand(hwnd, (HTREEITEM)item, expanded ? TVE_EXPAND : TVE_COLLAPSE))
674 {
675 return GATE_RESULT_OK;
676 }
677 else
678 {
679 return GATE_RESULT_FAILED;
680 }
681 }
682 return GATE_RESULT_OK;
683 }
684
685 gate_result_t gate_ui_treeview_get_selected_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t* item)
686 {
687 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
688 HTREEITEM hitem = TreeView_GetSelection(hwnd);
689 if (hitem != NULL)
690 {
691 *item = (gate_ui_treeview_item_t)hitem;
692 return GATE_RESULT_OK;
693 }
694 else
695 {
696 return GATE_RESULT_NOMATCH;
697 }
698 }
699
700 gate_result_t gate_ui_treeview_select_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
701 {
702 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
703 if (TreeView_SelectItem(hwnd, (HTREEITEM)item))
704 {
705 return GATE_RESULT_OK;
706 }
707 else
708 {
709 return GATE_RESULT_FAILED;
710 }
711 }
712
713 gate_result_t gate_ui_treeview_perform_action(gate_ui_treeview_t* trvw, gate_enumint_t action)
714 {
715 gate_result_t result;
716 gate_ui_treeview_item_t tvitem;
717 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
718
719 switch (action)
720 {
721 case GATE_UI_ACTION_ACTIVATE:
722 {
723 result = gate_ui_treeview_get_selected_item(trvw, &tvitem);
724 if (GATE_SUCCEEDED(result))
725 {
726 HTREEITEM hitem = (HTREEITEM)tvitem;
727 NMTREEVIEW nmtv;
728 gate_intptr_t lresult = 0;
729 gate_mem_clear(&nmtv, sizeof(nmtv));
730 nmtv.hdr.hwndFrom = hwnd;
731 nmtv.hdr.code = TVN_SELCHANGED;
732 nmtv.hdr.idFrom = (UINT_PTR)hwnd;
733 nmtv.itemNew.hItem = (HTREEITEM)tvitem;
734 gate_ui_treeview_events((void*)hwnd, &trvw->ctrl, WM_NOTIFY, (gate_intptr_t)hwnd, (gate_intptr_t)(void*)&nmtv, &lresult);
735 }
736 return GATE_RESULT_OK;
737 }
738 case GATE_UI_ACTION_CONTEXTMENU:
739 {
740 result = gate_ui_treeview_get_selected_item(trvw, &tvitem);
741 if (GATE_SUCCEEDED(result))
742 {
743 HTREEITEM hitem = (HTREEITEM)tvitem;
744 NMTREEVIEW nmtv;
745 RECT rc;
746 SHORT x, y;
747 LPARAM lparam;
748 gate_intptr_t lresult = 0;
749
750 TreeView_GetItemRect(hwnd, hitem, &rc, TRUE);
751 x = (rc.left + rc.right) / 2;
752 y = (rc.top + rc.bottom) / 2;
753 lparam = (LPARAM)((DWORD)(WORD)x | ((DWORD)(WORD)y << 16));
754 gate_ui_treeview_events(hwnd, &trvw->ctrl, WM_RBUTTONDOWN, MK_RBUTTON, lparam, &lresult);
755 }
756 return GATE_RESULT_OK;
757 }
758 }
759
760 return GATE_RESULT_NOTSUPPORTED;
761 }
762
763
764 #endif /*GATE_UI_WINAPI*/
765
766
767
768 #if defined(GATE_UI_GTK)
769
770 #include "gate/ui/gateui_gtk.h"
771
772 #define GATE_UI_GTK_TREEVIEW_FIELD_TEXT 0
773 #define GATE_UI_GTK_TREEVIEW_FIELD_ID 1
774 #define GATE_UI_GTK_TREEVIEW_FIELD_PARAM 2
775 #define GATE_UI_GTK_TREEVIEW_FIELD_ICON 3
776
777 static void gate_ui_gtk_treeview_on_cursor_changed(GtkTreeView* tree_view, gpointer user_data)
778 {
779 gate_ui_treeview_t* trvw = (gate_ui_treeview_t*)user_data;
780 gate_ui_treeview_item_t item;
781 gate_result_t result;
782 result = gate_ui_treeview_get_selected_item(trvw, &item);
783 if (GATE_SUCCEEDED(result))
784 {
785 trvw->on_select(&trvw->ctrl, item);
786 }
787 else
788 {
789 trvw->on_select(&trvw->ctrl, GATE_UI_TREEVIEW_INVALID_ITEM);
790 }
791 }
792
793 static void gate_ui_gtk_treeview_on_destroy(GtkWidget* object, gpointer user_data)
794 {
795 gate_ui_treeview_t* trvw = (gate_ui_treeview_t*)user_data;
796 gate_ui_iconlist_destroy(&trvw->icons);
797 }
798
799 gate_result_t gate_ui_treeview_create(gate_ui_treeview_t* trvw, gate_ui_ctrl_t* parent,
800 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
801 {
802 gate_result_t ret = GATE_RESULT_FAILED;
803
804 do
805 {
806 GtkWidget* widget;
807 GtkTreeViewColumn* col;
808 GtkCellRenderer* renderer;
809 GtkTreeModel* model;
810 /*GtkTreeStore* treestore;*/
811 GtkWidget* scroll_widget;
812 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
813
814 gate_mem_clear(trvw, sizeof(gate_ui_treeview_t));
815 widget = gtk_tree_view_new();
816 if (widget == NULL)
817 {
818 ret = GATE_RESULT_OUTOFRESOURCES;
819 break;
820 }
821
822 col = gtk_tree_view_column_new();
823 gtk_tree_view_column_set_title(col, "Tree view");
824
825 renderer = gtk_cell_renderer_pixbuf_new();
826 gtk_tree_view_column_pack_start(col, renderer, FALSE);
827 gtk_tree_view_column_add_attribute(col, renderer, "pixbuf", GATE_UI_GTK_TREEVIEW_FIELD_ICON);
828 renderer = gtk_cell_renderer_text_new();
829 gtk_tree_view_column_pack_start(col, renderer, FALSE);
830 gtk_tree_view_column_add_attribute(col, renderer, "text", GATE_UI_GTK_TREEVIEW_FIELD_TEXT);
831
832 model = GTK_TREE_MODEL(gtk_tree_store_new(4,
833 G_TYPE_STRING, /* text */
834 G_TYPE_POINTER, /* item-id */
835 G_TYPE_POINTER, /* item-param */
836 GDK_TYPE_PIXBUF, /* icon */
837 -1));
838
839 gtk_tree_view_set_model(GTK_TREE_VIEW(widget), model);
840 g_object_unref(model);
841
842 gtk_tree_view_append_column(GTK_TREE_VIEW(widget), col);
843
844 scroll_widget = gtk_scrolled_window_new(NULL, NULL);
845 if (scroll_widget == NULL)
846 {
847 gtk_widget_destroy(widget);
848 ret = GATE_RESULT_OUTOFRESOURCES;
849 break;
850 }
851
852 gtk_container_add(GTK_CONTAINER(scroll_widget), widget);
853 gtk_widget_show(widget);
854
855 ret = gate_ui_gtk_ctrl_init(&trvw->ctrl, scroll_widget, host, userparam, parent,
856 NULL, false, false, position, &flags);
857
858 if (GATE_SUCCEEDED(ret))
859 {
860 ret = gate_ui_iconlist_create(&trvw->icons, host, 16, 16);
861 if (GATE_FAILED(ret))
862 {
863 gate_ui_gtk_ctrl_destroy(&trvw->ctrl);
864 break;
865 }
866
867 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(widget), FALSE);
868 gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(widget), TRUE);
869
870 g_signal_connect(G_OBJECT(widget), "cursor-changed", G_CALLBACK(gate_ui_gtk_treeview_on_cursor_changed), (gpointer)trvw);
871 g_signal_connect(G_OBJECT(widget), "destroy", G_CALLBACK(gate_ui_gtk_treeview_on_destroy), (gpointer)trvw);
872 }
873 //cursor-changed
874 } while (0);
875
876 return ret;
877 }
878
879 gate_result_t gate_ui_treeview_add_icon(gate_ui_treeview_t* trvw, gate_ui_icon_t const* icon, gate_intptr_t* icon_key)
880 {
881 return gate_ui_iconlist_add_icon(&trvw->icons, icon, icon_key);
882 }
883
884 gate_result_t gate_ui_treeview_add_icon_image(gate_ui_treeview_t* trvw, gate_rasterimage_t const* image, gate_intptr_t* icon_key)
885 {
886 return gate_ui_iconlist_add_image(&trvw->icons, image, icon_key);
887 }
888
889 static gate_atomic_int64_t gate_ui_treeview_item_id = 0;
890
891 static gate_bool_t gate_ui_treeview_resolve(GtkTreeModel* model, GtkTreeIter* current_iter, void* id, GtkTreeIter* found_iter)
892 {
893 GtkTreeIter first;
894
895 if (current_iter == NULL)
896 {
897 if (!gtk_tree_model_get_iter_first(model, &first))
898 {
899 return false;
900 }
901 current_iter = &first;
902 }
903 do
904 {
905 GtkTreeIter first_child;
906 GValue value = GATE_INIT_EMPTY;
907 gtk_tree_model_get_value(model, current_iter, 1, &value);
908 if (g_value_get_pointer(&value) == id)
909 {
910 *found_iter = *current_iter;
911 return true;
912 }
913 g_value_unset(&value);
914
915 if (gtk_tree_model_iter_children(model, &first_child, current_iter))
916 {
917 if (gate_ui_treeview_resolve(model, &first_child, id, found_iter))
918 {
919 return true;
920 }
921 }
922 } while (gtk_tree_model_iter_next(model, current_iter));
923 return false;
924 }
925
926 gate_result_t gate_ui_treeview_add(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t const* parent, gate_string_t const* text,
927 gate_intptr_t icon_key, void* itemparam, gate_ui_treeview_item_t* newitem)
928 {
929 gate_result_t ret = GATE_RESULT_FAILED;
930
931 do
932 {
933 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
934 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
935 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
936 GtkTreeStore* store = GTK_TREE_STORE(model);
937 GtkTreeIter tree_iter;
938 GtkTreeIter parent_iter;
939 gate_ui_treeview_item_t new_item_id = (gate_uintptr_t)gate_atomic_int64_inc(&gate_ui_treeview_item_id);
940 char textbuffer[4096];
941
942 GATE_STRING_TO_BUFFER(text, textbuffer);
943 if (parent != NULL)
944 {
945 if (!gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)*parent, &parent_iter))
946 {
947 ret = GATE_RESULT_NOMATCH;
948 break;
949 }
950 }
951
952 gtk_tree_store_append(store, &tree_iter, parent ? &parent_iter : NULL);
953 gtk_tree_store_set(store, &tree_iter,
954 GATE_UI_GTK_TREEVIEW_FIELD_TEXT, textbuffer,
955 GATE_UI_GTK_TREEVIEW_FIELD_ID, (void*)new_item_id,
956 GATE_UI_GTK_TREEVIEW_FIELD_PARAM, itemparam,
957 -1);
958
959 if (trvw->icons.resources[0] && (icon_key != GATE_UI_TREEVIEW_INVALID_ICON))
960 {
961 gate_ui_icon_t const* ptr_icon = gate_arraylist_get((gate_arraylist_t)trvw->icons.resources[0], (gate_size_t)icon_key);
962 if (ptr_icon)
963 {
964 void* ptr_pixbuf = ptr_icon->resources[0];
965 if (ptr_pixbuf)
966 {
967 gtk_tree_store_set(store, &tree_iter, GATE_UI_GTK_TREEVIEW_FIELD_ICON, ptr_pixbuf, -1);
968 }
969 }
970 }
971
972 if (newitem != NULL)
973 {
974 *newitem = new_item_id;
975 }
976 ret = GATE_RESULT_OK;
977
978 } while (0);
979 return ret;
980 }
981 void* gate_ui_treeview_get_itemparam(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
982 {
983 void* ret = NULL;
984 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
985 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
986 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
987 GtkTreeIter iter_found;
988
989 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &iter_found))
990 {
991 GValue value = GATE_INIT_EMPTY;
992 gtk_tree_model_get_value(model, &iter_found, 2, &value);
993 ret = g_value_get_pointer(&value);
994 g_value_unset(&value);
995 }
996
997 /* error / unresolved case */
998 return ret;
999 }
1000
1001 static void gate_ui_treeview_remove_recursive(GtkTreeModel* model, GtkTreeIter* current_iter)
1002 {
1003 GtkTreeIter item;
1004 if (gtk_tree_model_iter_children(model, &item, current_iter))
1005 {
1006 do
1007 {
1008 gate_ui_treeview_remove_recursive(model, &item);
1009 } while (gtk_tree_model_iter_next(model, &item));
1010 }
1011
1012 item = *current_iter;
1013 gtk_tree_store_remove(GTK_TREE_STORE(model), &item);
1014 }
1015
1016 gate_result_t gate_ui_treeview_remove(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1017 {
1018 gate_result_t ret = GATE_RESULT_FAILED;
1019 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1020 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1021 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1022 GtkTreeIter iter_found;
1023 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &iter_found))
1024 {
1025 gate_ui_treeview_remove_recursive(model, &iter_found);
1026 ret = GATE_RESULT_OK;
1027 }
1028 else
1029 {
1030 ret = GATE_RESULT_NOMATCH;
1031 }
1032 return ret;
1033 }
1034 gate_result_t gate_ui_treeview_clear(gate_ui_treeview_t* trvw)
1035 {
1036 gate_result_t ret = GATE_RESULT_OK;
1037 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1038 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1039 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1040 gtk_tree_store_clear(GTK_TREE_STORE(model));
1041 return ret;
1042 }
1043 gate_result_t gate_ui_treeview_get_parent(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_ui_treeview_item_t* parent)
1044 {
1045 gate_result_t ret = GATE_RESULT_NOMATCH;
1046 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1047 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1048 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1049 GtkTreeIter found_iter;
1050 GtkTreeIter parent_iter;
1051 GValue value = GATE_INIT_EMPTY;
1052 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1053 {
1054 if (gtk_tree_model_iter_parent(model, &parent_iter, &found_iter))
1055 {
1056 gtk_tree_model_get_value(model, &parent_iter, 1, &value);
1057 if (parent != NULL)
1058 {
1059 *parent = (gate_ui_treeview_item_t)(gate_uintptr_t)g_value_get_pointer(&value);
1060 }
1061 g_value_unset(&value);
1062 ret = GATE_RESULT_OK;
1063 }
1064 }
1065 return ret;
1066 }
1067 gate_result_t gate_ui_treeview_get_children(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_array_t* children)
1068 {
1069 gate_result_t ret = GATE_RESULT_FAILED;
1070 gate_arraylist_t arraylist = NULL;
1071 do
1072 {
1073 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1074 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1075 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1076 GtkTreeIter found_iter;
1077 GtkTreeIter child_iter;
1078 GValue value = GATE_INIT_EMPTY;
1079
1080 arraylist = gate_arraylist_create(sizeof(gate_ui_treeview_item_t), NULL, 0, NULL, NULL);
1081 if (arraylist == NULL)
1082 {
1083 ret = GATE_RESULT_OUTOFMEMORY;
1084 break;
1085 }
1086
1087 if (item == 0)
1088 {
1089 if(!gtk_tree_model_get_iter_first(model, &found_iter))
1090 {
1091 ret = GATE_RESULT_NOMATCH;
1092 break;
1093 }
1094 do
1095 {
1096 gate_ui_treeview_item_t child_item;
1097 gtk_tree_model_get_value(model, &found_iter, 1, &value);
1098 child_item = (gate_ui_treeview_item_t)g_value_get_pointer(&value);
1099 g_value_unset(&value);
1100 gate_arraylist_add(arraylist, &child_item);
1101
1102 } while (gtk_tree_model_iter_next(model, &found_iter));
1103 }
1104 else
1105 {
1106 if (!gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1107 {
1108 ret = GATE_RESULT_NOMATCH;
1109 break;
1110 }
1111
1112 if (gtk_tree_model_iter_children(model, &child_iter, &found_iter))
1113 {
1114 do
1115 {
1116 void* ptr_value = NULL;
1117 gtk_tree_model_get_value(model, &child_iter, 1, &value);
1118 ptr_value = g_value_get_pointer(&value);
1119 gate_arraylist_add(arraylist, (void const*)&ptr_value);
1120 g_value_unset(&value);
1121 } while (gtk_tree_model_iter_next(model, &child_iter));
1122 }
1123 }
1124
1125 if (NULL != gate_array_create(children, arraylist))
1126 {
1127 ret = GATE_RESULT_OK;
1128 }
1129 } while (0);
1130 if (arraylist != NULL)
1131 {
1132 gate_arraylist_release(arraylist);
1133 }
1134 return ret;
1135 }
1136 gate_result_t gate_ui_treeview_get_text(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_string_t* text)
1137 {
1138 gate_result_t ret = GATE_RESULT_NOMATCH;
1139 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1140 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1141 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1142 GtkTreeIter found_iter;
1143 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1144 {
1145 GValue value = GATE_INIT_EMPTY;
1146 char const* text_buffer = NULL;
1147 gtk_tree_model_get_value(model, &found_iter, 0, &value);
1148 text_buffer = g_value_get_string(&value);
1149 if (NULL != gate_string_create(text, text_buffer, gate_str_length(text_buffer)))
1150 {
1151 ret = GATE_RESULT_OK;
1152 }
1153 g_value_unset(&value);
1154 }
1155 return ret;
1156 }
1157 gate_result_t gate_ui_treeview_set_text(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_string_t const* text)
1158 {
1159 gate_result_t ret = GATE_RESULT_NOMATCH;
1160 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1161 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1162 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1163 GtkTreeIter found_iter;
1164 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1165 {
1166 GValue value = GATE_INIT_EMPTY;
1167 gchar text_buffer[4096];
1168 GATE_STRING_TO_BUFFER(text, text_buffer);
1169 g_value_init(&value, G_TYPE_STRING);
1170 g_value_set_string(&value, text_buffer);
1171 gtk_tree_store_set_value(GTK_TREE_STORE(model), &found_iter, 0, &value);
1172 g_value_unset(&value);
1173 ret = GATE_RESULT_OK;
1174 }
1175 return ret;
1176 }
1177 gate_bool_t gate_ui_treeview_is_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1178 {
1179 gate_result_t ret = false;
1180 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1181 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1182 GtkTreeView* treeview = GTK_TREE_VIEW(widget);
1183 GtkTreeModel* model = gtk_tree_view_get_model(treeview);
1184 GtkTreeIter found_iter;
1185
1186 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1187 {
1188 GtkTreePath* path = gtk_tree_model_get_path(model, &found_iter);
1189 ret = gtk_tree_view_row_expanded(treeview, path);
1190 gtk_tree_path_free(path);
1191 }
1192 return ret;
1193 }
1194 gate_result_t gate_ui_treeview_set_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_bool_t expanded)
1195 {
1196 gate_result_t ret = GATE_RESULT_NOMATCH;
1197 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1198 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1199 GtkTreeView* treeview = GTK_TREE_VIEW(widget);
1200 GtkTreeModel* model = gtk_tree_view_get_model(treeview);
1201 GtkTreeIter found_iter;
1202
1203 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1204 {
1205 GtkTreePath* path = gtk_tree_model_get_path(model, &found_iter);
1206 if (expanded)
1207 {
1208 //gtk_tree_view_expand_all(treeview);
1209 //gtk_tree_view_expand_to_path(treeview, path);
1210 gtk_tree_view_expand_row(treeview, path, FALSE);
1211 }
1212 else
1213 {
1214 gtk_tree_view_collapse_row(treeview, path);
1215 }
1216 gtk_tree_path_free(path);
1217 ret = GATE_RESULT_OK;
1218 }
1219 return ret;
1220 }
1221 gate_result_t gate_ui_treeview_get_selected_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t* item)
1222 {
1223 gate_result_t ret = GATE_RESULT_FAILED;
1224 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1225 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1226 GtkTreeView* treeview = GTK_TREE_VIEW(widget);
1227 GtkTreeModel* model = gtk_tree_view_get_model(treeview);
1228 GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
1229 GtkTreeIter found_iter;
1230
1231 if (gtk_tree_selection_get_selected(selection, &model, &found_iter))
1232 {
1233 GValue value = GATE_INIT_EMPTY;
1234 gtk_tree_model_get_value(model, &found_iter, 1, &value);
1235 *item = (gate_ui_treeview_item_t)(gate_uintptr_t)g_value_get_pointer(&value);
1236 g_value_unset(&value);
1237 ret = GATE_RESULT_OK;
1238 }
1239 else
1240 {
1241 *item = GATE_UI_TREEVIEW_INVALID_ITEM;
1242 ret = GATE_RESULT_NOMATCH;
1243 }
1244 return ret;
1245 }
1246 gate_result_t gate_ui_treeview_select_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1247 {
1248 gate_result_t ret = GATE_RESULT_FAILED;
1249 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1250 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1251 GtkTreeView* treeview = GTK_TREE_VIEW(widget);
1252 GtkTreeModel* model = gtk_tree_view_get_model(treeview);
1253 GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
1254 GtkTreeIter found_iter;
1255 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1256 {
1257 GtkTreePath* path = gtk_tree_model_get_path(model, &found_iter);
1258 gtk_tree_selection_select_iter(selection, &found_iter);
1259 gtk_tree_path_free(path);
1260 if (trvw->on_select)
1261 {
1262 trvw->on_select(&trvw->ctrl, item);
1263 }
1264 ret = GATE_RESULT_OK;
1265 }
1266
1267 return ret;
1268 }
1269
1270 gate_result_t gate_ui_treeview_perform_action(gate_ui_treeview_t* trvw, gate_enumint_t action)
1271 {
1272 switch (action)
1273 {
1274 case GATE_UI_ACTION_ACTIVATE:
1275 {
1276 /* TODO */
1277 return GATE_RESULT_OK;
1278 }
1279 case GATE_UI_ACTION_CONTEXTMENU:
1280 {
1281 /* TODO */
1282 return GATE_RESULT_OK;
1283 }
1284 }
1285 return GATE_RESULT_NOTSUPPORTED;
1286 }
1287
1288 #endif /* GATE_UI_GTK */
1289
1290
1291
1292 #if defined(GATE_UI_MOTIF)
1293
1294 #include "gate/ui/gateui_motif.h"
1295 #include <Xm/List.h>
1296 #include <Xm/Tree.h>
1297 #include <Xm/Hierarchy.h>
1298 #include <Xm/Label.h>
1299 #include <Xm/PushB.h>
1300 #include <Xm/Outline.h>
1301 #include <Xm/ScrolledW.h>
1302 #include <Xm/ToggleB.h>
1303 #include <Xm/Manager.h>
1304
1305 4 static void motif_treeview_remove_node_widget(Widget node)
1306 {
1307 4 XtUnmanageChild(node);
1308 4 XtDestroyWidget(node);
1309 4 }
1310
1311 4 static void motif_treeview_remove_nodes_recursive(Widget node)
1312 {
1313 4 WidgetList wlist = XmHierarchyGetChildNodes(node);
1314
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (wlist)
1315 {
1316 gate_size_t ndx;
1317
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (ndx = 0; wlist[ndx]; ++ndx)
1318 {
1319 2 motif_treeview_remove_nodes_recursive(wlist[ndx]);
1320 }
1321 1 XtFree((char*)wlist);
1322 }
1323 4 motif_treeview_remove_node_widget(node);
1324 4 }
1325
1326 1 static gate_result_t motif_treeview_root_elements(gate_ui_treeview_t* tv, gate_array_t* list)
1327 {
1328 1 WidgetList children = NULL;
1329 1 Cardinal num_children = 0;
1330 Widget w;
1331 unsigned ndx;
1332 gate_arraylist_t arr;
1333
1334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(tv != NULL);
1335 1 w = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&tv->ctrl);
1336
1337 1 arr = gate_arraylist_create(sizeof(Widget), NULL, 0, NULL, NULL);
1338
1339 1 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &num_children, NULL, NULL);
1340
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
7 for (ndx = 0; ndx != num_children; ++ndx)
1341 {
1342 6 Widget parent_widget = NULL;
1343 6 Widget child_widget = children[ndx];
1344
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if (!XmIsPushButton(child_widget))
1345 {
1346 3 continue;
1347 }
1348 3 XtVaGetValues(child_widget, XmNparentNode, &parent_widget, NULL, NULL);
1349
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (parent_widget == NULL)
1350 {
1351 1 gate_arraylist_add(arr, &child_widget);
1352 }
1353 }
1354 1 gate_array_create(list, arr);
1355 1 gate_arraylist_release(arr);
1356 1 return GATE_RESULT_OK;
1357 }
1358
1359 1 static gate_result_t motif_treeview_destroy(gate_ui_ctrl_t* ctrl)
1360 {
1361 1 gate_ui_treeview_t* tv = (gate_ui_treeview_t*)ctrl;
1362 gate_array_t arr;
1363 unsigned ndx;
1364 gate_size_t cnt;
1365 Widget w;
1366
1367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(tv != NULL);
1368
1369 1 motif_treeview_root_elements(tv, &arr);
1370 1 cnt = gate_array_length(&arr);
1371
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (ndx = 0; ndx < cnt; ++ndx)
1372 {
1373 1 Widget* ptr_node = (Widget*)gate_array_get(&arr, ndx);
1374
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!ptr_node || !*ptr_node) continue;
1375 1 motif_treeview_remove_nodes_recursive(*ptr_node);
1376 }
1377 1 gate_array_release(&arr);
1378
1379 1 w = GATE_UI_MOTIF_GET_CTRL_CONTAINER(ctrl);
1380
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (w)
1381 {
1382 1 XtUnmanageChild(w);
1383 1 XtDestroyWidget(w);
1384 }
1385
1386 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
1387
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (w)
1388 {
1389 1 XtUnmanageChild(w);
1390 1 XtDestroyWidget(w);
1391 }
1392
1393 1 gate_mem_clear(ctrl, sizeof(gate_ui_ctrl_t));
1394 1 return GATE_RESULT_OK;
1395 }
1396
1397 6 static gate_result_t motif_treeview_get_children(gate_ui_ctrl_t* ctrl, void** ptr_to_widgetlist, gate_size_t* ptr_to_children_count)
1398 {
1399 6 WidgetList children = NULL;
1400 6 Cardinal num_children = 0;
1401 6 Widget w_tree = GATE_UI_MOTIF_GET_CTRL_CONTAINER(ctrl);
1402
1403 6 XtVaGetValues(w_tree, XmNchildren, &children, XmNnumChildren, &num_children, NULL, NULL);
1404
1405
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (ptr_to_widgetlist) *ptr_to_widgetlist = children;
1406
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (ptr_to_children_count) *ptr_to_children_count = num_children;
1407 6 return GATE_RESULT_OK;
1408 }
1409
1410
1411 static gate_ui_motif_dispatcher_t treeview_dispatcher =
1412 {
1413 &motif_treeview_destroy,
1414 NULL,
1415 NULL,
1416 NULL,
1417 NULL,
1418 NULL,
1419 &motif_treeview_get_children
1420 };
1421
1422 1 gate_result_t gate_ui_treeview_create(
1423 gate_ui_treeview_t* trvw, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
1424 gate_uint32_t flags, void* userparam)
1425 {
1426 1 gate_result_t ret = GATE_RESULT_FAILED;
1427 1 Widget w = NULL;
1428 1 Widget w_tree = NULL;
1429 do
1430 {
1431 1 gate_ui_host_t* ptr_host = NULL;
1432 1 Widget parent_widget = NULL;
1433 1 Widget w_scroll1 = NULL;
1434 1 Widget w_scroll2 = NULL;
1435 Arg args[10];
1436 Cardinal args_count;
1437 /* XmNtreeDefaultLineStyle; */
1438
1439
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!trvw || !parent)
1440 {
1441 ret = GATE_RESULT_INVALIDARG;
1442 break;
1443 }
1444
1445 1 parent_widget = GATE_UI_MOTIF_GET_CTRL_CONTAINER(parent);
1446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!parent_widget)
1447 {
1448 parent_widget = GATE_UI_MOTIF_GET_CTRL_WIDGET(parent);
1449 }
1450
1451 1 ptr_host = GATE_UI_MOTIF_GET_CTRL_HOST(parent);
1452
1453 1 args_count = 0;
1454 1 XtSetArg(args[args_count], XmNscrollingPolicy, XmAUTOMATIC); ++args_count;
1455 1 XtSetArg(args[args_count], XmNvisualPolicy, XmVARIABLE); ++args_count;
1456 1 XtSetArg(args[args_count], XmNshowSash, True); ++args_count;
1457 1 XtSetArg(args[args_count], XmNscrollBarDisplayPolicy, XmSTATIC); ++args_count;
1458 //XtSetArg(args[args_count], XmNallowResize, True); ++args_count;
1459 1 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
1460 1 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1461
1462 1 w = XmCreateScrolledWindow(parent_widget, NULL, args, args_count);
1463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w)
1464 {
1465 ret = GATE_RESULT_OUTOFRESOURCES;
1466 break;
1467 }
1468
1469 1 XtVaGetValues(w, XmNhorizontalScrollBar, &w_scroll1, XmNverticalScrollBar, &w_scroll2, NULL);
1470
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (w_scroll1)
1471 {
1472 1 XtVaSetValues(w_scroll1, XmNshadowThickness, 1, NULL);
1473 }
1474
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (w_scroll2)
1475 {
1476 1 XtVaSetValues(w_scroll2, XmNshadowThickness, 1, NULL);
1477 }
1478
1479 1 args_count = 0;
1480 1 XtSetArg(args[args_count], XmNunitType, XmPIXELS); ++args_count;
1481 1 XtSetArg(args[args_count], XmNconnectNodes, True); ++args_count;
1482 1 XtSetArg(args[args_count], XmNindentSpace, 24); ++args_count;
1483 1 XtSetArg(args[args_count], XmNshadowThickness, 0); ++args_count;
1484 1 XtSetArg(args[args_count], XmNhighlightThickness, 0); ++args_count;
1485 1 XtSetArg(args[args_count], XmNhorizontalMargin, 1); ++args_count;
1486 1 XtSetArg(args[args_count], XmNverticalMargin, 1); ++args_count;
1487
1488 1 w_tree = XmCreateOutline(w, NULL, args, args_count);
1489
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w_tree)
1490 {
1491 ret = GATE_RESULT_OUTOFRESOURCES;
1492 break;
1493 }
1494
1495 1 ret = gate_ui_iconlist_create(&trvw->icons, ptr_host, 16, 16);
1496
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(ret))
1497 {
1498 break;
1499 }
1500
1501 1 ret = gate_ui_motif_ctrl_init(&trvw->ctrl, w, userparam, NULL, parent, w_tree, position, &flags, &treeview_dispatcher);
1502
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1503
1504 1 XtManageChild(w);
1505 1 XtManageChild(w_tree);
1506
1507 } while (0);
1508
1509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(ret))
1510 {
1511 if (w_tree != NULL)
1512 {
1513 XtDestroyWidget(w_tree);
1514 }
1515 if (w != NULL)
1516 {
1517 XtDestroyWidget(w);
1518 }
1519 }
1520 1 return ret;
1521 }
1522
1523 gate_result_t gate_ui_treeview_add_icon(gate_ui_treeview_t* trvw, gate_ui_icon_t const* icon, gate_intptr_t* icon_key)
1524 {
1525 return gate_ui_iconlist_add_icon(&trvw->icons, icon, icon_key);
1526 }
1527
1528 1 gate_result_t gate_ui_treeview_add_icon_image(gate_ui_treeview_t* trvw, gate_rasterimage_t const* image, gate_intptr_t* icon_key)
1529 {
1530 1 return gate_ui_iconlist_add_image(&trvw->icons, image, icon_key);
1531 }
1532
1533 3 static gate_bool_t gate_ui_treeview_is_node_selected(Widget node)
1534 {
1535 3 Dimension dim = 0;
1536 3 XtVaGetValues(node, XmNshadowThickness, &dim, NULL, NULL);
1537 3 return dim != 0;
1538 }
1539
1540 9 static void gate_ui_treeview_set_node_selected(Widget node, gate_bool_t selected)
1541 {
1542 9 Dimension olddim = 0;
1543 9 Dimension newdim = selected ? 1 : 0;
1544 9 XtVaGetValues(node, XmNshadowThickness, &olddim, NULL, NULL);
1545
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
9 if (olddim != newdim)
1546 {
1547 2 XtVaSetValues(node, XmNshadowThickness, newdim, NULL, NULL);
1548 /* TODO: update UI*/
1549 }
1550 9 }
1551
1552 typedef gate_bool_t(*gate_ui_treeview_node_iterate_callback_t)(gate_ui_treeview_t* ptr_trvw, Widget node, void* param);
1553
1554 3 static gate_result_t gate_ui_treeview_node_iterate(gate_ui_treeview_t* ptr_trvw, gate_ui_treeview_node_iterate_callback_t callback, void* param)
1555 {
1556 gate_result_t ret;
1557 3 WidgetList nodes = NULL;
1558 3 gate_size_t nodes_count = 0;
1559 gate_size_t ndx;
1560 3 gate_bool_t continue_iterate = true;
1561
1562 3 ret = gate_ui_motif_ctrl_get_children(&ptr_trvw->ctrl, (void**)&nodes, &nodes_count);
1563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(ret))
1564 {
1565 return ret;
1566 }
1567
1568
3/4
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 3 times.
21 for (ndx = 0; continue_iterate && (ndx != nodes_count); ++ndx)
1569 {
1570 18 Widget w = nodes[ndx];
1571
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
18 if (!XtIsSubclass(w, xmPushButtonWidgetClass))
1572 {
1573 9 continue;
1574 }
1575 9 continue_iterate = callback(ptr_trvw, w, param);
1576 }
1577 3 return ret;
1578 }
1579
1580 static void gate_ui_treeview_set_node_selected_recursive(Widget node, Widget node_to_select)
1581 {
1582 WidgetList sub_nodes = NULL;
1583 gate_ui_treeview_set_node_selected(node, node == node_to_select);
1584 sub_nodes = XmHierarchyGetChildNodes(node);
1585 if (sub_nodes)
1586 {
1587 gate_size_t ndx;
1588 for (ndx = 0; sub_nodes[ndx]; ++ndx)
1589 {
1590 gate_ui_treeview_set_node_selected_recursive(sub_nodes[ndx], node_to_select);
1591 }
1592 XtFree((char*)sub_nodes);
1593 }
1594 }
1595
1596 9 static gate_bool_t gate_ui_treeview_node_iterate_select(gate_ui_treeview_t* ptr_trvw, Widget node, void* param)
1597 {
1598 9 Widget to_select = (Widget)param;
1599 9 gate_ui_treeview_set_node_selected(node, node == to_select);
1600 9 return true;
1601 }
1602
1603 3 static void gate_ui_treeview_select_node_widget_and_unselect_others(gate_ui_treeview_t* ptr_trvw, Widget node_to_select)
1604 {
1605 3 gate_ui_treeview_node_iterate(ptr_trvw, &gate_ui_treeview_node_iterate_select, (void*)node_to_select);
1606 3 }
1607
1608 3 static Widget gate_ui_treeview_get_selected_node_widget(gate_ui_treeview_t* ptr_trvw)
1609 {
1610 3 Widget ret = NULL;
1611 3 WidgetList children = NULL;
1612 gate_size_t ndx;
1613 3 gate_size_t children_count = 0;
1614 gate_result_t result;
1615
1616 3 result = gate_ui_motif_ctrl_get_children(&ptr_trvw->ctrl, (void**)&children, &children_count);
1617
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(result))
1618 {
1619 return NULL;
1620 }
1621
1622
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 for (ndx = 0; ndx != children_count; ++ndx)
1623 {
1624 3 Widget node = children[ndx];
1625
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (node)
1626 {
1627
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if (gate_ui_treeview_is_node_selected(node))
1628 {
1629 3 ret = node;
1630 3 break;
1631 }
1632 }
1633 }
1634 3 return ret;
1635 }
1636
1637 2 static void gate_ui_treeview_on_node_widget_click(Widget node_widget, XtPointer client_data, XtPointer event_data)
1638 {
1639 2 gate_ui_treeview_t* ptr_trvw = (gate_ui_treeview_t*)client_data;
1640
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (ptr_trvw)
1641 {
1642 2 gate_bool_t context_menu = false;
1643 2 XmPushButtonCallbackStruct* ptr_btn_event_data = (XmPushButtonCallbackStruct*)event_data;
1644
1645 2 gate_ui_treeview_select_node_widget_and_unselect_others(ptr_trvw, node_widget);
1646
1647
1648
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if(ptr_btn_event_data && ptr_btn_event_data->event)
1649 {
1650
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 switch(ptr_btn_event_data->event->type)
1651 {
1652 1 case KeyPress:
1653 {
1654 1 XKeyEvent* kev = &ptr_btn_event_data->event->xkey;
1655
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (kev->state & ControlMask)
1656 {
1657 1 context_menu = true;
1658 }
1659 1 break;
1660 }
1661 1 default:
1662 {
1663 1 break;
1664 }
1665 }
1666 }
1667
1668
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (context_menu)
1669 {
1670
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_trvw->on_contextmenu)
1671 {
1672 1 ptr_trvw->on_contextmenu(&ptr_trvw->ctrl, (gate_ui_treeview_item_t)node_widget);
1673 }
1674 }
1675 else
1676 {
1677
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_trvw->on_select)
1678 {
1679 1 ptr_trvw->on_select(&ptr_trvw->ctrl, (gate_ui_treeview_item_t)node_widget);
1680 }
1681 }
1682 }
1683 2 }
1684
1685 4 gate_result_t gate_ui_treeview_add(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t const* parent, gate_string_t const* text,
1686 gate_intptr_t iconkey, void* itemparam, gate_ui_treeview_item_t* newitem)
1687 {
1688 Widget w_tree;
1689 Widget w_node;
1690 XmString xmstr;
1691 Arg args[10];
1692 Cardinal args_count;
1693
1694 4 w_tree = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&trvw->ctrl);
1695
1696 4 xmstr = gate_ui_motif_create_string(text);
1697
1698 4 args_count = 0;
1699 4 XtSetArg(args[args_count], XmNlabelString, xmstr); ++args_count;
1700 4 XtSetArg(args[args_count], XmNnodeState, XmClosed); ++args_count;
1701
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 XtSetArg(args[args_count], XmNparentNode, parent ? (Widget)*parent : (Widget)NULL); ++args_count;
1702 //XtSetArg(args[args_count], XmNlineStyle, 99); ++args_count;
1703 4 XtSetArg(args[args_count], XmNshadowThickness, 0); ++args_count;
1704 //XtSetArg(args[args_count], XmNtoggleMode, XmTOGGLE_BOOLEAN); ++args_count;
1705 //XtSetArg(args[args_count], XmNset, XmUNSET); ++args_count;
1706 //XtSetArg(args[args_count], XmNalignment, XmALIGNMENT_BEGINNING); ++args_count;
1707 4 XtSetArg(args[args_count], XmNuserData, itemparam); ++args_count;
1708 4 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1709
1710 4 w_node = XtCreateWidget(NULL, xmPushButtonWidgetClass, w_tree, args, args_count);
1711 //w_node = XtCreateWidget(NULL, xmLabelWidgetClass, w_tree, args, argcount);
1712 //w_node = XtCreateWidget(NULL, xmToggleButtonWidgetClass, w_tree, args, argcount);
1713 4 XmStringFree(xmstr);
1714
1715 4 XtAddCallback(w_node, XmNactivateCallback, gate_ui_treeview_on_node_widget_click, trvw);
1716
1717 4 *newitem = (gate_uintptr_t)w_node;
1718 4 XtManageChild(w_node);
1719 4 return GATE_RESULT_OK;
1720 }
1721
1722 3 void* gate_ui_treeview_get_itemparam(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1723 {
1724 3 Widget w = (Widget)item;
1725 3 void* userdata = NULL;
1726
1727 3 XtVaGetValues(w, XmNuserData, &userdata, NULL, NULL);
1728 3 return userdata;
1729 }
1730
1731 1 gate_result_t gate_ui_treeview_remove(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1732 {
1733 1 Widget trvw_widget = GATE_UI_MOTIF_GET_CTRL_WIDGET(&trvw->ctrl);
1734 1 Widget w = (Widget)item;
1735 1 motif_treeview_remove_nodes_recursive(w);
1736 1 return GATE_RESULT_OK;
1737 }
1738
1739 gate_result_t gate_ui_treeview_clear(gate_ui_treeview_t* trvw)
1740 {
1741 return GATE_RESULT_NOTIMPLEMENTED;
1742 }
1743
1744 1 gate_result_t gate_ui_treeview_get_parent(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_ui_treeview_item_t* parent)
1745 {
1746 1 Widget w = (Widget)item;
1747 1 Widget w_parent = NULL;
1748
1749 1 XtVaGetValues(w, XmNparentNode, &w_parent, NULL, NULL);
1750
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (w_parent)
1751 {
1752 *parent = (gate_ui_treeview_item_t)w_parent;
1753 }
1754 else
1755 {
1756 1 *parent = 0;
1757 }
1758 1 return GATE_RESULT_OK;
1759 }
1760
1761 1 gate_result_t gate_ui_treeview_get_children(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_array_t* children)
1762 {
1763 1 Widget w_tree = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&trvw->ctrl);
1764 1 Widget w = (Widget)item;
1765 1 WidgetList wlist = NULL;
1766 1 Cardinal wlist_count = 0;
1767 1 gate_bool_t free_wlist = false;
1768 1 gate_bool_t filter_parent = false;
1769 1 gate_arraylist_t arr = gate_arraylist_create(sizeof(gate_ui_treeview_item_t), NULL, 0, NULL, NULL);
1770
1771
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == arr)
1772 {
1773 return GATE_RESULT_OUTOFMEMORY;
1774 }
1775
1776
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (item)
1777 {
1778 wlist = XmHierarchyGetChildNodes(w);
1779 if (wlist)
1780 {
1781 free_wlist = true;
1782 while (wlist[wlist_count] != NULL)
1783 {
1784 ++wlist_count;
1785 };
1786 }
1787 }
1788 else
1789 {
1790 1 XtVaGetValues(w_tree, XmNchildren, &wlist, XmNnumChildren, &wlist_count, NULL);
1791 1 filter_parent = true;
1792 }
1793
1794
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (wlist)
1795 {
1796 gate_size_t ndx;
1797
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
7 for (ndx = 0; ndx < wlist_count; ++ndx)
1798 {
1799 6 Widget child = wlist[ndx];
1800 6 gate_ui_treeview_item_t subitem = (gate_ui_treeview_item_t)child;
1801
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if (!XtIsSubclass(child, xmPushButtonWidgetClass))
1802 {
1803 5 continue;
1804 }
1805
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(filter_parent)
1806 {
1807 3 Widget w_parent = NULL;
1808 3 XtVaGetValues(child, XmNparentNode, &w_parent, NULL, NULL);
1809
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (w_parent != w)
1810 {
1811 2 continue;
1812 }
1813 }
1814 1 gate_arraylist_add(arr, &subitem);
1815 }
1816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(free_wlist)
1817 {
1818 XtFree((char*)wlist);
1819 }
1820 }
1821
1822
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_array_create(children, arr))
1823 {
1824 gate_arraylist_release(arr);
1825 return GATE_RESULT_OUTOFMEMORY;
1826 }
1827 else
1828 {
1829 1 gate_arraylist_release(arr);
1830 1 return GATE_RESULT_OK;
1831 }
1832 }
1833
1834 3 gate_result_t gate_ui_treeview_get_text(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_string_t* text)
1835 {
1836 3 Widget w = (Widget)item;
1837 3 return gate_ui_motif_widget_get_label(w, text);
1838 }
1839
1840 1 gate_result_t gate_ui_treeview_set_text(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_string_t const* text)
1841 {
1842 1 Widget w = (Widget)item;
1843 1 return gate_ui_motif_widget_set_label(w, text);
1844 }
1845
1846 1 gate_bool_t gate_ui_treeview_is_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1847 {
1848 1 Widget w = (Widget)item;
1849 1 Cardinal v = 0;
1850 1 XtVaGetValues(w, XmNoutlineState, &v, NULL, NULL);
1851 1 return (v == XmEXPANDED) ? true : false;
1852 }
1853
1854 2 gate_result_t gate_ui_treeview_set_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_bool_t expanded)
1855 {
1856 2 Widget w = (Widget)item;
1857 2 XtVaSetValues(w, XmNoutlineState, (expanded ? XmEXPANDED : XmCOLLAPSED), NULL, NULL);
1858 2 return GATE_RESULT_OK;
1859 }
1860
1861 1 gate_result_t gate_ui_treeview_get_selected_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t* item)
1862 {
1863 1 Widget sel_widget = gate_ui_treeview_get_selected_node_widget(trvw);
1864
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (sel_widget)
1865 {
1866 1 *item = (gate_ui_treeview_item_t)sel_widget;
1867 1 return GATE_RESULT_OK;
1868 }
1869 else
1870 {
1871 return GATE_RESULT_NOMATCH;
1872 }
1873 }
1874
1875 1 gate_result_t gate_ui_treeview_select_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1876 {
1877 1 Widget w_to_select = (Widget)item;
1878 1 gate_ui_treeview_select_node_widget_and_unselect_others(trvw, w_to_select);
1879
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (trvw->on_select)
1880 {
1881 1 trvw->on_select(&trvw->ctrl, item);
1882 }
1883 1 return GATE_RESULT_OK;
1884 }
1885
1886 2 gate_result_t gate_ui_treeview_perform_action(gate_ui_treeview_t* trvw, gate_enumint_t action)
1887 {
1888
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 switch (action)
1889 {
1890 1 case GATE_UI_ACTION_ACTIVATE:
1891 {
1892 1 Widget selected = gate_ui_treeview_get_selected_node_widget(trvw);
1893
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (selected != NULL)
1894 {
1895 XmPushButtonCallbackStruct event_data;
1896 XEvent evt;
1897 XButtonEvent* bev;
1898 1 gate_mem_clear(&event_data, sizeof(event_data));
1899 1 gate_mem_clear(&evt, sizeof(evt));
1900 1 event_data.click_count = 1;
1901 1 event_data.reason = 10;
1902 1 event_data.event = &evt;
1903 1 bev = &event_data.event->xbutton;
1904 1 bev->type = ButtonRelease;
1905 1 bev->button = 1;
1906 1 gate_ui_treeview_on_node_widget_click(selected, (XtPointer)trvw, &event_data);
1907 }
1908 1 return GATE_RESULT_OK;
1909 }
1910 1 case GATE_UI_ACTION_CONTEXTMENU:
1911 {
1912 1 Widget selected = gate_ui_treeview_get_selected_node_widget(trvw);
1913
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (selected != NULL)
1914 {
1915 XmPushButtonCallbackStruct event_data;
1916 XEvent evt;
1917 XKeyEvent* kev;
1918 1 gate_mem_clear(&event_data, sizeof(event_data));
1919 1 gate_mem_clear(&evt, sizeof(evt));
1920 1 event_data.click_count = 1;
1921 1 event_data.reason = 10;
1922 1 event_data.event = &evt;
1923 1 kev = &event_data.event->xkey;
1924 1 kev->type = KeyPress;
1925 1 kev->keycode = 65;
1926 1 kev->state = ControlMask;
1927 1 gate_ui_treeview_on_node_widget_click(selected, (XtPointer)trvw, &event_data);
1928 }
1929 1 return GATE_RESULT_OK;
1930 }
1931 }
1932 return GATE_RESULT_NOTSUPPORTED;
1933 }
1934
1935
1936 #endif /* GATE_UI_MOTIF */
1937