6601 lines
No EOL
194 KiB
C++
6601 lines
No EOL
194 KiB
C++
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#include "stdpch.h"
|
|
|
|
// Memory
|
|
#include <memory>
|
|
|
|
#include "nel/misc/i_xml.h"
|
|
#include "nel/misc/o_xml.h"
|
|
#include "nel/misc/algo.h"
|
|
|
|
#include "nel/net/tcp_sock.h"
|
|
|
|
// Globals
|
|
#include "interface_manager.h"
|
|
#include "input_handler_manager.h"
|
|
#include "interface_config.h"
|
|
#include "task_bar_manager.h"
|
|
#include "guild_manager.h"
|
|
#include "../client_cfg.h"
|
|
#include "encyclopedia_manager.h"
|
|
// Expr
|
|
#include "interface_expr.h"
|
|
#include "register_interface_elements.h"
|
|
// Action / Observers
|
|
#include "action_handler.h"
|
|
#include "interface_observer.h"
|
|
#include "interface_anim.h"
|
|
#include "interface_ddx.h"
|
|
#include "action_handler_help.h"
|
|
#include "action_handler_item.h"
|
|
// View
|
|
#include "view_bitmap.h"
|
|
//#include "view_bitmap_progress.h"
|
|
#include "view_bitmap_faber_mp.h"
|
|
#include "view_bitmap_combo.h"
|
|
#include "view_text.h"
|
|
// Ctrl
|
|
#include "ctrl_scroll.h"
|
|
#include "ctrl_button.h"
|
|
#include "ctrl_text_button.h"
|
|
// DBCtrl
|
|
#include "dbctrl_sheet.h"
|
|
// Group
|
|
#include "group_list.h"
|
|
#include "group_menu.h"
|
|
#include "group_container.h"
|
|
#include "group_modal.h"
|
|
#include "group_editbox.h"
|
|
#include "group_in_scene_bubble.h"
|
|
#include "group_skills.h"
|
|
#include "group_compas.h"
|
|
|
|
// Misc
|
|
#include "../input.h"
|
|
#include "bot_chat_manager.h"
|
|
#include "bot_chat_page_all.h"
|
|
#include "chat_displayer.h"
|
|
#include "skill_manager.h"
|
|
#include "../sound_manager.h"
|
|
#include "../actions.h"
|
|
#include "../actions_client.h"
|
|
|
|
#include "../weather_manager_client.h"
|
|
#include "../weather.h"
|
|
|
|
#include "../user_entity.h"
|
|
#include "../motion/user_controls.h"
|
|
#include "people_interraction.h"
|
|
#include "macrocmd_manager.h"
|
|
#include "inventory_manager.h"
|
|
|
|
#include "../connection.h" // needed for loading config file (PlayerSelectedFileName)
|
|
|
|
#include "sbrick_manager.h"
|
|
#include "sphrase_manager.h"
|
|
#include "bar_manager.h"
|
|
|
|
#include "../continent_manager.h"
|
|
#include "../entity_cl.h"
|
|
#include "../login.h"
|
|
|
|
#include "../sheet_manager.h" // for emotes
|
|
#include "../global.h" // for emotes
|
|
#include "../entity_animation_manager.h" // for emotes
|
|
#include "../net_manager.h" // for emotes
|
|
#include "../client_chat_manager.h" // for emotes
|
|
#include "../entities.h"
|
|
|
|
#include "chat_text_manager.h"
|
|
#include "../npc_icon.h"
|
|
|
|
#include "lua_helper.h"
|
|
#include "lua_ihm.h"
|
|
|
|
#include "add_on_manager.h"
|
|
|
|
#include "game_share/r2_share_itf.h"
|
|
|
|
#include "../time_client.h"
|
|
|
|
#include "../r2/editor.h"
|
|
#include "../r2/dmc/client_edition_module.h"
|
|
|
|
#include "../bg_downloader_access.h"
|
|
|
|
using namespace NLMISC;
|
|
|
|
extern CClientChatManager ChatMngr;
|
|
extern CContinentManager ContinentMngr;
|
|
extern CStringMapper *_UIStringMapper;
|
|
extern bool IsInRingSession;
|
|
extern CEventsListener EventsListener;
|
|
|
|
namespace R2
|
|
{
|
|
extern bool ReloadUIFlag;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
/*
|
|
Version 11: - Dyn chat in user tab
|
|
Version 10: - Last screen resolution serialisation
|
|
Version 9: UI_DB_SAVE_VERSION system
|
|
Version 8: - serialInSceneBubbleInfo (for ignore context help)
|
|
Version 7: - serialMacroMemory
|
|
Version 6: DEPRECATED - Info about friend/ignore list
|
|
Version 5: - Info Windows pos
|
|
Version 4: - User landmark serialisation
|
|
Version 3: - Added a Hack for CInterfaceConfig version miss
|
|
Version 2: - TaskBar serialisation
|
|
Version 1: - people interraction
|
|
Version 0: - base version
|
|
*/
|
|
#define ICFG_STREAM_VERSION 11
|
|
|
|
#ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
#define FOREACH(__itvar,__conttype,__contvar) \
|
|
for (__conttype::iterator __itvar(__contvar.begin()),__itvar##end(__contvar.end()); __itvar!=__itvar##end; ++__itvar)
|
|
#endif
|
|
|
|
// ***************************************************************************
|
|
|
|
using namespace std;
|
|
using namespace NLMISC;
|
|
using namespace NLNET;
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
extern NL3D::UDriver *Driver;
|
|
extern bool loginFinished;
|
|
// Edit actions
|
|
CActionsManager EditActions;
|
|
|
|
CInterfaceManager * CInterfaceManager::_Instance = NULL;
|
|
|
|
CChatDisplayer * ChatDisplayer = NULL;
|
|
|
|
|
|
void initActions();
|
|
void uninitActions();
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
string CInterfaceManager::_CtrlLaunchingModalId= "ctrl_launch_modal";
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static const uint DOUBLE_CLICK_MIN = 50;
|
|
static const uint DOUBLE_CLICK_MAX = 750;
|
|
|
|
///\todo nico: remove this dummy displayer
|
|
NLMISC::CLog g_log;
|
|
|
|
|
|
////////////
|
|
// GLOBAL //
|
|
////////////
|
|
|
|
// Hierarchical timer
|
|
H_AUTO_DECL ( RZ_Client_Update_Frame_Events )
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// AJM TEMP TEMP TEMP TEMP
|
|
#ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
|
|
// track creation of an interface group
|
|
void CInterfaceManager::DebugTrackGroupsCreated( CInterfaceGroup *pIG )
|
|
{
|
|
// add to set
|
|
_DebugTrackGroupSet.insert( pIG );
|
|
|
|
// add to map and increment create counter
|
|
_DebugTrackGroupMap[pIG] = _DebugTrackGroupCreateCount++;
|
|
}
|
|
|
|
// track destruction of an interface group
|
|
void CInterfaceManager::DebugTrackGroupsDestroyed( CInterfaceGroup *pIG )
|
|
{
|
|
// lookup id of the group being destroyed (for debugging)
|
|
int foo = DebugTrackGroupsGetId( pIG );
|
|
|
|
// remove from set
|
|
setInterfaceGroupPtr::iterator it = _DebugTrackGroupSet.find( pIG );
|
|
if( it == _DebugTrackGroupSet.end() )
|
|
{
|
|
nldebug( "AJM DEBUG: Interface Group %x Destroyed twice", pIG );
|
|
return;
|
|
}
|
|
_DebugTrackGroupSet.erase( pIG );
|
|
|
|
// remove from map and increment destroy counter
|
|
_DebugTrackGroupMap.erase(pIG);
|
|
_DebugTrackGroupDestroyCount++;
|
|
}
|
|
|
|
// display the count of undestroyed interface groups
|
|
void CInterfaceManager::DebugTrackGroupsDump()
|
|
{
|
|
// dump groups
|
|
nldebug( "AJM DEBUG: %d Interface Groups remaining", _DebugTrackGroupCreateCount-_DebugTrackGroupDestroyCount );
|
|
|
|
FOREACH( itIG, mapInterfaceGroupPtr2Int, _DebugTrackGroupMap )
|
|
{
|
|
nldebug( " %d", itIG->second );
|
|
}
|
|
}
|
|
|
|
// return the index for an interface group
|
|
int CInterfaceManager::DebugTrackGroupsGetId( CInterfaceGroup *pIG )
|
|
{
|
|
mapInterfaceGroupPtr2Int::iterator it = _DebugTrackGroupMap.find( pIG );
|
|
if( it != _DebugTrackGroupMap.end() )
|
|
return it->second;
|
|
return -1;
|
|
}
|
|
|
|
#endif // AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceManager::CInterfaceManager()
|
|
{
|
|
_Instance = this;
|
|
_DbRootNode = new CCDBNodeBranch("ROOT");
|
|
_ScreenW = _ScreenH = 0;
|
|
_LastInGameScreenW = _LastInGameScreenH = 0;
|
|
_Pointer = NULL;
|
|
_DescTextTarget = NULL;
|
|
_GlobalColor = CRGBA(255,255,255,255);
|
|
_GlobalColorForContent = _GlobalColor;
|
|
_ContentAlpha = 255;
|
|
_ContainerAlpha = 255;
|
|
_GlobalContentAlpha = 255;
|
|
_GlobalContainerAlpha = 255;
|
|
_GlobalRolloverFactorContent = 255;
|
|
_GlobalRolloverFactorContainer = 255;
|
|
_MouseOverWindow= false;
|
|
_MouseHandlingEnabled= true;
|
|
_ConfigLoaded = false;
|
|
_LogState = false;
|
|
_KeysLoaded = false;
|
|
_RProp = NULL;
|
|
_GProp = NULL;
|
|
_BProp = NULL;
|
|
_AProp = NULL;
|
|
_AlphaRolloverSpeedDB = NULL;
|
|
_NeutralColor = NULL;
|
|
_WarningColor = NULL;
|
|
_ErrorColor = NULL;
|
|
_EmotesInitialized = false;
|
|
|
|
// context help
|
|
_DeltaTimeStopingContextHelp= 0;
|
|
_MaxTimeStopingContextHelp= 0.2f;
|
|
_LastXContextHelp= -10000;
|
|
_LastYContextHelp= -10000;
|
|
|
|
// Global initialization
|
|
// *********************
|
|
|
|
|
|
//init the input handler through the parsing of a config file
|
|
CInputHandlerManager *InputHandlerManager = CInputHandlerManager::getInstance();
|
|
string filename = CPath::lookup(ClientCfg.XMLInputFile, false);
|
|
if (!filename.empty())
|
|
InputHandlerManager->readInputConfigFile(filename);
|
|
|
|
// Interface Manager init
|
|
_ViewRenderer.checkNewScreenSize();
|
|
_ViewRenderer.init();
|
|
|
|
_CurrentMode = 0;
|
|
|
|
_InGame = false;
|
|
|
|
_LocalSyncActionCounter= 0;
|
|
// 4Bits counter.
|
|
_LocalSyncActionCounterMask= 15;
|
|
|
|
for(uint i=0;i<CHARACTERISTICS::NUM_CHARACTERISTICS;i++)
|
|
{
|
|
_CurrentPlayerCharac[i]= 0;
|
|
}
|
|
|
|
_CheckMailNode = NULL;
|
|
_CheckForumNode = NULL;
|
|
_UpdateWeatherTime = 0;
|
|
|
|
_ContextHelpActive = true;
|
|
|
|
_DBB_UI_DUMMY = NULL;
|
|
_DB_UI_DUMMY_QUANTITY = NULL;
|
|
_DB_UI_DUMMY_QUALITY = NULL;
|
|
_DB_UI_DUMMY_SHEET = NULL;
|
|
_DB_UI_DUMMY_NAMEID = NULL;
|
|
_DB_UI_DUMMY_ENCHANT = NULL;
|
|
_DB_UI_DUMMY_SLOT_TYPE = NULL;
|
|
_DB_UI_DUMMY_PHRASE = NULL;
|
|
_DB_UI_DUMMY_WORNED = NULL;
|
|
_DB_UI_DUMMY_PREREQUISIT_VALID = NULL;
|
|
_DB_UI_DUMMY_FACTION_TYPE = NULL;
|
|
|
|
#ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
_DebugTrackGroupSet.clear();
|
|
_DebugTrackGroupMap.clear();
|
|
_DebugTrackGroupCreateCount = 0;
|
|
_DebugTrackGroupDestroyCount = 0;
|
|
#endif // AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceManager::~CInterfaceManager()
|
|
{
|
|
reset(); // to flush IDStringWaiters
|
|
|
|
//delete the interface group
|
|
for (uint32 i = 0; i < _MasterGroups.size(); ++i)
|
|
{
|
|
delete _MasterGroups[i].Group;
|
|
}
|
|
_ParentPositionsMap.clear();
|
|
_ParentSizesMap.clear();
|
|
_ParentSizesMaxMap.clear();
|
|
_LuaClassAssociation.clear();
|
|
_Templates.clear();
|
|
_Instance = NULL;
|
|
|
|
if (_DbRootNode)
|
|
{
|
|
delete _DbRootNode;
|
|
_DbRootNode = NULL;
|
|
}
|
|
|
|
// release the local string mapper
|
|
delete _UIStringMapper;
|
|
_UIStringMapper = NULL;
|
|
|
|
// release the database observers
|
|
releaseServerToLocalAutoCopyObservers();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::reset()
|
|
{
|
|
_ViewRenderer.reset();
|
|
_CtrlsUnderPointer.clear();
|
|
_CurCtrlContextHelp = "";
|
|
_ViewsUnderPointer.clear();
|
|
_GroupsUnderPointer.clear();
|
|
_CaptureKeyboard = NULL;
|
|
_OldCaptureKeyboard = NULL;
|
|
setCapturePointerLeft(NULL);
|
|
setCapturePointerRight(NULL);
|
|
_ActiveAnims.clear();
|
|
for (uint32 i = 0; i < _IDStringWaiters.size(); ++i)
|
|
delete _IDStringWaiters[i];
|
|
_IDStringWaiters.clear();
|
|
CGroupFrame::resetDisplayTypes();
|
|
|
|
_NeutralColor = NULL;
|
|
_WarningColor = NULL;
|
|
_ErrorColor = NULL;
|
|
_RProp = NULL;
|
|
_GProp = NULL;
|
|
_BProp = NULL;
|
|
_AProp = NULL;
|
|
_AlphaRolloverSpeedDB = NULL;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// unhook from observers we are tangled up in
|
|
void CInterfaceManager::releaseServerToLocalAutoCopyObservers()
|
|
{
|
|
ServerToLocalAutoCopyInventory.release();
|
|
ServerToLocalAutoCopyExchange.release();
|
|
ServerToLocalAutoCopyContextMenu.release();
|
|
ServerToLocalAutoCopySkillPoints.release();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::resetShardSpecificData()
|
|
{
|
|
_LocalSyncActionCounter= 0;
|
|
CGroupSkills::InhibitSkillUpFX = true;
|
|
CBarManager::getInstance()->resetShardSpecificData();
|
|
CBotChatManager::getInstance()->setCurrPage(NULL);
|
|
|
|
CSPhraseManager *pPM= CSPhraseManager::getInstance();
|
|
pPM->setEquipInvalidation(0, 0);
|
|
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(getElementFromId(WIN_TEMPINV));
|
|
if (pGC != NULL)
|
|
pGC->setActive(false);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::destroy ()
|
|
{
|
|
delete _Instance;
|
|
_Instance = NULL;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::initLogin()
|
|
{
|
|
// Init LUA Scripting
|
|
initLUA();
|
|
|
|
// Create String mapper
|
|
if (_UIStringMapper == NULL)
|
|
_UIStringMapper = CStringMapper::createLocalMapper();
|
|
|
|
// Clear the action manager
|
|
Actions.clear();
|
|
EditActions.clear();
|
|
|
|
// Register action in the action manager
|
|
ActionsContext.addActionsManager(&Actions, "");
|
|
ActionsContext.addActionsManager(&EditActions, RZ_CATEGORY_EDIT);
|
|
|
|
|
|
if (ClientCfg.XMLLoginInterfaceFiles.size()==0)
|
|
{
|
|
nlinfo("no xml login config files in client.cfg");
|
|
return;
|
|
}
|
|
|
|
nldebug("Textures Login Interface");
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesLoginInterface.begin(), end = ClientCfg.TexturesLoginInterface.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures Login Interface: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", false);
|
|
}
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesLoginInterfaceDXTC.begin(), end = ClientCfg.TexturesLoginInterfaceDXTC.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures Login Interface DXTC: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", true);
|
|
}
|
|
|
|
parseInterface (ClientCfg.XMLLoginInterfaceFiles, false);
|
|
|
|
updateAllLocalisedElements();
|
|
|
|
activateMasterGroup ("ui:login", true);
|
|
|
|
{
|
|
initActions();
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::uninitLogin()
|
|
{
|
|
|
|
activateMasterGroup ("ui:login", false);
|
|
|
|
removeAll();
|
|
reset();
|
|
|
|
_Pointer = NULL;
|
|
|
|
CInterfaceLink::removeAllLinks();
|
|
|
|
ICDBNode::CTextId textId("UI");
|
|
_DbRootNode->removeNode(textId);
|
|
|
|
{
|
|
uninitActions();
|
|
}
|
|
|
|
// Close LUA Scripting
|
|
uninitLUA();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::initOutGame()
|
|
{
|
|
// create String mapper
|
|
if (_UIStringMapper == NULL)
|
|
_UIStringMapper = CStringMapper::createLocalMapper();
|
|
|
|
// Clear the action manager
|
|
Actions.clear();
|
|
EditActions.clear();
|
|
|
|
// Register action in the action manager
|
|
ActionsContext.addActionsManager(&Actions, "");
|
|
ActionsContext.addActionsManager(&EditActions, RZ_CATEGORY_EDIT);
|
|
|
|
// Init LUA Scripting
|
|
initLUA();
|
|
|
|
if (ClientCfg.SelectCharacter != -1)
|
|
return;
|
|
|
|
{
|
|
if (SoundMngr != NULL)
|
|
{
|
|
NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
|
|
pMixer->loadSampleBank(false, "ui_outgame");
|
|
CVector initpos ( 0.0f, 0.0f, 0.0f );
|
|
pMixer->setListenerPos(initpos);
|
|
}
|
|
}
|
|
|
|
|
|
//NLMEMORY::CheckHeap (true);
|
|
|
|
|
|
if (ClientCfg.XMLOutGameInterfaceFiles.size()==0)
|
|
{
|
|
nlinfo("no xml outgame config files in client.cfg");
|
|
return;
|
|
}
|
|
|
|
nldebug("Textures OutGame Interface");
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesOutGameInterface.begin(), end = ClientCfg.TexturesOutGameInterface.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures OutGame Interface: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", false);
|
|
}
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesOutGameInterfaceDXTC.begin(), end = ClientCfg.TexturesOutGameInterfaceDXTC.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures OutGame Interface DXTC: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", true);
|
|
}
|
|
|
|
parseInterface (ClientCfg.XMLOutGameInterfaceFiles, false);
|
|
|
|
updateAllLocalisedElements();
|
|
|
|
activateMasterGroup ("ui:outgame", true);
|
|
|
|
// if (!ClientCfg.FSHost.empty())
|
|
// {
|
|
// // Hide the Launch Editor button, it works only with a Shard Unifier and web pages
|
|
// CInterfaceElement *elt = getElementFromId("ui:outgame:edit_session_but");
|
|
// elt->setActive(false);
|
|
// }
|
|
|
|
// Init the action manager
|
|
{
|
|
|
|
initActions();
|
|
}
|
|
//NLMEMORY::CheckHeap (true);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::uninitOutGame()
|
|
{
|
|
|
|
if (ClientCfg.SelectCharacter != -1)
|
|
return;
|
|
|
|
disableModalWindow();
|
|
|
|
//_DbRootNode->display("");
|
|
CBotChatManager::getInstance()->setCurrPage(NULL);
|
|
|
|
CInterfaceItemEdition::getInstance()->setCurrWindow(NULL);
|
|
|
|
NLMISC::TTime initStart;
|
|
initStart = ryzomGetLocalTime ();
|
|
if (SoundMngr != NULL)
|
|
{
|
|
NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
|
|
pMixer->unloadSampleBank("ui_outgame");
|
|
}
|
|
//nlinfo ("%d seconds for uninitOutGame", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
|
|
initStart = ryzomGetLocalTime ();
|
|
activateMasterGroup ("ui:outgame", false);
|
|
//nlinfo ("%d seconds for activateMasterGroup", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
initStart = ryzomGetLocalTime ();
|
|
removeAll();
|
|
//nlinfo ("%d seconds for removeAll", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
initStart = ryzomGetLocalTime ();
|
|
reset();
|
|
//nlinfo ("%d seconds for reset", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
// reset the mouse pointer to avoid invalid pointer access
|
|
_Pointer = NULL;
|
|
initStart = ryzomGetLocalTime ();
|
|
CInterfaceLink::removeAllLinks();
|
|
//nlinfo ("%d seconds for removeAllLinks", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
initStart = ryzomGetLocalTime ();
|
|
ICDBNode::CTextId textId("UI");
|
|
_DbRootNode->removeNode(textId);
|
|
//nlinfo ("%d seconds for removeNode", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
|
|
// Init the action manager
|
|
{
|
|
|
|
initStart = ryzomGetLocalTime ();
|
|
uninitActions();
|
|
// nlinfo ("%d seconds for uninitActions", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
}
|
|
|
|
// Close LUA Scripting
|
|
uninitLUA();
|
|
|
|
//NLMEMORY::CheckHeap (true);
|
|
}
|
|
|
|
|
|
void badXMLParseMessageBox()
|
|
{
|
|
NL3D::UDriver::TMessageBoxId ret = Driver->systemMessageBox( "Interface XML reading failed!\n"
|
|
"Some XML files are corrupted and may have been removed.\n"
|
|
"Ryzom may need to be restarted to run properly.\n"
|
|
"Would you like to quit now?",
|
|
"XML reading failed!",
|
|
NL3D::UDriver::yesNoType,
|
|
NL3D::UDriver::exclamationIcon);
|
|
if (ret == NL3D::UDriver::yesId)
|
|
{
|
|
extern void quitCrashReport ();
|
|
quitCrashReport ();
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::initInGame()
|
|
{
|
|
loginFinished = true;
|
|
_LogState = false;
|
|
|
|
// Whole initInGame profile
|
|
NLMISC::TTime initStart;
|
|
initStart = ryzomGetLocalTime ();
|
|
|
|
// Init LUA Scripting
|
|
initLUA();
|
|
|
|
// create the _UIStringMapper
|
|
if (_UIStringMapper == NULL)
|
|
_UIStringMapper = CStringMapper::createLocalMapper();
|
|
|
|
// Clear the action manager
|
|
Actions.clear();
|
|
EditActions.clear();
|
|
|
|
// Register action in the action manager
|
|
ActionsContext.addActionsManager(&Actions, "");
|
|
ActionsContext.addActionsManager(&EditActions, RZ_CATEGORY_EDIT);
|
|
|
|
|
|
if (SoundMngr != NULL)
|
|
{
|
|
NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
|
|
pMixer->loadSampleBank(false, "ui_ingame");
|
|
}
|
|
|
|
|
|
// NLMEMORY::CheckHeap (true);
|
|
|
|
if (ClientCfg.XMLInterfaceFiles.size()==0)
|
|
{
|
|
nlinfo("no xml config files in client.cfg");
|
|
return;
|
|
}
|
|
|
|
// Textures
|
|
loadIngameInterfaceTextures();
|
|
|
|
// NLMEMORY::CheckHeap (true);
|
|
|
|
// Skill Manager Init
|
|
CSkillManager *pSM = CSkillManager::getInstance();
|
|
pSM->initInGame();
|
|
|
|
// SBrick Manager Init
|
|
CSBrickManager *pSBM = CSBrickManager::getInstance();
|
|
pSBM->initInGame();
|
|
pSM->initTitles();
|
|
|
|
// SPhrase Manager DB Init (BEFORE loading). Must be init AFTER skill and brick init
|
|
CSPhraseManager *pPM= CSPhraseManager::getInstance();
|
|
pPM->initInGame();
|
|
|
|
// UI & keys
|
|
loadUI();
|
|
loadKeys();
|
|
|
|
// Initialize armour color (config.xml)
|
|
CDBCtrlSheet::initArmourColors();
|
|
|
|
// Initialize inventory manager : link to DB and to interface element so must be here
|
|
getInventory().init();
|
|
// Same for temp inventory manager
|
|
CTempInvManager::getInstance();
|
|
// Initialize guild manager
|
|
CGuildManager::getInstance();
|
|
|
|
// NLMEMORY::CheckHeap (true);
|
|
|
|
//init chat output
|
|
ChatDisplayer = new CChatDisplayer;
|
|
g_log.addDisplayer (ChatDisplayer);
|
|
NLMISC::ErrorLog->addDisplayer (ChatDisplayer);
|
|
NLMISC::WarningLog->addDisplayer (ChatDisplayer);
|
|
NLMISC::InfoLog->addDisplayer (ChatDisplayer);
|
|
NLMISC::DebugLog->addDisplayer (ChatDisplayer);
|
|
NLMISC::AssertLog->addDisplayer (ChatDisplayer);
|
|
|
|
// load bot chat datas
|
|
//CBotChat::init();
|
|
|
|
// init the bot chat
|
|
nlassert (BotChatPageAll == NULL);
|
|
BotChatPageAll = new CBotChatPageAll;
|
|
BotChatPageAll->init();
|
|
|
|
// NLMEMORY::CheckHeap (true);
|
|
|
|
// init the list of people
|
|
PeopleInterraction.init();
|
|
|
|
// flush system msg buffer
|
|
for( uint i=0; i<PeopleInterraction.SystemMessageBuffer.size(); ++i )
|
|
{
|
|
displaySystemInfo(PeopleInterraction.SystemMessageBuffer[i].Str, PeopleInterraction.SystemMessageBuffer[i].Cat);
|
|
}
|
|
PeopleInterraction.SystemMessageBuffer.clear();
|
|
|
|
// Init macro manager
|
|
CMacroCmdManager::getInstance()->initInGame();
|
|
|
|
{
|
|
H_AUTO( RZUpdAll )
|
|
|
|
updateAllLocalisedElements(); // To init all things
|
|
}
|
|
|
|
// Interface config
|
|
loadInterfaceConfig();
|
|
|
|
// Must do extra init for people interaction after load
|
|
PeopleInterraction.initAfterLoad();
|
|
|
|
//CBotChatUI::refreshActiveWindows(); // bot chat windows are saved too..
|
|
|
|
activateMasterGroup ("ui:interface", true);
|
|
|
|
// Update the time in the ui database
|
|
_CheckMailNode = getDbProp("UI:VARIABLES:MAIL_WAITING");
|
|
_CheckForumNode = getDbProp("UI:VARIABLES:FORUM_UPDATED");
|
|
|
|
// Init the action manager
|
|
{
|
|
|
|
initActions();
|
|
}
|
|
_InGame = true;
|
|
|
|
// Init bubble manager
|
|
InSceneBubbleManager.init();
|
|
|
|
// Init Memory Bar for phraseManager. DB and ctrl gray state
|
|
pPM->updateMemoryBar();
|
|
|
|
// Init emotes
|
|
_EmotesInitialized = false;
|
|
initEmotes();
|
|
|
|
// init chat manager
|
|
ChatMngr.initInGame();
|
|
|
|
// Init FlyingText manager
|
|
FlyingTextManager.initInGame();
|
|
|
|
// Init Bar Manager (HP, SAP etc... Bars)
|
|
CBarManager::getInstance()->initInGame();
|
|
|
|
// Init interface props linked to client time
|
|
initClientTime();
|
|
|
|
// Whole initInGame profile
|
|
nlinfo ("%d seconds for initInGame", (uint32)(ryzomGetLocalTime ()-initStart)/1000);
|
|
|
|
// reset the compass target
|
|
CGroupCompas *gc = dynamic_cast<CGroupCompas *>(getElementFromId("ui:interface:compass"));
|
|
if (gc && gc->isSavedTargetValid())
|
|
{
|
|
gc->setTarget(gc->getSavedTarget());
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::loadIngameInterfaceTextures()
|
|
{
|
|
nldebug("Textures Ingame Interface");
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesInterface.begin(), end = ClientCfg.TexturesInterface.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures Ingame Interface: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", false);
|
|
}
|
|
|
|
for (vector<string>::iterator it = ClientCfg.TexturesInterfaceDXTC.begin(), end = ClientCfg.TexturesInterfaceDXTC.end(); it != end; ++it)
|
|
{
|
|
nldebug("Textures Ingame Interface DXTC: %s", (*it).c_str());
|
|
loadTextures(*it + ".tga", *it + ".txt", true);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::loadUI()
|
|
{
|
|
// Copy the array of file to load
|
|
vector<string> xmlFilesToParse = getInGameXMLInterfaceFiles();
|
|
|
|
if (!parseInterface (xmlFilesToParse, false))
|
|
{
|
|
badXMLParseMessageBox();
|
|
}
|
|
|
|
configureQuitDialogBox();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::configureQuitDialogBox()
|
|
{
|
|
// Configure the quit dialog box according to the server
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
string quitDialogMainStr = "ui:interface:quit_dialog";
|
|
string quitDialogStr = quitDialogMainStr + ":indent_middle";
|
|
CInterfaceGroup *quitDlg = dynamic_cast<CInterfaceGroup*>(pIM->getElementFromId(quitDialogStr));
|
|
if (quitDlg)
|
|
{
|
|
CInterfaceElement *eltRet, *eltQuit, *eltQuitNow;
|
|
eltRet = quitDlg->getElement(quitDialogStr+":return_mainland");
|
|
eltQuit = quitDlg->getElement(quitDialogStr+":ryzom");
|
|
eltQuitNow = quitDlg->getElement(quitDialogStr+":ryzom_now");
|
|
sint buttonDeltaY;
|
|
fromString(getDefine("quit_button_delta_y"), buttonDeltaY);
|
|
extern R2::TUserRole UserRoleInSession;
|
|
|
|
bool sessionOwner = (R2::getEditor().getMode() != R2::CEditor::NotInitialized && R2::getEditor().getDMC().getEditionModule().isSessionOwner());
|
|
|
|
// Show Launch Editor if not in editor mode
|
|
CInterfaceElement *eltCancel = quitDlg->getElement(quitDialogStr+":cancel");
|
|
CInterfaceElement *eltEdit = quitDlg->getElement(quitDialogStr+":launch_editor");
|
|
if (eltEdit)
|
|
{
|
|
if (UserRoleInSession != R2::TUserRole::ur_editor && !sessionOwner)
|
|
{
|
|
eltEdit->setY(buttonDeltaY);
|
|
eltEdit->setActive(true);
|
|
|
|
if (eltCancel)
|
|
(safe_cast<CCtrlTextButton*>(eltCancel))->setText(CI18N::get("uittQuitCancel"));
|
|
}
|
|
else
|
|
{
|
|
eltEdit->setY(0); // prevent from displaying a gap between two shown buttons
|
|
eltEdit->setActive(false);
|
|
|
|
if (eltCancel)
|
|
(safe_cast<CCtrlTextButton*>(eltCancel))->setText(sessionOwner ? CI18N::get("uittQuitCancel") : CI18N::get("uittQuitCancelEditor"));
|
|
}
|
|
}
|
|
|
|
// Other buttons
|
|
if (IsInRingSession || (ClientCfg.Local && ClientCfg.R2EDEnabled))
|
|
{
|
|
// display "return to mainland", unless we are the scenario owner (player or 'aventure master')
|
|
if (eltRet)
|
|
{
|
|
if (!sessionOwner || R2::getEditor().getMode()==R2::CEditor::EditionMode)
|
|
{
|
|
//eltRet->setY(buttonDeltaY);
|
|
const char *textLabel = (UserRoleInSession == R2::TUserRole::ur_editor) ? "uittLeaveEditor" : "uittReturnToMainland";
|
|
(safe_cast<CCtrlTextButton*>(eltRet))->setText(CI18N::get(textLabel));
|
|
eltRet->setY(buttonDeltaY);
|
|
eltRet->setActive(true); // show Return to Mainland / PLAY
|
|
}
|
|
else
|
|
{
|
|
eltRet->setY(0);
|
|
// when an owner of the session, there's an additionnal 'stop' button
|
|
eltRet->setActive(false);
|
|
}
|
|
}
|
|
if (eltQuit)
|
|
{
|
|
eltQuit->setY(0);
|
|
eltQuit->setActive(false);
|
|
}
|
|
if (eltQuitNow)
|
|
{
|
|
eltQuitNow->setY(buttonDeltaY);
|
|
eltQuitNow->setActive(true); // show Quit (Now)
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (eltRet)
|
|
{
|
|
eltRet->setY(0); // prevent from displaying a gap between two shown buttons
|
|
eltRet->setActive(false);
|
|
}
|
|
if (eltQuit)
|
|
{
|
|
eltQuit->setY(buttonDeltaY);
|
|
eltQuit->setActive(true); // show Quit (with progress bar)
|
|
}
|
|
if (eltQuitNow)
|
|
{
|
|
eltQuitNow->setY(0);
|
|
eltQuitNow->setActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make all controls have the same size
|
|
CInterfaceGroup *quitDlgMain = dynamic_cast<CInterfaceGroup*>(pIM->getElementFromId(quitDialogMainStr));
|
|
if ( quitDlgMain )
|
|
{
|
|
|
|
quitDlgMain->invalidateCoords();
|
|
for (uint k = 0; k < 3; ++k)
|
|
{
|
|
quitDlgMain->updateCoords(); // calculate the width of the text buttons
|
|
}
|
|
}
|
|
const std::vector<CCtrlBase*>& controls = quitDlg->getControls();
|
|
sint32 biggestWidth = 0;
|
|
for ( std::vector<CCtrlBase*>::const_iterator ic=controls.begin(); ic!=controls.end(); ++ic )
|
|
{
|
|
CCtrlTextButton *ctb = dynamic_cast<CCtrlTextButton*>(*ic);
|
|
if ( ! ctb )
|
|
continue;
|
|
|
|
if ( ctb->getW() > biggestWidth )
|
|
biggestWidth = ctb->getW();
|
|
}
|
|
for ( std::vector<CCtrlBase*>::const_iterator ic=controls.begin(); ic!=controls.end(); ++ic )
|
|
{
|
|
CCtrlTextButton *ctb = dynamic_cast<CCtrlTextButton*>(*ic);
|
|
if ( ! ctb )
|
|
continue;
|
|
|
|
ctb->setWMin( biggestWidth );
|
|
}
|
|
|
|
if ( quitDlgMain )
|
|
{
|
|
|
|
quitDlgMain->invalidateCoords();
|
|
for (uint k = 0; k < 3; ++k)
|
|
{
|
|
quitDlgMain->updateCoords(); // calculate the width of the text buttons
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::loadKeys()
|
|
{
|
|
if (ClientCfg.R2EDEnabled) // in R2ED mode the CEditor class deals with it
|
|
return;
|
|
|
|
CMacroCmdManager::getInstance()->removeAllMacros();
|
|
|
|
vector<string> xmlFilesToParse;
|
|
|
|
// Does the keys file exist ?
|
|
string userKeyFileName = "save/keys_"+PlayerSelectedFileName+".xml";
|
|
if (CFile::fileExists(userKeyFileName) && CFile::getFileSize(userKeyFileName) > 0)
|
|
{
|
|
// Load the user key file
|
|
xmlFilesToParse.push_back (userKeyFileName);
|
|
}
|
|
// Load the default key (but don't replace existings bounds, see keys.xml "key_def_no_replace")
|
|
xmlFilesToParse.push_back ("keys.xml");
|
|
|
|
if (!parseInterface (xmlFilesToParse, true))
|
|
{
|
|
badXMLParseMessageBox();
|
|
}
|
|
|
|
_KeysLoaded = true;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::loadInterfaceConfig()
|
|
{
|
|
// Load interface.cfg
|
|
if (ClientCfg.R2EDEnabled) // in R2ED mode the CEditor class deals with it
|
|
return;
|
|
|
|
loadConfig ("save/interface_" + PlayerSelectedFileName + ".icfg"); // Invalidate coords of changed groups
|
|
|
|
_ConfigLoaded = true;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::uninitInGame0 ()
|
|
{
|
|
|
|
// Autosave of the keys
|
|
if (_KeysLoaded)
|
|
{
|
|
if (!ClientCfg.R2EDEnabled)
|
|
{
|
|
saveKeys ("save/keys_" + PlayerSelectedFileName + ".xml");
|
|
}
|
|
_KeysLoaded = false;
|
|
}
|
|
|
|
// Autosave of the interface in interface.cfg
|
|
if (_ConfigLoaded)
|
|
{
|
|
if (!ClientCfg.R2EDEnabled)
|
|
{
|
|
saveConfig ("save/interface_" + PlayerSelectedFileName + ".icfg");
|
|
}
|
|
_ConfigLoaded = false;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::uninitInGame1 ()
|
|
{
|
|
|
|
// release Bar Manager (HP, SAP etc... Bars)
|
|
CBarManager::getInstance()->releaseInGame();
|
|
|
|
// release FlyingTextManager
|
|
FlyingTextManager.releaseInGame();
|
|
|
|
// release chat manager
|
|
ChatMngr.releaseInGame();
|
|
|
|
// Reset the chat text manager
|
|
CChatTextManager::getInstance().reset();
|
|
|
|
// release emotes
|
|
uninitEmotes();
|
|
|
|
// release bubble manager
|
|
InSceneBubbleManager.release();
|
|
|
|
// kill chat displayer
|
|
if( ChatDisplayer )
|
|
{
|
|
DebugLog->removeDisplayer (ChatDisplayer);
|
|
InfoLog->removeDisplayer (ChatDisplayer);
|
|
WarningLog->removeDisplayer (ChatDisplayer);
|
|
ErrorLog->removeDisplayer (ChatDisplayer);
|
|
AssertLog->removeDisplayer (ChatDisplayer);
|
|
g_log.removeDisplayer(ChatDisplayer);
|
|
delete ChatDisplayer;
|
|
ChatDisplayer = NULL;
|
|
}
|
|
|
|
// Release inventory manager
|
|
CInventoryManager::releaseInstance();
|
|
// Same for temp inventory manager
|
|
CTempInvManager::releaseInstance();
|
|
// Release guild manager
|
|
CGuildManager::release();
|
|
|
|
// release bot chat and manager
|
|
CBotChatManager::getInstance()->setCurrPage(NULL);
|
|
delete BotChatPageAll;
|
|
BotChatPageAll = NULL;
|
|
CBotChatManager::releaseInstance();
|
|
|
|
//release CInterfaceItemEdition
|
|
CInterfaceItemEdition::getInstance()->setCurrWindow(NULL);
|
|
CInterfaceItemEdition::releaseInstance();
|
|
|
|
// release task bar manager
|
|
CTaskBarManager::releaseInstance();
|
|
|
|
// People inetrraction release
|
|
PeopleInterraction.release();
|
|
|
|
if (SoundMngr != NULL)
|
|
{
|
|
NLSOUND::UAudioMixer *pMixer = SoundMngr->getMixer();
|
|
pMixer->unloadSampleBank("ui_ingame");
|
|
}
|
|
|
|
// disable the game_quitting modal window
|
|
disableModalWindow();
|
|
|
|
// Remove all interface objects (containers, groups, variables, defines, ...)
|
|
activateMasterGroup ("ui:interface", false);
|
|
removeAll();
|
|
reset();
|
|
CInterfaceLink::removeAllLinks();
|
|
|
|
// Release DDX manager, before DB remove
|
|
CDDXManager::getInstance()->release();
|
|
|
|
// Release client time, before DB remove
|
|
releaseClientTime();
|
|
|
|
// remove DB entry
|
|
ICDBNode::CTextId textId("UI");
|
|
_DbRootNode->removeNode(textId);
|
|
|
|
// Uninit the action manager
|
|
{
|
|
|
|
uninitActions();
|
|
}
|
|
|
|
// uninit phrase mgr
|
|
CSPhraseManager *pPM = CSPhraseManager::getInstance();
|
|
pPM->reset();
|
|
CSPhraseManager::releaseInstance(); // must release before BrickManager, SkillManager
|
|
|
|
// uninit brick manager
|
|
// Don't release the instance because must not lost brick map and data
|
|
CSBrickManager::getInstance()->uninitInGame();
|
|
|
|
// Uninit skill manager (after phrase mgr)
|
|
// AJM don't release SkillManager, else impulse msg update guild title will crash :(
|
|
CSkillManager::getInstance()->uninitTitles();
|
|
|
|
// Uninit macro manager
|
|
CMacroCmdManager::getInstance()->uninitInGame();
|
|
|
|
// Release interface help
|
|
CInterfaceHelp::release();
|
|
|
|
// Release guild manager
|
|
CGuildManager::release();
|
|
|
|
// Close LUA Scripting
|
|
uninitLUA();
|
|
|
|
_InGame = false;
|
|
_NeutralColor = NULL;
|
|
_WarningColor = NULL;
|
|
_ErrorColor = NULL;
|
|
_AlphaRolloverSpeedDB = NULL;
|
|
_RProp = NULL;
|
|
_GProp = NULL;
|
|
_BProp = NULL;
|
|
_AProp = NULL;
|
|
|
|
#ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS
|
|
CInterfaceManager::getInstance()->DebugTrackGroupsDump();
|
|
|
|
// NLMEMORY::ReportMemoryLeak();
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::flushDebugWindow()
|
|
{
|
|
if (ChatDisplayer != NULL)
|
|
ChatDisplayer->update();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::updateFrameEvents()
|
|
{
|
|
|
|
H_AUTO_USE ( RZ_Client_Update_Frame_Events )
|
|
|
|
flushDebugWindow();
|
|
|
|
// Handle anims done in 2 times because some AH can add or remove anims
|
|
// First ensure we are working on a safe vector and update all anims
|
|
sint i;
|
|
vector<CInterfaceAnim*> vTmp = _ActiveAnims;
|
|
for (i = 0; i < (sint)vTmp.size(); ++i)
|
|
{
|
|
CInterfaceAnim *pIA = vTmp[i];
|
|
pIA->update();
|
|
}
|
|
CCDBNodeBranch::flushObserversCalls();
|
|
//
|
|
// Next : Test if we have to remove anims
|
|
for (i = 0; i < (sint)_ActiveAnims.size(); ++i)
|
|
{
|
|
CInterfaceAnim *pIA = _ActiveAnims[i];
|
|
if (pIA->isFinished())
|
|
{
|
|
_ActiveAnims.erase (_ActiveAnims.begin()+i);
|
|
--i;
|
|
}
|
|
}
|
|
//
|
|
CCDBNodeBranch::flushObserversCalls();
|
|
|
|
// Handle waiting texts from server
|
|
processServerIDString();
|
|
|
|
if (_InGame)
|
|
{
|
|
// Execute current macro
|
|
CMacroCmdManager::getInstance()->updateMacroExecution();
|
|
|
|
// Update guild handling (check if we have to rebuild)
|
|
CGuildManager::getInstance()->update();
|
|
|
|
// Update contact list with incoming server string ids
|
|
PeopleInterraction.updateWaitingContacts();
|
|
|
|
// Connect and receive/send to the yubo chat
|
|
checkYuboChat();
|
|
|
|
// Update string if some waiting
|
|
CEncyclopediaManager::getInstance()->updateAllFrame();
|
|
|
|
// Setup the weather setup in the player's map
|
|
if ((T0 - _UpdateWeatherTime) > (1 * 5 * 1000))
|
|
{
|
|
_UpdateWeatherTime = T0;
|
|
ucstring str = CI18N::get ("uiTheSeasonIs") +
|
|
CI18N::get ("uiSeason"+toStringEnum(computeCurrSeason())) +
|
|
CI18N::get ("uiAndTheWeatherIs") +
|
|
CI18N::get (WeatherManager.getCurrWeatherState().LocalizedName);
|
|
|
|
|
|
CViewText *pVT = dynamic_cast<CViewText*>(getElementFromId("ui:interface:map:content:map_content:weather"));
|
|
if (pVT != NULL)
|
|
pVT->setText(str);
|
|
|
|
// The date feature is temporarily disabled
|
|
str.clear();
|
|
|
|
// numeric version
|
|
//str = CI18N::get("uiDate");
|
|
//str += toString("%04d", RT.getRyzomYear()) + "/";
|
|
//str += toString("%01d", RT.getRyzomCycle()+1) + " : ";
|
|
//str += toString("%02d", RT.getRyzomMonthInCurrentCycle()+1) + "/";
|
|
//str += toString("%02d", RT.getRyzomDayOfMonth()+1) + " - "; // Start at 1 for January
|
|
//str += toString("%02d", (sint)RT.getRyzomTime()) + " " + CI18N::get("uiMissionTimerHour");
|
|
|
|
// literal version
|
|
// str = CI18N::get("uiDate");
|
|
str += toString("%02d", (sint)RT.getRyzomTime()) + CI18N::get("uiMissionTimerHour") + " - ";
|
|
str += CI18N::get("ui"+WEEKDAY::toString( (WEEKDAY::EWeekDay)RT.getRyzomDayOfWeek() )) + ", ";
|
|
str += CI18N::get("ui"+MONTH::toString( (MONTH::EMonth)RT.getRyzomMonthInCurrentCycle() )) + " ";
|
|
str += toString("%02d", RT.getRyzomDayOfMonth()+1) + ", ";
|
|
str += CI18N::get("uiAtysianCycle" + toString(RT.getRyzomCycle()+1) + "Ordinal") + " " + CI18N::get("uiAtysianCycle") + " ";
|
|
str += toString("%04d", RT.getRyzomYear());
|
|
|
|
pVT = dynamic_cast<CViewText*>(getElementFromId("ui:interface:map:content:map_content:time"));
|
|
if (pVT != NULL)
|
|
pVT->setText(str);
|
|
|
|
str.clear();
|
|
// Update the clock in the compass if enabled.
|
|
pVT = dynamic_cast<CViewText*>(getElementFromId("ui:interface:compass:clock:time"));
|
|
if (pVT != NULL)
|
|
{
|
|
if (pVT->getActive())
|
|
{
|
|
str = getTimestampHuman("%H:%M");
|
|
pVT->setText(str);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// send clock tick msg to ctrl that are captured
|
|
CEventDescriptorSystem clockTick;
|
|
clockTick.setEventTypeExtended(CEventDescriptorSystem::clocktick);
|
|
if (_CapturePointerLeft)
|
|
{
|
|
_CapturePointerLeft->handleEvent(clockTick);
|
|
}
|
|
if (_CapturePointerRight)
|
|
{
|
|
_CapturePointerRight->handleEvent(clockTick);
|
|
}
|
|
|
|
// and send clock tick msg to ctrl that are registered
|
|
std::vector<CCtrlBase*> clockMsgTarget = _ClockMsgTargets;
|
|
for(std::vector<CCtrlBase*>::iterator it = clockMsgTarget.begin(); it != clockMsgTarget.end(); ++it)
|
|
{
|
|
(*it)->handleEvent(clockTick);
|
|
}
|
|
CCDBNodeBranch::flushObserversCalls();
|
|
|
|
// Update SPhrase manager
|
|
CSPhraseManager *pPM= CSPhraseManager::getInstance();
|
|
pPM->update();
|
|
|
|
// if there's an external lua debugger, update it
|
|
extern void luaDebuggerMainLoop();
|
|
luaDebuggerMainLoop();
|
|
|
|
// handle gc for lua
|
|
if (_LuaState) _LuaState->handleGC();
|
|
|
|
CBGDownloaderAccess::getInstance().update();
|
|
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::updateFrameViews(NL3D::UCamera camera)
|
|
{
|
|
|
|
H_AUTO ( RZ_Interface_updateFrameViews )
|
|
|
|
if (!camera.empty())
|
|
_ViewRenderer.setWorldSpaceFrustum (camera.getFrustum());
|
|
|
|
checkCoords();
|
|
drawViews(camera);
|
|
|
|
// The interface manager may change usual Global setup. reset them.
|
|
TextContext->setShadeColor(CRGBA::Black);
|
|
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceOptions *CInterfaceManager::getOptions(const string &name)
|
|
{
|
|
map<string, NLMISC::CSmartPtr<CInterfaceOptions> >::iterator it = _OptionsMap.find(name);
|
|
if (it == _OptionsMap.end())
|
|
return NULL;
|
|
else
|
|
return it->second;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::runActionHandler (const string &ahCmdLine, CCtrlBase *pCaller, const string &ahUserParams)
|
|
{
|
|
if (ahCmdLine.empty()) return;
|
|
|
|
// Special AH form ("ah:params") ?
|
|
string::size_type i = ahCmdLine.find(':');
|
|
string ahName;
|
|
string ahParams;
|
|
if(i!=string::npos)
|
|
{
|
|
ahName= ahCmdLine.substr(0, i);
|
|
ahParams= ahCmdLine.substr(i+1);
|
|
}
|
|
else
|
|
{
|
|
ahName= ahCmdLine;
|
|
}
|
|
|
|
// Replace params if defined
|
|
if(!ahUserParams.empty())
|
|
ahParams= ahUserParams;
|
|
|
|
// Execute the action hanlder
|
|
CActionHandlerFactoryManager *pAHFM = CActionHandlerFactoryManager::getInstance();
|
|
map<string, IActionHandler*>::iterator it = pAHFM->FactoryMap.find (ahName);
|
|
if (it == pAHFM->FactoryMap.end())
|
|
{
|
|
nlwarning ("not found action handler : %s",ahName.c_str());
|
|
return;
|
|
}
|
|
IActionHandler *pAH = it->second;
|
|
pAH->execute (pCaller, ahParams);
|
|
|
|
// Quick Help
|
|
const string submitQuickHelp = "submit_quick_help";
|
|
it = pAHFM->FactoryMap.find(submitQuickHelp);
|
|
if(it == pAHFM->FactoryMap.end())
|
|
{
|
|
nlwarning ("not found action handler : %s", submitQuickHelp.c_str());
|
|
return;
|
|
}
|
|
pAH = it->second;
|
|
const std::string event = ahName + ":" + ahParams;
|
|
pAH->execute(NULL, event);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::runActionHandler (IActionHandler *pAH, CCtrlBase *pCaller, const std::string &Params)
|
|
{
|
|
if (pAH == NULL)
|
|
{
|
|
nlwarning ("no action handler");
|
|
return;
|
|
}
|
|
pAH->execute (pCaller, Params);
|
|
string AHName = getAHName(pAH);
|
|
|
|
// Quick Help
|
|
const string submitQuickHelp = "submit_quick_help";
|
|
CActionHandlerFactoryManager *pAHFM = CActionHandlerFactoryManager::getInstance();
|
|
map<string, IActionHandler*>::iterator it = pAHFM->FactoryMap.find (AHName);
|
|
it = pAHFM->FactoryMap.find(submitQuickHelp);
|
|
if(it == pAHFM->FactoryMap.end())
|
|
{
|
|
nlwarning ("not found action handler : %s", submitQuickHelp.c_str());
|
|
return;
|
|
}
|
|
pAH = it->second;
|
|
const std::string event = AHName + ":" + Params;
|
|
pAH->execute(NULL, event);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::setupOptions()
|
|
{
|
|
// After parsing options and templates node -> init system options.
|
|
CInterfaceOptions *opt= getOptions("system");
|
|
if(opt)
|
|
{
|
|
// List here all Special options
|
|
_SystemOptions[OptionCtrlSheetGrayColor]= opt->getValue("ctrl_sheet_gray_color");
|
|
_SystemOptions[OptionCtrlTextGrayColor]= opt->getValue("ctrl_text_gray_color");
|
|
_SystemOptions[OptionCtrlSheetRedifyColor]= opt->getValue("ctrl_sheet_redify_color");
|
|
_SystemOptions[OptionCtrlTextRedifyColor]= opt->getValue("ctrl_text_redify_color");
|
|
_SystemOptions[OptionCtrlSheetGreenifyColor]= opt->getValue("ctrl_sheet_greenify_color");
|
|
_SystemOptions[OptionCtrlTextGreenifyColor]= opt->getValue("ctrl_text_greenify_color");
|
|
_SystemOptions[OptionViewTextOverBackColor]= opt->getValue("text_over_back_color");
|
|
_SystemOptions[OptionFont]= opt->getValue("font");
|
|
_SystemOptions[OptionAddCoefFont]= opt->getValue("add_coef_font");
|
|
_SystemOptions[OptionMulCoefAnim]= opt->getValue("mul_coef_anim");
|
|
_SystemOptions[OptionTimeoutBubbles]= opt->getValue("bubbles_timeout");
|
|
_SystemOptions[OptionTimeoutMessages]= opt->getValue("messages_timeout");
|
|
_SystemOptions[OptionTimeoutContext]= opt->getValue("context_timeout");
|
|
_SystemOptions[OptionTimeoutContextHtml]= opt->getValue("context_html_timeout");
|
|
}
|
|
|
|
// Try to change font if any
|
|
string sFont = _SystemOptions[OptionFont].getValStr();
|
|
if ((!sFont.empty()) && (Driver != NULL))
|
|
resetTextContext(sFont.c_str(), true);
|
|
|
|
// Continue to parse the rest of the interface
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::parseInterface (const std::vector<std::string> &xmlFileNames, bool reload, bool isFilename)
|
|
{
|
|
// cache some commonly used db nodes
|
|
_DBB_UI_DUMMY = getDbBranch( "UI:DUMMY" );
|
|
_DB_UI_DUMMY_QUANTITY = getDbProp( "UI:DUMMY:QUANTITY", true );
|
|
_DB_UI_DUMMY_QUALITY = getDbProp( "UI:DUMMY:QUALITY", true );
|
|
_DB_UI_DUMMY_SHEET = getDbProp( "UI:DUMMY:SHEET", true );
|
|
_DB_UI_DUMMY_NAMEID = getDbProp( "UI:DUMMY:NAMEID", true );
|
|
_DB_UI_DUMMY_ENCHANT = getDbProp( "UI:DUMMY:ENCHANT", true );
|
|
_DB_UI_DUMMY_SLOT_TYPE = getDbProp( "UI:DUMMY:SLOT_TYPE", true );
|
|
_DB_UI_DUMMY_PHRASE = getDbProp( "UI:DUMMY:PHRASE", true );
|
|
_DB_UI_DUMMY_WORNED = getDbProp( "UI:DUMMY:WORNED", true );
|
|
_DB_UI_DUMMY_PREREQUISIT_VALID = getDbProp( "UI:DUMMY:PREREQUISIT_VALID", true );
|
|
_DB_UI_DUMMY_FACTION_TYPE = getDbProp( "UI:DUMMY:FACTION_TYPE", true );
|
|
|
|
_DB_UI_DUMMY_QUANTITY->setValue64(0);
|
|
_DB_UI_DUMMY_QUALITY->setValue64(0);
|
|
_DB_UI_DUMMY_SHEET->setValue64(0);
|
|
_DB_UI_DUMMY_NAMEID->setValue64(0);
|
|
_DB_UI_DUMMY_ENCHANT->setValue64(0);
|
|
_DB_UI_DUMMY_SLOT_TYPE->setValue64(0);
|
|
_DB_UI_DUMMY_PHRASE->setValue64(0);
|
|
_DB_UI_DUMMY_WORNED->setValue64(0);
|
|
_DB_UI_DUMMY_PREREQUISIT_VALID->setValueBool(true);
|
|
_DB_UI_DUMMY_FACTION_TYPE->setValue64(0);
|
|
|
|
return CInterfaceParser::parseInterface (xmlFileNames, reload, isFilename);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::loadTextures (const string &textFileName, const string &uvFileName, bool uploadDXTC)
|
|
{
|
|
_ViewRenderer.loadTextures (textFileName, uvFileName, uploadDXTC);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::loadConfig (const string &filename)
|
|
{
|
|
// reset the interface
|
|
vector<string> v;
|
|
if (ClientCfg.R2EDEnabled)
|
|
{
|
|
runProcedure ("proc_reset_r2ed_interface", NULL, v);
|
|
}
|
|
else
|
|
{
|
|
runProcedure ("proc_reset_interface", NULL, v);
|
|
}
|
|
|
|
// By default, consider the reset interface has been set with the current resolution
|
|
{
|
|
uint32 w,h;
|
|
// NB: even if minimzed, getScreenSize() no more return 0 values (return the last setuped screen size)
|
|
_ViewRenderer.getScreenSize(w, h);
|
|
// Windows are positioned according to resolution, and we must backup W/H for the system that move windows when the resolution change
|
|
_LastInGameScreenW= w;
|
|
_LastInGameScreenH= h;
|
|
}
|
|
|
|
// if the config file doesn't exist,just quit
|
|
CIFile f;
|
|
string sFileName;
|
|
sFileName = NLMISC::CPath::lookup (filename, false);
|
|
if (sFileName == "" || !f.open(sFileName))
|
|
return false;
|
|
|
|
|
|
// *** Load the config file
|
|
uint32 nNbMode;
|
|
CInterfaceConfig ic;
|
|
bool lastInGameScreenResLoaded= false;
|
|
try
|
|
{
|
|
sint ver = f.serialVersion(ICFG_STREAM_VERSION);
|
|
|
|
// serial user chats info (serial it before position of windows so that they can be updated properly)
|
|
if (ver >= 1)
|
|
{
|
|
f.serialCheck(uint32('_ICU'));
|
|
if (!PeopleInterraction.loadUserChatsInfos(f))
|
|
{
|
|
nlwarning("Bad user chat saving");
|
|
}
|
|
}
|
|
|
|
// header
|
|
f.serialCheck(uint32('GFCI'));
|
|
f.serial(nNbMode);
|
|
f.serial(_CurrentMode);
|
|
if(ver>=10)
|
|
{
|
|
f.serial(_LastInGameScreenW);
|
|
f.serial(_LastInGameScreenH);
|
|
lastInGameScreenResLoaded= true;
|
|
}
|
|
|
|
// Load All Window configuration of all Modes
|
|
for (uint32 i = 0; i < nNbMode; ++i)
|
|
{
|
|
NLMISC::contReset(_Modes[i]);
|
|
// must create a tmp mem stream because desktop image expect its datas to occupy the whole stream
|
|
// This is because of old system that manipulated desktop image direclty as a mem stream
|
|
CMemStream ms;
|
|
if (!ms.isReading()) ms.invert();
|
|
uint32 length;
|
|
f.serial(length);
|
|
if (length > 0)
|
|
{
|
|
// HACK. if the version is <=2, then the CInterfaceConfig has no serialVersion. append here a 0
|
|
if(ver<=2)
|
|
{
|
|
uint8 *pBuffer = ms.bufferToFill(length+1);
|
|
pBuffer[0]= 0;
|
|
f.serialBuffer(pBuffer+1, length);
|
|
}
|
|
else
|
|
{
|
|
uint8 *pBuffer = ms.bufferToFill(length);
|
|
f.serialBuffer(pBuffer, length);
|
|
}
|
|
}
|
|
ms.seek(0, NLMISC::IStream::begin);
|
|
_Modes[i].serial(ms); // build desktop image from stream
|
|
}
|
|
|
|
// load UI_DB_SAVE_VERSION
|
|
uint32 uiDbSaveVersion= 0; // default to 0 for old version of .icfg
|
|
if(ver>=9)
|
|
{
|
|
f.serial(uiDbSaveVersion);
|
|
}
|
|
|
|
// read database
|
|
ic.streamToDataBase(f, uiDbSaveVersion);
|
|
|
|
|
|
// special for in game: backup last mission because of delayed update
|
|
{
|
|
CCDBNodeLeaf *pNL = getDbProp("UI:SAVE:MISSION_SELECTED", false);
|
|
if (pNL)
|
|
{
|
|
CCDBNodeLeaf *pSelectedMissionBackup = getDbProp("UI:VARIABLES:MISSION_SELECTED_PREV_SESSION", true);
|
|
pSelectedMissionBackup->setValue64(pNL->getValue64());
|
|
}
|
|
}
|
|
//
|
|
|
|
// Deprecated. for Compatibility purpose: Load TaskBar.
|
|
if(ver>=2)
|
|
{
|
|
CTaskBarManager *pTBM= CTaskBarManager::getInstance();
|
|
pTBM->serial(f);
|
|
}
|
|
|
|
// Load user landmarks
|
|
ContinentMngr.serialUserLandMarks(f);
|
|
|
|
CCDBNodeLeaf *pNL = getDbProp( "SERVER:INTERFACES:NB_BONUS_LANDMARKS" );
|
|
if ( pNL )
|
|
{
|
|
ICDBNode::CTextId textId;
|
|
pNL->addObserver( &_LandmarkObs, textId);
|
|
}
|
|
|
|
// Info Windows position.
|
|
if(ver>=5)
|
|
CInterfaceHelp::serialInfoWindows(f);
|
|
else // Default pos
|
|
CInterfaceHelp::resetWindowPos(-100);
|
|
|
|
// Macro On Memory Position
|
|
CSPhraseManager *pPM = CSPhraseManager::getInstance();
|
|
if(ver>=7)
|
|
pPM->serialMacroMemory(f);
|
|
|
|
if(ver>=8)
|
|
CGroupInSceneBubbleManager::serialInSceneBubbleInfo(f);
|
|
|
|
if (ver >= 11)
|
|
{
|
|
if ( ! PeopleInterraction.loadUserDynChatsInfos(f))
|
|
{
|
|
nlwarning("Bad user dyn chat saving");
|
|
}
|
|
}
|
|
}
|
|
catch(const NLMISC::EStream &)
|
|
{
|
|
f.close();
|
|
string sFileNameBackup = sFileName+"backup";
|
|
if (CFile::fileExists(sFileNameBackup))
|
|
CFile::deleteFile(sFileNameBackup);
|
|
CFile::moveFile(sFileNameBackup.c_str(), sFileName.c_str());
|
|
nlwarning("Config loading failed : restore default");
|
|
vector<string> v;
|
|
if (!ClientCfg.R2EDEnabled)
|
|
{
|
|
runProcedure ("proc_reset_interface", NULL, v);
|
|
}
|
|
return false;
|
|
}
|
|
f.close();
|
|
|
|
// *** If saved resolution is different from the current one setuped, must fix positions in _Modes
|
|
if(lastInGameScreenResLoaded)
|
|
{
|
|
// NB: we are typically InGame here (even though the _InGame flag is not yet set)
|
|
// Use the screen size of the config file. Don't update current UI, just _Modes
|
|
moveAllWindowsToNewScreenSize(ClientCfg.Width, ClientCfg.Height, false);
|
|
}
|
|
|
|
// *** apply the current mode
|
|
_Modes[_CurrentMode].toCurrentDesktop();
|
|
|
|
// *** Apply the NPC icon display mode
|
|
CNPCIconCache::getInstance().init(!ClientCfg.R2EDEnabled && getDbProp("UI:SAVE:INSCENE:FRIEND:MISSION_ICON")->getValueBool());
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::CDBLandmarkObs::update(ICDBNode *node)
|
|
{
|
|
uint nbBonusLandmarks = ((CCDBNodeLeaf*)node)->getValue32();
|
|
ContinentMngr.checkNumberOfUserLandmarks( STANDARD_NUM_USER_LANDMARKS + nbBonusLandmarks );
|
|
}
|
|
|
|
|
|
// visitor to send onQuit msg on all element
|
|
class CQuitVisitor : public CInterfaceElementVisitor
|
|
{
|
|
public:
|
|
bool IsR2ED;
|
|
bool BadWindowFound; //
|
|
uint Desktop;
|
|
virtual void visit(CInterfaceElement *elem) { elem->onQuit(); }
|
|
virtual void visitGroup(CInterfaceGroup *group)
|
|
{
|
|
if (!IsR2ED) return;
|
|
if (Desktop != 0) return;
|
|
if (group->getShortId() == "gestionsets")
|
|
{
|
|
if (group->getActive())
|
|
{
|
|
BadWindowFound = true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::saveConfig (const string &filename)
|
|
{
|
|
|
|
CQuitVisitor quitVisitor;
|
|
|
|
quitVisitor.IsR2ED = false;
|
|
if (nlstricmp(NLMISC::CFile::getFilename(filename).substr(0, 5), "r2ed_") == 0)
|
|
{
|
|
quitVisitor.IsR2ED = true;
|
|
}
|
|
quitVisitor.BadWindowFound = false;
|
|
|
|
nlinfo( "Saving interface config : %s", filename.c_str() );
|
|
|
|
COFile f;
|
|
|
|
if (!f.open(filename)) return false;
|
|
|
|
CInterfaceConfig ic;
|
|
|
|
|
|
|
|
// cleanup all desktops
|
|
for(uint k = 0; k < MAX_NUM_MODES; ++k)
|
|
{
|
|
quitVisitor.Desktop = k;
|
|
setMode(k);
|
|
visit(&quitVisitor);
|
|
checkCoords();
|
|
}
|
|
setMode(0);
|
|
setMode(_CurrentMode);
|
|
|
|
if (quitVisitor.BadWindowFound)
|
|
{
|
|
#ifdef NL_DEBUG
|
|
nlassert(0);
|
|
#endif
|
|
// tmp patch : when trying to overwrite the r2ed_ config, if a bad window is found, just do nothing ...
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
_Modes[_CurrentMode].clear();
|
|
if (_Modes[_CurrentMode].isReading()) _Modes[_CurrentMode].invert();
|
|
clearAllEditBox();
|
|
restoreAllContainersBackupPosition();
|
|
ic.interfaceManagerToStream(_Modes[_CurrentMode]);
|
|
*/
|
|
|
|
uint32 i;
|
|
|
|
i = MAX_NUM_MODES;
|
|
try
|
|
{
|
|
f.serialVersion(ICFG_STREAM_VERSION);
|
|
|
|
// serial user chats info (serial it before position of windows so that they can be updated properly)
|
|
f.serialCheck(uint32('_ICU'));
|
|
if (!PeopleInterraction.saveUserChatsInfos(f))
|
|
{
|
|
nlwarning("Config saving failed");
|
|
// couldn't save result so do not continue
|
|
f.close();
|
|
return false;
|
|
}
|
|
|
|
// header
|
|
f.serialCheck(uint32('GFCI'));
|
|
f.serial(i);
|
|
f.serial(_CurrentMode);
|
|
f.serial(_LastInGameScreenW);
|
|
f.serial(_LastInGameScreenH);
|
|
|
|
// Save All Window configuration of all Modes
|
|
for (i = 0; i < MAX_NUM_MODES; ++i)
|
|
{
|
|
// must create a tmp mem stream because desktop image expect its datas to occupy the whole stream
|
|
// This is because of old system that manipulated desktop image direclty as a mem stream
|
|
CMemStream ms;
|
|
if (ms.isReading()) ms.invert();
|
|
_Modes[i].serial(ms);
|
|
uint32 length = ms.length();
|
|
f.serial(length);
|
|
if (length > 0)
|
|
{
|
|
f.serialBuffer(const_cast<uint8 *>(ms.buffer()), length);
|
|
}
|
|
}
|
|
|
|
// write UI_DB_SAVE_VERSION
|
|
uint32 uiDbSaveVersion;
|
|
fromString(getDefine("UI_DB_SAVE_VERSION"), uiDbSaveVersion);
|
|
f.serial(uiDbSaveVersion);
|
|
|
|
// write database
|
|
ic.dataBaseToStream(f);
|
|
|
|
// Deprecated. for Compatibility purpose: Save TaskBar.
|
|
CTaskBarManager *pTBM= CTaskBarManager::getInstance();
|
|
pTBM->serial(f);
|
|
|
|
// Save user landmarks
|
|
ContinentMngr.serialUserLandMarks(f);
|
|
|
|
// Info Windows position.
|
|
CInterfaceHelp::serialInfoWindows(f);
|
|
|
|
// Macro On Memory Position
|
|
CSPhraseManager *pPM = CSPhraseManager::getInstance();
|
|
pPM->serialMacroMemory(f);
|
|
|
|
CGroupInSceneBubbleManager::serialInSceneBubbleInfo(f);
|
|
|
|
if ( ! PeopleInterraction.saveUserDynChatsInfos(f))
|
|
{
|
|
nlwarning("Bad user dyn chat saving");
|
|
return false;
|
|
}
|
|
}
|
|
catch(const NLMISC::EStream &)
|
|
{
|
|
f.close();
|
|
nlwarning("Config saving failed.");
|
|
return false;
|
|
}
|
|
f.close();
|
|
|
|
ContinentMngr.serialFOWMaps();
|
|
|
|
return true;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::checkCoords()
|
|
{
|
|
H_AUTO ( RZ_Interface_validateCoords )
|
|
|
|
uint32 nMasterGroup;
|
|
|
|
{
|
|
H_AUTO ( RZ_Interface_checkCoords )
|
|
|
|
// checkCoords all the windows
|
|
for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::const_iterator itw;
|
|
for (itw = rList.begin(); itw!= rList.end();)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
itw++; // since checkCoords invalidate the iterator, be sure we move to the next one before
|
|
if (pIG->getActive())
|
|
pIG->checkCoords ();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool bRecomputeCtrlUnderPtr = false;
|
|
{
|
|
H_AUTO ( RZ_Interface_updateCoords )
|
|
|
|
// updateCoords all the needed windows
|
|
for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::const_iterator itw;
|
|
for (itw = rList.begin(); itw!= rList.end(); itw++)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
bool updateCoordCalled= false;
|
|
// updateCoords the window only if the master group is his parent and if need it
|
|
// do it until updateCoords() no more invalidate coordinates!!
|
|
while (pIG->getParent()==rMG.Group && (pIG->getInvalidCoords()>0))
|
|
{
|
|
bRecomputeCtrlUnderPtr = true;
|
|
// Update as many pass wanted (3 time for complex resizing, 1 for scroll for example)
|
|
uint numPass= pIG->getInvalidCoords();
|
|
// reset before updateCoords
|
|
pIG->resetInvalidCoords();
|
|
for(uint i=0;i<numPass;i++)
|
|
{
|
|
pIG->updateCoords ();
|
|
}
|
|
updateCoordCalled= true;
|
|
}
|
|
// If the group need to update pos each frame (eg: CGroupInScene),
|
|
// and updateCoords not called
|
|
if(pIG->getParent()==rMG.Group && !updateCoordCalled && pIG->isNeedFrameUpdatePos())
|
|
{
|
|
// This Group will compute the delta to apply.
|
|
pIG->onFrameUpdateWindowPos(0,0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_Pointer != NULL)
|
|
{
|
|
_Pointer->updateCoords();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (bRecomputeCtrlUnderPtr)
|
|
{
|
|
H_AUTO ( RZ_Interface_RecomputeCtrlUnderPtr )
|
|
if (_Pointer)
|
|
{
|
|
sint32 mx = _Pointer->getX();
|
|
sint32 my = _Pointer->getY();
|
|
getViewsUnder (mx, my, _ViewsUnderPointer);
|
|
getCtrlsUnder (mx, my, _CtrlsUnderPointer);
|
|
getGroupsUnder (mx, my, _GroupsUnderPointer);
|
|
CInterfaceGroup *ptr = getWindowUnder (mx, my);
|
|
_WindowUnder = ptr?ptr->getId():"";
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::drawViews(NL3D::UCamera camera)
|
|
{
|
|
{
|
|
H_AUTO ( RZ_Interface_DrawViews_Setup )
|
|
|
|
_ViewRenderer.activateWorldSpaceMatrix (false);
|
|
|
|
CCDBNodeBranch::flushObserversCalls();
|
|
|
|
// If an element has captured the keyboard, make sure it is alway visible (all parent windows active)
|
|
if (_CaptureKeyboard != NULL)
|
|
{
|
|
CCtrlBase *cb = _CaptureKeyboard;
|
|
do
|
|
{
|
|
if (!cb->getActive())
|
|
{
|
|
setCaptureKeyboard(NULL);
|
|
break;
|
|
}
|
|
cb = cb->getParent();
|
|
}
|
|
while (cb);
|
|
}
|
|
// Check if screen size changed
|
|
uint32 w, h;
|
|
_ViewRenderer.checkNewScreenSize ();
|
|
_ViewRenderer.getScreenSize (w, h);
|
|
if ((w != _ScreenW) || (h != _ScreenH))
|
|
{
|
|
// No Op if screen minimized
|
|
if(w!=0 && h!=0 && !_ViewRenderer.isMinimized())
|
|
{
|
|
updateAllLocalisedElements ();
|
|
_ScreenW = w;
|
|
_ScreenH = h;
|
|
}
|
|
}
|
|
|
|
// Update global color from database
|
|
_GlobalColor = CRGBA ( (uint8)getDbProp("UI:SAVE:COLOR:R")->getValue32(),
|
|
(uint8)getDbProp("UI:SAVE:COLOR:G")->getValue32(),
|
|
(uint8)getDbProp("UI:SAVE:COLOR:B")->getValue32(),
|
|
(uint8)getDbProp("UI:SAVE:COLOR:A")->getValue32() );
|
|
_GlobalColorForContent.R = _GlobalColor.R;
|
|
_GlobalColorForContent.G = _GlobalColor.G;
|
|
_GlobalColorForContent.B = _GlobalColor.B;
|
|
_GlobalColorForContent.A = (uint8) (( (uint16) _GlobalColor.A * (uint16) _ContentAlpha) >> 8);
|
|
|
|
// Update global alphaS from database
|
|
_GlobalContentAlpha = (uint8)getDbProp("UI:SAVE:CONTENT_ALPHA")->getValue32();
|
|
_GlobalContainerAlpha = (uint8)getDbProp("UI:SAVE:CONTAINER_ALPHA")->getValue32();
|
|
_GlobalRolloverFactorContent = (uint8)getDbProp("UI:SAVE:CONTENT_ROLLOVER_FACTOR")->getValue32();
|
|
_GlobalRolloverFactorContainer = (uint8)getDbProp("UI:SAVE:CONTAINER_ROLLOVER_FACTOR")->getValue32();
|
|
|
|
// Update Player characteristics (for Item carac requirement Redifying)
|
|
nlctassert(CHARACTERISTICS::NUM_CHARACTERISTICS==8);
|
|
for (uint i=0; i<CHARACTERISTICS::NUM_CHARACTERISTICS; ++i)
|
|
_CurrentPlayerCharac[i]= getDbValue32(toString("SERVER:CHARACTER_INFO:CHARACTERISTICS%d:VALUE", i));
|
|
|
|
// _CurrentPlayerCharac[CHARACTERISTICS::constitution]= getDbValue32("SERVER:CHARACTER_INFO:CHARACTERISTICS:Constitution");
|
|
// _CurrentPlayerCharac[CHARACTERISTICS::constitution]= getDbValue32("SERVER:CHARACTER_INFO:CHARACTERISTICS:Constitution");
|
|
// _CurrentPlayerCharac[CHARACTERISTICS::metabolism]= getDbValue32("SERVER:CHARACTER_INFO:CHARACTERISTICS:Metabolism");
|
|
// _CurrentPlayerCharac[CHARACTERISTICS::intelligence]= getDbValue32("SERVER:CHARACTER_INFO:CHARACTERISTICS:Intelligence");
|
|
// _CurrentPlayerCharac[CHARACTERISTICS::wisdom]= getDbValue32("SERVER:CHARACTER_INFO:CHARACTERISTICS:Wisdom");
|
|
// _CurrentPlayerCharac[CHARACTERISTICS::strength]= getDbValue32("SERVER:CHARACTER_INFO:CHARACTERISTICS:Strength");
|
|
// _CurrentPlayerCharac[CHARACTERISTICS::well_balanced]= getDbValue32("SERVER:CHARACTER_INFO:CHARACTERISTICS:WellBalanced");
|
|
// _CurrentPlayerCharac[CHARACTERISTICS::dexterity]= getDbValue32("SERVER:CHARACTER_INFO:CHARACTERISTICS:Dexterity");
|
|
// _CurrentPlayerCharac[CHARACTERISTICS::will]= getDbValue32("SERVER:CHARACTER_INFO:CHARACTERISTICS:Will");
|
|
}
|
|
|
|
|
|
{
|
|
H_AUTO ( RZ_Interface_DrawWindows )
|
|
|
|
/* Draw all the windows
|
|
To minimize texture swapping, we first sort per Window, then we sort per layer, then we render per Global Texture.
|
|
Computed String are rendered in on big drawQuads at last part of each layer
|
|
*/
|
|
CCDBNodeBranch::flushObserversCalls();
|
|
//
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
// Sort world space windows
|
|
rMG.sortWorldSpaceGroup ();
|
|
|
|
for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
if ( (nPriority == WIN_PRIORITY_WORLD_SPACE) && !camera.empty())
|
|
{
|
|
Driver->setViewMatrix(CMatrix::Identity);
|
|
Driver->setModelMatrix(CMatrix::Identity);
|
|
Driver->setFrustum(camera.getFrustum());
|
|
_ViewRenderer.activateWorldSpaceMatrix (true);
|
|
}
|
|
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::const_iterator itw;
|
|
|
|
for (itw = rList.begin(); itw != rList.end(); itw++)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
if( pIG ) // TODO: debug null pointer in PrioritizedWindows list
|
|
{
|
|
if (pIG->getActive())
|
|
{
|
|
// Draw all the elements of this window in the layers in ViewRendered
|
|
pIG->draw ();
|
|
// flush the layers
|
|
_ViewRenderer.flush ();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( (nPriority == WIN_PRIORITY_WORLD_SPACE) && !camera.empty())
|
|
{
|
|
Driver->setMatrixMode2D11();
|
|
_ViewRenderer.activateWorldSpaceMatrix (false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
H_AUTO ( RZ_Interface_DrawViews_After )
|
|
|
|
CCDBNodeBranch::flushObserversCalls();
|
|
|
|
// draw the special over extend text
|
|
drawOverExtendViewText();
|
|
|
|
// draw the context help
|
|
drawContextHelp ();
|
|
|
|
// Draw the pointer and DND Item
|
|
if (_Pointer != NULL)
|
|
{
|
|
//_Pointer->updateCoords();
|
|
|
|
if (_Pointer->show())
|
|
{
|
|
CDBCtrlSheet *pCS = dynamic_cast<CDBCtrlSheet*>((CCtrlBase*)_CapturePointerLeft);
|
|
if ((pCS != NULL) && (pCS->isDraging()))
|
|
{
|
|
sint x= _Pointer->getX() - pCS->getDeltaDragX();
|
|
sint y= _Pointer->getY() - pCS->getDeltaDragY();
|
|
pCS->drawSheet (x, y, false, false);
|
|
|
|
// if the control support CopyDrag, and if copy key pressed, display a tiny "+"
|
|
if(pCS->canDragCopy() && testDragCopyKey())
|
|
{
|
|
CViewRenderer &rVR = getViewRenderer();
|
|
sint w= rVR.getSystemTextureW(CViewRenderer::DragCopyTexture);
|
|
sint h= rVR.getSystemTextureW(CViewRenderer::DragCopyTexture);
|
|
rVR.draw11RotFlipBitmap (pCS->getRenderLayer()+1, x-w/2, y-h/2, 0, false,
|
|
rVR.getSystemTextureId(CViewRenderer::DragCopyTexture));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Even if hardware, Force draw if the cursor is a string (ATTACK etc...)
|
|
/*if (_Pointer->getActive() && (!IsMouseCursorHardware () || _Pointer->getStringMode()) )
|
|
_Pointer->draw ();*/
|
|
if (_Pointer->getActive())
|
|
_Pointer->draw ();
|
|
}
|
|
|
|
// flush layers
|
|
_ViewRenderer.flush();
|
|
|
|
// todo hulud remove Return in 2d world
|
|
Driver->setMatrixMode2D11();
|
|
|
|
// flush obs
|
|
CCDBNodeBranch::flushObserversCalls();
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
CCtrlBase* CInterfaceManager::getNewContextHelpCtrl()
|
|
{
|
|
// get the top most ctrl under us
|
|
CCtrlBase *best = NULL;
|
|
sint8 bestRenderLayer = -128;
|
|
for (sint i = (sint32)_CtrlsUnderPointer.size()-1; i>=0; i--)
|
|
{
|
|
CCtrlBase *pICL = _CtrlsUnderPointer[i];
|
|
if (pICL->getRenderLayer() > bestRenderLayer)
|
|
{
|
|
if ((pICL->getActive()) && (!pICL->emptyContextHelp()))
|
|
{
|
|
if (!_Pointer) return pICL;
|
|
sint32 mx, my;
|
|
_Pointer->getPointerPos(mx, my);
|
|
if (pICL->preciseHitTest(mx, my))
|
|
{
|
|
best = pICL;
|
|
bestRenderLayer = pICL->getRenderLayer();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!best)
|
|
{
|
|
// if a control was not found, try with the groups
|
|
sint8 bestRenderLayer = -128;
|
|
for (sint i = (sint32)_GroupsUnderPointer.size()-1; i>=0; i--)
|
|
{
|
|
CCtrlBase *pICL = _GroupsUnderPointer[i];
|
|
if (pICL->getRenderLayer() > bestRenderLayer)
|
|
{
|
|
if ((pICL->getActive()) && (!pICL->emptyContextHelp()))
|
|
{
|
|
if (!_Pointer) return pICL;
|
|
sint32 mx, my;
|
|
_Pointer->getPointerPos(mx, my);
|
|
if (pICL->preciseHitTest(mx, my))
|
|
{
|
|
best = pICL;
|
|
bestRenderLayer = pICL->getRenderLayer();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return best;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
CInterfaceGroup *CInterfaceManager::getWindowForActiveMasterGroup(const std::string &window)
|
|
{
|
|
// Search for all elements
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
const SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
CInterfaceElement *pEL= getElementFromId( rMG.Group->getId() + ":" + window);
|
|
if(pEL && pEL->isGroup())
|
|
return (CInterfaceGroup*)pEL;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void CInterfaceManager::updateTooltipCoords()
|
|
{
|
|
updateTooltipCoords(_CurCtrlContextHelp);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void CInterfaceManager::updateTooltipCoords(CCtrlBase *newCtrl)
|
|
{
|
|
if (!newCtrl) return;
|
|
if (!newCtrl->getInvalidCoords()) return;
|
|
CInterfaceGroup *groupContextHelp = getWindowForActiveMasterGroup(newCtrl->getContextHelpWindowName());
|
|
if(groupContextHelp)
|
|
{
|
|
CViewText *pTxt = (CViewText*)groupContextHelp->getView("text");
|
|
if (pTxt != NULL)
|
|
{
|
|
pTxt->setTextFormatTaged(_ContextHelpText);
|
|
// update only to get correct W/H
|
|
groupContextHelp->updateCoords ();
|
|
|
|
|
|
// **** Compute parent coordinates
|
|
CCtrlBase::TToolTipParentType parentType= newCtrl->getToolTipParent();
|
|
CInterfaceGroup *win= NULL;
|
|
// adjust to the mouse by default
|
|
sint32 xParent= _Pointer->getX();
|
|
sint32 yParent= _Pointer->getY();
|
|
sint32 wParent= 0;
|
|
sint32 hParent= 0;
|
|
// adjust to the window
|
|
if(parentType==CCtrlBase::TTWindow || parentType==CCtrlBase::TTSpecialWindow)
|
|
{
|
|
if(parentType==CCtrlBase::TTWindow)
|
|
win= newCtrl->getRootWindow();
|
|
else
|
|
win= dynamic_cast<CInterfaceGroup*>(getElementFromId(newCtrl->getToolTipSpecialParent()));
|
|
if(win)
|
|
{
|
|
xParent = win->getXReal();
|
|
yParent = win->getYReal();
|
|
wParent = win->getWReal();
|
|
hParent = win->getHReal();
|
|
}
|
|
// Bug...: leave default to pointer
|
|
}
|
|
// adjust to the ctrl
|
|
else if (parentType==CCtrlBase::TTCtrl)
|
|
{
|
|
xParent = newCtrl->getXReal();
|
|
yParent = newCtrl->getYReal();
|
|
wParent = newCtrl->getWReal();
|
|
hParent = newCtrl->getHReal();
|
|
// Additionaly, must clip this ctrl with its parent
|
|
// (else animals are buggy for instance)
|
|
CInterfaceGroup *parent= newCtrl->getParent();
|
|
if(parent)
|
|
{
|
|
sint32 xClip,yClip,wClip,hClip;
|
|
parent->getClip(xClip,yClip,wClip,hClip);
|
|
// clip bottom left
|
|
xParent= max(xParent, xClip);
|
|
yParent= max(yParent, yClip);
|
|
// clip top right
|
|
sint32 xrParent= min(xParent+ wParent, xClip+wClip);
|
|
sint32 ytParent= min(yParent+ hParent, yClip+hClip);
|
|
wParent= max((sint32)0, xrParent-xParent);
|
|
hParent= max((sint32)0, ytParent-yParent);
|
|
}
|
|
}
|
|
|
|
|
|
// **** resolve auto posref
|
|
uint clampCount = adjustTooltipPosition(newCtrl, win, newCtrl->getToolTipParentPosRef(), newCtrl->getToolTipPosRef(), xParent, yParent, wParent, hParent);
|
|
if (clampCount != 0)
|
|
{
|
|
// try to fallback on alternate tooltip posref
|
|
uint altClampCount = adjustTooltipPosition(newCtrl, win, newCtrl->getToolTipParentPosRefAlt(), newCtrl->getToolTipPosRefAlt(), xParent, yParent, wParent, hParent);
|
|
if (altClampCount > clampCount)
|
|
{
|
|
// worst ? resume to first posref
|
|
adjustTooltipPosition(newCtrl, win, newCtrl->getToolTipParentPosRef(), newCtrl->getToolTipPosRef(), xParent, yParent, wParent, hParent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void CInterfaceManager::drawContextHelp ()
|
|
{
|
|
if (!_Pointer || !_ContextHelpActive)
|
|
return;
|
|
|
|
|
|
sint32 x = _Pointer->getX();
|
|
sint32 y = _Pointer->getY();
|
|
|
|
|
|
// ***************
|
|
// **** try to disable
|
|
// ***************
|
|
// test disable first, so can recheck asap if another present. see below
|
|
if(_CurCtrlContextHelp)
|
|
{
|
|
if(x!=_LastXContextHelp || y!=_LastYContextHelp)
|
|
{
|
|
// May change of ctrl!! => disable context help
|
|
CCtrlBase *newCtrl= getNewContextHelpCtrl();
|
|
if(newCtrl!=_CurCtrlContextHelp)
|
|
{
|
|
// disable
|
|
disableContextHelp();
|
|
}
|
|
}
|
|
|
|
// Check if _CurCtrlContextHelp is visible
|
|
if (_CurCtrlContextHelp == NULL)
|
|
{
|
|
disableContextHelp();
|
|
}
|
|
else
|
|
{
|
|
bool bVisible = true;
|
|
if (_CurCtrlContextHelp->getActive() == false)
|
|
bVisible = false;
|
|
CInterfaceGroup *pParent = _CurCtrlContextHelp->getParent();
|
|
while (pParent != NULL)
|
|
{
|
|
if (pParent->getActive() == false)
|
|
bVisible = false;
|
|
pParent = pParent->getParent();
|
|
}
|
|
if (!bVisible)
|
|
disableContextHelp();
|
|
}
|
|
}
|
|
|
|
|
|
// ***************
|
|
// **** try to acquire
|
|
// ***************
|
|
if(!_CurCtrlContextHelp)
|
|
{
|
|
// get the ctrl of interset
|
|
CCtrlBase *newCtrl= getNewContextHelpCtrl();
|
|
|
|
if(x==_LastXContextHelp && y==_LastYContextHelp)
|
|
_DeltaTimeStopingContextHelp+= DT;
|
|
else
|
|
_DeltaTimeStopingContextHelp= 0;
|
|
|
|
// If reach the time limit
|
|
if( _DeltaTimeStopingContextHelp > _MaxTimeStopingContextHelp || (newCtrl && newCtrl->wantInstantContextHelp()))
|
|
{
|
|
// if present, get the ctx help text.
|
|
if(newCtrl)
|
|
{
|
|
// get the text
|
|
newCtrl->getContextHelp(_ContextHelpText);
|
|
// UserDefined context help
|
|
if( !newCtrl->getContextHelpActionHandler().empty() )
|
|
{
|
|
runActionHandler(newCtrl->getContextHelpActionHandler(), newCtrl, newCtrl->getContextHelpAHParams() );
|
|
}
|
|
|
|
// If the text is finally empty (Special AH case), abort
|
|
if(_ContextHelpText.empty())
|
|
newCtrl= NULL;
|
|
}
|
|
|
|
// not present? wait furthermore to move the mouse.
|
|
if(!newCtrl)
|
|
_DeltaTimeStopingContextHelp= 0;
|
|
else
|
|
{
|
|
// enable
|
|
_CurCtrlContextHelp = newCtrl->getId();
|
|
newCtrl->invalidateCoords();
|
|
}
|
|
}
|
|
}
|
|
|
|
updateTooltipCoords(_CurCtrlContextHelp);
|
|
|
|
|
|
// ***************
|
|
// **** display
|
|
// ***************
|
|
if(_CurCtrlContextHelp)
|
|
{
|
|
CInterfaceGroup *groupContextHelp = getWindowForActiveMasterGroup(_CurCtrlContextHelp->getContextHelpWindowName());
|
|
if(groupContextHelp)
|
|
{
|
|
/** If there's a modal box around, should be sure that the context help doesn't intersect it.
|
|
* If this is the case, we just disable it, unless the tooltip was generated by the current modal window
|
|
*/
|
|
if (!_ModalStack.empty())
|
|
{
|
|
CInterfaceGroup *mw = _ModalStack.back().ModalWindow;
|
|
if (mw && mw->isIn(*groupContextHelp))
|
|
{
|
|
if (_CurCtrlContextHelp->isSonOf(mw))
|
|
{
|
|
groupContextHelp->executeLuaScriptOnDraw();
|
|
groupContextHelp->draw ();
|
|
// flush layers
|
|
_ViewRenderer.flush();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
groupContextHelp->executeLuaScriptOnDraw();
|
|
groupContextHelp->draw ();
|
|
// flush layers
|
|
_ViewRenderer.flush();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
groupContextHelp->executeLuaScriptOnDraw();
|
|
groupContextHelp->draw ();
|
|
// flush layers
|
|
_ViewRenderer.flush();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Bkup movement
|
|
_LastXContextHelp= x;
|
|
_LastYContextHelp= y;
|
|
}
|
|
|
|
void CInterfaceManager::setContextHelpActive(bool active)
|
|
{
|
|
if (!active)
|
|
{
|
|
disableContextHelp();
|
|
}
|
|
_ContextHelpActive = active;
|
|
}
|
|
|
|
|
|
uint CInterfaceManager::adjustTooltipPosition(CCtrlBase *newCtrl,
|
|
CInterfaceGroup *win,
|
|
THotSpot ttParentRef,
|
|
THotSpot ttPosRef,
|
|
sint32 xParent,
|
|
sint32 yParent,
|
|
sint32 wParent,
|
|
sint32 hParent
|
|
)
|
|
{
|
|
CCtrlBase::TToolTipParentType parentType= newCtrl->getToolTipParent();
|
|
CInterfaceGroup *groupContextHelp = getWindowForActiveMasterGroup(newCtrl->getContextHelpWindowName());
|
|
if(ttPosRef==Hotspot_TTAuto || ttParentRef==Hotspot_TTAuto)
|
|
{
|
|
// NB: keep the special window if type is specialwindow (defined above)
|
|
if(!win)
|
|
win= newCtrl->getRootWindow();
|
|
sint32 xWin= 0;
|
|
sint32 yWin= 0;
|
|
sint32 wWin= 0;
|
|
sint32 hWin= 0;
|
|
if(win)
|
|
{
|
|
xWin = win->getXReal();
|
|
yWin = win->getYReal();
|
|
wWin = win->getWReal();
|
|
hWin = win->getHReal();
|
|
}
|
|
// for Window, display top or bottom according to window pos/size
|
|
if(parentType==CCtrlBase::TTWindow || parentType==CCtrlBase::TTSpecialWindow)
|
|
{
|
|
sint32 top= (sint32)_ScreenH - (yWin+hWin);
|
|
sint32 bottom= yWin;
|
|
if(top>bottom)
|
|
{
|
|
ttParentRef= Hotspot_TL;
|
|
ttPosRef= Hotspot_BL;
|
|
}
|
|
else
|
|
{
|
|
ttParentRef= Hotspot_BL;
|
|
ttPosRef= Hotspot_TL;
|
|
}
|
|
}
|
|
// for Ctrl, display top, left or right according to window pos/size
|
|
else if(parentType==CCtrlBase::TTCtrl)
|
|
{
|
|
sint32 right= (sint32)_ScreenW - (xWin+wWin);
|
|
sint32 left= xWin;
|
|
if(right>left)
|
|
{
|
|
ttParentRef= Hotspot_TR;
|
|
ttPosRef= Hotspot_BL;
|
|
}
|
|
else
|
|
{
|
|
ttParentRef= Hotspot_TL;
|
|
ttPosRef= Hotspot_BR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// default (mouse)
|
|
ttParentRef= Hotspot_BL;
|
|
ttPosRef= Hotspot_BL;
|
|
}
|
|
}
|
|
|
|
// **** compute coordinates of the tooltip
|
|
sint32 x= xParent;
|
|
sint32 y= yParent;
|
|
if (ttParentRef & Hotspot_Mx)
|
|
y += hParent/2;
|
|
if (ttParentRef & Hotspot_Tx)
|
|
y += hParent;
|
|
if (ttParentRef & Hotspot_xM)
|
|
x += wParent/2;
|
|
if (ttParentRef & Hotspot_xR)
|
|
x += wParent;
|
|
|
|
// adjust according to self posref
|
|
if (ttPosRef & Hotspot_Mx)
|
|
y -= groupContextHelp->getHReal()/2;
|
|
if (ttPosRef & Hotspot_Tx)
|
|
y -= groupContextHelp->getHReal();
|
|
if (ttPosRef & Hotspot_xM)
|
|
x -= groupContextHelp->getWReal()/2;
|
|
if (ttPosRef & Hotspot_xR)
|
|
x -= groupContextHelp->getWReal();
|
|
|
|
|
|
// **** clamp to screen coords, and set
|
|
uint clampCount = 0;
|
|
|
|
if ((x+groupContextHelp->getW()) > groupContextHelp->getParent()->getWReal())
|
|
{
|
|
++ clampCount;
|
|
x = groupContextHelp->getParent()->getWReal() - groupContextHelp->getW();
|
|
}
|
|
if (x < 0)
|
|
{
|
|
x = 0;
|
|
++ clampCount;
|
|
}
|
|
if ((y+groupContextHelp->getH()) > groupContextHelp->getParent()->getHReal())
|
|
{
|
|
y = groupContextHelp->getParent()->getHReal() - groupContextHelp->getH();
|
|
++ clampCount;
|
|
}
|
|
if (y < 0)
|
|
{
|
|
y = 0;
|
|
++ clampCount;
|
|
}
|
|
|
|
// update coords 3 times is required
|
|
groupContextHelp->setX (x);
|
|
groupContextHelp->setY (y);
|
|
groupContextHelp->updateCoords ();
|
|
groupContextHelp->updateCoords ();
|
|
groupContextHelp->updateCoords ();
|
|
|
|
return clampCount;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::setGlobalColor (NLMISC::CRGBA col)
|
|
{
|
|
if (!_RProp)
|
|
{
|
|
_RProp = getDbProp("UI:SAVE:COLOR:R");
|
|
_GProp = getDbProp("UI:SAVE:COLOR:G");
|
|
_BProp = getDbProp("UI:SAVE:COLOR:B");
|
|
_AProp = getDbProp("UI:SAVE:COLOR:A");
|
|
}
|
|
_RProp ->setValue32 (col.R);
|
|
_GProp ->setValue32 (col.G);
|
|
_BProp ->setValue32 (col.B);
|
|
_AProp ->setValue32 (col.A);
|
|
|
|
_GlobalColor = col;
|
|
|
|
// set the global color for content (the same with modulated alpha)
|
|
_GlobalColorForContent = _GlobalColor;
|
|
_GlobalColorForContent.A = (uint8) (( (uint16) _GlobalColorForContent.A * (uint16) _ContentAlpha) >> 8);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::isControlInWindow (CCtrlBase *ctrl, CInterfaceGroup *pNewCurrentWnd)
|
|
{
|
|
// We don't want to capture control if they are not owned by the top most window selected.
|
|
// Check all the parent of the control, one must be pNewCurrentWnd, else NULL
|
|
CInterfaceGroup *parent= ctrl->getParent();
|
|
while(parent!=NULL)
|
|
{
|
|
if(parent==pNewCurrentWnd)
|
|
return true;
|
|
else
|
|
parent= parent->getParent();
|
|
}
|
|
// not found => must not capture it
|
|
return false;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
uint CInterfaceManager::getDepth (CCtrlBase *ctrl, CInterfaceGroup *pNewCurrentWnd)
|
|
{
|
|
uint depth = 1;
|
|
CInterfaceGroup *parent= ctrl->getParent();
|
|
while (parent != NULL)
|
|
{
|
|
if (parent == pNewCurrentWnd)
|
|
break;
|
|
else
|
|
parent = parent->getParent();
|
|
depth++;
|
|
}
|
|
// The Resizer Ctrls take the precedence over Sons controls.
|
|
return depth + ctrl->getDeltaDepth();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::handleEvent (const CEventDescriptor& event)
|
|
{
|
|
bool handled= false;
|
|
|
|
// Check if we can receive events (no anims!)
|
|
for (uint i = 0; i < _ActiveAnims.size(); ++i)
|
|
if (_ActiveAnims[i]->isDisableButtons())
|
|
return false;
|
|
|
|
if (event.getType() == CEventDescriptor::key)
|
|
{
|
|
CEventDescriptorKey &eventDesc = (CEventDescriptorKey&)event;
|
|
_LastEventKeyDesc = eventDesc;
|
|
|
|
// Any Key event disable the ContextHelp
|
|
disableContextHelp();
|
|
|
|
// Hide menu if the key is pushed
|
|
// if ((eventDesc.getKeyEventType() == CEventDescriptorKey::keydown) && !_ModalStack.empty() && !eventDesc.getKeyAlt() && !eventDesc.getKeyCtrl() && !eventDesc.getKeyShift())
|
|
// Hide menu (or popup menu) is ESCAPE pressed
|
|
if( eventDesc.getKeyEventType() == CEventDescriptorKey::keychar && eventDesc.getChar() == KeyESCAPE )
|
|
{
|
|
if(_ModalStack.size() > 0)
|
|
{
|
|
CModalWndInfo mwi = _ModalStack.back();
|
|
if (mwi.ModalExitKeyPushed)
|
|
disableModalWindow();
|
|
}
|
|
}
|
|
|
|
// Manage "quit window" If the Key is ESCAPE, no captureKeyboard
|
|
if( eventDesc.getKeyEventType() == CEventDescriptorKey::keychar && eventDesc.getChar() == KeyESCAPE )
|
|
{
|
|
// Get the last escapable active top window. NB: this is ergonomically better.
|
|
CInterfaceGroup *win= getLastEscapableTopWindow();
|
|
if( win )
|
|
{
|
|
// If the window is a modal, must pop it.
|
|
if( dynamic_cast<CGroupModal*>(win) )
|
|
{
|
|
if(!win->getAHOnEscape().empty())
|
|
runActionHandler(win->getAHOnEscape(), win, win->getAHOnEscapeParams());
|
|
popModalWindow();
|
|
handled= true;
|
|
}
|
|
// else just disable it.
|
|
// Special case: leave the escape Key to the CaptureKeyboard .
|
|
else if(!_CaptureKeyboard )
|
|
{
|
|
if(!win->getAHOnEscape().empty())
|
|
runActionHandler(win->getAHOnEscape(), win, win->getAHOnEscapeParams());
|
|
win->setActive(false);
|
|
handled= true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Manage complex "Enter"
|
|
if (eventDesc.getKeyEventType() == CEventDescriptorKey::keychar && eventDesc.getChar() == KeyRETURN)
|
|
{
|
|
// If the top window has Enter AH
|
|
CInterfaceGroup *tw= getTopWindow();
|
|
if(tw && !tw->getAHOnEnter().empty())
|
|
{
|
|
// if the captured keyboard is in this Modal window, then must handle him in priority
|
|
if(_CaptureKeyboard && _CaptureKeyboard->getRootWindow()==tw)
|
|
{
|
|
bool result = _CaptureKeyboard->handleEvent(event);
|
|
CCDBNodeBranch::flushObserversCalls();
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
// The window or modal control the OnEnter. Execute, and don't go to the chat.
|
|
runActionHandler(tw->getAHOnEnter(), tw, tw->getAHOnEnterParams());
|
|
handled= true;
|
|
}
|
|
}
|
|
|
|
// else the 'return' key bring back to the last edit box (if possible)
|
|
CCtrlBase *oldCapture = _OldCaptureKeyboard ? _OldCaptureKeyboard : _DefaultCaptureKeyboard;
|
|
if (_CaptureKeyboard == NULL && oldCapture && !handled)
|
|
{
|
|
/* If the editbox does not want to recover focus, then abort. This possibility is normaly avoided
|
|
through setCaptureKeyboard() which already test getRecoverFocusOnEnter(), but it is still possible
|
|
for the default capture (main chat) or the old captured window to not want to recover
|
|
(temporary Read Only chat for instance)
|
|
*/
|
|
if(!dynamic_cast<CGroupEditBox*>(oldCapture) ||
|
|
dynamic_cast<CGroupEditBox*>(oldCapture)->getRecoverFocusOnEnter())
|
|
{
|
|
_CaptureKeyboard = oldCapture;
|
|
notifyElementCaptured(_CaptureKeyboard);
|
|
// make sure all parent windows are active
|
|
CCtrlBase *cb = _CaptureKeyboard;
|
|
CGroupContainer *lastContainer = NULL;
|
|
for(;;)
|
|
{
|
|
CGroupContainer *gc = dynamic_cast<CGroupContainer *>(cb);
|
|
if (gc) lastContainer = gc;
|
|
cb->forceOpen();
|
|
if (cb->getParent())
|
|
{
|
|
cb = cb->getParent();
|
|
}
|
|
else
|
|
{
|
|
cb->invalidateCoords();
|
|
break;
|
|
}
|
|
}
|
|
if (lastContainer)
|
|
{
|
|
setTopWindow(lastContainer);
|
|
lastContainer->enableBlink(1);
|
|
}
|
|
handled= true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// General case: handle it in the Captured keyboard
|
|
if (_CaptureKeyboard != NULL && !handled)
|
|
{
|
|
bool result = _CaptureKeyboard->handleEvent(event);
|
|
CCDBNodeBranch::flushObserversCalls();
|
|
return result;
|
|
}
|
|
}
|
|
else if (event.getType() == CEventDescriptor::mouse && _MouseHandlingEnabled )
|
|
{
|
|
CEventDescriptorMouse &eventDesc = (CEventDescriptorMouse&)event;
|
|
|
|
// First thing to do : Capture handling
|
|
if (_CapturePointerLeft != NULL)
|
|
handled|= _CapturePointerLeft->handleEvent(event);
|
|
|
|
if (_CapturePointerRight != NULL && _CapturePointerRight!=_CapturePointerLeft)
|
|
handled|= _CapturePointerRight->handleEvent(event);
|
|
|
|
CInterfaceGroup *ptr = getWindowUnder (eventDesc.getX(), eventDesc.getY());
|
|
_WindowUnder = ptr?ptr->getId():"";
|
|
|
|
// Any Mouse event but move disable the ContextHelp
|
|
if(eventDesc.getEventTypeExtended() != CEventDescriptorMouse::mousemove)
|
|
{
|
|
disableContextHelp();
|
|
}
|
|
|
|
// get the group under the mouse
|
|
CInterfaceGroup *pNewCurrentWnd = _WindowUnder;
|
|
_MouseOverWindow= pNewCurrentWnd!=NULL;
|
|
|
|
|
|
NLMISC::CRefPtr<CGroupModal> clickedOutModalWindow;
|
|
|
|
// modal special features
|
|
if (!_ModalStack.empty())
|
|
{
|
|
CModalWndInfo mwi = _ModalStack.back();
|
|
if(mwi.ModalWindow)
|
|
{
|
|
// If we are not in "click out" mode so we dont handle controls other than those of the modal
|
|
if (pNewCurrentWnd != mwi.ModalWindow && !mwi.ModalExitClickOut)
|
|
{
|
|
pNewCurrentWnd = NULL;
|
|
}
|
|
else
|
|
{
|
|
// If there is a handler on click out launch it
|
|
if (pNewCurrentWnd != mwi.ModalWindow)
|
|
if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown ||
|
|
(eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown))
|
|
if (!mwi.ModalHandlerClickOut.empty())
|
|
runActionHandler(mwi.ModalHandlerClickOut,NULL,mwi.ModalClickOutParams);
|
|
|
|
// If the current window is not the modal and if must quit on click out
|
|
if(pNewCurrentWnd != mwi.ModalWindow && mwi.ModalExitClickOut)
|
|
{
|
|
// NB: don't force handle==true because to quit a modal does not avoid other actions
|
|
|
|
// quit if click outside
|
|
if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown ||
|
|
(eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown))
|
|
{
|
|
clickedOutModalWindow = dynamic_cast<CGroupModal *>((CInterfaceGroup*)mwi.ModalWindow);
|
|
// disable the modal
|
|
popModalWindow();
|
|
if (!_ModalStack.empty())
|
|
{
|
|
// don't handle event unless it is a previous modal window
|
|
uint k = 0;
|
|
for(k = 0; k < _ModalStack.size(); ++k)
|
|
{
|
|
if (_ModalStack[k].ModalWindow == pNewCurrentWnd)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (k == _ModalStack.size())
|
|
{
|
|
pNewCurrentWnd = NULL; // can't handle event before we have left all modal windows
|
|
}
|
|
}
|
|
movePointer (0,0); // Reget controls under pointer
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Manage LeftClick.
|
|
if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown)
|
|
{
|
|
if ((pNewCurrentWnd != NULL) && (_ModalStack.empty()) && (pNewCurrentWnd->getOverlappable()))
|
|
{
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pNewCurrentWnd);
|
|
if (pGC != NULL)
|
|
{
|
|
if (!pGC->isGrayed()) setTopWindow(pNewCurrentWnd);
|
|
}
|
|
else
|
|
{
|
|
setTopWindow(pNewCurrentWnd);
|
|
}
|
|
}
|
|
|
|
// must not capture a new element if a sheet is currentlty being dragged.
|
|
// This may happen when alt-tab has been used => the sheet is dragged but the left button is up
|
|
if (!CDBCtrlSheet::getDraggedSheet())
|
|
{
|
|
// Take the top most control.
|
|
uint nMaxDepth = 0;
|
|
for (sint32 i = (sint32)_CtrlsUnderPointer.size()-1; i >= 0; i--)
|
|
{
|
|
CCtrlBase *ctrl= _CtrlsUnderPointer[i];
|
|
if (ctrl && ctrl->isCapturable() && isControlInWindow(ctrl, pNewCurrentWnd))
|
|
{
|
|
uint d = getDepth(ctrl, pNewCurrentWnd);
|
|
if (d > nMaxDepth)
|
|
{
|
|
nMaxDepth = d;
|
|
_CapturePointerLeft = ctrl;
|
|
}
|
|
}
|
|
}
|
|
notifyElementCaptured(_CapturePointerLeft);
|
|
if (clickedOutModalWindow && !clickedOutModalWindow->OnPostClickOut.empty())
|
|
{
|
|
runActionHandler(clickedOutModalWindow->OnPostClickOut, _CapturePointerLeft, clickedOutModalWindow->OnPostClickOutParams);
|
|
}
|
|
}
|
|
//if found
|
|
if (_CapturePointerLeft != NULL)
|
|
{
|
|
// consider clicking on a control implies handling of the event.
|
|
handled= true;
|
|
|
|
// handle the capture
|
|
_CapturePointerLeft->handleEvent(event);
|
|
}
|
|
}
|
|
|
|
// Manage RightClick
|
|
if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown)
|
|
{
|
|
if ((pNewCurrentWnd != NULL) && (_ModalStack.empty()) && (pNewCurrentWnd->getOverlappable()))
|
|
{
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pNewCurrentWnd);
|
|
if (pGC != NULL)
|
|
{
|
|
if (!pGC->isGrayed()) setTopWindow(pNewCurrentWnd);
|
|
}
|
|
else
|
|
{
|
|
setTopWindow(pNewCurrentWnd);
|
|
}
|
|
}
|
|
|
|
// Take the top most control.
|
|
{
|
|
uint nMaxDepth = 0;
|
|
for (sint32 i = (sint32)_CtrlsUnderPointer.size()-1; i >= 0; i--)
|
|
{
|
|
CCtrlBase *ctrl= _CtrlsUnderPointer[i];
|
|
if (ctrl && ctrl->isCapturable() && isControlInWindow(ctrl, pNewCurrentWnd))
|
|
{
|
|
uint d = getDepth(ctrl , pNewCurrentWnd);
|
|
if (d > nMaxDepth)
|
|
{
|
|
nMaxDepth = d;
|
|
_CapturePointerRight = ctrl;
|
|
}
|
|
}
|
|
}
|
|
notifyElementCaptured(_CapturePointerRight);
|
|
if (clickedOutModalWindow && !clickedOutModalWindow->OnPostClickOut.empty())
|
|
{
|
|
runActionHandler(clickedOutModalWindow->OnPostClickOut, _CapturePointerRight, clickedOutModalWindow->OnPostClickOutParams);
|
|
}
|
|
}
|
|
//if found
|
|
if (_CapturePointerRight != NULL)
|
|
{
|
|
// handle the capture
|
|
handled |= _CapturePointerRight->handleEvent(event);
|
|
}
|
|
}
|
|
if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup)
|
|
{
|
|
if (!handled)
|
|
if (pNewCurrentWnd != NULL)
|
|
pNewCurrentWnd->handleEvent(event);
|
|
if (_CapturePointerRight != NULL)
|
|
{
|
|
EventsListener.addUIHandledButtonMask(rightButton); // prevent 'click in scene' as mouse was previously captured
|
|
// (more a patch that anything, but 'UserControls' test for 'mouse up'
|
|
// directly later in the main loop (not through message queue), so it has no way of knowing that the event was handled...
|
|
setCapturePointerRight(NULL);
|
|
handled= true;
|
|
}
|
|
}
|
|
|
|
// window handling. if not handled by a control
|
|
if (!handled)
|
|
{
|
|
if (((pNewCurrentWnd != NULL) && _ModalStack.empty()) || ((!_ModalStack.empty() && _ModalStack.back().ModalWindow == pNewCurrentWnd)))
|
|
{
|
|
CEventDescriptorMouse ev2 = eventDesc;
|
|
sint32 x= eventDesc.getX(), y = eventDesc.getY();
|
|
if (pNewCurrentWnd)
|
|
{
|
|
pNewCurrentWnd->absoluteToRelative (x, y);
|
|
ev2.setX (x); ev2.setY (y);
|
|
handled|= pNewCurrentWnd->handleEvent (ev2);
|
|
}
|
|
|
|
// After handle event of a left click, may set window Top if movable (infos etc...)
|
|
//if( (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown) && pNewCurrentWnd->isMovable() )
|
|
// setTopWindow(pNewCurrentWnd);
|
|
}
|
|
}
|
|
|
|
// Put here to let a chance to the window to handle if the capture dont
|
|
if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup)
|
|
{
|
|
if (_CapturePointerLeft != NULL)
|
|
{
|
|
EventsListener.addUIHandledButtonMask (leftButton); // prevent 'click in scene' as mouse was previously captured
|
|
// (more a patch that anything, but 'UserControls' test for 'mouse up'
|
|
// directly later in the main loop (not through message queue), so it has no way of knowing that the event was handled...
|
|
setCapturePointerLeft(NULL);
|
|
//handled= true;
|
|
}
|
|
}
|
|
|
|
|
|
// If the current window is the modal, may Modal quit. Do it after standard event handle
|
|
if(!_ModalStack.empty() && pNewCurrentWnd == _ModalStack.back().ModalWindow)
|
|
{
|
|
// NB: don't force handle==true because to quit a modal does not avoid other actions
|
|
CModalWndInfo mwi = _ModalStack.back();
|
|
// and if must quit on click right
|
|
if(mwi.ModalExitClickR)
|
|
{
|
|
// quit if click right
|
|
if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup)
|
|
// disable the modal
|
|
disableModalWindow();
|
|
}
|
|
|
|
// and if must quit on click left
|
|
if(mwi.ModalExitClickL)
|
|
{
|
|
// quit if click right
|
|
if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup)
|
|
// disable the modal
|
|
disableModalWindow();
|
|
}
|
|
}
|
|
|
|
// If the mouse is over a window, always consider the event is taken (avoid click behind)
|
|
handled|= _MouseOverWindow;
|
|
}
|
|
|
|
CCDBNodeBranch::flushObserversCalls();
|
|
// event handled?
|
|
return handled;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::movePointer (sint32 dx, sint32 dy)
|
|
{
|
|
if (!_Pointer) return;
|
|
uint32 nScrW, nScrH;
|
|
sint32 oldpx, oldpy, newpx, newpy, disppx, disppy, olddisppx, olddisppy;
|
|
|
|
_ViewRenderer.getScreenSize (nScrW, nScrH);
|
|
_Pointer->getPointerPos (oldpx, oldpy);
|
|
|
|
olddisppx = oldpx;
|
|
olddisppy = oldpy;
|
|
|
|
newpx = oldpx + dx;
|
|
newpy = oldpy + dy;
|
|
|
|
if (newpx < 0) newpx = 0;
|
|
if (newpy < 0) newpy = 0;
|
|
if (newpx > (sint32)nScrW) newpx = nScrW;
|
|
if (newpy > (sint32)nScrH) newpy = nScrH;
|
|
dx = newpx - oldpx;
|
|
dy = newpy - oldpy;
|
|
|
|
disppx = newpx;
|
|
disppy = newpy;
|
|
|
|
_Pointer->setPointerPos (newpx, newpy);
|
|
_Pointer->setPointerDispPos (disppx, disppy);
|
|
|
|
// must get back coordinates because of snapping
|
|
sint32 mx = _Pointer->getX();
|
|
sint32 my = _Pointer->getY();
|
|
getViewsUnder (mx, my, _ViewsUnderPointer);
|
|
getCtrlsUnder (mx, my, _CtrlsUnderPointer);
|
|
getGroupsUnder (mx, my, _GroupsUnderPointer);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::movePointerAbs(sint32 px, sint32 py)
|
|
{
|
|
if (!_Pointer) return;
|
|
uint32 nScrW, nScrH;
|
|
_ViewRenderer.getScreenSize (nScrW, nScrH);
|
|
clamp(px, 0, (sint32) nScrW);
|
|
clamp(py, 0, (sint32) nScrH);
|
|
//
|
|
_Pointer->setPointerPos (px, py);
|
|
_Pointer->setPointerDispPos (px, py);
|
|
//
|
|
getViewsUnder (px, py, _ViewsUnderPointer);
|
|
getCtrlsUnder (px, py, _CtrlsUnderPointer);
|
|
getGroupsUnder (px, py, _GroupsUnderPointer);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::getNewWindowCoordToNewScreenSize(sint32 &x, sint32 &y, sint32 w, sint32 h, sint32 newScreenW, sint32 newScreenH) const
|
|
{
|
|
// NB: x is relative to Left of the window (and Left of screen)
|
|
// NB: y is relative to Top of the window (but Bottom of screen)
|
|
|
|
/*
|
|
The goal here is to move the window so it fit the new resolution
|
|
But we don't want to change its size (because somes windows just can't)
|
|
We also cannot use specific code according to each window because user may completly modify his interface
|
|
So the strategy is to dectect on which "side" (or center) the window is the best sticked,
|
|
and then just move the window according to this position
|
|
*/
|
|
|
|
// *** First detect from which screen position the window is the more sticked (borders or center)
|
|
// In X: best hotspot is left, middle or right?
|
|
sint32 posXToLeft= x;
|
|
sint32 posXToMiddle= x+w/2-_LastInGameScreenW/2;
|
|
sint32 posXToRight= _LastInGameScreenW-(x+w);
|
|
sint32 bestXHotSpot= Hotspot_xL;
|
|
sint32 bestXPosVal= posXToLeft;
|
|
if(abs(posXToMiddle) < bestXPosVal)
|
|
{
|
|
bestXHotSpot= Hotspot_xM;
|
|
bestXPosVal= abs(posXToMiddle);
|
|
}
|
|
if(posXToRight < bestXPosVal)
|
|
{
|
|
bestXHotSpot= Hotspot_xR;
|
|
bestXPosVal= posXToRight;
|
|
}
|
|
|
|
// Same In Y: best hotspot is bottom, middle or top?
|
|
// remember here that y is the top of window (relative to bottom of screen)
|
|
sint32 posYToBottom= y-h;
|
|
sint32 posYToMiddle= y-h/2-_LastInGameScreenH/2;
|
|
sint32 posYToTop= _LastInGameScreenH-y;
|
|
sint32 bestYHotSpot= Hotspot_Bx;
|
|
sint32 bestYPosVal= posYToBottom;
|
|
const sint32 middleYWeight= 6; // Avoid default Mission/Team/Map/ContactList positions to be considered as "middle"
|
|
if(abs(posYToMiddle)*middleYWeight < bestYPosVal)
|
|
{
|
|
bestYHotSpot= Hotspot_Mx;
|
|
bestYPosVal= abs(posYToMiddle)*middleYWeight;
|
|
}
|
|
if(posYToTop < bestYPosVal)
|
|
{
|
|
bestYHotSpot= Hotspot_Tx;
|
|
bestYPosVal= posYToTop;
|
|
}
|
|
|
|
// *** According to best matching hotspot, and new screen resolution, move the window
|
|
// x
|
|
if(bestXHotSpot==Hotspot_xL)
|
|
x= x;
|
|
else if(bestXHotSpot==Hotspot_xM)
|
|
x= newScreenW/2 + posXToMiddle - w/2;
|
|
else if(bestXHotSpot==Hotspot_xR)
|
|
x= newScreenW - posXToRight - w;
|
|
// y
|
|
if(bestYHotSpot==Hotspot_Bx)
|
|
y= y;
|
|
else if(bestYHotSpot==Hotspot_Mx)
|
|
y= newScreenH/2 + posYToMiddle + h/2;
|
|
else if(bestYHotSpot==Hotspot_Tx)
|
|
y= newScreenH - posYToTop;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::moveAllWindowsToNewScreenSize(sint32 newScreenW, sint32 newScreenH, bool fixCurrentUI)
|
|
{
|
|
// If resolutions correctly setuped, and really different from new setup
|
|
if( _LastInGameScreenW >0 && _LastInGameScreenH>0 &&
|
|
newScreenW >0 && newScreenH>0 &&
|
|
(_LastInGameScreenW != newScreenW || _LastInGameScreenH != newScreenH)
|
|
)
|
|
{
|
|
// *** Do it for the Active Desktop (if wanted)
|
|
if(fixCurrentUI)
|
|
{
|
|
// only for ui:interface (not login, nor outgame)
|
|
for (uint nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if(!rMG.Group || rMG.Group->getId()!="ui:interface")
|
|
continue;
|
|
|
|
// For all priorities, but the worldspace one
|
|
for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
|
|
{
|
|
if(nPriority==WIN_PRIORITY_WORLD_SPACE)
|
|
continue;
|
|
|
|
// For All windows (only layer 0 group container)
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::const_iterator itw;
|
|
for (itw = rList.begin(); itw != rList.end(); itw++)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
if(!pIG->isGroupContainer())
|
|
continue;
|
|
CGroupContainer *gc= safe_cast<CGroupContainer*>(pIG);
|
|
if(gc->getLayerSetup()!=0)
|
|
continue;
|
|
// should all be BL / TL
|
|
if(gc->getParentPosRef()!=Hotspot_BL || gc->getPosRef()!=Hotspot_TL)
|
|
continue;
|
|
|
|
// Get current window coordinates
|
|
sint32 x= pIG->getX(); // x is relative to Left of the window
|
|
sint32 y= pIG->getY(); // y is relative to Top of the window
|
|
sint32 w= pIG->getW(false); // the window may be hid, still get the correct(or estimated) W
|
|
sint32 h= pIG->getH(false); // the window may be hid, still get the correct(or estimated) H
|
|
|
|
// Compute the new coordinate
|
|
getNewWindowCoordToNewScreenSize(x, y, w, h, newScreenW, newScreenH);
|
|
|
|
// Change
|
|
pIG->setX(x);
|
|
pIG->setY(y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// *** Do it for All Backuped Desktops
|
|
for(uint md=0;md<MAX_NUM_MODES;md++)
|
|
{
|
|
CInterfaceConfig::CDesktopImage &mode= _Modes[md];
|
|
// For all containers of this mode
|
|
for(uint gc=0;gc<mode.GCImages.size();gc++)
|
|
{
|
|
CInterfaceConfig::SCont &gcCont= mode.GCImages[gc];
|
|
// Compute the new coordinate, directly in the X/Y fields of the structure
|
|
getNewWindowCoordToNewScreenSize(gcCont.X, gcCont.Y, gcCont.W, gcCont.H ,newScreenW, newScreenH);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now those are the last screen coordinates used for window position correction
|
|
if(newScreenW >0 && newScreenH>0)
|
|
{
|
|
_LastInGameScreenW= newScreenW;
|
|
_LastInGameScreenH= newScreenH;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::updateAllLocalisedElements()
|
|
{
|
|
|
|
uint32 nMasterGroup;
|
|
|
|
uint32 w, h;
|
|
_ViewRenderer.checkNewScreenSize ();
|
|
_ViewRenderer.getScreenSize (w, h);
|
|
|
|
// Update ui:* (limit the master containers to the height of the screen)
|
|
for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
rMG.Group->setW (w);
|
|
rMG.Group->setH (h);
|
|
}
|
|
_ViewRenderer.setClipWindow(0, 0, w, h);
|
|
|
|
// If all conditions are OK, move windows so they fit correctly with new screen size
|
|
// Do this work only InGame when Config is loaded
|
|
if( _InGame && _ConfigLoaded )
|
|
moveAllWindowsToNewScreenSize(w,h,true);
|
|
|
|
// Invalidate coordinates of all Windows of each MasterGroup
|
|
for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
|
|
rMG.Group->invalidateTexts (false);
|
|
rMG.Group->invalidateCoords ();
|
|
for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::const_iterator itw;
|
|
for (itw = rList.begin(); itw != rList.end(); itw++)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
pIG->invalidateTexts (false);
|
|
pIG->invalidateCoords ();
|
|
}
|
|
}
|
|
}
|
|
|
|
// setup for all
|
|
for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
bool bActive = rMG.Group->getActive ();
|
|
rMG.Group->setActive (true);
|
|
rMG.Group->updateCoords ();
|
|
rMG.Group->setActive (bActive);
|
|
}
|
|
|
|
// update coords one
|
|
checkCoords();
|
|
|
|
// Action by default (container opening
|
|
for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
rMG.Group->launch ();
|
|
}
|
|
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::addDBObserver (ICDBNode::IPropertyObserver* observer, ICDBNode::CTextId id)
|
|
{
|
|
return _DbRootNode->addObserver(observer, id);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::removeDBObserver (ICDBNode::IPropertyObserver* observer, ICDBNode::CTextId id)
|
|
{
|
|
return _DbRootNode->removeObserver(observer, id);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::addServerString (const std::string &sTarget, uint32 id, IStringProcess *cb)
|
|
{
|
|
if (id == 0)
|
|
{
|
|
CInterfaceExprValue val;
|
|
val.setUCString (ucstring(""));
|
|
CInterfaceLink::setTargetProperty (sTarget, val);
|
|
return;
|
|
}
|
|
SIDStringWaiter *pISW = new SIDStringWaiter;
|
|
pISW->Id = id;
|
|
pISW->IdOrString = false;
|
|
pISW->Target = sTarget;
|
|
pISW->Cb = cb;
|
|
_IDStringWaiters.push_back(pISW);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::addServerID (const std::string &sTarget, uint32 id, IStringProcess *cb)
|
|
{
|
|
if (id == 0)
|
|
{
|
|
CInterfaceExprValue val;
|
|
val.setUCString (ucstring(""));
|
|
CInterfaceLink::setTargetProperty (sTarget, val);
|
|
return;
|
|
}
|
|
SIDStringWaiter *pISW = new SIDStringWaiter;
|
|
pISW->Id = id;
|
|
pISW->IdOrString = true;
|
|
pISW->Target = sTarget;
|
|
pISW->Cb = cb;
|
|
_IDStringWaiters.push_back(pISW);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::processServerIDString()
|
|
{
|
|
STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
|
|
|
|
for (uint32 i = 0; i < _IDStringWaiters.size(); ++i)
|
|
{
|
|
bool bAffect = false;
|
|
ucstring ucstrToAffect;
|
|
SIDStringWaiter *pISW = _IDStringWaiters[i];
|
|
if (pISW->IdOrString == true) // ID !
|
|
{
|
|
if (pSMC->getString (pISW->Id, ucstrToAffect))
|
|
bAffect = true;
|
|
}
|
|
else // String !
|
|
{
|
|
if (pSMC->getDynString (pISW->Id, ucstrToAffect))
|
|
bAffect = true;
|
|
}
|
|
|
|
if (bAffect)
|
|
{
|
|
CInterfaceExprValue val;
|
|
bool bValid = true;
|
|
|
|
if (pISW->Cb != NULL)
|
|
{
|
|
bValid = pISW->Cb->cbIDStringReceived(ucstrToAffect);
|
|
delete pISW->Cb;
|
|
}
|
|
|
|
if (bValid)
|
|
{
|
|
val.setUCString (ucstrToAffect);
|
|
CInterfaceLink::setTargetProperty (pISW->Target, val);
|
|
}
|
|
|
|
// Remove entry
|
|
_IDStringWaiters.erase (_IDStringWaiters.begin()+i);
|
|
i--;
|
|
delete pISW;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
sint32 CInterfaceManager::getDbValue32 (const std::string & name)
|
|
{
|
|
CCDBNodeLeaf *node= getDbProp(name, false);
|
|
if(node)
|
|
return node->getValue32();
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CCDBNodeLeaf* CInterfaceManager::getDbProp(const std::string & name, bool bCreate)
|
|
{
|
|
if (name.empty()) return NULL;
|
|
CCDBNodeLeaf *pDBNL = NULL;
|
|
pDBNL = dynamic_cast<CCDBNodeLeaf*>(_DbRootNode->getNode( ICDBNode::CTextId(name), bCreate ));
|
|
return pDBNL;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CCDBNodeBranch *CInterfaceManager::getDbBranch(const std::string &name)
|
|
{
|
|
if (name.empty()) return NULL;
|
|
CCDBNodeBranch *nodeBranch;
|
|
nodeBranch = dynamic_cast<CCDBNodeBranch*>(_DbRootNode->getNode( ICDBNode::CTextId(name), false ));
|
|
return nodeBranch;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceGroup* CInterfaceManager::getWindowUnder (sint32 x, sint32 y)
|
|
{
|
|
H_AUTO (RZ_Interface_Window_Under )
|
|
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0; nPriority--)
|
|
{
|
|
const list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
|
|
list<CInterfaceGroup*>::const_reverse_iterator itw;
|
|
for (itw = rList.rbegin(); itw != rList.rend(); itw++)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
if (pIG->getActive() && pIG->getUseCursor())
|
|
{
|
|
if (pIG->isWindowUnder (x, y))
|
|
return pIG;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceGroup* CInterfaceManager::getGroupUnder (sint32 x, sint32 y)
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0; nPriority--)
|
|
{
|
|
const list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
|
|
list<CInterfaceGroup*>::const_reverse_iterator itw;
|
|
for (itw = rList.rbegin(); itw != rList.rend(); itw++)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
if (pIG->getActive() && pIG->getUseCursor())
|
|
{
|
|
CInterfaceGroup *pIGunder = pIG->getGroupUnder (x ,y);
|
|
if (pIGunder != NULL)
|
|
return pIGunder;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::getViewsUnder (sint32 x, sint32 y, std::vector<CViewBase*> &vVB)
|
|
{
|
|
vVB.clear ();
|
|
|
|
// No Op if screen minimized
|
|
if(_ViewRenderer.isMinimized())
|
|
return;
|
|
|
|
uint32 sw, sh;
|
|
_ViewRenderer.getScreenSize(sw, sh);
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0; nPriority--)
|
|
{
|
|
const list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
|
|
list<CInterfaceGroup*>::const_reverse_iterator itw;
|
|
for (itw = rList.rbegin(); itw != rList.rend(); itw++)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
|
|
// Accecpt if not modal clip
|
|
if (pIG->getActive() && pIG->getUseCursor())
|
|
{
|
|
if (pIG->getViewsUnder (x, y, 0, 0, (sint32) sw, (sint32) sh, vVB))
|
|
return ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::getCtrlsUnder (sint32 x, sint32 y, std::vector<CCtrlBase*> &vICL)
|
|
{
|
|
vICL.clear ();
|
|
|
|
// No Op if screen minimized
|
|
if(_ViewRenderer.isMinimized())
|
|
return;
|
|
|
|
uint32 sw, sh;
|
|
_ViewRenderer.getScreenSize(sw, sh);
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0 ; nPriority--)
|
|
{
|
|
const list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
|
|
list<CInterfaceGroup*>::const_reverse_iterator itw;
|
|
for (itw = rList.rbegin(); itw != rList.rend(); itw++)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
|
|
// Accecpt if not modal clip
|
|
if (_ModalStack.empty() || _ModalStack.back().ModalWindow == pIG || _ModalStack.back().ModalExitClickOut)
|
|
if (pIG->getActive() && pIG->getUseCursor())
|
|
{
|
|
if (pIG->getCtrlsUnder (x, y, 0, 0, (sint32) sw, (sint32) sh, vICL))
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::getGroupsUnder (sint32 x, sint32 y, std::vector<CInterfaceGroup *> &vIGL)
|
|
{
|
|
vIGL.clear ();
|
|
|
|
// No Op if screen minimized
|
|
if(_ViewRenderer.isMinimized())
|
|
return;
|
|
|
|
uint32 sw, sh;
|
|
_ViewRenderer.getScreenSize(sw, sh);
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0 ; nPriority--)
|
|
{
|
|
const list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
|
|
list<CInterfaceGroup*>::const_reverse_iterator itw;
|
|
for (itw = rList.rbegin(); itw != rList.rend(); itw++)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
|
|
// Accecpt if not modal clip
|
|
if (_ModalStack.empty() || _ModalStack.back().ModalWindow == pIG || _ModalStack.back().ModalExitClickOut)
|
|
if (pIG->getActive() && pIG->getUseCursor())
|
|
{
|
|
if (pIG->isIn(x, y))
|
|
{
|
|
vIGL.push_back(pIG);
|
|
pIG->getGroupsUnder (x, y, 0, 0, (sint32) sw, (sint32) sh, vIGL);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::activateMasterGroup (const std::string &sMasterGroupName, bool bActive)
|
|
{
|
|
CInterfaceGroup *pIG = getMasterGroupFromId (sMasterGroupName);
|
|
if (pIG != NULL)
|
|
{
|
|
pIG->setActive(bActive);
|
|
pIG->invalidateCoords();
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceGroup* CInterfaceManager::getWindow(CInterfaceElement *pIE)
|
|
{
|
|
CInterfaceGroup *pIG = pIE->getParent();
|
|
if (pIG == NULL) return NULL;
|
|
if (pIG->getParent() == NULL) return NULL;
|
|
while (pIG->getParent()->getParent() != NULL)
|
|
{
|
|
pIG = pIG->getParent();
|
|
}
|
|
return pIG;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceElement* CInterfaceManager::getElementFromId (const std::string &sEltId)
|
|
{
|
|
// System special
|
|
if(sEltId == _CtrlLaunchingModalId)
|
|
return getCtrlLaunchingModal();
|
|
|
|
// Search for all elements
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
CInterfaceElement *pIEL = rMG.Group->getElement (sEltId);
|
|
if (pIEL != NULL)
|
|
return pIEL;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceElement* CInterfaceManager::getElementFromDefine (const std::string &defineId)
|
|
{
|
|
return getElementFromId(getDefine(defineId));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceElement* CInterfaceManager::getElementFromId (const std::string &sStart, const std::string &sEltId)
|
|
{
|
|
CInterfaceElement *pIEL = getElementFromId (sEltId);
|
|
if (pIEL == NULL)
|
|
{
|
|
string sZeStart = sStart, sTmp;
|
|
if (sZeStart[sZeStart.size()-1] == ':')
|
|
sZeStart = sZeStart.substr(0, sZeStart.size()-1);
|
|
|
|
while (sZeStart != "")
|
|
{
|
|
if (sEltId[0] == ':')
|
|
sTmp = sZeStart + sEltId;
|
|
else
|
|
sTmp = sZeStart + ":" + sEltId;
|
|
pIEL = getElementFromId (sTmp);
|
|
if (pIEL != NULL)
|
|
return pIEL;
|
|
string::size_type nextPos = sZeStart.rfind(':');
|
|
if (nextPos == string::npos) break;
|
|
sZeStart = sZeStart.substr(0, nextPos);
|
|
}
|
|
}
|
|
return pIEL;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::setTopWindow (CInterfaceGroup* win)
|
|
{
|
|
//find the window in the window list
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
rMG.setTopWindow(win);
|
|
/*
|
|
for (list<CInterfaceGroup*>::iterator it = rMG.Windows.begin(); it != rMG.Windows.end() ;it++)
|
|
{
|
|
if (win == *it)
|
|
{
|
|
CInterfaceGroup* buf = *it;
|
|
|
|
CInterfaceGroup* pIGLast = rMG.Windows.back();
|
|
if (pIGLast != NULL)
|
|
{
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pIGLast);
|
|
if (pGC != NULL)
|
|
{
|
|
pGC->setHighLighted(false,0);
|
|
}
|
|
}
|
|
|
|
rMG.Windows.erase(it);
|
|
rMG.Windows.push_back(buf);
|
|
break;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::setBackWindow(CInterfaceGroup* win)
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
rMG.setBackWindow(win);
|
|
/*
|
|
//find the window in the window list
|
|
for (list<CInterfaceGroup*>::iterator it = rMG.Windows.begin(); it != rMG.Windows.end() ;it++)
|
|
{
|
|
if (win == *it)
|
|
{
|
|
CInterfaceGroup* buf = *it;
|
|
rMG.Windows.erase(it);
|
|
rMG.Windows.push_front(buf);
|
|
break;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceGroup *CInterfaceManager::getTopWindow (uint8 nPriority) const
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
const SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
// return the first.
|
|
if(rMG.PrioritizedWindows[nPriority].empty())
|
|
return NULL;
|
|
else
|
|
return rMG.PrioritizedWindows[nPriority].back();
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CInterfaceGroup *CInterfaceManager::getBackWindow (uint8 nPriority) const
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
const SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
// return the first.
|
|
if(rMG.PrioritizedWindows[nPriority].empty())
|
|
return NULL;
|
|
else
|
|
return rMG.PrioritizedWindows[nPriority].front();
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::enableModalWindow (CCtrlBase *ctrlLaunchingModal, CInterfaceGroup *pIG)
|
|
{
|
|
// disable any modal before. release keyboard
|
|
disableModalWindow();
|
|
pushModalWindow(ctrlLaunchingModal, pIG);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::enableModalWindow (CCtrlBase *CtrlLaunchingModal, const std::string &groupName)
|
|
{
|
|
CInterfaceGroup *group= dynamic_cast<CGroupModal*>( getElementFromId(groupName) );
|
|
if(group)
|
|
{
|
|
// enable the modal
|
|
enableModalWindow(CtrlLaunchingModal, group);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::disableModalWindow ()
|
|
{
|
|
while (!_ModalStack.empty())
|
|
{
|
|
CModalWndInfo winInfo = _ModalStack.back();
|
|
_ModalStack.pop_back(); // must pop back as early as possible because 'setActive' may trigger another 'popModalWindow', leading to a crash
|
|
// disable old modal window
|
|
if(winInfo.ModalWindow)
|
|
{
|
|
setBackWindow(winInfo.ModalWindow);
|
|
winInfo.ModalWindow->setActive(false);
|
|
}
|
|
}
|
|
|
|
// disable any context help
|
|
_CurCtrlContextHelp = "";
|
|
_DeltaTimeStopingContextHelp = 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::pushModalWindow(CCtrlBase *ctrlLaunchingModal, CInterfaceGroup *pIG)
|
|
{
|
|
// enable the wanted modal
|
|
if(pIG)
|
|
{
|
|
CModalWndInfo mwi;
|
|
mwi.ModalWindow = pIG;
|
|
mwi.CtrlLaunchingModal = ctrlLaunchingModal;
|
|
// setup special group
|
|
CGroupModal *groupModal= dynamic_cast<CGroupModal*>(pIG);
|
|
if(groupModal)
|
|
{
|
|
mwi.ModalExitClickOut = groupModal->ExitClickOut;
|
|
mwi.ModalExitClickL = groupModal->ExitClickL;
|
|
mwi.ModalExitClickR = groupModal->ExitClickR;
|
|
mwi.ModalHandlerClickOut = groupModal->OnClickOut;
|
|
mwi.ModalClickOutParams = groupModal->OnClickOutParams;
|
|
mwi.ModalExitKeyPushed = groupModal->ExitKeyPushed;
|
|
// update coords of the modal
|
|
if(groupModal->SpawnOnMousePos)
|
|
{
|
|
groupModal->SpawnMouseX = _Pointer->getX();
|
|
groupModal->SpawnMouseY = _Pointer->getY();
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// default for group not modal. Backward compatibility
|
|
mwi.ModalExitClickOut = false;
|
|
mwi.ModalExitClickL = false;
|
|
mwi.ModalExitClickR = false;
|
|
mwi.ModalExitKeyPushed = false;
|
|
}
|
|
|
|
_ModalStack.push_back(mwi);
|
|
|
|
// update coords and activate the modal
|
|
mwi.ModalWindow->invalidateCoords();
|
|
mwi.ModalWindow->setActive(true);
|
|
setTopWindow(mwi.ModalWindow);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::pushModalWindow(CCtrlBase *ctrlLaunchingModal, const std::string &groupName)
|
|
{
|
|
CInterfaceGroup *group= dynamic_cast<CGroupModal*>( getElementFromId(groupName) );
|
|
if(group)
|
|
{
|
|
// enable the modal
|
|
enableModalWindow(ctrlLaunchingModal, group);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::popModalWindow()
|
|
{
|
|
if (!_ModalStack.empty())
|
|
{
|
|
CModalWndInfo winInfo = _ModalStack.back();
|
|
_ModalStack.pop_back(); // must pop back as early as possible because 'setActive' may trigger another 'popModalWindow', leading to a crash
|
|
if(winInfo.ModalWindow)
|
|
{
|
|
setBackWindow(winInfo.ModalWindow);
|
|
winInfo.ModalWindow->setActive(false);
|
|
}
|
|
if (!_ModalStack.empty())
|
|
{
|
|
if(_ModalStack.back().ModalWindow)
|
|
{
|
|
_ModalStack.back().ModalWindow->setActive(true);
|
|
setTopWindow(_ModalStack.back().ModalWindow);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::popModalWindowCategory(const std::string &category)
|
|
{
|
|
for(;;)
|
|
{
|
|
if (_ModalStack.empty()) break;
|
|
if (!_ModalStack.back().ModalWindow) break;
|
|
CGroupModal *gm = dynamic_cast<CGroupModal *>((CInterfaceGroup*)(_ModalStack.back().ModalWindow));
|
|
if (gm && gm->Category == category)
|
|
{
|
|
_ModalStack.back().ModalWindow->setActive(false);
|
|
_ModalStack.pop_back();
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::setCaptureKeyboard(CCtrlBase *c)
|
|
{
|
|
CGroupEditBox *oldEb= dynamic_cast<CGroupEditBox*>((CCtrlBase*)_CaptureKeyboard);
|
|
CGroupEditBox *newEb= dynamic_cast<CGroupEditBox*>(c);
|
|
|
|
if (_CaptureKeyboard && _CaptureKeyboard != c)
|
|
{
|
|
_CaptureKeyboard->onKeyboardCaptureLost();
|
|
}
|
|
// If the old capturedKeyboard is an editBox and allow recoverFocusOnEnter
|
|
if ( oldEb && oldEb->getRecoverFocusOnEnter() )
|
|
{
|
|
_OldCaptureKeyboard = _CaptureKeyboard;
|
|
}
|
|
if ( newEb )
|
|
{
|
|
CGroupEditBox::disableSelection();
|
|
|
|
if (!newEb->getAHOnFocus().empty())
|
|
{
|
|
runActionHandler(newEb->getAHOnFocus(), newEb, newEb->getAHOnFocusParams());
|
|
}
|
|
|
|
}
|
|
_CaptureKeyboard = c;
|
|
notifyElementCaptured(c);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::resetCaptureKeyboard()
|
|
{
|
|
CCtrlBase *captureKeyboard = _CaptureKeyboard;
|
|
_OldCaptureKeyboard = NULL;
|
|
_CaptureKeyboard = NULL;
|
|
if (captureKeyboard)
|
|
{
|
|
captureKeyboard->onKeyboardCaptureLost();
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::runProcedure (const string &procName, CCtrlBase *pCaller,
|
|
const vector<string> ¶mList)
|
|
{
|
|
CstItProcedureMap it= _ProcedureMap.find(procName);
|
|
if(it!=_ProcedureMap.end())
|
|
{
|
|
// TMP TMP
|
|
/*std::string params;
|
|
for(uint k = 0; k < paramList.size(); ++k)
|
|
{
|
|
params += paramList[k] + " ";
|
|
}
|
|
|
|
nlinfo("runProcedure : %s : %s",procName.c_str(), params.c_str());*/
|
|
const CProcedure &proc= it->second;
|
|
// Run all actions
|
|
for(uint i=0;i<proc.Actions.size();i++)
|
|
{
|
|
const CAction &action= proc.Actions[i];
|
|
// test if the condition for the action is valid
|
|
if (action.CondBlocks.size() > 0)
|
|
{
|
|
CInterfaceExprValue result;
|
|
result.setBool(false);
|
|
string cond;
|
|
action.buildCond(paramList, cond);
|
|
CInterfaceExpr::eval(cond, result, NULL);
|
|
if (result.toBool())
|
|
{
|
|
if (!result.getBool()) continue;
|
|
}
|
|
}
|
|
// build the params sting
|
|
string params;
|
|
action.buildParams(paramList, params);
|
|
// run
|
|
//nlwarning("step %d : %s, %s", (int) i, action.Action.c_str(), params.c_str());
|
|
runActionHandler(action.Action, pCaller, params);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::setProcedureAction(const std::string &procName, uint actionIndex, const std::string &ah, const std::string ¶ms)
|
|
{
|
|
ItProcedureMap it= _ProcedureMap.find(procName);
|
|
if(it!=_ProcedureMap.end())
|
|
{
|
|
CProcedure &proc= it->second;
|
|
// set wanted action
|
|
if(actionIndex<proc.Actions.size())
|
|
{
|
|
CAction &action= proc.Actions[actionIndex];
|
|
action.Action= ah;
|
|
action.ParamBlocks.clear();
|
|
action.ParamBlocks.resize(1);
|
|
action.ParamBlocks[0].String= params;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
uint CInterfaceManager::getProcedureNumActions(const std::string &procName) const
|
|
{
|
|
CstItProcedureMap it= _ProcedureMap.find(procName);
|
|
if(it!=_ProcedureMap.end())
|
|
{
|
|
const CProcedure &proc= it->second;
|
|
return (uint)proc.Actions.size();
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::getProcedureAction(const std::string &procName, uint actionIndex, std::string &ah, std::string ¶ms) const
|
|
{
|
|
CstItProcedureMap it= _ProcedureMap.find(procName);
|
|
if(it!=_ProcedureMap.end())
|
|
{
|
|
const CProcedure &proc= it->second;
|
|
if(actionIndex<proc.Actions.size())
|
|
{
|
|
const CAction &action= proc.Actions[actionIndex];
|
|
// if not a variable parametrized Params
|
|
if(action.ParamBlocks.size()==1 && action.ParamBlocks[0].NumParam==-1)
|
|
{
|
|
ah= action.Action;
|
|
params= action.ParamBlocks[0].String;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::startAnim (const string &animId)
|
|
{
|
|
TAnimMap::iterator it = _AnimMap.find(animId);
|
|
if (it == _AnimMap.end())
|
|
{
|
|
nlwarning ("anim %s not found", animId.c_str());
|
|
return;
|
|
}
|
|
CInterfaceAnim *pIT = it->second;
|
|
stopAnim (animId);
|
|
pIT->start();
|
|
_ActiveAnims.push_back (pIT);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::stopAnim (const string &animId)
|
|
{
|
|
TAnimMap::iterator it = _AnimMap.find(animId);
|
|
if (it == _AnimMap.end())
|
|
{
|
|
nlwarning ("anim %s not found", animId.c_str());
|
|
return;
|
|
}
|
|
CInterfaceAnim *pIT = it->second;
|
|
for (uint i = 0; i < _ActiveAnims.size(); ++i)
|
|
if (_ActiveAnims[i] == pIT)
|
|
{
|
|
_ActiveAnims.erase (_ActiveAnims.begin()+i);
|
|
if (!pIT->isFinished())
|
|
pIT->stop();
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::messageBoxInternal(const string &msgBoxGroup, const ucstring &text, const string &masterGroup, TCaseMode caseMode)
|
|
{
|
|
CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(getElementFromId(masterGroup+":" + msgBoxGroup));
|
|
CViewText *viewText= dynamic_cast<CViewText*>(getElementFromId(masterGroup+":" + msgBoxGroup + ":text"));
|
|
|
|
if (group && viewText)
|
|
{
|
|
viewText->setCaseMode(caseMode);
|
|
viewText->setText(text);
|
|
enableModalWindow(NULL, group);
|
|
// don't understand why but need to update coords here
|
|
group->updateCoords();
|
|
group->updateCoords();
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::messageBox(const ucstring &text, const string &masterGroup, TCaseMode caseMode)
|
|
{
|
|
messageBoxInternal("message_box", text, masterGroup, caseMode);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::messageBoxWithHelp(const ucstring &text, const std::string &masterGroup,
|
|
const std::string &ahOnOk, const std::string ¶msOnOk,
|
|
TCaseMode caseMode)
|
|
{
|
|
// replace the procedure "proc_valid_message_box_ok" action
|
|
setProcedureAction("proc_message_box_with_help_ok", 1, ahOnOk, paramsOnOk);
|
|
const char *mbName = "message_box_with_help";
|
|
// if no action handler is wanted, then assume that
|
|
// clicking 'ok' do not have any consequence, so allow exiting the message box by clicking
|
|
// outside of it (this behavior is wanted on the login page, to allow to reclick on 'login' without
|
|
// having to click 'ok' in the message box each time)
|
|
CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(getElementFromId(masterGroup+":" + mbName));
|
|
CGroupModal *gm = dynamic_cast<CGroupModal *>(group);
|
|
if (gm)
|
|
{
|
|
gm->ExitClickOut = ahOnOk.empty();
|
|
}
|
|
messageBoxInternal(mbName, text, masterGroup, caseMode);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::validMessageBox(TValidMessageIcon icon, const ucstring &text, const std::string &ahOnOk,
|
|
const std::string ¶msOnOk, const std::string &ahOnCancel, const std::string ¶msOnCancel, const string &masterGroup)
|
|
{
|
|
CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(getElementFromId(masterGroup+":valid_message_box"));
|
|
CViewText *viewText= dynamic_cast<CViewText*>(getElementFromId(masterGroup+":valid_message_box:text"));
|
|
CViewBitmap *viewBitmap= dynamic_cast<CViewBitmap*>(getElementFromId(masterGroup+":valid_message_box:icon_group:icon"));
|
|
|
|
if (group && viewText)
|
|
{
|
|
// replace the procedure "proc_valid_message_box_ok" action
|
|
setProcedureAction("proc_valid_message_box_ok", 1, ahOnOk, paramsOnOk);
|
|
// replace the procedure "proc_valid_message_box_cancel" action
|
|
setProcedureAction("proc_valid_message_box_cancel", 1, ahOnCancel, paramsOnCancel);
|
|
|
|
// set text and icon
|
|
viewText->setText(text);
|
|
if(viewBitmap)
|
|
{
|
|
bool active= true;
|
|
if(icon==QuestionIconMsg)
|
|
viewBitmap->setTexture("brick_default.tga");
|
|
else if(icon==WarningIconMsg)
|
|
viewBitmap->setTexture("W_warning.tga");
|
|
else if(icon==ErrorIconMsg)
|
|
viewBitmap->setTexture("No_Action.tga");
|
|
else
|
|
active= false;
|
|
viewBitmap->setActive(active);
|
|
}
|
|
|
|
// Go
|
|
enableModalWindow(NULL, group);
|
|
// don't understand why but need to update coords here
|
|
group->updateCoords();
|
|
group->updateCoords();
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CInterfaceManager::getCurrentValidMessageBoxOnOk(string &ahOnOk, const std::string &masterGroup)
|
|
{
|
|
// any modal window opened?
|
|
CInterfaceGroup *mw= getModalWindow();
|
|
if(!mw)
|
|
return false;
|
|
|
|
// Is this modal window the valid_message_box window?
|
|
CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(getElementFromId(masterGroup+":valid_message_box"));
|
|
if(mw==group)
|
|
{
|
|
// Ok, get the current procedure OnOk action
|
|
string dummyParams;
|
|
if(getProcedureAction("proc_valid_message_box_ok", 1, ahOnOk, dummyParams))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::setContextHelpText(const ucstring &text)
|
|
{
|
|
_ContextHelpText = text;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::disableContextHelp()
|
|
{
|
|
_CurCtrlContextHelp = "";
|
|
_DeltaTimeStopingContextHelp = 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::disableContextHelpForControl(CCtrlBase *pCtrl)
|
|
{
|
|
if(!pCtrl)
|
|
return;
|
|
if(_CurCtrlContextHelp == pCtrl )
|
|
disableContextHelp();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::makeWindow(CInterfaceGroup *group)
|
|
{
|
|
if (!group) return;
|
|
uint32 i = 0;
|
|
for (i = 0; i < _MasterGroups.size(); ++i)
|
|
{
|
|
if (_MasterGroups[i].Group == group->getParent())
|
|
break;
|
|
}
|
|
|
|
if (i == _MasterGroups.size())
|
|
{
|
|
string stmp = string("not found master group for window: ")+group->getId();
|
|
nlwarning (stmp.c_str());
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// check if group hasn't been inserted twice.
|
|
if (_MasterGroups[i].isWindowPresent(group))
|
|
{
|
|
nlwarning("Window inserted twice");
|
|
}
|
|
else
|
|
{
|
|
_MasterGroups[i].addWindow(group,group->getPriority());
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::unMakeWindow(CInterfaceGroup *group, bool noWarning)
|
|
{
|
|
if (!group) return;
|
|
uint32 i = 0;
|
|
for (i = 0; i < _MasterGroups.size(); ++i)
|
|
{
|
|
if (_MasterGroups[i].Group == group->getParent())
|
|
break;
|
|
}
|
|
|
|
if (i == _MasterGroups.size())
|
|
{
|
|
if (!noWarning)
|
|
{
|
|
string stmp = string("not found master group for window: ")+group->getId();
|
|
nlwarning (stmp.c_str());
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// check if group hasn't been inserted twice.
|
|
if (!_MasterGroups[i].isWindowPresent(group))
|
|
{
|
|
if (!noWarning)
|
|
nlwarning("Window not inserted in master group");
|
|
}
|
|
else
|
|
{
|
|
_MasterGroups[i].delWindow(group);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::notifyElementCaptured(CCtrlBase *c)
|
|
{
|
|
std::set<CCtrlBase *> seen;
|
|
CCtrlBase *curr = c;
|
|
while (curr)
|
|
{
|
|
seen.insert(curr);
|
|
curr->elementCaptured(c);
|
|
curr = curr->getParent();
|
|
}
|
|
// also warn the ctrl under the pointer
|
|
for (uint i = 0; i < (uint) _CtrlsUnderPointer.size(); ++i)
|
|
{
|
|
if (!seen.count(_CtrlsUnderPointer[i]))
|
|
{
|
|
_CtrlsUnderPointer[i]->elementCaptured(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::enableMouseHandling(bool handle)
|
|
{
|
|
_MouseHandlingEnabled= handle;
|
|
if(!handle)
|
|
{
|
|
if(!_Pointer)
|
|
return;
|
|
|
|
// If Left captured, reset
|
|
if( _CapturePointerLeft )
|
|
{
|
|
setCapturePointerLeft(NULL);
|
|
}
|
|
|
|
// Same for Right
|
|
if( _CapturePointerRight )
|
|
{
|
|
setCapturePointerRight(NULL);
|
|
}
|
|
|
|
// Avoid any problem with modals
|
|
disableModalWindow();
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displayDebugInfo(const ucstring &str, TSystemInfoMode mode /*=InfoMsg*/)
|
|
{
|
|
if (PeopleInterraction.DebugInfo)
|
|
PeopleInterraction.ChatInput.DebugInfo.displayMessage(str, getDebugInfoColor(mode), 2);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
NLMISC::CRGBA CInterfaceManager::getDebugInfoColor(TSystemInfoMode mode)
|
|
{
|
|
if (_NeutralColor == NULL) // not initialised ?
|
|
{
|
|
#define SYSTEM_INFO_COLOR_DB_PATH "UI:VARIABLES:SYSTEM_INFOS:COLORS"
|
|
_NeutralColor = getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":NEUTRAL");
|
|
_WarningColor = getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":WARNING");
|
|
_ErrorColor = getDbProp(SYSTEM_INFO_COLOR_DB_PATH ":ERROR");
|
|
}
|
|
NLMISC::CRGBA color;
|
|
switch(mode)
|
|
{
|
|
case InfoMsg: color.setPacked(_NeutralColor->getValue32()); break;
|
|
case WarningMsg: color.setPacked(_WarningColor->getValue32()); break;
|
|
case ErrorMsg: color.setPacked(_ErrorColor->getValue32()); break;
|
|
default:
|
|
color = CRGBA::White;
|
|
break;
|
|
}
|
|
return color;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displaySystemInfo(const ucstring &str, const string &cat)
|
|
{
|
|
CClientConfig::SSysInfoParam::TMode mode = CClientConfig::SSysInfoParam::Normal;
|
|
CRGBA color = CRGBA::White;
|
|
|
|
|
|
map<string, CClientConfig::SSysInfoParam>::const_iterator it = ClientCfg.SystemInfoParams.find(strlwr(cat));
|
|
if (it != ClientCfg.SystemInfoParams.end())
|
|
{
|
|
mode = it->second.Mode;
|
|
color = it->second.Color;
|
|
}
|
|
|
|
if (mode != CClientConfig::SSysInfoParam::OverOnly && mode != CClientConfig::SSysInfoParam::Around)
|
|
{
|
|
if (PeopleInterraction.SystemInfo)
|
|
PeopleInterraction.ChatInput.SystemInfo.displayMessage(str, color, 2);
|
|
else
|
|
{
|
|
CPeopleInterraction::CSysMsg sysMsg;
|
|
sysMsg.Str = str;
|
|
sysMsg.Cat = cat;
|
|
PeopleInterraction.SystemMessageBuffer.push_back( sysMsg );
|
|
}
|
|
}
|
|
|
|
// If over popup a string at the bottom of the screen
|
|
if ((mode == CClientConfig::SSysInfoParam::Over) || (mode == CClientConfig::SSysInfoParam::OverOnly))
|
|
InSceneBubbleManager.addMessagePopup(str, color);
|
|
else if (mode == CClientConfig::SSysInfoParam::Center)
|
|
InSceneBubbleManager.addMessagePopupCenter(str, color);
|
|
else if (mode == CClientConfig::SSysInfoParam::Around && PeopleInterraction.AroundMe.Window)
|
|
PeopleInterraction.ChatInput.AroundMe.displayMessage(str, color, 2);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CRGBA CInterfaceManager::getSystemInfoColor(const std::string &cat)
|
|
{
|
|
CRGBA col = CRGBA::White;
|
|
map<string, CClientConfig::SSysInfoParam>::const_iterator it = ClientCfg.SystemInfoParams.find(strlwr(cat));
|
|
if (it != ClientCfg.SystemInfoParams.end())
|
|
col = it->second.Color;
|
|
return col;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::launchContextMenuInGame (const std::string &nameOfCM)
|
|
{
|
|
// Launch the context menu in-game: can't appear while dragging an item
|
|
if (CDBCtrlSheet::getDraggedSheet() == NULL)
|
|
{
|
|
if (_ModalStack.empty())
|
|
{
|
|
// We must be in-game !
|
|
CInterfaceGroup *pMG = getMasterGroupFromId("ui:interface");
|
|
// TMP nico : try with login screen:
|
|
if (!pMG)
|
|
{
|
|
pMG = getMasterGroupFromId("ui:login");
|
|
}
|
|
if (!pMG)
|
|
{
|
|
pMG = getMasterGroupFromId("ui:outgame");
|
|
}
|
|
if ((pMG != NULL) && (pMG->getActive()))
|
|
{
|
|
CInterfaceElement *pIE = getElementFromId(nameOfCM);
|
|
CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(pIE);
|
|
if (pIG != NULL)
|
|
{
|
|
enableModalWindow (NULL, pIG);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::registerClockMsgTarget(CCtrlBase *vb)
|
|
{
|
|
if (!vb) return;
|
|
if (isClockMsgTarget(vb))
|
|
{
|
|
nlwarning("<CInterfaceManager::registerClockMsgTarget> Element %s is already registered", vb->getId().c_str());
|
|
return;
|
|
}
|
|
_ClockMsgTargets.push_back(vb);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::unregisterClockMsgTarget(CCtrlBase *vb)
|
|
{
|
|
if (!vb) return;
|
|
std::vector<CCtrlBase*>::iterator it = std::find(_ClockMsgTargets.begin(), _ClockMsgTargets.end(), vb);
|
|
if (it != _ClockMsgTargets.end())
|
|
{
|
|
_ClockMsgTargets.erase(it);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceManager::isClockMsgTarget(CCtrlBase *vb) const
|
|
{
|
|
std::vector<CCtrlBase*>::const_iterator it = std::find(_ClockMsgTargets.begin(), _ClockMsgTargets.end(), vb);
|
|
return it != _ClockMsgTargets.end();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::setContentAlpha(uint8 alpha)
|
|
{
|
|
_ContentAlpha = alpha;
|
|
// update alpha of global color
|
|
_GlobalColorForContent.A = alpha;/*(uint8) (( (uint16) _GlobalColor.A * (uint16) _ContentAlpha) >> 8);*/
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::setContainerAlpha(uint8 alpha)
|
|
{
|
|
_ContainerAlpha = alpha;
|
|
// update alpha of global color
|
|
_GlobalColor.A = alpha;/*(uint8) (( (uint16) _GlobalColor.A * (uint16) _ContainerAlpha) >> 8); */
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::updateGroupContainerImage(CGroupContainer &gc, uint8 mode)
|
|
{
|
|
if (mode >= MAX_NUM_MODES)
|
|
{
|
|
nlwarning("wrong desktop");
|
|
return;
|
|
}
|
|
_Modes[mode].updateGroupContainerImage(gc);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::removeGroupContainerImage(const std::string &groupName, uint8 mode)
|
|
{
|
|
if (mode >= MAX_NUM_MODES)
|
|
{
|
|
nlwarning("wrong desktop");
|
|
return;
|
|
}
|
|
_Modes[mode].removeGroupContainerImage(groupName);
|
|
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::setMode(uint8 newMode)
|
|
{
|
|
if (newMode >= MAX_NUM_MODES)
|
|
return;
|
|
|
|
if (newMode == _CurrentMode)
|
|
return;
|
|
|
|
// Check if we can change vdesk !
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::const_iterator itw;
|
|
for (itw = rList.begin(); itw!= rList.end(); itw++)
|
|
{
|
|
CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(*itw);
|
|
if ((pGC != NULL)&&(pGC->getActive()))
|
|
{
|
|
// if this GC is a Full modal window, or if it is a modal son of another GC,
|
|
if (pGC->isModal() || pGC->isModalSon())
|
|
{
|
|
setTopWindow(pGC);
|
|
pGC->enableBlink(2);
|
|
return;
|
|
}
|
|
else
|
|
if (pGC->isGrayed())
|
|
{
|
|
// Make the corresponding child blink
|
|
pGC->blinkAllSons();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// check if there's a special behaviour with current captured ctrl that prevent from changing desktop
|
|
if (_CapturePointerLeft != NULL)
|
|
{
|
|
if (!_CapturePointerLeft->canChangeVirtualDesktop()) return;
|
|
}
|
|
if (_CapturePointerRight != NULL)
|
|
{
|
|
if (!_CapturePointerRight->canChangeVirtualDesktop()) return;
|
|
}
|
|
|
|
|
|
_Modes[_CurrentMode].fromCurrentDesktop();
|
|
_Modes[newMode].toCurrentDesktop();
|
|
//CBotChatUI::refreshActiveWindows();
|
|
|
|
_CurrentMode = newMode;
|
|
checkCoords();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::resetMode(uint8 newMode)
|
|
{
|
|
if (newMode >= MAX_NUM_MODES)
|
|
return;
|
|
NLMISC::contReset(_Modes[newMode]);
|
|
}
|
|
|
|
|
|
// for dump of interface content
|
|
struct CDumpedGroup
|
|
{
|
|
CInterfaceGroup *Group;
|
|
uint Depth; // depth in the tree
|
|
};
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::dumpUI(bool /* indent */)
|
|
{
|
|
std::vector<CDumpedGroup> left;
|
|
left.resize(_MasterGroups.size());
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
left[nMasterGroup].Group = _MasterGroups[nMasterGroup].Group;
|
|
left[nMasterGroup].Depth = 0;
|
|
}
|
|
|
|
while (!left.empty())
|
|
{
|
|
CInterfaceGroup *ig = left.back().Group;
|
|
if (ig)
|
|
{
|
|
uint currDepth = left.back().Depth;
|
|
std::string id = ig->getId();
|
|
std::string::size_type pos = id.find_last_of(':');
|
|
if (pos != std::string::npos)
|
|
{
|
|
id = id.substr(pos + 1);
|
|
}
|
|
std::string info(currDepth * 4, ' ');
|
|
info += id;
|
|
info += toString(", address=0x%p", ig);
|
|
nlinfo(info.c_str());
|
|
// dump view & controls for this group
|
|
for(uint k = 0; k < ig->getViews().size(); ++k)
|
|
{
|
|
std::string info(currDepth * 4, ' ');
|
|
info += toString("View %d / %d : ", (int) k + 1, (int) ig->getViews().size());
|
|
if (ig->getViews()[k])
|
|
{
|
|
info += id;
|
|
info += toString(", type = %s, address=0x%p", typeid(*ig->getViews()[k]).name(), ig->getViews()[k]);
|
|
}
|
|
else
|
|
{
|
|
info += "<NULL>";
|
|
}
|
|
nlinfo(info.c_str());
|
|
}
|
|
//
|
|
for(uint k = 0; k < ig->getControls().size(); ++k)
|
|
{
|
|
std::string info(currDepth * 4, ' ');
|
|
info += toString("Ctrl %d / %d : ", (int) k + 1, (int) ig->getControls().size());
|
|
if (ig->getControls()[k])
|
|
{
|
|
info += id;
|
|
info += toString(", type = %s, address=0x%p", typeid(*ig->getControls()[k]).name(), ig->getControls()[k]);
|
|
}
|
|
else
|
|
{
|
|
info += "<NULL>";
|
|
}
|
|
nlinfo(info.c_str());
|
|
}
|
|
|
|
//
|
|
left.pop_back();
|
|
|
|
for(uint k = 0; k < ig->getNumGroup(); ++k)
|
|
{
|
|
CDumpedGroup dg;
|
|
dg.Group = ig->getGroup(k);
|
|
dg.Depth = currDepth + 1;
|
|
left.push_back(dg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displayUIViewBBoxs(const std::string &uiFilter)
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::iterator it;
|
|
for(it = rList.begin(); it != rList.end(); ++it)
|
|
{
|
|
if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderView, uiFilter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displayUICtrlBBoxs(const std::string &uiFilter)
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::iterator it;
|
|
for(it = rList.begin(); it != rList.end(); ++it)
|
|
{
|
|
if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderCtrl, uiFilter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displayUIGroupBBoxs(const std::string &uiFilter)
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::iterator it;
|
|
for(it = rList.begin(); it != rList.end(); ++it)
|
|
{
|
|
if (*it) (*it)->renderWiredQuads(CInterfaceElement::RenderGroup, uiFilter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void writeComboActionMap (const CActionsManager &actions, xmlNodePtr node, const string &context)
|
|
{
|
|
// Get the combo defined
|
|
const CActionsManager::TComboActionMap &combos = actions.getComboActionMap ();
|
|
CActionsManager::TComboActionMap::const_iterator ite = combos.begin ();
|
|
while (ite != combos.end ())
|
|
{
|
|
// Key node
|
|
xmlNodePtr keyNode = xmlNewChild ( node, NULL, (const xmlChar*)"key", NULL );
|
|
|
|
// Props
|
|
xmlSetProp (keyNode, (const xmlChar*)"name", (const xmlChar*)CEventKey::getStringFromKey(ite->first.Key).c_str());
|
|
|
|
if (ite->first.KeyButtons&shiftKeyButton)
|
|
xmlSetProp (keyNode, (const xmlChar*)"shift", (const xmlChar*)"1");
|
|
if (ite->first.KeyButtons&ctrlKeyButton)
|
|
xmlSetProp (keyNode, (const xmlChar*)"ctrl", (const xmlChar*)"1");
|
|
if (ite->first.KeyButtons&altKeyButton)
|
|
xmlSetProp (keyNode, (const xmlChar*)"menu", (const xmlChar*)"1");
|
|
|
|
xmlSetProp (keyNode, (const xmlChar*)"action", (const xmlChar*)ite->second.Name.c_str());
|
|
if (!(const xmlChar*)ite->second.Argu.empty())
|
|
xmlSetProp (keyNode, (const xmlChar*)"params", (const xmlChar*)ite->second.Argu.c_str());
|
|
|
|
// Context
|
|
if (!context.empty ())
|
|
xmlSetProp (keyNode, (const xmlChar*)"context", (const xmlChar*)context.c_str());
|
|
|
|
ite++;
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void writeMacros (xmlNodePtr node)
|
|
{
|
|
const std::vector<CMacroCmd> ¯os = CMacroCmdManager::getInstance()->getMacros();
|
|
for (uint i = 0; i < macros.size(); ++i)
|
|
{
|
|
macros[i].writeTo(node);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
bool CInterfaceManager::saveKeys(const std::string &filename)
|
|
{
|
|
bool ret = false;
|
|
|
|
try
|
|
{
|
|
COFile file;
|
|
if (file.open (filename))
|
|
{
|
|
COXml xmlStream;
|
|
xmlStream.init (&file);
|
|
|
|
xmlDocPtr doc = xmlStream.getDocument ();
|
|
xmlNodePtr node = xmlNewDocNode(doc, NULL, (const xmlChar*)"interface_config", NULL);
|
|
xmlDocSetRootElement (doc, node);
|
|
|
|
writeComboActionMap (Actions, node, "");
|
|
writeComboActionMap (EditActions, node, RZ_CATEGORY_EDIT);
|
|
|
|
writeMacros (node);
|
|
|
|
// Flush the stream
|
|
xmlStream.flush();
|
|
|
|
// Close the stream
|
|
file.close ();
|
|
|
|
// Done
|
|
ret = true;
|
|
}
|
|
else
|
|
{
|
|
nlwarning ("Can't open the file %s", filename.c_str());
|
|
}
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
nlwarning ("Error while writing the file %s : %s. Remove it.", filename.c_str(), e.what ());
|
|
CFile::deleteFile(filename);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CInterfaceGroup *CInterfaceManager::getLastEscapableTopWindow() const
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
const SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0; nPriority--)
|
|
{
|
|
const list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
|
|
list<CInterfaceGroup*>::const_reverse_iterator it;
|
|
it= rList.rbegin();
|
|
for(;it!=rList.rend();it++)
|
|
{
|
|
if((*it)->getActive() && (*it)->getEscapable())
|
|
return *it;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::setWindowPriority (CInterfaceGroup *pWin, uint8 nNewPriority)
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
if (rMG.isWindowPresent(pWin))
|
|
{
|
|
rMG.delWindow(pWin);
|
|
rMG.addWindow(pWin, nNewPriority);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceManager::deletePlayerConfig (const std::string &playerFileIdent)
|
|
{
|
|
string fileName= "save/interface_" + playerFileIdent + ".icfg";
|
|
return CFile::deleteFile(fileName);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceManager::deletePlayerKeys (const std::string &playerFileIdent)
|
|
{
|
|
string fileName = "save/keys_"+playerFileIdent+".xml";
|
|
string fileNameEditor = "save/keys_r2ed_"+playerFileIdent+".xml";
|
|
return CFile::deleteFile(fileName) && CFile::deleteFile(fileNameEditor);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::log(const ucstring &str)
|
|
{
|
|
if (_LogState)
|
|
{
|
|
// Open file with the name of the player
|
|
const string fileName= "save/log_" + PlayerSelectedFileName + ".txt";
|
|
FILE *f = fopen(fileName.c_str(), "at");
|
|
if (f != NULL)
|
|
{
|
|
const string finalString = string(NLMISC::IDisplayer::dateToHumanString()) + " * " + str.toUtf8();
|
|
fprintf(f, "%s\n", finalString.c_str());
|
|
}
|
|
fclose(f);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::clearAllEditBox()
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::iterator it;
|
|
for(it = rList.begin(); it != rList.end(); ++it)
|
|
{
|
|
CInterfaceGroup *pIG = *it;
|
|
if (pIG != NULL)
|
|
pIG->clearAllEditBox();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::restoreAllContainersBackupPosition()
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
for (uint8 nPriority=0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::iterator it;
|
|
for(it = rList.begin(); it != rList.end(); ++it)
|
|
{
|
|
if (*it) (*it)->restoreAllContainersBackupPosition();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
uint8 CInterfaceManager::getLastTopWindowPriority() const
|
|
{
|
|
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
const SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
return rMG.LastTopWindowPriority;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::removeRefOnCtrl (CCtrlBase *ctrlBase)
|
|
{
|
|
if (_CurCtrlContextHelp == ctrlBase)
|
|
_CurCtrlContextHelp = "";
|
|
if (getCapturePointerLeft() == ctrlBase)
|
|
setCapturePointerLeft(NULL);
|
|
if (getCapturePointerRight() == ctrlBase)
|
|
setCapturePointerRight (NULL);
|
|
if (getCaptureKeyboard() == ctrlBase)
|
|
setCaptureKeyboard(NULL);
|
|
if (getOldCaptureKeyboard() == ctrlBase)
|
|
setOldCaptureKeyboard(NULL);
|
|
if (getDefaultCaptureKeyboard() == ctrlBase)
|
|
setDefaultCaptureKeyboard(NULL);
|
|
uint i;
|
|
for (i=0; i<_CtrlsUnderPointer.size(); i++)
|
|
{
|
|
if (_CtrlsUnderPointer[i] == ctrlBase)
|
|
{
|
|
_CtrlsUnderPointer.erase (_CtrlsUnderPointer.begin()+i);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
// Unregister from ClockMsgTargets
|
|
unregisterClockMsgTarget (ctrlBase);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::removeRefOnView (CViewBase *viewBase)
|
|
{
|
|
uint i;
|
|
for (i=0; i<_ViewsUnderPointer.size(); i++)
|
|
{
|
|
if (_ViewsUnderPointer[i] == viewBase)
|
|
{
|
|
_ViewsUnderPointer.erase (_ViewsUnderPointer.begin()+i);
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::removeRefOnGroup (CInterfaceGroup *group)
|
|
{
|
|
uint i;
|
|
for (i=0; i<_GroupsUnderPointer.size(); i++)
|
|
{
|
|
if (_GroupsUnderPointer[i] == group)
|
|
{
|
|
_GroupsUnderPointer.erase (_GroupsUnderPointer.begin()+i);
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
uint CInterfaceManager::getUserDblClickDelay()
|
|
{
|
|
uint nVal = 50;
|
|
CCDBNodeLeaf *pNL = getDbProp("UI:SAVE:DOUBLE_CLICK_SPEED");
|
|
if (pNL != NULL)
|
|
nVal = pNL->getValue32();
|
|
uint dbclickDelay = (uint)(DOUBLE_CLICK_MIN + (DOUBLE_CLICK_MAX-DOUBLE_CLICK_MIN) * (float)nVal / 100.0f);
|
|
return dbclickDelay;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::submitEvent (const std::string &event)
|
|
{
|
|
// Submit the event to the quick help system
|
|
runActionHandler("submit_quick_help", NULL, event);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::visit(CInterfaceElementVisitor *visitor)
|
|
{
|
|
nlassert(visitor);
|
|
for (uint nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
if (_MasterGroups[nMasterGroup].Group)
|
|
{
|
|
_MasterGroups[nMasterGroup].Group->visit(visitor);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::incLocalSyncActionCounter()
|
|
{
|
|
_LocalSyncActionCounter++;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::setOverExtendViewText(CViewText *vt, CRGBA backGround)
|
|
{
|
|
_OverExtendViewText= vt;
|
|
_OverExtendViewTextBackColor= backGround;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::drawOverExtendViewText()
|
|
{
|
|
// CViewRenderer &rVR= getViewRenderer();
|
|
|
|
if(_OverExtendViewText)
|
|
{
|
|
CViewText *vtSrc= safe_cast<CViewText*>((CInterfaceElement*)_OverExtendViewText);
|
|
|
|
CInterfaceGroup *groupOver = getWindowForActiveMasterGroup("over_extend_view_text");
|
|
if(groupOver)
|
|
{
|
|
CViewText *vtDst = dynamic_cast<CViewText*>(groupOver->getView("text"));
|
|
if (vtDst != NULL)
|
|
{
|
|
// Copy all aspects to the view
|
|
vtDst->setText (vtSrc->getText());
|
|
vtDst->setFontSize (vtSrc->getFontSize());
|
|
vtDst->setColor (vtSrc->getColor());
|
|
vtDst->setModulateGlobalColor(vtSrc->getModulateGlobalColor());
|
|
vtDst->setShadow(vtSrc->getShadow());
|
|
vtDst->setShadowColor(vtSrc->getShadowColor());
|
|
vtDst->setCaseMode(vtSrc->getCaseMode());
|
|
vtDst->setUnderlined(vtSrc->getUnderlined());
|
|
|
|
// setup background
|
|
CViewBitmap *pBack= dynamic_cast<CViewBitmap*>(groupOver->getView("midback"));
|
|
CViewBitmap *pOutline= dynamic_cast<CViewBitmap*>(groupOver->getView("midoutline"));
|
|
if(pBack)
|
|
pBack->setColor(_OverExtendViewTextBackColor);
|
|
if(pOutline)
|
|
{
|
|
pOutline->setColor(vtSrc->getColor());
|
|
pOutline->setModulateGlobalColor(vtSrc->getModulateGlobalColor());
|
|
}
|
|
|
|
// the group is the position of the overed text, but apply the delta of borders (vtDst X/Y)
|
|
sint32 x = vtSrc->getXReal() - vtDst->getX();
|
|
sint32 y = vtSrc->getYReal() - vtDst->getY();
|
|
|
|
// update one time only to get correct W/H
|
|
groupOver->updateCoords ();
|
|
|
|
if(!vtSrc->isClampRight())
|
|
{
|
|
// clamped from the left part
|
|
x += vtSrc->getWReal() - vtDst->getWReal();
|
|
}
|
|
|
|
// clamp to screen coords, and set
|
|
if ((x+groupOver->getW()) > groupOver->getParent()->getWReal())
|
|
x = groupOver->getParent()->getWReal() - groupOver->getW();
|
|
if (x < 0)
|
|
x = 0;
|
|
if ((y+groupOver->getH()) > groupOver->getParent()->getHReal())
|
|
y = groupOver->getParent()->getHReal() - groupOver->getH();
|
|
if (y < 0)
|
|
y = 0;
|
|
|
|
// set pos
|
|
groupOver->setX (x);
|
|
groupOver->setY (y);
|
|
|
|
// update coords 3 times is required
|
|
groupOver->updateCoords ();
|
|
groupOver->updateCoords ();
|
|
groupOver->updateCoords ();
|
|
|
|
// draw
|
|
groupOver->draw ();
|
|
// flush layers
|
|
_ViewRenderer.flush();
|
|
}
|
|
}
|
|
|
|
// Reset the ptr so at next frame, won't be rendered (but if reset)
|
|
_OverExtendViewText= NULL;
|
|
}
|
|
}
|
|
|
|
|
|
#if !FINAL_VERSION
|
|
|
|
// ***************************************************************************
|
|
NLMISC_COMMAND( localCounter, "Get value of local counter", "" )
|
|
{
|
|
if (args.size() != 0) return false;
|
|
CInterfaceManager *im = CInterfaceManager::getInstance();
|
|
im->displaySystemInfo(ucstring(toString(im->getLocalSyncActionCounter())));
|
|
return true;
|
|
}
|
|
|
|
#endif
|
|
|
|
// ***************************************************************************
|
|
|
|
NLMISC_COMMAND(loadui, "Load an interface file", "<loadui [all]/interface.xml>")
|
|
{
|
|
if (args.size() != 1)
|
|
return false;
|
|
|
|
CInterfaceManager *im = CInterfaceManager::getInstance();
|
|
|
|
std::vector<std::string> xmlFileNames;
|
|
|
|
if (args[0] == "all")
|
|
xmlFileNames = CInterfaceManager::getInGameXMLInterfaceFiles();
|
|
else
|
|
xmlFileNames.push_back (args[0]);
|
|
|
|
bool result = im->parseInterface (xmlFileNames, true);
|
|
#if !FINAL_VERSION
|
|
if (result)
|
|
CInterfaceManager::getInstance()->displaySystemInfo("File "+xmlFileNames.back()+" loaded successfully.");
|
|
else
|
|
CInterfaceManager::getInstance()->displaySystemInfo("File "+xmlFileNames.back()+" NOT loaded successully.");
|
|
#endif
|
|
|
|
// Invalidate the texts
|
|
im->updateAllLocalisedElements();
|
|
|
|
// reset captures
|
|
im->setCapturePointerLeft(NULL);
|
|
im->setCapturePointerRight(NULL);
|
|
im->setOldCaptureKeyboard(NULL);
|
|
im->setCaptureKeyboard(NULL);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::displayWebWindow(const string & name, const string & url)
|
|
{
|
|
CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(getElementFromId(name));
|
|
if (pIG != NULL)
|
|
{
|
|
pIG->setActive(true);
|
|
pIG->updateCoords();
|
|
pIG->center();
|
|
}
|
|
|
|
runActionHandler("browse", NULL, "name="+name+":content:html|url="+url);
|
|
}
|
|
/*
|
|
// ***************************************************************************
|
|
class CHandlerDispWebOnQuit : public IActionHandler
|
|
{
|
|
virtual void execute (CCtrlBase *pCaller, const string &Params)
|
|
{
|
|
if (ClientCfg.Local)
|
|
CInterfaceManager::getInstance()->runActionHandler("enter_modal", pCaller, "group=ui:interface:quit_dialog");
|
|
else
|
|
CInterfaceManager::getInstance()->displayWebWindow("ui:interface:web_on_quit", "http://213.208.119.190/igpoll/poll_form.php");
|
|
}
|
|
};
|
|
REGISTER_ACTION_HANDLER (CHandlerDispWebOnQuit, "disp_web_on_quit");
|
|
|
|
// ***************************************************************************
|
|
class CHandlerExitWebOnQuit : public IActionHandler
|
|
{
|
|
virtual void execute (CCtrlBase *pCaller, const string &Params)
|
|
{
|
|
CInterfaceManager::getInstance()->runActionHandler("quit_ryzom", pCaller);
|
|
}
|
|
};
|
|
REGISTER_ACTION_HANDLER (CHandlerExitWebOnQuit, "exit_web_on_quit");
|
|
*/
|
|
|
|
// ***************************************************************************
|
|
// EMOTES
|
|
// ***************************************************************************
|
|
|
|
struct CEmoteEntry
|
|
{
|
|
uint32 EmoteId;
|
|
string Path;
|
|
string Anim;
|
|
bool UsableFromClientUI;
|
|
|
|
bool operator< (const CEmoteEntry & entry) const
|
|
{
|
|
string path1 = Path;
|
|
string path2 = entry.Path;
|
|
|
|
for(;;)
|
|
{
|
|
string::size_type pos1 = path1.find('|');
|
|
string::size_type pos2 = path2.find('|');
|
|
|
|
ucstring s1 = toUpper(CI18N::get(path1.substr(0, pos1)));
|
|
ucstring s2 = toUpper(CI18N::get(path2.substr(0, pos2)));
|
|
|
|
sint result = s1.compare(s2);
|
|
if (result != 0)
|
|
return (result < 0);
|
|
|
|
if (pos1 == string::npos)
|
|
return (pos2 != string::npos);
|
|
if (pos2 == string::npos)
|
|
return false;
|
|
|
|
path1 = path1.substr(pos1 + 1);
|
|
path2 = path2.substr(pos2 + 1);
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::initEmotes()
|
|
{
|
|
_EmotesInitialized = true;
|
|
CTextEmotListSheet *pTELS = dynamic_cast<CTextEmotListSheet*>(SheetMngr.get(CSheetId("list.text_emotes")));
|
|
if (pTELS == NULL)
|
|
return;
|
|
|
|
static list<CEmoteEntry> entries;
|
|
if (entries.empty())
|
|
{
|
|
for (uint i = 0; i < pTELS->TextEmotList.size(); i++)
|
|
{
|
|
CEmoteEntry entry;
|
|
entry.EmoteId = i;
|
|
entry.Path = pTELS->TextEmotList[i].Path;
|
|
entry.Anim = pTELS->TextEmotList[i].Anim;
|
|
entry.UsableFromClientUI = pTELS->TextEmotList[i].UsableFromClientUI;
|
|
entries.push_back(entry);
|
|
}
|
|
entries.sort();
|
|
}
|
|
|
|
// The list of behaviour missnames emotList
|
|
CEmotListSheet *pEmotList = dynamic_cast<CEmotListSheet*>(SheetMngr.get(CSheetId("list.emot")));
|
|
nlassert (pEmotList != NULL);
|
|
nlassert (pEmotList->Emots.size() <= 255);
|
|
|
|
// Get the focus beta tester flag
|
|
bool betaTester = false;
|
|
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CSkillManager *pSM = CSkillManager::getInstance();
|
|
|
|
betaTester = pSM->isTitleUnblocked(CHARACTER_TITLE::FBT);
|
|
string previousMind = "";
|
|
CGroupSubMenu *pFirstMenu = 0;
|
|
|
|
for (list<CEmoteEntry>::const_iterator it = entries.begin(); it != entries.end(); it++)
|
|
{
|
|
uint32 nEmoteNb = (*it).EmoteId;
|
|
string sState = (*it).Anim;
|
|
string sName = (*it).Path;
|
|
|
|
// Check that the emote can be added to UI
|
|
// ---------------------------------------
|
|
if( (*it).UsableFromClientUI == false )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Check the emote reserved for FBT (hardcoded)
|
|
// --------------------------------------------
|
|
if (sState == "FBT" && !betaTester)
|
|
continue;
|
|
|
|
// Get the behaviour from the list of emotes
|
|
// -----------------------------------------
|
|
uint8 nBehav = 255;
|
|
uint32 i, j;
|
|
for (i = 0; i < pEmotList->Emots.size(); ++i)
|
|
if (CAnimationStateSheet::getAnimationStateName(pEmotList->Emots[i]) == sState)
|
|
{
|
|
nBehav = (uint8)i;
|
|
break;
|
|
}
|
|
|
|
// Add to the game context menu
|
|
// ----------------------------
|
|
uint32 nbToken = 1;
|
|
for (i = 0; i < sName.size(); ++i)
|
|
if (sName[i] == '|')
|
|
nbToken++;
|
|
|
|
CGroupMenu *pRootMenu = dynamic_cast<CGroupMenu*>(pIM->getElementFromId("ui:interface:user_chat_emote_menu"));
|
|
nlassert(pRootMenu);
|
|
|
|
CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
|
|
nlassert(pMenu);
|
|
|
|
// Add to the game context menu
|
|
// ----------------------------
|
|
for (i = 0; i < nbToken; ++i)
|
|
{
|
|
string sTmp;
|
|
if (i != (nbToken-1))
|
|
sTmp = sName.substr(0,sName.find('|'));
|
|
else
|
|
sTmp = sName;
|
|
|
|
// Look if this part of the path is already present
|
|
bool bFound = false;
|
|
for (j = 0; j < pMenu->getNumLine(); ++j)
|
|
{
|
|
if (sTmp == pMenu->getLineId(j))
|
|
{
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (!bFound) // Create it
|
|
{
|
|
if (i != (nbToken-1))
|
|
{
|
|
pMenu->addLine (CI18N::get(sTmp), "", "", sTmp);
|
|
|
|
// Create a sub menu
|
|
CGroupSubMenu *pNewSubMenu = new CGroupSubMenu(CViewBase::TCtorParam());
|
|
pMenu->setSubMenu(j, pNewSubMenu);
|
|
|
|
if (pFirstMenu == 0)
|
|
pFirstMenu = pNewSubMenu;
|
|
}
|
|
else
|
|
{
|
|
// Create a line
|
|
pMenu->addLine ("/" + CI18N::get(sTmp), "emote",
|
|
"nb="+toString(nEmoteNb)+"|behav="+toString(nBehav), sTmp);
|
|
}
|
|
}
|
|
|
|
// Jump to sub menu
|
|
if (i != (nbToken-1))
|
|
{
|
|
pMenu = pMenu->getSubMenu(j);
|
|
sName = sName.substr(sName.find('|')+1,sName.size());
|
|
}
|
|
}
|
|
|
|
// Create new command
|
|
// ------------------
|
|
if (CI18N::hasTranslation(sName))
|
|
{
|
|
CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
|
|
|
|
// convert command to utf8 since emote translation can have strange chars
|
|
string cmdName = (toLower(CI18N::get(sName))).toUtf8();
|
|
if(ICommand::exists(cmdName))
|
|
{
|
|
nlwarning("Translation for emote %s already exist: '%s' exist twice", sName.c_str(), cmdName.c_str());
|
|
}
|
|
else
|
|
{
|
|
CEmoteCmd *pNewCmd = new CEmoteCmd(cmdName.c_str(), "", "");
|
|
pNewCmd->EmoteNb = nEmoteNb;
|
|
pNewCmd->Behaviour = nBehav;
|
|
_EmoteCmds.push_back(pNewCmd);
|
|
|
|
// Quick-Emote too ?
|
|
for (i = 0; i< pMenu->getNumLine (); i++)
|
|
{
|
|
if (sName == pMenu->getLineId (i))
|
|
{
|
|
// Yeah that's a quick emote too; set command
|
|
pMenu->addLineAtIndex (i,
|
|
"@{FFFF}/" + toLower(CI18N::get(sName)),
|
|
"emote", "nb="+toString(nEmoteNb)+"|behav="+toString(nBehav),
|
|
"", "", "", false, false, true);
|
|
|
|
pMenu->removeLine (i+1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nlwarning("No translation for emote %s", sName.c_str());
|
|
}
|
|
}
|
|
|
|
// Insert separators
|
|
if (pFirstMenu)
|
|
{
|
|
pFirstMenu->addSeparatorAtIndex (0, "Positive");
|
|
pFirstMenu->addSeparatorAtIndex (4, "Neutral");
|
|
pFirstMenu->addSeparatorAtIndex (8, "Negative");
|
|
}
|
|
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::uninitEmotes()
|
|
{
|
|
if( !_EmotesInitialized )
|
|
return;
|
|
_EmotesInitialized = false;
|
|
|
|
// reset the emotes menu
|
|
CTextEmotListSheet *pTELS = dynamic_cast<CTextEmotListSheet*>(SheetMngr.get(CSheetId("list.text_emotes")));
|
|
if (pTELS != NULL && pTELS->TextEmotList.size() > 0)
|
|
{
|
|
// get the emotes menu id
|
|
string sPath = pTELS->TextEmotList[0].Path;
|
|
string sId = sPath.substr(0, sPath.find('|'));
|
|
|
|
// get the emotes menu
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
CGroupMenu *pRootMenu = dynamic_cast<CGroupMenu*>(pIM->getElementFromId("ui:interface:game_context_menu"));
|
|
if( pRootMenu )
|
|
{
|
|
CGroupSubMenu *pMenu = pRootMenu->getRootMenu();
|
|
for (uint i = 0; i < pMenu->getNumLine(); ++i)
|
|
{
|
|
if (pMenu->getLineId(i) == sId)
|
|
{
|
|
pMenu = pMenu->getSubMenu(i);
|
|
pMenu->reset();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// clear commands
|
|
for (uint32 i = 0; i < _EmoteCmds.size(); ++i)
|
|
delete _EmoteCmds[i];
|
|
_EmoteCmds.clear();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::updateEmotes()
|
|
{
|
|
uninitEmotes();
|
|
initEmotes();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Just call the action handler with good params
|
|
bool CInterfaceManager::CEmoteCmd::execute(const std::string &/* rawCommandString */, const vector<string> &args, CLog &/* log */, bool /* quiet */, bool /* human */)
|
|
{
|
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
string customPhrase;
|
|
if( args.size() > 0 )
|
|
{
|
|
customPhrase = args[0];
|
|
}
|
|
for(uint i = 1; i < args.size(); ++i )
|
|
{
|
|
customPhrase += " ";
|
|
customPhrase += args[i];
|
|
}
|
|
pIM->runActionHandler("emote", NULL, "nb="+toString(EmoteNb)+"|behav="+toString(Behaviour)+"|custom_phrase="+customPhrase);
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
static bool isSwimming()
|
|
{
|
|
if (UserEntity != NULL)
|
|
return (UserEntity->mode() == MBEHAV::SWIM || UserEntity->mode() == MBEHAV::MOUNT_SWIM);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static bool isStunned()
|
|
{
|
|
if (UserEntity != NULL)
|
|
return (UserEntity->behaviour() == MBEHAV::STUNNED);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static bool isDead()
|
|
{
|
|
if (UserEntity != NULL)
|
|
return (UserEntity->mode() == MBEHAV::DEATH);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
class CHandlerEmote : public IActionHandler
|
|
{
|
|
public:
|
|
void execute (CCtrlBase * /* pCaller */, const std::string &sParams)
|
|
{
|
|
// An emote is 2 things : a phrase and an animation
|
|
// Phrase is the phrase that server returns in chat system
|
|
// Behav is the animation played
|
|
// CustomPhrase is an user phrase which can replace default phrase
|
|
string sPhraseNb = getParam(sParams, "nb");
|
|
string sBehav = getParam(sParams, "behav");
|
|
string sCustomPhrase = getParam(sParams, "custom_phrase");
|
|
|
|
uint32 phraseNb;
|
|
fromString(sPhraseNb, phraseNb);
|
|
uint8 behaviour;
|
|
fromString(sBehav, behaviour);
|
|
|
|
MBEHAV::EBehaviour behavToSend = (MBEHAV::EBehaviour)(MBEHAV::EMOTE_BEGIN + behaviour);
|
|
uint16 phraseNbToSend = (uint16)phraseNb;
|
|
|
|
if (EAM)
|
|
{
|
|
const uint nbBehav = EAM->getNbEmots(); // Miscalled: this is the number of behaviour for all emotes
|
|
if ((behaviour >= nbBehav) || (behaviour == 255))
|
|
behavToSend = MBEHAV::IDLE;
|
|
}
|
|
else
|
|
{
|
|
if (behaviour == 255)
|
|
behavToSend = MBEHAV::IDLE;
|
|
}
|
|
|
|
/* Emotes forbidden when dead, emotes with behav forbidden when
|
|
* stunned or swimming */
|
|
if ( ( behavToSend != MBEHAV::IDLE && (isSwimming() || isStunned() || isDead() ) ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( sCustomPhrase.empty() )
|
|
{
|
|
// Create the message and send.
|
|
const string msgName = "COMMAND:EMOTE";
|
|
CBitMemStream out;
|
|
if(GenericMsgHeaderMngr.pushNameToStream(msgName, out))
|
|
{
|
|
out.serialEnum(behavToSend);
|
|
out.serial(phraseNbToSend);
|
|
NetMngr.push(out);
|
|
//nlinfo("impulseCallBack : %s %d %d sent", msgName.c_str(), (uint32)behavToSend, phraseNbToSend);
|
|
}
|
|
else
|
|
nlwarning("command 'emote': unknown message named '%s'.", msgName.c_str());
|
|
}
|
|
else
|
|
{
|
|
// Create the message and send.
|
|
const string msgName = "COMMAND:CUSTOM_EMOTE";
|
|
CBitMemStream out;
|
|
if(GenericMsgHeaderMngr.pushNameToStream(msgName, out))
|
|
{
|
|
ucstring ucstr;
|
|
ucstr.fromUtf8(sCustomPhrase);
|
|
|
|
if( sCustomPhrase == "none" )
|
|
{
|
|
if( behavToSend == MBEHAV::IDLE )
|
|
{
|
|
// display "no animation for emote"
|
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
|
ucstring msg = CI18N::get("msgCustomizedEmoteNoAnim");
|
|
string cat = getStringCategory(msg, msg);
|
|
pIM->displaySystemInfo(msg, cat);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ucstr = ucstring("&EMT&") + UserEntity->getDisplayName() + ucstring(" ") + ucstr;
|
|
}
|
|
|
|
out.serialEnum(behavToSend);
|
|
out.serial(ucstr);
|
|
NetMngr.push(out);
|
|
//nlinfo("impulseCallBack : %s %d %s sent", msgName.c_str(), (uint32)behavToSend, sCustomPhrase.c_str());
|
|
}
|
|
else
|
|
nlwarning("command 'emote': unknown message named '%s'.", msgName.c_str());
|
|
}
|
|
}
|
|
};
|
|
REGISTER_ACTION_HANDLER( CHandlerEmote, "emote");
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceManager::testDragCopyKey()
|
|
{
|
|
// hardcoded for now
|
|
return Driver->AsyncListener.isKeyDown(KeyCONTROL) ||
|
|
Driver->AsyncListener.isKeyDown(KeyLCONTROL) ||
|
|
Driver->AsyncListener.isKeyDown(KeyRCONTROL);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::setCapturePointerLeft(CCtrlBase *c)
|
|
{
|
|
// additionally, abort any dragging
|
|
if(CDBCtrlSheet::getDraggedSheet())
|
|
{
|
|
CDBCtrlSheet::getDraggedSheet()->abortDraging();
|
|
}
|
|
_CapturePointerLeft = c;
|
|
notifyElementCaptured(c);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::setCapturePointerRight(CCtrlBase *c)
|
|
{
|
|
_CapturePointerRight = c;
|
|
notifyElementCaptured(c);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::notifyMailAvailable()
|
|
{
|
|
if (_CheckMailNode != NULL)
|
|
_CheckMailNode->setValue32(1);
|
|
}
|
|
|
|
void CInterfaceManager::notifyForumUpdated()
|
|
{
|
|
if (_CheckForumNode != NULL)
|
|
_CheckForumNode->setValue32(1);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::resetTextIndex()
|
|
{
|
|
uint32 nMasterGroup;
|
|
for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
|
|
rMG.Group->invalidateTexts (true);
|
|
for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::const_iterator itw;
|
|
for (itw = rList.begin(); itw != rList.end(); itw++)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
pIG->invalidateTexts (true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CInterfaceElement *getInterfaceResource(const std::string &key)
|
|
{
|
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
|
return pIM->getElementFromId (key);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::sendStringToYuboChat(const ucstring &str)
|
|
{
|
|
// If the yubo chat really connected
|
|
if(_YuboChat.connected())
|
|
{
|
|
_YuboChat.send(str);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::checkYuboChat()
|
|
{
|
|
// flush the receive queue
|
|
if(_YuboChat.connected())
|
|
{
|
|
std::list<ucstring> toReceive;
|
|
_YuboChat.receive(toReceive);
|
|
while(!toReceive.empty())
|
|
{
|
|
PeopleInterraction.ChatInput.YuboChat.displayMessage(toReceive.front(), CRGBA::White, 2, NULL);
|
|
toReceive.pop_front();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::connectYuboChat()
|
|
{
|
|
// force disconnection if was connected
|
|
_YuboChat.disconnect();
|
|
|
|
uint32 KlientChatPort = 0;
|
|
|
|
extern TSessionId HighestMainlandSessionId;
|
|
switch(HighestMainlandSessionId.asInt())
|
|
{
|
|
case 101: KlientChatPort = 6002; break; // fr
|
|
case 102: KlientChatPort = 6003; break; // de
|
|
case 103: KlientChatPort = 6001; break; // en
|
|
case 301: KlientChatPort = 4000; break; // yubo
|
|
default:
|
|
if(!ClientCfg.KlientChatPort.empty())
|
|
fromString(ClientCfg.KlientChatPort, KlientChatPort);
|
|
break;
|
|
}
|
|
|
|
// check if must reconnect
|
|
if(KlientChatPort != 0 && !_YuboChat.connected())
|
|
{
|
|
// NB: hard code url, to avoid "client.cfg trojan"
|
|
// (a client.cfg with an url pointing to a hacker site, to grab login/password)
|
|
extern std::string LoginLogin, LoginPassword;
|
|
_YuboChat.connect(string("chat.ryzom.com:")+toString(KlientChatPort), LoginLogin, LoginPassword);
|
|
|
|
// Inform the interface that the chat is present
|
|
getDbProp("UI:VARIABLES:YUBO_CHAT_PRESENT")->setValue32(1);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInterfaceManager::executeLuaScript(const std::string &luaScript, bool smallScript)
|
|
{
|
|
H_AUTO ( RZ_Interface_executeLuaScript )
|
|
|
|
nlassert(_LuaState);
|
|
try
|
|
{
|
|
if(smallScript)
|
|
_LuaState->executeSmallScript(luaScript);
|
|
else
|
|
_LuaState->executeScript(luaScript);
|
|
}
|
|
catch(const ELuaError &e)
|
|
{
|
|
std::string msg = e.luaWhat();
|
|
char filename[MAX_PATH];
|
|
char exceptionName[MAX_PATH];
|
|
int line;
|
|
// Hamster: quick fix on AJM code but sscanf is still awfull
|
|
if (sscanf(msg.c_str(), "%s: %s.lua:%d:",exceptionName, filename, &line) == 3) // NB: test not exact here, but should work in 99,9 % of cases
|
|
{
|
|
msg = CLuaIHM::createGotoFileButtonTag(filename, line) + msg;
|
|
nlwarning(formatLuaErrorNlWarn(msg).c_str());
|
|
displaySystemInfo(formatLuaErrorSysInfo(msg));
|
|
}
|
|
else // AJM: handle the other 0.1% of cases
|
|
{
|
|
// Yoyo: seems that previous test doesn't work.... btw, must still print the message please...
|
|
nlwarning(formatLuaErrorNlWarn(msg).c_str());
|
|
displaySystemInfo(formatLuaErrorSysInfo(msg));
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::reloadAllLuaFileScripts()
|
|
{
|
|
std::set<std::string>::const_iterator it= _LuaFileScripts.begin();
|
|
for(;it!=_LuaFileScripts.end();it++)
|
|
{
|
|
string error;
|
|
// if fail to reload a script, display the error code
|
|
if(!loadLUA(*it, error))
|
|
{
|
|
displaySystemInfo(formatLuaErrorSysInfo(error));
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
std::vector<std::string> CInterfaceManager::getInGameXMLInterfaceFiles()
|
|
{
|
|
// Original Files
|
|
vector<string> ret;
|
|
ret= ClientCfg.XMLInterfaceFiles;
|
|
|
|
// Resolve any conflict (with CPath scheme, AddOn Should take the precedence)
|
|
// But still preserve order given in XMLInterfaceFiles (important for config.xml for instance)
|
|
set<string> fileSet;
|
|
for(uint i=0;i<ret.size();i++)
|
|
{
|
|
fileSet.insert(ret[i]);
|
|
}
|
|
|
|
// Add R2 Editor .xml. This is removed as it will not be done when initializing CEditor
|
|
// if (ClientCfg.R2EDEnabled)
|
|
// {
|
|
// // Add them to 'ret', only if not already inserted
|
|
// // since parser will crash on any duplicates
|
|
// for(uint i=0;i<ClientCfg.XMLR2EDInterfaceFiles.size();i++)
|
|
// {
|
|
// if(fileSet.find(ClientCfg.XMLR2EDInterfaceFiles[i])==fileSet.end())
|
|
// {
|
|
// fileSet.insert(ClientCfg.XMLR2EDInterfaceFiles[i]);
|
|
// ret.push_back(ClientCfg.XMLR2EDInterfaceFiles[i]);
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// Get Addons .xml
|
|
vector<string> adds;
|
|
InterfaceAddOnManager.getFiles("*.xml", adds);
|
|
|
|
// Add them to 'ret', only if not already inserted
|
|
for(uint i=0;i<adds.size();i++)
|
|
{
|
|
if(fileSet.find(adds[i])==fileSet.end())
|
|
{
|
|
fileSet.insert(adds[i]);
|
|
ret.push_back(adds[i]);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::formatLuaStackContext(std::string &stackContext)
|
|
{
|
|
stackContext= string("@{FC8A}") + stackContext + "@{FC8F} ";
|
|
}
|
|
std::string CInterfaceManager::formatLuaErrorNlWarn(const std::string &error)
|
|
{
|
|
// Remove color tags (see formatLuaErrorSC())
|
|
std::string ret= error;
|
|
strFindReplace(ret, "@{FC8A}", "");
|
|
strFindReplace(ret, "@{FC8F}", "");
|
|
return ret;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::dumpLuaString(const std::string &str)
|
|
{
|
|
nlinfo(str.c_str());
|
|
displaySystemInfo(formatLuaErrorSysInfo(str));
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::getLuaValueInfo(std::string &str, sint index)
|
|
{
|
|
nlassert(_LuaState);
|
|
CLuaState &ls= *_LuaState;
|
|
|
|
sint type= ls.type(index);
|
|
if(type==LUA_TNIL)
|
|
str= "nil";
|
|
else if(type==LUA_TNUMBER)
|
|
str= NLMISC::toString(ls.toNumber(index));
|
|
else if(type==LUA_TBOOLEAN)
|
|
str= ls.toBoolean(index)?"true":"false";
|
|
else if(type==LUA_TSTRING)
|
|
{
|
|
ls.toString(index, str);
|
|
str= toString("'") + str + toString("'");
|
|
}
|
|
else
|
|
{
|
|
str= ls.getTypename(type);
|
|
str+= ":";
|
|
str+= NLMISC::toString("%p", ls.toPointer(index));
|
|
// If its a table, append the size.
|
|
if(type==LUA_TTABLE)
|
|
{
|
|
ls.pushNil(); // first key
|
|
uint count= 0;
|
|
while (ls.next(index-1))
|
|
{
|
|
ls.pop(); // remove 'value'; keeps `key' for next iteration
|
|
count++;
|
|
}
|
|
str+= NLMISC::toString(" (size=%d)", count);
|
|
}
|
|
// If its a Userdata, try to display UI info
|
|
else if(type==LUA_TUSERDATA)
|
|
{
|
|
if(CLuaIHM::isUIOnStack(ls, index))
|
|
{
|
|
CInterfaceElement *ui= CLuaIHM::getUIOnStack(ls, index);
|
|
str+= NLMISC::toString(" (ui=%p)", ui);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::dumpLuaKeyValueInfo(uint recursTableLevel, uint tabLevel)
|
|
{
|
|
nlassert(_LuaState);
|
|
CLuaState &ls= *_LuaState;
|
|
CLuaStackChecker lsc(&ls);
|
|
|
|
// Dump Key Str
|
|
string key;
|
|
getLuaValueInfo(key, -2);
|
|
// Dump Value Str
|
|
string value;
|
|
getLuaValueInfo(value, -1);
|
|
|
|
// display.
|
|
string res;
|
|
// append tab for table hierarchy
|
|
for(uint i=0;i<tabLevel;i++)
|
|
res+= " ";
|
|
// display key and value
|
|
res+= key + " == " + value;
|
|
dumpLuaString(res);
|
|
|
|
// If the value is a table, and can recurs dumping
|
|
if(recursTableLevel>0 && ls.type(-1)==LUA_TTABLE)
|
|
{
|
|
ls.pushNil(); // first key
|
|
while (ls.next(-2))
|
|
{
|
|
// display the key value pair of this table (recurs)
|
|
dumpLuaKeyValueInfo(recursTableLevel-1, tabLevel+1);
|
|
ls.pop(); // remove 'value'; keeps `key' for next iteration
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::dumpLuaState(uint detail)
|
|
{
|
|
if(!_LuaState)
|
|
{
|
|
dumpLuaString("LUA State not created");
|
|
return;
|
|
}
|
|
|
|
// clamp detailed info to 2 (display at max content of eaxh Env of each group)
|
|
clamp(detail, 0U, 2U);
|
|
|
|
// Dump the Memory State
|
|
dumpLuaString(NLMISC::toString("Memory Used : %d Kb", _LuaState->getGCCount()));
|
|
dumpLuaString(NLMISC::toString("GC Threshold: %d Kb", _LuaState->getGCThreshold()));
|
|
|
|
// If want to display some detailed info
|
|
if(detail>0)
|
|
{
|
|
CLuaState &ls= *_LuaState;
|
|
CLuaStackChecker lsc(&ls);
|
|
|
|
// *** Dump all Lua Env Tables
|
|
ls.push(IHM_LUA_ENVTABLE);
|
|
ls.getTable(LUA_REGISTRYINDEX); // __ui_envtable
|
|
ls.pushNil(); // first key
|
|
uint count= 0;
|
|
while (ls.next(-2))
|
|
{
|
|
// `key' is at index -2 and `value' at index -1
|
|
dumpLuaKeyValueInfo(detail-1, 1);
|
|
ls.pop(); // remove 'value'; keeps `key' for next iteration
|
|
count++;
|
|
}
|
|
// pop table
|
|
ls.pop();
|
|
|
|
dumpLuaString(NLMISC::toString("Number of EnvTable for ui groups: %d", count));
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::luaGarbageCollect()
|
|
{
|
|
if(!_LuaState)
|
|
return;
|
|
dumpLuaString("Collecting Garbaged LUA variables");
|
|
_LuaState->setGCThreshold(0);
|
|
dumpLuaString(NLMISC::toString("Memory Used : %d Kb", _LuaState->getGCCount()));
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::hideAllWindows()
|
|
{
|
|
for (uint nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::const_iterator itw;
|
|
for (itw = rList.begin(); itw!= rList.end();)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
itw++; // since setActive invalidate the iterator, be sure we move to the next one before
|
|
pIG->setActive(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInterfaceManager::hideAllNonSavableWindows()
|
|
{
|
|
for (uint nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
|
|
{
|
|
SMasterGroup &rMG = _MasterGroups[nMasterGroup];
|
|
if (rMG.Group->getActive())
|
|
{
|
|
for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
|
|
{
|
|
list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
|
|
list<CInterfaceGroup*>::const_iterator itw;
|
|
for (itw = rList.begin(); itw!= rList.end();)
|
|
{
|
|
CInterfaceGroup *pIG = *itw;
|
|
CGroupContainer *cont = dynamic_cast<CGroupContainer *>(pIG);
|
|
itw++; // since setActive invalidate the iterator, be sure we move to the next one before
|
|
if (!cont || !cont->isSavable())
|
|
{
|
|
pIG->setActive(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::createLocalBranch(const std::string &fileName, NLMISC::IProgressCallback &progressCallBack)
|
|
{
|
|
try
|
|
{
|
|
CIFile file;
|
|
if (file.open (fileName))
|
|
{
|
|
// Init an xml stream
|
|
CIXml read;
|
|
read.init (file);
|
|
|
|
//Parse the parser output!!!
|
|
CCDBNodeBranch *localNode = new CCDBNodeBranch("LOCAL");
|
|
localNode->init( read.getRootNode (), progressCallBack );
|
|
_DbRootNode->attachChild(localNode,"LOCAL");
|
|
|
|
// Create the observers for auto-copy SERVER->LOCAL of inventory
|
|
ServerToLocalAutoCopyInventory.init("INVENTORY");
|
|
|
|
// Create the observers for auto-copy SERVER->LOCAL of exchange
|
|
ServerToLocalAutoCopyExchange.init("EXCHANGE");
|
|
|
|
// Create the observers for auto-copy SERVER->LOCAL of dm (animator) gift
|
|
ServerToLocalAutoCopyDMGift.init("DM_GIFT");
|
|
|
|
// Create the observers for auto-copy SERVER->LOCAL of context menu
|
|
ServerToLocalAutoCopyContextMenu.init("TARGET:CONTEXT_MENU");
|
|
|
|
// Create the observers for auto-copy SERVER->LOCAL of Skill Points
|
|
ServerToLocalAutoCopySkillPoints.init("USER");
|
|
}
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
// Output error
|
|
nlwarning ("CFormLoader: Error while loading the form %s: %s", fileName.c_str(), e.what());
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#ifdef NL_OS_WINDOWS
|
|
# pragma warning (push)
|
|
# pragma warning (disable : 4355) // 'this' used in base member initializer list
|
|
#endif
|
|
CInterfaceManager::CServerToLocalAutoCopy::CServerToLocalAutoCopy() : _LocalObserver(*this), _ServerObserver(*this)
|
|
{
|
|
_ServerCounter= NULL;
|
|
_UpdateList.reserve(300);
|
|
_LocalUpdating= false;
|
|
}
|
|
#ifdef NL_OS_WINDOWS
|
|
# pragma warning (pop)
|
|
#endif
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// unhook from everything we are tangled up in
|
|
void CInterfaceManager::CServerToLocalAutoCopy::release()
|
|
{
|
|
_Nodes.clear();
|
|
_ServerCounter = NULL;
|
|
_ServerNodeMap.clear();
|
|
_LocalNodeMap.clear();
|
|
_UpdateList.clear();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::CServerToLocalAutoCopy::buildRecursLocalLeaves(CCDBNodeBranch *branch, std::vector<CCDBNodeLeaf*> &leaves)
|
|
{
|
|
for(uint i=0;i<branch->getNbNodes();i++)
|
|
{
|
|
ICDBNode *node= branch->getNode(i);
|
|
if(node)
|
|
{
|
|
CCDBNodeLeaf *leaf= dynamic_cast<CCDBNodeLeaf*>(node);
|
|
if(leaf)
|
|
{
|
|
// just append to list
|
|
leaves.push_back(leaf);
|
|
}
|
|
else
|
|
{
|
|
// recurs if a branch (should be...)
|
|
CCDBNodeBranch *sonBranch= dynamic_cast<CCDBNodeBranch*>(node);
|
|
if(sonBranch)
|
|
buildRecursLocalLeaves(sonBranch, leaves);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::CServerToLocalAutoCopy::init(const std::string &dbPath)
|
|
{
|
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
|
|
|
// Get the synchronisation Counter in Server DB
|
|
_ServerCounter= pIM->getDbProp(string("SERVER:") + dbPath + ":COUNTER", false);
|
|
|
|
// if found
|
|
if(_ServerCounter)
|
|
{
|
|
// **** Add Observers on all nodes
|
|
// add the observers when server node change
|
|
pIM->addDBObserver(&_ServerObserver, string("SERVER:") + dbPath);
|
|
|
|
// add the observers when local node change
|
|
pIM->addDBObserver(&_LocalObserver, string("LOCAL:") + dbPath);
|
|
|
|
// **** Init the Nodes shortcut
|
|
// Parse all Local Nodes
|
|
CCDBNodeBranch *localBranch= pIM->getDbBranch(string("LOCAL:") + dbPath);
|
|
if(localBranch)
|
|
{
|
|
uint i;
|
|
std::vector<CCDBNodeLeaf*> leaves;
|
|
buildRecursLocalLeaves(localBranch, leaves);
|
|
|
|
// --- build _Nodes
|
|
_Nodes.reserve(leaves.size());
|
|
for(i=0;i<leaves.size();i++)
|
|
{
|
|
CCDBNodeLeaf *localLeaf= leaves[i];
|
|
|
|
// get the SERVER associated node name
|
|
string serverLeafStr= *localLeaf->getName();
|
|
CCDBNodeBranch* parent= localLeaf->getParent();
|
|
while( *parent->getName()!="LOCAL" )
|
|
{
|
|
serverLeafStr= *parent->getName()+":"+serverLeafStr;
|
|
parent= parent->getParent();
|
|
}
|
|
serverLeafStr= "SERVER:" + serverLeafStr;
|
|
|
|
// try then to get this server node
|
|
CCDBNodeLeaf *serverLeaf= pIM->getDbProp(serverLeafStr, false);
|
|
if(serverLeaf)
|
|
{
|
|
// Both server and local leaves exist, ok, append to _Nodes
|
|
CNode node;
|
|
node.ServerNode= serverLeaf;
|
|
node.LocalNode= localLeaf;
|
|
_Nodes.push_back(node);
|
|
}
|
|
}
|
|
|
|
// --- Init the maps
|
|
_ServerNodeMap.reserve(leaves.size());
|
|
_LocalNodeMap.reserve(leaves.size());
|
|
// For all valid _Nodes, insert in "map"
|
|
for(i=0;i<_Nodes.size();i++)
|
|
{
|
|
CNodeLocalComp lc;
|
|
CNodeServerComp sc;
|
|
lc.Node= &_Nodes[i];
|
|
sc.Node= &_Nodes[i];
|
|
_LocalNodeMap.push_back(lc);
|
|
_ServerNodeMap.push_back(sc);
|
|
}
|
|
// then sort
|
|
sort(_LocalNodeMap.begin(), _LocalNodeMap.end());
|
|
sort(_ServerNodeMap.begin(), _ServerNodeMap.end());
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::CServerToLocalAutoCopy::onServerChange(ICDBNode *serverNode)
|
|
{
|
|
if(_Nodes.empty())
|
|
return;
|
|
CCDBNodeLeaf *serverLeaf = safe_cast<CCDBNodeLeaf *>(serverNode);
|
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
|
|
|
// Add the leaf to the update list. only if not the counter
|
|
if(serverLeaf != _ServerCounter)
|
|
{
|
|
// build the map key
|
|
CNode nodeComp;
|
|
CNodeServerComp sc;
|
|
nodeComp.ServerNode= serverLeaf;
|
|
sc.Node= &nodeComp;
|
|
// try to find the node associated to this server leaf
|
|
uint index= searchLowerBound(_ServerNodeMap, sc);
|
|
// if found
|
|
if( index>0 || _ServerNodeMap[0].Node->ServerNode==serverLeaf )
|
|
{
|
|
CNode *node= _ServerNodeMap[index].Node;
|
|
// if this node is not already inserted
|
|
if(!node->InsertedInUpdateList)
|
|
{
|
|
// insert
|
|
node->InsertedInUpdateList= true;
|
|
_UpdateList.push_back(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
// if the client and server are synchonized.
|
|
if( ClientCfg.Local || pIM->localActionCounterSynchronizedWith(_ServerCounter) )
|
|
{
|
|
// update all leaves
|
|
for(uint i=0;i<_UpdateList.size();i++)
|
|
{
|
|
CNode *node= _UpdateList[i];
|
|
|
|
_LocalUpdating= true;
|
|
node->LocalNode->setValue64(node->ServerNode->getValue64());
|
|
_LocalUpdating= false;
|
|
|
|
// reset inserted flag
|
|
node->InsertedInUpdateList= false;
|
|
}
|
|
|
|
// clear update list
|
|
_UpdateList.clear();
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CInterfaceManager::CServerToLocalAutoCopy::onLocalChange(ICDBNode *localNode)
|
|
{
|
|
if(_Nodes.empty())
|
|
return;
|
|
|
|
// if the local changes because of localLeaf->setValue64() in onServerChange(), no-op !!!
|
|
if(_LocalUpdating)
|
|
return;
|
|
|
|
CCDBNodeLeaf *localLeaf = safe_cast<CCDBNodeLeaf *>(localNode);
|
|
|
|
// Add the leaf to the update list
|
|
// build the map key
|
|
CNode nodeComp;
|
|
CNodeLocalComp lc;
|
|
nodeComp.LocalNode= localLeaf;
|
|
lc.Node= &nodeComp;
|
|
// try to find the node associated to this local leaf
|
|
uint index= searchLowerBound(_LocalNodeMap, lc);
|
|
// if found
|
|
if( index>0 || _LocalNodeMap[0].Node->LocalNode==localLeaf )
|
|
{
|
|
CNode *node= _LocalNodeMap[index].Node;
|
|
// if this node is not already inserted
|
|
if(!node->InsertedInUpdateList)
|
|
{
|
|
// insert
|
|
node->InsertedInUpdateList= true;
|
|
_UpdateList.push_back(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
char* CInterfaceManager::getTimestampHuman(const char* format /* "[%H:%M:%S] " */)
|
|
{
|
|
static char cstime[25];
|
|
time_t date;
|
|
time (&date);
|
|
struct tm *tms = localtime(&date);
|
|
if (tms)
|
|
{
|
|
strftime(cstime, 25, format, tms);
|
|
}
|
|
else
|
|
{
|
|
strcpy(cstime, "");
|
|
}
|
|
|
|
return cstime;
|
|
}
|
|
|
|
|
|
/*
|
|
* Parse tokens in a chatmessage or emote
|
|
*
|
|
* Valid subjects:
|
|
* $me$
|
|
* $t$
|
|
* $tt$
|
|
* $tm1$..$tm8$
|
|
*
|
|
* Valid parameters:
|
|
* $<subject>.name$
|
|
* $<subject>.title$
|
|
* $<subject>.race$
|
|
* $<subject>.guild$
|
|
* $<subject>.gs(m/f/n)$
|
|
*
|
|
* Default parameter if parameter result is empty:
|
|
* $<subject>.<parameter>/<default>$
|
|
*
|
|
* All \d's in default parameter remove a following character.
|
|
*/
|
|
bool CInterfaceManager::parseTokens(ucstring& ucstr)
|
|
{
|
|
ucstring str = ucstr;
|
|
ucstring start_token("$");
|
|
ucstring end_token("$");
|
|
size_t start_pos = 0;
|
|
size_t end_pos = 1;
|
|
|
|
sint endless_loop_protector = 0;
|
|
while ((start_pos < str.length() - 1) &&
|
|
((start_pos = str.find(start_token, start_pos)) != string::npos))
|
|
{
|
|
endless_loop_protector++;
|
|
if (endless_loop_protector > 100)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Get the whole token substring first
|
|
end_pos = str.find(end_token, start_pos + 1);
|
|
|
|
if ((start_pos == ucstring::npos) ||
|
|
(end_pos == ucstring::npos) ||
|
|
(end_pos <= start_pos + 1))
|
|
{
|
|
// Wrong formatting; give up on this one.
|
|
start_pos = max(start_pos, end_pos);
|
|
continue;
|
|
}
|
|
|
|
// Get everything between the two "$"
|
|
size_t token_start_pos = start_pos + start_token.length();
|
|
size_t token_end_pos = end_pos - end_token.length();
|
|
if (token_start_pos < token_end_pos)
|
|
{
|
|
// Wrong formatting; give up on this one.
|
|
start_pos = end_pos;
|
|
continue;
|
|
}
|
|
|
|
ucstring token_whole = str.luabind_substr(start_pos, end_pos - start_pos + 1);
|
|
ucstring token_string = token_whole.luabind_substr(1, token_whole.length() - 2);
|
|
ucstring token_replacement = token_whole;
|
|
ucstring token_default = token_whole;
|
|
|
|
ucstring token_subject;
|
|
ucstring token_param;
|
|
|
|
// Does the token have a parameter?
|
|
// If not it is 'name' by default
|
|
vector<ucstring> token_vector;
|
|
vector<ucstring> param_vector;
|
|
splitUCString(token_string, ucstring("."), token_vector);
|
|
if (token_vector.size() == 0)
|
|
{
|
|
// Wrong formatting; give up on this one.
|
|
start_pos = end_pos;
|
|
continue;
|
|
}
|
|
token_subject = token_vector[0];
|
|
if (token_vector.size() == 1)
|
|
{
|
|
splitUCString(token_subject, ucstring("/"), param_vector);
|
|
token_subject = (param_vector.size() > 0) ? param_vector[0] : ucstring("");
|
|
token_param = ucstring("name");
|
|
}
|
|
else if (token_vector.size() > 1)
|
|
{
|
|
token_param = token_vector[1];
|
|
if (token_param.luabind_substr(0, 3) != ucstring("gs("))
|
|
{
|
|
splitUCString(token_vector[1], ucstring("/"), param_vector);
|
|
token_param = (param_vector.size() > 0) ? param_vector[0] : ucstring("");
|
|
}
|
|
}
|
|
|
|
// Get any default value, if not gs
|
|
sint extra_replacement = 0;
|
|
if (token_param.luabind_substr(0, 3) != ucstring("gs("))
|
|
{
|
|
if (param_vector.size() == 2)
|
|
{
|
|
// Set default value
|
|
token_replacement = param_vector[1];
|
|
// Delete following chars for every '\d' in default
|
|
string::size_type token_replacement_pos;
|
|
while ((token_replacement_pos = token_replacement.find(ucstring("\\d"))) != string::npos)
|
|
{
|
|
token_replacement.replace(token_replacement_pos, 2, ucstring(""));
|
|
extra_replacement++;
|
|
}
|
|
token_default = token_replacement;
|
|
}
|
|
}
|
|
|
|
CEntityCL *pTokenSubjectEntity = NULL;
|
|
|
|
if (token_subject == ucstring("me"))
|
|
{
|
|
pTokenSubjectEntity = static_cast<CEntityCL*>(UserEntity);
|
|
}
|
|
else if (token_subject == ucstring("t"))
|
|
{
|
|
// Target
|
|
uint targetSlot = UserEntity->targetSlot();
|
|
pTokenSubjectEntity = EntitiesMngr.entity(targetSlot);
|
|
}
|
|
else if (token_subject == ucstring("tt"))
|
|
{
|
|
// Target's target
|
|
uint targetSlot = UserEntity->targetSlot();
|
|
CEntityCL *target = EntitiesMngr.entity(targetSlot);
|
|
|
|
if (target)
|
|
{
|
|
// Check the new slot.
|
|
CLFECOMMON::TCLEntityId newSlot = target->targetSlot();
|
|
CEntityCL* pE = EntitiesMngr.entity(newSlot);
|
|
if (pE)
|
|
{
|
|
pTokenSubjectEntity = pE;
|
|
}
|
|
}
|
|
}
|
|
else if ((token_subject.length() == 3) &&
|
|
(token_subject.luabind_substr(0, 2) == ucstring("tm")))
|
|
{
|
|
// Teammate
|
|
uint indexInTeam = 0;
|
|
fromString(token_subject.luabind_substr(2, 1).toString(), indexInTeam);
|
|
|
|
// Make 0-based
|
|
--indexInTeam;
|
|
if (indexInTeam < PeopleInterraction.TeamList.getNumPeople() )
|
|
{
|
|
// Index is the database index (serverIndex() not used for team list)
|
|
CCDBNodeLeaf *pNL = CInterfaceManager::getInstance()->getDbProp( NLMISC::toString(TEAM_DB_PATH ":%hu:NAME", indexInTeam ), false);
|
|
if (pNL && pNL->getValueBool() )
|
|
{
|
|
// There is a character corresponding to this index
|
|
pNL = CInterfaceManager::getInstance()->getDbProp( NLMISC::toString( TEAM_DB_PATH ":%hu:UID", indexInTeam ), false );
|
|
if (pNL)
|
|
{
|
|
CLFECOMMON::TClientDataSetIndex compressedIndex = pNL->getValue32();
|
|
|
|
// Search entity in vision
|
|
CEntityCL *entity = EntitiesMngr.getEntityByCompressedIndex( compressedIndex );
|
|
if (entity)
|
|
{
|
|
pTokenSubjectEntity = entity;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Unknown token subject, skip it
|
|
start_pos = end_pos;
|
|
continue;
|
|
}
|
|
|
|
if (pTokenSubjectEntity != NULL)
|
|
{
|
|
// Parse the parameter
|
|
if (token_param == ucstring("name"))
|
|
{
|
|
ucstring name = pTokenSubjectEntity->getDisplayName();
|
|
// special case where there is only a title, very rare case for some NPC
|
|
if (name.empty())
|
|
{
|
|
name = pTokenSubjectEntity->getTitle();
|
|
}
|
|
token_replacement = name.empty() ? token_replacement : name;
|
|
}
|
|
else if (token_param == ucstring("title"))
|
|
{
|
|
ucstring title = pTokenSubjectEntity->getTitle();
|
|
token_replacement = title.empty() ? token_replacement : title;
|
|
}
|
|
else if (token_param == ucstring("race"))
|
|
{
|
|
CCharacterCL *pC = dynamic_cast<CCharacterCL*>(pTokenSubjectEntity);
|
|
if (pC)
|
|
{
|
|
EGSPD::CPeople::TPeople race = pC->people();
|
|
if (race >= EGSPD::CPeople::Playable && race <= EGSPD::CPeople::EndPlayable)
|
|
{
|
|
ucstring srace = NLMISC::CI18N::get("io" + EGSPD::CPeople::toString(race));
|
|
token_replacement = srace.empty() ? token_replacement : srace;
|
|
}
|
|
}
|
|
}
|
|
else if (token_param == ucstring("guild"))
|
|
{
|
|
STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
|
|
ucstring ucGuildName;
|
|
if (pSMC->getString(pTokenSubjectEntity->getGuildNameID(), ucGuildName))
|
|
{
|
|
token_replacement = ucGuildName.empty() ? token_replacement : ucGuildName;
|
|
}
|
|
}
|
|
else if (token_param.luabind_substr(0, 3) == ucstring("gs(") &&
|
|
token_param.luabind_substr(token_param.length() - 1 , 1) == ucstring(")"))
|
|
{
|
|
// Gender string
|
|
vector<ucstring> strList;
|
|
ucstring gender_string = token_param.luabind_substr(3, token_param.length() - 4);
|
|
splitUCString(gender_string, ucstring("/"), strList);
|
|
|
|
if (strList.size() <= 1)
|
|
{
|
|
start_pos = end_pos;
|
|
continue;
|
|
}
|
|
|
|
// We only care about the gender if the subject is humanoid.
|
|
GSGENDER::EGender gender = GSGENDER::neutral;
|
|
if (pTokenSubjectEntity->isUser() || pTokenSubjectEntity->isPlayer() || pTokenSubjectEntity->isNPC())
|
|
{
|
|
CCharacterCL *pC = dynamic_cast<CCharacterCL*>(pTokenSubjectEntity);
|
|
if (pC)
|
|
{
|
|
gender = pC->getGender();
|
|
}
|
|
}
|
|
|
|
// The neuter part is optional. Fallback to male if something is wrong.
|
|
GSGENDER::EGender g = ((uint)gender >= strList.size()) ? GSGENDER::male : gender;
|
|
token_replacement = strList[g];
|
|
}
|
|
}
|
|
|
|
if (token_whole == token_replacement)
|
|
{
|
|
// Nothing to replace; show message and exit
|
|
CInterfaceManager *im = CInterfaceManager::getInstance();
|
|
ucstring message = ucstring(CI18N::get("uiUntranslatedToken"));
|
|
message.replace(message.find(ucstring("%s")), 2, token_whole);
|
|
im->displaySystemInfo(message);
|
|
return false;
|
|
}
|
|
|
|
// Replace token
|
|
size_t token_whole_pos = str.find(token_whole);
|
|
|
|
// Only do extra replacement spaces if using default
|
|
extra_replacement = (token_replacement == token_default) ? extra_replacement : 0;
|
|
if (str.find(token_whole, start_pos) != string::npos)
|
|
{
|
|
str = str.replace(token_whole_pos, token_whole.length() + extra_replacement, token_replacement);
|
|
start_pos = token_whole_pos + token_replacement.length();
|
|
}
|
|
}
|
|
|
|
ucstr = str;
|
|
return true;;
|
|
} |