More unit tests for new code

0.8
Bruno Van de Velde 2015-07-27 11:38:15 +02:00
parent 1349212e69
commit 807d3e28c3
43 changed files with 1304 additions and 128 deletions

View File

@ -34,7 +34,7 @@ before_script:
script:
- cd build_gcc-5.1
- export CXX="g++-5"
- cmake -DTGUI_BUILD_EXAMPLES=TRUE -DTGUI_BUILD_TESTS=TRUE .. && make && ./tests/tests
- cmake -DTGUI_BUILD_EXAMPLES=TRUE -DTGUI_BUILD_TESTS=TRUE .. && make && (cd tests/ && ./tests ; cd ..)
- cd ../build_gcc-4.7
- export CXX="g++-4.7"
- cmake .. && make

View File

@ -45,6 +45,13 @@ else()
tgui_set_option(TGUI_BUILD_EXAMPLES FALSE BOOL "TRUE to build the TGUI examples, FALSE to ignore them")
endif()
# Add option to build the tests on linux
if(SFML_OS_IOS OR SFML_OS_ANDROID)
set(TGUI_BUILD_TESTS FALSE)
else()
tgui_set_option(TGUI_BUILD_TESTS FALSE BOOL "TRUE to build the TGUI tests (requires c++14)")
endif()
# Add an option for choosing the OpenGL implementation
tgui_set_option(TGUI_OPENGL_ES ${OPENGL_ES} BOOL "TRUE to use an OpenGL ES implementation, FALSE to use a desktop OpenGL implementation")
@ -89,28 +96,19 @@ if (SFML_OS_ANDROID)
set(CMAKE_CXX_FLAGS "${TGUI_TEMP_CXX_FLAGS}")
elseif(SFML_COMPILER_GCC)
elseif(SFML_COMPILER_GCC OR SFML_COMPILER_CLANG)
if (NOT CMAKE_CXX_FLAGS)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wshadow -Wno-long-long -pedantic -std=c++11" CACHE STRING "C++ compiler flags" FORCE)
set(CMAKE_C_FLAGS "-Wall -Wextra -Wshadow -Wno-long-long -pedantic" CACHE STRING "C compiler flags" FORCE)
endif()
elseif (SFML_COMPILER_CLANG)
if (NOT CMAKE_CXX_FLAGS)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wshadow -Wno-long-long -pedantic -std=c++11" CACHE STRING "C++ compiler flags" FORCE)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wshadow -Wno-long-long -pedantic -std=c++11" CACHE STRING "C compiler flags" FORCE)
set(CMAKE_C_FLAGS "-Wall -Wextra -Wshadow -Wno-long-long -pedantic" CACHE STRING "C compiler flags" FORCE)
# On mac, clang needs another parameter
if (SFML_OS_MACOSX)
if (SFML_COMPILER_CLANG AND SFML_OS_MACOSX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++" CACHE STRING "C++ compiler flags" FORCE)
endif()
endif()
endif()
# Define an option for choosing between static and dynamic C runtime (VC++ only)
if (SFML_OS_WINDOWS)
tgui_set_option(TGUI_USE_STATIC_STD_LIBS FALSE BOOL "TRUE to statically link to the standard libraries, FALSE to use them as DLLs. This option has to match with the one from sfml.")

View File

@ -45,6 +45,7 @@ namespace tgui
static ObjectConverter deserialize(ObjectConverter::Type type, const std::string& serializedString);
static void setFunction(ObjectConverter::Type type, const DeserializeFunc& deserializer);
static const DeserializeFunc& getFunction(ObjectConverter::Type type);
private:
static std::map<ObjectConverter::Type, DeserializeFunc> m_deserializers;

View File

@ -40,25 +40,18 @@ namespace tgui
class TGUI_API Serializer
{
public:
using SerializeFunc = std::function<std::string(const ObjectConverter&)>;
using SerializeFunc = std::function<std::string(ObjectConverter&&)>;
static std::string serialize(const ObjectConverter& object);
static std::string serialize(ObjectConverter&& object);
static void setFunction(ObjectConverter::Type type, const SerializeFunc& deserializer);
static void setFunction(ObjectConverter::Type type, const SerializeFunc& serializer);
static const SerializeFunc& getFunction(ObjectConverter::Type type);
private:
static std::map<ObjectConverter::Type, SerializeFunc> m_serializers;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// TODO: Documentation
TGUI_API std::string serializeFont(const ObjectConverter& value);
TGUI_API std::string serializeColor(const ObjectConverter& value);
TGUI_API std::string serializeBorders(const ObjectConverter& value);
TGUI_API std::string serializeTexture(const ObjectConverter& value);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -51,10 +51,15 @@ namespace tgui
/// TODO: Documentation
/// @internal
virtual void widgetAttached(Widget* widget);
/// TODO: Documentation
/// @internal
virtual void widgetDetached(Widget* widget);
/// TODO: Documentation
/// @internal
virtual void initWidget(Widget* widget, std::string primary, std::string secondary) = 0;
@ -100,11 +105,17 @@ namespace tgui
class TGUI_API Theme : public BaseTheme
{
public:
typedef std::shared_ptr<Theme> Ptr; ///< Shared theme pointer
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Construct the theme class, with an optional theme file to load
///
/// @param filename Filename of the theme file
///
/// @warning The theme has to be used as a std::shared_ptr<Theme> since it will be shared with the widget that it loads.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Theme(const std::string& filename = "");
@ -128,21 +139,16 @@ namespace tgui
void reload(Widget::Ptr widget, std::string className);
void setProperty(std::string className, const std::string& property, const std::string& value);
void setProperty(std::string className, const std::string& property, ObjectConverter&& value);
/// @internal
virtual void widgetDetached(Widget* widget) override;
/// @internal
virtual void initWidget(Widget* widget, std::string filename, std::string className) override;
template <typename T>
void setProperty(std::string className, const std::string& property, const T& value)
{
className = toLower(className);
for (auto& pair : m_widgets)
{
if (pair.second == className)
pair.first->getRenderer()->setProperty(property, value);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private:
@ -151,6 +157,8 @@ namespace tgui
std::map<Widget*, std::string> m_widgets; // Map widget to class name
std::map<std::string, std::string> m_widgetTypes; // Map class name to type
std::map<std::string, std::map<std::string, std::string>> m_widgetProperties; // Map class name to property-value pairs
friend class ThemeTest;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -121,6 +121,8 @@ namespace tgui
private:
static std::map<std::string, std::map<std::string, std::map<std::string, std::string>>> m_propertiesCache;
static std::map<std::string, std::map<std::string, std::string>> m_widgetTypeCache;
friend class DefaultThemeLoaderTest;
};

View File

@ -54,10 +54,19 @@ namespace tgui
template <typename T>
std::string convertTypeToString();
/// @internal
template <> inline std::string convertTypeToString<int>() { return "int"; }
/// @internal
template <> inline std::string convertTypeToString<sf::Vector2f>() { return "sf::Vector2f"; }
/// @internal
template <> inline std::string convertTypeToString<sf::String>() { return "sf::String"; }
/// @internal
template <> inline std::string convertTypeToString<std::vector<sf::String>>() { return "std::vector<sf::String>"; }
/// @internal
template <> inline std::string convertTypeToString<std::shared_ptr<ChildWindow>>() { return "std::shared_ptr<ChildWindow>"; }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -70,6 +79,7 @@ namespace tgui
static std::vector<std::string> getRow() { return {}; }
};
/// @internal
template <typename Type>
struct extractTypes<Type>
{
@ -77,6 +87,7 @@ namespace tgui
static std::vector<std::string> getRow() { return {convertTypeToString<Type>()}; }
};
/// @internal
template <typename Type, typename... OtherTypes>
struct extractTypes<Type, OtherTypes...>
{
@ -95,12 +106,14 @@ namespace tgui
}
};
/// @internal
template <typename... T>
struct extractTypes<TypeSet<T...>>
{
static std::vector<std::vector<std::string>> get() { return {extractTypes<T...>::getRow()}; }
};
/// @internal
template <typename... T, typename... U>
struct extractTypes<TypeSet<T...>, U...>
{
@ -118,12 +131,14 @@ namespace tgui
template <typename Func, typename TypeA, typename TypeB, typename... Args>
struct isConvertible;
/// @internal
template <typename Func, typename... TypesA, typename... TypesB, typename... Args>
struct isConvertible<Func, TypeSet<TypesA...>, TypeSet<TypesB...>, Args...>
{
using type = typename std::conditional<std::is_convertible<Func, std::function<void(Args..., TypesA...)>>::value, TypeSet<TypesA...>, TypeSet<TypesB...>>::type;
};
/// @internal
template <typename Func, typename... Type>
struct isConvertible<Func, TypeSet<>, TypeSet<Type...>>
{

View File

@ -148,22 +148,22 @@ namespace tgui
std::string getId() const;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Returns the constant texture data.
///
/// @return Read-only data of the texture
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const TextureData* getData() const;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Returns the texture data.
///
/// @return Data of the texture
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TextureData* getData();
std::shared_ptr<TextureData>& getData();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Returns the constant texture data.
///
/// @return Read-only data of the texture
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::shared_ptr<const TextureData> getData() const;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -288,7 +288,7 @@ namespace tgui
/// This function can be useful when implementing a resource manager.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setCopyCallback(const std::function<void(const TextureData*)>& func);
void setCopyCallback(const std::function<void(std::shared_ptr<TextureData>)>& func);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -299,7 +299,7 @@ namespace tgui
/// This function can be useful when implementing a resource manager.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setDestructCallback(const std::function<void(const TextureData*)>& func);
void setDestructCallback(const std::function<void(std::shared_ptr<TextureData>)>& func);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -397,8 +397,8 @@ namespace tgui
float m_rotation = 0;
std::string m_id;
std::function<void(const TextureData*)> m_copyCallback;
std::function<void(const TextureData*)> m_destructCallback;
std::function<void(std::shared_ptr<TextureData>)> m_copyCallback;
std::function<void(std::shared_ptr<TextureData>)> m_destructCallback;
static TextureLoaderFunc m_textureLoader;
static ImageLoaderFunc m_imageLoader;
};

View File

@ -56,7 +56,7 @@ namespace tgui
// Wrapper around TextureData to be used in TextureManager
struct TGUI_API TextureDataHolder
{
TextureData* data = nullptr;
std::shared_ptr<TextureData> data;
std::string filename;
unsigned int users;
};

View File

@ -67,7 +67,7 @@ namespace tgui
/// @param textureDataToCopy The original texture data that will now be reused.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void copyTexture(const TextureData* textureToCopy);
static void copyTexture(std::shared_ptr<TextureData> textureToCopy);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -78,7 +78,7 @@ namespace tgui
/// When no other texture is using the same image then the image will be removed from memory.
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void removeTexture(const TextureData* textureDataToRemove);
static void removeTexture(std::shared_ptr<TextureData> textureDataToRemove);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -594,6 +594,7 @@ namespace tgui
virtual bool setProperty(std::string property, const std::string& value);
virtual bool setProperty(std::string property, ObjectConverter&& value);
virtual ObjectConverter getProperty(std::string property) const;
virtual std::vector<std::pair<std::string, ObjectConverter>> getPropertyValuePairs() const;

View File

@ -259,6 +259,7 @@ namespace tgui
virtual bool setProperty(std::string property, const std::string& value) override;
virtual bool setProperty(std::string property, ObjectConverter&& value) override;
virtual ObjectConverter getProperty(std::string property) const override;
virtual std::vector<std::pair<std::string, ObjectConverter>> getPropertyValuePairs() const override;

View File

@ -1,5 +1,33 @@
# TODO Change to file list again (to avoid problems with caching)
file(GLOB TGUI_SRC "*.cpp" "extra/*.cpp")
# TODO: Make sure all files are listed
set(TGUI_SRC
Clipboard.cpp
Container.cpp
Global.cpp
Gui.cpp
Layout.cpp
Signal.cpp
Texture.cpp
TextureManager.cpp
ThemeFileParser.cpp
Transformable.cpp
Widget.cpp
Loading/DataIO.cpp
Loading/Deserializer.cpp
Loading/ObjectConverter.cpp
Loading/Serializer.cpp
Loading/Theme.cpp
Loading/ThemeLoader.cpp
Loading/WidgetConverter.cpp
Loading/WidgetLoader.cpp
Loading/WidgetSaver.cpp
Widgets/Button.cpp
Widgets/ClickableWidget.cpp
Widgets/EditBox.cpp
Widgets/Label.cpp
Widgets/Panel.cpp
Widgets/Picture.cpp
Widgets/Tooltip.cpp
)
# Determine library suffixes depending on static/shared configuration
if(TGUI_SHARED_LIBS)

View File

@ -23,7 +23,11 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <TGUI/TGUI.hpp>
#include <TGUI/Container.hpp>
#include <TGUI/Widgets/Tooltip.hpp>
#include <TGUI/Widgets/RadioButton.hpp>
#include <TGUI/Loading/WidgetSaver.hpp>
#include <TGUI/Loading/WidgetLoader.hpp>
#include <stack>
#include <cassert>

View File

@ -30,6 +30,8 @@
namespace
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
unsigned char hexToDec(char c)
{
if (c >= '0' && c <= '9')
@ -49,6 +51,8 @@ namespace
else
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool readIntRect(std::string value, sf::IntRect& rect)
{
@ -85,6 +89,11 @@ namespace
// Get the width value and delete this part of the string
rect.width = tgui::stoi(value.substr(0, commaPos));
value.erase(0, commaPos+1);
// There should be no commas in the string
commaPos = value.find(',');
if (commaPos != std::string::npos)
return false;
// Get the height value
rect.height = tgui::stoi(value);
@ -98,6 +107,8 @@ namespace
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
// Hidden functions
@ -164,10 +175,10 @@ namespace tgui
}
// The string can optionally start with "rgb" or "rgba", but this is ignored
if (string.substr(0, 3) == "rgb")
string.erase(0, 3);
else if (string.substr(0, 4) == "rgba")
if (string.substr(0, 4) == "rgba")
string.erase(0, 4);
else if (string.substr(0, 3) == "rgb")
string.erase(0, 3);
// Remove the first and last characters when they are brackets
if ((string[0] == '(') && (string[string.length()-1] == ')'))
@ -200,6 +211,11 @@ namespace tgui
color.b = tgui::stoi(string.substr(0, commaPos));
string.erase(0, commaPos+1);
// There should be no commas in the string
commaPos = string.find(',');
if (commaPos != std::string::npos)
throw Exception{"Failed to deserialize color '" + value + "'."};
// Get the alpha value
color.a = tgui::stoi(string);
}
@ -221,11 +237,28 @@ namespace tgui
TGUI_API ObjectConverter deserializeString(const std::string& value)
{
/// TODO: When no quotes around it then just return it, otherwise remove quotes and replace stuff like \n in the string
// Only deserialize the string when it is surrounded with quotes
if (!value.empty() && ((value[0] == '"') && (value[value.length()-1] == '"')))
{
std::string result = value.substr(1, value.length()-2);
std::size_t backslashPos = 0;
while ((backslashPos = result.find('\\', backslashPos)) < result.size()-1)
{
result.erase(backslashPos, 1);
// Remove the first and last characters when they are quotes
if (!value.empty() || ((value[0] == '"') && (value[value.length()-1] == '"')))
return {sf::String{value.substr(1, value.length()-2)}};
if (result[backslashPos] == 'n')
result[backslashPos] = '\n';
else if (result[backslashPos] == 't')
result[backslashPos] = '\t';
else if (result[backslashPos] == 'v')
result[backslashPos] = '\v';
backslashPos++;
}
return {sf::String{result}};
}
else
return {sf::String{value}};
}
@ -271,6 +304,11 @@ namespace tgui
borders.right = tgui::stof(string.substr(0, commaPos));
string.erase(0, commaPos+1);
// There should be no commas in the string
commaPos = string.find(',');
if (commaPos != std::string::npos)
throw Exception{"Failed to deserialize color '" + value + "'."};
// Get the fourth value
borders.bottom = tgui::stof(string);
@ -415,6 +453,13 @@ namespace tgui
{
m_deserializers[type] = deserializer;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const Deserializer::DeserializeFunc& Deserializer::getFunction(ObjectConverter::Type type)
{
return m_deserializers[type];
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

View File

@ -27,41 +27,19 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Hidden functions
namespace tgui
{
std::map<ObjectConverter::Type, Serializer::SerializeFunc> Serializer::m_serializers =
{
{ObjectConverter::Type::Font, serializeFont},
{ObjectConverter::Type::Color, serializeColor},
{ObjectConverter::Type::Borders, serializeBorders},
{ObjectConverter::Type::Texture, serializeTexture}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::string Serializer::serialize(const ObjectConverter& object)
{
return m_serializers[object.getType()](object);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Serializer::setFunction(ObjectConverter::Type type, const SerializeFunc& serializer)
{
m_serializers[type] = serializer;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::string serializeFont(const ObjectConverter& /*value*/)
std::string serializeFont(ObjectConverter&& /*value*/)
{
return "FONT_PLACEHOLDER"; /// TODO: Support deserializing fonts
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::string serializeColor(const ObjectConverter& value)
std::string serializeColor(ObjectConverter&& value)
{
sf::Color color = value.getColor();
if (color.a < 255)
@ -72,7 +50,7 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::string serializeBorders(const ObjectConverter& value)
std::string serializeBorders(ObjectConverter&& value)
{
Borders borders = value.getBorders();
return "(" + std::to_string(static_cast<unsigned int>(borders.left)) + ", " + std::to_string(static_cast<unsigned int>(borders.top))
@ -81,7 +59,7 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::string serializeTexture(const ObjectConverter& value)
std::string serializeTexture(ObjectConverter&& value)
{
Texture texture = value.getTexture();
std::string result = "\"" + texture.getId() + "\"";
@ -97,14 +75,75 @@ namespace tgui
+ ", " + tgui::to_string(texture.getMiddleRect().width) + ", " + tgui::to_string(texture.getMiddleRect().height) + ")";
}
if (texture.getData()->texture.isRepeated())
result += "Repeat";
result += " Repeat";
return result;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// TODO: Add serializeString to add quotes around string and to replace stuff like \n in the string
std::string serializeString(ObjectConverter&& value)
{
std::string result = value.getString();
auto replace = [&](char from, char to)
{
std::size_t pos = 0;
while ((pos = result.find(from, pos)) != std::string::npos)
{
result[pos] = to;
result.insert(pos, 1, '\\');
pos += 2;
}
};
replace('\\', '\\');
replace('\"', '\"');
replace('\v', 'v');
replace('\t', 't');
replace('\n', 'n');
return "\"" + result + "\"";
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
namespace tgui
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::map<ObjectConverter::Type, Serializer::SerializeFunc> Serializer::m_serializers =
{
{ObjectConverter::Type::Font, serializeFont},
{ObjectConverter::Type::Color, serializeColor},
{ObjectConverter::Type::String, serializeString},
{ObjectConverter::Type::Borders, serializeBorders},
{ObjectConverter::Type::Texture, serializeTexture}
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::string Serializer::serialize(ObjectConverter&& object)
{
return m_serializers[object.getType()](std::move(object));
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Serializer::setFunction(ObjectConverter::Type type, const SerializeFunc& serializer)
{
m_serializers[type] = serializer;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const Serializer::SerializeFunc& Serializer::getFunction(ObjectConverter::Type type)
{
return m_serializers[type];
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -24,6 +24,7 @@
#include <TGUI/Loading/Theme.hpp>
#include <TGUI/Loading/Serializer.hpp>
#include <TGUI/Widgets/Button.hpp>
#include <TGUI/Widgets/Label.hpp>
#include <TGUI/Widgets/EditBox.hpp>
@ -145,14 +146,18 @@ namespace tgui
for (auto& widget : m_widgets)
{
std::string widgetType;
if (m_filename != "")
{
if (m_widgetTypes.find(widget.second) == m_widgetTypes.end())
{
std::string widgetType = toLower(m_themeLoader->load(m_filename, widget.second, m_widgetProperties[widget.second]));
}
if (m_widgetTypes.find(widget.second) != m_widgetTypes.end())
widgetType = m_widgetTypes[widget.second];
else
widgetType = toLower(m_themeLoader->load(m_filename, widget.second, m_widgetProperties[widget.second]));
}
else
widgetType = widget.second;
m_widgetTypes[widget.second] = widgetType;
widgetReload(widget.first, filename, widget.second);
}
}
@ -206,6 +211,8 @@ namespace tgui
widgetAttached(widget.get());
widgetReload(widget.get(), m_filename, className);
m_widgetTypes[className] = widgetType;
m_widgets[widget.get()] = className;
}
@ -217,6 +224,34 @@ namespace tgui
if (it != m_widgets.end())
m_widgets.erase(it);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Theme::setProperty(std::string className, const std::string& property, const std::string& value)
{
className = toLower(className);
m_widgetProperties[className][toLower(property)] = value;
for (auto& pair : m_widgets)
{
if (pair.second == className)
pair.first->getRenderer()->setProperty(property, value);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Theme::setProperty(std::string className, const std::string& property, ObjectConverter&& value)
{
className = toLower(className);
m_widgetProperties[className][toLower(property)] = Serializer::serialize(std::move(value));
for (auto& pair : m_widgets)
{
if (pair.second == className)
pair.first->getRenderer()->setProperty(property, std::move(value));
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -245,13 +280,6 @@ namespace tgui
setResourcePath(oldResourcePath);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
void Theme::setLoader(const std::string& type, const LoaderFuncType& loader)
{
m_loaders[toLower(type)] = loader;
}
*/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

View File

@ -66,7 +66,7 @@ namespace tgui
std::string DefaultThemeLoader::load(const std::string& filename, const std::string& className, std::map<std::string, std::string>& propertyValuePair)
{
/// TODO: Allow comments
/// TODO: Allow comments (#, // and /*)
std::string lowercaseClassName = toLower(className);
@ -96,7 +96,7 @@ namespace tgui
for (auto& pair : child->propertyValuePairs)
{
m_propertiesCache[filename][parsedClassName][pair.first] = pair.second->value;
m_propertiesCache[filename][parsedClassName][toLower(pair.first)] = pair.second->value;
m_widgetTypeCache[filename][parsedClassName] = widgetType;
}
}

View File

@ -64,7 +64,7 @@ namespace tgui
node->children.emplace_back(std::make_shared<DataIO::Node>());
node->children.back()->name = "Renderer";
for (auto& pair : widget->getRenderer()->getPropertyValuePairs())
node->children.back()->propertyValuePairs[pair.first] = std::make_shared<DataIO::ValueNode>(node->children.back().get(), Serializer::serialize(pair.second));
node->children.back()->propertyValuePairs[pair.first] = std::make_shared<DataIO::ValueNode>(node->children.back().get(), Serializer::serialize(std::move(pair.second)));
}
return node;

View File

@ -90,15 +90,17 @@ namespace tgui
sf::Transformable::operator=(right);
sf::Drawable::operator=(right);
std::swap(m_data, temp.m_data);
std::swap(m_vertices, temp.m_vertices);
std::swap(m_size, temp.m_size);
std::swap(m_middleRect, temp.m_middleRect);
std::swap(m_textureRect, temp.m_textureRect);
std::swap(m_scalingType, temp.m_scalingType);
std::swap(m_loaded, temp.m_loaded);
std::swap(m_rotation, temp.m_rotation);
std::swap(m_id, temp.m_id);
std::swap(m_data, temp.m_data);
std::swap(m_vertices, temp.m_vertices);
std::swap(m_size, temp.m_size);
std::swap(m_middleRect, temp.m_middleRect);
std::swap(m_textureRect, temp.m_textureRect);
std::swap(m_scalingType, temp.m_scalingType);
std::swap(m_loaded, temp.m_loaded);
std::swap(m_rotation, temp.m_rotation);
std::swap(m_id, temp.m_id);
std::swap(m_copyCallback, temp.m_copyCallback);
std::swap(m_destructCallback, temp.m_destructCallback);
}
return *this;
@ -108,6 +110,9 @@ namespace tgui
void Texture::load(const sf::String& id, const sf::IntRect& partRect, const sf::IntRect& middleRect, bool repeated)
{
if (m_loaded && (m_destructCallback != nullptr))
m_destructCallback(getData());
m_loaded = false;
if (!m_textureLoader(*this, id, partRect))
throw Exception{"Failed to load " + id};
@ -121,6 +126,9 @@ namespace tgui
void Texture::setTexture(std::shared_ptr<TextureData> data, const sf::IntRect& middleRect)
{
if (m_loaded && (m_destructCallback != nullptr))
m_destructCallback(getData());
m_data = data;
m_loaded = true;
@ -141,16 +149,16 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const TextureData* Texture::getData() const
std::shared_ptr<TextureData>& Texture::getData()
{
return m_data.get();
return m_data;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TextureData* Texture::getData()
std::shared_ptr<const TextureData> Texture::getData() const
{
return m_data.get();
return m_data;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -187,14 +195,14 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Texture::setCopyCallback(const std::function<void(const TextureData*)>& func)
void Texture::setCopyCallback(const std::function<void(std::shared_ptr<TextureData>)>& func)
{
m_copyCallback = func;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Texture::setDestructCallback(const std::function<void(const TextureData*)>& func)
void Texture::setDestructCallback(const std::function<void(std::shared_ptr<TextureData>)>& func)
{
m_destructCallback = func;
}

View File

@ -50,7 +50,11 @@ namespace tgui
// The texture is now used at multiple places
++(dataIt->users);
*texture.getData() = *dataIt->data;
texture.getData() = dataIt->data;
// Let the texture alert the texture manager when it is being copied or destroyed
texture.setCopyCallback(&TextureManager::copyTexture);
texture.setDestructCallback(&TextureManager::removeTexture);
return true;
}
}
@ -91,7 +95,7 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TextureManager::copyTexture(const TextureData* textureDataToCopy)
void TextureManager::copyTexture(std::shared_ptr<TextureData> textureDataToCopy)
{
// Loop all our textures to check if we already have this one
for (auto& dataHolder : m_imageMap)
@ -113,7 +117,7 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TextureManager::removeTexture(const TextureData* textureDataToRemove)
void TextureManager::removeTexture(std::shared_ptr<TextureData> textureDataToRemove)
{
// Loop all our textures to check which one it is
for (auto imageIt = m_imageMap.begin(); imageIt != m_imageMap.end(); ++imageIt)

View File

@ -421,6 +421,13 @@ namespace tgui
{
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ObjectConverter WidgetRenderer::getProperty(std::string) const
{
return {};
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -393,6 +393,46 @@ namespace tgui
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ObjectConverter ButtonRenderer::getProperty(std::string property) const
{
property = toLower(property);
if (property == "font")
return m_button->m_font;
else if (property == "borders")
return m_borders;
else if (property == "textcolor")
return m_textColorNormal;
else if (property == "textcolornormal")
return m_textColorNormal;
else if (property == "textcolorhover")
return m_textColorHover;
else if (property == "textcolordown")
return m_textColorDown;
else if (property == "backgroundcolor")
return m_backgroundColorNormal;
else if (property == "backgroundcolornormal")
return m_backgroundColorNormal;
else if (property == "backgroundcolorhover")
return m_backgroundColorHover;
else if (property == "backgroundcolordown")
return m_backgroundColorDown;
else if (property == "bordercolor")
return m_borderColor;
else if (property == "normalimage")
return m_textureNormal;
else if (property == "hoverimage")
return m_textureHover;
else if (property == "downimage")
return m_textureDown;
else if (property == "focusedimage")
return m_textureFocused;
else
return WidgetRenderer::getProperty(property);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -25,7 +25,7 @@
#include <SFML/OpenGL.hpp>
#include <TGUI/Panel.hpp>
#include <TGUI/Widgets/Panel.hpp>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -1,12 +1,21 @@
set(TEST_SOURCES
main.cpp
Layouts.cpp
Loading/Serializer.cpp
Loading/Deserializer.cpp
Loading/Theme.cpp
Loading/ThemeLoader.cpp
)
# The tests require c++14
if(SFML_COMPILER_GCC OR SFML_COMPILER_CLANG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
endif()
add_executable(tests ${TEST_SOURCES})
target_link_libraries(tests ${PROJECT_NAME} ${TGUI_EXT_LIBS})
# for gcc >= 4.0 on Windows, apply the SFML_USE_STATIC_STD_LIBS option if it is enabled
# For gcc >= 4.0 on Windows, apply the SFML_USE_STATIC_STD_LIBS option if it is enabled
if(SFML_OS_WINDOWS AND SFML_COMPILER_GCC AND NOT SFML_GCC_VERSION VERSION_LESS "4")
if(SFML_USE_STATIC_STD_LIBS AND NOT SFML_COMPILER_GCC_TDM)
set_target_properties(tests PROPERTIES LINK_FLAGS "-static-libgcc -static-libstdc++")
@ -15,12 +24,17 @@ if(SFML_OS_WINDOWS AND SFML_COMPILER_GCC AND NOT SFML_GCC_VERSION VERSION_LESS "
endif()
endif()
# Copy the resources folder to the build directory to execute the tests without installing them
add_custom_command(TARGET tests
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/tests/resources $<TARGET_FILE_DIR:tests>/resources)
# Add the install rule for the executable
install(TARGETS tests
RUNTIME DESTINATION ${INSTALL_MISC_DIR}/tests/tests COMPONENT tests
BUNDLE DESTINATION ${INSTALL_MISC_DIR}/tests/tests COMPONENT tests)
RUNTIME DESTINATION ${INSTALL_MISC_DIR}/tests/ COMPONENT tests
BUNDLE DESTINATION ${INSTALL_MISC_DIR}/tests/ COMPONENT tests)
# install the examples
# Install the tests
install(DIRECTORY "${CMAKE_SOURCE_DIR}/tests/"
DESTINATION "${INSTALL_MISC_DIR}/tests/"
COMPONENT tests)

View File

@ -1,3 +1,27 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus's Graphical User Interface
// Copyright (C) 2012-2015 Bruno Van de Velde (vdv_b@tgui.eu)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "catch.hpp"
#include <TGUI/TGUI.hpp>

View File

@ -0,0 +1,129 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus's Graphical User Interface
// Copyright (C) 2012-2015 Bruno Van de Velde (vdv_b@tgui.eu)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "../catch.hpp"
#include <TGUI/Loading/Deserializer.hpp>
using Type = tgui::ObjectConverter::Type;
TEST_CASE("[Deserializer]") {
SECTION("deserialize font") {
/*
std::shared_ptr<sf::Font> font;
font = tgui::Deserializer::deserialize(tgui::ObjectConverter::Type::Font, "resources/DroidSansArmenian.ttf"
*/
}
SECTION("deserialize color") {
REQUIRE(tgui::Deserializer::deserialize(Type::Color, ",,").getColor() == sf::Color(0, 0, 0));
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "10, 20, 30").getColor() == sf::Color(10, 20, 30));
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "40, 50, 60, 70").getColor() == sf::Color(40, 50, 60, 70));
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "(80, 90, 100)").getColor() == sf::Color(80, 90, 100));
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "(110, 120, 130, 140)").getColor() == sf::Color(110, 120, 130, 140));
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "rgb(100, 0, 50)").getColor() == sf::Color(100, 0, 50));
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "rgba(100, 0, 50, 200)").getColor() == sf::Color(100, 0, 50, 200));
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "#123").getColor() == sf::Color(17, 34, 51));
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "#4567").getColor() == sf::Color(68, 85, 102, 119));
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "#89ABCD").getColor() == sf::Color(137, 171, 205));
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "#FEDCBA98").getColor() == sf::Color(254, 220, 186, 152));
REQUIRE_THROWS_AS(tgui::Deserializer::deserialize(Type::Color, ""), tgui::Exception);
REQUIRE_THROWS_AS(tgui::Deserializer::deserialize(Type::Color, "rgb(0,1)"), tgui::Exception);
REQUIRE_THROWS_AS(tgui::Deserializer::deserialize(Type::Color, ",,,,"), tgui::Exception);
}
SECTION("deserialize borders") {
REQUIRE(tgui::Deserializer::deserialize(Type::Borders, "10, 20, 30, 40").getBorders() == tgui::Borders(10, 20, 30, 40));
REQUIRE(tgui::Deserializer::deserialize(Type::Borders, "(50, 60, 70, 80)").getBorders() == tgui::Borders(50, 60, 70, 80));
REQUIRE_THROWS_AS(tgui::Deserializer::deserialize(Type::Borders, ""), tgui::Exception);
REQUIRE_THROWS_AS(tgui::Deserializer::deserialize(Type::Borders, "(0,1)"), tgui::Exception);
REQUIRE_THROWS_AS(tgui::Deserializer::deserialize(Type::Borders, ",,,,"), tgui::Exception);
}
SECTION("deserialize texture") {
tgui::Texture texture;
texture = tgui::Deserializer::deserialize(Type::Texture, "\"resources/image.png\"").getTexture();
REQUIRE(texture.isLoaded());
REQUIRE(texture.getData()->rect == sf::IntRect());
REQUIRE(texture.getMiddleRect() == sf::IntRect(0, 0, 50, 50));
texture = tgui::Deserializer::deserialize(Type::Texture, "\"resources/image.png\" Part(0, 0, 25, 25)").getTexture();
REQUIRE(texture.isLoaded());
REQUIRE(texture.getData()->rect == sf::IntRect(0, 0, 25, 25));
REQUIRE(texture.getMiddleRect() == sf::IntRect(0, 0, 25, 25));
texture = tgui::Deserializer::deserialize(Type::Texture, "\"resources/image.png\" Middle(10, 10, 30, 30)").getTexture();
REQUIRE(texture.isLoaded());
REQUIRE(texture.getData()->rect == sf::IntRect());
REQUIRE(texture.getMiddleRect() == sf::IntRect(10, 10, 30, 30));
texture = tgui::Deserializer::deserialize(Type::Texture, "\"resources/image.png\" Part(0, 0, 40, 40) Middle(10, 10, 20, 20)").getTexture();
REQUIRE(texture.isLoaded());
REQUIRE(texture.getData()->rect == sf::IntRect(0, 0, 40, 40));
REQUIRE(texture.getMiddleRect() == sf::IntRect(10, 10, 20, 20));
texture = tgui::Deserializer::deserialize(Type::Texture, "\"resources/image.png\" Part(0, 0, 40, 40) Middle(10, 10, 20, 20) Repeat").getTexture();
REQUIRE(texture.isLoaded());
REQUIRE(texture.getData()->rect == sf::IntRect(0, 0, 40, 40));
REQUIRE(texture.getMiddleRect() == sf::IntRect(10, 10, 20, 20));
REQUIRE_THROWS_AS(tgui::Deserializer::deserialize(Type::Texture, "resources/image.png"), tgui::Exception);
REQUIRE_THROWS_AS(tgui::Deserializer::deserialize(Type::Texture, ""), tgui::Exception);
REQUIRE_THROWS_AS(tgui::Deserializer::deserialize(Type::Texture, "\"resources/image.png\" xyz(0,0,0,0)"), tgui::Exception);
REQUIRE_THROWS_AS(tgui::Deserializer::deserialize(Type::Texture, "\"resources/image.png\" Part(0,1)"), tgui::Exception);
REQUIRE_THROWS_AS(tgui::Deserializer::deserialize(Type::Texture, "\"resources/image.png\" Middle(,,,,)"), tgui::Exception);
}
SECTION("deserialize string") {
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\"\"").getString() == "");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\"Just a string.\"").getString() == "Just a string.");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\"\\\\\"").getString() == "\\");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\"\\n\"").getString() == "\n");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\"\\t\"").getString() == "\t");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\"\\v\"").getString() == "\v");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\"\\\"\"").getString() == "\"");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\"a\\t\\\"str\\\"?\\nYES!\"").getString() == "a\t\"str\"?\nYES!");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "").getString() == "");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\\").getString() == "\\");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\\n").getString() == "\\n");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "str").getString() == "str");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\"\\m\"").getString() == "m");
REQUIRE(tgui::Deserializer::deserialize(Type::String, "\"\n\"").getString() == "\n");
}
SECTION("custom deserialize function") {
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "rgb(10, 20, 30)").getColor() == sf::Color(10, 20, 30));
auto oldFunc = tgui::Deserializer::getFunction(tgui::ObjectConverter::Type::Color);
tgui::Deserializer::setFunction(Type::Color, [](const std::string&){ return tgui::ObjectConverter{sf::Color::Green}; });
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "rgb(10, 20, 30)").getColor() == sf::Color::Green);
REQUIRE(tgui::Deserializer::deserialize(Type::Borders, "(50, 60, 70, 80)").getBorders() == tgui::Borders(50, 60, 70, 80));
tgui::Deserializer::setFunction(tgui::ObjectConverter::Type::Color, oldFunc);
REQUIRE(tgui::Deserializer::deserialize(Type::Color, "rgb(10, 20, 30)").getColor() == sf::Color(10, 20, 30));
}
}

