The Battle for Wesnoth  1.19.0+dev
lua_widget.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2024
3  by Guillaume Melquiond <guillaume.melquiond@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "scripting/lua_widget.hpp"
18 
19 #include "gui/widgets/widget.hpp"
20 #include "scripting/lua_common.hpp"
21 #include "scripting/lua_ptr.hpp"
22 #include "scripting/push_check.hpp"
23 
24 
25 
26 
27 static const char widgetKey[] = "widget";
28 static char widgetdataKey[] = "widgetdata";
29 
30 void luaW_pushwidget(lua_State* L, gui2::widget& w)
31 {
32  new(L) lua_ptr<gui2::widget>(w);
33  luaL_setmetatable(L, widgetKey);
34 }
35 
36 gui2::widget& luaW_checkwidget(lua_State* L, int n)
37 {
38  lua_ptr<gui2::widget>& lp = *static_cast<lua_ptr<gui2::widget>*>(luaL_checkudata(L, n, widgetKey));
39  auto ptr = lp.get_ptr();
40  if(!ptr) {
41  luaL_argerror(L, n, "widget was deleted");
42  }
43  return *ptr;
44 }
45 
47 {
48  lua_ptr<gui2::widget>& lp = *static_cast<lua_ptr<gui2::widget>*>(luaL_checkudata(L, n, widgetKey));
49  auto ptr = lp.get_ptr();
50  if(!ptr) {
51  luaL_argerror(L, n, "widget was deleted");
52  }
53  return lp;
54 }
55 
56 
57 bool luaW_iswidget(lua_State* L, int index)
58 {
59  return luaL_testudata(L, index, widgetKey) != nullptr;
60 }
61 
62 
63 static void luaW_pushwidgettablecontainer(lua_State* L)
64 {
65  lua_pushlightuserdata(L, &widgetdataKey[0]);
66  lua_rawget(L, LUA_REGISTRYINDEX);
67  if(lua_isnoneornil(L, -1)) {
68  lua_pop(L, 1);
69  lua_createtable(L, 0, 0);
70  lua_pushlightuserdata(L, &widgetdataKey[0]);
71  lua_pushvalue(L , -2);
72  lua_rawset(L, LUA_REGISTRYINDEX);
73  }
74 }
75 
76 void luaW_pushwindowtable(lua_State* L, gui2::window* owner)
77 {
79  lua_pushlightuserdata(L, owner);
80  lua_rawget(L, -2);
81  if(lua_isnoneornil(L, -1))
82  {
83  //stack: windowstable, nil
84  lua_pop(L, 1);
85  //stack: windowstable
86  lua_createtable(L, 1, 0);
87  //stack: windowstable, {}
88  lua_pushlightuserdata(L, owner);
89  //stack: windowtable, {}, wg_id
90  lua_pushvalue(L, -2);
91  //stack: windowtable, {}, wg_id, {}
92  lua_rawset(L, -4);
93  //stack: windowtable, {}
94  }
95  lua_remove(L, lua_absindex(L, -2));
96 }
97 
98 void luaW_clearwindowtable(lua_State* L, gui2::window* owner)
99 {
101  lua_pushlightuserdata(L, owner);
102  lua_pushnil(L);
103  lua_rawset(L, -3);
104  lua_pop(L, 1);
105 }
106 
107 
108 void luaW_pushwidgettable(lua_State* L, gui2::widget* wg, gui2::window* owner)
109 {
110  luaW_pushwindowtable(L, owner);
111  lua_pushlightuserdata(L, wg);
112  lua_rawget(L, -2);
113  if(lua_isnoneornil(L, -1))
114  {
115  //stack: windowtable, nil
116  lua_pop(L, 1);
117  //stack: windowtable
118  lua_createtable(L, 1, 0);
119  //stack: windowtable, {}
120  luaW_pushwidget(L, *wg);
121  //stack: windowtable, {}, wg
122  lua_rawseti(L, -2, 1);
123  //stack: windowtable, { wg},
124  lua_pushlightuserdata(L, wg);
125  //stack: windowtable, { wg}, wg_id
126  lua_pushvalue(L, -2);
127  //stack: windowtable, { wg}, wg_id, {wg}
128  lua_rawset(L, -4);
129  //stack: windowtable, { wg}
130  }
131  lua_remove(L, lua_absindex(L, -2));
132 }
133 
134 
135 bool luaW_setwidgetcallback(lua_State* L, gui2::widget* wg, gui2::window* owner, std::string_view name)
136 {
137  //stack: function
138  luaW_pushwidgettable(L, wg, owner);
139  //stack: function, {}
140  lua_push(L, name);
141  //stack: function, {}, name
142  lua_rawget(L, -2);
143  // function, old_function
144  bool existed_already = !lua_isnoneornil(L, -1);
145  lua_pop(L, 1);
146  // function,
147  lua_push(L, name);
148  //stack: function, {}, name
149  lua_rotate(L, lua_absindex(L, -3), -1);
150  //stack: {}, name, function
151  lua_rawset(L, -3);
152  //stack: {name = function}
153  lua_pop(L, 1);
154  return existed_already;
155 }
156 
157 void luaW_getwidgetcallback(lua_State* L, gui2::widget* wg, gui2::window* owner, std::string_view name)
158 {
159  luaW_pushwidgettable(L, wg, owner);
160  //stack: {name = function},
161  lua_push(L, name);
162  //stack: {name = function}, name
163  lua_rawget(L, -2);
164  //stack: {name = function}, function
165  lua_remove(L, lua_absindex(L, -2));
166  //stack: function
167 }
168 
169 void luaW_callwidgetcallback(lua_State* L, gui2::widget* wg, gui2::window* owner, std::string_view name)
170 {
171  luaW_getwidgetcallback(L, wg, owner, name);
172  assert(lua_isfunction(L, -1));
173  luaW_pushwidget(L, *wg);
174  lua_call(L, 1, 0);
175 }
176 
177 
178 static int impl_widget_collect(lua_State* L)
179 {
180  lua_ptr<gui2::widget>* w = static_cast<lua_ptr<gui2::widget>*>(luaL_checkudata(L, 1, widgetKey));
181  w->~lua_ptr<gui2::widget>();
182  return 0;
183 }
184 
185 
186 namespace lua_widget {
187  void register_metatable(lua_State* L)
188  {
189 
190  luaL_newmetatable(L, widgetKey);
191  lua_pushcfunction(L, lua_widget::impl_widget_get);
192  lua_setfield(L, -2, "__index");
193  lua_pushcfunction(L, lua_widget::impl_widget_set);
194  lua_setfield(L, -2, "__newindex");
195  lua_pushcfunction(L, lua_widget::impl_widget_dir);
196  lua_setfield(L, -2, "__dir");
197  lua_pushcfunction(L, impl_widget_collect);
198  lua_setfield(L, -2, "__gc");
199  lua_pushstring(L, widgetKey);
200  lua_setfield(L, -2, "__metatable");
201  }
202 }
Base class for all widgets.
Definition: widget.hpp:53
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:61
Tmust inherit enable_lua_ptr<T>
Definition: lua_ptr.hpp:34
T * get_ptr()
Definition: lua_ptr.hpp:37
int w
void luaW_pushwidget(lua_State *L, gui2::widget &w)
Definition: lua_widget.cpp:30
void luaW_clearwindowtable(lua_State *L, gui2::window *owner)
[-0, +0, -]
Definition: lua_widget.cpp:98
static const char widgetKey[]
Definition: lua_widget.cpp:27
static void luaW_pushwidgettablecontainer(lua_State *L)
Definition: lua_widget.cpp:63
bool luaW_iswidget(lua_State *L, int index)
Definition: lua_widget.cpp:57
void luaW_pushwindowtable(lua_State *L, gui2::window *owner)
[-0, +1, -]
Definition: lua_widget.cpp:76
gui2::widget & luaW_checkwidget(lua_State *L, int n)
Definition: lua_widget.cpp:36
static int impl_widget_collect(lua_State *L)
Definition: lua_widget.cpp:178
bool luaW_setwidgetcallback(lua_State *L, gui2::widget *wg, gui2::window *owner, std::string_view name)
returns true if a callback already existed.
Definition: lua_widget.cpp:135
lua_ptr< gui2::widget > & luaW_checkwidget_ptr(lua_State *L, int n)
Definition: lua_widget.cpp:46
void luaW_getwidgetcallback(lua_State *L, gui2::widget *wg, gui2::window *owner, std::string_view name)
pushed ther callback function onoto the stack [-0, +1, -]
Definition: lua_widget.cpp:157
static char widgetdataKey[]
Definition: lua_widget.cpp:28
void luaW_pushwidgettable(lua_State *L, gui2::widget *wg, gui2::window *owner)
[-0, +1, -]
Definition: lua_widget.cpp:108
void luaW_callwidgetcallback(lua_State *L, gui2::widget *wg, gui2::window *owner, std::string_view name)
callas a widgets callback [-0, +0, e]
Definition: lua_widget.cpp:169
int impl_widget_set(lua_State *L)
void register_metatable(lua_State *L)
Definition: lua_widget.cpp:187
int impl_widget_get(lua_State *L)
int impl_widget_dir(lua_State *L)
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:373
static map_location::DIRECTION n