GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/forms.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 152 237 64.1%
Functions: 13 24 54.2%
Branches: 33 84 39.3%

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/forms.h"
30 #include "gate/results.h"
31
32 #if defined(GATE_UI_WINAPI)
33
34 #include "gate/ui/gateui_winapi.h"
35 #include "gate/platform/windows/win32resource.h"
36 #include "gate/platforms.h"
37
38 #include <stdio.h>
39
40 #if defined(GATE_SYS_WINCE)
41 # include <aygshell.h>
42 # if defined(GATE_COMPILER_MSVC)
43 # pragma comment(lib, "aygshell.lib")
44 # endif
45 #endif
46
47
48 #define GATE_UI_FORM_MENU_STARTID 100
49
50 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
51
52 /* https://github.com/adzm/win32-custom-menubar-aero-theme */
53 #ifndef WM_UAHDESTROYWINDOW
54 #define WM_UAHDESTROYWINDOW 0x0090
55 #endif
56
57 #ifndef WM_UAHDRAWMENU
58 #define WM_UAHDRAWMENU 0x0091
59 #endif
60
61 #ifndef WM_UAHDRAWMENUITEM
62 #define WM_UAHDRAWMENUITEM 0x0092
63 #endif
64
65 #ifndef WM_UAHINITMENU
66 #define WM_UAHINITMENU 0x0093
67 #endif
68
69 #ifndef WM_UAHMEASUREMENUITEM
70 #define WM_UAHMEASUREMENUITEM 0x0094
71 #endif
72
73 #ifndef WM_UAHNCPAINTMENUPOPUP
74 #define WM_UAHNCPAINTMENUPOPUP 0x0095
75 #endif
76
77 typedef struct
78 {
79 HMENU hmenu;
80 HDC hdc;
81 DWORD dwFlags;
82 } GATE_UAHMENU;
83
84 typedef union
85 {
86 struct
87 {
88 DWORD cx;
89 DWORD cy;
90 } rgsizeBar[2];
91 struct
92 {
93 DWORD cx;
94 DWORD cy;
95 } rgsizePopup[4];
96 } GATE_UAHMENUITEMMETRICS;
97
98 typedef struct
99 {
100 DWORD rgcx[4];
101 DWORD fUpdateMaxWidths : 2;
102 } GATE_UAHMENUPOPUPMETRICS;
103
104 typedef struct
105 {
106 int iPosition; // 0-based position of menu item in menubar
107 GATE_UAHMENUITEMMETRICS umim;
108 GATE_UAHMENUPOPUPMETRICS umpm;
109 } GATE_UAHMENUITEM;
110
111 // the DRAWITEMSTRUCT contains the states of the menu items, as well as
112 // the position index of the item in the menu, which is duplicated in
113 // the UAHMENUITEM's iPosition as well
114 typedef struct
115 {
116 DRAWITEMSTRUCT dis; // itemID looks uninitialized
117 GATE_UAHMENU um;
118 GATE_UAHMENUITEM umi;
119 } GATE_UAHDRAWMENUITEM;
120
121 typedef struct
122 {
123 DWORD cbSize;
124 RECT rcBar;
125 HMENU hMenu;
126 HWND hwndMenu;
127 BOOL fBarFocused : 1;
128 BOOL fFocused : 1;
129 BOOL fUnused : 30;
130 } GATE_MENUBARINFO, * PGATE_MENUBARINFO, * LPGATE_MENUBARINFO;
131
132
133 static void gate_ui_form_apply_dark_mode_to_container(gate_ui_ctrl_t* ctrl, BOOL dark_mode)
134 {
135 gate_array_t children = GATE_INIT_EMPTY;
136 gate_result_t result;
137 HWND hwnd = GATE_UI_WINAPI_GET_HWND(ctrl);
138
139 gate_ui_winapi_apply_darkmode(hwnd, dark_mode);
140 gate_ui_ctrl_refresh(ctrl);
141
142 result = gate_ui_winapi_get_children(ctrl, &children);
143 if (GATE_SUCCEEDED(result))
144 {
145 gate_size_t ndx;
146 gate_size_t len = gate_array_length(&children);
147 for (ndx = 0; ndx != len; ++ndx)
148 {
149 gate_ui_ctrl_t* const* ptr_child = (gate_ui_ctrl_t* const*)gate_array_get(&children, ndx);
150 if (ptr_child)
151 {
152 gate_ui_form_apply_dark_mode_to_container(*ptr_child, dark_mode);
153 }
154 }
155 gate_array_release(&children);
156 }
157
158 }
159
160
161 #ifndef OBJID_CLIENT
162 #define OBJID_CLIENT ((LONG)0xFFFFFFFC)
163 #endif
164
165 #ifndef OBJID_MENU
166 #define OBJID_MENU ((LONG)0xFFFFFFFD)
167 #endif
168
169 #ifndef OBJID_SYSMENU
170 #define OBJID_SYSMENU ((LONG)0xFFFFFFFF)
171 #endif
172
173 #ifndef ODS_HOTLIGHT
174 #define ODS_HOTLIGHT 0x0040
175 #endif
176
177
178 static void gate_ui_redraw_menubar(gate_ui_ctrl_t* ctrl, HDC hdc)
179 {
180 gate_win32_userapi_t const* const userapi = gate_win32_userapi();
181 HWND hwnd = GATE_UI_WINAPI_GET_HWND(ctrl);
182 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(ctrl);
183 HBRUSH hbr_bk_gnd;
184 GATE_MENUBARINFO menu_bar_info;
185 RECT rect_window;
186 gate_ui_color_t bg_color;
187
188 gate_ui_host_default_color(host, GATE_UI_COLOR_MENUBACKGROUND, &bg_color);
189
190 hbr_bk_gnd = (HBRUSH)gate_ui_winapi_host_get_brush(host, &bg_color);
191 gate_mem_clear(&menu_bar_info, sizeof(menu_bar_info));
192 menu_bar_info.cbSize = sizeof(menu_bar_info);
193 userapi->UserGetMenuBarInfo(hwnd, OBJID_MENU, 0, &menu_bar_info);
194
195 GetWindowRect(hwnd, &rect_window);
196 OffsetRect(&menu_bar_info.rcBar, -rect_window.left, -rect_window.top);
197 rect_window.bottom++;
198 FillRect(hdc, &menu_bar_info.rcBar, hbr_bk_gnd);
199 }
200
201 #endif
202
203 static HICON get_default_app_icon()
204 {
205 static HICON hicon = NULL;
206 if (hicon == NULL)
207 {
208 hicon = LoadIcon(GetModuleHandle(NULL), _T("APP_ICON"));
209 }
210 return hicon;
211 }
212
213 static gate_bool_t gate_ui_form_events(void* hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult)
214 {
215 if (ctrl != NULL)
216 {
217 HWND hwndCtrl = GATE_UI_WINAPI_GET_HWND(ctrl);
218 if (((HWND)hwnd) == hwndCtrl)
219 {
220 gate_ui_form_t* form = (gate_ui_form_t*)ctrl;
221 gate_ui_host_t* host;
222 HDC hdc = (HDC)NULL;
223 HWND hwndChild = (HWND)NULL;
224 COLORREF bk_color = 0x383838;
225 COLORREF text_color = 0xFFFFFF;
226 HBRUSH hbr_bk_gnd = (HBRUSH)NULL;
227 RECT rect;
228 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
229 gate_ui_color_t ui_color;
230 gate_ui_color_t ui_text_color;
231 TCHAR buffer[256];
232 gate_size_t buffer_used;
233 LPCTSTR str_setting_param;
234 GATE_UAHDRAWMENUITEM* uah_draw_menu_item;
235 BOOL dark_mode;
236 #endif
237
238 switch (msg)
239 {
240 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
241 case WM_CTLCOLORBTN:
242 {
243 hwndChild = (HWND)lParam;
244 if (gate_ui_winapi_is_darkmode_applied(hwndCtrl))
245 {
246 host = GATE_UI_WINAPI_GET_HOST(ctrl);
247
248 //gate_ui_winapi_set_window_theme(hwndChild, NULL, NULL);
249
250 hdc = (HDC)wParam;
251 gate_ui_host_default_color(host, GATE_UI_COLOR_CONTROLTEXT, &ui_color);
252 text_color = RGB(ui_color.r, ui_color.g, ui_color.b);
253
254 gate_ui_host_default_color(host, GATE_UI_COLOR_CONTROL, &ui_color);
255 bk_color = RGB(ui_color.r, ui_color.g, ui_color.b);
256
257 SetBkColor(hdc, bk_color);
258 SetTextColor(hdc, text_color);
259 hbr_bk_gnd = (HBRUSH)gate_ui_winapi_host_get_brush(host, &ui_color);
260
261 *lresult = (gate_intptr_t)hbr_bk_gnd;
262 return true;
263 }
264 break;
265 }
266 case WM_CTLCOLOREDIT:
267 case WM_CTLCOLORLISTBOX:
268 case WM_CTLCOLORSCROLLBAR:
269 {
270 hwndChild = (HWND)lParam;
271 if (gate_ui_winapi_is_darkmode_applied(hwndCtrl))
272 {
273 host = GATE_UI_WINAPI_GET_HOST(ctrl);
274 hdc = (HDC)wParam;
275 gate_ui_host_default_color(host, GATE_UI_COLOR_CONTENTTEXT, &ui_color);
276 text_color = RGB(ui_color.r, ui_color.g, ui_color.b);
277
278 gate_ui_host_default_color(host, GATE_UI_COLOR_CONTENTBACKGROUND, &ui_color);
279 bk_color = RGB(ui_color.r, ui_color.g, ui_color.b);
280
281 SetTextColor(hdc, text_color);
282 SetBkColor(hdc, bk_color);
283 hbr_bk_gnd = (HBRUSH)gate_ui_winapi_host_get_brush(host, &ui_color);
284
285 *lresult = (gate_intptr_t)hbr_bk_gnd;
286 return true;
287 }
288 break;
289 }
290 #endif /* GATE_UI_WINAPI_DARKMODE_SUPPORT */
291
292 #if !defined(GATE_SYS_WIN16)
293 case WM_GETICON:
294 {
295 *lresult = (gate_intptr_t)(void*)get_default_app_icon();
296 return true;
297 }
298 case WM_CTLCOLORMSGBOX:
299 case WM_CTLCOLORDLG:
300 case WM_CTLCOLORSTATIC:
301 {
302 gate_bool_t is_dialog;
303 gate_uint32_t exstyles;
304 hdc = (HDC)wParam;
305 hwndChild = (HWND)lParam;
306 exstyles = gate_ui_winapi_get_window_exstyles(hwndCtrl);
307 is_dialog = GATE_FLAG_ENABLED(exstyles, WS_EX_DLGMODALFRAME);
308
309 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
310 if (gate_ui_winapi_is_darkmode_applied(hwndCtrl))
311 {
312 host = GATE_UI_WINAPI_GET_HOST(ctrl);
313
314 if (is_dialog)
315 {
316 gate_ui_host_default_color(host, GATE_UI_COLOR_DIALOGTEXT, &ui_color);
317 text_color = RGB(ui_color.r, ui_color.g, ui_color.b);
318
319 gate_ui_host_default_color(host, GATE_UI_COLOR_DIALOG, &ui_color);
320 bk_color = RGB(ui_color.r, ui_color.g, ui_color.b);
321
322 hbr_bk_gnd = (HBRUSH)gate_ui_winapi_host_get_brush(host, &ui_color);
323 }
324 else
325 {
326 gate_ui_host_default_color(host, GATE_UI_COLOR_WINDOWTEXT, &ui_color);
327 text_color = RGB(ui_color.r, ui_color.g, ui_color.b);
328
329 gate_ui_host_default_color(host, GATE_UI_COLOR_WINDOW, &ui_color);
330 bk_color = RGB(ui_color.r, ui_color.g, ui_color.b);
331
332 hbr_bk_gnd = (HBRUSH)gate_ui_winapi_host_get_brush(host, &ui_color);
333 }
334 }
335 else
336 #endif /* GATE_UI_WINAPI_DARKMODE_SUPPORT */
337 {
338 if (is_dialog)
339 {
340 text_color = GetSysColor(gate_ui_winapi_get_syscolor_index(GATE_UI_COLOR_DIALOGTEXT));
341 bk_color = GetSysColor(gate_ui_winapi_get_syscolor_index(GATE_UI_COLOR_DIALOG));
342 hbr_bk_gnd = (HBRUSH)gate_ui_winapi_get_syscolor_brush(gate_ui_winapi_get_syscolor_index(GATE_UI_COLOR_DIALOG));
343 }
344 else
345 {
346 text_color = GetSysColor(gate_ui_winapi_get_syscolor_index(GATE_UI_COLOR_WINDOWTEXT));
347 bk_color = GetSysColor(gate_ui_winapi_get_syscolor_index(GATE_UI_COLOR_WINDOW));
348 hbr_bk_gnd = (HBRUSH)gate_ui_winapi_get_syscolor_brush(gate_ui_winapi_get_syscolor_index(GATE_UI_COLOR_WINDOW));
349 }
350 }
351 SetTextColor(hdc, text_color);
352 SetBkColor(hdc, bk_color);
353 *lresult = (gate_intptr_t)hbr_bk_gnd;
354 return true;
355 }
356 #endif /* GATE_SYS_WIN16 */
357 case WM_MOVE:
358 {
359 gate_ui_point_t pnt;
360 pnt.x = (int)(short)LOWORD(lParam);
361 pnt.y = (int)(short)HIWORD(lParam);
362 if (form->on_move != NULL)
363 {
364 form->on_move(ctrl, &pnt);
365 }
366 break;
367 }
368 case WM_SIZE:
369 {
370 gate_ui_size_t sz;
371 if (form->layout != NULL)
372 {
373 gate_uint32_t lineheight;
374 gate_ui_position_t position;
375 host = GATE_UI_WINAPI_GET_HOST(&form->ctrl);
376 lineheight = gate_ui_host_default_control_height(host, 1);
377 position.pos.x = 0;
378 position.pos.y = 0;
379 gate_ui_ctrl_get_size(&form->ctrl, &position.size);
380 gate_ui_layout_apply(form->layout, lineheight, &position);
381 }
382 sz.width = (int)(short)LOWORD(lParam);
383 sz.height = (int)(short)HIWORD(lParam);
384 if (form->on_resize != NULL)
385 {
386 form->on_resize(ctrl, &sz);
387 }
388 break;
389 }
390 case WM_CLOSE:
391 {
392 if (form->on_close != NULL)
393 {
394 form->on_close(ctrl);
395 }
396 *lresult = 0;
397 return true;
398 }
399 case WM_ERASEBKGND:
400 {
401 GetClientRect(hwndCtrl, &rect);
402 hdc = (HDC)wParam;
403 #if defined(GATE_SYS_WIN16)
404 hbr_bk_gnd = (HBRUSH)GetStockObject(WHITE_BRUSH);
405 #else
406 hbr_bk_gnd = (HBRUSH)SendMessage(hwndCtrl, WM_CTLCOLORDLG, (WPARAM)hdc, (LPARAM)hwndCtrl);
407 #endif
408 FillRect(hdc, &rect, hbr_bk_gnd);
409 *lresult = TRUE;
410 return true;
411 }
412 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
413 case WM_UAHDRAWMENU:
414 {
415 if (gate_ui_winapi_is_darkmode_applied(hwndCtrl))
416 {
417 GATE_UAHMENU* uah_menu = (GATE_UAHMENU*)lParam;
418 gate_ui_redraw_menubar(ctrl, uah_menu->hdc);
419
420 *lresult = 0;
421 return true;
422 }
423 break;
424 }
425 case WM_UAHDRAWMENUITEM:
426 {
427 if (gate_ui_winapi_is_darkmode_applied(hwndCtrl))
428 {
429 int menu_result;
430 host = GATE_UI_WINAPI_GET_HOST(ctrl);
431 uah_draw_menu_item = (GATE_UAHDRAWMENUITEM*)lParam;
432
433 if (GATE_FLAG_ENABLED(uah_draw_menu_item->dis.itemState, ODS_SELECTED))
434 {
435 gate_ui_host_default_color(host, GATE_UI_COLOR_SELECTEDMENUBACKGROUND, &ui_color);
436 gate_ui_host_default_color(host, GATE_UI_COLOR_SELECTEDMENUTEXT, &ui_text_color);
437 }
438 else if (GATE_FLAG_ENABLED(uah_draw_menu_item->dis.itemState, ODS_HOTLIGHT))
439 {
440 gate_ui_host_default_color(host, GATE_UI_COLOR_HOVERMENUBACKGROUND, &ui_color);
441 gate_ui_host_default_color(host, GATE_UI_COLOR_HOVERMENUTEXT, &ui_text_color);
442 }
443 else
444 {
445 gate_ui_host_default_color(host, GATE_UI_COLOR_MENUBACKGROUND, &ui_color);
446 gate_ui_host_default_color(host, GATE_UI_COLOR_MENUTEXT, &ui_text_color);
447 }
448
449 hbr_bk_gnd = (HBRUSH)gate_ui_winapi_host_get_brush(host, &ui_color);
450 FillRect(uah_draw_menu_item->dis.hDC, &uah_draw_menu_item->dis.rcItem, hbr_bk_gnd);
451 SetBkColor(uah_draw_menu_item->um.hdc, RGB(ui_color.r, ui_color.g, ui_color.b));
452 SetBkMode(uah_draw_menu_item->um.hdc, OPAQUE);
453 SetTextColor(uah_draw_menu_item->um.hdc, RGB(ui_text_color.r, ui_text_color.g, ui_text_color.b));
454
455 gate_mem_clear(buffer, sizeof(buffer));
456 menu_result = GetMenuString(uah_draw_menu_item->um.hmenu,
457 uah_draw_menu_item->umi.iPosition,
458 buffer,
459 sizeof(buffer) / sizeof(buffer[0]),
460 MF_BYPOSITION);
461
462 buffer_used = gate_win32_str_len(buffer);
463
464 DrawText(uah_draw_menu_item->um.hdc,
465 buffer, (int)buffer_used, &uah_draw_menu_item->dis.rcItem,
466 DT_CENTER | DT_VCENTER | DT_SINGLELINE);
467 /*TextOut(uah_draw_menu_item->um.hdc,
468 uah_draw_menu_item->dis.rcItem.left,
469 uah_draw_menu_item->dis.rcItem.top, _T("XX"), 2);*/
470
471 *lresult = 0;
472 return true;
473 }
474 break;
475 }
476 #endif /* GATE_UI_WINAPI_DARKMODE_SUPPORT */
477
478 case WM_ACTIVATE:
479 {
480 gate_uint16_t activation_type = LOWORD(wParam);
481 switch (activation_type)
482 {
483 case WA_ACTIVE:
484 case WA_CLICKACTIVE:
485 {
486 #if defined(GATE_SYS_WINCE)
487 SHACTIVATEINFO* ptr_activate_info = (SHACTIVATEINFO*)GATE_UI_WINAPI_GET_CTRL_PARAM(ctrl);
488 if (ptr_activate_info)
489 {
490 SHHandleWMActivate(hwndCtrl, wParam, lParam, ptr_activate_info, FALSE);
491 }
492 #endif
493 if (form->on_activate)
494 {
495 form->on_activate(ctrl, true);
496 }
497 break;
498 }
499 case WA_INACTIVE:
500 {
501 if (form->on_activate)
502 {
503 form->on_activate(ctrl, false);
504 }
505 break;
506 }
507 }
508 break;
509 }
510 case WM_COMMAND:
511 {
512 if (HIWORD(wParam) == 0)
513 {
514 if ((form->on_menu != NULL) && (form->menulist != NULL))
515 {
516 gate_uint16_t menuid = LOWORD(wParam);
517 if (menuid >= 100)
518 {
519 gate_uint16_t menustartid = GATE_UI_FORM_MENU_STARTID;
520 #if defined(GATE_SYS_WINCE)
521 if (menuid == GATE_WINCE_TOOLBAR_OPTION1)
522 {
523 /* "menu" command button pressed; */
524 hwndChild = SHFindMenuBar(hwndCtrl);
525 if (hwndChild && form->menulist)
526 {
527 gate_ui_menu_entry_t const* ptr_menu_entry;
528 int menu_result;
529 gate_ui_point_t pnt;
530 GetWindowRect(hwndChild, &rect);
531 pnt.x = rect.left;
532 pnt.y = rect.top;
533
534 menu_result = gate_ui_popupmenu_show(ctrl, form->menulist,
535 &pnt, &ptr_menu_entry);
536 if (GATE_SUCCEEDED(menu_result) && (form->on_menu != NULL))
537 {
538 form->on_menu(ctrl, ptr_menu_entry);
539 }
540 }
541 }
542 else if (menuid == GATE_WINCE_TOOLBAR_OPTION2)
543 {
544 /* "confirm" command button pressed */
545 if (form->on_confirm)
546 {
547 form->on_confirm(ctrl);
548 }
549 }
550 #else
551 gate_ui_menu_entry_t const* menuentry = gate_ui_winapi_resolve_menu(&menustartid, menuid, form->menulist);
552 if (menuentry != NULL)
553 {
554 form->on_menu(&form->ctrl, menuentry);
555 }
556 #endif
557 * lresult = 0;
558 return true;
559 }
560 }
561 if (wParam == IDOK)
562 {
563 if (form->on_confirm)
564 {
565 form->on_confirm(&form->ctrl);
566 *lresult = 0;
567 return true;
568 }
569 }
570 if (wParam == IDCANCEL)
571 {
572 if (form->on_cancel)
573 {
574 form->on_cancel(&form->ctrl);
575 *lresult = 0;
576 return true;
577 }
578 }
579 }
580 break;
581 }
582 #if !defined(GATE_SYS_WIN16)
583 case WM_SETTINGCHANGE:
584 {
585 #if defined(GATE_SYS_WINCE)
586 SHACTIVATEINFO* ptr_activate_info = (SHACTIVATEINFO*)GATE_UI_WINAPI_GET_CTRL_PARAM(ctrl);
587 if (ptr_activate_info)
588 {
589 SHHandleWMSettingChange(hwndCtrl, wParam, lParam, ptr_activate_info);
590 }
591 *lresult = 0;
592 return true;
593 #elif defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
594 str_setting_param = (LPCTSTR)lParam;
595 if (0 == gate_win32_winstr_comp(str_setting_param, _T("ImmersiveColorSet")))
596 {
597 gate_ui_winapi_refresh_immersive_color_policy_state();
598 dark_mode = gate_ui_winapi_darkmode_enabled();
599 gate_ui_form_apply_dark_mode_to_container(ctrl, dark_mode);
600 *lresult = 0;
601 return true;
602 }
603 break;
604 #endif
605 }
606 #endif /* GATE_SYS_WIN16 */
607
608 #if defined(GATE_SYS_WINCE)
609 case WM_SYSCOMMAND:
610 {
611 switch (wParam)
612 {
613 case SC_CLOSE:
614 {
615 if (form->on_close != NULL)
616 {
617 form->on_close(ctrl);
618 }
619 *lresult = 0;
620 return true;
621 }
622 }
623 break;
624 }
625 #endif
626 }
627 }
628 }
629 return false;
630 }
631
632 gate_result_t gate_ui_form_create(
633 gate_ui_form_t* form, gate_ui_host_t* host,
634 gate_ui_position_t const* position, gate_string_t const* title, gate_uint32_t flags, gate_ui_form_t* owner,
635 void* userparam)
636 {
637 gate_result_t ret;
638 gate_uint32_t styles, exstyles;
639 HWND hwndOwner = (HWND)NULL;
640 #if defined(GATE_SYS_WINCE)
641 SHACTIVATEINFO* ptr_activate_info = NULL;
642 #endif
643 void* ctrl_param = NULL;
644
645 if ((host == NULL) && (owner != NULL))
646 {
647 host = GATE_UI_WINAPI_GET_HOST(&owner->ctrl);
648 }
649
650 gate_mem_clear(form, sizeof(gate_ui_form_t));
651
652 exstyles = 0;
653 styles = WS_GROUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
654
655 #if defined(GATE_SYS_WINCE)
656 ptr_activate_info = (SHACTIVATEINFO*)gate_mem_alloc(sizeof(SHACTIVATEINFO));
657 gate_mem_clear(ptr_activate_info, sizeof(SHACTIVATEINFO));
658 ptr_activate_info->cbSize = sizeof(SHACTIVATEINFO);
659 ctrl_param = ptr_activate_info;
660 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_FORM_NOCLOSE))
661 {
662 styles |= WS_SYSMENU;
663 }
664 #else
665 styles |= (WS_OVERLAPPED | WS_CAPTION);
666 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_RESIZABLE))
667 {
668 styles |= WS_SIZEBOX;
669 }
670 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_FORM_MINIMIZABLE))
671 {
672 styles |= (WS_MINIMIZEBOX | WS_SYSMENU);
673 }
674 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_FORM_MAXIMIZABLE))
675 {
676 styles |= (WS_MAXIMIZEBOX | WS_SYSMENU);
677 }
678
679 #if !defined(GATE_SYS_WIN16)
680 exstyles |= WS_EX_CONTROLPARENT;
681 if (owner == NULL)
682 {
683 exstyles |= WS_EX_APPWINDOW;
684 }
685 else
686 {
687 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_RESIZABLE))
688 {
689 exstyles |= WS_EX_TOOLWINDOW;
690 }
691 else
692 {
693 styles |= WS_DLGFRAME;
694 }
695 }
696 #endif /* GATE_SYS_WIN16 */
697
698 #endif
699
700 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED))
701 {
702 styles |= WS_DISABLED;
703 }
704 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE))
705 {
706 styles |= WS_VISIBLE;
707 }
708 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_FORM_DIALOGSTYLE))
709 {
710 styles |= WS_DLGFRAME;
711 exstyles |= WS_EX_DLGMODALFRAME;
712 }
713
714 if (owner != NULL)
715 {
716 hwndOwner = GATE_UI_WINAPI_GET_HWND(&owner->ctrl);
717 }
718
719 ret = gate_ui_winapi_create(&form->ctrl, host, (void*)hwndOwner, NULL,
720 position, styles, exstyles, title, userparam, false);
721 if (GATE_SUCCEEDED(ret))
722 {
723 HWND hwndForm;
724
725 GATE_UI_WINAPI_SET_CTRL_PARAM(&form->ctrl, ctrl_param);
726 hwndForm = GATE_UI_WINAPI_GET_HWND(&form->ctrl);
727
728 #if !defined(GATE_SYS_WINCE)
729 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_FORM_NOCLOSE))
730 {
731 HMENU sysmenu = GetSystemMenu(hwndForm, FALSE);
732 if (sysmenu)
733 {
734 EnableMenuItem(sysmenu, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
735 SetWindowPos(hwndForm, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
736 RedrawWindow(hwndForm, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);
737 }
738 }
739 #endif
740
741 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_MOVE, &gate_ui_form_events, &form->ctrl);
742 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_SIZE, &gate_ui_form_events, &form->ctrl);
743 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_CLOSE, &gate_ui_form_events, &form->ctrl);
744 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_ACTIVATE, &gate_ui_form_events, &form->ctrl);
745 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_COMMAND, &gate_ui_form_events, &form->ctrl);
746 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_DESTROY, &gate_ui_form_events, &form->ctrl);
747 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_ERASEBKGND, &gate_ui_form_events, &form->ctrl);
748
749 #if defined(GATE_SYS_WINCE)
750 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_SETTINGCHANGE, &gate_ui_form_events, &form->ctrl);
751 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_SYSCOMMAND, &gate_ui_form_events, &form->ctrl);
752 #elif !defined(GATE_SYS_WIN16)
753 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_CTLCOLORDLG, &gate_ui_form_events, &form->ctrl);
754 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_CTLCOLORSTATIC, &gate_ui_form_events, &form->ctrl);
755 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_CTLCOLOREDIT, &gate_ui_form_events, &form->ctrl);
756 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_CTLCOLORBTN, &gate_ui_form_events, &form->ctrl);
757 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_CTLCOLORLISTBOX, &gate_ui_form_events, &form->ctrl);
758 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_CTLCOLORMSGBOX, &gate_ui_form_events, &form->ctrl);
759 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_CTLCOLORSCROLLBAR, &gate_ui_form_events, &form->ctrl);
760 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_SETTINGCHANGE, &gate_ui_form_events, &form->ctrl);
761 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_GETICON, &gate_ui_form_events, &form->ctrl);
762 #endif
763
764 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
765 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_UAHDRAWMENU, &gate_ui_form_events, &form->ctrl);
766 gate_ui_winapi_register_event(host, (void*)hwndForm, WM_UAHDRAWMENUITEM, &gate_ui_form_events, &form->ctrl);
767 #endif
768
769 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE))
770 {
771 gate_ui_winapi_set_visible(&form->ctrl, true);
772 }
773 #if !defined(GATE_SYS_WIN16)
774 SendMessage(hwndForm, WM_SETICON, ICON_SMALL, (LPARAM)get_default_app_icon());
775 SendMessage(hwndForm, WM_SETICON, ICON_BIG, (LPARAM)get_default_app_icon());
776 #endif
777 }
778 return ret;
779 }
780
781 gate_result_t gate_ui_form_perform_action(gate_ui_form_t* form, gate_enumint_t action)
782 {
783 return GATE_RESULT_NOTSUPPORTED;
784 }
785
786
787 gate_result_t gate_ui_form_set_mode(gate_ui_form_t* form, gate_uint32_t mode)
788 {
789 gate_result_t ret;
790 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&form->ctrl);
791 int cmd = 0;
792 switch (mode)
793 {
794 case GATE_UI_FORM_MODE_NORMAL: cmd = SW_RESTORE; break;
795 case GATE_UI_FORM_MODE_MAXIMIZED: cmd = SW_MAXIMIZE; break;
796 case GATE_UI_FORM_MODE_MINIMIZED: cmd = SW_MINIMIZE; break;
797 default: return GATE_RESULT_INVALIDARG;
798 }
799 if (!ShowWindow(hwnd, cmd))
800 {
801 gate_win32_print_lasterror(&ret, NULL, 0);
802 }
803 else
804 {
805 ret = GATE_RESULT_OK;
806 }
807 return ret;
808 }
809
810 gate_result_t gate_ui_form_activate(gate_ui_form_t* form)
811 {
812 gate_result_t ret;
813 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&form->ctrl);
814 if (!ShowWindow(hwnd, SW_SHOW))
815 {
816 gate_win32_print_lasterror(&ret, NULL, 0);
817 }
818 else
819 {
820 #if !defined(GATE_SYS_WIN16)
821 SetForegroundWindow(hwnd);
822 #endif
823 ret = GATE_RESULT_OK;
824 }
825 return ret;
826 }
827 gate_result_t gate_ui_form_refresh(gate_ui_form_t* form)
828 {
829 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&form->ctrl);
830 if (RedrawWindow(hwnd, NULL, NULL, RDW_ERASE
831 #if defined(RDW_FRAME)
832 | RDW_FRAME
833 #endif
834 | RDW_INVALIDATE | RDW_ALLCHILDREN))
835 {
836 return GATE_RESULT_OK;
837 }
838 return GATE_RESULT_FAILED;
839 }
840
841 #if defined(GATE_SYS_WINCE)
842 HWND gate_ui_wince_create_menubar(HWND hwnd)
843 {
844 HWND ret = NULL;
845
846 do
847 {
848 SHMENUBARINFO mbi;
849 DWORD dwError;
850 RECT rc;
851 RECT rcMenuBar;
852 HMENU hmenu = CreateMenu();
853 HMENU popup = CreatePopupMenu();
854 AppendMenu(popup, MF_STRING | MF_ENABLED | MF_BYCOMMAND, 999, L"Test");
855 AppendMenu(hmenu, MF_STRING | MF_ENABLED | MF_POPUP | MF_BYCOMMAND, (UINT)popup, L"Menu");
856
857 gate_mem_clear(&mbi, sizeof(mbi));
858 mbi.cbSize = sizeof(mbi);
859 mbi.hwndParent = hwnd;
860 mbi.dwFlags = 0;
861 mbi.hInstRes = gate_win32_get_hinst();
862 mbi.nToolBarId = GATE_WINCE_TOOLBARID;
863
864 ret = SHFindMenuBar(hwnd);
865 if (ret)
866 {
867 break;
868 }
869
870 if (!SHCreateMenuBar(&mbi))
871 {
872 dwError = gate_win32_getlasterror();
873 if (ERROR_CALL_NOT_IMPLEMENTED == dwError)
874 {
875 /*TODO*/
876 }
877 break;
878 }
879
880 ret = mbi.hwndMB;
881 GetWindowRect(hwnd, &rc);
882 GetWindowRect(ret, &rcMenuBar);
883 rc.bottom -= (rcMenuBar.bottom - rcMenuBar.top);
884 MoveWindow(hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
885 DrawMenuBar(hwnd);
886
887 } while (0);
888
889 return ret;
890 }
891 #endif
892
893 gate_result_t gate_ui_form_set_menu(gate_ui_form_t* form, gate_ui_menulist_t const* menulist)
894 {
895 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
896 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&form->ctrl);
897 HMENU hmenu = (HMENU)NULL;
898
899 #if defined(GATE_SYS_WINCE)
900 hmenu = CreateMenu();
901 #else
902 hmenu = GetMenu(hwnd);
903 if (((HMENU)NULL) == hmenu)
904 {
905 hmenu = CreateMenu();
906 }
907 #endif
908
909 while (DeleteMenu(hmenu, 0, MF_BYPOSITION) == TRUE)
910 {
911 Sleep(0);
912 /* delete all existing menu entries */
913 }
914
915 #if defined(GATE_SYS_WINCE)
916 if (NULL != gate_ui_wince_create_menubar(hwnd))
917 {
918 ret = GATE_RESULT_OK;
919 form->menulist = menulist;
920 }
921 #else
922 if (menulist == NULL)
923 {
924 SetMenu(hwnd, (HMENU)NULL);
925 DestroyMenu(hmenu);
926 form->menulist = menulist;
927 }
928 else
929 {
930 gate_uint16_t startId = GATE_UI_FORM_MENU_STARTID;
931 gate_ui_winapi_build_menu((void*)hmenu, &startId, menulist);
932 if (FALSE == SetMenu(hwnd, hmenu))
933 {
934 gate_win32_print_lasterror(&ret, NULL, 0);
935 }
936 else
937 {
938 form->menulist = menulist;
939 DrawMenuBar(hwnd);
940 ret = GATE_RESULT_OK;
941 }
942 }
943 #endif
944 return ret;
945 }
946
947 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
948 {
949 gate_result_t ret = GATE_RESULT_OK;
950 form->layout = layout;
951 if (layout != NULL)
952 {
953 if (gate_ui_ctrl_is_created(&form->ctrl))
954 {
955 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(&form->ctrl);
956 gate_uint32_t line_height = gate_ui_host_default_control_height(host, 1);
957 gate_ui_position_t pose;
958 pose.pos.x = 0;
959 pose.pos.y = 0;
960 gate_ui_ctrl_get_size(&form->ctrl, &pose.size);
961 ret = gate_ui_layout_apply(layout, line_height, &pose);
962 }
963 }
964 return ret;
965 }
966 gate_result_t gate_ui_form_begin_dialog(gate_ui_form_t* form)
967 {
968 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
969
970 do
971 {
972 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&form->ctrl);
973 HWND hwndOwner = GetWindow(hwnd, GW_OWNER);
974 if (!hwnd)
975 {
976 ret = GATE_RESULT_INVALIDSTATE;
977 break;
978 }
979
980 #if defined(GATE_SYS_WINCE)
981 ShowWindow(hwnd, SW_SHOW);
982 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
983 SetForegroundWindow(hwnd);
984 SetActiveWindow(hwnd);
985 #else
986 if (hwndOwner)
987 {
988 EnableWindow(hwndOwner, FALSE);
989 }
990 ShowWindow(hwnd, SW_SHOW);
991 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
992 #endif
993 ret = GATE_RESULT_OK;
994 } while (0);
995
996 return ret;
997 }
998 gate_result_t gate_ui_form_end_dialog(gate_ui_form_t* form)
999 {
1000 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1001 do
1002 {
1003 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&form->ctrl);
1004 HWND hwndOwner = GetWindow(hwnd, GW_OWNER);
1005 if (!hwnd)
1006 {
1007 ret = GATE_RESULT_INVALIDSTATE;
1008 break;
1009 }
1010
1011 if (hwndOwner)
1012 {
1013 EnableWindow(hwndOwner, TRUE);
1014 }
1015
1016 SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
1017 ShowWindow(hwnd, SW_HIDE);
1018
1019 if (hwndOwner)
1020 {
1021 SetWindowPos(hwndOwner, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
1022 }
1023
1024 ret = GATE_RESULT_OK;
1025 } while (0);
1026
1027 return ret;
1028 }
1029
1030 gate_ui_form_t* gate_ui_form_get_top_level_form(gate_ui_ctrl_t* ctrl)
1031 {
1032 gate_ui_form_t* ret = NULL;
1033 do
1034 {
1035 gate_ui_host_t* host = NULL;
1036 HWND hwnd;
1037 if (!ctrl) break;
1038 host = gate_ui_ctrl_get_host(ctrl);
1039 if (!host) break;
1040 hwnd = (HWND)gate_ui_winapi_get_top_level_window(ctrl);
1041 if (!hwnd) break;
1042
1043 ret = (gate_ui_form_t*)gate_ui_winapi_resolve_ctrl(host, (void*)hwnd);
1044 } while (0);
1045
1046 return ret;
1047 }
1048
1049 #endif /* GATE_UI_WINAPI */
1050
1051
1052
1053 #if defined(GATE_UI_GTK)
1054
1055 #include "gate/ui/gateui_gtk.h"
1056
1057 static gboolean gate_ui_form_event_destroy(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
1058 {
1059 gate_ui_form_t* form = (gate_ui_form_t*)user_data;
1060 if (form->on_close)
1061 {
1062 form->on_close(&form->ctrl);
1063 }
1064 return TRUE;
1065 }
1066
1067 gate_result_t gate_ui_form_refresh(gate_ui_form_t* form)
1068 {
1069 gate_result_t ret = GATE_RESULT_OK;
1070
1071 if (form->layout != NULL)
1072 {
1073 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(&form->ctrl);
1074 GtkContainer* container = GATE_UI_GTK_GET_CTRL_CONTAINER(&form->ctrl);
1075 GtkWidget* menubar = (GtkWidget*)GATE_UI_GTK_GET_CTRL_PRIVATE_ARG(&form->ctrl);
1076 gate_uint32_t lineheight = gate_ui_host_default_control_height(host, 1);
1077 gate_ui_position_t position;
1078 GtkAllocation widget_alloc;
1079
1080 gtk_widget_get_allocation(GTK_WIDGET(container), &widget_alloc);
1081 if (menubar == NULL)
1082 {
1083 position.pos.x = 0;
1084 position.pos.y = 0;
1085 position.size.width = widget_alloc.width;
1086 position.size.height = widget_alloc.height;
1087 }
1088 else
1089 {
1090 position.pos.x = 0;
1091 position.pos.y = lineheight;
1092 position.size.width = widget_alloc.width;
1093 position.size.height = widget_alloc.height - lineheight;
1094 gtk_layout_move(GTK_LAYOUT(container), menubar, 0, 0);
1095 gtk_widget_set_size_request(menubar, widget_alloc.width, lineheight);
1096 }
1097 ret = gate_ui_layout_apply(form->layout, lineheight, &position);
1098 }
1099 return ret;
1100 }
1101
1102 static gboolean gate_ui_form_refresh_idle_callback(gpointer user_data)
1103 {
1104 gate_ui_form_t* form = (gate_ui_form_t*)user_data;
1105 gate_ui_form_refresh(form);
1106 return FALSE; /* FALSE means: do not invoke this callback again (until next call to g_idle_add()) */
1107 }
1108
1109 static gboolean gate_ui_form_event_configure(GtkWindow* window, GdkEventConfigure* evt, gpointer data)
1110 {
1111 gate_ui_form_t* form = (gate_ui_form_t*)data;
1112 gate_ui_position_t position;
1113
1114 g_idle_add(&gate_ui_form_refresh_idle_callback, form);
1115
1116 position.pos.x = evt->x;
1117 position.pos.y = evt->y;
1118 position.size.width = evt->width;
1119 position.size.height = evt->height;
1120
1121 if (form->on_move != NULL)
1122 {
1123 form->on_move(&form->ctrl, &position.pos);
1124 }
1125 if (form->on_resize != NULL)
1126 {
1127 form->on_resize(&form->ctrl, &position.size);
1128 }
1129 return FALSE;
1130 }
1131
1132 gate_result_t gate_ui_form_create(gate_ui_form_t* form, gate_ui_host_t* host, gate_ui_position_t const* position,
1133 gate_string_t const* title, gate_uint32_t flags, gate_ui_form_t* owner, void* userparam)
1134 {
1135 gate_result_t ret;
1136
1137 do
1138 {
1139 GtkWidget* window;
1140 /*GtkWidget* container;*/
1141
1142 gate_mem_clear(form, sizeof(gate_ui_form_t));
1143
1144 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1145 if (window == NULL)
1146 {
1147 ret = GATE_RESULT_FAILED;
1148 break;
1149 }
1150
1151 ret = gate_ui_gtk_ctrl_init(&form->ctrl, window, host, userparam, NULL, NULL, true, true, NULL, NULL);
1152 GATE_BREAK_IF_FAILED(ret);
1153
1154 if (owner != NULL)
1155 {
1156 GtkWidget* owner_window = GATE_UI_GTK_GET_CTRL_WIDGET(&owner->ctrl);
1157 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(owner_window));
1158 }
1159
1160 if (position != NULL)
1161 {
1162 gtk_window_set_default_size(GTK_WINDOW(window), position->size.width, position->size.height);
1163 gtk_widget_set_size_request(window, position->size.width, position->size.height);
1164 gtk_window_move(GTK_WINDOW(window), position->pos.x, position->pos.y);
1165 }
1166 else
1167 {
1168 gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
1169 }
1170
1171 /*
1172 container = gtk_layout_new(NULL, NULL);
1173 if(container == NULL)
1174 {
1175 gtk_widget_destroy(window);
1176 ret = GATE_RESULT_OUTOFRESOURCES;
1177 break;
1178 }
1179 gtk_container_add(GTK_CONTAINER(window), container);
1180
1181 gtk_widget_realize(window);
1182 gtk_widget_realize(container);
1183
1184 gtk_widget_set_redraw_on_allocate(window, TRUE);
1185 gtk_widget_set_redraw_on_allocate(container, TRUE);
1186
1187 gtk_widget_show(container);
1188
1189 GATE_UI_GTK_SET_CTRL_WIDGET(&form->ctrl, window);
1190 GATE_UI_GTK_SET_CTRL_HOST(&form->ctrl, host);
1191 GATE_UI_GTK_SET_CTRL_USER_PARAM(&form->ctrl, userparam);
1192 GATE_UI_GTK_SET_CTRL_CONTAINER(&form->ctrl, container);
1193
1194 //gtk_widget_add_events(GTK_WIDGET(window), GDK_CONFIGURE);
1195 */
1196
1197 if (gate_string_length(title) > 0)
1198 {
1199 gchar titletext[1024];
1200 gate_str_print_text(titletext, sizeof(titletext), title->str, title->length);
1201 gtk_window_set_title((GtkWindow*)window, titletext);
1202 }
1203
1204 g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(gate_ui_form_event_destroy), (gpointer)form);
1205 g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(gate_ui_form_event_configure), (gpointer)form);
1206
1207 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE))
1208 {
1209 gtk_widget_show(GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl));
1210 }
1211 //gate_ui_gtk_ctrl_set_visible(&form->ctrl, GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE));
1212 gate_ui_gtk_ctrl_set_enabled(&form->ctrl, GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED));
1213
1214 ret = GATE_RESULT_OK;
1215 } while (0);
1216 return ret;
1217 }
1218
1219 gate_result_t gate_ui_form_perform_action(gate_ui_form_t* form, gate_enumint_t action)
1220 {
1221 return GATE_RESULT_NOTSUPPORTED;
1222 }
1223
1224 gate_result_t gate_ui_form_set_mode(gate_ui_form_t* form, gate_uint32_t mode)
1225 {
1226 return GATE_RESULT_NOTIMPLEMENTED;
1227 }
1228
1229 gate_result_t gate_ui_form_activate(gate_ui_form_t* form)
1230 {
1231 gate_result_t ret = GATE_RESULT_FAILED;
1232 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl);
1233 if (widget)
1234 {
1235 gtk_window_present(GTK_WINDOW(widget));
1236 ret = GATE_RESULT_OK;
1237 }
1238 return ret;
1239 }
1240
1241 static gchar const gate_ui_gtk_menu_attachment[] = "gate_gtk_menu";
1242
1243 static gate_ui_menu_entry_t const* resolve_menu(gate_uint16_t* id_counter, gate_uint16_t required_id, gate_ui_menulist_t const* menulist)
1244 {
1245 gate_size_t index;
1246
1247 for (index = 0; index != menulist->count; ++index)
1248 {
1249 gate_ui_menu_entry_t const* entry = &menulist->entries[index];
1250 gate_uint16_t current_id = (*id_counter)++;
1251
1252 if (current_id == required_id)
1253 {
1254 /* entry found here */
1255 return entry;
1256 }
1257
1258 switch (entry->entry_type)
1259 {
1260 case GATE_UI_MENU_TYPE_SEPARATOR:
1261 {
1262 /* separators have no submenus*/
1263 break;
1264 }
1265 case GATE_UI_MENU_TYPE_TEXT:
1266 default:
1267 {
1268 if (entry->submenus != NULL)
1269 {
1270 gate_ui_menu_entry_t const* sub_entry = resolve_menu(id_counter, required_id, entry->submenus);
1271 if (sub_entry != NULL)
1272 {
1273 return sub_entry;
1274 }
1275 }
1276 break;
1277 }
1278 }
1279 }
1280 return NULL;
1281 }
1282
1283 static void gate_ui_form_menu_activated(GtkMenuItem* menuitem, gpointer user_data)
1284 {
1285 gate_ui_form_t* form = (gate_ui_form_t*)user_data;
1286
1287 if (form->on_menu)
1288 {
1289 gpointer menu_attachment = g_object_get_data(G_OBJECT(menuitem), gate_ui_gtk_menu_attachment);
1290 gate_uint16_t selected_menu_id = (gate_uint16_t)(gate_uintptr_t)menu_attachment;
1291 gate_uint16_t menu_id_counter = 1;
1292 gate_ui_menu_entry_t const* found_menu_entry = resolve_menu(&menu_id_counter, selected_menu_id, form->menulist);
1293 if (found_menu_entry)
1294 {
1295 form->on_menu(&form->ctrl, found_menu_entry);
1296 }
1297 }
1298 }
1299
1300 static void attach_menu_list(gate_ui_form_t* form, GtkWidget* menu, gate_uint16_t* id_counter, gate_ui_menulist_t const* menulist)
1301 {
1302 gate_size_t index;
1303 for (index = 0; index != menulist->count; ++index)
1304 {
1305 gate_ui_menu_entry_t const* entry = &menulist->entries[index];
1306 gate_uint16_t current_id = (*id_counter)++;
1307 GtkWidget* menuitem;
1308
1309 switch (entry->entry_type)
1310 {
1311 case GATE_UI_MENU_TYPE_SEPARATOR:
1312 {
1313 menuitem = gtk_separator_menu_item_new();
1314 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1315 break;
1316 }
1317 case GATE_UI_MENU_TYPE_TEXT:
1318 default:
1319 {
1320 menuitem = gtk_menu_item_new_with_label(entry->text);
1321
1322 if (entry->submenus != NULL)
1323 {
1324 GtkWidget* submenu = gtk_menu_new();
1325 attach_menu_list(form, submenu, id_counter, entry->submenus);
1326 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
1327 }
1328 else
1329 {
1330 g_object_set_data(G_OBJECT(menuitem), gate_ui_gtk_menu_attachment, (gpointer)(gate_uintptr_t)current_id);
1331 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(gate_ui_form_menu_activated), (void*)form);
1332 }
1333
1334 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1335 break;
1336 }
1337 }
1338 }
1339 }
1340
1341 gate_result_t gate_ui_form_set_menu(gate_ui_form_t* form, gate_ui_menulist_t const* menulist)
1342 {
1343 gate_result_t ret = GATE_RESULT_FAILED;
1344 GtkContainer* container = GATE_UI_GTK_GET_CTRL_CONTAINER(&form->ctrl);
1345 GtkWidget* menubar = (GtkWidget*)GATE_UI_GTK_GET_CTRL_PRIVATE_ARG(&form->ctrl);
1346 gate_uint16_t start_menu_id = 1;
1347
1348 if (menubar != NULL)
1349 {
1350 gtk_widget_destroy(menubar);
1351 GATE_UI_GTK_SET_CTRL_PRIVATE_ARG(&form->ctrl, NULL);
1352 }
1353 menubar = gtk_menu_bar_new();
1354 attach_menu_list(form, menubar, &start_menu_id, menulist);
1355 GATE_UI_GTK_SET_CTRL_PRIVATE_ARG(&form->ctrl, menubar);
1356
1357 gtk_layout_put(GTK_LAYOUT(container), menubar, 0, 0);
1358 /*gtk_widget_set_size_request(menubar, 640, 24);*/
1359 gtk_widget_realize(menubar);
1360 gtk_widget_set_redraw_on_allocate(menubar, TRUE);
1361 gtk_widget_show_all(menubar);
1362 gtk_widget_set_sensitive(menubar, TRUE);
1363
1364 form->menulist = menulist;
1365 ret = GATE_RESULT_OK;
1366 gate_ui_form_refresh(form);
1367 return ret;
1368 }
1369 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
1370 {
1371 gate_result_t ret = GATE_RESULT_OK;
1372 form->layout = layout;
1373 if (layout != NULL)
1374 {
1375 if (gate_ui_ctrl_is_created(&form->ctrl))
1376 {
1377 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(&form->ctrl);
1378 gate_uint32_t line_height = gate_ui_host_default_control_height(host, 1);
1379 gate_ui_position_t pose;
1380 pose.pos.x = 0;
1381 pose.pos.y = 0;
1382 gate_ui_ctrl_get_size(&form->ctrl, &pose.size);
1383 ret = gate_ui_layout_apply(layout, line_height, &pose);
1384 }
1385 }
1386 return ret;
1387 }
1388
1389 gate_result_t gate_ui_form_begin_dialog(gate_ui_form_t* form)
1390 {
1391 gate_result_t ret;
1392 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl);
1393 GtkWindow* owner = gtk_window_get_transient_for(GTK_WINDOW(widget));
1394 if (owner)
1395 {
1396 gtk_widget_set_sensitive(GTK_WIDGET(owner), FALSE);
1397 }
1398 ret = gate_ui_ctrl_set_visible(&form->ctrl, true);
1399 gate_ui_form_activate(form);
1400 return ret;
1401 }
1402 gate_result_t gate_ui_form_end_dialog(gate_ui_form_t* form)
1403 {
1404 gate_result_t ret;
1405 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl);
1406 GtkWindow* owner = gtk_window_get_transient_for(GTK_WINDOW(widget));
1407 ret = gate_ui_ctrl_set_visible(&form->ctrl, false);
1408 if (owner)
1409 {
1410 gtk_widget_set_sensitive(GTK_WIDGET(owner), TRUE);
1411 }
1412 return ret;
1413 }
1414
1415 gate_ui_form_t* gate_ui_form_get_top_level_form(gate_ui_ctrl_t* ctrl)
1416 {
1417 gate_ui_form_t* ret = NULL;
1418 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(ctrl);
1419 GtkWidget* top_level = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
1420 if (top_level)
1421 {
1422 if (GTK_IS_WINDOW(top_level))
1423 {
1424 gate_ui_ctrl_t* top_level_ctrl = gate_ui_gtk_ctrl_resolve(top_level);
1425 if (top_level_ctrl)
1426 {
1427 ret = (gate_ui_form_t*)top_level_ctrl;
1428 }
1429 }
1430 }
1431 return ret;
1432 }
1433
1434
1435 #endif /* GATE_UI_GTK */
1436
1437
1438
1439 #if defined(GATE_UI_MOTIF)
1440
1441 #include "gate/ui/gateui_motif.h"
1442 #include "gate/debugging.h"
1443 #include <Xm/Form.h>
1444 #include <Xm/MainW.h>
1445 #include <Xm/MenuShell.h>
1446 #include <Xm/RowColumn.h>
1447 #include <Xm/CascadeB.h>
1448 #include <Xm/SeparatoG.h>
1449 #include <Xm/PushBG.h>
1450 #include <Xm/Xm.h>
1451 #include <Xm/DialogS.h>
1452 #include <Xm/MwmUtil.h>
1453 #include <X11/Shell.h>
1454
1455 3 static gate_result_t form_apply_layout(gate_ui_form_t* ptr_form, gate_ui_position_t const* position)
1456 {
1457 3 gate_result_t ret = GATE_RESULT_FAILED;
1458
1459
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if (gate_ui_ctrl_is_created(&ptr_form->ctrl))
1460 {
1461 3 gate_ui_host_t* ptr_host = GATE_UI_MOTIF_GET_CTRL_HOST(&ptr_form->ctrl);
1462 3 gate_uint32_t ctrl_height = gate_ui_host_default_control_height(ptr_host, 1);
1463
1464 3 Widget w_menubar = (Widget)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&ptr_form->ctrl);
1465
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (w_menubar)
1466 {
1467 gate_ui_position_t newpos;
1468 3 newpos.pos.x = position->pos.x;
1469 3 newpos.pos.y = position->pos.y;
1470 3 newpos.size.width = position->size.width;
1471 3 newpos.size.height = 32;
1472 3 gate_ui_motif_widget_set_position(w_menubar, &newpos.pos, &newpos.size);
1473
1474 3 newpos.pos.x = position->pos.x;
1475 3 newpos.pos.y = position->pos.y + 32;
1476 3 newpos.size.width = position->size.width;
1477 3 newpos.size.height = position->size.height - 32;
1478
1479 3 ret = gate_ui_layout_apply(ptr_form->layout, ctrl_height, &newpos);
1480 }
1481 else
1482 {
1483 ret = gate_ui_layout_apply(ptr_form->layout, ctrl_height, position);
1484 }
1485 }
1486 3 return ret;
1487 }
1488
1489
1490 2 static gate_result_t gate_ui_form_apply_layout(gate_ui_form_t* form)
1491 {
1492 2 gate_result_t ret = GATE_RESULT_OK;
1493
1494
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!gate_ui_ctrl_is_created(&form->ctrl))
1495 {
1496 ret = GATE_RESULT_INVALIDSTATE;
1497 }
1498 else
1499 {
1500
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (form->layout != NULL)
1501 {
1502 gate_ui_position_t pose;
1503 2 pose.pos.x = 0;
1504 2 pose.pos.y = 0;
1505 2 gate_ui_ctrl_get_size(&form->ctrl, &pose.size);
1506 2 ret = form_apply_layout(form, &pose);
1507 }
1508 }
1509 2 return ret;
1510 }
1511
1512 1 static void form_container_resize_action(Widget w, XEvent* xevt, String* str, Cardinal* num_args)
1513 {
1514 1 gate_ui_form_t* ptr_form = NULL;
1515 gate_ui_position_t pos;
1516 1 XConfigureEvent* cevent = (XConfigureEvent*)xevt;
1517
1518 1 ptr_form = (gate_ui_form_t*)gate_ui_motif_widget_get_ctrl(w);
1519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!ptr_form)
1520 {
1521 return;
1522 }
1523
1524 1 pos.pos.x = 0; // cevent->x;
1525 1 pos.pos.y = 0; // cevent->y;
1526 1 pos.size.width = cevent->width - 2;
1527 1 pos.size.height = cevent->height - 2;
1528
1529 1 form_apply_layout(ptr_form, &pos);
1530 }
1531
1532 3 static void destroy_menuitem_widgets(Widget menuhost)
1533 {
1534 3 WidgetList children = NULL;
1535 3 Cardinal num_children = 0;
1536
1537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_DEBUG_ASSERT(menuhost != NULL);
1538 3 XtVaGetValues(menuhost, XmNchildren, &children, XmNnumChildren, &num_children, NULL, NULL);
1539
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 while (num_children-- > 0)
1540 {
1541 5 Widget child_widget = children[num_children];
1542
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (child_widget)
1543 {
1544 5 Widget pulldown_menu = NULL;
1545 5 XtVaGetValues(child_widget, XmNsubMenuId, &pulldown_menu, NULL, NULL);
1546
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (pulldown_menu)
1547 {
1548 2 destroy_menuitem_widgets(pulldown_menu);
1549 2 XtDestroyWidget(pulldown_menu);
1550 }
1551 5 XtDestroyWidget(child_widget);
1552 }
1553 }
1554 3 }
1555
1556 1 static gate_result_t form_destroy(gate_ui_ctrl_t* ctrl)
1557 {
1558 Widget menubar_widget;
1559
1560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(ctrl != NULL);
1561 1 menubar_widget = (Widget)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(ctrl);
1562
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (menubar_widget)
1563 {
1564 1 destroy_menuitem_widgets(menubar_widget);
1565 1 XtDestroyWidget(menubar_widget);
1566 1 GATE_UI_MOTIF_SET_CTRL_PRIVATE_ARG(ctrl, NULL);
1567 }
1568
1569 1 return gate_ui_motif_ctrl_destroy_default(ctrl);
1570 }
1571
1572 static gate_result_t form_get_text(gate_ui_ctrl_t* ctrl, gate_string_t* ptr_text)
1573 {
1574 Widget w;
1575
1576 if (!ctrl)
1577 {
1578 return GATE_RESULT_INVALIDSTATE;
1579 }
1580 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
1581 if (!w)
1582 {
1583 return GATE_RESULT_INVALIDSTATE;
1584 }
1585 if (ptr_text)
1586 {
1587 String ctxt = NULL;
1588 XtVaGetValues(w, XmNtitle, &ctxt, NULL, NULL);
1589 if (NULL == gate_string_create(ptr_text, ctxt, gate_str_length(ctxt)))
1590 {
1591 return GATE_RESULT_OUTOFMEMORY;
1592 }
1593 }
1594 return GATE_RESULT_OK;
1595 }
1596
1597 1 static gate_result_t form_set_text(gate_ui_ctrl_t* ctrl, gate_string_t const* text)
1598 {
1599 Widget w;
1600 1 gate_cstrbuffer8_t ctxt = GATE_INIT_EMPTY;
1601
1602
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!ctrl)
1603 {
1604 return GATE_RESULT_INVALIDSTATE;
1605 }
1606 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
1607
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w)
1608 {
1609 return GATE_RESULT_INVALIDSTATE;
1610 }
1611
1612
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_cstrbuffer_create_string(&ctxt, text, false))
1613 {
1614 return GATE_RESULT_OUTOFMEMORY;
1615 }
1616
1617 1 XtVaSetValues(w, XmNtitle, gate_cstrbuffer_get(&ctxt), NULL, NULL);
1618
1619 1 gate_cstrbuffer_destroy(&ctxt);
1620 1 return GATE_RESULT_OK;
1621 }
1622
1623 static gate_result_t form_get_state(gate_ui_ctrl_t* ctrl, gate_int32_t* ptr_state)
1624 {
1625 return GATE_RESULT_NOTIMPLEMENTED;
1626 }
1627
1628 static gate_result_t form_set_state(gate_ui_ctrl_t* ctrl, gate_int32_t state)
1629 {
1630 return GATE_RESULT_NOTIMPLEMENTED;
1631 }
1632
1633 1 static gate_result_t form_refresh(gate_ui_ctrl_t* ctrl)
1634 {
1635 1 gate_ui_form_t* form = (gate_ui_form_t*)ctrl;
1636 1 gate_result_t ret = gate_ui_motif_ctrl_refresh(ctrl);
1637 1 gate_ui_form_apply_layout(form);
1638 1 return ret;
1639 }
1640
1641
1642 static gate_ui_motif_dispatcher_t form_dispatcher =
1643 {
1644 &form_destroy,
1645 &form_get_text,
1646 &form_set_text,
1647 &form_get_state,
1648 &form_set_state,
1649 &form_refresh
1650 };
1651
1652
1653 static gate_ui_position_t const form_default_pos = { { 0, 0 }, { 640, 480 } };
1654
1655 1 gate_result_t gate_ui_form_create(gate_ui_form_t* form, gate_ui_host_t* host, gate_ui_position_t const* position,
1656 gate_string_t const* title, gate_uint32_t flags, gate_ui_form_t* owner, void* userparam)
1657 {
1658 gate_result_t ret;
1659 do
1660 {
1661 1 Widget w = NULL;
1662 1 Widget c = NULL;
1663 1 XtAppContext appctx = NULL;
1664 XtActionsRec actions[1];
1665 1 WidgetClass widget_cls = applicationShellWidgetClass;
1666 Arg args[20];
1667 1 unsigned argc = 0;
1668
1669
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!position)
1670 {
1671 1 position = &form_default_pos;
1672 }
1673
1674
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_FORM_DIALOGSTYLE) && (owner != NULL))
1675 {
1676 Widget w_owner = GATE_UI_MOTIF_GET_CTRL_WIDGET(&owner->ctrl);
1677 if (w_owner)
1678 {
1679 XtSetArg(args[argc], XmNtransientFor, w_owner); ++argc;
1680 }
1681 }
1682
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_RESIZABLE))
1683 {
1684 1 XtSetArg(args[argc], XtNallowShellResize, True); ++argc;
1685 1 XtSetArg(args[argc], XmNallowResize, True); ++argc;
1686 1 XtSetArg(args[argc], XmNnoResize, False); ++argc;
1687 1 XtSetArg(args[argc], XmNmwmFunctions, (MWM_FUNC_ALL | MWM_FUNC_MAXIMIZE)); ++argc;
1688 1 XtSetArg(args[argc], XmNmwmDecorations, (MWM_DECOR_ALL | MWM_DECOR_MAXIMIZE)); ++argc;
1689 }
1690
1691 1 ret = gate_ui_motif_ctrl_create(&form->ctrl, widget_cls,
1692 userparam, host, NULL, position, &flags, true, NULL, args, argc);
1693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1694
1695 1 GATE_UI_MOTIF_SET_CTRL_DISP(&form->ctrl, &form_dispatcher);
1696
1697 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1698
1699 1 appctx = (XtAppContext)GATE_UI_MOTIF_GET_HOST_APPHANDLE(host);
1700 1 actions[0].string = "resize";
1701 1 actions[0].proc = &form_container_resize_action;
1702 1 XtAppAddActions(appctx, actions, 1);
1703
1704 1 c = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&form->ctrl);
1705
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (c)
1706 {
1707 1 XtOverrideTranslations(c, XtParseTranslationTable("<Configure>: resize()"));
1708 }
1709
1710 1 form_set_text(&form->ctrl, title);
1711 } while (0);
1712
1713 1 return ret;
1714 }
1715
1716 gate_result_t gate_ui_form_perform_action(gate_ui_form_t* form, gate_enumint_t action)
1717 {
1718 return GATE_RESULT_NOTSUPPORTED;
1719 }
1720
1721 gate_result_t gate_ui_form_set_mode(gate_ui_form_t* form, gate_uint32_t mode)
1722 {
1723 gate_result_t ret = GATE_RESULT_OK;
1724 /* TODO */
1725 return ret;
1726 }
1727 gate_result_t gate_ui_form_activate(gate_ui_form_t* form)
1728 {
1729 gate_result_t ret = GATE_RESULT_OK;
1730 /* TODO */
1731 return ret;
1732 }
1733
1734 static void on_submenu_widget_click(Widget widget, XtPointer client_data, XtPointer call_data)
1735 {
1736 gate_ui_form_t* ptr_form = (gate_ui_form_t*)client_data;
1737
1738 if (ptr_form)
1739 {
1740 void* entry_id = NULL;
1741 gate_uint32_t menu_entry_id = 0;
1742 gate_ui_menu_entry_t const* ptr_selected_entry = NULL;
1743
1744 XtVaGetValues(widget, XmNuserData, &entry_id, NULL, NULL);
1745 menu_entry_id = (gate_uint32_t)(gate_uintptr_t)entry_id;
1746 ptr_selected_entry = gate_ui_menulist_resolve(ptr_form->menulist, menu_entry_id);
1747 if (ptr_selected_entry)
1748 {
1749 ptr_form->on_menu(&ptr_form->ctrl, ptr_selected_entry);
1750 }
1751 }
1752 }
1753
1754
1755 2 static gate_result_t gate_ui_form_create_submenu_widgets(gate_ui_form_t* ptr_form, Widget pulldown_menu, gate_ui_menulist_t const* submenu)
1756 {
1757 gate_size_t ndx;
1758
1759
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (ndx = 0; ndx != submenu->count; ++ndx)
1760 {
1761 4 gate_ui_menu_entry_t const* entry = &submenu->entries[ndx];
1762
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (entry->entry_type == GATE_UI_MENU_TYPE_SEPARATOR)
1763 {
1764 /* TODO */
1765 }
1766
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 else if (entry->entry_type == GATE_UI_MENU_TYPE_TEXT)
1767 {
1768 3 XmString label = gate_ui_motif_create_chr_string(entry->text);
1769 3 Widget w_menuentry = XtVaCreateManagedWidget(
1770 NULL, xmPushButtonGadgetClass, pulldown_menu,
1771 XmNlabelString, label,
1772 3 XmNuserData, (void*)(gate_uintptr_t)entry->id,
1773 NULL, NULL);
1774 3 XmStringFree(label);
1775 3 XtAddCallback(w_menuentry, XmNactivateCallback, &on_submenu_widget_click, ptr_form);
1776 }
1777 }
1778 2 return GATE_RESULT_OK;
1779 }
1780
1781 2 static void create_pulldown_menu_name(char* buffer, gate_size_t bufferlen)
1782 {
1783 static gate_atomic_int_t idgenerator = 0;
1784 gate_strbuilder_t builder;
1785 2 gate_strbuilder_create_static(&builder, buffer, bufferlen, 0);
1786 2 gate_strbuilder_append_cstr(&builder, "gate_form_pulldownmenu_");
1787 2 gate_strbuilder_append_int32(&builder, gate_atomic_int_inc(&idgenerator));
1788 2 }
1789
1790 1 static gate_result_t gate_ui_form_create_menu_widgets(gate_ui_form_t* form, Widget menubar_widget, gate_ui_menulist_t const* menulist)
1791 {
1792 gate_size_t ndx;
1793
1794
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (ndx = 0; ndx != menulist->count; ++ndx)
1795 {
1796 Widget pulldown_menu;
1797 XmString label;
1798 gate_ui_menu_entry_t const* entry;
1799 char pulldown_menu_name[256];
1800 2 Cardinal args_count = 0;
1801 Arg args[12];
1802
1803 2 create_pulldown_menu_name(pulldown_menu_name, sizeof(pulldown_menu_name));
1804 2 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
1805 2 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1806 2 pulldown_menu = XmCreatePulldownMenu(menubar_widget, pulldown_menu_name, args, args_count);
1807
1808 2 entry = &menulist->entries[ndx];
1809 2 label = gate_ui_motif_create_chr_string(entry->text);
1810 2 XtVaCreateManagedWidget(NULL, xmCascadeButtonWidgetClass, menubar_widget,
1811 XmNlabelString, label,
1812 XmNsubMenuId, pulldown_menu,
1813 XmNuserData, form,
1814 XmNshadowThickness, 1,
1815 XmNhighlightThickness, 1,
1816 NULL, NULL);
1817 2 XmStringFree(label);
1818
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (entry->submenus && entry->submenus->count > 0)
1819 {
1820 2 gate_ui_form_create_submenu_widgets(form, pulldown_menu, entry->submenus);
1821 }
1822 }
1823 1 return GATE_RESULT_OK;
1824 }
1825
1826 1 gate_result_t gate_ui_form_set_menu(gate_ui_form_t* form, gate_ui_menulist_t const* menulist)
1827 {
1828 1 gate_result_t ret = GATE_RESULT_FAILED;
1829
1830 do
1831 {
1832 1 Widget w_form = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&form->ctrl);
1833 1 Widget w_menubar = (Widget)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&form->ctrl);
1834
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!w_menubar)
1835 {
1836 Arg args[8];
1837 1 Cardinal args_count = 0;
1838 1 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
1839 1 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1840 1 w_menubar = XmCreateSimpleMenuBar(w_form, "MenuBar", args, args_count);
1841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w_menubar)
1842 {
1843 ret = GATE_RESULT_OUTOFMEMORY;
1844 break;
1845 }
1846 1 GATE_UI_MOTIF_SET_CTRL_PRIVATE_ARG(&form->ctrl, (void*)w_menubar);
1847 1 XtManageChild(w_menubar);
1848 }
1849 else
1850 {
1851 destroy_menuitem_widgets(w_menubar);
1852 }
1853
1854 1 ret = gate_ui_form_create_menu_widgets(form, w_menubar, menulist);
1855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1856
1857 1 form->menulist = menulist;
1858 1 ret = GATE_RESULT_OK;
1859 } while (0);
1860
1861 1 return ret;
1862 }
1863
1864 1 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
1865 {
1866 1 form->layout = layout;
1867 1 return gate_ui_form_apply_layout(form);
1868 }
1869 gate_result_t gate_ui_form_refresh(gate_ui_form_t* form)
1870 {
1871 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1872 if (!w)
1873 {
1874 return GATE_RESULT_INVALIDSTATE;
1875 }
1876 XtRealizeWidget(w);
1877 gate_ui_form_apply_layout(form);
1878 return GATE_RESULT_OK;
1879 }
1880 gate_result_t gate_ui_form_begin_dialog(gate_ui_form_t* form)
1881 {
1882 gate_result_t ret = GATE_RESULT_FAILED;
1883
1884 GATE_DEBUG_ASSERT(form != NULL);
1885 do
1886 {
1887 Widget w_owner = NULL;
1888 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1889 if (NULL == w)
1890 {
1891 ret = GATE_RESULT_INVALIDSTATE;
1892 break;
1893 }
1894
1895 XtPopup(w, XtGrabNone);
1896
1897 if (w_owner)
1898 {
1899 /* TODO */
1900 }
1901
1902 ret = GATE_RESULT_OK;
1903 } while (0);
1904 return ret;
1905 }
1906 gate_result_t gate_ui_form_end_dialog(gate_ui_form_t* form)
1907 {
1908 gate_result_t ret = GATE_RESULT_FAILED;
1909
1910 GATE_DEBUG_ASSERT(form != NULL);
1911 do
1912 {
1913 gate_ui_host_t* host = GATE_UI_MOTIF_GET_CTRL_HOST(&form->ctrl);
1914 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1915 Widget w_owner = NULL;
1916 if (NULL == w)
1917 {
1918 ret = GATE_RESULT_INVALIDSTATE;
1919 break;
1920 }
1921
1922 XtPopdown(w);
1923
1924 gate_ui_motif_host_dispatch_pending_events(host, false);
1925
1926 if (w_owner)
1927 {
1928 /* TODO */
1929 }
1930 ret = GATE_RESULT_OK;
1931 } while (0);
1932
1933 return ret;
1934 }
1935
1936 gate_ui_form_t* gate_ui_form_get_top_level_form(gate_ui_ctrl_t* ctrl)
1937 {
1938 gate_ui_ctrl_t* last_known_parent = ctrl;
1939 while (ctrl != NULL)
1940 {
1941 last_known_parent = ctrl;
1942 ctrl = gate_ui_ctrl_get_parent(ctrl);
1943 }
1944 return (gate_ui_form_t*)last_known_parent;
1945 }
1946
1947 #endif /* GATE_UI_MOTIF */
1948
1949
1950 #if defined(GATE_UI_WASMHTML)
1951
1952 #include "gate/ui/gateui_wasmhtml.h"
1953
1954 static const gate_string_t html_class_div = GATE_STRING_INIT_STATIC("div");
1955
1956 gate_result_t gate_ui_form_create(gate_ui_form_t* form, gate_ui_host_t* host, gate_ui_position_t const* position,
1957 gate_string_t const* title, gate_uint32_t flags, gate_ui_form_t* owner, void* userparam)
1958 {
1959 gate_uint32_t html_id = 0;
1960
1961 gate_ui_wasm_new_ctrl_id(host, &html_id);
1962 return gate_ui_wasm_ctrl_create(host, html_id, 0, &html_class_div, userparam, &form->ctrl);
1963 }
1964
1965 gate_result_t gate_ui_form_perform_action(gate_ui_form_t* form, gate_enumint_t action)
1966 {
1967 return GATE_RESULT_NOTSUPPORTED;
1968 }
1969
1970 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
1971 {
1972 return GATE_RESULT_NOTIMPLEMENTED;
1973 }
1974
1975
1976 #endif /* GATE_UI_WASMHTML */
1977