View File

@ -0,0 +1,92 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus's Graphical User Interface
// Copyright (C) 2012-2015 Bruno Van de Velde (vdv_b@tgui.eu)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "../catch.hpp"
#include <TGUI/Loading/Serializer.hpp>
TEST_CASE("[Serializer]") {
SECTION("serialize font") {
/*
auto font = std::make_shared<sf::Font>();
font->loadFromFile("resources/DroidSansArmenian.ttf");
REQUIRE(tgui::Serializer::serialize(font) == "FONT_PLACEHOLDER");
*/
}
SECTION("serialize color") {
REQUIRE(tgui::Serializer::serialize(sf::Color{100, 0, 50}) == "rgb(100, 0, 50)");
REQUIRE(tgui::Serializer::serialize(sf::Color{100, 0, 50, 200}) == "rgba(100, 0, 50, 200)");
REQUIRE(tgui::Serializer::serialize(sf::Color::Green) == "rgb(0, 255, 0)");
}
SECTION("serialize borders") {
REQUIRE(tgui::Serializer::serialize(tgui::Borders{}) == "(0, 0, 0, 0)");
REQUIRE(tgui::Serializer::serialize(tgui::Borders{10, 2, 50, 300}) == "(10, 2, 50, 300)");
}
SECTION("serialize texture") {
tgui::Texture texture;
texture.load("resources/image.png");
REQUIRE(tgui::Serializer::serialize(texture) == "\"resources/image.png\"");
texture.load("resources/image.png", {0, 0, 25, 25});
REQUIRE(tgui::Serializer::serialize(texture) == "\"resources/image.png\" Part(0, 0, 25, 25)");
texture.load("resources/image.png", {}, {10, 10, 30, 30});
REQUIRE(tgui::Serializer::serialize(texture) == "\"resources/image.png\" Middle(10, 10, 30, 30)");
texture.load("resources/image.png", {0, 0, 40, 40}, {10, 10, 20, 20});
REQUIRE(tgui::Serializer::serialize(texture) == "\"resources/image.png\" Part(0, 0, 40, 40) Middle(10, 10, 20, 20)");
texture.load("resources/image.png", {}, {}, true);
REQUIRE(tgui::Serializer::serialize(texture) == "\"resources/image.png\" Repeat");
texture.load("resources/image.png", {0, 0, 40, 40}, {10, 10, 20, 20}, true);
REQUIRE(tgui::Serializer::serialize(texture) == "\"resources/image.png\" Part(0, 0, 40, 40) Middle(10, 10, 20, 20) Repeat");
}
SECTION("serialize string") {
REQUIRE(tgui::Serializer::serialize({""}) == "\"\"");
REQUIRE(tgui::Serializer::serialize({"Just a string."}) == "\"Just a string.\"");
REQUIRE(tgui::Serializer::serialize({"\\"}) == "\"\\\\\"");
REQUIRE(tgui::Serializer::serialize({"\n"}) == "\"\\n\"");
REQUIRE(tgui::Serializer::serialize({"\t"}) == "\"\\t\"");
REQUIRE(tgui::Serializer::serialize({"\v"}) == "\"\\v\"");
REQUIRE(tgui::Serializer::serialize({"\""}) == "\"\\\"\"");
REQUIRE(tgui::Serializer::serialize({"a\t\"string\"?\nYES!"}) == "\"a\\t\\\"string\\\"?\\nYES!\"");
}
SECTION("custom serialize function") {
REQUIRE(tgui::Serializer::serialize(sf::Color::Blue) == "rgb(0, 0, 255)");
auto oldFunc = tgui::Serializer::getFunction(tgui::ObjectConverter::Type::Color);
tgui::Serializer::setFunction(tgui::ObjectConverter::Type::Color, [](tgui::ObjectConverter&&){ return "STR"; });
REQUIRE(tgui::Serializer::serialize(sf::Color::Blue) == "STR");
REQUIRE(tgui::Serializer::serialize(tgui::Borders{10, 2, 50, 300}) == "(10, 2, 50, 300)");
tgui::Serializer::setFunction(tgui::ObjectConverter::Type::Color, oldFunc);
REQUIRE(tgui::Serializer::serialize(sf::Color::Blue) == "rgb(0, 0, 255)");
}
}

