summaryrefslogtreecommitdiff
path: root/gui/include/template_widget.hpp
blob: f90b47319bf691deb684499709910aeb9ce8e520 (plain)
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
/*
 * SPDX-FileCopyrightText: 2025 Felix Morgner <felix.morgner@gmail.com>
 * SPDX-License-Identifier: LGPL-2.1-only
 */

#ifndef TURNS_UI_TEMPLATE_WIDGET_HPP
#define TURNS_UI_TEMPLATE_WIDGET_HPP

#include <glibmm/extraclassinit.h>
#include <glibmm/ustring.h>
#include <glibmm/wrap.h>

#include <gtkmm/widget.h>

#include <glib-object.h>
#include <glib.h>
#include <gtk/gtk.h>

#include <algorithm>
#include <utility>

namespace turns::ui
{

  template<typename CustomWidgetType, typename BaseWidgetType>
  struct template_widget : Glib::ExtraClassInit,
                           BaseWidgetType
  {
    template<typename... BaseWidgetCtorArgTypes>
    template_widget(Glib::ustring && resource_path, BaseWidgetCtorArgTypes &&... base_widget_ctor_args)
        : Glib::ExtraClassInit{class_init, &resource_path, instance_init}
        , BaseWidgetType{std::forward<BaseWidgetCtorArgTypes>(base_widget_ctor_args)...}
    {
    }

  protected:
    template<typename WidgetType = Gtk::Widget>
    auto get_widget(char const * name) -> WidgetType *
    {
      auto self = static_cast<CustomWidgetType *>(this);
      auto widget = GTK_WIDGET(Glib::unwrap(self));
      auto type = G_OBJECT_TYPE(Glib::unwrap(self));
      auto child = GTK_WIDGET(gtk_widget_get_template_child(widget, type, name));
      g_assert_nonnull(child);
      return dynamic_cast<WidgetType *>(Glib::wrap(child));
    }

  private:
    auto static class_init(void * g_class, void * g_class_data) -> void
    {
      g_return_if_fail(GTK_IS_WIDGET_CLASS(g_class));

      auto resource_path = static_cast<Glib::ustring const *>(g_class_data);

      gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(g_class), resource_path->c_str());

      std::ranges::for_each(CustomWidgetType::children, [g_class](auto const & child) {
        gtk_widget_class_bind_template_child_full(GTK_WIDGET_CLASS(g_class), child, false, 0);
      });
    }

    auto static instance_init(GTypeInstance * instance, void * /* type_class */) -> void
    {
      g_return_if_fail(GTK_IS_WIDGET(instance));

      gtk_widget_init_template(GTK_WIDGET(instance));
    }
  };

}  // namespace turns::ui::widgets

#endif