1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2017 Winch Gate Property Limited
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>
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/>.
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"
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"
44 #include "nel/gui/interface_expr.h"
45 #include "register_interface_elements.h"
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"
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"
63 #include "nel/gui/ctrl_scroll.h"
64 #include "nel/gui/ctrl_button.h"
65 #include "nel/gui/ctrl_text_button.h"
67 #include "dbctrl_sheet.h"
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"
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
;
149 extern void luaDebuggerMainLoop();
152 extern CClientChatManager ChatMngr
;
153 extern CContinentManager ContinentMngr
;
154 extern bool IsInRingSession
;
155 extern CEventsListener EventsListener
;
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)
184 // ***************************************************************************
187 using namespace NLMISC
;
188 using namespace NLNET
;
190 // ------------------------------------------------------------------------------------------------
192 extern bool loginFinished
;
193 void setLoginFinished( bool f
);
195 CActionsManager EditActions
;
197 CInterfaceManager
* CInterfaceManager::_Instance
= NULL
;
199 CChatDisplayer
* ChatDisplayer
= NULL
;
203 void uninitActions();
205 ///\todo nico: remove this dummy displayer
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
)
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
);
237 setInterfaceGroupPtr::iterator it
= _DebugTrackGroupSet
.find( pIG
);
238 if( it
== _DebugTrackGroupSet
.end() )
240 nldebug( "AJM DEBUG: Interface Group %x Destroyed twice", pIG
);
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()
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() )
271 #endif // AJM_DEBUG_TRACK_INTERFACE_GROUPS
273 class CDesktopUpdater
: public CWidgetManager::INewScreenSizeHandler
276 void process( uint32 w
, uint32 h
)
278 CInterfaceManager::getInstance()->updateDesktops( w
, h
);
282 class CDrawDraggedSheet
: public CWidgetManager::IOnWidgetsDrawnHandler
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
327 std::string
formatString( const std::string
&inputString
, const std::string
¶mString
)
329 std::string formatedResult
;
332 for(std::string::const_iterator it
= inputString
.begin(); it
!= inputString
.end();)
337 if (it
== inputString
.end())
339 formatedResult
+= '$';
346 case 't': // add text ID
348 formatedResult
+= paramString
;
352 case 'p': // add player name
354 if (ClientCfg
.Local
|| !UserEntity
)
356 if (*it
== 'P') formatedResult
+= "PLAYER";
357 else formatedResult
+= "Player";
361 std::string name
= UserEntity
->getEntityName();
362 if (*it
== 'P') name
= toUpper(name
);
363 formatedResult
+= name
;
368 case 'b': // add bot name
371 bool womanTitle
= false;
378 CLFECOMMON::TCLEntityId trader
= CLFECOMMON::INVALID_SLOT
;
380 trader
= UserEntity
->trader();
381 if (trader
!= CLFECOMMON::INVALID_SLOT
)
383 CEntityCL
*entity
= EntitiesMngr
.entity(trader
);
386 uint32 nDBid
= entity
->getNameId();
389 STRING_MANAGER::CStringManagerClient
*pSMC
= STRING_MANAGER::CStringManagerClient::instance();
390 pSMC
->getString(nDBid
, botName
);
394 botName
= entity
->getDisplayName();
396 CCharacterCL
*pChar
= dynamic_cast<CCharacterCL
*>(entity
);
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' ...)
413 // But if there is no name, display only the title
415 botName
= sTitleTranslated
;
419 // Else we want the title !
420 if (!botName
.empty())
422 botName
+= sTitleTranslated
;
425 formatedResult
+= botName
;
430 formatedResult
+= '$';
439 formatedResult
+= *it
;
444 return formatedResult
;
450 CStringManagerTextProvider SMTextProvider
;
451 CRyzomTextFormatter RyzomTextFormatter
;
454 CInterfaceManager
* CInterfaceManager::getInstance()
456 if( _Instance
== NULL
)
457 _Instance
= new CInterfaceManager();
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;
509 CWidgetManager::getInstance()->resetColorProps();
510 CWidgetManager::getInstance()->resetAlphaRolloverSpeedProps();
511 CWidgetManager::getInstance()->resetGlobalAlphasProps();
512 _NeutralColor
= NULL
;
513 _WarningColor
= NULL
;
515 _EmotesInitialized
= false;
518 // Global initialization
519 // *********************
521 // Interface Manager init
522 CViewRenderer::getInstance()->checkNewScreenSize();
525 CViewRenderer::getInstance()->getScreenSize(w
, h
);
526 CWidgetManager::getInstance()->setScreenWH(w
, h
);
528 CViewRenderer::getInstance()->init();
531 _Modes
.resize(MAX_NUM_MODES
);
535 _LocalSyncActionCounter
= 0;
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;
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
;
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
)
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
));
633 pGC
->setActive(false);
636 // ------------------------------------------------------------------------------------------------
638 // ------------------------------------------------------------------------------------------------
639 void CInterfaceManager::destroy ()
645 void CInterfaceManager::initLUA()
647 CInterfaceParser
*parser
= dynamic_cast< CInterfaceParser
* >( CWidgetManager::getInstance()->getParser() );
648 if( parser
->isLuaInitialized() )
653 if( !parser
->isLuaInitialized() )
656 CLuaIHMRyzom::RegisterRyzomFunctions( *( CLuaManager::getInstance().getLuaState() ) );
659 // ------------------------------------------------------------------------------------------------
660 void CInterfaceManager::initLogin()
662 // Init LUA Scripting
665 // Clear the action manager
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");
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);
705 // ------------------------------------------------------------------------------------------------
706 void CInterfaceManager::uninitLogin()
708 CInterfaceParser
*parser
= dynamic_cast< CInterfaceParser
* >( CWidgetManager::getInstance()->getParser() );
710 CWidgetManager::getInstance()->activateMasterGroup ("ui:login", false);
715 CWidgetManager::getInstance()->setPointer( NULL
);
717 CInterfaceLink::removeAllLinks();
719 ICDBNode::CTextId
textId("UI");
720 NLGUI::CDBManager::getInstance()->getDB()->removeNode(textId
);
726 // Close LUA Scripting
730 // ------------------------------------------------------------------------------------------------
731 void CInterfaceManager::initOutGame()
733 // Clear the action manager
737 // Register action in the action manager
738 ActionsContext
.addActionsManager(&Actions
, "");
739 ActionsContext
.addActionsManager(&EditActions
, RZ_CATEGORY_EDIT
);
741 // Init LUA Scripting
744 if (ClientCfg
.SelectCharacter
!= -1)
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");
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())
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);
793 // Init the action manager
798 //NLMEMORY::CheckHeap (true);
800 // Initialize the web browser
802 CGroupHTML
*pGH
= dynamic_cast<CGroupHTML
*>( CWidgetManager::getInstance()->getElementFromId(GROUP_BROWSER
));
806 pGH
->setActive(true);
807 pGH
->browse(ClientCfg
.PatchletUrl
.c_str());
812 // ------------------------------------------------------------------------------------------------
813 void CInterfaceManager::uninitOutGame()
816 if (ClientCfg
.SelectCharacter
!= -1)
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 ();
842 //nlinfo ("%d seconds for removeAll", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
843 // initStart = ryzomGetLocalTime ();
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 ();
861 // nlinfo ("%d seconds for uninitActions", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
864 // Close LUA Scripting
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 ();
889 // ------------------------------------------------------------------------------------------------
890 void CInterfaceManager::initInGame()
892 setLoginFinished( true );
895 // Whole initInGame profile
896 NLMISC::TTime initStart
;
897 initStart
= ryzomGetLocalTime ();
899 // Init LUA Scripting
902 // Clear the action manager
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");
927 loadIngameInterfaceTextures();
929 // NLMEMORY::CheckHeap (true);
931 // Skill Manager Init
932 CSkillManager
*pSM
= CSkillManager::getInstance();
935 // SBrick Manager Init
936 CSBrickManager
*pSBM
= CSBrickManager::getInstance();
940 // SPhrase Manager DB Init (BEFORE loading). Must be init AFTER skill and brick init
941 CSPhraseManager
*pPM
= CSPhraseManager::getInstance();
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);
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
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();
995 CWidgetManager::getInstance()->updateAllLocalisedElements(); // To init all things
999 loadInterfaceConfig();
1001 //Load user landmarks
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
1022 // Init bubble manager
1023 InSceneBubbleManager
.init();
1025 // Init Memory Bar for phraseManager. DB and ctrl gray state
1026 pPM
->updateMemoryBar();
1029 _EmotesInitialized
= false;
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
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);
1061 _LogState
= (node
->getValue32() != 0);
1066 displaySystemInfo(CI18N::get("uiLogTurnedOn"));
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
));
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");
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");
1133 if (UserRoleInSession
!= R2::TUserRole::ur_editor
&& !sessionOwner
)
1135 eltEdit
->setY(buttonDeltaY
);
1136 eltEdit
->setActive(true);
1139 (safe_cast
<CCtrlTextButton
*>(eltCancel
))->setText(CI18N::get("uittQuitCancel"));
1143 eltEdit
->setY(0); // prevent from displaying a gap between two shown buttons
1144 eltEdit
->setActive(false);
1147 (safe_cast
<CCtrlTextButton
*>(eltCancel
))->setText(sessionOwner
? CI18N::get("uittQuitCancel") : CI18N::get("uittQuitCancelEditor"));
1152 if (IsInRingSession
|| (ClientCfg
.Local
&& ClientCfg
.R2EDEnabled
))
1154 // display "return to mainland", unless we are the scenario owner (player or 'aventure master')
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
1168 // when an owner of the session, there's an additionnal 'stop' button
1169 eltRet
->setActive(false);
1175 eltQuit
->setActive(false);
1179 eltQuitNow
->setY(buttonDeltaY
);
1180 eltQuitNow
->setActive(true); // show Quit (Now)
1187 eltRet
->setY(0); // prevent from displaying a gap between two shown buttons
1188 eltRet
->setActive(false);
1192 eltQuit
->setY(buttonDeltaY
);
1193 eltQuit
->setActive(true); // show Quit (with progress bar)
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
));
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
);
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
);
1231 ctb
->setWMin( biggestWidth
);
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
))
1261 // ------------------------------------------------------------------------------------------------
1262 void CInterfaceManager::loadKeys()
1264 if (ClientCfg
.R2EDEnabled
) // in R2ED mode the CEditor class deals with it
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
);
1290 // ------------------------------------------------------------------------------------------------
1291 void CInterfaceManager::loadInterfaceConfig()
1293 // Load interface.cfg
1294 if (ClientCfg
.R2EDEnabled
) // in R2ED mode the CEditor class deals with it
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
1311 _KeysLoaded
= false;
1314 // Autosave of the interface in interface.cfg
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();
1344 // release bubble manager
1345 InSceneBubbleManager
.release();
1347 // kill chat displayer
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();
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();
1410 ICDBNode::CTextId
textId("UI");
1411 NLGUI::CDBManager::getInstance()->getDB()->removeNode(textId
);
1413 // Uninit the action manager
1419 // uninit phrase mgr
1420 CSPhraseManager
*pPM
= CSPhraseManager::getInstance();
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();
1445 _NeutralColor
= NULL
;
1446 _WarningColor
= 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();
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
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();
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"));
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
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");
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"));
1577 // Update the clock in the compass if enabled.
1578 pVT
= dynamic_cast<CViewText
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:compass:clock:time"));
1581 if (pVT
->getActive())
1584 str
= getTimestampHuman("%I:%M %p");
1586 str
= getTimestampHuman("%H:%M");
1593 CWidgetManager::getInstance()->sendClockTickEvent();
1595 IngameDbMngr
.flushObserverCalls();
1596 NLGUI::CDBManager::getInstance()->flushObserverCalls();
1598 // Update SPhrase manager
1599 CSPhraseManager
*pPM
= CSPhraseManager::getInstance();
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();
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();
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();
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
1691 if (ClientCfg
.R2EDEnabled
)
1693 CWidgetManager::getInstance()->runProcedure ("proc_reset_r2ed_interface", NULL
, v
);
1697 CWidgetManager::getInstance()->runProcedure ("proc_reset_interface", NULL
, v
);
1700 // By default, consider the reset interface has been set with the current resolution
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
1713 sFileName
= NLMISC::CPath::lookup (filename
, false);
1714 if (sFileName
.empty() || !f
.open(sFileName
))
1718 // *** Load the config file
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)
1730 f
.serialCheck(NELID("_ICU"));
1731 if (!PeopleInterraction
.loadUserChatsInfos(f
))
1733 nlwarning("Bad user chat saving");
1738 f
.serialCheck(NELID("GFCI"));
1740 f
.serial(_CurrentMode
);
1741 if (_CurrentMode
> nNbMode
)
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
1766 if (!ms
.isReading()) ms
.invert();
1771 // HACK. if the version is <=2, then the CInterfaceConfig has no serialVersion. append here a 0
1774 uint8
*pBuffer
= ms
.bufferToFill(length
+1);
1776 f
.serialBuffer(pBuffer
+1, length
);
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
1792 f
.serial(uiDbSaveVersion
);
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);
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.
1813 CTaskBarManager
*pTBM
= CTaskBarManager::getInstance();
1817 // Load user landmarks
1818 nbLandmarks
= ContinentMngr
.serialUserLandMarks(f
);
1820 CCDBNodeLeaf
*pNL
= NLGUI::CDBManager::getInstance()->getDbProp( "SERVER:INTERFACES:NB_BONUS_LANDMARKS" );
1823 ICDBNode::CTextId textId
;
1824 pNL
->addObserver( &_LandmarkObs
, textId
);
1827 // Info Windows position.
1829 CInterfaceHelp::serialInfoWindows(f
);
1831 CInterfaceHelp::resetWindowPos(-100);
1833 // Macro On Memory Position
1834 CSPhraseManager
*pPM
= CSPhraseManager::getInstance();
1836 pPM
->serialMacroMemory(f
);
1839 CGroupInSceneBubbleManager::serialInSceneBubbleInfo(f
);
1843 if ( ! PeopleInterraction
.loadUserDynChatsInfos(f
))
1845 nlwarning("Bad user dyn chat saving");
1849 catch(const NLMISC::EStream
&)
1853 createFileBackup("Config loading failed", sFileName
);
1855 nlwarning("Config loading failed : restore default");
1857 if (!ClientCfg
.R2EDEnabled
)
1859 CWidgetManager::getInstance()->runProcedure ("proc_reset_interface", NULL
, v
);
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
1879 if (f
.open(lmfile
, false, false, true))
1882 xml
= "<?xml version=\"1.0\"?>\n<interface_config />";
1883 f
.serialBuffer((uint8
*)xml
.c_str(), xml
.size());
1889 // merge .icfg landmarks with landmarks.xml
1894 // *** If saved resolution is different from the current one setuped, must fix positions in _Modes
1895 if(lastInGameScreenResLoaded
)
1897 // Temporarily set screen to saved size so that positions are correctly calculated
1898 CWidgetManager::getInstance()->setScreenWH(_LastInGameScreenW
, _LastInGameScreenH
);
1899 // NB: we are typically InGame here (even though the _InGame flag is not yet set)
1900 // Use the screen size of the config file. Don't update current UI, just _Modes
1902 // ClientCfg has W/H set to screen size, but interface expects scaled size
1903 sint32 scaledW
= ClientCfg
.Width
/ ClientCfg
.InterfaceScale
;
1904 sint32 scaledH
= ClientCfg
.Height
/ ClientCfg
.InterfaceScale
;
1905 CWidgetManager::getInstance()->moveAllWindowsToNewScreenSize(scaledW
, scaledH
, false);
1906 updateDesktops(scaledW
, scaledH
);
1909 // *** apply the current mode
1910 _Modes
[_CurrentMode
].toCurrentDesktop();
1912 // *** Apply the NPC icon display mode
1913 CNPCIconCache::getInstance().init(!ClientCfg
.R2EDEnabled
&& NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:INSCENE:FRIEND:MISSION_ICON")->getValueBool());
1919 // ------------------------------------------------------------------------------------------------
1920 void CInterfaceManager::CDBLandmarkObs::update(ICDBNode
*node
)
1922 ContinentMngr
.updateUserLandMarks();
1926 // visitor to send onQuit msg on all element
1927 class CQuitVisitor
: public CInterfaceElementVisitor
1931 bool BadWindowFound
; //
1933 virtual void visit(CInterfaceElement
*elem
) { elem
->onQuit(); }
1934 virtual void visitGroup(CInterfaceGroup
*group
)
1936 if (!IsR2ED
) return;
1937 if (Desktop
!= 0) return;
1938 if (group
->getShortId() == "gestionsets")
1940 if (group
->getActive())
1942 BadWindowFound
= true;
1948 bool CInterfaceManager::saveLandmarks(bool verbose
) const
1952 if (!ClientCfg
.R2EDEnabled
)
1954 uint8 currMode
= getMode();
1956 string filename
= getSaveFileName("landmarks", "xml");
1957 if (verbose
) CInterfaceManager::getInstance()->displaySystemInfo("Saving " + filename
);
1958 ret
= saveLandmarks(filename
);
1964 bool CInterfaceManager::loadLandmarks()
1966 // Does the keys file exist ?
1967 string filename
= getSaveFileName("landmarks", "xml");
1971 sFileName
= NLMISC::CPath::lookup (filename
, false);
1972 if (sFileName
.empty() || !f
.open(sFileName
))
1976 vector
<string
> xmlFilesToParse
;
1977 xmlFilesToParse
.push_back (filename
);
1979 //ContinentMngr.serialUserLandMarks(node);
1980 if (!parseInterface (xmlFilesToParse
, true))
1984 createFileBackup("Error while loading landmarks", filename
);
1992 bool CInterfaceManager::saveLandmarks(const std::string
&filename
) const
1994 nlinfo( "Saving landmarks : %s", filename
.c_str() );
2001 // using temporary file, so no f.close() unless its a success
2002 if (f
.open(filename
, false, false, true))
2005 xmlStream
.init (&f
);
2007 xmlDocPtr doc
= xmlStream
.getDocument ();
2008 xmlNodePtr node
= xmlNewDocNode(doc
, NULL
, (const xmlChar
*)"interface_config", NULL
);
2009 xmlDocSetRootElement (doc
, node
);
2011 ContinentMngr
.writeTo(node
);
2022 catch (const Exception
&e
)
2024 nlwarning ("Error while writing the file %s : %s.", filename
.c_str(), e
.what ());
2030 // ------------------------------------------------------------------------------------------------
2032 bool CInterfaceManager::saveConfig (bool verbose
)
2036 if (!ClientCfg
.R2EDEnabled
)
2038 uint8 currMode
= getMode();
2040 string filename
= getSaveFileName("interface", "icfg");
2042 if (verbose
) CInterfaceManager::getInstance()->displaySystemInfo("Saving " + filename
);
2043 ret
= saveConfig(filename
);
2045 if (currMode
!= getMode())
2052 // ------------------------------------------------------------------------------------------------
2053 bool CInterfaceManager::saveConfig (const string
&filename
)
2056 CQuitVisitor quitVisitor
;
2058 quitVisitor
.IsR2ED
= false;
2059 if (nlstricmp(NLMISC::CFile::getFilename(filename
).substr(0, 5), "r2ed_") == 0)
2061 quitVisitor
.IsR2ED
= true;
2063 quitVisitor
.BadWindowFound
= false;
2065 nlinfo( "Saving interface config : %s", filename
.c_str() );
2069 // using temporary file, so no f.close() unless its a success
2070 if (!f
.open(filename
, false, false, true)) return false;
2072 CInterfaceConfig ic
;
2076 // cleanup all desktops
2077 for(uint k
= 0; k
< _Modes
.size(); ++k
)
2079 quitVisitor
.Desktop
= k
;
2081 visit(&quitVisitor
);
2082 CWidgetManager::getInstance()->checkCoords();
2085 setMode(_CurrentMode
);
2087 if (quitVisitor
.BadWindowFound
)
2092 // tmp patch : when trying to overwrite the r2ed_ config, if a bad window is found, just do nothing ...
2097 _Modes[_CurrentMode].clear();
2098 if (_Modes[_CurrentMode].isReading()) _Modes[_CurrentMode].invert();
2100 restoreAllContainersBackupPosition();
2101 ic.interfaceManagerToStream(_Modes[_CurrentMode]);
2109 f
.serialVersion(ICFG_STREAM_VERSION
);
2111 // serial user chats info (serial it before position of windows so that they can be updated properly)
2112 f
.serialCheck(NELID("_ICU"));
2113 if (!PeopleInterraction
.saveUserChatsInfos(f
))
2115 nlwarning("Config saving failed");
2116 // couldn't save result so do not continue
2121 f
.serialCheck(NELID("GFCI"));
2123 f
.serial(_CurrentMode
);
2124 f
.serial(_LastInGameScreenW
);
2125 f
.serial(_LastInGameScreenH
);
2127 // Save All Window configuration of all Modes
2128 for (i
= 0; i
< _Modes
.size(); ++i
)
2130 // must create a tmp mem stream because desktop image expect its datas to occupy the whole stream
2131 // This is because of old system that manipulated desktop image direclty as a mem stream
2133 if (ms
.isReading()) ms
.invert();
2134 _Modes
[i
].serial(ms
);
2135 uint32 length
= ms
.length();
2139 f
.serialBuffer(const_cast<uint8
*>(ms
.buffer()), length
);
2143 // write UI_DB_SAVE_VERSION
2144 uint32 uiDbSaveVersion
;
2145 fromString( CWidgetManager::getInstance()->getParser()->getDefine("UI_DB_SAVE_VERSION"), uiDbSaveVersion
);
2146 f
.serial(uiDbSaveVersion
);
2149 ic
.dataBaseToStream(f
);
2151 // Deprecated. for Compatibility purpose: Save TaskBar.
2152 CTaskBarManager
*pTBM
= CTaskBarManager::getInstance();
2155 //ContinentMngr.serialUserLandMarks(f);
2156 // empty landmarks block for compatibility
2163 // Info Windows position.
2164 CInterfaceHelp::serialInfoWindows(f
);
2166 // Macro On Memory Position
2167 CSPhraseManager
*pPM
= CSPhraseManager::getInstance();
2168 pPM
->serialMacroMemory(f
);
2170 CGroupInSceneBubbleManager::serialInSceneBubbleInfo(f
);
2172 if ( ! PeopleInterraction
.saveUserDynChatsInfos(f
))
2174 nlwarning("Bad user dyn chat saving");
2180 catch(const NLMISC::EStream
&)
2182 nlwarning("Config saving failed.");
2186 ContinentMngr
.serialFOWMaps();
2191 // ------------------------------------------------------------------------------------------------
2192 void CInterfaceManager::drawViews(NL3D::UCamera camera
)
2194 IngameDbMngr
.flushObserverCalls();
2195 NLGUI::CDBManager::getInstance()->flushObserverCalls();
2197 // Update Player characteristics (for Item carac requirement Redifying)
2198 nlctassert(CHARACTERISTICS::NUM_CHARACTERISTICS
==8);
2199 for (uint i
=0; i
<CHARACTERISTICS::NUM_CHARACTERISTICS
; ++i
)
2201 if (!_CurrentPlayerCharacLeaf
[i
])
2202 _CurrentPlayerCharacLeaf
[i
] = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:CHARACTER_INFO:CHARACTERISTICS%d:VALUE", i
), false);
2204 NLMISC::CCDBNodeLeaf
*node
= NULL
;
2206 if (_CurrentPlayerCharacLeaf
[i
])
2207 node
= &*_CurrentPlayerCharacLeaf
[i
];
2209 _CurrentPlayerCharac
[i
] = node
? node
->getValue32() : 0;
2212 // scale must be updated right before widget manager checks it
2213 if (_InterfaceScaleChanged
)
2215 CViewRenderer::getInstance()->setInterfaceScale(_InterfaceScale
);
2216 _InterfaceScaleChanged
= false;
2219 CWidgetManager::getInstance()->drawViews( camera
);
2222 IngameDbMngr
.flushObserverCalls();
2226 // ------------------------------------------------------------------------------------------------
2227 bool CInterfaceManager::handleEvent (const NLGUI::CEventDescriptor
& event
)
2229 bool handled
= false;
2231 handled
= CWidgetManager::getInstance()->handleEvent( event
);
2233 if( event
.getType() == NLGUI::CEventDescriptor::mouse
)
2235 NLGUI::CEventDescriptorMouse
&eventDesc
= (NLGUI::CEventDescriptorMouse
&)event
;
2237 if( ( eventDesc
.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightup
) && handled
)
2239 // prevent 'click in scene' as mouse was previously captured
2240 // (more a patch that anything, but 'UserControls' test for 'mouse up'
2241 // directly later in the main loop (not through message queue), so it has no way of knowing that the event was handled...
2242 if( CWidgetManager::getInstance()->getCapturePointerRight() == NULL
)
2243 EventsListener
.addUIHandledButtonMask(rightButton
);
2245 if( ( eventDesc
.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup
) && handled
)
2247 // prevent 'click in scene' as mouse was previously captured
2248 // (more a patch that anything, but 'UserControls' test for 'mouse up'
2249 // directly later in the main loop (not through message queue), so it has no way of knowing that the event was handled...
2250 if( CWidgetManager::getInstance()->getCapturePointerLeft() == NULL
)
2251 EventsListener
.addUIHandledButtonMask(leftButton
);
2256 IngameDbMngr
.flushObserverCalls();
2261 void CInterfaceManager::updateDesktops( uint32 newScreenW
, uint32 newScreenH
)
2263 // *** Do it for All Backuped Desktops
2264 for(uint md
=0; md
<_Modes
.size(); md
++)
2266 CInterfaceConfig::CDesktopImage
&mode
= _Modes
[md
];
2267 // For all containers of this mode
2268 for(uint gc
=0;gc
<mode
.GCImages
.size();gc
++)
2270 CInterfaceConfig::SCont
&gcCont
= mode
.GCImages
[gc
];
2271 // Compute the new coordinate, directly in the X/Y fields of the structure
2272 CWidgetManager::getInstance()->getNewWindowCoordToNewScreenSize(gcCont
.X
, gcCont
.Y
, gcCont
.W
, gcCont
.H
,newScreenW
, newScreenH
);
2276 _LastInGameScreenW
= newScreenW
;
2277 _LastInGameScreenH
= newScreenH
;
2280 class InvalidateTextVisitor
: public CInterfaceElementVisitor
2283 InvalidateTextVisitor( bool reset
)
2285 this->reset
= reset
;
2288 void visitGroup( CInterfaceGroup
*group
)
2290 const std::vector
< CViewBase
* > &vs
= group
->getViews();
2291 for( std::vector
< CViewBase
* >::const_iterator itr
= vs
.begin(); itr
!= vs
.end(); ++itr
)
2293 CViewText
*vt
= dynamic_cast< CViewText
* >( *itr
);
2297 vt
->resetTextIndex();
2298 vt
->updateTextContext();
2308 // ------------------------------------------------------------------------------------------------
2309 void CInterfaceManager::addServerString (const std::string
&sTarget
, uint32 id
, IStringProcess
*cb
)
2313 CInterfaceExprValue val
;
2314 val
.setString (std::string());
2315 CInterfaceLink::setTargetProperty (sTarget
, val
);
2318 SIDStringWaiter
*pISW
= new SIDStringWaiter
;
2320 pISW
->IdOrString
= false;
2321 pISW
->Target
= sTarget
;
2323 _IDStringWaiters
.push_back(pISW
);
2326 // ------------------------------------------------------------------------------------------------
2327 void CInterfaceManager::addServerID (const std::string
&sTarget
, uint32 id
, IStringProcess
*cb
)
2331 CInterfaceExprValue val
;
2332 val
.setString (std::string());
2333 CInterfaceLink::setTargetProperty (sTarget
, val
);
2336 SIDStringWaiter
*pISW
= new SIDStringWaiter
;
2338 pISW
->IdOrString
= true;
2339 pISW
->Target
= sTarget
;
2341 _IDStringWaiters
.push_back(pISW
);
2344 // ------------------------------------------------------------------------------------------------
2345 void CInterfaceManager::processServerIDString()
2347 STRING_MANAGER::CStringManagerClient
*pSMC
= STRING_MANAGER::CStringManagerClient::instance();
2349 for (uint32 i
= 0; i
< _IDStringWaiters
.size(); ++i
)
2351 bool bAffect
= false;
2352 string ucstrToAffect
;
2353 SIDStringWaiter
*pISW
= _IDStringWaiters
[i
];
2354 if (pISW
->IdOrString
== true) // ID !
2356 if (pSMC
->getString (pISW
->Id
, ucstrToAffect
))
2361 if (pSMC
->getDynString (pISW
->Id
, ucstrToAffect
))
2367 CInterfaceExprValue val
;
2370 if (pISW
->Cb
!= NULL
)
2372 bValid
= pISW
->Cb
->cbIDStringReceived(ucstrToAffect
);
2378 ucstrToAffect
= STRING_MANAGER::CStringManagerClient::getLocalizedName(ucstrToAffect
);
2379 val
.setString (ucstrToAffect
);
2380 CInterfaceLink::setTargetProperty (pISW
->Target
, val
);
2384 _IDStringWaiters
.erase (_IDStringWaiters
.begin()+i
);
2391 // ------------------------------------------------------------------------------------------------
2392 void CInterfaceManager::messageBoxInternal(const string
&msgBoxGroup
, const string
&text
, const string
&masterGroup
, TCaseMode caseMode
)
2394 CInterfaceGroup
*group
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(masterGroup
+":" + msgBoxGroup
));
2395 CViewText
*viewText
= dynamic_cast<CViewText
*>(CWidgetManager::getInstance()->getElementFromId(masterGroup
+":" + msgBoxGroup
+ ":text"));
2397 if (group
&& viewText
)
2399 viewText
->setCaseMode(caseMode
);
2400 viewText
->setText(text
);
2401 CWidgetManager::getInstance()->enableModalWindow(NULL
, group
);
2402 // don't understand why but need to update coords here
2403 group
->updateCoords();
2404 group
->updateCoords();
2408 // ------------------------------------------------------------------------------------------------
2409 void CInterfaceManager::messageBox(const string
&text
, const string
&masterGroup
, TCaseMode caseMode
)
2411 messageBoxInternal("message_box", text
, masterGroup
, caseMode
);
2415 // ------------------------------------------------------------------------------------------------
2416 void CInterfaceManager::messageBoxWithHelp(const std::string
&text
, const std::string
&masterGroup
,
2417 const std::string
&ahOnOk
, const std::string
¶msOnOk
,
2420 // replace the procedure "proc_valid_message_box_ok" action
2421 CWidgetManager::getInstance()->setProcedureAction("proc_message_box_with_help_ok", 1, ahOnOk
, paramsOnOk
);
2422 const char *mbName
= "message_box_with_help";
2423 // if no action handler is wanted, then assume that
2424 // clicking 'ok' do not have any consequence, so allow exiting the message box by clicking
2425 // outside of it (this behavior is wanted on the login page, to allow to reclick on 'login' without
2426 // having to click 'ok' in the message box each time)
2427 CInterfaceGroup
*group
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(masterGroup
+":" + mbName
));
2428 CGroupModal
*gm
= dynamic_cast<CGroupModal
*>(group
);
2431 gm
->ExitClickOut
= ahOnOk
.empty();
2433 messageBoxInternal(mbName
, text
, masterGroup
, caseMode
);
2437 // ------------------------------------------------------------------------------------------------
2438 void CInterfaceManager::validMessageBox(TValidMessageIcon icon
, const std::string
&text
, const std::string
&ahOnOk
,
2439 const std::string
¶msOnOk
, const std::string
&ahOnCancel
, const std::string
¶msOnCancel
, const string
&masterGroup
)
2441 CInterfaceGroup
*group
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(masterGroup
+":valid_message_box"));
2442 CViewText
*viewText
= dynamic_cast<CViewText
*>(CWidgetManager::getInstance()->getElementFromId(masterGroup
+":valid_message_box:text"));
2443 CViewBitmap
*viewBitmap
= dynamic_cast<CViewBitmap
*>(CWidgetManager::getInstance()->getElementFromId(masterGroup
+":valid_message_box:icon_group:icon"));
2445 if (group
&& viewText
)
2447 // replace the procedure "proc_valid_message_box_ok" action
2448 CWidgetManager::getInstance()->setProcedureAction("proc_valid_message_box_ok", 1, ahOnOk
, paramsOnOk
);
2449 // replace the procedure "proc_valid_message_box_cancel" action
2450 CWidgetManager::getInstance()->setProcedureAction("proc_valid_message_box_cancel", 1, ahOnCancel
, paramsOnCancel
);
2452 // set text and icon
2453 viewText
->setText(text
);
2457 if(icon
==QuestionIconMsg
)
2458 viewBitmap
->setTexture("brick_default.tga");
2459 else if(icon
==WarningIconMsg
)
2460 viewBitmap
->setTexture("W_warning.tga");
2461 else if(icon
==ErrorIconMsg
)
2462 viewBitmap
->setTexture("No_Action.tga");
2465 viewBitmap
->setActive(active
);
2469 CWidgetManager::getInstance()->enableModalWindow(NULL
, group
);
2470 // don't understand why but need to update coords here
2471 group
->updateCoords();
2472 group
->updateCoords();
2477 // ------------------------------------------------------------------------------------------------
2478 bool CInterfaceManager::getCurrentValidMessageBoxOnOk(string
&ahOnOk
, const std::string
&masterGroup
)
2480 // any modal window opened?
2481 CInterfaceGroup
*mw
= CWidgetManager::getInstance()->getModalWindow();
2485 // Is this modal window the valid_message_box window?
2486 CInterfaceGroup
*group
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(masterGroup
+":valid_message_box"));
2489 // Ok, get the current procedure OnOk action
2491 if( CWidgetManager::getInstance()->getParser()->getProcedureAction("proc_valid_message_box_ok", 1, ahOnOk
, dummyParams
))
2499 // ***************************************************************************
2500 void CInterfaceManager::displayDebugInfo(const string
&str
, TSystemInfoMode mode
/*=InfoMsg*/)
2502 if (PeopleInterraction
.DebugInfo
)
2503 PeopleInterraction
.ChatInput
.DebugInfo
.displayMessage(str
, getDebugInfoColor(mode
), 2);
2506 // ***************************************************************************
2507 NLMISC::CRGBA
CInterfaceManager::getDebugInfoColor(TSystemInfoMode mode
)
2509 if (_NeutralColor
== NULL
) // not initialised ?
2511 #define SYSTEM_INFO_COLOR_DB_PATH "UI:VARIABLES:SYSTEM_INFOS:COLORS"
2512 _NeutralColor
= NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH
":NEUTRAL");
2513 _WarningColor
= NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH
":WARNING");
2514 _ErrorColor
= NLGUI::CDBManager::getInstance()->getDbProp(SYSTEM_INFO_COLOR_DB_PATH
":ERROR");
2516 NLMISC::CRGBA color
;
2519 case InfoMsg
: color
.setPacked(_NeutralColor
->getValue32()); break;
2520 case WarningMsg
: color
.setPacked(_WarningColor
->getValue32()); break;
2521 case ErrorMsg
: color
.setPacked(_ErrorColor
->getValue32()); break;
2523 color
= CRGBA::White
;
2529 // ***************************************************************************
2530 void CInterfaceManager::displaySystemInfo(const string
&str
, const string
&cat
)
2532 CClientConfig::SSysInfoParam::TMode mode
= CClientConfig::SSysInfoParam::Normal
;
2533 CRGBA color
= CRGBA::White
;
2536 map
<string
, CClientConfig::SSysInfoParam
>::const_iterator it
= ClientCfg
.SystemInfoParams
.find(toLowerAscii(cat
));
2537 if (it
!= ClientCfg
.SystemInfoParams
.end())
2539 mode
= it
->second
.Mode
;
2540 color
= it
->second
.Color
;
2543 if (mode
!= CClientConfig::SSysInfoParam::OverOnly
&& mode
!= CClientConfig::SSysInfoParam::Around
)
2545 if (PeopleInterraction
.SystemInfo
)
2546 PeopleInterraction
.ChatInput
.SystemInfo
.displayMessage(str
, color
, 2);
2549 CPeopleInterraction::CSysMsg sysMsg
;
2552 PeopleInterraction
.SystemMessageBuffer
.push_back( sysMsg
);
2556 if (mode
== CClientConfig::SSysInfoParam::Center
|| mode
== CClientConfig::SSysInfoParam::CenterAround
)
2557 InSceneBubbleManager
.addMessagePopupCenter(str
, color
);
2559 // If over popup a string at the bottom of the screen
2560 if ((mode
== CClientConfig::SSysInfoParam::Over
) || (mode
== CClientConfig::SSysInfoParam::OverOnly
))
2561 InSceneBubbleManager
.addMessagePopup(str
, color
);
2562 else if ( (mode
== CClientConfig::SSysInfoParam::Around
|| mode
== CClientConfig::SSysInfoParam::CenterAround
)
2563 && PeopleInterraction
.AroundMe
.Window
)
2564 PeopleInterraction
.ChatInput
.AroundMe
.displayMessage(str
, color
, 2);
2567 // ***************************************************************************
2568 CRGBA
CInterfaceManager::getSystemInfoColor(const std::string
&cat
)
2570 CRGBA col
= CRGBA::White
;
2571 map
<string
, CClientConfig::SSysInfoParam
>::const_iterator it
= ClientCfg
.SystemInfoParams
.find(toLowerAscii(cat
));
2572 if (it
!= ClientCfg
.SystemInfoParams
.end())
2573 col
= it
->second
.Color
;
2577 // ***************************************************************************
2578 void CInterfaceManager::launchContextMenuInGame (const std::string
&nameOfCM
)
2580 // Launch the context menu in-game: can't appear while dragging an item
2581 if (CCtrlDraggable::getDraggedSheet() == NULL
)
2583 if ( !CWidgetManager::getInstance()->hasModal() )
2585 // We must be in-game !
2586 CInterfaceGroup
*pMG
= CWidgetManager::getInstance()->getMasterGroupFromId("ui:interface");
2587 // TMP nico : try with login screen:
2590 pMG
= CWidgetManager::getInstance()->getMasterGroupFromId("ui:login");
2594 pMG
= CWidgetManager::getInstance()->getMasterGroupFromId("ui:outgame");
2596 if ((pMG
!= NULL
) && (pMG
->getActive()))
2598 CInterfaceElement
*pIE
= CWidgetManager::getInstance()->getElementFromId(nameOfCM
);
2599 CInterfaceGroup
*pIG
= dynamic_cast<CInterfaceGroup
*>(pIE
);
2602 CWidgetManager::getInstance()->enableModalWindow (NULL
, pIG
);
2610 // ***************************************************************************
2611 void CInterfaceManager::updateGroupContainerImage(CGroupContainer
&gc
, uint8 mode
)
2613 if (mode
>= _Modes
.size())
2615 nlwarning("wrong desktop");
2618 _Modes
[mode
].updateGroupContainerImage(gc
);
2621 // ***************************************************************************
2622 void CInterfaceManager::removeGroupContainerImage(const std::string
&groupName
, uint8 mode
)
2624 if (mode
>= _Modes
.size())
2626 nlwarning("wrong desktop");
2629 _Modes
[mode
].removeGroupContainerImage(groupName
);
2633 // ***************************************************************************
2634 void CInterfaceManager::removeGroupContainerImageFromDesktops(const std::string
&groupName
)
2636 for (uint i
= 0; i
< _Modes
.size(); i
++)
2638 _Modes
[i
].removeGroupContainerImage(groupName
);
2642 // ***************************************************************************
2643 void CInterfaceManager::setMode(uint8 newMode
)
2645 if (newMode
>= _Modes
.size())
2648 if (newMode
== _CurrentMode
)
2651 std::vector
< CWidgetManager::SMasterGroup
> &_MasterGroups
= CWidgetManager::getInstance()->getAllMasterGroup();
2653 // Check if we can change vdesk !
2654 for (uint32 nMasterGroup
= 0; nMasterGroup
< _MasterGroups
.size(); nMasterGroup
++)
2656 CWidgetManager::SMasterGroup
&rMG
= _MasterGroups
[nMasterGroup
];
2657 if (rMG
.Group
->getActive())
2659 for (uint8 nPriority
=0; nPriority
< WIN_PRIORITY_MAX
; ++nPriority
)
2661 list
<CInterfaceGroup
*> &rList
= rMG
.PrioritizedWindows
[nPriority
];
2662 list
<CInterfaceGroup
*>::const_iterator itw
;
2663 for (itw
= rList
.begin(); itw
!= rList
.end(); itw
++)
2665 CGroupContainer
*pGC
= dynamic_cast<CGroupContainer
*>(*itw
);
2666 if ((pGC
!= NULL
)&&(pGC
->getActive()))
2668 // if this GC is a Full modal window, or if it is a modal son of another GC,
2669 if (pGC
->isModal() || pGC
->isModalSon())
2671 CWidgetManager::getInstance()->setTopWindow(pGC
);
2672 pGC
->enableBlink(2);
2676 if (pGC
->isGrayed())
2678 // Make the corresponding child blink
2679 pGC
->blinkAllSons();
2688 // check if there's a special behaviour with current captured ctrl that prevent from changing desktop
2689 if ( CWidgetManager::getInstance()->getCapturePointerLeft() != NULL
)
2691 if (!CWidgetManager::getInstance()->getCapturePointerLeft()->canChangeVirtualDesktop()) return;
2693 if ( CWidgetManager::getInstance()->getCapturePointerRight() != NULL
)
2695 if (!CWidgetManager::getInstance()->getCapturePointerRight()->canChangeVirtualDesktop()) return;
2699 _Modes
[_CurrentMode
].fromCurrentDesktop();
2700 _Modes
[newMode
].toCurrentDesktop();
2701 //CBotChatUI::refreshActiveWindows();
2703 _CurrentMode
= newMode
;
2704 CWidgetManager::getInstance()->checkCoords();
2707 // ***************************************************************************
2708 void CInterfaceManager::resetMode(uint8 newMode
)
2710 if (newMode
>= _Modes
.size())
2712 NLMISC::contReset(_Modes
[newMode
]);
2716 // for dump of interface content
2719 CInterfaceGroup
*Group
;
2720 uint Depth
; // depth in the tree
2723 // ***************************************************************************
2724 void CInterfaceManager::dumpUI(bool /* indent */)
2726 std::vector
< CWidgetManager::SMasterGroup
> &_MasterGroups
= CWidgetManager::getInstance()->getAllMasterGroup();
2727 std::vector
<CDumpedGroup
> left
;
2728 left
.resize(_MasterGroups
.size());
2729 for (uint32 nMasterGroup
= 0; nMasterGroup
< _MasterGroups
.size(); nMasterGroup
++)
2731 left
[nMasterGroup
].Group
= _MasterGroups
[nMasterGroup
].Group
;
2732 left
[nMasterGroup
].Depth
= 0;
2735 while (!left
.empty())
2737 CInterfaceGroup
*ig
= left
.back().Group
;
2740 uint currDepth
= left
.back().Depth
;
2741 std::string id
= ig
->getId();
2742 std::string::size_type pos
= id
.find_last_of(':');
2743 if (pos
!= std::string::npos
)
2745 id
= id
.substr(pos
+ 1);
2747 std::string
info(currDepth
* 4, ' ');
2749 info
+= toString(", address=0x%p", ig
);
2750 nlinfo(info
.c_str());
2751 // dump view & controls for this group
2752 for(uint k
= 0; k
< ig
->getViews().size(); ++k
)
2754 std::string
info(currDepth
* 4, ' ');
2755 info
+= toString("View %d / %d : ", (int) k
+ 1, (int) ig
->getViews().size());
2756 if (ig
->getViews()[k
])
2759 NLGUI::CViewBase
*view
= ig
->getViews()[k
];
2760 info
+= toString(", type = %s, address=0x%p", typeid(*view
).name(), view
);
2766 nlinfo(info
.c_str());
2769 for(uint k
= 0; k
< ig
->getControls().size(); ++k
)
2771 std::string
info(currDepth
* 4, ' ');
2772 info
+= toString("Ctrl %d / %d : ", (int) k
+ 1, (int) ig
->getControls().size());
2773 if (ig
->getControls()[k
])
2776 NLGUI::CCtrlBase
*control
= ig
->getControls()[k
];
2777 info
+= toString(", type = %s, address=0x%p", typeid(*control
).name(), control
);
2783 nlinfo(info
.c_str());
2789 for(uint k
= 0; k
< ig
->getNumGroup(); ++k
)
2792 dg
.Group
= ig
->getGroup(k
);
2793 dg
.Depth
= currDepth
+ 1;
2800 // ***************************************************************************
2801 void CInterfaceManager::displayUIViewBBoxs(const std::string
&uiFilter
)
2803 std::vector
< CWidgetManager::SMasterGroup
> &_MasterGroups
= CWidgetManager::getInstance()->getAllMasterGroup();
2804 for (uint32 nMasterGroup
= 0; nMasterGroup
< _MasterGroups
.size(); nMasterGroup
++)
2806 CWidgetManager::SMasterGroup
&rMG
= _MasterGroups
[nMasterGroup
];
2807 for (uint8 nPriority
=0; nPriority
< WIN_PRIORITY_MAX
; ++nPriority
)
2809 list
<CInterfaceGroup
*> &rList
= rMG
.PrioritizedWindows
[nPriority
];
2810 list
<CInterfaceGroup
*>::iterator it
;
2811 for(it
= rList
.begin(); it
!= rList
.end(); ++it
)
2813 if (*it
) (*it
)->renderWiredQuads(CInterfaceElement::RenderView
, uiFilter
);
2819 // ***************************************************************************
2820 void CInterfaceManager::displayUICtrlBBoxs(const std::string
&uiFilter
)
2822 std::vector
< CWidgetManager::SMasterGroup
> &_MasterGroups
= CWidgetManager::getInstance()->getAllMasterGroup();
2823 for (uint32 nMasterGroup
= 0; nMasterGroup
< _MasterGroups
.size(); nMasterGroup
++)
2825 CWidgetManager::SMasterGroup
&rMG
= _MasterGroups
[nMasterGroup
];
2826 for (uint8 nPriority
=0; nPriority
< WIN_PRIORITY_MAX
; ++nPriority
)
2828 list
<CInterfaceGroup
*> &rList
= rMG
.PrioritizedWindows
[nPriority
];
2829 list
<CInterfaceGroup
*>::iterator it
;
2830 for(it
= rList
.begin(); it
!= rList
.end(); ++it
)
2832 if (*it
) (*it
)->renderWiredQuads(CInterfaceElement::RenderCtrl
, uiFilter
);
2838 // ***************************************************************************
2839 void CInterfaceManager::displayUIGroupBBoxs(const std::string
&uiFilter
)
2841 std::vector
< CWidgetManager::SMasterGroup
> &_MasterGroups
= CWidgetManager::getInstance()->getAllMasterGroup();
2842 for (uint32 nMasterGroup
= 0; nMasterGroup
< _MasterGroups
.size(); nMasterGroup
++)
2844 CWidgetManager::SMasterGroup
&rMG
= _MasterGroups
[nMasterGroup
];
2845 for (uint8 nPriority
=0; nPriority
< WIN_PRIORITY_MAX
; ++nPriority
)
2847 list
<CInterfaceGroup
*> &rList
= rMG
.PrioritizedWindows
[nPriority
];
2848 list
<CInterfaceGroup
*>::iterator it
;
2849 for(it
= rList
.begin(); it
!= rList
.end(); ++it
)
2851 if (*it
) (*it
)->renderWiredQuads(CInterfaceElement::RenderGroup
, uiFilter
);
2857 // ***************************************************************************
2858 void writeComboActionMap (const CActionsManager
&actions
, xmlNodePtr node
, const string
&context
)
2860 // Get the combo defined
2861 const CActionsManager::TComboActionMap
&combos
= actions
.getComboActionMap ();
2862 CActionsManager::TComboActionMap::const_iterator ite
= combos
.begin ();
2863 while (ite
!= combos
.end ())
2866 xmlNodePtr keyNode
= xmlNewChild ( node
, NULL
, (const xmlChar
*)"key", NULL
);
2869 xmlSetProp (keyNode
, (const xmlChar
*)"name", (const xmlChar
*)CEventKey::getStringFromKey(ite
->first
.Key
).c_str());
2871 if (ite
->first
.KeyButtons
&shiftKeyButton
)
2872 xmlSetProp (keyNode
, (const xmlChar
*)"shift", (const xmlChar
*)"1");
2873 if (ite
->first
.KeyButtons
&ctrlKeyButton
)
2874 xmlSetProp (keyNode
, (const xmlChar
*)"ctrl", (const xmlChar
*)"1");
2875 if (ite
->first
.KeyButtons
&altKeyButton
)
2876 xmlSetProp (keyNode
, (const xmlChar
*)"menu", (const xmlChar
*)"1");
2878 xmlSetProp (keyNode
, (const xmlChar
*)"action", (const xmlChar
*)ite
->second
.Name
.c_str());
2879 if (!(const xmlChar
*)ite
->second
.Argu
.empty())
2880 xmlSetProp (keyNode
, (const xmlChar
*)"params", (const xmlChar
*)ite
->second
.Argu
.c_str());
2883 if (!context
.empty ())
2884 xmlSetProp (keyNode
, (const xmlChar
*)"context", (const xmlChar
*)context
.c_str());
2890 // ***************************************************************************
2892 void writeMacros (xmlNodePtr node
)
2894 const std::vector
<CMacroCmd
> ¯os
= CMacroCmdManager::getInstance()->getMacros();
2895 for (uint i
= 0; i
< macros
.size(); ++i
)
2897 macros
[i
].writeTo(node
);
2901 // ***************************************************************************
2902 bool CInterfaceManager::saveKeys(bool verbose
)
2906 if (!ClientCfg
.R2EDEnabled
)
2908 string filename
= "save/keys_" + PlayerSelectedFileName
+ ".xml";
2909 if (!CFile::fileExists(filename
) && CFile::fileExists("save/shared_keys.xml"))
2910 filename
= "save/shared_keys.xml";
2912 if (verbose
) CInterfaceManager::getInstance()->displaySystemInfo("Saving " + filename
);
2914 ret
= saveKeys(filename
);
2920 // ***************************************************************************
2921 bool CInterfaceManager::saveKeys(const std::string
&filename
)
2928 // using temporary file, so no file.close() unless its a success
2929 if (file
.open (filename
, false, false, true))
2932 xmlStream
.init (&file
);
2934 xmlDocPtr doc
= xmlStream
.getDocument ();
2935 xmlNodePtr node
= xmlNewDocNode(doc
, NULL
, (const xmlChar
*)"interface_config", NULL
);
2936 xmlDocSetRootElement (doc
, node
);
2938 writeComboActionMap (Actions
, node
, "");
2939 writeComboActionMap (EditActions
, node
, RZ_CATEGORY_EDIT
);
2954 nlwarning ("Can't open the file %s", filename
.c_str());
2957 catch (const Exception
&e
)
2959 nlwarning ("Error while writing the file %s : %s.", filename
.c_str(), e
.what ());
2964 // ***************************************************************************
2965 bool CInterfaceManager::deletePlayerConfig (const std::string
&playerFileIdent
)
2967 string fileName
= "save/interface_" + playerFileIdent
+ ".icfg";
2968 return CFile::deleteFile(fileName
);
2972 // ***************************************************************************
2973 bool CInterfaceManager::deletePlayerKeys (const std::string
&playerFileIdent
)
2975 string fileName
= "save/keys_"+playerFileIdent
+".xml";
2976 string fileNameEditor
= "save/keys_r2ed_"+playerFileIdent
+".xml";
2977 return CFile::deleteFile(fileName
) && CFile::deleteFile(fileNameEditor
);
2980 // ***************************************************************************
2981 void CInterfaceManager::log(const std::string
&str
, const std::string
&cat
)
2985 // Open file with the name of the player
2986 const string fileName
= "save/log_" + PlayerSelectedFileName
+ ".txt";
2987 FILE *f
= nlfopen(fileName
, "at");
2990 const string finalString
= string(NLMISC::IDisplayer::dateToHumanString()) + " (" + NLMISC::toUpperAscii(cat
) + ") * " + str
;
2991 fprintf(f
, "%s\n", finalString
.c_str());
2997 // ***************************************************************************
2998 void CInterfaceManager::clearAllEditBox()
3000 std::vector
< CWidgetManager::SMasterGroup
> &_MasterGroups
= CWidgetManager::getInstance()->getAllMasterGroup();
3001 for (uint32 nMasterGroup
= 0; nMasterGroup
< _MasterGroups
.size(); nMasterGroup
++)
3003 CWidgetManager::SMasterGroup
&rMG
= _MasterGroups
[nMasterGroup
];
3004 for (uint8 nPriority
=0; nPriority
< WIN_PRIORITY_MAX
; ++nPriority
)
3006 list
<CInterfaceGroup
*> &rList
= rMG
.PrioritizedWindows
[nPriority
];
3007 list
<CInterfaceGroup
*>::iterator it
;
3008 for(it
= rList
.begin(); it
!= rList
.end(); ++it
)
3010 CInterfaceGroup
*pIG
= *it
;
3012 pIG
->clearAllEditBox();
3018 // ***************************************************************************
3019 void CInterfaceManager::restoreAllContainersBackupPosition()
3021 std::vector
< CWidgetManager::SMasterGroup
> &_MasterGroups
= CWidgetManager::getInstance()->getAllMasterGroup();
3022 for (uint32 nMasterGroup
= 0; nMasterGroup
< _MasterGroups
.size(); nMasterGroup
++)
3024 CWidgetManager::SMasterGroup
&rMG
= _MasterGroups
[nMasterGroup
];
3025 for (uint8 nPriority
=0; nPriority
< WIN_PRIORITY_MAX
; ++nPriority
)
3027 list
<CInterfaceGroup
*> &rList
= rMG
.PrioritizedWindows
[nPriority
];
3028 list
<CInterfaceGroup
*>::iterator it
;
3029 for(it
= rList
.begin(); it
!= rList
.end(); ++it
)
3031 if (*it
) (*it
)->restoreAllContainersBackupPosition();
3037 // ***************************************************************************
3038 void CInterfaceManager::visit(CInterfaceElementVisitor
*visitor
)
3041 std::vector
< CWidgetManager::SMasterGroup
> &_MasterGroups
= CWidgetManager::getInstance()->getAllMasterGroup();
3042 for (uint nMasterGroup
= 0; nMasterGroup
< _MasterGroups
.size(); nMasterGroup
++)
3044 if (_MasterGroups
[nMasterGroup
].Group
)
3046 _MasterGroups
[nMasterGroup
].Group
->visit(visitor
);
3051 // ***************************************************************************
3052 void CInterfaceManager::incLocalSyncActionCounter()
3054 _LocalSyncActionCounter
++;
3061 // ***************************************************************************
3062 NLMISC_COMMAND( localCounter
, "Get value of local counter", "" )
3064 if (args
.size() != 0) return false;
3065 CInterfaceManager
*im
= CInterfaceManager::getInstance();
3066 im
->displaySystemInfo(toString(im
->getLocalSyncActionCounter()));
3072 // ***************************************************************************
3074 NLMISC_COMMAND(loadui
, "Load an interface file", "<loadui [all]/interface.xml>")
3076 if (args
.size() != 1)
3079 CInterfaceManager
*im
= CInterfaceManager::getInstance();
3081 std::vector
<std::string
> xmlFileNames
;
3083 if (args
[0] == "all")
3084 xmlFileNames
= CInterfaceManager::getInGameXMLInterfaceFiles();
3086 xmlFileNames
.push_back (args
[0]);
3088 bool result
= im
->parseInterface (xmlFileNames
, true);
3091 CInterfaceManager::getInstance()->displaySystemInfo("File "+xmlFileNames
.back()+" loaded successfully.");
3093 CInterfaceManager::getInstance()->displaySystemInfo("File "+xmlFileNames
.back()+" NOT loaded successully.");
3096 // Invalidate the texts
3097 CWidgetManager::getInstance()->updateAllLocalisedElements();
3100 CWidgetManager::getInstance()->setCapturePointerLeft(NULL
);
3101 CWidgetManager::getInstance()->setCapturePointerRight(NULL
);
3102 CWidgetManager::getInstance()->setOldCaptureKeyboard(NULL
);
3103 CWidgetManager::getInstance()->setCaptureKeyboard(NULL
);
3108 // ***************************************************************************
3109 void CInterfaceManager::displayWebWindow(const string
& name
, const string
& url
)
3111 CInterfaceGroup
*pIG
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(name
));
3114 pIG
->setActive(true);
3115 pIG
->updateCoords();
3119 CAHManager::getInstance()->runActionHandler("browse", NULL
, "name="+name
+":content:html|url="+url
);
3122 // ***************************************************************************
3123 class CAHSaveUI
: public IActionHandler
3125 virtual void execute (CCtrlBase
*pCaller
, const string
&Params
)
3127 CInterfaceManager::getInstance()->saveKeys(true);
3128 CInterfaceManager::getInstance()->saveConfig(true);
3131 REGISTER_ACTION_HANDLER (CAHSaveUI
, "save_ui");
3134 // ***************************************************************************
3135 class CHandlerDispWebOnQuit : public IActionHandler
3137 virtual void execute (CCtrlBase *pCaller, const string &Params)
3139 if (ClientCfg.Local)
3140 CAHManager::getInstance()->runActionHandler("enter_modal", pCaller, "group=ui:interface:quit_dialog");
3142 CInterfaceManager::getInstance()->displayWebWindow("ui:interface:web_on_quit", "http://213.208.119.190/igpoll/poll_form.php");
3145 REGISTER_ACTION_HANDLER (CHandlerDispWebOnQuit, "disp_web_on_quit");
3147 // ***************************************************************************
3148 class CHandlerExitWebOnQuit : public IActionHandler
3150 virtual void execute (CCtrlBase *pCaller, const string &Params)
3152 CAHManager::getInstance()->runActionHandler("quit_ryzom", pCaller);
3155 REGISTER_ACTION_HANDLER (CHandlerExitWebOnQuit, "exit_web_on_quit");
3158 // ***************************************************************************
3160 // ***************************************************************************
3167 bool UsableFromClientUI
;
3169 bool operator< (const CEmoteEntry
& entry
) const
3171 string path1
= Path
;
3172 string path2
= entry
.Path
;
3176 string::size_type pos1
= path1
.find('|');
3177 string::size_type pos2
= path2
.find('|');
3179 string s1
= toUpper(CI18N::get(path1
.substr(0, pos1
)));
3180 string s2
= toUpper(CI18N::get(path2
.substr(0, pos2
)));
3182 sint result
= s1
.compare(s2
);
3184 return (result
< 0);
3186 if (pos1
== string::npos
)
3187 return (pos2
!= string::npos
);
3188 if (pos2
== string::npos
)
3191 path1
= path1
.substr(pos1
+ 1);
3192 path2
= path2
.substr(pos2
+ 1);
3198 static bool translateEmote(const std::string
&id
, std::string
&translatedName
, std::string
&commandName
, std::string
&commandNameAlt
)
3200 if (CI18N::hasTranslation(id
))
3202 translatedName
= CI18N::get(id
);
3204 // convert command to utf8 since emote translation can have strange chars
3205 commandName
= toLower(translatedName
);
3207 // replace all spaces by _
3208 while (strFindReplace(commandName
, " ", "_"));
3210 // TODO: remove accents
3211 commandNameAlt
= commandName
;
3213 if (commandNameAlt
== commandName
) commandNameAlt
.clear();
3218 translatedName
= id
;
3224 // ***************************************************************************
3225 void CInterfaceManager::initEmotes()
3227 _EmotesInitialized
= true;
3228 CTextEmotListSheet
*pTELS
= dynamic_cast<CTextEmotListSheet
*>(SheetMngr
.get(CSheetId("list.text_emotes")));
3232 static list
<CEmoteEntry
> entries
;
3233 if (entries
.empty())
3235 for (uint i
= 0; i
< pTELS
->TextEmotList
.size(); i
++)
3239 entry
.Path
= pTELS
->TextEmotList
[i
].Path
;
3240 entry
.Anim
= pTELS
->TextEmotList
[i
].Anim
;
3241 entry
.UsableFromClientUI
= pTELS
->TextEmotList
[i
].UsableFromClientUI
;
3242 entries
.push_back(entry
);
3247 // The list of behaviour missnames emotList
3248 CEmotListSheet
*pEmotList
= dynamic_cast<CEmotListSheet
*>(SheetMngr
.get(CSheetId("list.emot")));
3249 nlassert (pEmotList
!= NULL
);
3250 nlassert (pEmotList
->Emots
.size() <= 255);
3252 // Get the focus beta tester flag
3253 bool betaTester
= false;
3255 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
3256 CSkillManager
*pSM
= CSkillManager::getInstance();
3258 betaTester
= pSM
->isTitleUnblocked(CHARACTER_TITLE::FBT
);
3259 string previousMind
;
3260 CGroupSubMenu
*pFirstMenu
= 0;
3262 for (list
<CEmoteEntry
>::const_iterator it
= entries
.begin(); it
!= entries
.end(); it
++)
3264 uint32 nEmoteNb
= (*it
).EmoteId
;
3265 string sState
= (*it
).Anim
;
3266 string sName
= (*it
).Path
;
3268 // Check that the emote can be added to UI
3269 // ---------------------------------------
3270 if( (*it
).UsableFromClientUI
== false )
3275 // Check the emote reserved for FBT (hardcoded)
3276 // --------------------------------------------
3277 if (sState
== "FBT" && !betaTester
)
3280 // Get the behaviour from the list of emotes
3281 // -----------------------------------------
3284 for (i
= 0; i
< pEmotList
->Emots
.size(); ++i
)
3285 if (CAnimationStateSheet::getAnimationStateName(pEmotList
->Emots
[i
]) == sState
)
3291 // Add to the game context menu
3292 // ----------------------------
3294 for (i
= 0; i
< sName
.size(); ++i
)
3295 if (sName
[i
] == '|')
3298 CGroupMenu
*pRootMenu
= dynamic_cast<CGroupMenu
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:user_chat_emote_menu"));
3299 nlassert(pRootMenu
);
3301 CGroupSubMenu
*pMenu
= pRootMenu
->getRootMenu();
3304 std::string sTranslatedName
;
3305 std::string sCommandName
;
3306 std::string sCommandNameAlt
;
3308 // Add to the game context menu
3309 // ----------------------------
3310 for (i
= 0; i
< nbToken
; ++i
)
3313 if (i
!= (nbToken
-1))
3314 sTmp
= sName
.substr(0,sName
.find('|'));
3318 // Look if this part of the path is already present
3319 bool bFound
= false;
3320 for (j
= 0; j
< pMenu
->getNumLine(); ++j
)
3322 if (sTmp
== pMenu
->getLineId(j
))
3330 if (!bFound
) // Create it
3332 if (i
!= (nbToken
-1))
3334 pMenu
->addLine (CI18N::get(sTmp
), "", "", sTmp
);
3336 // Create a sub menu
3337 CGroupSubMenu
*pNewSubMenu
= new CGroupSubMenu(CViewBase::TCtorParam());
3338 pMenu
->setSubMenu(j
, pNewSubMenu
);
3340 if (pFirstMenu
== 0)
3341 pFirstMenu
= pNewSubMenu
;
3345 translateEmote(sTmp
, sTranslatedName
, sCommandName
, sCommandNameAlt
);
3348 pMenu
->addLine (sTranslatedName
+ " (/" + sCommandName
+ ")", "emote",
3349 "nb="+toString(nEmoteNb
)+"|behav="+toString(nBehav
), sTmp
);
3354 if (i
!= (nbToken
-1))
3356 pMenu
= pMenu
->getSubMenu(j
);
3357 sName
= sName
.substr(sName
.find('|')+1,sName
.size());
3361 if (sTranslatedName
.empty())
3362 translateEmote(sName
, sTranslatedName
, sCommandName
, sCommandNameAlt
);
3364 // Create new command
3365 // ------------------
3366 if (!sTranslatedName
.empty())
3368 if(ICommand::exists(sCommandName
))
3370 nlwarning("Translation for emote %s already exist: '%s' exist twice", sName
.c_str(), sCommandName
.c_str());
3374 CEmoteCmd
*pNewCmd
= new CEmoteCmd(sCommandName
.c_str(), "", "");
3375 pNewCmd
->EmoteNb
= nEmoteNb
;
3376 pNewCmd
->Behaviour
= nBehav
;
3377 _EmoteCmds
.push_back(pNewCmd
);
3379 // add alternative command if defined
3380 if (!sCommandNameAlt
.empty())
3382 if(ICommand::exists(sCommandNameAlt
))
3384 nlwarning("Translation for emote %s already exist: '%s' exist twice", sName
.c_str(), sCommandName
.c_str());
3388 CEmoteCmd
*pNewCmd
= new CEmoteCmd(sCommandNameAlt
.c_str(), "", "");
3389 pNewCmd
->EmoteNb
= nEmoteNb
;
3390 pNewCmd
->Behaviour
= nBehav
;
3391 _EmoteCmds
.push_back(pNewCmd
);
3395 CGroupSubMenu
*pMenu
= pRootMenu
->getRootMenu();
3397 // Quick-Emote too ?
3398 for (i
= 0; i
< pMenu
->getNumLine (); i
++)
3400 if (sName
== pMenu
->getLineId (i
))
3402 // Yeah that's a quick emote too; set command
3403 pMenu
->addLineAtIndex (i
,
3404 "@{FFFF}/" + sCommandName
,
3405 "emote", "nb="+toString(nEmoteNb
)+"|behav="+toString(nBehav
),
3406 "", "", "", false, false, true);
3408 pMenu
->removeLine (i
+1);
3416 nlwarning("No translation for emote %s", sName
.c_str());
3420 // Insert separators
3423 pFirstMenu
->addSeparatorAtIndex (0, "Positive");
3424 pFirstMenu
->addSeparatorAtIndex (4, "Neutral");
3425 pFirstMenu
->addSeparatorAtIndex (8, "Negative");
3430 // ***************************************************************************
3431 void CInterfaceManager::uninitEmotes()
3433 if( !_EmotesInitialized
)
3435 _EmotesInitialized
= false;
3437 // reset the emotes menu
3438 CTextEmotListSheet
*pTELS
= dynamic_cast<CTextEmotListSheet
*>(SheetMngr
.get(CSheetId("list.text_emotes")));
3439 if (pTELS
!= NULL
&& !pTELS
->TextEmotList
.empty())
3441 // get the emotes menu id
3442 string sPath
= pTELS
->TextEmotList
[0].Path
;
3443 string sId
= sPath
.substr(0, sPath
.find('|'));
3445 // get the emotes menu
3446 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
3447 CGroupMenu
*pRootMenu
= dynamic_cast<CGroupMenu
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:game_context_menu"));
3450 CGroupSubMenu
*pMenu
= pRootMenu
->getRootMenu();
3451 for (uint i
= 0; i
< pMenu
->getNumLine(); ++i
)
3453 if (pMenu
->getLineId(i
) == sId
)
3455 pMenu
= pMenu
->getSubMenu(i
);
3464 for (uint32 i
= 0; i
< _EmoteCmds
.size(); ++i
)
3465 delete _EmoteCmds
[i
];
3469 // ***************************************************************************
3470 void CInterfaceManager::updateEmotes()
3476 // ***************************************************************************
3477 // Just call the action handler with good params
3478 bool CInterfaceManager::CEmoteCmd::execute(const std::string
&/* rawCommandString */, const vector
<string
> &args
, CLog
&/* log */, bool /* quiet */, bool /* human */)
3480 string customPhrase
;
3483 customPhrase
= args
[0];
3485 for(uint i
= 1; i
< args
.size(); ++i
)
3487 customPhrase
+= " ";
3488 customPhrase
+= args
[i
];
3490 CAHManager::getInstance()->runActionHandler("emote", NULL
, "nb="+toString(EmoteNb
)+"|behav="+toString(Behaviour
)+"|custom_phrase="+customPhrase
);
3494 // ***************************************************************************
3495 bool CInterfaceManager::testDragCopyKey()
3497 // hardcoded for now
3498 return Driver
->AsyncListener
.isKeyDown(KeyCONTROL
) ||
3499 Driver
->AsyncListener
.isKeyDown(KeyLCONTROL
) ||
3500 Driver
->AsyncListener
.isKeyDown(KeyRCONTROL
);
3503 // ***************************************************************************
3504 void CInterfaceManager::notifyMailAvailable()
3506 if (_CheckMailNode
!= NULL
)
3507 _CheckMailNode
->setValue32(1);
3510 void CInterfaceManager::notifyForumUpdated()
3512 if (_CheckForumNode
!= NULL
)
3513 _CheckForumNode
->setValue32(1);
3516 void CInterfaceManager::queueLuaScript(const std::string
&script
)
3518 CAutoMutex
<CMutex
> autoMutex(_ScriptQueueMutex
);
3520 _ScriptQueue
.push(script
);
3523 void CInterfaceManager::flushScriptQueue()
3525 CAutoMutex
<CMutex
> autoMutex(_ScriptQueueMutex
);
3527 while(!_ScriptQueue
.empty())
3529 CLuaManager::getInstance().executeLuaScript(_ScriptQueue
.front());
3535 // ***************************************************************************
3536 void CInterfaceManager::resetTextIndex()
3538 uint32 nMasterGroup
;
3539 std::vector
< CWidgetManager::SMasterGroup
> &_MasterGroups
= CWidgetManager::getInstance()->getAllMasterGroup();
3540 for (nMasterGroup
= 0; nMasterGroup
< _MasterGroups
.size(); nMasterGroup
++)
3542 CWidgetManager::SMasterGroup
&rMG
= _MasterGroups
[nMasterGroup
];
3544 InvalidateTextVisitor
inv( true );
3545 rMG
.Group
->visitGroupAndChildren( &inv
);
3546 for (uint8 nPriority
= 0; nPriority
< WIN_PRIORITY_MAX
; nPriority
++)
3548 list
<CInterfaceGroup
*> &rList
= rMG
.PrioritizedWindows
[nPriority
];
3549 list
<CInterfaceGroup
*>::const_iterator itw
;
3550 for (itw
= rList
.begin(); itw
!= rList
.end(); itw
++)
3552 CInterfaceGroup
*pIG
= *itw
;
3553 pIG
->visitGroupAndChildren( &inv
);
3559 // ***************************************************************************
3560 CInterfaceElement
*getInterfaceResource(const std::string
&key
)
3562 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
3563 return CWidgetManager::getInstance()->getElementFromId (key
);
3566 // ***************************************************************************
3567 std::vector
<std::string
> CInterfaceManager::getInGameXMLInterfaceFiles()
3571 ret
= ClientCfg
.XMLInterfaceFiles
;
3573 // Resolve any conflict (with CPath scheme, AddOn Should take the precedence)
3574 // But still preserve order given in XMLInterfaceFiles (important for config.xml for instance)
3575 set
<string
> fileSet
;
3576 for(uint i
=0;i
<ret
.size();i
++)
3578 fileSet
.insert(ret
[i
]);
3581 // Add R2 Editor .xml. This is removed as it will not be done when initializing CEditor
3582 // if (ClientCfg.R2EDEnabled)
3584 // // Add them to 'ret', only if not already inserted
3585 // // since parser will crash on any duplicates
3586 // for(uint i=0;i<ClientCfg.XMLR2EDInterfaceFiles.size();i++)
3588 // if(fileSet.find(ClientCfg.XMLR2EDInterfaceFiles[i])==fileSet.end())
3590 // fileSet.insert(ClientCfg.XMLR2EDInterfaceFiles[i]);
3591 // ret.push_back(ClientCfg.XMLR2EDInterfaceFiles[i]);
3597 vector
<string
> adds
;
3598 InterfaceAddOnManager
.getFiles("*.xml", adds
);
3600 // Add them to 'ret', only if not already inserted
3601 for(uint i
=0;i
<adds
.size();i
++)
3603 if(fileSet
.find(adds
[i
])==fileSet
.end())
3605 fileSet
.insert(adds
[i
]);
3606 ret
.push_back(adds
[i
]);
3613 // ***************************************************************************
3614 void CInterfaceManager::dumpLuaString(const std::string
&str
)
3616 nlinfo(str
.c_str());
3617 displaySystemInfo(LuaHelperStuff::formatLuaErrorSysInfo(str
));
3620 // ***************************************************************************
3621 void CInterfaceManager::getLuaValueInfo(std::string
&str
, sint index
)
3623 CLuaState
&ls
= *( CLuaManager::getInstance().getLuaState() );
3625 sint type
= ls
.type(index
);
3630 else if(type
==LUA_TNUMBER
)
3632 str
= NLMISC::toString(ls
.isInteger(index
) ? ls
.toInteger(index
):ls
.toNumber(index
));
3634 else if(type
==LUA_TBOOLEAN
)
3636 str
= ls
.toBoolean(index
)?"true":"false";
3638 else if(type
==LUA_TSTRING
)
3640 ls
.toString(index
, str
);
3641 str
= toString("'") + str
+ toString("'");
3645 str
= ls
.getTypename(type
);
3647 str
+= NLMISC::toString("%p", ls
.toPointer(index
));
3648 // If its a table, append the size.
3649 if(type
==LUA_TTABLE
)
3651 ls
.pushNil(); // first key
3653 while (ls
.next(index
-1))
3655 ls
.pop(); // remove 'value'; keeps `key' for next iteration
3658 str
+= NLMISC::toString(" (size=%d)", count
);
3660 // If its a Userdata, try to display UI info
3661 else if(type
==LUA_TUSERDATA
)
3663 if(CLuaIHM::isUIOnStack(ls
, index
))
3665 CInterfaceElement
*ui
= CLuaIHM::getUIOnStack(ls
, index
);
3666 str
+= NLMISC::toString(" (ui=%p)", ui
);
3672 // ***************************************************************************
3673 void CInterfaceManager::dumpLuaKeyValueInfo(uint recursTableLevel
, uint tabLevel
)
3675 CLuaState
&ls
= *( CLuaManager::getInstance().getLuaState() );
3676 CLuaStackChecker
lsc(&ls
);
3680 getLuaValueInfo(key
, -2);
3683 getLuaValueInfo(value
, -1);
3687 // append tab for table hierarchy
3688 for(uint i
=0;i
<tabLevel
;i
++)
3690 // display key and value
3691 res
+= key
+ " == " + value
;
3694 // If the value is a table, and can recurs dumping
3695 if(recursTableLevel
>0 && ls
.type(-1)==LUA_TTABLE
)
3697 ls
.pushNil(); // first key
3700 // display the key value pair of this table (recurs)
3701 dumpLuaKeyValueInfo(recursTableLevel
-1, tabLevel
+1);
3702 ls
.pop(); // remove 'value'; keeps `key' for next iteration
3708 // ***************************************************************************
3709 void CInterfaceManager::dumpLuaState(uint detail
)
3711 CLuaState
*_LuaState
= CLuaManager::getInstance().getLuaState();
3713 // clamp detailed info to 2 (display at max content of eaxh Env of each group)
3714 clamp(detail
, 0U, 2U);
3716 // Dump the Memory State
3717 dumpLuaString(NLMISC::toString("Memory Used : %d Kb", _LuaState
->getGCCount()));
3718 dumpLuaString(NLMISC::toString("GC Threshold: %d Kb", _LuaState
->getGCThreshold()));
3720 // If want to display some detailed info
3723 CLuaState
&ls
= *_LuaState
;
3724 CLuaStackChecker
lsc(&ls
);
3726 // *** Dump all Lua Env Tables
3727 ls
.push(IHM_LUA_ENVTABLE
);
3728 ls
.getTable(LUA_REGISTRYINDEX
); // __ui_envtable
3729 ls
.pushNil(); // first key
3733 // `key' is at index -2 and `value' at index -1
3734 dumpLuaKeyValueInfo(detail
-1, 1);
3735 ls
.pop(); // remove 'value'; keeps `key' for next iteration
3741 dumpLuaString(NLMISC::toString("Number of EnvTable for ui groups: %d", count
));
3745 // ------------------------------------------------------------------------------------------------
3746 void CInterfaceManager::createLocalBranch(const std::string
&fileName
, NLMISC::IProgressCallback
&progressCallBack
)
3751 if (file
.open (fileName
))
3753 // Init an xml stream
3757 //Parse the parser output!!!
3758 CCDBNodeBranch
*localNode
= new CCDBNodeBranch("LOCAL");
3759 localNode
->init( read
.getRootNode (), progressCallBack
);
3760 NLGUI::CDBManager::getInstance()->getDB()->attachChild(localNode
,"LOCAL");
3762 // Create the observers for auto-copy SERVER->LOCAL of inventory
3763 ServerToLocalAutoCopyInventory
.init("INVENTORY");
3765 // Create the observers for auto-copy SERVER->LOCAL of exchange
3766 ServerToLocalAutoCopyExchange
.init("EXCHANGE");
3768 // Create the observers for auto-copy SERVER->LOCAL of dm (animator) gift
3769 ServerToLocalAutoCopyDMGift
.init("DM_GIFT");
3771 // Create the observers for auto-copy SERVER->LOCAL of context menu
3772 ServerToLocalAutoCopyContextMenu
.init("TARGET:CONTEXT_MENU");
3774 // Create the observers for auto-copy SERVER->LOCAL of Skill Points
3775 ServerToLocalAutoCopySkillPoints
.init("USER");
3778 catch (const Exception
&e
)
3781 nlwarning ("CFormLoader: Error while loading the form %s: %s", fileName
.c_str(), e
.what());
3785 // ------------------------------------------------------------------------------------------------
3786 #ifdef NL_OS_WINDOWS
3787 # pragma warning (push)
3788 # pragma warning (disable : 4355) // 'this' used in base member initializer list
3790 CInterfaceManager::CServerToLocalAutoCopy::CServerToLocalAutoCopy() : _LocalObserver(*this), _ServerObserver(*this)
3792 _ServerCounter
= NULL
;
3793 _UpdateList
.reserve(300);
3794 _LocalUpdating
= false;
3796 #ifdef NL_OS_WINDOWS
3797 # pragma warning (pop)
3800 // ------------------------------------------------------------------------------------------------
3801 // unhook from everything we are tangled up in
3802 void CInterfaceManager::CServerToLocalAutoCopy::release()
3805 _ServerCounter
= NULL
;
3806 _ServerNodeMap
.clear();
3807 _LocalNodeMap
.clear();
3808 _UpdateList
.clear();
3811 // ------------------------------------------------------------------------------------------------
3812 void CInterfaceManager::CServerToLocalAutoCopy::buildRecursLocalLeaves(CCDBNodeBranch
*branch
, std::vector
<CCDBNodeLeaf
*> &leaves
)
3814 for(uint i
=0;i
<branch
->getNbNodes();i
++)
3816 ICDBNode
*node
= branch
->getNode(i
);
3819 CCDBNodeLeaf
*leaf
= dynamic_cast<CCDBNodeLeaf
*>(node
);
3822 // just append to list
3823 leaves
.push_back(leaf
);
3827 // recurs if a branch (should be...)
3828 CCDBNodeBranch
*sonBranch
= dynamic_cast<CCDBNodeBranch
*>(node
);
3830 buildRecursLocalLeaves(sonBranch
, leaves
);
3836 // ------------------------------------------------------------------------------------------------
3837 void CInterfaceManager::CServerToLocalAutoCopy::init(const std::string
&dbPath
)
3839 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
3841 // Get the synchronisation Counter in Server DB
3842 _ServerCounter
= NLGUI::CDBManager::getInstance()->getDbProp(string("SERVER:") + dbPath
+ ":COUNTER", false);
3847 ICDBNode::CTextId textId
;
3849 // **** Add Observers on all nodes
3850 // add the observers when server node change
3851 textId
= ICDBNode::CTextId( string("SERVER:") + dbPath
);
3852 NLGUI::CDBManager::getInstance()->getDB()->addObserver(&_ServerObserver
, textId
);
3854 // add the observers when local node change
3855 textId
= ICDBNode::CTextId( string("LOCAL:") + dbPath
);
3856 NLGUI::CDBManager::getInstance()->getDB()->addObserver(&_LocalObserver
, textId
);
3858 // **** Init the Nodes shortcut
3859 // Parse all Local Nodes
3860 CCDBNodeBranch
*localBranch
= NLGUI::CDBManager::getInstance()->getDbBranch(string("LOCAL:") + dbPath
);
3864 std::vector
<CCDBNodeLeaf
*> leaves
;
3865 buildRecursLocalLeaves(localBranch
, leaves
);
3868 _Nodes
.reserve(leaves
.size());
3869 for(i
=0;i
<leaves
.size();i
++)
3871 CCDBNodeLeaf
*localLeaf
= leaves
[i
];
3873 // get the SERVER associated node name
3874 string serverLeafStr
= *localLeaf
->getName();
3875 CCDBNodeBranch
* parent
= localLeaf
->getParent();
3876 while( *parent
->getName()!="LOCAL" )
3878 serverLeafStr
= *parent
->getName()+":"+serverLeafStr
;
3879 parent
= parent
->getParent();
3881 serverLeafStr
= "SERVER:" + serverLeafStr
;
3883 // try then to get this server node
3884 CCDBNodeLeaf
*serverLeaf
= NLGUI::CDBManager::getInstance()->getDbProp(serverLeafStr
, false);
3887 // Both server and local leaves exist, ok, append to _Nodes
3889 node
.ServerNode
= serverLeaf
;
3890 node
.LocalNode
= localLeaf
;
3891 _Nodes
.push_back(node
);
3895 // --- Init the maps
3896 _ServerNodeMap
.reserve(leaves
.size());
3897 _LocalNodeMap
.reserve(leaves
.size());
3898 // For all valid _Nodes, insert in "map"
3899 for(i
=0;i
<_Nodes
.size();i
++)
3903 lc
.Node
= &_Nodes
[i
];
3904 sc
.Node
= &_Nodes
[i
];
3905 _LocalNodeMap
.push_back(lc
);
3906 _ServerNodeMap
.push_back(sc
);
3909 sort(_LocalNodeMap
.begin(), _LocalNodeMap
.end());
3910 sort(_ServerNodeMap
.begin(), _ServerNodeMap
.end());
3916 // ------------------------------------------------------------------------------------------------
3917 void CInterfaceManager::CServerToLocalAutoCopy::onServerChange(ICDBNode
*serverNode
)
3921 CCDBNodeLeaf
*serverLeaf
= safe_cast
<CCDBNodeLeaf
*>(serverNode
);
3922 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
3924 // Add the leaf to the update list. only if not the counter
3925 if(serverLeaf
!= _ServerCounter
)
3927 // build the map key
3930 nodeComp
.ServerNode
= serverLeaf
;
3932 // try to find the node associated to this server leaf
3933 uint index
= searchLowerBound(_ServerNodeMap
, sc
);
3935 if( index
>0 || _ServerNodeMap
[0].Node
->ServerNode
==serverLeaf
)
3937 CNode
*node
= _ServerNodeMap
[index
].Node
;
3938 // if this node is not already inserted
3939 if(!node
->InsertedInUpdateList
)
3942 node
->InsertedInUpdateList
= true;
3943 _UpdateList
.push_back(node
);
3948 // if the client and server are synchonized.
3949 if( ClientCfg
.Local
|| pIM
->localActionCounterSynchronizedWith(_ServerCounter
) )
3951 // update all leaves
3952 for(uint i
=0;i
<_UpdateList
.size();i
++)
3954 CNode
*node
= _UpdateList
[i
];
3956 _LocalUpdating
= true;
3957 node
->LocalNode
->setValue64(node
->ServerNode
->getValue64());
3958 _LocalUpdating
= false;
3960 // reset inserted flag
3961 node
->InsertedInUpdateList
= false;
3964 // clear update list
3965 _UpdateList
.clear();
3969 // ------------------------------------------------------------------------------------------------
3970 void CInterfaceManager::CServerToLocalAutoCopy::onLocalChange(ICDBNode
*localNode
)
3975 // if the local changes because of localLeaf->setValue64() in onServerChange(), no-op !!!
3979 CCDBNodeLeaf
*localLeaf
= safe_cast
<CCDBNodeLeaf
*>(localNode
);
3981 // Add the leaf to the update list
3982 // build the map key
3985 nodeComp
.LocalNode
= localLeaf
;
3987 // try to find the node associated to this local leaf
3988 uint index
= searchLowerBound(_LocalNodeMap
, lc
);
3990 if( index
>0 || _LocalNodeMap
[0].Node
->LocalNode
==localLeaf
)
3992 CNode
*node
= _LocalNodeMap
[index
].Node
;
3993 // if this node is not already inserted
3994 if(!node
->InsertedInUpdateList
)
3997 node
->InsertedInUpdateList
= true;
3998 _UpdateList
.push_back(node
);
4003 // ------------------------------------------------------------------------------------------------
4004 bool CInterfaceManager::use12hClock()
4006 CCDBNodeLeaf
*node
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_CLOCK_12H", false);
4008 return (node
&& node
->getValueBool());
4011 // ------------------------------------------------------------------------------------------------
4012 char* CInterfaceManager::getTimestampHuman(const char* format
/* "[%H:%M:%S] " */)
4014 static char cstime
[25];
4017 struct tm
*tms
= localtime(&date
);
4020 strftime(cstime
, 25, format
, tms
);
4032 * Parse tokens in a chatmessage or emote
4045 * $<subject>.gs(m/f/n)$
4047 * Default parameter if parameter result is empty:
4048 * $<subject>.<parameter>/<default>$
4050 * All \d's in default parameter remove a following character.
4052 bool CInterfaceManager::parseTokens(string
& ucstr
)
4055 string
start_token("$");
4056 string
end_token("$");
4057 size_t start_pos
= 0;
4060 sint endless_loop_protector
= 0;
4061 while ((start_pos
< str
.length() - 1) &&
4062 ((start_pos
= str
.find(start_token
, start_pos
)) != string::npos
))
4064 endless_loop_protector
++;
4065 if (endless_loop_protector
> 100)
4070 // Get the whole token substring first
4071 end_pos
= str
.find(end_token
, start_pos
+ 1);
4073 if ((start_pos
== string::npos
) ||
4074 (end_pos
== string::npos
) ||
4075 (end_pos
<= start_pos
+ 1))
4077 // Wrong formatting; give up on this one.
4078 start_pos
= max(start_pos
, end_pos
);
4082 // Get everything between the two "$"
4083 size_t token_start_pos
= start_pos
+ start_token
.length();
4084 size_t token_end_pos
= end_pos
- end_token
.length();
4085 if (token_start_pos
> token_end_pos
)
4087 // Wrong formatting; give up on this one.
4088 start_pos
= end_pos
;
4092 string token_whole
= str
.substr(start_pos
, end_pos
- start_pos
+ 1);
4093 string token_string
= token_whole
.substr(1, token_whole
.length() - 2);
4094 string token_replacement
= token_whole
;
4095 string token_default
= token_whole
;
4097 string token_subject
;
4100 // Does the token have a parameter?
4101 // If not it is 'name' by default
4102 vector
<string
> token_vector
;
4103 vector
<string
> param_vector
;
4104 splitString(token_string
, ".", token_vector
);
4105 if (token_vector
.empty())
4107 // Wrong formatting; give up on this one.
4108 start_pos
= end_pos
;
4111 token_subject
= token_vector
[0];
4112 if (token_vector
.size() == 1)
4114 splitString(token_subject
, "/", param_vector
);
4115 token_subject
= !param_vector
.empty() ? param_vector
[0] : string();
4116 token_param
= string("name");
4118 else if (token_vector
.size() > 1)
4120 token_param
= token_vector
[1];
4121 if (token_param
.substr(0, 3) != "gs(")
4123 splitString(token_vector
[1], "/", param_vector
);
4124 token_param
= !param_vector
.empty() ? param_vector
[0] : string();
4128 // Get any default value, if not gs
4129 sint extra_replacement
= 0;
4130 if (token_param
.substr(0, 3) != "gs(")
4132 if (param_vector
.size() == 2)
4134 // Set default value
4135 token_replacement
= param_vector
[1];
4136 // Delete following chars for every '\d' in default
4137 string::size_type token_replacement_pos
;
4138 while ((token_replacement_pos
= token_replacement
.find(string("\\d"))) != string::npos
)
4140 token_replacement
.replace(token_replacement_pos
, 2, string());
4141 extra_replacement
++;
4143 token_default
= token_replacement
;
4147 CEntityCL
*pTokenSubjectEntity
= NULL
;
4149 if (token_subject
== "me")
4151 pTokenSubjectEntity
= static_cast<CEntityCL
*>(UserEntity
);
4153 else if (token_subject
== "t")
4156 uint targetSlot
= UserEntity
->targetSlot();
4157 pTokenSubjectEntity
= EntitiesMngr
.entity(targetSlot
);
4159 else if (token_subject
== "tt")
4162 uint targetSlot
= UserEntity
->targetSlot();
4163 CEntityCL
*target
= EntitiesMngr
.entity(targetSlot
);
4167 // Check the new slot.
4168 CLFECOMMON::TCLEntityId newSlot
= target
->targetSlot();
4169 CEntityCL
* pE
= EntitiesMngr
.entity(newSlot
);
4172 pTokenSubjectEntity
= pE
;
4176 else if ((token_subject
.length() == 3) &&
4177 (token_subject
.substr(0, 2) == "tm"))
4180 uint indexInTeam
= 0;
4181 fromString(token_subject
.substr(2, 1), indexInTeam
);
4185 if (indexInTeam
< PeopleInterraction
.TeamList
.getNumPeople() )
4187 // Index is the database index (serverIndex() not used for team list)
4188 CCDBNodeLeaf
*pNL
= NLGUI::CDBManager::getInstance()->getDbProp( NLMISC::toString(TEAM_DB_PATH
":%hu:NAME", indexInTeam
), false);
4189 if (pNL
&& pNL
->getValueBool() )
4191 // There is a character corresponding to this index
4192 pNL
= NLGUI::CDBManager::getInstance()->getDbProp( NLMISC::toString( TEAM_DB_PATH
":%hu:UID", indexInTeam
), false );
4195 CLFECOMMON::TClientDataSetIndex compressedIndex
= pNL
->getValue32();
4197 // Search entity in vision
4198 CEntityCL
*entity
= EntitiesMngr
.getEntityByCompressedIndex( compressedIndex
);
4201 pTokenSubjectEntity
= entity
;
4209 // Unknown token subject, skip it
4210 start_pos
= end_pos
;
4214 if (pTokenSubjectEntity
!= NULL
)
4216 // Parse the parameter
4217 if (token_param
== "name")
4219 string name
= pTokenSubjectEntity
->getDisplayName();
4220 // special case where there is only a title, very rare case for some NPC
4223 name
= pTokenSubjectEntity
->getTitle();
4225 token_replacement
= name
.empty() ? token_replacement
: name
;
4227 else if (token_param
== "title")
4229 string title
= pTokenSubjectEntity
->getTitle();
4230 token_replacement
= title
.empty() ? token_replacement
: title
;
4232 else if (token_param
== "race")
4234 CCharacterCL
*pC
= dynamic_cast<CCharacterCL
*>(pTokenSubjectEntity
);
4237 EGSPD::CPeople::TPeople race
= pC
->people();
4238 if (race
>= EGSPD::CPeople::Playable
&& race
<= EGSPD::CPeople::EndPlayable
)
4240 string srace
= NLMISC::CI18N::get("io" + EGSPD::CPeople::toString(race
));
4241 token_replacement
= srace
.empty() ? token_replacement
: srace
;
4245 else if (token_param
== "guild")
4247 STRING_MANAGER::CStringManagerClient
*pSMC
= STRING_MANAGER::CStringManagerClient::instance();
4249 if (pSMC
->getString(pTokenSubjectEntity
->getGuildNameID(), ucGuildName
))
4251 token_replacement
= ucGuildName
.empty() ? token_replacement
: ucGuildName
;
4254 else if (token_param
.substr(0, 3) == "gs(" &&
4255 token_param
.substr(token_param
.length() - 1 , 1) == ")")
4258 vector
<string
> strList
;
4259 string gender_string
= token_param
.substr(3, token_param
.length() - 4);
4260 splitString(gender_string
, "/", strList
);
4262 if (strList
.size() <= 1)
4264 start_pos
= end_pos
;
4268 // We only care about the gender if the subject is humanoid.
4269 GSGENDER::EGender gender
= GSGENDER::neutral
;
4270 if (pTokenSubjectEntity
->isUser() || pTokenSubjectEntity
->isPlayer() || pTokenSubjectEntity
->isNPC())
4272 CCharacterCL
*pC
= dynamic_cast<CCharacterCL
*>(pTokenSubjectEntity
);
4275 gender
= pC
->getGender();
4279 // The neuter part is optional. Fallback to male if something is wrong.
4280 GSGENDER::EGender g
= ((uint
)gender
>= strList
.size()) ? GSGENDER::male
: gender
;
4281 token_replacement
= strList
[g
];
4285 if (token_whole
== token_replacement
)
4287 // Nothing to replace; show message and exit
4288 CInterfaceManager
*im
= CInterfaceManager::getInstance();
4289 string message
= CI18N::get("uiUntranslatedToken");
4290 message
.replace(message
.find("%s"), 2, token_whole
);
4291 im
->displaySystemInfo(message
);
4296 size_t token_whole_pos
= str
.find(token_whole
);
4298 // Only do extra replacement spaces if using default
4299 extra_replacement
= (token_replacement
== token_default
) ? extra_replacement
: 0;
4300 if (str
.find(token_whole
, start_pos
) != string::npos
)
4302 str
= str
.replace(token_whole_pos
, token_whole
.length() + extra_replacement
, token_replacement
);
4303 start_pos
= token_whole_pos
+ token_replacement
.length();
4311 std::string
CInterfaceManager::getNextBackupName(std::string filename
)
4313 std::string ts
= getTimestampHuman("%Y-%m-%d");
4317 std::string::size_type pos
= filename
.find_last_of('.');
4318 if (pos
== std::string::npos
)
4319 filename
= filename
+ "_" + ts
+ "_";
4321 filename
= filename
.substr(0, pos
) + "_" + ts
+ "_" + filename
.substr(pos
);
4324 // filename_YYYY-MM-DD_000.ext
4325 return CFile::findNewFile(filename
);
4328 void CInterfaceManager::createFileBackup(const std::string
&message
, const std::string
&filename
, bool useCopy
)
4330 std::string backupName
= getNextBackupName(filename
);
4331 nlwarning("%s: '%s'.", message
.c_str(), filename
.c_str());
4332 if (!backupName
.empty())
4336 nlwarning("Backup copy saved as '%s'", backupName
.c_str());
4337 CFile::copyFile(backupName
, filename
);
4341 nlwarning("File renamed to '%s'", backupName
.c_str());
4342 CFile::moveFile(backupName
, filename
);