// Ryzom - MMORPG Framework
// 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 .
// ----------------------------------------------------------------------------
#include "stdpch.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 "game_share/xml_auto_ptr.h"
#include "interface_parser.h"
#include "interface_observer.h"
#include "interface_options.h"
#include "interface_anim.h"
#include "interface_3d_scene.h"
// View
#include "view_bitmap.h"
#include "view_bitmap_faber_mp.h"
#include "view_bitmap_combo.h"
#include "view_text.h"
#include "view_text_formated.h"
#include "view_text_id.h"
#include "view_text_id_formated.h"
#include "view_radar.h"
#include "view_pointer.h"
// DBView (View linked to the database)
#include "dbview_bar.h"
#include "dbview_bar3.h"
#include "dbview_number.h"
#include "dbview_quantity.h"
#include "dbview_digit.h"
// Ctrl
#include "ctrl_scroll.h"
#include "ctrl_button.h"
#include "ctrl_col_pick.h"
#include "ctrl_tooltip.h"
#include "ctrl_text_button.h"
#include "group_paragraph.h" // For CCtrlLink
// DBCtrl
#include "dbctrl_sheet.h"
// Group
#include "group_frame.h"
#include "group_career.h"
#include "group_modal.h"
#include "group_modal_get_key.h"
#include "group_list.h"
#include "group_tree.h"
#include "group_menu.h"
#include "group_container.h"
#include "group_scrolltext.h"
#include "group_editbox.h"
#include "group_skills.h"
#include "group_html_forum.h"
#include "group_html_mail.h"
#include "group_html_qcm.h"
#include "group_html_cs.h"
#include "group_quick_help.h"
#include "group_compas.h"
#include "group_map.h"
#include "group_in_scene_user_info.h"
#include "group_in_scene_bubble.h"
#include "group_phrase_skill_filter.h"
#include "group_tab.h"
#include "group_table.h"
// DBGroup
#include "dbgroup_select_number.h"
#include "dbgroup_list_sheet.h"
#include "dbgroup_combo_box.h"
#include "dbgroup_list_sheet_trade.h"
#include "dbgroup_list_sheet_mission.h"
#include "guild_manager.h" // for CDBGroupListAscensor
#include "dbgroup_build_phrase.h"
#include "dbgroup_list_sheet_text_phrase.h"
#include "dbgroup_list_sheet_text_phrase_id.h"
#include "dbgroup_list_sheet_text_brick_composition.h"
#include "dbgroup_list_sheet_text_share.h"
#include "dbgroup_list_sheet_bonus_malus.h"
#include "dbgroup_list_sheet_icon_phrase.h"
// Misc.
#include "interface_link.h"
#include "interface_ddx.h"
#include "../actions.h"
#include "macrocmd_manager.h"
#include "inventory_manager.h"
#include "task_bar_manager.h"
#include "../commands.h"
#include "lua_helper.h"
#include "lua_ihm.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 = (uint32) 'IUG_';
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;
}
// ----------------------------------------------------------------------------
extern CActionsManager Actions; // Actions Manager.
extern CActionsManager EditActions; // Actions Manager.
extern CActionsContext ActionsContext; // Actions context.
// ----------------------------------------------------------------------------
using namespace NLMISC;
using namespace std;
// ----------------------------------------------------------------------------
// CRootGroup
// ----------------------------------------------------------------------------
class CRootGroup : public CInterfaceGroup
{
public:
CRootGroup(const TCtorParam ¶m)
: CInterfaceGroup(param)
{ }
/// Destructor
virtual ~CRootGroup() { }
virtual CInterfaceElement* getElement (const std::string &id)
{
if (_Id == id)
return this;
if (id.substr(0, _Id.size()) != _Id)
return NULL;
vector::const_iterator itv;
for (itv = _Views.begin(); itv != _Views.end(); itv++)
{
CViewBase *pVB = *itv;
if (pVB->getId() == id)
return pVB;
}
vector::const_iterator itc;
for (itc = _Controls.begin(); itc != _Controls.end(); itc++)
{
CCtrlBase* ctrl = *itc;
if (ctrl->getId() == id)
return ctrl;
}
// Accelerate
string sTmp = id;
sTmp = sTmp.substr(_Id.size()+1,sTmp.size());
string::size_type pos = sTmp.find(':');
if (pos != string::npos)
sTmp = sTmp.substr(0,pos);
map::iterator it = _Accel.find(sTmp);
if (it != _Accel.end())
{
CInterfaceGroup *pIG = it->second;
return pIG->getElement(id);
}
return NULL;
}
virtual void addGroup (CInterfaceGroup *child, sint eltOrder = -1)
{
string sTmp = child->getId();
sTmp = sTmp.substr(_Id.size()+1,sTmp.size());
_Accel.insert(pair(sTmp, child));
CInterfaceGroup::addGroup(child,eltOrder);
}
virtual bool delGroup (CInterfaceGroup *child, bool dontDelete = false)
{
string sTmp = child->getId();
sTmp = sTmp.substr(_Id.size()+1,sTmp.size());
map::iterator it = _Accel.find(sTmp);
if (it != _Accel.end())
{
_Accel.erase(it);
}
return CInterfaceGroup::delGroup(child,dontDelete);
}
private:
map _Accel;
};
// ----------------------------------------------------------------------------
// SMasterGroup
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void CInterfaceParser::SMasterGroup::addWindow(CInterfaceGroup *pIG, uint8 nPrio)
{
nlassert(nPrio(pIG)!=NULL));
for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
{
list::iterator it = PrioritizedWindows[i].begin();
while (it != PrioritizedWindows[i].end())
{
// If the element already exists in the list return !
if (*it == pIG)
return;
it++;
}
}
PrioritizedWindows[nPrio].push_back(pIG);
}
// ----------------------------------------------------------------------------
void CInterfaceParser::SMasterGroup::delWindow(CInterfaceGroup *pIG)
{
for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
{
list::iterator it = PrioritizedWindows[i].begin();
while (it != PrioritizedWindows[i].end())
{
if ((*it) == pIG)
{
PrioritizedWindows[i].erase(it);
return;
}
it++;
}
}
}
// ----------------------------------------------------------------------------
CInterfaceGroup* CInterfaceParser::SMasterGroup::getWindowFromId(const std::string &winID)
{
for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
{
list::iterator it = PrioritizedWindows[i].begin();
while (it != PrioritizedWindows[i].end())
{
if ((*it)->getId() == winID)
return *it;
it++;
}
}
return NULL;
}
// ----------------------------------------------------------------------------
bool CInterfaceParser::SMasterGroup::isWindowPresent(CInterfaceGroup *pIG)
{
for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
{
list::iterator it = PrioritizedWindows[i].begin();
while (it != PrioritizedWindows[i].end())
{
if ((*it) == pIG)
return true;
it++;
}
}
return false;
}
// Set a window top in its priority queue
// ----------------------------------------------------------------------------
void CInterfaceParser::SMasterGroup::setTopWindow(CInterfaceGroup *pIG)
{
for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
{
list::iterator it = PrioritizedWindows[i].begin();
while (it != PrioritizedWindows[i].end())
{
if (*it == pIG)
{
PrioritizedWindows[i].erase(it);
PrioritizedWindows[i].push_back(pIG);
LastTopWindowPriority= i;
return;
}
it++;
}
}
// todo hulud interface syntax error
nlwarning("window %s do not exist in a priority list", pIG->getId().c_str());
}
// ----------------------------------------------------------------------------
void CInterfaceParser::SMasterGroup::setBackWindow(CInterfaceGroup *pIG)
{
for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
{
list::iterator it = PrioritizedWindows[i].begin();
while (it != PrioritizedWindows[i].end())
{
if (*it == pIG)
{
PrioritizedWindows[i].erase(it);
PrioritizedWindows[i].push_front(pIG);
return;
}
it++;
}
}
// todo hulud interface syntax error
nlwarning("window %s do not exist in a priority list", pIG->getId().c_str());
}
// ----------------------------------------------------------------------------
void CInterfaceParser::SMasterGroup::deactiveAllContainers()
{
vector gcs;
// Make first a list of all window (Warning: all group container are not window!)
for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
{
list::iterator it = PrioritizedWindows[i].begin();
while (it != PrioritizedWindows[i].end())
{
CGroupContainer *pGC = dynamic_cast(*it);
if (pGC != NULL)
gcs.push_back(pGC);
it++;
}
}
// Then hide them. Must do this in 2 times, because setActive(false) change PrioritizedWindows,
// and hence invalidate its.
for (uint32 i = 0; i < gcs.size(); ++i)
{
gcs[i]->setActive(false);
}
}
// ----------------------------------------------------------------------------
void CInterfaceParser::SMasterGroup::centerAllContainers()
{
for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
{
list::iterator it = PrioritizedWindows[i].begin();
while (it != PrioritizedWindows[i].end())
{
CGroupContainer *pGC = dynamic_cast(*it);
if ((pGC != NULL) && (pGC->getParent() != NULL))
{
sint32 wParent = pGC->getParent()->getW(false);
sint32 w = pGC->getW(false);
pGC->setXAndInvalidateCoords((wParent - w) / 2);
sint32 hParent = pGC->getParent()->getH(false);
sint32 h = pGC->getH(false);
pGC->setYAndInvalidateCoords(h+(hParent - h) / 2);
}
it++;
}
}
}
// ----------------------------------------------------------------------------
void CInterfaceParser::SMasterGroup::unlockAllContainers()
{
for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
{
list::iterator it = PrioritizedWindows[i].begin();
while (it != PrioritizedWindows[i].end())
{
CGroupContainer *pGC = dynamic_cast(*it);
if (pGC != NULL)
pGC->setLocked(false);
it++;
}
}
}
// ----------------------------------------------------------------------------
// CInterfaceParser
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
CInterfaceParser::CInterfaceParser()
{
_Pointer= NULL;
// LUA
_LuaState= NULL;
}
CInterfaceParser::~CInterfaceParser()
{
// delete _Pointer;
_Pointer = NULL;
delete _LuaState;
_LuaState = 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((const uint8 *) &script[0]), script.size());
destStream.invert();
destStream.seek(0, NLMISC::IStream::begin);
}
// ----------------------------------------------------------------------------
bool CInterfaceParser::parseInterface (const std::vector & strings, bool reload, bool isFilename)
{
bool ok;
// 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 = "