340
tests/Loading/Theme.cpp Normal file
View File

@ -0,0 +1,340 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus's Graphical User Interface
// Copyright (C) 2012-2015 Bruno Van de Velde (vdv_b@tgui.eu)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "../catch.hpp"
#include <TGUI/TGUI.hpp>
namespace tgui
{
class ThemeTest
{
public:
static auto& getFilename(tgui::Theme::Ptr theme) { return theme->m_filename; }
static auto& getResourcePath(tgui::Theme::Ptr theme) { return theme->m_resourcePath; }
static auto& getWidgets(tgui::Theme::Ptr theme) { return theme->m_widgets; }
static auto& getWidgetTypes(tgui::Theme::Ptr theme) { return theme->m_widgetTypes; }
static auto& getWidgetProperties(tgui::Theme::Ptr theme) { return theme->m_widgetProperties; }
};
}
TEST_CASE("[Theme]") {
SECTION("creating") {
tgui::Theme::Ptr theme;
REQUIRE(theme == nullptr);
theme = tgui::Theme::create();
REQUIRE(theme != nullptr);
REQUIRE(tgui::ThemeTest::getFilename(theme) == "");
REQUIRE(tgui::ThemeTest::getResourcePath(theme) == "");
theme = tgui::Theme::create("resources/Black.conf");
REQUIRE(theme != nullptr);
REQUIRE(tgui::ThemeTest::getFilename(theme) == "resources/Black.conf");
REQUIRE(tgui::ThemeTest::getResourcePath(theme) == "resources/");
REQUIRE(tgui::ThemeTest::getWidgets(theme).empty());
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).empty());
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).empty());
}
SECTION("load") {
SECTION("default white theme") {
tgui::Theme::Ptr theme = tgui::Theme::create("");
REQUIRE(tgui::ThemeTest::getWidgets(theme).empty());
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).empty());
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).empty());
tgui::Button::Ptr button = theme->load("button");
REQUIRE(button->getTheme() == theme);
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).begin()->first == "button");
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).begin()->second == "button");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).empty());
button = nullptr;
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 0);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).size() == 1);
}
SECTION("black theme") {
tgui::Theme::Ptr theme = tgui::Theme::create("resources/Black.txt");
REQUIRE(tgui::ThemeTest::getWidgets(theme).empty());
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).empty());
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).empty());
tgui::Button::Ptr button = theme->load("button");
REQUIRE(button->getTheme() == theme);
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).begin()->first == "button");
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).begin()->second == "button");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).begin()->first == "button");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).begin()->second.size() > 0);
button = nullptr;
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 0);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).size() == 1);
}
SECTION("theme is shared") {
tgui::Theme::Ptr theme = tgui::Theme::create();
tgui::Button::Ptr button = theme->load("Button");
tgui::EditBox::Ptr editBox = theme->load("EditBox");
REQUIRE(button->getTheme() == theme);
REQUIRE(button->getTheme() == editBox->getTheme());
}
SECTION("nonexistent file") {
tgui::Theme::Ptr theme = tgui::Theme::create("nonexistent_file");
REQUIRE_THROWS_AS(theme->load("button"), tgui::Exception);
REQUIRE(tgui::ThemeTest::getWidgets(theme).empty());
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).empty());
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).begin()->first == "button");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).begin()->second.size() == 0);
}
SECTION("nonexistent section") {
tgui::Theme::Ptr theme = tgui::Theme::create("resources/Black.txt");
REQUIRE_THROWS_AS(theme->load("nonexistent_section"), tgui::Exception);
REQUIRE(tgui::ThemeTest::getWidgets(theme).empty());
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).empty());
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).begin()->first == "nonexistent_section");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).begin()->second.size() == 0);
}
}
SECTION("reload") {
SECTION("changing filename") {
tgui::Theme::Ptr theme1 = tgui::Theme::create("resources/ThemeButton1.txt");
tgui::Theme::Ptr theme2 = tgui::Theme::create("resources/ThemeButton2.txt");
tgui::Button::Ptr button1 = theme1->load("button1");
REQUIRE(button1->getTheme() == theme1);
REQUIRE(tgui::ThemeTest::getWidgets(theme1).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme1).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme1).begin()->first == "button1");
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme1).begin()->second == "button");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme1).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme1).begin()->first == "button1");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme1).begin()->second.size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme1).begin()->second.begin()->first == "textcolor");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme1).begin()->second.begin()->second == "rgb(255, 255, 0)");
tgui::Button::Ptr button2 = theme2->load("button2");
REQUIRE(button2->getTheme() == theme2);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme2).begin()->first == "button2");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme2).begin()->second.begin()->second == "rgb(0, 255, 255)");
theme1->reload("resources/ThemeMultipleButtons.txt");
REQUIRE(button1->getTheme() == theme1);
REQUIRE(tgui::ThemeTest::getWidgets(theme1).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme1).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme1).begin()->first == "button1");
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme1).begin()->second == "button");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme1).size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme1).begin()->first == "button1");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme1).begin()->second.size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme1).begin()->second.begin()->first == "textcolor");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme1).begin()->second.begin()->second == "rgb(255, 0, 0)");
theme2->reload("resources/ThemeMultipleButtons.txt");
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme2).begin()->first == "button2");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme2).begin()->second.begin()->second == "rgb(0, 255, 0)");
SECTION("nonexistent theme") {
REQUIRE_THROWS_AS(theme2->reload("nonexistent_file"), tgui::Exception);
}
SECTION("nonexistent section") {
REQUIRE_THROWS_AS(theme2->reload("resources/ThemeButton1.txt"), tgui::Exception);
}
}
SECTION("changing class name") {
tgui::Theme::Ptr theme = tgui::Theme::create("resources/ThemeMultipleButtons.txt");
tgui::Button::Ptr button1 = theme->load("button1");
tgui::Button::Ptr button2 = theme->load("button2");
tgui::Button::Ptr button3 = theme->load("button3");
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgets(theme)[button1.get()] == "button1");
REQUIRE(tgui::ThemeTest::getWidgets(theme)[button2.get()] == "button2");
REQUIRE(tgui::ThemeTest::getWidgets(theme)[button3.get()] == "button3");
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme)["button1"] == "button");
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme)["button2"] == "button");
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme)["button3"] == "button");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button1"].size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button2"].size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button3"].size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button1"]["textcolor"] == "rgb(255, 0, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button2"]["textcolor"] == "rgb(0, 255, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button3"]["textcolor"] == "rgb(0, 0, 255)");
REQUIRE(button1->getRenderer()->getProperty("TextColor").getColor() == sf::Color(255, 0, 0));
REQUIRE(button2->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 255, 0));
REQUIRE(button3->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 0, 255));
theme->reload("button1", "button2");
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgets(theme)[button1.get()] == "button2");
REQUIRE(tgui::ThemeTest::getWidgets(theme)[button2.get()] == "button2");
REQUIRE(tgui::ThemeTest::getWidgets(theme)[button3.get()] == "button3");
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme)["button1"] == "button");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button1"]["textcolor"] == "rgb(255, 0, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button2"]["textcolor"] == "rgb(0, 255, 0)");
REQUIRE(button1->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 255, 0));
REQUIRE(button2->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 255, 0));
REQUIRE(button3->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 0, 255));
theme->reload("button2", "button1");
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgets(theme)[button1.get()] == "button1");
REQUIRE(tgui::ThemeTest::getWidgets(theme)[button2.get()] == "button1");
REQUIRE(tgui::ThemeTest::getWidgets(theme)[button3.get()] == "button3");
REQUIRE(button1->getRenderer()->getProperty("TextColor").getColor() == sf::Color(255, 0, 0));
REQUIRE(button2->getRenderer()->getProperty("TextColor").getColor() == sf::Color(255, 0, 0));
REQUIRE(button3->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 0, 255));
button3 = nullptr;
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 2);
button2 = nullptr;
button1 = nullptr;
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 0);
}
SECTION("changing single widget") {
tgui::Theme::Ptr theme = tgui::Theme::create("resources/ThemeMultipleButtons.txt");
tgui::Button::Ptr button1 = theme->load("button1");
tgui::Button::Ptr button1b = theme->load("button1");
tgui::Button::Ptr button2 = theme->load("button2");
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).size() == 2);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).size() == 2);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button1"].size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button2"].size() == 1);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button1"]["textcolor"] == "rgb(255, 0, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button2"]["textcolor"] == "rgb(0, 255, 0)");
REQUIRE(button1->getRenderer()->getProperty("TextColor").getColor() == sf::Color(255, 0, 0));
REQUIRE(button1b->getRenderer()->getProperty("TextColor").getColor() == sf::Color(255, 0, 0));
REQUIRE(button2->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 255, 0));
theme->reload(button1, "button2");
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).size() == 2);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).size() == 2);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button1"]["textcolor"] == "rgb(255, 0, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button2"]["textcolor"] == "rgb(0, 255, 0)");
REQUIRE(button1->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 255, 0));
REQUIRE(button1b->getRenderer()->getProperty("TextColor").getColor() == sf::Color(255, 0, 0));
REQUIRE(button2->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 255, 0));
theme->reload(button1, "button3");
REQUIRE(tgui::ThemeTest::getWidgets(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgetTypes(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button1"]["textcolor"] == "rgb(255, 0, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button2"]["textcolor"] == "rgb(0, 255, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button3"]["textcolor"] == "rgb(0, 0, 255)");
REQUIRE(button1->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 0, 255));
REQUIRE(button1b->getRenderer()->getProperty("TextColor").getColor() == sf::Color(255, 0, 0));
REQUIRE(button2->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 255, 0));
}
}
SECTION("setProperty") {
tgui::Theme::Ptr theme = tgui::Theme::create("resources/ThemeMultipleButtons.txt");
tgui::Button::Ptr button1 = theme->load("button1");
tgui::Button::Ptr button2 = theme->load("button2");
tgui::Button::Ptr button3 = theme->load("button3");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button1"]["textcolor"] == "rgb(255, 0, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button2"]["textcolor"] == "rgb(0, 255, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button3"]["textcolor"] == "rgb(0, 0, 255)");
REQUIRE(button1->getRenderer()->getProperty("TextColor").getColor() == sf::Color(255, 0, 0));
REQUIRE(button2->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 255, 0));
REQUIRE(button3->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 0, 255));
theme->setProperty("button1", "textcolor", "rgb(0, 255, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button1"]["textcolor"] == "rgb(0, 255, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button2"]["textcolor"] == "rgb(0, 255, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button3"]["textcolor"] == "rgb(0, 0, 255)");
REQUIRE(button1->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 255, 0));
REQUIRE(button2->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 255, 0));
REQUIRE(button3->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 0, 255));
theme->setProperty("button2", "textcolor", sf::Color(0, 0, 255));
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme).size() == 3);
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button1"]["textcolor"] == "rgb(0, 255, 0)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button2"]["textcolor"] == "rgb(0, 0, 255)");
REQUIRE(tgui::ThemeTest::getWidgetProperties(theme)["button3"]["textcolor"] == "rgb(0, 0, 255)");
REQUIRE(button1->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 255, 0));
REQUIRE(button2->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 0, 255));
REQUIRE(button3->getRenderer()->getProperty("TextColor").getColor() == sf::Color(0, 0, 255));
}
SECTION("setConstructFunction") {
tgui::Theme::Ptr theme = tgui::Theme::create();
unsigned int count = 0;
tgui::Theme::setConstructFunction("Button", [&](){ count++; return std::make_shared<tgui::Button>(); });
theme->load("button");
REQUIRE(count == 1);
REQUIRE_THROWS_AS(theme->load("CustomWidget"), tgui::Exception);
unsigned int count2 = 0;
tgui::Theme::setConstructFunction("CustomWidget", [&](){ count2++; return std::make_shared<tgui::EditBox>(); });
theme->load("CustomWidget");
REQUIRE(count == 1);
REQUIRE(count2 == 1);
}
SECTION("setThemeLoader") {
struct CustomThemeLoader : public tgui::BaseThemeLoader {
std::string load(const std::string& one, const std::string& two, std::map<std::string, std::string>&) override {
REQUIRE(one == "resources/Black.txt");
REQUIRE(two == "editbox");
return two;
}
};
auto loader = std::make_shared<CustomThemeLoader>();
tgui::Theme::setThemeLoader(loader);
tgui::Theme::Ptr theme = tgui::Theme::create();
theme->load("BUTTON");
theme = tgui::Theme::create("resources/Black.txt");
theme->load("EditBox");
}
}

