GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/treeviews.c
Date: 2026-09-21 06:26:40
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 WINAPI 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 WINAPI 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 WINAPI 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 WINAPI gate_ui_treeview_events(ui_hwnd_t hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult)
288 {
289 if ((ctrl) && (hwnd))
290 {
291 gate_ui_treeview_t* const trvw = (gate_ui_treeview_t*)ctrl;
292 const HWND hwndCtrl = (HWND)GATE_UI_WINAPI_GET_HWND(ctrl);
293
294 if (hwndCtrl != HWND_NULL)
295 {
296 switch (msg)
297 {
298 case WM_ERASEBKGND:
299 {
300 HDC hdc = (HDC)wParam;
301 RECT rect;
302 BOOL succeeded = TRUE;
303 gate_ui_treeview_update_colors(ctrl);
304 #if !defined(GATE_SYS_WIN16)
305 succeeded =
306 #endif
307 GetClientRect(hwndCtrl, &rect);
308 if (succeeded)
309 {
310 HBRUSH hbrush = CreateSolidBrush(gate_ui_treeview_get_bk_color(ctrl));
311 if (hbrush)
312 {
313 FillRect(hdc, &rect, hbrush);
314 DeleteObject((HGDIOBJ)hbrush);
315 }
316 }
317 *lresult = 1;
318 return true;
319 }
320 case WM_LBUTTONDBLCLK:
321 {
322 HTREEITEM hItem;
323 TV_HITTESTINFO hti;
324 hti.flags = TVHT_ONITEM;
325 hti.hItem = NULL;
326 hti.pt.x = (LONG)LOWORD(lParam);
327 hti.pt.y = (LONG)HIWORD(lParam);
328 hItem = TreeView_HitTest(hwndCtrl, &hti);
329 if (hItem != NULL)
330 {
331 if (trvw->on_dblclick != NULL)
332 {
333 trvw->on_dblclick(&trvw->ctrl, (gate_ui_treeview_item_t)hItem);
334 }
335 }
336 *lresult = 0;
337 return true;
338 }
339 case WM_RBUTTONDOWN:
340 {
341 HTREEITEM hItem;
342 TV_HITTESTINFO hti;
343 hti.flags = TVHT_ONITEM;
344 hti.hItem = NULL;
345 hti.pt.x = (LONG)LOWORD(lParam);
346 hti.pt.y = (LONG)HIWORD(lParam);
347 hItem = TreeView_HitTest(hwndCtrl, &hti);
348 if (hItem != NULL)
349 {
350 if (trvw->on_contextmenu != NULL)
351 {
352 TreeView_SelectDropTarget(hwndCtrl, hItem);
353 trvw->on_contextmenu(&trvw->ctrl, (gate_ui_treeview_item_t)hItem);
354 TreeView_SelectDropTarget(hwndCtrl, NULL);
355 }
356 }
357 *lresult = 0;
358 return true;
359 }
360 case WM_NOTIFY:
361 {
362 NMHDR* nmhdr = (NMHDR*)lParam;
363 if (nmhdr->hwndFrom == hwndCtrl)
364 {
365 switch (nmhdr->code)
366 {
367 case TVN_SELCHANGED:
368 {
369 NMTREEVIEW* nmtv = (NMTREEVIEW*)nmhdr;
370 trvw->on_select(&trvw->ctrl, (gate_ui_treeview_item_t)nmtv->itemNew.hItem);
371 *lresult = 0;
372 return true;
373 }
374 }
375 }
376 break;
377 }
378 default:
379 {
380 break;
381 }
382 }
383 }
384 }
385 return false;
386 }
387
388 gate_result_t gate_ui_treeview_create(
389 gate_ui_treeview_t* trvw, gate_ui_ctrl_t* parent,
390 gate_ui_position_t const* position,
391 gate_uint32_t flags,
392 void* userparam
393 )
394 {
395 gate_result_t ret;
396
397 do
398 {
399 gate_uint32_t styles = WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS;
400 gate_uint32_t exstyles = 0;
401 ui_hwnd_t hwndParent;
402 gate_ui_host_t* host = gate_ui_ctrl_get_host(parent);
403
404 if (host == NULL)
405 {
406 ret = GATE_RESULT_INVALIDSTATE;
407 break;
408 }
409 hwndParent = GATE_UI_WINAPI_GET_HWND(parent);
410 if (hwndParent == UI_HWND_NULL)
411 {
412 ret = GATE_RESULT_INVALIDSTATE;
413 break;
414 }
415
416 gate_mem_clear(trvw, sizeof(gate_ui_treeview_t));
417
418 #if !defined(GATE_SYS_WIN16)
419 exstyles |= WS_EX_CLIENTEDGE;
420 #endif
421
422 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
423 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
424
425 ret = gate_ui_winapi_create(&trvw->ctrl, host, hwndParent, WC_TREEVIEW, position, styles, exstyles, NULL, userparam, true);
426 if (GATE_SUCCEEDED(ret))
427 {
428 ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
429
430 #if !defined(GATE_SYS_WIN16)
431 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_TREEVIEW_ICONS))
432 {
433 ret = gate_ui_iconlist_create(&trvw->icons, host, 16, 16);
434 if (GATE_FAILED(ret))
435 {
436 gate_ui_winapi_destroy(&trvw->ctrl);
437 break;
438 }
439 TreeView_SetImageList((HWND)hwnd, (HIMAGELIST)trvw->icons.resources[0], TVSIL_NORMAL);
440 }
441 #endif
442 gate_ui_winapi_register_event(host, hwndParent, WM_NOTIFY, &gate_ui_treeview_events, &trvw->ctrl);
443 gate_ui_winapi_register_event(host, hwnd, WM_RBUTTONDOWN, &gate_ui_treeview_events, &trvw->ctrl);
444 gate_ui_winapi_register_event(host, hwnd, WM_LBUTTONDBLCLK, &gate_ui_treeview_events, &trvw->ctrl);
445 gate_ui_winapi_register_event(host, hwnd, WM_ERASEBKGND, &gate_ui_treeview_events, &trvw->ctrl);
446
447 gate_ui_treeview_update_colors(&trvw->ctrl);
448 gate_ui_winapi_refresh(&trvw->ctrl);
449 }
450 } while (0);
451
452 return ret;
453 }
454
455 gate_result_t gate_ui_treeview_add_icon(gate_ui_treeview_t* trvw, gate_ui_icon_t const* icon, gate_intptr_t* icon_key)
456 {
457 return gate_ui_iconlist_add_icon(&trvw->icons, icon, icon_key);
458 }
459
460 gate_result_t gate_ui_treeview_add_icon_image(gate_ui_treeview_t* trvw, gate_rasterimage_t const* image, gate_intptr_t* icon_key)
461 {
462 return gate_ui_iconlist_add_image(&trvw->icons, image, icon_key);
463 }
464
465 gate_result_t gate_ui_treeview_add(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t const* parent, gate_string_t const* text,
466 gate_intptr_t iconkey, void* itemparam, gate_ui_treeview_item_t* newitem)
467 {
468 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
469 TVINSERTSTRUCT insert;
470 HTREEITEM newtreeitem;
471 TCHAR txtbuffer[4096];
472 gate_size_t txtbufferused = gate_win32_utf8_2_winstr(text->str, text->length, txtbuffer, sizeof(txtbuffer) / sizeof(txtbuffer[0]));
473 gate_mem_clear(&insert, sizeof(insert));
474 insert.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_STATE;
475 insert.item.pszText = &txtbuffer[0];
476 insert.item.cchTextMax = (int)txtbufferused;
477 insert.item.stateMask = TVIS_SELECTED;
478 insert.item.lParam = (LPARAM)(gate_intptr_t)itemparam;
479 if (parent == NULL)
480 {
481 insert.hParent = NULL;
482 insert.hInsertAfter = TVI_ROOT;
483 }
484 else
485 {
486 insert.hParent = (HTREEITEM)*parent;
487 insert.hInsertAfter = TVI_LAST;
488 }
489 if (trvw->icons.resources[0] != NULL)
490 {
491 if (iconkey != GATE_UI_TREEVIEW_INVALID_ICON)
492 {
493 insert.item.iImage = (int)iconkey;
494 insert.item.iSelectedImage = (int)iconkey;
495 insert.item.mask |= (TVIF_IMAGE | TVIF_SELECTEDIMAGE);
496 }
497 }
498
499 newtreeitem = TreeView_InsertItem(hwnd, &insert);
500 if (newtreeitem)
501 {
502 *newitem = (gate_ui_treeview_item_t)newtreeitem;
503 return GATE_RESULT_OK;
504 }
505 else
506 {
507 return GATE_RESULT_FAILED;
508 }
509 }
510
511 gate_result_t gate_ui_treeview_remove(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
512 {
513 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
514 if (TreeView_DeleteItem(hwnd, (HTREEITEM)item))
515 {
516 return GATE_RESULT_OK;
517 }
518 else
519 {
520 return GATE_RESULT_FAILED;
521 }
522 }
523
524 gate_result_t gate_ui_treeview_clear(gate_ui_treeview_t* trvw)
525 {
526 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
527 if (TreeView_DeleteAllItems(hwnd))
528 {
529 return GATE_RESULT_OK;
530 }
531 else
532 {
533 return GATE_RESULT_FAILED;
534 }
535 }
536
537 void* gate_ui_treeview_get_itemparam(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
538 {
539 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
540 TVITEM tvitem;
541 gate_mem_clear(&tvitem, sizeof(tvitem));
542 tvitem.hItem = (HTREEITEM)item;
543 tvitem.mask = TVIF_PARAM;
544 if (TreeView_GetItem(hwnd, &tvitem))
545 {
546 return (void*)(gate_intptr_t)tvitem.lParam;
547 }
548 return NULL;
549 }
550
551
552 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)
553 {
554 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
555 HTREEITEM parentItem = TreeView_GetParent(hwnd, (HTREEITEM)item);
556 if (parentItem == NULL)
557 {
558 return GATE_RESULT_NOTAVAILABLE;
559 }
560 else
561 {
562 *parent = (gate_ui_treeview_item_t)parentItem;
563 return GATE_RESULT_OK;
564 }
565 }
566 gate_result_t gate_ui_treeview_get_children(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_array_t* children)
567 {
568 gate_result_t ret;
569 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
570 HTREEITEM child = TreeView_GetChild(hwnd, (HTREEITEM)item);
571 TVITEM itemdata;
572 gate_arraylist_t itemlist;
573 gate_size_t prealloc = 0;
574 gate_ui_treeview_item_t nextitem;
575 if (child != NULL)
576 {
577 gate_mem_clear(&itemdata, sizeof(itemdata));
578 itemdata.hItem = (HTREEITEM)item;
579 itemdata.mask = TVIF_CHILDREN;
580 if (TreeView_GetItem(hwnd, &itemdata))
581 {
582 prealloc = itemdata.cChildren;
583 }
584 }
585 itemlist = gate_arraylist_create(sizeof(gate_ui_treeview_item_t), NULL, prealloc, NULL, NULL);
586 if (!itemlist)
587 {
588 ret = GATE_RESULT_OUTOFMEMORY;
589 }
590 else
591 {
592 ret = GATE_RESULT_OK;
593 while (child != NULL)
594 {
595 nextitem = (gate_ui_treeview_item_t)child;
596 if (NULL == gate_arraylist_add(itemlist, &nextitem))
597 {
598 ret = GATE_RESULT_OUTOFMEMORY;
599 break;
600 }
601 child = TreeView_GetNextItem(hwnd, child, TVGN_NEXT);
602 }
603 if (GATE_SUCCEEDED(ret))
604 {
605 if (NULL == gate_array_create(children, itemlist))
606 {
607 ret = GATE_RESULT_FAILED;
608 }
609 }
610 gate_arraylist_release(itemlist);
611 }
612 return ret;
613 }
614 gate_result_t gate_ui_treeview_get_text(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_string_t* text)
615 {
616 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
617 TCHAR buffer[4096];
618 TVITEM tvitem;
619 gate_mem_clear(&tvitem, sizeof(tvitem));
620 tvitem.hItem = (HTREEITEM)item;
621 tvitem.mask = TVIF_TEXT;
622 tvitem.pszText = &buffer[0];
623 tvitem.cchTextMax = sizeof(buffer) / sizeof(buffer[0]);
624 if (TreeView_GetItem(hwnd, &tvitem))
625 {
626 if (NULL != gate_win32_winstr_2_utf8_string(buffer, tvitem.cchTextMax, text))
627 {
628 return GATE_RESULT_OK;
629 }
630 }
631 return GATE_RESULT_FAILED;
632 }
633 gate_result_t gate_ui_treeview_set_text(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_string_t const* text)
634 {
635 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
636 TCHAR buffer[4096];
637 TVITEM tvitem;
638 gate_mem_clear(&tvitem, sizeof(tvitem));
639 tvitem.hItem = (HTREEITEM)item;
640 tvitem.mask = TVIF_TEXT;
641 tvitem.pszText = &buffer[0];
642 tvitem.cchTextMax = (int)gate_win32_utf8_2_winstr(text->str, text->length, buffer, sizeof(buffer) / sizeof(buffer[0]));
643 if (TreeView_SetItem(hwnd, &tvitem))
644 {
645 return GATE_RESULT_OK;
646 }
647 return GATE_RESULT_FAILED;
648 }
649
650 gate_bool_t gate_ui_treeview_is_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
651 {
652 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
653 TVITEM tvitem;
654 gate_mem_clear(&tvitem, sizeof(tvitem));
655 tvitem.hItem = (HTREEITEM)item;
656 tvitem.mask = TVIF_STATE;
657 tvitem.stateMask = TVIS_EXPANDED;
658 tvitem.state = 0;
659 if (TreeView_GetItem(hwnd, &tvitem))
660 {
661 return (tvitem.state & TVIS_EXPANDED) == TVIS_EXPANDED;
662 }
663 return false;
664 }
665 gate_result_t gate_ui_treeview_set_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_bool_t expanded)
666 {
667 if (gate_ui_treeview_is_expanded(trvw, item) != expanded)
668 {
669 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
670 if (TreeView_Expand(hwnd, (HTREEITEM)item, expanded ? TVE_EXPAND : TVE_COLLAPSE))
671 {
672 return GATE_RESULT_OK;
673 }
674 else
675 {
676 return GATE_RESULT_FAILED;
677 }
678 }
679 return GATE_RESULT_OK;
680 }
681
682 gate_result_t gate_ui_treeview_get_selected_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t* item)
683 {
684 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
685 HTREEITEM hitem = TreeView_GetSelection(hwnd);
686 if (hitem != NULL)
687 {
688 *item = (gate_ui_treeview_item_t)hitem;
689 return GATE_RESULT_OK;
690 }
691 else
692 {
693 return GATE_RESULT_NOMATCH;
694 }
695 }
696
697 gate_result_t gate_ui_treeview_select_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
698 {
699 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
700 if (TreeView_SelectItem(hwnd, (HTREEITEM)item))
701 {
702 return GATE_RESULT_OK;
703 }
704 else
705 {
706 return GATE_RESULT_FAILED;
707 }
708 }
709
710 gate_result_t gate_ui_treeview_perform_action(gate_ui_treeview_t* trvw, gate_enumint_t action)
711 {
712 gate_result_t result;
713 gate_ui_treeview_item_t tvitem;
714 const ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&trvw->ctrl);
715
716 switch (action)
717 {
718 case GATE_UI_ACTION_ACTIVATE:
719 {
720 result = gate_ui_treeview_get_selected_item(trvw, &tvitem);
721 if (GATE_SUCCEEDED(result))
722 {
723 const HTREEITEM hitem = (HTREEITEM)tvitem;
724 NMTREEVIEW nmtv;
725 gate_intptr_t lresult = 0;
726 gate_mem_clear(&nmtv, sizeof(nmtv));
727 nmtv.hdr.hwndFrom = (HWND)hwnd;
728 nmtv.hdr.code = TVN_SELCHANGED;
729 nmtv.hdr.idFrom = (UINT_PTR)hwnd;
730 nmtv.itemNew.hItem = hitem;
731 gate_ui_treeview_events(hwnd, &trvw->ctrl, WM_NOTIFY, (gate_intptr_t)hwnd, (gate_intptr_t)(void*)&nmtv, &lresult);
732 }
733 return GATE_RESULT_OK;
734 }
735 case GATE_UI_ACTION_CONTEXTMENU:
736 {
737 result = gate_ui_treeview_get_selected_item(trvw, &tvitem);
738 if (GATE_SUCCEEDED(result))
739 {
740 HTREEITEM hitem = (HTREEITEM)tvitem;
741 RECT rc;
742 SHORT x, y;
743 LPARAM lparam;
744 gate_intptr_t lresult = 0;
745
746 TreeView_GetItemRect((HWND)hwnd, hitem, &rc, TRUE);
747 x = (SHORT)((rc.left + rc.right) / 2);
748 y = (SHORT)((rc.top + rc.bottom) / 2);
749 lparam = (LPARAM)((DWORD)(WORD)x | ((DWORD)(WORD)y << 16));
750 gate_ui_treeview_events(hwnd, &trvw->ctrl, WM_RBUTTONDOWN, MK_RBUTTON, lparam, &lresult);
751 }
752 return GATE_RESULT_OK;
753 }
754 }
755
756 return GATE_RESULT_NOTSUPPORTED;
757 }
758
759 #endif /*GATE_UI_WINAPI*/
760
761
762
763 #if defined(GATE_UI_GTK)
764
765 #include "gate/ui/gateui_gtk.h"
766
767 #define GATE_UI_GTK_TREEVIEW_FIELD_TEXT 0
768 #define GATE_UI_GTK_TREEVIEW_FIELD_ID 1
769 #define GATE_UI_GTK_TREEVIEW_FIELD_PARAM 2
770 #define GATE_UI_GTK_TREEVIEW_FIELD_ICON 3
771
772 static void gate_ui_gtk_treeview_on_cursor_changed(GtkTreeView* tree_view, gpointer user_data)
773 {
774 gate_ui_treeview_t* trvw = (gate_ui_treeview_t*)user_data;
775 gate_ui_treeview_item_t item;
776 gate_result_t result;
777 result = gate_ui_treeview_get_selected_item(trvw, &item);
778 if (GATE_SUCCEEDED(result))
779 {
780 trvw->on_select(&trvw->ctrl, item);
781 }
782 else
783 {
784 trvw->on_select(&trvw->ctrl, GATE_UI_TREEVIEW_INVALID_ITEM);
785 }
786 }
787
788 static void gate_ui_gtk_treeview_on_destroy(GtkWidget* object, gpointer user_data)
789 {
790 gate_ui_treeview_t* trvw = (gate_ui_treeview_t*)user_data;
791 gate_ui_iconlist_destroy(&trvw->icons);
792 }
793
794 gate_result_t gate_ui_treeview_create(gate_ui_treeview_t* trvw, gate_ui_ctrl_t* parent,
795 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
796 {
797 gate_result_t ret = GATE_RESULT_FAILED;
798
799 do
800 {
801 GtkWidget* widget;
802 GtkTreeViewColumn* col;
803 GtkCellRenderer* renderer;
804 GtkTreeModel* model;
805 /*GtkTreeStore* treestore;*/
806 GtkWidget* scroll_widget;
807 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
808
809 gate_mem_clear(trvw, sizeof(gate_ui_treeview_t));
810 widget = gtk_tree_view_new();
811 if (widget == NULL)
812 {
813 ret = GATE_RESULT_OUTOFRESOURCES;
814 break;
815 }
816
817 col = gtk_tree_view_column_new();
818 gtk_tree_view_column_set_title(col, "Tree view");
819
820 renderer = gtk_cell_renderer_pixbuf_new();
821 gtk_tree_view_column_pack_start(col, renderer, FALSE);
822 gtk_tree_view_column_add_attribute(col, renderer, "pixbuf", GATE_UI_GTK_TREEVIEW_FIELD_ICON);
823 renderer = gtk_cell_renderer_text_new();
824 gtk_tree_view_column_pack_start(col, renderer, FALSE);
825 gtk_tree_view_column_add_attribute(col, renderer, "text", GATE_UI_GTK_TREEVIEW_FIELD_TEXT);
826
827 model = GTK_TREE_MODEL(gtk_tree_store_new(4,
828 G_TYPE_STRING, /* text */
829 G_TYPE_POINTER, /* item-id */
830 G_TYPE_POINTER, /* item-param */
831 GDK_TYPE_PIXBUF, /* icon */
832 -1));
833
834 gtk_tree_view_set_model(GTK_TREE_VIEW(widget), model);
835 g_object_unref(model);
836
837 gtk_tree_view_append_column(GTK_TREE_VIEW(widget), col);
838
839 scroll_widget = gtk_scrolled_window_new(NULL, NULL);
840 if (scroll_widget == NULL)
841 {
842 gtk_widget_destroy(widget);
843 ret = GATE_RESULT_OUTOFRESOURCES;
844 break;
845 }
846
847 gtk_container_add(GTK_CONTAINER(scroll_widget), widget);
848 gtk_widget_show(widget);
849
850 ret = gate_ui_gtk_ctrl_init(&trvw->ctrl, scroll_widget, host, userparam, parent,
851 NULL, false, false, position, &flags);
852
853 if (GATE_SUCCEEDED(ret))
854 {
855 ret = gate_ui_iconlist_create(&trvw->icons, host, 16, 16);
856 if (GATE_FAILED(ret))
857 {
858 gate_ui_gtk_ctrl_destroy(&trvw->ctrl);
859 break;
860 }
861
862 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(widget), FALSE);
863 gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(widget), TRUE);
864
865 g_signal_connect(G_OBJECT(widget), "cursor-changed", G_CALLBACK(gate_ui_gtk_treeview_on_cursor_changed), (gpointer)trvw);
866 g_signal_connect(G_OBJECT(widget), "destroy", G_CALLBACK(gate_ui_gtk_treeview_on_destroy), (gpointer)trvw);
867 }
868 //cursor-changed
869 } while (0);
870
871 return ret;
872 }
873
874 gate_result_t gate_ui_treeview_add_icon(gate_ui_treeview_t* trvw, gate_ui_icon_t const* icon, gate_intptr_t* icon_key)
875 {
876 return gate_ui_iconlist_add_icon(&trvw->icons, icon, icon_key);
877 }
878
879 gate_result_t gate_ui_treeview_add_icon_image(gate_ui_treeview_t* trvw, gate_rasterimage_t const* image, gate_intptr_t* icon_key)
880 {
881 return gate_ui_iconlist_add_image(&trvw->icons, image, icon_key);
882 }
883
884 static gate_atomic_int64_t gate_ui_treeview_item_id = 0;
885
886 static gate_bool_t gate_ui_treeview_resolve(GtkTreeModel* model, GtkTreeIter* current_iter, void* id, GtkTreeIter* found_iter)
887 {
888 GtkTreeIter first;
889
890 if (current_iter == NULL)
891 {
892 if (!gtk_tree_model_get_iter_first(model, &first))
893 {
894 return false;
895 }
896 current_iter = &first;
897 }
898 do
899 {
900 GtkTreeIter first_child;
901 GValue value = GATE_INIT_EMPTY;
902 gtk_tree_model_get_value(model, current_iter, 1, &value);
903 if (g_value_get_pointer(&value) == id)
904 {
905 *found_iter = *current_iter;
906 return true;
907 }
908 g_value_unset(&value);
909
910 if (gtk_tree_model_iter_children(model, &first_child, current_iter))
911 {
912 if (gate_ui_treeview_resolve(model, &first_child, id, found_iter))
913 {
914 return true;
915 }
916 }
917 } while (gtk_tree_model_iter_next(model, current_iter));
918 return false;
919 }
920
921 gate_result_t gate_ui_treeview_add(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t const* parent, gate_string_t const* text,
922 gate_intptr_t icon_key, void* itemparam, gate_ui_treeview_item_t* newitem)
923 {
924 gate_result_t ret = GATE_RESULT_FAILED;
925
926 do
927 {
928 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
929 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
930 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
931 GtkTreeStore* store = GTK_TREE_STORE(model);
932 GtkTreeIter tree_iter;
933 GtkTreeIter parent_iter;
934 gate_ui_treeview_item_t new_item_id = (gate_uintptr_t)gate_atomic_int64_inc(&gate_ui_treeview_item_id);
935 char textbuffer[4096];
936
937 GATE_STRING_TO_BUFFER(text, textbuffer);
938 if (parent != NULL)
939 {
940 if (!gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)*parent, &parent_iter))
941 {
942 ret = GATE_RESULT_NOMATCH;
943 break;
944 }
945 }
946
947 gtk_tree_store_append(store, &tree_iter, parent ? &parent_iter : NULL);
948 gtk_tree_store_set(store, &tree_iter,
949 GATE_UI_GTK_TREEVIEW_FIELD_TEXT, textbuffer,
950 GATE_UI_GTK_TREEVIEW_FIELD_ID, (void*)new_item_id,
951 GATE_UI_GTK_TREEVIEW_FIELD_PARAM, itemparam,
952 -1);
953
954 if (trvw->icons.resources[0] && (icon_key != GATE_UI_TREEVIEW_INVALID_ICON))
955 {
956 gate_ui_icon_t const* ptr_icon = gate_arraylist_get((gate_arraylist_t)trvw->icons.resources[0], (gate_size_t)icon_key);
957 if (ptr_icon)
958 {
959 void* ptr_pixbuf = ptr_icon->resources[0];
960 if (ptr_pixbuf)
961 {
962 gtk_tree_store_set(store, &tree_iter, GATE_UI_GTK_TREEVIEW_FIELD_ICON, ptr_pixbuf, -1);
963 }
964 }
965 }
966
967 if (newitem != NULL)
968 {
969 *newitem = new_item_id;
970 }
971 ret = GATE_RESULT_OK;
972
973 } while (0);
974 return ret;
975 }
976 void* gate_ui_treeview_get_itemparam(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
977 {
978 void* ret = NULL;
979 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
980 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
981 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
982 GtkTreeIter iter_found;
983
984 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &iter_found))
985 {
986 GValue value = GATE_INIT_EMPTY;
987 gtk_tree_model_get_value(model, &iter_found, 2, &value);
988 ret = g_value_get_pointer(&value);
989 g_value_unset(&value);
990 }
991
992 /* error / unresolved case */
993 return ret;
994 }
995
996 static void gate_ui_treeview_remove_recursive(GtkTreeModel* model, GtkTreeIter* current_iter)
997 {
998 GtkTreeIter item;
999 if (gtk_tree_model_iter_children(model, &item, current_iter))
1000 {
1001 do
1002 {
1003 gate_ui_treeview_remove_recursive(model, &item);
1004 } while (gtk_tree_model_iter_next(model, &item));
1005 }
1006
1007 item = *current_iter;
1008 gtk_tree_store_remove(GTK_TREE_STORE(model), &item);
1009 }
1010
1011 gate_result_t gate_ui_treeview_remove(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1012 {
1013 gate_result_t ret = GATE_RESULT_FAILED;
1014 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1015 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1016 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1017 GtkTreeIter iter_found;
1018 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &iter_found))
1019 {
1020 gate_ui_treeview_remove_recursive(model, &iter_found);
1021 ret = GATE_RESULT_OK;
1022 }
1023 else
1024 {
1025 ret = GATE_RESULT_NOMATCH;
1026 }
1027 return ret;
1028 }
1029 gate_result_t gate_ui_treeview_clear(gate_ui_treeview_t* trvw)
1030 {
1031 gate_result_t ret = GATE_RESULT_OK;
1032 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1033 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1034 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1035 gtk_tree_store_clear(GTK_TREE_STORE(model));
1036 return ret;
1037 }
1038 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)
1039 {
1040 gate_result_t ret = GATE_RESULT_NOMATCH;
1041 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1042 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1043 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1044 GtkTreeIter found_iter;
1045 GtkTreeIter parent_iter;
1046 GValue value = GATE_INIT_EMPTY;
1047 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1048 {
1049 if (gtk_tree_model_iter_parent(model, &parent_iter, &found_iter))
1050 {
1051 gtk_tree_model_get_value(model, &parent_iter, 1, &value);
1052 if (parent != NULL)
1053 {
1054 *parent = (gate_ui_treeview_item_t)(gate_uintptr_t)g_value_get_pointer(&value);
1055 }
1056 g_value_unset(&value);
1057 ret = GATE_RESULT_OK;
1058 }
1059 }
1060 return ret;
1061 }
1062 gate_result_t gate_ui_treeview_get_children(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_array_t* children)
1063 {
1064 gate_result_t ret = GATE_RESULT_FAILED;
1065 gate_arraylist_t arraylist = NULL;
1066 do
1067 {
1068 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1069 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1070 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1071 GtkTreeIter found_iter;
1072 GtkTreeIter child_iter;
1073 GValue value = GATE_INIT_EMPTY;
1074
1075 arraylist = gate_arraylist_create(sizeof(gate_ui_treeview_item_t), NULL, 0, NULL, NULL);
1076 if (arraylist == NULL)
1077 {
1078 ret = GATE_RESULT_OUTOFMEMORY;
1079 break;
1080 }
1081
1082 if (item == 0)
1083 {
1084 if(!gtk_tree_model_get_iter_first(model, &found_iter))
1085 {
1086 ret = GATE_RESULT_NOMATCH;
1087 break;
1088 }
1089 do
1090 {
1091 gate_ui_treeview_item_t child_item;
1092 gtk_tree_model_get_value(model, &found_iter, 1, &value);
1093 child_item = (gate_ui_treeview_item_t)g_value_get_pointer(&value);
1094 g_value_unset(&value);
1095 gate_arraylist_add(arraylist, &child_item);
1096
1097 } while (gtk_tree_model_iter_next(model, &found_iter));
1098 }
1099 else
1100 {
1101 if (!gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1102 {
1103 ret = GATE_RESULT_NOMATCH;
1104 break;
1105 }
1106
1107 if (gtk_tree_model_iter_children(model, &child_iter, &found_iter))
1108 {
1109 do
1110 {
1111 void* ptr_value = NULL;
1112 gtk_tree_model_get_value(model, &child_iter, 1, &value);
1113 ptr_value = g_value_get_pointer(&value);
1114 gate_arraylist_add(arraylist, (void const*)&ptr_value);
1115 g_value_unset(&value);
1116 } while (gtk_tree_model_iter_next(model, &child_iter));
1117 }
1118 }
1119
1120 if (NULL != gate_array_create(children, arraylist))
1121 {
1122 ret = GATE_RESULT_OK;
1123 }
1124 } while (0);
1125 if (arraylist != NULL)
1126 {
1127 gate_arraylist_release(arraylist);
1128 }
1129 return ret;
1130 }
1131 gate_result_t gate_ui_treeview_get_text(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_string_t* text)
1132 {
1133 gate_result_t ret = GATE_RESULT_NOMATCH;
1134 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1135 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1136 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1137 GtkTreeIter found_iter;
1138 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1139 {
1140 GValue value = GATE_INIT_EMPTY;
1141 char const* text_buffer = NULL;
1142 gtk_tree_model_get_value(model, &found_iter, 0, &value);
1143 text_buffer = g_value_get_string(&value);
1144 if (NULL != gate_string_create(text, text_buffer, gate_str_length(text_buffer)))
1145 {
1146 ret = GATE_RESULT_OK;
1147 }
1148 g_value_unset(&value);
1149 }
1150 return ret;
1151 }
1152 gate_result_t gate_ui_treeview_set_text(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_string_t const* text)
1153 {
1154 gate_result_t ret = GATE_RESULT_NOMATCH;
1155 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1156 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1157 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1158 GtkTreeIter found_iter;
1159 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1160 {
1161 GValue value = GATE_INIT_EMPTY;
1162 gchar text_buffer[4096];
1163 GATE_STRING_TO_BUFFER(text, text_buffer);
1164 g_value_init(&value, G_TYPE_STRING);
1165 g_value_set_string(&value, text_buffer);
1166 gtk_tree_store_set_value(GTK_TREE_STORE(model), &found_iter, 0, &value);
1167 g_value_unset(&value);
1168 ret = GATE_RESULT_OK;
1169 }
1170 return ret;
1171 }
1172 gate_bool_t gate_ui_treeview_is_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1173 {
1174 gate_result_t ret = false;
1175 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1176 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1177 GtkTreeView* treeview = GTK_TREE_VIEW(widget);
1178 GtkTreeModel* model = gtk_tree_view_get_model(treeview);
1179 GtkTreeIter found_iter;
1180
1181 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1182 {
1183 GtkTreePath* path = gtk_tree_model_get_path(model, &found_iter);
1184 ret = gtk_tree_view_row_expanded(treeview, path);
1185 gtk_tree_path_free(path);
1186 }
1187 return ret;
1188 }
1189 gate_result_t gate_ui_treeview_set_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_bool_t expanded)
1190 {
1191 gate_result_t ret = GATE_RESULT_NOMATCH;
1192 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1193 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1194 GtkTreeView* treeview = GTK_TREE_VIEW(widget);
1195 GtkTreeModel* model = gtk_tree_view_get_model(treeview);
1196 GtkTreeIter found_iter;
1197
1198 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1199 {
1200 GtkTreePath* path = gtk_tree_model_get_path(model, &found_iter);
1201 if (expanded)
1202 {
1203 //gtk_tree_view_expand_all(treeview);
1204 //gtk_tree_view_expand_to_path(treeview, path);
1205 gtk_tree_view_expand_row(treeview, path, FALSE);
1206 }
1207 else
1208 {
1209 gtk_tree_view_collapse_row(treeview, path);
1210 }
1211 gtk_tree_path_free(path);
1212 ret = GATE_RESULT_OK;
1213 }
1214 return ret;
1215 }
1216 gate_result_t gate_ui_treeview_get_selected_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t* item)
1217 {
1218 gate_result_t ret = GATE_RESULT_FAILED;
1219 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1220 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1221 GtkTreeView* treeview = GTK_TREE_VIEW(widget);
1222 GtkTreeModel* model = gtk_tree_view_get_model(treeview);
1223 GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
1224 GtkTreeIter found_iter;
1225
1226 if (gtk_tree_selection_get_selected(selection, &model, &found_iter))
1227 {
1228 GValue value = GATE_INIT_EMPTY;
1229 gtk_tree_model_get_value(model, &found_iter, 1, &value);
1230 *item = (gate_ui_treeview_item_t)(gate_uintptr_t)g_value_get_pointer(&value);
1231 g_value_unset(&value);
1232 ret = GATE_RESULT_OK;
1233 }
1234 else
1235 {
1236 *item = GATE_UI_TREEVIEW_INVALID_ITEM;
1237 ret = GATE_RESULT_NOMATCH;
1238 }
1239 return ret;
1240 }
1241 gate_result_t gate_ui_treeview_select_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1242 {
1243 gate_result_t ret = GATE_RESULT_FAILED;
1244 GtkWidget* scroll_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&trvw->ctrl);
1245 GtkWidget* widget = gtk_bin_get_child(GTK_BIN(scroll_widget));
1246 GtkTreeView* treeview = GTK_TREE_VIEW(widget);
1247 GtkTreeModel* model = gtk_tree_view_get_model(treeview);
1248 GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
1249 GtkTreeIter found_iter;
1250 if (gate_ui_treeview_resolve(model, NULL, (void*)(gate_uintptr_t)item, &found_iter))
1251 {
1252 GtkTreePath* path = gtk_tree_model_get_path(model, &found_iter);
1253 gtk_tree_selection_select_iter(selection, &found_iter);
1254 gtk_tree_path_free(path);
1255 if (trvw->on_select)
1256 {
1257 trvw->on_select(&trvw->ctrl, item);
1258 }
1259 ret = GATE_RESULT_OK;
1260 }
1261
1262 return ret;
1263 }
1264
1265 gate_result_t gate_ui_treeview_perform_action(gate_ui_treeview_t* trvw, gate_enumint_t action)
1266 {
1267 switch (action)
1268 {
1269 case GATE_UI_ACTION_ACTIVATE:
1270 {
1271 /* TODO */
1272 return GATE_RESULT_OK;
1273 }
1274 case GATE_UI_ACTION_CONTEXTMENU:
1275 {
1276 /* TODO */
1277 return GATE_RESULT_OK;
1278 }
1279 }
1280 return GATE_RESULT_NOTSUPPORTED;
1281 }
1282
1283 #endif /* GATE_UI_GTK */
1284
1285
1286
1287 #if defined(GATE_UI_MOTIF)
1288
1289 #include "gate/ui/gateui_motif.h"
1290 #include <Xm/List.h>
1291 #include <Xm/Tree.h>
1292 #include <Xm/Hierarchy.h>
1293 #include <Xm/Label.h>
1294 #include <Xm/PushB.h>
1295 #include <Xm/Outline.h>
1296 #include <Xm/ScrolledW.h>
1297 #include <Xm/ToggleB.h>
1298 #include <Xm/Manager.h>
1299
1300 4 static void motif_treeview_remove_node_widget(Widget node)
1301 {
1302 4 XtUnmanageChild(node);
1303 4 XtDestroyWidget(node);
1304 4 }
1305
1306 4 static void motif_treeview_remove_nodes_recursive(Widget node)
1307 {
1308 4 WidgetList wlist = XmHierarchyGetChildNodes(node);
1309
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (wlist)
1310 {
1311 gate_size_t ndx;
1312
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (ndx = 0; wlist[ndx]; ++ndx)
1313 {
1314 2 motif_treeview_remove_nodes_recursive(wlist[ndx]);
1315 }
1316 1 XtFree((char*)wlist);
1317 }
1318 4 motif_treeview_remove_node_widget(node);
1319 4 }
1320
1321 1 static gate_result_t motif_treeview_root_elements(gate_ui_treeview_t* tv, gate_array_t* list)
1322 {
1323 1 WidgetList children = NULL;
1324 1 Cardinal num_children = 0;
1325 Widget w;
1326 unsigned ndx;
1327 gate_arraylist_t arr;
1328
1329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(tv != NULL);
1330 1 w = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&tv->ctrl);
1331
1332 1 arr = gate_arraylist_create(sizeof(Widget), NULL, 0, NULL, NULL);
1333
1334 1 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &num_children, NULL, NULL);
1335
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
7 for (ndx = 0; ndx != num_children; ++ndx)
1336 {
1337 6 Widget parent_widget = NULL;
1338 6 Widget child_widget = children[ndx];
1339
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if (!XmIsPushButton(child_widget))
1340 {
1341 3 continue;
1342 }
1343 3 XtVaGetValues(child_widget, XmNparentNode, &parent_widget, NULL, NULL);
1344
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (parent_widget == NULL)
1345 {
1346 1 gate_arraylist_add(arr, &child_widget);
1347 }
1348 }
1349 1 gate_array_create(list, arr);
1350 1 gate_arraylist_release(arr);
1351 1 return GATE_RESULT_OK;
1352 }
1353
1354 1 static gate_result_t motif_treeview_destroy(gate_ui_ctrl_t* ctrl)
1355 {
1356 1 gate_ui_treeview_t* tv = (gate_ui_treeview_t*)ctrl;
1357 gate_array_t arr;
1358 unsigned ndx;
1359 gate_size_t cnt;
1360 Widget w;
1361
1362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(tv != NULL);
1363
1364 1 motif_treeview_root_elements(tv, &arr);
1365 1 cnt = gate_array_length(&arr);
1366
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (ndx = 0; ndx < cnt; ++ndx)
1367 {
1368 1 Widget* ptr_node = (Widget*)gate_array_get(&arr, ndx);
1369
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;
1370 1 motif_treeview_remove_nodes_recursive(*ptr_node);
1371 }
1372 1 gate_array_release(&arr);
1373
1374 1 w = GATE_UI_MOTIF_GET_CTRL_CONTAINER(ctrl);
1375
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (w)
1376 {
1377 1 XtUnmanageChild(w);
1378 1 XtDestroyWidget(w);
1379 }
1380
1381 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
1382
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (w)
1383 {
1384 1 XtUnmanageChild(w);
1385 1 XtDestroyWidget(w);
1386 }
1387
1388 1 gate_mem_clear(ctrl, sizeof(gate_ui_ctrl_t));
1389 1 return GATE_RESULT_OK;
1390 }
1391
1392 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)
1393 {
1394 6 WidgetList children = NULL;
1395 6 Cardinal num_children = 0;
1396 6 Widget w_tree = GATE_UI_MOTIF_GET_CTRL_CONTAINER(ctrl);
1397
1398 6 XtVaGetValues(w_tree, XmNchildren, &children, XmNnumChildren, &num_children, NULL, NULL);
1399
1400
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (ptr_to_widgetlist) *ptr_to_widgetlist = children;
1401
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (ptr_to_children_count) *ptr_to_children_count = num_children;
1402 6 return GATE_RESULT_OK;
1403 }
1404
1405
1406 static gate_ui_motif_dispatcher_t treeview_dispatcher =
1407 {
1408 &motif_treeview_destroy,
1409 NULL,
1410 NULL,
1411 NULL,
1412 NULL,
1413 NULL,
1414 &motif_treeview_get_children
1415 };
1416
1417 1 gate_result_t gate_ui_treeview_create(
1418 gate_ui_treeview_t* trvw, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
1419 gate_uint32_t flags, void* userparam)
1420 {
1421 1 gate_result_t ret = GATE_RESULT_FAILED;
1422 1 Widget w = NULL;
1423 1 Widget w_tree = NULL;
1424 do
1425 {
1426 1 gate_ui_host_t* ptr_host = NULL;
1427 1 Widget parent_widget = NULL;
1428 1 Widget w_scroll1 = NULL;
1429 1 Widget w_scroll2 = NULL;
1430 Arg args[10];
1431 Cardinal args_count;
1432 /* XmNtreeDefaultLineStyle; */
1433
1434
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!trvw || !parent)
1435 {
1436 ret = GATE_RESULT_INVALIDARG;
1437 break;
1438 }
1439
1440 1 parent_widget = GATE_UI_MOTIF_GET_CTRL_CONTAINER(parent);
1441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!parent_widget)
1442 {
1443 parent_widget = GATE_UI_MOTIF_GET_CTRL_WIDGET(parent);
1444 }
1445
1446 1 ptr_host = GATE_UI_MOTIF_GET_CTRL_HOST(parent);
1447
1448 1 args_count = 0;
1449 1 XtSetArg(args[args_count], XmNscrollingPolicy, XmAUTOMATIC); ++args_count;
1450 1 XtSetArg(args[args_count], XmNvisualPolicy, XmVARIABLE); ++args_count;
1451 1 XtSetArg(args[args_count], XmNshowSash, True); ++args_count;
1452 1 XtSetArg(args[args_count], XmNscrollBarDisplayPolicy, XmSTATIC); ++args_count;
1453 //XtSetArg(args[args_count], XmNallowResize, True); ++args_count;
1454 1 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
1455 1 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1456
1457 1 w = XmCreateScrolledWindow(parent_widget, NULL, args, args_count);
1458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w)
1459 {
1460 ret = GATE_RESULT_OUTOFRESOURCES;
1461 break;
1462 }
1463
1464 1 XtVaGetValues(w, XmNhorizontalScrollBar, &w_scroll1, XmNverticalScrollBar, &w_scroll2, NULL);
1465
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (w_scroll1)
1466 {
1467 1 XtVaSetValues(w_scroll1, XmNshadowThickness, 1, NULL);
1468 }
1469
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (w_scroll2)
1470 {
1471 1 XtVaSetValues(w_scroll2, XmNshadowThickness, 1, NULL);
1472 }
1473
1474 1 args_count = 0;
1475 1 XtSetArg(args[args_count], XmNunitType, XmPIXELS); ++args_count;
1476 1 XtSetArg(args[args_count], XmNconnectNodes, True); ++args_count;
1477 1 XtSetArg(args[args_count], XmNindentSpace, 24); ++args_count;
1478 1 XtSetArg(args[args_count], XmNshadowThickness, 0); ++args_count;
1479 1 XtSetArg(args[args_count], XmNhighlightThickness, 0); ++args_count;
1480 1 XtSetArg(args[args_count], XmNhorizontalMargin, 1); ++args_count;
1481 1 XtSetArg(args[args_count], XmNverticalMargin, 1); ++args_count;
1482
1483 1 w_tree = XmCreateOutline(w, NULL, args, args_count);
1484
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w_tree)
1485 {
1486 ret = GATE_RESULT_OUTOFRESOURCES;
1487 break;
1488 }
1489
1490 1 ret = gate_ui_iconlist_create(&trvw->icons, ptr_host, 16, 16);
1491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(ret))
1492 {
1493 break;
1494 }
1495
1496 1 ret = gate_ui_motif_ctrl_init(&trvw->ctrl, w, userparam, NULL, parent, w_tree, position, &flags, &treeview_dispatcher);
1497
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1498
1499 1 XtManageChild(w);
1500 1 XtManageChild(w_tree);
1501
1502 } while (0);
1503
1504
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(ret))
1505 {
1506 if (w_tree != NULL)
1507 {
1508 XtDestroyWidget(w_tree);
1509 }
1510 if (w != NULL)
1511 {
1512 XtDestroyWidget(w);
1513 }
1514 }
1515 1 return ret;
1516 }
1517
1518 gate_result_t gate_ui_treeview_add_icon(gate_ui_treeview_t* trvw, gate_ui_icon_t const* icon, gate_intptr_t* icon_key)
1519 {
1520 return gate_ui_iconlist_add_icon(&trvw->icons, icon, icon_key);
1521 }
1522
1523 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)
1524 {
1525 1 return gate_ui_iconlist_add_image(&trvw->icons, image, icon_key);
1526 }
1527
1528 3 static gate_bool_t gate_ui_treeview_is_node_selected(Widget node)
1529 {
1530 3 Dimension dim = 0;
1531 3 XtVaGetValues(node, XmNshadowThickness, &dim, NULL, NULL);
1532 3 return dim != 0;
1533 }
1534
1535 9 static void gate_ui_treeview_set_node_selected(Widget node, gate_bool_t selected)
1536 {
1537 9 Dimension olddim = 0;
1538 9 Dimension newdim = selected ? 1 : 0;
1539 9 XtVaGetValues(node, XmNshadowThickness, &olddim, NULL, NULL);
1540
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
9 if (olddim != newdim)
1541 {
1542 2 XtVaSetValues(node, XmNshadowThickness, newdim, NULL, NULL);
1543 /* TODO: update UI*/
1544 }
1545 9 }
1546
1547 typedef gate_bool_t(*gate_ui_treeview_node_iterate_callback_t)(gate_ui_treeview_t* ptr_trvw, Widget node, void* param);
1548
1549 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)
1550 {
1551 gate_result_t ret;
1552 3 WidgetList nodes = NULL;
1553 3 gate_size_t nodes_count = 0;
1554 gate_size_t ndx;
1555 3 gate_bool_t continue_iterate = true;
1556
1557 3 ret = gate_ui_motif_ctrl_get_children(&ptr_trvw->ctrl, (void**)&nodes, &nodes_count);
1558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(ret))
1559 {
1560 return ret;
1561 }
1562
1563
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)
1564 {
1565 18 Widget w = nodes[ndx];
1566
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
18 if (!XtIsSubclass(w, xmPushButtonWidgetClass))
1567 {
1568 9 continue;
1569 }
1570 9 continue_iterate = callback(ptr_trvw, w, param);
1571 }
1572 3 return ret;
1573 }
1574
1575 static void gate_ui_treeview_set_node_selected_recursive(Widget node, Widget node_to_select)
1576 {
1577 WidgetList sub_nodes = NULL;
1578 gate_ui_treeview_set_node_selected(node, node == node_to_select);
1579 sub_nodes = XmHierarchyGetChildNodes(node);
1580 if (sub_nodes)
1581 {
1582 gate_size_t ndx;
1583 for (ndx = 0; sub_nodes[ndx]; ++ndx)
1584 {
1585 gate_ui_treeview_set_node_selected_recursive(sub_nodes[ndx], node_to_select);
1586 }
1587 XtFree((char*)sub_nodes);
1588 }
1589 }
1590
1591 9 static gate_bool_t gate_ui_treeview_node_iterate_select(gate_ui_treeview_t* ptr_trvw, Widget node, void* param)
1592 {
1593 9 Widget to_select = (Widget)param;
1594 9 gate_ui_treeview_set_node_selected(node, node == to_select);
1595 9 return true;
1596 }
1597
1598 3 static void gate_ui_treeview_select_node_widget_and_unselect_others(gate_ui_treeview_t* ptr_trvw, Widget node_to_select)
1599 {
1600 3 gate_ui_treeview_node_iterate(ptr_trvw, &gate_ui_treeview_node_iterate_select, (void*)node_to_select);
1601 3 }
1602
1603 3 static Widget gate_ui_treeview_get_selected_node_widget(gate_ui_treeview_t* ptr_trvw)
1604 {
1605 3 Widget ret = NULL;
1606 3 WidgetList children = NULL;
1607 gate_size_t ndx;
1608 3 gate_size_t children_count = 0;
1609 gate_result_t result;
1610
1611 3 result = gate_ui_motif_ctrl_get_children(&ptr_trvw->ctrl, (void**)&children, &children_count);
1612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(result))
1613 {
1614 return NULL;
1615 }
1616
1617
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 for (ndx = 0; ndx != children_count; ++ndx)
1618 {
1619 3 Widget node = children[ndx];
1620
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (node)
1621 {
1622
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if (gate_ui_treeview_is_node_selected(node))
1623 {
1624 3 ret = node;
1625 3 break;
1626 }
1627 }
1628 }
1629 3 return ret;
1630 }
1631
1632 2 static void gate_ui_treeview_on_node_widget_click(Widget node_widget, XtPointer client_data, XtPointer event_data)
1633 {
1634 2 gate_ui_treeview_t* ptr_trvw = (gate_ui_treeview_t*)client_data;
1635
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (ptr_trvw)
1636 {
1637 2 gate_bool_t context_menu = false;
1638 2 XmPushButtonCallbackStruct* ptr_btn_event_data = (XmPushButtonCallbackStruct*)event_data;
1639
1640 2 gate_ui_treeview_select_node_widget_and_unselect_others(ptr_trvw, node_widget);
1641
1642
1643
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)
1644 {
1645
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 switch(ptr_btn_event_data->event->type)
1646 {
1647 1 case KeyPress:
1648 {
1649 1 XKeyEvent* kev = &ptr_btn_event_data->event->xkey;
1650
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (kev->state & ControlMask)
1651 {
1652 1 context_menu = true;
1653 }
1654 1 break;
1655 }
1656 1 default:
1657 {
1658 1 break;
1659 }
1660 }
1661 }
1662
1663
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (context_menu)
1664 {
1665
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_trvw->on_contextmenu)
1666 {
1667 1 ptr_trvw->on_contextmenu(&ptr_trvw->ctrl, (gate_ui_treeview_item_t)node_widget);
1668 }
1669 }
1670 else
1671 {
1672
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_trvw->on_select)
1673 {
1674 1 ptr_trvw->on_select(&ptr_trvw->ctrl, (gate_ui_treeview_item_t)node_widget);
1675 }
1676 }
1677 }
1678 2 }
1679
1680 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,
1681 gate_intptr_t iconkey, void* itemparam, gate_ui_treeview_item_t* newitem)
1682 {
1683 Widget w_tree;
1684 Widget w_node;
1685 XmString xmstr;
1686 Arg args[10];
1687 Cardinal args_count;
1688
1689 4 w_tree = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&trvw->ctrl);
1690
1691 4 xmstr = gate_ui_motif_create_string(text);
1692
1693 4 args_count = 0;
1694 4 XtSetArg(args[args_count], XmNlabelString, xmstr); ++args_count;
1695 4 XtSetArg(args[args_count], XmNnodeState, XmClosed); ++args_count;
1696
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;
1697 //XtSetArg(args[args_count], XmNlineStyle, 99); ++args_count;
1698 4 XtSetArg(args[args_count], XmNshadowThickness, 0); ++args_count;
1699 //XtSetArg(args[args_count], XmNtoggleMode, XmTOGGLE_BOOLEAN); ++args_count;
1700 //XtSetArg(args[args_count], XmNset, XmUNSET); ++args_count;
1701 //XtSetArg(args[args_count], XmNalignment, XmALIGNMENT_BEGINNING); ++args_count;
1702 4 XtSetArg(args[args_count], XmNuserData, itemparam); ++args_count;
1703 4 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1704
1705 4 w_node = XtCreateWidget(NULL, xmPushButtonWidgetClass, w_tree, args, args_count);
1706 //w_node = XtCreateWidget(NULL, xmLabelWidgetClass, w_tree, args, argcount);
1707 //w_node = XtCreateWidget(NULL, xmToggleButtonWidgetClass, w_tree, args, argcount);
1708 4 XmStringFree(xmstr);
1709
1710 4 XtAddCallback(w_node, XmNactivateCallback, gate_ui_treeview_on_node_widget_click, trvw);
1711
1712 4 *newitem = (gate_uintptr_t)w_node;
1713 4 XtManageChild(w_node);
1714 4 return GATE_RESULT_OK;
1715 }
1716
1717 3 void* gate_ui_treeview_get_itemparam(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1718 {
1719 3 Widget w = (Widget)item;
1720 3 void* userdata = NULL;
1721
1722 3 XtVaGetValues(w, XmNuserData, &userdata, NULL, NULL);
1723 3 return userdata;
1724 }
1725
1726 1 gate_result_t gate_ui_treeview_remove(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1727 {
1728 1 Widget trvw_widget = GATE_UI_MOTIF_GET_CTRL_WIDGET(&trvw->ctrl);
1729 1 Widget w = (Widget)item;
1730 1 motif_treeview_remove_nodes_recursive(w);
1731 1 return GATE_RESULT_OK;
1732 }
1733
1734 gate_result_t gate_ui_treeview_clear(gate_ui_treeview_t* trvw)
1735 {
1736 return GATE_RESULT_NOTIMPLEMENTED;
1737 }
1738
1739 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)
1740 {
1741 1 Widget w = (Widget)item;
1742 1 Widget w_parent = NULL;
1743
1744 1 XtVaGetValues(w, XmNparentNode, &w_parent, NULL, NULL);
1745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (w_parent)
1746 {
1747 *parent = (gate_ui_treeview_item_t)w_parent;
1748 }
1749 else
1750 {
1751 1 *parent = 0;
1752 }
1753 1 return GATE_RESULT_OK;
1754 }
1755
1756 1 gate_result_t gate_ui_treeview_get_children(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_array_t* children)
1757 {
1758 1 Widget w_tree = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&trvw->ctrl);
1759 1 Widget w = (Widget)item;
1760 1 WidgetList wlist = NULL;
1761 1 Cardinal wlist_count = 0;
1762 1 gate_bool_t free_wlist = false;
1763 1 gate_bool_t filter_parent = false;
1764 1 gate_arraylist_t arr = gate_arraylist_create(sizeof(gate_ui_treeview_item_t), NULL, 0, NULL, NULL);
1765
1766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == arr)
1767 {
1768 return GATE_RESULT_OUTOFMEMORY;
1769 }
1770
1771
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (item)
1772 {
1773 wlist = XmHierarchyGetChildNodes(w);
1774 if (wlist)
1775 {
1776 free_wlist = true;
1777 while (wlist[wlist_count] != NULL)
1778 {
1779 ++wlist_count;
1780 };
1781 }
1782 }
1783 else
1784 {
1785 1 XtVaGetValues(w_tree, XmNchildren, &wlist, XmNnumChildren, &wlist_count, NULL);
1786 1 filter_parent = true;
1787 }
1788
1789
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (wlist)
1790 {
1791 gate_size_t ndx;
1792
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
7 for (ndx = 0; ndx < wlist_count; ++ndx)
1793 {
1794 6 Widget child = wlist[ndx];
1795 6 gate_ui_treeview_item_t subitem = (gate_ui_treeview_item_t)child;
1796
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if (!XtIsSubclass(child, xmPushButtonWidgetClass))
1797 {
1798 5 continue;
1799 }
1800
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(filter_parent)
1801 {
1802 3 Widget w_parent = NULL;
1803 3 XtVaGetValues(child, XmNparentNode, &w_parent, NULL, NULL);
1804
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (w_parent != w)
1805 {
1806 2 continue;
1807 }
1808 }
1809 1 gate_arraylist_add(arr, &subitem);
1810 }
1811
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(free_wlist)
1812 {
1813 XtFree((char*)wlist);
1814 }
1815 }
1816
1817
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_array_create(children, arr))
1818 {
1819 gate_arraylist_release(arr);
1820 return GATE_RESULT_OUTOFMEMORY;
1821 }
1822 else
1823 {
1824 1 gate_arraylist_release(arr);
1825 1 return GATE_RESULT_OK;
1826 }
1827 }
1828
1829 3 gate_result_t gate_ui_treeview_get_text(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_string_t* text)
1830 {
1831 3 Widget w = (Widget)item;
1832 3 return gate_ui_motif_widget_get_label(w, text);
1833 }
1834
1835 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)
1836 {
1837 1 Widget w = (Widget)item;
1838 1 return gate_ui_motif_widget_set_label(w, text);
1839 }
1840
1841 1 gate_bool_t gate_ui_treeview_is_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1842 {
1843 1 Widget w = (Widget)item;
1844 1 Cardinal v = 0;
1845 1 XtVaGetValues(w, XmNoutlineState, &v, NULL, NULL);
1846 1 return (v == XmEXPANDED) ? true : false;
1847 }
1848
1849 2 gate_result_t gate_ui_treeview_set_expanded(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item, gate_bool_t expanded)
1850 {
1851 2 Widget w = (Widget)item;
1852 2 XtVaSetValues(w, XmNoutlineState, (expanded ? XmEXPANDED : XmCOLLAPSED), NULL, NULL);
1853 2 return GATE_RESULT_OK;
1854 }
1855
1856 1 gate_result_t gate_ui_treeview_get_selected_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t* item)
1857 {
1858 1 Widget sel_widget = gate_ui_treeview_get_selected_node_widget(trvw);
1859
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (sel_widget)
1860 {
1861 1 *item = (gate_ui_treeview_item_t)sel_widget;
1862 1 return GATE_RESULT_OK;
1863 }
1864 else
1865 {
1866 return GATE_RESULT_NOMATCH;
1867 }
1868 }
1869
1870 1 gate_result_t gate_ui_treeview_select_item(gate_ui_treeview_t* trvw, gate_ui_treeview_item_t item)
1871 {
1872 1 Widget w_to_select = (Widget)item;
1873 1 gate_ui_treeview_select_node_widget_and_unselect_others(trvw, w_to_select);
1874
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (trvw->on_select)
1875 {
1876 1 trvw->on_select(&trvw->ctrl, item);
1877 }
1878 1 return GATE_RESULT_OK;
1879 }
1880
1881 2 gate_result_t gate_ui_treeview_perform_action(gate_ui_treeview_t* trvw, gate_enumint_t action)
1882 {
1883
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 switch (action)
1884 {
1885 1 case GATE_UI_ACTION_ACTIVATE:
1886 {
1887 1 Widget selected = gate_ui_treeview_get_selected_node_widget(trvw);
1888
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (selected != NULL)
1889 {
1890 XmPushButtonCallbackStruct event_data;
1891 XEvent evt;
1892 XButtonEvent* bev;
1893 1 gate_mem_clear(&event_data, sizeof(event_data));
1894 1 gate_mem_clear(&evt, sizeof(evt));
1895 1 event_data.click_count = 1;
1896 1 event_data.reason = 10;
1897 1 event_data.event = &evt;
1898 1 bev = &event_data.event->xbutton;
1899 1 bev->type = ButtonRelease;
1900 1 bev->button = 1;
1901 1 gate_ui_treeview_on_node_widget_click(selected, (XtPointer)trvw, &event_data);
1902 }
1903 1 return GATE_RESULT_OK;
1904 }
1905 1 case GATE_UI_ACTION_CONTEXTMENU:
1906 {
1907 1 Widget selected = gate_ui_treeview_get_selected_node_widget(trvw);
1908
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (selected != NULL)
1909 {
1910 XmPushButtonCallbackStruct event_data;
1911 XEvent evt;
1912 XKeyEvent* kev;
1913 1 gate_mem_clear(&event_data, sizeof(event_data));
1914 1 gate_mem_clear(&evt, sizeof(evt));
1915 1 event_data.click_count = 1;
1916 1 event_data.reason = 10;
1917 1 event_data.event = &evt;
1918 1 kev = &event_data.event->xkey;
1919 1 kev->type = KeyPress;
1920 1 kev->keycode = 65;
1921 1 kev->state = ControlMask;
1922 1 gate_ui_treeview_on_node_widget_click(selected, (XtPointer)trvw, &event_data);
1923 }
1924 1 return GATE_RESULT_OK;
1925 }
1926 }
1927 return GATE_RESULT_NOTSUPPORTED;
1928 }
1929
1930
1931 #endif /* GATE_UI_MOTIF */
1932