1 /* GuiList.cpp
2 *
3 * Copyright (C) 1993-2020 Paul Boersma, 2013 Tom Naughton
4 *
5 * This code is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 *
10 * This code is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this work. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "GuiP.h"
20
21 Thing_implement (GuiList, GuiControl, 0);
22
23 #if motif
24 #define iam_list \
25 Melder_assert (widget -> widgetClass == xmListWidgetClass); \
26 GuiList me = (GuiList) widget -> userData
27 #endif
28
29 #if gtk
_GuiGtkList_destroyCallback(gpointer void_me)30 static void _GuiGtkList_destroyCallback (gpointer void_me) {
31 iam (GuiList);
32 forget (me);
33 }
_GuiGtkList_selectionChangedCallback(GtkTreeSelection * sel,gpointer void_me)34 static void _GuiGtkList_selectionChangedCallback (GtkTreeSelection *sel, gpointer void_me) {
35 iam (GuiList);
36 if (my d_selectionChangedCallback && ! my d_blockValueChangedCallbacks) {
37 trace (U"Selection changed.");
38 struct structGuiList_SelectionChangedEvent event { me };
39 my d_selectionChangedCallback (my d_selectionChangedBoss, & event);
40 }
41 }
42 #elif motif
_GuiWinList_destroy(GuiObject widget)43 void _GuiWinList_destroy (GuiObject widget) {
44 iam_list;
45 DestroyWindow (widget -> window);
46 forget (me); // NOTE: my widget is not destroyed here
47 }
_GuiWinList_map(GuiObject widget)48 void _GuiWinList_map (GuiObject widget) {
49 iam_list;
50 ShowWindow (widget -> window, SW_SHOW);
51 }
_GuiWinList_handleClick(GuiObject widget)52 void _GuiWinList_handleClick (GuiObject widget) {
53 iam_list;
54 if (my d_selectionChangedCallback) {
55 struct structGuiList_SelectionChangedEvent event { me };
56 my d_selectionChangedCallback (my d_selectionChangedBoss, & event);
57 }
58 }
59 #elif cocoa
60 @implementation GuiCocoaList {
61 GuiList d_userData;
62 }
63
64 /*
65 * Override NSObject methods.
66 */
67 - (void) dealloc {
68 [_contents release];
69 GuiThing me = d_userData;
70 forget (me);
71 //Melder_casual (U"deleting a list");
72 [super dealloc];
73 }
74
75 /*
76 * Override NSView methods.
77 */
78 - (id) initWithFrame: (NSRect) frameRect {
79 self = [super initWithFrame: frameRect];
80 if (self) {
81 _tableView = [[NSTableView alloc] initWithFrame: frameRect];
82 NSTableColumn *tableColumn = [[NSTableColumn alloc] initWithIdentifier: @"list"];
83 tableColumn.width = frameRect. size. width;
84 [tableColumn setEditable: NO];
85 [_tableView addTableColumn: tableColumn];
86
87 _tableView. delegate = self;
88 _tableView. dataSource = self;
89 _tableView. allowsEmptySelection = YES;
90 _tableView. headerView = nil;
91 _tableView. target = self;
92 _tableView. action = @selector (_GuiCocoaList_clicked:);
93
94 NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame: frameRect];
95 [scrollView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
96 [scrollView setBorderType: NSBezelBorder];
97 [scrollView setDocumentView: _tableView]; // this retains the table view
98 [scrollView setHasVerticalScroller: YES];
99 //[scrollView setHasHorizontalScroller: YES];
100
101 [self addSubview: scrollView]; // this retains the scroll view
102 [scrollView release];
103 [_tableView release];
104
105 _contents = [[NSMutableArray alloc] init];
106 }
107 return self;
108 }
109
110 /*
111 * Implement GuiCocoaAny protocol.
112 */
113 - (GuiThing) getUserData {
114 return d_userData;
115 }
116 - (void) setUserData: (GuiThing) userData {
117 Melder_assert (userData == nullptr || Thing_isa (userData, classGuiList));
118 d_userData = static_cast <GuiList> (userData);
119 }
120
121 /*
122 * Implement GuiCocoaList methods.
123 */
124 - (IBAction) _GuiCocoaList_clicked: (id) sender {
125 /*
126 * This method probably shouldn't do anything,
127 * because tableViewSelectionDidChange will already have been called at this point.
128 */
129 (void) sender;
130 trace (U"enter");
131 GuiList me = d_userData;
132 if (me && my d_selectionChangedCallback) {
133 //struct structGuiList_SelectionChangedEvent event { me };
134 //my d_selectionChangedCallback (my d_selectionChangedBoss, & event);
135 }
136 }
137
138 /*
139 * Override TableViewDataSource methods.
140 */
141 - (NSInteger) numberOfRowsInTableView: (NSTableView *) tableView {
142 (void) tableView;
143 return [_contents count];
144 }
145 - (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row {
146 (void) tableColumn;
147 (void) tableView;
148 return [_contents objectAtIndex: row];
149 }
150
151 /*
152 * Override TableViewDelegate methods.
153 */
154 - (void) tableViewSelectionDidChange: (NSNotification *) notification {
155 /*
156 * This is invoked when the user clicks in the table or uses the arrow keys.
157 */
158 (void) notification;
159 trace (U"enter");
160 GuiList me = d_userData;
161 if (me && my d_selectionChangedCallback && ! my d_blockValueChangedCallbacks) {
162 struct structGuiList_SelectionChangedEvent event { me };
163 my d_selectionChangedCallback (my d_selectionChangedBoss, & event);
164 }
165 }
166 @end
167 #endif
168
169 #if gtk
170 enum {
171 COLUMN_STRING,
172 N_COLUMNS
173 };
174 #endif
175
GuiList_create(GuiForm parent,int left,int right,int top,int bottom,bool allowMultipleSelection,conststring32 header)176 GuiList GuiList_create (GuiForm parent, int left, int right, int top, int bottom, bool allowMultipleSelection, conststring32 header) {
177 autoGuiList me = Thing_new (GuiList);
178 my d_shell = parent -> d_shell;
179 my d_parent = parent;
180 my d_allowMultipleSelection = allowMultipleSelection;
181 #if gtk
182 GtkCellRenderer *renderer = nullptr;
183 GtkTreeViewColumn *col = nullptr;
184 GtkTreeSelection *sel = nullptr;
185 GtkListStore *liststore = nullptr;
186
187 liststore = gtk_list_store_new (1, G_TYPE_STRING); // 1 column, of type String (this is a vararg list)
188 GuiObject scrolled = gtk_scrolled_window_new (nullptr, nullptr);
189 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
190 my d_widget = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore));
191 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (my d_widget), false);
192 gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (my d_widget));
193 gtk_widget_show (GTK_WIDGET (scrolled)); // BUG
194 gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (my d_widget), allowMultipleSelection ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE);
195 g_object_unref (liststore); // Destroys the widget after the list is destroyed
196
197 _GuiObject_setUserData (my d_widget, me.get());
198 _GuiObject_setUserData (scrolled, me.get()); // for resizing
199
200 renderer = gtk_cell_renderer_text_new ();
201 col = gtk_tree_view_column_new ();
202 gtk_tree_view_column_pack_start (col, renderer, true);
203 gtk_tree_view_column_add_attribute (col, renderer, "text", 0); // zeroeth column
204 if (header) {
205 //gtk_tree_view_column_set_title (col, Melder_peek32to8 (header));
206 }
207 gtk_tree_view_append_column (GTK_TREE_VIEW (my d_widget), col);
208
209 g_object_set_data_full (G_OBJECT (my d_widget), "guiList", me.get(), (GDestroyNotify) _GuiGtkList_destroyCallback);
210
211 /* GtkCellRenderer *renderer;
212 GtkTreeViewColumn *col;
213
214 my widget = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore));
215
216 renderer = gtk_cell_renderer_text_new ();
217 col = gtk_tree_view_column_new ();
218 gtk_tree_view_column_pack_start (col, renderer, true);
219 gtk_tree_view_column_add_attribute (col, renderer, "text", COL_ID);
220 gtk_tree_view_column_set_title (col, " ID ");
221 gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
222
223 renderer = gtk_cell_renderer_text_new ();
224 col = gtk_tree_view_column_new ();
225 gtk_tree_view_column_pack_start (col, renderer, true);
226 gtk_tree_view_column_add_attribute (col, renderer, "text", COL_TYPE);
227 gtk_tree_view_column_set_title (col, " Type ");
228 gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
229
230 renderer = gtk_cell_renderer_text_new ();
231 col = gtk_tree_view_column_new ();
232 gtk_tree_view_column_pack_start (col, renderer, true);
233 gtk_tree_view_column_add_attribute (col, renderer, "text", COL_NAME);
234 gtk_tree_view_column_set_title (col, " Name ");
235 gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
236 */
237
238 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (my d_widget));
239 if (allowMultipleSelection) {
240 gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
241 } else {
242 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
243 }
244 my v_positionInForm (scrolled, left, right, top, bottom, parent);
245 g_signal_connect (sel, "changed", G_CALLBACK (_GuiGtkList_selectionChangedCallback), me.get());
246 #elif motif
247 my d_widget = _Gui_initializeWidget (xmListWidgetClass, parent -> d_widget, U"list");
248 _GuiObject_setUserData (my d_widget, me.get());
249 my d_widget -> window = CreateWindowEx (0, L"listbox", L"list",
250 WS_CHILD | WS_BORDER | WS_VSCROLL | LBS_NOTIFY | WS_CLIPSIBLINGS |
251 ( allowMultipleSelection ? LBS_EXTENDEDSEL : 0 ),
252 my d_widget -> x, my d_widget -> y, my d_widget -> width, my d_widget -> height,
253 my d_widget -> parent -> window, nullptr, theGui.instance, nullptr);
254 SetWindowLongPtr (my d_widget -> window, GWLP_USERDATA, (LONG_PTR) my d_widget);
255 SetWindowFont (my d_widget -> window, GetStockFont (ANSI_VAR_FONT), false);
256 /*if (MEMBER (my parent, ScrolledWindow)) {
257 XtDestroyWidget (my d_widget -> parent -> motiff.scrolledWindow.horizontalBar);
258 my d_widget -> parent -> motiff.scrolledWindow.horizontalBar = nullptr;
259 XtDestroyWidget (my d_widget -> parent -> motiff.scrolledWindow.verticalBar);
260 my d_widget -> parent -> motiff.scrolledWindow.verticalBar = nullptr;
261 }*/
262 my v_positionInForm (my d_widget, left, right, top, bottom, parent);
263 #elif cocoa
264 (void) header;
265 GuiCocoaList *list = [[GuiCocoaList alloc] init];
266 my d_widget = (GuiObject) list;
267 my v_positionInForm (my d_widget, left, right, top, bottom, parent);
268 [[list tableView] setAllowsMultipleSelection: allowMultipleSelection];
269 [list setUserData: me.get()];
270 #endif
271 return me.releaseToAmbiguousOwner();
272 }
273
GuiList_createShown(GuiForm parent,int left,int right,int top,int bottom,bool allowMultipleSelection,conststring32 header)274 GuiList GuiList_createShown (GuiForm parent, int left, int right, int top, int bottom, bool allowMultipleSelection, conststring32 header) {
275 GuiList me = GuiList_create (parent, left, right, top, bottom, allowMultipleSelection, header);
276 GuiThing_show (me);
277 return me;
278 }
279
GuiList_deleteAllItems(GuiList me)280 void GuiList_deleteAllItems (GuiList me) {
281 GuiControlBlockValueChangedCallbacks block (me);
282 #if gtk
283 GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (my d_widget)));
284 gtk_list_store_clear (list_store);
285 #elif motif
286 ListBox_ResetContent (my d_widget -> window);
287 #elif cocoa
288 GuiCocoaList *list = (GuiCocoaList *) my d_widget;
289 [list. contents removeAllObjects];
290 [list. tableView reloadData];
291 #endif
292 }
293
GuiList_deleteItem(GuiList me,integer position)294 void GuiList_deleteItem (GuiList me, integer position) {
295 Melder_assert (position >= 1); // so that we can subtract 1 even if the result has to be unsigned
296 GuiControlBlockValueChangedCallbacks block (me);
297 #if gtk
298 GtkTreeIter iter;
299 GtkTreeModel *tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (my d_widget));
300 if (gtk_tree_model_iter_nth_child (tree_model, & iter, nullptr, (gint) (position - 1))) {
301 gtk_list_store_remove (GTK_LIST_STORE (tree_model), & iter);
302 }
303 #elif motif
304 ListBox_DeleteString (my d_widget -> window, position - 1);
305 #elif cocoa
306 GuiCocoaList *list = (GuiCocoaList *) my d_widget;
307 [list. contents removeObjectAtIndex: (NSUInteger) (position - 1)];
308 [list. tableView reloadData];
309 #endif
310 }
311
GuiList_deselectAllItems(GuiList me)312 void GuiList_deselectAllItems (GuiList me) {
313 GuiControlBlockValueChangedCallbacks block (me);
314 #if gtk
315 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (my d_widget));
316 gtk_tree_selection_unselect_all (selection);
317 #elif motif
318 ListBox_SetSel (my d_widget -> window, False, -1);
319 #elif cocoa
320 GuiCocoaList *list = (GuiCocoaList *) my d_widget;
321 [list. tableView deselectAll: nil];
322 #endif
323 }
324
GuiList_deselectItem(GuiList me,integer position)325 void GuiList_deselectItem (GuiList me, integer position) {
326 Melder_assert (position >= 1); // so that we can subtract 1 even if the result has to be unsigned
327 GuiControlBlockValueChangedCallbacks block (me);
328 #if gtk
329 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (my d_widget));
330 // GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (my d_widget)));
331 // GtkTreePath *path = gtk_tree_path_new_from_indices ((gint) position, -1 /* terminator */);
332 GtkTreeIter iter;
333 // gtk_tree_model_get_iter (GTK_TREE_MODEL (list_store), & iter, path);
334 // gtk_tree_path_free (path);
335 GtkTreeModel *tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (my d_widget));
336 if (gtk_tree_model_iter_nth_child (tree_model, & iter, nullptr, (gint) (position - 1))) {
337 gtk_tree_selection_unselect_iter (selection, & iter);
338 }
339 #elif motif
340 ListBox_SetSel (my d_widget -> window, False, position - 1);
341 #elif cocoa
342 GuiCocoaList *list = (GuiCocoaList *) my d_widget;
343 [list. tableView deselectRow: position - 1];
344 #endif
345 }
346
GuiList_getSelectedPositions(GuiList me)347 autoINTVEC GuiList_getSelectedPositions (GuiList me) {
348 autoINTVEC selectedPositions;
349 #if gtk
350 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (my d_widget));
351 GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (my d_widget)));
352 int n = gtk_tree_selection_count_selected_rows (selection);
353 if (n > 0) {
354 GList *list = gtk_tree_selection_get_selected_rows (selection, (GtkTreeModel **) & list_store);
355 integer ipos = 1;
356 selectedPositions = zero_INTVEC (n);
357 for (GList *l = g_list_first (list); l != nullptr; l = g_list_next (l)) {
358 gint *index = gtk_tree_path_get_indices ((GtkTreePath *) l -> data);
359 selectedPositions [ipos] = index [0] + 1;
360 ipos ++;
361 }
362 g_list_foreach (list, (GFunc) gtk_tree_path_free, nullptr);
363 g_list_free (list);
364 }
365 return selectedPositions;
366 #elif motif
367 int n = ListBox_GetSelCount (my d_widget -> window), *indices;
368 if (n == 0)
369 return selectedPositions;
370 if (n == -1) { // single selection
371 int selection = ListBox_GetCurSel (my d_widget -> window);
372 if (selection == -1)
373 return selectedPositions;
374 n = 1;
375 indices = Melder_calloc_f (int, n);
376 indices [0] = selection;
377 } else {
378 indices = Melder_calloc_f (int, n);
379 ListBox_GetSelItems (my d_widget -> window, n, indices);
380 }
381 selectedPositions = zero_INTVEC (n);
382 for (integer ipos = 1; ipos <= n; ipos ++)
383 selectedPositions [ipos] = indices [ipos - 1] + 1; // convert from zero-based list of zero-based indices
384 Melder_free (indices);
385 #elif cocoa
386 GuiCocoaList *list = (GuiCocoaList *) my d_widget;
387 NSIndexSet *indexSet = [list. tableView selectedRowIndexes];
388 selectedPositions = zero_INTVEC (uinteger_to_integer ([indexSet count]));
389 NSUInteger currentIndex = [indexSet firstIndex];
390 integer ipos = 0;
391 while (currentIndex != NSNotFound) {
392 selectedPositions [++ ipos] = uinteger_to_integer (currentIndex + 1);
393 currentIndex = [indexSet indexGreaterThanIndex: currentIndex];
394 }
395 Melder_assert (ipos == selectedPositions.size);
396 #endif
397 return selectedPositions;
398 }
399
GuiList_getBottomPosition(GuiList me)400 integer GuiList_getBottomPosition (GuiList me) {
401 #if gtk
402 GtkTreePath *path;
403 integer position = 1;
404 if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (my d_widget), nullptr, & path)) {
405 int *indices = gtk_tree_path_get_indices (path);
406 position = indices ? indices[0] + 1 : 1;
407 gtk_tree_path_free (path); // also frees indices !!
408 }
409 trace (U"bottom: ", position);
410 return position;
411 #elif motif
412 integer bottom = ListBox_GetTopIndex (my d_widget -> window) + my d_widget -> height / ListBox_GetItemHeight (my d_widget -> window, 0);
413 if (bottom < 1) bottom = 1;
414 integer n = ListBox_GetCount (my d_widget -> window);
415 if (bottom > n) bottom = n;
416 return bottom;
417 #elif cocoa
418 return 1; // TODO
419 #else
420 return 0;
421 #endif
422 }
423
GuiList_getNumberOfItems(GuiList me)424 integer GuiList_getNumberOfItems (GuiList me) {
425 integer numberOfItems = 0;
426 #if gtk
427 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (my d_widget));
428 numberOfItems = gtk_tree_model_iter_n_children (model, nullptr);
429 #elif motif
430 numberOfItems = ListBox_GetCount (my d_widget -> window);
431 #elif cocoa
432 GuiCocoaList *list = (GuiCocoaList *) my d_widget;
433 numberOfItems = [[list contents] count];
434 #endif
435 return numberOfItems;
436 }
437
GuiList_getTopPosition(GuiList me)438 integer GuiList_getTopPosition (GuiList me) {
439 #if gtk
440 GtkTreePath *path;
441 integer position = 1;
442 if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (my d_widget), & path, nullptr)) {
443 int *indices = gtk_tree_path_get_indices (path);
444 position = indices ? indices[0] + 1 : 1;
445 gtk_tree_path_free (path); // also frees indices !!
446 }
447 trace (U"top: ", position);
448 return position;
449 #elif motif
450 integer top = ListBox_GetTopIndex (my d_widget -> window);
451 if (top < 1) top = 1;
452 integer n = ListBox_GetCount (my d_widget -> window);
453 if (top > n) top = 0;
454 return top;
455 #elif cocoa
456 return 1; // TODO
457 #else
458 return 0;
459 #endif
460 }
461
GuiList_insertItem(GuiList me,conststring32 itemText,integer position_base1)462 void GuiList_insertItem (GuiList me, conststring32 itemText /* cattable */, integer position_base1) {
463 bool explicitlyInsertAtEnd = ( position_base1 <= 0 );
464 GuiControlBlockValueChangedCallbacks block (me);
465 #if gtk
466 GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (my d_widget)));
467 gtk_list_store_insert_with_values (list_store, nullptr, explicitlyInsertAtEnd ? 1000000000 : (gint) position_base1 - 1, COLUMN_STRING, Melder_peek32to8 (itemText), -1);
468 // TODO: Tekst opsplitsen
469 // does GTK know the '0' trick?
470 // it does know about nullptr, to append in another function
471 #elif motif
472 HWND nativeList = my d_widget -> window;
473 conststringW nativeItemText = Melder_peek32toW (itemText);
474 if (explicitlyInsertAtEnd) {
475 ListBox_AddString (nativeList, nativeItemText);
476 } else {
477 int nativePosition_base0 = position_base1 - 1;
478 ListBox_InsertString (nativeList, nativePosition_base0, nativeItemText);
479 }
480 #elif cocoa
481 GuiCocoaList *nativeList = (GuiCocoaList *) my d_widget;
482 NSString *nativeItemText = [[NSString alloc] initWithUTF8String: Melder_peek32to8 (itemText)];
483 if (explicitlyInsertAtEnd) {
484 [[nativeList contents] addObject: nativeItemText];
485 } else {
486 NSUInteger nativePosition_base0 = (uinteger) position_base1 - 1;
487 [[nativeList contents] insertObject: nativeItemText atIndex: nativePosition_base0];
488 }
489 [nativeItemText release];
490 [[nativeList tableView] reloadData];
491 #endif
492 }
493
GuiList_replaceItem(GuiList me,conststring32 itemText,integer position)494 void GuiList_replaceItem (GuiList me, conststring32 itemText, integer position) {
495 GuiControlBlockValueChangedCallbacks block (me);
496 #if gtk
497 GtkTreeIter iter;
498 GtkTreeModel *tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (my d_widget));
499 if (gtk_tree_model_iter_nth_child (tree_model, & iter, nullptr, (gint) (position - 1))) {
500 gtk_list_store_set (GTK_LIST_STORE (tree_model), & iter, COLUMN_STRING, Melder_peek32to8 (itemText), -1);
501 }
502 /*
503 GtkTreePath *path = gtk_tree_path_new_from_indices ((gint) position, -1); // -1 = terminator
504 GtkTreeIter iter;
505 GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (my d_widget)));
506 gtk_tree_model_get_iter (GTK_TREE_MODEL (list_store), & iter, path);
507 gtk_tree_path_free (path);*/
508 // gtk_list_store_set (list_store, & iter, 0, Melder_peek32to8 (itemText), -1);
509 // TODO: Tekst opsplitsen
510 #elif motif
511 integer nativePosition = position - 1; // convert from 1-based to zero-based
512 ListBox_DeleteString (my d_widget -> window, nativePosition);
513 ListBox_InsertString (my d_widget -> window, nativePosition, Melder_peek32toW (itemText));
514 #elif cocoa
515 GuiCocoaList *list = (GuiCocoaList *) my d_widget;
516 NSString *nsString = [[NSString alloc] initWithUTF8String: Melder_peek32to8 (itemText)];
517 [[list contents] replaceObjectAtIndex: position - 1 withObject: nsString];
518 [nsString release];
519 [[list tableView] reloadData];
520 #endif
521 }
522
GuiList_selectItem(GuiList me,integer position)523 void GuiList_selectItem (GuiList me, integer position) {
524 Melder_assert (position >= 1); // so that we can subtract 1 even if the result has to be unsigned
525 GuiControlBlockValueChangedCallbacks block (me);
526 #if gtk
527 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (my d_widget));
528 GtkTreePath *path = gtk_tree_path_new_from_indices ((gint) position - 1, -1 /* terminator */);
529 gtk_tree_selection_select_path (selection, path);
530 gtk_tree_path_free (path);
531
532 // TODO: check of het bovenstaande werkt, dan kan dit weg
533 // GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (my d_widget)));
534 // GtkTreePath *path = gtk_tree_path_new_from_indices ((gint) position, -1 /* terminator */);
535 // GtkTreeIter iter;
536 // gtk_tree_model_get_iter (GTK_TREE_MODEL (list_store), & iter, path);
537 // gtk_tree_selection_select_iter (selection, & iter);
538 #elif motif
539 if (! my d_allowMultipleSelection) {
540 ListBox_SetCurSel (my d_widget -> window, position - 1);
541 } else {
542 ListBox_SetSel (my d_widget -> window, True, position - 1);
543 }
544 #elif cocoa
545 NSIndexSet *indexSet = [[NSIndexSet alloc] initWithIndex: NSUInteger (position - 1)];
546 GuiCocoaList *list = (GuiCocoaList *) my d_widget;
547 [[list tableView] selectRowIndexes: indexSet byExtendingSelection: my d_allowMultipleSelection];
548 [indexSet release];
549 #endif
550 }
551
GuiList_setSelectionChangedCallback(GuiList me,GuiList_SelectionChangedCallback callback,Thing boss)552 void GuiList_setSelectionChangedCallback (GuiList me, GuiList_SelectionChangedCallback callback, Thing boss) {
553 my d_selectionChangedCallback = callback;
554 my d_selectionChangedBoss = boss;
555 }
556
GuiList_setDoubleClickCallback(GuiList me,GuiList_DoubleClickCallback callback,Thing boss)557 void GuiList_setDoubleClickCallback (GuiList me, GuiList_DoubleClickCallback callback, Thing boss) {
558 my d_doubleClickCallback = callback;
559 my d_doubleClickBoss = boss;
560 }
561
GuiList_setScrollCallback(GuiList me,GuiList_ScrollCallback callback,Thing boss)562 void GuiList_setScrollCallback (GuiList me, GuiList_ScrollCallback callback, Thing boss) {
563 my d_scrollCallback = callback;
564 my d_scrollBoss = boss;
565 }
566
GuiList_setTopPosition(GuiList me,integer topPosition)567 void GuiList_setTopPosition (GuiList me, integer topPosition) {
568 trace (U"Set top position ", topPosition);
569 #if gtk
570 // GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (my md_widget)));
571 GtkTreePath *path = gtk_tree_path_new_from_indices ((gint) topPosition, -1 /* terminator */); // BUG?
572 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (my d_widget), path, nullptr, false, 0.0, 0.0);
573 gtk_tree_path_free (path);
574 #elif motif
575 ListBox_SetTopIndex (my d_widget -> window, topPosition - 1);
576 #elif cocoa
577 // TODO: implement
578 #endif
579 }
580
581 /* End of file GuiList.cpp */
582