Merge remote-tracking branch 'ryzomcore/develop' into develop

develop
kaetemi 4 years ago
commit 56d747fa02
No known key found for this signature in database
GPG Key ID: 9873C4D40BB479BC

6
.gitignore vendored

@ -127,6 +127,9 @@ aes_state.txt
# intellij project folder
.idea/
# VSCode project folder
.vscode/
# Python cache
*.pyd
*.pyc
@ -242,6 +245,9 @@ external_stlport
nel_tools*
ryzom_tools*
#personal projects
personal/
# Dumps
*.dmp

@ -73,7 +73,7 @@ namespace NLGUI
void preprocess();
// parse selectors + combinators
std::vector<CCssSelector> parse_selector(const std::string &sel, std::string &pseudoElement) const;
std::vector<CCssSelector> parse_selector(const std::string &sel, std::string &pseudoElement, std::string::size_type &pos) const;
// parse selector and style
void parseRule(const std::string &selectorString, const std::string &styleString);

@ -96,6 +96,8 @@ namespace NLGUI
// match An+B rule to child index (1 based)
bool matchNth(sint childNr, sint a, sint b) const;
// match :lang(xx)
bool matchLang(const CHtmlElement &elm, const std::string &pseudo) const;
// parse nth-child string to 'a' and 'b' components
// :nth-child(odd)

@ -188,6 +188,12 @@ namespace NLGUI
void applyLineStyle(const std::string &value, CSSLineStyle *dest, const CSSLineStyle &currentStyle) const;
void applyPaddingWidth(const std::string &value, uint32 *dest, const uint32 currentPadding, uint32 fontSize) const;
// parse and replace var(--name, fallback) function
// return false if property should be ignored
bool cssFuncVar(std::string &func, const TStyle &styleRules, const std::set<std::string> &seenProperties) const;
// return false if property was not defined
bool lookupPropertyValue(const std::string &name, std::string &value, const TStyle &styleRules) const;
public:
void reset();

@ -36,6 +36,7 @@ typedef void CURLM;
namespace NLGUI
{
class CViewLink;
class CCtrlButton;
class CCtrlTextButton;
class CCtrlScroll;
@ -117,6 +118,9 @@ namespace NLGUI
// Browse error
void browseError (const char *msg);
// Error message with html content
void browseErrorHtml(const std::string &html);
bool isBrowsing();
// Update coords
@ -139,37 +143,15 @@ namespace NLGUI
float getTimeout() const {return (float)_TimeoutValue;}
// Some constants
NLMISC::CRGBA BgColor;
NLMISC::CRGBA ErrorColor;
NLMISC::CRGBA LinkColor;
NLMISC::CRGBA TextColor;
NLMISC::CRGBA H1Color;
NLMISC::CRGBA H2Color;
NLMISC::CRGBA H3Color;
NLMISC::CRGBA H4Color;
NLMISC::CRGBA H5Color;
NLMISC::CRGBA H6Color;
bool ErrorColorGlobalColor;
bool LinkColorGlobalColor;
bool TextColorGlobalColor;
bool H1ColorGlobalColor;
bool H2ColorGlobalColor;
bool H3ColorGlobalColor;
bool H4ColorGlobalColor;
bool H5ColorGlobalColor;
bool H6ColorGlobalColor;
uint TextFontSize;
uint H1FontSize;
uint H2FontSize;
uint H3FontSize;
uint H4FontSize;
uint H5FontSize;
uint H6FontSize;
uint TDBeginSpace;
uint PBeginSpace;
uint LIBeginSpace;
uint ULBeginSpace;
uint LIIndent;
uint ULIndent;
float LineSpaceFontFactor;
std::string DefaultButtonGroup;
@ -184,7 +166,6 @@ namespace NLGUI
std::string DefaultRadioButtonBitmapPushed;
std::string DefaultRadioButtonBitmapOver;
std::string DefaultBackgroundBitmapView;
std::string CurrentLinkTitle;
struct TFormField {
public:
@ -324,6 +305,12 @@ namespace NLGUI
// Translate a char
bool translateChar(u32char &output, u32char input, u32char lastChar) const;
// return true if text has same style
bool isSameStyle(CViewLink *text, const CStyleParams &style) const;
// add text link using template
void newTextButton(const std::string &text, const std::string &tpl);
void newTextLink(const std::string &text);
// Add a string in the current paragraph
void addString(const std::string &str);
@ -749,9 +736,7 @@ namespace NLGUI
bool _Localize;
// Current node is a text area
bool _TextArea;
std::string _TextAreaTemplate;
std::string _TextAreaContent;
std::string _TextAreaName;
uint _TextAreaRow;
uint _TextAreaCols;
@ -858,6 +843,7 @@ namespace NLGUI
CCurlWWWData *data;
std::string url;
std::string dest;
std::string tmpdest;
std::string luaScript;
std::string md5sum;
TDataType type;
@ -1001,11 +987,9 @@ namespace NLGUI
void htmlTD(const CHtmlElement &elm);
void htmlTDend(const CHtmlElement &elm);
void htmlTEXTAREA(const CHtmlElement &elm);
void htmlTEXTAREAend(const CHtmlElement &elm);
void htmlTH(const CHtmlElement &elm);
void htmlTHend(const CHtmlElement &elm);
void htmlTITLE(const CHtmlElement &elm);
void htmlTITLEend(const CHtmlElement &elm);
void htmlTR(const CHtmlElement &elm);
void htmlTRend(const CHtmlElement &elm);
//void htmlU(const CHtmlElement &elm);

@ -55,6 +55,8 @@ namespace NLGUI
Right
};
enum TTextAlign { AlignLeft = 0, AlignCenter, AlignRight, AlignJustify };
///constructor
CGroupParagraph(const TCtorParam &param);
@ -98,6 +100,8 @@ namespace NLGUI
// the same, but with id taken from the database
void addTextChildID (const std::string &dbPath, bool multiLine = true);
void setTextAlign(const TTextAlign align) { _TextAlign = align; }
protected:
void delChild (CViewBase* child);
@ -271,6 +275,9 @@ namespace NLGUI
// (the element drawn are stored in _views, _contrlos or _childrengroups of cinterfacegroup
std::vector<CElementInfo> _Elements;
// Horizontal align for elements
TTextAlign _TextAlign;
// Last parent width
sint32 _LastW;

@ -75,6 +75,18 @@ namespace NLGUI
// update Children index/parent/next/prevSibling pointers
void reindexChilds();
// escape text tag or attribute value
std::string htmlEscape(std::string val, bool isAttribute = false) const;
// serialize element attributes as string
std::string serializeAttributes() const;
// serialize child elements as html string
std::string serializeChilds() const;
// serialize itself and children as html string
std::string serialize() const;
// debug
std::string toString(bool tree = false, uint depth = 0) const;
@ -84,6 +96,9 @@ namespace NLGUI
TStyle getPseudo(const std::string &key) const;
void setPseudo(const std::string &key, const TStyle &style);
// return lang property for css :lang() pseudo class
std::string getInheritedLanguage() const;
private:
// pseudo elements like ":before" and ":after"
std::map<std::string, TStyle> _Pseudo;

@ -19,6 +19,9 @@
#include "nel/misc/types_nl.h"
// Forward declarations for libxml2
typedef struct _xmlNode xmlNode;
namespace NLGUI
{
class CHtmlElement;

@ -444,9 +444,13 @@ namespace NLGUI
SGlobalTexture ()
{
FromGlobaleTexture = true;
Scale = 1.f;
}
uint32 Width, Height;
uint32 DefaultWidth, DefaultHeight;
// used by texture atlas to unscale individual texture
// getTextureSizeFromId() calls to return 1x size for GUI.
float Scale;
NL3D::UTexture *Texture;
std::string Name;
bool FromGlobaleTexture;

@ -32,7 +32,7 @@ public:
uint32 Size;
uint32 LastModified;
void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
void serial(NLMISC::IStream &f);
};
@ -40,7 +40,7 @@ public:
CStreamedPackage();
~CStreamedPackage();
void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
void serial(NLMISC::IStream &f);
/// result: [out] ex. /00/00/000000000..
/// hash: [in]

@ -0,0 +1,74 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// 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 XML_MACROS_H
#define XML_MACROS_H
//
// xmlNodePtr cur;
// CXMLAutoPtr prop;
//
// sint i;
// XML_READ_SINT(cur, "prop_name", i, -1);
//
#define XML_READ_UINT(node, name, var, def) { \
uint tmp; \
prop = (char *) xmlGetProp(node, (xmlChar*)name); \
if (prop && fromString((const char*)prop, tmp)) \
var = tmp; \
else \
var = def; \
}
#define XML_READ_SINT(node, name, var, def) { \
sint tmp; \
prop = (char *) xmlGetProp(node, (xmlChar*)name); \
if (prop && fromString((const char*)prop, tmp)) \
var = tmp; \
else \
var = def; \
}
#define XML_READ_BOOL(node, name, var, def) { \
prop = (char *) xmlGetProp(node, (xmlChar*)name); \
if (prop) \
var = NLMISC::toBool((const char*)prop); \
else \
var = def; \
}
#define XML_READ_COLOR(node, name, var, def) { \
NLMISC::CRGBA tmp; \
prop = (char *) xmlGetProp(node, (xmlChar*)name); \
if (prop && fromString((const char*)prop, tmp)) \
var = tmp; \
else \
var = def; \
}
#define XML_READ_STRING(node, name, var, def) { \
prop = (char *) xmlGetProp(node, (xmlChar*)name); \
if (prop) \
var = (const char*)prop; \
else \
var = def; \
}
#endif // XML_MACROS_H

