[gtkmm] Gtk::Builder: Make get_widget_derived() a variadic template



commit 6e98903fc458c96fbf87b2080c9a06a0f221ead3
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date:   Thu Jan 28 10:53:18 2016 +0100

    Gtk::Builder: Make get_widget_derived() a variadic template
    
    * gtk/src/builder.hg: get_widget_derived() can take extra parameters, which
    are forwarded to the constructor of the derived class.
    Inspired by a patch by Armin Burgmeier <armin arbur net>.
    * tests/builder/main.cc: Add a parameter to the constructor of the derived
    class. Bug #134161.

 gtk/src/builder.hg    |   54 ++++++++++++++++++++++++++++++++----------------
 tests/builder/main.cc |   13 +++++++++--
 2 files changed, 46 insertions(+), 21 deletions(-)
---
diff --git a/gtk/src/builder.hg b/gtk/src/builder.hg
index 42ab976..db042d6 100644
--- a/gtk/src/builder.hg
+++ b/gtk/src/builder.hg
@@ -19,6 +19,7 @@
 
 #include <gtkmm/widget.h>
 #include <giomm/resource.h> //For ResourceError, thrown by create_from_resource().
+#include <utility> //For std::forward()
 
 _DEFS(gtkmm,gtk)
 _PINCLUDE(glibmm/private/object_p.h)
@@ -428,7 +429,7 @@ public:
    * @newin{2,12}
    *
    * @param name Name of object to get.
-   * @return The object named @a name or <tt>0</tt> if it could not be found in the object tree.
+   * @return The object named @a name or <tt>nullptr</tt> if it could not be found in the object tree.
    */
   _WRAP_METHOD(Glib::RefPtr<Glib::Object> get_object(const Glib::ustring& name), gtk_builder_get_object, 
refreturn)
   /** Gets the object named @a name.
@@ -436,11 +437,11 @@ public:
    * @newin{3,8}
    *
    * @param name Name of object to get.
-   * @return The object named @a name or <tt>0</tt> if it could not be found in the object tree.
+   * @return The object named @a name or <tt>nullptr</tt> if it could not be found in the object tree.
    */
   _WRAP_METHOD(Glib::RefPtr<const Glib::Object> get_object(const Glib::ustring& name) const, 
gtk_builder_get_object, refreturn, constversion)
 
-  /** Get a widget from the Builder file.
+  /** Gets a widget from the Builder file.
    * For instance:
    * @code
    * Gtk::Grid* pGrid = nullptr;
@@ -456,7 +457,7 @@ public:
    * container widget.
    *
    * @param name The name of the widget.
-   * @retval widget A pointer to the widget, or <tt>0</tt> on failure.
+   * @retval widget A pointer to the widget, or <tt>nullptr</tt> on failure.
    */
   template <class T_Widget> inline
   void get_widget(const Glib::ustring& name, T_Widget*& widget)
@@ -480,31 +481,48 @@ public:
     const_cast<Builder*>(this)->get_widget(name, widget);
   }
 
-  /** This provides a pointer to a widget whose details are specified in the GtkBuilder file, but which is 
implemented
-   * by your own derived class. Your class must have a constructor like so:
+  /** Gets a widget whose details are specified in the GtkBuilder file,
+   * but which is implemented by your own derived class.
+   *
+   * Your class must have a constructor like so:
+   * @code
+   * MyDerivedDialog::MyDerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refBuilder)
+   * : Gtk::Dialog(cobject) //Calls the base class constructor
+   * @endcode
+   * or, with additional parameters, for example:
    * @code
-   * DerivedDialog::DerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refBuilder)
+   * MyDerivedDialog::MyDerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refBuilder,
+   *   const Glib::ustring& msg, bool warning)
    * : Gtk::Dialog(cobject) //Calls the base class constructor
    * @endcode
    *
    * For instance:
    * @code
-   * Gtk::DerivedBox* pBox = nullptr;
-   * refXml->get_widget_derived("mybox", pBox);
+   * MyDerivedDialog* pDialog1 = nullptr;
+   * MyDerivedDialog* pDialog2 = nullptr;
+   * refBuilder->get_widget_derived("mydialog1", pDialog1);
+   * refBuilder->get_widget_derived("mydialog2", pDialog2, "A storm is imminent!", true);
    * @endcode
    *
+   * @note
+   * If get_widget_derived() is called more than once for the same widget (the
+   * same @a name), only the first call will call the widget's constructor.
+   * The following calls will return a pointer to the widget instance that
+   * was constructed by the first call.
+   *
    * @param name The name of the widget.
-   * @retval widget A pointer to the widget, or <tt>0</tt> on failure.
+   * @param args Additional arguments to pass to the constructor of the derived class.
+   * @retval widget A pointer to the widget, or <tt>nullptr</tt> on failure.
    */
