GCC Code Coverage Report


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