diff --git a/.gitignore b/.gitignore index 7796bda9f..4b691209f 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/nel/include/nel/gui/css_parser.h b/nel/include/nel/gui/css_parser.h index c3a426ee7..360e70a8d 100644 --- a/nel/include/nel/gui/css_parser.h +++ b/nel/include/nel/gui/css_parser.h @@ -73,7 +73,7 @@ namespace NLGUI void preprocess(); // parse selectors + combinators - std::vector parse_selector(const std::string &sel, std::string &pseudoElement) const; + std::vector 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); diff --git a/nel/include/nel/gui/css_selector.h b/nel/include/nel/gui/css_selector.h index ed04ba86d..3228869f3 100644 --- a/nel/include/nel/gui/css_selector.h +++ b/nel/include/nel/gui/css_selector.h @@ -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) diff --git a/nel/include/nel/gui/css_style.h b/nel/include/nel/gui/css_style.h index 5521818a4..9e8ad4b0e 100644 --- a/nel/include/nel/gui/css_style.h +++ b/nel/include/nel/gui/css_style.h @@ -188,6 +188,12 @@ namespace NLGUI void applyLineStyle(const std::string &value, CSSLineStyle *dest, const CSSLineStyle ¤tStyle) 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 &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(); diff --git a/nel/include/nel/gui/group_html.h b/nel/include/nel/gui/group_html.h index 172c8b434..b37d80272 100644 --- a/nel/include/nel/gui/group_html.h +++ b/nel/include/nel/gui/group_html.h @@ -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); diff --git a/nel/include/nel/gui/group_paragraph.h b/nel/include/nel/gui/group_paragraph.h index 20bc50585..b05d4e12e 100644 --- a/nel/include/nel/gui/group_paragraph.h +++ b/nel/include/nel/gui/group_paragraph.h @@ -55,6 +55,8 @@ namespace NLGUI Right }; + enum TTextAlign { AlignLeft = 0, AlignCenter, AlignRight, AlignJustify }; + ///constructor CGroupParagraph(const TCtorParam ¶m); @@ -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 _Elements; + // Horizontal align for elements + TTextAlign _TextAlign; + // Last parent width sint32 _LastW; diff --git a/nel/include/nel/gui/html_element.h b/nel/include/nel/gui/html_element.h index b7bceb4ab..d96b00508 100644 --- a/nel/include/nel/gui/html_element.h +++ b/nel/include/nel/gui/html_element.h @@ -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 _Pseudo; diff --git a/nel/include/nel/gui/html_parser.h b/nel/include/nel/gui/html_parser.h index 0c36014da..cf1392c0b 100644 --- a/nel/include/nel/gui/html_parser.h +++ b/nel/include/nel/gui/html_parser.h @@ -19,6 +19,9 @@ #include "nel/misc/types_nl.h" +// Forward declarations for libxml2 +typedef struct _xmlNode xmlNode; + namespace NLGUI { class CHtmlElement; diff --git a/nel/include/nel/gui/view_renderer.h b/nel/include/nel/gui/view_renderer.h index aefbb315f..4498a436a 100644 --- a/nel/include/nel/gui/view_renderer.h +++ b/nel/include/nel/gui/view_renderer.h @@ -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; diff --git a/nel/include/nel/misc/streamed_package.h b/nel/include/nel/misc/streamed_package.h index 82a138482..093f87a30 100644 --- a/nel/include/nel/misc/streamed_package.h +++ b/nel/include/nel/misc/streamed_package.h @@ -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] diff --git a/nel/include/nel/misc/xml_macros.h b/nel/include/nel/misc/xml_macros.h new file mode 100644 index 000000000..d25cd4c30 --- /dev/null +++ b/nel/include/nel/misc/xml_macros.h @@ -0,0 +1,74 @@ +// NeL - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + + +#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 + diff --git a/nel/src/3d/font_manager.cpp b/nel/src/3d/font_manager.cpp index 3d468f987..a2f0f6cb2 100644 --- a/nel/src/3d/font_manager.cpp +++ b/nel/src/3d/font_manager.cpp @@ -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; diff --git a/nel/src/gui/css_parser.cpp b/nel/src/gui/css_parser.cpp index ab9f6edb7..b3e3861bb 100644 --- a/nel/src/gui/css_parser.cpp +++ b/nel/src/gui/css_parser.cpp @@ -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 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 CCssParser::parse_selector(const std::string &sel, std::string &pseudoElement) const + std::vector CCssParser::parse_selector(const std::string &sel, std::string &pseudoElement, std::string::size_type &pos) const { std::vector 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,7 +621,8 @@ namespace NLGUI } else if (isSpace) { - current.Combinator = ' '; + if (sel[pos] != ',' && sel[pos] != '\0') + current.Combinator = ' '; } else { diff --git a/nel/src/gui/css_selector.cpp b/nel/src/gui/css_selector.cpp index 18d0375b0..dfc01b855 100644 --- a/nel/src/gui/css_selector.cpp +++ b/nel/src/gui/css_selector.cpp @@ -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; diff --git a/nel/src/gui/css_style.cpp b/nel/src/gui/css_style.cpp index ac36da726..3ff9744bc 100644 --- a/nel/src/gui/css_style.cpp +++ b/nel/src/gui/css_style.cpp @@ -386,27 +386,35 @@ namespace NLGUI // - normalize values void CCssStyle::normalize(const TStyle &styleRules, CStyleParams &style, const CStyleParams ¤t) const { + std::set 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 &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 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 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 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::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 diff --git a/nel/src/gui/dbgroup_combo_box.cpp b/nel/src/gui/dbgroup_combo_box.cpp index b54d33e8f..9adffab86 100644 --- a/nel/src/gui/dbgroup_combo_box.cpp +++ b/nel/src/gui/dbgroup_combo_box.cpp @@ -46,7 +46,7 @@ namespace NLGUI static inline bool lt_text(const std::pair &s1, const std::pair &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; diff --git a/nel/src/gui/group_html.cpp b/nel/src/gui/group_html.cpp index 3d37e42bc..eb75c1481 100644 --- a/nel/src/gui/group_html.cpp +++ b/nel/src/gui/group_html.cpp @@ -525,18 +525,19 @@ namespace NLGUI return false; } - string tmpdest = download.dest + ".tmp"; + // use browser Id so that two browsers would not use same temp file + download.tmpdest = localImageName(_Id + download.dest) + ".tmp"; // erase the tmp file if exists - if (CFile::fileExists(tmpdest)) + if (CFile::fileExists(download.tmpdest)) { - CFile::deleteFile(tmpdest); + CFile::deleteFile(download.tmpdest); } - FILE *fp = nlfopen (tmpdest, "wb"); + FILE *fp = nlfopen (download.tmpdest, "wb"); if (fp == NULL) { - nlwarning("Can't open file '%s' for writing: code=%d '%s'", tmpdest.c_str (), errno, strerror(errno)); + nlwarning("Can't open file '%s' for writing: code=%d '%s'", download.tmpdest.c_str (), errno, strerror(errno)); return false; } @@ -544,7 +545,7 @@ namespace NLGUI if (!curl) { fclose(fp); - CFile::deleteFile(tmpdest); + CFile::deleteFile(download.tmpdest); nlwarning("Creating cURL handle failed, unable to download '%s'", download.url.c_str()); return false; @@ -608,54 +609,57 @@ namespace NLGUI void CGroupHTML::finishCurlDownload(const CDataDownload &download) { - std::string tmpfile = download.dest + ".tmp"; - if (download.type == ImgType) { - // there is race condition if two browser instances are downloading same file - // second instance deletes first tmpfile and creates new file for itself. - if (CFile::getFileSize(tmpfile) > 0) + if (CFile::fileExists(download.tmpdest) && CFile::getFileSize(download.tmpdest) > 0) { try { // verify that image is not corrupted uint32 w, h; - CBitmap::loadSize(tmpfile, w, h); + CBitmap::loadSize(download.tmpdest, w, h); if (w != 0 && h != 0) { - // if not tmpfile, then img is already in cache - if (CFile::fileExists(tmpfile)) - { - if (CFile::fileExists(download.dest)) - { - CFile::deleteFile(download.dest); - } - - // to reload image on page, the easiest seems to be changing texture - // to temp file temporarily. that forces driver to reload texture from disk - // ITexture::touch() seem not to do this. - // cache was updated, first set texture as temp file - for(uint i = 0; i < download.imgs.size(); i++) - { - setImage(download.imgs[i].Image, tmpfile, download.imgs[i].Type); - setImageSize(download.imgs[i].Image, download.imgs[i].Style); - } - - CFile::moveFile(download.dest, tmpfile); - } + if (CFile::fileExists(download.dest)) + CFile::deleteFile(download.dest); + // to reload image on page, the easiest seems to be changing texture + // to temp file temporarily. that forces driver to reload texture from disk + // ITexture::touch() seem not to do this. + // cache was updated, first set texture as temp file for(uint i = 0; i < download.imgs.size(); i++) { - setImage(download.imgs[i].Image, download.dest, download.imgs[i].Type); + setImage(download.imgs[i].Image, download.tmpdest, download.imgs[i].Type); setImageSize(download.imgs[i].Image, download.imgs[i].Style); } + CFile::moveFile(download.dest, download.tmpdest); } } catch(const NLMISC::Exception &e) { // exception message has .tmp file name, so keep it for further analysis - nlwarning("Invalid image (%s): %s", download.url.c_str(), e.what()); + nlwarning("Invalid image (%s) from url (%s): %s", download.tmpdest.c_str(), download.url.c_str(), e.what()); + } + } + + if (CFile::fileExists(download.dest) && CFile::getFileSize(download.dest) > 0) + { + try + { + // verify that image is not corrupted + uint32 w, h; + CBitmap::loadSize(download.dest, w, h); + if (w != 0 && h != 0) + for(uint i = 0; i < download.imgs.size(); i++) + { + setImage(download.imgs[i].Image, download.dest, download.imgs[i].Type); + setImageSize(download.imgs[i].Image, download.imgs[i].Style); + } + } + catch(const NLMISC::Exception &e) + { + nlwarning("Invalid image (%s) from url (%s): %s", download.dest.c_str(), download.url.c_str(), e.what()); } } @@ -664,13 +668,13 @@ namespace NLGUI if (download.type == StylesheetType) { - if (CFile::fileExists(tmpfile)) + if (CFile::fileExists(download.tmpdest)) { if (CFile::fileExists(download.dest)) { CFile::deleteFile(download.dest); } - CFile::moveFile(download.dest, tmpfile); + CFile::moveFile(download.dest, download.tmpdest); } cssDownloadFinished(download.url, download.dest); @@ -681,20 +685,20 @@ namespace NLGUI { bool verified = false; // no tmpfile if file was already in cache - if (CFile::fileExists(tmpfile)) + if (CFile::fileExists(download.tmpdest)) { - verified = download.md5sum.empty() || (download.md5sum != getMD5(tmpfile).toString()); + verified = download.md5sum.empty() || (download.md5sum != getMD5(download.tmpdest).toString()); if (verified) { if (CFile::fileExists(download.dest)) { CFile::deleteFile(download.dest); } - CFile::moveFile(download.dest, tmpfile); + CFile::moveFile(download.dest, download.tmpdest); } else { - CFile::deleteFile(tmpfile); + CFile::deleteFile(download.tmpdest); } } else if (CFile::fileExists(download.dest)) @@ -746,7 +750,7 @@ namespace NLGUI if (type != OverImage) { std::string temp = dest; - if (!CFile::fileExists(temp)) + if (!CFile::fileExists(temp) || CFile::getFileSize(temp) == 0) { temp = placeholder; } @@ -967,9 +971,9 @@ namespace NLGUI { fclose(it->fp); - if (CFile::fileExists(it->dest + ".tmp")) + if (CFile::fileExists(it->tmpdest)) { - CFile::deleteFile(it->dest + ".tmp"); + CFile::deleteFile(it->tmpdest); } } } @@ -1227,10 +1231,10 @@ namespace NLGUI case HTML_TABLE: htmlTABLEend(elm); break; case HTML_TD: htmlTDend(elm); break; case HTML_TBODY: renderPseudoElement(":after", elm); break; - case HTML_TEXTAREA: htmlTEXTAREAend(elm); break; + case HTML_TEXTAREA: break; case HTML_TFOOT: renderPseudoElement(":after", elm); break; case HTML_TH: htmlTHend(elm); break; - case HTML_TITLE: htmlTITLEend(elm); break; + case HTML_TITLE: break; case HTML_TR: htmlTRend(elm); break; case HTML_U: renderPseudoElement(":after", elm); break; case HTML_UL: htmlULend(elm); break; @@ -1392,9 +1396,9 @@ namespace NLGUI { beginElement(elm); - std::list::iterator it = elm.Children.begin(); if (!_IgnoreChildElements) { + std::list::iterator it = elm.Children.begin(); while(it != elm.Children.end()) { renderDOM(*it); @@ -1456,37 +1460,15 @@ namespace NLGUI CWidgetManager::getInstance()->registerClockMsgTarget(this); // HTML parameters - BgColor = CRGBA::Black; ErrorColor = CRGBA(255, 0, 0); LinkColor = CRGBA(0, 0, 255); - TextColor = CRGBA(255, 255, 255); - H1Color = CRGBA(255, 255, 255); - H2Color = CRGBA(255, 255, 255); - H3Color = CRGBA(255, 255, 255); - H4Color = CRGBA(255, 255, 255); - H5Color = CRGBA(255, 255, 255); - H6Color = CRGBA(255, 255, 255); ErrorColorGlobalColor = false; LinkColorGlobalColor = false; TextColorGlobalColor = false; - H1ColorGlobalColor = false; - H2ColorGlobalColor = false; - H3ColorGlobalColor = false; - H4ColorGlobalColor = false; - H5ColorGlobalColor = false; - H6ColorGlobalColor = false; - TextFontSize = 9; - H1FontSize = 18; - H2FontSize = 15; - H3FontSize = 12; - H4FontSize = 9; - H5FontSize = 9; - H6FontSize = 9; LIBeginSpace = 4; ULBeginSpace = 12; PBeginSpace = 12; TDBeginSpace = 0; - LIIndent = -10; ULIndent = 30; LineSpaceFontFactor = 0.5f; DefaultButtonGroup = "html_text_button"; @@ -1558,11 +1540,6 @@ namespace NLGUI return _TitlePrefix; } else - if( name == "background_color" ) - { - return toString( BgColor ); - } - else if( name == "error_color" ) { return toString( ErrorColor ); @@ -1573,36 +1550,6 @@ namespace NLGUI return toString( LinkColor ); } else - if( name == "h1_color" ) - { - return toString( H1Color ); - } - else - if( name == "h2_color" ) - { - return toString( H2Color ); - } - else - if( name == "h3_color" ) - { - return toString( H3Color ); - } - else - if( name == "h4_color" ) - { - return toString( H4Color ); - } - else - if( name == "h5_color" ) - { - return toString( H5Color ); - } - else - if( name == "h6_color" ) - { - return toString( H6Color ); - } - else if( name == "error_color_global_color" ) { return toString( ErrorColorGlobalColor ); @@ -1618,71 +1565,6 @@ namespace NLGUI return toString( TextColorGlobalColor ); } else - if( name == "h1_color_global_color" ) - { - return toString( H1ColorGlobalColor ); - } - else - if( name == "h2_color_global_color" ) - { - return toString( H2ColorGlobalColor ); - } - else - if( name == "h3_color_global_color" ) - { - return toString( H3ColorGlobalColor ); - } - else - if( name == "h4_color_global_color" ) - { - return toString( H4ColorGlobalColor ); - } - else - if( name == "h5_color_global_color" ) - { - return toString( H5ColorGlobalColor ); - } - else - if( name == "h6_color_global_color" ) - { - return toString( H6ColorGlobalColor ); - } - else - if( name == "text_font_size" ) - { - return toString( TextFontSize ); - } - else - if( name == "h1_font_size" ) - { - return toString( H1FontSize ); - } - else - if( name == "h2_font_size" ) - { - return toString( H2FontSize ); - } - else - if( name == "h3_font_size" ) - { - return toString( H3FontSize ); - } - else - if( name == "h4_font_size" ) - { - return toString( H4FontSize ); - } - else - if( name == "h5_font_size" ) - { - return toString( H5FontSize ); - } - else - if( name == "h6_font_size" ) - { - return toString( H6FontSize ); - } - else if( name == "td_begin_space" ) { return toString( TDBeginSpace ); @@ -1703,11 +1585,6 @@ namespace NLGUI return toString( ULBeginSpace ); } else - if( name == "li_indent" ) - { - return toString( LIIndent ); - } - else if( name == "ul_indent" ) { return toString( ULIndent ); @@ -1820,14 +1697,6 @@ namespace NLGUI return; } else - if( name == "background_color" ) - { - CRGBA c; - if( fromString( value, c ) ) - BgColor = c; - return; - } - else if( name == "error_color" ) { CRGBA c; @@ -1844,54 +1713,6 @@ namespace NLGUI return; } else - if( name == "h1_color" ) - { - CRGBA c; - if( fromString( value, c ) ) - H1Color = c; - return; - } - else - if( name == "h2_color" ) - { - CRGBA c; - if( fromString( value, c ) ) - H2Color = c; - return; - } - else - if( name == "h3_color" ) - { - CRGBA c; - if( fromString( value, c ) ) - H3Color = c; - return; - } - else - if( name == "h4_color" ) - { - CRGBA c; - if( fromString( value, c ) ) - H4Color = c; - return; - } - else - if( name == "h5_color" ) - { - CRGBA c; - if( fromString( value, c ) ) - H5Color = c; - return; - } - else - if( name == "h6_color" ) - { - CRGBA c; - if( fromString( value, c ) ) - H6Color = c; - return; - } - else if( name == "error_color_global_color" ) { bool b; @@ -1916,110 +1737,6 @@ namespace NLGUI return; } else - if( name == "h1_color_global_color" ) - { - bool b; - if( fromString( value, b ) ) - H1ColorGlobalColor = b; - return; - } - else - if( name == "h2_color_global_color" ) - { - bool b; - if( fromString( value, b ) ) - H2ColorGlobalColor = b; - return; - } - else - if( name == "h3_color_global_color" ) - { - bool b; - if( fromString( value, b ) ) - H3ColorGlobalColor = b; - return; - } - else - if( name == "h4_color_global_color" ) - { - bool b; - if( fromString( value, b ) ) - H4ColorGlobalColor = b; - return; - } - else - if( name == "h5_color_global_color" ) - { - bool b; - if( fromString( value, b ) ) - H5ColorGlobalColor = b; - return; - } - else - if( name == "h6_color_global_color" ) - { - bool b; - if( fromString( value, b ) ) - H6ColorGlobalColor = b; - return; - } - else - if( name == "text_font_size" ) - { - uint i; - if( fromString( value, i ) ) - TextFontSize = i; - return; - } - else - if( name == "h1_font_size" ) - { - uint i; - if( fromString( value, i ) ) - H1FontSize = i; - return; - } - else - if( name == "h2_font_size" ) - { - uint i; - if( fromString( value, i ) ) - H2FontSize = i; - return; - } - else - if( name == "h3_font_size" ) - { - uint i; - if( fromString( value, i ) ) - H3FontSize = i; - return; - } - else - if( name == "h4_font_size" ) - { - uint i; - if( fromString( value, i ) ) - H4FontSize = i; - return; - } - else - if( name == "h5_font_size" ) - { - uint i; - if( fromString( value, i ) ) - H5FontSize = i; - return; - } - else - if( name == "h6_font_size" ) - { - uint i; - if( fromString( value, i ) ) - H6FontSize = i; - return; - } - else if( name == "td_begin_space" ) { uint i; @@ -2052,14 +1769,6 @@ namespace NLGUI return; } else - if( name == "li_indent" ) - { - uint i; - if( fromString( value, i ) ) - LIIndent = i; - return; - } - else if( name == "ul_indent" ) { uint i; @@ -2218,16 +1927,8 @@ namespace NLGUI xmlSetProp( node, BAD_CAST "type", BAD_CAST "html" ); xmlSetProp( node, BAD_CAST "url", BAD_CAST _URL.c_str() ); xmlSetProp( node, BAD_CAST "title_prefix", BAD_CAST _TitlePrefix.c_str() ); - xmlSetProp( node, BAD_CAST "background_color", BAD_CAST toString( BgColor ).c_str() ); xmlSetProp( node, BAD_CAST "error_color", BAD_CAST toString( ErrorColor ).c_str() ); xmlSetProp( node, BAD_CAST "link_color", BAD_CAST toString( LinkColor ).c_str() ); - xmlSetProp( node, BAD_CAST "background_color", BAD_CAST toString( BgColor ).c_str() ); - xmlSetProp( node, BAD_CAST "h1_color", BAD_CAST toString( H1Color ).c_str() ); - xmlSetProp( node, BAD_CAST "h2_color", BAD_CAST toString( H2Color ).c_str() ); - xmlSetProp( node, BAD_CAST "h3_color", BAD_CAST toString( H3Color ).c_str() ); - xmlSetProp( node, BAD_CAST "h4_color", BAD_CAST toString( H4Color ).c_str() ); - xmlSetProp( node, BAD_CAST "h5_color", BAD_CAST toString( H5Color ).c_str() ); - xmlSetProp( node, BAD_CAST "h6_color", BAD_CAST toString( H6Color ).c_str() ); xmlSetProp( node, BAD_CAST "error_color_global_color", BAD_CAST toString( ErrorColorGlobalColor ).c_str() ); @@ -2235,31 +1936,11 @@ namespace NLGUI BAD_CAST toString( LinkColorGlobalColor ).c_str() ); xmlSetProp( node, BAD_CAST "text_color_global_color", BAD_CAST toString( TextColorGlobalColor ).c_str() ); - xmlSetProp( node, BAD_CAST "h1_color_global_color", - BAD_CAST toString( H1ColorGlobalColor ).c_str() ); - xmlSetProp( node, BAD_CAST "h2_color_global_color", - BAD_CAST toString( H2ColorGlobalColor ).c_str() ); - xmlSetProp( node, BAD_CAST "h3_color_global_color", - BAD_CAST toString( H3ColorGlobalColor ).c_str() ); - xmlSetProp( node, BAD_CAST "h4_color_global_color", - BAD_CAST toString( H4ColorGlobalColor ).c_str() ); - xmlSetProp( node, BAD_CAST "h5_color_global_color", - BAD_CAST toString( H5ColorGlobalColor ).c_str() ); - xmlSetProp( node, BAD_CAST "h6_color_global_color", - BAD_CAST toString( H6ColorGlobalColor ).c_str() ); - - xmlSetProp( node, BAD_CAST "text_font_size", BAD_CAST toString( TextFontSize ).c_str() ); - xmlSetProp( node, BAD_CAST "h1_font_size", BAD_CAST toString( H1FontSize ).c_str() ); - xmlSetProp( node, BAD_CAST "h2_font_size", BAD_CAST toString( H2FontSize ).c_str() ); - xmlSetProp( node, BAD_CAST "h3_font_size", BAD_CAST toString( H3FontSize ).c_str() ); - xmlSetProp( node, BAD_CAST "h4_font_size", BAD_CAST toString( H4FontSize ).c_str() ); - xmlSetProp( node, BAD_CAST "h5_font_size", BAD_CAST toString( H5FontSize ).c_str() ); - xmlSetProp( node, BAD_CAST "h6_font_size", BAD_CAST toString( H6FontSize ).c_str() ); + xmlSetProp( node, BAD_CAST "td_begin_space", BAD_CAST toString( TDBeginSpace ).c_str() ); xmlSetProp( node, BAD_CAST "paragraph_begin_space", BAD_CAST toString( PBeginSpace ).c_str() ); xmlSetProp( node, BAD_CAST "li_begin_space", BAD_CAST toString( LIBeginSpace ).c_str() ); xmlSetProp( node, BAD_CAST "ul_begin_space", BAD_CAST toString( ULBeginSpace ).c_str() ); - xmlSetProp( node, BAD_CAST "li_indent", BAD_CAST toString( LIIndent ).c_str() ); xmlSetProp( node, BAD_CAST "ul_indent", BAD_CAST toString( ULIndent ).c_str() ); xmlSetProp( node, BAD_CAST "multi_line_space_factor", BAD_CAST toString( LineSpaceFontFactor ).c_str() ); xmlSetProp( node, BAD_CAST "form_text_area_group", BAD_CAST DefaultFormTextGroup.c_str() ); @@ -2311,36 +1992,12 @@ namespace NLGUI _TitlePrefix = CI18N::get((const char*)ptr); // Parameters - ptr = xmlGetProp (cur, (xmlChar*)"background_color"); - if (ptr) - BgColor = convertColor(ptr); ptr = xmlGetProp (cur, (xmlChar*)"error_color"); if (ptr) ErrorColor = convertColor(ptr); ptr = xmlGetProp (cur, (xmlChar*)"link_color"); if (ptr) LinkColor = convertColor(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"text_color"); - if (ptr) - TextColor = convertColor(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h1_color"); - if (ptr) - H1Color = convertColor(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h2_color"); - if (ptr) - H2Color = convertColor(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h3_color"); - if (ptr) - H3Color = convertColor(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h4_color"); - if (ptr) - H4Color = convertColor(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h5_color"); - if (ptr) - H5Color = convertColor(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h6_color"); - if (ptr) - H6Color = convertColor(ptr); ptr = xmlGetProp (cur, (xmlChar*)"error_color_global_color"); if (ptr) ErrorColorGlobalColor = convertBool(ptr); @@ -2350,45 +2007,6 @@ namespace NLGUI ptr = xmlGetProp (cur, (xmlChar*)"text_color_global_color"); if (ptr) TextColorGlobalColor = convertBool(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h1_color_global_color"); - if (ptr) - H1ColorGlobalColor = convertBool(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h2_color_global_color"); - if (ptr) - H2ColorGlobalColor = convertBool(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h3_color_global_color"); - if (ptr) - H3ColorGlobalColor = convertBool(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h4_color_global_color"); - if (ptr) - H4ColorGlobalColor = convertBool(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h5_color_global_color"); - if (ptr) - H5ColorGlobalColor = convertBool(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"h6_color_global_color"); - if (ptr) - H6ColorGlobalColor = convertBool(ptr); - ptr = xmlGetProp (cur, (xmlChar*)"text_font_size"); - if (ptr) - fromString((const char*)ptr, TextFontSize); - ptr = xmlGetProp (cur, (xmlChar*)"h1_font_size"); - if (ptr) - fromString((const char*)ptr, H1FontSize); - ptr = xmlGetProp (cur, (xmlChar*)"h2_font_size"); - if (ptr) - fromString((const char*)ptr, H2FontSize); - ptr = xmlGetProp (cur, (xmlChar*)"h3_font_size"); - if (ptr) - fromString((const char*)ptr, H3FontSize); - ptr = xmlGetProp (cur, (xmlChar*)"h4_font_size"); - if (ptr) - fromString((const char*)ptr, H4FontSize); - ptr = xmlGetProp (cur, (xmlChar*)"h5_font_size"); - if (ptr) - fromString((const char*)ptr, H5FontSize); - ptr = xmlGetProp (cur, (xmlChar*)"h6_font_size"); - if (ptr) - fromString((const char*)ptr, H6FontSize); ptr = xmlGetProp (cur, (xmlChar*)"td_begin_space"); if (ptr) fromString((const char*)ptr, TDBeginSpace); @@ -2401,9 +2019,6 @@ namespace NLGUI ptr = xmlGetProp (cur, (xmlChar*)"ul_begin_space"); if (ptr) fromString((const char*)ptr, ULBeginSpace); - ptr = xmlGetProp (cur, (xmlChar*)"li_indent"); - if (ptr) - fromString((const char*)ptr, LIIndent); ptr = xmlGetProp (cur, (xmlChar*)"ul_indent"); if (ptr) fromString((const char*)ptr, ULIndent); @@ -2543,6 +2158,17 @@ namespace NLGUI newParagraph->setResizeFromChildH(true); newParagraph->setMarginLeft(getIndent()); + if (!_Style.Current.TextAlign.empty()) + { + if (_Style.Current.TextAlign == "left") + newParagraph->setTextAlign(CGroupParagraph::AlignLeft); + else if (_Style.Current.TextAlign == "center") + newParagraph->setTextAlign(CGroupParagraph::AlignCenter); + else if (_Style.Current.TextAlign == "right") + newParagraph->setTextAlign(CGroupParagraph::AlignRight); + else if (_Style.Current.TextAlign == "justify") + newParagraph->setTextAlign(CGroupParagraph::AlignJustify); + } // Add to the group addHtmlGroup (newParagraph, beginSpace); @@ -2636,6 +2262,17 @@ namespace NLGUI invalidateCoords(); } + void CGroupHTML::browseErrorHtml(const std::string &html) + { + releaseDownloads(); + removeContent(); + + renderHtmlString(html); + + updateRefreshButton(); + invalidateCoords(); + } + // *************************************************************************** bool CGroupHTML::isBrowsing() @@ -2744,6 +2381,113 @@ namespace NLGUI } } + // *************************************************************************** + bool CGroupHTML::isSameStyle(CViewLink *text, const CStyleParams &style) const + { + if (!text) return false; + + bool embolden = style.FontWeight >= FONT_WEIGHT_BOLD; + bool sameShadow = style.TextShadow.Enabled && text->getShadow(); + if (sameShadow && style.TextShadow.Enabled) + { + sint sx, sy; + text->getShadowOffset(sx, sy); + sameShadow = (style.TextShadow.Color == text->getShadowColor()); + sameShadow = sameShadow && (style.TextShadow.Outline == text->getShadowOutline()); + sameShadow = sameShadow && (style.TextShadow.X == sx) && (style.TextShadow.Y == sy); + } + // Compatible with current parameters ? + return sameShadow && + (style.TextColor == text->getColor()) && + (style.FontFamily == text->getFontName()) && + (style.FontSize == (uint)text->getFontSize()) && + (style.Underlined == text->getUnderlined()) && + (style.StrikeThrough == text->getStrikeThrough()) && + (embolden == text->getEmbolden()) && + (style.FontOblique == text->getOblique()) && + (getLink() == text->Link) && + (style.GlobalColor == text->getModulateGlobalColor()); + } + + // *************************************************************************** + void CGroupHTML::newTextButton(const std::string &text, const std::string &tpl) + { + _CurrentViewLink = NULL; + _CurrentViewImage = NULL; + + // Action handler parameters : "name=group_html_id|form=id_of_the_form|submit_button=button_name" + string param = "name=" + this->_Id + "|url=" + getLink(); + string name; + if (!_AnchorName.empty()) + name = _AnchorName.back(); + + typedef pair TTmplParam; + vector tmplParams; + tmplParams.push_back(TTmplParam("id", "")); + tmplParams.push_back(TTmplParam("onclick", "browse")); + tmplParams.push_back(TTmplParam("onclick_param", param)); + tmplParams.push_back(TTmplParam("active", "true")); + CInterfaceGroup *buttonGroup = CWidgetManager::getInstance()->getParser()->createGroupInstance(tpl, getId()+":"+name, tmplParams); + if (!buttonGroup) + { + nlinfo("Text button template '%s' not found", tpl.c_str()); + return; + } + buttonGroup->setId(getId()+":"+name); + + // Add the ctrl button + CCtrlTextButton *ctrlButton = dynamic_cast(buttonGroup->getCtrl("button")); + if (!ctrlButton) ctrlButton = dynamic_cast(buttonGroup->getCtrl("b")); + if (!ctrlButton) + { + nlinfo("Text button template '%s' is missing :button or :b text element", tpl.c_str()); + return; + } + ctrlButton->setModulateGlobalColorAll(false); + + // Translate the tooltip + ctrlButton->setText(text); + ctrlButton->setDefaultContextHelp(std::string(getLinkTitle())); + // empty url / button disabled + ctrlButton->setFrozen(*getLink() == '\0'); + + setTextButtonStyle(ctrlButton, _Style.Current); + + _Paragraph->addChild(buttonGroup); + } + + // *************************************************************************** + void CGroupHTML::newTextLink(const std::string &text) + { + CViewLink *newLink = new CViewLink(CViewBase::TCtorParam()); + if (getA()) + { + newLink->Link = getLink(); + newLink->LinkTitle = getLinkTitle(); + if (!newLink->Link.empty()) + { + newLink->setHTMLView (this); + newLink->setActionOnLeftClick("browse"); + newLink->setParamsOnLeftClick("name=" + getId() + "|url=" + newLink->Link); + } + } + newLink->setText(text); + newLink->setMultiLineSpace((uint)((float)(_Style.Current.FontSize)*LineSpaceFontFactor)); + newLink->setMultiLine(true); + newLink->setModulateGlobalColor(_Style.Current.GlobalColor); + setTextStyle(newLink, _Style.Current); + + registerAnchor(newLink); + + if (getA() && !newLink->Link.empty()) + getParagraph()->addChildLink(newLink); + else + getParagraph()->addChild(newLink); + + _CurrentViewLink = newLink; + _CurrentViewImage = NULL; + } + // *************************************************************************** void CGroupHTML::addString(const std::string &str) @@ -2783,15 +2527,7 @@ namespace NLGUI } // In title ? - if (_Title) - { - _TitleString += tmpStr; - } - else if (_TextArea) - { - _TextAreaContent += tmpStr; - } - else if (_Object) + if (_Object) { _ObjectScript += tmpStr; } @@ -2818,32 +2554,11 @@ namespace NLGUI // Text added ? bool added = false; - bool embolden = style.FontWeight >= FONT_WEIGHT_BOLD; - // Number of child in this paragraph if (_CurrentViewLink) { bool skipLine = !_CurrentViewLink->getText().empty() && *(_CurrentViewLink->getText().rbegin()) == '\n'; - bool sameShadow = style.TextShadow.Enabled && _CurrentViewLink->getShadow(); - if (sameShadow && style.TextShadow.Enabled) - { - sint sx, sy; - _CurrentViewLink->getShadowOffset(sx, sy); - sameShadow = (style.TextShadow.Color == _CurrentViewLink->getShadowColor()); - sameShadow = sameShadow && (style.TextShadow.Outline == _CurrentViewLink->getShadowOutline()); - sameShadow = sameShadow && (style.TextShadow.X == sx) && (style.TextShadow.Y == sy); - } - // Compatible with current parameters ? - if (!skipLine && sameShadow && - (style.TextColor == _CurrentViewLink->getColor()) && - (style.FontFamily == _CurrentViewLink->getFontName()) && - (style.FontSize == (uint)_CurrentViewLink->getFontSize()) && - (style.Underlined == _CurrentViewLink->getUnderlined()) && - (style.StrikeThrough == _CurrentViewLink->getStrikeThrough()) && - (embolden == _CurrentViewLink->getEmbolden()) && - (style.FontOblique == _CurrentViewLink->getOblique()) && - (getLink() == _CurrentViewLink->Link) && - (style.GlobalColor == _CurrentViewLink->getModulateGlobalColor())) + if (!skipLine && isSameStyle(_CurrentViewLink, style)) { // Concat the text _CurrentViewLink->setText(_CurrentViewLink->getText()+tmpStr); @@ -2856,78 +2571,9 @@ namespace NLGUI if (!added) { if (getA() && string(getLinkClass()) == "ryzom-ui-button") - { - string buttonTemplate = DefaultButtonGroup; - // Action handler parameters : "name=group_html_id|form=id_of_the_form|submit_button=button_name" - string param = "name=" + this->_Id + "|url=" + getLink(); - string name; - if (!_AnchorName.empty()) - name = _AnchorName.back(); - typedef pair TTmplParam; - vector tmplParams; - tmplParams.push_back(TTmplParam("id", "")); - tmplParams.push_back(TTmplParam("onclick", "browse")); - tmplParams.push_back(TTmplParam("onclick_param", param)); - tmplParams.push_back(TTmplParam("active", "true")); - CInterfaceGroup *buttonGroup = CWidgetManager::getInstance()->getParser()->createGroupInstance(buttonTemplate, getId()+":"+name, tmplParams); - if (buttonGroup) - { - buttonGroup->setId(getId()+":"+name); - // Add the ctrl button - CCtrlTextButton *ctrlButton = dynamic_cast(buttonGroup->getCtrl("button")); - if (!ctrlButton) ctrlButton = dynamic_cast(buttonGroup->getCtrl("b")); - if (ctrlButton) - { - ctrlButton->setModulateGlobalColorAll (false); - - // Translate the tooltip - ctrlButton->setDefaultContextHelp(getLinkTitle()); - ctrlButton->setText(tmpStr); - // empty url / button disabled - bool disabled = string(getLink()).empty(); - ctrlButton->setFrozen(disabled); - - setTextButtonStyle(ctrlButton, style); - } - getParagraph()->addChild (buttonGroup); - paragraphChange (); - } - - } + newTextButton(tmpStr, DefaultButtonGroup); else - { - CViewLink *newLink = new CViewLink(CViewBase::TCtorParam()); - if (getA()) - { - newLink->Link = getLink(); - newLink->LinkTitle = getLinkTitle(); - if (!newLink->Link.empty()) - { - newLink->setHTMLView (this); - - newLink->setActionOnLeftClick("browse"); - newLink->setParamsOnLeftClick("name=" + getId() + "|url=" + newLink->Link); - } - } - newLink->setText(tmpStr); - newLink->setMultiLineSpace((uint)((float)(style.FontSize)*LineSpaceFontFactor)); - newLink->setMultiLine(true); - newLink->setModulateGlobalColor(style.GlobalColor); - setTextStyle(newLink, style); - // newLink->setLineAtBottom (true); - - registerAnchor(newLink); - - if (getA() && !newLink->Link.empty()) - { - getParagraph()->addChildLink(newLink); - } - else - { - getParagraph()->addChild(newLink); - } - paragraphChange (); - } + newTextLink(tmpStr); } } } @@ -3276,8 +2922,6 @@ namespace NLGUI _Anchors.clear(); _AnchorName.clear(); _CellParams.clear(); - _Title = false; - _TextArea = false; _Object = false; _Localize = false; _ReadingHeadTag = false; @@ -3413,12 +3057,10 @@ namespace NLGUI void CGroupHTML::setTitle(const std::string &title) { - _TitleString.clear(); - if(!_TitlePrefix.empty()) - { - _TitleString = _TitlePrefix + " - "; - } - _TitleString += title; + if(_TitlePrefix.empty()) + _TitleString = title; + else + _TitleString = _TitlePrefix + " - " + title; setContainerTitle(_TitleString); } @@ -3955,11 +3597,22 @@ namespace NLGUI { if (!success) { + CUrlParser uri(_CurlWWW->Url); + + // potentially unwanted chars + std::string url = _CurlWWW->Url; + url = strFindReplaceAll(url, string("<"), string("%3C")); + url = strFindReplaceAll(url, string(">"), string("%3E")); + url = strFindReplaceAll(url, string("\""), string("%22")); + url = strFindReplaceAll(url, string("'"), string("%27")); + std::string err; - err = "Connection failed with cURL error: "; + err = "cURL error"; + err += "

