From a5aa8e48a5516f00ce93e7d967fd9f076a3587dd Mon Sep 17 00:00:00 2001 From: Nimetu Date: Wed, 31 Jul 2019 20:56:55 +0300 Subject: [PATCH 01/35] Fixed: Initial image download did not become visible --HG-- branch : develop --- code/nel/src/gui/group_html.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 9e7275c07..558123ee4 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -711,7 +711,6 @@ namespace NLGUI return; } - // TODO: if no image in cache, nothing is visible finalUrl = upgradeInsecureUrl(getAbsoluteUrl(url)); // use requested url for local name (cache) @@ -719,9 +718,15 @@ namespace NLGUI LOG_DL("add to download '%s' dest '%s' img %p", finalUrl.c_str(), dest.c_str(), img); // Display cached image while downloading new - if (type != OverImage && CFile::fileExists(dest)) + if (type != OverImage) { - setImage(img, dest, type); + std::string temp = dest; + if (!CFile::fileExists(temp)) + { + // TODO: placeholder + temp = "web_del.tga"; + } + setImage(img, temp, type); setImageSize(img, style); } From 11150e6b79911a26aa54a6605b4139f77e1c54a3 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Wed, 31 Jul 2019 20:58:32 +0300 Subject: [PATCH 02/35] Changed: Switch compass to target mode after successful /tar command. --HG-- branch : develop --- .../client/src/interface_v3/action_handler_game.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/code/ryzom/client/src/interface_v3/action_handler_game.cpp b/code/ryzom/client/src/interface_v3/action_handler_game.cpp index 2f91cb9a5..3ad721809 100644 --- a/code/ryzom/client/src/interface_v3/action_handler_game.cpp +++ b/code/ryzom/client/src/interface_v3/action_handler_game.cpp @@ -53,6 +53,7 @@ #include "action_handler_tools.h" #include "../connection.h" #include "../client_chat_manager.h" +#include "group_compas.h" // Game specific includes #include "../motion/user_controls.h" @@ -2472,6 +2473,17 @@ class CAHTarget : public IActionHandler if (entity && entity->properties().selectable() && !entity->getDisplayName().empty()) { UserEntity->selection(entity->slot()); + CGroupCompas *gc = dynamic_cast(CWidgetManager::getInstance()->getElementFromId("ui:interface:compass")); + if (gc) + { + CCompassTarget ct; + ct.setType(CCompassTarget::Selection); + + gc->setActive(true); + gc->setTarget(ct); + gc->blink(); + CWidgetManager::getInstance()->setTopWindow(gc); + } } else if (!quiet) { From 923084a818e0146240d5971bee22b742af526829 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Fri, 4 May 2018 15:12:00 +0300 Subject: [PATCH 03/35] Added: Command to search and target closest user landmark. --HG-- branch : develop --- .../src/interface_v3/action_handler_game.cpp | 27 +++ .../client/src/interface_v3/group_map.cpp | 156 +++++++++++++++++- .../ryzom/client/src/interface_v3/group_map.h | 8 + 3 files changed, 186 insertions(+), 5 deletions(-) diff --git a/code/ryzom/client/src/interface_v3/action_handler_game.cpp b/code/ryzom/client/src/interface_v3/action_handler_game.cpp index 3ad721809..73b15a1d8 100644 --- a/code/ryzom/client/src/interface_v3/action_handler_game.cpp +++ b/code/ryzom/client/src/interface_v3/action_handler_game.cpp @@ -2493,6 +2493,33 @@ class CAHTarget : public IActionHandler }; REGISTER_ACTION_HANDLER (CAHTarget, "target"); +// *************************************************************************** +class CAHTargetLandmark : public IActionHandler +{ + virtual void execute (CCtrlBase * /* pCaller */, const string &Params) + { + string search = getParam(Params, "search"); + if (search.empty()) return; + + bool startsWith = false; + if (search.size() > 0 && (search[0] == '\'' || search[0] == '"') && search[0] == search[search.size()-1]) + { + startsWith = true; + search = trimQuotes(search); + } + + const std::string mapid = "ui:interface:map:content:map_content:actual_map"; + CGroupMap* cgMap = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(mapid)); + if (cgMap) + { + if (!cgMap->targetLandmarkByName(search, startsWith)) + { + CInterfaceManager::getInstance()->displaySystemInfo(CI18N::get("uiTargetErrorCmd")); + } + } + } +}; +REGISTER_ACTION_HANDLER (CAHTargetLandmark, "target_landmark"); class CAHAddShape : public IActionHandler diff --git a/code/ryzom/client/src/interface_v3/group_map.cpp b/code/ryzom/client/src/interface_v3/group_map.cpp index e9864b61b..87dbb38f5 100644 --- a/code/ryzom/client/src/interface_v3/group_map.cpp +++ b/code/ryzom/client/src/interface_v3/group_map.cpp @@ -100,6 +100,12 @@ const uint32 ISLAND_PIXEL_PER_METER = 2; static void setupFromZoom(CViewBase *pVB, CContLandMark::TContLMType t, float fMeterPerPixel); +// calculate distance (squared) between two points +static float distsqr(const CVector2f a, const CVector2f b) +{ + return pow(a.x - b.x, 2) + pow(a.y - b.y, 2); +} + // popup the landmark name dialog static void popupLandMarkNameDialog() @@ -2671,21 +2677,38 @@ void CGroupMap::updateLandMarkButton(CLandMarkButton *lmb, const CLandMarkOption } //============================================================================================================ -bool CGroupMap::filterLandmark(const ucstring &title) const +bool CGroupMap::filterLandmark(const ucstring &title, const std::vector filter, bool startsWith) const { - if (_LandmarkFilter.size() > 0) + if (filter.size() > 0) { ucstring lcTitle = toLower(title); - for(uint i = 0; i< _LandmarkFilter.size(); ++i) { - if (lcTitle.find(_LandmarkFilter[i]) == ucstring::npos) { + if (startsWith) + { + if (lcTitle.find(filter[0]) != 0) + { return false; } } + else + { + for(uint i = 0; i< filter.size(); ++i) + { + if (lcTitle.find(filter[i]) == ucstring::npos) + { + return false; + } + } + } } - return true; } +//============================================================================================================ +bool CGroupMap::filterLandmark(const ucstring &title) const +{ + return filterLandmark(title, _LandmarkFilter); +} + //============================================================================================================ void CGroupMap::addLandMark(TLandMarkButtonVect &destList, const NLMISC::CVector2f &pos, const ucstring &title, const CLandMarkOptions &options) { @@ -3186,6 +3209,129 @@ void CGroupMap::targetLandmarkResult(uint32 index) } } +//========================================================================================================= +CGroupMap::CLandMarkButton* CGroupMap::findClosestLandmark(const CVector2f ¢er, const ucstring &search, bool startsWith, const TLandMarkButtonVect &landmarks, float &closest) const +{ + CLandMarkButton *ret = NULL; + + std::vector keywords; + if (startsWith) + keywords.push_back(search); + else + splitUCString(toLower(search), ucstring(" "), keywords); + + closest = std::numeric_limits::max(); + for(TLandMarkButtonVect::const_iterator it = landmarks.begin(); it != landmarks.end(); ++it) + { + ucstring lc; + (*it)->getContextHelp(lc); + if(filterLandmark(lc, keywords, startsWith)) { + CVector2f pos; + mapToWorld(pos, (*it)->Pos); + float dist = distsqr(center, pos); + if (dist < closest) + { + ret = (*it); + closest = dist; + } + } + } + + return ret; +} + +//========================================================================================================= +CGroupMap::CLandMarkText* CGroupMap::findClosestLandmark(const CVector2f ¢er, const ucstring &search, bool startsWith, const TLandMarkTextVect &landmarks, float &closest) const +{ + CLandMarkText *ret = NULL; + + std::vector keywords; + if (startsWith) + keywords.push_back(search); + else + splitUCString(toLower(search), ucstring(" "), keywords); + + closest = std::numeric_limits::max(); + for(TLandMarkTextVect::const_iterator it = landmarks.begin(); it != landmarks.end(); ++it) + { + ucstring lc; + lc = (*it)->getText(); + if(filterLandmark(lc, keywords, startsWith)) { + CVector2f pos; + mapToWorld(pos, (*it)->Pos); + float dist = distsqr(center, pos); + if (dist < closest) + { + ret = (*it); + closest = dist; + } + } + } + + return ret; +} + +bool CGroupMap::targetLandmarkByName(const ucstring &search, bool startsWith) const +{ + CCompassTarget ct; + CLandMarkButton* lm; + float dist; + float closest = std::numeric_limits::max(); + bool found = false; + CVector2f center; + mapToWorld(center, _PlayerPos); + + lm = findClosestLandmark(center, search, startsWith, _UserLM, dist); + if (lm && dist < closest) + { + ct.setType(CCompassTarget::UserLandMark); + mapToWorld(ct.Pos, lm->Pos); + lm->getContextHelp(ct.Name); + closest = dist; + found = true; + } + + // only check other types if user landmark was not found + if (!found) + { + lm = findClosestLandmark(center, search, startsWith, _ContinentLM, dist); + if (lm && dist < closest) + { + ct.setType(CCompassTarget::ContinentLandMark); + mapToWorld(ct.Pos, lm->Pos); + lm->getContextHelp(ct.Name); + closest = dist; + found = true; + } + + CLandMarkText* lmt; + lmt = findClosestLandmark(center, search, startsWith, _ContinentText, dist); + if (lmt && dist < closest) + { + ct.setType(CCompassTarget::ContinentLandMark); + mapToWorld(ct.Pos, lmt->Pos); + ct.Name = lmt->getText(); + closest = dist; + found = true; + } + } + + if (found) + { + CInterfaceManager *im = CInterfaceManager::getInstance(); + CGroupCompas *gc = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(_CompassId)); + if (gc) + { + gc->setActive(true); + gc->setTarget(ct); + gc->blink(); + CWidgetManager::getInstance()->setTopWindow(gc); + } + } + + return found; +} + //========================================================================================================= void CGroupMap::getLandmarkPosition(const CCtrlButton *lm, NLMISC::CVector2f &worldPos) { diff --git a/code/ryzom/client/src/interface_v3/group_map.h b/code/ryzom/client/src/interface_v3/group_map.h index baf273779..ebfde5c36 100644 --- a/code/ryzom/client/src/interface_v3/group_map.h +++ b/code/ryzom/client/src/interface_v3/group_map.h @@ -192,6 +192,8 @@ public: // target the given landmark void targetLandmark(CCtrlButton *lm); void targetLandmarkResult(uint32 index); + // search matching landmark and target it. return true if landmark was targeted + bool targetLandmarkByName(const ucstring &search, bool startsWith) const; // get the world position of a landmark or return vector Null if not found void getLandmarkPosition(const CCtrlButton *lm, NLMISC::CVector2f &worldPos); @@ -551,6 +553,12 @@ private: // Test title against landmark filter bool filterLandmark(const ucstring &title) const; + bool filterLandmark(const ucstring &title, const std::vector filter, bool startsWith = false) const; + + // return closest landmark which matches (case insensitive) search string + // center position must be in world coordindates + CLandMarkButton* findClosestLandmark(const NLMISC::CVector2f ¢er, const ucstring &search, bool startsWith, const TLandMarkButtonVect &landmarks, float &closest) const; + CLandMarkText* findClosestLandmark(const NLMISC::CVector2f ¢er, const ucstring &search, bool startsWith, const TLandMarkTextVect &landmarks, float &closest) const; // update the scale depending on the window size and the user scale void updateScale(); From 39e0f4b4f24031e2391b3cb3320ce9f871310509 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Fri, 9 Aug 2019 11:08:20 +0300 Subject: [PATCH 04/35] Fixed: Invalid css width/height when using percent value --HG-- branch : develop --- code/nel/src/gui/css_style.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/code/nel/src/gui/css_style.cpp b/code/nel/src/gui/css_style.cpp index b0b536d0d..b83d14ead 100644 --- a/code/nel/src/gui/css_style.cpp +++ b/code/nel/src/gui/css_style.cpp @@ -723,6 +723,8 @@ namespace NLGUI style.Width = tmpf * style.FontSize; else if (unit == "pt") style.FontSize = tmpf / 0.75f; + else if (unit == "%") + style.Width = 0; // TODO: style.WidthRatio else style.Width = tmpf; } @@ -739,6 +741,8 @@ namespace NLGUI style.Height = tmpf * style.FontSize; else if (unit == "pt") style.FontSize = tmpf / 0.75f; + else if (unit == "%") + style.Height = 0; // TODO: style.HeightRatio else style.Height = tmpf; } @@ -755,6 +759,8 @@ namespace NLGUI style.MaxWidth = tmpf * style.FontSize; else if (unit == "pt") style.FontSize = tmpf / 0.75f; + else if (unit == "%") + style.MaxWidth = 0; // TODO: style.MaxWidthRatio else style.MaxWidth = tmpf; } @@ -771,6 +777,8 @@ namespace NLGUI style.MaxHeight = tmpf * style.FontSize; else if (unit == "pt") style.FontSize = tmpf / 0.75f; + else if (unit == "%") + style.MaxHeight = 0; // TODO: style.MaxHeightRatio else style.MaxHeight = tmpf; } From 4a15779094d987faa59d1ec568aa2e477df908ca Mon Sep 17 00:00:00 2001 From: Nimetu Date: Fri, 9 Aug 2019 14:44:33 +0300 Subject: [PATCH 05/35] Added: Right click action handler for menu item --HG-- branch : feature-closest-landmarks-menu --- code/nel/include/nel/gui/group_menu.h | 10 ++++++ code/nel/src/gui/group_menu.cpp | 48 +++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/code/nel/include/nel/gui/group_menu.h b/code/nel/include/nel/gui/group_menu.h index ecdd8aff0..51efaacb6 100644 --- a/code/nel/include/nel/gui/group_menu.h +++ b/code/nel/include/nel/gui/group_menu.h @@ -136,9 +136,13 @@ namespace NLGUI void removeLine(uint index); const std::string getActionHandler(uint lineIndex) const; const std::string getActionHandlerParam(uint lineIndex) const; + const std::string getRightClickHandler(uint lineIndex) const; + const std::string getRightClickHandlerParam(uint lineIndex) const; void setActionHandler(uint lineIndex, const std::string &ah = ""); void setActionHandlerParam(uint lineIndex, const std::string ¶ms = ""); + void setRightClickHandler(uint lineIndex, const std::string &ah = ""); + void setRightClickHandlerParam(uint lineIndex, const std::string ¶ms = ""); void openSubMenu (sint32 nb); @@ -235,6 +239,8 @@ namespace NLGUI CInterfaceGroup *Separator; std::string AHName; std::string AHParams; + std::string AHRightClick; + std::string AHRightClickParams; std::string Id; std::string Cond; // condition to know if the entry is grayed CViewBitmap *CheckBox; @@ -332,9 +338,13 @@ namespace NLGUI void deleteLine(uint index); const std::string getActionHandler(uint lineIndex) const; const std::string getActionHandlerParam(uint lineIndex) const; + const std::string getRightClickHandler(uint lineIndex) const; + const std::string getRightClickHandlerParam(uint lineIndex) const; void setActionHandler(uint lineIndex, const std::string &ah = ""); void setActionHandlerParam(uint lineIndex, const std::string ¶ms = ""); + void setRightClickHandler(uint lineIndex, const std::string &ah = ""); + void setRightClickHandlerParam(uint lineIndex, const std::string ¶ms = ""); void addLine (const ucstring &name, const std::string &ah = "", const std::string ¶ms = "", const std::string &id = std::string(), diff --git a/code/nel/src/gui/group_menu.cpp b/code/nel/src/gui/group_menu.cpp index 15a655d76..79be55110 100644 --- a/code/nel/src/gui/group_menu.cpp +++ b/code/nel/src/gui/group_menu.cpp @@ -1038,6 +1038,18 @@ namespace NLGUI } } + if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightup) + { + // If a line is selected and the line is not grayed and has right click action handler + if ((_Selected != -1) && (!_Lines[i].ViewText->getGrayed()) && !_Lines[_Selected].AHRightClick.empty()) + { + CAHManager::getInstance()->runActionHandler ( _Lines[_Selected].AHRightClick, + CWidgetManager::getInstance()->getCtrlLaunchingModal(), + _Lines[_Selected].AHRightClickParams ); + return true; + } + } + if (event.getType() == NLGUI::CEventDescriptor::mouse) { const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event; @@ -1685,6 +1697,28 @@ namespace NLGUI _Lines[lineIndex].AHParams = params; } + // ------------------------------------------------------------------------------------------------ + void CGroupSubMenu::setRightClickHandler(uint lineIndex, const std::string &ah) + { + if (lineIndex > _Lines.size()) + { + nlwarning("Bad index"); + return; + } + _Lines[lineIndex].AHRightClick = ah; + } + + // ------------------------------------------------------------------------------------------------ + void CGroupSubMenu::setRightClickHandlerParam(uint lineIndex, const std::string ¶ms) + { + if (lineIndex > _Lines.size()) + { + nlwarning("Bad index"); + return; + } + _Lines[lineIndex].AHRightClickParams = params; + } + // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::setSelectable(uint lineIndex, bool selectable) { @@ -2632,6 +2666,20 @@ namespace NLGUI _RootMenu->setActionHandlerParam(lineIndex, params); } + // ------------------------------------------------------------------------------------------------ + void CGroupMenu::setRightClickHandler(uint lineIndex, const std::string &ah) + { + if (_RootMenu) + _RootMenu->setRightClickHandler(lineIndex, ah); + } + + // ------------------------------------------------------------------------------------------------ + void CGroupMenu::setRightClickHandlerParam(uint lineIndex, const std::string ¶ms) + { + if (_RootMenu) + _RootMenu->setRightClickHandlerParam(lineIndex, params); + } + // ------------------------------------------------------------------------------------------------ void CGroupMenu::setUserGroupRight(uint line, CInterfaceGroup *gr, bool ownerShip /*=true*/) { From 3c1d6a24018012628d41d3d6d10d85901951da9b Mon Sep 17 00:00:00 2001 From: Nimetu Date: Fri, 9 Aug 2019 14:51:58 +0300 Subject: [PATCH 06/35] Added: Show closest landmarks on map right-click menu --HG-- branch : feature-closest-landmarks-menu --- .../src/interface_v3/action_handler_base.cpp | 27 ++- .../client/src/interface_v3/group_map.cpp | 176 +++++++++++++++++- .../ryzom/client/src/interface_v3/group_map.h | 4 + 3 files changed, 197 insertions(+), 10 deletions(-) diff --git a/code/ryzom/client/src/interface_v3/action_handler_base.cpp b/code/ryzom/client/src/interface_v3/action_handler_base.cpp index fcb66b1bc..2fbe4c662 100644 --- a/code/ryzom/client/src/interface_v3/action_handler_base.cpp +++ b/code/ryzom/client/src/interface_v3/action_handler_base.cpp @@ -23,6 +23,7 @@ #include "nel/gui/group_container.h" #include "nel/gui/group_editbox.h" +#include "nel/gui/group_menu.h" #include "dbctrl_sheet.h" #include "interface_3d_scene.h" #include "character_3d.h" @@ -74,7 +75,31 @@ class CAHActiveMenu : public IActionHandler // open the menu if (CDBCtrlSheet::getDraggedSheet() == NULL) { - CWidgetManager::getInstance()->enableModalWindow (pCaller, getParam(Params, "menu")); + std::string menuId = getParam(Params, "menu"); + CGroupMenu *groupMenu = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(menuId)); + if (groupMenu) + { + bool pushModal; + // default = false + fromString(getParam(Params, "pushmodal"), pushModal); + + if (pushModal) + { + // if false, then close all modal window when groupMenu deactivates + bool popModal; + if (!fromString(getParam(Params, "popmodal"), popModal)) + { + popModal = true; + } + groupMenu->setCloseSubMenuUsingPopModal(popModal); + CWidgetManager::getInstance()->pushModalWindow(pCaller, groupMenu); + } + else + { + groupMenu->setCloseSubMenuUsingPopModal(false); + CWidgetManager::getInstance()->enableModalWindow(pCaller, groupMenu); + } + } } } }; diff --git a/code/ryzom/client/src/interface_v3/group_map.cpp b/code/ryzom/client/src/interface_v3/group_map.cpp index 174ef45f7..864b0fe17 100644 --- a/code/ryzom/client/src/interface_v3/group_map.cpp +++ b/code/ryzom/client/src/interface_v3/group_map.cpp @@ -2654,6 +2654,9 @@ static void hideTeleportButtonsInPopupMenuIfNotEnoughPriv() ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:user_land_mark_menu:lmteleport"); if(ie) ie->setActive(showTeleport); + + ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:user_land_mark_menu_base:lmteleport"); + if(ie) ie->setActive(showTeleport); } //============================================================================================================ @@ -2717,8 +2720,8 @@ CGroupMap::CLandMarkButton *CGroupMap::createLandMarkButton(const CLandMarkOptio lmb->setModulateGlobalColorAll(false); if (!options.LandMarkMenu.empty()) { - lmb->setActionOnRightClick("active_menu"); - lmb->setParamsOnRightClick(NLMISC::toString("menu=%s", options.LandMarkMenu.c_str())); + lmb->setActionOnRightClick("world_map_right_click"); + lmb->setParamsOnRightClick(NLMISC::toString("map=%s|menu=%s", _Id.c_str(), options.LandMarkMenu.c_str())); } lmb->setPosRef(Hotspot_MM); return lmb; @@ -2853,6 +2856,23 @@ CCtrlButton *CGroupMap::addUserLandMark(const NLMISC::CVector2f &pos, const ucst return _UserLM.back(); } +//============================================================================================================ +CCtrlButton* CGroupMap::getLandmarkCtrl(const std::string &lmType, uint lmIndex) const +{ + CCtrlButton *ctrl = NULL; + if (lmType == "user") + { + if (lmIndex < _UserLM.size()) + { + ctrl = _UserLM[lmIndex]; + } + else nlwarning("_UserLM index out of bounds (size:%u, index:%u)", (uint)_UserLM.size(), lmIndex); + } + else nlwarning("unsupported landmark type '%s'", lmType.c_str()); + + return ctrl; +} + //============================================================================================================ void CGroupMap::removeUserLandMark(CCtrlButton *button) { @@ -3575,6 +3595,126 @@ int CGroupMap::luaIsIsland(CLuaState &ls) // ACTION HANDLERS // ///////////////////// +//========================================================================================================= +void CGroupMap::updateClosestLandMarkMenu(const std::string &menu, const NLMISC::CVector2f &pos) const +{ + static uint nbShowLandmarks = 5; + static uint nbShowLandmarksMax = 5; + + const CGroupMenu *pMenu = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(menu)); + if (!pMenu) return; + + CGroupSubMenu *rootMenu = pMenu->getRootMenu(); + if (!rootMenu) return; + + // remove previous markers from menu + for(uint i = 0; i < nbShowLandmarksMax; ++i) + { + std::string lineId = toString("%s:lmcosest%d", menu.c_str(), i); + sint index = rootMenu->getLineFromId(lineId); + if (index < 0) break; + rootMenu->removeLine(index); + } + + // no continent selected (ie world map view) + if (!_CurContinent) return; + + // sort landmarks, keep indices + typedef std::pair TSortedDistPair; + std::vector sortedIndices; + for(uint i = 0; i < _CurContinent->UserLandMarks.size(); ++i) + { + float dist = distsqr(pos, _CurContinent->UserLandMarks[i].Pos); + if (sortedIndices.empty()) + { + sortedIndices.push_back(TSortedDistPair(i, dist)); + } + else + { + bool found = false; + for(uint j = 0; j< sortedIndices.size(); j++) + { + if (dist < sortedIndices[j].second) + { + sortedIndices.insert(sortedIndices.begin() + j, TSortedDistPair(i, dist)); + found = true; + if (sortedIndices.size() > nbShowLandmarks) + { + sortedIndices.pop_back(); + } + break; + } + } + + if (!found && sortedIndices.size() < nbShowLandmarks) + { + sortedIndices.push_back(TSortedDistPair(i, dist)); + } + } + } + + // add landmarks to menu + uint lineIndex = rootMenu->getNumLines(); + for(uint i = 0; i< sortedIndices.size(); ++i) + { + uint32 index = sortedIndices[i].first; + ucstring name = ucstring(toString("%.2fm ", sqrt(sortedIndices[i].second))) + _CurContinent->UserLandMarks[index].Title; + std::string lineId = toString("%s:lmcosest%d", menu.c_str(), i); + std::string ahParams = toString("type=user|map=%s|index=%d", _Id.c_str(), index); + + CViewTextMenu* vt = rootMenu->addLine(ucstring(""), "map_landmark_by_index", ahParams, lineId.c_str(), "", "", false, false, false); + if (!vt) break; + + vt->setSingleLineTextFormatTaged(name); + // TODO: should calculate from mouse pos and client width + vt->setLineMaxW(800); + + CLandMarkOptions options = getUserLandMarkOptions(index); + + typedef std::pair TTmplParams; + std::vector vparams; + vparams.push_back(TTmplParams("id", toString("lmicon%d", i))); + vparams.push_back(TTmplParams("sizeref", "")); + vparams.push_back(TTmplParams("icon_texture", options.LandMarkTexNormal)); + vparams.push_back(TTmplParams("icon_color", options.ColorNormal.toString())); + + CInterfaceGroup *pUGLeft = CWidgetManager::getInstance()->getParser()->createGroupInstance("landmark_row_icon", lineId, vparams); + if (pUGLeft) + rootMenu->setUserGroupLeft(lineIndex, pUGLeft, true); + + rootMenu->setRightClickHandler(lineIndex, "map_landmark_by_index"); + rootMenu->setRightClickHandlerParam(lineIndex, toString("%s|menu=%s_base", ahParams.c_str(), options.LandMarkMenu.c_str())); + lineIndex++; + } +} + +//========================================================================================================= +// remap caller with landmark using index/type and call popup menu or set compass target if no menu is set +class CAHMapLandmarkByIndex : public IActionHandler +{ + virtual void execute (CCtrlBase* pCaller, const string ¶ms ) + { + const std::string mapName = getParam(params, "map"); + const std::string lmType = getParam(params, "type"); + const std::string menuId = getParam(params, "menu"); + uint index; + if (!fromString(getParam(params, "index"), index)) return; + + CGroupMap *map = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(mapName)); + if (!map) return; + + // remap caller to landmark from menu row + CCtrlButton* pButton = map->getLandmarkCtrl(lmType, index); + if (!pButton) return; + + if (menuId.empty()) + map->targetLandmark(pButton); + else + CAHManager::getInstance()->runActionHandler("active_menu", pButton, toString("pushmodal=true|popmodal=false|menu=%s", menuId.c_str())); + } +}; +REGISTER_ACTION_HANDLER(CAHMapLandmarkByIndex, "map_landmark_by_index"); + //========================================================================================================= // Set landmark filter class CAHLandMarkFilter : public IActionHandler @@ -3879,23 +4019,41 @@ class CAHWorldMapRightClick : public IActionHandler virtual void execute (CCtrlBase *pCaller, const string ¶ms) { std::string map = getParam(params, "map"); - CInterfaceManager *im = CInterfaceManager::getInstance(); + std::string menu = getParam(params, "menu"); hideTeleportButtonsInPopupMenuIfNotEnoughPriv(); CGroupMap *gm = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(map)); if (!gm) return; - if (!gm->isIsland()) + + if (gm->isIsland()) { - CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu=ui:interface:map_menu"); + if (gm->getArkPowoMode() == "editor") + menu = gm->getArkPowoMapMenu(); + else + menu = "ui:interface:map_menu_island"; } else { - if (gm->getArkPowoMode() == "editor") - CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu="+gm->getArkPowoMapMenu()); - else - CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu=ui:interface:map_menu_island"); + if (menu.empty()) + menu = "ui:interface:map_menu"; + + // update menu with closest landmarks + NLMISC::CVector2f pos(NLMISC::CVector2f::Null); + CCtrlButton *button = dynamic_cast(pCaller); + if (button) + gm->getLandmarkPosition(button, pos); + + if(pos == NLMISC::CVector2f::Null) + { + pos = gm->getRightClickLastPos(); + gm->mapToWorld(pos, pos); + } + + gm->updateClosestLandMarkMenu(menu, pos); } + + CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu=" + menu); } }; REGISTER_ACTION_HANDLER(CAHWorldMapRightClick, "world_map_right_click") diff --git a/code/ryzom/client/src/interface_v3/group_map.h b/code/ryzom/client/src/interface_v3/group_map.h index 57ccdcd7b..433718bb5 100644 --- a/code/ryzom/client/src/interface_v3/group_map.h +++ b/code/ryzom/client/src/interface_v3/group_map.h @@ -199,6 +199,8 @@ public: float getScale() const { return _UserScale; } /// add a user landmark (returns a pointer on its button).Coordinate are in the current map (not world coordinates) CCtrlButton *addUserLandMark(const NLMISC::CVector2f &pos, const ucstring &title, const CUserLandMark::EUserLandMarkType lmType); + /// return current continent landmark by its index and type + CCtrlButton* getLandmarkCtrl(const std::string &lmType, uint lmIndex) const; // remove a user landmark from a pointer on its button void removeUserLandMark(CCtrlButton *button); // update a user landmark from a pointer on its button @@ -293,6 +295,8 @@ public: bool isIsland() const { return _IsIsland; } + void updateClosestLandMarkMenu(const std::string &menu, const NLMISC::CVector2f &pos) const; + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private: // A non rectangular button to click on zone of the map From cc437ef7a93cdf33c1217b3847daf74dff29103a Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:37:05 +0300 Subject: [PATCH 07/35] Changed: Use external browser css file. --HG-- branch : html-improvements --- code/nel/include/nel/gui/group_html.h | 5 ++ code/nel/src/gui/group_html.cpp | 77 ++++++++++++--------------- 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/code/nel/include/nel/gui/group_html.h b/code/nel/include/nel/gui/group_html.h index d448b9d5f..fa5ddb9b2 100644 --- a/code/nel/include/nel/gui/group_html.h +++ b/code/nel/include/nel/gui/group_html.h @@ -539,6 +539,11 @@ namespace NLGUI // IL mode bool _LI; + // style from browser.css + CCssStyle _BrowserStyle; + // local file for browser.css + std::string _BrowserCssFile; + // Keep track of current element style CCssStyle _Style; CHtmlElement _HtmlDOM; diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 558123ee4..044ab8b77 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -1493,6 +1493,9 @@ namespace NLGUI initImageDownload(); initBnpDownload(); + + // setup default browser style + setProperty("browser_css_file", "browser.css"); } // *************************************************************************** @@ -1771,6 +1774,11 @@ namespace NLGUI { return toString( _TimeoutValue ); } + else + if( name == "browser_css_file" ) + { + return _BrowserCssFile; + } else return CGroupScrollText::getProperty( name ); } @@ -2144,6 +2152,24 @@ namespace NLGUI _TimeoutValue = d; return; } + else + if( name == "browser_css_file") + { + _BrowserStyle.reset(); + _BrowserCssFile = value; + if (!_BrowserCssFile.empty()) + { + std::string filename = CPath::lookup(_BrowserCssFile, false, true, true); + if (!filename.empty()) + { + NLMISC::CSString css; + if (css.readFromFile(filename)) + { + _BrowserStyle.parseStylesheet(css); + } + } + } + } else CGroupScrollText::setProperty( name, value ); } @@ -2217,6 +2243,7 @@ namespace NLGUI xmlSetProp( node, BAD_CAST "browse_redo", BAD_CAST _BrowseRedoButton.c_str() ); xmlSetProp( node, BAD_CAST "browse_refresh", BAD_CAST _BrowseRefreshButton.c_str() ); xmlSetProp( node, BAD_CAST "timeout", BAD_CAST toString( _TimeoutValue ).c_str() ); + xmlSetProp( node, BAD_CAST "browser_css_file", BAD_CAST _BrowserCssFile.c_str() ); return node; } @@ -2400,6 +2427,12 @@ namespace NLGUI if(ptr) fromString((const char*)ptr, _TimeoutValue); + ptr = xmlGetProp (cur, (xmlChar*)"browser_css_file"); + if (ptr) + { + setProperty("browser_css_file", (const char *)ptr); + } + return true; } @@ -4895,49 +4928,7 @@ namespace NLGUI _WaitingForStylesheet = false; _StylesheetQueue.clear(); _Style.reset(); - - std::string css; - - // TODO: browser css - css += "html { background-color: " + getRGBAString(BgColor) + "; color: " + getRGBAString(TextColor) + "; font-size: " + toString(TextFontSize) + "px;}"; - css += "a { color: " + getRGBAString(LinkColor) + "; text-decoration: underline; -ryzom-modulate-color: "+toString(LinkColorGlobalColor)+";}"; - css += "h1 { color: " + getRGBAString(H1Color) + "; font-size: "+ toString("%d", H1FontSize) + "px; -ryzom-modulate-color: "+toString(H1ColorGlobalColor)+";}"; - css += "h2 { color: " + getRGBAString(H2Color) + "; font-size: "+ toString("%d", H2FontSize) + "px; -ryzom-modulate-color: "+toString(H2ColorGlobalColor)+";}"; - css += "h3 { color: " + getRGBAString(H3Color) + "; font-size: "+ toString("%d", H3FontSize) + "px; -ryzom-modulate-color: "+toString(H3ColorGlobalColor)+";}"; - css += "h4 { color: " + getRGBAString(H4Color) + "; font-size: "+ toString("%d", H4FontSize) + "px; -ryzom-modulate-color: "+toString(H4ColorGlobalColor)+";}"; - css += "h5 { color: " + getRGBAString(H5Color) + "; font-size: "+ toString("%d", H5FontSize) + "px; -ryzom-modulate-color: "+toString(H5ColorGlobalColor)+";}"; - css += "h6 { color: " + getRGBAString(H6Color) + "; font-size: "+ toString("%d", H6FontSize) + "px; -ryzom-modulate-color: "+toString(H6ColorGlobalColor)+";}"; - css += "input[type=\"text\"] { color: " + getRGBAString(TextColor) + "; font-size: " + toString("%d", TextFontSize) + "px; font-weight: normal; text-shadow: 1px 1px #000;}"; - css += "pre { font-family: monospace;}"; - // th { text-align: center; } - overwrites align property - css += "th { font-weight: bold; }"; - css += "textarea { color: " + getRGBAString(TextColor) + "; font-weight: normal; font-size: " + toString("%d", TextFontSize) + "px; text-shadow: 1px 1px #000;}"; - css += "del { text-decoration: line-through;}"; - css += "u { text-decoration: underline;}"; - css += "em { font-style: italic; }"; - css += "strong { font-weight: bold; }"; - css += "small { font-size: smaller;}"; - css += "dt { font-weight: bold; }"; - css += "hr { color: rgb(120, 120, 120);}"; - // block level elements - css += "address, article, aside, blockquote, details, dialog, dd, div, dl, dt, fieldset, figcaption, figure,"; - css += "footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, li, main, nav, ol, p, pre, section, table,"; - css += "ul { display: block; }"; - css += "table { display: table; }"; - // td { padding: 1px;} - overwrites cellpadding attribute - // table { border-spacing: 2px;} - overwrites cellspacing attribute - css += "table { border-collapse: separate;}"; - // webkit pseudo elements - css += "meter::-webkit-meter-bar, meter::-webkit-optimum-value, meter::-webkit-suboptimum-value, meter::-webkit-even-less-good-value { background: none; }"; - css += "meter::-webkit-meter-bar { background-color: rgb(100, 100, 100); width: 5em; height: 1em;}"; - css += "meter::-webkit-meter-optimum-value { background-color: rgb(80, 220, 80); }"; - css += "meter::-webkit-meter-suboptimum-value { background-color: rgb(220, 220, 80); }"; - css += "meter::-webkit-meter-even-less-good-value { background-color: rgb(220, 80, 80); }"; - // webkit pseudo elements - css += "progress::-webkit-progress-bar, progress::-webkit-progress-value { background: none; }"; - css += "progress::-webkit-progress-bar { background-color: rgb(230, 230, 230); width: 10em; height: 1em; }"; - css += "progress::-webkit-progress-value { background-color: rgb(0, 100, 180);}"; - _Style.parseStylesheet(css); + _Style = _BrowserStyle; } // *************************************************************************** From 379a7f0e98450042ddd54e3aee3d5e7702e7b133 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:37:08 +0300 Subject: [PATCH 08/35] Changed: Ignore UI fontsize coef setting for html content. --HG-- branch : html-improvements --- code/nel/include/nel/gui/group_menu.h | 3 ++- code/nel/src/gui/group_html.cpp | 5 ++--- code/nel/src/gui/group_menu.cpp | 8 +++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/code/nel/include/nel/gui/group_menu.h b/code/nel/include/nel/gui/group_menu.h index cfe91f7f9..2adb11b64 100644 --- a/code/nel/include/nel/gui/group_menu.h +++ b/code/nel/include/nel/gui/group_menu.h @@ -352,7 +352,7 @@ namespace NLGUI void setMinH(sint32 minH); // change fontsize for new menu items - void setFontSize(uint32 fontSize); + void setFontSize(uint32 fontSize, bool coef = true); // Gray a line on the RootMenu void setGrayedLine(uint line, bool g); @@ -392,6 +392,7 @@ namespace NLGUI bool _Formatted; uint8 _Space; sint32 _FontSize; + bool _FontSizeCoef; NLMISC::CRGBA _ColorOver; // Color of the text when the mouse is over it NLMISC::CRGBA _ShadowColorOver; // Color of the shadow when the mouse is over it diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 044ab8b77..ad498651f 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -433,10 +433,9 @@ namespace NLGUI { if (pVT) { - pVT->setFontSize(style.FontSize); pVT->setColor(style.TextColor); pVT->setFontName(style.FontFamily); - pVT->setFontSize(style.FontSize); + pVT->setFontSize(style.FontSize, false); pVT->setEmbolden(style.FontWeight >= FONT_WEIGHT_BOLD); pVT->setOblique(style.FontOblique); pVT->setUnderlined(style.Underlined); @@ -6465,7 +6464,7 @@ namespace NLGUI sb->setMinH(_Style.Current.Height); sb->setMaxVisibleLine(size); - sb->setFontSize(_Style.Current.FontSize); + sb->setFontSize(_Style.Current.FontSize, false); } entry.SelectBox = sb; diff --git a/code/nel/src/gui/group_menu.cpp b/code/nel/src/gui/group_menu.cpp index d8b3452ed..f18e46d05 100644 --- a/code/nel/src/gui/group_menu.cpp +++ b/code/nel/src/gui/group_menu.cpp @@ -1221,7 +1221,7 @@ namespace NLGUI pV->setText (name); } pV->setColor (_GroupMenu->_Color); - pV->setFontSize (_GroupMenu->_FontSize); + pV->setFontSize (_GroupMenu->_FontSize, _GroupMenu->_FontSizeCoef); pV->setShadow (_GroupMenu->_Shadow); pV->setShadowOutline (_GroupMenu->_ShadowOutline); pV->setCheckable(checkable); @@ -1310,7 +1310,7 @@ namespace NLGUI } pV->setColor (_GroupMenu->_Color); - pV->setFontSize (_GroupMenu->_FontSize); + pV->setFontSize (_GroupMenu->_FontSize, _GroupMenu->_FontSizeCoef); pV->setShadow (_GroupMenu->_Shadow); pV->setShadowOutline (_GroupMenu->_ShadowOutline); pV->setCheckable(checkable); @@ -1968,6 +1968,7 @@ namespace NLGUI _ShadowColorGrayed = CRGBA::Black; _HighLightOver.set(128, 0, 0, 255); _FontSize = 12; + _FontSizeCoef = true; _Shadow = false; _ShadowOutline = false; _ResizeFromChildH = _ResizeFromChildW = true; @@ -2562,9 +2563,10 @@ namespace NLGUI } // ------------------------------------------------------------------------------------------------ - void CGroupMenu::setFontSize(uint fontSize) + void CGroupMenu::setFontSize(uint fontSize, bool coef) { _FontSize = fontSize; + _FontSizeCoef = coef; } // ------------------------------------------------------------------------------------------------ From 72b6d1e4c5493d1f72c92976d01e089da4c4d7b7 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:37:23 +0300 Subject: [PATCH 09/35] Fixed: Move tr elements directly under table into tbody --HG-- branch : html-improvements --- code/nel/src/gui/group_html.cpp | 4 ++++ code/nel/src/gui/html_parser.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index ad498651f..5bd258209 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -1143,8 +1143,10 @@ namespace NLGUI case HTML_STRONG: renderPseudoElement(":before", elm); break; case HTML_STYLE: htmlSTYLE(elm); break; case HTML_TABLE: htmlTABLE(elm); break; + case HTML_TBODY: renderPseudoElement(":before", elm); break; case HTML_TD: htmlTD(elm); break; case HTML_TEXTAREA: htmlTEXTAREA(elm); break; + case HTML_TFOOT: renderPseudoElement(":before", elm); break; case HTML_TH: htmlTH(elm); break; case HTML_TITLE: htmlTITLE(elm); break; case HTML_TR: htmlTR(elm); break; @@ -1205,7 +1207,9 @@ namespace NLGUI case HTML_STYLE: htmlSTYLEend(elm); break; 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_TFOOT: renderPseudoElement(":after", elm); break; case HTML_TH: htmlTHend(elm); break; case HTML_TITLE: htmlTITLEend(elm); break; case HTML_TR: htmlTRend(elm); break; diff --git a/code/nel/src/gui/html_parser.cpp b/code/nel/src/gui/html_parser.cpp index 1c5914bb5..3d7303706 100644 --- a/code/nel/src/gui/html_parser.cpp +++ b/code/nel/src/gui/html_parser.cpp @@ -190,6 +190,35 @@ namespace NLGUI elm.reindexChilds(); parent.reindexChilds(); } + + // move all directly under to its own ("table > tbody > tr" selector). + // TODO: move first real to front, move first real at the end + if (elm.ID == HTML_TABLE) + { + std::list::iterator it = elm.Children.begin(); + std::list::iterator tbody = elm.Children.end(); + for(it = elm.Children.begin(); it != elm.Children.end(); ++it) + { + if (it->ID == HTML_TR) + { + if (tbody == elm.Children.end()) + { + tbody = elm.Children.insert(it, CHtmlElement(CHtmlElement::ELEMENT_NODE, "tbody")); + tbody->ID = HTML_TBODY; + tbody->parent = &elm; + } + tbody->Children.splice(tbody->Children.end(), elm.Children, it); + it = tbody; + } + else if (tbody != elm.Children.end()) + { + tbody->reindexChilds(); + tbody = elm.Children.end(); + } + } + + elm.reindexChilds(); + } } } From ecc658703c19dee057e2b00482ee73258c058015 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:37:33 +0300 Subject: [PATCH 10/35] Fixed: Table cell background should be on top-left with no overflow. --HG-- branch : html-improvements --- code/nel/include/nel/gui/group_table.h | 9 ++++ code/nel/src/gui/group_table.cpp | 64 +++++++++++++++++--------- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/code/nel/include/nel/gui/group_table.h b/code/nel/include/nel/gui/group_table.h index 2be9ef98c..20900228b 100644 --- a/code/nel/include/nel/gui/group_table.h +++ b/code/nel/include/nel/gui/group_table.h @@ -96,6 +96,11 @@ namespace NLGUI bool _UserTexture; bool _TextureTiled; bool _TextureScaled; + // cached absolute coords for background texture + sint32 _TextureXReal; + sint32 _TextureYReal; + sint32 _TextureWReal; + sint32 _TextureHReal; // Alignment TAlign Align; @@ -112,10 +117,14 @@ namespace NLGUI void setTextureTile(bool tiled); void setTextureScale(bool scaled); + virtual void updateCoords(); + static void setDebugUICell( bool d ){ DebugUICell = d; } static bool getDebugUICell(){ return DebugUICell; } private: + void updateTextureCoords(); + void setEnclosedGroupDefaultParams(); static bool DebugUICell; }; diff --git a/code/nel/src/gui/group_table.cpp b/code/nel/src/gui/group_table.cpp index 45c3b7e1e..d703f941a 100644 --- a/code/nel/src/gui/group_table.cpp +++ b/code/nel/src/gui/group_table.cpp @@ -62,6 +62,10 @@ namespace NLGUI _UserTexture = false; _TextureTiled = false; _TextureScaled = false; + _TextureXReal = 0; + _TextureYReal = 0; + _TextureWReal = 0; + _TextureHReal = 0; setEnclosedGroupDefaultParams(); addGroup (Group); } @@ -492,36 +496,23 @@ namespace NLGUI col = CRGBA(255,255,255,255); else col = BgColor; - - + + sint32 oldSciX, oldSciY, oldSciW, oldSciH; + makeNewClip (oldSciX, oldSciY, oldSciW, oldSciH); + if (_TextureScaled && !_TextureTiled) { - rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, - _WReal, _HReal, - 0, false, - _TextureId, - col ); + rVR.drawRotFlipBitmap(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _HReal, 0, false, _TextureId, col); } else { if (!_TextureTiled) - { - rVR.draw11RotFlipBitmap (_RenderLayer, _XReal, _YReal, - 0, false, - _TextureId, - col); - } + rVR.drawRotFlipBitmap(_RenderLayer, _TextureXReal, _TextureYReal, _TextureWReal, _TextureHReal, 0, false, _TextureId, col); else - { - rVR.drawRotFlipBitmapTiled(_RenderLayer, _XReal, _YReal, - _WReal, _HReal, - 0, false, - _TextureId, - 0, - col); - } + rVR.drawRotFlipBitmapTiled(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _TextureHReal, 0, false, _TextureId, 0, col); } - + + restoreClip (oldSciX, oldSciY, oldSciW, oldSciH); } else { @@ -534,7 +525,7 @@ namespace NLGUI CGroupTable *table = static_cast (getParent ()); finalColor.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) finalColor.A) >> 8); } - + //nlinfo("Blank Texture"); rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor); } @@ -592,6 +583,8 @@ namespace NLGUI nlinfo("Set texture to cell : %s", TxName.c_str()); _UserTexture = true; _TextureId.setTexture (TxName.c_str (), 0, 0, -1, -1, false); + + updateTextureCoords(); } } @@ -611,6 +604,31 @@ namespace NLGUI _TextureScaled = scaled; } + // ---------------------------------------------------------------------------- + void CGroupCell::updateTextureCoords() + { + if (_TextureId < 0) return; + + CViewRenderer &rVR = *CViewRenderer::getInstance(); + rVR.getTextureSizeFromId (_TextureId, _TextureWReal, _TextureHReal); + + _TextureXReal = _XReal; + _TextureYReal = _YReal + _HReal - _TextureHReal; + if (_TextureTiled && _TextureHReal > 0) + { + sint diff = (_HReal / _TextureHReal) * _TextureHReal; + _TextureYReal -= diff; + _TextureHReal += diff; + } + } + + // ---------------------------------------------------------------------------- + void CGroupCell::updateCoords() + { + CInterfaceGroup::updateCoords(); + + updateTextureCoords(); + } // ---------------------------------------------------------------------------- NLMISC_REGISTER_OBJECT(CViewBase, CGroupTable, std::string, "table"); From 2dee4e41ea53f4504011a05305cbbc532ebb5bc2 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:37:54 +0300 Subject: [PATCH 11/35] Added: background-image for tables --HG-- branch : html-improvements --- code/nel/include/nel/gui/group_table.h | 17 ++++++ code/nel/src/gui/group_html.cpp | 62 +++++++++++++++------- code/nel/src/gui/group_table.cpp | 72 +++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 21 deletions(-) diff --git a/code/nel/include/nel/gui/group_table.h b/code/nel/include/nel/gui/group_table.h index 20900228b..f3f6478d6 100644 --- a/code/nel/include/nel/gui/group_table.h +++ b/code/nel/include/nel/gui/group_table.h @@ -164,6 +164,10 @@ namespace NLGUI bool ContinuousUpdate; + void setTexture(const std::string & TxName); + void setTextureTile(bool tiled); + void setTextureScale(bool scaled); + std::string getProperties( const std::string &name ) const; void setProperty( const std::string &name, const std::string &value ); xmlNodePtr serialize( xmlNodePtr parentNode, const char *type ) const; @@ -185,6 +189,19 @@ namespace NLGUI virtual bool parse (xmlNodePtr cur, CInterfaceGroup * parentGroup); + // Texture + CViewRenderer::CTextureId _TextureId; + bool _UserTexture; + bool _TextureTiled; + bool _TextureScaled; + // cached absolute coords for background texture + sint32 _TextureXReal; + sint32 _TextureYReal; + sint32 _TextureWReal; + sint32 _TextureHReal; + + void updateTextureCoords(); + // Content validated bool _ContentValidated; diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 5bd258209..596b663f1 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -286,28 +286,38 @@ namespace NLGUI { btn->setTextureOver(file); } + + return; } - else + + CViewBitmap *btm = dynamic_cast(view); + if(btm) { - CViewBitmap *btm = dynamic_cast(view); - if(btm) - { - btm->setTexture (file); - btm->invalidateCoords(); - btm->invalidateContent(); - paragraphChange(); - } - else - { - CGroupCell *btgc = dynamic_cast(view); - if(btgc) - { - btgc->setTexture (file); - btgc->invalidateCoords(); - btgc->invalidateContent(); - paragraphChange(); - } - } + btm->setTexture (file); + btm->invalidateCoords(); + btm->invalidateContent(); + paragraphChange(); + + return; + } + + CGroupCell *btgc = dynamic_cast(view); + if(btgc) + { + btgc->setTexture (file); + btgc->invalidateCoords(); + btgc->invalidateContent(); + paragraphChange(); + + return; + } + + CGroupTable *table = dynamic_cast(view); + if (table) + { + table->setTexture(file); + + return; } } @@ -6571,6 +6581,18 @@ namespace NLGUI scanHTMLColor(elm.getAttribute("bordercolor").c_str(), table->BorderColor); } + if (_Style.hasStyle("background-image")) + { + if (_Style.checkStyle("background-repeat", "repeat")) + table->setTextureTile(true); + + if (_Style.checkStyle("background-size", "100%")) + table->setTextureScale(true); + + string image = _Style.getStyle("background-image"); + addImageDownload(image, table); + } + table->setMarginLeft(getIndent()); addHtmlGroup (table, 0); diff --git a/code/nel/src/gui/group_table.cpp b/code/nel/src/gui/group_table.cpp index d703f941a..a69bae909 100644 --- a/code/nel/src/gui/group_table.cpp +++ b/code/nel/src/gui/group_table.cpp @@ -645,6 +645,13 @@ namespace NLGUI CellPadding=1; CellSpacing=2; ContinuousUpdate = false; + + _TextureTiled = false; + _TextureScaled = false; + _TextureXReal = 0; + _TextureYReal = 0; + _TextureWReal = 0; + _TextureHReal = 0; } // ---------------------------------------------------------------------------- @@ -712,7 +719,50 @@ namespace NLGUI _Cells.clear ();*/ } + // ---------------------------------------------------------------------------- + void CGroupTable::setTexture(const std::string & TxName) + { + if (TxName.empty() || TxName == "none") + { + _TextureId.setTexture(NULL); + } + else + { + _TextureId.setTexture (TxName.c_str (), 0, 0, -1, -1, false); + + updateTextureCoords(); + } + } + + // ---------------------------------------------------------------------------- + void CGroupTable::setTextureTile(bool tiled) + { + _TextureTiled = tiled; + } + // ---------------------------------------------------------------------------- + void CGroupTable::setTextureScale(bool scaled) + { + _TextureScaled = scaled; + } + + // ---------------------------------------------------------------------------- + void CGroupTable::updateTextureCoords() + { + if (_TextureId < 0) return; + + CViewRenderer &rVR = *CViewRenderer::getInstance(); + rVR.getTextureSizeFromId (_TextureId, _TextureWReal, _TextureHReal); + + _TextureXReal = _XReal; + _TextureYReal = _YReal + _HReal - _TextureHReal; + if (_TextureTiled && _TextureHReal > 0) + { + sint diff = (_HReal / _TextureHReal) * _TextureHReal; + _TextureYReal -= diff; + _TextureHReal += diff; + } + } // ---------------------------------------------------------------------------- void CGroupTable::updateCoords() @@ -1178,7 +1228,7 @@ namespace NLGUI CInterfaceGroup::updateCoords(); - + updateTextureCoords(); // Validated @@ -1360,6 +1410,26 @@ namespace NLGUI if (!_Columns.empty() && !_Rows.empty()) { + // Draw the background + if (_TextureId >= 0 && CurrentAlpha != 0) + { + CViewRenderer &rVR = *CViewRenderer::getInstance(); + + CRGBA col = CRGBA::White; + col.A = CurrentAlpha; + if (_TextureScaled && !_TextureTiled) + { + rVR.drawRotFlipBitmap(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _HReal, 0, false, _TextureId, col); + } + else + { + if (!_TextureTiled) + rVR.drawRotFlipBitmap(_RenderLayer, _TextureXReal, _TextureYReal, _TextureWReal, _TextureHReal, 0, false, _TextureId, col); + else + rVR.drawRotFlipBitmapTiled(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _TextureHReal, 0, false, _TextureId, 0, col); + } + } + sint32 border = Border + CellSpacing; if (border && BgColor.A) { From 13bdecc3aa176584370a32a7cb0d9dd83ff9c7b6 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:38:18 +0300 Subject: [PATCH 12/35] Changed: Helper functions (clear, empty) for CTextureId --HG-- branch : html-improvements --- code/nel/include/nel/gui/view_renderer.h | 6 ++++++ code/nel/src/gui/view_renderer.cpp | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/code/nel/include/nel/gui/view_renderer.h b/code/nel/include/nel/gui/view_renderer.h index 6a09a085b..1b489802f 100644 --- a/code/nel/include/nel/gui/view_renderer.h +++ b/code/nel/include/nel/gui/view_renderer.h @@ -101,6 +101,12 @@ namespace NLGUI return _TextureId; } + // Return true if TextureId is not set + bool empty() const { return _TextureId < 0; }; + + // delete TextureId if set + void clear(); + void serial(NLMISC::IStream &f); private: diff --git a/code/nel/src/gui/view_renderer.cpp b/code/nel/src/gui/view_renderer.cpp index 66da2800b..7d60f3c31 100644 --- a/code/nel/src/gui/view_renderer.cpp +++ b/code/nel/src/gui/view_renderer.cpp @@ -1932,6 +1932,16 @@ namespace NLGUI return _TextureId >= 0; } + // *************************************************************************** + void CViewRenderer::CTextureId::clear() + { + if (_TextureId >= 0) + { + CViewRenderer::getInstance()->deleteTexture(_TextureId); + _TextureId = -1; + } + } + // *************************************************************************** void CViewRenderer::CTextureId::serial(NLMISC::IStream &f) { From 26e356723eff5a05887c9e56dd6fe0cd235cb1d8 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:38:25 +0300 Subject: [PATCH 13/35] Added: CRGBA::Transparent color preset --HG-- branch : html-improvements --- code/nel/include/nel/misc/rgba.h | 1 + code/nel/src/misc/rgba.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/code/nel/include/nel/misc/rgba.h b/code/nel/include/nel/misc/rgba.h index 006b1f102..81204aca9 100644 --- a/code/nel/include/nel/misc/rgba.h +++ b/code/nel/include/nel/misc/rgba.h @@ -377,6 +377,7 @@ public: static const CRGBA Magenta ; static const CRGBA Cyan ; static const CRGBA White ; + static const CRGBA Transparent ; }; diff --git a/code/nel/src/misc/rgba.cpp b/code/nel/src/misc/rgba.cpp index 277793489..33b6c42ec 100644 --- a/code/nel/src/misc/rgba.cpp +++ b/code/nel/src/misc/rgba.cpp @@ -48,6 +48,7 @@ const CRGBA CRGBA::Blue(0, 0, 255) ; const CRGBA CRGBA::Magenta(255, 0, 255) ; const CRGBA CRGBA::Cyan(0, 255, 255) ; const CRGBA CRGBA::White(255, 255, 255) ; +const CRGBA CRGBA::Transparent(0, 0, 0, 0); // *************************************************************************** void CRGBA::serial(NLMISC::IStream &f) From 30e0018d0ad60d9fc9604bf962043212f976cb37 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:38:43 +0300 Subject: [PATCH 14/35] Fixed: Use empty placeholder for background images. --HG-- branch : html-improvements --- code/nel/include/nel/gui/group_html.h | 2 +- code/nel/src/gui/group_html.cpp | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/code/nel/include/nel/gui/group_html.h b/code/nel/include/nel/gui/group_html.h index fa5ddb9b2..31330fa51 100644 --- a/code/nel/include/nel/gui/group_html.h +++ b/code/nel/include/nel/gui/group_html.h @@ -124,7 +124,7 @@ namespace NLGUI void endParagraph(); // add image download (used by view_bitmap.cpp to load web images) - void addImageDownload(const std::string &url, CViewBase *img, const CStyleParams &style = CStyleParams(), const TImageType type = NormalImage); + void addImageDownload(const std::string &url, CViewBase *img, const CStyleParams &style = CStyleParams(), const TImageType type = NormalImage, const std::string &placeholder = "web_del.tga"); // remove image from download list if present void removeImageDownload(CViewBase *img); std::string localImageName(const std::string &url); diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 596b663f1..2b9ed3327 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -706,7 +706,7 @@ namespace NLGUI } // Add a image download request in the multi_curl - void CGroupHTML::addImageDownload(const string &url, CViewBase *img, const CStyleParams &style, TImageType type) + void CGroupHTML::addImageDownload(const string &url, CViewBase *img, const CStyleParams &style, TImageType type, const std::string &placeholder) { std::string finalUrl; img->setModulateGlobalColor(style.GlobalColor); @@ -732,8 +732,7 @@ namespace NLGUI std::string temp = dest; if (!CFile::fileExists(temp)) { - // TODO: placeholder - temp = "web_del.tga"; + temp = placeholder; } setImage(img, temp, type); setImageSize(img, style); @@ -3483,7 +3482,7 @@ namespace NLGUI else bitmap->setSizeRef(""); - addImageDownload(bgtex, view); + addImageDownload(bgtex, view, CStyleParams(), TImageType::NormalImage, ""); } } } @@ -6590,7 +6589,7 @@ namespace NLGUI table->setTextureScale(true); string image = _Style.getStyle("background-image"); - addImageDownload(image, table); + addImageDownload(image, table, CStyleParams(), TImageType::NormalImage, ""); } table->setMarginLeft(getIndent()); @@ -6664,7 +6663,7 @@ namespace NLGUI if (_Style.hasStyle("background-image")) { string image = _Style.getStyle("background-image"); - addImageDownload(image, _Cells.back()); + addImageDownload(image, _Cells.back(), CStyleParams(), TImageType::NormalImage, ""); } if (elm.hasNonEmptyAttribute("colspan")) From 036410af62586da00aae77526bab443eabcc24ab Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:40:11 +0300 Subject: [PATCH 15/35] Fixed: Drawing table and cell background image and modulating color from global. --HG-- branch : html-improvements --- code/nel/include/nel/gui/css_style.h | 1 + code/nel/include/nel/gui/group_table.h | 4 +- code/nel/src/gui/group_html.cpp | 28 ++++- code/nel/src/gui/group_table.cpp | 143 ++++++++++++------------- 4 files changed, 97 insertions(+), 79 deletions(-) diff --git a/code/nel/include/nel/gui/css_style.h b/code/nel/include/nel/gui/css_style.h index 0937ebe0b..dd8fa9dc6 100644 --- a/code/nel/include/nel/gui/css_style.h +++ b/code/nel/include/nel/gui/css_style.h @@ -174,6 +174,7 @@ namespace NLGUI styleStackIndex++; _StyleStack.push_back(Current); + Current.GlobalColor = false; Current.DisplayBlock = false; Current.Width=-1; Current.Height=-1; diff --git a/code/nel/include/nel/gui/group_table.h b/code/nel/include/nel/gui/group_table.h index f3f6478d6..3782ccdb6 100644 --- a/code/nel/include/nel/gui/group_table.h +++ b/code/nel/include/nel/gui/group_table.h @@ -92,8 +92,7 @@ namespace NLGUI NLMISC::CRGBA BgColor; // Texture - CViewRenderer::CTextureId _TextureId; /// Accelerator - bool _UserTexture; + CViewRenderer::CTextureId _TextureId; bool _TextureTiled; bool _TextureScaled; // cached absolute coords for background texture @@ -191,7 +190,6 @@ namespace NLGUI // Texture CViewRenderer::CTextureId _TextureId; - bool _UserTexture; bool _TextureTiled; bool _TextureScaled; // cached absolute coords for background texture diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 2b9ed3327..82724f28e 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -3450,6 +3450,7 @@ namespace NLGUI CViewBitmap *bitmap = dynamic_cast (view); if (bitmap) { + // TODO: background color should have separate bitmap from background texture // Change the background color bitmap->setColor (bgcolor); bitmap->setModulateGlobalColor(false); @@ -3472,6 +3473,7 @@ namespace NLGUI bitmap->setPosRef(Hotspot_TL); bitmap->setX(0); bitmap->setY(0); + // FIXME: renders behind container background bitmap->setRenderLayer(-2); bitmap->setScale(scale); bitmap->setTile(tile); @@ -5219,9 +5221,7 @@ namespace NLGUI { CGroupHTML::CCellParams cellParams; if (!_CellParams.empty() && inherit) - { cellParams = _CellParams.back(); - } if (_Style.hasStyle("background-color")) cellParams.BgColor = _Style.Current.BackgroundColor; @@ -6592,6 +6592,9 @@ namespace NLGUI addImageDownload(image, table, CStyleParams(), TImageType::NormalImage, ""); } + // setting ModulateGlobalColor must be after addImageDownload + if (_Style.checkStyle("-ryzom-modulate-bgcolor", "true")) + table->setModulateGlobalColor(true); table->setMarginLeft(getIndent()); addHtmlGroup (table, 0); @@ -6619,9 +6622,21 @@ namespace NLGUI // *************************************************************************** void CGroupHTML::htmlTD(const CHtmlElement &elm) { + CRGBA rowColor = CRGBA::Transparent; + // remember row color so we can blend it with cell color + if (!_CellParams.empty()) + rowColor = _CellParams.back().BgColor; + // Get cells parameters getCellsParameters(elm, true); + // if cell has own background,then it must be blended with row + if (rowColor.A > 0 && (elm.hasNonEmptyAttribute("bgcolor") || _Style.hasStyle("background-color"))) + { + if (_CellParams.back().BgColor.A < 255) + _CellParams.back().BgColor.blendFromui(rowColor, _CellParams.back().BgColor, _CellParams.back().BgColor.A); + } + if (elm.ID == HTML_TH) { if (!_Style.hasStyle("font-weight")) @@ -6691,6 +6706,11 @@ namespace NLGUI getPercentage (_Cells.back()->Height, temp, elm.getAttribute("height").c_str()); _Cells.back()->NewLine = getTR(); + + // setting ModulateGlobalColor must be after addImageDownload + if (_Style.checkStyle("-ryzom-modulate-bgcolor", "true")) + _Cells.back()->setModulateGlobalColor(true); + table->addChild (_Cells.back()); // reusing indent pushed by table @@ -6799,6 +6819,10 @@ namespace NLGUI // *************************************************************************** void CGroupHTML::htmlTR(const CHtmlElement &elm) { + // prevent inheriting background color + if (!_CellParams.empty()) + _CellParams.back().BgColor = CRGBA::Transparent; + // Get cells parameters getCellsParameters(elm, true); diff --git a/code/nel/src/gui/group_table.cpp b/code/nel/src/gui/group_table.cpp index a69bae909..a99cbddeb 100644 --- a/code/nel/src/gui/group_table.cpp +++ b/code/nel/src/gui/group_table.cpp @@ -59,7 +59,6 @@ namespace NLGUI IgnoreMaxWidth = false; IgnoreMinWidth = false; AddChildW = false; - _UserTexture = false; _TextureTiled = false; _TextureScaled = false; _TextureXReal = 0; @@ -486,16 +485,23 @@ namespace NLGUI } // Draw the background - if (_UserTexture || BgColor.A != 0) + if (BgColor.A > 0 || !_TextureId.empty()) { CViewRenderer &rVR = *CViewRenderer::getInstance(); - if (_UserTexture) + + uint8 CurrentAlpha = 255; + + if (getParent ()) { - CRGBA col; - if (BgColor.A == 0 ) - col = CRGBA(255,255,255,255); - else - col = BgColor; + CGroupTable *table = static_cast (getParent ()); + CurrentAlpha = table->CurrentAlpha; + } + + bool flush = false; + if (CurrentAlpha > 0 && !_TextureId.empty()) + { + CRGBA col = CRGBA::White; + col.A = CurrentAlpha; sint32 oldSciX, oldSciY, oldSciW, oldSciH; makeNewClip (oldSciX, oldSciY, oldSciW, oldSciH); @@ -513,22 +519,25 @@ namespace NLGUI } restoreClip (oldSciX, oldSciY, oldSciW, oldSciH); + + flush = true; } - else + + if (BgColor.A > 0) { - CRGBA finalColor; - finalColor.modulateFromColor (BgColor, CWidgetManager::getInstance()->getGlobalColor()); + CRGBA finalColor = BgColor; + if (_ModulateGlobalColor) + finalColor.modulateFromColor (finalColor, CWidgetManager::getInstance()->getGlobalColor()); + finalColor.A = (uint8) (((uint16) CurrentAlpha * (uint16) finalColor.A) >> 8); - // Get the parent table - if (getParent ()) - { - CGroupTable *table = static_cast (getParent ()); - finalColor.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) finalColor.A) >> 8); - } + if (finalColor.A > 0) + rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor); - //nlinfo("Blank Texture"); - rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor); + flush = true; } + + if (flush) + rVR.flush(); } // Get the parent table @@ -536,14 +545,14 @@ namespace NLGUI { CGroupTable *table = static_cast (getParent ()); if (table->Border) { - CRGBA lighter = blend(table->BorderColor, CRGBA::White, 0.5f); - - CRGBA borderColorTL; - borderColorTL.modulateFromColor (lighter, CWidgetManager::getInstance()->getGlobalColor()); + CRGBA borderColorTL = blend(table->BorderColor, CRGBA::White, 0.5f); + if (_ModulateGlobalColor) + borderColorTL.modulateFromColor (borderColorTL, CWidgetManager::getInstance()->getGlobalColor()); borderColorTL.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) borderColorTL.A) >> 8); - CRGBA borderColorBR; - borderColorBR.modulateFromColor (table->BorderColor, CWidgetManager::getInstance()->getGlobalColor()); + CRGBA borderColorBR = table->BorderColor; + if (_ModulateGlobalColor) + borderColorBR.modulateFromColor (borderColorBR, CWidgetManager::getInstance()->getGlobalColor()); borderColorBR.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) borderColorBR.A) >> 8); CViewRenderer &rVR = *CViewRenderer::getInstance(); @@ -575,13 +584,10 @@ namespace NLGUI { if (TxName.empty() || TxName == "none") { - _UserTexture = false; - nlinfo("Set no texture"); + _TextureId.clear(); } else { - nlinfo("Set texture to cell : %s", TxName.c_str()); - _UserTexture = true; _TextureId.setTexture (TxName.c_str (), 0, 0, -1, -1, false); updateTextureCoords(); @@ -607,7 +613,7 @@ namespace NLGUI // ---------------------------------------------------------------------------- void CGroupCell::updateTextureCoords() { - if (_TextureId < 0) return; + if (_TextureId.empty()) return; CViewRenderer &rVR = *CViewRenderer::getInstance(); rVR.getTextureSizeFromId (_TextureId, _TextureWReal, _TextureHReal); @@ -724,7 +730,7 @@ namespace NLGUI { if (TxName.empty() || TxName == "none") { - _TextureId.setTexture(NULL); + _TextureId.clear(); } else { @@ -749,7 +755,7 @@ namespace NLGUI // ---------------------------------------------------------------------------- void CGroupTable::updateTextureCoords() { - if (_TextureId < 0) return; + if (_TextureId.empty()) return; CViewRenderer &rVR = *CViewRenderer::getInstance(); rVR.getTextureSizeFromId (_TextureId, _TextureWReal, _TextureHReal); @@ -1410,13 +1416,30 @@ namespace NLGUI if (!_Columns.empty() && !_Rows.empty()) { + bool flush = false; + CViewRenderer &rVR = *CViewRenderer::getInstance(); + + if (BgColor.A > 0) + { + CRGBA finalColor = BgColor; + if (_ModulateGlobalColor) + finalColor.modulateFromColor (finalColor, CWidgetManager::getInstance()->getGlobalColor()); + finalColor.A = (uint8) (((uint16) CurrentAlpha * (uint16) finalColor.A) >> 8); + + rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor); + + flush = true; + } + // Draw the background - if (_TextureId >= 0 && CurrentAlpha != 0) + if (CurrentAlpha > 0 && !_TextureId.empty()) { - CViewRenderer &rVR = *CViewRenderer::getInstance(); + sint32 oldSciX, oldSciY, oldSciW, oldSciH; + makeNewClip (oldSciX, oldSciY, oldSciW, oldSciH); CRGBA col = CRGBA::White; col.A = CurrentAlpha; + if (_TextureScaled && !_TextureTiled) { rVR.drawRotFlipBitmap(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _HReal, 0, false, _TextureId, col); @@ -1428,53 +1451,25 @@ namespace NLGUI else rVR.drawRotFlipBitmapTiled(_RenderLayer, _TextureXReal, _TextureYReal, _WReal, _TextureHReal, 0, false, _TextureId, 0, col); } - } - sint32 border = Border + CellSpacing; - if (border && BgColor.A) - { - CRGBA finalColor; - finalColor.modulateFromColor (BgColor, CWidgetManager::getInstance()->getGlobalColor()); - finalColor.A = CurrentAlpha; - - // Draw the top line - CViewRenderer &rVR = *CViewRenderer::getInstance(); - rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal-border+_HReal, _WReal, border, 0, false, rVR.getBlankTextureId(), finalColor); - - // Draw the left line - sint32 insideHeight = std::max((sint32)0, (sint32)_HReal - (sint32)border); - rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, border, insideHeight, 0, false, rVR.getBlankTextureId(), finalColor); + restoreClip (oldSciX, oldSciY, oldSciW, oldSciH); + flush = true; + } - // Draw the inside borders - if (CellSpacing) - { - uint i; - sint32 x, y; - for (i=0; i<_Cells.size(); i++) - { - CGroupCell *cell = _Cells[i]; - - x = cell->getXReal(); - y = cell->getYReal() - CellSpacing; - // right - rVR.drawRotFlipBitmap (_RenderLayer, x + cell->getW(), y, CellSpacing, cell->getH() + CellSpacing, 0, false, rVR.getBlankTextureId(), finalColor); - // bottom - rVR.drawRotFlipBitmap (_RenderLayer, x, y, cell->getW(), CellSpacing, 0, false, rVR.getBlankTextureId(), finalColor); - } - } + // flush background color and image + if (flush) + rVR.flush(); - } if (Border) { - CViewRenderer &rVR = *CViewRenderer::getInstance(); - - CRGBA borderColorTL; - CRGBA lighter = blend(BorderColor, CRGBA::White, 0.5f); - borderColorTL.modulateFromColor (lighter, CWidgetManager::getInstance()->getGlobalColor()); + CRGBA borderColorTL = blend(BorderColor, CRGBA::White, 0.5f); + if (_ModulateGlobalColor) + borderColorTL.modulateFromColor (borderColorTL, CWidgetManager::getInstance()->getGlobalColor()); borderColorTL.A = CurrentAlpha; - CRGBA borderColorBR; - borderColorBR.modulateFromColor (BorderColor, CWidgetManager::getInstance()->getGlobalColor()); + CRGBA borderColorBR = BorderColor; + if (_ModulateGlobalColor) + borderColorBR.modulateFromColor (borderColorBR, CWidgetManager::getInstance()->getGlobalColor()); borderColorBR.A = CurrentAlpha; // beveled table border From f952202c099d8abb7b8c92a729ba0b86a35aa347 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:40:13 +0300 Subject: [PATCH 16/35] Added: Parsing css border shorthand --HG-- branch : html-improvements --- code/nel/include/nel/gui/css_style.h | 35 ++- code/nel/src/gui/css_style.cpp | 399 ++++++++++++++++++++++++--- code/nel/src/gui/group_html.cpp | 11 +- 3 files changed, 393 insertions(+), 52 deletions(-) diff --git a/code/nel/include/nel/gui/css_style.h b/code/nel/include/nel/gui/css_style.h index dd8fa9dc6..c60d123c4 100644 --- a/code/nel/include/nel/gui/css_style.h +++ b/code/nel/include/nel/gui/css_style.h @@ -27,6 +27,11 @@ namespace NLGUI typedef std::map TStyle; + // ie. border-style + enum CSSLineStyle { NONE = 0, HIDDEN, SOLID }; + // ie, border-width (px) + enum CSSLineWidth { THIN = 1, MEDIUM = 3, THICK = 5 }; + /** * \brief CSS style rules * \date 2019-03-15 10:50 GMT @@ -62,7 +67,11 @@ namespace NLGUI Height=-1; MaxWidth=-1; MaxHeight=-1; - BorderWidth=-1; + // border style + BorderTopWidth = BorderRightWidth = BorderBottomWidth = BorderLeftWidth = CSSLineWidth::MEDIUM; + BorderTopStyle = BorderRightStyle = BorderBottomStyle = BorderLeftStyle = CSSLineStyle::NONE; + BorderTopColor = BorderRightColor = BorderBottomColor = BorderLeftColor = NLMISC::CRGBA::Transparent; + // background BackgroundColor=NLMISC::CRGBA::Black; BackgroundColorOver=NLMISC::CRGBA::Black; } @@ -93,7 +102,9 @@ namespace NLGUI sint32 Height; sint32 MaxWidth; sint32 MaxHeight; - sint32 BorderWidth; + uint32 BorderTopWidth, BorderRightWidth, BorderBottomWidth, BorderLeftWidth; + CSSLineStyle BorderTopStyle, BorderRightStyle, BorderBottomStyle, BorderLeftStyle; + NLMISC::CRGBA BorderTopColor, BorderRightColor, BorderBottomColor, BorderLeftColor; NLMISC::CRGBA BackgroundColor; NLMISC::CRGBA BackgroundColorOver; @@ -106,6 +117,7 @@ namespace NLGUI class CCssStyle { public: + struct SStyleRule { std::vector Selector; TStyle Properties; @@ -148,9 +160,23 @@ namespace NLGUI // match selector to dom path bool match(const std::vector &selector, const CHtmlElement &elm) const; + // get shorthang 'top right bottom left' index values based size, ie 'padding' syntax + bool getShorthandIndices(const uint32 size, uint8 &t, uint8 &r, uint8 &b, uint8 &l) const; + + // break 'border' into 'border-top-color', 'border-top-style', etc rules + bool tryBorderWidthShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const; + bool tryBorderStyleShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const; + bool tryBorderColorShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const; + void parseBorderShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const; + // parse 'background' into 'background-color', 'background-image', etc void parseBackgroundShorthand(const std::string &value, CStyleParams &style) const; + // parse string value into corresponding value + void applyBorderWidth(const std::string &value, uint32 *dest, const uint32 currentWidth, const uint32 fontSize) const; + void applyBorderColor(const std::string &value, NLMISC::CRGBA *dest, const NLMISC::CRGBA ¤tColor, const NLMISC::CRGBA &textColor) const; + void applyLineStyle(const std::string &value, CSSLineStyle *dest, const CSSLineStyle ¤tStyle) const; + public: void reset(); @@ -180,7 +206,10 @@ namespace NLGUI Current.Height=-1; Current.MaxWidth=-1; Current.MaxHeight=-1; - Current.BorderWidth=-1; + + Current.BorderTopWidth = Current.BorderRightWidth = Current.BorderBottomWidth = Current.BorderLeftWidth = CSSLineWidth::MEDIUM; + Current.BorderTopStyle = Current.BorderRightStyle = Current.BorderBottomStyle = Current.BorderLeftStyle = CSSLineStyle::NONE; + Current.BorderTopColor = Current.BorderRightColor = Current.BorderBottomColor = Current.BorderLeftColor = Current.TextColor; Current.StyleRules.clear(); } diff --git a/code/nel/src/gui/css_style.cpp b/code/nel/src/gui/css_style.cpp index b83d14ead..72c9701df 100644 --- a/code/nel/src/gui/css_style.cpp +++ b/code/nel/src/gui/css_style.cpp @@ -338,9 +338,13 @@ namespace NLGUI // - normalize values void CCssStyle::normalize(const TStyle &styleRules, CStyleParams &style, const CStyleParams ¤t) const { + bool keep = true; TStyle::const_iterator it; for (it=styleRules.begin(); it != styleRules.end(); ++it) { + // shorthands will be replaced with proper statements and shorthand rule is removed + keep = true; + // update local copy of applied style style.StyleRules[it->first] = it->second; @@ -452,9 +456,34 @@ namespace NLGUI style.StyleRules["background-size"] = "100%"; } - TStyle::iterator pos = style.StyleRules.find(it->first); - if (pos != style.StyleRules.end()) - style.StyleRules.erase(pos); + keep = false; + } + else + if (it->first == "border" + || it->first == "border-top" || it->first == "border-right" + || it->first == "border-bottom" || it->first == "border-left") + { + // TODO: use enum or bitmap constant instead of passing a string name (it->first) + parseBorderShorthand(it->second, style, it->first); + keep = false; + } + else + if (it->first == "border-width") + { + tryBorderWidthShorthand(it->second, style, it->first); + keep = false; + } + else + if (it->first == "border-style") + { + tryBorderStyleShorthand(it->second, style, it->first); + keep = false; + } + else + if (it->first == "border-color") + { + tryBorderColorShorthand(it->second, style, it->first); + keep = false; } else if (it->first == "display") @@ -464,9 +493,91 @@ namespace NLGUI else style.DisplayBlock = (it->second == "block" || it->second == "table"); } + + if (!keep) + { + TStyle::iterator pos = style.StyleRules.find(it->first); + if (pos != style.StyleRules.end()) + style.StyleRules.erase(pos); + } } } + void CCssStyle::applyBorderWidth(const std::string &value, uint32 *dest, const uint32 currentWidth, const uint32 fontSize) const + { + if (!dest) return; + if (value == "inherit") + { + *dest = currentWidth; + } + else if (value == "thin") + { + *dest = 1; + } + else if (value == "medium") + { + *dest = 3; + } + else if (value == "thick") + { + *dest = 5; + } + else if (value == "0") + { + *dest = 0; + } + else + { + float tmpf; + std::string unit; + if (getCssLength(tmpf, unit, value.c_str())) + { + if (unit == "rem") + *dest = fontSize * tmpf; + else if (unit == "em") + *dest = fontSize * tmpf; + else if (unit == "pt") + *dest = tmpf / 0.75f; + else if (unit == "%") + *dest = 0; // no support for % in border width + else + *dest = tmpf; + } + } + } + + void CCssStyle::applyBorderColor(const std::string &value, CRGBA *dest, const CRGBA ¤tColor, const CRGBA &textColor) const + { + if (!dest) return; + + if (value == "inherit") + *dest = currentColor; + else if (value == "transparent") + *dest = CRGBA::Transparent; + else if (value == "currentcolor") + *dest = textColor; + else + scanHTMLColor(value.c_str(), *dest); + } + + void CCssStyle::applyLineStyle(const std::string &value, CSSLineStyle *dest, const CSSLineStyle ¤tStyle) const + { + if (!dest) return; + + if (value == "inherit") + *dest = currentStyle; + else if (value == "none") + *dest = CSSLineStyle::NONE; + else if (value == "hidden") + *dest = CSSLineStyle::HIDDEN; + else if (value == "inset") + *dest = CSSLineStyle::INSET; + else if (value == "outset") + *dest = CSSLineStyle::OUTSET; + else if (value == "solid") + *dest = CSSLineStyle::SOLID; + } + // apply style rules void CCssStyle::apply(CStyleParams &style, const CStyleParams ¤t) const { @@ -474,48 +585,18 @@ namespace NLGUI TStyle::const_iterator it; for (it=style.StyleRules.begin(); it != style.StyleRules.end(); ++it) { - if (it->first == "border" || it->first == "border-width") - { - // TODO: border: 1px solid red; - if (it->second == "inherit") - { - style.BorderWidth = current.BorderWidth; - } - else if (it->second == "none") - { - style.BorderWidth = 0; - } - else if (it->second == "thin") - { - style.BorderWidth = 1; - } - else if (it->second == "medium") - { - style.BorderWidth = 3; - } - else if (it->second == "thick") - { - style.BorderWidth = 5; - } - else - { - float tmpf; - std::string unit; - if (getCssLength(tmpf, unit, it->second.c_str())) - { - if (unit == "rem") - style.BorderWidth = Root.FontSize * tmpf; - else if (unit == "em") - style.BorderWidth = current.FontSize * tmpf; - else if (unit == "pt") - style.BorderWidth = tmpf / 0.75f; - else if (unit == "%") - style.BorderWidth = 0; // no support for % in border width - else - style.BorderWidth = tmpf; - } - } - } + if (it->first == "border-top-width") applyBorderWidth(it->second, &style.BorderTopWidth, current.BorderTopWidth, current.FontSize); + else if (it->first == "border-top-color") applyBorderColor(it->second, &style.BorderTopColor, current.BorderTopColor, current.TextColor); + else if (it->first == "border-top-style") applyLineStyle(it->second, &style.BorderTopStyle, current.BorderTopStyle); + else if (it->first == "border-right-width") applyBorderWidth(it->second, &style.BorderRightWidth, current.BorderRightWidth, current.FontSize); + else if (it->first == "border-right-color") applyBorderColor(it->second, &style.BorderRightColor, current.BorderRightColor, current.TextColor); + else if (it->first == "border-right-style") applyLineStyle(it->second, &style.BorderRightStyle, current.BorderRightStyle); + else if (it->first == "border-bottom-width") applyBorderWidth(it->second, &style.BorderBottomWidth, current.BorderBottomWidth, current.FontSize); + else if (it->first == "border-bottom-color") applyBorderColor(it->second, &style.BorderBottomColor, current.BorderBottomColor, current.TextColor); + else if (it->first == "border-bottom-style") applyLineStyle(it->second, &style.BorderBottomStyle, current.BorderBottomStyle); + else if (it->first == "border-left-width") applyBorderWidth(it->second, &style.BorderLeftWidth, current.BorderLeftWidth, current.FontSize); + else if (it->first == "border-left-color") applyBorderColor(it->second, &style.BorderLeftColor, current.BorderLeftColor, current.TextColor); + else if (it->first == "border-left-style") applyLineStyle(it->second, &style.BorderLeftStyle, current.BorderLeftStyle); else if (it->first == "font-style") { @@ -864,6 +945,7 @@ namespace NLGUI style.StrikeThrough = current.StrikeThrough; } + // *************************************************************************** void CCssStyle::parseBackgroundShorthand(const std::string &value, CStyleParams &style) const { // background: url(image.jpg) top center / 200px 200px no-repeat fixed padding-box content-box red; @@ -1198,6 +1280,233 @@ namespace NLGUI } } + // *************************************************************************** + bool CCssStyle::getShorthandIndices(const uint32 size, uint8 &t, uint8 &r, uint8 &b, uint8 &l) const + { + if (size == 0 || size > 4) return false; + + if (size == 1) + { + t = r = b = l = 0; + } + else if (size == 2) + { + t = b = 0; + r = l = 1; + } + else if (size == 3) + { + t = 0; + r = l = 1; + b = 2; + } + else // size == 4 + { + t = 0; + r = 1; + b = 2; + l = 3; + } + + return true; + } + + // *************************************************************************** + bool CCssStyle::tryBorderWidthShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const + { + std::vector parts; + NLMISC::splitString(toLower(value), " ", parts); + float tmpf; + std::string unit; + + // verify that parts are valid + uint8 maxSize = (prop == "border" || prop == "border-width") ? 4 : 1; + bool hasTop = (prop == "border" || prop == "border-width" || prop == "border-top" || prop == "border-top-width"); + bool hasRight = (prop == "border" || prop == "border-width" || prop == "border-right" || prop == "border-right-width"); + bool hasBottom = (prop == "border" || prop == "border-width" || prop == "border-bottom" || prop == "border-bottom-width"); + bool hasLeft = (prop == "border" || prop == "border-width" || prop == "border-left" || prop == "border-left-width"); + if (parts.size() > maxSize || (!hasTop && !hasRight && !hasBottom && !hasLeft)) + { + return false; + } + + for(uint i = 0; i< parts.size(); ++i) + { + if (parts[i] != "inherit" && parts[i] != "thin" && parts[i] != "medium" && parts[i] != "thick" + && !getCssLength(tmpf, unit, parts[i].c_str())) + { + return false; + } + } + + uint8 t, r, b, l; + if (!getShorthandIndices(parts.size(), t, r, b, l)) return false; + if (hasTop) style.StyleRules["border-top-width"] = parts[t]; + if (hasRight) style.StyleRules["border-right-width"] = parts[r]; + if (hasBottom) style.StyleRules["border-bottom-width"] = parts[b]; + if (hasLeft) style.StyleRules["border-left-width"] = parts[l]; + + return true; + } + // *************************************************************************** + bool CCssStyle::tryBorderStyleShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const + { + std::vector parts; + NLMISC::splitString(toLower(value), " ", parts); + + // verify that parts are valid + uint8 maxSize = (prop == "border" || prop == "border-style") ? 4 : 1; + bool hasTop = (prop == "border" || prop == "border-style" || prop == "border-top" || prop == "border-top-style"); + bool hasRight = (prop == "border" || prop == "border-style" || prop == "border-right" || prop == "border-right-style"); + bool hasBottom = (prop == "border" || prop == "border-style" || prop == "border-bottom" || prop == "border-bottom-style"); + bool hasLeft = (prop == "border" || prop == "border-style" || prop == "border-left" || prop == "border-left-style"); + if (parts.size() > maxSize || (!hasTop && !hasRight && !hasBottom && !hasLeft)) + { + return false; + } + + const uint nbValues = 10; + std::string values[nbValues] = {"none", "hidden", "dotted", "dashed", + "solid", "double", "groove", "ridge", "inset", "outset"}; + + for(uint i = 0; i < parts.size(); ++i) + { + bool found = false; + for(uint iValue = 0; iValue < nbValues; ++iValue) + { + if (parts[i] == values[iValue]) + { + found = true; + break; + } + } + + if (!found) + { + // invalid rule + return false; + } + } + + uint8 t, r, b, l; + if (!getShorthandIndices(parts.size(), t, r, b, l)) return false; + if (hasTop) style.StyleRules["border-top-style"] = parts[t]; + if (hasRight) style.StyleRules["border-right-style"] = parts[r]; + if (hasBottom) style.StyleRules["border-bottom-style"] = parts[b]; + if (hasLeft) style.StyleRules["border-left-style"] = parts[l]; + + return true; + } + // *************************************************************************** + bool CCssStyle::tryBorderColorShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const + { + std::vector parts; + NLMISC::splitString(toLower(value), " ", parts); + CRGBA color; + + // verify that parts are valid + uint8 maxSize = (prop == "border" || prop == "border-color") ? 4 : 1; + bool hasTop = (prop == "border" || prop == "border-color" || prop == "border-top" || prop == "border-top-color"); + bool hasRight = (prop == "border" || prop == "border-color" || prop == "border-right" || prop == "border-right-color"); + bool hasBottom = (prop == "border" || prop == "border-color" || prop == "border-bottom" || prop == "border-bottom-color"); + bool hasLeft = (prop == "border" || prop == "border-color" || prop == "border-left" || prop == "border-left-color"); + if (parts.size() > maxSize || (!hasTop && !hasRight && !hasBottom && !hasLeft)) + { + return false; + } + + for(uint i = 0; i< parts.size(); ++i) + { + if (!scanHTMLColor(parts[i].c_str(), color) && parts[i] != "currentcolor" && parts[i] != "inherit") + return false; + } + + uint8 t, r, b, l; + if (!getShorthandIndices(parts.size(), t, r, b, l)) return false; + if (hasTop) style.StyleRules["border-top-color"] = parts[t]; + if (hasRight) style.StyleRules["border-right-color"] = parts[r]; + if (hasBottom) style.StyleRules["border-bottom-color"] = parts[b]; + if (hasLeft) style.StyleRules["border-left-color"] = parts[l]; + + return true; + } + + // *************************************************************************** + void CCssStyle::parseBorderShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const + { + // border: 1px solid #000; + bool hasTop = (prop == "border" || prop == "border-top"); + bool hasRight = (prop == "border" || prop == "border-right"); + bool hasBottom = (prop == "border" || prop == "border-bottom"); + bool hasLeft = (prop == "border" || prop == "border-left"); + + bool foundWidth = false; + bool foundStyle = false; + bool foundColor = false; + + CStyleParams borderStyle; + std::vector parts; + NLMISC::splitString(toLower(value), " ", parts); + + for(uint index = 0; index < parts.size(); ++index) + { + bool matched = false; + if (!foundWidth) + { + matched = foundWidth = tryBorderWidthShorthand(parts[index], borderStyle, prop); + } + + if (!matched && !foundStyle) + { + matched = foundStyle = tryBorderStyleShorthand(parts[index], borderStyle, prop); + } + + if (!matched && !foundColor) + { + matched = foundColor = tryBorderColorShorthand(parts[index], borderStyle, prop); + } + + // invalid rule if nothing gets matched + if (!matched) + { + return; + } + } + + // apply rules that are present + TStyle::const_iterator it = borderStyle.StyleRules.begin(); + while(it != borderStyle.StyleRules.end()) + { + style.StyleRules[it->first] = it->second; + ++it; + } + + // reset those not present + if (!foundWidth) + { + if (hasTop) style.StyleRules["border-top-width"] = "medium"; + if (hasRight) style.StyleRules["border-right-width"] = "medium"; + if (hasBottom) style.StyleRules["border-bottom-width"] = "medium"; + if (hasLeft) style.StyleRules["border-left-width"] = "medium"; + } + // + if (!foundStyle) + { + if (hasTop) style.StyleRules["border-top-style"] = "none"; + if (hasRight) style.StyleRules["border-right-style"] = "none"; + if (hasBottom) style.StyleRules["border-bottom-style"] = "none"; + if (hasLeft) style.StyleRules["border-left-style"] = "none"; + } + // + if (!foundColor) + { + if (hasTop) style.StyleRules["border-top-color"] = "currentcolor"; + if (hasRight) style.StyleRules["border-right-color"] = "currentcolor"; + if (hasBottom) style.StyleRules["border-bottom-color"] = "currentcolor"; + if (hasLeft) style.StyleRules["border-left-color"] = "currentcolor"; + } + } + // *************************************************************************** void CCssStyle::applyCssMinMax(sint32 &width, sint32 &height, sint32 minw, sint32 minh, sint32 maxw, sint32 maxh) const { diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 82724f28e..b95d645f7 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -6187,7 +6187,8 @@ namespace NLGUI // width: 5em, height: 1em uint32 width = _Style.Current.Width > -1 ? _Style.Current.Width : _Style.Current.FontSize * 5; uint32 height = _Style.Current.Height > -1 ? _Style.Current.Height : _Style.Current.FontSize; - uint32 border = _Style.Current.BorderWidth > -1 ? _Style.Current.BorderWidth : 0; + // FIXME: only using border-top + uint32 border = _Style.Current.BorderTopWidth > -1 ? _Style.Current.BorderTopWidth : 0; uint barw = (uint) (width * meter.getValueRatio()); CRGBA bgColor = meter.getBarColor(elm, _Style); @@ -6402,7 +6403,8 @@ namespace NLGUI // width: 10em, height: 1em uint32 width = _Style.Current.Width > -1 ? _Style.Current.Width : _Style.Current.FontSize * 10; uint32 height = _Style.Current.Height > -1 ? _Style.Current.Height : _Style.Current.FontSize; - uint32 border = _Style.Current.BorderWidth > -1 ? _Style.Current.BorderWidth : 0; + // FIXME: only using border-top + uint32 border = _Style.Current.BorderTopWidth > -1 ? _Style.Current.BorderTopWidth : 0; uint barw = (uint) (width * progress.getValueRatio()); CRGBA bgColor = progress.getBarColor(elm, _Style); @@ -6554,9 +6556,10 @@ namespace NLGUI else if (elm.hasNonEmptyAttribute("width")) getPercentage (table->ForceWidthMin, table->TableRatio, elm.getAttribute("width").c_str()); - if (_Style.hasStyle("border") || _Style.hasStyle("border-width")) + if (_Style.hasStyle("border") || _Style.hasStyle("border-width") || _Style.hasStyle("border-top-width")) { - table->Border = _Style.Current.BorderWidth; + // FIXME: only using border-top + table->Border = _Style.Current.BorderTopWidth; } else if (elm.hasAttribute("border")) { From 19b5dd96d1b47bd3e914e201dbff8bd47ff747b4 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:41:09 +0300 Subject: [PATCH 17/35] Fixed: Missing include --HG-- branch : html-improvements --- code/nel/include/nel/gui/widget_manager.h | 1 + 1 file changed, 1 insertion(+) diff --git a/code/nel/include/nel/gui/widget_manager.h b/code/nel/include/nel/gui/widget_manager.h index 68576ce0f..518c5be16 100644 --- a/code/nel/include/nel/gui/widget_manager.h +++ b/code/nel/include/nel/gui/widget_manager.h @@ -26,6 +26,7 @@ #include "nel/misc/types_nl.h" #include "nel/gui/interface_common.h" #include "nel/gui/interface_options.h" +#include "nel/gui/interface_group.h" #include "nel/gui/event_descriptor.h" #include "nel/3d/u_camera.h" #include "nel/gui/parser.h" From 24d03e9c268d982ce725800686a6ddd871c32db1 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:41:11 +0300 Subject: [PATCH 18/35] Added: Table/cell borders with independent size and color --HG-- branch : html-improvements --- .../nel/include/nel/gui/css_border_renderer.h | 94 +++++ code/nel/include/nel/gui/css_style.h | 6 +- code/nel/include/nel/gui/css_types.h | 39 +++ code/nel/include/nel/gui/group_table.h | 11 +- code/nel/src/gui/css_border_renderer.cpp | 320 ++++++++++++++++++ code/nel/src/gui/group_html.cpp | 87 +++-- code/nel/src/gui/group_table.cpp | 143 ++++---- 7 files changed, 610 insertions(+), 90 deletions(-) create mode 100644 code/nel/include/nel/gui/css_border_renderer.h create mode 100644 code/nel/include/nel/gui/css_types.h create mode 100644 code/nel/src/gui/css_border_renderer.cpp diff --git a/code/nel/include/nel/gui/css_border_renderer.h b/code/nel/include/nel/gui/css_border_renderer.h new file mode 100644 index 000000000..41ea3b7e6 --- /dev/null +++ b/code/nel/include/nel/gui/css_border_renderer.h @@ -0,0 +1,94 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + + +#ifndef NL_CSS_BORDER_RENDERER_H +#define NL_CSS_BORDER_RENDERER_H + +#include "nel/misc/types_nl.h" +#include "nel/misc/rgba.h" +#include "nel/misc/geom_ext.h" +#include "nel/gui/css_types.h" + +namespace NLGUI +{ + /** + * \brief Border renderer for GUI classes + * \date 2019-09-03 10:50 GMT + * \author Meelis Mägi (Nimetu) + */ + class CSSBorderRenderer + { + private: + // parent element screen coordinates + sint32 _XReal, _YReal; + sint32 _WReal, _HReal; + + NLMISC::CQuadUV _QuadT; + NLMISC::CQuadUV _QuadR; + NLMISC::CQuadUV _QuadB; + NLMISC::CQuadUV _QuadL; + + uint8 _RenderLayer; + bool _ModulateGlobalColor; + + // if true, then updateCoords() is called from draw() + bool _Dirty; + // if true, then at least one border is set + bool _Border; + bool _BorderTop, _BorderRight, _BorderBottom, _BorderLeft; + + public: + uint32 TopWidth, RightWidth, BottomWidth, LeftWidth; + NLMISC::CRGBA TopColor, RightColor, BottomColor, LeftColor; + CSSLineStyle TopStyle, RightStyle, BottomStyle, LeftStyle; + + // alpha value from parent + uint8 CurrentAlpha; + + public: + CSSBorderRenderer(); + + void setRenderLayer(sint layer); + void setModulateGlobalColor(bool m); + + void setRect(sint32 x, sint32 y, sint32 w, sint32 h); + + void setWidth(uint32 top, uint32 right, uint32 bottom, uint32 left); + void setStyle(CSSLineStyle top, CSSLineStyle right, CSSLineStyle bottom, CSSLineStyle left); + void setColor(const NLMISC::CRGBA &top, const NLMISC::CRGBA &right, const NLMISC::CRGBA &bottom, const NLMISC::CRGBA &left); + + void updateCoords(); + void invalidateCoords() { _Dirty = _Border = true; } + void invalidateContent() { _Dirty = _Border = true; }; + + uint32 getTopWidth() const; + uint32 getRightWidth() const; + uint32 getBottomWidth() const; + uint32 getLeftWidth() const; + + uint32 getLeftRightWidth() const; + uint32 getTopBottomWidth() const; + + void draw(); + }; // CSSBorderRenderer + +}//namespace + +#endif // NL_CSS_BORDER_RENDERER_H + + diff --git a/code/nel/include/nel/gui/css_style.h b/code/nel/include/nel/gui/css_style.h index c60d123c4..94d86bf5d 100644 --- a/code/nel/include/nel/gui/css_style.h +++ b/code/nel/include/nel/gui/css_style.h @@ -20,6 +20,7 @@ #include "nel/misc/types_nl.h" #include "nel/misc/rgba.h" #include "nel/gui/css_selector.h" +#include "nel/gui/css_types.h" namespace NLGUI { @@ -27,11 +28,6 @@ namespace NLGUI typedef std::map TStyle; - // ie. border-style - enum CSSLineStyle { NONE = 0, HIDDEN, SOLID }; - // ie, border-width (px) - enum CSSLineWidth { THIN = 1, MEDIUM = 3, THICK = 5 }; - /** * \brief CSS style rules * \date 2019-03-15 10:50 GMT diff --git a/code/nel/include/nel/gui/css_types.h b/code/nel/include/nel/gui/css_types.h new file mode 100644 index 000000000..aa673a63e --- /dev/null +++ b/code/nel/include/nel/gui/css_types.h @@ -0,0 +1,39 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef CL_CSS_TYPES_H +#define CL_CSS_TYPES_H + +#include "nel/misc/types_nl.h" + +namespace NLGUI +{ + /** + * \brief CSS types used in GUI classes + * \date 2019-09-03 10:50 GMT + * \author Meelis Mägi (Nimetu) + */ + + // ie. border-style + enum CSSLineStyle { NONE = 0, HIDDEN, SOLID, INSET, OUTSET }; + // ie, border-width (px) + enum CSSLineWidth { THIN = 1, MEDIUM = 3, THICK = 5 }; + +}//namespace + +#endif // CL_CSS_TYPES_H + + diff --git a/code/nel/include/nel/gui/group_table.h b/code/nel/include/nel/gui/group_table.h index 3782ccdb6..e45575e47 100644 --- a/code/nel/include/nel/gui/group_table.h +++ b/code/nel/include/nel/gui/group_table.h @@ -23,9 +23,11 @@ #include "nel/gui/group_frame.h" #include "nel/gui/view_text.h" #include "nel/gui/ctrl_button.h" +#include "nel/gui/css_types.h" namespace NLGUI { + class CSSBorderRenderer; /** * This group is used to simulate HTML cells. @@ -91,6 +93,8 @@ namespace NLGUI // The cell color NLMISC::CRGBA BgColor; + CSSBorderRenderer* Border; + // Texture CViewRenderer::CTextureId _TextureId; bool _TextureTiled; @@ -151,9 +155,10 @@ namespace NLGUI // The Width you want in pixel. This is the
parameter sint32 ForceWidthMin; - // Table borders - sint32 Border; - NLMISC::CRGBA BorderColor; + CSSBorderRenderer* Border; + + // Cell has 1px solid border when
has 'border' attribute with width > 0 + bool CellBorder; sint32 CellPadding; sint32 CellSpacing; diff --git a/code/nel/src/gui/css_border_renderer.cpp b/code/nel/src/gui/css_border_renderer.cpp new file mode 100644 index 000000000..fd3ad569f --- /dev/null +++ b/code/nel/src/gui/css_border_renderer.cpp @@ -0,0 +1,320 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#include "stdpch.h" +#include "nel/gui/css_border_renderer.h" +#include "nel/gui/view_renderer.h" +#include "nel/gui/widget_manager.h" + +using namespace std; +using namespace NLMISC; + +#ifdef DEBUG_NEW +#define new DEBUG_NEW +#endif + +namespace NLGUI +{ + + + // ---------------------------------------------------------------------------- + CSSBorderRenderer::CSSBorderRenderer() + { + TopWidth = RightWidth = BottomWidth = LeftWidth = 0; + TopColor = RightColor = BottomColor = LeftColor = CRGBA(128, 128, 128, 255); + TopStyle = RightStyle = BottomStyle = LeftStyle = CSSLineStyle::SOLID; + CurrentAlpha = 255; + + _RenderLayer = 0; + _ModulateGlobalColor = false; + + _Border = true; + _Dirty = true; + _BorderTop = _BorderRight = _BorderBottom = _BorderLeft = false; + + // + _QuadT.Uv0.set(0.f, 0.f); + _QuadT.Uv1.set(0.f, 0.f); + _QuadT.Uv2.set(1.f, 1.f); + _QuadT.Uv3.set(0.f, 1.f); + // + _QuadR.Uv0.set(0.f, 0.f); + _QuadR.Uv1.set(0.f, 0.f); + _QuadR.Uv2.set(1.f, 1.f); + _QuadR.Uv3.set(0.f, 1.f); + // + _QuadB.Uv0.set(0.f, 0.f); + _QuadB.Uv1.set(0.f, 0.f); + _QuadB.Uv2.set(1.f, 1.f); + _QuadB.Uv3.set(0.f, 1.f); + // + _QuadL.Uv0.set(0.f, 0.f); + _QuadL.Uv1.set(0.f, 0.f); + _QuadL.Uv2.set(1.f, 1.f); + _QuadL.Uv3.set(0.f, 1.f); + } + + // ---------------------------------------------------------------------------- + void CSSBorderRenderer::setRenderLayer(sint layer) + { + _RenderLayer = layer; + } + + // ---------------------------------------------------------------------------- + void CSSBorderRenderer::setModulateGlobalColor(bool s) + { + _ModulateGlobalColor = s; + } + + // ---------------------------------------------------------------------------- + void CSSBorderRenderer::setRect(sint32 x, sint32 y, sint32 w, sint32 h) + { + _XReal = x; + _YReal = y; + _WReal = w; + _HReal = h; + + _Dirty = _Border = (w > 0 && h > 0); + } + + // ---------------------------------------------------------------------------- + void CSSBorderRenderer::setWidth(uint32 top, uint32 right, uint32 bottom, uint32 left) + { + TopWidth = top; + RightWidth = right; + BottomWidth = bottom; + LeftWidth = left; + + _Dirty = _Border = (top > 0 || right > 0 || bottom > 0 || left > 0); + } + + // ---------------------------------------------------------------------------- + void CSSBorderRenderer::setStyle(CSSLineStyle top, CSSLineStyle right, CSSLineStyle bottom, CSSLineStyle left) + { + TopStyle = top; + RightStyle = right; + BottomStyle = bottom; + LeftStyle = left; + + _Dirty = _Border = true; + } + + // ---------------------------------------------------------------------------- + void CSSBorderRenderer::setColor(const NLMISC::CRGBA &top, const NLMISC::CRGBA &right, const NLMISC::CRGBA &bottom, const NLMISC::CRGBA &left) + { + TopColor = top; + RightColor = right; + BottomColor = bottom; + LeftColor = left; + + _Dirty = true; + } + + // ---------------------------------------------------------------------------- + uint32 CSSBorderRenderer::getTopWidth() const + { + if (TopStyle == CSSLineStyle::NONE || TopStyle == CSSLineStyle::HIDDEN) + return 0; + + return TopWidth; + } + + // ---------------------------------------------------------------------------- + uint32 CSSBorderRenderer::getRightWidth() const + { + if (RightStyle == CSSLineStyle::NONE || RightStyle == CSSLineStyle::HIDDEN) + return 0; + + return RightWidth; + } + + // ---------------------------------------------------------------------------- + uint32 CSSBorderRenderer::getBottomWidth() const + { + if (BottomStyle == CSSLineStyle::NONE || BottomStyle == CSSLineStyle::HIDDEN) + return 0; + + return BottomWidth; + } + + // ---------------------------------------------------------------------------- + uint32 CSSBorderRenderer::getLeftWidth() const + { + if (LeftStyle == CSSLineStyle::NONE || LeftStyle == CSSLineStyle::HIDDEN) + return 0; + + return LeftWidth; + } + + // ---------------------------------------------------------------------------- + uint32 CSSBorderRenderer::getLeftRightWidth() const + { + return getLeftWidth() + getRightWidth(); + } + + // ---------------------------------------------------------------------------- + uint32 CSSBorderRenderer::getTopBottomWidth() const + { + return getTopWidth() + getBottomWidth(); + } + + // ---------------------------------------------------------------------------- + void CSSBorderRenderer::updateCoords() + { + _Dirty = false; + if (!_Border) return; + + sint dTop = getTopWidth(); _BorderTop = dTop > 0; + sint dRight = getRightWidth(); _BorderRight = dRight > 0; + sint dBottom = getBottomWidth(); _BorderBottom = dBottom > 0; + sint dLeft = getLeftWidth(); _BorderLeft = dLeft > 0; + + _Border = _BorderTop || _BorderRight || _BorderBottom || _BorderLeft; + if (!_Border) return; + + if (_BorderTop) + { + // top-left + _QuadT.V3.x = _XReal; + _QuadT.V3.y = _YReal + _HReal; + // top-right + _QuadT.V2.x = _XReal + _WReal; + _QuadT.V2.y = _YReal + _HReal; + // bottom-right + _QuadT.V1.x = _XReal + _WReal - dRight; + _QuadT.V1.y = _YReal + _HReal - dTop; + // bottom-left + _QuadT.V0.x = _XReal + dLeft; + _QuadT.V0.y = _YReal + _HReal - dTop; + } + + if (_BorderRight) + { + // top-left + _QuadR.V3.x = _XReal + _WReal - dRight; + _QuadR.V3.y = _YReal + _HReal - dTop; + // top-right + _QuadR.V2.x = _XReal + _WReal; + _QuadR.V2.y = _YReal + _HReal; + // bottom-right + _QuadR.V1.x = _XReal + _WReal; + _QuadR.V1.y = _YReal; + // bottom-left + _QuadR.V0.x = _XReal + _WReal - dRight; + _QuadR.V0.y = _YReal + dBottom; + } + + if (_BorderBottom) + { + // top-left + _QuadB.V3.x = _XReal + dLeft; + _QuadB.V3.y = _YReal + dBottom; + // top-right + _QuadB.V2.x = _XReal + _WReal - dRight; + _QuadB.V2.y = _YReal + dBottom; + // bottom-right + _QuadB.V1.x = _XReal + _WReal; + _QuadB.V1.y = _YReal; + // bottom-left + _QuadB.V0.x = _XReal; + _QuadB.V0.y = _YReal; + } + + if (_BorderLeft) + { + // top-left + _QuadL.V3.x = _XReal; + _QuadL.V3.y = _YReal + _HReal; + // top-right + _QuadL.V2.x = _XReal + dLeft; + _QuadL.V2.y = _YReal + _HReal - dTop; + // bottom-right + _QuadL.V1.x = _XReal + dLeft; + _QuadL.V1.y = _YReal + dBottom; + // bottom-left + _QuadL.V0.x = _XReal; + _QuadL.V0.y = _YReal; + } + } + + // ---------------------------------------------------------------------------- + void CSSBorderRenderer::draw() { + if (_Dirty) updateCoords(); + if (!_Border) return; + + CViewRenderer &rVR = *CViewRenderer::getInstance(); + + // TODO: no need for widget manager, if global color is set from parent + CRGBA globalColor; + if (_ModulateGlobalColor) + globalColor = CWidgetManager::getInstance()->getGlobalColor(); + + // TODO: monitor ModulateGlobalColor and CurrentAlpha in table checkCoords and recalculate colors on change only + // OUTSET - bottom/right darker than normal (default table style) + // INSET - top/left darker than normal + if (_BorderTop) + { + CRGBA borderColorT = TopColor; + if (TopStyle == CSSLineStyle::INSET) + borderColorT = blend(borderColorT, CRGBA::Black, 0.5f); + + if (_ModulateGlobalColor) + borderColorT.modulateFromColor (borderColorT, globalColor); + + borderColorT.A = (uint8) (((uint16) CurrentAlpha * (uint16) borderColorT.A) >> 8); + rVR.drawQuad(_RenderLayer, _QuadT, rVR.getBlankTextureId(), borderColorT, false); + } + if (_BorderRight) + { + CRGBA borderColorR = RightColor; + if (RightStyle == CSSLineStyle::OUTSET) + borderColorR = blend(borderColorR, CRGBA::Black, 0.5f); + + if (_ModulateGlobalColor) + borderColorR.modulateFromColor (borderColorR, globalColor); + + borderColorR.A = (uint8) (((uint16) CurrentAlpha * (uint16) borderColorR.A) >> 8); + rVR.drawQuad(_RenderLayer, _QuadR, rVR.getBlankTextureId(), borderColorR, false); + } + if (_BorderBottom) + { + CRGBA borderColorB = BottomColor; + if (BottomStyle == CSSLineStyle::OUTSET) + borderColorB = blend(borderColorB, CRGBA::Black, 0.5f); + + if (_ModulateGlobalColor) + borderColorB.modulateFromColor (borderColorB, globalColor); + + borderColorB.A = (uint8) (((uint16) CurrentAlpha * (uint16) borderColorB.A) >> 8); + rVR.drawQuad(_RenderLayer, _QuadB, rVR.getBlankTextureId(), borderColorB, false); + } + if (_BorderLeft) + { + CRGBA borderColorL = LeftColor; + if (LeftStyle == CSSLineStyle::INSET) + borderColorL = blend(borderColorL, CRGBA::Black, 0.5f); + + if (_ModulateGlobalColor) + borderColorL.modulateFromColor (borderColorL, globalColor); + + borderColorL.A = (uint8) (((uint16) CurrentAlpha * (uint16) borderColorL.A) >> 8); + rVR.drawQuad(_RenderLayer, _QuadL, rVR.getBlankTextureId(), borderColorL, false); + } + } + +}//namespace + diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index b95d645f7..1a129ebae 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -52,6 +52,7 @@ #include "nel/gui/html_element.h" #include "nel/gui/css_style.h" #include "nel/gui/css_parser.h" +#include "nel/gui/css_border_renderer.h" #include @@ -6556,31 +6557,50 @@ namespace NLGUI else if (elm.hasNonEmptyAttribute("width")) getPercentage (table->ForceWidthMin, table->TableRatio, elm.getAttribute("width").c_str()); - if (_Style.hasStyle("border") || _Style.hasStyle("border-width") || _Style.hasStyle("border-top-width")) + // border from css or from attribute { - // FIXME: only using border-top - table->Border = _Style.Current.BorderTopWidth; - } - else if (elm.hasAttribute("border")) - { - std::string s = elm.getAttribute("border"); - if (s.empty()) - table->Border = 1; - else - fromString(elm.getAttribute("border"), table->Border); - } + uint32 borderWidth = 0; + CRGBA borderColor = CRGBA::Transparent; - if (_Style.hasStyle("border-color")) - { - std::string s = toLower(_Style.getStyle("border-color")); - if (s == "currentcolor") - table->BorderColor = _Style.Current.TextColor; + // TODO: _Style->hasBorder() ?? + table->Border = new CSSBorderRenderer(); + if (elm.hasAttribute("border")) + { + std::string s = elm.getAttribute("border"); + if (s.empty()) + borderWidth = 1; + else + fromString(elm.getAttribute("border"), borderWidth); + + if (elm.hasNonEmptyAttribute("bordercolor")) + scanHTMLColor(elm.getAttribute("bordercolor").c_str(), borderColor); + else + borderColor = CRGBA(128, 128, 128, 255); + + table->CellBorder = (borderWidth > 0); + table->Border->setWidth(borderWidth, borderWidth, borderWidth, borderWidth); + table->Border->setColor(borderColor, borderColor, borderColor, borderColor); + table->Border->setStyle(CSSLineStyle::OUTSET, CSSLineStyle::OUTSET, CSSLineStyle::OUTSET, CSSLineStyle::OUTSET); + } else - scanHTMLColor(s.c_str(), table->BorderColor); - } - else if (elm.hasNonEmptyAttribute("bordercolor")) - { - scanHTMLColor(elm.getAttribute("bordercolor").c_str(), table->BorderColor); + { + table->CellBorder = false; + } + + if (_Style.hasStyle("border-top-width")) table->Border->TopWidth = _Style.Current.BorderTopWidth; + if (_Style.hasStyle("border-right-width")) table->Border->RightWidth = _Style.Current.BorderRightWidth; + if (_Style.hasStyle("border-bottom-width")) table->Border->BottomWidth = _Style.Current.BorderBottomWidth; + if (_Style.hasStyle("border-left-width")) table->Border->LeftWidth = _Style.Current.BorderLeftWidth; + + if (_Style.hasStyle("border-top-color")) table->Border->TopColor = _Style.Current.BorderTopColor; + if (_Style.hasStyle("border-right-color")) table->Border->RightColor = _Style.Current.BorderRightColor; + if (_Style.hasStyle("border-bottom-color")) table->Border->BottomColor = _Style.Current.BorderBottomColor; + if (_Style.hasStyle("border-left-color")) table->Border->LeftColor = _Style.Current.BorderLeftColor; + + if (_Style.hasStyle("border-top-style")) table->Border->TopStyle = _Style.Current.BorderTopStyle; + if (_Style.hasStyle("border-right-style")) table->Border->RightStyle = _Style.Current.BorderRightStyle; + if (_Style.hasStyle("border-bottom-style")) table->Border->BottomStyle = _Style.Current.BorderBottomStyle; + if (_Style.hasStyle("border-left-style")) table->Border->LeftStyle = _Style.Current.BorderLeftStyle; } if (_Style.hasStyle("background-image")) @@ -6714,6 +6734,29 @@ namespace NLGUI if (_Style.checkStyle("-ryzom-modulate-bgcolor", "true")) _Cells.back()->setModulateGlobalColor(true); + // border from
+ if (table->CellBorder) + { + _Cells.back()->Border->setWidth(1, 1, 1, 1); + _Cells.back()->Border->setColor(table->Border->TopColor, table->Border->RightColor, table->Border->BottomColor, table->Border->LeftColor); + _Cells.back()->Border->setStyle(CSSLineStyle::INSET, CSSLineStyle::INSET, CSSLineStyle::INSET, CSSLineStyle::INSET); + } + + if (_Style.hasStyle("border-top-width")) _Cells.back()->Border->TopWidth = _Style.Current.BorderTopWidth; + if (_Style.hasStyle("border-right-width")) _Cells.back()->Border->RightWidth = _Style.Current.BorderRightWidth; + if (_Style.hasStyle("border-bottom-width")) _Cells.back()->Border->BottomWidth = _Style.Current.BorderBottomWidth; + if (_Style.hasStyle("border-left-width")) _Cells.back()->Border->LeftWidth = _Style.Current.BorderLeftWidth; + + if (_Style.hasStyle("border-top-color")) _Cells.back()->Border->TopColor = _Style.Current.BorderTopColor; + if (_Style.hasStyle("border-right-color")) _Cells.back()->Border->RightColor = _Style.Current.BorderRightColor; + if (_Style.hasStyle("border-bottom-color")) _Cells.back()->Border->BottomColor = _Style.Current.BorderBottomColor; + if (_Style.hasStyle("border-left-color")) _Cells.back()->Border->LeftColor = _Style.Current.BorderLeftColor; + + if (_Style.hasStyle("border-top-style")) _Cells.back()->Border->TopStyle = _Style.Current.BorderTopStyle; + if (_Style.hasStyle("border-right-style")) _Cells.back()->Border->RightStyle = _Style.Current.BorderRightStyle; + if (_Style.hasStyle("border-bottom-style")) _Cells.back()->Border->BottomStyle = _Style.Current.BorderBottomStyle; + if (_Style.hasStyle("border-left-style")) _Cells.back()->Border->LeftStyle = _Style.Current.BorderLeftStyle; + table->addChild (_Cells.back()); // reusing indent pushed by table diff --git a/code/nel/src/gui/group_table.cpp b/code/nel/src/gui/group_table.cpp index a99cbddeb..68f01b65d 100644 --- a/code/nel/src/gui/group_table.cpp +++ b/code/nel/src/gui/group_table.cpp @@ -25,6 +25,7 @@ #include "nel/misc/i_xml.h" #include "nel/misc/i18n.h" #include "nel/misc/xml_auto_ptr.h" +#include "nel/gui/css_border_renderer.h" using namespace std; using namespace NLMISC; @@ -52,6 +53,8 @@ namespace NLGUI RowSpan = 1; TableColumnIndex = 0; Group = new CInterfaceGroup(CViewBase::TCtorParam()); + // TODO: only initialize if border is set + Border = new CSSBorderRenderer(); Align = Left; VAlign = Middle; LeftMargin = 0; @@ -541,26 +544,13 @@ namespace NLGUI } // Get the parent table - if (getParent ()) + if (CurrentAlpha > 0) { - CGroupTable *table = static_cast (getParent ()); - if (table->Border) { - CRGBA borderColorTL = blend(table->BorderColor, CRGBA::White, 0.5f); - if (_ModulateGlobalColor) - borderColorTL.modulateFromColor (borderColorTL, CWidgetManager::getInstance()->getGlobalColor()); - borderColorTL.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) borderColorTL.A) >> 8); - - CRGBA borderColorBR = table->BorderColor; - if (_ModulateGlobalColor) - borderColorBR.modulateFromColor (borderColorBR, CWidgetManager::getInstance()->getGlobalColor()); - borderColorBR.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) borderColorBR.A) >> 8); - - CViewRenderer &rVR = *CViewRenderer::getInstance(); - rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, 1, 0, false, rVR.getBlankTextureId(), borderColorTL ); - rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), borderColorBR ); - rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_HReal-1, _WReal, 1, 0, false, rVR.getBlankTextureId(), borderColorBR ); - rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_WReal-1, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), borderColorTL ); - } + // TODO: monitor these in checkCoords and update when changed + Border->CurrentAlpha = CurrentAlpha; + Border->setRenderLayer(_RenderLayer); + Border->setModulateGlobalColor(_ModulateGlobalColor); + Border->draw(); } CInterfaceGroup::draw (); @@ -646,8 +636,11 @@ namespace NLGUI _ContentValidated = false; TableRatio = 0.f; ForceWidthMin = 0; - Border=0; - BorderColor = CRGBA(32, 32, 32, 255); + + // TODO: only initialize when needed + Border = new CSSBorderRenderer(); + + CellBorder = false; CellPadding=1; CellSpacing=2; ContinuousUpdate = false; @@ -719,6 +712,12 @@ namespace NLGUI // ---------------------------------------------------------------------------- CGroupTable::~CGroupTable() { + if (Border) + { + delete Border; + Border = NULL; + } + /* uint i; for (i=0; i<_Cells.size(); i++) delete _Cells[i]; @@ -895,9 +894,9 @@ namespace NLGUI column++; } - // Width of cells and table borders - sint32 padding = CellPadding + (Border ? 1 : 0); - sint32 borderWidth = 2*Border + ((sint32)_Columns.size()+1) * CellSpacing + ((sint32)_Columns.size()*2) * padding; + // Additional space contributing to table width + sint32 borderWidth = Border->getLeftWidth() + Border->getRightWidth(); + borderWidth += ((sint32)_Columns.size()+1) * CellSpacing;// + ((sint32)_Columns.size()*2) * padding; // Get the width sint32 tableWidthMax = ForceWidthMin?ForceWidthMin:_LastParentW; // getWReal(); @@ -1102,8 +1101,10 @@ namespace NLGUI // *** Now we know each column width, resize cells and get the height for each row column = 0; + // FIXME: real cell padding + sint32 padding = CellPadding; sint32 row = 0; - sint32 currentX = Border + CellSpacing + padding; + sint32 currentX = Border->LeftWidth + CellSpacing + padding; _Rows.clear (); for (i=0; i<_Cells.size(); i++) @@ -1113,7 +1114,7 @@ namespace NLGUI if (cell->NewLine) { column = 0; - currentX = Border + CellSpacing + padding; + currentX = Border->LeftWidth + CellSpacing + padding; _Rows.push_back(CRow()); } @@ -1168,7 +1169,11 @@ namespace NLGUI // Resize the row array float rowspan = 1.f / (float)cell->RowSpan; - _Rows.back().Height = std::max((sint32)(cell->Height*rowspan), std::max(_Rows.back().Height, (sint32)(cell->Group->getH()*rowspan))); + uint cellBorder = 0; + if (cell->Border) + cellBorder += cell->Border->TopWidth + cell->Border->BottomWidth; + sint32 cellHeight = std::max((sint32)(cell->Height*rowspan + cellBorder), (sint32)(cell->Group->getH()*rowspan + cellBorder)); + _Rows.back().Height = std::max(_Rows.back().Height, (sint32)cellHeight); // Next column currentX += columnWidth + 2*padding + CellSpacing; @@ -1177,7 +1182,10 @@ namespace NLGUI // Set cell Y row = 0; - sint32 currentY = -(Border + CellSpacing + padding); + sint32 currentY = -(CellSpacing + padding); + if (Border) + currentY -= Border->TopWidth; + for (i=0; i<_Cells.size(); i++) { // New cell ? @@ -1224,7 +1232,7 @@ namespace NLGUI // Resize the table setW(finalWidth+borderWidth-_LastParentW); if (!_Rows.empty()) - currentY -= _Rows[row].Height + padding + CellSpacing + Border; + currentY -= _Rows[row].Height + padding + CellSpacing + Border->BottomWidth; setH(-currentY); // All done @@ -1236,6 +1244,20 @@ namespace NLGUI updateTextureCoords(); + // update borders if present + if (Border) + { + Border->setRect(_XReal + _MarginLeft, _YReal, _WReal, _HReal); + } + + // update cell borders if present + for (uint32 i=0; i<_Cells.size(); i++) + { + if (_Cells[i]->Border) + { + _Cells[i]->Border->setRect(_Cells[i]->_XReal, _Cells[i]->_YReal, _Cells[i]->_WReal, _Cells[i]->_HReal); + } + } // Validated _ContentValidated = true; @@ -1341,7 +1363,8 @@ namespace NLGUI for (i=0; iLeftWidth + Border->RightWidth + ((sint32)columns.size()+1) * CellSpacing + ((sint32)columns.size()*2) * CellPadding; return maxWidth; } @@ -1386,7 +1409,8 @@ namespace NLGUI for (i=0; iLeftWidth + Border->RightWidth + ((sint32)columns.size()+1) * CellSpacing + ((sint32)columns.size()*2) * CellPadding; return maxWidth; } @@ -1460,29 +1484,15 @@ namespace NLGUI if (flush) rVR.flush(); - if (Border) + // TODO: monitor ModulateGlobalColor and CurrentAlpha in checkCoords and recalculate colors on change only + if (CurrentAlpha > 0 && Border) { - CRGBA borderColorTL = blend(BorderColor, CRGBA::White, 0.5f); - if (_ModulateGlobalColor) - borderColorTL.modulateFromColor (borderColorTL, CWidgetManager::getInstance()->getGlobalColor()); - borderColorTL.A = CurrentAlpha; - - CRGBA borderColorBR = BorderColor; - if (_ModulateGlobalColor) - borderColorBR.modulateFromColor (borderColorBR, CWidgetManager::getInstance()->getGlobalColor()); - borderColorBR.A = CurrentAlpha; - - // beveled table border - for (sint32 i=0; iCurrentAlpha = CurrentAlpha; + Border->setRenderLayer(_RenderLayer); + Border->setModulateGlobalColor(_ModulateGlobalColor); + Border->draw(); } - } CInterfaceGroup::draw (); @@ -1495,12 +1505,12 @@ namespace NLGUI { if( name == "border" ) { - return toString( Border ); + return toString( Border->TopWidth ); } else if( name == "bordercolor" ) { - return toString( BorderColor ); + return toString( Border->TopColor ); } else if( name == "cellpadding" ) @@ -1535,7 +1545,12 @@ namespace NLGUI { sint32 i; if( fromString( value, i ) ) - Border = i; + { + Border->TopWidth = i; + Border->RightWidth = i; + Border->BottomWidth = i; + Border->LeftWidth = i; + } return; } else @@ -1543,7 +1558,12 @@ namespace NLGUI { CRGBA c; if( fromString( value, c ) ) - BorderColor = c; + { + Border->TopColor = c; + Border->RightColor = c; + Border->BottomColor = c; + Border->LeftColor = c; + } return; } else @@ -1588,8 +1608,8 @@ namespace NLGUI return NULL; xmlSetProp( node, BAD_CAST "type", BAD_CAST "table" ); - xmlSetProp( node, BAD_CAST "border", BAD_CAST toString( Border ).c_str() ); - xmlSetProp( node, BAD_CAST "bordercolor", BAD_CAST toString( BorderColor ).c_str() ); + xmlSetProp( node, BAD_CAST "border", BAD_CAST toString( Border->TopWidth ).c_str() ); + xmlSetProp( node, BAD_CAST "bordercolor", BAD_CAST toString( Border->TopColor ).c_str() ); xmlSetProp( node, BAD_CAST "cellpadding", BAD_CAST toString( CellPadding ).c_str() ); xmlSetProp( node, BAD_CAST "cellspacing", BAD_CAST toString( CellSpacing ).c_str() ); xmlSetProp( node, BAD_CAST "bgcolor", BAD_CAST toString( BgColor ).c_str() ); @@ -1611,13 +1631,16 @@ namespace NLGUI ptr = (char*) xmlGetProp( cur, (xmlChar*)"border" ); if (ptr) { - fromString((const char*)ptr, Border); + uint32 w; + fromString((const char*)ptr, w); + Border->setWidth(w, w, w, w); } // ptr = (char*) xmlGetProp( cur, (xmlChar*)"bordercolor" ); if (ptr) { - BorderColor = convertColor((const char*)ptr); + CRGBA c = convertColor((const char*)ptr); + Border->setColor(c, c, c, c); } // ptr = (char*) xmlGetProp( cur, (xmlChar*)"cellpadding" ); From 1a98c83080d40504b43870ddbbde80a01480a8ca Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 14:16:31 +0300 Subject: [PATCH 19/35] Changed: Use transparency from global content on table/cell border instead background --HG-- branch : html-improvements --- code/nel/src/gui/group_table.cpp | 44 ++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/code/nel/src/gui/group_table.cpp b/code/nel/src/gui/group_table.cpp index 68f01b65d..c268e2bfc 100644 --- a/code/nel/src/gui/group_table.cpp +++ b/code/nel/src/gui/group_table.cpp @@ -487,19 +487,19 @@ namespace NLGUI rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_WReal-1, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), CRGBA(0,255,255,255) ); } + uint8 CurrentAlpha = 255; + CGroupTable *table = NULL; + if (getParent ()) + { + table = static_cast (getParent ()); + CurrentAlpha = table->CurrentAlpha; + } + // Draw the background if (BgColor.A > 0 || !_TextureId.empty()) { CViewRenderer &rVR = *CViewRenderer::getInstance(); - uint8 CurrentAlpha = 255; - - if (getParent ()) - { - CGroupTable *table = static_cast (getParent ()); - CurrentAlpha = table->CurrentAlpha; - } - bool flush = false; if (CurrentAlpha > 0 && !_TextureId.empty()) { @@ -544,13 +544,16 @@ namespace NLGUI } // Get the parent table - if (CurrentAlpha > 0) { // TODO: monitor these in checkCoords and update when changed - Border->CurrentAlpha = CurrentAlpha; - Border->setRenderLayer(_RenderLayer); - Border->setModulateGlobalColor(_ModulateGlobalColor); - Border->draw(); + uint8 contentAlpha = CWidgetManager::getInstance()->getGlobalColorForContent().A; + if (contentAlpha > 0) + { + Border->CurrentAlpha = contentAlpha; + Border->setRenderLayer(_RenderLayer); + Border->setModulateGlobalColor(_ModulateGlobalColor); + Border->draw(); + } } CInterfaceGroup::draw (); @@ -1484,14 +1487,17 @@ namespace NLGUI if (flush) rVR.flush(); - // TODO: monitor ModulateGlobalColor and CurrentAlpha in checkCoords and recalculate colors on change only - if (CurrentAlpha > 0 && Border) + if (Border) { // TODO: monitor these in checkCoords and update when changed - Border->CurrentAlpha = CurrentAlpha; - Border->setRenderLayer(_RenderLayer); - Border->setModulateGlobalColor(_ModulateGlobalColor); - Border->draw(); + uint8 contentAlpha = CWidgetManager::getInstance()->getGlobalColorForContent().A; + if (contentAlpha > 0) + { + Border->CurrentAlpha = CurrentAlpha; + Border->setRenderLayer(_RenderLayer); + Border->setModulateGlobalColor(_ModulateGlobalColor); + Border->draw(); + } } } From 0fb06e0ff36f8f8d49773285de65ad9092d26068 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:43:00 +0300 Subject: [PATCH 20/35] Added: Table cell independent padding. --HG-- branch : html-improvements --- code/nel/include/nel/gui/css_style.h | 7 ++++ code/nel/include/nel/gui/group_table.h | 4 ++ code/nel/src/gui/css_style.cpp | 53 ++++++++++++++++++++++++++ code/nel/src/gui/group_html.cpp | 22 +++++++---- code/nel/src/gui/group_table.cpp | 1 + 5 files changed, 79 insertions(+), 8 deletions(-) diff --git a/code/nel/include/nel/gui/css_style.h b/code/nel/include/nel/gui/css_style.h index 94d86bf5d..50dd3180a 100644 --- a/code/nel/include/nel/gui/css_style.h +++ b/code/nel/include/nel/gui/css_style.h @@ -70,6 +70,7 @@ namespace NLGUI // background BackgroundColor=NLMISC::CRGBA::Black; BackgroundColorOver=NLMISC::CRGBA::Black; + PaddingTop = PaddingRight = PaddingBottom = PaddingLeft = 0; } bool hasStyle(const std::string &key) const @@ -103,6 +104,7 @@ namespace NLGUI NLMISC::CRGBA BorderTopColor, BorderRightColor, BorderBottomColor, BorderLeftColor; NLMISC::CRGBA BackgroundColor; NLMISC::CRGBA BackgroundColorOver; + uint32 PaddingTop, PaddingRight, PaddingBottom, PaddingLeft; std::string WhiteSpace; std::string TextAlign; @@ -168,10 +170,14 @@ namespace NLGUI // parse 'background' into 'background-color', 'background-image', etc void parseBackgroundShorthand(const std::string &value, CStyleParams &style) const; + // parse 'padding' into 'padding-top', 'padding-left', etc + void parsePaddingShorthand(const std::string &value, CStyleParams &style) const; + // parse string value into corresponding value void applyBorderWidth(const std::string &value, uint32 *dest, const uint32 currentWidth, const uint32 fontSize) const; void applyBorderColor(const std::string &value, NLMISC::CRGBA *dest, const NLMISC::CRGBA ¤tColor, const NLMISC::CRGBA &textColor) const; 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; public: void reset(); @@ -206,6 +212,7 @@ namespace NLGUI Current.BorderTopWidth = Current.BorderRightWidth = Current.BorderBottomWidth = Current.BorderLeftWidth = CSSLineWidth::MEDIUM; Current.BorderTopStyle = Current.BorderRightStyle = Current.BorderBottomStyle = Current.BorderLeftStyle = CSSLineStyle::NONE; Current.BorderTopColor = Current.BorderRightColor = Current.BorderBottomColor = Current.BorderLeftColor = Current.TextColor; + Current.PaddingTop = Current.PaddingRight = Current.PaddingBottom = Current.PaddingLeft = 0; Current.StyleRules.clear(); } diff --git a/code/nel/include/nel/gui/group_table.h b/code/nel/include/nel/gui/group_table.h index e45575e47..ccc2ce3cf 100644 --- a/code/nel/include/nel/gui/group_table.h +++ b/code/nel/include/nel/gui/group_table.h @@ -94,6 +94,7 @@ namespace NLGUI NLMISC::CRGBA BgColor; CSSBorderRenderer* Border; + uint32 PaddingTop, PaddingRight, PaddingBottom, PaddingLeft; // Texture CViewRenderer::CTextureId _TextureId; @@ -120,6 +121,9 @@ namespace NLGUI void setTextureTile(bool tiled); void setTextureScale(bool scaled); + uint32 getPaddingLeftRight() const { return PaddingLeft + PaddingRight; }; + uint32 getPaddingTopBottom() const { return PaddingTop + PaddingBottom; }; + virtual void updateCoords(); static void setDebugUICell( bool d ){ DebugUICell = d; } diff --git a/code/nel/src/gui/css_style.cpp b/code/nel/src/gui/css_style.cpp index 72c9701df..888044e5c 100644 --- a/code/nel/src/gui/css_style.cpp +++ b/code/nel/src/gui/css_style.cpp @@ -493,6 +493,12 @@ namespace NLGUI else style.DisplayBlock = (it->second == "block" || it->second == "table"); } + else + if (it->first == "padding") + { + parsePaddingShorthand(it->second, style); + keep = false; + } if (!keep) { @@ -578,6 +584,33 @@ namespace NLGUI *dest = CSSLineStyle::SOLID; } + void CCssStyle::applyPaddingWidth(const std::string &value, uint32 *dest, const uint32 currentPadding, uint32 fontSize) const + { + if (!dest) return; + + if (value == "inherit") + { + *dest = currentPadding; + return; + } + + float tmpf; + std::string unit; + if (getCssLength(tmpf, unit, value.c_str())) + { + if (unit == "rem") + *dest = fontSize * tmpf; + else if (unit == "em") + *dest = fontSize * tmpf; + else if (unit == "pt") + *dest = tmpf / 0.75f; + else if (unit == "%") + *dest = 0; // TODO: requires content width, must remember 'unit' type + else + *dest = tmpf; + } + } + // apply style rules void CCssStyle::apply(CStyleParams &style, const CStyleParams ¤t) const { @@ -597,6 +630,10 @@ namespace NLGUI else if (it->first == "border-left-width") applyBorderWidth(it->second, &style.BorderLeftWidth, current.BorderLeftWidth, current.FontSize); else if (it->first == "border-left-color") applyBorderColor(it->second, &style.BorderLeftColor, current.BorderLeftColor, current.TextColor); else if (it->first == "border-left-style") applyLineStyle(it->second, &style.BorderLeftStyle, current.BorderLeftStyle); + else if (it->first == "padding-top") applyPaddingWidth(it->second, &style.PaddingTop, current.PaddingTop, current.FontSize); + else if (it->first == "padding-right") applyPaddingWidth(it->second, &style.PaddingRight, current.PaddingRight, current.FontSize); + else if (it->first == "padding-bottom") applyPaddingWidth(it->second, &style.PaddingBottom, current.PaddingBottom, current.FontSize); + else if (it->first == "padding-left") applyPaddingWidth(it->second, &style.PaddingLeft, current.PaddingLeft, current.FontSize); else if (it->first == "font-style") { @@ -1507,6 +1544,22 @@ namespace NLGUI } } + // *************************************************************************** + void CCssStyle::parsePaddingShorthand(const std::string &value, CStyleParams &style) const + { + std::vector parts; + NLMISC::splitString(toLower(value), " ", parts); + + uint8 t, r, b, l; + if (!getShorthandIndices(parts.size(), t, r, b, l)) + return; + + style.StyleRules["padding-top"] = parts[t]; + style.StyleRules["padding-right"] = parts[r]; + style.StyleRules["padding-bottom"] = parts[b]; + style.StyleRules["padding-left"] = parts[l]; + } + // *************************************************************************** void CCssStyle::applyCssMinMax(sint32 &width, sint32 &height, sint32 minw, sint32 minh, sint32 maxw, sint32 maxh) const { diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 1a129ebae..5b641647d 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -6682,14 +6682,6 @@ namespace NLGUI return; } - if (_Style.hasStyle("padding")) - { - uint32 a; - // TODO: cssLength - if (fromString(_Style.getStyle("padding"), a)) - table->CellPadding = a; - } - _Cells.back() = new CGroupCell(CViewBase::TCtorParam()); if (_Style.checkStyle("background-repeat", "repeat")) @@ -6757,6 +6749,20 @@ namespace NLGUI if (_Style.hasStyle("border-bottom-style")) _Cells.back()->Border->BottomStyle = _Style.Current.BorderBottomStyle; if (_Style.hasStyle("border-left-style")) _Cells.back()->Border->LeftStyle = _Style.Current.BorderLeftStyle; + // padding from
+ if (table->CellPadding) + { + _Cells.back()->PaddingTop = table->CellPadding; + _Cells.back()->PaddingRight = table->CellPadding; + _Cells.back()->PaddingBottom = table->CellPadding; + _Cells.back()->PaddingLeft = table->CellPadding; + } + + if (_Style.hasStyle("padding-top")) _Cells.back()->PaddingTop = _Style.Current.PaddingTop; + if (_Style.hasStyle("padding-right")) _Cells.back()->PaddingRight = _Style.Current.PaddingRight; + if (_Style.hasStyle("padding-bottom")) _Cells.back()->PaddingBottom = _Style.Current.PaddingBottom; + if (_Style.hasStyle("padding-left")) _Cells.back()->PaddingLeft = _Style.Current.PaddingLeft; + table->addChild (_Cells.back()); // reusing indent pushed by table diff --git a/code/nel/src/gui/group_table.cpp b/code/nel/src/gui/group_table.cpp index c268e2bfc..98ad6fcfc 100644 --- a/code/nel/src/gui/group_table.cpp +++ b/code/nel/src/gui/group_table.cpp @@ -55,6 +55,7 @@ namespace NLGUI Group = new CInterfaceGroup(CViewBase::TCtorParam()); // TODO: only initialize if border is set Border = new CSSBorderRenderer(); + PaddingTop = PaddingRight = PaddingBottom = PaddingLeft = 0; Align = Left; VAlign = Middle; LeftMargin = 0; From 0f23f3a59b3f10b4d713c003d192f2d716f9dd76 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:43:25 +0300 Subject: [PATCH 21/35] Fixed: Table cell should inherit height attribute from row --HG-- branch : html-improvements --- code/nel/include/nel/gui/group_html.h | 2 ++ code/nel/src/gui/group_html.cpp | 16 ++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/code/nel/include/nel/gui/group_html.h b/code/nel/include/nel/gui/group_html.h index 31330fa51..58e4f802c 100644 --- a/code/nel/include/nel/gui/group_html.h +++ b/code/nel/include/nel/gui/group_html.h @@ -700,6 +700,7 @@ namespace NLGUI VAlign = CGroupCell::Middle; LeftMargin = 0; NoWrap = false; + Height = 0; } NLMISC::CRGBA BgColor; std::string Style; @@ -707,6 +708,7 @@ namespace NLGUI CGroupCell::TVAlign VAlign; sint32 LeftMargin; bool NoWrap; + sint32 Height; }; std::vector _CellParams; diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 5b641647d..81f036f05 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -5235,6 +5235,11 @@ namespace NLGUI if (elm.hasNonEmptyAttribute("l_margin")) fromString(elm.getAttribute("l_margin"), cellParams.LeftMargin); + if (_Style.hasStyle("height")) + cellParams.Height = _Style.Current.Height; + else if (elm.hasNonEmptyAttribute("height")) + fromString(elm.getAttribute("height"), cellParams.Height); + { std::string align; // having text-align on table/tr should not override td align attribute @@ -6708,6 +6713,7 @@ namespace NLGUI _Cells.back()->NoWrap = _CellParams.back().NoWrap; _Cells.back()->ColSpan = std::max(1, _Cells.back()->ColSpan); _Cells.back()->RowSpan = std::max(1, _Cells.back()->RowSpan); + _Cells.back()->Height = _CellParams.back().Height; float temp; if (_Style.hasStyle("width")) @@ -6715,11 +6721,6 @@ namespace NLGUI else if (elm.hasNonEmptyAttribute("width")) getPercentage (_Cells.back()->WidthWanted, _Cells.back()->TableRatio, elm.getAttribute("width").c_str()); - if (_Style.hasStyle("height")) - getPercentage (_Cells.back()->Height, temp, _Style.getStyle("height").c_str()); - else if (elm.hasNonEmptyAttribute("height")) - getPercentage (_Cells.back()->Height, temp, elm.getAttribute("height").c_str()); - _Cells.back()->NewLine = getTR(); // setting ModulateGlobalColor must be after addImageDownload @@ -6871,9 +6872,12 @@ namespace NLGUI // *************************************************************************** void CGroupHTML::htmlTR(const CHtmlElement &elm) { - // prevent inheriting background color + // prevent inheriting from table if (!_CellParams.empty()) + { _CellParams.back().BgColor = CRGBA::Transparent; + _CellParams.back().Height = 0; + } // Get cells parameters getCellsParameters(elm, true); From 25ee8029e36f8fd3b17721a88f5db48048871434 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:43:52 +0300 Subject: [PATCH 22/35] Fixed: Table/cell width using css units --HG-- branch : html-improvements --- code/nel/src/gui/group_html.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 81f036f05..6dedb31c4 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -6558,9 +6558,22 @@ namespace NLGUI fromString(elm.getAttribute("cellpadding"), table->CellPadding); if (_Style.hasStyle("width")) - getPercentage(table->ForceWidthMin, table->TableRatio, _Style.getStyle("width").c_str()); + { + // _Style.Width does not handle '%' unit currently + if (_Style.Current.Width > 0) + { + table->ForceWidthMin = _Style.Current.Width; + table->TableRatio = 0; + } + else + { + getPercentage (table->ForceWidthMin, table->TableRatio, _Style.getStyle("width").c_str()); + } + } else if (elm.hasNonEmptyAttribute("width")) + { getPercentage (table->ForceWidthMin, table->TableRatio, elm.getAttribute("width").c_str()); + } // border from css or from attribute { @@ -6717,9 +6730,22 @@ namespace NLGUI float temp; if (_Style.hasStyle("width")) - getPercentage (_Cells.back()->WidthWanted, _Cells.back()->TableRatio, _Style.getStyle("width").c_str()); + { + // _Style.Width does not handle '%' unit currently + if (_Style.Current.Width > 0) + { + _Cells.back()->WidthWanted = _Style.Current.Width; + _Cells.back()->TableRatio = 0; + } + else + { + getPercentage (_Cells.back()->WidthWanted, _Cells.back()->TableRatio, _Style.getStyle("width").c_str()); + } + } else if (elm.hasNonEmptyAttribute("width")) + { getPercentage (_Cells.back()->WidthWanted, _Cells.back()->TableRatio, elm.getAttribute("width").c_str()); + } _Cells.back()->NewLine = getTR(); From f25771118d8897622c5cb041749e9b7ddac94784 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:44:00 +0300 Subject: [PATCH 23/35] Fixed: Table layout calculation with border/padding --HG-- branch : html-improvements --- code/nel/src/gui/group_table.cpp | 126 ++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 46 deletions(-) diff --git a/code/nel/src/gui/group_table.cpp b/code/nel/src/gui/group_table.cpp index 98ad6fcfc..6f61b7571 100644 --- a/code/nel/src/gui/group_table.cpp +++ b/code/nel/src/gui/group_table.cpp @@ -813,24 +813,24 @@ namespace NLGUI additionnalWidth = (sint32) width; } + sint32 cellBorderPadding = cell->getPaddingLeftRight(); + if (cell->Border) + cellBorderPadding += cell->Border->getLeftRightWidth(); + // Get width min and max if( !cell->IgnoreMaxWidth) - { - cell->WidthMax = cell->getMaxUsedW() + cell->LeftMargin; - } + cell->WidthMax = cell->getMaxUsedW() + cell->LeftMargin + cellBorderPadding; else - { cell->WidthMax = cell->WidthWanted + additionnalWidth + cell->LeftMargin; - } + sint32 cellWidth; if(!cell->IgnoreMinWidth) - { - cellWidth = cell->NoWrap ? cell->WidthMax : cell->getMinUsedW() + cell->LeftMargin; - } + cellWidth = cell->NoWrap ? cell->WidthMax : cell->getMinUsedW() + cell->LeftMargin + cellBorderPadding; else - { cellWidth = cell->NoWrap ? cell->WidthMax : cell->LeftMargin; - } + + if (cellWidth < cellBorderPadding) + cellWidth = cellBorderPadding; // New cell ? if (cell->NewLine) @@ -872,11 +872,11 @@ namespace NLGUI _Columns[column].WidthMax = (sint32)(cell->WidthMax*colspan); if (cell->TableRatio*colspan > _Columns[column].TableRatio) _Columns[column].TableRatio = cell->TableRatio*colspan; - if (cell->WidthWanted*colspan + additionnalWidth > _Columns[column].WidthWanted) - _Columns[column].WidthWanted = (sint32)(cell->WidthWanted*colspan) + additionnalWidth; + if ((cell->WidthWanted + additionnalWidth)*colspan > _Columns[column].WidthWanted) + _Columns[column].WidthWanted = (sint32)((cell->WidthWanted + additionnalWidth)*colspan); - if (_Columns[column].WidthWanted + additionnalWidth) - _Columns[column].WidthMax = _Columns[column].WidthWanted + additionnalWidth; + if (_Columns[column].WidthWanted > _Columns[column].WidthMax) + _Columns[column].WidthMax = _Columns[column].WidthWanted; if (_Columns[column].WidthWanted > _Columns[column].Width) _Columns[column].Width = _Columns[column].WidthWanted; @@ -899,14 +899,20 @@ namespace NLGUI } // Additional space contributing to table width - sint32 borderWidth = Border->getLeftWidth() + Border->getRightWidth(); - borderWidth += ((sint32)_Columns.size()+1) * CellSpacing;// + ((sint32)_Columns.size()*2) * padding; + sint32 tableBorderSpacing = Border->getLeftWidth() + Border->getRightWidth(); + tableBorderSpacing += ((sint32)_Columns.size()+1) * CellSpacing;; + + sint32 innerForceWidthMin = ForceWidthMin; + if (innerForceWidthMin < tableBorderSpacing) + innerForceWidthMin = 0; + else + innerForceWidthMin -= tableBorderSpacing; // Get the width - sint32 tableWidthMax = ForceWidthMin?ForceWidthMin:_LastParentW; // getWReal(); - sint32 tableWidthMin = std::max(ForceWidthMin, (sint32)((float)tableWidthMax*TableRatio)); - tableWidthMax = std::max ((sint32)0, tableWidthMax-borderWidth); - tableWidthMin = std::max ((sint32)0, tableWidthMin-borderWidth); + sint32 tableWidthMax = innerForceWidthMin ? innerForceWidthMin : _LastParentW - tableBorderSpacing; // getWReal(); + sint32 tableWidthMin = std::max(innerForceWidthMin, (sint32)((float)tableWidthMax*TableRatio)); + tableWidthMax = std::max ((sint32)0, tableWidthMax); + tableWidthMin = std::max ((sint32)0, tableWidthMin); // Get the width of the table and normalize percent of the cell (sum of TableRatio must == 1) sint32 tableWidth = 0; @@ -922,10 +928,10 @@ namespace NLGUI // force table width to fit all columns // if width is set, then use column min width - if (ForceWidthMin > 0) - tableWidthMax = std::min(_LastParentW - borderWidth, std::max(tableWidthMax, tableWidth)); + if (innerForceWidthMin > 0) + tableWidthMax = std::min(_LastParentW - tableBorderSpacing, std::max(tableWidthMax, tableWidth)); else - tableWidthMax = std::min(_LastParentW - borderWidth, std::max(tableWidthMax, tableMaxContentWidth)); + tableWidthMax = std::min(_LastParentW - tableBorderSpacing, std::max(tableWidthMax, tableMaxContentWidth)); if (tableWidthMax < 0) tableWidthMax = 0; @@ -934,6 +940,7 @@ namespace NLGUI std::swap(tableWidthMin, tableWidthMax); // Eval table size with all percent cells resized + // TODO: _Columns[i].TableRatio is for outer width sint32 tableWidthSizeAfterPercent = tableWidth; for (i=0; i<_Columns.size(); i++) { @@ -1106,9 +1113,8 @@ namespace NLGUI column = 0; // FIXME: real cell padding - sint32 padding = CellPadding; sint32 row = 0; - sint32 currentX = Border->LeftWidth + CellSpacing + padding; + sint32 currentX = 0; _Rows.clear (); for (i=0; i<_Cells.size(); i++) @@ -1118,7 +1124,7 @@ namespace NLGUI if (cell->NewLine) { column = 0; - currentX = Border->LeftWidth + CellSpacing + padding; + currentX = Border->LeftWidth + CellSpacing; _Rows.push_back(CRow()); } @@ -1127,7 +1133,7 @@ namespace NLGUI { // we have active rowspan, must add up 'skipped' columns for( ; column < (uint)cell->TableColumnIndex; ++column) - currentX += _Columns[column].Width + padding*2 + CellSpacing; + currentX += _Columns[column].Width + CellSpacing; } // Set the x and width @@ -1136,11 +1142,19 @@ namespace NLGUI sint32 alignmentX = 0; sint32 widthReduceX = 0; sint32 columnWidth = _Columns[column].Width; + sint32 cellBorderPaddingLeft = cell->PaddingLeft; + sint32 cellBorderPaddingRight = cell->PaddingRight; + if (cell->Border) + { + cellBorderPaddingLeft += cell->Border->getLeftWidth(); + cellBorderPaddingRight += cell->Border->getRightWidth(); + } + if (cell->ColSpan > 1) { // scan ahead and add up column widths as they might be different for(int j = 1; jColSpan; j++) - columnWidth += CellSpacing + padding*2 + _Columns[column+j].Width; + columnWidth += CellSpacing + _Columns[column+j].Width; } if (cell->WidthMax < columnWidth) @@ -1160,11 +1174,13 @@ namespace NLGUI } } - cell->setX(currentX - padding); - cell->setW(columnWidth + padding*2); + // outer + cell->setX(currentX); + cell->setW(columnWidth); - cell->Group->setX(alignmentX + cell->LeftMargin + padding); - cell->Group->setW(columnWidth - widthReduceX); + // inner + cell->Group->setX(cellBorderPaddingLeft + alignmentX + cell->LeftMargin); + cell->Group->setW(columnWidth - widthReduceX - cellBorderPaddingLeft - cellBorderPaddingRight); cell->Group->CInterfaceElement::updateCoords(); // Update coords to get H @@ -1173,22 +1189,22 @@ namespace NLGUI // Resize the row array float rowspan = 1.f / (float)cell->RowSpan; - uint cellBorder = 0; + uint cellBorderPadding = cell->getPaddingTopBottom(); if (cell->Border) - cellBorder += cell->Border->TopWidth + cell->Border->BottomWidth; - sint32 cellHeight = std::max((sint32)(cell->Height*rowspan + cellBorder), (sint32)(cell->Group->getH()*rowspan + cellBorder)); + cellBorderPadding += cell->Border->getTopBottomWidth(); + sint32 cellHeight = std::max((sint32)(cell->Height*rowspan), (sint32)(cell->Group->getH()*rowspan + cellBorderPadding)); _Rows.back().Height = std::max(_Rows.back().Height, (sint32)cellHeight); // Next column - currentX += columnWidth + 2*padding + CellSpacing; + currentX += columnWidth + CellSpacing; column += cell->ColSpan; } // Set cell Y row = 0; - sint32 currentY = -(CellSpacing + padding); + sint32 currentY = -CellSpacing; if (Border) - currentY -= Border->TopWidth; + currentY -= Border->getTopWidth(); for (i=0; i<_Cells.size(); i++) { @@ -1198,7 +1214,7 @@ namespace NLGUI { if (_Rows[row].Height != 0) { - currentY -= _Rows[row].Height + 2*padding + CellSpacing; + currentY -= _Rows[row].Height + CellSpacing; } row++; } @@ -1206,12 +1222,19 @@ namespace NLGUI // Check align sint32 alignmentY = 0; sint32 rowHeight = _Rows[row].Height; + sint32 cellBorderPaddingTop = cell->PaddingTop; + sint32 cellBorderPaddingBottom = cell->PaddingBottom; + if (cell->Border) + { + cellBorderPaddingTop += cell->Border->getTopWidth(); + cellBorderPaddingBottom += cell->Border->getBottomWidth(); + } if (cell->RowSpan > 1) { // we need to scan down and add up row heights int k = std::min((sint32)_Rows.size(), row + cell->RowSpan); for(int j=row+1; jGroup->getH() < rowHeight) { @@ -1228,15 +1251,26 @@ namespace NLGUI } } - cell->setY(currentY + padding); - cell->setH (rowHeight + 2*padding); - cell->Group->setY(-(alignmentY + padding)); + // outer + cell->setY(currentY); + cell->setH (rowHeight); + // inner + cell->Group->setY(-(alignmentY + cellBorderPaddingTop - cellBorderPaddingBottom)); } - // Resize the table - setW(finalWidth+borderWidth-_LastParentW); + // final row if (!_Rows.empty()) - currentY -= _Rows[row].Height + padding + CellSpacing + Border->BottomWidth; + currentY -= _Rows.back().Height; + currentY -= CellSpacing; + finalWidth += ((sint)_Columns.size() + 1) * CellSpacing; + if (Border) + { + currentY -= Border->getBottomWidth(); + finalWidth += Border->getLeftWidth() + Border->getRightWidth(); + } + + // Resize the table + setW(finalWidth-_LastParentW); setH(-currentY); // All done From 4ec90240777c2eabc6b196c9407223ffa9f601ef Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 11:08:20 +0300 Subject: [PATCH 24/35] Changed: Treat input 'size' attribute as chars (old was pixels). Add '-ryzom-input-size-px: true;' css property for old behaviour. --HG-- branch : html-improvements --- code/nel/src/gui/group_html.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 6dedb31c4..08325333f 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -5969,16 +5969,20 @@ namespace NLGUI ucstring ucValue; ucValue.fromUtf8(elm.getAttribute("value")); - uint size = 120; + uint size = 20; uint maxlength = 1024; if (elm.hasNonEmptyAttribute("size")) fromString(elm.getAttribute("size"), size); if (elm.hasNonEmptyAttribute("maxlength")) fromString(elm.getAttribute("maxlength"), maxlength); + // ryzom client used to have 'size' attribute in pixels, (12 == was default font size) + if (_Style.hasStyle("-ryzom-input-size-px") && _Style.getStyle("-ryzom-input-size-px") == "true") + size = size / 12; + string textTemplate(!templateName.empty() ? templateName : DefaultFormTextGroup); // Add the editbox - CInterfaceGroup *textArea = addTextArea (textTemplate, name.c_str (), 1, size/12, false, ucValue, maxlength); + CInterfaceGroup *textArea = addTextArea (textTemplate, name.c_str (), 1, size, false, ucValue, maxlength); if (textArea) { // Add the text area to the form From 5940e276fb8c3094954fe294ca03d1d6bc9df926 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 20:53:53 +0300 Subject: [PATCH 25/35] Fixed: Strip whitespace between table elements --HG-- branch : html-improvements --- code/nel/src/gui/group_html.cpp | 48 ++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 08325333f..2e34ad8fa 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -2643,31 +2643,49 @@ namespace NLGUI // Keep this char ? bool keep = true; + // char is between table elements + // TODO: only whitespace is handled, text is added to either TD, or after TABLE (should be before) + bool tableWhitespace = getTable() && (_Cells.empty() || _Cells.back() == NULL); + switch (input) { // Return / tab only in
 mode
 		case '\t':
 		case '\n':
 			{
-				// Get the last char
-				ucchar lastChar = lastCharParam;
-				if (lastChar == 0)
-					lastChar = getLastChar();
-				keep = ((lastChar != (ucchar)' ') &&
-						(lastChar != 0)) || getPRE() || (_CurrentViewImage && (lastChar == 0));
-				if(!getPRE())
-					input = ' ';
+				if (tableWhitespace)
+				{
+					keep = false;
+				}
+				else
+				{
+					// Get the last char
+					ucchar lastChar = lastCharParam;
+					if (lastChar == 0)
+						lastChar = getLastChar();
+					keep = ((lastChar != (ucchar)' ') &&
+							(lastChar != 0)) || getPRE() || (_CurrentViewImage && (lastChar == 0));
+					if(!getPRE())
+						input = ' ';
+				}
 			}
 			break;
 		case ' ':
 			{
-				// Get the last char
-				ucchar lastChar = lastCharParam;
-				if (lastChar == 0)
-					lastChar = getLastChar();
-				keep = ((lastChar != (ucchar)' ') &&
-						(lastChar != (ucchar)'\n') &&
-						(lastChar != 0)) || getPRE() || (_CurrentViewImage && (lastChar == 0));
+				if (tableWhitespace)
+				{
+					keep = false;
+				}
+				else
+				{
+					// Get the last char
+					ucchar lastChar = lastCharParam;
+					if (lastChar == 0)
+						lastChar = getLastChar();
+					keep = ((lastChar != (ucchar)' ') &&
+							(lastChar != (ucchar)'\n') &&
+							(lastChar != 0)) || getPRE() || (_CurrentViewImage && (lastChar == 0));
+				}
 			}
 			break;
 		case 0xd:

