0ad/source/gui/GUIutil.cpp

392 lines
8.5 KiB
C++
Raw Normal View History

/*
GUI utilities
by Gustav Larsson
gee@pyro.nu
*/
#include "precompiled.h"
#include "GUI.h"
2003-12-01 08:06:55 +01:00
#include "Parser.h"
using namespace std;
2004-05-29 06:06:50 +02:00
template <typename T>
bool __ParseString(const CStr& Value, T &tOutput)
2004-05-29 06:06:50 +02:00
{
// TODO Gee: Unsupported, report error/warning
return false;
}
template <>
bool __ParseString<bool>(const CStr& Value, bool &Output)
2004-05-29 06:06:50 +02:00
{
if (Value == CStr(_T("true")))
Output = true;
else
if (Value == CStr(_T("false")))
Output = false;
else
return false;
return true;
}
template <>
bool __ParseString<int>(const CStr& Value, int &Output)
2004-05-29 06:06:50 +02:00
{
Output = Value.ToInt();
return true;
}
template <>
bool __ParseString<float>(const CStr& Value, float &Output)
2004-05-29 06:06:50 +02:00
{
Output = Value.ToFloat();
return true;
}
template <>
bool __ParseString<CRect>(const CStr& Value, CRect &Output)
2004-05-29 06:06:50 +02:00
{
// Use the parser to parse the values
CParser parser;
parser.InputTaskType("", "_$value_$value_$value_$value_");
string str = (const TCHAR*)Value;
CParserLine line;
line.ParseString(parser, str);
if (!line.m_ParseOK)
{
// Parsing failed
return false;
}
float values[4];
2004-05-29 06:06:50 +02:00
for (int i=0; i<4; ++i)
{
if (!line.GetArgFloat(i, values[i]))
2004-05-29 06:06:50 +02:00
{
// Parsing failed
return false;
}
}
// Finally the rectangle values
Output = CRect(values[0], values[1], values[2], values[3]);
return true;
}
template <>
bool __ParseString<CClientArea>(const CStr& Value, CClientArea &Output)
2004-05-29 06:06:50 +02:00
{
return Output.SetClientArea(Value);
}
template <>
bool __ParseString<CColor>(const CStr& Value, CColor &Output)
2004-05-29 06:06:50 +02:00
{
// Use the parser to parse the values
CParser parser;
parser.InputTaskType("", "_$value_$value_$value_[$value_]");
string str = (const TCHAR*)Value;
CParserLine line;
line.ParseString(parser, str);
if (!line.m_ParseOK)
{
// TODO Gee: Parsing failed
return false;
}
float values[4];
values[3] = 255.f; // default
for (int i=0; i<(int)line.GetArgCount(); ++i)
2004-05-29 06:06:50 +02:00
{
if (!line.GetArgFloat(i, values[i]))
{
// Parsing failed
2004-05-29 06:06:50 +02:00
return false;
}
}
Output.r = values[0]/255.f;
Output.g = values[1]/255.f;
Output.b = values[2]/255.f;
Output.a = values[3]/255.f;
return true;
}
template <>
bool __ParseString<CSize>(const CStr& Value, CSize &Output)
{
// Use the parser to parse the values
CParser parser;
parser.InputTaskType("", "_$value_$value_");
string str = (const TCHAR*)Value;
CParserLine line;
line.ParseString(parser, str);
if (!line.m_ParseOK)
{
// Parsing failed
return false;
}
float x, y;
// x
if (!line.GetArgFloat(0, x))
{
// TODO Gee: Parsing failed
return false;
}
// y
if (!line.GetArgFloat(1, y))
{
// TODO Gee: Parsing failed
return false;
}
Output.cx = x;
Output.cy = y;
return true;
}
template <>
bool __ParseString<EAlign>(const CStr &Value, EAlign &Output)
{
if (Value == (CStr)"left")
Output = EAlign_Left;
else
if (Value == (CStr)"center")
Output = EAlign_Center;
else
if (Value == (CStr)"right")
Output = EAlign_Right;
else
return false;
return true;
}
template <>
bool __ParseString<EVAlign>(const CStr &Value, EVAlign &Output)
{
if (Value == (CStr)"top")
Output = EVAlign_Top;
else
if (Value == (CStr)"center")
Output = EVAlign_Center;
else
if (Value == (CStr)"bottom")
Output = EVAlign_Bottom;
else
return false;
return true;
}
2004-05-29 06:06:50 +02:00
template <>
bool __ParseString<CGUIString>(const CStr& Value, CGUIString &Output)
2004-05-29 06:06:50 +02:00
{
Output.SetValue(Value);
return true;
}
2003-11-24 18:13:37 +01:00
//--------------------------------------------------------
// Help Classes/Structs for the GUI implementation
//--------------------------------------------------------
CClientArea::CClientArea() : pixel(0,0,0,0), percent(0,0,0,0)
{
}
CClientArea::CClientArea(const CStr& Value)
2003-11-24 18:13:37 +01:00
{
SetClientArea(Value);
}
2003-12-01 08:06:55 +01:00
CRect CClientArea::GetClientArea(const CRect &parent) const
2003-11-24 18:13:37 +01:00
{
2003-12-01 08:06:55 +01:00
// If it's a 0 0 100% 100% we need no calculations
if (percent == CRect(0.f,0.f,100.f,100.f) && pixel == CRect(0.f,0.f,0.f,0.f))
2003-12-01 08:06:55 +01:00
return parent;
2003-11-24 18:13:37 +01:00
CRect client;
// This should probably be cached and not calculated all the time for every object.
client.left = parent.left + (parent.right-parent.left)*percent.left/100.f + pixel.left;
client.top = parent.top + (parent.bottom-parent.top)*percent.top/100.f + pixel.top;
client.right = parent.left + (parent.right-parent.left)*percent.right/100.f + pixel.right;
client.bottom = parent.top + (parent.bottom-parent.top)*percent.bottom/100.f + pixel.bottom;
2003-11-24 18:13:37 +01:00
return client;
}
bool CClientArea::SetClientArea(const CStr& Value)
2003-11-24 18:13:37 +01:00
{
// Get value in STL string format
string _Value = (const TCHAR*)Value;
// This might lack incredible speed, but since all XML files
// are read at startup, reading 100 client areas will be
// negligible in the loading time.
// Setup parser to parse the value
CParser parser;
// One of the for values:
// will give outputs like (in argument):
// (200) <== no percent, just the first $value
// (200) (percent) <== just the percent
// (200) (percent) (100) <== percent PLUS pixel
// (200) (percent) (-100) <== percent MINUS pixel
// (200) (percent) (100) (-100) <== Both PLUS and MINUS are used, INVALID
2003-11-25 04:21:11 +01:00
string one_value = "_[-_$arg(_minus)]$value[$arg(percent)%_[+_$value]_[-_$arg(_minus)$value]_]";
2003-11-24 18:13:37 +01:00
string four_values = one_value + "$arg(delim)" +
one_value + "$arg(delim)" +
one_value + "$arg(delim)" +
one_value + "$arg(delim)_"; // it's easier to just end with another delimiter
parser.InputTaskType("ClientArea", four_values);
CParserLine line;
line.ParseString(parser, _Value);
if (!line.m_ParseOK)
return false;
int arg_count[4]; // argument counts for the four values
int arg_start[4] = {0,0,0,0}; // location of first argument, [0] is alwasy 0
// Divide into the four piles (delimiter is an argument named "delim")
for (int i=0, valuenr=0; i<(int)line.GetArgCount(); ++i)
2003-11-24 18:13:37 +01:00
{
string str;
line.GetArgString(i, str);
if (str == "delim")
{
if (valuenr==0)
{
arg_count[0] = i;
arg_start[1] = i+1;
}
else
{
if (valuenr!=3)
{
arg_start[valuenr+1] = i+1;
arg_count[valuenr] = arg_start[valuenr+1] - arg_start[valuenr] - 1;
}
else
arg_count[3] = (int)line.GetArgCount() - arg_start[valuenr] - 1;
2003-11-24 18:13:37 +01:00
}
++valuenr;
}
}
// Iterate argument
// This is the scheme:
// 1 argument = Just pixel value
// 2 arguments = Just percent value
// 3 arguments = percent and pixel
// 4 arguments = INVALID
// Default to 0
float values[4][2] = {{0.f,0.f},{0.f,0.f},{0.f,0.f},{0.f,0.f}};
2003-11-24 18:13:37 +01:00
for (int v=0; v<4; ++v)
{
if (arg_count[v] == 1)
{
string str;
line.GetArgString(arg_start[v], str);
if (!line.GetArgFloat(arg_start[v], values[v][1]))
2003-11-24 18:13:37 +01:00
return false;
}
else
if (arg_count[v] == 2)
{
if (!line.GetArgFloat(arg_start[v], values[v][0]))
2003-11-24 18:13:37 +01:00
return false;
}
else
if (arg_count[v] == 3)
{
if (!line.GetArgFloat(arg_start[v], values[v][0]) ||
!line.GetArgFloat(arg_start[v]+2, values[v][1]))
2003-11-24 18:13:37 +01:00
return false;
}
else return false;
}
// Now store the values[][] in the right place
pixel.left = values[0][1];
pixel.top = values[1][1];
pixel.right = values[2][1];
pixel.bottom = values[3][1];
percent.left = values[0][0];
percent.top = values[1][0];
percent.right = values[2][0];
percent.bottom = values[3][0];
2003-11-24 18:13:37 +01:00
return true;
}
//--------------------------------------------------------
// Utilities implementation
//--------------------------------------------------------
IGUIObject * CInternalCGUIAccessorBase::GetObjectPointer(CGUI &GUIinstance, const CStr& Object)
{
// if (!GUIinstance.ObjectExists(Object))
// return NULL;
return GUIinstance.m_pAllObjects.find(Object)->second;
}
const IGUIObject * CInternalCGUIAccessorBase::GetObjectPointer(const CGUI &GUIinstance, const CStr& Object)
{
// if (!GUIinstance.ObjectExists(Object))
// return NULL;
return GUIinstance.m_pAllObjects.find(Object)->second;
2003-11-24 18:13:37 +01:00
}
2003-11-25 04:21:11 +01:00
void CInternalCGUIAccessorBase::QueryResetting(IGUIObject *pObject)
{
2003-12-01 08:06:55 +01:00
GUI<>::RecurseObject(0, pObject, &IGUIObject::ResetStates);
2003-11-25 04:21:11 +01:00
}
2003-12-27 08:23:47 +01:00
void CInternalCGUIAccessorBase::HandleMessage(IGUIObject *pObject, const SGUIMessage &message)
{
pObject->HandleMessage(message);
}
//#ifndef NDEBUG
#define TYPE(T) \
template<> void CheckType<T>(const IGUIObject* obj, const CStr& setting) { \
if (((IGUIObject*)obj)->m_Settings[setting].m_Type != GUIST_##T) \
{ \
debug_warn("EXCESSIVELY FATAL ERROR: Inconsistent types in GUI"); \
throw "EXCESSIVELY FATAL ERROR: Inconsistent types in GUI"; /* TODO: better reporting */ \
} \
}
TYPE(bool)
TYPE(int)
TYPE(float)
TYPE(CClientArea)
TYPE(CStr)
TYPE(CColor)
TYPE(CGUIString)
TYPE(EAlign)
TYPE(EVAlign)
#undef TYPE
//#endif // #ifndef NDEBUG