Connection failed with cURL error

"; err += error; - err += "\nURL '" + _CurlWWW->Url + "'"; - browseError(err.c_str()); + err += "
(" + uri.scheme + "://" + uri.host + ") reload"; + err += ""; + browseErrorHtml(err); return; } @@ -4071,10 +3724,9 @@ namespace NLGUI obj.LastModified = data.data->getLastModified(); CHttpCache::getInstance()->store(data.dest, obj); - std::string tmpfile = data.dest + ".tmp"; - if (code == 304 && CFile::fileExists(tmpfile)) + if (code == 304 && CFile::fileExists(data.tmpdest)) { - CFile::deleteFile(tmpfile); + CFile::deleteFile(data.tmpdest); } } else if ((code >= 301 && code <= 303) || code == 307 || code == 308) @@ -4102,10 +3754,9 @@ namespace NLGUI LOG_DL("Redirect '%s'", location.c_str()); // no finished callback called, so cleanup old temp - std::string tmpfile = data.dest + ".tmp"; - if (CFile::fileExists(tmpfile)) + if (CFile::fileExists(data.tmpdest)) { - CFile::deleteFile(tmpfile); + CFile::deleteFile(data.tmpdest); } return; } @@ -4393,7 +4044,7 @@ namespace NLGUI clearContext(); // Reset default background color - setBackgroundColor (BgColor); + setBackgroundColor (_BrowserStyle.Current.BackgroundColor); setBackground ("blank.tga", true, false); paragraphChange (); @@ -5377,6 +5028,11 @@ namespace NLGUI cellParams.Align = CGroupCell::Center; else if (align == "right") cellParams.Align = CGroupCell::Right; + else if (align != "justify") + align.clear(); + + // copy td align (can be empty) attribute back into css + _Style.Current.TextAlign = align; } { @@ -6789,10 +6445,12 @@ namespace NLGUI string image = _Style.getStyle("background-image"); addImageDownload(image, table, CStyleParams(), NormalImage, ""); } + else + { + // will be set in addImageDownload if background-image exists + table->setModulateGlobalColor(_Style.Current.GlobalColor); + } - // setting ModulateGlobalColor must be after addImageDownload - if (_Style.checkStyle("-ryzom-modulate-bgcolor", "true")) - table->setModulateGlobalColor(true); table->setMarginLeft(getIndent()); addHtmlGroup (table, 0); @@ -6876,6 +6534,11 @@ namespace NLGUI string image = _Style.getStyle("background-image"); addImageDownload(image, _Cells.back(), CStyleParams(), NormalImage, ""); } + else + { + // will be set in addImageDownload if background-image is set + _Cells.back()->setModulateGlobalColor(_Style.Current.GlobalColor); + } if (elm.hasNonEmptyAttribute("colspan")) fromString(elm.getAttribute("colspan"), _Cells.back()->ColSpan); @@ -6912,10 +6575,6 @@ namespace NLGUI _Cells.back()->NewLine = getTR(); - // setting ModulateGlobalColor must be after addImageDownload - if (_Style.checkStyle("-ryzom-modulate-bgcolor", "true")) - _Cells.back()->setModulateGlobalColor(true); - // border from if (table->CellBorder) { @@ -6980,6 +6639,9 @@ namespace NLGUI // *************************************************************************** void CGroupHTML::htmlTEXTAREA(const CHtmlElement &elm) { + _IgnoreChildElements = true; + + // TODO: allow textarea without form if (_Forms.empty()) return; @@ -6994,7 +6656,6 @@ namespace NLGUI _TextAreaName.clear(); _TextAreaRow = 1; _TextAreaCols = 10; - _TextAreaContent.clear(); _TextAreaMaxLength = 1024; if (elm.hasNonEmptyAttribute("name")) _TextAreaName = elm.getAttribute("name"); @@ -7006,16 +6667,11 @@ namespace NLGUI fromString(elm.getAttribute("maxlength"), _TextAreaMaxLength); _TextAreaTemplate = !templateName.empty() ? templateName : DefaultFormTextAreaGroup; - _TextArea = true; - _PRE.push_back(true); - } - void CGroupHTML::htmlTEXTAREAend(const CHtmlElement &elm) - { - if (_Forms.empty()) - return; + std::string content = strFindReplaceAll(elm.serializeChilds(), std::string("\t"), std::string(" ")); + content = strFindReplaceAll(content, std::string("\n"), std::string(" ")); - CInterfaceGroup *textArea = addTextArea (_TextAreaTemplate, _TextAreaName.c_str (), _TextAreaRow, _TextAreaCols, true, _TextAreaContent, _TextAreaMaxLength); + CInterfaceGroup *textArea = addTextArea (_TextAreaTemplate, _TextAreaName.c_str (), _TextAreaRow, _TextAreaCols, true, content, _TextAreaMaxLength); if (textArea) { // Add the text area to the form @@ -7024,9 +6680,6 @@ namespace NLGUI entry.TextArea = textArea; _Forms.back().Entries.push_back (entry); } - - _TextArea = false; - popIfNotEmpty (_PRE); } // *************************************************************************** @@ -7043,18 +6696,14 @@ namespace NLGUI // *************************************************************************** void CGroupHTML::htmlTITLE(const CHtmlElement &elm) { + _IgnoreChildElements = true; + // TODO: only from // if (!_ReadingHeadTag) return; - if(!_TitlePrefix.empty()) - _TitleString = _TitlePrefix + " - "; - else - _TitleString.clear(); - _Title = true; - } - void CGroupHTML::htmlTITLEend(const CHtmlElement &elm) - { - _Title = false; + // consume all child elements + _TitleString = strFindReplaceAll(elm.serializeChilds(), std::string("\t"), std::string(" ")); + _TitleString = strFindReplaceAll(_TitleString, std::string("\n"), std::string(" ")); setTitle(_TitleString); } diff --git a/nel/src/gui/group_paragraph.cpp b/nel/src/gui/group_paragraph.cpp index 4ca13c8ae..623975b98 100644 --- a/nel/src/gui/group_paragraph.cpp +++ b/nel/src/gui/group_paragraph.cpp @@ -65,6 +65,7 @@ namespace NLGUI _Indent = 0; _FirstViewIndentView = false; _TextId = 0; + _TextAlign = AlignLeft; } // ---------------------------------------------------------------------------- @@ -713,6 +714,10 @@ namespace NLGUI CViewText *viewText = dynamic_cast(_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') { diff --git a/nel/src/gui/html_element.cpp b/nel/src/gui/html_element.cpp index f0b764640..454833a5a 100644 --- a/nel/src/gui/html_element.cpp +++ b/nel/src/gui/html_element.cpp @@ -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 searchReplace = { + "&", "&", + "<", "<", + ">", ">", + "\xA0", " ", + }; + + 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 = """; + val = strFindReplaceAll(val, q, quot); + } + + return val; + } + + // *************************************************************************** + std::string CHtmlElement::serializeAttributes() const + { + std::string result; + for(std::map::const_iterator it = Attributes.begin(); it != Attributes.end(); ++it) + { + if (it->first == "class") + { + result += " class=\""; + for(std::set::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::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 += ""; + + return result; + } + // *************************************************************************** std::string CHtmlElement::toString(bool tree, uint depth) const { diff --git a/nel/src/gui/html_parser.cpp b/nel/src/gui/html_parser.cpp index bcb83bf8e..b8eb0176b 100644 --- a/nel/src/gui/html_parser.cpp +++ b/nel/src/gui/html_parser.cpp @@ -66,7 +66,15 @@ namespace NLGUI { if (node->type == XML_TEXT_NODE) { - parent.Children.push_back(CHtmlElement(CHtmlElement::TEXT_NODE, (const char*)(node->content))); + // 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:
// dd without end tag:
diff --git a/nel/src/gui/view_renderer.cpp b/nel/src/gui/view_renderer.cpp index 66aea4cfb..76e064dfd 100644 --- a/nel/src/gui/view_renderer.cpp +++ b/nel/src/gui/view_renderer.cpp @@ -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; diff --git a/nel/src/misc/bitmap.cpp b/nel/src/misc/bitmap.cpp index 33c0cec43..ee6a0e69e 100644 --- a/nel/src/misc/bitmap.cpp +++ b/nel/src/misc/bitmap.cpp @@ -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; diff --git a/nel/src/misc/streamed_package.cpp b/nel/src/misc/streamed_package.cpp index 28e2db956..ad013cccf 100644 --- a/nel/src/misc/streamed_package.cpp +++ b/nel/src/misc/streamed_package.cpp @@ -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); diff --git a/nel/tools/CMakeLists.txt b/nel/tools/CMakeLists.txt index 5297f34a4..079ded560 100644 --- a/nel/tools/CMakeLists.txt +++ b/nel/tools/CMakeLists.txt @@ -37,3 +37,8 @@ ENDIF() IF(WITH_NEL_TESTS) ADD_SUBDIRECTORY(nel_unit_test) ENDIF() + +IF(WITH_HTMLCSS_TEST) + ADD_SUBDIRECTORY(htmlcss_test) +ENDIF() + diff --git a/nel/tools/htmlcss_test/CMakeLists.txt b/nel/tools/htmlcss_test/CMakeLists.txt new file mode 100644 index 000000000..d37498f60 --- /dev/null +++ b/nel/tools/htmlcss_test/CMakeLists.txt @@ -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 diff --git a/nel/tools/htmlcss_test/htmlcss_test.cpp b/nel/tools/htmlcss_test/htmlcss_test.cpp new file mode 100644 index 000000000..4e5b79843 --- /dev/null +++ b/nel/tools/htmlcss_test/htmlcss_test.cpp @@ -0,0 +1,183 @@ +/* + * File: main.cpp + * Author: Karu + * + * Created on 2015-04-11 + */ + +typedef struct _xmlNode xmlNode; + +#include +#include + +#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 links; + std::vector 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 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; +} diff --git a/nel/tools/htmlcss_test/tests/01-syntax-tests.html b/nel/tools/htmlcss_test/tests/01-syntax-tests.html new file mode 100644 index 000000000..f9b2c9356 --- /dev/null +++ b/nel/tools/htmlcss_test/tests/01-syntax-tests.html @@ -0,0 +1,28 @@ + + + + +
+ + link + link + + + diff --git a/nel/tools/htmlcss_test/tests/css-tricks/01-var-toggle.html b/nel/tools/htmlcss_test/tests/css-tricks/01-var-toggle.html new file mode 100644 index 000000000..72e49b854 --- /dev/null +++ b/nel/tools/htmlcss_test/tests/css-tricks/01-var-toggle.html @@ -0,0 +1,24 @@ + + + + +

