diff --git a/code/nel/include/nel/gui/group_paragraph.h b/code/nel/include/nel/gui/group_paragraph.h index b8792ece1..0004850fa 100644 --- a/code/nel/include/nel/gui/group_paragraph.h +++ b/code/nel/include/nel/gui/group_paragraph.h @@ -206,12 +206,6 @@ namespace NLGUI invalidateContent(); } - // Set the HTML group used for links - void setBrowseGroup (CInterfaceElement *group) - { - _BrowseGroup = group; - } - /// \from CInterfaceElement void onInvalidateContent(); sint32 getMaxUsedW() const; @@ -293,9 +287,6 @@ namespace NLGUI // The links std::vector _Links; - // The HTML group used - CInterfaceElement *_BrowseGroup; - private: std::string _HardText; uint32 _TextId; diff --git a/code/nel/include/nel/gui/view_link.h b/code/nel/include/nel/gui/view_link.h index 1cc40a883..0fbca1065 100644 --- a/code/nel/include/nel/gui/view_link.h +++ b/code/nel/include/nel/gui/view_link.h @@ -50,10 +50,21 @@ namespace NLGUI void setHTMLView( CGroupHTML *html); bool getMouseOverShape(std::string &texName, uint8 &rot, NLMISC::CRGBA &col); + void setActionOnLeftClick(const std::string &actionHandler) { _AHOnLeftClick = actionHandler; }; + void setParamsOnLeftClick(const std::string &actionParams) { _AHOnLeftClickParams = actionParams; }; + + const std::string &getActionOnLeftClick() const { return _AHOnLeftClick; } + const std::string &getParamsOnLeftClick() const { return _AHOnLeftClickParams; } protected: // The main HTML group CGroupHTML *HTML; + + // Left mouse click action + // Don't use CStringShared as URLs change past values would be permanently remembered. + std::string _AHOnLeftClick; + std::string _AHOnLeftClickParams; + }; } diff --git a/code/nel/src/gui/action_handler.cpp b/code/nel/src/gui/action_handler.cpp index b43d37ded..2d2246937 100644 --- a/code/nel/src/gui/action_handler.cpp +++ b/code/nel/src/gui/action_handler.cpp @@ -23,6 +23,7 @@ #include "nel/gui/db_manager.h" #include "nel/gui/interface_link.h" #include "nel/gui/widget_manager.h" +#include "nel/gui/view_renderer.h" using namespace std; using namespace NLMISC; @@ -742,4 +743,14 @@ namespace NLGUI }; REGISTER_ACTION_HANDLER (CAHUnlockAllContainer, "unlock_all_container"); -} \ No newline at end of file + // ------------------------------------------------------------------------------------------------ + class CAHCopyToClipboard : public IActionHandler + { + virtual void execute (CCtrlBase *pCaller, const std::string ¶ms) + { + if (!CViewRenderer::getInstance()->getDriver()->copyTextToClipboard(params)) + nlwarning("Copy to clipboard failed: '%s'", params.c_str()); + } + }; + REGISTER_ACTION_HANDLER(CAHCopyToClipboard, "copy_to_clipboard"); +} diff --git a/code/nel/src/gui/group_html.cpp b/code/nel/src/gui/group_html.cpp index 247e33f41..a3cfd514f 100644 --- a/code/nel/src/gui/group_html.cpp +++ b/code/nel/src/gui/group_html.cpp @@ -497,7 +497,11 @@ namespace NLGUI if (res != CURLE_OK) { - browseError(string("Connection failed with curl error " + string(curl_easy_strerror(res))).c_str()); + std::string err; + err = "Connection failed with cURL error: "; + err += curl_easy_strerror(res); + err += "\nURL '" + _CurlWWW->Url + "'"; + browseError(err.c_str()); } else if ((code >= 301 && code <= 303) || code == 307 || code == 308) @@ -541,7 +545,7 @@ namespace NLGUI if ( (code < 200 || code >= 300) ) { - browseError(string("Connection failed (curl code " + toString((sint32)res) + "), http code " + toString((sint32)code) + ") : " + _CurlWWW->Url).c_str()); + browseError(string("Connection failed (curl code " + toString((sint32)res) + ")\nhttp code " + toString((sint32)code) + ")\nURL '" + _CurlWWW->Url + "'").c_str()); } else { @@ -3769,7 +3773,6 @@ namespace NLGUI CGroupParagraph *newParagraph = new CGroupParagraph(CViewBase::TCtorParam()); newParagraph->setResizeFromChildH(true); - newParagraph->setBrowseGroup (this); newParagraph->setIndent(_Indent); // Add to the group @@ -4123,6 +4126,9 @@ namespace NLGUI if (!newLink->Link.empty()) { newLink->setHTMLView (this); + + newLink->setActionOnLeftClick("browse"); + newLink->setParamsOnLeftClick("name=" + getId() + "|url=" + newLink->Link); } } newLink->setText(tmpStr); @@ -5216,6 +5222,11 @@ namespace NLGUI void CGroupHTML::doBrowseAnchor(const std::string &anchor) { + if (_Anchors.count(anchor) == 0) + { + return; + } + CInterfaceElement *pIE = _Anchors.find(anchor)->second; if (pIE) { diff --git a/code/nel/src/gui/group_list.cpp b/code/nel/src/gui/group_list.cpp index f08bba10c..216c8f682 100644 --- a/code/nel/src/gui/group_list.cpp +++ b/code/nel/src/gui/group_list.cpp @@ -740,13 +740,11 @@ namespace NLGUI CInterfaceGroup::updateCoords(); - sint32 nCurrentX = 0; // Current offset of an element - EAlign addElt = _AddElt; if ((addElt == Top) || (addElt == Bottom)) { // Calculate size - sint32 newH = 0, newW = 0; + sint32 newH = 0; bool bFirst = true; for (uint32 i = 0; i < _Elements.size(); ++i) @@ -756,10 +754,7 @@ namespace NLGUI if (!bFirst) newH += _Space; bFirst = false; - nCurrentX += _Elements[i].Element->getX(); - newW = max (newW, _Elements[i].Element->getW()+(sint32)abs(nCurrentX)); } - _W = max(newW, _MinW); _H = max(newH, _MinH); if (_DynamicDisplaySize) { @@ -767,10 +762,13 @@ namespace NLGUI _MaxH = _H; } if (_H < _MaxH) setOfsY(0); + + // if width is not from parent, then ensure minimum size + if ((_SizeRef & 1) == 0) _W = max(_W, _MinW); } else { - sint32 newW = 0, newH = 0; + sint32 newW = 0; bool bFirst = true; for (uint32 i = 0; i < _Elements.size(); ++i) @@ -780,16 +778,17 @@ namespace NLGUI if (!bFirst) newW += _Space; bFirst = false; - newH = max (newH, _Elements[i].Element->getH()); } _W = max(newW, _MinW); - _H = max(newH, _MinH); if (_DynamicDisplaySize) { _MaxW = _W; _MaxH = _H; } if (_W < _MaxW) setOfsX(0); + + // if height is not from parent, then ensure minimum size + if ((_SizeRef & 2) == 0) _H = max(_H, _MinH); } CInterfaceElement::updateCoords(); diff --git a/code/nel/src/gui/group_menu.cpp b/code/nel/src/gui/group_menu.cpp index 97d45c870..d2e11a2c9 100644 --- a/code/nel/src/gui/group_menu.cpp +++ b/code/nel/src/gui/group_menu.cpp @@ -240,6 +240,7 @@ namespace NLGUI _GroupList->setY (4); _GroupList->setSpace (_GroupMenu->_Space); _GroupList->setSerializable( false ); + _GroupList->setResizeFromChildW(true); addGroup (_GroupList); } } diff --git a/code/nel/src/gui/group_paragraph.cpp b/code/nel/src/gui/group_paragraph.cpp index b0c8a8167..b2635b52e 100644 --- a/code/nel/src/gui/group_paragraph.cpp +++ b/code/nel/src/gui/group_paragraph.cpp @@ -59,7 +59,6 @@ namespace NLGUI _TopSpace = 0; _Indent = 0; _FirstViewIndentView = false; - _BrowseGroup = NULL; _TextId = 0; } @@ -868,11 +867,8 @@ namespace NLGUI ctrl->setParentPosRef (Hotspot_TL); ctrl->setPosRef (Hotspot_TL); ctrl->setActive(true); - if (_BrowseGroup) - { - ctrl->setActionOnLeftClick("browse"); - ctrl->setParamsOnLeftClick("name="+_BrowseGroup->getId()+"|url="+link.Link->Link); - } + ctrl->setActionOnLeftClick(link.Link->getActionOnLeftClick()); + ctrl->setParamsOnLeftClick(link.Link->getParamsOnLeftClick()); ctrl->setScale(true); addCtrl(ctrl); } diff --git a/code/nel/tools/3d/textures_tool/main.cpp b/code/nel/tools/3d/textures_tool/main.cpp index 592df935f..cccb62bee 100644 --- a/code/nel/tools/3d/textures_tool/main.cpp +++ b/code/nel/tools/3d/textures_tool/main.cpp @@ -180,8 +180,8 @@ int main(int argc, char **argv) for (uint j = 0; j < size; ++j) { - // TODO: find what computation do -// *(pRGBA++)-> = color; + pRGBA->modulateFromColorRGBOnly(*pRGBA, color); + ++pRGBA; } NLMISC::COFile out; diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml b/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml index 58f41d919..d7aabccae 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml @@ -50,6 +50,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/interaction.lua b/code/ryzom/client/data/gamedev/interfaces_v3/interaction.lua index 489484ee8..9f672e961 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/interaction.lua +++ b/code/ryzom/client/data/gamedev/interfaces_v3/interaction.lua @@ -537,3 +537,17 @@ function game:openWebIGBrowserHeader() ui.w = ui_webig_browser_w; end end + +------------------------------------------------------------------------------------------------------------ +local SavedUrl = ""; +function game:chatUrl(url) + SavedUrl = url + runAH(nil, "active_menu", "menu=ui:interface:chat_uri_action_menu"); +end +function game:chatUrlCopy() + runAH(nil, "copy_to_clipboard", SavedUrl) +end +function game:chatUrlBrowse() + runAH(nil, "browse", "name=ui:interface:webig:content:html|url=" .. SavedUrl) +end + diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/interaction.xml b/code/ryzom/client/data/gamedev/interfaces_v3/interaction.xml index d6d4a4cba..cbf4b15ce 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/interaction.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/interaction.xml @@ -3127,4 +3127,19 @@ + + + + + + + diff --git a/code/ryzom/client/src/client_cfg.cpp b/code/ryzom/client/src/client_cfg.cpp index c30f07906..20a5f60e9 100644 --- a/code/ryzom/client/src/client_cfg.cpp +++ b/code/ryzom/client/src/client_cfg.cpp @@ -2033,13 +2033,9 @@ void CClientConfig::release () // Are we in window mode ? if (ClientCfg.Windowed /* && !isWindowMaximized() */) { - // Save windows position + // Save windows position. width/height are saved when leaving ingame. writeInt("PositionX", x); writeInt("PositionY", y); - - // Save windows size - writeInt("Width", std::max((sint)width, 800)); - writeInt("Height", std::max((sint)height, 600)); } } diff --git a/code/ryzom/client/src/client_chat_manager.cpp b/code/ryzom/client/src/client_chat_manager.cpp index 1bf6227d9..3211e764c 100644 --- a/code/ryzom/client/src/client_chat_manager.cpp +++ b/code/ryzom/client/src/client_chat_manager.cpp @@ -1375,8 +1375,24 @@ class CHandlerTalk : public IActionHandler } else { - ChatMngr.setChatMode((CChatGroup::TGroupType)mode); - ChatMngr.chat(text, mode == CChatGroup::team); + if (mode == CChatGroup::dyn_chat) + { + uint channel; + fromString(getParam (sParams, "channel"), channel); + if (channel < CChatGroup::MaxDynChanPerPlayer) + { + PeopleInterraction.talkInDynamicChannel(channel, text); + } + else + { + nlwarning("/ah talk: invalid dyn_chat channel %d\n", channel); + } + } + else + { + ChatMngr.setChatMode((CChatGroup::TGroupType)mode); + ChatMngr.chat(text, mode == CChatGroup::team); + } } } } @@ -1391,9 +1407,21 @@ class CHandlerEnterTalk : public IActionHandler { // Param uint mode; + uint channel = 0; + fromString(getParam (sParams, "mode"), mode); - ChatMngr.updateChatModeAndButton(mode); + if (mode == CChatGroup::dyn_chat) + { + fromString(getParam(sParams, "channel"), channel); + + if (channel >= CChatGroup::MaxDynChanPerPlayer) + { + channel = 0; + } + } + + ChatMngr.updateChatModeAndButton(mode, channel); } }; REGISTER_ACTION_HANDLER( CHandlerEnterTalk, "enter_talk"); diff --git a/code/ryzom/client/src/commands.cpp b/code/ryzom/client/src/commands.cpp index 70cbfc229..44b165c61 100644 --- a/code/ryzom/client/src/commands.cpp +++ b/code/ryzom/client/src/commands.cpp @@ -1198,77 +1198,6 @@ NLMISC_COMMAND(db, "Modify Database"," ") return true; } -static bool talkInChan(uint32 nb,std::vectorargs) -{ - uint32 maxChans = CChatGroup::MaxDynChanPerPlayer; - if (nb>=maxChans) - { - return false; - } - if(!args.empty()) - { - std::string tmp; - std::vector::const_iterator first(args.begin()),last(args.end()); - - for(;first!=last;++first) - { - tmp = tmp + (*first); - tmp = tmp+" "; - } - - ucstring uctmp; - uctmp.fromUtf8(tmp); - PeopleInterraction.talkInDynamicChannel(nb, uctmp); - return true; - } - else - { - ChatMngr.updateChatModeAndButton(CChatGroup::dyn_chat, nb); - } - return false; -} - -NLMISC_COMMAND(0,"talk in 0th dynamic chat channel"," ") -{ - return talkInChan(0,args); -} - -NLMISC_COMMAND(1,"talk in first dynamic chat channel"," ") -{ - return talkInChan(1,args); -} - -NLMISC_COMMAND(2,"talk in 2nd dynamic chat channel"," ") -{ - return talkInChan(2,args); -} - -NLMISC_COMMAND(3,"talk in 3rd dynamic chat channel"," ") -{ - return talkInChan(3,args); -} - -NLMISC_COMMAND(4,"talk in 4th dynamic chat channel"," ") -{ - return talkInChan(4,args); -} - -NLMISC_COMMAND(5,"talk in 5th dynamic chat channel"," ") -{ - return talkInChan(5,args); -} - -NLMISC_COMMAND(6,"talk in 6th dynamic chat channel"," ") -{ - return talkInChan(6,args); -} - -NLMISC_COMMAND(7,"talk in 7th dynamic chat channel"," ") -{ - return talkInChan(7,args); -} - - NLMISC_COMMAND(setItemName, "set name of items, sbrick, etc.."," ") { if (args.size() < 2) return false; diff --git a/code/ryzom/client/src/interface_v3/chat_text_manager.cpp b/code/ryzom/client/src/interface_v3/chat_text_manager.cpp index 750630a17..5195d0b51 100644 --- a/code/ryzom/client/src/interface_v3/chat_text_manager.cpp +++ b/code/ryzom/client/src/interface_v3/chat_text_manager.cpp @@ -20,6 +20,7 @@ // client #include "chat_text_manager.h" #include "nel/gui/view_text.h" +#include "nel/gui/group_paragraph.h" #include "interface_manager.h" using namespace std; @@ -149,34 +150,165 @@ static CInterfaceGroup *buildLineWithCommand(CInterfaceGroup *commandGroup, CVie return group; } -//================================================================================= -CViewBase *CChatTextManager::createMsgText(const ucstring &cstMsg, NLMISC::CRGBA col, bool justified /*=false*/) +static inline bool isUrlTag(const ucstring &s, ucstring::size_type index, ucstring::size_type textSize) { - ucstring msg = cstMsg; - CInterfaceGroup *commandGroup = parseCommandTag(msg); - CViewText *vt = new CViewText(CViewText::TCtorParam()); - // get parameters from config.xml - vt->setShadow(isTextShadowed()); - vt->setShadowOutline(false); - vt->setFontSize(getTextFontSize()); - vt->setMultiLine(true); - vt->setTextMode(justified ? CViewText::Justified : CViewText::DontClipWord); - vt->setMultiLineSpace(getTextMultiLineSpace()); - vt->setModulateGlobalColor(false); - - ucstring cur_time; - if (showTimestamps()) + // Format http://, https:// + // or markdown style (title)[http://..] + if(textSize > index+7) { - CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_CLOCK_12H", false); - if (node && node->getValueBool()) - cur_time = CInterfaceManager::getTimestampHuman("[%I:%M:%S %p] "); - else - cur_time = CInterfaceManager::getTimestampHuman(); + bool markdown = false; + ucstring::size_type i = index; + // advance index to url section if markdown style link is detected + if (s[i] == '(') + { + // scan for ')[http://' + while(i < textSize-9) + { + if (s[i] == ')' && s[i+1] == '[') + { + i += 2; + markdown = true; + break; + } + else + if (s[i] == ')') + { + i += 1; + break; + } + i++; + } + } + + if (textSize > i + 7) + { + bool isUrl = (toLower(s.substr(i, 7)) == ucstring("http://") || toLower(s.substr(i, 8)) == ucstring("https://")); + // match "text http://" and not "texthttp://" + if (isUrl && i > 0 && !markdown) + { + // '}' is in the list because of color tags, ie "@{FFFF}http://..." + const ucchar chars[] = {' ', '"', '\'', '(', '[', '}'}; + isUrl = std::find(std::begin(chars), std::end(chars), s[i - 1]) != std::end(chars); + } + return isUrl; + } } - // if text contain any color code, set the text formated and white, - // otherwise, set text normal and apply global color - size_t codePos = msg.find(ucstring("@{")); + return false; +} + +// *************************************************************************** +// isUrlTag must match +static inline void getUrlTag(const ucstring &s, ucstring::size_type &index, ucstring &url, ucstring &title) +{ + bool isMarkdown = false; + ucstring::size_type textSize = s.size(); + ucstring::size_type pos; + + // see if we have markdown format + if (s[index] == '(') + { + index++; + pos = index; + while(pos < textSize-9) + { + if (s[pos] == ')' && s[pos + 1] == '[') + { + isMarkdown = true; + title = s.substr(index, pos - index); + index = pos + 2; + break; + } + else if (s[pos] == ')') + { + break; + } + + pos++; + } + } + + ucchar chOpen = ' '; + ucchar chClose = ' '; + if (isMarkdown) + { + chOpen = '['; + chClose = ']'; + } + else if (index > 0) + { + chOpen = s[index - 1]; + if (chOpen == '\'') chClose = '\''; + else if (chOpen == '"') chClose = '"'; + else if (chOpen == '(') chClose = ')'; + else if (chOpen == '[') chClose = ']'; + else chClose = ' '; + } + + if (chOpen == chClose) + { + pos = s.find_first_of(chClose, index); + + // handle common special case: 'text http://.../, text' + if (pos != ucstring::npos && index > 0) + { + if (s[index-1] == ' ' && (s[pos-1] == ',' || s[pos-1] == '.')) + { + pos--; + } + } + } + else + { + // scan for nested open/close tags + pos = index; + sint nested = 0; + while(pos < textSize) + { + if (s[pos] == chOpen) + { + nested++; + } + else if (s[pos] == chClose) + { + if (nested == 0) + { + break; + } + else + { + nested--; + } + } + + pos++; + } + } + + // fallback to full string length as we did match http:// already and url spans to the end probably + if (pos == ucstring::npos) + { + pos = textSize; + } + + url = s.substr(index, pos - index); + index = pos; + + // skip ']' closing char + if (isMarkdown) index++; +} + +//================================================================================= +static void prependTimestamp(ucstring &msg) +{ + ucstring cur_time; + CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_CLOCK_12H", false); + if (node && node->getValueBool()) + cur_time = CInterfaceManager::getTimestampHuman("[%I:%M:%S %p] "); + else + cur_time = CInterfaceManager::getTimestampHuman(); + + ucstring::size_type codePos = msg.find(ucstring("@{")); if (codePos != ucstring::npos) { // Prepend the current time (do it after the color if the color at first position. @@ -189,13 +321,49 @@ CViewBase *CChatTextManager::createMsgText(const ucstring &cstMsg, NLMISC::CRGBA { msg = cur_time + msg; } - + } + else + { + msg = cur_time + msg; + } +} + +//================================================================================= +CViewBase *CChatTextManager::createMsgText(const ucstring &cstMsg, NLMISC::CRGBA col, bool justified /*=false*/, bool plaintext /*=false*/) +{ + ucstring msg = cstMsg; + CInterfaceGroup *commandGroup = parseCommandTag(msg); + + if (showTimestamps()) + prependTimestamp(msg); + + // must wrap all lines to CGroupParagraph because CGroupList will calculate + // width from previous line which ends up as CViewText otherwise + return createMsgTextComplex(msg, col, justified, plaintext, commandGroup); +} + +//================================================================================= +CViewBase *CChatTextManager::createMsgTextSimple(const ucstring &msg, NLMISC::CRGBA col, bool justified, CInterfaceGroup *commandGroup) +{ + CViewText *vt = new CViewText(CViewText::TCtorParam()); + // get parameters from config.xml + vt->setShadow(isTextShadowed()); + vt->setShadowOutline(false); + vt->setFontSize(getTextFontSize()); + vt->setMultiLine(true); + vt->setTextMode(justified ? CViewText::Justified : CViewText::DontClipWord); + vt->setMultiLineSpace(getTextMultiLineSpace()); + vt->setModulateGlobalColor(false); + + // if text contain any color code, set the text formated and white, + // otherwise, set text normal and apply global color + if (msg.find(ucstring("@{")) != ucstring::npos) + { vt->setTextFormatTaged(msg); vt->setColor(NLMISC::CRGBA::White); } else { - msg = cur_time + msg; vt->setText(msg); vt->setColor(col); } @@ -210,6 +378,112 @@ CViewBase *CChatTextManager::createMsgText(const ucstring &cstMsg, NLMISC::CRGBA } } +//================================================================================= +CViewBase *CChatTextManager::createMsgTextComplex(const ucstring &msg, NLMISC::CRGBA col, bool justified, bool plaintext, CInterfaceGroup *commandGroup) +{ + ucstring::size_type textSize = msg.size(); + + CGroupParagraph *para = new CGroupParagraph(CViewBase::TCtorParam()); + para->setId("line"); + para->setSizeRef("w"); + para->setResizeFromChildH(true); + + if (plaintext) + { + CViewBase *vt = createMsgTextSimple(msg, col, justified, NULL); + vt->setId("text"); + para->addChild(vt); + + return para; + } + + + // quickly check if text has links or not + bool hasUrl; + { + ucstring s = toLower(msg); + hasUrl = (s.find(ucstring("http://")) || s.find(ucstring("https://"))); + } + + ucstring::size_type pos = 0; + for (ucstring::size_type i = 0; i< textSize;) + { + if (hasUrl && isUrlTag(msg, i, textSize)) + { + if (pos != i) + { + CViewBase *vt = createMsgTextSimple(msg.substr(pos, i - pos), col, justified, NULL); + para->addChild(vt); + } + + ucstring url; + ucstring title; + getUrlTag(msg, i, url, title); + if (url.size() > 0) + { + CViewLink *vt = new CViewLink(CViewBase::TCtorParam()); + vt->setId("link"); + vt->setUnderlined(true); + vt->setShadow(isTextShadowed()); + vt->setShadowOutline(false); + vt->setFontSize(getTextFontSize()); + vt->setMultiLine(true); + vt->setTextMode(justified ? CViewText::Justified : CViewText::DontClipWord); + vt->setMultiLineSpace(getTextMultiLineSpace()); + vt->setModulateGlobalColor(false); + + //NLMISC::CRGBA color; + //color.blendFromui(col, CRGBA(255, 153, 0, 255), 100); + //vt->setColor(color); + vt->setColor(col); + + if (title.size() > 0) + { + vt->LinkTitle = title.toUtf8(); + vt->setText(title); + } + else + { + vt->LinkTitle = url.toUtf8(); + vt->setText(url); + } + + if (url.find_first_of('\'') != string::npos) + { + ucstring clean; + for(string::size_type i = 0; i< url.size(); ++i) + { + if (url[i] == '\'') + clean += ucstring("%27"); + else + clean += url[i]; + } + url = clean; + } + vt->setActionOnLeftClick("lua"); + vt->setParamsOnLeftClick("game:chatUrl('" + url.toUtf8() + "')"); + + para->addChildLink(vt); + + pos = i; + } + } + else + { + ++i; + } + } + + if (pos < textSize) + { + CViewBase *vt = createMsgTextSimple(msg.substr(pos, textSize - pos), col, justified, NULL); + vt->setId("text"); + para->addChild(vt); + } + + return para; +} + //================================================================================= CChatTextManager &CChatTextManager::getInstance() { diff --git a/code/ryzom/client/src/interface_v3/chat_text_manager.h b/code/ryzom/client/src/interface_v3/chat_text_manager.h index 0dfe05673..41326f067 100644 --- a/code/ryzom/client/src/interface_v3/chat_text_manager.h +++ b/code/ryzom/client/src/interface_v3/chat_text_manager.h @@ -24,6 +24,7 @@ namespace NLGUI { class CViewBase; + class CInterfaceGroup; } class ucstring; @@ -49,8 +50,9 @@ public: * \param msg the actual text * \param col the color of the text * \param justified Should be true for justified text (stretch spaces of line to fill the full width) + * \param plaintext Text will not be parsed for uri markup links */ - NLGUI::CViewBase *createMsgText(const ucstring &msg, NLMISC::CRGBA col, bool justified = false); + NLGUI::CViewBase *createMsgText(const ucstring &msg, NLMISC::CRGBA col, bool justified = false, bool plaintext = false); // Singleton access static CChatTextManager &getInstance(); @@ -73,6 +75,9 @@ private: ~CChatTextManager(); bool showTimestamps() const; + + NLGUI::CViewBase *createMsgTextSimple(const ucstring &msg, NLMISC::CRGBA col, bool justified, NLGUI::CInterfaceGroup *commandGroup); + NLGUI::CViewBase *createMsgTextComplex(const ucstring &msg, NLMISC::CRGBA col, bool justified, bool plaintext, NLGUI::CInterfaceGroup *commandGroup); }; // shortcut to get text manager instance diff --git a/code/ryzom/client/src/release.cpp b/code/ryzom/client/src/release.cpp index 98c81f27c..c326957cd 100644 --- a/code/ryzom/client/src/release.cpp +++ b/code/ryzom/client/src/release.cpp @@ -132,6 +132,19 @@ extern void selectTipsOfTheDay (uint tips); // FUNCTIONS // /////////////// +// *************************************************************************** +// Saving ingame resolution when in windowed mode +static void saveIngameResolution() +{ + if (ClientCfg.Windowed) + { + uint32 width, height; + Driver->getWindowSize(width, height); + ClientCfg.writeInt("Width", std::max((sint)width, 800)); + ClientCfg.writeInt("Height", std::max((sint)height, 600)); + } +} + // *************************************************************************** // 3D element release, called from both releaseMainLoopReselect() and releaseMainLoop() static void releaseMainLoopScenes() @@ -209,6 +222,8 @@ void releaseMainLoopReselect() { ProgressBar.release(); + saveIngameResolution(); + CInterfaceManager *pIM= CInterfaceManager::getInstance(); // save keys loaded and interface cfg (not done in releaseMainLoop() because done at end of mainLoop()...) @@ -364,6 +379,8 @@ void releaseMainLoop(bool closeConnection) { ProgressBar.release(); + saveIngameResolution(); + // Release R2 editor if applicable R2::getEditor().autoConfigRelease(IsInRingSession);