// 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 "nel/misc/big_file.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"
#include "../r2/editor.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_';
using namespace NLMISC;
void badLuaParseMessageBox()
{
NL3D::UDriver::TMessageBoxId ret = Driver->systemMessageBox( "LUA files reading failed!\n"
"Some LUA files are corrupted, moved or may have been removed.\n"
"Ryzom may need to be restarted to run properly.\n"
"Would you like to quit now?",
"LUA reading failed!",
NL3D::UDriver::yesNoType,
NL3D::UDriver::exclamationIcon);
if (ret == NL3D::UDriver::yesId)
{
extern void quitCrashReport ();
quitCrashReport ();
exit (EXIT_FAILURE);
}
}
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]), (uint)script.size());
destStream.invert();
destStream.seek(0, NLMISC::IStream::begin);
}
// ----------------------------------------------------------------------------
bool CInterfaceParser::parseInterface (const std::vector & strings, bool reload, bool isFilename, bool checkInData)
{
bool ok;
bool needCheck = checkInData;
#if !FINAL_VERSION
needCheck = false;
#endif
// TestYoyo. UnHide For Parsing Profile
/*
NLMISC::CHTimer::startBench();
{
H_AUTO(parseInterface);
*/
//ignore the content of tags containing only white space
xmlKeepBlanksDefault(0);
//parse all interface files and build a single xml document
xmlNodePtr globalEnclosing;
nlassert (strings.size());
CIXml read;
string nextFileName;
static const char *SCRIPT_AS_STRING = "