From d3c609820797d0767a6108ad22d646a80b688cca Mon Sep 17 00:00:00 2001
From: Nimetu 
Date: Thu, 12 Sep 2019 18:15:09 +0300
Subject: [PATCH 26/35] Fixed: Browser css file could not be loaded from bnp

--HG--
branch : html-improvements
---
 code/nel/include/nel/misc/file.h |  5 +++++
 code/nel/src/gui/group_html.cpp  | 18 +++++++++++++++---
 code/nel/src/misc/file.cpp       | 31 +++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/code/nel/include/nel/misc/file.h b/code/nel/include/nel/misc/file.h
index 78dba95c6..3e40d122a 100644
--- a/code/nel/include/nel/misc/file.h
+++ b/code/nel/include/nel/misc/file.h
@@ -119,6 +119,11 @@ public:		// Advanced Usage.
 	// return a string separated by \n or eof, used to parsing text file
 	void getline (char *buffer, uint32 bufferSize);
 
+	// read whole file into a string. resulting buffer may contain NULL chars.
+	// internal read position is modified.
+	// return true on success, false on failure.
+	bool readAll(std::string &buffer);
+
 	// return the size of the file
 	uint32 getFileSize () const { return _FileSize; }
 
diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp
index 2e34ad8fa..b6b83fa3c 100644
--- a/code/nel/src/gui/group_html.cpp
+++ b/code/nel/src/gui/group_html.cpp
@@ -2175,12 +2175,24 @@ namespace NLGUI
 				std::string filename = CPath::lookup(_BrowserCssFile, false, true, true);
 				if (!filename.empty())
 				{
-					NLMISC::CSString css;
-					if (css.readFromFile(filename))
+					CIFile in;
+					if (in.open(filename))
 					{
-						_BrowserStyle.parseStylesheet(css);
+						std::string css;
+						if (in.readAll(css))
+							_BrowserStyle.parseStylesheet(css);
+						else
+							nlwarning("Failed to read browser css from '%s'", filename.c_str());
+					}
+					else
+					{
+						nlwarning("Failed to open browser css file '%s'", filename.c_str());
 					}
 				}