View File

@ -0,0 +1,121 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus's Graphical User Interface
// Copyright (C) 2012-2015 Bruno Van de Velde (vdv_b@tgui.eu)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "../catch.hpp"
#include <TGUI/Loading/ThemeLoader.hpp>
namespace tgui
{
struct DefaultThemeLoaderTest
{
static auto& getPropertiesCache(std::shared_ptr<DefaultThemeLoader> loader) { return loader->m_propertiesCache; }
static auto& getWidgetTypeCache(std::shared_ptr<DefaultThemeLoader> loader) { return loader->m_widgetTypeCache; }
};
}
TEST_CASE("[ThemeLoader]") {
tgui::DefaultThemeLoader::flushCache();
auto loader = std::make_shared<tgui::DefaultThemeLoader>();
std::map<std::string, std::string> properties;
SECTION("load black theme") {
loader->load("resources/Black.txt", "EditBox", properties);
REQUIRE(properties.size() > 0);
}
SECTION("load nonexistent theme") {
REQUIRE_THROWS_AS(loader->load("resources/nonexistent.txt", "", properties), tgui::Exception);
}
SECTION("load nonexistent class name") {
REQUIRE_THROWS_AS(loader->load("resources/Black.txt", "NonexistentClassName", properties), tgui::Exception);
}
SECTION("load theme with missing opening brace") {
REQUIRE_THROWS_AS(loader->load("resources/ThemeMissingOpeningBrace.txt", "button1", properties), tgui::Exception);
}
SECTION("load theme with missing closing brace") {
REQUIRE_THROWS_AS(loader->load("resources/ThemeMissingClosingBrace.txt", "button1", properties), tgui::Exception);
}
SECTION("load theme with missing semi-colon") {
REQUIRE_THROWS_AS(loader->load("resources/ThemeMissingSemiColon.txt", "button1", properties), tgui::Exception);
}
SECTION("load theme with special cases") {
REQUIRE_NOTHROW(loader->load("resources/ThemeSpecialCases.txt", "name.WITH.dots", properties));
}
SECTION("load theme with comments") {
/*
REQUIRE_NOTHROW(loader->load("resources/ThemeComments.txt", "Button1", properties));
REQUIRE(properties.size() == 1);
REQUIRE(properties["textcolor"] == "rgb(255, 0, 0)");
REQUIRE_NOTHROW(loader->load("resources/ThemeComments.txt", "CorrectName", properties));
REQUIRE(properties.size() == 1);
REQUIRE(properties["textcolor"] == "rgb(0, 255, 0)");
REQUIRE_NOTHROW(loader->load("resources/ThemeComments.txt", "Button3", properties));
REQUIRE(properties.size() == 1);
REQUIRE(properties["textcolor"] == "rgb(0, 0, 255)");
*/
}
SECTION("cache") {
REQUIRE(tgui::DefaultThemeLoaderTest::getPropertiesCache(loader).size() == 0);
REQUIRE(tgui::DefaultThemeLoaderTest::getWidgetTypeCache(loader).size() == 0);
loader->load("resources/ThemeSpecialCases.txt", "name.WITH.dots", properties);
REQUIRE(properties.size() == 2);
REQUIRE(properties["textcolor"] == "rgb(0, 255, 0)");
REQUIRE(properties["backgroundcolor"] == "rgb(255, 255, 255)");
REQUIRE(tgui::DefaultThemeLoaderTest::getPropertiesCache(loader).size() == 1);
REQUIRE(tgui::DefaultThemeLoaderTest::getWidgetTypeCache(loader).size() == 1);
auto& cache = tgui::DefaultThemeLoaderTest::getPropertiesCache(loader)["resources/ThemeSpecialCases.txt"];
REQUIRE(cache.size() == 3);
REQUIRE(cache["button1"].size() == 1);
REQUIRE(cache["button1"]["textcolor"] == "rgb(255, 0, 0)");
REQUIRE(cache["name.with.dots"].size() == 2);
REQUIRE(cache["name.with.dots"]["textcolor"] == "rgb(0, 255, 0)");
REQUIRE(cache["name.with.dots"]["backgroundcolor"] == "rgb(255, 255, 255)");
REQUIRE(cache["button"].size() == 1);
REQUIRE(cache["button"]["textcolor"] == "rgb(0, 0, 255)");
auto& typeCache = tgui::DefaultThemeLoaderTest::getWidgetTypeCache(loader)["resources/ThemeSpecialCases.txt"];
REQUIRE(typeCache.size() == 3);
REQUIRE(typeCache["button1"] == "button");
REQUIRE(typeCache["name.with.dots"] == "button");
REQUIRE(typeCache["button"] == "button");
loader->load("resources/Black.txt", "EditBox", properties);
REQUIRE(tgui::DefaultThemeLoaderTest::getPropertiesCache(loader).size() == 2);
tgui::DefaultThemeLoader::flushCache();
REQUIRE(tgui::DefaultThemeLoaderTest::getPropertiesCache(loader).size() == 0);
}
}

