1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
#ifndef _GI_GTK_BUILDER_EXTRA_DEF_HPP_
#define _GI_GTK_BUILDER_EXTRA_DEF_HPP_
namespace gi
{
namespace repository
{
namespace Gtk
{
class Builder;
namespace base
{
class BuilderExtra : public GI_GTK_BUILDER_BASE
{
typedef GI_GTK_BUILDER_BASE super;
public:
using super::get_object;
// T must be object-side type (not impl type)
template<typename T>
T get_object(const gi::cstring_v name)
{
auto obj = super::get_object(name);
return gi::object_cast<T>(obj);
}
/*
* T_Derived should be a custom subclass of some widget/object BaseClass.
* It should have a constructor of following signature that delegates
* to use the latter's special constructor (see also gtk example);
*
* T_Derived(BaseClass::instance_type instance, Gtk::Builder) :
* BaseClass(instance, this) {}
*
* Of course, it may also have additional arguments, and specify some
* additional arguments to super class constructor, if needed.
* See also comments on the latter.
*
* Note that this function *should* be called at some stage for any created
* C++-type based widget to ensure full and proper "C++ side" setup.
* See also gtk example (for additional comments).
*/
template<typename T_Derived, typename... Args>
gi::ref_ptr<T_Derived> get_object_derived(
const gi::cstring_v name, Args &&...args)
{
// instance type of class that T_Derived is based on
// (Gtk::Window for Gtk::WindowClass)
using instance_type = typename T_Derived::instance_type;
auto obj = super::get_object(name);
if (!obj)
return {};
// should be of expected base type
auto wobj = gi::object_cast<instance_type>(obj);
if (!wobj) {
g_error("wrong type (%s)", name.c_str());
return {};
}
// perhaps wrapper already of suitable type
auto wrapper = detail::ObjectClass::instance(obj.gobj_());
auto wrapper_cast = dynamic_cast<T_Derived *>(wrapper);
if (wrapper && !wrapper_cast) {
g_error("wrong C++ instance type (%s)", name.c_str());
return {};
} else if (wrapper_cast) {
return ref_ptr<T_Derived>(wrapper_cast, false);
}
// obtain builder from this
// (Builder subclass not yet declared/defined at this stage)
auto &builder = *(Builder *)(this);
// make wrapper using suitable constructor signature
// which does not add ref on provided instance
// so ref_ptr needs to grab an extra one
return ref_ptr<T_Derived>(
new T_Derived(wobj, builder, std::forward<Args>(args)...), false);
}
}; // class
#undef GI_GTK_BUILDER_BASE
#define GI_GTK_BUILDER_BASE base::BuilderExtra
} // namespace base
} // namespace Gtk
} // namespace repository
} // namespace gi
#endif
|