GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/spinners.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 0 69 0.0%
Functions: 0 6 0.0%
Branches: 0 40 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/spinners.h"
30 #include "gate/results.h"
31 #include "gate/debugging.h"
32
33
34 #if defined(GATE_UI_WINAPI)
35
36 #if !defined(_WIN32_IE)
37 # define _WIN32_IE 0x0501
38 #endif
39
40 #include "gate/ui/gateui_winapi.h"
41 #include "gate/platforms.h"
42
43 #if !defined(GATE_SYS_WIN16)
44 #include <commctrl.h>
45 #else
46 # define UPDOWN_CLASS "msctls_updown32"
47
48 # define UDN_FIRST (0U-721U) // updown
49 # define UDN_LAST (0U-729U)
50 # define UDN_DELTAPOS (UDN_FIRST - 1)
51
52 # define UDM_SETRANGE (WM_USER+101)
53 # define UDM_GETRANGE (WM_USER+102)
54 # define UDM_SETPOS (WM_USER+103)
55 # define UDM_GETPOS (WM_USER+104)
56 # define UDM_SETBUDDY (WM_USER+105)
57 # define UDM_GETBUDDY (WM_USER+106)
58 # define UDM_SETACCEL (WM_USER+107)
59 # define UDM_GETACCEL (WM_USER+108)
60 # define UDM_SETBASE (WM_USER+109)
61 # define UDM_GETBASE (WM_USER+110)
62 # define UDM_SETRANGE32 (WM_USER+111)
63 # define UDM_GETRANGE32 (WM_USER+112) // wParam & lParam are LPINT
64 # define UDM_SETPOS32 (WM_USER+113)
65 # define UDM_GETPOS32 (WM_USER+114)
66
67 # define UDS_WRAP 0x0001
68 # define UDS_SETBUDDYINT 0x0002
69 # define UDS_ALIGNRIGHT 0x0004
70 # define UDS_ALIGNLEFT 0x0008
71 # define UDS_AUTOBUDDY 0x0010
72 # define UDS_ARROWKEYS 0x0020
73 # define UDS_HORZ 0x0040
74 # define UDS_NOTHOUSANDS 0x0080
75 # define UDS_HOTTRACK 0x0100
76 #endif
77
78 static HWND gate_ui_spinbox_get_text(HWND container)
79 {
80 return GetWindow(container, GW_CHILD);
81 }
82 static HWND gate_ui_spinbox_get_updown(HWND container)
83 {
84 HWND hwnd_text = gate_ui_spinbox_get_text(container);
85 return GetWindow(hwnd_text, GW_HWNDNEXT);
86 }
87
88 gate_result_t gate_ui_spinner_get_state(gate_ui_ctrl_t* ctrl, gate_int32_t* state)
89 {
90 gate_int64_t tmp = 0;
91 gate_result_t result = gate_ui_spinbox_get_value((gate_ui_spinbox_t*)ctrl, &tmp);
92 if (state) *state = (gate_int32_t)tmp;
93 return result;
94 }
95
96 gate_result_t gate_ui_spinner_set_state(gate_ui_ctrl_t* ctrl, gate_int32_t state)
97 {
98 return gate_ui_spinbox_set_value((gate_ui_spinbox_t*)ctrl, (gate_int64_t)state);
99 }
100
101 static gate_result_t gate_ui_spinner_refresh(gate_ui_ctrl_t* ctrl)
102 {
103 gate_result_t ret;
104 HWND hwnd_ctrl = GATE_UI_WINAPI_GET_HWND(ctrl);
105 HWND hwnd_text = gate_ui_spinbox_get_text(hwnd_ctrl);
106 HWND hwnd_updown = gate_ui_spinbox_get_updown(hwnd_ctrl);
107
108 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
109 BOOL dark_mode;
110 if (gate_ui_winapi_darkmode_supported())
111 {
112 dark_mode = gate_ui_winapi_darkmode_enabled() ? TRUE : FALSE;
113 gate_ui_winapi_apply_darkmode(hwnd_text, dark_mode);
114 gate_ui_winapi_apply_darkmode(hwnd_updown, dark_mode);
115 }
116 #endif /* GATE_UI_WINAPI_DARKMODE_SUPPORT */
117
118 ret = gate_ui_winapi_refresh(ctrl);
119 gate_ui_winapi_refresh_hwnd(hwnd_text);
120 gate_ui_winapi_refresh_hwnd(hwnd_updown);
121
122 return ret;
123 }
124
125 static gate_ui_winapi_dispatchers_t global_win32_spinner_dispatchers =
126 {
127 &gate_ui_winapi_destroy_with_font,
128 &gate_ui_winapi_is_enabled,
129 &gate_ui_winapi_is_visible,
130 &gate_ui_winapi_is_focused,
131 &gate_ui_winapi_get_position,
132 &gate_ui_winapi_get_size,
133 &gate_ui_winapi_get_children,
134 &gate_ui_winapi_get_text_length,
135 &gate_ui_winapi_get_text,
136 &gate_ui_spinner_get_state,
137 &gate_ui_winapi_set_enabled,
138 &gate_ui_winapi_set_visible,
139 &gate_ui_winapi_set_focus,
140 &gate_ui_winapi_set_position,
141 &gate_ui_winapi_set_text,
142 &gate_ui_spinner_set_state,
143 &gate_ui_spinner_refresh
144 };
145
146
147 static gate_bool_t gate_ui_spinbox_events(void* hwnd, gate_ui_ctrl_t* ctrl, gate_uint32_t msg, gate_uintptr_t wParam, gate_intptr_t lParam, gate_intptr_t* lresult)
148 {
149 if ((ctrl != NULL) && (hwnd != NULL))
150 {
151 HWND hwnd_ctrl = GATE_UI_WINAPI_GET_HWND(ctrl);
152 if (hwnd_ctrl)
153 {
154 gate_ui_spinbox_t* spinbox = (gate_ui_spinbox_t*)ctrl;
155 switch (msg)
156 {
157 #if !defined(GATE_SYS_WIN16)
158 case WM_CTLCOLOREDIT:
159 case WM_CTLCOLORBTN:
160 case WM_CTLCOLORLISTBOX:
161 case WM_CTLCOLORMSGBOX:
162 case WM_CTLCOLORSCROLLBAR:
163 case WM_CTLCOLORDLG:
164 case WM_CTLCOLORSTATIC:
165 {
166 *lresult = SendMessage(GetParent((HWND)hwnd_ctrl), msg, wParam, lParam);
167 return true;
168 }
169 #endif /* GATE_SYS_WIN16 */
170 case UDN_DELTAPOS:
171 {
172 LRESULT pos;
173 #if defined(UDM_GETPOS32)
174 pos = SendMessage(hwnd_ctrl, UDM_GETPOS32, 0, 0);
175 #else
176 pos = (LRESULT)LOWORD(SendMessage(hwnd, UDM_GETPOS, 0, 0));
177 #endif
178 if (spinbox->on_change)
179 {
180 spinbox->on_change(ctrl, (gate_int64_t)pos);
181 }
182 *lresult = 0;
183 return true;
184 }
185 case WM_SIZE:
186 {
187 int updown_width = 24;
188 RECT rect;
189 HWND hwnd_text = gate_ui_spinbox_get_text(hwnd_ctrl);
190 HWND hwnd_updown = gate_ui_spinbox_get_updown(hwnd_ctrl);
191 GetClientRect(hwnd_ctrl, &rect);
192 SetWindowPos(hwnd_text, NULL, 0, 0, rect.right - updown_width, rect.bottom, SWP_NOZORDER);
193 SetWindowPos(hwnd_updown, NULL, rect.right - updown_width, 0, updown_width, rect.bottom, SWP_NOZORDER);
194 *lresult = 0;
195 return true;
196 }
197 case WM_ENABLE:
198 {
199 HWND hwnd_text = gate_ui_spinbox_get_text(hwnd_ctrl);
200 HWND hwnd_updown = gate_ui_spinbox_get_updown(hwnd_ctrl);
201 EnableWindow(hwnd_text, (BOOL)wParam);
202 EnableWindow(hwnd_updown, (BOOL)wParam);
203 return false;
204 }
205 default:
206 {
207 break;
208 }
209 }
210 }
211 }
212 return false;
213 }
214
215 gate_result_t gate_ui_spinbox_create(
216 gate_ui_spinbox_t* spinbox, gate_ui_ctrl_t* parent,
217 gate_ui_position_t const* position,
218 gate_uint32_t flags,
219 void* userparam
220 )
221 {
222 gate_result_t ret = GATE_RESULT_FAILED;
223
224 do
225 {
226 gate_uint32_t styles = 0, exstyles = 0;
227 HWND hwnd_parent;
228 HWND hwnd_container;
229 HWND hwnd_text;
230 HWND hwnd_updown;
231 HINSTANCE hinst;
232
233 gate_ui_host_t* host = gate_ui_ctrl_get_host(parent);
234 if (host == NULL)
235 {
236 ret = GATE_RESULT_INVALIDSTATE;
237 break;
238 }
239 hwnd_parent = GATE_UI_WINAPI_GET_HWND(parent);
240 if (hwnd_parent == NULL)
241 {
242 ret = GATE_RESULT_INVALIDSTATE;
243 break;
244 }
245
246 gate_mem_clear(spinbox, sizeof(gate_ui_spinbox_t));
247
248 {
249 /* create a container windows which contains the text and up-down elements */
250
251 exstyles = 0;
252 #if !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WIN16)
253 exstyles |= WS_EX_CONTROLPARENT;
254 #endif
255 styles = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE;
256 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
257 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
258
259 ret = gate_ui_winapi_create(&spinbox->ctrl, host, hwnd_parent, NULL, position, styles, exstyles, NULL, userparam, false);
260
261 if (GATE_FAILED(ret))
262 {
263 break;
264 }
265 hwnd_container = GATE_UI_WINAPI_GET_HWND(&spinbox->ctrl);
266 hinst = (HINSTANCE)GATE_UI_WINAPI_GET_HOST_APPHANDLE(host);
267 }
268
269 {
270 /* create the text-element as child window */
271 HFONT hfont;
272 styles = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE | ES_AUTOHSCROLL;
273 #if !defined(GATE_SYS_WIN16)
274 styles |= ES_NUMBER;
275 exstyles = WS_EX_CLIENTEDGE;
276 #endif
277 hwnd_text = CreateWindowEx(exstyles, _T("EDIT"), NULL, styles, 0, 0, 10, 10, hwnd_container, NULL, hinst, NULL);
278 if (NULL == hwnd_text)
279 {
280 gate_ui_ctrl_destroy(&spinbox->ctrl);
281 ret = GATE_RESULT_OUTOFRESOURCES;
282 break;
283 }
284 hfont = (HFONT)GATE_UI_WINAPI_GET_HOST_FONT(host);
285 if (hfont != NULL)
286 {
287 SendMessage(hwnd_text, WM_SETFONT, (WPARAM)(gate_uintptr_t)hfont, TRUE);
288 }
289 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
290 if (gate_ui_winapi_darkmode_enabled())
291 {
292 gate_ui_winapi_apply_darkmode(hwnd_text, TRUE);
293 }
294 #endif
295 }
296
297 {
298 /* create up-down control as child window */
299 exstyles = 0;
300 styles = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE;
301 styles |= (UDS_ARROWKEYS | UDS_SETBUDDYINT | UDS_NOTHOUSANDS);
302
303 hwnd_updown = CreateWindowEx(exstyles, UPDOWN_CLASS, NULL, styles, 0, 0, 10, 10, hwnd_container, NULL, hinst, NULL);
304 if (NULL == hwnd_text)
305 {
306 DestroyWindow(hwnd_text);
307 gate_ui_ctrl_destroy(&spinbox->ctrl);
308 ret = GATE_RESULT_OUTOFRESOURCES;
309 break;
310 }
311
312 #if defined(GATE_UI_WINAPI_DARKMODE_SUPPORT)
313 if (gate_ui_winapi_darkmode_enabled())
314 {
315 gate_ui_winapi_apply_darkmode(hwnd_updown, TRUE);
316 }
317 #endif
318
319 SendMessage(hwnd_updown, UDM_SETBUDDY, (WPARAM)hwnd_text, 0);
320 SendMessage(hwnd_updown, UDM_SETRANGE32, (WPARAM)LONG_MIN, (LPARAM)LONG_MAX);
321 SendMessage(hwnd_updown, UDM_SETPOS, 0, MAKELONG(0, 0));
322 }
323
324 GATE_UI_WINAPI_SET_DISPATCHER(&spinbox->ctrl, &global_win32_spinner_dispatchers);
325
326 gate_ui_winapi_register_event(host, hwnd_container, WM_SIZE, &gate_ui_spinbox_events, &spinbox->ctrl);
327 gate_ui_winapi_register_event(host, hwnd_container, WM_ENABLE, &gate_ui_spinbox_events, &spinbox->ctrl);
328 gate_ui_winapi_register_event(host, hwnd_container, UDN_DELTAPOS, &gate_ui_spinbox_events, &spinbox->ctrl);
329 #if !defined(GATE_SYS_WIN16)
330 gate_ui_winapi_register_event(host, hwnd_container, WM_CTLCOLORDLG, &gate_ui_spinbox_events, &spinbox->ctrl);
331 gate_ui_winapi_register_event(host, hwnd_container, WM_CTLCOLORSTATIC, &gate_ui_spinbox_events, &spinbox->ctrl);
332 gate_ui_winapi_register_event(host, hwnd_container, WM_CTLCOLOREDIT, &gate_ui_spinbox_events, &spinbox->ctrl);
333 gate_ui_winapi_register_event(host, hwnd_container, WM_CTLCOLORBTN, &gate_ui_spinbox_events, &spinbox->ctrl);
334 gate_ui_winapi_register_event(host, hwnd_container, WM_CTLCOLORLISTBOX, &gate_ui_spinbox_events, &spinbox->ctrl);
335 gate_ui_winapi_register_event(host, hwnd_container, WM_CTLCOLORMSGBOX, &gate_ui_spinbox_events, &spinbox->ctrl);
336 gate_ui_winapi_register_event(host, hwnd_container, WM_CTLCOLORSCROLLBAR, &gate_ui_spinbox_events, &spinbox->ctrl);
337 #endif
338
339 ret = GATE_RESULT_OK;
340
341 } while (0);
342
343 return ret;
344 }
345
346 gate_result_t gate_ui_spinbox_set_limits(gate_ui_spinbox_t* spinbox, gate_int64_t const* minimum, gate_int64_t const* maximum)
347 {
348 gate_result_t ret = GATE_RESULT_FAILED;
349 HWND hwnd_container = GATE_UI_WINAPI_GET_HWND(&spinbox->ctrl);
350 if (hwnd_container)
351 {
352 HWND hwnd_updown = gate_ui_spinbox_get_updown(hwnd_container);
353 if (hwnd_updown)
354 {
355 INT lower_limit = 0;
356 INT upper_limit = 0;
357 LRESULT result;
358
359 #if defined(UDM_SETRANGE32) && defined(UDM_GETRANGE32)
360 SendMessage(hwnd_updown, UDM_GETRANGE32, (WPARAM)&lower_limit, (LPARAM)&upper_limit);
361 if (minimum)
362 {
363 lower_limit = (INT)*minimum;
364 }
365 if (maximum)
366 {
367 upper_limit = (INT)*maximum;
368 }
369 SendMessage(hwnd_updown, UDM_SETRANGE32, (WPARAM)lower_limit, (LPARAM)upper_limit);
370 #else
371 result = SendMessage(hwnd_updown, UDM_GETRANGE, 0, 0);
372 lower_limit = (INT)(short)HIWORD(result);
373 upper_limit = (INT)(short)LOWORD(result);
374 if (minimum)
375 {
376 lower_limit = (INT)*minimum;
377 }
378 if (maximum)
379 {
380 upper_limit = (INT)*maximum;
381 }
382 SendMessage(hwnd_updown, UDM_SETRANGE, 0, MAKELPARAM(upper_limit, lower_limit));
383 #endif
384 ret = GATE_RESULT_OK;
385 }
386 }
387 return ret;
388
389 }
390 gate_result_t gate_ui_spinbox_get_limits(gate_ui_spinbox_t* spinbox, gate_int64_t* minimum, gate_int64_t* maximum)
391 {
392 gate_result_t ret = GATE_RESULT_FAILED;
393 HWND hwnd_container = GATE_UI_WINAPI_GET_HWND(&spinbox->ctrl);
394 HWND hwnd_updown;
395 INT lower_limit = 0;
396 INT upper_limit = 0;
397 LRESULT result;
398 if (hwnd_container)
399 {
400 hwnd_updown = gate_ui_spinbox_get_updown(hwnd_container);
401 if (hwnd_updown)
402 {
403 #if defined(UDM_GETRANGE32)
404 result = SendMessage(hwnd_updown, UDM_GETRANGE32, (WPARAM)&lower_limit, (LPARAM)&upper_limit);
405 #else
406 result = SendMessage(hwnd_updown, UDM_GETRANGE, 0, 0);
407 lower_limit = (INT)(short)HIWORD(result);
408 upper_limit = (INT)(short)LOWORD(result);
409 #endif
410 if (minimum)
411 {
412 *minimum = (gate_int64_t)lower_limit;
413 }
414 if (maximum)
415 {
416 *maximum = (gate_int64_t)upper_limit;
417 }
418 ret = GATE_RESULT_OK;
419 }
420 }
421 return ret;
422 }
423
424 gate_result_t gate_ui_spinbox_set_value(gate_ui_spinbox_t* spinbox, gate_int64_t value)
425 {
426 gate_result_t ret = GATE_RESULT_FAILED;
427 HWND hwnd_container = GATE_UI_WINAPI_GET_HWND(&spinbox->ctrl);
428 if (hwnd_container)
429 {
430 HWND hwnd_updown = gate_ui_spinbox_get_updown(hwnd_container);
431 if (hwnd_updown)
432 {
433 #if defined(UDM_SETPOS32)
434 SendMessage(hwnd_updown, UDM_SETPOS32, 0, (LPARAM)value);
435 #else
436 SendMessage(hwnd_updown, UDM_SETPOS, 0, (LPARAM)value);
437 #endif
438 ret = GATE_RESULT_OK;
439 }
440 }
441 return ret;
442 }
443 gate_result_t gate_ui_spinbox_get_value(gate_ui_spinbox_t* spinbox, gate_int64_t* value)
444 {
445 gate_result_t ret = GATE_RESULT_FAILED;
446 HWND hwnd_container = GATE_UI_WINAPI_GET_HWND(&spinbox->ctrl);
447 if (hwnd_container)
448 {
449 HWND hwnd_updown = gate_ui_spinbox_get_updown(hwnd_container);
450 if (hwnd_updown)
451 {
452 LRESULT spinvalue = 0;
453 BOOL failed = FALSE;
454 #if defined(UDM_GETPOS32)
455 spinvalue = SendMessage(hwnd_updown, UDM_GETPOS32, 0, (LPARAM)&failed);
456 #else
457 spinvalue = (LRESULT)(gate_int16_t)LOWORD(SendMessage(hwnd_updown, UDM_GETPOS, 0, 0));
458 #endif
459 if (!failed)
460 {
461 *value = (gate_int64_t)spinvalue;
462 ret = GATE_RESULT_OK;
463 }
464 }
465 }
466 return ret;
467 }
468
469 #endif
470
471
472 #if defined(GATE_UI_GTK)
473
474 #include "gate/ui/gateui_gtk.h"
475
476 static gate_uint32_t gate_ui_gtk_spinbox_get_text_length(gate_ui_ctrl_t* ctrl)
477 {
478 gint char_count = 0;
479 GtkButton* button = GTK_BUTTON(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
480 if (button)
481 {
482 gchar const* ptr_text = gtk_button_get_label(button);
483 if (ptr_text)
484 {
485 char_count = gate_str_length(ptr_text);
486 }
487 }
488 return (gate_uint32_t)char_count;
489 }
490 static gate_result_t gate_ui_gtk_spinbox_get_text(gate_ui_ctrl_t* ctrl, gate_string_t* text)
491 {
492 gate_result_t ret = GATE_RESULT_FAILED;
493 GtkButton* button = GTK_BUTTON(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
494 if (button)
495 {
496 gchar const* ptr_text = gtk_button_get_label(button);
497 if (ptr_text)
498 {
499 if (NULL == gate_string_create(text, ptr_text, gate_str_length(ptr_text)))
500 {
501 ret = GATE_RESULT_OUTOFMEMORY;
502 }
503 else
504 {
505 ret = GATE_RESULT_OK;
506 }
507 }
508 else
509 {
510 gate_string_create_empty(text);
511 ret = GATE_RESULT_OK;
512 }
513 }
514 return ret;
515
516 }
517 static gate_result_t gate_ui_gtk_spinbox_set_text(gate_ui_ctrl_t* ctrl, gate_string_t const* text)
518 {
519 gate_result_t ret = GATE_RESULT_FAILED;
520 gchar label[4096];
521 GtkButton* button = GTK_BUTTON(GATE_UI_GTK_GET_CTRL_WIDGET(ctrl));
522 if (button)
523 {
524 gate_str_print_text(label, sizeof(label), text->str, text->length);
525 gtk_button_set_label(button, label);
526 ret = GATE_RESULT_OK;
527 }
528 return ret;
529 }
530 static gate_result_t gate_ui_gtk_spinbox_get_state(gate_ui_ctrl_t* ctrl, gate_int32_t* value)
531 {
532 return GATE_RESULT_NOTIMPLEMENTED;
533 }
534 static gate_result_t gate_ui_gtk_spinbox_set_state(gate_ui_ctrl_t* ctrl, gate_int32_t value)
535 {
536 return GATE_RESULT_NOTIMPLEMENTED;
537 }
538
539 static gate_ui_gtk_dispatcher_t gate_ui_gtk_spinbox_dispatcher =
540 {
541 &gate_ui_gtk_spinbox_get_text_length,
542 &gate_ui_gtk_spinbox_get_text,
543 &gate_ui_gtk_spinbox_set_text,
544 &gate_ui_gtk_spinbox_get_state,
545 &gate_ui_gtk_spinbox_set_state,
546 NULL
547 };
548
549 static void gate_ui_spinbox_changed_cb(GtkSpinButton* spin_button, GtkScrollType scroll, gpointer user_data)
550 {
551 gate_ui_spinbox_t* spinbox_ctrl = (gate_ui_spinbox_t*)user_data;
552 gate_int64_t value = 0;
553 if (spinbox_ctrl)
554 {
555 if (spinbox_ctrl->on_change != NULL)
556 {
557 gate_ui_spinbox_get_value(spinbox_ctrl, &value);
558 spinbox_ctrl->on_change(&spinbox_ctrl->ctrl, value);
559 }
560 }
561 }
562
563
564 gate_result_t gate_ui_spinbox_create(gate_ui_spinbox_t* spinbox, gate_ui_ctrl_t* parent,
565 gate_ui_position_t const* position, gate_uint32_t flags, void* userparam)
566 {
567 gate_result_t ret = GATE_RESULT_OK;
568 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
569 GtkWidget* widget;
570
571 gate_mem_clear(spinbox, sizeof(gate_ui_spinbox_t));
572 widget = gtk_spin_button_new(NULL, 1.0, 0);
573 if (widget == NULL)
574 {
575 return GATE_RESULT_FAILED;
576 }
577
578 ret = gate_ui_gtk_ctrl_init(&spinbox->ctrl, widget, host, userparam, parent,
579 &gate_ui_gtk_spinbox_dispatcher, false, false, position, &flags);
580
581 if (GATE_SUCCEEDED(ret))
582 {
583 gtk_spin_button_set_range(GTK_SPIN_BUTTON(widget), (gdouble)LONG_MIN, (gdouble)LONG_MAX);
584 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(widget), 1.0, 100.0);
585 g_signal_connect(G_OBJECT(widget), "change-value", G_CALLBACK(gate_ui_spinbox_changed_cb), (gpointer)spinbox);
586 }
587
588 return ret;
589 }
590
591 gate_result_t gate_ui_spinbox_set_limits(gate_ui_spinbox_t* spinbox, gate_int64_t const* minimum, gate_int64_t const* maximum)
592 {
593 gate_result_t ret = GATE_RESULT_OK;
594 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&spinbox->ctrl);
595 GtkSpinButton* spinbutton = GTK_SPIN_BUTTON(widget);
596 gdouble min_value = 0.0;
597 gdouble max_value = 0.0;
598 gtk_spin_button_get_range(spinbutton, &min_value, &max_value);
599 if (minimum)
600 {
601 min_value = (gdouble)*minimum;
602 }
603 if (maximum)
604 {
605 max_value = (gdouble)*maximum;
606 }
607 gtk_spin_button_set_range(spinbutton, min_value, max_value);
608 return ret;
609 }
610
611 gate_result_t gate_ui_spinbox_get_limits(gate_ui_spinbox_t* spinbox, gate_int64_t* minimum, gate_int64_t* maximum)
612 {
613 gate_result_t ret = GATE_RESULT_OK;
614 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&spinbox->ctrl);
615 GtkSpinButton* spinbutton = GTK_SPIN_BUTTON(widget);
616 gdouble min_value = 0.0;
617 gdouble max_value = 0.0;
618 gtk_spin_button_get_range(spinbutton, &min_value, &max_value);
619 if (minimum)
620 {
621 *minimum = (gate_int64_t)min_value;
622 }
623 if (maximum)
624 {
625 *maximum = (gate_int64_t)max_value;
626 }
627 return ret;
628 }
629
630 gate_result_t gate_ui_spinbox_set_value(gate_ui_spinbox_t* spinbox, gate_int64_t value)
631 {
632 gate_result_t ret = GATE_RESULT_OK;
633 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&spinbox->ctrl);
634 GtkSpinButton* spinbutton = GTK_SPIN_BUTTON(widget);
635 gtk_spin_button_set_value(spinbutton, (gdouble)value);
636 return ret;
637 }
638
639 gate_result_t gate_ui_spinbox_get_value(gate_ui_spinbox_t* spinbox, gate_int64_t* value)
640 {
641 gate_result_t ret = GATE_RESULT_OK;
642 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&spinbox->ctrl);
643 GtkSpinButton* spinbutton = GTK_SPIN_BUTTON(widget);
644 gdouble native_value = gtk_spin_button_get_value(spinbutton);
645 if (value)
646 {
647 *value = (gate_int64_t)native_value;
648 }
649 return ret;
650 }
651
652 #endif /* GATE_UI_GTK */
653
654
655
656 #if defined(GATE_UI_MOTIF)
657
658 #include "gate/ui/gateui_motif.h"
659 #include <Xm/SpinB.h>
660 #include <Xm/SSpinB.h>
661
662
663 static void spinbox_value_changed(Widget widget, XtPointer client_data, XtPointer call_data)
664 {
665 gate_ui_spinbox_t* ptr_spinbox = (gate_ui_spinbox_t*)client_data;
666 if (!ptr_spinbox || !ptr_spinbox->on_change)
667 {
668 return;
669 }
670 ptr_spinbox->on_change(&ptr_spinbox->ctrl, 0);
671
672 }
673
674 gate_result_t gate_ui_spinbox_create(gate_ui_spinbox_t* spinbox, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
675 gate_uint32_t flags, void* userparam)
676 {
677 gate_result_t ret = GATE_RESULT_FAILED;
678 do
679 {
680 Widget w = NULL;
681 Arg args[12];
682 unsigned args_count = 0;
683
684 if (!spinbox || !parent)
685 {
686 ret = GATE_RESULT_INVALIDARG;
687 break;
688 }
689
690 XtSetArg(args[args_count], XmNarrowLayout, XmARROWS_SPLIT); ++args_count;
691 XtSetArg(args[args_count], XmNminimumValue, 0); ++args_count;
692 XtSetArg(args[args_count], XmNmaximumValue, 32767); ++args_count;
693 XtSetArg(args[args_count], XmNposition, 1); ++args_count;
694 XtSetArg(args[args_count], XmNincrementValue, 1); ++args_count;
695 XtSetArg(args[args_count], XmNpositionType, XmPOSITION_VALUE); ++args_count;
696 XtSetArg(args[args_count], XmNspinBoxChildType, XmNUMERIC); ++args_count;
697 XtSetArg(args[args_count], XmNshadowThickness, 0); ++args_count;
698 XtSetArg(args[args_count], XmNarrowSensitivity, XmARROWS_SENSITIVE); ++args_count;
699
700 ret = gate_ui_motif_ctrl_create(&spinbox->ctrl, xmSimpleSpinBoxWidgetClass, userparam, NULL, parent,
701 position, &flags, false, NULL, args, args_count);
702 GATE_BREAK_IF_FAILED(ret);
703
704 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&spinbox->ctrl);
705 XtAddCallback(w, XmNvalueChangedCallback, &spinbox_value_changed, spinbox);
706 } while (0);
707
708 return ret;
709 }
710
711 gate_result_t gate_ui_spinbox_set_limits(gate_ui_spinbox_t* spinbox, gate_int64_t const* minimum, gate_int64_t const* maximum)
712 {
713 Widget w;
714 GATE_DEBUG_ASSERT(spinbox != NULL);
715 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&spinbox->ctrl);
716 GATE_DEBUG_ASSERT(w != NULL);
717
718 if (minimum)
719 {
720 spinbox->min_limit = *minimum;
721 XtVaSetValues(w, XmNminimumValue, (int)*minimum, NULL, NULL);
722 }
723 if (maximum)
724 {
725 spinbox->max_limit = *maximum;
726 XtVaSetValues(w, XmNmaximumValue, (int)*maximum, NULL, NULL);
727 }
728 return GATE_RESULT_OK;
729 }
730
731 gate_result_t gate_ui_spinbox_get_limits(gate_ui_spinbox_t* spinbox, gate_int64_t* minimum, gate_int64_t* maximum)
732 {
733 Widget w;
734 int limit;
735 GATE_DEBUG_ASSERT(spinbox != NULL);
736 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&spinbox->ctrl);
737 GATE_DEBUG_ASSERT(w != NULL);
738
739 if (minimum)
740 {
741 XtVaGetValues(w, XmNminimumValue, &limit, NULL, NULL);
742 *minimum = limit;
743 }
744 if (maximum)
745 {
746 XtVaGetValues(w, XmNmaximumValue, &limit, NULL, NULL);
747 *maximum = limit;
748 }
749 return GATE_RESULT_OK;
750 }
751
752 gate_result_t gate_ui_spinbox_set_value(gate_ui_spinbox_t* spinbox, gate_int64_t value)
753 {
754 Widget w;
755 int limit;
756 GATE_DEBUG_ASSERT(spinbox != NULL);
757 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&spinbox->ctrl);
758 GATE_DEBUG_ASSERT(w != NULL);
759
760 XtVaGetValues(w, XmNminimumValue, &limit, NULL, NULL);
761 if (value < spinbox->min_limit)
762 {
763 spinbox->value = spinbox->min_limit;
764 }
765 else if (value > spinbox->max_limit)
766 {
767 spinbox->value = spinbox->max_limit;
768 }
769 else
770 {
771 spinbox->value = value;
772 }
773 XtVaSetValues(w, XmNposition, (int)spinbox->value, NULL, NULL);
774 return GATE_RESULT_OK;
775 }
776
777 gate_result_t gate_ui_spinbox_get_value(gate_ui_spinbox_t* spinbox, gate_int64_t* value)
778 {
779 Widget w;
780 int pos = 0;
781 GATE_DEBUG_ASSERT(spinbox != NULL);
782 w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&spinbox->ctrl);
783 GATE_DEBUG_ASSERT(w != NULL);
784
785 if (value)
786 {
787 XtVaGetValues(w, XmNposition, &pos, NULL, NULL);
788 *value = spinbox->value;
789 }
790 return GATE_RESULT_OK;
791 }
792
793 #endif /* GATE_UI_MOTIF */
794