GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/forms.c
Date: 2026-03-20 22:56:14
Exec Total Coverage
Lines: 158 237 66.7%
Functions: 14 24 58.3%
Branches: 34 84 40.5%

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