The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
lua_widget.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2009 - 2025
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
18
26#include "scripting/lua_ptr.hpp"
28
29
30
31
32static const char widgetKey[] = "widget";
33static char widgetdataKey[] = "widgetdata";
34
35void luaW_pushwidget(lua_State* L, gui2::widget& w)
36{
38 luaL_setmetatable(L, widgetKey);
39}
40
41gui2::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
62bool luaW_iswidget(lua_State* L, int index)
63{
64 return luaL_testudata(L, index, widgetKey) != nullptr;
65}
66
67
68static 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
81void 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
103void 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
113void 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
140bool 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
162void 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
174void 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
183static 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?
191static 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
211namespace 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:41
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:59
T must inherit enable_lua_ptr<T>
Definition lua_ptr.hpp:66
T * get_ptr()
Definition lua_ptr.hpp:69
bool luaW_tableget(lua_State *L, int index, const char *key)
void luaW_pushwidget(lua_State *L, gui2::widget &w)
void luaW_clearwindowtable(lua_State *L, gui2::window *owner)
[-0, +0, -]
gui2::widget & luaW_checkwidget(lua_State *L, int n)
static const char widgetKey[]
static void luaW_pushwidgettablecontainer(lua_State *L)
bool luaW_iswidget(lua_State *L, int index)
void luaW_pushwindowtable(lua_State *L, gui2::window *owner)
[-0, +1, -]
static int impl_widget_length(lua_State *L)
static int impl_widget_collect(lua_State *L)
bool luaW_setwidgetcallback(lua_State *L, gui2::widget *wg, gui2::window *owner, std::string_view name)
returns true if a callback already existed.
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, -]
static char widgetdataKey[]
void luaW_pushwidgettable(lua_State *L, gui2::widget *wg, gui2::window *owner)
[-0, +1, -]
void luaW_callwidgetcallback(lua_State *L, gui2::widget *wg, gui2::window *owner, std::string_view name)
callas a widgets callback [-0, +0, e]
lua_ptr< gui2::widget > & luaW_checkwidget_ptr(lua_State *L, int n)
int impl_widget_set(lua_State *L)
void register_metatable(lua_State *L)
int impl_widget_get(lua_State *L)
int impl_widget_dir(lua_State *L)
int w
Definition pathfind.cpp:188
void lua_push(lua_State *L, const T &val)
static map_location::direction n