-  template <class T_Widget> inline
-  void get_widget_derived(const Glib::ustring& name, T_Widget*& widget)
+  template <typename T_Widget, typename... Args> inline
+  void get_widget_derived(const Glib::ustring& name, T_Widget*& widget, Args&&... args)
   {
      // Initialize output parameter:
      widget = nullptr;
 
      // Get the widget from the GtkBuilder file.
-     typedef typename T_Widget::BaseObjectType cwidget_type;
-     cwidget_type* pCWidget = (cwidget_type*)get_cwidget(name);
+     using cwidget_type = typename T_Widget::BaseObjectType;
+     auto pCWidget = (cwidget_type*)get_cwidget(name);
 
      //The error was already reported by get_cwidget().
      if(!pCWidget)
@@ -532,7 +550,7 @@ public:
        //Set the output variable. We needed to do this because we can not template the return type.
        Glib::RefPtr<Gtk::Builder> refThis(this);
        refThis->reference(); //take a copy.
-       widget = new T_Widget(pCWidget, refThis);
+       widget = new T_Widget(pCWidget, refThis, std::forward<Args>(args)...);
        // Don't add reference to widget. That's done only in methods that return
        // a Glib::RefPtr<Something>.
      }
@@ -541,10 +559,10 @@ public:
   /** See the non-const version.
    * @newin{3,8}
    */
-  template <class T_Widget> inline
-  void get_widget_derived(const Glib::ustring& name, const T_Widget*& widget) const
+  template <typename T_Widget, typename... Args> inline
+  void get_widget_derived(const Glib::ustring& name, const T_Widget*& widget, Args&&... args) const
   {
-    const_cast<Builder*>(this)->get_widget_derived(name, widget);
+    const_cast<Builder*>(this)->get_widget_derived(name, widget, std::forward<Args>(args)...);
   }
 
 #m4 _CONVERSION(`GSList*',`std::vector<Glib::RefPtr<Glib::Object> 
',`Glib::SListHandler<Glib::RefPtr<Glib::Object> >::slist_to_vector($3, Glib::OWNERSHIP_SHALLOW)')
diff --git a/tests/builder/main.cc b/tests/builder/main.cc
index f3c7f8a..02a8043 100644
--- a/tests/builder/main.cc
+++ b/tests/builder/main.cc
@@ -91,10 +91,17 @@ void* on_orphaned_button_deleted(void* /* data */)
 class DerivedButton : public Gtk::Button
 {
 public:
-  DerivedButton(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& /* refBuilder */)
+  DerivedButton(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& /* refBuilder */,
+    const Glib::ustring icon_name = Glib::ustring())
   : Gtk::Button(cobject)
   {
     std::cout << "DerivedButton::ctor" << std::endl;
+
+    if (!icon_name.empty())
+    {
+      set_image_from_icon_name(icon_name);
+      property_always_show_image() = true;
+    }
   }
 
   virtual ~DerivedButton()
@@ -112,7 +119,7 @@ public:
     std::cout << "MainWindow::ctor" << std::endl;
 
     // Called twice just to see if two calls affect the ref count.
-    refBuilder->get_widget_derived("derived_button", m_pDerivedButton);
+    refBuilder->get_widget_derived("derived_button", m_pDerivedButton, "face-smile");
     refBuilder->get_widget_derived("derived_button", m_pDerivedButton);
     refBuilder->get_widget("standard_button", m_pStandardButton);
     refBuilder->get_widget("standard_button", m_pStandardButton);
@@ -171,7 +178,7 @@ int main(int argc, char* argv[])
     << "  ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl;
 
   const int result = app->run(*main_win);
- 
+
   std::cout << "After app->run(*main_win)" << std::endl
     << "  ref_count(MainWindow)=" << window->ref_count << std::endl
     << "  ref_count(DerivedButton)=" << derived_button->ref_count << std::endl


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]