GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/forms.c
Date: 2026-02-03 22:06:38
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 Sleep(0);
911 /* delete all existing menu entries */
912 }
913
914 #if defined(GATE_SYS_WINCE)
915 if (NULL != gate_ui_wince_create_menubar(hwnd))
916 {
917 ret = GATE_RESULT_OK;
918 form->menulist = menulist;
919 }
920 #else
921 if (menulist == NULL)
922 {
923 SetMenu(hwnd, (HMENU)NULL);
924 DestroyMenu(hmenu);
925 form->menulist = menulist;
926 }
927 else
928 {
929 gate_uint16_t startId = GATE_UI_FORM_MENU_STARTID;
930 gate_ui_winapi_build_menu((void*)hmenu, &startId, menulist);
931 if (FALSE == SetMenu(hwnd, hmenu))
932 {
933 gate_win32_print_lasterror(&ret, NULL, 0);
934 }
935 else
936 {
937 form->menulist = menulist;
938 DrawMenuBar(hwnd);
939 ret = GATE_RESULT_OK;
940 }
941 }
942 #endif
943 return ret;
944 }
945
946 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
947 {
948 gate_result_t ret = GATE_RESULT_OK;
949 form->layout = layout;
950 if (layout != NULL)
951 {
952 if (gate_ui_ctrl_is_created(&form->ctrl))
953 {
954 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(&form->ctrl);
955 gate_uint32_t line_height = gate_ui_host_default_control_height(host, 1);
956 gate_ui_position_t pose;
957 pose.pos.x = 0;
958 pose.pos.y = 0;
959 gate_ui_ctrl_get_size(&form->ctrl, &pose.size);
960 ret = gate_ui_layout_apply(layout, line_height, &pose);
961 }
962 }
963 return ret;
964 }
965 gate_result_t gate_ui_form_begin_dialog(gate_ui_form_t* form)
966 {
967 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
968
969 do
970 {
971 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&form->ctrl);
972 HWND hwndOwner = GetWindow(hwnd, GW_OWNER);
973 if (!hwnd)
974 {
975 ret = GATE_RESULT_INVALIDSTATE;
976 break;
977 }
978
979 #if defined(GATE_SYS_WINCE)
980 ShowWindow(hwnd, SW_SHOW);
981 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
982 SetForegroundWindow(hwnd);
983 SetActiveWindow(hwnd);
984 #else
985 if (hwndOwner)
986 {
987 EnableWindow(hwndOwner, FALSE);
988 }
989 ShowWindow(hwnd, SW_SHOW);
990 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
991 #endif
992 ret = GATE_RESULT_OK;
993 } while (0);
994
995 return ret;
996 }
997 gate_result_t gate_ui_form_end_dialog(gate_ui_form_t* form)
998 {
999 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
1000 do
1001 {
1002 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&form->ctrl);
1003 HWND hwndOwner = GetWindow(hwnd, GW_OWNER);
1004 if (!hwnd)
1005 {
1006 ret = GATE_RESULT_INVALIDSTATE;
1007 break;
1008 }
1009
1010 if (hwndOwner)
1011 {
1012 EnableWindow(hwndOwner, TRUE);
1013 }
1014
1015 SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
1016 ShowWindow(hwnd, SW_HIDE);
1017
1018 if (hwndOwner)
1019 {
1020 SetWindowPos(hwndOwner, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
1021 }
1022
1023 ret = GATE_RESULT_OK;
1024 } while (0);
1025
1026 return ret;
1027 }
1028
1029 gate_ui_form_t* gate_ui_form_get_top_level_form(gate_ui_ctrl_t* ctrl)
1030 {
1031 gate_ui_form_t* ret = NULL;
1032 do
1033 {
1034 gate_ui_host_t* host = NULL;
1035 HWND hwnd;
1036 if (!ctrl) break;
1037 host = gate_ui_ctrl_get_host(ctrl);
1038 if (!host) break;
1039 hwnd = (HWND)gate_ui_winapi_get_top_level_window(ctrl);
1040 if (!hwnd) break;
1041
1042 ret = (gate_ui_form_t*)gate_ui_winapi_resolve_ctrl(host, (void*)hwnd);
1043 } while (0);
1044
1045 return ret;
1046 }
1047
1048 #endif /* GATE_UI_WINAPI */
1049
1050
1051
1052 #if defined(GATE_UI_GTK)
1053
1054 #include "gate/ui/gateui_gtk.h"
1055
1056 static gate_uint32_t form_get_text_length(gate_ui_ctrl_t* ctrl)
1057 {
1058 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(ctrl);
1059 char const* title = gtk_window_get_title((GtkWindow*)widget);
1060 return (gate_uint32_t)gate_str_length(title);
1061 }
1062
1063 static gate_result_t form_get_text(gate_ui_ctrl_t* ctrl, gate_string_t* text)
1064 {
1065 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(ctrl);
1066 char const* title = gtk_window_get_title((GtkWindow*)widget);
1067 gate_size_t len = gate_str_length(title);
1068 if (NULL == gate_string_create(text, title, len))
1069 {
1070 return GATE_RESULT_OUTOFMEMORY;
1071 }
1072 return GATE_RESULT_OK;
1073 }
1074 static gate_result_t form_set_text(gate_ui_ctrl_t* ctrl, gate_string_t const* text)
1075 {
1076 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(ctrl);
1077 gate_cstrbuffer_t buffer;
1078 gate_result_t ret;
1079
1080 do
1081 {
1082 if (NULL == gate_cstrbuffer_create_string(&buffer, text, false))
1083 {
1084 ret = GATE_RESULT_OUTOFMEMORY;
1085 break;
1086 }
1087
1088 gtk_window_set_title((GtkWindow*)widget, gate_cstrbuffer_get(&buffer));
1089
1090 gate_cstrbuffer_destroy(&buffer);
1091 ret = GATE_RESULT_OK;
1092 } while(0);
1093 return ret;
1094 }
1095 static gate_result_t form_get_state(gate_ui_ctrl_t* ctrl, gate_int32_t* value)
1096 {
1097 return GATE_RESULT_NOTSUPPORTED;
1098 }
1099 static gate_result_t form_set_state(gate_ui_ctrl_t* ctrl, gate_int32_t value)
1100 {
1101 return GATE_RESULT_NOTSUPPORTED;
1102 }
1103 static gate_result_t form_refresh(gate_ui_ctrl_t* ctrl)
1104 {
1105 gate_ui_form_t* frm = (gate_ui_form_t*)ctrl;
1106 return gate_ui_form_refresh(frm);
1107 }
1108 static gate_result_t form_destroy(gate_ui_ctrl_t* ctrl)
1109 {
1110 return gate_ui_gtk_ctrl_destroy_native(ctrl);
1111 }
1112
1113
1114 static gate_ui_gtk_dispatcher_t form_dispatcher =
1115 {
1116 &form_get_text_length,
1117 &form_get_text,
1118 &form_set_text,
1119 &form_get_state,
1120 &form_set_state,
1121 &form_refresh,
1122 &form_destroy
1123 };
1124
1125 static gboolean gate_ui_form_event_destroy(GtkWidget* widget, GdkEvent* evt, gpointer user_data)
1126 {
1127 gate_ui_form_t* form = (gate_ui_form_t*)user_data;
1128 if (form->on_close)
1129 {
1130 form->on_close(&form->ctrl);
1131 }
1132 return TRUE;
1133 }
1134
1135 gate_result_t gate_ui_form_refresh(gate_ui_form_t* form)
1136 {
1137 gate_result_t ret = GATE_RESULT_OK;
1138
1139 if (form->layout != NULL)
1140 {
1141 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(&form->ctrl);
1142 GtkContainer* container = GATE_UI_GTK_GET_CTRL_CONTAINER(&form->ctrl);
1143 GtkWidget* menubar = (GtkWidget*)GATE_UI_GTK_GET_CTRL_PRIVATE_ARG(&form->ctrl);
1144 gate_uint32_t lineheight = gate_ui_host_default_control_height(host, 1);
1145 gate_ui_position_t position;
1146 GtkAllocation widget_alloc;
1147
1148 gtk_widget_get_allocation(GTK_WIDGET(container), &widget_alloc);
1149 if (menubar == NULL)
1150 {
1151 position.pos.x = 0;
1152 position.pos.y = 0;
1153 position.size.width = widget_alloc.width;
1154 position.size.height = widget_alloc.height;
1155 }
1156 else
1157 {
1158 position.pos.x = 0;
1159 position.pos.y = lineheight;
1160 position.size.width = widget_alloc.width;
1161 position.size.height = widget_alloc.height - lineheight;
1162 gtk_layout_move(GTK_LAYOUT(container), menubar, 0, 0);
1163 gtk_widget_set_size_request(menubar, widget_alloc.width, lineheight);
1164 }
1165 ret = gate_ui_layout_apply(form->layout, lineheight, &position);
1166 }
1167 return ret;
1168 }
1169
1170 static gboolean gate_ui_form_refresh_idle_callback(gpointer user_data)
1171 {
1172 gate_ui_form_t* form = (gate_ui_form_t*)user_data;
1173 gate_ui_form_refresh(form);
1174 return FALSE; /* FALSE means: do not invoke this callback again (until next call to g_idle_add()) */
1175 }
1176
1177 static gboolean gate_ui_form_event_configure(GtkWindow* window, GdkEventConfigure* evt, gpointer data)
1178 {
1179 gate_ui_form_t* form = (gate_ui_form_t*)data;
1180 gate_ui_position_t position;
1181
1182 g_idle_add(&gate_ui_form_refresh_idle_callback, form);
1183
1184 position.pos.x = evt->x;
1185 position.pos.y = evt->y;
1186 position.size.width = evt->width;
1187 position.size.height = evt->height;
1188
1189 if (form->on_move != NULL)
1190 {
1191 form->on_move(&form->ctrl, &position.pos);
1192 }
1193 if (form->on_resize != NULL)
1194 {
1195 form->on_resize(&form->ctrl, &position.size);
1196 }
1197 return FALSE;
1198 }
1199
1200 gate_result_t gate_ui_form_create(gate_ui_form_t* form, gate_ui_host_t* host, gate_ui_position_t const* position,
1201 gate_string_t const* title, gate_uint32_t flags, gate_ui_form_t* owner, void* userparam)
1202 {
1203 gate_result_t ret;
1204
1205 do
1206 {
1207 GtkWidget* window;
1208 /*GtkWidget* container;*/
1209
1210 gate_mem_clear(form, sizeof(gate_ui_form_t));
1211
1212 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1213 if (window == NULL)
1214 {
1215 ret = GATE_RESULT_FAILED;
1216 break;
1217 }
1218
1219 ret = gate_ui_gtk_ctrl_init(&form->ctrl, window, host, userparam, NULL, &form_dispatcher, true, true, NULL, NULL);
1220 GATE_BREAK_IF_FAILED(ret);
1221
1222 if (owner != NULL)
1223 {
1224 GtkWidget* owner_window = GATE_UI_GTK_GET_CTRL_WIDGET(&owner->ctrl);
1225 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(owner_window));
1226 }
1227
1228 if (position != NULL)
1229 {
1230 gtk_window_set_default_size(GTK_WINDOW(window), position->size.width, position->size.height);
1231 gtk_widget_set_size_request(window, position->size.width, position->size.height);
1232 gtk_window_move(GTK_WINDOW(window), position->pos.x, position->pos.y);
1233 }
1234 else
1235 {
1236 gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
1237 }
1238
1239 /*
1240 container = gtk_layout_new(NULL, NULL);
1241 if(container == NULL)
1242 {
1243 gtk_widget_destroy(window);
1244 ret = GATE_RESULT_OUTOFRESOURCES;
1245 break;
1246 }
1247 gtk_container_add(GTK_CONTAINER(window), container);
1248
1249 gtk_widget_realize(window);
1250 gtk_widget_realize(container);
1251
1252 gtk_widget_set_redraw_on_allocate(window, TRUE);
1253 gtk_widget_set_redraw_on_allocate(container, TRUE);
1254
1255 gtk_widget_show(container);
1256
1257 GATE_UI_GTK_SET_CTRL_WIDGET(&form->ctrl, window);
1258 GATE_UI_GTK_SET_CTRL_HOST(&form->ctrl, host);
1259 GATE_UI_GTK_SET_CTRL_USER_PARAM(&form->ctrl, userparam);
1260 GATE_UI_GTK_SET_CTRL_CONTAINER(&form->ctrl, container);
1261
1262 //gtk_widget_add_events(GTK_WIDGET(window), GDK_CONFIGURE);
1263 */
1264
1265 if (gate_string_length(title) > 0)
1266 {
1267 gchar titletext[1024];
1268 gate_str_print_text(titletext, sizeof(titletext), title->str, title->length);
1269 gtk_window_set_title((GtkWindow*)window, titletext);
1270 }
1271
1272 g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(gate_ui_form_event_destroy), (gpointer)form);
1273 g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(gate_ui_form_event_configure), (gpointer)form);
1274
1275 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE))
1276 {
1277 gtk_widget_show(GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl));
1278 }
1279 //gate_ui_gtk_ctrl_set_visible(&form->ctrl, GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE));
1280 gate_ui_gtk_ctrl_set_enabled(&form->ctrl, GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED));
1281
1282 ret = GATE_RESULT_OK;
1283 } while (0);
1284 return ret;
1285 }
1286
1287 gate_result_t gate_ui_form_perform_action(gate_ui_form_t* form, gate_enumint_t action)
1288 {
1289 return GATE_RESULT_NOTSUPPORTED;
1290 }
1291
1292 gate_result_t gate_ui_form_set_mode(gate_ui_form_t* form, gate_uint32_t mode)
1293 {
1294 return GATE_RESULT_NOTIMPLEMENTED;
1295 }
1296
1297 gate_result_t gate_ui_form_activate(gate_ui_form_t* form)
1298 {
1299 gate_result_t ret = GATE_RESULT_FAILED;
1300 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl);
1301 if (widget)
1302 {
1303 gtk_window_present(GTK_WINDOW(widget));
1304 ret = GATE_RESULT_OK;
1305 }
1306 return ret;
1307 }
1308
1309 static gchar const gate_ui_gtk_menu_attachment[] = "gate_gtk_menu";
1310
1311 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)
1312 {
1313 gate_size_t index;
1314
1315 for (index = 0; index != menulist->count; ++index)
1316 {
1317 gate_ui_menu_entry_t const* entry = &menulist->entries[index];
1318 gate_uint16_t current_id = (*id_counter)++;
1319
1320 if (current_id == required_id)
1321 {
1322 /* entry found here */
1323 return entry;
1324 }
1325
1326 switch (entry->entry_type)
1327 {
1328 case GATE_UI_MENU_TYPE_SEPARATOR:
1329 {
1330 /* separators have no submenus*/
1331 break;
1332 }
1333 case GATE_UI_MENU_TYPE_TEXT:
1334 default:
1335 {
1336 if (entry->submenus != NULL)
1337 {
1338 gate_ui_menu_entry_t const* sub_entry = resolve_menu(id_counter, required_id, entry->submenus);
1339 if (sub_entry != NULL)
1340 {
1341 return sub_entry;
1342 }
1343 }
1344 break;
1345 }
1346 }
1347 }
1348 return NULL;
1349 }
1350
1351 static void gate_ui_form_menu_activated(GtkMenuItem* menuitem, gpointer user_data)
1352 {
1353 gate_ui_form_t* form = (gate_ui_form_t*)user_data;
1354
1355 if (form->on_menu)
1356 {
1357 gpointer menu_attachment = g_object_get_data(G_OBJECT(menuitem), gate_ui_gtk_menu_attachment);
1358 gate_uint16_t selected_menu_id = (gate_uint16_t)(gate_uintptr_t)menu_attachment;
1359 gate_uint16_t menu_id_counter = 1;
1360 gate_ui_menu_entry_t const* found_menu_entry = resolve_menu(&menu_id_counter, selected_menu_id, form->menulist);
1361 if (found_menu_entry)
1362 {
1363 form->on_menu(&form->ctrl, found_menu_entry);
1364 }
1365 }
1366 }
1367
1368 static void attach_menu_list(gate_ui_form_t* form, GtkWidget* menu, gate_uint16_t* id_counter, gate_ui_menulist_t const* menulist)
1369 {
1370 gate_size_t index;
1371 for (index = 0; index != menulist->count; ++index)
1372 {
1373 gate_ui_menu_entry_t const* entry = &menulist->entries[index];
1374 gate_uint16_t current_id = (*id_counter)++;
1375 GtkWidget* menuitem;
1376
1377 switch (entry->entry_type)
1378 {
1379 case GATE_UI_MENU_TYPE_SEPARATOR:
1380 {
1381 menuitem = gtk_separator_menu_item_new();
1382 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1383 break;
1384 }
1385 case GATE_UI_MENU_TYPE_TEXT:
1386 default:
1387 {
1388 menuitem = gtk_menu_item_new_with_label(entry->text);
1389
1390 if (entry->submenus != NULL)
1391 {
1392 GtkWidget* submenu = gtk_menu_new();
1393 attach_menu_list(form, submenu, id_counter, entry->submenus);
1394 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
1395 }
1396 else
1397 {
1398 g_object_set_data(G_OBJECT(menuitem), gate_ui_gtk_menu_attachment, (gpointer)(gate_uintptr_t)current_id);
1399 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(gate_ui_form_menu_activated), (void*)form);
1400 }
1401
1402 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1403 break;
1404 }
1405 }
1406 }
1407 }
1408
1409 gate_result_t gate_ui_form_set_menu(gate_ui_form_t* form, gate_ui_menulist_t const* menulist)
1410 {
1411 gate_result_t ret = GATE_RESULT_FAILED;
1412 GtkContainer* container = GATE_UI_GTK_GET_CTRL_CONTAINER(&form->ctrl);
1413 GtkWidget* menubar = (GtkWidget*)GATE_UI_GTK_GET_CTRL_PRIVATE_ARG(&form->ctrl);
1414 gate_uint16_t start_menu_id = 1;
1415
1416 if (menubar != NULL)
1417 {
1418 gtk_widget_destroy(menubar);
1419 GATE_UI_GTK_SET_CTRL_PRIVATE_ARG(&form->ctrl, NULL);
1420 }
1421 menubar = gtk_menu_bar_new();
1422 attach_menu_list(form, menubar, &start_menu_id, menulist);
1423 GATE_UI_GTK_SET_CTRL_PRIVATE_ARG(&form->ctrl, menubar);
1424
1425 gtk_layout_put(GTK_LAYOUT(container), menubar, 0, 0);
1426 /*gtk_widget_set_size_request(menubar, 640, 24);*/
1427 gtk_widget_realize(menubar);
1428 gtk_widget_set_redraw_on_allocate(menubar, TRUE);
1429 gtk_widget_show_all(menubar);
1430 gtk_widget_set_sensitive(menubar, TRUE);
1431
1432 form->menulist = menulist;
1433 ret = GATE_RESULT_OK;
1434 gate_ui_form_refresh(form);
1435 return ret;
1436 }
1437 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
1438 {
1439 gate_result_t ret = GATE_RESULT_OK;
1440 form->layout = layout;
1441 if (layout != NULL)
1442 {
1443 if (gate_ui_ctrl_is_created(&form->ctrl))
1444 {
1445 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(&form->ctrl);
1446 gate_uint32_t line_height = gate_ui_host_default_control_height(host, 1);
1447 gate_ui_position_t pose;
1448 pose.pos.x = 0;
1449 pose.pos.y = 0;
1450 gate_ui_ctrl_get_size(&form->ctrl, &pose.size);
1451 ret = gate_ui_layout_apply(layout, line_height, &pose);
1452 }
1453 }
1454 return ret;
1455 }
1456
1457 gate_result_t gate_ui_form_begin_dialog(gate_ui_form_t* form)
1458 {
1459 gate_result_t ret;
1460 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl);
1461 GtkWindow* owner = gtk_window_get_transient_for(GTK_WINDOW(widget));
1462 if (owner)
1463 {
1464 gtk_widget_set_sensitive(GTK_WIDGET(owner), FALSE);
1465 }
1466 ret = gate_ui_ctrl_set_visible(&form->ctrl, true);
1467 gate_ui_form_activate(form);
1468 return ret;
1469 }
1470 gate_result_t gate_ui_form_end_dialog(gate_ui_form_t* form)
1471 {
1472 gate_result_t ret;
1473 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&form->ctrl);
1474 GtkWindow* owner = gtk_window_get_transient_for(GTK_WINDOW(widget));
1475 ret = gate_ui_ctrl_set_visible(&form->ctrl, false);
1476 if (owner)
1477 {
1478 gtk_widget_set_sensitive(GTK_WIDGET(owner), TRUE);
1479 }
1480 return ret;
1481 }
1482
1483 gate_ui_form_t* gate_ui_form_get_top_level_form(gate_ui_ctrl_t* ctrl)
1484 {
1485 gate_ui_form_t* ret = NULL;
1486 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(ctrl);
1487 GtkWidget* top_level = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
1488 if (top_level)
1489 {
1490 if (GTK_IS_WINDOW(top_level))
1491 {
1492 gate_ui_ctrl_t* top_level_ctrl = gate_ui_gtk_ctrl_resolve(top_level);
1493 if (top_level_ctrl)
1494 {
1495 ret = (gate_ui_form_t*)top_level_ctrl;
1496 }
1497 }
1498 }
1499 return ret;
1500 }
1501
1502
1503 #endif /* GATE_UI_GTK */
1504
1505
1506
1507 #if defined(GATE_UI_MOTIF)
1508
1509 #include "gate/ui/gateui_motif.h"
1510 #include "gate/debugging.h"
1511 #include <Xm/Form.h>
1512 #include <Xm/MainW.h>
1513 #include <Xm/MenuShell.h>
1514 #include <Xm/RowColumn.h>
1515 #include <Xm/CascadeB.h>
1516 #include <Xm/SeparatoG.h>
1517 #include <Xm/PushBG.h>
1518 #include <Xm/Xm.h>
1519 #include <Xm/DialogS.h>
1520 #include <Xm/MwmUtil.h>
1521 #include <X11/Shell.h>
1522
1523 4 static gate_result_t form_apply_layout(gate_ui_form_t* ptr_form, gate_ui_position_t const* position)
1524 {
1525 4 gate_result_t ret = GATE_RESULT_FAILED;
1526
1527
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (gate_ui_ctrl_is_created(&ptr_form->ctrl))
1528 {
1529 4 gate_ui_host_t* ptr_host = GATE_UI_MOTIF_GET_CTRL_HOST(&ptr_form->ctrl);
1530 4 gate_uint32_t ctrl_height = gate_ui_host_default_control_height(ptr_host, 1);
1531
1532 4 Widget w_menubar = (Widget)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&ptr_form->ctrl);
1533
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (w_menubar)
1534 {
1535 gate_ui_position_t newpos;
1536 4 newpos.pos.x = position->pos.x;
1537 4 newpos.pos.y = position->pos.y;
1538 4 newpos.size.width = position->size.width;
1539 4 newpos.size.height = 32;
1540 4 gate_ui_motif_widget_set_position(w_menubar, &newpos.pos, &newpos.size);
1541
1542 4 newpos.pos.x = position->pos.x;
1543 4 newpos.pos.y = position->pos.y + 32;
1544 4 newpos.size.width = position->size.width;
1545 4 newpos.size.height = position->size.height - 32;
1546
1547 4 ret = gate_ui_layout_apply(ptr_form->layout, ctrl_height, &newpos);
1548 }
1549 else
1550 {
1551 ret = gate_ui_layout_apply(ptr_form->layout, ctrl_height, position);
1552 }
1553 }
1554 4 return ret;
1555 }
1556
1557
1558 3 static gate_result_t gate_ui_form_apply_layout(gate_ui_form_t* form)
1559 {
1560 3 gate_result_t ret = GATE_RESULT_OK;
1561
1562
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (!gate_ui_ctrl_is_created(&form->ctrl))
1563 {
1564 ret = GATE_RESULT_INVALIDSTATE;
1565 }
1566 else
1567 {
1568
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (form->layout != NULL)
1569 {
1570 gate_ui_position_t pose;
1571 3 pose.pos.x = 0;
1572 3 pose.pos.y = 0;
1573 3 gate_ui_ctrl_get_size(&form->ctrl, &pose.size);
1574 3 ret = form_apply_layout(form, &pose);
1575 }
1576 }
1577 3 return ret;
1578 }
1579
1580 1 static void form_container_resize_action(Widget w, XEvent* xevt, String* str, Cardinal* num_args)
1581 {
1582 1 gate_ui_form_t* ptr_form = NULL;
1583 gate_ui_position_t pos;
1584 1 XConfigureEvent* cevent = (XConfigureEvent*)xevt;
1585
1586 1 ptr_form = (gate_ui_form_t*)gate_ui_motif_widget_get_ctrl(w);
1587
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!ptr_form)
1588 {
1589 return;
1590 }
1591
1592 1 pos.pos.x = 0; // cevent->x;
1593 1 pos.pos.y = 0; // cevent->y;
1594 1 pos.size.width = cevent->width - 2;
1595 1 pos.size.height = cevent->height - 2;
1596
1597 1 form_apply_layout(ptr_form, &pos);
1598 }
1599
1600 3 static void destroy_menuitem_widgets(Widget menuhost)
1601 {
1602 3 WidgetList children = NULL;
1603 3 Cardinal num_children = 0;
1604
1605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_DEBUG_ASSERT(menuhost != NULL);
1606 3 XtVaGetValues(menuhost, XmNchildren, &children, XmNnumChildren, &num_children, NULL, NULL);
1607
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 while (num_children-- > 0)
1608 {
1609 5 Widget child_widget = children[num_children];
1610
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (child_widget)
1611 {
1612 5 Widget pulldown_menu = NULL;
1613 5 XtVaGetValues(child_widget, XmNsubMenuId, &pulldown_menu, NULL, NULL);
1614
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (pulldown_menu)
1615 {
1616 2 destroy_menuitem_widgets(pulldown_menu);
1617 2 XtDestroyWidget(pulldown_menu);
1618 }
1619 5 XtDestroyWidget(child_widget);
1620 }
1621 }
1622 3 }
1623
1624 1 static gate_result_t form_destroy(gate_ui_ctrl_t* ctrl)
1625 {
1626 Widget menubar_widget;
1627
1628
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(ctrl != NULL);
1629 1 menubar_widget = (Widget)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(ctrl);
1630
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (menubar_widget)
1631 {
1632 1 destroy_menuitem_widgets(menubar_widget);
1633 1 XtDestroyWidget(menubar_widget);
1634 1 GATE_UI_MOTIF_SET_CTRL_PRIVATE_ARG(ctrl, NULL);
1635 }
1636
1637 1 return gate_ui_motif_ctrl_destroy_default(ctrl);
1638 }
1639
1640 static gate_result_t form_get_text(gate_ui_ctrl_t* ctrl, gate_string_t* ptr_text)
1641 {
1642 Widget w;
1643
1644 if (!ctrl)
1645 {
1646 return GATE_RESULT_INVALIDSTATE;
1647 }
1648 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
1649 if (!w)
1650 {
1651 return GATE_RESULT_INVALIDSTATE;
1652 }
1653 if (ptr_text)
1654 {
1655 String ctxt = NULL;
1656 XtVaGetValues(w, XmNtitle, &ctxt, NULL, NULL);
1657 if (NULL == gate_string_create(ptr_text, ctxt, gate_str_length(ctxt)))
1658 {
1659 return GATE_RESULT_OUTOFMEMORY;
1660 }
1661 }
1662 return GATE_RESULT_OK;
1663 }
1664
1665 1 static gate_result_t form_set_text(gate_ui_ctrl_t* ctrl, gate_string_t const* text)
1666 {
1667 Widget w;
1668 1 gate_cstrbuffer8_t ctxt = GATE_INIT_EMPTY;
1669
1670
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!ctrl)
1671 {
1672 return GATE_RESULT_INVALIDSTATE;
1673 }
1674 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
1675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w)
1676 {
1677 return GATE_RESULT_INVALIDSTATE;
1678 }
1679
1680
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_cstrbuffer_create_string(&ctxt, text, false))
1681 {
1682 return GATE_RESULT_OUTOFMEMORY;
1683 }
1684
1685 1 XtVaSetValues(w, XmNtitle, gate_cstrbuffer_get(&ctxt), NULL, NULL);
1686
1687 1 gate_cstrbuffer_destroy(&ctxt);
1688 1 return GATE_RESULT_OK;
1689 }
1690
1691 static gate_result_t form_get_state(gate_ui_ctrl_t* ctrl, gate_int32_t* ptr_state)
1692 {
1693 return GATE_RESULT_NOTIMPLEMENTED;
1694 }
1695
1696 static gate_result_t form_set_state(gate_ui_ctrl_t* ctrl, gate_int32_t state)
1697 {
1698 return GATE_RESULT_NOTIMPLEMENTED;
1699 }
1700
1701 1 static gate_result_t form_refresh(gate_ui_ctrl_t* ctrl)
1702 {
1703 1 gate_ui_form_t* form = (gate_ui_form_t*)ctrl;
1704 1 gate_result_t ret = gate_ui_motif_ctrl_refresh(ctrl);
1705 1 gate_ui_form_apply_layout(form);
1706 1 return ret;
1707 }
1708
1709
1710 static gate_ui_motif_dispatcher_t form_dispatcher =
1711 {
1712 &form_destroy,
1713 &form_get_text,
1714 &form_set_text,
1715 &form_get_state,
1716 &form_set_state,
1717 &form_refresh
1718 };
1719
1720
1721 static gate_ui_position_t const form_default_pos = { { 0, 0 }, { 640, 480 } };
1722
1723 1 gate_result_t gate_ui_form_create(gate_ui_form_t* form, gate_ui_host_t* host, gate_ui_position_t const* position,
1724 gate_string_t const* title, gate_uint32_t flags, gate_ui_form_t* owner, void* userparam)
1725 {
1726 gate_result_t ret;
1727 do
1728 {
1729 1 Widget w = NULL;
1730 1 Widget c = NULL;
1731 1 XtAppContext appctx = NULL;
1732 XtActionsRec actions[1];
1733 1 WidgetClass widget_cls = applicationShellWidgetClass;
1734 Arg args[20];
1735 1 unsigned argc = 0;
1736
1737
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!position)
1738 {
1739 1 position = &form_default_pos;
1740 }
1741
1742
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))
1743 {
1744 Widget w_owner = GATE_UI_MOTIF_GET_CTRL_WIDGET(&owner->ctrl);
1745 if (w_owner)
1746 {
1747 XtSetArg(args[argc], XmNtransientFor, w_owner); ++argc;
1748 }
1749 }
1750
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_RESIZABLE))
1751 {
1752 1 XtSetArg(args[argc], XtNallowShellResize, True); ++argc;
1753 1 XtSetArg(args[argc], XmNallowResize, True); ++argc;
1754 1 XtSetArg(args[argc], XmNnoResize, False); ++argc;
1755 1 XtSetArg(args[argc], XmNmwmFunctions, (MWM_FUNC_ALL | MWM_FUNC_MAXIMIZE)); ++argc;
1756 1 XtSetArg(args[argc], XmNmwmDecorations, (MWM_DECOR_ALL | MWM_DECOR_MAXIMIZE)); ++argc;
1757 }
1758
1759 1 ret = gate_ui_motif_ctrl_create(&form->ctrl, widget_cls,
1760 userparam, host, NULL, position, &flags, true, NULL, args, argc);
1761
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1762
1763 1 GATE_UI_MOTIF_SET_CTRL_DISP(&form->ctrl, &form_dispatcher);
1764
1765 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1766
1767 1 appctx = (XtAppContext)GATE_UI_MOTIF_GET_HOST_APPHANDLE(host);
1768 1 actions[0].string = "resize";
1769 1 actions[0].proc = &form_container_resize_action;
1770 1 XtAppAddActions(appctx, actions, 1);
1771
1772 1 c = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&form->ctrl);
1773
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (c)
1774 {
1775 1 XtOverrideTranslations(c, XtParseTranslationTable("<Configure>: resize()"));
1776 }
1777
1778 1 form_set_text(&form->ctrl, title);
1779 } while (0);
1780
1781 1 return ret;
1782 }
1783
1784 gate_result_t gate_ui_form_perform_action(gate_ui_form_t* form, gate_enumint_t action)
1785 {
1786 return GATE_RESULT_NOTSUPPORTED;
1787 }
1788
1789 gate_result_t gate_ui_form_set_mode(gate_ui_form_t* form, gate_uint32_t mode)
1790 {
1791 gate_result_t ret = GATE_RESULT_OK;
1792 /* TODO */
1793 return ret;
1794 }
1795 gate_result_t gate_ui_form_activate(gate_ui_form_t* form)
1796 {
1797 gate_result_t ret = GATE_RESULT_OK;
1798 /* TODO */
1799 return ret;
1800 }
1801
1802 static void on_submenu_widget_click(Widget widget, XtPointer client_data, XtPointer call_data)
1803 {
1804 gate_ui_form_t* ptr_form = (gate_ui_form_t*)client_data;
1805
1806 if (ptr_form)
1807 {
1808 void* entry_id = NULL;
1809 gate_uint32_t menu_entry_id = 0;
1810 gate_ui_menu_entry_t const* ptr_selected_entry = NULL;
1811
1812 XtVaGetValues(widget, XmNuserData, &entry_id, NULL, NULL);
1813 menu_entry_id = (gate_uint32_t)(gate_uintptr_t)entry_id;
1814 ptr_selected_entry = gate_ui_menulist_resolve(ptr_form->menulist, menu_entry_id);
1815 if (ptr_selected_entry)
1816 {
1817 ptr_form->on_menu(&ptr_form->ctrl, ptr_selected_entry);
1818 }
1819 }
1820 }
1821
1822
1823 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)
1824 {
1825 gate_size_t ndx;
1826
1827
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (ndx = 0; ndx != submenu->count; ++ndx)
1828 {
1829 4 gate_ui_menu_entry_t const* entry = &submenu->entries[ndx];
1830
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (entry->entry_type == GATE_UI_MENU_TYPE_SEPARATOR)
1831 {
1832 /* TODO */
1833 }
1834
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 else if (entry->entry_type == GATE_UI_MENU_TYPE_TEXT)
1835 {
1836 3 XmString label = gate_ui_motif_create_chr_string(entry->text);
1837 3 Widget w_menuentry = XtVaCreateManagedWidget(
1838 NULL, xmPushButtonGadgetClass, pulldown_menu,
1839 XmNlabelString, label,
1840 3 XmNuserData, (void*)(gate_uintptr_t)entry->id,
1841 NULL, NULL);
1842 3 XmStringFree(label);
1843 3 XtAddCallback(w_menuentry, XmNactivateCallback, &on_submenu_widget_click, ptr_form);
1844 }
1845 }
1846 2 return GATE_RESULT_OK;
1847 }
1848
1849 2 static void create_pulldown_menu_name(char* buffer, gate_size_t bufferlen)
1850 {
1851 static gate_atomic_int_t idgenerator = 0;
1852 gate_strbuilder_t builder;
1853 2 gate_strbuilder_create_static(&builder, buffer, bufferlen, 0);
1854 2 gate_strbuilder_append_cstr(&builder, "gate_form_pulldownmenu_");
1855 2 gate_strbuilder_append_int32(&builder, gate_atomic_int_inc(&idgenerator));
1856 2 }
1857
1858 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)
1859 {
1860 gate_size_t ndx;
1861
1862
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (ndx = 0; ndx != menulist->count; ++ndx)
1863 {
1864 Widget pulldown_menu;
1865 XmString label;
1866 gate_ui_menu_entry_t const* entry;
1867 char pulldown_menu_name[256];
1868 2 Cardinal args_count = 0;
1869 Arg args[12];
1870
1871 2 create_pulldown_menu_name(pulldown_menu_name, sizeof(pulldown_menu_name));
1872 2 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
1873 2 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1874 2 pulldown_menu = XmCreatePulldownMenu(menubar_widget, pulldown_menu_name, args, args_count);
1875
1876 2 entry = &menulist->entries[ndx];
1877 2 label = gate_ui_motif_create_chr_string(entry->text);
1878 2 XtVaCreateManagedWidget(NULL, xmCascadeButtonWidgetClass, menubar_widget,
1879 XmNlabelString, label,
1880 XmNsubMenuId, pulldown_menu,
1881 XmNuserData, form,
1882 XmNshadowThickness, 1,
1883 XmNhighlightThickness, 1,
1884 NULL, NULL);
1885 2 XmStringFree(label);
1886
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)
1887 {
1888 2 gate_ui_form_create_submenu_widgets(form, pulldown_menu, entry->submenus);
1889 }
1890 }
1891 1 return GATE_RESULT_OK;
1892 }
1893
1894 1 gate_result_t gate_ui_form_set_menu(gate_ui_form_t* form, gate_ui_menulist_t const* menulist)
1895 {
1896 1 gate_result_t ret = GATE_RESULT_FAILED;
1897
1898 do
1899 {
1900 1 Widget w_form = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&form->ctrl);
1901 1 Widget w_menubar = (Widget)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&form->ctrl);
1902
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!w_menubar)
1903 {
1904 Arg args[8];
1905 1 Cardinal args_count = 0;
1906 1 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
1907 1 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1908 1 w_menubar = XmCreateSimpleMenuBar(w_form, "MenuBar", args, args_count);
1909
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w_menubar)
1910 {
1911 ret = GATE_RESULT_OUTOFMEMORY;
1912 break;
1913 }
1914 1 GATE_UI_MOTIF_SET_CTRL_PRIVATE_ARG(&form->ctrl, (void*)w_menubar);
1915 1 XtManageChild(w_menubar);
1916 }
1917 else
1918 {
1919 destroy_menuitem_widgets(w_menubar);
1920 }
1921
1922 1 ret = gate_ui_form_create_menu_widgets(form, w_menubar, menulist);
1923
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1924
1925 1 form->menulist = menulist;
1926 1 ret = GATE_RESULT_OK;
1927 } while (0);
1928
1929 1 return ret;
1930 }
1931
1932 1 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
1933 {
1934 1 form->layout = layout;
1935 1 return gate_ui_form_apply_layout(form);
1936 }
1937 1 gate_result_t gate_ui_form_refresh(gate_ui_form_t* form)
1938 {
1939 1 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!w)
1941 {
1942 return GATE_RESULT_INVALIDSTATE;
1943 }
1944 1 XtRealizeWidget(w);
1945 1 gate_ui_form_apply_layout(form);
1946 1 return GATE_RESULT_OK;
1947 }
1948 gate_result_t gate_ui_form_begin_dialog(gate_ui_form_t* form)
1949 {
1950 gate_result_t ret = GATE_RESULT_FAILED;
1951
1952 GATE_DEBUG_ASSERT(form != NULL);
1953 do
1954 {
1955 Widget w_owner = NULL;
1956 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1957 if (NULL == w)
1958 {
1959 ret = GATE_RESULT_INVALIDSTATE;
1960 break;
1961 }
1962
1963 XtPopup(w, XtGrabNone);
1964
1965 if (w_owner)
1966 {
1967 /* TODO */
1968 }
1969
1970 ret = GATE_RESULT_OK;
1971 } while (0);
1972 return ret;
1973 }
1974 gate_result_t gate_ui_form_end_dialog(gate_ui_form_t* form)
1975 {
1976 gate_result_t ret = GATE_RESULT_FAILED;
1977
1978 GATE_DEBUG_ASSERT(form != NULL);
1979 do
1980 {
1981 gate_ui_host_t* host = GATE_UI_MOTIF_GET_CTRL_HOST(&form->ctrl);
1982 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&form->ctrl);
1983 Widget w_owner = NULL;
1984 if (NULL == w)
1985 {
1986 ret = GATE_RESULT_INVALIDSTATE;
1987 break;
1988 }
1989
1990 XtPopdown(w);
1991
1992 gate_ui_motif_host_dispatch_pending_events(host, false);
1993
1994 if (w_owner)
1995 {
1996 /* TODO */
1997 }
1998 ret = GATE_RESULT_OK;
1999 } while (0);
2000
2001 return ret;
2002 }
2003
2004 gate_ui_form_t* gate_ui_form_get_top_level_form(gate_ui_ctrl_t* ctrl)
2005 {
2006 gate_ui_ctrl_t* last_known_parent = ctrl;
2007 while (ctrl != NULL)
2008 {
2009 last_known_parent = ctrl;
2010 ctrl = gate_ui_ctrl_get_parent(ctrl);
2011 }
2012 return (gate_ui_form_t*)last_known_parent;
2013 }
2014
2015 #endif /* GATE_UI_MOTIF */
2016
2017
2018 #if defined(GATE_UI_WASMHTML)
2019
2020 #include "gate/ui/gateui_wasmhtml.h"
2021
2022 static const gate_string_t html_class_div = GATE_STRING_INIT_STATIC("div");
2023
2024 gate_result_t gate_ui_form_create(gate_ui_form_t* form, gate_ui_host_t* host, gate_ui_position_t const* position,
2025 gate_string_t const* title, gate_uint32_t flags, gate_ui_form_t* owner, void* userparam)
2026 {
2027 gate_uint32_t html_id = 0;
2028
2029 gate_ui_wasm_new_ctrl_id(host, &html_id);
2030 return gate_ui_wasm_ctrl_create(host, html_id, 0, &html_class_div, userparam, &form->ctrl);
2031 }
2032
2033 gate_result_t gate_ui_form_perform_action(gate_ui_form_t* form, gate_enumint_t action)
2034 {
2035 return GATE_RESULT_NOTSUPPORTED;
2036 }
2037
2038 gate_result_t gate_ui_form_set_layout(gate_ui_form_t* form, gate_ui_layout_t const* layout)
2039 {
2040 return GATE_RESULT_NOTIMPLEMENTED;
2041 }
2042
2043
2044 #endif /* GATE_UI_WASMHTML */
2045