2019-03-18 23:15:40 +01:00
/* Copyright (C) 2019 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"
2016-12-07 20:03:54 +01:00
# include "CChart.h"
2004-05-29 06:06:50 +02:00
# 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"
2017-04-30 18:51:18 +02:00
# include "CSlider.h"
2015-08-21 19:08:41 +02:00
# 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"
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
2016-12-07 20:18:57 +01:00
if ( ev - > ev . type = = SDL_HOTKEYDOWN | | ev - > ev . type = = SDL_HOTKEYUP )
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 ) ;
2016-12-07 20:18:57 +01:00
2010-10-23 04:37:00 +02:00
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 )
2016-12-07 20:18:57 +01:00
{
// Update hotkey status before sending the event,
// else the status will be outdated when processing the GUI event.
HotkeyInputHandler ( ev ) ;
ret = IN_HANDLED ;
if ( ev - > ev . type = = SDL_HOTKEYDOWN )
obj - > SendEvent ( GUIM_PRESSED , " press " ) ;
else
obj - > SendEvent ( GUIM_RELEASED , " release " ) ;
}
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.
2017-06-14 19:13:44 +02: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 ) ;
2019-08-21 15:22:25 +02:00
m_BaseObject - > RecurseObject ( & IGUIObject : : IsHiddenOrGhost , & IGUIObject : : HandleMessage , 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 )
{
2017-06-14 19:13:44 +02: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
2019-08-21 15:22:25 +02:00
m_BaseObject - > RecurseObject ( & IGUIObject : : IsHiddenOrGhost , & IGUIObject : : UpdateMouseOver , static_cast < IGUIObject * const & > ( 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
2019-08-21 15:22:25 +02:00
m_BaseObject - > RecurseObject ( & IGUIObject : : IsHidden , & IGUIObject : : ResetStates ) ;
2004-05-29 06:06:50 +02:00
2014-03-07 23:43:57 +01:00
// Since the hover state will have been reset, we reload it.
2019-08-21 15:22:25 +02:00
m_BaseObject - > RecurseObject ( & IGUIObject : : IsHiddenOrGhost , & IGUIObject : : UpdateMouseOver , static_cast < IGUIObject * const & > ( 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 ( )
{
2019-08-21 15:22:25 +02:00
const CStr action = " tick " ;
m_BaseObject - > RecurseObject ( nullptr , & IGUIObject : : ScriptEvent , action ) ;
2004-12-21 14:37:24 +01:00
2019-08-21 12:12:33 +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.
2019-08-21 15:22:25 +02:00
const CStr EventNameLower = EventName . LowerCase ( ) ;
m_BaseObject - > RecurseObject ( nullptr , & IGUIObject : : ScriptEvent , EventNameLower ) ;
2019-07-19 23:15:04 +02:00
}
2019-08-21 15:22:25 +02:00
void CGUI : : SendEventToAll ( const CStr & EventName , const JS : : HandleValueArray & paramData )
2019-07-19 23:15:04 +02:00
{
2019-08-21 15:22:25 +02:00
const CStr EventNameLower = EventName . LowerCase ( ) ;
m_BaseObject - > RecurseObject ( nullptr , & IGUIObject : : ScriptEvent , EventNameLower , paramData ) ;
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 ) ) ;
2019-04-20 17:49:42 +02:00
m_ScriptInterface - > SetCallbackData ( this ) ;
2014-01-04 11:14:53 +01:00
GuiScriptingInit ( * m_ScriptInterface ) ;
2014-01-17 19:21:27 +01:00
m_ScriptInterface - > LoadGlobalScripts ( ) ;
2019-08-01 22:20:24 +02:00
2019-08-21 12:12:33 +02:00
m_BaseObject = new CGUIDummyObject ( * 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 )
2019-08-21 12:12:33 +02:00
return ( * m_ObjectTypes [ str ] ) ( * this ) ;
2019-08-01 22:20:24 +02:00
// Error reporting will be handled with the nullptr return.
return nullptr ;
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 ) ;
2016-12-07 20:03:54 +01:00
AddObjectType ( " chart " , & CChart : : ConstructObject ) ;
2017-04-30 18:51:18 +02:00
AddObjectType ( " slider " , & CSlider : : 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
{
2019-08-21 15:22:25 +02:00
m_BaseObject - > RecurseObject ( & IGUIObject : : IsHidden , & 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
2019-08-18 17:17:49 +02:00
if ( ! Sprite )
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
2019-08-21 12:12:33 +02:00
Sprite . Draw ( * this , 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
MOVABLE idiom, const CGUI struct maps, in place move construction instead of copying temporaries during CGUI XML loading and GenerateText.
Introduce MOVABLE idiom indicating that a class can use move semantics.
Make values of CGUI struct maps holding XML data const to ensure at the
root that the data is not modified.
Use NONCOPYABLE and MOVABLE for SGUIIcon and SGUIStyle to enforce the
non-copy policy on the compiler level (until someone changes the GUI
design to make modifications needed).
As indicated by that:
Replace copy operations by in place move operations for these CGUI
struct maps in the CGUI Xeromyces XML loading functions.
Replace copy operations by const references for CSize and SGUIIcon in
CGUIString::GenerateTextCall and CGUI::GenerateText.
This avoids copying of non primitive members, such as the strings and
containers of strings.
Further related cleanup to be kept separated for auditability.
Differential Revision: https://code.wildfiregames.com/D2163
Few comments on IRC by: wraitii, Itms
Tested on: gcc 9, Jenkins, partially VS2015
Refs #1984,
NONCOPYABLE CGUISpriteInstances: 0a7d0ecdde, 8f4f8e240f, c19f3608a5
NONCOPYABLE Image, Sprite: fb8032043b
NONCOPYABLE GUI page: 94c57085e9
NONCOPYABLE GUIManager: 7c2e9027c2
NONCOPYABLE macro: 16ccae10cd
This was SVN commit r22637.
2019-08-09 19:25:55 +02:00
for ( const std : : pair < CStr , const CGUISprite * > & p : m_Sprites )
2015-08-21 19:08:41 +02:00
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
2019-08-21 15:22:25 +02:00
m_BaseObject - > RecurseObject ( nullptr , & 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
{
2016-06-14 17:06:39 +02:00
m_BaseObject - > AddChild ( pObject ) ;
2003-11-25 03:47:12 +01:00
// Cache tree
2019-08-21 15:22:25 +02:00
pObject - > RecurseObject ( nullptr , & IGUIObject : : UpdateCachedSize ) ;
2003-11-25 03:47:12 +01:00
2011-04-28 22:42:11 +02:00
SGUIMessage msg ( GUIM_LOAD ) ;
2019-08-21 15:22:25 +02:00
pObject - > RecurseObject ( nullptr , & 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
2019-08-21 15:22:25 +02:00
m_BaseObject - > RecurseObject ( nullptr , & 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 ;
2019-08-21 15:22:25 +02:00
m_BaseObject - > RecurseObject ( & IGUIObject : : IsHiddenOrGhost , & 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
2019-03-18 23:15:40 +01:00
const SGUIScrollBarStyle * CGUI : : GetScrollBarStyle ( const CStr & style ) const
{
MOVABLE idiom, const CGUI struct maps, in place move construction instead of copying temporaries during CGUI XML loading and GenerateText.
Introduce MOVABLE idiom indicating that a class can use move semantics.
Make values of CGUI struct maps holding XML data const to ensure at the
root that the data is not modified.
Use NONCOPYABLE and MOVABLE for SGUIIcon and SGUIStyle to enforce the
non-copy policy on the compiler level (until someone changes the GUI
design to make modifications needed).
As indicated by that:
Replace copy operations by in place move operations for these CGUI
struct maps in the CGUI Xeromyces XML loading functions.
Replace copy operations by const references for CSize and SGUIIcon in
CGUIString::GenerateTextCall and CGUI::GenerateText.
This avoids copying of non primitive members, such as the strings and
containers of strings.
Further related cleanup to be kept separated for auditability.
Differential Revision: https://code.wildfiregames.com/D2163
Few comments on IRC by: wraitii, Itms
Tested on: gcc 9, Jenkins, partially VS2015
Refs #1984,
NONCOPYABLE CGUISpriteInstances: 0a7d0ecdde, 8f4f8e240f, c19f3608a5
NONCOPYABLE Image, Sprite: fb8032043b
NONCOPYABLE GUI page: 94c57085e9
NONCOPYABLE GUIManager: 7c2e9027c2
NONCOPYABLE macro: 16ccae10cd
This was SVN commit r22637.
2019-08-09 19:25:55 +02:00
std : : map < CStr , const SGUIScrollBarStyle > : : const_iterator it = m_ScrollBarStyles . find ( style ) ;
2019-03-18 23:15:40 +01:00
if ( it = = m_ScrollBarStyles . end ( ) )
return nullptr ;
return & it - > second ;
}
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 )
2019-08-27 18:03:24 +02:00
object - > LoadStyle ( " 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
2019-08-27 18:03:24 +02:00
object - > LoadStyle ( 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
2019-08-21 12:12:33 +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
2019-08-26 14:25:07 +02:00
if ( object - > GetSetting < bool > ( " 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
2019-08-20 12:51:29 +02:00
// shared_ptr to link the effect to every image, faster than copy.
2019-08-17 13:52:57 +02:00
std : : shared_ptr < SGUIImageEffects > effects ;
2004-12-18 14:32:00 +01:00
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
{
2019-08-17 13:52:57 +02:00
effects = std : : make_shared < SGUIImageEffects > ( ) ;
2009-12-03 21:17:22 +01:00
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 )
2019-08-17 13:52:57 +02:00
img - > m_Effects = effects ;
2004-12-18 14:32:00 +01:00
MOVABLE idiom, const CGUI struct maps, in place move construction instead of copying temporaries during CGUI XML loading and GenerateText.
Introduce MOVABLE idiom indicating that a class can use move semantics.
Make values of CGUI struct maps holding XML data const to ensure at the
root that the data is not modified.
Use NONCOPYABLE and MOVABLE for SGUIIcon and SGUIStyle to enforce the
non-copy policy on the compiler level (until someone changes the GUI
design to make modifications needed).
As indicated by that:
Replace copy operations by in place move operations for these CGUI
struct maps in the CGUI Xeromyces XML loading functions.
Replace copy operations by const references for CSize and SGUIIcon in
CGUIString::GenerateTextCall and CGUI::GenerateText.
This avoids copying of non primitive members, such as the strings and
containers of strings.
Further related cleanup to be kept separated for auditability.
Differential Revision: https://code.wildfiregames.com/D2163
Few comments on IRC by: wraitii, Itms
Tested on: gcc 9, Jenkins, partially VS2015
Refs #1984,
NONCOPYABLE CGUISpriteInstances: 0a7d0ecdde, 8f4f8e240f, c19f3608a5
NONCOPYABLE Image, Sprite: fb8032043b
NONCOPYABLE GUI page: 94c57085e9
NONCOPYABLE GUIManager: 7c2e9027c2
NONCOPYABLE macro: 16ccae10cd
This was SVN commit r22637.
2019-08-09 19:25:55 +02:00
m_Sprites . erase ( name ) ;
m_Sprites . emplace ( 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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < CClientArea > : : ParseString ( this , 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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < CClientArea > : : ParseString ( this , 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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < CRect > : : ParseString ( this , 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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < CSize > : : ParseString ( this , 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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < float > : : ParseString ( this , 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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < bool > : : ParseString ( this , 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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < float > : : ParseString ( this , 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
{
Stop copying color every draw call for every GUI object using colors.
Avoid color copies for rendering Draw calls in
GUIRenderer::UpdateDrawCallCache, CButton::Draw, CChart::DrawAxes,
CDropDown::Draw, CList::DrawList, COList::DrawList, refs #1984,
8f4f8e240f, 3028551b91, a905fbbc98.
Avoid color copies during XML loading in CGUI::Xeromyces_ReadImage,
CGUI::Xeromyces_ReadEffects, COList::HandleAdditionalChildren.
Add CGUI::HasPreDefinedColor and mark m_PreDefinedColors,
CGUI::GetPreDefinedColor, IGUIButtonBehavior::ChooseColor() as const for
consistency with the other "databases", refs 3028551b91.
Mark CGUIColor as NONCOPYABLE to add compiler errors if there is an
unexplicit copy, refs 3028551b91.
Explicit ugly copy in CGUI::Xeromyces_ReadColor and
CGUIColor::ParseString.
Deregister copying <CGUIColor>GetSetting functions, refs 8f4f8e240f.
Uses the const ref GetSetting from 3dfa23cd25.
This was SVN commit r22694.
2019-08-19 14:53:58 +02:00
if ( ! GUI < CGUIColor > : : ParseString ( this , attr_value , Image - > m_BackColor ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
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
{
Stop copying color every draw call for every GUI object using colors.
Avoid color copies for rendering Draw calls in
GUIRenderer::UpdateDrawCallCache, CButton::Draw, CChart::DrawAxes,
CDropDown::Draw, CList::DrawList, COList::DrawList, refs #1984,
8f4f8e240f, 3028551b91, a905fbbc98.
Avoid color copies during XML loading in CGUI::Xeromyces_ReadImage,
CGUI::Xeromyces_ReadEffects, COList::HandleAdditionalChildren.
Add CGUI::HasPreDefinedColor and mark m_PreDefinedColors,
CGUI::GetPreDefinedColor, IGUIButtonBehavior::ChooseColor() as const for
consistency with the other "databases", refs 3028551b91.
Mark CGUIColor as NONCOPYABLE to add compiler errors if there is an
unexplicit copy, refs 3028551b91.
Explicit ugly copy in CGUI::Xeromyces_ReadColor and
CGUIColor::ParseString.
Deregister copying <CGUIColor>GetSetting functions, refs 8f4f8e240f.
Uses the const ref GetSetting from 3dfa23cd25.
This was SVN commit r22694.
2019-08-19 14:53:58 +02:00
if ( ! GUI < CGUIColor > : : ParseString ( this , attr_value , Image - > m_BorderColor ) )
2015-01-22 21:37:38 +01:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , utf8_from_wstring ( attr_value ) ) ;
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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < bool > : : ParseString ( this , 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
{
2019-08-17 13:52:57 +02:00
Image - > m_Effects = std : : make_shared < SGUIImageEffects > ( ) ;
2014-01-03 21:19:43 +01:00
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 ) ) ;
2004-12-18 14:32:00 +01:00
2012-02-08 21:43:38 +01:00
if ( attr_name = = " add_color " )
{
2019-08-21 12:12:33 +02:00
if ( ! effects . m_AddColor . ParseString ( * this , attr . Value , 0 ) )
2019-08-13 17:42:14 +02:00
LOGERROR ( " GUI: Error parsing '%s' ( \" %s \" ) " , attr_name , attr . Value ) ;
2012-02-08 21:43:38 +01:00
}
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
MOVABLE idiom, const CGUI struct maps, in place move construction instead of copying temporaries during CGUI XML loading and GenerateText.
Introduce MOVABLE idiom indicating that a class can use move semantics.
Make values of CGUI struct maps holding XML data const to ensure at the
root that the data is not modified.
Use NONCOPYABLE and MOVABLE for SGUIIcon and SGUIStyle to enforce the
non-copy policy on the compiler level (until someone changes the GUI
design to make modifications needed).
As indicated by that:
Replace copy operations by in place move operations for these CGUI
struct maps in the CGUI Xeromyces XML loading functions.
Replace copy operations by const references for CSize and SGUIIcon in
CGUIString::GenerateTextCall and CGUI::GenerateText.
This avoids copying of non primitive members, such as the strings and
containers of strings.
Further related cleanup to be kept separated for auditability.
Differential Revision: https://code.wildfiregames.com/D2163
Few comments on IRC by: wraitii, Itms
Tested on: gcc 9, Jenkins, partially VS2015
Refs #1984,
NONCOPYABLE CGUISpriteInstances: 0a7d0ecdde, 8f4f8e240f, c19f3608a5
NONCOPYABLE Image, Sprite: fb8032043b
NONCOPYABLE GUI page: 94c57085e9
NONCOPYABLE GUIManager: 7c2e9027c2
NONCOPYABLE macro: 16ccae10cd
This was SVN commit r22637.
2019-08-09 19:25:55 +02:00
style . m_SettingsDefaults . emplace ( attr_name , attr . Value . FromUTF8 ( ) ) ;
2003-12-01 08:06:55 +01:00
}
MOVABLE idiom, const CGUI struct maps, in place move construction instead of copying temporaries during CGUI XML loading and GenerateText.
Introduce MOVABLE idiom indicating that a class can use move semantics.
Make values of CGUI struct maps holding XML data const to ensure at the
root that the data is not modified.
Use NONCOPYABLE and MOVABLE for SGUIIcon and SGUIStyle to enforce the
non-copy policy on the compiler level (until someone changes the GUI
design to make modifications needed).
As indicated by that:
Replace copy operations by in place move operations for these CGUI
struct maps in the CGUI Xeromyces XML loading functions.
Replace copy operations by const references for CSize and SGUIIcon in
CGUIString::GenerateTextCall and CGUI::GenerateText.
This avoids copying of non primitive members, such as the strings and
containers of strings.
Further related cleanup to be kept separated for auditability.
Differential Revision: https://code.wildfiregames.com/D2163
Few comments on IRC by: wraitii, Itms
Tested on: gcc 9, Jenkins, partially VS2015
Refs #1984,
NONCOPYABLE CGUISpriteInstances: 0a7d0ecdde, 8f4f8e240f, c19f3608a5
NONCOPYABLE Image, Sprite: fb8032043b
NONCOPYABLE GUI page: 94c57085e9
NONCOPYABLE GUIManager: 7c2e9027c2
NONCOPYABLE macro: 16ccae10cd
This was SVN commit r22637.
2019-08-09 19:25:55 +02:00
m_Styles . erase ( name ) ;
m_Styles . emplace ( name , std : : move ( style ) ) ;
2003-12-01 08:06:55 +01:00
}
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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < bool > : : ParseString ( this , 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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < float > : : ParseString ( this , 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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < float > : : ParseString ( this , 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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < float > : : ParseString ( this , 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
MOVABLE idiom, const CGUI struct maps, in place move construction instead of copying temporaries during CGUI XML loading and GenerateText.
Introduce MOVABLE idiom indicating that a class can use move semantics.
Make values of CGUI struct maps holding XML data const to ensure at the
root that the data is not modified.
Use NONCOPYABLE and MOVABLE for SGUIIcon and SGUIStyle to enforce the
non-copy policy on the compiler level (until someone changes the GUI
design to make modifications needed).
As indicated by that:
Replace copy operations by in place move operations for these CGUI
struct maps in the CGUI Xeromyces XML loading functions.
Replace copy operations by const references for CSize and SGUIIcon in
CGUIString::GenerateTextCall and CGUI::GenerateText.
This avoids copying of non primitive members, such as the strings and
containers of strings.
Further related cleanup to be kept separated for auditability.
Differential Revision: https://code.wildfiregames.com/D2163
Few comments on IRC by: wraitii, Itms
Tested on: gcc 9, Jenkins, partially VS2015
Refs #1984,
NONCOPYABLE CGUISpriteInstances: 0a7d0ecdde, 8f4f8e240f, c19f3608a5
NONCOPYABLE Image, Sprite: fb8032043b
NONCOPYABLE GUI page: 94c57085e9
NONCOPYABLE GUIManager: 7c2e9027c2
NONCOPYABLE macro: 16ccae10cd
This was SVN commit r22637.
2019-08-09 19:25:55 +02:00
m_ScrollBarStyles . erase ( name ) ;
m_ScrollBarStyles . emplace ( name , std : : move ( scrollbar ) ) ;
2004-08-31 04:09:58 +02:00
}
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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < CSize > : : ParseString ( this , 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 ;
Delete wrongful proxy CGUIManager::GetPreDefinedColor from f0d9806b3f.
It is wrong because the predefined colors should be loaded from the GUI
page that requests to have the color parsed, which may be different from
the topmost page.
Similar to FindObjectByName removed in f9b529f2fb.
Achieve this by implementing the CGUISetting<CGUIColor>::FromJSVal
specialization, moved from ScriptInterface::FromJSVal<CGUIColor>,
instead of adding a CGUI pointer to CGUIColor.
Mark ScriptInterface::FromJSVal<GUIColor> and inherited
CColor::ParseString explicitly as deleted, so that people get a compile
error if they forget to check for predefined colors when parsing a
color.
Refs #5387, D1746 > D1684 > this > f9b529f2fb, 9be8a560a9, 415939b59b,
2c47fbd66a, 85a622b13a.
Differential Revision: https://code.wildfiregames.com/D2108
Tested on: clang 8, VS2015
This was SVN commit r22663.
2019-08-13 20:00:41 +02:00
if ( ! GUI < int > : : ParseString ( this , 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
}
MOVABLE idiom, const CGUI struct maps, in place move construction instead of copying temporaries during CGUI XML loading and GenerateText.
Introduce MOVABLE idiom indicating that a class can use move semantics.
Make values of CGUI struct maps holding XML data const to ensure at the
root that the data is not modified.
Use NONCOPYABLE and MOVABLE for SGUIIcon and SGUIStyle to enforce the
non-copy policy on the compiler level (until someone changes the GUI
design to make modifications needed).
As indicated by that:
Replace copy operations by in place move operations for these CGUI
struct maps in the CGUI Xeromyces XML loading functions.
Replace copy operations by const references for CSize and SGUIIcon in
CGUIString::GenerateTextCall and CGUI::GenerateText.
This avoids copying of non primitive members, such as the strings and
containers of strings.
Further related cleanup to be kept separated for auditability.
Differential Revision: https://code.wildfiregames.com/D2163
Few comments on IRC by: wraitii, Itms
Tested on: gcc 9, Jenkins, partially VS2015
Refs #1984,
NONCOPYABLE CGUISpriteInstances: 0a7d0ecdde, 8f4f8e240f, c19f3608a5
NONCOPYABLE Image, Sprite: fb8032043b
NONCOPYABLE GUI page: 94c57085e9
NONCOPYABLE GUIManager: 7c2e9027c2
NONCOPYABLE macro: 16ccae10cd
This was SVN commit r22637.
2019-08-09 19:25:55 +02:00
m_Icons . erase ( name ) ;
m_Icons . emplace ( name , std : : move ( 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 )
{
2019-08-21 12:12:33 +02:00
IGUIObject * object = new CTooltip ( * this ) ;
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 ( ) ;
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 ;
Stop copying color every draw call for every GUI object using colors.
Avoid color copies for rendering Draw calls in
GUIRenderer::UpdateDrawCallCache, CButton::Draw, CChart::DrawAxes,
CDropDown::Draw, CList::DrawList, COList::DrawList, refs #1984,
8f4f8e240f, 3028551b91, a905fbbc98.
Avoid color copies during XML loading in CGUI::Xeromyces_ReadImage,
CGUI::Xeromyces_ReadEffects, COList::HandleAdditionalChildren.
Add CGUI::HasPreDefinedColor and mark m_PreDefinedColors,
CGUI::GetPreDefinedColor, IGUIButtonBehavior::ChooseColor() as const for
consistency with the other "databases", refs 3028551b91.
Mark CGUIColor as NONCOPYABLE to add compiler errors if there is an
unexplicit copy, refs 3028551b91.
Explicit ugly copy in CGUI::Xeromyces_ReadColor and
CGUIColor::ParseString.
Deregister copying <CGUIColor>GetSetting functions, refs 8f4f8e240f.
Uses the const ref GetSetting from 3dfa23cd25.
This was SVN commit r22694.
2019-08-19 14:53:58 +02:00
CColor color ;
if ( color . ParseString ( value ) )
2005-07-25 21:06:18 +02:00
{
Stop copying color every draw call for every GUI object using colors.
Avoid color copies for rendering Draw calls in
GUIRenderer::UpdateDrawCallCache, CButton::Draw, CChart::DrawAxes,
CDropDown::Draw, CList::DrawList, COList::DrawList, refs #1984,
8f4f8e240f, 3028551b91, a905fbbc98.
Avoid color copies during XML loading in CGUI::Xeromyces_ReadImage,
CGUI::Xeromyces_ReadEffects, COList::HandleAdditionalChildren.
Add CGUI::HasPreDefinedColor and mark m_PreDefinedColors,
CGUI::GetPreDefinedColor, IGUIButtonBehavior::ChooseColor() as const for
consistency with the other "databases", refs 3028551b91.
Mark CGUIColor as NONCOPYABLE to add compiler errors if there is an
unexplicit copy, refs 3028551b91.
Explicit ugly copy in CGUI::Xeromyces_ReadColor and
CGUIColor::ParseString.
Deregister copying <CGUIColor>GetSetting functions, refs 8f4f8e240f.
Uses the const ref GetSetting from 3dfa23cd25.
This was SVN commit r22694.
2019-08-19 14:53:58 +02:00
m_PreDefinedColors . erase ( name ) ;
m_PreDefinedColors . emplace (
std : : piecewise_construct ,
std : : forward_as_tuple ( name ) ,
std : : forward_as_tuple ( color . r , color . g , color . b , color . a ) ) ;
2005-07-25 21:06:18 +02:00
}
Stop copying color every draw call for every GUI object using colors.
Avoid color copies for rendering Draw calls in
GUIRenderer::UpdateDrawCallCache, CButton::Draw, CChart::DrawAxes,
CDropDown::Draw, CList::DrawList, COList::DrawList, refs #1984,
8f4f8e240f, 3028551b91, a905fbbc98.
Avoid color copies during XML loading in CGUI::Xeromyces_ReadImage,
CGUI::Xeromyces_ReadEffects, COList::HandleAdditionalChildren.
Add CGUI::HasPreDefinedColor and mark m_PreDefinedColors,
CGUI::GetPreDefinedColor, IGUIButtonBehavior::ChooseColor() as const for
consistency with the other "databases", refs 3028551b91.
Mark CGUIColor as NONCOPYABLE to add compiler errors if there is an
unexplicit copy, refs 3028551b91.
Explicit ugly copy in CGUI::Xeromyces_ReadColor and
CGUIColor::ParseString.
Deregister copying <CGUIColor>GetSetting functions, refs 8f4f8e240f.
Uses the const ref GetSetting from 3dfa23cd25.
This was SVN commit r22694.
2019-08-19 14:53:58 +02:00
else
LOGERROR ( " GUI: Unable to create custom color '%s'. Invalid color syntax. " , name . c_str ( ) ) ;
2005-07-25 21:06:18 +02:00
}