[gtkmm] Gtk::FlowBox, ListBox: Add bind_model() and bind_list_store()
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtkmm] Gtk::FlowBox, ListBox: Add bind_model() and bind_list_store()
- Date: Thu, 30 Jun 2016 07:48:44 +0000 (UTC)
commit ed8a5bcfe94aba8da2ceb14f235986f37ee4e067
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date: Thu Jun 30 09:45:40 2016 +0200
Gtk::FlowBox, ListBox: Add bind_model() and bind_list_store()
Most of ListBox::bind_model() by Murray Cumming <murrayc murrayc com>
Bug #755149
gtk/src/flowbox.ccg | 31 ++++++++++++
gtk/src/flowbox.hg | 121 +++++++++++++++++++++++++++++++++++++++++++++++-
gtk/src/listbox.ccg | 29 +++++++++++
gtk/src/listbox.hg | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 309 insertions(+), 1 deletions(-)
---
diff --git a/gtk/src/flowbox.ccg b/gtk/src/flowbox.ccg
index 9963fea..d24a642 100644
--- a/gtk/src/flowbox.ccg
+++ b/gtk/src/flowbox.ccg
@@ -74,6 +74,26 @@ static void SignalProxy_Sort_gtk_callback_destroy(void* data)
delete static_cast<Gtk::FlowBox::SlotSort*>(data);
}
+static GtkWidget* proxy_bind_model_create_widget_callback(void* item, void* data)
+{
+ auto& slot = *static_cast<Gtk::FlowBox::SlotCreateWidget<Glib::Object>*>(data);
+ auto cobject = static_cast<GObject*>(item);
+
+ try
+ {
+ // take_copy is true here, because wrap() returns a Glib::RefPtr<Glib::Object>.
+ // cobject will be unreferenced when the RefPtr is deleted.
+ Gtk::Widget* widget = slot(Glib::wrap(cobject, true));
+ if (widget)
+ return widget->gobj();
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ return nullptr;
+}
+
} // anonymous namespace
namespace Gtk
@@ -121,5 +141,16 @@ void FlowBox::unset_sort_func()
gtk_flow_box_set_sort_func(gobj(), nullptr, nullptr, nullptr);
}
+void FlowBox::bind_model(const Glib::RefPtr<Gio::ListModel>& model,
+ const SlotCreateWidget<Glib::Object>& slot_create_widget)
+{
+ // Create a copy of the slot.
+ // It will be deleted by Glib::destroy_notify_delete<SlotCreateWidget>.
+ auto slot_copy = new SlotCreateWidget<Glib::Object>(slot_create_widget);
+
+ gtk_flow_box_bind_model(gobj(), Glib::unwrap(model), &proxy_bind_model_create_widget_callback,
+ slot_copy, &Glib::destroy_notify_delete<SlotCreateWidget<Glib::Object>>);
+}
+
} //namespace Gtk
diff --git a/gtk/src/flowbox.hg b/gtk/src/flowbox.hg
index 87edd24..65400f0 100644
--- a/gtk/src/flowbox.hg
+++ b/gtk/src/flowbox.hg
@@ -17,7 +17,9 @@
#include <gtkmm/container.h>
#include <gtkmm/orientable.h>
#include <gtkmm/flowboxchild.h>
+#include <giomm/liststore.h>
#include <vector>
+#include <utility> // std::forward
_DEFS(gtkmm,gtk)
_PINCLUDE(gtkmm/private/container_p.h)
@@ -213,6 +215,79 @@ public:
_WRAP_METHOD(void invalidate_sort(), gtk_flow_box_invalidate_sort)
+ /** For instance:
+ * Gtk::Widget* on_create_widget(const Glib::RefPtr<T_item>& item);
+ *
+ * Called for flow boxes that are bound to a Gio::ListModel with bind_model()
+ * or bind_list_store() for each item that gets added to the model.
+ *
+ * @newin{3,22}
+ *
+ * @tparam T_item Base class of the items in the Gio::ListModel. All items must
+ * be of type T_item or a type derived from T_item.
+ * T_item must be Glib::Object or a type derived from Glib::Object.
+ * @param item The item from the model for which to create a widget.
+ * @eturn A Gtk::Widget that represents @a item.
+ */
+ template <typename T_item>
+ using SlotCreateWidget = sigc::slot<Gtk::Widget*, const Glib::RefPtr<T_item>&>;
+
+ /** Binds a Gio::ListModel.
+ *
+ * If this FlowBox was already bound to a model, that previous binding is
+ * destroyed.
+ *
+ * The contents of the FlowBox are cleared and then filled with widgets that
+ * represent items from @a model. The FlowBox is updated whenever @a model changes.
+ * If @a model is an empty Glib::RefPtr, the FlowBox is left empty.
+ *
+ * It is undefined to add or remove widgets directly (for example, with
+ * insert() or Gtk::Container::add()) while the FlowBox is bound to a model.
+ *
+ * Note that using a model is incompatible with the filtering and sorting
+ * functionality in FlowBox. When using a model, filtering and sorting
+ * should be implemented by the model.
+ *
+ * @newin{3,22}
+ *
+ * @param model The Gio::ListModel to be bound.
+ * @param slot_create_widget A slot that creates widgets for items.
+ *
+ * @see bind_list_store()
+ */
+ void bind_model(const Glib::RefPtr<Gio::ListModel>& model,
+ const SlotCreateWidget<Glib::Object>& slot_create_widget);
+ _IGNORE(gtk_flow_box_bind_model)
+
+ /** Binds a Gio::ListStore<>.
+ *
+ * If this FlowBox was already bound to a Gio::ListModel, that previous binding is
+ * destroyed. (Gio::ListStore is a Gio::ListModel.)
+ *
+ * The contents of the FlowBox are cleared and then filled with widgets that
+ * represent items from @a store. The FlowBox is updated whenever @a store changes.
+ * If @a store is an empty Glib::RefPtr, the FlowBox is left empty.
+ *
+ * It is undefined to add or remove widgets directly (for example, with
+ * insert() or Gtk::Container::add()) while the FlowBox is bound to a model.
+ *
+ * Note that using a model is incompatible with the filtering and sorting
+ * functionality in FlowBox. When using a model, filtering and sorting
+ * should be implemented by the model.
+ *
+ * @newin{3,22}
+ *
+ * @tparam T_item Base class of the items in the Gio::ListStore. All items must
+ * be of type T_item or a type derived from T_item.
+ * T_item must be Glib::Object or a type derived from Glib::Object.
+ * @tparam T_slot SlotCreateWidget<T_item> or a type that can be converted
+ * to SlotCreateWidget<T_item>.
+ * @param store The Gio::ListStore<> to be bound.
+ * @param slot_create_widget A slot that creates widgets for items.
+ */
+ template <typename T_item, typename T_slot>
+ void bind_list_store(const Glib::RefPtr<Gio::ListStore<T_item>>& store,
+ T_slot&& slot_create_widget);
_WRAP_PROPERTY("selection-mode", SelectionMode)
_WRAP_PROPERTY("activate-on-single-click", bool)
@@ -226,7 +301,51 @@ public:
_WRAP_SIGNAL(void child_activated(FlowBoxChild* child), "child-activated")
_WRAP_SIGNAL(void selected_children_changed(), "selected-children-changed")
_IGNORE_SIGNAL(activate-cursor-child, toggle-cursor-child, move-cursor, select-all, unselect-all) //
Action signals
+
+private:
+ template <typename T_item>
+ static GtkWidget* proxy_bind_list_store_create_widget_callback(void* item, void* data);
};
-} // namespace Gtk
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template <typename T_item, typename T_slot>
+void FlowBox::bind_list_store(const Glib::RefPtr<Gio::ListStore<T_item>>& store,
+ T_slot&& slot_create_widget)
+{
+ // Create a copy of the slot.
+ // It will be deleted by Glib::destroy_notify_delete<SlotCreateWidget>.
+ auto slot_copy = new SlotCreateWidget<T_item>(std::forward<T_slot>(slot_create_widget));
+
+ gtk_flow_box_bind_model(gobj(),
+ Glib::unwrap(Glib::RefPtr<Gio::ListModel>::cast_static(store)),
+ &proxy_bind_list_store_create_widget_callback<T_item>,
+ slot_copy, &Glib::destroy_notify_delete<SlotCreateWidget<T_item>>);
+}
+
+template <typename T_item>
+GtkWidget* FlowBox::proxy_bind_list_store_create_widget_callback(void* item, void* data)
+{
+ auto& slot = *static_cast<SlotCreateWidget<T_item>*>(data);
+ auto cobject = static_cast<typename T_item::BaseObjectType*>(item);
+
+ try
+ {
+ // cast_dynamic is necessary if T_item is a user-defined type, such as
+ // class MyObject : public Glib::Object
+ // take_copy is true here, because wrap() returns a Glib::RefPtr<>.
+ // cobject will be unreferenced when the RefPtr is deleted.
+ Gtk::Widget* widget = slot(Glib::RefPtr<T_item>::cast_dynamic(Glib::wrap(cobject, true)));
+ if (widget)
+ return widget->gobj();
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ return nullptr;
+}
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+} // namespace Gtk
diff --git a/gtk/src/listbox.ccg b/gtk/src/listbox.ccg
index 69a8118..c68734d 100644
--- a/gtk/src/listbox.ccg
+++ b/gtk/src/listbox.ccg
@@ -95,6 +95,25 @@ static void proxy_foreach_callback(GtkListBox* /* list_box */, GtkListBoxRow* ro
}
}
+static GtkWidget* proxy_bind_model_create_widget_callback(void* item, void* data)
+{
+ auto& slot = *static_cast<Gtk::ListBox::SlotCreateWidget<Glib::Object>*>(data);
+ auto cobject = static_cast<GObject*>(item);
+
+ try
+ {
+ // take_copy is true here, because wrap() returns a Glib::RefPtr<Glib::Object>.
+ // cobject will be unreferenced when the RefPtr is deleted.
+ Gtk::Widget* widget = slot(Glib::wrap(cobject, true));
+ if (widget)
+ return widget->gobj();
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ return nullptr;
+}
} // anonymous namespace
@@ -171,7 +190,17 @@ void ListBox::selected_foreach(const SlotForeach& slot)
{
SlotForeach slot_copy(slot); //TODO: Is this necessary?
gtk_list_box_selected_foreach(gobj(), &proxy_foreach_callback, &slot_copy);
+}
+
+void ListBox::bind_model(const Glib::RefPtr<Gio::ListModel>& model,
+ const SlotCreateWidget<Glib::Object>& slot_create_widget)
+{
+ // Create a copy of the slot.
+ // It will be deleted by Glib::destroy_notify_delete<SlotCreateWidget>.
+ auto slot_copy = new SlotCreateWidget<Glib::Object>(slot_create_widget);
+ gtk_list_box_bind_model(gobj(), Glib::unwrap(model), &proxy_bind_model_create_widget_callback,
+ slot_copy, &Glib::destroy_notify_delete<SlotCreateWidget<Glib::Object>>);
}
} //namespace Gtk
diff --git a/gtk/src/listbox.hg b/gtk/src/listbox.hg
index 3bbcc23..b7bd210 100644
--- a/gtk/src/listbox.hg
+++ b/gtk/src/listbox.hg
@@ -17,6 +17,9 @@
#include <gtkmm/container.h>
#include <gtkmm/listboxrow.h>
#include <gtkmm/enums.h>
+#include <giomm/liststore.h>
+#include <vector>
+#include <utility> // std::forward
_DEFS(gtkmm,gtk)
_PINCLUDE(gtkmm/private/container_p.h)
@@ -40,6 +43,8 @@ class Adjustment;
* add any kind of widget to it via Container::add(), and a ListBoxRow
* widget will automatically be inserted between the list and the widget.
*
+ * Also see FlowBox.
+ *
* A ListBox looks like this:
* @image html listbox1.png
*
@@ -238,6 +243,85 @@ public:
_WRAP_METHOD(void drag_unhighlight_row(), gtk_list_box_drag_unhighlight_row)
_WRAP_METHOD(void drag_highlight_row(ListBoxRow& row), gtk_list_box_drag_highlight_row)
+ /** For instance:
+ * Gtk::Widget* on_create_widget(const Glib::RefPtr<T_item>& item);
+ *
+ * Called for list boxes that are bound to a Gio::ListModel with bind_model()
+ * or bind_list_store() for each item that gets added to the model.
+ *
+ * Versions of GTK+ prior to 3.18 called show_all() on the rows
+ * created by the SlotCreateWidget, but this forced all widgets
+ * inside the row to be shown, and is no longer the case. Applications should
+ * be updated to show the desired row widgets.
+ *
+ * @newin{3,22}
+ *
+ * @tparam T_item Base class of the items in the Gio::ListModel. All items must
+ * be of type T_item or a type derived from T_item.
+ * T_item must be Glib::Object or a type derived from Glib::Object.
+ * @param item The item from the model for which to create a widget.
+ * @eturn A Gtk::Widget that represents @a item.
+ */
+ template <typename T_item>
+ using SlotCreateWidget = sigc::slot<Gtk::Widget*, const Glib::RefPtr<T_item>&>;
+
+ /** Binds a Gio::ListModel.
+ *
+ * If this ListBox was already bound to a model, that previous binding is
+ * destroyed.
+ *
+ * The contents of the ListBox are cleared and then filled with widgets that
+ * represent items from @a model. The ListBox is updated whenever @a model changes.
+ * If @a model is an empty Glib::RefPtr, the ListBox is left empty.
+ *
+ * It is undefined to add or remove widgets directly (for example, with
+ * insert() or Gtk::Container::add()) while the ListBox is bound to a model.
+ *
+ * Note that using a model is incompatible with the filtering and sorting
+ * functionality in ListBox. When using a model, filtering and sorting
+ * should be implemented by the model.
+ *
+ * @newin{3,22}
+ *
+ * @param model The Gio::ListModel to be bound.
+ * @param slot_create_widget A slot that creates widgets for items.
+ *
+ * @see bind_list_store()
+ */
+ void bind_model(const Glib::RefPtr<Gio::ListModel>& model,
+ const SlotCreateWidget<Glib::Object>& slot_create_widget);
+ _IGNORE(gtk_list_box_bind_model)
+
+ /** Binds a Gio::ListStore<>.
+ *
+ * If this ListBox was already bound to a Gio::ListModel, that previous binding is
+ * destroyed. (Gio::ListStore is a Gio::ListModel.)
+ *
+ * The contents of the ListBox are cleared and then filled with widgets that
+ * represent items from @a store. The ListBox is updated whenever @a store changes.
+ * If @a store is an empty Glib::RefPtr, the ListBox is left empty.
+ *
+ * It is undefined to add or remove widgets directly (for example, with
+ * insert() or Gtk::Container::add()) while the ListBox is bound to a model.
+ *
+ * Note that using a model is incompatible with the filtering and sorting
+ * functionality in ListBox. When using a model, filtering and sorting
+ * should be implemented by the model.
+ *
+ * @newin{3,22}
+ *
+ * @tparam T_item Base class of the items in the Gio::ListStore. All items must
+ * be of type T_item or a type derived from T_item.
+ * T_item must be Glib::Object or a type derived from Glib::Object.
+ * @tparam T_slot SlotCreateWidget<T_item> or a type that can be converted
+ * to SlotCreateWidget<T_item>.
+ * @param store The Gio::ListStore<> to be bound.
+ * @param slot_create_widget A slot that creates widgets for items.
+ */
+ template <typename T_item, typename T_slot>
+ void bind_list_store(const Glib::RefPtr<Gio::ListStore<T_item>>& store,
+ T_slot&& slot_create_widget);
+
_WRAP_PROPERTY("selection-mode", SelectionMode)
_WRAP_PROPERTY("activate-on-single-click", bool)
@@ -248,6 +332,51 @@ public:
_WRAP_SIGNAL(void selected_rows_changed(), selected-rows-changed, no_default_handler)
_IGNORE_SIGNAL(activate-cursor-row, toggle-cursor-row, move-cursor, select-all, unselect-all) // Action
signals
+
+private:
+ template <typename T_item>
+ static GtkWidget* proxy_bind_list_store_create_widget_callback(void* item, void* data);
};
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template <typename T_item, typename T_slot>
+void ListBox::bind_list_store(const Glib::RefPtr<Gio::ListStore<T_item>>& store,
+ T_slot&& slot_create_widget)
+{
+ // Create a copy of the slot.
+ // It will be deleted by Glib::destroy_notify_delete<SlotCreateWidget>.
+ auto slot_copy = new SlotCreateWidget<T_item>(std::forward<T_slot>(slot_create_widget));
+
+ gtk_list_box_bind_model(gobj(),
+ Glib::unwrap(Glib::RefPtr<Gio::ListModel>::cast_static(store)),
+ &proxy_bind_list_store_create_widget_callback<T_item>,
+ slot_copy, &Glib::destroy_notify_delete<SlotCreateWidget<T_item>>);
+}
+
+template <typename T_item>
+GtkWidget* ListBox::proxy_bind_list_store_create_widget_callback(void* item, void* data)
+{
+ auto& slot = *static_cast<SlotCreateWidget<T_item>*>(data);
+ auto cobject = static_cast<typename T_item::BaseObjectType*>(item);
+
+ try
+ {
+ // cast_dynamic is necessary if T_item is a user-defined type, such as
+ // class MyObject : public Glib::Object
+ // take_copy is true here, because wrap() returns a Glib::RefPtr<>.
+ // cobject will be unreferenced when the RefPtr is deleted.
+ Gtk::Widget* widget = slot(Glib::RefPtr<T_item>::cast_dynamic(Glib::wrap(cobject, true)));
+ if (widget)
+ return widget->gobj();
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ return nullptr;
+}
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
} // namespace Gtk
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]