2020-09-21 17:17:34 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-06-21 12:25:28 +00:00
|
|
|
//
|
2024-06-02 20:30:41 +00:00
|
|
|
// ES-DE Frontend
|
2020-06-21 12:25:28 +00:00
|
|
|
// ThemeData.h
|
|
|
|
//
|
2022-01-29 17:41:22 +00:00
|
|
|
// Finds available themes on the file system and loads and parses these.
|
|
|
|
// Basic error checking for valid elements and data types is done here,
|
|
|
|
// with additional validation handled by the individual components.
|
2020-06-21 12:25:28 +00:00
|
|
|
//
|
|
|
|
|
2017-10-31 17:12:50 +00:00
|
|
|
#ifndef ES_CORE_THEME_DATA_H
|
|
|
|
#define ES_CORE_THEME_DATA_H
|
2013-11-12 23:28:15 +00:00
|
|
|
|
2023-01-08 16:00:36 +00:00
|
|
|
#include "GuiComponent.h"
|
2018-01-29 22:50:10 +00:00
|
|
|
#include "utils/FileSystemUtil.h"
|
2021-08-17 20:11:16 +00:00
|
|
|
#include "utils/MathUtil.h"
|
2022-04-09 13:57:37 +00:00
|
|
|
#include "utils/StringUtil.h"
|
2020-10-18 17:45:26 +00:00
|
|
|
|
2022-01-31 22:22:42 +00:00
|
|
|
#include <algorithm>
|
2021-09-19 12:37:10 +00:00
|
|
|
#include <any>
|
2013-12-31 03:48:28 +00:00
|
|
|
#include <deque>
|
2017-11-01 22:21:10 +00:00
|
|
|
#include <map>
|
2018-01-29 22:50:10 +00:00
|
|
|
#include <memory>
|
2017-11-01 22:21:10 +00:00
|
|
|
#include <sstream>
|
2018-01-29 22:50:10 +00:00
|
|
|
#include <vector>
|
2013-12-30 23:23:34 +00:00
|
|
|
|
|
|
|
namespace ThemeFlags
|
2013-11-12 23:28:15 +00:00
|
|
|
{
|
2022-01-22 20:21:13 +00:00
|
|
|
// clang-format off
|
|
|
|
// These are only the most common flags shared accross multiple components, in addition
|
|
|
|
// to these there are many component-specific options.
|
2020-06-21 12:25:28 +00:00
|
|
|
enum PropertyFlags : unsigned int {
|
2022-09-07 17:59:27 +00:00
|
|
|
PATH = 0x00000001,
|
|
|
|
POSITION = 0x00000002,
|
|
|
|
SIZE = 0x00000004,
|
|
|
|
ORIGIN = 0x00000008,
|
|
|
|
COLOR = 0x00000010,
|
|
|
|
FONT_PATH = 0x00000020,
|
|
|
|
FONT_SIZE = 0x00000040,
|
|
|
|
ALIGNMENT = 0x00000080,
|
|
|
|
TEXT = 0x00000100,
|
|
|
|
METADATA = 0x00000200,
|
|
|
|
LETTER_CASE = 0x00000400,
|
2023-07-30 16:17:27 +00:00
|
|
|
LINE_SPACING = 0x00000800,
|
|
|
|
DELAY = 0x00001000,
|
|
|
|
Z_INDEX = 0x00002000,
|
|
|
|
ROTATION = 0x00004000,
|
|
|
|
BRIGHTNESS = 0x00008000,
|
|
|
|
OPACITY = 0x00010000,
|
|
|
|
SATURATION = 0x00020000,
|
|
|
|
VISIBLE = 0x00040000,
|
2022-09-07 17:59:27 +00:00
|
|
|
ALL = 0xFFFFFFFF
|
2020-06-21 12:25:28 +00:00
|
|
|
};
|
2022-01-22 20:21:13 +00:00
|
|
|
// clang-format on
|
|
|
|
} // namespace ThemeFlags
|
2013-12-30 23:23:34 +00:00
|
|
|
|
2023-01-04 18:01:41 +00:00
|
|
|
namespace ThemeTriggers
|
|
|
|
{
|
|
|
|
enum class TriggerType {
|
|
|
|
NONE,
|
|
|
|
NO_VIDEOS,
|
|
|
|
NO_MEDIA
|
|
|
|
};
|
|
|
|
} // namespace ThemeTriggers
|
|
|
|
|
2013-12-30 23:23:34 +00:00
|
|
|
class ThemeException : public std::exception
|
|
|
|
{
|
2013-12-31 03:48:28 +00:00
|
|
|
public:
|
2022-01-23 19:03:50 +00:00
|
|
|
std::string message;
|
2013-11-12 23:28:15 +00:00
|
|
|
|
2022-01-23 19:03:50 +00:00
|
|
|
const char* what() const throw() { return message.c_str(); }
|
2013-11-12 23:28:15 +00:00
|
|
|
|
2022-01-23 19:03:50 +00:00
|
|
|
template <typename T> friend ThemeException& operator<<(ThemeException& e, T message)
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << e.message << message;
|
|
|
|
e.message = ss.str();
|
|
|
|
return e;
|
|
|
|
}
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2021-07-07 18:31:46 +00:00
|
|
|
void setFiles(const std::deque<std::string>& deque)
|
2020-06-21 12:25:28 +00:00
|
|
|
{
|
2022-01-23 19:03:50 +00:00
|
|
|
// Add all paths to the error message, separated by -> so it's easy to read the log
|
|
|
|
// output in case of theme loading errors.
|
2022-01-23 16:50:51 +00:00
|
|
|
*this << "\"" << deque.front() << "\"";
|
2021-11-17 16:48:49 +00:00
|
|
|
for (auto it = deque.cbegin() + 1; it != deque.cend(); ++it)
|
2021-01-17 20:52:34 +00:00
|
|
|
*this << " -> \"" << (*it) << "\"";
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2013-11-12 23:28:15 +00:00
|
|
|
};
|
|
|
|
|
2013-12-30 23:23:34 +00:00
|
|
|
class ThemeData
|
|
|
|
{
|
2014-01-01 05:39:22 +00:00
|
|
|
public:
|
2020-06-21 12:25:28 +00:00
|
|
|
class ThemeElement
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
std::string type;
|
|
|
|
|
|
|
|
struct Property {
|
2021-08-15 20:03:17 +00:00
|
|
|
void operator=(const glm::vec4& value)
|
2020-10-17 12:05:41 +00:00
|
|
|
{
|
|
|
|
r = value;
|
2022-01-16 11:09:55 +00:00
|
|
|
const glm::vec4 initVector {value};
|
|
|
|
v = glm::vec2 {initVector.x, initVector.y};
|
2020-10-17 12:05:41 +00:00
|
|
|
}
|
2021-08-16 16:25:01 +00:00
|
|
|
void operator=(const glm::vec2& value) { v = value; }
|
2021-03-27 09:26:13 +00:00
|
|
|
void operator=(const std::string& value) { s = value; }
|
|
|
|
void operator=(const unsigned int& value) { i = value; }
|
|
|
|
void operator=(const float& value) { f = value; }
|
|
|
|
void operator=(const bool& value) { b = value; }
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2021-08-15 20:03:17 +00:00
|
|
|
glm::vec4 r;
|
2021-08-16 16:25:01 +00:00
|
|
|
glm::vec2 v;
|
2020-06-21 12:25:28 +00:00
|
|
|
std::string s;
|
|
|
|
unsigned int i;
|
|
|
|
float f;
|
|
|
|
bool b;
|
|
|
|
};
|
|
|
|
|
2021-03-27 09:26:13 +00:00
|
|
|
std::map<std::string, Property> properties;
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2021-07-07 18:31:46 +00:00
|
|
|
template <typename T> const T get(const std::string& prop) const
|
2020-06-21 12:25:28 +00:00
|
|
|
{
|
2021-08-16 16:25:01 +00:00
|
|
|
if (std::is_same<T, glm::vec2>::value)
|
2021-09-19 12:37:10 +00:00
|
|
|
return std::any_cast<const T>(properties.at(prop).v);
|
2020-06-21 12:25:28 +00:00
|
|
|
else if (std::is_same<T, std::string>::value)
|
2021-09-19 12:37:10 +00:00
|
|
|
return std::any_cast<const T>(properties.at(prop).s);
|
2020-06-21 12:25:28 +00:00
|
|
|
else if (std::is_same<T, unsigned int>::value)
|
2021-09-19 12:37:10 +00:00
|
|
|
return std::any_cast<const T>(properties.at(prop).i);
|
2020-06-21 12:25:28 +00:00
|
|
|
else if (std::is_same<T, float>::value)
|
2021-09-19 12:37:10 +00:00
|
|
|
return std::any_cast<const T>(properties.at(prop).f);
|
2020-06-21 12:25:28 +00:00
|
|
|
else if (std::is_same<T, bool>::value)
|
2021-09-19 12:37:10 +00:00
|
|
|
return std::any_cast<const T>(properties.at(prop).b);
|
2021-08-15 20:03:17 +00:00
|
|
|
else if (std::is_same<T, glm::vec4>::value)
|
2021-09-19 12:37:10 +00:00
|
|
|
return std::any_cast<const T>(properties.at(prop).r);
|
2020-06-21 12:25:28 +00:00
|
|
|
return T();
|
|
|
|
}
|
|
|
|
|
2021-07-07 18:31:46 +00:00
|
|
|
bool has(const std::string& prop) const
|
|
|
|
{
|
|
|
|
return (properties.find(prop) != properties.cend());
|
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
};
|
2013-11-12 23:28:15 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
ThemeData();
|
2013-11-12 23:28:15 +00:00
|
|
|
|
2022-01-29 17:41:22 +00:00
|
|
|
class ThemeView
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
std::map<std::string, ThemeElement> elements;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ThemeVariant {
|
|
|
|
std::string name;
|
|
|
|
std::string label;
|
|
|
|
bool selectable;
|
2023-01-04 18:01:41 +00:00
|
|
|
std::map<ThemeTriggers::TriggerType, std::pair<std::string, std::vector<std::string>>>
|
|
|
|
overrides;
|
2022-11-03 22:19:25 +00:00
|
|
|
|
|
|
|
ThemeVariant()
|
|
|
|
: selectable {false}
|
|
|
|
{
|
|
|
|
}
|
2022-01-29 17:41:22 +00:00
|
|
|
};
|
|
|
|
|
2022-10-31 18:32:13 +00:00
|
|
|
struct ThemeColorScheme {
|
|
|
|
std::string name;
|
|
|
|
std::string label;
|
|
|
|
};
|
|
|
|
|
2023-01-08 16:00:36 +00:00
|
|
|
struct ThemeTransitions {
|
|
|
|
std::string name;
|
|
|
|
std::string label;
|
|
|
|
bool selectable;
|
|
|
|
std::map<ViewTransition, ViewTransitionAnimation> animations;
|
|
|
|
|
|
|
|
ThemeTransitions()
|
|
|
|
: selectable {true}
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-01-29 17:41:22 +00:00
|
|
|
struct ThemeCapability {
|
2023-01-20 17:37:32 +00:00
|
|
|
std::string themeName;
|
2022-01-29 17:41:22 +00:00
|
|
|
std::vector<ThemeVariant> variants;
|
2022-10-31 18:32:13 +00:00
|
|
|
std::vector<ThemeColorScheme> colorSchemes;
|
2023-12-20 20:58:40 +00:00
|
|
|
std::vector<std::string> fontSizes;
|
2022-01-29 17:41:22 +00:00
|
|
|
std::vector<std::string> aspectRatios;
|
2024-08-29 17:09:33 +00:00
|
|
|
std::vector<std::string> languages;
|
2023-01-08 16:00:36 +00:00
|
|
|
std::vector<ThemeTransitions> transitions;
|
2023-01-08 18:30:16 +00:00
|
|
|
std::vector<std::string> suppressedTransitionProfiles;
|
2023-07-30 16:17:27 +00:00
|
|
|
bool validTheme;
|
2022-01-29 17:41:22 +00:00
|
|
|
};
|
|
|
|
|
2023-08-14 20:40:32 +00:00
|
|
|
struct Theme {
|
2022-01-23 19:03:50 +00:00
|
|
|
std::string path;
|
2022-01-29 17:41:22 +00:00
|
|
|
ThemeCapability capabilities;
|
2022-01-23 19:03:50 +00:00
|
|
|
|
|
|
|
std::string getName() const { return Utils::FileSystem::getStem(path); }
|
|
|
|
std::string getThemePath(const std::string& system) const
|
|
|
|
{
|
|
|
|
return path + "/" + system + "/theme.xml";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-04-09 13:57:37 +00:00
|
|
|
struct StringComparator {
|
|
|
|
bool operator()(const std::string& a, const std::string& b) const
|
|
|
|
{
|
|
|
|
return Utils::String::toUpper(a) < Utils::String::toUpper(b);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-10-29 11:04:00 +00:00
|
|
|
void loadFile(const std::map<std::string, std::string>& sysDataMap,
|
|
|
|
const std::string& path,
|
2023-01-04 18:01:41 +00:00
|
|
|
const ThemeTriggers::TriggerType trigger,
|
2022-10-29 11:04:00 +00:00
|
|
|
const bool customCollection);
|
2022-01-23 19:03:50 +00:00
|
|
|
bool hasView(const std::string& view);
|
2022-01-29 17:41:22 +00:00
|
|
|
ThemeView& getViewElements(std::string view) { return mViews[view]; }
|
2022-01-23 19:03:50 +00:00
|
|
|
|
|
|
|
const ThemeElement* getElement(const std::string& view,
|
|
|
|
const std::string& element,
|
|
|
|
const std::string& expectedType) const;
|
|
|
|
|
2023-08-14 20:40:32 +00:00
|
|
|
static void populateThemes();
|
|
|
|
const static std::map<std::string, Theme, StringComparator>& getThemes() { return sThemes; }
|
|
|
|
const static std::string getSystemThemeFile(const std::string& system);
|
2023-12-20 20:58:40 +00:00
|
|
|
const static std::string getFontSizeLabel(const std::string& fontSize);
|
2022-01-31 22:22:42 +00:00
|
|
|
const static std::string getAspectRatioLabel(const std::string& aspectRatio);
|
2024-08-29 17:09:33 +00:00
|
|
|
const static std::string getLanguageLabel(const std::string& language);
|
2023-01-08 16:00:36 +00:00
|
|
|
static void setThemeTransitions();
|
2013-11-12 23:28:15 +00:00
|
|
|
|
2023-01-04 18:01:41 +00:00
|
|
|
const std::map<ThemeTriggers::TriggerType, std::pair<std::string, std::vector<std::string>>>
|
2023-08-14 20:40:32 +00:00
|
|
|
getCurrentThemeSelectedVariantOverrides();
|
2023-02-09 23:34:24 +00:00
|
|
|
const static void themeLoadedLogOutput();
|
2022-01-29 17:41:22 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
enum ElementPropertyType {
|
|
|
|
NORMALIZED_RECT,
|
|
|
|
NORMALIZED_PAIR,
|
|
|
|
PATH,
|
|
|
|
STRING,
|
|
|
|
COLOR,
|
2022-02-13 14:01:55 +00:00
|
|
|
UNSIGNED_INTEGER,
|
2020-06-21 12:25:28 +00:00
|
|
|
FLOAT,
|
|
|
|
BOOLEAN
|
|
|
|
};
|
2013-12-30 23:23:34 +00:00
|
|
|
|
2022-01-23 19:03:50 +00:00
|
|
|
std::map<std::string, std::string> mVariables;
|
2014-05-01 02:12:45 +00:00
|
|
|
|
2013-11-12 23:28:15 +00:00
|
|
|
private:
|
2022-01-23 19:03:50 +00:00
|
|
|
unsigned int getHexColor(const std::string& str);
|
|
|
|
std::string resolvePlaceholders(const std::string& in);
|
|
|
|
|
2022-01-29 17:41:22 +00:00
|
|
|
static ThemeCapability parseThemeCapabilities(const std::string& path);
|
|
|
|
|
2022-10-31 18:32:13 +00:00
|
|
|
void parseIncludes(const pugi::xml_node& root);
|
|
|
|
void parseVariants(const pugi::xml_node& root);
|
|
|
|
void parseColorSchemes(const pugi::xml_node& root);
|
2023-12-20 20:58:40 +00:00
|
|
|
void parseFontSizes(const pugi::xml_node& root);
|
2024-08-31 10:52:20 +00:00
|
|
|
void parseLanguages(const pugi::xml_node& root);
|
2022-10-31 18:32:13 +00:00
|
|
|
void parseAspectRatios(const pugi::xml_node& root);
|
2023-01-15 17:24:08 +00:00
|
|
|
void parseTransitions(const pugi::xml_node& root);
|
2020-06-21 12:25:28 +00:00
|
|
|
void parseVariables(const pugi::xml_node& root);
|
2022-10-31 18:32:13 +00:00
|
|
|
void parseViews(const pugi::xml_node& root);
|
|
|
|
void parseView(const pugi::xml_node& root, ThemeView& view);
|
|
|
|
void parseElement(const pugi::xml_node& root,
|
2021-07-07 18:31:46 +00:00
|
|
|
const std::map<std::string, ElementPropertyType>& typeMap,
|
2023-07-30 16:17:27 +00:00
|
|
|
ThemeElement& element);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2024-07-13 17:14:34 +00:00
|
|
|
#if defined(GETTEXT_DUMMY_ENTRIES)
|
2024-07-04 16:53:13 +00:00
|
|
|
// This is just to get gettext msgid entries added to the PO message catalog files.
|
|
|
|
void gettextMessageCatalogEntries();
|
2024-07-13 17:14:34 +00:00
|
|
|
#endif
|
2024-07-04 16:53:13 +00:00
|
|
|
|
2022-01-29 17:41:22 +00:00
|
|
|
static std::vector<std::string> sSupportedViews;
|
2023-01-04 18:01:41 +00:00
|
|
|
static std::vector<std::string> sSupportedMediaTypes;
|
2023-01-08 16:00:36 +00:00
|
|
|
static std::vector<std::string> sSupportedTransitions;
|
|
|
|
static std::vector<std::string> sSupportedTransitionAnimations;
|
2023-12-20 20:58:40 +00:00
|
|
|
|
|
|
|
static std::vector<std::pair<std::string, std::string>> sSupportedFontSizes;
|
2022-01-31 22:22:42 +00:00
|
|
|
static std::vector<std::pair<std::string, std::string>> sSupportedAspectRatios;
|
2024-08-29 17:09:33 +00:00
|
|
|
static std::vector<std::pair<std::string, std::string>> sSupportedLanguages;
|
2022-11-01 16:08:51 +00:00
|
|
|
static std::map<std::string, float> sAspectRatioMap;
|
2022-01-29 17:41:22 +00:00
|
|
|
|
2022-02-10 23:19:08 +00:00
|
|
|
static std::map<std::string, std::map<std::string, std::string>> sPropertyAttributeMap;
|
|
|
|
static std::map<std::string, std::map<std::string, ElementPropertyType>> sElementMap;
|
|
|
|
|
2023-08-14 20:40:32 +00:00
|
|
|
static inline std::map<std::string, Theme, StringComparator> sThemes;
|
|
|
|
static inline std::map<std::string, Theme, StringComparator>::iterator sCurrentTheme {};
|
2023-02-09 23:34:24 +00:00
|
|
|
static inline std::string sVariantDefinedTransitions;
|
2022-01-29 17:41:22 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
std::map<std::string, ThemeView> mViews;
|
2022-01-29 17:41:22 +00:00
|
|
|
std::deque<std::string> mPaths;
|
|
|
|
std::vector<std::string> mVariants;
|
2022-10-31 18:32:13 +00:00
|
|
|
std::vector<std::string> mColorSchemes;
|
2023-12-20 20:58:40 +00:00
|
|
|
std::vector<std::string> mFontSizes;
|
2024-08-31 10:52:20 +00:00
|
|
|
std::vector<std::string> mLanguages;
|
2022-01-29 17:41:22 +00:00
|
|
|
std::string mSelectedVariant;
|
2023-01-04 18:01:41 +00:00
|
|
|
std::string mOverrideVariant;
|
2022-10-31 18:32:13 +00:00
|
|
|
std::string mSelectedColorScheme;
|
2023-12-20 20:58:40 +00:00
|
|
|
std::string mSelectedFontSize;
|
2023-02-09 23:34:24 +00:00
|
|
|
static inline std::string sSelectedAspectRatio;
|
|
|
|
static inline bool sAspectRatioMatch {false};
|
2024-08-29 17:09:33 +00:00
|
|
|
static inline std::string sThemeLanguage;
|
2022-10-29 11:04:00 +00:00
|
|
|
bool mCustomCollection;
|
2013-11-12 23:28:15 +00:00
|
|
|
};
|
2017-10-31 17:12:50 +00:00
|
|
|
|
|
|
|
#endif // ES_CORE_THEME_DATA_H
|