GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/forms.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 234 0.0%
Functions: 0 23 0.0%
Branches: 0 74 0.0%

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