Added support for theme-controlled transition animations.

This commit is contained in:
Leon Styhre 2023-01-08 17:00:36 +01:00
parent 1f0bf21675
commit 71b4fc947a
8 changed files with 546 additions and 70 deletions

View file

@ -294,6 +294,101 @@ void GuiMenu::openUIOptions()
themeAspectRatiosFunc(Settings::getInstance()->getString("ThemeSet"), themeAspectRatiosFunc(Settings::getInstance()->getString("ThemeSet"),
Settings::getInstance()->getString("ThemeAspectRatio")); Settings::getInstance()->getString("ThemeAspectRatio"));
// Theme transition animations.
auto themeTransitionAnimations = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "THEME TRANSITION ANIMS", false);
std::string selectedAnim {Settings::getInstance()->getString("ThemeTransitionAnimations")};
themeTransitionAnimations->add("AUTOMATIC", "automatic", selectedAnim == "automatic");
// If there are no objects returned, then there must be a manually modified entry in the
// configuration file. Simply set the animation type to "automatic" in this case.
if (themeTransitionAnimations->getSelectedObjects().size() == 0)
themeTransitionAnimations->selectEntry(0);
s->addWithLabel("THEME TRANSITION ANIMATIONS", themeTransitionAnimations);
s->addSaveFunc([themeTransitionAnimations, s] {
if (themeTransitionAnimations->getSelected() !=
Settings::getInstance()->getString("ThemeTransitionAnimations")) {
Settings::getInstance()->setString("ThemeTransitionAnimations",
themeTransitionAnimations->getSelected());
ThemeData::setThemeTransitions();
s->setNeedsSaving();
}
});
auto themeTransitionAnimationsFunc = [=](const std::string& selectedTheme,
const std::string& selectedTransitionAnimation) {
std::map<std::string, ThemeData::ThemeSet, ThemeData::StringComparator>::const_iterator
currentSet {themeSets.find(selectedTheme)};
if (currentSet == themeSets.cend())
return;
// We need to recreate the OptionListComponent entries.
themeTransitionAnimations->clearEntries();
if (currentSet->second.capabilities.legacyTheme) {
themeTransitionAnimations->add("Legacy theme set", "automatic", true);
themeTransitionAnimations->setEnabled(false);
themeTransitionAnimations->setOpacity(DISABLED_OPACITY);
themeTransitionAnimations->getParent()
->getChild(themeTransitionAnimations->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
else {
themeTransitionAnimations->add("AUTOMATIC", "automatic",
"automatic" == selectedTransitionAnimation);
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 transitionAnim {
currentSet->second.capabilities.transitions.front().name};
themeTransitionAnimations->add(label, transitionAnim,
transitionAnim == selectedTransitionAnimation);
}
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 transitionAnim {
currentSet->second.capabilities.transitions[i].name};
themeTransitionAnimations->add(label, transitionAnim,
transitionAnim == selectedTransitionAnimation);
}
}
if (std::find(currentSet->second.capabilities.suppressedTransitionEntries.cbegin(),
currentSet->second.capabilities.suppressedTransitionEntries.cend(),
"builtin-instant") ==
currentSet->second.capabilities.suppressedTransitionEntries.cend()) {
themeTransitionAnimations->add("INSTANT (BUILT-IN)", "builtin-instant",
"builtin-instant" == selectedTransitionAnimation);
}
if (std::find(currentSet->second.capabilities.suppressedTransitionEntries.cbegin(),
currentSet->second.capabilities.suppressedTransitionEntries.cend(),
"builtin-slide") ==
currentSet->second.capabilities.suppressedTransitionEntries.cend()) {
themeTransitionAnimations->add("SLIDE (BUILT-IN)", "builtin-slide",
"builtin-slide" == selectedTransitionAnimation);
}
if (std::find(currentSet->second.capabilities.suppressedTransitionEntries.cbegin(),
currentSet->second.capabilities.suppressedTransitionEntries.cend(),
"builtin-fade") ==
currentSet->second.capabilities.suppressedTransitionEntries.cend()) {
themeTransitionAnimations->add("FADE (BUILT-IN)", "builtin-fade",
"builtin-fade" == selectedTransitionAnimation);
}
if (themeTransitionAnimations->getSelectedObjects().size() == 0)
themeTransitionAnimations->selectEntry(0);
}
};
themeTransitionAnimationsFunc(Settings::getInstance()->getString("ThemeSet"),
Settings::getInstance()->getString("ThemeTransitionAnimations"));
// Legacy gamelist view style. // Legacy gamelist view style.
auto gamelistViewStyle = std::make_shared<OptionListComponent<std::string>>( auto gamelistViewStyle = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "LEGACY GAMELIST VIEW STYLE", false); getHelpStyle(), "LEGACY GAMELIST VIEW STYLE", false);
@ -318,21 +413,28 @@ void GuiMenu::openUIOptions()
} }
}); });
// Legacy ransition style. // Legacy transition animations.
auto transitionStyle = std::make_shared<OptionListComponent<std::string>>( auto legacyTransitionAnimations = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "LEGACY TRANSITION STYLE", false); getHelpStyle(), "LEGACY TRANSITION ANIMS", false);
std::vector<std::string> transitions; const std::string& selectedLegacyAnimations {
transitions.push_back("slide"); Settings::getInstance()->getString("LegacyTransitionAnimations")};
transitions.push_back("fade"); legacyTransitionAnimations->add("INSTANT", "builtin-instant",
transitions.push_back("instant"); selectedLegacyAnimations == "builtin-instant");
for (auto it = transitions.cbegin(); it != transitions.cend(); ++it) legacyTransitionAnimations->add("SLIDE", "builtin-slide",
transitionStyle->add(*it, *it, selectedLegacyAnimations == "builtin-slide");
Settings::getInstance()->getString("TransitionStyle") == *it); legacyTransitionAnimations->add("FADE", "builtin-fade",
s->addWithLabel("LEGACY TRANSITION STYLE", transitionStyle); selectedLegacyAnimations == "builtin-fade");
s->addSaveFunc([transitionStyle, s] { // If there are no objects returned, then there must be a manually modified entry in the
if (transitionStyle->getSelected() != // configuration file. Simply set the animations to "builtin-instant" in this case.
Settings::getInstance()->getString("TransitionStyle")) { if (legacyTransitionAnimations->getSelectedObjects().size() == 0)
Settings::getInstance()->setString("TransitionStyle", transitionStyle->getSelected()); legacyTransitionAnimations->selectEntry(0);
s->addWithLabel("LEGACY TRANSITION ANIMATIONS", legacyTransitionAnimations);
s->addSaveFunc([legacyTransitionAnimations, s] {
if (legacyTransitionAnimations->getSelected() !=
Settings::getInstance()->getString("LegacyTransitionAnimations")) {
Settings::getInstance()->setString("LegacyTransitionAnimations",
legacyTransitionAnimations->getSelected());
ThemeData::setThemeTransitions();
s->setNeedsSaving(); s->setNeedsSaving();
} }
}); });
@ -729,6 +831,7 @@ void GuiMenu::openUIOptions()
themeVariantsFunc(themeName, themeVariant->getSelected()); themeVariantsFunc(themeName, themeVariant->getSelected());
themeColorSchemesFunc(themeName, themeColorScheme->getSelected()); themeColorSchemesFunc(themeName, themeColorScheme->getSelected());
themeAspectRatiosFunc(themeName, themeAspectRatio->getSelected()); themeAspectRatiosFunc(themeName, themeAspectRatio->getSelected());
themeTransitionAnimationsFunc(themeName, themeTransitionAnimations->getSelected());
} }
int selectableVariants {0}; int selectableVariants {0};
for (auto& variant : selectedSet->second.capabilities.variants) { for (auto& variant : selectedSet->second.capabilities.variants) {
@ -785,12 +888,18 @@ void GuiMenu::openUIOptions()
gamelistViewStyle->getParent() gamelistViewStyle->getParent()
->getChild(gamelistViewStyle->getChildIndex() - 1) ->getChild(gamelistViewStyle->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY); ->setOpacity(DISABLED_OPACITY);
// TEMPORARY
// transitionStyle->setEnabled(false); themeTransitionAnimations->setEnabled(true);
// transitionStyle->setOpacity(DISABLED_OPACITY); themeTransitionAnimations->setOpacity(1.0f);
// transitionStyle->getParent() themeTransitionAnimations->getParent()
// ->getChild(transitionStyle->getChildIndex() - 1) ->getChild(themeTransitionAnimations->getChildIndex() - 1)
// ->setOpacity(DISABLED_OPACITY); ->setOpacity(1.0f);
legacyTransitionAnimations->setEnabled(false);
legacyTransitionAnimations->setOpacity(DISABLED_OPACITY);
legacyTransitionAnimations->getParent()
->getChild(legacyTransitionAnimations->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
// Pillarboxes are theme-controlled for newer themes. // Pillarboxes are theme-controlled for newer themes.
gamelistVideoPillarbox->setEnabled(false); gamelistVideoPillarbox->setEnabled(false);
@ -813,10 +922,16 @@ void GuiMenu::openUIOptions()
->getChild(gamelistViewStyle->getChildIndex() - 1) ->getChild(gamelistViewStyle->getChildIndex() - 1)
->setOpacity(1.0f); ->setOpacity(1.0f);
transitionStyle->setEnabled(true); themeTransitionAnimations->setEnabled(false);
transitionStyle->setOpacity(1.0f); themeTransitionAnimations->setOpacity(DISABLED_OPACITY);
transitionStyle->getParent() themeTransitionAnimations->getParent()
->getChild(transitionStyle->getChildIndex() - 1) ->getChild(themeTransitionAnimations->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
legacyTransitionAnimations->setEnabled(true);
legacyTransitionAnimations->setOpacity(1.0f);
legacyTransitionAnimations->getParent()
->getChild(legacyTransitionAnimations->getChildIndex() - 1)
->setOpacity(1.0f); ->setOpacity(1.0f);
gamelistVideoPillarbox->setEnabled(true); gamelistVideoPillarbox->setEnabled(true);

View file

@ -227,8 +227,9 @@ void SystemView::onCursorChanged(const CursorState& state)
{ {
const int cursor {mPrimary->getCursor()}; const int cursor {mPrimary->getCursor()};
const int scrollVelocity {mPrimary->getScrollingVelocity()}; const int scrollVelocity {mPrimary->getScrollingVelocity()};
const std::string& transitionStyle {Settings::getInstance()->getString("TransitionStyle")}; const ViewTransitionAnimation transitionAnim {static_cast<ViewTransitionAnimation>(
mFadeTransitions = transitionStyle == "fade"; Settings::getInstance()->getInt("TransitionsSystemToSystem"))};
mFadeTransitions = (transitionAnim == ViewTransitionAnimation::FADE);
// Some logic needed to avoid various navigation glitches with GridComponent and // Some logic needed to avoid various navigation glitches with GridComponent and
// TextListComponent. // TextListComponent.
@ -278,7 +279,7 @@ void SystemView::onCursorChanged(const CursorState& state)
// This is needed to avoid erratic camera movements during extreme navigation input when using // This is needed to avoid erratic camera movements during extreme navigation input when using
// slide transitions. This should very rarely occur during normal application usage. // slide transitions. This should very rarely occur during normal application usage.
if (transitionStyle == "slide") { if (transitionAnim == ViewTransitionAnimation::SLIDE) {
bool resetCamOffset {false}; bool resetCamOffset {false};
if (scrollVelocity == -1 && mPreviousScrollVelocity == 1) { if (scrollVelocity == -1 && mPreviousScrollVelocity == 1) {
@ -372,7 +373,7 @@ void SystemView::onCursorChanged(const CursorState& state)
animTime = animTime =
glm::clamp(std::fabs(glm::mix(0.0f, animTime, timeDiff * 1.5f)), timeMin, animTime); glm::clamp(std::fabs(glm::mix(0.0f, animTime, timeDiff * 1.5f)), timeMin, animTime);
if (transitionStyle == "fade") { if (transitionAnim == ViewTransitionAnimation::FADE) {
float startFade {mFadeOpacity}; float startFade {mFadeOpacity};
anim = new LambdaAnimation( anim = new LambdaAnimation(
[this, startFade, endPos](float t) { [this, startFade, endPos](float t) {
@ -398,7 +399,7 @@ void SystemView::onCursorChanged(const CursorState& state)
}, },
static_cast<int>(animTime * 1.3f)); static_cast<int>(animTime * 1.3f));
} }
else if (transitionStyle == "slide") { else if (transitionAnim == ViewTransitionAnimation::SLIDE) {
mUpdatedGameCount = false; mUpdatedGameCount = false;
anim = new LambdaAnimation( anim = new LambdaAnimation(
[this, startPos, endPos, posMax](float t) { [this, startPos, endPos, posMax](float t) {
@ -815,7 +816,8 @@ void SystemView::populate()
} }
} }
mFadeTransitions = Settings::getInstance()->getString("TransitionStyle") == "fade"; mFadeTransitions = (static_cast<ViewTransitionAnimation>(Settings::getInstance()->getInt(
"TransitionsSystemToSystem")) == ViewTransitionAnimation::FADE);
} }
void SystemView::updateGameCount() void SystemView::updateGameCount()

View file

@ -37,6 +37,7 @@ ViewController::ViewController() noexcept
, mCurrentView {nullptr} , mCurrentView {nullptr}
, mPreviousView {nullptr} , mPreviousView {nullptr}
, mSkipView {nullptr} , mSkipView {nullptr}
, mLastTransitionAnim {ViewTransitionAnimation::INSTANT}
, mGameToLaunch {nullptr} , mGameToLaunch {nullptr}
, mCamera {Renderer::getIdentity()} , mCamera {Renderer::getIdentity()}
, mSystemViewTransition {false} , mSystemViewTransition {false}
@ -220,7 +221,7 @@ void ViewController::goToStart(bool playTransition)
// If a specific system is requested, go directly to its game list. // If a specific system is requested, go directly to its game list.
auto requestedSystem = Settings::getInstance()->getString("StartupSystem"); auto requestedSystem = Settings::getInstance()->getString("StartupSystem");
if ("" != requestedSystem && "retropie" != requestedSystem) { if (requestedSystem != "") {
for (auto it = SystemData::sSystemVector.cbegin(); // Line break. for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
it != SystemData::sSystemVector.cend(); ++it) { it != SystemData::sSystemVector.cend(); ++it) {
if ((*it)->getName() == requestedSystem) { if ((*it)->getName() == requestedSystem) {
@ -263,7 +264,7 @@ bool ViewController::isCameraMoving()
void ViewController::cancelViewTransitions() void ViewController::cancelViewTransitions()
{ {
if (Settings::getInstance()->getString("TransitionStyle") == "slide") { if (mLastTransitionAnim == ViewTransitionAnimation::SLIDE) {
if (isCameraMoving()) { if (isCameraMoving()) {
mCamera[3].x = -mCurrentView->getPosition().x; mCamera[3].x = -mCurrentView->getPosition().x;
mCamera[3].y = -mCurrentView->getPosition().y; mCamera[3].y = -mCurrentView->getPosition().y;
@ -277,7 +278,7 @@ void ViewController::cancelViewTransitions()
mSkipView = nullptr; mSkipView = nullptr;
} }
} }
else if (Settings::getInstance()->getString("TransitionStyle") == "fade") { else if (mLastTransitionAnim == ViewTransitionAnimation::FADE) {
if (isAnimationPlaying(0)) { if (isAnimationPlaying(0)) {
finishAnimation(0); finishAnimation(0);
mCancelledTransition = true; mCancelledTransition = true;
@ -354,8 +355,11 @@ void ViewController::goToSystemView(SystemData* system, bool playTransition)
// Application startup animation. // Application startup animation.
if (applicationStartup) { if (applicationStartup) {
const ViewTransitionAnimation transitionAnim {static_cast<ViewTransitionAnimation>(
Settings::getInstance()->getInt("TransitionsStartupToSystem"))};
mCamera = glm::translate(mCamera, glm::round(-mCurrentView->getPosition())); mCamera = glm::translate(mCamera, glm::round(-mCurrentView->getPosition()));
if (Settings::getInstance()->getString("TransitionStyle") == "slide") { if (transitionAnim == ViewTransitionAnimation::SLIDE) {
if (getSystemListView()->getPrimaryType() == SystemView::PrimaryType::CAROUSEL) { if (getSystemListView()->getPrimaryType() == SystemView::PrimaryType::CAROUSEL) {
if (getSystemListView()->getCarouselType() == if (getSystemListView()->getCarouselType() ==
CarouselComponent<SystemData*>::CarouselType::HORIZONTAL || CarouselComponent<SystemData*>::CarouselType::HORIZONTAL ||
@ -370,7 +374,7 @@ void ViewController::goToSystemView(SystemData* system, bool playTransition)
} }
updateHelpPrompts(); updateHelpPrompts();
} }
else if (Settings::getInstance()->getString("TransitionStyle") == "fade") { else if (transitionAnim == ViewTransitionAnimation::FADE) {
if (getSystemListView()->getPrimaryType() == SystemView::PrimaryType::CAROUSEL) { if (getSystemListView()->getPrimaryType() == SystemView::PrimaryType::CAROUSEL) {
if (getSystemListView()->getCarouselType() == if (getSystemListView()->getCarouselType() ==
CarouselComponent<SystemData*>::CarouselType::HORIZONTAL || CarouselComponent<SystemData*>::CarouselType::HORIZONTAL ||
@ -389,18 +393,21 @@ void ViewController::goToSystemView(SystemData* system, bool playTransition)
} }
} }
if (applicationStartup) {
#if defined(__APPLE__) #if defined(__APPLE__)
// The startup animations are very choppy on macOS as of moving to SDL 2.0.18 so the // The startup animations are very choppy on macOS as of moving to SDL 2.0.18 so the
// best user experience is to simply disable them on this OS. // best user experience is to simply disable them on this OS.
if (applicationStartup) playViewTransition(ViewTransition::STARTUP_TO_SYSTEM, true);
playViewTransition(true);
else if (playTransition)
#else #else
if (playTransition || applicationStartup) playViewTransition(ViewTransition::STARTUP_TO_SYSTEM);
#endif #endif
playViewTransition(); }
else else if (playTransition) {
playViewTransition(true); playViewTransition(ViewTransition::GAMELIST_TO_SYSTEM);
}
else {
playViewTransition(ViewTransition::GAMELIST_TO_SYSTEM, true);
}
} }
void ViewController::goToSystem(SystemData* system, bool animate) void ViewController::goToSystem(SystemData* system, bool animate)
@ -433,21 +440,37 @@ void ViewController::goToGamelist(SystemData* system)
bool wrapFirstToLast {false}; bool wrapFirstToLast {false};
bool wrapLastToFirst {false}; bool wrapLastToFirst {false};
bool slideTransitions {false}; bool slideTransitions {false};
bool fadeTransitions {false};
if (mCurrentView != nullptr) if (mCurrentView != nullptr)
mCurrentView->onTransition(); mCurrentView->onTransition();
if (Settings::getInstance()->getString("TransitionStyle") == "slide") ViewTransition transitionType;
ViewTransitionAnimation transitionAnim;
if (mState.viewing == SYSTEM_SELECT) {
transitionType = ViewTransition::SYSTEM_TO_GAMELIST;
transitionAnim = static_cast<ViewTransitionAnimation>(
Settings::getInstance()->getInt("TransitionsSystemToGamelist"));
}
else {
transitionType = ViewTransition::GAMELIST_TO_GAMELIST;
transitionAnim = static_cast<ViewTransitionAnimation>(
Settings::getInstance()->getInt("TransitionsGamelistToGamelist"));
}
if (transitionAnim == ViewTransitionAnimation::SLIDE)
slideTransitions = true; slideTransitions = true;
if (transitionAnim == ViewTransitionAnimation::FADE)
fadeTransitions = true;
// Restore the X position for the view, if it was previously moved. // Restore the X position for the view, if it was previously moved.
if (mWrappedViews) if (mWrappedViews)
restoreViewPosition(); restoreViewPosition();
if (mPreviousView && Settings::getInstance()->getString("TransitionStyle") == "fade" && if (mPreviousView && fadeTransitions && isAnimationPlaying(0))
isAnimationPlaying(0)) {
mPreviousView->onHide(); mPreviousView->onHide();
}
if (mPreviousView) { if (mPreviousView) {
mSkipView = mPreviousView; mSkipView = mPreviousView;
@ -540,12 +563,17 @@ void ViewController::goToGamelist(SystemData* system)
// Application startup animation, if starting in a gamelist rather than in the system view. // Application startup animation, if starting in a gamelist rather than in the system view.
if (mState.viewing == NOTHING) { if (mState.viewing == NOTHING) {
if (mLastTransitionAnim == ViewTransitionAnimation::FADE)
cancelViewTransitions();
transitionType = ViewTransition::STARTUP_TO_GAMELIST;
mCamera = glm::translate(mCamera, glm::round(-mCurrentView->getPosition())); mCamera = glm::translate(mCamera, glm::round(-mCurrentView->getPosition()));
if (Settings::getInstance()->getString("TransitionStyle") == "slide") { if (static_cast<ViewTransitionAnimation>(Settings::getInstance()->getInt(
"TransitionsStartupToGamelist")) == ViewTransitionAnimation::SLIDE) {
mCamera[3].y -= Renderer::getScreenHeight(); mCamera[3].y -= Renderer::getScreenHeight();
updateHelpPrompts(); updateHelpPrompts();
} }
else if (Settings::getInstance()->getString("TransitionStyle") == "fade") { else if (static_cast<ViewTransitionAnimation>(Settings::getInstance()->getInt(
"TransitionsStartupToGamelist")) == ViewTransitionAnimation::FADE) {
mCamera[3].y += Renderer::getScreenHeight() * 2.0f; mCamera[3].y += Renderer::getScreenHeight() * 2.0f;
} }
else { else {
@ -570,14 +598,14 @@ void ViewController::goToGamelist(SystemData* system)
if (mCurrentView) if (mCurrentView)
mCurrentView->onShow(); mCurrentView->onShow();
playViewTransition(); playViewTransition(transitionType);
} }
void ViewController::playViewTransition(bool instant) void ViewController::playViewTransition(ViewTransition transitionType, bool instant)
{ {
mCancelledTransition = false; mCancelledTransition = false;
glm::vec3 target {}; glm::vec3 target {0.0f, 0.0f, 0.0f};
if (mCurrentView) if (mCurrentView)
target = mCurrentView->getPosition(); target = mCurrentView->getPosition();
@ -586,9 +614,30 @@ void ViewController::playViewTransition(bool instant)
if (target == static_cast<glm::vec3>(-mCamera[3]) && !isAnimationPlaying(0)) if (target == static_cast<glm::vec3>(-mCamera[3]) && !isAnimationPlaying(0))
return; return;
std::string transition_style {Settings::getInstance()->getString("TransitionStyle")}; ViewTransitionAnimation transitionAnim {ViewTransitionAnimation::INSTANT};
if (instant || transition_style == "instant") { if (transitionType == ViewTransition::SYSTEM_TO_SYSTEM)
transitionAnim = static_cast<ViewTransitionAnimation>(
Settings::getInstance()->getInt("TransitionsSystemToSystem"));
else if (transitionType == ViewTransition::SYSTEM_TO_GAMELIST)
transitionAnim = static_cast<ViewTransitionAnimation>(
Settings::getInstance()->getInt("TransitionsSystemToGamelist"));
else if (transitionType == ViewTransition::GAMELIST_TO_GAMELIST)
transitionAnim = static_cast<ViewTransitionAnimation>(
Settings::getInstance()->getInt("TransitionsGamelistToGamelist"));
else if (transitionType == ViewTransition::GAMELIST_TO_SYSTEM)
transitionAnim = static_cast<ViewTransitionAnimation>(
Settings::getInstance()->getInt("TransitionsGamelistToSystem"));
else if (transitionType == ViewTransition::STARTUP_TO_SYSTEM)
transitionAnim = static_cast<ViewTransitionAnimation>(
Settings::getInstance()->getInt("TransitionsStartupToSystem"));
else
transitionAnim = static_cast<ViewTransitionAnimation>(
Settings::getInstance()->getInt("TransitionsStartupToGamelist"));
mLastTransitionAnim = transitionAnim;
if (instant || transitionAnim == ViewTransitionAnimation::INSTANT) {
setAnimation(new LambdaAnimation( setAnimation(new LambdaAnimation(
[this, target](float /*t*/) { [this, target](float /*t*/) {
this->mCamera[3].x = -target.x; this->mCamera[3].x = -target.x;
@ -600,7 +649,7 @@ void ViewController::playViewTransition(bool instant)
1)); 1));
updateHelpPrompts(); updateHelpPrompts();
} }
else if (transition_style == "fade") { else if (transitionAnim == ViewTransitionAnimation::FADE) {
// Stop whatever's currently playing, leaving mFadeOpacity wherever it is. // Stop whatever's currently playing, leaving mFadeOpacity wherever it is.
cancelAnimation(0); cancelAnimation(0);
@ -641,7 +690,7 @@ void ViewController::playViewTransition(bool instant)
advanceAnimation(0, static_cast<int>(mFadeOpacity * FADE_DURATION)); advanceAnimation(0, static_cast<int>(mFadeOpacity * FADE_DURATION));
} }
} }
else if (transition_style == "slide") { else if (transitionAnim == ViewTransitionAnimation::SLIDE) {
auto slideCallback = [this]() { auto slideCallback = [this]() {
if (mSkipView) { if (mSkipView) {
mSkipView->onHide(); mSkipView->onHide();
@ -1046,7 +1095,7 @@ void ViewController::render(const glm::mat4& parentTrans)
void ViewController::preload() void ViewController::preload()
{ {
unsigned int systemCount = static_cast<int>(SystemData::sSystemVector.size()); unsigned int systemCount {static_cast<unsigned int>(SystemData::sSystemVector.size())};
// This reduces the amount of texture pop-in when loading theme extras. // This reduces the amount of texture pop-in when loading theme extras.
if (!SystemData::sSystemVector.empty()) if (!SystemData::sSystemVector.empty())
@ -1064,6 +1113,8 @@ void ViewController::preload()
getGamelistView(*it)->preloadGamelist(); getGamelistView(*it)->preloadGamelist();
} }
ThemeData::setThemeTransitions();
// Load navigation sounds, either from the theme if it supports it, or otherwise from // Load navigation sounds, either from the theme if it supports it, or otherwise from
// the bundled fallback sound files. // the bundled fallback sound files.
bool themeSoundSupport {false}; bool themeSoundSupport {false};
@ -1082,7 +1133,7 @@ void ViewController::reloadGamelistView(GamelistView* view, bool reloadTheme)
{ {
for (auto it = mGamelistViews.cbegin(); it != mGamelistViews.cend(); ++it) { for (auto it = mGamelistViews.cbegin(); it != mGamelistViews.cend(); ++it) {
if (it->second.get() == view) { if (it->second.get() == view) {
bool isCurrent {(mCurrentView == it->second)}; bool isCurrent {mCurrentView == it->second};
SystemData* system {it->first}; SystemData* system {it->first};
FileData* cursor {view->getCursor()}; FileData* cursor {view->getCursor()};
@ -1147,6 +1198,8 @@ void ViewController::reloadAll()
it->first->getIndex()->resetFilters(); it->first->getIndex()->resetFilters();
} }
ThemeData::setThemeTransitions();
// Rebuild SystemListView. // Rebuild SystemListView.
mSystemListView.reset(); mSystemListView.reset();
getSystemListView(); getSystemListView();
@ -1160,7 +1213,7 @@ void ViewController::reloadAll()
mCurrentView = getGamelistView(mState.getSystem()); mCurrentView = getGamelistView(mState.getSystem());
} }
else if (mState.viewing == SYSTEM_SELECT) { else if (mState.viewing == SYSTEM_SELECT) {
SystemData* system = mState.getSystem(); SystemData* system {mState.getSystem()};
mSystemListView->goToSystem(system, false); mSystemListView->goToSystem(system, false);
mCurrentView = mSystemListView; mCurrentView = mSystemListView;
mCamera[3].x = 0.0f; mCamera[3].x = 0.0f;

View file

@ -160,7 +160,7 @@ private:
std::string mRomDirectory; std::string mRomDirectory;
GuiMsgBox* mNoGamesMessageBox; GuiMsgBox* mNoGamesMessageBox;
void playViewTransition(bool instant = false); void playViewTransition(ViewTransition transitionType, bool instant = false);
int getSystemId(SystemData* system); int getSystemId(SystemData* system);
// Restore view position if it was moved during wrap around. // Restore view position if it was moved during wrap around.
void restoreViewPosition(); void restoreViewPosition();
@ -170,6 +170,7 @@ private:
std::shared_ptr<GuiComponent> mSkipView; std::shared_ptr<GuiComponent> mSkipView;
std::map<SystemData*, std::shared_ptr<GamelistView>> mGamelistViews; std::map<SystemData*, std::shared_ptr<GamelistView>> mGamelistViews;
std::shared_ptr<SystemView> mSystemListView; std::shared_ptr<SystemView> mSystemListView;
ViewTransitionAnimation mLastTransitionAnim;
std::vector<std::string> mGameEndEventParams; std::vector<std::string> mGameEndEventParams;
FileData* mGameToLaunch; FileData* mGameToLaunch;

View file

@ -34,6 +34,21 @@ class InputConfig;
class ThemeData; class ThemeData;
class Window; class Window;
enum class ViewTransition {
SYSTEM_TO_SYSTEM,
SYSTEM_TO_GAMELIST,
GAMELIST_TO_GAMELIST,
GAMELIST_TO_SYSTEM,
STARTUP_TO_SYSTEM,
STARTUP_TO_GAMELIST
};
enum ViewTransitionAnimation {
INSTANT,
SLIDE,
FADE
};
enum Alignment { enum Alignment {
ALIGN_LEFT, ALIGN_LEFT,
ALIGN_CENTER, // Used for both horizontal and vertical alignments. ALIGN_CENTER, // Used for both horizontal and vertical alignments.

View file

@ -9,6 +9,7 @@
#include "Settings.h" #include "Settings.h"
#include "GuiComponent.h"
#include "Log.h" #include "Log.h"
#include "Scripting.h" #include "Scripting.h"
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
@ -20,10 +21,8 @@
namespace namespace
{ {
// These values are NOT saved to es_settings.xml since they're not set via // These settings are not saved to es_settings.xml. Most can be set using command-line
// the in-program settings menu. Most can be set using command-line arguments, // arguments but a couple are debug flags or used for other application-internal purposes.
// but some are debug flags that are either hardcoded or set by internal debug
// functions.
std::vector<std::string> settingsSkipSaving { std::vector<std::string> settingsSkipSaving {
// clang-format off // clang-format off
// These options can be set using command-line arguments: // These options can be set using command-line arguments:
@ -38,18 +37,24 @@ namespace
"ForceKiosk", // --force-kiosk "ForceKiosk", // --force-kiosk
"ForceKid", // --force-kid "ForceKid", // --force-kid
// These options are not shown in the --help text and are intended // These command-line argument options are not shown in the --help text and are intended
// for debugging and testing purposes: // for debugging and testing purposes:
"ScreenWidth", // Set via --screensize [width] [height] "ScreenWidth", // Set via --screensize [width] [height]
"ScreenHeight", // set via --screensize [width] [height] "ScreenHeight", // set via --screensize [width] [height]
"ScreenOffsetX", // Set via --screenoffset [X] [Y] "ScreenOffsetX", // Set via --screenoffset [X] [Y]
"ScreenOffsetY", // Set via --screenoffset [X] [Y] "ScreenOffsetY", // Set via --screenoffset [X] [Y]
// These options are not configurable from the command-line: // These options are only used internally during the application session:
"DebugGrid", "DebugGrid",
"DebugText", "DebugText",
"DebugImage", "DebugImage",
"ScraperFilter" "ScraperFilter",
"TransitionsSystemToSystem",
"TransitionsSystemToGamelist",
"TransitionsGamelistToGamelist",
"TransitionsGamelistToSystem",
"TransitionsStartupToSystem",
"TransitionsStartupToGamelist"
// clang-format on // clang-format on
}; };
@ -151,8 +156,9 @@ void Settings::setDefaults()
mStringMap["ThemeVariant"] = {"", ""}; mStringMap["ThemeVariant"] = {"", ""};
mStringMap["ThemeColorScheme"] = {"", ""}; mStringMap["ThemeColorScheme"] = {"", ""};
mStringMap["ThemeAspectRatio"] = {"", ""}; mStringMap["ThemeAspectRatio"] = {"", ""};
mStringMap["ThemeTransitionAnimations"] = {"automatic", "automatic"};
mStringMap["GamelistViewStyle"] = {"automatic", "automatic"}; mStringMap["GamelistViewStyle"] = {"automatic", "automatic"};
mStringMap["TransitionStyle"] = {"slide", "slide"}; mStringMap["LegacyTransitionAnimations"] = {"builtin-instant", "builtin-instant"};
mStringMap["QuickSystemSelect"] = {"leftrightshoulders", "leftrightshoulders"}; mStringMap["QuickSystemSelect"] = {"leftrightshoulders", "leftrightshoulders"};
mStringMap["StartupSystem"] = {"", ""}; mStringMap["StartupSystem"] = {"", ""};
mStringMap["DefaultSortOrder"] = {"filename, ascending", "filename, ascending"}; mStringMap["DefaultSortOrder"] = {"filename, ascending", "filename, ascending"};
@ -323,6 +329,19 @@ void Settings::setDefaults()
mBoolMap["DebugText"] = {false, false}; mBoolMap["DebugText"] = {false, false};
mBoolMap["DebugImage"] = {false, false}; mBoolMap["DebugImage"] = {false, false};
mIntMap["ScraperFilter"] = {0, 0}; mIntMap["ScraperFilter"] = {0, 0};
mIntMap["TransitionsSystemToSystem"] = {ViewTransitionAnimation::INSTANT,
ViewTransitionAnimation::INSTANT};
mIntMap["TransitionsSystemToGamelist"] = {ViewTransitionAnimation::INSTANT,
ViewTransitionAnimation::INSTANT};
mIntMap["TransitionsGamelistToGamelist"] = {ViewTransitionAnimation::INSTANT,
ViewTransitionAnimation::INSTANT};
mIntMap["TransitionsGamelistToSystem"] = {ViewTransitionAnimation::INSTANT,
ViewTransitionAnimation::INSTANT};
mIntMap["TransitionsStartupToSystem"] = {ViewTransitionAnimation::INSTANT,
ViewTransitionAnimation::INSTANT};
mIntMap["TransitionsStartupToGamelist"] = {ViewTransitionAnimation::INSTANT,
ViewTransitionAnimation::INSTANT};
} }
void Settings::saveFile() void Settings::saveFile()

View file

@ -40,6 +40,19 @@ std::vector<std::string> ThemeData::sSupportedMediaTypes {
{"fanart"}, {"fanart"},
{"video"}}; {"video"}};
std::vector<std::string> ThemeData::sSupportedTransitions {
{"systemToSystem"},
{"systemToGamelist"},
{"gamelistToGamelist"},
{"gamelistToSystem"},
{"startupToSystem"},
{"startupToGamelist"}};
std::vector<std::string> ThemeData::sSupportedTransitionAnimations {
{"builtin-instant"},
{"builtin-slide"},
{"builtin-fade"}};
std::vector<std::string> ThemeData::sLegacySupportedViews { std::vector<std::string> ThemeData::sLegacySupportedViews {
{"all"}, {"all"},
{"system"}, {"system"},
@ -495,6 +508,7 @@ ThemeData::ThemeData()
, mCustomCollection {false} , mCustomCollection {false}
{ {
mCurrentThemeSet = mThemeSets.find(Settings::getInstance()->getString("ThemeSet")); mCurrentThemeSet = mThemeSets.find(Settings::getInstance()->getString("ThemeSet"));
mVariantDefinedTransitions = "";
} }
void ThemeData::loadFile(const std::map<std::string, std::string>& sysDataMap, void ThemeData::loadFile(const std::map<std::string, std::string>& sysDataMap,
@ -819,6 +833,95 @@ const std::string ThemeData::getAspectRatioLabel(const std::string& aspectRatio)
return "invalid ratio"; return "invalid ratio";
} }
void ThemeData::setThemeTransitions()
{
auto setTransitionsFunc = [](int transitionAnim) {
Settings::getInstance()->setInt("TransitionsSystemToSystem", transitionAnim);
Settings::getInstance()->setInt("TransitionsSystemToGamelist", transitionAnim);
Settings::getInstance()->setInt("TransitionsGamelistToGamelist", transitionAnim);
Settings::getInstance()->setInt("TransitionsGamelistToSystem", transitionAnim);
Settings::getInstance()->setInt("TransitionsStartupToSystem", transitionAnim);
Settings::getInstance()->setInt("TransitionsStartupToGamelist", transitionAnim);
};
int transitionAnim {ViewTransitionAnimation::INSTANT};
setTransitionsFunc(transitionAnim);
if (mCurrentThemeSet->second.capabilities.legacyTheme) {
const std::string& legacyTransitionSetting {
Settings::getInstance()->getString("LegacyTransitionAnimations")};
if (legacyTransitionSetting == "builtin-slide")
transitionAnim = static_cast<int>(ViewTransitionAnimation::SLIDE);
else if (legacyTransitionSetting == "builtin-fade")
transitionAnim = static_cast<int>(ViewTransitionAnimation::FADE);
setTransitionsFunc(transitionAnim);
}
else {
const std::string& transitionSetting {
Settings::getInstance()->getString("ThemeTransitionAnimations")};
std::string profile;
size_t profileEntry {0};
if (transitionSetting == "automatic") {
if (mVariantDefinedTransitions != "")
profile = mVariantDefinedTransitions;
else if (!mCurrentThemeSet->second.capabilities.transitions.empty())
profile = mCurrentThemeSet->second.capabilities.transitions.front().name;
}
else {
profile = transitionSetting;
}
auto it = std::find_if(
mCurrentThemeSet->second.capabilities.transitions.cbegin(),
mCurrentThemeSet->second.capabilities.transitions.cend(),
[&profile](const ThemeTransitions transitions) { return transitions.name == profile; });
if (it != mCurrentThemeSet->second.capabilities.transitions.cend())
profileEntry = static_cast<size_t>(
std::distance(mCurrentThemeSet->second.capabilities.transitions.cbegin(), it) + 1);
if (profileEntry != 0 &&
mCurrentThemeSet->second.capabilities.transitions.size() > profileEntry - 1) {
auto transitionMap =
mCurrentThemeSet->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 (transitionSetting == "builtin-slide" || transitionSetting == "builtin-fade") {
if (std::find(
mCurrentThemeSet->second.capabilities.suppressedTransitionEntries.cbegin(),
mCurrentThemeSet->second.capabilities.suppressedTransitionEntries.cend(),
transitionSetting) ==
mCurrentThemeSet->second.capabilities.suppressedTransitionEntries.cend()) {
if (transitionSetting == "builtin-slide") {
transitionAnim = static_cast<int>(ViewTransitionAnimation::SLIDE);
}
else if (transitionSetting == "builtin-fade") {
transitionAnim = static_cast<int>(ViewTransitionAnimation::FADE);
}
setTransitionsFunc(transitionAnim);
}
}
}
}
const std::map<ThemeTriggers::TriggerType, std::pair<std::string, std::vector<std::string>>> const std::map<ThemeTriggers::TriggerType, std::pair<std::string, std::vector<std::string>>>
ThemeData::getCurrentThemeSetSelectedVariantOverrides() ThemeData::getCurrentThemeSetSelectedVariantOverrides()
{ {
@ -1128,6 +1231,140 @@ ThemeData::ThemeCapability ThemeData::parseThemeCapabilities(const std::string&
capabilities.colorSchemes.emplace_back(readColorScheme); capabilities.colorSchemes.emplace_back(readColorScheme);
} }
} }
for (pugi::xml_node transitions {themeCapabilities.child("transitions")}; transitions;
transitions = transitions.next_sibling("transitions")) {
std::map<ViewTransition, ViewTransitionAnimation> readTransitions;
std::string name {transitions.attribute("name").as_string()};
std::string label;
bool selectable {true};
if (name.empty()) {
LOG(LogWarning)
<< "Found <transitions> tag without name attribute, ignoring entry in \""
<< capFile << "\"";
name.clear();
}
else {
if (std::find(sSupportedTransitionAnimations.cbegin(),
sSupportedTransitionAnimations.cend(),
name) != sSupportedTransitionAnimations.cend()) {
LOG(LogWarning)
<< "Found <transitions> tag using reserved name attribute value \"" << name
<< "\", ignoring entry in \"" << capFile << "\"";
name.clear();
}
else {
for (auto& transitionEntry : capabilities.transitions) {
if (transitionEntry.name == name) {
LOG(LogWarning)
<< "Found <transitions> tag with previously used name attribute "
"value \""
<< name << "\", ignoring entry in \"" << capFile << "\"";
name.clear();
}
}
}
}
if (name == "")
continue;
const pugi::xml_node& labelTag {transitions.child("label")};
if (labelTag != nullptr)
label = labelTag.text().as_string();
const pugi::xml_node& selectableTag {transitions.child("selectable")};
if (selectableTag != nullptr) {
const std::string& value {selectableTag.text().as_string()};
if (value.front() == '0' || value.front() == 'f' || value.front() == 'F' ||
value.front() == 'n' || value.front() == 'N')
selectable = false;
}
for (auto& currTransition : sSupportedTransitions) {
const pugi::xml_node& transitionTag {transitions.child(currTransition.c_str())};
if (transitionTag != nullptr) {
const std::string& transitionValue {transitionTag.text().as_string()};
if (transitionValue.empty()) {
LOG(LogWarning) << "Found <" << currTransition
<< "> transition tag without any value, "
"ignoring entry in \""
<< capFile << "\"";
}
else if (std::find(sSupportedTransitionAnimations.cbegin(),
sSupportedTransitionAnimations.cend(),
currTransition) != sSupportedTransitionAnimations.cend()) {
LOG(LogWarning)
<< "Invalid <" << currTransition << "> transition tag value \""
<< transitionValue << "\", ignoring entry in \"" << capFile << "\"";
}
else {
ViewTransitionAnimation transitionAnim {ViewTransitionAnimation::INSTANT};
if (transitionValue == "slide")
transitionAnim = ViewTransitionAnimation::SLIDE;
else if (transitionValue == "fade")
transitionAnim = ViewTransitionAnimation::FADE;
if (currTransition == "systemToSystem")
readTransitions[ViewTransition::SYSTEM_TO_SYSTEM] = transitionAnim;
else if (currTransition == "systemToGamelist")
readTransitions[ViewTransition::SYSTEM_TO_GAMELIST] = transitionAnim;
else if (currTransition == "gamelistToGamelist")
readTransitions[ViewTransition::GAMELIST_TO_GAMELIST] = transitionAnim;
else if (currTransition == "gamelistToSystem")
readTransitions[ViewTransition::GAMELIST_TO_SYSTEM] = transitionAnim;
else if (currTransition == "startupToSystem")
readTransitions[ViewTransition::STARTUP_TO_SYSTEM] = transitionAnim;
else if (currTransition == "startupToGamelist")
readTransitions[ViewTransition::STARTUP_TO_GAMELIST] = transitionAnim;
}
}
}
if (!readTransitions.empty()) {
ThemeTransitions transition;
transition.name = name;
transition.label = label;
transition.selectable = selectable;
transition.animations = std::move(readTransitions);
capabilities.transitions.emplace_back(std::move(transition));
}
}
for (pugi::xml_node suppressTransitionEntries {
themeCapabilities.child("suppressTransitionEntries")};
suppressTransitionEntries;
suppressTransitionEntries =
suppressTransitionEntries.next_sibling("suppressTransitionEntries")) {
std::vector<std::string> readSuppressEntries;
for (pugi::xml_node entries {suppressTransitionEntries.child("entry")}; entries;
entries = entries.next_sibling("entry")) {
const std::string& entryValue {entries.text().as_string()};
if (std::find(sSupportedTransitionAnimations.cbegin(),
sSupportedTransitionAnimations.cend(),
entryValue) != sSupportedTransitionAnimations.cend()) {
capabilities.suppressedTransitionEntries.emplace_back(entryValue);
}
else {
LOG(LogWarning)
<< "Found suppressTransitionEntries <entry> tag with invalid value \""
<< entryValue << "\", ignoring entry in \"" << capFile << "\"";
}
}
// Sort and remove any duplicates.
if (capabilities.suppressedTransitionEntries.size() > 1) {
std::sort(capabilities.suppressedTransitionEntries.begin(),
capabilities.suppressedTransitionEntries.end());
auto last = std::unique(capabilities.suppressedTransitionEntries.begin(),
capabilities.suppressedTransitionEntries.end());
capabilities.suppressedTransitionEntries.erase(
last, capabilities.suppressedTransitionEntries.end());
}
}
} }
else { else {
LOG(LogDebug) << "No capabilities.xml file found, flagging as legacy theme set"; LOG(LogDebug) << "No capabilities.xml file found, flagging as legacy theme set";
@ -1311,6 +1548,21 @@ void ThemeData::parseVariants(const pugi::xml_node& root)
mOverrideVariant}; mOverrideVariant};
if (variant == viewKey || viewKey == "all") { if (variant == viewKey || viewKey == "all") {
const pugi::xml_node& transitions {node.child("transitions")};
if (transitions != nullptr) {
const std::string& transitionsValue {transitions.text().as_string()};
if (std::find_if(mCurrentThemeSet->second.capabilities.transitions.cbegin(),
mCurrentThemeSet->second.capabilities.transitions.cend(),
[&transitionsValue](const ThemeTransitions transitions) {
return transitions.name == transitionsValue;
}) ==
mCurrentThemeSet->second.capabilities.transitions.cend()) {
throw error << ": <transitions> value \"" << transitionsValue
<< "\" is not matching any defined transitions";
}
mVariantDefinedTransitions = transitionsValue;
}
parseVariables(node); parseVariables(node);
parseColorSchemes(node); parseColorSchemes(node);
parseIncludes(node); parseIncludes(node);

View file

@ -11,6 +11,7 @@
#ifndef ES_CORE_THEME_DATA_H #ifndef ES_CORE_THEME_DATA_H
#define ES_CORE_THEME_DATA_H #define ES_CORE_THEME_DATA_H
#include "GuiComponent.h"
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include "utils/MathUtil.h" #include "utils/MathUtil.h"
#include "utils/StringUtil.h" #include "utils/StringUtil.h"
@ -198,10 +199,24 @@ public:
std::string label; std::string label;
}; };
struct ThemeTransitions {
std::string name;
std::string label;
bool selectable;
std::map<ViewTransition, ViewTransitionAnimation> animations;
ThemeTransitions()
: selectable {true}
{
}
};
struct ThemeCapability { struct ThemeCapability {
std::vector<ThemeVariant> variants; std::vector<ThemeVariant> variants;
std::vector<ThemeColorScheme> colorSchemes; std::vector<ThemeColorScheme> colorSchemes;
std::vector<std::string> aspectRatios; std::vector<std::string> aspectRatios;
std::vector<ThemeTransitions> transitions;
std::vector<std::string> suppressedTransitionEntries;
bool legacyTheme; bool legacyTheme;
}; };
@ -245,6 +260,7 @@ public:
const static std::string getThemeFromCurrentSet(const std::string& system); const static std::string getThemeFromCurrentSet(const std::string& system);
const static std::string getAspectRatioLabel(const std::string& aspectRatio); const static std::string getAspectRatioLabel(const std::string& aspectRatio);
const static std::string getCurrentThemeSetName() { return mCurrentThemeSet->first; } const static std::string getCurrentThemeSetName() { return mCurrentThemeSet->first; }
static void setThemeTransitions();
const bool isLegacyTheme() { return mLegacyTheme; } const bool isLegacyTheme() { return mLegacyTheme; }
const std::map<ThemeTriggers::TriggerType, std::pair<std::string, std::vector<std::string>>> const std::map<ThemeTriggers::TriggerType, std::pair<std::string, std::vector<std::string>>>
@ -291,6 +307,8 @@ private:
static std::vector<std::string> sSupportedViews; static std::vector<std::string> sSupportedViews;
static std::vector<std::string> sSupportedMediaTypes; 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> sLegacySupportedViews;
static std::vector<std::string> sLegacySupportedFeatures; static std::vector<std::string> sLegacySupportedFeatures;
static std::vector<std::string> sLegacyProperties; static std::vector<std::string> sLegacyProperties;
@ -302,6 +320,7 @@ private:
static inline std::map<std::string, ThemeSet, StringComparator> mThemeSets; static inline std::map<std::string, ThemeSet, StringComparator> mThemeSets;
static inline std::map<std::string, ThemeSet, StringComparator>::iterator mCurrentThemeSet {}; static inline std::map<std::string, ThemeSet, StringComparator>::iterator mCurrentThemeSet {};
static inline std::string mVariantDefinedTransitions;
std::map<std::string, ThemeView> mViews; std::map<std::string, ThemeView> mViews;
std::deque<std::string> mPaths; std::deque<std::string> mPaths;