GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/listviews_motif.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 830 0.0%
Functions: 0 61 0.0%
Branches: 0 400 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/listviews.h"
30 #include "gate/results.h"
31 #include "gate/debugging.h"
32
33
34 #if defined(GATE_UI_MOTIF)
35
36 #include "gate/ui/gateui_motif.h"
37 #include <Xm/List.h>
38 #include <Xm/Container.h>
39 #include <Xm/Label.h>
40 #include <Xm/ScrolledW.h>
41 #include <Xm/IconG.h>
42 #include <Xm/ScrollBar.h>
43
44 static gate_size_t gate_ui_listbox_widget_get_item_count(Widget w)
45 {
46 int list_count = 0;
47 XtVaGetValues(w, XmNitemCount, &list_count, NULL);
48 return (gate_size_t)list_count;
49 }
50
51 gate_result_t gate_ui_listbox_create(gate_ui_listbox_t* lstbox, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
52 gate_uint32_t flags, void* userparam)
53 {
54 gate_result_t ret = GATE_RESULT_FAILED;
55 Widget parent_widget = NULL;
56 Widget w;
57 Widget w_list;
58 Arg args[8];
59 Cardinal args_count;
60
61 do
62 {
63 if (!lstbox || !parent)
64 {
65 ret = GATE_RESULT_INVALIDARG;
66 break;
67 }
68
69 parent_widget = GATE_UI_MOTIF_GET_CTRL_CONTAINER(parent);
70 if (!parent_widget)
71 {
72 parent_widget = GATE_UI_MOTIF_GET_CTRL_WIDGET(parent);
73 }
74 args_count = 0;
75 XtSetArg(args[args_count], XmNscrollingPolicy, XmAPPLICATION_DEFINED); ++args_count;
76 XtSetArg(args[args_count], XmNvisualPolicy, XmVARIABLE); ++args_count;
77 XtSetArg(args[args_count], XmNscrollBarDisplayPolicy, XmSTATIC); ++args_count;
78 XtSetArg(args[args_count], XmNshadowThickness, 0); ++args_count;
79 XtSetArg(args[args_count], XmNhighlightThickness, 0); ++args_count;
80
81 w = XmCreateScrolledWindow(parent_widget, NULL, args, args_count);
82 if (!w)
83 {
84 ret = GATE_RESULT_OUTOFRESOURCES;
85 break;
86 }
87
88 args_count = 0;
89 XtSetArg(args[args_count], XmNautomaticSelection, XmBROWSE_SELECT); ++args_count;
90 //XtSetArg(args[args_count], XmNscrollBarDisplayPolicy, XmAS_NEEDED); ++args_count;
91 XtSetArg(args[args_count], XmNselectionPolicy, XmSINGLE_SELECT); ++args_count;
92 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
93 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
94
95 w_list = XmCreateList(w, NULL, args, args_count);
96 if (!w_list)
97 {
98 XtDestroyWidget(w);
99 ret = GATE_RESULT_OUTOFRESOURCES;
100 break;
101 }
102
103 ret = gate_ui_motif_ctrl_init(&lstbox->ctrl, w, userparam, NULL, parent, w_list, position, &flags, NULL);
104 GATE_BREAK_IF_FAILED(ret);
105
106 XtManageChild(w);
107 XtManageChild(w_list);
108
109 } while (0);
110
111 return ret;
112 }
113
114 gate_result_t gate_ui_listbox_insert_item(gate_ui_listbox_t* lstbox, gate_size_t const* at_index, gate_string_t const* text, void* itemparam)
115 {
116 gate_result_t ret = GATE_RESULT_FAILED;
117 Widget w = NULL;
118 XmString str = NULL;
119 gate_size_t item_count;
120 int insert_pos;
121
122 do
123 {
124 GATE_UI_MOTIF_EXTRACT_CONTAINER_OR_RETURN_ERROR(lstbox, w);
125
126 str = gate_ui_motif_create_string(text);
127 if (!str)
128 {
129 ret = GATE_RESULT_OUTOFMEMORY;
130 break;
131 }
132
133 /* insert at end */
134 insert_pos = 0;
135
136 if (at_index)
137 {
138 item_count = gate_ui_listbox_widget_get_item_count(w);
139 if (*at_index < item_count)
140 {
141 /* insert at position, counting starts at "1" */
142 insert_pos = (*at_index) + 1;
143 }
144 }
145 XmListAddItem(w, str, insert_pos);
146 ret = GATE_RESULT_OK;
147
148 } while (0);
149
150 if (str)
151 {
152 XmStringFree(str);
153 }
154
155 return ret;
156 }
157
158 gate_result_t gate_ui_listbox_remove_item(gate_ui_listbox_t* lstbox, gate_size_t index)
159 {
160 Widget w = NULL;
161 GATE_UI_MOTIF_EXTRACT_CONTAINER_OR_RETURN_ERROR(lstbox, w);
162 XmListDeletePos(w, (int)(index + 1));
163 return GATE_RESULT_OK;
164 }
165
166 gate_result_t gate_ui_listbox_remove_all_items(gate_ui_listbox_t* lstbox)
167 {
168 Widget w = NULL;
169 GATE_UI_MOTIF_EXTRACT_CONTAINER_OR_RETURN_ERROR(lstbox, w);
170 XmListDeleteAllItems(w);
171 return GATE_RESULT_OK;
172 }
173
174 gate_size_t gate_ui_listbox_get_item_count(gate_ui_listbox_t* lstbox)
175 {
176 gate_size_t ret = 0;
177 Widget w_list;
178 int list_count = 0;
179
180 do
181 {
182 if (!lstbox) break;
183 w_list = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&lstbox->ctrl);
184 if (!w_list) break;
185
186 ret = gate_ui_listbox_widget_get_item_count(w_list);
187 } while (0);
188
189 return 0;
190 }
191
192 void* gate_ui_listbox_get_item_param(gate_ui_listbox_t* lstbox, gate_size_t index)
193 {
194 return NULL;
195 }
196
197 gate_result_t gate_ui_listbox_find_param(gate_ui_listbox_t* lstbox, void* param, gate_size_t startIndex, gate_size_t* foundIndex)
198 {
199 return GATE_RESULT_NOTIMPLEMENTED;
200 }
201
202 gate_result_t gate_ui_listbox_get_text(gate_ui_listbox_t* lstbox, gate_size_t index, gate_string_t* text)
203 {
204 int count = 0;
205 XmStringTable tbl = NULL;
206 Widget w = NULL;
207 char const* ptr_data;
208
209 GATE_UI_MOTIF_EXTRACT_CONTAINER_OR_RETURN_ERROR(lstbox, w);
210 XtVaGetValues(w, XmNitemCount, &count, XmNitems, &tbl, NULL);
211 if (index >= (int)count)
212 {
213 return GATE_RESULT_OUTOFBOUNDS;
214 }
215
216 return gate_ui_motif_convert_string(tbl[index], text);
217 }
218
219 gate_result_t gate_ui_listbox_set_text(gate_ui_listbox_t* lstbox, gate_size_t index, gate_string_t const* text)
220 {
221 Widget w = NULL;
222 int positions[1];
223 XmString strs[1];
224 GATE_UI_MOTIF_EXTRACT_CONTAINER_OR_RETURN_ERROR(lstbox, w);
225 strs[0] = gate_ui_motif_create_string(text);
226 if (!strs[0]) return GATE_RESULT_OUTOFMEMORY;
227 positions[0] = (int)(index + 1);
228 XmListReplacePositions(w, positions, strs, 1);
229 XmStringFree(strs[0]);
230 return GATE_RESULT_OK;
231 }
232
233 gate_size_t gate_ui_listbox_get_selected_item(gate_ui_listbox_t* lstbox)
234 {
235 gate_size_t ret = GATE_UI_LISTBOX_INVALID_INDEX;
236 Widget w = NULL;
237 int count = 0;
238 int* ptr_positions = NULL;
239 do
240 {
241 if (!lstbox)
242 {
243 ret = GATE_RESULT_INVALIDARG;
244 break;
245 }
246 w = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&lstbox->ctrl);
247 if (!w)
248 {
249 ret = GATE_RESULT_INVALIDSTATE;
250 break;
251 }
252 XtVaGetValues(w, XmNselectedPositionCount, &count, XmNselectedPositions, &ptr_positions, NULL);
253 } while (0);
254 return ret;
255 }
256
257 gate_result_t gate_ui_listbox_set_selected_item(gate_ui_listbox_t* lstbox, gate_size_t index)
258 {
259 gate_result_t ret = GATE_RESULT_FAILED;
260 Widget w;
261 GATE_UI_MOTIF_EXTRACT_CONTAINER_OR_RETURN_ERROR(lstbox, w);
262 if (index == GATE_UI_LISTBOX_INVALID_INDEX)
263 {
264 XmListDeselectAllItems(w);
265 }
266 else
267 {
268 XmListSelectPos(w, (int)(index + 1), 1);
269 }
270 return GATE_RESULT_OK;
271 }
272
273
274
275
276
277 static void motif_free_pixmap_array(gate_ui_ctrl_t* ctrl)
278 {
279 gate_ui_host_t* host;
280 Display* dpy = NULL;
281 gate_arraylist_t pixmap_array;
282 gate_size_t arrlen;
283 gate_size_t ndx;
284 Pixmap* ptr_pixmap;
285
286 GATE_DEBUG_ASSERT(ctrl != NULL);
287
288 host = GATE_UI_MOTIF_GET_CTRL_HOST(ctrl);
289 pixmap_array = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(ctrl);
290 if (pixmap_array)
291 {
292 if (host)
293 {
294 dpy = GATE_UI_MOTIF_GET_HOST_DISPLAY(host);
295 }
296 arrlen = gate_arraylist_length(pixmap_array);
297 for (ndx = 0; ndx < arrlen; ++ndx)
298 {
299 ptr_pixmap = (Pixmap*)gate_arraylist_get(pixmap_array, ndx);
300 if (dpy && ptr_pixmap && (*ptr_pixmap != 0))
301 {
302 XFreePixmap(dpy, *ptr_pixmap);
303 }
304 }
305 gate_arraylist_release(pixmap_array);
306 GATE_UI_MOTIF_SET_CTRL_PRIVATE_ARG(ctrl, NULL);
307 }
308 }
309
310 static gate_result_t motif_listview_destroy(gate_ui_ctrl_t* ctrl)
311 {
312 gate_ui_listview_t* lv = (gate_ui_listview_t*)ctrl;
313 Widget w_scroll;
314 Widget w_list;
315 Cardinal col_count = 0;
316 unsigned ndx;
317 XmStringTable col_tbl = NULL;
318
319 GATE_DEBUG_ASSERT(lv != NULL);
320
321 gate_ui_listview_remove_all_items(lv);
322
323 w_scroll = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
324 w_list = GATE_UI_MOTIF_GET_CTRL_CONTAINER(ctrl);
325
326 if (w_list)
327 {
328 XtVaGetValues(w_list, XmNdetailColumnHeadingCount, &col_count, XmNdetailColumnHeading, &col_tbl, NULL, NULL);
329 XtVaSetValues(w_list, XmNdetailColumnHeadingCount, 0, XmNdetailColumnHeading, NULL, NULL, NULL);
330 if ((col_count > 0) && (col_tbl != NULL))
331 {
332 for (ndx = 0; ndx != col_count; ++ndx)
333 {
334 if (col_tbl[ndx])
335 {
336 XmStringFree(col_tbl[ndx]);
337 }
338 }
339 XtFree((char*)col_tbl);
340 }
341
342 XtUnmanageChild(w_list);
343 XtDestroyWidget(w_list);
344 }
345 if (w_scroll)
346 {
347 XtUnmanageChild(w_scroll);
348 XtDestroyWidget(w_scroll);
349 }
350
351 motif_free_pixmap_array(ctrl);
352
353 gate_mem_clear(ctrl, sizeof(gate_ui_ctrl_t));
354 return GATE_RESULT_OK;
355 }
356
357 static gate_result_t motif_listview_get_children(gate_ui_ctrl_t* ctrl, void** ptr_to_widgetlist, gate_size_t* ptr_to_children_count)
358 {
359 Widget w = GATE_UI_MOTIF_GET_CTRL_CONTAINER(ctrl);
360 WidgetList children = NULL;
361 Cardinal num_children = 0;
362
363 GATE_DEBUG_ASSERT(w != NULL);
364 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &num_children, NULL, NULL);
365 if (ptr_to_widgetlist)
366 {
367 *ptr_to_widgetlist = children;
368 }
369 if (ptr_to_children_count)
370 {
371 *ptr_to_children_count = (gate_size_t)num_children;
372 }
373 return GATE_RESULT_OK;
374 }
375
376 static gate_ui_motif_dispatcher_t listview_dispatcher =
377 {
378 &motif_listview_destroy,
379 NULL,
380 NULL,
381 NULL,
382 NULL,
383 NULL,
384 &motif_listview_get_children
385 };
386
387 static gate_size_t motif_listview_resolve_item_widget_index(gate_ui_listview_t* lstvw, Widget item)
388 {
389 WidgetList wl = NULL;
390 gate_size_t widget_count = 0;
391 gate_result_t ret = motif_listview_get_children(&lstvw->ctrl, (void**)&wl, &widget_count);
392 gate_size_t item_index = 0;
393 gate_size_t ndx;
394 Widget w;
395
396 for (ndx = 0; ndx != widget_count; ++ndx)
397 {
398 w = wl[ndx];
399 if (!XmIsIconGadget(w))
400 {
401 continue;
402 }
403 if (w == item)
404 {
405 return item_index;
406 }
407 ++item_index;
408 }
409 return GATE_STR_NPOS;
410 }
411
412 static Widget motif_listview_get_item_widget(gate_ui_listview_t* lstvw, gate_size_t index)
413 {
414 WidgetList wl = NULL;
415 gate_size_t widget_count = 0;
416 gate_size_t item_count = 0;
417 gate_size_t ndx;
418 Widget w;
419 WidgetClass wc;
420 gate_result_t ret = motif_listview_get_children(&lstvw->ctrl, (void**)&wl, &widget_count);
421 if (GATE_SUCCEEDED(ret))
422 {
423 for (ndx = 0; ndx != widget_count; ++ndx)
424 {
425 w = wl[ndx];
426 if (!XmIsIconGadget(w))
427 {
428 continue;
429 }
430 if (index == item_count)
431 {
432 return w;
433 }
434 ++item_count;
435 }
436 }
437 return NULL;
438 }
439
440
441 static void motif_listview_selection_callback(Widget widget, XtPointer client_data, XtPointer call_data)
442 {
443 gate_ui_listview_t* lv = (gate_ui_listview_t*)client_data;
444 XmContainerSelectCallbackStruct* evt_data = (XmContainerSelectCallbackStruct*)call_data;
445 gate_size_t item_index;
446 Widget item_widget;
447 void* item_data = NULL;
448
449 if (lv && lv->on_select && evt_data && evt_data->selected_item_count > 0)
450 {
451 item_widget = evt_data->selected_items[0];
452 item_index = motif_listview_resolve_item_widget_index(lv, item_widget);
453 if (item_index != GATE_STR_NPOS)
454 {
455 XtVaGetValues(item_widget, XmNuserData, &item_data, NULL, NULL);
456 lv->on_select(&lv->ctrl, item_index, item_data);
457 }
458 }
459 }
460
461 gate_result_t gate_ui_listview_create(gate_ui_listview_t* lstvw, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
462 gate_uint32_t flags, void* userparam)
463 {
464 gate_result_t ret = GATE_RESULT_FAILED;
465 Widget parent_widget = NULL;
466 Widget w;
467 Widget w_list;
468 Widget w_scroll1 = NULL;
469 Widget w_scroll2 = NULL;
470 Arg args[12];
471 Cardinal args_count;
472
473 do
474 {
475 if (!lstvw || !parent)
476 {
477 ret = GATE_RESULT_INVALIDARG;
478 break;
479 }
480
481 parent_widget = GATE_UI_MOTIF_GET_CTRL_CONTAINER(parent);
482 if (!parent_widget)
483 {
484 parent_widget = GATE_UI_MOTIF_GET_CTRL_WIDGET(parent);
485 }
486 args_count = 0;
487 XtSetArg(args[args_count], XmNscrollingPolicy, XmAUTOMATIC); ++args_count;
488 XtSetArg(args[args_count], XmNvisualPolicy, XmVARIABLE); ++args_count;
489 //XtSetArg(args[args_count], XmNscrollBarDisplayPolicy, XmSTATIC); ++args_count;
490 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
491 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
492
493 w = XmCreateScrolledWindow(parent_widget, NULL, args, args_count);
494 if (!w)
495 {
496 ret = GATE_RESULT_OUTOFRESOURCES;
497 break;
498 }
499
500 XtVaGetValues(w, XmNhorizontalScrollBar, &w_scroll1, XmNverticalScrollBar, &w_scroll2, NULL);
501 if (w_scroll1)
502 {
503 XtVaSetValues(w_scroll1, XmNshadowThickness, 1, NULL);
504 }
505 if (w_scroll2)
506 {
507 XtVaSetValues(w_scroll2, XmNshadowThickness, 1, NULL);
508 }
509
510 args_count = 0;
511 XtSetArg(args[args_count], XmNlayoutType, XmDETAIL); ++args_count;
512 XtSetArg(args[args_count], XmNautomaticSelection, XmAUTO_SELECT); ++args_count;
513 XtSetArg(args[args_count], XmNselectionPolicy, XmSINGLE_SELECT); ++args_count;
514 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
515
516 w_list = XmCreateContainer(w, NULL, args, args_count);
517 if (!w_list)
518 {
519 XtDestroyWidget(w);
520 ret = GATE_RESULT_OUTOFRESOURCES;
521 break;
522 }
523
524 ret = gate_ui_motif_ctrl_init(&lstvw->ctrl, w, userparam, NULL, parent, w_list, position, &flags, &listview_dispatcher);
525 GATE_BREAK_IF_FAILED(ret);
526
527 XtManageChild(w);
528 XtManageChild(w_list);
529
530 XtAddCallback(w_list, XmNselectionCallback, &motif_listview_selection_callback, lstvw);
531 } while (0);
532
533 return ret;
534 }
535
536 gate_result_t gate_ui_listview_set_columns(gate_ui_listview_t* lstvw, gate_ui_listview_column_t const* columns, gate_size_t column_count)
537 {
538 Widget w;
539 gate_size_t ndx;
540 Cardinal col_count = (Cardinal)column_count;
541 XmStringTable col_headers = (XmStringTable)XtMalloc(column_count * sizeof(XmString));
542
543 if (!col_headers)
544 {
545 return GATE_RESULT_OUTOFMEMORY;
546 }
547
548 for (ndx = 0; ndx != column_count; ++ndx)
549 {
550 col_headers[ndx] = gate_ui_motif_create_string(&columns[ndx].title);
551 }
552
553 w = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&lstvw->ctrl);
554 XtVaSetValues(w,
555 XmNdetailColumnHeadingCount, col_count,
556 XmNdetailColumnHeading, col_headers,
557 NULL, NULL);
558 return GATE_RESULT_OK;
559 }
560
561 gate_size_t gate_ui_listview_get_column_count(gate_ui_listview_t* lstvw)
562 {
563 Widget w;
564 Cardinal col_count = 0;
565
566 GATE_DEBUG_ASSERT(lstvw != NULL);
567
568 w = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&lstvw->ctrl);
569 XtVaGetValues(w, XmNdetailColumnHeadingCount, &col_count, NULL, NULL);
570 return col_count;
571 }
572
573 gate_result_t gate_ui_listview_get_column(gate_ui_listview_t* lstvw, gate_size_t index, gate_string_t* text, gate_uint32_t* width)
574 {
575 XmStringTable tbl = NULL;
576 Widget w = NULL;
577 Cardinal col_count = 0;
578 unsigned ndx;
579
580 GATE_DEBUG_ASSERT(lstvw != NULL);
581
582 w = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&lstvw->ctrl);
583 if (!w)
584 {
585 return GATE_RESULT_INVALIDSTATE;
586 }
587 XtVaGetValues(w, XmNdetailColumnHeadingCount, &col_count, XmNdetailColumnHeading, &tbl, NULL, NULL);
588 if ((index < col_count) && (tbl != NULL))
589 {
590 if (text)
591 {
592 gate_ui_motif_convert_string(tbl[index], text);
593 }
594 if (width)
595 {
596 *width = 0;
597 }
598 return GATE_RESULT_OK;
599 }
600 return GATE_RESULT_OUTOFBOUNDS;
601 }
602
603 gate_result_t gate_ui_listview_add_icon(gate_ui_listview_t* lstvw, gate_ui_icon_t const* icon, gate_intptr_t* icon_key)
604 {
605 return GATE_RESULT_NOTIMPLEMENTED;
606 }
607
608 static Pixmap create_mask_pixmap(gate_ui_host_t* host, gate_rasterimage_t const* image)
609 {
610 Display* dpy = GATE_UI_MOTIF_GET_HOST_DISPLAY(host);
611 Window win = XDefaultRootWindow(dpy);
612 Pixmap pm;
613 GC gc;
614 gate_color_t col;
615 unsigned int x, y, width, height;
616
617 width = gate_rasterimage_width(image);
618 height = gate_rasterimage_height(image);
619
620 pm = XCreatePixmap(dpy, win, image->width, image->height, 1);
621 gc = XCreateGC(dpy, pm, 0, NULL);
622 XSetForeground(dpy, gc, 0);
623 XFillRectangle(dpy, pm, gc, 0, 0, width, height);
624 XSetForeground(dpy, gc, 1);
625 for (y = 0; y != height; ++y)
626 {
627 for (x = 0; x != width; ++x)
628 {
629 gate_rasterimage_get_pixel(image, x, y, &col);
630 if (col.a > 127)
631 {
632 XDrawPoint(dpy, pm, gc, x, y);
633 }
634 }
635 }
636 XFreeGC(dpy, gc);
637 return pm;
638 }
639
640 static gate_result_t motif_ctrl_add_pixmap_image(gate_ui_ctrl_t* ctrl, gate_rasterimage_t const* image, gate_intptr_t* icon_key)
641 {
642 gate_arraylist_t pixmap_array = NULL;
643 gate_result_t ret;
644 gate_ui_graphics_t graph;
645 gate_ui_host_t* host = NULL;
646 Pixmap pm;
647 gate_size_t len;
648
649 GATE_DEBUG_ASSERT(ctrl != NULL);
650
651 do
652 {
653 host = GATE_UI_MOTIF_GET_CTRL_HOST(ctrl);
654 pixmap_array = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(ctrl);
655 if (pixmap_array == NULL)
656 {
657 pixmap_array = gate_arraylist_create(sizeof(Pixmap), NULL, 16, NULL, NULL);
658 if (NULL == pixmap_array)
659 {
660 GATE_DEBUG_TRACE("Failed to allocate pixmap array");
661 ret = GATE_RESULT_OUTOFMEMORY;
662 break;
663 }
664 GATE_UI_MOTIF_SET_CTRL_PRIVATE_ARG(ctrl, pixmap_array);
665 }
666
667 pm = create_mask_pixmap(host, image);
668 gate_arraylist_add(pixmap_array, &pm);
669
670 ret = gate_ui_graphics_create_image_from(&graph, host, image);
671 GATE_BREAK_IF_FAILED(ret);
672
673 pm = (Pixmap)graph.resources[1];
674 graph.resources[1] = 0;
675 gate_ui_graphics_destroy(&graph);
676
677 gate_arraylist_add(pixmap_array, &pm);
678 len = gate_arraylist_length(pixmap_array);
679 if (icon_key)
680 {
681 *icon_key = (gate_intptr_t)len;
682 }
683 ret = GATE_RESULT_OK;
684 } while (0);
685
686 return ret;
687 }
688
689 static gate_result_t motif_ctrl_get_pixmap_image(gate_ui_ctrl_t* ctrl, gate_intptr_t icon_key, Pixmap* ptr_pm_image, Pixmap* ptr_pm_mask)
690 {
691 Pixmap ret = 0;
692 gate_arraylist_t pixmap_array = NULL;
693 Pixmap* ptr_pixmap = NULL;
694
695 if (icon_key == GATE_UI_LISTVIEW_INVALID_ICON)
696 {
697 return GATE_RESULT_NOTAVAILABLE;
698 }
699
700 pixmap_array = (gate_arraylist_t)GATE_UI_MOTIF_GET_CTRL_PRIVATE_ARG(ctrl);
701 if (!pixmap_array)
702 {
703 return GATE_RESULT_NOTAVAILABLE;
704 }
705
706 /* retrieve image pixmap */
707 if (ptr_pm_image)
708 {
709 ptr_pixmap = (Pixmap*)gate_arraylist_get(pixmap_array, icon_key - 1);
710 if (!ptr_pixmap)
711 {
712 return GATE_RESULT_NOTAVAILABLE;
713 }
714 *ptr_pm_image = *ptr_pixmap;
715 }
716
717 /* retrieve mask image */
718 if (ptr_pm_mask)
719 {
720 ptr_pixmap = (Pixmap*)gate_arraylist_get(pixmap_array, icon_key - 2);
721 *ptr_pm_mask = ptr_pixmap ? *ptr_pixmap : 0;
722 }
723
724 return GATE_RESULT_OK;
725 }
726
727
728 gate_result_t gate_ui_listview_add_icon_image(gate_ui_listview_t* lstvw, gate_rasterimage_t const* image, gate_intptr_t* icon_key)
729 {
730 GATE_DEBUG_ASSERT(lstvw != NULL);
731 return motif_ctrl_add_pixmap_image(&lstvw->ctrl, image, icon_key);
732 }
733
734 gate_result_t gate_ui_listview_insert_item(gate_ui_listview_t* lstvw, gate_size_t const* atIndex, gate_string_t const* text,
735 gate_intptr_t icon_key, void* itemparam)
736 {
737 Widget w_lstvw;
738 Widget new_widget;
739 Arg args[12] = GATE_INIT_EMPTY;
740 Cardinal arg_count = 0;
741 XmString main_text = NULL;
742 XmStringTable text_items;
743 gate_size_t ndx;
744 Cardinal col_count;
745 Pixmap pm_image;
746 Pixmap pm_mask;
747 gate_result_t result;
748
749 if (!lstvw)
750 {
751 return GATE_RESULT_INVALIDSTATE;
752 }
753 w_lstvw = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&lstvw->ctrl);
754 if (!w_lstvw)
755 {
756 return GATE_RESULT_INVALIDSTATE;
757 }
758
759 col_count = (Cardinal)gate_ui_listview_get_column_count(lstvw);
760 if (col_count > 0)
761 {
762 main_text = gate_ui_motif_create_string(text);
763 --col_count;
764 }
765 if (col_count > 0)
766 {
767 text_items = (XmStringTable)XtMalloc(col_count * sizeof(XmString));
768 if (!text_items)
769 {
770 return GATE_RESULT_OUTOFMEMORY;
771 }
772 }
773 else
774 {
775 text_items = NULL;
776 }
777
778 for (ndx = 0; ndx < col_count; ++ndx)
779 {
780 text_items[ndx] = NULL;
781 }
782
783 XtSetArg(args[arg_count], XmNviewType, XmSMALL_ICON); ++arg_count;
784 XtSetArg(args[arg_count], XmNshadowThickness, 0); ++arg_count;
785 XtSetArg(args[arg_count], XmNlabelString, main_text); ++arg_count;
786 XtSetArg(args[arg_count], XmNdetail, text_items); ++arg_count;
787 XtSetArg(args[arg_count], XmNdetailCount, col_count); ++arg_count;
788 XtSetArg(args[arg_count], XmNuserData, itemparam); ++arg_count;
789
790 result = motif_ctrl_get_pixmap_image(&lstvw->ctrl, icon_key, &pm_image, &pm_mask);
791 if (GATE_SUCCEEDED(result))
792 {
793 if (pm_image)
794 {
795 XtSetArg(args[arg_count], XmNsmallIconPixmap, pm_image);
796 ++arg_count;
797 }
798 if (pm_mask)
799 {
800 XtSetArg(args[arg_count], XmNsmallIconMask, pm_mask);
801 ++arg_count;
802 }
803 }
804
805 new_widget = XmCreateIconGadget(w_lstvw, NULL, args, arg_count);
806
807 if (!new_widget)
808 {
809 return GATE_RESULT_FAILED;
810 }
811 XtManageChild(new_widget);
812
813 if (text_items)
814 {
815 XtFree((char*)text_items);
816 }
817 if (main_text)
818 {
819 XmStringFree(main_text);
820 }
821
822 return GATE_RESULT_OK;
823 }
824
825 gate_result_t gate_ui_listview_remove_item(gate_ui_listview_t* lstvw, gate_size_t index)
826 {
827 Widget w;
828 XmString text = NULL;
829 Cardinal detail_count = 0;
830 XmStringTable detail_tbl = NULL;
831 GATE_DEBUG_ASSERT(lstvw != NULL);
832 w = motif_listview_get_item_widget(lstvw, index);
833 if (w == NULL)
834 {
835 return GATE_RESULT_NOTAVAILABLE;
836 }
837 XtVaGetValues(w, XmNlabelString, &text, NULL, NULL);
838 XtVaSetValues(w, XmNlabelString, NULL, NULL, NULL);
839
840 if (text)
841 {
842 XmStringFree(text);
843 }
844
845 XtUnmanageChild(w);
846 XtDestroyWidget(w);
847 return GATE_RESULT_OK;
848 }
849
850 gate_result_t gate_ui_listview_remove_all_items(gate_ui_listview_t* lstvw)
851 {
852 Widget w_list;
853 gate_size_t count = 0;
854 GATE_DEBUG_ASSERT(lstvw != NULL);
855
856 count = gate_ui_listview_get_item_count(lstvw);
857 while (count-- > 0)
858 {
859 gate_ui_listview_remove_item(lstvw, count);
860 }
861 return GATE_RESULT_OK;
862 }
863
864 gate_size_t gate_ui_listview_get_item_count(gate_ui_listview_t* lstvw)
865 {
866 WidgetList wl = NULL;
867 gate_size_t widget_count = 0;
868 gate_size_t item_count = 0;
869 gate_size_t ndx;
870 Widget w;
871 WidgetClass wc;
872 gate_result_t ret;
873
874 GATE_DEBUG_ASSERT(lstvw != NULL);
875 ret = gate_ui_motif_ctrl_get_children(&lstvw->ctrl, (void**)&wl, &widget_count);
876 if (GATE_SUCCEEDED(ret))
877 {
878 for (ndx = 0; ndx != widget_count; ++ndx)
879 {
880 w = wl[ndx];
881 if (!XmIsIconGadget(w))
882 {
883 continue;
884 }
885 ++item_count;
886 }
887 }
888 return item_count;
889 }
890
891 void* gate_ui_listview_get_item_param(gate_ui_listview_t* lstvw, gate_size_t index)
892 {
893 void* data = NULL;
894 Widget w;
895
896 GATE_DEBUG_ASSERT(lstvw != NULL);
897 w = motif_listview_get_item_widget(lstvw, index);
898 if (w != NULL)
899 {
900 XtVaGetValues(w, XmNuserData, &data, NULL, NULL);
901 }
902 return data;
903 }
904
905 gate_result_t gate_ui_listview_find_param(gate_ui_listview_t* lstvw, void* param, gate_size_t startIndex, gate_size_t* foundIndex)
906 {
907 WidgetList wl = NULL;
908 gate_size_t widget_count = 0;
909 gate_size_t item_count = 0;
910 gate_size_t ndx;
911 Widget w;
912 WidgetClass wc;
913 void* data = NULL;
914 gate_result_t ret;
915
916 GATE_DEBUG_ASSERT(lstvw != NULL);
917 ret = motif_listview_get_children(&lstvw->ctrl, (void**)&wl, &widget_count);
918 if (GATE_SUCCEEDED(ret))
919 {
920 for (ndx = 0; ndx != widget_count; ++ndx)
921 {
922 w = wl[ndx];
923 if (!XmIsIconGadget(w))
924 {
925 continue;
926 }
927 if (item_count >= startIndex)
928 {
929 XtVaGetValues(w, XmNuserData, &data, NULL, NULL);
930 if (data == param)
931 {
932 if (foundIndex)
933 {
934 *foundIndex = ndx;
935 }
936 return GATE_RESULT_OK;
937 }
938 }
939 ++item_count;
940 }
941 }
942 return GATE_RESULT_NOMATCH;
943 }
944
945 gate_result_t gate_ui_listview_get_text(gate_ui_listview_t* lstvw, gate_size_t index, gate_size_t subindex, gate_string_t* text)
946 {
947 Widget w;
948 XmString xmstr = NULL;
949 XmStringTable strtbl = NULL;
950 Cardinal strcnt = 0;
951
952 GATE_DEBUG_ASSERT(lstvw != NULL);
953 w = motif_listview_get_item_widget(lstvw, index);
954 if (!w)
955 {
956 return GATE_RESULT_OUTOFBOUNDS;
957 }
958 if (index == 0)
959 {
960 XtVaGetValues(w, XmNlabelString, &xmstr, NULL, NULL);
961 if (text)
962 {
963 return gate_ui_motif_convert_string(xmstr, text);
964 }
965 }
966 else
967 {
968 XtVaGetValues(w, XmNdetailCount, &strcnt, XmNdetail, &strtbl, NULL, NULL);
969 if (index >= strcnt)
970 {
971 return GATE_RESULT_OUTOFBOUNDS;
972 }
973 if (text)
974 {
975 return gate_ui_motif_convert_string(strtbl[index], text);
976 }
977 }
978 return GATE_RESULT_OK;
979 }
980
981 gate_result_t gate_ui_listview_set_text(gate_ui_listview_t* lstvw, gate_size_t index, gate_size_t subindex, gate_string_t const* text)
982 {
983 Widget w_lstvw;
984 Widget new_widget;
985 Widget item_widget;
986 XmStringTable text_items = NULL;
987 XmString xmstr = NULL;
988 XmString oldstr = NULL;
989 gate_size_t ndx;
990 Cardinal col_count;
991 Cardinal text_items_count = 0;
992
993 GATE_DEBUG_ASSERT(lstvw != NULL);
994
995 w_lstvw = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&lstvw->ctrl);
996 if (!w_lstvw)
997 {
998 return GATE_RESULT_INVALIDSTATE;
999 }
1000
1001 item_widget = motif_listview_get_item_widget(lstvw, index);
1002 if (!item_widget)
1003 {
1004 return GATE_RESULT_NOMATCH;
1005 }
1006
1007 col_count = (Cardinal)gate_ui_listview_get_column_count(lstvw);
1008
1009 xmstr = gate_ui_motif_create_string(text);
1010 if (subindex == 0)
1011 {
1012 XtVaGetValues(item_widget, XmNlabelString, &oldstr, NULL, NULL);
1013 XtVaSetValues(item_widget, XmNlabelString, xmstr, NULL, NULL);
1014 }
1015 else if (subindex < col_count)
1016 {
1017 XtVaGetValues(item_widget, XmNdetailCount, &text_items_count, XmNdetail, &text_items, NULL, NULL);
1018 if (text_items && (subindex - 1 < text_items_count))
1019 {
1020 oldstr = text_items[subindex - 1];
1021 text_items[subindex - 1] = xmstr;
1022 }
1023 }
1024 if (oldstr)
1025 {
1026 XmStringFree(oldstr);
1027 }
1028 return GATE_RESULT_OK;
1029 }
1030
1031 gate_bool_t gate_ui_listview_is_checked(gate_ui_listview_t* lstvw, gate_size_t index)
1032 {
1033 return false;
1034 }
1035
1036 gate_result_t gate_ui_listview_set_checked(gate_ui_listview_t* lstvw, gate_size_t index, gate_bool_t checked)
1037 {
1038 return GATE_RESULT_NOTIMPLEMENTED;
1039 }
1040
1041 gate_result_t gate_ui_listview_get_checked_items(gate_ui_listview_t* lstvw, gate_array_t* indexarray)
1042 {
1043 return GATE_RESULT_NOTIMPLEMENTED;
1044 }
1045
1046 gate_bool_t gate_ui_listview_is_selected(gate_ui_listview_t* lstvw, gate_size_t index)
1047 {
1048 Widget w_lstvw;
1049 Widget w_item;
1050 Cardinal selcnt = 0;
1051 WidgetList selitems = NULL;
1052 unsigned ndx;
1053
1054 w_item = motif_listview_get_item_widget(lstvw, index);
1055 if (!w_item)
1056 {
1057 return false;
1058 }
1059
1060 w_lstvw = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&lstvw->ctrl);
1061 if (!w_lstvw)
1062 {
1063 return false;
1064 }
1065
1066 XtVaGetValues(w_lstvw, XmNselectedObjectCount, &selcnt, XmNselectedObjects, &selitems, NULL, NULL);
1067 if ((selitems == NULL) || (selcnt == 0))
1068 {
1069 return false;
1070 }
1071 for (ndx = 0; ndx != selcnt; ++ndx)
1072 {
1073 if (selitems[ndx] == w_item)
1074 {
1075 return true;
1076 }
1077 }
1078 return false;
1079 }
1080
1081 gate_result_t gate_ui_listview_get_selected_item(gate_ui_listview_t* lstvw, gate_size_t* index)
1082 {
1083 Widget w_lstvw;
1084 Cardinal selcnt = 0;
1085 WidgetList selitems = NULL;
1086
1087 GATE_DEBUG_ASSERT(lstvw != NULL);
1088
1089 w_lstvw = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&lstvw->ctrl);
1090 if (!w_lstvw)
1091 {
1092 return GATE_RESULT_INVALIDSTATE;
1093 }
1094
1095 XtVaGetValues(w_lstvw, XmNselectedObjectCount, &selcnt, XmNselectedObjects, &selitems, NULL, NULL);
1096 if ((selcnt == 0) || (selitems == NULL))
1097 {
1098 return GATE_RESULT_NOTAVAILABLE;
1099 }
1100
1101 if (index)
1102 {
1103 *index = motif_listview_resolve_item_widget_index(lstvw, selitems[0]);
1104 }
1105 return GATE_RESULT_OK;
1106 }
1107
1108 gate_result_t gate_ui_listview_get_selected_items(gate_ui_listview_t* lstvw, gate_array_t* indexarray)
1109 {
1110 Widget w_lstvw;
1111 Cardinal selcnt = 0;
1112 Cardinal ndx;
1113 WidgetList selitems = NULL;
1114 gate_arraylist_t arr = NULL;
1115 gate_size_t itemndx;
1116
1117 GATE_DEBUG_ASSERT(lstvw != NULL);
1118
1119 w_lstvw = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&lstvw->ctrl);
1120 if (!w_lstvw)
1121 {
1122 return GATE_RESULT_INVALIDSTATE;
1123 }
1124
1125 XtVaGetValues(w_lstvw, XmNselectedObjectCount, &selcnt, XmNselectedObjects, &selitems, NULL, NULL);
1126 if ((selcnt == 0) || (selitems == NULL))
1127 {
1128 return GATE_RESULT_NOTAVAILABLE;
1129 }
1130
1131 arr = gate_arraylist_create(sizeof(gate_size_t), NULL, selcnt, NULL, NULL);
1132 if (arr == NULL)
1133 {
1134 return GATE_RESULT_OUTOFMEMORY;
1135 }
1136
1137 for (ndx = 0; ndx != selcnt; ++ndx)
1138 {
1139 itemndx = motif_listview_resolve_item_widget_index(lstvw, selitems[ndx]);
1140 if (itemndx != GATE_STR_NPOS)
1141 {
1142 gate_arraylist_add(arr, &itemndx);
1143 }
1144 }
1145
1146 if (indexarray)
1147 {
1148 gate_array_create(indexarray, arr);
1149
1150 }
1151
1152 gate_arraylist_release(arr);
1153 return GATE_RESULT_OK;
1154 }
1155
1156 gate_result_t gate_ui_listview_select_item(gate_ui_listview_t* lstvw, gate_size_t index, gate_bool_t selected)
1157 {
1158 Widget w_lstvw;
1159 Widget w_item;
1160 Widget sel_widgets[1];
1161
1162 GATE_DEBUG_ASSERT(lstvw != NULL);
1163
1164 w_lstvw = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&lstvw->ctrl);
1165 if (!w_lstvw)
1166 {
1167 return GATE_RESULT_INVALIDSTATE;
1168 }
1169
1170 w_item = motif_listview_get_item_widget(lstvw, index);
1171 if (w_item == NULL)
1172 {
1173 return GATE_RESULT_OUTOFBOUNDS;
1174 }
1175
1176 if (selected)
1177 {
1178 sel_widgets[0] = w_item;
1179 XtVaSetValues(w_lstvw, XmNselectedObjects, &sel_widgets[0], XmNselectedObjectCount, 1, NULL, NULL);
1180 }
1181 else
1182 {
1183 XtVaSetValues(w_lstvw, XmNselectedObjects, NULL, XmNselectedObjectCount, 0, NULL, NULL);
1184 }
1185
1186 return GATE_RESULT_OK;
1187 }
1188
1189
1190
1191
1192
1193 static gate_result_t motif_itemview_destroy(gate_ui_ctrl_t* ctrl)
1194 {
1195 gate_ui_itemview_t* iv = (gate_ui_itemview_t*)ctrl;
1196 Widget w_scroll;
1197 Widget w_list;
1198
1199 GATE_DEBUG_ASSERT(iv != NULL);
1200
1201 gate_ui_itemview_remove_all_items(iv);
1202
1203 w_scroll = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
1204 w_list = GATE_UI_MOTIF_GET_CTRL_CONTAINER(ctrl);
1205
1206 if (w_list)
1207 {
1208 XtUnmanageChild(w_list);
1209 XtDestroyWidget(w_list);
1210 }
1211 if (w_scroll)
1212 {
1213 XtUnmanageChild(w_scroll);
1214 XtDestroyWidget(w_scroll);
1215 }
1216
1217 motif_free_pixmap_array(ctrl);
1218
1219 gate_mem_clear(ctrl, sizeof(gate_ui_ctrl_t));
1220 return GATE_RESULT_OK;
1221 }
1222
1223
1224 static gate_ui_motif_dispatcher_t itemview_dispatcher =
1225 {
1226 &motif_itemview_destroy,
1227 NULL,
1228 NULL,
1229 NULL,
1230 NULL,
1231 NULL,
1232 NULL
1233 };
1234
1235
1236 static Widget motif_itemview_get_item_widget(gate_ui_itemview_t* itemview, gate_size_t index)
1237 {
1238 gate_result_t result;
1239 WidgetList wl = NULL;
1240 gate_size_t widget_count = 0;
1241
1242 GATE_DEBUG_ASSERT(itemview != NULL);
1243 result = gate_ui_motif_ctrl_get_children(&itemview->ctrl, (void**)&wl, &widget_count);
1244 if (GATE_FAILED(result))
1245 {
1246 return NULL;
1247 }
1248 if ((index >= widget_count) || (wl == NULL))
1249 {
1250 return NULL;
1251 }
1252 return wl[index];
1253 }
1254
1255 static gate_size_t motif_itemview_resolve_item_widget_index(gate_ui_itemview_t* itemview, Widget item_widget)
1256 {
1257 gate_result_t result;
1258 WidgetList wl = NULL;
1259 gate_size_t widget_count = 0;
1260 gate_size_t ndx;
1261
1262 GATE_DEBUG_ASSERT(itemview != NULL);
1263 result = gate_ui_motif_ctrl_get_children(&itemview->ctrl, (void**)&wl, &widget_count);
1264 if (GATE_FAILED(result))
1265 {
1266 return GATE_STR_NPOS;
1267 }
1268 for (ndx = 0; ndx != widget_count; ++ndx)
1269 {
1270 if (wl[ndx] == item_widget)
1271 {
1272 return ndx;
1273 }
1274 }
1275 return GATE_STR_NPOS;
1276 }
1277
1278
1279 static void motif_itemview_selection_callback(Widget widget, XtPointer client_data, XtPointer call_data)
1280 {
1281 gate_ui_itemview_t* iv = (gate_ui_itemview_t*)client_data;
1282 XmContainerSelectCallbackStruct* evt_data = (XmContainerSelectCallbackStruct*)call_data;
1283 gate_size_t item_index;
1284 Widget item_widget;
1285 void* item_data = NULL;
1286
1287 if (iv && iv->on_select && evt_data && evt_data->selected_item_count > 0)
1288 {
1289 item_widget = evt_data->selected_items[0];
1290 item_index = motif_itemview_resolve_item_widget_index(iv, item_widget);
1291 if (item_index != GATE_STR_NPOS)
1292 {
1293 XtVaGetValues(item_widget, XmNuserData, &item_data, NULL, NULL);
1294 iv->on_select(&iv->ctrl, item_index, item_data);
1295 }
1296 }
1297 }
1298
1299 gate_result_t gate_ui_itemview_create(gate_ui_itemview_t* itemview, gate_ui_ctrl_t* parent, gate_ui_position_t const* position,
1300 gate_uint32_t flags, void* userparam)
1301 {
1302 gate_result_t ret = GATE_RESULT_FAILED;
1303 Widget parent_widget = NULL;
1304 Widget w;
1305 Widget w_list;
1306 Widget w_scroll1 = NULL;
1307 Widget w_scroll2 = NULL;
1308 Arg args[12];
1309 Cardinal args_count;
1310
1311 do
1312 {
1313 if (!itemview || !parent)
1314 {
1315 ret = GATE_RESULT_INVALIDARG;
1316 break;
1317 }
1318
1319 parent_widget = GATE_UI_MOTIF_GET_CTRL_CONTAINER(parent);
1320 if (!parent_widget)
1321 {
1322 parent_widget = GATE_UI_MOTIF_GET_CTRL_WIDGET(parent);
1323 }
1324 args_count = 0;
1325
1326 XtSetArg(args[args_count], XmNscrollingPolicy, XmAUTOMATIC); ++args_count;
1327 XtSetArg(args[args_count], XmNvisualPolicy, XmVARIABLE); ++args_count;
1328 XtSetArg(args[args_count], XmNscrollBarDisplayPolicy, XmSTATIC); ++args_count;
1329 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
1330 XtSetArg(args[args_count], XmNhighlightThickness, 1); ++args_count;
1331
1332 w = XmCreateScrolledWindow(parent_widget, NULL, args, args_count);
1333 if (!w)
1334 {
1335 ret = GATE_RESULT_OUTOFRESOURCES;
1336 break;
1337 }
1338
1339 XtVaGetValues(w, XmNhorizontalScrollBar, &w_scroll1, XmNverticalScrollBar, &w_scroll2, NULL, NULL);
1340 if (w_scroll1 != NULL)
1341 {
1342 XtSetSensitive(w_scroll1, False);
1343 }
1344 if (w_scroll2 != NULL)
1345 {
1346 XtVaSetValues(w_scroll2, XmNshadowThickness, 1, NULL, NULL);
1347 }
1348
1349 args_count = 0;
1350 XtSetArg(args[args_count], XmNlayoutType, XmSPATIAL); ++args_count;
1351 XtSetArg(args[args_count], XmNspatialStyle, XmGRID); ++args_count;
1352 XtSetArg(args[args_count], XmNspatialResizeModel, XmGROW_MINOR); ++args_count;
1353 XtSetArg(args[args_count], XmNspatialSnapModel, XmSNAP_TO_GRID); ++args_count;
1354 XtSetArg(args[args_count], XmNspatialIncludeModel, XmFIRST_FIT); ++args_count;
1355 XtSetArg(args[args_count], XmNlayoutDirection, XmTOP_TO_BOTTOM_LEFT_TO_RIGHT); ++args_count;
1356 XtSetArg(args[args_count], XmNautomaticSelection, XmAUTO_SELECT); ++args_count;
1357 XtSetArg(args[args_count], XmNselectionPolicy, XmSINGLE_SELECT); ++args_count;
1358 XtSetArg(args[args_count], XmNlargeCellWidth, 640); ++args_count;
1359
1360 XtSetArg(args[args_count], XmNshadowThickness, 1); ++args_count;
1361
1362 w_list = XmCreateContainer(w, NULL, args, args_count);
1363 if (!w_list)
1364 {
1365 XtDestroyWidget(w);
1366 ret = GATE_RESULT_OUTOFRESOURCES;
1367 break;
1368 }
1369
1370 ret = gate_ui_motif_ctrl_init(&itemview->ctrl, w, userparam, NULL, parent, w_list, position, &flags, &itemview_dispatcher);
1371 GATE_BREAK_IF_FAILED(ret);
1372
1373 XtManageChild(w);
1374 XtManageChild(w_list);
1375
1376 XtAddCallback(w_list, XmNselectionCallback, &motif_itemview_selection_callback, itemview);
1377 } while (0);
1378
1379 return ret;
1380 }
1381
1382 gate_result_t gate_ui_itemview_add_icon(gate_ui_itemview_t* itemview, gate_ui_icon_t const* icon, gate_intptr_t* icon_key)
1383 {
1384 return GATE_RESULT_NOTIMPLEMENTED;
1385 }
1386
1387 gate_result_t gate_ui_itemview_add_icon_image(gate_ui_itemview_t* itemview, gate_rasterimage_t const* image, gate_intptr_t* icon_key)
1388 {
1389 GATE_DEBUG_ASSERT(itemview != NULL);
1390 return motif_ctrl_add_pixmap_image(&itemview->ctrl, image, icon_key);
1391 }
1392
1393 static XmString motif_itemview_create_label(gate_string_t const* title, gate_string_t const* subtitle, gate_string_t const* additionals)
1394 {
1395 gate_strbuilder_t sb;
1396 gate_string_t tmp_text = GATE_STRING_INIT_EMPTY;
1397 XmString ret;
1398
1399 gate_strbuilder_create(&sb, 32);
1400 gate_strbuilder_append_string(&sb, title);
1401 gate_strbuilder_append_cstr(&sb, "\n");
1402 gate_strbuilder_append_string(&sb, subtitle);
1403 gate_strbuilder_append_cstr(&sb, "\n");
1404 gate_strbuilder_append_string(&sb, additionals);
1405
1406 gate_strbuilder_to_string(&sb, &tmp_text);
1407 ret = gate_ui_motif_create_string(&tmp_text);
1408 gate_strbuilder_release(&sb);
1409 return ret;
1410 }
1411
1412 gate_result_t gate_ui_itemview_insert(gate_ui_itemview_t* itemview, gate_size_t const* atIndex, gate_string_t const* title,
1413 gate_string_t const* subtitle, gate_string_t const* additionals, gate_intptr_t icon_key, void* itemparam)
1414 {
1415 Widget w_view;
1416 Widget new_widget;
1417 Arg args[16] = GATE_INIT_EMPTY;
1418 Cardinal arg_count = 0;
1419 XmString main_text = NULL;
1420 gate_size_t ndx;
1421 Cardinal col_count;
1422 Pixmap pm_image;
1423 Pixmap pm_mask;
1424 gate_result_t result;
1425
1426 GATE_DEBUG_ASSERT(itemview != NULL);
1427
1428 w_view = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&itemview->ctrl);
1429 if (!w_view)
1430 {
1431 return GATE_RESULT_INVALIDSTATE;
1432 }
1433
1434 main_text = motif_itemview_create_label(title, subtitle, additionals);
1435
1436 XtSetArg(args[arg_count], XmNviewType, XmSMALL_ICON); ++arg_count;
1437 XtSetArg(args[arg_count], XmNshadowThickness, 0); ++arg_count;
1438 XtSetArg(args[arg_count], XmNlabelString, main_text); ++arg_count;
1439 XtSetArg(args[arg_count], XmNuserData, itemparam); ++arg_count;
1440
1441 result = motif_ctrl_get_pixmap_image(&itemview->ctrl, icon_key, &pm_image, &pm_mask);
1442 if (GATE_SUCCEEDED(result))
1443 {
1444 if (pm_image)
1445 {
1446 XtSetArg(args[arg_count], XmNsmallIconPixmap, pm_image);
1447 ++arg_count;
1448 }
1449 if (pm_mask)
1450 {
1451 XtSetArg(args[arg_count], XmNsmallIconMask, pm_mask);
1452 ++arg_count;
1453 }
1454 }
1455
1456 new_widget = XmCreateIconGadget(w_view, NULL, args, arg_count);
1457
1458 if (!new_widget)
1459 {
1460 return GATE_RESULT_FAILED;
1461 }
1462 XtManageChild(new_widget);
1463
1464 if (main_text)
1465 {
1466 XmStringFree(main_text);
1467 }
1468
1469 return GATE_RESULT_OK;
1470 }
1471
1472
1473
1474 gate_result_t gate_ui_itemview_remove(gate_ui_itemview_t* itemview, gate_size_t index)
1475 {
1476 Widget w = motif_itemview_get_item_widget(itemview, index);
1477 if (w == NULL)
1478 {
1479 return GATE_RESULT_NOTAVAILABLE;
1480 }
1481 else
1482 {
1483 XtDestroyWidget(w);
1484 return GATE_RESULT_OK;
1485 }
1486 }
1487
1488 gate_result_t gate_ui_itemview_remove_all_items(gate_ui_itemview_t* itemview)
1489 {
1490 Widget w_list = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&itemview->ctrl);
1491 gate_ui_motif_widget_destroy_children(w_list, false);
1492 return GATE_RESULT_OK;
1493 }
1494
1495 gate_size_t gate_ui_itemview_get_count(gate_ui_itemview_t* itemview)
1496 {
1497 WidgetList wl = NULL;
1498 gate_size_t widget_count = 0;
1499 gate_result_t ret;
1500
1501 GATE_DEBUG_ASSERT(itemview != NULL);
1502 ret = gate_ui_motif_ctrl_get_children(&itemview->ctrl, (void**)&wl, &widget_count);
1503 if (GATE_FAILED(ret))
1504 {
1505 return 0;
1506 }
1507 else
1508 {
1509 return widget_count;
1510 }
1511 }
1512
1513 void* gate_ui_itemview_get_item_param(gate_ui_itemview_t* itemview, gate_size_t index)
1514 {
1515 Widget w;
1516 void* ret = NULL;
1517
1518 GATE_DEBUG_ASSERT(itemview != NULL);
1519
1520 w = motif_itemview_get_item_widget(itemview, index);
1521 if (w)
1522 {
1523 XtVaGetValues(w, XmNuserData, &ret, NULL, NULL);
1524 }
1525 return ret;
1526 }
1527
1528 gate_result_t gate_ui_itemview_find_param(gate_ui_itemview_t* itemview, void* find_param, gate_size_t startIndex, gate_size_t* foundIndex)
1529 {
1530 WidgetList wl = NULL;
1531 Widget w;
1532 gate_size_t widget_count = 0;
1533 gate_size_t ndx;
1534 gate_result_t ret;
1535 void* item_param;
1536
1537 GATE_DEBUG_ASSERT(itemview != NULL);
1538 do
1539 {
1540 ret = gate_ui_motif_ctrl_get_children(&itemview->ctrl, (void**)&wl, &widget_count);
1541 GATE_BREAK_IF_FAILED(ret);
1542
1543 ret = GATE_RESULT_NOMATCH;
1544 for (ndx = startIndex; ndx < widget_count; ++ndx)
1545 {
1546 w = wl[ndx];
1547 if (!w)
1548 {
1549 continue;
1550 }
1551 item_param = NULL;
1552 XtVaGetValues(w, XmNuserData, &item_param, NULL, NULL);
1553 if (item_param == find_param)
1554 {
1555 if (foundIndex)
1556 {
1557 *foundIndex = ndx;
1558 }
1559 ret = GATE_RESULT_OK;
1560 break;
1561 }
1562 }
1563 } while (0);
1564 return ret;
1565 }
1566
1567 gate_result_t gate_ui_itemview_get_text(gate_ui_itemview_t* itemview, gate_size_t index,
1568 gate_string_t* title, gate_string_t* subtitle, gate_string_t* additionals)
1569 {
1570 Widget w_item;
1571 XmString xmstr;
1572 gate_string_t item_str = GATE_STRING_INIT_EMPTY;
1573 gate_size_t pos1 = GATE_STR_NPOS;
1574 gate_size_t pos2 = GATE_STR_NPOS;
1575
1576 GATE_DEBUG_ASSERT(itemview != NULL);
1577
1578 w_item = motif_itemview_get_item_widget(itemview, index);
1579 if (w_item == NULL)
1580 {
1581 return GATE_RESULT_OUTOFBOUNDS;
1582 }
1583
1584 XtVaGetValues(w_item, XmNlabelString, &xmstr, NULL, NULL);
1585 if (xmstr)
1586 {
1587 gate_ui_motif_convert_string(xmstr, &item_str);
1588 }
1589
1590 pos1 = gate_string_char_pos(&item_str, '\n', 0);
1591 if (pos1 != GATE_STR_NPOS)
1592 {
1593 pos2 = gate_string_char_pos(&item_str, '\n', pos1 + 1);
1594 }
1595 if (title)
1596 {
1597 gate_string_substr(title, &item_str, 0, pos1);
1598 }
1599 if (subtitle)
1600 {
1601 gate_string_substr(subtitle, &item_str, pos1 + 1, pos2 - pos1 - 1);
1602 }
1603 if (additionals)
1604 {
1605 gate_string_substr(additionals, &item_str, pos2 + 1, GATE_STR_NPOS);
1606 }
1607
1608 gate_string_release(&item_str);
1609
1610 return GATE_RESULT_OK;
1611 }
1612
1613 gate_result_t gate_ui_itemview_set_text(gate_ui_itemview_t* itemview, gate_size_t index,
1614 gate_string_t const* title, gate_string_t const* subtitle, gate_string_t const* additionals)
1615 {
1616 Widget w_item;
1617 XmString xmstr;
1618 gate_string_t old_title = GATE_STRING_INIT_EMPTY;
1619 gate_string_t old_subtitle = GATE_STRING_INIT_EMPTY;
1620 gate_string_t old_add = GATE_STRING_INIT_EMPTY;
1621
1622 GATE_DEBUG_ASSERT(itemview != NULL);
1623
1624 w_item = motif_itemview_get_item_widget(itemview, index);
1625 if (w_item == NULL)
1626 {
1627 return GATE_RESULT_OUTOFBOUNDS;
1628 }
1629
1630 if (!title || !subtitle || !additionals)
1631 {
1632 gate_ui_itemview_get_text(itemview, index, &old_title, &old_subtitle, &old_add);
1633 if (!title) title = &old_title;
1634 if (!subtitle) subtitle = &old_subtitle;
1635 if (!additionals) additionals = &old_add;
1636 }
1637
1638 xmstr = motif_itemview_create_label(title, subtitle, additionals);
1639 XtVaSetValues(w_item, XmNlabelString, xmstr, NULL, NULL);
1640
1641 gate_string_release(&old_title);
1642 gate_string_release(&old_subtitle);
1643 gate_string_release(&old_add);
1644
1645 return GATE_RESULT_OK;
1646 }
1647
1648 gate_bool_t gate_ui_itemview_is_selected(gate_ui_itemview_t* itemview, gate_size_t index)
1649 {
1650 Widget w_iv;
1651 Widget w_item;
1652 Cardinal selcnt = 0;
1653 WidgetList selitems = NULL;
1654 unsigned ndx;
1655
1656 GATE_DEBUG_ASSERT(itemview != NULL);
1657
1658 w_item = motif_itemview_get_item_widget(itemview, index);
1659 if (!w_item)
1660 {
1661 return false;
1662 }
1663
1664 w_iv = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&itemview->ctrl);
1665 if (!w_iv)
1666 {
1667 return false;
1668 }
1669
1670 XtVaGetValues(w_iv, XmNselectedObjectCount, &selcnt, XmNselectedObjects, &selitems, NULL, NULL);
1671 if ((selitems == NULL) || (selcnt == 0))
1672 {
1673 return false;
1674 }
1675 for (ndx = 0; ndx != selcnt; ++ndx)
1676 {
1677 if (selitems[ndx] == w_item)
1678 {
1679 return true;
1680 }
1681 }
1682 return false;
1683 }
1684
1685 gate_result_t gate_ui_itemview_get_selected_item(gate_ui_itemview_t* itemview, gate_size_t* index)
1686 {
1687 Widget w_iv;
1688 Cardinal selcnt = 0;
1689 WidgetList selitems = NULL;
1690
1691 GATE_DEBUG_ASSERT(itemview != NULL);
1692
1693 w_iv = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&itemview->ctrl);
1694 if (!w_iv)
1695 {
1696 return GATE_RESULT_INVALIDSTATE;
1697 }
1698
1699 XtVaGetValues(w_iv, XmNselectedObjectCount, &selcnt, XmNselectedObjects, &selitems, NULL, NULL);
1700 if ((selcnt == 0) || (selitems == NULL))
1701 {
1702 return GATE_RESULT_NOTAVAILABLE;
1703 }
1704
1705 if (index)
1706 {
1707 *index = motif_itemview_resolve_item_widget_index(itemview, selitems[0]);
1708 }
1709 return GATE_RESULT_OK;
1710 }
1711
1712 gate_result_t gate_ui_itemview_select_item(gate_ui_itemview_t* itemview, gate_size_t index)
1713 {
1714 Widget w_iv;
1715 Widget w_item;
1716 Widget sel_widgets[1];
1717
1718 GATE_DEBUG_ASSERT(itemview != NULL);
1719
1720 w_iv = GATE_UI_MOTIF_GET_CTRL_CONTAINER(&itemview->ctrl);
1721 if (!w_iv)
1722 {
1723 return GATE_RESULT_INVALIDSTATE;
1724 }
1725
1726 w_item = motif_itemview_get_item_widget(itemview, index);
1727 if (w_item == NULL)
1728 {
1729 XtVaSetValues(w_iv, XmNselectedObjects, NULL, XmNselectedObjectCount, 0, NULL, NULL);
1730 }
1731 else
1732 {
1733 sel_widgets[0] = w_item;
1734 XtVaSetValues(w_iv, XmNselectedObjects, &sel_widgets[0], XmNselectedObjectCount, 1, NULL, NULL);
1735 }
1736
1737 return GATE_RESULT_OK;
1738 }
1739
1740 #endif /* GATE_UI_MOTIF */
1741