GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/comboboxes.c
Date: 2026-09-21 06:26:40
Exec Total Coverage
Lines: 127 162 78.4%
Functions: 12 12 100.0%
Branches: 29 62 46.8%

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/comboboxes.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 #include "gate/debugging.h"
38
39 static gate_bool_t WINAPI gate_ui_combobox_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)
40 {
41 if ((ctrl != NULL) && (hwnd != UI_HWND_NULL))
42 {
43 ui_hwnd_t hwndCtrl = GATE_UI_WINAPI_GET_HWND(ctrl);
44 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(ctrl);
45 if (hwndCtrl != UI_HWND_NULL)
46 {
47 switch (msg)
48 {
49 case WM_COMMAND:
50 {
51 if (hwndCtrl == (ui_hwnd_t)lParam)
52 {
53 gate_ui_combobox_t* const combobox = (gate_ui_combobox_t*)ctrl;
54 switch (HIWORD(wParam))
55 {
56 case CBN_SELCHANGE:
57 {
58 LRESULT sel_index = SendMessage((HWND)hwndCtrl, CB_GETCURSEL, 0, 0);
59 if ((combobox != NULL) && (sel_index != CB_ERR) && (combobox->on_select != NULL))
60 {
61 combobox->on_select(&combobox->ctrl, sel_index);
62 }
63 *lresult = 0;
64 return true;
65 }
66 default:
67 {
68 break;
69 }
70 }
71 }
72 break;
73 }
74 default:
75 {
76 break;
77 }
78 }
79 }
80 }
81 return false;
82 }
83
84 static gate_result_t WINAPI gate_ui_combobox_set_position(gate_ui_ctrl_t* ctrl, gate_ui_point_t const* position, gate_ui_size_t const* size)
85 {
86 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(ctrl);
87 gate_ui_size_t new_size;
88 if (size)
89 {
90 gate_uint32_t line_height = gate_ui_host_default_line_height(host);
91 new_size = *size;
92 if (new_size.height < (int)(line_height * 10))
93 {
94 new_size.height = (int)(line_height * 10);
95 }
96 }
97 return gate_ui_winapi_set_position(ctrl, position, size ? &new_size : NULL);
98 }
99
100 static gate_ui_winapi_dispatchers_t global_win32_combobox_dispatchers =
101 {
102 &gate_ui_winapi_destroy_with_font,
103 &gate_ui_winapi_is_enabled,
104 &gate_ui_winapi_is_visible,
105 &gate_ui_winapi_is_focused,
106 &gate_ui_winapi_get_position,
107 &gate_ui_winapi_get_size,
108 &gate_ui_winapi_get_children,
109 &gate_ui_winapi_get_text_length,
110 &gate_ui_winapi_get_text,
111 &gate_ui_winapi_get_state,
112 &gate_ui_winapi_set_enabled,
113 &gate_ui_winapi_set_visible,
114 &gate_ui_winapi_set_focus,
115 &gate_ui_combobox_set_position,
116 &gate_ui_winapi_set_text,
117 &gate_ui_winapi_set_state,
118 &gate_ui_winapi_refresh
119 };
120
121 gate_result_t gate_ui_combobox_create(
122 gate_ui_combobox_t* combobox, gate_ui_ctrl_t* parent,
123 gate_ui_position_t const* position,
124 gate_uint32_t flags,
125 void* userparam
126 )
127 {
128 static gate_int32_t COMBOBOX_MIN_HEIGHT = 128;
129 gate_result_t ret;
130
131 do
132 {
133 gate_uint32_t styles, exstyles;
134 gate_ui_position_t adapted_position;
135 ui_hwnd_t hwndParent, hwndCtrl;
136 gate_ui_host_t* host = gate_ui_ctrl_get_host(parent);
137 if (host == NULL)
138 {
139 ret = GATE_RESULT_INVALIDSTATE;
140 break;
141 }
142 hwndParent = GATE_UI_WINAPI_GET_HWND(parent);
143 if (!hwndParent)
144 {
145 ret = GATE_RESULT_INVALIDSTATE;
146 break;
147 }
148
149 gate_mem_clear(combobox, sizeof(gate_ui_combobox_t));
150
151 exstyles = 0;
152 styles = WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | CBS_DROPDOWNLIST | CBS_NOINTEGRALHEIGHT;
153 /*styles |= BS_FLAT;*/
154 if (!GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_ENABLED)) styles |= WS_DISABLED;
155 if (GATE_FLAG_ENABLED(flags, GATE_UI_FLAG_VISIBLE)) styles |= WS_VISIBLE;
156
157 if (position)
158 {
159 gate_mem_copy(&adapted_position, position, sizeof(gate_ui_position_t));
160 }
161 else
162 {
163 gate_ui_ctrl_get_size(parent, &adapted_position.size);
164 adapted_position.pos.x = 0;
165 adapted_position.pos.y = 0;
166 }
167 if (adapted_position.size.height < COMBOBOX_MIN_HEIGHT)
168 {
169 adapted_position.size.height = COMBOBOX_MIN_HEIGHT;
170 }
171
172 ret = gate_ui_winapi_create(&combobox->ctrl, host, hwndParent, _T("COMBOBOX"),
173 position ? &adapted_position : NULL, styles, exstyles, NULL, userparam, true);
174 if (GATE_SUCCEEDED(ret))
175 {
176 GATE_UI_WINAPI_SET_DISPATCHER(&combobox->ctrl, &global_win32_combobox_dispatchers);
177 hwndCtrl = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
178 gate_ui_winapi_register_event(host, hwndParent, WM_COMMAND, &gate_ui_combobox_events, &combobox->ctrl);
179 }
180 } while (0);
181
182 return ret;
183 }
184
185 gate_result_t gate_ui_combobox_perform_action(gate_ui_combobox_t* combobox, gate_enumint_t action)
186 {
187 GATE_DEBUG_ASSERT(combobox != NULL);
188 switch (action)
189 {
190 case GATE_UI_ACTION_ACTIVATE:
191 {
192 gate_ui_ctrl_t* const ctrl = &combobox->ctrl;
193 ui_hwnd_t const hwnd = GATE_UI_WINAPI_GET_HWND(ctrl);
194 gate_intptr_t lresult = 0;
195 gate_ui_combobox_events(hwnd, &combobox->ctrl, WM_COMMAND,
196 (gate_intptr_t)MAKELONG(0, CBN_SELCHANGE), (gate_intptr_t)hwnd,
197 &lresult);
198 return GATE_RESULT_OK;
199 }
200 }
201 return GATE_RESULT_NOTSUPPORTED;
202 }
203
204
205 gate_size_t gate_ui_combobox_get_item_count(gate_ui_combobox_t* combobox)
206 {
207 gate_size_t ret = 0;
208 const ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
209 if (hwnd != UI_HWND_NULL)
210 {
211 const LRESULT result = SendMessage(hwnd, CB_GETCOUNT, 0, 0);
212 if (result != CB_ERR)
213 {
214 ret = (gate_size_t)result;
215 }
216 }
217 return ret;
218 }
219
220 gate_result_t gate_ui_combobox_insert_item(gate_ui_combobox_t* combobox, gate_size_t const* at_index,
221 gate_string_t const* text, void* itemparam)
222 {
223 gate_result_t ret = GATE_RESULT_FAILED;
224 const ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
225 if (hwnd != UI_HWND_NULL)
226 {
227 TCHAR text_buffer[4096];
228 LRESULT new_index;
229 if (text)
230 {
231 gate_win32_utf8_2_winstr(text->str, text->length, text_buffer, sizeof(text_buffer) / sizeof(text_buffer[0]));
232 }
233 else
234 {
235 text_buffer[0] = 0;
236 }
237 new_index = SendMessage((HWND)hwnd, CB_INSERTSTRING, (at_index ? (WPARAM)*at_index : (WPARAM)-1), (LPARAM)text_buffer);
238 if (CB_ERR == new_index)
239 {
240 ret = GATE_RESULT_FAILED;
241 }
242 else
243 {
244 SendMessage((HWND)hwnd, CB_SETITEMDATA, (WPARAM)new_index, (LPARAM)(gate_intptr_t)itemparam);
245 ret = GATE_RESULT_OK;
246 }
247 }
248 return ret;
249 }
250
251 gate_result_t gate_ui_combobox_remove_item(gate_ui_combobox_t* combobox, gate_size_t index)
252 {
253 gate_result_t ret = GATE_RESULT_FAILED;
254 const ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
255 if (hwnd != UI_HWND_NULL)
256 {
257 SendMessage((HWND)hwnd, CB_DELETESTRING, (WPARAM)index, 0);
258 ret = GATE_RESULT_OK;
259 }
260 return ret;
261 }
262
263 gate_result_t gate_ui_combobox_get_selected_item(gate_ui_combobox_t* combobox, gate_size_t* index)
264 {
265 gate_result_t ret = GATE_RESULT_FAILED;
266 const ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
267 if (hwnd != UI_HWND_NULL)
268 {
269 LRESULT sel_index = SendMessage((HWND)hwnd, CB_GETCURSEL, 0, 0);
270 if (sel_index == CB_ERR)
271 {
272 ret = GATE_RESULT_NOTAVAILABLE;
273 }
274 else
275 {
276 if (index)
277 {
278 *index = sel_index;
279 }
280 ret = GATE_RESULT_OK;
281 }
282 }
283 return ret;
284 }
285
286 gate_result_t gate_ui_combobox_set_selected_item(gate_ui_combobox_t* combobox, gate_size_t index)
287 {
288 gate_result_t ret = GATE_RESULT_FAILED;
289 const ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
290 if (hwnd != UI_HWND_NULL)
291 {
292 SendMessage((HWND)hwnd, CB_SETCURSEL, (WPARAM)index, 0);
293 ret = GATE_RESULT_OK;
294 }
295 return ret;
296 }
297
298 gate_result_t gate_ui_combobox_get_item_text(gate_ui_combobox_t* combobox, gate_size_t index, gate_string_t* text)
299 {
300 gate_result_t ret = GATE_RESULT_FAILED;
301 const ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
302 TCHAR buffer[4096];
303 TCHAR* ptr_buffer = &buffer[0];
304 LRESULT buf_len;
305
306 do
307 {
308 if (hwnd == UI_HWND_NULL)
309 {
310 ret = GATE_RESULT_FAILED;
311 break;
312 }
313
314 buf_len = SendMessage((HWND)hwnd, CB_GETLBTEXTLEN, (WPARAM)index, 0);
315 if (CB_ERR == buf_len)
316 {
317 ret = GATE_RESULT_FAILED;
318 break;
319 }
320
321 if (buf_len >= sizeof(buffer) / sizeof(buffer[0]))
322 {
323 ptr_buffer = (TCHAR*)gate_mem_alloc((buf_len + 2) * sizeof(TCHAR));
324 if (ptr_buffer == NULL)
325 {
326 ret = GATE_RESULT_OUTOFMEMORY;
327 break;
328 }
329 }
330 buf_len = SendMessage((HWND)hwnd, CB_GETLBTEXT, (WPARAM)index, (LPARAM)(gate_intptr_t)ptr_buffer);
331 if (buf_len > 0)
332 {
333 if (NULL == gate_win32_winstr_2_utf8_string(ptr_buffer, buf_len, text))
334 {
335 ret = GATE_RESULT_OUTOFMEMORY;
336 break;
337 }
338 }
339 else
340 {
341 gate_string_create_empty(text);
342 }
343 ret = GATE_RESULT_OK;
344
345 } while (0);
346
347 if ((ptr_buffer != &buffer[0]) && (ptr_buffer != NULL))
348 {
349 gate_mem_dealloc(ptr_buffer);
350 }
351
352 return ret;
353 }
354
355 void* gate_ui_combobox_get_item_param(gate_ui_combobox_t* combobox, gate_size_t index)
356 {
357 void* ret = NULL;
358 const ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
359 LRESULT data;
360 if (hwnd != UI_HWND_NULL)
361 {
362 data = SendMessage((HWND)hwnd, CB_GETITEMDATA, (WPARAM)index, 0);
363 ret = (void*)(gate_intptr_t)data;
364 }
365 return ret;
366 }
367
368 gate_result_t gate_ui_combobox_find_item_param(gate_ui_combobox_t* combobox, void* input_match_param,
369 gate_size_t* output_match_index, gate_size_t start_at)
370 {
371 gate_result_t ret = GATE_RESULT_FAILED;
372 const ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
373 LRESULT lresult, ndx;
374 LRESULT data;
375 if (hwnd != UI_HWND_NULL)
376 {
377 lresult = SendMessage((HWND)hwnd, CB_GETCOUNT, 0, 0);
378 if (lresult != CB_ERR)
379 {
380 ret = GATE_RESULT_NOMATCH;
381 for (ndx = (LRESULT)start_at; ndx < lresult; ++ndx)
382 {
383 data = SendMessage((HWND)hwnd, CB_GETITEMDATA, (WPARAM)ndx, 0);
384 if ((LRESULT)input_match_param == data)
385 {
386 if (output_match_index)
387 {
388 *output_match_index = (gate_size_t)ndx;
389 ret = GATE_RESULT_OK;
390 break;
391 }
392 }
393 }
394 }
395 }
396 return ret;
397 }
398
399
400 gate_result_t gate_ui_combobox_set_item_text(gate_ui_combobox_t* combobox, gate_size_t index, gate_string_t const* text)
401 {
402 gate_result_t ret = GATE_RESULT_FAILED;
403 void* item_data = gate_ui_combobox_get_item_param(combobox, index);
404 ret = gate_ui_combobox_insert_item(combobox, &index, text, item_data);
405 if (GATE_SUCCEEDED(ret))
406 {
407 gate_ui_combobox_remove_item(combobox, index + 1);
408 }
409 return ret;
410 }
411
412 gate_result_t gate_ui_combobox_clear(gate_ui_combobox_t* combobox)
413 {
414 gate_result_t ret = GATE_RESULT_FAILED;
415 const ui_hwnd_t hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
416 if (hwnd != UI_HWND_NULL)
417 {
418 SendMessage((HWND)hwnd, CB_RESETCONTENT, 0, 0);
419 ret = GATE_RESULT_OK;
420 }
421 return ret;
422 }
423
424 #endif /*GATE_UI_WINAPI*/
425
426
427 #if defined(GATE_UI_GTK)
428
429 #include "gate/debugging.h"
430 #include "gate/ui/gateui_gtk.h"
431
432 static void gate_ui_gtk_combobox_on_changed(GtkComboBox* combo, gpointer user_data)
433 {
434 // Get the active index
435 gate_ui_combobox_t* combobox = (gate_ui_combobox_t*)user_data;
436 gint active = gtk_combo_box_get_active(combo);
437
438 if ((active != -1) && (combobox != NULL) && (combobox->on_select != NULL))
439 {
440 combobox->on_select(&combobox->ctrl, (gate_size_t)active);
441 }
442 }
443
444 gate_result_t gate_ui_combobox_create(gate_ui_combobox_t* combobox, gate_ui_ctrl_t* parent,
445 gate_ui_position_t const* position,
446 gate_uint32_t flags, void* userparam)
447 {
448 gate_result_t ret = GATE_RESULT_OK;
449 GtkWidget* widget;
450 GtkListStore* liststore;
451 GtkCellRenderer* cellrenderer;
452 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
453
454 gate_mem_clear(combobox, sizeof(gate_ui_combobox_t));
455
456 liststore = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING);
457
458 widget = gtk_combo_box_new_with_model(GTK_TREE_MODEL(liststore));
459
460 cellrenderer = gtk_cell_renderer_text_new();
461 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), cellrenderer, TRUE);
462 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(widget), cellrenderer, "text", 1, NULL);
463
464 if (widget == NULL)
465 {
466 return GATE_RESULT_FAILED;
467 }
468
469 ret = gate_ui_gtk_ctrl_init(&combobox->ctrl, widget, host, userparam, parent,
470 NULL, false, false, position, &flags);
471
472 if(GATE_SUCCEEDED(ret))
473 {
474 g_signal_connect(widget, "changed", G_CALLBACK(gate_ui_gtk_combobox_on_changed), (gpointer)combobox);
475 }
476 return ret;
477 }
478
479 gate_result_t gate_ui_combobox_perform_action(gate_ui_combobox_t* combobox, gate_enumint_t action)
480 {
481 GtkWidget* widget;
482 GATE_DEBUG_ASSERT(combobox != NULL);
483 widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
484 switch (action)
485 {
486 case GATE_UI_ACTION_ACTIVATE:
487 gate_ui_gtk_combobox_on_changed((GtkComboBox*)widget, (gpointer)combobox);
488 return GATE_RESULT_OK;
489 }
490 return GATE_RESULT_NOTSUPPORTED;
491 }
492
493 static gate_bool_t gate_ui_combobox_resolve_index(GtkTreeModel* model, gate_size_t index, GtkTreeIter* found_iter)
494 {
495 gate_bool_t ret = false;
496 GtkTreeIter iter;
497
498 if (!gtk_tree_model_get_iter_first(model, &iter))
499 {
500 return false;
501 }
502
503 do
504 {
505 if (index == 0)
506 {
507 *found_iter = iter;
508 ret = true;
509 break;
510 }
511 --index;
512 } while (gtk_tree_model_iter_next(model, &iter));
513 return ret;
514 }
515
516 gate_size_t gate_ui_combobox_get_item_count(gate_ui_combobox_t* combobox)
517 {
518 gate_size_t ret = 0;
519 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
520 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
521 GtkTreeIter iter;
522
523 if (gtk_tree_model_get_iter_first(model, &iter))
524 {
525 do
526 {
527 ++ret;
528 } while (gtk_tree_model_iter_next(model, &iter));
529 }
530
531 return ret;
532 }
533
534 gate_result_t gate_ui_combobox_insert_item(gate_ui_combobox_t* combobox, gate_size_t const* atIndex,
535 gate_string_t const* text, void* itemparam)
536 {
537 gate_result_t ret = GATE_RESULT_FAILED;
538
539 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
540 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
541 GtkListStore* store = GTK_LIST_STORE(model);
542 GtkTreeIter at_iter;
543 GtkTreeIter new_iter;
544
545
546 if (atIndex != NULL)
547 {
548 if (gate_ui_combobox_resolve_index(model, *atIndex, &at_iter))
549 {
550 gtk_list_store_insert_before(store, &new_iter, &at_iter);
551 }
552 else
553 {
554 gtk_list_store_append(store, &new_iter);
555 }
556 }
557 else
558 {
559 gtk_list_store_append(store, &new_iter);
560 }
561
562 if (text != NULL)
563 {
564 char text_buffer[GATE_MAX_COPYBUFFER_LENGTH];
565 GATE_STRING_TO_BUFFER(text, text_buffer);
566 gtk_list_store_set(store, &new_iter,
567 0, itemparam,
568 1, text_buffer,
569 -1);
570 }
571 else
572 {
573 gtk_list_store_set(store, &new_iter,
574 0, itemparam,
575 -1);
576 }
577 ret = GATE_RESULT_OK;
578
579 return ret;
580 }
581
582 gate_result_t gate_ui_combobox_remove_item(gate_ui_combobox_t* combobox, gate_size_t index)
583 {
584 gate_result_t ret = GATE_RESULT_FAILED;
585
586 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
587 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
588 GtkTreeIter iter;
589
590 if (gate_ui_combobox_resolve_index(model, index, &iter))
591 {
592 GtkListStore* store = GTK_LIST_STORE(model);
593 gboolean iter_valid = gtk_list_store_remove(store, &iter);
594 ret = GATE_RESULT_OK;
595 }
596 else
597 {
598 ret = GATE_RESULT_NOTAVAILABLE;
599 }
600 return ret;
601 }
602
603 gate_result_t gate_ui_combobox_get_selected_item(gate_ui_combobox_t* combobox, gate_size_t* index)
604 {
605 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
606 gint ndx = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
607 if (ndx < 0)
608 {
609 return GATE_RESULT_NOTAVAILABLE;
610 }
611 else
612 {
613 *index = (gate_size_t)ndx;
614 return GATE_RESULT_OK;
615 }
616 }
617
618 gate_result_t gate_ui_combobox_set_selected_item(gate_ui_combobox_t* combobox, gate_size_t index)
619 {
620 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
621 gtk_combo_box_set_active(GTK_COMBO_BOX(widget), (gint)index);
622 return GATE_RESULT_OK;
623 }
624
625 gate_result_t gate_ui_combobox_get_item_text(gate_ui_combobox_t* combobox, gate_size_t index, gate_string_t* text)
626 {
627 gate_result_t ret = GATE_RESULT_FAILED;
628 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
629 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
630 GtkTreeIter iter;
631
632 if (gate_ui_combobox_resolve_index(model, index, &iter))
633 {
634 GValue value = GATE_INIT_EMPTY;
635 gchar const* ptr_text;
636
637 gtk_tree_model_get_value(model, &iter, 1, &value);
638 ptr_text = g_value_get_string(&value);
639 if (NULL == gate_string_create(text, ptr_text, gate_str_length(ptr_text)))
640 {
641 ret = GATE_RESULT_OUTOFMEMORY;
642 }
643 else
644 {
645 ret = GATE_RESULT_OK;
646 }
647 g_value_unset(&value);
648 }
649 else
650 {
651 ret = GATE_RESULT_NOTAVAILABLE;
652 }
653 return ret;
654 }
655
656 void* gate_ui_combobox_get_item_param(gate_ui_combobox_t* combobox, gate_size_t index)
657 {
658 void* ret = NULL;
659 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
660 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
661 GtkTreeIter iter;
662 GValue value = GATE_INIT_EMPTY;
663
664 if (gate_ui_combobox_resolve_index(model, index, &iter))
665 {
666 gtk_tree_model_get_value(model, &iter, 0, &value);
667 ret = g_value_get_pointer(&value);
668 g_value_unset(&value);
669 }
670 return ret;
671 }
672 gate_result_t gate_ui_combobox_find_item_param(gate_ui_combobox_t* combobox, void* input_match_param,
673 gate_size_t* output_match_index, gate_size_t start_at)
674 {
675 gate_result_t ret = GATE_RESULT_FAILED;
676 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
677 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
678 GtkTreeIter iter;
679 gate_size_t index;
680 GValue value = GATE_INIT_EMPTY;
681 gpointer data_ptr;
682 gate_bool_t param_found;
683
684 if (gtk_tree_model_get_iter_first(model, &iter))
685 {
686 ret = GATE_RESULT_NOMATCH;
687 index = 0;
688 do
689 {
690 if (index >= start_at)
691 {
692 gtk_tree_model_get_value(model, &iter, 0, &value);
693 data_ptr = g_value_get_pointer(&value);
694 param_found = (data_ptr == input_match_param);
695 g_value_unset(&value);
696 if (param_found)
697 {
698 if (output_match_index)
699 {
700 *output_match_index = index;
701 }
702 ret = GATE_RESULT_OK;
703 break;
704 }
705 }
706 ++index;
707 } while (gtk_tree_model_iter_next(model, &iter));
708 }
709 return ret;
710 }
711
712 gate_result_t gate_ui_combobox_set_item_text(gate_ui_combobox_t* combobox, gate_size_t index, gate_string_t const* text)
713 {
714 gate_result_t ret = GATE_RESULT_FAILED;
715 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
716 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
717 GtkListStore* store = GTK_LIST_STORE(model);
718 GtkTreeIter iter;
719 GValue value = GATE_INIT_EMPTY;
720 gchar text_buffer[GATE_MAX_COPYBUFFER_LENGTH];
721
722 if (gate_ui_combobox_resolve_index(model, index, &iter))
723 {
724 GATE_STRING_TO_BUFFER(text, text_buffer);
725 g_value_set_string(&value, text_buffer);
726 gtk_list_store_set_value(store, &iter, 1, &value);
727 g_value_unset(&value);
728 ret = GATE_RESULT_OK;
729 }
730 else
731 {
732 ret = GATE_RESULT_NOTAVAILABLE;
733 }
734 return ret;
735 }
736
737 gate_result_t gate_ui_combobox_clear(gate_ui_combobox_t* combobox)
738 {
739 gate_result_t ret = GATE_RESULT_OK;
740 GtkWidget* const widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
741 GtkTreeModel* const model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
742 if (model != NULL)
743 {
744 GtkListStore* store = GTK_LIST_STORE(model);
745 gtk_list_store_clear(store);
746 }
747 return ret;
748 }
749
750 #endif /* GATE_UI_GTK */
751
752
753
754 #if defined(GATE_UI_MOTIF)
755
756 #include "gate/ui/gateui_motif.h"
757 #include "gate/debugging.h"
758 #include <Xm/ComboBox.h>
759
760 1 gate_result_t gate_ui_combobox_create(gate_ui_combobox_t* combobox, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
761 gate_uint32_t flags, void* userparam)
762 {
763 Widget w;
764 1 Widget w_parent = NULL;
765 1 gate_result_t ret = GATE_RESULT_FAILED;
766 1 gate_ui_host_t* host = NULL;
767 Arg args[8];
768 1 unsigned args_count = 0;
769 1 gate_arraylist_t item_params = NULL;
770
771 do
772 {
773 1 w_parent = (Widget)GATE_UI_MOTIF_GET_CTRL_CONTAINER(parent);
774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == w_parent)
775 {
776 w_parent = (Widget)GATE_UI_MOTIF_GET_CTRL_WIDGET(parent);
777 }
778
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == w_parent)
779 {
780 ret = GATE_RESULT_INVALIDSTATE;
781 break;
782 }
783 1 host = GATE_UI_MOTIF_GET_CTRL_HOST(parent);
784
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == host)
785 {
786 ret = GATE_RESULT_INVALIDSTATE;
787 break;
788 }
789
790 1 XtSetArg(args[args_count], XmNcomboBoxType, XmDROP_DOWN_LIST); ++args_count;
791 1 XtSetArg(args[args_count], XmNvisibleItemCount, 12); ++args_count;
792 1 XtSetArg(args[args_count], XmNpositionMode, XmONE_BASED); ++args_count;
793 1 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
794 1 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
795
796 1 w = XmCreateComboBox(w_parent, NULL, args, args_count);
797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (w == NULL)
798 {
799 ret = GATE_RESULT_FAILED;
800 break;
801 }
802 1 XtManageChild(w);
803 1 ret = gate_ui_motif_ctrl_init(&combobox->ctrl, w, userparam, host, parent, NULL, position, &flags, NULL);
804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
805
806 1 item_params = gate_arraylist_create(sizeof(void*), NULL, 16, NULL, NULL);
807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (item_params == NULL)
808 {
809 gate_ui_motif_ctrl_destroy(&combobox->ctrl);
810 ret = GATE_RESULT_OUTOFMEMORY;
811 break;
812 }
813 1 GATE_UI_MOTIF_SET_CTRL_PRIVATE_ARG(&combobox->ctrl, item_params);
814 } while (0);
815 1 return ret;
816 }
817
818 1 gate_result_t gate_ui_combobox_perform_action(gate_ui_combobox_t* combobox, gate_enumint_t action)
819 {
820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(combobox != NULL);
821
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 switch (action)
822 {
823 1 case GATE_UI_ACTION_ACTIVATE:
824 {
825 1 gate_ui_ctrl_t* const ctrl = &combobox->ctrl;
826 /* TODO */
827 (void)ctrl;
828 1 return GATE_RESULT_OK;
829 }
830 }
831 return GATE_RESULT_NOTSUPPORTED;
832 }
833
834 15 gate_size_t gate_ui_combobox_get_item_count(gate_ui_combobox_t* combobox)
835 {
836 15 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
837 15 int cnt = 0;
838
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (w != NULL)
839 {
840 15 XtVaGetValues(w, XmNitemCount, &cnt, NULL);
841 }
842
843 15 return (gate_size_t)cnt;
844 }
845
846 3 gate_result_t gate_ui_combobox_insert_item(gate_ui_combobox_t* combobox, gate_size_t const* at_index, gate_string_t const* text, void* itemparam)
847 {
848 3 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
849 3 gate_result_t ret = GATE_RESULT_FAILED;
850 3 XmString xstr = NULL;
851 3 int pos = 0; /* default pos => add at end */
852 3 gate_arraylist_t item_params = NULL;
853 3 gate_size_t cnt = 0;
854 3 void* new_item = NULL;
855
856 3 item_params = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&combobox->ctrl);
857
858 3 cnt = gate_ui_combobox_get_item_count(combobox);
859
860
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (at_index)
861 {
862 if (*at_index >= cnt)
863 {
864 pos = 0;
865 }
866 else
867 {
868 pos = (int)(*at_index + 1);
869 }
870 }
871 else
872 {
873 3 pos = 0;
874 }
875
876 do
877 {
878 3 xstr = gate_ui_motif_create_string(text);
879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (xstr == NULL)
880 {
881 ret = GATE_RESULT_OUTOFMEMORY;
882 break;
883 }
884
885
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (pos == 0)
886 {
887 3 new_item = gate_arraylist_add(item_params, &itemparam);
888 }
889 else
890 {
891 new_item = gate_arraylist_insert(item_params, (gate_size_t)(pos - 1), &itemparam, 1);
892 }
893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (new_item == NULL)
894 {
895 ret = GATE_RESULT_OUTOFMEMORY;
896 break;
897 }
898
899 3 XmComboBoxAddItem(w, xstr, pos, False);
900 3 ret = GATE_RESULT_OK;
901 } while (0);
902
903
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (xstr != NULL)
904 {
905 3 XmStringFree(xstr);
906 }
907 3 return ret;
908 }
909
910 1 gate_result_t gate_ui_combobox_remove_item(gate_ui_combobox_t* combobox, gate_size_t index)
911 {
912 1 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
913 1 const gate_arraylist_t item_params = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&combobox->ctrl);
914 1 const gate_size_t cnt = gate_ui_combobox_get_item_count(combobox);
915 1 int pos = (int)(index + 1);
916
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (index < cnt)
917 {
918 1 XmComboBoxDeletePos(w, pos);
919 1 gate_arraylist_remove(item_params, index, 1);
920 1 return GATE_RESULT_OK;
921 }
922 else
923 {
924 return GATE_RESULT_OUTOFBOUNDS;
925 }
926 }
927
928 2 gate_result_t gate_ui_combobox_get_selected_item(gate_ui_combobox_t* combobox, gate_size_t* index)
929 {
930 2 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
931 2 int pos = 0;
932 2 XtVaGetValues(w, XmNselectedPosition, &pos, NULL);
933
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (pos > 0)
934 {
935
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (index != NULL)
936 {
937 2 *index = (gate_size_t)(pos - 1);
938 }
939 2 return GATE_RESULT_OK;
940 }
941 else
942 {
943 if (index != NULL)
944 {
945 *index = GATE_UI_COMBOBOX_INVALID_INDEX;
946 }
947 return GATE_RESULT_OK;
948 }
949 return GATE_RESULT_FAILED;
950 }
951
952 3 gate_result_t gate_ui_combobox_set_selected_item(gate_ui_combobox_t* combobox, gate_size_t index)
953 {
954 3 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
955 3 const int pos = (int)index + 1;
956
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (index >= gate_ui_combobox_get_item_count(combobox))
957 {
958 return GATE_RESULT_OUTOFBOUNDS;
959 }
960 3 XtVaSetValues(w, XmNselectedPosition, pos, NULL);
961 3 return GATE_RESULT_OK;
962 }
963
964 2 gate_result_t gate_ui_combobox_get_item_text(gate_ui_combobox_t* combobox, gate_size_t index, gate_string_t* text)
965 {
966 2 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
967 2 XmStringTable strings = NULL;
968
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (index >= gate_ui_combobox_get_item_count(combobox))
969 {
970 return GATE_RESULT_OUTOFBOUNDS;
971 }
972 2 XtVaGetValues(w, XmNitems, &strings, NULL);
973
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (strings)
974 {
975 2 return gate_ui_motif_convert_string(strings[index], text);
976 }
977 return GATE_RESULT_FAILED;
978 }
979
980 3 void* gate_ui_combobox_get_item_param(gate_ui_combobox_t* combobox, gate_size_t index)
981 {
982 3 const gate_arraylist_t item_params = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&combobox->ctrl);
983 3 void** ptr_param = (void**)gate_arraylist_get(item_params, index);
984
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (ptr_param)
985 {
986 3 return *ptr_param;
987 }
988 return NULL;
989 }
990
991 1 gate_result_t gate_ui_combobox_find_item_param(gate_ui_combobox_t* combobox, void* match_param, gate_size_t* match_index, gate_size_t start_at)
992 {
993 1 const gate_arraylist_t item_params = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&combobox->ctrl);
994 1 const gate_size_t cnt = gate_arraylist_length(item_params);
995 1 gate_size_t ndx = start_at;
996 1 void** ptr_param = NULL;
997
998
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 while (ndx < cnt)
999 {
1000 1 ptr_param = (void**)gate_arraylist_get(item_params, ndx);
1001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!ptr_param) break;
1002
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (match_param == *ptr_param)
1003 {
1004
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (match_index)
1005 {
1006 1 *match_index = ndx;
1007 }
1008 1 return GATE_RESULT_OK;
1009 }
1010 ++ndx;
1011 }
1012 return GATE_RESULT_NOMATCH;
1013 }
1014
1015 1 gate_result_t gate_ui_combobox_set_item_text(gate_ui_combobox_t* combobox, gate_size_t index, gate_string_t const* text)
1016 {
1017 1 gate_result_t ret = GATE_RESULT_FAILED;
1018 1 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
1019 1 gate_size_t cnt = gate_ui_combobox_get_item_count(combobox);
1020 1 XmString xstr = NULL;
1021
1022 do
1023 {
1024
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (index >= cnt)
1025 {
1026 ret = GATE_RESULT_OUTOFBOUNDS;
1027 break;
1028 }
1029 1 xstr = gate_ui_motif_create_string(text);
1030
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!xstr)
1031 {
1032 ret = GATE_RESULT_OUTOFMEMORY;
1033 break;
1034 }
1035 1 XmComboBoxAddItem(w, xstr, (int)index + 1, False);
1036 1 XmComboBoxDeletePos(w, (int)index + 2);
1037 1 ret = GATE_RESULT_OK;
1038 } while (0);
1039
1040
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (xstr != NULL)
1041 {
1042 1 XmStringFree(xstr);
1043 }
1044 1 return ret;
1045 }
1046
1047 1 gate_result_t gate_ui_combobox_clear(gate_ui_combobox_t* combobox)
1048 {
1049 1 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
1050 1 gate_arraylist_t item_params = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&combobox->ctrl);
1051 1 gate_size_t cnt = gate_ui_combobox_get_item_count(combobox);
1052
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 while (cnt > 0)
1053 {
1054 XmComboBoxDeletePos(w, (int)cnt);
1055 --cnt;
1056 }
1057 1 gate_arraylist_clear(item_params);
1058 1 return GATE_RESULT_OK;
1059 }
1060
1061 #endif /* GATE_UI_MOTIF */
1062