@ -146,6 +146,9 @@ void CFontManager::computeString (NLMISC::CUtfStringView sv,
{
// Creating font
k.Char = *it;
// draw tab as space
if (k.Char == '\t')
k.Char = ' ';
if (k.Char < 0x20) // Control Characters
k.Char += 0x2400;
if (k.Char == 0x7F) // DEL
@ -304,6 +307,9 @@ void CFontManager::computeStringInfo ( NLMISC::CUtfStringView sv,
{
// Creating font
k.Char = *it;
// draw tab as space
if (k.Char == '\t')
k.Char = ' ';
if (k.Char < 0x20)
k.Char += 0x2400;
k.FontGenerator = fontGen;

@ -50,7 +50,11 @@ namespace NLGUI
pos = elements[i].find_first_of(':');
if (pos != std::string::npos)
{
std::string key = trim(toLowerAscii(elements[i].substr(0, pos)));
// css properties are case-insensitive, but
// custom properties (--name; ...;) are case sensitive
std::string key = trim(elements[i].substr(0, pos));
if (key.size() < 2 || (key[0] != '-' && key[1] != '-'))
key = toLowerAscii(key);
std::string value = trim(elements[i].substr(pos+1));
styles.push_back(TStylePair(key, value));
}
@ -94,25 +98,22 @@ namespace NLGUI
// @internal
void CCssParser::parseRule(const std::string &selectorString, const std::string &styleString)
{
std::vector<std::string> selectors;
NLMISC::explode(selectorString, std::string(","), selectors);
TStyleVec props;
props = parseDecls(styleString);
// duplicate props to each selector in selector list,
// example 'div > p, h1' creates 'div>p' and 'h1'
for(uint i=0; i<selectors.size(); ++i)
for(std::string::size_type pos = 0; pos < selectorString.size(); pos++)
{
CCssStyle::SStyleRule rule;
while(pos < selectorString.size() && is_whitespace(selectorString[pos]))
pos++;
rule.Selector = parse_selector(trim(selectors[i]), rule.PseudoElement);
CCssStyle::SStyleRule rule;
rule.Selector = parse_selector(selectorString, rule.PseudoElement, pos);
rule.Properties = props;
if (!rule.Selector.empty())
{
_Rules.push_back(rule);
}
}
}
@ -341,7 +342,7 @@ namespace NLGUI
// ***************************************************************************
// parse selector list
// @internal
std::vector<CCssSelector> CCssParser::parse_selector(const std::string &sel, std::string &pseudoElement) const
std::vector<CCssSelector> CCssParser::parse_selector(const std::string &sel, std::string &pseudoElement, std::string::size_type &pos) const
{
std::vector<CCssSelector> result;
CCssSelector current;
@ -349,8 +350,8 @@ namespace NLGUI
pseudoElement.clear();
bool failed = false;
std::string::size_type start = 0, pos = 0;
while(pos < sel.size())
std::string::size_type start = pos;
while(pos < sel.size() && sel[pos] != ',')
{
std::string uc;
uc = sel[pos];
@ -366,6 +367,14 @@ namespace NLGUI
continue;
}
if (sel[pos] == '*' && current.empty())
{
pos++;
current.Element = "*";
start = pos;
continue;
}
if(sel[pos] == '#')
{
pos++;
@ -612,6 +621,7 @@ namespace NLGUI
}
else if (isSpace)
{
if (sel[pos] != ',' && sel[pos] != '\0')
current.Combinator = ' ';
}
else

@ -235,6 +235,11 @@ namespace NLGUI
// 1st child should be '1' and not '0'
if (!matchNth(elm.childIndex+1, a, b)) return false;
}
else if (startsWith(PseudoClass[i], "lang("))
{
std::string lang = PseudoClass[i].substr(5, PseudoClass[i].size() - 6);
if (lang.empty() || !matchLang(elm, lang)) return false;
}
else
{
return false;
@ -324,6 +329,29 @@ namespace NLGUI
}
}
bool CCssSelector::matchLang(const CHtmlElement &elm, const std::string &pseudo) const
{
// TODO: does not support comma separated, or escaped/quoted/wildcard tags
std::string lang = toLowerAscii(elm.getInheritedLanguage());
if (lang.empty() || pseudo.empty())
return false;
// lang = 'en', pseudo = 'en-US'
if (lang.size() < pseudo.size())
return false;
std::string selector = toLowerAscii(pseudo);
bool selectorHasRegion = selector.find("-") != std::string::npos;
bool langHasRegion = lang.find("-") != std::string::npos;
// both are 'en', or 'en-US' type
if (langHasRegion == selectorHasRegion)
return lang == selector;
// lang = 'en-US', selector = 'en'
return lang[selector.size()] == '-' && startsWith(lang, selector);
}
std::string CCssSelector::toString() const
{
std::string ret;

@ -386,27 +386,35 @@ namespace NLGUI
// - normalize values
void CCssStyle::normalize(const TStyle &styleRules, CStyleParams &style, const CStyleParams &current) const
{
std::set<std::string> seenProperties;
TStyle::const_iterator it;
for (it=styleRules.begin(); it != styleRules.end(); ++it)
{
std::string value = it->second;
// replace possible custom properties, ignore property if var() fails
if (!cssFuncVar(value, styleRules, seenProperties))
continue;
// update local copy of applied style
style.StyleRules[it->first] = it->second;
style.StyleRules[it->first] = value;
if (it->first == "color")
{
if (it->second == "inherit")
if (value == "inherit")
{
style.TextColor = current.TextColor;
}
else
{
scanHTMLColor(it->second.c_str(), style.TextColor);
scanHTMLColor(value.c_str(), style.TextColor);
}
}
else
if (it->first == "font")
{
if (it->second == "inherit")
if (value == "inherit")
{
style.FontSize = current.FontSize;
style.FontFamily = current.FontFamily;
@ -417,42 +425,42 @@ namespace NLGUI
else
if (it->first == "font-size")
{
if (it->second == "inherit")
if (value == "inherit")
{
style.FontSize = current.FontSize;
}
else if (it->second == "x-small")
else if (value == "x-small")
{
style.FontSize = 10; // 62.5%
}
else if (it->second == "small")
else if (value == "small")
{
style.FontSize = 13; // 80%;
}
else if (it->second == "medium")
else if (value == "medium")
{
style.FontSize = 16; // 100%;
}
else if (it->second == "large")
else if (value == "large")
{
style.FontSize = 18; // 112.5%
}
else if (it->second == "x-large")
else if (value == "x-large")
{
style.FontSize = 24; // 150%
}
else if (it->second == "xx-large")
else if (value == "xx-large")
{
style.FontSize = 32; // 200%;
}
else if (it->second == "smaller")
else if (value == "smaller")
{
if (style.FontSize < 5)
style.FontSize = 3;
else
style.FontSize -= 2;
}
else if (it->second == "larger")
else if (value == "larger")
{
style.FontSize += 2;
}
@ -460,7 +468,7 @@ namespace NLGUI
{
float tmpf;
std::string unit;
if (getCssLength(tmpf, unit, it->second.c_str()))
if (getCssLength(tmpf, unit, value.c_str()))
{
if (unit == "rem")
style.FontSize = Root.FontSize * tmpf;
@ -479,16 +487,16 @@ namespace NLGUI
if (it->first == "background-repeat")
{
// old ryzom specific value
if (it->second == "1")
if (value == "1")
style.StyleRules[it->first] = "repeat";
}
else
if (it->first == "display")
{
if (it->second == "inherit")
if (value == "inherit")
style.DisplayBlock = current.DisplayBlock;
else
style.DisplayBlock = (it->second == "block" || it->second == "table");
style.DisplayBlock = (value == "block" || value == "table");
}
}
}
@ -1668,5 +1676,181 @@ namespace NLGUI
}
}
// ***************************************************************************
static void skipString(const std::string &value, std::string::size_type &pos)
{
char quote = value[pos];
while(pos < value.size() && value[pos] != quote)
{
if (value[pos] == '\\')
pos++;
pos++;
}
}
static void skipBlock(const std::string &value, std::string::size_type &pos, bool isString)
{
char openChar = value[pos];
char closeChar = value[pos];
if (openChar == '(') closeChar = ')';
else if (openChar == '[') closeChar = ']';
else if (openChar == '{') closeChar = '}';
pos++;
while(pos < value.size())
{
char c = value[pos];
if (c == '\\')
pos++;
else if (!isString && (c == '(' || c == '[' || c == '{'))
skipBlock(value, pos, false);
else if (c == closeChar)
break;
else if (c == '"' || c == '\'')
{
if (isString)
break;
skipBlock(value, pos, true);
}
pos++;
}
}
static void skipWhitespace(const std::string &value, std::string::size_type &pos)
{
while(pos < value.size() && (value[pos] == ' ' || value[pos] == '\t' || value[pos] == '\r'))
pos++;
}
// ***************************************************************************
bool CCssStyle::cssFuncVar(std::string &func, const TStyle &styleRules, const std::set<std::string> &seenProperties) const
{
// TODO: fails if var() is inside string, ie '--text: ".. var(...) .."';
// start of 'var('
std::string::size_type pos = func.find("var(");
if (pos == std::string::npos)
return true;
// simple test to make sure 'var' is not substring
if (pos > 0 && (func[pos-1] != '_') && ((func[pos-1] >= 'a' && func[pos-1] <= 'z') || (func[pos-1] >= 'A' && func[pos-1] <='Z')))
return true;
// find closing ')'
std::string::size_type funcStart = pos;
std::string::size_type funcEnd = funcStart + 3;
skipBlock(func, funcEnd, false);
pos += 4;
// ',' separator
std::string::size_type sep = func.find_first_of(",)", pos);
if (sep > funcEnd)
{
// unlikely
sep = funcEnd;
}
else if (sep + 1 == funcEnd)
{
// no whitespace between ',' and ')', ie 'var(--name,)'
return false;
}
// extract name
std::string name = func.substr(funcStart + 4, sep - pos);
if (seenProperties.count(name) > 0)
return false;
std::string value;
// if name is not defined or resolves to 'initial', use fallback
bool found = lookupPropertyValue(name, value, styleRules);
if (found) {
// check if substituted value has 'var()'
std::set<std::string> newSeen = seenProperties;
newSeen.insert(name);
found = cssFuncVar(value, styleRules, newSeen);
if (value == "initial")
found = false;
}
// --name failed and we have fallback
if (!found && func[sep] == ',')
{
sep++;
skipWhitespace(func, sep);
value = func.substr(sep, funcEnd - sep);
if (value.empty())
{
found = true;
}
else
{
// check if substituted fallback has 'var()'
std::set<std::string> newSeen = seenProperties;
newSeen.insert(name);
found = cssFuncVar(value, styleRules, newSeen);
if (value == "initial")
found = false;
}
}
// invalidate property as both name and fallback failed
if (!found)
return false;
// everything before 'var(' and after ')'
std::string result;
if (funcStart > 0)
result = trim(func.substr(0, funcStart)) + " ";
result += trim(value);
if ((funcEnd+1) < func.size())
result += " " + trim(func.substr(funcEnd+1));
// check replaced string for var()
std::set<std::string> newSeen = seenProperties;
newSeen.insert(name);
bool success = cssFuncVar(result, styleRules, newSeen);
if (result == "initial")
success = false;
func = result;
return success;
}
// ***************************************************************************
bool CCssStyle::lookupPropertyValue(const std::string &name, std::string &value, const TStyle &styleRules) const
{
bool success = true;
TStyle::const_iterator it = styleRules.find(name);
if (it != styleRules.end())
value = it->second;
else if (Current.hasStyle(name))
value = Current.getStyle(name);
else
success = false;
if (success && value != "inherit")
return true;
std::vector<CStyleParams>::const_reverse_iterator rit = _StyleStack.rbegin();
for(; rit != _StyleStack.rend(); ++rit)
{
if (rit->hasStyle(name))
{
value = rit->getStyle(name);
if (value != "inherit")
{
return true;
}
}
}
return false;
}
} // namespace

@ -46,7 +46,7 @@ namespace NLGUI
static inline bool lt_text(const std::pair<int,std::string> &s1, const std::pair<int,std::string> &s2)
{
// return toLower(s1.second) < toLower(s2.second);
return -NLMISC::compareCaseInsensitive(s1.second, s2.second);
return NLMISC::compareCaseInsensitive(s1.second, s2.second) < 0;
}
std::string CDBGroupComboBox::measureMenu;

File diff suppressed because it is too large Load Diff

@ -65,6 +65,7 @@ namespace NLGUI
_Indent = 0;
_FirstViewIndentView = false;
_TextId = 0;
_TextAlign = AlignLeft;
}
// ----------------------------------------------------------------------------
@ -713,6 +714,10 @@ namespace NLGUI
CViewText *viewText = dynamic_cast<CViewText*>(_Elements[i].Element);
if (viewText)
{
// FIXME: this does not work with multiple view text on same line
if (_TextAlign == AlignCenter && elmCount == 1)
viewText->setTextMode(CViewText::Centered);
viewText->setFirstLineX(x + ((i==0)?_FirstViewIndentView:0));
viewText->setX(0);
viewText->updateTextContext();
@ -730,6 +735,12 @@ namespace NLGUI
// Does we balance the last line height ?
if (viewText)
{
if (_TextAlign == AlignCenter && elmCount == 1)
{
sint pad = width - viewText->getWReal();
viewText->setX(pad/2);
}
changeLine = viewText->getNumLine() > 1;
if (!viewText->getText().empty() && *(viewText->getText().rbegin()) == '\n')
{

@ -18,6 +18,7 @@
#include "stdpch.h"
#include "nel/gui/html_element.h"
#include "nel/gui/libwww.h"
using namespace std;
using namespace NLMISC;
@ -122,6 +123,118 @@ namespace NLGUI
}
}
// ***************************************************************************
std::string CHtmlElement::getInheritedLanguage() const
{
const CHtmlElement *node = this;
while(node)
{
if (node->hasAttribute("lang"))
return node->getAttribute("lang");
node = node->parent;
}
return "";
}
// ***************************************************************************
std::string CHtmlElement::htmlEscape(std::string val, bool isAttribute) const
{
static const std::vector<std::string> searchReplace = {
"&", "&amp;",
"<", "&lt;",
">", "&gt;",
"\xA0", "&nbsp;",
};
for(uint i = 0; i < searchReplace.size(); i+=2)
val = strFindReplaceAll(val, searchReplace[i], searchReplace[i+1]);
if (isAttribute)
{
static const std::string q = "\"";
static const std::string quot = "&quot;";
val = strFindReplaceAll(val, q, quot);
}
return val;
}
// ***************************************************************************
std::string CHtmlElement::serializeAttributes() const
{
std::string result;
for(std::map<std::string, std::string>::const_iterator it = Attributes.begin(); it != Attributes.end(); ++it)
{
if (it->first == "class")
{
result += " class=\"";
for(std::set<std::string>::const_iterator it2 = ClassNames.begin(); it2 != ClassNames.end(); ++it2)
{
if (it2 != ClassNames.begin())
{
result += " ";
}
result += htmlEscape(*it2, true);
}
result += "\"";
}
else
{
result += " " + it->first + "=\"" + htmlEscape(it->second, true) + "\"";
}
}
return result;
}
// ***************************************************************************
std::string CHtmlElement::serializeChilds() const
{
std::string result;
for(std::list<CHtmlElement>::const_iterator it = Children.begin(); it != Children.end(); ++it)
result += it->serialize();
return result;
}
// ***************************************************************************
std::string CHtmlElement::serialize() const
{
if (Type == TEXT_NODE)
{
if (parent && (parent->ID == HTML_SCRIPT || parent->ID == HTML_STYLE ||
parent->ID == HTML_IFRAME || parent->ID == HTML_NOEMBED ||
parent->ID == HTML_NOSCRIPT))
{
return Value;
} else {
return htmlEscape(Value);
}
}
std::string result = "<" + Value + serializeAttributes() + ">";
if (ID == HTML_AREA || ID == HTML_BASE || ID == HTML_BR ||
ID == HTML_COL || ID == HTML_EMBED || ID == HTML_HR ||
ID == HTML_IMG || ID == HTML_INPUT || ID == HTML_LINK ||
ID == HTML_META || ID == HTML_PARAM || ID == HTML_WBR)
{
return result;
}
// first linebreak that will be ignored on parse time
if (ID == HTML_PRE || ID == HTML_TEXTAREA)
result += "\n";
if (!Children.empty())
result += serializeChilds();
result += "</" + Value + ">";
return result;
}
// ***************************************************************************
std::string CHtmlElement::toString(bool tree, uint depth) const
{

@ -65,9 +65,17 @@ namespace NLGUI
while(node)
{
if (node->type == XML_TEXT_NODE)
{
// linebreak right after pre,textare open tag should be removed
if (parent.Children.empty() && (*node->content == '\n') && (parent.ID == HTML_PRE || parent.ID == HTML_TEXTAREA))
{
parent.Children.push_back(CHtmlElement(CHtmlElement::TEXT_NODE, (const char*)(node->content) + 1));
}
else
{
parent.Children.push_back(CHtmlElement(CHtmlElement::TEXT_NODE, (const char*)(node->content)));
}
}
else
if (node->type == XML_ELEMENT_NODE)
{
@ -174,6 +182,16 @@ namespace NLGUI
{
parseNode(node->children, elm, styles, links);
if (!elm.Children.empty() && elm.ID == HTML_PRE && elm.Children.back().Type == CHtmlElement::TEXT_NODE)
{
std::string::size_type size = elm.Children.back().Value.size();
// strip last '\n' from non-empty line
if (size > 1 && elm.Children.back().Value[size-1] == '\n')
{
elm.Children.back().Value = elm.Children.back().Value.substr(0, size - 1);
}
}
// must cleanup nested tags that libxml2 does not fix
// dt without end tag: <dl><dt><dt></dl>
// dd without end tag: <dl><dd><dd></dl>

@ -622,9 +622,7 @@ namespace NLGUI
return;
sint32 txw, txh;
SImage &rImage = *getSImage(nTxId);
txw = (sint32)((rImage.UVMax.U - rImage.UVMin.U)*rImage.GlobalTexturePtr->Width+0.5f);
txh = (sint32)((rImage.UVMax.V - rImage.UVMin.V)*rImage.GlobalTexturePtr->Height+0.5f);
getTextureSizeFromId(nTxId, txw, txh);
drawRotFlipBitmap (layerId, x, y, txw, txh, rot, flipv, nTxId, col);
}
@ -860,6 +858,14 @@ namespace NLGUI
CIFile ifTmp;
if (ifTmp.open(filename))
CBitmap::loadSize (ifTmp, gt.Width, gt.Height);
// extract textures scale from filename
// texture_interface_v3_2x.tga / texture_interface_v3_4x.tga
if (textureFileName.find("_2x.") != std::string::npos)
gt.Scale = 2.f;
else if (textureFileName.find("_4x.") != std::string::npos)
gt.Scale = 4.f;
gt.Texture = driver->createTextureFile (filename);
// Force to generate the texture now. This way we can extract the mouse bitmaps from it now without having to load it again.
// Its why we don't release it at the end, because it is likely to be uploaded soon)
@ -934,6 +940,10 @@ namespace NLGUI
CBitmap curs;
curs.resize(x1 - x0, y1 - y0);
curs.blit(*texDatas, x0, y0, (x1 - x0), (y1 - y0), 0, 0);
// TODO: scaled cursors not supported
if (gt.Scale > 1.f) {
curs.resample((sint)(curs.getWidth() / gt.Scale), (sint)(curs.getHeight() / gt.Scale));
}
driver->addCursor(image.Name, curs);
}
}
@ -1359,8 +1369,8 @@ namespace NLGUI
else
{
SImage &rImage = *getSImage(id);
width = (sint32)((rImage.UVMax.U - rImage.UVMin.U)*rImage.GlobalTexturePtr->Width+0.5f);
height = (sint32)((rImage.UVMax.V - rImage.UVMin.V)*rImage.GlobalTexturePtr->Height+0.5f);
width = (sint32)(((rImage.UVMax.U - rImage.UVMin.U)*rImage.GlobalTexturePtr->Width / rImage.GlobalTexturePtr->Scale)+0.5f);
height = (sint32)(((rImage.UVMax.V - rImage.UVMin.V)*rImage.GlobalTexturePtr->Height / rImage.GlobalTexturePtr->Scale)+0.5f);
}
}
/*
@ -1375,9 +1385,11 @@ namespace NLGUI
SImage &rImage = *getSImage(id);
SGlobalTexture &rGT = *rImage.GlobalTexturePtr;
// get (possibly) scaled width/height
sint32 width, height;
width = (sint32)((rImage.UVMax.U - rImage.UVMin.U)*rGT.Width+0.5f);
height = (sint32)((rImage.UVMax.V - rImage.UVMin.V)*rGT.Height+0.5f);
getTextureSizeFromId(id, width, height);
if (width == 0 || height == 0)
return CRGBA(255,255,255);
float xRatio = ((float)x) / ((float)(width));
float yRatio = ((float)y) / ((float)(height));
UTexture *pTF = rGT.Texture;

@ -3568,7 +3568,7 @@ void CBitmap::loadSize(NLMISC::IStream &f, uint32 &retWidth, uint32 &retHeight)
}
while(!eof);
}
else if(fileType == JPG_HEADER)
else if(memcmp(&fileType, &JPG_HEADER, 2) == 0)
{
uint8 blockMarker1 = 0;
uint8 blockMarker2 = 0;

@ -32,7 +32,7 @@ CStreamedPackage::~CStreamedPackage()
// release
}
void CStreamedPackage::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
void CStreamedPackage::serial(NLMISC::IStream &f)
{
f.serialCheck(NELID("SNPK"));
@ -42,7 +42,7 @@ void CStreamedPackage::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
f.serialCont(Entries);
}
void CStreamedPackage::CEntry::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
void CStreamedPackage::CEntry::serial(NLMISC::IStream &f)
{
uint version = 1;
f.serialVersion(version);

@ -37,3 +37,8 @@ ENDIF()
IF(WITH_NEL_TESTS)
ADD_SUBDIRECTORY(nel_unit_test)
ENDIF()
IF(WITH_HTMLCSS_TEST)
ADD_SUBDIRECTORY(htmlcss_test)
ENDIF()

@ -0,0 +1,15 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.1)
CMAKE_POLICY(SET CMP0015 NEW)
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${CMAKE_LIBRARY_DIR})
ADD_DEFINITIONS(${LIBXML2_DEFINITIONS})
FILE(GLOB SRC htmlcss_test.cpp)
ADD_EXECUTABLE(htmlcss_test ${SRC})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${LUA_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR} )
TARGET_LINK_LIBRARIES(htmlcss_test nelmisc nelgui ${LUA_LIBRARIES} ${LIBXML2_LIBRARIES})
NL_DEFAULT_PROPS(htmlcss_test "Ryzom, Tests: html/css parser tests")
NL_ADD_RUNTIME_FLAGS(htmlcss_test)
INSTALL(TARGETS htmlcss_test RUNTIME DESTINATION bin COMPONENT tools)
# TODO: test fixtures

@ -0,0 +1,183 @@
/*
* File: main.cpp
* Author: Karu <nimetu@gmail.com>
*
* Created on 2015-04-11
*/
typedef struct _xmlNode xmlNode;
#include <string>
#include <fstream>
#include "nel/misc/types_nl.h"
#include "nel/misc/file.h"
#include "nel/misc/path.h"
#include "nel/gui/html_parser.h"
#include "nel/gui/css_parser.h"
#include "nel/gui/html_element.h"
#include "nel/gui/css_style.h"
#include "nel/gui/libwww.h"
using namespace std;
using namespace NLMISC;
using namespace NLGUI;
sint indent { 0 };
// ***************************************************************************
void checkRuleset(CHtmlElement &elm, CCssStyle &style, TStyleVec testset, bool exists)
{
bool verbose = false;
std::string existsMessage = exists ? "exist" : "unset";
for (auto it : testset)
{
bool failed = (exists != style.hasStyle(it.first));
if (failed)
{
bool failed2 = true;
if (it.first == "font-size")
{
printf("[%s]: font-size: %d; expected '%s'\n", existsMessage.c_str(), style.Current.FontSize, it.second.c_str());
printf(" (%s)\n", elm.toString().c_str());
failed2 = false;
}
else if (it.first == "background-color")
{
printf("[%s]: background-color: '%s'; expected '%s'\n", existsMessage.c_str(), style.Current.BackgroundColor.toString().c_str(), it.second.c_str());
printf(" (%s)\n", elm.toString().c_str());
failed2 = false;
}
if (failed2)
{
printf("[%s] FAIL: '%s': '%s'\n", existsMessage.c_str(), it.first.c_str(), it.second.c_str());
printf(" (%s)\n", elm.toString().c_str());
for (auto it2 : style.Current.StyleRules)
printf("'%s': '%s'\n", it2.first.c_str(), it2.second.c_str());
}
}
else if (exists && !style.checkStyle(it.first, it.second))
{
printf("[%s] FAIL: expecting '%s': '%s', got '%s'\n", existsMessage.c_str(), it.first.c_str(), it.second.c_str(), style.getStyle(it.first).c_str());
printf(" (%s)\n", elm.toString().c_str());
}
else if (!failed)
{
if (verbose)
printf("[%s] PASS: '%s': '%s'\n", existsMessage.c_str(), it.first.c_str(), it.second.c_str());
}
}
}
// ***************************************************************************
void recursiveHtmlRender(CHtmlElement &elm, CCssStyle &style)
{
bool verbose = false;
if (elm.Type == CHtmlElement::TEXT_NODE)
{
std::string val = trim(elm.Value);
if (verbose)
if (!val.empty())
printf("[%d] '%s'\n", indent, val.c_str());
}
else if (elm.Type == CHtmlElement::ELEMENT_NODE)
{
style.pushStyle();
if (verbose)
printf("========= '%s'\n", elm.toString().c_str());
style.getStyleFor(elm);
style.applyStyle(elm.Style);
if (elm.hasAttribute("data-ruleset"))
{
TStyleVec testset = CCssParser::parseDecls(elm.getAttribute("data-ruleset"));
checkRuleset(elm, style, testset, true);
}
if (elm.hasAttribute("data-ruleunset"))
{
TStyleVec testset = CCssParser::parseDecls(elm.getAttribute("data-ruleunset"));
checkRuleset(elm, style, testset, false);
}
if (elm.hasAttribute("data-ruleset-before"))
{
TStyleVec testset = CCssParser::parseDecls(elm.getAttribute("data-ruleset-before"));
}
for (auto it = elm.Children.begin(); it != elm.Children.end(); ++it)
{
recursiveHtmlRender(*it, style);
}
style.popStyle();
}
}
// ***************************************************************************
void runTestOnFile(const std::string &filename)
{
CHtmlElement dom;
CHtmlParser htmlParser;
std::vector<CHtmlParser::StyleLink> links;
std::vector<std::string> styles;
//, elm, styles, links
ifstream f(filename);
if (!f.is_open())
{
printf("!! failed to open file '%s'\n", filename.c_str());
return;
}
printf(": %s\n", filename.c_str());
std::string htmlString;
std::string line;
while (getline(f, line))
htmlString += line;
htmlParser.getDOM(htmlString, dom, styles, links);
CCssStyle style;
for (std::string s : styles)
{
if (!s.empty())
style.parseStylesheet(s);
}
for (auto it = dom.Children.begin(); it != dom.Children.end(); ++it)
recursiveHtmlRender(*it, style);
}
// ***************************************************************************
int main(int argc, const char *argv[])
{
CApplicationContext *appContext = new CApplicationContext;
// htmlcss_test file.html
if (argc == 2)
{
runTestOnFile(argv[1]);
}
else
{
std::vector<std::string> result;
CPath::getPathContent("tests/", true /*recursive*/, false /*wantDir*/, true /*wantFile*/, result, NULL /*callback*/, true /*showEverything*/);
printf(":: got %ld files\n", result.size());
for (const auto &fname : result)
{
if (endsWith(fname, ".html") && fname != "tests/XX-template.html")
runTestOnFile(fname);
}
}
printf(">>> all done\n");
return EXIT_SUCCESS;
}

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<body>
<style>
:lang(en) { --text: '(en)'; }
:lang(de-DE) { --text: '(de-DE)'; }
a { test: " (" var(--lang) ")"}
div {
/* '--a' and '--b' are both 'initial' */
--should-not-exist: var(--a, var(--b, ( "p() " ) ), { "b" [ "r" ] });
/* 'before -var- after' */
--concate-test: 'before' var(--exists) 'after';
--exists: '-var-';
/* fallback should be at least one char */
--invalid-fallback: var(--exists,);
/* using fallback */
--fallback: var(--a, 'ok');
}
</style>
<div data-ruleset="--concate-test: 'before' '-var-' 'after'; --exists: '-var-'; --fallback: 'ok';"
data-ruleunset="--should-not-exists: 1; --invalid-fallback: 1;" />
<a lang="en" data-ruleset="--text: '(en)';">link</a>
<a lang="de" data-ruleunset="--text: 1;">link</a>
</body>
</html>

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<body>
<style>
p {
--mq-sm: initial;
}
.small {
--mq-sm: ;
}
p {
--padding-when-small: var(--mq-sm) 2rem;
--padding-when-large: 4rem;
padding: var(--padding-when-small, var(--padding-when-large));
}
</style>
<p data-ruleset="padding-left: 4rem;" comment="--mq-sm==initial, should use fallback value" />
<div>
<p class="small" data-ruleset="padding-left: 2rem;" comment="--mq-sm==;, should use defined value"/>
</div>
</body>
</html>

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<body>
<style>
:root {
--main-color: #06c;
--accent-color: #006;
}
/* The rest of the CSS file */
#foo h1 {
color: var(--main-color);
}
</style>
<div id="foo">
<h1 data-ruleset="color: #06c;">Header</h1>
</div>
</body>
</html>

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<body>
<style>
:root {
--main-color: #06c;
--accent-color: #006;
--MAIN-COLOR: #f00;
}
/* The rest of the CSS file */
#foo h1 {
color: var(--main-color);
}
h2 {
color: var(--MAIN-COLOR);
}
</style>
<div id="foo">
<h1 data-ruleset="color: #06c;">Header1</h1>
<h2 data-ruleset="color: #f00;">Header2</h1>
</div>
</body>
</html>

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<body>
<style>
:root {
--foo: if(x > 5) this.width = 10;
}
/* The rest of the CSS file */
#foo h1 {
test: var(--foo)
}
</style>
<div id="foo">
<h1 data-ruleset="test: if(x > 5) this.width = 10;">Header</h1>
</div>
</body>
</html>

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<body>
<style>
:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
</style>
<p data-ruleset="color: blue;">I inherited blue from the root element!</p>
<div data-ruleset="color: green;">I got green set directly on me!</div>
<div id='alert' data-ruleset="color: red;">
While I got red set directly on me!
<p data-ruleset="color: red;">Im red too, because of inheritance!</p>
</div>
</body>
</html>

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<body>
<style>
a:lang(en) {--lang: 'en';}
a:lang(de) {--lang: 'de';}
a { test: var(--lang); }
</style>
<a lang="en" data-ruleset="test: 'en';">link</a>
<a lang="de" data-ruleset="test: 'de';">link</a>
</body>
</html>

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<body>
<style>
:root {
--main-color: #c06;
--accent-background: var(--main-color);
}
div {
test: var(--accent-background);
}
</style>
<div data-ruleset="test: #c06;"/>
</body>
</html>

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<body>
<style>
div {
--one: calc(var(--two) + 20px);
--two: calc(var(--one) - 20px);
--ok: 'ok';
}
</style>
<div data-ruleset="--ok: 'ok';"
data-ruleunset="--one: 1; --two: 1;" />
</body>
</html>

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<body>
<style>
one { --foo: 10px; }
two { --bar: calc(var(--foo) + 10px); }
three { --foo: calc(var(--bar) + 10px); }
</style>
<one data-ruleset="--foo: 10px;">
<two data-ruleset="--bar: calc( 10px + 10px);">
<three data-ruleset="--foo: calc( calc( 10px + 10px) + 10px);"/>
</two>
</one>
</body>
</html>

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<body>
<style>
/* In the components style: */
.component .header {
color: var(--header-color, blue);
}
.component .text {
color: var(--text-color, black);
}
/* In the larger applications style: */
.component {
--text-color: #080;
/* header-color isnt set, and so remains blue, the fallback value */
}
</style>
<div class="component">
<h1 class="header" data-ruleset="color: blue;">header</h1>
<p class="text" data-ruleset="color: #080;">text</p>
</div>
</body>
</html>

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<body>
<style>
div {
--side: margin-top;
var(--side): 20px;
}
</style>
<div data-ruleset="--side: margin-top;" data-ruleunset="var(--side): 1;" />
</body>
</html>

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<body>
<style>
div {
--gap: 20;
margin-top: var(--gap)px;
}
</style>
<!-- should have whitespace, ie '20 px' -->
<div data-ruleset="margin-top: 20 px;" />
</body>
</html>

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<body>
<style>
:root { --not-a-color: 20px; }
p { background-color: red; }
p { background-color: var(--not-a-color); }
</style>
<!-- this should have 'red' because var() has invalid value for color -->
<!-- TODO: not really supported by NEL currently -->
<div data-ruleset="background-color: red;" />
</body>
</html>

@ -274,7 +274,6 @@ void CItemSheet::build(const NLGEORGES::UFormElm &item)
string IconText;
if(!item.getValueByName (IconText, "3d.text overlay"))
debug("key '3d.text overlay' not found.");
IconText = toLowerAscii(IconText);
IdIconText = ClientSheetsStrings.add(IconText);
// See if this item can be hiden when equipped

@ -131,7 +131,6 @@ void COutpostBuildingSheet::build(const NLGEORGES::UFormElm &root)
string IconText;
if(!root.getValueByName (IconText, "text overlay"))
debug("key 'text overlay' not found.");
IconText = toLowerAscii(IconText);
IdIconText = ClientSheetsStrings.add(IconText);
}

@ -56,6 +56,7 @@
#include "../r2/editor.h"
#include "nel/gui/lua_manager.h"
#include "nel/misc/xml_macros.h"
extern CSheetManager SheetMngr;
@ -565,6 +566,15 @@ CCtrlDraggable(param)
_RegenText = NULL;
_RegenTextValue = 0;
_RegenTextEnabled = true;
_RegenTextShadow = true;
_RegenTextOutline = false;
_RegenTextFctLua = false;
_RegenTextY = 2;
_RegenTextFontSize = 8;
_RegenTextColor = NLMISC::CRGBA::White;
_RegenTextShadowColor = NLMISC::CRGBA::Black;
_RegenTextOutlineColor = NLMISC::CRGBA::Black;
}
// ----------------------------------------------------------------------------
@ -677,6 +687,17 @@ bool CDBCtrlSheet::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup)
prop = (char*) xmlGetProp( cur, (xmlChar*)"focus_buff_icon" );
if (prop) _FocusBuffIcon = string((const char *)prop);
XML_READ_BOOL(cur, "regen_text", _RegenTextEnabled, true);
XML_READ_BOOL(cur, "regen_text_shadow", _RegenTextShadow, true);
XML_READ_BOOL(cur, "regen_text_outline", _RegenTextOutline, false);
XML_READ_SINT(cur, "regen_text_y", _RegenTextY, 2);
XML_READ_UINT(cur, "regen_text_fontsize", _RegenTextFontSize, 8);
XML_READ_COLOR(cur, "regen_text_color", _RegenTextColor, NLMISC::CRGBA::White);
XML_READ_COLOR(cur, "regen_text_shadow_color", _RegenTextShadowColor, NLMISC::CRGBA::Black);
XML_READ_COLOR(cur, "regen_text_outline_color", _RegenTextOutlineColor, NLMISC::CRGBA::Black);
XML_READ_STRING(cur, "regen_text_fct", _RegenTextFct, "");
_RegenTextFctLua = startsWith(_RegenTextFct, "lua:");
updateActualType();
// Init size for Type
initSheetSize();
@ -2108,35 +2129,8 @@ void CDBCtrlSheet::draw()
rVR.drawQuad(_RenderLayer + 1, regenTris[tri], backTex, CRGBA::White, false);
}
if (!_RegenText) {
_RegenText = new CViewText(CViewBase::TCtorParam());
_RegenText->setId(getId() + ":regen");
_RegenText->setParent(_Parent);
_RegenText->setOverflowText(std::string());
_RegenText->setModulateGlobalColor(false);
_RegenText->setMultiLine(false);
_RegenText->setTextMode(CViewText::ClipWord);
_RegenText->setFontSizing("0", "0");
// TODO: font size / color hardcoded.
_RegenText->setFontSize(8);
_RegenText->setColor(CRGBA::White);
_RegenText->setShadow(true);
_RegenText->setActive(true);
_RegenText->updateTextContext();
}
// TODO: ticks in second hardcoded
uint32 nextValue = _RegenTickRange.EndTick > LastGameCycle ? (_RegenTickRange.EndTick - LastGameCycle) / 10 : 0;
if (_RegenTextValue != nextValue)
{
_RegenTextValue = nextValue;
_RegenText->setText(toString("%d", _RegenTextValue));
_RegenText->updateTextContext();
}
_RegenText->setXReal(_XReal+1);
_RegenText->setYReal(_YReal+2);
_RegenText->setRenderLayer(_RenderLayer+2);
_RegenText->draw();
if (_RegenTextEnabled)
drawRegenText();
}
}
@ -2166,6 +2160,118 @@ void CDBCtrlSheet::draw()
}
}
// ----------------------------------------------------------------------------
void CDBCtrlSheet::drawRegenText()
{
if (!_RegenText) {
_RegenText = new CViewText(CViewBase::TCtorParam());
_RegenText->setId(getId() + ":regen");
_RegenText->setParent(_Parent);
_RegenText->setOverflowText(std::string());
_RegenText->setModulateGlobalColor(false);
_RegenText->setMultiLine(true);
_RegenText->setTextMode(CViewText::ClipWord);
_RegenText->setFontSize(_RegenTextFontSize);
_RegenText->setColor(_RegenTextColor);
// do not set shadow if outline is set to avoid clearing it on draw (would call invalidate)
_RegenText->setShadow(_RegenTextShadow && !_RegenTextOutline);
_RegenText->setShadowOutline(false);
_RegenText->setShadowColor(_RegenTextShadowColor);
_RegenText->setActive(true);
_RegenText->updateTextContext();
}
// TODO: 10 hardcoded (ticks in second)
sint32 nextValue;
if (_RegenTickRange.EndTick > LastGameCycle)
nextValue = (_RegenTickRange.EndTick - LastGameCycle) / 10;
else if (_RegenTextFctLua)
nextValue = ((sint64)_RegenTickRange.EndTick - (sint64)LastGameCycle) / 10;
else
nextValue = 0;
if (_RegenTextValue != nextValue)
{
_RegenTextValue = nextValue;
if (_RegenTextFct.empty())
{
// format as "10m", "9'59", "59"
if (_RegenTextValue > 600)
{
_RegenText->setText(toString("%dm", _RegenTextValue / 60));
}
else if (_RegenTextValue > 0)
{
if (_RegenTextValue < 60)
_RegenText->setText(toString("%d", _RegenTextValue));
else
_RegenText->setText(toString("%d'%02d", _RegenTextValue / 60, _RegenTextValue % 60));
}
else
{
_RegenText->setText("");
}
}
else
{
std::string fct;
if (_RegenTextFctLua)
{
CCDBNodeBranch *root = getRootBranch();
if (root)
fct = toString("%s(%d, '%s')", _RegenTextFct.c_str(), _RegenTextValue, root->getFullName().c_str());
else
fct = toString("%s(%d, nil)", _RegenTextFct.c_str(), _RegenTextValue);
}
else
{
fct = toString("%s(%d)", _RegenTextFct.c_str(), _RegenTextValue);
}
// if using color tags in format, then RegenText color should be set to CRGBA::White
// as tag color is modulated with main color
std::string result;
if (CInterfaceExpr::evalAsString(fct, result))
_RegenText->setTextFormatTaged(result);
}
_RegenText->updateTextContext();
// todo: posref
// note: if x,y is moved outside icon area it might get cliped and not be visible (wreal/hreal == 0)
_RegenText->setX(_WReal / 2 -_RegenText->getMaxUsedW() / 2);
// move RegenTextY=0 to baseline
_RegenText->setY(_RegenTextY - _RegenText->getFontLegHeight());
}
_RegenText->setXReal(_XReal + _RegenText->getX());
_RegenText->setYReal(_YReal + _RegenText->getY());
_RegenText->setRenderLayer(_RenderLayer+2);
// TODO: create shader for this
if (_RegenTextOutline)
{
// player.xml t_bonus_text template way of drawing
sint x = _RegenText->getXReal();
sint y = _RegenText->getYReal();
_RegenText->setColor(_RegenTextShadowColor);
_RegenText->setXReal(x-1); _RegenText->setYReal(y+0); _RegenText->draw();
_RegenText->setXReal(x+1); _RegenText->setYReal(y+0); _RegenText->draw();
_RegenText->setXReal(x+0); _RegenText->setYReal(y-1); _RegenText->draw();
_RegenText->setXReal(x+0); _RegenText->setYReal(y+1); _RegenText->draw();
_RegenText->setColor(_RegenTextColor);
_RegenText->setXReal(x); _RegenText->setYReal(y);
_RegenText->draw();
_RegenText->draw();
}
else
{
_RegenText->draw();
_RegenText->draw();
}
}
// ----------------------------------------------------------------------------
void CDBCtrlSheet::drawRotatedQuad(CViewRenderer &vr, float angle, float scale, uint renderLayer, uint32 texId, sint32 texWidth, sint32 texHeight)
@ -4760,6 +4866,12 @@ std::string CDBCtrlSheet::getContextHelpWindowName() const
return CCtrlBase::getContextHelpWindowName();
}
// ***************************************************************************
void CDBCtrlSheet::setRegenTextFct(const std::string &s)
{
_RegenTextFct = s;
_RegenTextFctLua = startsWith(s, "lua:");
}
// ***************************************************************************
void CDBCtrlSheet::setRegenTickRange(const CTickRange &tickRange)

@ -602,6 +602,25 @@ public:
void setRegenTickRange(const CTickRange &tickRange);
const CTickRange &getRegenTickRange() const { return _RegenTickRange; }
// Default regen text is displayed on bottom of icon.
void setRegenText(bool b) { _RegenTextEnabled = b; }
// Allow to override default formatter.
// First parameter will be replaced with current timer value (always >= 0)
// If its a lua function, then parameters are
// 1: current timer value; can be negative
// 2: DB path for ctrl root (ie UI:VARIABLES:BONUSES:0), or nil
//
// ie: "secondsToTimeStringShort" -> CInterfaceExpr::evalAsString("secondsToTimeStringShort(123)", ret)
// ie: "lua:secondsToTimeStringShort" -> CInterfaceExpr::evalAsString("lua:secondsToTimeStringShort(123, 'UI:VARIABLES:BONUSES:0')", ret)
void setRegenTextFct(const std::string &s);
void setRegenTextY(sint32 y) { _RegenTextY = y; }
void setRegenTextShadow(bool b) { _RegenTextShadow = b; }
void setRegenTextShadowColor(NLMISC::CRGBA c) { _RegenTextShadowColor = c; }
void setRegenTextOutline(bool b) { _RegenTextOutline = b; }
void setRegenTextOutlineColor(NLMISC::CRGBA c) { _RegenTextOutlineColor = c; }
void setRegenTextFontSize(uint32 s) { _RegenTextFontSize = s; }
void setRegenTextColor(NLMISC::CRGBA c) { _RegenTextColor = c; }
// start notify anim (at the end of regen usually)
void startNotifyAnim();
@ -738,7 +757,19 @@ protected:
CTickRange _RegenTickRange;
NLGUI::CViewText *_RegenText;
uint32 _RegenTextValue;
sint32 _RegenTextValue;
//
std::string _RegenTextFct;
bool _RegenTextFctLua;
bool _RegenTextEnabled;
bool _RegenTextShadow;
bool _RegenTextOutline;
sint32 _RegenTextY;
uint32 _RegenTextFontSize;
NLMISC::CRGBA _RegenTextShadowColor;
NLMISC::CRGBA _RegenTextOutlineColor;
NLMISC::CRGBA _RegenTextColor;
/// D'n'd
sint32 _DragX, _DragY;
@ -852,6 +883,9 @@ private:
// gelper to draw the notify animation
void drawRotatedQuad(CViewRenderer &vr, float angle, float scale, uint renderLayer, uint32 textureId, sint32 texWidth, sint32 texHeight);
// create and draw regen text over icon
void drawRegenText();
};
/** User type (used with expression system of the interface, see interface_expr.h, that contains a pointer to a CDBCtrlSheet

@ -23,7 +23,7 @@
#include "stdpch.h"
#include "dbgroup_list_sheet_bonus_malus.h"
#include "interface_manager.h"
#include "nel/misc/xml_macros.h"
using namespace std;
using namespace NLMISC;
@ -35,87 +35,106 @@ NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupListSheetBonusMalus, std::string, "lis
// ***************************************************************************
CDBGroupListSheetBonusMalus::CDBGroupListSheetBonusMalus(const TCtorParam &param)
: CDBGroupListSheet(param)
: CDBGroupListSheet(param),
_RegenTextEnabled(true),
_RegenTextY(-14), _RegenTextFontSize(8),
_RegenTextColor(NLMISC::CRGBA::White),
_RegenTextDisabledColor(NLMISC::CRGBA(127,127,127))
{
_TextId= -1;
// want leave space between controls in the list
// Yoyo: I think it's better like this, + this is important for space consideration and because of XPCat/PVPOutpost
//_ListLeaveSpace= false;
}
// ***************************************************************************
bool CDBGroupListSheetBonusMalus::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup)
CDBGroupListSheetBonusMalus::CSheetChildTimer::CSheetChildTimer()
: TimerDB(NULL), DisabledDB(NULL), TimerCache(0),
_RegenTextColor(NLMISC::CRGBA::White),
_RegenTextDisabledColor(NLMISC::CRGBA(127,127,127))
{
CInterfaceManager *pIM= CInterfaceManager::getInstance();
}
if(!CDBGroupListSheet::parse(cur, parentGroup))
return false;
// ***************************************************************************
void CDBGroupListSheetBonusMalus::CSheetChildTimer::init(CDBGroupListSheet *pFather, uint index)
{
// init my parent
CSheetChild::init(pFather, index);
// read the texture
CXMLAutoPtr prop;
prop = (char*) xmlGetProp( cur, (xmlChar*)"disable_texture" );
if (prop)
CCDBNodeBranch *root = Ctrl->getRootBranch();
if (root)
{
CInterfaceManager *pIM = CInterfaceManager::getInstance();
CViewRenderer &rVR = *CViewRenderer::getInstance();
_TextId= rVR.getTextureIdFromName ((const char *)prop);
TimerDB = dynamic_cast<CCDBNodeLeaf *>(root->getNode(ICDBNode::CTextId("DISABLED_TIME"), false));
DisabledDB = dynamic_cast<CCDBNodeLeaf *>(root->getNode(ICDBNode::CTextId("DISABLED"), false));
}
// get the Node leaves to be tested each frame
uint i= 0;
for(;;)
{
string db= toString("%s:%d:" DISABLE_LEAF, _DbBranchName.c_str(), i);
CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(db, false);
if(!node)
if (Ctrl)
{
break;
}
else
CDBGroupListSheetBonusMalus *owner = dynamic_cast<CDBGroupListSheetBonusMalus *>(pFather);
if (owner)
{
_DisableStates.push_back(node);
i++;
}
_RegenTextColor = owner->_RegenTextColor;
_RegenTextDisabledColor = owner->_RegenTextDisabledColor;
Ctrl->setRegenText(owner->_RegenTextEnabled);
Ctrl->setRegenTextY(owner->_RegenTextY);
Ctrl->setRegenTextColor(owner->_RegenTextColor);
Ctrl->setRegenTextFontSize(owner->_RegenTextFontSize);
if (!owner->_RegenTextFct.empty())
Ctrl->setRegenTextFct(owner->_RegenTextFct);
}
return true;
Ctrl->setRegenTextOutline(true);
}
}
// ***************************************************************************
void CDBGroupListSheetBonusMalus::draw ()
void CDBGroupListSheetBonusMalus::CSheetChildTimer::update(CDBGroupListSheet * /* pFather */)
{
CDBGroupListSheet::draw();
// CInterfaceManager *pIM= CInterfaceManager::getInstance();
// CViewRenderer &rVR= *CViewRenderer::getInstance();
if(!TimerDB)
return;
// sint32 drl= getRenderLayer()+1;
// May draw disable bitmaps on the ctrl sheets if disabled.
uint numCtrls= (uint)min(_SheetChildren.size(), _DisableStates.size());
for(uint i=0;i<numCtrls;i++)
NLMISC::TGameCycle tick = TimerDB->getValue32();
if (TimerCache != tick)
{
CDBCtrlSheet *ctrl= _SheetChildren[i]->Ctrl;
// if the ctrl is displayed, and if the state is disabled
if(ctrl->getActive())
TimerCache = TimerDB->getValue32();
Ctrl->setRegenTickRange(CTickRange(LastGameCycle, TimerCache));
if (DisabledDB)
{
if(_DisableStates[i]->getValue32()!=0)
if (DisabledDB->getValue32() == 0)
{
ctrl->setGrayed(true);
/*
// YOYO: for now, don't display the gray bitmap. cross not cool.
CRGBA crossColor= ctrl->getSheetColor();
crossColor.A>>= 2;
// Draw the disable bitmap on this control. +1 for the slot (ugly)
rVR.drawRotFlipBitmap(drl, ctrl->getXReal()+1, ctrl->getYReal()+1,
CCtrlSheetInfo::BrickSheetWidth, CCtrlSheetInfo::BrickSheetHeight, 0, 0, _TextId, crossColor);
*/
// active timer
Ctrl->setGrayed(false);
Ctrl->setRegenTextColor(_RegenTextColor);
}
else
{
// skill disabled timer
Ctrl->setGrayed(true);
Ctrl->setRegenTextColor(_RegenTextDisabledColor);
}
}
else
ctrl->setGrayed(false);
{
Ctrl->setGrayed(true);
}
}
}
// ***************************************************************************
bool CDBGroupListSheetBonusMalus::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup)
{
CInterfaceManager *pIM= CInterfaceManager::getInstance();
if(!CDBGroupListSheet::parse(cur, parentGroup))
return false;
CXMLAutoPtr prop;
XML_READ_BOOL(cur, "regen_text", _RegenTextEnabled, true);
XML_READ_SINT(cur, "regen_text_y", _RegenTextY, -14);
XML_READ_UINT(cur, "regen_text_fontsize", _RegenTextFontSize, 8);
XML_READ_COLOR(cur, "regen_text_color", _RegenTextColor, NLMISC::CRGBA::White);
XML_READ_COLOR(cur, "regen_text_disabled_color", _RegenTextDisabledColor, NLMISC::CRGBA(127, 127, 127));
XML_READ_STRING(cur, "regen_text_fct", _RegenTextFct, "");
return true;
}

@ -25,7 +25,6 @@
#include "nel/misc/types_nl.h"
#include "dbgroup_list_sheet.h"
// ***************************************************************************
/**
* Special list_sheet that display some disalbe bitmap if needed according to DB
@ -40,14 +39,34 @@ public:
/// Constructor
CDBGroupListSheetBonusMalus(const TCtorParam &param);
virtual bool parse (xmlNodePtr cur, CInterfaceGroup *parentGroup);
// A child node
struct CSheetChildTimer : public CDBGroupListSheet::CSheetChild
{
CSheetChildTimer();
virtual void init(CDBGroupListSheet *pFather, uint index) NL_OVERRIDE;
virtual void update(CDBGroupListSheet *pFather) NL_OVERRIDE;
NLMISC::CCDBNodeLeaf *TimerDB;
NLMISC::CCDBNodeLeaf *DisabledDB;
uint TimerCache;
NLMISC::CRGBA _RegenTextColor;
NLMISC::CRGBA _RegenTextDisabledColor;
};
virtual bool parse(xmlNodePtr cur, CInterfaceGroup *parentGroup) NL_OVERRIDE;
virtual void draw ();
virtual CSheetChild *createSheetChild() NL_OVERRIDE { return new CSheetChildTimer; }
private:
sint32 _TextId;
friend CSheetChildTimer;
std::vector<NLMISC::CCDBNodeLeaf*> _DisableStates;
bool _RegenTextEnabled;
std::string _RegenTextFct;
sint32 _RegenTextY;
uint32 _RegenTextFontSize;
NLMISC::CRGBA _RegenTextColor;
NLMISC::CRGBA _RegenTextDisabledColor;
};

@ -168,8 +168,8 @@ void CGroupQuickHelp::setGroupTextSize (CInterfaceGroup *group, bool selected)
{
bool globalColor = selected ? TextColorGlobalColor : _NonSelectedGlobalColor;
bool linkGlobalColor = selected ? LinkColorGlobalColor : _NonSelectedGlobalColor;
uint fontSize = selected ? TextFontSize : _NonSelectedSize;
NLMISC::CRGBA color = selected ? TextColor : _NonSelectedColor;
uint fontSize = selected ? _BrowserStyle.Current.FontSize : _NonSelectedSize;
NLMISC::CRGBA color = selected ? _BrowserStyle.Current.TextColor : _NonSelectedColor;
NLMISC::CRGBA linkColor = selected ? LinkColor : _NonSelectedLinkColor;
// Look for text in this group

@ -195,7 +195,7 @@ bool CPeopleList::sortExByContactId(const CPeople& a, const CPeople& b)
//==================================================================
bool CPeopleList::sortExByName(const CPeople& a, const CPeople& b)
{
return -NLMISC::compareCaseInsensitive(a.getName(), b.getName()); // FIXME: Locale-dependent sort
return NLMISC::compareCaseInsensitive(a.getName(), b.getName()) < 0; // FIXME: Locale-dependent sort
}
//==================================================================
@ -204,7 +204,7 @@ bool CPeopleList::sortExByOnline(const CPeople& a, const CPeople& b)
// We want order: online/alpha, offworld/alpha, offline/alpha
if (a.Online == b.Online)
{
return -NLMISC::compareCaseInsensitive(a.getName(), b.getName()); // FIXME: Locale-dependent sort
return NLMISC::compareCaseInsensitive(a.getName(), b.getName()) < 0; // FIXME: Locale-dependent sort
}
else
{

@ -2670,17 +2670,6 @@ void CUserEntity::selection(const CLFECOMMON::TCLEntityId &slot) // virtual
{
playerGiftNeeded->setValue32(0);
}
//
missionOption = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:TARGET:CONTEXT_MENU:MISSIONS_OPTIONS:%d:TITLE", (int) k), false);
if (missionOption)
{
missionOption->setValue32(0);
}
playerGiftNeeded = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:TARGET:CONTEXT_MENU:MISSIONS_OPTIONS:%d:PLAYER_GIFT_NEEDED", (int) k), false);
if (playerGiftNeeded)
{
playerGiftNeeded->setValue32(0);
}
}
/* TODO ULU : Add RP tags */

@ -323,19 +323,6 @@ namespace EFFECT_FAMILIES
{ "thorn_wall_aura.sbrick", PowerThornWall },
{ "water_wall_aura.sbrick", PowerWaterWall },
{ "lightning_wall_aura.sbrick", PowerLightningWall },
{ "life_aura.sbrick", PowerRootLifeAura },
{ "stamina_aura.sbrick", PowerRootStaminaAura },
{ "sap_aura.sbrick", PowerRootSapAura },
{ "umbrella_aura.sbrick", PowerRootUmbrella },
{ "melee_protection_aura.sbrick", PowerRootProtection },
{ "anti_magic_shield_aura.sbrick", PowerRootAntiMagicShield },
{ "war_cry_aura.sbrick", PowerRootWarCry },
{ "fire_wall_aura.sbrick", PowerRootFireWall },
{ "thorn_wall_aura.sbrick", PowerRootThornWall },
{ "water_wall_aura.sbrick", PowerRootWaterWall },
{ "lightning_wall_aura.sbrick", PowerRootLightningWall },
{ "chg_charac.sbrick", PowerChgCharac },
{ "mod_defense.sbrick", PowerModDefenseSkill },
{ "mod_dodge.sbrick", PowerModDodgeSkill },

Loading…
Cancel
Save