mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-12-20 16:08:44 +00:00
CHANGED: #1471 CInterfaceExpr, CInterfaceExprNode and related classes are now in NELGUI and under NLGUI namespace.
--HG-- branch : gui-refactoring
This commit is contained in:
parent
4284b5f4d5
commit
2db0a5d06e
39 changed files with 1607 additions and 1604 deletions
239
code/nel/include/nel/gui/interface_expr.h
Normal file
239
code/nel/include/nel/gui/interface_expr.h
Normal file
|
@ -0,0 +1,239 @@
|
|||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef CL_INTERFACE_EXPR_H
|
||||
#define CL_INTERFACE_EXPR_H
|
||||
|
||||
|
||||
#include "nel/misc/ucstring.h"
|
||||
#include "nel/misc/rgba.h"
|
||||
|
||||
namespace NLMISC{
|
||||
class ICDBNode;
|
||||
class CCDBNodeLeaf;
|
||||
class CCDBNodeBranch;
|
||||
}
|
||||
|
||||
namespace NLGUI
|
||||
{
|
||||
|
||||
struct CInterfaceExprUserType;
|
||||
class CInterfaceExprNode;
|
||||
|
||||
/** a value that can be returned by a CInterfaceExpr instance
|
||||
* It supports basic type;
|
||||
* It can be extended by user defined types
|
||||
*/
|
||||
class CInterfaceExprValue
|
||||
{
|
||||
public:
|
||||
enum TType { Boolean = 0, Integer, Double, String, RGBA, UserType, NoType };
|
||||
public:
|
||||
// default ctor
|
||||
CInterfaceExprValue() : _Type(NoType) {}
|
||||
// copy ctor
|
||||
CInterfaceExprValue(const CInterfaceExprValue &other);
|
||||
// assignment operator
|
||||
CInterfaceExprValue &operator = (const CInterfaceExprValue &other);
|
||||
// dtor
|
||||
~CInterfaceExprValue() { clean(); }
|
||||
|
||||
TType getType() const { return _Type; }
|
||||
// get. Should be used only if the type is valid
|
||||
bool getBool() const;
|
||||
sint64 getInteger() const;
|
||||
double getDouble() const;
|
||||
std::string getString() const;
|
||||
NLMISC::CRGBA getRGBA() const;
|
||||
const ucstring &getUCString() const;
|
||||
CInterfaceExprUserType *getUserType() const;
|
||||
// set
|
||||
void setBool(bool value) { clean(); _Type = Boolean; _BoolValue = value; }
|
||||
void setInteger(sint64 value) { clean(); _Type = Integer; _IntegerValue = value; }
|
||||
void setDouble(double value) { clean(); _Type = Double; _DoubleValue = value; }
|
||||
void setString(const std::string &value) { clean(); _Type = String; _StringValue = value; }
|
||||
void setUCString(const ucstring &value) { clean(); _Type = String; _StringValue = value; }
|
||||
void setRGBA(NLMISC::CRGBA value) { clean(); _Type = RGBA; _RGBAValue = (uint32)(value.R+(value.G<<8)+(value.B<<16)+(value.A<<24)); }
|
||||
void setUserType(CInterfaceExprUserType *value);
|
||||
// reset this object to initial state (no type)
|
||||
void clean();
|
||||
// conversions. They return true if success
|
||||
bool toBool();
|
||||
bool toInteger();
|
||||
bool toDouble();
|
||||
bool toString();
|
||||
bool toType(TType type);
|
||||
bool toRGBA();
|
||||
// test if the value if a bool, double, or integer
|
||||
bool isNumerical() const;
|
||||
/** evaluate a from a string
|
||||
* \param expr : where to start the evaluation
|
||||
* \return the position following the token, or NULL if the parsing failed
|
||||
*/
|
||||
const char *initFromString(const char *expr);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private:
|
||||
TType _Type;
|
||||
union
|
||||
{
|
||||
bool _BoolValue;
|
||||
sint64 _IntegerValue;
|
||||
double _DoubleValue;
|
||||
CInterfaceExprUserType *_UserTypeValue;
|
||||
uint32 _RGBAValue;
|
||||
};
|
||||
ucstring _StringValue; // well, can't fit in union, unless we do some horrible hack..
|
||||
private:
|
||||
const char *evalBoolean(const char *expr);
|
||||
const char *evalNumber(const char *expr);
|
||||
const char *evalString(const char *expr);
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for user defined types that are use by the 'CInterfaceExprValue' class
|
||||
* Derivers should include the 'clone' method
|
||||
*
|
||||
* CInterfaceExprValue instances have ownership of this object.
|
||||
*
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2003
|
||||
*/
|
||||
struct CInterfaceExprUserType
|
||||
{
|
||||
// cloning method
|
||||
virtual CInterfaceExprUserType *clone() const = 0;
|
||||
// dtor
|
||||
virtual ~CInterfaceExprUserType() {}
|
||||
};
|
||||
|
||||
|
||||
/** Evaluate expressions used in interface.
|
||||
* It can retrieve values from the database.
|
||||
* It can also build a list of database values it depends of.
|
||||
*
|
||||
* An expression can be :
|
||||
*
|
||||
* - a string : 'toto', 'abcd', 'a\nbcd', 'a\\t', the escape sequences are the one of C
|
||||
* - a integer 1, 2, 3
|
||||
* - a double 1.1, 2.2
|
||||
* - a database entry : @ui:interface:toto:truc. If the address is a leaf, it returns the leaf value and put an observer on it. If not a leaf, it returns 0, but put an observer on it.
|
||||
* - a database indirection @db:value[db:index] is replaced by @db:value0 if db:index == 0 for example
|
||||
* - a user function call : fct(expr0, epxr1, ...).
|
||||
*
|
||||
* NB : The lua language has been integrated since then (2005), and should be more suited
|
||||
* for most of the tasks.
|
||||
*
|
||||
*
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2002
|
||||
*/
|
||||
class CInterfaceExpr
|
||||
{
|
||||
public:
|
||||
// list of argument for a function
|
||||
typedef std::vector<CInterfaceExprValue> TArgList;
|
||||
/** prototype of a user callable function
|
||||
* It should return true if the result is meaningful. If not, the rest of the evaluation is stopped
|
||||
*/
|
||||
typedef bool (* TUserFct) (TArgList &args, CInterfaceExprValue &result);
|
||||
public:
|
||||
|
||||
// release memory
|
||||
static void release();
|
||||
|
||||
/** This try to eval the provided expression.
|
||||
* - This returns a result
|
||||
* - This eventually fill a vector with a set of database entries it has dependencies on
|
||||
* \param expr The expression to evaluate
|
||||
* \param result The result value
|
||||
* \param nodes If not NULL, will be filled with the database nodes this expression depends on
|
||||
* Node will only be inserted once, so we end up with a set of node (not ordered)
|
||||
* \param noFctCalls when set to true, the terminal function calls will not be made, so the evaluation is only used to see which database entries the expression depends on.
|
||||
*/
|
||||
static bool eval(const std::string &expr, CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> *nodes = NULL, bool noFctCalls = false);
|
||||
|
||||
/** Build a tree from the given expression so that it can be evaluated quickly.
|
||||
* This is useful for a fixed expression that must be evaluated often
|
||||
*/
|
||||
static CInterfaceExprNode *buildExprTree(const std::string &expr);
|
||||
|
||||
|
||||
/** Register a function that can have several arguments
|
||||
* // NB : this is case sensitive
|
||||
*/
|
||||
static void registerUserFct(const char *name, TUserFct fct);
|
||||
// Simple evaluations
|
||||
static bool evalAsInt(const std::string &expr, sint64 &dest);
|
||||
static bool evalAsDouble(const std::string &expr, double &dest);
|
||||
static bool evalAsBool(const std::string &expr, bool &dest);
|
||||
static bool evalAsString(const std::string &expr, std::string &dest);
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private:
|
||||
// map of user functions
|
||||
typedef std::map<std::string, TUserFct> TUserFctMap;
|
||||
private:
|
||||
static TUserFctMap *_UserFct;
|
||||
private:
|
||||
/** eval the value of a single expression
|
||||
* \return position to the next valid character
|
||||
*/
|
||||
static const char *evalExpr(const char *expr, CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> *nodes, bool noFctCalls);
|
||||
static const char *evalFct(const char *expr,CInterfaceExprValue &result,std::vector<NLMISC::ICDBNode *> *nodes, bool noFctCalls);
|
||||
static const char *evalDBEntry(const char *expr,CInterfaceExprValue &result,std::vector<NLMISC::ICDBNode *> *nodes);
|
||||
public:
|
||||
static const char *unpackDBentry(const char *expr, std::vector<NLMISC::ICDBNode *> *nodes, std::string &dest, bool *hasIndirections = NULL);
|
||||
|
||||
/** Build tree of a single expression
|
||||
* \return position to the next valid character
|
||||
*/
|
||||
private:
|
||||
static const char *buildExprTree(const char *expr, CInterfaceExprNode *&result);
|
||||
static const char *buildFctNode(const char *expr, CInterfaceExprNode *&result);
|
||||
static const char *buildDBEntryNode(const char *expr,CInterfaceExprNode *&result);
|
||||
};
|
||||
|
||||
|
||||
// helper macro to register user functions at startup
|
||||
#define REGISTER_INTERFACE_USER_FCT(name, fct) \
|
||||
const struct __InterUserFctRegister__##fct\
|
||||
{\
|
||||
__InterUserFctRegister__##fct() { CInterfaceExpr::registerUserFct(name, fct); }\
|
||||
} __InterUserFctRegisterInstance__##fct;
|
||||
|
||||
|
||||
// helper macro to declare a user function
|
||||
// the code must follow
|
||||
// arguments are available in 'args', result should be put in 'result'
|
||||
#define DECLARE_INTERFACE_USER_FCT(name) \
|
||||
bool name(CInterfaceExpr::TArgList &args, CInterfaceExprValue &result)
|
||||
|
||||
|
||||
// helper macro to declare a C constant mirroring
|
||||
#define DECLARE_INTERFACE_CONSTANT(_name, _cconst) \
|
||||
static DECLARE_INTERFACE_USER_FCT(_name) \
|
||||
{ \
|
||||
result.setInteger(_cconst); \
|
||||
return true; \
|
||||
} \
|
||||
REGISTER_INTERFACE_USER_FCT(#_name, _name)
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
118
code/nel/include/nel/gui/interface_expr_node.h
Normal file
118
code/nel/include/nel/gui/interface_expr_node.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
#ifndef CL_INTERFACE_EXPR_NODE_H
|
||||
#define CL_INTERFACE_EXPR_NODE_H
|
||||
|
||||
#include "interface_expr.h"
|
||||
|
||||
namespace NLGUI
|
||||
{
|
||||
|
||||
/** Base node of an interface expression parse tree
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2003
|
||||
*/
|
||||
class CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
virtual ~CInterfaceExprNode() {}
|
||||
// eval result of expression, and eventually get the nodes the epression depends on
|
||||
virtual void eval(CInterfaceExprValue &result) = 0;
|
||||
// The same, but get db nodes the expression depends on (appended to vector)
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes) = 0;
|
||||
// Get dependencies of the node (appended to vector)
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes) = 0;
|
||||
};
|
||||
|
||||
|
||||
// *******************************************************************************************************
|
||||
/** A constant value already parsed by interface (in a interface expr parse tree)
|
||||
*/
|
||||
class CInterfaceExprNodeValue : public CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
CInterfaceExprValue Value;
|
||||
public:
|
||||
virtual void eval(CInterfaceExprValue &result);
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
};
|
||||
|
||||
// *******************************************************************************************************
|
||||
/** A fct call (in a interface expr parse tree)
|
||||
*/
|
||||
class CInterfaceExprNodeValueFnCall : public CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
CInterfaceExpr::TUserFct Func;
|
||||
// list of parameters
|
||||
std::vector<CInterfaceExprNode *> Params;
|
||||
public:
|
||||
virtual void eval(CInterfaceExprValue &result);
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual ~CInterfaceExprNodeValueFnCall();
|
||||
};
|
||||
|
||||
// *******************************************************************************************************
|
||||
/** A db leaf read (in a interface expr parse tree)
|
||||
*/
|
||||
class CInterfaceExprNodeDBLeaf : public CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
class NLMISC::CCDBNodeLeaf *Leaf;
|
||||
public:
|
||||
virtual void eval(CInterfaceExprValue &result);
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
};
|
||||
|
||||
// *******************************************************************************************************
|
||||
/** A db branch read (in a interface expr parse tree)
|
||||
*/
|
||||
class CInterfaceExprNodeDBBranch : public CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
class NLMISC::CCDBNodeBranch *Branch;
|
||||
public:
|
||||
virtual void eval(CInterfaceExprValue &result);
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
};
|
||||
|
||||
// *******************************************************************************************************
|
||||
/** A dependant db read (in a interface expr parse tree)
|
||||
* This is rarely used so no real optim there..
|
||||
*/
|
||||
class CInterfaceExprNodeDependantDBRead : public CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
std::string Expr;
|
||||
public:
|
||||
virtual void eval(CInterfaceExprValue &result);
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -326,6 +326,8 @@ public:
|
|||
void buildFromHLS(float h, float l, float s);
|
||||
//@}
|
||||
|
||||
static CRGBA stringToRGBA( const char *ptr );
|
||||
|
||||
|
||||
/// Swap the B and R components, to simulate a CBRGA
|
||||
void swapBR()
|
||||
|
|
939
code/nel/src/gui/interface_expr.cpp
Normal file
939
code/nel/src/gui/interface_expr.cpp
Normal file
|
@ -0,0 +1,939 @@
|
|||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "nel/misc/algo.h"
|
||||
#include <algorithm>
|
||||
#include "nel/gui/db_manager.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "nel/gui/interface_expr_node.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace NLMISC;
|
||||
|
||||
namespace NLGUI
|
||||
{
|
||||
|
||||
// Yoyo: Act like a singleton, else registerUserFct may crash.
|
||||
CInterfaceExpr::TUserFctMap *CInterfaceExpr::_UserFct= NULL;
|
||||
|
||||
static const std::string ExprLuaId="lua:";
|
||||
|
||||
//==================================================================
|
||||
// release memory
|
||||
void CInterfaceExpr::release()
|
||||
{
|
||||
delete _UserFct;
|
||||
_UserFct = NULL;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
void formatLuaCall(const std::string &expr, std::string &tempStr)
|
||||
{
|
||||
/* Call the LUA interface exp fct, with the script as line, and resolve string definition conflicts:
|
||||
eg: replace
|
||||
lua:getSkillFromName('SM')
|
||||
into
|
||||
lua('getSkillFromName(\"SM\")')
|
||||
*/
|
||||
tempStr= expr.substr(ExprLuaId.size()); // eg: tempStr= getSkillFromName('SM')
|
||||
while(strFindReplace(tempStr, "'", "\\\"")); // eg: tempStr= getSkillFromName(\"SM\")
|
||||
tempStr= string("lua('") + tempStr + "')"; // eg: tempStr= lua('getSkillFromName(\"SM\")')
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExpr::eval(const std::string &expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes, bool noFctCalls /* = false */)
|
||||
{
|
||||
// Yoyo: Special InterfaceExpr Form to execute lua code?
|
||||
if(expr.compare(0, ExprLuaId.size(), ExprLuaId) ==0 )
|
||||
{
|
||||
std::string tempStr;
|
||||
formatLuaCall(expr, tempStr);
|
||||
return evalExpr(tempStr.c_str(), result, nodes, noFctCalls) != NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return evalExpr(expr.c_str(), result, nodes, noFctCalls) != NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
CInterfaceExprNode *CInterfaceExpr::buildExprTree(const std::string &expr)
|
||||
{
|
||||
CInterfaceExprNode *node;
|
||||
|
||||
// Yoyo: Special InterfaceExpr Form to execute lua code?
|
||||
if(expr.compare(0, ExprLuaId.size(), ExprLuaId) ==0 )
|
||||
{
|
||||
std::string tempStr;
|
||||
formatLuaCall(expr, tempStr);
|
||||
if (!buildExprTree(tempStr.c_str(), node)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!buildExprTree(expr.c_str(), node)) return false;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
//==================================================================
|
||||
void CInterfaceExpr::registerUserFct(const char *name,TUserFct fct)
|
||||
{
|
||||
if(!_UserFct) _UserFct= new TUserFctMap;
|
||||
|
||||
nlassert(fct != NULL);
|
||||
(*_UserFct)[std::string(name)] = fct;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
/** tool fct : skip space, tab and carret-returns
|
||||
*/
|
||||
static const char *skipBlank(const char *start)
|
||||
{
|
||||
nlassert(start);
|
||||
while (*start == ' ' || *start == '\t' || *start == '\r' || *start == '\n') ++start;
|
||||
return start;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::evalExpr(const char *expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes, bool noFctCalls)
|
||||
{
|
||||
nlassert(expr != NULL);
|
||||
expr = skipBlank(expr);
|
||||
if (isalpha(*expr)) // alpha character means this is a function name
|
||||
{
|
||||
return evalFct(expr, result, nodes, noFctCalls);
|
||||
}
|
||||
else if (*expr == '@') // is it a database entry ?
|
||||
{
|
||||
++ expr;
|
||||
expr = skipBlank(expr);
|
||||
return evalDBEntry(expr, result, nodes);
|
||||
}
|
||||
|
||||
// try to parse a literal value
|
||||
const char *newExpr = result.initFromString(expr);
|
||||
if (!newExpr)
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalExpr> : syntax error : %s", expr);
|
||||
return NULL;
|
||||
}
|
||||
return newExpr;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::buildExprTree(const char *expr, CInterfaceExprNode *&result)
|
||||
{
|
||||
nlassert(expr != NULL);
|
||||
expr = skipBlank(expr);
|
||||
if (isalpha(*expr)) // alpha character means this is a function name
|
||||
{
|
||||
return buildFctNode(expr, result);
|
||||
}
|
||||
else if (*expr == '@') // is it a database entry ?
|
||||
{
|
||||
++ expr;
|
||||
expr = skipBlank(expr);
|
||||
return buildDBEntryNode(expr, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
CInterfaceExprValue value;
|
||||
// try to parse a literal value
|
||||
const char *newExpr = value.initFromString(expr);
|
||||
if (!newExpr)
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::buildExprTree> : syntax error : %s", expr);
|
||||
return NULL;
|
||||
}
|
||||
CInterfaceExprNodeValue *node = new CInterfaceExprNodeValue;
|
||||
node->Value = value;
|
||||
result = node;
|
||||
return newExpr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::evalFct(const char *expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes, bool noFctCalls)
|
||||
{
|
||||
if(!_UserFct) _UserFct= new TUserFctMap;
|
||||
|
||||
const char *start = expr;
|
||||
while (isalnum(*expr)) ++ expr;
|
||||
std::string fctName(start, expr - start);
|
||||
// find entry in the map
|
||||
TUserFctMap::iterator fctIt = _UserFct->find(fctName);
|
||||
if (fctIt == _UserFct->end())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalFct> : Unknown function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
nlassert(fctIt->second != NULL);
|
||||
// eval list of arguments
|
||||
TArgList argList;
|
||||
expr = skipBlank(expr);
|
||||
if (*expr != '(')
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalFct> : '(' expected for function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
++ expr;
|
||||
expr = skipBlank(expr);
|
||||
if (*expr != ')')
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
expr = skipBlank(expr);
|
||||
// parse an argument
|
||||
argList.push_back(CInterfaceExprValue());
|
||||
expr = evalExpr(expr, argList.back(), nodes, noFctCalls);
|
||||
if (expr == NULL) return NULL;
|
||||
expr = skipBlank(expr);
|
||||
if (*expr == ')') break;
|
||||
// if it isn't the end of the expression, then we should find a ',' before next argument
|
||||
if (*expr != ',')
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalFct> : ',' expected in function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
++ expr;
|
||||
}
|
||||
}
|
||||
++ expr;
|
||||
// call the fct
|
||||
if (!noFctCalls) // should we make terminal function calls ?
|
||||
{
|
||||
if (fctIt->second(argList, result)) return expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return expr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::buildFctNode(const char *expr, CInterfaceExprNode *&result)
|
||||
{
|
||||
if(!_UserFct) _UserFct= new TUserFctMap;
|
||||
|
||||
const char *start = expr;
|
||||
while (isalnum(*expr)) ++ expr;
|
||||
std::string fctName(start, expr - start);
|
||||
// find entry in the map
|
||||
TUserFctMap::iterator fctIt = _UserFct->find(fctName);
|
||||
if (fctIt == _UserFct->end())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::buildFctNode> : Unknown function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
nlassert(fctIt->second != NULL);
|
||||
// List of parameters
|
||||
expr = skipBlank(expr);
|
||||
if (*expr != '(')
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::buildFctNode> : '(' expected for function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
++ expr;
|
||||
expr = skipBlank(expr);
|
||||
std::vector<CInterfaceExprNode *> Params;
|
||||
if (*expr != ')')
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
expr = skipBlank(expr);
|
||||
// parse an argument
|
||||
CInterfaceExprNode *node = NULL;
|
||||
expr = buildExprTree(expr, node);
|
||||
if (expr == NULL)
|
||||
{
|
||||
for(uint k = 0; k < Params.size(); ++k)
|
||||
{
|
||||
delete Params[k];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
Params.push_back(node);
|
||||
expr = skipBlank(expr);
|
||||
if (*expr == ')') break;
|
||||
// if it isn't the end of the expression, then we should find a ',' before next argument
|
||||
if (*expr != ',')
|
||||
{
|
||||
for(uint k = 0; k < Params.size(); ++k)
|
||||
{
|
||||
delete Params[k];
|
||||
}
|
||||
nlwarning("CInterfaceExpr::evalFct : ',' expected in function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
++ expr;
|
||||
}
|
||||
}
|
||||
++ expr;
|
||||
CInterfaceExprNodeValueFnCall *node = new CInterfaceExprNodeValueFnCall;
|
||||
node->Params.swap(Params);
|
||||
node->Func = fctIt->second;
|
||||
result = node;
|
||||
return expr;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::evalDBEntry(const char *expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes)
|
||||
{
|
||||
std::string dbEntry;
|
||||
expr = unpackDBentry(expr, nodes, dbEntry);
|
||||
if (!expr) return NULL;
|
||||
// TestYoyo
|
||||
//nlassert(NLGUI::CDBManager::getInstance()->getDbProp(dbEntry, false) || CInterfaceManager::getInstance()->getDbBranch(dbEntry));
|
||||
// get the db value
|
||||
CCDBNodeLeaf *nl = NLGUI::CDBManager::getInstance()->getDbProp(dbEntry);
|
||||
if (nl)
|
||||
{
|
||||
if (nodes)
|
||||
{
|
||||
// insert node if not already present
|
||||
if (std::find(nodes->begin(), nodes->end(), nl) == nodes->end())
|
||||
{
|
||||
nodes->push_back(nl);
|
||||
}
|
||||
}
|
||||
result.setInteger(nl->getValue64());
|
||||
return expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCDBNodeBranch *nb = NLGUI::CDBManager::getInstance()->getDbBranch(dbEntry);
|
||||
if (nodes && nb)
|
||||
{
|
||||
if (std::find(nodes->begin(), nodes->end(), nb) == nodes->end())
|
||||
{
|
||||
nodes->push_back(nb);
|
||||
}
|
||||
}
|
||||
if (!nb) return NULL;
|
||||
result.setInteger(0);
|
||||
return expr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::buildDBEntryNode(const char *expr, CInterfaceExprNode *&result)
|
||||
{
|
||||
std::string dbEntry;
|
||||
bool indirection;
|
||||
const char *startChar = expr;
|
||||
expr = unpackDBentry(expr, NULL, dbEntry, &indirection);
|
||||
if (!expr) return NULL;
|
||||
if (indirection)
|
||||
{
|
||||
// special node with no optimisation
|
||||
CInterfaceExprNodeDependantDBRead *node = new CInterfaceExprNodeDependantDBRead;
|
||||
node->Expr.resize(expr - startChar + 1);
|
||||
std::copy(startChar, expr, node->Expr.begin() + 1);
|
||||
node->Expr[0] = '@';
|
||||
result = node;
|
||||
return expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TestYoyo
|
||||
//nlassert(NLGUI::CDBManager::getInstance()->getDbProp(dbEntry, false) || CInterfaceManager::getInstance()->getDbBranch(dbEntry));
|
||||
CCDBNodeLeaf *nl = NLGUI::CDBManager::getInstance()->getDbProp(dbEntry);
|
||||
if (nl)
|
||||
{
|
||||
CInterfaceExprNodeDBLeaf *node = new CInterfaceExprNodeDBLeaf;
|
||||
node->Leaf = nl;
|
||||
result = node;
|
||||
return expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCDBNodeBranch *nb = NLGUI::CDBManager::getInstance()->getDbBranch(dbEntry);
|
||||
if (nb)
|
||||
{
|
||||
CInterfaceExprNodeDBBranch *node = new CInterfaceExprNodeDBBranch;
|
||||
node->Branch = nb;
|
||||
result = node;
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::unpackDBentry(const char *expr, std::vector<ICDBNode *> *nodes, std::string &dest, bool *hasIndirections /* = NULL*/)
|
||||
{
|
||||
std::string entryName;
|
||||
bool indirection = false;
|
||||
for (;;)
|
||||
{
|
||||
if (*expr == '[')
|
||||
{
|
||||
indirection = true;
|
||||
++ expr;
|
||||
std::string subEntry;
|
||||
expr = unpackDBentry(expr, nodes, subEntry);
|
||||
if (!expr) return NULL;
|
||||
// Read DB Index Offset.
|
||||
sint32 indirectionOffset= 0;
|
||||
if (*expr == '-' || *expr =='+' )
|
||||
{
|
||||
bool negative= *expr == '-';
|
||||
std::string offsetString;
|
||||
++ expr;
|
||||
while(*expr!=0 && isdigit(*expr))
|
||||
{
|
||||
offsetString.push_back(*expr);
|
||||
++ expr;
|
||||
}
|
||||
// get offset
|
||||
fromString(offsetString, indirectionOffset);
|
||||
if(negative)
|
||||
indirectionOffset= -indirectionOffset;
|
||||
}
|
||||
// Test end of indirection
|
||||
if (*expr != ']')
|
||||
{
|
||||
nlwarning("CInterfaceExpr::unpackDBentry: ']' expected");
|
||||
return NULL;
|
||||
}
|
||||
++ expr;
|
||||
// get the db value at sub entry
|
||||
// TestYoyo
|
||||
//nlassert(NLGUI::CDBManager::getInstance()->getDbProp(subEntry, false) || CInterfaceManager::getInstance()->getDbBranch(subEntry));
|
||||
CCDBNodeLeaf *nl = NLGUI::CDBManager::getInstance()->getDbProp(subEntry);
|
||||
if (nodes)
|
||||
{
|
||||
if (std::find(nodes->begin(), nodes->end(), nl) == nodes->end())
|
||||
{
|
||||
nodes->push_back(nl);
|
||||
}
|
||||
}
|
||||
// compute indirection, (clamp).
|
||||
sint32 indirectionValue= nl->getValue32() + indirectionOffset;
|
||||
indirectionValue= std::max((sint32)0, indirectionValue);
|
||||
|
||||
// Append to entry name.
|
||||
entryName += NLMISC::toString(indirectionValue);
|
||||
}
|
||||
else if (isalnum(*expr) || *expr == '_' || *expr == ':')
|
||||
{
|
||||
entryName += *expr;
|
||||
++ expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasIndirections)
|
||||
{
|
||||
*hasIndirections = indirection;
|
||||
}
|
||||
dest = entryName;
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExpr::evalAsInt(const std::string &expr, sint64 &dest)
|
||||
{
|
||||
CInterfaceExprValue result;
|
||||
if (!eval(expr, result)) return false;
|
||||
if (!result.toInteger())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalAsInt> Can't convert value to an integer, expr = %s", expr.c_str());
|
||||
return false;
|
||||
}
|
||||
dest = result.getInteger();
|
||||
return true;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExpr::evalAsDouble(const std::string &expr, double &dest)
|
||||
{
|
||||
CInterfaceExprValue result;
|
||||
if (!eval(expr, result)) return false;
|
||||
if (!result.toDouble())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalAsDouble> Can't convert value to a double, expr = %s", expr.c_str());
|
||||
return false;
|
||||
}
|
||||
dest = result.getDouble();
|
||||
return true;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExpr::evalAsBool(const std::string &expr, bool &dest)
|
||||
{
|
||||
CInterfaceExprValue result;
|
||||
if (!eval(expr, result)) return false;
|
||||
if (!result.toBool())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalAsBool> Can't convert value to a boolean, expr = %s", expr.c_str());
|
||||
return false;
|
||||
}
|
||||
dest = result.getBool();
|
||||
return true;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExpr::evalAsString(const std::string &expr, std::string &dest)
|
||||
{
|
||||
CInterfaceExprValue result;
|
||||
if (!eval(expr, result)) return false;
|
||||
if (!result.toString())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalAsString> Can't convert value to a string, expr = %s", expr.c_str());
|
||||
return false;
|
||||
}
|
||||
dest = result.getString();
|
||||
return true;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
//==================================================================
|
||||
//==================================================================
|
||||
//==================================================================
|
||||
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toBool()
|
||||
{
|
||||
switch(_Type)
|
||||
{
|
||||
case Boolean: return true;
|
||||
case Integer: setBool(_IntegerValue != 0); return true;
|
||||
case Double: setBool(_DoubleValue != 0); return true;
|
||||
case String: return evalBoolean(_StringValue.toString().c_str()) != NULL;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toInteger()
|
||||
{
|
||||
switch(_Type)
|
||||
{
|
||||
case Boolean: setInteger(_BoolValue ? 1 : 0); return true;
|
||||
case Integer: return true;
|
||||
case Double: setInteger((sint64) _DoubleValue); return true;
|
||||
case String:
|
||||
if (evalNumber(_StringValue.toString().c_str())) return toInteger();
|
||||
return false;
|
||||
case RGBA: setInteger((sint64) _RGBAValue); return true;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toDouble()
|
||||
{
|
||||
switch(_Type)
|
||||
{
|
||||
case Boolean: setDouble(_BoolValue ? 1 : 0); return true;
|
||||
case Integer: setDouble((double) _IntegerValue); return true;
|
||||
case Double: return true;
|
||||
case String:
|
||||
if (evalNumber(_StringValue.toString().c_str())) return toBool();
|
||||
return false;
|
||||
case RGBA: setDouble((double) _RGBAValue); return true;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toString()
|
||||
{
|
||||
switch(_Type)
|
||||
{
|
||||
case Boolean: setString(_BoolValue ? "true" : "false"); return true;
|
||||
case Integer: setString(NLMISC::toString(_IntegerValue)); return true;
|
||||
case Double: setString(NLMISC::toString("%.2f", _DoubleValue)); return true;
|
||||
case String: return true;
|
||||
case RGBA:
|
||||
{
|
||||
uint r,g,b,a;
|
||||
r= (_RGBAValue&0xff);
|
||||
g= ((_RGBAValue>>8)&0xff);
|
||||
b= ((_RGBAValue>>16)&0xff);
|
||||
a= ((_RGBAValue>>24)&0xff);
|
||||
setString(NLMISC::toString("%d %d %d %d", r, g, b, a));
|
||||
return true;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toRGBA()
|
||||
{
|
||||
switch(_Type)
|
||||
{
|
||||
case RGBA:
|
||||
return true;
|
||||
|
||||
case Integer:
|
||||
setRGBA(NLMISC::CRGBA((uint8)(_IntegerValue&0xff), (uint8)((_IntegerValue>>8)&0xff),
|
||||
(uint8)((_IntegerValue>>16)&0xff), (uint8)((_IntegerValue>>24)&0xff)));
|
||||
return true;
|
||||
|
||||
case String:
|
||||
setRGBA( NLMISC::CRGBA::stringToRGBA(_StringValue.toString().c_str()));
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::isNumerical() const
|
||||
{
|
||||
return _Type == Boolean || _Type == Integer || _Type == Double;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExprValue::initFromString(const char *expr)
|
||||
{
|
||||
nlassert(expr);
|
||||
expr = skipBlank(expr);
|
||||
if (isdigit(*expr) || *expr == '.' || *expr == '-') return evalNumber(expr);
|
||||
switch(*expr)
|
||||
{
|
||||
case 't':
|
||||
case 'T':
|
||||
case 'f':
|
||||
case 'F':
|
||||
return evalBoolean(expr);
|
||||
case '\'':
|
||||
return evalString(expr);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExprValue::evalBoolean(const char *expr)
|
||||
{
|
||||
nlassert(expr);
|
||||
expr = skipBlank(expr);
|
||||
if (toupper(expr[0]) == 'T' &&
|
||||
toupper(expr[1]) == 'R' &&
|
||||
toupper(expr[2]) == 'U' &&
|
||||
toupper(expr[3]) == 'E')
|
||||
{
|
||||
setBool(true);
|
||||
return expr + 4;
|
||||
}
|
||||
//
|
||||
if (toupper(expr[0]) == 'F' &&
|
||||
toupper(expr[1]) == 'A' &&
|
||||
toupper(expr[2]) == 'L' &&
|
||||
toupper(expr[3]) == 'S' &&
|
||||
toupper(expr[4]) == 'E')
|
||||
{
|
||||
setBool(false);
|
||||
return expr + 5;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExprValue::evalNumber(const char *expr)
|
||||
{
|
||||
bool negative;
|
||||
bool hasPoint = false;
|
||||
|
||||
expr = skipBlank(expr);
|
||||
|
||||
if (*expr == '-')
|
||||
{
|
||||
negative = true;
|
||||
++ expr;
|
||||
expr = skipBlank(expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
negative = false;
|
||||
}
|
||||
|
||||
const char *start = expr;
|
||||
while (*expr == '.' || isdigit(*expr))
|
||||
{
|
||||
if (*expr == '.') hasPoint = true;
|
||||
++ expr;
|
||||
}
|
||||
if (start == expr) return NULL;
|
||||
if (!hasPoint)
|
||||
{
|
||||
sint64 value = 0;
|
||||
// this is an integer
|
||||
for (const char *nbPtr = start; nbPtr < expr; ++ nbPtr)
|
||||
{
|
||||
value *= 10;
|
||||
value += (sint64) (*nbPtr - '0');
|
||||
}
|
||||
setInteger(negative ? - value : value);
|
||||
return expr;
|
||||
}
|
||||
else // floating point value : use scanf
|
||||
{
|
||||
// well, for now, we only parse a float
|
||||
float value;
|
||||
std::string floatValue(start, expr - start);
|
||||
if (fromString(floatValue, value))
|
||||
{
|
||||
setDouble(negative ? - value : value);
|
||||
return expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExprValue::evalString(const char *expr)
|
||||
{
|
||||
expr = skipBlank(expr);
|
||||
if (*expr != '\'') return NULL;
|
||||
++expr;
|
||||
std::string str;
|
||||
for (;;)
|
||||
{
|
||||
if (expr == '\0')
|
||||
{
|
||||
nlwarning("CInterfaceExprValue::evalString : end of buffer encountered in a string");
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
if (*expr == '\'')
|
||||
{
|
||||
++ expr;
|
||||
break;
|
||||
}
|
||||
if (*expr == '\\') // special char
|
||||
{
|
||||
++ expr;
|
||||
switch (*expr)
|
||||
{
|
||||
case 't': str += '\t'; break;
|
||||
case 'r': str += '\r'; break;
|
||||
case 'n': str += '\n'; break;
|
||||
case '\'': str += '\''; break;
|
||||
case '"': str += '"'; break;
|
||||
case '\\': str += '\\'; break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
// string continue on next line, so do nothing
|
||||
break;
|
||||
case '\0': continue;
|
||||
default:
|
||||
nlwarning("CInterfaceExprValue::evalString : unknown escape sequence : \\%c", *expr);
|
||||
if (*expr) str += *expr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (*expr == '\n' || *expr == '\r')
|
||||
{
|
||||
nlwarning("CInterfaceExprValue::evalString : line break encountered in a string");
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
str += *expr;
|
||||
}
|
||||
++ expr;
|
||||
}
|
||||
setString(str);
|
||||
return expr;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toType(TType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case Boolean: return toBool();
|
||||
case Integer: return toInteger();
|
||||
case Double: return toDouble();
|
||||
case String: return toString();
|
||||
case RGBA: return toRGBA();
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==================================================================
|
||||
void CInterfaceExprValue::clean()
|
||||
{
|
||||
switch (_Type)
|
||||
{
|
||||
case String: _StringValue.clear(); break;
|
||||
case UserType: delete _UserTypeValue; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
void CInterfaceExprValue::setUserType(CInterfaceExprUserType *value)
|
||||
{
|
||||
if (_Type == UserType && value == _UserTypeValue) return;
|
||||
clean();
|
||||
_Type = UserType;
|
||||
_UserTypeValue = value;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::getBool() const
|
||||
{
|
||||
if (_Type != Boolean)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getBool> bad type!");
|
||||
return false;
|
||||
}
|
||||
return _BoolValue;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
sint64 CInterfaceExprValue::getInteger() const
|
||||
{
|
||||
if (_Type != Integer)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getInteger> bad type!");
|
||||
return 0;
|
||||
}
|
||||
return _IntegerValue;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
double CInterfaceExprValue::getDouble() const
|
||||
{
|
||||
if (_Type != Double)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getDouble> bad type!");
|
||||
return 0;
|
||||
}
|
||||
return _DoubleValue;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
std::string CInterfaceExprValue::getString() const
|
||||
{
|
||||
if (_Type != String)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getString> bad type!");
|
||||
return "";
|
||||
}
|
||||
return _StringValue.toString();
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
NLMISC::CRGBA CInterfaceExprValue::getRGBA() const
|
||||
{
|
||||
if (_Type != RGBA)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getRGBA> bad type!");
|
||||
return CRGBA::White;
|
||||
}
|
||||
NLMISC::CRGBA col;
|
||||
col.R = (uint8)(_RGBAValue&0xff);
|
||||
col.G = (uint8)((_RGBAValue>>8)&0xff);
|
||||
col.B = (uint8)((_RGBAValue>>16)&0xff);
|
||||
col.A = (uint8)((_RGBAValue>>24)&0xff);
|
||||
return col;
|
||||
}
|
||||
|
||||
|
||||
//==================================================================
|
||||
const ucstring &CInterfaceExprValue::getUCString() const
|
||||
{
|
||||
if (_Type != String)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getString> bad type!");
|
||||
static ucstring emptyString;
|
||||
return emptyString;
|
||||
}
|
||||
return _StringValue;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
CInterfaceExprUserType *CInterfaceExprValue::getUserType() const
|
||||
{
|
||||
if (_Type != UserType)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getUserType> bad type!");
|
||||
return NULL;
|
||||
}
|
||||
return _UserTypeValue;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
CInterfaceExprValue::CInterfaceExprValue(const CInterfaceExprValue &other) : _Type(NoType)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
CInterfaceExprValue &CInterfaceExprValue::operator = (const CInterfaceExprValue &other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
clean();
|
||||
switch(other._Type)
|
||||
{
|
||||
case Boolean: _BoolValue = other._BoolValue; break;
|
||||
case Integer: _IntegerValue = other._IntegerValue; break;
|
||||
case Double: _DoubleValue = other._DoubleValue; break;
|
||||
case String: _StringValue = other._StringValue; break;
|
||||
case RGBA: _RGBAValue = other._RGBAValue; break;
|
||||
case UserType:
|
||||
if (other._UserTypeValue != NULL)
|
||||
{
|
||||
_UserTypeValue = other._UserTypeValue->clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
_UserTypeValue = NULL;
|
||||
}
|
||||
break;
|
||||
case NoType: break;
|
||||
default:
|
||||
nlwarning("<CInterfaceExprValue::operator=> bad source type") ;
|
||||
return *this;
|
||||
break;
|
||||
}
|
||||
_Type = other._Type;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
|
161
code/nel/src/gui/interface_expr_node.cpp
Normal file
161
code/nel/src/gui/interface_expr_node.cpp
Normal file
|
@ -0,0 +1,161 @@
|
|||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include "nel/misc/cdb_leaf.h"
|
||||
#include "nel/misc/cdb_branch.h"
|
||||
#include "nel/gui/interface_expr_node.h"
|
||||
|
||||
using NLMISC::ICDBNode;
|
||||
using NLMISC::CCDBNodeBranch;
|
||||
using NLMISC::CCDBNodeLeaf;
|
||||
|
||||
namespace NLGUI
|
||||
{
|
||||
|
||||
// *******************************************************************************************************
|
||||
void CInterfaceExprNodeValue::eval(CInterfaceExprValue &result)
|
||||
{
|
||||
result = Value;
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeValue::evalWithDepends(CInterfaceExprValue &result, std::vector<ICDBNode *> &/* nodes */)
|
||||
{
|
||||
result = Value;
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeValue::getDepends(std::vector<ICDBNode *> &/* nodes */)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// *******************************************************************************************************
|
||||
void CInterfaceExprNodeValueFnCall::eval(CInterfaceExprValue &result)
|
||||
{
|
||||
nlassert(Func);
|
||||
uint numParams = (uint)Params.size();
|
||||
std::vector<CInterfaceExprValue> params(numParams);
|
||||
for(uint k = 0; k < numParams; ++k)
|
||||
{
|
||||
Params[k]->eval(params[k]);
|
||||
}
|
||||
Func(params, result); // do actual call
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeValueFnCall::evalWithDepends(CInterfaceExprValue &result, std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
nlassert(Func);
|
||||
uint numParams = (uint)Params.size();
|
||||
std::vector<CInterfaceExprValue> params(numParams);
|
||||
for(uint k = 0; k < numParams; ++k)
|
||||
{
|
||||
Params[k]->evalWithDepends(params[k], nodes);
|
||||
}
|
||||
Func(params, result); // do actual call
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeValueFnCall::getDepends(std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
uint numParams = (uint)Params.size();
|
||||
for(uint k = 0; k < numParams; ++k)
|
||||
{
|
||||
Params[k]->getDepends(nodes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CInterfaceExprNodeValueFnCall::~CInterfaceExprNodeValueFnCall()
|
||||
{
|
||||
for(uint k = 0; k < Params.size(); ++k)
|
||||
{
|
||||
delete Params[k];
|
||||
}
|
||||
}
|
||||
|
||||
// *******************************************************************************************************
|
||||
void CInterfaceExprNodeDBLeaf::eval(CInterfaceExprValue &result)
|
||||
{
|
||||
nlassert(Leaf);
|
||||
result.setInteger(Leaf->getValue64());
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDBLeaf::evalWithDepends(CInterfaceExprValue &result,std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
nlassert(Leaf);
|
||||
result.setInteger(Leaf->getValue64());
|
||||
if (std::find(nodes.begin(), nodes.end(), Leaf) == nodes.end())
|
||||
{
|
||||
nodes.push_back(Leaf);
|
||||
}
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDBLeaf::getDepends(std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
nlassert(Leaf);
|
||||
if (std::find(nodes.begin(), nodes.end(), Leaf) == nodes.end())
|
||||
{
|
||||
nodes.push_back(Leaf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *******************************************************************************************************
|
||||
void CInterfaceExprNodeDBBranch::eval(CInterfaceExprValue &result)
|
||||
{
|
||||
nlassert(Branch);
|
||||
result.setInteger(0);
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDBBranch::evalWithDepends(CInterfaceExprValue &result,std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
nlassert(Branch);
|
||||
result.setInteger(0);
|
||||
if (std::find(nodes.begin(), nodes.end(), Branch) == nodes.end())
|
||||
{
|
||||
nodes.push_back(Branch);
|
||||
}
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDBBranch::getDepends(std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
nlassert(Branch);
|
||||
if (std::find(nodes.begin(), nodes.end(), Branch) == nodes.end())
|
||||
{
|
||||
nodes.push_back(Branch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *******************************************************************************************************
|
||||
void CInterfaceExprNodeDependantDBRead::eval(CInterfaceExprValue &result)
|
||||
{
|
||||
// no gain there, but barely used
|
||||
CInterfaceExpr::eval(Expr, result);
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDependantDBRead::evalWithDepends(CInterfaceExprValue &result, std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
CInterfaceExpr::eval(Expr, result, &nodes);
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDependantDBRead::getDepends(std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
CInterfaceExprValue dummyResult;
|
||||
CInterfaceExpr::eval(Expr, dummyResult, &nodes, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -728,6 +728,21 @@ void CRGBA::buildFromHLS(float h, float l, float s)
|
|||
}
|
||||
}
|
||||
|
||||
CRGBA CRGBA::stringToRGBA( const char *ptr )
|
||||
{
|
||||
if (!ptr)
|
||||
return NLMISC::CRGBA::White;
|
||||
|
||||
int r = 255, g = 255, b = 255, a = 255;
|
||||
sscanf( ptr, "%d %d %d %d", &r, &g, &b, &a );
|
||||
clamp( r, 0, 255 );
|
||||
clamp( g, 0, 255 );
|
||||
clamp( b, 0, 255 );
|
||||
clamp( a, 0, 255 );
|
||||
|
||||
return CRGBA( r,g,b,a );
|
||||
}
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// ***************************************************************************
|
||||
|
|
|
@ -1374,7 +1374,7 @@ void CClientConfig::setValues()
|
|||
SPrintfCommand pcom;
|
||||
pcom.X = pc->asInt(i);
|
||||
pcom.Y = pc->asInt(i+1);
|
||||
pcom.Color = stringToRGBA( pc->asString(i+2).c_str() );
|
||||
pcom.Color = CRGBA::stringToRGBA( pc->asString(i+2).c_str() );
|
||||
pcom.FontSize = pc->asInt(i+3);
|
||||
pcom.Text = pc->asString(i+4);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
#include "interface_v3/ctrl_button.h"
|
||||
#include "interface_v3/input_handler_manager.h"
|
||||
#include "interface_v3/group_editbox.h"
|
||||
#include "interface_v3/interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "init_main_loop.h"
|
||||
#include "continent_manager.h"
|
||||
#include "interface_v3/group_quick_help.h"
|
||||
|
@ -1338,7 +1338,7 @@ void setTarget(CCtrlBase *ctrl, const string &targetName, ucstring &value)
|
|||
CInterfaceExprValue exprValue;
|
||||
exprValue.setUCString(value);
|
||||
|
||||
CInterfaceParser::splitLinkTargets(targetName, ig, targets);
|
||||
CInterfaceLink::splitLinkTargets(targetName, ig, targets);
|
||||
for(uint k = 0; k < targets.size(); ++k)
|
||||
{
|
||||
if (targets[k].Elem) targets[k].affect(exprValue);
|
||||
|
@ -1364,7 +1364,7 @@ void setTarget(CCtrlBase *ctrl, const string &targetName, uint32 value)
|
|||
CInterfaceExprValue exprValue;
|
||||
exprValue.setInteger(value);
|
||||
|
||||
CInterfaceParser::splitLinkTargets(targetName, ig, targets);
|
||||
CInterfaceLink::splitLinkTargets(targetName, ig, targets);
|
||||
for(uint k = 0; k < targets.size(); ++k)
|
||||
{
|
||||
if (targets[k].Elem) targets[k].affect(exprValue);
|
||||
|
@ -1813,7 +1813,7 @@ string getTarget(CCtrlBase * /* ctrl */, const string &targetName)
|
|||
{
|
||||
string sTmp = targetName;
|
||||
std::vector<CInterfaceLink::CTargetInfo> targetsVector;
|
||||
CInterfaceParser::splitLinkTargets(sTmp, NULL, targetsVector);
|
||||
CInterfaceLink::splitLinkTargets(sTmp, NULL, targetsVector);
|
||||
|
||||
CInterfaceLink::CTargetInfo &rTI = targetsVector[0];
|
||||
|
||||
|
@ -1835,7 +1835,7 @@ ucstring getUCTarget(CCtrlBase * /* ctrl */, const string &targetName)
|
|||
{
|
||||
string sTmp = targetName;
|
||||
std::vector<CInterfaceLink::CTargetInfo> targetsVector;
|
||||
CInterfaceParser::splitLinkTargets(sTmp, NULL, targetsVector);
|
||||
CInterfaceLink::splitLinkTargets(sTmp, NULL, targetsVector);
|
||||
|
||||
CInterfaceLink::CTargetInfo &rTI = targetsVector[0];
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "action_handler.h"
|
||||
#include "action_handler_misc.h"
|
||||
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "interface_manager.h"
|
||||
|
||||
#include "group_container.h"
|
||||
|
@ -298,7 +298,7 @@ public:
|
|||
|
||||
if (ig != NULL)
|
||||
{
|
||||
CInterfaceParser::splitLinkTargets(property, ig, targets);
|
||||
CInterfaceLink::splitLinkTargets(property, ig, targets);
|
||||
for(uint k = 0; k < targets.size(); ++k)
|
||||
{
|
||||
if (targets[k].Elem) targets[k].affect(value);
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "bot_chat_page_ring_sessions.h"
|
||||
#include "dbctrl_sheet.h"
|
||||
#include "ctrl_sheet_selection.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "group_menu.h"
|
||||
#include "group_container.h"
|
||||
#include "group_editbox.h"
|
||||
|
@ -3902,7 +3902,7 @@ public:
|
|||
uint entity;
|
||||
fromString(getParam(sParams, "entity"), entity);
|
||||
|
||||
CRGBA color = stringToRGBA(getParam(sParams, "color").c_str());
|
||||
CRGBA color = CRGBA::stringToRGBA(getParam(sParams, "color").c_str());
|
||||
if (entity < 256)
|
||||
EntitiesMngr.entity (entity)->addHPOutput (CI18N::get (text), color);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "../sheet_manager.h"
|
||||
#include "skill_manager.h"
|
||||
#include "dbctrl_sheet.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "group_container.h"
|
||||
#include "group_editbox.h"
|
||||
#include "group_quick_help.h"
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "dbctrl_sheet.h"
|
||||
#include "dbgroup_list_sheet.h"
|
||||
#include "group_editbox.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "player_trade.h"
|
||||
#include "../user_entity.h"
|
||||
#include "../net_manager.h"
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "group_editbox.h"
|
||||
#include "people_interraction.h"
|
||||
#include "nel/misc/algo.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "interface_link.h"
|
||||
#include "../client_chat_manager.h"
|
||||
#include "../motion/user_controls.h"
|
||||
|
@ -427,7 +427,7 @@ class CActionHandlerAddLink : public IActionHandler
|
|||
}
|
||||
|
||||
std::vector<CInterfaceLink::CTargetInfo> targetsVect;
|
||||
bool result = CInterfaceParser::splitLinkTargets(targets, parentGroup, targetsVect);
|
||||
bool result = CInterfaceLink::splitLinkTargets(targets, parentGroup, targetsVect);
|
||||
if (!result)
|
||||
{
|
||||
nlwarning("<CActionHandlerAddLink> Couldn't parse all links");
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "action_handler.h"
|
||||
#include "action_handler_tools.h"
|
||||
#include "game_share/outpost.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "group_map.h"
|
||||
#include "../sheet_manager.h"
|
||||
#include "../net_manager.h"
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include "bar_manager.h"
|
||||
#include "interface_manager.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "../time_client.h"
|
||||
|
||||
|
||||
|
|
|
@ -554,7 +554,7 @@ void CChatGroupWindow::displayMessage(const ucstring &msg, NLMISC::CRGBA col, CC
|
|||
|
||||
// on a new message, change the Tab color
|
||||
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
||||
CRGBA newMsgColor= stringToRGBA(pIM->getDefine("chat_group_tab_color_newmsg").c_str());
|
||||
CRGBA newMsgColor= CRGBA::stringToRGBA(pIM->getDefine("chat_group_tab_color_newmsg").c_str());
|
||||
|
||||
ucstring newmsg = msg;
|
||||
ucstring prefix;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
// client
|
||||
#include "nel/gui/reflect.h"
|
||||
#include "ctrl_base.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "action_handler.h"
|
||||
#include "sphrase_manager.h"
|
||||
// game share
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
#include "stdpch.h"
|
||||
#include "interface_manager.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "group_menu.h"
|
||||
#include "nel/misc/xml_auto_ptr.h"
|
||||
#include "view_bitmap.h"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "group_phrase_skill_filter.h"
|
||||
#include "interface_manager.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
|
||||
#include "view_text.h"
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "group_skills.h"
|
||||
#include "interface_manager.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
|
||||
#include "view_text.h"
|
||||
#include "view_bitmap.h"
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "interface_anim.h"
|
||||
#include "interface_manager.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "nel/misc/xml_auto_ptr.h"
|
||||
#include "action_handler.h"
|
||||
#include "../time_client.h"
|
||||
|
@ -75,7 +75,7 @@ bool CInterfaceTrack::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup)
|
|||
}
|
||||
|
||||
//
|
||||
if (!CInterfaceParser::splitLinkTargets (ptr, parentGroup, _Targets))
|
||||
if (!CInterfaceLink::splitLinkTargets (ptr, parentGroup, _Targets))
|
||||
{
|
||||
nlwarning ("no target for track");
|
||||
return false;
|
||||
|
|
|
@ -761,7 +761,7 @@ void CInterfaceElement::convertHotSpotCouple (const char *ptr, THotSpot &parent
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
NLMISC::CRGBA CInterfaceElement::convertColor (const char *ptr)
|
||||
{
|
||||
return stringToRGBA(ptr);
|
||||
return NLMISC::CRGBA::stringToRGBA(ptr);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -1,930 +0,0 @@
|
|||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "stdpch.h"
|
||||
#include "interface_expr.h"
|
||||
#include "interface_manager.h"
|
||||
#include "interface_expr_node.h"
|
||||
#include "../misc.h"
|
||||
#include "nel/misc/algo.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
using namespace NLMISC;
|
||||
|
||||
// Yoyo: Act like a singleton, else registerUserFct may crash.
|
||||
CInterfaceExpr::TUserFctMap *CInterfaceExpr::_UserFct= NULL;
|
||||
|
||||
static const std::string ExprLuaId="lua:";
|
||||
|
||||
//==================================================================
|
||||
// release memory
|
||||
void CInterfaceExpr::release()
|
||||
{
|
||||
delete _UserFct;
|
||||
_UserFct = NULL;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
void formatLuaCall(const std::string &expr, std::string &tempStr)
|
||||
{
|
||||
/* Call the LUA interface exp fct, with the script as line, and resolve string definition conflicts:
|
||||
eg: replace
|
||||
lua:getSkillFromName('SM')
|
||||
into
|
||||
lua('getSkillFromName(\"SM\")')
|
||||
*/
|
||||
tempStr= expr.substr(ExprLuaId.size()); // eg: tempStr= getSkillFromName('SM')
|
||||
while(strFindReplace(tempStr, "'", "\\\"")); // eg: tempStr= getSkillFromName(\"SM\")
|
||||
tempStr= string("lua('") + tempStr + "')"; // eg: tempStr= lua('getSkillFromName(\"SM\")')
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExpr::eval(const std::string &expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes, bool noFctCalls /* = false */)
|
||||
{
|
||||
// Yoyo: Special InterfaceExpr Form to execute lua code?
|
||||
if(expr.compare(0, ExprLuaId.size(), ExprLuaId) ==0 )
|
||||
{
|
||||
std::string tempStr;
|
||||
formatLuaCall(expr, tempStr);
|
||||
return evalExpr(tempStr.c_str(), result, nodes, noFctCalls) != NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return evalExpr(expr.c_str(), result, nodes, noFctCalls) != NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
CInterfaceExprNode *CInterfaceExpr::buildExprTree(const std::string &expr)
|
||||
{
|
||||
CInterfaceExprNode *node;
|
||||
|
||||
// Yoyo: Special InterfaceExpr Form to execute lua code?
|
||||
if(expr.compare(0, ExprLuaId.size(), ExprLuaId) ==0 )
|
||||
{
|
||||
std::string tempStr;
|
||||
formatLuaCall(expr, tempStr);
|
||||
if (!buildExprTree(tempStr.c_str(), node)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!buildExprTree(expr.c_str(), node)) return false;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
//==================================================================
|
||||
void CInterfaceExpr::registerUserFct(const char *name,TUserFct fct)
|
||||
{
|
||||
if(!_UserFct) _UserFct= new TUserFctMap;
|
||||
|
||||
nlassert(fct != NULL);
|
||||
(*_UserFct)[std::string(name)] = fct;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
/** tool fct : skip space, tab and carret-returns
|
||||
*/
|
||||
static const char *skipBlank(const char *start)
|
||||
{
|
||||
nlassert(start);
|
||||
while (*start == ' ' || *start == '\t' || *start == '\r' || *start == '\n') ++start;
|
||||
return start;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::evalExpr(const char *expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes, bool noFctCalls)
|
||||
{
|
||||
nlassert(expr != NULL);
|
||||
expr = skipBlank(expr);
|
||||
if (isalpha(*expr)) // alpha character means this is a function name
|
||||
{
|
||||
return evalFct(expr, result, nodes, noFctCalls);
|
||||
}
|
||||
else if (*expr == '@') // is it a database entry ?
|
||||
{
|
||||
++ expr;
|
||||
expr = skipBlank(expr);
|
||||
return evalDBEntry(expr, result, nodes);
|
||||
}
|
||||
|
||||
// try to parse a literal value
|
||||
const char *newExpr = result.initFromString(expr);
|
||||
if (!newExpr)
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalExpr> : syntax error : %s", expr);
|
||||
return NULL;
|
||||
}
|
||||
return newExpr;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::buildExprTree(const char *expr, CInterfaceExprNode *&result)
|
||||
{
|
||||
nlassert(expr != NULL);
|
||||
expr = skipBlank(expr);
|
||||
if (isalpha(*expr)) // alpha character means this is a function name
|
||||
{
|
||||
return buildFctNode(expr, result);
|
||||
}
|
||||
else if (*expr == '@') // is it a database entry ?
|
||||
{
|
||||
++ expr;
|
||||
expr = skipBlank(expr);
|
||||
return buildDBEntryNode(expr, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
CInterfaceExprValue value;
|
||||
// try to parse a literal value
|
||||
const char *newExpr = value.initFromString(expr);
|
||||
if (!newExpr)
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::buildExprTree> : syntax error : %s", expr);
|
||||
return NULL;
|
||||
}
|
||||
CInterfaceExprNodeValue *node = new CInterfaceExprNodeValue;
|
||||
node->Value = value;
|
||||
result = node;
|
||||
return newExpr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::evalFct(const char *expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes, bool noFctCalls)
|
||||
{
|
||||
if(!_UserFct) _UserFct= new TUserFctMap;
|
||||
|
||||
const char *start = expr;
|
||||
while (isalnum(*expr)) ++ expr;
|
||||
std::string fctName(start, expr - start);
|
||||
// find entry in the map
|
||||
TUserFctMap::iterator fctIt = _UserFct->find(fctName);
|
||||
if (fctIt == _UserFct->end())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalFct> : Unknown function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
nlassert(fctIt->second != NULL);
|
||||
// eval list of arguments
|
||||
TArgList argList;
|
||||
expr = skipBlank(expr);
|
||||
if (*expr != '(')
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalFct> : '(' expected for function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
++ expr;
|
||||
expr = skipBlank(expr);
|
||||
if (*expr != ')')
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
expr = skipBlank(expr);
|
||||
// parse an argument
|
||||
argList.push_back(CInterfaceExprValue());
|
||||
expr = evalExpr(expr, argList.back(), nodes, noFctCalls);
|
||||
if (expr == NULL) return NULL;
|
||||
expr = skipBlank(expr);
|
||||
if (*expr == ')') break;
|
||||
// if it isn't the end of the expression, then we should find a ',' before next argument
|
||||
if (*expr != ',')
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalFct> : ',' expected in function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
++ expr;
|
||||
}
|
||||
}
|
||||
++ expr;
|
||||
// call the fct
|
||||
if (!noFctCalls) // should we make terminal function calls ?
|
||||
{
|
||||
if (fctIt->second(argList, result)) return expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return expr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::buildFctNode(const char *expr, CInterfaceExprNode *&result)
|
||||
{
|
||||
if(!_UserFct) _UserFct= new TUserFctMap;
|
||||
|
||||
const char *start = expr;
|
||||
while (isalnum(*expr)) ++ expr;
|
||||
std::string fctName(start, expr - start);
|
||||
// find entry in the map
|
||||
TUserFctMap::iterator fctIt = _UserFct->find(fctName);
|
||||
if (fctIt == _UserFct->end())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::buildFctNode> : Unknown function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
nlassert(fctIt->second != NULL);
|
||||
// List of parameters
|
||||
expr = skipBlank(expr);
|
||||
if (*expr != '(')
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::buildFctNode> : '(' expected for function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
++ expr;
|
||||
expr = skipBlank(expr);
|
||||
std::vector<CInterfaceExprNode *> Params;
|
||||
if (*expr != ')')
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
expr = skipBlank(expr);
|
||||
// parse an argument
|
||||
CInterfaceExprNode *node = NULL;
|
||||
expr = buildExprTree(expr, node);
|
||||
if (expr == NULL)
|
||||
{
|
||||
for(uint k = 0; k < Params.size(); ++k)
|
||||
{
|
||||
delete Params[k];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
Params.push_back(node);
|
||||
expr = skipBlank(expr);
|
||||
if (*expr == ')') break;
|
||||
// if it isn't the end of the expression, then we should find a ',' before next argument
|
||||
if (*expr != ',')
|
||||
{
|
||||
for(uint k = 0; k < Params.size(); ++k)
|
||||
{
|
||||
delete Params[k];
|
||||
}
|
||||
nlwarning("CInterfaceExpr::evalFct : ',' expected in function %s", fctName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
++ expr;
|
||||
}
|
||||
}
|
||||
++ expr;
|
||||
CInterfaceExprNodeValueFnCall *node = new CInterfaceExprNodeValueFnCall;
|
||||
node->Params.swap(Params);
|
||||
node->Func = fctIt->second;
|
||||
result = node;
|
||||
return expr;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::evalDBEntry(const char *expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes)
|
||||
{
|
||||
std::string dbEntry;
|
||||
expr = unpackDBentry(expr, nodes, dbEntry);
|
||||
if (!expr) return NULL;
|
||||
// TestYoyo
|
||||
//nlassert(NLGUI::CDBManager::getInstance()->getDbProp(dbEntry, false) || CInterfaceManager::getInstance()->getDbBranch(dbEntry));
|
||||
// get the db value
|
||||
CCDBNodeLeaf *nl = NLGUI::CDBManager::getInstance()->getDbProp(dbEntry);
|
||||
if (nl)
|
||||
{
|
||||
if (nodes)
|
||||
{
|
||||
// insert node if not already present
|
||||
if (std::find(nodes->begin(), nodes->end(), nl) == nodes->end())
|
||||
{
|
||||
nodes->push_back(nl);
|
||||
}
|
||||
}
|
||||
result.setInteger(nl->getValue64());
|
||||
return expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCDBNodeBranch *nb = NLGUI::CDBManager::getInstance()->getDbBranch(dbEntry);
|
||||
if (nodes && nb)
|
||||
{
|
||||
if (std::find(nodes->begin(), nodes->end(), nb) == nodes->end())
|
||||
{
|
||||
nodes->push_back(nb);
|
||||
}
|
||||
}
|
||||
if (!nb) return NULL;
|
||||
result.setInteger(0);
|
||||
return expr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::buildDBEntryNode(const char *expr, CInterfaceExprNode *&result)
|
||||
{
|
||||
std::string dbEntry;
|
||||
bool indirection;
|
||||
const char *startChar = expr;
|
||||
expr = unpackDBentry(expr, NULL, dbEntry, &indirection);
|
||||
if (!expr) return NULL;
|
||||
if (indirection)
|
||||
{
|
||||
// special node with no optimisation
|
||||
CInterfaceExprNodeDependantDBRead *node = new CInterfaceExprNodeDependantDBRead;
|
||||
node->Expr.resize(expr - startChar + 1);
|
||||
std::copy(startChar, expr, node->Expr.begin() + 1);
|
||||
node->Expr[0] = '@';
|
||||
result = node;
|
||||
return expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TestYoyo
|
||||
//nlassert(NLGUI::CDBManager::getInstance()->getDbProp(dbEntry, false) || CInterfaceManager::getInstance()->getDbBranch(dbEntry));
|
||||
CCDBNodeLeaf *nl = NLGUI::CDBManager::getInstance()->getDbProp(dbEntry);
|
||||
if (nl)
|
||||
{
|
||||
CInterfaceExprNodeDBLeaf *node = new CInterfaceExprNodeDBLeaf;
|
||||
node->Leaf = nl;
|
||||
result = node;
|
||||
return expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCDBNodeBranch *nb = NLGUI::CDBManager::getInstance()->getDbBranch(dbEntry);
|
||||
if (nb)
|
||||
{
|
||||
CInterfaceExprNodeDBBranch *node = new CInterfaceExprNodeDBBranch;
|
||||
node->Branch = nb;
|
||||
result = node;
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExpr::unpackDBentry(const char *expr, std::vector<ICDBNode *> *nodes, std::string &dest, bool *hasIndirections /* = NULL*/)
|
||||
{
|
||||
std::string entryName;
|
||||
bool indirection = false;
|
||||
for (;;)
|
||||
{
|
||||
if (*expr == '[')
|
||||
{
|
||||
indirection = true;
|
||||
++ expr;
|
||||
std::string subEntry;
|
||||
expr = unpackDBentry(expr, nodes, subEntry);
|
||||
if (!expr) return NULL;
|
||||
// Read DB Index Offset.
|
||||
sint32 indirectionOffset= 0;
|
||||
if (*expr == '-' || *expr =='+' )
|
||||
{
|
||||
bool negative= *expr == '-';
|
||||
std::string offsetString;
|
||||
++ expr;
|
||||
while(*expr!=0 && isdigit(*expr))
|
||||
{
|
||||
offsetString.push_back(*expr);
|
||||
++ expr;
|
||||
}
|
||||
// get offset
|
||||
fromString(offsetString, indirectionOffset);
|
||||
if(negative)
|
||||
indirectionOffset= -indirectionOffset;
|
||||
}
|
||||
// Test end of indirection
|
||||
if (*expr != ']')
|
||||
{
|
||||
nlwarning("CInterfaceExpr::unpackDBentry: ']' expected");
|
||||
return NULL;
|
||||
}
|
||||
++ expr;
|
||||
// get the db value at sub entry
|
||||
// TestYoyo
|
||||
//nlassert(NLGUI::CDBManager::getInstance()->getDbProp(subEntry, false) || CInterfaceManager::getInstance()->getDbBranch(subEntry));
|
||||
CCDBNodeLeaf *nl = NLGUI::CDBManager::getInstance()->getDbProp(subEntry);
|
||||
if (nodes)
|
||||
{
|
||||
if (std::find(nodes->begin(), nodes->end(), nl) == nodes->end())
|
||||
{
|
||||
nodes->push_back(nl);
|
||||
}
|
||||
}
|
||||
// compute indirection, (clamp).
|
||||
sint32 indirectionValue= nl->getValue32() + indirectionOffset;
|
||||
indirectionValue= std::max((sint32)0, indirectionValue);
|
||||
|
||||
// Append to entry name.
|
||||
entryName += NLMISC::toString(indirectionValue);
|
||||
}
|
||||
else if (isalnum(*expr) || *expr == '_' || *expr == ':')
|
||||
{
|
||||
entryName += *expr;
|
||||
++ expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasIndirections)
|
||||
{
|
||||
*hasIndirections = indirection;
|
||||
}
|
||||
dest = entryName;
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExpr::evalAsInt(const std::string &expr, sint64 &dest)
|
||||
{
|
||||
CInterfaceExprValue result;
|
||||
if (!eval(expr, result)) return false;
|
||||
if (!result.toInteger())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalAsInt> Can't convert value to an integer, expr = %s", expr.c_str());
|
||||
return false;
|
||||
}
|
||||
dest = result.getInteger();
|
||||
return true;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExpr::evalAsDouble(const std::string &expr, double &dest)
|
||||
{
|
||||
CInterfaceExprValue result;
|
||||
if (!eval(expr, result)) return false;
|
||||
if (!result.toDouble())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalAsDouble> Can't convert value to a double, expr = %s", expr.c_str());
|
||||
return false;
|
||||
}
|
||||
dest = result.getDouble();
|
||||
return true;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExpr::evalAsBool(const std::string &expr, bool &dest)
|
||||
{
|
||||
CInterfaceExprValue result;
|
||||
if (!eval(expr, result)) return false;
|
||||
if (!result.toBool())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalAsBool> Can't convert value to a boolean, expr = %s", expr.c_str());
|
||||
return false;
|
||||
}
|
||||
dest = result.getBool();
|
||||
return true;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExpr::evalAsString(const std::string &expr, std::string &dest)
|
||||
{
|
||||
CInterfaceExprValue result;
|
||||
if (!eval(expr, result)) return false;
|
||||
if (!result.toString())
|
||||
{
|
||||
nlwarning("<CInterfaceExpr::evalAsString> Can't convert value to a string, expr = %s", expr.c_str());
|
||||
return false;
|
||||
}
|
||||
dest = result.getString();
|
||||
return true;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
//==================================================================
|
||||
//==================================================================
|
||||
//==================================================================
|
||||
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toBool()
|
||||
{
|
||||
switch(_Type)
|
||||
{
|
||||
case Boolean: return true;
|
||||
case Integer: setBool(_IntegerValue != 0); return true;
|
||||
case Double: setBool(_DoubleValue != 0); return true;
|
||||
case String: return evalBoolean(_StringValue.toString().c_str()) != NULL;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toInteger()
|
||||
{
|
||||
switch(_Type)
|
||||
{
|
||||
case Boolean: setInteger(_BoolValue ? 1 : 0); return true;
|
||||
case Integer: return true;
|
||||
case Double: setInteger((sint64) _DoubleValue); return true;
|
||||
case String:
|
||||
if (evalNumber(_StringValue.toString().c_str())) return toInteger();
|
||||
return false;
|
||||
case RGBA: setInteger((sint64) _RGBAValue); return true;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toDouble()
|
||||
{
|
||||
switch(_Type)
|
||||
{
|
||||
case Boolean: setDouble(_BoolValue ? 1 : 0); return true;
|
||||
case Integer: setDouble((double) _IntegerValue); return true;
|
||||
case Double: return true;
|
||||
case String:
|
||||
if (evalNumber(_StringValue.toString().c_str())) return toBool();
|
||||
return false;
|
||||
case RGBA: setDouble((double) _RGBAValue); return true;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toString()
|
||||
{
|
||||
switch(_Type)
|
||||
{
|
||||
case Boolean: setString(_BoolValue ? "true" : "false"); return true;
|
||||
case Integer: setString(NLMISC::toString(_IntegerValue)); return true;
|
||||
case Double: setString(NLMISC::toString("%.2f", _DoubleValue)); return true;
|
||||
case String: return true;
|
||||
case RGBA:
|
||||
{
|
||||
uint r,g,b,a;
|
||||
r= (_RGBAValue&0xff);
|
||||
g= ((_RGBAValue>>8)&0xff);
|
||||
b= ((_RGBAValue>>16)&0xff);
|
||||
a= ((_RGBAValue>>24)&0xff);
|
||||
setString(NLMISC::toString("%d %d %d %d", r, g, b, a));
|
||||
return true;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toRGBA()
|
||||
{
|
||||
switch(_Type)
|
||||
{
|
||||
case RGBA: return true;
|
||||
case Integer: setRGBA(NLMISC::CRGBA((uint8)(_IntegerValue&0xff), (uint8)((_IntegerValue>>8)&0xff),
|
||||
(uint8)((_IntegerValue>>16)&0xff), (uint8)((_IntegerValue>>24)&0xff))); return true;
|
||||
case String:
|
||||
setRGBA(stringToRGBA(_StringValue.toString().c_str())); return true;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::isNumerical() const
|
||||
{
|
||||
return _Type == Boolean || _Type == Integer || _Type == Double;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExprValue::initFromString(const char *expr)
|
||||
{
|
||||
nlassert(expr);
|
||||
expr = skipBlank(expr);
|
||||
if (isdigit(*expr) || *expr == '.' || *expr == '-') return evalNumber(expr);
|
||||
switch(*expr)
|
||||
{
|
||||
case 't':
|
||||
case 'T':
|
||||
case 'f':
|
||||
case 'F':
|
||||
return evalBoolean(expr);
|
||||
case '\'':
|
||||
return evalString(expr);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExprValue::evalBoolean(const char *expr)
|
||||
{
|
||||
nlassert(expr);
|
||||
expr = skipBlank(expr);
|
||||
if (toupper(expr[0]) == 'T' &&
|
||||
toupper(expr[1]) == 'R' &&
|
||||
toupper(expr[2]) == 'U' &&
|
||||
toupper(expr[3]) == 'E')
|
||||
{
|
||||
setBool(true);
|
||||
return expr + 4;
|
||||
}
|
||||
//
|
||||
if (toupper(expr[0]) == 'F' &&
|
||||
toupper(expr[1]) == 'A' &&
|
||||
toupper(expr[2]) == 'L' &&
|
||||
toupper(expr[3]) == 'S' &&
|
||||
toupper(expr[4]) == 'E')
|
||||
{
|
||||
setBool(false);
|
||||
return expr + 5;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExprValue::evalNumber(const char *expr)
|
||||
{
|
||||
bool negative;
|
||||
bool hasPoint = false;
|
||||
|
||||
expr = skipBlank(expr);
|
||||
|
||||
if (*expr == '-')
|
||||
{
|
||||
negative = true;
|
||||
++ expr;
|
||||
expr = skipBlank(expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
negative = false;
|
||||
}
|
||||
|
||||
const char *start = expr;
|
||||
while (*expr == '.' || isdigit(*expr))
|
||||
{
|
||||
if (*expr == '.') hasPoint = true;
|
||||
++ expr;
|
||||
}
|
||||
if (start == expr) return NULL;
|
||||
if (!hasPoint)
|
||||
{
|
||||
sint64 value = 0;
|
||||
// this is an integer
|
||||
for (const char *nbPtr = start; nbPtr < expr; ++ nbPtr)
|
||||
{
|
||||
value *= 10;
|
||||
value += (sint64) (*nbPtr - '0');
|
||||
}
|
||||
setInteger(negative ? - value : value);
|
||||
return expr;
|
||||
}
|
||||
else // floating point value : use scanf
|
||||
{
|
||||
// well, for now, we only parse a float
|
||||
float value;
|
||||
std::string floatValue(start, expr - start);
|
||||
if (fromString(floatValue, value))
|
||||
{
|
||||
setDouble(negative ? - value : value);
|
||||
return expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
const char *CInterfaceExprValue::evalString(const char *expr)
|
||||
{
|
||||
expr = skipBlank(expr);
|
||||
if (*expr != '\'') return NULL;
|
||||
++expr;
|
||||
std::string str;
|
||||
for (;;)
|
||||
{
|
||||
if (expr == '\0')
|
||||
{
|
||||
nlwarning("CInterfaceExprValue::evalString : end of buffer encountered in a string");
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
if (*expr == '\'')
|
||||
{
|
||||
++ expr;
|
||||
break;
|
||||
}
|
||||
if (*expr == '\\') // special char
|
||||
{
|
||||
++ expr;
|
||||
switch (*expr)
|
||||
{
|
||||
case 't': str += '\t'; break;
|
||||
case 'r': str += '\r'; break;
|
||||
case 'n': str += '\n'; break;
|
||||
case '\'': str += '\''; break;
|
||||
case '"': str += '"'; break;
|
||||
case '\\': str += '\\'; break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
// string continue on next line, so do nothing
|
||||
break;
|
||||
case '\0': continue;
|
||||
default:
|
||||
nlwarning("CInterfaceExprValue::evalString : unknown escape sequence : \\%c", *expr);
|
||||
if (*expr) str += *expr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (*expr == '\n' || *expr == '\r')
|
||||
{
|
||||
nlwarning("CInterfaceExprValue::evalString : line break encountered in a string");
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
str += *expr;
|
||||
}
|
||||
++ expr;
|
||||
}
|
||||
setString(str);
|
||||
return expr;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::toType(TType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case Boolean: return toBool();
|
||||
case Integer: return toInteger();
|
||||
case Double: return toDouble();
|
||||
case String: return toString();
|
||||
case RGBA: return toRGBA();
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==================================================================
|
||||
void CInterfaceExprValue::clean()
|
||||
{
|
||||
switch (_Type)
|
||||
{
|
||||
case String: _StringValue.clear(); break;
|
||||
case UserType: delete _UserTypeValue; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
void CInterfaceExprValue::setUserType(CInterfaceExprUserType *value)
|
||||
{
|
||||
if (_Type == UserType && value == _UserTypeValue) return;
|
||||
clean();
|
||||
_Type = UserType;
|
||||
_UserTypeValue = value;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
bool CInterfaceExprValue::getBool() const
|
||||
{
|
||||
if (_Type != Boolean)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getBool> bad type!");
|
||||
return false;
|
||||
}
|
||||
return _BoolValue;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
sint64 CInterfaceExprValue::getInteger() const
|
||||
{
|
||||
if (_Type != Integer)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getInteger> bad type!");
|
||||
return 0;
|
||||
}
|
||||
return _IntegerValue;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
double CInterfaceExprValue::getDouble() const
|
||||
{
|
||||
if (_Type != Double)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getDouble> bad type!");
|
||||
return 0;
|
||||
}
|
||||
return _DoubleValue;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
std::string CInterfaceExprValue::getString() const
|
||||
{
|
||||
if (_Type != String)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getString> bad type!");
|
||||
return "";
|
||||
}
|
||||
return _StringValue.toString();
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
NLMISC::CRGBA CInterfaceExprValue::getRGBA() const
|
||||
{
|
||||
if (_Type != RGBA)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getRGBA> bad type!");
|
||||
return CRGBA::White;
|
||||
}
|
||||
NLMISC::CRGBA col;
|
||||
col.R = (uint8)(_RGBAValue&0xff);
|
||||
col.G = (uint8)((_RGBAValue>>8)&0xff);
|
||||
col.B = (uint8)((_RGBAValue>>16)&0xff);
|
||||
col.A = (uint8)((_RGBAValue>>24)&0xff);
|
||||
return col;
|
||||
}
|
||||
|
||||
|
||||
//==================================================================
|
||||
const ucstring &CInterfaceExprValue::getUCString() const
|
||||
{
|
||||
if (_Type != String)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getString> bad type!");
|
||||
static ucstring emptyString;
|
||||
return emptyString;
|
||||
}
|
||||
return _StringValue;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
CInterfaceExprUserType *CInterfaceExprValue::getUserType() const
|
||||
{
|
||||
if (_Type != UserType)
|
||||
{
|
||||
nlwarning("<CInterfaceExprValue::getUserType> bad type!");
|
||||
return NULL;
|
||||
}
|
||||
return _UserTypeValue;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
CInterfaceExprValue::CInterfaceExprValue(const CInterfaceExprValue &other) : _Type(NoType)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
//==================================================================
|
||||
CInterfaceExprValue &CInterfaceExprValue::operator = (const CInterfaceExprValue &other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
clean();
|
||||
switch(other._Type)
|
||||
{
|
||||
case Boolean: _BoolValue = other._BoolValue; break;
|
||||
case Integer: _IntegerValue = other._IntegerValue; break;
|
||||
case Double: _DoubleValue = other._DoubleValue; break;
|
||||
case String: _StringValue = other._StringValue; break;
|
||||
case RGBA: _RGBAValue = other._RGBAValue; break;
|
||||
case UserType:
|
||||
if (other._UserTypeValue != NULL)
|
||||
{
|
||||
_UserTypeValue = other._UserTypeValue->clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
_UserTypeValue = NULL;
|
||||
}
|
||||
break;
|
||||
case NoType: break;
|
||||
default:
|
||||
nlwarning("<CInterfaceExprValue::operator=> bad source type") ;
|
||||
return *this;
|
||||
break;
|
||||
}
|
||||
_Type = other._Type;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef CL_INTERFACE_EXPR_H
|
||||
#define CL_INTERFACE_EXPR_H
|
||||
|
||||
|
||||
#include "nel/misc/ucstring.h"
|
||||
#include "nel/misc/rgba.h"
|
||||
|
||||
namespace NLMISC{
|
||||
class ICDBNode;
|
||||
class CCDBNodeLeaf;
|
||||
class CCDBNodeBranch;
|
||||
}
|
||||
|
||||
|
||||
struct CInterfaceExprUserType;
|
||||
class CInterfaceExprNode;
|
||||
|
||||
/** a value that can be returned by a CInterfaceExpr instance
|
||||
* It supports basic type;
|
||||
* It can be extended by user defined types
|
||||
*/
|
||||
class CInterfaceExprValue
|
||||
{
|
||||
public:
|
||||
enum TType { Boolean = 0, Integer, Double, String, RGBA, UserType, NoType };
|
||||
public:
|
||||
// default ctor
|
||||
CInterfaceExprValue() : _Type(NoType) {}
|
||||
// copy ctor
|
||||
CInterfaceExprValue(const CInterfaceExprValue &other);
|
||||
// assignment operator
|
||||
CInterfaceExprValue &operator = (const CInterfaceExprValue &other);
|
||||
// dtor
|
||||
~CInterfaceExprValue() { clean(); }
|
||||
|
||||
TType getType() const { return _Type; }
|
||||
// get. Should be used only if the type is valid
|
||||
bool getBool() const;
|
||||
sint64 getInteger() const;
|
||||
double getDouble() const;
|
||||
std::string getString() const;
|
||||
NLMISC::CRGBA getRGBA() const;
|
||||
const ucstring &getUCString() const;
|
||||
CInterfaceExprUserType *getUserType() const;
|
||||
// set
|
||||
void setBool(bool value) { clean(); _Type = Boolean; _BoolValue = value; }
|
||||
void setInteger(sint64 value) { clean(); _Type = Integer; _IntegerValue = value; }
|
||||
void setDouble(double value) { clean(); _Type = Double; _DoubleValue = value; }
|
||||
void setString(const std::string &value) { clean(); _Type = String; _StringValue = value; }
|
||||
void setUCString(const ucstring &value) { clean(); _Type = String; _StringValue = value; }
|
||||
void setRGBA(NLMISC::CRGBA value) { clean(); _Type = RGBA; _RGBAValue = (uint32)(value.R+(value.G<<8)+(value.B<<16)+(value.A<<24)); }
|
||||
void setUserType(CInterfaceExprUserType *value);
|
||||
// reset this object to initial state (no type)
|
||||
void clean();
|
||||
// conversions. They return true if success
|
||||
bool toBool();
|
||||
bool toInteger();
|
||||
bool toDouble();
|
||||
bool toString();
|
||||
bool toType(TType type);
|
||||
bool toRGBA();
|
||||
// test if the value if a bool, double, or integer
|
||||
bool isNumerical() const;
|
||||
/** evaluate a from a string
|
||||
* \param expr : where to start the evaluation
|
||||
* \return the position following the token, or NULL if the parsing failed
|
||||
*/
|
||||
const char *initFromString(const char *expr);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private:
|
||||
TType _Type;
|
||||
union
|
||||
{
|
||||
bool _BoolValue;
|
||||
sint64 _IntegerValue;
|
||||
double _DoubleValue;
|
||||
CInterfaceExprUserType *_UserTypeValue;
|
||||
uint32 _RGBAValue;
|
||||
};
|
||||
ucstring _StringValue; // well, can't fit in union, unless we do some horrible hack..
|
||||
private:
|
||||
const char *evalBoolean(const char *expr);
|
||||
const char *evalNumber(const char *expr);
|
||||
const char *evalString(const char *expr);
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for user defined types that are use by the 'CInterfaceExprValue' class
|
||||
* Derivers should include the 'clone' method
|
||||
*
|
||||
* CInterfaceExprValue instances have ownership of this object.
|
||||
*
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2003
|
||||
*/
|
||||
struct CInterfaceExprUserType
|
||||
{
|
||||
// cloning method
|
||||
virtual CInterfaceExprUserType *clone() const = 0;
|
||||
// dtor
|
||||
virtual ~CInterfaceExprUserType() {}
|
||||
};
|
||||
|
||||
|
||||
/** Evaluate expressions used in interface.
|
||||
* It can retrieve values from the database.
|
||||
* It can also build a list of database values it depends of.
|
||||
*
|
||||
* An expression can be :
|
||||
*
|
||||
* - a string : 'toto', 'abcd', 'a\nbcd', 'a\\t', the escape sequences are the one of C
|
||||
* - a integer 1, 2, 3
|
||||
* - a double 1.1, 2.2
|
||||
* - a database entry : @ui:interface:toto:truc. If the address is a leaf, it returns the leaf value and put an observer on it. If not a leaf, it returns 0, but put an observer on it.
|
||||
* - a database indirection @db:value[db:index] is replaced by @db:value0 if db:index == 0 for example
|
||||
* - a user function call : fct(expr0, epxr1, ...).
|
||||
*
|
||||
* NB : The lua language has been integrated since then (2005), and should be more suited
|
||||
* for most of the tasks.
|
||||
*
|
||||
*
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2002
|
||||
*/
|
||||
class CInterfaceExpr
|
||||
{
|
||||
public:
|
||||
// list of argument for a function
|
||||
typedef std::vector<CInterfaceExprValue> TArgList;
|
||||
/** prototype of a user callable function
|
||||
* It should return true if the result is meaningful. If not, the rest of the evaluation is stopped
|
||||
*/
|
||||
typedef bool (* TUserFct) (TArgList &args, CInterfaceExprValue &result);
|
||||
public:
|
||||
|
||||
// release memory
|
||||
static void release();
|
||||
|
||||
/** This try to eval the provided expression.
|
||||
* - This returns a result
|
||||
* - This eventually fill a vector with a set of database entries it has dependencies on
|
||||
* \param expr The expression to evaluate
|
||||
* \param result The result value
|
||||
* \param nodes If not NULL, will be filled with the database nodes this expression depends on
|
||||
* Node will only be inserted once, so we end up with a set of node (not ordered)
|
||||
* \param noFctCalls when set to true, the terminal function calls will not be made, so the evaluation is only used to see which database entries the expression depends on.
|
||||
*/
|
||||
static bool eval(const std::string &expr, CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> *nodes = NULL, bool noFctCalls = false);
|
||||
|
||||
/** Build a tree from the given expression so that it can be evaluated quickly.
|
||||
* This is useful for a fixed expression that must be evaluated often
|
||||
*/
|
||||
static CInterfaceExprNode *buildExprTree(const std::string &expr);
|
||||
|
||||
|
||||
/** Register a function that can have several arguments
|
||||
* // NB : this is case sensitive
|
||||
*/
|
||||
static void registerUserFct(const char *name, TUserFct fct);
|
||||
// Simple evaluations
|
||||
static bool evalAsInt(const std::string &expr, sint64 &dest);
|
||||
static bool evalAsDouble(const std::string &expr, double &dest);
|
||||
static bool evalAsBool(const std::string &expr, bool &dest);
|
||||
static bool evalAsString(const std::string &expr, std::string &dest);
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private:
|
||||
// map of user functions
|
||||
typedef std::map<std::string, TUserFct> TUserFctMap;
|
||||
private:
|
||||
static TUserFctMap *_UserFct;
|
||||
private:
|
||||
/** eval the value of a single expression
|
||||
* \return position to the next valid character
|
||||
*/
|
||||
static const char *evalExpr(const char *expr, CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> *nodes, bool noFctCalls);
|
||||
static const char *evalFct(const char *expr,CInterfaceExprValue &result,std::vector<NLMISC::ICDBNode *> *nodes, bool noFctCalls);
|
||||
static const char *evalDBEntry(const char *expr,CInterfaceExprValue &result,std::vector<NLMISC::ICDBNode *> *nodes);
|
||||
public:
|
||||
static const char *unpackDBentry(const char *expr, std::vector<NLMISC::ICDBNode *> *nodes, std::string &dest, bool *hasIndirections = NULL);
|
||||
|
||||
/** Build tree of a single expression
|
||||
* \return position to the next valid character
|
||||
*/
|
||||
private:
|
||||
static const char *buildExprTree(const char *expr, CInterfaceExprNode *&result);
|
||||
static const char *buildFctNode(const char *expr, CInterfaceExprNode *&result);
|
||||
static const char *buildDBEntryNode(const char *expr,CInterfaceExprNode *&result);
|
||||
};
|
||||
|
||||
|
||||
// helper macro to register user functions at startup
|
||||
#define REGISTER_INTERFACE_USER_FCT(name, fct) \
|
||||
const struct __InterUserFctRegister__##fct\
|
||||
{\
|
||||
__InterUserFctRegister__##fct() { CInterfaceExpr::registerUserFct(name, fct); }\
|
||||
} __InterUserFctRegisterInstance__##fct;
|
||||
|
||||
|
||||
// helper macro to declare a user function
|
||||
// the code must follow
|
||||
// arguments are available in 'args', result should be put in 'result'
|
||||
#define DECLARE_INTERFACE_USER_FCT(name) \
|
||||
bool name(CInterfaceExpr::TArgList &args, CInterfaceExprValue &result)
|
||||
|
||||
|
||||
// helper macro to declare a C constant mirroring
|
||||
#define DECLARE_INTERFACE_CONSTANT(_name, _cconst) \
|
||||
static DECLARE_INTERFACE_USER_FCT(_name) \
|
||||
{ \
|
||||
result.setInteger(_cconst); \
|
||||
return true; \
|
||||
} \
|
||||
REGISTER_INTERFACE_USER_FCT(#_name, _name)
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
#include "stdpch.h"
|
||||
#include "interface_expr_node.h"
|
||||
#include "nel/misc/cdb_leaf.h"
|
||||
#include "nel/misc/cdb_branch.h"
|
||||
|
||||
using NLMISC::ICDBNode;
|
||||
using NLMISC::CCDBNodeBranch;
|
||||
using NLMISC::CCDBNodeLeaf;
|
||||
|
||||
// *******************************************************************************************************
|
||||
void CInterfaceExprNodeValue::eval(CInterfaceExprValue &result)
|
||||
{
|
||||
result = Value;
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeValue::evalWithDepends(CInterfaceExprValue &result, std::vector<ICDBNode *> &/* nodes */)
|
||||
{
|
||||
result = Value;
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeValue::getDepends(std::vector<ICDBNode *> &/* nodes */)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// *******************************************************************************************************
|
||||
void CInterfaceExprNodeValueFnCall::eval(CInterfaceExprValue &result)
|
||||
{
|
||||
nlassert(Func);
|
||||
uint numParams = (uint)Params.size();
|
||||
std::vector<CInterfaceExprValue> params(numParams);
|
||||
for(uint k = 0; k < numParams; ++k)
|
||||
{
|
||||
Params[k]->eval(params[k]);
|
||||
}
|
||||
Func(params, result); // do actual call
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeValueFnCall::evalWithDepends(CInterfaceExprValue &result, std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
nlassert(Func);
|
||||
uint numParams = (uint)Params.size();
|
||||
std::vector<CInterfaceExprValue> params(numParams);
|
||||
for(uint k = 0; k < numParams; ++k)
|
||||
{
|
||||
Params[k]->evalWithDepends(params[k], nodes);
|
||||
}
|
||||
Func(params, result); // do actual call
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeValueFnCall::getDepends(std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
uint numParams = (uint)Params.size();
|
||||
for(uint k = 0; k < numParams; ++k)
|
||||
{
|
||||
Params[k]->getDepends(nodes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CInterfaceExprNodeValueFnCall::~CInterfaceExprNodeValueFnCall()
|
||||
{
|
||||
for(uint k = 0; k < Params.size(); ++k)
|
||||
{
|
||||
delete Params[k];
|
||||
}
|
||||
}
|
||||
|
||||
// *******************************************************************************************************
|
||||
void CInterfaceExprNodeDBLeaf::eval(CInterfaceExprValue &result)
|
||||
{
|
||||
nlassert(Leaf);
|
||||
result.setInteger(Leaf->getValue64());
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDBLeaf::evalWithDepends(CInterfaceExprValue &result,std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
nlassert(Leaf);
|
||||
result.setInteger(Leaf->getValue64());
|
||||
if (std::find(nodes.begin(), nodes.end(), Leaf) == nodes.end())
|
||||
{
|
||||
nodes.push_back(Leaf);
|
||||
}
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDBLeaf::getDepends(std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
nlassert(Leaf);
|
||||
if (std::find(nodes.begin(), nodes.end(), Leaf) == nodes.end())
|
||||
{
|
||||
nodes.push_back(Leaf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *******************************************************************************************************
|
||||
void CInterfaceExprNodeDBBranch::eval(CInterfaceExprValue &result)
|
||||
{
|
||||
nlassert(Branch);
|
||||
result.setInteger(0);
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDBBranch::evalWithDepends(CInterfaceExprValue &result,std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
nlassert(Branch);
|
||||
result.setInteger(0);
|
||||
if (std::find(nodes.begin(), nodes.end(), Branch) == nodes.end())
|
||||
{
|
||||
nodes.push_back(Branch);
|
||||
}
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDBBranch::getDepends(std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
nlassert(Branch);
|
||||
if (std::find(nodes.begin(), nodes.end(), Branch) == nodes.end())
|
||||
{
|
||||
nodes.push_back(Branch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *******************************************************************************************************
|
||||
void CInterfaceExprNodeDependantDBRead::eval(CInterfaceExprValue &result)
|
||||
{
|
||||
// no gain there, but barely used
|
||||
CInterfaceExpr::eval(Expr, result);
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDependantDBRead::evalWithDepends(CInterfaceExprValue &result, std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
CInterfaceExpr::eval(Expr, result, &nodes);
|
||||
}
|
||||
|
||||
void CInterfaceExprNodeDependantDBRead::getDepends(std::vector<ICDBNode *> &nodes)
|
||||
{
|
||||
CInterfaceExprValue dummyResult;
|
||||
CInterfaceExpr::eval(Expr, dummyResult, &nodes, true);
|
||||
}
|
||||
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
#ifndef CL_INTERFACE_EXPR_NODE_H
|
||||
#define CL_INTERFACE_EXPR_NODE_H
|
||||
|
||||
#include "interface_expr.h"
|
||||
|
||||
/** Base node of an interface expression parse tree
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2003
|
||||
*/
|
||||
class CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
virtual ~CInterfaceExprNode() {}
|
||||
// eval result of expression, and eventually get the nodes the epression depends on
|
||||
virtual void eval(CInterfaceExprValue &result) = 0;
|
||||
// The same, but get db nodes the expression depends on (appended to vector)
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes) = 0;
|
||||
// Get dependencies of the node (appended to vector)
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes) = 0;
|
||||
};
|
||||
|
||||
|
||||
// *******************************************************************************************************
|
||||
/** A constant value already parsed by interface (in a interface expr parse tree)
|
||||
*/
|
||||
class CInterfaceExprNodeValue : public CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
CInterfaceExprValue Value;
|
||||
public:
|
||||
virtual void eval(CInterfaceExprValue &result);
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
};
|
||||
|
||||
// *******************************************************************************************************
|
||||
/** A fct call (in a interface expr parse tree)
|
||||
*/
|
||||
class CInterfaceExprNodeValueFnCall : public CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
CInterfaceExpr::TUserFct Func;
|
||||
// list of parameters
|
||||
std::vector<CInterfaceExprNode *> Params;
|
||||
public:
|
||||
virtual void eval(CInterfaceExprValue &result);
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual ~CInterfaceExprNodeValueFnCall();
|
||||
};
|
||||
|
||||
// *******************************************************************************************************
|
||||
/** A db leaf read (in a interface expr parse tree)
|
||||
*/
|
||||
class CInterfaceExprNodeDBLeaf : public CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
class NLMISC::CCDBNodeLeaf *Leaf;
|
||||
public:
|
||||
virtual void eval(CInterfaceExprValue &result);
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
};
|
||||
|
||||
// *******************************************************************************************************
|
||||
/** A db branch read (in a interface expr parse tree)
|
||||
*/
|
||||
class CInterfaceExprNodeDBBranch : public CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
class NLMISC::CCDBNodeBranch *Branch;
|
||||
public:
|
||||
virtual void eval(CInterfaceExprValue &result);
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
};
|
||||
|
||||
// *******************************************************************************************************
|
||||
/** A dependant db read (in a interface expr parse tree)
|
||||
* This is rarely used so no real optim there..
|
||||
*/
|
||||
class CInterfaceExprNodeDependantDBRead : public CInterfaceExprNode
|
||||
{
|
||||
public:
|
||||
std::string Expr;
|
||||
public:
|
||||
virtual void eval(CInterfaceExprValue &result);
|
||||
virtual void evalWithDepends(CInterfaceExprValue &result, std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
virtual void getDepends(std::vector<NLMISC::ICDBNode *> &nodes);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -20,7 +20,7 @@
|
|||
#include "stdpch.h"
|
||||
|
||||
// client
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "ctrl_sheet_selection.h"
|
||||
#include "interface_manager.h"
|
||||
// game_share
|
||||
|
@ -519,7 +519,7 @@ static DECLARE_INTERFACE_USER_FCT(userFctGetProp)
|
|||
|
||||
string sTmp = args[0].getString();
|
||||
std::vector<CInterfaceLink::CTargetInfo> targetsVector;
|
||||
CInterfaceParser::splitLinkTargets(sTmp, NULL, targetsVector);
|
||||
CInterfaceLink::splitLinkTargets(sTmp, NULL, targetsVector);
|
||||
|
||||
if (targetsVector.empty())
|
||||
{
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include "stdpch.h"
|
||||
// Interface
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "interface_manager.h"
|
||||
#include "interface_element.h"
|
||||
#include "chat_window.h"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
// client
|
||||
#include "../sheet_manager.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "dbctrl_sheet.h"
|
||||
#include "ctrl_sheet_selection.h"
|
||||
#include "dbgroup_list_sheet.h"
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
|
||||
#include "stdpch.h"
|
||||
#include "interface_link.h"
|
||||
#include "interface_expr.h"
|
||||
#include "interface_element.h"
|
||||
#include "interface_manager.h"
|
||||
#include "interface_expr_node.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "nel/gui/interface_expr_node.h"
|
||||
#include "nel/gui/reflect.h"
|
||||
#include "nel/gui/db_manager.h"
|
||||
#include "nel/misc/cdb_branch.h"
|
||||
|
@ -444,6 +444,88 @@ void CInterfaceLink::removeAllLinks()
|
|||
nlassert(_LinkList.empty());
|
||||
}
|
||||
|
||||
// ***************************************************************************
|
||||
bool CInterfaceLink::splitLinkTarget(const std::string &target, CInterfaceGroup *parentGroup, std::string &propertyName, CInterfaceElement *&targetElm)
|
||||
{
|
||||
// the last token of the target gives the name of the property
|
||||
std::string::size_type lastPos = target.find_last_of(':');
|
||||
if (lastPos == (target.length() - 1))
|
||||
{
|
||||
// todo hulud interface syntax error
|
||||
nlwarning("The target should at least contains a path and a property as follow 'path:property'");
|
||||
return false;
|
||||
}
|
||||
std::string elmPath;
|
||||
std::string elmProp;
|
||||
CInterfaceElement *elm = NULL;
|
||||
if (parentGroup)
|
||||
{
|
||||
if (lastPos == std::string::npos)
|
||||
{
|
||||
elmProp = target;
|
||||
elm = parentGroup;
|
||||
elmPath = "current";
|
||||
}
|
||||
else
|
||||
{
|
||||
elmProp = target.substr(lastPos + 1);
|
||||
elmPath = parentGroup->getId() + ":" + target.substr(0, lastPos);
|
||||
elm = parentGroup->getElement(elmPath);
|
||||
}
|
||||
}
|
||||
if (!elm)
|
||||
{
|
||||
// try the absolute adress of the element
|
||||
elmPath = target.substr(0, lastPos);
|
||||
elm = CInterfaceManager::getInstance()->getElementFromId(elmPath);
|
||||
elmProp = target.substr(lastPos + 1);
|
||||
}
|
||||
|
||||
if (!elm)
|
||||
{
|
||||
// todo hulud interface syntax error
|
||||
nlwarning("<splitLinkTarget> can't find target link %s", elmPath.c_str());
|
||||
return false;
|
||||
}
|
||||
targetElm = elm;
|
||||
propertyName = elmProp;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
bool CInterfaceLink::splitLinkTargets(const std::string &targets, CInterfaceGroup *parentGroup,std::vector<CInterfaceLink::CTargetInfo> &targetsVect)
|
||||
{
|
||||
std::vector<std::string> targetNames;
|
||||
NLMISC::splitString(targets, ",", targetNames);
|
||||
targetsVect.clear();
|
||||
targetsVect.reserve(targetNames.size());
|
||||
bool everythingOk = true;
|
||||
for (uint k = 0; k < targetNames.size(); ++k)
|
||||
{
|
||||
CInterfaceLink::CTargetInfo ti;
|
||||
std::string::size_type startPos = targetNames[k].find_first_not_of(" ");
|
||||
if(startPos == std::string::npos)
|
||||
{
|
||||
// todo hulud interface syntax error
|
||||
nlwarning("<splitLinkTargets> empty target encountered");
|
||||
continue;
|
||||
}
|
||||
std::string::size_type lastPos = targetNames[k].find_last_not_of(" ");
|
||||
|
||||
if (!splitLinkTarget(targetNames[k].substr(startPos, lastPos - startPos+1), parentGroup, ti.PropertyName, ti.Elem))
|
||||
{
|
||||
// todo hulud interface syntax error
|
||||
nlwarning("<splitLinkTargets> Can't get link target");
|
||||
everythingOk = false;
|
||||
continue;
|
||||
}
|
||||
targetsVect.push_back(ti);
|
||||
}
|
||||
return everythingOk;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================
|
||||
void CInterfaceLink::checkNbRefs()
|
||||
{
|
||||
|
@ -470,7 +552,7 @@ void CInterfaceLink::setTargetProperty (const std::string &Target, const CInt
|
|||
if (pIG != NULL)
|
||||
{
|
||||
std::vector<CTargetInfo> vTargets;
|
||||
CInterfaceParser::splitLinkTargets(Target, pIG, vTargets);
|
||||
splitLinkTargets(Target, pIG, vTargets);
|
||||
if ((vTargets.size() > 0) && (vTargets[0].Elem))
|
||||
{
|
||||
vTargets[0].affect(val);
|
||||
|
|
|
@ -25,13 +25,14 @@
|
|||
namespace NLGUI
|
||||
{
|
||||
class CReflectedProperty;
|
||||
class CInterfaceExprValue;
|
||||
class CInterfaceExprNode;
|
||||
}
|
||||
|
||||
|
||||
class CInterfaceElement;
|
||||
class CInterfaceExprValue;
|
||||
class CInterfaceGroup;
|
||||
class CInterfaceExprNode;
|
||||
|
||||
|
||||
using namespace NLGUI;
|
||||
|
||||
|
@ -115,6 +116,16 @@ public:
|
|||
static void setTargetProperty (const std::string & Target, const CInterfaceExprValue &val);
|
||||
|
||||
static bool isUpdatingAllLinks() { return _UpdateAllLinks; }
|
||||
|
||||
/** From a target name of a link, retrieve the target element and its target target property
|
||||
* \return true if the target is valid
|
||||
*/
|
||||
static bool splitLinkTarget(const std::string &target, CInterfaceGroup *parentGroup, std::string &propertyName, CInterfaceElement *&targetElm);
|
||||
|
||||
/** From several target names of a link (seprated by ','), retrieve the target elements and their target properties
|
||||
* \return true if all targets are valid
|
||||
*/
|
||||
static bool splitLinkTargets(const std::string &targets, CInterfaceGroup *parentGroup, std::vector<CInterfaceLink::CTargetInfo> &targetsVect);
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private:
|
||||
friend struct CRemoveTargetPred;
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "../client_cfg.h"
|
||||
#include "encyclopedia_manager.h"
|
||||
// Expr
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "register_interface_elements.h"
|
||||
// Action / Observers
|
||||
#include "action_handler.h"
|
||||
|
|
|
@ -1403,7 +1403,7 @@ bool CInterfaceParser::parseLink(xmlNodePtr cur, CInterfaceGroup * parentGroup)
|
|||
ptr = (char*) xmlGetProp (cur, (xmlChar*)"target");
|
||||
if (ptr)
|
||||
{
|
||||
splitLinkTargets(std::string((const char*)ptr), parentGroup, targets);
|
||||
CInterfaceLink::splitLinkTargets(std::string((const char*)ptr), parentGroup, targets);
|
||||
}
|
||||
// optional action handler
|
||||
std::string action;
|
||||
|
@ -2925,88 +2925,6 @@ bool CInterfaceParser::parseSheetSelection(xmlNodePtr cur)
|
|||
return true;
|
||||
}
|
||||
|
||||
// ***************************************************************************
|
||||
bool CInterfaceParser::splitLinkTarget(const std::string &target, CInterfaceGroup *parentGroup, std::string &propertyName, CInterfaceElement *&targetElm)
|
||||
{
|
||||
// the last token of the target gives the name of the property
|
||||
std::string::size_type lastPos = target.find_last_of(':');
|
||||
if (lastPos == (target.length() - 1))
|
||||
{
|
||||
// todo hulud interface syntax error
|
||||
nlwarning("The target should at least contains a path and a property as follow 'path:property'");
|
||||
return false;
|
||||
}
|
||||
std::string elmPath;
|
||||
std::string elmProp;
|
||||
CInterfaceElement *elm = NULL;
|
||||
if (parentGroup)
|
||||
{
|
||||
if (lastPos == std::string::npos)
|
||||
{
|
||||
elmProp = target;
|
||||
elm = parentGroup;
|
||||
elmPath = "current";
|
||||
}
|
||||
else
|
||||
{
|
||||
elmProp = target.substr(lastPos + 1);
|
||||
elmPath = parentGroup->getId() + ":" + target.substr(0, lastPos);
|
||||
elm = parentGroup->getElement(elmPath);
|
||||
}
|
||||
}
|
||||
if (!elm)
|
||||
{
|
||||
// try the absolute adress of the element
|
||||
elmPath = target.substr(0, lastPos);
|
||||
elm = CInterfaceManager::getInstance()->getElementFromId(elmPath);
|
||||
elmProp = target.substr(lastPos + 1);
|
||||
}
|
||||
|
||||
if (!elm)
|
||||
{
|
||||
// todo hulud interface syntax error
|
||||
nlwarning("<CInterfaceParser::splitLinkTarget> can't find target link %s", elmPath.c_str());
|
||||
return false;
|
||||
}
|
||||
targetElm = elm;
|
||||
propertyName = elmProp;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
bool CInterfaceParser::splitLinkTargets(const std::string &targets, CInterfaceGroup *parentGroup,std::vector<CInterfaceLink::CTargetInfo> &targetsVect)
|
||||
{
|
||||
std::vector<std::string> targetNames;
|
||||
NLMISC::splitString(targets, ",", targetNames);
|
||||
targetsVect.clear();
|
||||
targetsVect.reserve(targetNames.size());
|
||||
bool everythingOk = true;
|
||||
for (uint k = 0; k < targetNames.size(); ++k)
|
||||
{
|
||||
CInterfaceLink::CTargetInfo ti;
|
||||
std::string::size_type startPos = targetNames[k].find_first_not_of(" ");
|
||||
if(startPos == std::string::npos)
|
||||
{
|
||||
// todo hulud interface syntax error
|
||||
nlwarning("<CInterfaceParser::splitLinkTargets> empty target encountered");
|
||||
continue;
|
||||
}
|
||||
std::string::size_type lastPos = targetNames[k].find_last_not_of(" ");
|
||||
|
||||
if (!splitLinkTarget(targetNames[k].substr(startPos, lastPos - startPos+1), parentGroup, ti.PropertyName, ti.Elem))
|
||||
{
|
||||
// todo hulud interface syntax error
|
||||
nlwarning("<CInterfaceParser::splitLinkTargets> Can't get link target");
|
||||
everythingOk = false;
|
||||
continue;
|
||||
}
|
||||
targetsVect.push_back(ti);
|
||||
}
|
||||
return everythingOk;
|
||||
}
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
bool CInterfaceParser::addLink(CInterfaceLink *link, const std::string &id)
|
||||
{
|
||||
|
|
|
@ -214,16 +214,6 @@ public:
|
|||
void setDefine(const std::string &id, const std::string &value);
|
||||
// @}
|
||||
|
||||
/** From a target name of a link, retrieve the target element and its target target property
|
||||
* \return true if the target is valid
|
||||
*/
|
||||
static bool splitLinkTarget(const std::string &target, CInterfaceGroup *parentGroup, std::string &propertyName, CInterfaceElement *&targetElm);
|
||||
|
||||
/** From several target names of a link (seprated by ','), retrieve the target elements and their target properties
|
||||
* \return true if all targets are valid
|
||||
*/
|
||||
static bool splitLinkTargets(const std::string &targets, CInterfaceGroup *parentGroup, std::vector<CInterfaceLink::CTargetInfo> &targetsVect);
|
||||
|
||||
/// \name Dynamic links mgt
|
||||
// @{
|
||||
/** Associate the given dynamic link with an ID
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
#include "game_share/people_pd.h"
|
||||
#include "group_tree.h"
|
||||
#include "interface_link.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "people_interraction.h"
|
||||
#include "nel/misc/algo.h"
|
||||
#include "nel/misc/file.h"
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "dbgroup_combo_box.h"
|
||||
#include "group_container.h"
|
||||
#include "group_modal_get_key.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
|
||||
// tmp
|
||||
#include "../r2/editor.h"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
// client
|
||||
#include "../string_manager_client.h"
|
||||
#include "people_interraction.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "interface_manager.h"
|
||||
#include "action_handler.h"
|
||||
#include "action_handler_misc.h"
|
||||
|
@ -30,7 +30,7 @@
|
|||
#include "group_menu.h"
|
||||
#include "../client_chat_manager.h"
|
||||
#include "../string_manager_client.h"
|
||||
#include "interface_expr.h"
|
||||
#include "nel/gui/interface_expr.h"
|
||||
#include "ctrl_button.h"
|
||||
#include "ctrl_text_button.h"
|
||||
#include "filtered_chat_summary.h"
|
||||
|
@ -1027,7 +1027,7 @@ class CHandlerChatGroupFilter : public IActionHandler
|
|||
CCtrlTabButton *pTabButton= dynamic_cast<CCtrlTabButton*>(pCaller);
|
||||
if(pTabButton)
|
||||
{
|
||||
CRGBA stdColor= stringToRGBA(pIM->getDefine("chat_group_tab_color_normal").c_str());
|
||||
CRGBA stdColor= CRGBA::stringToRGBA(pIM->getDefine("chat_group_tab_color_normal").c_str());
|
||||
pTabButton->setTextColorNormal(stdColor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -976,21 +976,6 @@ std::string getStringCategoryIfAny(const ucstring &src, ucstring &dest)
|
|||
}
|
||||
|
||||
|
||||
NLMISC::CRGBA stringToRGBA(const char *ptr)
|
||||
{
|
||||
if (!ptr) return NLMISC::CRGBA::White;
|
||||
int r = 255, g = 255, b = 255, a = 255;
|
||||
sscanf (ptr, "%d %d %d %d", &r, &g, &b, &a);
|
||||
NLMISC::clamp (r, 0, 255);
|
||||
NLMISC::clamp (g, 0, 255);
|
||||
NLMISC::clamp (b, 0, 255);
|
||||
NLMISC::clamp (a, 0, 255);
|
||||
return CRGBA(r,g,b,a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
|
||||
inline bool isSeparator (ucchar c)
|
||||
|
|
|
@ -166,9 +166,6 @@ std::string getStringCategory(const ucstring &src, ucstring &dest, bool alwaysAd
|
|||
// Get the category from the string (src="&SYS&Who are you?" and dest="Who are you?" and return "SYS"), if no category, return ""
|
||||
std::string getStringCategoryIfAny(const ucstring &src, ucstring &dest);
|
||||
|
||||
NLMISC::CRGBA stringToRGBA(const char *ptr);
|
||||
|
||||
|
||||
// Number of shortcut
|
||||
#define RYZOM_MAX_SHORTCUT 20
|
||||
|
||||
|
|
Loading…
Reference in a new issue