mirror of
https://github.com/tuxbox-neutrino/neutrino.git
synced 2025-08-29 16:31:11 +02:00
LUA: experimental support for native neutrino menues
Signed-off-by: M. Liebmann <tuxcode.bbg@gmail.com>
This commit is contained in:
@@ -26,6 +26,9 @@
|
||||
#include <global.h>
|
||||
#include <system/settings.h>
|
||||
#include <gui/widget/msgbox.h>
|
||||
#ifdef MARTII
|
||||
#include <gui/filebrowser.h>
|
||||
#endif
|
||||
#include <neutrino.h>
|
||||
|
||||
#include "luainstance.h"
|
||||
@@ -220,6 +223,17 @@ static void set_lua_variables(lua_State *L)
|
||||
{ "END_Y", g_settings.screen_EndY },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
#ifdef MARTII
|
||||
table_key menureturn[] =
|
||||
{
|
||||
{ "NONE", menu_return::RETURN_NONE },
|
||||
{ "REPAINT", menu_return::RETURN_REPAINT },
|
||||
{ "EXIT", menu_return::RETURN_EXIT },
|
||||
{ "EXIT_ALL", menu_return::RETURN_EXIT_ALL },
|
||||
{ "EXIT_REPAINT", menu_return::RETURN_EXIT_REPAINT },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
#endif
|
||||
|
||||
/* list of environment variable arrays to be exported */
|
||||
lua_envexport e[] =
|
||||
@@ -229,6 +243,9 @@ static void set_lua_variables(lua_State *L)
|
||||
{ "SCREEN", screenopts },
|
||||
{ "FONT", fontlist },
|
||||
{ "CORNER", corners },
|
||||
#ifdef MARTII
|
||||
{ "MENU_RETURN", menureturn },
|
||||
#endif
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -378,6 +395,9 @@ void CLuaInstance::registerFunctions()
|
||||
lua_pop(lua, 1);
|
||||
|
||||
lua_register(lua, className, NewWindow);
|
||||
#ifdef MARTII
|
||||
MenueRegister(lua);
|
||||
#endif
|
||||
}
|
||||
|
||||
CLuaData *CLuaInstance::CheckData(lua_State *L, int narg)
|
||||
@@ -561,3 +581,374 @@ int CLuaInstance::GCWindow(lua_State *L)
|
||||
delete w;
|
||||
return 0;
|
||||
}
|
||||
#ifdef MARTII
|
||||
#if 0
|
||||
local m = menue.new{name="mytitle", icon="myicon", hide_parent=true}
|
||||
m:addItem{type="back"}
|
||||
m:addItem{type="separator"}
|
||||
|
||||
function talk(a)
|
||||
print(">talk")
|
||||
print(a)
|
||||
print("<talk")
|
||||
return MENU_RETURN["RETURN_REPAINT"]
|
||||
end
|
||||
|
||||
function anotherMenue()
|
||||
print(">>anothermenue");
|
||||
local m = menue.new{name="anothermenue", icon="settings"}
|
||||
m:addItem{type="back"}
|
||||
m:addItem{type="separator"}
|
||||
m:addItem{type="numeric", name="testnumeric"}
|
||||
m:exec()
|
||||
print("<<anothermenue");
|
||||
end
|
||||
|
||||
|
||||
m:addItem{type="chooser", name="testchooser", action="talk", options={ "on", "off", "auto" }, icon=
|
||||
m:addItem{type="forwarder", name="testforwarder", action="anotherMenue", icon="network"}
|
||||
m:addItem{type="separator"}
|
||||
m:addItem{type="numeric", name="testnumeric", action="talk"}
|
||||
m:addItem{type="separator"}
|
||||
m:addItem{type="filebrowser", name="fbrowser", action="talk"}
|
||||
m:addItem{type="separator"}
|
||||
m:addItem{type="stringinput", name="stringinput", action="talk"}
|
||||
m:exec()
|
||||
#endif
|
||||
|
||||
bool CLuaInstance::tableLookupString(lua_State *L, const char *what, std::string &value)
|
||||
{
|
||||
bool res = false;
|
||||
lua_pushstring(L, what);
|
||||
lua_gettable(L, -2);
|
||||
res = lua_isstring(L, -1);
|
||||
if (res)
|
||||
value = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CLuaInstance::tableLookupInt(lua_State *L, const char *what, int &value)
|
||||
{
|
||||
bool res = false;
|
||||
lua_pushstring(L, what);
|
||||
lua_gettable(L, -2);
|
||||
res = lua_isnumber(L, -1);
|
||||
if (res)
|
||||
value = (int) lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CLuaMenueChangeObserver::changeNotify(lua_State *L, const std::string &luaAction, void *Data)
|
||||
{
|
||||
const char *optionValue = (const char *) Data;
|
||||
lua_pushglobaltable(L);
|
||||
lua_getfield(L, -1, luaAction.c_str());
|
||||
lua_remove(L, -2);
|
||||
lua_pushstring(L, optionValue);
|
||||
lua_pcall(L, 1 /* one arg */, 1 /* one result */, 0);
|
||||
double res = lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0;
|
||||
fprintf(stderr, "res is %d\n", (int)res);
|
||||
lua_pop(L, 1);
|
||||
return res == menu_return::RETURN_REPAINT || res == menu_return::RETURN_EXIT_REPAINT;
|
||||
}
|
||||
|
||||
void CLuaInstance::MenueRegister(lua_State *L)
|
||||
{
|
||||
luaL_Reg meth[] = {
|
||||
{ "new", CLuaInstance::MenueNew },
|
||||
{ "addItem", CLuaInstance::MenueAddItem },
|
||||
{ "exec", CLuaInstance::MenueExec },
|
||||
{ "hide", CLuaInstance::MenueHide },
|
||||
{ "__gc", CLuaInstance::MenueDelete },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
luaL_newmetatable(L, "menue");
|
||||
luaL_setfuncs(L, meth, 0);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -1, "__index");
|
||||
lua_setglobal(L, "menue");
|
||||
}
|
||||
|
||||
CLuaMenue *CLuaInstance::MenueCheck(lua_State *L, int n)
|
||||
{
|
||||
return *(CLuaMenue **) luaL_checkudata(L, n, "menue");
|
||||
}
|
||||
|
||||
CLuaMenue::CLuaMenue()
|
||||
{
|
||||
m = NULL;
|
||||
observ = new CLuaMenueChangeObserver();
|
||||
}
|
||||
|
||||
CLuaMenue::~CLuaMenue()
|
||||
{
|
||||
delete m;
|
||||
delete observ;
|
||||
}
|
||||
|
||||
CLuaMenueForwarder::CLuaMenueForwarder(lua_State *_L, std::string _luaAction)
|
||||
{
|
||||
L = _L;
|
||||
luaAction = _luaAction;
|
||||
}
|
||||
|
||||
CLuaMenueForwarder::~CLuaMenueForwarder()
|
||||
{
|
||||
}
|
||||
|
||||
int CLuaMenueForwarder::exec(CMenuTarget* /*parent*/, const std::string & /*actionKey*/)
|
||||
{
|
||||
CFileBrowser fileBrowser;
|
||||
if (!luaAction.empty()){
|
||||
lua_pushglobaltable(L);
|
||||
lua_getfield(L, -1, luaAction.c_str());
|
||||
lua_remove(L, -2);
|
||||
lua_pcall(L, 0 /* no arg */, 1 /* one result */, 0);
|
||||
//double res = lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return menu_return::RETURN_REPAINT;
|
||||
}
|
||||
CLuaMenueFilebrowser::CLuaMenueFilebrowser(lua_State *_L, std::string _luaAction, char *_value)
|
||||
{
|
||||
L = _L;
|
||||
luaAction = _luaAction;
|
||||
value = _value;
|
||||
}
|
||||
|
||||
CLuaMenueFilebrowser::~CLuaMenueFilebrowser()
|
||||
{
|
||||
}
|
||||
|
||||
int CLuaMenueFilebrowser::exec(CMenuTarget* /*parent*/, const std::string & /*actionKey*/)
|
||||
{
|
||||
CFileBrowser fileBrowser;
|
||||
#if 0 // NOTYET
|
||||
CFileFilter fileFilter;
|
||||
fileFilter.addFilter("...");
|
||||
fileBrowser.Filter = &fileFilter;
|
||||
#endif
|
||||
if (fileBrowser.exec(value) == true)
|
||||
strcpy(value, fileBrowser.getSelectedFile()->Name.c_str());
|
||||
if (!luaAction.empty()){
|
||||
lua_pushglobaltable(L);
|
||||
lua_getfield(L, -1, luaAction.c_str());
|
||||
lua_remove(L, -2);
|
||||
lua_pushstring(L, value);
|
||||
lua_pcall(L, 1 /* one arg */, 1 /* one result */, 0);
|
||||
//double res = lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return menu_return::RETURN_REPAINT;
|
||||
}
|
||||
|
||||
CLuaMenueStringinput::CLuaMenueStringinput(lua_State *_L, std::string _luaAction, const char *_name, char *_value, int _size, std::string _valid_chars, CChangeObserver *_observ, const char *_icon)
|
||||
{
|
||||
L = _L;
|
||||
luaAction = _luaAction;
|
||||
name = _name;
|
||||
value = _value;
|
||||
size = _size;
|
||||
valid_chars = _valid_chars;
|
||||
icon = _icon;
|
||||
observ = _observ;
|
||||
}
|
||||
|
||||
CLuaMenueStringinput::~CLuaMenueStringinput()
|
||||
{
|
||||
}
|
||||
|
||||
int CLuaMenueStringinput::exec(CMenuTarget* /*parent*/, const std::string & /*actionKey*/)
|
||||
{
|
||||
CStringInput i((char *)name, value, size, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, valid_chars.c_str(), observ, icon);
|
||||
i.luaAction = luaAction;
|
||||
i.luaState = L;
|
||||
i.exec(NULL, "");
|
||||
return menu_return::RETURN_REPAINT;
|
||||
}
|
||||
|
||||
|
||||
int CLuaInstance::MenueNew(lua_State *L)
|
||||
{
|
||||
CMenuWidget *m;
|
||||
|
||||
if (lua_istable(L, 1)) {
|
||||
std::string name, icon;
|
||||
tableLookupString(L, "name", name) || tableLookupString(L, "title", name);
|
||||
tableLookupString(L, "icon", icon);
|
||||
int mwidth;
|
||||
if(tableLookupInt(L, "mwidth", mwidth))
|
||||
m = new CMenuWidget(name.c_str(), icon.c_str(), mwidth);
|
||||
else
|
||||
m = new CMenuWidget(name.c_str(), icon.c_str());
|
||||
} else
|
||||
m = new CMenuWidget();
|
||||
|
||||
CLuaMenue **udata = (CLuaMenue **) lua_newuserdata(L, sizeof(CLuaMenue *));
|
||||
*udata = new CLuaMenue();
|
||||
(*udata)->m = m;
|
||||
luaL_getmetatable(L, "menue");
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CLuaInstance::MenueDelete(lua_State *L)
|
||||
{
|
||||
CLuaMenue *m = MenueCheck(L, 1);
|
||||
|
||||
while(!m->targets.empty()) {
|
||||
delete m->targets.front();
|
||||
m->targets.pop_front();
|
||||
}
|
||||
while(!m->tofree.empty()) {
|
||||
free(m->tofree.front());
|
||||
m->tofree.pop_front();
|
||||
}
|
||||
|
||||
delete m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CLuaInstance::MenueAddItem(lua_State *L)
|
||||
{
|
||||
CLuaMenue *m = MenueCheck(L, 1);
|
||||
lua_assert(lua_istable(L, 2));
|
||||
|
||||
CLuaMenueItem i;
|
||||
m->items.push_front(i);
|
||||
std::list<CLuaMenueItem>::iterator it = m->items.begin();
|
||||
|
||||
tableLookupString(L, "name", (*it).name);
|
||||
std::string type; tableLookupString(L, "type", type);
|
||||
|
||||
if (type == "back") {
|
||||
m->m->addItem(GenericMenuBack);
|
||||
} else if (type == "separator") {
|
||||
if (!(*it).name.empty())
|
||||
m->m->addItem(new CNonLocalizedMenuSeparator((*it).name.c_str(), NONEXISTANT_LOCALE));
|
||||
else
|
||||
m->m->addItem(GenericMenuSeparatorLine);
|
||||
} else {
|
||||
tableLookupString(L, "icon", (*it).Icon);
|
||||
tableLookupString(L, "right_icon", (*it).right_Icon);
|
||||
std::string action; tableLookupString(L, "action", action);
|
||||
std::string shortcut; tableLookupString(L, "shortcut", shortcut);
|
||||
std::string value; tableLookupString(L, "value", value);
|
||||
int directkey = CRCInput::RC_nokey; tableLookupInt(L, "directkey", directkey);
|
||||
int pulldown = false; tableLookupInt(L, "pulldown", pulldown);
|
||||
const char *icon = (*it).Icon.c_str();
|
||||
const char *right_icon = (*it).right_Icon.c_str();
|
||||
if (!*icon)
|
||||
icon = NULL;
|
||||
if (!*right_icon)
|
||||
right_icon = NULL;
|
||||
|
||||
std::string tmp = "true";
|
||||
tableLookupString(L, "enabled", tmp) || tableLookupString(L, "active", tmp);
|
||||
bool enabled = (tmp == "true" || tmp == "1" || tmp == "yes");
|
||||
tableLookupString(L, "range", tmp);
|
||||
int range_from = 0, range_to = 99;
|
||||
sscanf(tmp.c_str(), "%d,%d", &range_from, &range_to);
|
||||
|
||||
if (type == "forwarder") {
|
||||
strncpy((*it).s, value.c_str(), sizeof((*it).s));
|
||||
CLuaMenueForwarder *forwarder = new CLuaMenueForwarder(L, action);
|
||||
CMenuItem *mi = new CMenuForwarderNonLocalized(
|
||||
(*it).name.c_str(), enabled, (*it).s, forwarder, NULL/*ActionKey*/, directkey, icon, right_icon);
|
||||
mi->luaAction = action;
|
||||
mi->luaState = L;
|
||||
m->m->addItem(mi);
|
||||
m->targets.push_front(forwarder);
|
||||
} else if (type == "chooser") {
|
||||
int options_count = 0;
|
||||
lua_pushstring(L, "options");
|
||||
lua_gettable(L, -2);
|
||||
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 2)) {
|
||||
lua_pushvalue(L, -2);
|
||||
options_count++;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
CMenuOptionChooser::keyval_ext *kext = (CMenuOptionChooser::keyval_ext *)calloc(options_count, sizeof(CMenuOptionChooser::keyval_ext));
|
||||
m->tofree.push_front(kext);
|
||||
lua_pushstring(L, "options");
|
||||
lua_gettable(L, -2);
|
||||
(*it).i = 0;
|
||||
int j = 0;
|
||||
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 2)) {
|
||||
lua_pushvalue(L, -2);
|
||||
const char *key = lua_tostring(L, -1);
|
||||
const char *val = lua_tostring(L, -2);
|
||||
kext[j].key = atoi(key);
|
||||
kext[j].value = NONEXISTANT_LOCALE;
|
||||
kext[j].valname = strdup(val);
|
||||
m->tofree.push_front((void *)kext[j].valname);
|
||||
if (!strcmp(value.c_str(), kext[j].valname))
|
||||
(*it).i = j;
|
||||
j++;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
CMenuItem *mi = new CMenuOptionChooser((*it).name.c_str(), &(*it).i, kext, options_count, enabled, m->observ, directkey, icon, pulldown);
|
||||
mi->luaAction = action;
|
||||
mi->luaState = L;
|
||||
m->m->addItem(mi);
|
||||
} else if (type == "numeric") {
|
||||
(*it).i = range_from;
|
||||
sscanf(value.c_str(), "%d", &(*it).i);
|
||||
CMenuItem *mi = new CMenuOptionNumberChooser(NONEXISTANT_LOCALE, &(*it).i, enabled, range_from, range_to, m->observ,
|
||||
0, 0, NONEXISTANT_LOCALE, (*it).name.c_str(), pulldown);
|
||||
mi->luaAction = action;
|
||||
mi->luaState = L;
|
||||
m->m->addItem(mi);
|
||||
} else if (type == "string") {
|
||||
strncpy((*it).s, value.c_str(), sizeof((*it).s));
|
||||
CMenuItem *mi = new CMenuOptionStringChooser((*it).name.c_str(), (*it).s, enabled, m->observ, directkey, icon, pulldown);
|
||||
mi->luaAction = action;
|
||||
mi->luaState = L;
|
||||
m->m->addItem(mi);
|
||||
|
||||
} else if (type == "stringinput") {
|
||||
strncpy((*it).s, value.c_str(), sizeof((*it).s));
|
||||
std::string valid_chars = " 0123456789. ";
|
||||
tableLookupString(L, "valid_chars", valid_chars);
|
||||
int size = 30;
|
||||
tableLookupInt(L, "size", size);
|
||||
CLuaMenueStringinput *stringinput = new CLuaMenueStringinput(L, action, (*it).name.c_str(), (*it).s, size, valid_chars, m->observ, icon);
|
||||
CMenuItem *mi = new CMenuForwarderNonLocalized(
|
||||
(*it).name.c_str(), enabled, (*it).s, stringinput, NULL/*ActionKey*/, directkey, icon, right_icon);
|
||||
mi->luaAction = action;
|
||||
mi->luaState = L;
|
||||
m->m->addItem(mi);
|
||||
m->targets.push_front(stringinput);
|
||||
} else if (type == "filebrowser") {
|
||||
strncpy((*it).s, value.c_str(), sizeof((*it).s));
|
||||
CLuaMenueFilebrowser *filebrowser = new CLuaMenueFilebrowser(L, action, (*it).s);
|
||||
CMenuItem *mi = new CMenuForwarderNonLocalized(
|
||||
(*it).name.c_str(), enabled, (*it).s, filebrowser, NULL/*ActionKey*/, directkey, icon, right_icon);
|
||||
mi->luaAction = action;
|
||||
mi->luaState = L;
|
||||
m->m->addItem(mi);
|
||||
m->targets.push_front(filebrowser);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CLuaInstance::MenueHide(lua_State *L)
|
||||
{
|
||||
CLuaMenue *m = MenueCheck(L, 1);
|
||||
m->m->hide();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CLuaInstance::MenueExec(lua_State *L)
|
||||
{
|
||||
CLuaMenue *m = MenueCheck(L, 1);
|
||||
m->m->exec(NULL, "");
|
||||
m->m->hide();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@@ -26,6 +26,9 @@ extern "C" {
|
||||
#include <lualib.h>
|
||||
}
|
||||
#include <driver/fb_window.h>
|
||||
#ifdef MARTII
|
||||
#include <gui/widget/menue.h>
|
||||
#endif
|
||||
|
||||
/* this is stored as userdata in the lua_State */
|
||||
struct CLuaData
|
||||
@@ -33,12 +36,86 @@ struct CLuaData
|
||||
CFBWindow *fbwin;
|
||||
CRCInput *rcinput;
|
||||
};
|
||||
#ifdef MARTII
|
||||
struct CLuaMenueItem
|
||||
{
|
||||
union
|
||||
{
|
||||
int i;
|
||||
char s[255];
|
||||
};
|
||||
std::string name;
|
||||
std::string Icon;
|
||||
std::string right_Icon;
|
||||
};
|
||||
|
||||
class CLuaMenueChangeObserver : public CChangeObserver
|
||||
{
|
||||
public:
|
||||
bool changeNotify(lua_State *, const std::string &, void *);
|
||||
};
|
||||
|
||||
class CLuaMenue
|
||||
{
|
||||
public:
|
||||
CMenuWidget *m;
|
||||
CLuaMenueChangeObserver *observ;
|
||||
std::list<CLuaMenueItem> items;
|
||||
std::list<CMenuTarget *> targets;
|
||||
std::list<void *> tofree;
|
||||
CLuaMenue();
|
||||
~CLuaMenue();
|
||||
};
|
||||
|
||||
class CLuaMenueForwarder : public CMenuTarget
|
||||
{
|
||||
private:
|
||||
lua_State *L;
|
||||
std::string luaAction;
|
||||
public:
|
||||
CLuaMenueForwarder(lua_State *L, std::string _luaAction);
|
||||
~CLuaMenueForwarder();
|
||||
int exec(CMenuTarget* parent, const std::string & actionKey);
|
||||
};
|
||||
|
||||
class CLuaMenueFilebrowser : public CMenuTarget
|
||||
{
|
||||
private:
|
||||
lua_State *L;
|
||||
std::string luaAction;
|
||||
char *value;
|
||||
public:
|
||||
CLuaMenueFilebrowser(lua_State *L, std::string _luaAction, char *_value);
|
||||
~CLuaMenueFilebrowser();
|
||||
int exec(CMenuTarget* parent, const std::string & actionKey);
|
||||
};
|
||||
|
||||
class CLuaMenueStringinput : public CMenuTarget
|
||||
{
|
||||
private:
|
||||
lua_State *L;
|
||||
std::string luaAction;
|
||||
const char *name;
|
||||
char *value;
|
||||
int size;
|
||||
std::string valid_chars;
|
||||
CChangeObserver *observ;
|
||||
const char *icon;
|
||||
public:
|
||||
CLuaMenueStringinput(lua_State *_L, std::string _luaAction, const char *_name, char *_value, int _size, std::string _valid_chars, CChangeObserver *_observ, const char *_icon);
|
||||
~CLuaMenueStringinput();
|
||||
int exec(CMenuTarget* /*parent*/, const std::string & /*actionKey*/);
|
||||
};
|
||||
#endif
|
||||
|
||||
/* inspired by Steve Kemp http://www.steve.org.uk/ */
|
||||
class CLuaInstance
|
||||
{
|
||||
static const char className[];
|
||||
static const luaL_Reg methods[];
|
||||
#ifdef MARTII
|
||||
static const luaL_Reg menue_methods[];
|
||||
#endif
|
||||
static CLuaData *CheckData(lua_State *L, int narg);
|
||||
public:
|
||||
CLuaInstance();
|
||||
@@ -56,6 +133,17 @@ private:
|
||||
static int FontHeight(lua_State *L);
|
||||
static int GetInput(lua_State *L);
|
||||
static int GCWindow(lua_State *L);
|
||||
#ifdef MARTII
|
||||
void MenueRegister(lua_State *L);
|
||||
static int MenueNew(lua_State *L);
|
||||
static int MenueDelete(lua_State *L);
|
||||
static int MenueAddItem(lua_State *L);
|
||||
static int MenueHide(lua_State *L);
|
||||
static int MenueExec(lua_State *L);
|
||||
static CLuaMenue *MenueCheck(lua_State *L, int n);
|
||||
static bool tableLookupString(lua_State*, const char*, std::string&);
|
||||
static bool tableLookupInt(lua_State*, const char*, int&);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* _LUAINSTANCE_H */
|
||||
|
Reference in New Issue
Block a user