GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/forms.c
Date: 2026-09-21 06:26:40
Exec Total Coverage
Lines: 167 237 70.5%
Functions: 15 24 62.5%
Branches: 38 84 45.2%

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 #include "gate/debugging.h"
38
39 #include <stdio.h>
40
41 #if defined(GATE_SYS_WINCE)
42 # include <aygshell.h>
43 # if defined(GATE_COMPILER_MSVC)
44 # pragma comment(lib, "aygshell.lib")
45 # endif
46 #endif
47
48
49 #define GATE_UI_FORM_MENU_STARTID 100
50
51 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
52
53 /* https://github.com/adzm/win32-custom-menubar-aero-theme */
54 #ifndef WM_UAHDESTROYWINDOW
55 #define WM_UAHDESTROYWINDOW 0x0090
56 #endif
57
58 #ifndef WM_UAHDRAWMENU
59 #define WM_UAHDRAWMENU 0x0091
60 #endif
61
62 #ifndef WM_UAHDRAWMENUITEM
63 #define WM_UAHDRAWMENUITEM 0x0092
64 #endif
65
66 #ifndef WM_UAHINITMENU
67 #define WM_UAHINITMENU 0x0093
68 #endif
69
70 #ifndef WM_UAHMEASUREMENUITEM
71 #define WM_UAHMEASUREMENUITEM 0x0094
72 #endif
73
74 #ifndef WM_UAHNCPAINTMENUPOPUP
75 #define WM_UAHNCPAINTMENUPOPUP 0x0095
76 #endif
77
78 typedef struct
79 {
80 HMENU hmenu;
81 HDC hdc;
82 DWORD dwFlags;
83 } GATE_UAHMENU;
84
85 typedef union
86 {
87 struct
88 {
89 DWORD cx;
90 DWORD cy;
91 } rgsizeBar[2];
92 struct
93 {
94 DWORD cx;
95 DWORD cy;
96 } rgsizePopup[4];
97 } GATE_UAHMENUITEMMETRICS;
98
99 typedef struct
100 {
101 DWORD rgcx[4];
102 DWORD fUpdateMaxWidths : 2;
103 } GATE_UAHMENUPOPUPMETRICS;
104
105 typedef struct
106 {
107 int iPosition; // 0-based position of menu item in menubar
108 GATE_UAHMENUITEMMETRICS umim;
109 GATE_UAHMENUPOPUPMETRICS umpm;
110 } GATE_UAHMENUITEM;
111
112 // the DRAWITEMSTRUCT contains the states of the menu items, as well as
113 // the position index of the item in the menu, which is duplicated in
114 // the UAHMENUITEM's iPosition as well
115 typedef struct
116 {
117 DRAWITEMSTRUCT dis; // itemID looks uninitialized
118 GATE_UAHMENU um;
119 GATE_UAHMENUITEM umi;
120 } GATE_UAHDRAWMENUITEM;
121
122 typedef struct
123 {
124 DWORD cbSize;
125 RECT rcBar;
126 HMENU hMenu;
127 HWND hwndMenu;
128 BOOL fBarFocused : 1;
129 BOOL fFocused : 1;
130 BOOL fUnused : 30;
131 } GATE_MENUBARINFO, * PGATE_MENUBARINFO, * LPGATE_MENUBARINFO;
132
133
134 static void gate_ui_form_apply_dark_mode_to_container(gate_ui_ctrl_t* ctrl, BOOL dark_mode)
135 {
136 gate_array_t children = GATE_INIT_EMPTY;
137 gate_result_t result;
138 HWND hwnd = GATE_UI_WINAPI_GET_HWND(ctrl);
139
140 gate_ui_winapi_apply_darkmode(hwnd, dark_mode);
141 gate_ui_ctrl_refresh(ctrl);
142
143 result = gate_ui_winapi_get_children(ctrl, &children);
144 if (GATE_SUCCEEDED(result))
145 {
146 gate_size_t ndx;
147 gate_size_t len = gate_array_length(&children);
148 for (ndx = 0; ndx != len; ++ndx)
149 {
150 gate_ui_ctrl_t* const* ptr_child = (gate_ui_ctrl_t* const*)gate_array_get(&children, ndx);
151 if (ptr_child)
152 {
153 gate_ui_form_apply_dark_mode_to_container(*ptr_child, dark_mode);
154 }
155 }
156 gate_array_release(&children);
157 }
158
159 }
160
161
162 #ifndef OBJID_CLIENT
163 #define OBJID_CLIENT ((LONG)0xFFFFFFFC)
164 #endif
165
166 #ifndef OBJID_MENU
167 #define OBJID_MENU ((LONG)0xFFFFFFFD)
168 #endif
169
170 #ifndef OBJID_SYSMENU
171 #define OBJID_SYSMENU ((LONG)0xFFFFFFFF)
172 #endif
173
174 #ifndef ODS_HOTLIGHT
175 #define ODS_HOTLIGHT 0x0040
176 #endif
177
178
179 static void gate_ui_redraw_menubar(gate_ui_ctrl_t* ctrl, HDC hdc)
180 {
181 gate_win32_userapi_t const* const userapi = gate_win32_userapi();
182 HWND hwnd = GATE_UI_WINAPI_GET_HWND(ctrl);
183 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(ctrl);
184 HBRUSH hbr_bk_gnd;
185 GATE_MENUBARINFO menu_bar_info;
186 RECT rect_window;
187 gate_ui_color_t bg_color;
188
189 gate_ui_host_default_color(host, GATE_UI_COLOR_MENUBACKGROUND, &bg_color);
190
191 hbr_bk_gnd = (HBRUSH)gate_ui_winapi_host_get_brush(host, &bg_color);
192 gate_mem_clear(&menu_bar_info, sizeof(menu_bar_info));
193 menu_bar_info.cbSize = sizeof(menu_bar_info);
194 userapi->UserGetMenuBarInfo(hwnd, OBJID_MENU, 0, &menu_bar_info);
195
196 GetWindowRect(hwnd, &rect_window);
197 OffsetRect(&menu_bar_info.rcBar, -rect_window.left, -rect_window.top);
198 rect_window.bottom++;
199 FillRect(hdc, &menu_bar_info.rcBar, hbr_bk_gnd);
200 }
201
202 #endif
203
204 static HICON WINAPI get_default_app_icon()
205 {
206 static HICON hicon = NULL;
207 if (hicon == NULL)
208 {
209 hicon = LoadIcon(GetModuleHandle(NULL), _T("APP_ICON"));
210 }
211 return hicon;
212 }
213
214 static gate_bool_t WINAPI gate_ui_form_events(ui_hwnd_t hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult)
215 {
216 if (ctrl != NULL)
217 {
218 ui_hwnd_t hwndCtrl = GATE_UI_WINAPI_GET_HWND(ctrl);
219 if (hwnd == hwndCtrl)
220 {
221 gate_ui_form_t* form = (gate_ui_form_t*)ctrl;
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 gate_ui_host_t* 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 gate_ui_host_t* 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 gate_ui_host_t* 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 gate_ui_host_t* 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((HWND)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((HWND)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 gate_ui_host_t* 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 ui_hwnd_t hwndOwner = UI_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_DEBUG_ASSERT(host != NULL);
651
652 gate_mem_clear(form, sizeof(gate_ui_form_t));
653
654 exstyles = 0;
655 styles = WS_GROUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
656
657 #if defined(GATE_SYS_WINCE)
658 ptr_activate_info = (SHACTIVATEINFO*)gate_mem_alloc(sizeof(SHACTIVATEINFO));
659 gate_mem_clear(ptr_activate_info, sizeof(SHACTIVATEINFO));
660 ptr_activate_info->cbSize = sizeof(SHACTIVATEINFO);
661 ctrl_param = ptr_activate_info;
662 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_FORM_NOCLOSE))
663 {
664 styles |= WS_SYSMENU;
665 }
666 #else
667 styles |= (WS_OVERLAPPED | WS_CAPTION);
668 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_RESIZABLE))
669 {
670 styles |= WS_SIZEBOX;
671 }
672 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_FORM_MINIMIZABLE))
673 {
674 styles |= (WS_MINIMIZEBOX | WS_SYSMENU);
675 }
676 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_FORM_MAXIMIZABLE))
677 {
678 styles |= (WS_MAXIMIZEBOX | WS_SYSMENU);
679 }
680
681 #if !defined(GATE_SYS_WIN16)
682 exstyles |= WS_EX_CONTROLPARENT;
683 if (owner == NULL)
684 {
685 exstyles |= WS_EX_APPWINDOW;
686 }
687 else
688 {
689 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_RESIZABLE))
690 {
691 exstyles |= WS_EX_TOOLWINDOW;
692 }
693 else
694 {
695 styles |= WS_DLGFRAME;
696 }
697 }
698 #endif /* GATE_SYS_WIN16 */
699
700 #endif
701
702 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED))
703 {
704 styles |= WS_DISABLED;
705 }
706 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE))
707 {
708 styles |= WS_VISIBLE;
709 }
710 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_FORM_DIALOGSTYLE))
711 {
712 styles |= WS_DLGFRAME;
713 exstyles |= WS_EX_DLGMODALFRAME;
714 }
715
716 if (owner != NULL)
717 {
718 hwndOwner = GATE_UI_WINAPI_GET_HWND(&owner->ctrl);
719 }
720
721 ret = gate_ui_winapi_create(&form->ctrl, host, hwndOwner, NULL,
722 position, styles, exstyles, title, userparam, false);
723
724 if (GATE_SUCCEEDED(ret))
725 {
726 ui_hwnd_t hwndForm;
727
728 GATE_UI_WINAPI_SET_CTRL_PARAM(&form->ctrl, ctrl_param);
729 hwndForm = GATE_UI_WINAPI_GET_HWND(&form->ctrl);
730
731 #if !defined(GATE_SYS_WINCE)
732 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_FORM_NOCLOSE))
733 {
734 HMENU sysmenu = GetSystemMenu((HWND)hwndForm, FALSE);
735 if (sysmenu)
736 {
737 EnableMenuItem(sysmenu, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
738 SetWindowPos((HWND)hwndForm, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
739 RedrawWindow((HWND)hwndForm, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);
740 }
741 }
742 #endif
743 gate_ui_winapi_register_event(host, hwndForm, WM_MOVE, &gate_ui_form_events, &form->ctrl);
744 gate_ui_winapi_register_event(host, hwndForm, WM_SIZE, &gate_ui_form_events, &form->ctrl);
745 gate_ui_winapi_register_event(host, hwndForm, WM_CLOSE, &gate_ui_form_events, &form->ctrl);
746 gate_ui_winapi_register_event(host, hwndForm, WM_ACTIVATE, &gate_ui_form_events, &form->ctrl);
747 gate_ui_winapi_register_event(host, hwndForm, WM_COMMAND, &gate_ui_form_events, &form->ctrl);
748 gate_ui_winapi_register_event(host, hwndForm, WM_DESTROY, &gate_ui_form_events, &form->ctrl);
749 gate_ui_winapi_register_event(host, hwndForm, WM_ERASEBKGND, &gate_ui_form_events, &form->ctrl);
750
751 #if defined(GATE_SYS_WINCE)
752 gate_ui_winapi_register_event(host, hwndForm, WM_SETTINGCHANGE, &gate_ui_form_events, &form->ctrl);
753 gate_ui_winapi_register_event(host, hwndForm, WM_SYSCOMMAND, &gate_ui_form_events, &form->ctrl);
754 #elif !defined(GATE_SYS_WIN16)
755 gate_ui_winapi_register_event(host, hwndForm, WM_CTLCOLORDLG, &gate_ui_form_events, &form->ctrl);
756 gate_ui_winapi_register_event(host, hwndForm, WM_CTLCOLORSTATIC, &gate_ui_form_events, &form->ctrl);
757 gate_ui_winapi_register_event(host, hwndForm, WM_CTLCOLOREDIT, &gate_ui_form_events, &form->ctrl);
758 gate_ui_winapi_register_event(host, hwndForm, WM_CTLCOLORBTN, &gate_ui_form_events, &form->ctrl);
759 gate_ui_winapi_register_event(host, hwndForm, WM_CTLCOLORLISTBOX, &gate_ui_form_events, &form->ctrl);
760 gate_ui_winapi_register_event(host, hwndForm, WM_CTLCOLORMSGBOX, &gate_ui_form_events, &form->ctrl);
761 gate_ui_winapi_register_event(host, hwndForm, WM_CTLCOLORSCROLLBAR, &gate_ui_form_events, &form->ctrl);
762 gate_ui_winapi_register_event(host, hwndForm, WM_SETTINGCHANGE, &gate_ui_form_events, &form->ctrl);
763 gate_ui_winapi_register_event(host, hwndForm, WM_GETICON, &gate_ui_form_events, &form->ctrl);
764 #endif
765
766 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
767 gate_ui_winapi_register_event(host, hwndForm, WM_UAHDRAWMENU, &gate_ui_form_events, &form->ctrl);
768 gate_ui_winapi_register_event(host, hwndForm, WM_UAHDRAWMENUITEM, &gate_ui_form_events, &form->ctrl);
769 #endif
770
771 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE))
772 {
773 gate_ui_winapi_set_visible(&form->ctrl, true);
774 }
775 #if !defined(GATE_SYS_WIN16)
776 SendMessage((HWND)hwndForm, WM_SETICON, ICON_SMALL, (LPARAM)get_default_app_icon());
777 SendMessage((HWND)hwndForm, WM_SETICON, ICON_BIG, (LPARAM)get_default_app_icon());
778 #endif
779 }
780
781 return ret;
782 }
783
784 gate_result_t gate_ui_form_perform_action(gate_ui_form_t* form, gate_enumint_t action)
785 {
786 return GATE_RESULT_NOTSUPPORTED;
787 }
788
789
790 gate_result_t gate_ui_form_set_mode(gate_ui_form_t* form, gate_uint32_t mode)
791 {
792 gate_result_t ret;
793 ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&form->ctrl);
794 int cmd = 0;
795 switch (mode)
796 {
797 case GATE_UI_FORM_MODE_NORMAL: cmd = SW_RESTORE; break;
798 case GATE_UI_FORM_MODE_MAXIMIZED: cmd = SW_MAXIMIZE; break;
799 case GATE_UI_FORM_MODE_MINIMIZED: cmd = SW_MINIMIZE; break;
800 default: return GATE_RESULT_INVALIDARG;
801 }
802 if (!ShowWindow((HWND)hwnd, cmd))
803 {
804 gate_win32_print_lasterror(&ret, NULL, 0);
805 }
806 else
807 {
808 ret = GATE_RESULT_OK;
809 }
810 return ret;
811 }
812
813 gate_result_t gate_ui_form_activate(gate_ui_form_t* form)
814 {
815 gate_result_t ret;
816 const HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&form->ctrl);
817 if (!ShowWindow(hwnd, SW_SHOW))
818 {
819 gate_win32_print_lasterror(&ret, NULL, 0);
820 }
821 else
822 {
823 #if !defined(GATE_SYS_WIN16)
824 SetForegroundWindow(hwnd);
825 #endif
826 ret = GATE_RESULT_OK;
827 }
828 return ret;
829 }
830 gate_result_t gate_ui_form_refresh(gate_ui_form_t* form)
831 {
832 HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&form->ctrl);
833 if (RedrawWindow(hwnd, NULL, NULL, RDW_ERASE
834 #if defined(RDW_FRAME)
835 | RDW_FRAME
836 #endif
837 | RDW_INVALIDATE | RDW_ALLCHILDREN))
838 {
839 return GATE_RESULT_OK;
840 }
841 return GATE_RESULT_FAILED;
842 }
843
844 #if defined(GATE_SYS_WINCE)
845 HWND gate_ui_wince_create_menubar(HWND hwnd)
846 {
847 HWND ret = NULL;
848
849 do
850 {
851 SHMENUBARINFO mbi;
852 DWORD dwError;
853 RECT rc;
854 RECT rcMenuBar;
855 HMENU hmenu = CreateMenu();
856 HMENU popup = CreatePopupMenu();
857 AppendMenu(popup, MF_STRING | MF_ENABLED | MF_BYCOMMAND, 999, L"Test");
858 AppendMenu(hmenu, MF_STRING | MF_ENABLED | MF_POPUP | MF_BYCOMMAND, (UINT)popup, L"Menu");
859
860 gate_mem_clear(&mbi, sizeof(mbi));
861 mbi.cbSize = sizeof(mbi);
862 mbi.hwndParent = hwnd;
863 mbi.dwFlags = 0;
864 mbi.hInstRes = gate_win32_get_hinst();
865 mbi.nToolBarId = GATE_WINCE_TOOLBARID;
866
867 ret = SHFindMenuBar(hwnd);
868 if (ret)
869 {
870 break;
871 }
872
873 if (!SHCreateMenuBar(&mbi))
874 {
875 dwError = gate_win32_getlasterror();
876 if (ERROR_CALL_NOT_IMPLEMENTED == dwError)
877 {
878 /*TODO*/
879 }
880 break;
881 }
882
883 ret = mbi.hwndMB;
884 GetWindowRect(hwnd, &rc);
885 GetWindowRect(ret, &rcMenuBar);
886 rc.bottom -= (rcMenuBar.bottom - rcMenuBar.top);
887 MoveWindow(hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
888 DrawMenuBar(hwnd);
889
890 } while (0);
891
892 return ret;
893 }
894 #endif
895
896 gate_result_t gate_ui_form_set_menu(gate_ui_form_t* form, gate_ui_menulist_t const* menulist)
897 {
898 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
899 HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&form->ctrl);
900 HMENU hmenu = (HMENU)NULL;
901
902 #if defined(GATE_SYS_WINCE)
903 hmenu = CreateMenu();
904 #else
905 hmenu = GetMenu(hwnd);
906 if (((HMENU)NULL) == hmenu)
907 {
908 hmenu = CreateMenu();
909 }
910 #endif
911
912 while (DeleteMenu(hmenu, 0, MF_BYPOSITION) == TRUE)
913 {
914 /* delete all existing menu entries */
915 }
916
917 #if defined(GATE_SYS_WINCE)
918 if (NULL != gate_ui_wince_create_menubar(hwnd))
919 {
920 ret = GATE_RESULT_OK;
921 form->menulist = menulist;
922 }
923 #else
924 if (menulist == NULL)
925 {
926 SetMenu(hwnd, (HMENU)NULL);
927 DestroyMenu(hmenu);
928 form->menulist = menulist;
929 }
930 else
931 {
932 gate_uint16_t startId = GATE_UI_FORM_MENU_STARTID;
933 gate_ui_winapi_build_menu((void*)hmenu, &startId, menulist);
934 if (FALSE == SetMenu(hwnd, hmenu))
935 {
936 gate_win32_print_lasterror(&ret, NULL, 0);
937 }
938 else
939 {
940 form->menulist = menulist;
941 DrawMenuBar(hwnd);
942 ret = GATE_RESULT_OK;
943 }
944 }
945 #endif
946 return ret;
947 }
948
949 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
950 {
951 gate_result_t ret = GATE_RESULT_OK;
952 form->layout = layout;
953 if (layout != NULL)
954 {
955 if (gate_ui_ctrl_is_created(&form->ctrl))
956 {
957 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(&form->ctrl);
958 gate_uint32_t line_height = gate_ui_host_default_control_height(host, 1);
959 gate_ui_position_t pose;
960 pose.pos.x = 0;
961 pose.pos.y = 0;
962 gate_ui_ctrl_get_size(&form->ctrl, &pose.size);
963 ret = gate_ui_layout_apply(layout, line_height, &pose);
964 }
965 }
966 return ret;
967 }
968 gate_result_t gate_ui_form_begin_dialog(gate_ui_form_t* form)
969 {
970 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
971
972 do
973 {
974 HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&form->ctrl);
975 HWND hwndOwner = GetWindow(hwnd, GW_OWNER);
976 if (!hwnd)
977 {
978 ret = GATE_RESULT_INVALIDSTATE;
979 break;
980 }
981
982 #if defined(GATE_SYS_WINCE)
983 ShowWindow(hwnd, SW_SHOW);
984 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
985 SetForegroundWindow(hwnd);
986 SetActiveWindow(hwnd);
987 #else
988 if (hwndOwner)
989 {
990 EnableWindow(hwndOwner, FALSE);
991 }
992 ShowWindow(hwnd, SW_SHOW);
993 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
994 #endif
995 ret = GATE_RESULT_OK;
996 } while (0);
997
998 return ret;
999 }
1000 gate_result_t gate_ui_form_end_dialog(gate_ui_form_t* form)
1001 {
1002 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1003 do
1004 {
1005 HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(&form->ctrl);
1006 HWND hwndOwner = GetWindow(hwnd, GW_OWNER);
1007 if (!hwnd)
1008 {
1009 ret = GATE_RESULT_INVALIDSTATE;
1010 break;
1011 }
1012
1013 if (hwndOwner)
1014 {
1015 EnableWindow(hwndOwner, TRUE);
1016 }
1017
1018 SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
1019 ShowWindow(hwnd, SW_HIDE);
1020
1021 if (hwndOwner)
1022 {
1023 SetWindowPos(hwndOwner, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
1024 }
1025
1026 ret = GATE_RESULT_OK;
1027 } while (0);
1028
1029 return ret;
1030 }
1031
1032 gate_ui_form_t* gate_ui_form_get_top_level_form(gate_ui_ctrl_t* ctrl)
1033 {
1034 gate_ui_form_t* ret = NULL;
1035 do
1036 {
1037 gate_ui_host_t* host = NULL;
1038 ui_hwnd_t hwnd;
1039 if (!ctrl) break;
1040 host = gate_ui_ctrl_get_host(ctrl);
1041 if (!host) break;
1042 hwnd = gate_ui_winapi_get_top_level_window(ctrl);
1043 if (!hwnd) break;
1044
1045 ret = (gate_ui_form_t*)gate_ui_winapi_resolve_ctrl(host, hwnd);
1046 } while (0);
1047
1048 return ret;
1049 }
1050
1051 #endif /* GATE_UI_WINAPI */
1052
1053
1054
1055 #if defined(GATE_UI_GTK)
1056
1057 #include "gate/ui/gateui_gtk.h"
1058
1059 static gate_uint32_t form_get_text_length(gate_ui_ctrl_t* ctrl)
1060 {
1061 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(ctrl);
1062 char const* title = gtk_window_get_title((GtkWindow*)widget);
1063 return (gate_uint32_t)gate_str_length(title);
1064 }
1065
1066 static gate_result_t form_get_text(gate_ui_ctrl_t* ctrl, gate_string_t* text)
1067 {
1068 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(ctrl);
1069 char const* title = gtk_window_get_title((GtkWindow*)widget);
1070 gate_size_t len = gate_str_length(title);
1071 if (NULL == gate_string_create(text, title, len))
1072 {
1073 return GATE_RESULT_OUTOFMEMORY;
1074 }
1075 return GATE_RESULT_OK;
1076 }
1077 static gate_result_t form_set_text(gate_ui_ctrl_t* ctrl, gate_string_t const* text)
1078 {
1079 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(ctrl);
1080 gate_cstrbuffer_t buffer;
1081 gate_result_t ret;
1082
1083 do
1084 {
1085 if (NULL == gate_cstrbuffer_create_string(&buffer, text, false))
1086 {
1087 ret = GATE_RESULT_OUTOFMEMORY;
1088 break;
1089 }
1090
1091 gtk_window_set_title((GtkWindow*)widget, gate_cstrbuffer_get(&buffer));
1092
1093 gate_cstrbuffer_destroy(&buffer);
1094 ret = GATE_RESULT_OK;
1095 } while(0);
1096 return ret;
1097 }
1098 static gate_result_t form_get_state(gate_ui_ctrl_t* ctrl, gate_int32_t* value)
1099 {
1100 return GATE_RESULT_NOTSUPPORTED;
1101 }
1102 static gate_result_t form_set_state(gate_ui_ctrl_t* ctrl, gate_int32_t value)
1103 {
1104 return GATE_RESULT_NOTSUPPORTED;
1105 }
1106 static gate_result_t form_refresh(gate_ui_ctrl_t* ctrl)
1107 {
1108 gate_ui_form_t* frm = (gate_ui_form_t*)ctrl;
1109 return gate_ui_form_refresh(frm);
1110 }
1111 static gate_result_t form_destroy(gate_ui_ctrl_t* ctrl)
1112 {
1113 return gate_ui_gtk_ctrl_destroy_native(ctrl);
1114 }
1115
1116
1117 static gate_ui_gtk_dispatcher_t form_dispatcher =
1118 {
1119 &form_get_text_length,
1120 &form_get_text,
1121 &form_set_text,
1122 &form_get_state,
1123 &form_set_state,
1124 &form_refresh,
1125 &form_destroy
1126 };
1127
1128 static gboolean gate_ui_form_event_destroy(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
1129 {
1130 gate_ui_form_t* form = (gate_ui_form_t*)user_data;
1131 if (form->on_close)
1132 {
1133 form->on_close(&form->ctrl);
1134 }
1135 return TRUE;
1136 }
1137
1138 gate_result_t gate_ui_form_refresh(gate_ui_form_t* form)
1139 {
1140 gate_result_t ret = GATE_RESULT_OK;
1141
1142 if (form->layout != NULL)
1143 {
1144 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(&form->ctrl);
1145 GtkContainer* container = GATE_UI_GTK_GET_CTRL_CONTAINER(&form->ctrl);
1146 GtkWidget* menubar = (GtkWidget*)GATE_UI_GTK_GET_CTRL_PRIVATE_ARG(&form->ctrl);
1147 gate_uint32_t lineheight = gate_ui_host_default_control_height(host, 1);
1148 gate_ui_position_t position;
1149 GtkAllocation widget_alloc;
1150
1151 gtk_widget_get_allocation(GTK_WIDGET(container), &widget_alloc);
1152 if (menubar == NULL)
1153 {
1154 position.pos.x = 0;
1155 position.pos.y = 0;
1156 position.size.width = widget_alloc.width;
1157 position.size.height = widget_alloc.height;
1158 }
1159 else
1160 {
1161 position.pos.x = 0;
1162 position.pos.y = lineheight;
1163 position.size.width = widget_alloc.width;
1164 position.size.height = widget_alloc.height - lineheight;
1165 gtk_layout_move(GTK_LAYOUT(container), menubar, 0, 0);
1166 gtk_widget_set_size_request(menubar, widget_alloc.width, lineheight);
1167 }
1168 ret = gate_ui_layout_apply(form->layout, lineheight, &position);
1169 }
1170 return ret;
1171 }
1172
1173 static gboolean gate_ui_form_refresh_idle_callback(gpointer user_data)
1174 {
1175 gate_ui_form_t* form = (gate_ui_form_t*)user_data;
1176 gate_ui_form_refresh(form);
1177 return FALSE; /* FALSE means: do not invoke this callback again (until next call to g_idle_add()) */
1178 }
1179
1180 static gboolean gate_ui_form_event_configure(GtkWindow* window, GdkEventConfigure* evt, gpointer data)
1181 {
1182 gate_ui_form_t* form = (gate_ui_form_t*)data;
1183 gate_ui_position_t position;
1184
1185 g_idle_add(&gate_ui_form_refresh_idle_callback, form);
1186
1187 position.pos.x = evt->x;
1188 position.pos.y = evt->y;
1189 position.size.width = evt->width;
1190 position.size.height = evt->height;
1191
1192 if (form->on_move != NULL)
1193 {
1194 form->on_move(&form->ctrl, &position.pos);
1195 }
1196 if (form->on_resize != NULL)
1197 {
1198 form->on_resize(&form->ctrl, &position.size);
1199 }
1200 return FALSE;
1201 }
1202
1203 gate_result_t gate_ui_form_create(gate_ui_form_t* form, gate_ui_host_t* host, gate_ui_position_t const* position,
1204 gate_string_t const* title, gate_uint32_t flags, gate_ui_form_t* owner, void* userparam)
1205 {
1206 gate_result_t ret;
1207
1208 do
1209 {
1210 GtkWidget* window;
1211 /*GtkWidget* container;*/
1212
1213 gate_mem_clear(form, sizeof(gate_ui_form_t));
1214
1215 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1216 if (window == NULL)
1217 {
1218 ret = GATE_RESULT_FAILED;
1219 break;
1220 }
1221
1222 ret = gate_ui_gtk_ctrl_init(&form->ctrl, window, host, userparam, NULL, &form_dispatcher, true, true, NULL, NULL);
1223 GATE_BREAK_IF_FAILED(ret);
1224
1225 if (owner != NULL)
1226 {
1227 GtkWidget* owner_window = GATE_UI_GTK_GET_CTRL_WIDGET(&owner->ctrl);
1228 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(owner_window));
1229 }
1230
1231 if (position != NULL)
1232 {
1233 gtk_window_set_default_size(GTK_WINDOW(window), position->size.width, position->size.height);
1234 gtk_widget_set_size_request(window, position->size.width, position->size.height);
1235 gtk_window_move(GTK_WINDOW(window), position->pos.x, position->pos.y);
1236 }
1237 else
1238 {
1239 gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
1240 }
1241
1242 /*
1243 container = gtk_layout_new(NULL, NULL);
1244 if(container == NULL)
1245 {
1246 gtk_widget_destroy(window);
1247 ret = GATE_RESULT_OUTOFRESOURCES;
1248 break;
1249 }
1250 gtk_container_add(GTK_CONTAINER(window), container);
1251
1252 gtk_widget_realize(window);
1253 gtk_widget_realize(container);
1254
1255 gtk_widget_set_redraw_on_allocate(window, TRUE);
1256 gtk_widget_set_redraw_on_allocate(container, TRUE);
1257
1258 gtk_widget_show(container);
1259
1260 GATE_UI_GTK_SET_CTRL_WIDGET(&form->ctrl, window);
1261 GATE_UI_GTK_SET_CTRL_HOST(&form->ctrl, host);
1262 GATE_UI_GTK_SET_CTRL_USER_PARAM(&form->ctrl, userparam);
1263 GATE_UI_GTK_SET_CTRL_CONTAINER(&form->ctrl, container);
1264
1265 //gtk_widget_add_events(GTK_WIDGET(window), GDK_CONFIGURE);
1266 */
1267
1268 if (gate_string_length(title) > 0)
1269 {
1270 gchar titletext[1024];
1271 gate_str_print_text(titletext, sizeof(titletext), title->str, title->length);
1272 gtk_window_set_title((GtkWindow*)window, titletext);
1273 }
1274
1275 g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(gate_ui_form_event_destroy), (gpointer)form);
1276 g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(gate_ui_form_event_configure), (gpointer)form);
1277
1278 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE))
1279 {
1280 gtk_widget_show(GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl));
1281 }
1282 //gate_ui_gtk_ctrl_set_visible(&form->ctrl, GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE));
1283 gate_ui_gtk_ctrl_set_enabled(&form->ctrl, GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED));
1284
1285 ret = GATE_RESULT_OK;
1286 } while (0);
1287 return ret;
1288 }
1289
1290 gate_result_t gate_ui_form_perform_action(gate_ui_form_t* form, gate_enumint_t action)
1291 {
1292 return GATE_RESULT_NOTSUPPORTED;
1293 }
1294
1295 gate_result_t gate_ui_form_set_mode(gate_ui_form_t* form, gate_uint32_t mode)
1296 {
1297 return GATE_RESULT_NOTIMPLEMENTED;
1298 }
1299
1300 gate_result_t gate_ui_form_activate(gate_ui_form_t* form)
1301 {
1302 gate_result_t ret = GATE_RESULT_FAILED;
1303 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl);
1304 if (widget)
1305 {
1306 gtk_window_present(GTK_WINDOW(widget));
1307 ret = GATE_RESULT_OK;
1308 }
1309 return ret;
1310 }
1311
1312 static gchar const gate_ui_gtk_menu_attachment[] = "gate_gtk_menu";
1313
1314 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)
1315 {
1316 gate_size_t index;
1317
1318 for (index = 0; index != menulist->count; ++index)
1319 {
1320 gate_ui_menu_entry_t const* entry = &menulist->entries[index];
1321 gate_uint16_t current_id = (*id_counter)++;
1322
1323 if (current_id == required_id)
1324 {
1325 /* entry found here */
1326 return entry;
1327 }
1328
1329 switch (entry->entry_type)
1330 {
1331 case GATE_UI_MENU_TYPE_SEPARATOR:
1332 {
1333 /* separators have no submenus*/
1334 break;
1335 }
1336 case GATE_UI_MENU_TYPE_TEXT:
1337 default:
1338 {
1339 if (entry->submenus != NULL)
1340 {
1341 gate_ui_menu_entry_t const* sub_entry = resolve_menu(id_counter, required_id, entry->submenus);
1342 if (sub_entry != NULL)
1343 {
1344 return sub_entry;
1345 }
1346 }
1347 break;
1348 }
1349 }
1350 }
1351 return NULL;
1352 }
1353
1354 static void gate_ui_form_menu_activated(GtkMenuItem* menuitem, gpointer user_data)
1355 {
1356 gate_ui_form_t* form = (gate_ui_form_t*)user_data;
1357
1358 if (form->on_menu)
1359 {
1360 gpointer menu_attachment = g_object_get_data(G_OBJECT(menuitem), gate_ui_gtk_menu_attachment);
1361 gate_uint16_t selected_menu_id = (gate_uint16_t)(gate_uintptr_t)menu_attachment;
1362 gate_uint16_t menu_id_counter = 1;
1363 gate_ui_menu_entry_t const* found_menu_entry = resolve_menu(&menu_id_counter, selected_menu_id, form->menulist);
1364 if (found_menu_entry)
1365 {
1366 form->on_menu(&form->ctrl, found_menu_entry);
1367 }
1368 }
1369 }
1370
1371 static void attach_menu_list(gate_ui_form_t* form, GtkWidget* menu, gate_uint16_t* id_counter, gate_ui_menulist_t const* menulist)
1372 {
1373 gate_size_t index;
1374 for (index = 0; index != menulist->count; ++index)
1375 {
1376 gate_ui_menu_entry_t const* entry = &menulist->entries[index];
1377 gate_uint16_t current_id = (*id_counter)++;
1378 GtkWidget* menuitem;
1379
1380 switch (entry->entry_type)
1381 {
1382 case GATE_UI_MENU_TYPE_SEPARATOR:
1383 {
1384 menuitem = gtk_separator_menu_item_new();
1385 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1386 break;
1387 }
1388 case GATE_UI_MENU_TYPE_TEXT:
1389 default:
1390 {
1391 menuitem = gtk_menu_item_new_with_label(entry->text);
1392
1393 if (entry->submenus != NULL)
1394 {
1395 GtkWidget* submenu = gtk_menu_new();
1396 attach_menu_list(form, submenu, id_counter, entry->submenus);
1397 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
1398 }
1399 else
1400 {
1401 g_object_set_data(G_OBJECT(menuitem), gate_ui_gtk_menu_attachment, (gpointer)(gate_uintptr_t)current_id);
1402 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(gate_ui_form_menu_activated), (void*)form);
1403 }
1404
1405 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1406 break;
1407 }
1408 }
1409 }
1410 }
1411
1412 gate_result_t gate_ui_form_set_menu(gate_ui_form_t* form, gate_ui_menulist_t const* menulist)
1413 {
1414 gate_result_t ret = GATE_RESULT_FAILED;
1415 GtkContainer* container = GATE_UI_GTK_GET_CTRL_CONTAINER(&form->ctrl);
1416 GtkWidget* menubar = (GtkWidget*)GATE_UI_GTK_GET_CTRL_PRIVATE_ARG(&form->ctrl);
1417 gate_uint16_t start_menu_id = 1;
1418
1419 if (menubar != NULL)
1420 {
1421 gtk_widget_destroy(menubar);
1422 GATE_UI_GTK_SET_CTRL_PRIVATE_ARG(&form->ctrl, NULL);
1423 }
1424 menubar = gtk_menu_bar_new();
1425 attach_menu_list(form, menubar, &start_menu_id, menulist);
1426 GATE_UI_GTK_SET_CTRL_PRIVATE_ARG(&form->ctrl, menubar);
1427
1428 gtk_layout_put(GTK_LAYOUT(container), menubar, 0, 0);
1429 /*gtk_widget_set_size_request(menubar, 640, 24);*/
1430 gtk_widget_realize(menubar);
1431 gtk_widget_set_redraw_on_allocate(menubar, TRUE);
1432 gtk_widget_show_all(menubar);
1433 gtk_widget_set_sensitive(menubar, TRUE);
1434
1435 form->menulist = menulist;
1436 ret = GATE_RESULT_OK;
1437 gate_ui_form_refresh(form);
1438 return ret;
1439 }
1440 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
1441 {
1442 gate_result_t ret = GATE_RESULT_OK;
1443 form->layout = layout;
1444 if (layout != NULL)
1445 {
1446 if (gate_ui_ctrl_is_created(&form->ctrl))
1447 {
1448 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(&form->ctrl);
1449 gate_uint32_t line_height = gate_ui_host_default_control_height(host, 1);
1450 gate_ui_position_t pose;
1451 pose.pos.x = 0;
1452 pose.pos.y = 0;
1453 gate_ui_ctrl_get_size(&form->ctrl, &pose.size);
1454 ret = gate_ui_layout_apply(layout, line_height, &pose);
1455 }
1456 }
1457 return ret;
1458 }
1459
1460 gate_result_t gate_ui_form_begin_dialog(gate_ui_form_t* form)
1461 {
1462 gate_result_t ret;
1463 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl);
1464 GtkWindow* owner = gtk_window_get_transient_for(GTK_WINDOW(widget));
1465 if (owner)
1466 {
1467 gtk_widget_set_sensitive(GTK_WIDGET(owner), FALSE);
1468 }
1469 ret = gate_ui_ctrl_set_visible(&form->ctrl, true);
1470 gate_ui_form_activate(form);
1471 return ret;
1472 }
1473 gate_result_t gate_ui_form_end_dialog(gate_ui_form_t* form)
1474 {
1475 gate_result_t ret;
1476 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl);
1477 GtkWindow* owner = gtk_window_get_transient_for(GTK_WINDOW(widget));
1478 ret = gate_ui_ctrl_set_visible(&form->ctrl, false);
1479 if (owner)
1480 {
1481 gtk_widget_set_sensitive(GTK_WIDGET(owner), TRUE);
1482 }
1483 return ret;
1484 }
1485
1486 gate_ui_form_t* gate_ui_form_get_top_level_form(gate_ui_ctrl_t* ctrl)
1487 {
1488 gate_ui_form_t* ret = NULL;
1489 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(ctrl);
1490 GtkWidget* top_level = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
1491 if (top_level)
1492 {
1493 if (GTK_IS_WINDOW(top_level))
1494 {
1495 gate_ui_ctrl_t* top_level_ctrl = gate_ui_gtk_ctrl_resolve(top_level);
1496 if (top_level_ctrl)
1497 {
1498 ret = (gate_ui_form_t*)top_level_ctrl;
1499 }
1500 }
1501 }
1502 return ret;
1503 }
1504
1505
1506 #endif /* GATE_UI_GTK */
1507
1508
1509
1510 #if defined(GATE_UI_MOTIF)
1511
1512 #include "gate/ui/gateui_motif.h"
1513 #include "gate/debugging.h"
1514 #include <Xm/Form.h>
1515 #include <Xm/MainW.h>
1516 #include <Xm/MenuShell.h>
1517 #include <Xm/RowColumn.h>
1518 #include <Xm/CascadeB.h>
1519 #include <Xm/SeparatoG.h>
1520 #include <Xm/PushBG.h>
1521 #include <Xm/Xm.h>
1522 #include <Xm/DialogS.h>
1523 #include <Xm/MwmUtil.h>
1524 #include <X11/Shell.h>
1525
1526 4 static gate_result_t form_apply_layout(gate_ui_form_t* ptr_form, gate_ui_position_t const* position)
1527 {
1528 4 gate_result_t ret = GATE_RESULT_FAILED;
1529
1530
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (gate_ui_ctrl_is_created(&ptr_form->ctrl))
1531 {
1532 4 gate_ui_host_t* ptr_host = GATE_UI_MOTIF_GET_CTRL_HOST(&ptr_form->ctrl);
1533 4 gate_uint32_t ctrl_height = gate_ui_host_default_control_height(ptr_host, 1);
1534
1535 4 Widget w_menubar = (Widget)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&ptr_form->ctrl);
1536
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (w_menubar)
1537 {
1538 gate_ui_position_t newpos;
1539 4 newpos.pos.x = position->pos.x;
1540 4 newpos.pos.y = position->pos.y;
1541 4 newpos.size.width = position->size.width;
1542 4 newpos.size.height = 32;
1543 4 gate_ui_motif_widget_set_position(w_menubar, &newpos.pos, &newpos.size);
1544
1545 4 newpos.pos.x = position->pos.x;
1546 4 newpos.pos.y = position->pos.y + 32;
1547 4 newpos.size.width = position->size.width;
1548 4 newpos.size.height = position->size.height - 32;
1549
1550 4 ret = gate_ui_layout_apply(ptr_form->layout, ctrl_height, &newpos);
1551 }
1552 else
1553 {
1554 ret = gate_ui_layout_apply(ptr_form->layout, ctrl_height, position);
1555 }
1556 }
1557 4 return ret;
1558 }
1559
1560
1561 3 static gate_result_t gate_ui_form_apply_layout(gate_ui_form_t* form)
1562 {
1563 3 gate_result_t ret = GATE_RESULT_OK;
1564
1565
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (!gate_ui_ctrl_is_created(&form->ctrl))
1566 {
1567 ret = GATE_RESULT_INVALIDSTATE;
1568 }
1569 else
1570 {
1571
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (form->layout != NULL)
1572 {
1573 gate_ui_position_t pose;
1574 3 pose.pos.x = 0;
1575 3 pose.pos.y = 0;
1576 3 gate_ui_ctrl_get_size(&form->ctrl, &pose.size);
1577 3 ret = form_apply_layout(form, &pose);
1578 }
1579 }
1580 3 return ret;
1581 }
1582
1583 1 static void form_container_resize_action(Widget w, XEvent* xevt, String* str, Cardinal* num_args)
1584 {
1585 1 gate_ui_form_t* ptr_form = NULL;
1586 gate_ui_position_t pos;
1587 1 XConfigureEvent* cevent = (XConfigureEvent*)xevt;
1588
1589 1 ptr_form = (gate_ui_form_t*)gate_ui_motif_widget_get_ctrl(w);
1590
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!ptr_form)
1591 {
1592 return;
1593 }
1594
1595 1 pos.pos.x = 0; // cevent->x;
1596 1 pos.pos.y = 0; // cevent->y;
1597 1 pos.size.width = cevent->width - 2;
1598 1 pos.size.height = cevent->height - 2;
1599
1600 1 form_apply_layout(ptr_form, &pos);
1601 }
1602
1603 3 static void destroy_menuitem_widgets(Widget menuhost)
1604 {
1605 3 WidgetList children = NULL;
1606 3 Cardinal num_children = 0;
1607
1608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_DEBUG_ASSERT(menuhost != NULL);
1609 3 XtVaGetValues(menuhost, XmNchildren, &children, XmNnumChildren, &num_children, NULL, NULL);
1610
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 while (num_children-- > 0)
1611 {
1612 5 Widget child_widget = children[num_children];
1613
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (child_widget)
1614 {
1615 5 Widget pulldown_menu = NULL;
1616 5 XtVaGetValues(child_widget, XmNsubMenuId, &pulldown_menu, NULL, NULL);
1617
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (pulldown_menu)
1618 {
1619 2 destroy_menuitem_widgets(pulldown_menu);
1620 2 XtDestroyWidget(pulldown_menu);
1621 }
1622 5 XtDestroyWidget(child_widget);
1623 }
1624 }
1625 3 }
1626
1627 1 static gate_result_t form_destroy(gate_ui_ctrl_t* ctrl)
1628 {
1629 Widget menubar_widget;
1630
1631
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(ctrl != NULL);
1632 1 menubar_widget = (Widget)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(ctrl);
1633
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (menubar_widget)
1634 {
1635 1 destroy_menuitem_widgets(menubar_widget);
1636 1 XtDestroyWidget(menubar_widget);
1637 1 GATE_UI_MOTIF_SET_CTRL_PRIVATE_ARG(ctrl, NULL);
1638 }
1639
1640 1 return gate_ui_motif_ctrl_destroy_default(ctrl);
1641 }
1642
1643 1 static gate_result_t form_get_text(gate_ui_ctrl_t* ctrl, gate_string_t* ptr_text)
1644 {
1645 Widget w;
1646
1647
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!ctrl)
1648 {
1649 return GATE_RESULT_INVALIDSTATE;
1650 }
1651 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
1652
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w)
1653 {
1654 return GATE_RESULT_INVALIDSTATE;
1655 }
1656
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_text)
1657 {
1658 1 String ctxt = NULL;
1659 1 XtVaGetValues(w, XmNtitle, &ctxt, NULL, NULL);
1660
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (NULL == gate_string_create(ptr_text, ctxt, gate_str_length(ctxt)))
1661 {
1662 return GATE_RESULT_OUTOFMEMORY;
1663 }
1664 }
1665 1 return GATE_RESULT_OK;
1666 }
1667
1668 1 static gate_result_t form_set_text(gate_ui_ctrl_t* ctrl, gate_string_t const* text)
1669 {
1670 Widget w;
1671 1 gate_cstrbuffer8_t ctxt = GATE_INIT_EMPTY;
1672
1673
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!ctrl)
1674 {
1675 return GATE_RESULT_INVALIDSTATE;
1676 }
1677 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
1678
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w)
1679 {
1680 return GATE_RESULT_INVALIDSTATE;
1681 }
1682
1683
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_cstrbuffer_create_string(&ctxt, text, false))
1684 {
1685 return GATE_RESULT_OUTOFMEMORY;
1686 }
1687
1688 1 XtVaSetValues(w, XmNtitle, gate_cstrbuffer_get(&ctxt), NULL, NULL);
1689
1690 1 gate_cstrbuffer_destroy(&ctxt);
1691 1 return GATE_RESULT_OK;
1692 }
1693
1694 static gate_result_t form_get_state(gate_ui_ctrl_t* ctrl, gate_int32_t* ptr_state)
1695 {
1696 return GATE_RESULT_NOTIMPLEMENTED;
1697 }
1698
1699 static gate_result_t form_set_state(gate_ui_ctrl_t* ctrl, gate_int32_t state)
1700 {
1701 return GATE_RESULT_NOTIMPLEMENTED;
1702 }
1703
1704 1 static gate_result_t form_refresh(gate_ui_ctrl_t* ctrl)
1705 {
1706 1 gate_ui_form_t* form = (gate_ui_form_t*)ctrl;
1707 1 gate_result_t ret = gate_ui_motif_ctrl_refresh(ctrl);
1708 1 gate_ui_form_apply_layout(form);
1709 1 return ret;
1710 }
1711
1712
1713 static gate_ui_motif_dispatcher_t form_dispatcher =
1714 {
1715 &form_destroy,
1716 &form_get_text,
1717 &form_set_text,
1718 &form_get_state,
1719 &form_set_state,
1720 &form_refresh
1721 };
1722
1723
1724 static gate_ui_position_t const form_default_pos = { { 0, 0 }, { 640, 480 } };
1725
1726 1 gate_result_t gate_ui_form_create(gate_ui_form_t* form, gate_ui_host_t* host, gate_ui_position_t const* position,
1727 gate_string_t const* title, gate_uint32_t flags, gate_ui_form_t* owner, void* userparam)
1728 {
1729 gate_result_t ret;
1730 do
1731 {
1732 1 Widget w = NULL;
1733 1 Widget c = NULL;
1734 1 XtAppContext appctx = NULL;
1735 XtActionsRec actions[1];
1736 1 WidgetClass widget_cls = applicationShellWidgetClass;
1737 Arg args[20];
1738 1 unsigned argc = 0;
1739
1740
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!position)
1741 {
1742 1 position = &form_default_pos;
1743 }
1744
1745
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))
1746 {
1747 Widget w_owner = GATE_UI_MOTIF_GET_CTRL_WIDGET(&owner->ctrl);
1748 if (w_owner)
1749 {
1750 XtSetArg(args[argc], XmNtransientFor, w_owner); ++argc;
1751 }
1752 }
1753
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_RESIZABLE))
1754 {
1755 1 XtSetArg(args[argc], XtNallowShellResize, True); ++argc;
1756 1 XtSetArg(args[argc], XmNallowResize, True); ++argc;
1757 1 XtSetArg(args[argc], XmNnoResize, False); ++argc;
1758 1 XtSetArg(args[argc], XmNmwmFunctions, (MWM_FUNC_ALL | MWM_FUNC_MAXIMIZE)); ++argc;
1759 1 XtSetArg(args[argc], XmNmwmDecorations, (MWM_DECOR_ALL | MWM_DECOR_MAXIMIZE)); ++argc;
1760 }
1761
1762 1 ret = gate_ui_motif_ctrl_create(&form->ctrl, widget_cls,
1763 userparam, host, NULL, position, &flags, true, NULL, args, argc);
1764
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1765
1766 1 GATE_UI_MOTIF_SET_CTRL_DISP(&form->ctrl, &form_dispatcher);
1767
1768 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1769
1770 1 appctx = (XtAppContext)GATE_UI_MOTIF_GET_HOST_APPHANDLE(host);
1771 1 actions[0].string = "resize";
1772 1 actions[0].proc = &form_container_resize_action;
1773 1 XtAppAddActions(appctx, actions, 1);
1774
1775 1 c = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&form->ctrl);
1776
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (c)
1777 {
1778 1 XtOverrideTranslations(c, XtParseTranslationTable("<Configure>: resize()"));
1779 }
1780
1781 1 form_set_text(&form->ctrl, title);
1782 } while (0);
1783
1784 1 return ret;
1785 }
1786
1787 gate_result_t gate_ui_form_perform_action(gate_ui_form_t* form, gate_enumint_t action)
1788 {
1789 return GATE_RESULT_NOTSUPPORTED;
1790 }
1791
1792 gate_result_t gate_ui_form_set_mode(gate_ui_form_t* form, gate_uint32_t mode)
1793 {
1794 gate_result_t ret = GATE_RESULT_OK;
1795 /* TODO */
1796 return ret;
1797 }
1798 gate_result_t gate_ui_form_activate(gate_ui_form_t* form)
1799 {
1800 gate_result_t ret = GATE_RESULT_OK;
1801 /* TODO */
1802 return ret;
1803 }
1804
1805 static void on_submenu_widget_click(Widget widget, XtPointer client_data, XtPointer call_data)
1806 {
1807 gate_ui_form_t* ptr_form = (gate_ui_form_t*)client_data;
1808
1809 if (ptr_form)
1810 {
1811 void* entry_id = NULL;
1812 gate_uint32_t menu_entry_id = 0;
1813 gate_ui_menu_entry_t const* ptr_selected_entry = NULL;
1814
1815 XtVaGetValues(widget, XmNuserData, &entry_id, NULL, NULL);
1816 menu_entry_id = (gate_uint32_t)(gate_uintptr_t)entry_id;
1817 ptr_selected_entry = gate_ui_menulist_resolve(ptr_form->menulist, menu_entry_id);
1818 if (ptr_selected_entry)
1819 {
1820 ptr_form->on_menu(&ptr_form->ctrl, ptr_selected_entry);
1821 }
1822 }
1823 }
1824
1825
1826 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)
1827 {
1828 gate_size_t ndx;
1829
1830
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (ndx = 0; ndx != submenu->count; ++ndx)
1831 {
1832 4 gate_ui_menu_entry_t const* entry = &submenu->entries[ndx];
1833
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (entry->entry_type == GATE_UI_MENU_TYPE_SEPARATOR)
1834 {
1835 /* TODO */
1836 }
1837
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 else if (entry->entry_type == GATE_UI_MENU_TYPE_TEXT)
1838 {
1839 3 XmString label = gate_ui_motif_create_chr_string(entry->text);
1840 3 Widget w_menuentry = XtVaCreateManagedWidget(
1841 NULL, xmPushButtonGadgetClass, pulldown_menu,
1842 XmNlabelString, label,
1843 3 XmNuserData, (void*)(gate_uintptr_t)entry->id,
1844 NULL, NULL);
1845 3 XmStringFree(label);
1846 3 XtAddCallback(w_menuentry, XmNactivateCallback, &on_submenu_widget_click, ptr_form);
1847 }
1848 }
1849 2 return GATE_RESULT_OK;
1850 }
1851
1852 2 static void create_pulldown_menu_name(char* buffer, gate_size_t bufferlen)
1853 {
1854 static gate_atomic_int_t idgenerator = 0;
1855 gate_strbuilder_t builder;
1856 2 gate_strbuilder_create_static(&builder, buffer, bufferlen, 0);
1857 2 gate_strbuilder_append_cstr(&builder, "gate_form_pulldownmenu_");
1858 2 gate_strbuilder_append_int32(&builder, gate_atomic_int_inc(&idgenerator));
1859 2 }
1860
1861 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)
1862 {
1863 gate_size_t ndx;
1864
1865
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (ndx = 0; ndx != menulist->count; ++ndx)
1866 {
1867 Widget pulldown_menu;
1868 XmString label;
1869 gate_ui_menu_entry_t const* entry;
1870 char pulldown_menu_name[256];
1871 2 Cardinal args_count = 0;
1872 Arg args[12];
1873
1874 2 create_pulldown_menu_name(pulldown_menu_name, sizeof(pulldown_menu_name));
1875 2 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
1876 2 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1877 2 pulldown_menu = XmCreatePulldownMenu(menubar_widget, pulldown_menu_name, args, args_count);
1878
1879 2 entry = &menulist->entries[ndx];
1880 2 label = gate_ui_motif_create_chr_string(entry->text);
1881 2 XtVaCreateManagedWidget(NULL, xmCascadeButtonWidgetClass, menubar_widget,
1882 XmNlabelString, label,
1883 XmNsubMenuId, pulldown_menu,
1884 XmNuserData, form,
1885 XmNshadowThickness, 1,
1886 XmNhighlightThickness, 1,
1887 NULL, NULL);
1888 2 XmStringFree(label);
1889
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)
1890 {
1891 2 gate_ui_form_create_submenu_widgets(form, pulldown_menu, entry->submenus);
1892 }
1893 }
1894 1 return GATE_RESULT_OK;
1895 }
1896
1897 1 gate_result_t gate_ui_form_set_menu(gate_ui_form_t* form, gate_ui_menulist_t const* menulist)
1898 {
1899 1 gate_result_t ret = GATE_RESULT_FAILED;
1900
1901 do
1902 {
1903 1 Widget w_form = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&form->ctrl);
1904 1 Widget w_menubar = (Widget)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&form->ctrl);
1905
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!w_menubar)
1906 {
1907 Arg args[8];
1908 1 Cardinal args_count = 0;
1909 1 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
1910 1 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1911 1 w_menubar = XmCreateSimpleMenuBar(w_form, "MenuBar", args, args_count);
1912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w_menubar)
1913 {
1914 ret = GATE_RESULT_OUTOFMEMORY;
1915 break;
1916 }
1917 1 GATE_UI_MOTIF_SET_CTRL_PRIVATE_ARG(&form->ctrl, (void*)w_menubar);
1918 1 XtManageChild(w_menubar);
1919 }
1920 else
1921 {
1922 destroy_menuitem_widgets(w_menubar);
1923 }
1924
1925 1 ret = gate_ui_form_create_menu_widgets(form, w_menubar, menulist);
1926
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1927
1928 1 form->menulist = menulist;
1929 1 ret = GATE_RESULT_OK;
1930 } while (0);
1931
1932 1 return ret;
1933 }
1934
1935 1 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
1936 {
1937 1 form->layout = layout;
1938 1 return gate_ui_form_apply_layout(form);
1939 }
1940 1 gate_result_t gate_ui_form_refresh(gate_ui_form_t* form)
1941 {
1942 1 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w)
1944 {
1945 return GATE_RESULT_INVALIDSTATE;
1946 }
1947 1 XtRealizeWidget(w);
1948 1 gate_ui_form_apply_layout(form);
1949 1 return GATE_RESULT_OK;
1950 }
1951 gate_result_t gate_ui_form_begin_dialog(gate_ui_form_t* form)
1952 {
1953 gate_result_t ret = GATE_RESULT_FAILED;
1954
1955 GATE_DEBUG_ASSERT(form != NULL);
1956 do
1957 {
1958 Widget w_owner = NULL;
1959 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1960 if (NULL == w)
1961 {
1962 ret = GATE_RESULT_INVALIDSTATE;
1963 break;
1964 }
1965
1966 XtPopup(w, XtGrabNone);
1967
1968 if (w_owner)
1969 {
1970 /* TODO */
1971 }
1972
1973 ret = GATE_RESULT_OK;
1974 } while (0);
1975 return ret;
1976 }
1977 gate_result_t gate_ui_form_end_dialog(gate_ui_form_t* form)
1978 {
1979 gate_result_t ret = GATE_RESULT_FAILED;
1980
1981 GATE_DEBUG_ASSERT(form != NULL);
1982 do
1983 {
1984 gate_ui_host_t* host = GATE_UI_MOTIF_GET_CTRL_HOST(&form->ctrl);
1985 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1986 Widget w_owner = NULL;
1987 if (NULL == w)
1988 {
1989 ret = GATE_RESULT_INVALIDSTATE;
1990 break;
1991 }
1992
1993 XtPopdown(w);
1994
1995 gate_ui_motif_host_dispatch_pending_events(host, false);
1996
1997 if (w_owner)
1998 {
1999 /* TODO */
2000 }
2001 ret = GATE_RESULT_OK;
2002 } while (0);
2003
2004 return ret;
2005 }
2006
2007 gate_ui_form_t* gate_ui_form_get_top_level_form(gate_ui_ctrl_t* ctrl)
2008 {
2009 gate_ui_ctrl_t* last_known_parent = ctrl;
2010 while (ctrl != NULL)
2011 {
2012 last_known_parent = ctrl;
2013 ctrl = gate_ui_ctrl_get_parent(ctrl);
2014 }
2015 return (gate_ui_form_t*)last_known_parent;
2016 }
2017
2018 #endif /* GATE_UI_MOTIF */
2019
2020
2021 #if defined(GATE_UI_WASMHTML)
2022
2023 #include "gate/ui/gateui_wasmhtml.h"
2024
2025 static const gate_string_t html_class_div = GATE_STRING_INIT_STATIC("div");
2026
2027 gate_result_t gate_ui_form_create(gate_ui_form_t* form, gate_ui_host_t* host, gate_ui_position_t const* position,
2028 gate_string_t const* title, gate_uint32_t flags, gate_ui_form_t* owner, void* userparam)
2029 {
2030 gate_uint32_t html_id = 0;
2031
2032 gate_ui_wasm_new_ctrl_id(host, &html_id);
2033 return gate_ui_wasm_ctrl_create(host, html_id, 0, &html_class_div, userparam, &form->ctrl);
2034 }
2035
2036 gate_result_t gate_ui_form_perform_action(gate_ui_form_t* form, gate_enumint_t action)
2037 {
2038 return GATE_RESULT_NOTSUPPORTED;
2039 }
2040
2041 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
2042 {
2043 return GATE_RESULT_NOTIMPLEMENTED;
2044 }
2045
2046
2047 #endif /* GATE_UI_WASMHTML */
2048