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