+				else
+				{
+					nlwarning("Browser css file '%s' not found", _BrowserCssFile.c_str());
+				}
 			}
 		}
 		else
diff --git a/code/nel/src/misc/file.cpp b/code/nel/src/misc/file.cpp
index 63b27e768..834b11a8d 100644
--- a/code/nel/src/misc/file.cpp
+++ b/code/nel/src/misc/file.cpp
@@ -361,6 +361,37 @@ void		CIFile::flush()
 	}
 }
 
+// ======================================================================================================
+bool	CIFile::readAll(std::string &buffer)
+{
+	try
+	{
+		uint32 remaining = _FileSize;
+
+		buffer.clear();
+		buffer.reserve(_FileSize);
+		while(!eof() && remaining > 0)
+		{
+			const static uint bufsize = 1024;
+			char buf[bufsize];
+			uint32 readnow = bufsize;
+			if (readnow > remaining)
+				readnow = remaining;
+
+			serialBuffer((uint8 *)&buf[0], readnow);
+			buffer.append(buf, readnow);
+			remaining -= readnow;
+		}
+	}
+	catch (const EFile &)
+	{
+		// buffer state is unknown
+		return false;
+	}
+
+	return true;
+}
+
 // ======================================================================================================
 void		CIFile::getline (char *buffer, uint32 bufferSize)
 {

From c6dc92e0ec56ccfc898d4d432eb9ec758e50d813 Mon Sep 17 00:00:00 2001
From: Nimetu 
Date: Thu, 12 Sep 2019 19:34:32 +0300
Subject: [PATCH 27/35] Fixed: Cleanup of table/cell border

--HG--
branch : html-improvements
---
 code/nel/include/nel/gui/group_table.h |  1 +
 code/nel/src/gui/group_html.cpp        |  2 --
 code/nel/src/gui/group_table.cpp       | 10 ++++++++++
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/code/nel/include/nel/gui/group_table.h b/code/nel/include/nel/gui/group_table.h
index ccc2ce3cf..52839e14b 100644
--- a/code/nel/include/nel/gui/group_table.h
+++ b/code/nel/include/nel/gui/group_table.h
@@ -41,6 +41,7 @@ namespace NLGUI
         DECLARE_UI_CLASS( CGroupCell )
 
 		CGroupCell(const TCtorParam ¶m);
+		~CGroupCell();
 
 		enum TAlign
 		{
diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp
index b6b83fa3c..fcb1f58f0 100644
--- a/code/nel/src/gui/group_html.cpp
+++ b/code/nel/src/gui/group_html.cpp
@@ -6614,8 +6614,6 @@ namespace NLGUI
 			uint32 borderWidth = 0;
 			CRGBA borderColor = CRGBA::Transparent;
 
-			// TODO: _Style->hasBorder() ??
-			table->Border = new CSSBorderRenderer();
 			if (elm.hasAttribute("border"))
 			{
 				std::string s = elm.getAttribute("border");
diff --git a/code/nel/src/gui/group_table.cpp b/code/nel/src/gui/group_table.cpp
index 6f61b7571..6f4e93741 100644
--- a/code/nel/src/gui/group_table.cpp
+++ b/code/nel/src/gui/group_table.cpp
@@ -73,6 +73,16 @@ namespace NLGUI
 		addGroup (Group);
 	}
 
+	// ----------------------------------------------------------------------------
+	CGroupCell::~CGroupCell()
+	{
+		if (Border)
+		{
+			delete Border;
+			Border = NULL;
+		}
+	}
+
 	// ----------------------------------------------------------------------------
 	void CGroupCell::setEnclosedGroupDefaultParams()
 	{

From 0ef7419fd6f309718e1045584fd5c9984307230d Mon Sep 17 00:00:00 2001
From: Nimetu 
Date: Sat, 14 Sep 2019 15:26:21 +0300
Subject: [PATCH 28/35] Fixed: Wrong border size when border hidden/none

--HG--
branch : html-improvements
---
 code/nel/src/gui/group_table.cpp | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/code/nel/src/gui/group_table.cpp b/code/nel/src/gui/group_table.cpp
index 6f4e93741..fa6279ad7 100644
--- a/code/nel/src/gui/group_table.cpp
+++ b/code/nel/src/gui/group_table.cpp
@@ -1134,7 +1134,9 @@ namespace NLGUI
 					if (cell->NewLine)
 					{
 						column = 0;
-						currentX = Border->LeftWidth + CellSpacing;
+						currentX = CellSpacing;
+						if (Border)
+							currentX += Border->getLeftWidth();
 
 						_Rows.push_back(CRow());
 					}
@@ -1412,7 +1414,9 @@ namespace NLGUI
 			maxWidth += columns[i];
 
 		// TODO: CellPadding is probably already in columns width
-		maxWidth += Border->LeftWidth + Border->RightWidth + ((sint32)columns.size()+1) * CellSpacing + ((sint32)columns.size()*2) * CellPadding;
+		maxWidth += ((sint32)columns.size()+1) * CellSpacing + ((sint32)columns.size()*2) * CellPadding;
+		if (Border)
+			maxWidth += Border->getLeftRightWidth();
 
 		return maxWidth;
 	}
@@ -1458,7 +1462,9 @@ namespace NLGUI
 			maxWidth += columns[i];
 
 		// TODO: CellPadding is probably already in columns width
-		maxWidth += Border->LeftWidth + Border->RightWidth + ((sint32)columns.size()+1) * CellSpacing + ((sint32)columns.size()*2) * CellPadding;
+		maxWidth += ((sint32)columns.size()+1) * CellSpacing + ((sint32)columns.size()*2) * CellPadding;
+		if (Border)
+			maxWidth += Border->getLeftRightWidth();
 
 		return maxWidth;
 	}
@@ -1556,12 +1562,16 @@ namespace NLGUI
 	{
 		if( name == "border" )
 		{
-			return toString( Border->TopWidth );
+			if (Border)
+				return toString( Border->TopWidth );
+			return "0";
 		}
 		else
 		if( name == "bordercolor" )
 		{
-			return toString( Border->TopColor );
+			if (Border)
+				return toString( Border->TopColor );
+			return toString(CRGBA::Transparent);
 		}
 		else
 		if( name == "cellpadding" )
@@ -1597,6 +1607,8 @@ namespace NLGUI
 			sint32 i;
 			if( fromString( value, i ) )
 			{
+				if (!Border)
+					Border = new CSSBorderRenderer();
 				Border->TopWidth = i;
 				Border->RightWidth = i;
 				Border->BottomWidth = i;
@@ -1610,6 +1622,8 @@ namespace NLGUI
 			CRGBA c;
 			if( fromString( value, c ) )
 			{
+				if (!Border)
+					Border = new CSSBorderRenderer();
 				Border->TopColor = c;
 				Border->RightColor = c;
 				Border->BottomColor = c;
@@ -1659,8 +1673,11 @@ namespace NLGUI
 			return NULL;
 
 		xmlSetProp( node, BAD_CAST "type", BAD_CAST "table" );
-		xmlSetProp( node, BAD_CAST "border", BAD_CAST toString( Border->TopWidth ).c_str() );
-		xmlSetProp( node, BAD_CAST "bordercolor", BAD_CAST toString( Border->TopColor ).c_str() );
+		if (Border)
+		{
+			xmlSetProp( node, BAD_CAST "border", BAD_CAST toString( Border->TopWidth ).c_str() );
+			xmlSetProp( node, BAD_CAST "bordercolor", BAD_CAST toString( Border->TopColor ).c_str() );
+		}
 		xmlSetProp( node, BAD_CAST "cellpadding", BAD_CAST toString( CellPadding ).c_str() );
 		xmlSetProp( node, BAD_CAST "cellspacing", BAD_CAST toString( CellSpacing ).c_str() );
 		xmlSetProp( node, BAD_CAST "bgcolor", BAD_CAST toString( BgColor ).c_str() );

From 79fd4cf8d7421562daa2631140683c4a3561026a Mon Sep 17 00:00:00 2001
From: Nimetu 
Date: Sat, 14 Sep 2019 15:27:33 +0300
Subject: [PATCH 29/35] Changed: refactor

--HG--
branch : html-improvements
---
 code/nel/include/nel/gui/css_style.h |  12 +--
 code/nel/src/gui/css_style.cpp       | 124 +++++++++++++--------------
 2 files changed, 68 insertions(+), 68 deletions(-)

diff --git a/code/nel/include/nel/gui/css_style.h b/code/nel/include/nel/gui/css_style.h
index 50dd3180a..b4e751ac8 100644
--- a/code/nel/include/nel/gui/css_style.h
+++ b/code/nel/include/nel/gui/css_style.h
@@ -162,16 +162,16 @@ namespace NLGUI
 		bool getShorthandIndices(const uint32 size, uint8 &t, uint8 &r, uint8 &b, uint8 &l) const;
 
 		// break 'border' into 'border-top-color', 'border-top-style', etc rules
-		bool tryBorderWidthShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const;
-		bool tryBorderStyleShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const;
-		bool tryBorderColorShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const;
-		void parseBorderShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const;
+		bool tryBorderWidthShorthand(const std::string &prop, const std::string &value, TStyle &style) const;
+		bool tryBorderStyleShorthand(const std::string &prop, const std::string &value, TStyle &style) const;
+		bool tryBorderColorShorthand(const std::string &prop, const std::string &value, TStyle &style) const;
+		void expandBorderShorthand(const std::string &prop, const std::string &value, TStyle &style) const;
 
 		// parse 'background' into 'background-color', 'background-image', etc
-		void parseBackgroundShorthand(const std::string &value, CStyleParams &style) const;
+		void expandBackgroundShorthand(const std::string &value, TStyle &style) const;
 
 		// parse 'padding' into 'padding-top', 'padding-left', etc
-		void parsePaddingShorthand(const std::string &value, CStyleParams &style) const;
+		void expandPaddingShorthand(const std::string &value, TStyle &style) const;
 
 		// parse string value into corresponding value
 		void applyBorderWidth(const std::string &value, uint32 *dest, const uint32 currentWidth, const uint32 fontSize) const;
diff --git a/code/nel/src/gui/css_style.cpp b/code/nel/src/gui/css_style.cpp
index 888044e5c..79565acfa 100644
--- a/code/nel/src/gui/css_style.cpp
+++ b/code/nel/src/gui/css_style.cpp
@@ -434,7 +434,7 @@ namespace NLGUI
 			else
 			if (it->first == "background")
 			{
-				parseBackgroundShorthand(it->second, style);
+				expandBackgroundShorthand(it->second, style.StyleRules);
 			}
 			else
 			if (it->first == "background-repeat")
@@ -464,25 +464,25 @@ namespace NLGUI
 				|| it->first == "border-bottom" || it->first == "border-left")
 			{
 				// TODO: use enum or bitmap constant instead of passing a string name (it->first)
-				parseBorderShorthand(it->second, style, it->first);
+				expandBorderShorthand(it->first, it->second, style.StyleRules);
 				keep = false;
 			}
 			else
 			if (it->first == "border-width")
 			{
-				tryBorderWidthShorthand(it->second, style, it->first);
+				tryBorderWidthShorthand(it->first, it->second, style.StyleRules);
 				keep = false;
 			}
 			else
 			if (it->first == "border-style")
 			{
-				tryBorderStyleShorthand(it->second, style, it->first);
+				tryBorderStyleShorthand(it->first, it->second, style.StyleRules);
 				keep = false;
 			}
 			else
 			if (it->first == "border-color")
 			{
-				tryBorderColorShorthand(it->second, style, it->first);
+				tryBorderColorShorthand(it->first, it->second, style.StyleRules);
 				keep = false;
 			}
 			else
@@ -496,7 +496,7 @@ namespace NLGUI
 			else
 			if (it->first == "padding")
 			{
-				parsePaddingShorthand(it->second, style);
+				expandPaddingShorthand(it->second, style.StyleRules);
 				keep = false;
 			}
 
@@ -983,7 +983,7 @@ namespace NLGUI
 	}
 
 	// ***************************************************************************
-	void CCssStyle::parseBackgroundShorthand(const std::string &value, CStyleParams &style) const
+	void CCssStyle::expandBackgroundShorthand(const std::string &value, TStyle &style) const
 	{
 		// background: url(image.jpg) top center / 200px 200px no-repeat fixed padding-box content-box red;
 		// background-image      : url(image.jpg)
@@ -1261,16 +1261,16 @@ namespace NLGUI
 			{
 				if (props[i] == "background-position")
 				{
-					style.StyleRules["background-position-x"] = bgPositionX;
-					style.StyleRules["background-position-y"] = bgPositionY;
+					style["background-position-x"] = bgPositionX;
+					style["background-position-y"] = bgPositionY;
 				}
 				else if (props[i] == "background-clip")
 				{
-					style.StyleRules["background-clip"] = bgClipValue;
+					style["background-clip"] = bgClipValue;
 				}
 				else
 				{
-					style.StyleRules[props[i]] = values[i];
+					style[props[i]] = values[i];
 				}
 			}
 			else
@@ -1278,40 +1278,40 @@ namespace NLGUI
 				// fill in default if one is set
 				if (props[i] == "background-image")
 				{
-					style.StyleRules[props[i]] = "none";
+					style[props[i]] = "none";
 				}
 				else if (props[i] == "background-position")
 				{
-					style.StyleRules[props[i]] = "0% 0%";
-					style.StyleRules["background-position-x"] = "left 0%";
-					style.StyleRules["background-position-y"] = "top 0%";
+					style[props[i]] = "0% 0%";
+					style["background-position-x"] = "left 0%";
+					style["background-position-y"] = "top 0%";
 				}
 				else if (props[i] == "background-size")
 				{
-					style.StyleRules[props[i]] = "auto auto";
+					style[props[i]] = "auto auto";
 				}
 				else if (props[i] == "background-repeat")
 				{
-					style.StyleRules[props[i]] = "repeat";
+					style[props[i]] = "repeat";
 				}
 				else if(props[i] == "background-attachment")
 				{
-					style.StyleRules[props[i]] = "scroll";
+					style[props[i]] = "scroll";
 				}
 				else if(props[i] == "background-origin")
 				{
-					style.StyleRules[props[i]] = "padding-box";
+					style[props[i]] = "padding-box";
 				}
 				else if (props[i] == "background-clip")
 				{
 					if (bgClipFound)
-						style.StyleRules[props[i]] = bgClipValue;
+						style[props[i]] = bgClipValue;
 					else
-						style.StyleRules[props[i]] = "border-box";
+						style[props[i]] = "border-box";
 				}
 				else if (props[i] == "background-color")
 				{
-					style.StyleRules[props[i]] = "transparent";
+					style[props[i]] = "transparent";
 				}
 			}
 		}
@@ -1349,7 +1349,7 @@ namespace NLGUI
 	}
 
 	// ***************************************************************************
