mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-28 17:15:38 +00:00
Large update to get the new theme engine up and running.
This commit is contained in:
parent
0ca2b62edf
commit
c35a297d9a
|
@ -642,6 +642,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
AudioManager::getInstance();
|
||||
MameNames::getInstance();
|
||||
ThemeData::getThemeSets();
|
||||
loadSystemsReturnCode loadSystemsStatus = loadSystemConfigFile();
|
||||
|
||||
if (loadSystemsStatus) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "Window.h"
|
||||
#include "components/BadgeComponent.h"
|
||||
#include "components/DateTimeComponent.h"
|
||||
#include "components/LottieComponent.h"
|
||||
#include "components/RatingComponent.h"
|
||||
#include "components/ScrollableContainer.h"
|
||||
#include "components/TextComponent.h"
|
||||
|
|
|
@ -45,7 +45,7 @@ void GamelistView::legacyPopulateFields()
|
|||
|
||||
// Thumbnails.
|
||||
mImageComponents.push_back(std::make_unique<ImageComponent>());
|
||||
mImageComponents.back()->setMetadataField("md_thumbnail");
|
||||
mImageComponents.back()->setMetadataField("image_md_thumbnail");
|
||||
mImageComponents.back()->setOrigin(0.5f, 0.5f);
|
||||
mImageComponents.back()->setVisible(false);
|
||||
mImageComponents.back()->setMaxSize(mSize.x * (0.25f - 2.0f * padding), mSize.y * 0.10f);
|
||||
|
@ -54,7 +54,7 @@ void GamelistView::legacyPopulateFields()
|
|||
|
||||
// Marquee.
|
||||
mImageComponents.push_back(std::make_unique<ImageComponent>());
|
||||
mImageComponents.back()->setMetadataField("md_marquee");
|
||||
mImageComponents.back()->setMetadataField("image_md_marquee");
|
||||
mImageComponents.back()->setOrigin(0.5f, 0.5f);
|
||||
mImageComponents.back()->setVisible(false);
|
||||
mImageComponents.back()->setMaxSize(mSize.x * (0.5f - 2.0f * padding), mSize.y * 0.18f);
|
||||
|
@ -63,7 +63,7 @@ void GamelistView::legacyPopulateFields()
|
|||
|
||||
// Image.
|
||||
mImageComponents.push_back(std::make_unique<ImageComponent>());
|
||||
mImageComponents.back()->setMetadataField("md_image");
|
||||
mImageComponents.back()->setMetadataField("image_md_image");
|
||||
mImageComponents.back()->setOrigin(0.5f, 0.5f);
|
||||
mImageComponents.back()->setPosition(mSize.x * 0.25f,
|
||||
mList.getPosition().y + mSize.y * 0.2125f);
|
||||
|
@ -74,9 +74,10 @@ void GamelistView::legacyPopulateFields()
|
|||
if (mViewStyle == ViewController::VIDEO) {
|
||||
// Video.
|
||||
mVideoComponents.push_back(std::make_unique<VideoFFmpegComponent>());
|
||||
mVideoComponents.back()->setMetadataField("md_video");
|
||||
mVideoComponents.back()->setMetadataField("video_md_video");
|
||||
mVideoComponents.back()->setOrigin(0.5f, 0.5f);
|
||||
mVideoComponents.back()->setPosition(mSize.x * 0.25f, mSize.y * 0.4f);
|
||||
mVideoComponents.back()->setPosition(mSize.x * 0.25f,
|
||||
mList.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);
|
||||
addChild(mVideoComponents.back().get());
|
||||
|
@ -85,84 +86,85 @@ void GamelistView::legacyPopulateFields()
|
|||
mList.setPosition(mSize.x * (0.50f + padding), mList.getPosition().y);
|
||||
mList.setSize(mSize.x * (0.50f - padding), mList.getSize().y);
|
||||
mList.setAlignment(TextListComponent<FileData*>::ALIGN_LEFT);
|
||||
mList.setCursorChangedCallback([&](const CursorState& /*state*/) { legacyUpdateInfoPanel(); });
|
||||
mList.setCursorChangedCallback([&](const CursorState& /*state*/) { updateInfoPanel(); });
|
||||
|
||||
// Metadata labels + values.
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setText("Rating: ", false);
|
||||
mTextComponents.back()->setMetadataField("md_lbl_rating");
|
||||
mTextComponents.back()->setMetadataField("text_md_lbl_rating");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setText("Released: ", false);
|
||||
mTextComponents.back()->setMetadataField("md_lbl_releasedate");
|
||||
mTextComponents.back()->setMetadataField("text_md_lbl_releasedate");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setText("Developer: ", false);
|
||||
mTextComponents.back()->setMetadataField("md_lbl_developer");
|
||||
mTextComponents.back()->setMetadataField("text_md_lbl_developer");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setText("Publisher: ", false);
|
||||
mTextComponents.back()->setMetadataField("md_lbl_publisher");
|
||||
mTextComponents.back()->setMetadataField("text_md_lbl_publisher");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setText("Genre: ", false);
|
||||
mTextComponents.back()->setMetadataField("md_lbl_genre");
|
||||
mTextComponents.back()->setMetadataField("text_md_lbl_genre");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setText("Players: ", false);
|
||||
mTextComponents.back()->setMetadataField("md_lbl_players");
|
||||
mTextComponents.back()->setMetadataField("text_md_lbl_players");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setText("Last played: ", false);
|
||||
mTextComponents.back()->setMetadataField("md_lbl_lastplayed");
|
||||
mTextComponents.back()->setMetadataField("text_md_lbl_lastplayed");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setText("Times played: ", false);
|
||||
mTextComponents.back()->setMetadataField("md_lbl_playcount");
|
||||
mTextComponents.back()->setMetadataField("text_md_lbl_playcount");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mRatingComponents.push_back(std::make_unique<RatingComponent>());
|
||||
mRatingComponents.back()->setMetadataField("md_rating");
|
||||
mRatingComponents.back()->setMetadataField("rating_md_rating");
|
||||
mRatingComponents.back()->setDefaultZIndex(40.0f);
|
||||
addChild(mRatingComponents.back().get());
|
||||
|
||||
mDateTimeComponents.push_back(std::make_unique<DateTimeComponent>());
|
||||
mDateTimeComponents.back()->setMetadataField("md_releasedate");
|
||||
mDateTimeComponents.back()->setMetadataField("datetime_md_releasedate");
|
||||
addChild(mDateTimeComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setMetadataField("md_developer");
|
||||
mTextComponents.back()->setMetadataField("text_md_developer");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setMetadataField("md_publisher");
|
||||
mTextComponents.back()->setMetadataField("text_md_publisher");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setMetadataField("md_genre");
|
||||
mTextComponents.back()->setMetadataField("text_md_genre");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setMetadataField("md_players");
|
||||
mTextComponents.back()->setMetadataField("text_md_players");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mDateTimeComponents.push_back(std::make_unique<DateTimeComponent>());
|
||||
mDateTimeComponents.back()->setMetadataField("md_lastplayed");
|
||||
mDateTimeComponents.back()->setMetadataField("datetime_md_lastplayed");
|
||||
mDateTimeComponents.back()->setDisplayRelative(true);
|
||||
addChild(mDateTimeComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setMetadataField("md_playcount");
|
||||
mTextComponents.back()->setMetadataField("text_md_playcount");
|
||||
addChild(mTextComponents.back().get());
|
||||
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setMetadataField("md_name");
|
||||
mTextComponents.back()->setMetadataField("text_md_name");
|
||||
mTextComponents.back()->setPosition(mSize.x, mSize.y);
|
||||
mTextComponents.back()->setFont(Font::get(FONT_SIZE_MEDIUM));
|
||||
mTextComponents.back()->setHorizontalAlignment(ALIGN_CENTER);
|
||||
|
@ -172,7 +174,7 @@ void GamelistView::legacyPopulateFields()
|
|||
|
||||
// Badges.
|
||||
mBadgeComponents.push_back(std::make_unique<BadgeComponent>());
|
||||
mBadgeComponents.back()->setMetadataField("md_badges");
|
||||
mBadgeComponents.back()->setMetadataField("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);
|
||||
|
@ -180,22 +182,21 @@ void GamelistView::legacyPopulateFields()
|
|||
addChild(mBadgeComponents.back().get());
|
||||
|
||||
// Scrollable container (game description).
|
||||
mScrollableContainerComponents.push_back(std::make_unique<ScrollableContainer>());
|
||||
mScrollableContainerComponents.back()->setMetadataField("md_description");
|
||||
mScrollableContainerComponents.back()->setSize(
|
||||
mSize.x * (0.50f - 2.0f * padding),
|
||||
mSize.y - mScrollableContainerComponents.back()->getPosition().y);
|
||||
mScrollableContainerComponents.back()->setAutoScroll(true);
|
||||
mScrollableContainerComponents.back()->setDefaultZIndex(40.0f);
|
||||
addChild(mScrollableContainerComponents.back().get());
|
||||
mContainerComponents.push_back(std::make_unique<ScrollableContainer>());
|
||||
mContainerComponents.back()->setMetadataField("text_md_description");
|
||||
mContainerComponents.back()->setSize(mSize.x * (0.50f - 2.0f * padding),
|
||||
mSize.y - mContainerComponents.back()->getPosition().y);
|
||||
mContainerComponents.back()->setAutoScroll(true);
|
||||
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(mScrollableContainerComponents.back()->getSize().x, 0.0f);
|
||||
mScrollableContainerComponents.back()->addChild(mTextComponents.back().get());
|
||||
mTextComponents.back()->setSize(mContainerComponents.back()->getSize().x, 0.0f);
|
||||
mContainerComponents.back()->addChild(mTextComponents.back().get());
|
||||
|
||||
mGamelistInfoComponents.push_back(std::make_unique<TextComponent>());
|
||||
mGamelistInfoComponents.back()->setMetadataField("gamelistInfo");
|
||||
mGamelistInfoComponents.back()->setMetadataField("text_gamelistInfo");
|
||||
mGamelistInfoComponents.back()->setOrigin(0.5f, 0.5f);
|
||||
mGamelistInfoComponents.back()->setFont(Font::get(FONT_SIZE_SMALL));
|
||||
mGamelistInfoComponents.back()->setDefaultZIndex(50.0f);
|
||||
|
@ -209,9 +210,9 @@ void GamelistView::legacyOnThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
|
||||
using namespace ThemeFlags;
|
||||
|
||||
mTextComponents[LOGOTEXT]->applyTheme(theme, getName(), "logoText", ALL);
|
||||
mImageComponents[LOGO]->applyTheme(theme, getName(), "logo", ALL);
|
||||
mImageComponents[BACKGROUND]->applyTheme(theme, getName(), "background", ALL);
|
||||
mTextComponents[LOGOTEXT]->applyTheme(theme, getName(), "text_logoText", ALL);
|
||||
mImageComponents[LOGO]->applyTheme(theme, getName(), "image_logo", ALL);
|
||||
mImageComponents[BACKGROUND]->applyTheme(theme, getName(), "image_background", ALL);
|
||||
|
||||
// Remove old theme extras.
|
||||
for (auto extra : mThemeExtras) {
|
||||
|
@ -225,12 +226,13 @@ void GamelistView::legacyOnThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
for (auto extra : mThemeExtras)
|
||||
addChild(extra);
|
||||
|
||||
mList.applyTheme(theme, getName(), "gamelist", ALL);
|
||||
mList.applyTheme(theme, getName(), "textlist_gamelist", ALL);
|
||||
|
||||
mImageComponents[LegacyImage::MD_THUMBNAIL]->applyTheme(
|
||||
theme, getName(), mImageComponents[LegacyImage::MD_THUMBNAIL]->getMetadataField(), ALL);
|
||||
mImageComponents[LegacyImage::MD_MARQUEE]->applyTheme(
|
||||
theme, getName(), "md_marquee", POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||
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(
|
||||
|
@ -276,15 +278,15 @@ void GamelistView::legacyOnThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
ALL);
|
||||
}
|
||||
|
||||
for (auto& container : mScrollableContainerComponents) {
|
||||
for (auto& container : mContainerComponents) {
|
||||
container->applyTheme(theme, getName(), container->getMetadataField(),
|
||||
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
||||
}
|
||||
|
||||
mTextComponents[LegacyText::MD_DESCRIPTION]->setSize(
|
||||
mScrollableContainerComponents.front()->getSize().x, 0.0f);
|
||||
mTextComponents[LegacyText::MD_DESCRIPTION]->setSize(mContainerComponents.front()->getSize().x,
|
||||
0.0f);
|
||||
mTextComponents[LegacyText::MD_DESCRIPTION]->applyTheme(
|
||||
theme, getName(), "md_description",
|
||||
theme, getName(), "text_md_description",
|
||||
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
||||
|
||||
for (auto& gamelistInfo : mGamelistInfoComponents)
|
||||
|
@ -299,10 +301,10 @@ void GamelistView::legacyOnThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
|
||||
// Hide some components if we're in Basic mode.
|
||||
if (mViewStyle == ViewController::BASIC) {
|
||||
if (mTheme->getElement(getName(), "logoText", "text") == nullptr)
|
||||
if (mTheme->getElement(getName(), "text_logoText", "text") == nullptr)
|
||||
mTextComponents[LegacyText::LOGOTEXT]->setVisible(false);
|
||||
mImageComponents[LegacyImage::MD_IMAGE]->setVisible(false);
|
||||
for (auto& container : mScrollableContainerComponents)
|
||||
for (auto& container : mContainerComponents)
|
||||
container->setVisible(false);
|
||||
}
|
||||
|
||||
|
@ -339,11 +341,12 @@ void GamelistView::legacyUpdateInfoPanel()
|
|||
|
||||
// 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 (mList.isScrolling())
|
||||
if (mList.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)
|
||||
|
@ -484,7 +487,7 @@ void GamelistView::legacyUpdateInfoPanel()
|
|||
}
|
||||
|
||||
mTextComponents[LegacyText::MD_DESCRIPTION]->setText(file->metadata.get("desc"));
|
||||
for (auto& container : mScrollableContainerComponents)
|
||||
for (auto& container : mContainerComponents)
|
||||
container->reset();
|
||||
|
||||
for (auto& rating : mRatingComponents)
|
||||
|
@ -540,66 +543,6 @@ void GamelistView::legacyUpdateInfoPanel()
|
|||
}
|
||||
}
|
||||
|
||||
for (auto& text : mTextComponents) {
|
||||
if (text->getValue() != "")
|
||||
continue;
|
||||
|
||||
std::string metadata = text->getMetadataField();
|
||||
if (metadata == "")
|
||||
continue;
|
||||
|
||||
if (metadata == "md_controller") {
|
||||
std::string controller =
|
||||
BadgeComponent::getDisplayName(file->metadata.get("controller"));
|
||||
text->setValue(controller == "unknown" ? "" : controller);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (metadata == "md_name")
|
||||
text->setValue(file->metadata.get("name"));
|
||||
else if (metadata == "md_rating")
|
||||
text->setValue(mRatingComponents.front()->getRatingValue());
|
||||
else if (metadata == "md_developer")
|
||||
text->setValue(file->metadata.get("developer"));
|
||||
else if (metadata == "md_publisher")
|
||||
text->setValue(file->metadata.get("publisher"));
|
||||
else if (metadata == "md_genre")
|
||||
text->setValue(file->metadata.get("genre"));
|
||||
else if (metadata == "md_players")
|
||||
text->setValue(file->metadata.get("players"));
|
||||
else if (metadata == "md_favorite")
|
||||
text->setValue(file->metadata.get("favorite") == "true" ? "yes" : "no");
|
||||
else if (metadata == "md_completed")
|
||||
text->setValue(file->metadata.get("completed") == "true" ? "yes" : "no");
|
||||
else if (metadata == "md_kidgame")
|
||||
text->setValue(file->metadata.get("kidgame") == "true" ? "yes" : "no");
|
||||
else if (metadata == "md_broken")
|
||||
text->setValue(file->metadata.get("broken") == "true" ? "yes" : "no");
|
||||
else if (metadata == "md_playcount")
|
||||
text->setValue(file->metadata.get("playcount"));
|
||||
else if (metadata == "md_altemulator")
|
||||
text->setValue(file->metadata.get("altemulator"));
|
||||
else
|
||||
text->setValue(metadata);
|
||||
}
|
||||
|
||||
for (auto& date : mDateTimeComponents) {
|
||||
std::string metadata = date->getMetadataField();
|
||||
if (metadata == "")
|
||||
continue;
|
||||
|
||||
if (metadata == "md_releasedate") {
|
||||
date->setValue(file->metadata.get("releasedate"));
|
||||
}
|
||||
else if (metadata == "md_lastplayed") {
|
||||
date->setValue(file->metadata.get("lastplayed"));
|
||||
date->setDisplayRelative(true);
|
||||
}
|
||||
else {
|
||||
date->setValue("19700101T000000");
|
||||
}
|
||||
}
|
||||
|
||||
fadingOut = false;
|
||||
}
|
||||
|
||||
|
@ -756,10 +699,10 @@ void GamelistView::legacyInitMDValues()
|
|||
mRatingComponents.front()->setPosition(Renderer::getScreenWidth() * 2.0f,
|
||||
Renderer::getScreenHeight() * 2.0f);
|
||||
|
||||
mScrollableContainerComponents.front()->setPosition(Renderer::getScreenWidth() * 2.0f,
|
||||
mContainerComponents.front()->setPosition(Renderer::getScreenWidth() * 2.0f,
|
||||
Renderer::getScreenHeight() * 2.0f);
|
||||
|
||||
for (auto& container : mScrollableContainerComponents) {
|
||||
for (auto& container : mContainerComponents) {
|
||||
container->setPosition(container->getPosition().x, bottom + mSize.y * 0.01f);
|
||||
container->setSize(container->getSize().x, mSize.y - container->getPosition().y);
|
||||
}
|
||||
|
|
|
@ -13,17 +13,14 @@
|
|||
#include "UIModeController.h"
|
||||
#include "animations/LambdaAnimation.h"
|
||||
|
||||
// #define FADE_IN_START_OPACITY 0.5f
|
||||
// #define FADE_IN_TIME 325
|
||||
#define FADE_IN_START_OPACITY 0.5f
|
||||
#define FADE_IN_TIME 325
|
||||
|
||||
GamelistView::GamelistView(FileData* root, bool legacyMode)
|
||||
GamelistView::GamelistView(FileData* root)
|
||||
: GamelistBase {root}
|
||||
, mLegacyMode {legacyMode}
|
||||
, mLegacyMode {false}
|
||||
, mViewStyle {ViewController::BASIC}
|
||||
{
|
||||
// TEMPORARY
|
||||
mLegacyMode = true;
|
||||
|
||||
mViewStyle = ViewController::getInstance()->getState().viewstyle;
|
||||
|
||||
if (mLegacyMode)
|
||||
|
@ -71,8 +68,14 @@ void GamelistView::onFileChanged(FileData* file, bool reloadGamelist)
|
|||
void GamelistView::onShow()
|
||||
{
|
||||
// Reset any Lottie animations.
|
||||
for (auto& animation : mLottieAnimComponents)
|
||||
animation->resetFileAnimation();
|
||||
|
||||
// Reset any Lottie animations.
|
||||
if (mLegacyMode) {
|
||||
for (auto extra : mThemeExtras)
|
||||
extra->resetFileAnimation();
|
||||
}
|
||||
|
||||
mLastUpdated = nullptr;
|
||||
GuiComponent::onShow();
|
||||
|
@ -84,6 +87,8 @@ void GamelistView::onShow()
|
|||
|
||||
void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||
{
|
||||
mLegacyMode = mTheme->isLegacyTheme();
|
||||
|
||||
if (mLegacyMode) {
|
||||
legacyOnThemeChanged(theme);
|
||||
return;
|
||||
|
@ -91,21 +96,94 @@ void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
|
||||
using namespace ThemeFlags;
|
||||
|
||||
// Remove old theme extras.
|
||||
for (auto extra : mThemeExtras) {
|
||||
removeChild(extra);
|
||||
delete extra;
|
||||
if (mTheme->hasView("gamelist")) {
|
||||
for (auto& element : mTheme->getViewElements("gamelist").elements) {
|
||||
if (element.second.type == "image") {
|
||||
mImageComponents.push_back(std::make_unique<ImageComponent>());
|
||||
mImageComponents.back()->setDefaultZIndex(30.0f);
|
||||
mImageComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
if (mImageComponents.back()->getMetadataField() != "")
|
||||
mImageComponents.back()->setScrollHide(true);
|
||||
addChild(mImageComponents.back().get());
|
||||
}
|
||||
else if (element.second.type == "video") {
|
||||
mVideoComponents.push_back(std::make_unique<VideoFFmpegComponent>());
|
||||
mVideoComponents.back()->setDefaultZIndex(30.0f);
|
||||
addChild(mVideoComponents.back().get());
|
||||
mVideoComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
if (mVideoComponents.back()->getMetadataField() != "")
|
||||
mVideoComponents.back()->setScrollHide(true);
|
||||
}
|
||||
else if (element.second.type == "animation") {
|
||||
mLottieAnimComponents.push_back(std::make_unique<LottieComponent>());
|
||||
mLottieAnimComponents.back()->setDefaultZIndex(35.0f);
|
||||
mLottieAnimComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
addChild(mLottieAnimComponents.back().get());
|
||||
}
|
||||
else if (element.second.type == "badges") {
|
||||
mBadgeComponents.push_back(std::make_unique<BadgeComponent>());
|
||||
mBadgeComponents.back()->setDefaultZIndex(35.0f);
|
||||
mBadgeComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
mBadgeComponents.back()->setScrollHide(true);
|
||||
addChild(mBadgeComponents.back().get());
|
||||
}
|
||||
else if (element.second.type == "text") {
|
||||
if (element.second.has("container") && element.second.get<bool>("container")) {
|
||||
mContainerTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mContainerTextComponents.back()->setDefaultZIndex(40.0f);
|
||||
mContainerComponents.push_back(std::make_unique<ScrollableContainer>());
|
||||
mContainerComponents.back()->setAutoScroll(true);
|
||||
mContainerComponents.back()->addChild(mContainerTextComponents.back().get());
|
||||
mContainerComponents.back()->applyTheme(theme, "gamelist", element.first,
|
||||
POSITION | ThemeFlags::SIZE | Z_INDEX |
|
||||
VISIBLE);
|
||||
mContainerTextComponents.back()->applyTheme(theme, "gamelist", element.first,
|
||||
ALL ^ POSITION ^ Z_INDEX ^
|
||||
ThemeFlags::SIZE ^ VISIBLE);
|
||||
mContainerTextComponents.back()->setSize(
|
||||
mContainerComponents.back()->getSize().x, 0.0f);
|
||||
mContainerComponents.back()->setDefaultZIndex(
|
||||
mContainerTextComponents.back()->getDefaultZIndex());
|
||||
mContainerComponents.back()->setZIndex(
|
||||
mContainerTextComponents.back()->getZIndex());
|
||||
mContainerComponents.back()->setScrollHide(true);
|
||||
addChild(mContainerComponents.back().get());
|
||||
}
|
||||
else {
|
||||
mTextComponents.push_back(std::make_unique<TextComponent>());
|
||||
mTextComponents.back()->setDefaultZIndex(40.0f);
|
||||
mTextComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
if (mTextComponents.back()->getMetadataField() != "")
|
||||
mTextComponents.back()->setScrollHide(true);
|
||||
addChild(mTextComponents.back().get());
|
||||
}
|
||||
}
|
||||
else if (element.second.type == "datetime") {
|
||||
mDateTimeComponents.push_back(std::make_unique<DateTimeComponent>());
|
||||
mDateTimeComponents.back()->setDefaultZIndex(40.0f);
|
||||
mDateTimeComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
if (mDateTimeComponents.back()->getMetadataField() != "")
|
||||
mDateTimeComponents.back()->setScrollHide(true);
|
||||
addChild(mDateTimeComponents.back().get());
|
||||
}
|
||||
else if (element.second.type == "gamelistinfo") {
|
||||
mGamelistInfoComponents.push_back(std::make_unique<TextComponent>());
|
||||
mGamelistInfoComponents.back()->setDefaultZIndex(45.0f);
|
||||
mGamelistInfoComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
addChild(mGamelistInfoComponents.back().get());
|
||||
}
|
||||
else if (element.second.type == "rating") {
|
||||
mRatingComponents.push_back(std::make_unique<RatingComponent>());
|
||||
mRatingComponents.back()->setDefaultZIndex(45.0f);
|
||||
mRatingComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
||||
mRatingComponents.back()->setScrollHide(true);
|
||||
addChild(mRatingComponents.back().get());
|
||||
}
|
||||
}
|
||||
}
|
||||
mThemeExtras.clear();
|
||||
|
||||
// Add new theme extras.
|
||||
mThemeExtras = ThemeData::makeExtras(theme, getName());
|
||||
for (auto extra : mThemeExtras)
|
||||
addChild(extra);
|
||||
|
||||
mList.applyTheme(theme, getName(), "gamelist", ALL);
|
||||
|
||||
// TODO: Implement logic to populate component vectors.
|
||||
mList.setDefaultZIndex(50.0f);
|
||||
mList.applyTheme(theme, "gamelist", "textlist_gamelist", ALL);
|
||||
|
||||
sortChildren();
|
||||
}
|
||||
|
@ -117,6 +195,23 @@ void GamelistView::update(int deltaTime)
|
|||
return;
|
||||
}
|
||||
|
||||
if (ViewController::getInstance()->getGameLaunchTriggered()) {
|
||||
for (auto& image : mImageComponents) {
|
||||
if (image->isAnimationPlaying(0))
|
||||
image->finishAnimation(0);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& video : mVideoComponents) {
|
||||
if (!mVideoPlaying)
|
||||
video->onHide();
|
||||
else if (mVideoPlaying && !video->isVideoPaused() && !mWindow->isScreensaverActive())
|
||||
video->onShow();
|
||||
|
||||
if (ViewController::getInstance()->getGameLaunchTriggered() && video->isAnimationPlaying(0))
|
||||
video->finishAnimation(0);
|
||||
}
|
||||
|
||||
updateChildren(deltaTime);
|
||||
}
|
||||
|
||||
|
@ -140,7 +235,10 @@ void GamelistView::render(const glm::mat4& parentTrans)
|
|||
HelpStyle GamelistView::getHelpStyle()
|
||||
{
|
||||
HelpStyle style;
|
||||
if (mLegacyMode)
|
||||
style.applyTheme(mTheme, getName());
|
||||
else
|
||||
style.applyTheme(mTheme, "gamelist");
|
||||
return style;
|
||||
}
|
||||
|
||||
|
@ -193,6 +291,11 @@ std::vector<HelpPrompt> GamelistView::getHelpPrompts()
|
|||
|
||||
void GamelistView::updateInfoPanel()
|
||||
{
|
||||
if (mLegacyMode) {
|
||||
legacyUpdateInfoPanel();
|
||||
return;
|
||||
}
|
||||
|
||||
FileData* file {(mList.size() == 0 || mList.isScrolling()) ? nullptr : mList.getSelected()};
|
||||
|
||||
// If the game data has already been rendered to the info panel, then skip it this time.
|
||||
|
@ -219,8 +322,438 @@ void GamelistView::updateInfoPanel()
|
|||
}
|
||||
}
|
||||
|
||||
if (hideMetaDataFields)
|
||||
;
|
||||
|
||||
// TODO: Implement gamelist logic.
|
||||
// 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 (mList.isScrolling()) {
|
||||
if ((mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true") ||
|
||||
(mLastUpdated->getSystem()->isCustomCollection() &&
|
||||
mLastUpdated->getPath() == mLastUpdated->getSystem()->getName()))
|
||||
hideMetaDataFields = true;
|
||||
}
|
||||
|
||||
if (hideMetaDataFields) {
|
||||
for (auto& text : mTextComponents) {
|
||||
if (text->getMetadataField() != "")
|
||||
text->setVisible(false);
|
||||
}
|
||||
for (auto& date : mDateTimeComponents)
|
||||
date->setVisible(false);
|
||||
for (auto& badge : mBadgeComponents)
|
||||
badge->setVisible(false);
|
||||
for (auto& rating : mRatingComponents)
|
||||
rating->setVisible(false);
|
||||
for (auto& cText : mContainerTextComponents) {
|
||||
if (cText->getMetadataField() != "md_description")
|
||||
cText->setVisible(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (auto& text : mTextComponents) {
|
||||
if (text->getMetadataField() != "")
|
||||
text->setVisible(true);
|
||||
}
|
||||
for (auto& date : mDateTimeComponents)
|
||||
date->setVisible(true);
|
||||
for (auto& badge : mBadgeComponents)
|
||||
badge->setVisible(true);
|
||||
for (auto& rating : mRatingComponents)
|
||||
rating->setVisible(true);
|
||||
for (auto& cText : mContainerTextComponents) {
|
||||
if (cText->getMetadataField() != "md_description")
|
||||
cText->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool fadingOut = false;
|
||||
if (file == nullptr) {
|
||||
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) {
|
||||
for (auto& image : mImageComponents) {
|
||||
if (image->getMetadataField() == "md_image")
|
||||
image->setImage(mRandomGame->getImagePath());
|
||||
else if (image->getMetadataField() == "md_miximage")
|
||||
image->setImage(mRandomGame->getMiximagePath());
|
||||
else if (image->getMetadataField() == "md_marquee")
|
||||
image->setImage(mRandomGame->getMarqueePath(), false, true);
|
||||
else if (image->getMetadataField() == "md_screenshot")
|
||||
image->setImage(mRandomGame->getScreenshotPath());
|
||||
else if (image->getMetadataField() == "md_titlescreen")
|
||||
image->setImage(mRandomGame->getTitleScreenPath());
|
||||
else if (image->getMetadataField() == "md_cover")
|
||||
image->setImage(mRandomGame->getCoverPath());
|
||||
else if (image->getMetadataField() == "md_backcover")
|
||||
image->setImage(mRandomGame->getBackCoverPath());
|
||||
else if (image->getMetadataField() == "md_3dbox")
|
||||
image->setImage(mRandomGame->get3DBoxPath());
|
||||
else if (image->getMetadataField() == "md_fanart")
|
||||
image->setImage(mRandomGame->getFanArtPath());
|
||||
else if (image->getMetadataField() == "md_thumbnail")
|
||||
image->setImage(mRandomGame->getThumbnailPath());
|
||||
}
|
||||
|
||||
for (auto& video : mVideoComponents) {
|
||||
if (video->getMetadataField() == "md_image")
|
||||
video->setImage(mRandomGame->getImagePath());
|
||||
else if (video->getMetadataField() == "md_miximage")
|
||||
video->setImage(mRandomGame->getMiximagePath());
|
||||
else if (video->getMetadataField() == "md_marquee")
|
||||
video->setImage(mRandomGame->getMarqueePath(), false, true);
|
||||
else if (video->getMetadataField() == "md_screenshot")
|
||||
video->setImage(mRandomGame->getScreenshotPath());
|
||||
else if (video->getMetadataField() == "md_titlescreen")
|
||||
video->setImage(mRandomGame->getTitleScreenPath());
|
||||
else if (video->getMetadataField() == "md_cover")
|
||||
video->setImage(mRandomGame->getCoverPath());
|
||||
else if (video->getMetadataField() == "md_backcover")
|
||||
video->setImage(mRandomGame->getBackCoverPath());
|
||||
else if (video->getMetadataField() == "md_3dbox")
|
||||
video->setImage(mRandomGame->get3DBoxPath());
|
||||
else if (video->getMetadataField() == "md_fanart")
|
||||
video->setImage(mRandomGame->getFanArtPath());
|
||||
else if (video->getMetadataField() == "md_thumbnail")
|
||||
video->setImage(mRandomGame->getThumbnailPath());
|
||||
|
||||
// Always stop the video before setting a new video as it will otherwise
|
||||
// continue to play if it has the same path (i.e. it is the same physical
|
||||
// video file) as the previously set video. That may happen when entering a
|
||||
// folder with the same name as the first game file inside, or as in this
|
||||
// case, when entering a custom collection.
|
||||
video->onHide();
|
||||
|
||||
if (video->hasStaticVideo())
|
||||
video->setStaticVideo();
|
||||
else if (!video->setVideo(mRandomGame->getVideoPath()))
|
||||
video->setDefaultVideo();
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (auto& image : mImageComponents) {
|
||||
if (image->getMetadataField() != "")
|
||||
image->setImage("");
|
||||
}
|
||||
|
||||
for (auto& video : mVideoComponents) {
|
||||
video->setImage("");
|
||||
video->setVideo("");
|
||||
if (video->hasStaticVideo()) {
|
||||
video->onStopVideo();
|
||||
video->setStaticVideo();
|
||||
}
|
||||
else {
|
||||
video->setDefaultVideo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (auto& image : mImageComponents) {
|
||||
if (image->getMetadataField() == "md_image")
|
||||
image->setImage(file->getImagePath());
|
||||
else if (image->getMetadataField() == "md_miximage")
|
||||
image->setImage(file->getMiximagePath());
|
||||
else if (image->getMetadataField() == "md_marquee")
|
||||
image->setImage(file->getMarqueePath(), false, true);
|
||||
else if (image->getMetadataField() == "md_screenshot")
|
||||
image->setImage(file->getScreenshotPath());
|
||||
else if (image->getMetadataField() == "md_titlescreen")
|
||||
image->setImage(file->getTitleScreenPath());
|
||||
else if (image->getMetadataField() == "md_cover")
|
||||
image->setImage(file->getCoverPath());
|
||||
else if (image->getMetadataField() == "md_backcover")
|
||||
image->setImage(file->getBackCoverPath());
|
||||
else if (image->getMetadataField() == "md_3dbox")
|
||||
image->setImage(file->get3DBoxPath());
|
||||
else if (image->getMetadataField() == "md_fanart")
|
||||
image->setImage(file->getFanArtPath());
|
||||
else if (image->getMetadataField() == "md_thumbnail")
|
||||
image->setImage(file->getThumbnailPath());
|
||||
}
|
||||
|
||||
for (auto& video : mVideoComponents) {
|
||||
if (video->getMetadataField() == "md_image")
|
||||
video->setImage(file->getImagePath());
|
||||
else if (video->getMetadataField() == "md_miximage")
|
||||
video->setImage(file->getMiximagePath());
|
||||
else if (video->getMetadataField() == "md_marquee")
|
||||
video->setImage(file->getMarqueePath(), false, true);
|
||||
else if (video->getMetadataField() == "md_screenshot")
|
||||
video->setImage(file->getScreenshotPath());
|
||||
else if (video->getMetadataField() == "md_titlescreen")
|
||||
video->setImage(file->getTitleScreenPath());
|
||||
else if (video->getMetadataField() == "md_cover")
|
||||
video->setImage(file->getCoverPath());
|
||||
else if (video->getMetadataField() == "md_backcover")
|
||||
video->setImage(file->getBackCoverPath());
|
||||
else if (video->getMetadataField() == "md_3dbox")
|
||||
video->setImage(file->get3DBoxPath());
|
||||
else if (video->getMetadataField() == "md_fanart")
|
||||
video->setImage(file->getFanArtPath());
|
||||
else if (video->getMetadataField() == "md_thumbnail")
|
||||
video->setImage(file->getThumbnailPath());
|
||||
|
||||
video->onHide();
|
||||
|
||||
if (video->hasStaticVideo())
|
||||
video->setStaticVideo();
|
||||
else if (!video->setVideo(file->getVideoPath()))
|
||||
video->setDefaultVideo();
|
||||
}
|
||||
}
|
||||
|
||||
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 += ViewController::FILTER_CHAR + " " +
|
||||
std::to_string(mFilteredGameCount) + " / " +
|
||||
std::to_string(mGameCount);
|
||||
else
|
||||
gamelistInfoString +=
|
||||
ViewController::FILTER_CHAR + " " + std::to_string(mFilteredGameCount) +
|
||||
" + " + std::to_string(mFilteredGameCountAll - mFilteredGameCount) + " / " +
|
||||
std::to_string(mGameCount);
|
||||
}
|
||||
else {
|
||||
gamelistInfoString +=
|
||||
ViewController::CONTROLLER_CHAR + " " + std::to_string(mGameCount);
|
||||
if (!(file->getSystem()->isCollection() &&
|
||||
file->getSystem()->getFullName() == "favorites"))
|
||||
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " " +
|
||||
std::to_string(mFavoritesGameCount);
|
||||
}
|
||||
|
||||
if (mIsFolder && infoAlign != ALIGN_RIGHT)
|
||||
gamelistInfoString += " " + ViewController::FOLDER_CHAR;
|
||||
|
||||
gamelistInfo->setValue(gamelistInfoString);
|
||||
}
|
||||
|
||||
// Fade in the game image.
|
||||
for (auto& image : mImageComponents) {
|
||||
if (image->getMetadataField() == "md_image") {
|
||||
auto func = [&image](float t) {
|
||||
image->setOpacity(static_cast<unsigned char>(
|
||||
glm::mix(static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
||||
};
|
||||
image->setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Fade in the static image.
|
||||
for (auto& video : mVideoComponents) {
|
||||
if (video->getMetadataField() == "md_video") {
|
||||
auto func = [&video](float t) {
|
||||
video->setOpacity(static_cast<unsigned char>(
|
||||
glm::mix(static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
||||
};
|
||||
video->setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& container : mContainerComponents)
|
||||
container->reset();
|
||||
|
||||
for (auto& rating : mRatingComponents)
|
||||
rating->setValue(file->metadata.get("rating"));
|
||||
|
||||
// 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 == "controller") {
|
||||
if (file->metadata.get("controller").compare("") != 0) {
|
||||
badgeInfo.gameController = file->metadata.get("controller");
|
||||
badgeSlots.push_back(badgeInfo);
|
||||
}
|
||||
}
|
||||
else if (badge == "altemulator") {
|
||||
if (file->metadata.get(badge).compare("") != 0)
|
||||
badgeSlots.push_back(badgeInfo);
|
||||
}
|
||||
else {
|
||||
if (file->metadata.get(badge).compare("true") == 0)
|
||||
badgeSlots.push_back(badgeInfo);
|
||||
}
|
||||
}
|
||||
badgeComponent->setBadges(badgeSlots);
|
||||
}
|
||||
|
||||
for (auto& text : mTextComponents) {
|
||||
if (text->getMetadataField() == "md_name")
|
||||
text->setText(file->metadata.get("name"));
|
||||
}
|
||||
|
||||
if (file->getType() == GAME) {
|
||||
if (!hideMetaDataFields) {
|
||||
for (auto& date : mDateTimeComponents) {
|
||||
if (date->getMetadataField() == "md_lastplayed")
|
||||
date->setValue(file->metadata.get("lastplayed"));
|
||||
else if (date->getMetadataField() == "md_playcount")
|
||||
date->setValue(file->metadata.get("playcount"));
|
||||
}
|
||||
}
|
||||
else if (file->getType() == FOLDER) {
|
||||
if (!hideMetaDataFields) {
|
||||
for (auto& date : mDateTimeComponents) {
|
||||
if (date->getMetadataField() == "md_lastplayed") {
|
||||
date->setValue(file->metadata.get("lastplayed"));
|
||||
date->setVisible(false);
|
||||
date->setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string metadata;
|
||||
|
||||
auto getMetadataValue = [&file, &metadata]() -> std::string {
|
||||
if (metadata == "md_name")
|
||||
return file->metadata.get("name");
|
||||
else if (metadata == "md_description")
|
||||
return file->metadata.get("desc");
|
||||
else if (metadata == "md_developer")
|
||||
return file->metadata.get("developer");
|
||||
else if (metadata == "md_publisher")
|
||||
return file->metadata.get("publisher");
|
||||
else if (metadata == "md_genre")
|
||||
return file->metadata.get("genre");
|
||||
else if (metadata == "md_players")
|
||||
return file->metadata.get("players");
|
||||
else if (metadata == "md_favorite")
|
||||
return file->metadata.get("favorite") == "true" ? "Yes" : "No";
|
||||
else if (metadata == "md_completed")
|
||||
return file->metadata.get("completed") == "true" ? "Yes" : "No";
|
||||
else if (metadata == "md_kidgame")
|
||||
return file->metadata.get("kidgame") == "true" ? "Yes" : "No";
|
||||
else if (metadata == "md_broken")
|
||||
return file->metadata.get("broken") == "true" ? "Yes" : "No";
|
||||
else if (metadata == "md_playcount")
|
||||
return file->metadata.get("playcount");
|
||||
else if (metadata == "md_altemulator")
|
||||
return file->metadata.get("altemulator");
|
||||
else
|
||||
return metadata;
|
||||
};
|
||||
|
||||
for (auto& text : mContainerTextComponents) {
|
||||
metadata = text->getMetadataField();
|
||||
if (metadata == "")
|
||||
continue;
|
||||
|
||||
if (metadata == "md_rating") {
|
||||
text->setValue(mRatingComponents.front()->getRatingValue());
|
||||
continue;
|
||||
}
|
||||
else if (metadata == "md_controller") {
|
||||
std::string controller =
|
||||
BadgeComponent::getDisplayName(file->metadata.get("controller"));
|
||||
text->setValue(controller == "unknown" ? "" : controller);
|
||||
continue;
|
||||
}
|
||||
|
||||
text->setValue(getMetadataValue());
|
||||
}
|
||||
|
||||
for (auto& text : mTextComponents) {
|
||||
metadata = text->getMetadataField();
|
||||
if (metadata == "")
|
||||
continue;
|
||||
|
||||
if (metadata == "md_rating") {
|
||||
text->setValue(mRatingComponents.front()->getRatingValue());
|
||||
continue;
|
||||
}
|
||||
else if (metadata == "md_controller") {
|
||||
std::string controller =
|
||||
BadgeComponent::getDisplayName(file->metadata.get("controller"));
|
||||
text->setValue(controller == "unknown" ? "" : controller);
|
||||
continue;
|
||||
}
|
||||
|
||||
text->setValue(getMetadataValue());
|
||||
}
|
||||
|
||||
for (auto& date : mDateTimeComponents) {
|
||||
std::string metadata = date->getMetadataField();
|
||||
if (metadata == "")
|
||||
continue;
|
||||
|
||||
if (metadata == "md_releasedate") {
|
||||
date->setValue(file->metadata.get("releasedate"));
|
||||
}
|
||||
else if (metadata == "md_lastplayed") {
|
||||
date->setValue(file->metadata.get("lastplayed"));
|
||||
date->setDisplayRelative(true);
|
||||
}
|
||||
else {
|
||||
date->setValue("19700101T000000");
|
||||
}
|
||||
}
|
||||
|
||||
fadingOut = false;
|
||||
}
|
||||
|
||||
std::vector<GuiComponent*> comps;
|
||||
|
||||
for (auto& text : mTextComponents) {
|
||||
if (text->getScrollHide())
|
||||
comps.emplace_back(text.get());
|
||||
}
|
||||
for (auto& date : mDateTimeComponents) {
|
||||
if (date->getScrollHide())
|
||||
comps.emplace_back(date.get());
|
||||
}
|
||||
for (auto& image : mImageComponents) {
|
||||
if (image->getScrollHide())
|
||||
comps.emplace_back(image.get());
|
||||
}
|
||||
for (auto& badge : mBadgeComponents) {
|
||||
if (badge->getScrollHide())
|
||||
comps.emplace_back(badge.get());
|
||||
}
|
||||
for (auto& rating : mRatingComponents) {
|
||||
if (rating->getScrollHide())
|
||||
comps.emplace_back(rating.get());
|
||||
}
|
||||
for (auto& container : mContainerComponents) {
|
||||
if (container->getScrollHide())
|
||||
comps.emplace_back(container.get());
|
||||
}
|
||||
|
||||
for (auto it = comps.cbegin(); it != comps.cend(); ++it) {
|
||||
GuiComponent* comp = *it;
|
||||
// An animation is playing, then animate if reverse != fadingOut.
|
||||
// An animation is not playing, then animate if opacity != our target opacity.
|
||||
if ((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
|
||||
(!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255))) {
|
||||
auto func = [comp](float t) {
|
||||
comp->setOpacity(static_cast<unsigned char>(glm::mix(0.0f, 1.0f, t) * 255));
|
||||
};
|
||||
comp->setAnimation(new LambdaAnimation(func, 150), 0, nullptr, fadingOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
class GamelistView : public GamelistBase
|
||||
{
|
||||
public:
|
||||
GamelistView(FileData* root, bool legacyMode = false);
|
||||
GamelistView(FileData* root);
|
||||
~GamelistView();
|
||||
|
||||
// Called when a FileData* is added, has its metadata changed, or is removed.
|
||||
|
@ -76,9 +76,11 @@ private:
|
|||
std::vector<std::unique_ptr<DateTimeComponent>> mDateTimeComponents;
|
||||
std::vector<std::unique_ptr<ImageComponent>> mImageComponents;
|
||||
std::vector<std::unique_ptr<VideoFFmpegComponent>> mVideoComponents;
|
||||
std::vector<std::unique_ptr<LottieComponent>> mLottieAnimComponents;
|
||||
std::vector<std::unique_ptr<BadgeComponent>> mBadgeComponents;
|
||||
std::vector<std::unique_ptr<RatingComponent>> mRatingComponents;
|
||||
std::vector<std::unique_ptr<ScrollableContainer>> mScrollableContainerComponents;
|
||||
std::vector<std::unique_ptr<ScrollableContainer>> mContainerComponents;
|
||||
std::vector<std::unique_ptr<TextComponent>> mContainerTextComponents;
|
||||
std::vector<std::unique_ptr<TextComponent>> mGamelistInfoComponents;
|
||||
|
||||
enum LegacyText {
|
||||
|
|
|
@ -76,7 +76,8 @@ void SystemView::populate()
|
|||
glm::vec3 offsetLogoPlaceholderText = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
// Make logo.
|
||||
const ThemeData::ThemeElement* logoElem = theme->getElement("system", "logo", "image");
|
||||
const ThemeData::ThemeElement* logoElem =
|
||||
theme->getElement("system", "image_logo", "image");
|
||||
if (logoElem) {
|
||||
auto path = logoElem->get<std::string>("path");
|
||||
std::string defaultPath =
|
||||
|
@ -86,7 +87,8 @@ void SystemView::populate()
|
|||
ResourceManager::getInstance().fileExists(defaultPath))) {
|
||||
auto* logo = new ImageComponent(false, false);
|
||||
logo->setMaxSize(glm::round(mCarousel.logoSize * mCarousel.logoScale));
|
||||
logo->applyTheme(theme, "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR);
|
||||
logo->applyTheme(theme, "system", "image_logo",
|
||||
ThemeFlags::PATH | ThemeFlags::COLOR);
|
||||
logo->setRotateByTargetSize(true);
|
||||
e.data.logo = std::shared_ptr<GuiComponent>(logo);
|
||||
}
|
||||
|
@ -100,7 +102,7 @@ void SystemView::populate()
|
|||
glm::vec3 center {resolution.x / 2.0f, resolution.y / 2.0f, 1.0f};
|
||||
|
||||
// Placeholder Image.
|
||||
logoElem = theme->getElement("system", "logoPlaceholderImage", "image");
|
||||
logoElem = theme->getElement("system", "image_logoPlaceholderImage", "image");
|
||||
if (logoElem) {
|
||||
auto path = logoElem->get<std::string>("path");
|
||||
std::string defaultPath =
|
||||
|
@ -109,7 +111,8 @@ void SystemView::populate()
|
|||
(!defaultPath.empty() &&
|
||||
ResourceManager::getInstance().fileExists(defaultPath))) {
|
||||
auto* logo = new ImageComponent(false, false);
|
||||
logo->applyTheme(theme, "system", "logoPlaceholderImage", ThemeFlags::ALL);
|
||||
logo->applyTheme(theme, "system", "image_logoPlaceholderImage",
|
||||
ThemeFlags::ALL);
|
||||
if (!logoElem->has("size"))
|
||||
logo->setMaxSize(mCarousel.logoSize * mCarousel.logoScale);
|
||||
offsetLogo = logo->getPosition() - center;
|
||||
|
@ -120,7 +123,7 @@ void SystemView::populate()
|
|||
|
||||
// Placeholder Text.
|
||||
const ThemeData::ThemeElement* logoPlaceholderText =
|
||||
theme->getElement("system", "logoPlaceholderText", "text");
|
||||
theme->getElement("system", "text_logoPlaceholderText", "text");
|
||||
if (logoPlaceholderText) {
|
||||
// Element 'logoPlaceholderText' found in theme: place text
|
||||
auto* text = new TextComponent(it->getName(), Font::get(FONT_SIZE_LARGE),
|
||||
|
@ -134,7 +137,7 @@ void SystemView::populate()
|
|||
text->setHorizontalAlignment(ALIGN_CENTER);
|
||||
text->setVerticalAlignment(mCarousel.logoAlignment);
|
||||
}
|
||||
text->applyTheme(it->getTheme(), "system", "logoPlaceholderText",
|
||||
text->applyTheme(it->getTheme(), "system", "text_logoPlaceholderText",
|
||||
ThemeFlags::ALL);
|
||||
if (!e.data.logo) {
|
||||
e.data.logo = std::shared_ptr<GuiComponent>(text);
|
||||
|
@ -541,15 +544,16 @@ void SystemView::getViewElements(const std::shared_ptr<ThemeData>& theme)
|
|||
return;
|
||||
|
||||
const ThemeData::ThemeElement* carouselElem =
|
||||
theme->getElement("system", "systemcarousel", "carousel");
|
||||
theme->getElement("system", "carousel_systemcarousel", "carousel");
|
||||
|
||||
if (carouselElem)
|
||||
getCarouselFromTheme(carouselElem);
|
||||
|
||||
const ThemeData::ThemeElement* sysInfoElem = theme->getElement("system", "systemInfo", "text");
|
||||
const ThemeData::ThemeElement* sysInfoElem =
|
||||
theme->getElement("system", "text_systemInfo", "text");
|
||||
|
||||
if (sysInfoElem)
|
||||
mSystemInfo.applyTheme(theme, "system", "systemInfo", ThemeFlags::ALL);
|
||||
mSystemInfo.applyTheme(theme, "system", "text_systemInfo", ThemeFlags::ALL);
|
||||
|
||||
mViewNeedsReload = false;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "resources/Font.h"
|
||||
|
||||
#define PREFIX "button_"
|
||||
|
||||
HelpStyle::HelpStyle()
|
||||
{
|
||||
position =
|
||||
|
@ -32,7 +34,7 @@ HelpStyle::HelpStyle()
|
|||
|
||||
void HelpStyle::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view)
|
||||
{
|
||||
auto elem = theme->getElement(view, "help", "helpsystem");
|
||||
auto elem = theme->getElement(view, "helpsystem_help", "helpsystem");
|
||||
if (!elem)
|
||||
return;
|
||||
|
||||
|
@ -73,74 +75,76 @@ void HelpStyle::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::s
|
|||
textStyle = elem->get<std::string>("textStyle");
|
||||
|
||||
// Load custom button icons.
|
||||
// The names may look a bit strange when combined with the PREFIX string "button_" but it's
|
||||
// because ThemeData adds this prefix to avoid name collisions when using XML attributes.
|
||||
|
||||
// General.
|
||||
if (elem->has("dpad_updown"))
|
||||
mCustomButtons.dpad_updown = elem->get<std::string>("dpad_updown");
|
||||
if (elem->has("dpad_leftright"))
|
||||
mCustomButtons.dpad_leftright = elem->get<std::string>("dpad_leftright");
|
||||
if (elem->has("dpad_all"))
|
||||
mCustomButtons.dpad_all = elem->get<std::string>("dpad_all");
|
||||
if (elem->has("thumbstick_click"))
|
||||
mCustomButtons.thumbstick_click = elem->get<std::string>("thumbstick_click");
|
||||
if (elem->has("button_l"))
|
||||
mCustomButtons.button_l = elem->get<std::string>("button_l");
|
||||
if (elem->has("button_r"))
|
||||
mCustomButtons.button_r = elem->get<std::string>("button_r");
|
||||
if (elem->has("button_lr"))
|
||||
mCustomButtons.button_lr = elem->get<std::string>("button_lr");
|
||||
if (elem->has("button_lt"))
|
||||
mCustomButtons.button_lt = elem->get<std::string>("button_lt");
|
||||
if (elem->has("button_rt"))
|
||||
mCustomButtons.button_rt = elem->get<std::string>("button_rt");
|
||||
if (elem->has(PREFIX "dpad_updown"))
|
||||
mCustomButtons.dpad_updown = elem->get<std::string>(PREFIX "dpad_updown");
|
||||
if (elem->has(PREFIX "dpad_leftright"))
|
||||
mCustomButtons.dpad_leftright = elem->get<std::string>(PREFIX "dpad_leftright");
|
||||
if (elem->has(PREFIX "dpad_all"))
|
||||
mCustomButtons.dpad_all = elem->get<std::string>(PREFIX "dpad_all");
|
||||
if (elem->has(PREFIX "thumbstick_click"))
|
||||
mCustomButtons.thumbstick_click = elem->get<std::string>(PREFIX "thumbstick_click");
|
||||
if (elem->has(PREFIX "button_l"))
|
||||
mCustomButtons.button_l = elem->get<std::string>(PREFIX "button_l");
|
||||
if (elem->has(PREFIX "button_r"))
|
||||
mCustomButtons.button_r = elem->get<std::string>(PREFIX "button_r");
|
||||
if (elem->has(PREFIX "button_lr"))
|
||||
mCustomButtons.button_lr = elem->get<std::string>(PREFIX "button_lr");
|
||||
if (elem->has(PREFIX "button_lt"))
|
||||
mCustomButtons.button_lt = elem->get<std::string>(PREFIX "button_lt");
|
||||
if (elem->has(PREFIX "button_rt"))
|
||||
mCustomButtons.button_rt = elem->get<std::string>(PREFIX "button_rt");
|
||||
|
||||
// SNES.
|
||||
if (elem->has("button_a_SNES"))
|
||||
mCustomButtons.button_a_SNES = elem->get<std::string>("button_a_SNES");
|
||||
if (elem->has("button_b_SNES"))
|
||||
mCustomButtons.button_b_SNES = elem->get<std::string>("button_b_SNES");
|
||||
if (elem->has("button_x_SNES"))
|
||||
mCustomButtons.button_x_SNES = elem->get<std::string>("button_x_SNES");
|
||||
if (elem->has("button_y_SNES"))
|
||||
mCustomButtons.button_y_SNES = elem->get<std::string>("button_y_SNES");
|
||||
if (elem->has("button_start_SNES"))
|
||||
mCustomButtons.button_start_SNES = elem->get<std::string>("button_start_SNES");
|
||||
if (elem->has("button_back_SNES"))
|
||||
mCustomButtons.button_back_SNES = elem->get<std::string>("button_back_SNES");
|
||||
if (elem->has(PREFIX "button_a_SNES"))
|
||||
mCustomButtons.button_a_SNES = elem->get<std::string>(PREFIX "button_a_SNES");
|
||||
if (elem->has(PREFIX "button_b_SNES"))
|
||||
mCustomButtons.button_b_SNES = elem->get<std::string>(PREFIX "button_b_SNES");
|
||||
if (elem->has(PREFIX "button_x_SNES"))
|
||||
mCustomButtons.button_x_SNES = elem->get<std::string>(PREFIX "button_x_SNES");
|
||||
if (elem->has(PREFIX "button_y_SNES"))
|
||||
mCustomButtons.button_y_SNES = elem->get<std::string>(PREFIX "button_y_SNES");
|
||||
if (elem->has(PREFIX "button_start_SNES"))
|
||||
mCustomButtons.button_start_SNES = elem->get<std::string>(PREFIX "button_start_SNES");
|
||||
if (elem->has(PREFIX "button_back_SNES"))
|
||||
mCustomButtons.button_back_SNES = elem->get<std::string>(PREFIX "button_back_SNES");
|
||||
|
||||
// PS.
|
||||
if (elem->has("button_a_PS"))
|
||||
mCustomButtons.button_a_PS = elem->get<std::string>("button_a_PS");
|
||||
if (elem->has("button_b_PS"))
|
||||
mCustomButtons.button_b_PS = elem->get<std::string>("button_b_PS");
|
||||
if (elem->has("button_x_PS"))
|
||||
mCustomButtons.button_x_PS = elem->get<std::string>("button_x_PS");
|
||||
if (elem->has("button_y_PS"))
|
||||
mCustomButtons.button_y_PS = elem->get<std::string>("button_y_PS");
|
||||
if (elem->has("button_start_PS4"))
|
||||
mCustomButtons.button_start_PS4 = elem->get<std::string>("button_start_PS4");
|
||||
if (elem->has("button_back_PS4"))
|
||||
mCustomButtons.button_back_PS4 = elem->get<std::string>("button_back_PS4");
|
||||
if (elem->has("button_start_PS5"))
|
||||
mCustomButtons.button_start_PS5 = elem->get<std::string>("button_start_PS5");
|
||||
if (elem->has("button_back_PS5"))
|
||||
mCustomButtons.button_back_PS5 = elem->get<std::string>("button_back_PS5");
|
||||
// PlayStation.
|
||||
if (elem->has(PREFIX "button_a_PS"))
|
||||
mCustomButtons.button_a_PS = elem->get<std::string>(PREFIX "button_a_PS");
|
||||
if (elem->has(PREFIX "button_b_PS"))
|
||||
mCustomButtons.button_b_PS = elem->get<std::string>(PREFIX "button_b_PS");
|
||||
if (elem->has(PREFIX "button_x_PS"))
|
||||
mCustomButtons.button_x_PS = elem->get<std::string>(PREFIX "button_x_PS");
|
||||
if (elem->has(PREFIX "button_y_PS"))
|
||||
mCustomButtons.button_y_PS = elem->get<std::string>(PREFIX "button_y_PS");
|
||||
if (elem->has(PREFIX "button_start_PS4"))
|
||||
mCustomButtons.button_start_PS4 = elem->get<std::string>(PREFIX "button_start_PS4");
|
||||
if (elem->has(PREFIX "button_back_PS4"))
|
||||
mCustomButtons.button_back_PS4 = elem->get<std::string>(PREFIX "button_back_PS4");
|
||||
if (elem->has(PREFIX "button_start_PS5"))
|
||||
mCustomButtons.button_start_PS5 = elem->get<std::string>(PREFIX "button_start_PS5");
|
||||
if (elem->has(PREFIX "button_back_PS5"))
|
||||
mCustomButtons.button_back_PS5 = elem->get<std::string>(PREFIX "button_back_PS5");
|
||||
|
||||
// XBOX.
|
||||
if (elem->has("button_a_XBOX"))
|
||||
mCustomButtons.button_a_XBOX = elem->get<std::string>("button_a_XBOX");
|
||||
if (elem->has("button_b_XBOX"))
|
||||
mCustomButtons.button_b_XBOX = elem->get<std::string>("button_b_XBOX");
|
||||
if (elem->has("button_x_XBOX"))
|
||||
mCustomButtons.button_x_XBOX = elem->get<std::string>("button_x_XBOX");
|
||||
if (elem->has("button_y_XBOX"))
|
||||
mCustomButtons.button_y_XBOX = elem->get<std::string>("button_y_XBOX");
|
||||
if (elem->has("button_start_XBOX"))
|
||||
mCustomButtons.button_start_XBOX = elem->get<std::string>("button_start_XBOX");
|
||||
if (elem->has("button_back_XBOX"))
|
||||
mCustomButtons.button_back_XBOX = elem->get<std::string>("button_back_XBOX");
|
||||
if (elem->has("button_start_XBOX360"))
|
||||
mCustomButtons.button_start_XBOX360 = elem->get<std::string>("button_start_XBOX360");
|
||||
if (elem->has("button_back_XBOX360"))
|
||||
mCustomButtons.button_back_XBOX360 = elem->get<std::string>("button_back_XBOX360");
|
||||
if (elem->has(PREFIX "button_a_XBOX"))
|
||||
mCustomButtons.button_a_XBOX = elem->get<std::string>(PREFIX "button_a_XBOX");
|
||||
if (elem->has(PREFIX "button_b_XBOX"))
|
||||
mCustomButtons.button_b_XBOX = elem->get<std::string>(PREFIX "button_b_XBOX");
|
||||
if (elem->has(PREFIX "button_x_XBOX"))
|
||||
mCustomButtons.button_x_XBOX = elem->get<std::string>(PREFIX "button_x_XBOX");
|
||||
if (elem->has(PREFIX "button_y_XBOX"))
|
||||
mCustomButtons.button_y_XBOX = elem->get<std::string>(PREFIX "button_y_XBOX");
|
||||
if (elem->has(PREFIX "button_start_XBOX"))
|
||||
mCustomButtons.button_start_XBOX = elem->get<std::string>(PREFIX "button_start_XBOX");
|
||||
if (elem->has(PREFIX "button_back_XBOX"))
|
||||
mCustomButtons.button_back_XBOX = elem->get<std::string>(PREFIX "button_back_XBOX");
|
||||
if (elem->has(PREFIX "button_start_XBOX360"))
|
||||
mCustomButtons.button_start_XBOX360 = elem->get<std::string>(PREFIX "button_start_XBOX360");
|
||||
if (elem->has(PREFIX "button_back_XBOX360"))
|
||||
mCustomButtons.button_back_XBOX360 = elem->get<std::string>(PREFIX "button_back_XBOX360");
|
||||
}
|
||||
|
|
|
@ -133,6 +133,8 @@ void Settings::setDefaults()
|
|||
mStringMap["GamelistViewStyle"] = {"automatic", "automatic"};
|
||||
mStringMap["TransitionStyle"] = {"slide", "slide"};
|
||||
mStringMap["ThemeSet"] = {"rbsimple-DE", "rbsimple-DE"};
|
||||
mStringMap["ThemeVariant"] = {"", ""};
|
||||
mStringMap["ThemeAspectRatio"] = {"", ""};
|
||||
mStringMap["UIMode"] = {"full", "full"};
|
||||
mStringMap["DefaultSortOrder"] = {"filename, ascending", "filename, ascending"};
|
||||
mStringMap["MenuOpeningEffect"] = {"scale-up", "scale-up"};
|
||||
|
|
|
@ -33,18 +33,20 @@ std::shared_ptr<Sound> Sound::getFromTheme(ThemeData* const theme,
|
|||
const std::string& view,
|
||||
const std::string& element)
|
||||
{
|
||||
std::string elemName {element.substr(6, std::string::npos)};
|
||||
|
||||
if (theme == nullptr) {
|
||||
LOG(LogDebug) << "Sound::getFromTheme(): Using fallback sound file for \"" << element
|
||||
LOG(LogDebug) << "Sound::getFromTheme(): Using fallback sound file for \"" << elemName
|
||||
<< "\"";
|
||||
return get(ResourceManager::getInstance().getResourcePath(":/sounds/" + element + ".wav"));
|
||||
return get(ResourceManager::getInstance().getResourcePath(":/sounds/" + elemName + ".wav"));
|
||||
}
|
||||
|
||||
LOG(LogDebug) << "Sound::getFromTheme(): Looking for tag <sound name=\"" << element << "\">";
|
||||
LOG(LogDebug) << "Sound::getFromTheme(): Looking for tag <sound name=\"" << elemName << "\">";
|
||||
|
||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "sound");
|
||||
if (!elem || !elem->has("path")) {
|
||||
LOG(LogDebug) << "Sound::getFromTheme(): Tag not found, using fallback sound file";
|
||||
return get(ResourceManager::getInstance().getResourcePath(":/sounds/" + element + ".wav"));
|
||||
return get(ResourceManager::getInstance().getResourcePath(":/sounds/" + elemName + ".wav"));
|
||||
}
|
||||
|
||||
LOG(LogDebug) << "Sound::getFromTheme(): Tag found, ready to load theme sound file";
|
||||
|
@ -79,8 +81,7 @@ void Sound::init()
|
|||
Uint8* data = nullptr;
|
||||
Uint32 dlen = 0;
|
||||
if (SDL_LoadWAV(mPath.c_str(), &wave, &data, &dlen) == nullptr) {
|
||||
LOG(LogError) << "Failed to load theme navigation sound file:";
|
||||
LOG(LogError) << SDL_GetError();
|
||||
LOG(LogError) << "Failed to load theme navigation sound file: " << SDL_GetError();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -90,14 +91,12 @@ void Sound::init()
|
|||
AudioManager::sAudioFormat.channels, AudioManager::sAudioFormat.freq);
|
||||
|
||||
if (conversionStream == nullptr) {
|
||||
LOG(LogError) << "Failed to create sample conversion stream:";
|
||||
LOG(LogError) << SDL_GetError();
|
||||
LOG(LogError) << "Failed to create sample conversion stream: " << SDL_GetError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (SDL_AudioStreamPut(conversionStream, data, dlen) == -1) {
|
||||
LOG(LogError) << "Failed to put samples in the conversion stream:";
|
||||
LOG(LogError) << SDL_GetError();
|
||||
LOG(LogError) << "Failed to put samples in the conversion stream: " << SDL_GetError();
|
||||
SDL_FreeAudioStream(conversionStream);
|
||||
return;
|
||||
}
|
||||
|
@ -106,8 +105,7 @@ void Sound::init()
|
|||
|
||||
Uint8* converted = new Uint8[sampleLength];
|
||||
if (SDL_AudioStreamGet(conversionStream, converted, sampleLength) == -1) {
|
||||
LOG(LogError) << "Failed to convert sound file '" << mPath << "':";
|
||||
LOG(LogError) << SDL_GetError();
|
||||
LOG(LogError) << "Failed to convert sound file '" << mPath << "': " << SDL_GetError();
|
||||
SDL_FreeAudioStream(conversionStream);
|
||||
delete[] converted;
|
||||
return;
|
||||
|
@ -209,13 +207,13 @@ void NavigationSounds::loadThemeNavigationSounds(ThemeData* const theme)
|
|||
"Theme set does not include navigation sound support, using fallback sounds";
|
||||
}
|
||||
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "systembrowse"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "quicksysselect"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "select"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "back"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "scroll"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "favorite"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "launch"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "sound_systembrowse"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "sound_quicksysselect"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "sound_select"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "sound_back"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "sound_scroll"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "sound_favorite"));
|
||||
mNavigationSounds.push_back(Sound::getFromTheme(theme, "all", "sound_launch"));
|
||||
}
|
||||
|
||||
void NavigationSounds::playThemeNavigationSound(NavigationSoundsID soundID)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,9 +3,9 @@
|
|||
// EmulationStation Desktop Edition
|
||||
// ThemeData.h
|
||||
//
|
||||
// Finds available themes on the file system and loads these,
|
||||
// including the parsing of individual theme components
|
||||
// (includes, features, variables, views, elements).
|
||||
// Finds available themes on the file system and loads and parses these.
|
||||
// Basic error checking for valid elements and data types is done here,
|
||||
// with additional validation handled by the individual components.
|
||||
//
|
||||
|
||||
#ifndef ES_CORE_THEME_DATA_H
|
||||
|
@ -158,8 +158,31 @@ public:
|
|||
|
||||
ThemeData();
|
||||
|
||||
class ThemeView
|
||||
{
|
||||
public:
|
||||
std::map<std::string, ThemeElement> elements;
|
||||
std::vector<std::string> legacyOrderedKeys;
|
||||
};
|
||||
|
||||
struct ThemeVariant {
|
||||
std::string name;
|
||||
std::string label;
|
||||
bool selectable;
|
||||
bool override;
|
||||
std::string overrideTrigger;
|
||||
std::string overrideVariant;
|
||||
};
|
||||
|
||||
struct ThemeCapability {
|
||||
std::vector<ThemeVariant> variants;
|
||||
std::vector<std::string> aspectRatios;
|
||||
bool legacyTheme;
|
||||
};
|
||||
|
||||
struct ThemeSet {
|
||||
std::string path;
|
||||
ThemeCapability capabilities;
|
||||
|
||||
std::string getName() const { return Utils::FileSystem::getStem(path); }
|
||||
std::string getThemePath(const std::string& system) const
|
||||
|
@ -168,21 +191,22 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// Throws ThemeException.
|
||||
void loadFile(const std::map<std::string, std::string>& sysDataMap, const std::string& path);
|
||||
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);
|
||||
|
||||
// If expectedType is an empty string, then do no type checking.
|
||||
const ThemeElement* getElement(const std::string& view,
|
||||
const std::string& element,
|
||||
const std::string& expectedType) const;
|
||||
|
||||
static std::map<std::string, ThemeSet> getThemeSets();
|
||||
static std::map<std::string, ThemeSet>& getThemeSets();
|
||||
static std::string getThemeFromCurrentSet(const std::string& system);
|
||||
|
||||
const bool isLegacyTheme() { return mLegacyTheme; }
|
||||
|
||||
enum ElementPropertyType {
|
||||
NORMALIZED_RECT,
|
||||
NORMALIZED_PAIR,
|
||||
|
@ -196,26 +220,16 @@ public:
|
|||
std::map<std::string, std::string> mVariables;
|
||||
|
||||
private:
|
||||
class ThemeView
|
||||
{
|
||||
public:
|
||||
std::map<std::string, ThemeElement> elements;
|
||||
std::vector<std::string> orderedKeys;
|
||||
};
|
||||
|
||||
static std::map<std::string, std::map<std::string, ElementPropertyType>> sElementMap;
|
||||
static std::vector<std::string> sSupportedFeatures;
|
||||
static std::vector<std::string> sSupportedViews;
|
||||
|
||||
std::deque<std::string> mPaths;
|
||||
float mVersion;
|
||||
|
||||
static const std::shared_ptr<ThemeData> getDefault();
|
||||
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& themeRoot);
|
||||
void parseFeatures(const pugi::xml_node& themeRoot);
|
||||
void parseVariants(const pugi::xml_node& themeRoot);
|
||||
void parseAspectRatios(const pugi::xml_node& themeRoot);
|
||||
void parseVariables(const pugi::xml_node& root);
|
||||
void parseViews(const pugi::xml_node& themeRoot);
|
||||
void parseView(const pugi::xml_node& viewNode, ThemeView& view);
|
||||
|
@ -223,7 +237,24 @@ private:
|
|||
const std::map<std::string, ElementPropertyType>& typeMap,
|
||||
ThemeElement& element);
|
||||
|
||||
static std::map<std::string, std::map<std::string, ElementPropertyType>> sElementMap;
|
||||
static std::map<std::string, std::map<std::string, std::string>> sPropertyAttributeMap;
|
||||
|
||||
static std::vector<std::string> sLegacySupportedFeatures;
|
||||
static std::vector<std::string> sLegacySupportedViews;
|
||||
static std::vector<std::string> sSupportedViews;
|
||||
static std::vector<std::string> sSupportedAspectRatios;
|
||||
|
||||
static inline std::map<std::string, ThemeSet> mThemeSets;
|
||||
std::map<std::string, ThemeData::ThemeSet>::iterator mCurrentThemeSet;
|
||||
|
||||
std::map<std::string, ThemeView> mViews;
|
||||
std::deque<std::string> mPaths;
|
||||
std::vector<std::string> mVariants;
|
||||
std::vector<std::string> mAspectRatios;
|
||||
std::string mSelectedVariant;
|
||||
std::string mSelectedAspectRatio;
|
||||
bool mLegacyTheme;
|
||||
};
|
||||
|
||||
#endif // ES_CORE_THEME_DATA_H
|
||||
|
|
|
@ -290,8 +290,10 @@ void BadgeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
|
||||
for (auto slot : slots) {
|
||||
if (std::find(mBadgeTypes.cbegin(), mBadgeTypes.cend(), slot) != mBadgeTypes.end()) {
|
||||
if (properties & PATH && elem->has(slot))
|
||||
mBadgeIcons[slot] = elem->get<std::string>(slot);
|
||||
// The "badge_" string is required as ThemeData adds this as a prefix to avoid
|
||||
// name collisions when using XML attributes.
|
||||
if (properties & PATH && elem->has("badge_" + slot))
|
||||
mBadgeIcons[slot] = elem->get<std::string>("badge_" + slot);
|
||||
|
||||
FlexboxComponent::FlexboxItem item;
|
||||
item.label = slot;
|
||||
|
@ -309,8 +311,9 @@ void BadgeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
}
|
||||
|
||||
for (auto& gameController : sGameControllers) {
|
||||
if (properties & PATH && elem->has(gameController.shortName))
|
||||
gameController.fileName = elem->get<std::string>(gameController.shortName);
|
||||
if (properties & PATH && elem->has("controller_" + gameController.shortName))
|
||||
gameController.fileName =
|
||||
elem->get<std::string>("controller_" + gameController.shortName);
|
||||
}
|
||||
|
||||
GuiComponent::applyTheme(theme, view, element, properties);
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
unsigned int properties) override;
|
||||
|
||||
private:
|
||||
inline static std::vector<GameControllers> sGameControllers;
|
||||
static inline std::vector<GameControllers> sGameControllers;
|
||||
|
||||
std::vector<FlexboxComponent::FlexboxItem> mFlexboxItems;
|
||||
FlexboxComponent mFlexboxComponent;
|
||||
|
|
|
@ -111,7 +111,6 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
unsigned int properties)
|
||||
{
|
||||
GuiComponent::applyTheme(theme, view, element, properties);
|
||||
|
||||
using namespace ThemeFlags;
|
||||
|
||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "datetime");
|
||||
|
|
|
@ -475,7 +475,6 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
unsigned int properties)
|
||||
{
|
||||
using namespace ThemeFlags;
|
||||
|
||||
GuiComponent::applyTheme(theme, view, element,
|
||||
(properties ^ ThemeFlags::SIZE) |
|
||||
((properties & (ThemeFlags::SIZE | POSITION)) ? ORIGIN : 0));
|
||||
|
@ -505,6 +504,9 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
setImage(elem->get<std::string>("path"), tile);
|
||||
}
|
||||
|
||||
if (properties & METADATA && elem->has("metadata"))
|
||||
setMetadataField(elem->get<std::string>("metadata"));
|
||||
|
||||
if (properties & COLOR) {
|
||||
if (elem->has("color"))
|
||||
setColorShift(elem->get<unsigned int>("color"));
|
||||
|
|
|
@ -214,7 +214,6 @@ void LottieComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
unsigned int properties)
|
||||
{
|
||||
using namespace ThemeFlags;
|
||||
|
||||
const ThemeData::ThemeElement* elem {theme->getElement(view, element, "animation")};
|
||||
|
||||
if (elem->has("size")) {
|
||||
|
|
|
@ -50,8 +50,8 @@ private:
|
|||
std::vector<uint8_t> mPictureRGBA;
|
||||
std::unordered_map<size_t, std::vector<uint8_t>> mFrameCache;
|
||||
// Set a 1024 MiB total Lottie animation cache as default.
|
||||
inline static size_t mMaxTotalFrameCache = 1024 * 1024 * 1024;
|
||||
inline static size_t mTotalFrameCache;
|
||||
static inline size_t mMaxTotalFrameCache = 1024 * 1024 * 1024;
|
||||
static inline size_t mTotalFrameCache;
|
||||
bool mCacheFrames;
|
||||
size_t mMaxCacheSize;
|
||||
size_t mCacheSize;
|
||||
|
|
|
@ -211,7 +211,6 @@ void RatingComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
unsigned int properties)
|
||||
{
|
||||
using namespace ThemeFlags;
|
||||
|
||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "rating");
|
||||
if (!elem)
|
||||
return;
|
||||
|
|
|
@ -291,11 +291,15 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
const std::string& element,
|
||||
unsigned int properties)
|
||||
{
|
||||
using namespace ThemeFlags;
|
||||
GuiComponent::applyTheme(theme, view, element, properties);
|
||||
|
||||
using namespace ThemeFlags;
|
||||
std::string elementType {"text"};
|
||||
|
||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "text");
|
||||
if (element.substr(0, 13) == "gamelistinfo_")
|
||||
elementType = "gamelistinfo";
|
||||
|
||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, elementType);
|
||||
if (!elem)
|
||||
return;
|
||||
|
||||
|
|
|
@ -75,13 +75,13 @@ bool VideoComponent::setVideo(std::string path)
|
|||
return false;
|
||||
}
|
||||
|
||||
void VideoComponent::setImage(std::string path)
|
||||
void VideoComponent::setImage(const std::string& path, bool tile, bool linearMagnify)
|
||||
{
|
||||
// Check that the image has changed.
|
||||
if (path == mStaticImagePath)
|
||||
return;
|
||||
|
||||
mStaticImage.setImage(path);
|
||||
mStaticImage.setImage(path, tile, linearMagnify);
|
||||
mStaticImagePath = path;
|
||||
}
|
||||
|
||||
|
@ -212,7 +212,6 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
unsigned int properties)
|
||||
{
|
||||
using namespace ThemeFlags;
|
||||
|
||||
GuiComponent::applyTheme(theme, view, element,
|
||||
(properties ^ ThemeFlags::SIZE) |
|
||||
((properties & (ThemeFlags::SIZE | POSITION)) ? ORIGIN : 0));
|
||||
|
@ -245,14 +244,24 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
if (elem->has("default"))
|
||||
mConfig.defaultVideoPath = elem->get<std::string>("default");
|
||||
|
||||
if (elem->has("path"))
|
||||
mConfig.staticVideoPath = elem->get<std::string>("path");
|
||||
|
||||
if ((properties & ThemeFlags::DELAY) && elem->has("delay"))
|
||||
mConfig.startDelay = static_cast<unsigned>((elem->get<float>("delay") * 1000.0f));
|
||||
|
||||
if (elem->has("showSnapshotNoVideo"))
|
||||
if (!theme->isLegacyTheme())
|
||||
mConfig.showSnapshotNoVideo = true;
|
||||
else if (elem->has("showSnapshotNoVideo"))
|
||||
mConfig.showSnapshotNoVideo = elem->get<bool>("showSnapshotNoVideo");
|
||||
|
||||
if (elem->has("showSnapshotDelay"))
|
||||
if (!theme->isLegacyTheme() && mConfig.startDelay != 0)
|
||||
mConfig.showSnapshotDelay = true;
|
||||
else if (elem->has("showSnapshotDelay"))
|
||||
mConfig.showSnapshotDelay = elem->get<bool>("showSnapshotDelay");
|
||||
|
||||
if (properties & METADATA && elem->has("imageMetadata"))
|
||||
setMetadataField(elem->get<std::string>("imageMetadata"));
|
||||
}
|
||||
|
||||
std::vector<HelpPrompt> VideoComponent::getHelpPrompts()
|
||||
|
|
|
@ -26,6 +26,7 @@ class VideoComponent : public GuiComponent
|
|||
bool showSnapshotNoVideo;
|
||||
bool showSnapshotDelay;
|
||||
std::string defaultVideoPath;
|
||||
std::string staticVideoPath;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -36,8 +37,10 @@ public:
|
|||
bool setVideo(std::string path);
|
||||
// Configures the component to show the default video.
|
||||
void setDefaultVideo() { setVideo(mConfig.defaultVideoPath); }
|
||||
// Configures the component to show the static video.
|
||||
void setStaticVideo() { setVideo(mConfig.staticVideoPath); }
|
||||
// Loads a static image that is displayed if the video cannot be played.
|
||||
void setImage(std::string path);
|
||||
void setImage(const std::string& path, bool tile = false, bool linearMagnify = false);
|
||||
// Sets whether we're in media viewer mode.
|
||||
void setMediaViewerMode(bool isMediaViewer) { mMediaViewerMode = isMediaViewer; }
|
||||
// Sets whether we're in screensaver mode.
|
||||
|
@ -45,6 +48,8 @@ public:
|
|||
// Set the opacity for the embedded static image.
|
||||
void setOpacity(unsigned char opacity) override { mOpacity = opacity; }
|
||||
|
||||
bool hasStaticVideo() { return !mConfig.staticVideoPath.empty(); }
|
||||
|
||||
void onShow() override;
|
||||
void onHide() override;
|
||||
void onStopVideo() override;
|
||||
|
|
|
@ -215,6 +215,7 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
|
|||
Renderer::drawTriangleStrips(&vertices[0], 4, trans);
|
||||
}
|
||||
else {
|
||||
if (mVisible)
|
||||
VideoComponent::renderSnapshot(parentTrans);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue