1
0
forked from 0ad/0ad
0ad/source/gui/IGUIObject.cpp

336 lines
7.7 KiB
C++
Raw Normal View History

2003-11-24 03:18:41 +01:00
/*
IGUIObject
by Gustav Larsson
gee@pyro.nu
*/
//#include "stdafx."
#include "GUI.h"
///// janwas: again, including etiquette?
2003-12-01 08:06:55 +01:00
#include "Parser.h"
2003-11-24 03:18:41 +01:00
#include <assert.h>
/////
using namespace std;
// Offsets
map_Settings IGUIObject::m_SettingsInfo;
//-------------------------------------------------------------------
// Implementation Macros
//-------------------------------------------------------------------
2003-12-01 08:06:55 +01:00
/*#define _GUI_ADD_OFFSET(type, str, var) \
2003-11-24 03:18:41 +01:00
SettingsInfo[str].m_Offset = offsetof(IGUIObject, m_BaseSettings) + offsetof(SGUIBaseSettings,var); \
SettingsInfo[str].m_Type = type;
2003-12-01 08:06:55 +01:00
*/
2003-11-24 03:18:41 +01:00
//-------------------------------------------------------------------
// Constructor / Destructor
//-------------------------------------------------------------------
IGUIObject::IGUIObject() :
m_pGUI(NULL),
m_pParent(NULL),
m_MouseHovering(false)
{
// Default values of base settings !
m_BaseSettings.m_Enabled = true;
m_BaseSettings.m_Hidden = false;
m_BaseSettings.m_Style = "null";
m_BaseSettings.m_Z = 0.f;
2003-11-25 03:47:12 +01:00
m_BaseSettings.m_Absolute = true;
2003-11-24 03:18:41 +01:00
// Static! Only done once
if (m_SettingsInfo.empty())
{
SetupBaseSettingsInfo(m_SettingsInfo);
}
}
IGUIObject::~IGUIObject()
{
}
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
void IGUIObject::AddChild(IGUIObject *pChild)
{
//
// assert(pChild);
pChild->SetParent(this);
m_Children.push_back(pChild);
// If this (not the child) object is already attached
// to a CGUI, it pGUI pointer will be non-null.
// This will mean we'll have to check if we're using
// names already used.
if (pChild->GetGUI())
{
try
{
// Atomic function, if it fails it won't
// have changed anything
//UpdateObjects();
pChild->GetGUI()->UpdateObjects();
}
catch (PS_RESULT e)
{
// If anything went wrong, reverse what we did and throw
// an exception telling it never added a child
m_Children.erase( m_Children.end()-1 );
// We'll throw the same exception for easier
// error handling
throw e;
}
}
// else do nothing
}
void IGUIObject::AddToPointersMap(map_pObjects &ObjectMap)
{
// 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)
if (m_Name == string())
{
throw PS_NEEDS_NAME;
}
if (ObjectMap.count(m_Name) > 0)
{
throw PS_NAME_AMBIGUITY;
}
else
{
ObjectMap[m_Name] = this;
}
}
void IGUIObject::Destroy()
{
// Is there anything besides the children to destroy?
}
void IGUIObject::SetupBaseSettingsInfo(map_Settings &SettingsInfo)
{
2003-12-01 08:06:55 +01:00
/* _GUI_ADD_OFFSET("bool", "enabled", m_Enabled)
2003-11-24 18:13:37 +01:00
_GUI_ADD_OFFSET("bool", "hidden", m_Hidden)
_GUI_ADD_OFFSET("client area", "size", m_Size)
_GUI_ADD_OFFSET("string", "style", m_Style)
_GUI_ADD_OFFSET("float", "z", m_Z)
_GUI_ADD_OFFSET("string", "caption", m_Caption)
2003-11-25 03:47:12 +01:00
_GUI_ADD_OFFSET("bool", "absolute", m_Absolute)
2003-12-01 08:06:55 +01:00
*/
GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Enabled, "bool", "enabled")
GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Hidden, "bool", "hidden")
GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Size, "client area", "size")
GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Style, "string", "style")
GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Z, "float", "z")
GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Caption, "string", "caption")
GUI_ADD_OFFSET_GENERIC(SettingsInfo, GUISS_BASE, SGUIBaseSettings, m_Absolute, "bool", "absolute")
2003-11-24 03:18:41 +01:00
}
bool IGUIObject::MouseOver()
{
if(!GetGUI())
throw PS_NEEDS_PGUI;
u16 mouse_x = GetMouseX(),
mouse_y = GetMouseY();
2003-11-25 04:21:11 +01:00
return (mouse_x >= m_CachedActualSize.left &&
mouse_x <= m_CachedActualSize.right &&
mouse_y >= m_CachedActualSize.top &&
mouse_y <= m_CachedActualSize.bottom);
2003-11-24 03:18:41 +01:00
}
u16 IGUIObject::GetMouseX() const
{
return ((GetGUI())?(GetGUI()->m_MouseX):0);
}
u16 IGUIObject::GetMouseY() const
{
return ((GetGUI())?(GetGUI()->m_MouseY):0);
}
void IGUIObject::UpdateMouseOver(IGUIObject * const &pMouseOver)
{
// Check if this is the object being hovered.
if (pMouseOver == this)
{
if (!m_MouseHovering)
{
// It wasn't hovering, so that must mean it just entered
HandleMessage(GUIM_MOUSE_ENTER);
}
// Either way, set to true
m_MouseHovering = true;
// call mouse over
HandleMessage(GUIM_MOUSE_OVER);
}
else // Some other object (or none) is hovered
{
if (m_MouseHovering)
{
m_MouseHovering = false;
HandleMessage(GUIM_MOUSE_LEAVE);
}
}
}
bool IGUIObject::SettingExists(const CStr &Setting) const
{
// Because GetOffsets will direct dynamically defined
// classes with polymorifsm to respective m_SettingsInfo
// we need to make no further updates on this function
// in derived classes.
return (GetSettingsInfo().count(Setting) == 1)?true:false;
}
void IGUIObject::SetSetting(const CStr &Setting, const CStr &Value)
{
if (!SettingExists(Setting))
{
throw PS_FAIL;
}
// Get setting
SGUISetting set = GetSettingsInfo()[Setting];
if (set.m_Type == CStr(_T("string")))
{
2003-12-01 08:06:55 +01:00
GUI<CStr>::SetSetting(this, Setting, Value);
2003-11-24 03:18:41 +01:00
}
else
2003-11-25 03:47:12 +01:00
if (set.m_Type == CStr(_T("bool")))
{
2003-12-01 08:06:55 +01:00
bool _Value;
if (!GUI<bool>::ParseString(Value, _Value))
2003-11-25 03:47:12 +01:00
throw PS_FAIL;
2003-12-01 08:06:55 +01:00
GUI<bool>::SetSetting(this, Setting, _Value);
2003-11-25 03:47:12 +01:00
}
else
2003-11-24 03:18:41 +01:00
if (set.m_Type == CStr(_T("float")))
{
2003-12-01 08:06:55 +01:00
float _Value;
if (!GUI<float>::ParseString(Value, _Value))
throw PS_FAIL;
GUI<float>::SetSetting(this, Setting, _Value);
2003-11-24 03:18:41 +01:00
}
else
if (set.m_Type == CStr(_T("rect")))
{
2003-12-01 08:06:55 +01:00
CRect _Value;
if (!GUI<CRect>::ParseString(Value, _Value))
2003-11-24 03:18:41 +01:00
throw PS_FAIL;
2003-12-01 08:06:55 +01:00
GUI<CRect>::SetSetting(this, Setting, _Value);
2003-11-24 03:18:41 +01:00
}
else
2003-11-24 18:13:37 +01:00
if (set.m_Type == CStr(_T("client area")))
{
2003-12-01 08:06:55 +01:00
CClientArea _Value;
if (!GUI<CClientArea>::ParseString(Value, _Value))
throw PS_FAIL;
2003-11-24 18:13:37 +01:00
2003-12-01 08:06:55 +01:00
GUI<CClientArea>::SetSetting(this, Setting, _Value);
2003-11-24 18:13:37 +01:00
}
else
2003-11-24 03:18:41 +01:00
{
throw PS_FAIL;
}
}
void IGUIObject::ChooseMouseOverAndClosest(IGUIObject* &pObject)
{
if (MouseOver())
{
// Check if we've got competition at all
if (pObject == NULL)
{
pObject = this;
return;
}
// Or if it's closer
if (GetBaseSettings().m_Z >= pObject->GetBaseSettings().m_Z)
{
pObject = this;
return;
}
}
}
IGUIObject *IGUIObject::GetParent()
{
// 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;
}
2003-12-01 08:06:55 +01:00
void * IGUIObject::GetStructPointer(const EGUISettingsStruct &SettingsStruct) const
{
switch (SettingsStruct)
{
case GUISS_BASE:
return (void*)&m_BaseSettings;
default:
// GeeTODO report error
return NULL;
}
}
2003-11-24 18:13:37 +01:00
void IGUIObject::UpdateCachedSize()
{
2003-11-25 03:47:12 +01: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.
if (m_BaseSettings.m_Absolute == false && m_pParent)
m_CachedActualSize = m_BaseSettings.m_Size.GetClientArea( m_pParent->m_CachedActualSize );
else
m_CachedActualSize = m_BaseSettings.m_Size.GetClientArea( CRect(0, 0, g_xres, g_yres) );
2003-11-24 18:13:37 +01:00
}
2003-11-24 03:18:41 +01:00
// GeeTODO keep this function and all???
void IGUIObject::CheckSettingsValidity()
{
// If we hide an object, reset many of its parts
if (GetBaseSettings().m_Hidden)
{
// Simulate that no object is hovered for this object and all its children
// why? because it's
try
{
GUI<IGUIObject*>::RecurseObject(0, this, &IGUIObject::UpdateMouseOver, NULL);
}
catch (...) {}
}
try
{
2003-11-25 03:47:12 +01:00
// Send message to itself
2003-11-24 03:18:41 +01:00
HandleMessage(GUIM_SETTINGS_UPDATED);
}
catch (...)
{
}
2003-11-24 18:13:37 +01:00
}