3122 lines
84 KiB
C++
3122 lines
84 KiB
C++
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
#include "stdpch.h"
|
|
#include <map>
|
|
#include "nel/misc/rgba.h"
|
|
#include "nel/gui/interface_parser.h"
|
|
#include "nel/misc/i_xml.h"
|
|
#include "nel/misc/file.h"
|
|
#include "nel/misc/algo.h"
|
|
#include "nel/misc/mem_stream.h"
|
|
#include "nel/misc/factory.h"
|
|
#include "nel/misc/big_file.h"
|
|
#include "nel/misc/xml_auto_ptr.h"
|
|
#include "nel/gui/interface_options.h"
|
|
#include "nel/gui/interface_anim.h"
|
|
#include "nel/gui/interface_expr.h"
|
|
#include "nel/gui/view_pointer.h"
|
|
#include "nel/gui/group_modal.h"
|
|
#include "nel/gui/group_list.h"
|
|
#include "nel/gui/group_container.h"
|
|
#include "nel/gui/interface_link.h"
|
|
#include "nel/gui/lua_helper.h"
|
|
#include "nel/gui/lua_ihm.h"
|
|
#include "nel/gui/lua_manager.h"
|
|
#include "nel/gui/root_group.h"
|
|
|
|
#ifdef LUA_NEVRAX_VERSION
|
|
#include "lua_ide_dll_nevrax/include/lua_ide_dll/ide_interface.h" // external debugger
|
|
#endif
|
|
const uint32 UI_CACHE_SERIAL_CHECK = NELID("IUG_");
|
|
|
|
using namespace NLMISC;
|
|
using namespace std;
|
|
|
|
namespace NLGUI
|
|
{
|
|
|
|
void saveXMLTree(COFile &f, xmlNodePtr node)
|
|
{
|
|
// save node name
|
|
std::string name = (const char *) node->name;
|
|
f.serial(name);
|
|
// save properties
|
|
uint32 numProp = 0;
|
|
xmlAttrPtr currProp = node->properties;
|
|
while (currProp)
|
|
{
|
|
++ numProp;
|
|
currProp = currProp->next;
|
|
}
|
|
f.serial(numProp);
|
|
currProp = node->properties;
|
|
while (currProp)
|
|
{
|
|
std::string name = (const char *) currProp->name;
|
|
f.serial(name);
|
|
CXMLAutoPtr ptr(xmlGetProp(node, currProp->name));
|
|
std::string value = (const char *) ptr;
|
|
f.serial(value);
|
|
currProp = currProp->next;
|
|
}
|
|
uint32 numChildren = 0;
|
|
xmlNodePtr currChild = node->children;
|
|
while (currChild)
|
|
{
|
|
++ numChildren;
|
|
currChild = currChild->next;
|
|
}
|
|
f.serial(numChildren);
|
|
currChild = node->children;
|
|
while (currChild)
|
|
{
|
|
saveXMLTree(f, currChild);
|
|
currChild = currChild->next;
|
|
}
|
|
}
|
|
|
|
xmlNodePtr buildTree(CIFile &f)
|
|
{
|
|
// load node name
|
|
std::string name;
|
|
f.serial(name);
|
|
xmlNodePtr node = xmlNewNode(NULL, (const xmlChar *) name.c_str());
|
|
// slod properties
|
|
uint32 numProp;
|
|
f.serial(numProp);
|
|
for(uint k = 0; k < numProp; ++k)
|
|
{
|
|
std::string name, value;
|
|
f.serial(name, value);
|
|
xmlSetProp(node, (const xmlChar *) name.c_str(), (const xmlChar *) value.c_str());
|
|
}
|
|
uint32 numChildren;
|
|
f.serial(numChildren);
|
|
for(uint k = 0; k < numChildren; ++k)
|
|
{
|
|
xmlAddChild(node, buildTree(f));
|
|
}
|
|
return node;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// CInterfaceParser
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// ----------------------------------------------------------------------------
|
|
CInterfaceParser::CInterfaceParser()
|
|
{
|
|
luaInitialized = false;
|
|
cacheUIParsing = false;
|
|
linkId = 0;
|
|
editorMode = false;
|
|
setupCallback = NULL;
|
|
}
|
|
|
|
CInterfaceParser::~CInterfaceParser()
|
|
{
|
|
_ParentPositionsMap.clear();
|
|
_ParentSizesMap.clear();
|
|
_ParentSizesMaxMap.clear();
|
|
_LuaClassAssociation.clear();
|
|
_Templates.clear();
|
|
removeAllModules();
|
|
setupCallback = NULL;
|
|
}
|
|
/** Convert a string into a memstream
|
|
*/
|
|
static void interfaceScriptAsMemStream(const std::string &script, CMemStream &destStream)
|
|
{
|
|
NLMISC::contReset(destStream);
|
|
if (destStream.isReading()) // we must be sure that we are reading the stream
|
|
{
|
|
destStream.invert();
|
|
}
|
|
destStream.seek(0, NLMISC::IStream::begin);
|
|
if (script.empty()) return;
|
|
destStream.serialBuffer(const_cast<uint8 *>((const uint8 *) &script[0]), (uint)script.size());
|
|
destStream.invert();
|
|
destStream.seek(0, NLMISC::IStream::begin);
|
|
}
|
|
|
|
std::string CInterfaceParser::lookup( const std::string &file )
|
|
{
|
|
std::string filename;
|
|
|
|
if( editorMode && !_WorkDir.empty() )
|
|
{
|
|
std::string wdpath = CPath::standardizePath( _WorkDir ) + file;
|
|
if( CFile::fileExists( wdpath ) )
|
|
filename = wdpath;
|
|
}
|
|
if( filename.empty() )
|
|
filename = CPath::lookup( file );
|
|
|
|
return filename;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseInterface (const std::vector<std::string> & strings, bool reload, bool isFilename, bool checkInData)
|
|
{
|
|
bool ok;
|
|
|
|
bool needCheck = false;
|
|
|
|
#if !FINAL_VERSION
|
|
needCheck = false;
|
|
#endif
|
|
|
|
// TestYoyo. UnHide For Parsing Profile
|
|
/*
|
|
NLMISC::CHTimer::startBench();
|
|
{
|
|
|
|
H_AUTO(parseInterface);
|
|
*/
|
|
|
|
//ignore the content of tags containing only white space
|
|
xmlKeepBlanksDefault(0);
|
|
//parse all interface files and build a single xml document
|
|
xmlNodePtr globalEnclosing;
|
|
nlassert (strings.size());
|
|
CIXml read;
|
|
string nextFileName;
|
|
static const char *SCRIPT_AS_STRING = "<script as string>";
|
|
try
|
|
{
|
|
CIFile file;
|
|
CMemStream scriptStream;
|
|
string firstFileName;
|
|
vector<string>::const_iterator it = strings.begin();
|
|
if (isFilename)
|
|
{
|
|
//get the first file document pointer
|
|
firstFileName = *it;
|
|
string filename = lookup( firstFileName );
|
|
bool isInData = false;
|
|
string::size_type pos = filename.find ("@");
|
|
if (pos != string::npos)
|
|
{
|
|
vector<string> bigFilePaths;
|
|
CBigFile::getInstance().getBigFilePaths(bigFilePaths);
|
|
if (CBigFile::getInstance().getBigFileName(filename.substr(0, pos)) != "data/"+filename.substr(0, pos))
|
|
isInData = false;
|
|
else
|
|
isInData = true;
|
|
}
|
|
|
|
if ((needCheck && !isInData) || !file.open (lookup(firstFileName)))
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not open file %s, skipping xml parsing",firstFileName.c_str());
|
|
return false;
|
|
}
|
|
read.init (file);
|
|
}
|
|
else
|
|
{
|
|
firstFileName = SCRIPT_AS_STRING; // for error msg
|
|
interfaceScriptAsMemStream(*it, scriptStream);
|
|
read.init(scriptStream);
|
|
}
|
|
//get the enclosing element (<interface config>)
|
|
globalEnclosing = read.getRootNode();
|
|
if (!globalEnclosing)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("no root element in xml file %s, skipping xml parsing",firstFileName.c_str());
|
|
return false;
|
|
}
|
|
if (strcmp( (char*)globalEnclosing->name,"interface_config") )
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("wrong root element in xml file %s, skipping xml parsing",firstFileName.c_str());
|
|
return false;
|
|
}
|
|
if (isFilename)
|
|
{
|
|
file.close();
|
|
}
|
|
|
|
// Get all other xml files, and add their nodes to the first xml document
|
|
it++;
|
|
uint32 i = 0;
|
|
for (; it != strings.end(); it++)
|
|
{
|
|
//nlwarning("Parsing interface file : %s", it->c_str());
|
|
nextFileName = *it;
|
|
CIXml nextRead;
|
|
xmlNodePtr cur = NULL;
|
|
bool saveParseResult = false;
|
|
bool readFromUncompressedXML = true;
|
|
if( isFilename && cacheUIParsing )
|
|
{
|
|
saveParseResult = true;
|
|
std::string archive = CPath::lookup(nextFileName + "_compressed", false, false);
|
|
std::string current = lookup(nextFileName);
|
|
if (!archive.empty() && !current.empty())
|
|
{
|
|
if (CFile::getFileModificationDate(current) <= CFile::getFileModificationDate(archive))
|
|
{
|
|
CIFile input;
|
|
input.open(archive);
|
|
input.serialCheck(UI_CACHE_SERIAL_CHECK);
|
|
input.serialVersion(0);
|
|
cur = buildTree(input);
|
|
input.serialCheck(UI_CACHE_SERIAL_CHECK);
|
|
readFromUncompressedXML = false;
|
|
saveParseResult = false;
|
|
}
|
|
}
|
|
}
|
|
if (!cur)
|
|
{
|
|
if (isFilename)
|
|
{
|
|
if (!file.open(lookup(nextFileName)))
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not open file %s, skipping xml parsing",nextFileName.c_str());
|
|
return false;
|
|
}
|
|
nextRead.init (file);
|
|
}
|
|
else
|
|
{
|
|
interfaceScriptAsMemStream(nextFileName, scriptStream);
|
|
nextFileName = SCRIPT_AS_STRING; // for error MSG
|
|
read.init(scriptStream);
|
|
}
|
|
cur = nextRead.getRootNode();
|
|
if (!cur)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("no root element in xml file %s, skipping xml parsing", it->c_str() );
|
|
return false;
|
|
}
|
|
}
|
|
if (saveParseResult)
|
|
{
|
|
nlassert(isFilename);
|
|
std::string outputFilename = CPath::standardizePath("data") + CFile::getFilename(nextFileName) + std::string("_compressed");
|
|
COFile f;
|
|
f.open(outputFilename);
|
|
f.serialCheck(UI_CACHE_SERIAL_CHECK);
|
|
f.serialVersion(0);
|
|
saveXMLTree(f, cur);
|
|
f.serialCheck(UI_CACHE_SERIAL_CHECK);
|
|
}
|
|
if (strcmp( (char*)cur->name,"interface_config") )
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("wrong root element in xml file %s. should be interface config, skipping xml parsing", nextFileName.c_str());
|
|
return false;
|
|
}
|
|
xmlNodePtr curSon = cur->children;
|
|
while (curSon)
|
|
{
|
|
xmlNodePtr bufNode = xmlCopyNode (curSon, 1);
|
|
xmlAddChild (globalEnclosing,bufNode);
|
|
curSon = curSon->next;
|
|
}
|
|
if (!readFromUncompressedXML)
|
|
{
|
|
freeXMLNodeAndSibblings(cur);
|
|
}
|
|
if (isFilename)
|
|
{
|
|
file.close();
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
// Output error
|
|
// todo hulud interface syntax error
|
|
nlwarning ("CInterfaceParser: Error while loading the xml interface file %s, skipping xml parsing : %s", nextFileName.c_str(), e.what());
|
|
if (testWildCard(nextFileName, "save/keys_?*.xml"))
|
|
{
|
|
// if file matches 'save/keys_?*.xml', move this file as a backup
|
|
string backup = nextFileName+".backup";
|
|
if (CFile::fileExists(backup))
|
|
CFile::deleteFile(backup);
|
|
CFile::moveFile(backup.c_str(), nextFileName.c_str());
|
|
}
|
|
return false;
|
|
}
|
|
//parse the built doc
|
|
ok = parseXMLDocument(globalEnclosing, reload);
|
|
// freeXMLNodeAndSibblings(globalEnclosing); // Done by the ~CIXml
|
|
|
|
|
|
// TestYoyo. UnHide for Parsing Profile
|
|
/*
|
|
}
|
|
NLMISC::CHTimer::endBench();
|
|
// Display and save profile to a File.
|
|
CLog log;
|
|
CFileDisplayer fileDisplayer(NLMISC::CFile::findNewFile(getLogDirectory() + "profile_parseInterface.log"));
|
|
log.addDisplayer(&fileDisplayer);
|
|
// diplay
|
|
NLMISC::CHTimer::displayHierarchicalByExecutionPathSorted(&log, CHTimer::TotalTime, true, 48, 2);
|
|
NLMISC::CHTimer::display(&log, CHTimer::TotalTime);
|
|
*/
|
|
|
|
if( ok )
|
|
{
|
|
if( CWidgetManager::getInstance()->getPointer() == NULL )
|
|
{
|
|
CViewPointer *pointer = dynamic_cast< CViewPointer* >( NLMISC_GET_FACTORY(CViewBase, std::string).createObject( "generic_pointer", CViewBase::TCtorParam() ) );
|
|
CWidgetManager::getInstance()->setPointer( pointer );
|
|
}
|
|
}
|
|
|
|
|
|
return ok;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseXMLDocument(xmlNodePtr root, bool reload)
|
|
{
|
|
|
|
CWidgetManager::SMasterGroup *curRoot = NULL;
|
|
CInterfaceGroup *rootGroup = NULL;
|
|
//parse templates
|
|
xmlNodePtr curNode = root->children;
|
|
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
|
|
while (curNode)
|
|
{
|
|
// first solve define for the xml node and his sons
|
|
if(!solveDefine(curNode))
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not read all define");
|
|
}
|
|
// then try to solve Style for the xml node and his sons
|
|
else if (!solveStyle(curNode))
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not read all styles");
|
|
}
|
|
if( !strcmp((char*)curNode->name,"key" ) && editorMode )
|
|
{
|
|
saveKeySettings( curNode );
|
|
}
|
|
// If define and style oks, try to parse "1st pass" objets (define, options....).
|
|
else if ( !strcmp((char*)curNode->name,"template") )
|
|
{
|
|
// Check there is a valid name for this template
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp( curNode, (xmlChar*)"name" ));
|
|
if (ptr)
|
|
{
|
|
// remove any template with the same name in the list (useful when using 'loadui' command)
|
|
for(uint k = 0; k < _Templates.size(); ++k)
|
|
{
|
|
CXMLAutoPtr otherTemplName((const char*) xmlGetProp( _Templates[k], (xmlChar*)"name" ));
|
|
if (strcmp((const char *) otherTemplName, (const char *) ptr) == 0)
|
|
{
|
|
nlwarning("Replacing template %s with new version", (const char *) ptr);
|
|
xmlFreeNode(_Templates[k]);
|
|
_Templates[k] = NULL;
|
|
}
|
|
}
|
|
_Templates.erase(std::remove(_Templates.begin(), _Templates.end(), (xmlNodePtr) NULL), _Templates.end());
|
|
_Templates.push_back(curNode);
|
|
}
|
|
else
|
|
// todo hulud interface syntax error
|
|
nlwarning ("no name in a template node");
|
|
}
|
|
else if ( !strcmp((char*)curNode->name,"options") )
|
|
{
|
|
if (!parseOptions(curNode,rootGroup))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse options");
|
|
}
|
|
else if ( !strcmp((char*)curNode->name,"define") )
|
|
{
|
|
if (!parseDefine(curNode))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse define");
|
|
}
|
|
else if ( !strcmp((char*)curNode->name,"style") )
|
|
{
|
|
if (!parseStyle(curNode))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse 'style'");
|
|
}
|
|
else
|
|
{
|
|
IParserModule *module = getModuleFor( (char*)( curNode->name ) );
|
|
if( module != NULL ){
|
|
if( module->canParseInStage( IParserModule::Unresolved ) )
|
|
module->parse( curNode, rootGroup );
|
|
}
|
|
}
|
|
|
|
curNode = curNode->next;
|
|
}
|
|
|
|
|
|
if (!reload) // TMP : crahs when doing the setup twice (old pointer on the text manager ...)
|
|
{
|
|
setupOptions();
|
|
}
|
|
|
|
|
|
//parse filters , groups and eventually instances
|
|
// vector that are on top of the xml hierarchy
|
|
root = root->children;
|
|
while (root)
|
|
{
|
|
if ( !strcmp((char*)root->name,"root") )
|
|
{
|
|
CXMLAutoPtr ptr((const char*)xmlGetProp (root, (xmlChar*)"id"));
|
|
if (ptr)
|
|
{
|
|
rootGroup = CWidgetManager::getInstance()->getMasterGroupFromId (string("ui:") + (const char*)ptr);
|
|
if (rootGroup == NULL)
|
|
{
|
|
rootGroup = (CInterfaceGroup*)(new CRootGroup(CViewBase::TCtorParam()));
|
|
rootGroup->parse (root, NULL);
|
|
CWidgetManager::SMasterGroup mg;
|
|
mg.Group = rootGroup;
|
|
_MasterGroups.push_back (mg);
|
|
}
|
|
for (uint32 i = 0; i < _MasterGroups.size(); ++i)
|
|
if (_MasterGroups[i].Group == rootGroup)
|
|
curRoot = &_MasterGroups[i];
|
|
}
|
|
else
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse root");
|
|
}
|
|
}
|
|
else if (!strcmp((char*)root->name,"group"))
|
|
{
|
|
if (!parseGroup(root,rootGroup, reload))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse group");
|
|
}
|
|
else if (!strcmp((char*)root->name,"instance"))
|
|
{
|
|
if (!parseInstance(root))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse instance");
|
|
}
|
|
else if (!strcmp((char*)root->name,"view"))
|
|
{
|
|
if (!parseView(root,rootGroup, reload))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse view");
|
|
}
|
|
else if (!strcmp((char*)root->name,"ctrl"))
|
|
{
|
|
if (!parseControl(root,rootGroup, reload))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse control");
|
|
}
|
|
else if ( !strcmp((char*)root->name,"vector") )
|
|
{
|
|
if (!parseVector(root))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse vector");
|
|
}
|
|
else if ( !strcmp((char*)root->name,"link") )
|
|
{
|
|
if (!parseLink(root,rootGroup))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse link");
|
|
}
|
|
else if ( !strcmp((char*)root->name,"variable") )
|
|
{
|
|
if (!parseVariable(root,rootGroup))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse variable");
|
|
}
|
|
else if ( !strcmp((char*)root->name,"tree") )
|
|
{
|
|
if (!parseTree(root,curRoot))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse tree");
|
|
/* if (!setupTree(root,curRoot))
|
|
nlwarning ("could not setup tree"); */
|
|
}
|
|
else if ( !strcmp((char*)root->name,"proc") )
|
|
{
|
|
if (!parseProcedure(root, reload))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse procedure");
|
|
}
|
|
else if ( !strcmp((char*)root->name,"sheet_selection") )
|
|
{
|
|
if (!parseSheetSelection(root))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse sheet selection");
|
|
}
|
|
else if ( !strcmp((char*)root->name,"anim") )
|
|
{
|
|
if (!parseAnim(root,rootGroup))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse 'anim'");
|
|
}
|
|
else if ( !strcmp((char*)root->name,"lua") )
|
|
{
|
|
if(!parseLUAScript(root))
|
|
{
|
|
nlerror ("could not parse 'lua'");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IParserModule *module = getModuleFor( (char*)( root->name ) );
|
|
if( module != NULL )
|
|
{
|
|
if( module->canParseInStage( IParserModule::Resolved ) )
|
|
module->parse( root, rootGroup );
|
|
}
|
|
}
|
|
|
|
root = root->next;
|
|
}
|
|
|
|
// add all modals group to the window list
|
|
for (uint32 i = 0; i < _MasterGroups.size(); ++i)
|
|
{
|
|
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[i];
|
|
// insert all modals
|
|
for (uint32 j = 0; j < rMG.Group->getGroups().size(); ++j)
|
|
{
|
|
CGroupModal *pIG = dynamic_cast<CGroupModal*>(rMG.Group->getGroups()[j]);
|
|
// if it is a modal group
|
|
if(pIG)
|
|
{
|
|
// add to the window list
|
|
CWidgetManager::getInstance()->addWindowToMasterGroup(rMG.Group->getId(), pIG);
|
|
}
|
|
}
|
|
}
|
|
|
|
// init all the elements coords, and Lua Script
|
|
if (!initCoordsAndLuaScript())
|
|
return false;
|
|
|
|
std::vector<xmlNodePtr> keptTemplates;
|
|
|
|
// keep template that have the "keep" flag if we are not reloading
|
|
// if reloading, always keep the template
|
|
{
|
|
CXMLAutoPtr ptr;
|
|
for(uint k = 0; k < _Templates.size(); ++k)
|
|
{
|
|
CXMLAutoPtr ptr(xmlGetProp(_Templates[k], (const xmlChar *) "keep"));
|
|
if (reload || (ptr && nlstricmp((const char *) ptr, "true") == 0))
|
|
{
|
|
// xmlUnsetProp(_Templates[k], (const xmlChar *) "keep");
|
|
xmlNodePtr copy = xmlCopyNode(_Templates[k], 1);
|
|
if (copy)
|
|
keptTemplates.push_back(copy);
|
|
}
|
|
|
|
// free the original node, whether we kept a copy or not
|
|
xmlUnlinkNode( _Templates[k] );
|
|
xmlFreeNode( _Templates[k] );
|
|
_Templates[k] = NULL;
|
|
}
|
|
// keep new list
|
|
_Templates.swap(keptTemplates);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseTemplateNode(xmlNodePtr node,xmlNodePtr instance,xmlNodePtr templ)
|
|
{
|
|
CXMLAutoPtr ptr;
|
|
//get the node properties
|
|
xmlAttrPtr props = node->properties;
|
|
while (props)
|
|
{
|
|
//get the property value
|
|
ptr = (char*)xmlGetProp( node, props->name);
|
|
nlassert(ptr);
|
|
//if it begins with a #, it is a reference in the instance attribute
|
|
if (strchr(ptr, '#') != NULL)
|
|
{
|
|
string LastProp = ptr;
|
|
string NewProp ="";
|
|
string RepProp;
|
|
|
|
while (LastProp.size() > 0)
|
|
{
|
|
string::size_type diesPos = LastProp.find("#");
|
|
if (diesPos != string::npos)
|
|
{
|
|
if (diesPos > 0)
|
|
{
|
|
NewProp += LastProp.substr(0, LastProp.find("#"));
|
|
LastProp = LastProp.substr(LastProp.find("#"),LastProp.size());
|
|
}
|
|
|
|
CXMLAutoPtr instanceProp;
|
|
for (uint32 i = 0; i < LastProp.size(); ++i)
|
|
{
|
|
RepProp = LastProp.substr(0, LastProp.size()-i);
|
|
instanceProp = xmlGetProp (instance , (const xmlChar*)(RepProp.c_str() + 1));
|
|
if (instanceProp)
|
|
break;
|
|
instanceProp = xmlGetProp (templ , (const xmlChar*)(RepProp.c_str() + 1));
|
|
if (instanceProp)
|
|
break;
|
|
}
|
|
if (!instanceProp)
|
|
{
|
|
CXMLAutoPtr ptr2((const char*)xmlGetProp( instance, (xmlChar*)"id"));
|
|
string sTmp;
|
|
if (ptr2.getDatas() != NULL)
|
|
sTmp = string("cannot parse template node property: ") + ((const char *) ptr + 1) + string(" in instance : ") + string((const char*)ptr2);
|
|
else
|
|
sTmp = string("cannot parse template node property: ") + ((const char *) ptr + 1) + string(" in instance : NULL");
|
|
// todo hulud interface syntax error
|
|
nlinfo(sTmp.c_str());
|
|
|
|
return false;
|
|
}
|
|
NewProp += string((const char*)instanceProp);
|
|
LastProp = LastProp.substr (RepProp.size(), LastProp.size());
|
|
}
|
|
else
|
|
{
|
|
NewProp += LastProp;
|
|
LastProp = "";
|
|
}
|
|
}
|
|
xmlSetProp(node,props->name, (const xmlChar*)NewProp.c_str());
|
|
}
|
|
props = props->next;
|
|
}
|
|
//parse the node children
|
|
node = node->children;
|
|
while (node)
|
|
{
|
|
if (!parseTemplateNode(node,instance,templ))
|
|
return false;
|
|
node = node->next;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseInstance(xmlNodePtr cur)
|
|
{
|
|
CXMLAutoPtr ptr;
|
|
|
|
//try to find the instance template in our template vector. If the template doesn't exist, return false
|
|
CXMLAutoPtr templ((const char*) xmlGetProp( cur, (xmlChar*)"template" ));
|
|
if (!templ)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo("parse error : no referenced template in an instance");
|
|
return false;
|
|
}
|
|
vector<xmlNodePtr>::const_iterator it;
|
|
for (it = _Templates.begin(); it != _Templates.end();it++)
|
|
{
|
|
ptr = (char*) xmlGetProp( *it, (xmlChar*)"name" );
|
|
if (!ptr)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo("no name in a template node");
|
|
return false;
|
|
}
|
|
if ( !strcmp(templ,ptr) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if ( it == _Templates.end() )
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo("the template %s was not found", (const char*)templ);
|
|
return false;
|
|
}
|
|
|
|
xmlNodePtr templNode = *it;
|
|
//for each child of the template, create the appropriate node
|
|
xmlNodePtr child = (*it)->children;
|
|
xmlNodePtr nextSibling=cur;
|
|
while (child)
|
|
{
|
|
//copy the template child node
|
|
xmlNodePtr node = xmlCopyNode (child, 1);
|
|
|
|
//add it to our tree
|
|
//node = xmlAddChild(cur->parent,node);
|
|
node = xmlAddNextSibling (nextSibling, node);
|
|
nextSibling = nextSibling->next;
|
|
|
|
//parse the child
|
|
if (!parseTemplateNode(node, cur, templNode))
|
|
return false;
|
|
child = child->next;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseVector(xmlNodePtr cur)
|
|
{
|
|
//get the number of elements
|
|
CXMLAutoPtr cSize((const char*) xmlGetProp( cur, (xmlChar*)"_size" ));
|
|
if (!cSize)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo("no _size in a vector");
|
|
return false;
|
|
}
|
|
sint32 size;
|
|
fromString(cSize, size);
|
|
if (size <= 0)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo("size<0");
|
|
return false;
|
|
}
|
|
|
|
// Vector of groups
|
|
bool bGroupVector = true;
|
|
|
|
//get the first position reference
|
|
CXMLAutoPtr firstpos((const char*) xmlGetProp( cur, (xmlChar*)"_firstpos" ));
|
|
if (!firstpos)
|
|
{
|
|
bGroupVector = false;
|
|
}
|
|
//get the next position reference
|
|
CXMLAutoPtr nextpos((const char*) xmlGetProp( cur, (xmlChar*)"_nextpos" ));
|
|
if (!nextpos)
|
|
{
|
|
bGroupVector = false;
|
|
}
|
|
|
|
sint32 index = 0;
|
|
//get the first index value
|
|
CXMLAutoPtr indexChar((const char*) xmlGetProp( cur, (xmlChar*)"_firstindex" ));
|
|
if (indexChar)
|
|
{
|
|
fromString((const char*)indexChar, index);
|
|
}
|
|
|
|
sint32 step = 1;
|
|
//get the step for the indices
|
|
CXMLAutoPtr stepChar((const char*) xmlGetProp( cur, (xmlChar*)"_step" ));
|
|
if (stepChar)
|
|
{
|
|
fromString((const char*)stepChar, step);
|
|
}
|
|
|
|
|
|
//get the x and y of the first element
|
|
CXMLAutoPtr xfirst((const char*) xmlGetProp( cur, (xmlChar*)"_xfirst" ));
|
|
CXMLAutoPtr yfirst((const char*) xmlGetProp( cur, (xmlChar*)"_yfirst" ));
|
|
|
|
xmlNodePtr node;
|
|
CXMLAutoPtr id;
|
|
xmlNodePtr nextSibling= cur;
|
|
//now we can add all the following elements
|
|
sint32 i;
|
|
for (i = index;; i += step)
|
|
{
|
|
if (step > 0)
|
|
{
|
|
if (i >= index + size) break;
|
|
}
|
|
else
|
|
{
|
|
if (i <= index - size) break;
|
|
}
|
|
//copy the node
|
|
node = xmlCopyNode(cur,1);
|
|
//set the name and posref
|
|
|
|
if (bGroupVector)
|
|
{
|
|
if (i==index)
|
|
{
|
|
xmlSetProp(node,(xmlChar*)"posref",(const xmlChar*)firstpos);
|
|
if (xfirst)
|
|
{
|
|
xmlSetProp(node,(xmlChar*)"x",(const xmlChar*)xfirst);
|
|
}
|
|
if (yfirst)
|
|
{
|
|
xmlSetProp(node,(xmlChar*)"y",(const xmlChar*)yfirst);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xmlSetProp(node,(xmlChar*)"posref",(const xmlChar*)nextpos);
|
|
xmlSetProp(node,(xmlChar*)"posparent",(const xmlChar*)id);
|
|
}
|
|
}
|
|
|
|
xmlNodeSetName(node,(xmlChar*)"instance");
|
|
|
|
//replace all the $i
|
|
xmlAttrPtr attr = node->properties;
|
|
while(attr)
|
|
{
|
|
CXMLAutoPtr prop((const char*) xmlGetProp( node, attr->name ));
|
|
string str((const char*)prop);
|
|
string::size_type pos = str.find("$i");
|
|
while (pos != string::npos)
|
|
{
|
|
str.replace(pos,2,toString(i));
|
|
pos = str.find("$i",pos);
|
|
}
|
|
xmlSetProp(node,attr->name,(xmlChar*)str.c_str());
|
|
attr = attr->next;
|
|
|
|
}
|
|
//add the new instance to our tree, just near us.
|
|
xmlAddNextSibling (nextSibling, node);
|
|
nextSibling= node;
|
|
|
|
//get the node id, used in the next iteration
|
|
if (bGroupVector)
|
|
{
|
|
id = (char*) xmlGetProp( node, (xmlChar*)"id" );
|
|
if (!id)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo("no id in a vector");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return step > 0 ? (i == index + size) : (i == index - size);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseLink(xmlNodePtr cur, CInterfaceGroup * parentGroup)
|
|
{
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp (cur, (xmlChar*)"expr"));
|
|
if (!ptr)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("<CInterfaceParser::parseLink> Can't read the expression for a link node");
|
|
return false;
|
|
}
|
|
std::string expr = ptr;
|
|
|
|
|
|
std::vector<CInterfaceLink::CTargetInfo> targets;
|
|
std::vector<CInterfaceLink::CCDBTargetInfo> cdbTargets;
|
|
|
|
ptr = (char*) xmlGetProp (cur, (xmlChar*)"target");
|
|
std::string target;
|
|
if( ptr )
|
|
{
|
|
target = std::string( (const char*)ptr );
|
|
if( !editorMode )
|
|
CInterfaceLink::splitLinkTargetsExt(std::string((const char*)ptr), parentGroup, targets, cdbTargets);
|
|
}
|
|
|
|
// optional action handler
|
|
std::string action;
|
|
std::string params;
|
|
std::string cond;
|
|
ptr = (char*) xmlGetProp (cur, (xmlChar*)"action");
|
|
if (ptr) action = (const char *) ptr;
|
|
ptr = (char*) xmlGetProp (cur, (xmlChar*)"params");
|
|
if (ptr) params = (const char *) ptr;
|
|
ptr = (char*) xmlGetProp (cur, (xmlChar*)"cond");
|
|
if (ptr) cond = (const char *) ptr;
|
|
|
|
// create the link
|
|
if( !editorMode )
|
|
{
|
|
CInterfaceLink *il = new CInterfaceLink;
|
|
il->init(targets, cdbTargets, expr, action, params, cond, parentGroup); // init will add 'il' in the list of link present in 'elm'
|
|
}
|
|
else
|
|
{
|
|
SLinkData linkData;
|
|
linkData.parent = parentGroup->getId();
|
|
linkData.expr = expr;
|
|
linkData.target = target;
|
|
linkData.action = action;
|
|
linkData.cond = cond;
|
|
linkData.params = params;
|
|
|
|
addLinkData( linkData );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseVariable (xmlNodePtr cur, CInterfaceGroup * /* parentGroup */)
|
|
{
|
|
//get the args
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp (cur, (xmlChar*)"entry"));
|
|
if (!ptr)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo ("no entry in a variable tag");
|
|
return false;
|
|
}
|
|
string entry((const char*)ptr);
|
|
|
|
ptr = (char*) xmlGetProp (cur, (xmlChar*)"type");
|
|
if (!ptr)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo ("no type in a variable tag");
|
|
return false;
|
|
}
|
|
string type((const char*)ptr);
|
|
|
|
string value;
|
|
ptr = (char*) xmlGetProp (cur, (xmlChar*)"value");
|
|
if (!ptr)
|
|
{
|
|
//if no value is specified, try to get the db entry directly
|
|
value = entry;
|
|
}
|
|
else
|
|
{
|
|
value = string((const char*)ptr);
|
|
}
|
|
|
|
// Array definition
|
|
sint size= 1;
|
|
bool ArrayMode= false;
|
|
string entryPrefix;
|
|
string entrySuffix;
|
|
ptr = (char*) xmlGetProp (cur, (xmlChar*)"size");
|
|
if (ptr)
|
|
{
|
|
ArrayMode= true;
|
|
fromString((const char*)ptr, size);
|
|
|
|
string::size_type pos= entry.find("$i");
|
|
if( pos==string::npos )
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo ("no $i found in a 'variable' tag with 'size' defined ");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
entryPrefix= entry.substr(0, pos);
|
|
entrySuffix= entry.substr(pos+2);
|
|
}
|
|
}
|
|
|
|
// loop all variables
|
|
for(sint index= 0;index<size;index++)
|
|
{
|
|
// If array variable, build the variable name
|
|
if(ArrayMode)
|
|
{
|
|
entry= entryPrefix + toString(index) + entrySuffix;
|
|
}
|
|
|
|
// access the database
|
|
CInterfaceProperty prop;
|
|
|
|
if (type == "sint64")
|
|
prop.readSInt64(value.c_str(),entry);
|
|
else if (type == "sint32")
|
|
prop.readSInt32(value.c_str(),entry);
|
|
else if (type == "float" || type == "double")
|
|
prop.readDouble(value.c_str(),entry);
|
|
else if (type == "bool")
|
|
prop.readBool(value.c_str(),entry);
|
|
else if (type == "rgba")
|
|
prop.readRGBA(value.c_str(),entry);
|
|
else if (type == "hotspot")
|
|
prop.readHotSpot(value.c_str(),entry);
|
|
else if (type == "text")
|
|
{
|
|
/*uint textId = addText(value);
|
|
prop.readSInt32(toString(textId),entry);*/
|
|
}
|
|
}
|
|
|
|
if( editorMode )
|
|
{
|
|
VariableData data;
|
|
|
|
ptr = xmlGetProp( cur, BAD_CAST "entry" );
|
|
if( ptr )
|
|
data.entry = std::string( (const char*)ptr );
|
|
|
|
data.type = type;
|
|
|
|
ptr = xmlGetProp( cur, BAD_CAST "value" );
|
|
if( ptr )
|
|
data.value = std::string( (const char*)ptr );
|
|
|
|
ptr = xmlGetProp( cur, BAD_CAST "size" );
|
|
if( ptr )
|
|
fromString( std::string( (const char*)ptr ), data.size );
|
|
|
|
variableCache[ data.entry ] = data;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseOptions (xmlNodePtr cur, CInterfaceGroup * /* parentGroup */)
|
|
{
|
|
// build the options from type
|
|
CInterfaceOptions *options = NULL;
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"type" ));
|
|
if (ptr)
|
|
{
|
|
options = NLMISC_GET_FACTORY( CInterfaceOptions, std::string ).createObject( std::string( (const char*)ptr ), CInterfaceOptions::TCtorParam() );
|
|
|
|
if( options == NULL )
|
|
options = new CInterfaceOptions( CInterfaceOptions::TCtorParam() );
|
|
}
|
|
else
|
|
{
|
|
options = new CInterfaceOptions( CInterfaceOptions::TCtorParam() );
|
|
}
|
|
|
|
CWidgetManager *wm = CWidgetManager::getInstance();
|
|
|
|
// get the name
|
|
ptr = (char*) xmlGetProp( cur, (xmlChar*)"name" );
|
|
if (!ptr)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo ("options has no name");
|
|
return false;
|
|
}
|
|
string optionsName = ptr;
|
|
|
|
// herit if possible
|
|
ptr = (char*) xmlGetProp( cur, (xmlChar*)"herit" );
|
|
if (ptr)
|
|
{
|
|
string optionsParentName = ptr;
|
|
CInterfaceOptions *io = wm->getOptions( optionsParentName );
|
|
if( io != NULL )
|
|
options->copyBasicMap( *io );
|
|
}
|
|
|
|
// parse parameters
|
|
if (options->parse (cur))
|
|
{
|
|
// Remove old one
|
|
wm->removeOptions( optionsName );
|
|
wm->addOptions( optionsName, options );
|
|
}
|
|
else
|
|
{
|
|
delete options;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseGroup (xmlNodePtr cur, CInterfaceGroup * parentGroup, bool reload)
|
|
{
|
|
CInterfaceGroup * group;
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"type" ));
|
|
if (ptr)
|
|
{
|
|
group = dynamic_cast<CInterfaceGroup*>( NLMISC_GET_FACTORY(CViewBase, std::string).createObject(string((const char*)ptr), CViewBase::TCtorParam()) );
|
|
if (group == NULL)
|
|
{
|
|
group = dynamic_cast<CInterfaceGroup*>(NLMISC_GET_FACTORY(CViewBase, std::string).createObject("interface_group", CViewBase::TCtorParam()));
|
|
}
|
|
|
|
}
|
|
else
|
|
group = dynamic_cast<CInterfaceGroup*>(NLMISC_GET_FACTORY(CViewBase, std::string).createObject("interface_group", CViewBase::TCtorParam()));
|
|
|
|
// parse the group attributes
|
|
if (!group->parse(cur,parentGroup))
|
|
{
|
|
delete group;
|
|
// todo hulud interface syntax error
|
|
nlwarning ("cannot parse group attributes");
|
|
return false;
|
|
}
|
|
|
|
if (parentGroup)
|
|
{
|
|
CGroupList *pList = dynamic_cast<CGroupList*>(parentGroup);
|
|
if (parentGroup->getElement(group->getId()) != NULL)
|
|
{
|
|
// Remove old groupe and replace
|
|
if (reload)
|
|
{
|
|
// Remove from the parent
|
|
parentGroup->delElement (group->getId(), true);
|
|
}
|
|
else
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("id already exists for %s in %s", group->getId().c_str(), parentGroup->getId().c_str());
|
|
delete group;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (pList != NULL)
|
|
pList->addChild (group);
|
|
else
|
|
parentGroup->addGroup (group);
|
|
}
|
|
else
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo ("no parent for %s", group->getId().c_str());
|
|
delete group;
|
|
return false;
|
|
}
|
|
|
|
//parse the children
|
|
bool ok = parseGroupChildren(cur, group, reload);
|
|
|
|
if (!ok)
|
|
{
|
|
string tmp = "cannot parse group "+group->getId();
|
|
// todo hulud interface syntax error
|
|
nlinfo (tmp.c_str());
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseGroupChildren(xmlNodePtr cur, CInterfaceGroup * parentGroup, bool reload)
|
|
{
|
|
cur = cur->children;
|
|
bool ok = true;
|
|
while (cur)
|
|
{
|
|
if ( !strcmp((char*)cur->name,"view") )
|
|
ok = ok && parseView(cur,parentGroup, reload);
|
|
else if ( !strcmp((char*)cur->name,"ctrl") )
|
|
ok = ok && parseControl(cur,parentGroup, reload);
|
|
else if ( !strcmp((char*)cur->name,"group") )
|
|
ok = ok && parseGroup(cur,parentGroup, reload);
|
|
else if ( !strcmp((char*)cur->name,"instance") )
|
|
ok = ok && parseInstance(cur);
|
|
else if ( !strcmp((char*)cur->name,"vector") )
|
|
ok = ok && parseVector(cur);
|
|
else if ( !strcmp((char*)cur->name,"link") )
|
|
ok = ok && parseLink(cur,parentGroup);
|
|
else
|
|
{
|
|
IParserModule *module = getModuleFor( (char*)( cur->name ) );
|
|
if( module != NULL )
|
|
{
|
|
if( module->canParseInStage( IParserModule::GroupChildren ) )
|
|
ok = ok && module->parse( cur, parentGroup );
|
|
}
|
|
}
|
|
|
|
|
|
cur = cur->next;
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseControl (xmlNodePtr cur, CInterfaceGroup * parentGroup, bool reload)
|
|
{
|
|
CCtrlBase* ctrl = NULL;
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"type" ));
|
|
if (!ptr)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo ("no type in a control tag");
|
|
return false;
|
|
}
|
|
|
|
ctrl = dynamic_cast<CCtrlBase*>(NLMISC_GET_FACTORY(CViewBase, std::string).createObject(string((const char*)ptr), CViewBase::TCtorParam()));
|
|
|
|
if (ctrl)
|
|
{
|
|
if (!ctrl->parse(cur,parentGroup))
|
|
{
|
|
delete ctrl;
|
|
return false;
|
|
}
|
|
if (parentGroup->getElement(ctrl->getId()) != NULL)
|
|
{
|
|
// Remove old groupe and replace
|
|
if (reload)
|
|
parentGroup->delElement (ctrl->getId());
|
|
else
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("id already exists for %s in %s", ctrl->getId().c_str(), parentGroup->getId().c_str());
|
|
delete ctrl;
|
|
return false;
|
|
}
|
|
}
|
|
// Add the ctrl to the parent group
|
|
parentGroup->addCtrl(ctrl);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseView(xmlNodePtr cur, CInterfaceGroup * parentGroup, bool reload)
|
|
{
|
|
CViewBase * view=NULL;
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"type" ));
|
|
if (!ptr)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo("no type in a view");
|
|
return false;
|
|
}
|
|
|
|
view = NLMISC_GET_FACTORY(CViewBase, std::string).createObject(string((const char*)ptr), CViewBase::TCtorParam());
|
|
|
|
if ( !strcmp(ptr,"pointer"))
|
|
{
|
|
if( editorMode )
|
|
savePointerSettings( cur );
|
|
|
|
CWidgetManager::getInstance()->setPointer( dynamic_cast<CViewPointer*>(view) );
|
|
}
|
|
|
|
//nlinfo("view type %s mem : %d",ptr,view->getMemory());
|
|
if (view)
|
|
{
|
|
if (!view->parse(cur,parentGroup))
|
|
{
|
|
delete view;
|
|
return false;
|
|
}
|
|
if (parentGroup->getElement(view->getId()) != NULL)
|
|
{
|
|
// Remove old groupe and replace
|
|
if ( reload )
|
|
parentGroup->delElement (view->getId());
|
|
else
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("id already exists for %s in %s", view->getId().c_str(), parentGroup->getId().c_str());
|
|
delete view;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//add the view to the parent group
|
|
CGroupList *pList = dynamic_cast<CGroupList*>(parentGroup);
|
|
if (pList != NULL)
|
|
{
|
|
pList->addChild (view);
|
|
}
|
|
else
|
|
{
|
|
parentGroup->addView(view);
|
|
}
|
|
return true;
|
|
}
|
|
// todo hulud interface syntax error
|
|
nlinfo("unknown view type %s", (const char*)ptr);
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseTreeNode (xmlNodePtr cur, CGroupContainer *parentGroup)
|
|
{
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"node" ));
|
|
if (!ptr) return false;
|
|
CInterfaceElement *pEltFound = NULL;
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
for (uint32 i = 0; i < _MasterGroups.size(); ++i)
|
|
{
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[i];
|
|
for (uint32 j = 0; j < rMG.Group->getGroups().size(); ++j)
|
|
{
|
|
CInterfaceGroup *pIG = rMG.Group->getGroups()[j];
|
|
string stmp = strlwr(pIG->getId().substr(pIG->getId().rfind(':')+1,pIG->getId().size()));
|
|
string stmp2 = strlwr(string((const char*)ptr));
|
|
if (stmp == stmp2)
|
|
{
|
|
pEltFound = pIG;
|
|
break;
|
|
}
|
|
}
|
|
if (pEltFound != NULL)
|
|
break;
|
|
}
|
|
if (pEltFound == NULL)
|
|
{
|
|
string stmp = string("element not found for tree : ") + string((const char*)ptr);
|
|
// todo hulud interface syntax error
|
|
nlinfo(stmp.c_str());
|
|
return false;
|
|
}
|
|
CGroupContainer *pIC = dynamic_cast<CGroupContainer*>(pEltFound);
|
|
if (pIC == NULL)
|
|
{
|
|
string stmp = string("not a container : ") + pEltFound->getId();
|
|
// todo hulud interface syntax error
|
|
nlinfo(stmp.c_str());
|
|
return false;
|
|
}
|
|
parentGroup->attachContainer (pIC);
|
|
cur = cur->children;
|
|
while (cur)
|
|
{
|
|
parseTreeNode(cur, pIC);
|
|
cur = cur->next;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::setupTreeNode (xmlNodePtr cur, CGroupContainer * /* parentGroup */)
|
|
{
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"node" ));
|
|
if (!ptr) return false;
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
CInterfaceElement *pEltFound = NULL;
|
|
for (uint32 i = 0; i < _MasterGroups.size(); ++i)
|
|
{
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[i];
|
|
for (uint32 j = 0; j < rMG.Group->getGroups().size(); ++j)
|
|
{
|
|
CInterfaceGroup *pIG = rMG.Group->getGroups()[j];
|
|
string stmp = strlwr(pIG->getId().substr(pIG->getId().rfind(':')+1,pIG->getId().size()));
|
|
string stmp2 = strlwr(string((const char*)ptr));
|
|
if (stmp == stmp2)
|
|
{
|
|
pEltFound = pIG;
|
|
break;
|
|
}
|
|
}
|
|
if (pEltFound != NULL)
|
|
break;
|
|
}
|
|
if (pEltFound == NULL)
|
|
{
|
|
string stmp = string("element not found for tree : ") + string((const char*)ptr);
|
|
// todo hulud interface syntax error
|
|
nlinfo(stmp.c_str());
|
|
return false;
|
|
}
|
|
CGroupContainer *pIC = dynamic_cast<CGroupContainer*>(pEltFound);
|
|
if (pIC == NULL)
|
|
{
|
|
string stmp = string("not a container : ") + pEltFound->getId();
|
|
// todo hulud interface syntax error
|
|
nlinfo(stmp.c_str());
|
|
return false;
|
|
}
|
|
// See if the group should be docked.
|
|
ptr = (char*) xmlGetProp( cur, (xmlChar*)"docked" );
|
|
if (nlstricmp((const char *) ptr, "true") == 0)
|
|
{
|
|
// dock the container
|
|
pIC->popupCurrentPos();
|
|
// compute position on screen
|
|
sint32 x = 0, y = 0, w = 200, h = 100;
|
|
ptr = (char*) xmlGetProp( cur, (xmlChar*)"x" );
|
|
if (ptr)
|
|
{
|
|
sint32 value;
|
|
if (fromString((const char*)ptr, value))
|
|
{
|
|
x = value;
|
|
}
|
|
}
|
|
ptr = (char*) xmlGetProp( cur, (xmlChar*)"y" );
|
|
if (ptr)
|
|
{
|
|
sint32 value;
|
|
if (fromString((const char*)ptr, value))
|
|
{
|
|
y = value;
|
|
}
|
|
}
|
|
ptr = (char*) xmlGetProp( cur, (xmlChar*)"w" );
|
|
if (ptr)
|
|
{
|
|
sint32 value;
|
|
if (fromString((const char*)ptr, value))
|
|
{
|
|
w = value;
|
|
}
|
|
}
|
|
ptr = (char*) xmlGetProp( cur, (xmlChar*)"h" );
|
|
if (ptr)
|
|
{
|
|
sint32 value;
|
|
if (fromString((const char*)ptr, value))
|
|
{
|
|
h = value;
|
|
}
|
|
}
|
|
pIC->setX(x);
|
|
pIC->setY(y);
|
|
pIC->setW(w);
|
|
pIC->setH(h);
|
|
pIC->invalidateCoords();
|
|
}
|
|
//
|
|
while (cur)
|
|
{
|
|
setupTreeNode(cur, pIC);
|
|
cur = cur->next;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CInterfaceParser::savePointerSettings( xmlNodePtr node )
|
|
{
|
|
if( node == NULL )
|
|
return;
|
|
|
|
xmlAttrPtr prop = node->properties;
|
|
|
|
std::string key;
|
|
std::string value;
|
|
|
|
while( prop != NULL )
|
|
{
|
|
key = std::string( reinterpret_cast< const char* >( prop->name ) );
|
|
value = std::string( reinterpret_cast< char* >( prop->children->content ) );
|
|
|
|
pointerSettings[ key ] = value;
|
|
|
|
prop = prop->next;
|
|
}
|
|
}
|
|
|
|
void CInterfaceParser::saveKeySettings( xmlNodePtr node )
|
|
{
|
|
if( node == NULL )
|
|
return;
|
|
|
|
xmlAttrPtr prop = node->properties;
|
|
|
|
std::string name( reinterpret_cast< char* >( xmlGetProp( node, BAD_CAST "name" ) ) );
|
|
if( name.empty() )
|
|
return;
|
|
|
|
std::string key;
|
|
std::string value;
|
|
std::map< std::string, std::string > propMap;
|
|
|
|
while( prop != NULL )
|
|
{
|
|
key = std::string( reinterpret_cast< const char* >( prop->name ) );
|
|
value = std::string( reinterpret_cast< char* >( prop->children->content ) );
|
|
|
|
if( key == "name" )
|
|
{
|
|
prop = prop->next;
|
|
continue;
|
|
}
|
|
|
|
propMap[ key ] = value;
|
|
|
|
prop = prop->next;
|
|
}
|
|
|
|
if( propMap.empty() )
|
|
return;
|
|
|
|
keySettings[ name ] = propMap;
|
|
}
|
|
|
|
void CInterfaceParser::addModule( std::string name, IParserModule *module )
|
|
{
|
|
std::map< std::string, IParserModule* >::iterator itr =
|
|
moduleMap.find( name );
|
|
|
|
if( itr != moduleMap.end() )
|
|
{
|
|
nlwarning( "Tried to add parser module %s, which already exists.",name.c_str() );
|
|
delete module;
|
|
return;
|
|
}
|
|
|
|
module->setParser( this );
|
|
moduleMap[ name ] = module;
|
|
}
|
|
|
|
CInterfaceParser::IParserModule* CInterfaceParser::getModuleFor( std::string name ) const
|
|
{
|
|
std::map< std::string, IParserModule* >::const_iterator itr =
|
|
moduleMap.find( name );
|
|
if( itr == moduleMap.end() )
|
|
return NULL;
|
|
else
|
|
return itr->second;
|
|
}
|
|
|
|
void CInterfaceParser::removeAllModules()
|
|
{
|
|
std::map< std::string, IParserModule* >::iterator itr;
|
|
for( itr = moduleMap.begin(); itr != moduleMap.end(); ++itr )
|
|
{
|
|
delete itr->second;
|
|
}
|
|
moduleMap.clear();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::setupTree (xmlNodePtr cur, CWidgetManager::SMasterGroup * /* parentGroup */)
|
|
{
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"node" ));
|
|
if (!ptr) return false;
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
CInterfaceElement *pEltFound = NULL;
|
|
for (uint32 i = 0; i < _MasterGroups.size(); ++i)
|
|
{
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[i];
|
|
for (uint32 j = 0; j < rMG.Group->getGroups().size(); ++j)
|
|
{
|
|
CInterfaceGroup *pIG = rMG.Group->getGroups()[j];
|
|
string stmp = strlwr(pIG->getId().substr(pIG->getId().rfind(':')+1,pIG->getId().size()));
|
|
string stmp2 = strlwr(string((const char*)ptr));
|
|
if (stmp == stmp2)
|
|
{
|
|
pEltFound = pIG;
|
|
break;
|
|
}
|
|
}
|
|
if (pEltFound != NULL)
|
|
break;
|
|
}
|
|
|
|
if (pEltFound == NULL)
|
|
{
|
|
string stmp = string("no group found for ") + string((const char*)ptr);
|
|
// todo hulud interface syntax error
|
|
nlinfo(stmp.c_str());
|
|
return false;
|
|
}
|
|
|
|
// the element must be a group
|
|
CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(pEltFound);
|
|
if (pIG == NULL)
|
|
{
|
|
string stmp = string("not a group !") + pEltFound->getId();
|
|
// todo hulud interface syntax error
|
|
nlinfo(stmp.c_str());
|
|
return false;
|
|
}
|
|
|
|
// but must not be a group modal
|
|
if (dynamic_cast<CGroupModal*>(pIG))
|
|
{
|
|
string stmp = string("tree can't have modal group !") + pEltFound->getId();
|
|
// todo hulud interface syntax error
|
|
nlinfo(stmp.c_str());
|
|
return false;
|
|
}
|
|
|
|
|
|
CGroupContainer *pIC = dynamic_cast<CGroupContainer*>(pEltFound);
|
|
if (pIC != NULL)
|
|
{
|
|
cur = cur->children;
|
|
while (cur)
|
|
{
|
|
setupTreeNode(cur, pIC);
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseTree (xmlNodePtr cur, CWidgetManager::SMasterGroup *parentGroup)
|
|
{
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"node" ));
|
|
if (!ptr) return false;
|
|
std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
|
|
CInterfaceElement *pEltFound = NULL;
|
|
for (uint32 i = 0; i < _MasterGroups.size(); ++i)
|
|
{
|
|
CWidgetManager::SMasterGroup &rMG = _MasterGroups[i];
|
|
for (uint32 j = 0; j < rMG.Group->getGroups().size(); ++j)
|
|
{
|
|
CInterfaceGroup *pIG = rMG.Group->getGroups()[j];
|
|
string stmp = NLMISC::toLower(pIG->getId().substr(pIG->getId().rfind(':')+1,pIG->getId().size()));
|
|
string stmp2 = NLMISC::toLower(string((const char*)ptr));
|
|
if (stmp == stmp2)
|
|
{
|
|
pEltFound = pIG;
|
|
break;
|
|
}
|
|
}
|
|
if (pEltFound != NULL)
|
|
break;
|
|
}
|
|
|
|
if (pEltFound == NULL)
|
|
{
|
|
string stmp = string("no group found for ") + string((const char*)ptr);
|
|
// todo hulud interface syntax error
|
|
nlinfo(stmp.c_str());
|
|
return false;
|
|
}
|
|
|
|
// the element must be a group
|
|
CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(pEltFound);
|
|
if (pIG == NULL)
|
|
{
|
|
string stmp = string("not a group !") + pEltFound->getId();
|
|
// todo hulud interface syntax error
|
|
nlinfo(stmp.c_str());
|
|
return false;
|
|
}
|
|
|
|
// but must not be a group modal
|
|
if (dynamic_cast<CGroupModal*>(pIG))
|
|
{
|
|
string stmp = string("tree can't have modal group !") + pEltFound->getId();
|
|
// todo hulud interface syntax error
|
|
nlinfo(stmp.c_str());
|
|
return false;
|
|
}
|
|
|
|
// Ok add it.
|
|
CWidgetManager::getInstance()->addWindowToMasterGroup(parentGroup->Group->getId(), pIG);
|
|
|
|
CGroupContainer *pIC = dynamic_cast<CGroupContainer*>(pEltFound);
|
|
if (pIC != NULL)
|
|
{
|
|
cur = cur->children;
|
|
while (cur)
|
|
{
|
|
parseTreeNode(cur, pIC);
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseDefine(xmlNodePtr cur)
|
|
{
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"id" ));
|
|
if (!ptr || *ptr==0)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo ("no id in a define");
|
|
return false;
|
|
}
|
|
CXMLAutoPtr ptrVal2;
|
|
CXMLAutoPtr ptrVal((const char*) xmlGetProp( cur, (xmlChar*)"value" ));
|
|
if (!ptrVal)
|
|
{
|
|
ptrVal2 = (char*) xmlGetProp( cur, (xmlChar*)"value_from_code" );
|
|
if (!ptrVal2)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("<parseDefine> : no value nor value_from_code in a define");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// verify id.
|
|
string id= (const char*)ptr;
|
|
for(uint i=0;i<id.size();i++)
|
|
{
|
|
if(!validDefineChar(id[i]))
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("<parseDefine> : bad id in a define. Bad char found: %c", id[i]);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check if we have to execute some code
|
|
if (ptrVal2)
|
|
{
|
|
CInterfaceExprValue res;
|
|
|
|
if (CInterfaceExpr::eval(ptrVal2, res))
|
|
{
|
|
if (!res.toString())
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("<parseDefine> : cant eval to string value_from_code : %s", (const char*)ptrVal2);
|
|
return false;
|
|
}
|
|
setDefine(id, res.getString().c_str());
|
|
}
|
|
else
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("<parseDefine> : cant eval value_from_code : %s", (const char*)ptrVal2);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Assign var
|
|
setDefine (id, (const char*)ptrVal);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::parseProcedure(xmlNodePtr cur, bool reload)
|
|
{
|
|
CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"id" ));
|
|
if (!ptr || *ptr==0)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("no id in a procedure");
|
|
return false;
|
|
}
|
|
string procId= ptr;
|
|
|
|
if (_ProcedureMap.find(procId) != _ProcedureMap.end())
|
|
{
|
|
// If reloading the interface, remove the old proc
|
|
if (reload)
|
|
{
|
|
_ProcedureMap.erase (procId);
|
|
}
|
|
else
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning ("id already exists for procedure %s", procId.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// build the procedure
|
|
CProcedure newProc;
|
|
|
|
// Look for sons.
|
|
cur = cur->children;
|
|
while (cur)
|
|
{
|
|
if (stricmp((char*)cur->name,"action") == 0)
|
|
{
|
|
CXMLAutoPtr name((const char*) xmlGetProp (cur, (xmlChar*)"handler"));
|
|
CXMLAutoPtr params((const char*) xmlGetProp (cur, (xmlChar*)"params"));
|
|
CXMLAutoPtr cond((const char*) xmlGetProp (cur, (xmlChar*)"cond"));
|
|
CProcAction action;
|
|
if(!name)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo("no action name in a action of procedure %s", procId.c_str());
|
|
return false;
|
|
}
|
|
else
|
|
action.Action= (const char*)name;
|
|
if(params)
|
|
{
|
|
action.Parameters = (const char*)params;
|
|
action.buildParamBlock((const char*)params);
|
|
}
|
|
if(cond)
|
|
{
|
|
action.Conditions = (const char*)cond;
|
|
action.buildCondBlock ((const char*)cond);
|
|
}
|
|
newProc.Actions.push_back(action);
|
|
}
|
|
else if (!strcmp((char*)cur->name,"instance"))
|
|
{
|
|
if (!parseInstance(cur))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse instance");
|
|
}
|
|
else if (!strcmp((char*)cur->name,"vector"))
|
|
{
|
|
if (!parseVector(cur))
|
|
// todo hulud interface syntax error
|
|
nlwarning ("could not parse vector");
|
|
}
|
|
cur = cur->next;
|
|
}
|
|
|
|
// add/replace the procedure
|
|
_ProcedureMap[procId]= newProc;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CInterfaceParser::setupOptions()
|
|
{
|
|
if( setupCallback != NULL )
|
|
setupCallback->setupOptions();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool CInterfaceParser::initCoordsAndLuaScript()
|
|
{
|
|
// set all position associations
|
|
for (map<CInterfaceElement*,string>::const_iterator it = _ParentPositionsMap.begin(); it != _ParentPositionsMap.end();it++)
|
|
{
|
|
CInterfaceElement *pIEL = it->first;
|
|
string EltName = it->second;
|
|
|
|
CInterfaceGroup *parent = pIEL->getParent();
|
|
CInterfaceElement *parentpos;
|
|
//if the element has a parent check the parent's children
|
|
if (parent)
|
|
parentpos = parent->getElement(EltName);
|
|
//if the element has no parent, check the windows
|
|
else
|
|
parentpos = CWidgetManager::getInstance()->getWindowFromId(EltName);
|
|
|
|
if (parentpos == NULL)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo(" the element %s was not found as %s position reference ", EltName.c_str(), pIEL->getId().c_str());
|
|
}
|
|
else
|
|
{
|
|
pIEL->setParentPos (parentpos);
|
|
}
|
|
}
|
|
// Same for size
|
|
for (map<CInterfaceElement*,string>::const_iterator it2 = _ParentSizesMap.begin(); it2 != _ParentSizesMap.end(); it2++)
|
|
{
|
|
CInterfaceElement *pIEL = it2->first;
|
|
string EltName = it2->second;
|
|
|
|
CInterfaceGroup *parent = pIEL->getParent();
|
|
CInterfaceElement *parentsize;
|
|
if (EltName == "parent")
|
|
{
|
|
parentsize = pIEL->getParent();
|
|
}
|
|
else
|
|
{
|
|
//if the element has a parent check the parent's children
|
|
if (parent)
|
|
parentsize = parent->getElement(EltName);
|
|
//if the element has no parent, check the windows
|
|
else
|
|
parentsize = CWidgetManager::getInstance()->getWindowFromId(EltName);
|
|
}
|
|
|
|
if (parentsize == NULL)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo(" the element %s was not found as %s size reference ", EltName.c_str(), pIEL->getId().c_str());
|
|
}
|
|
else
|
|
{
|
|
pIEL->setParentSize (parentsize);
|
|
}
|
|
}
|
|
// Same for size max
|
|
for (map<CInterfaceElement*,string>::const_iterator it3 = _ParentSizesMaxMap.begin(); it3 != _ParentSizesMaxMap.end(); it3++)
|
|
{
|
|
CInterfaceGroup *pIEL = dynamic_cast<CInterfaceGroup*>(it3->first);
|
|
if (pIEL == NULL) continue;
|
|
string EltName = it3->second;
|
|
|
|
CInterfaceGroup *parent = pIEL->getParent();
|
|
CInterfaceElement *parentsizemax;
|
|
if (EltName == "parent")
|
|
{
|
|
parentsizemax = parent;
|
|
}
|
|
else
|
|
{
|
|
//if the element has a parent check the parent's children
|
|
if (parent)
|
|
parentsizemax = parent->getElement(EltName);
|
|
//if the element has no parent, check the windows
|
|
else
|
|
parentsizemax = CWidgetManager::getInstance()->getWindowFromId(EltName);
|
|
}
|
|
|
|
if (parentsizemax == NULL)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo(" the element %s was not found as %s sizemax reference ", EltName.c_str(), pIEL->getId().c_str());
|
|
}
|
|
else
|
|
{
|
|
pIEL->setParentSizeMax (parentsizemax);
|
|
}
|
|
}
|
|
|
|
// Same For LUA Class association
|
|
for (map<CInterfaceGroup*,string>::const_iterator itLua = _LuaClassAssociation.begin(); itLua != _LuaClassAssociation.end(); itLua++)
|
|
{
|
|
// execute the script on this group
|
|
CAHManager::getInstance()->runActionHandler("lua", itLua->first, itLua->second);
|
|
}
|
|
|
|
|
|
// Clear all structures used only for init
|
|
NLMISC::contReset (_ParentPositionsMap);
|
|
NLMISC::contReset (_ParentSizesMap);
|
|
NLMISC::contReset (_ParentSizesMaxMap);
|
|
NLMISC::contReset (_LuaClassAssociation);
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void CInterfaceParser::addParentPositionAssociation(CInterfaceElement* element, const std::string& parent)
|
|
{
|
|
_ParentPositionsMap.insert (std::map<CInterfaceElement*,std::string>::value_type(element, parent));
|
|
}
|
|
|
|
std::string CInterfaceParser::getParentPosAssociation( CInterfaceElement *element ) const
|
|
{
|
|
std::map< CInterfaceElement*, std::string >::const_iterator itr =
|
|
_ParentPositionsMap.find( element );
|
|
if( itr == _ParentPositionsMap.end() )
|
|
return "parent";
|
|
else
|
|
return CInterfaceElement::stripId( itr->second );
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void CInterfaceParser::addParentSizeAssociation(CInterfaceElement* element, const std::string& parent)
|
|
{
|
|
_ParentSizesMap.insert (std::map<CInterfaceElement*,std::string>::value_type(element, parent));
|
|
}
|
|
|
|
std::string CInterfaceParser::getParentSizeAssociation( CInterfaceElement *element ) const
|
|
{
|
|
std::map< CInterfaceElement*, std::string >::const_iterator itr =
|
|
_ParentSizesMap.find( element );
|
|
if( itr == _ParentSizesMap.end() )
|
|
return "parent";
|
|
else
|
|
return CInterfaceElement::stripId( itr->second );
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void CInterfaceParser::addParentSizeMaxAssociation (CInterfaceElement *element, const std::string &parent)
|
|
{
|
|
_ParentSizesMaxMap.insert (std::map<CInterfaceElement*,std::string>::value_type(element, parent));
|
|
}
|
|
|
|
std::string CInterfaceParser::getParentSizeMaxAssociation( CInterfaceElement *element ) const
|
|
{
|
|
std::map< CInterfaceElement*, std::string >::const_iterator itr =
|
|
_ParentSizesMap.find( element );
|
|
if( itr == _ParentSizesMap.end() )
|
|
return "parent";
|
|
else
|
|
return CInterfaceElement::stripId( itr->second );
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void CInterfaceParser::addLuaClassAssociation (CInterfaceGroup *group, const std::string &luaScript)
|
|
{
|
|
_LuaClassAssociation.insert (std::map<CInterfaceGroup*,std::string>::value_type(group, luaScript));
|
|
}
|
|
|
|
std::string CInterfaceParser::getLuaClassAssociation( CInterfaceGroup *group ) const
|
|
{
|
|
std::map< CInterfaceGroup*, std::string >::const_iterator itr =
|
|
_LuaClassAssociation.find( group );
|
|
if( itr == _LuaClassAssociation.end() )
|
|
return "";
|
|
else
|
|
return itr->second;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
const std::string &CInterfaceParser::getDefine(const std::string &id) const
|
|
{
|
|
static string NullStr;
|
|
CstItVarMap it= _DefineMap.find(id);
|
|
if(it==_DefineMap.end())
|
|
return NullStr;
|
|
else
|
|
return it->second;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceParser::isDefineExist(const std::string &id) const
|
|
{
|
|
CstItVarMap it= _DefineMap.find(id);
|
|
return it!=_DefineMap.end();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceParser::setDefine(const std::string &id, const std::string &value)
|
|
{
|
|
_DefineMap[id]= value;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceParser::validDefineChar(char c) const
|
|
{
|
|
if(c>='A' && c<='Z')
|
|
return true;
|
|
if(c>='a' && c<='z')
|
|
return true;
|
|
if(c>='0' && c<='9')
|
|
return true;
|
|
if(c=='_')
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
#define DEFINE_IDENT '%'
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceParser::solveDefine(const std::string &propVal, std::string &newPropVal, std::string &defError)
|
|
{
|
|
string::size_type curPos= 0;
|
|
string::size_type lastPos= 0;
|
|
|
|
//if it has some % then solve define value
|
|
while( (curPos=propVal.find(DEFINE_IDENT, curPos)) != string::npos)
|
|
{
|
|
// If it is end of line
|
|
if(curPos==propVal.size()-1)
|
|
{
|
|
// then skip
|
|
curPos= propVal.size();
|
|
}
|
|
// If it is a double %%
|
|
else if(propVal[curPos+1]==DEFINE_IDENT)
|
|
{
|
|
// copy from last to cur included
|
|
curPos++;
|
|
newPropVal+= propVal.substr(lastPos, curPos-lastPos);
|
|
// both % are skipped
|
|
curPos++;
|
|
lastPos= curPos;
|
|
}
|
|
// else parse define value
|
|
else
|
|
{
|
|
// copy the last not define sub string.
|
|
newPropVal+= propVal.substr(lastPos, curPos-lastPos);
|
|
|
|
// skip the %
|
|
curPos++;
|
|
|
|
// get the id pos
|
|
uint startIdPos= (uint)curPos;
|
|
while( curPos<propVal.size() && validDefineChar(propVal[curPos]) )
|
|
curPos++;
|
|
// get the id
|
|
string defineId= propVal.substr(startIdPos, curPos-startIdPos);
|
|
if(!isDefineExist(defineId))
|
|
{
|
|
defError= defineId;
|
|
return false;
|
|
}
|
|
// Add the define value to the string
|
|
newPropVal+= getDefine(defineId);
|
|
|
|
// valid pos is current pos
|
|
lastPos= curPos;
|
|
}
|
|
}
|
|
// concat last part
|
|
newPropVal+= propVal.substr(lastPos, propVal.size()-lastPos);
|
|
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceParser::solveDefine(xmlNodePtr cur)
|
|
{
|
|
CXMLAutoPtr ptr;
|
|
|
|
//get the node properties
|
|
xmlAttrPtr props = cur->properties;
|
|
while (props)
|
|
{
|
|
//get the property value
|
|
ptr = (char*)xmlGetProp( cur, props->name);
|
|
nlassert(ptr);
|
|
string propVal= ptr;
|
|
string newPropVal;
|
|
|
|
// solve define of this prop
|
|
string defError;
|
|
if(!solveDefine(propVal, newPropVal, defError))
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo("can't find define: %s", defError.c_str());
|
|
return false;
|
|
}
|
|
|
|
// change value
|
|
xmlSetProp(cur, props->name, (const xmlChar*)newPropVal.c_str());
|
|
|
|
// next property
|
|
props = props->next;
|
|
}
|
|
|
|
// recurs to node children
|
|
cur= cur->children;
|
|
while(cur)
|
|
{
|
|
if(!solveDefine(cur))
|
|
return false;
|
|
cur= cur->next;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceParser::parseSheetSelection(xmlNodePtr cur)
|
|
{
|
|
CXMLAutoPtr prop;
|
|
prop = (char*) xmlGetProp( cur, (xmlChar*)"name" );
|
|
if (!prop)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("<CInterfaceParser::parseSheetSelection> can't get name of a selection");
|
|
return false;
|
|
}
|
|
std::string groupName = (const char *) prop;
|
|
prop = (char*) xmlGetProp( cur, (xmlChar*)"texture" );
|
|
if (!prop)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("<CInterfaceParser::parseSheetSelection> can't get texture name for selection %s", groupName.c_str());
|
|
return false;
|
|
}
|
|
std::string texName = (const char *) prop;
|
|
prop = (char*) xmlGetProp( cur, (xmlChar*)"color" );
|
|
CRGBA color = CRGBA::White;
|
|
if (prop)
|
|
{
|
|
color = CInterfaceElement::convertColor(prop);
|
|
}
|
|
bool globalColor = true;
|
|
prop = (char*) xmlGetProp( cur, (xmlChar*)"global_color" );
|
|
if (prop) globalColor = CInterfaceElement::convertBool(prop);
|
|
sint groupIndex = _CtrlSheetSelection.addGroup(groupName);
|
|
if (groupIndex != -1)
|
|
{
|
|
CSheetSelectionGroup *csg = _CtrlSheetSelection.getGroup(groupIndex);
|
|
csg->setTexture(texName);
|
|
csg->setColor(color);
|
|
csg->enableGlobalColor(globalColor);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceParser::addLink(CInterfaceLink *link, const std::string &id)
|
|
{
|
|
if (!link)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("link empty");
|
|
return false;
|
|
}
|
|
TLinkMap::const_iterator it = _LinkMap.find(id);
|
|
if (it != _LinkMap.end())
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("<CInterfaceParser::addLink> link %s added twice", id.c_str());
|
|
return false;
|
|
}
|
|
#ifdef NL_DEBUG
|
|
link->LinkName = id;
|
|
#endif
|
|
_LinkMap[id] = link;
|
|
return false;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceParser::removeLink(const std::string &id)
|
|
{
|
|
TLinkMap::iterator it = _LinkMap.find(id);
|
|
if (it == _LinkMap.end())
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("<CInterfaceParser::removeLink> unknown link %s", id.c_str());
|
|
return false;
|
|
}
|
|
CSmartPtr<CInterfaceLink> &link = it->second; // dont need to copy a smart ptr on link since still in map
|
|
for (uint k = 0; k < link->getNumTargets(); ++k)
|
|
{
|
|
link->getTarget(k)->removeLink(link); // remove the link from the list & delete it
|
|
}
|
|
it->second->uninit();
|
|
_LinkMap.erase(it); // NB : the link is holded by a smart ptr, to do this decrease the ref count
|
|
return true;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
xmlNodePtr CInterfaceParser::searchTreeNodeInHierarchy(xmlNodePtr root, const char *node)
|
|
{
|
|
// if I match...
|
|
CXMLAutoPtr prop((const char*) xmlGetProp( root, (xmlChar*)"node" ));
|
|
// not a valide tree node? abort.
|
|
if (!prop) return NULL;
|
|
// match?
|
|
if ( !strcmp((const char*)prop, node ) )
|
|
return root;
|
|
|
|
// No, try with sons.
|
|
xmlNodePtr cur= root->children;
|
|
while(cur)
|
|
{
|
|
xmlNodePtr candidate= searchTreeNodeInHierarchy(cur, node);
|
|
// if found in this branch.
|
|
if(candidate)
|
|
return candidate;
|
|
|
|
// try next
|
|
cur= cur->next;
|
|
}
|
|
|
|
// not found
|
|
return NULL;
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceParser::parseAnim(xmlNodePtr cur, CInterfaceGroup * parentGroup)
|
|
{
|
|
CInterfaceAnim *pAnim;
|
|
|
|
CXMLAutoPtr ptr;
|
|
|
|
ptr = (char*) xmlGetProp( cur, (xmlChar*)"id" );
|
|
if (!ptr)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlinfo ("anim has no id");
|
|
return false;
|
|
}
|
|
string animId = ptr;
|
|
pAnim = new CInterfaceAnim;
|
|
|
|
if (pAnim->parse (cur, parentGroup))
|
|
{
|
|
if (_AnimMap.count(animId))
|
|
{
|
|
nlwarning("Anim %s already exists, replacing with new one", animId.c_str());
|
|
}
|
|
_AnimMap[animId] = pAnim;
|
|
}
|
|
else
|
|
{
|
|
delete pAnim;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//==================================================================
|
|
void CInterfaceParser::freeXMLNodeAndSibblings(xmlNodePtr node)
|
|
{
|
|
if (!node) return;
|
|
while (node)
|
|
{
|
|
xmlNodePtr currNode = node;
|
|
node = node->next;
|
|
xmlFreeNode(currNode);
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
CInterfaceGroup *CInterfaceParser::createGroupInstance(const std::string &templateName, const std::string &parentID, const std::pair<std::string,std::string> *templateParams, uint numParams, bool updateLinks /* = true */)
|
|
{
|
|
// create basic xml node that contains infos for the template
|
|
xmlNodePtr instance = xmlNewNode(NULL, (const xmlChar *) "instance");
|
|
if (!instance)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("<CInterfaceParser::createGroupInstance> Can't create xml node ");
|
|
return NULL;
|
|
}
|
|
for(uint k = 0; k < numParams; ++k)
|
|
{
|
|
xmlSetProp(instance, (const xmlChar *) templateParams[k].first.c_str(), (const xmlChar *) templateParams[k].second.c_str());
|
|
}
|
|
xmlSetProp(instance, (const xmlChar *) "template", (const xmlChar *) templateName.c_str());
|
|
if (!parseInstance(instance))
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("<CInterfaceParser::createGroupInstance> cannot create instance from template %s", templateName.c_str());
|
|
freeXMLNodeAndSibblings(instance);
|
|
return NULL;
|
|
}
|
|
|
|
// result should contain a group
|
|
xmlNodePtr currNode = instance->next;
|
|
while (currNode)
|
|
{
|
|
if (strcmp((const char *) currNode->name, "group") == 0 && currNode->type == XML_ELEMENT_NODE)
|
|
{
|
|
// TODO nico : build a struct from that mess
|
|
std::map<CInterfaceElement*,std::string> localParentPositionsMap;
|
|
std::map<CInterfaceElement*,std::string> localParentSizesMap;
|
|
std::map<CInterfaceElement*,std::string> localParentSizesMaxMap;
|
|
std::map<CInterfaceGroup*,std::string> localLuaClassAssociation;
|
|
|
|
localParentPositionsMap.swap(_ParentPositionsMap);
|
|
localParentSizesMap.swap(_ParentSizesMap);
|
|
localParentSizesMaxMap.swap(_ParentSizesMaxMap);
|
|
localLuaClassAssociation.swap(_LuaClassAssociation);
|
|
|
|
CViewBase::TCtorParam params;
|
|
CInterfaceGroup dummyGroup(params);
|
|
dummyGroup.setId(parentID);
|
|
if (!parseGroup(currNode, &dummyGroup, false))
|
|
{
|
|
localParentPositionsMap.swap(_ParentPositionsMap);
|
|
localParentSizesMap.swap(_ParentSizesMap);
|
|
localParentSizesMaxMap.swap(_ParentSizesMaxMap);
|
|
localLuaClassAssociation.swap(_LuaClassAssociation);
|
|
freeXMLNodeAndSibblings(instance);
|
|
return NULL;
|
|
}
|
|
freeXMLNodeAndSibblings(instance);
|
|
CInterfaceGroup *group = dummyGroup.getGroup((uint) 0);
|
|
dummyGroup.delGroup(group, true);
|
|
group->setParent(NULL);
|
|
group->setParentPos(NULL);
|
|
initCoordsAndLuaScript();
|
|
localParentPositionsMap.swap(_ParentPositionsMap);
|
|
localParentSizesMap.swap(_ParentSizesMap);
|
|
localParentSizesMaxMap.swap(_ParentSizesMaxMap);
|
|
localLuaClassAssociation.swap(_LuaClassAssociation);
|
|
if ((group != NULL) && updateLinks)
|
|
{
|
|
group->updateAllLinks();
|
|
}
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(group);
|
|
if (pGC != NULL)
|
|
pGC->setup();
|
|
return group;
|
|
}
|
|
currNode = currNode->next;
|
|
}
|
|
// todo hulud interface syntax error
|
|
CXMLAutoPtr ptr(xmlGetProp(instance, (const xmlChar *) templateName.c_str()));
|
|
nlwarning("<CInterfaceParser::createGroupInstance> no group found in template %s", (const char*)ptr);
|
|
freeXMLNodeAndSibblings(instance);
|
|
return NULL;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CInterfaceElement *CInterfaceParser::createUIElement(const std::string &templateName, const std::string &parentID, const std::pair<std::string,std::string> *templateParams, uint numParams, bool updateLinks /* = true */)
|
|
{
|
|
std::string elementId;
|
|
|
|
// create basic xml node that contains infos for the template
|
|
xmlNodePtr instance = xmlNewNode(NULL, (const xmlChar *) "instance");
|
|
if (!instance)
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("<CInterfaceParser::addUIElement> Can't create xml node ");
|
|
return NULL;
|
|
}
|
|
for(uint k = 0; k < numParams; ++k)
|
|
{
|
|
xmlSetProp(instance, (const xmlChar *) templateParams[k].first.c_str(), (const xmlChar *) templateParams[k].second.c_str());
|
|
if (!strcmp(templateParams[k].first.c_str(), "id"))
|
|
{
|
|
elementId = templateParams[k].second;
|
|
}
|
|
}
|
|
xmlSetProp(instance, (const xmlChar *) "template", (const xmlChar *) templateName.c_str());
|
|
if (!parseInstance(instance))
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("<CInterfaceParser::addUIElement> cannot create instance from template %s", templateName.c_str());
|
|
freeXMLNodeAndSibblings(instance);
|
|
return NULL;
|
|
}
|
|
|
|
CInterfaceElement *pIE= CWidgetManager::getInstance()->getElementFromId(parentID);
|
|
CInterfaceGroup * parentGroup = dynamic_cast<CInterfaceGroup*>(pIE);
|
|
|
|
if(!parentGroup)
|
|
{
|
|
nlwarning("<CInterfaceParser::addUIElement> no parent group %s found ", parentID.c_str());
|
|
freeXMLNodeAndSibblings(instance);
|
|
return NULL;
|
|
}
|
|
|
|
// result should contain a group
|
|
xmlNodePtr currNode = instance->next;
|
|
CInterfaceElement * newElement = NULL;
|
|
while (currNode)
|
|
{
|
|
if (strcmp((const char *) currNode->name, "group") == 0 && currNode->type == XML_ELEMENT_NODE)
|
|
{
|
|
if (!parseGroup(currNode, parentGroup, false))
|
|
{
|
|
freeXMLNodeAndSibblings(instance);
|
|
return NULL;
|
|
}
|
|
freeXMLNodeAndSibblings(instance);
|
|
newElement = parentGroup->getGroup(elementId);
|
|
parentGroup->delGroup((CInterfaceGroup*)newElement, true);
|
|
}
|
|
else if (strcmp((const char *) currNode->name, "ctrl") == 0 && currNode->type == XML_ELEMENT_NODE)
|
|
{
|
|
if (!parseControl(currNode, parentGroup, false))
|
|
{
|
|
freeXMLNodeAndSibblings(instance);
|
|
return NULL;
|
|
}
|
|
freeXMLNodeAndSibblings(instance);
|
|
newElement = parentGroup->getCtrl(elementId);
|
|
parentGroup->delCtrl((CCtrlBase*)newElement, true);
|
|
}
|
|
|
|
if(newElement != NULL)
|
|
{
|
|
initCoordsAndLuaScript();
|
|
if (updateLinks)
|
|
{
|
|
newElement->updateAllLinks();
|
|
}
|
|
return newElement;
|
|
}
|
|
|
|
currNode = currNode->next;
|
|
}
|
|
// todo hulud interface syntax error
|
|
CXMLAutoPtr ptr(xmlGetProp(instance, (const xmlChar *) templateName.c_str()));
|
|
nlwarning("<CInterfaceParser::addUIElement> no group found in template %s", (const char *)ptr);
|
|
freeXMLNodeAndSibblings(instance);
|
|
return NULL;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceParser::removeAllLinks()
|
|
{
|
|
_LinkMap.clear();
|
|
links.clear();
|
|
linkId = 0;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceParser::removeAllProcedures()
|
|
{
|
|
_ProcedureMap.clear();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceParser::removeAllDefines()
|
|
{
|
|
_DefineMap.clear();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceParser::removeAllTemplates()
|
|
{
|
|
for (uint i = 0; i < _Templates.size(); ++i)
|
|
xmlFreeNode(_Templates[i]);
|
|
_Templates.clear();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceParser::removeAllAnims()
|
|
{
|
|
TAnimMap::iterator it = _AnimMap.begin();
|
|
while (it != _AnimMap.end())
|
|
{
|
|
CInterfaceAnim *pAnim = it->second;
|
|
delete pAnim;
|
|
it++;
|
|
}
|
|
_AnimMap.clear();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceParser::removeAll()
|
|
{
|
|
removeAllLinks();
|
|
CWidgetManager::getInstance()->removeAllOptions();
|
|
removeAllProcedures();
|
|
removeAllDefines();
|
|
removeAllTemplates();
|
|
removeAllAnims();
|
|
CWidgetManager::getInstance()->removeAllMasterGroups();
|
|
_StyleMap.clear();
|
|
_CtrlSheetSelection.deleteGroups();
|
|
NLMISC::contReset (_ParentPositionsMap);
|
|
NLMISC::contReset (_ParentSizesMap);
|
|
NLMISC::contReset (_ParentSizesMaxMap);
|
|
NLMISC::contReset (_LuaClassAssociation);
|
|
variableCache.clear();
|
|
pointerSettings.clear();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
uint CInterfaceParser::getProcedureNumActions(const std::string &procName) const
|
|
{
|
|
CstItProcedureMap it= _ProcedureMap.find(procName);
|
|
if(it!=_ProcedureMap.end())
|
|
{
|
|
const CProcedure &proc= it->second;
|
|
return (uint)proc.Actions.size();
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceParser::getProcedureAction(const std::string &procName, uint actionIndex, std::string &ah, std::string ¶ms) const
|
|
{
|
|
CstItProcedureMap it= _ProcedureMap.find(procName);
|
|
if(it!=_ProcedureMap.end())
|
|
{
|
|
const CProcedure &proc= it->second;
|
|
if(actionIndex<proc.Actions.size())
|
|
{
|
|
const CProcAction &action= proc.Actions[actionIndex];
|
|
// if not a variable parametrized Params
|
|
if(action.ParamBlocks.size()==1 && action.ParamBlocks[0].NumParam==-1)
|
|
{
|
|
ah= action.Action;
|
|
params= action.ParamBlocks[0].String;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
CInterfaceAnim* CInterfaceParser::getAnim( const std::string &name) const
|
|
{
|
|
TAnimMap::const_iterator it = _AnimMap.find( name );
|
|
if( it == _AnimMap.end() )
|
|
{
|
|
nlwarning( "anim %s not found", name.c_str() );
|
|
return NULL;
|
|
}
|
|
else
|
|
return it->second;
|
|
}
|
|
|
|
CProcedure* CInterfaceParser::getProc( const std::string &name )
|
|
{
|
|
TProcedureMap::iterator itr = _ProcedureMap.find( name );
|
|
if( itr == _ProcedureMap.end() )
|
|
return NULL;
|
|
|
|
return &itr->second;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceParser::parseStyle(xmlNodePtr cur)
|
|
{
|
|
string styleId;
|
|
CXMLAutoPtr prop;
|
|
|
|
prop = xmlGetProp (cur, (xmlChar*)"style");
|
|
if(prop)
|
|
styleId= (const char*)prop;
|
|
else
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("'style' not found in 'style'");
|
|
return false;
|
|
}
|
|
|
|
// create or replace style
|
|
CStyle newStyle;
|
|
|
|
//get the node properties
|
|
xmlAttrPtr props = cur->properties;
|
|
while (props)
|
|
{
|
|
// if not the "style" property
|
|
if( nlstricmp((const char*)props->name, "style") != 0 )
|
|
{
|
|
// Append it.
|
|
newStyle.Properties.push_back(CStyleProperty());
|
|
newStyle.Properties.back().Name= (const char*)props->name;
|
|
|
|
CXMLAutoPtr ptr(xmlGetProp( cur, props->name ));
|
|
newStyle.Properties.back().Value = (const char*)ptr;
|
|
}
|
|
|
|
props= props->next;
|
|
}
|
|
|
|
// associate.
|
|
_StyleMap[styleId]= newStyle;
|
|
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceParser::parseLUAScript (xmlNodePtr cur)
|
|
{
|
|
// read fileName
|
|
CXMLAutoPtr prop;
|
|
string fileName;
|
|
prop = xmlGetProp (cur, (xmlChar*)"file");
|
|
if(prop)
|
|
fileName= (const char*)prop;
|
|
else
|
|
{
|
|
nlwarning("'file' not found in 'lua'");
|
|
return false;
|
|
}
|
|
|
|
// Append to set of reloadable FileScripts
|
|
_LuaFileScripts.insert(fileName);
|
|
|
|
// just display warning here.
|
|
string dummyError;
|
|
return loadLUA(fileName, dummyError);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceParser::solveStyle(xmlNodePtr cur)
|
|
{
|
|
CXMLAutoPtr ptr;
|
|
|
|
// if the node is a style, abort (not recrusive because use "style" as param name)
|
|
if ( !strcmp((char*)cur->name,"style") )
|
|
return true;
|
|
|
|
// try to read a "style" param.
|
|
ptr= (char*)xmlGetProp( cur, (xmlChar*)"style");
|
|
if(ptr)
|
|
{
|
|
// get the style
|
|
TStyleMap::iterator it= _StyleMap.find((const char*)ptr);
|
|
if( it==_StyleMap.end() )
|
|
{
|
|
// todo hulud interface syntax error
|
|
nlwarning("style '%s' not found", (const char*)ptr);
|
|
return false;
|
|
}
|
|
|
|
// the style
|
|
CStyle &style= it->second;
|
|
|
|
// for all properties of the style, set them in the node
|
|
for(uint i=0;i<style.Properties.size();i++)
|
|
{
|
|
const char *propName= style.Properties[i].Name.c_str();
|
|
const char *propValue= style.Properties[i].Value.c_str();
|
|
|
|
// replace it only if the property is not already defined, (=> user can overide style properties)
|
|
CXMLAutoPtr ptr2(xmlGetProp( cur, (xmlChar*)propName));
|
|
if( !ptr2 )
|
|
{
|
|
xmlSetProp(cur, (xmlChar*)propName, (xmlChar*)propValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
// recurs to node children
|
|
cur= cur->children;
|
|
while(cur)
|
|
{
|
|
if(!solveStyle(cur))
|
|
return false;
|
|
cur= cur->next;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
#ifdef LUA_NEVRAX_VERSION
|
|
|
|
class CLuaDebugBreakScreen : public IDebuggedAppMainLoop
|
|
{
|
|
public:
|
|
// called by external lua debugger when application is breaked
|
|
virtual void breakEventLoop()
|
|
{
|
|
Driver->clearBuffers(CRGBA(90, 90, 90));
|
|
TextContext->setShaded(true);
|
|
TextContext->setFontSize(40);
|
|
TextContext->setColor(CRGBA::White);
|
|
|
|
// TOP LEFT //
|
|
//----------//
|
|
TextContext->setHotSpot(NL3D::UTextContext::MiddleMiddle);
|
|
TextContext->printfAt(0.5f, 0.5f, "Break in LUA code");
|
|
Driver->swapBuffers();
|
|
}
|
|
};
|
|
static CLuaDebugBreakScreen LuaDebugBreakScreen;
|
|
|
|
#endif
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceParser::initLUA()
|
|
{
|
|
CLuaManager::enableLuaDebugging();
|
|
|
|
#ifdef LUA_NEVRAX_VERSION
|
|
extern ILuaIDEInterface *LuaDebuggerIDE;
|
|
if (LuaDebuggerIDE) LuaDebuggerIDE->setDebuggedAppMainLoop(&LuaDebugBreakScreen);
|
|
#endif
|
|
|
|
// register LUA methods
|
|
CLuaIHM::registerAll( *( CLuaManager::getInstance().getLuaState() ) );
|
|
luaInitialized = true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceParser::uninitLUA()
|
|
{
|
|
_LuaFileScripts.clear();
|
|
CLuaManager::getInstance().ResetLuaState();
|
|
luaInitialized = false;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceParser::loadLUA(const std::string &fileName, std::string &error)
|
|
{
|
|
// get file
|
|
|
|
bool needCheck = false;
|
|
|
|
#if !FINAL_VERSION
|
|
needCheck = false;
|
|
#endif
|
|
|
|
string pathName= CPath::lookup(fileName, false);
|
|
if(pathName.empty())
|
|
{
|
|
nlwarning("LUA Script '%s' not found", fileName.c_str());
|
|
return false;
|
|
}
|
|
|
|
bool isInData = false;
|
|
std::string::size_type pos = pathName.find("@");
|
|
if (pos != string::npos)
|
|
{
|
|
if (CBigFile::getInstance().getBigFileName(pathName.substr(0, pos)) != "data/"+pathName.substr(0, pos))
|
|
isInData = false;
|
|
else
|
|
isInData = true;
|
|
}
|
|
|
|
if (needCheck && !isInData)
|
|
{
|
|
nlwarning("You are not allowed to modify the lua files");
|
|
// return true so it'll not generate a message box, we just ignore the file
|
|
return true;
|
|
}
|
|
|
|
// Parse script
|
|
try
|
|
{
|
|
CLuaManager::getInstance().getLuaState()->executeFile(pathName);
|
|
}
|
|
catch(const ELuaError &e)
|
|
{
|
|
nlwarning(e.luaWhat().c_str());
|
|
error= e.luaWhat();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CInterfaceParser::reloadAllLuaFileScripts()
|
|
{
|
|
std::set< std::string >::const_iterator it;
|
|
for( it = _LuaFileScripts.begin(); it != _LuaFileScripts.end(); ++it )
|
|
{
|
|
std::string error;
|
|
// if fail to reload a script, display the error code
|
|
if( !loadLUA( *it, error ) )
|
|
{
|
|
nlwarning( LuaHelperStuff::formatLuaErrorSysInfo( error ).c_str() );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CInterfaceParser::hasProc( const std::string &name ) const
|
|
{
|
|
TProcedureMap::const_iterator itr
|
|
= _ProcedureMap.find( name );
|
|
if( itr != _ProcedureMap.end() )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
bool CInterfaceParser::addProc( const std::string &name )
|
|
{
|
|
if( hasProc( name ) )
|
|
return false;
|
|
|
|
_ProcedureMap[ name ] = CProcedure();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CInterfaceParser::removeProc( const std::string &name )
|
|
{
|
|
TProcedureMap::iterator itr =
|
|
_ProcedureMap.find( name );
|
|
if( itr == _ProcedureMap.end() )
|
|
return false;
|
|
|
|
_ProcedureMap.erase( itr );
|
|
return true;
|
|
}
|
|
|
|
uint32 CInterfaceParser::addLinkData( SLinkData &linkData )
|
|
{
|
|
linkData.id = ++linkId;
|
|
links[ linkData.id ] = linkData;
|
|
return linkId;
|
|
}
|
|
|
|
void CInterfaceParser::removeLinkData( uint32 id )
|
|
{
|
|
std::map< uint32, SLinkData >::iterator itr =
|
|
links.find( id );
|
|
if( itr == links.end() )
|
|
return;
|
|
|
|
links.erase( itr );
|
|
}
|
|
|
|
bool CInterfaceParser::getLinkData( uint32 id, SLinkData &linkData )
|
|
{
|
|
std::map< uint32, SLinkData >::iterator itr =
|
|
links.find( id );
|
|
if( itr == links.end() )
|
|
return false;
|
|
|
|
linkData = itr->second;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CInterfaceParser::updateLinkData( uint32 id, const SLinkData &linkData )
|
|
{
|
|
std::map< uint32, SLinkData >::iterator itr =
|
|
links.find( id );
|
|
if( itr == links.end() )
|
|
return;
|
|
itr->second = linkData;
|
|
}
|
|
|
|
void CInterfaceParser::setVariable( const VariableData &v )
|
|
{
|
|
CInterfaceProperty prop;
|
|
const std::string &type = v.type;
|
|
const std::string &value = v.value;
|
|
const std::string &entry = v.entry;
|
|
|
|
if( type == "sint64" )
|
|
prop.readSInt64( value.c_str(), entry );
|
|
else
|
|
if( type == "sint32" )
|
|
prop.readSInt32( value.c_str(), entry );
|
|
else
|
|
if( type == "float" || type == "double" )
|
|
prop.readDouble( value.c_str(), entry );
|
|
else
|
|
if( type == "bool" )
|
|
prop.readBool( value.c_str(), entry );
|
|
else
|
|
if( type == "rgba" )
|
|
prop.readRGBA( value.c_str(), entry );
|
|
else
|
|
if( type == "hotspot" )
|
|
prop.readHotSpot( value.c_str(), entry );
|
|
|
|
variableCache[ entry ] = v;
|
|
}
|
|
|
|
|
|
bool CInterfaceParser::serializeVariables( xmlNodePtr parentNode ) const
|
|
{
|
|
if( parentNode == NULL )
|
|
return false;
|
|
|
|
xmlNodePtr node = NULL;
|
|
|
|
std::map< std::string, VariableData >::const_iterator itr;
|
|
for( itr = variableCache.begin(); itr != variableCache.end(); ++itr )
|
|
{
|
|
const VariableData &data = itr->second;
|
|
|
|
node = xmlNewNode( NULL, BAD_CAST "variable" );
|
|
if( node == NULL )
|
|
return false;
|
|
|
|
xmlAddChild( parentNode, node );
|
|
|
|
xmlSetProp( node, BAD_CAST "entry", BAD_CAST data.entry.c_str() );
|
|
xmlSetProp( node, BAD_CAST "type", BAD_CAST data.type.c_str() );
|
|
|
|
if( !data.value.empty() )
|
|
xmlSetProp( node, BAD_CAST "value", BAD_CAST data.value.c_str() );
|
|
|
|
if( data.size != 0 )
|
|
xmlSetProp( node, BAD_CAST "size", BAD_CAST toString( data.size ).c_str() );
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CInterfaceParser::serializeProcs( xmlNodePtr parentNode) const
|
|
{
|
|
if( parentNode == NULL )
|
|
return false;
|
|
|
|
xmlNodePtr procNode = NULL;
|
|
xmlNodePtr actionNode = NULL;
|
|
|
|
TProcedureMap::const_iterator itr;
|
|
for( itr = _ProcedureMap.begin(); itr != _ProcedureMap.end(); ++itr )
|
|
{
|
|
procNode = xmlNewNode( NULL, BAD_CAST "proc" );
|
|
if( procNode == NULL )
|
|
return false;
|
|
|
|
xmlAddChild( parentNode, procNode );
|
|
|
|
const CProcedure &proc = itr->second;
|
|
|
|
xmlSetProp( procNode, BAD_CAST "id", BAD_CAST itr->first.c_str() );
|
|
|
|
std::vector< CProcAction >::const_iterator itr2;
|
|
for( itr2 = proc.Actions.begin(); itr2 != proc.Actions.end(); ++itr2 )
|
|
{
|
|
actionNode = xmlNewNode( NULL, BAD_CAST "action" );
|
|
if( actionNode == NULL )
|
|
return false;
|
|
|
|
xmlAddChild( procNode, actionNode );
|
|
|
|
const CProcAction &action = *itr2;
|
|
|
|
xmlSetProp( actionNode, BAD_CAST "handler", BAD_CAST action.Action.c_str() );
|
|
|
|
if( !action.Parameters.empty() )
|
|
xmlSetProp( actionNode, BAD_CAST "params", BAD_CAST action.Parameters.c_str() );
|
|
|
|
if( !action.Conditions.empty() )
|
|
xmlSetProp( actionNode, BAD_CAST "cond", BAD_CAST action.Conditions.c_str() );
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CInterfaceParser::serializePointerSettings( xmlNodePtr parentNode ) const
|
|
{
|
|
if( parentNode == NULL )
|
|
return false;
|
|
|
|
xmlNodePtr node = xmlNewNode( NULL, BAD_CAST "view" );
|
|
if( node == NULL )
|
|
return false;
|
|
|
|
xmlAddChild( parentNode, node );
|
|
|
|
std::map< std::string, std::string >::const_iterator itr;
|
|
for( itr = pointerSettings.begin(); itr != pointerSettings.end(); ++itr )
|
|
{
|
|
const std::string &key = itr->first;
|
|
const std::string &value = itr->second;
|
|
|
|
xmlSetProp( node, BAD_CAST key.c_str(), BAD_CAST value.c_str() );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CInterfaceParser::serializeKeySettings( xmlNodePtr parentNode ) const
|
|
{
|
|
if( parentNode == NULL )
|
|
return false;
|
|
|
|
std::map< std::string, std::map< std::string, std::string > >::const_iterator itr;
|
|
for( itr = keySettings.begin(); itr != keySettings.end(); ++itr )
|
|
{
|
|
xmlNodePtr node = xmlNewNode( NULL, BAD_CAST "key" );
|
|
if( node == NULL )
|
|
return false;
|
|
|
|
xmlAddChild( parentNode, node );
|
|
xmlSetProp( node, BAD_CAST "name", BAD_CAST itr->first.c_str() );
|
|
|
|
const std::map< std::string, std::string > &settings = itr->second;
|
|
|
|
std::map< std::string, std::string >::const_iterator itr2;
|
|
for( itr2 = settings.begin(); itr2 != settings.end(); ++itr2 )
|
|
{
|
|
const std::string &key = itr2->first;
|
|
const std::string &value = itr2->second;
|
|
|
|
xmlSetProp( node, BAD_CAST key.c_str(), BAD_CAST value.c_str() );
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
CViewBase* CInterfaceParser::createClass( const std::string &name )
|
|
{
|
|
return NLMISC_GET_FACTORY( CViewBase, std::string ).createObject( std::string( name ) , CViewBase::TCtorParam() );
|
|
}
|
|
}
|
|
|