Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / client / src / interface_v3 / interface_manager.cpp
blob04b94faaf5e5811d8384a2fc42048e94b34f5a10
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 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 uint32 width, height;
1903 // get non-scaled width/height
1904 Driver->getWindowSize(width, height);
1905 // convert to scaled width/height for ui
1906 sint32 scaledW = width / ClientCfg.InterfaceScale;
1907 sint32 scaledH = height / ClientCfg.InterfaceScale;
1908 CWidgetManager::getInstance()->moveAllWindowsToNewScreenSize(scaledW, scaledH, false);
1909 updateDesktops(scaledW, scaledH);
1912 // *** apply the current mode
1913 _Modes[_CurrentMode].toCurrentDesktop();
1915 // *** Apply the NPC icon display mode
1916 CNPCIconCache::getInstance().init(!ClientCfg.R2EDEnabled && NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:INSCENE:FRIEND:MISSION_ICON")->getValueBool());
1918 return true;
1922 // ------------------------------------------------------------------------------------------------
1923 void CInterfaceManager::CDBLandmarkObs::update(ICDBNode *node)
1925 ContinentMngr.updateUserLandMarks();
1929 // visitor to send onQuit msg on all element
1930 class CQuitVisitor : public CInterfaceElementVisitor
1932 public:
1933 bool IsR2ED;
1934 bool BadWindowFound; //
1935 uint Desktop;
1936 virtual void visit(CInterfaceElement *elem) { elem->onQuit(); }
1937 virtual void visitGroup(CInterfaceGroup *group)
1939 if (!IsR2ED) return;
1940 if (Desktop != 0) return;
1941 if (group->getShortId() == "gestionsets")
1943 if (group->getActive())
1945 BadWindowFound = true;
1951 bool CInterfaceManager::saveLandmarks(bool verbose) const
1953 bool ret = true;
1955 if (!ClientCfg.R2EDEnabled)
1957 uint8 currMode = getMode();
1959 string filename = getSaveFileName("landmarks", "xml");
1960 if (verbose) CInterfaceManager::getInstance()->displaySystemInfo("Saving " + filename);
1961 ret = saveLandmarks(filename);
1964 return ret;
1967 bool CInterfaceManager::loadLandmarks()
1969 // Does the keys file exist ?
1970 string filename = getSaveFileName("landmarks", "xml");
1972 CIFile f;
1973 string sFileName;
1974 sFileName = NLMISC::CPath::lookup (filename, false);
1975 if (sFileName.empty() || !f.open(sFileName))
1976 return false;
1978 bool ret = false;
1979 vector<string> xmlFilesToParse;
1980 xmlFilesToParse.push_back (filename);
1982 //ContinentMngr.serialUserLandMarks(node);
1983 if (!parseInterface (xmlFilesToParse, true))
1985 f.close();
1987 createFileBackup("Error while loading landmarks", filename);
1989 ret = false;
1992 return ret;
1995 bool CInterfaceManager::saveLandmarks(const std::string &filename) const
1997 nlinfo( "Saving landmarks : %s", filename.c_str() );
1999 bool ret = false;
2002 COFile f;
2004 // using temporary file, so no f.close() unless its a success
2005 if (f.open(filename, false, false, true))
2007 COXml xmlStream;
2008 xmlStream.init (&f);
2010 xmlDocPtr doc = xmlStream.getDocument ();
2011 xmlNodePtr node = xmlNewDocNode(doc, NULL, (const xmlChar*)"interface_config", NULL);
2012 xmlDocSetRootElement (doc, node);
2014 ContinentMngr.writeTo(node);
2016 // Flush the stream
2017 xmlStream.flush();
2019 // Close the stream
2020 f.close ();
2022 ret = true;
2025 catch (const Exception &e)
2027 nlwarning ("Error while writing the file %s : %s.", filename.c_str(), e.what ());
2030 return ret;
2033 // ------------------------------------------------------------------------------------------------
2035 bool CInterfaceManager::saveConfig (bool verbose)
2037 bool ret = true;
2039 if (!ClientCfg.R2EDEnabled)
2041 uint8 currMode = getMode();
2043 string filename = getSaveFileName("interface", "icfg");
2045 if (verbose) CInterfaceManager::getInstance()->displaySystemInfo("Saving " + filename);
2046 ret = saveConfig(filename);
2048 if (currMode != getMode())
2049 setMode(currMode);
2052 return ret;
2055 // ------------------------------------------------------------------------------------------------
2056 bool CInterfaceManager::saveConfig (const string &filename)
2059 CQuitVisitor quitVisitor;
2061 quitVisitor.IsR2ED = false;
2062 if (nlstricmp(NLMISC::CFile::getFilename(filename).substr(0, 5), "r2ed_") == 0)
2064 quitVisitor.IsR2ED = true;
2066 quitVisitor.BadWindowFound = false;
2068 nlinfo( "Saving interface config : %s", filename.c_str() );
2070 COFile f;
2072 // using temporary file, so no f.close() unless its a success
2073 if (!f.open(filename, false, false, true)) return false;
2075 CInterfaceConfig ic;
2079 // cleanup all desktops
2080 for(uint k = 0; k < _Modes.size(); ++k)
2082 quitVisitor.Desktop = k;
2083 setMode(k);
2084 visit(&quitVisitor);
2085 CWidgetManager::getInstance()->checkCoords();
2087 setMode(0);
2088 setMode(_CurrentMode);
2090 if (quitVisitor.BadWindowFound)
2092 #ifdef NL_DEBUG
2093 nlassert(0);
2094 #endif
2095 // tmp patch : when trying to overwrite the r2ed_ config, if a bad window is found, just do nothing ...
2096 return true;
2100 _Modes[_CurrentMode].clear();
2101 if (_Modes[_CurrentMode].isReading()) _Modes[_CurrentMode].invert();
2102 clearAllEditBox();
2103 restoreAllContainersBackupPosition();
2104 ic.interfaceManagerToStream(_Modes[_CurrentMode]);
2107 uint32 i;
2109 i = _Modes.size();
2112 f.serialVersion(ICFG_STREAM_VERSION);
2114 // serial user chats info (serial it before position of windows so that they can be updated properly)
2115 f.serialCheck(NELID("_ICU"));
2116 if (!PeopleInterraction.saveUserChatsInfos(f))
2118 nlwarning("Config saving failed");
2119 // couldn't save result so do not continue
2120 return false;
2123 // header
2124 f.serialCheck(NELID("GFCI"));
2125 f.serial(i);
2126 f.serial(_CurrentMode);
2127 f.serial(_LastInGameScreenW);
2128 f.serial(_LastInGameScreenH);
2130 // Save All Window configuration of all Modes
2131 for (i = 0; i < _Modes.size(); ++i)
2133 // must create a tmp mem stream because desktop image expect its datas to occupy the whole stream
2134 // This is because of old system that manipulated desktop image direclty as a mem stream
2135 CMemStream ms;
2136 if (ms.isReading()) ms.invert();
2137 _Modes[i].serial(ms);
2138 uint32 length = ms.length();
2139 f.serial(length);
2140 if (length > 0)
2142 f.serialBuffer(const_cast<uint8 *>(ms.buffer()), length);
2146 // write UI_DB_SAVE_VERSION
2147 uint32 uiDbSaveVersion;
2148 fromString( CWidgetManager::getInstance()->getParser()->getDefine("UI_DB_SAVE_VERSION"), uiDbSaveVersion);
2149 f.serial(uiDbSaveVersion);
2151 // write database
2152 ic.dataBaseToStream(f);
2154 // Deprecated. for Compatibility purpose: Save TaskBar.
2155 CTaskBarManager *pTBM= CTaskBarManager::getInstance();
2156 pTBM->serial(f);
2158 //ContinentMngr.serialUserLandMarks(f);
2159 // empty landmarks block for compatibility
2161 f.serialVersion(1);
2162 uint32 numCont = 0;
2163 f.serial(numCont);
2166 // Info Windows position.
2167 CInterfaceHelp::serialInfoWindows(f);
2169 // Macro On Memory Position
2170 CSPhraseManager *pPM = CSPhraseManager::getInstance();
2171 pPM->serialMacroMemory(f);
2173 CGroupInSceneBubbleManager::serialInSceneBubbleInfo(f);
2175 if ( ! PeopleInterraction.saveUserDynChatsInfos(f))
2177 nlwarning("Bad user dyn chat saving");
2178 return false;
2181 f.close();
2183 catch(const NLMISC::EStream &)
2185 nlwarning("Config saving failed.");
2186 return false;
2189 ContinentMngr.serialFOWMaps();
2191 return true;
2194 // ------------------------------------------------------------------------------------------------
2195 void CInterfaceManager::drawViews(NL3D::UCamera camera)
2197 IngameDbMngr.flushObserverCalls();
2198 NLGUI::CDBManager::getInstance()->flushObserverCalls();
2200 // Update Player characteristics (for Item carac requirement Redifying)
2201 nlctassert(CHARACTERISTICS::NUM_CHARACTERISTICS==8);
2202 for (uint i=0; i<CHARACTERISTICS::NUM_CHARACTERISTICS; ++i)
2204 if (!_CurrentPlayerCharacLeaf[i])
2205 _CurrentPlayerCharacLeaf[i] = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:CHARACTER_INFO:CHARACTERISTICS%d:VALUE", i), false);
2207 NLMISC::CCDBNodeLeaf *node = NULL;
2209 if (_CurrentPlayerCharacLeaf[i])
2210 node = &*_CurrentPlayerCharacLeaf[i];
2212 _CurrentPlayerCharac[i] = node ? node->getValue32() : 0;
2215 // scale must be updated right before widget manager checks it
2216 if (_InterfaceScaleChanged)
2218 CViewRenderer::getInstance()->setInterfaceScale(_InterfaceScale);
2219 _InterfaceScaleChanged = false;
2222 CWidgetManager::getInstance()->drawViews( camera );
2224 // flush obs
2225 IngameDbMngr.flushObserverCalls();
2229 // ------------------------------------------------------------------------------------------------
2230 bool CInterfaceManager::handleEvent (const NLGUI::CEventDescriptor& event)
2232 bool handled = false;
2234 handled = CWidgetManager::getInstance()->handleEvent( event );
2236 if( event.getType() == NLGUI::CEventDescriptor::mouse )
2238 NLGUI::CEventDescriptorMouse &eventDesc = (NLGUI::CEventDescriptorMouse&)event;
2240 if( ( eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightup ) && handled )
2242 // prevent 'click in scene' as mouse was previously captured
2243 // (more a patch that anything, but 'UserControls' test for 'mouse up'
2244 // directly later in the main loop (not through message queue), so it has no way of knowing that the event was handled...
2245 if( CWidgetManager::getInstance()->getCapturePointerRight() == NULL )
2246 EventsListener.addUIHandledButtonMask(rightButton);
2247 }else
2248 if( ( eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup ) && handled )
2250 // prevent 'click in scene' as mouse was previously captured
2251 // (more a patch that anything, but 'UserControls' test for 'mouse up'
2252 // directly later in the main loop (not through message queue), so it has no way of knowing that the event was handled...
2253 if( CWidgetManager::getInstance()->getCapturePointerLeft() == NULL )
2254 EventsListener.addUIHandledButtonMask(leftButton);
2259 IngameDbMngr.flushObserverCalls();
2260 // event handled?
2261 return handled;
2264 void CInterfaceManager::updateDesktops( uint32 newScreenW, uint32 newScreenH )
2266 // *** Do it for All Backuped Desktops
2267 for(uint md=0; md<_Modes.size(); md++)
2269 CInterfaceConfig::CDesktopImage &mode= _Modes[md];
2270 // For all containers of this mode
2271 for(uint gc=0;gc<mode.GCImages.size();gc++)
2273 CInterfaceConfig::SCont &gcCont= mode.GCImages[gc];
2274 // Compute the new coordinate, directly in the X/Y fields of the structure
2275 CWidgetManager::getInstance()->getNewWindowCoordToNewScreenSize(gcCont.X, gcCont.Y, gcCont.W, gcCont.H ,newScreenW, newScreenH);
2279 _LastInGameScreenW = newScreenW;
2280 _LastInGameScreenH = newScreenH;
2283 class InvalidateTextVisitor : public CInterfaceElementVisitor
2285 public:
2286 InvalidateTextVisitor( bool reset )
2288 this->reset = reset;
2291 void visitGroup( CInterfaceGroup *group )
2293 const std::vector< CViewBase* > &vs = group->getViews();
2294 for( std::vector< CViewBase* >::const_iterator itr = vs.begin(); itr != vs.end(); ++itr )
2296 CViewText *vt = dynamic_cast< CViewText* >( *itr );
2297 if( vt != NULL )
2299 if( reset )
2300 vt->resetTextIndex();
2301 vt->updateTextContext();
2306 private:
2307 bool reset;
2311 // ------------------------------------------------------------------------------------------------
2312 void CInterfaceManager::addServerString (const std::string &sTarget, uint32 id, IStringProcess *cb)
2314 if (id == 0)
2316 CInterfaceExprValue val;
2317 val.setString (std::string());
2318 CInterfaceLink::setTargetProperty (sTarget, val);
2319 return;
2321 SIDStringWaiter *pISW = new SIDStringWaiter;
2322 pISW->Id = id;
2323 pISW->IdOrString = false;
2324 pISW->Target = sTarget;
2325 pISW->Cb = cb;
2326 _IDStringWaiters.push_back(pISW);
2329 // ------------------------------------------------------------------------------------------------
2330 void CInterfaceManager::addServerID (const std::string &sTarget, uint32 id, IStringProcess *cb)
2332 if (id == 0)
2334 CInterfaceExprValue val;
2335 val.setString (std::string());
2336 CInterfaceLink::setTargetProperty (sTarget, val);
2337 return;
2339 SIDStringWaiter *pISW = new SIDStringWaiter;
2340 pISW->Id = id;
2341 pISW->IdOrString = true;
2342 pISW->Target = sTarget;
2343 pISW->Cb = cb;
2344 _IDStringWaiters.push_back(pISW);
2347 // ------------------------------------------------------------------------------------------------
2348 void CInterfaceManager::processServerIDString()
2350 STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
2352 for (uint32 i = 0; i < _IDStringWaiters.size(); ++i)
2354 bool bAffect = false;
2355 string ucstrToAffect;
2356 SIDStringWaiter *pISW = _IDStringWaiters[i];
2357 if (pISW->IdOrString == true) // ID !
2359 if (pSMC->getString (pISW->Id, ucstrToAffect))
2360 bAffect = true;
2362 else // String !
2364 if (pSMC->getDynString (pISW->Id, ucstrToAffect))
2365 bAffect = true;
2368 if (bAffect)
2370 CInterfaceExprValue val;
2371 bool bValid = true;
2373 if (pISW->Cb != NULL)
2375 bValid = pISW->Cb->cbIDStringReceived(ucstrToAffect);
2376 delete pISW->Cb;
2379 if (bValid)
2381 ucstrToAffect = STRING_MANAGER::CStringManagerClient::getLocalizedName(ucstrToAffect);
2382 val.setString (ucstrToAffect);
2383 CInterfaceLink::setTargetProperty (pISW->Target, val);
2386 // Remove entry
2387 _IDStringWaiters.erase (_IDStringWaiters.begin()+i);
2388 i--;
2389 delete pISW;
2394 // ------------------------------------------------------------------------------------------------
2395 void CInterfaceManager::messageBoxInternal(const string &msgBoxGroup, const string &text, const string &masterGroup, TCaseMode caseMode)
2397 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":" + msgBoxGroup));
2398 CViewText *viewText= dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":" + msgBoxGroup + ":text"));
2400 if (group && viewText)
2402 viewText->setCaseMode(caseMode);
2403 viewText->setText(text);
2404 CWidgetManager::getInstance()->enableModalWindow(NULL, group);
2405 // don't understand why but need to update coords here
2406 group->updateCoords();
2407 group->updateCoords();
2411 // ------------------------------------------------------------------------------------------------
2412 void CInterfaceManager::messageBox(const string &text, const string &masterGroup, TCaseMode caseMode)
2414 messageBoxInternal("message_box", text, masterGroup, caseMode);
2418 // ------------------------------------------------------------------------------------------------
2419 void CInterfaceManager::messageBoxWithHelp(const std::string &text, const std::string &masterGroup,
2420 const std::string &ahOnOk, const std::string &paramsOnOk,
2421 TCaseMode caseMode)
2423 // replace the procedure "proc_valid_message_box_ok" action
2424 CWidgetManager::getInstance()->setProcedureAction("proc_message_box_with_help_ok", 1, ahOnOk, paramsOnOk);
2425 const char *mbName = "message_box_with_help";
2426 // if no action handler is wanted, then assume that
2427 // clicking 'ok' do not have any consequence, so allow exiting the message box by clicking
2428 // outside of it (this behavior is wanted on the login page, to allow to reclick on 'login' without
2429 // having to click 'ok' in the message box each time)
2430 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":" + mbName));
2431 CGroupModal *gm = dynamic_cast<CGroupModal *>(group);
2432 if (gm)
2434 gm->ExitClickOut = ahOnOk.empty();
2436 messageBoxInternal(mbName, text, masterGroup, caseMode);
2440 // ------------------------------------------------------------------------------------------------
2441 void CInterfaceManager::validMessageBox(TValidMessageIcon icon, const std::string &text, const std::string &ahOnOk,
2442 const std::string &paramsOnOk, const std::string &ahOnCancel, const std::string &paramsOnCancel, const string &masterGroup)
2444 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box"));
2445 CViewText *viewText= dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box:text"));
2446 CViewBitmap *viewBitmap= dynamic_cast<CViewBitmap*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box:icon_group:icon"));
2448 if (group && viewText)
2450 // replace the procedure "proc_valid_message_box_ok" action
2451 CWidgetManager::getInstance()->setProcedureAction("proc_valid_message_box_ok", 1, ahOnOk, paramsOnOk);
2452 // replace the procedure "proc_valid_message_box_cancel" action
2453 CWidgetManager::getInstance()->setProcedureAction("proc_valid_message_box_cancel", 1, ahOnCancel, paramsOnCancel);
2455 // set text and icon
2456 viewText->setText(text);
2457 if(viewBitmap)
2459 bool active= true;
2460 if(icon==QuestionIconMsg)
2461 viewBitmap->setTexture("brick_default.tga");
2462 else if(icon==WarningIconMsg)
2463 viewBitmap->setTexture("W_warning.tga");
2464 else if(icon==ErrorIconMsg)
2465 viewBitmap->setTexture("No_Action.tga");
2466 else
2467 active= false;
2468 viewBitmap->setActive(active);
2471 // Go
2472 CWidgetManager::getInstance()->enableModalWindow(NULL, group);
2473 // don't understand why but need to update coords here
2474 group->updateCoords();
2475 group->updateCoords();
2480 // ------------------------------------------------------------------------------------------------
2481 bool CInterfaceManager::getCurrentValidMessageBoxOnOk(string &ahOnOk, const std::string &masterGroup)
2483 // any modal window opened?
2484 CInterfaceGroup *mw= CWidgetManager::getInstance()->getModalWindow();
2485 if(!mw)
2486 return false;
2488 // Is this modal window the valid_message_box window?
2489 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(masterGroup+":valid_message_box"));
2490 if(mw==group)
2492 // Ok, get the current procedure OnOk action
2493 string dummyParams;
2494 if( CWidgetManager::getInstance()->getParser()->getProcedureAction("proc_valid_message_box_ok", 1, ahOnOk, dummyParams))
2495 return true;
2498 return false;
2502 // ***************************************************************************
2503 void CInterfaceManager::displayDebugInfo(const string &str, TSystemInfoMode mode /*=InfoMsg*/)
2505 if (PeopleInterraction.DebugInfo)
2506 PeopleInterraction.ChatInput.DebugInfo.displayMessage(str, getDebugInfoColor(mode), 2);
2509 // ***************************************************************************
2510 NLMISC::CRGBA CInterfaceManager::getDebugInfoColor(TSystemInfoMode mode)
2512 if (_NeutralColor == NULL) // not initialised ?
2514 #define SYSTEM_INFO_COLOR_DB_PATH "UI:VARIABLES:SYSTEM_INFOS:COLORS"
2515 _NeutralColor = NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":NEUTRAL");
2516 _WarningColor = NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":WARNING");
2517 _ErrorColor = NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":ERROR");
2519 NLMISC::CRGBA color;
2520 switch(mode)
2522 case InfoMsg: color.setPacked(_NeutralColor->getValue32()); break;
2523 case WarningMsg: color.setPacked(_WarningColor->getValue32()); break;
2524 case ErrorMsg: color.setPacked(_ErrorColor->getValue32()); break;
2525 default:
2526 color = CRGBA::White;
2527 break;
2529 return color;
2532 // ***************************************************************************
2533 void CInterfaceManager::displaySystemInfo(const string &str, const string &cat)
2535 CClientConfig::SSysInfoParam::TMode mode = CClientConfig::SSysInfoParam::Normal;
2536 CRGBA color = CRGBA::White;
2539 map<string, CClientConfig::SSysInfoParam>::const_iterator it = ClientCfg.SystemInfoParams.find(toLowerAscii(cat));
2540 if (it != ClientCfg.SystemInfoParams.end())
2542 mode = it->second.Mode;
2543 color = it->second.Color;
2546 if (mode != CClientConfig::SSysInfoParam::OverOnly && mode != CClientConfig::SSysInfoParam::Around)
2548 if (PeopleInterraction.SystemInfo)
2549 PeopleInterraction.ChatInput.SystemInfo.displayMessage(str, color, 2);
2550 else
2552 CPeopleInterraction::CSysMsg sysMsg;
2553 sysMsg.Str = str;
2554 sysMsg.Cat = cat;
2555 PeopleInterraction.SystemMessageBuffer.push_back( sysMsg );
2559 if (mode == CClientConfig::SSysInfoParam::Center || mode == CClientConfig::SSysInfoParam::CenterAround)
2560 InSceneBubbleManager.addMessagePopupCenter(str, color);
2562 // If over popup a string at the bottom of the screen
2563 if ((mode == CClientConfig::SSysInfoParam::Over) || (mode == CClientConfig::SSysInfoParam::OverOnly))
2564 InSceneBubbleManager.addMessagePopup(str, color);
2565 else if ( (mode == CClientConfig::SSysInfoParam::Around || mode == CClientConfig::SSysInfoParam::CenterAround)
2566 && PeopleInterraction.AroundMe.Window)
2567 PeopleInterraction.ChatInput.AroundMe.displayMessage(str, color, 2);
2570 // ***************************************************************************
2571 CRGBA CInterfaceManager::getSystemInfoColor(const std::string &cat)
2573 CRGBA col = CRGBA::White;
2574 map<string, CClientConfig::SSysInfoParam>::const_iterator it = ClientCfg.SystemInfoParams.find(toLowerAscii(cat));
2575 if (it != ClientCfg.SystemInfoParams.end())
2576 col = it->second.Color;
2577 return col;
2580 // ***************************************************************************
2581 void CInterfaceManager::launchContextMenuInGame (const std::string &nameOfCM)
2583 // Launch the context menu in-game: can't appear while dragging an item
2584 if (CCtrlDraggable::getDraggedSheet() == NULL)
2586 if ( !CWidgetManager::getInstance()->hasModal() )
2588 // We must be in-game !
2589 CInterfaceGroup *pMG = CWidgetManager::getInstance()->getMasterGroupFromId("ui:interface");
2590 // TMP nico : try with login screen:
2591 if (!pMG)
2593 pMG = CWidgetManager::getInstance()->getMasterGroupFromId("ui:login");
2595 if (!pMG)
2597 pMG = CWidgetManager::getInstance()->getMasterGroupFromId("ui:outgame");
2599 if ((pMG != NULL) && (pMG->getActive()))
2601 CInterfaceElement *pIE = CWidgetManager::getInstance()->getElementFromId(nameOfCM);
2602 CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(pIE);
2603 if (pIG != NULL)
2605 CWidgetManager::getInstance()->enableModalWindow (NULL, pIG);
2613 // ***************************************************************************
2614 void CInterfaceManager::updateGroupContainerImage(CGroupContainer &gc, uint8 mode)
2616 if (mode >= _Modes.size())
2618 nlwarning("wrong desktop");
2619 return;
2621 _Modes[mode].updateGroupContainerImage(gc);
2624 // ***************************************************************************
2625 void CInterfaceManager::removeGroupContainerImage(const std::string &groupName, uint8 mode)
2627 if (mode >= _Modes.size())
2629 nlwarning("wrong desktop");
2630 return;
2632 _Modes[mode].removeGroupContainerImage(groupName);
2636 // ***************************************************************************
2637 void CInterfaceManager::removeGroupContainerImageFromDesktops(const std::string &groupName)
2639 for (uint i = 0; i < _Modes.size(); i++)
2641 _Modes[i].removeGroupContainerImage(groupName);
2645 // ***************************************************************************
2646 void CInterfaceManager::setMode(uint8 newMode)
2648 if (newMode >= _Modes.size())
2649 return;
2651 if (newMode == _CurrentMode)
2652 return;
2654 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
2656 // Check if we can change vdesk !
2657 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2659 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2660 if (rMG.Group->getActive())
2662 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
2664 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
2665 list<CInterfaceGroup*>::const_iterator itw;
2666 for (itw = rList.begin(); itw!= rList.end(); itw++)
2668 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(*itw);
2669 if ((pGC != NULL)&&(pGC->getActive()))
2671 // if this GC is a Full modal window, or if it is a modal son of another GC,
2672 if (pGC->isModal() || pGC->isModalSon())
2674 CWidgetManager::getInstance()->setTopWindow(pGC);
2675 pGC->enableBlink(2);
2676 return;
2678 else
2679 if (pGC->isGrayed())
2681 // Make the corresponding child blink
2682 pGC->blinkAllSons();
2683 return;
2691 // check if there's a special behaviour with current captured ctrl that prevent from changing desktop
2692 if ( CWidgetManager::getInstance()->getCapturePointerLeft() != NULL)
2694 if (!CWidgetManager::getInstance()->getCapturePointerLeft()->canChangeVirtualDesktop()) return;
2696 if ( CWidgetManager::getInstance()->getCapturePointerRight() != NULL)
2698 if (!CWidgetManager::getInstance()->getCapturePointerRight()->canChangeVirtualDesktop()) return;
2702 _Modes[_CurrentMode].fromCurrentDesktop();
2703 _Modes[newMode].toCurrentDesktop();
2704 //CBotChatUI::refreshActiveWindows();
2706 _CurrentMode = newMode;
2707 CWidgetManager::getInstance()->checkCoords();
2710 // ***************************************************************************
2711 void CInterfaceManager::resetMode(uint8 newMode)
2713 if (newMode >= _Modes.size())
2714 return;
2715 NLMISC::contReset(_Modes[newMode]);
2719 // for dump of interface content
2720 struct CDumpedGroup
2722 CInterfaceGroup *Group;
2723 uint Depth; // depth in the tree
2726 // ***************************************************************************
2727 void CInterfaceManager::dumpUI(bool /* indent */)
2729 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
2730 std::vector<CDumpedGroup> left;
2731 left.resize(_MasterGroups.size());
2732 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2734 left[nMasterGroup].Group = _MasterGroups[nMasterGroup].Group;
2735 left[nMasterGroup].Depth = 0;
2738 while (!left.empty())
2740 CInterfaceGroup *ig = left.back().Group;
2741 if (ig)
2743 uint currDepth = left.back().Depth;
2744 std::string id = ig->getId();
2745 std::string::size_type pos = id.find_last_of(':');
2746 if (pos != std::string::npos)
2748 id = id.substr(pos + 1);
2750 std::string info(currDepth * 4, ' ');
2751 info += id;
2752 info += toString(", address=0x%p", ig);
2753 nlinfo(info.c_str());
2754 // dump view & controls for this group
2755 for(uint k = 0; k < ig->getViews().size(); ++k)
2757 std::string info(currDepth * 4, ' ');
2758 info += toString("View %d / %d : ", (int) k + 1, (int) ig->getViews().size());
2759 if (ig->getViews()[k])
2761 info += id;
2762 NLGUI::CViewBase *view = ig->getViews()[k];
2763 info += toString(", type = %s, address=0x%p", typeid(*view).name(), view);
2765 else
2767 info += "<NULL>";
2769 nlinfo(info.c_str());
2772 for(uint k = 0; k < ig->getControls().size(); ++k)
2774 std::string info(currDepth * 4, ' ');
2775 info += toString("Ctrl %d / %d : ", (int) k + 1, (int) ig->getControls().size());
2776 if (ig->getControls()[k])
2778 info += id;
2779 NLGUI::CCtrlBase *control = ig->getControls()[k];
2780 info += toString(", type = %s, address=0x%p", typeid(*control).name(), control);
2782 else
2784 info += "<NULL>";
2786 nlinfo(info.c_str());
2790 left.pop_back();
2792 for(uint k = 0; k < ig->getNumGroup(); ++k)
2794 CDumpedGroup dg;
2795 dg.Group = ig->getGroup(k);
2796 dg.Depth = currDepth + 1;
2797 left.push_back(dg);
2803 // ***************************************************************************
2804 void CInterfaceManager::displayUIViewBBoxs(const std::string &uiFilter)
2806 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
2807 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2809 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2810 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
2812 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
2813 list<CInterfaceGroup*>::iterator it;
2814 for(it = rList.begin(); it != rList.end(); ++it)
2816 if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderView, uiFilter);
2822 // ***************************************************************************
2823 void CInterfaceManager::displayUICtrlBBoxs(const std::string &uiFilter)
2825 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
2826 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2828 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2829 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
2831 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
2832 list<CInterfaceGroup*>::iterator it;
2833 for(it = rList.begin(); it != rList.end(); ++it)
2835 if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderCtrl, uiFilter);
2841 // ***************************************************************************
2842 void CInterfaceManager::displayUIGroupBBoxs(const std::string &uiFilter)
2844 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
2845 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2847 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2848 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
2850 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
2851 list<CInterfaceGroup*>::iterator it;
2852 for(it = rList.begin(); it != rList.end(); ++it)
2854 if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderGroup, uiFilter);
2860 // ***************************************************************************
2861 void writeComboActionMap (const CActionsManager &actions, xmlNodePtr node, const string &context)
2863 // Get the combo defined
2864 const CActionsManager::TComboActionMap &combos = actions.getComboActionMap ();
2865 CActionsManager::TComboActionMap::const_iterator ite = combos.begin ();
2866 while (ite != combos.end ())
2868 // Key node
2869 xmlNodePtr keyNode = xmlNewChild ( node, NULL, (const xmlChar*)"key", NULL );
2871 // Props
2872 xmlSetProp (keyNode, (const xmlChar*)"name", (const xmlChar*)CEventKey::getStringFromKey(ite->first.Key).c_str());
2874 if (ite->first.KeyButtons&shiftKeyButton)
2875 xmlSetProp (keyNode, (const xmlChar*)"shift", (const xmlChar*)"1");
2876 if (ite->first.KeyButtons&ctrlKeyButton)
2877 xmlSetProp (keyNode, (const xmlChar*)"ctrl", (const xmlChar*)"1");
2878 if (ite->first.KeyButtons&altKeyButton)
2879 xmlSetProp (keyNode, (const xmlChar*)"menu", (const xmlChar*)"1");
2881 xmlSetProp (keyNode, (const xmlChar*)"action", (const xmlChar*)ite->second.Name.c_str());
2882 if (!(const xmlChar*)ite->second.Argu.empty())
2883 xmlSetProp (keyNode, (const xmlChar*)"params", (const xmlChar*)ite->second.Argu.c_str());
2885 // Context
2886 if (!context.empty ())
2887 xmlSetProp (keyNode, (const xmlChar*)"context", (const xmlChar*)context.c_str());
2889 ite++;
2893 // ***************************************************************************
2895 void writeMacros (xmlNodePtr node)
2897 const std::vector<CMacroCmd> &macros = CMacroCmdManager::getInstance()->getMacros();
2898 for (uint i = 0; i < macros.size(); ++i)
2900 macros[i].writeTo(node);
2904 // ***************************************************************************
2905 bool CInterfaceManager::saveKeys(bool verbose)
2907 bool ret = true;
2909 if (!ClientCfg.R2EDEnabled)
2911 string filename = "save/keys_" + PlayerSelectedFileName + ".xml";
2912 if (!CFile::fileExists(filename) && CFile::fileExists("save/shared_keys.xml"))
2913 filename = "save/shared_keys.xml";
2915 if (verbose) CInterfaceManager::getInstance()->displaySystemInfo("Saving " + filename);
2917 ret = saveKeys(filename);
2920 return ret;
2923 // ***************************************************************************
2924 bool CInterfaceManager::saveKeys(const std::string &filename)
2926 bool ret = false;
2930 COFile file;
2931 // using temporary file, so no file.close() unless its a success
2932 if (file.open (filename, false, false, true))
2934 COXml xmlStream;
2935 xmlStream.init (&file);
2937 xmlDocPtr doc = xmlStream.getDocument ();
2938 xmlNodePtr node = xmlNewDocNode(doc, NULL, (const xmlChar*)"interface_config", NULL);
2939 xmlDocSetRootElement (doc, node);
2941 writeComboActionMap (Actions, node, "");
2942 writeComboActionMap (EditActions, node, RZ_CATEGORY_EDIT);
2944 writeMacros (node);
2946 // Flush the stream
2947 xmlStream.flush();
2949 // Close the stream
2950 file.close ();
2952 // Done
2953 ret = true;
2955 else
2957 nlwarning ("Can't open the file %s", filename.c_str());
2960 catch (const Exception &e)
2962 nlwarning ("Error while writing the file %s : %s.", filename.c_str(), e.what ());
2964 return ret;
2967 // ***************************************************************************
2968 bool CInterfaceManager::deletePlayerConfig (const std::string &playerFileIdent)
2970 string fileName= "save/interface_" + playerFileIdent + ".icfg";
2971 return CFile::deleteFile(fileName);
2975 // ***************************************************************************
2976 bool CInterfaceManager::deletePlayerKeys (const std::string &playerFileIdent)
2978 string fileName = "save/keys_"+playerFileIdent+".xml";
2979 string fileNameEditor = "save/keys_r2ed_"+playerFileIdent+".xml";
2980 return CFile::deleteFile(fileName) && CFile::deleteFile(fileNameEditor);
2983 // ***************************************************************************
2984 void CInterfaceManager::log(const std::string &str, const std::string &cat)
2986 if (_LogState)
2988 // Open file with the name of the player
2989 const string fileName= "save/log_" + PlayerSelectedFileName + ".txt";
2990 FILE *f = nlfopen(fileName, "at");
2991 if (f != NULL)
2993 const string finalString = string(NLMISC::IDisplayer::dateToHumanString()) + " (" + NLMISC::toUpperAscii(cat) + ") * " + str;
2994 fprintf(f, "%s\n", finalString.c_str());
2995 fclose(f);
3000 // ***************************************************************************
3001 void CInterfaceManager::clearAllEditBox()
3003 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
3004 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
3006 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
3007 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
3009 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
3010 list<CInterfaceGroup*>::iterator it;
3011 for(it = rList.begin(); it != rList.end(); ++it)
3013 CInterfaceGroup *pIG = *it;
3014 if (pIG != NULL)
3015 pIG->clearAllEditBox();
3021 // ***************************************************************************
3022 void CInterfaceManager::restoreAllContainersBackupPosition()
3024 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
3025 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
3027 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
3028 for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
3030 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
3031 list<CInterfaceGroup*>::iterator it;
3032 for(it = rList.begin(); it != rList.end(); ++it)
3034 if (*it) (*it)->restoreAllContainersBackupPosition();
3040 // ***************************************************************************
3041 void CInterfaceManager::visit(CInterfaceElementVisitor *visitor)
3043 nlassert(visitor);
3044 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
3045 for (uint nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
3047 if (_MasterGroups[nMasterGroup].Group)
3049 _MasterGroups[nMasterGroup].Group->visit(visitor);
3054 // ***************************************************************************
3055 void CInterfaceManager::incLocalSyncActionCounter()
3057 _LocalSyncActionCounter++;
3062 #if !FINAL_VERSION
3064 // ***************************************************************************
3065 NLMISC_COMMAND( localCounter, "Get value of local counter", "" )
3067 if (args.size() != 0) return false;
3068 CInterfaceManager *im = CInterfaceManager::getInstance();
3069 im->displaySystemInfo(toString(im->getLocalSyncActionCounter()));
3070 return true;
3073 #endif
3075 // ***************************************************************************
3077 NLMISC_COMMAND(loadui, "Load an interface file", "<loadui [all]/interface.xml>")
3079 if (args.size() != 1)
3080 return false;
3082 CInterfaceManager *im = CInterfaceManager::getInstance();
3084 std::vector<std::string> xmlFileNames;
3086 if (args[0] == "all")
3087 xmlFileNames = CInterfaceManager::getInGameXMLInterfaceFiles();
3088 else
3089 xmlFileNames.push_back (args[0]);
3091 bool result = im->parseInterface (xmlFileNames, true);
3092 #if !FINAL_VERSION
3093 if (result)
3094 CInterfaceManager::getInstance()->displaySystemInfo("File "+xmlFileNames.back()+" loaded successfully.");
3095 else
3096 CInterfaceManager::getInstance()->displaySystemInfo("File "+xmlFileNames.back()+" NOT loaded successully.");
3097 #endif
3099 // Invalidate the texts
3100 CWidgetManager::getInstance()->updateAllLocalisedElements();
3102 // reset captures
3103 CWidgetManager::getInstance()->setCapturePointerLeft(NULL);
3104 CWidgetManager::getInstance()->setCapturePointerRight(NULL);
3105 CWidgetManager::getInstance()->setOldCaptureKeyboard(NULL);
3106 CWidgetManager::getInstance()->setCaptureKeyboard(NULL);
3108 return result;
3111 // ***************************************************************************
3112 void CInterfaceManager::displayWebWindow(const string & name, const string & url)
3114 CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(name));
3115 if (pIG != NULL)
3117 pIG->setActive(true);
3118 pIG->updateCoords();
3119 pIG->center();
3122 CAHManager::getInstance()->runActionHandler("browse", NULL, "name="+name+":content:html|url="+url);
3125 // ***************************************************************************
3126 class CAHSaveUI : public IActionHandler
3128 virtual void execute (CCtrlBase *pCaller, const string &Params)
3130 CInterfaceManager::getInstance()->saveKeys(true);
3131 CInterfaceManager::getInstance()->saveConfig(true);
3134 REGISTER_ACTION_HANDLER (CAHSaveUI, "save_ui");
3137 // ***************************************************************************
3138 class CHandlerDispWebOnQuit : public IActionHandler
3140 virtual void execute (CCtrlBase *pCaller, const string &Params)
3142 if (ClientCfg.Local)
3143 CAHManager::getInstance()->runActionHandler("enter_modal", pCaller, "group=ui:interface:quit_dialog");
3144 else
3145 CInterfaceManager::getInstance()->displayWebWindow("ui:interface:web_on_quit", "http://213.208.119.190/igpoll/poll_form.php");
3148 REGISTER_ACTION_HANDLER (CHandlerDispWebOnQuit, "disp_web_on_quit");
3150 // ***************************************************************************
3151 class CHandlerExitWebOnQuit : public IActionHandler
3153 virtual void execute (CCtrlBase *pCaller, const string &Params)
3155 CAHManager::getInstance()->runActionHandler("quit_ryzom", pCaller);
3158 REGISTER_ACTION_HANDLER (CHandlerExitWebOnQuit, "exit_web_on_quit");
3161 // ***************************************************************************
3162 // EMOTES
3163 // ***************************************************************************
3165 struct CEmoteEntry
3167 uint32 EmoteId;
3168 string Path;
3169 string Anim;
3170 bool UsableFromClientUI;
3172 bool operator< (const CEmoteEntry & entry) const
3174 string path1 = Path;
3175 string path2 = entry.Path;
3177 for(;;)
3179 string::size_type pos1 = path1.find('|');
3180 string::size_type pos2 = path2.find('|');
3182 string s1 = toUpper(CI18N::get(path1.substr(0, pos1)));
3183 string s2 = toUpper(CI18N::get(path2.substr(0, pos2)));
3185 sint result = s1.compare(s2);
3186 if (result != 0)
3187 return (result < 0);
3189 if (pos1 == string::npos)
3190 return (pos2 != string::npos);
3191 if (pos2 == string::npos)
3192 return false;
3194 path1 = path1.substr(pos1 + 1);
3195 path2 = path2.substr(pos2 + 1);
3197 return false;
3201 static bool translateEmote(const std::string &id, std::string &translatedName, std::string &commandName, std::string &commandNameAlt)
3203 if (CI18N::hasTranslation(id))
3205 translatedName = CI18N::get(id);
3207 // convert command to utf8 since emote translation can have strange chars
3208 commandName = toLower(translatedName);
3210 // replace all spaces by _
3211 while (strFindReplace(commandName, " ", "_"));
3213 // TODO: remove accents
3214 commandNameAlt = commandName;
3216 if (commandNameAlt == commandName) commandNameAlt.clear();
3218 return true;
3221 translatedName = id;
3222 commandName = id;
3224 return false;
3227 // ***************************************************************************
3228 void CInterfaceManager::initEmotes()
3230 _EmotesInitialized = true;
3231 CTextEmotListSheet *pTELS = dynamic_cast<CTextEmotListSheet*>(SheetMngr.get(CSheetId("list.text_emotes")));
3232 if (pTELS == NULL)
3233 return;
3235 static list<CEmoteEntry> entries;
3236 if (entries.empty())
3238 for (uint i = 0; i < pTELS->TextEmotList.size(); i++)
3240 CEmoteEntry entry;
3241 entry.EmoteId = i;
3242 entry.Path = pTELS->TextEmotList[i].Path;
3243 entry.Anim = pTELS->TextEmotList[i].Anim;
3244 entry.UsableFromClientUI = pTELS->TextEmotList[i].UsableFromClientUI;
3245 entries.push_back(entry);
3247 entries.sort();
3250 // The list of behaviour missnames emotList
3251 CEmotListSheet *pEmotList = dynamic_cast<CEmotListSheet*>(SheetMngr.get(CSheetId("list.emot")));
3252 nlassert (pEmotList != NULL);
3253 nlassert (pEmotList->Emots.size() <= 255);
3255 // Get the focus beta tester flag
3256 bool betaTester = false;
3258 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3259 CSkillManager *pSM = CSkillManager::getInstance();
3261 betaTester = pSM->isTitleUnblocked(CHARACTER_TITLE::FBT);
3262 string previousMind;
3263 CGroupSubMenu *pFirstMenu = 0;
3265 for (list<CEmoteEntry>::const_iterator it = entries.begin(); it != entries.end(); it++)
3267 uint32 nEmoteNb = (*it).EmoteId;
3268 string sState = (*it).Anim;
3269 string sName = (*it).Path;
3271 // Check that the emote can be added to UI
3272 // ---------------------------------------
3273 if( (*it).UsableFromClientUI == false )
3275 continue;
3278 // Check the emote reserved for FBT (hardcoded)
3279 // --------------------------------------------
3280 if (sState == "FBT" && !betaTester)
3281 continue;
3283 // Get the behaviour from the list of emotes
3284 // -----------------------------------------
3285 uint8 nBehav = 255;
3286 uint32 i, j;
3287 for (i = 0; i < pEmotList->Emots.size(); ++i)
3288 if (CAnimationStateSheet::getAnimationStateName(pEmotList->Emots[i]) == sState)
3290 nBehav = (uint8)i;
3291 break;
3294 // Add to the game context menu
3295 // ----------------------------
3296 uint32 nbToken = 1;
3297 for (i = 0; i < sName.size(); ++i)
3298 if (sName[i] == '|')
3299 nbToken++;
3301 CGroupMenu *pRootMenu = dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:user_chat_emote_menu"));
3302 nlassert(pRootMenu);
3304 CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
3305 nlassert(pMenu);
3307 std::string sTranslatedName;
3308 std::string sCommandName;
3309 std::string sCommandNameAlt;
3311 // Add to the game context menu
3312 // ----------------------------
3313 for (i = 0; i < nbToken; ++i)
3315 string sTmp;
3316 if (i != (nbToken-1))
3317 sTmp = sName.substr(0,sName.find('|'));
3318 else
3319 sTmp = sName;
3321 // Look if this part of the path is already present
3322 bool bFound = false;
3323 for (j = 0; j < pMenu->getNumLine(); ++j)
3325 if (sTmp == pMenu->getLineId(j))
3327 bFound = true;
3328 break;
3333 if (!bFound) // Create it
3335 if (i != (nbToken-1))
3337 pMenu->addLine (CI18N::get(sTmp), "", "", sTmp);
3339 // Create a sub menu
3340 CGroupSubMenu *pNewSubMenu = new CGroupSubMenu(CViewBase::TCtorParam());
3341 pMenu->setSubMenu(j, pNewSubMenu);
3343 if (pFirstMenu == 0)
3344 pFirstMenu = pNewSubMenu;
3346 else
3348 translateEmote(sTmp, sTranslatedName, sCommandName, sCommandNameAlt);
3350 // Create a line
3351 pMenu->addLine (sTranslatedName + " (/" + sCommandName + ")", "emote",
3352 "nb="+toString(nEmoteNb)+"|behav="+toString(nBehav), sTmp);
3356 // Jump to sub menu
3357 if (i != (nbToken-1))
3359 pMenu = pMenu->getSubMenu(j);
3360 sName = sName.substr(sName.find('|')+1,sName.size());
3364 if (sTranslatedName.empty())
3365 translateEmote(sName, sTranslatedName, sCommandName, sCommandNameAlt);
3367 // Create new command
3368 // ------------------
3369 if (!sTranslatedName.empty())
3371 if(ICommand::exists(sCommandName))
3373 nlwarning("Translation for emote %s already exist: '%s' exist twice", sName.c_str(), sCommandName.c_str());
3375 else
3377 CEmoteCmd *pNewCmd = new CEmoteCmd(sCommandName.c_str(), "", "");
3378 pNewCmd->EmoteNb = nEmoteNb;
3379 pNewCmd->Behaviour = nBehav;
3380 _EmoteCmds.push_back(pNewCmd);
3382 // add alternative command if defined
3383 if (!sCommandNameAlt.empty())
3385 if(ICommand::exists(sCommandNameAlt))
3387 nlwarning("Translation for emote %s already exist: '%s' exist twice", sName.c_str(), sCommandName.c_str());
3389 else
3391 CEmoteCmd *pNewCmd = new CEmoteCmd(sCommandNameAlt.c_str(), "", "");
3392 pNewCmd->EmoteNb = nEmoteNb;
3393 pNewCmd->Behaviour = nBehav;
3394 _EmoteCmds.push_back(pNewCmd);
3398 CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
3400 // Quick-Emote too ?
3401 for (i = 0; i< pMenu->getNumLine (); i++)
3403 if (sName == pMenu->getLineId (i))
3405 // Yeah that's a quick emote too; set command
3406 pMenu->addLineAtIndex (i,
3407 "@{FFFF}/" + sCommandName,
3408 "emote", "nb="+toString(nEmoteNb)+"|behav="+toString(nBehav),
3409 "", "", "", false, false, true);
3411 pMenu->removeLine (i+1);
3412 break;
3417 else
3419 nlwarning("No translation for emote %s", sName.c_str());
3423 // Insert separators
3424 if (pFirstMenu)
3426 pFirstMenu->addSeparatorAtIndex (0, "Positive");
3427 pFirstMenu->addSeparatorAtIndex (4, "Neutral");
3428 pFirstMenu->addSeparatorAtIndex (8, "Negative");
3433 // ***************************************************************************
3434 void CInterfaceManager::uninitEmotes()
3436 if( !_EmotesInitialized )
3437 return;
3438 _EmotesInitialized = false;
3440 // reset the emotes menu
3441 CTextEmotListSheet *pTELS = dynamic_cast<CTextEmotListSheet*>(SheetMngr.get(CSheetId("list.text_emotes")));
3442 if (pTELS != NULL && !pTELS->TextEmotList.empty())
3444 // get the emotes menu id
3445 string sPath = pTELS->TextEmotList[0].Path;
3446 string sId = sPath.substr(0, sPath.find('|'));
3448 // get the emotes menu
3449 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3450 CGroupMenu *pRootMenu = dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:game_context_menu"));
3451 if( pRootMenu )
3453 CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
3454 for (uint i = 0; i < pMenu->getNumLine(); ++i)
3456 if (pMenu->getLineId(i) == sId)
3458 pMenu = pMenu->getSubMenu(i);
3459 pMenu->reset();
3460 break;
3466 // clear commands
3467 for (uint32 i = 0; i < _EmoteCmds.size(); ++i)
3468 delete _EmoteCmds[i];
3469 _EmoteCmds.clear();
3472 // ***************************************************************************
3473 void CInterfaceManager::updateEmotes()
3475 uninitEmotes();
3476 initEmotes();
3479 // ***************************************************************************
3480 // Just call the action handler with good params
3481 bool CInterfaceManager::CEmoteCmd::execute(const std::string &/* rawCommandString */, const vector<string> &args, CLog &/* log */, bool /* quiet */, bool /* human */)
3483 string customPhrase;
3484 if (!args.empty())
3486 customPhrase = args[0];
3488 for(uint i = 1; i < args.size(); ++i )
3490 customPhrase += " ";
3491 customPhrase += args[i];
3493 CAHManager::getInstance()->runActionHandler("emote", NULL, "nb="+toString(EmoteNb)+"|behav="+toString(Behaviour)+"|custom_phrase="+customPhrase);
3494 return true;
3497 // ***************************************************************************
3498 bool CInterfaceManager::testDragCopyKey()
3500 // hardcoded for now
3501 return Driver->AsyncListener.isKeyDown(KeyCONTROL) ||
3502 Driver->AsyncListener.isKeyDown(KeyLCONTROL) ||
3503 Driver->AsyncListener.isKeyDown(KeyRCONTROL);
3506 // ***************************************************************************
3507 void CInterfaceManager::notifyMailAvailable()
3509 if (_CheckMailNode != NULL)
3510 _CheckMailNode->setValue32(1);
3513 void CInterfaceManager::notifyForumUpdated()
3515 if (_CheckForumNode != NULL)
3516 _CheckForumNode->setValue32(1);
3519 void CInterfaceManager::queueLuaScript(const std::string &script)
3521 CAutoMutex<CMutex> autoMutex(_ScriptQueueMutex);
3523 _ScriptQueue.push(script);
3526 void CInterfaceManager::flushScriptQueue()
3528 CAutoMutex<CMutex> autoMutex(_ScriptQueueMutex);
3530 while(!_ScriptQueue.empty())
3532 CLuaManager::getInstance().executeLuaScript(_ScriptQueue.front());
3533 _ScriptQueue.pop();
3538 // ***************************************************************************
3539 void CInterfaceManager::resetTextIndex()
3541 uint32 nMasterGroup;
3542 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = CWidgetManager::getInstance()->getAllMasterGroup();
3543 for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
3545 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
3547 InvalidateTextVisitor inv( true );
3548 rMG.Group->visitGroupAndChildren( &inv );
3549 for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
3551 list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
3552 list<CInterfaceGroup*>::const_iterator itw;
3553 for (itw = rList.begin(); itw != rList.end(); itw++)
3555 CInterfaceGroup *pIG = *itw;
3556 pIG->visitGroupAndChildren( &inv );
3562 // ***************************************************************************
3563 CInterfaceElement *getInterfaceResource(const std::string &key)
3565 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3566 return CWidgetManager::getInstance()->getElementFromId (key);
3569 // ***************************************************************************
3570 std::vector<std::string> CInterfaceManager::getInGameXMLInterfaceFiles()
3572 // Original Files
3573 vector<string> ret;
3574 ret= ClientCfg.XMLInterfaceFiles;
3576 // Resolve any conflict (with CPath scheme, AddOn Should take the precedence)
3577 // But still preserve order given in XMLInterfaceFiles (important for config.xml for instance)
3578 set<string> fileSet;
3579 for(uint i=0;i<ret.size();i++)
3581 fileSet.insert(ret[i]);
3584 // Add R2 Editor .xml. This is removed as it will not be done when initializing CEditor
3585 // if (ClientCfg.R2EDEnabled)
3586 // {
3587 // // Add them to 'ret', only if not already inserted
3588 // // since parser will crash on any duplicates
3589 // for(uint i=0;i<ClientCfg.XMLR2EDInterfaceFiles.size();i++)
3590 // {
3591 // if(fileSet.find(ClientCfg.XMLR2EDInterfaceFiles[i])==fileSet.end())
3592 // {
3593 // fileSet.insert(ClientCfg.XMLR2EDInterfaceFiles[i]);
3594 // ret.push_back(ClientCfg.XMLR2EDInterfaceFiles[i]);
3595 // }
3596 // }
3597 // }
3599 // Get Addons .xml
3600 vector<string> adds;
3601 InterfaceAddOnManager.getFiles("*.xml", adds);
3603 // Add them to 'ret', only if not already inserted
3604 for(uint i=0;i<adds.size();i++)
3606 if(fileSet.find(adds[i])==fileSet.end())
3608 fileSet.insert(adds[i]);
3609 ret.push_back(adds[i]);
3613 return ret;
3616 // ***************************************************************************
3617 void CInterfaceManager::dumpLuaString(const std::string &str)
3619 nlinfo(str.c_str());
3620 displaySystemInfo(LuaHelperStuff::formatLuaErrorSysInfo(str));
3623 // ***************************************************************************
3624 void CInterfaceManager::getLuaValueInfo(std::string &str, sint index)
3626 CLuaState &ls= *( CLuaManager::getInstance().getLuaState() );
3628 sint type= ls.type(index);
3629 if(type==LUA_TNIL)
3631 str= "nil";
3633 else if(type==LUA_TNUMBER)
3635 str= NLMISC::toString(ls.isInteger(index) ? ls.toInteger(index):ls.toNumber(index));
3637 else if(type==LUA_TBOOLEAN)
3639 str= ls.toBoolean(index)?"true":"false";
3641 else if(type==LUA_TSTRING)
3643 ls.toString(index, str);
3644 str= toString("'") + str + toString("'");
3646 else
3648 str= ls.getTypename(type);
3649 str+= ":";
3650 str+= NLMISC::toString("%p", ls.toPointer(index));
3651 // If its a table, append the size.
3652 if(type==LUA_TTABLE)
3654 ls.pushNil(); // first key
3655 uint count= 0;
3656 while (ls.next(index-1))
3658 ls.pop(); // remove 'value'; keeps `key' for next iteration
3659 count++;
3661 str+= NLMISC::toString(" (size=%d)", count);
3663 // If its a Userdata, try to display UI info
3664 else if(type==LUA_TUSERDATA)
3666 if(CLuaIHM::isUIOnStack(ls, index))
3668 CInterfaceElement *ui= CLuaIHM::getUIOnStack(ls, index);
3669 str+= NLMISC::toString(" (ui=%p)", ui);
3675 // ***************************************************************************
3676 void CInterfaceManager::dumpLuaKeyValueInfo(uint recursTableLevel, uint tabLevel)
3678 CLuaState &ls= *( CLuaManager::getInstance().getLuaState() );
3679 CLuaStackChecker lsc(&ls);
3681 // Dump Key Str
3682 string key;
3683 getLuaValueInfo(key, -2);
3684 // Dump Value Str
3685 string value;
3686 getLuaValueInfo(value, -1);
3688 // display.
3689 string res;
3690 // append tab for table hierarchy
3691 for(uint i=0;i<tabLevel;i++)
3692 res+= " ";
3693 // display key and value
3694 res+= key + " == " + value;
3695 dumpLuaString(res);
3697 // If the value is a table, and can recurs dumping
3698 if(recursTableLevel>0 && ls.type(-1)==LUA_TTABLE)
3700 ls.pushNil(); // first key
3701 while (ls.next(-2))
3703 // display the key value pair of this table (recurs)
3704 dumpLuaKeyValueInfo(recursTableLevel-1, tabLevel+1);
3705 ls.pop(); // remove 'value'; keeps `key' for next iteration
3711 // ***************************************************************************
3712 void CInterfaceManager::dumpLuaState(uint detail)
3714 CLuaState *_LuaState = CLuaManager::getInstance().getLuaState();
3716 // clamp detailed info to 2 (display at max content of eaxh Env of each group)
3717 clamp(detail, 0U, 2U);
3719 // Dump the Memory State
3720 dumpLuaString(NLMISC::toString("Memory Used : %d Kb", _LuaState->getGCCount()));
3721 dumpLuaString(NLMISC::toString("GC Threshold: %d Kb", _LuaState->getGCThreshold()));
3723 // If want to display some detailed info
3724 if(detail>0)
3726 CLuaState &ls= *_LuaState;
3727 CLuaStackChecker lsc(&ls);
3729 // *** Dump all Lua Env Tables
3730 ls.push(IHM_LUA_ENVTABLE);
3731 ls.getTable(LUA_REGISTRYINDEX); // __ui_envtable
3732 ls.pushNil(); // first key
3733 uint count= 0;
3734 while (ls.next(-2))
3736 // `key' is at index -2 and `value' at index -1
3737 dumpLuaKeyValueInfo(detail-1, 1);
3738 ls.pop(); // remove 'value'; keeps `key' for next iteration
3739 count++;
3741 // pop table
3742 ls.pop();
3744 dumpLuaString(NLMISC::toString("Number of EnvTable for ui groups: %d", count));
3748 // ------------------------------------------------------------------------------------------------
3749 void CInterfaceManager::createLocalBranch(const std::string &fileName, NLMISC::IProgressCallback &progressCallBack)
3753 CIFile file;
3754 if (file.open (fileName))
3756 // Init an xml stream
3757 CIXml read;
3758 read.init (file);
3760 //Parse the parser output!!!
3761 CCDBNodeBranch *localNode = new CCDBNodeBranch("LOCAL");
3762 localNode->init( read.getRootNode (), progressCallBack );
3763 NLGUI::CDBManager::getInstance()->getDB()->attachChild(localNode,"LOCAL");
3765 // Create the observers for auto-copy SERVER->LOCAL of inventory
3766 ServerToLocalAutoCopyInventory.init("INVENTORY");
3768 // Create the observers for auto-copy SERVER->LOCAL of exchange
3769 ServerToLocalAutoCopyExchange.init("EXCHANGE");
3771 // Create the observers for auto-copy SERVER->LOCAL of dm (animator) gift
3772 ServerToLocalAutoCopyDMGift.init("DM_GIFT");
3774 // Create the observers for auto-copy SERVER->LOCAL of context menu
3775 ServerToLocalAutoCopyContextMenu.init("TARGET:CONTEXT_MENU");
3777 // Create the observers for auto-copy SERVER->LOCAL of Skill Points
3778 ServerToLocalAutoCopySkillPoints.init("USER");
3781 catch (const Exception &e)
3783 // Output error
3784 nlwarning ("CFormLoader: Error while loading the form %s: %s", fileName.c_str(), e.what());
3788 // ------------------------------------------------------------------------------------------------
3789 #ifdef NL_OS_WINDOWS
3790 # pragma warning (push)
3791 # pragma warning (disable : 4355) // 'this' used in base member initializer list
3792 #endif
3793 CInterfaceManager::CServerToLocalAutoCopy::CServerToLocalAutoCopy() : _LocalObserver(*this), _ServerObserver(*this)
3795 _ServerCounter= NULL;
3796 _UpdateList.reserve(300);
3797 _LocalUpdating= false;
3799 #ifdef NL_OS_WINDOWS
3800 # pragma warning (pop)
3801 #endif
3803 // ------------------------------------------------------------------------------------------------
3804 // unhook from everything we are tangled up in
3805 void CInterfaceManager::CServerToLocalAutoCopy::release()
3807 _Nodes.clear();
3808 _ServerCounter = NULL;
3809 _ServerNodeMap.clear();
3810 _LocalNodeMap.clear();
3811 _UpdateList.clear();
3814 // ------------------------------------------------------------------------------------------------
3815 void CInterfaceManager::CServerToLocalAutoCopy::buildRecursLocalLeaves(CCDBNodeBranch *branch, std::vector<CCDBNodeLeaf*> &leaves)
3817 for(uint i=0;i<branch->getNbNodes();i++)
3819 ICDBNode *node= branch->getNode(i);
3820 if(node)
3822 CCDBNodeLeaf *leaf= dynamic_cast<CCDBNodeLeaf*>(node);
3823 if(leaf)
3825 // just append to list
3826 leaves.push_back(leaf);
3828 else
3830 // recurs if a branch (should be...)
3831 CCDBNodeBranch *sonBranch= dynamic_cast<CCDBNodeBranch*>(node);
3832 if(sonBranch)
3833 buildRecursLocalLeaves(sonBranch, leaves);
3839 // ------------------------------------------------------------------------------------------------
3840 void CInterfaceManager::CServerToLocalAutoCopy::init(const std::string &dbPath)
3842 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3844 // Get the synchronisation Counter in Server DB
3845 _ServerCounter= NLGUI::CDBManager::getInstance()->getDbProp(string("SERVER:") + dbPath + ":COUNTER", false);
3847 // if found
3848 if(_ServerCounter)
3850 ICDBNode::CTextId textId;
3852 // **** Add Observers on all nodes
3853 // add the observers when server node change
3854 textId = ICDBNode::CTextId( string("SERVER:") + dbPath );
3855 NLGUI::CDBManager::getInstance()->getDB()->addObserver(&_ServerObserver, textId );
3857 // add the observers when local node change
3858 textId = ICDBNode::CTextId( string("LOCAL:") + dbPath );
3859 NLGUI::CDBManager::getInstance()->getDB()->addObserver(&_LocalObserver, textId );
3861 // **** Init the Nodes shortcut
3862 // Parse all Local Nodes
3863 CCDBNodeBranch *localBranch= NLGUI::CDBManager::getInstance()->getDbBranch(string("LOCAL:") + dbPath);
3864 if(localBranch)
3866 uint i;
3867 std::vector<CCDBNodeLeaf*> leaves;
3868 buildRecursLocalLeaves(localBranch, leaves);
3870 // --- build _Nodes
3871 _Nodes.reserve(leaves.size());
3872 for(i=0;i<leaves.size();i++)
3874 CCDBNodeLeaf *localLeaf= leaves[i];
3876 // get the SERVER associated node name
3877 string serverLeafStr= *localLeaf->getName();
3878 CCDBNodeBranch* parent= localLeaf->getParent();
3879 while( *parent->getName()!="LOCAL" )
3881 serverLeafStr= *parent->getName()+":"+serverLeafStr;
3882 parent= parent->getParent();
3884 serverLeafStr= "SERVER:" + serverLeafStr;
3886 // try then to get this server node
3887 CCDBNodeLeaf *serverLeaf= NLGUI::CDBManager::getInstance()->getDbProp(serverLeafStr, false);
3888 if(serverLeaf)
3890 // Both server and local leaves exist, ok, append to _Nodes
3891 CNode node;
3892 node.ServerNode= serverLeaf;
3893 node.LocalNode= localLeaf;
3894 _Nodes.push_back(node);
3898 // --- Init the maps
3899 _ServerNodeMap.reserve(leaves.size());
3900 _LocalNodeMap.reserve(leaves.size());
3901 // For all valid _Nodes, insert in "map"
3902 for(i=0;i<_Nodes.size();i++)
3904 CNodeLocalComp lc;
3905 CNodeServerComp sc;
3906 lc.Node= &_Nodes[i];
3907 sc.Node= &_Nodes[i];
3908 _LocalNodeMap.push_back(lc);
3909 _ServerNodeMap.push_back(sc);
3911 // then sort
3912 sort(_LocalNodeMap.begin(), _LocalNodeMap.end());
3913 sort(_ServerNodeMap.begin(), _ServerNodeMap.end());
3919 // ------------------------------------------------------------------------------------------------
3920 void CInterfaceManager::CServerToLocalAutoCopy::onServerChange(ICDBNode *serverNode)
3922 if(_Nodes.empty())
3923 return;
3924 CCDBNodeLeaf *serverLeaf = safe_cast<CCDBNodeLeaf *>(serverNode);
3925 CInterfaceManager *pIM= CInterfaceManager::getInstance();
3927 // Add the leaf to the update list. only if not the counter
3928 if(serverLeaf != _ServerCounter)
3930 // build the map key
3931 CNode nodeComp;
3932 CNodeServerComp sc;
3933 nodeComp.ServerNode= serverLeaf;
3934 sc.Node= &nodeComp;
3935 // try to find the node associated to this server leaf
3936 uint index= searchLowerBound(_ServerNodeMap, sc);
3937 // if found
3938 if( index>0 || _ServerNodeMap[0].Node->ServerNode==serverLeaf )
3940 CNode *node= _ServerNodeMap[index].Node;
3941 // if this node is not already inserted
3942 if(!node->InsertedInUpdateList)
3944 // insert
3945 node->InsertedInUpdateList= true;
3946 _UpdateList.push_back(node);
3951 // if the client and server are synchonized.
3952 if( ClientCfg.Local || pIM->localActionCounterSynchronizedWith(_ServerCounter) )
3954 // update all leaves
3955 for(uint i=0;i<_UpdateList.size();i++)
3957 CNode *node= _UpdateList[i];
3959 _LocalUpdating= true;
3960 node->LocalNode->setValue64(node->ServerNode->getValue64());
3961 _LocalUpdating= false;
3963 // reset inserted flag
3964 node->InsertedInUpdateList= false;
3967 // clear update list
3968 _UpdateList.clear();
3972 // ------------------------------------------------------------------------------------------------
3973 void CInterfaceManager::CServerToLocalAutoCopy::onLocalChange(ICDBNode *localNode)
3975 if(_Nodes.empty())
3976 return;
3978 // if the local changes because of localLeaf->setValue64() in onServerChange(), no-op !!!
3979 if(_LocalUpdating)
3980 return;
3982 CCDBNodeLeaf *localLeaf = safe_cast<CCDBNodeLeaf *>(localNode);
3984 // Add the leaf to the update list
3985 // build the map key
3986 CNode nodeComp;
3987 CNodeLocalComp lc;
3988 nodeComp.LocalNode= localLeaf;
3989 lc.Node= &nodeComp;
3990 // try to find the node associated to this local leaf
3991 uint index= searchLowerBound(_LocalNodeMap, lc);
3992 // if found
3993 if( index>0 || _LocalNodeMap[0].Node->LocalNode==localLeaf )
3995 CNode *node= _LocalNodeMap[index].Node;
3996 // if this node is not already inserted
3997 if(!node->InsertedInUpdateList)
3999 // insert
4000 node->InsertedInUpdateList= true;
4001 _UpdateList.push_back(node);
4006 // ------------------------------------------------------------------------------------------------
4007 bool CInterfaceManager::use12hClock()
4009 CCDBNodeLeaf *node = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_CLOCK_12H", false);
4011 return (node && node->getValueBool());
4014 // ------------------------------------------------------------------------------------------------
4015 char* CInterfaceManager::getTimestampHuman(const char* format /* "[%H:%M:%S] " */)
4017 static char cstime[25];
4018 time_t date;
4019 time (&date);
4020 struct tm *tms = localtime(&date);
4021 if (tms)
4023 strftime(cstime, 25, format, tms);
4025 else
4027 strcpy(cstime, "");
4030 return cstime;
4035 * Parse tokens in a chatmessage or emote
4037 * Valid subjects:
4038 * $me$
4039 * $t$
4040 * $tt$
4041 * $tm1$..$tm8$
4043 * Valid parameters:
4044 * $<subject>.name$
4045 * $<subject>.title$
4046 * $<subject>.race$
4047 * $<subject>.guild$
4048 * $<subject>.gs(m/f/n)$
4050 * Default parameter if parameter result is empty:
4051 * $<subject>.<parameter>/<default>$
4053 * All \d's in default parameter remove a following character.
4055 bool CInterfaceManager::parseTokens(string& ucstr)
4057 string str = ucstr;
4058 string start_token("$");
4059 string end_token("$");
4060 size_t start_pos = 0;
4061 size_t end_pos = 1;
4063 sint endless_loop_protector = 0;
4064 while ((start_pos < str.length() - 1) &&
4065 ((start_pos = str.find(start_token, start_pos)) != string::npos))
4067 endless_loop_protector++;
4068 if (endless_loop_protector > 100)
4070 break;
4073 // Get the whole token substring first
4074 end_pos = str.find(end_token, start_pos + 1);
4076 if ((start_pos == string::npos) ||
4077 (end_pos == string::npos) ||
4078 (end_pos <= start_pos + 1))
4080 // Wrong formatting; give up on this one.
4081 start_pos = max(start_pos, end_pos);
4082 continue;
4085 // Get everything between the two "$"
4086 size_t token_start_pos = start_pos + start_token.length();
4087 size_t token_end_pos = end_pos - end_token.length();
4088 if (token_start_pos > token_end_pos)
4090 // Wrong formatting; give up on this one.
4091 start_pos = end_pos;
4092 continue;
4095 string token_whole = str.substr(start_pos, end_pos - start_pos + 1);
4096 string token_string = token_whole.substr(1, token_whole.length() - 2);
4097 string token_replacement = token_whole;
4098 string token_default = token_whole;
4100 string token_subject;
4101 string token_param;
4103 // Does the token have a parameter?
4104 // If not it is 'name' by default
4105 vector<string> token_vector;
4106 vector<string> param_vector;
4107 splitString(token_string, ".", token_vector);
4108 if (token_vector.empty())
4110 // Wrong formatting; give up on this one.
4111 start_pos = end_pos;
4112 continue;
4114 token_subject = token_vector[0];
4115 if (token_vector.size() == 1)
4117 splitString(token_subject, "/", param_vector);
4118 token_subject = !param_vector.empty() ? param_vector[0] : string();
4119 token_param = string("name");
4121 else if (token_vector.size() > 1)
4123 token_param = token_vector[1];
4124 if (token_param.substr(0, 3) != "gs(")
4126 splitString(token_vector[1], "/", param_vector);
4127 token_param = !param_vector.empty() ? param_vector[0] : string();
4131 // Get any default value, if not gs
4132 sint extra_replacement = 0;
4133 if (token_param.substr(0, 3) != "gs(")
4135 if (param_vector.size() == 2)
4137 // Set default value
4138 token_replacement = param_vector[1];
4139 // Delete following chars for every '\d' in default
4140 string::size_type token_replacement_pos;
4141 while ((token_replacement_pos = token_replacement.find(string("\\d"))) != string::npos)
4143 token_replacement.replace(token_replacement_pos, 2, string());
4144 extra_replacement++;
4146 token_default = token_replacement;
4150 CEntityCL *pTokenSubjectEntity = NULL;
4152 if (token_subject == "me")
4154 pTokenSubjectEntity = static_cast<CEntityCL*>(UserEntity);
4156 else if (token_subject == "t")
4158 // Target
4159 uint targetSlot = UserEntity->targetSlot();
4160 pTokenSubjectEntity = EntitiesMngr.entity(targetSlot);
4162 else if (token_subject == "tt")
4164 // Target's target
4165 uint targetSlot = UserEntity->targetSlot();
4166 CEntityCL *target = EntitiesMngr.entity(targetSlot);
4168 if (target)
4170 // Check the new slot.
4171 CLFECOMMON::TCLEntityId newSlot = target->targetSlot();
4172 CEntityCL* pE = EntitiesMngr.entity(newSlot);
4173 if (pE)
4175 pTokenSubjectEntity = pE;
4179 else if ((token_subject.length() == 3) &&
4180 (token_subject.substr(0, 2) == "tm"))
4182 // Teammate
4183 uint indexInTeam = 0;
4184 fromString(token_subject.substr(2, 1), indexInTeam);
4186 // Make 0-based
4187 --indexInTeam;
4188 if (indexInTeam < PeopleInterraction.TeamList.getNumPeople() )
4190 // Index is the database index (serverIndex() not used for team list)
4191 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp( NLMISC::toString(TEAM_DB_PATH ":%hu:NAME", indexInTeam ), false);
4192 if (pNL && pNL->getValueBool() )
4194 // There is a character corresponding to this index
4195 pNL = NLGUI::CDBManager::getInstance()->getDbProp( NLMISC::toString( TEAM_DB_PATH ":%hu:UID", indexInTeam ), false );
4196 if (pNL)
4198 CLFECOMMON::TClientDataSetIndex compressedIndex = pNL->getValue32();
4200 // Search entity in vision
4201 CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex( compressedIndex );
4202 if (entity)
4204 pTokenSubjectEntity = entity;
4210 else
4212 // Unknown token subject, skip it
4213 start_pos = end_pos;
4214 continue;
4217 if (pTokenSubjectEntity != NULL)
4219 // Parse the parameter
4220 if (token_param == "name")
4222 string name = pTokenSubjectEntity->getDisplayName();
4223 // special case where there is only a title, very rare case for some NPC
4224 if (name.empty())
4226 name = pTokenSubjectEntity->getTitle();
4228 token_replacement = name.empty() ? token_replacement : name;
4230 else if (token_param == "title")
4232 string title = pTokenSubjectEntity->getTitle();
4233 token_replacement = title.empty() ? token_replacement : title;
4235 else if (token_param == "race")
4237 CCharacterCL *pC = dynamic_cast<CCharacterCL*>(pTokenSubjectEntity);
4238 if (pC)
4240 EGSPD::CPeople::TPeople race = pC->people();
4241 if (race >= EGSPD::CPeople::Playable && race <= EGSPD::CPeople::EndPlayable)
4243 string srace = NLMISC::CI18N::get("io" + EGSPD::CPeople::toString(race));
4244 token_replacement = srace.empty() ? token_replacement : srace;
4248 else if (token_param == "guild")
4250 STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
4251 string ucGuildName;
4252 if (pSMC->getString(pTokenSubjectEntity->getGuildNameID(), ucGuildName))
4254 token_replacement = ucGuildName.empty() ? token_replacement : ucGuildName;
4257 else if (token_param.substr(0, 3) == "gs(" &&
4258 token_param.substr(token_param.length() - 1 , 1) == ")")
4260 // Gender string
4261 vector<string> strList;
4262 string gender_string = token_param.substr(3, token_param.length() - 4);
4263 splitString(gender_string, "/", strList);
4265 if (strList.size() <= 1)
4267 start_pos = end_pos;
4268 continue;
4271 // We only care about the gender if the subject is humanoid.
4272 GSGENDER::EGender gender = GSGENDER::neutral;
4273 if (pTokenSubjectEntity->isUser() || pTokenSubjectEntity->isPlayer() || pTokenSubjectEntity->isNPC())
4275 CCharacterCL *pC = dynamic_cast<CCharacterCL*>(pTokenSubjectEntity);
4276 if (pC)
4278 gender = pC->getGender();
4282 // The neuter part is optional. Fallback to male if something is wrong.
4283 GSGENDER::EGender g = ((uint)gender >= strList.size()) ? GSGENDER::male : gender;
4284 token_replacement = strList[g];
4288 if (token_whole == token_replacement)
4290 // Nothing to replace; show message and exit
4291 CInterfaceManager *im = CInterfaceManager::getInstance();
4292 string message = CI18N::get("uiUntranslatedToken");
4293 message.replace(message.find("%s"), 2, token_whole);
4294 im->displaySystemInfo(message);
4295 return false;
4298 // Replace token
4299 size_t token_whole_pos = str.find(token_whole);
4301 // Only do extra replacement spaces if using default
4302 extra_replacement = (token_replacement == token_default) ? extra_replacement : 0;
4303 if (str.find(token_whole, start_pos) != string::npos)
4305 str = str.replace(token_whole_pos, token_whole.length() + extra_replacement, token_replacement);
4306 start_pos = token_whole_pos + token_replacement.length();
4310 ucstr = str;
4311 return true;;
4314 std::string CInterfaceManager::getNextBackupName(std::string filename)
4316 std::string ts = getTimestampHuman("%Y-%m-%d");
4318 if (!ts.empty())
4320 std::string::size_type pos = filename.find_last_of('.');
4321 if (pos == std::string::npos)
4322 filename = filename + "_" + ts + "_";
4323 else
4324 filename = filename.substr(0, pos) + "_" + ts + "_" + filename.substr(pos);
4327 // filename_YYYY-MM-DD_000.ext
4328 return CFile::findNewFile(filename);
4331 void CInterfaceManager::createFileBackup(const std::string &message, const std::string &filename, bool useCopy)
4333 std::string backupName = getNextBackupName(filename);
4334 nlwarning("%s: '%s'.", message.c_str(), filename.c_str());
4335 if (!backupName.empty())
4337 if (useCopy)
4339 nlwarning("Backup copy saved as '%s'", backupName.c_str());
4340 CFile::copyFile(backupName, filename);
4342 else
4344 nlwarning("File renamed to '%s'", backupName.c_str());
4345 CFile::moveFile(backupName, filename);