Fix css style order when using external css files
[ryzomcore.git] / ryzom / client / src / interface_v3 / interface_manager.cpp
blob66ed242331df41d517e0d44cb8221ed1932e4cfd
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2017 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 // Copyright (C) 2011 Robert TIMM (rti) <mail@rtti.de>
7 // Copyright (C) 2012 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
8 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
9 //
10 // This program is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Affero General Public License as
12 // published by the Free Software Foundation, either version 3 of the
13 // License, or (at your option) any later version.
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Affero General Public License for more details.
20 // You should have received a copy of the GNU Affero General Public License
21 // along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "stdpch.h"
27 // Memory
28 #include <memory>
30 #include "nel/misc/i_xml.h"
31 #include "nel/misc/o_xml.h"
32 #include "nel/misc/algo.h"
34 #include "nel/net/tcp_sock.h"
36 // Globals
37 #include "interface_manager.h"
38 #include "interface_config.h"
39 #include "task_bar_manager.h"
40 #include "guild_manager.h"
41 #include "../client_cfg.h"
42 #include "encyclopedia_manager.h"
43 // Expr
44 #include "nel/gui/interface_expr.h"
45 #include "register_interface_elements.h"
46 // Action / Observers
47 #include "nel/gui/action_handler.h"
48 #include "action_handler_misc.h"
49 #include "interface_observer.h"
50 #include "nel/gui/interface_anim.h"
51 #include "interface_ddx.h"
52 #include "action_handler_help.h"
53 #include "action_handler_item.h"
54 // View
55 #include "nel/gui/view_bitmap.h"
56 //#include "view_bitmap_progress.h"
57 #include "view_bitmap_faber_mp.h"
58 #include "nel/gui/view_bitmap_combo.h"
59 #include "nel/gui/view_text.h"
60 #include "nel/gui/view_text_id.h"
61 #include "nel/gui/view_text_formated.h"
62 // Ctrl
63 #include "nel/gui/ctrl_scroll.h"
64 #include "nel/gui/ctrl_button.h"
65 #include "nel/gui/ctrl_text_button.h"
66 // DBCtrl
67 #include "dbctrl_sheet.h"
68 // Group
69 #include "nel/gui/group_list.h"
70 #include "nel/gui/group_menu.h"
71 #include "nel/gui/group_container.h"
72 #include "nel/gui/group_modal.h"
73 #include "nel/gui/group_editbox.h"
74 #include "group_in_scene_bubble.h"
75 #include "group_skills.h"
76 #include "group_compas.h"
77 #include "nel/gui/group_html.h"
79 // Misc
80 #include "../input.h"
81 #include "bot_chat_manager.h"
82 #include "bot_chat_page_all.h"
83 #include "chat_displayer.h"
84 #include "skill_manager.h"
85 #include "../sound_manager.h"
86 #include "../actions.h"
87 #include "../actions_client.h"
89 #include "../weather_manager_client.h"
90 #include "../weather.h"
92 #include "../user_entity.h"
93 #include "../motion/user_controls.h"
94 #include "people_interraction.h"
95 #include "macrocmd_manager.h"
96 #include "inventory_manager.h"
98 #include "../connection.h" // needed for loading config file (PlayerSelectedFileName)
100 #include "sbrick_manager.h"
101 #include "sphrase_manager.h"
102 #include "bar_manager.h"
104 #include "../continent_manager.h"
105 #include "../entity_cl.h"
106 #include "../login.h"
108 #include "../sheet_manager.h" // for emotes
109 #include "../entity_animation_manager.h" // for emotes
110 #include "../net_manager.h" // for emotes
111 #include "../client_chat_manager.h" // for emotes
112 #include "../entities.h"
114 #include "../../common/src/game_share/ryzom_database_banks.h"
116 #include "chat_text_manager.h"
117 #include "../npc_icon.h"
119 #include "nel/gui/lua_helper.h"
120 using namespace NLGUI;
121 #include "nel/gui/lua_ihm.h"
122 #include "nel/web/curl_certificates.h"
124 #include "lua_ihm_ryzom.h"
126 #include "add_on_manager.h"
128 #include "game_share/r2_share_itf.h"
130 #include "../time_client.h"
132 #include "../r2/editor.h"
133 #include "../r2/dmc/client_edition_module.h"
135 #include "../bg_downloader_access.h"
137 #include "parser_modules.h"
139 #include "../global.h"
140 #include "user_agent.h"
141 #include "../item_group_manager.h"
143 #include "group_html_webig.h"
145 using namespace NLMISC;
147 namespace NLGUI
149 extern void luaDebuggerMainLoop();
152 extern CClientChatManager ChatMngr;
153 extern CContinentManager ContinentMngr;
154 extern bool IsInRingSession;
155 extern CEventsListener EventsListener;
157 namespace R2
159 extern bool ReloadUIFlag;
162 // ***************************************************************************
164 Version 11: - Dyn chat in user tab
165 Version 10: - Last screen resolution serialisation
166 Version 9: UI_DB_SAVE_VERSION system
167 Version 8: - serialInSceneBubbleInfo (for ignore context help)
168 Version 7: - serialMacroMemory
169 Version 6: DEPRECATED - Info about friend/ignore list
170 Version 5: - Info Windows pos
171 Version 4: - User landmark serialisation
172 Version 3: - Added a Hack for CInterfaceConfig version miss
173 Version 2: - TaskBar serialisation
174 Version 1: - people interraction
175 Version 0: - base version
177 #define ICFG_STREAM_VERSION 11
179 #ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
180 #define FOREACH(__itvar,__conttype,__contvar) \
181 for (__conttype::iterator __itvar(__contvar.begin()),__itvar##end(__contvar.end()); __itvar!=__itvar##end; ++__itvar)
182 #endif
184 // ***************************************************************************
186 using namespace std;
187 using namespace NLMISC;
188 using namespace NLNET;
190 // ------------------------------------------------------------------------------------------------
192 extern bool loginFinished;
193 void setLoginFinished( bool f );
194 // Edit actions
195 CActionsManager EditActions;
197 CInterfaceManager * CInterfaceManager::_Instance = NULL;
199 CChatDisplayer * ChatDisplayer = NULL;
202 void initActions();
203 void uninitActions();
205 ///\todo nico: remove this dummy displayer
206 NLMISC::CLog g_log;
209 ////////////
210 // GLOBAL //
211 ////////////
213 // Hierarchical timer
214 H_AUTO_DECL ( RZ_Client_Update_Frame_Events )
216 // ------------------------------------------------------------------------------------------------
217 // AJM TEMP TEMP TEMP TEMP
218 #ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
220 // track creation of an interface group
221 void CInterfaceManager::DebugTrackGroupsCreated( CInterfaceGroup *pIG )
223 // add to set
224 _DebugTrackGroupSet.insert( pIG );
226 // add to map and increment create counter
227 _DebugTrackGroupMap[pIG] = _DebugTrackGroupCreateCount++;
230 // track destruction of an interface group
231 void CInterfaceManager::DebugTrackGroupsDestroyed( CInterfaceGroup *pIG )
233 // lookup id of the group being destroyed (for debugging)
234 int foo = DebugTrackGroupsGetId( pIG );
236 // remove from set
237 setInterfaceGroupPtr::iterator it = _DebugTrackGroupSet.find( pIG );
238 if( it == _DebugTrackGroupSet.end() )
240 nldebug( "AJM DEBUG: Interface Group %x Destroyed twice", pIG );
241 return;
243 _DebugTrackGroupSet.erase( pIG );
245 // remove from map and increment destroy counter
246 _DebugTrackGroupMap.erase(pIG);
247 _DebugTrackGroupDestroyCount++;
250 // display the count of undestroyed interface groups
251 void CInterfaceManager::DebugTrackGroupsDump()
253 // dump groups
254 nldebug( "AJM DEBUG: %d Interface Groups remaining", _DebugTrackGroupCreateCount-_DebugTrackGroupDestroyCount );
256 FOREACH( itIG, mapInterfaceGroupPtr2Int, _DebugTrackGroupMap )
258 nldebug( " %d", itIG->second );
262 // return the index for an interface group
263 int CInterfaceManager::DebugTrackGroupsGetId( CInterfaceGroup *pIG )
265 mapInterfaceGroupPtr2Int::iterator it = _DebugTrackGroupMap.find( pIG );
266 if( it != _DebugTrackGroupMap.end() )
267 return it->second;
268 return -1;
271 #endif // AJM_DEBUG_TRACK_INTERFACE_GROUPS
273 class CDesktopUpdater : public CWidgetManager::INewScreenSizeHandler
275 public:
276 void process( uint32 w, uint32 h )
278 CInterfaceManager::getInstance()->updateDesktops( w, h );
282 class CDrawDraggedSheet : public CWidgetManager::IOnWidgetsDrawnHandler
284 public:
285 void process()
287 if ( CWidgetManager::getInstance()->getPointer()->show())
289 CDBCtrlSheet *pCS = dynamic_cast<CDBCtrlSheet*>( CWidgetManager::getInstance()->getCapturePointerLeft() );
290 if ((pCS != NULL) && (pCS->isDragged()))
292 sint x= CWidgetManager::getInstance()->getPointer()->getX() - pCS->getDeltaDragX();
293 sint y= CWidgetManager::getInstance()->getPointer()->getY() - pCS->getDeltaDragY();
294 pCS->drawSheet (x, y, false, false);
296 // if the control support CopyDrag, and if copy key pressed, display a tiny "+"
297 if(pCS->canDragCopy() && CInterfaceManager::getInstance()->testDragCopyKey())
299 CViewRenderer &rVR = *CViewRenderer::getInstance();
300 sint w= rVR.getSystemTextureW(CViewRenderer::DragCopyTexture);
301 sint h= rVR.getSystemTextureW(CViewRenderer::DragCopyTexture);
302 rVR.draw11RotFlipBitmap (pCS->getRenderLayer()+1, x-w/2, y-h/2, 0, false,
303 rVR.getSystemTextureId(CViewRenderer::DragCopyTexture));
311 class CStringManagerTextProvider : public CViewTextID::IViewTextProvider
313 bool getString( uint32 stringId, string &result )
315 return STRING_MANAGER::CStringManagerClient::instance()->getString( stringId, result );
318 bool getDynString( uint32 dynStringId, string &result )
320 return STRING_MANAGER::CStringManagerClient::instance()->getDynString( dynStringId, result );
324 class CRyzomTextFormatter : public CViewTextFormated::IViewTextFormatter
326 public:
327 std::string formatString( const std::string &inputString, const std::string &paramString )
329 std::string formatedResult;
331 // Apply the format
332 for(std::string::const_iterator it = inputString.begin(); it != inputString.end();)
334 if (*it == '$')
336 ++it;
337 if (it == inputString.end())
339 formatedResult += '$';
340 --it;
341 break;
344 switch(*it)
346 case 't': // add text ID
348 formatedResult += paramString;
349 break;
351 case 'P':
352 case 'p': // add player name
354 if (ClientCfg.Local || !UserEntity)
356 if (*it == 'P') formatedResult += "PLAYER";
357 else formatedResult += "Player";
359 else
361 std::string name = UserEntity->getEntityName();
362 if (*it == 'P') name = toUpper(name);
363 formatedResult += name;
365 break;
367 case 's':
368 case 'b': // add bot name
370 string botName;
371 bool womanTitle = false;
372 if (ClientCfg.Local)
374 botName = "NPC";
376 else
378 CLFECOMMON::TCLEntityId trader = CLFECOMMON::INVALID_SLOT;
379 if(UserEntity)
380 trader = UserEntity->trader();
381 if (trader != CLFECOMMON::INVALID_SLOT)
383 CEntityCL *entity = EntitiesMngr.entity(trader);
384 if (entity != NULL)
386 uint32 nDBid = entity->getNameId();
387 if (nDBid != 0)
389 STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
390 pSMC->getString(nDBid, botName);
392 else
394 botName = entity->getDisplayName();
396 CCharacterCL *pChar = dynamic_cast<CCharacterCL*>(entity);
397 if (pChar != NULL)
398 womanTitle = pChar->getGender() == GSGENDER::female;
402 // get the title translated
403 string sTitleTranslated = botName; // FIXME: UTF-8
404 CStringPostProcessRemoveName spprn;
405 spprn.Woman = womanTitle;
406 spprn.cbIDStringReceived(sTitleTranslated);
408 botName = CEntityCL::removeTitleAndShardFromName(botName);
410 // short name (with no title such as 'guard', 'merchant' ...)
411 if (*it == 's')
413 // But if there is no name, display only the title
414 if (botName.empty())
415 botName = sTitleTranslated;
417 else
419 // Else we want the title !
420 if (!botName.empty())
421 botName += " ";
422 botName += sTitleTranslated;
425 formatedResult += botName;
426 break;
428 default:
430 formatedResult += '$';
431 --it;
432 break;
435 ++it;
437 else
439 formatedResult += *it;
440 ++it;
444 return formatedResult;
448 namespace
450 CStringManagerTextProvider SMTextProvider;
451 CRyzomTextFormatter RyzomTextFormatter;
454 CInterfaceManager* CInterfaceManager::getInstance()
456 if( _Instance == NULL )
457 _Instance = new CInterfaceManager();
458 return _Instance;
461 // ------------------------------------------------------------------------------------------------
462 CInterfaceManager::CInterfaceManager()
464 CWidgetManager::getInstance()->registerNewScreenSizeHandler( new CDesktopUpdater() );
465 CWidgetManager::getInstance()->registerOnWidgetsDrawnHandler( new CDrawDraggedSheet() );
467 CInterfaceParser *parser = dynamic_cast< CInterfaceParser* >( CWidgetManager::getInstance()->getParser() );
469 parser->setSetupOptionsCallback( this );
470 parser->addModule( "scene3d", new CIF3DSceneParser() );
471 parser->addModule( "ddx", new CIFDDXParser() );
472 parser->addModule( "action_category", new CActionCategoryParser() );
473 parser->addModule( "command", new CCommandParser() );
474 parser->addModule( "key", new CKeyParser() );
475 parser->addModule( "macro", new CMacroParser() );
476 parser->addModule( "landmarks", new CLandmarkParser() );
477 parser->setCacheUIParsing( ClientCfg.CacheUIParsing );
479 CViewRenderer::setDriver( Driver );
480 CViewRenderer::setTextContext( TextContext );
481 CViewRenderer::hwCursorScale = ClientCfg.HardwareCursorScale;
482 CViewRenderer::hwCursors = &ClientCfg.HardwareCursors;
483 CViewRenderer::getInstance();
484 CViewTextID::setTextProvider( &SMTextProvider );
485 CViewTextFormated::setFormatter( &RyzomTextFormatter );
487 CGroupHTML::options.trustedDomains = ClientCfg.WebIgTrustedDomains;
488 CGroupHTML::options.languageCode = ClientCfg.getHtmlLanguageCode();
489 CGroupHTML::options.appName = getUserAgentName();
490 CGroupHTML::options.appVersion = getUserAgentVersion();
491 CGroupHTML::options.curlMaxConnections = ClientCfg.CurlMaxConnections;
493 if (!ClientCfg.CurlCABundle.empty())
495 // specify custom CA certs, lookup will be made in this function
496 NLWEB::CCurlCertificates::addCertificateFile(ClientCfg.CurlCABundle);
499 NLGUI::CDBManager::getInstance()->resizeBanks( NB_CDB_BANKS );
500 interfaceLinkUpdater = new CInterfaceLink::CInterfaceLinkUpdater();
501 _ScreenW = _ScreenH = 0;
502 _LastInGameScreenW = _LastInGameScreenH = 0;
503 _InterfaceScaleChanged = false;
504 _InterfaceScale = 1.0f;
505 _DescTextTarget = NULL;
506 _ConfigLoaded = false;
507 _LogState = false;
508 _KeysLoaded = false;
509 CWidgetManager::getInstance()->resetColorProps();
510 CWidgetManager::getInstance()->resetAlphaRolloverSpeedProps();
511 CWidgetManager::getInstance()->resetGlobalAlphasProps();
512 _NeutralColor = NULL;
513 _WarningColor = NULL;
514 _ErrorColor = NULL;
515 _EmotesInitialized = false;
518 // Global initialization
519 // *********************
521 // Interface Manager init
522 CViewRenderer::getInstance()->checkNewScreenSize();
524 uint32 w,h;
525 CViewRenderer::getInstance()->getScreenSize(w, h);
526 CWidgetManager::getInstance()->setScreenWH(w, h);
528 CViewRenderer::getInstance()->init();
530 _CurrentMode = 0;
531 _Modes.resize(MAX_NUM_MODES);
533 setInGame( false );
535 _LocalSyncActionCounter= 0;
536 // 4Bits counter.
537 _LocalSyncActionCounterMask= 15;
539 for(uint i=0;i<CHARACTERISTICS::NUM_CHARACTERISTICS;i++)
541 _CurrentPlayerCharac[i]= 0;
544 _CheckMailNode = NULL;
545 _CheckForumNode = NULL;
546 _UpdateWeatherTime = 0;
548 _DBB_UI_DUMMY = NULL;
549 _DB_UI_DUMMY_QUANTITY = NULL;
550 _DB_UI_DUMMY_QUALITY = NULL;
551 _DB_UI_DUMMY_SHEET = NULL;
552 _DB_UI_DUMMY_NAMEID = NULL;
553 _DB_UI_DUMMY_ENCHANT = NULL;
554 _DB_UI_DUMMY_SLOT_TYPE = NULL;
555 _DB_UI_DUMMY_PHRASE = NULL;
556 _DB_UI_DUMMY_WORNED = NULL;
557 _DB_UI_DUMMY_PREREQUISIT_VALID = NULL;
558 _DB_UI_DUMMY_FACTION_TYPE = NULL;
560 #ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
561 _DebugTrackGroupSet.clear();
562 _DebugTrackGroupMap.clear();
563 _DebugTrackGroupCreateCount = 0;
564 _DebugTrackGroupDestroyCount = 0;
565 #endif // AJM_DEBUG_TRACK_INTERFACE_GROUPS
569 // ------------------------------------------------------------------------------------------------
570 CInterfaceManager::~CInterfaceManager()
572 CViewTextID::setTextProvider( NULL );
573 CViewTextFormated::setFormatter( NULL );
574 reset(); // to flush IDStringWaiters
576 // release the database observers
577 releaseServerToLocalAutoCopyObservers();
580 removeFlushObserver( interfaceLinkUpdater );
581 delete interfaceLinkUpdater;
582 interfaceLinkUpdater = NULL;
584 _Instance = NULL;
587 // ------------------------------------------------------------------------------------------------
588 void CInterfaceManager::reset()
590 CViewRenderer::getInstance()->reset();
591 CWidgetManager::getInstance()->reset();
593 for (uint32 i = 0; i < _IDStringWaiters.size(); ++i)
594 delete _IDStringWaiters[i];
595 _IDStringWaiters.clear();
596 CGroupFrame::resetDisplayTypes();
598 _NeutralColor = NULL;
599 _WarningColor = NULL;
600 _ErrorColor = NULL;
604 // ------------------------------------------------------------------------------------------------
605 // unhook from observers we are tangled up in
606 void CInterfaceManager::releaseServerToLocalAutoCopyObservers()
608 ServerToLocalAutoCopyInventory.release();
609 ServerToLocalAutoCopyExchange.release();
610 ServerToLocalAutoCopyContextMenu.release();
611 ServerToLocalAutoCopySkillPoints.release();
614 void CInterfaceManager::setInGame( bool i )
616 _InGame = i;
617 CWidgetManager::getInstance()->setIngame( i );
620 // ------------------------------------------------------------------------------------------------
621 void CInterfaceManager::resetShardSpecificData()
623 _LocalSyncActionCounter= 0;
624 CGroupSkills::InhibitSkillUpFX = true;
625 CBarManager::getInstance()->resetShardSpecificData();
626 CBotChatManager::getInstance()->setCurrPage(NULL);
628 CSPhraseManager *pPM= CSPhraseManager::getInstance();
629 pPM->setEquipInvalidation(0, 0);
631 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(CWidgetManager::getInstance()->getElementFromId(WIN_TEMPINV));
632 if (pGC != NULL)
633 pGC->setActive(false);
636 // ------------------------------------------------------------------------------------------------
638 // ------------------------------------------------------------------------------------------------
639 void CInterfaceManager::destroy ()
641 delete _Instance;
642 _Instance = NULL;
645 void CInterfaceManager::initLUA()
647 CInterfaceParser *parser = dynamic_cast< CInterfaceParser* >( CWidgetManager::getInstance()->getParser() );
648 if( parser->isLuaInitialized() )
649 return;
651 parser->initLUA();
653 if( !parser->isLuaInitialized() )
654 return;
656 CLuaIHMRyzom::RegisterRyzomFunctions( *( CLuaManager::getInstance().getLuaState() ) );
659 // ------------------------------------------------------------------------------------------------
660 void CInterfaceManager::initLogin()
662 // Init LUA Scripting
663 initLUA();
665 // Clear the action manager
666 Actions.clear();
667 EditActions.clear();
669 // Register action in the action manager
670 ActionsContext.addActionsManager(&Actions, "");
671 ActionsContext.addActionsManager(&EditActions, RZ_CATEGORY_EDIT);
674 if (ClientCfg.XMLLoginInterfaceFiles.empty())
676 nlinfo("no xml login config files in client.cfg");
677 return;
680 nldebug("Textures Login Interface");
682 for (vector<string>::iterator it = ClientCfg.TexturesLoginInterface.begin(), end = ClientCfg.TexturesLoginInterface.end(); it != end; ++it)
684 nldebug("Textures Login Interface: %s", (*it).c_str());
685 loadTextures(*it + ".tga", *it + ".txt", false);
688 for (vector<string>::iterator it = ClientCfg.TexturesLoginInterfaceDXTC.begin(), end = ClientCfg.TexturesLoginInterfaceDXTC.end(); it != end; ++it)
690 nldebug("Textures Login Interface DXTC: %s", (*it).c_str());
691 loadTextures(*it + ".tga", *it + ".txt", true);
694 parseInterface (ClientCfg.XMLLoginInterfaceFiles, false);
696 CWidgetManager::getInstance()->updateAllLocalisedElements();
698 CWidgetManager::getInstance()->activateMasterGroup ("ui:login", true);
701 initActions();
705 // ------------------------------------------------------------------------------------------------
706 void CInterfaceManager::uninitLogin()
708 CInterfaceParser *parser = dynamic_cast< CInterfaceParser* >( CWidgetManager::getInstance()->getParser() );
710 CWidgetManager::getInstance()->activateMasterGroup ("ui:login", false);
712 parser->removeAll();
713 reset();
715 CWidgetManager::getInstance()->setPointer( NULL );
717 CInterfaceLink::removeAllLinks();
719 ICDBNode::CTextId textId("UI");
720 NLGUI::CDBManager::getInstance()->getDB()->removeNode(textId);
723 uninitActions();
726 // Close LUA Scripting
727 parser->uninitLUA();
730 // ------------------------------------------------------------------------------------------------
731 void CInterfaceManager::initOutGame()
733 // Clear the action manager
734 Actions.clear();
735 EditActions.clear();
737 // Register action in the action manager
738 ActionsContext.addActionsManager(&Actions, "");
739 ActionsContext.addActionsManager(&EditActions, RZ_CATEGORY_EDIT);
741 // Init LUA Scripting
742 initLUA();
744 if (ClientCfg.SelectCharacter != -1)
745 return;
748 if (SoundMngr != NULL)
750 NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
751 pMixer->loadSampleBank(false, "ui_outgame");
752 CVector initpos ( 0.0f, 0.0f, 0.0f );
753 pMixer->setListenerPos(initpos);
758 //NLMEMORY::CheckHeap (true);
760 if (ClientCfg.XMLOutGameInterfaceFiles.empty())
762 nlinfo("no xml outgame config files in client.cfg");
763 return;
766 nldebug("Textures OutGame Interface");
768 for (vector<string>::iterator it = ClientCfg.TexturesOutGameInterface.begin(), end = ClientCfg.TexturesOutGameInterface.end(); it != end; ++it)
770 nldebug("Textures OutGame Interface: %s", (*it).c_str());
771 loadTextures(*it + ".tga", *it + ".txt", false);
774 for (vector<string>::iterator it = ClientCfg.TexturesOutGameInterfaceDXTC.begin(), end = ClientCfg.TexturesOutGameInterfaceDXTC.end(); it != end; ++it)
776 nldebug("Textures OutGame Interface DXTC: %s", (*it).c_str());
777 loadTextures(*it + ".tga", *it + ".txt", true);
780 parseInterface (ClientCfg.XMLOutGameInterfaceFiles, false);
782 CWidgetManager::getInstance()->updateAllLocalisedElements();
784 CWidgetManager::getInstance()->activateMasterGroup ("ui:outgame", true);
786 // if (!ClientCfg.FSHost.empty())
787 // {
788 // // Hide the Launch Editor button, it works only with a Shard Unifier and web pages
789 // CInterfaceElement *elt = getElementFromId("ui:outgame:edit_session_but");
790 // elt->setActive(false);
791 // }
793 // Init the action manager
796 initActions();
798 //NLMEMORY::CheckHeap (true);
800 // Initialize the web browser
802 CGroupHTML *pGH = dynamic_cast<CGroupHTML*>( CWidgetManager::getInstance()->getElementFromId(GROUP_BROWSER));
804 if (pGH)
806 pGH->setActive(true);
807 pGH->browse(ClientCfg.PatchletUrl.c_str());
812 // ------------------------------------------------------------------------------------------------
813 void CInterfaceManager::uninitOutGame()
816 if (ClientCfg.SelectCharacter != -1)
817 return;
819 CWidgetManager::getInstance()->disableModalWindow();
821 //_Database->display("");
822 CBotChatManager::getInstance()->setCurrPage(NULL);
824 CInterfaceItemEdition::getInstance()->setCurrWindow(NULL);
826 // NLMISC::TTime initStart;
827 // initStart = ryzomGetLocalTime ();
828 if (SoundMngr != NULL)
830 NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
831 pMixer->unloadSampleBank("ui_outgame");
833 //nlinfo ("%d seconds for uninitOutGame", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
835 // initStart = ryzomGetLocalTime ();
836 CWidgetManager::getInstance()->activateMasterGroup ("ui:outgame", false);
838 CInterfaceParser *parser = dynamic_cast< CInterfaceParser* >( CWidgetManager::getInstance()->getParser() );
839 //nlinfo ("%d seconds for activateMasterGroup", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
840 // initStart = ryzomGetLocalTime ();
841 parser->removeAll();
842 //nlinfo ("%d seconds for removeAll", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
843 // initStart = ryzomGetLocalTime ();
844 reset();
845 //nlinfo ("%d seconds for reset", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
846 // reset the mouse pointer to avoid invalid pointer access
847 CWidgetManager::getInstance()->setPointer( NULL );
848 // initStart = ryzomGetLocalTime ();
849 CInterfaceLink::removeAllLinks();
850 //nlinfo ("%d seconds for removeAllLinks", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
851 // initStart = ryzomGetLocalTime ();
852 ICDBNode::CTextId textId("UI");
853 NLGUI::CDBManager::getInstance()->getDB()->removeNode(textId);
854 //nlinfo ("%d seconds for removeNode", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
856 // Init the action manager
859 // initStart = ryzomGetLocalTime ();
860 uninitActions();
861 // nlinfo ("%d seconds for uninitActions", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
864 // Close LUA Scripting
865 parser->uninitLUA();
867 //NLMEMORY::CheckHeap (true);
871 void badXMLParseMessageBox()
873 NL3D::UDriver *driver = CViewRenderer::getInstance()->getDriver();
874 NL3D::UDriver::TMessageBoxId ret = driver->systemMessageBox( "Interface XML reading failed!\n"
875 "Some XML files are corrupted and may have been removed.\n"
876 "Ryzom may need to be restarted to run properly.\n"
877 "Would you like to quit now?",
878 "XML reading failed!",
879 NL3D::UDriver::yesNoType,
880 NL3D::UDriver::exclamationIcon);
881 if (ret == NL3D::UDriver::yesId)
883 extern void quitCrashReport ();
884 quitCrashReport ();
885 exit (EXIT_FAILURE);
889 // ------------------------------------------------------------------------------------------------
890 void CInterfaceManager::initInGame()
892 setLoginFinished( true );
893 _LogState = false;
895 // Whole initInGame profile
896 NLMISC::TTime initStart;
897 initStart = ryzomGetLocalTime ();
899 // Init LUA Scripting
900 initLUA();
902 // Clear the action manager
903 Actions.clear();
904 EditActions.clear();
906 // Register action in the action manager
907 ActionsContext.addActionsManager(&Actions, "");
908 ActionsContext.addActionsManager(&EditActions, RZ_CATEGORY_EDIT);
911 if (SoundMngr != NULL)
913 NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
914 pMixer->loadSampleBank(false, "ui_ingame");
918 // NLMEMORY::CheckHeap (true);
920 if (ClientCfg.XMLInterfaceFiles.empty())
922 nlinfo("no xml config files in client.cfg");
923 return;
926 // Textures
927 loadIngameInterfaceTextures();
929 // NLMEMORY::CheckHeap (true);
931 // Skill Manager Init
932 CSkillManager *pSM = CSkillManager::getInstance();
933 pSM->initInGame();
935 // SBrick Manager Init
936 CSBrickManager *pSBM = CSBrickManager::getInstance();
937 pSBM->initInGame();
938 pSM->initTitles();
940 // SPhrase Manager DB Init (BEFORE loading). Must be init AFTER skill and brick init
941 CSPhraseManager *pPM= CSPhraseManager::getInstance();
942 pPM->initInGame();
944 // UI & keys
945 loadUI();
946 loadKeys();
948 // Initialize armour color (config.xml)
949 CDBCtrlSheet::initArmourColors();
951 // Initialize inventory manager : link to DB and to interface element so must be here
952 getInventory().init();
953 // Same for temp inventory manager
954 CTempInvManager::getInstance();
955 // Initialize guild manager
956 CGuildManager::getInstance();
958 // NLMEMORY::CheckHeap (true);
960 //init chat output
961 ChatDisplayer = new CChatDisplayer;
962 g_log.addDisplayer (ChatDisplayer);
963 NLMISC::ErrorLog->addDisplayer (ChatDisplayer);
964 NLMISC::WarningLog->addDisplayer (ChatDisplayer);
965 NLMISC::InfoLog->addDisplayer (ChatDisplayer);
966 NLMISC::DebugLog->addDisplayer (ChatDisplayer);
967 NLMISC::AssertLog->addDisplayer (ChatDisplayer);
969 // load bot chat datas
970 //CBotChat::init();
972 // init the bot chat
973 nlassert (BotChatPageAll == NULL);
974 BotChatPageAll = new CBotChatPageAll;
975 BotChatPageAll->init();
977 // NLMEMORY::CheckHeap (true);
979 // init the list of people
980 PeopleInterraction.init();
982 // flush system msg buffer
983 for( uint i=0; i<PeopleInterraction.SystemMessageBuffer.size(); ++i )
985 displaySystemInfo(PeopleInterraction.SystemMessageBuffer[i].Str, PeopleInterraction.SystemMessageBuffer[i].Cat);
987 PeopleInterraction.SystemMessageBuffer.clear();
989 // Init macro manager
990 CMacroCmdManager::getInstance()->initInGame();
993 H_AUTO( RZUpdAll )
995 CWidgetManager::getInstance()->updateAllLocalisedElements(); // To init all things
998 // Interface config
999 loadInterfaceConfig();
1001 //Load user landmarks
1002 loadLandmarks();
1004 // Must do extra init for people interaction after load
1005 PeopleInterraction.initAfterLoad();
1007 //CBotChatUI::refreshActiveWindows(); // bot chat windows are saved too..
1009 CWidgetManager::getInstance()->activateMasterGroup ("ui:interface", true);
1011 // Update the time in the ui database
1012 _CheckMailNode = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:MAIL_WAITING");
1013 _CheckForumNode = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:FORUM_UPDATED");
1015 // Init the action manager
1018 initActions();
1020 setInGame( true );
1022 // Init bubble manager
1023 InSceneBubbleManager.init();
1025 // Init Memory Bar for phraseManager. DB and ctrl gray state
1026 pPM->updateMemoryBar();
1028 // Init emotes
1029 _EmotesInitialized = false;
1030 initEmotes();
1032 // init chat manager
1033 ChatMngr.initInGame();
1035 // Init FlyingText manager
1036 FlyingTextManager.initInGame();
1038 // Init Bar Manager (HP, SAP etc... Bars)
1039 CBarManager::getInstance()->initInGame();
1041 // Init interface props linked to client time
1042 initClientTime();
1044 // Whole initInGame profile
1045 nlinfo ("%d seconds for initInGame", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
1047 // reset the compass target
1048 CGroupCompas *gc = dynamic_cast<CGroupCompas *>(CWidgetManager::getInstance()->getElementFromId("ui:interface:compass"));
1049 if (gc && gc->isSavedTargetValid())
1051 gc->setTarget(gc->getSavedTarget());
1054 // rebuild mp3 player playlist if user reselected a char (songs are already scanned)
1055 CAHManager::getInstance()->runActionHandler("music_player", NULL, "update_playlist");
1056 CAHManager::getInstance()->runActionHandler("music_player", NULL, "stop");
1058 CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CHATLOG_STATE", false);
1059 if (node)
1061 _LogState = (node->getValue32() != 0);
1064 if (_LogState)
1066 displaySystemInfo(CI18N::get("uiLogTurnedOn"));
1068 else
1070 displaySystemInfo(CI18N::get("uiLogTurnedOff"));
1073 startWebIgNotificationThread();
1076 // ------------------------------------------------------------------------------------------------
1077 void CInterfaceManager::loadIngameInterfaceTextures()
1079 nldebug("Textures Ingame Interface");
1081 for (vector<string>::iterator it = ClientCfg.TexturesInterface.begin(), end = ClientCfg.TexturesInterface.end(); it != end; ++it)
1083 nldebug("Textures Ingame Interface: %s", (*it).c_str());
1084 loadTextures(*it + ".tga", *it + ".txt", false);
1087 for (vector<string>::iterator it = ClientCfg.TexturesInterfaceDXTC.begin(), end = ClientCfg.TexturesInterfaceDXTC.end(); it != end; ++it)
1089 nldebug("Textures Ingame Interface DXTC: %s", (*it).c_str());
1090 loadTextures(*it + ".tga", *it + ".txt", true);
1094 // ------------------------------------------------------------------------------------------------
1095 void CInterfaceManager::loadUI()
1097 // Copy the array of file to load
1098 vector<string> xmlFilesToParse = getInGameXMLInterfaceFiles();
1100 if (!parseInterface (xmlFilesToParse, false))
1102 badXMLParseMessageBox();
1105 configureQuitDialogBox();
1108 // ------------------------------------------------------------------------------------------------
1109 void CInterfaceManager::configureQuitDialogBox()
1111 // Configure the quit dialog box according to the server
1112 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1113 string quitDialogMainStr = "ui:interface:quit_dialog";
1114 string quitDialogStr = quitDialogMainStr + ":indent_middle";
1115 CInterfaceGroup *quitDlg = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(quitDialogStr));
1116 if (quitDlg)
1118 CInterfaceElement *eltRet, *eltQuit, *eltQuitNow;
1119 eltRet = quitDlg->getElement(quitDialogStr+":return_mainland");
1120 eltQuit = quitDlg->getElement(quitDialogStr+":ryzom");
1121 eltQuitNow = quitDlg->getElement(quitDialogStr+":ryzom_now");
1122 sint buttonDeltaY;
1123 fromString( CWidgetManager::getInstance()->getParser()->getDefine("quit_button_delta_y"), buttonDeltaY);
1124 extern R2::TUserRole UserRoleInSession;
1126 bool sessionOwner = (R2::getEditor().getMode() != R2::CEditor::NotInitialized && R2::getEditor().getDMC().getEditionModule().isSessionOwner());
1128 // Show Launch Editor if not in editor mode
1129 CInterfaceElement *eltCancel = quitDlg->getElement(quitDialogStr+":cancel");
1130 CInterfaceElement *eltEdit = quitDlg->getElement(quitDialogStr+":launch_editor");
1131 if (eltEdit)
1133 if (UserRoleInSession != R2::TUserRole::ur_editor && !sessionOwner)
1135 eltEdit->setY(buttonDeltaY);
1136 eltEdit->setActive(true);
1138 if (eltCancel)
1139 (safe_cast<CCtrlTextButton*>(eltCancel))->setText(CI18N::get("uittQuitCancel"));
1141 else
1143 eltEdit->setY(0); // prevent from displaying a gap between two shown buttons
1144 eltEdit->setActive(false);
1146 if (eltCancel)
1147 (safe_cast<CCtrlTextButton*>(eltCancel))->setText(sessionOwner ? CI18N::get("uittQuitCancel") : CI18N::get("uittQuitCancelEditor"));
1151 // Other buttons
1152 if (IsInRingSession || (ClientCfg.Local && ClientCfg.R2EDEnabled))
1154 // display "return to mainland", unless we are the scenario owner (player or 'aventure master')
1155 if (eltRet)
1157 if (!sessionOwner || R2::getEditor().getMode()==R2::CEditor::EditionMode)
1159 //eltRet->setY(buttonDeltaY);
1160 const char *textLabel = (UserRoleInSession == R2::TUserRole::ur_editor) ? "uittLeaveEditor" : "uittReturnToMainland";
1161 (safe_cast<CCtrlTextButton*>(eltRet))->setText(CI18N::get(textLabel));
1162 eltRet->setY(buttonDeltaY);
1163 eltRet->setActive(true); // show Return to Mainland / PLAY
1165 else
1167 eltRet->setY(0);
1168 // when an owner of the session, there's an additionnal 'stop' button
1169 eltRet->setActive(false);
1172 if (eltQuit)
1174 eltQuit->setY(0);
1175 eltQuit->setActive(false);
1177 if (eltQuitNow)
1179 eltQuitNow->setY(buttonDeltaY);
1180 eltQuitNow->setActive(true); // show Quit (Now)
1183 else
1185 if (eltRet)
1187 eltRet->setY(0); // prevent from displaying a gap between two shown buttons
1188 eltRet->setActive(false);
1190 if (eltQuit)
1192 eltQuit->setY(buttonDeltaY);
1193 eltQuit->setActive(true); // show Quit (with progress bar)
1195 if (eltQuitNow)
1197 eltQuitNow->setY(0);
1198 eltQuitNow->setActive(false);
1203 // Make all controls have the same size
1204 CInterfaceGroup *quitDlgMain = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(quitDialogMainStr));
1205 if ( quitDlgMain )
1208 quitDlgMain->invalidateCoords();
1209 for (uint k = 0; k < 3; ++k)
1211 quitDlgMain->updateCoords(); // calculate the width of the text buttons
1214 const std::vector<CCtrlBase*>& controls = quitDlg->getControls();
1215 sint32 biggestWidth = 0;
1216 for ( std::vector<CCtrlBase*>::const_iterator ic=controls.begin(); ic!=controls.end(); ++ic )
1218 CCtrlTextButton *ctb = dynamic_cast<CCtrlTextButton*>(*ic);
1219 if ( ! ctb )
1220 continue;
1222 if ( ctb->getW() > biggestWidth )
1223 biggestWidth = ctb->getW();
1225 for ( std::vector<CCtrlBase*>::const_iterator ic=controls.begin(); ic!=controls.end(); ++ic )
1227 CCtrlTextButton *ctb = dynamic_cast<CCtrlTextButton*>(*ic);
1228 if ( ! ctb )
1229 continue;
1231 ctb->setWMin( biggestWidth );
1234 if ( quitDlgMain )
1237 quitDlgMain->invalidateCoords();
1238 for (uint k = 0; k < 3; ++k)
1240 quitDlgMain->updateCoords(); // calculate the width of the text buttons
1245 // ------------------------------------------------------------------------------------------------
1247 std::string CInterfaceManager::getSaveFileName(const std::string &module, const std::string &ext, bool useShared) const
1249 string filename = "save/" + module + "_" + PlayerSelectedFileName + "." + ext;
1250 if (useShared && !CFile::fileExists(filename))
1252 string sharedFile = "save/shared_" + module + "." + ext;
1253 if (CFile::fileExists(sharedFile))
1255 return sharedFile;
1258 return filename;
1261 // ------------------------------------------------------------------------------------------------
1262 void CInterfaceManager::loadKeys()
1264 if (ClientCfg.R2EDEnabled) // in R2ED mode the CEditor class deals with it
1265 return;
1267 CMacroCmdManager::getInstance()->removeAllMacros();
1269 vector<string> xmlFilesToParse;
1271 // Does the keys file exist ?
1272 string userKeyFileName = getSaveFileName("keys", "xml");
1273 if (CFile::fileExists(userKeyFileName) && CFile::getFileSize(userKeyFileName) > 0)
1275 // Load the user key file
1276 xmlFilesToParse.push_back (userKeyFileName);
1279 // Load the default key (but don't replace existings bounds, see keys.xml "key_def_no_replace")
1280 xmlFilesToParse.push_back ("keys.xml");
1282 if (!parseInterface (xmlFilesToParse, true))
1284 createFileBackup("Error loading keys", userKeyFileName);
1287 _KeysLoaded = true;
1290 // ------------------------------------------------------------------------------------------------
1291 void CInterfaceManager::loadInterfaceConfig()
1293 // Load interface.cfg
1294 if (ClientCfg.R2EDEnabled) // in R2ED mode the CEditor class deals with it
1295 return;
1297 string filename = getSaveFileName("interface", "icfg");
1298 loadConfig(filename); // Invalidate coords of changed groups
1300 _ConfigLoaded = true;
1303 // ------------------------------------------------------------------------------------------------
1304 void CInterfaceManager::uninitInGame0 ()
1306 // Autosave of the keys
1307 if (_KeysLoaded)
1309 saveKeys();
1311 _KeysLoaded = false;
1314 // Autosave of the interface in interface.cfg
1315 if (_ConfigLoaded)
1317 saveConfig();
1319 _ConfigLoaded = false;
1324 // ------------------------------------------------------------------------------------------------
1325 void CInterfaceManager::uninitInGame1 ()
1327 stopWebIgNotificationThread();
1329 // release Bar Manager (HP, SAP etc... Bars)
1330 CBarManager::getInstance()->releaseInGame();
1332 // release FlyingTextManager
1333 FlyingTextManager.releaseInGame();
1335 // release chat manager
1336 ChatMngr.releaseInGame();
1338 // Reset the chat text manager
1339 CChatTextManager::getInstance().reset();
1341 // release emotes
1342 uninitEmotes();
1344 // release bubble manager
1345 InSceneBubbleManager.release();
1347 // kill chat displayer
1348 if( ChatDisplayer )
1350 DebugLog->removeDisplayer (ChatDisplayer);
1351 InfoLog->removeDisplayer (ChatDisplayer);
1352 WarningLog->removeDisplayer (ChatDisplayer);
1353 ErrorLog->removeDisplayer (ChatDisplayer);
1354 AssertLog->removeDisplayer (ChatDisplayer);
1355 g_log.removeDisplayer(ChatDisplayer);
1356 delete ChatDisplayer;
1357 ChatDisplayer = NULL;
1360 // Release inventory manager
1361 CInventoryManager::releaseInstance();
1362 // Same for temp inventory manager
1363 CTempInvManager::releaseInstance();
1364 // Release guild manager
1365 CGuildManager::release();
1367 // release bot chat and manager
1368 CBotChatManager::getInstance()->setCurrPage(NULL);
1369 delete BotChatPageAll;
1370 BotChatPageAll = NULL;
1371 CBotChatManager::releaseInstance();
1373 //release CInterfaceItemEdition
1374 CInterfaceItemEdition::getInstance()->setCurrWindow(NULL);
1375 CInterfaceItemEdition::releaseInstance();
1377 // release task bar manager
1378 CTaskBarManager::releaseInstance();
1380 // People inetrraction release
1381 PeopleInterraction.release();
1383 if (SoundMngr != NULL)
1385 NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
1386 pMixer->unloadSampleBank("ui_ingame");
1389 // disable the game_quitting modal window
1390 CWidgetManager::getInstance()->disableModalWindow();
1392 // Remove all interface objects (containers, groups, variables, defines, ...)
1393 CWidgetManager::getInstance()->activateMasterGroup ("ui:interface", false);
1395 CInterfaceParser *parser = dynamic_cast< CInterfaceParser* >( CWidgetManager::getInstance()->getParser() );
1397 parser->removeAll();
1398 reset();
1399 CInterfaceLink::removeAllLinks();
1401 CWidgetManager::getInstance()->setPointer( NULL );
1403 // Release DDX manager, before DB remove
1404 CDDXManager::getInstance()->release();
1406 // Release client time, before DB remove
1407 releaseClientTime();
1409 // remove DB entry
1410 ICDBNode::CTextId textId("UI");
1411 NLGUI::CDBManager::getInstance()->getDB()->removeNode(textId);
1413 // Uninit the action manager
1416 uninitActions();
1419 // uninit phrase mgr
1420 CSPhraseManager *pPM = CSPhraseManager::getInstance();
1421 pPM->reset();
1422 CSPhraseManager::releaseInstance(); // must release before BrickManager, SkillManager
1424 // uninit brick manager
1425 // Don't release the instance because must not lost brick map and data
1426 CSBrickManager::getInstance()->uninitInGame();
1428 // Uninit skill manager (after phrase mgr)
1429 // AJM don't release SkillManager, else impulse msg update guild title will crash :(
1430 CSkillManager::getInstance()->uninitTitles();
1432 // Uninit macro manager
1433 CMacroCmdManager::getInstance()->uninitInGame();
1435 // Release interface help
1436 CInterfaceHelp::release();
1438 // Release guild manager
1439 CGuildManager::release();
1441 // Close LUA Scripting
1442 parser->uninitLUA();
1444 setInGame( false );
1445 _NeutralColor = NULL;
1446 _WarningColor = NULL;
1447 _ErrorColor = NULL;
1448 CWidgetManager::getInstance()->resetColorProps();
1449 CWidgetManager::getInstance()->resetAlphaRolloverSpeedProps();
1450 CWidgetManager::getInstance()->resetGlobalAlphasProps();
1452 #ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
1453 CInterfaceManager::getInstance()->DebugTrackGroupsDump();
1455 // NLMEMORY::ReportMemoryLeak();
1456 #endif
1461 // ------------------------------------------------------------------------------------------------
1462 void CInterfaceManager::flushDebugWindow()
1464 if (ChatDisplayer != NULL)
1465 ChatDisplayer->update();
1468 // ------------------------------------------------------------------------------------------------
1469 // Make sure 0.166 is displayed as 16% and 0.167 as 17%
1470 // because they belong to different weather conditions
1471 static float roundWeatherValue(float weatherValue)
1473 // Number of possible weather setups in server
1474 const static uint NB_WEATHER_SETUPS = 6;
1475 float floorValue = floorf(weatherValue * 100.f) / 100.f;
1476 uint weatherIndex = min((uint)(weatherValue * NB_WEATHER_SETUPS), NB_WEATHER_SETUPS - 1);
1477 uint floorIndex = min((uint)(floorValue * NB_WEATHER_SETUPS), NB_WEATHER_SETUPS - 1);
1479 if (weatherIndex > floorIndex)
1480 return ceilf(weatherValue * 100.f) / 100.f;
1482 return weatherValue;
1485 // ------------------------------------------------------------------------------------------------
1486 void CInterfaceManager::updateFrameEvents()
1489 H_AUTO_USE ( RZ_Client_Update_Frame_Events )
1491 // lua scripts from different thread
1492 flushScriptQueue();
1494 flushDebugWindow();
1496 // Handle anims done in 2 times because some AH can add or remove anims
1497 // First ensure we are working on a safe vector and update all anims
1498 CWidgetManager::getInstance()->updateAnims();
1500 IngameDbMngr.flushObserverCalls();
1501 NLGUI::CDBManager::getInstance()->flushObserverCalls();
1503 CWidgetManager::getInstance()->removeFinishedAnims();
1506 IngameDbMngr.flushObserverCalls();
1507 NLGUI::CDBManager::getInstance()->flushObserverCalls();
1509 // Handle waiting texts from server
1510 processServerIDString();
1512 if (_InGame)
1514 // Execute current macro
1515 CMacroCmdManager::getInstance()->updateMacroExecution();
1517 // Update guild handling (check if we have to rebuild)
1518 CGuildManager::getInstance()->update();
1520 // Update contact list with incoming server string ids
1521 PeopleInterraction.updateWaitingContacts();
1523 // Update string if some waiting
1524 CEncyclopediaManager::getInstance()->updateAllFrame();
1526 // Setup the weather setup in the player's map every 3 sec (1 ingame minute)
1527 if ((T0 - _UpdateWeatherTime) > (1 * 3 * 1000))
1529 _UpdateWeatherTime = T0;
1530 string str = CI18N::get ("uiTheSeasonIs") +
1531 CI18N::get ("uiSeason"+toStringEnum(computeCurrSeason())) +
1532 CI18N::get ("uiAndTheWeatherIs") +
1533 CI18N::get (WeatherManager.getCurrWeatherState().LocalizedName) +
1534 toString(", %d", (uint)(roundWeatherValue(WeatherManager.getWeatherValue()) * 100.f)) + "% " +CI18N::get("uiHumidity");
1538 CViewText *pVT = dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:weather"));
1539 if (pVT != NULL)
1540 pVT->setText(str);
1542 CCtrlBase *pTooltip= dynamic_cast<CCtrlBase*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:weather_tt"));
1543 if (pTooltip != NULL)
1545 string tt = toString("%02d", WeatherManager.getNextWeatherHour()) + CI18N::get("uiMissionTimerHour") +
1546 " - " + CI18N::get("uiHumidity") + " " +
1547 toString("%d", (uint)(roundWeatherValue(WeatherManager.getNextWeatherValue()) * 100.f)) + "%";
1548 pTooltip->setDefaultContextHelp(tt);
1551 // The date feature is temporarily disabled
1552 str.clear();
1554 // numeric version
1555 //str = CI18N::get("uiDate");
1556 //str += toString("%04d", RT.getRyzomYear()) + "/";
1557 //str += toString("%01d", RT.getRyzomCycle()+1) + " : ";
1558 //str += toString("%02d", RT.getRyzomMonthInCurrentCycle()+1) + "/";
1559 //str += toString("%02d", RT.getRyzomDayOfMonth()+1) + " - "; // Start at 1 for January
1560 //str += toString("%02d", (sint)RT.getRyzomTime()) + " " + CI18N::get("uiMissionTimerHour");
1562 // literal version
1563 // str = CI18N::get("uiDate");
1564 uint minutes = ((RT.getRyzomTime() - (sint)RT.getRyzomTime()) * (float) RYZOM_HOUR_IN_MINUTES);
1565 str += toString("%02d:%02d", (sint)RT.getRyzomTime(), minutes) + " - ";
1566 str += CI18N::get("ui"+WEEKDAY::toString( (WEEKDAY::EWeekDay)RT.getRyzomDayOfWeek() )) + ", ";
1567 str += CI18N::get("ui"+MONTH::toString( (MONTH::EMonth)RT.getRyzomMonthInCurrentCycle() )) + " ";
1568 str += toString("%02d", RT.getRyzomDayOfMonth()+1) + ", ";
1569 str += CI18N::get("uiAtysianCycle" + toString(RT.getRyzomCycle()+1) + "Ordinal") + " " + CI18N::get("uiAtysianCycle") + " ";
1570 str += toString("%04d", RT.getRyzomYear());
1572 pVT = dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:time"));
1573 if (pVT != NULL)
1574 pVT->setText(str);
1576 str.clear();
1577 // Update the clock in the compass if enabled.
1578 pVT = dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:compass:clock:time"));
1579 if (pVT != NULL)
1581 if (pVT->getActive())
1583 if (use12hClock())
1584 str = getTimestampHuman("%I:%M %p");
1585 else
1586 str = getTimestampHuman("%H:%M");
1587 pVT->setText(str);
1593 CWidgetManager::getInstance()->sendClockTickEvent();
1595 IngameDbMngr.flushObserverCalls();
1596 NLGUI::CDBManager::getInstance()->flushObserverCalls();
1598 // Update SPhrase manager
1599 CSPhraseManager *pPM= CSPhraseManager::getInstance();
1600 pPM->update();
1602 // if there's an external lua debugger, update it
1603 luaDebuggerMainLoop();
1605 // handle gc for lua
1606 CLuaManager::getInstance().getLuaState()->handleGC();
1608 #ifdef RYZOM_BG_DOWNLOADER
1609 CBGDownloaderAccess::getInstance().update();
1610 #endif
1612 CItemGroupManager::getInstance()->update();
1616 // ------------------------------------------------------------------------------------------------
1617 void CInterfaceManager::updateFrameViews(NL3D::UCamera camera)
1620 H_AUTO ( RZ_Interface_updateFrameViews )
1622 if (!camera.empty())
1623 CViewRenderer::getInstance()->setWorldSpaceFrustum (camera.getFrustum());
1625 CWidgetManager::getInstance()->checkCoords();
1626 drawViews(camera);
1628 // The interface manager may change usual Global setup. reset them.
1629 CViewRenderer::getTextContext()->setShadeColor(CRGBA::Black);
1633 void CInterfaceManager::setupOptions()
1635 CWidgetManager *wm = CWidgetManager::getInstance();
1636 wm->setupOptions();
1638 // Try to change font if any
1639 string sFont = wm->getSystemOption( CWidgetManager::OptionFont ).getValStr();
1641 if ((!sFont.empty()) && (Driver != NULL))
1642 resetTextContext(sFont.c_str(), true);
1643 // Continue to parse the rest of the interface
1645 sFont = wm->getSystemOption (CWidgetManager::OptionMonospaceFont).getValStr();
1646 if ((!sFont.empty()) && (Driver != NULL))
1647 CViewRenderer::registerFont("monospace", sFont);
1650 // ------------------------------------------------------------------------------------------------
1651 bool CInterfaceManager::parseInterface (const std::vector<std::string> &xmlFileNames, bool reload, bool isFilename)
1653 // cache some commonly used db nodes
1654 _DBB_UI_DUMMY = NLGUI::CDBManager::getInstance()->getDbBranch( "UI:DUMMY" );
1655 _DB_UI_DUMMY_QUANTITY = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:QUANTITY", true );
1656 _DB_UI_DUMMY_QUALITY = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:QUALITY", true );
1657 _DB_UI_DUMMY_SHEET = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:SHEET", true );
1658 _DB_UI_DUMMY_NAMEID = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:NAMEID", true );
1659 _DB_UI_DUMMY_ENCHANT = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:ENCHANT", true );
1660 _DB_UI_DUMMY_SLOT_TYPE = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:SLOT_TYPE", true );
1661 _DB_UI_DUMMY_PHRASE = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:PHRASE", true );
1662 _DB_UI_DUMMY_WORNED = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:WORNED", true );
1663 _DB_UI_DUMMY_PREREQUISIT_VALID = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:PREREQUISIT_VALID", true );
1664 _DB_UI_DUMMY_FACTION_TYPE = NLGUI::CDBManager::getInstance()->getDbProp( "UI:DUMMY:FACTION_TYPE", true );
1666 _DB_UI_DUMMY_QUANTITY->setValue64(0);
1667 _DB_UI_DUMMY_QUALITY->setValue64(0);
1668 _DB_UI_DUMMY_SHEET->setValue64(0);
1669 _DB_UI_DUMMY_NAMEID->setValue64(0);
1670 _DB_UI_DUMMY_ENCHANT->setValue64(0);
1671 _DB_UI_DUMMY_SLOT_TYPE->setValue64(0);
1672 _DB_UI_DUMMY_PHRASE->setValue64(0);
1673 _DB_UI_DUMMY_WORNED->setValue64(0);
1674 _DB_UI_DUMMY_PREREQUISIT_VALID->setValueBool(true);
1675 _DB_UI_DUMMY_FACTION_TYPE->setValue64(0);
1677 return CWidgetManager::getInstance()->getParser()->parseInterface (xmlFileNames, reload, isFilename);
1680 // ------------------------------------------------------------------------------------------------
1681 void CInterfaceManager::loadTextures (const string &textFileName, const string &uvFileName, bool uploadDXTC)
1683 CViewRenderer::getInstance()->loadTextures (textFileName, uvFileName, uploadDXTC);
1686 // ------------------------------------------------------------------------------------------------
1687 bool CInterfaceManager::loadConfig (const string &filename)
1689 // reset the interface
1690 vector<string> v;
1691 if (ClientCfg.R2EDEnabled)
1693 CWidgetManager::getInstance()->runProcedure ("proc_reset_r2ed_interface", NULL, v);
1695 else
1697 CWidgetManager::getInstance()->runProcedure ("proc_reset_interface", NULL, v);
1700 // By default, consider the reset interface has been set with the current resolution
1702 uint32 w,h;
1703 // NB: even if minimzed, getScreenSize() no more return 0 values (return the last setuped screen size)
1704 CViewRenderer::getInstance()->getScreenSize(w, h);
1705 // Windows are positioned according to resolution, and we must backup W/H for the system that move windows when the resolution change
1706 _LastInGameScreenW= w;
1707 _LastInGameScreenH= h;
1710 // if the config file doesn't exist,just quit
1711 CIFile f;
1712 string sFileName;
1713 sFileName = NLMISC::CPath::lookup (filename, false);
1714 if (sFileName.empty() || !f.open(sFileName))
1715 return false;
1718 // *** Load the config file
1719 uint32 nNbMode;
1720 CInterfaceConfig ic;
1721 bool lastInGameScreenResLoaded= false;
1722 uint32 nbLandmarks = 0;
1725 sint ver = f.serialVersion(ICFG_STREAM_VERSION);
1727 // serial user chats info (serial it before position of windows so that they can be updated properly)
1728 if (ver >= 1)
1730 f.serialCheck(NELID("_ICU"));
1731 if (!PeopleInterraction.loadUserChatsInfos(f))
1733 nlwarning("Bad user chat saving");
1737 // header
1738 f.serialCheck(NELID("GFCI"));
1739 f.serial(nNbMode);
1740 f.serial(_CurrentMode);
1741 if (_CurrentMode > nNbMode)
1743 _CurrentMode = 0;
1746 if(ver>=10)
1748 f.serial(_LastInGameScreenW);
1749 f.serial(_LastInGameScreenH);
1750 lastInGameScreenResLoaded= true;
1753 // Initialize at least number of modes that are saved in stream
1754 _Modes.resize(std::max((uint32)MAX_NUM_MODES, nNbMode));
1755 for (uint32 i = 0; i < _Modes.size(); ++i)
1757 NLMISC::contReset(_Modes[i]);
1760 // Load All Window configuration of all Modes
1761 for (uint32 i = 0; i < nNbMode; ++i)
1763 // must create a tmp mem stream because desktop image expect its datas to occupy the whole stream
1764 // This is because of old system that manipulated desktop image direclty as a mem stream
1765 CMemStream ms;
1766 if (!ms.isReading()) ms.invert();
1767 uint32 length;
1768 f.serial(length);
1769 if (length > 0)
1771 // HACK. if the version is <=2, then the CInterfaceConfig has no serialVersion. append here a 0
1772 if(ver<=2)
1774 uint8 *pBuffer = ms.bufferToFill(length+1);
1775 pBuffer[0]= 0;
1776 f.serialBuffer(pBuffer+1, length);
1778 else
1780 uint8 *pBuffer = ms.bufferToFill(length);
1781 f.serialBuffer(pBuffer, length);
1784 ms.seek(0, NLMISC::IStream::begin);
1785 _Modes[i].serial(ms); // build desktop image from stream
1788 // load UI_DB_SAVE_VERSION
1789 uint32 uiDbSaveVersion= 0; // default to 0 for old version of .icfg
1790 if(ver>=9)
1792 f.serial(uiDbSaveVersion);
1795 // read database
1796 ic.streamToDataBase(f, uiDbSaveVersion);
1799 // special for in game: backup last mission because of delayed update
1801 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:MISSION_SELECTED", false);
1802 if (pNL)
1804 CCDBNodeLeaf *pSelectedMissionBackup = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:MISSION_SELECTED_PREV_SESSION", true);
1805 pSelectedMissionBackup->setValue64(pNL->getValue64());
1810 // Deprecated. for Compatibility purpose: Load TaskBar.
1811 if(ver>=2)
1813 CTaskBarManager *pTBM= CTaskBarManager::getInstance();
1814 pTBM->serial(f);
1817 // Load user landmarks
1818 nbLandmarks = ContinentMngr.serialUserLandMarks(f);
1820 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp( "SERVER:INTERFACES:NB_BONUS_LANDMARKS" );
1821 if ( pNL )
1823 ICDBNode::CTextId textId;
1824 pNL->addObserver( &_LandmarkObs, textId);
1827 // Info Windows position.
1828 if(ver>=5)
1829 CInterfaceHelp::serialInfoWindows(f);
1830 else // Default pos
1831 CInterfaceHelp::resetWindowPos(-100);
1833 // Macro On Memory Position
1834 CSPhraseManager *pPM = CSPhraseManager::getInstance();
1835 if(ver>=7)
1836 pPM->serialMacroMemory(f);
1838 if(ver>=8)
1839 CGroupInSceneBubbleManager::serialInSceneBubbleInfo(f);
1841 if (ver >= 11)
1843 if ( ! PeopleInterraction.loadUserDynChatsInfos(f))
1845 nlwarning("Bad user dyn chat saving");
1849 catch(const NLMISC::EStream &)
1851 f.close();
1853 createFileBackup("Config loading failed", sFileName);
1855 nlwarning("Config loading failed : restore default");
1856 vector<string> v;
1857 if (!ClientCfg.R2EDEnabled)
1859 CWidgetManager::getInstance()->runProcedure ("proc_reset_interface", NULL, v);
1861 return false;
1863 f.close();
1865 if (nbLandmarks > 0)
1867 // use copy for backup so on save proper shared/player icfg file is used
1868 createFileBackup("Landmarks will be migrated to xml", sFileName, true);
1870 // if icfg is interface_player.icfg, then landmarks must also be loaded/saved to player file
1871 if (nlstricmp(sFileName.substr(0, 12), "save/shared_") != 0)
1873 string lmfile = getSaveFileName("landmarks", "xml", false);
1874 if (!CFile::fileExists(lmfile))
1876 // create placeholder player landmarks file so saveLandmarks will use it
1877 // even if shared landmarks file exists
1878 COFile f;
1879 if (f.open(lmfile, false, false, true))
1881 std::string xml;
1882 xml = "<?xml version=\"1.0\"?>\n<interface_config />";
1883 f.serialBuffer((uint8 *)xml.c_str(), xml.size());
1884 f.close();
1889 // merge .icfg landmarks with landmarks.xml
1890 loadLandmarks();
1891 saveLandmarks();
1894 // *** If saved resolution is different from the current one setuped, must fix positions in _Modes
1895 if(lastInGameScreenResLoaded)
1897 // Temporarily set screen to saved size so that positions are correctly calculated
1898 CWidgetManager::getInstance()->setScreenWH(_LastInGameScreenW, _LastInGameScreenH);
1899 // NB: we are typically InGame here (even though the _InGame flag is not yet set)
1900 // Use the screen size of the config file. Don't update current UI, just _Modes
1902 // ClientCfg has W/H set to screen size, but interface expects scaled size
1903 sint32 scaledW = ClientCfg.Width / ClientCfg.InterfaceScale;
1904 sint32 scaledH = ClientCfg.Height / ClientCfg.InterfaceScale;
1905 CWidgetManager::getInstance()->moveAllWindowsToNewScreenSize(scaledW, scaledH, false);
1906 updateDesktops(scaledW, scaledH);
1909 // *** apply the current mode
1910 _Modes[_CurrentMode].toCurrentDesktop();
1912 // *** Apply the NPC icon display mode
1913 CNPCIconCache::getInstance().init(!ClientCfg.R2EDEnabled && NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:INSCENE:FRIEND:MISSION_ICON")->getValueBool());
1915 return true;
1919 // ------------------------------------------------------------------------------------------------
1920 void CInterfaceManager::CDBLandmarkObs::update(ICDBNode *node)
1922 ContinentMngr.updateUserLandMarks();
1926 // visitor to send onQuit msg on all element
1927 class CQuitVisitor : public CInterfaceElementVisitor
1929 public:
1930 bool IsR2ED;
1931 bool BadWindowFound; //
1932 uint Desktop;
1933 virtual void visit(CInterfaceElement *elem) { elem->onQuit(); }
1934 virtual void visitGroup(CInterfaceGroup *group)
1936 if (!IsR2ED) return;
1937 if (Desktop != 0) return;
1938 if (group->getShortId() == "gestionsets")
1940 if (group->getActive())
1942 BadWindowFound = true;
1948 bool CInterfaceManager::saveLandmarks(bool verbose) const
1950 bool ret = true;
1952 if (!ClientCfg.R2EDEnabled)
1954 uint8 currMode = getMode();
1956 string filename = getSaveFileName("landmarks", "xml");
1957 if (verbose) CInterfaceManager::getInstance()->displaySystemInfo("Saving " + filename);
1958 ret = saveLandmarks(filename);
1961 return ret;
1964 bool CInterfaceManager::loadLandmarks()
1966 // Does the keys file exist ?
1967 string filename = getSaveFileName("landmarks", "xml");
1969 CIFile f;
1970 string sFileName;
1971 sFileName = NLMISC::CPath::lookup (filename, false);
1972 if (sFileName.empty() || !f.open(sFileName))
1973 return false;
1975 bool ret = false;
1976 vector<string> xmlFilesToParse;
1977 xmlFilesToParse.push_back (filename);
1979 //ContinentMngr.serialUserLandMarks(node);
1980 if (!parseInterface (xmlFilesToParse, true))
1982 f.close();
1984 createFileBackup("Error while loading landmarks", filename);
1986 ret = false;
1989 return ret;
1992 bool CInterfaceManager::saveLandmarks(const std::string &filename) const
1994 nlinfo( "Saving landmarks : %s", filename.c_str() );
1996 bool ret = false;
1999 COFile f;
2001 // using temporary file, so no f.close() unless its a success
2002 if (f.open(filename, false, false, true))
2004 COXml xmlStream;
2005 xmlStream.init (&f);
2007 xmlDocPtr doc = xmlStream.getDocument ();
2008 xmlNodePtr node = xmlNewDocNode(doc, NULL, (const xmlChar*)"interface_config", NULL);
2009 xmlDocSetRootElement (doc, node);
2011 ContinentMngr.writeTo(node);
2013 // Flush the stream
2014 xmlStream.flush();
2016 // Close the stream
2017 f.close ();
2019 ret = true;
2022 catch (const Exception &e)
2024 nlwarning ("Error while writing the file %s : %s.", filename.c_str(), e.what ());
2027 return ret;
2030 // ------------------------------------------------------------------------------------------------
2032 bool CInterfaceManager::saveConfig (bool verbose)
2034 bool ret = true;
2036 if (!ClientCfg.R2EDEnabled)
2038 uint8 currMode = getMode();
2040 string filename = getSaveFileName("interface", "icfg");
2042 if (verbose) CInterfaceManager::getInstance()->displaySystemInfo("Saving " + filename);
2043 ret = saveConfig(filename);
2045 if (currMode != getMode())
2046 setMode(currMode);
2049 return ret;
2052 // ------------------------------------------------------------------------------------------------
2053 bool CInterfaceManager::saveConfig (const string &filename)
2056 CQuitVisitor quitVisitor;
2058 quitVisitor.IsR2ED = false;
2059 if (nlstricmp(NLMISC::CFile::getFilename(filename).substr(0, 5), "r2ed_") == 0)
2061 quitVisitor.IsR2ED = true;
2063 quitVisitor.BadWindowFound = false;
2065 nlinfo( "Saving interface config : %s", filename.c_str() );
2067 COFile f;
2069 // using temporary file, so no f.close() unless its a success
2070 if (!f.open(filename, false, false, true)) return false;
2072 CInterfaceConfig ic;
2076 // cleanup all desktops
2077 for(uint k = 0; k < _Modes.size(); ++k)
2079 quitVisitor.Desktop = k;
2080 setMode(k);
2081 visit(&quitVisitor);
2082 CWidgetManager::getInstance()->checkCoords();
2084 setMode(0);
2085 setMode(_CurrentMode);
2087 if (quitVisitor.BadWindowFound)
2089 #ifdef NL_DEBUG
2090 nlassert(0);
2091 #endif
2092 // tmp patch : when trying to overwrite the r2ed_ config, if a bad window is found, just do nothing ...
2093 return true;
2097 _Modes[_CurrentMode].clear();
2098 if (_Modes[_CurrentMode].isReading()) _Modes[_CurrentMode].invert();
2099 clearAllEditBox();
2100 restoreAllContainersBackupPosition();
2101 ic.interfaceManagerToStream(_Modes[_CurrentMode]);
2104 uint32 i;
2106 i = _Modes.size();
2109 f.serialVersion(ICFG_STREAM_VERSION);
2111 // serial user chats info (serial it before position of windows so that they can be updated properly)
2112 f.serialCheck(NELID("_ICU"));
2113 if (!PeopleInterraction.saveUserChatsInfos(f))
2115 nlwarning("Config saving failed");
2116 // couldn't save result so do not continue
2117 return false;
2120 // header
2121 f.serialCheck(NELID("GFCI"));
2122 f.serial(i);
2123 f.serial(_CurrentMode);
2124 f.serial(_LastInGameScreenW);
2125 f.serial(_LastInGameScreenH);
2127 // Save All Window configuration of all Modes
2128 for (i = 0; i < _Modes.size(); ++i)
2130 // must create a tmp mem stream because desktop image expect its datas to occupy the whole stream
2131 // This is because of old system that manipulated desktop image direclty as a mem stream
2132 CMemStream ms;
2133 if (ms.isReading()) ms.invert();
2134 _Modes[i].serial(ms);
2135 uint32 length = ms.length();
2136 f.serial(length);
2137 if (length > 0)
2139 f.serialBuffer(const_cast<uint8 *>(ms.buffer()), length);
2143 // write UI_DB_SAVE_VERSION
2144 uint32 uiDbSaveVersion;
2145 fromString( CWidgetManager::getInstance()->getParser()->getDefine("UI_DB_SAVE_VERSION"), uiDbSaveVersion);
2146 f.serial(uiDbSaveVersion);
2148 // write database
2149 ic.dataBaseToStream(f);
2151 // Deprecated. for Compatibility purpose: Save TaskBar.
2152 CTaskBarManager *pTBM= CTaskBarManager::getInstance();
2153 pTBM->serial(f);
2155 //ContinentMngr.serialUserLandMarks(f);
2156 // empty landmarks block for compatibility
2158 f.serialVersion(1);
2159 uint32 numCont = 0;
2160 f.serial(numCont);
2163 // Info Windows position.
2164 CInterfaceHelp::serialInfoWindows(f);
2166 // Macro On Memory Position
2167 CSPhraseManager *pPM = CSPhraseManager::getInstance();
2168 pPM->serialMacroMemory(f);
2170 CGroupInSceneBubbleManager::serialInSceneBubbleInfo(f);
2172 if ( ! PeopleInterraction.saveUserDynChatsInfos(f))
2174 nlwarning("Bad user dyn chat saving");
2175 return false;
2178 f.close();
2180 catch(const NLMISC::EStream &)
2182 nlwarning("Config saving failed.");
2183 return false;
2186 ContinentMngr.serialFOWMaps();
2188 return true;
2191 // ------------------------------------------------------------------------------------------------
2192 void CInterfaceManager::drawViews(NL3D::UCamera camera)
2194 IngameDbMngr.flushObserverCalls();
2195 NLGUI::CDBManager::getInstance()->flushObserverCalls();
2197 // Update Player characteristics (for Item carac requirement Redifying)
2198 nlctassert(CHARACTERISTICS::NUM_CHARACTERISTICS==8);
2199 for (uint i=0; i<CHARACTERISTICS::NUM_CHARACTERISTICS; ++i)
2201 if (!_CurrentPlayerCharacLeaf[i])
2202 _CurrentPlayerCharacLeaf[i] = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:CHARACTER_INFO:CHARACTERISTICS%d:VALUE", i), false);
2204 NLMISC::CCDBNodeLeaf *node = NULL;
2206 if (_CurrentPlayerCharacLeaf[i])
2207 node = &*_CurrentPlayerCharacLeaf[i];
2209 _CurrentPlayerCharac[i] = node ? node->getValue32() : 0;
2212 // scale must be updated right before widget manager checks it
2213 if (_InterfaceScaleChanged)
2215 CViewRenderer::getInstance()->setInterfaceScale(_InterfaceScale);
2216 _InterfaceScaleChanged = false;
2219 CWidgetManager::getInstance()->drawViews( camera );
2221 // flush obs
2222 IngameDbMngr.flushObserverCalls();
2226 // ------------------------------------------------------------------------------------------------
2227 bool CInterfaceManager::handleEvent (const NLGUI::CEventDescriptor& event)
2229 bool handled = false;
2231 handled = CWidgetManager::getInstance()->handleEvent( event );
2233 if( event.getType() == NLGUI::CEventDescriptor::mouse )
2235 NLGUI::CEventDescriptorMouse &eventDesc = (NLGUI::CEventDescriptorMouse&)event;
2237 if( ( eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightup ) && handled )
2239 // prevent 'click in scene' as mouse was previously captured
2240 // (more a patch that anything, but 'UserControls' test for 'mouse up'
2241 // directly later in the main loop (not through message queue), so it has no way of knowing that the event was handled...
2242 if( CWidgetManager::getInstance()->getCapturePointerRight() == NULL )
2243 EventsListener.addUIHandledButtonMask(rightButton);
2244 }else
2245 if( ( eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup ) && handled )
2247 // prevent 'click in scene' as mouse was previously captured
2248 // (more a patch that anything, but 'UserControls' test for 'mouse up'
2249 // directly later in the main loop (not through message queue), so it has no way of knowing that the event was handled...
2250 if( CWidgetManager::getInstance()->getCapturePointerLeft() == NULL )
2251 EventsListener.addUIHandledButtonMask(leftButton);
2256 IngameDbMngr.flushObserverCalls();
2257 // event handled?
2258 return handled;
2261 void CInterfaceManager::updateDesktops( uint32 newScreenW, uint32 newScreenH )
2263 // *** Do it for All Backuped Desktops
2264 for(uint md=0; md<_Modes.size(); md++)
2266 CInterfaceConfig::CDesktopImage &mode= _Modes[md];
2267 // For all containers of this mode
2268 for(uint gc=0;gc<mode.GCImages.size();gc++)
2270 CInterfaceConfig::SCont &gcCont= mode.GCImages[gc];
2271 // Compute the new coordinate, directly in the X/Y fields of the structure
2272 CWidgetManager::getInstance()->getNewWindowCoordToNewScreenSize(gcCont.X, gcCont.Y, gcCont.W, gcCont.H ,newScreenW, newScreenH);
2276 _LastInGameScreenW = newScreenW;
2277 _LastInGameScreenH = newScreenH;
2280 class InvalidateTextVisitor : public CInterfaceElementVisitor
2282 public:
2283 InvalidateTextVisitor( bool reset )
2285 this->reset = reset;
2288 void visitGroup( CInterfaceGroup *group )
2290 const std::vector< CViewBase* > &vs = group->getViews();
2291 for( std::vector< CViewBase* >::const_iterator itr = vs.begin(); itr != vs.end(); ++itr )
2293 CViewText *vt = dynamic_cast< CViewText* >( *itr );
2294 if( vt != NULL )
2296 if( reset )
2297 vt->resetTextIndex();
2298 vt->updateTextContext();
2303 private:
2304 bool reset;
2308 // ------------------------------------------------------------------------------------------------
2309 void CInterfaceManager::addServerString (const std::string &sTarget, uint32 id, IStringProcess *cb)
2311 if (id == 0)
2313 CInterfaceExprValue val;
2314 val.setString (std::string());
2315 CInterfaceLink::setTargetProperty (sTarget, val);
2316 return;
2318 SIDStringWaiter *pISW = new SIDStringWaiter;
2319 pISW->Id = id;
2320 pISW->IdOrString = false;
2321 pISW->Target = sTarget;
2322 pISW->Cb = cb;
2323 _IDStringWaiters.push_back(pISW);
2326 // ------------------------------------------------------------------------------------------------
2327 void CInterfaceManager::addServerID (const std::string &sTarget, uint32 id, IStringProcess *cb)
2329 if (id == 0)
2331 CInterfaceExprValue val;
2332 val.setString (std::string());
2333 CInterfaceLink::setTargetProperty (sTarget, val);
2334 return;
2336 SIDStringWaiter *pISW = new SIDStringWaiter;
2337 pISW->Id = id;
2338 pISW->IdOrString = true;
2339 pISW->Target = sTarget;
2340 pISW->Cb = cb;
2341 _IDStringWaiters.push_back(pISW);
2344 // ------------------------------------------------------------------------------------------------
2345 void CInterfaceManager::processServerIDString()
2347 STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
2349 for (uint32 i = 0; i < _IDStringWaiters.size(); ++i)
2351 bool bAffect = false;
2352 string ucstrToAffect;
2353 SIDStringWaiter *pISW = _IDStringWaiters[i];
2354 if (pISW->IdOrString == true) // ID !
2356 if (pSMC->getString (pISW->Id, ucstrToAffect))
2357 bAffect = true;
2359 else // String !
2361 if (pSMC->getDynString (pISW->Id, ucstrToAffect))
2362 bAffect = true;
2365 if (bAffect)
2367 CInterfaceExprValue val;
2368 bool bValid = true;
2370 if (pISW->Cb != NULL)
2372 bValid = pISW->Cb->cbIDStringReceived(ucstrToAffect);
2373 delete pISW->Cb;
2376 if (bValid)
2378 ucstrToAffect = STRING_MANAGER::CStringManagerClient::getLocalizedName(ucstrToAffect);
2379 val.setString (ucstrToAffect);
2380 CInterfaceLink::setTargetProperty (pISW->Target, val);
2383 // Remove entry
2384 _IDStringWaiters.erase (_IDStringWaiters.begin()+i);
2385 i--;
2386 delete pISW;
2391 // ------------------------------------------------------------------------------------------------
2392 void CInterfaceManager::messageBoxInternal(const string &msgBoxGroup, const string &text, const string &masterGroup, TCaseMode caseMode)
2394 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":" + msgBoxGroup));
2395 CViewText *viewText= dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":" + msgBoxGroup + ":text"));
2397 if (group && viewText)
2399 viewText->setCaseMode(caseMode);
2400 viewText->setText(text);
2401 CWidgetManager::getInstance()->enableModalWindow(NULL, group);
2402 // don't understand why but need to update coords here
2403 group->updateCoords();
2404 group->updateCoords();
2408 // ------------------------------------------------------------------------------------------------
2409 void CInterfaceManager::messageBox(const string &text, const string &masterGroup, TCaseMode caseMode)
2411 messageBoxInternal("message_box", text, masterGroup, caseMode);
2415 // ------------------------------------------------------------------------------------------------
2416 void CInterfaceManager::messageBoxWithHelp(const std::string &text, const std::string &masterGroup,
2417 const std::string &ahOnOk, const std::string &paramsOnOk,
2418 TCaseMode caseMode)
2420 // replace the procedure "proc_valid_message_box_ok" action
2421 CWidgetManager::getInstance()->setProcedureAction("proc_message_box_with_help_ok", 1, ahOnOk, paramsOnOk);
2422 const char *mbName = "message_box_with_help";
2423 // if no action handler is wanted, then assume that
2424 // clicking 'ok' do not have any consequence, so allow exiting the message box by clicking
2425 // outside of it (this behavior is wanted on the login page, to allow to reclick on 'login' without
2426 // having to click 'ok' in the message box each time)
2427 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":" + mbName));
2428 CGroupModal *gm = dynamic_cast<CGroupModal *>(group);
2429 if (gm)
2431 gm->ExitClickOut = ahOnOk.empty();
2433 messageBoxInternal(mbName, text, masterGroup, caseMode);
2437 // ------------------------------------------------------------------------------------------------
2438 void CInterfaceManager::validMessageBox(TValidMessageIcon icon, const std::string &text, const std::string &ahOnOk,
2439 const std::string &paramsOnOk, const std::string &ahOnCancel, const std::string &paramsOnCancel, const string &masterGroup)
2441 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box"));
2442 CViewText *viewText= dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box:text"));
2443 CViewBitmap *viewBitmap= dynamic_cast<CViewBitmap*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box:icon_group:icon"));
2445 if (group && viewText)
2447 // replace the procedure "proc_valid_message_box_ok" action
2448 CWidgetManager::getInstance()->setProcedureAction("proc_valid_message_box_ok", 1, ahOnOk, paramsOnOk);
2449 // replace the procedure "proc_valid_message_box_cancel" action
2450 CWidgetManager::getInstance()->setProcedureAction("proc_valid_message_box_cancel", 1, ahOnCancel, paramsOnCancel);
2452 // set text and icon
2453 viewText->setText(text);
2454 if(viewBitmap)
2456 bool active= true;
2457 if(icon==QuestionIconMsg)
2458 viewBitmap->setTexture("brick_default.tga");
2459 else if(icon==WarningIconMsg)
2460 viewBitmap->setTexture("W_warning.tga");
2461 else if(icon==ErrorIconMsg)
2462 viewBitmap->setTexture("No_Action.tga");
2463 else
2464 active= false;
2465 viewBitmap->setActive(active);
2468 // Go
2469 CWidgetManager::getInstance()->enableModalWindow(NULL, group);
2470 // don't understand why but need to update coords here
2471 group->updateCoords();
2472 group->updateCoords();
2477 // ------------------------------------------------------------------------------------------------
2478 bool CInterfaceManager::getCurrentValidMessageBoxOnOk(string &ahOnOk, const std::string &masterGroup)
2480 // any modal window opened?
2481 CInterfaceGroup *mw= CWidgetManager::getInstance()->getModalWindow();
2482 if(!mw)
2483 return false;
2485 // Is this modal window the valid_message_box window?
2486 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box"));
2487 if(mw==group)
2489 // Ok, get the current procedure OnOk action
2490 string dummyParams;
2491 if( CWidgetManager::getInstance()->getParser()->getProcedureAction("proc_valid_message_box_ok", 1, ahOnOk, dummyParams))
2492 return true;
2495 return false;
2499 // ***************************************************************************
2500 void CInterfaceManager::displayDebugInfo(const string &str, TSystemInfoMode mode /*=InfoMsg*/)
2502 if (PeopleInterraction.DebugInfo)
2503 PeopleInterraction.ChatInput.DebugInfo.displayMessage(str, getDebugInfoColor(mode), 2);
2506 // ***************************************************************************
2507 NLMISC::CRGBA CInterfaceManager::getDebugInfoColor(TSystemInfoMode mode)
2509 if (_NeutralColor == NULL) // not initialised ?
2511 #define SYSTEM_INFO_COLOR_DB_PATH "UI:VARIABLES:SYSTEM_INFOS:COLORS"
2512 _NeutralColor = NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":NEUTRAL");
2513 _WarningColor = NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":WARNING");
2514 _ErrorColor = NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":ERROR");
2516 NLMISC::CRGBA color;
2517 switch(mode)
2519 case InfoMsg: color.setPacked(_NeutralColor->getValue32()); break;
2520 case WarningMsg: color.setPacked(_WarningColor->getValue32()); break;
2521 case ErrorMsg: color.setPacked(_ErrorColor->getValue32()); break;
2522 default:
2523 color = CRGBA::White;
2524 break;
2526 return color;
2529 // ***************************************************************************
2530 void CInterfaceManager::displaySystemInfo(const string &str, const string &cat)
2532 CClientConfig::SSysInfoParam::TMode mode = CClientConfig::SSysInfoParam::Normal;
2533 CRGBA color = CRGBA::White;
2536 map<string, CClientConfig::SSysInfoParam>::const_iterator it = ClientCfg.SystemInfoParams.find(toLowerAscii(cat));
2537 if (it != ClientCfg.SystemInfoParams.end())
2539 mode = it->second.Mode;
2540 color = it->second.Color;
2543 if (mode != CClientConfig::SSysInfoParam::OverOnly && mode != CClientConfig::SSysInfoParam::Around)
2545 if (PeopleInterraction.SystemInfo)
2546 PeopleInterraction.ChatInput.SystemInfo.displayMessage(str, color, 2);
2547 else
2549 CPeopleInterraction::CSysMsg sysMsg;
2550 sysMsg.Str = str;
2551 sysMsg.Cat = cat;
2552 PeopleInterraction.SystemMessageBuffer.push_back( sysMsg );
2556 if (mode == CClientConfig::SSysInfoParam::Center || mode == CClientConfig::SSysInfoParam::CenterAround)
2557 InSceneBubbleManager.addMessagePopupCenter(str, color);
2559 // If over popup a string at the bottom of the screen
2560 if ((mode == CClientConfig::SSysInfoParam::Over) || (mode == CClientConfig::SSysInfoParam::OverOnly))
2561 InSceneBubbleManager.addMessagePopup(str, color);
2562 else if ( (mode == CClientConfig::SSysInfoParam::Around || mode == CClientConfig::SSysInfoParam::CenterAround)
2563 && PeopleInterraction.AroundMe.Window)
2564 PeopleInterraction.ChatInput.AroundMe.displayMessage(str, color, 2);
2567 // ***************************************************************************
2568 CRGBA CInterfaceManager::getSystemInfoColor(const std::string &cat)
2570 CRGBA col = CRGBA::White;
2571 map<string, CClientConfig::SSysInfoParam>::const_iterator it = ClientCfg.SystemInfoParams.find(toLowerAscii(cat));
2572 if (it != ClientCfg.SystemInfoParams.end())
2573 col = it->second.Color;
2574 return col;
2577 // ***************************************************************************
2578 void CInterfaceManager::launchContextMenuInGame (const std::string &nameOfCM)
2580 // Launch the context menu in-game: can't appear while dragging an item
2581 if (CCtrlDraggable::getDraggedSheet() == NULL)
2583 if ( !CWidgetManager::getInstance()->hasModal() )
2585 // We must be in-game !
2586 CInterfaceGroup *pMG = CWidgetManager::getInstance()->getMasterGroupFromId("ui:interface");
2587 // TMP nico : try with login screen:
2588 if (!pMG)
2590 pMG = CWidgetManager::getInstance()->getMasterGroupFromId("ui:login");
2592 if (!pMG)
2594 pMG = CWidgetManager::getInstance()->getMasterGroupFromId("ui:outgame");
2596 if ((pMG != NULL) && (pMG->getActive()))
2598 CInterfaceElement *pIE = CWidgetManager::getInstance()->getElementFromId(nameOfCM);
2599 CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(pIE);
2600 if (pIG != NULL)
2602 CWidgetManager::getInstance()->enableModalWindow (NULL, pIG);
2610 // ***************************************************************************
2611 void CInterfaceManager::updateGroupContainerImage(CGroupContainer &gc, uint8 mode)
2613 if (mode >= _Modes.size())
2615 nlwarning("wrong desktop");
2616 return;
2618 _Modes[mode].updateGroupContainerImage(gc);
2621 // ***************************************************************************
2622 void CInterfaceManager::removeGroupContainerImage(const std::string &groupName, uint8 mode)
2624 if (mode >= _Modes.size())
2626 nlwarning("wrong desktop");
2627 return;
2629 _Modes[mode].removeGroupContainerImage(groupName);
2633 // ***************************************************************************
2634 void CInterfaceManager::removeGroupContainerImageFromDesktops(const std::string &groupName)
2636 for (uint i = 0; i < _Modes.size(); i++)
2638 _Modes[i].removeGroupContainerImage(groupName);
2642 // ***************************************************************************
2643 void CInterfaceManager::setMode(uint8 newMode)
2645 if (newMode >= _Modes.size())
2646 return;
2648 if (newMode == _CurrentMode)
2649 return;
2651 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
2653 // Check if we can change vdesk !
2654 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2656 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2657 if (rMG.Group->getActive())
2659 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
2661 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
2662 list<CInterfaceGroup*>::const_iterator itw;
2663 for (itw = rList.begin(); itw!= rList.end(); itw++)
2665 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(*itw);
2666 if ((pGC != NULL)&&(pGC->getActive()))
2668 // if this GC is a Full modal window, or if it is a modal son of another GC,
2669 if (pGC->isModal() || pGC->isModalSon())
2671 CWidgetManager::getInstance()->setTopWindow(pGC);
2672 pGC->enableBlink(2);
2673 return;
2675 else
2676 if (pGC->isGrayed())
2678 // Make the corresponding child blink
2679 pGC->blinkAllSons();
2680 return;
2688 // check if there's a special behaviour with current captured ctrl that prevent from changing desktop
2689 if ( CWidgetManager::getInstance()->getCapturePointerLeft() != NULL)
2691 if (!CWidgetManager::getInstance()->getCapturePointerLeft()->canChangeVirtualDesktop()) return;
2693 if ( CWidgetManager::getInstance()->getCapturePointerRight() != NULL)
2695 if (!CWidgetManager::getInstance()->getCapturePointerRight()->canChangeVirtualDesktop()) return;
2699 _Modes[_CurrentMode].fromCurrentDesktop();
2700 _Modes[newMode].toCurrentDesktop();
2701 //CBotChatUI::refreshActiveWindows();
2703 _CurrentMode = newMode;
2704 CWidgetManager::getInstance()->checkCoords();
2707 // ***************************************************************************
2708 void CInterfaceManager::resetMode(uint8 newMode)
2710 if (newMode >= _Modes.size())
2711 return;
2712 NLMISC::contReset(_Modes[newMode]);
2716 // for dump of interface content
2717 struct CDumpedGroup
2719 CInterfaceGroup *Group;
2720 uint Depth; // depth in the tree
2723 // ***************************************************************************
2724 void CInterfaceManager::dumpUI(bool /* indent */)
2726 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
2727 std::vector<CDumpedGroup> left;
2728 left.resize(_MasterGroups.size());
2729 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2731 left[nMasterGroup].Group = _MasterGroups[nMasterGroup].Group;
2732 left[nMasterGroup].Depth = 0;
2735 while (!left.empty())
2737 CInterfaceGroup *ig = left.back().Group;
2738 if (ig)
2740 uint currDepth = left.back().Depth;
2741 std::string id = ig->getId();
2742 std::string::size_type pos = id.find_last_of(':');
2743 if (pos != std::string::npos)
2745 id = id.substr(pos + 1);
2747 std::string info(currDepth * 4, ' ');
2748 info += id;
2749 info += toString(", address=0x%p", ig);
2750 nlinfo(info.c_str());
2751 // dump view & controls for this group
2752 for(uint k = 0; k < ig->getViews().size(); ++k)
2754 std::string info(currDepth * 4, ' ');
2755 info += toString("View %d / %d : ", (int) k + 1, (int) ig->getViews().size());
2756 if (ig->getViews()[k])
2758 info += id;
2759 NLGUI::CViewBase *view = ig->getViews()[k];
2760 info += toString(", type = %s, address=0x%p", typeid(*view).name(), view);
2762 else
2764 info += "<NULL>";
2766 nlinfo(info.c_str());
2769 for(uint k = 0; k < ig->getControls().size(); ++k)
2771 std::string info(currDepth * 4, ' ');
2772 info += toString("Ctrl %d / %d : ", (int) k + 1, (int) ig->getControls().size());
2773 if (ig->getControls()[k])
2775 info += id;
2776 NLGUI::CCtrlBase *control = ig->getControls()[k];
2777 info += toString(", type = %s, address=0x%p", typeid(*control).name(), control);
2779 else
2781 info += "<NULL>";
2783 nlinfo(info.c_str());
2787 left.pop_back();
2789 for(uint k = 0; k < ig->getNumGroup(); ++k)
2791 CDumpedGroup dg;
2792 dg.Group = ig->getGroup(k);
2793 dg.Depth = currDepth + 1;
2794 left.push_back(dg);
2800 // ***************************************************************************
2801 void CInterfaceManager::displayUIViewBBoxs(const std::string &uiFilter)
2803 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
2804 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2806 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2807 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
2809 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
2810 list<CInterfaceGroup*>::iterator it;
2811 for(it = rList.begin(); it != rList.end(); ++it)
2813 if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderView, uiFilter);
2819 // ***************************************************************************
2820 void CInterfaceManager::displayUICtrlBBoxs(const std::string &uiFilter)
2822 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
2823 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2825 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2826 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
2828 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
2829 list<CInterfaceGroup*>::iterator it;
2830 for(it = rList.begin(); it != rList.end(); ++it)
2832 if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderCtrl, uiFilter);
2838 // ***************************************************************************
2839 void CInterfaceManager::displayUIGroupBBoxs(const std::string &uiFilter)
2841 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
2842 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2844 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2845 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
2847 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
2848 list<CInterfaceGroup*>::iterator it;
2849 for(it = rList.begin(); it != rList.end(); ++it)
2851 if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderGroup, uiFilter);
2857 // ***************************************************************************
2858 void writeComboActionMap (const CActionsManager &actions, xmlNodePtr node, const string &context)
2860 // Get the combo defined
2861 const CActionsManager::TComboActionMap &combos = actions.getComboActionMap ();
2862 CActionsManager::TComboActionMap::const_iterator ite = combos.begin ();
2863 while (ite != combos.end ())
2865 // Key node
2866 xmlNodePtr keyNode = xmlNewChild ( node, NULL, (const xmlChar*)"key", NULL );
2868 // Props
2869 xmlSetProp (keyNode, (const xmlChar*)"name", (const xmlChar*)CEventKey::getStringFromKey(ite->first.Key).c_str());
2871 if (ite->first.KeyButtons&shiftKeyButton)
2872 xmlSetProp (keyNode, (const xmlChar*)"shift", (const xmlChar*)"1");
2873 if (ite->first.KeyButtons&ctrlKeyButton)
2874 xmlSetProp (keyNode, (const xmlChar*)"ctrl", (const xmlChar*)"1");
2875 if (ite->first.KeyButtons&altKeyButton)
2876 xmlSetProp (keyNode, (const xmlChar*)"menu", (const xmlChar*)"1");
2878 xmlSetProp (keyNode, (const xmlChar*)"action", (const xmlChar*)ite->second.Name.c_str());
2879 if (!(const xmlChar*)ite->second.Argu.empty())
2880 xmlSetProp (keyNode, (const xmlChar*)"params", (const xmlChar*)ite->second.Argu.c_str());
2882 // Context
2883 if (!context.empty ())
2884 xmlSetProp (keyNode, (const xmlChar*)"context", (const xmlChar*)context.c_str());
2886 ite++;
2890 // ***************************************************************************
2892 void writeMacros (xmlNodePtr node)
2894 const std::vector<CMacroCmd> &macros = CMacroCmdManager::getInstance()->getMacros();
2895 for (uint i = 0; i < macros.size(); ++i)
2897 macros[i].writeTo(node);
2901 // ***************************************************************************
2902 bool CInterfaceManager::saveKeys(bool verbose)
2904 bool ret = true;
2906 if (!ClientCfg.R2EDEnabled)
2908 string filename = "save/keys_" + PlayerSelectedFileName + ".xml";
2909 if (!CFile::fileExists(filename) && CFile::fileExists("save/shared_keys.xml"))
2910 filename = "save/shared_keys.xml";
2912 if (verbose) CInterfaceManager::getInstance()->displaySystemInfo("Saving " + filename);
2914 ret = saveKeys(filename);
2917 return ret;
2920 // ***************************************************************************
2921 bool CInterfaceManager::saveKeys(const std::string &filename)
2923 bool ret = false;
2927 COFile file;
2928 // using temporary file, so no file.close() unless its a success
2929 if (file.open (filename, false, false, true))
2931 COXml xmlStream;
2932 xmlStream.init (&file);
2934 xmlDocPtr doc = xmlStream.getDocument ();
2935 xmlNodePtr node = xmlNewDocNode(doc, NULL, (const xmlChar*)"interface_config", NULL);
2936 xmlDocSetRootElement (doc, node);
2938 writeComboActionMap (Actions, node, "");
2939 writeComboActionMap (EditActions, node, RZ_CATEGORY_EDIT);
2941 writeMacros (node);
2943 // Flush the stream
2944 xmlStream.flush();
2946 // Close the stream
2947 file.close ();
2949 // Done
2950 ret = true;
2952 else
2954 nlwarning ("Can't open the file %s", filename.c_str());
2957 catch (const Exception &e)
2959 nlwarning ("Error while writing the file %s : %s.", filename.c_str(), e.what ());
2961 return ret;
2964 // ***************************************************************************
2965 bool CInterfaceManager::deletePlayerConfig (const std::string &playerFileIdent)
2967 string fileName= "save/interface_" + playerFileIdent + ".icfg";
2968 return CFile::deleteFile(fileName);
2972 // ***************************************************************************
2973 bool CInterfaceManager::deletePlayerKeys (const std::string &playerFileIdent)
2975 string fileName = "save/keys_"+playerFileIdent+".xml";
2976 string fileNameEditor = "save/keys_r2ed_"+playerFileIdent+".xml";
2977 return CFile::deleteFile(fileName) && CFile::deleteFile(fileNameEditor);
2980 // ***************************************************************************
2981 void CInterfaceManager::log(const std::string &str, const std::string &cat)
2983 if (_LogState)
2985 // Open file with the name of the player
2986 const string fileName= "save/log_" + PlayerSelectedFileName + ".txt";
2987 FILE *f = nlfopen(fileName, "at");
2988 if (f != NULL)
2990 const string finalString = string(NLMISC::IDisplayer::dateToHumanString()) + " (" + NLMISC::toUpperAscii(cat) + ") * " + str;
2991 fprintf(f, "%s\n", finalString.c_str());
2992 fclose(f);
2997 // ***************************************************************************
2998 void CInterfaceManager::clearAllEditBox()
3000 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
3001 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
3003 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
3004 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
3006 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
3007 list<CInterfaceGroup*>::iterator it;
3008 for(it = rList.begin(); it != rList.end(); ++it)
3010 CInterfaceGroup *pIG = *it;
3011 if (pIG != NULL)
3012 pIG->clearAllEditBox();
3018 // ***************************************************************************
3019 void CInterfaceManager::restoreAllContainersBackupPosition()
3021 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
3022 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
3024 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
3025 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
3027 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
3028 list<CInterfaceGroup*>::iterator it;
3029 for(it = rList.begin(); it != rList.end(); ++it)
3031 if (*it) (*it)->restoreAllContainersBackupPosition();
3037 // ***************************************************************************
3038 void CInterfaceManager::visit(CInterfaceElementVisitor *visitor)
3040 nlassert(visitor);
3041 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
3042 for (uint nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
3044 if (_MasterGroups[nMasterGroup].Group)
3046 _MasterGroups[nMasterGroup].Group->visit(visitor);
3051 // ***************************************************************************
3052 void CInterfaceManager::incLocalSyncActionCounter()
3054 _LocalSyncActionCounter++;
3059 #if !FINAL_VERSION
3061 // ***************************************************************************
3062 NLMISC_COMMAND( localCounter, "Get value of local counter", "" )
3064 if (args.size() != 0) return false;
3065 CInterfaceManager *im = CInterfaceManager::getInstance();
3066 im->displaySystemInfo(toString(im->getLocalSyncActionCounter()));
3067 return true;
3070 #endif
3072 // ***************************************************************************
3074 NLMISC_COMMAND(loadui, "Load an interface file", "<loadui [all]/interface.xml>")
3076 if (args.size() != 1)
3077 return false;
3079 CInterfaceManager *im = CInterfaceManager::getInstance();
3081 std::vector<std::string> xmlFileNames;
3083 if (args[0] == "all")
3084 xmlFileNames = CInterfaceManager::getInGameXMLInterfaceFiles();
3085 else
3086 xmlFileNames.push_back (args[0]);
3088 bool result = im->parseInterface (xmlFileNames, true);
3089 #if !FINAL_VERSION
3090 if (result)
3091 CInterfaceManager::getInstance()->displaySystemInfo("File "+xmlFileNames.back()+" loaded successfully.");
3092 else
3093 CInterfaceManager::getInstance()->displaySystemInfo("File "+xmlFileNames.back()+" NOT loaded successully.");
3094 #endif
3096 // Invalidate the texts
3097 CWidgetManager::getInstance()->updateAllLocalisedElements();
3099 // reset captures
3100 CWidgetManager::getInstance()->setCapturePointerLeft(NULL);
3101 CWidgetManager::getInstance()->setCapturePointerRight(NULL);
3102 CWidgetManager::getInstance()->setOldCaptureKeyboard(NULL);
3103 CWidgetManager::getInstance()->setCaptureKeyboard(NULL);
3105 return result;
3108 // ***************************************************************************
3109 void CInterfaceManager::displayWebWindow(const string & name, const string & url)
3111 CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(name));
3112 if (pIG != NULL)
3114 pIG->setActive(true);
3115 pIG->updateCoords();
3116 pIG->center();
3119 CAHManager::getInstance()->runActionHandler("browse", NULL, "name="+name+":content:html|url="+url);
3122 // ***************************************************************************
3123 class CAHSaveUI : public IActionHandler
3125 virtual void execute (CCtrlBase *pCaller, const string &Params)
3127 CInterfaceManager::getInstance()->saveKeys(true);
3128 CInterfaceManager::getInstance()->saveConfig(true);
3131 REGISTER_ACTION_HANDLER (CAHSaveUI, "save_ui");
3134 // ***************************************************************************
3135 class CHandlerDispWebOnQuit : public IActionHandler
3137 virtual void execute (CCtrlBase *pCaller, const string &Params)
3139 if (ClientCfg.Local)
3140 CAHManager::getInstance()->runActionHandler("enter_modal", pCaller, "group=ui:interface:quit_dialog");
3141 else
3142 CInterfaceManager::getInstance()->displayWebWindow("ui:interface:web_on_quit", "http://213.208.119.190/igpoll/poll_form.php");
3145 REGISTER_ACTION_HANDLER (CHandlerDispWebOnQuit, "disp_web_on_quit");
3147 // ***************************************************************************
3148 class CHandlerExitWebOnQuit : public IActionHandler
3150 virtual void execute (CCtrlBase *pCaller, const string &Params)
3152 CAHManager::getInstance()->runActionHandler("quit_ryzom", pCaller);
3155 REGISTER_ACTION_HANDLER (CHandlerExitWebOnQuit, "exit_web_on_quit");
3158 // ***************************************************************************
3159 // EMOTES
3160 // ***************************************************************************
3162 struct CEmoteEntry
3164 uint32 EmoteId;
3165 string Path;
3166 string Anim;
3167 bool UsableFromClientUI;
3169 bool operator< (const CEmoteEntry & entry) const
3171 string path1 = Path;
3172 string path2 = entry.Path;
3174 for(;;)
3176 string::size_type pos1 = path1.find('|');
3177 string::size_type pos2 = path2.find('|');
3179 string s1 = toUpper(CI18N::get(path1.substr(0, pos1)));
3180 string s2 = toUpper(CI18N::get(path2.substr(0, pos2)));
3182 sint result = s1.compare(s2);
3183 if (result != 0)
3184 return (result < 0);
3186 if (pos1 == string::npos)
3187 return (pos2 != string::npos);
3188 if (pos2 == string::npos)
3189 return false;
3191 path1 = path1.substr(pos1 + 1);
3192 path2 = path2.substr(pos2 + 1);
3194 return false;
3198 static bool translateEmote(const std::string &id, std::string &translatedName, std::string &commandName, std::string &commandNameAlt)
3200 if (CI18N::hasTranslation(id))
3202 translatedName = CI18N::get(id);
3204 // convert command to utf8 since emote translation can have strange chars
3205 commandName = toLower(translatedName);
3207 // replace all spaces by _
3208 while (strFindReplace(commandName, " ", "_"));
3210 // TODO: remove accents
3211 commandNameAlt = commandName;
3213 if (commandNameAlt == commandName) commandNameAlt.clear();
3215 return true;
3218 translatedName = id;
3219 commandName = id;
3221 return false;
3224 // ***************************************************************************
3225 void CInterfaceManager::initEmotes()
3227 _EmotesInitialized = true;
3228 CTextEmotListSheet *pTELS = dynamic_cast<CTextEmotListSheet*>(SheetMngr.get(CSheetId("list.text_emotes")));
3229 if (pTELS == NULL)
3230 return;
3232 static list<CEmoteEntry> entries;
3233 if (entries.empty())
3235 for (uint i = 0; i < pTELS->TextEmotList.size(); i++)
3237 CEmoteEntry entry;
3238 entry.EmoteId = i;
3239 entry.Path = pTELS->TextEmotList[i].Path;
3240 entry.Anim = pTELS->TextEmotList[i].Anim;
3241 entry.UsableFromClientUI = pTELS->TextEmotList[i].UsableFromClientUI;
3242 entries.push_back(entry);
3244 entries.sort();
3247 // The list of behaviour missnames emotList
3248 CEmotListSheet *pEmotList = dynamic_cast<CEmotListSheet*>(SheetMngr.get(CSheetId("list.emot")));
3249 nlassert (pEmotList != NULL);
3250 nlassert (pEmotList->Emots.size() <= 255);
3252 // Get the focus beta tester flag
3253 bool betaTester = false;
3255 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3256 CSkillManager *pSM = CSkillManager::getInstance();
3258 betaTester = pSM->isTitleUnblocked(CHARACTER_TITLE::FBT);
3259 string previousMind;
3260 CGroupSubMenu *pFirstMenu = 0;
3262 for (list<CEmoteEntry>::const_iterator it = entries.begin(); it != entries.end(); it++)
3264 uint32 nEmoteNb = (*it).EmoteId;
3265 string sState = (*it).Anim;
3266 string sName = (*it).Path;
3268 // Check that the emote can be added to UI
3269 // ---------------------------------------
3270 if( (*it).UsableFromClientUI == false )
3272 continue;
3275 // Check the emote reserved for FBT (hardcoded)
3276 // --------------------------------------------
3277 if (sState == "FBT" && !betaTester)
3278 continue;
3280 // Get the behaviour from the list of emotes
3281 // -----------------------------------------
3282 uint8 nBehav = 255;
3283 uint32 i, j;
3284 for (i = 0; i < pEmotList->Emots.size(); ++i)
3285 if (CAnimationStateSheet::getAnimationStateName(pEmotList->Emots[i]) == sState)
3287 nBehav = (uint8)i;
3288 break;
3291 // Add to the game context menu
3292 // ----------------------------
3293 uint32 nbToken = 1;
3294 for (i = 0; i < sName.size(); ++i)
3295 if (sName[i] == '|')
3296 nbToken++;
3298 CGroupMenu *pRootMenu = dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:user_chat_emote_menu"));
3299 nlassert(pRootMenu);
3301 CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
3302 nlassert(pMenu);
3304 std::string sTranslatedName;
3305 std::string sCommandName;
3306 std::string sCommandNameAlt;
3308 // Add to the game context menu
3309 // ----------------------------
3310 for (i = 0; i < nbToken; ++i)
3312 string sTmp;
3313 if (i != (nbToken-1))
3314 sTmp = sName.substr(0,sName.find('|'));
3315 else
3316 sTmp = sName;
3318 // Look if this part of the path is already present
3319 bool bFound = false;
3320 for (j = 0; j < pMenu->getNumLine(); ++j)
3322 if (sTmp == pMenu->getLineId(j))
3324 bFound = true;
3325 break;
3330 if (!bFound) // Create it
3332 if (i != (nbToken-1))
3334 pMenu->addLine (CI18N::get(sTmp), "", "", sTmp);
3336 // Create a sub menu
3337 CGroupSubMenu *pNewSubMenu = new CGroupSubMenu(CViewBase::TCtorParam());
3338 pMenu->setSubMenu(j, pNewSubMenu);
3340 if (pFirstMenu == 0)
3341 pFirstMenu = pNewSubMenu;
3343 else
3345 translateEmote(sTmp, sTranslatedName, sCommandName, sCommandNameAlt);
3347 // Create a line
3348 pMenu->addLine (sTranslatedName + " (/" + sCommandName + ")", "emote",
3349 "nb="+toString(nEmoteNb)+"|behav="+toString(nBehav), sTmp);
3353 // Jump to sub menu
3354 if (i != (nbToken-1))
3356 pMenu = pMenu->getSubMenu(j);
3357 sName = sName.substr(sName.find('|')+1,sName.size());
3361 if (sTranslatedName.empty())
3362 translateEmote(sName, sTranslatedName, sCommandName, sCommandNameAlt);
3364 // Create new command
3365 // ------------------
3366 if (!sTranslatedName.empty())
3368 if(ICommand::exists(sCommandName))
3370 nlwarning("Translation for emote %s already exist: '%s' exist twice", sName.c_str(), sCommandName.c_str());
3372 else
3374 CEmoteCmd *pNewCmd = new CEmoteCmd(sCommandName.c_str(), "", "");
3375 pNewCmd->EmoteNb = nEmoteNb;
3376 pNewCmd->Behaviour = nBehav;
3377 _EmoteCmds.push_back(pNewCmd);
3379 // add alternative command if defined
3380 if (!sCommandNameAlt.empty())
3382 if(ICommand::exists(sCommandNameAlt))
3384 nlwarning("Translation for emote %s already exist: '%s' exist twice", sName.c_str(), sCommandName.c_str());
3386 else
3388 CEmoteCmd *pNewCmd = new CEmoteCmd(sCommandNameAlt.c_str(), "", "");
3389 pNewCmd->EmoteNb = nEmoteNb;
3390 pNewCmd->Behaviour = nBehav;
3391 _EmoteCmds.push_back(pNewCmd);
3395 CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
3397 // Quick-Emote too ?
3398 for (i = 0; i< pMenu->getNumLine (); i++)
3400 if (sName == pMenu->getLineId (i))
3402 // Yeah that's a quick emote too; set command
3403 pMenu->addLineAtIndex (i,
3404 "@{FFFF}/" + sCommandName,
3405 "emote", "nb="+toString(nEmoteNb)+"|behav="+toString(nBehav),
3406 "", "", "", false, false, true);
3408 pMenu->removeLine (i+1);
3409 break;
3414 else
3416 nlwarning("No translation for emote %s", sName.c_str());
3420 // Insert separators
3421 if (pFirstMenu)
3423 pFirstMenu->addSeparatorAtIndex (0, "Positive");
3424 pFirstMenu->addSeparatorAtIndex (4, "Neutral");
3425 pFirstMenu->addSeparatorAtIndex (8, "Negative");
3430 // ***************************************************************************
3431 void CInterfaceManager::uninitEmotes()
3433 if( !_EmotesInitialized )
3434 return;
3435 _EmotesInitialized = false;
3437 // reset the emotes menu
3438 CTextEmotListSheet *pTELS = dynamic_cast<CTextEmotListSheet*>(SheetMngr.get(CSheetId("list.text_emotes")));
3439 if (pTELS != NULL && !pTELS->TextEmotList.empty())
3441 // get the emotes menu id
3442 string sPath = pTELS->TextEmotList[0].Path;
3443 string sId = sPath.substr(0, sPath.find('|'));
3445 // get the emotes menu
3446 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3447 CGroupMenu *pRootMenu = dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:game_context_menu"));
3448 if( pRootMenu )
3450 CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
3451 for (uint i = 0; i < pMenu->getNumLine(); ++i)
3453 if (pMenu->getLineId(i) == sId)
3455 pMenu = pMenu->getSubMenu(i);
3456 pMenu->reset();
3457 break;
3463 // clear commands
3464 for (uint32 i = 0; i < _EmoteCmds.size(); ++i)
3465 delete _EmoteCmds[i];
3466 _EmoteCmds.clear();
3469 // ***************************************************************************
3470 void CInterfaceManager::updateEmotes()
3472 uninitEmotes();
3473 initEmotes();
3476 // ***************************************************************************
3477 // Just call the action handler with good params
3478 bool CInterfaceManager::CEmoteCmd::execute(const std::string &/* rawCommandString */, const vector<string> &args, CLog &/* log */, bool /* quiet */, bool /* human */)
3480 string customPhrase;
3481 if (!args.empty())
3483 customPhrase = args[0];
3485 for(uint i = 1; i < args.size(); ++i )
3487 customPhrase += " ";
3488 customPhrase += args[i];
3490 CAHManager::getInstance()->runActionHandler("emote", NULL, "nb="+toString(EmoteNb)+"|behav="+toString(Behaviour)+"|custom_phrase="+customPhrase);
3491 return true;
3494 // ***************************************************************************
3495 bool CInterfaceManager::testDragCopyKey()
3497 // hardcoded for now
3498 return Driver->AsyncListener.isKeyDown(KeyCONTROL) ||
3499 Driver->AsyncListener.isKeyDown(KeyLCONTROL) ||
3500 Driver->AsyncListener.isKeyDown(KeyRCONTROL);
3503 // ***************************************************************************
3504 void CInterfaceManager::notifyMailAvailable()
3506 if (_CheckMailNode != NULL)
3507 _CheckMailNode->setValue32(1);
3510 void CInterfaceManager::notifyForumUpdated()
3512 if (_CheckForumNode != NULL)
3513 _CheckForumNode->setValue32(1);
3516 void CInterfaceManager::queueLuaScript(const std::string &script)
3518 CAutoMutex<CMutex> autoMutex(_ScriptQueueMutex);
3520 _ScriptQueue.push(script);
3523 void CInterfaceManager::flushScriptQueue()
3525 CAutoMutex<CMutex> autoMutex(_ScriptQueueMutex);
3527 while(!_ScriptQueue.empty())
3529 CLuaManager::getInstance().executeLuaScript(_ScriptQueue.front());
3530 _ScriptQueue.pop();
3535 // ***************************************************************************
3536 void CInterfaceManager::resetTextIndex()
3538 uint32 nMasterGroup;
3539 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
3540 for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
3542 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
3544 InvalidateTextVisitor inv( true );
3545 rMG.Group->visitGroupAndChildren( &inv );
3546 for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
3548 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
3549 list<CInterfaceGroup*>::const_iterator itw;
3550 for (itw = rList.begin(); itw != rList.end(); itw++)
3552 CInterfaceGroup *pIG = *itw;
3553 pIG->visitGroupAndChildren( &inv );
3559 // ***************************************************************************
3560 CInterfaceElement *getInterfaceResource(const std::string &key)
3562 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3563 return CWidgetManager::getInstance()->getElementFromId (key);
3566 // ***************************************************************************
3567 std::vector<std::string> CInterfaceManager::getInGameXMLInterfaceFiles()
3569 // Original Files
3570 vector<string> ret;
3571 ret= ClientCfg.XMLInterfaceFiles;
3573 // Resolve any conflict (with CPath scheme, AddOn Should take the precedence)
3574 // But still preserve order given in XMLInterfaceFiles (important for config.xml for instance)
3575 set<string> fileSet;
3576 for(uint i=0;i<ret.size();i++)
3578 fileSet.insert(ret[i]);
3581 // Add R2 Editor .xml. This is removed as it will not be done when initializing CEditor
3582 // if (ClientCfg.R2EDEnabled)
3583 // {
3584 // // Add them to 'ret', only if not already inserted
3585 // // since parser will crash on any duplicates
3586 // for(uint i=0;i<ClientCfg.XMLR2EDInterfaceFiles.size();i++)
3587 // {
3588 // if(fileSet.find(ClientCfg.XMLR2EDInterfaceFiles[i])==fileSet.end())
3589 // {
3590 // fileSet.insert(ClientCfg.XMLR2EDInterfaceFiles[i]);
3591 // ret.push_back(ClientCfg.XMLR2EDInterfaceFiles[i]);
3592 // }
3593 // }
3594 // }
3596 // Get Addons .xml
3597 vector<string> adds;
3598 InterfaceAddOnManager.getFiles("*.xml", adds);
3600 // Add them to 'ret', only if not already inserted
3601 for(uint i=0;i<adds.size();i++)
3603 if(fileSet.find(adds[i])==fileSet.end())
3605 fileSet.insert(adds[i]);
3606 ret.push_back(adds[i]);
3610 return ret;
3613 // ***************************************************************************
3614 void CInterfaceManager::dumpLuaString(const std::string &str)
3616 nlinfo(str.c_str());
3617 displaySystemInfo(LuaHelperStuff::formatLuaErrorSysInfo(str));
3620 // ***************************************************************************
3621 void CInterfaceManager::getLuaValueInfo(std::string &str, sint index)
3623 CLuaState &ls= *( CLuaManager::getInstance().getLuaState() );
3625 sint type= ls.type(index);
3626 if(type==LUA_TNIL)
3628 str= "nil";
3630 else if(type==LUA_TNUMBER)
3632 str= NLMISC::toString(ls.isInteger(index) ? ls.toInteger(index):ls.toNumber(index));
3634 else if(type==LUA_TBOOLEAN)
3636 str= ls.toBoolean(index)?"true":"false";
3638 else if(type==LUA_TSTRING)
3640 ls.toString(index, str);
3641 str= toString("'") + str + toString("'");
3643 else
3645 str= ls.getTypename(type);
3646 str+= ":";
3647 str+= NLMISC::toString("%p", ls.toPointer(index));
3648 // If its a table, append the size.
3649 if(type==LUA_TTABLE)
3651 ls.pushNil(); // first key
3652 uint count= 0;
3653 while (ls.next(index-1))
3655 ls.pop(); // remove 'value'; keeps `key' for next iteration
3656 count++;
3658 str+= NLMISC::toString(" (size=%d)", count);
3660 // If its a Userdata, try to display UI info
3661 else if(type==LUA_TUSERDATA)
3663 if(CLuaIHM::isUIOnStack(ls, index))
3665 CInterfaceElement *ui= CLuaIHM::getUIOnStack(ls, index);
3666 str+= NLMISC::toString(" (ui=%p)", ui);
3672 // ***************************************************************************
3673 void CInterfaceManager::dumpLuaKeyValueInfo(uint recursTableLevel, uint tabLevel)
3675 CLuaState &ls= *( CLuaManager::getInstance().getLuaState() );
3676 CLuaStackChecker lsc(&ls);
3678 // Dump Key Str
3679 string key;
3680 getLuaValueInfo(key, -2);
3681 // Dump Value Str
3682 string value;
3683 getLuaValueInfo(value, -1);
3685 // display.
3686 string res;
3687 // append tab for table hierarchy
3688 for(uint i=0;i<tabLevel;i++)
3689 res+= " ";
3690 // display key and value
3691 res+= key + " == " + value;
3692 dumpLuaString(res);
3694 // If the value is a table, and can recurs dumping
3695 if(recursTableLevel>0 && ls.type(-1)==LUA_TTABLE)
3697 ls.pushNil(); // first key
3698 while (ls.next(-2))
3700 // display the key value pair of this table (recurs)
3701 dumpLuaKeyValueInfo(recursTableLevel-1, tabLevel+1);
3702 ls.pop(); // remove 'value'; keeps `key' for next iteration
3708 // ***************************************************************************
3709 void CInterfaceManager::dumpLuaState(uint detail)
3711 CLuaState *_LuaState = CLuaManager::getInstance().getLuaState();
3713 // clamp detailed info to 2 (display at max content of eaxh Env of each group)
3714 clamp(detail, 0U, 2U);
3716 // Dump the Memory State
3717 dumpLuaString(NLMISC::toString("Memory Used : %d Kb", _LuaState->getGCCount()));
3718 dumpLuaString(NLMISC::toString("GC Threshold: %d Kb", _LuaState->getGCThreshold()));
3720 // If want to display some detailed info
3721 if(detail>0)
3723 CLuaState &ls= *_LuaState;
3724 CLuaStackChecker lsc(&ls);
3726 // *** Dump all Lua Env Tables
3727 ls.push(IHM_LUA_ENVTABLE);
3728 ls.getTable(LUA_REGISTRYINDEX); // __ui_envtable
3729 ls.pushNil(); // first key
3730 uint count= 0;
3731 while (ls.next(-2))
3733 // `key' is at index -2 and `value' at index -1
3734 dumpLuaKeyValueInfo(detail-1, 1);
3735 ls.pop(); // remove 'value'; keeps `key' for next iteration
3736 count++;
3738 // pop table
3739 ls.pop();
3741 dumpLuaString(NLMISC::toString("Number of EnvTable for ui groups: %d", count));
3745 // ------------------------------------------------------------------------------------------------
3746 void CInterfaceManager::createLocalBranch(const std::string &fileName, NLMISC::IProgressCallback &progressCallBack)
3750 CIFile file;
3751 if (file.open (fileName))
3753 // Init an xml stream
3754 CIXml read;
3755 read.init (file);
3757 //Parse the parser output!!!
3758 CCDBNodeBranch *localNode = new CCDBNodeBranch("LOCAL");
3759 localNode->init( read.getRootNode (), progressCallBack );
3760 NLGUI::CDBManager::getInstance()->getDB()->attachChild(localNode,"LOCAL");
3762 // Create the observers for auto-copy SERVER->LOCAL of inventory
3763 ServerToLocalAutoCopyInventory.init("INVENTORY");
3765 // Create the observers for auto-copy SERVER->LOCAL of exchange
3766 ServerToLocalAutoCopyExchange.init("EXCHANGE");
3768 // Create the observers for auto-copy SERVER->LOCAL of dm (animator) gift
3769 ServerToLocalAutoCopyDMGift.init("DM_GIFT");
3771 // Create the observers for auto-copy SERVER->LOCAL of context menu
3772 ServerToLocalAutoCopyContextMenu.init("TARGET:CONTEXT_MENU");
3774 // Create the observers for auto-copy SERVER->LOCAL of Skill Points
3775 ServerToLocalAutoCopySkillPoints.init("USER");
3778 catch (const Exception &e)
3780 // Output error
3781 nlwarning ("CFormLoader: Error while loading the form %s: %s", fileName.c_str(), e.what());
3785 // ------------------------------------------------------------------------------------------------
3786 #ifdef NL_OS_WINDOWS
3787 # pragma warning (push)
3788 # pragma warning (disable : 4355) // 'this' used in base member initializer list
3789 #endif
3790 CInterfaceManager::CServerToLocalAutoCopy::CServerToLocalAutoCopy() : _LocalObserver(*this), _ServerObserver(*this)
3792 _ServerCounter= NULL;
3793 _UpdateList.reserve(300);
3794 _LocalUpdating= false;
3796 #ifdef NL_OS_WINDOWS
3797 # pragma warning (pop)
3798 #endif
3800 // ------------------------------------------------------------------------------------------------
3801 // unhook from everything we are tangled up in
3802 void CInterfaceManager::CServerToLocalAutoCopy::release()
3804 _Nodes.clear();
3805 _ServerCounter = NULL;
3806 _ServerNodeMap.clear();
3807 _LocalNodeMap.clear();
3808 _UpdateList.clear();
3811 // ------------------------------------------------------------------------------------------------
3812 void CInterfaceManager::CServerToLocalAutoCopy::buildRecursLocalLeaves(CCDBNodeBranch *branch, std::vector<CCDBNodeLeaf*> &leaves)
3814 for(uint i=0;i<branch->getNbNodes();i++)
3816 ICDBNode *node= branch->getNode(i);
3817 if(node)
3819 CCDBNodeLeaf *leaf= dynamic_cast<CCDBNodeLeaf*>(node);
3820 if(leaf)
3822 // just append to list
3823 leaves.push_back(leaf);
3825 else
3827 // recurs if a branch (should be...)
3828 CCDBNodeBranch *sonBranch= dynamic_cast<CCDBNodeBranch*>(node);
3829 if(sonBranch)
3830 buildRecursLocalLeaves(sonBranch, leaves);
3836 // ------------------------------------------------------------------------------------------------
3837 void CInterfaceManager::CServerToLocalAutoCopy::init(const std::string &dbPath)
3839 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3841 // Get the synchronisation Counter in Server DB
3842 _ServerCounter= NLGUI::CDBManager::getInstance()->getDbProp(string("SERVER:") + dbPath + ":COUNTER", false);
3844 // if found
3845 if(_ServerCounter)
3847 ICDBNode::CTextId textId;
3849 // **** Add Observers on all nodes
3850 // add the observers when server node change
3851 textId = ICDBNode::CTextId( string("SERVER:") + dbPath );
3852 NLGUI::CDBManager::getInstance()->getDB()->addObserver(&_ServerObserver, textId );
3854 // add the observers when local node change
3855 textId = ICDBNode::CTextId( string("LOCAL:") + dbPath );
3856 NLGUI::CDBManager::getInstance()->getDB()->addObserver(&_LocalObserver, textId );
3858 // **** Init the Nodes shortcut
3859 // Parse all Local Nodes
3860 CCDBNodeBranch *localBranch= NLGUI::CDBManager::getInstance()->getDbBranch(string("LOCAL:") + dbPath);
3861 if(localBranch)
3863 uint i;
3864 std::vector<CCDBNodeLeaf*> leaves;
3865 buildRecursLocalLeaves(localBranch, leaves);
3867 // --- build _Nodes
3868 _Nodes.reserve(leaves.size());
3869 for(i=0;i<leaves.size();i++)
3871 CCDBNodeLeaf *localLeaf= leaves[i];
3873 // get the SERVER associated node name
3874 string serverLeafStr= *localLeaf->getName();
3875 CCDBNodeBranch* parent= localLeaf->getParent();
3876 while( *parent->getName()!="LOCAL" )
3878 serverLeafStr= *parent->getName()+":"+serverLeafStr;
3879 parent= parent->getParent();
3881 serverLeafStr= "SERVER:" + serverLeafStr;
3883 // try then to get this server node
3884 CCDBNodeLeaf *serverLeaf= NLGUI::CDBManager::getInstance()->getDbProp(serverLeafStr, false);
3885 if(serverLeaf)
3887 // Both server and local leaves exist, ok, append to _Nodes
3888 CNode node;
3889 node.ServerNode= serverLeaf;
3890 node.LocalNode= localLeaf;
3891 _Nodes.push_back(node);
3895 // --- Init the maps
3896 _ServerNodeMap.reserve(leaves.size());
3897 _LocalNodeMap.reserve(leaves.size());
3898 // For all valid _Nodes, insert in "map"
3899 for(i=0;i<_Nodes.size();i++)
3901 CNodeLocalComp lc;
3902 CNodeServerComp sc;
3903 lc.Node= &_Nodes[i];
3904 sc.Node= &_Nodes[i];
3905 _LocalNodeMap.push_back(lc);
3906 _ServerNodeMap.push_back(sc);
3908 // then sort
3909 sort(_LocalNodeMap.begin(), _LocalNodeMap.end());
3910 sort(_ServerNodeMap.begin(), _ServerNodeMap.end());
3916 // ------------------------------------------------------------------------------------------------
3917 void CInterfaceManager::CServerToLocalAutoCopy::onServerChange(ICDBNode *serverNode)
3919 if(_Nodes.empty())
3920 return;
3921 CCDBNodeLeaf *serverLeaf = safe_cast<CCDBNodeLeaf *>(serverNode);
3922 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3924 // Add the leaf to the update list. only if not the counter
3925 if(serverLeaf != _ServerCounter)
3927 // build the map key
3928 CNode nodeComp;
3929 CNodeServerComp sc;
3930 nodeComp.ServerNode= serverLeaf;
3931 sc.Node= &nodeComp;
3932 // try to find the node associated to this server leaf
3933 uint index= searchLowerBound(_ServerNodeMap, sc);
3934 // if found
3935 if( index>0 || _ServerNodeMap[0].Node->ServerNode==serverLeaf )
3937 CNode *node= _ServerNodeMap[index].Node;
3938 // if this node is not already inserted
3939 if(!node->InsertedInUpdateList)
3941 // insert
3942 node->InsertedInUpdateList= true;
3943 _UpdateList.push_back(node);
3948 // if the client and server are synchonized.
3949 if( ClientCfg.Local || pIM->localActionCounterSynchronizedWith(_ServerCounter) )
3951 // update all leaves
3952 for(uint i=0;i<_UpdateList.size();i++)
3954 CNode *node= _UpdateList[i];
3956 _LocalUpdating= true;
3957 node->LocalNode->setValue64(node->ServerNode->getValue64());
3958 _LocalUpdating= false;
3960 // reset inserted flag
3961 node->InsertedInUpdateList= false;
3964 // clear update list
3965 _UpdateList.clear();
3969 // ------------------------------------------------------------------------------------------------
3970 void CInterfaceManager::CServerToLocalAutoCopy::onLocalChange(ICDBNode *localNode)
3972 if(_Nodes.empty())
3973 return;
3975 // if the local changes because of localLeaf->setValue64() in onServerChange(), no-op !!!
3976 if(_LocalUpdating)
3977 return;
3979 CCDBNodeLeaf *localLeaf = safe_cast<CCDBNodeLeaf *>(localNode);
3981 // Add the leaf to the update list
3982 // build the map key
3983 CNode nodeComp;
3984 CNodeLocalComp lc;
3985 nodeComp.LocalNode= localLeaf;
3986 lc.Node= &nodeComp;
3987 // try to find the node associated to this local leaf
3988 uint index= searchLowerBound(_LocalNodeMap, lc);
3989 // if found
3990 if( index>0 || _LocalNodeMap[0].Node->LocalNode==localLeaf )
3992 CNode *node= _LocalNodeMap[index].Node;
3993 // if this node is not already inserted
3994 if(!node->InsertedInUpdateList)
3996 // insert
3997 node->InsertedInUpdateList= true;
3998 _UpdateList.push_back(node);
4003 // ------------------------------------------------------------------------------------------------
4004 bool CInterfaceManager::use12hClock()
4006 CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_CLOCK_12H", false);
4008 return (node && node->getValueBool());
4011 // ------------------------------------------------------------------------------------------------
4012 char* CInterfaceManager::getTimestampHuman(const char* format /* "[%H:%M:%S] " */)
4014 static char cstime[25];
4015 time_t date;
4016 time (&date);
4017 struct tm *tms = localtime(&date);
4018 if (tms)
4020 strftime(cstime, 25, format, tms);
4022 else
4024 strcpy(cstime, "");
4027 return cstime;
4032 * Parse tokens in a chatmessage or emote
4034 * Valid subjects:
4035 * $me$
4036 * $t$
4037 * $tt$
4038 * $tm1$..$tm8$
4040 * Valid parameters:
4041 * $<subject>.name$
4042 * $<subject>.title$
4043 * $<subject>.race$
4044 * $<subject>.guild$
4045 * $<subject>.gs(m/f/n)$
4047 * Default parameter if parameter result is empty:
4048 * $<subject>.<parameter>/<default>$
4050 * All \d's in default parameter remove a following character.
4052 bool CInterfaceManager::parseTokens(string& ucstr)
4054 string str = ucstr;
4055 string start_token("$");
4056 string end_token("$");
4057 size_t start_pos = 0;
4058 size_t end_pos = 1;
4060 sint endless_loop_protector = 0;
4061 while ((start_pos < str.length() - 1) &&
4062 ((start_pos = str.find(start_token, start_pos)) != string::npos))
4064 endless_loop_protector++;
4065 if (endless_loop_protector > 100)
4067 break;
4070 // Get the whole token substring first
4071 end_pos = str.find(end_token, start_pos + 1);
4073 if ((start_pos == string::npos) ||
4074 (end_pos == string::npos) ||
4075 (end_pos <= start_pos + 1))
4077 // Wrong formatting; give up on this one.
4078 start_pos = max(start_pos, end_pos);
4079 continue;
4082 // Get everything between the two "$"
4083 size_t token_start_pos = start_pos + start_token.length();
4084 size_t token_end_pos = end_pos - end_token.length();
4085 if (token_start_pos > token_end_pos)
4087 // Wrong formatting; give up on this one.
4088 start_pos = end_pos;
4089 continue;
4092 string token_whole = str.substr(start_pos, end_pos - start_pos + 1);
4093 string token_string = token_whole.substr(1, token_whole.length() - 2);
4094 string token_replacement = token_whole;
4095 string token_default = token_whole;
4097 string token_subject;
4098 string token_param;
4100 // Does the token have a parameter?
4101 // If not it is 'name' by default
4102 vector<string> token_vector;
4103 vector<string> param_vector;
4104 splitString(token_string, ".", token_vector);
4105 if (token_vector.empty())
4107 // Wrong formatting; give up on this one.
4108 start_pos = end_pos;
4109 continue;
4111 token_subject = token_vector[0];
4112 if (token_vector.size() == 1)
4114 splitString(token_subject, "/", param_vector);
4115 token_subject = !param_vector.empty() ? param_vector[0] : string();
4116 token_param = string("name");
4118 else if (token_vector.size() > 1)
4120 token_param = token_vector[1];
4121 if (token_param.substr(0, 3) != "gs(")
4123 splitString(token_vector[1], "/", param_vector);
4124 token_param = !param_vector.empty() ? param_vector[0] : string();
4128 // Get any default value, if not gs
4129 sint extra_replacement = 0;
4130 if (token_param.substr(0, 3) != "gs(")
4132 if (param_vector.size() == 2)
4134 // Set default value
4135 token_replacement = param_vector[1];
4136 // Delete following chars for every '\d' in default
4137 string::size_type token_replacement_pos;
4138 while ((token_replacement_pos = token_replacement.find(string("\\d"))) != string::npos)
4140 token_replacement.replace(token_replacement_pos, 2, string());
4141 extra_replacement++;
4143 token_default = token_replacement;
4147 CEntityCL *pTokenSubjectEntity = NULL;
4149 if (token_subject == "me")
4151 pTokenSubjectEntity = static_cast<CEntityCL*>(UserEntity);
4153 else if (token_subject == "t")
4155 // Target
4156 uint targetSlot = UserEntity->targetSlot();
4157 pTokenSubjectEntity = EntitiesMngr.entity(targetSlot);
4159 else if (token_subject == "tt")
4161 // Target's target
4162 uint targetSlot = UserEntity->targetSlot();
4163 CEntityCL *target = EntitiesMngr.entity(targetSlot);
4165 if (target)
4167 // Check the new slot.
4168 CLFECOMMON::TCLEntityId newSlot = target->targetSlot();
4169 CEntityCL* pE = EntitiesMngr.entity(newSlot);
4170 if (pE)
4172 pTokenSubjectEntity = pE;
4176 else if ((token_subject.length() == 3) &&
4177 (token_subject.substr(0, 2) == "tm"))
4179 // Teammate
4180 uint indexInTeam = 0;
4181 fromString(token_subject.substr(2, 1), indexInTeam);
4183 // Make 0-based
4184 --indexInTeam;
4185 if (indexInTeam < PeopleInterraction.TeamList.getNumPeople() )
4187 // Index is the database index (serverIndex() not used for team list)
4188 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp( NLMISC::toString(TEAM_DB_PATH ":%hu:NAME", indexInTeam ), false);
4189 if (pNL && pNL->getValueBool() )
4191 // There is a character corresponding to this index
4192 pNL = NLGUI::CDBManager::getInstance()->getDbProp( NLMISC::toString( TEAM_DB_PATH ":%hu:UID", indexInTeam ), false );
4193 if (pNL)
4195 CLFECOMMON::TClientDataSetIndex compressedIndex = pNL->getValue32();
4197 // Search entity in vision
4198 CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex( compressedIndex );
4199 if (entity)
4201 pTokenSubjectEntity = entity;
4207 else
4209 // Unknown token subject, skip it
4210 start_pos = end_pos;
4211 continue;
4214 if (pTokenSubjectEntity != NULL)
4216 // Parse the parameter
4217 if (token_param == "name")
4219 string name = pTokenSubjectEntity->getDisplayName();
4220 // special case where there is only a title, very rare case for some NPC
4221 if (name.empty())
4223 name = pTokenSubjectEntity->getTitle();
4225 token_replacement = name.empty() ? token_replacement : name;
4227 else if (token_param == "title")
4229 string title = pTokenSubjectEntity->getTitle();
4230 token_replacement = title.empty() ? token_replacement : title;
4232 else if (token_param == "race")
4234 CCharacterCL *pC = dynamic_cast<CCharacterCL*>(pTokenSubjectEntity);
4235 if (pC)
4237 EGSPD::CPeople::TPeople race = pC->people();
4238 if (race >= EGSPD::CPeople::Playable && race <= EGSPD::CPeople::EndPlayable)
4240 string srace = NLMISC::CI18N::get("io" + EGSPD::CPeople::toString(race));
4241 token_replacement = srace.empty() ? token_replacement : srace;
4245 else if (token_param == "guild")
4247 STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
4248 string ucGuildName;
4249 if (pSMC->getString(pTokenSubjectEntity->getGuildNameID(), ucGuildName))
4251 token_replacement = ucGuildName.empty() ? token_replacement : ucGuildName;
4254 else if (token_param.substr(0, 3) == "gs(" &&
4255 token_param.substr(token_param.length() - 1 , 1) == ")")
4257 // Gender string
4258 vector<string> strList;
4259 string gender_string = token_param.substr(3, token_param.length() - 4);
4260 splitString(gender_string, "/", strList);
4262 if (strList.size() <= 1)
4264 start_pos = end_pos;
4265 continue;
4268 // We only care about the gender if the subject is humanoid.
4269 GSGENDER::EGender gender = GSGENDER::neutral;
4270 if (pTokenSubjectEntity->isUser() || pTokenSubjectEntity->isPlayer() || pTokenSubjectEntity->isNPC())
4272 CCharacterCL *pC = dynamic_cast<CCharacterCL*>(pTokenSubjectEntity);
4273 if (pC)
4275 gender = pC->getGender();
4279 // The neuter part is optional. Fallback to male if something is wrong.
4280 GSGENDER::EGender g = ((uint)gender >= strList.size()) ? GSGENDER::male : gender;
4281 token_replacement = strList[g];
4285 if (token_whole == token_replacement)
4287 // Nothing to replace; show message and exit
4288 CInterfaceManager *im = CInterfaceManager::getInstance();
4289 string message = CI18N::get("uiUntranslatedToken");
4290 message.replace(message.find("%s"), 2, token_whole);
4291 im->displaySystemInfo(message);
4292 return false;
4295 // Replace token
4296 size_t token_whole_pos = str.find(token_whole);
4298 // Only do extra replacement spaces if using default
4299 extra_replacement = (token_replacement == token_default) ? extra_replacement : 0;
4300 if (str.find(token_whole, start_pos) != string::npos)
4302 str = str.replace(token_whole_pos, token_whole.length() + extra_replacement, token_replacement);
4303 start_pos = token_whole_pos + token_replacement.length();
4307 ucstr = str;
4308 return true;;
4311 std::string CInterfaceManager::getNextBackupName(std::string filename)
4313 std::string ts = getTimestampHuman("%Y-%m-%d");
4315 if (!ts.empty())
4317 std::string::size_type pos = filename.find_last_of('.');
4318 if (pos == std::string::npos)
4319 filename = filename + "_" + ts + "_";
4320 else
4321 filename = filename.substr(0, pos) + "_" + ts + "_" + filename.substr(pos);
4324 // filename_YYYY-MM-DD_000.ext
4325 return CFile::findNewFile(filename);
4328 void CInterfaceManager::createFileBackup(const std::string &message, const std::string &filename, bool useCopy)
4330 std::string backupName = getNextBackupName(filename);
4331 nlwarning("%s: '%s'.", message.c_str(), filename.c_str());
4332 if (!backupName.empty())
4334 if (useCopy)
4336 nlwarning("Backup copy saved as '%s'", backupName.c_str());
4337 CFile::copyFile(backupName, filename);
4339 else
4341 nlwarning("File renamed to '%s'", backupName.c_str());
4342 CFile::moveFile(backupName, filename);