2019-07-19 14:15:04 -07:00
/* Copyright (C) 2019 Wildfire Games.
2009-04-18 10:00:33 -07: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 11:38:14 -07:00
# include "precompiled.h"
2015-08-21 10:08:41 -07:00
2003-11-23 18:18:41 -08:00
# include "GUI.h"
2019-08-29 02:07:29 -07:00
# include "gui/CGUISetting.h"
2004-07-08 08:23:47 -07:00
# include "gui/scripting/JSInterface_GUITypes.h"
2015-08-21 10:08:41 -07:00
# include "gui/scripting/JSInterface_IGUIObject.h"
2016-08-02 09:58:30 -07:00
# include "ps/GameSetup/Config.h"
2009-09-27 08:04:46 -07:00
# include "ps/CLogger.h"
2016-06-21 03:33:11 -07:00
# include "ps/Profile.h"
2015-08-21 10:08:41 -07:00
# include "scriptinterface/ScriptInterface.h"
2019-08-22 15:34:12 -07:00
# include "soundmanager/ISoundManager.h"
2009-09-27 08:04:46 -07:00
2019-08-21 03:12:33 -07:00
IGUIObject : : IGUIObject ( CGUI & pGUI )
2019-08-01 13:20:24 -07:00
: m_pGUI ( pGUI ) , m_pParent ( NULL ) , m_MouseHovering ( false ) , m_LastClickTime ( )
2003-11-23 18:18:41 -08:00
{
2019-08-03 19:20:08 -07:00
AddSetting < bool > ( " enabled " ) ;
AddSetting < bool > ( " hidden " ) ;
AddSetting < CClientArea > ( " size " ) ;
AddSetting < CStr > ( " style " ) ;
AddSetting < CStr > ( " hotkey " ) ;
AddSetting < float > ( " z " ) ;
AddSetting < bool > ( " absolute " ) ;
AddSetting < bool > ( " ghost " ) ;
AddSetting < float > ( " aspectratio " ) ;
AddSetting < CStrW > ( " tooltip " ) ;
AddSetting < CStr > ( " tooltip_style " ) ;
2004-05-28 21:06:50 -07:00
// Setup important defaults
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
SetSetting < bool > ( " hidden " , false , true ) ;
SetSetting < bool > ( " ghost " , false , true ) ;
SetSetting < bool > ( " enabled " , true , true ) ;
SetSetting < bool > ( " absolute " , true , true ) ;
2003-11-23 18:18:41 -08:00
}
IGUIObject : : ~ IGUIObject ( )
{
2019-08-03 19:20:08 -07:00
for ( const std : : pair < CStr , IGUISetting * > & p : m_Settings )
delete p . second ;
2015-01-24 06:46:52 -08:00
2019-08-01 13:20:24 -07:00
if ( ! m_ScriptHandlers . empty ( ) )
2019-08-21 03:12:33 -07:00
JS_RemoveExtraGCRootsTracer ( m_pGUI . GetScriptInterface ( ) - > GetJSRuntime ( ) , Trace , this ) ;
2003-11-23 18:18:41 -08:00
}
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
2015-01-24 06:46:52 -08:00
2015-08-21 10:08:41 -07:00
void IGUIObject : : AddChild ( IGUIObject * pChild )
2003-11-23 18:18:41 -08:00
{
2011-04-30 06:01:45 -07:00
// ENSURE(pChild);
2003-11-23 18:18:41 -08:00
pChild - > SetParent ( this ) ;
m_Children . push_back ( pChild ) ;
{
try
{
// Atomic function, if it fails it won't
// have changed anything
//UpdateObjects();
2019-08-21 03:12:33 -07:00
pChild - > GetGUI ( ) . UpdateObjects ( ) ;
2003-11-23 18:18:41 -08:00
}
2009-09-27 08:04:46 -07:00
catch ( PSERROR_GUI & )
2003-11-23 18:18:41 -08:00
{
// If anything went wrong, reverse what we did and throw
// an exception telling it never added a child
2015-08-21 10:08:41 -07:00
m_Children . erase ( m_Children . end ( ) - 1 ) ;
2009-09-27 08:04:46 -07:00
throw ;
2003-11-23 18:18:41 -08:00
}
}
// else do nothing
}
2015-08-21 10:08:41 -07:00
void IGUIObject : : AddToPointersMap ( map_pObjects & ObjectMap )
2003-11-23 18:18:41 -08:00
{
// Just don't do anything about the top node
if ( m_pParent = = NULL )
return ;
// Now actually add this one
// notice we won't add it if it's doesn't have any parent
// (i.e. being the base object)
2007-02-01 06:46:14 -08:00
if ( m_Name . empty ( ) )
2003-11-23 18:18:41 -08:00
{
2009-09-23 14:16:55 -07:00
throw PSERROR_GUI_ObjectNeedsName ( ) ;
2003-11-23 18:18:41 -08:00
}
if ( ObjectMap . count ( m_Name ) > 0 )
{
2010-06-30 14:20:08 -07:00
throw PSERROR_GUI_NameAmbiguity ( m_Name . c_str ( ) ) ;
2003-11-23 18:18:41 -08:00
}
else
{
ObjectMap [ m_Name ] = this ;
}
}
void IGUIObject : : Destroy ( )
{
// Is there anything besides the children to destroy?
}
2019-08-03 19:20:08 -07:00
template < typename T >
void IGUIObject : : AddSetting ( const CStr & Name )
2003-11-23 18:18:41 -08:00
{
2019-08-03 19:20:08 -07:00
// This can happen due to inheritance
if ( SettingExists ( Name ) )
2004-05-28 21:06:50 -07:00
return ;
2019-08-03 19:20:08 -07:00
m_Settings [ Name ] = new CGUISetting < T > ( * this , Name ) ;
2003-11-23 18:18:41 -08:00
}
2004-12-16 16:05:37 -08:00
2019-08-26 05:25:07 -07:00
bool IGUIObject : : SettingExists ( const CStr & Setting ) const
{
return m_Settings . count ( Setting ) = = 1 ;
}
template < typename T >
T & IGUIObject : : GetSetting ( const CStr & Setting )
{
return static_cast < CGUISetting < T > * > ( m_Settings . at ( Setting ) ) - > m_pSetting ;
}
template < typename T >
const T & IGUIObject : : GetSetting ( const CStr & Setting ) const
{
return static_cast < CGUISetting < T > * > ( m_Settings . at ( Setting ) ) - > m_pSetting ;
}
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
bool IGUIObject : : SetSettingFromString ( const CStr & Setting , const CStrW & Value , const bool SendMessage )
{
2019-09-16 09:13:25 -07:00
const std : : map < CStr , IGUISetting * > : : iterator it = m_Settings . find ( Setting ) ;
if ( it = = m_Settings . end ( ) )
{
LOGERROR ( " GUI object '%s' has no property called '%s', can't set parse and set value '%s' " , GetPresentableName ( ) . c_str ( ) , Setting . c_str ( ) , Value . ToUTF8 ( ) . c_str ( ) ) ;
return false ;
}
return it - > second - > FromString ( Value , SendMessage ) ;
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
}
template < typename T >
void IGUIObject : : SetSetting ( const CStr & Setting , T & Value , const bool SendMessage )
{
2019-09-04 08:29:36 -07:00
PreSettingChange ( Setting ) ;
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
static_cast < CGUISetting < T > * > ( m_Settings [ Setting ] ) - > m_pSetting = std : : move ( Value ) ;
SettingChanged ( Setting , SendMessage ) ;
}
template < typename T >
void IGUIObject : : SetSetting ( const CStr & Setting , const T & Value , const bool SendMessage )
{
2019-09-04 08:29:36 -07:00
PreSettingChange ( Setting ) ;
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
static_cast < CGUISetting < T > * > ( m_Settings [ Setting ] ) - > m_pSetting = Value ;
SettingChanged ( Setting , SendMessage ) ;
}
2019-09-04 08:29:36 -07:00
void IGUIObject : : PreSettingChange ( const CStr & Setting )
{
if ( Setting = = " hotkey " )
m_pGUI . UnsetObjectHotkey ( this , GetSetting < CStr > ( Setting ) ) ;
}
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
void IGUIObject : : SettingChanged ( const CStr & Setting , const bool SendMessage )
{
if ( Setting = = " size " )
{
// If setting was "size", we need to re-cache itself and all children
RecurseObject ( nullptr , & IGUIObject : : UpdateCachedSize ) ;
}
else if ( Setting = = " hidden " )
{
// Hiding an object requires us to reset it and all children
if ( GetSetting < bool > ( Setting ) )
RecurseObject ( nullptr , & IGUIObject : : ResetStates ) ;
}
2019-09-04 08:29:36 -07:00
else if ( Setting = = " hotkey " )
m_pGUI . SetObjectHotkey ( this , GetSetting < CStr > ( Setting ) ) ;
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
if ( SendMessage )
{
SGUIMessage msg ( GUIM_SETTINGS_UPDATED , Setting ) ;
HandleMessage ( msg ) ;
}
}
2019-08-22 16:51:10 -07:00
bool IGUIObject : : IsMouseOver ( ) const
2003-11-23 18:18:41 -08:00
{
2019-08-21 03:12:33 -07:00
return m_CachedActualSize . PointInside ( m_pGUI . GetMousePos ( ) ) ;
2003-11-23 18:18:41 -08:00
}
2010-10-29 21:02:42 -07:00
bool IGUIObject : : MouseOverIcon ( )
{
return false ;
}
2015-08-21 10:08:41 -07:00
void IGUIObject : : UpdateMouseOver ( IGUIObject * const & pMouseOver )
2003-11-23 18:18:41 -08:00
{
if ( pMouseOver = = this )
{
if ( ! m_MouseHovering )
2011-04-28 13:42:11 -07:00
SendEvent ( GUIM_MOUSE_ENTER , " mouseenter " ) ;
2003-11-23 18:18:41 -08:00
m_MouseHovering = true ;
2011-04-28 13:42:11 -07:00
SendEvent ( GUIM_MOUSE_OVER , " mousemove " ) ;
2003-11-23 18:18:41 -08:00
}
2016-06-07 05:02:33 -07:00
else
2003-11-23 18:18:41 -08:00
{
if ( m_MouseHovering )
{
m_MouseHovering = false ;
2011-04-28 13:42:11 -07:00
SendEvent ( GUIM_MOUSE_LEAVE , " mouseleave " ) ;
2003-11-23 18:18:41 -08:00
}
}
}
2015-08-21 10:08:41 -07:00
void IGUIObject : : ChooseMouseOverAndClosest ( IGUIObject * & pObject )
2003-11-23 18:18:41 -08:00
{
2019-08-22 16:51:10 -07:00
if ( ! IsMouseOver ( ) )
2015-08-21 10:08:41 -07:00
return ;
// Check if we've got competition at all
if ( pObject = = NULL )
2003-11-23 18:18:41 -08:00
{
2015-08-21 10:08:41 -07:00
pObject = this ;
return ;
}
2003-11-23 18:18:41 -08:00
2015-08-21 10:08:41 -07:00
// Or if it's closer
if ( GetBufferedZ ( ) > = pObject - > GetBufferedZ ( ) )
{
pObject = this ;
return ;
2003-11-23 18:18:41 -08:00
}
}
2015-08-21 10:08:41 -07:00
IGUIObject * IGUIObject : : GetParent ( ) const
2003-11-23 18:18:41 -08:00
{
// Important, we're not using GetParent() for these
// checks, that could screw it up
if ( m_pParent )
{
if ( m_pParent - > m_pParent = = NULL )
return NULL ;
}
return m_pParent ;
}
2019-07-27 19:39:52 -07:00
void IGUIObject : : ResetStates ( )
{
// Notify the gui that we aren't hovered anymore
UpdateMouseOver ( nullptr ) ;
}
2003-11-24 09:13:37 -08:00
void IGUIObject : : UpdateCachedSize ( )
{
2019-08-26 05:25:07 -07:00
const CClientArea & ca = GetSetting < CClientArea > ( " size " ) ;
const float aspectratio = GetSetting < float > ( " aspectratio " ) ;
2015-08-21 10:08:41 -07:00
2003-11-24 18:47:12 -08:00
// If absolute="false" and the object has got a parent,
// use its cached size instead of the screen. Notice
// it must have just been cached for it to work.
2019-08-26 05:25:07 -07:00
if ( ! GetSetting < bool > ( " absolute " ) & & m_pParent & & ! IsRootObject ( ) )
2019-08-19 03:32:29 -07:00
m_CachedActualSize = ca . GetClientArea ( m_pParent - > m_CachedActualSize ) ;
2003-11-24 18:47:12 -08:00
else
2019-08-19 03:32:29 -07:00
m_CachedActualSize = ca . GetClientArea ( CRect ( 0.f , 0.f , g_xres / g_GuiScale , g_yres / g_GuiScale ) ) ;
2004-05-28 21:06:50 -07:00
2010-08-10 15:39:00 -07:00
// In a few cases, GUI objects have to resize to fill the screen
// but maintain a constant aspect ratio.
// Adjust the size to be the max possible, centered in the original size:
if ( aspectratio )
{
if ( m_CachedActualSize . GetWidth ( ) > m_CachedActualSize . GetHeight ( ) * aspectratio )
{
float delta = m_CachedActualSize . GetWidth ( ) - m_CachedActualSize . GetHeight ( ) * aspectratio ;
m_CachedActualSize . left + = delta / 2.f ;
m_CachedActualSize . right - = delta / 2.f ;
}
else
{
float delta = m_CachedActualSize . GetHeight ( ) - m_CachedActualSize . GetWidth ( ) / aspectratio ;
m_CachedActualSize . bottom - = delta / 2.f ;
m_CachedActualSize . top + = delta / 2.f ;
}
}
2003-11-24 09:13:37 -08:00
}
2019-08-27 09:03:24 -07:00
void IGUIObject : : LoadStyle ( const CStr & StyleName )
2003-12-26 22:26:03 -08:00
{
2019-08-27 09:03:24 -07:00
if ( ! m_pGUI . HasStyle ( StyleName ) )
2009-11-03 13:46:35 -08:00
debug_warn ( L " IGUIObject::LoadStyle failed " ) ;
2004-12-13 04:07:12 -08:00
2019-08-27 09:03:24 -07:00
// The default style may specify settings for any GUI object.
// Other styles are reported if they specify a Setting that does not exist,
// so that the XML author is informed and can correct the style.
2004-12-13 04:07:12 -08:00
2019-08-27 09:03:24 -07:00
for ( const std : : pair < CStr , CStrW > & p : m_pGUI . GetStyle ( StyleName ) . m_SettingsDefaults )
{
if ( SettingExists ( p . first ) )
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
SetSettingFromString ( p . first , p . second , true ) ;
2019-08-27 09:03:24 -07:00
else if ( StyleName ! = " default " )
LOGWARNING ( " GUI object has no setting \" %s \" , but the style \" %s \" defines it " , p . first , StyleName . c_str ( ) ) ;
2003-12-26 22:26:03 -08:00
}
}
float IGUIObject : : GetBufferedZ ( ) const
{
2019-08-26 05:25:07 -07:00
const float Z = GetSetting < float > ( " z " ) ;
2004-05-28 21:06:50 -07:00
2019-08-26 05:25:07 -07:00
if ( GetSetting < bool > ( " absolute " ) )
2004-05-28 21:06:50 -07:00
return Z ;
2019-08-23 07:43:10 -07:00
2003-12-26 22:26:03 -08:00
{
if ( GetParent ( ) )
2004-05-28 21:06:50 -07:00
return GetParent ( ) - > GetBufferedZ ( ) + Z ;
2003-12-26 22:26:03 -08:00
else
2004-08-08 11:21:58 -07:00
{
2005-07-19 20:52:09 -07:00
// In philosophy, a parentless object shouldn't be able to have a relative sizing,
2015-08-21 10:08:41 -07:00
// but we'll accept it so that absolute can be used as default without a complaint.
2005-07-19 20:52:09 -07:00
// Also, you could consider those objects children to the screen resolution.
2004-05-28 21:06:50 -07:00
return Z ;
2004-08-08 11:21:58 -07:00
}
2003-12-26 22:26:03 -08:00
}
}
2019-08-21 03:12:33 -07:00
void IGUIObject : : RegisterScriptHandler ( const CStr & Action , const CStr & Code , CGUI & pGUI )
2004-07-08 08:23:47 -07:00
{
2019-08-21 03:12:33 -07:00
JSContext * cx = pGUI . GetScriptInterface ( ) - > GetContext ( ) ;
2014-03-28 13:26:32 -07:00
JSAutoRequest rq ( cx ) ;
2019-08-21 03:12:33 -07:00
JS : : RootedValue globalVal ( cx , pGUI . GetGlobalObject ( ) ) ;
2014-08-08 06:41:47 -07:00
JS : : RootedObject globalObj ( cx , & globalVal . toObject ( ) ) ;
2015-08-21 10:08:41 -07:00
2004-07-08 08:23:47 -07:00
const int paramCount = 1 ;
const char * paramNames [ paramCount ] = { " mouse " } ;
2004-07-11 11:18:54 -07:00
// Location to report errors from
CStr CodeName = GetName ( ) + " " + Action ;
2004-12-21 10:41:58 -08:00
// Generate a unique name
2015-08-21 10:08:41 -07:00
static int x = 0 ;
2004-12-21 10:41:58 -08:00
char buf [ 64 ] ;
2010-07-19 16:01:58 -07:00
sprintf_s ( buf , ARRAY_SIZE ( buf ) , " __eventhandler%d (%s) " , x + + , Action . c_str ( ) ) ;
2004-12-21 10:41:58 -08:00
2015-01-24 06:46:52 -08:00
JS : : CompileOptions options ( cx ) ;
options . setFileAndLine ( CodeName . c_str ( ) , 0 ) ;
2019-08-08 02:05:42 -07:00
options . setIsRunOnce ( false ) ;
2015-01-24 06:46:52 -08:00
2016-09-02 09:34:02 -07:00
JS : : RootedFunction func ( cx ) ;
JS : : AutoObjectVector emptyScopeChain ( cx ) ;
if ( ! JS : : CompileFunction ( cx , emptyScopeChain , options , buf , paramCount , paramNames , Code . c_str ( ) , Code . length ( ) , & func ) )
{
LOGERROR ( " RegisterScriptHandler: Failed to compile the script for %s " , Action . c_str ( ) ) ;
return ;
}
2015-08-21 10:08:41 -07:00
2014-08-08 06:41:47 -07:00
JS : : RootedObject funcObj ( cx , JS_GetFunctionObject ( func ) ) ;
SetScriptHandler ( Action , funcObj ) ;
2005-03-30 14:33:10 -08:00
}
2004-12-21 10:41:58 -08:00
2014-08-08 06:41:47 -07:00
void IGUIObject : : SetScriptHandler ( const CStr & Action , JS : : HandleObject Function )
2005-03-30 14:33:10 -08:00
{
2019-08-01 13:20:24 -07:00
if ( m_ScriptHandlers . empty ( ) )
2019-08-21 03:12:33 -07:00
JS_AddExtraGCRootsTracer ( m_pGUI . GetScriptInterface ( ) - > GetJSRuntime ( ) , Trace , this ) ;
2019-08-01 13:20:24 -07:00
2015-01-24 06:46:52 -08:00
m_ScriptHandlers [ Action ] = JS : : Heap < JSObject * > ( Function ) ;
2004-07-08 08:23:47 -07:00
}
2011-04-28 13:42:11 -07:00
InReaction IGUIObject : : SendEvent ( EGUIMessageType type , const CStr & EventName )
{
2011-11-09 05:09:01 -08:00
PROFILE2_EVENT ( " gui event " ) ;
PROFILE2_ATTR ( " type: %s " , EventName . c_str ( ) ) ;
PROFILE2_ATTR ( " object: %s " , m_Name . c_str ( ) ) ;
2011-04-28 13:42:11 -07:00
SGUIMessage msg ( type ) ;
HandleMessage ( msg ) ;
ScriptEvent ( EventName ) ;
return ( msg . skipped ? IN_PASS : IN_HANDLED ) ;
}
2004-07-08 08:23:47 -07:00
void IGUIObject : : ScriptEvent ( const CStr & Action )
{
2019-07-19 14:15:04 -07:00
std : : map < CStr , JS : : Heap < JSObject * > > : : iterator it = m_ScriptHandlers . find ( Action ) ;
2004-07-08 08:23:47 -07:00
if ( it = = m_ScriptHandlers . end ( ) )
return ;
2019-08-21 03:12:33 -07:00
JSContext * cx = m_pGUI . GetScriptInterface ( ) - > GetContext ( ) ;
2014-03-28 13:26:32 -07:00
JSAutoRequest rq ( cx ) ;
2014-01-04 02:14:53 -08:00
2004-07-08 08:23:47 -07:00
// Set up the 'mouse' parameter
2014-07-26 15:33:16 -07:00
JS : : RootedValue mouse ( cx ) ;
2019-07-22 12:35:14 -07:00
2019-08-21 03:12:33 -07:00
const CPos & mousePos = m_pGUI . GetMousePos ( ) ;
2019-08-10 05:51:27 -07:00
2019-09-12 17:56:51 -07:00
ScriptInterface : : CreateObject (
cx ,
2019-07-22 12:35:14 -07:00
& mouse ,
2019-08-10 05:51:27 -07:00
" x " , mousePos . x ,
" y " , mousePos . y ,
2019-08-21 03:12:33 -07:00
" buttons " , m_pGUI . GetMouseButtons ( ) ) ;
2014-07-26 15:33:16 -07:00
JS : : AutoValueVector paramData ( cx ) ;
paramData . append ( mouse ) ;
JS : : RootedObject obj ( cx , GetJSObject ( ) ) ;
2015-01-24 06:46:52 -08:00
JS : : RootedValue handlerVal ( cx , JS : : ObjectValue ( * it - > second ) ) ;
2014-07-26 15:33:16 -07:00
JS : : RootedValue result ( cx ) ;
2015-01-24 06:46:52 -08:00
bool ok = JS_CallFunctionValue ( cx , obj , handlerVal , paramData , & result ) ;
2004-07-24 07:04:40 -07:00
if ( ! ok )
{
2011-02-27 09:57:32 -08:00
// We have no way to propagate the script exception, so just ignore it
// and hope the caller checks JS_IsExceptionPending
2004-07-24 07:04:40 -07:00
}
2004-07-08 08:23:47 -07:00
}
2004-08-30 19:09:58 -07:00
2019-08-21 06:22:25 -07:00
void IGUIObject : : ScriptEvent ( const CStr & Action , const JS : : HandleValueArray & paramData )
2010-09-11 12:49:21 -07:00
{
2019-07-19 14:15:04 -07:00
std : : map < CStr , JS : : Heap < JSObject * > > : : iterator it = m_ScriptHandlers . find ( Action ) ;
2010-09-11 12:49:21 -07:00
if ( it = = m_ScriptHandlers . end ( ) )
return ;
2019-08-21 03:12:33 -07:00
JSContext * cx = m_pGUI . GetScriptInterface ( ) - > GetContext ( ) ;
2014-03-28 13:26:32 -07:00
JSAutoRequest rq ( cx ) ;
2014-08-08 06:41:47 -07:00
JS : : RootedObject obj ( cx , GetJSObject ( ) ) ;
2015-01-24 06:46:52 -08:00
JS : : RootedValue handlerVal ( cx , JS : : ObjectValue ( * it - > second ) ) ;
2014-08-08 06:41:47 -07:00
JS : : RootedValue result ( cx ) ;
2019-07-19 14:15:04 -07:00
if ( ! JS_CallFunctionValue ( cx , obj , handlerVal , paramData , & result ) )
2014-01-04 02:14:53 -08:00
JS_ReportError ( cx , " Errors executing script action \" %s \" " , Action . c_str ( ) ) ;
2010-09-11 12:49:21 -07:00
}
2019-08-02 05:18:30 -07:00
void IGUIObject : : CreateJSObject ( )
2007-06-08 15:56:01 -07:00
{
2019-08-21 03:12:33 -07:00
JSContext * cx = m_pGUI . GetScriptInterface ( ) - > GetContext ( ) ;
2014-03-28 13:26:32 -07:00
JSAutoRequest rq ( cx ) ;
2019-08-02 05:18:30 -07:00
2019-08-21 03:12:33 -07:00
m_JSObject . init ( cx , m_pGUI . GetScriptInterface ( ) - > CreateCustomObject ( " GUIObject " ) ) ;
2019-08-02 05:18:30 -07:00
JS_SetPrivate ( m_JSObject . get ( ) , this ) ;
}
JSObject * IGUIObject : : GetJSObject ( )
{
2007-06-08 15:56:01 -07:00
// Cache the object when somebody first asks for it, because otherwise
2019-08-02 05:18:30 -07:00
// we end up doing far too much object allocation.
2016-09-02 09:53:22 -07:00
if ( ! m_JSObject . initialized ( ) )
2019-08-02 05:18:30 -07:00
CreateJSObject ( ) ;
2015-01-24 06:46:52 -08:00
return m_JSObject . get ( ) ;
2007-06-08 15:56:01 -07:00
}
2019-08-22 16:51:10 -07:00
bool IGUIObject : : IsHidden ( ) const
2019-08-21 06:22:25 -07:00
{
// Statically initialise some strings, so we don't have to do
// lots of allocation every time this function is called
static const CStr strHidden ( " hidden " ) ;
2019-08-26 05:25:07 -07:00
return GetSetting < bool > ( strHidden ) ;
2019-08-21 06:22:25 -07:00
}
2019-08-22 16:51:10 -07:00
bool IGUIObject : : IsHiddenOrGhost ( ) const
2019-08-21 06:22:25 -07:00
{
static const CStr strGhost ( " ghost " ) ;
2019-08-26 05:25:07 -07:00
return IsHidden ( ) | | GetSetting < bool > ( strGhost ) ;
2019-08-21 06:22:25 -07:00
}
2019-08-22 15:34:12 -07:00
void IGUIObject : : PlaySound ( const CStr & settingName ) const
{
if ( ! g_SoundManager )
return ;
2019-08-26 05:25:07 -07:00
const CStrW & soundPath = GetSetting < CStrW > ( settingName ) ;
2019-08-22 15:34:12 -07:00
if ( ! soundPath . empty ( ) )
g_SoundManager - > PlayAsUI ( soundPath . c_str ( ) , false ) ;
}
2004-08-30 19:09:58 -07:00
CStr IGUIObject : : GetPresentableName ( ) const
{
// __internal(), must be at least 13 letters to be able to be
// an internal name
2007-02-01 06:46:14 -08:00
if ( m_Name . length ( ) < = 12 )
2004-08-30 19:09:58 -07:00
return m_Name ;
2007-02-01 06:46:14 -08:00
if ( m_Name . substr ( 0 , 10 ) = = " __internal " )
2004-08-30 19:09:58 -07:00
return CStr ( " [unnamed object] " ) ;
else
return m_Name ;
2004-10-14 03:09:26 -07:00
}
void IGUIObject : : SetFocus ( )
{
2019-08-21 03:12:33 -07:00
m_pGUI . SetFocusedObject ( this ) ;
2004-10-14 03:09:26 -07:00
}
bool IGUIObject : : IsFocused ( ) const
{
2019-08-21 03:12:33 -07:00
return m_pGUI . GetFocusedObject ( ) = = this ;
2004-11-07 13:30:47 -08:00
}
2005-07-20 16:49:39 -07:00
bool IGUIObject : : IsRootObject ( ) const
{
2019-08-21 03:12:33 -07:00
return m_pParent = = m_pGUI . GetBaseObject ( ) ;
2005-07-20 16:49:39 -07:00
}
2009-09-27 08:04:46 -07:00
2015-08-21 10:08:41 -07:00
void IGUIObject : : TraceMember ( JSTracer * trc )
2015-01-24 06:46:52 -08:00
{
2019-08-01 13:20:24 -07:00
// Please ensure to adapt the Tracer enabling and disabling in accordance with the GC things traced!
2016-01-12 16:42:55 -08:00
for ( std : : pair < const CStr , JS : : Heap < JSObject * > > & handler : m_ScriptHandlers )
2016-09-02 09:25:42 -07:00
JS_CallObjectTracer ( trc , & handler . second , " IGUIObject::m_ScriptHandlers " ) ;
2015-01-24 06:46:52 -08:00
}
2019-08-03 19:20:08 -07:00
// Instantiate templated functions:
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
// These functions avoid copies by working with a reference and move semantics.
2019-08-26 05:25:07 -07:00
# define TYPE(T) \
template void IGUIObject : : AddSetting < T > ( const CStr & Name ) ; \
template T & IGUIObject : : GetSetting < T > ( const CStr & Setting ) ; \
template const T & IGUIObject : : GetSetting < T > ( const CStr & Setting ) const ; \
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
template void IGUIObject : : SetSetting < T > ( const CStr & Setting , T & Value , const bool SendMessage ) ; \
2019-08-26 05:25:07 -07:00
# include "gui/GUItypes.h"
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
# undef TYPE
2019-08-26 05:25:07 -07:00
Move static GUI<>::SetSetting operating on IGUIObject to a member IGUIObject::SetSetting.
Remove PSERROR codes from SetSetting (let std::map throw an out_of_range
if a caller wants to Set a setting that doesn't exist without having
checked with SettingExists, equal to GetSetting from 92b6cdfeab).
That also simplifies std::function SetSettingWrap construct from
0a7d0ecdde to void IGUIObject::SettingChanged.
Don't trigger debug_warn or exceptions in GUITooltip::ShowTooltip if the
XML author specified wrong tooltip input, and dodge another
dynamic_cast.
Rename existing IGUIObject::SetSetting to
IGUIObject::SetSettingFromString and comment that it is purposed for
parsing XML files.
Remove SetSetting default value, so that authors are made aware
explicitly of the need to decide the function broadcasting a message,
refs d87057b1c0, 719f2d7967, ...
Change const bool& SkipMessage to const bool SendMessage, so that a
positive value relates to a positive action.
Clean AddSettings whitespace and integer types.
Differential Revision: https://code.wildfiregames.com/D2231
Tested on: gcc 9.1.0, clang 8.0.1, Jenkins
Comments By: Philip on IRC on 2010-07-24 on GUIUtil being ugly, in case
that one counts
This was SVN commit r22796.
2019-08-28 04:21:11 -07:00
// Copying functions - discouraged except for primitives.
# define TYPE(T) \
template void IGUIObject : : SetSetting < T > ( const CStr & Setting , const T & Value , const bool SendMessage ) ; \
# define GUITYPE_IGNORE_NONCOPYABLE
# include "gui/GUItypes.h"
# undef GUITYPE_IGNORE_NONCOPYABLE
2019-08-03 19:20:08 -07:00
# undef TYPE