GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/tabs.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 152 196 77.6%
Functions: 13 16 81.2%
Branches: 46 90 51.1%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, 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/tabs.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
38 #if defined(GATE_SYS_WIN16)
39
40 #define WC_TABCONTROL "SysTabControl"
41
42 typedef struct tagNMHDR
43 {
44 HWND hwndFrom;
45 UINT_PTR idFrom;
46 UINT code;
47 } NMHDR;
48
49 typedef struct tagTCITEM
50 {
51 UINT mask;
52 DWORD dwState;
53 DWORD dwStateMask;
54 LPSTR pszText;
55 int cchTextMax;
56 int iImage;
57
58 LPARAM lParam;
59 } TCITEM, * LPTCITEM;
60
61 #define TC_ITEM TCITEM
62
63 #define TCM_FIRST 0x1300 // Tab control messages
64 #define TCN_FIRST (0U-550U) // tab control
65 #define TCN_LAST (0U-580U)
66
67 #define WM_NOTIFY 0x004E
68 #define TCN_SELCHANGE (TCN_FIRST - 1)
69 #define TCS_TABS 0x0000
70 #define TCS_BUTTONS 0x0100
71 #define TCS_SINGLELINE 0x0000
72 #define TCS_MULTILINE 0x0200
73
74 #define TCIF_TEXT 0x0001
75 #define TCIF_IMAGE 0x0002
76 #define TCIF_RTLREADING 0x0004
77 #define TCIF_PARAM 0x0008
78 #define TCIF_STATE 0x0010
79
80 #define TCM_SETITEMEXTRA (TCM_FIRST + 14)
81 #define TabCtrl_SetItemExtra(hwndTC, cb) \
82 (BOOL)SendMessage((hwndTC), TCM_SETITEMEXTRA, (WPARAM)(cb), 0L)
83
84 #define TCM_ADJUSTRECT (TCM_FIRST + 40)
85 #define TabCtrl_AdjustRect(hwnd, bLarger, prc) \
86 (int)SendMessage(hwnd, TCM_ADJUSTRECT, (WPARAM)(BOOL)(bLarger), (LPARAM)(RECT *)(prc))
87
88 #define TCM_GETCURSEL (TCM_FIRST + 11)
89 #define TabCtrl_GetCurSel(hwnd) \
90 (int)SendMessage((hwnd), TCM_GETCURSEL, 0, 0)
91
92 #define TCM_SETCURSEL (TCM_FIRST + 12)
93 #define TabCtrl_SetCurSel(hwnd, i) \
94 (int)SendMessage((hwnd), TCM_SETCURSEL, (WPARAM)(i), 0)
95
96 #define TCM_INSERTITEM (TCM_FIRST + 7)
97 #define TabCtrl_InsertItem(hwnd, iItem, pitem) \
98 (int)SendMessage((hwnd), TCM_INSERTITEM, (WPARAM)(int)(iItem), (LPARAM)(const TC_ITEM *)(pitem))
99
100
101 #define TCM_DELETEITEM (TCM_FIRST + 8)
102 #define TabCtrl_DeleteItem(hwnd, i) \
103 (BOOL)SendMessage((hwnd), TCM_DELETEITEM, (WPARAM)(int)(i), 0L)
104
105
106 #define TCM_DELETEALLITEMS (TCM_FIRST + 9)
107 #define TabCtrl_DeleteAllItems(hwnd) \
108 (BOOL)SendMessage((hwnd), TCM_DELETEALLITEMS, 0, 0L)
109
110
111 #define TCM_GETITEMRECT (TCM_FIRST + 10)
112 #define TabCtrl_GetItemRect(hwnd, i, prc) \
113 (BOOL)SendMessage((hwnd), TCM_GETITEMRECT, (WPARAM)(int)(i), (LPARAM)(RECT *)(prc))
114
115 #define TCM_GETITEMCOUNT (TCM_FIRST + 4)
116 #define TabCtrl_GetItemCount(hwnd) \
117 (int)SendMessage((hwnd), TCM_GETITEMCOUNT, 0, 0L)
118
119 #define TCM_GETITEM (TCM_FIRST + 5)
120 #define TabCtrl_GetItem(hwnd, iItem, pitem) \
121 (BOOL)SendMessage((hwnd), TCM_GETITEM, (WPARAM)(int)(iItem), (LPARAM)(TC_ITEM *)(pitem))
122
123 #define TCM_SETITEM (TCM_FIRST + 6)
124 #define TabCtrl_SetItem(hwnd, iItem, pitem) \
125 (BOOL)SendMessage((hwnd), TCM_SETITEM, (WPARAM)(int)(iItem), (LPARAM)(TC_ITEM *)(pitem))
126
127
128 #else
129 # include <commctrl.h>
130 #endif
131
132
133 static gate_result_t gate_ui_tabs_destroy_impl(gate_ui_ctrl_t* ctrl)
134 {
135 gate_ui_tabctrl_t* tabctrl = (gate_ui_tabctrl_t*)ctrl;
136 gate_ui_tabctrl_clear(tabctrl);
137 gate_ui_winapi_destroy(ctrl);
138 gate_arraylist_release(tabctrl->pages);
139 tabctrl->pages = NULL;
140
141 GATE_UI_WINAPI_SET_HWND(ctrl, NULL);
142 GATE_UI_WINAPI_SET_HWND_PARENT(ctrl, NULL);
143 GATE_UI_WINAPI_SET_HOST(ctrl, NULL);
144 GATE_UI_WINAPI_SET_HWND_PROC(ctrl, NULL);
145 GATE_UI_WINAPI_SET_USER_PARAM(ctrl, NULL);
146 GATE_UI_WINAPI_SET_DISPATCHER(ctrl, NULL);
147 GATE_UI_WINAPI_SET_CTRL_PARAM(ctrl, NULL);
148 return GATE_RESULT_OK;
149 }
150 /*
151 static gate_bool_t gate_ui_tabs_is_enabled_impl(gate_ui_ctrl_t* ctrl);
152 static gate_bool_t gate_ui_tabs_is_visible_impl(gate_ui_ctrl_t* ctrl);
153 static gate_bool_t gate_ui_tabs_is_focused_impl(gate_ui_ctrl_t* ctrl);
154 static gate_result_t gate_ui_tabs_get_position_impl(gate_ui_ctrl_t* ctrl, gate_ui_position_t* position);
155 static gate_result_t gate_ui_tabs_get_size_impl(gate_ui_ctrl_t* ctrl, gate_ui_size_t* size);
156 static gate_result_t gate_ui_tabs_get_children_impl(gate_ui_ctrl_t* ctrl, gate_array_t* children);
157 static gate_result_t gate_ui_tabs_get_text_length_impl(gate_ui_ctrl_t* ctrl, gate_uint32_t* textlength);
158 static gate_result_t gate_ui_tabs_get_text_impl(gate_ui_ctrl_t* ctrl, gate_string_t* text);
159 static gate_result_t gate_ui_tabs_get_state_impl(gate_ui_ctrl_t* ctrl, gate_int32_t* state);
160 static gate_result_t gate_ui_tabs_set_enabled_impl(gate_ui_ctrl_t* ctrl, gate_bool_t enabledstate);
161 static gate_result_t gate_ui_tabs_set_visible_impl(gate_ui_ctrl_t* ctrl, gate_bool_t visibility);
162 static gate_result_t gate_ui_tabs_set_focus_impl(gate_ui_ctrl_t* ctrl);
163 static gate_result_t gate_ui_tabs_set_position_impl(gate_ui_ctrl_t* ctrl, gate_ui_point_t const* position, gate_ui_size_t const* size);
164 static gate_result_t gate_ui_tabs_set_text_impl(gate_ui_ctrl_t* ctrl, gate_string_t const* text);
165 static gate_result_t gate_ui_tabs_set_state_impl(gate_ui_ctrl_t* ctrl, gate_int32_t state);
166 */
167 static gate_result_t gate_ui_tabs_refresh_impl(gate_ui_ctrl_t* ctrl)
168 {
169 gate_ui_tabctrl_t* tabctrl = (gate_ui_tabctrl_t*)ctrl;
170 return gate_ui_tabctrl_refresh(tabctrl);
171 }
172
173 static gate_ui_winapi_dispatchers_t gate_ui_tabs_dispatcher =
174 {
175 &gate_ui_tabs_destroy_impl,
176
177 NULL, /* &gate_ui_tabs_is_enabled_impl, */
178 NULL, /* &gate_ui_tabs_is_visible_impl, */
179 NULL, /* &gate_ui_tabs_is_focused_impl, */
180 NULL, /* &gate_ui_tabs_get_position_impl, */
181 NULL, /* &gate_ui_tabs_get_size_impl, */
182 NULL, /* &gate_ui_tabs_get_children_impl, */
183 NULL, /* &gate_ui_tabs_get_text_length_impl, */
184 NULL, /* &gate_ui_tabs_get_text_impl, */
185 NULL, /* &gate_ui_tabs_get_state_impl, */
186
187 NULL, /* &gate_ui_tabs_set_enabled_impl, */
188 NULL, /* &gate_ui_tabs_set_visible_impl, */
189 NULL, /* &gate_ui_tabs_set_focus_impl, */
190 NULL, /* &gate_ui_tabs_set_position_impl, */
191 NULL, /* &gate_ui_tabs_set_text_impl, */
192 NULL, /* &gate_ui_tabs_set_state_impl, */
193 &gate_ui_tabs_refresh_impl
194 };
195
196
197 static gate_result_t gate_ui_tabctrl_get_area(HWND hwnd, gate_ui_position_t* pos)
198 {
199 RECT client_rect, rect;
200 BOOL succeeded = TRUE;
201 #if !defined(GATE_SYS_WIN16)
202 succeeded =
203 #endif
204 GetClientRect(hwnd, &client_rect);
205 if (succeeded)
206 {
207 gate_mem_clear(&rect, sizeof(rect));
208 TabCtrl_AdjustRect(hwnd, FALSE, &rect);
209 pos->pos.x = client_rect.left + rect.left;
210 pos->pos.y = client_rect.top + rect.top;
211 pos->size.width = client_rect.right - rect.left + rect.right;
212 pos->size.height = client_rect.bottom - rect.top + rect.bottom;
213 return GATE_RESULT_OK;
214 }
215 return GATE_RESULT_FAILED;
216 }
217
218
219 static gate_bool_t gate_ui_tabctrl_events(void* hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult)
220 {
221 if ((ctrl != NULL) && (hwnd != NULL))
222 {
223 HWND hwnd_ctrl = GATE_UI_WINAPI_GET_HWND(ctrl);
224 if (NULL != hwnd_ctrl)
225 {
226 gate_ui_tabctrl_t* tabctrl = (gate_ui_tabctrl_t*)ctrl;
227 switch (msg)
228 {
229 #if !defined(GATE_SYS_WIN16)
230 case WM_CTLCOLORBTN:
231 case WM_CTLCOLOREDIT:
232 case WM_CTLCOLORLISTBOX:
233 case WM_CTLCOLORSCROLLBAR:
234 {
235 *lresult = SendMessage(GetParent((HWND)hwnd), msg, wParam, lParam);
236 return true;
237 }
238 case WM_CTLCOLORMSGBOX:
239 case WM_CTLCOLORDLG:
240 case WM_CTLCOLORSTATIC:
241 {
242 /* tabs are always acting like dialog-parents,
243 also if they are placed on standard forms,
244 that would return white/standard colors -> so fix it here
245 */
246 HDC hdc = (HDC)wParam;
247 HWND hwnd_child = (HWND)lParam;
248 COLORREF text_color;
249 COLORREF bk_color;
250 HBRUSH hbr_bk_gnd;
251
252 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
253 if (gate_ui_winapi_is_darkmode_applied(hwnd_ctrl))
254 {
255 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(ctrl);
256 gate_ui_color_t ui_color;
257
258 gate_ui_host_default_color(host, GATE_UI_COLOR_DIALOGTEXT, &ui_color);
259 text_color = RGB(ui_color.r, ui_color.g, ui_color.b);
260
261 gate_ui_host_default_color(host, GATE_UI_COLOR_DIALOG, &ui_color);
262 bk_color = RGB(ui_color.r, ui_color.g, ui_color.b);
263
264 hbr_bk_gnd = (HBRUSH)gate_ui_winapi_host_get_brush(host, &ui_color);
265 }
266 else
267 #endif /* GATE_UI_WINAPI_DARKMODE_SUPPORT */
268 {
269 text_color = GetSysColor(gate_ui_winapi_get_syscolor_index(GATE_UI_COLOR_DIALOGTEXT));
270 bk_color = GetSysColor(gate_ui_winapi_get_syscolor_index(GATE_UI_COLOR_DIALOG));
271 hbr_bk_gnd = (HBRUSH)gate_ui_winapi_get_syscolor_brush(gate_ui_winapi_get_syscolor_index(GATE_UI_COLOR_DIALOG));
272 }
273 SetTextColor(hdc, text_color);
274 SetBkColor(hdc, bk_color);
275 *lresult = (gate_intptr_t)hbr_bk_gnd;
276 return true;
277 }
278 #endif /* GATE_SYS_WIN16 */
279 case WM_SIZE:
280 {
281 gate_ui_tabctrl_refresh(tabctrl);
282 break;
283 }
284 case WM_NOTIFY:
285 {
286 NMHDR* hdr = (NMHDR*)lParam;
287 if (hdr->hwndFrom == hwnd_ctrl)
288 {
289 switch (hdr->code)
290 {
291 case TCN_SELCHANGE:
292 {
293 int index = TabCtrl_GetCurSel(hwnd_ctrl);
294 if (index >= 0)
295 {
296 gate_ui_tabctrl_refresh(tabctrl);
297 if (tabctrl->on_select)
298 {
299 tabctrl->on_select(&tabctrl->ctrl, index);
300 }
301 }
302 *lresult = 0;
303 break;
304 }
305 default:
306 {
307 break;
308 }
309 }
310 }
311 break;
312 }
313
314 case WM_DESTROY:
315 {
316 gate_ui_tabctrl_clear(tabctrl);
317 break;
318 }
319 }
320 }
321 }
322 return false;
323 }
324
325 gate_result_t gate_ui_tabctrl_create(gate_ui_tabctrl_t* tabctrl, gate_ui_ctrl_t* parent,
326 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
327 {
328 gate_result_t ret;
329
330 do
331 {
332 gate_uint32_t styles = WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | TCS_SINGLELINE | TCS_TABS;
333 gate_uint32_t exstyles = 0;
334 HWND hwnd_parent;
335 HWND hwnd_ctrl;
336 gate_ui_host_t* host = gate_ui_ctrl_get_host(parent);
337
338 if (host == NULL)
339 {
340 ret = GATE_RESULT_INVALIDSTATE;
341 break;
342 }
343 hwnd_parent = GATE_UI_WINAPI_GET_HWND(parent);
344 if (hwnd_parent == NULL)
345 {
346 ret = GATE_RESULT_INVALIDSTATE;
347 break;
348 }
349
350 gate_mem_clear(tabctrl, sizeof(gate_ui_tabctrl_t));
351 tabctrl->pages = gate_arraylist_create(sizeof(gate_ui_panel_t*), NULL, 0, NULL, NULL);
352 if (tabctrl->pages == NULL)
353 {
354 ret = GATE_RESULT_OUTOFMEMORY;
355 break;
356 }
357
358 #if !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WIN16)
359 exstyles |= WS_EX_CONTROLPARENT;
360 #endif
361 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
362 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
363
364 ret = gate_ui_winapi_create(&tabctrl->ctrl, host, hwnd_parent, WC_TABCONTROL, position, styles, exstyles, NULL, userparam, true);
365 if (GATE_SUCCEEDED(ret))
366 {
367 GATE_UI_WINAPI_SET_DISPATCHER(&tabctrl->ctrl, &gate_ui_tabs_dispatcher);
368 hwnd_ctrl = GATE_UI_WINAPI_GET_HWND(&tabctrl->ctrl);
369
370 gate_ui_winapi_register_event(host, hwnd_ctrl, WM_DESTROY, &gate_ui_tabctrl_events, &tabctrl->ctrl);
371 gate_ui_winapi_register_event(host, hwnd_ctrl, WM_SIZE, &gate_ui_tabctrl_events, &tabctrl->ctrl);
372 gate_ui_winapi_register_event(host, hwnd_parent, WM_NOTIFY, &gate_ui_tabctrl_events, &tabctrl->ctrl);
373
374 #if !defined(GATE_SYS_WIN16)
375 gate_ui_winapi_register_event(host, hwnd_ctrl, WM_CTLCOLORDLG, &gate_ui_tabctrl_events, &tabctrl->ctrl);
376 gate_ui_winapi_register_event(host, hwnd_ctrl, WM_CTLCOLORSTATIC, &gate_ui_tabctrl_events, &tabctrl->ctrl);
377 gate_ui_winapi_register_event(host, hwnd_ctrl, WM_CTLCOLOREDIT, &gate_ui_tabctrl_events, &tabctrl->ctrl);
378 gate_ui_winapi_register_event(host, hwnd_ctrl, WM_CTLCOLORBTN, &gate_ui_tabctrl_events, &tabctrl->ctrl);
379 gate_ui_winapi_register_event(host, hwnd_ctrl, WM_CTLCOLORLISTBOX, &gate_ui_tabctrl_events, &tabctrl->ctrl);
380 gate_ui_winapi_register_event(host, hwnd_ctrl, WM_CTLCOLORMSGBOX, &gate_ui_tabctrl_events, &tabctrl->ctrl);
381 gate_ui_winapi_register_event(host, hwnd_ctrl, WM_CTLCOLORSCROLLBAR, &gate_ui_tabctrl_events, &tabctrl->ctrl);
382 #endif
383 }
384 else
385 {
386 gate_arraylist_release(tabctrl->pages);
387 }
388 } while (0);
389
390 return ret;
391 }
392
393 gate_result_t gate_ui_tabctrl_refresh(gate_ui_tabctrl_t* tabctrl)
394 {
395 gate_result_t ret = GATE_RESULT_FAILED;
396 gate_size_t index;
397 gate_size_t count = gate_ui_tabctrl_get_tab_count(tabctrl);
398 gate_size_t selected = gate_ui_tabctrl_get_selected_tab(tabctrl);
399 gate_ui_position_t panel_pos;
400 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&tabctrl->ctrl);
401
402 do
403 {
404 ret = gate_ui_tabctrl_get_area(hwnd, &panel_pos);
405 GATE_BREAK_IF_FAILED(ret);
406
407 for (index = 0; index != count; ++index)
408 {
409 gate_ui_panel_t** ptr_ptr_panel = (gate_ui_panel_t**)gate_arraylist_get(tabctrl->pages, index);
410 if (ptr_ptr_panel)
411 {
412 gate_ui_panel_t* ptr_panel = *ptr_ptr_panel;
413 if (ptr_panel)
414 {
415 if (index == selected)
416 {
417 gate_ui_ctrl_set_position(&ptr_panel->ctrl, &panel_pos.pos, &panel_pos.size);
418 gate_ui_ctrl_set_visible(&ptr_panel->ctrl, true);
419 gate_ui_ctrl_refresh(&ptr_panel->ctrl);
420 }
421 else
422 {
423 gate_ui_ctrl_set_visible(&ptr_panel->ctrl, false);
424 }
425 }
426 }
427 }
428 } while (0);
429
430 return ret;
431 }
432
433
434 gate_result_t gate_ui_tabctrl_add_tab(gate_ui_tabctrl_t* tabctrl, gate_string_t const* text, void* itemparam)
435 {
436 size_t next_index = gate_ui_tabctrl_get_tab_count(tabctrl);
437 return gate_ui_tabctrl_insert_tab(tabctrl, next_index, text, itemparam);
438 }
439 gate_result_t gate_ui_tabctrl_insert_tab(gate_ui_tabctrl_t* tabctrl, gate_size_t at_index, gate_string_t const* text, void* itemparam)
440 {
441 gate_result_t ret = GATE_RESULT_FAILED;
442 gate_ui_panel_t* ptr_panel = NULL;
443
444 do
445 {
446 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&tabctrl->ctrl);
447 TCHAR text_buffer[1024];
448 gate_size_t text_buffer_used;
449 TCITEM tcitem;
450 gate_size_t item_count = (size_t)TabCtrl_GetItemCount(hwnd);
451 if (item_count != gate_arraylist_length(tabctrl->pages))
452 {
453 ret = GATE_RESULT_INVALIDCONTENT;
454 break;
455 }
456 if (at_index > item_count)
457 {
458 at_index = item_count;
459 }
460
461 ptr_panel = gate_mem_alloc(sizeof(gate_ui_panel_t));
462 if (NULL == ptr_panel)
463 {
464 ret = GATE_RESULT_OUTOFMEMORY;
465 break;
466 }
467 gate_mem_clear(ptr_panel, sizeof(gate_ui_panel_t));
468
469 ret = gate_ui_panel_create(ptr_panel, &tabctrl->ctrl, NULL, GATE_UI_FLAG_ENABLED, itemparam);
470 if (GATE_FAILED(ret))
471 {
472 gate_mem_clear(ptr_panel, sizeof(gate_ui_panel_t));
473 break;
474 }
475
476 if (NULL == gate_arraylist_insert(tabctrl->pages, at_index, &ptr_panel, 1))
477 {
478 ret = GATE_RESULT_OUTOFMEMORY;
479 break;
480 }
481
482 gate_mem_clear(&tcitem, sizeof(tcitem));
483 if (text)
484 {
485 text_buffer_used = gate_win32_utf8_2_winstr(text->str, text->length, text_buffer, sizeof(text_buffer) / sizeof(text_buffer[0]));
486 }
487 else
488 {
489 text_buffer[0] = 0;
490 text_buffer_used = 0;
491 }
492 tcitem.mask = TCIF_PARAM | TCIF_TEXT;
493 tcitem.lParam = (LPARAM)itemparam;
494 tcitem.pszText = text_buffer;
495 tcitem.cchTextMax = (int)text_buffer_used;
496 if (-1 == TabCtrl_InsertItem(hwnd, (int)at_index, &tcitem))
497 {
498 /* failed */
499 ret = GATE_RESULT_FAILED;
500 gate_arraylist_remove(tabctrl->pages, at_index, 1);
501 break;
502 }
503
504 ptr_panel = NULL;
505 ret = GATE_RESULT_OK;
506
507 if (gate_ui_tabctrl_get_selected_tab(tabctrl) == (gate_size_t)-1)
508 {
509 gate_ui_tabctrl_set_selected_tab(tabctrl, 0);
510 }
511 else
512 {
513 gate_ui_tabctrl_refresh(tabctrl);
514 }
515 } while (0);
516
517 if (ptr_panel != NULL)
518 {
519 if (gate_ui_ctrl_is_created(&ptr_panel->ctrl))
520 {
521 gate_ui_ctrl_destroy(&ptr_panel->ctrl);
522 }
523 gate_mem_dealloc(ptr_panel);
524 }
525 return ret;
526 }
527 gate_size_t gate_ui_tabctrl_get_tab_count(gate_ui_tabctrl_t* tabctrl)
528 {
529 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&tabctrl->ctrl);
530 return (gate_size_t)TabCtrl_GetItemCount(hwnd);
531 }
532 gate_result_t gate_ui_tabctrl_remove_tab(gate_ui_tabctrl_t* tabctrl, gate_size_t index)
533 {
534 gate_result_t ret = GATE_RESULT_FAILED;
535 gate_size_t count = gate_ui_tabctrl_get_tab_count(tabctrl);
536
537 if (gate_arraylist_length(tabctrl->pages) == count)
538 {
539 if (index < count)
540 {
541 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&tabctrl->ctrl);
542 gate_ui_panel_t* ptr_panel = *(gate_ui_panel_t**)gate_arraylist_get(tabctrl->pages, index);
543 if (ptr_panel)
544 {
545 gate_ui_ctrl_destroy(&ptr_panel->ctrl);
546 gate_mem_dealloc(ptr_panel);
547 }
548 gate_arraylist_remove(tabctrl->pages, index, 1);
549 TabCtrl_DeleteItem(hwnd, (int)index);
550 ret = GATE_RESULT_OK;
551 }
552 else
553 {
554 ret = GATE_RESULT_OUTOFBOUNDS;
555 }
556 }
557 else
558 {
559 ret = GATE_RESULT_INVALIDCONTENT;
560 }
561 return ret;
562 }
563 gate_result_t gate_ui_tabctrl_clear(gate_ui_tabctrl_t* tabctrl)
564 {
565 gate_result_t ret = GATE_RESULT_OK;
566 while (GATE_SUCCEEDED(ret) && (gate_ui_tabctrl_get_tab_count(tabctrl) != 0))
567 {
568 ret = gate_ui_tabctrl_remove_tab(tabctrl, 0);
569 }
570 return ret;
571 }
572 gate_size_t gate_ui_tabctrl_get_selected_tab(gate_ui_tabctrl_t* tabctrl)
573 {
574 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&tabctrl->ctrl);
575 return (gate_size_t)TabCtrl_GetCurSel(hwnd);
576 }
577 gate_result_t gate_ui_tabctrl_set_selected_tab(gate_ui_tabctrl_t* tabctrl, gate_size_t index)
578 {
579 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&tabctrl->ctrl);
580 gate_size_t count = (gate_size_t)TabCtrl_GetItemCount(hwnd);
581 if (index < count)
582 {
583 TabCtrl_SetCurSel(hwnd, (int)index);
584 return gate_ui_tabctrl_refresh(tabctrl);
585 }
586 else
587 {
588 return GATE_RESULT_OUTOFBOUNDS;
589 }
590 }
591
592 gate_result_t gate_ui_tabctrl_get_tab_text(gate_ui_tabctrl_t* tabctrl, gate_size_t index, gate_string_t* text)
593 {
594 gate_result_t ret = GATE_RESULT_FAILED;
595 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&tabctrl->ctrl);
596 TCHAR buffer[1024];
597 TCITEM tcitem;
598 gate_mem_clear(&tcitem, sizeof(tcitem));
599 tcitem.mask = TCIF_TEXT;
600 tcitem.pszText = buffer;
601 tcitem.cchTextMax = (sizeof(buffer) / sizeof(buffer[0]));
602 if (TabCtrl_GetItem(hwnd, (int)index, &tcitem))
603 {
604 TCHAR const* const ptr_text = tcitem.pszText;
605 gate_size_t const text_len = gate_win32_winstr_length_max(ptr_text, tcitem.cchTextMax);
606
607 if (NULL != gate_win32_winstr_2_utf8_string(ptr_text, text_len, text))
608 {
609 ret = GATE_RESULT_OK;
610 }
611 else
612 {
613 ret = GATE_RESULT_OUTOFMEMORY;
614 }
615 }
616 return ret;
617 }
618 gate_result_t gate_ui_tabctrl_set_tab_text(gate_ui_tabctrl_t* tabctrl, gate_size_t index, gate_string_t const* text)
619 {
620 gate_result_t ret = GATE_RESULT_FAILED;
621 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&tabctrl->ctrl);
622 TCHAR buffer[1024];
623 TCITEM tcitem;
624 gate_mem_clear(&tcitem, sizeof(tcitem));
625 tcitem.mask = TCIF_TEXT;
626 tcitem.pszText = buffer;
627 tcitem.cchTextMax = (int)gate_win32_utf8_2_winstr(text->str, text->length, buffer, sizeof(buffer) / sizeof(buffer[0]));
628 TabCtrl_SetItem(hwnd, (int)index, &tcitem);
629 ret = GATE_RESULT_OK;
630 return ret;
631 }
632 gate_result_t gate_ui_tabctrl_get_tab_panel(gate_ui_tabctrl_t* tabctrl, gate_size_t index, gate_ui_panel_t** ptr_panel)
633 {
634 gate_result_t ret = GATE_RESULT_FAILED;
635 gate_ui_panel_t** ptr_ptr_panel = (gate_ui_panel_t**)gate_arraylist_get(tabctrl->pages, index);
636 if (ptr_ptr_panel && ptr_panel)
637 {
638 *ptr_panel = *ptr_ptr_panel;
639 ret = GATE_RESULT_OK;
640 }
641 return ret;
642 }
643 void* gate_ui_tabctrl_get_tab_param(gate_ui_tabctrl_t* tabctrl, gate_size_t index)
644 {
645 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&tabctrl->ctrl);
646 TCITEM tcitem;
647 gate_mem_clear(&tcitem, sizeof(tcitem));
648 tcitem.mask = TCIF_PARAM;
649 if (TabCtrl_GetItem(hwnd, (int)index, &tcitem))
650 {
651 return (void*)tcitem.lParam;
652 }
653 return NULL;
654 }
655
656 #endif
657
658
659 #if defined(GATE_UI_GTK)
660
661 #include "gate/ui/gateui_gtk.h"
662
663
664 static gboolean gate_ui_gtk_tabctrl_refresh_current_page(gpointer user_data)
665 {
666 gate_ui_tabctrl_t* tab_ctrl = (gate_ui_tabctrl_t*)user_data;
667 if (tab_ctrl)
668 {
669 gate_size_t selected_index = gate_ui_tabctrl_get_selected_tab(tab_ctrl);
670 if (selected_index != GATE_UI_TABCTRL_INVALID_INDEX)
671 {
672 gate_ui_panel_t* ptr_panel = NULL;
673 gate_ui_tabctrl_get_tab_panel(tab_ctrl, selected_index, &ptr_panel);
674 if (ptr_panel)
675 {
676 gate_ui_panel_refresh(ptr_panel);
677 }
678 }
679 }
680 return FALSE; /* FALSE means: do not invoke this callback again (until next call to g_idle_add()) */
681 }
682
683
684 static void gate_ui_gtk_tabctrl_on_select(GtkNotebook* notebook, GtkWidget* page, guint page_num, gpointer user_data)
685 {
686 gate_ui_tabctrl_t* tab_ctrl = (gate_ui_tabctrl_t*)user_data;
687 if (tab_ctrl)
688 {
689 g_idle_add(&gate_ui_gtk_tabctrl_refresh_current_page, tab_ctrl);
690
691 if (tab_ctrl->on_select != NULL)
692 {
693 tab_ctrl->on_select(&tab_ctrl->ctrl, page_num);
694 }
695 }
696 }
697 /*
698 static void gate_ui_gtk_tabctrl_on_resize(GtkContainer* container, gpointer user_data)
699 {
700 gate_ui_tabctrl_t* tab_ctrl = (gate_ui_tabctrl_t*)user_data;
701 gate_ui_panel_t* ptr_panel = NULL;
702 gate_size_t selected_index = 0;
703 if(tab_ctrl)
704 {
705 g_idle_add(&gate_ui_gtk_tabctrl_refresh_current_page, tab_ctrl);
706 }
707 }
708
709 static gboolean gate_ui_gtk_tabctrl_event_configure(GtkWidget* widget, GdkEvent* event, gpointer user_data)
710 {
711 gate_ui_tabctrl_t* tab_ctrl = (gate_ui_tabctrl_t*)user_data;
712 gate_ui_panel_t* ptr_panel = NULL;
713 gate_size_t selected_index = 0;
714 if(tab_ctrl)
715 {
716 g_idle_add(&gate_ui_gtk_tabctrl_refresh_current_page, tab_ctrl);
717 }
718 return FALSE;
719 }
720 */
721
722
723 static gate_result_t gate_ui_gtk_tabctrl_refresh(gate_ui_ctrl_t* ctrl)
724 {
725 gate_ui_tabctrl_t* tab_ctrl = (gate_ui_tabctrl_t*)ctrl;
726 gate_size_t selected_index = 0;
727 if (tab_ctrl)
728 {
729 g_idle_add(&gate_ui_gtk_tabctrl_refresh_current_page, tab_ctrl);
730 }
731 return gate_ui_gtk_ctrl_refresh(ctrl);
732 }
733 static gate_result_t gate_ui_gtk_tabctrl_destroy(gate_ui_ctrl_t* ctrl)
734 {
735 gate_ui_tabctrl_t* tab_ctrl = (gate_ui_tabctrl_t*)ctrl;
736 gate_ui_tabctrl_clear(tab_ctrl);
737 return gate_ui_gtk_ctrl_destroy_native(&tab_ctrl->ctrl);
738 }
739
740 static gate_ui_gtk_dispatcher_t gate_ui_gtk_tabctrl_dispatcher =
741 {
742 NULL /*get_text_length*/,
743 NULL /*get_text*/,
744 NULL /*set_text*/,
745 NULL /*get_state*/,
746 NULL /*set_state*/,
747 &gate_ui_gtk_tabctrl_refresh,
748 &gate_ui_gtk_tabctrl_destroy
749 };
750
751
752
753
754
755 gate_result_t gate_ui_tabctrl_create(gate_ui_tabctrl_t* tabctrl, gate_ui_ctrl_t* parent,
756 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
757 {
758 gate_result_t ret = GATE_RESULT_OK;
759
760 do
761 {
762 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
763 GtkWidget* widget;
764
765 gate_mem_clear(tabctrl, sizeof(gate_ui_tabctrl_t));
766
767 tabctrl->pages = NULL;
768
769 widget = gtk_notebook_new();
770 if (widget == NULL)
771 {
772 ret = GATE_RESULT_FAILED;
773 break;
774 }
775
776 ret = gate_ui_gtk_ctrl_init(&tabctrl->ctrl, widget, host, userparam, parent,
777 &gate_ui_gtk_tabctrl_dispatcher, false, false, position, &flags);
778 GATE_BREAK_IF_FAILED(ret);
779
780 gtk_notebook_set_scrollable(GTK_NOTEBOOK(widget), TRUE);
781 gtk_notebook_popup_enable(GTK_NOTEBOOK(widget));
782
783 gtk_widget_add_events(widget, GDK_STRUCTURE_MASK);
784
785 g_signal_connect(G_OBJECT(widget), "switch-page", G_CALLBACK(gate_ui_gtk_tabctrl_on_select), (gpointer)tabctrl);
786 /*
787 g_signal_connect(G_OBJECT(widget), "check-resize", G_CALLBACK(gate_ui_gtk_tabctrl_on_resize), (gpointer)tabctrl);
788 g_signal_connect(G_OBJECT(widget), "configure-event", G_CALLBACK(gate_ui_gtk_tabctrl_event_configure), (gpointer)tabctrl);
789 */
790 /*g_signal_connect(G_OBJECT(widget), "destroy", G_CALLBACK(gate_ui_gtk_tabctrl_destroy), (gpointer)tabctrl);*/
791
792 } while (0);
793
794 return ret;
795 }
796 gate_result_t gate_ui_tabctrl_add_tab(gate_ui_tabctrl_t* tabctrl, gate_string_t const* text, void* itemparam)
797 {
798 return gate_ui_tabctrl_insert_tab(tabctrl, (gate_size_t)-1, text, itemparam);
799 }
800 gate_result_t gate_ui_tabctrl_insert_tab(gate_ui_tabctrl_t* tabctrl, gate_size_t at_index, gate_string_t const* text, void* itemparam)
801 {
802 gate_result_t ret = GATE_RESULT_OK;
803 gate_ui_panel_t* new_panel = NULL;
804 GtkWidget* panel_widget = NULL;
805
806
807 do
808 {
809 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&tabctrl->ctrl);
810 char text_buffer[4096];
811 gint pg_index;
812 if (tabctrl->pages == NULL)
813 {
814 tabctrl->pages = gate_arraylist_create(sizeof(gate_ui_panel_t*), NULL, 16, NULL, NULL);
815 if (tabctrl->pages == NULL)
816 {
817 ret = GATE_RESULT_OUTOFMEMORY;
818 break;
819 }
820 }
821
822 GATE_STRING_TO_BUFFER(text, text_buffer);
823 new_panel = gate_mem_alloc(sizeof(gate_ui_panel_t));
824 if (!new_panel)
825 {
826 ret = GATE_RESULT_OUTOFMEMORY;
827 break;
828 }
829 gate_mem_clear(new_panel, sizeof(gate_ui_panel_t));
830
831 ret = gate_ui_panel_create(new_panel, &tabctrl->ctrl, NULL, GATE_UI_FLAG_ENABLED | GATE_UI_FLAG_VISIBLE | GATE_UI_FLAG_RESIZABLE | GATE_UI_FLAG_NOPARENT, tabctrl);
832 GATE_BREAK_IF_FAILED(ret);
833 panel_widget = GATE_UI_GTK_GET_CTRL_WIDGET(&new_panel->ctrl);
834 gtk_widget_show_all(panel_widget);
835
836 if (at_index == GATE_UI_TABCTRL_INVALID_INDEX)
837 {
838 gate_arraylist_add(tabctrl->pages, &new_panel);
839 pg_index = -1;
840 }
841 else
842 {
843 pg_index = (gint)(gate_intptr_t)at_index;
844 gate_arraylist_insert(tabctrl->pages, at_index, &new_panel, 1);
845 }
846
847 pg_index = gtk_notebook_insert_page(GTK_NOTEBOOK(widget), panel_widget, gtk_label_new(text_buffer), pg_index);
848
849 ret = GATE_RESULT_OK;
850 panel_widget = NULL;
851 new_panel = NULL;
852 g_idle_add(&gate_ui_gtk_tabctrl_refresh_current_page, tabctrl);
853
854 } while (0);
855
856
857 if (panel_widget != NULL)
858 {
859 gtk_widget_destroy(panel_widget);
860 }
861
862 if (new_panel != NULL)
863 {
864 gate_mem_dealloc(new_panel);
865 }
866
867 return ret;
868 }
869 gate_size_t gate_ui_tabctrl_get_tab_count(gate_ui_tabctrl_t* tabctrl)
870 {
871 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&tabctrl->ctrl);
872 gint count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(widget));
873 return (gate_size_t)count;
874 }
875 gate_result_t gate_ui_tabctrl_remove_tab(gate_ui_tabctrl_t* tabctrl, gate_size_t index)
876 {
877 gate_result_t ret = GATE_RESULT_FAILED;
878 do
879 {
880 gate_ui_panel_t* ptr_panel = NULL;
881 gate_ui_panel_t** ptr;
882 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&tabctrl->ctrl);
883
884 if (!widget)
885 {
886 ret = GATE_RESULT_INVALIDSTATE;
887 break;
888 }
889
890 ret = gate_ui_tabctrl_get_tab_panel(tabctrl, index, &ptr_panel);
891 GATE_BREAK_IF_FAILED(ret);
892
893 ptr = (gate_ui_panel_t**)gate_arraylist_get(tabctrl->pages, index);
894 if (!ptr)
895 {
896 ret = GATE_RESULT_NOMATCH;
897 break;
898 }
899
900 if (*ptr != ptr_panel)
901 {
902 ret = GATE_RESULT_CRITICALERROR;
903 break;
904 }
905
906 /*gtk_notebook_detach_tab(GTK_NOTEBOOK(widget), GATE_UI_GTK_GET_CTRK_WIDGET(&ptr->ctrl));*/
907 gate_ui_ctrl_destroy(&ptr_panel->ctrl);
908 ret = gate_arraylist_remove(tabctrl->pages, index, 1);
909 if (GATE_SUCCEEDED(ret))
910 {
911 gate_mem_dealloc(ptr_panel);
912 }
913 } while (0);
914
915 return ret;
916 }
917 gate_result_t gate_ui_tabctrl_clear(gate_ui_tabctrl_t* tabctrl)
918 {
919 gate_result_t ret = GATE_RESULT_OK;
920 while (GATE_SUCCEEDED(ret) && (gate_ui_tabctrl_get_tab_count(tabctrl) > 0))
921 {
922 ret = gate_ui_tabctrl_remove_tab(tabctrl, 0);
923 }
924 if (GATE_SUCCEEDED(ret))
925 {
926 if (tabctrl->pages)
927 {
928 gate_size_t ndx;
929 gate_size_t len = gate_arraylist_length(tabctrl->pages);
930 for (ndx = 0; ndx != len; ++ndx)
931 {
932 gate_ui_panel_t** ptr_panel = (gate_ui_panel_t**)gate_arraylist_get(tabctrl->pages, ndx);
933 if (ptr_panel && *ptr_panel)
934 {
935 gate_mem_dealloc(*ptr_panel);
936 }
937 }
938
939 }
940
941 gate_arraylist_release(tabctrl->pages);
942 tabctrl->pages = NULL;
943 }
944 return ret;
945 }
946 gate_size_t gate_ui_tabctrl_get_selected_tab(gate_ui_tabctrl_t* tabctrl)
947 {
948 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&tabctrl->ctrl);
949 gint selected = gtk_notebook_get_current_page(GTK_NOTEBOOK(widget));
950 if (selected < 0)
951 {
952 return GATE_UI_TABCTRL_INVALID_INDEX;
953 }
954 else
955 {
956 return (gate_size_t)selected;
957 }
958 }
959 gate_result_t gate_ui_tabctrl_set_selected_tab(gate_ui_tabctrl_t* tabctrl, gate_size_t index)
960 {
961 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&tabctrl->ctrl);
962 gtk_notebook_set_current_page(GTK_NOTEBOOK(widget), (gint)index);
963 return GATE_RESULT_OK;
964 }
965
966 gate_result_t gate_ui_tabctrl_get_tab_text(gate_ui_tabctrl_t* tabctrl, gate_size_t index, gate_string_t* text)
967 {
968 gate_result_t ret = GATE_RESULT_FAILED;
969 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&tabctrl->ctrl);
970
971 if (widget)
972 {
973 GtkWidget* child = gtk_notebook_get_nth_page(GTK_NOTEBOOK(widget), (gint)index);
974 if (child)
975 {
976 GtkWidget* label = gtk_notebook_get_tab_label(GTK_NOTEBOOK(widget), child);
977 if (label && GTK_IS_LABEL(label))
978 {
979 gchar const* text_buffer = gtk_label_get_text(GTK_LABEL(label));
980 if (NULL == gate_string_create(text, text_buffer, gate_str_length(text_buffer)))
981 {
982 ret = GATE_RESULT_OUTOFMEMORY;
983 }
984 else
985 {
986 ret = GATE_RESULT_OK;
987 }
988 }
989 }
990 }
991 return ret;
992 }
993 gate_result_t gate_ui_tabctrl_set_tab_text(gate_ui_tabctrl_t* tabctrl, gate_size_t index, gate_string_t const* text)
994 {
995 gate_result_t ret = GATE_RESULT_FAILED;
996 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&tabctrl->ctrl);
997
998 if (widget)
999 {
1000 GtkWidget* child = gtk_notebook_get_nth_page(GTK_NOTEBOOK(widget), (gint)index);
1001 if (child)
1002 {
1003 char text_buffer[4096];
1004 GATE_STRING_TO_BUFFER(text, text_buffer);
1005 gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(widget), child, text_buffer);
1006 ret = GATE_RESULT_OK;
1007 }
1008 }
1009 return ret;
1010 }
1011 gate_result_t gate_ui_tabctrl_get_tab_panel(gate_ui_tabctrl_t* tabctrl, gate_size_t index, gate_ui_panel_t** ptr_panel)
1012 {
1013 gate_result_t ret = GATE_RESULT_FAILED;
1014 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&tabctrl->ctrl);
1015
1016 if (widget)
1017 {
1018 void* ptr = gate_arraylist_get(tabctrl->pages, index);
1019 if (ptr && ptr_panel)
1020 {
1021 *ptr_panel = *((gate_ui_panel_t**)ptr);
1022 ret = GATE_RESULT_OK;
1023 }
1024 }
1025 return ret;
1026 }
1027 void* gate_ui_tabctrl_get_tab_param(gate_ui_tabctrl_t* tabctrl, gate_size_t index)
1028 {
1029 return NULL;
1030 }
1031 gate_result_t gate_ui_tabctrl_refresh(gate_ui_tabctrl_t* tabctrl)
1032 {
1033 gate_size_t selected = gate_ui_tabctrl_get_selected_tab(tabctrl);
1034 if (selected != GATE_UI_TABCTRL_INVALID_INDEX)
1035 {
1036 gate_ui_panel_t* ptr_panel = NULL;
1037 gate_ui_tabctrl_get_tab_panel(tabctrl, selected, &ptr_panel);
1038 if (ptr_panel)
1039 {
1040 gate_ui_panel_refresh(ptr_panel);
1041 }
1042 }
1043
1044 return GATE_RESULT_OK;
1045 }
1046
1047 #endif
1048
1049
1050
1051 #if defined(GATE_UI_MOTIF)
1052
1053 #include "gate/ui/gateui_motif.h"
1054 #include <Xm/Notebook.h>
1055 #include <Xm/PushB.h>
1056
1057 1 static gate_result_t motif_tabctrl_destroy(gate_ui_ctrl_t* ctrl)
1058 {
1059 1 gate_ui_tabctrl_t* tc = (gate_ui_tabctrl_t*)ctrl;
1060 Widget w;
1061
1062
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(tc != NULL);
1063 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
1064
1065 1 gate_ui_tabctrl_clear(tc);
1066 1 XtUnmanageChild(w);
1067 1 XtDestroyWidget(w);
1068
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (tc->pages)
1069 {
1070 1 gate_arraylist_release(tc->pages);
1071 1 tc->pages = NULL;
1072 }
1073 1 GATE_UI_MOTIF_SET_CTRL_WIDGET(ctrl, NULL);
1074 1 GATE_UI_MOTIF_SET_CTRL_CONTAINER(ctrl, NULL);
1075 1 return GATE_RESULT_OK;
1076 }
1077
1078 static gate_result_t motif_tabctrl_get_children(gate_ui_ctrl_t* ctrl, void** ptr_to_widgetlist, gate_size_t* ptr_to_children_count)
1079 {
1080 if (ptr_to_widgetlist)
1081 {
1082 *ptr_to_widgetlist = NULL;
1083 }
1084
1085 if (ptr_to_children_count)
1086 {
1087 *ptr_to_children_count = 0;
1088 }
1089 return GATE_RESULT_OK;
1090 }
1091
1092 static gate_ui_motif_dispatcher_t tabctrl_dispatcher =
1093 {
1094 &motif_tabctrl_destroy,
1095 NULL,
1096 NULL,
1097 NULL,
1098 NULL,
1099 NULL,
1100 &motif_tabctrl_get_children
1101 };
1102
1103 1 gate_result_t gate_ui_tabctrl_create(gate_ui_tabctrl_t* tabctrl, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
1104 gate_uint32_t flags, void* userparam)
1105 {
1106 1 gate_result_t ret = GATE_RESULT_FAILED;
1107
1108 do
1109 {
1110 Arg args[12];
1111 1 unsigned args_count = 0;
1112
1113
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!tabctrl || !parent)
1114 {
1115 ret = GATE_RESULT_INVALIDARG;
1116 break;
1117 }
1118
1119 1 gate_mem_clear(tabctrl, sizeof(gate_ui_tabctrl_t));
1120 1 tabctrl->pages = gate_arraylist_create(sizeof(gate_ui_panel_t*), NULL, 0, NULL, NULL);
1121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (tabctrl->pages == NULL)
1122 {
1123 ret = GATE_RESULT_OUTOFMEMORY;
1124 break;
1125 }
1126
1127 1 XtSetArg(args[args_count], XmNorientation, XmVERTICAL); ++args_count;
1128 1 XtSetArg(args[args_count], XmNbackPagePlacement, XmTOP_RIGHT); ++args_count;
1129 1 XtSetArg(args[args_count], XmNbindingType, XmNONE); ++args_count;
1130 1 XtSetArg(args[args_count], XmNfirstPageNumber, 1); ++args_count;
1131 1 XtSetArg(args[args_count], XmNlastPageNumber, 1); ++args_count;
1132 1 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
1133 1 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1134 1 XtSetArg(args[args_count], XmNframeShadowThickness, 1); ++args_count;
1135
1136 1 XtSetArg(args[args_count], XmNinnerMarginWidth, 2); ++args_count;
1137 1 XtSetArg(args[args_count], XmNinnerMarginHeight, 2); ++args_count;
1138
1139 1 ret = gate_ui_motif_ctrl_create(&tabctrl->ctrl, xmNotebookWidgetClass, userparam, NULL, parent,
1140 position, &flags, false, &tabctrl_dispatcher, args, args_count);
1141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(ret))
1142 {
1143 gate_arraylist_release(tabctrl->pages);
1144 }
1145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1146 } while (0);
1147
1148 1 return ret;
1149 }
1150
1151 5 gate_result_t gate_ui_tabctrl_add_tab(gate_ui_tabctrl_t* tabctrl, gate_string_t const* text, void* itemparam)
1152 {
1153 5 gate_result_t ret = GATE_RESULT_FAILED;
1154 5 Widget tab = NULL;
1155 gate_ui_panel_t* ptr_panel;
1156
1157 do
1158 {
1159 5 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&tabctrl->ctrl);
1160 5 Widget page = NULL;
1161 5 int page_num = (int)gate_arraylist_length(tabctrl->pages) + 1;
1162 5 XtVaSetValues(w, XmNlastPageNumber, page_num, NULL);
1163
1164 5 ptr_panel = gate_mem_alloc(sizeof(gate_ui_panel_t));
1165
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (NULL == ptr_panel)
1166 {
1167 ret = GATE_RESULT_OUTOFMEMORY;
1168 break;
1169 }
1170 5 gate_mem_clear(ptr_panel, sizeof(gate_ui_panel_t));
1171
1172 5 ret = gate_ui_panel_create(ptr_panel, &tabctrl->ctrl, NULL,
1173 GATE_UI_FLAG_ENABLED | GATE_UI_FLAG_VISIBLE, itemparam);
1174
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (GATE_FAILED(ret))
1175 {
1176 gate_mem_clear(ptr_panel, sizeof(gate_ui_panel_t));
1177 break;
1178 }
1179
1180
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (NULL == gate_arraylist_add(tabctrl->pages, &ptr_panel))
1181 {
1182 ret = GATE_RESULT_OUTOFMEMORY;
1183 break;
1184 }
1185
1186 5 page = GATE_UI_MOTIF_GET_CTRL_WIDGET(&ptr_panel->ctrl);
1187 5 XtVaSetValues(page,
1188 XmNnotebookChildType, XmPAGE,
1189 XmNpageNumber, page_num,
1190 NULL);
1191
1192 5 tab = XmVaCreatePushButton(w, NULL,
1193 XmNnotebookChildType, XmMAJOR_TAB,
1194 XmNpageNumber, page_num,
1195 XmNshadowThickness, 1,
1196 XmNhighlightThickness, 1,
1197 NULL);
1198
1199
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (NULL == tab)
1200 {
1201 ret = GATE_RESULT_OUTOFRESOURCES;
1202 break;
1203 }
1204 5 gate_ui_motif_widget_set_label(tab, text);
1205 5 XtManageChild(tab);
1206
1207 5 tab = NULL;
1208 5 ptr_panel = NULL;
1209 5 ret = GATE_RESULT_OK;
1210
1211 5 gate_ui_tabctrl_refresh(tabctrl);
1212 } while (0);
1213
1214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (tab != NULL)
1215 {
1216 XtUnmanageChild(tab);
1217 XtDestroyWidget(tab);
1218 }
1219
1220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ptr_panel != NULL)
1221 {
1222 if (gate_ui_ctrl_is_created(&ptr_panel->ctrl))
1223 {
1224 gate_ui_ctrl_destroy(&ptr_panel->ctrl);
1225 }
1226 gate_mem_dealloc(ptr_panel);
1227 }
1228
1229 5 return ret;
1230 }
1231
1232 gate_result_t gate_ui_tabctrl_insert_tab(gate_ui_tabctrl_t* tabctrl, gate_size_t at_index, gate_string_t const* text, void* itemparam)
1233 {
1234 return gate_ui_tabctrl_add_tab(tabctrl, text, itemparam);
1235 }
1236 2 gate_size_t gate_ui_tabctrl_get_tab_count(gate_ui_tabctrl_t* tabctrl)
1237 {
1238 2 return gate_arraylist_length(tabctrl->pages);
1239 }
1240
1241 9 static Widget find_tabctrl_tab(Widget w, int find_page_num)
1242 {
1243 9 Cardinal num_children = 0;
1244 9 WidgetList children = NULL;
1245
1246 9 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &num_children, NULL, NULL);
1247
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 while (num_children-- > 0)
1248 {
1249 33 Widget child = children[num_children];
1250
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (child)
1251 {
1252 33 unsigned char child_type = 0;
1253 33 int cur_pg_num = 0;
1254 33 XtVaGetValues(child, XmNnotebookChildType, &child_type, XmNpageNumber, &cur_pg_num, NULL);
1255
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 12 times.
33 if (XmMAJOR_TAB == child_type)
1256 {
1257
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 12 times.
21 if (cur_pg_num == find_page_num)
1258 {
1259 9 return child;
1260 }
1261 }
1262 }
1263 }
1264 return NULL;
1265 }
1266
1267 1 gate_result_t gate_ui_tabctrl_remove_tab(gate_ui_tabctrl_t* tabctrl, gate_size_t index)
1268 {
1269 1 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&tabctrl->ctrl);
1270 1 Cardinal num_children = 0;
1271 1 WidgetList children = NULL;
1272 1 int page_num = index + 1;
1273 1 Widget tab = find_tabctrl_tab(w, page_num);
1274 1 gate_ui_panel_t** ptr_panel = (gate_ui_panel_t**)gate_arraylist_get(tabctrl->pages, index);
1275
1276
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if ((ptr_panel == NULL) || (tab == NULL))
1277 {
1278 return GATE_RESULT_NOTAVAILABLE;
1279 }
1280 1 XtDestroyWidget(tab);
1281 1 gate_ui_ctrl_destroy(&(*ptr_panel)->ctrl);
1282
1283 1 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &num_children, NULL, NULL);
1284
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 while (num_children-- > 0)
1285 {
1286 13 Widget child = children[num_children];
1287 13 int cur_page_num = 0;
1288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!child)
1289 {
1290 continue;
1291 }
1292 13 XtVaGetValues(child, XmNpageNumber, &cur_page_num, NULL);
1293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (cur_page_num > page_num)
1294 {
1295 --cur_page_num;
1296 XtVaSetValues(child, XmNpageNumber, cur_page_num, NULL);
1297 }
1298 }
1299 1 gate_arraylist_remove(tabctrl->pages, index, 1);
1300 1 return GATE_RESULT_OK;
1301 }
1302
1303 1 gate_size_t gate_ui_tabctrl_get_selected_tab(gate_ui_tabctrl_t* tabctrl)
1304 {
1305 1 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&tabctrl->ctrl);
1306 1 int page_num = 0;
1307 1 XtVaGetValues(w, XmNcurrentPageNumber, &page_num, NULL);
1308
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (page_num > 0)
1309 {
1310 1 return (gate_size_t)(page_num - 1);
1311 }
1312 return 0;
1313 }
1314
1315 3 gate_result_t gate_ui_tabctrl_set_selected_tab(gate_ui_tabctrl_t* tabctrl, gate_size_t index)
1316 {
1317 3 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&tabctrl->ctrl);
1318 3 int page_num = (int)(index + 1);
1319 3 XtVaSetValues(w, XmNcurrentPageNumber, page_num, NULL);
1320 3 return GATE_RESULT_OK;
1321 }
1322
1323 1 gate_result_t gate_ui_tabctrl_clear(gate_ui_tabctrl_t* tabctrl)
1324 {
1325 Widget w;
1326
1327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(tabctrl != NULL);
1328 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&tabctrl->ctrl);
1329
1330
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (w != NULL)
1331 {
1332 1 WidgetList children = NULL;
1333 1 Cardinal num_children = 0;
1334 1 int const page_count = 0;
1335
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (tabctrl->pages != NULL)
1336 {
1337 1 gate_size_t len = gate_arraylist_length(tabctrl->pages);
1338
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 while (len-- > 0)
1339 {
1340 4 gate_ui_panel_t** pptr_panel = (gate_ui_panel_t**)gate_arraylist_get(tabctrl->pages, len);
1341
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 gate_ui_panel_t* ptr_panel = pptr_panel ? *pptr_panel : NULL;
1342
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ptr_panel == NULL)
1343 {
1344 continue;
1345 }
1346 4 gate_ui_motif_ctrl_destroy(&ptr_panel->ctrl);
1347 4 gate_mem_dealloc(ptr_panel);
1348 }
1349 1 gate_arraylist_clear(tabctrl->pages);
1350 }
1351
1352 /* find pushbutton tab widget that need to be destroyed too */
1353 1 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &num_children, NULL, NULL);
1354
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 while (num_children-- > 0)
1355 {
1356 9 Widget child_widget = children[num_children];
1357
1358
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (child_widget)
1359 {
1360 9 int child_type = 0;
1361 9 XtVaGetValues(child_widget, XmNnotebookChildType, &child_type, NULL, NULL);
1362
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
9 if ((child_type == XmMAJOR_TAB) && (XtIsSubclass(child_widget, xmPushButtonWidgetClass)))
1363 {
1364 4 gate_ui_motif_widget_destroy_children(child_widget, true);
1365 }
1366 }
1367 }
1368
1369 1 XtVaSetValues(w, XmNlastPageNumber, page_count, NULL);
1370 }
1371 1 return GATE_RESULT_OK;
1372 }
1373
1374 4 gate_result_t gate_ui_tabctrl_get_tab_text(gate_ui_tabctrl_t* tabctrl, gate_size_t index, gate_string_t* text)
1375 {
1376 Widget w;
1377 Widget tab;
1378
1379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATE_DEBUG_ASSERT(tabctrl != NULL);
1380 4 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&tabctrl->ctrl);
1381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATE_DEBUG_ASSERT(w != NULL);
1382 4 tab = find_tabctrl_tab(w, (int)(index + 1));
1383
1384
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (NULL == tab)
1385 {
1386 return GATE_RESULT_NOTAVAILABLE;
1387 }
1388 4 return gate_ui_motif_widget_get_label(tab, text);
1389 }
1390
1391 4 gate_result_t gate_ui_tabctrl_set_tab_text(gate_ui_tabctrl_t* tabctrl, gate_size_t index, gate_string_t const* text)
1392 {
1393 4 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&tabctrl->ctrl);
1394 4 Widget tab = find_tabctrl_tab(w, (int)(index + 1));
1395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (NULL == tab)
1396 {
1397 return GATE_RESULT_NOTAVAILABLE;
1398 }
1399 4 return gate_ui_motif_widget_set_label(tab, text);
1400 }
1401
1402 4 gate_result_t gate_ui_tabctrl_get_tab_panel(gate_ui_tabctrl_t* tabctrl, gate_size_t index, gate_ui_panel_t** ptr_panel)
1403 {
1404 4 gate_ui_panel_t** panel = (gate_ui_panel_t**)gate_arraylist_get(tabctrl->pages, index);
1405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!panel)
1406 {
1407 return GATE_RESULT_NOTAVAILABLE;
1408 }
1409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!*panel)
1410 {
1411 return GATE_RESULT_NOTAVAILABLE;
1412 }
1413
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (ptr_panel)
1414 {
1415 4 *ptr_panel = *panel;
1416 }
1417 4 return GATE_RESULT_OK;
1418 }
1419
1420 void* gate_ui_tabctrl_get_tab_param(gate_ui_tabctrl_t* tabctrl, gate_size_t index)
1421 {
1422 gate_ui_panel_t** panel = (gate_ui_panel_t**)gate_arraylist_get(tabctrl->pages, index);
1423 if (!panel)
1424 {
1425 return NULL;
1426 }
1427 if (!*panel)
1428 {
1429 return NULL;
1430 }
1431 return GATE_UI_MOTIF_GET_CTRL_USER_PARAM(&(*panel)->ctrl);
1432 }
1433
1434 5 gate_result_t gate_ui_tabctrl_refresh(gate_ui_tabctrl_t* tabctrl)
1435 {
1436 5 return gate_ui_motif_ctrl_refresh(&tabctrl->ctrl);
1437 }
1438
1439 #endif /* GATE_UI_MOTIF */
1440