-	bool CCssStyle::tryBorderWidthShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const
+	bool CCssStyle::tryBorderWidthShorthand(const std::string &prop, const std::string &value, TStyle &style) const
 	{
 		std::vector parts;
 		NLMISC::splitString(toLower(value), " ", parts);
@@ -1378,15 +1378,15 @@ namespace NLGUI
 
 		uint8 t, r, b, l;
 		if (!getShorthandIndices(parts.size(), t, r, b, l)) return false;
-		if (hasTop) style.StyleRules["border-top-width"] = parts[t];
-		if (hasRight) style.StyleRules["border-right-width"] = parts[r];
-		if (hasBottom) style.StyleRules["border-bottom-width"] = parts[b];
-		if (hasLeft) style.StyleRules["border-left-width"] = parts[l];
+		if (hasTop) style["border-top-width"] = parts[t];
+		if (hasRight) style["border-right-width"] = parts[r];
+		if (hasBottom) style["border-bottom-width"] = parts[b];
+		if (hasLeft) style["border-left-width"] = parts[l];
 
 		return true;
 	}
 	// ***************************************************************************
-	bool CCssStyle::tryBorderStyleShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const
+	bool CCssStyle::tryBorderStyleShorthand(const std::string &prop, const std::string &value, TStyle &style) const
 	{
 		std::vector parts;
 		NLMISC::splitString(toLower(value), " ", parts);
@@ -1427,15 +1427,15 @@ namespace NLGUI
 
 		uint8 t, r, b, l;
 		if (!getShorthandIndices(parts.size(), t, r, b, l)) return false;
-		if (hasTop) style.StyleRules["border-top-style"] = parts[t];
-		if (hasRight) style.StyleRules["border-right-style"] = parts[r];
-		if (hasBottom) style.StyleRules["border-bottom-style"] = parts[b];
-		if (hasLeft) style.StyleRules["border-left-style"] = parts[l];
+		if (hasTop) style["border-top-style"] = parts[t];
+		if (hasRight) style["border-right-style"] = parts[r];
+		if (hasBottom) style["border-bottom-style"] = parts[b];
+		if (hasLeft) style["border-left-style"] = parts[l];
 
 		return true;
 	}
 	// ***************************************************************************
