GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/labels.c
Date: 2026-09-21 06:26:40
Exec Total Coverage
Lines: 34 37 91.9%
Functions: 3 3 100.0%
Branches: 10 20 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/labels.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_label_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_NULL))
41 {
42 const ui_hwnd_t hwndCtrl = GATE_UI_WINAPI_GET_HWND(ctrl);
43 if (hwndCtrl != UI_HWND_NULL)
44 {
45 switch (msg)
46 {
47 case WM_SIZE:
48 {
49 if (hwndCtrl == hwnd)
50 {
51 InvalidateRect((HWND)hwndCtrl, NULL, TRUE);
52 }
53 return false;
54 }
55 case WM_COMMAND:
56 {
57 if (hwndCtrl == (ui_hwnd_t)lParam)
58 {
59 gate_ui_label_t* label = (gate_ui_label_t*)ctrl;
60 switch (HIWORD(wParam))
61 {
62 #if !defined(GATE_SYS_WIN16)
63 case STN_CLICKED:
64 {
65 if ((label != NULL) && (label->on_click != NULL))
66 {
67 label->on_click(ctrl);
68 }
69 return true;
70 }
71 #endif
72 default:
73 {
74 break;
75 }
76 }
77 }
78 break;
79 }
80 case WM_DRAWITEM:
81 {
82 DRAWITEMSTRUCT* drw = (DRAWITEMSTRUCT*)lParam;
83 if ((drw->hwndItem == (HWND)hwndCtrl)
84 #if !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WIN16)
85 && (drw->CtlType == ODT_STATIC)
86 #endif
87 )
88 {
89 HDC hdc = drw->hDC;
90 gate_uint32_t styles = (gate_uint32_t)(gate_uintptr_t)GATE_UI_WINAPI_GET_CTRL_PARAM(ctrl);
91 UINT flags = DT_VCENTER | DT_SINGLELINE | DT_NOCLIP;
92 RECT rect = drw->rcItem;
93 HBRUSH hbrush;
94 TCHAR txtbuffer[1024];
95 int txtbufferused = GetWindowText(drw->hwndItem, txtbuffer, sizeof(txtbuffer) / sizeof(txtbuffer[0]));
96
97 GetClientRect(drw->hwndItem, &rect);
98
99 if (styles & GATE_UI_FLAG_LABEL_RIGHT)
100 {
101 flags |= DT_RIGHT;
102 }
103 else if (styles & GATE_UI_FLAG_LABEL_CENTER)
104 {
105 flags |= DT_CENTER;
106 }
107 else
108 {
109 flags |= DT_LEFT;
110 }
111
112 #if defined(GATE_SYS_WIN16)
113 hbrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
114 #else
115 hbrush = (HBRUSH)SendMessage(GetParent(hwndCtrl), WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwndCtrl);
116 #endif
117 FillRect(hdc, &rect, hbrush);
118 DrawText(hdc, txtbuffer, txtbufferused, &rect, flags);
119 *lresult = TRUE;
120 return true;
121 }
122 }
123 default:
124 {
125 break;
126 }
127 }
128 }
129 }
130 return false;
131 }
132
133 gate_result_t gate_ui_label_perform_action(gate_ui_label_t* label, gate_enumint_t action)
134 {
135 gate_ui_ctrl_t* const ctrl = &label->ctrl;
136 ui_hwnd_t const hwnd = GATE_UI_WINAPI_GET_HWND(ctrl);
137 gate_intptr_t lresult = 0;
138 switch (action)
139 {
140 case GATE_UI_ACTION_ACTIVATE:
141 #if defined(GATE_SYS_WIN16)
142 #else
143 gate_ui_label_events(hwnd, ctrl, WM_COMMAND, (gate_uintptr_t)MAKELONG(0, STN_CLICKED), (gate_uintptr_t)hwnd, &lresult);
144 #endif
145 return GATE_RESULT_OK;
146 default:
147 break;
148 }
149 return GATE_RESULT_NOTSUPPORTED;
150 }
151
152 gate_result_t gate_ui_label_create(
153 gate_ui_label_t* label, gate_ui_ctrl_t* parent,
154 gate_ui_position_t const* position,
155 gate_string_t const* caption,
156 gate_uint32_t flags,
157 void* userparam
158 )
159 {
160 gate_result_t ret;
161 do
162 {
163 gate_uint32_t styles, exstyles;
164 ui_hwnd_t hwndParent;
165 DWORD winversion_major = 0;
166 gate_ui_host_t* host = gate_ui_ctrl_get_host(parent);
167 if (host == NULL)
168 {
169 ret = GATE_RESULT_INVALIDSTATE;
170 break;
171 }
172 hwndParent = GATE_UI_WINAPI_GET_HWND(parent);
173 if (hwndParent == UI_HWND_NULL)
174 {
175 ret = GATE_RESULT_INVALIDSTATE;
176 break;
177 }
178
179 gate_mem_clear(label, sizeof(gate_ui_label_t));
180
181 exstyles = 0;
182 styles = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
183 #if !defined(GATE_SYS_WIN16)
184 styles |= SS_NOTIFY;
185 #if !defined(GATE_SYS_WINCE)
186 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_LABEL_MULTILINE))
187 {
188 gate_win32_get_version(&winversion_major, NULL, NULL, NULL);
189 if (winversion_major >= 4)
190 {
191 styles |= SS_OWNERDRAW;
192 }
193 else
194 {
195 /* owner-drawn static controls not supported before NT4/9x */
196 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_LABEL_RIGHT))
197 {
198 styles |= SS_RIGHT;
199 }
200 else if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_LABEL_CENTER))
201 {
202 styles |= SS_CENTER;
203 }
204 else
205 {
206 styles |= SS_LEFTNOWORDWRAP;
207 }
208 }
209 }
210 else
211 #endif
212 #endif
213 {
214 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_LABEL_RIGHT))
215 {
216 styles |= SS_RIGHT;
217 }
218 else if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_LABEL_CENTER))
219 {
220 styles |= SS_CENTER;
221 }
222 else
223 {
224 styles |= SS_LEFT;
225 }
226 }
227
228 GATE_UI_WINAPI_SET_CTRL_PARAM(&label->ctrl, (gate_uintptr_t)flags);
229
230 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
231 //if(GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
232
233 ret = gate_ui_winapi_create(&label->ctrl, host, hwndParent, _T("STATIC"), position, styles, exstyles, caption, userparam, true);
234 if (GATE_SUCCEEDED(ret))
235 {
236 const ui_hwnd_t hwndCtrl = GATE_UI_WINAPI_GET_HWND(&label->ctrl);
237 gate_ui_winapi_register_event(host, hwndParent, WM_COMMAND, &gate_ui_label_events, &label->ctrl);
238 gate_ui_winapi_register_event(host, hwndParent, WM_DRAWITEM, &gate_ui_label_events, &label->ctrl);
239 gate_ui_winapi_register_event(host, hwndCtrl, WM_SIZE, &gate_ui_label_events, &label->ctrl);
240 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE))
241 {
242 gate_ui_ctrl_set_visible(&label->ctrl, true);
243 }
244 }
245 } while (0);
246
247 return ret;
248 }
249
250
251 #endif /*GATE_UI_WINAPI*/
252
253
254
255 #if defined(GATE_UI_GTK)
256
257 #include "gate/ui/gateui_gtk.h"
258
259 static gate_uint32_t gate_ui_gtk_label_get_text_length(gate_ui_ctrl_t* ctrl)
260 {
261 gint char_count = 0;
262 GtkLabel* label = GTK_LABEL(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
263 if (label)
264 {
265 gchar const* ptr_text = gtk_label_get_text(label);
266 if (ptr_text)
267 {
268 char_count = gate_str_length(ptr_text);
269 }
270 }
271 return (gate_uint32_t)char_count;
272 }
273 static gate_result_t gate_ui_gtk_label_get_text(gate_ui_ctrl_t* ctrl, gate_string_t* text)
274 {
275 gate_result_t ret = GATE_RESULT_FAILED;
276 GtkLabel* label = GTK_LABEL(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
277 if (label)
278 {
279 gchar const* ptr_text = gtk_label_get_text(label);
280 if (ptr_text)
281 {
282 if (NULL == gate_string_create(text, ptr_text, gate_str_length(ptr_text)))
283 {
284 ret = GATE_RESULT_OUTOFMEMORY;
285 }
286 else
287 {
288 ret = GATE_RESULT_OK;
289 }
290 }
291 else
292 {
293 gate_string_create_empty(text);
294 ret = GATE_RESULT_OK;
295 }
296 }
297 return ret;
298
299 }
300 static gate_result_t gate_ui_gtk_label_set_text(gate_ui_ctrl_t* ctrl, gate_string_t const* text)
301 {
302 gate_result_t ret = GATE_RESULT_FAILED;
303 GtkLabel* label = GTK_LABEL(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
304 if (label)
305 {
306 gchar text_buffer[8192];
307 gate_str_print_text(text_buffer, sizeof(text_buffer), text->str, text->length);
308 gtk_label_set_text(label, text_buffer);
309 ret = GATE_RESULT_OK;
310 }
311 return ret;
312 }
313
314 static gate_ui_gtk_dispatcher_t gate_ui_gtk_label_dispatcher =
315 {
316 gate_ui_gtk_label_get_text_length,
317 gate_ui_gtk_label_get_text,
318 gate_ui_gtk_label_set_text,
319 NULL,
320 NULL,
321 NULL
322 };
323
324 /*
325 static void gate_ui_label_clicked(GtkWidget* label, gpointer user_data)
326 {
327 gate_ui_label_t* label_ctrl = (gate_ui_label_t*)user_data;
328 if (label_ctrl)
329 {
330 if (label_ctrl->on_click != NULL)
331 {
332 label_ctrl->on_click(&label_ctrl->ctrl);
333 }
334 }
335 }
336 */
337
338 static gboolean gate_ui_label_button_pressed(GtkWidget* widget, GdkEventButton event, gpointer user_data)
339 {
340 gate_ui_label_t* label_ctrl = (gate_ui_label_t*)user_data;
341 printf("label_button\n");
342 if (label_ctrl != NULL)
343 {
344 if (label_ctrl->on_click != NULL)
345 {
346 label_ctrl->on_click(&label_ctrl->ctrl);
347 }
348 }
349 return TRUE;
350 }
351
352
353 gate_result_t gate_ui_label_create(gate_ui_label_t* label, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
354 gate_string_t const* caption, gate_uint32_t flags, void* userparam)
355 {
356 gate_result_t ret = GATE_RESULT_OK;
357 GtkWidget* widget;
358 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
359
360 gate_mem_clear(label, sizeof(gate_ui_label_t));
361 widget = gtk_label_new(NULL);
362 if (widget == NULL)
363 {
364 return GATE_RESULT_FAILED;
365 }
366
367 ret = gate_ui_gtk_ctrl_init(&label->ctrl, widget, host, userparam, parent,
368 &gate_ui_gtk_label_dispatcher, false, false, position, &flags);
369
370 if (GATE_SUCCEEDED(ret))
371 {
372 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_LABEL_RIGHT))
373 {
374 gtk_label_set_xalign(GTK_LABEL(widget), 1.0f);
375 gtk_label_set_justify(GTK_LABEL(widget), GTK_JUSTIFY_RIGHT);
376 }
377 else if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_LABEL_CENTER))
378 {
379 gtk_label_set_xalign(GTK_LABEL(widget), 0.5f);
380 gtk_label_set_justify(GTK_LABEL(widget), GTK_JUSTIFY_CENTER);
381 }
382 else
383 {
384 gtk_label_set_xalign(GTK_LABEL(widget), 0.0f);
385 gtk_label_set_justify(GTK_LABEL(widget), GTK_JUSTIFY_LEFT);
386 }
387
388 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_LABEL_MULTILINE))
389 {
390 }
391
392 if (gate_string_length(caption) > 0)
393 {
394 gate_ui_ctrl_set_text(&label->ctrl, caption);
395 }
396
397 //g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(gate_ui_label_clicked), (gpointer)label);
398 g_signal_connect(G_OBJECT(widget), "button-press-event", G_CALLBACK(gate_ui_label_button_pressed), (gpointer)label);
399 }
400
401 return ret;
402 }
403
404 gate_result_t gate_ui_label_perform_action(gate_ui_label_t* label, gate_enumint_t action)
405 {
406 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&label->ctrl);
407 switch(action)
408 {
409 case GATE_UI_ACTION_ACTIVATE:
410 {
411 GdkEventButton evt;
412 gate_mem_clear(&evt, sizeof(evt));
413 gate_ui_label_button_pressed(widget, evt, (gpointer)label);
414 return GATE_RESULT_OK;
415 }
416 }
417 return GATE_RESULT_NOTSUPPORTED;
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/Label.h>
429
430 1 static void gate_ui_label_event_onclick(Widget w, XtPointer ptr_data, XEvent* xevent, Boolean* ptr_continue_dispatch)
431 {
432 1 gate_ui_label_t* const label = (gate_ui_label_t*)ptr_data;
433
5/10
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 if (label && label->on_click && xevent && (xevent->type == ButtonPress) && (xevent->xbutton.button == Button1))
434 {
435 1 label->on_click(&label->ctrl);
436 }
437
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_continue_dispatch)
438 {
439 1 *ptr_continue_dispatch = FALSE;
440 }
441 1 }
442
443 1 gate_result_t gate_ui_label_perform_action(gate_ui_label_t* label, gate_enumint_t action)
444 {
445 1 Widget const w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&label->ctrl);
446 XEvent xevent;
447 1 Boolean continue_dispatch = TRUE;
448
449
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 switch(action)
450 {
451 1 case GATE_UI_ACTION_ACTIVATE:
452 1 gate_mem_clear(&xevent, sizeof(xevent));
453 1 xevent.xbutton.type = ButtonPress;
454 1 xevent.xbutton.button = Button1;
455 1 gate_ui_label_event_onclick(w, (XtPointer)label, &xevent, &continue_dispatch);
456 1 return GATE_RESULT_OK;
457 }
458 return GATE_RESULT_NOTSUPPORTED;
459 }
460
461
462 1 gate_result_t gate_ui_label_create(gate_ui_label_t* label, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
463 gate_string_t const* caption, gate_uint32_t flags, void* userparam)
464 {
465 1 gate_result_t ret = GATE_RESULT_FAILED;
466
467 do
468 {
469 1 Widget w = NULL;
470 Arg args[12];
471 1 unsigned args_count = 0;
472
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!label || !parent)
473 {
474 ret = GATE_RESULT_INVALIDARG;
475 break;
476 }
477
478 1 XtSetArg(args[args_count], XmNalignment, XmALIGNMENT_BEGINNING); ++args_count;
479 1 XtSetArg(args[args_count], XmNrecomputeSize, 0); ++args_count;
480 1 XtSetArg(args[args_count], XmNmarginLeft, 0); ++args_count;
481 1 XtSetArg(args[args_count], XmNmarginTop, 0); ++args_count;
482 1 XtSetArg(args[args_count], XmNmarginRight, 0); ++args_count;
483 1 XtSetArg(args[args_count], XmNmarginBottom, 0); ++args_count;
484
485 1 ret = gate_ui_motif_ctrl_create(&label->ctrl, xmLabelWidgetClass, userparam, NULL, parent,
486 position, &flags, false, NULL, args, args_count);
487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
488
489 1 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&label->ctrl);
490 1 ret = gate_ui_motif_widget_set_label(w, caption);
491 1 XtAddEventHandler(w, ButtonPressMask, False, &gate_ui_label_event_onclick, label);
492
493 } while (0);
494
495 1 return ret;
496 }
497 #endif /* GATE_UI_MOTIF */
498
499 #if defined(GATE_UI_WASMHTML)
500
501 #include "gate/ui/gateui_wasmhtml.h"
502
503 static gate_string_t const html_class_label = GATE_STRING_INIT_STATIC("div");
504
505 gate_result_t gate_ui_label_create(gate_ui_label_t* label, gate_ui_ctrl_t* parent,
506 gate_ui_position_t const* position, gate_string_t const* caption,
507 gate_uint32_t flags, void* userparam)
508 {
509 gate_result_t ret = GATE_RESULT_FAILED;
510 gate_ui_host_t* host = gate_ui_ctrl_get_host(parent);
511 gate_uint32_t parent_id = gate_ui_wasm_ctrl_get_container(parent);
512 gate_uint32_t new_id = 0;
513
514 gate_ui_wasm_new_ctrl_id(host, &new_id);
515 ret = gate_ui_wasm_ctrl_create(host, new_id, parent_id, &html_class_label, userparam, &label->ctrl);
516 if (position)
517 {
518 gate_ui_wasm_ctrl_set_position(&label->ctrl, &position->pos, &position->size);
519 }
520 gate_ui_wasm_ctrl_set_text(&label->ctrl, caption);
521 return ret;
522 }
523
524 gate_result_t gate_ui_label_perform_action(gate_ui_label_t* label, gate_enumint_t action)
525 {
526 return GATE_RESULT_NOTSUPPORTED;
527 }
528
529
530 #endif /* GATE_UI_WASMHTML */
531