From a5aa8e48a5516f00ce93e7d967fd9f076a3587dd Mon Sep 17 00:00:00 2001 From: Nimetu Date: Wed, 31 Jul 2019 20:56:55 +0300 Subject: [PATCH 01/54] 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/54] 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/54] 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 efaadfe12118c0a9629f07edbb377d4ec37be688 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Thu, 23 May 2019 14:40:18 +0300 Subject: [PATCH 04/54] Added: Missing properties to item CItemImage --HG-- branch : feature-item-icon-buffs --- code/ryzom/client/src/interface_v3/inventory_manager.cpp | 6 +++++- code/ryzom/client/src/interface_v3/inventory_manager.h | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/code/ryzom/client/src/interface_v3/inventory_manager.cpp b/code/ryzom/client/src/interface_v3/inventory_manager.cpp index e4ce2b6e9..139d45370 100644 --- a/code/ryzom/client/src/interface_v3/inventory_manager.cpp +++ b/code/ryzom/client/src/interface_v3/inventory_manager.cpp @@ -127,6 +127,8 @@ CItemImage::CItemImage() Sheet = NULL; Quality = NULL; Quantity = NULL; + CreateTime = NULL; + Serial = NULL; UserColor = NULL; Price = NULL; Weight= NULL; @@ -141,6 +143,8 @@ void CItemImage::build(CCDBNodeBranch *branch) Sheet = dynamic_cast(branch->getNode(ICDBNode::CTextId("SHEET"), false)); Quality = dynamic_cast(branch->getNode(ICDBNode::CTextId("QUALITY"), false)); Quantity = dynamic_cast(branch->getNode(ICDBNode::CTextId("QUANTITY"), false)); + CreateTime = dynamic_cast(branch->getNode(ICDBNode::CTextId("CREATE_TIME"), false)); + Serial = dynamic_cast(branch->getNode(ICDBNode::CTextId("SERIAL"), false)); UserColor = dynamic_cast(branch->getNode(ICDBNode::CTextId("USER_COLOR"), false)); Price = dynamic_cast(branch->getNode(ICDBNode::CTextId("PRICE"), false)); Weight = dynamic_cast(branch->getNode(ICDBNode::CTextId("WEIGHT"), false)); @@ -149,7 +153,7 @@ void CItemImage::build(CCDBNodeBranch *branch) ResaleFlag = dynamic_cast(branch->getNode(ICDBNode::CTextId("RESALE_FLAG"), false)); // Should always have at least those one:(ie all but Price) - nlassert(Sheet && Quality && Quantity && UserColor && Weight && NameId && InfoVersion); + nlassert(Sheet && Quality && Quantity && CreateTime && Serial && UserColor && Weight && NameId && InfoVersion); } // ************************************************************************************************* diff --git a/code/ryzom/client/src/interface_v3/inventory_manager.h b/code/ryzom/client/src/interface_v3/inventory_manager.h index 0fa6fd2ee..f33277fc4 100644 --- a/code/ryzom/client/src/interface_v3/inventory_manager.h +++ b/code/ryzom/client/src/interface_v3/inventory_manager.h @@ -60,6 +60,8 @@ public: NLMISC::CCDBNodeLeaf *Sheet; NLMISC::CCDBNodeLeaf *Quality; NLMISC::CCDBNodeLeaf *Quantity; + NLMISC::CCDBNodeLeaf *CreateTime; + NLMISC::CCDBNodeLeaf *Serial; NLMISC::CCDBNodeLeaf *UserColor; NLMISC::CCDBNodeLeaf *Price; NLMISC::CCDBNodeLeaf *Weight; @@ -76,6 +78,8 @@ public: uint32 getSheetID() const { return (uint32) (Sheet ? Sheet->getValue32() : 0); } uint16 getQuality() const { return (uint16) (Quality ? Quality->getValue16() : 0); } uint16 getQuantity() const { return (uint16) (Quantity ? Quantity->getValue16() : 0); } + uint32 getCreateTime() const { return (uint32) (CreateTime ? CreateTime->getValue32() : 0); } + uint32 getSerial() const { return (uint32) (Serial ? Serial->getValue32() : 0); } uint8 getUserColor() const { return (uint8) (UserColor ? UserColor->getValue16() : 0); } uint32 getPrice() const { return (uint32) (Price ? Price->getValue32() : 0); } uint32 getWeight() const { return (uint32) (Weight ? Weight->getValue32() : 0); } @@ -87,6 +91,8 @@ public: void setSheetID(uint32 si) { if (Sheet) Sheet->setValue32((sint32) si); } void setQuality(uint16 quality) { if (Quality) Quality->setValue16((sint16) quality); } void setQuantity(uint16 quantity) { if (Quantity) Quantity->setValue16((sint16) quantity); } + void setCreateTime(uint32 create_time) { if (CreateTime) CreateTime->setValue32((sint32) create_time); } + void setSerial(uint32 serial) { if (Serial) Serial->setValue32((sint32) serial); } void setUserColor(uint8 uc) { if (UserColor) UserColor->setValue8((sint8) uc); } void setPrice(uint32 price) { if (Price) Price->setValue32((sint32) price); } void setWeight(uint32 wgt) { if (Weight) Weight->setValue32((sint32) wgt); } From 4636e328857eef6e1426a215483cbd83b3004525 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Tue, 28 May 2019 21:50:41 +0300 Subject: [PATCH 05/54] Fixed: Add missing properties to trade/mission item db --HG-- branch : feature-item-icon-buffs --- .../client/src/interface_v3/obs_huge_list.cpp | 19 ++++++++++++++++++- .../client/src/interface_v3/obs_huge_list.h | 6 ++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/code/ryzom/client/src/interface_v3/obs_huge_list.cpp b/code/ryzom/client/src/interface_v3/obs_huge_list.cpp index 76506ed57..03c2d973a 100644 --- a/code/ryzom/client/src/interface_v3/obs_huge_list.cpp +++ b/code/ryzom/client/src/interface_v3/obs_huge_list.cpp @@ -161,6 +161,8 @@ bool CHugeListObs::init() case Trading: _Items[k].SlotType = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SLOT_TYPE").c_str(), (int) k), false); _Items[k].Quality = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:QUALITY").c_str(), (int) k), false); + _Items[k].Serial = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SERIAL").c_str(), (int) k), false); + _Items[k].CreateTime = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:CREATE_TIME").c_str(), (int) k), false); _Items[k].SheetIDOrSkill = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SHEET").c_str(), (int) k), false); _Items[k].Price = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:PRICE").c_str(), (int) k), false); _Items[k].Weight = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:WEIGHT").c_str(), (int) k), false); @@ -181,6 +183,7 @@ bool CHugeListObs::init() if ((_Items[k].SlotType == NULL) || (_Items[k].Quality == NULL) || (_Items[k].SheetIDOrSkill == NULL) || (_Items[k].Price == NULL) || (_Items[k].Weight==NULL) || (_Items[k].InfoVersion==NULL) || (_Items[k].UserColor==NULL) || (_Items[k].NameId==NULL) || (_Items[k].Quantity==NULL) || + (_Items[k].Serial == NULL) || (_Items[k].CreateTime == NULL) || (_Items[k].PriceRetire==NULL) || (_Items[k].SellerType==NULL) || (_Items[k].ResaleTimeLeft==NULL) || (_Items[k].VendorNameId==NULL) || (_Items[k].Enchant ==NULL) || (_Items[k].RMClassType == NULL) || (_Items[k].RMFaberStatType == NULL) || (_Items[k].PrerequisitValid == NULL) || @@ -191,6 +194,8 @@ bool CHugeListObs::init() case ItemForMissions: _Items[k].SlotType = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SLOT_TYPE").c_str(), (int) k), false); _Items[k].Quality = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:QUALITY").c_str(), (int) k), false); + _Items[k].Serial = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SERIAL").c_str(), (int) k), false); + _Items[k].CreateTime = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:CREATE_TIME").c_str(), (int) k), false); _Items[k].SheetIDOrSkill = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:SHEET").c_str(), (int) k), false); _Items[k].LogicTextID = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:LOGIC_TEXT_ID").c_str(), (int) k), false); _Items[k].DescTextID = NLGUI::CDBManager::getInstance()->getDbProp(toString((dbPath + ":%d:DESC_TEXT_ID").c_str(), (int) k), false); @@ -205,7 +210,7 @@ bool CHugeListObs::init() (_Items[k].LogicTextID == NULL) || (_Items[k].DescTextID == NULL) || (_Items[k].Weight==NULL) || (_Items[k].InfoVersion==NULL) || (_Items[k].UserColor==NULL) || (_Items[k].Enchant ==NULL) || (_Items[k].RMClassType == NULL) || (_Items[k].RMFaberStatType == NULL) || - (_Items[k].NameId==NULL) + (_Items[k].NameId==NULL) || (_Items[k].Serial == NULL) || (_Items[k].CreateTime == NULL) ) return false; break; @@ -383,6 +388,8 @@ void CHugeListObs::update(ICDBNode * /* node */) { page.Items[k].SlotType = (TRADE_SLOT_TYPE::TTradeSlotType) _Items[k].SlotType->getValue32(); page.Items[k].Quality = (uint16) _Items[k].Quality->getValue16(); + page.Items[k].Serial = (uint32) _Items[k].Serial->getValue32(); + page.Items[k].CreateTime = (uint32) _Items[k].CreateTime->getValue32(); page.Items[k].SheetIDOrSkill = (uint32) _Items[k].SheetIDOrSkill->getValue32(); page.Items[k].Price = (uint32) _Items[k].Price->getValue32(); page.Items[k].Weight= (uint16) _Items[k].Weight->getValue16(); @@ -420,6 +427,8 @@ void CHugeListObs::update(ICDBNode * /* node */) case ItemForMissions: page.Items[k].SlotType = (TRADE_SLOT_TYPE::TTradeSlotType) _Items[k].SlotType->getValue32(); page.Items[k].Quality = (uint16) _Items[k].Quality->getValue16(); + page.Items[k].Serial = (uint32) _Items[k].Serial->getValue32(); + page.Items[k].CreateTime = (uint32) _Items[k].CreateTime->getValue32(); page.Items[k].SheetIDOrSkill = (uint32) _Items[k].SheetIDOrSkill->getValue32(); page.Items[k].LogicTextID = (uint32) _Items[k].LogicTextID->getValue32(); page.Items[k].DescTextID = (uint32) _Items[k].DescTextID->getValue32(); @@ -569,6 +578,10 @@ void CHugeListObs::updateUIItemPage(uint index) case Trading: leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":QUALITY", false); if (leaf) leaf->setValue32(currItem.Quality); + leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SERIAL", false); + if (leaf) leaf->setValue32(currItem.Serial); + leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":CREATE_TIME", false); + if (leaf) leaf->setValue32(currItem.CreateTime); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SLOT_TYPE", false); if (leaf) leaf->setValue32(currItem.SlotType); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SHEET", false); @@ -610,6 +623,10 @@ void CHugeListObs::updateUIItemPage(uint index) case ItemForMissions: leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":QUALITY", false); if (leaf) leaf->setValue32(currItem.Quality); + leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SERIAL", false); + if (leaf) leaf->setValue32(currItem.Serial); + leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":CREATE_TIME", false); + if (leaf) leaf->setValue32(currItem.CreateTime); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SLOT_TYPE", false); if (leaf) leaf->setValue32(currItem.SlotType); leaf = NLGUI::CDBManager::getInstance()->getDbProp(dbPath + toString(k + index * TRADE_PAGE_NUM_ITEMS) + ":SHEET", false); diff --git a/code/ryzom/client/src/interface_v3/obs_huge_list.h b/code/ryzom/client/src/interface_v3/obs_huge_list.h index 64ef38252..480d31540 100644 --- a/code/ryzom/client/src/interface_v3/obs_huge_list.h +++ b/code/ryzom/client/src/interface_v3/obs_huge_list.h @@ -124,6 +124,8 @@ private: // NLMISC::CCDBNodeLeaf *SlotType; NLMISC::CCDBNodeLeaf *Quality; + NLMISC::CCDBNodeLeaf *Serial; + NLMISC::CCDBNodeLeaf *CreateTime; NLMISC::CCDBNodeLeaf *SheetIDOrSkill; // NLMISC::CCDBNodeLeaf *LogicTextID; // valid if the item is to be obtained for a mission @@ -157,6 +159,8 @@ private: GuildName(NULL), SlotType(NULL), Quality(NULL), + Serial(NULL), + CreateTime(NULL), SheetIDOrSkill(NULL), LogicTextID(NULL), DescTextID(NULL), @@ -216,6 +220,8 @@ private: TRADE_SLOT_TYPE::TTradeSlotType SlotType; uint16 Quality; + uint32 Serial; + uint32 CreateTime; uint32 SheetIDOrSkill; uint32 LogicTextID; // Valid if the item is to be obtained as a mission reward uint32 DescTextID; // Valid if the item is to be obtained as a mission reward From e0a1cd3c4a526b4491d5820ab2bb4723d2f5a84c Mon Sep 17 00:00:00 2001 From: Nimetu Date: Thu, 23 May 2019 09:04:00 +0300 Subject: [PATCH 06/54] Changed: Cache extra item info responses from server --HG-- branch : feature-item-icon-buffs --- code/ryzom/client/src/commands.cpp | 7 + .../src/interface_v3/inventory_manager.cpp | 341 +++++++++++++++++- .../src/interface_v3/inventory_manager.h | 43 ++- 3 files changed, 369 insertions(+), 22 deletions(-) diff --git a/code/ryzom/client/src/commands.cpp b/code/ryzom/client/src/commands.cpp index 07d84461c..074079780 100644 --- a/code/ryzom/client/src/commands.cpp +++ b/code/ryzom/client/src/commands.cpp @@ -4493,6 +4493,13 @@ NLMISC_COMMAND(debugItemInfoWaiters, "log ItemInfoWaiters", "") return true; } +NLMISC_COMMAND(debugItemInfoCache, "log ItemInfoCache", "") +{ + getInventory().debugItemInfoCache(); + + return true; +} + NLMISC_COMMAND(debugInfoWindows, "log info windows sheetId", "") { CInterfaceHelp::debugOpenedInfoWindows(); diff --git a/code/ryzom/client/src/interface_v3/inventory_manager.cpp b/code/ryzom/client/src/interface_v3/inventory_manager.cpp index 139d45370..78966338a 100644 --- a/code/ryzom/client/src/interface_v3/inventory_manager.cpp +++ b/code/ryzom/client/src/interface_v3/inventory_manager.cpp @@ -58,6 +58,8 @@ using namespace std; using namespace NLMISC; +extern TSessionId CharacterHomeSessionId; + extern NLMISC::CLog g_log; // Context help extern void contextHelp (const std::string &help); @@ -156,6 +158,144 @@ void CItemImage::build(CCDBNodeBranch *branch) nlassert(Sheet && Quality && Quantity && CreateTime && Serial && UserColor && Weight && NameId && InfoVersion); } +uint64 CItemImage::getItemId() const +{ + return ((uint64)getSerial() << 32) | getCreateTime(); +} + +// ************************************************************************************************* +void CItemInfoCache::load(const std::string &filename) +{ + try + { + CIFile f; + if (f.open(filename)) + { + serial(f); + } + } catch(...) + { } +} + +void CItemInfoCache::save(const std::string &filename) +{ + try + { + COFile f; + if (f.open(filename)) + { + serial(f); + } + }catch(...) + { } +} + +void CItemInfoCache::serial(NLMISC::IStream &s) +{ + s.serialCheck(NELID("METI")); + uint ver = 1; + s.serialVersion(ver); + + uint8 byte = 1; + if (s.isReading()) + { + _ItemInfoCacheMap.clear(); + while(true) + { + uint64 key; + + s.serial(byte); + if (byte == 0) + { + break; + } + s.serial(key); + s.serial(_ItemInfoCacheMap[key].CacheCycle); + _ItemInfoCacheMap[key].serial(s); + + // these are not used in item info cache + _ItemInfoCacheMap[key].InfoVersionFromMsg = 0; + _ItemInfoCacheMap[key].InfoVersionFromSlot = 0; + _ItemInfoCacheMap[key].InfoVersionSlotServerWaiting = 0; + } + } + else + { + byte = 1; + TItemInfoCacheMap::iterator it = _ItemInfoCacheMap.begin(); + while (it != _ItemInfoCacheMap.end()) + { + // purge item from cache if not encountered in X save + if (it->second.CacheCycle < 10000) + { + // 'record exists' byte + s.serial(byte); + + // item id (serial << 32 | createTime) + uint64 key = it->first; + s.serial(key); + + uint32 cycle = it->second.CacheCycle+1; + s.serial(cycle); + + // item info + it->second.serial(s); + } + + ++it; + } + // eof of records byte + byte = 0; + s.serial(byte); + } +} + +const CClientItemInfo *CItemInfoCache::getItemInfo(uint32 serial, uint32 createTime) const +{ + if (serial > 0 && createTime > 0) + { + uint64 itemId = ((uint64)serial << 32) | createTime; + return getItemInfo(itemId); + } + + return NULL; +} + +const CClientItemInfo *CItemInfoCache::getItemInfo(uint64 itemId) const +{ + if (itemId > 0) + { + TItemInfoCacheMap::const_iterator it = _ItemInfoCacheMap.find(itemId); + if (it != _ItemInfoCacheMap.end()) + return &(it->second); + } + + return NULL; +} + +void CItemInfoCache::readFromImpulse(uint64 itemId, CItemInfos itemInfo) +{ + if (itemId > 0) + { + _ItemInfoCacheMap[itemId].readFromImpulse(itemInfo); + _ItemInfoCacheMap[itemId].CacheCycle = 0; + } +} + +void CItemInfoCache::debugItemInfoCache() const +{ + nlinfo("ItemInfoCache: %d entries", _ItemInfoCacheMap.size()); + uint count = 0; + for (auto it = _ItemInfoCacheMap.begin(); it != _ItemInfoCacheMap.end(); ++it) + { + uint32 serial = (it->first >> 32) & 0xFFFFFFFF; + uint32 created = it->first & 0xFFFFFFFF; + nlinfo("[%-4d] cacheCycle:%d, serial:%d, createTime:%d", count++, it->second.CacheCycle, serial, created); + } + CInterfaceManager *pIM= CInterfaceManager::getInstance(); + pIM->displaySystemInfo(toString("ItemInfoCache: %d entries written to client.log", _ItemInfoCacheMap.size())); +} + // ************************************************************************************************* // CInventoryManager // ************************************************************************************************* @@ -184,12 +324,16 @@ CInventoryManager::CInventoryManager() BagItemEquipped[i]= false; } + _ItemInfoCacheFilename = toString("save/item_infos_%d.cache", CharacterHomeSessionId.asInt()); + _ItemInfoCache.load(_ItemInfoCacheFilename); + nlctassert(NumInventories== sizeof(InventoryIndexes)/sizeof(InventoryIndexes[0])); } // *************************************************************************** CInventoryManager::~CInventoryManager() { + _ItemInfoCache.save(_ItemInfoCacheFilename); } // ************************************************************************************************* @@ -261,6 +405,11 @@ CItemImage &CInventoryManager::getServerBagItem(uint index) nlassert(index < MAX_BAGINV_ENTRIES); return ServerBag[index]; } +const CItemImage &CInventoryManager::getServerBagItem(uint index) const +{ + nlassert(index < MAX_BAGINV_ENTRIES); + return ServerBag[index]; +} // ************************************************************************************************* CItemImage &CInventoryManager::getServerTempItem(uint index) @@ -268,6 +417,11 @@ CItemImage &CInventoryManager::getServerTempItem(uint index) nlassert(index < MAX_TEMPINV_ENTRIES); return ServerTempInv[index]; } +const CItemImage &CInventoryManager::getServerTempItem(uint index) const +{ + nlassert(index < MAX_TEMPINV_ENTRIES); + return ServerTempInv[index]; +} // ************************************************************************************************* CItemImage *CInventoryManager::getServerHandItem(uint index) @@ -1740,12 +1894,12 @@ void CTempInvManager::update() // show/hide weight info depending on temp inventory mode bool displayWeight = (_Mode == TEMP_INV_MODE::Craft); - CViewBase *weightText = dynamic_cast(pGC->getView("weight_txt")); - if (weightText != NULL) + CViewBase *weightText = dynamic_cast(pGC->getView("weight_txt")); + if (weightText != NULL) weightText->setActive(displayWeight); CViewBase *weightImg = dynamic_cast(pGC->getView("weight")); if (weightImg != NULL) - weightImg->setActive(displayWeight); + weightImg->setActive(displayWeight); if (_Mode == TEMP_INV_MODE::Forage) { @@ -2182,24 +2336,24 @@ bool SBagOptions::canDisplay(CDBCtrlSheet *pCS) const return false; // Armor - if ((pIS->Family == ITEMFAMILY::ARMOR) || + if ((pIS->Family == ITEMFAMILY::ARMOR) || (pIS->Family == ITEMFAMILY::JEWELRY)) if (!bFilterArmor) bDisplay = false; // Weapon - if ((pIS->Family == ITEMFAMILY::SHIELD) || + if ((pIS->Family == ITEMFAMILY::SHIELD) || (pIS->Family == ITEMFAMILY::MELEE_WEAPON) || - (pIS->Family == ITEMFAMILY::RANGE_WEAPON) || + (pIS->Family == ITEMFAMILY::RANGE_WEAPON) || (pIS->Family == ITEMFAMILY::AMMO) || - (pIS->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) || + (pIS->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) || (pIS->Family == ITEMFAMILY::ITEM_SAP_RECHARGE) || (pIS->Family == ITEMFAMILY::BRICK) ) if (!bFilterWeapon) bDisplay = false; // Tool - if ((pIS->Family == ITEMFAMILY::CRAFTING_TOOL) || + if ((pIS->Family == ITEMFAMILY::CRAFTING_TOOL) || (pIS->Family == ITEMFAMILY::HARVEST_TOOL) || - (pIS->Family == ITEMFAMILY::TAMING_TOOL) || + (pIS->Family == ITEMFAMILY::TAMING_TOOL) || (pIS->Family == ITEMFAMILY::TRAINING_TOOL) || (pIS->Family == ITEMFAMILY::BAG)) if (!bFilterTool) bDisplay = false; @@ -3266,22 +3420,53 @@ uint CInventoryManager::getItemSheetForSlotId(uint slotId) const return 0; } +// *************************************************************************** +const CClientItemInfo *CInventoryManager::getItemInfoCache(uint32 serial, uint32 createTime) const +{ + return _ItemInfoCache.getItemInfo(serial, createTime); +} + // *************************************************************************** const CClientItemInfo &CInventoryManager::getItemInfo(uint slotId) const { TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId); static CClientItemInfo empty; - if(it==_ItemInfoMap.end()) + if (it == _ItemInfoMap.end() || !isItemInfoUpToDate(slotId)) + { + // if slot has not been populated yet or out of date, then return info from cache if possible + const CItemImage *item = getServerItem(slotId); + if (item && item->getItemId() > 0) { + const CClientItemInfo *ret = _ItemInfoCache.getItemInfo(item->getItemId()); + if (ret != NULL) + { + return *ret; + } + } + } + + if (it == _ItemInfoMap.end()) + { return empty; - else - return it->second; + } + + return it->second; } // *************************************************************************** -bool CInventoryManager::isItemInfoUpToDate(uint slotId) +bool CInventoryManager::isItemInfoAvailable(uint slotId) const +{ + TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId); + return it != _ItemInfoMap.end(); +} +// *************************************************************************** +bool CInventoryManager::isItemInfoUpToDate(uint slotId) const { + TItemInfoMap::const_iterator it= _ItemInfoMap.find(slotId); + if (it == _ItemInfoMap.end()) + return true; + // true if the version already matches - return getItemInfo(slotId).InfoVersionFromMsg == getItemInfo(slotId).InfoVersionFromSlot; + return it->second.InfoVersionFromMsg == it->second.InfoVersionFromSlot; } // *************************************************************************** @@ -3318,8 +3503,10 @@ void CInventoryManager::removeItemInfoWaiter(IItemInfoWaiter *waiter) void CInventoryManager::updateItemInfoWaiters(uint itemSlotId) { // First verify if the versions matches. If differ, no need to update waiters since not good. - if(getItemInfo(itemSlotId).InfoVersionFromMsg != getItemInfo(itemSlotId).InfoVersionFromSlot) + if (!isItemInfoUpToDate(itemSlotId)) + { return; + } bool isItemFromTrading= (itemSlotId>>CItemInfos::SlotIdIndexBitSize)==INVENTORIES::trading; @@ -3413,10 +3600,15 @@ void CInventoryManager::onReceiveItemSheet(ICDBNode* node) // *************************************************************************** void CInventoryManager::onReceiveItemInfo(const CItemInfos &itemInfo) { - uint itemSlotId; - // update the Info - itemSlotId= itemInfo.slotId; + uint itemSlotId = itemInfo.slotId; + + const CItemImage *item = getServerItem(itemSlotId); + if (item && item->getItemId() > 0) + { + _ItemInfoCache.readFromImpulse(item->getItemId(), itemInfo); + } + // write in map, from DB. _ItemInfoMap[itemSlotId].readFromImpulse(itemInfo); @@ -3430,7 +3622,7 @@ void CInventoryManager::onReceiveItemInfo(const CItemInfos &itemInfo) // *************************************************************************** void CInventoryManager::onRefreshItemInfoVersion(uint16 slotId, uint8 infoVersion) { - _ItemInfoMap[slotId].refreshInfoVersion( infoVersion ); + _ItemInfoMap[slotId].refreshInfoVersion(infoVersion); } // *************************************************************************** @@ -3526,13 +3718,19 @@ void CInventoryManager::debugItemInfoWaiters() } } +// *************************************************************************** +void CInventoryManager::debugItemInfoCache() const +{ + _ItemInfoCache.debugItemInfoCache(); +} + // *************************************************************************** void CInventoryManager::sortBag() { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CDBGroupIconListBag *pIconList; CDBGroupListSheetBag *pList; - + pIconList = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(LIST_BAG_ICONS)); if (pIconList != NULL) pIconList->needToSort(); pList = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(LIST_BAG_TEXT)); @@ -3681,6 +3879,14 @@ CItemImage &CInventoryManager::getServerPAItem(uint beastIndex, uint index) return ServerPAInv[beastIndex][index]; } +const CItemImage &CInventoryManager::getServerPAItem(uint beastIndex, uint index) const +{ + nlassert(beastIndex < MAX_INVENTORY_ANIMAL); + nlassert(index < MAX_ANIMALINV_ENTRIES); + return ServerPAInv[beastIndex][index]; +} + + // *************************************************************************** CItemImage &CInventoryManager::getLocalItem(uint inv, uint index) { @@ -3707,6 +3913,93 @@ CItemImage &CInventoryManager::getServerItem(uint inv, uint index) return dummy; } +// *************************************************************************** +const CItemImage *CInventoryManager::getServerItem(uint slotId) const +{ + uint inv, index; + getSlotInvIndex(slotId, inv, index); + + if (inv == INVENTORIES::bag) + { + return &getServerBagItem(index); + } + else if (inv >= INVENTORIES::pet_animal && inv getDbBranch("SERVER:GUILD:INVENTORY:" + toString(index)); + if (itemBranch) + { + static CItemImage image; + image.build(itemBranch); + return ℑ + } + } + return NULL; + } + else if (inv == INVENTORIES::player_room) + { + // player is in their room + if (getInventory().isInventoryAvailable(INVENTORIES::player_room)) + { + CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch(SERVER_INVENTORY ":ROOM:" + toString(index)); + if (itemBranch) + { + static CItemImage image; + image.build(itemBranch); + return ℑ + } + } + return NULL; + } + else if (inv == INVENTORIES::trading) + { + CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:TRADING:" + toString(index)); + if (itemBranch) + { + static CItemImage image; + image.build(itemBranch); + return ℑ + } + } + else if (inv == INVENTORIES::exchange) + { + CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:EXCHANGE:GIVE:" + toString(index)); + if (itemBranch) + { + static CItemImage image; + image.build(itemBranch); + return ℑ + } + } + else if (inv == INVENTORIES::exchange_proposition) + { + CCDBNodeBranch *itemBranch = NLGUI::CDBManager::getInstance()->getDbBranch("LOCAL:EXCHANGE:RECEIVE:" + toString(index)); + if (itemBranch) + { + static CItemImage image; + image.build(itemBranch); + return ℑ + } + } + else + { + nlwarning("getServerItem: invalid inventory %d for slotId %d", inv, slotId); + } + + // invalid inventory + return NULL; +} + // *************************************************************************** CInventoryManager::TInvType CInventoryManager::invTypeFromString(const string &str) { @@ -3723,3 +4016,11 @@ CInventoryManager::TInvType CInventoryManager::invTypeFromString(const string &s if (sTmp == "inv_room") return InvRoom; return InvUnknown; } + +// *************************************************************************** +void CInventoryManager::getSlotInvIndex(uint slotId, uint &inv, uint &index) const +{ + inv = slotId >> CItemInfos::SlotIdIndexBitSize; + index = slotId & CItemInfos::SlotIdIndexBitMask; +} + diff --git a/code/ryzom/client/src/interface_v3/inventory_manager.h b/code/ryzom/client/src/interface_v3/inventory_manager.h index f33277fc4..7659409ca 100644 --- a/code/ryzom/client/src/interface_v3/inventory_manager.h +++ b/code/ryzom/client/src/interface_v3/inventory_manager.h @@ -74,6 +74,7 @@ public: CItemImage(); // build from a branch void build(NLMISC::CCDBNodeBranch *branch); + uint64 getItemId() const; // shortcuts to avoid NULL pointer tests uint32 getSheetID() const { return (uint32) (Sheet ? Sheet->getValue32() : 0); } uint16 getQuality() const { return (uint16) (Quality ? Quality->getValue16() : 0); } @@ -114,11 +115,15 @@ public: // This is the InfoVersionFromSlot when last request was sent to server uint16 InfoVersionSlotServerWaiting; + // Used to track cache age (reset on use, +1 on every save) + uint32 CacheCycle; + CClientItemInfo() { InfoVersionFromMsg= 0; InfoVersionFromSlot= 0; InfoVersionSlotServerWaiting= 0; + CacheCycle= 0; } /// Set InfoVersion from Info message (info requested by the player) @@ -128,6 +133,25 @@ public: void refreshInfoVersion(uint8 infoVersion) { InfoVersionFromMsg= infoVersion; } }; +class CItemInfoCache +{ +public: + void load(const std::string &filename); + void save(const std::string &filename); + void serial(NLMISC::IStream &s); + + // retrieve pointer to item info or null if error + const CClientItemInfo *getItemInfo(uint32 serial, uint32 createTime) const; + const CClientItemInfo *getItemInfo(uint64 itemId) const; + + // set/update item info in cache + void readFromImpulse(uint64 itemId, CItemInfos itemInfo); + void debugItemInfoCache() const; + +private: + typedef std::map TItemInfoCacheMap; + TItemInfoCacheMap _ItemInfoCacheMap; +}; class IItemInfoWaiter { @@ -195,8 +219,10 @@ public: // SERVER INVENTORY // get item of bag (local inventory) CItemImage &getServerBagItem(uint index); + const CItemImage &getServerBagItem(uint index) const; // get temporary item (local inventory) CItemImage &getServerTempItem(uint index); + const CItemImage &getServerTempItem(uint index) const; // get hand item (local inventory) CItemImage *getServerHandItem(uint index); // get equip item (local inventory) @@ -206,8 +232,11 @@ public: void setServerMoney(uint64 value); // get item of pack animal (server inventory). beastIndex ranges from 0 to MAX_INVENTORY_ANIMAL-1 CItemImage &getServerPAItem(uint beastIndex, uint index); + const CItemImage &getServerPAItem(uint beastIndex, uint index) const; // get the item Image for the given inventory. assert if bad inventory CItemImage &getServerItem(uint inv, uint index); + // get the item Image for the given slotId or NULL if bad + const CItemImage *getServerItem(uint slotId) const; // Drag'n'Drop Management enum TFrom { Slot, TextList, IconList, Nowhere }; @@ -273,9 +302,13 @@ public: uint16 getItemSlotId(CDBCtrlSheet *ctrl); uint16 getItemSlotId(const std::string &itemDb, uint slotIndex); const CClientItemInfo &getItemInfo(uint slotId) const; + // get item info from cache + const CClientItemInfo *getItemInfoCache(uint32 serial, uint32 createTime) const; uint getItemSheetForSlotId(uint slotId) const; + // Returns true if the item info is already in slot cache + bool isItemInfoAvailable(uint slotId) const; // Returns true if the item info version already matches - bool isItemInfoUpToDate(uint slotId); + bool isItemInfoUpToDate(uint slotId) const; // Add a Waiter on ItemInfo (ItemHelp opening). no-op if here, but reorder (returns true if the version already matches or if waiter is NULL) void addItemInfoWaiter(IItemInfoWaiter *waiter); // remove a Waiter on ItemInfo (ItemHelp closing). no-op if not here. NB: no delete @@ -285,6 +318,7 @@ public: void onRefreshItemInfoVersion(uint16 slotId, uint8 infoVersion); // Log for debug void debugItemInfoWaiters(); + void debugItemInfoCache() const; void sortBag(); @@ -300,6 +334,9 @@ public: enum TInvType { InvBag, InvPA0, InvPA1, InvPA2, InvPA3, InvPA4, InvPA5, InvPA6, InvGuild, InvRoom, InvUnknown }; static TInvType invTypeFromString(const std::string &str); + // inventory and slot from slotId + void getSlotInvIndex(uint slotId, uint &inv, uint &index) const; + private: // LOCAL INVENTORY @@ -324,7 +361,9 @@ private: CDBCtrlSheet *DNDCurrentItem; // ItemExtraInfo management. - typedef std::map TItemInfoMap; + std::string _ItemInfoCacheFilename; + CItemInfoCache _ItemInfoCache; + typedef std::map TItemInfoMap; TItemInfoMap _ItemInfoMap; typedef std::list TItemInfoWaiters; TItemInfoWaiters _ItemInfoWaiters; From 2f883ddb1d7f07d9e072a9fa0918ce4ac4da5ef3 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Wed, 22 May 2019 15:52:23 +0300 Subject: [PATCH 07/54] Changed: Display stat buff and enchant info on item icon --HG-- branch : feature-item-icon-buffs --- .../client/src/interface_v3/dbctrl_sheet.cpp | 429 ++++++++++++------ .../client/src/interface_v3/dbctrl_sheet.h | 56 ++- .../src/interface_v3/inventory_manager.h | 17 +- .../src/interface_v3/item_info_waiter.h | 39 ++ 4 files changed, 390 insertions(+), 151 deletions(-) create mode 100644 code/ryzom/client/src/interface_v3/item_info_waiter.h diff --git a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp index 1b9a7d720..f94a7f180 100644 --- a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp +++ b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp @@ -75,52 +75,52 @@ const uint64 NOTIFY_ANIM_MS_DURATION = 1000; // *************************************************************************** - - -// ********************************************************************************************************** -class CControlSheetTooltipInfoWaiter : public IItemInfoWaiter +void CControlSheetInfoWaiter::sendRequest() { -public: - // The item used to open this window - CDBCtrlSheet* CtrlSheet; - string LuaMethodName; -public: - ucstring infoValidated(CDBCtrlSheet* ctrlSheet, string luaMethodName); - virtual void infoReceived(); -}; -static CControlSheetTooltipInfoWaiter ControlSheetTooltipUpdater; + Requesting = true; + getInventory().addItemInfoWaiter(this); +} -void CControlSheetTooltipInfoWaiter::infoReceived() +void CControlSheetInfoWaiter::infoReceived() { - getInventory().removeItemInfoWaiter(&ControlSheetTooltipUpdater); - infoValidated(CtrlSheet, LuaMethodName); + if (!Requesting) { + return; + } + + getInventory().removeItemInfoWaiter(this); + infoValidated(); + CtrlSheet->infoReceived(); + Requesting = false; } -ucstring CControlSheetTooltipInfoWaiter::infoValidated(CDBCtrlSheet* ctrlSheet, string luaMethodName) +ucstring CControlSheetInfoWaiter::infoValidated() const { ucstring help; - // delegate setup of context he help ( & window ) to lua - CInterfaceManager *im = CInterfaceManager::getInstance(); - CLuaState *ls= CLuaManager::getInstance().getLuaState(); + if (CtrlSheet && !LuaMethodName.empty()) { - CLuaStackRestorer lsr(ls, 0); + // delegate setup of context he help ( & window ) to lua + CInterfaceManager *im = CInterfaceManager::getInstance(); + CLuaState *ls= CLuaManager::getInstance().getLuaState(); + { + CLuaStackRestorer lsr(ls, 0); - CLuaIHM::pushReflectableOnStack(*ls, (CReflectableRefPtrTarget *)ctrlSheet); - ls->pushGlobalTable(); - CLuaObject game(*ls); - game = game["game"]; - game.callMethodByNameNoThrow(luaMethodName.c_str(), 1, 1); + CLuaIHM::pushReflectableOnStack(*ls, (CReflectableRefPtrTarget *)CtrlSheet); + ls->pushGlobalTable(); + CLuaObject game(*ls); + game = game["game"]; + game.callMethodByNameNoThrow(LuaMethodName.c_str(), 1, 1); - // retrieve result from stack - if (!ls->empty()) - { - CLuaIHM::pop(*ls, help); - } - else - { - nlwarning(toString("Ucstring result expected when calling '%s', possible script error", luaMethodName.c_str()).c_str()); + // retrieve result from stack + if (!ls->empty()) + { + CLuaIHM::pop(*ls, help); + } + else + { + nlwarning(toString("Ucstring result expected when calling '%s', possible script error", LuaMethodName.c_str()).c_str()); + } } } @@ -137,7 +137,7 @@ int CDBCtrlSheet::luaGetDraggedSheet(CLuaState &ls) // *************************************************************************** int CDBCtrlSheet::luaGetItemInfo(CLuaState &ls) { - CDBCtrlSheet *ctrlSheet = const_cast(this); + CDBCtrlSheet *ctrlSheet = const_cast(this); uint32 itemSlotId = getInventory().getItemSlotId(ctrlSheet); CClientItemInfo itemInfo = getInventory().getItemInfo(itemSlotId); @@ -203,7 +203,7 @@ int CDBCtrlSheet::luaGetCreatorName(CLuaState &ls) ucstring creatorName; STRING_MANAGER::CStringManagerClient::instance()->getString(itemInfo.CreatorName, creatorName); CLuaIHM::push(ls, creatorName); - + return 1; } @@ -236,7 +236,6 @@ int CDBCtrlSheet::luaWaitInfo(CLuaState &ls) // *************************************************************************** int CDBCtrlSheet::luaBuildCrystallizedSpellListBrick(CLuaState &ls) { - CDBCtrlSheet *ctrlSheet = const_cast(this); uint32 itemSlotId= getInventory().getItemSlotId(ctrlSheet); @@ -257,7 +256,7 @@ int CDBCtrlSheet::luaBuildCrystallizedSpellListBrick(CLuaState &ls) } } - + // Reset other to 0. for(;;currentBrick++) { @@ -505,6 +504,7 @@ CCtrlDraggable(param) _Useable= true; _GrayedLink= NULL; _NeedSetup= true; + _ItemInfoChanged = true; _IconW = 0; _IconH = 0; _SetupInit= false; @@ -528,6 +528,11 @@ CCtrlDraggable(param) _ItemRMClassType= NULL; _ItemRMFaberStatType= NULL; _NotifyAnimEndTime = 0; + + _HpBuffIcon = "ico_heal.tga"; + _SapBuffIcon = "ico_sap.tga"; + _StaBuffIcon = "ico_stamina.tga"; + _FocusBuffIcon = "ico_focus.tga"; } // ---------------------------------------------------------------------------- @@ -535,6 +540,11 @@ CDBCtrlSheet::~CDBCtrlSheet() { NL3D::UDriver *Driver = CViewRenderer::getInstance()->getDriver(); + if (_ItemInfoWaiter.Requesting) + { + getInventory().removeItemInfoWaiter(&_ItemInfoWaiter); + } + if (_GuildBack) { if (Driver) @@ -613,6 +623,22 @@ bool CDBCtrlSheet::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup) prop = (char*) xmlGetProp( cur, (xmlChar*)"slot" ); if(prop) _DrawSlot= CInterfaceElement::convertBool(prop); + // + _HpBuffIcon = "ico_heal.tga"; + prop = (char*) xmlGetProp( cur, (xmlChar*)"hp_buff_icon" ); + if (prop) _HpBuffIcon = string((const char *)prop); + + _SapBuffIcon = "ico_sap.tga"; + prop = (char*) xmlGetProp( cur, (xmlChar*)"sap_buff_icon" ); + if (prop) _SapBuffIcon = string((const char *)prop); + + _StaBuffIcon = "ico_stamina.tga"; + prop = (char*) xmlGetProp( cur, (xmlChar*)"sta_buff_icon" ); + if (prop) _StaBuffIcon = string((const char *)prop); + + _FocusBuffIcon = "ico_focus.tga"; + prop = (char*) xmlGetProp( cur, (xmlChar*)"focus_buff_icon" ); + if (prop) _FocusBuffIcon = string((const char *)prop); updateActualType(); // Init size for Type @@ -1040,6 +1066,64 @@ void CDBCtrlSheet::updateIconSize() } } +// *************************************************************************** +void CDBCtrlSheet::infoReceived() +{ + if (!_ItemSheet) + { + return; + } + + const CClientItemInfo *itemInfo = getInventory().getItemInfoCache(getItemSerial(), getItemCreateTime()); + if (itemInfo == NULL) + { + // schedule for recheck on next draw() + _ItemInfoChanged = true; + return; + } + + // crystallized spell + { + _EnchantIcons.clear(); + CViewRenderer &rVR = *CViewRenderer::getInstance(); + CSBrickManager *pBM= CSBrickManager::getInstance(); + for(uint i=0; iEnchantment.Bricks.size(); ++i) + { + const CSBrickSheet *brick = pBM->getBrick(itemInfo->Enchantment.Bricks[i]); + if (brick) + { + if (!brick->isRoot() && !brick->isCredit() && !brick->isParameter()) + { + _EnchantIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(brick->getIcon()), brick->IconColor)); + rVR.getTextureSizeFromId(_EnchantIcons.back().TextureId, _EnchantIcons.back().IconW, _EnchantIcons.back().IconH); + } + else if (brick->isRoot()) + { + // there should be single root icon and it should be first one + _EnchantIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(brick->getIconBack()), brick->IconBackColor)); + rVR.getTextureSizeFromId(_EnchantIcons.back().TextureId, _EnchantIcons.back().IconW, _EnchantIcons.back().IconH); + } + } + } + } + + // buff icons + { + _BuffIcons.clear(); + CViewRenderer &rVR = *CViewRenderer::getInstance(); + + if (itemInfo->HpBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_HpBuffIcon))); + if (itemInfo->SapBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_SapBuffIcon))); + if (itemInfo->StaBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_StaBuffIcon))); + if (itemInfo->FocusBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_FocusBuffIcon))); + + // update sizes + for(uint i = 0; i < _BuffIcons.size(); ++i) + { + rVR.getTextureSizeFromId(_BuffIcons[i].TextureId, _BuffIcons[i].IconW, _BuffIcons[i].IconH); + } + } +} // *************************************************************************** void CDBCtrlSheet::setupPact() @@ -1103,6 +1187,7 @@ void CDBCtrlSheet::setupItem () CInterfaceManager *pIM= CInterfaceManager::getInstance(); sint32 sheet = _SheetId.getSInt32(); + // If this is the same sheet, need to resetup if (_LastSheetId != sheet || _NeedSetup) { @@ -1203,6 +1288,9 @@ void CDBCtrlSheet::setupItem () // Special Item requirement updateItemCharacRequirement(_LastSheetId); + + // update item info markers + _ItemInfoChanged = true; } else { @@ -1277,6 +1365,13 @@ void CDBCtrlSheet::setupItem () _Useable = CSkillManager::getInstance()->checkBaseSkillMetRequirement(_ItemSheet->RequiredSkill, _ItemSheet->RequiredSkillLevel); } */ + + // at each frame, update item info icon if changed + if (_ItemInfoChanged) + { + _ItemInfoChanged = false; + setupItemInfoWaiter(); + } } @@ -1857,7 +1952,7 @@ void CDBCtrlSheet::draw() CInterfaceManager *pIM = CInterfaceManager::getInstance(); CViewRenderer &rVR = *CViewRenderer::getInstance(); - + if (_Type != SheetType_Macro) { if (_LastSheetId != _SheetId.getSInt32()) @@ -1949,13 +2044,13 @@ void CDBCtrlSheet::draw() rVR.getTextureSizeFromId(frontTex, texWidth, texHeight); CQuadUV regenTris[5]; - uint numTris = buildPie(regenTris, 0.f, amount, texWidth); + uint numTris = buildPie(regenTris, 0.f, amount, texWidth); nlassert(numTris <= sizeofarray(regenTris)); for (uint tri = 0; tri < numTris; ++tri) { rVR.drawQuad(_RenderLayer + 1, regenTris[tri], frontTex, CRGBA::White, false); } - numTris = buildPie(regenTris, amount, 1.f, texWidth); + numTris = buildPie(regenTris, amount, 1.f, texWidth); nlassert(numTris <= sizeofarray(regenTris)); for (uint tri = 0; tri < numTris; ++tri) { @@ -1977,7 +2072,7 @@ void CDBCtrlSheet::draw() if (texId != -1) { sint32 texWidth, texHeight; - rVR.getTextureSizeFromId(texId, texWidth, texHeight); + rVR.getTextureSizeFromId(texId, texWidth, texHeight); const float freq0 = 1.f; const float phase0 = 0.f; const float freq1 = -1.f; @@ -1994,20 +2089,20 @@ void CDBCtrlSheet::draw() // ---------------------------------------------------------------------------- void CDBCtrlSheet::drawRotatedQuad(CViewRenderer &vr, float angle, float scale, uint renderLayer, uint32 texId, sint32 texWidth, sint32 texHeight) { - NLMISC::CQuadUV quv; + NLMISC::CQuadUV quv; float cosA = cosf(angle); float sinA = sinf(angle); // - quv.V0.set(_XReal + 0.5f * _WReal + 0.5f * scale * texWidth * (- cosA + sinA), + quv.V0.set(_XReal + 0.5f * _WReal + 0.5f * scale * texWidth * (- cosA + sinA), _YReal + 0.5f * _HReal + 0.5f * scale * texHeight * (- sinA - cosA), 0.5f); // - quv.V1.set(_XReal + 0.5f * _WReal + 0.5f * scale * texWidth * (cosA + sinA), + quv.V1.set(_XReal + 0.5f * _WReal + 0.5f * scale * texWidth * (cosA + sinA), _YReal + 0.5f * _HReal + 0.5f * scale * texHeight * (sinA - cosA), 0.5f); // - quv.V2.set(_XReal + 0.5f * _WReal + 0.5f * scale * texWidth * (cosA - sinA), - _YReal + 0.5f * _HReal + 0.5f * scale * texHeight * (sinA + cosA), 0.5f); + quv.V2.set(_XReal + 0.5f * _WReal + 0.5f * scale * texWidth * (cosA - sinA), + _YReal + 0.5f * _HReal + 0.5f * scale * texHeight * (sinA + cosA), 0.5f); // - quv.V3.set(_XReal + 0.5f * _WReal + 0.5f * scale * texWidth * (- cosA - sinA), + quv.V3.set(_XReal + 0.5f * _WReal + 0.5f * scale * texWidth * (- cosA - sinA), _YReal + 0.5f * _HReal + 0.5f * scale * texHeight * (- sinA + cosA), 0.5f); // quv.Uv0.set(0.f, 0.f); @@ -2022,13 +2117,13 @@ void CDBCtrlSheet::drawRotatedQuad(CViewRenderer &vr, float angle, float scale, // ---------------------------------------------------------------------------- inline void CDBCtrlSheet::uvToScreen(float x, float y, CVector &screenPos, uint texSize) const { - screenPos.set(_XReal + texSize * x, _YReal + texSize * (1.f - y), 0.5f); + screenPos.set(_XReal + texSize * x, _YReal + texSize * (1.f - y), 0.5f); } // ---------------------------------------------------------------------------- void CDBCtrlSheet::buildPieCorner(float angle, CUV &uv, CVector &pos, uint texSize) const -{ +{ float radAngle = angle * 2.f * float(NLMISC::Pi); // angle origin is at 12'o'clock float x = cosf(0.5f * float(NLMISC::Pi) - radAngle); @@ -2061,33 +2156,33 @@ void CDBCtrlSheet::buildPieCorner(float angle, CUV &uv, CVector &pos, uint texSi y /= -x; x = -1.f; } - } + } // remap to unit quad // (well we could have worked with tan() too, I find it simpler this way ....) uv.set(0.5f * x + 0.5f, 0.5f - 0.5f * y); - uvToScreen(uv.U, uv.V, pos, texSize); + uvToScreen(uv.U, uv.V, pos, texSize); } // ---------------------------------------------------------------------------- uint CDBCtrlSheet::buildPie(CQuadUV *triPtr, float startAngle, float endAngle, uint texSize) -{ +{ static volatile bool exit1 = false; nlassert(startAngle <= endAngle); - const sint32 factor = 65536; - const float invFactor = 1.f / factor; + const sint32 factor = 65536; + const float invFactor = 1.f / factor; sint32 iCurr = (uint32) (startAngle * factor) ; sint32 iEnd = (uint32) (endAngle * factor); clamp(iCurr, 0, factor); clamp(iEnd, 0, factor); uint triCount = 0; CVector quadCenter; - uvToScreen(0.5f, 0.5f, quadCenter, texSize); + uvToScreen(0.5f, 0.5f, quadCenter, texSize); while (iCurr != iEnd) { sint32 iNext = iCurr + (factor / 4); - iNext -= ((iNext - factor / 8) % (factor / 4)); // snap to nearest corner - iNext = std::min(iNext, iEnd); + iNext -= ((iNext - factor / 8) % (factor / 4)); // snap to nearest corner + iNext = std::min(iNext, iEnd); // well, not really a quad, but we don't have yet simple triangles rendering in the ui triPtr->Uv0.set(0.5f, 0.5f); triPtr->V0 = quadCenter; @@ -2220,6 +2315,69 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti rVR.draw11RotFlipBitmap (_RenderLayer+1, x, y, 0, false, _DispOver2BmpId, fastMulRGB(curSheetColor, _IconOver2Color)); } + if (!_BuffIcons.empty()) + { + // there is max 4 icons + sint32 hArea = (hSheet / 4); + sint32 xIcon = x; + sint32 yIcon = y; + for (uint i = 0; i < _BuffIcons.size(); ++i) + { + sint32 wIcon = _BuffIcons[i].IconW; + sint32 hIcon = _BuffIcons[i].IconH; + if (hIcon > hArea) + { + wIcon = wIcon * ((float)hArea / hIcon); + hIcon = hArea; + } + rVR.drawRotFlipBitmap (_RenderLayer+1, xIcon, yIcon, wIcon, hIcon, 0, false, _BuffIcons[i].TextureId, fastMulRGB(curSheetColor, _BuffIcons[i].Color)); + xIcon += wIcon; + // move up the row for 3rd/4th icon + if (i % 3 == 1) { + xIcon = x; + yIcon += hIcon; + } + } + } + + // Is the item enchanted ? + sint32 enchant = _Enchant.getSInt32(); + if (enchant > 0) + { + // Yes draw the additionnal bitmap and the charge (number of enchanted spell we can launch with the enchanted item) + enchant--; + rVR.draw11RotFlipBitmap (_RenderLayer+1, x, y, 0, false, rVR.getSystemTextureId(CViewRenderer::ItemEnchantedTexture), curSheetColor); + drawNumber(x+1, y-2+hSheet-rVR.getFigurTextureH(), wSheet, hSheet, numberColor, enchant, false); + } + + if (!_EnchantIcons.empty()) + { + // should only only 2 icons at most + // draw them in single line, top-right + sint32 hArea = (hSheet / 3); + sint32 xIcon = x + wSheet - 1; + sint32 yIcon = y + hSheet - 1/* - hArea*/; + // 0 is expected to be background + for (uint i = 1; i < _EnchantIcons.size(); ++i) + { + sint32 wIcon = _EnchantIcons[i].IconW; + sint32 hIcon = _EnchantIcons[i].IconH; + if (hIcon > hArea) + { + wIcon = wIcon * ((float)hArea / hIcon); + hIcon = hArea; + } + // need to move x before draw because of right aligned + if (i == 1) + { + xIcon -= wIcon; + } + yIcon -= hIcon; + rVR.drawRotFlipBitmap(_RenderLayer + 1, xIcon, yIcon, wIcon, hIcon, 0, false, _EnchantIcons[0].TextureId, fastMulRGB(curSheetColor, _EnchantIcons[0].Color)); + rVR.drawRotFlipBitmap(_RenderLayer+1, xIcon, yIcon, wIcon, hIcon, 0, false, _EnchantIcons[i].TextureId, fastMulRGB(curSheetColor, _EnchantIcons[i].Color)); + } + } + // Draw Quality. -1 for lookandfeel. Draw it with global color if (_DispQuality != -1) { @@ -2242,15 +2400,6 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti } drawNumber(x+1+crossW, y+1, wSheet, hSheet, curSheetColor, quantity, false); } - // Is the item enchanted ? - sint32 enchant = _Enchant.getSInt32(); - if (enchant > 0) - { - // Yes draw the additionnal bitmap and the charge (number of enchanted spell we can launch with the enchanted item) - enchant--; - rVR.draw11RotFlipBitmap (_RenderLayer+2, x, y, 0, false, rVR.getSystemTextureId(CViewRenderer::ItemEnchantedTexture), curSheetColor); - drawNumber(x+1, y-2+hSheet-rVR.getFigurTextureH(), wSheet, hSheet, numberColor, enchant, false); - } // if a raw material for example, must add special icon text. displayCharBitmaps(_RenderLayer+2, x, y, curSheetColor); @@ -2348,8 +2497,8 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti case SheetType_SPhrase : setupSPhrase(); break; default: nlassert(true); break; } - - + + bool showOutOfRangeSymbol = false; bool forceGrayed = false; @@ -2361,15 +2510,15 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti { CSPhraseManager *pPM= CSPhraseManager::getInstance(); const CSPhraseCom &phrase= pPM->getPhrase(phraseId); - // get the phrase Data version, to check if it had changed. + // get the phrase Data version, to check if it had changed. uint32 totalActionMalus = pPM->getTotalActionMalus(phrase); uint8 targetSlot = UserEntity->targetSlot(); if (targetSlot < CLFECOMMON::INVALID_SLOT) { CEntityCL *target = EntitiesMngr.entity(targetSlot); if (target && UserEntity) - { - double dist2 = (target->pos() - UserEntity->pos()).sqrnorm(); + { + double dist2 = (target->pos() - UserEntity->pos()).sqrnorm(); CSBrickManager *pBM= CSBrickManager::getInstance(); CSBrickSheet *rootBrick= NULL; if(phrase.Bricks.size()) @@ -2396,7 +2545,7 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti break; } } - + if (!isPrimalMagic) { forceGrayed = !(target->isPlayer() && target->isFriend()); @@ -2405,21 +2554,21 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti { forceGrayed = false; } - + } - + if (!forceGrayed) { sint phraseRange; sint rangeMalus; pPM->getPhraseMagicRange(phrase, totalActionMalus, phraseRange, rangeMalus); - double rangeDist = (float) (phraseRange + rangeMalus); + double rangeDist = (float) (phraseRange + rangeMalus); if (phraseRange != 0) // if range is '0' then it is a 'self' action { - rangeDist += 0.5 + target->getSheetScale() * target->getSheetColRadius(); // player radius + rangeDist += 0.5 + target->getSheetScale() * target->getSheetColRadius(); // player radius if (dist2 > rangeDist * rangeDist) { - showOutOfRangeSymbol = true; + showOutOfRangeSymbol = true; } } } @@ -2451,11 +2600,11 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti if (isTaunt && !forceGrayed) { - double rangeDist = (float) maxRange; - rangeDist += 0.5 + target->getSheetScale() * target->getSheetColRadius(); // player radius + double rangeDist = (float) maxRange; + rangeDist += 0.5 + target->getSheetScale() * target->getSheetColRadius(); // player radius if (dist2 > rangeDist * rangeDist) { - showOutOfRangeSymbol = true; + showOutOfRangeSymbol = true; } } } @@ -2522,15 +2671,15 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti // if the pointer is over the button if (_Over) // Draw -1,-1 because the slot over is 26x26 - rVR.draw11RotFlipBitmap (_RenderLayer+1, x-1, y-1, 0, false, _TextureIdOver, curSheetColor ); + rVR.draw11RotFlipBitmap (_RenderLayer+1, x-1, y-1, 0, false, _TextureIdOver, curSheetColor ); } if (showOutOfRangeSymbol) - { + { rVR.draw11RotFlipBitmap (_RenderLayer+1, x, y, 0, false, rVR.getSystemTextureId(CViewRenderer::OutOfRangeTexture), CRGBA::White); - } + } } - break; + break; case CCtrlSheetInfo::SheetType_OutpostBuilding: setupOutpostBuilding(); if (_DispBackBmpId != -1) @@ -3114,6 +3263,53 @@ const COutpostBuildingSheet *CDBCtrlSheet::asOutpostBuildingSheet() const return NULL; } +// *************************************************************************** +void CDBCtrlSheet::setupItemInfoWaiter() +{ + const CItemSheet *item = asItemSheet(); + if(!item) + return; + + if (!useItemInfoForFamily(item->Family)) + return; + + if (getItemSerial() == 0 || getItemCreateTime() == 0) + return; + + string luaMethodName = ((item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ? "updateCrystallizedSpellTooltip" : "updateBuffItemTooltip"); + CDBCtrlSheet *ctrlSheet = const_cast(this); + uint itemSlotId = getInventory().getItemSlotId(ctrlSheet); + + // Prepare the waiter for tooltips + _ItemInfoWaiter.ItemSheet= ctrlSheet->getSheetId(); + _ItemInfoWaiter.LuaMethodName = luaMethodName; + _ItemInfoWaiter.ItemSlotId= itemSlotId; + _ItemInfoWaiter.CtrlSheet = ctrlSheet; + + // send out request only if cache is not set + const CClientItemInfo *itemInfo = getInventory().getItemInfoCache(getItemSerial(), getItemCreateTime()); + if (itemInfo) + { + infoReceived(); + } + else + { + // Using isInventoryPresent/Available() will fail for packers when out of range + // Getting server item however will work correctly for packer/room/guild + const CItemImage *itemImage = getInventory().getServerItem(itemSlotId); + if (itemImage) + { + _ItemInfoWaiter.sendRequest(); + } + else + { + // schedule for next draw() - if inventory should not be available (ie guild), + // but user opens it anyway, then this will loop back here on every draw() + _ItemInfoChanged = true; + } + } +} + // *************************************************************************** void CDBCtrlSheet::getContextHelp(ucstring &help) const { @@ -3177,34 +3373,17 @@ void CDBCtrlSheet::getContextHelp(ucstring &help) const { if (useItemInfoForFamily(item->Family)) { - string luaMethodName = ( (item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ? "updateCrystallizedSpellTooltip" : "updateBuffItemTooltip"); - CDBCtrlSheet *ctrlSheet = const_cast(this); - CCtrlBase *ctrlBase = const_cast(this); - if ( ! getInventory().isItemInfoUpToDate(getInventory().getItemSlotId(ctrlSheet))) - { - // Prepare the waiter - ControlSheetTooltipUpdater.ItemSheet= ctrlSheet->getSheetId(); - ControlSheetTooltipUpdater.LuaMethodName = luaMethodName; - ControlSheetTooltipUpdater.ItemSlotId= getInventory().getItemSlotId(ctrlSheet); - ControlSheetTooltipUpdater.CtrlSheet = ctrlSheet; - - // Add the waiter - getInventory().addItemInfoWaiter(&ControlSheetTooltipUpdater); - } - - if (!_ContextHelp.empty()) - { - help= _ContextHelp; - ctrlBase->setDefaultContextHelp(ucstring()); - } - else - help = ControlSheetTooltipUpdater.infoValidated(ctrlSheet, luaMethodName); + // call lua function to update tooltip window + help = _ItemInfoWaiter.infoValidated(); + } + else if (!_ContextHelp.empty()) + { + help = _ContextHelp; } else - if (!_ContextHelp.empty()) - help= _ContextHelp; - else - help= getItemActualName(); + { + help = getItemActualName(); + } } else help= _ContextHelp; @@ -3247,18 +3426,18 @@ void CDBCtrlSheet::getContextHelp(ucstring &help) const } else { - // delegate setup of context he help ( & window ) to lua + // delegate setup of context he help ( & window ) to lua CInterfaceManager *im = CInterfaceManager::getInstance(); CLuaState *ls= CLuaManager::getInstance().getLuaState(); { CLuaStackRestorer lsr(ls, 0); - CSPhraseManager *pPM= CSPhraseManager::getInstance(); + CSPhraseManager *pPM= CSPhraseManager::getInstance(); _PhraseAdapter = new CSPhraseComAdpater; _PhraseAdapter->Phrase = pPM->getPhrase(phraseId); CLuaIHM::pushReflectableOnStack(*ls, _PhraseAdapter); - ls->pushGlobalTable(); + ls->pushGlobalTable(); CLuaObject game(*ls); - game = game["game"]; + game = game["game"]; game.callMethodByNameNoThrow("updatePhraseTooltip", 1, 1); // retrieve result from stack help = ucstring(); @@ -3322,21 +3501,7 @@ void CDBCtrlSheet::getContextHelpToolTip(ucstring &help) const { if (useItemInfoForFamily(item->Family)) { - string luaMethodName = (item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ? "updateCrystallizedSpellTooltip" : "updateBuffItemTooltip"; - CDBCtrlSheet *ctrlSheet = const_cast(this); - if ( ! getInventory().isItemInfoUpToDate(getInventory().getItemSlotId(ctrlSheet))) - { - // Prepare the waiter - ControlSheetTooltipUpdater.ItemSheet= ctrlSheet->getSheetId(); - ControlSheetTooltipUpdater.LuaMethodName = luaMethodName; - ControlSheetTooltipUpdater.ItemSlotId= getInventory().getItemSlotId(ctrlSheet); - ControlSheetTooltipUpdater.CtrlSheet = ctrlSheet; - - // Add the waiter - getInventory().addItemInfoWaiter(&ControlSheetTooltipUpdater); - } - - help = ControlSheetTooltipUpdater.infoValidated(ctrlSheet, luaMethodName); + help = _ItemInfoWaiter.infoValidated(); return; } } @@ -3551,6 +3716,10 @@ void CDBCtrlSheet::resetAllTexIDs() _Stackable= 1; _IconW = 0; _IconH = 0; + + _ItemInfoChanged = true; + _EnchantIcons.clear(); + _BuffIcons.clear(); } diff --git a/code/ryzom/client/src/interface_v3/dbctrl_sheet.h b/code/ryzom/client/src/interface_v3/dbctrl_sheet.h index ac2f2c3aa..1d185d9f4 100644 --- a/code/ryzom/client/src/interface_v3/dbctrl_sheet.h +++ b/code/ryzom/client/src/interface_v3/dbctrl_sheet.h @@ -37,7 +37,7 @@ #include "game_share/item_family.h" // #include "../time_client.h" - +#include "item_info_waiter.h" class CItemSheet; class CPactSheet; @@ -53,6 +53,25 @@ namespace NLGUI class CViewRenderer; } +class CDBCtrlSheet; + +// *************************************************************************** +// Item info request from server +class CControlSheetInfoWaiter : public IItemInfoWaiter +{ +public: + CDBCtrlSheet* CtrlSheet; + string LuaMethodName; + bool Requesting; + CControlSheetInfoWaiter() + : IItemInfoWaiter(), Requesting(false) + { } +public: + ucstring infoValidated() const; + void sendRequest(); + virtual void infoReceived(); +}; + // *************************************************************************** /** Common info for CDBCtrlSheet and CDBGroupListSheet @@ -576,12 +595,14 @@ public: // For auras, powers, etc. set the range of ticks during which regen occurs void setRegenTickRange(const CTickRange &tickRange); const CTickRange &getRegenTickRange() const { return _RegenTickRange; } - + // start notify anim (at the end of regen usually) void startNotifyAnim(); -protected: + // callback from info waiter + void infoReceived(); +protected: inline bool useItemInfoForFamily(ITEMFAMILY::EItemFamily family) const; void setupItem(); @@ -622,6 +643,7 @@ protected: NLMISC::CCDBNodeLeaf *_ItemRMFaberStatType; mutable sint32 _LastSheetId; + bool _ItemInfoChanged; /// Display sint32 _DispSlotBmpId; // Display slot bitmap id @@ -632,6 +654,26 @@ protected: sint32 _DispOverBmpId; // Over Icon sint32 _DispOver2BmpId; // Over Icon N0 2 for bricks / items. Useful for items when _DispOverBmpId is used to paint user color on the item. + std::string _HpBuffIcon; + std::string _SapBuffIcon; + std::string _StaBuffIcon; + std::string _FocusBuffIcon; + + // texture ids to show + struct SBuffIcon + { + SBuffIcon(sint32 txid, NLMISC::CRGBA col=NLMISC::CRGBA::White) + :TextureId(txid), Color(col), IconW(0), IconH(0) + { } + + sint32 TextureId; + NLMISC::CRGBA Color; + sint32 IconW; + sint32 IconH; + }; + std::vector _BuffIcons; + std::vector _EnchantIcons; + // Level Brick or Quality union { @@ -751,6 +793,7 @@ protected: sint64 _NotifyAnimEndTime; + CControlSheetInfoWaiter _ItemInfoWaiter; private: mutable TSheetType _ActualType; @@ -769,17 +812,20 @@ private: // special for items void updateItemCharacRequirement(sint32 sheetId); + // Send ITEM_INFO:GET request to server to fetch Buffs, Enchant info + void setupItemInfoWaiter(); + // update armour color, and cache void updateArmourColor(sint8 col); // setup sheet DB. _DbBranchName must be ok, and _SecondIndexInDb and _IndexInDb as well void setupSheetDbLinks (); - + // 'regen' rendering // convert from uv coordinates in the [0, 1] x [0, 1] range to screen coords inline void uvToScreen(float x, float y, NLMISC::CVector &screenPos, uint texSize) const; - // from an angle in the [0, 1] range, return both uv & screen coords for that angle + // from an angle in the [0, 1] range, return both uv & screen coords for that angle // (angle is projected on the side of rectangle of the 'regen' texture) void buildPieCorner(float angle, NLMISC::CUV &uv, NLMISC::CVector &pos, uint texSize) const; // from a start and end angle in the [0, 1] range, build the set of uv mapped triangles necessary diff --git a/code/ryzom/client/src/interface_v3/inventory_manager.h b/code/ryzom/client/src/interface_v3/inventory_manager.h index 7659409ca..8cc9f85d2 100644 --- a/code/ryzom/client/src/interface_v3/inventory_manager.h +++ b/code/ryzom/client/src/interface_v3/inventory_manager.h @@ -31,7 +31,7 @@ namespace NLMISC{ class CCDBNodeBranch; } class CDBCtrlSheet; - +class IItermInfoWaiter; const uint MAX_TEMPINV_ENTRIES = INVENTORIES::NbTempInvSlots; const uint MAX_BAGINV_ENTRIES = INVENTORIES::NbBagSlots; @@ -153,21 +153,6 @@ private: TItemInfoCacheMap _ItemInfoCacheMap; }; -class IItemInfoWaiter -{ -public: - IItemInfoWaiter() {ItemSlotId= 0; ItemSheet= 0;} - virtual ~IItemInfoWaiter() {} - // The item SheetId. If differ from current sheet in the SlotId, the infos are not updated / requested - uint ItemSheet; - // The item SlotId to retrieve info. - uint ItemSlotId; - - // Called when the info is received for this slot. - virtual void infoReceived() =0; -}; - - // *************************************************************************** /** This manager gives direct access to inventory slots (bag, temporary inventory, hands, and equip inventory) * This also give access to player money diff --git a/code/ryzom/client/src/interface_v3/item_info_waiter.h b/code/ryzom/client/src/interface_v3/item_info_waiter.h new file mode 100644 index 000000000..7976f94f2 --- /dev/null +++ b/code/ryzom/client/src/interface_v3/item_info_waiter.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 RZ_ITEM_INFO_WAITER_H +#define RZ_ITEM_INFO_WAITER_H + +class IItemInfoWaiter +{ +public: + IItemInfoWaiter() {ItemSlotId= 0; ItemSheet= 0;} + virtual ~IItemInfoWaiter() {} + // The item SheetId. If differ from current sheet in the SlotId, the infos are not updated / requested + uint ItemSheet; + // The item SlotId to retrieve info. + uint ItemSlotId; + + // Called when the info is received for this slot. + virtual void infoReceived() =0; +}; + +#endif // RZ_DBCTRL_SHEET_INFO_WAITER_H + +/* End of item_info_waiter.h */ + From 570c73576c363892303b796ca6a358a8b193e5b9 Mon Sep 17 00:00:00 2001 From: Inky Date: Sun, 26 May 2019 01:09:10 +0300 Subject: [PATCH 08/54] Changed: add channel rgba colors and index order --HG-- branch : lua --- .../client/src/interface_v3/lua_ihm_ryzom.cpp | 76 +++++++++++-------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp index 875edde9c..293b0e15a 100644 --- a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp +++ b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp @@ -3996,7 +3996,7 @@ int CLuaIHMRyzom::setArkPowoOptions(CLuaState &ls) // *************************************************************************** int CLuaIHMRyzom::readUserChannels(CLuaState &ls) { - std::string filename = CInterfaceManager::getInstance()->getSaveFileName("channels", "xml"); + const std::string filename = CInterfaceManager::getInstance()->getSaveFileName("channels", "xml"); try { CIFile fd; @@ -4007,37 +4007,43 @@ int CLuaIHMRyzom::readUserChannels(CLuaState &ls) xmlKeepBlanksDefault(0); xmlNodePtr root = stream.getRootNode(); - if (!root) - return 0; + + if (!root) return 0; + CXMLAutoPtr prop; - // table ls.newTable(); CLuaObject output(ls); - uint nb = 0; + std::vector< string > tags; + + // allowed tags + tags.push_back("id"); + tags.push_back("name"); + tags.push_back("rgba"); + tags.push_back("passwd"); + xmlNodePtr node = root->children; + uint nb = 0; while (node) { - prop = xmlGetProp(node, (xmlChar*)"name"); - if (!prop) - return 0; - std::string name = (const char*)prop; + ls.newTable(); + CLuaObject nodeTable(ls); - prop = xmlGetProp(node, (xmlChar*)"passwd"); - if (!prop) - return 0; - std::string pass = (const char*)prop; + for (uint i = 0; i < tags.size(); i++) + { + prop = xmlGetProp(node, (xmlChar*)tags[i].c_str()); + if (!prop) return 0; - output.setValue(name.c_str(), pass.c_str()); + nodeTable.setValue(tags[i].c_str(), (const char *)prop); + } + output.setValue(toString("%i", nb).c_str(), nodeTable); node = node->next; nb++; } + output.push(); // no exception fd.close(); - - // release lua table - output.push(); } nlinfo("parse %s", filename.c_str()); } @@ -4049,7 +4055,6 @@ int CLuaIHMRyzom::readUserChannels(CLuaState &ls) return 1; } -// *************************************************************************** int CLuaIHMRyzom::saveUserChannels(CLuaState &ls) { const char *funcName = "saveUserChannels"; @@ -4067,7 +4072,7 @@ int CLuaIHMRyzom::saveUserChannels(CLuaState &ls) CLuaObject params; params.pop(ls); - std::string filename = CInterfaceManager::getInstance()->getSaveFileName("channels", "xml"); + const std::string filename = CInterfaceManager::getInstance()->getSaveFileName("channels", "xml"); try { COFile fd; @@ -4080,27 +4085,38 @@ int CLuaIHMRyzom::saveUserChannels(CLuaState &ls) xmlNodePtr node = xmlNewDocNode(doc, NULL, (const xmlChar*)"interface_config", NULL); xmlDocSetRootElement(doc, node); + std::string key, value; ENUM_LUA_TABLE(params, it) { - if (!it.nextKey().isString()) - continue; - if (!it.nextValue().isString()) - continue; + if (it.nextKey().type() == LUA_TSTRING) + { + xmlNodePtr newNode = xmlNewChild(node, NULL, (const xmlChar*)"channels", NULL); + + if (it.nextValue().type() == LUA_TTABLE) + { + xmlSetProp(newNode, (const xmlChar*)"id", (const xmlChar*)it.nextKey().toString().c_str()); - std::string name = it.nextKey().toString(); - std::string pass = it.nextValue().toString(); + ENUM_LUA_TABLE(it.nextValue(), itt) + { + if (!itt.nextKey().isString()) + continue; + if (!itt.nextValue().isString()) + continue; - xmlNodePtr newNode = xmlNewChild(node, NULL, (const xmlChar*)"channels", NULL); - xmlSetProp(newNode, (const xmlChar*)"name", (const xmlChar*)name.c_str()); - xmlSetProp(newNode, (const xmlChar*)"passwd", (const xmlChar*)pass.c_str()); + key = itt.nextKey().toString(); + value = itt.nextValue().toString(); + + xmlSetProp(newNode, (const xmlChar*)key.c_str(), (const xmlChar*)value.c_str()); + } + } + } } stream.flush(); - // no exception fd.close(); } nlinfo("save %s", filename.c_str()); if (verbose) - CInterfaceManager::getInstance()->displaySystemInfo("Saving " + filename); + CInterfaceManager::getInstance()->displaySystemInfo("Save " + filename); } catch (const Exception &e) { From ba42b50cf05228131a55da0e653f47e6f6121f3d Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sat, 1 Jun 2019 14:13:43 +0300 Subject: [PATCH 09/54] Changed: Send item info request for updated tooltips (ie durability changes) --HG-- branch : feature-item-icon-buffs --- code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp | 2 ++ code/ryzom/client/src/interface_v3/dbctrl_sheet.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp index f94a7f180..2d3a6790a 100644 --- a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp +++ b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp @@ -3374,6 +3374,7 @@ void CDBCtrlSheet::getContextHelp(ucstring &help) const if (useItemInfoForFamily(item->Family)) { // call lua function to update tooltip window + _ItemInfoWaiter.sendRequest(); help = _ItemInfoWaiter.infoValidated(); } else if (!_ContextHelp.empty()) @@ -3501,6 +3502,7 @@ void CDBCtrlSheet::getContextHelpToolTip(ucstring &help) const { if (useItemInfoForFamily(item->Family)) { + _ItemInfoWaiter.sendRequest(); help = _ItemInfoWaiter.infoValidated(); return; } diff --git a/code/ryzom/client/src/interface_v3/dbctrl_sheet.h b/code/ryzom/client/src/interface_v3/dbctrl_sheet.h index 1d185d9f4..2b12924a5 100644 --- a/code/ryzom/client/src/interface_v3/dbctrl_sheet.h +++ b/code/ryzom/client/src/interface_v3/dbctrl_sheet.h @@ -793,7 +793,7 @@ protected: sint64 _NotifyAnimEndTime; - CControlSheetInfoWaiter _ItemInfoWaiter; + mutable CControlSheetInfoWaiter _ItemInfoWaiter; private: mutable TSheetType _ActualType; From 9dec7f9dbe813e40df9eaaf516aa9d0bbea1a73f Mon Sep 17 00:00:00 2001 From: Inky Date: Fri, 21 Jun 2019 21:15:34 +0300 Subject: [PATCH 10/54] Changed: get the lua script executed at checkCoords time --HG-- branch : lua --- code/nel/include/nel/gui/interface_group.h | 2 ++ code/nel/include/nel/gui/lua_ihm.h | 1 + code/nel/src/gui/lua_ihm.cpp | 30 ++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/code/nel/include/nel/gui/interface_group.h b/code/nel/include/nel/gui/interface_group.h index 01f2b9701..e782af01e 100644 --- a/code/nel/include/nel/gui/interface_group.h +++ b/code/nel/include/nel/gui/interface_group.h @@ -313,6 +313,8 @@ namespace NLGUI void deleteLUAEnvTable(bool recurse = false); // Set the LUA script to execute at checkCoords time (empty to reset) void setLuaScriptOnDraw(const std::string &script); + // Get the LUA script executed at checkCoords time + inline CStringShared getLuaScriptOnDraw() { return _LUAOnDraw; } // void executeLuaScriptOnDraw(); // Set the LUA script to execute when a list of DB change (of forms: "@DB1,@DB2" ....). The dbList is the key diff --git a/code/nel/include/nel/gui/lua_ihm.h b/code/nel/include/nel/gui/lua_ihm.h index e45e1125f..a7c5f9e2b 100644 --- a/code/nel/include/nel/gui/lua_ihm.h +++ b/code/nel/include/nel/gui/lua_ihm.h @@ -161,6 +161,7 @@ namespace NLGUI static int luaMethodCall(lua_State *ls); static int setOnDraw(CLuaState &ls); // params: CInterfaceGroup*, "script". return: none + static int getOnDraw(CLuaState &ls); // params: CInterfaceGroup*. return: "script" (nil if none) static int addOnDbChange(CLuaState &ls); // params: CInterfaceGroup*, "dblist", "script". return: none static int removeOnDbChange(CLuaState &ls);// params: CInterfaceGroup*. return: none static int setCaptureKeyboard(CLuaState &ls); diff --git a/code/nel/src/gui/lua_ihm.cpp b/code/nel/src/gui/lua_ihm.cpp index 4a51d221f..6da211b52 100644 --- a/code/nel/src/gui/lua_ihm.cpp +++ b/code/nel/src/gui/lua_ihm.cpp @@ -794,6 +794,35 @@ namespace NLGUI return 0; } + // *************************************************************************** + int CLuaIHM::getOnDraw(CLuaState &ls) + { + //H_AUTO(Lua_CLuaIHM_getOnDraw + CLuaStackChecker lsc(&ls, 1); + + // params: CInterfaceElement*. + // return: "script" (nil if empty) + CLuaIHM::checkArgCount(ls, "getOnDraw", 1); + CLuaIHM::check(ls, CLuaIHM::isUIOnStack(ls, 1), "getOnDraw() requires a UI object in param 1"); + + // retrieve arguments + CInterfaceElement *pIE = CLuaIHM::getUIOnStack(ls, 1); + if (pIE) + { + // must be a group + CInterfaceGroup *group = dynamic_cast(pIE); + if (group) + { + if (!group->getLuaScriptOnDraw().empty()) { + ls.push(group->getLuaScriptOnDraw()); + return 1; + } + } + } + ls.pushNil(); + return 1; + } + // *************************************************************************** int CLuaIHM::addOnDbChange(CLuaState &ls) { @@ -1589,6 +1618,7 @@ namespace NLGUI // *** Register Functions ls.registerFunc("setOnDraw", setOnDraw); + ls.registerFunc("getOnDraw", getOnDraw); ls.registerFunc("setCaptureKeyboard", setCaptureKeyboard); ls.registerFunc("resetCaptureKeyboard", resetCaptureKeyboard); ls.registerFunc("setTopWindow", setTopWindow); From a1492e70e0369a6fa84c0df5a42a3c96b1085899 Mon Sep 17 00:00:00 2001 From: Inky Date: Sat, 22 Jun 2019 23:38:03 +0300 Subject: [PATCH 11/54] Changed: bind to interact with vertical/horizontal scroll elements --HG-- branch : lua --- .../client/src/interface_v3/lua_ihm_ryzom.cpp | 47 ++++++++++++++++++- .../client/src/interface_v3/lua_ihm_ryzom.h | 3 ++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp index 293b0e15a..0fab25843 100644 --- a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp +++ b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp @@ -495,6 +495,7 @@ void CLuaIHMRyzom::RegisterRyzomFunctions(NLGUI::CLuaState &ls) ls.registerFunc("saveUserChannels", saveUserChannels); ls.registerFunc("readUserChannels", readUserChannels); ls.registerFunc("getMaxDynChan", getMaxDynChan); + ls.registerFunc("scrollElement", scrollElement); lua_State *L = ls.getStatePointer(); @@ -4248,4 +4249,48 @@ int CLuaIHMRyzom::displayChatMessage(CLuaState &ls) ci.DynamicChat[id].displayMessage(ucstring(msg), prop.getRGBA()); } return 1; -} \ No newline at end of file +} + +// *************************************************************************** +int CLuaIHMRyzom::scrollElement(CLuaState &ls) +{ + const char *funcName = "scrollElement"; + + // scrollElement(object, vertical, direction, offset_multiplier) + + CLuaIHM::checkArgMin(ls, funcName, 3); + CLuaIHM::check(ls, ls.getTop() > 2, funcName); + + CLuaIHM::check(ls, CLuaIHM::isUIOnStack(ls, 1), toString("%s requires a UI object in param 1", funcName)); + CLuaIHM::check(ls, ls.type(2)==LUA_TBOOLEAN, toString("%s requires a boolean in param 2", funcName)); + CLuaIHM::check(ls, ls.isInteger(3), toString("%s requires a number in param 3", funcName)); + + if (ls.getTop() > 3) + CLuaIHM::check(ls, ls.isInteger(4), toString("%s requires a number in param 4", funcName)); + + CInterfaceElement *pIE = CLuaIHM::getUIOnStack(ls, 1); + if (pIE) + { + // must be a scroll element + CCtrlScroll *pCS = dynamic_cast(pIE); + if (pCS) + { + sint32 direction = 0; + sint32 multiplier = 16; + + direction = (ls.toInteger(3) > 0) ? 1 : -1; + if (ls.getTop() > 3) + multiplier = (ls.toInteger(4) > 0) ? ls.toInteger(4) : 1; + + const bool vertical = ls.toBoolean(2); + if (vertical) + pCS->moveTrackY(-(direction * multiplier)); + else + pCS->moveTrackX(-(direction * multiplier)); + + return 0; + } + } + ls.pushNil(); + return 1; +} diff --git a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.h b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.h index d60279aec..b071d5228 100644 --- a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.h +++ b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.h @@ -271,6 +271,9 @@ private: static bool isPlayerInPVPMode(); static bool isTargetInPVPMode(); + // vertical and horizontal scrolling + // do not require element to be focused + static int scrollElement(CLuaState &ls); // return none (nil if error) public: From 7a2608e38c82f803cf974aabe7f9b1437c0cc212 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Mon, 5 Aug 2019 13:47:23 +0300 Subject: [PATCH 12/54] Fixed: Buff markers visible for icons that does not support them. --HG-- branch : feature-item-icon-buffs --- .../client/src/interface_v3/dbctrl_sheet.cpp | 21 +++++++++++++++++-- .../client/src/interface_v3/dbctrl_sheet.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp index 2d3a6790a..b49df3d2d 100644 --- a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp +++ b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp @@ -1066,11 +1066,19 @@ void CDBCtrlSheet::updateIconSize() } } +// *************************************************************************** +void CDBCtrlSheet::clearIconBuffs() +{ + _EnchantIcons.clear(); + _BuffIcons.clear(); +} + // *************************************************************************** void CDBCtrlSheet::infoReceived() { if (!_ItemSheet) { + clearIconBuffs(); return; } @@ -1082,9 +1090,10 @@ void CDBCtrlSheet::infoReceived() return; } + clearIconBuffs(); + // crystallized spell { - _EnchantIcons.clear(); CViewRenderer &rVR = *CViewRenderer::getInstance(); CSBrickManager *pBM= CSBrickManager::getInstance(); for(uint i=0; iEnchantment.Bricks.size(); ++i) @@ -1109,7 +1118,6 @@ void CDBCtrlSheet::infoReceived() // buff icons { - _BuffIcons.clear(); CViewRenderer &rVR = *CViewRenderer::getInstance(); if (itemInfo->HpBuff > 0) _BuffIcons.push_back(SBuffIcon(rVR.getTextureIdFromName(_HpBuffIcon))); @@ -3268,13 +3276,22 @@ void CDBCtrlSheet::setupItemInfoWaiter() { const CItemSheet *item = asItemSheet(); if(!item) + { + clearIconBuffs(); return; + } if (!useItemInfoForFamily(item->Family)) + { + clearIconBuffs(); return; + } if (getItemSerial() == 0 || getItemCreateTime() == 0) + { + clearIconBuffs(); return; + } string luaMethodName = ((item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ? "updateCrystallizedSpellTooltip" : "updateBuffItemTooltip"); CDBCtrlSheet *ctrlSheet = const_cast(this); diff --git a/code/ryzom/client/src/interface_v3/dbctrl_sheet.h b/code/ryzom/client/src/interface_v3/dbctrl_sheet.h index 2b12924a5..71c7b670a 100644 --- a/code/ryzom/client/src/interface_v3/dbctrl_sheet.h +++ b/code/ryzom/client/src/interface_v3/dbctrl_sheet.h @@ -804,6 +804,8 @@ private: void updateIconSize(); void resetAllTexIDs(); void setupInit(); + // remove enchant and buff markers from item icon + void clearIconBuffs(); void setupCharBitmaps(sint32 maxW, sint32 maxLine, sint32 maxWChar= 1000, bool topDown= false); void resetCharBitmaps(); From 131f05387a708c1bd1d2b9c0dc3129f2313af352 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Mon, 5 Aug 2019 14:20:50 +0300 Subject: [PATCH 13/54] Added: Option to turn icon buff markers on/off --HG-- branch : feature-item-icon-buffs --- .../src/interface_v3/action_handler_game.cpp | 14 ++++++++++++++ .../ryzom/client/src/interface_v3/dbctrl_sheet.cpp | 11 +++++------ code/ryzom/client/src/interface_v3/dbctrl_sheet.h | 5 +++++ 3 files changed, 24 insertions(+), 6 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 9ccdf1b11..13c720f66 100644 --- a/code/ryzom/client/src/interface_v3/action_handler_game.cpp +++ b/code/ryzom/client/src/interface_v3/action_handler_game.cpp @@ -4609,3 +4609,17 @@ public: }; REGISTER_ACTION_HANDLER( CHandlerSortTribeFame, "sort_tribefame"); +// *************************************************************************** +class CHandlerTriggerIconBuffs : public IActionHandler +{ +public: + void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */) + { + CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_ICON_BUFFS", false); + // no node - show, + // node == false - hide + CDBCtrlSheet::setShowIconBuffs(!node || node->getValueBool()); + } +}; +REGISTER_ACTION_HANDLER(CHandlerTriggerIconBuffs, "trigger_show_icon_buffs"); + diff --git a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp index b49df3d2d..fe7c3b281 100644 --- a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp +++ b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp @@ -73,6 +73,9 @@ REGISTER_UI_CLASS(CDBCtrlSheet) const uint64 NOTIFY_ANIM_MS_DURATION = 1000; +// state kept and changed by UI:SAVE:SHOW_ICON_BUFFS +bool CDBCtrlSheet::_ShowIconBuffs = true; + // *************************************************************************** void CControlSheetInfoWaiter::sendRequest() @@ -2323,7 +2326,7 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti rVR.draw11RotFlipBitmap (_RenderLayer+1, x, y, 0, false, _DispOver2BmpId, fastMulRGB(curSheetColor, _IconOver2Color)); } - if (!_BuffIcons.empty()) + if (_ShowIconBuffs && !_BuffIcons.empty()) { // there is max 4 icons sint32 hArea = (hSheet / 4); @@ -2358,7 +2361,7 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti drawNumber(x+1, y-2+hSheet-rVR.getFigurTextureH(), wSheet, hSheet, numberColor, enchant, false); } - if (!_EnchantIcons.empty()) + if (_ShowIconBuffs && !_EnchantIcons.empty()) { // should only only 2 icons at most // draw them in single line, top-right @@ -4691,7 +4694,3 @@ void CDBCtrlSheet::startNotifyAnim() _NotifyAnimEndTime = T1 + NOTIFY_ANIM_MS_DURATION; } - - - - diff --git a/code/ryzom/client/src/interface_v3/dbctrl_sheet.h b/code/ryzom/client/src/interface_v3/dbctrl_sheet.h index 71c7b670a..28d7a1ddf 100644 --- a/code/ryzom/client/src/interface_v3/dbctrl_sheet.h +++ b/code/ryzom/client/src/interface_v3/dbctrl_sheet.h @@ -602,6 +602,9 @@ public: // callback from info waiter void infoReceived(); + // set enchant/buff marker visiblility + static void setShowIconBuffs(bool b) { _ShowIconBuffs = b; } + protected: inline bool useItemInfoForFamily(ITEMFAMILY::EItemFamily family) const; @@ -799,6 +802,8 @@ private: static CDBCtrlSheet *_CurrSelection; static CDBCtrlSheet *_CurrMenuSheet; + + static bool _ShowIconBuffs; private: void updateActualType() const; void updateIconSize(); From 39e0f4b4f24031e2391b3cb3320ce9f871310509 Mon Sep 17 00:00:00 2001 From: Nimetu Date: Fri, 9 Aug 2019 11:08:20 +0300 Subject: [PATCH 14/54] 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 15/54] 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 16/54] 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 8aea3d661ae5d7624a4b90d4a5ebf3e5eac93df6 Mon Sep 17 00:00:00 2001 From: Riasan Date: Mon, 19 Aug 2019 19:12:04 +0200 Subject: [PATCH 17/54] Changed: set Fullscreen to 0 to prevent crashes on last OSX Version --HG-- branch : atys --- code/ryzom/client/client_default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ryzom/client/client_default.cfg b/code/ryzom/client/client_default.cfg index 3f3971ed5..7431807cf 100644 --- a/code/ryzom/client/client_default.cfg +++ b/code/ryzom/client/client_default.cfg @@ -15,7 +15,7 @@ SaveConfig = 1; Driver3D="Auto"; // Valid values are "Auto" or "0", "OpengGL" or "1" & "Direct3D" or "2" // "Auto" will choose the best suited driver depending on hardware -FullScreen = 1; +FullScreen = 0; Width = 0; Height = 0; PositionX = 0; From d0b3d0596cb4022e90da0fd48312474b2362d9d5 Mon Sep 17 00:00:00 2001 From: Inky Date: Tue, 27 Aug 2019 21:30:07 +0300 Subject: [PATCH 18/54] Fixed: undesired code introduced from merging lua branch --HG-- branch : atys --- code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp index d7ad2bc7f..a59963fcd 100644 --- a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp +++ b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.cpp @@ -3293,7 +3293,6 @@ void CLuaIHMRyzom::browseNpcWebPage(const std::string &htmlId, const std::string groupHtml->setTimeout((float)std::max(0.0, timeout)); // Browse the url - groupHtml->clean(); groupHtml->browse(url.c_str()); // Set top of the page CCtrlScroll *pScroll = groupHtml->getScrollBar(); From cc437ef7a93cdf33c1217b3847daf74dff29103a Mon Sep 17 00:00:00 2001 From: Nimetu Date: Sun, 8 Sep 2019 10:37:05 +0300 Subject: [PATCH 19/54] 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 20/54] 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 21/54] 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 22/54] 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 23/54] 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 24/54] 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 25/54] 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 26/54] 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 27/54] 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 28/54] 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 29/54] 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 30/54] 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 31/54] 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 32/54] 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 33/54] 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 34/54] 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 35/54] 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 36/54] 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 37/54] 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 38/54] 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 39/54] 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 40/54] 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 41/54] 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 42/54] 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 43/54] 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