GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/tabs.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 171 0.0%
Functions: 0 15 0.0%
Branches: 0 66 0.0%

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