GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/buttons.c
Date: 2026-09-21 06:26:40
Exec Total Coverage
Lines: 24 30 80.0%
Functions: 3 3 100.0%
Branches: 6 12 50.0%

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/buttons.h"
30 #include "gate/results.h"
31
32 #if defined(GATE_UI_WINAPI)
33
34
35 #include "gate/ui/gateui_winapi.h"
36 #include "gate/platforms.h"
37
38 static gate_bool_t WINAPI gate_ui_button_events(ui_hwnd_t hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult)
39 {
40 if ((ctrl != NULL) && (hwnd != (ui_hwnd_t)NULL))
41 {
42 const HWND hwndCtrl = (HWND)GATE_UI_WINAPI_GET_HWND(ctrl);
43 if (hwndCtrl)
44 {
45 switch (msg)
46 {
47 case WM_COMMAND:
48 {
49 if (hwndCtrl == (HWND)lParam)
50 {
51 gate_ui_button_t* button = (gate_ui_button_t*)ctrl;
52 switch (HIWORD(wParam))
53 {
54 case BN_CLICKED:
55 {
56 if (button->on_click != NULL)
57 {
58 button->on_click(ctrl);
59 }
60 *lresult = 0;
61 return true;
62 }
63 default:
64 {
65 break;
66 }
67 }
68 }
69 break;
70 }
71 default:
72 {
73 break;
74 }
75 }
76 }
77 }
78 return false;
79 }
80
81 gate_result_t gate_ui_button_perform_action(gate_ui_button_t* button, gate_enumint_t action)
82 {
83 gate_ui_ctrl_t* const ctrl = &button->ctrl;
84 ui_hwnd_t const hwnd = GATE_UI_WINAPI_GET_HWND(ctrl);
85 gate_intptr_t lresult = 0;
86 switch (action)
87 {
88 case GATE_UI_ACTION_ACTIVATE:
89 gate_ui_button_events(hwnd, ctrl, WM_COMMAND, (gate_uintptr_t)MAKELONG(0, BN_CLICKED), (gate_uintptr_t)hwnd, &lresult);
90 return GATE_RESULT_OK;
91 default:
92 break;
93 }
94 return GATE_RESULT_NOTSUPPORTED;
95 }
96
97 gate_result_t gate_ui_button_create(
98 gate_ui_button_t* button, gate_ui_ctrl_t* parent,
99 gate_ui_position_t const* position,
100 gate_string_t const* caption,
101 gate_uint32_t flags,
102 void* userparam
103 )
104 {
105 gate_result_t ret;
106 do
107 {
108 gate_uint32_t styles, exstyles;
109 ui_hwnd_t hwndParent;
110 gate_ui_host_t* host = gate_ui_ctrl_get_host(parent);
111 if (!host)
112 {
113 ret = GATE_RESULT_INVALIDSTATE;
114 break;
115 }
116 hwndParent = GATE_UI_WINAPI_GET_HWND(parent);
117 if (hwndParent == UI_HWND_NULL)
118 {
119 ret = GATE_RESULT_INVALIDSTATE;
120 break;
121 }
122
123 gate_mem_clear(button, sizeof(gate_ui_button_t));
124
125 exstyles = 0;
126 styles = WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | BS_PUSHBUTTON;
127 #if !defined(GATE_SYS_WIN16)
128 styles |= (BS_MULTILINE | BS_VCENTER);
129 #endif
130 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
131 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
132
133 ret = gate_ui_winapi_create(&button->ctrl, host, hwndParent,
134 _T("BUTTON"), position, styles, exstyles, caption, userparam, true);
135 if (GATE_SUCCEEDED(ret))
136 {
137 gate_ui_winapi_register_event(host, hwndParent, WM_COMMAND, &gate_ui_button_events, &button->ctrl);
138 }
139 } while (0);
140
141 return ret;
142 }
143
144 #endif /*GATE_UI_WINAPI*/
145
146
147 #if defined(GATE_UI_GTK)
148
149 #include "gate/ui/gateui_gtk.h"
150
151 static gate_uint32_t gate_ui_gtk_button_get_text_length(gate_ui_ctrl_t* ctrl)
152 {
153 gint char_count = 0;
154 gchar const* ptr_text = NULL;
155 GtkButton* button = GTK_BUTTON(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
156 if (button)
157 {
158 ptr_text = gtk_button_get_label(button);
159 if (ptr_text)
160 {
161 char_count = gate_str_length(ptr_text);
162 }
163 }
164 return (gate_uint32_t)char_count;
165 }
166 static gate_result_t gate_ui_gtk_button_get_text(gate_ui_ctrl_t* ctrl, gate_string_t* text)
167 {
168 gate_result_t ret = GATE_RESULT_FAILED;
169 gchar const* ptr_text = NULL;
170 GtkButton* button = GTK_BUTTON(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
171 if (button)
172 {
173 ptr_text = gtk_button_get_label(button);
174 if (ptr_text)
175 {
176 if (NULL == gate_string_create(text, ptr_text, gate_str_length(ptr_text)))
177 {
178 ret = GATE_RESULT_OUTOFMEMORY;
179 }
180 else
181 {
182 ret = GATE_RESULT_OK;
183 }
184 }
185 else
186 {
187 gate_string_create_empty(text);
188 ret = GATE_RESULT_OK;
189 }
190 }
191 return ret;
192
193 }
194 static gate_result_t gate_ui_gtk_button_set_text(gate_ui_ctrl_t* ctrl, gate_string_t const* text)
195 {
196 gate_result_t ret = GATE_RESULT_FAILED;
197 gchar label[4096];
198 GtkButton* button = GTK_BUTTON(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
199 if (button)
200 {
201 gate_str_print_text(label, sizeof(label), text->str, text->length);
202 gtk_button_set_label(button, label);
203 ret = GATE_RESULT_OK;
204 }
205 return ret;
206 }
207 static gate_result_t gate_ui_gtk_button_get_state(gate_ui_ctrl_t* ctrl, gate_int32_t* value)
208 {
209 return GATE_RESULT_NOTIMPLEMENTED;
210 }
211 static gate_result_t gate_ui_gtk_button_set_state(gate_ui_ctrl_t* ctrl, gate_int32_t value)
212 {
213 return GATE_RESULT_NOTIMPLEMENTED;
214 }
215
216 static gate_ui_gtk_dispatcher_t gate_ui_gtk_button_dispatcher =
217 {
218 gate_ui_gtk_button_get_text_length,
219 gate_ui_gtk_button_get_text,
220 gate_ui_gtk_button_set_text,
221 NULL,
222 NULL,
223 NULL
224 };
225
226
227 static void gate_ui_button_clicked(GtkButton* button, gpointer user_data)
228 {
229 gate_ui_button_t* button_ctrl = (gate_ui_button_t*)user_data;
230 if (button_ctrl)
231 {
232 if (button_ctrl->on_click != NULL)
233 {
234 button_ctrl->on_click(&button_ctrl->ctrl);
235 }
236 }
237 }
238
239 gate_result_t gate_ui_button_perform_action(gate_ui_button_t* button, gate_enumint_t action)
240 {
241 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&button->ctrl);
242 switch(action)
243 {
244 case GATE_UI_ACTION_ACTIVATE:
245 gate_ui_button_clicked((GtkButton*)widget, (gpointer)button);
246 return GATE_RESULT_OK;
247 }
248 return GATE_RESULT_NOTSUPPORTED;
249 }
250
251
252 gate_result_t gate_ui_button_create(gate_ui_button_t* button, gate_ui_ctrl_t* parent,
253 gate_ui_position_t const* position, gate_string_t const* caption,
254 gate_uint32_t flags, void* userparam)
255 {
256 gate_result_t ret = GATE_RESULT_OK;
257 GtkWidget* widget;
258 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
259
260 gate_mem_clear(button, sizeof(gate_ui_button_t));
261 widget = gtk_button_new();
262 if (widget == NULL)
263 {
264 return GATE_RESULT_FAILED;
265 }
266
267 ret = gate_ui_gtk_ctrl_init(&button->ctrl, widget, host, userparam, parent,
268 &gate_ui_gtk_button_dispatcher, false, false, position, &flags);
269
270 if (GATE_SUCCEEDED(ret))
271 {
272 if (gate_string_length(caption) > 0)
273 {
274 gate_ui_ctrl_set_text(&button->ctrl, caption);
275 }
276
277 g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(gate_ui_button_clicked), (gpointer)button);
278 }
279
280 return ret;
281 }
282
283
284 #endif /* GATE_UI_GTK */
285
286 #if defined(GATE_UI_MOTIF)
287
288 #include "gate/ui/gateui_motif.h"
289 #include <Xm/PushB.h>
290
291 1 static void button_pushed(Widget widget, XtPointer client_data, XtPointer call_data)
292 {
293 1 gate_ui_button_t* ptr_button = (gate_ui_button_t*)client_data;
294
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!ptr_button || !ptr_button->on_click)
295 {
296 return;
297 }
298 1 ptr_button->on_click(&ptr_button->ctrl);
299 }
300
301 1 gate_result_t gate_ui_button_perform_action(gate_ui_button_t* button, gate_enumint_t action)
302 {
303 1 Widget const w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&button->ctrl);
304
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 switch(action)
305 {
306 1 case GATE_UI_ACTION_ACTIVATE:
307 1 button_pushed(w, (XtPointer)button, NULL);
308 1 return GATE_RESULT_OK;
309 default:
310 break;
311 }
312 return GATE_RESULT_NOTSUPPORTED;
313 }
314
315 2 gate_result_t gate_ui_button_create(gate_ui_button_t* button, gate_ui_ctrl_t* parent,
316 gate_ui_position_t const* position, gate_string_t const* caption,
317 gate_uint32_t flags, void* userparam)
318 {
319 2 gate_result_t ret = GATE_RESULT_FAILED;
320 2 Widget w = NULL;
321 Arg args[8];
322 2 unsigned args_count = 0;
323
324 do
325 {
326
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (!button || !parent)
327 {
328 ret = GATE_RESULT_INVALIDARG;
329 break;
330 }
331
332 2 XtSetArg(args[args_count], XmNrecomputeSize, 0); ++args_count;
333 2 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
334 2 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
335
336 2 ret = gate_ui_motif_ctrl_create(&button->ctrl, xmPushButtonWidgetClass, userparam, NULL, parent,
337 position, &flags, false, NULL, args, args_count);
338
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
339
340 2 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&button->ctrl);
341 2 XtAddCallback(w, XmNactivateCallback, &button_pushed, button);
342 2 ret = gate_ui_motif_widget_set_label(w, caption);
343 } while (0);
344
345 2 return ret;
346 }
347
348 #endif /* GATE_UI_MOTIF */
349
350
351 #if defined(GATE_UI_WASMHTML)
352
353 #include "gate/ui/gateui_wasmhtml.h"
354
355 static gate_string_t const html_class_button = GATE_STRING_INIT_STATIC("button");
356
357 gate_result_t gate_ui_button_perform_action(gate_ui_button_t* button, gate_enumint_t action)
358 {
359 return GATE_RESULT_NOTSUPPORTED;
360 }
361
362 gate_result_t gate_ui_button_create(gate_ui_button_t* button, gate_ui_ctrl_t* parent,
363 gate_ui_position_t const* position, gate_string_t const* caption,
364 gate_uint32_t flags, void* userparam)
365 {
366 gate_result_t ret = GATE_RESULT_FAILED;
367 gate_ui_host_t* host = gate_ui_ctrl_get_host(parent);
368 gate_uint32_t parent_id = gate_ui_wasm_ctrl_get_container(parent);
369 gate_uint32_t new_id = 0;
370
371 do
372 {
373 gate_ui_wasm_new_ctrl_id(host, &new_id);
374 ret = gate_ui_wasm_ctrl_create(host, new_id, parent_id, &html_class_button, userparam, &button->ctrl);
375 GATE_BREAK_IF_FAILED(ret);
376
377 if (position)
378 {
379 gate_ui_wasm_ctrl_set_position(&button->ctrl, &position->pos, &position->size);
380 }
381 gate_ui_wasm_ctrl_set_text(&button->ctrl, caption);
382 } while (0);
383
384 return ret;
385 }
386
387 #endif /* GATE_UI_WASMHTML */
388
389