-	bool CCssStyle::tryBorderColorShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const
+	bool CCssStyle::tryBorderColorShorthand(const std::string &prop, const std::string &value, TStyle &style) const
 	{
 		std::vector parts;
 		NLMISC::splitString(toLower(value), " ", parts);
@@ -1460,16 +1460,16 @@ namespace NLGUI
 
 		uint8 t, r, b, l;
 		if (!getShorthandIndices(parts.size(), t, r, b, l)) return false;
-		if (hasTop) style.StyleRules["border-top-color"] = parts[t];
-		if (hasRight) style.StyleRules["border-right-color"] = parts[r];
-		if (hasBottom) style.StyleRules["border-bottom-color"] = parts[b];
-		if (hasLeft) style.StyleRules["border-left-color"] = parts[l];
+		if (hasTop) style["border-top-color"] = parts[t];
+		if (hasRight) style["border-right-color"] = parts[r];
+		if (hasBottom) style["border-bottom-color"] = parts[b];
+		if (hasLeft) style["border-left-color"] = parts[l];
 
 		return true;
 	}
 
 	// ***************************************************************************
-	void CCssStyle::parseBorderShorthand(const std::string &value, CStyleParams &style, const std::string &prop) const
+	void CCssStyle::expandBorderShorthand(const std::string &prop, const std::string &value, TStyle &style) const
 	{
 		// border: 1px solid #000;
 		bool hasTop    = (prop == "border" || prop == "border-top");
@@ -1481,7 +1481,7 @@ namespace NLGUI
 		bool foundStyle = false;
 		bool foundColor = false;
 
-		CStyleParams borderStyle;
+		TStyle borderStyle;
 		std::vector parts;
 		NLMISC::splitString(toLower(value), " ", parts);
 
@@ -1490,17 +1490,17 @@ namespace NLGUI
 			bool matched = false;
 			if (!foundWidth)
 			{
-				matched = foundWidth = tryBorderWidthShorthand(parts[index], borderStyle, prop);
+				matched = foundWidth = tryBorderWidthShorthand(prop, parts[index], borderStyle);
 			}
 
 			if (!matched && !foundStyle)
 			{
-				matched = foundStyle = tryBorderStyleShorthand(parts[index], borderStyle, prop);
+				matched = foundStyle = tryBorderStyleShorthand(prop, parts[index], borderStyle);
 			}
 
 			if (!matched && !foundColor)
 			{
-				matched = foundColor = tryBorderColorShorthand(parts[index], borderStyle, prop);
+				matched = foundColor = tryBorderColorShorthand(prop, parts[index], borderStyle);
 			}
 
 			// invalid rule if nothing gets matched
@@ -1511,41 +1511,41 @@ namespace NLGUI
 		}
 
 		// apply rules that are present
-		TStyle::const_iterator it = borderStyle.StyleRules.begin();
-		while(it != borderStyle.StyleRules.end())
+		TStyle::const_iterator it = borderStyle.begin();
+		while(it != borderStyle.end())
 		{
-			style.StyleRules[it->first] = it->second;
+			style[it->first] = it->second;
 			++it;
 		}
 
 		// reset those not present
 		if (!foundWidth)
 		{
-			if (hasTop) style.StyleRules["border-top-width"] = "medium";
-			if (hasRight) style.StyleRules["border-right-width"] = "medium";
-			if (hasBottom) style.StyleRules["border-bottom-width"] = "medium";
-			if (hasLeft) style.StyleRules["border-left-width"] = "medium";
+			if (hasTop) style["border-top-width"] = "medium";
+			if (hasRight) style["border-right-width"] = "medium";
+			if (hasBottom) style["border-bottom-width"] = "medium";
+			if (hasLeft) style["border-left-width"] = "medium";
 		}
 		//
 		if (!foundStyle)
 		{
-			if (hasTop) style.StyleRules["border-top-style"] = "none";
-			if (hasRight) style.StyleRules["border-right-style"] = "none";
-			if (hasBottom) style.StyleRules["border-bottom-style"] = "none";
-			if (hasLeft) style.StyleRules["border-left-style"] = "none";
+			if (hasTop) style["border-top-style"] = "none";
+			if (hasRight) style["border-right-style"] = "none";
+			if (hasBottom) style["border-bottom-style"] = "none";
+			if (hasLeft) style["border-left-style"] = "none";
 		}
 		//
 		if (!foundColor)
 		{
-			if (hasTop) style.StyleRules["border-top-color"] = "currentcolor";
-			if (hasRight) style.StyleRules["border-right-color"] = "currentcolor";
-			if (hasBottom) style.StyleRules["border-bottom-color"] = "currentcolor";
-			if (hasLeft) style.StyleRules["border-left-color"] = "currentcolor";
+			if (hasTop) style["border-top-color"] = "currentcolor";
+			if (hasRight) style["border-right-color"] = "currentcolor";
+			if (hasBottom) style["border-bottom-color"] = "currentcolor";
+			if (hasLeft) style["border-left-color"] = "currentcolor";
 		}
 	}
 
 	// ***************************************************************************