BIN
tests/resources/Black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

168
tests/resources/Black.txt Normal file
View File

@ -0,0 +1,168 @@
Button {
NormalImage : "Black.png" Part( 0, 64, 45, 50) Middle(10, 0, 25, 50);
HoverImage : "Black.png" Part(45, 64, 45, 50) Middle(10, 0, 25, 50);
DownImage : "Black.png" Part(90, 64, 45, 50) Middle(10, 0, 25, 50);
TextColorNormal : rgb(190, 190, 190);
TextColorHover : rgb(250, 250, 250);
TextColorDown : rgb(250, 250, 250);
}
Button.Button2 {
NormalImage : "Black.png" Part( 0, 64, 45, 50) Middle(10, 0, 25, 50);
HoverImage : "Black.png" Part(45, 64, 45, 50) Middle(10, 0, 25, 50);
DownImage : "Black.png" Part(90, 64, 45, 50) Middle(10, 0, 25, 50);
TextColorNormal : rgb(190, 0, 190);
TextColorHover : rgb(250, 250, 250);
TextColorDown : rgb(250, 250, 250);
}
ChatBox {
BackgroundImage : "Black.png" Part(0, 154, 48, 48) Middle(16, 16, 16, 16);
Scrollbar : "Scrollbar";
Padding : (3, 3, 3, 3);
}
Checkbox {
UncheckedImage : "Black.png" Part(124, 0, 32, 32);
CheckedImage : "Black.png" Part(156, 0, 32, 32);
UncheckedHoverImage : "Black.png" Part(188, 0, 32, 32);
CheckedHoverImage : "Black.png" Part(220, 0, 32, 32);
TextColorNormal : rgb(190, 190, 190);
TextColorHover : rgb(250, 250, 250);
}
ChildWindow {
TitlebarImage : "Black.png" Part(48, 154, 75, 25) Middle(25, 0, 25, 25);
TitleColor : rgb(190, 190, 190);
BackgroundColor : rgb( 80, 80, 80);
BorderColor : rgb(0, 0, 0);
Borders : (1, 1, 1, 1);
DistanceToSide : 5;
CloseButton : "ChildWindowCloseButton";
}
ChildWindowCloseButton {
NormalImage : "Black.png" Part(48, 179, 15, 15);
HoverImage : "Black.png" Part(63, 179, 15, 15);
DownImage : "Black.png" Part(78, 179, 15, 15);
}
ComboBox {
BackgroundImage : "Black.png" Part(0, 154, 48, 48) Middle(16, 16, 16, 16);
ArrowDownNormalImage : "Black.png" Part(60, 0, 32, 32);
ArrowDownHoverImage : "Black.png" Part(60, 32, 32, 32);
ArrowUpNormalImage : "Black.png" Part(92, 0, 32, 32);
ArrowUpHoverImage : "Black.png" Part(92, 32, 32, 32);
TextColor : (190, 190, 190);
Padding : (3, 3, 3, 3);
ListBox : "ListBox";
}
EditBox {
NormalImage : "Black.png" Part(0, 114, 60, 40) Middle(15, 0, 30, 40);
HoverImage : "Black.png" Part(0, 114, 60, 40) Middle(15, 0, 30, 40);
TextColor : rgb(190, 190, 190);
SelectedTextColor : rgb(255, 255, 255);
SelectedTextBackgroundColor : rgb( 10, 110, 255);
DefaultTextColor : rgb(120, 120, 120);
CaretColor : rgb(110, 110, 255);
Padding : (6, 4, 6, 4);
}
Label {
TextColor : (190, 190, 190);
}
ListBox {
BackgroundImage : "Black.png" Part(0, 154, 48, 48) Middle(16, 16, 16, 16);
TextColorNormal : rgb(190, 190, 190);
TextColorHover : rgb(250, 250, 250);
HoverBackgroundColor : rgb(255, 255, 255, 20);
SelectedBackgroundColor : rgb( 10, 110, 255);
SelectedTextColor : rgb(255, 255, 255);
Padding : (3, 3, 3, 3);
Scrollbar : "Scrollbar";
}
ProgressBar {
BackImage : "Black.png" Part(180, 64, 90, 40) Middle(20, 0, 50, 40);
FrontImage : "Black.png" Part(180, 108, 82, 32) Middle(16, 0, 50, 32);
TextColorBack : rgb(190, 190, 190);
TextColorFront : rgb(250, 250, 250);
}
MenuBar {
BackgroundImage : "Black.png" Part(115, 179, 8, 6) Middle(2, 2, 4, 2);
ItemBackgroundImage : "Black.png" Part(115, 181, 8, 4) Middle(2, 0, 4, 2);
SelectedItemBackgroundImage : "Black.png" Part(115, 185, 8, 6) Middle(2, 2, 4, 2);
TextColor : rgb(190, 190, 190);
SelectedTextColor : rgb(255, 255, 255);
DistanceToSide : 5;
}
MessageBox {
ChildWindow : "ChildWindow";
Button : "Button";
TextColor : rgb(190, 190, 190);
}
RadioButton {
UncheckedImage : "Black.png" Part(124, 32, 32, 32);
CheckedImage : "Black.png" Part(156, 32, 32, 32);
UncheckedHoverImage : "Black.png" Part(188, 32, 32, 32);
CheckedHoverImage : "Black.png" Part(220, 32, 32, 32);
TextColorNormal : rgb(190, 190, 190);
TextColorHover : rgb(250, 250, 250);
}
Scrollbar {
TrackNormalImage : "Black.png" Part(123, 154, 20, 20);
ThumbNormalImage : "Black.png" Part(143, 154, 20, 20);
ThumbHoverImage : "Black.png" Part(143, 174, 20, 20);
ArrowUpNormalImage : "Black.png" Part(163, 154, 20, 20) Middle(0, 0, 20, 19);
ArrowUpHoverImage : "Black.png" Part(183, 154, 20, 20) Middle(0, 0, 20, 19);
ArrowDownNormalImage : "Black.png" Part(163, 174, 20, 20) Middle(0, 1, 20, 19);
ArrowDownHoverImage : "Black.png" Part(183, 174, 20, 20) Middle(0, 1, 20, 19);
}
Slider {
TrackNormalImage : "Black.png" Part(203, 150, 20, 45) Middle(0, 15, 20, 15);
TrackHoverImage : "Black.png" Part(223, 150, 20, 45) Middle(0, 15, 20, 15);
ThumbNormalImage : "Black.png" Part(243, 150, 30, 30);
}
SpinButton {
ArrowUpNormalImage : "Black.png" Part(163, 154, 20, 20) Middle(0, 0, 20, 19);
ArrowUpHoverImage : "Black.png" Part(183, 154, 20, 20) Middle(0, 0, 20, 19);
ArrowDownNormalImage : "Black.png" Part(163, 174, 20, 20) Middle(0, 1, 20, 19);
ArrowDownHoverImage : "Black.png" Part(183, 174, 20, 20) Middle(0, 1, 20, 19);
SpaceBetweenArrows : 0;
}
Tab {
NormalImage : "Black.png" Part(0, 0, 60, 32) Middle(16, 0, 28, 32);
SelectedImage : "Black.png" Part(0, 32, 60, 32) Middle(16, 0, 28, 32);
TextColor : rgb(190, 190, 190);
SelectedTextColor : rgb(255, 255, 255);
BorderColor : rgb( 0, 0, 0);
DistanceToSide : 8;
}
TextBox {
BackgroundImage : "Black.png" Part(0, 154, 48, 48) Middle(16, 16, 16, 16);
TextColor : rgb(190, 190, 190);
SelectedTextColor : rgb(255, 255, 255);
SelectedTextBackgroundColor : rgb( 10, 110, 255);
CaretColor : rgb(110, 110, 255);
Padding : (3, 3, 3, 3);
Scrollbar : "Scrollbar";
}
Tooltip {
TextColor : rgb(190, 190, 190);
BackgroundColor : rgb( 80, 80, 80);
BorderColor : rgb( 0, 0, 0);
Borders : (1, 1, 1, 1);
Padding : (2, 2, 2, 2);
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Button.Button1 {
TextColor : rgb(255, 255, 0);
}

View File

@ -0,0 +1,3 @@
Button.Button2 {
TextColor : rgb(0, 255, 255);
}

View File

@ -0,0 +1,13 @@
// Comment
Button.Button1 {
TextColor : rgb(255, 0, 0);
/* BackgroundColor : rgb(255, 255, 255); */
} // Comment
Button.Correct/*Comment*/Name {
TextColor : rgb(0, 255 /*100*/, 0); # Comment
}
Button.Button3 { // Comment
Text/*Comment*/Color : rgb(0, 0, 255);
}

View File

@ -0,0 +1,11 @@
Button.Button1 {
TextColor : rgb(255, 0, 0);
}
Button.Button2 {
TextColor : rgb(0, 255, 0);
Button.Button3 {
TextColor : rgb(0, 0, 255);
}

View File

@ -0,0 +1,11 @@
Button.Button1 {
TextColor : rgb(255, 0, 0);
}
Button.Button2
TextColor : rgb(0, 255, 0);
}
Button.Button3 {
TextColor : rgb(0, 0, 255);
}

View File

@ -0,0 +1,4 @@
Button {
TextColor : rgb(0, 255, 0)
BackgroundColor : rgb(255, 255, 255);
}

View File

@ -0,0 +1,11 @@
Button.Button1 {
TextColor : rgb(255, 0, 0);
}
Button.Button2 {
TextColor : rgb(0, 255, 0);
}
Button.Button3 {
TextColor : rgb(0, 0, 255);
}

View File

@ -0,0 +1,10 @@
Button.Button1 { TextColor : rgb(255, 0, 0); }
Button.Name.With.Dots {
TextColor : rgb(0, 255, 0);
BackgroundColor : rgb(255, 255, 255);
}
Button {
TextColor : rgb(0, 0, 255)
}

BIN
tests/resources/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB