1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module gtk.ListBox;
26 
27 private import gio.ListModelIF;
28 private import glib.ConstructionException;
29 private import glib.ListG;
30 private import gobject.ObjectG;
31 private import gobject.Signals;
32 private import gtk.Adjustment;
33 private import gtk.Container;
34 private import gtk.ListBoxRow;
35 private import gtk.Widget;
36 private import gtk.c.functions;
37 public  import gtk.c.types;
38 public  import gtkc.gtktypes;
39 private import std.algorithm;
40 
41 
42 /**
43  * A GtkListBox is a vertical container that contains GtkListBoxRow
44  * children. These rows can by dynamically sorted and filtered, and
45  * headers can be added dynamically depending on the row content.
46  * It also allows keyboard and mouse navigation and selection like
47  * a typical list.
48  * 
49  * Using GtkListBox is often an alternative to #GtkTreeView, especially
50  * when the list contents has a more complicated layout than what is allowed
51  * by a #GtkCellRenderer, or when the contents is interactive (i.e. has a
52  * button in it).
53  * 
54  * Although a #GtkListBox must have only #GtkListBoxRow children you can
55  * add any kind of widget to it via gtk_container_add(), and a #GtkListBoxRow
56  * widget will automatically be inserted between the list and the widget.
57  * 
58  * #GtkListBoxRows can be marked as activatable or selectable. If a row
59  * is activatable, #GtkListBox::row-activated will be emitted for it when
60  * the user tries to activate it. If it is selectable, the row will be marked
61  * as selected when the user tries to select it.
62  * 
63  * The GtkListBox widget was added in GTK+ 3.10.
64  * 
65  * # CSS nodes
66  * 
67  * |[<!-- language="plain" -->
68  * list
69  * ╰── row[.activatable]
70  * ]|
71  * 
72  * GtkListBox uses a single CSS node named list. Each GtkListBoxRow uses
73  * a single CSS node named row. The row nodes get the .activatable
74  * style class added when appropriate.
75  */
76 public class ListBox : Container
77 {
78 	/** the main Gtk struct */
79 	protected GtkListBox* gtkListBox;
80 
81 	/** Get the main Gtk struct */
82 	public GtkListBox* getListBoxStruct(bool transferOwnership = false)
83 	{
84 		if (transferOwnership)
85 			ownedRef = false;
86 		return gtkListBox;
87 	}
88 
89 	/** the main Gtk struct as a void* */
90 	protected override void* getStruct()
91 	{
92 		return cast(void*)gtkListBox;
93 	}
94 
95 	/**
96 	 * Sets our main struct and passes it to the parent class.
97 	 */
98 	public this (GtkListBox* gtkListBox, bool ownedRef = false)
99 	{
100 		this.gtkListBox = gtkListBox;
101 		super(cast(GtkContainer*)gtkListBox, ownedRef);
102 	}
103 
104 
105 	/** */
106 	public static GType getType()
107 	{
108 		return gtk_list_box_get_type();
109 	}
110 
111 	/**
112 	 * Creates a new #GtkListBox container.
113 	 *
114 	 * Returns: a new #GtkListBox
115 	 *
116 	 * Since: 3.10
117 	 *
118 	 * Throws: ConstructionException GTK+ fails to create the object.
119 	 */
120 	public this()
121 	{
122 		auto p = gtk_list_box_new();
123 
124 		if(p is null)
125 		{
126 			throw new ConstructionException("null returned by new");
127 		}
128 
129 		this(cast(GtkListBox*) p);
130 	}
131 
132 	/**
133 	 * Binds @model to @box.
134 	 *
135 	 * If @box was already bound to a model, that previous binding is
136 	 * destroyed.
137 	 *
138 	 * The contents of @box are cleared and then filled with widgets that
139 	 * represent items from @model. @box is updated whenever @model changes.
140 	 * If @model is %NULL, @box is left empty.
141 	 *
142 	 * It is undefined to add or remove widgets directly (for example, with
143 	 * gtk_list_box_insert() or gtk_container_add()) while @box is bound to a
144 	 * model.
145 	 *
146 	 * Note that using a model is incompatible with the filtering and sorting
147 	 * functionality in GtkListBox. When using a model, filtering and sorting
148 	 * should be implemented by the model.
149 	 *
150 	 * Params:
151 	 *     model = the #GListModel to be bound to @box
152 	 *     createWidgetFunc = a function that creates widgets for items
153 	 *         or %NULL in case you also passed %NULL as @model
154 	 *     userData = user data passed to @create_widget_func
155 	 *     userDataFreeFunc = function for freeing @user_data
156 	 *
157 	 * Since: 3.16
158 	 */
159 	public void bindModel(ListModelIF model, GtkListBoxCreateWidgetFunc createWidgetFunc, void* userData, GDestroyNotify userDataFreeFunc)
160 	{
161 		gtk_list_box_bind_model(gtkListBox, (model is null) ? null : model.getListModelStruct(), createWidgetFunc, userData, userDataFreeFunc);
162 	}
163 
164 	/**
165 	 * This is a helper function for implementing DnD onto a #GtkListBox.
166 	 * The passed in @row will be highlighted via gtk_drag_highlight(),
167 	 * and any previously highlighted row will be unhighlighted.
168 	 *
169 	 * The row will also be unhighlighted when the widget gets
170 	 * a drag leave event.
171 	 *
172 	 * Params:
173 	 *     row = a #GtkListBoxRow
174 	 *
175 	 * Since: 3.10
176 	 */
177 	public void dragHighlightRow(ListBoxRow row)
178 	{
179 		gtk_list_box_drag_highlight_row(gtkListBox, (row is null) ? null : row.getListBoxRowStruct());
180 	}
181 
182 	/**
183 	 * If a row has previously been highlighted via gtk_list_box_drag_highlight_row()
184 	 * it will have the highlight removed.
185 	 *
186 	 * Since: 3.10
187 	 */
188 	public void dragUnhighlightRow()
189 	{
190 		gtk_list_box_drag_unhighlight_row(gtkListBox);
191 	}
192 
193 	/**
194 	 * Returns whether rows activate on single clicks.
195 	 *
196 	 * Returns: %TRUE if rows are activated on single click, %FALSE otherwise
197 	 *
198 	 * Since: 3.10
199 	 */
200 	public bool getActivateOnSingleClick()
201 	{
202 		return gtk_list_box_get_activate_on_single_click(gtkListBox) != 0;
203 	}
204 
205 	/**
206 	 * Gets the adjustment (if any) that the widget uses to
207 	 * for vertical scrolling.
208 	 *
209 	 * Returns: the adjustment
210 	 *
211 	 * Since: 3.10
212 	 */
213 	public Adjustment getAdjustment()
214 	{
215 		auto p = gtk_list_box_get_adjustment(gtkListBox);
216 
217 		if(p is null)
218 		{
219 			return null;
220 		}
221 
222 		return ObjectG.getDObject!(Adjustment)(cast(GtkAdjustment*) p);
223 	}
224 
225 	/**
226 	 * Gets the n-th child in the list (not counting headers).
227 	 * If @_index is negative or larger than the number of items in the
228 	 * list, %NULL is returned.
229 	 *
230 	 * Params:
231 	 *     index = the index of the row
232 	 *
233 	 * Returns: the child #GtkWidget or %NULL
234 	 *
235 	 * Since: 3.10
236 	 */
237 	public ListBoxRow getRowAtIndex(int index)
238 	{
239 		auto p = gtk_list_box_get_row_at_index(gtkListBox, index);
240 
241 		if(p is null)
242 		{
243 			return null;
244 		}
245 
246 		return ObjectG.getDObject!(ListBoxRow)(cast(GtkListBoxRow*) p);
247 	}
248 
249 	/**
250 	 * Gets the row at the @y position.
251 	 *
252 	 * Params:
253 	 *     y = position
254 	 *
255 	 * Returns: the row or %NULL
256 	 *     in case no row exists for the given y coordinate.
257 	 *
258 	 * Since: 3.10
259 	 */
260 	public ListBoxRow getRowAtY(int y)
261 	{
262 		auto p = gtk_list_box_get_row_at_y(gtkListBox, y);
263 
264 		if(p is null)
265 		{
266 			return null;
267 		}
268 
269 		return ObjectG.getDObject!(ListBoxRow)(cast(GtkListBoxRow*) p);
270 	}
271 
272 	/**
273 	 * Gets the selected row.
274 	 *
275 	 * Note that the box may allow multiple selection, in which
276 	 * case you should use gtk_list_box_selected_foreach() to
277 	 * find all selected rows.
278 	 *
279 	 * Returns: the selected row
280 	 *
281 	 * Since: 3.10
282 	 */
283 	public ListBoxRow getSelectedRow()
284 	{
285 		auto p = gtk_list_box_get_selected_row(gtkListBox);
286 
287 		if(p is null)
288 		{
289 			return null;
290 		}
291 
292 		return ObjectG.getDObject!(ListBoxRow)(cast(GtkListBoxRow*) p);
293 	}
294 
295 	/**
296 	 * Creates a list of all selected children.
297 	 *
298 	 * Returns: A #GList containing the #GtkWidget for each selected child.
299 	 *     Free with g_list_free() when done.
300 	 *
301 	 * Since: 3.14
302 	 */
303 	public ListG getSelectedRows()
304 	{
305 		auto p = gtk_list_box_get_selected_rows(gtkListBox);
306 
307 		if(p is null)
308 		{
309 			return null;
310 		}
311 
312 		return new ListG(cast(GList*) p);
313 	}
314 
315 	/**
316 	 * Gets the selection mode of the listbox.
317 	 *
318 	 * Returns: a #GtkSelectionMode
319 	 *
320 	 * Since: 3.10
321 	 */
322 	public GtkSelectionMode getSelectionMode()
323 	{
324 		return gtk_list_box_get_selection_mode(gtkListBox);
325 	}
326 
327 	/**
328 	 * Insert the @child into the @box at @position. If a sort function is
329 	 * set, the widget will actually be inserted at the calculated position and
330 	 * this function has the same effect of gtk_container_add().
331 	 *
332 	 * If @position is -1, or larger than the total number of items in the
333 	 * @box, then the @child will be appended to the end.
334 	 *
335 	 * Params:
336 	 *     child = the #GtkWidget to add
337 	 *     position = the position to insert @child in
338 	 *
339 	 * Since: 3.10
340 	 */
341 	public void insert(Widget child, int position)
342 	{
343 		gtk_list_box_insert(gtkListBox, (child is null) ? null : child.getWidgetStruct(), position);
344 	}
345 
346 	/**
347 	 * Update the filtering for all rows. Call this when result
348 	 * of the filter function on the @box is changed due
349 	 * to an external factor. For instance, this would be used
350 	 * if the filter function just looked for a specific search
351 	 * string and the entry with the search string has changed.
352 	 *
353 	 * Since: 3.10
354 	 */
355 	public void invalidateFilter()
356 	{
357 		gtk_list_box_invalidate_filter(gtkListBox);
358 	}
359 
360 	/**
361 	 * Update the separators for all rows. Call this when result
362 	 * of the header function on the @box is changed due
363 	 * to an external factor.
364 	 *
365 	 * Since: 3.10
366 	 */
367 	public void invalidateHeaders()
368 	{
369 		gtk_list_box_invalidate_headers(gtkListBox);
370 	}
371 
372 	/**
373 	 * Update the sorting for all rows. Call this when result
374 	 * of the sort function on the @box is changed due
375 	 * to an external factor.
376 	 *
377 	 * Since: 3.10
378 	 */
379 	public void invalidateSort()
380 	{
381 		gtk_list_box_invalidate_sort(gtkListBox);
382 	}
383 
384 	/**
385 	 * Prepend a widget to the list. If a sort function is set, the widget will
386 	 * actually be inserted at the calculated position and this function has the
387 	 * same effect of gtk_container_add().
388 	 *
389 	 * Params:
390 	 *     child = the #GtkWidget to add
391 	 *
392 	 * Since: 3.10
393 	 */
394 	public void prepend(Widget child)
395 	{
396 		gtk_list_box_prepend(gtkListBox, (child is null) ? null : child.getWidgetStruct());
397 	}
398 
399 	/**
400 	 * Select all children of @box, if the selection mode allows it.
401 	 *
402 	 * Since: 3.14
403 	 */
404 	public void selectAll()
405 	{
406 		gtk_list_box_select_all(gtkListBox);
407 	}
408 
409 	/**
410 	 * Make @row the currently selected row.
411 	 *
412 	 * Params:
413 	 *     row = The row to select or %NULL
414 	 *
415 	 * Since: 3.10
416 	 */
417 	public void selectRow(ListBoxRow row)
418 	{
419 		gtk_list_box_select_row(gtkListBox, (row is null) ? null : row.getListBoxRowStruct());
420 	}
421 
422 	/**
423 	 * Calls a function for each selected child.
424 	 *
425 	 * Note that the selection cannot be modified from within this function.
426 	 *
427 	 * Params:
428 	 *     func = the function to call for each selected child
429 	 *     data = user data to pass to the function
430 	 *
431 	 * Since: 3.14
432 	 */
433 	public void selectedForeach(GtkListBoxForeachFunc func, void* data)
434 	{
435 		gtk_list_box_selected_foreach(gtkListBox, func, data);
436 	}
437 
438 	/**
439 	 * If @single is %TRUE, rows will be activated when you click on them,
440 	 * otherwise you need to double-click.
441 	 *
442 	 * Params:
443 	 *     single = a boolean
444 	 *
445 	 * Since: 3.10
446 	 */
447 	public void setActivateOnSingleClick(bool single)
448 	{
449 		gtk_list_box_set_activate_on_single_click(gtkListBox, single);
450 	}
451 
452 	/**
453 	 * Sets the adjustment (if any) that the widget uses to
454 	 * for vertical scrolling. For instance, this is used
455 	 * to get the page size for PageUp/Down key handling.
456 	 *
457 	 * In the normal case when the @box is packed inside
458 	 * a #GtkScrolledWindow the adjustment from that will
459 	 * be picked up automatically, so there is no need
460 	 * to manually do that.
461 	 *
462 	 * Params:
463 	 *     adjustment = the adjustment, or %NULL
464 	 *
465 	 * Since: 3.10
466 	 */
467 	public void setAdjustment(Adjustment adjustment)
468 	{
469 		gtk_list_box_set_adjustment(gtkListBox, (adjustment is null) ? null : adjustment.getAdjustmentStruct());
470 	}
471 
472 	/**
473 	 * By setting a filter function on the @box one can decide dynamically which
474 	 * of the rows to show. For instance, to implement a search function on a list that
475 	 * filters the original list to only show the matching rows.
476 	 *
477 	 * The @filter_func will be called for each row after the call, and it will
478 	 * continue to be called each time a row changes (via gtk_list_box_row_changed()) or
479 	 * when gtk_list_box_invalidate_filter() is called.
480 	 *
481 	 * Note that using a filter function is incompatible with using a model
482 	 * (see gtk_list_box_bind_model()).
483 	 *
484 	 * Params:
485 	 *     filterFunc = callback that lets you filter which rows to show
486 	 *     userData = user data passed to @filter_func
487 	 *     destroy = destroy notifier for @user_data
488 	 *
489 	 * Since: 3.10
490 	 */
491 	public void setFilterFunc(GtkListBoxFilterFunc filterFunc, void* userData, GDestroyNotify destroy)
492 	{
493 		gtk_list_box_set_filter_func(gtkListBox, filterFunc, userData, destroy);
494 	}
495 
496 	/**
497 	 * By setting a header function on the @box one can dynamically add headers
498 	 * in front of rows, depending on the contents of the row and its position in the list.
499 	 * For instance, one could use it to add headers in front of the first item of a
500 	 * new kind, in a list sorted by the kind.
501 	 *
502 	 * The @update_header can look at the current header widget using gtk_list_box_row_get_header()
503 	 * and either update the state of the widget as needed, or set a new one using
504 	 * gtk_list_box_row_set_header(). If no header is needed, set the header to %NULL.
505 	 *
506 	 * Note that you may get many calls @update_header to this for a particular row when e.g.
507 	 * changing things that don’t affect the header. In this case it is important for performance
508 	 * to not blindly replace an existing header with an identical one.
509 	 *
510 	 * The @update_header function will be called for each row after the call, and it will
511 	 * continue to be called each time a row changes (via gtk_list_box_row_changed()) and when
512 	 * the row before changes (either by gtk_list_box_row_changed() on the previous row, or when
513 	 * the previous row becomes a different row). It is also called for all rows when
514 	 * gtk_list_box_invalidate_headers() is called.
515 	 *
516 	 * Params:
517 	 *     updateHeader = callback that lets you add row headers
518 	 *     userData = user data passed to @update_header
519 	 *     destroy = destroy notifier for @user_data
520 	 *
521 	 * Since: 3.10
522 	 */
523 	public void setHeaderFunc(GtkListBoxUpdateHeaderFunc updateHeader, void* userData, GDestroyNotify destroy)
524 	{
525 		gtk_list_box_set_header_func(gtkListBox, updateHeader, userData, destroy);
526 	}
527 
528 	/**
529 	 * Sets the placeholder widget that is shown in the list when
530 	 * it doesn't display any visible children.
531 	 *
532 	 * Params:
533 	 *     placeholder = a #GtkWidget or %NULL
534 	 *
535 	 * Since: 3.10
536 	 */
537 	public void setPlaceholder(Widget placeholder)
538 	{
539 		gtk_list_box_set_placeholder(gtkListBox, (placeholder is null) ? null : placeholder.getWidgetStruct());
540 	}
541 
542 	/**
543 	 * Sets how selection works in the listbox.
544 	 * See #GtkSelectionMode for details.
545 	 *
546 	 * Params:
547 	 *     mode = The #GtkSelectionMode
548 	 *
549 	 * Since: 3.10
550 	 */
551 	public void setSelectionMode(GtkSelectionMode mode)
552 	{
553 		gtk_list_box_set_selection_mode(gtkListBox, mode);
554 	}
555 
556 	/**
557 	 * By setting a sort function on the @box one can dynamically reorder the rows
558 	 * of the list, based on the contents of the rows.
559 	 *
560 	 * The @sort_func will be called for each row after the call, and will continue to
561 	 * be called each time a row changes (via gtk_list_box_row_changed()) and when
562 	 * gtk_list_box_invalidate_sort() is called.
563 	 *
564 	 * Note that using a sort function is incompatible with using a model
565 	 * (see gtk_list_box_bind_model()).
566 	 *
567 	 * Params:
568 	 *     sortFunc = the sort function
569 	 *     userData = user data passed to @sort_func
570 	 *     destroy = destroy notifier for @user_data
571 	 *
572 	 * Since: 3.10
573 	 */
574 	public void setSortFunc(GtkListBoxSortFunc sortFunc, void* userData, GDestroyNotify destroy)
575 	{
576 		gtk_list_box_set_sort_func(gtkListBox, sortFunc, userData, destroy);
577 	}
578 
579 	/**
580 	 * Unselect all children of @box, if the selection mode allows it.
581 	 *
582 	 * Since: 3.14
583 	 */
584 	public void unselectAll()
585 	{
586 		gtk_list_box_unselect_all(gtkListBox);
587 	}
588 
589 	/**
590 	 * Unselects a single row of @box, if the selection mode allows it.
591 	 *
592 	 * Params:
593 	 *     row = the row to unselected
594 	 *
595 	 * Since: 3.14
596 	 */
597 	public void unselectRow(ListBoxRow row)
598 	{
599 		gtk_list_box_unselect_row(gtkListBox, (row is null) ? null : row.getListBoxRowStruct());
600 	}
601 
602 	protected class OnActivateCursorRowDelegateWrapper
603 	{
604 		void delegate(ListBox) dlg;
605 		gulong handlerId;
606 
607 		this(void delegate(ListBox) dlg)
608 		{
609 			this.dlg = dlg;
610 			onActivateCursorRowListeners ~= this;
611 		}
612 
613 		void remove(OnActivateCursorRowDelegateWrapper source)
614 		{
615 			foreach(index, wrapper; onActivateCursorRowListeners)
616 			{
617 				if (wrapper.handlerId == source.handlerId)
618 				{
619 					onActivateCursorRowListeners[index] = null;
620 					onActivateCursorRowListeners = std.algorithm.remove(onActivateCursorRowListeners, index);
621 					break;
622 				}
623 			}
624 		}
625 	}
626 	OnActivateCursorRowDelegateWrapper[] onActivateCursorRowListeners;
627 
628 	/** */
629 	gulong addOnActivateCursorRow(void delegate(ListBox) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
630 	{
631 		auto wrapper = new OnActivateCursorRowDelegateWrapper(dlg);
632 		wrapper.handlerId = Signals.connectData(
633 			this,
634 			"activate-cursor-row",
635 			cast(GCallback)&callBackActivateCursorRow,
636 			cast(void*)wrapper,
637 			cast(GClosureNotify)&callBackActivateCursorRowDestroy,
638 			connectFlags);
639 		return wrapper.handlerId;
640 	}
641 
642 	extern(C) static void callBackActivateCursorRow(GtkListBox* listboxStruct, OnActivateCursorRowDelegateWrapper wrapper)
643 	{
644 		wrapper.dlg(wrapper.outer);
645 	}
646 
647 	extern(C) static void callBackActivateCursorRowDestroy(OnActivateCursorRowDelegateWrapper wrapper, GClosure* closure)
648 	{
649 		wrapper.remove(wrapper);
650 	}
651 
652 	protected class OnMoveCursorDelegateWrapper
653 	{
654 		void delegate(GtkMovementStep, int, ListBox) dlg;
655 		gulong handlerId;
656 
657 		this(void delegate(GtkMovementStep, int, ListBox) dlg)
658 		{
659 			this.dlg = dlg;
660 			onMoveCursorListeners ~= this;
661 		}
662 
663 		void remove(OnMoveCursorDelegateWrapper source)
664 		{
665 			foreach(index, wrapper; onMoveCursorListeners)
666 			{
667 				if (wrapper.handlerId == source.handlerId)
668 				{
669 					onMoveCursorListeners[index] = null;
670 					onMoveCursorListeners = std.algorithm.remove(onMoveCursorListeners, index);
671 					break;
672 				}
673 			}
674 		}
675 	}
676 	OnMoveCursorDelegateWrapper[] onMoveCursorListeners;
677 
678 	/** */
679 	gulong addOnMoveCursor(void delegate(GtkMovementStep, int, ListBox) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
680 	{
681 		auto wrapper = new OnMoveCursorDelegateWrapper(dlg);
682 		wrapper.handlerId = Signals.connectData(
683 			this,
684 			"move-cursor",
685 			cast(GCallback)&callBackMoveCursor,
686 			cast(void*)wrapper,
687 			cast(GClosureNotify)&callBackMoveCursorDestroy,
688 			connectFlags);
689 		return wrapper.handlerId;
690 	}
691 
692 	extern(C) static void callBackMoveCursor(GtkListBox* listboxStruct, GtkMovementStep object, int p0, OnMoveCursorDelegateWrapper wrapper)
693 	{
694 		wrapper.dlg(object, p0, wrapper.outer);
695 	}
696 
697 	extern(C) static void callBackMoveCursorDestroy(OnMoveCursorDelegateWrapper wrapper, GClosure* closure)
698 	{
699 		wrapper.remove(wrapper);
700 	}
701 
702 	protected class OnRowActivatedDelegateWrapper
703 	{
704 		void delegate(ListBoxRow, ListBox) dlg;
705 		gulong handlerId;
706 
707 		this(void delegate(ListBoxRow, ListBox) dlg)
708 		{
709 			this.dlg = dlg;
710 			onRowActivatedListeners ~= this;
711 		}
712 
713 		void remove(OnRowActivatedDelegateWrapper source)
714 		{
715 			foreach(index, wrapper; onRowActivatedListeners)
716 			{
717 				if (wrapper.handlerId == source.handlerId)
718 				{
719 					onRowActivatedListeners[index] = null;
720 					onRowActivatedListeners = std.algorithm.remove(onRowActivatedListeners, index);
721 					break;
722 				}
723 			}
724 		}
725 	}
726 	OnRowActivatedDelegateWrapper[] onRowActivatedListeners;
727 
728 	/**
729 	 * The ::row-activated signal is emitted when a row has been activated by the user.
730 	 *
731 	 * Params:
732 	 *     row = the activated row
733 	 *
734 	 * Since: 3.10
735 	 */
736 	gulong addOnRowActivated(void delegate(ListBoxRow, ListBox) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
737 	{
738 		auto wrapper = new OnRowActivatedDelegateWrapper(dlg);
739 		wrapper.handlerId = Signals.connectData(
740 			this,
741 			"row-activated",
742 			cast(GCallback)&callBackRowActivated,
743 			cast(void*)wrapper,
744 			cast(GClosureNotify)&callBackRowActivatedDestroy,
745 			connectFlags);
746 		return wrapper.handlerId;
747 	}
748 
749 	extern(C) static void callBackRowActivated(GtkListBox* listboxStruct, GtkListBoxRow* row, OnRowActivatedDelegateWrapper wrapper)
750 	{
751 		wrapper.dlg(ObjectG.getDObject!(ListBoxRow)(row), wrapper.outer);
752 	}
753 
754 	extern(C) static void callBackRowActivatedDestroy(OnRowActivatedDelegateWrapper wrapper, GClosure* closure)
755 	{
756 		wrapper.remove(wrapper);
757 	}
758 
759 	protected class OnRowSelectedDelegateWrapper
760 	{
761 		void delegate(ListBoxRow, ListBox) dlg;
762 		gulong handlerId;
763 
764 		this(void delegate(ListBoxRow, ListBox) dlg)
765 		{
766 			this.dlg = dlg;
767 			onRowSelectedListeners ~= this;
768 		}
769 
770 		void remove(OnRowSelectedDelegateWrapper source)
771 		{
772 			foreach(index, wrapper; onRowSelectedListeners)
773 			{
774 				if (wrapper.handlerId == source.handlerId)
775 				{
776 					onRowSelectedListeners[index] = null;
777 					onRowSelectedListeners = std.algorithm.remove(onRowSelectedListeners, index);
778 					break;
779 				}
780 			}
781 		}
782 	}
783 	OnRowSelectedDelegateWrapper[] onRowSelectedListeners;
784 
785 	/**
786 	 * The ::row-selected signal is emitted when a new row is selected, or
787 	 * (with a %NULL @row) when the selection is cleared.
788 	 *
789 	 * When the @box is using #GTK_SELECTION_MULTIPLE, this signal will not
790 	 * give you the full picture of selection changes, and you should use
791 	 * the #GtkListBox::selected-rows-changed signal instead.
792 	 *
793 	 * Params:
794 	 *     row = the selected row
795 	 *
796 	 * Since: 3.10
797 	 */
798 	gulong addOnRowSelected(void delegate(ListBoxRow, ListBox) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
799 	{
800 		auto wrapper = new OnRowSelectedDelegateWrapper(dlg);
801 		wrapper.handlerId = Signals.connectData(
802 			this,
803 			"row-selected",
804 			cast(GCallback)&callBackRowSelected,
805 			cast(void*)wrapper,
806 			cast(GClosureNotify)&callBackRowSelectedDestroy,
807 			connectFlags);
808 		return wrapper.handlerId;
809 	}
810 
811 	extern(C) static void callBackRowSelected(GtkListBox* listboxStruct, GtkListBoxRow* row, OnRowSelectedDelegateWrapper wrapper)
812 	{
813 		wrapper.dlg(ObjectG.getDObject!(ListBoxRow)(row), wrapper.outer);
814 	}
815 
816 	extern(C) static void callBackRowSelectedDestroy(OnRowSelectedDelegateWrapper wrapper, GClosure* closure)
817 	{
818 		wrapper.remove(wrapper);
819 	}
820 
821 	protected class OnSelectAllDelegateWrapper
822 	{
823 		void delegate(ListBox) dlg;
824 		gulong handlerId;
825 
826 		this(void delegate(ListBox) dlg)
827 		{
828 			this.dlg = dlg;
829 			onSelectAllListeners ~= this;
830 		}
831 
832 		void remove(OnSelectAllDelegateWrapper source)
833 		{
834 			foreach(index, wrapper; onSelectAllListeners)
835 			{
836 				if (wrapper.handlerId == source.handlerId)
837 				{
838 					onSelectAllListeners[index] = null;
839 					onSelectAllListeners = std.algorithm.remove(onSelectAllListeners, index);
840 					break;
841 				}
842 			}
843 		}
844 	}
845 	OnSelectAllDelegateWrapper[] onSelectAllListeners;
846 
847 	/**
848 	 * The ::select-all signal is a [keybinding signal][GtkBindingSignal]
849 	 * which gets emitted to select all children of the box, if the selection
850 	 * mode permits it.
851 	 *
852 	 * The default bindings for this signal is Ctrl-a.
853 	 *
854 	 * Since: 3.14
855 	 */
856 	gulong addOnSelectAll(void delegate(ListBox) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
857 	{
858 		auto wrapper = new OnSelectAllDelegateWrapper(dlg);
859 		wrapper.handlerId = Signals.connectData(
860 			this,
861 			"select-all",
862 			cast(GCallback)&callBackSelectAll,
863 			cast(void*)wrapper,
864 			cast(GClosureNotify)&callBackSelectAllDestroy,
865 			connectFlags);
866 		return wrapper.handlerId;
867 	}
868 
869 	extern(C) static void callBackSelectAll(GtkListBox* listboxStruct, OnSelectAllDelegateWrapper wrapper)
870 	{
871 		wrapper.dlg(wrapper.outer);
872 	}
873 
874 	extern(C) static void callBackSelectAllDestroy(OnSelectAllDelegateWrapper wrapper, GClosure* closure)
875 	{
876 		wrapper.remove(wrapper);
877 	}
878 
879 	protected class OnSelectedRowsChangedDelegateWrapper
880 	{
881 		void delegate(ListBox) dlg;
882 		gulong handlerId;
883 
884 		this(void delegate(ListBox) dlg)
885 		{
886 			this.dlg = dlg;
887 			onSelectedRowsChangedListeners ~= this;
888 		}
889 
890 		void remove(OnSelectedRowsChangedDelegateWrapper source)
891 		{
892 			foreach(index, wrapper; onSelectedRowsChangedListeners)
893 			{
894 				if (wrapper.handlerId == source.handlerId)
895 				{
896 					onSelectedRowsChangedListeners[index] = null;
897 					onSelectedRowsChangedListeners = std.algorithm.remove(onSelectedRowsChangedListeners, index);
898 					break;
899 				}
900 			}
901 		}
902 	}
903 	OnSelectedRowsChangedDelegateWrapper[] onSelectedRowsChangedListeners;
904 
905 	/**
906 	 * The ::selected-rows-changed signal is emitted when the
907 	 * set of selected rows changes.
908 	 *
909 	 * Since: 3.14
910 	 */
911 	gulong addOnSelectedRowsChanged(void delegate(ListBox) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
912 	{
913 		auto wrapper = new OnSelectedRowsChangedDelegateWrapper(dlg);
914 		wrapper.handlerId = Signals.connectData(
915 			this,
916 			"selected-rows-changed",
917 			cast(GCallback)&callBackSelectedRowsChanged,
918 			cast(void*)wrapper,
919 			cast(GClosureNotify)&callBackSelectedRowsChangedDestroy,
920 			connectFlags);
921 		return wrapper.handlerId;
922 	}
923 
924 	extern(C) static void callBackSelectedRowsChanged(GtkListBox* listboxStruct, OnSelectedRowsChangedDelegateWrapper wrapper)
925 	{
926 		wrapper.dlg(wrapper.outer);
927 	}
928 
929 	extern(C) static void callBackSelectedRowsChangedDestroy(OnSelectedRowsChangedDelegateWrapper wrapper, GClosure* closure)
930 	{
931 		wrapper.remove(wrapper);
932 	}
933 
934 	protected class OnToggleCursorRowDelegateWrapper
935 	{
936 		void delegate(ListBox) dlg;
937 		gulong handlerId;
938 
939 		this(void delegate(ListBox) dlg)
940 		{
941 			this.dlg = dlg;
942 			onToggleCursorRowListeners ~= this;
943 		}
944 
945 		void remove(OnToggleCursorRowDelegateWrapper source)
946 		{
947 			foreach(index, wrapper; onToggleCursorRowListeners)
948 			{
949 				if (wrapper.handlerId == source.handlerId)
950 				{
951 					onToggleCursorRowListeners[index] = null;
952 					onToggleCursorRowListeners = std.algorithm.remove(onToggleCursorRowListeners, index);
953 					break;
954 				}
955 			}
956 		}
957 	}
958 	OnToggleCursorRowDelegateWrapper[] onToggleCursorRowListeners;
959 
960 	/** */
961 	gulong addOnToggleCursorRow(void delegate(ListBox) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
962 	{
963 		auto wrapper = new OnToggleCursorRowDelegateWrapper(dlg);
964 		wrapper.handlerId = Signals.connectData(
965 			this,
966 			"toggle-cursor-row",
967 			cast(GCallback)&callBackToggleCursorRow,
968 			cast(void*)wrapper,
969 			cast(GClosureNotify)&callBackToggleCursorRowDestroy,
970 			connectFlags);
971 		return wrapper.handlerId;
972 	}
973 
974 	extern(C) static void callBackToggleCursorRow(GtkListBox* listboxStruct, OnToggleCursorRowDelegateWrapper wrapper)
975 	{
976 		wrapper.dlg(wrapper.outer);
977 	}
978 
979 	extern(C) static void callBackToggleCursorRowDestroy(OnToggleCursorRowDelegateWrapper wrapper, GClosure* closure)
980 	{
981 		wrapper.remove(wrapper);
982 	}
983 
984 	protected class OnUnselectAllDelegateWrapper
985 	{
986 		void delegate(ListBox) dlg;
987 		gulong handlerId;
988 
989 		this(void delegate(ListBox) dlg)
990 		{
991 			this.dlg = dlg;
992 			onUnselectAllListeners ~= this;
993 		}
994 
995 		void remove(OnUnselectAllDelegateWrapper source)
996 		{
997 			foreach(index, wrapper; onUnselectAllListeners)
998 			{
999 				if (wrapper.handlerId == source.handlerId)
1000 				{
1001 					onUnselectAllListeners[index] = null;
1002 					onUnselectAllListeners = std.algorithm.remove(onUnselectAllListeners, index);
1003 					break;
1004 				}
1005 			}
1006 		}
1007 	}
1008 	OnUnselectAllDelegateWrapper[] onUnselectAllListeners;
1009 
1010 	/**
1011 	 * The ::unselect-all signal is a [keybinding signal][GtkBindingSignal]
1012 	 * which gets emitted to unselect all children of the box, if the selection
1013 	 * mode permits it.
1014 	 *
1015 	 * The default bindings for this signal is Ctrl-Shift-a.
1016 	 *
1017 	 * Since: 3.14
1018 	 */
1019 	gulong addOnUnselectAll(void delegate(ListBox) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
1020 	{
1021 		auto wrapper = new OnUnselectAllDelegateWrapper(dlg);
1022 		wrapper.handlerId = Signals.connectData(
1023 			this,
1024 			"unselect-all",
1025 			cast(GCallback)&callBackUnselectAll,
1026 			cast(void*)wrapper,
1027 			cast(GClosureNotify)&callBackUnselectAllDestroy,
1028 			connectFlags);
1029 		return wrapper.handlerId;
1030 	}
1031 
1032 	extern(C) static void callBackUnselectAll(GtkListBox* listboxStruct, OnUnselectAllDelegateWrapper wrapper)
1033 	{
1034 		wrapper.dlg(wrapper.outer);
1035 	}
1036 
1037 	extern(C) static void callBackUnselectAllDestroy(OnUnselectAllDelegateWrapper wrapper, GClosure* closure)
1038 	{
1039 		wrapper.remove(wrapper);
1040 	}
1041 }