forked from 0ad/0ad
Start phasing out the use of CParser in the GUI. Makes GUI parsing generally faster and stricter while adding better tests and debug information.
This was SVN commit r15213.
This commit is contained in:
parent
9c908a5f46
commit
5ce12c2263
@ -532,7 +532,7 @@
|
||||
</object>
|
||||
|
||||
<object name="tradeStatistics" size="20 90 100%-20 168">
|
||||
<object name="landTraders" size="0 0 100% 50%" type="text" style="ModernLabelText" text_align="left" ghost="true" />
|
||||
<object name="landTraders" size="0 0 100% 50%" type="text" style="ModernLabelText" text_align="left" ghost="true" />
|
||||
<object name="shipTraders" size="0 50% 100% 100%" type="text" style="ModernLabelText" text_align="left" ghost="true" />
|
||||
</object>
|
||||
|
||||
|
@ -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 <string>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
@ -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<float>(const CStrW& Value, float &Output)
|
||||
template <>
|
||||
bool __ParseString<CRect>(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<CColor>(const CStrW& Value, CColor &Output)
|
||||
template <>
|
||||
bool __ParseString<CSize>(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<CPos>(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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user