+

+

+

+ + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e01.basic.html b/nel/tools/htmlcss_test/tests/custom-properties/e01.basic.html new file mode 100644 index 000000000..c5085b8ef --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e01.basic.html @@ -0,0 +1,18 @@ + + + + +
+

Header

+
+ + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e02.case-sensitive-name.html b/nel/tools/htmlcss_test/tests/custom-properties/e02.case-sensitive-name.html new file mode 100644 index 000000000..1d9dc7b88 --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e02.case-sensitive-name.html @@ -0,0 +1,23 @@ + + + + +
+

Header1

+

Header2

+
+ + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e03.value-syntax.html b/nel/tools/htmlcss_test/tests/custom-properties/e03.value-syntax.html new file mode 100644 index 000000000..28f0a9c69 --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e03.value-syntax.html @@ -0,0 +1,17 @@ + + + + +
+

Header

+
+ + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e05.inherited.html b/nel/tools/htmlcss_test/tests/custom-properties/e05.inherited.html new file mode 100644 index 000000000..bafbbf37f --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e05.inherited.html @@ -0,0 +1,17 @@ + + + + +

I inherited blue from the root element!

+
I got green set directly on me!
+
+ While I got red set directly on me! +

I’m red too, because of inheritance!

+
+ + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e06.i18n.html b/nel/tools/htmlcss_test/tests/custom-properties/e06.i18n.html new file mode 100644 index 000000000..861e60412 --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e06.i18n.html @@ -0,0 +1,15 @@ + + + + + + link + + link + + + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e07-safe-use-not-cyclic.html b/nel/tools/htmlcss_test/tests/custom-properties/e07-safe-use-not-cyclic.html new file mode 100644 index 000000000..39ed3a299 --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e07-safe-use-not-cyclic.html @@ -0,0 +1,15 @@ + + + + +
+ + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e08-cyclic.html b/nel/tools/htmlcss_test/tests/custom-properties/e08-cyclic.html new file mode 100644 index 000000000..4d1f5fdd8 --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e08-cyclic.html @@ -0,0 +1,14 @@ + + + + +
+ + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e09-not-cyclic.html b/nel/tools/htmlcss_test/tests/custom-properties/e09-not-cyclic.html new file mode 100644 index 000000000..f3e1788ee --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e09-not-cyclic.html @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e10.fallback.html b/nel/tools/htmlcss_test/tests/custom-properties/e10.fallback.html new file mode 100644 index 000000000..5d785bffa --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e10.fallback.html @@ -0,0 +1,24 @@ + + + + +
+

