Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / gui / interface_parser.cpp
blobeab381d22ad4d617961abd331132c554d66e2b17
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2015 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stdpch.h"
23 #include <map>
24 #include "nel/misc/rgba.h"
25 #include "nel/gui/interface_parser.h"
26 #include "nel/misc/i_xml.h"
27 #include "nel/misc/file.h"
28 #include "nel/misc/algo.h"
29 #include "nel/misc/mem_stream.h"
30 #include "nel/misc/factory.h"
31 #include "nel/misc/big_file.h"
32 #include "nel/misc/xml_auto_ptr.h"
33 #include "nel/gui/interface_options.h"
34 #include "nel/gui/interface_anim.h"
35 #include "nel/gui/interface_expr.h"
36 #include "nel/gui/view_pointer.h"
37 #include "nel/gui/group_modal.h"
38 #include "nel/gui/group_list.h"
39 #include "nel/gui/group_container.h"
40 #include "nel/gui/interface_link.h"
41 #include "nel/gui/lua_helper.h"
42 #include "nel/gui/lua_ihm.h"
43 #include "nel/gui/lua_manager.h"
44 #include "nel/gui/root_group.h"
46 #ifdef LUA_NEVRAX_VERSION
47 #include "lua_ide_dll_nevrax/include/lua_ide_dll/ide_interface.h" // external debugger
48 #endif
50 #ifdef DEBUG_NEW
51 #define new DEBUG_NEW
52 #endif
54 const uint32 UI_CACHE_SERIAL_CHECK = NELID("IUG_");
56 using namespace NLMISC;
57 using namespace std;
59 namespace NLGUI
62 void saveXMLTree(COFile &f, xmlNodePtr node)
64 // save node name
65 std::string name = (const char *) node->name;
66 f.serial(name);
67 // save properties
68 uint32 numProp = 0;
69 xmlAttrPtr currProp = node->properties;
70 while (currProp)
72 ++ numProp;
73 currProp = currProp->next;
75 f.serial(numProp);
76 currProp = node->properties;
77 while (currProp)
79 std::string name = (const char *) currProp->name;
80 f.serial(name);
81 CXMLAutoPtr ptr(xmlGetProp(node, currProp->name));
82 std::string value = (const char *) ptr;
83 f.serial(value);
84 currProp = currProp->next;
86 uint32 numChildren = 0;
87 xmlNodePtr currChild = node->children;
88 while (currChild)
90 ++ numChildren;
91 currChild = currChild->next;
93 f.serial(numChildren);
94 currChild = node->children;
95 while (currChild)
97 saveXMLTree(f, currChild);
98 currChild = currChild->next;
102 xmlNodePtr buildTree(CIFile &f)
104 // load node name
105 std::string name;
106 f.serial(name);
107 xmlNodePtr node = xmlNewNode(NULL, (const xmlChar *) name.c_str());
108 // slod properties
109 uint32 numProp;
110 f.serial(numProp);
111 for(uint k = 0; k < numProp; ++k)
113 std::string name, value;
114 f.serial(name, value);
115 xmlSetProp(node, (const xmlChar *) name.c_str(), (const xmlChar *) value.c_str());
117 uint32 numChildren;
118 f.serial(numChildren);
119 for(uint k = 0; k < numChildren; ++k)
121 xmlAddChild(node, buildTree(f));
123 return node;
126 // ----------------------------------------------------------------------------
127 // CInterfaceParser
128 // ----------------------------------------------------------------------------
130 // ----------------------------------------------------------------------------
131 CInterfaceParser::CInterfaceParser()
133 luaInitialized = false;
134 cacheUIParsing = false;
135 linkId = 0;
136 editorMode = false;
137 setupCallback = NULL;
140 CInterfaceParser::~CInterfaceParser()
142 _ParentPositionsMap.clear();
143 _ParentSizesMap.clear();
144 _ParentSizesMaxMap.clear();
145 _LuaClassAssociation.clear();
146 _Templates.clear();
147 removeAllModules();
148 setupCallback = NULL;
150 /** Convert a string into a memstream
152 static void interfaceScriptAsMemStream(const std::string &script, CMemStream &destStream)
154 NLMISC::contReset(destStream);
155 if (destStream.isReading()) // we must be sure that we are reading the stream
157 destStream.invert();
159 destStream.seek(0, NLMISC::IStream::begin);
160 if (script.empty()) return;
161 destStream.serialBuffer(const_cast<uint8 *>((const uint8 *) &script[0]), (uint)script.size());
162 destStream.invert();
163 destStream.seek(0, NLMISC::IStream::begin);
166 std::string CInterfaceParser::lookup( const std::string &file )
168 std::string filename;
170 if( editorMode && !_WorkDir.empty() )
172 std::string wdpath = CPath::standardizePath( _WorkDir ) + file;
173 if( CFile::fileExists( wdpath ) )
174 filename = wdpath;
176 if( filename.empty() )
177 filename = CPath::lookup( file );
179 return filename;
182 // ----------------------------------------------------------------------------
183 bool CInterfaceParser::parseInterface (const std::vector<std::string> & strings, bool reload, bool isFilename, bool checkInData)
185 bool ok;
187 bool needCheck = false;
189 #if !FINAL_VERSION
190 needCheck = false;
191 #endif
193 // TestYoyo. UnHide For Parsing Profile
195 NLMISC::CHTimer::startBench();
198 H_AUTO(parseInterface);
201 //ignore the content of tags containing only white space
202 xmlKeepBlanksDefault(0);
203 //parse all interface files and build a single xml document
204 xmlNodePtr globalEnclosing;
205 nlassert (!strings.empty());
206 CIXml read;
207 string nextFileName;
208 static const char *SCRIPT_AS_STRING = "<script as string>";
211 CIFile file;
212 CMemStream scriptStream;
213 string firstFileName;
214 vector<string>::const_iterator it = strings.begin();
215 if (isFilename)
217 //get the first file document pointer
218 firstFileName = *it;
219 string filename = lookup( firstFileName );
220 bool isInData = false;
221 string::size_type pos = filename.find ("@");
222 if (pos != string::npos)
224 vector<string> bigFilePaths;
225 CBigFile::getInstance().getBigFilePaths(bigFilePaths);
226 if (CBigFile::getInstance().getBigFileName(filename.substr(0, pos)) != "data/"+filename.substr(0, pos))
227 isInData = false;
228 else
229 isInData = true;
232 if ((needCheck && !isInData) || !file.open (lookup(firstFileName)))
234 // todo hulud interface syntax error
235 nlwarning ("could not open file %s, skipping xml parsing",firstFileName.c_str());
236 return false;
238 read.init (file);
240 else
242 firstFileName = SCRIPT_AS_STRING; // for error msg
243 interfaceScriptAsMemStream(*it, scriptStream);
244 read.init(scriptStream);
246 //get the enclosing element (<interface config>)
247 globalEnclosing = read.getRootNode();
248 if (!globalEnclosing)
250 // todo hulud interface syntax error
251 nlwarning ("no root element in xml file %s, skipping xml parsing",firstFileName.c_str());
252 return false;
254 if (strcmp( (char*)globalEnclosing->name,"interface_config") )
256 // todo hulud interface syntax error
257 nlwarning ("wrong root element in xml file %s, skipping xml parsing",firstFileName.c_str());
258 return false;
260 if (isFilename)
262 file.close();
265 // Get all other xml files, and add their nodes to the first xml document
266 it++;
267 uint32 i = 0;
268 for (; it != strings.end(); it++)
270 //nlwarning("Parsing interface file : %s", it->c_str());
271 nextFileName = *it;
272 CIXml nextRead;
273 xmlNodePtr cur = NULL;
274 bool saveParseResult = false;
275 bool readFromUncompressedXML = true;
276 if( isFilename && cacheUIParsing )
278 saveParseResult = true;
279 std::string archive = CPath::lookup(nextFileName + "_compressed", false, false);
280 std::string current = lookup(nextFileName);
281 if (!archive.empty() && !current.empty())
283 if (CFile::getFileModificationDate(current) <= CFile::getFileModificationDate(archive))
285 CIFile input;
286 input.open(archive);
287 input.serialCheck(UI_CACHE_SERIAL_CHECK);
288 input.serialVersion(0);
289 cur = buildTree(input);
290 input.serialCheck(UI_CACHE_SERIAL_CHECK);
291 readFromUncompressedXML = false;
292 saveParseResult = false;
296 if (!cur)
298 if (isFilename)
300 if (!file.open(lookup(nextFileName)))
302 // todo hulud interface syntax error
303 nlwarning ("could not open file %s, skipping xml parsing",nextFileName.c_str());
304 return false;
306 nextRead.init (file);
308 else
310 interfaceScriptAsMemStream(nextFileName, scriptStream);
311 nextFileName = SCRIPT_AS_STRING; // for error MSG
312 read.init(scriptStream);
314 cur = nextRead.getRootNode();
315 if (!cur)
317 // todo hulud interface syntax error
318 nlwarning ("no root element in xml file %s, skipping xml parsing", it->c_str() );
319 return false;
322 if (saveParseResult)
324 nlassert(isFilename);
325 std::string outputFilename = CPath::standardizePath("data") + CFile::getFilename(nextFileName) + std::string("_compressed");
326 COFile f;
327 f.open(outputFilename);
328 f.serialCheck(UI_CACHE_SERIAL_CHECK);
329 f.serialVersion(0);
330 saveXMLTree(f, cur);
331 f.serialCheck(UI_CACHE_SERIAL_CHECK);
333 if (strcmp( (char*)cur->name,"interface_config") )
335 // todo hulud interface syntax error
336 nlwarning ("wrong root element in xml file %s. should be interface config, skipping xml parsing", nextFileName.c_str());
337 return false;
339 xmlNodePtr curSon = cur->children;
340 while (curSon)
342 xmlNodePtr bufNode = xmlCopyNode (curSon, 1);
343 xmlAddChild (globalEnclosing,bufNode);
344 curSon = curSon->next;
346 if (!readFromUncompressedXML)
348 freeXMLNodeAndSibblings(cur);
350 if (isFilename)
352 file.close();
354 i++;
357 catch (const Exception &e)
359 // Output error
360 // todo hulud interface syntax error
361 nlwarning ("CInterfaceParser: Error while loading the xml interface file %s, skipping xml parsing : %s", nextFileName.c_str(), e.what());
362 if (testWildCard(nextFileName, "save/keys_?*.xml"))
364 // if file matches 'save/keys_?*.xml', move this file as a backup
365 string backup = nextFileName+".backup";
366 if (CFile::fileExists(backup))
367 CFile::deleteFile(backup);
368 CFile::moveFile(backup, nextFileName);
370 return false;
372 //parse the built doc
373 ok = parseXMLDocument(globalEnclosing, reload);
374 // freeXMLNodeAndSibblings(globalEnclosing); // Done by the ~CIXml
377 // TestYoyo. UnHide for Parsing Profile
380 NLMISC::CHTimer::endBench();
381 // Display and save profile to a File.
382 CLog log;
383 CFileDisplayer fileDisplayer(NLMISC::CFile::findNewFile(getLogDirectory() + "profile_parseInterface.log"));
384 log.addDisplayer(&fileDisplayer);
385 // diplay
386 NLMISC::CHTimer::displayHierarchicalByExecutionPathSorted(&log, CHTimer::TotalTime, true, 48, 2);
387 NLMISC::CHTimer::display(&log, CHTimer::TotalTime);
390 if( ok )
392 if( CWidgetManager::getInstance()->getPointer() == NULL )
394 CViewPointer *pointer = dynamic_cast< CViewPointer* >( NLMISC_GET_FACTORY(CViewBase, std::string).createObject( "generic_pointer", CViewBase::TCtorParam() ) );
395 CWidgetManager::getInstance()->setPointer( pointer );
400 return ok;
404 // ----------------------------------------------------------------------------
405 bool CInterfaceParser::parseXMLDocument(xmlNodePtr root, bool reload)
408 CWidgetManager::SMasterGroup *curRoot = NULL;
409 CInterfaceGroup *rootGroup = NULL;
410 //parse templates
411 xmlNodePtr curNode = root->children;
413 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
415 while (curNode)
417 // first solve define for the xml node and his sons
418 if(!solveDefine(curNode))
420 // todo hulud interface syntax error
421 nlwarning ("could not read all define");
423 // then try to solve Style for the xml node and his sons
424 else if (!solveStyle(curNode))
426 // todo hulud interface syntax error
427 nlwarning ("could not read all styles");
429 if( !strcmp((char*)curNode->name,"key" ) && editorMode )
431 saveKeySettings( curNode );
433 // If define and style oks, try to parse "1st pass" objets (define, options....).
434 else if ( !strcmp((char*)curNode->name,"template") )
436 // Check there is a valid name for this template
437 CXMLAutoPtr ptr((const char*) xmlGetProp( curNode, (xmlChar*)"name" ));
438 if (ptr)
440 // remove any template with the same name in the list (useful when using 'loadui' command)
441 for(uint k = 0; k < _Templates.size(); ++k)
443 CXMLAutoPtr otherTemplName((const char*) xmlGetProp( _Templates[k], (xmlChar*)"name" ));
444 if (strcmp((const char *) otherTemplName, (const char *) ptr) == 0)
446 nlwarning("Replacing template %s with new version", (const char *) ptr);
447 xmlFreeNode(_Templates[k]);
448 _Templates[k] = NULL;
451 _Templates.erase(std::remove(_Templates.begin(), _Templates.end(), (xmlNodePtr) NULL), _Templates.end());
452 _Templates.push_back(curNode);
454 else
455 // todo hulud interface syntax error
456 nlwarning ("no name in a template node");
458 else if ( !strcmp((char*)curNode->name,"options") )
460 if (!parseOptions(curNode,rootGroup))
461 // todo hulud interface syntax error
462 nlwarning ("could not parse options");
464 else if ( !strcmp((char*)curNode->name,"define") )
466 if (!parseDefine(curNode))
467 // todo hulud interface syntax error
468 nlwarning ("could not parse define");
470 else if ( !strcmp((char*)curNode->name,"style") )
472 if (!parseStyle(curNode))
473 // todo hulud interface syntax error
474 nlwarning ("could not parse 'style'");
476 else
478 IParserModule *module = getModuleFor( (char*)( curNode->name ) );
479 if( module != NULL ){
480 if( module->canParseInStage( IParserModule::Unresolved ) )
481 module->parse( curNode, rootGroup );
485 curNode = curNode->next;
489 if (!reload) // TMP : crahs when doing the setup twice (old pointer on the text manager ...)
491 setupOptions();
495 //parse filters , groups and eventually instances
496 // vector that are on top of the xml hierarchy
497 root = root->children;
498 while (root)
500 if ( !strcmp((char*)root->name,"root") )
502 CXMLAutoPtr ptr((const char*)xmlGetProp (root, (xmlChar*)"id"));
503 if (ptr)
505 rootGroup = CWidgetManager::getInstance()->getMasterGroupFromId (string("ui:") + (const char*)ptr);
506 if (rootGroup == NULL)
508 rootGroup = (CInterfaceGroup*)(new CRootGroup(CViewBase::TCtorParam()));
509 rootGroup->parse (root, NULL);
510 CWidgetManager::SMasterGroup mg;
511 mg.Group = rootGroup;
512 _MasterGroups.push_back (mg);
514 for (uint32 i = 0; i < _MasterGroups.size(); ++i)
515 if (_MasterGroups[i].Group == rootGroup)
516 curRoot = &_MasterGroups[i];
518 else
520 // todo hulud interface syntax error
521 nlwarning ("could not parse root");
524 else if (!strcmp((char*)root->name,"group"))
526 if (!parseGroup(root,rootGroup, reload))
527 // todo hulud interface syntax error
528 nlwarning ("could not parse group");
530 else if (!strcmp((char*)root->name,"instance"))
532 if (!parseInstance(root))
533 // todo hulud interface syntax error
534 nlwarning ("could not parse instance");
536 else if (!strcmp((char*)root->name,"view"))
538 if (!parseView(root,rootGroup, reload))
539 // todo hulud interface syntax error
540 nlwarning ("could not parse view");
542 else if (!strcmp((char*)root->name,"ctrl"))
544 if (!parseControl(root,rootGroup, reload))
545 // todo hulud interface syntax error
546 nlwarning ("could not parse control");
548 else if ( !strcmp((char*)root->name,"vector") )
550 if (!parseVector(root))
551 // todo hulud interface syntax error
552 nlwarning ("could not parse vector");
554 else if ( !strcmp((char*)root->name,"link") )
556 if (!parseLink(root,rootGroup))
557 // todo hulud interface syntax error
558 nlwarning ("could not parse link");
560 else if ( !strcmp((char*)root->name,"variable") )
562 if (!parseVariable(root,rootGroup))
563 // todo hulud interface syntax error
564 nlwarning ("could not parse variable");
566 else if ( !strcmp((char*)root->name,"tree") )
568 if (!parseTree(root,curRoot))
569 // todo hulud interface syntax error
570 nlwarning ("could not parse tree");
571 /* if (!setupTree(root,curRoot))
572 nlwarning ("could not setup tree"); */
574 else if ( !strcmp((char*)root->name,"proc") )
576 if (!parseProcedure(root, reload))
577 // todo hulud interface syntax error
578 nlwarning ("could not parse procedure");
580 else if ( !strcmp((char*)root->name,"sheet_selection") )
582 if (!parseSheetSelection(root))
583 // todo hulud interface syntax error
584 nlwarning ("could not parse sheet selection");
586 else if ( !strcmp((char*)root->name,"anim") )
588 if (!parseAnim(root,rootGroup))
589 // todo hulud interface syntax error
590 nlwarning ("could not parse 'anim'");
592 else if ( !strcmp((char*)root->name,"lua") )
594 if(!parseLUAScript(root))
596 nlerror ("could not parse 'lua'");
599 else
601 IParserModule *module = getModuleFor( (char*)( root->name ) );
602 if( module != NULL )
604 if( module->canParseInStage( IParserModule::Resolved ) )
605 module->parse( root, rootGroup );
609 root = root->next;
612 // add all modals group to the window list
613 for (uint32 i = 0; i < _MasterGroups.size(); ++i)
616 CWidgetManager::SMasterGroup &rMG = _MasterGroups[i];
617 // insert all modals
618 for (uint32 j = 0; j < rMG.Group->getGroups().size(); ++j)
620 CGroupModal *pIG = dynamic_cast<CGroupModal*>(rMG.Group->getGroups()[j]);
621 // if it is a modal group
622 if(pIG)
624 // add to the window list
625 CWidgetManager::getInstance()->addWindowToMasterGroup(rMG.Group->getId(), pIG);
630 // init all the elements coords, and Lua Script
631 if (!initCoordsAndLuaScript())
632 return false;
634 std::vector<xmlNodePtr> keptTemplates;
636 // keep template that have the "keep" flag if we are not reloading
637 // if reloading, always keep the template
639 CXMLAutoPtr ptr;
640 for(uint k = 0; k < _Templates.size(); ++k)
642 CXMLAutoPtr ptr(xmlGetProp(_Templates[k], (const xmlChar *) "keep"));
643 if (reload || (ptr && nlstricmp((const char *) ptr, "true") == 0))
645 // xmlUnsetProp(_Templates[k], (const xmlChar *) "keep");
646 xmlNodePtr copy = xmlCopyNode(_Templates[k], 1);
647 if (copy)
648 keptTemplates.push_back(copy);
651 // free the original node, whether we kept a copy or not
652 xmlUnlinkNode( _Templates[k] );
653 xmlFreeNode( _Templates[k] );
654 _Templates[k] = NULL;
656 // keep new list
657 _Templates.swap(keptTemplates);
659 return true;
662 // ----------------------------------------------------------------------------
663 bool CInterfaceParser::parseTemplateNode(xmlNodePtr node,xmlNodePtr instance,xmlNodePtr templ)
665 CXMLAutoPtr ptr;
666 //get the node properties
667 xmlAttrPtr props = node->properties;
668 while (props)
670 //get the property value
671 ptr = (char*)xmlGetProp( node, props->name);
672 nlassert(ptr);
673 //if it begins with a #, it is a reference in the instance attribute
674 if (strchr(ptr, '#') != NULL)
676 string LastProp = ptr.str();
677 string NewProp;
678 string RepProp;
680 while (!LastProp.empty())
682 string::size_type diesPos = LastProp.find("#");
683 if (diesPos != string::npos)
685 if (diesPos > 0)
687 NewProp += LastProp.substr(0, LastProp.find("#"));
688 LastProp = LastProp.substr(LastProp.find("#"),LastProp.size());
691 CXMLAutoPtr instanceProp;
692 for (uint32 i = 0; i < LastProp.size(); ++i)
694 RepProp = LastProp.substr(0, LastProp.size()-i);
695 instanceProp = xmlGetProp (instance , (const xmlChar*)(RepProp.c_str() + 1));
696 if (instanceProp)
697 break;
698 instanceProp = xmlGetProp (templ , (const xmlChar*)(RepProp.c_str() + 1));
699 if (instanceProp)
700 break;
702 if (!instanceProp)
704 CXMLAutoPtr ptr2((const char*)xmlGetProp( instance, (xmlChar*)"id"));
705 string sTmp;
706 if (ptr2.getDatas() != NULL)
707 sTmp = string("cannot parse template node property: ") + ((const char *) ptr + 1) + string(" in instance : ") + string((const char*)ptr2);
708 else
709 sTmp = string("cannot parse template node property: ") + ((const char *) ptr + 1) + string(" in instance : NULL");
710 // todo hulud interface syntax error
711 nlinfo(sTmp.c_str());
713 return false;
715 NewProp += string((const char*)instanceProp);
716 LastProp = LastProp.substr (RepProp.size(), LastProp.size());
718 else
720 NewProp += LastProp;
721 LastProp.clear();
724 xmlSetProp(node,props->name, (const xmlChar*)NewProp.c_str());
726 props = props->next;
728 //parse the node children
729 node = node->children;
730 while (node)
732 if (!parseTemplateNode(node,instance,templ))
733 return false;
734 node = node->next;
736 return true;
739 // ----------------------------------------------------------------------------
740 bool CInterfaceParser::parseInstance(xmlNodePtr cur)
742 CXMLAutoPtr ptr;
744 //try to find the instance template in our template vector. If the template doesn't exist, return false
745 CXMLAutoPtr templ((const char*) xmlGetProp( cur, (xmlChar*)"template" ));
746 if (!templ)
748 // todo hulud interface syntax error
749 nlinfo("parse error : no referenced template in an instance");
750 return false;
752 vector<xmlNodePtr>::const_iterator it;
753 for (it = _Templates.begin(); it != _Templates.end();it++)
755 ptr = (char*) xmlGetProp( *it, (xmlChar*)"name" );
756 if (!ptr)
758 // todo hulud interface syntax error
759 nlinfo("no name in a template node");
760 return false;
762 if ( !strcmp(templ,ptr) )
764 break;
767 if ( it == _Templates.end() )
769 // todo hulud interface syntax error
770 nlinfo("the template %s was not found", (const char*)templ);
771 return false;
774 xmlNodePtr templNode = *it;
775 //for each child of the template, create the appropriate node
776 xmlNodePtr child = (*it)->children;
777 xmlNodePtr nextSibling=cur;
778 while (child)
780 //copy the template child node
781 xmlNodePtr node = xmlCopyNode (child, 1);
783 //add it to our tree
784 //node = xmlAddChild(cur->parent,node);
785 node = xmlAddNextSibling (nextSibling, node);
786 nextSibling = nextSibling->next;
788 //parse the child
789 if (!parseTemplateNode(node, cur, templNode))
790 return false;
791 child = child->next;
793 return true;
796 // ----------------------------------------------------------------------------
797 bool CInterfaceParser::parseVector(xmlNodePtr cur)
799 //get the number of elements
800 CXMLAutoPtr cSize((const char*) xmlGetProp( cur, (xmlChar*)"_size" ));
801 if (!cSize)
803 // todo hulud interface syntax error
804 nlinfo("no _size in a vector");
805 return false;
807 sint32 size;
808 fromString(cSize.str(), size);
809 if (size <= 0)
811 // todo hulud interface syntax error
812 nlinfo("size<0");
813 return false;
816 // Vector of groups
817 bool bGroupVector = true;
819 //get the first position reference
820 CXMLAutoPtr firstpos((const char*) xmlGetProp( cur, (xmlChar*)"_firstpos" ));
821 if (!firstpos)
823 bGroupVector = false;
825 //get the next position reference
826 CXMLAutoPtr nextpos((const char*) xmlGetProp( cur, (xmlChar*)"_nextpos" ));
827 if (!nextpos)
829 bGroupVector = false;
832 sint32 index = 0;
833 //get the first index value
834 CXMLAutoPtr indexChar((const char*) xmlGetProp( cur, (xmlChar*)"_firstindex" ));
835 if (indexChar)
837 fromString((const char*)indexChar, index);
840 sint32 step = 1;
841 //get the step for the indices
842 CXMLAutoPtr stepChar((const char*) xmlGetProp( cur, (xmlChar*)"_step" ));
843 if (stepChar)
845 fromString((const char*)stepChar, step);
849 //get the x and y of the first element
850 CXMLAutoPtr xfirst((const char*) xmlGetProp( cur, (xmlChar*)"_xfirst" ));
851 CXMLAutoPtr yfirst((const char*) xmlGetProp( cur, (xmlChar*)"_yfirst" ));
853 xmlNodePtr node;
854 CXMLAutoPtr id;
855 xmlNodePtr nextSibling= cur;
856 //now we can add all the following elements
857 sint32 i;
858 for (i = index;; i += step)
860 if (step > 0)
862 if (i >= index + size) break;
864 else
866 if (i <= index - size) break;
868 //copy the node
869 node = xmlCopyNode(cur,1);
870 //set the name and posref
872 if (bGroupVector)
874 if (i==index)
876 xmlSetProp(node,(xmlChar*)"posref",(const xmlChar*)firstpos);
877 if (xfirst)
879 xmlSetProp(node,(xmlChar*)"x",(const xmlChar*)xfirst);
881 if (yfirst)
883 xmlSetProp(node,(xmlChar*)"y",(const xmlChar*)yfirst);
886 else
888 xmlSetProp(node,(xmlChar*)"posref",(const xmlChar*)nextpos);
889 xmlSetProp(node,(xmlChar*)"posparent",(const xmlChar*)id);
893 xmlNodeSetName(node,(xmlChar*)"instance");
895 //replace all the $i
896 xmlAttrPtr attr = node->properties;
897 while(attr)
899 CXMLAutoPtr prop((const char*) xmlGetProp( node, attr->name ));
900 string str((const char*)prop);
901 string::size_type pos = str.find("$i");
902 while (pos != string::npos)
904 str.replace(pos,2,toString(i));
905 pos = str.find("$i",pos);
907 xmlSetProp(node,attr->name,(xmlChar*)str.c_str());
908 attr = attr->next;
911 //add the new instance to our tree, just near us.
912 xmlAddNextSibling (nextSibling, node);
913 nextSibling= node;
915 //get the node id, used in the next iteration
916 if (bGroupVector)
918 id = (char*) xmlGetProp( node, (xmlChar*)"id" );
919 if (!id)
921 // todo hulud interface syntax error
922 nlinfo("no id in a vector");
923 break;
928 return step > 0 ? (i == index + size) : (i == index - size);
931 // ----------------------------------------------------------------------------
932 bool CInterfaceParser::parseLink(xmlNodePtr cur, CInterfaceGroup * parentGroup)
934 CXMLAutoPtr ptr((const char*) xmlGetProp (cur, (xmlChar*)"expr"));
935 if (!ptr)
937 // todo hulud interface syntax error
938 nlwarning("<CInterfaceParser::parseLink> Can't read the expression for a link node");
939 return false;
941 std::string expr = ptr.str();
944 std::vector<CInterfaceLink::CTargetInfo> targets;
945 std::vector<CInterfaceLink::CCDBTargetInfo> cdbTargets;
947 ptr = (char*) xmlGetProp (cur, (xmlChar*)"target");
948 std::string target;
949 if( ptr )
951 target = std::string( (const char*)ptr );
952 if( !editorMode )
953 CInterfaceLink::splitLinkTargetsExt(std::string((const char*)ptr), parentGroup, targets, cdbTargets);
956 // optional action handler
957 std::string action;
958 std::string params;
959 std::string cond;
960 ptr = (char*) xmlGetProp (cur, (xmlChar*)"action");
961 if (ptr) action = (const char *) ptr;
962 ptr = (char*) xmlGetProp (cur, (xmlChar*)"params");
963 if (ptr) params = (const char *) ptr;
964 ptr = (char*) xmlGetProp (cur, (xmlChar*)"cond");
965 if (ptr) cond = (const char *) ptr;
967 // create the link
968 if( !editorMode )
970 CInterfaceLink *il = new CInterfaceLink;
971 il->init(targets, cdbTargets, expr, action, params, cond, parentGroup); // init will add 'il' in the list of link present in 'elm'
973 else
975 SLinkData linkData;
976 linkData.parent = parentGroup->getId();
977 linkData.expr = expr;
978 linkData.target = target;
979 linkData.action = action;
980 linkData.cond = cond;
981 linkData.params = params;
983 addLinkData( linkData );
986 return true;
989 // ----------------------------------------------------------------------------
990 bool CInterfaceParser::parseVariable (xmlNodePtr cur, CInterfaceGroup * /* parentGroup */)
992 //get the args
993 CXMLAutoPtr ptr((const char*) xmlGetProp (cur, (xmlChar*)"entry"));
994 if (!ptr)
996 // todo hulud interface syntax error
997 nlinfo ("no entry in a variable tag");
998 return false;
1000 string entry((const char*)ptr);
1002 ptr = (char*) xmlGetProp (cur, (xmlChar*)"type");
1003 if (!ptr)
1005 // todo hulud interface syntax error
1006 nlinfo ("no type in a variable tag");
1007 return false;
1009 string type((const char*)ptr);
1011 string value;
1012 ptr = (char*) xmlGetProp (cur, (xmlChar*)"value");
1013 if (!ptr)
1015 //if no value is specified, try to get the db entry directly
1016 value = entry;
1018 else
1020 value = string((const char*)ptr);
1023 // Array definition
1024 sint size= 1;
1025 bool ArrayMode= false;
1026 string entryPrefix;
1027 string entrySuffix;
1028 ptr = (char*) xmlGetProp (cur, (xmlChar*)"size");
1029 if (ptr)
1031 ArrayMode= true;
1032 fromString((const char*)ptr, size);
1034 string::size_type pos= entry.find("$i");
1035 if( pos==string::npos )
1037 // todo hulud interface syntax error
1038 nlinfo ("no $i found in a 'variable' tag with 'size' defined ");
1039 return false;
1041 else
1043 entryPrefix= entry.substr(0, pos);
1044 entrySuffix= entry.substr(pos+2);
1048 // loop all variables
1049 for(sint index= 0;index<size;index++)
1051 // If array variable, build the variable name
1052 if(ArrayMode)
1054 entry= entryPrefix + toString(index) + entrySuffix;
1057 // access the database
1058 CInterfaceProperty prop;
1060 if (type == "sint64")
1061 prop.readSInt64(value.c_str(),entry);
1062 else if (type == "sint32")
1063 prop.readSInt32(value.c_str(),entry);
1064 else if (type == "float" || type == "double")
1065 prop.readDouble(value.c_str(),entry);
1066 else if (type == "bool")
1067 prop.readBool(value.c_str(),entry);
1068 else if (type == "rgba")
1069 prop.readRGBA(value.c_str(),entry);
1070 else if (type == "hotspot")
1071 prop.readHotSpot(value.c_str(),entry);
1072 else if (type == "text")
1074 /*uint textId = addText(value);
1075 prop.readSInt32(toString(textId),entry);*/
1079 if( editorMode )
1081 VariableData data;
1083 ptr = xmlGetProp( cur, BAD_CAST "entry" );
1084 if( ptr )
1085 data.entry = std::string( (const char*)ptr );
1087 data.type = type;
1089 ptr = xmlGetProp( cur, BAD_CAST "value" );
1090 if( ptr )
1091 data.value = std::string( (const char*)ptr );
1093 ptr = xmlGetProp( cur, BAD_CAST "size" );
1094 if( ptr )
1095 fromString( std::string( (const char*)ptr ), data.size );
1097 variableCache[ data.entry ] = data;
1100 return true;
1103 // ----------------------------------------------------------------------------
1104 bool CInterfaceParser::parseOptions (xmlNodePtr cur, CInterfaceGroup * /* parentGroup */)
1106 // build the options from type
1107 CInterfaceOptions *options = NULL;
1108 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"type" ));
1109 if (ptr)
1111 options = NLMISC_GET_FACTORY( CInterfaceOptions, std::string ).createObject( std::string( (const char*)ptr ), CInterfaceOptions::TCtorParam() );
1113 if( options == NULL )
1114 options = new CInterfaceOptions( CInterfaceOptions::TCtorParam() );
1116 else
1118 options = new CInterfaceOptions( CInterfaceOptions::TCtorParam() );
1121 CWidgetManager *wm = CWidgetManager::getInstance();
1123 // get the name
1124 ptr = (char*) xmlGetProp( cur, (xmlChar*)"name" );
1125 if (!ptr)
1127 // todo hulud interface syntax error
1128 nlinfo ("options has no name");
1129 return false;
1131 string optionsName = ptr.str();
1133 // herit if possible
1134 ptr = (char*) xmlGetProp( cur, (xmlChar*)"herit" );
1135 if (ptr)
1137 string optionsParentName = ptr.str();
1138 CInterfaceOptions *io = wm->getOptions( optionsParentName );
1139 if( io != NULL )
1140 options->copyBasicMap( *io );
1143 // parse parameters
1144 if (options->parse (cur))
1146 // Remove old one
1147 wm->removeOptions( optionsName );
1148 wm->addOptions( optionsName, options );
1150 else
1152 delete options;
1153 return false;
1155 return true;
1158 // ----------------------------------------------------------------------------
1159 bool CInterfaceParser::parseGroup (xmlNodePtr cur, CInterfaceGroup * parentGroup, bool reload)
1161 CInterfaceGroup * group;
1162 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"type" ));
1163 if (ptr)
1165 group = dynamic_cast<CInterfaceGroup*>( NLMISC_GET_FACTORY(CViewBase, std::string).createObject(string((const char*)ptr), CViewBase::TCtorParam()) );
1166 if (group == NULL)
1168 group = dynamic_cast<CInterfaceGroup*>(NLMISC_GET_FACTORY(CViewBase, std::string).createObject("interface_group", CViewBase::TCtorParam()));
1172 else
1173 group = dynamic_cast<CInterfaceGroup*>(NLMISC_GET_FACTORY(CViewBase, std::string).createObject("interface_group", CViewBase::TCtorParam()));
1175 // parse the group attributes
1176 if (!group->parse(cur,parentGroup))
1178 delete group;
1179 // todo hulud interface syntax error
1180 nlwarning ("cannot parse group attributes");
1181 return false;
1184 if (parentGroup)
1186 CGroupList *pList = dynamic_cast<CGroupList*>(parentGroup);
1187 if (parentGroup->getElement(group->getId()) != NULL)
1189 // Remove old groupe and replace
1190 if (reload)
1192 // Remove from the parent
1193 parentGroup->delElement (group->getId(), true);
1195 else
1197 // todo hulud interface syntax error
1198 nlwarning ("id already exists for %s in %s", group->getId().c_str(), parentGroup->getId().c_str());
1199 delete group;
1200 return false;
1204 if (pList != NULL)
1205 pList->addChild (group);
1206 else
1207 parentGroup->addGroup (group);
1209 else
1211 // todo hulud interface syntax error
1212 nlinfo ("no parent for %s", group->getId().c_str());
1213 delete group;
1214 return false;
1217 //parse the children
1218 bool ok = parseGroupChildren(cur, group, reload);
1220 if (!ok)
1222 string tmp = "cannot parse group "+group->getId();
1223 // todo hulud interface syntax error
1224 nlinfo (tmp.c_str());
1226 return ok;
1229 // ----------------------------------------------------------------------------
1230 bool CInterfaceParser::parseGroupChildren(xmlNodePtr cur, CInterfaceGroup * parentGroup, bool reload)
1232 cur = cur->children;
1233 bool ok = true;
1234 while (cur)
1236 if ( !strcmp((char*)cur->name,"view") )
1237 ok = ok && parseView(cur,parentGroup, reload);
1238 else if ( !strcmp((char*)cur->name,"ctrl") )
1239 ok = ok && parseControl(cur,parentGroup, reload);
1240 else if ( !strcmp((char*)cur->name,"group") )
1241 ok = ok && parseGroup(cur,parentGroup, reload);
1242 else if ( !strcmp((char*)cur->name,"instance") )
1243 ok = ok && parseInstance(cur);
1244 else if ( !strcmp((char*)cur->name,"vector") )
1245 ok = ok && parseVector(cur);
1246 else if ( !strcmp((char*)cur->name,"link") )
1247 ok = ok && parseLink(cur,parentGroup);
1248 else
1250 IParserModule *module = getModuleFor( (char*)( cur->name ) );
1251 if( module != NULL )
1253 if( module->canParseInStage( IParserModule::GroupChildren ) )
1254 ok = ok && module->parse( cur, parentGroup );
1259 cur = cur->next;
1261 return ok;
1264 // ----------------------------------------------------------------------------
1265 bool CInterfaceParser::parseControl (xmlNodePtr cur, CInterfaceGroup * parentGroup, bool reload)
1267 CCtrlBase* ctrl = NULL;
1268 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"type" ));
1269 if (!ptr)
1271 // todo hulud interface syntax error
1272 nlinfo ("no type in a control tag");
1273 return false;
1276 ctrl = dynamic_cast<CCtrlBase*>(NLMISC_GET_FACTORY(CViewBase, std::string).createObject(string((const char*)ptr), CViewBase::TCtorParam()));
1278 if (ctrl)
1280 if (!ctrl->parse(cur,parentGroup))
1282 delete ctrl;
1283 return false;
1285 if (parentGroup->getElement(ctrl->getId()) != NULL)
1287 // Remove old groupe and replace
1288 if (reload)
1289 parentGroup->delElement (ctrl->getId());
1290 else
1292 // todo hulud interface syntax error
1293 nlwarning ("id already exists for %s in %s", ctrl->getId().c_str(), parentGroup->getId().c_str());
1294 delete ctrl;
1295 return false;
1298 // Add the ctrl to the parent group
1299 parentGroup->addCtrl(ctrl);
1300 return true;
1302 return false;
1305 // ----------------------------------------------------------------------------
1306 bool CInterfaceParser::parseView(xmlNodePtr cur, CInterfaceGroup * parentGroup, bool reload)
1308 CViewBase * view=NULL;
1309 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"type" ));
1310 if (!ptr)
1312 // todo hulud interface syntax error
1313 nlinfo("no type in a view");
1314 return false;
1317 view = NLMISC_GET_FACTORY(CViewBase, std::string).createObject(string((const char*)ptr), CViewBase::TCtorParam());
1319 if ( !strcmp(ptr,"pointer"))
1321 if( editorMode )
1322 savePointerSettings( cur );
1324 CWidgetManager::getInstance()->setPointer( dynamic_cast<CViewPointer*>(view) );
1327 //nlinfo("view type %s mem : %d",ptr,view->getMemory());
1328 if (view)
1330 if (!view->parse(cur,parentGroup))
1332 delete view;
1333 return false;
1335 if (parentGroup->getElement(view->getId()) != NULL)
1337 // Remove old groupe and replace
1338 if ( reload )
1339 parentGroup->delElement (view->getId());
1340 else
1342 // todo hulud interface syntax error
1343 nlwarning ("id already exists for %s in %s", view->getId().c_str(), parentGroup->getId().c_str());
1344 delete view;
1345 return false;
1349 //add the view to the parent group
1350 CGroupList *pList = dynamic_cast<CGroupList*>(parentGroup);
1351 if (pList != NULL)
1353 pList->addChild (view);
1355 else
1357 parentGroup->addView(view);
1359 return true;
1361 // todo hulud interface syntax error
1362 nlinfo("unknown view type %s", (const char*)ptr);
1363 return false;
1366 // ----------------------------------------------------------------------------
1367 bool CInterfaceParser::parseTreeNode (xmlNodePtr cur, CGroupContainer *parentGroup)
1369 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"node" ));
1370 if (!ptr) return false;
1372 string stmp2 = toLowerAscii(string((const char*)ptr));
1374 CInterfaceElement *pEltFound = NULL;
1375 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
1376 for (uint32 i = 0; i < _MasterGroups.size(); ++i)
1378 CWidgetManager::SMasterGroup &rMG = _MasterGroups[i];
1379 for (uint32 j = 0; j < rMG.Group->getGroups().size(); ++j)
1381 CInterfaceGroup *pIG = rMG.Group->getGroups()[j];
1382 string stmp = toLowerAscii(pIG->getId().substr(pIG->getId().rfind(':')+1,pIG->getId().size()));
1384 if (stmp == stmp2)
1386 pEltFound = pIG;
1387 break;
1390 if (pEltFound != NULL)
1391 break;
1393 if (pEltFound == NULL)
1395 string stmp = string("element not found for tree : ") + string((const char*)ptr);
1396 // todo hulud interface syntax error
1397 nlinfo(stmp.c_str());
1398 return false;
1400 CGroupContainer *pIC = dynamic_cast<CGroupContainer*>(pEltFound);
1401 if (pIC == NULL)
1403 string stmp = string("not a container : ") + pEltFound->getId();
1404 // todo hulud interface syntax error
1405 nlinfo(stmp.c_str());
1406 return false;
1408 parentGroup->attachContainer (pIC);
1409 cur = cur->children;
1410 while (cur)
1412 parseTreeNode(cur, pIC);
1413 cur = cur->next;
1415 return true;
1418 // ----------------------------------------------------------------------------
1419 bool CInterfaceParser::setupTreeNode (xmlNodePtr cur, CGroupContainer * /* parentGroup */)
1421 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"node" ));
1422 if (!ptr) return false;
1424 string stmp2 = toLowerAscii(string((const char*)ptr));
1426 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
1427 CInterfaceElement *pEltFound = NULL;
1428 for (uint32 i = 0; i < _MasterGroups.size(); ++i)
1430 CWidgetManager::SMasterGroup &rMG = _MasterGroups[i];
1431 for (uint32 j = 0; j < rMG.Group->getGroups().size(); ++j)
1433 CInterfaceGroup *pIG = rMG.Group->getGroups()[j];
1434 string stmp = toLowerAscii(pIG->getId().substr(pIG->getId().rfind(':')+1,pIG->getId().size()));
1435 if (stmp == stmp2)
1437 pEltFound = pIG;
1438 break;
1441 if (pEltFound != NULL)
1442 break;
1444 if (pEltFound == NULL)
1446 string stmp = string("element not found for tree : ") + string((const char*)ptr);
1447 // todo hulud interface syntax error
1448 nlinfo(stmp.c_str());
1449 return false;
1451 CGroupContainer *pIC = dynamic_cast<CGroupContainer*>(pEltFound);
1452 if (pIC == NULL)
1454 string stmp = string("not a container : ") + pEltFound->getId();
1455 // todo hulud interface syntax error
1456 nlinfo(stmp.c_str());
1457 return false;
1459 // See if the group should be docked.
1460 ptr = (char*) xmlGetProp( cur, (xmlChar*)"docked" );
1461 if (nlstricmp((const char *) ptr, "true") == 0)
1463 // dock the container
1464 pIC->popupCurrentPos();
1465 // compute position on screen
1466 sint32 x = 0, y = 0, w = 200, h = 100;
1467 ptr = (char*) xmlGetProp( cur, (xmlChar*)"x" );
1468 if (ptr)
1470 sint32 value;
1471 if (fromString((const char*)ptr, value))
1473 x = value;
1476 ptr = (char*) xmlGetProp( cur, (xmlChar*)"y" );
1477 if (ptr)
1479 sint32 value;
1480 if (fromString((const char*)ptr, value))
1482 y = value;
1485 ptr = (char*) xmlGetProp( cur, (xmlChar*)"w" );
1486 if (ptr)
1488 sint32 value;
1489 if (fromString((const char*)ptr, value))
1491 w = value;
1494 ptr = (char*) xmlGetProp( cur, (xmlChar*)"h" );
1495 if (ptr)
1497 sint32 value;
1498 if (fromString((const char*)ptr, value))
1500 h = value;
1503 pIC->setX(x);
1504 pIC->setY(y);
1505 pIC->setW(w);
1506 pIC->setH(h);
1507 pIC->invalidateCoords();
1510 while (cur)
1512 setupTreeNode(cur, pIC);
1513 cur = cur->next;
1515 return true;
1518 void CInterfaceParser::savePointerSettings( xmlNodePtr node )
1520 if( node == NULL )
1521 return;
1523 xmlAttrPtr prop = node->properties;
1525 std::string key;
1526 std::string value;
1528 while( prop != NULL )
1530 key = std::string( reinterpret_cast< const char* >( prop->name ) );
1531 value = std::string( reinterpret_cast< char* >( prop->children->content ) );
1533 pointerSettings[ key ] = value;
1535 prop = prop->next;
1539 void CInterfaceParser::saveKeySettings( xmlNodePtr node )
1541 if( node == NULL )
1542 return;
1544 xmlAttrPtr prop = node->properties;
1546 std::string name( reinterpret_cast< char* >( xmlGetProp( node, BAD_CAST "name" ) ) );
1547 if( name.empty() )
1548 return;
1550 std::string key;
1551 std::string value;
1552 std::map< std::string, std::string > propMap;
1554 while( prop != NULL )
1556 key = std::string( reinterpret_cast< const char* >( prop->name ) );
1557 value = std::string( reinterpret_cast< char* >( prop->children->content ) );
1559 if( key == "name" )
1561 prop = prop->next;
1562 continue;
1565 propMap[ key ] = value;
1567 prop = prop->next;
1570 if( propMap.empty() )
1571 return;
1573 keySettings[ name ] = propMap;
1576 void CInterfaceParser::addModule( std::string name, IParserModule *module )
1578 std::map< std::string, IParserModule* >::iterator itr =
1579 moduleMap.find( name );
1581 if( itr != moduleMap.end() )
1583 nlwarning( "Tried to add parser module %s, which already exists.",name.c_str() );
1584 delete module;
1585 return;
1588 module->setParser( this );
1589 moduleMap[ name ] = module;
1592 CInterfaceParser::IParserModule* CInterfaceParser::getModuleFor( std::string name ) const
1594 std::map< std::string, IParserModule* >::const_iterator itr =
1595 moduleMap.find( name );
1596 if( itr == moduleMap.end() )
1597 return NULL;
1598 else
1599 return itr->second;
1602 void CInterfaceParser::removeAllModules()
1604 std::map< std::string, IParserModule* >::iterator itr;
1605 for( itr = moduleMap.begin(); itr != moduleMap.end(); ++itr )
1607 delete itr->second;
1609 moduleMap.clear();
1612 // ----------------------------------------------------------------------------
1613 bool CInterfaceParser::setupTree (xmlNodePtr cur, CWidgetManager::SMasterGroup * /* parentGroup */)
1615 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"node" ));
1616 if (!ptr) return false;
1618 string stmp2 = toLowerAscii(string((const char*)ptr));
1620 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
1621 CInterfaceElement *pEltFound = NULL;
1622 for (uint32 i = 0; i < _MasterGroups.size(); ++i)
1624 CWidgetManager::SMasterGroup &rMG = _MasterGroups[i];
1625 for (uint32 j = 0; j < rMG.Group->getGroups().size(); ++j)
1627 CInterfaceGroup *pIG = rMG.Group->getGroups()[j];
1628 string stmp = toLowerAscii(pIG->getId().substr(pIG->getId().rfind(':')+1,pIG->getId().size()));
1630 if (stmp == stmp2)
1632 pEltFound = pIG;
1633 break;
1636 if (pEltFound != NULL)
1637 break;
1640 if (pEltFound == NULL)
1642 string stmp = string("no group found for ") + string((const char*)ptr);
1643 // todo hulud interface syntax error
1644 nlinfo(stmp.c_str());
1645 return false;
1648 // the element must be a group
1649 CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(pEltFound);
1650 if (pIG == NULL)
1652 string stmp = string("not a group !") + pEltFound->getId();
1653 // todo hulud interface syntax error
1654 nlinfo(stmp.c_str());
1655 return false;
1658 // but must not be a group modal
1659 if (dynamic_cast<CGroupModal*>(pIG))
1661 string stmp = string("tree can't have modal group !") + pEltFound->getId();
1662 // todo hulud interface syntax error
1663 nlinfo(stmp.c_str());
1664 return false;
1668 CGroupContainer *pIC = dynamic_cast<CGroupContainer*>(pEltFound);
1669 if (pIC != NULL)
1671 cur = cur->children;
1672 while (cur)
1674 setupTreeNode(cur, pIC);
1675 cur = cur->next;
1678 return true;
1683 // ----------------------------------------------------------------------------
1684 bool CInterfaceParser::parseTree (xmlNodePtr cur, CWidgetManager::SMasterGroup *parentGroup)
1686 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"node" ));
1687 if (!ptr) return false;
1688 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
1689 CInterfaceElement *pEltFound = NULL;
1690 for (uint32 i = 0; i < _MasterGroups.size(); ++i)
1692 CWidgetManager::SMasterGroup &rMG = _MasterGroups[i];
1693 for (uint32 j = 0; j < rMG.Group->getGroups().size(); ++j)
1695 CInterfaceGroup *pIG = rMG.Group->getGroups()[j];
1696 string stmp = NLMISC::toLowerAscii(pIG->getId().substr(pIG->getId().rfind(':')+1,pIG->getId().size()));
1697 string stmp2 = NLMISC::toLowerAscii(string((const char*)ptr));
1698 if (stmp == stmp2)
1700 pEltFound = pIG;
1701 break;
1704 if (pEltFound != NULL)
1705 break;
1708 if (pEltFound == NULL)
1710 string stmp = string("no group found for ") + string((const char*)ptr);
1711 // todo hulud interface syntax error
1712 nlinfo(stmp.c_str());
1713 return false;
1716 // the element must be a group
1717 CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(pEltFound);
1718 if (pIG == NULL)
1720 string stmp = string("not a group !") + pEltFound->getId();
1721 // todo hulud interface syntax error
1722 nlinfo(stmp.c_str());
1723 return false;
1726 // but must not be a group modal
1727 if (dynamic_cast<CGroupModal*>(pIG))
1729 string stmp = string("tree can't have modal group !") + pEltFound->getId();
1730 // todo hulud interface syntax error
1731 nlinfo(stmp.c_str());
1732 return false;
1735 // Ok add it.
1736 CWidgetManager::getInstance()->addWindowToMasterGroup(parentGroup->Group->getId(), pIG);
1738 CGroupContainer *pIC = dynamic_cast<CGroupContainer*>(pEltFound);
1739 if (pIC != NULL)
1741 cur = cur->children;
1742 while (cur)
1744 parseTreeNode(cur, pIC);
1745 cur = cur->next;
1748 return true;
1751 // ----------------------------------------------------------------------------
1752 bool CInterfaceParser::parseDefine(xmlNodePtr cur)
1754 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"id" ));
1755 if (!ptr || *ptr==0)
1757 // todo hulud interface syntax error
1758 nlinfo ("no id in a define");
1759 return false;
1761 CXMLAutoPtr ptrVal2;
1762 CXMLAutoPtr ptrVal((const char*) xmlGetProp( cur, (xmlChar*)"value" ));
1763 if (!ptrVal)
1765 ptrVal2 = (char*) xmlGetProp( cur, (xmlChar*)"value_from_code" );
1766 if (!ptrVal2)
1768 // todo hulud interface syntax error
1769 nlwarning ("<parseDefine> : no value nor value_from_code in a define");
1770 return false;
1774 // verify id.
1775 string id= (const char*)ptr;
1776 for(uint i=0;i<id.size();i++)
1778 if(!validDefineChar(id[i]))
1780 // todo hulud interface syntax error
1781 nlwarning ("<parseDefine> : bad id in a define. Bad char found: %c", id[i]);
1782 return false;
1786 // Check if we have to execute some code
1787 if (ptrVal2)
1789 CInterfaceExprValue res;
1791 if (CInterfaceExpr::eval(ptrVal2.str(), res))
1793 if (!res.toString())
1795 // todo hulud interface syntax error
1796 nlwarning ("<parseDefine> : cant eval to string value_from_code : %s", (const char*)ptrVal2);
1797 return false;
1799 setDefine(id, res.getString().c_str());
1801 else
1803 // todo hulud interface syntax error
1804 nlwarning ("<parseDefine> : cant eval value_from_code : %s", (const char*)ptrVal2);
1805 return false;
1808 else
1810 // Assign var
1811 setDefine (id, (const char*)ptrVal);
1814 return true;
1817 // ----------------------------------------------------------------------------
1818 bool CInterfaceParser::parseProcedure(xmlNodePtr cur, bool reload)
1820 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"id" ));
1821 if (!ptr || *ptr==0)
1823 // todo hulud interface syntax error
1824 nlwarning ("no id in a procedure");
1825 return false;
1827 string procId= ptr.str();
1829 if (_ProcedureMap.find(procId) != _ProcedureMap.end())
1831 // If reloading the interface, remove the old proc
1832 if (reload)
1834 _ProcedureMap.erase (procId);
1836 else
1838 // todo hulud interface syntax error
1839 nlwarning ("id already exists for procedure %s", procId.c_str());
1840 return false;
1844 // build the procedure
1845 CProcedure newProc;
1847 // Look for sons.
1848 cur = cur->children;
1849 while (cur)
1851 if (stricmp((char*)cur->name,"action") == 0)
1853 CXMLAutoPtr name((const char*) xmlGetProp (cur, (xmlChar*)"handler"));
1854 CXMLAutoPtr params((const char*) xmlGetProp (cur, (xmlChar*)"params"));
1855 CXMLAutoPtr cond((const char*) xmlGetProp (cur, (xmlChar*)"cond"));
1856 CProcAction action;
1857 if(!name)
1859 // todo hulud interface syntax error
1860 nlinfo("no action name in a action of procedure %s", procId.c_str());
1861 return false;
1863 else
1864 action.Action= (const char*)name;
1865 if(params)
1867 action.Parameters = (const char*)params;
1868 action.buildParamBlock((const char*)params);
1870 if(cond)
1872 action.Conditions = (const char*)cond;
1873 action.buildCondBlock ((const char*)cond);
1875 newProc.Actions.push_back(action);
1877 else if (!strcmp((char*)cur->name,"instance"))
1879 if (!parseInstance(cur))
1880 // todo hulud interface syntax error
1881 nlwarning ("could not parse instance");
1883 else if (!strcmp((char*)cur->name,"vector"))
1885 if (!parseVector(cur))
1886 // todo hulud interface syntax error
1887 nlwarning ("could not parse vector");
1889 cur = cur->next;
1892 // add/replace the procedure
1893 _ProcedureMap[procId]= newProc;
1895 return true;
1898 void CInterfaceParser::setupOptions()
1900 if( setupCallback != NULL )
1901 setupCallback->setupOptions();
1904 // ----------------------------------------------------------------------------
1905 bool CInterfaceParser::initCoordsAndLuaScript()
1907 // set all position associations
1908 for (map<CInterfaceElement*,string>::const_iterator it = _ParentPositionsMap.begin(); it != _ParentPositionsMap.end();it++)
1910 CInterfaceElement *pIEL = it->first;
1911 string EltName = it->second;
1913 CInterfaceGroup *parent = pIEL->getParent();
1914 CInterfaceElement *parentpos;
1915 //if the element has a parent check the parent's children
1916 if (parent)
1917 parentpos = parent->getElement(EltName);
1918 //if the element has no parent, check the windows
1919 else
1920 parentpos = CWidgetManager::getInstance()->getWindowFromId(EltName);
1922 if (parentpos == NULL)
1924 // todo hulud interface syntax error
1925 nlinfo(" the element %s was not found as %s position reference ", EltName.c_str(), pIEL->getId().c_str());
1927 else
1929 pIEL->setParentPos (parentpos);
1932 // Same for size
1933 for (map<CInterfaceElement*,string>::const_iterator it2 = _ParentSizesMap.begin(); it2 != _ParentSizesMap.end(); it2++)
1935 CInterfaceElement *pIEL = it2->first;
1936 string EltName = it2->second;
1938 CInterfaceGroup *parent = pIEL->getParent();
1939 CInterfaceElement *parentsize;
1940 if (EltName == "parent")
1942 parentsize = pIEL->getParent();
1944 else
1946 //if the element has a parent check the parent's children
1947 if (parent)
1948 parentsize = parent->getElement(EltName);
1949 //if the element has no parent, check the windows
1950 else
1951 parentsize = CWidgetManager::getInstance()->getWindowFromId(EltName);
1954 if (parentsize == NULL)
1956 // todo hulud interface syntax error
1957 nlinfo(" the element %s was not found as %s size reference ", EltName.c_str(), pIEL->getId().c_str());
1959 else
1961 pIEL->setParentSize (parentsize);
1964 // Same for size max
1965 for (map<CInterfaceElement*,string>::const_iterator it3 = _ParentSizesMaxMap.begin(); it3 != _ParentSizesMaxMap.end(); it3++)
1967 CInterfaceGroup *pIEL = dynamic_cast<CInterfaceGroup*>(it3->first);
1968 if (pIEL == NULL) continue;
1969 string EltName = it3->second;
1971 CInterfaceGroup *parent = pIEL->getParent();
1972 CInterfaceElement *parentsizemax;
1973 if (EltName == "parent")
1975 parentsizemax = parent;
1977 else
1979 //if the element has a parent check the parent's children
1980 if (parent)
1981 parentsizemax = parent->getElement(EltName);
1982 //if the element has no parent, check the windows
1983 else
1984 parentsizemax = CWidgetManager::getInstance()->getWindowFromId(EltName);
1987 if (parentsizemax == NULL)
1989 // todo hulud interface syntax error
1990 nlinfo(" the element %s was not found as %s sizemax reference ", EltName.c_str(), pIEL->getId().c_str());
1992 else
1994 pIEL->setParentSizeMax (parentsizemax);
1998 // Same For LUA Class association
1999 for (map<CInterfaceGroup*,string>::const_iterator itLua = _LuaClassAssociation.begin(); itLua != _LuaClassAssociation.end(); itLua++)
2001 // execute the script on this group
2002 CAHManager::getInstance()->runActionHandler("lua", itLua->first, itLua->second);
2006 // Clear all structures used only for init
2007 NLMISC::contReset (_ParentPositionsMap);
2008 NLMISC::contReset (_ParentSizesMap);
2009 NLMISC::contReset (_ParentSizesMaxMap);
2010 NLMISC::contReset (_LuaClassAssociation);
2011 return true;
2014 // ----------------------------------------------------------------------------
2015 void CInterfaceParser::addParentPositionAssociation(CInterfaceElement* element, const std::string& parent)
2017 _ParentPositionsMap.insert (std::map<CInterfaceElement*,std::string>::value_type(element, parent));
2020 std::string CInterfaceParser::getParentPosAssociation( CInterfaceElement *element ) const
2022 std::map< CInterfaceElement*, std::string >::const_iterator itr =
2023 _ParentPositionsMap.find( element );
2024 if( itr == _ParentPositionsMap.end() )
2025 return "parent";
2026 else
2027 return CInterfaceElement::stripId( itr->second );
2030 // ----------------------------------------------------------------------------
2031 void CInterfaceParser::addParentSizeAssociation(CInterfaceElement* element, const std::string& parent)
2033 _ParentSizesMap.insert (std::map<CInterfaceElement*,std::string>::value_type(element, parent));
2036 std::string CInterfaceParser::getParentSizeAssociation( CInterfaceElement *element ) const
2038 std::map< CInterfaceElement*, std::string >::const_iterator itr =
2039 _ParentSizesMap.find( element );
2040 if( itr == _ParentSizesMap.end() )
2041 return "parent";
2042 else
2043 return CInterfaceElement::stripId( itr->second );
2046 // ----------------------------------------------------------------------------
2047 void CInterfaceParser::addParentSizeMaxAssociation (CInterfaceElement *element, const std::string &parent)
2049 _ParentSizesMaxMap.insert (std::map<CInterfaceElement*,std::string>::value_type(element, parent));
2052 std::string CInterfaceParser::getParentSizeMaxAssociation( CInterfaceElement *element ) const
2054 std::map< CInterfaceElement*, std::string >::const_iterator itr =
2055 _ParentSizesMap.find( element );
2056 if( itr == _ParentSizesMap.end() )
2057 return "parent";
2058 else
2059 return CInterfaceElement::stripId( itr->second );
2062 // ----------------------------------------------------------------------------
2063 void CInterfaceParser::addLuaClassAssociation (CInterfaceGroup *group, const std::string &luaScript)
2065 _LuaClassAssociation.insert (std::map<CInterfaceGroup*,std::string>::value_type(group, luaScript));
2068 std::string CInterfaceParser::getLuaClassAssociation( CInterfaceGroup *group ) const
2070 std::map< CInterfaceGroup*, std::string >::const_iterator itr =
2071 _LuaClassAssociation.find( group );
2072 if( itr == _LuaClassAssociation.end() )
2073 return "";
2074 else
2075 return itr->second;
2078 // ***************************************************************************
2079 const std::string &CInterfaceParser::getDefine(const std::string &id) const
2081 static string NullStr;
2082 CstItVarMap it= _DefineMap.find(id);
2083 if(it==_DefineMap.end())
2084 return NullStr;
2085 else
2086 return it->second;
2089 // ***************************************************************************
2090 bool CInterfaceParser::isDefineExist(const std::string &id) const
2092 CstItVarMap it= _DefineMap.find(id);
2093 return it!=_DefineMap.end();
2097 // ***************************************************************************
2098 void CInterfaceParser::setDefine(const std::string &id, const std::string &value)
2100 _DefineMap[id]= value;
2104 // ***************************************************************************
2105 bool CInterfaceParser::validDefineChar(char c) const
2107 if(c>='A' && c<='Z')
2108 return true;
2109 if(c>='a' && c<='z')
2110 return true;
2111 if(c>='0' && c<='9')
2112 return true;
2113 if(c=='_')
2114 return true;
2116 return false;
2119 #define DEFINE_IDENT '%'
2121 // ***************************************************************************
2122 bool CInterfaceParser::solveDefine(const std::string &propVal, std::string &newPropVal, std::string &defError)
2124 string::size_type curPos= 0;
2125 string::size_type lastPos= 0;
2127 //if it has some % then solve define value
2128 while( (curPos=propVal.find(DEFINE_IDENT, curPos)) != string::npos)
2130 // If it is end of line
2131 if(curPos==propVal.size()-1)
2133 // then skip
2134 curPos= propVal.size();
2136 // If it is a double %%
2137 else if(propVal[curPos+1]==DEFINE_IDENT)
2139 // copy from last to cur included
2140 curPos++;
2141 newPropVal+= propVal.substr(lastPos, curPos-lastPos);
2142 // both % are skipped
2143 curPos++;
2144 lastPos= curPos;
2146 // else parse define value
2147 else
2149 // copy the last not define sub string.
2150 newPropVal+= propVal.substr(lastPos, curPos-lastPos);
2152 // skip the %
2153 curPos++;
2155 // get the id pos
2156 uint startIdPos= (uint)curPos;
2157 while( curPos<propVal.size() && validDefineChar(propVal[curPos]) )
2158 curPos++;
2159 // get the id
2160 string defineId= propVal.substr(startIdPos, curPos-startIdPos);
2161 if(!isDefineExist(defineId))
2163 defError= defineId;
2164 return false;
2166 // Add the define value to the string
2167 newPropVal+= getDefine(defineId);
2169 // valid pos is current pos
2170 lastPos= curPos;
2173 // concat last part
2174 newPropVal+= propVal.substr(lastPos, propVal.size()-lastPos);
2176 return true;
2179 // ***************************************************************************
2180 bool CInterfaceParser::solveDefine(xmlNodePtr cur)
2182 CXMLAutoPtr ptr;
2184 //get the node properties
2185 xmlAttrPtr props = cur->properties;
2186 while (props)
2188 //get the property value
2189 ptr = (char*)xmlGetProp( cur, props->name);
2190 nlassert(ptr);
2191 string propVal= ptr.str();
2192 string newPropVal;
2194 // solve define of this prop
2195 string defError;
2196 if(!solveDefine(propVal, newPropVal, defError))
2198 // todo hulud interface syntax error
2199 nlinfo("can't find define: %s", defError.c_str());
2200 return false;
2203 // change value
2204 xmlSetProp(cur, props->name, (const xmlChar*)newPropVal.c_str());
2206 // next property
2207 props = props->next;
2210 // recurs to node children
2211 cur= cur->children;
2212 while(cur)
2214 if(!solveDefine(cur))
2215 return false;
2216 cur= cur->next;
2219 return true;
2222 // ***************************************************************************
2223 bool CInterfaceParser::parseSheetSelection(xmlNodePtr cur)
2225 CXMLAutoPtr prop;
2226 prop = (char*) xmlGetProp( cur, (xmlChar*)"name" );
2227 if (!prop)
2229 // todo hulud interface syntax error
2230 nlwarning("<CInterfaceParser::parseSheetSelection> can't get name of a selection");
2231 return false;
2233 std::string groupName = (const char *) prop;
2234 prop = (char*) xmlGetProp( cur, (xmlChar*)"texture" );
2235 if (!prop)
2237 // todo hulud interface syntax error
2238 nlwarning("<CInterfaceParser::parseSheetSelection> can't get texture name for selection %s", groupName.c_str());
2239 return false;
2241 std::string texName = (const char *) prop;
2242 prop = (char*) xmlGetProp( cur, (xmlChar*)"color" );
2243 CRGBA color = CRGBA::White;
2244 if (prop)
2246 color = CInterfaceElement::convertColor(prop);
2248 bool globalColor = true;
2249 prop = (char*) xmlGetProp( cur, (xmlChar*)"global_color" );
2250 if (prop) globalColor = CInterfaceElement::convertBool(prop);
2251 sint groupIndex = _CtrlSheetSelection.addGroup(groupName);
2252 if (groupIndex != -1)
2254 CSheetSelectionGroup *csg = _CtrlSheetSelection.getGroup(groupIndex);
2255 csg->setTexture(texName);
2256 csg->setColor(color);
2257 csg->enableGlobalColor(globalColor);
2259 return true;
2262 // ***************************************************************************
2263 bool CInterfaceParser::addLink(CInterfaceLink *link, const std::string &id)
2265 if (!link)
2267 // todo hulud interface syntax error
2268 nlwarning("link empty");
2269 return false;
2271 TLinkMap::const_iterator it = _LinkMap.find(id);
2272 if (it != _LinkMap.end())
2274 // todo hulud interface syntax error
2275 nlwarning("<CInterfaceParser::addLink> link %s added twice", id.c_str());
2276 return false;
2278 #ifdef NL_DEBUG
2279 link->LinkName = id;
2280 #endif
2281 _LinkMap[id] = link;
2282 return false;
2285 // ***************************************************************************
2286 bool CInterfaceParser::removeLink(const std::string &id)
2288 TLinkMap::iterator it = _LinkMap.find(id);
2289 if (it == _LinkMap.end())
2291 // todo hulud interface syntax error
2292 nlwarning("<CInterfaceParser::removeLink> unknown link %s", id.c_str());
2293 return false;
2295 CSmartPtr<CInterfaceLink> &link = it->second; // dont need to copy a smart ptr on link since still in map
2296 for (uint k = 0; k < link->getNumTargets(); ++k)
2298 link->getTarget(k)->removeLink(link); // remove the link from the list & delete it
2300 it->second->uninit();
2301 _LinkMap.erase(it); // NB : the link is holded by a smart ptr, to do this decrease the ref count
2302 return true;
2306 // ***************************************************************************
2307 xmlNodePtr CInterfaceParser::searchTreeNodeInHierarchy(xmlNodePtr root, const char *node)
2309 // if I match...
2310 CXMLAutoPtr prop((const char*) xmlGetProp( root, (xmlChar*)"node" ));
2311 // not a valide tree node? abort.
2312 if (!prop) return NULL;
2313 // match?
2314 if ( !strcmp((const char*)prop, node ) )
2315 return root;
2317 // No, try with sons.
2318 xmlNodePtr cur= root->children;
2319 while(cur)
2321 xmlNodePtr candidate= searchTreeNodeInHierarchy(cur, node);
2322 // if found in this branch.
2323 if(candidate)
2324 return candidate;
2326 // try next
2327 cur= cur->next;
2330 // not found
2331 return NULL;
2334 //==================================================================
2335 bool CInterfaceParser::parseAnim(xmlNodePtr cur, CInterfaceGroup * parentGroup)
2337 CInterfaceAnim *pAnim;
2339 CXMLAutoPtr ptr;
2341 ptr = (char*) xmlGetProp( cur, (xmlChar*)"id" );
2342 if (!ptr)
2344 // todo hulud interface syntax error
2345 nlinfo ("anim has no id");
2346 return false;
2348 string animId = ptr.str();
2349 pAnim = new CInterfaceAnim;
2351 if (pAnim->parse (cur, parentGroup))
2353 if (_AnimMap.count(animId))
2355 nlwarning("Anim %s already exists, replacing with new one", animId.c_str());
2357 _AnimMap[animId] = pAnim;
2359 else
2361 delete pAnim;
2362 return false;
2364 return true;
2367 //==================================================================
2368 void CInterfaceParser::freeXMLNodeAndSibblings(xmlNodePtr node)
2370 if (!node) return;
2371 while (node)
2373 xmlNodePtr currNode = node;
2374 node = node->next;
2375 xmlFreeNode(currNode);
2380 // ***************************************************************************
2381 CInterfaceGroup *CInterfaceParser::createGroupInstance(const std::string &templateName, const std::string &parentID, const std::pair<std::string,std::string> *templateParams, uint numParams, bool updateLinks /* = true */)
2383 // create basic xml node that contains infos for the template
2384 xmlNodePtr instance = xmlNewNode(NULL, (const xmlChar *) "instance");
2385 if (!instance)
2387 // todo hulud interface syntax error
2388 nlwarning("<CInterfaceParser::createGroupInstance> Can't create xml node ");
2389 return NULL;
2391 for(uint k = 0; k < numParams; ++k)
2393 xmlSetProp(instance, (const xmlChar *) templateParams[k].first.c_str(), (const xmlChar *) templateParams[k].second.c_str());
2395 xmlSetProp(instance, (const xmlChar *) "template", (const xmlChar *) templateName.c_str());
2396 if (!parseInstance(instance))
2398 // todo hulud interface syntax error
2399 nlwarning("<CInterfaceParser::createGroupInstance> cannot create instance from template %s", templateName.c_str());
2400 freeXMLNodeAndSibblings(instance);
2401 return NULL;
2404 // result should contain a group
2405 xmlNodePtr currNode = instance->next;
2406 while (currNode)
2408 if (strcmp((const char *) currNode->name, "group") == 0 && currNode->type == XML_ELEMENT_NODE)
2410 // TODO nico : build a struct from that mess
2411 std::map<CInterfaceElement*,std::string> localParentPositionsMap;
2412 std::map<CInterfaceElement*,std::string> localParentSizesMap;
2413 std::map<CInterfaceElement*,std::string> localParentSizesMaxMap;
2414 std::map<CInterfaceGroup*,std::string> localLuaClassAssociation;
2416 localParentPositionsMap.swap(_ParentPositionsMap);
2417 localParentSizesMap.swap(_ParentSizesMap);
2418 localParentSizesMaxMap.swap(_ParentSizesMaxMap);
2419 localLuaClassAssociation.swap(_LuaClassAssociation);
2421 CViewBase::TCtorParam params;
2422 CInterfaceGroup dummyGroup(params);
2423 dummyGroup.setId(parentID);
2424 if (!parseGroup(currNode, &dummyGroup, false))
2426 localParentPositionsMap.swap(_ParentPositionsMap);
2427 localParentSizesMap.swap(_ParentSizesMap);
2428 localParentSizesMaxMap.swap(_ParentSizesMaxMap);
2429 localLuaClassAssociation.swap(_LuaClassAssociation);
2430 freeXMLNodeAndSibblings(instance);
2431 return NULL;
2433 freeXMLNodeAndSibblings(instance);
2434 CInterfaceGroup *group = dummyGroup.getGroup((uint) 0);
2435 dummyGroup.delGroup(group, true);
2436 group->setParent(NULL);
2437 group->setParentPos(NULL);
2438 initCoordsAndLuaScript();
2439 localParentPositionsMap.swap(_ParentPositionsMap);
2440 localParentSizesMap.swap(_ParentSizesMap);
2441 localParentSizesMaxMap.swap(_ParentSizesMaxMap);
2442 localLuaClassAssociation.swap(_LuaClassAssociation);
2443 if ((group != NULL) && updateLinks)
2445 group->updateAllLinks();
2447 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(group);
2448 if (pGC != NULL)
2449 pGC->setup();
2450 return group;
2452 currNode = currNode->next;
2454 // todo hulud interface syntax error
2455 CXMLAutoPtr ptr(xmlGetProp(instance, (const xmlChar *) templateName.c_str()));
2456 nlwarning("<CInterfaceParser::createGroupInstance> no group found in template %s", (const char*)ptr);
2457 freeXMLNodeAndSibblings(instance);
2458 return NULL;
2461 // ***************************************************************************
2462 CInterfaceElement *CInterfaceParser::createUIElement(const std::string &templateName, const std::string &parentID, const std::pair<std::string,std::string> *templateParams, uint numParams, bool updateLinks /* = true */)
2464 std::string elementId;
2466 // create basic xml node that contains infos for the template
2467 xmlNodePtr instance = xmlNewNode(NULL, (const xmlChar *) "instance");
2468 if (!instance)
2470 // todo hulud interface syntax error
2471 nlwarning("<CInterfaceParser::addUIElement> Can't create xml node ");
2472 return NULL;
2474 for(uint k = 0; k < numParams; ++k)
2476 xmlSetProp(instance, (const xmlChar *) templateParams[k].first.c_str(), (const xmlChar *) templateParams[k].second.c_str());
2477 if (!strcmp(templateParams[k].first.c_str(), "id"))
2479 elementId = templateParams[k].second;
2482 xmlSetProp(instance, (const xmlChar *) "template", (const xmlChar *) templateName.c_str());
2483 if (!parseInstance(instance))
2485 // todo hulud interface syntax error
2486 nlwarning("<CInterfaceParser::addUIElement> cannot create instance from template %s", templateName.c_str());
2487 freeXMLNodeAndSibblings(instance);
2488 return NULL;
2491 CInterfaceElement *pIE= CWidgetManager::getInstance()->getElementFromId(parentID);
2492 CInterfaceGroup * parentGroup = dynamic_cast<CInterfaceGroup*>(pIE);
2494 if(!parentGroup)
2496 nlwarning("<CInterfaceParser::addUIElement> no parent group %s found ", parentID.c_str());
2497 freeXMLNodeAndSibblings(instance);
2498 return NULL;
2501 // result should contain a group
2502 xmlNodePtr currNode = instance->next;
2503 CInterfaceElement * newElement = NULL;
2504 while (currNode)
2506 if (strcmp((const char *) currNode->name, "group") == 0 && currNode->type == XML_ELEMENT_NODE)
2508 if (!parseGroup(currNode, parentGroup, false))
2510 freeXMLNodeAndSibblings(instance);
2511 return NULL;
2513 freeXMLNodeAndSibblings(instance);
2514 newElement = parentGroup->getGroup(elementId);
2515 parentGroup->delGroup((CInterfaceGroup*)newElement, true);
2517 else if (strcmp((const char *) currNode->name, "ctrl") == 0 && currNode->type == XML_ELEMENT_NODE)
2519 if (!parseControl(currNode, parentGroup, false))
2521 freeXMLNodeAndSibblings(instance);
2522 return NULL;
2524 freeXMLNodeAndSibblings(instance);
2525 newElement = parentGroup->getCtrl(elementId);
2526 parentGroup->delCtrl((CCtrlBase*)newElement, true);
2529 if(newElement != NULL)
2531 initCoordsAndLuaScript();
2532 if (updateLinks)
2534 newElement->updateAllLinks();
2536 return newElement;
2539 currNode = currNode->next;
2541 // todo hulud interface syntax error
2542 CXMLAutoPtr ptr(xmlGetProp(instance, (const xmlChar *) templateName.c_str()));
2543 nlwarning("<CInterfaceParser::addUIElement> no group found in template %s", (const char *)ptr);
2544 freeXMLNodeAndSibblings(instance);
2545 return NULL;
2548 // ***************************************************************************
2549 void CInterfaceParser::removeAllLinks()
2551 _LinkMap.clear();
2552 links.clear();
2553 linkId = 0;
2556 // ***************************************************************************
2557 void CInterfaceParser::removeAllProcedures()
2559 _ProcedureMap.clear();
2562 // ***************************************************************************
2563 void CInterfaceParser::removeAllDefines()
2565 _DefineMap.clear();
2568 // ***************************************************************************
2569 void CInterfaceParser::removeAllTemplates()
2571 for (uint i = 0; i < _Templates.size(); ++i)
2572 xmlFreeNode(_Templates[i]);
2573 _Templates.clear();
2576 // ***************************************************************************
2577 void CInterfaceParser::removeAllAnims()
2579 TAnimMap::iterator it = _AnimMap.begin();
2580 while (it != _AnimMap.end())
2582 CInterfaceAnim *pAnim = it->second;
2583 delete pAnim;
2584 it++;
2586 _AnimMap.clear();
2589 // ***************************************************************************
2592 // ***************************************************************************
2593 void CInterfaceParser::removeAll()
2595 removeAllLinks();
2596 CWidgetManager::getInstance()->removeAllOptions();
2597 removeAllProcedures();
2598 removeAllDefines();
2599 removeAllTemplates();
2600 removeAllAnims();
2601 CWidgetManager::getInstance()->removeAllMasterGroups();
2602 _StyleMap.clear();
2603 _CtrlSheetSelection.deleteGroups();
2604 NLMISC::contReset (_ParentPositionsMap);
2605 NLMISC::contReset (_ParentSizesMap);
2606 NLMISC::contReset (_ParentSizesMaxMap);
2607 NLMISC::contReset (_LuaClassAssociation);
2608 variableCache.clear();
2609 pointerSettings.clear();
2613 // ------------------------------------------------------------------------------------------------
2614 uint CInterfaceParser::getProcedureNumActions(const std::string &procName) const
2616 CstItProcedureMap it= _ProcedureMap.find(procName);
2617 if(it!=_ProcedureMap.end())
2619 const CProcedure &proc= it->second;
2620 return (uint)proc.Actions.size();
2622 else
2623 return 0;
2626 // ------------------------------------------------------------------------------------------------
2627 bool CInterfaceParser::getProcedureAction(const std::string &procName, uint actionIndex, std::string &ah, std::string &params) const
2629 CstItProcedureMap it= _ProcedureMap.find(procName);
2630 if(it!=_ProcedureMap.end())
2632 const CProcedure &proc= it->second;
2633 if(actionIndex<proc.Actions.size())
2635 const CProcAction &action= proc.Actions[actionIndex];
2636 // if not a variable parametrized Params
2637 if(action.ParamBlocks.size()==1 && action.ParamBlocks[0].NumParam==-1)
2639 ah= action.Action;
2640 params= action.ParamBlocks[0].String;
2641 return true;
2646 return false;
2649 CInterfaceAnim* CInterfaceParser::getAnim( const std::string &name) const
2651 TAnimMap::const_iterator it = _AnimMap.find( name );
2652 if( it == _AnimMap.end() )
2654 nlwarning( "anim %s not found", name.c_str() );
2655 return NULL;
2657 else
2658 return it->second;
2661 CProcedure* CInterfaceParser::getProc( const std::string &name )
2663 TProcedureMap::iterator itr = _ProcedureMap.find( name );
2664 if( itr == _ProcedureMap.end() )
2665 return NULL;
2667 return &itr->second;
2670 // ***************************************************************************
2671 bool CInterfaceParser::parseStyle(xmlNodePtr cur)
2673 string styleId;
2674 CXMLAutoPtr prop;
2676 prop = xmlGetProp (cur, (xmlChar*)"style");
2677 if(prop)
2678 styleId= (const char*)prop;
2679 else
2681 // todo hulud interface syntax error
2682 nlwarning("'style' not found in 'style'");
2683 return false;
2686 // create or replace style
2687 CStyle newStyle;
2689 //get the node properties
2690 xmlAttrPtr props = cur->properties;
2691 while (props)
2693 // if not the "style" property
2694 if( nlstricmp((const char*)props->name, "style") != 0 )
2696 // Append it.
2697 newStyle.Properties.push_back(CStyleProperty());
2698 newStyle.Properties.back().Name= (const char*)props->name;
2700 CXMLAutoPtr ptr(xmlGetProp( cur, props->name ));
2701 newStyle.Properties.back().Value = (const char*)ptr;
2704 props= props->next;
2707 // associate.
2708 _StyleMap[styleId]= newStyle;
2710 return true;
2713 // ***************************************************************************
2714 bool CInterfaceParser::parseLUAScript (xmlNodePtr cur)
2716 // read fileName
2717 CXMLAutoPtr prop;
2718 string fileName;
2719 prop = xmlGetProp (cur, (xmlChar*)"file");
2720 if(prop)
2721 fileName= (const char*)prop;
2722 else
2724 nlwarning("'file' not found in 'lua'");
2725 return false;
2728 // Append to set of reloadable FileScripts
2729 _LuaFileScripts.insert(fileName);
2731 // just display warning here.
2732 string dummyError;
2733 return loadLUA(fileName, dummyError);
2736 // ***************************************************************************
2737 bool CInterfaceParser::solveStyle(xmlNodePtr cur)
2739 CXMLAutoPtr ptr;
2741 // if the node is a style, abort (not recrusive because use "style" as param name)
2742 if ( !strcmp((char*)cur->name,"style") )
2743 return true;
2745 // try to read a "style" param.
2746 ptr= (char*)xmlGetProp( cur, (xmlChar*)"style");
2747 if(ptr)
2749 // get the style
2750 TStyleMap::iterator it= _StyleMap.find((const char*)ptr);
2751 if( it==_StyleMap.end() )
2753 // todo hulud interface syntax error
2754 nlwarning("style '%s' not found", (const char*)ptr);
2755 return false;
2758 // the style
2759 CStyle &style= it->second;
2761 // for all properties of the style, set them in the node
2762 for(uint i=0;i<style.Properties.size();i++)
2764 const char *propName= style.Properties[i].Name.c_str();
2765 const char *propValue= style.Properties[i].Value.c_str();
2767 // replace it only if the property is not already defined, (=> user can overide style properties)
2768 CXMLAutoPtr ptr2(xmlGetProp( cur, (xmlChar*)propName));
2769 if( !ptr2 )
2771 xmlSetProp(cur, (xmlChar*)propName, (xmlChar*)propValue);
2776 // recurs to node children
2777 cur= cur->children;
2778 while(cur)
2780 if(!solveStyle(cur))
2781 return false;
2782 cur= cur->next;
2785 return true;
2788 // ***************************************************************************
2790 #ifdef LUA_NEVRAX_VERSION
2792 class CLuaDebugBreakScreen : public IDebuggedAppMainLoop
2794 public:
2795 // called by external lua debugger when application is breaked
2796 virtual void breakEventLoop()
2798 Driver->clearBuffers(CRGBA(90, 90, 90));
2799 TextContext->setShaded(true);
2800 TextContext->setFontSize(40);
2801 TextContext->setColor(CRGBA::White);
2803 // TOP LEFT //
2804 //----------//
2805 TextContext->setHotSpot(NL3D::UTextContext::MiddleMiddle);
2806 TextContext->printfAt(0.5f, 0.5f, "Break in LUA code");
2807 Driver->swapBuffers();
2810 static CLuaDebugBreakScreen LuaDebugBreakScreen;
2812 #endif
2815 // ***************************************************************************
2816 void CInterfaceParser::initLUA()
2818 CLuaManager::enableLuaDebugging();
2820 #ifdef LUA_NEVRAX_VERSION
2821 extern ILuaIDEInterface *LuaDebuggerIDE;
2822 if (LuaDebuggerIDE) LuaDebuggerIDE->setDebuggedAppMainLoop(&LuaDebugBreakScreen);
2823 #endif
2825 // register LUA methods
2826 CLuaIHM::registerAll( *( CLuaManager::getInstance().getLuaState() ) );
2827 luaInitialized = true;
2830 // ***************************************************************************
2831 void CInterfaceParser::uninitLUA()
2833 _LuaFileScripts.clear();
2834 CLuaManager::getInstance().ResetLuaState();
2835 luaInitialized = false;
2838 // ***************************************************************************
2839 bool CInterfaceParser::loadLUA(const std::string &fileName, std::string &error)
2841 // get file
2843 bool needCheck = false;
2845 #if !FINAL_VERSION
2846 needCheck = false;
2847 #endif
2849 string pathName= CPath::lookup(fileName, false);
2850 if(pathName.empty())
2852 nlwarning("LUA Script '%s' not found", fileName.c_str());
2853 return false;
2856 bool isInData = false;
2857 std::string::size_type pos = pathName.find("@");
2858 if (pos != string::npos)
2860 if (CBigFile::getInstance().getBigFileName(pathName.substr(0, pos)) != "data/"+pathName.substr(0, pos))
2861 isInData = false;
2862 else
2863 isInData = true;
2866 if (needCheck && !isInData)
2868 nlwarning("You are not allowed to modify the lua files");
2869 // return true so it'll not generate a message box, we just ignore the file
2870 return true;
2873 // Parse script
2876 CLuaManager::getInstance().getLuaState()->executeFile(pathName);
2878 catch(const ELuaError &e)
2880 nlwarning(e.luaWhat().c_str());
2881 error= e.luaWhat();
2882 return false;
2885 return true;
2888 void CInterfaceParser::reloadAllLuaFileScripts()
2890 std::set< std::string >::const_iterator it;
2891 for( it = _LuaFileScripts.begin(); it != _LuaFileScripts.end(); ++it )
2893 std::string error;
2894 // if fail to reload a script, display the error code
2895 if( !loadLUA( *it, error ) )
2897 nlwarning( LuaHelperStuff::formatLuaErrorSysInfo( error ).c_str() );
2902 bool CInterfaceParser::hasProc( const std::string &name ) const
2904 TProcedureMap::const_iterator itr
2905 = _ProcedureMap.find( name );
2906 if( itr != _ProcedureMap.end() )
2907 return true;
2908 else
2909 return false;
2912 bool CInterfaceParser::addProc( const std::string &name )
2914 if( hasProc( name ) )
2915 return false;
2917 _ProcedureMap[ name ] = CProcedure();
2919 return true;
2922 bool CInterfaceParser::removeProc( const std::string &name )
2924 TProcedureMap::iterator itr =
2925 _ProcedureMap.find( name );
2926 if( itr == _ProcedureMap.end() )
2927 return false;
2929 _ProcedureMap.erase( itr );
2930 return true;
2933 uint32 CInterfaceParser::addLinkData( SLinkData &linkData )
2935 linkData.id = ++linkId;
2936 links[ linkData.id ] = linkData;
2937 return linkId;
2940 void CInterfaceParser::removeLinkData( uint32 id )
2942 std::map< uint32, SLinkData >::iterator itr =
2943 links.find( id );
2944 if( itr == links.end() )
2945 return;
2947 links.erase( itr );
2950 bool CInterfaceParser::getLinkData( uint32 id, SLinkData &linkData )
2952 std::map< uint32, SLinkData >::iterator itr =
2953 links.find( id );
2954 if( itr == links.end() )
2955 return false;
2957 linkData = itr->second;
2959 return true;
2962 void CInterfaceParser::updateLinkData( uint32 id, const SLinkData &linkData )
2964 std::map< uint32, SLinkData >::iterator itr =
2965 links.find( id );
2966 if( itr == links.end() )
2967 return;
2968 itr->second = linkData;
2971 void CInterfaceParser::setVariable( const VariableData &v )
2973 CInterfaceProperty prop;
2974 const std::string &type = v.type;
2975 const std::string &value = v.value;
2976 const std::string &entry = v.entry;
2978 if( type == "sint64" )
2979 prop.readSInt64( value.c_str(), entry );
2980 else
2981 if( type == "sint32" )
2982 prop.readSInt32( value.c_str(), entry );
2983 else
2984 if( type == "float" || type == "double" )
2985 prop.readDouble( value.c_str(), entry );
2986 else
2987 if( type == "bool" )
2988 prop.readBool( value.c_str(), entry );
2989 else
2990 if( type == "rgba" )
2991 prop.readRGBA( value.c_str(), entry );
2992 else
2993 if( type == "hotspot" )
2994 prop.readHotSpot( value.c_str(), entry );
2996 variableCache[ entry ] = v;
3000 bool CInterfaceParser::serializeVariables( xmlNodePtr parentNode ) const
3002 if( parentNode == NULL )
3003 return false;
3005 xmlNodePtr node = NULL;
3007 std::map< std::string, VariableData >::const_iterator itr;
3008 for( itr = variableCache.begin(); itr != variableCache.end(); ++itr )
3010 const VariableData &data = itr->second;
3012 node = xmlNewNode( NULL, BAD_CAST "variable" );
3013 if( node == NULL )
3014 return false;
3016 xmlAddChild( parentNode, node );
3018 xmlSetProp( node, BAD_CAST "entry", BAD_CAST data.entry.c_str() );
3019 xmlSetProp( node, BAD_CAST "type", BAD_CAST data.type.c_str() );
3021 if( !data.value.empty() )
3022 xmlSetProp( node, BAD_CAST "value", BAD_CAST data.value.c_str() );
3024 if( data.size != 0 )
3025 xmlSetProp( node, BAD_CAST "size", BAD_CAST toString( data.size ).c_str() );
3029 return true;
3033 bool CInterfaceParser::serializeProcs( xmlNodePtr parentNode) const
3035 if( parentNode == NULL )
3036 return false;
3038 xmlNodePtr procNode = NULL;
3039 xmlNodePtr actionNode = NULL;
3041 TProcedureMap::const_iterator itr;
3042 for( itr = _ProcedureMap.begin(); itr != _ProcedureMap.end(); ++itr )
3044 procNode = xmlNewNode( NULL, BAD_CAST "proc" );
3045 if( procNode == NULL )
3046 return false;
3048 xmlAddChild( parentNode, procNode );
3050 const CProcedure &proc = itr->second;
3052 xmlSetProp( procNode, BAD_CAST "id", BAD_CAST itr->first.c_str() );
3054 std::vector< CProcAction >::const_iterator itr2;
3055 for( itr2 = proc.Actions.begin(); itr2 != proc.Actions.end(); ++itr2 )
3057 actionNode = xmlNewNode( NULL, BAD_CAST "action" );
3058 if( actionNode == NULL )
3059 return false;
3061 xmlAddChild( procNode, actionNode );
3063 const CProcAction &action = *itr2;
3065 xmlSetProp( actionNode, BAD_CAST "handler", BAD_CAST action.Action.c_str() );
3067 if( !action.Parameters.empty() )
3068 xmlSetProp( actionNode, BAD_CAST "params", BAD_CAST action.Parameters.c_str() );
3070 if( !action.Conditions.empty() )
3071 xmlSetProp( actionNode, BAD_CAST "cond", BAD_CAST action.Conditions.c_str() );
3076 return true;
3080 bool CInterfaceParser::serializePointerSettings( xmlNodePtr parentNode ) const
3082 if( parentNode == NULL )
3083 return false;
3085 xmlNodePtr node = xmlNewNode( NULL, BAD_CAST "view" );
3086 if( node == NULL )
3087 return false;
3089 xmlAddChild( parentNode, node );
3091 std::map< std::string, std::string >::const_iterator itr;
3092 for( itr = pointerSettings.begin(); itr != pointerSettings.end(); ++itr )
3094 const std::string &key = itr->first;
3095 const std::string &value = itr->second;
3097 xmlSetProp( node, BAD_CAST key.c_str(), BAD_CAST value.c_str() );
3100 return true;
3104 bool CInterfaceParser::serializeKeySettings( xmlNodePtr parentNode ) const
3106 if( parentNode == NULL )
3107 return false;
3109 std::map< std::string, std::map< std::string, std::string > >::const_iterator itr;
3110 for( itr = keySettings.begin(); itr != keySettings.end(); ++itr )
3112 xmlNodePtr node = xmlNewNode( NULL, BAD_CAST "key" );
3113 if( node == NULL )
3114 return false;
3116 xmlAddChild( parentNode, node );
3117 xmlSetProp( node, BAD_CAST "name", BAD_CAST itr->first.c_str() );
3119 const std::map< std::string, std::string > &settings = itr->second;
3121 std::map< std::string, std::string >::const_iterator itr2;
3122 for( itr2 = settings.begin(); itr2 != settings.end(); ++itr2 )
3124 const std::string &key = itr2->first;
3125 const std::string &value = itr2->second;
3127 xmlSetProp( node, BAD_CAST key.c_str(), BAD_CAST value.c_str() );
3131 return true;
3134 CViewBase* CInterfaceParser::createClass( const std::string &name )
3136 return NLMISC_GET_FACTORY( CViewBase, std::string ).createObject( std::string( name ) , CViewBase::TCtorParam() );