diff --git a/binaries/data/mods/public/gui/session/session.xml b/binaries/data/mods/public/gui/session/session.xml
index f7ab18788d..5492bb9810 100644
--- a/binaries/data/mods/public/gui/session/session.xml
+++ b/binaries/data/mods/public/gui/session/session.xml
@@ -532,7 +532,7 @@
diff --git a/source/gui/GUIbase.cpp b/source/gui/GUIbase.cpp
index 2cab7f9df6..3a65bd1193 100644
--- a/source/gui/GUIbase.cpp
+++ b/source/gui/GUIbase.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009 Wildfire Games.
+/* Copyright (C) 2014 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -21,8 +21,7 @@ GUI base
#include "precompiled.h"
-#include
-
+#include "ps/CLogger.h"
#include "GUI.h"
//--------------------------------------------------------
@@ -62,118 +61,86 @@ CRect CClientArea::GetClientArea(const CRect &parent) const
bool CClientArea::SetClientArea(const CStr& 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.
+ /* ClientAreas contain a left, top, right, and bottom
+ * for example: "50%-150 10%+9 50%+150 10%+25" means
+ * the left edge is at 50% minus 150 pixels, the top
+ * edge is at 10% plus 9 pixels, the right edge is at
+ * 50% plus 150 pixels, and the bottom edge is at 10%
+ * plus 25 pixels.
+ * All four coordinates are required and can be
+ * defined only in pixels, only in percents, or some
+ * combination of both.
+ */
- // Setup parser to parse the value
+ // Check the input is only numeric
+ const char* input = Value.c_str();
+ CStr buffer = "";
+ unsigned int coord = 0;
+ float pixels[4] = {0, 0, 0, 0};
+ float percents[4] = {0, 0, 0, 0};
+ for (unsigned int i = 0; i < Value.length(); i++)
+ {
+ switch (input[i])
+ {
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ buffer.push_back(input[i]);
+ break;
+ case '+':
+ pixels[coord] += buffer.ToFloat();
+ buffer = "+";
+ break;
+ case '-':
+ pixels[coord] += buffer.ToFloat();
+ buffer = "-";
+ break;
+ case '%':
+ percents[coord] += buffer.ToFloat();
+ buffer = "";
+ break;
+ case ' ':
+ pixels[coord] += buffer.ToFloat();
+ buffer = "";
+ coord++;
+ break;
+ default:
+ LOGWARNING(L"ClientArea definitions may only contain numerics. Your input: '%s'", Value.c_str());
+ return false;
+ }
+ if (coord > 3)
+ {
+ LOGWARNING(L"Too many CClientArea parameters (4 max). Your input: '%s'", Value.c_str());
+ return false;
+ }
+ }
- // One of the four 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
- /*
- string one_value = "_[-_$arg(_minus)]$value[$arg(percent)%_[+_$value]_[-_$arg(_minus)$value]_]";
- 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
- */
- // Don't use the above strings, because they make this code go very slowly
- const char* four_values =
- "_[-_$arg(_minus)]$value[$arg(percent)%_[+_$value]_[-_$arg(_minus)$value]_]" "$arg(delim)"
- "_[-_$arg(_minus)]$value[$arg(percent)%_[+_$value]_[-_$arg(_minus)$value]_]" "$arg(delim)"
- "_[-_$arg(_minus)]$value[$arg(percent)%_[+_$value]_[-_$arg(_minus)$value]_]" "$arg(delim)"
- "_[-_$arg(_minus)]$value[$arg(percent)%_[+_$value]_[-_$arg(_minus)$value]_]" "$arg(delim)"
- "_";
- CParser& parser (CParserCache::Get(four_values));
-
- CParserLine line;
- line.ParseString(parser, Value);
-
- if (!line.m_ParseOK)
+ if (coord < 3)
+ {
+ LOGWARNING(L"Too few CClientArea parameters (4 min). Your input: '%s'", Value.c_str());
return false;
-
- int arg_count[4] = {0,0,0,0}; // argument counts for the four values
- int arg_start[4] = {0,0,0,0}; // location of first argument, [0] is always 0
-
- // Divide into the four piles (delimiter is an argument named "delim")
- for (int i=0, valuenr=0; i<(int)line.GetArgCount(); ++i)
- {
- std::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)
- {
- ENSURE(valuenr <= 2);
- 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;
- }
-
- ++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
+ // Now that we're at the end of the string, flush the remaining buffer.
+ pixels[coord] += buffer.ToFloat();
- // Default to 0
- float values[4][2] = {{0.f,0.f},{0.f,0.f},{0.f,0.f},{0.f,0.f}};
- for (int v=0; v<4; ++v)
- {
- if (arg_count[v] == 1)
- {
- std::string str;
- line.GetArgString(arg_start[v], str);
-
- if (!line.GetArgFloat(arg_start[v], values[v][1]))
- return false;
- }
- else
- if (arg_count[v] == 2)
- {
- if (!line.GetArgFloat(arg_start[v], values[v][0]))
- 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]))
- 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];
+ // Now store the coords in the right place
+ pixel.left = pixels[0];
+ pixel.top = pixels[1];
+ pixel.right = pixels[2];
+ pixel.bottom = pixels[3];
+ percent.left = percents[0];
+ percent.top = percents[1];
+ percent.right = percents[2];
+ percent.bottom = percents[3];
return true;
}
diff --git a/source/gui/GUIutil.cpp b/source/gui/GUIutil.cpp
index bcee7f250d..c1efceadc3 100644
--- a/source/gui/GUIutil.cpp
+++ b/source/gui/GUIutil.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2012 Wildfire Games.
+/* Copyright (C) 2014 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -23,7 +23,6 @@ GUI utilities
#include "GUI.h"
#include "GUIManager.h"
#include "maths/Matrix3D.h"
-#include "ps/Parser.h"
extern int g_xres, g_yres;
@@ -61,28 +60,35 @@ bool __ParseString(const CStrW& Value, float &Output)
template <>
bool __ParseString(const CStrW& Value, CRect &Output)
{
- // Use the parser to parse the values
- CParser& parser (CParserCache::Get("_$value_$value_$value_$value_"));
-
- CParserLine line;
- line.ParseString(parser, Value.ToUTF8());
- if (!line.m_ParseOK)
+ const unsigned int NUM_COORDS = 4;
+ float coords[NUM_COORDS];
+ std::wstringstream stream;
+ stream.str(Value);
+ // Parse each coordinate
+ for (unsigned int i = 0; i < NUM_COORDS; i++)
{
- // Parsing failed
- return false;
- }
- float values[4];
- for (int i=0; i<4; ++i)
- {
- if (!line.GetArgFloat(i, values[i]))
+ if (stream.eof())
{
- // Parsing failed
+ LOGWARNING(L"Too few CRect parameters (min %i). Your input: '%s'", NUM_COORDS, Value.ToUTF8().c_str());
+ return false;
+ }
+ stream >> coords[i];
+ if ((stream.rdstate() & std::wstringstream::failbit) != 0)
+ {
+ LOGWARNING(L"Unable to parse CRect parameters. Your input: '%s'", Value.ToUTF8().c_str());
return false;
}
}
+ if (!stream.eof())
+ {
+ LOGWARNING(L"Too many CRect parameters (max %i). Your input: '%s'", NUM_COORDS, Value.ToUTF8().c_str());
+ return false;
+ }
+
// Finally the rectangle values
- Output = CRect(values[0], values[1], values[2], values[3]);
+ Output = CRect(coords[0], coords[1], coords[2], coords[3]);
+
return true;
}
@@ -119,57 +125,69 @@ bool __ParseString(const CStrW& Value, CColor &Output)
template <>
bool __ParseString(const CStrW& Value, CSize &Output)
{
- // Use the parser to parse the values
- CParser& parser (CParserCache::Get("_$value_$value_"));
-
- CParserLine line;
- line.ParseString(parser, Value.ToUTF8());
- if (!line.m_ParseOK)
+ const unsigned int NUM_COORDS = 2;
+ float coords[NUM_COORDS];
+ std::wstringstream stream;
+ stream.str(Value);
+ // Parse each coordinate
+ for (unsigned int i = 0; i < NUM_COORDS; i++)
{
- // Parsing failed
+ if (stream.eof())
+ {
+ LOGWARNING(L"Too few CSize parameters (min %i). Your input: '%s'", NUM_COORDS, Value.ToUTF8().c_str());
+ return false;
+ }
+ stream >> coords[i];
+ if ((stream.rdstate() & std::wstringstream::failbit) != 0)
+ {
+ LOGWARNING(L"Unable to parse CSize parameters. Your input: '%s'", Value.ToUTF8().c_str());
+ return false;
+ }
+ }
+
+ Output.cx = coords[0];
+ Output.cy = coords[1];
+
+ if (!stream.eof())
+ {
+ LOGWARNING(L"Too many CSize parameters (max %i). Your input: '%s'", NUM_COORDS, Value.ToUTF8().c_str());
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(const CStrW& Value, CPos &Output)
{
- CParser& parser (CParserCache::Get("_[-$arg(_minus)]$value_[-$arg(_minus)]$value_"));
+ const unsigned int NUM_COORDS = 2;
+ float coords[NUM_COORDS];
+ std::wstringstream stream;
+ stream.str(Value);
+ // Parse each coordinate
+ for (unsigned int i = 0; i < NUM_COORDS; i++)
+ {
+ if (stream.eof())
+ {
+ LOGWARNING(L"Too few CPos parameters (min %i). Your input: '%s'", NUM_COORDS, Value.ToUTF8().c_str());
+ return false;
+ }
+ stream >> coords[i];
+ if ((stream.rdstate() & std::wstringstream::failbit) != 0)
+ {
+ LOGWARNING(L"Unable to parse CPos parameters. Your input: '%s'", Value.ToUTF8().c_str());
+ return false;
+ }
+ }
- CParserLine line;
- line.ParseString(parser, Value.ToUTF8());
- if (!line.m_ParseOK)
- return false;
+ Output.x = coords[0];
+ Output.y = coords[1];
- float x, y;
- if (!line.GetArgFloat(0, x))
+ if (!stream.eof())
+ {
+ LOGWARNING(L"Too many CPos parameters (max %i). Your input: '%s'", NUM_COORDS, Value.ToUTF8().c_str());
return false;
- if (!line.GetArgFloat(1, y))
- return false;
-
- Output.x = x;
- Output.y = y;
+ }
return true;
}
diff --git a/source/gui/GUIutil.h b/source/gui/GUIutil.h
index 448d137e5d..32cd980823 100644
--- a/source/gui/GUIutil.h
+++ b/source/gui/GUIutil.h
@@ -37,7 +37,6 @@ GUI util
// Includes / Compiler directives
//--------------------------------------------------------
#include "GUIbase.h"
-#include "ps/Parser.h"
// TODO Gee: New
#include "ps/Overlay.h"
#include "CGUI.h"
diff --git a/source/gui/IGUIObject.cpp b/source/gui/IGUIObject.cpp
index c280ff86c1..e7de78a35e 100644
--- a/source/gui/IGUIObject.cpp
+++ b/source/gui/IGUIObject.cpp
@@ -22,8 +22,6 @@ IGUIObject
#include "precompiled.h"
#include "GUI.h"
-#include "ps/Parser.h"
-
#include "gui/scripting/JSInterface_IGUIObject.h"
#include "gui/scripting/JSInterface_GUITypes.h"
#include "scriptinterface/ScriptInterface.h"
diff --git a/source/gui/tests/test_ParseString.h b/source/gui/tests/test_ParseString.h
index dbea409981..2e2bd7d64c 100644
--- a/source/gui/tests/test_ParseString.h
+++ b/source/gui/tests/test_ParseString.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 Wildfire Games.
+/* Copyright (C) 2014 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -18,26 +18,87 @@
#include "lib/self_test.h"
#include "gui/GUIbase.h"
+#include "gui/GUIutil.h"
+#include "ps/CLogger.h"
class TestGuiParseString : public CxxTest::TestSuite
{
public:
void test_clientarea()
{
+ TestLogger nolog;
CClientArea ca;
- TS_ASSERT(ca.SetClientArea("0 1 2 3"));
- TS_ASSERT_EQUALS(ca, CClientArea(CRect(0, 1, 2, 3), CRect(0, 0, 0, 0)));
- TS_ASSERT(ca.SetClientArea("5% 10%+1 20%-2 3"));
- TS_ASSERT_EQUALS(ca, CClientArea(CRect(0, 1, -2, 3), CRect(5, 10, 20, 0)));
+ // Test only pixels
+ TS_ASSERT(ca.SetClientArea("0.0 -10 20.0 -30"));
+ TS_ASSERT_EQUALS(ca, CClientArea(CRect(0, -10, 20, -30), CRect(0, 0, 0, 0)));
- TS_ASSERT(!ca.SetClientArea("0+5% 1 2 3"));
+ // Test only pixels, but with math
+ TS_ASSERT(ca.SetClientArea("0 -100-10+100 20+200-200 -30"));
+ TS_ASSERT_EQUALS(ca, CClientArea(CRect(0, -10, 20, -30), CRect(0, 0, 0, 0)));
- TS_ASSERT(!ca.SetClientArea("5%+10-10 1 2 3"));
+ // Test only percent
+ TS_ASSERT(ca.SetClientArea("-5% 10.0% -20% 30.0%"));
+ TS_ASSERT_EQUALS(ca, CClientArea(CRect(0, 0, 0, 0), CRect(-5, 10, -20, 30)));
- TS_ASSERT(ca.SetClientArea("5% 10%-1 -20%-2 3"));
- TS_ASSERT_EQUALS(ca, CClientArea(CRect(0, -1, -2, 3), CRect(5, 10, -20, 0)));
+ // Test only percent, but with math
+ TS_ASSERT(ca.SetClientArea("15%-5%-15% 10% -20% 30%+500%-500%"));
+ TS_ASSERT_EQUALS(ca, CClientArea(CRect(0, 0, 0, 0), CRect(-5, 10, -20, 30)));
- TS_ASSERT(!ca.SetClientArea("5% 10%+1 -20%-2 3")); // parser bug
+ // Test mixed
+ TS_ASSERT(ca.SetClientArea("5% -10 -20% 30"));
+ TS_ASSERT_EQUALS(ca, CClientArea(CRect(0, -10, 0, 30), CRect(5, 0, -20, 0)));
+
+ // Test mixed with math
+ TS_ASSERT(ca.SetClientArea("5%+10%-10% 30%-10-30% 50-20%-50 30-100+100"));
+ TS_ASSERT_EQUALS(ca, CClientArea(CRect(0, -10, 0, 30), CRect(5, 0, -20, 0)));
+
+ // Test for fail with too many/few parameters
+ TS_ASSERT(!ca.SetClientArea("10 20 30 40 50"));
+ TS_ASSERT(!ca.SetClientArea("10 20 30"));
+
+ // Test for fail with garbage data
+ TS_ASSERT(!ca.SetClientArea("Hello world!"));
+ TS_ASSERT(!ca.SetClientArea("abc 123 xyz 789"));
+ TS_ASSERT(!ca.SetClientArea("300 wide, 400 high"));
+ }
+
+ void test_rect()
+ {
+ TestLogger nolog;
+ CRect test;
+
+ TS_ASSERT(__ParseString(CStrW(L"0.0 10.0 20.0 30.0"), test));
+ TS_ASSERT_EQUALS(CRect(0.0, 10.0, 20.0, 30.0), test);
+
+ TS_ASSERT(!__ParseString(CStrW(L"0 10 20"), test));
+ TS_ASSERT(!__ParseString(CStrW(L"0 10 20 30 40"), test));
+ TS_ASSERT(!__ParseString(CStrW(L"0,0 10,0 20,0 30,0"), test));
+ }
+
+ void test_size()
+ {
+ TestLogger nolog;
+ CSize test;
+
+ TS_ASSERT(__ParseString(CStrW(L"0.0 10.0"), test));
+ TS_ASSERT_EQUALS(CSize(0.0, 10.0), test);
+
+ TS_ASSERT(!__ParseString(CStrW(L"0"), test));
+ TS_ASSERT(!__ParseString(CStrW(L"0 10 20"), test));
+ TS_ASSERT(!__ParseString(CStrW(L"0,0 10,0"), test));
+ }
+
+ void test_pos()
+ {
+ TestLogger nolog;
+ CPos test;
+
+ TS_ASSERT(__ParseString(CStrW(L"0.0 10.0"), test));
+ TS_ASSERT_EQUALS(CPos(0.0, 10.0), test);
+
+ TS_ASSERT(!__ParseString(CStrW(L"0"), test));
+ TS_ASSERT(!__ParseString(CStrW(L"0 10 20"), test));
+ TS_ASSERT(!__ParseString(CStrW(L"0,0 10,0"), test));
}
};