GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/checkboxes.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 36 40 90.0%
Functions: 5 5 100.0%
Branches: 5 10 50.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/checkboxes.h"
30 #include "gate/results.h"
31
32 #if defined(GATE_UI_WINAPI)
33
34 #include "gate/ui/gateui_winapi.h"
35 #include "gate/platforms.h"
36
37 static gate_bool_t gate_ui_checkbox_events(void* hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult)
38 {
39 if ((ctrl != NULL) && (hwnd))
40 {
41 HWND hwndCtrl = GATE_UI_WINAPI_GET_HWND(ctrl);
42 if (hwndCtrl)
43 {
44 switch (msg)
45 {
46 case WM_COMMAND:
47 {
48 if (hwndCtrl == (HWND)lParam)
49 {
50 gate_ui_checkbox_t* checkbox = (gate_ui_checkbox_t*)ctrl;
51 switch (HIWORD(wParam))
52 {
53 case BN_CLICKED:
54 {
55 if (checkbox->on_click != NULL)
56 {
57 checkbox->on_click(ctrl);
58 }
59 *lresult = 0;
60 return true;
61 }
62 default:
63 {
64 break;
65 }
66 }
67 }
68 break;
69 }
70 default:
71 {
72 break;
73 }
74 }
75 }
76 }
77 return false;
78 }
79
80 #ifndef BST_CHECKED
81 #define BST_CHECKED 1
82 #endif
83
84 #ifndef BST_INDETERMINATE
85 #define BST_INDETERMINATE 2
86 #endif
87 #ifndef BST_UNCHECKED
88 #define BST_UNCHECKED 0
89 #endif
90
91 static gate_result_t gate_ui_checkbox_get_state(gate_ui_ctrl_t* ctrl, gate_int32_t* state)
92 {
93 gate_result_t ret = GATE_RESULT_OK;
94 HWND hwnd = GATE_UI_WINAPI_GET_HWND(ctrl);
95 LRESULT btn_state = SendMessage(hwnd, BM_GETCHECK, 0, 0);
96 switch (btn_state)
97 {
98 case BST_CHECKED:
99 {
100 *state = 1;
101 break;
102 }
103 case BST_INDETERMINATE:
104 {
105 *state = -1;
106 break;
107 }
108 case BST_UNCHECKED:
109 {
110 *state = 0;
111 break;
112 }
113 default:
114 {
115 ret = GATE_RESULT_FAILED;
116 break;
117 }
118 }
119 return ret;
120 }
121
122 static gate_result_t gate_ui_checkbox_set_state(gate_ui_ctrl_t* ctrl, gate_int32_t state)
123 {
124 gate_result_t ret = GATE_RESULT_OK;
125 HWND hwnd = GATE_UI_WINAPI_GET_HWND(ctrl);
126 WPARAM newstate = 0;
127
128 if (state == 0)
129 {
130 newstate = BST_UNCHECKED;
131 }
132 else if (state > 0)
133 {
134 newstate = BST_CHECKED;
135 }
136 else
137 {
138 newstate = BST_INDETERMINATE;
139 }
140 if (0 != SendMessage(hwnd, BM_SETCHECK, newstate, 0))
141 {
142 ret = GATE_RESULT_FAILED;
143 }
144 return ret;
145 }
146
147 static gate_result_t gate_ui_checkbox_refresh(gate_ui_ctrl_t* ctrl)
148 {
149 HWND hwnd_ctrl = GATE_UI_WINAPI_GET_HWND(ctrl);
150 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
151 gate_ui_winapi_set_window_theme((void*)hwnd_ctrl, L"", L"");
152 #endif /* GATE_UI_WINAPI_DARKMODE_SUPPORT */
153 return gate_ui_winapi_refresh(ctrl);
154 }
155
156 static gate_ui_winapi_dispatchers_t global_win32_checkbox_dispatchers =
157 {
158 &gate_ui_winapi_destroy_with_font,
159 &gate_ui_winapi_is_enabled,
160 &gate_ui_winapi_is_visible,
161 &gate_ui_winapi_is_focused,
162 &gate_ui_winapi_get_position,
163 &gate_ui_winapi_get_size,
164 &gate_ui_winapi_get_children,
165 &gate_ui_winapi_get_text_length,
166 &gate_ui_winapi_get_text,
167 &gate_ui_checkbox_get_state,
168 &gate_ui_winapi_set_enabled,
169 &gate_ui_winapi_set_visible,
170 &gate_ui_winapi_set_focus,
171 &gate_ui_winapi_set_position,
172 &gate_ui_winapi_set_text,
173 &gate_ui_checkbox_set_state,
174 &gate_ui_checkbox_refresh
175 };
176
177 gate_result_t gate_ui_checkbox_perform_action(gate_ui_checkbox_t* checkbox, gate_enumint_t action)
178 {
179 gate_ui_ctrl_t* const ctrl = &checkbox->ctrl;
180 HWND const hwnd = GATE_UI_WINAPI_GET_HWND(ctrl);
181 gate_intptr_t lresult = 0;
182 gate_int32_t state = 0;
183 gate_result_t result;
184 switch (action)
185 {
186 case GATE_UI_ACTION_ACTIVATE:
187 result = gate_ui_checkbox_get_state(ctrl, &state);
188 if (GATE_SUCCEEDED(result))
189 {
190 gate_ui_checkbox_set_state(ctrl, (state == 0) ? 1 : 0);
191 }
192 gate_ui_checkbox_events(hwnd, ctrl, WM_COMMAND, (gate_uintptr_t)MAKELONG(0, BN_CLICKED), (gate_uintptr_t)hwnd, &lresult);
193 return GATE_RESULT_OK;
194 default:
195 break;
196 }
197 return GATE_RESULT_NOTSUPPORTED;
198 }
199
200
201 gate_result_t gate_ui_checkbox_create(
202 gate_ui_checkbox_t* checkbox, gate_ui_ctrl_t* parent,
203 gate_ui_position_t const* position,
204 gate_string_t const* caption,
205 gate_uint32_t flags,
206 void* userparam
207 )
208 {
209 gate_result_t ret;
210
211 do
212 {
213 gate_uint32_t styles, exstyles;
214 HWND hwndParent;
215 HWND hwndCtrl;
216 gate_ui_host_t* host = gate_ui_ctrl_get_host(parent);
217 if (!host)
218 {
219 ret = GATE_RESULT_INVALIDSTATE;
220 break;
221 }
222 hwndParent = GATE_UI_WINAPI_GET_HWND(parent);
223 if (!hwndParent)
224 {
225 ret = GATE_RESULT_INVALIDSTATE;
226 break;
227 }
228
229 gate_mem_clear(checkbox, sizeof(gate_ui_checkbox_t));
230
231 exstyles = 0;
232 styles = WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | BS_AUTOCHECKBOX | BS_CHECKBOX;
233 #if !defined(GATE_SYS_WIN16)
234 styles |= (BS_MULTILINE | BS_TEXT | BS_VCENTER | BS_NOTIFY);
235 #endif
236
237 #if !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WIN16)
238 styles |= BS_FLAT;
239 #endif
240 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
241 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
242
243 ret = gate_ui_winapi_create(&checkbox->ctrl, host, (void*)hwndParent,
244 _T("BUTTON"), position, styles, exstyles, caption, userparam, true);
245 if (GATE_SUCCEEDED(ret))
246 {
247 GATE_UI_WINAPI_SET_DISPATCHER(&checkbox->ctrl, &global_win32_checkbox_dispatchers);
248 gate_ui_winapi_register_event(host, (void*)hwndParent, WM_COMMAND, &gate_ui_checkbox_events, &checkbox->ctrl);
249
250 hwndCtrl = GATE_UI_WINAPI_GET_HWND(&checkbox->ctrl);
251 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
252 gate_ui_winapi_set_window_theme((void*)hwndCtrl, L"", L"");
253 #endif /* GATE_UI_WINAPI_DARKMODE_SUPPORT */
254 }
255 } while (0);
256
257 return ret;
258 }
259
260 #endif /*GATE_UI_WINAPI*/
261
262
263 #if defined(GATE_UI_GTK)
264
265 #include "gate/ui/gateui_gtk.h"
266
267 static void gate_ui_gtk_checkbox_clicked(GtkWidget* checkbox, gpointer user_data)
268 {
269 gate_ui_checkbox_t* checkbox_ctrl = (gate_ui_checkbox_t*)user_data;
270 if (checkbox_ctrl)
271 {
272 if (checkbox_ctrl->on_click != NULL)
273 {
274 checkbox_ctrl->on_click(&checkbox_ctrl->ctrl);
275 }
276 }
277 }
278
279
280 static gate_uint32_t gate_ui_gtk_checkbox_get_text_length(gate_ui_ctrl_t* ctrl)
281 {
282 gint char_count = 0;
283 gchar const* ptr_text = NULL;
284 GtkButton* checkbox = GTK_BUTTON(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
285 if (checkbox)
286 {
287 ptr_text = gtk_button_get_label(checkbox);
288 if (ptr_text)
289 {
290 char_count = gate_str_length(ptr_text);
291 }
292 }
293 return (gate_uint32_t)char_count;
294 }
295 static gate_result_t gate_ui_gtk_checkbox_get_text(gate_ui_ctrl_t* ctrl, gate_string_t* text)
296 {
297 gate_result_t ret = GATE_RESULT_FAILED;
298 gchar const* ptr_text = NULL;
299 GtkButton* checkbox = GTK_BUTTON(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
300 if (checkbox)
301 {
302 ptr_text = gtk_button_get_label(checkbox);
303 if (ptr_text)
304 {
305 if (NULL == gate_string_create(text, ptr_text, gate_str_length(ptr_text)))
306 {
307 ret = GATE_RESULT_OUTOFMEMORY;
308 }
309 else
310 {
311 ret = GATE_RESULT_OK;
312 }
313 }
314 else
315 {
316 gate_string_create_empty(text);
317 ret = GATE_RESULT_OK;
318 }
319 }
320 return ret;
321
322 }
323 static gate_result_t gate_ui_gtk_checkbox_set_text(gate_ui_ctrl_t* ctrl, gate_string_t const* text)
324 {
325 gate_result_t ret = GATE_RESULT_FAILED;
326 gchar label[4096];
327 GtkButton* checkbox = GTK_BUTTON(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
328 if (checkbox)
329 {
330 gate_str_print_text(label, sizeof(label), text->str, text->length);
331 gtk_button_set_label(checkbox, label);
332 ret = GATE_RESULT_OK;
333 }
334 return ret;
335 }
336 static gate_result_t gate_ui_gtk_checkbox_get_state(gate_ui_ctrl_t* ctrl, gate_int32_t* value)
337 {
338 gate_result_t ret = GATE_RESULT_FAILED;
339 gchar const* ptr_text = NULL;
340 GtkToggleButton* checkbox = GTK_TOGGLE_BUTTON(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
341 if (checkbox)
342 {
343 if (gtk_toggle_button_get_active(checkbox))
344 {
345 *value = 1;
346 }
347 else
348 {
349 *value = 0;
350 }
351 ret = GATE_RESULT_OK;
352 }
353 return ret;
354 }
355 static gate_result_t gate_ui_gtk_checkbox_set_state(gate_ui_ctrl_t* ctrl, gate_int32_t value)
356 {
357 gate_result_t ret = GATE_RESULT_FAILED;
358 GtkToggleButton* checkbox = GTK_TOGGLE_BUTTON(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
359 if (checkbox)
360 {
361 gtk_toggle_button_set_active(checkbox, (value == 0) ? FALSE : TRUE);
362 ret = GATE_RESULT_OK;
363 }
364 return ret;
365 }
366
367 static gate_ui_gtk_dispatcher_t gate_ui_gtk_checkbox_dispatcher =
368 {
369 gate_ui_gtk_checkbox_get_text_length,
370 gate_ui_gtk_checkbox_get_text,
371 gate_ui_gtk_checkbox_set_text,
372 gate_ui_gtk_checkbox_get_state,
373 gate_ui_gtk_checkbox_set_state,
374 NULL
375 };
376
377
378 gate_result_t gate_ui_checkbox_perform_action(gate_ui_checkbox_t* checkbox, gate_enumint_t action)
379 {
380 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&checkbox->ctrl);
381 switch(action)
382 {
383 case GATE_UI_ACTION_ACTIVATE:
384 gate_ui_gtk_checkbox_clicked(widget, checkbox);
385 return GATE_RESULT_OK;
386 }
387 return GATE_RESULT_NOTSUPPORTED;
388 }
389
390 gate_result_t gate_ui_checkbox_create(gate_ui_checkbox_t* checkbox, gate_ui_ctrl_t* parent,
391 gate_ui_position_t const* position, gate_string_t const* caption,
392 gate_uint32_t flags, void* userparam)
393 {
394 gate_result_t ret = GATE_RESULT_OK;
395 GtkWidget* widget;
396 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
397
398 gate_mem_clear(&checkbox->ctrl, sizeof(gate_ui_ctrl_t));
399 widget = gtk_check_button_new();
400 if (widget == NULL)
401 {
402 return GATE_RESULT_FAILED;
403 }
404
405 ret = gate_ui_gtk_ctrl_init(&checkbox->ctrl, widget, host, userparam, parent,
406 &gate_ui_gtk_checkbox_dispatcher, false, false, position, &flags);
407
408 if (GATE_SUCCEEDED(ret))
409 {
410 if (gate_string_length(caption) > 0)
411 {
412 gate_ui_ctrl_set_text(&checkbox->ctrl, caption);
413 }
414 g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(gate_ui_gtk_checkbox_clicked), (gpointer)checkbox);
415 }
416
417 return ret;
418 }
419
420
421 #endif /* GATE_UI_GTK */
422
423
424
425 #if defined(GATE_UI_MOTIF)
426
427 #include "gate/ui/gateui_motif.h"
428 #include <Xm/ToggleB.h>
429
430 2 static gate_result_t checkbox_get_state(gate_ui_ctrl_t* ctrl, gate_int32_t* ptr_state)
431 {
432 2 Widget w = NULL;
433 2 int state = 0;
434 2 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
435 2 XtVaGetValues(w, XmNset, &state, NULL);
436
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (ptr_state)
437 {
438 2 *ptr_state = (state == XmSET) ? 1 : 0;
439 }
440 2 return GATE_RESULT_OK;
441 }
442
443 2 static gate_result_t checkbox_set_state(gate_ui_ctrl_t* ctrl, gate_int32_t state)
444 {
445 2 Widget w = NULL;
446 2 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
447 2 XtVaSetValues(w, XmNset, (state ? XmSET : XmUNSET), NULL);
448 2 return GATE_RESULT_OK;
449 }
450
451 static gate_ui_motif_dispatcher_t checkbox_disp =
452 {
453 NULL,
454 NULL,
455 NULL,
456 &checkbox_get_state,
457 &checkbox_set_state
458 };
459
460 1 static void checkbox_pushed(Widget widget, XtPointer client_data, XtPointer call_data)
461 {
462 1 gate_ui_checkbox_t* const ptr_checkbox = (gate_ui_checkbox_t*)client_data;
463
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!ptr_checkbox || !ptr_checkbox->on_click)
464 {
465 return;
466 }
467 1 ptr_checkbox->on_click(&ptr_checkbox->ctrl);
468 }
469
470 1 gate_result_t gate_ui_checkbox_perform_action(gate_ui_checkbox_t* checkbox, gate_enumint_t action)
471 {
472 1 Widget const w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&checkbox->ctrl);
473
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 switch(action)
474 {
475 1 case GATE_UI_ACTION_ACTIVATE:
476 1 checkbox_pushed(w, (XtPointer)checkbox, NULL);
477 1 return GATE_RESULT_OK;
478 default:
479 break;
480 }
481 return GATE_RESULT_NOTSUPPORTED;
482
483 }
484
485 1 gate_result_t gate_ui_checkbox_create(gate_ui_checkbox_t* checkbox, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
486 gate_string_t const* caption, gate_uint32_t flags, void* userparam)
487 {
488 1 gate_result_t ret = GATE_RESULT_FAILED;
489 1 Widget w = NULL;
490 Arg args[8];
491 1 unsigned args_count = 0;
492
493 do
494 {
495 1 XtSetArg(args[args_count], XmNtoggleMode, XmTOGGLE_BOOLEAN); ++args_count;
496 1 XtSetArg(args[args_count], XmNset, XmUNSET); ++args_count;
497 1 XtSetArg(args[args_count], XmNalignment, XmALIGNMENT_BEGINNING); ++args_count;
498
499 1 ret = gate_ui_motif_ctrl_create(&checkbox->ctrl, xmToggleButtonWidgetClass, userparam, NULL, parent,
500 position, &flags, false, &checkbox_disp, args, args_count);
501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
502
503 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&checkbox->ctrl);
504 1 XtAddCallback(w, XmNvalueChangedCallback, &checkbox_pushed, checkbox);
505
506 1 gate_ui_motif_widget_set_label(w, caption);
507
508 } while (0);
509 1 return ret;
510 }
511
512 #endif /* GATE_UI_MOTIF */
513
514