-	void CCssStyle::parsePaddingShorthand(const std::string &value, CStyleParams &style) const
+	void CCssStyle::expandPaddingShorthand(const std::string &value, TStyle &style) const
 	{
 		std::vector parts;
 		NLMISC::splitString(toLower(value), " ", parts);
@@ -1554,10 +1554,10 @@ namespace NLGUI
 		if (!getShorthandIndices(parts.size(), t, r, b, l))
 			return;
 
-		style.StyleRules["padding-top"] = parts[t];
-		style.StyleRules["padding-right"] = parts[r];
-		style.StyleRules["padding-bottom"] = parts[b];
-		style.StyleRules["padding-left"] = parts[l];
+		style["padding-top"] = parts[t];
+		style["padding-right"] = parts[r];
+		style["padding-bottom"] = parts[b];
+		style["padding-left"] = parts[l];
 	}
 
 	// ***************************************************************************

From 963a9814da53364d30ce07a3d458c97a2ae3f6ea Mon Sep 17 00:00:00 2001
From: Nimetu 
Date: Sat, 14 Sep 2019 15:27:36 +0300
Subject: [PATCH 30/35] Changed: refactor css shorthand expansion to own method

--HG--
branch : html-improvements
---
 code/nel/include/nel/gui/css_style.h |   4 +
 code/nel/src/gui/css_style.cpp       | 120 +++++++++++++--------------
 2 files changed, 63 insertions(+), 61 deletions(-)

