GuiList.cpp 22 KB

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