Navi Lua
From NaviWiki
I needed the Navi Library to be Lua friendly, so I wrote a simple wrapper for most of the NaviManager functions. The following is barely tested but works for my use. Buyer Beware!
NaviLua library v0.4 Mark Manyen (MadMark) 08/05/2008 This library provides an interface to the Navi library to the Lua language. Usage: Include NaviLua.h and NaviLua.cpp in your project and provide access to the Lua source and the Navi library via your project include path. Call the init function on startup (initNaviLua(lua_State *pLua)). NaviLua is designed to use your existing Lua state, if you don't have one you will need to create one to pass into the init function. Using the library in Lua is very close to using the Navi library in C++, except for the following deviations from the standard Navi lilbrary calling conventions: ---------- The NaviData object is replaced with a standard Lua table with an entry “naviDataName” set to the NaviData name. The data name string is the key to the table so you can reference it in the standard Lua manner (i.e. MyValue = myNaviData[“key”]) ---------- ---------- createNavi position override takes a string instead of the standard NaviLibrary enum. The recognized strings are: "Left” "TopLeft" "TopCenter" "TopRight" "Right" "BottomRight" "BottomCenter" "BottomLeft" “Center”. ---------- ---------- The NaviEventListener object is replaced with a single Lua function. The name of the Lua function to call on events is passed to addNaviEventListener as a string. The referenced function has the following signature: function LuaNaviDataEvent(eventType, naviName, data, param) eventType is a string, “Data” or “LinkClicked” naviName is then name of the navi generatin the event data is the name of the naviData (for “Data”) or the link href (for “LinkClicked”) param is a table containg the naviData ---------- Release History: v0.4 Updated to Beta Navi 1.6 v0.3 Updated to the latest API (SVN Version 16) v0.2 Removed the dependancy on CLua and fleashed out the API v0.1 Initial Release, only what I needed to get started on my main projects
NaviLua.h
#pragma once struct lua_State; void initNaviLua(lua_State *pLua = NULL); bool RunLuaScript(const char *pFilename);
NaviLua.cpp
#include "StdAfx.h"
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#include <Navi.h>
#include <NaviLua.h>
// handle little macro that helps to define lua glue functions
#define LuaGlue(n) extern "C" int n(lua_State *L)
using namespace NaviLibrary;
LuaGlue (_createNavi)
{
int argNum = 1;
const std::string pName = luaL_checkstring(L, argNum++);
const std::string pUrl = luaL_checkstring(L, argNum++);
short x=0,y=0,w,h;
const char *pPositionCmd = NULL;
RelativePosition p = Left;
if(lua_type(L, argNum) == LUA_TSTRING) // position based on string command
{
pPositionCmd = luaL_checkstring(L, argNum++);
// parse
if(strcmp(pPositionCmd, "Left") == 0)
p = Left;
if(strcmp(pPositionCmd, "TopLeft") == 0)
p = TopLeft;
if(strcmp(pPositionCmd, "TopCenter") == 0)
p = TopCenter;
if(strcmp(pPositionCmd, "TopRight") == 0)
p = TopRight;
if(strcmp(pPositionCmd, "Right") == 0)
p = Right;
if(strcmp(pPositionCmd, "BottomRight") == 0)
p = BottomRight;
if(strcmp(pPositionCmd, "BottomCenter") == 0)
p = BottomCenter;
if(strcmp(pPositionCmd, "BottomLeft") == 0)
p = BottomLeft;
if(strcmp(pPositionCmd, "Center") == 0)
p = Center;
}
// x and y are now required even after a RelativePosition, they will be used as offsets if rel
x = (short) luaL_checkint(L, argNum++);
y = (short) luaL_checkint(L, argNum++);
w = (short) luaL_checkint(L, argNum++);
h = (short) luaL_checkint(L, argNum++);
unsigned short zOrder = (unsigned int)luaL_optnumber(L, argNum++, 0);
bool hideUntilLoaded = true;
if(lua_type(L, argNum) == LUA_TBOOLEAN)
hideUntilLoaded = lua_toboolean(L, argNum) != 0;
argNum++;
NaviLibrary::NaviPosition *naviPos;
if(pPositionCmd)
{
naviPos = new NaviLibrary::NaviPosition(p, x, y);
}
else
{
naviPos = new NaviLibrary::NaviPosition(x, y);
}
NaviLibrary::NaviManager::Get().createNavi(pName, pUrl, *naviPos, w, h, zOrder, hideUntilLoaded);
delete naviPos;
return 0;
}
LuaGlue (_setNaviMask)
{
#if 0
const char *pName = luaL_checkstring(L, 1);
const char *pMaskName = luaL_checkstring(L, 2);
NaviLibrary::NaviManager::Get().setNaviMask(pName, pMaskName);
#else
assert(false); //setNaviMask no longer supported
#endif
return 0;
}
/////////////////////////////////////////////////////////////
class cLuaNaviFunctor : public NaviLibrary::NaviEventListener
{
public:
cLuaNaviFunctor(const char *pLuaFunc, lua_State *pLua) {m_sLuaFunc = pLuaFunc; m_pLuaState = pLua;}
void onNaviDataEvent(Navi *pNavi, const NaviLibrary::NaviData &naviData);
void onNavigateBegin(Navi* caller, const std::string& url, bool &shouldContinue);
void onLocationChange(Navi* caller, const std::string &url);
void onNavigateComplete(Navi* caller, const std::string &url, int responseCode);
private:
std::string m_sLuaFunc;
lua_State *m_pLuaState;
};
void cLuaNaviFunctor::onNaviDataEvent(Navi *pNavi, const NaviLibrary::NaviData &naviData)
{
std::string naviName = pNavi->getName();
std::string LuaCommand = m_sLuaFunc + "(\"Data\", \"" + naviName + "\", \"" + naviData.getName() + "\", {";
NaviLibrary::NaviData myData = naviData;
std::map<std::string,std::string> naviDataMap;
naviDataMap = myData.toStringMap(false);
std::map<std::string,std::string>::iterator it = naviDataMap.begin();
while(it != naviDataMap.end())
{
LuaCommand += (*it).first;
LuaCommand += "=\"";
LuaCommand += (*it).second;
LuaCommand += "\", ";
++it;
}
char buf[16];
sprintf(buf, "n=%d})", naviDataMap.size());
LuaCommand += buf;
if (0 != luaL_loadbuffer(m_pLuaState, LuaCommand.c_str(), LuaCommand.size(), "navilua"))
{
char ebuf[1025];
sprintf(ebuf, "Lua Load Error!\nCommand:%s\nError Message:%s\n", LuaCommand.c_str(), luaL_checkstring(m_pLuaState, -1));
throw ebuf;
}
if (0 != lua_pcall(m_pLuaState, 0, LUA_MULTRET, 0))
{
char ebuf[1025];
sprintf(ebuf, "Lua Run Error!\nCommand:%s\nError Message:%s\n", LuaCommand.c_str(), luaL_checkstring(m_pLuaState, -1));
throw ebuf;
}
}
void cLuaNaviFunctor::onNavigateBegin(Navi *pNavi, const std::string& url, bool &shouldContinue)
{
#if 0
std::string naviName = pNavi->getName();
std::string LuaCommand = m_sLuaFunc + "(\"LinkClicked\", \"" + naviName + "\", \"" + linkHref + "\")";
if (0 != luaL_loadbuffer(m_pLuaState, LuaCommand.c_str(), LuaCommand.size(), "navilua"))
{
char ebuf[256];
sprintf(ebuf, "Lua Load Error!\nCommand:%s\nError Message:%s\n", LuaCommand.c_str(), luaL_checkstring(m_pLuaState, -1));
throw ebuf;
}
if (0 != lua_pcall(m_pLuaState, 0, LUA_MULTRET, 0))
{
char ebuf[256];
sprintf(ebuf, "Lua Run Error!\nCommand:%s\nError Message:%s\n", LuaCommand.c_str(), luaL_checkstring(m_pLuaState, -1));
throw ebuf;
}
#endif
}
void cLuaNaviFunctor::onLocationChange(Navi *pNavi, const std::string &linkHref)
{
#if 0
std::string naviName = pNavi->getName();
std::string LuaCommand = m_sLuaFunc + "(\"LinkClicked\", \"" + naviName + "\", \"" + linkHref + "\")";
if (0 != luaL_loadbuffer(m_pLuaState, LuaCommand.c_str(), LuaCommand.size(), "navilua"))
{
char ebuf[256];
sprintf(ebuf, "Lua Load Error!\nCommand:%s\nError Message:%s\n", LuaCommand.c_str(), luaL_checkstring(m_pLuaState, -1));
throw ebuf;
}
if (0 != lua_pcall(m_pLuaState, 0, LUA_MULTRET, 0))
{
char ebuf[256];
sprintf(ebuf, "Lua Run Error!\nCommand:%s\nError Message:%s\n", LuaCommand.c_str(), luaL_checkstring(m_pLuaState, -1));
throw ebuf;
}
#endif
}
void cLuaNaviFunctor::onNavigateComplete(Navi *pNavi, const std::string &linkHref, int responseCode)
{
#if 0
std::string naviName = pNavi->getName();
std::string LuaCommand = m_sLuaFunc + "(\"LinkClicked\", \"" + naviName + "\", \"" + linkHref + "\")";
if (0 != luaL_loadbuffer(m_pLuaState, LuaCommand.c_str(), LuaCommand.size(), "navilua"))
{
char ebuf[256];
sprintf(ebuf, "Lua Load Error!\nCommand:%s\nError Message:%s\n", LuaCommand.c_str(), luaL_checkstring(m_pLuaState, -1));
throw ebuf;
}
if (0 != lua_pcall(m_pLuaState, 0, LUA_MULTRET, 0))
{
char ebuf[256];
sprintf(ebuf, "Lua Run Error!\nCommand:%s\nError Message:%s\n", LuaCommand.c_str(), luaL_checkstring(m_pLuaState, -1));
throw ebuf;
}
#endif
}
static std::map<std::string, cLuaNaviFunctor *> s_mapFunctors;
LuaGlue (_addNaviEventListener)
{
int argNum = 1;
const char *pName = luaL_checkstring(L, argNum++);
std::string luaFuncName = luaL_checkstring(L, argNum++);
s_mapFunctors[luaFuncName] = new cLuaNaviFunctor(luaFuncName.c_str(), L);
Navi *pNavi = NaviLibrary::NaviManager::Get().getNavi(pName);
pNavi->addEventListener(s_mapFunctors[luaFuncName]);
return 0;
}
LuaGlue (_destroyNavi)
{
const char *pName = luaL_checkstring(L, 1);
// need to create a way to remove any event listeners associated with this navi
NaviLibrary::NaviManager::Get().destroyNavi(pName);
return 0;
}
LuaGlue(_removeNaviEventListener)
{
int argNum = 1;
const char *pName = luaL_checkstring(L, argNum++);
std::string luaFuncName = luaL_checkstring(L, argNum++);
cLuaNaviFunctor *pFunctor = s_mapFunctors[luaFuncName];
if(pFunctor)
{
Navi *pNavi = NaviLibrary::NaviManager::Get().getNavi(pName);
pNavi->removeEventListener(pFunctor);
s_mapFunctors[luaFuncName] = NULL;
delete pFunctor;
}
return 0;
}
/////////////////////////////////////////////////////////////
LuaGlue (_setNaviColorKey)
{
#if 0
int argNum = 1;
const char *pName = luaL_checkstring(L, argNum++);
const char *pColorStr = luaL_checkstring(L, argNum++);
float keyFillOpacity = (float) luaL_optnumber(L, argNum++, 0);
const char *keyFillColor = luaL_optstring(L, argNum++, "#000000");
float keyFuzziness = (float) luaL_optnumber(L, argNum++, 0);
Navi *pNavi = NaviLibrary::NaviManager::Get().getNavi(pName);
setNaviColorKey(pName, pColorStr, keyFillOpacity, keyFillColor, keyFuzziness);
#else
assert(false); //no longer supported
#endif
return 0;
}
LuaGlue(_navigateNaviTo)
{
int argNum = 1;
const char *pName = luaL_checkstring(L, argNum++);
const char *pUrl = luaL_checkstring(L, argNum++);
Navi *pNavi = NaviLibrary::NaviManager::Get().getNavi(pName);
std::map<std::string, std::string> mapTable;
if(lua_istable(L, argNum))
{
lua_pushnil(L); /* first key */
while (lua_next(L, argNum) != 0)
{
/* uses 'key' (at index -2) and 'value' (at index -1) */
mapTable[luaL_checkstring(L, -2)] = luaL_checkstring(L, -1);
/* removes 'value'; keeps 'key' for next iteration */
lua_pop(L, 1);
}
}
if(mapTable.size())
{
std::string naviName = "unnamedNaviData";
const char *pDataName = mapTable["naviDataName"].c_str();
if(pDataName)
naviName = pDataName;
NaviLibrary::NaviData naviData(naviName);
std::map<std::string, std::string>::iterator it = mapTable.begin();
while(it != mapTable.end())
{
naviData[(*it).first] = (*it).second;
++it;
}
pNavi->navigateTo(pUrl, naviData);
}
else
{
pNavi->navigateTo(pUrl);
}
return 0;
}
LuaGlue(_setNaviOpacity)
{
int argNum = 1;
const char *pName = luaL_checkstring(L, argNum++);
float opacity = (float) luaL_optnumber(L, argNum++, 1.0);
Navi *pNavi = NaviManager::Get().getNavi(pName);
pNavi->setOpacity(opacity);
return 0;
}
LuaGlue(_setNaviIgnoreTransparent)
{
int argNum = 1;
const char *pName = luaL_checkstring(L, argNum++);
Navi *pNavi = NaviManager::Get().getNavi(pName);
bool ignoreTrans = true;
if(lua_type(L, argNum) == LUA_TBOOLEAN)
{
ignoreTrans = lua_toboolean(L, argNum) != 0;
}
argNum++;
float defineThreshold = (float) luaL_optnumber(L, argNum++, 0.05);
pNavi->setIgnoreTransparent(ignoreTrans, defineThreshold);
return 0;
}
LuaGlue(_setNaviIgnoreBounds)
{
int argNum = 1;
const char *pName = luaL_checkstring(L, argNum++);
bool ignore = true;
if(lua_type(L, argNum) == LUA_TBOOLEAN)
{
ignore = lua_toboolean(L, argNum) != 0;
}
argNum++;
Navi *pNavi = NaviManager::Get().getNavi(pName);
pNavi->setIgnoreBounds(ignore);
return 0;
}
LuaGlue(_setForceMaxUpdate)
{
int argNum = 1;
const char *pName = luaL_checkstring(L, argNum++);
bool bOn = lua_toboolean(L, argNum++) != 0;
Navi *pNavi = NaviManager::Get().getNavi(pName);
pNavi->setForceMaxUpdate(bOn);
return 0;
}
LuaGlue(_setMaxUpdatesPerSec)
{
#if 1
int argNum = 1;
const char *pName = luaL_checkstring(L, argNum++);
unsigned int iRate = (unsigned int) luaL_checkint(L, argNum++);
Navi *pNavi = NaviManager::Get().getNavi(pName);
pNavi->setMaxUPS(iRate);
#else
assert(false);
#endif
return 0;
}
/////////////////////////////////////////////////////////////
LuaGlue(_naviEvaluateJS)
{
int argNum = 1;
std::string naviName = luaL_checkstring(L, argNum++);
std::string script = luaL_checkstring(L, argNum++);
Navi *pNavi = NaviManager::Get().getNavi(naviName);
std::string r = pNavi->evaluateJS(script);
lua_pushstring(L, r.c_str());
return 1;
}
LuaGlue(_createNaviMaterial)
{
int argNum = 1;
std::string naviName = luaL_checkstring(L, argNum++);
std::string homepage = luaL_checkstring(L, argNum++);
unsigned short w = (unsigned short) luaL_checkint(L, argNum++);
unsigned short h = (unsigned short) luaL_checkint(L, argNum++);
Ogre::FilterOptions texFiltering = Ogre::FO_ANISOTROPIC;
Navi *pNavi = NaviLibrary::NaviManager::Get().createNaviMaterial(naviName, homepage, w, h, texFiltering);
lua_pushstring(L, pNavi->getName().c_str());
return 1;
}
LuaGlue(_canNavigateBack)
{
int argNum = 1;
std::string naviName = luaL_checkstring(L, argNum++);
Navi *pNavi = NaviManager::Get().getNavi(naviName);
lua_pushboolean(L, pNavi->canNavigateBack());
return 1;
}
LuaGlue(_navigateNaviBack)
{
int argNum = 1;
std::string naviName = luaL_checkstring(L, argNum++);
Navi *pNavi = NaviManager::Get().getNavi(naviName);
pNavi->navigateBack();
return 0;
}
LuaGlue(_canNavigateForward)
{
int argNum = 1;
std::string naviName = luaL_checkstring(L, argNum++);
Navi *pNavi = NaviManager::Get().getNavi(naviName);
lua_pushboolean(L, pNavi->canNavigateForward());
return 1;
}
LuaGlue(_navigateNaviForward)
{
int argNum = 1;
std::string naviName = luaL_checkstring(L, argNum++);
Navi *pNavi = NaviManager::Get().getNavi(naviName);
pNavi->navigateForward();
return 0;
}
LuaGlue(_navigateNaviStop)
{
int argNum = 1;
std::string naviName = luaL_checkstring(L, argNum++);
Navi *pNavi = NaviManager::Get().getNavi(naviName);
pNavi->navigateStop();
return 0;
}
LuaGlue(_setNaviBackgroundColor)
{
#if 0
int argNum = 1;
std::string naviName = luaL_checkstring(L, argNum++);
float r = (float) luaL_optnumber(L, argNum++, 1.0);
float g = (float) luaL_optnumber(L, argNum++, 1.0);
float b = (float) luaL_optnumber(L, argNum++, 1.0);
Navi *pNavi = NaviManager::Get().getNavi(naviName);
pNavi->setBackgroundColor(r, g, b);
#else
assert(false);
#endif
return 0;
}
LuaGlue(_isAnyNaviFocused)
{
lua_pushboolean(L, NaviLibrary::NaviManager::Get().isAnyNaviFocused());
return 1;
}
LuaGlue(_getFocusedNaviName)
{
lua_pushstring(L, NaviLibrary::NaviManager::Get().getFocusedNavi()->getName().c_str());
return 1;
}
LuaGlue(_getNaviMaterialName)
{
int argNum = 1;
std::string naviName = luaL_checkstring(L, argNum++);
Navi *pNavi = NaviManager::Get().getNavi(naviName);
lua_pushstring(L, pNavi->getMaterialName().c_str());
return 1;
}
LuaGlue(_getNaviVisibility)
{
int argNum = 1;
std::string naviName = luaL_checkstring(L, argNum++);
Navi *pNavi = NaviManager::Get().getNavi(naviName);
lua_pushboolean(L, pNavi->getVisibility());
return 1;
}
LuaGlue(_deFocusAllNavis)
{
NaviLibrary::NaviManager::Get().deFocusAllNavis();
return 0;
}
LuaGlue(_showNavi)
{
int argNum = 1;
const char *naviName = luaL_checkstring(L, argNum++);
if(naviName)
{
Navi *pNavi = NaviManager::Get().getNavi(naviName);
pNavi->show();
}
return 0;
}
LuaGlue(_hideNavi)
{
int argNum = 1;
const char *naviName = luaL_checkstring(L, argNum++);
if(naviName)
{
Navi *pNavi = NaviManager::Get().getNavi(naviName);
pNavi->hide();
}
return 0;
}
LuaGlue(_htmlToDataURI)
{
const char *html = luaL_checkstring(L, 1);
lua_pushstring(L, NaviUtilities::htmlToDataURI(html).c_str());
return 1;
}
extern "C" {
typedef struct
{
const char *name;
int (*func)(lua_State *);
}luaDef;
};
luaDef NaviGlue[] =
{
{"createNavi", _createNavi},
{"destroyNavi", _destroyNavi},
{"setNaviMask", _setNaviMask},
{"addNaviEventListener", _addNaviEventListener},
{"setNaviColorKey", _setNaviColorKey},
{"navigateNaviTo", _navigateNaviTo},
{"setNaviOpacity", _setNaviOpacity},
{"setForceMaxUpdate", _setForceMaxUpdate},
{"setMaxUpdatesPerSec", _setMaxUpdatesPerSec},
{"naviEvaluateJS", _naviEvaluateJS},
{"createNaviMaterial", _createNaviMaterial},
{"canNavigateBack", _canNavigateBack},
{"navigateNaviBack", _navigateNaviBack},
{"canNavigateForward", _canNavigateForward},
{"navigateNaviForward", _navigateNaviForward},
{"navigateNaviStop", _navigateNaviStop},
{"setNaviBackgroundColor", _setNaviBackgroundColor},
{"setNaviIgnoreTransparent", _setNaviIgnoreTransparent},
{"setNaviIgnoreBounds", _setNaviIgnoreBounds},
{"isAnyNaviFocused", _isAnyNaviFocused},
{"getFocusedNaviName", _getFocusedNaviName},
{"getNaviMaterialName", _getNaviMaterialName},
{"getNaviVisibility", _getNaviVisibility},
{"deFocusAllNavis", _deFocusAllNavis},
{"showNavi", _showNavi},
{"hideNavi", _hideNavi},
{"htmlToDataURI", _htmlToDataURI},
{NULL, NULL},
};
/*
** List of unimplemented NaviManager methods:
**
** getNaviInternalPanel - Doesn't make sense to do, returns an Orge internal that I don't implement in Lua, if you do, then feel free
**
** Mouse events are handled in the c++ code in my world, so no need to expose then to Lua
** injectMouseMove
** injectNaviMaterialMouseMove
** injectMouseWheel
** injectNaviMaterialMouseWheel
** injectMouseDown
** injectMouseUp
** injectNaviMaterialMouseDown
** injectNaviMaterialMouseUp
*/
static lua_State *g_pLua = NULL;
void initNaviLua(lua_State *pLua)
{
if(pLua == NULL)
{
pLua = lua_open();
luaL_openlibs(pLua);
}
g_pLua = pLua;
for(int i=0; NaviGlue[i].name; i++)
{
lua_register(pLua, NaviGlue[i].name, NaviGlue[i].func);
}
}
bool RunLuaScript(const char *pFilename)
{
if (0 != luaL_loadfile(g_pLua, pFilename))
{
#if 0
if(m_pErrorHandler)
{
char buf[256];
sprintf(buf, "Lua Error - Script Load\nScript Name:%s\nError Message:%s\n", pFilename, luaL_checkstring(m_pScriptContext, -1));
m_pErrorHandler(buf);
}
#endif
return false;
}
if (0 != lua_pcall(g_pLua, 0, LUA_MULTRET, 0))
{
#if 0
if(m_pErrorHandler)
{
char buf[256];
sprintf(buf, "Lua Error - Script Run\nScript Name:%s\nError Message:%s\n", pFilename, luaL_checkstring(m_pScriptContext, -1));
m_pErrorHandler(buf);
}
#endif
return false;
}
return true;
}

