Completely removed support for legacy EmulationStation theme sets

This commit is contained in:
Leon Styhre 2023-07-30 18:17:27 +02:00
parent d0fc8cd56e
commit ed1e11418b
28 changed files with 949 additions and 2797 deletions

View file

@ -55,7 +55,6 @@ set(ES_HEADERS
# Views
${CMAKE_CURRENT_SOURCE_DIR}/src/views/GamelistBase.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/GamelistLegacy.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/GamelistView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/SystemView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/ViewController.h

View file

@ -152,8 +152,6 @@ void GuiMenu::openUIOptions()
// If required, abbreviate the theme set name so it doesn't overlap the setting name.
const float maxNameLength {mSize.x * 0.62f};
std::string themeName {(*it).first};
if ((*it).second.second.capabilities.legacyTheme)
themeName.append(" [LEGACY]");
themeSet->add(themeName, it->second.first, (*it).second.first == selectedSet->first,
maxNameLength);
}
@ -217,10 +215,7 @@ void GuiMenu::openUIOptions()
themeVariant->selectEntry(0);
}
else {
if (currentSet->second.capabilities.legacyTheme)
themeVariant->add("Legacy theme set", "none", true);
else
themeVariant->add("None defined", "none", true);
themeVariant->add("None defined", "none", true);
themeVariant->setEnabled(false);
themeVariant->setOpacity(DISABLED_OPACITY);
themeVariant->getParent()
@ -266,10 +261,7 @@ void GuiMenu::openUIOptions()
themeColorScheme->selectEntry(0);
}
else {
if (currentSet->second.capabilities.legacyTheme)
themeColorScheme->add("Legacy theme set", "none", true);
else
themeColorScheme->add("None defined", "none", true);
themeColorScheme->add("None defined", "none", true);
themeColorScheme->setEnabled(false);
themeColorScheme->setOpacity(DISABLED_OPACITY);
themeColorScheme->getParent()
@ -311,10 +303,7 @@ void GuiMenu::openUIOptions()
themeAspectRatio->selectEntry(0);
}
else {
if (currentSet->second.capabilities.legacyTheme)
themeAspectRatio->add("Legacy theme set", "none", true);
else
themeAspectRatio->add("None defined", "none", true);
themeAspectRatio->add("None defined", "none", true);
themeAspectRatio->setEnabled(false);
themeAspectRatio->setOpacity(DISABLED_OPACITY);
themeAspectRatio->getParent()
@ -353,8 +342,56 @@ void GuiMenu::openUIOptions()
return;
// We need to recreate the OptionListComponent entries.
themeTransitions->clearEntries();
if (currentSet->second.capabilities.legacyTheme) {
themeTransitions->add("Legacy theme set", "automatic", true);
themeTransitions->add("AUTOMATIC", "automatic", "automatic" == selectedThemeTransitions);
if (currentSet->second.capabilities.transitions.size() == 1 &&
currentSet->second.capabilities.transitions.front().selectable) {
std::string label;
if (currentSet->second.capabilities.transitions.front().label == "")
label = "THEME PROFILE";
else
label = currentSet->second.capabilities.transitions.front().label;
const std::string transitions {
currentSet->second.capabilities.transitions.front().name};
themeTransitions->add(label, transitions, transitions == selectedThemeTransitions);
}
else {
for (size_t i {0}; i < currentSet->second.capabilities.transitions.size(); ++i) {
if (!currentSet->second.capabilities.transitions[i].selectable)
continue;
std::string label;
if (currentSet->second.capabilities.transitions[i].label == "")
label = "THEME PROFILE " + std::to_string(i + 1);
else
label = currentSet->second.capabilities.transitions[i].label;
const std::string transitions {currentSet->second.capabilities.transitions[i].name};
themeTransitions->add(label, transitions, transitions == selectedThemeTransitions);
}
}
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
"builtin-instant") ==
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
themeTransitions->add("INSTANT (BUILT-IN)", "builtin-instant",
"builtin-instant" == selectedThemeTransitions);
}
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
"builtin-slide") ==
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
themeTransitions->add("SLIDE (BUILT-IN)", "builtin-slide",
"builtin-slide" == selectedThemeTransitions);
}
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
"builtin-fade") ==
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
themeTransitions->add("FADE (BUILT-IN)", "builtin-fade",
"builtin-fade" == selectedThemeTransitions);
}
if (themeTransitions->getSelectedObjects().size() == 0)
themeTransitions->selectEntry(0);
if (themeTransitions->getNumEntries() == 1) {
themeTransitions->setEnabled(false);
themeTransitions->setOpacity(DISABLED_OPACITY);
themeTransitions->getParent()
@ -362,128 +399,17 @@ void GuiMenu::openUIOptions()
->setOpacity(DISABLED_OPACITY);
}
else {
themeTransitions->add("AUTOMATIC", "automatic",
"automatic" == selectedThemeTransitions);
if (currentSet->second.capabilities.transitions.size() == 1 &&
currentSet->second.capabilities.transitions.front().selectable) {
std::string label;
if (currentSet->second.capabilities.transitions.front().label == "")
label = "THEME PROFILE";
else
label = currentSet->second.capabilities.transitions.front().label;
const std::string transitions {
currentSet->second.capabilities.transitions.front().name};
themeTransitions->add(label, transitions, transitions == selectedThemeTransitions);
}
else {
for (size_t i {0}; i < currentSet->second.capabilities.transitions.size(); ++i) {
if (!currentSet->second.capabilities.transitions[i].selectable)
continue;
std::string label;
if (currentSet->second.capabilities.transitions[i].label == "")
label = "THEME PROFILE " + std::to_string(i + 1);
else
label = currentSet->second.capabilities.transitions[i].label;
const std::string transitions {
currentSet->second.capabilities.transitions[i].name};
themeTransitions->add(label, transitions,
transitions == selectedThemeTransitions);
}
}
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
"builtin-instant") ==
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
themeTransitions->add("INSTANT (BUILT-IN)", "builtin-instant",
"builtin-instant" == selectedThemeTransitions);
}
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
"builtin-slide") ==
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
themeTransitions->add("SLIDE (BUILT-IN)", "builtin-slide",
"builtin-slide" == selectedThemeTransitions);
}
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
"builtin-fade") ==
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
themeTransitions->add("FADE (BUILT-IN)", "builtin-fade",
"builtin-fade" == selectedThemeTransitions);
}
if (themeTransitions->getSelectedObjects().size() == 0)
themeTransitions->selectEntry(0);
if (themeTransitions->getNumEntries() == 1) {
themeTransitions->setEnabled(false);
themeTransitions->setOpacity(DISABLED_OPACITY);
themeTransitions->getParent()
->getChild(themeTransitions->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
else {
themeTransitions->setEnabled(true);
themeTransitions->setOpacity(1.0f);
themeTransitions->getParent()
->getChild(themeTransitions->getChildIndex() - 1)
->setOpacity(1.0f);
}
themeTransitions->setEnabled(true);
themeTransitions->setOpacity(1.0f);
themeTransitions->getParent()
->getChild(themeTransitions->getChildIndex() - 1)
->setOpacity(1.0f);
}
};
themeTransitionsFunc(Settings::getInstance()->getString("ThemeSet"),
Settings::getInstance()->getString("ThemeTransitions"));
// Legacy gamelist view style.
auto gamelistViewStyle = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "LEGACY GAMELIST VIEW STYLE", false);
std::string selectedViewStyle {Settings::getInstance()->getString("GamelistViewStyle")};
gamelistViewStyle->add("AUTOMATIC", "automatic", selectedViewStyle == "automatic");
gamelistViewStyle->add("BASIC", "basic", selectedViewStyle == "basic");
gamelistViewStyle->add("DETAILED", "detailed", selectedViewStyle == "detailed");
gamelistViewStyle->add("VIDEO", "video", selectedViewStyle == "video");
// If there are no objects returned, then there must be a manually modified entry in the
// configuration file. Simply set the view style to "automatic" in this case.
if (gamelistViewStyle->getSelectedObjects().size() == 0)
gamelistViewStyle->selectEntry(0);
s->addWithLabel("LEGACY GAMELIST VIEW STYLE", gamelistViewStyle);
s->addSaveFunc([gamelistViewStyle, s] {
if (gamelistViewStyle->getSelected() !=
Settings::getInstance()->getString("GamelistViewStyle")) {
Settings::getInstance()->setString("GamelistViewStyle",
gamelistViewStyle->getSelected());
s->setNeedsSaving();
s->setNeedsReloading();
s->setInvalidateCachedBackground();
}
});
// Legacy theme transitions.
auto legacyThemeTransitions = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "LEGACY THEME TRANSITIONS", false);
const std::string& selectedLegacyThemeTransitions {
Settings::getInstance()->getString("LegacyThemeTransitions")};
legacyThemeTransitions->add("INSTANT", "builtin-instant",
selectedLegacyThemeTransitions == "builtin-instant");
legacyThemeTransitions->add("SLIDE", "builtin-slide",
selectedLegacyThemeTransitions == "builtin-slide");
legacyThemeTransitions->add("FADE", "builtin-fade",
selectedLegacyThemeTransitions == "builtin-fade");
// If there are no objects returned, then there must be a manually modified entry in the
// configuration file. Simply set legacy theme transitions to "builtin-instant" in this case.
if (legacyThemeTransitions->getSelectedObjects().size() == 0)
legacyThemeTransitions->selectEntry(0);
s->addWithLabel("LEGACY THEME TRANSITIONS", legacyThemeTransitions);
s->addSaveFunc([legacyThemeTransitions, s] {
if (legacyThemeTransitions->getSelected() !=
Settings::getInstance()->getString("LegacyThemeTransitions")) {
Settings::getInstance()->setString("LegacyThemeTransitions",
legacyThemeTransitions->getSelected());
ThemeData::setThemeTransitions();
s->setNeedsSaving();
}
});
// Quick system select (navigate between systems in the gamelist view).
auto quickSystemSelect = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "QUICK SYSTEM SELECT", false);
@ -807,32 +733,6 @@ void GuiMenu::openUIOptions()
});
}
// Display pillarboxes (and letterboxes) for videos in the gamelists.
auto gamelistVideoPillarbox = std::make_shared<SwitchComponent>();
gamelistVideoPillarbox->setState(Settings::getInstance()->getBool("GamelistVideoPillarbox"));
s->addWithLabel("DISPLAY PILLARBOXES FOR GAMELIST VIDEOS", gamelistVideoPillarbox);
s->addSaveFunc([gamelistVideoPillarbox, s] {
if (gamelistVideoPillarbox->getState() !=
Settings::getInstance()->getBool("GamelistVideoPillarbox")) {
Settings::getInstance()->setBool("GamelistVideoPillarbox",
gamelistVideoPillarbox->getState());
s->setNeedsSaving();
}
});
// Render scanlines for videos in the gamelists.
auto gamelistVideoScanlines = std::make_shared<SwitchComponent>();
gamelistVideoScanlines->setState(Settings::getInstance()->getBool("GamelistVideoScanlines"));
s->addWithLabel("RENDER SCANLINES FOR GAMELIST VIDEOS", gamelistVideoScanlines);
s->addSaveFunc([gamelistVideoScanlines, s] {
if (gamelistVideoScanlines->getState() !=
Settings::getInstance()->getBool("GamelistVideoScanlines")) {
Settings::getInstance()->setBool("GamelistVideoScanlines",
gamelistVideoScanlines->getState());
s->setNeedsSaving();
}
});
// Sort folders on top of the gamelists.
auto foldersOnTop = std::make_shared<SwitchComponent>();
foldersOnTop->setState(Settings::getInstance()->getBool("FoldersOnTop"));
@ -948,7 +848,7 @@ void GuiMenu::openUIOptions()
if (variant.selectable)
++selectableVariants;
}
if (!selectedSet->second.capabilities.legacyTheme && selectableVariants > 0) {
if (selectableVariants > 0) {
themeVariant->setEnabled(true);
themeVariant->setOpacity(1.0f);
themeVariant->getParent()
@ -962,8 +862,7 @@ void GuiMenu::openUIOptions()
->getChild(themeVariant->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
if (!selectedSet->second.capabilities.legacyTheme &&
selectedSet->second.capabilities.colorSchemes.size() > 0) {
if (selectedSet->second.capabilities.colorSchemes.size() > 0) {
themeColorScheme->setEnabled(true);
themeColorScheme->setOpacity(1.0f);
themeColorScheme->getParent()
@ -977,8 +876,7 @@ void GuiMenu::openUIOptions()
->getChild(themeColorScheme->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
if (!selectedSet->second.capabilities.legacyTheme &&
selectedSet->second.capabilities.aspectRatios.size() > 0) {
if (selectedSet->second.capabilities.aspectRatios.size() > 0) {
themeAspectRatio->setEnabled(true);
themeAspectRatio->setOpacity(1.0f);
themeAspectRatio->getParent()
@ -992,64 +890,6 @@ void GuiMenu::openUIOptions()
->getChild(themeAspectRatio->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
if (!selectedSet->second.capabilities.legacyTheme) {
gamelistViewStyle->setEnabled(false);
gamelistViewStyle->setOpacity(DISABLED_OPACITY);
gamelistViewStyle->getParent()
->getChild(gamelistViewStyle->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
legacyThemeTransitions->setEnabled(false);
legacyThemeTransitions->setOpacity(DISABLED_OPACITY);
legacyThemeTransitions->getParent()
->getChild(legacyThemeTransitions->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
// Pillarboxes are theme-controlled for newer themes.
gamelistVideoPillarbox->setEnabled(false);
gamelistVideoPillarbox->setOpacity(DISABLED_OPACITY);
gamelistVideoPillarbox->getParent()
->getChild(gamelistVideoPillarbox->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
// Scanlines are theme-controlled for newer themes.
gamelistVideoScanlines->setEnabled(false);
gamelistVideoScanlines->setOpacity(DISABLED_OPACITY);
gamelistVideoScanlines->getParent()
->getChild(gamelistVideoScanlines->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
else {
gamelistViewStyle->setEnabled(true);
gamelistViewStyle->setOpacity(1.0f);
gamelistViewStyle->getParent()
->getChild(gamelistViewStyle->getChildIndex() - 1)
->setOpacity(1.0f);
themeTransitions->setEnabled(false);
themeTransitions->setOpacity(DISABLED_OPACITY);
themeTransitions->getParent()
->getChild(themeTransitions->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
legacyThemeTransitions->setEnabled(true);
legacyThemeTransitions->setOpacity(1.0f);
legacyThemeTransitions->getParent()
->getChild(legacyThemeTransitions->getChildIndex() - 1)
->setOpacity(1.0f);
gamelistVideoPillarbox->setEnabled(true);
gamelistVideoPillarbox->setOpacity(1.0f);
gamelistVideoPillarbox->getParent()
->getChild(gamelistVideoPillarbox->getChildIndex() - 1)
->setOpacity(1.0f);
gamelistVideoScanlines->setEnabled(true);
gamelistVideoScanlines->setOpacity(1.0f);
gamelistVideoScanlines->getParent()
->getChild(gamelistVideoScanlines->getChildIndex() - 1)
->setOpacity(1.0f);
}
};
scrollThemeSetFunc(selectedSet->first, true);

View file

@ -1,750 +0,0 @@
// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// GamelistLegacy.h
//
// Specific gamelist functions for backward compatibility (legacy mode).
//
#ifndef ES_APP_VIEWS_GAMELIST_LEGACY_H
#define ES_APP_VIEWS_GAMELIST_LEGACY_H
#include "CollectionSystemsManager.h"
#include "animations/LambdaAnimation.h"
#define FADE_IN_START_OPACITY 0.5f
#define FADE_IN_TIME 325
void GamelistView::legacyPopulateFields()
{
const float padding {0.01f};
// Logo text (fallback if no logo image exists).
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setText(mRoot->getSystem()->getFullName(), false);
mTextComponents.back()->setSize(mSize.x, 0.0f);
mTextComponents.back()->setPosition(0.0f, 0.0f);
mTextComponents.back()->setHorizontalAlignment(ALIGN_CENTER);
mTextComponents.back()->setColor(0x000000FF);
mTextComponents.back()->setDefaultZIndex(50.0f);
mTextComponents.back()->setZIndex(10.0f);
addChild(mTextComponents.back().get());
// Logo.
mImageComponents.push_back(std::make_unique<ImageComponent>());
mImageComponents.back()->setResize(0.0f, mSize.y * 0.185f);
mImageComponents.back()->setOrigin(0.5f, 0.0f);
mImageComponents.back()->setPosition(mSize.x / 2.0f, 0.0f);
mImageComponents.back()->setDefaultZIndex(50.0f);
mImageComponents.back()->setVisible(false);
addChild(mImageComponents.back().get());
// Background.
mImageComponents.push_back(std::make_unique<ImageComponent>());
mImageComponents.back()->setResize(mSize.x, mSize.y);
mImageComponents.back()->setDefaultZIndex(0.0f);
addChild(mImageComponents.back().get());
// Thumbnails.
mImageComponents.push_back(std::make_unique<ImageComponent>());
mImageComponents.back()->setThemeMetadata("image_md_thumbnail");
mImageComponents.back()->setOrigin(0.5f, 0.5f);
mImageComponents.back()->setMaxSize(mSize.x * (0.25f - 2.0f * padding), mSize.y * 0.10f);
mImageComponents.back()->setDefaultZIndex(25.0f);
mImageComponents.back()->setScrollFadeIn(true);
mImageComponents.back()->setVisible(false);
addChild(mImageComponents.back().get());
// Marquee.
mImageComponents.push_back(std::make_unique<ImageComponent>());
mImageComponents.back()->setThemeMetadata("image_md_marquee");
mImageComponents.back()->setLinearInterpolation(true);
mImageComponents.back()->setOrigin(0.5f, 0.5f);
mImageComponents.back()->setMaxSize(mSize.x * (0.5f - 2.0f * padding), mSize.y * 0.18f);
mImageComponents.back()->setDefaultZIndex(35.0f);
mImageComponents.back()->setVisible(false);
addChild(mImageComponents.back().get());
// Image.
mImageComponents.push_back(std::make_unique<ImageComponent>());
mImageComponents.back()->setThemeMetadata("image_md_image");
mImageComponents.back()->setOrigin(0.5f, 0.5f);
mImageComponents.back()->setPosition(mSize.x * 0.25f,
mPrimary->getPosition().y + mSize.y * 0.2125f);
mImageComponents.back()->setMaxSize(mSize.x * (0.50f - 2.0f * padding), mSize.y * 0.4f);
mImageComponents.back()->setDefaultZIndex(30.0f);
mImageComponents.back()->setScrollFadeIn(true);
mImageComponents.back()->setVisible(false);
addChild(mImageComponents.back().get());
if (mViewStyle == ViewController::VIDEO) {
// Video.
mVideoComponents.push_back(std::make_unique<VideoFFmpegComponent>());
mVideoComponents.back()->setThemeMetadata("video_md_video");
mVideoComponents.back()->setOrigin(0.5f, 0.5f);
mVideoComponents.back()->setPosition(mSize.x * 0.25f,
mPrimary->getPosition().y + mSize.y * 0.2125f);
mVideoComponents.back()->setSize(mSize.x * (0.5f - 2.0f * padding), mSize.y * 0.4f);
mVideoComponents.back()->setDefaultZIndex(30.0f);
mVideoComponents.back()->setScrollFadeIn(true);
mVideoComponents.back()->setVisible(false);
addChild(mVideoComponents.back().get());
}
mPrimary->setPosition(mSize.x * (0.50f + padding), mPrimary->getPosition().y);
mPrimary->setSize(mSize.x * (0.50f - padding), mPrimary->getSize().y);
mPrimary->setAlignment(TextListComponent<FileData*>::PrimaryAlignment::ALIGN_LEFT);
mPrimary->setCursorChangedCallback([&](const CursorState& state) { legacyUpdateView(state); });
// Metadata labels + values.
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setText("Rating: ", false);
mTextComponents.back()->setThemeMetadata("text_md_lbl_rating");
addChild(mTextComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setText("Released: ", false);
mTextComponents.back()->setThemeMetadata("text_md_lbl_releasedate");
addChild(mTextComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setText("Developer: ", false);
mTextComponents.back()->setThemeMetadata("text_md_lbl_developer");
addChild(mTextComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setText("Publisher: ", false);
mTextComponents.back()->setThemeMetadata("text_md_lbl_publisher");
addChild(mTextComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setText("Genre: ", false);
mTextComponents.back()->setThemeMetadata("text_md_lbl_genre");
addChild(mTextComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setText("Players: ", false);
mTextComponents.back()->setThemeMetadata("text_md_lbl_players");
addChild(mTextComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setText("Last played: ", false);
mTextComponents.back()->setThemeMetadata("text_md_lbl_lastplayed");
addChild(mTextComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setText("Times played: ", false);
mTextComponents.back()->setThemeMetadata("text_md_lbl_playcount");
addChild(mTextComponents.back().get());
mRatingComponents.push_back(std::make_unique<RatingComponent>());
mRatingComponents.back()->setThemeMetadata("rating_md_rating");
mRatingComponents.back()->setDefaultZIndex(40.0f);
addChild(mRatingComponents.back().get());
mDateTimeComponents.push_back(std::make_unique<DateTimeComponent>());
mDateTimeComponents.back()->setThemeMetadata("datetime_md_releasedate");
addChild(mDateTimeComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setThemeMetadata("text_md_developer");
addChild(mTextComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setThemeMetadata("text_md_publisher");
addChild(mTextComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setThemeMetadata("text_md_genre");
addChild(mTextComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setThemeMetadata("text_md_players");
addChild(mTextComponents.back().get());
mDateTimeComponents.push_back(std::make_unique<DateTimeComponent>());
mDateTimeComponents.back()->setThemeMetadata("datetime_md_lastplayed");
mDateTimeComponents.back()->setDisplayRelative(true);
addChild(mDateTimeComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setThemeMetadata("text_md_playcount");
addChild(mTextComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setThemeMetadata("text_md_name");
mTextComponents.back()->setPosition(mSize.x, mSize.y);
mTextComponents.back()->setFont(Font::get(FONT_SIZE_MEDIUM_FIXED));
mTextComponents.back()->setHorizontalAlignment(ALIGN_CENTER);
mTextComponents.back()->setColor(0xAAAAAAFF);
mTextComponents.back()->setDefaultZIndex(40.0f);
addChild(mTextComponents.back().get());
// Badges.
mBadgeComponents.push_back(std::make_unique<BadgeComponent>());
mBadgeComponents.back()->setThemeMetadata("badges_md_badges");
mBadgeComponents.back()->setOrigin(0.5f, 0.5f);
mBadgeComponents.back()->setPosition(mSize.x * 0.8f, mSize.y * 0.7f);
mBadgeComponents.back()->setSize(mSize.x * 0.15f, mSize.y * 0.2f);
mBadgeComponents.back()->setDefaultZIndex(50.0f);
addChild(mBadgeComponents.back().get());
// Scrollable container (game description).
mContainerComponents.push_back(std::make_unique<ScrollableContainer>());
mContainerComponents.back()->setThemeMetadata("text_md_description");
mContainerComponents.back()->setAutoScroll(true);
mContainerComponents.back()->setVisible(false);
mContainerComponents.back()->setDefaultZIndex(40.0f);
addChild(mContainerComponents.back().get());
mTextComponents.push_back(std::make_unique<TextComponent>());
mTextComponents.back()->setFont(Font::get(FONT_SIZE_SMALL));
mTextComponents.back()->setSize(mContainerComponents.back()->getSize().x, 0.0f);
mContainerComponents.back()->addChild(mTextComponents.back().get());
mGamelistInfoComponents.push_back(std::make_unique<TextComponent>());
mGamelistInfoComponents.back()->setThemeMetadata("text_gamelistInfo");
mGamelistInfoComponents.back()->setOrigin(0.5f, 0.5f);
mGamelistInfoComponents.back()->setFont(Font::get(FONT_SIZE_SMALL));
mGamelistInfoComponents.back()->setDefaultZIndex(50.0f);
mGamelistInfoComponents.back()->setVisible(true);
addChild(mGamelistInfoComponents.back().get());
}
void GamelistView::legacyOnThemeChanged(const std::shared_ptr<ThemeData>& theme)
{
if (mTextList == nullptr) {
mTextList = std::make_unique<TextListComponent<FileData*>>();
mPrimary = mTextList.get();
}
mSystemNameSuffix = true;
legacyPopulateFields();
using namespace ThemeFlags;
mTextComponents[LOGOTEXT]->applyTheme(theme, getName(), "text_logoText", ALL);
mImageComponents[LOGO]->applyTheme(theme, getName(), "image_logo", ALL);
mImageComponents[BACKGROUND]->applyTheme(theme, getName(), "image_background", ALL);
auto themeView = theme->getViewElements(getName());
if (themeView.elements.find("text_logoText") == themeView.elements.end())
mTextComponents[LOGOTEXT]->setVisible(false);
if (getName() == "basic")
mPrimary->setAlignment(TextListComponent<FileData*>::PrimaryAlignment::ALIGN_CENTER);
// Make sure we don't display both the logo image and logo text.
if (mImageComponents[LOGO]->hasImage())
mTextComponents[LOGOTEXT]->setVisible(false);
// Remove old theme extras.
for (auto extra : mThemeExtras) {
removeChild(extra);
delete extra;
}
mThemeExtras.clear();
// Add new theme extras.
mThemeExtras = ThemeData::makeExtras(theme, getName());
for (auto extra : mThemeExtras)
addChild(extra);
mPrimary->setPosition(0.0f, mSize.y * 0.1f);
mPrimary->setSize(mSize.x, mSize.y * 0.8f);
mPrimary->setDefaultZIndex(50.0f);
mPrimary->applyTheme(theme, getName(), "textlist_gamelist", ALL);
addChild(mPrimary);
mImageComponents[LegacyImage::MD_THUMBNAIL]->applyTheme(
theme, getName(), mImageComponents[LegacyImage::MD_THUMBNAIL]->getThemeMetadata(), ALL);
mImageComponents[LegacyImage::MD_MARQUEE]->applyTheme(theme, getName(), "image_md_marquee",
POSITION | ThemeFlags::SIZE | Z_INDEX |
ROTATION | VISIBLE);
if (mViewStyle == ViewController::DETAILED) {
mImageComponents[LegacyImage::MD_IMAGE]->applyTheme(
theme, getName(), mImageComponents[LegacyImage::MD_IMAGE]->getThemeMetadata(),
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
}
else if (mViewStyle == ViewController::VIDEO) {
mVideoComponents.front()->applyTheme(
theme, getName(), mVideoComponents.front()->getThemeMetadata(),
POSITION | ThemeFlags::SIZE | ThemeFlags::DELAY | Z_INDEX | ROTATION | VISIBLE);
mImageComponents[LegacyImage::MD_IMAGE]->setVisible(false);
mImageComponents[LegacyImage::MD_IMAGE]->applyTheme(
theme, getName(), mImageComponents[LegacyImage::MD_IMAGE]->getThemeMetadata(),
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
}
legacyInitMDLabels();
legacyInitMDValues();
mTextComponents[LegacyText::MD_NAME]->applyTheme(
theme, getName(), mTextComponents[LegacyText::MD_NAME]->getThemeMetadata(), ALL);
for (size_t i = 0; i < mBadgeComponents.size(); ++i)
mBadgeComponents[i]->applyTheme(theme, getName(), mBadgeComponents[i]->getThemeMetadata(),
ALL);
for (size_t i = 0; i < mRatingComponents.size(); ++i)
mRatingComponents[i]->applyTheme(theme, getName(), mRatingComponents[i]->getThemeMetadata(),
ALL);
mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE]->applyTheme(
theme, getName(), mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE]->getThemeMetadata(),
ALL);
mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED]->applyTheme(
theme, getName(), mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED]->getThemeMetadata(),
ALL);
for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::MD_NAME; ++i) {
mTextComponents[i]->applyTheme(theme, getName(), mTextComponents[i]->getThemeMetadata(),
ALL ^ ThemeFlags::TEXT);
}
for (auto& container : mContainerComponents) {
container->applyTheme(theme, getName(), container->getThemeMetadata(),
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
}
mTextComponents[LegacyText::MD_DESCRIPTION]->setSize(mContainerComponents.front()->getSize().x,
0.0f);
mTextComponents[LegacyText::MD_DESCRIPTION]->applyTheme(
theme, getName(), "text_md_description",
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
for (auto& gamelistInfo : mGamelistInfoComponents)
gamelistInfo->applyTheme(theme, getName(), gamelistInfo->getThemeMetadata(),
ALL ^ ThemeFlags::TEXT);
// If there is no position defined in the theme for gamelistInfo, then hide it.
if (mGamelistInfoComponents.front()->getPosition() == glm::vec3 {})
mGamelistInfoComponents.front()->setVisible(false);
else
mGamelistInfoComponents.front()->setVisible(true);
// Hide some components if we're in Basic mode.
if (mViewStyle == ViewController::BASIC) {
mImageComponents[LegacyImage::MD_IMAGE]->setVisible(false);
for (auto& container : mContainerComponents)
container->setVisible(false);
}
populateList(mRoot->getChildrenListToDisplay(), mRoot);
sortChildren();
mHelpStyle.applyTheme(mTheme, getName());
}
void GamelistView::legacyUpdateView(const CursorState& state)
{
FileData* file {(mPrimary->size() > 0 && state == CursorState::CURSOR_STOPPED) ?
mPrimary->getSelected() :
nullptr};
// If the game data has already been rendered to the info panel, then skip it this time.
if (file == mLastUpdated)
return;
if (state == CursorState::CURSOR_STOPPED)
mLastUpdated = file;
bool hideMetaDataFields {false};
if (file) {
// Always hide the metadata fields if browsing grouped custom collections.
if (file->getSystem()->isCustomCollection() &&
file->getPath() == file->getSystem()->getName())
hideMetaDataFields = true;
else
hideMetaDataFields = (file->metadata.get("hidemetadata") == "true");
// Always hide the metadata fields for placeholders as well.
if (file->getType() == PLACEHOLDER) {
hideMetaDataFields = true;
mLastUpdated = nullptr;
}
}
// If we're scrolling, hide the metadata fields if the last game had this options set,
// or if we're in the grouped custom collection view.
if (mPrimary->isScrolling()) {
if ((mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true") ||
(mLastUpdated->getSystem()->isCustomCollection() &&
mLastUpdated->getPath() == mLastUpdated->getSystem()->getName()))
hideMetaDataFields = true;
}
if (hideMetaDataFields || mViewStyle == ViewController::BASIC) {
for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::MD_DESCRIPTION; ++i)
mTextComponents[i]->setVisible(false);
for (auto& date : mDateTimeComponents)
date->setVisible(false);
for (auto& badge : mBadgeComponents)
badge->setVisible(false);
for (auto& rating : mRatingComponents)
rating->setVisible(false);
}
else {
for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::MD_DESCRIPTION; ++i)
mTextComponents[i]->setVisible(true);
for (auto& date : mDateTimeComponents)
date->setVisible(true);
for (auto& badge : mBadgeComponents)
badge->setVisible(true);
for (auto& rating : mRatingComponents)
rating->setVisible(true);
}
bool fadingOut {false};
if (file == nullptr) {
if (mViewStyle == ViewController::VIDEO) {
mVideoComponents.front()->stopVideoPlayer();
mVideoComponents.front()->setVideo("");
if (!mVideoComponents.front()->hasStartDelay())
mVideoComponents.front()->setImage("");
}
mVideoPlaying = false;
fadingOut = true;
}
else {
// If we're browsing a grouped custom collection, then update the folder metadata
// which will generate a description of three random games and return a pointer to
// the first of these so that we can display its game media.
if (file->getSystem()->isCustomCollection() &&
file->getPath() == file->getSystem()->getName()) {
mRandomGame = CollectionSystemsManager::getInstance()->updateCollectionFolderMetadata(
file->getSystem());
if (mRandomGame) {
mImageComponents[LegacyImage::MD_THUMBNAIL]->setImage(mRandomGame->getImagePath());
mImageComponents[LegacyImage::MD_MARQUEE]->setImage(mRandomGame->getMarqueePath());
if (mViewStyle == ViewController::VIDEO) {
mVideoComponents.front()->setImage(mRandomGame->getImagePath());
mVideoComponents.front()->stopVideoPlayer();
if (!mVideoComponents.front()->setVideo(mRandomGame->getVideoPath()))
mVideoComponents.front()->setDefaultVideo();
mVideoComponents.front()->startVideoPlayer();
mImageComponents[LegacyImage::MD_IMAGE]->setImage(mRandomGame->getImagePath());
}
else {
mImageComponents[LegacyImage::MD_IMAGE]->setImage(mRandomGame->getImagePath());
}
}
else {
mImageComponents[LegacyImage::MD_THUMBNAIL]->setImage("");
mImageComponents[LegacyImage::MD_MARQUEE]->setImage("");
mImageComponents[LegacyImage::MD_IMAGE]->setImage("");
if (mViewStyle == ViewController::VIDEO) {
mVideoComponents.front()->setImage("");
mVideoComponents.front()->setVideo("");
mVideoComponents.front()->setDefaultVideo();
}
}
}
else {
mImageComponents[LegacyImage::MD_THUMBNAIL]->setImage(file->getImagePath());
mImageComponents[LegacyImage::MD_MARQUEE]->setImage(file->getMarqueePath());
if (mViewStyle == ViewController::VIDEO) {
mVideoComponents.front()->setImage(file->getImagePath());
mVideoComponents.front()->stopVideoPlayer();
if (!mVideoComponents.front()->setVideo(file->getVideoPath()))
mVideoComponents.front()->setDefaultVideo();
mVideoComponents.front()->startVideoPlayer();
mImageComponents[LegacyImage::MD_IMAGE]->setImage(file->getImagePath());
}
else {
mImageComponents[LegacyImage::MD_IMAGE]->setImage(file->getImagePath());
}
}
mVideoPlaying = true;
// Populate the gamelistInfo field which shows an icon if a folder has been entered
// as well as the game count for the entire system (total and favorites separately).
// If a filter has been applied, then the number of filtered and total games replaces
// the game counter.
for (auto& gamelistInfo : mGamelistInfoComponents) {
std::string gamelistInfoString;
Alignment infoAlign {gamelistInfo->getHorizontalAlignment()};
if (mIsFolder && infoAlign == ALIGN_RIGHT)
gamelistInfoString = ViewController::FOLDER_CHAR + " ";
if (mIsFiltered) {
if (mFilteredGameCountAll == mFilteredGameCount)
gamelistInfoString.append(ViewController::FILTER_CHAR)
.append(" ")
.append(std::to_string(mFilteredGameCount))
.append(" / ")
.append(std::to_string(mGameCount));
else
gamelistInfoString.append(ViewController::FILTER_CHAR)
.append(" ")
.append(std::to_string(mFilteredGameCount))
.append(" + ")
.append(std::to_string(mFilteredGameCountAll - mFilteredGameCount))
.append(" / ")
.append(std::to_string(mGameCount));
}
else {
gamelistInfoString.append(ViewController::CONTROLLER_CHAR)
.append(" ")
.append(std::to_string(mGameCount));
if (!(file->getSystem()->isCollection() &&
file->getSystem()->getFullName() == "favorites"))
gamelistInfoString.append(" ")
.append(ViewController::FAVORITE_CHAR)
.append(" ")
.append(std::to_string(mFavoritesGameCount));
}
if (mIsFolder && infoAlign != ALIGN_RIGHT)
gamelistInfoString.append(" ").append(ViewController::FOLDER_CHAR);
gamelistInfo->setValue(gamelistInfoString);
}
if (mViewStyle == ViewController::DETAILED) {
// Fade in the game image.
auto funcImage = [this](float t) {
mImageComponents[LegacyImage::MD_IMAGE]->setOpacity(
glm::mix(FADE_IN_START_OPACITY, 1.0f, t));
};
mImageComponents[LegacyImage::MD_IMAGE]->setAnimation(
new LambdaAnimation(funcImage, FADE_IN_TIME), 0, nullptr, false);
// Fade in the thumbnail.
auto funcThumbnail = [this](float t) {
mImageComponents[LegacyImage::MD_THUMBNAIL]->setOpacity(
glm::mix(FADE_IN_START_OPACITY, 1.0f, t));
};
mImageComponents[LegacyImage::MD_THUMBNAIL]->setAnimation(
new LambdaAnimation(funcThumbnail, FADE_IN_TIME), 0, nullptr, false);
}
else if (mViewStyle == ViewController::VIDEO) {
// Fade in the static image.
auto funcVideo = [this](float t) {
mVideoComponents.front()->setOpacity(glm::mix(FADE_IN_START_OPACITY, 1.0f, t));
};
mVideoComponents.front()->setAnimation(new LambdaAnimation(funcVideo, FADE_IN_TIME), 0,
nullptr, false);
// Fade in the game image.
auto funcImage = [this](float t) {
mImageComponents[LegacyImage::MD_IMAGE]->setOpacity(
glm::mix(FADE_IN_START_OPACITY, 1.0f, t));
};
mImageComponents[LegacyImage::MD_IMAGE]->setAnimation(
new LambdaAnimation(funcImage, FADE_IN_TIME), 0, nullptr, false);
}
mTextComponents[LegacyText::MD_DESCRIPTION]->setText(file->metadata.get("desc"));
for (auto& container : mContainerComponents)
container->reset();
for (auto& rating : mRatingComponents)
rating->setValue(file->metadata.get("rating"));
mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE]->setValue(
file->metadata.get("releasedate"));
mTextComponents[LegacyText::MD_DEVELOPER]->setValue(file->metadata.get("developer"));
mTextComponents[LegacyText::MD_PUBLISHER]->setValue(file->metadata.get("publisher"));
mTextComponents[LegacyText::MD_GENRE]->setValue(file->metadata.get("genre"));
mTextComponents[LegacyText::MD_PLAYERS]->setValue(file->metadata.get("players"));
// Populate the badge slots based on game metadata.
std::vector<BadgeComponent::BadgeInfo> badgeSlots;
for (auto& badgeComponent : mBadgeComponents) {
for (auto& badge : badgeComponent->getBadgeTypes()) {
BadgeComponent::BadgeInfo badgeInfo;
badgeInfo.badgeType = badge;
if (badge == "collection" && CollectionSystemsManager::getInstance()->isEditing()) {
if (CollectionSystemsManager::getInstance()->inCustomCollection(
CollectionSystemsManager::getInstance()->getEditingCollection(),
file)) {
badgeSlots.emplace_back(badgeInfo);
}
}
else if (badge == "folder") {
if (file->getType() == FOLDER) {
if (file->metadata.get("folderlink") != "")
badgeInfo.folderLink = true;
badgeSlots.emplace_back(badgeInfo);
}
}
else if (badge == "controller") {
if (file->metadata.get("controller") != "") {
badgeInfo.gameController = file->metadata.get("controller");
badgeSlots.emplace_back(badgeInfo);
}
}
else if (badge == "altemulator") {
if (file->metadata.get(badge) != "")
badgeSlots.emplace_back(badgeInfo);
}
else {
if (file->metadata.get(badge) == "true")
badgeSlots.emplace_back(badgeInfo);
}
}
badgeComponent->setBadges(badgeSlots);
}
mTextComponents[LegacyText::MD_NAME]->setValue(file->metadata.get("name"));
if (file->getType() == GAME) {
if (!hideMetaDataFields) {
mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED]->setValue(
file->metadata.get("lastplayed"));
mTextComponents[LegacyText::MD_PLAYCOUNT]->setValue(
file->metadata.get("playcount"));
}
}
else if (file->getType() == FOLDER) {
if (!hideMetaDataFields) {
mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED]->setValue(
file->metadata.get("lastplayed"));
mTextComponents[LegacyText::MD_LBL_PLAYCOUNT]->setVisible(false);
mTextComponents[LegacyText::MD_PLAYCOUNT]->setVisible(false);
}
}
fadingOut = false;
}
std::vector<GuiComponent*> comps;
for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::END; ++i)
comps.emplace_back(mTextComponents[i].get());
comps.emplace_back(mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE].get());
comps.emplace_back(mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED].get());
comps.emplace_back(mTextComponents[LegacyText::MD_NAME].get());
comps.emplace_back(mImageComponents[LegacyImage::MD_THUMBNAIL].get());
comps.emplace_back(mImageComponents[LegacyImage::MD_MARQUEE].get());
comps.emplace_back(mImageComponents[LegacyImage::MD_IMAGE].get());
if (mVideoComponents.size() > 0)
comps.emplace_back(mVideoComponents.front().get());
comps.push_back(mBadgeComponents.front().get());
comps.push_back(mRatingComponents.front().get());
for (auto it = comps.cbegin(); it != comps.cend(); ++it) {
GuiComponent* comp {*it};
if ((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
(!comp->isAnimationPlaying(0) &&
comp->getOpacity() != (fadingOut ? 0.0f : comp->getColorOpacity()))) {
auto func = [comp](float t) { comp->setOpacity(glm::mix(0.0f, 1.0f, t)); };
comp->setAnimation(new LambdaAnimation(func, 150), 0, nullptr, fadingOut);
}
}
if (state == CursorState::CURSOR_SCROLLING)
mLastUpdated = nullptr;
}
void GamelistView::legacyUpdate(int deltaTime)
{
if (ViewController::getInstance()->getGameLaunchTriggered() &&
mImageComponents[LegacyImage::MD_IMAGE]->isAnimationPlaying(0))
mImageComponents[LegacyImage::MD_IMAGE]->finishAnimation(0);
if (mViewStyle == ViewController::VIDEO) {
if (ViewController::getInstance()->getGameLaunchTriggered() &&
mVideoComponents.front()->isAnimationPlaying(0))
mVideoComponents.front()->finishAnimation(0);
}
updateChildren(deltaTime);
}
void GamelistView::legacyInitMDLabels()
{
std::vector<TextComponent*> components;
for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::MD_DEVELOPER; ++i)
components.emplace_back(&*mTextComponents[i]);
const unsigned int colCount {2};
const unsigned int rowCount {static_cast<unsigned int>(components.size() / 2)};
glm::vec3 start {mSize.x * 0.01f, mSize.y * 0.625f, 0.0f};
const float colSize {(mSize.x * 0.48f) / colCount};
const float rowPadding {0.01f * mSize.y};
for (unsigned int i = 0; i < components.size(); ++i) {
const unsigned int row {i % rowCount};
glm::vec3 pos {0.0f, 0.0f, 0.0f};
if (row == 0) {
pos = start + glm::vec3 {colSize * (i / rowCount), 0.0f, 0.0f};
}
else {
// Work from the last component.
GuiComponent* lc {components[i - 1]};
pos = lc->getPosition() + glm::vec3 {0.0f, lc->getSize().y + rowPadding, 0.0f};
}
components[i]->setFont(Font::get(FONT_SIZE_SMALL));
components[i]->setPosition(pos);
components[i]->setDefaultZIndex(40.0f);
}
}
void GamelistView::legacyInitMDValues()
{
std::vector<TextComponent*> labels;
std::vector<GuiComponent*> values;
std::shared_ptr<Font> defaultFont {Font::get(FONT_SIZE_SMALL)};
for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::MD_DEVELOPER; ++i) {
labels.emplace_back(&*mTextComponents[i]);
mTextComponents[i]->setFont(defaultFont);
}
for (size_t i = LegacyText::MD_DEVELOPER; i < LegacyText::MD_DESCRIPTION; ++i)
mTextComponents[i]->setFont(defaultFont);
mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE]->setFont(defaultFont);
mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED]->setFont(defaultFont);
values.emplace_back(mRatingComponents.front().get());
values.emplace_back(mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE].get());
values.emplace_back(mTextComponents[LegacyText::MD_DEVELOPER].get());
values.emplace_back(mTextComponents[LegacyText::MD_PUBLISHER].get());
values.emplace_back(mTextComponents[LegacyText::MD_GENRE].get());
values.emplace_back(mTextComponents[LegacyText::MD_PLAYERS].get());
values.emplace_back(mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED].get());
values.emplace_back(mTextComponents[LegacyText::MD_PLAYCOUNT].get());
float bottom {0.0f};
const float colSize {(mSize.x * 0.48f) / 2.0f};
for (unsigned int i = 0; i < labels.size(); ++i) {
const float heightDiff {(labels[i]->getSize().y - values[i]->getSize().y) / 2.0f};
values[i]->setPosition(mSize.x + glm::vec3 {labels[i]->getSize().x, heightDiff, 0.0f});
values[i]->setSize(colSize - labels[i]->getSize().x, values[i]->getSize().y);
values[i]->setDefaultZIndex(40.0f);
float testBot {values[i]->getPosition().y + values[i]->getSize().y};
if (testBot > bottom)
bottom = testBot;
}
// Default to off the screen for the following components.
mRatingComponents.front()->setPosition(Renderer::getScreenWidth() * 2.0f,
Renderer::getScreenHeight() * 2.0f);
mContainerComponents.front()->setPosition(Renderer::getScreenWidth() * 2.0f,
Renderer::getScreenHeight() * 2.0f);
for (auto& container : mContainerComponents) {
container->setPosition(container->getPosition().x, bottom + mSize.y * 0.01f);
container->setSize(mSize.x * 0.2f, mSize.y * 0.2f);
}
}
#endif // ES_APP_VIEWS_GAMELIST_LEGACY_H

View file

@ -7,7 +7,6 @@
//
#include "views/GamelistView.h"
#include "views/GamelistLegacy.h"
#include "CollectionSystemsManager.h"
#include "UIModeController.h"
@ -19,11 +18,8 @@
GamelistView::GamelistView(FileData* root)
: GamelistBase {root}
, mRenderer {Renderer::getInstance()}
, mViewStyle {ViewController::BASIC}
, mLegacyMode {false}
, mStaticVideoAudio {false}
{
mViewStyle = ViewController::getInstance()->getState().viewstyle;
}
GamelistView::~GamelistView()
@ -38,9 +34,6 @@ GamelistView::~GamelistView()
const std::pair<bool, LetterCase> GamelistView::getDescriptionSystemNameSuffix() const
{
if (mLegacyMode)
return std::make_pair(true, LetterCase::UPPERCASE);
bool suffix {false};
LetterCase letterCase {LetterCase::UPPERCASE};
@ -97,11 +90,7 @@ void GamelistView::onShow()
mLastUpdated = nullptr;
GuiComponent::onShow();
if (mLegacyMode)
legacyUpdateView(CursorState::CURSOR_STOPPED);
else
updateView(CursorState::CURSOR_STOPPED);
updateView(CursorState::CURSOR_STOPPED);
mPrimary->finishAnimation(0);
}
@ -123,12 +112,6 @@ void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
selectedSet {themeSets.find(Settings::getInstance()->getString("ThemeSet"))};
assert(selectedSet != themeSets.cend());
mLegacyMode = selectedSet->second.capabilities.legacyTheme;
if (mLegacyMode) {
legacyOnThemeChanged(theme);
return;
}
mStaticVideoAudio = false;
const bool isStartupSystem {Settings::getInstance()->getString("StartupSystem") ==
@ -391,11 +374,6 @@ void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
void GamelistView::update(int deltaTime)
{
if (mLegacyMode) {
legacyUpdate(deltaTime);
return;
}
if (ViewController::getInstance()->getGameLaunchTriggered()) {
for (auto& image : mImageComponents) {
if (image->isAnimationPlaying(0))
@ -463,9 +441,7 @@ std::vector<HelpPrompt> GamelistView::getHelpPrompts()
if (mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
!CollectionSystemsManager::getInstance()->isEditing() && mCursorStack.empty() &&
ViewController::getInstance()->getState().viewing == ViewController::GAMELIST) {
if (!(mLegacyMode &&
ViewController::getInstance()->getState().viewstyle == ViewController::BASIC))
prompts.push_back(HelpPrompt("y", "jump to game"));
prompts.push_back(HelpPrompt("y", "jump to game"));
}
else if (mRoot->getSystem()->isGameSystem() &&
(mRoot->getSystem()->getThemeFolder() != "custom-collections" ||
@ -492,11 +468,6 @@ std::vector<HelpPrompt> GamelistView::getHelpPrompts()
void GamelistView::updateView(const CursorState& state)
{
if (mLegacyMode) {
legacyUpdateView(state);
return;
}
bool loadedTexture {false};
if (mPrimary->isScrolling()) {

View file

@ -28,20 +28,6 @@ public:
void preloadGamelist() { updateView(CursorState::CURSOR_STOPPED); }
void launch(FileData* game) override { ViewController::getInstance()->triggerGameLaunch(game); }
std::string getName() const
{
auto selectedViewStyle = ViewController::getInstance()->getState();
switch (selectedViewStyle.viewstyle) {
case ViewController::VIDEO:
return "video";
case ViewController::DETAILED:
return "detailed";
case ViewController::BASIC:
default:
return "basic";
}
}
void startViewVideos() override
{
for (auto& video : mVideoComponents)
@ -117,18 +103,8 @@ private:
void updateView(const CursorState& state);
void setGameImage(FileData* file, GuiComponent* comp);
// Legacy (backward compatibility) functions.
void legacyPopulateFields();
void legacyOnThemeChanged(const std::shared_ptr<ThemeData>& theme);
void legacyUpdateView(const CursorState& state);
void legacyUpdate(int deltaTime);
void legacyInitMDLabels();
void legacyInitMDValues();
Renderer* mRenderer;
HelpStyle mHelpStyle;
ViewController::GamelistViewStyle mViewStyle;
bool mLegacyMode;
bool mStaticVideoAudio;
std::shared_ptr<ThemeData> mTheme;
@ -146,39 +122,6 @@ private:
std::vector<std::unique_ptr<ScrollableContainer>> mContainerComponents;
std::vector<std::unique_ptr<TextComponent>> mContainerTextComponents;
std::vector<std::unique_ptr<TextComponent>> mGamelistInfoComponents;
enum LegacyText {
LOGOTEXT = 0,
MD_LBL_RATING = 1,
MD_LBL_RELEASEDATE = 2,
MD_LBL_DEVELOPER = 3,
MD_LBL_PUBLISHER = 4,
MD_LBL_GENRE = 5,
MD_LBL_PLAYERS = 6,
MD_LBL_LASTPLAYED = 7,
MD_LBL_PLAYCOUNT = 8,
MD_DEVELOPER = 9,
MD_PUBLISHER = 10,
MD_GENRE = 11,
MD_PLAYERS = 12,
MD_PLAYCOUNT = 13,
MD_NAME = 14,
MD_DESCRIPTION = 15,
END
};
enum LegacyDateTime {
MD_RELEASEDATE = 0, //
MD_LASTPLAYED = 1
};
enum LegacyImage {
LOGO = 0, //
BACKGROUND = 1,
MD_THUMBNAIL = 2,
MD_MARQUEE = 3,
MD_IMAGE = 4
};
};
#endif // ES_APP_VIEWS_GAMELIST_VIEW_H

View file

@ -31,7 +31,6 @@ SystemView::SystemView()
, mPreviousScrollVelocity {0}
, mUpdatedGameCount {false}
, mViewNeedsReload {true}
, mLegacyMode {false}
, mNavigated {false}
, mMaxFade {false}
, mFadeTransitions {false}
@ -41,18 +40,6 @@ SystemView::SystemView()
populate();
}
SystemView::~SystemView()
{
if (mLegacyMode) {
// Delete any existing extras.
for (auto& entry : mSystemElements) {
for (auto extra : entry.legacyExtras)
delete extra;
entry.legacyExtras.clear();
}
}
}
void SystemView::onShow()
{
finishAnimation(0);
@ -465,12 +452,6 @@ void SystemView::populate()
selectedSet {themeSets.find(Settings::getInstance()->getString("ThemeSet"))};
assert(selectedSet != themeSets.cend());
mLegacyMode = selectedSet->second.capabilities.legacyTheme;
if (mLegacyMode) {
mLegacySystemInfo = std::make_unique<TextComponent>(
"SYSTEM INFO", Font::get(FONT_SIZE_SMALL), 0x33333300, ALIGN_CENTER);
}
for (auto it : SystemData::sSystemVector) {
const std::shared_ptr<ThemeData>& theme {it->getTheme()};
@ -478,294 +459,235 @@ void SystemView::populate()
std::string defaultImagePath;
std::string itemText;
if (mLegacyMode && mViewNeedsReload) {
if (mCarousel == nullptr) {
mCarousel = std::make_unique<CarouselComponent<SystemData*>>();
mPrimary = mCarousel.get();
// For legacy themes the carousel has a zIndex value of 40 instead of 50.
mPrimary->setDefaultZIndex(40.0f);
mPrimary->setCursorChangedCallback(
[&](const CursorState& state) { onCursorChanged(state); });
mPrimary->setCancelTransitionsCallback([&] {
ViewController::getInstance()->cancelViewTransitions();
mNavigated = true;
if (mSystemElements.size() > 1) {
for (auto& anim :
mSystemElements[mPrimary->getCursor()].lottieAnimComponents)
anim->setPauseAnimation(true);
for (auto& anim : mSystemElements[mPrimary->getCursor()].GIFAnimComponents)
anim->setPauseAnimation(true);
}
});
}
legacyApplyTheme(theme);
}
if (mLegacyMode) {
SystemViewElements elements;
elements.system = it;
SystemViewElements elements;
elements.system = it;
if (theme->hasView("system")) {
elements.name = it->getName();
elements.legacyExtras = ThemeData::makeExtras(theme, "system");
// Sort the extras by z-index.
std::stable_sort(
elements.legacyExtras.begin(), elements.legacyExtras.end(),
[](GuiComponent* a, GuiComponent* b) { return b->getZIndex() > a->getZIndex(); });
mSystemElements.emplace_back(std::move(elements));
mSystemElements.back().helpStyle.applyTheme(theme, "system");
}
if (!mLegacyMode) {
SystemViewElements elements;
elements.system = it;
if (theme->hasView("system")) {
elements.name = it->getName();
elements.fullName = it->getFullName();
for (auto& element : theme->getViewElements("system").elements) {
if (element.second.type == "gameselector") {
elements.gameSelectors.emplace_back(
std::make_unique<GameSelectorComponent>(it));
elements.gameSelectors.back()->applyTheme(theme, "system", element.first,
ThemeFlags::ALL);
elements.gameSelectors.back()->setNeedsRefresh();
elements.fullName = it->getFullName();
for (auto& element : theme->getViewElements("system").elements) {
if (element.second.type == "gameselector") {
elements.gameSelectors.emplace_back(
std::make_unique<GameSelectorComponent>(it));
elements.gameSelectors.back()->applyTheme(theme, "system", element.first,
ThemeFlags::ALL);
elements.gameSelectors.back()->setNeedsRefresh();
}
if (element.second.type == "carousel" || element.second.type == "grid" ||
element.second.type == "textlist") {
if (element.second.type == "carousel" &&
(mGrid != nullptr || mTextList != nullptr)) {
LOG(LogWarning) << "SystemView::populate(): Multiple primary components "
<< "defined, skipping carousel configuration entry";
continue;
}
if (element.second.type == "carousel" || element.second.type == "grid" ||
element.second.type == "textlist") {
if (element.second.type == "carousel" &&
(mGrid != nullptr || mTextList != nullptr)) {
LOG(LogWarning)
<< "SystemView::populate(): Multiple primary components "
<< "defined, skipping carousel configuration entry";
continue;
}
if (element.second.type == "grid" &&
(mCarousel != nullptr || mTextList != nullptr)) {
LOG(LogWarning)
<< "SystemView::populate(): Multiple primary components "
<< "defined, skipping grid configuration entry";
continue;
}
if (element.second.type == "textlist" &&
(mCarousel != nullptr || mGrid != nullptr)) {
LOG(LogWarning)
<< "SystemView::populate(): Multiple primary components "
<< "defined, skipping textlist configuration entry";
continue;
}
if (element.second.type == "carousel" && mCarousel == nullptr) {
mCarousel = std::make_unique<CarouselComponent<SystemData*>>();
mPrimary = mCarousel.get();
mPrimaryType = PrimaryType::CAROUSEL;
}
else if (element.second.type == "grid" && mGrid == nullptr) {
mGrid = std::make_unique<GridComponent<SystemData*>>();
mPrimary = mGrid.get();
mPrimaryType = PrimaryType::GRID;
}
else if (element.second.type == "textlist" && mTextList == nullptr) {
mTextList = std::make_unique<TextListComponent<SystemData*>>();
mPrimary = mTextList.get();
mPrimaryType = PrimaryType::TEXTLIST;
}
mPrimary->setDefaultZIndex(50.0f);
mPrimary->applyTheme(theme, "system", element.first, ThemeFlags::ALL);
mPrimary->setCursorChangedCallback(
[&](const CursorState& state) { onCursorChanged(state); });
mPrimary->setCancelTransitionsCallback([&] {
ViewController::getInstance()->cancelViewTransitions();
mNavigated = true;
if (mSystemElements.size() > 1) {
for (auto& anim :
mSystemElements[mPrimary->getCursor()].lottieAnimComponents)
anim->setPauseAnimation(true);
for (auto& anim :
mSystemElements[mPrimary->getCursor()].GIFAnimComponents)
anim->setPauseAnimation(true);
}
});
if (mCarousel != nullptr || mGrid != nullptr) {
if (element.second.has("staticImage"))
imagePath = element.second.get<std::string>("staticImage");
if (element.second.has("defaultImage"))
defaultImagePath = element.second.get<std::string>("defaultImage");
if (element.second.has("text"))
itemText = element.second.get<std::string>("text");
}
if (element.second.type == "grid" &&
(mCarousel != nullptr || mTextList != nullptr)) {
LOG(LogWarning) << "SystemView::populate(): Multiple primary components "
<< "defined, skipping grid configuration entry";
continue;
}
else if (element.second.type == "image" &&
!(element.second.has("visible") &&
!element.second.get<bool>("visible"))) {
// If this is the first system then forceload to avoid texture pop-in.
if (it == SystemData::sSystemVector.front())
elements.imageComponents.emplace_back(
std::make_unique<ImageComponent>(true));
else
elements.imageComponents.emplace_back(
std::make_unique<ImageComponent>());
elements.imageComponents.back()->setDefaultZIndex(30.0f);
elements.imageComponents.back()->applyTheme(theme, "system", element.first,
ThemeFlags::ALL);
elements.children.emplace_back(elements.imageComponents.back().get());
if (element.second.type == "textlist" &&
(mCarousel != nullptr || mGrid != nullptr)) {
LOG(LogWarning) << "SystemView::populate(): Multiple primary components "
<< "defined, skipping textlist configuration entry";
continue;
}
else if (element.second.type == "video" &&
!(element.second.has("visible") &&
!element.second.get<bool>("visible"))) {
elements.videoComponents.emplace_back(
std::make_unique<VideoFFmpegComponent>());
elements.videoComponents.back()->setDefaultZIndex(30.0f);
elements.videoComponents.back()->setStaticVideo();
elements.videoComponents.back()->applyTheme(theme, "system", element.first,
ThemeFlags::ALL);
elements.children.emplace_back(elements.videoComponents.back().get());
if (element.second.type == "carousel" && mCarousel == nullptr) {
mCarousel = std::make_unique<CarouselComponent<SystemData*>>();
mPrimary = mCarousel.get();
mPrimaryType = PrimaryType::CAROUSEL;
}
else if (element.second.type == "animation" && element.second.has("path") &&
!(element.second.has("visible") &&
!element.second.get<bool>("visible"))) {
const std::string extension {Utils::FileSystem::getExtension(
element.second.get<std::string>("path"))};
if (extension == ".json") {
elements.lottieAnimComponents.emplace_back(
std::make_unique<LottieAnimComponent>());
elements.lottieAnimComponents.back()->setDefaultZIndex(35.0f);
elements.lottieAnimComponents.back()->applyTheme(
theme, "system", element.first, ThemeFlags::ALL);
elements.children.emplace_back(
elements.lottieAnimComponents.back().get());
}
else if (extension == ".gif") {
elements.GIFAnimComponents.emplace_back(
std::make_unique<GIFAnimComponent>());
elements.GIFAnimComponents.back()->setDefaultZIndex(35.0f);
elements.GIFAnimComponents.back()->applyTheme(
theme, "system", element.first, ThemeFlags::ALL);
elements.children.emplace_back(elements.GIFAnimComponents.back().get());
}
else if (extension == ".") {
LOG(LogWarning)
<< "SystemView::populate(): Invalid theme configuration, "
"animation file extension is missing";
}
else {
LOG(LogWarning)
<< "SystemView::populate(): Invalid theme configuration, "
"animation file extension defined as \""
<< extension << "\"";
}
else if (element.second.type == "grid" && mGrid == nullptr) {
mGrid = std::make_unique<GridComponent<SystemData*>>();
mPrimary = mGrid.get();
mPrimaryType = PrimaryType::GRID;
}
else if (element.second.type == "text" &&
!(element.second.has("visible") &&
!element.second.get<bool>("visible"))) {
// Set as container by default if metadata type is "description".
bool container {false};
if (element.second.has("container")) {
container = element.second.get<bool>("container");
}
else if (element.second.has("metadata") &&
element.second.get<std::string>("metadata") == "description") {
container = true;
}
if (element.second.has("systemdata") &&
element.second.get<std::string>("systemdata").substr(0, 9) ==
"gamecount") {
// A container can't be used if systemdata is set to a gamecount value.
if (element.second.has("systemdata")) {
elements.gameCountComponents.emplace_back(
std::make_unique<TextComponent>());
elements.gameCountComponents.back()->setDefaultZIndex(40.0f);
elements.gameCountComponents.back()->applyTheme(
theme, "system", element.first, ThemeFlags::ALL);
elements.children.emplace_back(
elements.gameCountComponents.back().get());
}
}
else {
if (container) {
elements.containerComponents.push_back(
std::make_unique<ScrollableContainer>());
elements.containerComponents.back()->setDefaultZIndex(40.0f);
elements.containerTextComponents.push_back(
std::make_unique<TextComponent>());
elements.containerTextComponents.back()->setDefaultZIndex(40.0f);
elements.containerComponents.back()->addChild(
elements.containerTextComponents.back().get());
elements.containerComponents.back()->applyTheme(
theme, "system", element.first,
ThemeFlags::POSITION | ThemeFlags::SIZE | ThemeFlags::Z_INDEX |
ThemeFlags::VISIBLE);
elements.containerComponents.back()->setAutoScroll(true);
elements.containerTextComponents.back()->setSize(
elements.containerComponents.back()->getSize().x, 0.0f);
elements.containerTextComponents.back()->applyTheme(
theme, "system", element.first,
ThemeFlags::ALL ^ ThemeFlags::POSITION ^ ThemeFlags::ORIGIN ^
ThemeFlags::Z_INDEX ^ ThemeFlags::SIZE ^
ThemeFlags::VISIBLE ^ ThemeFlags::ROTATION);
elements.children.emplace_back(
elements.containerComponents.back().get());
}
else {
elements.textComponents.emplace_back(
std::make_unique<TextComponent>());
elements.textComponents.back()->setDefaultZIndex(40.0f);
elements.textComponents.back()->applyTheme(
theme, "system", element.first, ThemeFlags::ALL);
elements.children.emplace_back(
elements.textComponents.back().get());
}
}
else if (element.second.type == "textlist" && mTextList == nullptr) {
mTextList = std::make_unique<TextListComponent<SystemData*>>();
mPrimary = mTextList.get();
mPrimaryType = PrimaryType::TEXTLIST;
}
else if (element.second.type == "datetime" &&
!(element.second.has("visible") &&
!element.second.get<bool>("visible"))) {
elements.dateTimeComponents.emplace_back(
std::make_unique<DateTimeComponent>());
elements.dateTimeComponents.back()->setDefaultZIndex(40.0f);
elements.dateTimeComponents.back()->applyTheme(
theme, "system", element.first, ThemeFlags::ALL);
elements.dateTimeComponents.back()->setVisible(false);
elements.children.emplace_back(elements.dateTimeComponents.back().get());
}
else if (element.second.type == "rating" &&
!(element.second.has("visible") &&
!element.second.get<bool>("visible"))) {
elements.ratingComponents.emplace_back(std::make_unique<RatingComponent>());
elements.ratingComponents.back()->setDefaultZIndex(45.0f);
elements.ratingComponents.back()->applyTheme(theme, "system", element.first,
ThemeFlags::ALL);
elements.ratingComponents.back()->setVisible(false);
elements.ratingComponents.back()->setOpacity(
elements.ratingComponents.back()->getOpacity());
elements.children.emplace_back(elements.ratingComponents.back().get());
mPrimary->setDefaultZIndex(50.0f);
mPrimary->applyTheme(theme, "system", element.first, ThemeFlags::ALL);
mPrimary->setCursorChangedCallback(
[&](const CursorState& state) { onCursorChanged(state); });
mPrimary->setCancelTransitionsCallback([&] {
ViewController::getInstance()->cancelViewTransitions();
mNavigated = true;
if (mSystemElements.size() > 1) {
for (auto& anim :
mSystemElements[mPrimary->getCursor()].lottieAnimComponents)
anim->setPauseAnimation(true);
for (auto& anim :
mSystemElements[mPrimary->getCursor()].GIFAnimComponents)
anim->setPauseAnimation(true);
}
});
if (mCarousel != nullptr || mGrid != nullptr) {
if (element.second.has("staticImage"))
imagePath = element.second.get<std::string>("staticImage");
if (element.second.has("defaultImage"))
defaultImagePath = element.second.get<std::string>("defaultImage");
if (element.second.has("text"))
itemText = element.second.get<std::string>("text");
}
}
else if (element.second.type == "image" &&
!(element.second.has("visible") && !element.second.get<bool>("visible"))) {
// If this is the first system then forceload to avoid texture pop-in.
if (it == SystemData::sSystemVector.front())
elements.imageComponents.emplace_back(
std::make_unique<ImageComponent>(true));
else
elements.imageComponents.emplace_back(std::make_unique<ImageComponent>());
elements.imageComponents.back()->setDefaultZIndex(30.0f);
elements.imageComponents.back()->applyTheme(theme, "system", element.first,
ThemeFlags::ALL);
elements.children.emplace_back(elements.imageComponents.back().get());
}
else if (element.second.type == "video" &&
!(element.second.has("visible") && !element.second.get<bool>("visible"))) {
elements.videoComponents.emplace_back(std::make_unique<VideoFFmpegComponent>());
elements.videoComponents.back()->setDefaultZIndex(30.0f);
elements.videoComponents.back()->setStaticVideo();
elements.videoComponents.back()->applyTheme(theme, "system", element.first,
ThemeFlags::ALL);
elements.children.emplace_back(elements.videoComponents.back().get());
}
else if (element.second.type == "animation" && element.second.has("path") &&
!(element.second.has("visible") && !element.second.get<bool>("visible"))) {
const std::string extension {
Utils::FileSystem::getExtension(element.second.get<std::string>("path"))};
if (extension == ".json") {
elements.lottieAnimComponents.emplace_back(
std::make_unique<LottieAnimComponent>());
elements.lottieAnimComponents.back()->setDefaultZIndex(35.0f);
elements.lottieAnimComponents.back()->applyTheme(
theme, "system", element.first, ThemeFlags::ALL);
elements.children.emplace_back(elements.lottieAnimComponents.back().get());
}
else if (extension == ".gif") {
elements.GIFAnimComponents.emplace_back(
std::make_unique<GIFAnimComponent>());
elements.GIFAnimComponents.back()->setDefaultZIndex(35.0f);
elements.GIFAnimComponents.back()->applyTheme(
theme, "system", element.first, ThemeFlags::ALL);
elements.children.emplace_back(elements.GIFAnimComponents.back().get());
}
else if (extension == ".") {
LOG(LogWarning) << "SystemView::populate(): Invalid theme configuration, "
"animation file extension is missing";
}
else {
LOG(LogWarning) << "SystemView::populate(): Invalid theme configuration, "
"animation file extension defined as \""
<< extension << "\"";
}
}
else if (element.second.type == "text" &&
!(element.second.has("visible") && !element.second.get<bool>("visible"))) {
// Set as container by default if metadata type is "description".
bool container {false};
if (element.second.has("container")) {
container = element.second.get<bool>("container");
}
else if (element.second.has("metadata") &&
element.second.get<std::string>("metadata") == "description") {
container = true;
}
if (element.second.has("systemdata") &&
element.second.get<std::string>("systemdata").substr(0, 9) == "gamecount") {
// A container can't be used if systemdata is set to a gamecount value.
if (element.second.has("systemdata")) {
elements.gameCountComponents.emplace_back(
std::make_unique<TextComponent>());
elements.gameCountComponents.back()->setDefaultZIndex(40.0f);
elements.gameCountComponents.back()->applyTheme(
theme, "system", element.first, ThemeFlags::ALL);
elements.children.emplace_back(
elements.gameCountComponents.back().get());
}
}
else {
if (container) {
elements.containerComponents.push_back(
std::make_unique<ScrollableContainer>());
elements.containerComponents.back()->setDefaultZIndex(40.0f);
elements.containerTextComponents.push_back(
std::make_unique<TextComponent>());
elements.containerTextComponents.back()->setDefaultZIndex(40.0f);
elements.containerComponents.back()->addChild(
elements.containerTextComponents.back().get());
elements.containerComponents.back()->applyTheme(
theme, "system", element.first,
ThemeFlags::POSITION | ThemeFlags::SIZE | ThemeFlags::Z_INDEX |
ThemeFlags::VISIBLE);
elements.containerComponents.back()->setAutoScroll(true);
elements.containerTextComponents.back()->setSize(
elements.containerComponents.back()->getSize().x, 0.0f);
elements.containerTextComponents.back()->applyTheme(
theme, "system", element.first,
ThemeFlags::ALL ^ ThemeFlags::POSITION ^ ThemeFlags::ORIGIN ^
ThemeFlags::Z_INDEX ^ ThemeFlags::SIZE ^ ThemeFlags::VISIBLE ^
ThemeFlags::ROTATION);
elements.children.emplace_back(
elements.containerComponents.back().get());
}
else {
elements.textComponents.emplace_back(std::make_unique<TextComponent>());
elements.textComponents.back()->setDefaultZIndex(40.0f);
elements.textComponents.back()->applyTheme(
theme, "system", element.first, ThemeFlags::ALL);
elements.children.emplace_back(elements.textComponents.back().get());
}
}
}
else if (element.second.type == "datetime" &&
!(element.second.has("visible") && !element.second.get<bool>("visible"))) {
elements.dateTimeComponents.emplace_back(std::make_unique<DateTimeComponent>());
elements.dateTimeComponents.back()->setDefaultZIndex(40.0f);
elements.dateTimeComponents.back()->applyTheme(theme, "system", element.first,
ThemeFlags::ALL);
elements.dateTimeComponents.back()->setVisible(false);
elements.children.emplace_back(elements.dateTimeComponents.back().get());
}
else if (element.second.type == "rating" &&
!(element.second.has("visible") && !element.second.get<bool>("visible"))) {
elements.ratingComponents.emplace_back(std::make_unique<RatingComponent>());
elements.ratingComponents.back()->setDefaultZIndex(45.0f);
elements.ratingComponents.back()->applyTheme(theme, "system", element.first,
ThemeFlags::ALL);
elements.ratingComponents.back()->setVisible(false);
elements.ratingComponents.back()->setOpacity(
elements.ratingComponents.back()->getOpacity());
elements.children.emplace_back(elements.ratingComponents.back().get());
}
}
std::stable_sort(
elements.children.begin(), elements.children.end(),
[](GuiComponent* a, GuiComponent* b) { return b->getZIndex() > a->getZIndex(); });
std::stable_sort(elements.imageComponents.begin(), elements.imageComponents.end(),
[](const std::unique_ptr<ImageComponent>& a,
const std::unique_ptr<ImageComponent>& b) {
return b->getZIndex() > a->getZIndex();
});
std::stable_sort(elements.textComponents.begin(), elements.textComponents.end(),
[](const std::unique_ptr<TextComponent>& a,
const std::unique_ptr<TextComponent>& b) {
return b->getZIndex() > a->getZIndex();
});
std::stable_sort(elements.containerTextComponents.begin(),
elements.containerTextComponents.end(),
[](const std::unique_ptr<TextComponent>& a,
const std::unique_ptr<TextComponent>& b) {
return b->getZIndex() > a->getZIndex();
});
mSystemElements.emplace_back(std::move(elements));
mSystemElements.back().helpStyle.applyTheme(theme, "system");
}
std::stable_sort(
elements.children.begin(), elements.children.end(),
[](GuiComponent* a, GuiComponent* b) { return b->getZIndex() > a->getZIndex(); });
std::stable_sort(
elements.imageComponents.begin(), elements.imageComponents.end(),
[](const std::unique_ptr<ImageComponent>& a, const std::unique_ptr<ImageComponent>& b) {
return b->getZIndex() > a->getZIndex();
});
std::stable_sort(
elements.textComponents.begin(), elements.textComponents.end(),
[](const std::unique_ptr<TextComponent>& a, const std::unique_ptr<TextComponent>& b) {
return b->getZIndex() > a->getZIndex();
});
std::stable_sort(
elements.containerTextComponents.begin(), elements.containerTextComponents.end(),
[](const std::unique_ptr<TextComponent>& a, const std::unique_ptr<TextComponent>& b) {
return b->getZIndex() > a->getZIndex();
});
mSystemElements.emplace_back(std::move(elements));
mSystemElements.back().helpStyle.applyTheme(theme, "system");
if (mPrimary == nullptr) {
mCarousel = std::make_unique<CarouselComponent<SystemData*>>();
mPrimary = mCarousel.get();
@ -812,17 +734,10 @@ void SystemView::populate()
if (mCarousel != nullptr) {
CarouselComponent<SystemData*>::Entry entry;
if (mLegacyMode) {
// Keep showing only the short name for legacy themes to maintain maximum
// backward compatibility. This also applies to unreadable theme sets.
entry.name = it->getName();
}
else {
if (itemText == "")
entry.name = it->getFullName();
else
entry.name = itemText;
}
if (itemText == "")
entry.name = it->getFullName();
else
entry.name = itemText;
letterCaseFunc(entry.name);
entry.object = it;
entry.data.imagePath = imagePath;
@ -924,47 +839,39 @@ void SystemView::updateGameCount(SystemData* system)
games = true;
}
if (mLegacyMode) {
mLegacySystemInfo->setText(ss.str());
}
else {
auto elementsIt = std::find_if(mSystemElements.cbegin(), mSystemElements.cend(),
[sourceSystem](const SystemViewElements& systemElements) {
return systemElements.system == sourceSystem;
});
for (auto& gameCountComp : (*elementsIt).gameCountComponents) {
if (gameCountComp->getThemeSystemdata() == "gamecount") {
auto elementsIt = std::find_if(mSystemElements.cbegin(), mSystemElements.cend(),
[sourceSystem](const SystemViewElements& systemElements) {
return systemElements.system == sourceSystem;
});
for (auto& gameCountComp : (*elementsIt).gameCountComponents) {
if (gameCountComp->getThemeSystemdata() == "gamecount") {
gameCountComp->setValue(ss.str());
}
else if (gameCountComp->getThemeSystemdata() == "gamecountGames") {
if (games)
gameCountComp->setValue(ssGames.str());
else
gameCountComp->setValue(ss.str());
}
else if (gameCountComp->getThemeSystemdata() == "gamecountGamesNoText") {
gameCountComp->setValue(std::to_string(gameCount.first));
}
else if (gameCountComp->getThemeSystemdata() == "gamecountFavorites") {
gameCountComp->setValue(ssFavorites.str());
}
else if (gameCountComp->getThemeSystemdata() == "gamecountFavoritesNoText") {
if (!favoriteSystem && !recentSystem) {
gameCountComp->setValue(std::to_string(gameCount.second));
}
else if (gameCountComp->getThemeSystemdata() == "gamecountGames") {
if (games)
gameCountComp->setValue(ssGames.str());
else
gameCountComp->setValue(ss.str());
}
else if (gameCountComp->getThemeSystemdata() == "gamecountGamesNoText") {
gameCountComp->setValue(std::to_string(gameCount.first));
}
else if (gameCountComp->getThemeSystemdata() == "gamecountFavorites") {
gameCountComp->setValue(ssFavorites.str());
}
else if (gameCountComp->getThemeSystemdata() == "gamecountFavoritesNoText") {
if (!favoriteSystem && !recentSystem) {
gameCountComp->setValue(std::to_string(gameCount.second));
}
}
else {
gameCountComp->setValue(gameCountComp->getThemeSystemdata());
}
}
else {
gameCountComp->setValue(gameCountComp->getThemeSystemdata());
}
}
}
void SystemView::updateGameSelectors()
{
if (mLegacyMode)
return;
const int cursor {mPrimary->getCursor()};
if (mSystemElements[cursor].gameSelectors.size() == 0)
@ -1479,36 +1386,6 @@ void SystemView::updateGameSelectors()
}
}
void SystemView::legacyApplyTheme(const std::shared_ptr<ThemeData>& theme)
{
if (theme->hasView("system"))
mViewNeedsReload = false;
else
mViewNeedsReload = true;
if (mCarousel != nullptr)
mPrimary->applyTheme(theme, "system", "carousel_systemcarousel", ThemeFlags::ALL);
else if (mTextList != nullptr)
mPrimary->applyTheme(theme, "system", "textlist_gamelist", ThemeFlags::ALL);
mLegacySystemInfo->setSize(mSize.x, mLegacySystemInfo->getFont()->getLetterHeight() * 2.2f);
mLegacySystemInfo->setPosition(0.0f,
std::floor(mPrimary->getPosition().y) + mPrimary->getSize().y);
mLegacySystemInfo->setBackgroundColor(0xDDDDDDD8);
mLegacySystemInfo->setRenderBackground(true);
mLegacySystemInfo->setFont(Font::get(0.035f * mSize.y, Font::getDefaultPath()));
mLegacySystemInfo->setColor(0x000000FF);
mLegacySystemInfo->setUppercase(true);
mLegacySystemInfo->setZIndex(50.0f);
mLegacySystemInfo->setDefaultZIndex(50.0f);
const ThemeData::ThemeElement* sysInfoElem {
theme->getElement("system", "text_systemInfo", "text")};
if (sysInfoElem)
mLegacySystemInfo->applyTheme(theme, "system", "text_systemInfo", ThemeFlags::ALL);
}
void SystemView::renderElements(const glm::mat4& parentTrans, bool abovePrimary)
{
glm::mat4 trans {getTransform() * parentTrans};
@ -1524,7 +1401,7 @@ void SystemView::renderElements(const glm::mat4& parentTrans, bool abovePrimary)
renderAfter += 1;
}
for (int i = renderBefore; i <= renderAfter; ++i) {
for (int i {renderBefore}; i <= renderAfter; ++i) {
int index {i};
while (index < 0)
index += static_cast<int>(mPrimary->getNumEntries());
@ -1560,24 +1437,7 @@ void SystemView::renderElements(const glm::mat4& parentTrans, bool abovePrimary)
static_cast<int>(glm::round(elementTrans[3].y))},
glm::ivec2 {static_cast<int>(mSize.x), static_cast<int>(mSize.y)});
if (mLegacyMode && mSystemElements.size() > static_cast<size_t>(index)) {
for (auto element : mSystemElements[index].legacyExtras) {
if (abovePrimary && element->getZIndex() < primaryZIndex)
continue;
if ((mFadeTransitions || element->getDimming() != 1.0f) &&
element->getZIndex() < primaryZIndex)
element->setDimming(1.0f - mFadeOpacity);
if (mFadeTransitions && mPrimary->getFadeAbovePrimary()) {
if (mFadeTransitions && isAnimationPlaying(0))
element->setOpacity(1.0f - mFadeOpacity);
else
element->setOpacity(1.0f);
}
element->render(elementTrans);
}
}
else if (!mLegacyMode && mSystemElements.size() > static_cast<size_t>(index)) {
if (mSystemElements.size() > static_cast<size_t>(index)) {
for (auto child : mSystemElements[index].children) {
if (abovePrimary && (child->getZIndex() > primaryZIndex)) {
if (mFadeTransitions && mPrimary->getFadeAbovePrimary()) {
@ -1598,18 +1458,6 @@ void SystemView::renderElements(const glm::mat4& parentTrans, bool abovePrimary)
}
}
if (mLegacyMode) {
if (mFadeTransitions && !abovePrimary) {
if (mFadeTransitions && isAnimationPlaying(0))
mLegacySystemInfo->setOpacity(1.0f - mFadeOpacity);
else
mLegacySystemInfo->setOpacity(1.0f);
}
if ((abovePrimary && mLegacySystemInfo->getZIndex() > 40.0f) ||
(!abovePrimary && mLegacySystemInfo->getZIndex() <= 40.0f))
mLegacySystemInfo->render(elementTrans);
}
mRenderer->popClipRect();
}
}

View file

@ -36,7 +36,6 @@ public:
using PrimaryType = PrimaryComponent<SystemData*>::PrimaryType;
SystemView();
~SystemView();
void onShow() override;
void onTransition() override;
@ -108,7 +107,6 @@ private:
void populate();
void updateGameCount(SystemData* system = nullptr);
void updateGameSelectors();
void legacyApplyTheme(const std::shared_ptr<ThemeData>& theme);
void renderElements(const glm::mat4& parentTrans, bool abovePrimary);
struct SystemViewElements {
@ -117,7 +115,6 @@ private:
std::string name;
std::string fullName;
std::vector<std::unique_ptr<GameSelectorComponent>> gameSelectors;
std::vector<GuiComponent*> legacyExtras;
std::vector<GuiComponent*> children;
std::vector<std::unique_ptr<ImageComponent>> imageComponents;
@ -136,7 +133,6 @@ private:
std::unique_ptr<CarouselComponent<SystemData*>> mCarousel;
std::unique_ptr<GridComponent<SystemData*>> mGrid;
std::unique_ptr<TextListComponent<SystemData*>> mTextList;
std::unique_ptr<TextComponent> mLegacySystemInfo;
std::vector<SystemViewElements> mSystemElements;
PrimaryComponent<SystemData*>* mPrimary;
PrimaryType mPrimaryType;
@ -152,7 +148,6 @@ private:
bool mUpdatedGameCount;
bool mViewNeedsReload;
bool mLegacyMode;
bool mNavigated;
bool mMaxFade;
bool mFadeTransitions;

View file

@ -51,7 +51,6 @@ ViewController::ViewController() noexcept
, mNextSystem {false}
{
mState.viewing = NOTHING;
mState.viewstyle = AUTOMATIC;
}
ViewController* ViewController::getInstance()
@ -699,19 +698,6 @@ void ViewController::goToGamelist(SystemData* system)
mState.viewing = GAMELIST;
mState.system = system;
if (system->getTheme()->isLegacyTheme()) {
auto it = mGamelistViews.find(system);
if (it != mGamelistViews.cend()) {
std::string viewStyle {it->second->getName()};
if (viewStyle == "basic")
mState.viewstyle = BASIC;
else if (viewStyle == "detailed")
mState.viewstyle = DETAILED;
else if (viewStyle == "video")
mState.viewstyle = VIDEO;
}
}
if (mCurrentView)
mCurrentView->onShow();
@ -905,55 +891,7 @@ std::shared_ptr<GamelistView> ViewController::getGamelistView(SystemData* system
// If there's no entry, then create it and return it.
std::shared_ptr<GamelistView> view;
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) {
const std::vector<FileData*> files {
system->getRootFolder()->getFilesRecursive(GAME | FOLDER)};
for (auto it = files.cbegin(); it != files.cend(); ++it) {
if (themeHasVideoView && !(*it)->getVideoPath().empty()) {
selectedViewStyle = VIDEO;
break;
}
else if (!(*it)->getImagePath().empty()) {
selectedViewStyle = DETAILED;
// Don't break out in case any subsequent files have videos.
}
}
}
// 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 if (Settings::getInstance()->getBool("ThemeVariantTriggers")) {
if (Settings::getInstance()->getBool("ThemeVariantTriggers")) {
const auto overrides = system->getTheme()->getCurrentThemeSetSelectedVariantOverrides();
if (!overrides.empty()) {
@ -1469,15 +1407,8 @@ HelpStyle ViewController::getHelpStyle()
HelpStyle ViewController::getViewHelpStyle()
{
if (mState.getSystem()->getTheme()->isLegacyTheme()) {
// For backward compatibility with legacy theme sets, read the helpsystem theme config
// from the system view entry.
if (mState.viewing == ViewMode::GAMELIST)
return getGamelistView(mState.getSystem())->getHelpStyle();
else
return getSystemListView()->getHelpStyle();
}
else {
if (mState.viewing == ViewMode::GAMELIST)
return getGamelistView(mState.getSystem())->getHelpStyle();
else
return getSystemListView()->getHelpStyle();
}
}

View file

@ -104,16 +104,8 @@ public:
GAMELIST
};
enum GamelistViewStyle {
AUTOMATIC,
BASIC,
DETAILED,
VIDEO
};
struct State {
ViewMode viewing;
GamelistViewStyle viewstyle;
SystemData* getSystem() const
{

View file

@ -34,7 +34,6 @@ HelpStyle::HelpStyle()
, iconTextSpacingDimmed {iconTextSpacing}
, opacity {1.0f}
, opacityDimmed {opacity}
, legacyTheme {false}
, letterCase {"uppercase"}
{
}
@ -45,8 +44,6 @@ void HelpStyle::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::s
if (!elem)
return;
legacyTheme = theme->isLegacyTheme();
if (elem->has("pos"))
position = elem->get<glm::vec2>("pos") *
glm::vec2 {Renderer::getScreenWidth(), Renderer::getScreenHeight()};
@ -82,15 +79,13 @@ void HelpStyle::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::s
iconColorDimmed = iconColor;
if (elem->has("fontPath") || elem->has("fontSize")) {
font = Font::getFromTheme(elem, ThemeFlags::ALL, font, 0.0f, false, theme->isLegacyTheme());
font = Font::getFromTheme(elem, ThemeFlags::ALL, font, 0.0f, false);
if (!elem->has("fontSizeDimmed"))
fontDimmed = Font::getFromTheme(elem, ThemeFlags::ALL, font, 0.0f, false,
theme->isLegacyTheme());
fontDimmed = Font::getFromTheme(elem, ThemeFlags::ALL, font, 0.0f, false);
}
if (elem->has("fontSizeDimmed")) {
fontDimmed = Font::getFromTheme(elem, ThemeFlags::ALL, font, 0.0f, false,
theme->isLegacyTheme(), 1.0f, true);
fontDimmed = Font::getFromTheme(elem, ThemeFlags::ALL, font, 0.0f, false, 1.0f, true);
}
if (elem->has("entrySpacing"))

View file

@ -34,7 +34,6 @@ struct HelpStyle {
float iconTextSpacingDimmed;
float opacity;
float opacityDimmed;
bool legacyTheme;
std::string letterCase;
struct CustomButtonIcons {

View file

@ -65,7 +65,7 @@ namespace
continue;
}
pugi::xml_node node = doc.append_child(type.c_str());
pugi::xml_node node {doc.append_child(type.c_str())};
node.append_attribute("name").set_value(it->first.c_str());
node.append_attribute("value").set_value(it->second.second);
}
@ -160,8 +160,6 @@ void Settings::setDefaults()
mStringMap["ThemeColorScheme"] = {"", ""};
mStringMap["ThemeAspectRatio"] = {"", ""};
mStringMap["ThemeTransitions"] = {"automatic", "automatic"};
mStringMap["GamelistViewStyle"] = {"automatic", "automatic"};
mStringMap["LegacyThemeTransitions"] = {"builtin-instant", "builtin-instant"};
mStringMap["QuickSystemSelect"] = {"leftrightshoulders", "leftrightshoulders"};
mStringMap["StartupSystem"] = {"", ""};
mStringMap["DefaultSortOrder"] = {"filename, ascending", "filename, ascending"};
@ -214,8 +212,6 @@ void Settings::setDefaults()
mBoolMap["ThemeVariantTriggers"] = {true, true};
mBoolMap["MenuBlurBackground"] = {true, true};
mBoolMap["GamelistVideoPillarbox"] = {true, true};
mBoolMap["GamelistVideoScanlines"] = {false, false};
mBoolMap["FoldersOnTop"] = {true, true};
mBoolMap["FavoritesFirst"] = {true, true};
mBoolMap["FavoritesStar"] = {true, true};

View file

@ -20,8 +20,6 @@
#include <algorithm>
#include <pugixml.hpp>
#define MINIMUM_LEGACY_THEME_FORMAT_VERSION 3
// clang-format off
std::vector<std::string> ThemeData::sSupportedViews {
{"all"},
@ -53,35 +51,6 @@ std::vector<std::string> ThemeData::sSupportedTransitionAnimations {
{"builtin-slide"},
{"builtin-fade"}};
std::vector<std::string> ThemeData::sLegacySupportedViews {
{"all"},
{"system"},
{"basic"},
{"detailed"},
{"grid"},
{"video"}};
std::vector<std::string> ThemeData::sLegacySupportedFeatures {
{"navigationsounds"},
{"video"},
{"carousel"},
{"z-index"},
{"visible"}};
std::vector<std::string> ThemeData::sLegacyProperties {
{"showSnapshotNoVideo"},
{"showSnapshotDelay"},
{"forceUppercase"},
{"alignment"},
{"defaultLogo"},
{"logoSize"},
{"logoScale"},
{"logoRotation"},
{"logoRotationOrigin"},
{"logoAlignment"},
{"maxLogoCount"},
{"selectorOffsetY"}};
std::vector<std::pair<std::string, std::string>> ThemeData::sSupportedAspectRatios {
{"automatic", "automatic"},
{"16:9", "16:9"},
@ -137,7 +106,6 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"defaultImage", PATH},
{"defaultFolderImage", PATH},
{"maxItemCount", FLOAT},
{"maxLogoCount", FLOAT}, // For backward compatibility with legacy themes.
{"itemsBeforeCenter", UNSIGNED_INTEGER},
{"itemsAfterCenter", UNSIGNED_INTEGER},
{"itemStacking", STRING},
@ -173,12 +141,6 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"unfocusedItemSaturation", FLOAT},
{"unfocusedItemDimming", FLOAT},
{"fastScrolling", BOOLEAN},
{"defaultLogo", PATH}, // For backward compatibility with legacy themes.
{"logoSize", NORMALIZED_PAIR}, // For backward compatibility with legacy themes.
{"logoScale", FLOAT}, // For backward compatibility with legacy themes.
{"logoRotation", FLOAT}, // For backward compatibility with legacy themes.
{"logoRotationOrigin", NORMALIZED_PAIR}, // For backward compatibility with legacy themes.
{"logoAlignment", STRING}, // For backward compatibility with legacy themes.
{"color", COLOR},
{"colorEnd", COLOR},
{"gradientType", STRING},
@ -196,8 +158,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"systemNameSuffix", BOOLEAN},
{"letterCaseSystemNameSuffix", STRING},
{"fadeAbovePrimary", BOOLEAN},
{"zIndex", FLOAT},
{"legacyZIndexMode", STRING}}}, // For backward compatibility with legacy themes.
{"zIndex", FLOAT}}},
{"grid",
{{"pos", NORMALIZED_PAIR},
{"size", NORMALIZED_PAIR},
@ -260,7 +221,6 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"selectorHeight", FLOAT},
{"selectorHorizontalOffset", FLOAT},
{"selectorVerticalOffset", FLOAT},
{"selectorOffsetY", FLOAT}, // For backward compatibility with legacy themes.
{"selectorColor", COLOR},
{"selectorColorEnd", COLOR},
{"selectorGradientType", STRING},
@ -274,14 +234,11 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"selectedSecondaryBackgroundColor", COLOR},
{"fontPath", PATH},
{"fontSize", FLOAT},
{"scrollSound", PATH}, // For backward compatibility with legacy themes.
{"horizontalAlignment", STRING},
{"alignment", STRING}, // For backward compatibility with legacy themes.
{"horizontalMargin", FLOAT},
{"letterCase", STRING},
{"letterCaseAutoCollections", STRING},
{"letterCaseCustomCollections", STRING},
{"forceUppercase", BOOLEAN}, // For backward compatibility with legacy themes.
{"lineSpacing", FLOAT},
{"indicators", STRING},
{"collectionIndicators", STRING},
@ -348,9 +305,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"opacity", FLOAT},
{"saturation", FLOAT},
{"visible", BOOLEAN},
{"zIndex", FLOAT},
{"showSnapshotNoVideo", BOOLEAN}, // For backward compatibility with legacy themes.
{"showSnapshotDelay", BOOLEAN}}}, // For backward compatibility with legacy themes.
{"zIndex", FLOAT}}},
{"animation",
{{"pos", NORMALIZED_PAIR},
{"size", NORMALIZED_PAIR},
@ -379,7 +334,6 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"rotation", FLOAT},
{"rotationOrigin", NORMALIZED_PAIR},
{"horizontalAlignment", STRING},
{"alignment", STRING}, // For backward compatibility with legacy themes.
{"direction", STRING},
{"lines", UNSIGNED_INTEGER},
{"itemsPerLine", UNSIGNED_INTEGER},
@ -428,11 +382,9 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"fontSize", FLOAT},
{"horizontalAlignment", STRING},
{"verticalAlignment", STRING},
{"alignment", STRING}, // For backward compatibility with legacy themes.
{"color", COLOR},
{"backgroundColor", COLOR},
{"letterCase", STRING},
{"forceUppercase", BOOLEAN}, // For backward compatibility with legacy themes.
{"lineSpacing", FLOAT},
{"opacity", FLOAT},
{"visible", BOOLEAN},
@ -451,11 +403,9 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"fontSize", FLOAT},
{"horizontalAlignment", STRING},
{"verticalAlignment", STRING},
{"alignment", STRING}, // For backward compatibility with legacy themes.
{"color", COLOR},
{"backgroundColor", COLOR},
{"letterCase", STRING},
{"forceUppercase", BOOLEAN}, // For backward compatibility with legacy themes.
{"lineSpacing", FLOAT},
{"format", STRING},
{"displayRelative", BOOLEAN},
@ -472,7 +422,6 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"fontSize", FLOAT},
{"horizontalAlignment", STRING},
{"verticalAlignment", STRING},
{"alignment", STRING}, // For backward compatibility with legacy themes.
{"color", COLOR},
{"backgroundColor", COLOR},
{"opacity", FLOAT},
@ -515,56 +464,15 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"iconTextSpacing", FLOAT},
{"iconTextSpacingDimmed", FLOAT},
{"letterCase", STRING},
{"textStyle", STRING}, // For backward compatibility with legacy themes.
{"opacity", FLOAT},
{"opacityDimmed", FLOAT},
{"customButtonIcon", PATH}}},
{"navigationsounds",
{{"systembrowseSound", PATH},
{"quicksysselectSound", PATH},
{"selectSound", PATH},
{"backSound", PATH},
{"scrollSound", PATH},
{"favoriteSound", PATH},
{"launchSound", PATH}}},
// Legacy components below, not in use any longer but needed for backward compatibility.
{"sound",
{{"path", PATH}}},
{"imagegrid",
{{"pos", NORMALIZED_PAIR},
{"size", NORMALIZED_PAIR},
{"margin", NORMALIZED_PAIR},
{"padding", NORMALIZED_RECT},
{"autoLayout", NORMALIZED_PAIR},
{"autoLayoutSelectedZoom", FLOAT},
{"gameImage", PATH},
{"folderImage", PATH},
{"imageSource", STRING},
{"scrollDirection", STRING},
{"centerSelection", BOOLEAN},
{"scrollLoop", BOOLEAN},
{"animate", BOOLEAN},
{"zIndex", FLOAT}}},
{"gridtile",
{{"size", NORMALIZED_PAIR},
{"padding", NORMALIZED_PAIR},
{"imageColor", COLOR},
{"backgroundImage", PATH},
{"backgroundCornerSize", NORMALIZED_PAIR},
{"backgroundColor", COLOR},
{"backgroundCenterColor", COLOR},
{"backgroundEdgeColor", COLOR}}},
{"ninepatch",
{{"pos", NORMALIZED_PAIR},
{"size", NORMALIZED_PAIR},
{"path", PATH},
{"visible", BOOLEAN},
{"zIndex", FLOAT}}}};
{{"path", PATH}}}};
// clang-format on
ThemeData::ThemeData()
: mLegacyTheme {false}
, mCustomCollection {false}
: mCustomCollection {false}
{
sCurrentThemeSet = sThemeSets.find(Settings::getInstance()->getString("ThemeSet"));
sVariantDefinedTransitions = "";
@ -605,93 +513,70 @@ void ThemeData::loadFile(const std::map<std::string, std::string>& sysDataMap,
if (!root)
throw error << ": Missing <theme> tag";
if (sCurrentThemeSet != sThemeSets.cend())
mLegacyTheme = sCurrentThemeSet->second.capabilities.legacyTheme;
// The resolution tag introduced in RetroPie EmulationStation in 2020 is a very bad idea
// as it changes sizing of components from relative values to absolute pixel values.
// So themes using it will simply not get loaded at all.
if (root.child("resolution") != nullptr)
throw error << ": <resolution> tag not supported";
// Check for legacy theme version.
int legacyVersion {root.child("formatVersion").text().as_int(-1)};
if (root.child("formatVersion") != nullptr)
throw error << ": Legacy <formatVersion> tag found";
if (mLegacyTheme) {
if (legacyVersion == -1)
throw error << ": <formatVersion> tag missing for legacy theme set";
if (sCurrentThemeSet->second.capabilities.variants.size() > 0) {
for (auto& variant : sCurrentThemeSet->second.capabilities.variants)
mVariants.emplace_back(variant.name);
if (legacyVersion < MINIMUM_LEGACY_THEME_FORMAT_VERSION)
throw error << ": Defined legacy format version " << legacyVersion
<< " is less than the minimum supported version "
<< MINIMUM_LEGACY_THEME_FORMAT_VERSION;
}
else if (legacyVersion != -1) {
throw error << ": Legacy <formatVersion> tag found for non-legacy theme set";
if (std::find(mVariants.cbegin(), mVariants.cend(),
Settings::getInstance()->getString("ThemeVariant")) != mVariants.cend())
mSelectedVariant = Settings::getInstance()->getString("ThemeVariant");
else
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 (!mLegacyTheme) {
if (sCurrentThemeSet->second.capabilities.variants.size() > 0) {
for (auto& variant : sCurrentThemeSet->second.capabilities.variants)
mVariants.emplace_back(variant.name);
if (sCurrentThemeSet->second.capabilities.colorSchemes.size() > 0) {
for (auto& colorScheme : sCurrentThemeSet->second.capabilities.colorSchemes)
mColorSchemes.emplace_back(colorScheme.name);
if (std::find(mVariants.cbegin(), mVariants.cend(),
Settings::getInstance()->getString("ThemeVariant")) != mVariants.cend())
mSelectedVariant = Settings::getInstance()->getString("ThemeVariant");
else
mSelectedVariant = mVariants.front();
// Special shortcut variant to apply configuration to all defined variants.
mVariants.emplace_back("all");
if (std::find(mColorSchemes.cbegin(), mColorSchemes.cend(),
Settings::getInstance()->getString("ThemeColorScheme")) !=
mColorSchemes.cend())
mSelectedColorScheme = Settings::getInstance()->getString("ThemeColorScheme");
else
mSelectedColorScheme = mColorSchemes.front();
}
if (trigger != ThemeTriggers::TriggerType::NONE) {
auto overrides = getCurrentThemeSetSelectedVariantOverrides();
if (overrides.find(trigger) != overrides.end())
mOverrideVariant = overrides.at(trigger).first;
}
}
sAspectRatioMatch = false;
if (sCurrentThemeSet->second.capabilities.colorSchemes.size() > 0) {
for (auto& colorScheme : sCurrentThemeSet->second.capabilities.colorSchemes)
mColorSchemes.emplace_back(colorScheme.name);
if (sCurrentThemeSet->second.capabilities.aspectRatios.size() > 0) {
if (std::find(sCurrentThemeSet->second.capabilities.aspectRatios.cbegin(),
sCurrentThemeSet->second.capabilities.aspectRatios.cend(),
Settings::getInstance()->getString("ThemeAspectRatio")) !=
sCurrentThemeSet->second.capabilities.aspectRatios.cend())
sSelectedAspectRatio = Settings::getInstance()->getString("ThemeAspectRatio");
else
sSelectedAspectRatio = sCurrentThemeSet->second.capabilities.aspectRatios.front();
if (std::find(mColorSchemes.cbegin(), mColorSchemes.cend(),
Settings::getInstance()->getString("ThemeColorScheme")) !=
mColorSchemes.cend())
mSelectedColorScheme = Settings::getInstance()->getString("ThemeColorScheme");
else
mSelectedColorScheme = mColorSchemes.front();
}
if (sSelectedAspectRatio == "automatic") {
// Auto-detect the closest aspect ratio based on what's available in the theme set.
sSelectedAspectRatio = "16:9";
const float screenAspectRatio {Renderer::getScreenAspectRatio()};
float diff {std::fabs(sAspectRatioMap["16:9"] - screenAspectRatio)};
sAspectRatioMatch = false;
for (auto& aspectRatio : sCurrentThemeSet->second.capabilities.aspectRatios) {
if (aspectRatio == "automatic")
continue;
if (sCurrentThemeSet->second.capabilities.aspectRatios.size() > 0) {
if (std::find(sCurrentThemeSet->second.capabilities.aspectRatios.cbegin(),
sCurrentThemeSet->second.capabilities.aspectRatios.cend(),
Settings::getInstance()->getString("ThemeAspectRatio")) !=
sCurrentThemeSet->second.capabilities.aspectRatios.cend())
sSelectedAspectRatio = Settings::getInstance()->getString("ThemeAspectRatio");
else
sSelectedAspectRatio = sCurrentThemeSet->second.capabilities.aspectRatios.front();
if (sSelectedAspectRatio == "automatic") {
// Auto-detect the closest aspect ratio based on what's available in the theme set.
sSelectedAspectRatio = "16:9";
const float screenAspectRatio {Renderer::getScreenAspectRatio()};
float diff {std::fabs(sAspectRatioMap["16:9"] - screenAspectRatio)};
for (auto& aspectRatio : sCurrentThemeSet->second.capabilities.aspectRatios) {
if (aspectRatio == "automatic")
continue;
if (sAspectRatioMap.find(aspectRatio) != sAspectRatioMap.end()) {
const float newDiff {
std::fabs(sAspectRatioMap[aspectRatio] - screenAspectRatio)};
if (newDiff < 0.01f)
sAspectRatioMatch = true;
if (newDiff < diff) {
diff = newDiff;
sSelectedAspectRatio = aspectRatio;
}
if (sAspectRatioMap.find(aspectRatio) != sAspectRatioMap.end()) {
const float newDiff {
std::fabs(sAspectRatioMap[aspectRatio] - screenAspectRatio)};
if (newDiff < 0.01f)
sAspectRatioMatch = true;
if (newDiff < diff) {
diff = newDiff;
sSelectedAspectRatio = aspectRatio;
}
}
}
@ -699,19 +584,13 @@ void ThemeData::loadFile(const std::map<std::string, std::string>& sysDataMap,
}
parseVariables(root);
if (!mLegacyTheme)
parseColorSchemes(root);
parseColorSchemes(root);
parseIncludes(root);
parseViews(root);
// For non-legacy themes this will simply check for the presence of a feature tag and throw
// an error if it's found.
parseFeatures(root);
if (!mLegacyTheme) {
parseVariants(root);
parseAspectRatios(root);
}
if (root.child("feature") != nullptr)
throw error << ": Legacy <feature> tag found";
parseVariants(root);
parseAspectRatios(root);
}
bool ThemeData::hasView(const std::string& view)
@ -720,37 +599,6 @@ bool ThemeData::hasView(const std::string& view)
return (viewIt != mViews.cend());
}
std::vector<GuiComponent*> ThemeData::makeExtras(const std::shared_ptr<ThemeData>& theme,
const std::string& view)
{
std::vector<GuiComponent*> comps;
auto viewIt = theme->mViews.find(view);
if (viewIt == theme->mViews.cend())
return comps;
for (auto it = viewIt->second.legacyOrderedKeys.cbegin(); // Line break.
it != viewIt->second.legacyOrderedKeys.cend(); ++it) {
ThemeElement& elem {viewIt->second.elements.at(*it)};
if (elem.extra) {
GuiComponent* comp {nullptr};
const std::string& t {elem.type};
if (t == "image")
comp = new ImageComponent;
else if (t == "text")
comp = new TextComponent;
if (comp) {
comp->setDefaultZIndex(10.0f);
comp->applyTheme(theme, view, *it, ThemeFlags::ALL);
comps.push_back(comp);
}
}
}
return comps;
}
const ThemeData::ThemeElement* ThemeData::getElement(const std::string& view,
const std::string& element,
const std::string& expectedType) const
@ -854,6 +702,9 @@ void ThemeData::populateThemeSets()
#endif
ThemeCapability capabilities {parseThemeCapabilities(*it)};
if (!capabilities.validTheme)
continue;
std::string themeName;
if (capabilities.themeName != "") {
themeName.append(" (theme name \"")
@ -862,27 +713,22 @@ void ThemeData::populateThemeSets()
}
#if defined(_WIN64)
LOG(LogInfo) << "Added" << (capabilities.legacyTheme ? " legacy" : "")
<< " theme set \"" << Utils::String::replace(*it, "/", "\\") << "\""
<< themeName;
LOG(LogInfo) << "Added theme set \"" << Utils::String::replace(*it, "/", "\\")
<< "\"" << themeName;
#else
LOG(LogInfo) << "Added" << (capabilities.legacyTheme ? " legacy" : "")
<< " theme set \"" << *it << "\"" << themeName;
LOG(LogInfo) << "Added theme set \"" << *it << "\"" << themeName;
#endif
if (!capabilities.legacyTheme) {
int aspectRatios {0};
if (capabilities.aspectRatios.size() > 0)
aspectRatios = static_cast<int>(capabilities.aspectRatios.size()) - 1;
LOG(LogDebug) << "Theme set includes support for "
<< capabilities.variants.size() << " variant"
<< (capabilities.variants.size() != 1 ? "s" : "") << ", "
<< capabilities.colorSchemes.size() << " color scheme"
<< (capabilities.colorSchemes.size() != 1 ? "s" : "") << ", "
<< aspectRatios << " aspect ratio"
<< (aspectRatios != 1 ? "s" : "") << " and "
<< capabilities.transitions.size() << " transition"
<< (capabilities.transitions.size() != 1 ? "s" : "");
}
int aspectRatios {0};
if (capabilities.aspectRatios.size() > 0)
aspectRatios = static_cast<int>(capabilities.aspectRatios.size()) - 1;
LOG(LogDebug) << "Theme set includes support for " << capabilities.variants.size()
<< " variant" << (capabilities.variants.size() != 1 ? "s" : "")
<< ", " << capabilities.colorSchemes.size() << " color scheme"
<< (capabilities.colorSchemes.size() != 1 ? "s" : "") << ", "
<< aspectRatios << " aspect ratio" << (aspectRatios != 1 ? "s" : "")
<< " and " << capabilities.transitions.size() << " transition"
<< (capabilities.transitions.size() != 1 ? "s" : "");
ThemeSet set {*it, capabilities};
sThemeSets[set.getName()] = set;
}
@ -958,77 +804,63 @@ void ThemeData::setThemeTransitions()
int transitionAnim {ViewTransitionAnimation::INSTANT};
setTransitionsFunc(transitionAnim);
if (sCurrentThemeSet->second.capabilities.legacyTheme) {
const std::string& legacyTransitionsSetting {
Settings::getInstance()->getString("LegacyThemeTransitions")};
if (legacyTransitionsSetting == "builtin-slide")
transitionAnim = static_cast<int>(ViewTransitionAnimation::SLIDE);
else if (legacyTransitionsSetting == "builtin-fade")
transitionAnim = static_cast<int>(ViewTransitionAnimation::FADE);
setTransitionsFunc(transitionAnim);
const std::string& transitionsSetting {Settings::getInstance()->getString("ThemeTransitions")};
std::string profile;
size_t profileEntry {0};
if (transitionsSetting == "automatic") {
if (sVariantDefinedTransitions != "")
profile = sVariantDefinedTransitions;
else if (!sCurrentThemeSet->second.capabilities.transitions.empty())
profile = sCurrentThemeSet->second.capabilities.transitions.front().name;
}
else {
const std::string& transitionsSetting {
Settings::getInstance()->getString("ThemeTransitions")};
std::string profile;
size_t profileEntry {0};
profile = transitionsSetting;
}
if (transitionsSetting == "automatic") {
if (sVariantDefinedTransitions != "")
profile = sVariantDefinedTransitions;
else if (!sCurrentThemeSet->second.capabilities.transitions.empty())
profile = sCurrentThemeSet->second.capabilities.transitions.front().name;
}
else {
profile = transitionsSetting;
}
auto it = std::find_if(
sCurrentThemeSet->second.capabilities.transitions.cbegin(),
sCurrentThemeSet->second.capabilities.transitions.cend(),
[&profile](const ThemeTransitions transitions) { return transitions.name == profile; });
if (it != sCurrentThemeSet->second.capabilities.transitions.cend())
profileEntry = static_cast<size_t>(
std::distance(sCurrentThemeSet->second.capabilities.transitions.cbegin(), it) + 1);
auto it = std::find_if(
sCurrentThemeSet->second.capabilities.transitions.cbegin(),
sCurrentThemeSet->second.capabilities.transitions.cend(),
[&profile](const ThemeTransitions transitions) { return transitions.name == profile; });
if (it != sCurrentThemeSet->second.capabilities.transitions.cend())
profileEntry = static_cast<size_t>(
std::distance(sCurrentThemeSet->second.capabilities.transitions.cbegin(), it) + 1);
if (profileEntry != 0 &&
sCurrentThemeSet->second.capabilities.transitions.size() > profileEntry - 1) {
auto transitionMap =
sCurrentThemeSet->second.capabilities.transitions[profileEntry - 1].animations;
if (transitionMap.find(ViewTransition::SYSTEM_TO_SYSTEM) != transitionMap.end())
Settings::getInstance()->setInt("TransitionsSystemToSystem",
transitionMap[ViewTransition::SYSTEM_TO_SYSTEM]);
if (transitionMap.find(ViewTransition::SYSTEM_TO_GAMELIST) != transitionMap.end())
Settings::getInstance()->setInt("TransitionsSystemToGamelist",
transitionMap[ViewTransition::SYSTEM_TO_GAMELIST]);
if (transitionMap.find(ViewTransition::GAMELIST_TO_GAMELIST) != transitionMap.end())
Settings::getInstance()->setInt(
"TransitionsGamelistToGamelist",
transitionMap[ViewTransition::GAMELIST_TO_GAMELIST]);
if (transitionMap.find(ViewTransition::GAMELIST_TO_SYSTEM) != transitionMap.end())
Settings::getInstance()->setInt("TransitionsGamelistToSystem",
transitionMap[ViewTransition::GAMELIST_TO_SYSTEM]);
if (transitionMap.find(ViewTransition::STARTUP_TO_SYSTEM) != transitionMap.end())
Settings::getInstance()->setInt("TransitionsStartupToSystem",
transitionMap[ViewTransition::STARTUP_TO_SYSTEM]);
if (transitionMap.find(ViewTransition::STARTUP_TO_GAMELIST) != transitionMap.end())
Settings::getInstance()->setInt("TransitionsStartupToGamelist",
transitionMap[ViewTransition::STARTUP_TO_GAMELIST]);
}
else if (transitionsSetting == "builtin-slide" || transitionsSetting == "builtin-fade") {
if (std::find(
sCurrentThemeSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
sCurrentThemeSet->second.capabilities.suppressedTransitionProfiles.cend(),
transitionsSetting) ==
sCurrentThemeSet->second.capabilities.suppressedTransitionProfiles.cend()) {
if (transitionsSetting == "builtin-slide") {
transitionAnim = static_cast<int>(ViewTransitionAnimation::SLIDE);
}
else if (transitionsSetting == "builtin-fade") {
transitionAnim = static_cast<int>(ViewTransitionAnimation::FADE);
}
setTransitionsFunc(transitionAnim);
if (profileEntry != 0 &&
sCurrentThemeSet->second.capabilities.transitions.size() > profileEntry - 1) {
auto transitionMap =
sCurrentThemeSet->second.capabilities.transitions[profileEntry - 1].animations;
if (transitionMap.find(ViewTransition::SYSTEM_TO_SYSTEM) != transitionMap.end())
Settings::getInstance()->setInt("TransitionsSystemToSystem",
transitionMap[ViewTransition::SYSTEM_TO_SYSTEM]);
if (transitionMap.find(ViewTransition::SYSTEM_TO_GAMELIST) != transitionMap.end())
Settings::getInstance()->setInt("TransitionsSystemToGamelist",
transitionMap[ViewTransition::SYSTEM_TO_GAMELIST]);
if (transitionMap.find(ViewTransition::GAMELIST_TO_GAMELIST) != transitionMap.end())
Settings::getInstance()->setInt("TransitionsGamelistToGamelist",
transitionMap[ViewTransition::GAMELIST_TO_GAMELIST]);
if (transitionMap.find(ViewTransition::GAMELIST_TO_SYSTEM) != transitionMap.end())
Settings::getInstance()->setInt("TransitionsGamelistToSystem",
transitionMap[ViewTransition::GAMELIST_TO_SYSTEM]);
if (transitionMap.find(ViewTransition::STARTUP_TO_SYSTEM) != transitionMap.end())
Settings::getInstance()->setInt("TransitionsStartupToSystem",
transitionMap[ViewTransition::STARTUP_TO_SYSTEM]);
if (transitionMap.find(ViewTransition::STARTUP_TO_GAMELIST) != transitionMap.end())
Settings::getInstance()->setInt("TransitionsStartupToGamelist",
transitionMap[ViewTransition::STARTUP_TO_GAMELIST]);
}
else if (transitionsSetting == "builtin-slide" || transitionsSetting == "builtin-fade") {
if (std::find(sCurrentThemeSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
sCurrentThemeSet->second.capabilities.suppressedTransitionProfiles.cend(),
transitionsSetting) ==
sCurrentThemeSet->second.capabilities.suppressedTransitionProfiles.cend()) {
if (transitionsSetting == "builtin-slide") {
transitionAnim = static_cast<int>(ViewTransitionAnimation::SLIDE);
}
else if (transitionsSetting == "builtin-fade") {
transitionAnim = static_cast<int>(ViewTransitionAnimation::FADE);
}
setTransitionsFunc(transitionAnim);
}
}
}
@ -1050,20 +882,15 @@ ThemeData::getCurrentThemeSetSelectedVariantOverrides()
const void ThemeData::themeLoadedLogOutput()
{
if (sCurrentThemeSet->second.capabilities.legacyTheme) {
LOG(LogInfo) << "Finished loading legacy theme set \"" << sCurrentThemeSet->first << "\"";
}
else {
LOG(LogInfo) << "Finished loading theme set \"" << sCurrentThemeSet->first << "\"";
if (sSelectedAspectRatio != "") {
const bool autoDetect {Settings::getInstance()->getString("ThemeAspectRatio") ==
"automatic"};
const std::string match {sAspectRatioMatch ? "exact match " : "closest match "};
LOG(LogInfo) << "Finished loading theme set \"" << sCurrentThemeSet->first << "\"";
if (sSelectedAspectRatio != "") {
const bool autoDetect {Settings::getInstance()->getString("ThemeAspectRatio") ==
"automatic"};
const std::string match {sAspectRatioMatch ? "exact match " : "closest match "};
LOG(LogInfo) << "Aspect ratio " << (autoDetect ? "automatically " : "manually ")
<< "set to " << (autoDetect ? match : "") << "\""
<< Utils::String::replace(sSelectedAspectRatio, "_", " ") << "\"";
}
LOG(LogInfo) << "Aspect ratio " << (autoDetect ? "automatically " : "manually ")
<< "set to " << (autoDetect ? match : "") << "\""
<< Utils::String::replace(sSelectedAspectRatio, "_", " ") << "\"";
}
}
@ -1117,7 +944,7 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
const std::string capFile {path + "/capabilities.xml"};
if (Utils::FileSystem::isRegularFile(capFile) || Utils::FileSystem::isSymlink(capFile)) {
capabilities.legacyTheme = false;
capabilities.validTheme = true;
pugi::xml_document doc;
#if defined(_WIN64)
@ -1519,8 +1346,10 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
}
}
else {
LOG(LogDebug) << "No capabilities.xml file found, flagging as legacy theme set";
capabilities.legacyTheme = true;
capabilities.validTheme = false;
LOG(LogWarning)
<< "No capabilities.xml file found, this does not appear to be a valid theme set: \""
<< path << "\"";
}
// Add the aspect ratios in the order they are defined in sSupportedAspectRatios so they
@ -1568,10 +1397,9 @@ void ThemeData::parseIncludes(const pugi::xml_node& root)
error << "ThemeData::parseIncludes(): ";
error.setFiles(mPaths);
if (!mLegacyTheme) {
if (root.child("formatVersion").text().as_int(-1) != -1)
throw error << ": Legacy <formatVersion> tag found for non-legacy theme set";
}
// Check for legacy theme version.
if (root.child("formatVersion") != nullptr)
throw error << ": Legacy <formatVersion> tag found";
for (pugi::xml_node node {root.child("include")}; node; node = node.next_sibling("include")) {
std::string relPath {resolvePlaceholders(node.text().as_string())};
@ -1624,49 +1452,20 @@ void ThemeData::parseIncludes(const pugi::xml_node& root)
if (!theme)
throw error << ": Missing <theme> tag";
if (!mLegacyTheme)
parseTransitions(theme);
parseTransitions(theme);
parseVariables(theme);
if (!mLegacyTheme)
parseColorSchemes(theme);
parseColorSchemes(theme);
parseIncludes(theme);
parseViews(theme);
// For non-legacy themes this will simply check for the presence of a feature tag and throw
// an error if it's found.
parseFeatures(theme);
if (!mLegacyTheme) {
parseVariants(theme);
parseAspectRatios(theme);
}
if (theme.child("feature") != nullptr)
throw error << ": Legacy <feature> tag found";
parseVariants(theme);
parseAspectRatios(theme);
mPaths.pop_back();
}
}
void ThemeData::parseFeatures(const pugi::xml_node& root)
{
ThemeException error;
error << "ThemeData::parseFeatures(): ";
error.setFiles(mPaths);
if (!mLegacyTheme && root.child("feature") != nullptr)
throw error << ": Legacy <feature> tag found for non-legacy theme set";
for (pugi::xml_node node {root.child("feature")}; node; node = node.next_sibling("feature")) {
if (!node.attribute("supported"))
throw error << ": Feature missing \"supported\" attribute";
const std::string supportedAttr {node.attribute("supported").as_string()};
if (std::find(sLegacySupportedFeatures.cbegin(), sLegacySupportedFeatures.cend(),
supportedAttr) != sLegacySupportedFeatures.cend()) {
parseViews(node);
}
}
}
void ThemeData::parseVariants(const pugi::xml_node& root)
{
if (sCurrentThemeSet == sThemeSets.end())
@ -1830,8 +1629,7 @@ void ThemeData::parseVariables(const pugi::xml_node& root)
const std::string val {resolvePlaceholders(it->text().as_string())};
if (!val.empty()) {
// Overriding existing variables is not allowed for legacy themes.
if (!mLegacyTheme && mVariables.find(key) != mVariables.end())
if (mVariables.find(key) != mVariables.end())
mVariables[key] = val;
else
mVariables.insert(std::pair<std::string, std::string>(key, val));
@ -1861,29 +1659,15 @@ void ThemeData::parseViews(const pugi::xml_node& root)
prevOff = nameAttr.find_first_not_of(delim, off);
off = nameAttr.find_first_of(delim, prevOff);
if (mLegacyTheme) {
if (std::find(sLegacySupportedViews.cbegin(), sLegacySupportedViews.cend(),
viewKey) != sLegacySupportedViews.cend()) {
ThemeView& view {
mViews.insert(std::pair<std::string, ThemeView>(viewKey, ThemeView()))
.first->second};
parseView(node, view);
}
else {
throw error << ": Unsupported \"" << viewKey << "\" view style defined";
}
if (std::find(sSupportedViews.cbegin(), sSupportedViews.cend(), viewKey) !=
sSupportedViews.cend()) {
ThemeView& view {
mViews.insert(std::pair<std::string, ThemeView>(viewKey, ThemeView()))
.first->second};
parseView(node, view);
}
else {
if (std::find(sSupportedViews.cbegin(), sSupportedViews.cend(), viewKey) !=
sSupportedViews.cend()) {
ThemeView& view {
mViews.insert(std::pair<std::string, ThemeView>(viewKey, ThemeView()))
.first->second};
parseView(node, view);
}
else {
throw error << ": Unsupported \"" << viewKey << "\" view style defined";
}
throw error << ": Unsupported \"" << viewKey << "\" view style defined";
}
}
}
@ -1913,75 +1697,29 @@ void ThemeData::parseView(const pugi::xml_node& root, ThemeView& view)
off = nameAttr.find_first_of(delim, prevOff);
// Add the element type as a prefix to avoid name collisions between different
// component types. Also include workarounds for legacy theme sets for when the
// fixed labels have been defined with the wrong element type.
const std::string elementType {node.name()};
LegacyWorkaround legacyWorkaround {LegacyWorkaround::NONE};
if (mLegacyTheme && elementType == "text" &&
(elemKey == "md_releasedate" || elemKey == "md_lastplayed")) {
LOG(LogDebug) << "ThemeData::parseView(): Element type for \"" << elemKey
<< "\" incorrectly set to \"text\" "
"instead of \"datetime\", applying workaround";
legacyWorkaround = LegacyWorkaround::DATETIME;
elemKey = "datetime_" + elemKey;
}
else if (mLegacyTheme && elementType == "datetime" &&
(elemKey == "md_lbl_releasedate" || elemKey == "md_lbl_lastplayed")) {
LOG(LogDebug) << "ThemeData::parseView(): Element type for \"" << elemKey
<< "\" incorrectly set to \"datetime\" "
"instead of \"text\", applying workaround";
legacyWorkaround = LegacyWorkaround::TEXT;
elemKey = "text_" + elemKey;
}
else if (mLegacyTheme && elementType == "text" && elemKey == "md_rating") {
LOG(LogDebug) << "ThemeData::parseView(): Element type for \"" << elemKey
<< "\" incorrectly set to \"text\" "
"instead of \"rating\", applying workaround";
legacyWorkaround = LegacyWorkaround::RATING;
elemKey = "rating_" + elemKey;
}
else {
elemKey = elementType + "_" + elemKey;
}
// component types.
elemKey = std::string {node.name()} + "_" + elemKey;
parseElement(
node, elemTypeIt->second,
view.elements.insert(std::pair<std::string, ThemeElement>(elemKey, ThemeElement()))
.first->second,
legacyWorkaround);
if (mLegacyTheme &&
std::find(view.legacyOrderedKeys.cbegin(), view.legacyOrderedKeys.cend(),
elemKey) == view.legacyOrderedKeys.cend())
view.legacyOrderedKeys.push_back(elemKey);
.first->second);
}
}
}
void ThemeData::parseElement(const pugi::xml_node& root,
const std::map<std::string, ElementPropertyType>& typeMap,
ThemeElement& element,
const LegacyWorkaround legacyWorkaround)
ThemeElement& element)
{
ThemeException error;
error << "ThemeData::parseElement(): ";
error.setFiles(mPaths);
element.type = root.name();
if (legacyWorkaround == LegacyWorkaround::DATETIME)
element.type = "datetime";
else if (legacyWorkaround == LegacyWorkaround::TEXT)
element.type = "text";
else if (legacyWorkaround == LegacyWorkaround::RATING)
element.type = "rating";
else
element.type = root.name();
element.extra = root.attribute("extra").as_bool(false);
if (mLegacyTheme)
element.extra = root.attribute("extra").as_bool(false);
else if (!mLegacyTheme && std::string(root.attribute("extra").as_string("")) != "")
throw error << ": Legacy \"extra\" attribute found for non-legacy theme set";
if (root.attribute("extra") != nullptr)
throw error << ": Legacy \"extra\" attribute found for element of type \"" << element.type
<< "\"";
for (pugi::xml_node node {root.first_child()}; node; node = node.next_sibling()) {
auto typeIt = typeMap.find(node.name());
@ -1996,27 +1734,15 @@ void ThemeData::parseElement(const pugi::xml_node& root,
// exist at the same time. A backspace is assigned in SystemData to flag the
// variables that do not apply and if it's encountered here we simply skip the
// property.
if (!mLegacyTheme && str == "\b")
if (str == "\b")
continue;
// Skip this check for legacy themes to not break backward compatibility with some
// themes sets that include empty property values.
if (!mLegacyTheme && str == "")
// Strictly enforce that there are no blank values in the theme configuration.
if (str == "")
throw error << ": Property \"" << typeIt->first << "\" for element \"" << element.type
<< "\" has no value defined";
std::string nodeName = node.name();
// Strictly enforce removal of legacy properties for non-legacy theme sets by creating
// an unthemed system if they're present in the configuration.
if (!mLegacyTheme) {
for (auto& legacyProperty : sLegacyProperties) {
if (nodeName == legacyProperty) {
throw error << ": Legacy <" << nodeName
<< "> property found for non-legacy theme set";
}
}
}
std::string nodeName {node.name()};
// If an attribute exists, then replace nodeName with its name.
auto attributeEntry = sPropertyAttributeMap.find(element.type);

View file

@ -24,18 +24,6 @@
#include <sstream>
#include <vector>
namespace pugi
{
class xml_node;
}
class GuiComponent;
class ImageComponent;
class NinePatchComponent;
class Sound;
class TextComponent;
class Window;
namespace ThemeFlags
{
// clang-format off
@ -53,15 +41,14 @@ namespace ThemeFlags
TEXT = 0x00000100,
METADATA = 0x00000200,
LETTER_CASE = 0x00000400,
FORCE_UPPERCASE = 0x00000800, // For backward compatibility with legacy themes.
LINE_SPACING = 0x00001000,
DELAY = 0x00002000,
Z_INDEX = 0x00004000,
ROTATION = 0x00008000,
BRIGHTNESS = 0x00010000,
OPACITY = 0x00020000,
SATURATION = 0x00040000,
VISIBLE = 0x00080000,
LINE_SPACING = 0x00000800,
DELAY = 0x00001000,
Z_INDEX = 0x00002000,
ROTATION = 0x00004000,
BRIGHTNESS = 0x00008000,
OPACITY = 0x00010000,
SATURATION = 0x00020000,
VISIBLE = 0x00040000,
ALL = 0xFFFFFFFF
};
// clang-format on
@ -107,7 +94,6 @@ public:
class ThemeElement
{
public:
bool extra;
std::string type;
struct Property {
@ -162,7 +148,6 @@ public:
{
public:
std::map<std::string, ThemeElement> elements;
std::vector<std::string> legacyOrderedKeys;
};
struct ThemeVariant {
@ -202,7 +187,7 @@ public:
std::vector<std::string> aspectRatios;
std::vector<ThemeTransitions> transitions;
std::vector<std::string> suppressedTransitionProfiles;
bool legacyTheme;
bool validTheme;
};
struct ThemeSet {
@ -230,9 +215,6 @@ public:
bool hasView(const std::string& view);
ThemeView& getViewElements(std::string view) { return mViews[view]; }
static std::vector<GuiComponent*> makeExtras(const std::shared_ptr<ThemeData>& theme,
const std::string& view);
const ThemeElement* getElement(const std::string& view,
const std::string& element,
const std::string& expectedType) const;
@ -247,7 +229,6 @@ public:
const static std::string getCurrentThemeSetName() { return sCurrentThemeSet->first; }
static void setThemeTransitions();
const bool isLegacyTheme() { return mLegacyTheme; }
const std::map<ThemeTriggers::TriggerType, std::pair<std::string, std::vector<std::string>>>
getCurrentThemeSetSelectedVariantOverrides();
const static void themeLoadedLogOutput();
@ -266,20 +247,12 @@ public:
std::map<std::string, std::string> mVariables;
private:
enum class LegacyWorkaround {
NONE = 0x00000000,
TEXT = 0x00000001,
DATETIME = 0x00000002,
RATING = 0x00000004
};
unsigned int getHexColor(const std::string& str);
std::string resolvePlaceholders(const std::string& in);
static ThemeCapability parseThemeCapabilities(const std::string& path);
void parseIncludes(const pugi::xml_node& root);
void parseFeatures(const pugi::xml_node& root);
void parseVariants(const pugi::xml_node& root);
void parseColorSchemes(const pugi::xml_node& root);
void parseAspectRatios(const pugi::xml_node& root);
@ -289,16 +262,12 @@ private:
void parseView(const pugi::xml_node& root, ThemeView& view);
void parseElement(const pugi::xml_node& root,
const std::map<std::string, ElementPropertyType>& typeMap,
ThemeElement& element,
const LegacyWorkaround legacyWorkaround);
ThemeElement& element);
static std::vector<std::string> sSupportedViews;
static std::vector<std::string> sSupportedMediaTypes;
static std::vector<std::string> sSupportedTransitions;
static std::vector<std::string> sSupportedTransitionAnimations;
static std::vector<std::string> sLegacySupportedViews;
static std::vector<std::string> sLegacySupportedFeatures;
static std::vector<std::string> sLegacyProperties;
static std::vector<std::pair<std::string, std::string>> sSupportedAspectRatios;
static std::map<std::string, float> sAspectRatioMap;
@ -318,7 +287,6 @@ private:
std::string mSelectedColorScheme;
static inline std::string sSelectedAspectRatio;
static inline bool sAspectRatioMatch {false};
bool mLegacyTheme;
bool mCustomCollection;
};

View file

@ -228,18 +228,6 @@ void BadgeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
mFlexboxComponent.setAlignment(horizontalAlignment);
}
}
// Legacy themes only.
else if (elem->has("alignment")) {
const std::string alignment {elem->get<std::string>("alignment")};
if (alignment != "left" && alignment != "right") {
LOG(LogWarning) << "BadgeComponent: Invalid theme configuration, property \"alignment\""
" for element \""
<< element.substr(7) << "\" defined as \"" << alignment << "\"";
}
else {
mFlexboxComponent.setAlignment(alignment);
}
}
if (elem->has("direction")) {
const std::string direction {elem->get<std::string>("direction")};

View file

@ -165,21 +165,6 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
<< verticalAlignment << "\"";
}
// Legacy themes only.
if (properties & ALIGNMENT && elem->has("alignment")) {
const std::string& alignment {elem->get<std::string>("alignment")};
if (alignment == "left")
setHorizontalAlignment(ALIGN_LEFT);
else if (alignment == "center")
setHorizontalAlignment(ALIGN_CENTER);
else if (alignment == "right")
setHorizontalAlignment(ALIGN_RIGHT);
else
LOG(LogWarning) << "DateTimeComponent: Invalid theme configuration, property "
"<alignment> defined as \""
<< alignment << "\"";
}
if (properties & METADATA && elem->has("metadata")) {
mThemeMetadata = "";
const std::string& metadata {elem->get<std::string>("metadata")};
@ -226,18 +211,14 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
float maxHeight {0.0f};
if (!theme->isLegacyTheme() && elem->has("size")) {
if (elem->has("size")) {
const glm::vec2 size {elem->get<glm::vec2>("size")};
if (size.x != 0.0f && size.y != 0.0f)
maxHeight = mSize.y * 2.0f;
}
// Legacy themes only.
if (properties & FORCE_UPPERCASE && elem->has("forceUppercase"))
setUppercase(elem->get<bool>("forceUppercase"));
if (properties & LINE_SPACING && elem->has("lineSpacing"))
setLineSpacing(glm::clamp(elem->get<float>("lineSpacing"), 0.5f, 3.0f));
setFont(Font::getFromTheme(elem, properties, mFont, maxHeight, false, theme->isLegacyTheme()));
setFont(Font::getFromTheme(elem, properties, mFont, maxHeight, false));
}

View file

@ -306,13 +306,7 @@ void HelpComponent::updateGrid()
mGrid->setEntry(labels.at(i), glm::ivec2 {col + 2, 0}, false, false);
}
// There is a bug for legacy themes where the entrySpacing width is added to the right of
// the grid when aligning to the right using an X origin value of 1. This issue is retained
// for legacy themes for backward compatibility reasons.
if (mStyle.legacyTheme) {
mGrid->setPosition({mStyle.position.x, mStyle.position.y, 0.0f});
}
else if (isDimmed) {
if (isDimmed) {
mGrid->setPosition(
{mStyle.positionDimmed.x + ((mStyle.entrySpacingDimmed * mRenderer->getScreenWidth()) *
mStyle.originDimmed.x),

View file

@ -32,7 +32,6 @@ TextComponent::TextComponent()
, mNoTopMargin {false}
, mSelectable {false}
, mVerticalAutoSizing {false}
, mLegacyTheme {false}
{
}
@ -63,7 +62,6 @@ TextComponent::TextComponent(const std::string& text,
, mNoTopMargin {false}
, mSelectable {false}
, mVerticalAutoSizing {false}
, mLegacyTheme {false}
{
setFont(font);
setColor(color);
@ -298,9 +296,6 @@ void TextComponent::onTextChanged()
// Used to initialize all glyphs, which is needed to populate mMaxGlyphHeight.
lineHeight = mFont->loadGlyphs(text + "\n") * mLineSpacing;
if (mLegacyTheme)
font->useLegacyMaxGlyphHeight();
const bool isMultiline {mAutoCalcExtent.y == 1 || mSize.y > lineHeight};
if (isMultiline && !isScrollable) {
@ -367,8 +362,6 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
using namespace ThemeFlags;
GuiComponent::applyTheme(theme, view, element, properties);
mLegacyTheme = theme->isLegacyTheme();
std::string elementType {"text"};
std::string componentName {"TextComponent"};
@ -424,22 +417,6 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
<< element.substr(5) << "\" defined as \"" << verticalAlignment << "\"";
}
// Legacy themes only.
if (properties & ALIGNMENT && elem->has("alignment")) {
const std::string& alignment {elem->get<std::string>("alignment")};
if (alignment == "left")
setHorizontalAlignment(ALIGN_LEFT);
else if (alignment == "center")
setHorizontalAlignment(ALIGN_CENTER);
else if (alignment == "right")
setHorizontalAlignment(ALIGN_RIGHT);
else
LOG(LogWarning) << componentName
<< ": Invalid theme configuration, property "
"\"alignment\" for element \""
<< element.substr(5) << "\" defined as \"" << alignment << "\"";
}
if (properties & TEXT && elem->has("text"))
setText(elem->get<std::string>("text"));
@ -540,18 +517,14 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
float maxHeight {0.0f};
if (!theme->isLegacyTheme() && elem->has("size")) {
if (elem->has("size")) {
const glm::vec2 size {elem->get<glm::vec2>("size")};
if (size.x != 0.0f && size.y != 0.0f)
maxHeight = mSize.y * 2.0f;
}
// Legacy themes only.
if (properties & FORCE_UPPERCASE && elem->has("forceUppercase"))
setUppercase(elem->get<bool>("forceUppercase"));
if (properties & LINE_SPACING && elem->has("lineSpacing"))
setLineSpacing(glm::clamp(elem->get<float>("lineSpacing"), 0.5f, 3.0f));
setFont(Font::getFromTheme(elem, properties, mFont, maxHeight, false, theme->isLegacyTheme()));
setFont(Font::getFromTheme(elem, properties, mFont, maxHeight, false));
}

View file

@ -131,7 +131,6 @@ private:
bool mNoTopMargin;
bool mSelectable;
bool mVerticalAutoSizing;
bool mLegacyTheme;
};
#endif // ES_CORE_COMPONENTS_TEXT_COMPONENT_H

View file

@ -42,7 +42,6 @@ VideoComponent::VideoComponent()
, mPlayAudio {true}
, mDrawPillarboxes {true}
, mRenderScanlines {false}
, mLegacyTheme {false}
, mHasVideo {false}
, mGeneralFade {false}
, mFadeIn {1.0f}
@ -125,8 +124,6 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
const ThemeData::ThemeElement* elem {theme->getElement(view, element, "video")};
mLegacyTheme = theme->isLegacyTheme();
if (!elem)
return;
@ -226,15 +223,10 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
mConfig.startDelay =
static_cast<unsigned int>(glm::clamp(elem->get<float>("delay"), 0.0f, 15.0f) * 1000.0f);
if (!theme->isLegacyTheme())
mConfig.showSnapshotNoVideo = true;
else if (elem->has("showSnapshotNoVideo"))
mConfig.showSnapshotNoVideo = elem->get<bool>("showSnapshotNoVideo");
mConfig.showSnapshotNoVideo = true;
if (!theme->isLegacyTheme() && mConfig.startDelay != 0)
if (mConfig.startDelay != 0)
mConfig.showSnapshotDelay = true;
else if (elem->has("showSnapshotDelay"))
mConfig.showSnapshotDelay = elem->get<bool>("showSnapshotDelay");
if (properties && elem->has("fadeInTime"))
mFadeInTime = glm::clamp(elem->get<float>("fadeInTime"), 0.0f, 8.0f) * 1000.0f;
@ -277,7 +269,7 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
}
}
if (!mLegacyTheme && mThemeImageTypes.empty())
if (mThemeImageTypes.empty())
mConfig.startDelay = 0;
if (elem->has("color")) {
@ -404,9 +396,6 @@ void VideoComponent::startVideoPlayer()
void VideoComponent::renderSnapshot(const glm::mat4& parentTrans)
{
if (mLegacyTheme && !mHasVideo && !mConfig.showSnapshotNoVideo)
return;
if (mHasVideo && (!mConfig.showSnapshotDelay || mConfig.startDelay == 0))
return;

View file

@ -56,13 +56,7 @@ public:
bool hasStaticVideo() { return !mConfig.staticVideoPath.empty(); }
bool hasStaticImage() { return mStaticImage.getTextureSize() != glm::ivec2 {0, 0}; }
bool hasStartDelay()
{
if (mLegacyTheme)
return mConfig.showSnapshotDelay && mConfig.startDelay > 0;
else
return mConfig.startDelay > 0;
}
bool hasStartDelay() { return mConfig.startDelay > 0; }
// These functions update the embedded static image.
void onOriginChanged() override { mStaticImage.setOrigin(mOrigin); }
@ -134,7 +128,6 @@ protected:
bool mPlayAudio;
bool mDrawPillarboxes;
bool mRenderScanlines;
bool mLegacyTheme;
bool mHasVideo;
bool mGeneralFade;
float mFadeIn;

View file

@ -256,10 +256,8 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
// in those modules as a post-processing step.
if (!mScreensaverMode && !mMediaViewerMode) {
vertices[0].opacity = mFadeIn * mOpacity * mThemeOpacity;
if ((mLegacyTheme && Settings::getInstance()->getBool("GamelistVideoScanlines")) ||
(!mLegacyTheme && mRenderScanlines)) {
if (mRenderScanlines)
vertices[0].shaders = Renderer::Shader::SCANLINES;
}
}
mRenderer->drawTriangleStrips(&vertices[0], 4, Renderer::BlendFactor::SRC_ALPHA,
@ -995,8 +993,7 @@ void VideoFFmpegComponent::calculateBlackRectangle()
mVideoRectangleCoords.clear();
mRectangleOffset = {0.0f, 0.0f};
if ((mLegacyTheme && Settings::getInstance()->getBool("GamelistVideoPillarbox")) ||
(!mLegacyTheme && mDrawPillarboxes)) {
if (mDrawPillarboxes) {
float rectHeight {0.0f};
float rectWidth {0.0f};
// Video is in landscape orientation.

File diff suppressed because it is too large Load diff

View file

@ -131,7 +131,6 @@ private:
int mLoopTime;
bool mLoopScroll;
bool mGamelistView;
bool mLegacyMode;
std::shared_ptr<Font> mFont;
float mSelectorHeight;
@ -172,7 +171,6 @@ TextListComponent<T>::TextListComponent()
, mLoopTime {0}
, mLoopScroll {false}
, mGamelistView {std::is_same_v<T, FileData*> ? true : false}
, mLegacyMode {false}
, mFont {Font::get(FONT_SIZE_MEDIUM_FIXED)}
, mSelectorHeight {mFont->getSize() * 1.5f}
, mSelectorHorizontalOffset {0.0f}
@ -336,33 +334,11 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT
float entrySize {0.0f};
float lineSpacingHeight {0.0f};
// The vertical spacing between rows for legacy themes is very inaccurate and will look
// different depending on the resolution, but it's done for maximum backward compatibility.
if (mLegacyMode) {
font->useLegacyMaxGlyphHeight();
entrySize = std::max(font->getHeight(mLineSpacing), font->getSize() * mLineSpacing);
lineSpacingHeight = std::floor(font->getSize() * mLineSpacing - font->getSize());
}
else {
entrySize = font->getSize() * mLineSpacing;
lineSpacingHeight = font->getSize() * mLineSpacing - font->getSize() * 1.0f;
}
entrySize = font->getSize() * mLineSpacing;
lineSpacingHeight = font->getSize() * mLineSpacing - font->getSize() * 1.0f;
if (mLegacyMode) {
// This extra vertical margin is technically incorrect, but it adds a little extra leeway
// to avoid removing the last row on some older theme sets. There was a sizing bug in the
// RetroPie fork of EmulationStation and some theme authors set sizes that are just slightly
// too small for the last row to show up when the sizing calculation is done correctly.
const float extraMargin {(Renderer::getScreenHeightModifier() >= 1.0f ? 3.0f : 0.0f)};
// Number of entries that can fit on the screen simultaneously.
screenCount = static_cast<int>(
floorf((mSize.y + lineSpacingHeight / 2.0f + extraMargin) / entrySize));
}
else {
// Number of entries that can fit on the screen simultaneously.
screenCount =
static_cast<int>(std::floor((mSize.y + lineSpacingHeight / 2.0f) / entrySize));
}
// Number of entries that can fit on the screen simultaneously.
screenCount = static_cast<int>(std::floor((mSize.y + lineSpacingHeight / 2.0f) / entrySize));
if (size() >= screenCount) {
startEntry = mCursor - screenCount / 2;
@ -532,8 +508,6 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
if (!elem)
return;
mLegacyMode = theme->isLegacyTheme();
if (properties & COLOR) {
if (elem->has("selectorColor")) {
mSelectorColor = elem->get<unsigned int>("selectorColor");
@ -577,9 +551,7 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
mSelectedSecondaryBackgroundColor = mSelectedBackgroundColor;
}
setFont(Font::getFromTheme(elem, properties, mFont, 0.0f, false, mLegacyMode));
if (mLegacyMode)
mFont->useLegacyMaxGlyphHeight();
setFont(Font::getFromTheme(elem, properties, mFont, 0.0f, false));
const float selectorHeight {mFont->getHeight(mLineSpacing)};
mSelectorHeight = selectorHeight;
@ -602,24 +574,6 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
<< "\"";
}
}
else if (elem->has("alignment")) {
// Legacy themes only.
const std::string& alignment {elem->get<std::string>("alignment")};
if (alignment == "left") {
setAlignment(PrimaryAlignment::ALIGN_LEFT);
}
else if (alignment == "center") {
setAlignment(PrimaryAlignment::ALIGN_CENTER);
}
else if (alignment == "right") {
setAlignment(PrimaryAlignment::ALIGN_RIGHT);
}
else {
LOG(LogWarning) << "TextListComponent: Invalid theme configuration, property "
"\"alignment\" for element \""
<< element.substr(9) << "\" defined as \"" << alignment << "\"";
}
}
if (elem->has("horizontalMargin")) {
mHorizontalMargin =
elem->get<float>("horizontalMargin") *
@ -687,12 +641,6 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
}
}
// Legacy themes only.
if (properties & FORCE_UPPERCASE && elem->has("forceUppercase")) {
if (elem->get<bool>("forceUppercase"))
mLetterCase = LetterCase::UPPERCASE;
}
mSelectorHorizontalOffset = 0.0f;
mSelectorVerticalOffset = 0.0f;

View file

@ -13,6 +13,7 @@
#include "GuiComponent.h"
#include "components/ButtonComponent.h"
#include "components/ComponentGrid.h"
#include "components/TextComponent.h"
#include "components/TextEditComponent.h"
class GuiTextEditKeyboardPopup : public GuiComponent

View file

@ -13,6 +13,7 @@
#include "GuiComponent.h"
#include "components/ButtonComponent.h"
#include "components/ComponentGrid.h"
#include "components/TextComponent.h"
#include "components/TextEditComponent.h"
class GuiTextEditPopup : public GuiComponent

View file

@ -22,7 +22,6 @@ Font::Font(float size, const std::string& path, const bool linearMagnify)
, mLinearMagnify {linearMagnify}
, mLetterHeight {0.0f}
, mMaxGlyphHeight {static_cast<int>(std::round(size))}
, mLegacyMaxGlyphHeight {0}
{
if (mFontSize < 3.0f) {
mFontSize = 3.0f;
@ -430,12 +429,9 @@ std::shared_ptr<Font> Font::getFromTheme(const ThemeData::ThemeElement* elem,
const std::shared_ptr<Font>& orig,
const float maxHeight,
const bool linearMagnify,
const bool legacyTheme,
const float sizeMultiplier,
const bool fontSizeDimmed)
{
mLegacyTheme = legacyTheme;
using namespace ThemeFlags;
if (!(properties & FONT_PATH) && !(properties & FONT_SIZE))
return orig;
@ -472,10 +468,7 @@ std::shared_ptr<Font> Font::getFromTheme(const ThemeData::ThemeElement* elem,
path = getDefaultPath();
}
if (mLegacyTheme)
return get(std::floor(size), path, false);
else
return get(size, path, linearMagnify);
return get(size, path, linearMagnify);
}
size_t Font::getMemUsage() const
@ -784,9 +777,6 @@ Font::Glyph* Font::getGlyph(const unsigned int id)
mRenderer->updateTexture(tex->textureId, Renderer::TextureType::RED, cursor.x, cursor.y,
glyphSize.x, glyphSize.y, glyphSlot->bitmap.buffer);
if (glyphSize.y > mLegacyMaxGlyphHeight)
mLegacyMaxGlyphHeight = glyphSize.y;
return &glyph;
}

View file

@ -89,9 +89,6 @@ public:
// guaranteed and can be exceeded by a few pixels for some glyphs.
int loadGlyphs(const std::string& text);
// This is needed to maintain maximum compatibility with legacy theme sets.
void useLegacyMaxGlyphHeight() { mMaxGlyphHeight = mLegacyMaxGlyphHeight; }
TextCache* buildTextCache(const std::string& text,
float offsetX,
float offsetY,
@ -137,7 +134,6 @@ public:
const std::shared_ptr<Font>& orig,
const float maxHeight = 0.0f,
const bool linearMagnify = false,
const bool legacyTheme = false,
const float sizeMultiplier = 1.0f,
const bool fontSizeDimmed = false);
@ -208,7 +204,6 @@ private:
static inline FT_Library sLibrary {nullptr};
static inline std::map<std::tuple<float, std::string, bool>, std::weak_ptr<Font>> sFontMap;
static inline bool mLegacyTheme {false};
Renderer* mRenderer;
std::vector<std::unique_ptr<FontTexture>> mTextures;
@ -220,7 +215,6 @@ private:
const bool mLinearMagnify;
float mLetterHeight;
int mMaxGlyphHeight;
int mLegacyMaxGlyphHeight;
};
// Used to store a sort of "pre-rendered" string.