mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 06:05:38 +00:00
Added variant trigger support.
This commit is contained in:
parent
549d78dfed
commit
fa67018b72
|
@ -239,7 +239,7 @@ SystemData::SystemData(const std::string& name,
|
|||
mPlaceholder = new FileData(PLACEHOLDER, "<No Entries Found>", getSystemEnvData(), this);
|
||||
|
||||
setIsGameSystemStatus();
|
||||
loadTheme();
|
||||
loadTheme(ThemeTriggers::TriggerType::NONE);
|
||||
}
|
||||
|
||||
SystemData::~SystemData()
|
||||
|
@ -1304,7 +1304,7 @@ std::pair<unsigned int, unsigned int> SystemData::getDisplayedGameCount() const
|
|||
return mRootFolder->getGameCount();
|
||||
}
|
||||
|
||||
void SystemData::loadTheme()
|
||||
void SystemData::loadTheme(ThemeTriggers::TriggerType trigger)
|
||||
{
|
||||
mTheme = std::make_shared<ThemeData>();
|
||||
|
||||
|
@ -1354,7 +1354,7 @@ void SystemData::loadTheme()
|
|||
sysData.insert(std::pair<std::string, std::string>("system.theme.collections", "\b"));
|
||||
}
|
||||
|
||||
mTheme->loadFile(sysData, path, isCustomCollection());
|
||||
mTheme->loadFile(sysData, path, trigger, isCustomCollection());
|
||||
}
|
||||
catch (ThemeException& e) {
|
||||
LOG(LogError) << e.what() << " (system \"" << mName << "\", theme \"" << mThemeFolder
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define ES_APP_SYSTEM_DATA_H
|
||||
|
||||
#include "PlatformId.h"
|
||||
#include "ThemeData.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
@ -134,8 +135,8 @@ public:
|
|||
|
||||
void sortSystem(bool reloadGamelist = true, bool jumpToFirstRow = false);
|
||||
|
||||
// Load or re-load theme.
|
||||
void loadTheme();
|
||||
// Load or reload theme.
|
||||
void loadTheme(ThemeTriggers::TriggerType trigger);
|
||||
|
||||
FileFilterIndex* getIndex() { return mFilterIndex; }
|
||||
void onMetaDataSavePoint();
|
||||
|
|
|
@ -739,22 +739,22 @@ std::shared_ptr<GamelistView> ViewController::getGamelistView(SystemData* system
|
|||
// If there's no entry, then create it and return it.
|
||||
std::shared_ptr<GamelistView> view;
|
||||
|
||||
bool themeHasVideoView {system->getTheme()->hasView("video")};
|
||||
|
||||
// Decide which view style to use.
|
||||
GamelistViewStyle selectedViewStyle {AUTOMATIC};
|
||||
|
||||
std::string viewPreference {Settings::getInstance()->getString("GamelistViewStyle")};
|
||||
if (viewPreference == "basic")
|
||||
selectedViewStyle = BASIC;
|
||||
else if (viewPreference == "detailed")
|
||||
selectedViewStyle = DETAILED;
|
||||
else if (viewPreference == "video")
|
||||
selectedViewStyle = VIDEO;
|
||||
|
||||
if (system->getTheme()->isLegacyTheme()) {
|
||||
const bool themeHasVideoView {system->getTheme()->hasView("video")};
|
||||
|
||||
// Decide which view style to use.
|
||||
GamelistViewStyle selectedViewStyle {AUTOMATIC};
|
||||
|
||||
const std::string& viewPreference {Settings::getInstance()->getString("GamelistViewStyle")};
|
||||
if (viewPreference == "basic")
|
||||
selectedViewStyle = BASIC;
|
||||
else if (viewPreference == "detailed")
|
||||
selectedViewStyle = DETAILED;
|
||||
else if (viewPreference == "video")
|
||||
selectedViewStyle = VIDEO;
|
||||
|
||||
if (selectedViewStyle == AUTOMATIC) {
|
||||
std::vector<FileData*> files {
|
||||
const std::vector<FileData*> files {
|
||||
system->getRootFolder()->getFilesRecursive(GAME | FOLDER)};
|
||||
|
||||
for (auto it = files.cbegin(); it != files.cend(); ++it) {
|
||||
|
@ -768,29 +768,125 @@ std::shared_ptr<GamelistView> ViewController::getGamelistView(SystemData* system
|
|||
}
|
||||
}
|
||||
}
|
||||
// Create the view.
|
||||
switch (selectedViewStyle) {
|
||||
case VIDEO: {
|
||||
mState.viewstyle = VIDEO;
|
||||
break;
|
||||
}
|
||||
case DETAILED: {
|
||||
mState.viewstyle = DETAILED;
|
||||
break;
|
||||
}
|
||||
case BASIC: {
|
||||
}
|
||||
default: {
|
||||
if (!system->isGroupedCustomCollection())
|
||||
mState.viewstyle = BASIC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Variant triggers.
|
||||
const auto overrides = system->getTheme()->getCurrentThemeSetSelectedVariantOverrides();
|
||||
|
||||
// Create the view.
|
||||
switch (selectedViewStyle) {
|
||||
case VIDEO: {
|
||||
mState.viewstyle = VIDEO;
|
||||
break;
|
||||
}
|
||||
case DETAILED: {
|
||||
mState.viewstyle = DETAILED;
|
||||
break;
|
||||
}
|
||||
case BASIC: {
|
||||
}
|
||||
default: {
|
||||
if (!system->isGroupedCustomCollection())
|
||||
mState.viewstyle = BASIC;
|
||||
break;
|
||||
if (!overrides.empty()) {
|
||||
ThemeTriggers::TriggerType noVideosTriggerType {ThemeTriggers::TriggerType::NONE};
|
||||
ThemeTriggers::TriggerType noMediaTriggerType {ThemeTriggers::TriggerType::NONE};
|
||||
|
||||
const std::vector<FileData*> files {
|
||||
system->getRootFolder()->getFilesRecursive(GAME | FOLDER)};
|
||||
|
||||
if (overrides.find(ThemeTriggers::TriggerType::NO_VIDEOS) != overrides.end()) {
|
||||
noVideosTriggerType = ThemeTriggers::TriggerType::NO_VIDEOS;
|
||||
|
||||
for (auto it = files.cbegin(); it != files.cend(); ++it) {
|
||||
if (!(*it)->getVideoPath().empty()) {
|
||||
noVideosTriggerType = ThemeTriggers::TriggerType::NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (overrides.find(ThemeTriggers::TriggerType::NO_MEDIA) != overrides.end()) {
|
||||
noMediaTriggerType = ThemeTriggers::TriggerType::NO_MEDIA;
|
||||
|
||||
for (auto& imageType : overrides.at(ThemeTriggers::TriggerType::NO_MEDIA).second) {
|
||||
for (auto it = files.cbegin(); it != files.cend(); ++it) {
|
||||
if (imageType == "miximage") {
|
||||
if (!(*it)->getMiximagePath().empty()) {
|
||||
noMediaTriggerType = ThemeTriggers::TriggerType::NONE;
|
||||
goto BREAK;
|
||||
}
|
||||
}
|
||||
else if (imageType == "marquee") {
|
||||
if (!(*it)->getMarqueePath().empty()) {
|
||||
noMediaTriggerType = ThemeTriggers::TriggerType::NONE;
|
||||
goto BREAK;
|
||||
}
|
||||
}
|
||||
else if (imageType == "screenshot") {
|
||||
if (!(*it)->getScreenshotPath().empty()) {
|
||||
noMediaTriggerType = ThemeTriggers::TriggerType::NONE;
|
||||
goto BREAK;
|
||||
}
|
||||
}
|
||||
else if (imageType == "titlescreen") {
|
||||
if (!(*it)->getTitleScreenPath().empty()) {
|
||||
noMediaTriggerType = ThemeTriggers::TriggerType::NONE;
|
||||
goto BREAK;
|
||||
}
|
||||
}
|
||||
else if (imageType == "cover") {
|
||||
if (!(*it)->getCoverPath().empty()) {
|
||||
noMediaTriggerType = ThemeTriggers::TriggerType::NONE;
|
||||
goto BREAK;
|
||||
}
|
||||
}
|
||||
else if (imageType == "backcover") {
|
||||
if (!(*it)->getBackCoverPath().empty()) {
|
||||
noMediaTriggerType = ThemeTriggers::TriggerType::NONE;
|
||||
goto BREAK;
|
||||
}
|
||||
}
|
||||
else if (imageType == "3dbox") {
|
||||
if (!(*it)->get3DBoxPath().empty()) {
|
||||
noMediaTriggerType = ThemeTriggers::TriggerType::NONE;
|
||||
goto BREAK;
|
||||
}
|
||||
}
|
||||
else if (imageType == "physicalmedia") {
|
||||
if (!(*it)->getPhysicalMediaPath().empty()) {
|
||||
noMediaTriggerType = ThemeTriggers::TriggerType::NONE;
|
||||
goto BREAK;
|
||||
}
|
||||
}
|
||||
else if (imageType == "fanart") {
|
||||
if (!(*it)->getFanArtPath().empty()) {
|
||||
noMediaTriggerType = ThemeTriggers::TriggerType::NONE;
|
||||
goto BREAK;
|
||||
}
|
||||
}
|
||||
else if (imageType == "video") {
|
||||
if (!(*it)->getVideoPath().empty()) {
|
||||
noMediaTriggerType = ThemeTriggers::TriggerType::NONE;
|
||||
goto BREAK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BREAK:
|
||||
// noMedia takes precedence over the noVideos trigger.
|
||||
if (noMediaTriggerType == ThemeTriggers::TriggerType::NO_MEDIA)
|
||||
system->loadTheme(noMediaTriggerType);
|
||||
else
|
||||
system->loadTheme(noVideosTriggerType);
|
||||
}
|
||||
}
|
||||
|
||||
view = std::shared_ptr<GamelistView>(new GamelistView(system->getRootFolder()));
|
||||
|
||||
view->setTheme(system->getTheme());
|
||||
|
||||
std::vector<SystemData*>& sysVec = SystemData::sSystemVector;
|
||||
|
@ -970,7 +1066,7 @@ void ViewController::preload()
|
|||
|
||||
// Load navigation sounds, either from the theme if it supports it, or otherwise from
|
||||
// the bundled fallback sound files.
|
||||
bool themeSoundSupport = false;
|
||||
bool themeSoundSupport {false};
|
||||
for (SystemData* system : SystemData::sSystemVector) {
|
||||
if (system->getTheme()->hasView("all")) {
|
||||
NavigationSounds::getInstance().loadThemeNavigationSounds(system->getTheme().get());
|
||||
|
@ -1000,7 +1096,7 @@ void ViewController::reloadGamelistView(GamelistView* view, bool reloadTheme)
|
|||
mCurrentView = nullptr;
|
||||
|
||||
if (reloadTheme)
|
||||
system->loadTheme();
|
||||
system->loadTheme(ThemeTriggers::TriggerType::NONE);
|
||||
system->getIndex()->setKidModeFilters();
|
||||
std::shared_ptr<GamelistView> newView {getGamelistView(system)};
|
||||
|
||||
|
@ -1047,15 +1143,18 @@ void ViewController::reloadAll()
|
|||
|
||||
// Load themes, create GamelistViews and reset filters.
|
||||
for (auto it = cursorMap.cbegin(); it != cursorMap.cend(); ++it) {
|
||||
it->first->loadTheme();
|
||||
it->first->loadTheme(ThemeTriggers::TriggerType::NONE);
|
||||
it->first->getIndex()->resetFilters();
|
||||
getGamelistView(it->first)->setCursor(it->second);
|
||||
}
|
||||
|
||||
// Rebuild SystemListView.
|
||||
mSystemListView.reset();
|
||||
getSystemListView();
|
||||
|
||||
// Restore cursor positions for all systems.
|
||||
for (auto it = cursorMap.cbegin(); it != cursorMap.cend(); ++it)
|
||||
getGamelistView(it->first)->setCursor(it->second);
|
||||
|
||||
// Update mCurrentView since the pointers changed.
|
||||
if (mState.viewing == GAMELIST) {
|
||||
mCurrentView = getGamelistView(mState.getSystem());
|
||||
|
@ -1073,7 +1172,7 @@ void ViewController::reloadAll()
|
|||
// Load navigation sounds, either from the theme if it supports it, or otherwise from
|
||||
// the bundled fallback sound files.
|
||||
NavigationSounds::getInstance().deinit();
|
||||
bool themeSoundSupport = false;
|
||||
bool themeSoundSupport {false};
|
||||
for (SystemData* system : SystemData::sSystemVector) {
|
||||
if (system->getTheme()->hasView("all")) {
|
||||
NavigationSounds::getInstance().loadThemeNavigationSounds(system->getTheme().get());
|
||||
|
|
|
@ -28,6 +28,18 @@ std::vector<std::string> ThemeData::sSupportedViews {
|
|||
{"system"},
|
||||
{"gamelist"}};
|
||||
|
||||
std::vector<std::string> ThemeData::sSupportedMediaTypes {
|
||||
{"miximage"},
|
||||
{"marquee"},
|
||||
{"screenshot"},
|
||||
{"titlescreen"},
|
||||
{"cover"},
|
||||
{"backcover"},
|
||||
{"3dbox"},
|
||||
{"physicalmedia"},
|
||||
{"fanart"},
|
||||
{"video"}};
|
||||
|
||||
std::vector<std::string> ThemeData::sLegacySupportedViews {
|
||||
{"all"},
|
||||
{"system"},
|
||||
|
@ -497,9 +509,11 @@ ThemeData::ThemeData()
|
|||
|
||||
void ThemeData::loadFile(const std::map<std::string, std::string>& sysDataMap,
|
||||
const std::string& path,
|
||||
const ThemeTriggers::TriggerType trigger,
|
||||
const bool customCollection)
|
||||
{
|
||||
mCustomCollection = customCollection;
|
||||
mOverrideVariant = "";
|
||||
|
||||
mPaths.push_back(path);
|
||||
|
||||
|
@ -565,6 +579,12 @@ void ThemeData::loadFile(const std::map<std::string, std::string>& sysDataMap,
|
|||
mSelectedVariant = mVariants.front();
|
||||
// Special shortcut variant to apply configuration to all defined variants.
|
||||
mVariants.emplace_back("all");
|
||||
|
||||
if (trigger != ThemeTriggers::TriggerType::NONE) {
|
||||
auto overrides = getCurrentThemeSetSelectedVariantOverrides();
|
||||
if (overrides.find(trigger) != overrides.end())
|
||||
mOverrideVariant = overrides.at(trigger).first;
|
||||
}
|
||||
}
|
||||
|
||||
if (mCurrentThemeSet->second.capabilities.colorSchemes.size() > 0) {
|
||||
|
@ -809,6 +829,21 @@ const std::string ThemeData::getAspectRatioLabel(const std::string& aspectRatio)
|
|||
return "invalid ratio";
|
||||
}
|
||||
|
||||
const std::map<ThemeTriggers::TriggerType, std::pair<std::string, std::vector<std::string>>>
|
||||
ThemeData::getCurrentThemeSetSelectedVariantOverrides()
|
||||
{
|
||||
const auto variantIter = std::find_if(
|
||||
mCurrentThemeSet->second.capabilities.variants.cbegin(),
|
||||
mCurrentThemeSet->second.capabilities.variants.cend(),
|
||||
[this](ThemeVariant currVariant) { return currVariant.name == mSelectedVariant; });
|
||||
|
||||
if (variantIter != mCurrentThemeSet->second.capabilities.variants.cend() &&
|
||||
!(*variantIter).overrides.empty())
|
||||
return (*variantIter).overrides;
|
||||
else
|
||||
return ThemeVariant().overrides;
|
||||
}
|
||||
|
||||
unsigned int ThemeData::getHexColor(const std::string& str)
|
||||
{
|
||||
ThemeException error;
|
||||
|
@ -816,20 +851,20 @@ unsigned int ThemeData::getHexColor(const std::string& str)
|
|||
if (str == "")
|
||||
throw error << "Empty color property";
|
||||
|
||||
size_t len {str.size()};
|
||||
if (len != 6 && len != 8)
|
||||
const size_t length {str.size()};
|
||||
if (length != 6 && length != 8)
|
||||
throw error << "Invalid color property \"" << str
|
||||
<< "\" (must be 6 or 8 characters in length)";
|
||||
|
||||
unsigned int val;
|
||||
unsigned int value;
|
||||
std::stringstream ss;
|
||||
ss << str;
|
||||
ss >> std::hex >> val;
|
||||
ss >> std::hex >> value;
|
||||
|
||||
if (len == 6)
|
||||
val = (val << 8) | 0xFF;
|
||||
if (length == 6)
|
||||
value = (value << 8) | 0xFF;
|
||||
|
||||
return val;
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string ThemeData::resolvePlaceholders(const std::string& in)
|
||||
|
@ -854,18 +889,19 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
{
|
||||
ThemeCapability capabilities;
|
||||
std::vector<std::string> aspectRatiosTemp;
|
||||
bool hasTriggers {false};
|
||||
|
||||
std::string capFile {path + "/capabilities.xml"};
|
||||
const std::string capFile {path + "/capabilities.xml"};
|
||||
|
||||
if (Utils::FileSystem::isRegularFile(capFile) || Utils::FileSystem::isSymlink(capFile)) {
|
||||
capabilities.legacyTheme = false;
|
||||
|
||||
pugi::xml_document doc;
|
||||
#if defined(_WIN64)
|
||||
pugi::xml_parse_result res {
|
||||
const pugi::xml_parse_result& res {
|
||||
doc.load_file(Utils::String::stringToWideString(capFile).c_str())};
|
||||
#else
|
||||
pugi::xml_parse_result res {doc.load_file(capFile.c_str())};
|
||||
const pugi::xml_parse_result& res {doc.load_file(capFile.c_str())};
|
||||
#endif
|
||||
if (res.status == pugi::status_no_document_element) {
|
||||
LOG(LogDebug) << "Found a capabilities.xml file with no configuration";
|
||||
|
@ -874,7 +910,7 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
LOG(LogError) << "Couldn't parse capabilities.xml: " << res.description();
|
||||
return capabilities;
|
||||
}
|
||||
pugi::xml_node themeCapabilities {doc.child("themeCapabilities")};
|
||||
const pugi::xml_node& themeCapabilities {doc.child("themeCapabilities")};
|
||||
if (!themeCapabilities) {
|
||||
LOG(LogError) << "Missing <themeCapabilities> tag in capabilities.xml";
|
||||
return capabilities;
|
||||
|
@ -882,7 +918,7 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
|
||||
for (pugi::xml_node aspectRatio {themeCapabilities.child("aspectRatio")}; aspectRatio;
|
||||
aspectRatio = aspectRatio.next_sibling("aspectRatio")) {
|
||||
std::string value {aspectRatio.text().get()};
|
||||
const std::string& value {aspectRatio.text().get()};
|
||||
if (std::find_if(sSupportedAspectRatios.cbegin(), sSupportedAspectRatios.cend(),
|
||||
[&value](const std::pair<std::string, std::string>& entry) {
|
||||
return entry.first == value;
|
||||
|
@ -906,7 +942,7 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
for (pugi::xml_node variant {themeCapabilities.child("variant")}; variant;
|
||||
variant = variant.next_sibling("variant")) {
|
||||
ThemeVariant readVariant;
|
||||
std::string name {variant.attribute("name").as_string()};
|
||||
const std::string& name {variant.attribute("name").as_string()};
|
||||
if (name.empty()) {
|
||||
LOG(LogWarning)
|
||||
<< "Found <variant> tag without name attribute, ignoring entry in \"" << capFile
|
||||
|
@ -921,7 +957,7 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
readVariant.name = name;
|
||||
}
|
||||
|
||||
pugi::xml_node labelTag {variant.child("label")};
|
||||
const pugi::xml_node& labelTag {variant.child("label")};
|
||||
if (labelTag == nullptr) {
|
||||
LOG(LogDebug)
|
||||
<< "No variant <label> tag found, setting label value to the variant name \""
|
||||
|
@ -929,7 +965,7 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
readVariant.label = name;
|
||||
}
|
||||
else {
|
||||
std::string labelValue {labelTag.text().as_string()};
|
||||
const std::string& labelValue {labelTag.text().as_string()};
|
||||
if (labelValue == "") {
|
||||
LOG(LogWarning) << "No variant <label> value defined, setting value to "
|
||||
"the variant name \""
|
||||
|
@ -941,9 +977,9 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
}
|
||||
}
|
||||
|
||||
pugi::xml_node selectableTag {variant.child("selectable")};
|
||||
const pugi::xml_node& selectableTag {variant.child("selectable")};
|
||||
if (selectableTag != nullptr) {
|
||||
std::string value {selectableTag.text().as_string()};
|
||||
const std::string& value {selectableTag.text().as_string()};
|
||||
if (value.front() == '0' || value.front() == 'f' || value.front() == 'F' ||
|
||||
value.front() == 'n' || value.front() == 'N')
|
||||
readVariant.selectable = false;
|
||||
|
@ -951,37 +987,82 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
readVariant.selectable = true;
|
||||
}
|
||||
|
||||
pugi::xml_node overrideTag {variant.child("override")};
|
||||
if (overrideTag != nullptr) {
|
||||
pugi::xml_node triggerTag {overrideTag.child("trigger")};
|
||||
if (triggerTag != nullptr) {
|
||||
std::string triggerValue {triggerTag.text().as_string()};
|
||||
if (triggerValue == "") {
|
||||
LOG(LogWarning)
|
||||
<< "No <trigger> tag value defined for variant \"" << readVariant.name
|
||||
<< "\", ignoring entry in \"" << capFile << "\"";
|
||||
}
|
||||
else {
|
||||
pugi::xml_node useVariantTag {overrideTag.child("useVariant")};
|
||||
if (useVariantTag != nullptr) {
|
||||
std::string useVariantValue {useVariantTag.text().as_string()};
|
||||
if (useVariantValue == "") {
|
||||
LOG(LogWarning)
|
||||
<< "No <useVariant> tag value defined for variant \""
|
||||
<< readVariant.name << "\", ignoring entry in \"" << capFile
|
||||
<< "\"";
|
||||
}
|
||||
else {
|
||||
readVariant.override = true;
|
||||
readVariant.overrideTrigger = triggerValue;
|
||||
readVariant.overrideVariant = useVariantValue;
|
||||
for (pugi::xml_node overrideTag {variant.child("override")}; overrideTag;
|
||||
overrideTag = overrideTag.next_sibling("override")) {
|
||||
if (overrideTag != nullptr) {
|
||||
std::vector<std::string> mediaTypes;
|
||||
const pugi::xml_node& mediaTypeTag {overrideTag.child("mediaType")};
|
||||
if (mediaTypeTag != nullptr) {
|
||||
std::string mediaTypeValue {mediaTypeTag.text().as_string()};
|
||||
for (auto& character : mediaTypeValue) {
|
||||
if (std::isspace(character))
|
||||
character = ',';
|
||||
}
|
||||
mediaTypeValue = Utils::String::replace(mediaTypeValue, ",,", ",");
|
||||
mediaTypes = Utils::String::delimitedStringToVector(mediaTypeValue, ",");
|
||||
|
||||
for (std::string& type : mediaTypes) {
|
||||
if (std::find(sSupportedMediaTypes.cbegin(),
|
||||
sSupportedMediaTypes.cend(),
|
||||
type) == sSupportedMediaTypes.cend()) {
|
||||
LOG(LogError) << "ThemeData::parseThemeCapabilities(): Invalid "
|
||||
"override configuration, unsupported "
|
||||
"\"mediaType\" value \""
|
||||
<< type << "\"";
|
||||
mediaTypes.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const pugi::xml_node& triggerTag {overrideTag.child("trigger")};
|
||||
if (triggerTag != nullptr) {
|
||||
const std::string& triggerValue {triggerTag.text().as_string()};
|
||||
if (triggerValue == "") {
|
||||
LOG(LogWarning) << "No <trigger> tag value defined for variant \""
|
||||
<< readVariant.name << "\", ignoring entry in \""
|
||||
<< capFile << "\"";
|
||||
}
|
||||
else if (triggerValue != "noVideos" && triggerValue != "noMedia") {
|
||||
LOG(LogWarning) << "Invalid <useVariant> tag value \"" << triggerValue
|
||||
<< "\" defined for variant \"" << readVariant.name
|
||||
<< "\", ignoring entry in \"" << capFile << "\"";
|
||||
}
|
||||
else {
|
||||
LOG(LogWarning) << "Found an <override> tag without a corresponding "
|
||||
"<useVariant> tag, "
|
||||
<< "ignoring entry for variant \"" << readVariant.name
|
||||
<< "\" in \"" << capFile << "\"";
|
||||
const pugi::xml_node& useVariantTag {overrideTag.child("useVariant")};
|
||||
if (useVariantTag != nullptr) {
|
||||
const std::string& useVariantValue {
|
||||
useVariantTag.text().as_string()};
|
||||
if (useVariantValue == "") {
|
||||
LOG(LogWarning)
|
||||
<< "No <useVariant> tag value defined for variant \""
|
||||
<< readVariant.name << "\", ignoring entry in \"" << capFile
|
||||
<< "\"";
|
||||
}
|
||||
else {
|
||||
hasTriggers = true;
|
||||
if (triggerValue == "noVideos") {
|
||||
readVariant
|
||||
.overrides[ThemeTriggers::TriggerType::NO_VIDEOS] =
|
||||
std::make_pair(useVariantValue,
|
||||
std::vector<std::string>());
|
||||
}
|
||||
else if (triggerValue == "noMedia") {
|
||||
if (mediaTypes.empty())
|
||||
mediaTypes.emplace_back("miximage");
|
||||
readVariant
|
||||
.overrides[ThemeTriggers::TriggerType::NO_MEDIA] =
|
||||
std::make_pair(useVariantValue, mediaTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG(LogWarning)
|
||||
<< "Found an <override> tag without a corresponding "
|
||||
"<useVariant> tag, "
|
||||
<< "ignoring entry for variant \"" << readVariant.name
|
||||
<< "\" in \"" << capFile << "\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1012,7 +1093,7 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
for (pugi::xml_node colorScheme {themeCapabilities.child("colorScheme")}; colorScheme;
|
||||
colorScheme = colorScheme.next_sibling("colorScheme")) {
|
||||
ThemeColorScheme readColorScheme;
|
||||
std::string name {colorScheme.attribute("name").as_string()};
|
||||
const std::string& name {colorScheme.attribute("name").as_string()};
|
||||
if (name.empty()) {
|
||||
LOG(LogWarning)
|
||||
<< "Found <colorScheme> tag without name attribute, ignoring entry in \""
|
||||
|
@ -1022,7 +1103,7 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
readColorScheme.name = name;
|
||||
}
|
||||
|
||||
pugi::xml_node labelTag {colorScheme.child("label")};
|
||||
const pugi::xml_node& labelTag {colorScheme.child("label")};
|
||||
if (labelTag == nullptr) {
|
||||
LOG(LogDebug) << "No colorScheme <label> tag found, setting label value to the "
|
||||
"color scheme name \""
|
||||
|
@ -1030,7 +1111,7 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
readColorScheme.label = name;
|
||||
}
|
||||
else {
|
||||
std::string labelValue {labelTag.text().as_string()};
|
||||
const std::string& labelValue {labelTag.text().as_string()};
|
||||
if (labelValue == "") {
|
||||
LOG(LogWarning) << "No colorScheme <label> value defined, setting value to "
|
||||
"the color scheme name \""
|
||||
|
@ -1077,6 +1158,28 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
|
|||
}
|
||||
}
|
||||
|
||||
if (hasTriggers) {
|
||||
for (auto& variant : capabilities.variants) {
|
||||
for (auto it = variant.overrides.begin(); it != variant.overrides.end();) {
|
||||
const auto variantIter =
|
||||
std::find_if(capabilities.variants.begin(), capabilities.variants.end(),
|
||||
[it](ThemeVariant currVariant) {
|
||||
return currVariant.name == (*it).second.first;
|
||||
});
|
||||
if (variantIter == capabilities.variants.end()) {
|
||||
LOG(LogWarning)
|
||||
<< "The <useVariant> tag value \"" << (*it).second.first
|
||||
<< "\" does not match any defined variants, ignoring entry in \"" << capFile
|
||||
<< "\"";
|
||||
it = variant.overrides.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
|
@ -1214,7 +1317,10 @@ void ThemeData::parseVariants(const pugi::xml_node& root)
|
|||
<< "\" is not defined in capabilities.xml";
|
||||
}
|
||||
|
||||
if (mSelectedVariant == viewKey || viewKey == "all") {
|
||||
const std::string variant {mOverrideVariant.empty() ? mSelectedVariant :
|
||||
mOverrideVariant};
|
||||
|
||||
if (variant == viewKey || viewKey == "all") {
|
||||
parseVariables(node);
|
||||
parseColorSchemes(node);
|
||||
parseIncludes(node);
|
||||
|
|
|
@ -66,6 +66,15 @@ namespace ThemeFlags
|
|||
// clang-format on
|
||||
} // namespace ThemeFlags
|
||||
|
||||
namespace ThemeTriggers
|
||||
{
|
||||
enum class TriggerType {
|
||||
NONE,
|
||||
NO_VIDEOS,
|
||||
NO_MEDIA
|
||||
};
|
||||
} // namespace ThemeTriggers
|
||||
|
||||
class ThemeException : public std::exception
|
||||
{
|
||||
public:
|
||||
|
@ -175,13 +184,11 @@ public:
|
|||
std::string name;
|
||||
std::string label;
|
||||
bool selectable;
|
||||
bool override;
|
||||
std::string overrideTrigger;
|
||||
std::string overrideVariant;
|
||||
std::map<ThemeTriggers::TriggerType, std::pair<std::string, std::vector<std::string>>>
|
||||
overrides;
|
||||
|
||||
ThemeVariant()
|
||||
: selectable {false}
|
||||
, override {false}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -218,6 +225,7 @@ public:
|
|||
|
||||
void loadFile(const std::map<std::string, std::string>& sysDataMap,
|
||||
const std::string& path,
|
||||
const ThemeTriggers::TriggerType trigger,
|
||||
const bool customCollection);
|
||||
bool hasView(const std::string& view);
|
||||
ThemeView& getViewElements(std::string view) { return mViews[view]; }
|
||||
|
@ -239,6 +247,8 @@ public:
|
|||
const static std::string getCurrentThemeSetName() { return mCurrentThemeSet->first; }
|
||||
|
||||
const bool isLegacyTheme() { return mLegacyTheme; }
|
||||
const std::map<ThemeTriggers::TriggerType, std::pair<std::string, std::vector<std::string>>>
|
||||
getCurrentThemeSetSelectedVariantOverrides();
|
||||
|
||||
enum ElementPropertyType {
|
||||
NORMALIZED_RECT,
|
||||
|
@ -280,6 +290,7 @@ private:
|
|||
const LegacyWorkaround legacyWorkaround);
|
||||
|
||||
static std::vector<std::string> sSupportedViews;
|
||||
static std::vector<std::string> sSupportedMediaTypes;
|
||||
static std::vector<std::string> sLegacySupportedViews;
|
||||
static std::vector<std::string> sLegacySupportedFeatures;
|
||||
static std::vector<std::string> sLegacyProperties;
|
||||
|
@ -298,6 +309,7 @@ private:
|
|||
std::vector<std::string> mVariants;
|
||||
std::vector<std::string> mColorSchemes;
|
||||
std::string mSelectedVariant;
|
||||
std::string mOverrideVariant;
|
||||
std::string mSelectedColorScheme;
|
||||
std::string mSelectedAspectRatio;
|
||||
bool mLegacyTheme;
|
||||
|
|
Loading…
Reference in a new issue