The Battle for Wesnoth  1.19.5+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/listbox.hpp"
24 #include "gui/widgets/widget.hpp"
25 #include "scripting/lua_common.hpp"
26 #include "scripting/lua_ptr.hpp"
27 #include "scripting/push_check.hpp"
28 
29 
30 
31 
32 static const char widgetKey[] = "widget";
33 static char widgetdataKey[] = "widgetdata";
34 
35 void luaW_pushwidget(lua_State* L, gui2::widget& w)
36 {
37  new(L) lua_ptr<gui2::widget>(w);
38  luaL_setmetatable(L, widgetKey);
39 }
40 
41 gui2::widget& luaW_checkwidget(lua_State* L, int n)
42 {
43  lua_ptr<gui2::widget>& lp = *static_cast<lua_ptr<gui2::widget>*>(luaL_checkudata(L, n, widgetKey));
44  auto ptr = lp.get_ptr();
45  if(!ptr) {
46  luaL_argerror(L, n, "widget was deleted");
47  }
48  return *ptr;
49 }
50 
52 {
53  lua_ptr<gui2::widget>& lp = *static_cast<lua_ptr<gui2::widget>*>(luaL_checkudata(L, n, widgetKey));
54  auto ptr = lp.get_ptr();
55  if(!ptr) {
56  luaL_argerror(L, n, "widget was deleted");
57  }
58  return lp;
59 }
60 
61 
62 bool luaW_iswidget(lua_State* L, int index)
63 {
64  return luaL_testudata(L, index, widgetKey) != nullptr;
65 }
66 
67 
68 static void luaW_pushwidgettablecontainer(lua_State* L)
69 {
70  lua_pushlightuserdata(L, &widgetdataKey[0]);
71  lua_rawget(L, LUA_REGISTRYINDEX);
72  if(lua_isnoneornil(L, -1)) {
73  lua_pop(L, 1);
74  lua_createtable(L, 0, 0);
75  lua_pushlightuserdata(L, &widgetdataKey[0]);
76  lua_pushvalue(L , -2);
77  lua_rawset(L, LUA_REGISTRYINDEX);
78  }
79 }
80 
81 void luaW_pushwindowtable(lua_State* L, gui2::window* owner)
82 {
84  lua_pushlightuserdata(L, owner);
85  lua_rawget(L, -2);
86  if(lua_isnoneornil(L, -1))
87  {
88  //stack: windowstable, nil
89  lua_pop(L, 1);
90  //stack: windowstable
91  lua_createtable(L, 1, 0);
92  //stack: windowstable, {}
93  lua_pushlightuserdata(L, owner);
94  //stack: windowtable, {}, wg_id
95  lua_pushvalue(L, -2);
96  //stack: windowtable, {}, wg_id, {}
97  lua_rawset(L, -4);
98  //stack: windowtable, {}
99  }
100  lua_remove(L, lua_absindex(L, -2));
101 }
102 
103 void luaW_clearwindowtable(lua_State* L, gui2::window* owner)
104 {
106  lua_pushlightuserdata(L, owner);
107  lua_pushnil(L);
108  lua_rawset(L, -3);
109  lua_pop(L, 1);
110 }
111 
112 
113 void luaW_pushwidgettable(lua_State* L, gui2::widget* wg, gui2::window* owner)
114 {
115  luaW_pushwindowtable(L, owner);
116  lua_pushlightuserdata(L, wg);
117  lua_rawget(L, -2);
118  if(lua_isnoneornil(L, -1))
119  {
120  //stack: windowtable, nil
121  lua_pop(L, 1);
122  //stack: windowtable
123  lua_createtable(L, 1, 0);
124  //stack: windowtable, {}
125  luaW_pushwidget(L, *wg);
126  //stack: windowtable, {}, wg
127  lua_rawseti(L, -2, 1);
128  //stack: windowtable, { wg},
129  lua_pushlightuserdata(L, wg);
130  //stack: windowtable, { wg}, wg_id
131  lua_pushvalue(L, -2);
132  //stack: windowtable, { wg}, wg_id, {wg}
133  lua_rawset(L, -4);
134  //stack: windowtable, { wg}
135  }
136  lua_remove(L, lua_absindex(L, -2));
137 }
138 
139 
140 bool luaW_setwidgetcallback(lua_State* L, gui2::widget* wg, gui2::window* owner, std::string_view name)
141 {
142  //stack: function
143  luaW_pushwidgettable(L, wg, owner);
144  //stack: function, {}
145  lua_push(L, name);
146  //stack: function, {}, name
147  lua_rawget(L, -2);
148  // function, old_function
149  bool existed_already = !lua_isnoneornil(L, -1);
150  lua_pop(L, 1);
151  // function,
152  lua_push(L, name);
153  //stack: function, {}, name
154  lua_rotate(L, lua_absindex(L, -3), -1);
155  //stack: {}, name, function
156  lua_rawset(L, -3);
157  //stack: {name = function}
158  lua_pop(L, 1);
159  return existed_already;
160 }
161 
162 void luaW_getwidgetcallback(lua_State* L, gui2::widget* wg, gui2::window* owner, std::string_view name)
163 {
164  luaW_pushwidgettable(L, wg, owner);
165  //stack: {name = function},
166  lua_push(L, name);
167  //stack: {name = function}, name
168  lua_rawget(L, -2);
169  //stack: {name = function}, function
170  lua_remove(L, lua_absindex(L, -2));
171  //stack: function
172 }
173 
174 void luaW_callwidgetcallback(lua_State* L, gui2::widget* wg, gui2::window* owner, std::string_view name)
175 {
176  luaW_getwidgetcallback(L, wg, owner, name);
177  assert(lua_isfunction(L, -1));
178  luaW_pushwidget(L, *wg);
179  lua_call(L, 1, 0);
180 }
181 
182 
183 static int impl_widget_collect(lua_State* L)
184 {
185  lua_ptr<gui2::widget>* w = static_cast<lua_ptr<gui2::widget>*>(luaL_checkudata(L, 1, widgetKey));
186  w->~lua_ptr<gui2::widget>();
187  return 0;
188 }
189 
190 // merge in number_of_items stuff from wiget_methods here?
191 static int impl_widget_length(lua_State* L)
192 {
194  if(gui2::listbox* list = dynamic_cast<gui2::listbox*>(&w)) {
195  lua_pushinteger(L, list->get_item_count());
196  } else if(gui2::multi_page* multi_page = dynamic_cast<gui2::multi_page*>(&w)) {
197  lua_pushinteger(L, multi_page->get_page_count());
198  } else if(gui2::stacked_widget* stacked_widget = dynamic_cast<gui2::stacked_widget*>(&w)) {
199  lua_pushinteger(L, stacked_widget->get_layer_count());
200  } else if(gui2::tree_view* tree_view = dynamic_cast<gui2::tree_view*>(&w)) {
201  lua_pushinteger(L, tree_view->get_root_node().count_children());
202  } else if(gui2::tree_view_node* tree_view_node = dynamic_cast<gui2::tree_view_node*>(&w)) {
203  lua_pushinteger(L, tree_view_node->count_children());
204  } else {
205  luaW_tableget(L, 1, "type");
206  return luaL_error(L, "unsupported widget for # operator: %s", luaL_checkstring(L, -1));
207  }
208  return 1;
209 }
210 
211 namespace lua_widget {
212  void register_metatable(lua_State* L)
213  {
214 
215  luaL_newmetatable(L, widgetKey);
216  lua_pushcfunction(L, lua_widget::impl_widget_get);
217  lua_setfield(L, -2, "__index");
218  lua_pushcfunction(L, lua_widget::impl_widget_set);
219  lua_setfield(L, -2, "__newindex");
220  lua_pushcfunction(L, lua_widget::impl_widget_dir);
221  lua_setfield(L, -2, "__dir");
222  lua_pushcfunction(L, impl_widget_collect);
223  lua_setfield(L, -2, "__gc");
224  lua_pushcfunction(L, impl_widget_length);
225  lua_setfield(L, -2, "__len");
226  lua_pushstring(L, widgetKey);
227  lua_setfield(L, -2, "__metatable");
228  }
229 }
The listbox class.
Definition: listbox.hpp:43
Base class for all widgets.
Definition: widget.hpp:55
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
bool luaW_tableget(lua_State *L, int index, const char *key)
void luaW_pushwidget(lua_State *L, gui2::widget &w)
Definition: lua_widget.cpp:35
void luaW_clearwindowtable(lua_State *L, gui2::window *owner)
[-0, +0, -]
Definition: lua_widget.cpp:103
static const char widgetKey[]
Definition: lua_widget.cpp:32
static void luaW_pushwidgettablecontainer(lua_State *L)
Definition: lua_widget.cpp:68
bool luaW_iswidget(lua_State *L, int index)
Definition: lua_widget.cpp:62
void luaW_pushwindowtable(lua_State *L, gui2::window *owner)
[-0, +1, -]
Definition: lua_widget.cpp:81
static int impl_widget_length(lua_State *L)
Definition: lua_widget.cpp:191
gui2::widget & luaW_checkwidget(lua_State *L, int n)
Definition: lua_widget.cpp:41
static int impl_widget_collect(lua_State *L)
Definition: lua_widget.cpp:183
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:140
lua_ptr< gui2::widget > & luaW_checkwidget_ptr(lua_State *L, int n)
Definition: lua_widget.cpp:51
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:162
static char widgetdataKey[]
Definition: lua_widget.cpp:33
void luaW_pushwidgettable(lua_State *L, gui2::widget *wg, gui2::window *owner)
[-0, +1, -]
Definition: lua_widget.cpp:113
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:174
int impl_widget_set(lua_State *L)
void register_metatable(lua_State *L)
Definition: lua_widget.cpp:212
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:425
static map_location::direction n