Navi Lua

From NaviWiki

Jump to: navigation, search

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;
}
Personal tools