diff --git a/code/nel/include/nel/gui/css_style.h b/code/nel/include/nel/gui/css_style.h
index b4e751ac8..b553881d1 100644
--- a/code/nel/include/nel/gui/css_style.h
+++ b/code/nel/include/nel/gui/css_style.h
@@ -173,6 +173,10 @@ namespace NLGUI
 		// parse 'padding' into 'padding-top', 'padding-left', etc
 		void expandPaddingShorthand(const std::string &value, TStyle &style) const;
 
+		// expand shorthand rule, ie "border", into longhand names, ie "border-top-width"
+		// if shorthand is present in style, then its removed
+		void expandShorthand(const std::string &prop, const std::string &value, TStyle &style) const;
+
 		// parse string value into corresponding value
 		void applyBorderWidth(const std::string &value, uint32 *dest, const uint32 currentWidth, const uint32 fontSize) const;
 		void applyBorderColor(const std::string &value, NLMISC::CRGBA *dest, const NLMISC::CRGBA ¤tColor, const NLMISC::CRGBA &textColor) const;
diff --git a/code/nel/src/gui/css_style.cpp b/code/nel/src/gui/css_style.cpp
index 79565acfa..3f13dbb10 100644
--- a/code/nel/src/gui/css_style.cpp
+++ b/code/nel/src/gui/css_style.cpp
@@ -338,13 +338,9 @@ namespace NLGUI
 	// - normalize values
 	void CCssStyle::normalize(const TStyle &styleRules, CStyleParams &style, const CStyleParams ¤t) const
 	{
-		bool keep = true;
 		TStyle::const_iterator it;
 		for (it=styleRules.begin(); it != styleRules.end(); ++it)
 		{
-			// shorthands will be replaced with proper statements  and shorthand rule is removed
-			keep = true;
-
 			// update local copy of applied style
 			style.StyleRules[it->first] = it->second;
 
@@ -432,11 +428,6 @@ namespace NLGUI
 				}
 			}
 			else
-			if (it->first == "background")
-			{
-				expandBackgroundShorthand(it->second, style.StyleRules);
-			}
-			else
 			if (it->first == "background-repeat")
 			{
 				// old ryzom specific value
@@ -444,48 +435,6 @@ namespace NLGUI
 					style.StyleRules[it->first] = "repeat";
 			}
 			else
-			if (it->first == "background-scale")
-			{
-				// replace old ryzom specific rule with background-size
-				if (it->second != "1")
-				{
-					style.StyleRules["background-size"] = "auto";
-				}
-				else
-				{
-					style.StyleRules["background-size"] = "100%";
-				}
-
-				keep = false;
-			}
-			else
-			if (it->first == "border"
-				|| it->first == "border-top" || it->first == "border-right"
-				|| it->first == "border-bottom" || it->first == "border-left")
-			{
-				// TODO: use enum or bitmap constant instead of passing a string name (it->first)
-				expandBorderShorthand(it->first, it->second, style.StyleRules);
-				keep = false;
-			}
-			else
-			if (it->first == "border-width")
-			{
-				tryBorderWidthShorthand(it->first, it->second, style.StyleRules);
-				keep = false;
-			}
-			else
-			if (it->first == "border-style")
-			{
-				tryBorderStyleShorthand(it->first, it->second, style.StyleRules);
-				keep = false;
-			}
-			else
-			if (it->first == "border-color")
-			{
-				tryBorderColorShorthand(it->first, it->second, style.StyleRules);
-				keep = false;
-			}
-			else
 			if (it->first == "display")
 			{
 				if (it->second == "inherit")
@@ -494,17 +443,8 @@ namespace NLGUI
 					style.DisplayBlock = (it->second == "block" || it->second == "table");
 			}
 			else
-			if (it->first == "padding")
 			{
-				expandPaddingShorthand(it->second, style.StyleRules);
-				keep = false;
-			}
-
-			if (!keep)
-			{
-				TStyle::iterator pos = style.StyleRules.find(it->first);
-				if (pos != style.StyleRules.end())
-					style.StyleRules.erase(pos);
+				expandShorthand(it->first, it->second, style.StyleRules);
 			}
 		}
 	}
@@ -1560,6 +1500,64 @@ namespace NLGUI
 		style["padding-left"] = parts[l];
 	}
 
+	// ***************************************************************************
+	void CCssStyle::expandShorthand(const std::string &prop, const std::string &value, TStyle &style) const
+	{
+		// if shorthand matches, then remove it after expansion
+		bool keep = false;
+
+		if (prop == "background")
+		{
+			expandBackgroundShorthand(value, style);
+		}
+		else if (prop == "background-scale")
+		{
+			// replace old ryzom specific rule with background-size
+			if (value != "1")
+			{
+				style["background-size"] = "auto";
+			}
+			else
+			{
+				style["background-size"] = "100%";
+			}
+		}
+		else if (prop == "border"
+			|| prop == "border-top" || prop == "border-right"
+			|| prop == "border-bottom" || prop == "border-left")
+		{
+			// TODO: use enum or bitmap constant instead of passing a string name (prop)
+			expandBorderShorthand(prop, value, style);
+		}
+		else if (prop == "border-width")
+		{
+			tryBorderWidthShorthand(prop, value, style);
+		}
+		else if (prop == "border-style")
+		{
+			tryBorderStyleShorthand(prop, value, style);
+		}
+		else if (prop == "border-color")
+		{
+			tryBorderColorShorthand(prop, value, style);
+		}
+		else if (prop == "padding")
+		{
+			expandPaddingShorthand(value, style);
+		}
+		else
+		{
+			keep = true;
+		}
+
+		if (!keep)
+		{
+			TStyle::iterator pos = style.find(prop);
+			if (pos != style.end())
+				style.erase(pos);
+		}
+	}
+
 	// ***************************************************************************
 	void CCssStyle::applyCssMinMax(sint32 &width, sint32 &height, sint32 minw, sint32 minh, sint32 maxw, sint32 maxh) const
 	{

From d7c754039e3a6377a0e428b22ea8fde3bccc33c5 Mon Sep 17 00:00:00 2001
From: Nimetu 
Date: Sat, 14 Sep 2019 15:27:37 +0300
Subject: [PATCH 31/35] Fixed: shorthand/longhand properties handled in wrong
 order

--HG--
branch : html-improvements
---
 code/nel/include/nel/gui/css_parser.h |  2 +-
 code/nel/include/nel/gui/css_style.h  |  6 ++++--
 code/nel/src/gui/css_parser.cpp       |  8 ++++----
 code/nel/src/gui/css_style.cpp        | 20 +++++++++++---------
 4 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/code/nel/include/nel/gui/css_parser.h b/code/nel/include/nel/gui/css_parser.h
index cfaf03caa..a6dc92022 100644
--- a/code/nel/include/nel/gui/css_parser.h
+++ b/code/nel/include/nel/gui/css_parser.h
@@ -31,7 +31,7 @@ namespace NLGUI
 	class CCssParser {
 	public:
 		// parse style declaration, eg "color: red; font-size: 10px;"
-		static TStyle parseDecls(const std::string &styleString);
+		static TStyleVec parseDecls(const std::string &styleString);
 
 		// parse css stylesheet
 		void parseStylesheet(const std::string &cssString, std::vector &rules);
diff --git a/code/nel/include/nel/gui/css_style.h b/code/nel/include/nel/gui/css_style.h
index b553881d1..4eabe26ba 100644
--- a/code/nel/include/nel/gui/css_style.h
+++ b/code/nel/include/nel/gui/css_style.h
@@ -27,6 +27,8 @@ namespace NLGUI
 	class CHtmlElement;
 
 	typedef std::map TStyle;
+	typedef std::pair TStylePair;
+	typedef std::vector TStyleVec;
 
 	/**
 	 * \brief CSS style rules
@@ -118,7 +120,7 @@ namespace NLGUI
 
 		struct SStyleRule {
 			std::vector Selector;
-			TStyle Properties;
+			TStyleVec Properties;
 
 			// pseudo element like ':before'
 			std::string PseudoElement;
@@ -153,7 +155,7 @@ namespace NLGUI
 		void apply(CStyleParams &style, const CStyleParams ¤t) const;
 
 		// merge src into dest by overwriting key in dest
-		void merge(TStyle &dst, const TStyle &src) const;
+		void merge(TStyle &dst, const TStyleVec &src) const;
 
 		// match selector to dom path
 		bool match(const std::vector &selector, const CHtmlElement &elm) const;
diff --git a/code/nel/src/gui/css_parser.cpp b/code/nel/src/gui/css_parser.cpp
index 39a4496bc..e59cf832b 100644
--- a/code/nel/src/gui/css_parser.cpp
+++ b/code/nel/src/gui/css_parser.cpp
@@ -35,9 +35,9 @@ namespace NLGUI
 	//
 	// key is converted to lowercase
 	// value is left as is
-	TStyle CCssParser::parseDecls(const std::string &styleString)
+	TStyleVec CCssParser::parseDecls(const std::string &styleString)
 	{
-		TStyle styles;
+		TStyleVec styles;
 		std::vector elements;
 		NLMISC::splitString(styleString, ";", elements);
 
@@ -49,7 +49,7 @@ namespace NLGUI
 			{
 				std::string key = trim(toLower(elements[i].substr(0, pos)));
 				std::string value = trim(elements[i].substr(pos+1));
-				styles[key] = value;
+				styles.push_back(TStylePair(key, value));
 			}
 		}
 
@@ -94,7 +94,7 @@ namespace NLGUI
 		std::vector selectors;
 		NLMISC::explode(selectorString, ucstring(","), selectors);
 
-		TStyle props;
+		TStyleVec props;
 		props = parseDecls(styleString.toUtf8());
 
 		// duplicate props to each selector in selector list,
diff --git a/code/nel/src/gui/css_style.cpp b/code/nel/src/gui/css_style.cpp
index 3f13dbb10..4555de6c9 100644
--- a/code/nel/src/gui/css_style.cpp
+++ b/code/nel/src/gui/css_style.cpp
@@ -102,7 +102,9 @@ namespace NLGUI
 				}
 				else
 				{
-					elm.setPseudo(i->PseudoElement, i->Properties);
+					TStyle props;
+					merge(props, i->Properties);
+					elm.setPseudo(i->PseudoElement, props);
 				}
 			}
 		}
@@ -110,17 +112,18 @@ namespace NLGUI
 		// style from "style" attribute overrides