lxgui
gui_region_tpl.hpp
1 #ifndef LXGUI_GUI_REGION_TPL_HPP
2 #define LXGUI_GUI_REGION_TPL_HPP
3 
4 #include "lxgui/gui_frame.hpp"
5 #include "lxgui/gui_manager.hpp"
6 #include "lxgui/gui_region.hpp"
7 #include "lxgui/gui_registry.hpp"
8 #include "lxgui/gui_root.hpp"
9 #include "lxgui/lxgui.hpp"
10 #include "lxgui/utils_observer.hpp"
11 #include "lxgui/utils_string.hpp"
12 
13 #include <lxgui/extern_sol2_state.hpp>
14 
17 namespace sol {
18 
19 template<typename T>
20 struct unique_usertype_traits<lxgui::utils::observer_ptr<T>> {
21  static T* get(lua_State*, const lxgui::utils::observer_ptr<T>& pointer) noexcept {
22  return pointer.get();
23  }
24 
25  static bool is_null(lua_State*, const lxgui::utils::observer_ptr<T>& pointer) noexcept {
26  return pointer.expired();
27  }
28 };
29 
30 } // namespace sol
34 namespace lxgui::gui {
35 
36 template<typename T>
38  sol::types<T>, lua_State* lua, int index, sol::stack::record& /*tracking*/) {
39  // NB: not sure why, but using tracking here leads to issues later on, so
40  // ignore it for now.
41 
42  using RegionType = std::remove_pointer_t<T>;
43 
44  sol::optional<lxgui::utils::observer_ptr<RegionType>&> optional =
45  sol::stack::check_get<lxgui::utils::observer_ptr<RegionType>&>(
46  lua, index, sol::no_panic /*, tracking*/);
47 
48  if (!optional.has_value())
49  return;
50 
51  if (optional->expired())
52  throw sol::error("object has been deleted");
53 }
54 
55 inline utils::observer_ptr<region>
56 get_object(manager& mgr, const std::variant<std::string, region*>& parent) {
57  return std::visit(
58  [&](const auto& value) -> utils::observer_ptr<region> {
59  using data_type = std::decay_t<decltype(value)>;
60  if constexpr (std::is_same_v<data_type, std::string>) {
61  if (utils::has_no_content(value))
62  return nullptr;
63 
64  auto parent_obj = mgr.get_root().get_registry().get_region_by_name(value);
65  if (!parent_obj)
66  throw sol::error("no region with name \"" + value + "\"");
67 
68  return parent_obj;
69  } else {
70  return observer_from(value);
71  }
72  },
73  parent);
74 }
75 
76 template<typename T>
77 utils::observer_ptr<T> get_object(manager& mgr, const std::variant<std::string, T*>& parent) {
78  return std::visit(
79  [&](const auto& value) -> utils::observer_ptr<T> {
80  using data_type = std::decay_t<decltype(value)>;
81  if constexpr (std::is_same_v<data_type, std::string>) {
82  if (utils::has_no_content(value))
83  return nullptr;
84 
85  auto parent_object = mgr.get_root().get_registry().get_region_by_name(value);
86  if (!parent_object)
87  throw sol::error("no region with name \"" + value + "\"");
88 
89  auto parent_obj = down_cast<T>(parent_object);
90  if (!parent_obj)
91  throw sol::error(
92  "region \"" + value + "\" is not a " + std::string(T::class_name));
93 
94  return parent_obj;
95  } else {
96  return observer_from(value);
97  }
98  },
99  parent);
100 }
101 
102 #if defined(LXGUI_COMPILER_EMSCRIPTEN)
103 // Workaround for compiler crash in Emscripten; explicitly convert member
104 // function pointers to free functions. sol2 is able to do this automatically,
105 // but Emscripten/clang is not happy about it.
106 template<typename T, T F>
107 struct member_function_holder;
108 
109 template<typename R, typename T, typename... Args, R (T::*Function)(Args...)>
110 struct member_function_holder<R (T::*)(Args...), Function> {
111  static constexpr auto make_free_function() {
112  return [](T& self, Args... args) { return (self.*Function)(std::move(args)...); };
113  }
114 };
115 
116 template<typename R, typename T, typename... Args, R (T::*Function)(Args...) const>
117 struct member_function_holder<R (T::*)(Args...) const, Function> {
118  static constexpr auto make_free_function() {
119  return [](const T& self, Args... args) { return (self.*Function)(std::move(args)...); };
120  }
121 };
122 
123 template<auto T>
124 constexpr auto member_function() {
125  return member_function_holder<decltype(T), T>::make_free_function();
126 }
127 #else
128 // Simply use the member function pointer directly for all other compilers.
129 template<auto T>
130 constexpr auto member_function() {
131  return T;
132 }
133 #endif
134 
135 template<typename T>
136 void region::create_glue_(T& self) {
137  get_lua_().globals()[get_name()] = observer_from(&self);
138 }
139 
140 template<typename T>
141 void region::initialize_(T& self, const region_core_attributes& /*attr*/) {
142  if (!is_virtual())
143  create_glue_(self);
144 }
145 
146 template<typename T>
147 const std::vector<std::string>& region::get_type_list_impl_() {
148  if constexpr (std::is_same_v<T, region>) {
149  static const std::vector<std::string> type = {region::class_name};
150 
151  return type;
152  } else {
153  static const std::vector<std::string> type = []() {
154  using base = typename T::base;
155  auto list = get_type_list_impl_<base>();
156  list.push_back(T::class_name);
157  return list;
158  }();
159 
160  return type;
161  }
162 }
163 
164 } // namespace lxgui::gui
165 
166 #endif
Manages the user interface.
Definition: gui_manager.hpp:44
root & get_root()
Returns the UI root object, which contains root frames.
void create_glue_(T &self)
void initialize_(T &self, const region_core_attributes &attr)
Set up function to call in all derived class constructors.
bool is_virtual() const
Checks if this region is virtual.
Definition: gui_region.cpp:553
const std::string & get_name() const
Returns this region's name.
Definition: gui_region.cpp:140
static const std::vector< std::string > & get_type_list_impl_()
static constexpr const char * class_name
Definition: gui_region.hpp:735
sol::state & get_lua_()
Definition: gui_region.cpp:767
utils::observer_ptr< const region > get_region_by_name(std::string_view name) const
Returns the region associated with the given name.
registry & get_registry()
Returns the UI object registry, which keeps track of all objects in the UI.
Definition: gui_root.hpp:261
utils::observer_ptr< ObjectType > observer_from(ObjectType *self)
Obtain an observer pointer from a raw pointer (typically 'this')
Definition: gui_region.hpp:946
utils::observer_ptr< region > get_object(manager &mgr, const std::variant< std::string, region * > &parent)
void sol_lua_check_access(sol::types< T >, lua_State *lua, int index, sol::stack::record &)
constexpr auto member_function()
T & get(variant &value)
Retrieve the value stored in an utils::variant.
Struct holding all the core information about a region necessary for its creation.