header

+

text

+
+ + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e11.1.invalid-property-name.html b/nel/tools/htmlcss_test/tests/custom-properties/e11.1.invalid-property-name.html new file mode 100644 index 000000000..488e733a9 --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e11.1.invalid-property-name.html @@ -0,0 +1,12 @@ + + + + +
+ + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e11.2.whitespace-after-var.html b/nel/tools/htmlcss_test/tests/custom-properties/e11.2.whitespace-after-var.html new file mode 100644 index 000000000..a67b4ba1d --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e11.2.whitespace-after-var.html @@ -0,0 +1,13 @@ + + + + + +
+ + diff --git a/nel/tools/htmlcss_test/tests/custom-properties/e13.invalid-variables.html b/nel/tools/htmlcss_test/tests/custom-properties/e13.invalid-variables.html new file mode 100644 index 000000000..f60877d82 --- /dev/null +++ b/nel/tools/htmlcss_test/tests/custom-properties/e13.invalid-variables.html @@ -0,0 +1,13 @@ + + + + + + +
+ + diff --git a/ryzom/client/src/client_sheets/item_sheet.cpp b/ryzom/client/src/client_sheets/item_sheet.cpp index 5918ba73c..d5831167c 100644 --- a/ryzom/client/src/client_sheets/item_sheet.cpp +++ b/ryzom/client/src/client_sheets/item_sheet.cpp @@ -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 diff --git a/ryzom/client/src/client_sheets/outpost_building_sheet.cpp b/ryzom/client/src/client_sheets/outpost_building_sheet.cpp index 42083c83f..0f741c1a2 100644 --- a/ryzom/client/src/client_sheets/outpost_building_sheet.cpp +++ b/ryzom/client/src/client_sheets/outpost_building_sheet.cpp @@ -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); } diff --git a/ryzom/client/src/interface_v3/dbctrl_sheet.cpp b/ryzom/client/src/interface_v3/dbctrl_sheet.cpp index f24137f23..70efd1f59 100644 --- a/ryzom/client/src/interface_v3/dbctrl_sheet.cpp +++ b/ryzom/client/src/interface_v3/dbctrl_sheet.cpp @@ -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) diff --git a/ryzom/client/src/interface_v3/dbctrl_sheet.h b/ryzom/client/src/interface_v3/dbctrl_sheet.h index a26a74b22..ab44ce99f 100644 --- a/ryzom/client/src/interface_v3/dbctrl_sheet.h +++ b/ryzom/client/src/interface_v3/dbctrl_sheet.h @@ -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 diff --git a/ryzom/client/src/interface_v3/dbgroup_list_sheet_bonus_malus.cpp b/ryzom/client/src/interface_v3/dbgroup_list_sheet_bonus_malus.cpp index 175d7339b..f41dd3085 100644 --- a/ryzom/client/src/interface_v3/dbgroup_list_sheet_bonus_malus.cpp +++ b/ryzom/client/src/interface_v3/dbgroup_list_sheet_bonus_malus.cpp @@ -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 ¶m) -: 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(root->getNode(ICDBNode::CTextId("DISABLED_TIME"), false)); + DisabledDB = dynamic_cast(root->getNode(ICDBNode::CTextId("DISABLED"), false)); } - // get the Node leaves to be tested each frame - uint i= 0; - for(;;) + if (Ctrl) { - string db= toString("%s:%d:" DISABLE_LEAF, _DbBranchName.c_str(), i); - CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(db, false); - if(!node) + CDBGroupListSheetBonusMalus *owner = dynamic_cast(pFather); + if (owner) { - break; + _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); } - else - { - _DisableStates.push_back(node); - i++; - } - } - return true; + Ctrl->setRegenTextOutline(true); + } } // *************************************************************************** -void CDBGroupListSheetBonusMalus::draw () +void CDBGroupListSheetBonusMalus::CSheetChildTimer::update(CDBGroupListSheet * /* pFather */) { - CDBGroupListSheet::draw(); - -// CInterfaceManager *pIM= CInterfaceManager::getInstance(); -// CViewRenderer &rVR= *CViewRenderer::getInstance(); - -// sint32 drl= getRenderLayer()+1; + if(!TimerDB) + return; - // May draw disable bitmaps on the ctrl sheets if disabled. - uint numCtrls= (uint)min(_SheetChildren.size(), _DisableStates.size()); - for(uint i=0;igetValue32(); + 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 - ctrl->setGrayed(false); + { + // skill disabled timer + Ctrl->setGrayed(true); + Ctrl->setRegenTextColor(_RegenTextDisabledColor); + } + } + else + { + 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; +} + diff --git a/ryzom/client/src/interface_v3/dbgroup_list_sheet_bonus_malus.h b/ryzom/client/src/interface_v3/dbgroup_list_sheet_bonus_malus.h index 05774ec8d..d63e664ed 100644 --- a/ryzom/client/src/interface_v3/dbgroup_list_sheet_bonus_malus.h +++ b/ryzom/client/src/interface_v3/dbgroup_list_sheet_bonus_malus.h @@ -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 ¶m); - 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 _DisableStates; + bool _RegenTextEnabled; + std::string _RegenTextFct; + sint32 _RegenTextY; + uint32 _RegenTextFontSize; + NLMISC::CRGBA _RegenTextColor; + NLMISC::CRGBA _RegenTextDisabledColor; }; diff --git a/ryzom/client/src/interface_v3/group_quick_help.cpp b/ryzom/client/src/interface_v3/group_quick_help.cpp index 8a5e925cf..c8d5fdd9b 100644 --- a/ryzom/client/src/interface_v3/group_quick_help.cpp +++ b/ryzom/client/src/interface_v3/group_quick_help.cpp @@ -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 diff --git a/ryzom/client/src/interface_v3/people_list.cpp b/ryzom/client/src/interface_v3/people_list.cpp index d99089a69..246f3bc0a 100644 --- a/ryzom/client/src/interface_v3/people_list.cpp +++ b/ryzom/client/src/interface_v3/people_list.cpp @@ -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 { diff --git a/ryzom/client/src/user_entity.cpp b/ryzom/client/src/user_entity.cpp index dce3191dd..2ed7355b0 100644 --- a/ryzom/client/src/user_entity.cpp +++ b/ryzom/client/src/user_entity.cpp @@ -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 */ diff --git a/ryzom/common/src/game_share/effect_families.cpp b/ryzom/common/src/game_share/effect_families.cpp index 391626393..8d00cf200 100644 --- a/ryzom/common/src/game_share/effect_families.cpp +++ b/ryzom/common/src/game_share/effect_families.cpp @@ -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 },