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