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