GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/tabs.c
Date: 2026-10-19 17:06:30
Exec Total Coverage
Lines: 155 194 79.9%
Functions: 14 16 87.5%
Branches: 47 88 53.4%

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