GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/toolbars.c
Date: 2026-03-20 22:56:14
Exec Total Coverage
Lines: 71 90 78.9%
Functions: 6 9 66.7%
Branches: 18 40 45.0%

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/toolbars.h"
30 #include "gate/results.h"
31
32 #if defined(GATE_UI_WINAPI)
33
34 #ifndef _WIN32_IE
35 # if defined(GATE_COMPILER_TCC)
36 # define _WIN32_IE 0x0501
37 # else
38 # define _WIN32_IE 0x0400
39 # endif
40 #endif
41
42 #include "gate/ui/gateui_winapi.h"
43 #include "gate/ui/graphics.h"
44 #include "gate/platforms.h"
45
46 #if defined(GATE_SYS_WIN16)
47
48 typedef struct tagNMHDR
49 {
50 HWND hwndFrom;
51 UINT_PTR idFrom;
52 UINT code;
53 } NMHDR;
54
55 typedef struct tagNMMOUSE
56 {
57 NMHDR hdr;
58 DWORD dwItemSpec;
59 DWORD dwItemData;
60 POINT pt;
61 LPARAM dwHitInfo;
62 } NMMOUSE, * LPNMMOUSE;
63
64 typedef struct _TBBUTTON
65 {
66 int iBitmap;
67 int idCommand;
68 BYTE fsState;
69 BYTE fsStyle;
70 DWORD dwData;
71 INT_PTR iString;
72 } TBBUTTON, * LPTBBUTTON;
73
74 typedef struct
75 {
76 UINT cbSize;
77 DWORD dwMask;
78 int idCommand;
79 int iImage;
80 BYTE fsState;
81 BYTE fsStyle;
82 WORD cx;
83 DWORD lParam;
84 LPSTR pszText;
85 int cchText;
86 } TBBUTTONINFO, * LPTBBUTTONINFO;
87
88 #define NM_FIRST (0U- 0U)
89 #define NM_LAST (0U- 99U)
90 #define TBN_FIRST (0U-700U)
91 #define TBN_LAST (0U-720U)
92 #define WM_NOTIFY 0x004E
93 #define NM_CLICK (NM_FIRST-2)
94 #define NM_DBLCLK (NM_FIRST-3)
95 #define TB_GETBUTTONINFO (WM_USER + 65)
96 #define TB_SETBUTTONINFO (WM_USER + 66)
97 #define TB_AUTOSIZE (WM_USER + 33)
98 #define TBIF_IMAGE 0x00000001
99 #define TBIF_TEXT 0x00000002
100 #define TBIF_STATE 0x00000004
101 #define TBIF_STYLE 0x00000008
102 #define TBIF_LPARAM 0x00000010
103 #define TBIF_COMMAND 0x00000020
104 #define TBIF_SIZE 0x00000040
105
106 #define TBIF_BYINDEX 0x80000000
107
108 #define TBSTYLE_BUTTON 0x0000
109 #define TBSTYLE_SEP 0x0001
110 #define TBSTYLE_CHECK 0x0002
111 #define TBSTYLE_GROUP 0x0004
112 #define TBSTYLE_CHECKGROUP (TBSTYLE_GROUP | TBSTYLE_CHECK)
113 #define TBSTYLE_DROPDOWN 0x0008
114 #define TBSTYLE_AUTOSIZE 0x0010
115 #define TBSTYLE_NOPREFIX 0x0020
116
117 #define TBSTYLE_TOOLTIPS 0x0100
118 #define TBSTYLE_WRAPABLE 0x0200
119 #define TBSTYLE_ALTDRAG 0x0400
120 #define TBSTYLE_FLAT 0x0800
121 #define TBSTYLE_LIST 0x1000
122 #define TBSTYLE_CUSTOMERASE 0x2000
123 #define TBSTYLE_REGISTERDROP 0x4000
124 #define TBSTYLE_TRANSPARENT 0x8000
125
126 #define CCS_NORESIZE 0x00000004L
127 #define CCS_NOPARENTALIGN 0x00000008L
128
129 #define TBSTATE_CHECKED 0x01
130 #define TBSTATE_PRESSED 0x02
131 #define TBSTATE_ENABLED 0x04
132 #define TBSTATE_HIDDEN 0x08
133 #define TBSTATE_INDETERMINATE 0x10
134 #define TBSTATE_WRAP 0x20
135 #define TBSTATE_ELLIPSES 0x40
136 #define TBSTATE_MARKED 0x80
137
138 #define TB_ADDBUTTONS (WM_USER + 20)
139 #define TB_INSERTBUTTON (WM_USER + 21)
140
141 #define TB_DELETEBUTTON (WM_USER + 22)
142 #define TB_GETBUTTON (WM_USER + 23)
143 #define TB_BUTTONCOUNT (WM_USER + 24)
144 #define TB_COMMANDTOINDEX (WM_USER + 25)
145
146 #define TOOLBARCLASSNAME "ToolbarWindow"
147
148 #else
149 # include <commctrl.h>
150 #endif
151
152
153 #ifndef TBCDRF_USECDCOLORS
154 #define TBCDRF_USECDCOLORS 0x00800000
155 #endif
156
157 static gate_bool_t gate_ui_toolbar_events(void* hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult)
158 {
159
160 if ((ctrl != NULL) && (hwnd != NULL))
161 {
162 HWND hwndCtrl = GATE_UI_WINAPI_GET_HWND(ctrl);
163 if (NULL != hwndCtrl)
164 {
165 gate_ui_toolbar_t* toolbar = (gate_ui_toolbar_t*)ctrl;
166 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(ctrl);
167
168 switch (msg)
169 {
170 case WM_COMMAND:
171 {
172 if ((HWND)lParam == hwndCtrl)
173 {
174 /* toolbar button was clicked */
175 if (toolbar->on_click != NULL)
176 {
177 LPARAM lparam_button = 0;
178 int buttonindex = (int)SendMessage(hwndCtrl, TB_BUTTONCOUNT, 0, 0);
179 while (buttonindex > 0)
180 {
181 TBBUTTON tb_button;
182 --buttonindex;
183 gate_mem_clear(&tb_button, sizeof(tb_button));
184 if (SendMessage(hwndCtrl, TB_GETBUTTON, (WPARAM)buttonindex, (LPARAM)&tb_button))
185 {
186 if (tb_button.idCommand == (WPARAM)LOWORD(wParam))
187 {
188 /* we found our clicked button */
189 toolbar->on_click(&toolbar->ctrl, (gate_ui_toolbar_button_t)(LOWORD(wParam)), (void*)tb_button.dwData);
190 break;
191 }
192 }
193 }
194 }
195 *lresult = 0;
196 return true;
197 }
198 break;
199 }
200 case WM_NOTIFY:
201 {
202 NMHDR* nmhdr = (NMHDR*)(lParam);
203 if (nmhdr->hwndFrom == hwndCtrl)
204 {
205 switch (nmhdr->code)
206 {
207 case NM_DBLCLK:
208 {
209 break;
210 }
211 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
212 case NM_CUSTOMDRAW:
213 {
214 HBRUSH hbgbrush;
215 NMTBCUSTOMDRAW* tb_draw;
216 gate_ui_color_t color;
217 if (!gate_ui_winapi_darkmode_enabled())
218 {
219 break;
220 }
221
222 tb_draw = (NMTBCUSTOMDRAW*)lParam;
223
224 switch (tb_draw->nmcd.dwDrawStage)
225 {
226 case CDDS_PREPAINT:
227 {
228 gate_ui_host_default_color(host, GATE_UI_COLOR_MENUBACKGROUND, &color);
229 hbgbrush = (HBRUSH)gate_ui_winapi_host_get_brush(host, &color);
230 FillRect(tb_draw->nmcd.hdc, &tb_draw->nmcd.rc, hbgbrush);
231
232 *lresult = CDRF_NOTIFYITEMDRAW;
233 return true;
234 }
235 case CDDS_ITEMPREPAINT:
236 {
237 //gate_ui_host_default_color(host, GATE_UI_COLOR_MENUTEXT, &color);
238 //tb_draw->clrText = RGB(color.r, color.g, color.b);
239 //gate_ui_host_default_color(host, GATE_UI_COLOR_SELECTEDMENUTEXT, &color);
240 // tb_draw->clrTextHighlight = RGB(color.r, color.g, color.b);
241
242 if (tb_draw->nmcd.uItemState & CDIS_SELECTED)
243 {
244 gate_ui_host_default_color(host, GATE_UI_COLOR_SELECTEDMENUBACKGROUND, &color);
245 hbgbrush = (HBRUSH)gate_ui_winapi_host_get_brush(host, &color);
246 }
247 else if (tb_draw->nmcd.uItemState & CDIS_HOT)
248 {
249 //gate_ui_host_default_color(host, GATE_UI_COLOR_HOVERMENUBACKGROUND, &color);
250 //hbgbrush = (HBRUSH)gate_ui_winapi_host_get_brush(host, &color);
251 hbgbrush = NULL;
252 }
253 else
254 {
255 gate_ui_host_default_color(host, GATE_UI_COLOR_MENUBACKGROUND, &color);
256 hbgbrush = (HBRUSH)gate_ui_winapi_host_get_brush(host, &color);
257 }
258
259 if (NULL != hbgbrush)
260 {
261 FillRect(tb_draw->nmcd.hdc, &tb_draw->nmcd.rc, hbgbrush);
262 }
263
264 *lresult = CDRF_NEWFONT;
265 return true;
266 }
267 case (CDDS_SUBITEM | CDDS_ITEMPREPAINT):
268 {
269 //SelectObject(tb_draw->nmcd.hdc, CreateSolidBrush(RGB(0, 0, 0)));
270 //FillRect(tb_draw->nmcd.hdc, &tb_draw->nmcd.rc, tb_draw->clrBtnFace);
271 *lresult = CDRF_NEWFONT;
272 return true;
273 }
274 default:
275 {
276 *lresult = CDRF_DODEFAULT;
277 return true;
278 }
279 }
280
281 break;
282 }
283 #endif /* GATE_UI_WINAPI_DARKMODE_SUPPORT */
284 } /* switch */
285 }
286
287 break;
288 }
289 case WM_DESTROY:
290 {
291 #if defined(GATE_SYS_WINCE) || defined(GATE_SYS_WIN16)
292 #else
293 HIMAGELIST himagelist = (HIMAGELIST)SendMessage(hwnd, TB_GETIMAGELIST, 0, 0);
294 if (himagelist)
295 {
296 SendMessage(hwnd, TB_SETIMAGELIST, 0, 0);
297 gate_ui_winapi_imagelist_destroy(himagelist);
298 }
299 #endif
300 gate_ui_winapi_unregister_window(host, hwnd);
301 break;
302 }
303 default:
304 {
305 break;
306 }
307 }
308 }
309 }
310 return false;
311 }
312
313 #if !defined(ILC_COLOR16) && defined(ILC_COLOR)
314 # define ILC_COLOR16 ILC_COLOR
315 #endif
316
317 gate_result_t gate_ui_toolbar_create(gate_ui_toolbar_t* toolbar, gate_ui_ctrl_t* parent,
318 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
319 {
320 gate_result_t ret;
321
322 do
323 {
324 gate_ui_host_t* host = gate_ui_ctrl_get_host(parent);
325 HWND hwndParent;
326 HWND hwnd;
327 gate_uint32_t styles;
328 gate_uint32_t exstyles = 0;
329 #if defined(GATE_SYS_WINCE) || defined(GATE_SYS_WIN16)
330 HINSTANCE hinst;
331 #else
332 HIMAGELIST himagelist;
333 #endif
334
335 if (host == NULL)
336 {
337 ret = GATE_RESULT_INVALIDSTATE;
338 break;
339 }
340 hwndParent = GATE_UI_WINAPI_GET_HWND(parent);
341 if (hwndParent == NULL)
342 {
343 ret = GATE_RESULT_INVALIDSTATE;
344 break;
345 }
346
347 gate_mem_clear(toolbar, sizeof(gate_ui_toolbar_t));
348
349 #if defined(GATE_SYS_WINCE)
350 hinst = (HINSTANCE)GATE_UI_WINAPI_GET_HOST_APPHANDLE(host);
351 styles = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP;
352 hwnd = CreateToolbarEx(hwndParent, styles,
353 0, 0, hinst, 0, NULL, 0, 0, 0, 0, 0, sizeof(TBBUTTON));
354
355 ret = gate_ui_winapi_setup_control(&toolbar->ctrl, host, hwnd, hwndParent, userparam);
356 if (GATE_FAILED(ret))
357 {
358 DestroyWindow(hwnd);
359 break;
360 }
361 #else /* GATE_SYS_WINCE */
362 styles = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP | TBSTYLE_TOOLTIPS | CCS_NOPARENTALIGN | CCS_NORESIZE;
363 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
364 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
365
366 ret = gate_ui_winapi_create(&toolbar->ctrl, host, hwndParent, TOOLBARCLASSNAME, position, styles, exstyles, NULL, userparam, true);
367 if (GATE_FAILED(ret))
368 {
369 break;
370 }
371
372 #if !defined(GATE_SYS_WIN16)
373 hwnd = GATE_UI_WINAPI_GET_HWND(&toolbar->ctrl);
374 SendMessage(hwnd, TB_SETBITMAPSIZE, 0, MAKELONG(16, 16));
375 SendMessage(hwnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
376 himagelist = (HIMAGELIST)gate_ui_winapi_imagelist_create(16, 16, ILC_COLOR16 | ILC_MASK, 0, 0);
377 if (!himagelist)
378 {
379 gate_ui_winapi_destroy(&toolbar->ctrl);
380 ret = GATE_RESULT_OUTOFRESOURCES;
381 break;
382 }
383 SendMessage(hwnd, TB_SETIMAGELIST, 0, (LPARAM)himagelist);
384 #endif
385
386 #endif /* GATE_SYS_WINCE */
387
388 gate_ui_winapi_register_event(host, hwndParent, WM_NOTIFY, &gate_ui_toolbar_events, &toolbar->ctrl);
389 gate_ui_winapi_register_event(host, hwndParent, WM_COMMAND, &gate_ui_toolbar_events, &toolbar->ctrl);
390 gate_ui_winapi_register_event(host, hwnd, WM_DESTROY, &gate_ui_toolbar_events, &toolbar->ctrl);
391 /*
392 gate_ui_winapi_register_event(host, hwndParent, WM_DRAWITEM, &gate_ui_label_events, &label->ctrl);
393 */
394
395 } while (0);
396
397 return ret;
398 }
399
400 static int volatile global_gate_toolbar_id = 0;
401
402 #if !defined(I_IMAGENONE)
403 # define I_IMAGENONE (-2)
404 #endif
405
406 static gate_result_t gate_ui_toolbar_add_bitmap_id(gate_ui_toolbar_t* toolbar, int bitmap_id, void* button_param,
407 gate_ui_toolbar_button_t* button_id)
408 {
409 gate_result_t ret = GATE_RESULT_FAILED;
410 do
411 {
412 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&toolbar->ctrl);
413 TBBUTTON button;
414
415 button.iBitmap = bitmap_id;
416 button.idCommand = ++global_gate_toolbar_id;
417 button.fsState = TBSTATE_ENABLED;
418 button.fsStyle = TBSTYLE_BUTTON;
419 button.dwData = (DWORD_PTR)button_param;
420 button.iString = 0;
421
422 if (FALSE == SendMessage(hwnd, TB_ADDBUTTONS, 1, (LPARAM)&button))
423 {
424 ret = GATE_RESULT_FAILED;
425 }
426 else
427 {
428 TBBUTTONINFO buttoninfo;
429 gate_mem_clear(&buttoninfo, sizeof(buttoninfo));
430 buttoninfo.cbSize = sizeof(buttoninfo);
431 buttoninfo.dwMask = TBIF_COMMAND | TBIF_LPARAM;
432 buttoninfo.idCommand = button.idCommand;
433 buttoninfo.lParam = (LPARAM)button_param;
434 SendMessage(hwnd, TB_SETBUTTONINFO, (WPARAM)button.idCommand, (LPARAM)&buttoninfo);
435
436 SendMessage(hwnd, TB_AUTOSIZE, 0, 0);
437 *button_id = button.idCommand;
438 ret = GATE_RESULT_OK;
439 }
440 } while (0);
441
442 return ret;
443 }
444
445 static gate_result_t gate_ui_toolbar_add_HICON(gate_ui_toolbar_t* toolbar, HICON hicon,
446 void* button_param, gate_ui_toolbar_button_t* button_id)
447 {
448 gate_result_t ret = GATE_RESULT_FAILED;
449 #if !defined(GATE_SYS_WIN16)
450 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&toolbar->ctrl);
451 int bitmap_id;
452 HIMAGELIST himagelist = (HIMAGELIST)SendMessage(hwnd, TB_GETIMAGELIST, 0, 0);
453
454 #if !defined(GATE_SYS_WINCE)
455 if (himagelist == NULL)
456 {
457 /* NT3 or Win9x without IE does not support GETIMAGELIST */
458 ICONINFO iconinfo;
459 TBADDBITMAP bminfo;
460
461 GetIconInfo(hicon, &iconinfo);
462 bminfo.hInst = NULL;
463 bminfo.nID = (UINT_PTR)iconinfo.hbmColor;
464 bitmap_id = (int)SendMessage(hwnd, TB_ADDBITMAP, 1, (LRESULT)&bminfo);
465 }
466 else
467 #endif
468 {
469 bitmap_id = gate_ui_winapi_imagelist_replace_icon(himagelist, -1, hicon);
470 if (bitmap_id == -1)
471 {
472 #if defined(GATE_SYS_WINCE)
473 hicon = (HICON)LoadCursor(NULL, IDC_ICON);
474 #else
475 hicon = LoadIcon(NULL, IDI_WARNING);
476 #endif
477 bitmap_id = gate_ui_winapi_imagelist_replace_icon(himagelist, -1, hicon);
478 }
479 }
480
481 if (bitmap_id == -1)
482 {
483 /* Failed to add ICON bitmap to toolbar's image list */
484 ret = GATE_RESULT_FAILED;
485 }
486 else
487 {
488 ret = gate_ui_toolbar_add_bitmap_id(toolbar, bitmap_id, button_param, button_id);
489 }
490
491 #endif
492 return ret;
493 }
494
495 gate_result_t gate_ui_toolbar_add_icon_button(gate_ui_toolbar_t* toolbar, gate_ui_icon_t const* icon,
496 void* button_param, gate_ui_toolbar_button_t* button_id)
497 {
498 gate_result_t ret = GATE_RESULT_FAILED;
499
500 #if !defined(GATE_SYS_WIN16)
501 if (GATE_FLAG_ENABLED(icon->flags, GATE_UI_ICON_FLAG_STOCK))
502 {
503 int bitmap_id = 0xff;
504 gate_uint32_t stock_id = (gate_uint32_t)(gate_uintptr_t)icon->resources[1];
505 switch (stock_id)
506 {
507 case GATE_UI_ICON_STOCK_APP:
508 case GATE_UI_ICON_STOCK_DOCUMENT:
509 case GATE_UI_ICON_STOCK_FOLDER:
510 case GATE_UI_ICON_STOCK_FOLDEROPEN:
511 case GATE_UI_ICON_STOCK_NEWFILE: bitmap_id = STD_FILENEW; break;
512 case GATE_UI_ICON_STOCK_OPENFILE: bitmap_id = STD_FILEOPEN; break;
513 case GATE_UI_ICON_STOCK_SAVEFILE: bitmap_id = STD_FILESAVE; break;
514 case GATE_UI_ICON_STOCK_PRINTER: bitmap_id = STD_PRINT; break;
515 case GATE_UI_ICON_STOCK_CUT: bitmap_id = STD_CUT; break;
516 case GATE_UI_ICON_STOCK_COPY: bitmap_id = STD_COPY; break;
517 case GATE_UI_ICON_STOCK_PASTE: bitmap_id = STD_PASTE; break;
518 case GATE_UI_ICON_STOCK_DELETE: bitmap_id = STD_DELETE; break;
519 case GATE_UI_ICON_STOCK_FIND: bitmap_id = STD_FIND; break;
520 case GATE_UI_ICON_STOCK_HELP: bitmap_id = STD_HELP; break;
521
522 case GATE_UI_ICON_STOCK_STORAGE:
523 case GATE_UI_ICON_STOCK_COMPUTER:
524 case GATE_UI_ICON_STOCK_NETWORK:
525 case GATE_UI_ICON_STOCK_GLOBE:
526 case GATE_UI_ICON_STOCK_HOME:
527 case GATE_UI_ICON_STOCK_IMAGE:
528 case GATE_UI_ICON_STOCK_AUDIO:
529 case GATE_UI_ICON_STOCK_VIDEO:
530 case GATE_UI_ICON_STOCK_MAIL:
531 case GATE_UI_ICON_STOCK_SETTINGS: bitmap_id = STD_PROPERTIES; break;
532 default:
533 break;
534 }
535 ret = gate_ui_toolbar_add_bitmap_id(toolbar, bitmap_id, button_param, button_id);
536 }
537 else
538 {
539 HICON hicon = (HICON)icon->resources[0];
540 ret = gate_ui_toolbar_add_HICON(toolbar, hicon, button_param, button_id);
541 }
542 #endif /* GATE_SYS_WIN16 */
543 return ret;
544 }
545
546 gate_result_t gate_ui_toolbar_add_image_button(gate_ui_toolbar_t* toolbar, gate_rasterimage_t const* raster,
547 void* button_param, gate_ui_toolbar_button_t* button_id)
548 {
549 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(&toolbar->ctrl);
550 gate_ui_icon_t icon;
551 gate_result_t ret;
552 HICON hicon;
553
554 ret = gate_ui_icon_create_image(&icon, host, raster);
555 hicon = (HICON)icon.resources[0];
556
557 if (GATE_SUCCEEDED(ret))
558 {
559 ret = gate_ui_toolbar_add_HICON(toolbar, hicon, button_param, button_id);
560 gate_ui_icon_destroy(&icon);
561 }
562 return ret;
563 }
564 gate_result_t gate_ui_toolbar_add_separator(gate_ui_toolbar_t* toolbar)
565 {
566 gate_result_t ret = GATE_RESULT_OK;
567 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&toolbar->ctrl);
568 TBBUTTON button;
569 button.iBitmap = 0;
570 button.idCommand = 0;
571 button.fsState = TBSTATE_ENABLED;
572 button.fsStyle = TBSTYLE_SEP;
573 button.dwData = 0;
574 button.iString = 0;
575 if (FALSE == SendMessage(hwnd, TB_ADDBUTTONS, 1, (LPARAM)&button))
576 {
577 //ret = GATE_RESULT_FAILED;
578 }
579 else
580 {
581 SendMessage(hwnd, TB_AUTOSIZE, 0, 0);
582 }
583
584 return ret;
585 }
586
587 gate_int32_t gate_ui_toolbar_get_ideal_height(gate_ui_toolbar_t* toolbar)
588 {
589 #if defined(GATE_SYS_WIN16)
590 return 36;
591 #elif defined(GATE_SYS_WINCE)
592 return 20;
593 #else
594 HWND const hwnd = GATE_UI_WINAPI_GET_HWND(&toolbar->ctrl);
595 DWORD const padd = SendMessage(hwnd, TB_GETPADDING, 0, 0);
596 gate_int32_t const py = (gate_int32_t)HIWORD(padd);
597 return py * 2 + 16;
598 #endif
599 }
600
601
602 #endif /* GATE_UI_WINAPI */
603
604
605 #if defined(GATE_UI_GTK)
606
607 #include "gate/ui/gateui_gtk.h"
608
609 gate_result_t gate_ui_toolbar_create(gate_ui_toolbar_t* toolbar, gate_ui_ctrl_t* parent,
610 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
611 {
612 gate_result_t ret;
613 do
614 {
615 GtkWidget* widget;
616 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
617 GtkContainer* parentContainer = GATE_UI_GTK_GET_CTRL_CONTAINER(parent);
618
619 gate_mem_clear(toolbar, sizeof(gate_ui_toolbar_t));
620 widget = gtk_toolbar_new();
621 if (widget == NULL)
622 {
623 ret = GATE_RESULT_FAILED;
624 break;
625 }
626
627 ret = gate_ui_gtk_ctrl_init(&toolbar->ctrl, widget, host, userparam, parent,
628 NULL, false, false, position, &flags);
629 GATE_BREAK_IF_FAILED(ret);
630 gtk_toolbar_set_style(GTK_TOOLBAR(widget), GTK_TOOLBAR_ICONS);
631
632
633 } while (0);
634 return ret;
635 }
636
637 static void gate_ui_toolbar_button_clicked(GtkToolButton* toolbutton, gpointer user_data)
638 {
639 GtkWidget* toolbar_widget = gtk_widget_get_parent(GTK_WIDGET(toolbutton));
640
641 if (NULL != toolbar_widget)
642 {
643 gate_ui_ctrl_t* toolbar_ctrl = gate_ui_gtk_ctrl_resolve(toolbar_widget);
644
645 if (toolbar_ctrl)
646 {
647 gate_ui_toolbar_t* toolbar = (gate_ui_toolbar_t*)toolbar_ctrl;
648 if (toolbar->on_click)
649 {
650 toolbar->on_click(&toolbar->ctrl, (gate_ui_toolbar_button_t)toolbutton, user_data);
651 }
652 }
653 }
654 }
655
656 gate_result_t gate_ui_toolbar_add_icon_button(gate_ui_toolbar_t* toolbar, gate_ui_icon_t const* icon,
657 void* button_param, gate_ui_toolbar_button_t* button_id)
658 {
659 gate_result_t ret = GATE_RESULT_OK;
660 do
661 {
662 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&toolbar->ctrl);
663 GtkWidget* icon_widget = gtk_image_new_from_pixbuf((GdkPixbuf*)icon->resources[0]);
664 GtkToolItem* item = gtk_tool_button_new(icon_widget, NULL);
665 if (NULL == item)
666 {
667 ret = GATE_RESULT_OUTOFMEMORY;
668 break;
669 }
670 gtk_toolbar_insert(GTK_TOOLBAR(widget), item, -1);
671 gtk_widget_show_all(widget);
672 g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(gate_ui_toolbar_button_clicked), (gpointer)button_param);
673
674 if (button_id)
675 {
676 *button_id = (gate_ui_toolbar_button_t)item;
677 }
678 } while (0);
679 return ret;
680 }
681
682 gate_result_t gate_ui_toolbar_add_image_button(gate_ui_toolbar_t* toolbar, gate_rasterimage_t const* raster,
683 void* button_param, gate_ui_toolbar_button_t* button_id)
684 {
685 gate_result_t ret = GATE_RESULT_OK;
686 gate_ui_icon_t icon = GATE_INIT_EMPTY;
687 do
688 {
689 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&toolbar->ctrl);
690 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(&toolbar->ctrl);
691 GtkWidget* icon_widget;
692 GtkToolItem* item;
693
694 ret = gate_ui_icon_create_image(&icon, host, raster);
695 GATE_BREAK_IF_FAILED(ret);
696 icon_widget = gtk_image_new_from_pixbuf((GdkPixbuf*)icon.resources[0]);
697 if (NULL == icon_widget)
698 {
699 ret = GATE_RESULT_FAILED;
700 break;
701 }
702 item = gtk_tool_button_new(icon_widget, NULL);
703 if (NULL == item)
704 {
705 gtk_widget_destroy(icon_widget);
706 ret = GATE_RESULT_FAILED;
707 break;
708 }
709 gtk_toolbar_insert(GTK_TOOLBAR(widget), item, -1);
710 gtk_widget_show_all(widget);
711
712 g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(gate_ui_toolbar_button_clicked), (gpointer)button_param);
713
714 if (button_id)
715 {
716 *button_id = (gate_ui_toolbar_button_t)item;
717 }
718
719 } while (0);
720
721 gate_ui_icon_destroy(&icon);
722
723 return ret;
724 }
725
726 gate_result_t gate_ui_toolbar_add_separator(gate_ui_toolbar_t* toolbar)
727 {
728 gate_result_t ret = GATE_RESULT_OK;
729 do
730 {
731 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&toolbar->ctrl);
732 GtkToolItem* item = gtk_tool_item_new();
733 if (NULL == item)
734 {
735 ret = GATE_RESULT_OUTOFMEMORY;
736 break;
737 }
738 gtk_toolbar_insert(GTK_TOOLBAR(widget), item, -1);
739 } while (0);
740 return ret;
741 }
742
743 gate_int32_t gate_ui_toolbar_get_ideal_height(gate_ui_toolbar_t* toolbar)
744 {
745 /*
746 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(&toolbar->ctrl);
747 return (gate_int32_t)gate_ui_host_default_control_height(host, 1);
748 */
749 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&toolbar->ctrl);
750 gint minimal = 0;
751 gint natural = 0;
752 gtk_widget_get_preferred_height(widget, &minimal, &natural);
753 return (gate_int32_t)minimal;
754 }
755
756
757 #endif
758
759
760
761 #if defined(GATE_UI_MOTIF)
762
763 #include "gate/ui/gateui_motif.h"
764 #include "gate/debugging.h"
765 #include <Xm/RowColumn.h>
766 #include <Xm/PushB.h>
767
768 1 static gate_result_t motif_toolbar_destroy(gate_ui_ctrl_t* ctrl)
769 {
770 Widget w;
771 1 gate_ui_host_t* host = NULL;
772
773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(ctrl != NULL);
774
775 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
776 1 host = GATE_UI_MOTIF_GET_CTRL_HOST(ctrl);
777
778
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (w && host)
779 {
780 1 Cardinal wcnt = 0;
781 1 WidgetList wl = NULL;
782 1 Display* dpy = GATE_UI_MOTIF_GET_HOST_DISPLAY(host);
783 1 XtVaGetValues(w, XmNnumChildren, &wcnt, XmNchildren, &wl, NULL, NULL);
784
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 while (wcnt-- > 0)
785 {
786 1 Widget child = wl[wcnt];
787 1 Pixmap pm = 0;
788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!child) continue;
789 1 XtVaGetValues(child, XmNarmPixmap, &pm, NULL, NULL);
790
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pm)
791 {
792 1 XFreePixmap(dpy, pm);
793 }
794 1 XtUnmanageChild(child);
795 1 XtDestroyWidget(child);
796 }
797
798 1 gate_ui_motif_widget_destroy_children(w, false);
799 }
800 1 return gate_ui_motif_ctrl_destroy_default(ctrl);
801 }
802
803 3 static gate_result_t motif_toolbar_refresh(gate_ui_ctrl_t* ctrl)
804 {
805 3 return gate_ui_motif_ctrl_refresh(ctrl);
806 }
807
808 1 static gate_result_t motif_toolbar_get_children(gate_ui_ctrl_t* ctrl, void** ptr_to_widgetlist, gate_size_t* ptr_to_children_count)
809 {
810 GATE_UNUSED_ARG(ctrl);
811
812
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_to_widgetlist) *ptr_to_widgetlist = NULL;
813
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_to_children_count) *ptr_to_children_count = 0;
814 1 return GATE_RESULT_OK;
815 }
816
817
818 static gate_ui_motif_dispatcher_t tb_dispatcher =
819 {
820 &motif_toolbar_destroy,
821 NULL,
822 NULL,
823 NULL,
824 NULL,
825 &motif_toolbar_refresh,
826 &motif_toolbar_get_children
827 };
828
829 1 gate_result_t gate_ui_toolbar_create(gate_ui_toolbar_t* toolbar, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
830 gate_uint32_t flags, void* userparam)
831 {
832 1 gate_result_t ret = GATE_RESULT_FAILED;
833
834 do
835 {
836 Arg args[8];
837 1 unsigned args_count = 0;
838
839
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!toolbar || !parent)
840 {
841 ret = GATE_RESULT_INVALIDARG;
842 break;
843 }
844
845 1 XtSetArg(args[args_count], XmNorientation, XmHORIZONTAL); ++args_count;
846 1 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
847 1 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
848
849 1 ret = gate_ui_motif_ctrl_create(&toolbar->ctrl, xmRowColumnWidgetClass, userparam, NULL, parent,
850 position, &flags, false, &tb_dispatcher, args, args_count);
851
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
852 } while (0);
853
854 1 return ret;
855 }
856
857 static void toolbar_button_pushed(Widget widget, XtPointer client_data, XtPointer call_data)
858 {
859 void* button_param = (void*)client_data;
860 Widget parent = XtParent(widget);
861 gate_ui_ctrl_t* ptr_ctrl = gate_ui_motif_widget_get_ctrl(parent);
862 gate_ui_toolbar_t* ptr_toolbar = (gate_ui_toolbar_t*)ptr_ctrl;
863 gate_ui_toolbar_button_t button_id = (gate_ui_toolbar_button_t)widget;
864
865
866 if (!ptr_toolbar || !ptr_toolbar->on_click)
867 {
868 return;
869 }
870 ptr_toolbar->on_click(ptr_ctrl, button_id, button_param);
871 }
872
873 gate_result_t gate_ui_toolbar_add_icon_button(gate_ui_toolbar_t* toolbar, gate_ui_icon_t const* icon, void* button_param,
874 gate_ui_toolbar_button_t* button_id)
875 {
876 return GATE_RESULT_NOTIMPLEMENTED;
877 }
878
879 1 gate_result_t gate_ui_toolbar_add_image_button(gate_ui_toolbar_t* toolbar, gate_rasterimage_t const* raster, void* button_param,
880 gate_ui_toolbar_button_t* button_id)
881 {
882 1 gate_result_t ret = GATE_RESULT_FAILED;
883 1 Widget new_button = NULL;
884
885
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(toolbar != NULL);
886
887 do
888 {
889 1 gate_ui_host_t* host = GATE_UI_MOTIF_GET_CTRL_HOST(&toolbar->ctrl);
890 1 Widget widget_tb = GATE_UI_MOTIF_GET_CTRL_WIDGET(&toolbar->ctrl);
891 gate_ui_graphics_t graph;
892 1 gate_ui_position_t pos = { 0, 0, 32, 32 };
893 1 gate_ui_color_t bg_col = { 192, 192, 192, 255 };
894 1 Pixmap pm = 0;
895 Arg args[8];
896 1 Cardinal args_count = 0;
897
898
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(widget_tb != NULL);
899
900 1 ret = gate_ui_graphics_create_image(&graph, host, raster->width, raster->height, 0);
901
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
902
903 1 gate_ui_graphics_rect(&graph, pos, &bg_col, 0, &bg_col);
904 1 ret = gate_ui_graphics_draw_image(&graph, raster, NULL, NULL, NULL);
905
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
906
907 1 pm = (Pixmap)gate_ui_graphics_surface(&graph);
908 1 graph.resources[1] = NULL; /* remove pixmap resource from graphics object */
909
910 1 XtSetArg(args[args_count], XmNuserData, NULL); ++args_count;
911 1 XtSetArg(args[args_count], XmNlabelType, XmPIXMAP); ++args_count;
912 1 XtSetArg(args[args_count], XmNarmPixmap, pm); ++args_count;
913 1 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
914 1 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
915
916 1 new_button = XtCreateWidget(NULL, xmPushButtonWidgetClass, widget_tb, args, args_count);
917 1 gate_ui_graphics_destroy(&graph);
918
919
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!new_button)
920 {
921 ret = GATE_RESULT_FAILED;
922 break;
923 }
924
925 1 XtManageChild(new_button);
926
927 1 XtAddCallback(new_button, XmNactivateCallback, &toolbar_button_pushed, button_param);
928
929 1 *button_id = (gate_ui_toolbar_button_t)(gate_intptr_t)new_button;
930 1 ret = GATE_RESULT_OK;
931 } while (0);
932
933
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (GATE_FAILED(ret) && (new_button != NULL))
934 {
935 XtDestroyWidget(new_button);
936 }
937 1 return ret;
938 }
939
940 1 gate_result_t gate_ui_toolbar_add_separator(gate_ui_toolbar_t* toolbar)
941 {
942 1 return GATE_RESULT_OK;
943 }
944
945 gate_int32_t gate_ui_toolbar_get_ideal_height(gate_ui_toolbar_t* toolbar)
946 {
947 gate_ui_host_t* host = GATE_UI_MOTIF_GET_CTRL_HOST(&toolbar->ctrl);
948 return (gate_int32_t)gate_ui_host_default_control_height(host, 1);
949 }
950
951
952 #endif /* GATE_UI_MOTIF */
953