2016-06-14 17:06:39 +02:00
/* Copyright (C) 2016 Wildfire Games.
2009-04-18 19:00:33 +02:00
* This file is part of 0 A . D .
*
* 0 A . D . is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 2 of the License , or
* ( at your option ) any later version .
*
* 0 A . D . 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 General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with 0 A . D . If not , see < http : //www.gnu.org/licenses/>.
*/
2004-06-03 20:38:14 +02:00
# include "precompiled.h"
2004-06-15 23:08:05 +02:00
2004-09-19 13:38:54 +02:00
# include <stdarg.h>
2015-08-21 19:08:41 +02:00
# include <string>
2004-09-19 13:38:54 +02:00
2003-11-03 17:22:45 +01:00
# include "GUI.h"
2004-05-29 06:06:50 +02:00
// Types - when including them into the engine.
# include "CButton.h"
# include "CCheckBox.h"
2015-08-21 19:08:41 +02:00
# include "CDropDown.h"
# include "CImage.h"
2004-10-14 12:09:26 +02:00
# include "CInput.h"
2005-04-07 11:13:10 +02:00
# include "CList.h"
2013-11-07 21:07:24 +01:00
# include "COList.h"
2004-10-14 04:32:26 +02:00
# include "CProgressBar.h"
2015-08-21 19:08:41 +02:00
# include "CRadioButton.h"
# include "CText.h"
2004-12-21 14:37:24 +01:00
# include "CTooltip.h"
2004-10-08 03:10:14 +02:00
# include "MiniMap.h"
2004-05-29 06:06:50 +02:00
2013-10-18 17:53:07 +02:00
# include "graphics/FontMetrics.h"
2012-01-30 01:27:23 +01:00
# include "graphics/ShaderManager.h"
2012-01-29 21:04:21 +01:00
# include "graphics/TextRenderer.h"
2014-04-20 22:03:57 +02:00
# include "i18n/L10n.h"
2015-08-21 19:08:41 +02:00
# include "lib/bits.h"
# include "lib/input.h"
2007-12-20 21:21:45 +01:00
# include "lib/sysdep/sysdep.h"
2015-08-21 19:08:41 +02:00
# include "lib/timer.h"
2014-04-20 22:03:57 +02:00
# include "lib/utf8.h"
2012-01-29 21:04:21 +01:00
# include "ps/CLogger.h"
# include "ps/Filesystem.h"
2016-08-02 18:58:30 +02:00
# include "ps/GameSetup/Config.h"
2012-01-29 21:04:21 +01:00
# include "ps/Globals.h"
2015-08-21 19:08:41 +02:00
# include "ps/Hotkey.h"
2007-06-15 19:03:26 +02:00
# include "ps/Profile.h"
2012-01-29 21:04:21 +01:00
# include "ps/Pyrogenesis.h"
# include "ps/XML/Xeromyces.h"
2012-01-30 01:27:23 +01:00
# include "renderer/Renderer.h"
2015-08-21 19:08:41 +02:00
# include "scripting/ScriptFunctions.h"
2010-11-17 00:00:52 +01:00
# include "scriptinterface/ScriptInterface.h"
2012-01-29 21:04:21 +01:00
extern int g_yres ;
2004-07-08 17:23:47 +02:00
2006-01-21 12:07:25 +01:00
const double SELECT_DBLCLICK_RATE = 0.5 ;
2015-06-01 02:29:23 +02:00
const u32 MAX_OBJECT_DEPTH = 100 ; // Max number of nesting for GUI includes. Used to detect recursive inclusion
2004-08-15 22:57:31 +02:00
2006-08-26 23:52:18 +02:00
InReaction CGUI : : HandleEvent ( const SDL_Event_ * ev )
2003-11-03 17:22:45 +01:00
{
2005-10-20 17:27:39 +02:00
InReaction ret = IN_PASS ;
2004-10-14 12:09:26 +02:00
2010-10-23 04:37:00 +02:00
if ( ev - > ev . type = = SDL_HOTKEYDOWN )
2004-07-22 18:18:12 +02:00
{
2010-10-23 04:37:00 +02:00
const char * hotkey = static_cast < const char * > ( ev - > ev . user . data1 ) ;
std : : map < CStr , std : : vector < IGUIObject * > > : : iterator it = m_HotkeyObjects . find ( hotkey ) ;
if ( it ! = m_HotkeyObjects . end ( ) )
2015-08-21 19:08:41 +02:00
for ( IGUIObject * const & obj : it - > second )
obj - > SendEvent ( GUIM_PRESSED , " press " ) ;
2004-07-22 18:18:12 +02:00
}
2006-08-26 23:52:18 +02:00
else if ( ev - > ev . type = = SDL_MOUSEMOTION )
2003-12-27 07:26:03 +01:00
{
2004-09-03 07:48:47 +02:00
// Yes the mouse position is stored as float to avoid
2005-10-20 19:44:56 +02:00
// constant conversions when operating in a
2004-09-03 07:48:47 +02:00
// float-based environment.
2015-01-24 21:06:37 +01:00
m_MousePos = CPos ( ( float ) ev - > ev . motion . x * g_GuiScale , ( float ) ev - > ev . motion . y * g_GuiScale ) ;
2003-11-03 17:22:45 +01:00
2011-04-28 22:42:11 +02:00
SGUIMessage msg ( GUIM_MOUSE_MOTION ) ;
2015-08-21 19:08:41 +02:00
GUI < SGUIMessage > : : RecurseObject ( GUIRR_HIDDEN | GUIRR_GHOST , m_BaseObject ,
& IGUIObject : : HandleMessage ,
2011-04-28 22:42:11 +02:00
msg ) ;
2003-12-27 07:26:03 +01:00
}
2004-07-08 17:23:47 +02:00
// Update m_MouseButtons. (BUTTONUP is handled later.)
2006-08-26 23:52:18 +02:00
else if ( ev - > ev . type = = SDL_MOUSEBUTTONDOWN )
2003-12-27 07:26:03 +01:00
{
2006-08-26 23:52:18 +02:00
switch ( ev - > ev . button . button )
2005-10-24 23:10:45 +02:00
{
case SDL_BUTTON_LEFT :
case SDL_BUTTON_RIGHT :
case SDL_BUTTON_MIDDLE :
2008-09-06 23:15:53 +02:00
m_MouseButtons | = Bit < unsigned int > ( ev - > ev . button . button ) ;
2005-10-24 23:10:45 +02:00
break ;
default :
break ;
}
2003-12-27 07:26:03 +01:00
}
2010-11-14 23:47:39 +01:00
// Update m_MousePos (for delayed mouse button events)
CPos oldMousePos = m_MousePos ;
if ( ev - > ev . type = = SDL_MOUSEBUTTONDOWN | | ev - > ev . type = = SDL_MOUSEBUTTONUP )
{
2015-01-24 21:06:37 +01:00
m_MousePos = CPos ( ( float ) ev - > ev . button . x * g_GuiScale , ( float ) ev - > ev . button . y * g_GuiScale ) ;
2010-11-14 23:47:39 +01:00
}
2003-11-03 17:22:45 +01:00
// Only one object can be hovered
2015-08-21 19:08:41 +02:00
IGUIObject * pNearest = NULL ;
2003-11-03 17:22:45 +01:00
2004-10-14 12:09:26 +02:00
// TODO Gee: (2004-09-08) Big TODO, don't do the below if the SDL_Event is something like a keypress!
2003-11-25 03:47:12 +01:00
try
2003-11-03 17:22:45 +01:00
{
2015-08-21 19:08:41 +02:00
PROFILE ( " mouse events " ) ;
2004-05-29 06:06:50 +02:00
// TODO Gee: Optimizations needed!
// these two recursive function are quite overhead heavy.
2003-11-25 03:47:12 +01:00
// pNearest will after this point at the hovered object, possibly NULL
2010-08-22 01:58:08 +02:00
pNearest = FindObjectUnderMouse ( ) ;
2004-07-11 18:22:35 +02:00
2003-11-25 03:47:12 +01:00
// Now we'll call UpdateMouseOver on *all* objects,
// we'll input the one hovered, and they will each
// update their own data and send messages accordingly
2016-06-14 17:06:39 +02:00
GUI < IGUIObject * > : : RecurseObject ( GUIRR_HIDDEN | GUIRR_GHOST ,
m_BaseObject , & IGUIObject : : UpdateMouseOver , pNearest ) ;
2003-11-25 03:47:12 +01:00
2006-08-26 23:52:18 +02:00
if ( ev - > ev . type = = SDL_MOUSEBUTTONDOWN )
2003-11-25 03:47:12 +01:00
{
2006-08-26 23:52:18 +02:00
switch ( ev - > ev . button . button )
2003-11-25 03:47:12 +01:00
{
2004-05-29 06:06:50 +02:00
case SDL_BUTTON_LEFT :
2010-08-13 15:50:03 +02:00
// Focus the clicked object (or focus none if nothing clicked on)
SetFocusedObject ( pNearest ) ;
2004-05-29 06:06:50 +02:00
if ( pNearest )
2011-04-28 22:42:11 +02:00
ret = pNearest - > SendEvent ( GUIM_MOUSE_PRESS_LEFT , " mouseleftpress " ) ;
2004-07-11 18:22:35 +02:00
break ;
2004-05-29 06:06:50 +02:00
2010-08-22 01:58:08 +02:00
case SDL_BUTTON_RIGHT :
if ( pNearest )
2011-04-28 22:42:11 +02:00
ret = pNearest - > SendEvent ( GUIM_MOUSE_PRESS_RIGHT , " mouserightpress " ) ;
2010-08-22 01:58:08 +02:00
break ;
2004-05-29 06:06:50 +02:00
default :
break ;
}
}
2016-06-14 17:06:39 +02:00
else if ( ev - > ev . type = = SDL_MOUSEWHEEL & & pNearest )
2012-02-06 23:47:35 +01:00
{
if ( ev - > ev . wheel . y < 0 )
2016-06-14 17:06:39 +02:00
ret = pNearest - > SendEvent ( GUIM_MOUSE_WHEEL_DOWN , " mousewheeldown " ) ;
2012-02-06 23:47:35 +01:00
else if ( ev - > ev . wheel . y > 0 )
2016-06-14 17:06:39 +02:00
ret = pNearest - > SendEvent ( GUIM_MOUSE_WHEEL_UP , " mousewheelup " ) ;
2012-02-06 23:47:35 +01:00
}
else if ( ev - > ev . type = = SDL_MOUSEBUTTONUP )
2004-05-29 06:06:50 +02:00
{
2006-08-26 23:52:18 +02:00
switch ( ev - > ev . button . button )
2004-05-29 06:06:50 +02:00
{
2004-12-21 14:37:24 +01:00
case SDL_BUTTON_LEFT :
2003-12-27 07:26:03 +01:00
if ( pNearest )
2004-07-11 18:22:35 +02:00
{
2008-01-07 21:03:19 +01:00
double timeElapsed = timer_Time ( ) - pNearest - > m_LastClickTime [ SDL_BUTTON_LEFT ] ;
pNearest - > m_LastClickTime [ SDL_BUTTON_LEFT ] = timer_Time ( ) ;
2015-08-21 19:08:41 +02:00
2006-01-21 12:07:25 +01:00
if ( timeElapsed < SELECT_DBLCLICK_RATE )
2011-04-28 22:42:11 +02:00
ret = pNearest - > SendEvent ( GUIM_MOUSE_DBLCLICK_LEFT , " mouseleftdoubleclick " ) ;
2006-01-21 12:07:25 +01:00
else
2011-04-28 22:42:11 +02:00
ret = pNearest - > SendEvent ( GUIM_MOUSE_RELEASE_LEFT , " mouseleftrelease " ) ;
2006-01-21 12:07:25 +01:00
}
break ;
case SDL_BUTTON_RIGHT :
if ( pNearest )
{
2008-01-07 21:03:19 +01:00
double timeElapsed = timer_Time ( ) - pNearest - > m_LastClickTime [ SDL_BUTTON_RIGHT ] ;
pNearest - > m_LastClickTime [ SDL_BUTTON_RIGHT ] = timer_Time ( ) ;
2015-08-21 19:08:41 +02:00
2006-01-21 12:07:25 +01:00
if ( timeElapsed < SELECT_DBLCLICK_RATE )
2011-04-28 22:42:11 +02:00
ret = pNearest - > SendEvent ( GUIM_MOUSE_DBLCLICK_RIGHT , " mouserightdoubleclick " ) ;
2006-01-21 12:07:25 +01:00
else
2011-04-28 22:42:11 +02:00
ret = pNearest - > SendEvent ( GUIM_MOUSE_RELEASE_RIGHT , " mouserightrelease " ) ;
2004-07-11 18:22:35 +02:00
}
2004-12-21 14:37:24 +01:00
break ;
2003-12-27 07:26:03 +01:00
}
2004-05-29 06:06:50 +02:00
// Reset all states on all visible objects
2015-08-21 19:08:41 +02:00
GUI < > : : RecurseObject ( GUIRR_HIDDEN , m_BaseObject ,
2004-05-29 06:06:50 +02:00
& IGUIObject : : ResetStates ) ;
2014-03-07 23:43:57 +01:00
// Since the hover state will have been reset, we reload it.
2016-06-14 17:06:39 +02:00
GUI < IGUIObject * > : : RecurseObject ( GUIRR_HIDDEN | GUIRR_GHOST ,
m_BaseObject , & IGUIObject : : UpdateMouseOver , pNearest ) ;
2003-11-25 03:47:12 +01:00
}
}
2009-09-27 17:04:46 +02:00
catch ( PSERROR_GUI & e )
2003-11-25 03:47:12 +01:00
{
2005-08-09 18:02:15 +02:00
UNUSED2 ( e ) ;
2009-11-03 22:46:35 +01:00
debug_warn ( L " CGUI::HandleEvent error " ) ;
2003-12-27 07:26:03 +01:00
// TODO Gee: Handle
2003-11-25 03:47:12 +01:00
}
2003-11-03 17:22:45 +01:00
2004-07-08 17:23:47 +02:00
// BUTTONUP's effect on m_MouseButtons is handled after
// everything else, so that e.g. 'press' handlers (activated
// on button up) see which mouse button had been pressed.
2006-08-26 23:52:18 +02:00
if ( ev - > ev . type = = SDL_MOUSEBUTTONUP )
2004-07-08 17:23:47 +02:00
{
2006-08-26 23:52:18 +02:00
switch ( ev - > ev . button . button )
2005-10-24 23:10:45 +02:00
{
case SDL_BUTTON_LEFT :
case SDL_BUTTON_RIGHT :
case SDL_BUTTON_MIDDLE :
2008-09-06 23:15:53 +02:00
m_MouseButtons & = ~ Bit < unsigned int > ( ev - > ev . button . button ) ;
2005-10-24 23:10:45 +02:00
break ;
default :
break ;
}
2004-07-08 17:23:47 +02:00
}
2010-11-14 23:47:39 +01:00
// Restore m_MousePos (for delayed mouse button events)
if ( ev - > ev . type = = SDL_MOUSEBUTTONDOWN | | ev - > ev . type = = SDL_MOUSEBUTTONUP )
m_MousePos = oldMousePos ;
2004-10-14 12:09:26 +02:00
// Handle keys for input boxes
2005-01-22 19:46:03 +01:00
if ( GetFocusedObject ( ) )
2004-10-14 12:09:26 +02:00
{
2016-06-14 17:06:39 +02:00
if ( ( ev - > ev . type = = SDL_KEYDOWN & &
ev - > ev . key . keysym . sym ! = SDLK_ESCAPE & &
! g_keys [ SDLK_LCTRL ] & & ! g_keys [ SDLK_RCTRL ] & &
! g_keys [ SDLK_LALT ] & & ! g_keys [ SDLK_RALT ] ) | |
ev - > ev . type = = SDL_HOTKEYDOWN | |
ev - > ev . type = = SDL_TEXTINPUT | |
ev - > ev . type = = SDL_TEXTEDITING )
2004-10-14 12:09:26 +02:00
{
ret = GetFocusedObject ( ) - > ManuallyHandleEvent ( ev ) ;
}
2005-10-20 19:44:56 +02:00
// else will return IN_PASS because we never used the button.
2004-10-14 12:09:26 +02:00
}
return ret ;
2003-11-03 17:22:45 +01:00
}
2004-07-24 21:09:12 +02:00
void CGUI : : TickObjects ( )
{
CStr action = " tick " ;
2015-08-21 19:08:41 +02:00
GUI < CStr > : : RecurseObject ( 0 , m_BaseObject ,
2004-07-24 21:09:12 +02:00
& IGUIObject : : ScriptEvent , action ) ;
2004-12-21 14:37:24 +01:00
2010-08-22 01:58:08 +02:00
m_Tooltip . Update ( FindObjectUnderMouse ( ) , m_MousePos , this ) ;
2004-07-24 21:09:12 +02:00
}
2006-07-20 16:37:58 +02:00
void CGUI : : SendEventToAll ( const CStr & EventName )
2005-01-01 18:30:55 +01:00
{
2006-03-03 07:03:16 +01:00
// janwas 2006-03-03: spoke with Ykkrosh about EventName case.
// when registering, case is converted to lower - this avoids surprise
// if someone were to get the case wrong and then not notice their
// handler is never called. however, until now, the other end
// (sending events here) wasn't converting to lower case,
// leading to a similar problem.
// now fixed; case is irrelevant since all are converted to lower.
2015-08-21 19:08:41 +02:00
GUI < CStr > : : RecurseObject ( 0 , m_BaseObject ,
2006-03-03 07:03:16 +01:00
& IGUIObject : : ScriptEvent , EventName . LowerCase ( ) ) ;
2005-01-01 18:30:55 +01:00
}
2015-08-21 19:08:41 +02:00
CGUI : : CGUI ( const shared_ptr < ScriptRuntime > & runtime )
: m_MouseButtons ( 0 ) , m_FocusedObject ( NULL ) , m_InternalNameNumber ( 0 )
2003-11-03 17:22:45 +01:00
{
2014-01-04 11:14:53 +01:00
m_ScriptInterface . reset ( new ScriptInterface ( " Engine " , " GUIPage " , runtime ) ) ;
GuiScriptingInit ( * m_ScriptInterface ) ;
2014-01-17 19:21:27 +01:00
m_ScriptInterface - > LoadGlobalScripts ( ) ;
2003-11-06 12:54:46 +01:00
m_BaseObject = new CGUIDummyObject ;
2015-08-21 19:08:41 +02:00
m_BaseObject - > SetGUI ( this ) ;
2003-11-03 17:22:45 +01:00
}
CGUI : : ~ CGUI ( )
{
2009-12-03 21:17:22 +01:00
Destroy ( ) ;
2003-11-03 17:22:45 +01:00
if ( m_BaseObject )
delete m_BaseObject ;
}
2015-08-21 19:08:41 +02:00
IGUIObject * CGUI : : ConstructObject ( const CStr & str )
2003-11-03 17:22:45 +01:00
{
if ( m_ObjectTypes . count ( str ) > 0 )
return ( * m_ObjectTypes [ str ] ) ( ) ;
else
2003-11-24 03:18:41 +01:00
{
2004-09-02 05:02:32 +02:00
// Error reporting will be handled with the NULL return.
2003-11-03 17:22:45 +01:00
return NULL ;
2003-11-24 03:18:41 +01:00
}
2003-11-03 17:22:45 +01:00
}
2003-11-24 03:18:41 +01:00
void CGUI : : Initialize ( )
2003-11-03 17:22:45 +01:00
{
// Add base types!
2003-11-24 03:18:41 +01:00
// You can also add types outside the GUI to extend the flexibility of the GUI.
2004-12-05 22:56:09 +01:00
// Pyrogenesis though will have all the object types inserted from here.
2004-05-29 06:06:50 +02:00
AddObjectType ( " empty " , & CGUIDummyObject : : ConstructObject ) ;
AddObjectType ( " button " , & CButton : : ConstructObject ) ;
2004-09-02 05:02:32 +02:00
AddObjectType ( " image " , & CImage : : ConstructObject ) ;
2004-05-29 06:06:50 +02:00
AddObjectType ( " text " , & CText : : ConstructObject ) ;
AddObjectType ( " checkbox " , & CCheckBox : : ConstructObject ) ;
AddObjectType ( " radiobutton " , & CRadioButton : : ConstructObject ) ;
2004-10-14 04:32:26 +02:00
AddObjectType ( " progressbar " , & CProgressBar : : ConstructObject ) ;
2009-12-03 21:17:22 +01:00
AddObjectType ( " minimap " , & CMiniMap : : ConstructObject ) ;
2004-10-14 12:09:26 +02:00
AddObjectType ( " input " , & CInput : : ConstructObject ) ;
2005-07-20 07:27:32 +02:00
AddObjectType ( " list " , & CList : : ConstructObject ) ;
2013-11-07 21:07:24 +01:00
AddObjectType ( " olist " , & COList : : ConstructObject ) ;
2005-04-24 01:20:50 +02:00
AddObjectType ( " dropdown " , & CDropDown : : ConstructObject ) ;
2012-03-08 21:42:28 +01:00
AddObjectType ( " tooltip " , & CTooltip : : ConstructObject ) ;
2003-11-03 17:22:45 +01:00
}
void CGUI : : Draw ( )
{
2004-07-08 17:23:47 +02:00
// Clear the depth buffer, so the GUI is
// drawn on top of everything else
glClear ( GL_DEPTH_BUFFER_BIT ) ;
2003-11-24 03:18:41 +01:00
2003-11-03 17:22:45 +01:00
try
{
2003-11-24 03:18:41 +01:00
// Recurse IGUIObject::Draw() with restriction: hidden
// meaning all hidden objects won't call Draw (nor will it recurse its children)
GUI < > : : RecurseObject ( GUIRR_HIDDEN , m_BaseObject , & IGUIObject : : Draw ) ;
2003-11-03 17:22:45 +01:00
}
2009-09-27 17:04:46 +02:00
catch ( PSERROR_GUI & e )
2003-11-03 17:22:45 +01:00
{
2015-01-22 21:36:24 +01:00
LOGERROR ( " GUI draw error: %s " , e . what ( ) ) ;
2003-11-03 17:22:45 +01:00
}
}
2015-08-21 19:08:41 +02:00
void CGUI : : DrawSprite ( const CGUISpriteInstance & Sprite , int CellID , const float & Z , const CRect & Rect , const CRect & UNUSED ( Clipping ) )
2003-12-01 08:06:55 +01:00
{
2004-12-15 22:24:46 +01:00
// If the sprite doesn't exist (name == ""), don't bother drawing anything
if ( Sprite . IsEmpty ( ) )
2003-12-01 08:06:55 +01:00
return ;
2004-07-24 16:04:40 +02:00
// TODO: Clipping?
2003-12-01 08:06:55 +01:00
2012-01-29 21:04:21 +01:00
Sprite . Draw ( Rect , CellID , m_Sprites , Z ) ;
2003-12-01 08:06:55 +01:00
}
2003-11-03 17:22:45 +01:00
void CGUI : : Destroy ( )
{
// We can use the map to delete all
2003-11-22 16:07:22 +01:00
// now we don't want to cancel all if one Destroy fails
2015-08-21 19:08:41 +02:00
for ( const std : : pair < CStr , IGUIObject * > & p : m_pAllObjects )
2003-11-03 17:22:45 +01:00
{
try
{
2015-08-21 19:08:41 +02:00
p . second - > Destroy ( ) ;
2003-11-03 17:22:45 +01:00
}
2009-09-27 17:04:46 +02:00
catch ( PSERROR_GUI & e )
2003-11-03 17:22:45 +01:00
{
2005-08-09 18:02:15 +02:00
UNUSED2 ( e ) ;
2009-11-03 22:46:35 +01:00
debug_warn ( L " CGUI::Destroy error " ) ;
2003-12-27 07:26:03 +01:00
// TODO Gee: Handle
2003-11-03 17:22:45 +01:00
}
2014-06-14 18:12:41 +02:00
2015-08-21 19:08:41 +02:00
delete p . second ;
2003-11-03 17:22:45 +01:00
}
m_pAllObjects . clear ( ) ;
2015-08-21 19:08:41 +02:00
for ( const std : : pair < CStr , CGUISprite * > & p : m_Sprites )
delete p . second ;
2003-11-03 17:22:45 +01:00
m_Sprites . clear ( ) ;
2004-08-31 04:09:58 +02:00
m_Icons . clear ( ) ;
2003-11-03 17:22:45 +01:00
}
2003-11-24 18:13:37 +01:00
void CGUI : : UpdateResolution ( )
{
2003-11-25 03:47:12 +01:00
// Update ALL cached
2015-08-21 19:08:41 +02:00
GUI < > : : RecurseObject ( 0 , m_BaseObject , & IGUIObject : : UpdateCachedSize ) ;
2003-11-24 18:13:37 +01:00
}
2003-11-24 03:18:41 +01:00
void CGUI : : AddObject ( IGUIObject * pObject )
2003-11-03 17:22:45 +01:00
{
2003-12-01 08:06:55 +01:00
try
{
2003-11-03 17:22:45 +01:00
// Add CGUI pointer
2003-11-24 03:18:41 +01:00
GUI < CGUI * > : : RecurseObject ( 0 , pObject , & IGUIObject : : SetGUI , this ) ;
2003-11-03 17:22:45 +01:00
2016-06-14 17:06:39 +02:00
m_BaseObject - > AddChild ( pObject ) ;
2003-11-25 03:47:12 +01:00
// Cache tree
GUI < > : : RecurseObject ( 0 , pObject , & IGUIObject : : UpdateCachedSize ) ;
2011-04-28 22:42:11 +02:00
SGUIMessage msg ( GUIM_LOAD ) ;
GUI < SGUIMessage > : : RecurseObject ( 0 , pObject , & IGUIObject : : HandleMessage , msg ) ;
2003-12-01 08:06:55 +01:00
}
2009-09-27 17:04:46 +02:00
catch ( PSERROR_GUI & )
2003-11-03 17:22:45 +01:00
{
2009-09-27 17:04:46 +02:00
throw ;
2003-12-01 08:06:55 +01:00
}
2003-11-03 17:22:45 +01:00
}
void CGUI : : UpdateObjects ( )
{
2016-06-14 17:06:39 +02:00
// We'll fill a temporary map until we know everything succeeded
2003-11-03 17:22:45 +01:00
map_pObjects AllObjects ;
try
{
// Fill freshly
2015-08-21 19:08:41 +02:00
GUI < map_pObjects > : : RecurseObject ( 0 , m_BaseObject , & IGUIObject : : AddToPointersMap , AllObjects ) ;
2003-11-03 17:22:45 +01:00
}
2009-09-27 17:04:46 +02:00
catch ( PSERROR_GUI & )
2003-11-03 17:22:45 +01:00
{
2009-09-27 17:04:46 +02:00
throw ;
2003-11-03 17:22:45 +01:00
}
// Else actually update the real one
2005-01-13 01:17:31 +01:00
m_pAllObjects . swap ( AllObjects ) ;
2003-11-03 17:22:45 +01:00
}
2004-06-18 16:07:06 +02:00
bool CGUI : : ObjectExists ( const CStr & Name ) const
2003-11-03 17:22:45 +01:00
{
2004-05-29 13:59:59 +02:00
return m_pAllObjects . count ( Name ) ! = 0 ;
2004-05-29 06:06:50 +02:00
}
2004-07-08 17:23:47 +02:00
IGUIObject * CGUI : : FindObjectByName ( const CStr & Name ) const
{
map_pObjects : : const_iterator it = m_pAllObjects . find ( Name ) ;
if ( it = = m_pAllObjects . end ( ) )
return NULL ;
else
return it - > second ;
}
2010-08-22 01:58:08 +02:00
IGUIObject * CGUI : : FindObjectUnderMouse ( ) const
{
IGUIObject * pNearest = NULL ;
2016-06-14 17:06:39 +02:00
2010-08-22 01:58:08 +02:00
GUI < IGUIObject * > : : RecurseObject ( GUIRR_HIDDEN | GUIRR_GHOST , m_BaseObject ,
2016-06-14 17:06:39 +02:00
& IGUIObject : : ChooseMouseOverAndClosest , pNearest ) ;
2010-08-22 01:58:08 +02:00
return pNearest ;
}
2010-08-13 15:50:03 +02:00
void CGUI : : SetFocusedObject ( IGUIObject * pObject )
{
if ( pObject = = m_FocusedObject )
return ;
if ( m_FocusedObject )
2011-04-28 22:42:11 +02:00
{
SGUIMessage msg ( GUIM_LOST_FOCUS ) ;
m_FocusedObject - > HandleMessage ( msg ) ;
}
2010-08-13 15:50:03 +02:00
m_FocusedObject = pObject ;
if ( m_FocusedObject )
2011-04-28 22:42:11 +02:00
{
SGUIMessage msg ( GUIM_GOT_FOCUS ) ;
m_FocusedObject - > HandleMessage ( msg ) ;
}
2010-08-13 15:50:03 +02:00
}
2004-07-08 17:23:47 +02:00
2004-05-29 06:06:50 +02:00
// private struct used only in GenerateText(...)
2004-05-29 13:59:59 +02:00
struct SGenerateTextImage
2004-05-29 06:06:50 +02:00
{
2004-12-18 14:32:00 +01:00
float m_YFrom , // The image's starting location in Y
m_YTo , // The image's end location in Y
2004-09-03 07:48:47 +02:00
m_Indentation ; // The image width in other words
2004-05-29 06:06:50 +02:00
// Some help functions
// TODO Gee: CRect => CPoint ?
2015-08-21 19:08:41 +02:00
void SetupSpriteCall ( const bool Left , SGUIText : : SSpriteCall & SpriteCall ,
2004-12-18 14:32:00 +01:00
const float width , const float y ,
2015-08-21 19:08:41 +02:00
const CSize & Size , const CStr & TextureName ,
2004-12-18 14:32:00 +01:00
const float BufferZone , const int CellID )
2004-05-29 06:06:50 +02:00
{
// TODO Gee: Temp hardcoded values
SpriteCall . m_Area . top = y + BufferZone ;
SpriteCall . m_Area . bottom = y + BufferZone + Size . cy ;
2015-08-21 19:08:41 +02:00
2004-05-29 06:06:50 +02:00
if ( Left )
{
SpriteCall . m_Area . left = BufferZone ;
SpriteCall . m_Area . right = Size . cx + BufferZone ;
}
else
{
SpriteCall . m_Area . left = width - BufferZone - Size . cx ;
SpriteCall . m_Area . right = width - BufferZone ;
}
2004-12-18 14:32:00 +01:00
SpriteCall . m_CellID = CellID ;
2004-12-15 22:24:46 +01:00
SpriteCall . m_Sprite = TextureName ;
2004-05-29 06:06:50 +02:00
m_YFrom = SpriteCall . m_Area . top - BufferZone ;
m_YTo = SpriteCall . m_Area . bottom + BufferZone ;
m_Indentation = Size . cx + BufferZone * 2 ;
}
} ;
2015-08-21 19:08:41 +02:00
SGUIText CGUI : : GenerateText ( const CGUIString & string , const CStrW & FontW , const float & Width , const float & BufferZone , const IGUIObject * pObject )
2004-05-29 06:06:50 +02:00
{
2016-06-14 17:06:39 +02:00
SGUIText Text ;
2013-10-18 18:15:42 +02:00
CStrIntern Font ( FontW . ToUTF8 ( ) ) ;
2014-06-14 18:12:41 +02:00
2015-08-21 19:08:41 +02:00
if ( string . m_Words . empty ( ) )
2004-05-29 06:06:50 +02:00
return Text ;
2015-08-21 19:08:41 +02:00
float x = BufferZone , y = BufferZone ; // drawing pointer
int from = 0 ;
bool done = false ;
2004-05-29 06:06:50 +02:00
2004-09-04 22:35:12 +02:00
bool FirstLine = true ; // Necessary because text in the first line is shorter
// (it doesn't count the line spacing)
2004-05-29 06:06:50 +02:00
// Images on the left or the right side.
2008-07-13 23:22:03 +02:00
std : : vector < SGenerateTextImage > Images [ 2 ] ;
2015-08-21 19:08:41 +02:00
int pos_last_img = - 1 ; // Position in the string where last img (either left or right) were encountered.
2004-05-29 06:06:50 +02:00
// in order to avoid duplicate processing.
// Easier to read.
bool WordWrapping = ( Width ! = 0 ) ;
2013-01-06 02:46:44 +01:00
// get the alignment type for the control we are computing the text for since
// we are computing the horizontal alignment in this method in order to not have
// to run through the TextCalls a second time in the CalculateTextPosition method again
EAlign align ;
GUI < EAlign > : : GetSetting ( pObject , " text_align " , align ) ;
2004-05-29 06:06:50 +02:00
// Go through string word by word
2015-08-21 19:08:41 +02:00
for ( int i = 0 ; i < ( int ) string . m_Words . size ( ) - 1 & & ! done ; + + i )
2004-05-29 06:06:50 +02:00
{
// Pre-process each line one time, so we know which floating images
// will be added for that line.
// Generated stuff is stored in Feedback.
CGUIString : : SFeedback Feedback ;
// Preliminary line_height, used for word-wrapping with floating images.
2015-08-21 19:08:41 +02:00
float prelim_line_height = 0.f ;
2004-05-29 06:06:50 +02:00
// Width and height of all text calls generated.
2014-01-17 03:54:57 +01:00
string . GenerateTextCall ( this , Feedback , Font ,
2004-09-04 22:35:12 +02:00
string . m_Words [ i ] , string . m_Words [ i + 1 ] ,
FirstLine ) ;
2004-05-29 06:06:50 +02:00
// Loop through our images queues, to see if images has been added.
2015-08-21 19:08:41 +02:00
2004-05-29 06:06:50 +02:00
// Check if this has already been processed.
// Also, floating images are only applicable if Word-Wrapping is on
if ( WordWrapping & & i > pos_last_img )
{
// Loop left/right
2015-08-21 19:08:41 +02:00
for ( int j = 0 ; j < 2 ; + + j )
2004-05-29 06:06:50 +02:00
{
2015-08-21 19:08:41 +02:00
for ( const CStr & imgname : Feedback . m_Images [ j ] )
2004-05-29 06:06:50 +02:00
{
SGUIText : : SSpriteCall SpriteCall ;
SGenerateTextImage Image ;
// Y is if no other floating images is above, y. Else it is placed
// after the last image, like a stack downwards.
2004-09-03 07:48:47 +02:00
float _y ;
2013-05-22 00:11:47 +02:00
if ( ! Images [ j ] . empty ( ) )
2007-05-09 23:01:11 +02:00
_y = std : : max ( y , Images [ j ] . back ( ) . m_YTo ) ;
2004-05-29 06:06:50 +02:00
else
2015-08-21 19:08:41 +02:00
_y = y ;
2004-05-29 06:06:50 +02:00
2004-08-31 04:09:58 +02:00
// Get Size from Icon database
2015-08-21 19:08:41 +02:00
SGUIIcon icon = GetIcon ( imgname ) ;
2004-08-31 04:09:58 +02:00
CSize size = icon . m_Size ;
2015-08-21 19:08:41 +02:00
Image . SetupSpriteCall ( ( j = = CGUIString : : SFeedback : : Left ) , SpriteCall , Width , _y , size , icon . m_SpriteName , BufferZone , icon . m_CellID ) ;
2004-05-29 06:06:50 +02:00
// Check if image is the lowest thing.
2007-05-09 23:01:11 +02:00
Text . m_Size . cy = std : : max ( Text . m_Size . cy , Image . m_YTo ) ;
2004-05-29 06:06:50 +02:00
Images [ j ] . push_back ( Image ) ;
Text . m_SpriteCalls . push_back ( SpriteCall ) ;
}
}
}
2007-05-09 23:01:11 +02:00
pos_last_img = std : : max ( pos_last_img , i ) ;
2004-05-29 06:06:50 +02:00
x + = Feedback . m_Size . cx ;
2007-05-09 23:01:11 +02:00
prelim_line_height = std : : max ( prelim_line_height , Feedback . m_Size . cy ) ;
2004-05-29 06:06:50 +02:00
// If Width is 0, then there's no word-wrapping, disable NewLine.
2004-07-24 16:04:40 +02:00
if ( ( WordWrapping & & ( x > Width - BufferZone | | Feedback . m_NewLine ) ) | | i = = ( int ) string . m_Words . size ( ) - 2 )
2004-05-29 06:06:50 +02:00
{
2004-08-31 04:09:58 +02:00
// Change 'from' to 'i', but first keep a copy of its value.
2004-05-29 06:06:50 +02:00
int temp_from = from ;
from = i ;
2015-08-21 19:08:41 +02:00
static const int From = 0 , To = 1 ;
2004-05-29 06:06:50 +02:00
//int width_from=0, width_to=width;
2004-09-03 07:48:47 +02:00
float width_range [ 2 ] ;
2004-05-29 06:06:50 +02:00
width_range [ From ] = BufferZone ;
width_range [ To ] = Width - BufferZone ;
2004-08-31 04:09:58 +02:00
// Floating images are only applicable if word-wrapping is enabled.
2004-05-29 06:06:50 +02:00
if ( WordWrapping )
{
// Decide width of the line. We need to iterate our floating images.
// this won't be exact because we're assuming the line_height
// will be as our preliminary calculation said. But that may change,
// although we'd have to add a couple of more loops to try straightening
2004-12-21 14:37:24 +01:00
// this problem out, and it is very unlikely to happen noticeably if one
// structures his text in a stylistically pure fashion. Even if not, it
2004-05-29 06:06:50 +02:00
// is still quite unlikely it will happen.
// Loop through left and right side, from and to.
2015-08-21 19:08:41 +02:00
for ( int j = 0 ; j < 2 ; + + j )
2004-05-29 06:06:50 +02:00
{
2015-08-21 19:08:41 +02:00
for ( const SGenerateTextImage & img : Images [ j ] )
2004-05-29 06:06:50 +02:00
{
// We're working with two intervals here, the image's and the line height's.
// let's find the union of these two.
2004-09-03 07:48:47 +02:00
float union_from , union_to ;
2004-05-29 06:06:50 +02:00
2015-08-21 19:08:41 +02:00
union_from = std : : max ( y , img . m_YFrom ) ;
union_to = std : : min ( y + prelim_line_height , img . m_YTo ) ;
2004-07-31 15:37:35 +02:00
// The union is not empty
2004-05-29 06:06:50 +02:00
if ( union_to > union_from )
{
if ( j = = From )
2015-08-21 19:08:41 +02:00
width_range [ From ] = std : : max ( width_range [ From ] , img . m_Indentation ) ;
2004-05-29 06:06:50 +02:00
else
2015-08-21 19:08:41 +02:00
width_range [ To ] = std : : min ( width_range [ To ] , Width - img . m_Indentation ) ;
2004-05-29 06:06:50 +02:00
}
}
}
}
// Reset X for the next loop
x = width_range [ From ] ;
2013-01-06 02:46:44 +01:00
// Now we'll do another loop to figure out the height and width of
// the line (the height of the largest character and the width is
// the sum of all of the individual widths). This
2004-05-29 06:06:50 +02:00
// couldn't be determined in the first loop (main loop)
// because it didn't regard images, so we don't know
// if all characters processed, will actually be involved
// in that line.
2015-08-21 19:08:41 +02:00
float line_height = 0.f ;
float line_width = 0.f ;
for ( int j = temp_from ; j < = i ; + + j )
2004-05-29 06:06:50 +02:00
{
// We don't want to use Feedback now, so we'll have to use
// another.
CGUIString : : SFeedback Feedback2 ;
2004-08-31 04:09:58 +02:00
// Don't attach object, it'll suppress the errors
// we want them to be reported in the final GenerateTextCall()
// so that we don't get duplicates.
2014-01-17 03:54:57 +01:00
string . GenerateTextCall ( this , Feedback2 , Font ,
2004-09-04 22:35:12 +02:00
string . m_Words [ j ] , string . m_Words [ j + 1 ] ,
FirstLine ) ;
2004-05-29 06:06:50 +02:00
// Append X value.
x + = Feedback2 . m_Size . cx ;
if ( WordWrapping & & x > width_range [ To ] & & j ! = temp_from & & ! Feedback2 . m_NewLine )
break ;
// Let line_height be the maximum m_Height we encounter.
2007-05-09 23:01:11 +02:00
line_height = std : : max ( line_height , Feedback2 . m_Size . cy ) ;
2004-05-29 06:06:50 +02:00
2013-01-06 02:46:44 +01:00
line_width + = Feedback2 . m_Size . cx ;
2004-05-29 06:06:50 +02:00
if ( WordWrapping & & Feedback2 . m_NewLine )
break ;
}
2013-01-06 02:46:44 +01:00
float dx = 0.f ;
// compute offset based on what kind of alignment
switch ( align )
{
case EAlign_Left :
// don't add an offset
dx = 0.f ;
break ;
case EAlign_Center :
dx = ( ( width_range [ To ] - width_range [ From ] ) - line_width ) / 2 ;
break ;
case EAlign_Right :
dx = width_range [ To ] - line_width ;
break ;
default :
debug_warn ( L " Broken EAlign in CGUI::GenerateText() " ) ;
break ;
}
2004-05-29 06:06:50 +02:00
// Reset x once more
x = width_range [ From ] ;
2004-07-14 00:48:53 +02:00
// Move down, because font drawing starts from the baseline
y + = line_height ;
2004-05-29 06:06:50 +02:00
// Do the real processing now
2015-08-21 19:08:41 +02:00
for ( int j = temp_from ; j < = i ; + + j )
2004-05-29 06:06:50 +02:00
{
// We don't want to use Feedback now, so we'll have to use
2004-08-31 04:09:58 +02:00
// another one.
2004-05-29 06:06:50 +02:00
CGUIString : : SFeedback Feedback2 ;
// Defaults
2014-01-17 03:54:57 +01:00
string . GenerateTextCall ( this , Feedback2 , Font ,
2015-08-21 19:08:41 +02:00
string . m_Words [ j ] , string . m_Words [ j + 1 ] ,
2004-09-04 22:35:12 +02:00
FirstLine , pObject ) ;
2004-05-29 06:06:50 +02:00
// Iterate all and set X/Y values
// Since X values are not set, we need to make an internal
// iteration with an increment that will append the internal
// x, that is what x_pointer is for.
2015-08-21 19:08:41 +02:00
float x_pointer = 0.f ;
2004-05-29 06:06:50 +02:00
2015-08-21 19:08:41 +02:00
for ( SGUIText : : STextCall & tc : Feedback2 . m_TextCalls )
2004-05-29 06:06:50 +02:00
{
2015-08-21 19:08:41 +02:00
tc . m_Pos = CPos ( dx + x + x_pointer , y ) ;
2004-05-29 06:06:50 +02:00
2015-08-21 19:08:41 +02:00
x_pointer + = tc . m_Size . cx ;
2004-05-29 06:06:50 +02:00
2015-08-21 19:08:41 +02:00
if ( tc . m_pSpriteCall )
tc . m_pSpriteCall - > m_Area + = tc . m_Pos - CSize ( 0 , tc . m_pSpriteCall - > m_Area . GetHeight ( ) ) ;
2004-05-29 06:06:50 +02:00
}
// Append X value.
x + = Feedback2 . m_Size . cx ;
2007-05-09 23:01:11 +02:00
Text . m_Size . cx = std : : max ( Text . m_Size . cx , x + BufferZone ) ;
2004-05-29 06:06:50 +02:00
2004-08-31 04:09:58 +02:00
// The first word overrides the width limit, what we
// do, in those cases, are just drawing that word even
2004-05-29 06:06:50 +02:00
// though it'll extend the object.
if ( WordWrapping ) // only if word-wrapping is applicable
{
if ( Feedback2 . m_NewLine )
{
from = j + 1 ;
2004-08-31 04:09:58 +02:00
// Sprite call can exist within only a newline segment,
// therefore we need this.
Text . m_SpriteCalls . insert ( Text . m_SpriteCalls . end ( ) , Feedback2 . m_SpriteCalls . begin ( ) , Feedback2 . m_SpriteCalls . end ( ) ) ;
2004-05-29 06:06:50 +02:00
break ;
}
2015-08-21 19:08:41 +02:00
else if ( x > width_range [ To ] & & j = = temp_from )
2004-05-29 06:06:50 +02:00
{
from = j + 1 ;
// do not break, since we want it to be added to m_TextCalls
}
2015-08-21 19:08:41 +02:00
else if ( x > width_range [ To ] )
2004-05-29 06:06:50 +02:00
{
from = j ;
break ;
}
}
// Add the whole Feedback2.m_TextCalls to our m_TextCalls.
Text . m_TextCalls . insert ( Text . m_TextCalls . end ( ) , Feedback2 . m_TextCalls . begin ( ) , Feedback2 . m_TextCalls . end ( ) ) ;
Text . m_SpriteCalls . insert ( Text . m_SpriteCalls . end ( ) , Feedback2 . m_SpriteCalls . begin ( ) , Feedback2 . m_SpriteCalls . end ( ) ) ;
2004-07-24 16:04:40 +02:00
if ( j = = ( int ) string . m_Words . size ( ) - 2 )
2004-05-29 06:06:50 +02:00
done = true ;
}
2004-08-31 04:09:58 +02:00
2004-07-14 00:48:53 +02:00
// Reset X
2004-09-03 07:48:47 +02:00
x = 0.f ;
2004-05-29 06:06:50 +02:00
// Update height of all
2007-05-09 23:01:11 +02:00
Text . m_Size . cy = std : : max ( Text . m_Size . cy , y + BufferZone ) ;
2004-05-29 06:06:50 +02:00
2004-09-04 22:35:12 +02:00
FirstLine = false ;
2004-05-29 06:06:50 +02:00
// Now if we entered as from = i, then we want
// i being one minus that, so that it will become
// the same i in the next loop. The difference is that
// we're on a new line now.
i = from - 1 ;
}
}
return Text ;
}
2015-08-21 19:08:41 +02:00
void CGUI : : DrawText ( SGUIText & Text , const CColor & DefaultColor , const CPos & pos , const float & z , const CRect & clipping )
2004-05-29 06:06:50 +02:00
{
2013-09-29 15:19:52 +02:00
CShaderTechniquePtr tech = g_Renderer . GetShaderManager ( ) . LoadEffect ( str_gui_text ) ;
2004-07-14 00:48:53 +02:00
2012-02-12 21:45:31 +01:00
tech - > BeginPass ( ) ;
2004-07-14 00:48:53 +02:00
2013-10-18 18:05:02 +02:00
bool isClipped = ( clipping ! = CRect ( ) ) ;
if ( isClipped )
2005-07-24 02:01:41 +02:00
{
2012-01-29 21:04:21 +01:00
glEnable ( GL_SCISSOR_TEST ) ;
2015-01-24 21:06:37 +01:00
glScissor (
clipping . left / g_GuiScale ,
g_yres - clipping . bottom / g_GuiScale ,
clipping . GetWidth ( ) / g_GuiScale ,
clipping . GetHeight ( ) / g_GuiScale ) ;
2005-07-24 02:01:41 +02:00
}
2012-02-12 21:45:31 +01:00
CTextRenderer textRenderer ( tech - > GetShader ( ) ) ;
2013-10-18 18:05:02 +02:00
textRenderer . SetClippingRect ( clipping ) ;
2012-02-25 18:14:47 +01:00
textRenderer . Translate ( 0.0f , 0.0f , z ) ;
2004-07-14 00:48:53 +02:00
2015-08-21 19:08:41 +02:00
for ( const SGUIText : : STextCall & tc : Text . m_TextCalls )
2004-05-29 06:06:50 +02:00
{
2004-08-31 04:09:58 +02:00
// If this is just a placeholder for a sprite call, continue
2015-08-21 19:08:41 +02:00
if ( tc . m_pSpriteCall )
2004-05-29 06:06:50 +02:00
continue ;
2015-08-21 19:08:41 +02:00
CColor color = tc . m_UseCustomColor ? tc . m_Color : DefaultColor ;
2004-07-14 00:48:53 +02:00
2012-01-29 21:04:21 +01:00
textRenderer . Color ( color ) ;
2015-08-21 19:08:41 +02:00
textRenderer . Font ( tc . m_Font ) ;
textRenderer . Put ( ( float ) ( int ) ( pos . x + tc . m_Pos . x ) , ( float ) ( int ) ( pos . y + tc . m_Pos . y ) , & tc . m_String ) ;
2004-05-29 06:06:50 +02:00
}
2012-01-29 21:04:21 +01:00
textRenderer . Render ( ) ;
2004-07-14 00:48:53 +02:00
2015-08-21 19:08:41 +02:00
for ( const SGUIText : : SSpriteCall & sc : Text . m_SpriteCalls )
DrawSprite ( sc . m_Sprite , sc . m_CellID , z , sc . m_Area + pos ) ;
2004-09-03 07:48:47 +02:00
2013-10-18 18:05:02 +02:00
if ( isClipped )
2012-01-29 21:04:21 +01:00
glDisable ( GL_SCISSOR_TEST ) ;
2012-02-12 21:45:31 +01:00
tech - > EndPass ( ) ;
2003-11-03 17:22:45 +01:00
}
2015-08-21 19:08:41 +02:00
bool CGUI : : GetPreDefinedColor ( const CStr & name , CColor & Output ) const
2005-07-25 21:06:18 +02:00
{
2015-08-21 19:08:41 +02:00
std : : map < CStr , CColor > : : const_iterator cit = m_PreDefinedColors . find ( name ) ;
if ( cit = = m_PreDefinedColors . end ( ) )
2005-07-25 21:06:18 +02:00
return false ;
2015-08-21 19:08:41 +02:00
Output = cit - > second ;
return true ;
2005-07-25 21:06:18 +02:00
}
2003-11-24 03:18:41 +01:00
/**
* @ callgraph
*/
2011-02-19 22:24:39 +01:00
void CGUI : : LoadXmlFile ( const VfsPath & Filename , boost : : unordered_set < VfsPath > & Paths )
2003-11-03 17:22:45 +01:00
{
2009-12-03 21:17:22 +01:00
Paths . insert ( Filename ) ;
2003-11-03 17:22:45 +01:00
2004-07-08 17:23:47 +02:00
CXeromyces XeroFile ;
2015-06-07 23:56:52 +02:00
if ( XeroFile . Load ( g_VFS , Filename , " gui " ) ! = PSRETURN_OK )
2004-07-11 18:22:35 +02:00
return ;
2003-11-03 17:22:45 +01:00
2007-05-02 14:07:08 +02:00
XMBElement node = XeroFile . GetRoot ( ) ;
2003-11-25 03:47:12 +01:00
2014-06-11 19:14:35 +02:00
CStr root_name ( XeroFile . GetElementString ( node . GetNodeName ( ) ) ) ;
2004-07-17 19:09:33 +02:00
try
2004-07-08 17:23:47 +02:00
{
2004-07-17 19:09:33 +02:00
if ( root_name = = " objects " )
{
2009-12-03 21:17:22 +01:00
Xeromyces_ReadRootObjects ( node , & XeroFile , Paths ) ;
2004-07-17 19:09:33 +02:00
// Re-cache all values so these gets cached too.
//UpdateResolution();
}
2015-08-21 19:08:41 +02:00
else if ( root_name = = " sprites " )
2004-07-17 19:09:33 +02:00
Xeromyces_ReadRootSprites ( node , & XeroFile ) ;
2015-08-21 19:08:41 +02:00
else if ( root_name = = " styles " )
2004-07-17 19:09:33 +02:00
Xeromyces_ReadRootStyles ( node , & XeroFile ) ;
2015-08-21 19:08:41 +02:00
else if ( root_name = = " setup " )
2004-07-17 19:09:33 +02:00
Xeromyces_ReadRootSetup ( node , & XeroFile ) ;
else
2009-11-03 22:46:35 +01:00
debug_warn ( L " CGUI::LoadXmlFile error " ) ;
2004-07-08 17:23:47 +02:00
}
2005-05-24 02:00:40 +02:00
catch ( PSERROR_GUI & e )
2004-07-08 17:23:47 +02:00
{
2015-01-22 21:36:24 +01:00
LOGERROR ( " Errors loading GUI file %s (%u) " , Filename . string8 ( ) , e . getCode ( ) ) ;
2004-07-17 19:09:33 +02:00
return ;
2004-07-08 17:23:47 +02:00
}
2003-11-03 17:22:45 +01:00
}
//===================================================================
2004-07-08 17:23:47 +02:00
// XML Reading Xeromyces Specific Sub-Routines
2003-11-03 17:22:45 +01:00
//===================================================================
2011-02-19 22:24:39 +01:00
void CGUI : : Xeromyces_ReadRootObjects ( XMBElement Element , CXeromyces * pFile , boost : : unordered_set < VfsPath > & Paths )
2003-11-03 17:22:45 +01:00
{
2007-05-02 14:07:08 +02:00
int el_script = pFile - > GetElementID ( " script " ) ;
2004-07-11 18:22:35 +02:00
2010-02-28 22:36:25 +01:00
std : : vector < std : : pair < CStr , CStr > > subst ;
2003-11-03 17:22:45 +01:00
// Iterate main children
2004-07-11 18:22:35 +02:00
// they should all be <object> or <script> elements
2015-06-01 02:29:35 +02:00
for ( XMBElement child : Element . GetChildNodes ( ) )
2003-11-03 17:22:45 +01:00
{
2007-05-02 14:07:08 +02:00
if ( child . GetNodeName ( ) = = el_script )
2004-07-11 18:22:35 +02:00
// Execute the inline script
2009-12-03 21:17:22 +01:00
Xeromyces_ReadScript ( child , pFile , Paths ) ;
2004-07-11 18:22:35 +02:00
else
// Read in this whole object into the GUI
2014-06-11 19:14:35 +02:00
Xeromyces_ReadObject ( child , pFile , m_BaseObject , subst , Paths , 0 ) ;
2003-11-03 17:22:45 +01:00
}
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadRootSprites ( XMBElement Element , CXeromyces * pFile )
2003-11-03 17:22:45 +01:00
{
2015-06-01 02:29:35 +02:00
for ( XMBElement child : Element . GetChildNodes ( ) )
2004-07-08 17:23:47 +02:00
Xeromyces_ReadSprite ( child , pFile ) ;
2003-11-03 17:22:45 +01:00
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadRootStyles ( XMBElement Element , CXeromyces * pFile )
2003-12-01 08:06:55 +01:00
{
2015-06-01 02:29:35 +02:00
for ( XMBElement child : Element . GetChildNodes ( ) )
2004-07-08 17:23:47 +02:00
Xeromyces_ReadStyle ( child , pFile ) ;
2003-12-01 08:06:55 +01:00
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadRootSetup ( XMBElement Element , CXeromyces * pFile )
2003-12-27 07:26:03 +01:00
{
2015-06-01 02:29:35 +02:00
for ( XMBElement child : Element . GetChildNodes ( ) )
2003-12-27 07:26:03 +01:00
{
2014-06-11 19:14:35 +02:00
CStr name ( pFile - > GetElementString ( child . GetNodeName ( ) ) ) ;
2003-12-27 07:26:03 +01:00
2004-07-10 22:33:42 +02:00
if ( name = = " scrollbar " )
2004-07-08 17:23:47 +02:00
Xeromyces_ReadScrollBarStyle ( child , pFile ) ;
2015-08-21 19:08:41 +02:00
else if ( name = = " icon " )
2004-08-31 04:09:58 +02:00
Xeromyces_ReadIcon ( child , pFile ) ;
2015-08-21 19:08:41 +02:00
else if ( name = = " tooltip " )
2004-12-21 14:37:24 +01:00
Xeromyces_ReadTooltip ( child , pFile ) ;
2015-08-21 19:08:41 +02:00
else if ( name = = " color " )
2005-07-25 21:06:18 +02:00
Xeromyces_ReadColor ( child , pFile ) ;
else
2009-11-03 22:46:35 +01:00
debug_warn ( L " Invalid data - DTD shouldn't allow this " ) ;
2003-12-27 07:26:03 +01:00
}
}
2015-08-21 19:08:41 +02:00
void CGUI : : Xeromyces_ReadObject ( XMBElement Element , CXeromyces * pFile , IGUIObject * pParent , std : : vector < std : : pair < CStr , CStr > > & NameSubst , boost : : unordered_set < VfsPath > & Paths , u32 nesting_depth )
2003-11-03 17:22:45 +01:00
{
2011-04-30 15:01:45 +02:00
ENSURE ( pParent ) ;
2003-11-03 17:22:45 +01:00
2007-05-02 14:07:08 +02:00
XMBAttributeList attributes = Element . GetAttributes ( ) ;
2004-07-08 17:23:47 +02:00
2015-08-21 19:08:41 +02:00
CStr type ( attributes . GetNamedItem ( pFile - > GetAttributeID ( " type " ) ) ) ;
2009-03-23 22:35:26 +01:00
if ( type . empty ( ) )
type = " empty " ;
2003-11-03 17:22:45 +01:00
// Construct object from specified type
// henceforth, we need to do a rollback before aborting.
// i.e. releasing this object
2016-06-14 17:06:39 +02:00
IGUIObject * object = ConstructObject ( type ) ;
2003-11-03 17:22:45 +01:00
if ( ! object )
{
2015-01-22 21:36:24 +01:00
LOGERROR ( " GUI: Unrecognized object type \" %s \" " , type . c_str ( ) ) ;
2003-11-03 17:22:45 +01:00
return ;
}
2004-07-08 17:23:47 +02:00
// Cache some IDs for element attribute names, to avoid string comparisons
2007-05-02 14:07:08 +02:00
# define ELMT(x) int elmt_##x = pFile->GetElementID(#x)
# define ATTR(x) int attr_##x = pFile->GetAttributeID(#x)
2004-07-08 17:23:47 +02:00
ELMT ( object ) ;
ELMT ( action ) ;
2010-02-28 22:36:25 +01:00
ELMT ( repeat ) ;
2014-04-20 22:03:57 +02:00
ELMT ( translatableAttribute ) ;
ELMT ( translate ) ;
ELMT ( attribute ) ;
ELMT ( keep ) ;
2014-06-14 18:12:41 +02:00
ELMT ( include ) ;
2004-07-08 17:23:47 +02:00
ATTR ( style ) ;
ATTR ( type ) ;
ATTR ( name ) ;
2004-07-22 18:18:12 +02:00
ATTR ( hotkey ) ;
2004-07-08 17:23:47 +02:00
ATTR ( z ) ;
ATTR ( on ) ;
2004-07-11 18:22:35 +02:00
ATTR ( file ) ;
2014-06-17 15:03:55 +02:00
ATTR ( directory ) ;
2014-04-20 22:03:57 +02:00
ATTR ( id ) ;
2014-05-01 00:33:08 +02:00
ATTR ( context ) ;
2004-07-08 17:23:47 +02:00
2003-12-01 08:06:55 +01:00
//
// Read Style and set defaults
//
2003-12-27 07:26:03 +01:00
// If the setting "style" is set, try loading that setting.
//
// Always load default (if it's available) first!
//
2014-06-11 19:14:35 +02:00
CStr argStyle ( attributes . GetNamedItem ( attr_style ) ) ;
2003-12-01 08:06:55 +01:00
2004-12-21 14:37:24 +01:00
if ( m_Styles . count ( " default " ) = = 1 )
object - > LoadStyle ( * this , " default " ) ;
2003-12-27 07:26:03 +01:00
2014-06-14 18:12:41 +02:00
if ( ! argStyle . empty ( ) )
2003-12-01 08:06:55 +01:00
{
if ( m_Styles . count ( argStyle ) = = 0 )
2015-01-22 21:36:24 +01:00
LOGERROR ( " GUI: Trying to use style '%s' that doesn't exist. " , argStyle . c_str ( ) ) ;
2014-06-14 18:12:41 +02:00
else
object - > LoadStyle ( * this , argStyle ) ;
2003-12-01 08:06:55 +01:00
}
2003-12-27 07:26:03 +01:00
2003-11-03 17:22:45 +01:00
bool NameSet = false ;
2016-06-14 17:06:39 +02:00
bool ManuallySetZ = false ;
2003-11-03 17:22:45 +01:00
2014-06-11 19:14:35 +02:00
CStrW inclusionPath ;
2004-10-31 23:00:01 +01:00
CStr hotkeyTag ;
2004-07-22 18:18:12 +02:00
2015-06-01 02:29:35 +02:00
for ( XMBAttribute attr : attributes )
2003-11-03 17:22:45 +01:00
{
2004-05-29 06:06:50 +02:00
// If value is "null", then it is equivalent as never being entered
2009-11-03 22:46:35 +01:00
if ( CStr ( attr . Value ) = = " null " )
2004-05-29 06:06:50 +02:00
continue ;
2003-12-01 08:06:55 +01:00
// Ignore "type" and "style", we've already checked it
2004-07-17 19:09:33 +02:00
if ( attr . Name = = attr_type | | attr . Name = = attr_style )
2003-11-03 17:22:45 +01:00
continue ;
2004-07-08 17:23:47 +02:00
if ( attr . Name = = attr_name )
2003-11-03 17:22:45 +01:00
{
2014-06-11 19:14:35 +02:00
CStr name ( attr . Value ) ;
2010-02-28 22:36:25 +01:00
2015-08-21 19:08:41 +02:00
for ( const std : : pair < CStr , CStr > & sub : NameSubst )
name . Replace ( sub . first , sub . second ) ;
2010-02-28 22:36:25 +01:00
object - > SetName ( name ) ;
2003-11-03 17:22:45 +01:00
NameSet = true ;
continue ;
}
2004-10-31 23:00:01 +01:00
if ( attr . Name = = attr_hotkey )
2004-07-22 18:18:12 +02:00
hotkeyTag = attr . Value ;
2004-07-08 17:23:47 +02:00
if ( attr . Name = = attr_z )
2003-12-27 07:26:03 +01:00
ManuallySetZ = true ;
2011-02-17 21:08:20 +01:00
if ( object - > SetSetting ( pFile - > GetAttributeString ( attr . Name ) , attr . Value . FromUTF8 ( ) , true ) ! = PSRETURN_OK )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: (object: %s) Can't set \" %s \" to \" %s \" " , object - > GetPresentableName ( ) , pFile - > GetAttributeString ( attr . Name ) , attr . Value ) ;
2003-11-03 17:22:45 +01:00
}
2004-05-29 06:06:50 +02:00
// Check if name isn't set, generate an internal name in that case.
2003-11-03 17:22:45 +01:00
if ( ! NameSet )
{
2011-02-17 21:08:20 +01:00
object - > SetName ( " __internal( " + CStr : : FromInt ( m_InternalNameNumber ) + " ) " ) ;
2004-05-29 06:06:50 +02:00
+ + m_InternalNameNumber ;
2003-11-03 17:22:45 +01:00
}
2014-06-14 18:12:41 +02:00
if ( ! hotkeyTag . empty ( ) )
2010-10-23 04:37:00 +02:00
m_HotkeyObjects [ hotkeyTag ] . push_back ( object ) ;
2004-07-08 17:23:47 +02:00
2014-06-11 19:14:35 +02:00
CStrW caption ( Element . GetText ( ) . FromUTF8 ( ) ) ;
if ( ! caption . empty ( ) )
2005-02-05 08:25:16 +01:00
object - > SetSetting ( " caption " , caption , true ) ;
2004-12-13 13:07:12 +01:00
2015-06-01 02:29:35 +02:00
for ( XMBElement child : Element . GetChildNodes ( ) )
2003-11-03 17:22:45 +01:00
{
2004-07-08 17:23:47 +02:00
// Check what name the elements got
2007-05-02 14:07:08 +02:00
int element_name = child . GetNodeName ( ) ;
2003-11-03 17:22:45 +01:00
2004-07-08 17:23:47 +02:00
if ( element_name = = elmt_object )
{
// Call this function on the child
2014-06-11 19:14:35 +02:00
Xeromyces_ReadObject ( child , pFile , object , NameSubst , Paths , nesting_depth ) ;
2003-11-03 17:22:45 +01:00
}
2004-07-08 17:23:47 +02:00
else if ( element_name = = elmt_action )
2003-11-03 17:22:45 +01:00
{
2004-07-11 18:22:35 +02:00
// Scripted <action> element
// Check for a 'file' parameter
2014-06-11 19:14:35 +02:00
CStrW filename ( child . GetAttributes ( ) . GetNamedItem ( attr_file ) . FromUTF8 ( ) ) ;
2004-07-11 18:22:35 +02:00
CStr code ;
// If there is a file, open it and use it as the code
2014-06-11 19:14:35 +02:00
if ( ! filename . empty ( ) )
2004-07-11 18:22:35 +02:00
{
2009-12-03 21:17:22 +01:00
Paths . insert ( filename ) ;
2004-07-29 18:17:21 +02:00
CVFSFile scriptfile ;
2010-07-04 12:15:53 +02:00
if ( scriptfile . Load ( g_VFS , filename ) ! = PSRETURN_OK )
2004-07-11 18:22:35 +02:00
{
2015-01-22 21:37:38 +01:00
LOGERROR ( " Error opening GUI script action file '%s' " , utf8_from_wstring ( filename ) ) ;
2004-07-17 19:09:33 +02:00
throw PSERROR_GUI_JSOpenFailed ( ) ;
}
2004-07-11 18:22:35 +02:00
2012-05-04 23:48:46 +02:00
code = scriptfile . DecodeUTF8 ( ) ; // assume it's UTF-8
2004-07-11 18:22:35 +02:00
}
2014-04-20 22:03:57 +02:00
XMBElementList grandchildren = child . GetChildNodes ( ) ;
2015-06-01 02:29:35 +02:00
if ( ! grandchildren . empty ( ) ) // The <action> element contains <keep> and <translate> tags.
for ( XMBElement grandchild : grandchildren )
2014-04-20 22:03:57 +02:00
{
if ( grandchild . GetNodeName ( ) = = elmt_translate )
2014-10-15 18:04:37 +02:00
code + = g_L10n . Translate ( grandchild . GetText ( ) ) ;
2014-04-20 22:03:57 +02:00
else if ( grandchild . GetNodeName ( ) = = elmt_keep )
code + = grandchild . GetText ( ) ;
}
else // It’s pure JavaScript code.
// Read the inline code (concatenating to the file code, if both are specified)
code + = CStr ( child . GetText ( ) ) ;
2004-07-11 18:22:35 +02:00
2009-11-03 22:46:35 +01:00
CStr action = CStr ( child . GetAttributes ( ) . GetNamedItem ( attr_on ) ) ;
2014-06-14 18:12:41 +02:00
2014-01-04 11:14:53 +01:00
// We need to set the GUI this object belongs to because RegisterScriptHandler requires an associated GUI.
object - > SetGUI ( this ) ;
2004-07-11 18:22:35 +02:00
object - > RegisterScriptHandler ( action . LowerCase ( ) , code , this ) ;
2003-11-03 17:22:45 +01:00
}
2010-02-28 22:36:25 +01:00
else if ( element_name = = elmt_repeat )
{
2014-12-10 21:10:02 +01:00
Xeromyces_ReadRepeat ( child , pFile , object , NameSubst , Paths , nesting_depth ) ;
2010-02-28 22:36:25 +01:00
}
2014-04-20 22:03:57 +02:00
else if ( element_name = = elmt_translatableAttribute )
{
// This is an element in the form “<translatableAttribute id="attributeName">attributeValue</translatableAttribute>”.
CStr attributeName ( child . GetAttributes ( ) . GetNamedItem ( attr_id ) ) ; // Read the attribute name.
2014-06-14 18:12:41 +02:00
if ( attributeName . empty ( ) )
2014-04-20 22:03:57 +02:00
{
2015-01-22 21:36:24 +01:00
LOGERROR ( " GUI: ‘translatableAttribute’ XML element with empty ‘id’ XML attribute found. (object: %s) " , object - > GetPresentableName ( ) . c_str ( ) ) ;
2014-06-14 18:12:41 +02:00
continue ;
2014-04-20 22:03:57 +02:00
}
2014-06-14 18:12:41 +02:00
CStr value ( child . GetText ( ) ) ;
if ( value . empty ( ) )
continue ;
CStr context ( child . GetAttributes ( ) . GetNamedItem ( attr_context ) ) ; // Read the context if any.
if ( ! context . empty ( ) )
2014-04-20 22:03:57 +02:00
{
2014-10-15 18:04:37 +02:00
CStr translatedValue ( g_L10n . TranslateWithContext ( context , value ) ) ;
2014-12-13 02:08:29 +01:00
object - > SetSetting ( attributeName , translatedValue . FromUTF8 ( ) , true ) ;
2014-06-14 18:12:41 +02:00
}
else
{
2014-10-15 18:04:37 +02:00
CStr translatedValue ( g_L10n . Translate ( value ) ) ;
2014-12-13 02:08:29 +01:00
object - > SetSetting ( attributeName , translatedValue . FromUTF8 ( ) , true ) ;
2014-04-20 22:03:57 +02:00
}
}
else if ( element_name = = elmt_attribute )
{
// This is an element in the form “<attribute id="attributeName"><keep>Don’t translate this part
// </keep><translate>but translate this one.</translate></attribute>”.
CStr attributeName ( child . GetAttributes ( ) . GetNamedItem ( attr_id ) ) ; // Read the attribute name.
2014-06-14 18:12:41 +02:00
if ( attributeName . empty ( ) )
2014-04-20 22:03:57 +02:00
{
2015-01-22 21:36:24 +01:00
LOGERROR ( " GUI: ‘attribute’ XML element with empty ‘id’ XML attribute found. (object: %s) " , object - > GetPresentableName ( ) . c_str ( ) ) ;
2014-06-14 18:12:41 +02:00
continue ;
}
2014-04-20 22:03:57 +02:00
2014-06-14 18:12:41 +02:00
CStr translatedValue ;
2015-06-01 02:29:35 +02:00
for ( XMBElement grandchild : child . GetChildNodes ( ) )
2014-06-14 18:12:41 +02:00
{
if ( grandchild . GetNodeName ( ) = = elmt_translate )
2014-10-15 18:04:37 +02:00
translatedValue + = g_L10n . Translate ( grandchild . GetText ( ) ) ;
2014-06-14 18:12:41 +02:00
else if ( grandchild . GetNodeName ( ) = = elmt_keep )
translatedValue + = grandchild . GetText ( ) ;
2014-04-20 22:03:57 +02:00
}
2014-12-13 02:08:29 +01:00
object - > SetSetting ( attributeName , translatedValue . FromUTF8 ( ) , true ) ;
2014-06-14 18:12:41 +02:00
}
else if ( element_name = = elmt_include )
{
CStrW filename ( child . GetAttributes ( ) . GetNamedItem ( attr_file ) . FromUTF8 ( ) ) ;
2014-06-17 15:03:55 +02:00
CStrW directory ( child . GetAttributes ( ) . GetNamedItem ( attr_directory ) . FromUTF8 ( ) ) ;
if ( ! filename . empty ( ) )
2014-04-20 22:03:57 +02:00
{
2014-06-17 15:03:55 +02:00
if ( ! directory . empty ( ) )
2015-01-22 21:37:38 +01:00
LOGWARNING ( " GUI: Include element found with file name (%s) and directory name (%s). Only the file will be processed. " , utf8_from_wstring ( filename ) , utf8_from_wstring ( directory ) ) ;
2014-06-14 18:12:41 +02:00
2014-06-17 15:03:55 +02:00
Paths . insert ( filename ) ;
2014-06-14 18:12:41 +02:00
2014-06-17 15:03:55 +02:00
CXeromyces XeroIncluded ;
2015-06-07 23:56:52 +02:00
if ( XeroIncluded . Load ( g_VFS , filename , " gui " ) ! = PSRETURN_OK )
2014-06-17 15:03:55 +02:00
{
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error reading included XML: '%s' " , utf8_from_wstring ( filename ) ) ;
2014-06-17 15:03:55 +02:00
continue ;
}
2014-06-14 18:12:41 +02:00
2014-06-17 15:03:55 +02:00
XMBElement node = XeroIncluded . GetRoot ( ) ;
if ( node . GetNodeName ( ) ! = XeroIncluded . GetElementID ( " object " ) )
2014-06-14 18:12:41 +02:00
{
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error reading included XML: '%s', root element must have be of type 'object'. " , utf8_from_wstring ( filename ) ) ;
2014-06-14 18:12:41 +02:00
continue ;
}
2015-06-01 02:29:23 +02:00
if ( nesting_depth + 1 > = MAX_OBJECT_DEPTH )
{
LOGERROR ( " GUI: Too many nested GUI includes. Probably caused by a recursive include attribute. Abort rendering '%s'. " , utf8_from_wstring ( filename ) ) ;
continue ;
}
2014-06-17 15:03:55 +02:00
Xeromyces_ReadObject ( node , & XeroIncluded , object , NameSubst , Paths , nesting_depth + 1 ) ;
2014-04-20 22:03:57 +02:00
}
2014-06-17 15:03:55 +02:00
else if ( ! directory . empty ( ) )
{
2015-06-01 02:29:23 +02:00
if ( nesting_depth + 1 > = MAX_OBJECT_DEPTH )
{
LOGERROR ( " GUI: Too many nested GUI includes. Probably caused by a recursive include attribute. Abort rendering '%s'. " , utf8_from_wstring ( directory ) ) ;
continue ;
}
2014-06-17 15:03:55 +02:00
VfsPaths pathnames ;
vfs : : GetPathnames ( g_VFS , directory , L " *.xml " , pathnames ) ;
2015-06-01 02:29:23 +02:00
for ( const VfsPath & path : pathnames )
2014-06-17 15:03:55 +02:00
{
// as opposed to loading scripts, don't care if it's loaded before
// one might use the same parts of the GUI in different situations
2015-06-01 02:29:23 +02:00
Paths . insert ( path ) ;
2014-06-17 15:03:55 +02:00
CXeromyces XeroIncluded ;
2015-06-07 23:56:52 +02:00
if ( XeroIncluded . Load ( g_VFS , path , " gui " ) ! = PSRETURN_OK )
2014-06-17 15:03:55 +02:00
{
2015-06-01 02:29:23 +02:00
LOGERROR ( " GUI: Error reading included XML: '%s' " , path . string8 ( ) ) ;
2014-06-17 15:03:55 +02:00
continue ;
}
XMBElement node = XeroIncluded . GetRoot ( ) ;
if ( node . GetNodeName ( ) ! = XeroIncluded . GetElementID ( " object " ) )
{
2015-06-01 02:29:23 +02:00
LOGERROR ( " GUI: Error reading included XML: '%s', root element must have be of type 'object'. " , path . string8 ( ) ) ;
2014-06-17 15:03:55 +02:00
continue ;
}
Xeromyces_ReadObject ( node , & XeroIncluded , object , NameSubst , Paths , nesting_depth + 1 ) ;
}
}
else
2015-01-22 21:36:24 +01:00
LOGERROR ( " GUI: 'include' XML element must have valid 'file' or 'directory' attribute found. (object %s) " , object - > GetPresentableName ( ) . c_str ( ) ) ;
2014-04-20 22:03:57 +02:00
}
2005-04-07 11:13:10 +02:00
else
{
// Try making the object read the tag.
if ( ! object - > HandleAdditionalChildren ( child , pFile ) )
2015-01-22 21:36:24 +01:00
LOGERROR ( " GUI: (object: %s) Reading unknown children for its type " , object - > GetPresentableName ( ) . c_str ( ) ) ;
2005-04-07 11:13:10 +02:00
}
2015-08-21 19:08:41 +02:00
}
2003-11-03 17:22:45 +01:00
2003-12-27 07:26:03 +01:00
if ( ! ManuallySetZ )
{
// Set it automatically to 10 plus its parents
2009-12-03 21:17:22 +01:00
bool absolute ;
GUI < bool > : : GetSetting ( object , " absolute " , absolute ) ;
if ( absolute )
2015-06-01 02:29:23 +02:00
// If the object is absolute, we'll have to get the parent's Z buffered,
// and add to that!
2009-12-03 21:17:22 +01:00
GUI < float > : : SetSetting ( object , " z " , pParent - > GetBufferedZ ( ) + 10.f , true ) ;
2003-12-27 07:26:03 +01:00
else
2015-06-01 02:29:23 +02:00
// If the object is relative, then we'll just store Z as "10"
2009-12-03 21:17:22 +01:00
GUI < float > : : SetSetting ( object , " z " , 10.f , true ) ;
2003-12-27 07:26:03 +01:00
}
2003-11-03 17:22:45 +01:00
try
{
if ( pParent = = m_BaseObject )
AddObject ( object ) ;
else
pParent - > AddChild ( object ) ;
}
2009-09-27 17:04:46 +02:00
catch ( PSERROR_GUI & e )
2009-11-03 22:46:35 +01:00
{
2015-01-22 21:36:24 +01:00
LOGERROR ( " GUI error: %s " , e . what ( ) ) ;
2003-11-03 17:22:45 +01:00
}
}
2015-08-21 19:08:41 +02:00
void CGUI : : Xeromyces_ReadRepeat ( XMBElement Element , CXeromyces * pFile , IGUIObject * pParent , std : : vector < std : : pair < CStr , CStr > > & NameSubst , boost : : unordered_set < VfsPath > & Paths , u32 nesting_depth )
2010-02-28 22:36:25 +01:00
{
# define ELMT(x) int elmt_##x = pFile->GetElementID(#x)
# define ATTR(x) int attr_##x = pFile->GetAttributeID(#x)
ELMT ( object ) ;
ATTR ( count ) ;
2014-12-10 21:10:02 +01:00
ATTR ( var ) ;
2010-02-28 22:36:25 +01:00
XMBAttributeList attributes = Element . GetAttributes ( ) ;
int count = CStr ( attributes . GetNamedItem ( attr_count ) ) . ToInt ( ) ;
2014-12-10 21:10:02 +01:00
CStr var ( " [ " + attributes . GetNamedItem ( attr_var ) + " ] " ) ;
if ( var . size ( ) < 3 )
var = " [n] " ;
2010-02-28 22:36:25 +01:00
for ( int n = 0 ; n < count ; + + n )
{
2015-08-21 19:08:41 +02:00
NameSubst . emplace_back ( var , " [ " + CStr : : FromInt ( n ) + " ] " ) ;
2010-02-28 22:36:25 +01:00
XERO_ITER_EL ( Element , child )
{
if ( child . GetNodeName ( ) = = elmt_object )
2014-12-10 21:10:02 +01:00
Xeromyces_ReadObject ( child , pFile , pParent , NameSubst , Paths , nesting_depth ) ;
2010-02-28 22:36:25 +01:00
}
2014-12-10 21:10:02 +01:00
NameSubst . pop_back ( ) ;
2010-02-28 22:36:25 +01:00
}
}
2011-02-19 22:24:39 +01:00
void CGUI : : Xeromyces_ReadScript ( XMBElement Element , CXeromyces * pFile , boost : : unordered_set < VfsPath > & Paths )
2004-07-11 18:22:35 +02:00
{
// Check for a 'file' parameter
2015-08-21 19:08:41 +02:00
CStrW file ( Element . GetAttributes ( ) . GetNamedItem ( pFile - > GetAttributeID ( " file " ) ) . FromUTF8 ( ) ) ;
2004-07-11 18:22:35 +02:00
2004-07-11 20:18:54 +02:00
// If there is a file specified, open and execute it
2014-06-11 19:14:35 +02:00
if ( ! file . empty ( ) )
2009-12-03 21:17:22 +01:00
{
Paths . insert ( file ) ;
2010-01-24 18:24:35 +01:00
try
{
2014-01-04 11:14:53 +01:00
m_ScriptInterface - > LoadGlobalScriptFile ( file ) ;
2010-01-24 18:24:35 +01:00
}
catch ( PSERROR_Scripting & e )
{
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error executing script %s: %s " , utf8_from_wstring ( file ) , e . what ( ) ) ;
2010-01-24 18:24:35 +01:00
}
2009-12-03 21:17:22 +01:00
}
2004-07-11 18:22:35 +02:00
2014-06-11 19:14:35 +02:00
// If it has a directory attribute, read all JS files in that directory
2015-08-21 19:08:41 +02:00
CStrW directory ( Element . GetAttributes ( ) . GetNamedItem ( pFile - > GetAttributeID ( " directory " ) ) . FromUTF8 ( ) ) ;
2014-06-11 19:14:35 +02:00
if ( ! directory . empty ( ) )
{
VfsPaths pathnames ;
vfs : : GetPathnames ( g_VFS , directory , L " *.js " , pathnames ) ;
2015-07-30 01:44:12 +02:00
for ( const VfsPath & path : pathnames )
2014-06-11 19:14:35 +02:00
{
// Only load new files (so when the insert succeeds)
2015-07-30 01:44:12 +02:00
if ( Paths . insert ( path ) . second )
2014-06-11 19:14:35 +02:00
try
{
2015-07-30 01:44:12 +02:00
m_ScriptInterface - > LoadGlobalScriptFile ( path ) ;
2014-06-11 19:14:35 +02:00
}
catch ( PSERROR_Scripting & e )
{
2015-07-30 01:44:12 +02:00
LOGERROR ( " GUI: Error executing script %s: %s " , path . string8 ( ) , e . what ( ) ) ;
2014-06-11 19:14:35 +02:00
}
}
}
2004-07-11 18:22:35 +02:00
// Execute inline scripts
2010-01-24 18:24:35 +01:00
try
{
2014-06-11 19:14:35 +02:00
CStr code ( Element . GetText ( ) ) ;
if ( ! code . empty ( ) )
2014-01-04 11:14:53 +01:00
m_ScriptInterface - > LoadGlobalScript ( L " Some XML file " , code . FromUTF8 ( ) ) ;
2010-01-24 18:24:35 +01:00
}
catch ( PSERROR_Scripting & e )
{
2015-01-22 21:36:24 +01:00
LOGERROR ( " GUI: Error executing inline script: %s " , e . what ( ) ) ;
2010-01-24 18:24:35 +01:00
}
2004-07-11 18:22:35 +02:00
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadSprite ( XMBElement Element , CXeromyces * pFile )
2003-11-03 17:22:45 +01:00
{
2014-01-03 21:19:43 +01:00
CGUISprite * Sprite = new CGUISprite ;
2015-08-21 19:08:41 +02:00
2003-11-03 17:22:45 +01:00
// Get name, we know it exists because of DTD requirements
2016-06-14 17:06:39 +02:00
CStr name = Element . GetAttributes ( ) . GetNamedItem ( pFile - > GetAttributeID ( " name " ) ) ;
2003-11-03 17:22:45 +01:00
2004-12-21 14:37:24 +01:00
if ( m_Sprites . find ( name ) ! = m_Sprites . end ( ) )
2015-01-22 21:36:24 +01:00
LOGWARNING ( " GUI sprite name '%s' used more than once; first definition will be discarded " , name . c_str ( ) ) ;
2004-12-21 14:37:24 +01:00
2004-12-18 14:32:00 +01:00
SGUIImageEffects * effects = NULL ;
2015-06-01 02:29:35 +02:00
for ( XMBElement child : Element . GetChildNodes ( ) )
2003-11-03 17:22:45 +01:00
{
2014-06-11 19:14:35 +02:00
CStr ElementName ( pFile - > GetElementString ( child . GetNodeName ( ) ) ) ;
2003-11-03 17:22:45 +01:00
2004-12-18 14:32:00 +01:00
if ( ElementName = = " image " )
2014-01-03 21:19:43 +01:00
Xeromyces_ReadImage ( child , pFile , * Sprite ) ;
2004-12-18 14:32:00 +01:00
else if ( ElementName = = " effect " )
{
2009-12-03 21:17:22 +01:00
if ( effects )
2015-01-22 21:31:30 +01:00
LOGERROR ( " GUI <sprite> must not have more than one <effect> " ) ;
2009-12-03 21:17:22 +01:00
else
{
effects = new SGUIImageEffects ;
Xeromyces_ReadEffects ( child , pFile , * effects ) ;
}
2004-12-18 14:32:00 +01:00
}
else
2009-11-03 22:46:35 +01:00
debug_warn ( L " Invalid data - DTD shouldn't allow this " ) ;
2003-11-03 17:22:45 +01:00
}
2004-12-18 14:32:00 +01:00
// Apply the effects to every image (unless the image overrides it with
// different effects)
if ( effects )
2015-08-21 19:08:41 +02:00
for ( SGUIImage * const & img : Sprite - > m_Images )
if ( ! img - > m_Effects )
img - > m_Effects = new SGUIImageEffects ( * effects ) ; // do a copy just so it can be deleted correctly later
2004-12-18 14:32:00 +01:00
delete effects ;
2014-01-03 21:19:43 +01:00
m_Sprites [ name ] = Sprite ;
2003-11-03 17:22:45 +01:00
}
2015-08-21 19:08:41 +02:00
void CGUI : : Xeromyces_ReadImage ( XMBElement Element , CXeromyces * pFile , CGUISprite & parent )
2003-11-03 17:22:45 +01:00
{
2014-01-03 21:19:43 +01:00
SGUIImage * Image = new SGUIImage ;
2015-08-21 19:08:41 +02:00
2014-01-03 21:19:43 +01:00
Image - > m_TextureSize = CClientArea ( CRect ( 0 , 0 , 0 , 0 ) , CRect ( 0 , 0 , 100 , 100 ) ) ;
Image - > m_Size = CClientArea ( CRect ( 0 , 0 , 0 , 0 ) , CRect ( 0 , 0 , 100 , 100 ) ) ;
2015-08-21 19:08:41 +02:00
2003-12-27 07:26:03 +01:00
// TODO Gee: Setup defaults here (or maybe they are in the SGUIImage ctor)
2003-11-03 17:22:45 +01:00
2015-06-01 02:29:35 +02:00
for ( XMBAttribute attr : Element . GetAttributes ( ) )
2003-11-03 17:22:45 +01:00
{
2014-06-11 19:14:35 +02:00
CStr attr_name ( pFile - > GetAttributeString ( attr . Name ) ) ;
CStrW attr_value ( attr . Value . FromUTF8 ( ) ) ;
2003-11-03 17:22:45 +01:00
2004-07-10 22:33:42 +02:00
if ( attr_name = = " texture " )
2003-11-03 17:22:45 +01:00
{
2014-01-03 21:19:43 +01:00
Image - > m_TextureName = VfsPath ( " art/textures/ui " ) / attr_value ;
2003-11-03 17:22:45 +01:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " size " )
2003-11-03 17:22:45 +01:00
{
2003-12-01 08:06:55 +01:00
CClientArea ca ;
if ( ! GUI < CClientArea > : : ParseString ( attr_value , ca ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2015-08-21 19:08:41 +02:00
else
Image - > m_Size = ca ;
2003-12-01 08:06:55 +01:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " texture_size " )
2004-07-14 00:48:53 +02:00
{
CClientArea ca ;
if ( ! GUI < CClientArea > : : ParseString ( attr_value , ca ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2015-08-21 19:08:41 +02:00
else
Image - > m_TextureSize = ca ;
2004-07-14 00:48:53 +02:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " real_texture_placement " )
2004-09-02 05:02:32 +02:00
{
CRect rect ;
if ( ! GUI < CRect > : : ParseString ( attr_value , rect ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2015-08-21 19:08:41 +02:00
else
Image - > m_TexturePlacementInFile = rect ;
2004-09-02 05:02:32 +02:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " cell_size " )
2004-12-17 17:20:08 +01:00
{
CSize size ;
if ( ! GUI < CSize > : : ParseString ( attr_value , size ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2015-08-21 19:08:41 +02:00
else
Image - > m_CellSize = size ;
2004-12-17 17:20:08 +01:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " fixed_h_aspect_ratio " )
2011-08-20 19:17:53 +02:00
{
float val ;
if ( ! GUI < float > : : ParseString ( attr_value , val ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2015-08-21 19:08:41 +02:00
else
Image - > m_FixedHAspectRatio = val ;
2011-08-20 19:17:53 +02:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " round_coordinates " )
2011-08-20 19:17:53 +02:00
{
bool b ;
if ( ! GUI < bool > : : ParseString ( attr_value , b ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2015-08-21 19:08:41 +02:00
else
Image - > m_RoundCoordinates = b ;
2011-08-20 19:17:53 +02:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " wrap_mode " )
2011-08-20 19:17:53 +02:00
{
if ( attr_value = = L " repeat " )
2014-01-03 21:19:43 +01:00
Image - > m_WrapMode = GL_REPEAT ;
2011-08-20 19:17:53 +02:00
else if ( attr_value = = L " mirrored_repeat " )
2014-01-03 21:19:43 +01:00
Image - > m_WrapMode = GL_MIRRORED_REPEAT ;
2011-08-20 19:17:53 +02:00
else if ( attr_value = = L " clamp_to_edge " )
2014-01-03 21:19:43 +01:00
Image - > m_WrapMode = GL_CLAMP_TO_EDGE ;
2011-08-20 19:17:53 +02:00
else
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2011-08-20 19:17:53 +02:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " z_level " )
2004-05-29 06:06:50 +02:00
{
2004-09-03 07:48:47 +02:00
float z_level ;
if ( ! GUI < float > : : ParseString ( attr_value , z_level ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2015-08-21 19:08:41 +02:00
else
Image - > m_DeltaZ = z_level / 100.f ;
2004-05-29 06:06:50 +02:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " backcolor " )
2003-12-01 08:06:55 +01:00
{
CColor color ;
if ( ! GUI < CColor > : : ParseString ( attr_value , color ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2015-08-21 19:08:41 +02:00
else
Image - > m_BackColor = color ;
2003-12-01 08:06:55 +01:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " bordercolor " )
2004-09-06 04:21:21 +02:00
{
CColor color ;
if ( ! GUI < CColor > : : ParseString ( attr_value , color ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2015-08-21 19:08:41 +02:00
else
Image - > m_BorderColor = color ;
2004-09-06 04:21:21 +02:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " border " )
2004-09-06 04:21:21 +02:00
{
bool b ;
if ( ! GUI < bool > : : ParseString ( attr_value , b ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2015-08-21 19:08:41 +02:00
else
Image - > m_Border = b ;
2004-09-06 04:21:21 +02:00
}
2004-12-18 14:32:00 +01:00
else
2009-11-03 22:46:35 +01:00
debug_warn ( L " Invalid data - DTD shouldn't allow this " ) ;
2004-12-18 14:32:00 +01:00
}
// Look for effects
2015-06-01 02:29:35 +02:00
for ( XMBElement child : Element . GetChildNodes ( ) )
2004-12-18 14:32:00 +01:00
{
2014-06-11 19:14:35 +02:00
CStr ElementName ( pFile - > GetElementString ( child . GetNodeName ( ) ) ) ;
2004-12-18 14:32:00 +01:00
if ( ElementName = = " effect " )
{
2014-01-03 21:19:43 +01:00
if ( Image - > m_Effects )
2015-01-22 21:31:30 +01:00
LOGERROR ( " GUI <image> must not have more than one <effect> " ) ;
2009-12-03 21:17:22 +01:00
else
{
2014-01-03 21:19:43 +01:00
Image - > m_Effects = new SGUIImageEffects ;
Xeromyces_ReadEffects ( child , pFile , * Image - > m_Effects ) ;
2009-12-03 21:17:22 +01:00
}
2004-12-18 14:32:00 +01:00
}
else
2009-11-03 22:46:35 +01:00
debug_warn ( L " Invalid data - DTD shouldn't allow this " ) ;
2003-11-03 17:22:45 +01:00
}
2003-12-01 08:06:55 +01:00
2014-06-14 18:12:41 +02:00
parent . AddImage ( Image ) ;
2003-11-03 17:22:45 +01:00
}
2003-12-01 08:06:55 +01:00
2015-08-21 19:08:41 +02:00
void CGUI : : Xeromyces_ReadEffects ( XMBElement Element , CXeromyces * pFile , SGUIImageEffects & effects )
2004-12-18 14:32:00 +01:00
{
2015-06-01 02:29:35 +02:00
for ( XMBAttribute attr : Element . GetAttributes ( ) )
2004-12-18 14:32:00 +01:00
{
2014-06-11 19:14:35 +02:00
CStr attr_name ( pFile - > GetAttributeString ( attr . Name ) ) ;
CStrW attr_value ( attr . Value . FromUTF8 ( ) ) ;
2004-12-18 14:32:00 +01:00
2012-02-08 21:43:38 +01:00
if ( attr_name = = " add_color " )
{
CColor color ;
2014-06-04 02:58:05 +02:00
if ( ! GUI < int > : : ParseColor ( attr_value , color , 0 ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
2012-02-08 21:43:38 +01:00
else effects . m_AddColor = color ;
}
else if ( attr_name = = " grayscale " )
effects . m_Greyscale = true ;
2004-12-19 13:20:04 +01:00
else
2009-11-03 22:46:35 +01:00
debug_warn ( L " Invalid data - DTD shouldn't allow this " ) ;
2004-12-18 14:32:00 +01:00
}
}
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadStyle ( XMBElement Element , CXeromyces * pFile )
2003-12-01 08:06:55 +01:00
{
SGUIStyle style ;
CStr name ;
2014-06-14 18:12:41 +02:00
2015-06-01 02:29:35 +02:00
for ( XMBAttribute attr : Element . GetAttributes ( ) )
2003-12-01 08:06:55 +01:00
{
2014-06-11 19:14:35 +02:00
CStr attr_name ( pFile - > GetAttributeString ( attr . Name ) ) ;
2003-12-01 08:06:55 +01:00
// The "name" setting is actually the name of the style
// and not a new default
2004-07-10 22:33:42 +02:00
if ( attr_name = = " name " )
2011-02-17 21:08:20 +01:00
name = attr . Value ;
2003-12-01 08:06:55 +01:00
else
2011-02-17 21:08:20 +01:00
style . m_SettingsDefaults [ attr_name ] = attr . Value . FromUTF8 ( ) ;
2003-12-01 08:06:55 +01:00
}
m_Styles [ name ] = style ;
}
2003-12-27 07:26:03 +01:00
2004-07-08 17:23:47 +02:00
void CGUI : : Xeromyces_ReadScrollBarStyle ( XMBElement Element , CXeromyces * pFile )
2003-12-27 07:26:03 +01:00
{
SGUIScrollBarStyle scrollbar ;
CStr name ;
2014-02-19 22:59:07 +01:00
// Setup some defaults.
scrollbar . m_MinimumBarSize = 0.f ;
2014-03-05 02:06:13 +01:00
// Using 1.0e10 as a substitute for infinity
scrollbar . m_MaximumBarSize = 1.0e10 ;
2014-02-19 22:59:07 +01:00
scrollbar . m_UseEdgeButtons = false ;
2015-06-01 02:29:35 +02:00
for ( XMBAttribute attr : Element . GetAttributes ( ) )
2003-12-27 07:26:03 +01:00
{
2007-05-02 14:07:08 +02:00
CStr attr_name = pFile - > GetAttributeString ( attr . Name ) ;
2015-08-21 19:08:41 +02:00
CStr attr_value ( attr . Value ) ;
2003-12-27 07:26:03 +01:00
2004-10-31 23:00:01 +01:00
if ( attr_value = = " null " )
2004-05-29 06:06:50 +02:00
continue ;
2004-07-10 22:33:42 +02:00
if ( attr_name = = " name " )
2003-12-27 07:26:03 +01:00
name = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " show_edge_buttons " )
2013-11-07 21:07:24 +01:00
{
bool b ;
if ( ! GUI < bool > : : ParseString ( attr_value . FromUTF8 ( ) , b ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , attr_value ) ;
2013-11-07 21:07:24 +01:00
else
scrollbar . m_UseEdgeButtons = b ;
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " width " )
2003-12-27 07:26:03 +01:00
{
2004-09-03 07:48:47 +02:00
float f ;
2011-02-17 21:08:20 +01:00
if ( ! GUI < float > : : ParseString ( attr_value . FromUTF8 ( ) , f ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , attr_value ) ;
2009-12-03 21:17:22 +01:00
else
scrollbar . m_Width = f ;
2003-12-27 07:26:03 +01:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " minimum_bar_size " )
2004-05-29 06:06:50 +02:00
{
2004-09-03 07:48:47 +02:00
float f ;
2011-02-17 21:08:20 +01:00
if ( ! GUI < float > : : ParseString ( attr_value . FromUTF8 ( ) , f ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , attr_value ) ;
2009-12-03 21:17:22 +01:00
else
scrollbar . m_MinimumBarSize = f ;
2004-05-29 06:06:50 +02:00
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " maximum_bar_size " )
2013-08-26 06:17:26 +02:00
{
float f ;
if ( ! GUI < float > : : ParseString ( attr_value . FromUTF8 ( ) , f ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , attr_value ) ;
2013-08-26 06:17:26 +02:00
else
scrollbar . m_MaximumBarSize = f ;
}
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_button_top " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonTop = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_button_top_pressed " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonTopPressed = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_button_top_disabled " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonTopDisabled = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_button_top_over " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonTopOver = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_button_bottom " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonBottom = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_button_bottom_pressed " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonBottomPressed = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_button_bottom_disabled " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonBottomDisabled = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_button_bottom_over " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteButtonBottomOver = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_back_vertical " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteBackVertical = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_bar_vertical " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteBarVertical = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_bar_vertical_over " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteBarVerticalOver = attr_value ;
2015-08-21 19:08:41 +02:00
else if ( attr_name = = " sprite_bar_vertical_pressed " )
2004-05-29 06:06:50 +02:00
scrollbar . m_SpriteBarVerticalPressed = attr_value ;
2004-08-31 04:09:58 +02:00
}
2004-05-29 06:06:50 +02:00
2004-08-31 04:09:58 +02:00
m_ScrollBarStyles [ name ] = scrollbar ;
}
2004-05-29 06:06:50 +02:00
2004-08-31 04:09:58 +02:00
void CGUI : : Xeromyces_ReadIcon ( XMBElement Element , CXeromyces * pFile )
{
SGUIIcon icon ;
CStr name ;
2004-05-29 06:06:50 +02:00
2015-06-01 02:29:35 +02:00
for ( XMBAttribute attr : Element . GetAttributes ( ) )
2004-08-31 04:09:58 +02:00
{
2014-06-11 19:14:35 +02:00
CStr attr_name ( pFile - > GetAttributeString ( attr . Name ) ) ;
CStr attr_value ( attr . Value ) ;
2004-05-29 06:06:50 +02:00
2004-10-31 23:00:01 +01:00
if ( attr_value = = " null " )
2004-08-31 04:09:58 +02:00
continue ;
2004-05-29 06:06:50 +02:00
2004-08-31 04:09:58 +02:00
if ( attr_name = = " name " )
name = attr_value ;
2014-06-14 18:12:41 +02:00
else if ( attr_name = = " sprite " )
2005-07-25 02:52:03 +02:00
icon . m_SpriteName = attr_value ;
2014-06-14 18:12:41 +02:00
else if ( attr_name = = " size " )
2004-08-31 04:09:58 +02:00
{
CSize size ;
2011-02-17 21:08:20 +01:00
if ( ! GUI < CSize > : : ParseString ( attr_value . FromUTF8 ( ) , size ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " Error parsing '%s' ( \" %s \" ) inside <icon>. " , attr_name , attr_value ) ;
2009-12-03 21:17:22 +01:00
else
icon . m_Size = size ;
2004-08-31 04:09:58 +02:00
}
2014-06-14 18:12:41 +02:00
else if ( attr_name = = " cell_id " )
2004-12-18 14:32:00 +01:00
{
int cell_id ;
2011-02-17 21:08:20 +01:00
if ( ! GUI < int > : : ParseString ( attr_value . FromUTF8 ( ) , cell_id ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) inside <icon>. " , attr_name , attr_value ) ;
2009-12-03 21:17:22 +01:00
else
icon . m_CellID = cell_id ;
2004-12-18 14:32:00 +01:00
}
else
2009-11-03 22:46:35 +01:00
debug_warn ( L " Invalid data - DTD shouldn't allow this " ) ;
2003-12-27 07:26:03 +01:00
}
2004-08-31 04:09:58 +02:00
m_Icons [ name ] = icon ;
2003-12-27 07:26:03 +01:00
}
2004-12-21 14:37:24 +01:00
void CGUI : : Xeromyces_ReadTooltip ( XMBElement Element , CXeromyces * pFile )
{
2004-12-23 14:56:34 +01:00
IGUIObject * object = new CTooltip ;
2004-12-21 14:37:24 +01:00
2015-06-01 02:29:35 +02:00
for ( XMBAttribute attr : Element . GetAttributes ( ) )
2004-12-21 14:37:24 +01:00
{
2014-06-11 19:14:35 +02:00
CStr attr_name ( pFile - > GetAttributeString ( attr . Name ) ) ;
CStr attr_value ( attr . Value ) ;
2004-12-21 14:37:24 +01:00
if ( attr_name = = " name " )
2004-12-23 14:56:34 +01:00
object - > SetName ( " __tooltip_ " + attr_value ) ;
2004-12-21 14:37:24 +01:00
else
2011-02-17 21:08:20 +01:00
object - > SetSetting ( attr_name , attr_value . FromUTF8 ( ) ) ;
2004-12-21 14:37:24 +01:00
}
AddObject ( object ) ;
}
2005-07-25 21:06:18 +02:00
void CGUI : : Xeromyces_ReadColor ( XMBElement Element , CXeromyces * pFile )
{
2007-05-02 14:07:08 +02:00
XMBAttributeList attributes = Element . GetAttributes ( ) ;
2005-07-25 21:06:18 +02:00
CColor color ;
2007-05-02 14:07:08 +02:00
CStr name = attributes . GetNamedItem ( pFile - > GetAttributeID ( " name " ) ) ;
2005-07-25 21:06:18 +02:00
2015-08-21 19:08:41 +02:00
// Try parsing value
2014-06-11 19:14:35 +02:00
CStr value ( Element . GetText ( ) ) ;
2015-08-21 19:08:41 +02:00
if ( value . empty ( ) )
return ;
// Try setting color to value
if ( ! color . ParseString ( value ) )
2005-07-25 21:06:18 +02:00
{
2015-08-21 19:08:41 +02:00
LOGERROR ( " GUI: Unable to create custom color '%s'. Invalid color syntax. " , name . c_str ( ) ) ;
return ;
2005-07-25 21:06:18 +02:00
}
2015-08-21 19:08:41 +02:00
m_PreDefinedColors [ name ] = color ;
2005-07-25 21:06:18 +02:00
}