GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/comboboxes.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 120 162 74.1%
Functions: 11 12 91.7%
Branches: 28 62 45.2%

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/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 gate_ui_combobox_events(void* 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 != NULL))
42 {
43 HWND hwndCtrl = GATE_UI_WINAPI_GET_HWND(ctrl);
44 gate_ui_host_t* host = GATE_UI_WINAPI_GET_HOST(ctrl);
45 if (hwndCtrl)
46 {
47 switch (msg)
48 {
49 case WM_COMMAND:
50 {
51 if (hwndCtrl == (HWND)lParam)
52 {
53 gate_ui_combobox_t* combobox = (gate_ui_combobox_t*)ctrl;
54 switch (HIWORD(wParam))
55 {
56 case CBN_SELCHANGE:
57 {
58 LRESULT sel_index = SendMessage(hwndCtrl, CB_GETCURSEL, 0, 0);
59 if ((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 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 HWND 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, (void*)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, (void*)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 HWND 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 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
209 if (hwnd)
210 {
211 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 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
225 if (hwnd)
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, 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, 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 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
255 if (hwnd)
256 {
257 SendMessage(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 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
267 if (hwnd)
268 {
269 LRESULT sel_index = SendMessage(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 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
290 if (hwnd)
291 {
292 SendMessage(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 HWND 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)
309 {
310 ret = GATE_RESULT_FAILED;
311 break;
312 }
313
314 buf_len = SendMessage(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, 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 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
359 LRESULT data;
360 if (hwnd)
361 {
362 data = SendMessage(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 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
373 LRESULT lresult, ndx;
374 LRESULT data;
375 if (hwnd)
376 {
377 lresult = SendMessage(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, 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 HWND hwnd = GATE_UI_WINAPI_GET_HWND(&combobox->ctrl);
416 if (hwnd)
417 {
418 SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
419 ret = GATE_RESULT_OK;
420 }
421 return ret;
422 }
423
424
425 #endif /*GATE_UI_WINAPI*/
426
427
428 #if defined(GATE_UI_GTK)
429
430 #include "gate/debugging.h"
431 #include "gate/ui/gateui_gtk.h"
432
433 static void gate_ui_gtk_combobox_on_changed(GtkComboBox* combo, gpointer user_data)
434 {
435 // Get the active index
436 gate_ui_combobox_t* combobox = (gate_ui_combobox_t*)user_data;
437 gint active = gtk_combo_box_get_active(combo);
438
439 if ((active != -1) && (combobox != NULL) && (combobox->on_select != NULL))
440 {
441 combobox->on_select(&combobox->ctrl, (gate_size_t)active);
442 }
443 }
444
445 gate_result_t gate_ui_combobox_create(gate_ui_combobox_t* combobox, gate_ui_ctrl_t* parent,
446 gate_ui_position_t const* position,
447 gate_uint32_t flags, void* userparam)
448 {
449 gate_result_t ret = GATE_RESULT_OK;
450 GtkWidget* widget;
451 GtkListStore* liststore;
452 GtkCellRenderer* cellrenderer;
453 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(parent);
454
455 gate_mem_clear(combobox, sizeof(gate_ui_combobox_t));
456
457 liststore = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING);
458
459 widget = gtk_combo_box_new_with_model(GTK_TREE_MODEL(liststore));
460
461 cellrenderer = gtk_cell_renderer_text_new();
462 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), cellrenderer, TRUE);
463 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(widget), cellrenderer, "text", 1, NULL);
464
465 if (widget == NULL)
466 {
467 return GATE_RESULT_FAILED;
468 }
469
470 ret = gate_ui_gtk_ctrl_init(&combobox->ctrl, widget, host, userparam, parent,
471 NULL, false, false, position, &flags);
472
473 if(GATE_SUCCEEDED(ret))
474 {
475 g_signal_connect(widget, "changed", G_CALLBACK(gate_ui_gtk_combobox_on_changed), (gpointer)combobox);
476 }
477 return ret;
478 }
479
480 gate_result_t gate_ui_combobox_perform_action(gate_ui_combobox_t* combobox, gate_enumint_t action)
481 {
482 GtkWidget* widget;
483 GATE_DEBUG_ASSERT(combobox != NULL);
484 widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
485 switch (action)
486 {
487 case GATE_UI_ACTION_ACTIVATE:
488 gate_ui_gtk_combobox_on_changed((GtkComboBox*)widget, (gpointer)combobox);
489 return GATE_RESULT_OK;
490 }
491 return GATE_RESULT_NOTSUPPORTED;
492 }
493
494 static gate_bool_t gate_ui_combobox_resolve_index(GtkTreeModel* model, gate_size_t index, GtkTreeIter* found_iter)
495 {
496 gate_bool_t ret = false;
497 GtkTreeIter iter;
498
499 if (!gtk_tree_model_get_iter_first(model, &iter))
500 {
501 return false;
502 }
503
504 do
505 {
506 if (index == 0)
507 {
508 *found_iter = iter;
509 ret = true;
510 break;
511 }
512 --index;
513 } while (gtk_tree_model_iter_next(model, &iter));
514 return ret;
515 }
516
517 gate_size_t gate_ui_combobox_get_item_count(gate_ui_combobox_t* combobox)
518 {
519 gate_size_t ret = 0;
520 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
521 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
522 GtkTreeIter iter;
523
524 if (gtk_tree_model_get_iter_first(model, &iter))
525 {
526 do
527 {
528 ++ret;
529 } while (gtk_tree_model_iter_next(model, &iter));
530 }
531
532 return ret;
533 }
534
535 gate_result_t gate_ui_combobox_insert_item(gate_ui_combobox_t* combobox, gate_size_t const* atIndex,
536 gate_string_t const* text, void* itemparam)
537 {
538 gate_result_t ret = GATE_RESULT_FAILED;
539
540 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
541 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
542 GtkListStore* store = GTK_LIST_STORE(model);
543 GtkTreeIter at_iter;
544 GtkTreeIter new_iter;
545
546
547 if (atIndex != NULL)
548 {
549 if (gate_ui_combobox_resolve_index(model, *atIndex, &at_iter))
550 {
551 gtk_list_store_insert_before(store, &new_iter, &at_iter);
552 }
553 else
554 {
555 gtk_list_store_append(store, &new_iter);
556 }
557 }
558 else
559 {
560 gtk_list_store_append(store, &new_iter);
561 }
562
563 if (text != NULL)
564 {
565 char text_buffer[GATE_MAX_COPYBUFFER_LENGTH];
566 GATE_STRING_TO_BUFFER(text, text_buffer);
567 gtk_list_store_set(store, &new_iter,
568 0, itemparam,
569 1, text_buffer,
570 -1);
571 }
572 else
573 {
574 gtk_list_store_set(store, &new_iter,
575 0, itemparam,
576 -1);
577 }
578 ret = GATE_RESULT_OK;
579
580 return ret;
581 }
582
583 gate_result_t gate_ui_combobox_remove_item(gate_ui_combobox_t* combobox, gate_size_t index)
584 {
585 gate_result_t ret = GATE_RESULT_FAILED;
586
587 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
588 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
589 GtkTreeIter iter;
590
591 if (gate_ui_combobox_resolve_index(model, index, &iter))
592 {
593 GtkListStore* store = GTK_LIST_STORE(model);
594 gboolean iter_valid = gtk_list_store_remove(store, &iter);
595 ret = GATE_RESULT_OK;
596 }
597 else
598 {
599 ret = GATE_RESULT_NOTAVAILABLE;
600 }
601 return ret;
602 }
603
604 gate_result_t gate_ui_combobox_get_selected_item(gate_ui_combobox_t* combobox, gate_size_t* index)
605 {
606 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
607 gint ndx = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
608 if (ndx < 0)
609 {
610 return GATE_RESULT_NOTAVAILABLE;
611 }
612 else
613 {
614 *index = (gate_size_t)ndx;
615 return GATE_RESULT_OK;
616 }
617 }
618
619 gate_result_t gate_ui_combobox_set_selected_item(gate_ui_combobox_t* combobox, gate_size_t index)
620 {
621 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
622 gtk_combo_box_set_active(GTK_COMBO_BOX(widget), (gint)index);
623 return GATE_RESULT_OK;
624 }
625
626 gate_result_t gate_ui_combobox_get_item_text(gate_ui_combobox_t* combobox, gate_size_t index, gate_string_t* text)
627 {
628 gate_result_t ret = GATE_RESULT_FAILED;
629 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
630 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
631 GtkTreeIter iter;
632
633 if (gate_ui_combobox_resolve_index(model, index, &iter))
634 {
635 GValue value = GATE_INIT_EMPTY;
636 gchar const* ptr_text;
637
638 gtk_tree_model_get_value(model, &iter, 1, &value);
639 ptr_text = g_value_get_string(&value);
640 if (NULL == gate_string_create(text, ptr_text, gate_str_length(ptr_text)))
641 {
642 ret = GATE_RESULT_OUTOFMEMORY;
643 }
644 else
645 {
646 ret = GATE_RESULT_OK;
647 }
648 g_value_unset(&value);
649 }
650 else
651 {
652 ret = GATE_RESULT_NOTAVAILABLE;
653 }
654 return ret;
655 }
656
657 void* gate_ui_combobox_get_item_param(gate_ui_combobox_t* combobox, gate_size_t index)
658 {
659 void* ret = NULL;
660 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
661 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
662 GtkTreeIter iter;
663 GValue value = GATE_INIT_EMPTY;
664
665 if (gate_ui_combobox_resolve_index(model, index, &iter))
666 {
667 gtk_tree_model_get_value(model, &iter, 0, &value);
668 ret = g_value_get_pointer(&value);
669 g_value_unset(&value);
670 }
671 return ret;
672 }
673 gate_result_t gate_ui_combobox_find_item_param(gate_ui_combobox_t* combobox, void* input_match_param,
674 gate_size_t* output_match_index, gate_size_t start_at)
675 {
676 gate_result_t ret = GATE_RESULT_FAILED;
677 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
678 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
679 GtkTreeIter iter;
680 gate_size_t index;
681 GValue value = GATE_INIT_EMPTY;
682 gpointer data_ptr;
683 gate_bool_t param_found;
684
685 if (gtk_tree_model_get_iter_first(model, &iter))
686 {
687 ret = GATE_RESULT_NOMATCH;
688 index = 0;
689 do
690 {
691 if (index >= start_at)
692 {
693 gtk_tree_model_get_value(model, &iter, 0, &value);
694 data_ptr = g_value_get_pointer(&value);
695 param_found = (data_ptr == input_match_param);
696 g_value_unset(&value);
697 if (param_found)
698 {
699 if (output_match_index)
700 {
701 *output_match_index = index;
702 }
703 ret = GATE_RESULT_OK;
704 break;
705 }
706 }
707 ++index;
708 } while (gtk_tree_model_iter_next(model, &iter));
709 }
710 return ret;
711 }
712
713 gate_result_t gate_ui_combobox_set_item_text(gate_ui_combobox_t* combobox, gate_size_t index, gate_string_t const* text)
714 {
715 gate_result_t ret = GATE_RESULT_FAILED;
716 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
717 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
718 GtkListStore* store = GTK_LIST_STORE(model);
719 GtkTreeIter iter;
720 GValue value = GATE_INIT_EMPTY;
721 gchar text_buffer[GATE_MAX_COPYBUFFER_LENGTH];
722
723 if (gate_ui_combobox_resolve_index(model, index, &iter))
724 {
725 GATE_STRING_TO_BUFFER(text, text_buffer);
726 g_value_set_string(&value, text_buffer);
727 gtk_list_store_set_value(store, &iter, 1, &value);
728 g_value_unset(&value);
729 ret = GATE_RESULT_OK;
730 }
731 else
732 {
733 ret = GATE_RESULT_NOTAVAILABLE;
734 }
735 return ret;
736 }
737
738 gate_result_t gate_ui_combobox_clear(gate_ui_combobox_t* combobox)
739 {
740 gate_result_t ret = GATE_RESULT_FAILED;
741 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(&combobox->ctrl);
742 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
743 GtkListStore* store = GTK_LIST_STORE(model);
744 gtk_list_store_clear(store);
745 ret = GATE_RESULT_OK;
746 return ret;
747 }
748
749 #endif /* GATE_UI_GTK */
750
751
752
753 #if defined(GATE_UI_MOTIF)
754
755 #include "gate/ui/gateui_motif.h"
756 #include "gate/debugging.h"
757 #include <Xm/ComboBox.h>
758
759 1 gate_result_t gate_ui_combobox_create(gate_ui_combobox_t* combobox, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
760 gate_uint32_t flags, void* userparam)
761 {
762 Widget w;
763 1 Widget w_parent = NULL;
764 1 gate_result_t ret = GATE_RESULT_FAILED;
765 1 gate_ui_host_t* host = NULL;
766 Arg args[8];
767 1 unsigned args_count = 0;
768 1 gate_arraylist_t item_params = NULL;
769
770 do
771 {
772 1 w_parent = (Widget)GATE_UI_MOTIF_GET_CTRL_CONTAINER(parent);
773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == w_parent)
774 {
775 w_parent = (Widget)GATE_UI_MOTIF_GET_CTRL_WIDGET(parent);
776 }
777
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == w_parent)
778 {
779 ret = GATE_RESULT_INVALIDSTATE;
780 break;
781 }
782 1 host = GATE_UI_MOTIF_GET_CTRL_HOST(parent);
783
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == host)
784 {
785 ret = GATE_RESULT_INVALIDSTATE;
786 break;
787 }
788
789 1 XtSetArg(args[args_count], XmNcomboBoxType, XmDROP_DOWN_LIST); ++args_count;
790 1 XtSetArg(args[args_count], XmNvisibleItemCount, 12); ++args_count;
791 1 XtSetArg(args[args_count], XmNpositionMode, XmONE_BASED); ++args_count;
792 1 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
793 1 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
794
795 1 w = XmCreateComboBox(w_parent, NULL, args, args_count);
796
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (w == NULL)
797 {
798 ret = GATE_RESULT_FAILED;
799 break;
800 }
801 1 XtManageChild(w);
802 1 ret = gate_ui_motif_ctrl_init(&combobox->ctrl, w, userparam, host, parent, NULL, position, &flags, NULL);
803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
804
805 1 item_params = gate_arraylist_create(sizeof(void*), NULL, 16, NULL, NULL);
806
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (item_params == NULL)
807 {
808 gate_ui_motif_ctrl_destroy(&combobox->ctrl);
809 ret = GATE_RESULT_OUTOFMEMORY;
810 break;
811 }
812 1 GATE_UI_MOTIF_SET_CTRL_PRIVATE_ARG(&combobox->ctrl, item_params);
813 } while (0);
814 1 return ret;
815 }
816
817 1 gate_result_t gate_ui_combobox_perform_action(gate_ui_combobox_t* combobox, gate_enumint_t action)
818 {
819
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(combobox != NULL);
820
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 switch (action)
821 {
822 1 case GATE_UI_ACTION_ACTIVATE:
823 {
824 1 gate_ui_ctrl_t* const ctrl = &combobox->ctrl;
825 /* TODO */
826 1 return GATE_RESULT_OK;
827 }
828 }
829 return GATE_RESULT_NOTSUPPORTED;
830 }
831
832 14 gate_size_t gate_ui_combobox_get_item_count(gate_ui_combobox_t* combobox)
833 {
834 14 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
835 14 int cnt = 0;
836
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (w != NULL)
837 {
838 14 XtVaGetValues(w, XmNitemCount, &cnt, NULL);
839 }
840
841 14 return (gate_size_t)cnt;
842 }
843
844 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)
845 {
846 3 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
847 3 gate_result_t ret = GATE_RESULT_FAILED;
848 3 XmString xstr = NULL;
849 3 int pos = 0; /* default pos => add at end */
850 3 gate_arraylist_t item_params = NULL;
851 3 gate_size_t cnt = 0;
852 3 void* new_item = NULL;
853
854 3 item_params = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&combobox->ctrl);
855
856 3 cnt = gate_ui_combobox_get_item_count(combobox);
857
858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (at_index)
859 {
860 if (*at_index >= cnt)
861 {
862 pos = 0;
863 }
864 else
865 {
866 pos = (int)(*at_index + 1);
867 }
868 }
869 else
870 {
871 3 pos = 0;
872 }
873
874 do
875 {
876 3 xstr = gate_ui_motif_create_string(text);
877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (xstr == NULL)
878 {
879 ret = GATE_RESULT_OUTOFMEMORY;
880 break;
881 }
882
883
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (pos == 0)
884 {
885 3 new_item = gate_arraylist_add(item_params, &itemparam);
886 }
887 else
888 {
889 new_item = gate_arraylist_insert(item_params, (gate_size_t)(pos - 1), &itemparam, 1);
890 }
891
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (new_item == NULL)
892 {
893 ret = GATE_RESULT_OUTOFMEMORY;
894 break;
895 }
896
897 3 XmComboBoxAddItem(w, xstr, pos, False);
898 3 ret = GATE_RESULT_OK;
899 } while (0);
900
901
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (xstr != NULL)
902 {
903 3 XmStringFree(xstr);
904 }
905 3 return ret;
906 }
907
908 1 gate_result_t gate_ui_combobox_remove_item(gate_ui_combobox_t* combobox, gate_size_t index)
909 {
910 1 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
911 1 const gate_arraylist_t item_params = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&combobox->ctrl);
912 1 const gate_size_t cnt = gate_ui_combobox_get_item_count(combobox);
913 1 int pos = (int)(index + 1);
914
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (index < cnt)
915 {
916 1 XmComboBoxDeletePos(w, pos);
917 1 gate_arraylist_remove(item_params, index, 1);
918 1 return GATE_RESULT_OK;
919 }
920 else
921 {
922 return GATE_RESULT_OUTOFBOUNDS;
923 }
924 }
925
926 1 gate_result_t gate_ui_combobox_get_selected_item(gate_ui_combobox_t* combobox, gate_size_t* index)
927 {
928 1 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
929 1 int pos = 0;
930 1 XtVaGetValues(w, XmNselectedPosition, &pos, NULL);
931
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pos > 0)
932 {
933
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (index != NULL)
934 {
935 1 *index = (gate_size_t)(pos - 1);
936 }
937 1 return GATE_RESULT_OK;
938 }
939 else
940 {
941 if (index != NULL)
942 {
943 *index = GATE_UI_COMBOBOX_INVALID_INDEX;
944 }
945 return GATE_RESULT_OK;
946 }
947 return GATE_RESULT_FAILED;
948 }
949
950 3 gate_result_t gate_ui_combobox_set_selected_item(gate_ui_combobox_t* combobox, gate_size_t index)
951 {
952 3 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
953 3 const int pos = (int)index + 1;
954
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (index >= gate_ui_combobox_get_item_count(combobox))
955 {
956 return GATE_RESULT_OUTOFBOUNDS;
957 }
958 3 XtVaSetValues(w, XmNselectedPosition, pos, NULL);
959 3 return GATE_RESULT_OK;
960 }
961
962 2 gate_result_t gate_ui_combobox_get_item_text(gate_ui_combobox_t* combobox, gate_size_t index, gate_string_t* text)
963 {
964 2 const Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
965 2 XmStringTable strings = NULL;
966
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (index >= gate_ui_combobox_get_item_count(combobox))
967 {
968 return GATE_RESULT_OUTOFBOUNDS;
969 }
970 2 XtVaGetValues(w, XmNitems, &strings, NULL);
971
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (strings)
972 {
973 2 return gate_ui_motif_convert_string(strings[index], text);
974 }
975 return GATE_RESULT_FAILED;
976 }
977
978 2 void* gate_ui_combobox_get_item_param(gate_ui_combobox_t* combobox, gate_size_t index)
979 {
980 2 const gate_arraylist_t item_params = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&combobox->ctrl);
981 2 void** ptr_param = (void**)gate_arraylist_get(item_params, index);
982
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (ptr_param)
983 {
984 2 return *ptr_param;
985 }
986 return NULL;
987 }
988
989 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)
990 {
991 1 const gate_arraylist_t item_params = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&combobox->ctrl);
992 1 const gate_size_t cnt = gate_arraylist_length(item_params);
993 1 gate_size_t ndx = start_at;
994 1 void** ptr_param = NULL;
995
996
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 while (ndx < cnt)
997 {
998 1 ptr_param = (void**)gate_arraylist_get(item_params, ndx);
999
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!ptr_param) break;
1000
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (match_param == *ptr_param)
1001 {
1002
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (match_index)
1003 {
1004 1 *match_index = ndx;
1005 }
1006 1 return GATE_RESULT_OK;
1007 }
1008 ++ndx;
1009 }
1010 return GATE_RESULT_NOMATCH;
1011 }
1012
1013 1 gate_result_t gate_ui_combobox_set_item_text(gate_ui_combobox_t* combobox, gate_size_t index, gate_string_t const* text)
1014 {
1015 1 gate_result_t ret = GATE_RESULT_FAILED;
1016 1 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
1017 1 gate_size_t cnt = gate_ui_combobox_get_item_count(combobox);
1018 1 XmString xstr = NULL;
1019
1020 do
1021 {
1022
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (index >= cnt)
1023 {
1024 ret = GATE_RESULT_OUTOFBOUNDS;
1025 break;
1026 }
1027 1 xstr = gate_ui_motif_create_string(text);
1028
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!xstr)
1029 {
1030 ret = GATE_RESULT_OUTOFMEMORY;
1031 break;
1032 }
1033 1 XmComboBoxAddItem(w, xstr, (int)index + 1, False);
1034 1 XmComboBoxDeletePos(w, (int)index + 2);
1035 1 ret = GATE_RESULT_OK;
1036 } while (0);
1037
1038
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (xstr != NULL)
1039 {
1040 1 XmStringFree(xstr);
1041 }
1042 1 return ret;
1043 }
1044
1045 gate_result_t gate_ui_combobox_clear(gate_ui_combobox_t* combobox)
1046 {
1047 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(&combobox->ctrl);
1048 gate_arraylist_t item_params = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(&combobox->ctrl);
1049 gate_size_t cnt = gate_ui_combobox_get_item_count(combobox);
1050 while (cnt > 0)
1051 {
1052 XmComboBoxDeletePos(w, (int)cnt);
1053 --cnt;
1054 }
1055 gate_arraylist_clear(item_params);
1056 return GATE_RESULT_OK;
1057 }
1058
1059 #endif /* GATE_UI_MOTIF */
1060