Fix debian/rules to build in BUILD/ dir.
[tagua/yd.git] / src / luaapi / loader.cpp
blob6b05e1cb05dba197a3ed2135436824fb86ce0a70
1 /*
2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@gmail.com>
3 (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 */
12 #include <stdlib.h>
13 #include <iostream>
14 #include <QRect>
15 #include <QDir>
17 #include <KConfigGroup>
18 #include <KDesktopFile>
19 #include <KStandardDirs>
21 #include "common.h"
22 #include "loader/image.h"
23 #include "luaapi/imaging.h"
24 #include "luaapi/loader.h"
25 #include "luaapi/options.h"
26 #include "themeinfo.h"
28 namespace LuaApi {
30 const luaL_Reg Loader::lualibs[] = {
31 {"", luaopen_base},
32 {LUA_LOADLIBNAME, luaopen_package},
33 {LUA_TABLIBNAME, luaopen_table},
34 {LUA_IOLIBNAME, luaopen_io},
35 {LUA_OSLIBNAME, luaopen_os},
36 {LUA_STRLIBNAME, luaopen_string},
37 {LUA_MATHLIBNAME, luaopen_math},
38 {LUA_DBLIBNAME, luaopen_debug},
39 {LUA_FUNCLIBNAME, luaopen_func},
40 {LUA_COLLECTLIBNAME, luaopen_collect},
41 {NULL, NULL}
44 Loader::Loader()
45 : m_error(false) {
46 initialize(0);
48 lua_newtable(m_state);
49 lua_setglobal(m_state, "theme");
52 Loader::Loader(::Loader::Context *ctx, const ThemeInfo& theme)
53 : m_error(false) {
54 initialize(ctx);
55 addMetaData(theme);
58 void Loader::addMetaData(const ThemeInfo& theme) {
59 lua_State* const l = m_state;
61 lua_newtable(l);
63 #define ADD_FIELD_AUX(FIELD_NAME, FIELD) \
64 lua_pushstring(l, FIELD_NAME); \
65 lua_pushstring(l, qPrintable(theme.FIELD)); \
66 lua_settable(l, -3);
67 #define ADD_FIELD(FIELD) ADD_FIELD_AUX(#FIELD, FIELD)
69 ADD_FIELD(name);
70 ADD_FIELD(description);
71 ADD_FIELD_AUX("desktop_file", desktopFile);
72 ADD_FIELD(file_name);
73 lua_pushstring(l, "variants");
74 lua_newtable(l);
75 for (int i = 0; i < theme.variants.size(); i++) {
76 lua_pushnumber(l, i);
77 lua_pushstring(l, qPrintable(theme.variants[i]));
78 lua_settable(l, -3);
80 lua_settable(l, -3);
82 #undef ADD_FIELD_AUX
83 #undef ADD_FIELD
85 lua_setglobal(l, "theme");
88 void Loader::initialize(::Loader::Context *ctx) {
89 lua_State* l = lua_open();
90 m_state = l;
92 for (const luaL_Reg *lib = lualibs; lib->func; lib++) {
93 lua_pushcfunction(l, lib->func);
94 lua_pushstring(l, lib->name);
95 lua_call(l, 1, 0);
98 Wrapper<QRectF>::register_class(l);
99 Wrapper<QPointF>::register_class(l);
100 Wrapper<QColor>::register_class(l);
101 Wrapper<QLinearGradient>::register_class(l);
102 Wrapper<QRadialGradient>::register_class(l);
103 Wrapper<QConicalGradient>::register_class(l);
104 Wrapper<QBrush>::register_class(l);
105 Wrapper<QFont>::register_class(l);
106 Wrapper< ::Loader::Image>::register_class(l);
107 Wrapper< ::Loader::Glyph>::register_class(l);
109 Wrapper<OptList>::register_class(l);
110 Wrapper<BoolOptList>::register_class(l);
111 Wrapper<BoolOptPtr>::register_class(l);
112 Wrapper<IntOptPtr>::register_class(l);
113 Wrapper<StringOptPtr>::register_class(l);
114 Wrapper<UrlOptPtr>::register_class(l);
115 Wrapper<ColorOptPtr>::register_class(l);
116 Wrapper<FontOptPtr>::register_class(l);
117 Wrapper<ComboOptPtr>::register_class(l);
118 Wrapper<SelectOptPtr>::register_class(l);
120 lua_pushlightuserdata(l, ctx);
121 lua_setfield(l, LUA_REGISTRYINDEX, LOADING_CONTEXT);
123 lua_pushlightuserdata(l, this);
124 lua_setfield(l, LUA_REGISTRYINDEX, API_LOADER);
126 lua_pushlightuserdata(m_state, &m_curr_dir);
127 lua_setfield(m_state, LUA_REGISTRYINDEX, CURRENT_DIRECTORY);
129 lua_pushcfunction(l, import_func);
130 lua_setglobal(l, "import");
133 Loader::~Loader() {
134 lua_close(m_state);
137 bool Loader::runFile(const QString& file, bool setdir) {
139 QString path = QDir::cleanPath(
140 QDir::isAbsolutePath(file) ? file : m_curr_dir.filePath(file) );
141 if (!QFile::exists(path)) {
142 // find it in the scripts dir
143 path = KStandardDirs::locate("appdata", "scripts/" + file);
145 if (!QFile::exists(path)) {
146 // give up
147 return false;
150 if(setdir) {
151 QFileInfo f_info( path );
152 m_curr_dir = f_info.dir();
155 bool retv;
156 if(luaL_loadfile(m_state, path.toAscii().constData()) == 0) {
157 if(lua_pcall(m_state, 0, LUA_MULTRET, 0) != 0)
158 retv = false;
159 else
160 retv = true;
162 else
163 retv = false;
165 if(!retv) {
166 m_error = true;
167 m_error_string = QString(lua_tostring(m_state, -1));
168 lua_pop(m_state, 1);
171 return retv;
174 template<typename T>
175 struct Loader::create_value_data {
176 const QString& key;
177 int size;
178 const LuaValueMap* args;
179 bool allow_nil;
180 T out;
181 create_value_data(const QString& _key, int _size, const LuaValueMap* _args, bool _allow_nil)
182 : key(_key)
183 , size(_size)
184 , args(_args)
185 , allow_nil(_allow_nil) {
189 template<typename T>
190 T Loader::getValue(const QString& key, int size, const LuaValueMap* args, bool allow_nil) {
191 StackCheck s(m_state);
193 create_value_data<T> data(key, size, args, allow_nil);
194 if(lua_cpcall(m_state, create_value_func<T>, &data) != 0) {
195 m_error = true;
196 m_error_string = QString(lua_tostring(m_state, -1))+"\nsearched key was: "+key;
197 lua_pop(m_state, 1);
198 return T();
200 return data.out;
203 template ::Loader::Glyph Loader::getValue< ::Loader::Glyph>(const QString&, int, const LuaValueMap*, bool);
204 template OptList Loader::getValue<OptList>(const QString&, int, const LuaValueMap*, bool);
205 template QString Loader::getValue<QString>(const QString&, int, const LuaValueMap*, bool);
206 template QStringList Loader::getValue<QStringList>(const QString&, int, const LuaValueMap*, bool);
207 template QImage Loader::getValue<QImage>(const QString&, int, const LuaValueMap*, bool);
208 template ImageOrMap Loader::getValue<ImageOrMap>(const QString&, int, const LuaValueMap*, bool);
209 template double Loader::getValue<double>(const QString&, int, const LuaValueMap*, bool);
210 template QPointF Loader::getValue<QPointF>(const QString&, int, const LuaValueMap*, bool);
211 template QRectF Loader::getValue<QRectF>(const QString&, int, const LuaValueMap*, bool);
212 template QColor Loader::getValue<QColor>(const QString&, int, const LuaValueMap*, bool);
213 template QBrush Loader::getValue<QBrush>(const QString&, int, const LuaValueMap*, bool);
214 template QFont Loader::getValue<QFont>(const QString&, int, const LuaValueMap*, bool);
215 template LuaValueMap Loader::getValue<LuaValueMap>(const QString&, int, const LuaValueMap*, bool);
217 template<typename T>
218 void Loader::retrieve(create_value_data<T>* d, lua_State *l, int pos) {
219 d->out = *Wrapper<T>::retrieve(l, pos, AssertOk);
222 template<>
223 void Loader::retrieve<double>(create_value_data<double>* d, lua_State *l, int pos) {
224 d->out = lua_tonumber(l, pos);
227 template<>
228 void Loader::retrieve<QString>(create_value_data<QString>* d, lua_State *l, int pos) {
229 d->out = lua_tostring(l, pos);
232 template<>
233 void Loader::retrieve<QColor>(create_value_data<QColor>* d, lua_State *l, int pos) {
234 d->out = Wrapper<QColor>::get(l, pos);
237 template<>
238 void Loader::retrieve<QBrush>(create_value_data<QBrush>* d, lua_State *l, int pos) {
239 d->out = Wrapper<QBrush>::get(l, pos);
242 template<>
243 void Loader::retrieve<QStringList>(create_value_data<QStringList>* d, lua_State *l, int pos) {
244 if(lua_isstring(l, pos))
245 d->out << QString(lua_tostring(l, -1));
246 else if(lua_istable(l, pos)) {
247 lua_pushnil(l);
248 while (lua_next(l, pos<0 ? pos-1 : pos) != 0) {
249 d->out << QString(lua_tostring(l, -1));
250 lua_pop(l, 1);
253 else
254 luaL_error(l, "Can't convert to a QStringList (not string nor table)");
257 template<>
258 void Loader::retrieve<LuaValueMap>(create_value_data<LuaValueMap>* d, lua_State *l, int pos) {
259 if(lua_istable(l, pos)) {
260 lua_pushnil(l);
261 while (lua_next(l, pos<0 ? pos-1 : pos) != 0) {
262 QString key = lua_tostring(l, -2);
263 if(QPointF *res = Wrapper<QPointF>::retrieve(l, -1, Check))
264 d->out[key] = *res;
265 else if(QRectF *res = Wrapper<QRectF>::retrieve(l, -1, Check))
266 d->out[key] = *res;
267 else
268 d->out[key] = lua_tonumber(l, -1);
269 lua_pop(l, 1);
272 else
273 luaL_error(l, "Can't convert to a LuaValueMap (not table)");
276 template<>
277 void Loader::retrieve<QImage>(create_value_data<QImage>* d, lua_State *l, int pos) {
278 ::Loader::Image *retv = Wrapper< ::Loader::Image>::retrieve(l, pos, AssertOk);
279 d->out = retv->image();
282 template<>
283 void Loader::retrieve<ImageOrMap>(create_value_data<ImageOrMap>* d, lua_State *l, int pos) {
284 if(::Loader::Image *img = Wrapper< ::Loader::Image>::retrieve(l, pos))
285 d->out = img->image();
286 else if(lua_istable(l, pos)) {
288 //collect the images in this way to avoid leaking memory if Wrapper::retrieve raises an exception
289 d->out = ImageMap();
290 ImageMap& out = boost::get<ImageMap>(d->out);
292 lua_pushnil(l);
293 while (lua_next(l, pos<0 ? pos-1 : pos) != 0) {
294 QRectF *rect = Wrapper<QRectF>::retrieve(l, -2, AssertOk);
295 ::Loader::Image *img = Wrapper< ::Loader::Image>::retrieve(l, -1, AssertOk);
297 QRect r = rect->toRect();
298 out[rect->toRect()] = img->image();
300 lua_pop(l, 1);
303 else
304 luaL_error(l, "Can't convert to a ImageOrMap (not image nor table)");
307 template<typename T>
308 int Loader::create_value_func(lua_State *l) {
309 StackCheck s(l, -1);
310 create_value_data<T>* data = reinterpret_cast<create_value_data<T>*>(lua_touserdata(l, -1));
311 lua_pop(l, 1);
313 lua_getglobal(l, "theme");
314 lua_getfield(l, -1, data->key.toAscii().constData());
315 lua_remove(l, -2);
317 // If it is a function, call it
318 if(lua_isfunction(l, -1)) {
319 int nparams = 0;
320 if(data->size) {
321 lua_pushnumber(l, data->size);
322 nparams++;
324 if(data->args) {
325 lua_pushvaluemap(l, data->args);
326 nparams++;
328 lua_call(l, nparams, 1);
331 // retrieve value
332 if (!lua_isnil(l, -1)) {
333 retrieve<T>(data, l, -1);
335 else if (!data->allow_nil) {
336 luaL_error(l, "No such entry: %s", data->key.toAscii().constData());
339 lua_pop(l, 1);
341 return 0;
345 int Loader::import_func(lua_State *l) {
346 lua_getfield(l, LUA_REGISTRYINDEX, API_LOADER);
347 Loader* api = reinterpret_cast<Loader*>(lua_touserdata(l, -1));
348 lua_pop(l, 1);
350 int n = lua_gettop(l);
351 if (n != 1)
352 luaL_error(l, "Wrong argument count for \"import\"");
353 QString file(lua_tostring(l, 1));
354 lua_pop(l, n);
356 if (!api->runFile(file, false)) {
357 luaL_error(l, "Error importing \"%s\":\n%s", file.toAscii().constData(),
358 api->errorString().toAscii().constData() );
361 return 0;
364 } // namespace LuaLoader