diff --git a/DEVNOTES.md b/DEVNOTES.md index adf33b753..795c270b7 100644 --- a/DEVNOTES.md +++ b/DEVNOTES.md @@ -25,7 +25,7 @@ Some key points: * Name member variables starting with a small 'm', e.g. mMyMemberVariable * Use the same naming convention for functions as for local variables, e.g. someFunction() * Inline functions makes perfect sense to use, but don't overdo it by using them for functions that won't be called very frequently -* Never put more than one statement on a single line, except for lambda expressions +* Never put more than one statement on a single line (there are some exceptions though like lambda expressions and some switch statements) * Avoid overoptimizations, especially if it sacrifices readability, makes the code hard to expand on or is error prone * For the rest, check the code and have fun! :) diff --git a/es-app/src/EmulationStation.h b/es-app/src/EmulationStation.h index 5e8cec120..ffc02e3c0 100644 --- a/es-app/src/EmulationStation.h +++ b/es-app/src/EmulationStation.h @@ -1,5 +1,5 @@ // -// EmulationStation.h +// EmulationStation.h // // Version and build information. // diff --git a/es-app/src/SystemScreenSaver.cpp b/es-app/src/SystemScreenSaver.cpp index 4df8a1d3d..70ead9cb5 100644 --- a/es-app/src/SystemScreenSaver.cpp +++ b/es-app/src/SystemScreenSaver.cpp @@ -2,7 +2,7 @@ // SystemScreenSaver.cpp // // Screensaver, supporting the following modes: -// Dim, black, video, slideshow. +// Dim, black, video, slideshow. // #include "SystemScreenSaver.h" diff --git a/es-app/src/SystemScreenSaver.h b/es-app/src/SystemScreenSaver.h index 4f5461a44..4390a8a22 100644 --- a/es-app/src/SystemScreenSaver.h +++ b/es-app/src/SystemScreenSaver.h @@ -2,7 +2,7 @@ // SystemScreenSaver.h // // Screensaver, supporting the following modes: -// Dim, black, video, slideshow. +// Dim, black, video, slideshow. // #pragma once diff --git a/es-app/src/guis/GuiCollectionSystemsOptions.cpp b/es-app/src/guis/GuiCollectionSystemsOptions.cpp index 1ec301477..00bc1a94f 100644 --- a/es-app/src/guis/GuiCollectionSystemsOptions.cpp +++ b/es-app/src/guis/GuiCollectionSystemsOptions.cpp @@ -2,7 +2,7 @@ // GuiCollectionSystemsOptions.cpp // // User interface for the game collection settings. -// Submenu to the GuiMenu main menu. +// Submenu to the GuiMenu main menu. // #include "guis/GuiCollectionSystemsOptions.h" diff --git a/es-app/src/guis/GuiCollectionSystemsOptions.h b/es-app/src/guis/GuiCollectionSystemsOptions.h index 4ab9df6e4..96da01de9 100644 --- a/es-app/src/guis/GuiCollectionSystemsOptions.h +++ b/es-app/src/guis/GuiCollectionSystemsOptions.h @@ -2,7 +2,7 @@ // GuiCollectionSystemsOptions.h // // User interface for the game collection settings. -// Submenu to the GuiMenu main menu. +// Submenu to the GuiMenu main menu. // #pragma once diff --git a/es-app/src/guis/GuiGeneralScreensaverOptions.h b/es-app/src/guis/GuiGeneralScreensaverOptions.h index 8d5192119..bcdeae517 100644 --- a/es-app/src/guis/GuiGeneralScreensaverOptions.h +++ b/es-app/src/guis/GuiGeneralScreensaverOptions.h @@ -3,7 +3,7 @@ // // User interface for the screensaver options. // Based on the GuiScreenSaverOptions template. -// Submenu to the GuiMenu main menu. +// Submenu to the GuiMenu main menu. // #pragma once diff --git a/es-app/src/guis/GuiSlideshowScreensaverOptions.h b/es-app/src/guis/GuiSlideshowScreensaverOptions.h index c4e1741d3..7aa9d71ae 100644 --- a/es-app/src/guis/GuiSlideshowScreensaverOptions.h +++ b/es-app/src/guis/GuiSlideshowScreensaverOptions.h @@ -1,5 +1,5 @@ // -// GuiSlideshowScreensaverOptions.h +// GuiSlideshowScreensaverOptions.h // // User interface for the slideshow screensaver options. // Submenu to GuiGeneralScreensaverOptions. diff --git a/es-app/src/guis/GuiVideoScreensaverOptions.cpp b/es-app/src/guis/GuiVideoScreensaverOptions.cpp index 5304b157d..7952a15c6 100644 --- a/es-app/src/guis/GuiVideoScreensaverOptions.cpp +++ b/es-app/src/guis/GuiVideoScreensaverOptions.cpp @@ -59,7 +59,7 @@ GuiVideoScreensaverOptions::GuiVideoScreensaverOptions(Window* window, const cha // Set subtitle position. auto ss_omx_subs_align = std::make_shared> - (mWindow, "GAME INFO ALIGNMENT", false); + (mWindow, getHelpStyle(), "GAME INFO ALIGNMENT", false); std::vector align_mode; align_mode.push_back("left"); align_mode.push_back("center"); @@ -132,7 +132,7 @@ void GuiVideoScreensaverOptions::save() "never" && Settings::getInstance()->getBool("ScreenSaverOmxPlayer")); if (startingStatusNotRisky && endStatusRisky) { // If before it wasn't risky but now there's a risk of problems, show warning. - mWindow->pushGui(new GuiMsgBox(mWindow, + mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), "Using OMX Player and displaying Game Info may result in the video flickering in " "some TV modes. If that happens, consider:\n\n• Disabling the \"Show Game Info\" " "option;\n• Disabling \"Overscan\" on the Pi configuration menu might help:\nRetroPie > " diff --git a/es-app/src/guis/GuiVideoScreensaverOptions.h b/es-app/src/guis/GuiVideoScreensaverOptions.h index 2690070dd..ecd269207 100644 --- a/es-app/src/guis/GuiVideoScreensaverOptions.h +++ b/es-app/src/guis/GuiVideoScreensaverOptions.h @@ -1,5 +1,5 @@ // -// GuiVideoScreensaverOptions.h +// GuiVideoScreensaverOptions.h // // User interface for the video screensaver options. // Submenu to GuiGeneralScreensaverOptions. diff --git a/es-app/src/scrapers/GamesDBJSONScraper.cpp b/es-app/src/scrapers/GamesDBJSONScraper.cpp index 140cd5aa9..e9458e07a 100644 --- a/es-app/src/scrapers/GamesDBJSONScraper.cpp +++ b/es-app/src/scrapers/GamesDBJSONScraper.cpp @@ -24,9 +24,9 @@ // able to have it throw in case of error with the following: //ifndef RAPIDJSON_ASSERT //#define RAPIDJSON_ASSERT(x) \ -// if (!(x)) { \ -// throw std::runtime_error("rapidjson internal assertion failure: " #x); \ -// } +// if (!(x)) { \ +// throw std::runtime_error("rapidjson internal assertion failure: " #x); \ +// } //#endif // RAPIDJSON_ASSERT #include diff --git a/es-core/src/HttpReq.cpp b/es-core/src/HttpReq.cpp index 40f4bc41b..49d031caf 100644 --- a/es-core/src/HttpReq.cpp +++ b/es-core/src/HttpReq.cpp @@ -44,11 +44,11 @@ bool HttpReq::isUrl(const std::string& str) std::string::npos || str.find("www.") != std::string::npos)); } -HttpReq::HttpReq(const std::string& url) : mStatus(REQ_IN_PROGRESS), mHandle(NULL) +HttpReq::HttpReq(const std::string& url) : mStatus(REQ_IN_PROGRESS), mHandle(nullptr) { mHandle = curl_easy_init(); - if (mHandle == NULL) { + if (mHandle == nullptr) { mStatus = REQ_IO_ERROR; onError("curl_easy_init failed"); return; @@ -147,7 +147,7 @@ HttpReq::Status HttpReq::status() if (msg->msg == CURLMSG_DONE) { HttpReq* req = s_requests[msg->easy_handle]; - if (req == NULL) { + if (req == nullptr) { LOG(LogError) << "Cannot find easy handle!"; continue; } diff --git a/es-core/src/Platform.cpp b/es-core/src/Platform.cpp index f2aae8e41..c98a48b6d 100644 --- a/es-core/src/Platform.cpp +++ b/es-core/src/Platform.cpp @@ -69,7 +69,7 @@ void touch(const std::string& filename) { #ifdef WIN32 FILE* fp = fopen(filename.c_str(), "ab+"); - if (fp != NULL) + if (fp != nullptr) fclose(fp); #else int fd = open(filename.c_str(), O_CREAT|O_WRONLY, 0644); diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index af26d9915..be5e60c00 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -11,11 +11,12 @@ #include "Log.h" #include "Scripting.h" #include "Platform.h" + #include #include #include -Settings* Settings::sInstance = NULL; +Settings* Settings::sInstance = nullptr; // These values are NOT saved to es_settings.cfg since they're not set via // the in-program settings menu. Most can be set using command-line arguments, @@ -59,7 +60,7 @@ Settings::Settings() Settings* Settings::getInstance() { - if (sInstance == NULL) + if (sInstance == nullptr) sInstance = new Settings(); return sInstance; diff --git a/es-core/src/Sound.cpp b/es-core/src/Sound.cpp index 0d68c94af..4f441b34c 100644 --- a/es-core/src/Sound.cpp +++ b/es-core/src/Sound.cpp @@ -82,7 +82,7 @@ bool NavigationSounds::isPlayingThemeNavigationSound(NavigationSoundsID soundID) Sound::Sound( const std::string & path) - : mSampleData(NULL), + : mSampleData(nullptr), mSamplePos(0), mSampleLength(0), playing(false) @@ -103,7 +103,7 @@ void Sound::loadFile(const std::string & path) void Sound::init() { - if(mSampleData != NULL) + if(mSampleData != nullptr) deinit(); if(mPath.empty()) diff --git a/es-core/src/components/AnimatedImageComponent.cpp b/es-core/src/components/AnimatedImageComponent.cpp index b0332fe65..16bc040f0 100644 --- a/es-core/src/components/AnimatedImageComponent.cpp +++ b/es-core/src/components/AnimatedImageComponent.cpp @@ -1,86 +1,90 @@ +// +// AnimatedImageComponent.cpp +// +// Creates animation from multiple images files. +// + #include "components/AnimatedImageComponent.h" #include "components/ImageComponent.h" #include "resources/ResourceManager.h" #include "Log.h" -AnimatedImageComponent::AnimatedImageComponent(Window* window) : GuiComponent(window), mEnabled(false) +AnimatedImageComponent::AnimatedImageComponent(Window* window) + : GuiComponent(window), mEnabled(false) { } void AnimatedImageComponent::load(const AnimationDef* def) { - mFrames.clear(); + mFrames.clear(); - assert(def->frameCount >= 1); + assert(def->frameCount >= 1); - for(size_t i = 0; i < def->frameCount; i++) - { - if(def->frames[i].path != NULL && !ResourceManager::getInstance()->fileExists(def->frames[i].path)) - { - LOG(LogError) << "Missing animation frame " << i << " (\"" << def->frames[i].path << "\")"; - continue; - } + for (size_t i = 0; i < def->frameCount; i++) { + if (def->frames[i].path != nullptr && + !ResourceManager::getInstance()->fileExists(def->frames[i].path)) { + LOG(LogError) << "Missing animation frame " << i << + " (\"" << def->frames[i].path << "\")"; + continue; + } - auto img = std::unique_ptr(new ImageComponent(mWindow)); - img->setResize(mSize.x(), mSize.y()); - img->setImage(std::string(def->frames[i].path), false); + auto img = std::unique_ptr(new ImageComponent(mWindow)); + img->setResize(mSize.x(), mSize.y()); + img->setImage(std::string(def->frames[i].path), false); - mFrames.push_back(ImageFrame(std::move(img), def->frames[i].time)); - } + mFrames.push_back(ImageFrame(std::move(img), def->frames[i].time)); + } - mLoop = def->loop; + mLoop = def->loop; - mCurrentFrame = 0; - mFrameAccumulator = 0; - mEnabled = true; + mCurrentFrame = 0; + mFrameAccumulator = 0; + mEnabled = true; } void AnimatedImageComponent::reset() { - mCurrentFrame = 0; - mFrameAccumulator = 0; + mCurrentFrame = 0; + mFrameAccumulator = 0; } void AnimatedImageComponent::onSizeChanged() { - for(auto it = mFrames.cbegin(); it != mFrames.cend(); it++) - { - it->first->setResize(mSize.x(), mSize.y()); - } + for (auto it = mFrames.cbegin(); it != mFrames.cend(); it++) { + it->first->setResize(mSize.x(), mSize.y()); + } } void AnimatedImageComponent::update(int deltaTime) { - if(!mEnabled || mFrames.size() == 0) - return; + if (!mEnabled || mFrames.size() == 0) + return; - mFrameAccumulator += deltaTime; + mFrameAccumulator += deltaTime; - while(mFrames.at(mCurrentFrame).second <= mFrameAccumulator) - { - mCurrentFrame++; + while (mFrames.at(mCurrentFrame).second <= mFrameAccumulator) { + mCurrentFrame++; - if(mCurrentFrame == (int)mFrames.size()) - { - if(mLoop) - { - // restart - mCurrentFrame = 0; - }else{ - // done, stop at last frame - mCurrentFrame--; - mEnabled = false; - break; - } - } + if (mCurrentFrame == (int)mFrames.size()) { + if (mLoop) { + // Restart. + mCurrentFrame = 0; + } + else { + // Done, stop at last frame. + mCurrentFrame--; + mEnabled = false; + break; + } + } - mFrameAccumulator -= mFrames.at(mCurrentFrame).second; - } + mFrameAccumulator -= mFrames.at(mCurrentFrame).second; + } } void AnimatedImageComponent::render(const Transform4x4f& trans) { - if(mFrames.size()) - mFrames.at(mCurrentFrame).first->render(getTransform() * trans); + if (mFrames.size()) + mFrames.at(mCurrentFrame).first->render(getTransform() * trans); } diff --git a/es-core/src/components/AnimatedImageComponent.h b/es-core/src/components/AnimatedImageComponent.h index c128ed30b..cf156b55c 100644 --- a/es-core/src/components/AnimatedImageComponent.h +++ b/es-core/src/components/AnimatedImageComponent.h @@ -1,3 +1,9 @@ +// +// AnimatedImageComponent.h +// +// Creates animation from multiple images files. +// + #pragma once #ifndef ES_CORE_COMPONENTS_ANIMATED_IMAGE_COMPONENT_H #define ES_CORE_COMPONENTS_ANIMATED_IMAGE_COMPONENT_H @@ -6,42 +12,40 @@ class ImageComponent; -struct AnimationFrame -{ - const char* path; - int time; +struct AnimationFrame { + const char* path; + int time; }; -struct AnimationDef -{ - AnimationFrame* frames; - size_t frameCount; - bool loop; +struct AnimationDef { + AnimationFrame* frames; + size_t frameCount; + bool loop; }; class AnimatedImageComponent : public GuiComponent { public: - AnimatedImageComponent(Window* window); + AnimatedImageComponent(Window* window); - void load(const AnimationDef* def); // no reference to def is kept after loading is complete + void load(const AnimationDef* def); // No reference to def is kept after loading is complete. - void reset(); // set to frame 0 + void reset(); // Set to frame 0. - void update(int deltaTime) override; - void render(const Transform4x4f& trans) override; + void update(int deltaTime) override; + void render(const Transform4x4f& trans) override; - void onSizeChanged() override; + void onSizeChanged() override; private: - typedef std::pair, int> ImageFrame; + typedef std::pair, int> ImageFrame; - std::vector mFrames; + std::vector mFrames; - bool mLoop; - bool mEnabled; - int mFrameAccumulator; - int mCurrentFrame; + bool mLoop; + bool mEnabled; + int mFrameAccumulator; + int mCurrentFrame; }; #endif // ES_CORE_COMPONENTS_ANIMATED_IMAGE_COMPONENT_H diff --git a/es-core/src/components/BusyComponent.cpp b/es-core/src/components/BusyComponent.cpp index ba7219d00..a17294581 100644 --- a/es-core/src/components/BusyComponent.cpp +++ b/es-core/src/components/BusyComponent.cpp @@ -1,56 +1,65 @@ +// +// BusyComponent.cpp +// +// Animated busy indicator. +// + #include "BusyComponent.h" #include "components/AnimatedImageComponent.h" #include "components/ImageComponent.h" #include "components/TextComponent.h" -// animation definition +// Animation definition. AnimationFrame BUSY_ANIMATION_FRAMES[] = { - {":/graphics/busy_0.svg", 300}, - {":/graphics/busy_1.svg", 300}, - {":/graphics/busy_2.svg", 300}, - {":/graphics/busy_3.svg", 300}, + {":/graphics/busy_0.svg", 300}, + {":/graphics/busy_1.svg", 300}, + {":/graphics/busy_2.svg", 300}, + {":/graphics/busy_3.svg", 300}, }; + const AnimationDef BUSY_ANIMATION_DEF = { BUSY_ANIMATION_FRAMES, 4, true }; -BusyComponent::BusyComponent(Window* window) : GuiComponent(window), - mBackground(window, ":/graphics/frame.png"), mGrid(window, Vector2i(5, 3)) +BusyComponent::BusyComponent(Window* window): GuiComponent(window), + mBackground(window, ":/graphics/frame.png"), mGrid(window, Vector2i(5, 3)) { - mAnimation = std::make_shared(mWindow); - mAnimation->load(&BUSY_ANIMATION_DEF); - mText = std::make_shared(mWindow, "WORKING...", Font::get(FONT_SIZE_MEDIUM), 0x777777FF); + mAnimation = std::make_shared(mWindow); + mAnimation->load(&BUSY_ANIMATION_DEF); + mText = std::make_shared(mWindow, "WORKING...", + Font::get(FONT_SIZE_MEDIUM), 0x777777FF); - // col 0 = animation, col 1 = spacer, col 2 = text - mGrid.setEntry(mAnimation, Vector2i(1, 1), false, true); - mGrid.setEntry(mText, Vector2i(3, 1), false, true); + // Col 0 = animation, col 1 = spacer, col 2 = text. + mGrid.setEntry(mAnimation, Vector2i(1, 1), false, true); + mGrid.setEntry(mText, Vector2i(3, 1), false, true); - addChild(&mBackground); - addChild(&mGrid); + addChild(&mBackground); + addChild(&mGrid); } void BusyComponent::onSizeChanged() { - mGrid.setSize(mSize); + mGrid.setSize(mSize); - if(mSize.x() == 0 || mSize.y() == 0) - return; + if (mSize.x() == 0 || mSize.y() == 0) + return; - const float middleSpacerWidth = 0.01f * Renderer::getScreenWidth(); - const float textHeight = mText->getFont()->getLetterHeight(); - mText->setSize(0, textHeight); - const float textWidth = mText->getSize().x() + 4; + const float middleSpacerWidth = 0.01f * Renderer::getScreenWidth(); + const float textHeight = mText->getFont()->getLetterHeight(); + mText->setSize(0, textHeight); + const float textWidth = mText->getSize().x() + 4; - mGrid.setColWidthPerc(1, textHeight / mSize.x()); // animation is square - mGrid.setColWidthPerc(2, middleSpacerWidth / mSize.x()); - mGrid.setColWidthPerc(3, textWidth / mSize.x()); + mGrid.setColWidthPerc(1, textHeight / mSize.x()); // Animation is square. + mGrid.setColWidthPerc(2, middleSpacerWidth / mSize.x()); + mGrid.setColWidthPerc(3, textWidth / mSize.x()); - mGrid.setRowHeightPerc(1, textHeight / mSize.y()); + mGrid.setRowHeightPerc(1, textHeight / mSize.y()); - mBackground.fitTo(Vector2f(mGrid.getColWidth(1) + mGrid.getColWidth(2) + mGrid.getColWidth(3), textHeight + 2), - mAnimation->getPosition(), Vector2f(0, 0)); + mBackground.fitTo(Vector2f(mGrid.getColWidth(1) + + mGrid.getColWidth(2) + mGrid.getColWidth(3), textHeight + 2), + mAnimation->getPosition(), Vector2f(0, 0)); } void BusyComponent::reset() { - //mAnimation->reset(); + //mAnimation->reset(); } diff --git a/es-core/src/components/BusyComponent.h b/es-core/src/components/BusyComponent.h index fe996a31c..9f9daca24 100644 --- a/es-core/src/components/BusyComponent.h +++ b/es-core/src/components/BusyComponent.h @@ -1,3 +1,9 @@ +// +// BusyComponent.h +// +// Animated busy indicator. +// + #pragma once #ifndef ES_CORE_COMPONENTS_BUSY_COMPONENT_H #define ES_CORE_COMPONENTS_BUSY_COMPONENT_H @@ -12,18 +18,18 @@ class TextComponent; class BusyComponent : public GuiComponent { public: - BusyComponent(Window* window); + BusyComponent(Window* window); - void onSizeChanged() override; + void onSizeChanged() override; - void reset(); // reset to frame 0 + void reset(); // Reset to frame 0. private: - NinePatchComponent mBackground; - ComponentGrid mGrid; + NinePatchComponent mBackground; + ComponentGrid mGrid; - std::shared_ptr mAnimation; - std::shared_ptr mText; + std::shared_ptr mAnimation; + std::shared_ptr mText; }; #endif // ES_CORE_COMPONENTS_BUSY_COMPONENT_H diff --git a/es-core/src/components/ButtonComponent.cpp b/es-core/src/components/ButtonComponent.cpp index daa888253..a52216398 100644 --- a/es-core/src/components/ButtonComponent.cpp +++ b/es-core/src/components/ButtonComponent.cpp @@ -1,119 +1,128 @@ +// +// ButtonComponent.cpp +// +// Basic on/off button. +// + #include "components/ButtonComponent.h" #include "resources/Font.h" #include "utils/StringUtil.h" -ButtonComponent::ButtonComponent(Window* window, const std::string& text, const std::string& helpText, const std::function& func) : GuiComponent(window), - mBox(window, ":/graphics/button.png"), - mFont(Font::get(FONT_SIZE_MEDIUM)), - mFocused(false), - mEnabled(true), - mTextColorFocused(0xFFFFFFFF), mTextColorUnfocused(0x777777FF) +ButtonComponent::ButtonComponent( + Window* window, const std::string& text, + const std::string& helpText, + const std::function& func) + : GuiComponent(window), + mBox(window, ":/graphics/button.png"), + mFont(Font::get(FONT_SIZE_MEDIUM)), + mFocused(false), + mEnabled(true), + mTextColorFocused(0xFFFFFFFF), mTextColorUnfocused(0x777777FF) { - setPressedFunc(func); - setText(text, helpText); - updateImage(); + setPressedFunc(func); + setText(text, helpText); + updateImage(); } void ButtonComponent::onSizeChanged() { - mBox.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32)); + mBox.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32)); } void ButtonComponent::setPressedFunc(std::function f) { - mPressedFunc = f; + mPressedFunc = f; } bool ButtonComponent::input(InputConfig* config, Input input) { - if(config->isMappedTo("a", input) && input.value != 0) - { - if(mPressedFunc && mEnabled) - mPressedFunc(); - return true; - } + if (config->isMappedTo("a", input) && input.value != 0) { + if (mPressedFunc && mEnabled) + mPressedFunc(); + return true; + } - return GuiComponent::input(config, input); + return GuiComponent::input(config, input); } void ButtonComponent::setText(const std::string& text, const std::string& helpText) { - mText = Utils::String::toUpper(text); - mHelpText = helpText; + mText = Utils::String::toUpper(text); + mHelpText = helpText; - mTextCache = std::unique_ptr(mFont->buildTextCache(mText, 0, 0, getCurTextColor())); + mTextCache = std::unique_ptr(mFont->buildTextCache(mText, 0, 0, getCurTextColor())); - float minWidth = mFont->sizeText("DELETE").x() + 12; - setSize(Math::max(mTextCache->metrics.size.x() + 12, minWidth), mTextCache->metrics.size.y()); + float minWidth = mFont->sizeText("DELETE").x() + 12; + setSize(Math::max(mTextCache->metrics.size.x() + 12, minWidth), mTextCache->metrics.size.y()); - updateHelpPrompts(); + updateHelpPrompts(); } void ButtonComponent::onFocusGained() { - mFocused = true; - updateImage(); + mFocused = true; + updateImage(); } void ButtonComponent::onFocusLost() { - mFocused = false; - updateImage(); + mFocused = false; + updateImage(); } void ButtonComponent::setEnabled(bool enabled) { - mEnabled = enabled; - updateImage(); + mEnabled = enabled; + updateImage(); } void ButtonComponent::updateImage() { - if(!mEnabled || !mPressedFunc) - { - mBox.setImagePath(":/graphics/button_filled.png"); - mBox.setCenterColor(0x770000FF); - mBox.setEdgeColor(0x770000FF); - return; - } + if (!mEnabled || !mPressedFunc) { + mBox.setImagePath(":/graphics/button_filled.png"); + mBox.setCenterColor(0x770000FF); + mBox.setEdgeColor(0x770000FF); + return; + } - mBox.setCenterColor(0xFFFFFFFF); - mBox.setEdgeColor(0xFFFFFFFF); - mBox.setImagePath(mFocused ? ":/graphics/button_filled.png" : ":/graphics/button.png"); + mBox.setCenterColor(0xFFFFFFFF); + mBox.setEdgeColor(0xFFFFFFFF); + mBox.setImagePath(mFocused ? ":/graphics/button_filled.png" : ":/graphics/button.png"); } void ButtonComponent::render(const Transform4x4f& parentTrans) { - Transform4x4f trans = parentTrans * getTransform(); + Transform4x4f trans = parentTrans * getTransform(); - mBox.render(trans); + mBox.render(trans); - if(mTextCache) - { - Vector3f centerOffset((mSize.x() - mTextCache->metrics.size.x()) / 2, (mSize.y() - mTextCache->metrics.size.y()) / 2, 0); - trans = trans.translate(centerOffset); + if (mTextCache) + { + Vector3f centerOffset((mSize.x() - mTextCache->metrics.size.x()) / 2, + (mSize.y() - mTextCache->metrics.size.y()) / 2, 0); + trans = trans.translate(centerOffset); - Renderer::setMatrix(trans); - mTextCache->setColor(getCurTextColor()); - mFont->renderTextCache(mTextCache.get()); - trans = trans.translate(-centerOffset); - } + Renderer::setMatrix(trans); + mTextCache->setColor(getCurTextColor()); + mFont->renderTextCache(mTextCache.get()); + trans = trans.translate(-centerOffset); + } - renderChildren(trans); + renderChildren(trans); } unsigned int ButtonComponent::getCurTextColor() const { - if(!mFocused) - return mTextColorUnfocused; - else - return mTextColorFocused; + if (!mFocused) + return mTextColorUnfocused; + else + return mTextColorFocused; } std::vector ButtonComponent::getHelpPrompts() { - std::vector prompts; - prompts.push_back(HelpPrompt("a", mHelpText.empty() ? mText.c_str() : mHelpText.c_str())); - return prompts; + std::vector prompts; + prompts.push_back(HelpPrompt("a", mHelpText.empty() ? mText.c_str() : mHelpText.c_str())); + return prompts; } diff --git a/es-core/src/components/ButtonComponent.h b/es-core/src/components/ButtonComponent.h index 2c25881f0..5ad5eb041 100644 --- a/es-core/src/components/ButtonComponent.h +++ b/es-core/src/components/ButtonComponent.h @@ -1,3 +1,9 @@ +// +// ButtonComponent.h +// +// Basic on/off button. +// + #pragma once #ifndef ES_CORE_COMPONENTS_BUTTON_COMPONENT_H #define ES_CORE_COMPONENTS_BUTTON_COMPONENT_H @@ -10,42 +16,42 @@ class TextCache; class ButtonComponent : public GuiComponent { public: - ButtonComponent(Window* window, const std::string& text = "", const std::string& helpText = "", const std::function& func = nullptr); + ButtonComponent(Window* window, const std::string& text = "", + const std::string& helpText = "", const std::function& func = nullptr); - void setPressedFunc(std::function f); + void setPressedFunc(std::function f); + void setEnabled(bool enable); - void setEnabled(bool enable); + bool input(InputConfig* config, Input input) override; + void render(const Transform4x4f& parentTrans) override; - bool input(InputConfig* config, Input input) override; - void render(const Transform4x4f& parentTrans) override; + void setText(const std::string& text, const std::string& helpText); - void setText(const std::string& text, const std::string& helpText); + inline const std::string& getText() const { return mText; }; + inline const std::function& getPressedFunc() const { return mPressedFunc; }; - inline const std::string& getText() const { return mText; }; - inline const std::function& getPressedFunc() const { return mPressedFunc; }; + void onSizeChanged() override; + void onFocusGained() override; + void onFocusLost() override; - void onSizeChanged() override; - void onFocusGained() override; - void onFocusLost() override; - - virtual std::vector getHelpPrompts() override; + virtual std::vector getHelpPrompts() override; private: - std::shared_ptr mFont; - std::function mPressedFunc; + std::shared_ptr mFont; + std::function mPressedFunc; - bool mFocused; - bool mEnabled; - unsigned int mTextColorFocused; - unsigned int mTextColorUnfocused; + bool mFocused; + bool mEnabled; + unsigned int mTextColorFocused; + unsigned int mTextColorUnfocused; - unsigned int getCurTextColor() const; - void updateImage(); + unsigned int getCurTextColor() const; + void updateImage(); - std::string mText; - std::string mHelpText; - std::unique_ptr mTextCache; - NinePatchComponent mBox; + std::string mText; + std::string mHelpText; + std::unique_ptr mTextCache; + NinePatchComponent mBox; }; #endif // ES_CORE_COMPONENTS_BUTTON_COMPONENT_H diff --git a/es-core/src/components/ComponentGrid.cpp b/es-core/src/components/ComponentGrid.cpp index a04263816..cdebcd049 100644 --- a/es-core/src/components/ComponentGrid.cpp +++ b/es-core/src/components/ComponentGrid.cpp @@ -100,7 +100,7 @@ void ComponentGrid::setEntry( { assert(pos.x() >= 0 && pos.x() < mGridSize.x() && pos.y() >= 0 && pos.y() < mGridSize.y()); assert(comp != nullptr); - assert(comp->getParent() == NULL); + assert(comp->getParent() == nullptr); GridEntry entry(pos, size, comp, canFocus, resize, updateType, border); mCells.push_back(entry); @@ -223,7 +223,7 @@ const ComponentGrid::GridEntry* ComponentGrid::getCellAt(int x, int y) const return &(*it); } - return NULL; + return nullptr; } bool ComponentGrid::input(InputConfig* config, Input input) @@ -327,7 +327,7 @@ void ComponentGrid::onFocusGained() bool ComponentGrid::cursorValid() { const GridEntry* e = getCellAt(mCursor); - return (e != NULL && e->canFocus); + return (e != nullptr && e->canFocus); } void ComponentGrid::update(int deltaTime) @@ -359,7 +359,7 @@ void ComponentGrid::render(const Transform4x4f& parentTrans) void ComponentGrid::textInput(const char* text) { const GridEntry* selectedEntry = getCellAt(mCursor); - if (selectedEntry != NULL && selectedEntry->canFocus) + if (selectedEntry != nullptr && selectedEntry->canFocus) selectedEntry->component->textInput(text); } diff --git a/es-core/src/components/ComponentGrid.h b/es-core/src/components/ComponentGrid.h index 52608f6e2..02d1b7436 100644 --- a/es-core/src/components/ComponentGrid.h +++ b/es-core/src/components/ComponentGrid.h @@ -104,7 +104,7 @@ private: operator bool() const { - return component != NULL; + return component != nullptr; } }; diff --git a/es-core/src/components/ComponentList.cpp b/es-core/src/components/ComponentList.cpp index b67fab4de..0df4c961c 100644 --- a/es-core/src/components/ComponentList.cpp +++ b/es-core/src/components/ComponentList.cpp @@ -20,7 +20,7 @@ void ComponentList::addRow(const ComponentListRow& row, bool setCursorHere) { IList::Entry e; e.name = ""; - e.object = NULL; + e.object = nullptr; e.data = row; this->add(e); diff --git a/es-core/src/components/GridTileComponent.cpp b/es-core/src/components/GridTileComponent.cpp index d6f5312a0..5d02aa273 100644 --- a/es-core/src/components/GridTileComponent.cpp +++ b/es-core/src/components/GridTileComponent.cpp @@ -1,3 +1,9 @@ +// +// GridTileComponent.cpp +// +// X*Y grid. +// + #include "GridTileComponent.h" #include "animations/LambdaAnimation.h" @@ -6,318 +12,310 @@ GridTileComponent::GridTileComponent(Window* window) : GuiComponent(window), mBackground(window) { - mDefaultProperties.mSize = getDefaultTileSize(); - mDefaultProperties.mPadding = Vector2f(16.0f, 16.0f); - mDefaultProperties.mImageColor = 0xAAAAAABB; - mDefaultProperties.mBackgroundImage = ":/graphics/frame.png"; - mDefaultProperties.mBackgroundCornerSize = Vector2f(16 ,16); - mDefaultProperties.mBackgroundCenterColor = 0xAAAAEEFF; - mDefaultProperties.mBackgroundEdgeColor = 0xAAAAEEFF; + mDefaultProperties.mSize = getDefaultTileSize(); + mDefaultProperties.mPadding = Vector2f(16.0f, 16.0f); + mDefaultProperties.mImageColor = 0xAAAAAABB; + mDefaultProperties.mBackgroundImage = ":/graphics/frame.png"; + mDefaultProperties.mBackgroundCornerSize = Vector2f(16 ,16); + mDefaultProperties.mBackgroundCenterColor = 0xAAAAEEFF; + mDefaultProperties.mBackgroundEdgeColor = 0xAAAAEEFF; - mSelectedProperties.mSize = getSelectedTileSize(); - mSelectedProperties.mPadding = mDefaultProperties.mPadding; - mSelectedProperties.mImageColor = 0xFFFFFFFF; - mSelectedProperties.mBackgroundImage = mDefaultProperties.mBackgroundImage; - mSelectedProperties.mBackgroundCornerSize = mDefaultProperties.mBackgroundCornerSize; - mSelectedProperties.mBackgroundCenterColor = 0xFFFFFFFF; - mSelectedProperties.mBackgroundEdgeColor = 0xFFFFFFFF; + mSelectedProperties.mSize = getSelectedTileSize(); + mSelectedProperties.mPadding = mDefaultProperties.mPadding; + mSelectedProperties.mImageColor = 0xFFFFFFFF; + mSelectedProperties.mBackgroundImage = mDefaultProperties.mBackgroundImage; + mSelectedProperties.mBackgroundCornerSize = mDefaultProperties.mBackgroundCornerSize; + mSelectedProperties.mBackgroundCenterColor = 0xFFFFFFFF; + mSelectedProperties.mBackgroundEdgeColor = 0xFFFFFFFF; - mImage = std::make_shared(mWindow); - mImage->setOrigin(0.5f, 0.5f); + mImage = std::make_shared(mWindow); + mImage->setOrigin(0.5f, 0.5f); - mBackground.setOrigin(0.5f, 0.5f); + mBackground.setOrigin(0.5f, 0.5f); - addChild(&mBackground); - addChild(&(*mImage)); + addChild(&mBackground); + addChild(&(*mImage)); - mSelectedZoomPercent = 0; + mSelectedZoomPercent = 0; - setSelected(false, false); - setVisible(true); + setSelected(false, false); + setVisible(true); } void GridTileComponent::render(const Transform4x4f& parentTrans) { - Transform4x4f trans = getTransform() * parentTrans; + Transform4x4f trans = getTransform() * parentTrans; - if (mVisible) - renderChildren(trans); + if (mVisible) + renderChildren(trans); } -// Update all the tile properties to the new status (selected or default) +// Update all the tile properties to the new status (selected or default). void GridTileComponent::update(int deltaTime) { - GuiComponent::update(deltaTime); + GuiComponent::update(deltaTime); - calcCurrentProperties(); + calcCurrentProperties(); - mBackground.setImagePath(mCurrentProperties.mBackgroundImage); + mBackground.setImagePath(mCurrentProperties.mBackgroundImage); - mImage->setColorShift(mCurrentProperties.mImageColor); - mBackground.setCenterColor(mCurrentProperties.mBackgroundCenterColor); - mBackground.setEdgeColor(mCurrentProperties.mBackgroundEdgeColor); + mImage->setColorShift(mCurrentProperties.mImageColor); + mBackground.setCenterColor(mCurrentProperties.mBackgroundCenterColor); + mBackground.setEdgeColor(mCurrentProperties.mBackgroundEdgeColor); - resize(); + resize(); } void applyThemeToProperties(const ThemeData::ThemeElement* elem, GridTileProperties* properties) { - Vector2f screen = Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); + Vector2f screen = Vector2f((float)Renderer::getScreenWidth(), + (float)Renderer::getScreenHeight()); - if (elem->has("size")) - properties->mSize = elem->get("size") * screen; + if (elem->has("size")) + properties->mSize = elem->get("size") * screen; - if (elem->has("padding")) - properties->mPadding = elem->get("padding"); + if (elem->has("padding")) + properties->mPadding = elem->get("padding"); - if (elem->has("imageColor")) - properties->mImageColor = elem->get("imageColor"); + if (elem->has("imageColor")) + properties->mImageColor = elem->get("imageColor"); - if (elem->has("backgroundImage")) - properties->mBackgroundImage = elem->get("backgroundImage"); + if (elem->has("backgroundImage")) + properties->mBackgroundImage = elem->get("backgroundImage"); - if (elem->has("backgroundCornerSize")) - properties->mBackgroundCornerSize = elem->get("backgroundCornerSize"); + if (elem->has("backgroundCornerSize")) + properties->mBackgroundCornerSize = elem->get("backgroundCornerSize"); - if (elem->has("backgroundColor")) - { - properties->mBackgroundCenterColor = elem->get("backgroundColor"); - properties->mBackgroundEdgeColor = elem->get("backgroundColor"); - } + if (elem->has("backgroundColor")) { + properties->mBackgroundCenterColor = elem->get("backgroundColor"); + properties->mBackgroundEdgeColor = elem->get("backgroundColor"); + } - if (elem->has("backgroundCenterColor")) - properties->mBackgroundCenterColor = elem->get("backgroundCenterColor"); + if (elem->has("backgroundCenterColor")) + properties->mBackgroundCenterColor = elem->get("backgroundCenterColor"); - if (elem->has("backgroundEdgeColor")) - properties->mBackgroundEdgeColor = elem->get("backgroundEdgeColor"); + if (elem->has("backgroundEdgeColor")) + properties->mBackgroundEdgeColor = elem->get("backgroundEdgeColor"); } -void GridTileComponent::applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& /*element*/, unsigned int /*properties*/) +void GridTileComponent::applyTheme(const std::shared_ptr& theme, + const std::string& view, const std::string& /*element*/, unsigned int /*properties*/) { - Vector2f screen = Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); + Vector2f screen = Vector2f((float)Renderer::getScreenWidth(), + (float)Renderer::getScreenHeight()); - // Apply theme to the default gridtile - const ThemeData::ThemeElement* elem = theme->getElement(view, "default", "gridtile"); - if (elem) - applyThemeToProperties(elem, &mDefaultProperties); + // Apply theme to the default gridtile. + const ThemeData::ThemeElement* elem = theme->getElement(view, "default", "gridtile"); + if (elem) + applyThemeToProperties(elem, &mDefaultProperties); - // Apply theme to the selected gridtile - // NOTE that some of the default gridtile properties influence on the selected gridtile properties - // See THEMES.md for more informations - elem = theme->getElement(view, "selected", "gridtile"); + // Apply theme to the selected gridtile. Note that some of the default gridtile + // properties have influence on the selected gridtile properties. + // See THEMES.md for more informations. + elem = theme->getElement(view, "selected", "gridtile"); - mSelectedProperties.mSize = getSelectedTileSize(); - mSelectedProperties.mPadding = mDefaultProperties.mPadding; - mSelectedProperties.mBackgroundImage = mDefaultProperties.mBackgroundImage; - mSelectedProperties.mBackgroundCornerSize = mDefaultProperties.mBackgroundCornerSize; + mSelectedProperties.mSize = getSelectedTileSize(); + mSelectedProperties.mPadding = mDefaultProperties.mPadding; + mSelectedProperties.mBackgroundImage = mDefaultProperties.mBackgroundImage; + mSelectedProperties.mBackgroundCornerSize = mDefaultProperties.mBackgroundCornerSize; - if (elem) - applyThemeToProperties(elem, &mSelectedProperties); + if (elem) + applyThemeToProperties(elem, &mSelectedProperties); } -// Made this a static function because the ImageGridComponent need to know the default tile size -// to calculate the grid dimension before it instantiate the GridTileComponents +// Made this a static function because the ImageGridComponent needs to know the default tile +// max size to calculate the grid dimension before it instantiates the GridTileComponents. Vector2f GridTileComponent::getDefaultTileSize() { - Vector2f screen = Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); + Vector2f screen = Vector2f((float)Renderer::getScreenWidth(), + (float)Renderer::getScreenHeight()); - return screen * 0.22f; + return screen * 0.22f; } Vector2f GridTileComponent::getSelectedTileSize() const { - return mDefaultProperties.mSize * 1.2f; + return mDefaultProperties.mSize * 1.2f; } bool GridTileComponent::isSelected() const { - return mSelected; + return mSelected; } void GridTileComponent::reset() { - setImage(""); + setImage(""); } void GridTileComponent::setImage(const std::string& path) { - mImage->setImage(path); + mImage->setImage(path); - // Resize now to prevent flickering images when scrolling - resize(); + // Resize now to prevent flickering images when scrolling. + resize(); } void GridTileComponent::setImage(const std::shared_ptr& texture) { - mImage->setImage(texture); + mImage->setImage(texture); - // Resize now to prevent flickering images when scrolling - resize(); + // Resize now to prevent flickering images when scrolling. + resize(); } -void GridTileComponent::setSelected(bool selected, bool allowAnimation, Vector3f* pPosition, bool force) +void GridTileComponent::setSelected(bool selected, bool allowAnimation, + Vector3f* pPosition, bool force) { - if (mSelected == selected && !force) - { - return; - } + if (mSelected == selected && !force) + return; - mSelected = selected; + mSelected = selected; - if (selected) - { - if (pPosition == NULL || !allowAnimation) - { - cancelAnimation(3); + if (selected) { + if (pPosition == nullptr || !allowAnimation) { + cancelAnimation(3); - this->setSelectedZoom(1); - mAnimPosition = Vector3f(0, 0, 0); + this->setSelectedZoom(1); + mAnimPosition = Vector3f(0, 0, 0); - resize(); - } - else - { - mAnimPosition = Vector3f(pPosition->x(), pPosition->y(), pPosition->z()); + resize(); + } + else { + mAnimPosition = Vector3f(pPosition->x(), pPosition->y(), pPosition->z()); - auto func = [this](float t) - { - t -= 1; // cubic ease out - float pct = Math::lerp(0, 1, t*t*t + 1); + auto func = [this](float t) { + t -= 1; // Cubic ease out. + float pct = Math::lerp(0, 1, t*t*t + 1); + this->setSelectedZoom(pct); + }; - this->setSelectedZoom(pct); - }; + cancelAnimation(3); + setAnimation(new LambdaAnimation(func, 250), 0, [this] { + this->setSelectedZoom(1); + mAnimPosition = Vector3f(0, 0, 0); + }, false, 3); + } + } + // If (!selected). + else { + if (!allowAnimation) { + cancelAnimation(3); + this->setSelectedZoom(0); - cancelAnimation(3); - setAnimation(new LambdaAnimation(func, 250), 0, [this] { - this->setSelectedZoom(1); - mAnimPosition = Vector3f(0, 0, 0); - }, false, 3); - } - } - else // if (!selected) - { - if (!allowAnimation) - { - cancelAnimation(3); - this->setSelectedZoom(0); + resize(); + } + else { + this->setSelectedZoom(1); - resize(); - } - else - { - this->setSelectedZoom(1); + auto func = [this](float t) { + t -= 1; // Cubic ease out. + float pct = Math::lerp(0, 1, t*t*t + 1); + this->setSelectedZoom(1.0 - pct); + }; - auto func = [this](float t) - { - t -= 1; // cubic ease out - float pct = Math::lerp(0, 1, t*t*t + 1); - this->setSelectedZoom(1.0 - pct); - }; - - cancelAnimation(3); - setAnimation(new LambdaAnimation(func, 250), 0, [this] { - this->setSelectedZoom(0); - }, false, 3); - } - } + cancelAnimation(3); + setAnimation(new LambdaAnimation(func, 250), 0, [this] { + this->setSelectedZoom(0); + }, false, 3); + } + } } void GridTileComponent::setSelectedZoom(float percent) { - if (mSelectedZoomPercent == percent) - return; + if (mSelectedZoomPercent == percent) + return; - mSelectedZoomPercent = percent; - resize(); + mSelectedZoomPercent = percent; + resize(); } void GridTileComponent::setVisible(bool visible) { - mVisible = visible; + mVisible = visible; } void GridTileComponent::resize() { - calcCurrentProperties(); + calcCurrentProperties(); - mImage->setMaxSize(mCurrentProperties.mSize - mCurrentProperties.mPadding * 2); - mBackground.setCornerSize(mCurrentProperties.mBackgroundCornerSize); - mBackground.fitTo(mCurrentProperties.mSize - mBackground.getCornerSize() * 2); + mImage->setMaxSize(mCurrentProperties.mSize - mCurrentProperties.mPadding * 2); + mBackground.setCornerSize(mCurrentProperties.mBackgroundCornerSize); + mBackground.fitTo(mCurrentProperties.mSize - mBackground.getCornerSize() * 2); } unsigned int mixColors(unsigned int first, unsigned int second, float percent) { - unsigned char alpha0 = (first >> 24) & 0xFF; - unsigned char blue0 = (first >> 16) & 0xFF; - unsigned char green0 = (first >> 8) & 0xFF; - unsigned char red0 = first & 0xFF; + unsigned char alpha0 = (first >> 24) & 0xFF; + unsigned char blue0 = (first >> 16) & 0xFF; + unsigned char green0 = (first >> 8) & 0xFF; + unsigned char red0 = first & 0xFF; - unsigned char alpha1 = (second >> 24) & 0xFF; - unsigned char blue1 = (second >> 16) & 0xFF; - unsigned char green1 = (second >> 8) & 0xFF; - unsigned char red1 = second & 0xFF; + unsigned char alpha1 = (second >> 24) & 0xFF; + unsigned char blue1 = (second >> 16) & 0xFF; + unsigned char green1 = (second >> 8) & 0xFF; + unsigned char red1 = second & 0xFF; - unsigned char alpha = (unsigned char)(alpha0 * (1.0 - percent) + alpha1 * percent); - unsigned char blue = (unsigned char)(blue0 * (1.0 - percent) + blue1 * percent); - unsigned char green = (unsigned char)(green0 * (1.0 - percent) + green1 * percent); - unsigned char red = (unsigned char)(red0 * (1.0 - percent) + red1 * percent); + unsigned char alpha = (unsigned char)(alpha0 * (1.0 - percent) + alpha1 * percent); + unsigned char blue = (unsigned char)(blue0 * (1.0 - percent) + blue1 * percent); + unsigned char green = (unsigned char)(green0 * (1.0 - percent) + green1 * percent); + unsigned char red = (unsigned char)(red0 * (1.0 - percent) + red1 * percent); - return (alpha << 24) | (blue << 16) | (green << 8) | red; + return (alpha << 24) | (blue << 16) | (green << 8) | red; } void GridTileComponent::calcCurrentProperties() { - mCurrentProperties = mSelected ? mSelectedProperties : mDefaultProperties; + mCurrentProperties = mSelected ? mSelectedProperties : mDefaultProperties; - float zoomPercentInverse = 1.0 - mSelectedZoomPercent; + float zoomPercentInverse = 1.0 - mSelectedZoomPercent; - if (mSelectedZoomPercent != 0.0f && mSelectedZoomPercent != 1.0f) { - if (mDefaultProperties.mSize != mSelectedProperties.mSize) { - mCurrentProperties.mSize = mDefaultProperties.mSize * zoomPercentInverse + mSelectedProperties.mSize * mSelectedZoomPercent; - } + if (mSelectedZoomPercent != 0.0f && mSelectedZoomPercent != 1.0f) { + if (mDefaultProperties.mSize != mSelectedProperties.mSize) + mCurrentProperties.mSize = mDefaultProperties.mSize * zoomPercentInverse + + mSelectedProperties.mSize * mSelectedZoomPercent; - if (mDefaultProperties.mPadding != mSelectedProperties.mPadding) - { - mCurrentProperties.mPadding = mDefaultProperties.mPadding * zoomPercentInverse + mSelectedProperties.mPadding * mSelectedZoomPercent; - } + if (mDefaultProperties.mPadding != mSelectedProperties.mPadding) + mCurrentProperties.mPadding = mDefaultProperties.mPadding * zoomPercentInverse + + mSelectedProperties.mPadding * mSelectedZoomPercent; - if (mDefaultProperties.mImageColor != mSelectedProperties.mImageColor) - { - mCurrentProperties.mImageColor = mixColors(mDefaultProperties.mImageColor, mSelectedProperties.mImageColor, mSelectedZoomPercent); - } + if (mDefaultProperties.mImageColor != mSelectedProperties.mImageColor) + mCurrentProperties.mImageColor = mixColors(mDefaultProperties.mImageColor, + mSelectedProperties.mImageColor, mSelectedZoomPercent); - if (mDefaultProperties.mBackgroundCornerSize != mSelectedProperties.mBackgroundCornerSize) - { - mCurrentProperties.mBackgroundCornerSize = mDefaultProperties.mBackgroundCornerSize * zoomPercentInverse + mSelectedProperties.mBackgroundCornerSize * mSelectedZoomPercent; - } + if (mDefaultProperties.mBackgroundCornerSize != mSelectedProperties.mBackgroundCornerSize) + mCurrentProperties.mBackgroundCornerSize = mDefaultProperties.mBackgroundCornerSize * + zoomPercentInverse + mSelectedProperties.mBackgroundCornerSize * + mSelectedZoomPercent; - if (mDefaultProperties.mBackgroundCenterColor != mSelectedProperties.mBackgroundCenterColor) - { - mCurrentProperties.mBackgroundCenterColor = mixColors(mDefaultProperties.mBackgroundCenterColor, mSelectedProperties.mBackgroundCenterColor, mSelectedZoomPercent); - } + if (mDefaultProperties.mBackgroundCenterColor != mSelectedProperties.mBackgroundCenterColor) + mCurrentProperties.mBackgroundCenterColor = + mixColors(mDefaultProperties.mBackgroundCenterColor, + mSelectedProperties.mBackgroundCenterColor, mSelectedZoomPercent); - if (mDefaultProperties.mBackgroundEdgeColor != mSelectedProperties.mBackgroundEdgeColor) - { - mCurrentProperties.mBackgroundEdgeColor = mixColors(mDefaultProperties.mBackgroundEdgeColor, mSelectedProperties.mBackgroundEdgeColor, mSelectedZoomPercent); - } - } + if (mDefaultProperties.mBackgroundEdgeColor != mSelectedProperties.mBackgroundEdgeColor) + mCurrentProperties.mBackgroundEdgeColor = + mixColors(mDefaultProperties.mBackgroundEdgeColor, + mSelectedProperties.mBackgroundEdgeColor, mSelectedZoomPercent); + } } Vector3f GridTileComponent::getBackgroundPosition() { - return mBackground.getPosition() + mPosition; + return mBackground.getPosition() + mPosition; } std::shared_ptr GridTileComponent::getTexture() { - if (mImage != nullptr) - return mImage->getTexture(); + if (mImage != nullptr) + return mImage->getTexture(); - return nullptr; + return nullptr; }; void GridTileComponent::forceSize(Vector2f size, float selectedZoom) { - mDefaultProperties.mSize = size; - mSelectedProperties.mSize = size * selectedZoom; + mDefaultProperties.mSize = size; + mSelectedProperties.mSize = size * selectedZoom; } diff --git a/es-core/src/components/GridTileComponent.h b/es-core/src/components/GridTileComponent.h index 4fa11216d..2d97a4f59 100644 --- a/es-core/src/components/GridTileComponent.h +++ b/es-core/src/components/GridTileComponent.h @@ -1,3 +1,9 @@ +// +// GridTileComponent.h +// +// X*Y grid. +// + #pragma once #ifndef ES_CORE_COMPONENTS_GRID_TILE_COMPONENT_H #define ES_CORE_COMPONENTS_GRID_TILE_COMPONENT_H @@ -5,63 +11,64 @@ #include "NinePatchComponent.h" #include "ImageComponent.h" -struct GridTileProperties -{ - Vector2f mSize; - Vector2f mPadding; - unsigned int mImageColor; - std::string mBackgroundImage; - Vector2f mBackgroundCornerSize; - unsigned int mBackgroundCenterColor; - unsigned int mBackgroundEdgeColor; +struct GridTileProperties { + Vector2f mSize; + Vector2f mPadding; + unsigned int mImageColor; + std::string mBackgroundImage; + Vector2f mBackgroundCornerSize; + unsigned int mBackgroundCenterColor; + unsigned int mBackgroundEdgeColor; }; class GridTileComponent : public GuiComponent { public: - GridTileComponent(Window* window); + GridTileComponent(Window* window); - void render(const Transform4x4f& parentTrans) override; - virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) override; + void render(const Transform4x4f& parentTrans) override; + virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, + const std::string& element, unsigned int properties) override; - // Made this a static function because the ImageGridComponent need to know the default tile max size - // to calculate the grid dimension before it instantiate the GridTileComponents - static Vector2f getDefaultTileSize(); - Vector2f getSelectedTileSize() const; - bool isSelected() const; + // Made this a static function because the ImageGridComponent needs to know the default tile + // max size to calculate the grid dimension before it instantiates the GridTileComponents. + static Vector2f getDefaultTileSize(); + Vector2f getSelectedTileSize() const; + bool isSelected() const; - void reset(); + void reset(); - void setImage(const std::string& path); - void setImage(const std::shared_ptr& texture); - void setSelected(bool selected, bool allowAnimation = true, Vector3f* pPosition = NULL, bool force=false); - void setVisible(bool visible); + void setImage(const std::string& path); + void setImage(const std::shared_ptr& texture); + void setSelected(bool selected, bool allowAnimation = true, + Vector3f* pPosition = nullptr, bool force=false); + void setVisible(bool visible); - void forceSize(Vector2f size, float selectedZoom); + void forceSize(Vector2f size, float selectedZoom); - Vector3f getBackgroundPosition(); + Vector3f getBackgroundPosition(); - virtual void update(int deltaTime) override; + virtual void update(int deltaTime) override; - std::shared_ptr getTexture(); + std::shared_ptr getTexture(); private: - void resize(); - void calcCurrentProperties(); - void setSelectedZoom(float percent); + void resize(); + void calcCurrentProperties(); + void setSelectedZoom(float percent); - std::shared_ptr mImage; - NinePatchComponent mBackground; + std::shared_ptr mImage; + NinePatchComponent mBackground; - GridTileProperties mDefaultProperties; - GridTileProperties mSelectedProperties; - GridTileProperties mCurrentProperties; + GridTileProperties mDefaultProperties; + GridTileProperties mSelectedProperties; + GridTileProperties mCurrentProperties; - float mSelectedZoomPercent; - bool mSelected; - bool mVisible; + float mSelectedZoomPercent; + bool mSelected; + bool mVisible; - Vector3f mAnimPosition; + Vector3f mAnimPosition; }; #endif // ES_CORE_COMPONENTS_GRID_TILE_COMPONENT_H diff --git a/es-core/src/components/HelpComponent.cpp b/es-core/src/components/HelpComponent.cpp index 1d7ef5529..ce43e3584 100644 --- a/es-core/src/components/HelpComponent.cpp +++ b/es-core/src/components/HelpComponent.cpp @@ -1,3 +1,9 @@ +// +// HelpComponent.cpp +// +// Help information in icon and text pairs. +// + #include "components/HelpComponent.h" #include "components/ComponentGrid.h" @@ -8,25 +14,25 @@ #include "Log.h" #include "Settings.h" -#define OFFSET_X 12 // move the entire thing right by this amount (px) -#define OFFSET_Y 12 // move the entire thing up by this amount (px) +#define OFFSET_X 12 // Move the entire thing right by this amount (px). +#define OFFSET_Y 12 // Move the entire thing up by this amount (px). -#define ICON_TEXT_SPACING 8 // space between [icon] and [text] (px) -#define ENTRY_SPACING 16 // space between [text] and next [icon] (px) +#define ICON_TEXT_SPACING 8 // Space between [icon] and [text] (px). +#define ENTRY_SPACING 16 // Space between [text] and next [icon] (px). static const std::map ICON_PATH_MAP { - { "up/down", ":/help/dpad_updown.svg" }, - { "left/right", ":/help/dpad_leftright.svg" }, - { "up/down/left/right", ":/help/dpad_all.svg" }, - { "a", ":/help/button_a.svg" }, - { "b", ":/help/button_b.svg" }, - { "x", ":/help/button_x.svg" }, - { "y", ":/help/button_y.svg" }, - { "l", ":/help/button_l.svg" }, - { "r", ":/help/button_r.svg" }, - { "lr", ":/help/button_lr.svg" }, - { "start", ":/help/button_start.svg" }, - { "select", ":/help/button_select.svg" } + { "up/down", ":/help/dpad_updown.svg" }, + { "left/right", ":/help/dpad_leftright.svg" }, + { "up/down/left/right", ":/help/dpad_all.svg" }, + { "a", ":/help/button_a.svg" }, + { "b", ":/help/button_b.svg" }, + { "x", ":/help/button_x.svg" }, + { "y", ":/help/button_y.svg" }, + { "l", ":/help/button_l.svg" }, + { "r", ":/help/button_r.svg" }, + { "lr", ":/help/button_lr.svg" }, + { "start", ":/help/button_start.svg" }, + { "select", ":/help/button_select.svg" } }; HelpComponent::HelpComponent(Window* window) : GuiComponent(window) @@ -35,108 +41,106 @@ HelpComponent::HelpComponent(Window* window) : GuiComponent(window) void HelpComponent::clearPrompts() { - mPrompts.clear(); - updateGrid(); + mPrompts.clear(); + updateGrid(); } void HelpComponent::setPrompts(const std::vector& prompts) { - mPrompts = prompts; - updateGrid(); + mPrompts = prompts; + updateGrid(); } void HelpComponent::setStyle(const HelpStyle& style) { - mStyle = style; - updateGrid(); + mStyle = style; + updateGrid(); } void HelpComponent::updateGrid() { - if(!Settings::getInstance()->getBool("ShowHelpPrompts") || mPrompts.empty()) - { - mGrid.reset(); - return; - } + if (!Settings::getInstance()->getBool("ShowHelpPrompts") || mPrompts.empty()) { + mGrid.reset(); + return; + } - std::shared_ptr& font = mStyle.font; + std::shared_ptr& font = mStyle.font; - mGrid = std::make_shared(mWindow, Vector2i((int)mPrompts.size() * 4, 1)); - // [icon] [spacer1] [text] [spacer2] + mGrid = std::make_shared(mWindow, Vector2i((int)mPrompts.size() * 4, 1)); - std::vector< std::shared_ptr > icons; - std::vector< std::shared_ptr > labels; + // [icon] [spacer1] [text] [spacer2] - float width = 0; - const float height = Math::round(font->getLetterHeight() * 1.25f); - for(auto it = mPrompts.cbegin(); it != mPrompts.cend(); it++) - { - auto icon = std::make_shared(mWindow); - icon->setImage(getIconTexture(it->first.c_str())); - icon->setColorShift(mStyle.iconColor); - icon->setResize(0, height); - icons.push_back(icon); + std::vector< std::shared_ptr > icons; + std::vector< std::shared_ptr > labels; - auto lbl = std::make_shared(mWindow, Utils::String::toUpper(it->second), font, mStyle.textColor); - labels.push_back(lbl); + float width = 0; + const float height = Math::round(font->getLetterHeight() * 1.25f); - width += icon->getSize().x() + lbl->getSize().x() + ICON_TEXT_SPACING + ENTRY_SPACING; - } + for (auto it = mPrompts.cbegin(); it != mPrompts.cend(); it++) { + auto icon = std::make_shared(mWindow); + icon->setImage(getIconTexture(it->first.c_str())); + icon->setColorShift(mStyle.iconColor); + icon->setResize(0, height); + icons.push_back(icon); - mGrid->setSize(width, height); - for(unsigned int i = 0; i < icons.size(); i++) - { - const int col = i*4; - mGrid->setColWidthPerc(col, icons.at(i)->getSize().x() / width); - mGrid->setColWidthPerc(col + 1, ICON_TEXT_SPACING / width); - mGrid->setColWidthPerc(col + 2, labels.at(i)->getSize().x() / width); + auto lbl = std::make_shared(mWindow, + Utils::String::toUpper(it->second), font, mStyle.textColor); + labels.push_back(lbl); - mGrid->setEntry(icons.at(i), Vector2i(col, 0), false, false); - mGrid->setEntry(labels.at(i), Vector2i(col + 2, 0), false, false); - } + width += icon->getSize().x() + lbl->getSize().x() + ICON_TEXT_SPACING + ENTRY_SPACING; + } - mGrid->setPosition(Vector3f(mStyle.position.x(), mStyle.position.y(), 0.0f)); - //mGrid->setPosition(OFFSET_X, Renderer::getScreenHeight() - mGrid->getSize().y() - OFFSET_Y); - mGrid->setOrigin(mStyle.origin); + mGrid->setSize(width, height); + + for (unsigned int i = 0; i < icons.size(); i++) { + const int col = i*4; + mGrid->setColWidthPerc(col, icons.at(i)->getSize().x() / width); + mGrid->setColWidthPerc(col + 1, ICON_TEXT_SPACING / width); + mGrid->setColWidthPerc(col + 2, labels.at(i)->getSize().x() / width); + + mGrid->setEntry(icons.at(i), Vector2i(col, 0), false, false); + mGrid->setEntry(labels.at(i), Vector2i(col + 2, 0), false, false); + } + + mGrid->setPosition(Vector3f(mStyle.position.x(), mStyle.position.y(), 0.0f)); + //mGrid->setPosition(OFFSET_X, Renderer::getScreenHeight() - mGrid->getSize().y() - OFFSET_Y); + mGrid->setOrigin(mStyle.origin); } std::shared_ptr HelpComponent::getIconTexture(const char* name) { - auto it = mIconCache.find(name); - if(it != mIconCache.cend()) - return it->second; + auto it = mIconCache.find(name); + if (it != mIconCache.cend()) + return it->second; - auto pathLookup = ICON_PATH_MAP.find(name); - if(pathLookup == ICON_PATH_MAP.cend()) - { - LOG(LogError) << "Unknown help icon \"" << name << "\"!"; - return nullptr; - } - if(!ResourceManager::getInstance()->fileExists(pathLookup->second)) - { - LOG(LogError) << "Help icon \"" << name << "\" - corresponding image file \"" << pathLookup->second << "\" misisng!"; - return nullptr; - } + auto pathLookup = ICON_PATH_MAP.find(name); + if (pathLookup == ICON_PATH_MAP.cend()) { + LOG(LogError) << "Unknown help icon \"" << name << "\"!"; + return nullptr; + } + if (!ResourceManager::getInstance()->fileExists(pathLookup->second)) { + LOG(LogError) << "Help icon \"" << name << + "\" - corresponding image file \"" << pathLookup->second << "\" misisng!"; + return nullptr; + } - std::shared_ptr tex = TextureResource::get(pathLookup->second); - mIconCache[std::string(name)] = tex; - return tex; + std::shared_ptr tex = TextureResource::get(pathLookup->second); + mIconCache[std::string(name)] = tex; + return tex; } void HelpComponent::setOpacity(unsigned char opacity) { - GuiComponent::setOpacity(opacity); + GuiComponent::setOpacity(opacity); - for(unsigned int i = 0; i < mGrid->getChildCount(); i++) - { - mGrid->getChild(i)->setOpacity(opacity); - } + for (unsigned int i = 0; i < mGrid->getChildCount(); i++) + mGrid->getChild(i)->setOpacity(opacity); } void HelpComponent::render(const Transform4x4f& parentTrans) { - Transform4x4f trans = parentTrans * getTransform(); + Transform4x4f trans = parentTrans * getTransform(); - if(mGrid) - mGrid->render(trans); + if (mGrid) + mGrid->render(trans); } diff --git a/es-core/src/components/HelpComponent.h b/es-core/src/components/HelpComponent.h index e9c5d2e07..80b4ed5e9 100644 --- a/es-core/src/components/HelpComponent.h +++ b/es-core/src/components/HelpComponent.h @@ -1,3 +1,9 @@ +// +// HelpComponent.h +// +// Help information in icon and text pairs. +// + #pragma once #ifndef ES_CORE_COMPONENTS_HELP_COMPONENT_H #define ES_CORE_COMPONENTS_HELP_COMPONENT_H @@ -12,25 +18,25 @@ class TextureResource; class HelpComponent : public GuiComponent { public: - HelpComponent(Window* window); + HelpComponent(Window* window); - void clearPrompts(); - void setPrompts(const std::vector& prompts); + void clearPrompts(); + void setPrompts(const std::vector& prompts); - void render(const Transform4x4f& parent) override; - void setOpacity(unsigned char opacity) override; + void render(const Transform4x4f& parent) override; + void setOpacity(unsigned char opacity) override; - void setStyle(const HelpStyle& style); + void setStyle(const HelpStyle& style); private: - std::shared_ptr getIconTexture(const char* name); - std::map< std::string, std::shared_ptr > mIconCache; + std::shared_ptr getIconTexture(const char* name); + std::map< std::string, std::shared_ptr > mIconCache; - std::shared_ptr mGrid; - void updateGrid(); + std::shared_ptr mGrid; + void updateGrid(); - std::vector mPrompts; - HelpStyle mStyle; + std::vector mPrompts; + HelpStyle mStyle; }; #endif // ES_CORE_COMPONENTS_HELP_COMPONENT_H diff --git a/es-core/src/components/IList.h b/es-core/src/components/IList.h index ce94560f3..e79da1a26 100644 --- a/es-core/src/components/IList.h +++ b/es-core/src/components/IList.h @@ -1,3 +1,9 @@ +// +// IList.h +// +// Gamelist base class. +// + #pragma once #ifndef ES_CORE_COMPONENTS_ILIST_H #define ES_CORE_COMPONENTS_ILIST_H @@ -6,334 +12,341 @@ #include "resources/Font.h" #include "PowerSaver.h" -enum CursorState -{ - CURSOR_STOPPED, - CURSOR_SCROLLING +enum CursorState { + CURSOR_STOPPED, + CURSOR_SCROLLING }; -enum ListLoopType -{ - LIST_ALWAYS_LOOP, - LIST_PAUSE_AT_END, - LIST_NEVER_LOOP +enum ListLoopType { + LIST_ALWAYS_LOOP, + LIST_PAUSE_AT_END, + LIST_NEVER_LOOP }; -struct ScrollTier -{ - int length; // how long we stay on this level before going to the next - int scrollDelay; // how long between scrolls +struct ScrollTier { + int length; // How long we stay on this tier before going to the next. + int scrollDelay; // How long between scrolls. }; -struct ScrollTierList -{ - const int count; - const ScrollTier* tiers; +struct ScrollTierList { + const int count; + const ScrollTier* tiers; }; -// default scroll tiers +// Default scroll tiers. const ScrollTier QUICK_SCROLL_TIERS[] = { - {500, 500}, - {2000, 114}, - {4000, 32}, - {0, 16} + {500, 500}, + {2000, 114}, + {4000, 32}, + {0, 16} +}; +const ScrollTierList LIST_SCROLL_STYLE_QUICK = { + 4, + QUICK_SCROLL_TIERS }; -const ScrollTierList LIST_SCROLL_STYLE_QUICK = { 4, QUICK_SCROLL_TIERS }; const ScrollTier SLOW_SCROLL_TIERS[] = { - {500, 500}, - {0, 200} + {500, 500}, + {0, 200} }; + const ScrollTierList LIST_SCROLL_STYLE_SLOW = { 2, SLOW_SCROLL_TIERS }; template class IList : public GuiComponent { public: - struct Entry - { - std::string name; - UserData object; - EntryData data; - }; + struct Entry { + std::string name; + UserData object; + EntryData data; + }; protected: - int mCursor; + int mCursor; - int mScrollTier; - int mScrollVelocity; + int mScrollTier; + int mScrollVelocity; - int mScrollTierAccumulator; - int mScrollCursorAccumulator; + int mScrollTierAccumulator; + int mScrollCursorAccumulator; - unsigned char mTitleOverlayOpacity; - unsigned int mTitleOverlayColor; - ImageComponent mGradient; - std::shared_ptr mTitleOverlayFont; + unsigned char mTitleOverlayOpacity; + unsigned int mTitleOverlayColor; + ImageComponent mGradient; + std::shared_ptr mTitleOverlayFont; - const ScrollTierList& mTierList; - const ListLoopType mLoopType; + const ScrollTierList& mTierList; + const ListLoopType mLoopType; - std::vector mEntries; + std::vector mEntries; public: - IList(Window* window, const ScrollTierList& tierList = LIST_SCROLL_STYLE_QUICK, const ListLoopType& loopType = LIST_PAUSE_AT_END) : GuiComponent(window), - mGradient(window), mTierList(tierList), mLoopType(loopType) - { - mCursor = 0; - mScrollTier = 0; - mScrollVelocity = 0; - mScrollTierAccumulator = 0; - mScrollCursorAccumulator = 0; + IList( + Window* window, + const ScrollTierList& tierList = LIST_SCROLL_STYLE_QUICK, + const ListLoopType& loopType = LIST_PAUSE_AT_END) + : GuiComponent(window), + mGradient(window), + mTierList(tierList), + mLoopType(loopType) + { + mCursor = 0; + mScrollTier = 0; + mScrollVelocity = 0; + mScrollTierAccumulator = 0; + mScrollCursorAccumulator = 0; - mTitleOverlayOpacity = 0x00; - mTitleOverlayColor = 0xFFFFFF00; - mGradient.setResize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); - mGradient.setImage(":/graphics/scroll_gradient.png"); - mTitleOverlayFont = Font::get(FONT_SIZE_LARGE); - } + mTitleOverlayOpacity = 0x00; + mTitleOverlayColor = 0xFFFFFF00; + mGradient.setResize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); + mGradient.setImage(":/graphics/scroll_gradient.png"); + mTitleOverlayFont = Font::get(FONT_SIZE_LARGE); + } - bool isScrolling() const - { - return (mScrollVelocity != 0 && mScrollTier > 0); - } + bool isScrolling() const + { + return (mScrollVelocity != 0 && mScrollTier > 0); + } - int getScrollingVelocity() - { - return mScrollVelocity; - } + int getScrollingVelocity() + { + return mScrollVelocity; + } - void stopScrolling() - { - listInput(0); - onCursorChanged(CURSOR_STOPPED); - } + void stopScrolling() + { + listInput(0); + onCursorChanged(CURSOR_STOPPED); + } - void clear() - { - mEntries.clear(); - mCursor = 0; - listInput(0); - onCursorChanged(CURSOR_STOPPED); - } + void clear() + { + mEntries.clear(); + mCursor = 0; + listInput(0); + onCursorChanged(CURSOR_STOPPED); + } - inline const std::string& getSelectedName() - { - assert(size() > 0); - return mEntries.at(mCursor).name; - } + inline const std::string& getSelectedName() + { + assert(size() > 0); + return mEntries.at(mCursor).name; + } - inline const UserData& getSelected() const - { - assert(size() > 0); - return mEntries.at(mCursor).object; - } + inline const UserData& getSelected() const + { + assert(size() > 0); + return mEntries.at(mCursor).object; + } - inline const UserData& getFirst() const - { - assert(size() > 0); - return mEntries.front().object; - } + inline const UserData& getFirst() const + { + assert(size() > 0); + return mEntries.front().object; + } - inline const UserData& getLast() const - { - assert(size() > 0); - return mEntries.back().object; - } + inline const UserData& getLast() const + { + assert(size() > 0); + return mEntries.back().object; + } - void setCursor(typename std::vector::const_iterator& it) - { - assert(it != mEntries.cend()); - mCursor = it - mEntries.cbegin(); - onCursorChanged(CURSOR_STOPPED); - } + void setCursor(typename std::vector::const_iterator& it) + { + assert(it != mEntries.cend()); + mCursor = it - mEntries.cbegin(); + onCursorChanged(CURSOR_STOPPED); + } - // returns true if successful (select is in our list), false if not - bool setCursor(const UserData& obj) - { - for(auto it = mEntries.cbegin(); it != mEntries.cend(); it++) - { - if((*it).object == obj) - { - mCursor = (int)(it - mEntries.cbegin()); - onCursorChanged(CURSOR_STOPPED); - return true; - } - } + // Returns true if successful (select is in our list), false if not. + bool setCursor(const UserData& obj) + { + for (auto it = mEntries.cbegin(); it != mEntries.cend(); it++) { + if ((*it).object == obj) { + mCursor = (int)(it - mEntries.cbegin()); + onCursorChanged(CURSOR_STOPPED); + return true; + } + } - return false; - } + return false; + } - // entry management - void add(const Entry& e) - { - mEntries.push_back(e); - } + // Entry management. + void add(const Entry& e) + { + mEntries.push_back(e); + } - bool remove(const UserData& obj) - { - for(auto it = mEntries.cbegin(); it != mEntries.cend(); it++) - { - if((*it).object == obj) - { - remove(it); - return true; - } - } + bool remove(const UserData& obj) + { + for (auto it = mEntries.cbegin(); it != mEntries.cend(); it++) { + if ((*it).object == obj) { + remove(it); + return true; + } + } - return false; - } + return false; + } - inline int size() const { return (int)mEntries.size(); } + inline int size() const { return (int)mEntries.size(); } protected: - void remove(typename std::vector::const_iterator& it) - { - if(mCursor > 0 && it - mEntries.cbegin() <= mCursor) - { - mCursor--; - onCursorChanged(CURSOR_STOPPED); - } + void remove(typename std::vector::const_iterator& it) + { + if (mCursor > 0 && it - mEntries.cbegin() <= mCursor) { + mCursor--; + onCursorChanged(CURSOR_STOPPED); + } - mEntries.erase(it); - } + mEntries.erase(it); + } - bool listFirstRow() - { - mCursor = 0; - onCursorChanged(CURSOR_STOPPED); - onScroll(); - return true; - } + bool listFirstRow() + { + mCursor = 0; + onCursorChanged(CURSOR_STOPPED); + onScroll(); + return true; + } - bool listLastRow() - { - mCursor = mEntries.size() - 1; - onCursorChanged(CURSOR_STOPPED); - onScroll(); - return true; - } + bool listLastRow() + { + mCursor = mEntries.size() - 1; + onCursorChanged(CURSOR_STOPPED); + onScroll(); + return true; + } - bool listInput(int velocity) // a velocity of 0 = stop scrolling - { - PowerSaver::setState(velocity == 0); - // generate an onCursorChanged event in the stopped state when the user lets go of the key - if(velocity == 0 && mScrollVelocity != 0) - onCursorChanged(CURSOR_STOPPED); + bool listInput(int velocity) // A velocity of 0 = stop scrolling. + { + PowerSaver::setState(velocity == 0); - mScrollVelocity = velocity; - mScrollTier = 0; - mScrollTierAccumulator = 0; - mScrollCursorAccumulator = 0; + // Generate an onCursorChanged event in the stopped state when the user + // lets go of the key. + if (velocity == 0 && mScrollVelocity != 0) + onCursorChanged(CURSOR_STOPPED); - int prevCursor = mCursor; - scroll(mScrollVelocity); - return (prevCursor != mCursor); - } + mScrollVelocity = velocity; + mScrollTier = 0; + mScrollTierAccumulator = 0; + mScrollCursorAccumulator = 0; - void listUpdate(int deltaTime) - { - // update the title overlay opacity - const int dir = (mScrollTier >= mTierList.count - 1) ? 1 : -1; // fade in if scroll tier is >= 1, otherwise fade out - int op = mTitleOverlayOpacity + deltaTime*dir; // we just do a 1-to-1 time -> opacity, no scaling - if(op >= 255) - mTitleOverlayOpacity = 255; - else if(op <= 0) - mTitleOverlayOpacity = 0; - else - mTitleOverlayOpacity = (unsigned char)op; + int prevCursor = mCursor; + scroll(mScrollVelocity); + return (prevCursor != mCursor); + } - if(mScrollVelocity == 0 || size() < 2) - return; + void listUpdate(int deltaTime) + { + // Update the title overlay opacity. + // Fade in if scroll tier is >= 1, otherwise fade out. + const int dir = (mScrollTier >= mTierList.count - 1) ? 1 : -1; + // We just do a 1-to-1 time -> opacity, no scaling. + int op = mTitleOverlayOpacity + deltaTime*dir; + if (op >= 255) + mTitleOverlayOpacity = 255; + else if (op <= 0) + mTitleOverlayOpacity = 0; + else + mTitleOverlayOpacity = (unsigned char)op; - mScrollCursorAccumulator += deltaTime; - mScrollTierAccumulator += deltaTime; + if (mScrollVelocity == 0 || size() < 2) + return; - // we delay scrolling until after scroll tier has updated so isScrolling() returns accurately during onCursorChanged callbacks - // we don't just do scroll tier first because it would not catch the scrollDelay == tier length case - int scrollCount = 0; - while(mScrollCursorAccumulator >= mTierList.tiers[mScrollTier].scrollDelay) - { - mScrollCursorAccumulator -= mTierList.tiers[mScrollTier].scrollDelay; - scrollCount++; - } + mScrollCursorAccumulator += deltaTime; + mScrollTierAccumulator += deltaTime; - // are we ready to go even FASTER? - while(mScrollTier < mTierList.count - 1 && mScrollTierAccumulator >= mTierList.tiers[mScrollTier].length) - { - mScrollTierAccumulator -= mTierList.tiers[mScrollTier].length; - mScrollTier++; - } + // We delay scrolling until after scroll tier has updated so isScrolling() returns + // accurately during onCursorChanged callbacks. We don't just do scroll tier first + // because it would not catch the scrollDelay == tier length case. + int scrollCount = 0; + while (mScrollCursorAccumulator >= mTierList.tiers[mScrollTier].scrollDelay) { + mScrollCursorAccumulator -= mTierList.tiers[mScrollTier].scrollDelay; + scrollCount++; + } - // actually perform the scrolling - for(int i = 0; i < scrollCount; i++) - scroll(mScrollVelocity); - } + // Are we ready to go even FASTER? + while (mScrollTier < mTierList.count - 1 && mScrollTierAccumulator >= + mTierList.tiers[mScrollTier].length) { + mScrollTierAccumulator -= mTierList.tiers[mScrollTier].length; + mScrollTier++; + } - void listRenderTitleOverlay(const Transform4x4f& /*trans*/) - { - if(size() == 0 || !mTitleOverlayFont || mTitleOverlayOpacity == 0) - return; + // Actually perform the scrolling. + for (int i = 0; i < scrollCount; i++) + scroll(mScrollVelocity); + } - // we don't bother caching this because it's only two letters and will change pretty much every frame if we're scrolling - const std::string text = getSelectedName().size() >= 2 ? getSelectedName().substr(0, 2) : "??"; + void listRenderTitleOverlay(const Transform4x4f& /*trans*/) + { + if (size() == 0 || !mTitleOverlayFont || mTitleOverlayOpacity == 0) + return; - Vector2f off = mTitleOverlayFont->sizeText(text); - off[0] = (Renderer::getScreenWidth() - off.x()) * 0.5f; - off[1] = (Renderer::getScreenHeight() - off.y()) * 0.5f; + // We don't bother caching this because it's only two letters and will change pretty + // much every frame if we're scrolling. + const std::string text = getSelectedName().size() >= 2 ? + getSelectedName().substr(0, 2) : "??"; - Transform4x4f identTrans = Transform4x4f::Identity(); + Vector2f off = mTitleOverlayFont->sizeText(text); + off[0] = (Renderer::getScreenWidth() - off.x()) * 0.5f; + off[1] = (Renderer::getScreenHeight() - off.y()) * 0.5f; - mGradient.setOpacity(mTitleOverlayOpacity); - mGradient.render(identTrans); + Transform4x4f identTrans = Transform4x4f::Identity(); - TextCache* cache = mTitleOverlayFont->buildTextCache(text, off.x(), off.y(), 0xFFFFFF00 | mTitleOverlayOpacity); - mTitleOverlayFont->renderTextCache(cache); // relies on mGradient's render for Renderer::setMatrix() - delete cache; - } + mGradient.setOpacity(mTitleOverlayOpacity); + mGradient.render(identTrans); - void scroll(int amt) - { - if(mScrollVelocity == 0 || size() < 2) - return; + TextCache* cache = mTitleOverlayFont->buildTextCache(text, off.x(), off.y(), + 0xFFFFFF00 | mTitleOverlayOpacity); + // Relies on mGradient's render for Renderer::setMatrix() + mTitleOverlayFont->renderTextCache(cache); + delete cache; + } - int cursor = mCursor + amt; - int absAmt = amt < 0 ? -amt : amt; + void scroll(int amt) + { + if (mScrollVelocity == 0 || size() < 2) + return; - // stop at the end if we've been holding down the button for a long time or - // we're scrolling faster than one item at a time (e.g. page up/down) - // otherwise, loop around - if((mLoopType == LIST_PAUSE_AT_END && (mScrollTier > 0 || absAmt > 1)) || - mLoopType == LIST_NEVER_LOOP) - { - if(cursor < 0) - { - cursor = 0; - mScrollVelocity = 0; - mScrollTier = 0; - }else if(cursor >= size()) - { - cursor = size() - 1; - mScrollVelocity = 0; - mScrollTier = 0; - } - }else{ - while(cursor < 0) - cursor += size(); - while(cursor >= size()) - cursor -= size(); - } + int cursor = mCursor + amt; + int absAmt = amt < 0 ? -amt : amt; - if(cursor != mCursor) - onScroll(); + // Stop at the end if we've been holding down the button for a long time or + // we're scrolling faster than one item at a time (e.g. page up/down). + // Otherwise, loop around. + if ((mLoopType == LIST_PAUSE_AT_END && (mScrollTier > 0 || absAmt > 1)) || + mLoopType == LIST_NEVER_LOOP) { + if (cursor < 0) { + cursor = 0; + mScrollVelocity = 0; + mScrollTier = 0; + } + else if (cursor >= size()) { + cursor = size() - 1; + mScrollVelocity = 0; + mScrollTier = 0; + } + } + else { + while (cursor < 0) + cursor += size(); + while (cursor >= size()) + cursor -= size(); + } - mCursor = cursor; - onCursorChanged((mScrollTier > 0) ? CURSOR_SCROLLING : CURSOR_STOPPED); - } + if (cursor != mCursor) + onScroll(); - virtual void onCursorChanged(const CursorState& /*state*/) {} - virtual void onScroll() {} + mCursor = cursor; + onCursorChanged((mScrollTier > 0) ? CURSOR_SCROLLING : CURSOR_STOPPED); + } + + virtual void onCursorChanged(const CursorState& /*state*/) {} + virtual void onScroll() {} }; #endif // ES_CORE_COMPONENTS_ILIST_H diff --git a/es-core/src/components/ImageComponent.cpp b/es-core/src/components/ImageComponent.cpp index 823ceb570..5eb9dd343 100644 --- a/es-core/src/components/ImageComponent.cpp +++ b/es-core/src/components/ImageComponent.cpp @@ -1,3 +1,9 @@ +// +// ImageComponent.cpp +// +// Handles images: loading, resizing, cropping, color shifting etc. +// + #include "components/ImageComponent.h" #include "resources/TextureResource.h" @@ -7,23 +13,39 @@ Vector2i ImageComponent::getTextureSize() const { - if(mTexture) - return mTexture->getSize(); - else - return Vector2i::Zero(); + if (mTexture) + return mTexture->getSize(); + else + return Vector2i::Zero(); } Vector2f ImageComponent::getSize() const { - return GuiComponent::getSize() * (mBottomRightCrop - mTopLeftCrop); + return GuiComponent::getSize() * (mBottomRightCrop - mTopLeftCrop); } -ImageComponent::ImageComponent(Window* window, bool forceLoad, bool dynamic) : GuiComponent(window), - mTargetIsMax(false), mTargetIsMin(false), mFlipX(false), mFlipY(false), mTargetSize(0, 0), mColorShift(0xFFFFFFFF), - mColorShiftEnd(0xFFFFFFFF), mColorGradientHorizontal(true), mForceLoad(forceLoad), mDynamic(dynamic), - mFadeOpacity(0), mFading(false), mRotateByTargetSize(false), mTopLeftCrop(0.0f, 0.0f), mBottomRightCrop(1.0f, 1.0f) +ImageComponent::ImageComponent( + Window* window, + bool forceLoad, + bool dynamic) + : GuiComponent(window), + mTargetIsMax(false), + mTargetIsMin(false), + mFlipX(false), + mFlipY(false), + mTargetSize(0, 0), + mColorShift(0xFFFFFFFF), + mColorShiftEnd(0xFFFFFFFF), + mColorGradientHorizontal(true), + mForceLoad(forceLoad), + mDynamic(dynamic), + mFadeOpacity(0), + mFading(false), + mRotateByTargetSize(false), + mTopLeftCrop(0.0f, 0.0f), + mBottomRightCrop(1.0f, 1.0f) { - updateColors(); + updateColors(); } ImageComponent::~ImageComponent() @@ -32,412 +54,406 @@ ImageComponent::~ImageComponent() void ImageComponent::resize() { - if(!mTexture) - return; + if (!mTexture) + return; - const Vector2f textureSize = mTexture->getSourceImageSize(); - if(textureSize == Vector2f::Zero()) - return; + const Vector2f textureSize = mTexture->getSourceImageSize(); + if (textureSize == Vector2f::Zero()) + return; - if(mTexture->isTiled()) - { - mSize = mTargetSize; - }else{ - // SVG rasterization is determined by height (see SVGResource.cpp), and rasterization is done in terms of pixels - // if rounding is off enough in the rasterization step (for images with extreme aspect ratios), it can cause cutoff when the aspect ratio breaks - // so, we always make sure the resultant height is an integer to make sure cutoff doesn't happen, and scale width from that - // (you'll see this scattered throughout the function) - // this is probably not the best way, so if you're familiar with this problem and have a better solution, please make a pull request! + if (mTexture->isTiled()) { + mSize = mTargetSize; + } + else { + // SVG rasterization is determined by height and rasterization is done in terms of pixels. + // If rounding is off enough in the rasterization step (for images with extreme aspect + // ratios), it can cause cutoff when the aspect ratio breaks. + // So we always make sure the resultant height is an integer to make sure cutoff doesn't + // happen, and scale width from that (you'll see this scattered throughout the function). + // This is probably not the best way, so if you're familiar with this problem and have a + // better solution, please make a pull request! + if (mTargetIsMax) { + mSize = textureSize; - if(mTargetIsMax) - { - mSize = textureSize; + Vector2f resizeScale((mTargetSize.x() / mSize.x()), (mTargetSize.y() / mSize.y())); - Vector2f resizeScale((mTargetSize.x() / mSize.x()), (mTargetSize.y() / mSize.y())); + if (resizeScale.x() < resizeScale.y()) { + // This will be mTargetSize.x(). We can't exceed it, nor be lower than it. + mSize[0] *= resizeScale.x(); + // We need to make sure we're not creating an image larger than max size. + mSize[1] = Math::min(Math::round(mSize[1] *= resizeScale.x()), mTargetSize.y()); + } + else { + // This will be mTargetSize.y(). We can't exceed it. + mSize[1] = Math::round(mSize[1] * resizeScale.y()); + // For SVG rasterization, always calculate width from rounded height (see comment + // above). We need to make sure we're not creating an image larger than max size. + mSize[0] = Math::min((mSize[1] / textureSize.y()) * textureSize.x(), + mTargetSize.x()); + } + } + else if (mTargetIsMin) { + mSize = textureSize; - if(resizeScale.x() < resizeScale.y()) - { - mSize[0] *= resizeScale.x(); // this will be mTargetSize.x(). We can't exceed it, nor be lower than it. - // we need to make sure we're not creating an image larger than max size - mSize[1] = Math::min(Math::round(mSize[1] *= resizeScale.x()), mTargetSize.y()); - }else{ - mSize[1] = Math::round(mSize[1] * resizeScale.y()); // this will be mTargetSize.y(). We can't exceed it. + Vector2f resizeScale((mTargetSize.x() / mSize.x()), (mTargetSize.y() / mSize.y())); - // for SVG rasterization, always calculate width from rounded height (see comment above) - // we need to make sure we're not creating an image larger than max size - mSize[0] = Math::min((mSize[1] / textureSize.y()) * textureSize.x(), mTargetSize.x()); - } - }else if(mTargetIsMin) - { - mSize = textureSize; + if (resizeScale.x() > resizeScale.y()) { + mSize[0] *= resizeScale.x(); + mSize[1] *= resizeScale.x(); - Vector2f resizeScale((mTargetSize.x() / mSize.x()), (mTargetSize.y() / mSize.y())); + float cropPercent = (mSize.y() - mTargetSize.y()) / (mSize.y() * 2); + crop(0, cropPercent, 0, cropPercent); + } + else { + mSize[0] *= resizeScale.y(); + mSize[1] *= resizeScale.y(); - if(resizeScale.x() > resizeScale.y()) - { - mSize[0] *= resizeScale.x(); - mSize[1] *= resizeScale.x(); + float cropPercent = (mSize.x() - mTargetSize.x()) / (mSize.x() * 2); + crop(cropPercent, 0, cropPercent, 0); + } + // For SVG rasterization, always calculate width from rounded height (see comment + // above). We need to make sure we're not creating an image smaller than min size. + mSize[1] = Math::max(Math::round(mSize[1]), mTargetSize.y()); + mSize[0] = Math::max((mSize[1] / textureSize.y()) * textureSize.x(), mTargetSize.x()); - float cropPercent = (mSize.y() - mTargetSize.y()) / (mSize.y() * 2); - crop(0, cropPercent, 0, cropPercent); - }else{ - mSize[0] *= resizeScale.y(); - mSize[1] *= resizeScale.y(); + } + else { + // If both components are set, we just stretch. + // If no components are set, we don't resize at all. + mSize = mTargetSize == Vector2f::Zero() ? textureSize : mTargetSize; - float cropPercent = (mSize.x() - mTargetSize.x()) / (mSize.x() * 2); - crop(cropPercent, 0, cropPercent, 0); - } + // If only one component is set, we resize in a way that maintains aspect ratio. + // For SVG rasterization, we always calculate width from rounded height (see + // comment above). + if (!mTargetSize.x() && mTargetSize.y()) { + mSize[1] = Math::round(mTargetSize.y()); + mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); + } + else if (mTargetSize.x() && !mTargetSize.y()) { + mSize[1] = Math::round((mTargetSize.x() / textureSize.x()) * textureSize.y()); + mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); + } + } + } - // for SVG rasterization, always calculate width from rounded height (see comment above) - // we need to make sure we're not creating an image smaller than min size - mSize[1] = Math::max(Math::round(mSize[1]), mTargetSize.y()); - mSize[0] = Math::max((mSize[1] / textureSize.y()) * textureSize.x(), mTargetSize.x()); + mSize[0] = Math::round(mSize.x()); + mSize[1] = Math::round(mSize.y()); + // mSize.y() should already be rounded. + mTexture->rasterizeAt((size_t)mSize.x(), (size_t)mSize.y()); - }else{ - // if both components are set, we just stretch - // if no components are set, we don't resize at all - mSize = mTargetSize == Vector2f::Zero() ? textureSize : mTargetSize; - - // if only one component is set, we resize in a way that maintains aspect ratio - // for SVG rasterization, we always calculate width from rounded height (see comment above) - if(!mTargetSize.x() && mTargetSize.y()) - { - mSize[1] = Math::round(mTargetSize.y()); - mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); - }else if(mTargetSize.x() && !mTargetSize.y()) - { - mSize[1] = Math::round((mTargetSize.x() / textureSize.x()) * textureSize.y()); - mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); - } - } - } - - mSize[0] = Math::round(mSize.x()); - mSize[1] = Math::round(mSize.y()); - // mSize.y() should already be rounded - mTexture->rasterizeAt((size_t)mSize.x(), (size_t)mSize.y()); - - onSizeChanged(); + onSizeChanged(); } void ImageComponent::onSizeChanged() { - updateVertices(); + updateVertices(); } void ImageComponent::setDefaultImage(std::string path) { - mDefaultPath = path; + mDefaultPath = path; } void ImageComponent::setImage(std::string path, bool tile) { - if(path.empty() || !ResourceManager::getInstance()->fileExists(path)) - { - if(mDefaultPath.empty() || !ResourceManager::getInstance()->fileExists(mDefaultPath)) - mTexture.reset(); - else - mTexture = TextureResource::get(mDefaultPath, tile, mForceLoad, mDynamic); - } else { - mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic); - } + if (path.empty() || !ResourceManager::getInstance()->fileExists(path)) { + if (mDefaultPath.empty() || !ResourceManager::getInstance()->fileExists(mDefaultPath)) + mTexture.reset(); + else + mTexture = TextureResource::get(mDefaultPath, tile, mForceLoad, mDynamic); + } + else { + mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic); + } - resize(); + resize(); } void ImageComponent::setImage(const char* path, size_t length, bool tile) { - mTexture.reset(); + mTexture.reset(); - mTexture = TextureResource::get("", tile); - mTexture->initFromMemory(path, length); + mTexture = TextureResource::get("", tile); + mTexture->initFromMemory(path, length); - resize(); + resize(); } void ImageComponent::setImage(const std::shared_ptr& texture) { - mTexture = texture; - resize(); + mTexture = texture; + resize(); } void ImageComponent::setResize(float width, float height) { - mTargetSize = Vector2f(width, height); - mTargetIsMax = false; - mTargetIsMin = false; - resize(); + mTargetSize = Vector2f(width, height); + mTargetIsMax = false; + mTargetIsMin = false; + resize(); } void ImageComponent::setMaxSize(float width, float height) { - mTargetSize = Vector2f(width, height); - mTargetIsMax = true; - mTargetIsMin = false; - resize(); + mTargetSize = Vector2f(width, height); + mTargetIsMax = true; + mTargetIsMin = false; + resize(); } void ImageComponent::setMinSize(float width, float height) { - mTargetSize = Vector2f(width, height); - mTargetIsMax = false; - mTargetIsMin = true; - resize(); + mTargetSize = Vector2f(width, height); + mTargetIsMax = false; + mTargetIsMin = true; + resize(); } Vector2f ImageComponent::getRotationSize() const { - return mRotateByTargetSize ? mTargetSize : mSize; + return mRotateByTargetSize ? mTargetSize : mSize; } void ImageComponent::setRotateByTargetSize(bool rotate) { - mRotateByTargetSize = rotate; + mRotateByTargetSize = rotate; } void ImageComponent::cropLeft(float percent) { - assert(percent >= 0.0f && percent <= 1.0f); - mTopLeftCrop.x() = percent; + assert(percent >= 0.0f && percent <= 1.0f); + mTopLeftCrop.x() = percent; } void ImageComponent::cropTop(float percent) { - assert(percent >= 0.0f && percent <= 1.0f); - mTopLeftCrop.y() = percent; + assert(percent >= 0.0f && percent <= 1.0f); + mTopLeftCrop.y() = percent; } void ImageComponent::cropRight(float percent) { - assert(percent >= 0.0f && percent <= 1.0f); - mBottomRightCrop.x() = 1.0f - percent; + assert(percent >= 0.0f && percent <= 1.0f); + mBottomRightCrop.x() = 1.0f - percent; } void ImageComponent::cropBot(float percent) { - assert(percent >= 0.0f && percent <= 1.0f); - mBottomRightCrop.y() = 1.0f - percent; + assert(percent >= 0.0f && percent <= 1.0f); + mBottomRightCrop.y() = 1.0f - percent; } void ImageComponent::crop(float left, float top, float right, float bot) { - cropLeft(left); - cropTop(top); - cropRight(right); - cropBot(bot); + cropLeft(left); + cropTop(top); + cropRight(right); + cropBot(bot); } void ImageComponent::uncrop() { - crop(0, 0, 0, 0); + crop(0, 0, 0, 0); } void ImageComponent::setFlipX(bool flip) { - mFlipX = flip; - updateVertices(); + mFlipX = flip; + updateVertices(); } void ImageComponent::setFlipY(bool flip) { - mFlipY = flip; - updateVertices(); + mFlipY = flip; + updateVertices(); } void ImageComponent::setColorShift(unsigned int color) { - mColorShift = color; - mColorShiftEnd = color; - updateColors(); + mColorShift = color; + mColorShiftEnd = color; + updateColors(); } void ImageComponent::setColorShiftEnd(unsigned int color) { - mColorShiftEnd = color; - updateColors(); + mColorShiftEnd = color; + updateColors(); } void ImageComponent::setColorGradientHorizontal(bool horizontal) { - mColorGradientHorizontal = horizontal; - updateColors(); + mColorGradientHorizontal = horizontal; + updateColors(); } void ImageComponent::setOpacity(unsigned char opacity) { - mOpacity = opacity; - updateColors(); + mOpacity = opacity; + updateColors(); } void ImageComponent::updateVertices() { - if(!mTexture || !mTexture->isInitialized()) - return; + if (!mTexture || !mTexture->isInitialized()) + return; - // we go through this mess to make sure everything is properly rounded - // if we just round vertices at the end, edge cases occur near sizes of 0.5 - const Vector2f topLeft = { mSize * mTopLeftCrop }; - const Vector2f bottomRight = { mSize * mBottomRightCrop }; - const float px = mTexture->isTiled() ? mSize.x() / getTextureSize().x() : 1.0f; - const float py = mTexture->isTiled() ? mSize.y() / getTextureSize().y() : 1.0f; + // We go through this mess to make sure everything is properly rounded. + // If we just round vertices at the end, edge cases occur near sizes of 0.5. + const Vector2f topLeft = { mSize * mTopLeftCrop }; + const Vector2f bottomRight = { mSize * mBottomRightCrop }; + const float px = mTexture->isTiled() ? mSize.x() / getTextureSize().x() : 1.0f; + const float py = mTexture->isTiled() ? mSize.y() / getTextureSize().y() : 1.0f; - mVertices[0] = { { topLeft.x(), topLeft.y() }, { mTopLeftCrop.x(), py - mTopLeftCrop.y() }, 0 }; - mVertices[1] = { { topLeft.x(), bottomRight.y() }, { mTopLeftCrop.x(), 1.0f - mBottomRightCrop.y() }, 0 }; - mVertices[2] = { { bottomRight.x(), topLeft.y() }, { mBottomRightCrop.x() * px, py - mTopLeftCrop.y() }, 0 }; - mVertices[3] = { { bottomRight.x(), bottomRight.y() }, { mBottomRightCrop.x() * px, 1.0f - mBottomRightCrop.y() }, 0 }; + mVertices[0] = { { topLeft.x(), topLeft.y() }, { mTopLeftCrop.x(), py - mTopLeftCrop.y() }, 0 }; + mVertices[1] = { { topLeft.x(), bottomRight.y() }, { mTopLeftCrop.x(), 1.0f - mBottomRightCrop.y() }, 0 }; + mVertices[2] = { { bottomRight.x(), topLeft.y() }, { mBottomRightCrop.x() * px, py - mTopLeftCrop.y() }, 0 }; + mVertices[3] = { { bottomRight.x(), bottomRight.y() }, { mBottomRightCrop.x() * px, 1.0f - mBottomRightCrop.y() }, 0 }; - updateColors(); + updateColors(); - // round vertices - for(int i = 0; i < 4; ++i) - mVertices[i].pos.round(); + // Round vertices. + for (int i = 0; i < 4; ++i) + mVertices[i].pos.round(); - if(mFlipX) - { - for(int i = 0; i < 4; ++i) - mVertices[i].tex[0] = px - mVertices[i].tex[0]; - } + if (mFlipX) { + for (int i = 0; i < 4; ++i) + mVertices[i].tex[0] = px - mVertices[i].tex[0]; + } - if(mFlipY) - { - for(int i = 0; i < 4; ++i) - mVertices[i].tex[1] = py - mVertices[i].tex[1]; - } + if (mFlipY) { + for (int i = 0; i < 4; ++i) + mVertices[i].tex[1] = py - mVertices[i].tex[1]; + } } void ImageComponent::updateColors() { - const float opacity = (mOpacity * (mFading ? mFadeOpacity / 255.0 : 1.0)) / 255.0; - const unsigned int color = Renderer::convertColor(mColorShift & 0xFFFFFF00 | (unsigned char)((mColorShift & 0xFF) * opacity)); - const unsigned int colorEnd = Renderer::convertColor(mColorShiftEnd & 0xFFFFFF00 | (unsigned char)((mColorShiftEnd & 0xFF) * opacity)); + const float opacity = (mOpacity * (mFading ? mFadeOpacity / 255.0 : 1.0)) / 255.0; + const unsigned int color = Renderer::convertColor(mColorShift & 0xFFFFFF00 | + (unsigned char)((mColorShift & 0xFF) * opacity)); + const unsigned int colorEnd = Renderer::convertColor(mColorShiftEnd & 0xFFFFFF00 | + (unsigned char)((mColorShiftEnd & 0xFF) * opacity)); - mVertices[0].col = color; - mVertices[1].col = mColorGradientHorizontal ? colorEnd : color; - mVertices[2].col = mColorGradientHorizontal ? color : colorEnd; - mVertices[3].col = colorEnd; + mVertices[0].col = color; + mVertices[1].col = mColorGradientHorizontal ? colorEnd : color; + mVertices[2].col = mColorGradientHorizontal ? color : colorEnd; + mVertices[3].col = colorEnd; } void ImageComponent::render(const Transform4x4f& parentTrans) { - if (!isVisible()) - return; + if (!isVisible()) + return; - Transform4x4f trans = parentTrans * getTransform(); - Renderer::setMatrix(trans); + Transform4x4f trans = parentTrans * getTransform(); + Renderer::setMatrix(trans); - if(mTexture && mOpacity > 0) - { - if(Settings::getInstance()->getBool("DebugImage")) { - Vector2f targetSizePos = (mTargetSize - mSize) * mOrigin * -1; - Renderer::drawRect(targetSizePos.x(), targetSizePos.y(), mTargetSize.x(), mTargetSize.y(), 0xFF000033, 0xFF000033); - Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), 0x00000033, 0x00000033); - } - if(mTexture->isInitialized()) - { - // actually draw the image - // The bind() function returns false if the texture is not currently loaded. A blank - // texture is bound in this case but we want to handle a fade so it doesn't just 'jump' in - // when it finally loads - fadeIn(mTexture->bind()); - Renderer::drawTriangleStrips(&mVertices[0], 4); + if (mTexture && mOpacity > 0) { + if (Settings::getInstance()->getBool("DebugImage")) { + Vector2f targetSizePos = (mTargetSize - mSize) * mOrigin * -1; + Renderer::drawRect(targetSizePos.x(), targetSizePos.y(), mTargetSize.x(), + mTargetSize.y(), 0xFF000033, 0xFF000033); + Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), 0x00000033, 0x00000033); + } + if (mTexture->isInitialized()) { + // Actually draw the image. + // The bind() function returns false if the texture is not currently loaded. A blank + // texture is bound in this case but we want to handle a fade so it doesn't just + // 'jump' in when it finally loads. + fadeIn(mTexture->bind()); + Renderer::drawTriangleStrips(&mVertices[0], 4); - }else{ - LOG(LogError) << "Image texture is not initialized!"; - mTexture.reset(); - } - } + } + else { + LOG(LogError) << "Image texture is not initialized!"; + mTexture.reset(); + } + } - GuiComponent::renderChildren(trans); + GuiComponent::renderChildren(trans); } void ImageComponent::fadeIn(bool textureLoaded) { - if (!mForceLoad) - { - if (!textureLoaded) - { - // Start the fade if this is the first time we've encountered the unloaded texture - if (!mFading) - { - // Start with a zero opacity and flag it as fading - mFadeOpacity = 0; - mFading = true; - updateColors(); - } - } - else if (mFading) - { - // The texture is loaded and we need to fade it in. The fade is based on the frame rate - // and is 1/4 second if running at 60 frames per second although the actual value is not - // that important - int opacity = mFadeOpacity + 255 / 15; - // See if we've finished fading - if (opacity >= 255) - { - mFadeOpacity = 255; - mFading = false; - } - else - { - mFadeOpacity = (unsigned char)opacity; - } - updateColors(); - } - } + if (!mForceLoad) { + if (!textureLoaded) { + // Start the fade if this is the first time we've encountered the unloaded texture. + if (!mFading) { + // Start with a zero opacity and flag it as fading. + mFadeOpacity = 0; + mFading = true; + updateColors(); + } + } + else if (mFading) { + // The texture is loaded and we need to fade it in. The fade is based on the frame + // rate and is 1/4 second if running at 60 frames per second although the actual + // value is not that important. + int opacity = mFadeOpacity + 255 / 15; + // See if we've finished fading. + if (opacity >= 255) { + mFadeOpacity = 255; + mFading = false; + } + else { + mFadeOpacity = (unsigned char)opacity; + } + updateColors(); + } + } } bool ImageComponent::hasImage() { - return (bool)mTexture; + return (bool)mTexture; } -void ImageComponent::applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) +void ImageComponent::applyTheme(const std::shared_ptr& theme, const std::string& view, + const std::string& element, unsigned int properties) { - using namespace ThemeFlags; + using namespace ThemeFlags; - GuiComponent::applyTheme(theme, view, element, (properties ^ SIZE) | ((properties & (SIZE | POSITION)) ? ORIGIN : 0)); + GuiComponent::applyTheme(theme, view, element, (properties ^ SIZE) | + ((properties & (SIZE | POSITION)) ? ORIGIN : 0)); - const ThemeData::ThemeElement* elem = theme->getElement(view, element, "image"); - if(!elem) - return; + const ThemeData::ThemeElement* elem = theme->getElement(view, element, "image"); + if (!elem) + return; - Vector2f scale = getParent() ? getParent()->getSize() : Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); + Vector2f scale = getParent() ? getParent()->getSize() : + Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); - if(properties & ThemeFlags::SIZE) - { - if(elem->has("size")) - setResize(elem->get("size") * scale); - else if(elem->has("maxSize")) - setMaxSize(elem->get("maxSize") * scale); - else if(elem->has("minSize")) - setMinSize(elem->get("minSize") * scale); - } + if (properties & ThemeFlags::SIZE) { + if (elem->has("size")) + setResize(elem->get("size") * scale); + else if (elem->has("maxSize")) + setMaxSize(elem->get("maxSize") * scale); + else if (elem->has("minSize")) + setMinSize(elem->get("minSize") * scale); + } - if(elem->has("default")) - setDefaultImage(elem->get("default")); + if (elem->has("default")) + setDefaultImage(elem->get("default")); - if(properties & PATH && elem->has("path")) - { - bool tile = (elem->has("tile") && elem->get("tile")); - setImage(elem->get("path"), tile); - } + if (properties & PATH && elem->has("path")) { + bool tile = (elem->has("tile") && elem->get("tile")); + setImage(elem->get("path"), tile); + } - if(properties & COLOR) - { - if(elem->has("color")) - setColorShift(elem->get("color")); - - if (elem->has("colorEnd")) - setColorShiftEnd(elem->get("colorEnd")); - - if (elem->has("gradientType")) - setColorGradientHorizontal(!(elem->get("gradientType").compare("horizontal"))); - } + if (properties & COLOR) { + if (elem->has("color")) + setColorShift(elem->get("color")); + if (elem->has("colorEnd")) + setColorShiftEnd(elem->get("colorEnd")); + if (elem->has("gradientType")) + setColorGradientHorizontal(!(elem->get("gradientType").compare("horizontal"))); + } } std::vector ImageComponent::getHelpPrompts() { - std::vector ret; - ret.push_back(HelpPrompt("a", "select")); - return ret; + std::vector ret; + ret.push_back(HelpPrompt("a", "select")); + return ret; } diff --git a/es-core/src/components/ImageComponent.h b/es-core/src/components/ImageComponent.h index 18ef31dab..e33f5f93e 100644 --- a/es-core/src/components/ImageComponent.h +++ b/es-core/src/components/ImageComponent.h @@ -1,3 +1,9 @@ +// +// ImageComponent.h +// +// Handles images: loading, resizing, cropping, color shifting etc. +// + #pragma once #ifndef ES_CORE_COMPONENTS_IMAGE_COMPONENT_H #define ES_CORE_COMPONENTS_IMAGE_COMPONENT_H @@ -11,102 +17,108 @@ class TextureResource; class ImageComponent : public GuiComponent { public: - ImageComponent(Window* window, bool forceLoad = false, bool dynamic = true); - virtual ~ImageComponent(); + ImageComponent(Window* window, bool forceLoad = false, bool dynamic = true); + virtual ~ImageComponent(); - void setDefaultImage(std::string path); + void setDefaultImage(std::string path); - //Loads the image at the given filepath. Will tile if tile is true (retrieves texture as tiling, creates vertices accordingly). - void setImage(std::string path, bool tile = false); - //Loads an image from memory. - void setImage(const char* image, size_t length, bool tile = false); - //Use an already existing texture. - void setImage(const std::shared_ptr& texture); + // Loads the image at the given filepath. Will tile if tile is true (retrieves texture + // as tiling, creates vertices accordingly). + void setImage(std::string path, bool tile = false); + // Loads an image from memory. + void setImage(const char* image, size_t length, bool tile = false); + // Use an already existing texture. + void setImage(const std::shared_ptr& texture); - void onSizeChanged() override; - void setOpacity(unsigned char opacity) override; + void onSizeChanged() override; + void setOpacity(unsigned char opacity) override; - // Resize the image to fit this size. If one axis is zero, scale that axis to maintain aspect ratio. - // If both are non-zero, potentially break the aspect ratio. If both are zero, no resizing. - // Can be set before or after an image is loaded. - // setMaxSize() and setResize() are mutually exclusive. - void setResize(float width, float height); - inline void setResize(const Vector2f& size) { setResize(size.x(), size.y()); } + // Resize the image to fit this size. If one axis is zero, scale that axis to maintain + // aspect ratio. If both are non-zero, potentially break the aspect ratio. If both are + // zero, don't do any resizing. + // Can be set before or after an image is loaded. + // setMaxSize() and setResize() are mutually exclusive. + void setResize(float width, float height); + inline void setResize(const Vector2f& size) { setResize(size.x(), size.y()); } - // Resize the image to be as large as possible but fit within a box of this size. - // Can be set before or after an image is loaded. - // Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive. - void setMaxSize(float width, float height); - inline void setMaxSize(const Vector2f& size) { setMaxSize(size.x(), size.y()); } + // Resize the image to be as large as possible but fit within a box of this size. + // Can be set before or after an image is loaded. + // Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive. + void setMaxSize(float width, float height); + inline void setMaxSize(const Vector2f& size) { setMaxSize(size.x(), size.y()); } - void setMinSize(float width, float height); - inline void setMinSize(const Vector2f& size) { setMinSize(size.x(), size.y()); } + void setMinSize(float width, float height); + inline void setMinSize(const Vector2f& size) { setMinSize(size.x(), size.y()); } - Vector2f getRotationSize() const override; + Vector2f getRotationSize() const override; - // Applied AFTER image positioning and sizing - // cropTop(0.2) will crop 20% of the top of the image. - void cropLeft(float percent); - void cropTop(float percent); - void cropRight(float percent); - void cropBot(float percent); - void crop(float left, float top, float right, float bot); - void uncrop(); + // Applied AFTER image positioning and sizing. + // cropTop(0.2) will crop 20% of the top of the image. + void cropLeft(float percent); + void cropTop(float percent); + void cropRight(float percent); + void cropBot(float percent); + void crop(float left, float top, float right, float bot); + void uncrop(); - // Multiply all pixels in the image by this color when rendering. - void setColorShift(unsigned int color) override; - void setColorShiftEnd(unsigned int color); - void setColorGradientHorizontal(bool horizontal); + // Multiply all pixels in the image by this color when rendering. + void setColorShift(unsigned int color) override; + void setColorShiftEnd(unsigned int color); + void setColorGradientHorizontal(bool horizontal); - void setFlipX(bool flip); // Mirror on the X axis. - void setFlipY(bool flip); // Mirror on the Y axis. + void setFlipX(bool flip); // Mirror on the X axis. + void setFlipY(bool flip); // Mirror on the Y axis. - void setRotateByTargetSize(bool rotate); // Flag indicating if rotation should be based on target size vs. actual size. + // Flag indicating if rotation should be based on target size vs. actual size. + void setRotateByTargetSize(bool rotate); - // Returns the size of the current texture, or (0, 0) if none is loaded. May be different than drawn size (use getSize() for that). - Vector2i getTextureSize() const; + // Returns the size of the current texture, or (0, 0) if none is loaded. + // May be different than drawn size (use getSize() for that). + Vector2i getTextureSize() const; - Vector2f getSize() const override; + Vector2f getSize() const override; - bool hasImage(); + bool hasImage(); - void render(const Transform4x4f& parentTrans) override; + void render(const Transform4x4f& parentTrans) override; - virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) override; + virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, + const std::string& element, unsigned int properties) override; - virtual std::vector getHelpPrompts() override; + virtual std::vector getHelpPrompts() override; + + std::shared_ptr getTexture() { return mTexture; }; - std::shared_ptr getTexture() { return mTexture; }; private: - Vector2f mTargetSize; + Vector2f mTargetSize; - bool mFlipX, mFlipY, mTargetIsMax, mTargetIsMin; + bool mFlipX, mFlipY, mTargetIsMax, mTargetIsMin; - // Calculates the correct mSize from our resizing information (set by setResize/setMaxSize). - // Used internally whenever the resizing parameters or texture change. - void resize(); + // Calculates the correct mSize from our resizing information (set by setResize/setMaxSize). + // Used internally whenever the resizing parameters or texture change. + void resize(); - Renderer::Vertex mVertices[4]; + Renderer::Vertex mVertices[4]; - void updateVertices(); - void updateColors(); - void fadeIn(bool textureLoaded); + void updateVertices(); + void updateColors(); + void fadeIn(bool textureLoaded); - unsigned int mColorShift; - unsigned int mColorShiftEnd; - bool mColorGradientHorizontal; + unsigned int mColorShift; + unsigned int mColorShiftEnd; + bool mColorGradientHorizontal; - std::string mDefaultPath; + std::string mDefaultPath; - std::shared_ptr mTexture; - unsigned char mFadeOpacity; - bool mFading; - bool mForceLoad; - bool mDynamic; - bool mRotateByTargetSize; + std::shared_ptr mTexture; + unsigned char mFadeOpacity; + bool mFading; + bool mForceLoad; + bool mDynamic; + bool mRotateByTargetSize; - Vector2f mTopLeftCrop; - Vector2f mBottomRightCrop; + Vector2f mTopLeftCrop; + Vector2f mBottomRightCrop; }; #endif // ES_CORE_COMPONENTS_IMAGE_COMPONENT_H diff --git a/es-core/src/components/ImageGridComponent.h b/es-core/src/components/ImageGridComponent.h index d889bf6bd..a9fad3a94 100644 --- a/es-core/src/components/ImageGridComponent.h +++ b/es-core/src/components/ImageGridComponent.h @@ -1,3 +1,9 @@ +// +// ImageGridComponent.cpp +// +// X*Y image grid, used by GridGameListView. +// + #pragma once #ifndef ES_CORE_COMPONENTS_IMAGE_GRID_COMPONENT_H #define ES_CORE_COMPONENTS_IMAGE_GRID_COMPONENT_H @@ -10,714 +16,698 @@ #define EXTRAITEMS 2 -enum ScrollDirection -{ - SCROLL_VERTICALLY, - SCROLL_HORIZONTALLY +enum ScrollDirection { + SCROLL_VERTICALLY, + SCROLL_HORIZONTALLY }; -enum ImageSource -{ - THUMBNAIL, - IMAGE, - MARQUEE +enum ImageSource { + THUMBNAIL, + IMAGE, + MARQUEE }; -struct ImageGridData -{ - std::string texturePath; +struct ImageGridData { + std::string texturePath; }; template class ImageGridComponent : public IList { protected: - using IList::mEntries; - using IList::mScrollTier; - using IList::listUpdate; - using IList::listInput; - using IList::listRenderTitleOverlay; - using IList::getTransform; - using IList::mSize; - using IList::mCursor; - using IList::mWindow; -// The following change is required for compilation with Clang. -// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2070 -// using IList::Entry; - using IList::IList; + using IList::mEntries; + using IList::mScrollTier; + using IList::listUpdate; + using IList::listInput; + using IList::listRenderTitleOverlay; + using IList::getTransform; + using IList::mSize; + using IList::mCursor; + using IList::mWindow; + // The following change is required for compilation with Clang. + // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2070 + // using IList::Entry; + using IList::IList; public: - using IList::size; - using IList::isScrolling; - using IList::stopScrolling; + using IList::size; + using IList::isScrolling; + using IList::stopScrolling; - ImageGridComponent(Window* window); + ImageGridComponent(Window* window); - void add(const std::string& name, const std::string& imagePath, const T& obj); + void add(const std::string& name, const std::string& imagePath, const T& obj); - bool input(InputConfig* config, Input input) override; - void update(int deltaTime) override; - void render(const Transform4x4f& parentTrans) override; - virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) override; + bool input(InputConfig* config, Input input) override; + void update(int deltaTime) override; + void render(const Transform4x4f& parentTrans) override; + virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, + const std::string& element, unsigned int properties) override; - void onSizeChanged() override; - inline void setCursorChangedCallback(const std::function& func) { mCursorChangedCallback = func; } + void onSizeChanged() override; + inline void setCursorChangedCallback(const std::function& func) + { mCursorChangedCallback = func; } - ImageSource getImageSource() { return mImageSource; }; + ImageSource getImageSource() { return mImageSource; }; protected: - virtual void onCursorChanged(const CursorState& state) override; + virtual void onCursorChanged(const CursorState& state) override; private: - // TILES - void buildTiles(); - void updateTiles(bool ascending = true, bool allowAnimation = true, bool updateSelectedState = true); - void updateTileAtPos(int tilePos, int imgPos, bool allowAnimation, bool updateSelectedState); - void calcGridDimension(); - bool isScrollLoop(); + // Tiles. + void buildTiles(); + void updateTiles(bool ascending = true, bool allowAnimation = true, + bool updateSelectedState = true); + void updateTileAtPos(int tilePos, int imgPos, bool allowAnimation, bool updateSelectedState); + void calcGridDimension(); + bool isScrollLoop(); - bool isVertical() { return mScrollDirection == SCROLL_VERTICALLY; }; + bool isVertical() { return mScrollDirection == SCROLL_VERTICALLY; }; + // Images and entries. + bool mEntriesDirty; + int mLastCursor; + std::string mDefaultGameTexture; + std::string mDefaultFolderTexture; - // IMAGES & ENTRIES - bool mEntriesDirty; - int mLastCursor; - std::string mDefaultGameTexture; - std::string mDefaultFolderTexture; + // Tiles. + bool mLastRowPartial; + Vector2f mAutoLayout; + float mAutoLayoutZoom; - // TILES - bool mLastRowPartial; - Vector2f mAutoLayout; - float mAutoLayoutZoom; + Vector4f mPadding; + Vector2f mMargin; + Vector2f mTileSize; + Vector2i mGridDimension; + std::shared_ptr mTheme; + std::vector< std::shared_ptr > mTiles; - Vector4f mPadding; - Vector2f mMargin; - Vector2f mTileSize; - Vector2i mGridDimension; - std::shared_ptr mTheme; - std::vector< std::shared_ptr > mTiles; + int mStartPosition; - int mStartPosition; + float mCamera; + float mCameraDirection; - float mCamera; - float mCameraDirection; - - // MISCELLANEOUS - bool mAnimate; - bool mCenterSelection; - bool mScrollLoop; - ScrollDirection mScrollDirection; - ImageSource mImageSource; - std::function mCursorChangedCallback; + // Miscellaneous. + bool mAnimate; + bool mCenterSelection; + bool mScrollLoop; + ScrollDirection mScrollDirection; + ImageSource mImageSource; + std::function mCursorChangedCallback; }; template ImageGridComponent::ImageGridComponent(Window* window) : IList(window) { - Vector2f screen = Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); + Vector2f screen = Vector2f((float)Renderer::getScreenWidth(), + (float)Renderer::getScreenHeight()); - mCamera = 0.0; - mCameraDirection = 1.0; + mCamera = 0.0; + mCameraDirection = 1.0; - mAutoLayout = Vector2f::Zero(); - mAutoLayoutZoom = 1.0; + mAutoLayout = Vector2f::Zero(); + mAutoLayoutZoom = 1.0; - mStartPosition = 0; + mStartPosition = 0; - mEntriesDirty = true; - mLastCursor = 0; - mDefaultGameTexture = ":/graphics/cartridge.svg"; - mDefaultFolderTexture = ":/graphics/folder.svg"; + mEntriesDirty = true; + mLastCursor = 0; + mDefaultGameTexture = ":/graphics/cartridge.svg"; + mDefaultFolderTexture = ":/graphics/folder.svg"; - mSize = screen * 0.80f; - mMargin = screen * 0.07f; - mPadding = Vector4f::Zero(); - mTileSize = GridTileComponent::getDefaultTileSize(); + mSize = screen * 0.80f; + mMargin = screen * 0.07f; + mPadding = Vector4f::Zero(); + mTileSize = GridTileComponent::getDefaultTileSize(); - mAnimate = true; - mCenterSelection = false; - mScrollLoop = false; - mScrollDirection = SCROLL_VERTICALLY; - mImageSource = THUMBNAIL; + mAnimate = true; + mCenterSelection = false; + mScrollLoop = false; + mScrollDirection = SCROLL_VERTICALLY; + mImageSource = THUMBNAIL; } template void ImageGridComponent::add(const std::string& name, const std::string& imagePath, const T& obj) { - typename IList::Entry entry; - entry.name = name; - entry.object = obj; - entry.data.texturePath = imagePath; + typename IList::Entry entry; + entry.name = name; + entry.object = obj; + entry.data.texturePath = imagePath; - static_cast*>(this)->add(entry); - mEntriesDirty = true; + static_cast*>(this)->add(entry); + mEntriesDirty = true; } template bool ImageGridComponent::input(InputConfig* config, Input input) { - if(input.value != 0) - { - int idx = isVertical() ? 0 : 1; + if (input.value != 0) { + int idx = isVertical() ? 0 : 1; - Vector2i dir = Vector2i::Zero(); - if(config->isMappedLike("up", input)) - dir[1 ^ idx] = -1; - else if(config->isMappedLike("down", input)) - dir[1 ^ idx] = 1; - else if(config->isMappedLike("left", input)) - dir[0 ^ idx] = -1; - else if(config->isMappedLike("right", input)) - dir[0 ^ idx] = 1; + Vector2i dir = Vector2i::Zero(); + if (config->isMappedLike("up", input)) + dir[1 ^ idx] = -1; + else if (config->isMappedLike("down", input)) + dir[1 ^ idx] = 1; + else if (config->isMappedLike("left", input)) + dir[0 ^ idx] = -1; + else if (config->isMappedLike("right", input)) + dir[0 ^ idx] = 1; - if(dir != Vector2i::Zero()) - { - if (isVertical()) - listInput(dir.x() + dir.y() * mGridDimension.x()); - else - listInput(dir.x() + dir.y() * mGridDimension.y()); - return true; - } - }else{ - if(config->isMappedLike("up", input) || config->isMappedLike("down", input) || config->isMappedLike("left", input) || config->isMappedLike("right", input)) - { - stopScrolling(); - } - } + if (dir != Vector2i::Zero()) { + if (isVertical()) + listInput(dir.x() + dir.y() * mGridDimension.x()); + else + listInput(dir.x() + dir.y() * mGridDimension.y()); + return true; + } + } + else { + if (config->isMappedLike("up", input) || config->isMappedLike("down", input) || + config->isMappedLike("left", input) || config->isMappedLike("right", input)) + stopScrolling(); + } - return GuiComponent::input(config, input); + return GuiComponent::input(config, input); } template void ImageGridComponent::update(int deltaTime) { - GuiComponent::update(deltaTime); - listUpdate(deltaTime); + GuiComponent::update(deltaTime); + listUpdate(deltaTime); - for(auto it = mTiles.begin(); it != mTiles.end(); it++) - (*it)->update(deltaTime); + for (auto it = mTiles.begin(); it != mTiles.end(); it++) + (*it)->update(deltaTime); } template void ImageGridComponent::render(const Transform4x4f& parentTrans) { - Transform4x4f trans = getTransform() * parentTrans; - Transform4x4f tileTrans = trans; + Transform4x4f trans = getTransform() * parentTrans; + Transform4x4f tileTrans = trans; - float offsetX = isVertical() ? 0.0f : mCamera * mCameraDirection * (mTileSize.x() + mMargin.x()); - float offsetY = isVertical() ? mCamera * mCameraDirection * (mTileSize.y() + mMargin.y()) : 0.0f; + float offsetX = isVertical() ? 0.0f : mCamera * mCameraDirection * + (mTileSize.x() + mMargin.x()); + float offsetY = isVertical() ? mCamera * mCameraDirection * + (mTileSize.y() + mMargin.y()) : 0.0f; - tileTrans.translate(Vector3f(offsetX, offsetY, 0.0)); + tileTrans.translate(Vector3f(offsetX, offsetY, 0.0)); - if(mEntriesDirty) - { - updateTiles(); - mEntriesDirty = false; - } + if (mEntriesDirty) { + updateTiles(); + mEntriesDirty = false; + } - // Create a clipRect to hide tiles used to buffer texture loading - float scaleX = trans.r0().x(); - float scaleY = trans.r1().y(); + // Create a clipRect to hide tiles used to buffer texture loading. + float scaleX = trans.r0().x(); + float scaleY = trans.r1().y(); - Vector2i pos((int)Math::round(trans.translation()[0]), (int)Math::round(trans.translation()[1])); - Vector2i size((int)Math::round(mSize.x() * scaleX), (int)Math::round(mSize.y() * scaleY)); + Vector2i pos((int)Math::round(trans.translation()[0]), + (int)Math::round(trans.translation()[1])); + Vector2i size((int)Math::round(mSize.x() * scaleX), + (int)Math::round(mSize.y() * scaleY)); - Renderer::pushClipRect(pos, size); + Renderer::pushClipRect(pos, size); - // Render all the tiles but the selected one - std::shared_ptr selectedTile = NULL; - for(auto it = mTiles.begin(); it != mTiles.end(); it++) - { - std::shared_ptr tile = (*it); + // Render all the tiles but the selected one. + std::shared_ptr selectedTile = nullptr; + for (auto it = mTiles.begin(); it != mTiles.end(); it++) { + std::shared_ptr tile = (*it); + // If it's the selected image, keep it for later, otherwise render it now. + if (tile->isSelected()) + selectedTile = tile; + else + tile->render(tileTrans); + } - // If it's the selected image, keep it for later, otherwise render it now - if(tile->isSelected()) - selectedTile = tile; - else - tile->render(tileTrans); - } + Renderer::popClipRect(); - Renderer::popClipRect(); + // Render the selected image on top of the others. + if (selectedTile != nullptr) + selectedTile->render(tileTrans); - // Render the selected image on top of the others - if (selectedTile != NULL) - selectedTile->render(tileTrans); + listRenderTitleOverlay(trans); - listRenderTitleOverlay(trans); - - GuiComponent::renderChildren(trans); + GuiComponent::renderChildren(trans); } template -void ImageGridComponent::applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) +void ImageGridComponent::applyTheme(const std::shared_ptr& theme, + const std::string& view, const std::string& element, unsigned int properties) { - // Apply theme to GuiComponent but not size property, which will be applied at the end of this function - GuiComponent::applyTheme(theme, view, element, properties ^ ThemeFlags::SIZE); + // Apply theme to GuiComponent but not the size property, which will be applied + // at the end of this function. + GuiComponent::applyTheme(theme, view, element, properties ^ ThemeFlags::SIZE); - // Keep the theme pointer to apply it on the tiles later on - mTheme = theme; + // Keep the theme pointer to apply it on the tiles later on. + mTheme = theme; - Vector2f screen = Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); + Vector2f screen = Vector2f((float)Renderer::getScreenWidth(), + (float)Renderer::getScreenHeight()); - const ThemeData::ThemeElement* elem = theme->getElement(view, element, "imagegrid"); - if (elem) - { - if (elem->has("margin")) - mMargin = elem->get("margin") * screen; + const ThemeData::ThemeElement* elem = theme->getElement(view, element, "imagegrid"); + if (elem) { + if (elem->has("margin")) + mMargin = elem->get("margin") * screen; - if (elem->has("padding")) - mPadding = elem->get("padding") * Vector4f(screen.x(), screen.y(), screen.x(), screen.y()); + if (elem->has("padding")) + mPadding = elem->get("padding") * + Vector4f(screen.x(), screen.y(), screen.x(), screen.y()); - if (elem->has("autoLayout")) - mAutoLayout = elem->get("autoLayout"); + if (elem->has("autoLayout")) + mAutoLayout = elem->get("autoLayout"); - if (elem->has("autoLayoutSelectedZoom")) - mAutoLayoutZoom = elem->get("autoLayoutSelectedZoom"); + if (elem->has("autoLayoutSelectedZoom")) + mAutoLayoutZoom = elem->get("autoLayoutSelectedZoom"); - if (elem->has("imageSource")) - { - auto direction = elem->get("imageSource"); - if (direction == "image") - mImageSource = IMAGE; - else if (direction == "marquee") - mImageSource = MARQUEE; - else - mImageSource = THUMBNAIL; - } - else - mImageSource = THUMBNAIL; + if (elem->has("imageSource")) { + auto direction = elem->get("imageSource"); + if (direction == "image") + mImageSource = IMAGE; + else if (direction == "marquee") + mImageSource = MARQUEE; + else + mImageSource = THUMBNAIL; + } + else { + mImageSource = THUMBNAIL; + } - if (elem->has("scrollDirection")) - mScrollDirection = (ScrollDirection)(elem->get("scrollDirection") == "horizontal"); + if (elem->has("scrollDirection")) + mScrollDirection = (ScrollDirection)(elem-> + get("scrollDirection") == "horizontal"); - if (elem->has("centerSelection")) - { - mCenterSelection = (elem->get("centerSelection")); + if (elem->has("centerSelection")) { + mCenterSelection = (elem->get("centerSelection")); - if (elem->has("scrollLoop")) - mScrollLoop = (elem->get("scrollLoop")); - } + if (elem->has("scrollLoop")) + mScrollLoop = (elem->get("scrollLoop")); + } - if (elem->has("animate")) - mAnimate = (elem->get("animate")); - else - mAnimate = true; + if (elem->has("animate")) + mAnimate = (elem->get("animate")); + else + mAnimate = true; - if (elem->has("gameImage")) - { - std::string path = elem->get("gameImage"); + if (elem->has("gameImage")) { + std::string path = elem->get("gameImage"); - if (!ResourceManager::getInstance()->fileExists(path)) - LOG(LogWarning) << "Could not replace default game image, check path: " << path; - else - { - std::string oldDefaultGameTexture = mDefaultGameTexture; - mDefaultGameTexture = path; + if (!ResourceManager::getInstance()->fileExists(path)) { + LOG(LogWarning) << "Could not replace default game image, check path: " << path; + } + else { + std::string oldDefaultGameTexture = mDefaultGameTexture; + mDefaultGameTexture = path; - // mEntries are already loaded at this point, - // so we need to update them with new game image texture - for (auto it = mEntries.begin(); it != mEntries.end(); it++) - { - if ((*it).data.texturePath == oldDefaultGameTexture) - (*it).data.texturePath = mDefaultGameTexture; - } - } - } + // mEntries are already loaded at this point, so we need to + // update them with the new game image texture. + for (auto it = mEntries.begin(); it != mEntries.end(); it++) { + if ((*it).data.texturePath == oldDefaultGameTexture) + (*it).data.texturePath = mDefaultGameTexture; + } + } + } - if (elem->has("folderImage")) - { - std::string path = elem->get("folderImage"); + if (elem->has("folderImage")) { + std::string path = elem->get("folderImage"); - if (!ResourceManager::getInstance()->fileExists(path)) - LOG(LogWarning) << "Could not replace default folder image, check path: " << path; - else - { - std::string oldDefaultFolderTexture = mDefaultFolderTexture; - mDefaultFolderTexture = path; + if (!ResourceManager::getInstance()->fileExists(path)) { + LOG(LogWarning) << "Could not replace default folder image, check path: " << path; + } + else { + std::string oldDefaultFolderTexture = mDefaultFolderTexture; + mDefaultFolderTexture = path; - // mEntries are already loaded at this point, - // so we need to update them with new folder image texture - for (auto it = mEntries.begin(); it != mEntries.end(); it++) - { - if ((*it).data.texturePath == oldDefaultFolderTexture) - (*it).data.texturePath = mDefaultFolderTexture; - } - } - } - } + // mEntries are already loaded at this point, so we need to + // update them with new folder image texture. + for (auto it = mEntries.begin(); it != mEntries.end(); it++) { + if ((*it).data.texturePath == oldDefaultFolderTexture) + (*it).data.texturePath = mDefaultFolderTexture; + } + } + } + } - // We still need to manually get the grid tile size here, - // so we can recalculate the new grid dimension, and THEN (re)build the tiles - elem = theme->getElement(view, "default", "gridtile"); + // We still need to manually get the grid tile size here, so we can recalculate + // the new grid dimension, and THEN (re)build the tiles. + elem = theme->getElement(view, "default", "gridtile"); - mTileSize = elem && elem->has("size") ? - elem->get("size") * screen : - GridTileComponent::getDefaultTileSize(); + mTileSize = elem && elem->has("size") ? + elem->get("size") * screen : + GridTileComponent::getDefaultTileSize(); - // Apply size property, will trigger a call to onSizeChanged() which will build the tiles - GuiComponent::applyTheme(theme, view, element, ThemeFlags::SIZE); + // Apply size property which will trigger a call to onSizeChanged() which will build the tiles. + GuiComponent::applyTheme(theme, view, element, ThemeFlags::SIZE); - // Trigger the call manually if the theme have no "imagegrid" element - if (!elem) - buildTiles(); + // Trigger the call manually if the theme have no "imagegrid" element. + if (!elem) + buildTiles(); } template void ImageGridComponent::onSizeChanged() { - buildTiles(); - updateTiles(); + buildTiles(); + updateTiles(); } template void ImageGridComponent::onCursorChanged(const CursorState& state) { - if (mLastCursor == mCursor) - { - if (state == CURSOR_STOPPED && mCursorChangedCallback) - mCursorChangedCallback(state); + if (mLastCursor == mCursor) { + if (state == CURSOR_STOPPED && mCursorChangedCallback) + mCursorChangedCallback(state); + return; + } - return; - } + bool direction = mCursor >= mLastCursor; + int diff = direction ? mCursor - mLastCursor : mLastCursor - mCursor; + if (isScrollLoop() && diff == mEntries.size() - 1) + direction = !direction; - bool direction = mCursor >= mLastCursor; - int diff = direction ? mCursor - mLastCursor : mLastCursor - mCursor; - if (isScrollLoop() && diff == mEntries.size() - 1) - { - direction = !direction; - } + int oldStart = mStartPosition; - int oldStart = mStartPosition; + int dimScrollable = (isVertical() ? mGridDimension.y() : mGridDimension.x()) - 2 * EXTRAITEMS; + int dimOpposite = isVertical() ? mGridDimension.x() : mGridDimension.y(); - int dimScrollable = (isVertical() ? mGridDimension.y() : mGridDimension.x()) - 2 * EXTRAITEMS; - int dimOpposite = isVertical() ? mGridDimension.x() : mGridDimension.y(); + int centralCol = (int)(dimScrollable - 0.5) / 2; + int maxCentralCol = dimScrollable / 2; - int centralCol = (int)(dimScrollable - 0.5) / 2; - int maxCentralCol = dimScrollable / 2; + int oldCol = (mLastCursor / dimOpposite); + int col = (mCursor / dimOpposite); - int oldCol = (mLastCursor / dimOpposite); - int col = (mCursor / dimOpposite); + int lastCol = ((mEntries.size() - 1) / dimOpposite); - int lastCol = ((mEntries.size() - 1) / dimOpposite); + int lastScroll = std::max(0, (lastCol + 1 - dimScrollable)); - int lastScroll = std::max(0, (lastCol + 1 - dimScrollable)); + float startPos = 0; + float endPos = 1; - float startPos = 0; - float endPos = 1; + if (((GuiComponent*)this)->isAnimationPlaying(2)) { + startPos = 0; + ((GuiComponent*)this)->cancelAnimation(2); + updateTiles(direction, false, false); + } - if (((GuiComponent*)this)->isAnimationPlaying(2)) - { - startPos = 0; - ((GuiComponent*)this)->cancelAnimation(2); - updateTiles(direction, false, false); - } + if (mAnimate) { + std::shared_ptr oldTile = nullptr; + std::shared_ptr newTile = nullptr; - if (mAnimate) { + int oldIdx = mLastCursor - mStartPosition + (dimOpposite * EXTRAITEMS); + if (oldIdx >= 0 && oldIdx < mTiles.size()) + oldTile = mTiles[oldIdx]; - std::shared_ptr oldTile = nullptr; - std::shared_ptr newTile = nullptr; + int newIdx = mCursor - mStartPosition + (dimOpposite * EXTRAITEMS); + if (isScrollLoop()) { + if (newIdx < 0) + newIdx += mEntries.size(); + else if (newIdx >= mTiles.size()) + newIdx -= mEntries.size(); + } - int oldIdx = mLastCursor - mStartPosition + (dimOpposite * EXTRAITEMS); - if (oldIdx >= 0 && oldIdx < mTiles.size()) - oldTile = mTiles[oldIdx]; + if (newIdx >= 0 && newIdx < mTiles.size()) + newTile = mTiles[newIdx]; - int newIdx = mCursor - mStartPosition + (dimOpposite * EXTRAITEMS); - if (isScrollLoop()) { - if (newIdx < 0) - newIdx += mEntries.size(); - else if (newIdx >= mTiles.size()) - newIdx -= mEntries.size(); - } + for (auto it = mTiles.begin(); it != mTiles.end(); it++) { + if ((*it)->isSelected() && *it != oldTile && *it != newTile) { + startPos = 0; + (*it)->setSelected(false, false, nullptr); + } + } - if (newIdx >= 0 && newIdx < mTiles.size()) - newTile = mTiles[newIdx]; + Vector3f oldPos = Vector3f::Zero(); - for (auto it = mTiles.begin(); it != mTiles.end(); it++) { - if ((*it)->isSelected() && *it != oldTile && *it != newTile) { - startPos = 0; - (*it)->setSelected(false, false, nullptr); - } - } + if (oldTile != nullptr && oldTile != newTile) { + oldPos = oldTile->getBackgroundPosition(); + oldTile->setSelected(false, true, nullptr, true); + } - Vector3f oldPos = Vector3f::Zero(); + if (newTile != nullptr) + newTile->setSelected(true, true, oldPos == Vector3f::Zero() ? nullptr : &oldPos, true); + } - if (oldTile != nullptr && oldTile != newTile) { - oldPos = oldTile->getBackgroundPosition(); - oldTile->setSelected(false, true, nullptr, true); - } + int firstVisibleCol = mStartPosition / dimOpposite; - if (newTile != nullptr) - newTile->setSelected(true, true, oldPos == Vector3f::Zero() ? nullptr : &oldPos, true); - } + if ((col < centralCol || (col == 0 && col == centralCol)) && !mCenterSelection) { + mStartPosition = 0; + } + else if ((col - centralCol) > lastScroll && !mCenterSelection && !isScrollLoop()) { + mStartPosition = lastScroll * dimOpposite; + } + else if ((maxCentralCol != centralCol && col == firstVisibleCol + maxCentralCol) || + col == firstVisibleCol + centralCol) { + if (col == firstVisibleCol + maxCentralCol) + mStartPosition = (col - maxCentralCol) * dimOpposite; + else + mStartPosition = (col - centralCol) * dimOpposite; + } + else { + if (oldCol == firstVisibleCol + maxCentralCol) + mStartPosition = (col - maxCentralCol) * dimOpposite; + else + mStartPosition = (col - centralCol) * dimOpposite; + } - int firstVisibleCol = mStartPosition / dimOpposite; + auto lastCursor = mLastCursor; + mLastCursor = mCursor; - if ((col < centralCol || (col == 0 && col == centralCol)) && !mCenterSelection) - mStartPosition = 0; - else if ((col - centralCol) > lastScroll && !mCenterSelection && !isScrollLoop()) - mStartPosition = lastScroll * dimOpposite; - else if ((maxCentralCol != centralCol && col == firstVisibleCol + maxCentralCol) || col == firstVisibleCol + centralCol) - { - if (col == firstVisibleCol + maxCentralCol) - mStartPosition = (col - maxCentralCol) * dimOpposite; - else - mStartPosition = (col - centralCol) * dimOpposite; - } - else - { - if (oldCol == firstVisibleCol + maxCentralCol) - mStartPosition = (col - maxCentralCol) * dimOpposite; - else - mStartPosition = (col - centralCol) * dimOpposite; - } + mCameraDirection = direction ? -1.0f : 1.0f; + mCamera = 0; - auto lastCursor = mLastCursor; - mLastCursor = mCursor; + if (lastCursor < 0 || !mAnimate) { + updateTiles(direction, mAnimate && (lastCursor >= 0 || isScrollLoop())); - mCameraDirection = direction ? -1.0f : 1.0f; - mCamera = 0; + if (mCursorChangedCallback) + mCursorChangedCallback(state); - if (lastCursor < 0 || !mAnimate) - { - updateTiles(direction, mAnimate && (lastCursor >= 0 || isScrollLoop())); + return; + } - if (mCursorChangedCallback) - mCursorChangedCallback(state); + if (mCursorChangedCallback) + mCursorChangedCallback(state); - return; - } + bool moveCamera = (oldStart != mStartPosition); - if (mCursorChangedCallback) - mCursorChangedCallback(state); + auto func = [this, startPos, endPos, moveCamera](float t) { + if (!moveCamera) + return; - bool moveCamera = (oldStart != mStartPosition); + t -= 1; // cubic ease out + float pct = Math::lerp(0, 1, t*t*t + 1); + t = startPos * (1.0f - pct) + endPos * pct; + mCamera = t; + }; - auto func = [this, startPos, endPos, moveCamera](float t) - { - if (!moveCamera) - return; - - t -= 1; // cubic ease out - float pct = Math::lerp(0, 1, t*t*t + 1); - t = startPos * (1.0f - pct) + endPos * pct; - - mCamera = t; - }; - - ((GuiComponent*)this)->setAnimation(new LambdaAnimation(func, 250), 0, [this, direction] { - mCamera = 0; - updateTiles(direction, false); - }, false, 2); + ((GuiComponent*)this)->setAnimation(new LambdaAnimation(func, 250), 0, [this, direction] { + mCamera = 0; + updateTiles(direction, false); + }, false, 2); } -// Create and position tiles (mTiles) +// Create and position tiles (mTiles). template void ImageGridComponent::buildTiles() { - mStartPosition = 0; - mTiles.clear(); + mStartPosition = 0; + mTiles.clear(); - calcGridDimension(); + calcGridDimension(); - if (mCenterSelection) - { - int dimScrollable = (isVertical() ? mGridDimension.y() : mGridDimension.x()) - 2 * EXTRAITEMS; - mStartPosition -= (int) Math::floorf(dimScrollable / 2.0f); - } + if (mCenterSelection) { + int dimScrollable = (isVertical() ? mGridDimension.y() : + mGridDimension.x()) - 2 * EXTRAITEMS; + mStartPosition -= (int) Math::floorf(dimScrollable / 2.0f); + } - Vector2f tileDistance = mTileSize + mMargin; + Vector2f tileDistance = mTileSize + mMargin; - if (mAutoLayout.x() != 0 && mAutoLayout.y() != 0) - { - auto x = (mSize.x() - (mMargin.x() * (mAutoLayout.x() - 1)) - mPadding.x() - mPadding.z()) / (int) mAutoLayout.x(); - auto y = (mSize.y() - (mMargin.y() * (mAutoLayout.y() - 1)) - mPadding.y() - mPadding.w()) / (int) mAutoLayout.y(); + if (mAutoLayout.x() != 0 && mAutoLayout.y() != 0) { + auto x = (mSize.x() - (mMargin.x() * (mAutoLayout.x() - 1)) - mPadding.x() - + mPadding.z()) / (int) mAutoLayout.x(); + auto y = (mSize.y() - (mMargin.y() * (mAutoLayout.y() - 1)) - mPadding.y() - + mPadding.w()) / (int) mAutoLayout.y(); - mTileSize = Vector2f(x, y); - tileDistance = mTileSize + mMargin; - } + mTileSize = Vector2f(x, y); + tileDistance = mTileSize + mMargin; + } - bool vert = isVertical(); + bool vert = isVertical(); + Vector2f startPosition = mTileSize / 2; + startPosition += mPadding.v2(); - Vector2f startPosition = mTileSize / 2; + int X; + int Y; - startPosition += mPadding.v2(); + // Layout tile size and position. + for (int y = 0; y < (vert ? mGridDimension.y() : mGridDimension.x()); y++) { + for (int x = 0; x < (vert ? mGridDimension.x() : mGridDimension.y()); x++) { + // Create tiles. + auto tile = std::make_shared(mWindow); - int X, Y; + // In Vertical mod, tiles are ordered from left to right, then from top to bottom. + // In Horizontal mod, tiles are ordered from top to bottom, then from left to right. + X = vert ? x : y - EXTRAITEMS; + Y = vert ? y - EXTRAITEMS : x; - // Layout tile size and position - for (int y = 0; y < (vert ? mGridDimension.y() : mGridDimension.x()); y++) - { - for (int x = 0; x < (vert ? mGridDimension.x() : mGridDimension.y()); x++) - { - // Create tiles - auto tile = std::make_shared(mWindow); + tile->setPosition(X * tileDistance.x() + startPosition.x(), Y * + tileDistance.y() + startPosition.y()); + tile->setOrigin(0.5f, 0.5f); + tile->setImage(""); - // In Vertical mod, tiles are ordered from left to right, then from top to bottom - // In Horizontal mod, tiles are ordered from top to bottom, then from left to right - X = vert ? x : y - EXTRAITEMS; - Y = vert ? y - EXTRAITEMS : x; + if (mTheme) + tile->applyTheme(mTheme, "grid", "gridtile", ThemeFlags::ALL); - tile->setPosition(X * tileDistance.x() + startPosition.x(), Y * tileDistance.y() + startPosition.y()); - tile->setOrigin(0.5f, 0.5f); - tile->setImage(""); + if (mAutoLayout.x() != 0 && mAutoLayout.y() != 0) + tile->forceSize(mTileSize, mAutoLayoutZoom); - if (mTheme) - tile->applyTheme(mTheme, "grid", "gridtile", ThemeFlags::ALL); - - if (mAutoLayout.x() != 0 && mAutoLayout.y() != 0) - tile->forceSize(mTileSize, mAutoLayoutZoom); - - mTiles.push_back(tile); - } - } + mTiles.push_back(tile); + } + } } template -void ImageGridComponent::updateTiles(bool ascending, bool allowAnimation, bool updateSelectedState) +void ImageGridComponent::updateTiles(bool ascending, bool allowAnimation, + bool updateSelectedState) { - if (!mTiles.size()) - return; + if (!mTiles.size()) + return; - // Stop updating the tiles at highest scroll speed - if (mScrollTier == 3) - { - for (int ti = 0; ti < (int)mTiles.size(); ti++) - { - std::shared_ptr tile = mTiles.at(ti); + // Stop updating the tiles at highest scroll speed. + if (mScrollTier == 3) { + for (int ti = 0; ti < (int)mTiles.size(); ti++) { + std::shared_ptr tile = mTiles.at(ti); - tile->setSelected(false); - tile->setImage(mDefaultGameTexture); - tile->setVisible(false); - } - return; - } + tile->setSelected(false); + tile->setImage(mDefaultGameTexture); + tile->setVisible(false); + } + return; + } - // Temporary store previous texture so they can't be unloaded - std::vector> previousTextures; - for (int ti = 0; ti < (int)mTiles.size(); ti++) - { - std::shared_ptr tile = mTiles.at(ti); - previousTextures.push_back(tile->getTexture()); - } + // Temporary store previous texture so they can't be unloaded. + std::vector> previousTextures; + for (int ti = 0; ti < (int)mTiles.size(); ti++) { + std::shared_ptr tile = mTiles.at(ti); + previousTextures.push_back(tile->getTexture()); + } - // If going down, update from top to bottom - // If going up, update from bottom to top - int scrollDirection = ascending ? 1 : -1; - int ti = ascending ? 0 : (int)mTiles.size() - 1; - int end = ascending ? (int)mTiles.size() : -1; - int img = mStartPosition + ti; + // If going down, update from top to bottom. + // If going up, update from bottom to top. + int scrollDirection = ascending ? 1 : -1; + int ti = ascending ? 0 : (int)mTiles.size() - 1; + int end = ascending ? (int)mTiles.size() : -1; + int img = mStartPosition + ti; - img -= EXTRAITEMS * (isVertical() ? mGridDimension.x() : mGridDimension.y()); + img -= EXTRAITEMS * (isVertical() ? mGridDimension.x() : mGridDimension.y()); - // Update the tiles - while (ti != end) - { - updateTileAtPos(ti, img, allowAnimation, updateSelectedState); + // Update the tiles. + while (ti != end) { + updateTileAtPos(ti, img, allowAnimation, updateSelectedState); - ti += scrollDirection; - img += scrollDirection; - } + ti += scrollDirection; + img += scrollDirection; + } - if (updateSelectedState) - mLastCursor = mCursor; + if (updateSelectedState) + mLastCursor = mCursor; - mLastCursor = mCursor; + mLastCursor = mCursor; } template -void ImageGridComponent::updateTileAtPos(int tilePos, int imgPos, bool allowAnimation, bool updateSelectedState) +void ImageGridComponent::updateTileAtPos(int tilePos, int imgPos, + bool allowAnimation, bool updateSelectedState) { - std::shared_ptr tile = mTiles.at(tilePos); + std::shared_ptr tile = mTiles.at(tilePos); - if(isScrollLoop()) - { - if (imgPos < 0) - imgPos += mEntries.size(); - else if (imgPos >= size()) - imgPos -= mEntries.size(); - } + if (isScrollLoop()) { + if (imgPos < 0) + imgPos += mEntries.size(); + else if (imgPos >= size()) + imgPos -= mEntries.size(); + } - // If we have more tiles than we have to display images on screen, hide them - if(imgPos < 0 || imgPos >= size() || tilePos < 0 || tilePos >= (int) mTiles.size()) // Same for tiles out of the buffer - { - if (updateSelectedState) - tile->setSelected(false, allowAnimation); + // If we have more tiles than we have to display images on screen, hide them. + // Same for tiles out of the buffer. + if (imgPos < 0 || imgPos >= size() || tilePos < 0 || tilePos >= (int) mTiles.size()) { + if (updateSelectedState) + tile->setSelected(false, allowAnimation); + tile->reset(); + tile->setVisible(false); + } + else { + tile->setVisible(true); - tile->reset(); - tile->setVisible(false); - } - else - { - tile->setVisible(true); + std::string imagePath = mEntries.at(imgPos).data.texturePath; - std::string imagePath = mEntries.at(imgPos).data.texturePath; + if (ResourceManager::getInstance()->fileExists(imagePath)) + tile->setImage(imagePath); + else if (mEntries.at(imgPos).object->getType() == 2) + tile->setImage(mDefaultFolderTexture); + else + tile->setImage(mDefaultGameTexture); - if (ResourceManager::getInstance()->fileExists(imagePath)) - tile->setImage(imagePath); - else if (mEntries.at(imgPos).object->getType() == 2) - tile->setImage(mDefaultFolderTexture); - else - tile->setImage(mDefaultGameTexture); + if (updateSelectedState) { + if (imgPos == mCursor && mCursor != mLastCursor) { + int dif = mCursor - tilePos; + int idx = mLastCursor - dif; - if (updateSelectedState) - { - if (imgPos == mCursor && mCursor != mLastCursor) - { - int dif = mCursor - tilePos; - int idx = mLastCursor - dif; + if (idx < 0 || idx >= mTiles.size()) + idx = 0; - if (idx < 0 || idx >= mTiles.size()) - idx = 0; + Vector3f pos = mTiles.at(idx)->getBackgroundPosition(); + tile->setSelected(true, allowAnimation, &pos); + } + else { + tile->setSelected(imgPos == mCursor, allowAnimation); + } + } - Vector3f pos = mTiles.at(idx)->getBackgroundPosition(); - tile->setSelected(true, allowAnimation, &pos); - } - else - tile->setSelected(imgPos == mCursor, allowAnimation); - } - - } + } } -// Calculate how much tiles of size mTileSize we can fit in a grid of size mSize using a margin of size mMargin +// Calculate how much tiles of size mTileSize we can fit in a grid of size mSize using +// a margin of size mMargin. template void ImageGridComponent::calcGridDimension() { - // GRID_SIZE = COLUMNS * TILE_SIZE + (COLUMNS - 1) * MARGIN - // <=> COLUMNS = (GRID_SIZE + MARGIN) / (TILE_SIZE + MARGIN) - Vector2f gridDimension = (mSize + mMargin) / (mTileSize + mMargin); + // grid_size = columns * tile_size + (columns - 1) * margin + // <=> columns = (grid_size + margin) / (tile_size + margin) + Vector2f gridDimension = (mSize + mMargin) / (mTileSize + mMargin); - if (mAutoLayout.x() != 0 && mAutoLayout.y() != 0) - gridDimension = mAutoLayout; + if (mAutoLayout.x() != 0 && mAutoLayout.y() != 0) + gridDimension = mAutoLayout; - mLastRowPartial = Math::floorf(gridDimension.y()) != gridDimension.y(); + mLastRowPartial = Math::floorf(gridDimension.y()) != gridDimension.y(); - // Ceil y dim so we can display partial last row - mGridDimension = Vector2i(gridDimension.x(), Math::ceilf(gridDimension.y())); + // Ceil y dim so we can display partial last row. + mGridDimension = Vector2i(gridDimension.x(), Math::ceilf(gridDimension.y())); - // Grid dimension validation - if (mGridDimension.x() < 1) { - LOG(LogError) << "Theme defined grid X dimension below 1"; - } - if (mGridDimension.y() < 1) { - LOG(LogError) << "Theme defined grid Y dimension below 1"; - } + // Grid dimension validation. + if (mGridDimension.x() < 1) { + LOG(LogError) << "Theme defined grid X dimension below 1"; + } + if (mGridDimension.y() < 1) { + LOG(LogError) << "Theme defined grid Y dimension below 1"; + } - // Add extra tiles to both sides : Add EXTRAITEMS before, EXTRAITEMS after - if (isVertical()) - mGridDimension.y() += 2 * EXTRAITEMS; - else - mGridDimension.x() += 2 * EXTRAITEMS; + // Add extra tiles to both sides: Add EXTRAITEMS before, EXTRAITEMS after. + if (isVertical()) + mGridDimension.y() += 2 * EXTRAITEMS; + else + mGridDimension.x() += 2 * EXTRAITEMS; } template bool ImageGridComponent::isScrollLoop() { - if (!mScrollLoop) - return false; - if (isVertical()) - return (mGridDimension.x() * (mGridDimension.y() - 2 * EXTRAITEMS)) <= mEntries.size(); - return (mGridDimension.y() * (mGridDimension.x() - 2 * EXTRAITEMS)) <= mEntries.size(); + if (!mScrollLoop) + return false; + if (isVertical()) + return (mGridDimension.x() * (mGridDimension.y() - 2 * EXTRAITEMS)) <= mEntries.size(); + return (mGridDimension.y() * (mGridDimension.x() - 2 * EXTRAITEMS)) <= mEntries.size(); }; #endif // ES_CORE_COMPONENTS_IMAGE_GRID_COMPONENT_H diff --git a/es-core/src/components/NinePatchComponent.cpp b/es-core/src/components/NinePatchComponent.cpp index 50cec7642..0a42a1d68 100644 --- a/es-core/src/components/NinePatchComponent.cpp +++ b/es-core/src/components/NinePatchComponent.cpp @@ -1,168 +1,181 @@ +// +// NinePatchComponent.cpp +// +// Breaks up an image into 3x3 patches to accomodate resizing without distortions. +// + #include "components/NinePatchComponent.h" #include "resources/TextureResource.h" #include "Log.h" #include "ThemeData.h" -NinePatchComponent::NinePatchComponent(Window* window, const std::string& path, unsigned int edgeColor, unsigned int centerColor) : GuiComponent(window), - mCornerSize(16, 16), - mEdgeColor(edgeColor), mCenterColor(centerColor), - mPath(path), - mVertices(NULL) +NinePatchComponent::NinePatchComponent( + Window* window, + const std::string& path, + unsigned int edgeColor, + unsigned int centerColor) + : GuiComponent(window), + mCornerSize(16, 16), + mEdgeColor(edgeColor), + mCenterColor(centerColor), + mPath(path), + mVertices(nullptr) { - if(!mPath.empty()) - buildVertices(); + if (!mPath.empty()) + buildVertices(); } NinePatchComponent::~NinePatchComponent() { - if (mVertices != NULL) - delete[] mVertices; + if (mVertices != nullptr) + delete[] mVertices; } void NinePatchComponent::updateColors() { - const unsigned int edgeColor = Renderer::convertColor(mEdgeColor); - const unsigned int centerColor = Renderer::convertColor(mCenterColor); + const unsigned int edgeColor = Renderer::convertColor(mEdgeColor); + const unsigned int centerColor = Renderer::convertColor(mCenterColor); - for(int i = 0; i < 6*9; ++i) - mVertices[i].col = edgeColor; + for (int i = 0; i < 6*9; ++i) + mVertices[i].col = edgeColor; - for(int i = 6*4; i < 6; ++i) - mVertices[(6*4)+i].col = centerColor; + for (int i = 6*4; i < 6; ++i) + mVertices[(6*4)+i].col = centerColor; } void NinePatchComponent::buildVertices() { - if(mVertices != NULL) - delete[] mVertices; + if (mVertices != nullptr) + delete[] mVertices; - mTexture = TextureResource::get(mPath); + mTexture = TextureResource::get(mPath); - if(mTexture->getSize() == Vector2i::Zero()) - { - mVertices = NULL; - LOG(LogWarning) << "NinePatchComponent missing texture!"; - return; - } + if (mTexture->getSize() == Vector2i::Zero()) { + mVertices = nullptr; + LOG(LogWarning) << "NinePatchComponent missing texture!"; + return; + } - mVertices = new Renderer::Vertex[6 * 9]; + mVertices = new Renderer::Vertex[6 * 9]; - const Vector2f texSize = Vector2f((float)mTexture->getSize().x(), (float)mTexture->getSize().y()); + const Vector2f texSize = Vector2f((float)mTexture->getSize().x(), + (float)mTexture->getSize().y()); - const float imgSizeX[3] = { mCornerSize.x(), mSize.x() - mCornerSize.x() * 2, mCornerSize.x()}; - const float imgSizeY[3] = { mCornerSize.y(), mSize.y() - mCornerSize.y() * 2, mCornerSize.y()}; - const float imgPosX[3] = { 0, imgSizeX[0], imgSizeX[0] + imgSizeX[1]}; - const float imgPosY[3] = { 0, imgSizeY[0], imgSizeY[0] + imgSizeY[1]}; + const float imgSizeX[3] = { mCornerSize.x(), mSize.x() - mCornerSize.x() * 2, mCornerSize.x()}; + const float imgSizeY[3] = { mCornerSize.y(), mSize.y() - mCornerSize.y() * 2, mCornerSize.y()}; + const float imgPosX[3] = { 0, imgSizeX[0], imgSizeX[0] + imgSizeX[1]}; + const float imgPosY[3] = { 0, imgSizeY[0], imgSizeY[0] + imgSizeY[1]}; - //the "1 +" in posY and "-" in sizeY is to deal with texture coordinates having a bottom left corner origin vs. verticies having a top left origin - const float texSizeX[3] = { mCornerSize.x() / texSize.x(), (texSize.x() - mCornerSize.x() * 2) / texSize.x(), mCornerSize.x() / texSize.x() }; - const float texSizeY[3] = { -mCornerSize.y() / texSize.y(), -(texSize.y() - mCornerSize.y() * 2) / texSize.y(), -mCornerSize.y() / texSize.y() }; - const float texPosX[3] = { 0, texSizeX[0], texSizeX[0] + texSizeX[1] }; - const float texPosY[3] = { 1, 1 + texSizeY[0], 1 + texSizeY[0] + texSizeY[1] }; + // The "1 +" in posY and "-" in sizeY is to deal with texture coordinates having a bottom + // left corner origin vs. verticies having a top left origin. + const float texSizeX[3] = { mCornerSize.x() / texSize.x(), (texSize.x() - mCornerSize.x() * 2) / texSize.x(), mCornerSize.x() / texSize.x() }; + const float texSizeY[3] = { -mCornerSize.y() / texSize.y(), -(texSize.y() - mCornerSize.y() * 2) / texSize.y(), -mCornerSize.y() / texSize.y() }; + const float texPosX[3] = { 0, texSizeX[0], texSizeX[0] + texSizeX[1] }; + const float texPosY[3] = { 1, 1 + texSizeY[0], 1 + texSizeY[0] + texSizeY[1] }; - int v = 0; - for(int slice = 0; slice < 9; slice++) - { - const int sliceX = slice % 3; - const int sliceY = slice / 3; - const Vector2f imgPos = Vector2f(imgPosX[sliceX], imgPosY[sliceY]); - const Vector2f imgSize = Vector2f(imgSizeX[sliceX], imgSizeY[sliceY]); - const Vector2f texPos = Vector2f(texPosX[sliceX], texPosY[sliceY]); - const Vector2f texSize = Vector2f(texSizeX[sliceX], texSizeY[sliceY]); + int v = 0; - mVertices[v + 1] = { { imgPos.x() , imgPos.y() }, { texPos.x(), texPos.y() }, 0 }; - mVertices[v + 2] = { { imgPos.x() , imgPos.y() + imgSize.y() }, { texPos.x(), texPos.y() + texSize.y() }, 0 }; - mVertices[v + 3] = { { imgPos.x() + imgSize.x(), imgPos.y() }, { texPos.x() + texSize.x(), texPos.y() }, 0 }; - mVertices[v + 4] = { { imgPos.x() + imgSize.x(), imgPos.y() + imgSize.y() }, { texPos.x() + texSize.x(), texPos.y() + texSize.y() }, 0 }; + for (int slice = 0; slice < 9; slice++) { + const int sliceX = slice % 3; + const int sliceY = slice / 3; + const Vector2f imgPos = Vector2f(imgPosX[sliceX], imgPosY[sliceY]); + const Vector2f imgSize = Vector2f(imgSizeX[sliceX], imgSizeY[sliceY]); + const Vector2f texPos = Vector2f(texPosX[sliceX], texPosY[sliceY]); + const Vector2f texSize = Vector2f(texSizeX[sliceX], texSizeY[sliceY]); - // round vertices - for(int i = 1; i < 5; ++i) - mVertices[v + i].pos.round(); + mVertices[v + 1] = { { imgPos.x() , imgPos.y() }, { texPos.x(), texPos.y() }, 0 }; + mVertices[v + 2] = { { imgPos.x() , imgPos.y() + imgSize.y() }, { texPos.x(), texPos.y() + texSize.y() }, 0 }; + mVertices[v + 3] = { { imgPos.x() + imgSize.x(), imgPos.y() }, { texPos.x() + texSize.x(), texPos.y() }, 0 }; + mVertices[v + 4] = { { imgPos.x() + imgSize.x(), imgPos.y() + imgSize.y() }, { texPos.x() + texSize.x(), texPos.y() + texSize.y() }, 0 }; - // make duplicates of first and last vertex so this can be rendered as a triangle strip - mVertices[v + 0] = mVertices[v + 1]; - mVertices[v + 5] = mVertices[v + 4]; + // Round vertices. + for (int i = 1; i < 5; ++i) + mVertices[v + i].pos.round(); - v += 6; - } + // Make duplicates of first and last vertex so this can be rendered as a triangle strip. + mVertices[v + 0] = mVertices[v + 1]; + mVertices[v + 5] = mVertices[v + 4]; - updateColors(); + v += 6; + } + + updateColors(); } void NinePatchComponent::render(const Transform4x4f& parentTrans) { - if (!isVisible()) - return; + if (!isVisible()) + return; - Transform4x4f trans = parentTrans * getTransform(); + Transform4x4f trans = parentTrans * getTransform(); - if(mTexture && mVertices != NULL) - { - Renderer::setMatrix(trans); + if (mTexture && mVertices != nullptr) { + Renderer::setMatrix(trans); - mTexture->bind(); - Renderer::drawTriangleStrips(&mVertices[0], 6*9); - } + mTexture->bind(); + Renderer::drawTriangleStrips(&mVertices[0], 6*9); + } - renderChildren(trans); + renderChildren(trans); } void NinePatchComponent::onSizeChanged() { - buildVertices(); + buildVertices(); } const Vector2f& NinePatchComponent::getCornerSize() const { - return mCornerSize; + return mCornerSize; } void NinePatchComponent::setCornerSize(int sizeX, int sizeY) { - mCornerSize = Vector2f(sizeX, sizeY); - buildVertices(); + mCornerSize = Vector2f(sizeX, sizeY); + buildVertices(); } void NinePatchComponent::fitTo(Vector2f size, Vector3f position, Vector2f padding) { - size += padding; - position[0] -= padding.x() / 2; - position[1] -= padding.y() / 2; + size += padding; + position[0] -= padding.x() / 2; + position[1] -= padding.y() / 2; - setSize(size + mCornerSize * 2); - setPosition(position.x() + Math::lerp(-mCornerSize.x(), mCornerSize.x(), mOrigin.x()), - position.y() + Math::lerp(-mCornerSize.y(), mCornerSize.y(), mOrigin.y())); + setSize(size + mCornerSize * 2); + setPosition(position.x() + Math::lerp(-mCornerSize.x(), mCornerSize.x(), mOrigin.x()), + position.y() + Math::lerp(-mCornerSize.y(), mCornerSize.y(), mOrigin.y())); } void NinePatchComponent::setImagePath(const std::string& path) { - mPath = path; - buildVertices(); + mPath = path; + buildVertices(); } void NinePatchComponent::setEdgeColor(unsigned int edgeColor) { - mEdgeColor = edgeColor; - updateColors(); + mEdgeColor = edgeColor; + updateColors(); } void NinePatchComponent::setCenterColor(unsigned int centerColor) { - mCenterColor = centerColor; - updateColors(); + mCenterColor = centerColor; + updateColors(); } -void NinePatchComponent::applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) +void NinePatchComponent::applyTheme(const std::shared_ptr& theme, + const std::string& view, const std::string& element, unsigned int properties) { - GuiComponent::applyTheme(theme, view, element, properties); + GuiComponent::applyTheme(theme, view, element, properties); - using namespace ThemeFlags; + using namespace ThemeFlags; + const ThemeData::ThemeElement* elem = theme->getElement(view, element, "ninepatch"); - const ThemeData::ThemeElement* elem = theme->getElement(view, element, "ninepatch"); - if(!elem) - return; + if (!elem) + return; - if(properties & PATH && elem->has("path")) - setImagePath(elem->get("path")); + if (properties & PATH && elem->has("path")) + setImagePath(elem->get("path")); } diff --git a/es-core/src/components/NinePatchComponent.h b/es-core/src/components/NinePatchComponent.h index 584dc61e3..62bc89040 100644 --- a/es-core/src/components/NinePatchComponent.h +++ b/es-core/src/components/NinePatchComponent.h @@ -1,3 +1,9 @@ +// +// NinePatchComponent.h +// +// Breaks up an image into 3x3 patches to accomodate resizing without distortions. +// + #pragma once #ifndef ES_CORE_COMPONENTS_NINE_PATCH_COMPONENT_H #define ES_CORE_COMPONENTS_NINE_PATCH_COMPONENT_H @@ -7,13 +13,14 @@ class TextureResource; -// Display an image in a way so that edges don't get too distorted no matter the final size. Useful for UI elements like backgrounds, buttons, etc. +// Display an image in a way so that edges don't get too distorted no matter the final size. +// Useful for UI elements like backgrounds, buttons, etc. // This is accomplished by splitting an image into 9 pieces: // ___________ // |_1_|_2_|_3_| // |_4_|_5_|_6_| // |_7_|_8_|_9_| - +// // Corners (1, 3, 7, 9) will not be stretched at all. // Borders (2, 4, 6, 8) will be stretched along one axis (2 and 8 horizontally, 4 and 6 vertically). // The center (5) will be stretched. @@ -21,36 +28,41 @@ class TextureResource; class NinePatchComponent : public GuiComponent { public: - NinePatchComponent(Window* window, const std::string& path = "", unsigned int edgeColor = 0xFFFFFFFF, unsigned int centerColor = 0xFFFFFFFF); - virtual ~NinePatchComponent(); + NinePatchComponent(Window* window, const std::string& path = "", + unsigned int edgeColor = 0xFFFFFFFF, unsigned int centerColor = 0xFFFFFFFF); + virtual ~NinePatchComponent(); - void render(const Transform4x4f& parentTrans) override; + void render(const Transform4x4f& parentTrans) override; - void onSizeChanged() override; + void onSizeChanged() override; - void fitTo(Vector2f size, Vector3f position = Vector3f::Zero(), Vector2f padding = Vector2f::Zero()); + void fitTo(Vector2f size, Vector3f position = Vector3f::Zero(), + Vector2f padding = Vector2f::Zero()); - void setImagePath(const std::string& path); - void setEdgeColor(unsigned int edgeColor); // Apply a color shift to the "edge" parts of the ninepatch. - void setCenterColor(unsigned int centerColor); // Apply a color shift to the "center" part of the ninepatch. + void setImagePath(const std::string& path); + // Apply a color shift to the "edge" parts of the ninepatch. + void setEdgeColor(unsigned int edgeColor); + // Apply a color shift to the "center" part of the ninepatch. + void setCenterColor(unsigned int centerColor); - virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) override; + virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, + const std::string& element, unsigned int properties) override; - const Vector2f& getCornerSize() const; - void setCornerSize(int sizeX, int sizeY); - inline void setCornerSize(const Vector2f& size) { setCornerSize(size.x(), size.y()); } + const Vector2f& getCornerSize() const; + void setCornerSize(int sizeX, int sizeY); + inline void setCornerSize(const Vector2f& size) { setCornerSize(size.x(), size.y()); } private: - void buildVertices(); - void updateColors(); + void buildVertices(); + void updateColors(); - Renderer::Vertex* mVertices; + Renderer::Vertex* mVertices; - std::string mPath; - Vector2f mCornerSize; - unsigned int mEdgeColor; - unsigned int mCenterColor; - std::shared_ptr mTexture; + std::string mPath; + Vector2f mCornerSize; + unsigned int mEdgeColor; + unsigned int mCenterColor; + std::shared_ptr mTexture; }; #endif // ES_CORE_COMPONENTS_NINE_PATCH_COMPONENT_H diff --git a/es-core/src/components/OptionListComponent.h b/es-core/src/components/OptionListComponent.h index 189873391..fddc20f5a 100644 --- a/es-core/src/components/OptionListComponent.h +++ b/es-core/src/components/OptionListComponent.h @@ -1,8 +1,8 @@ // -// OptionListComponent.h +// OptionListComponent.h // -// Provides a list of options. -// Supports various types using templates. +// Provides a list of options. +// Supports various types using templates. // #pragma once @@ -28,354 +28,354 @@ template class OptionListComponent : public GuiComponent { public: - OptionListComponent( - Window* window, - const HelpStyle& helpstyle, - const std::string& name, - bool multiSelect = false) - : GuiComponent(window), - mHelpStyle(helpstyle), - mMultiSelect(multiSelect), - mName(name), - mText(window), - mLeftArrow(window), - mRightArrow(window) - { - auto font = Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT); - mText.setFont(font); - mText.setColor(0x777777FF); - mText.setHorizontalAlignment(ALIGN_CENTER); - addChild(&mText); + OptionListComponent( + Window* window, + const HelpStyle& helpstyle, + const std::string& name, + bool multiSelect = false) + : GuiComponent(window), + mHelpStyle(helpstyle), + mMultiSelect(multiSelect), + mName(name), + mText(window), + mLeftArrow(window), + mRightArrow(window) + { + auto font = Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT); + mText.setFont(font); + mText.setColor(0x777777FF); + mText.setHorizontalAlignment(ALIGN_CENTER); + addChild(&mText); - mLeftArrow.setResize(0, mText.getFont()->getLetterHeight()); - mRightArrow.setResize(0, mText.getFont()->getLetterHeight()); + mLeftArrow.setResize(0, mText.getFont()->getLetterHeight()); + mRightArrow.setResize(0, mText.getFont()->getLetterHeight()); - if(mMultiSelect) { - mRightArrow.setImage(":/graphics/arrow.svg"); - addChild(&mRightArrow); - } - else { - mLeftArrow.setImage(":/graphics/option_arrow.svg"); - mLeftArrow.setFlipX(true); - addChild(&mLeftArrow); + if(mMultiSelect) { + mRightArrow.setImage(":/graphics/arrow.svg"); + addChild(&mRightArrow); + } + else { + mLeftArrow.setImage(":/graphics/option_arrow.svg"); + mLeftArrow.setFlipX(true); + addChild(&mLeftArrow); - mRightArrow.setImage(":/graphics/option_arrow.svg"); - addChild(&mRightArrow); - } + mRightArrow.setImage(":/graphics/option_arrow.svg"); + addChild(&mRightArrow); + } - setSize(mLeftArrow.getSize().x() + mRightArrow.getSize().x(), font->getHeight()); - } + setSize(mLeftArrow.getSize().x() + mRightArrow.getSize().x(), font->getHeight()); + } - // Handles positioning/resizing of text and arrows. - void onSizeChanged() override - { - mLeftArrow.setResize(0, mText.getFont()->getLetterHeight()); - mRightArrow.setResize(0, mText.getFont()->getLetterHeight()); + // Handles positioning/resizing of text and arrows. + void onSizeChanged() override + { + mLeftArrow.setResize(0, mText.getFont()->getLetterHeight()); + mRightArrow.setResize(0, mText.getFont()->getLetterHeight()); - if(mSize.x() < (mLeftArrow.getSize().x() + mRightArrow.getSize().x())) { - LOG(LogWarning) << "OptionListComponent too narrow!"; - } + if(mSize.x() < (mLeftArrow.getSize().x() + mRightArrow.getSize().x())) { + LOG(LogWarning) << "OptionListComponent too narrow!"; + } - mText.setSize(mSize.x() - mLeftArrow.getSize().x() - - mRightArrow.getSize().x(), mText.getFont()->getHeight()); + mText.setSize(mSize.x() - mLeftArrow.getSize().x() - + mRightArrow.getSize().x(), mText.getFont()->getHeight()); - // Position. - mLeftArrow.setPosition(0, (mSize.y() - mLeftArrow.getSize().y()) / 2); - mText.setPosition(mLeftArrow.getPosition().x() + mLeftArrow.getSize().x(), - (mSize.y() - mText.getSize().y()) / 2); - mRightArrow.setPosition(mText.getPosition().x() + mText.getSize().x(), - (mSize.y() - mRightArrow.getSize().y()) / 2); - } + // Position. + mLeftArrow.setPosition(0, (mSize.y() - mLeftArrow.getSize().y()) / 2); + mText.setPosition(mLeftArrow.getPosition().x() + mLeftArrow.getSize().x(), + (mSize.y() - mText.getSize().y()) / 2); + mRightArrow.setPosition(mText.getPosition().x() + mText.getSize().x(), + (mSize.y() - mRightArrow.getSize().y()) / 2); + } - bool input(InputConfig* config, Input input) override - { - if(input.value != 0) { - if(config->isMappedTo("a", input)) { - open(); - return true; - } - if(!mMultiSelect) { - if(config->isMappedLike("left", input)) { - // Move selection to previous. - unsigned int i = getSelectedId(); - int next = (int)i - 1; - if(next < 0) - next += (int)mEntries.size(); + bool input(InputConfig* config, Input input) override + { + if(input.value != 0) { + if(config->isMappedTo("a", input)) { + open(); + return true; + } + if(!mMultiSelect) { + if(config->isMappedLike("left", input)) { + // Move selection to previous. + unsigned int i = getSelectedId(); + int next = (int)i - 1; + if(next < 0) + next += (int)mEntries.size(); - mEntries.at(i).selected = false; - mEntries.at(next).selected = true; - onSelectedChanged(); - return true; + mEntries.at(i).selected = false; + mEntries.at(next).selected = true; + onSelectedChanged(); + return true; - } - else if(config->isMappedLike("right", input)) { - // Move selection to next. - unsigned int i = getSelectedId(); - int next = (i + 1) % mEntries.size(); - mEntries.at(i).selected = false; - mEntries.at(next).selected = true; - onSelectedChanged(); - return true; - } - } - } - return GuiComponent::input(config, input); - } + } + else if(config->isMappedLike("right", input)) { + // Move selection to next. + unsigned int i = getSelectedId(); + int next = (i + 1) % mEntries.size(); + mEntries.at(i).selected = false; + mEntries.at(next).selected = true; + onSelectedChanged(); + return true; + } + } + } + return GuiComponent::input(config, input); + } - std::vector getSelectedObjects() - { - std::vector ret; - for(auto it = mEntries.cbegin(); it != mEntries.cend(); it++) { - if(it->selected) - ret.push_back(it->object); - } + std::vector getSelectedObjects() + { + std::vector ret; + for(auto it = mEntries.cbegin(); it != mEntries.cend(); it++) { + if(it->selected) + ret.push_back(it->object); + } - return ret; - } + return ret; + } - T getSelected() - { - assert(mMultiSelect == false); - auto selected = getSelectedObjects(); - assert(selected.size() == 1); - return selected.at(0); - } + T getSelected() + { + assert(mMultiSelect == false); + auto selected = getSelectedObjects(); + assert(selected.size() == 1); + return selected.at(0); + } - void add(const std::string& name, const T& obj, bool selected) - { - OptionListData e; - e.name = name; - e.object = obj; - e.selected = selected; + void add(const std::string& name, const T& obj, bool selected) + { + OptionListData e; + e.name = name; + e.object = obj; + e.selected = selected; - mEntries.push_back(e); - onSelectedChanged(); - } + mEntries.push_back(e); + onSelectedChanged(); + } - bool selectEntry(unsigned int entry) - { - if (entry > mEntries.size()) { - return false; - } - else { - mEntries.at(entry).selected = true; - onSelectedChanged(); - return true; - } - } + bool selectEntry(unsigned int entry) + { + if (entry > mEntries.size()) { + return false; + } + else { + mEntries.at(entry).selected = true; + onSelectedChanged(); + return true; + } + } - bool unselectEntry(unsigned int entry) - { - if (entry > mEntries.size()) { - return false; - } - else { - mEntries.at(entry).selected = false; - onSelectedChanged(); - return true; - } - } + bool unselectEntry(unsigned int entry) + { + if (entry > mEntries.size()) { + return false; + } + else { + mEntries.at(entry).selected = false; + onSelectedChanged(); + return true; + } + } - void selectAll() - { - for(unsigned int i = 0; i < mEntries.size(); i++) - mEntries.at(i).selected = true; - onSelectedChanged(); - } + void selectAll() + { + for(unsigned int i = 0; i < mEntries.size(); i++) + mEntries.at(i).selected = true; + onSelectedChanged(); + } - void selectNone() - { - for(unsigned int i = 0; i < mEntries.size(); i++) - mEntries.at(i).selected = false; - onSelectedChanged(); - } + void selectNone() + { + for(unsigned int i = 0; i < mEntries.size(); i++) + mEntries.at(i).selected = false; + onSelectedChanged(); + } - HelpStyle getHelpStyle() override { return mHelpStyle; }; + HelpStyle getHelpStyle() override { return mHelpStyle; }; private: - struct OptionListData { - std::string name; - T object; - bool selected; - }; + struct OptionListData { + std::string name; + T object; + bool selected; + }; - HelpStyle mHelpStyle; + HelpStyle mHelpStyle; - unsigned int getSelectedId() - { - assert(mMultiSelect == false); - for(unsigned int i = 0; i < mEntries.size(); i++) { - if(mEntries.at(i).selected) - return i; - } + unsigned int getSelectedId() + { + assert(mMultiSelect == false); + for(unsigned int i = 0; i < mEntries.size(); i++) { + if(mEntries.at(i).selected) + return i; + } - LOG(LogWarning) << "OptionListComponent::getSelectedId() - " - "no selected element found, defaulting to 0"; - return 0; - } + LOG(LogWarning) << "OptionListComponent::getSelectedId() - " + "no selected element found, defaulting to 0"; + return 0; + } - void open() - { - mWindow->pushGui(new OptionListPopup(mWindow, getHelpStyle(), this, mName)); - } + void open() + { + mWindow->pushGui(new OptionListPopup(mWindow, getHelpStyle(), this, mName)); + } - void onSelectedChanged() - { - if(mMultiSelect) { - // Display # selected. - std::stringstream ss; - ss << getSelectedObjects().size() << " SELECTED"; - mText.setText(ss.str()); - mText.setSize(0, mText.getSize().y()); - setSize(mText.getSize().x() + mRightArrow.getSize().x() + 24, mText.getSize().y()); - if(mParent) // Hack since theres no "on child size changed" callback atm... - mParent->onSizeChanged(); - } - else { - // Display currently selected + l/r cursors. - for(auto it = mEntries.cbegin(); it != mEntries.cend(); it++) { - if(it->selected) { - mText.setText(Utils::String::toUpper(it->name)); - mText.setSize(0, mText.getSize().y()); - setSize(mText.getSize().x() + mLeftArrow.getSize().x() + - mRightArrow.getSize().x() + 24, mText.getSize().y()); - if(mParent) // Hack since theres no "on child size changed" callback atm... - mParent->onSizeChanged(); - break; - } - } - } - } + void onSelectedChanged() + { + if(mMultiSelect) { + // Display # selected. + std::stringstream ss; + ss << getSelectedObjects().size() << " SELECTED"; + mText.setText(ss.str()); + mText.setSize(0, mText.getSize().y()); + setSize(mText.getSize().x() + mRightArrow.getSize().x() + 24, mText.getSize().y()); + if(mParent) // Hack since theres no "on child size changed" callback atm... + mParent->onSizeChanged(); + } + else { + // Display currently selected + l/r cursors. + for(auto it = mEntries.cbegin(); it != mEntries.cend(); it++) { + if(it->selected) { + mText.setText(Utils::String::toUpper(it->name)); + mText.setSize(0, mText.getSize().y()); + setSize(mText.getSize().x() + mLeftArrow.getSize().x() + + mRightArrow.getSize().x() + 24, mText.getSize().y()); + if(mParent) // Hack since theres no "on child size changed" callback atm... + mParent->onSizeChanged(); + break; + } + } + } + } - std::vector getHelpPrompts() override - { - std::vector prompts; - if(!mMultiSelect) - prompts.push_back(HelpPrompt("left/right", "change value")); + std::vector getHelpPrompts() override + { + std::vector prompts; + if(!mMultiSelect) + prompts.push_back(HelpPrompt("left/right", "change value")); - prompts.push_back(HelpPrompt("a", "select")); - return prompts; - } + prompts.push_back(HelpPrompt("a", "select")); + return prompts; + } - bool mMultiSelect; + bool mMultiSelect; - std::string mName; - TextComponent mText; - ImageComponent mLeftArrow; - ImageComponent mRightArrow; + std::string mName; + TextComponent mText; + ImageComponent mLeftArrow; + ImageComponent mRightArrow; - std::vector mEntries; + std::vector mEntries; - // Subclass to OptionListComponent. - class OptionListPopup : public GuiComponent - { - public: - OptionListPopup( - Window* window, - const HelpStyle& helpstyle, - OptionListComponent* parent, - const std::string& title) - : GuiComponent(window), - mHelpStyle(helpstyle), - mMenu(window, title.c_str()), - mParent(parent) - { - auto font = Font::get(FONT_SIZE_MEDIUM); - ComponentListRow row; + // Subclass to OptionListComponent. + class OptionListPopup : public GuiComponent + { + public: + OptionListPopup( + Window* window, + const HelpStyle& helpstyle, + OptionListComponent* parent, + const std::string& title) + : GuiComponent(window), + mHelpStyle(helpstyle), + mMenu(window, title.c_str()), + mParent(parent) + { + auto font = Font::get(FONT_SIZE_MEDIUM); + ComponentListRow row; - // For select all/none. - std::vector checkboxes; + // For select all/none. + std::vector checkboxes; - for(auto it = mParent->mEntries.begin(); it != mParent->mEntries.end(); it++) { - row.elements.clear(); - row.addElement(std::make_shared - (mWindow, Utils::String::toUpper(it->name), font, 0x777777FF), true); + for(auto it = mParent->mEntries.begin(); it != mParent->mEntries.end(); it++) { + row.elements.clear(); + row.addElement(std::make_shared + (mWindow, Utils::String::toUpper(it->name), font, 0x777777FF), true); - OptionListData& e = *it; + OptionListData& e = *it; - if(mParent->mMultiSelect) { - // Add checkbox. - auto checkbox = std::make_shared(mWindow); - checkbox->setImage(it->selected ? CHECKED_PATH : UNCHECKED_PATH); - checkbox->setResize(0, font->getLetterHeight()); - row.addElement(checkbox, false); + if(mParent->mMultiSelect) { + // Add checkbox. + auto checkbox = std::make_shared(mWindow); + checkbox->setImage(it->selected ? CHECKED_PATH : UNCHECKED_PATH); + checkbox->setResize(0, font->getLetterHeight()); + row.addElement(checkbox, false); - // Input handler. - // Update checkbox state & selected value. - row.makeAcceptInputHandler([this, &e, checkbox] { - e.selected = !e.selected; - checkbox->setImage(e.selected ? CHECKED_PATH : UNCHECKED_PATH); - mParent->onSelectedChanged(); - }); + // Input handler. + // Update checkbox state & selected value. + row.makeAcceptInputHandler([this, &e, checkbox] { + e.selected = !e.selected; + checkbox->setImage(e.selected ? CHECKED_PATH : UNCHECKED_PATH); + mParent->onSelectedChanged(); + }); - // For select all/none. - checkboxes.push_back(checkbox.get()); - } - else { - // Input handler for non-multiselect. - // Update selected value and close. - row.makeAcceptInputHandler([this, &e] { - mParent->mEntries.at(mParent->getSelectedId()).selected = false; - e.selected = true; - mParent->onSelectedChanged(); - delete this; - }); - } + // For select all/none. + checkboxes.push_back(checkbox.get()); + } + else { + // Input handler for non-multiselect. + // Update selected value and close. + row.makeAcceptInputHandler([this, &e] { + mParent->mEntries.at(mParent->getSelectedId()).selected = false; + e.selected = true; + mParent->onSelectedChanged(); + delete this; + }); + } - // Also set cursor to this row if we're not multi-select and this row is selected. - mMenu.addRow(row, (!mParent->mMultiSelect && it->selected)); - } + // Also set cursor to this row if we're not multi-select and this row is selected. + mMenu.addRow(row, (!mParent->mMultiSelect && it->selected)); + } - mMenu.addButton("BACK", "back", [this] { delete this; }); + mMenu.addButton("BACK", "back", [this] { delete this; }); - if(mParent->mMultiSelect) { - mMenu.addButton("SELECT ALL", "select all", [this, checkboxes] { - for(unsigned int i = 0; i < mParent->mEntries.size(); i++) { - mParent->mEntries.at(i).selected = true; - checkboxes.at(i)->setImage(CHECKED_PATH); - } - mParent->onSelectedChanged(); - }); + if(mParent->mMultiSelect) { + mMenu.addButton("SELECT ALL", "select all", [this, checkboxes] { + for(unsigned int i = 0; i < mParent->mEntries.size(); i++) { + mParent->mEntries.at(i).selected = true; + checkboxes.at(i)->setImage(CHECKED_PATH); + } + mParent->onSelectedChanged(); + }); - mMenu.addButton("SELECT NONE", "select none", [this, checkboxes] { - for(unsigned int i = 0; i < mParent->mEntries.size(); i++) { - mParent->mEntries.at(i).selected = false; - checkboxes.at(i)->setImage(UNCHECKED_PATH); - } - mParent->onSelectedChanged(); - }); - } + mMenu.addButton("SELECT NONE", "select none", [this, checkboxes] { + for(unsigned int i = 0; i < mParent->mEntries.size(); i++) { + mParent->mEntries.at(i).selected = false; + checkboxes.at(i)->setImage(UNCHECKED_PATH); + } + mParent->onSelectedChanged(); + }); + } - mMenu.setPosition((Renderer::getScreenWidth() - mMenu.getSize().x()) / 2, - Renderer::getScreenHeight() * 0.15f); - addChild(&mMenu); - } + mMenu.setPosition((Renderer::getScreenWidth() - mMenu.getSize().x()) / 2, + Renderer::getScreenHeight() * 0.15f); + addChild(&mMenu); + } - bool input(InputConfig* config, Input input) override - { - if(config->isMappedTo("b", input) && input.value != 0) { - delete this; - return true; - } + bool input(InputConfig* config, Input input) override + { + if(config->isMappedTo("b", input) && input.value != 0) { + delete this; + return true; + } - return GuiComponent::input(config, input); - } + return GuiComponent::input(config, input); + } - std::vector getHelpPrompts() override - { - auto prompts = mMenu.getHelpPrompts(); - prompts.push_back(HelpPrompt("a", "select")); - prompts.push_back(HelpPrompt("b", "back")); - return prompts; - } + std::vector getHelpPrompts() override + { + auto prompts = mMenu.getHelpPrompts(); + prompts.push_back(HelpPrompt("a", "select")); + prompts.push_back(HelpPrompt("b", "back")); + return prompts; + } - HelpStyle getHelpStyle() override { return mHelpStyle; }; + HelpStyle getHelpStyle() override { return mHelpStyle; }; - private: - MenuComponent mMenu; - OptionListComponent* mParent; - HelpStyle mHelpStyle; - }; + private: + MenuComponent mMenu; + OptionListComponent* mParent; + HelpStyle mHelpStyle; + }; }; #endif // ES_CORE_COMPONENTS_OPTION_LIST_COMPONENT_H diff --git a/es-core/src/components/ScrollableContainer.cpp b/es-core/src/components/ScrollableContainer.cpp index 5157b977b..4e185a46f 100644 --- a/es-core/src/components/ScrollableContainer.cpp +++ b/es-core/src/components/ScrollableContainer.cpp @@ -1,133 +1,141 @@ +// +// ScrollableContainer.cpp +// +// Area containing scrollable information, for example the game description +// text container in the detailed, video and grid views. +// + #include "components/ScrollableContainer.h" #include "math/Vector2i.h" #include "renderers/Renderer.h" -#define AUTO_SCROLL_RESET_DELAY 3000 // ms to reset to top after we reach the bottom -#define AUTO_SCROLL_DELAY 1000 // ms to wait before we start to scroll -#define AUTO_SCROLL_SPEED 50 // ms between scrolls +#define AUTO_SCROLL_RESET_DELAY 3000 // ms to reset to top after we reach the bottom. +#define AUTO_SCROLL_DELAY 1000 // ms to wait before we start to scroll. +#define AUTO_SCROLL_SPEED 100 // ms between scrolls. -ScrollableContainer::ScrollableContainer(Window* window) : GuiComponent(window), - mAutoScrollDelay(0), mAutoScrollSpeed(0), mAutoScrollAccumulator(0), mScrollPos(0, 0), mScrollDir(0, 0), mAutoScrollResetAccumulator(0) +ScrollableContainer::ScrollableContainer( + Window* window) + : GuiComponent(window), + mAutoScrollDelay(0), + mAutoScrollSpeed(0), + mAutoScrollAccumulator(0), + mScrollPos(0, 0), + mScrollDir(0, 0), + mAutoScrollResetAccumulator(0) { } void ScrollableContainer::render(const Transform4x4f& parentTrans) { - if (!isVisible()) - return; + if (!isVisible()) + return; - Transform4x4f trans = parentTrans * getTransform(); + Transform4x4f trans = parentTrans * getTransform(); - Vector2i clipPos((int)trans.translation().x(), (int)trans.translation().y()); + Vector2i clipPos((int)trans.translation().x(), (int)trans.translation().y()); - Vector3f dimScaled = trans * Vector3f(mSize.x(), mSize.y(), 0); - Vector2i clipDim((int)(dimScaled.x() - trans.translation().x()), (int)(dimScaled.y() - trans.translation().y())); + Vector3f dimScaled = trans * Vector3f(mSize.x(), mSize.y(), 0); + Vector2i clipDim((int)(dimScaled.x() - trans.translation().x()), + (int)(dimScaled.y() - trans.translation().y())); - Renderer::pushClipRect(clipPos, clipDim); + Renderer::pushClipRect(clipPos, clipDim); - trans.translate(-Vector3f(mScrollPos.x(), mScrollPos.y(), 0)); - Renderer::setMatrix(trans); + trans.translate(-Vector3f(mScrollPos.x(), mScrollPos.y(), 0)); + Renderer::setMatrix(trans); - GuiComponent::renderChildren(trans); - - Renderer::popClipRect(); + GuiComponent::renderChildren(trans); + Renderer::popClipRect(); } void ScrollableContainer::setAutoScroll(bool autoScroll) { - if(autoScroll) - { - mScrollDir = Vector2f(0, 1); - mAutoScrollDelay = AUTO_SCROLL_DELAY; - mAutoScrollSpeed = AUTO_SCROLL_SPEED; - reset(); - }else{ - mScrollDir = Vector2f(0, 0); - mAutoScrollDelay = 0; - mAutoScrollSpeed = 0; - mAutoScrollAccumulator = 0; - } + if (autoScroll) { + mScrollDir = Vector2f(0, 1); + mAutoScrollDelay = AUTO_SCROLL_DELAY; + mAutoScrollSpeed = AUTO_SCROLL_SPEED; + reset(); + } + else { + mScrollDir = Vector2f(0, 0); + mAutoScrollDelay = 0; + mAutoScrollSpeed = 0; + mAutoScrollAccumulator = 0; + } } Vector2f ScrollableContainer::getScrollPos() const { - return mScrollPos; + return mScrollPos; } void ScrollableContainer::setScrollPos(const Vector2f& pos) { - mScrollPos = pos; + mScrollPos = pos; } void ScrollableContainer::update(int deltaTime) { - if(mAutoScrollSpeed != 0) - { - mAutoScrollAccumulator += deltaTime; + if (mAutoScrollSpeed != 0) { + mAutoScrollAccumulator += deltaTime; - //scale speed by our width! more text per line = slower scrolling - const float widthMod = (680.0f / getSize().x()); - while(mAutoScrollAccumulator >= mAutoScrollSpeed) - { - mScrollPos += mScrollDir; - mAutoScrollAccumulator -= mAutoScrollSpeed; - } - } + // Scale speed by our width! more text per line = slower scrolling. + const float widthMod = (680.0f / getSize().x()); + while (mAutoScrollAccumulator >= mAutoScrollSpeed) { + mScrollPos += mScrollDir; + mAutoScrollAccumulator -= mAutoScrollSpeed; + } + } - //clip scrolling within bounds - if(mScrollPos.x() < 0) - mScrollPos[0] = 0; - if(mScrollPos.y() < 0) - mScrollPos[1] = 0; + // Clip scrolling within bounds. + if (mScrollPos.x() < 0) + mScrollPos[0] = 0; + if (mScrollPos.y() < 0) + mScrollPos[1] = 0; - const Vector2f contentSize = getContentSize(); - if(mScrollPos.x() + getSize().x() > contentSize.x()) - { - mScrollPos[0] = contentSize.x() - getSize().x(); - mAtEnd = true; - } + const Vector2f contentSize = getContentSize(); + if (mScrollPos.x() + getSize().x() > contentSize.x()) { + mScrollPos[0] = contentSize.x() - getSize().x(); + mAtEnd = true; + } - if(contentSize.y() < getSize().y()) - { - mScrollPos[1] = 0; - }else if(mScrollPos.y() + getSize().y() > contentSize.y()) - { - mScrollPos[1] = contentSize.y() - getSize().y(); - mAtEnd = true; - } + if (contentSize.y() < getSize().y()) { + mScrollPos[1] = 0; + } + else if (mScrollPos.y() + getSize().y() > contentSize.y()) { + mScrollPos[1] = contentSize.y() - getSize().y(); + mAtEnd = true; + } - if(mAtEnd) - { - mAutoScrollResetAccumulator += deltaTime; - if(mAutoScrollResetAccumulator >= AUTO_SCROLL_RESET_DELAY) - reset(); - } + if (mAtEnd) { + mAutoScrollResetAccumulator += deltaTime; + if (mAutoScrollResetAccumulator >= AUTO_SCROLL_RESET_DELAY) + reset(); + } - GuiComponent::update(deltaTime); + GuiComponent::update(deltaTime); } -//this should probably return a box to allow for when controls don't start at 0,0 +// This should probably return a box to allow for when controls don't start at 0,0. Vector2f ScrollableContainer::getContentSize() { - Vector2f max(0, 0); - for(unsigned int i = 0; i < mChildren.size(); i++) - { - Vector2f pos(mChildren.at(i)->getPosition()[0], mChildren.at(i)->getPosition()[1]); - Vector2f bottomRight = mChildren.at(i)->getSize() + pos; - if(bottomRight.x() > max.x()) - max.x() = bottomRight.x(); - if(bottomRight.y() > max.y()) - max.y() = bottomRight.y(); - } + Vector2f max(0, 0); + for (unsigned int i = 0; i < mChildren.size(); i++) { + Vector2f pos(mChildren.at(i)->getPosition()[0], mChildren.at(i)->getPosition()[1]); + Vector2f bottomRight = mChildren.at(i)->getSize() + pos; + if (bottomRight.x() > max.x()) + max.x() = bottomRight.x(); + if (bottomRight.y() > max.y()) + max.y() = bottomRight.y(); + } - return max; + return max; } void ScrollableContainer::reset() { - mScrollPos = Vector2f(0, 0); - mAutoScrollResetAccumulator = 0; - mAutoScrollAccumulator = -mAutoScrollDelay + mAutoScrollSpeed; - mAtEnd = false; + mScrollPos = Vector2f(0, 0); + mAutoScrollResetAccumulator = 0; + mAutoScrollAccumulator = -mAutoScrollDelay + mAutoScrollSpeed; + mAtEnd = false; } diff --git a/es-core/src/components/ScrollableContainer.h b/es-core/src/components/ScrollableContainer.h index 6700a78cb..307d29186 100644 --- a/es-core/src/components/ScrollableContainer.h +++ b/es-core/src/components/ScrollableContainer.h @@ -1,3 +1,10 @@ +// +// ScrollableContainer.h +// +// Area containing scrollable information, for example the game description +// text container in the detailed, video and grid views. +// + #pragma once #ifndef ES_CORE_COMPONENTS_SCROLLABLE_CONTAINER_H #define ES_CORE_COMPONENTS_SCROLLABLE_CONTAINER_H @@ -7,26 +14,26 @@ class ScrollableContainer : public GuiComponent { public: - ScrollableContainer(Window* window); + ScrollableContainer(Window* window); - Vector2f getScrollPos() const; - void setScrollPos(const Vector2f& pos); - void setAutoScroll(bool autoScroll); - void reset(); + Vector2f getScrollPos() const; + void setScrollPos(const Vector2f& pos); + void setAutoScroll(bool autoScroll); + void reset(); - void update(int deltaTime) override; - void render(const Transform4x4f& parentTrans) override; + void update(int deltaTime) override; + void render(const Transform4x4f& parentTrans) override; private: - Vector2f getContentSize(); + Vector2f getContentSize(); - Vector2f mScrollPos; - Vector2f mScrollDir; - int mAutoScrollDelay; // ms to wait before starting to autoscroll - int mAutoScrollSpeed; // ms to wait before scrolling down by mScrollDir - int mAutoScrollAccumulator; - bool mAtEnd; - int mAutoScrollResetAccumulator; + Vector2f mScrollPos; + Vector2f mScrollDir; + int mAutoScrollDelay; // ms to wait before starting to autoscroll. + int mAutoScrollSpeed; // ms to wait before scrolling down by mScrollDir. + int mAutoScrollAccumulator; + bool mAtEnd; + int mAutoScrollResetAccumulator; }; #endif // ES_CORE_COMPONENTS_SCROLLABLE_CONTAINER_H diff --git a/es-core/src/components/SliderComponent.cpp b/es-core/src/components/SliderComponent.cpp index 934aefe42..7a928b914 100644 --- a/es-core/src/components/SliderComponent.cpp +++ b/es-core/src/components/SliderComponent.cpp @@ -1,3 +1,9 @@ +// +// SliderComponent.cpp +// +// Slider to set value in a predefined range. +// + #include "components/SliderComponent.h" #include "resources/Font.h" @@ -5,138 +11,149 @@ #define MOVE_REPEAT_DELAY 500 #define MOVE_REPEAT_RATE 40 -SliderComponent::SliderComponent(Window* window, float min, float max, float increment, const std::string& suffix) : GuiComponent(window), - mMin(min), mMax(max), mSingleIncrement(increment), mMoveRate(0), mKnob(window), mSuffix(suffix) +SliderComponent::SliderComponent( + Window* window, + float min, + float max, + float increment, + const std::string& suffix) + : GuiComponent(window), + mMin(min), + mMax(max), + mSingleIncrement(increment), + mMoveRate(0), + mKnob(window), + mSuffix(suffix) { - assert((min - max) != 0); + assert((min - max) != 0); - // some sane default value - mValue = (max + min) / 2; + // Some sane default value. + mValue = (max + min) / 2; - mKnob.setOrigin(0.5f, 0.5f); - mKnob.setImage(":/graphics/slider_knob.svg"); + mKnob.setOrigin(0.5f, 0.5f); + mKnob.setImage(":/graphics/slider_knob.svg"); - setSize(Renderer::getScreenWidth() * 0.15f, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()); + setSize(Renderer::getScreenWidth() * 0.15f, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()); } bool SliderComponent::input(InputConfig* config, Input input) { - if(config->isMappedLike("left", input)) - { - if(input.value) - setValue(mValue - mSingleIncrement); + if (config->isMappedLike("left", input)) { + if (input.value) + setValue(mValue - mSingleIncrement); - mMoveRate = input.value ? -mSingleIncrement : 0; - mMoveAccumulator = -MOVE_REPEAT_DELAY; - return true; - } - if(config->isMappedLike("right", input)) - { - if(input.value) - setValue(mValue + mSingleIncrement); + mMoveRate = input.value ? -mSingleIncrement : 0; + mMoveAccumulator = -MOVE_REPEAT_DELAY; + return true; + } + if (config->isMappedLike("right", input)) { + if (input.value) + setValue(mValue + mSingleIncrement); - mMoveRate = input.value ? mSingleIncrement : 0; - mMoveAccumulator = -MOVE_REPEAT_DELAY; - return true; - } + mMoveRate = input.value ? mSingleIncrement : 0; + mMoveAccumulator = -MOVE_REPEAT_DELAY; + return true; + } - return GuiComponent::input(config, input); + return GuiComponent::input(config, input); } void SliderComponent::update(int deltaTime) { - if(mMoveRate != 0) - { - mMoveAccumulator += deltaTime; - while(mMoveAccumulator >= MOVE_REPEAT_RATE) - { - setValue(mValue + mMoveRate); - mMoveAccumulator -= MOVE_REPEAT_RATE; - } - } + if (mMoveRate != 0) { + mMoveAccumulator += deltaTime; + while (mMoveAccumulator >= MOVE_REPEAT_RATE) { + setValue(mValue + mMoveRate); + mMoveAccumulator -= MOVE_REPEAT_RATE; + } + } - GuiComponent::update(deltaTime); + GuiComponent::update(deltaTime); } void SliderComponent::render(const Transform4x4f& parentTrans) { - Transform4x4f trans = parentTrans * getTransform(); - Renderer::setMatrix(trans); + Transform4x4f trans = parentTrans * getTransform(); + Renderer::setMatrix(trans); - // render suffix - if(mValueCache) - mFont->renderTextCache(mValueCache.get()); + // Render suffix. + if (mValueCache) + mFont->renderTextCache(mValueCache.get()); - float width = mSize.x() - mKnob.getSize().x() - (mValueCache ? mValueCache->metrics.size.x() + 4 : 0); + float width = mSize.x() - mKnob.getSize().x() - + (mValueCache ? mValueCache->metrics.size.x() + 4 : 0); - //render line - const float lineWidth = 2; - Renderer::drawRect(mKnob.getSize().x() / 2, mSize.y() / 2 - lineWidth / 2, width, lineWidth, 0x777777FF, 0x777777FF); + // Render line. + const float lineWidth = 2; + Renderer::drawRect(mKnob.getSize().x() / 2, mSize.y() / 2 - + lineWidth / 2, width, lineWidth, 0x777777FF, 0x777777FF); - //render knob - mKnob.render(trans); + // Render knob. + mKnob.render(trans); - GuiComponent::renderChildren(trans); + GuiComponent::renderChildren(trans); } void SliderComponent::setValue(float value) { - mValue = value; - if(mValue < mMin) - mValue = mMin; - else if(mValue > mMax) - mValue = mMax; + mValue = value; + if (mValue < mMin) + mValue = mMin; + else if (mValue > mMax) + mValue = mMax; - onValueChanged(); + onValueChanged(); } float SliderComponent::getValue() { - return mValue; + return mValue; } void SliderComponent::onSizeChanged() { - if(!mSuffix.empty()) - mFont = Font::get((int)(mSize.y()), FONT_PATH_LIGHT); + if (!mSuffix.empty()) + mFont = Font::get((int)(mSize.y()), FONT_PATH_LIGHT); - onValueChanged(); + onValueChanged(); } void SliderComponent::onValueChanged() { - // update suffix textcache - if(mFont) - { - std::stringstream ss; - ss << std::fixed; - ss.precision(0); - ss << mValue; - ss << mSuffix; - const std::string val = ss.str(); + // Update suffix textcache. + if (mFont) { + std::stringstream ss; + ss << std::fixed; + ss.precision(0); + ss << mValue; + ss << mSuffix; + const std::string val = ss.str(); - ss.str(""); - ss.clear(); - ss << std::fixed; - ss.precision(0); - ss << mMax; - ss << mSuffix; - const std::string max = ss.str(); + ss.str(""); + ss.clear(); + ss << std::fixed; + ss.precision(0); + ss << mMax; + ss << mSuffix; + const std::string max = ss.str(); - Vector2f textSize = mFont->sizeText(max); - mValueCache = std::shared_ptr(mFont->buildTextCache(val, mSize.x() - textSize.x(), (mSize.y() - textSize.y()) / 2, 0x777777FF)); - mValueCache->metrics.size[0] = textSize.x(); // fudge the width - } + Vector2f textSize = mFont->sizeText(max); + mValueCache = std::shared_ptr(mFont->buildTextCache(val, mSize.x() - + textSize.x(), (mSize.y() - textSize.y()) / 2, 0x777777FF)); + mValueCache->metrics.size[0] = textSize.x(); // Fudge the width. + } - // update knob position/size - mKnob.setResize(0, mSize.y() * 0.7f); - float lineLength = mSize.x() - mKnob.getSize().x() - (mValueCache ? mValueCache->metrics.size.x() + 4 : 0); - mKnob.setPosition(((mValue + mMin) / mMax) * lineLength + mKnob.getSize().x()/2, mSize.y() / 2); + // Update knob position/size. + mKnob.setResize(0, mSize.y() * 0.7f); + float lineLength = mSize.x() - mKnob.getSize().x() - + (mValueCache ? mValueCache->metrics.size.x() + 4 : 0); + mKnob.setPosition(((mValue + mMin) / mMax) * lineLength + + mKnob.getSize().x()/2, mSize.y() / 2); } std::vector SliderComponent::getHelpPrompts() { - std::vector prompts; - prompts.push_back(HelpPrompt("left/right", "change value")); - return prompts; + std::vector prompts; + prompts.push_back(HelpPrompt("left/right", "change value")); + return prompts; } diff --git a/es-core/src/components/SliderComponent.h b/es-core/src/components/SliderComponent.h index f3ae181fc..d1e883324 100644 --- a/es-core/src/components/SliderComponent.h +++ b/es-core/src/components/SliderComponent.h @@ -1,3 +1,9 @@ +// +// SliderComponent.h +// +// Slider to set value in a predefined range. +// + #pragma once #ifndef ES_CORE_COMPONENTS_SLIDER_COMPONENT_H #define ES_CORE_COMPONENTS_SLIDER_COMPONENT_H @@ -12,34 +18,40 @@ class TextCache; class SliderComponent : public GuiComponent { public: - //Minimum value (far left of the slider), maximum value (far right of the slider), increment size (how much just pressing L/R moves by), unit to display (optional). - SliderComponent(Window* window, float min, float max, float increment, const std::string& suffix = ""); + // Minimum value (far left of the slider), maximum value (far right of the slider), + // increment size (how much just pressing L/R moves by), unit to display (optional). + SliderComponent( + Window* window, + float min, + float max, + float increment, + const std::string& suffix = ""); - void setValue(float val); - float getValue(); + void setValue(float val); + float getValue(); - bool input(InputConfig* config, Input input) override; - void update(int deltaTime) override; - void render(const Transform4x4f& parentTrans) override; + bool input(InputConfig* config, Input input) override; + void update(int deltaTime) override; + void render(const Transform4x4f& parentTrans) override; - void onSizeChanged() override; + void onSizeChanged() override; - virtual std::vector getHelpPrompts() override; + virtual std::vector getHelpPrompts() override; private: - void onValueChanged(); + void onValueChanged(); - float mMin, mMax; - float mValue; - float mSingleIncrement; - float mMoveRate; - int mMoveAccumulator; + float mMin, mMax; + float mValue; + float mSingleIncrement; + float mMoveRate; + int mMoveAccumulator; - ImageComponent mKnob; + ImageComponent mKnob; - std::string mSuffix; - std::shared_ptr mFont; - std::shared_ptr mValueCache; + std::string mSuffix; + std::shared_ptr mFont; + std::shared_ptr mValueCache; }; #endif // ES_CORE_COMPONENTS_SLIDER_COMPONENT_H diff --git a/es-core/src/components/TextComponent.cpp b/es-core/src/components/TextComponent.cpp index 450b88850..e5a78806a 100644 --- a/es-core/src/components/TextComponent.cpp +++ b/es-core/src/components/TextComponent.cpp @@ -1,295 +1,319 @@ +// +// TextComponent.cpp +// +// Displays text. +// + #include "components/TextComponent.h" #include "utils/StringUtil.h" #include "Log.h" #include "Settings.h" -TextComponent::TextComponent(Window* window) : GuiComponent(window), - mFont(Font::get(FONT_SIZE_MEDIUM)), mUppercase(false), mColor(0x000000FF), mAutoCalcExtent(true, true), - mHorizontalAlignment(ALIGN_LEFT), mVerticalAlignment(ALIGN_CENTER), mLineSpacing(1.5f), mBgColor(0), - mRenderBackground(false) +TextComponent::TextComponent( + Window* window) + : GuiComponent(window), + mFont(Font::get(FONT_SIZE_MEDIUM)), + mUppercase(false), + mColor(0x000000FF), + mAutoCalcExtent(true, true), + mHorizontalAlignment(ALIGN_LEFT), + mVerticalAlignment(ALIGN_CENTER), + mLineSpacing(1.5f), + mBgColor(0), + mRenderBackground(false) { } -TextComponent::TextComponent(Window* window, const std::string& text, const std::shared_ptr& font, unsigned int color, Alignment align, - Vector3f pos, Vector2f size, unsigned int bgcolor) : GuiComponent(window), - mFont(NULL), mUppercase(false), mColor(0x000000FF), mAutoCalcExtent(true, true), - mHorizontalAlignment(align), mVerticalAlignment(ALIGN_CENTER), mLineSpacing(1.5f), mBgColor(0), - mRenderBackground(false) +TextComponent::TextComponent( + Window* window, + const std::string& text, + const std::shared_ptr& font, + unsigned int color, + Alignment align, + Vector3f pos, + Vector2f size, + unsigned int bgcolor) + : GuiComponent(window), + mFont(nullptr), + mUppercase(false), + mColor(0x000000FF), + mAutoCalcExtent(true, true), + mHorizontalAlignment(align), + mVerticalAlignment(ALIGN_CENTER), + mLineSpacing(1.5f), + mBgColor(0), + mRenderBackground(false) { - setFont(font); - setColor(color); - setBackgroundColor(bgcolor); - setText(text); - setPosition(pos); - setSize(size); + setFont(font); + setColor(color); + setBackgroundColor(bgcolor); + setText(text); + setPosition(pos); + setSize(size); } void TextComponent::onSizeChanged() { - mAutoCalcExtent = Vector2i((getSize().x() == 0), (getSize().y() == 0)); - onTextChanged(); + mAutoCalcExtent = Vector2i((getSize().x() == 0), (getSize().y() == 0)); + onTextChanged(); } void TextComponent::setFont(const std::shared_ptr& font) { - mFont = font; - onTextChanged(); + mFont = font; + onTextChanged(); } -// Set the color of the font/text +// Set the color of the font/text. void TextComponent::setColor(unsigned int color) { - mColor = color; - mColorOpacity = mColor & 0x000000FF; - onColorChanged(); + mColor = color; + mColorOpacity = mColor & 0x000000FF; + onColorChanged(); } -// Set the color of the background box +// Set the color of the background box. void TextComponent::setBackgroundColor(unsigned int color) { - mBgColor = color; - mBgColorOpacity = mBgColor & 0x000000FF; + mBgColor = color; + mBgColorOpacity = mBgColor & 0x000000FF; } void TextComponent::setRenderBackground(bool render) { - mRenderBackground = render; + mRenderBackground = render; } -// Scale the opacity +// Scale the opacity. void TextComponent::setOpacity(unsigned char opacity) { - // This method is mostly called to do fading in-out of the Text component element. - // Therefore, we assume here that opacity is a fractional value (expressed as an int 0-255), - // of the opacity originally set with setColor() or setBackgroundColor(). + // This method is mostly called to do fading in-out of the Text component element. + // Therefore, we assume here that opacity is a fractional value (expressed as an int 0-255), + // of the opacity originally set with setColor() or setBackgroundColor(). - unsigned char o = (unsigned char)((float)opacity / 255.f * (float) mColorOpacity); - mColor = (mColor & 0xFFFFFF00) | (unsigned char) o; + unsigned char o = (unsigned char)((float)opacity / 255.f * (float) mColorOpacity); + mColor = (mColor & 0xFFFFFF00) | (unsigned char) o; - unsigned char bgo = (unsigned char)((float)opacity / 255.f * (float)mBgColorOpacity); - mBgColor = (mBgColor & 0xFFFFFF00) | (unsigned char)bgo; + unsigned char bgo = (unsigned char)((float)opacity / 255.f * (float)mBgColorOpacity); + mBgColor = (mBgColor & 0xFFFFFF00) | (unsigned char)bgo; - onColorChanged(); - - GuiComponent::setOpacity(opacity); + onColorChanged(); + GuiComponent::setOpacity(opacity); } unsigned char TextComponent::getOpacity() const { - return mColor & 0x000000FF; + return mColor & 0x000000FF; } void TextComponent::setText(const std::string& text) { - mText = text; - onTextChanged(); + mText = text; + onTextChanged(); } void TextComponent::setUppercase(bool uppercase) { - mUppercase = uppercase; - onTextChanged(); + mUppercase = uppercase; + onTextChanged(); } void TextComponent::render(const Transform4x4f& parentTrans) { - if (!isVisible()) - return; + if (!isVisible()) + return; - Transform4x4f trans = parentTrans * getTransform(); + Transform4x4f trans = parentTrans * getTransform(); - if (mRenderBackground) - { - Renderer::setMatrix(trans); - Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), mBgColor, mBgColor); - } + if (mRenderBackground) { + Renderer::setMatrix(trans); + Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), mBgColor, mBgColor); + } - if(mTextCache) - { - const Vector2f& textSize = mTextCache->metrics.size; - float yOff = 0; - switch(mVerticalAlignment) - { - case ALIGN_TOP: - yOff = 0; - break; - case ALIGN_BOTTOM: - yOff = (getSize().y() - textSize.y()); - break; - case ALIGN_CENTER: - yOff = (getSize().y() - textSize.y()) / 2.0f; - break; - default: - break; - } - Vector3f off(0, yOff, 0); + if (mTextCache) { + const Vector2f& textSize = mTextCache->metrics.size; + float yOff = 0; + switch (mVerticalAlignment) { + case ALIGN_TOP: + yOff = 0; + break; + case ALIGN_BOTTOM: + yOff = (getSize().y() - textSize.y()); + break; + case ALIGN_CENTER: + yOff = (getSize().y() - textSize.y()) / 2.0f; + break; + default: + break; + } + Vector3f off(0, yOff, 0); - if(Settings::getInstance()->getBool("DebugText")) - { - // draw the "textbox" area, what we are aligned within - Renderer::setMatrix(trans); - Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), 0xFF000033, 0xFF000033); - } + if (Settings::getInstance()->getBool("DebugText")) { + // Draw the "textbox" area, what we are aligned within. + Renderer::setMatrix(trans); + Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), 0xFF000033, 0xFF000033); + } - trans.translate(off); - Renderer::setMatrix(trans); + trans.translate(off); + Renderer::setMatrix(trans); - // draw the text area, where the text actually is going - if(Settings::getInstance()->getBool("DebugText")) - { - switch(mHorizontalAlignment) - { - case ALIGN_LEFT: - Renderer::drawRect(0.0f, 0.0f, mTextCache->metrics.size.x(), mTextCache->metrics.size.y(), 0x00000033, 0x00000033); - break; - case ALIGN_CENTER: - Renderer::drawRect((mSize.x() - mTextCache->metrics.size.x()) / 2.0f, 0.0f, mTextCache->metrics.size.x(), mTextCache->metrics.size.y(), 0x00000033, 0x00000033); - break; - case ALIGN_RIGHT: - Renderer::drawRect(mSize.x() - mTextCache->metrics.size.x(), 0.0f, mTextCache->metrics.size.x(), mTextCache->metrics.size.y(), 0x00000033, 0x00000033); - break; - default: - break; - } - } - mFont->renderTextCache(mTextCache.get()); - } + // Draw the text area, where the text actually is located. + if (Settings::getInstance()->getBool("DebugText")) { + switch (mHorizontalAlignment) { + case ALIGN_LEFT: + Renderer::drawRect(0.0f, 0.0f, mTextCache->metrics.size.x(), + mTextCache->metrics.size.y(), 0x00000033, 0x00000033); + break; + case ALIGN_CENTER: + Renderer::drawRect((mSize.x() - mTextCache->metrics.size.x()) / 2.0f, 0.0f, + mTextCache->metrics.size.x(), mTextCache->metrics.size.y(), + 0x00000033, 0x00000033); + break; + case ALIGN_RIGHT: + Renderer::drawRect(mSize.x() - mTextCache->metrics.size.x(), 0.0f, + mTextCache->metrics.size.x(), mTextCache->metrics.size.y(), + 0x00000033, 0x00000033); + break; + default: + break; + } + } + mFont->renderTextCache(mTextCache.get()); + } } void TextComponent::calculateExtent() { - if(mAutoCalcExtent.x()) - { - mSize = mFont->sizeText(mUppercase ? Utils::String::toUpper(mText) : mText, mLineSpacing); - }else{ - if(mAutoCalcExtent.y()) - { - mSize[1] = mFont->sizeWrappedText(mUppercase ? Utils::String::toUpper(mText) : mText, getSize().x(), mLineSpacing).y(); - } - } + if (mAutoCalcExtent.x()) { + mSize = mFont->sizeText(mUppercase ? Utils::String::toUpper(mText) : mText, mLineSpacing); + } + else { + if (mAutoCalcExtent.y()) + mSize[1] = mFont->sizeWrappedText(mUppercase ? Utils::String::toUpper(mText) + : mText, getSize().x(), mLineSpacing).y(); + } } void TextComponent::onTextChanged() { - calculateExtent(); + calculateExtent(); - if(!mFont || mText.empty()) - { - mTextCache.reset(); - return; - } + if (!mFont || mText.empty()) { + mTextCache.reset(); + return; + } - std::string text = mUppercase ? Utils::String::toUpper(mText) : mText; + std::string text = mUppercase ? Utils::String::toUpper(mText) : mText; - std::shared_ptr f = mFont; - const bool isMultiline = (mSize.y() == 0 || mSize.y() > f->getHeight()*1.2f); + std::shared_ptr f = mFont; + const bool isMultiline = (mSize.y() == 0 || mSize.y() > f->getHeight()*1.2f); - bool addAbbrev = false; - if(!isMultiline) - { - size_t newline = text.find('\n'); - text = text.substr(0, newline); // single line of text - stop at the first newline since it'll mess everything up - addAbbrev = newline != std::string::npos; - } + bool addAbbrev = false; + if (!isMultiline) { + size_t newline = text.find('\n'); + // Single line of text - stop at the first newline since it'll mess everything up. + text = text.substr(0, newline); + addAbbrev = newline != std::string::npos; + } - Vector2f size = f->sizeText(text); - if(!isMultiline && mSize.x() && text.size() && (size.x() > mSize.x() || addAbbrev)) - { - // abbreviate text - const std::string abbrev = "..."; - Vector2f abbrevSize = f->sizeText(abbrev); + Vector2f size = f->sizeText(text); + if (!isMultiline && mSize.x() && text.size() && (size.x() > mSize.x() || addAbbrev)) { + // Abbreviate text. + const std::string abbrev = "..."; + Vector2f abbrevSize = f->sizeText(abbrev); - while(text.size() && size.x() + abbrevSize.x() > mSize.x()) - { - size_t newSize = Utils::String::prevCursor(text, text.size()); - text.erase(newSize, text.size() - newSize); - size = f->sizeText(text); - } + while (text.size() && size.x() + abbrevSize.x() > mSize.x()) { + size_t newSize = Utils::String::prevCursor(text, text.size()); + text.erase(newSize, text.size() - newSize); + size = f->sizeText(text); + } - text.append(abbrev); + text.append(abbrev); - mTextCache = std::shared_ptr(f->buildTextCache(text, Vector2f(0, 0), (mColor >> 8 << 8) | mOpacity, mSize.x(), mHorizontalAlignment, mLineSpacing)); - }else{ - mTextCache = std::shared_ptr(f->buildTextCache(f->wrapText(text, mSize.x()), Vector2f(0, 0), (mColor >> 8 << 8) | mOpacity, mSize.x(), mHorizontalAlignment, mLineSpacing)); - } + mTextCache = std::shared_ptr(f->buildTextCache(text, Vector2f(0, 0), + (mColor >> 8 << 8) | mOpacity, mSize.x(), mHorizontalAlignment, mLineSpacing)); + } + else { + mTextCache = std::shared_ptr(f->buildTextCache(f->wrapText( + text, mSize.x()), Vector2f(0, 0), (mColor >> 8 << 8) | mOpacity, mSize.x(), + mHorizontalAlignment, mLineSpacing)); + } } void TextComponent::onColorChanged() { - if(mTextCache) - { - mTextCache->setColor(mColor); - } + if (mTextCache) + mTextCache->setColor(mColor); } void TextComponent::setHorizontalAlignment(Alignment align) { - mHorizontalAlignment = align; - onTextChanged(); + mHorizontalAlignment = align; + onTextChanged(); } void TextComponent::setVerticalAlignment(Alignment align) { - mVerticalAlignment = align; + mVerticalAlignment = align; } void TextComponent::setLineSpacing(float spacing) { - mLineSpacing = spacing; - onTextChanged(); + mLineSpacing = spacing; + onTextChanged(); } void TextComponent::setValue(const std::string& value) { - setText(value); + setText(value); } std::string TextComponent::getValue() const { - return mText; + return mText; } -void TextComponent::applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) +void TextComponent::applyTheme(const std::shared_ptr& theme, const std::string& view, + const std::string& element, unsigned int properties) { - GuiComponent::applyTheme(theme, view, element, properties); + GuiComponent::applyTheme(theme, view, element, properties); - using namespace ThemeFlags; + using namespace ThemeFlags; - const ThemeData::ThemeElement* elem = theme->getElement(view, element, "text"); - if(!elem) - return; + const ThemeData::ThemeElement* elem = theme->getElement(view, element, "text"); + if (!elem) + return; - if (properties & COLOR && elem->has("color")) - setColor(elem->get("color")); + if (properties & COLOR && elem->has("color")) + setColor(elem->get("color")); - setRenderBackground(false); - if (properties & COLOR && elem->has("backgroundColor")) { - setBackgroundColor(elem->get("backgroundColor")); - setRenderBackground(true); - } + setRenderBackground(false); + if (properties & COLOR && elem->has("backgroundColor")) { + setBackgroundColor(elem->get("backgroundColor")); + setRenderBackground(true); + } - if(properties & ALIGNMENT && elem->has("alignment")) - { - std::string str = elem->get("alignment"); - if(str == "left") - setHorizontalAlignment(ALIGN_LEFT); - else if(str == "center") - setHorizontalAlignment(ALIGN_CENTER); - else if(str == "right") - setHorizontalAlignment(ALIGN_RIGHT); - else - LOG(LogError) << "Unknown text alignment string: " << str; - } + if (properties & ALIGNMENT && elem->has("alignment")) { + std::string str = elem->get("alignment"); + if (str == "left") + setHorizontalAlignment(ALIGN_LEFT); + else if (str == "center") + setHorizontalAlignment(ALIGN_CENTER); + else if (str == "right") + setHorizontalAlignment(ALIGN_RIGHT); + else + LOG(LogError) << "Unknown text alignment string: " << str; + } - if(properties & TEXT && elem->has("text")) - setText(elem->get("text")); + if (properties & TEXT && elem->has("text")) + setText(elem->get("text")); - if(properties & FORCE_UPPERCASE && elem->has("forceUppercase")) - setUppercase(elem->get("forceUppercase")); + if (properties & FORCE_UPPERCASE && elem->has("forceUppercase")) + setUppercase(elem->get("forceUppercase")); - if(properties & LINE_SPACING && elem->has("lineSpacing")) - setLineSpacing(elem->get("lineSpacing")); + if (properties & LINE_SPACING && elem->has("lineSpacing")) + setLineSpacing(elem->get("lineSpacing")); - setFont(Font::getFromTheme(elem, properties, mFont)); + setFont(Font::getFromTheme(elem, properties, mFont)); } diff --git a/es-core/src/components/TextComponent.h b/es-core/src/components/TextComponent.h index 689742c76..b458344ee 100644 --- a/es-core/src/components/TextComponent.h +++ b/es-core/src/components/TextComponent.h @@ -1,3 +1,9 @@ +// +// TextComponent.h +// +// Displays text. +// + #pragma once #ifndef ES_CORE_COMPONENTS_TEXT_COMPONENT_H #define ES_CORE_COMPONENTS_TEXT_COMPONENT_H @@ -9,63 +15,73 @@ class ThemeData; // Used to display text. // TextComponent::setSize(x, y) works a little differently than most components: -// * (0, 0) - will automatically calculate a size that fits the text on one line (expand horizontally) -// * (x != 0, 0) - wrap text so that it does not reach beyond x. Will automatically calculate a vertical size (expand vertically). -// * (x != 0, y <= fontHeight) - will truncate text so it fits within this box. +// * (0, 0) - Will automatically calculate a size that fits +// the text on one line (expand horizontally). +// * (x != 0, 0) - Wrap text so that it does not reach beyond x. Will +// automatically calculate a vertical size (expand vertically). +// * (x != 0, y <= fontHeight) - Will truncate text so it fits within this box. class TextComponent : public GuiComponent { public: - TextComponent(Window* window); - TextComponent(Window* window, const std::string& text, const std::shared_ptr& font, unsigned int color = 0x000000FF, Alignment align = ALIGN_LEFT, - Vector3f pos = Vector3f::Zero(), Vector2f size = Vector2f::Zero(), unsigned int bgcolor = 0x00000000); + TextComponent(Window* window); + TextComponent( + Window* window, + const std::string& text, + const std::shared_ptr& font, + unsigned int color = 0x000000FF, + Alignment align = ALIGN_LEFT, + Vector3f pos = Vector3f::Zero(), + Vector2f size = Vector2f::Zero(), + unsigned int bgcolor = 0x00000000); - void setFont(const std::shared_ptr& font); - void setUppercase(bool uppercase); - void onSizeChanged() override; - void setText(const std::string& text); - void setColor(unsigned int color) override; - void setHorizontalAlignment(Alignment align); - void setVerticalAlignment(Alignment align); - void setLineSpacing(float spacing); - void setBackgroundColor(unsigned int color); - void setRenderBackground(bool render); + void setFont(const std::shared_ptr& font); + void setUppercase(bool uppercase); + void onSizeChanged() override; + void setText(const std::string& text); + void setColor(unsigned int color) override; + void setHorizontalAlignment(Alignment align); + void setVerticalAlignment(Alignment align); + void setLineSpacing(float spacing); + void setBackgroundColor(unsigned int color); + void setRenderBackground(bool render); - unsigned int getColor() const override { return mColor; }; - void render(const Transform4x4f& parentTrans) override; + unsigned int getColor() const override { return mColor; }; + void render(const Transform4x4f& parentTrans) override; - std::string getValue() const override; - void setValue(const std::string& value) override; + std::string getValue() const override; + void setValue(const std::string& value) override; - unsigned char getOpacity() const override; - void setOpacity(unsigned char opacity) override; + unsigned char getOpacity() const override; + void setOpacity(unsigned char opacity) override; - inline std::shared_ptr getFont() const { return mFont; } + inline std::shared_ptr getFont() const { return mFont; } - virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) override; + virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, + const std::string& element, unsigned int properties) override; protected: - virtual void onTextChanged(); + virtual void onTextChanged(); - std::string mText; - std::shared_ptr mFont; + std::string mText; + std::shared_ptr mFont; private: - void calculateExtent(); + void calculateExtent(); - void onColorChanged(); + void onColorChanged(); - unsigned int mColor; - unsigned int mBgColor; - unsigned char mColorOpacity; - unsigned char mBgColorOpacity; - bool mRenderBackground; + unsigned int mColor; + unsigned int mBgColor; + unsigned char mColorOpacity; + unsigned char mBgColorOpacity; + bool mRenderBackground; - bool mUppercase; - Vector2i mAutoCalcExtent; - std::shared_ptr mTextCache; - Alignment mHorizontalAlignment; - Alignment mVerticalAlignment; - float mLineSpacing; + bool mUppercase; + Vector2i mAutoCalcExtent; + std::shared_ptr mTextCache; + Alignment mHorizontalAlignment; + Alignment mVerticalAlignment; + float mLineSpacing; }; #endif // ES_CORE_COMPONENTS_TEXT_COMPONENT_H diff --git a/es-core/src/components/TextListComponent.h b/es-core/src/components/TextListComponent.h index d26a37409..52f666ecc 100644 --- a/es-core/src/components/TextListComponent.h +++ b/es-core/src/components/TextListComponent.h @@ -1,7 +1,7 @@ // -// TextListComponent.h +// TextListComponent.h // -// Used for displaying and navigating the gamelists. +// Used for displaying and navigating the gamelists. // #pragma once @@ -18,8 +18,8 @@ class TextCache; struct TextListData { - unsigned int colorId; - std::shared_ptr textCache; + unsigned int colorId; + std::shared_ptr textCache; }; // A graphical list. Supports multiple colors for rows and scrolling. @@ -27,441 +27,441 @@ template class TextListComponent : public IList { protected: - using IList::mEntries; - using IList::listUpdate; - using IList::listInput; - using IList::listRenderTitleOverlay; - using IList::getTransform; - using IList::mSize; - using IList::mCursor; -// The following change is required for compilation with Clang. -// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2070 -// using IList::Entry; - using IList::IList; + using IList::mEntries; + using IList::listUpdate; + using IList::listInput; + using IList::listRenderTitleOverlay; + using IList::getTransform; + using IList::mSize; + using IList::mCursor; + // The following change is required for compilation with Clang. + // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2070 + // using IList::Entry; + using IList::IList; public: - using IList::size; - using IList::isScrolling; - using IList::stopScrolling; + using IList::size; + using IList::isScrolling; + using IList::stopScrolling; - TextListComponent(Window* window); + TextListComponent(Window* window); - bool input(InputConfig* config, Input input) override; - void update(int deltaTime) override; - void render(const Transform4x4f& parentTrans) override; - void applyTheme(const std::shared_ptr& theme, const std::string& view, - const std::string& element, unsigned int properties) override; + bool input(InputConfig* config, Input input) override; + void update(int deltaTime) override; + void render(const Transform4x4f& parentTrans) override; + void applyTheme(const std::shared_ptr& theme, const std::string& view, + const std::string& element, unsigned int properties) override; - void add(const std::string& name, const T& obj, unsigned int colorId); + void add(const std::string& name, const T& obj, unsigned int colorId); - enum Alignment { - ALIGN_LEFT, - ALIGN_CENTER, - ALIGN_RIGHT - }; + enum Alignment { + ALIGN_LEFT, + ALIGN_CENTER, + ALIGN_RIGHT + }; - inline void setAlignment(Alignment align) { mAlignment = align; } + inline void setAlignment(Alignment align) { mAlignment = align; } - inline void setCursorChangedCallback(const std::function& func) - { mCursorChangedCallback = func; } + inline void setCursorChangedCallback(const std::function& func) + { mCursorChangedCallback = func; } - inline void setFont(const std::shared_ptr& font) - { - mFont = font; - for (auto it = mEntries.begin(); it != mEntries.end(); it++) - it->data.textCache.reset(); - } + inline void setFont(const std::shared_ptr& font) + { + mFont = font; + for (auto it = mEntries.begin(); it != mEntries.end(); it++) + it->data.textCache.reset(); + } - inline void setUppercase(bool /*uppercase*/) - { - mUppercase = true; - for (auto it = mEntries.begin(); it != mEntries.end(); it++) - it->data.textCache.reset(); - } + inline void setUppercase(bool /*uppercase*/) + { + mUppercase = true; + for (auto it = mEntries.begin(); it != mEntries.end(); it++) + it->data.textCache.reset(); + } - inline void setSelectorHeight(float selectorScale) { mSelectorHeight = selectorScale; } - inline void setSelectorOffsetY(float selectorOffsetY) { mSelectorOffsetY = selectorOffsetY; } - inline void setSelectorColor(unsigned int color) { mSelectorColor = color; } - inline void setSelectorColorEnd(unsigned int color) { mSelectorColorEnd = color; } - inline void setSelectorColorGradientHorizontal(bool horizontal) - { mSelectorColorGradientHorizontal = horizontal; } - inline void setSelectedColor(unsigned int color) { mSelectedColor = color; } - inline void setColor(unsigned int id, unsigned int color) { mColors[id] = color; } - inline void setLineSpacing(float lineSpacing) { mLineSpacing = lineSpacing; } + inline void setSelectorHeight(float selectorScale) { mSelectorHeight = selectorScale; } + inline void setSelectorOffsetY(float selectorOffsetY) { mSelectorOffsetY = selectorOffsetY; } + inline void setSelectorColor(unsigned int color) { mSelectorColor = color; } + inline void setSelectorColorEnd(unsigned int color) { mSelectorColorEnd = color; } + inline void setSelectorColorGradientHorizontal(bool horizontal) + { mSelectorColorGradientHorizontal = horizontal; } + inline void setSelectedColor(unsigned int color) { mSelectedColor = color; } + inline void setColor(unsigned int id, unsigned int color) { mColors[id] = color; } + inline void setLineSpacing(float lineSpacing) { mLineSpacing = lineSpacing; } protected: - virtual void onScroll() override { - NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND); } - virtual void onCursorChanged(const CursorState& state) override; + virtual void onScroll() override { + NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND); } + virtual void onCursorChanged(const CursorState& state) override; private: - int mMarqueeOffset; - int mMarqueeOffset2; - int mMarqueeTime; + int mMarqueeOffset; + int mMarqueeOffset2; + int mMarqueeTime; - Alignment mAlignment; - float mHorizontalMargin; + Alignment mAlignment; + float mHorizontalMargin; - std::function mCursorChangedCallback; + std::function mCursorChangedCallback; - std::shared_ptr mFont; - bool mUppercase; - float mLineSpacing; - float mSelectorHeight; - float mSelectorOffsetY; - unsigned int mSelectorColor; - unsigned int mSelectorColorEnd; - bool mSelectorColorGradientHorizontal = true; - unsigned int mSelectedColor; - static const unsigned int COLOR_ID_COUNT = 2; - unsigned int mColors[COLOR_ID_COUNT]; + std::shared_ptr mFont; + bool mUppercase; + float mLineSpacing; + float mSelectorHeight; + float mSelectorOffsetY; + unsigned int mSelectorColor; + unsigned int mSelectorColorEnd; + bool mSelectorColorGradientHorizontal = true; + unsigned int mSelectedColor; + static const unsigned int COLOR_ID_COUNT = 2; + unsigned int mColors[COLOR_ID_COUNT]; - ImageComponent mSelectorImage; + ImageComponent mSelectorImage; }; template TextListComponent::TextListComponent(Window* window) : - IList(window), mSelectorImage(window) + IList(window), mSelectorImage(window) { - mMarqueeOffset = 0; - mMarqueeOffset2 = 0; - mMarqueeTime = 0; + mMarqueeOffset = 0; + mMarqueeOffset2 = 0; + mMarqueeTime = 0; - mHorizontalMargin = 0; - mAlignment = ALIGN_CENTER; + mHorizontalMargin = 0; + mAlignment = ALIGN_CENTER; - mFont = Font::get(FONT_SIZE_MEDIUM); - mUppercase = false; - mLineSpacing = 1.5f; - mSelectorHeight = mFont->getSize() * 1.5f; - mSelectorOffsetY = 0; - mSelectorColor = 0x000000FF; - mSelectorColorEnd = 0x000000FF; - mSelectorColorGradientHorizontal = true; - mSelectedColor = 0; - mColors[0] = 0x0000FFFF; - mColors[1] = 0x00FF00FF; + mFont = Font::get(FONT_SIZE_MEDIUM); + mUppercase = false; + mLineSpacing = 1.5f; + mSelectorHeight = mFont->getSize() * 1.5f; + mSelectorOffsetY = 0; + mSelectorColor = 0x000000FF; + mSelectorColorEnd = 0x000000FF; + mSelectorColorGradientHorizontal = true; + mSelectedColor = 0; + mColors[0] = 0x0000FFFF; + mColors[1] = 0x00FF00FF; } template void TextListComponent::render(const Transform4x4f& parentTrans) { - Transform4x4f trans = parentTrans * getTransform(); + Transform4x4f trans = parentTrans * getTransform(); - std::shared_ptr& font = mFont; + std::shared_ptr& font = mFont; - if (size() == 0) - return; + if (size() == 0) + return; - const float entrySize = Math::max(font->getHeight(1.0), (float)font->getSize()) * mLineSpacing; + const float entrySize = Math::max(font->getHeight(1.0), (float)font->getSize()) * mLineSpacing; - int startEntry = 0; + int startEntry = 0; - // Number of entries that can fit on the screen simultaniously. - int screenCount = (int)(mSize.y() / entrySize + 0.5f); + // Number of entries that can fit on the screen simultaniously. + int screenCount = (int)(mSize.y() / entrySize + 0.5f); - if (size() >= screenCount) - { - startEntry = mCursor - screenCount/2; - if (startEntry < 0) - startEntry = 0; - if (startEntry >= size() - screenCount) - startEntry = size() - screenCount; - } + if (size() >= screenCount) + { + startEntry = mCursor - screenCount/2; + if (startEntry < 0) + startEntry = 0; + if (startEntry >= size() - screenCount) + startEntry = size() - screenCount; + } - float y = 0; + float y = 0; - int listCutoff = startEntry + screenCount; - if (listCutoff > size()) - listCutoff = size(); + int listCutoff = startEntry + screenCount; + if (listCutoff > size()) + listCutoff = size(); - // Draw selector bar. - if (startEntry < listCutoff) { - if (mSelectorImage.hasImage()) { - mSelectorImage.setPosition(0.f, - (mCursor - startEntry)*entrySize + mSelectorOffsetY, 0.f); - mSelectorImage.render(trans); - } - else { - Renderer::setMatrix(trans); - Renderer::drawRect( - 0.0f, - (mCursor - startEntry)*entrySize + - mSelectorOffsetY, - mSize.x(), - mSelectorHeight, - mSelectorColor, - mSelectorColorEnd, - mSelectorColorGradientHorizontal); - } - } + // Draw selector bar. + if (startEntry < listCutoff) { + if (mSelectorImage.hasImage()) { + mSelectorImage.setPosition(0.f, + (mCursor - startEntry)*entrySize + mSelectorOffsetY, 0.f); + mSelectorImage.render(trans); + } + else { + Renderer::setMatrix(trans); + Renderer::drawRect( + 0.0f, + (mCursor - startEntry)*entrySize + + mSelectorOffsetY, + mSize.x(), + mSelectorHeight, + mSelectorColor, + mSelectorColorEnd, + mSelectorColorGradientHorizontal); + } + } - // Clip to inside margins. - Vector3f dim(mSize.x(), mSize.y(), 0); - dim = trans * dim - trans.translation(); - Renderer::pushClipRect(Vector2i((int)(trans.translation().x() + mHorizontalMargin), - (int)trans.translation().y()), Vector2i((int)(dim.x() - mHorizontalMargin*2), - (int)dim.y())); + // Clip to inside margins. + Vector3f dim(mSize.x(), mSize.y(), 0); + dim = trans * dim - trans.translation(); + Renderer::pushClipRect(Vector2i((int)(trans.translation().x() + mHorizontalMargin), + (int)trans.translation().y()), Vector2i((int)(dim.x() - mHorizontalMargin*2), + (int)dim.y())); - for (int i = startEntry; i < listCutoff; i++) { - typename IList::Entry& entry = mEntries.at((unsigned int)i); + for (int i = startEntry; i < listCutoff; i++) { + typename IList::Entry& entry = mEntries.at((unsigned int)i); - unsigned int color; - if (mCursor == i && mSelectedColor) - color = mSelectedColor; - else - color = mColors[entry.data.colorId]; + unsigned int color; + if (mCursor == i && mSelectedColor) + color = mSelectedColor; + else + color = mColors[entry.data.colorId]; - if (!entry.data.textCache) - entry.data.textCache = std::unique_ptr - (font->buildTextCache(mUppercase ? - Utils::String::toUpper(entry.name) : entry.name, 0, 0, 0x000000FF)); + if (!entry.data.textCache) + entry.data.textCache = std::unique_ptr + (font->buildTextCache(mUppercase ? + Utils::String::toUpper(entry.name) : entry.name, 0, 0, 0x000000FF)); - entry.data.textCache->setColor(color); + entry.data.textCache->setColor(color); - Vector3f offset(0, y, 0); + Vector3f offset(0, y, 0); - switch (mAlignment) { - case ALIGN_LEFT: - offset[0] = mHorizontalMargin; - break; - case ALIGN_CENTER: - offset[0] = (int)((mSize.x() - entry.data.textCache->metrics.size.x()) / 2); - if (offset[0] < mHorizontalMargin) - offset[0] = mHorizontalMargin; - break; - case ALIGN_RIGHT: - offset[0] = (mSize.x() - entry.data.textCache->metrics.size.x()); - offset[0] -= mHorizontalMargin; - if (offset[0] < mHorizontalMargin) - offset[0] = mHorizontalMargin; - break; - } + switch (mAlignment) { + case ALIGN_LEFT: + offset[0] = mHorizontalMargin; + break; + case ALIGN_CENTER: + offset[0] = (int)((mSize.x() - entry.data.textCache->metrics.size.x()) / 2); + if (offset[0] < mHorizontalMargin) + offset[0] = mHorizontalMargin; + break; + case ALIGN_RIGHT: + offset[0] = (mSize.x() - entry.data.textCache->metrics.size.x()); + offset[0] -= mHorizontalMargin; + if (offset[0] < mHorizontalMargin) + offset[0] = mHorizontalMargin; + break; + } - // Render text. - Transform4x4f drawTrans = trans; + // Render text. + Transform4x4f drawTrans = trans; - // Currently selected item text might be scrolling. - if ((mCursor == i) && (mMarqueeOffset > 0)) - drawTrans.translate(offset - Vector3f((float)mMarqueeOffset, 0, 0)); - else - drawTrans.translate(offset); + // Currently selected item text might be scrolling. + if ((mCursor == i) && (mMarqueeOffset > 0)) + drawTrans.translate(offset - Vector3f((float)mMarqueeOffset, 0, 0)); + else + drawTrans.translate(offset); - Renderer::setMatrix(drawTrans); - font->renderTextCache(entry.data.textCache.get()); + Renderer::setMatrix(drawTrans); + font->renderTextCache(entry.data.textCache.get()); - // Render currently selected item text again if marquee is - // scrolled far enough for it to repeat. - if ((mCursor == i) && (mMarqueeOffset2 < 0)) { - drawTrans = trans; - drawTrans.translate(offset - Vector3f((float)mMarqueeOffset2, 0, 0)); - Renderer::setMatrix(drawTrans); - font->renderTextCache(entry.data.textCache.get()); - } + // Render currently selected item text again if marquee is + // scrolled far enough for it to repeat. + if ((mCursor == i) && (mMarqueeOffset2 < 0)) { + drawTrans = trans; + drawTrans.translate(offset - Vector3f((float)mMarqueeOffset2, 0, 0)); + Renderer::setMatrix(drawTrans); + font->renderTextCache(entry.data.textCache.get()); + } - y += entrySize; - } + y += entrySize; + } - Renderer::popClipRect(); - listRenderTitleOverlay(trans); - GuiComponent::renderChildren(trans); + Renderer::popClipRect(); + listRenderTitleOverlay(trans); + GuiComponent::renderChildren(trans); } template bool TextListComponent::input(InputConfig* config, Input input) { - if (size() > 0) { - if (input.value != 0) { - if (config->isMappedLike("down", input)) { - listInput(1); - return true; - } + if (size() > 0) { + if (input.value != 0) { + if (config->isMappedLike("down", input)) { + listInput(1); + return true; + } - if (config->isMappedLike("up", input)) { - listInput(-1); - return true; - } - if (config->isMappedLike("rightshoulder", input)) { - listInput(10); - return true; - } + if (config->isMappedLike("up", input)) { + listInput(-1); + return true; + } + if (config->isMappedLike("rightshoulder", input)) { + listInput(10); + return true; + } - if (config->isMappedLike("leftshoulder", input)) { - listInput(-10); - return true; - } + if (config->isMappedLike("leftshoulder", input)) { + listInput(-10); + return true; + } - if (config->isMappedLike("righttrigger", input)) { - return this->listLastRow(); - } + if (config->isMappedLike("righttrigger", input)) { + return this->listLastRow(); + } - if (config->isMappedLike("lefttrigger", input)) { - return this->listFirstRow(); - } - } - else { - if (config->isMappedLike("down", input) || - config->isMappedLike("up", input) || - config->isMappedLike("rightshoulder", input) || - config->isMappedLike("leftshoulder", input) || - config->isMappedLike("lefttrigger", input) || - config->isMappedLike("righttrigger", input)) - stopScrolling(); - } - } - // Explicitly stop the scrolling, otherwise it will go forever in case - // the menu was openened or another gamelist was selected using the - // quick system selector etc. - stopScrolling(); + if (config->isMappedLike("lefttrigger", input)) { + return this->listFirstRow(); + } + } + else { + if (config->isMappedLike("down", input) || + config->isMappedLike("up", input) || + config->isMappedLike("rightshoulder", input) || + config->isMappedLike("leftshoulder", input) || + config->isMappedLike("lefttrigger", input) || + config->isMappedLike("righttrigger", input)) + stopScrolling(); + } + } + // Explicitly stop the scrolling, otherwise it will go forever in case + // the menu was openened or another gamelist was selected using the + // quick system selector etc. + stopScrolling(); - return GuiComponent::input(config, input); + return GuiComponent::input(config, input); } template void TextListComponent::update(int deltaTime) { - listUpdate(deltaTime); + listUpdate(deltaTime); - if (!isScrolling() && size() > 0) { - // Always reset the marquee offsets. - mMarqueeOffset = 0; - mMarqueeOffset2 = 0; + if (!isScrolling() && size() > 0) { + // Always reset the marquee offsets. + mMarqueeOffset = 0; + mMarqueeOffset2 = 0; - // If we're not scrolling and this object's text goes outside our size, marquee it! - const float textLength = mFont->sizeText(mEntries.at((unsigned int)mCursor).name).x(); - const float limit = mSize.x() - mHorizontalMargin * 2; + // If we're not scrolling and this object's text goes outside our size, marquee it! + const float textLength = mFont->sizeText(mEntries.at((unsigned int)mCursor).name).x(); + const float limit = mSize.x() - mHorizontalMargin * 2; - if (textLength > limit) { - // Loop. - // Pixels per second (based on nes-mini font at 1920x1080 to produce a speed of 200). - const float speed = mFont->sizeText("ABCDEFGHIJKLMNOPQRSTUVWXYZ").x() * 0.247f; - const float delay = 3000; - const float scrollLength = textLength; - const float returnLength = speed * 1.5f; - const float scrollTime = (scrollLength * 1000) / speed; - const float returnTime = (returnLength * 1000) / speed; - const int maxTime = (int)(delay + scrollTime + returnTime); + if (textLength > limit) { + // Loop. + // Pixels per second (based on nes-mini font at 1920x1080 to produce a speed of 200). + const float speed = mFont->sizeText("ABCDEFGHIJKLMNOPQRSTUVWXYZ").x() * 0.247f; + const float delay = 3000; + const float scrollLength = textLength; + const float returnLength = speed * 1.5f; + const float scrollTime = (scrollLength * 1000) / speed; + const float returnTime = (returnLength * 1000) / speed; + const int maxTime = (int)(delay + scrollTime + returnTime); - mMarqueeTime += deltaTime; - while (mMarqueeTime > maxTime) - mMarqueeTime -= maxTime; + mMarqueeTime += deltaTime; + while (mMarqueeTime > maxTime) + mMarqueeTime -= maxTime; - mMarqueeOffset = (int)(Math::Scroll::loop(delay, scrollTime + returnTime, - (float)mMarqueeTime, scrollLength + returnLength)); + mMarqueeOffset = (int)(Math::Scroll::loop(delay, scrollTime + returnTime, + (float)mMarqueeTime, scrollLength + returnLength)); - if (mMarqueeOffset > (scrollLength - (limit - returnLength))) - mMarqueeOffset2 = (int)(mMarqueeOffset - (scrollLength + returnLength)); - } - } + if (mMarqueeOffset > (scrollLength - (limit - returnLength))) + mMarqueeOffset2 = (int)(mMarqueeOffset - (scrollLength + returnLength)); + } + } - GuiComponent::update(deltaTime); + GuiComponent::update(deltaTime); } // List management stuff. template void TextListComponent::add(const std::string& name, const T& obj, unsigned int color) { - assert(color < COLOR_ID_COUNT); + assert(color < COLOR_ID_COUNT); - typename IList::Entry entry; - entry.name = name; - entry.object = obj; - entry.data.colorId = color; - static_cast*>(this)->add(entry); + typename IList::Entry entry; + entry.name = name; + entry.object = obj; + entry.data.colorId = color; + static_cast*>(this)->add(entry); } template void TextListComponent::onCursorChanged(const CursorState& state) { - mMarqueeOffset = 0; - mMarqueeOffset2 = 0; - mMarqueeTime = 0; + mMarqueeOffset = 0; + mMarqueeOffset2 = 0; + mMarqueeTime = 0; - if (mCursorChangedCallback) - mCursorChangedCallback(state); + if (mCursorChangedCallback) + mCursorChangedCallback(state); } template void TextListComponent::applyTheme(const std::shared_ptr& theme, - const std::string& view, const std::string& element, unsigned int properties) + const std::string& view, const std::string& element, unsigned int properties) { - GuiComponent::applyTheme(theme, view, element, properties); + GuiComponent::applyTheme(theme, view, element, properties); - const ThemeData::ThemeElement* elem = theme->getElement(view, element, "textlist"); - if (!elem) - return; + const ThemeData::ThemeElement* elem = theme->getElement(view, element, "textlist"); + if (!elem) + return; - using namespace ThemeFlags; - if (properties & COLOR) { - if (elem->has("selectorColor")) { - setSelectorColor(elem->get("selectorColor")); - setSelectorColorEnd(elem->get("selectorColor")); - } - if (elem->has("selectorColorEnd")) - setSelectorColorEnd(elem->get("selectorColorEnd")); - if (elem->has("selectorGradientType")) - setSelectorColorGradientHorizontal(!(elem->get - ("selectorGradientType").compare("horizontal"))); - if (elem->has("selectedColor")) - setSelectedColor(elem->get("selectedColor")); - if (elem->has("primaryColor")) - setColor(0, elem->get("primaryColor")); - if (elem->has("secondaryColor")) - setColor(1, elem->get("secondaryColor")); - } + using namespace ThemeFlags; + if (properties & COLOR) { + if (elem->has("selectorColor")) { + setSelectorColor(elem->get("selectorColor")); + setSelectorColorEnd(elem->get("selectorColor")); + } + if (elem->has("selectorColorEnd")) + setSelectorColorEnd(elem->get("selectorColorEnd")); + if (elem->has("selectorGradientType")) + setSelectorColorGradientHorizontal(!(elem->get + ("selectorGradientType").compare("horizontal"))); + if (elem->has("selectedColor")) + setSelectedColor(elem->get("selectedColor")); + if (elem->has("primaryColor")) + setColor(0, elem->get("primaryColor")); + if (elem->has("secondaryColor")) + setColor(1, elem->get("secondaryColor")); + } - setFont(Font::getFromTheme(elem, properties, mFont)); - const float selectorHeight = Math::max(mFont->getHeight(1.0), - (float)mFont->getSize()) * mLineSpacing; - setSelectorHeight(selectorHeight); + setFont(Font::getFromTheme(elem, properties, mFont)); + const float selectorHeight = Math::max(mFont->getHeight(1.0), + (float)mFont->getSize()) * mLineSpacing; + setSelectorHeight(selectorHeight); - if (properties & ALIGNMENT) { - if (elem->has("alignment")) { - const std::string& str = elem->get("alignment"); - if (str == "left") - setAlignment(ALIGN_LEFT); - else if (str == "center") - setAlignment(ALIGN_CENTER); - else if (str == "right") - setAlignment(ALIGN_RIGHT); - else - LOG(LogError) << "Unknown TextListComponent alignment \"" << str << "\"!"; - } - if (elem->has("horizontalMargin")) { - mHorizontalMargin = elem->get("horizontalMargin") * - (this->mParent ? this->mParent->getSize().x() : - (float)Renderer::getScreenWidth()); - } - } + if (properties & ALIGNMENT) { + if (elem->has("alignment")) { + const std::string& str = elem->get("alignment"); + if (str == "left") + setAlignment(ALIGN_LEFT); + else if (str == "center") + setAlignment(ALIGN_CENTER); + else if (str == "right") + setAlignment(ALIGN_RIGHT); + else + LOG(LogError) << "Unknown TextListComponent alignment \"" << str << "\"!"; + } + if (elem->has("horizontalMargin")) { + mHorizontalMargin = elem->get("horizontalMargin") * + (this->mParent ? this->mParent->getSize().x() : + (float)Renderer::getScreenWidth()); + } + } - if (properties & FORCE_UPPERCASE && elem->has("forceUppercase")) - setUppercase(elem->get("forceUppercase")); + if (properties & FORCE_UPPERCASE && elem->has("forceUppercase")) + setUppercase(elem->get("forceUppercase")); - if (properties & LINE_SPACING) { - if (elem->has("lineSpacing")) - setLineSpacing(elem->get("lineSpacing")); - if (elem->has("selectorHeight")) - setSelectorHeight(elem->get("selectorHeight") * Renderer::getScreenHeight()); - if (elem->has("selectorOffsetY")) { - float scale = this->mParent ? this->mParent->getSize().y() : (float)Renderer::getScreenHeight(); - setSelectorOffsetY(elem->get("selectorOffsetY") * scale); - } - else { - setSelectorOffsetY(0.0); - } - } + if (properties & LINE_SPACING) { + if (elem->has("lineSpacing")) + setLineSpacing(elem->get("lineSpacing")); + if (elem->has("selectorHeight")) + setSelectorHeight(elem->get("selectorHeight") * Renderer::getScreenHeight()); + if (elem->has("selectorOffsetY")) { + float scale = this->mParent ? this->mParent->getSize().y() : (float)Renderer::getScreenHeight(); + setSelectorOffsetY(elem->get("selectorOffsetY") * scale); + } + else { + setSelectorOffsetY(0.0); + } + } - if (elem->has("selectorImagePath")) { - std::string path = elem->get("selectorImagePath"); - bool tile = elem->has("selectorImageTile") && elem->get("selectorImageTile"); - mSelectorImage.setImage(path, tile); - mSelectorImage.setSize(mSize.x(), mSelectorHeight); - mSelectorImage.setColorShift(mSelectorColor); - mSelectorImage.setColorShiftEnd(mSelectorColorEnd); - } - else { - mSelectorImage.setImage(""); - } + if (elem->has("selectorImagePath")) { + std::string path = elem->get("selectorImagePath"); + bool tile = elem->has("selectorImageTile") && elem->get("selectorImageTile"); + mSelectorImage.setImage(path, tile); + mSelectorImage.setSize(mSize.x(), mSelectorHeight); + mSelectorImage.setColorShift(mSelectorColor); + mSelectorImage.setColorShiftEnd(mSelectorColorEnd); + } + else { + mSelectorImage.setImage(""); + } } #endif // ES_APP_COMPONENTS_TEXT_LIST_COMPONENT_H diff --git a/es-core/src/components/VideoComponent.cpp b/es-core/src/components/VideoComponent.cpp index d1824a377..77225cbd3 100644 --- a/es-core/src/components/VideoComponent.cpp +++ b/es-core/src/components/VideoComponent.cpp @@ -1,3 +1,9 @@ +// +// VideoComponent.cpp +// +// Base class for playing videos. +// + #include "components/VideoComponent.h" #include "resources/ResourceManager.h" @@ -15,228 +21,230 @@ #define FADE_TIME_MS 200 std::string getTitlePath() { - std::string titleFolder = getTitleFolder(); - return titleFolder + "last_title.srt"; + std::string titleFolder = getTitleFolder(); + return titleFolder + "last_title.srt"; } std::string getTitleFolder() { - std::string home = Utils::FileSystem::getHomePath(); - return home + "/.emulationstation/tmp/"; + std::string home = Utils::FileSystem::getHomePath(); + return home + "/.emulationstation/tmp/"; } void writeSubtitle(const char* gameName, const char* systemName, bool always) { - FILE* file = fopen(getTitlePath().c_str(), "w"); - int end = (int)(Settings::getInstance()->getInt("ScreenSaverSwapVideoTimeout") / (1000)); - if (always) { - fprintf(file, "1\n00:00:01,000 --> 00:00:%d,000\n", end); - } - else - { - fprintf(file, "1\n00:00:01,000 --> 00:00:08,000\n"); - } - fprintf(file, "%s\n", gameName); - fprintf(file, "%s\n\n", systemName); + FILE* file = fopen(getTitlePath().c_str(), "w"); + int end = (int)(Settings::getInstance()->getInt("ScreenSaverSwapVideoTimeout") / (1000)); - if (!always) { - if (end > 12) - { - fprintf(file, "2\n00:00:%d,000 --> 00:00:%d,000\n%s\n%s\n", end-4, end, gameName, systemName); - } - } + if (always) + fprintf(file, "1\n00:00:01,000 --> 00:00:%d,000\n", end); + else + fprintf(file, "1\n00:00:01,000 --> 00:00:08,000\n"); - fflush(file); - fclose(file); - file = NULL; + fprintf(file, "%s\n", gameName); + fprintf(file, "%s\n\n", systemName); + + if (!always) { + if (end > 12) + fprintf(file, "2\n00:00:%d,000 --> 00:00:%d,000\n%s\n%s\n", + end-4, end, gameName, systemName); + } + + fflush(file); + fclose(file); + file = nullptr; } void VideoComponent::setScreensaverMode(bool isScreensaver) { - mScreensaverMode = isScreensaver; + mScreensaverMode = isScreensaver; } -VideoComponent::VideoComponent(Window* window) : - GuiComponent(window), - mStaticImage(window), - mVideoHeight(0), - mVideoWidth(0), - mStartDelayed(false), - mIsPlaying(false), - mShowing(false), - mScreensaverActive(false), - mDisable(false), - mScreensaverMode(false), - mTargetIsMax(false), - mTargetSize(0, 0) +VideoComponent::VideoComponent( + Window* window) + : GuiComponent(window), + mStaticImage(window), + mVideoHeight(0), + mVideoWidth(0), + mStartDelayed(false), + mIsPlaying(false), + mShowing(false), + mScreensaverActive(false), + mDisable(false), + mScreensaverMode(false), + mTargetIsMax(false), + mTargetSize(0, 0) { - // Setup the default configuration - mConfig.showSnapshotDelay = false; - mConfig.showSnapshotNoVideo = false; - mConfig.startDelay = 0; - if (mWindow->getGuiStackSize() > 1) { - topWindow(false); - } + // Setup the default configuration. + mConfig.showSnapshotDelay = false; + mConfig.showSnapshotNoVideo = false; + mConfig.startDelay = 0; - std::string path = getTitleFolder(); - if(!Utils::FileSystem::exists(path)) - Utils::FileSystem::createDirectory(path); + if (mWindow->getGuiStackSize() > 1) + topWindow(false); + + std::string path = getTitleFolder(); + + if (!Utils::FileSystem::exists(path)) + Utils::FileSystem::createDirectory(path); } VideoComponent::~VideoComponent() { - // Stop any currently running video - stopVideo(); - // Delete subtitle file, if existing - remove(getTitlePath().c_str()); + // Stop any currently running video. + stopVideo(); + // Delete subtitle file, if existing. + remove(getTitlePath().c_str()); } void VideoComponent::onOriginChanged() { - // Update the embeded static image - mStaticImage.setOrigin(mOrigin); + // Update the embeded static image. + mStaticImage.setOrigin(mOrigin); } + void VideoComponent::onPositionChanged() { - // Update the embeded static image - mStaticImage.setPosition(mPosition); + // Update the embeded static image. + mStaticImage.setPosition(mPosition); } void VideoComponent::onSizeChanged() { - // Update the embeded static image - mStaticImage.onSizeChanged(); + // Update the embeded static image. + mStaticImage.onSizeChanged(); } bool VideoComponent::setVideo(std::string path) { - // Convert the path into a generic format - std::string fullPath = Utils::FileSystem::getCanonicalPath(path); + // Convert the path into a generic format. + std::string fullPath = Utils::FileSystem::getCanonicalPath(path); - // Check that it's changed - if (fullPath == mVideoPath) - return !path.empty(); + // Check that it's changed. + if (fullPath == mVideoPath) + return !path.empty(); - // Store the path - mVideoPath = fullPath; + // Store the path. + mVideoPath = fullPath; - // If the file exists then set the new video - if (!fullPath.empty() && ResourceManager::getInstance()->fileExists(fullPath)) - { - // Return true to show that we are going to attempt to play a video - return true; - } - // Return false to show that no video will be displayed - return false; + // If the file exists then set the new video. + if (!fullPath.empty() && ResourceManager::getInstance()->fileExists(fullPath)) { + // Return true to show that we are going to attempt to play a video. + return true; + } + + // Return false to show that no video will be displayed. + return false; } void VideoComponent::setImage(std::string path) { - // Check that the image has changed - if (path == mStaticImagePath) - return; + // Check that the image has changed. + if (path == mStaticImagePath) + return; - mStaticImage.setImage(path); - mFadeIn = 0.0f; - mStaticImagePath = path; + mStaticImage.setImage(path); + mFadeIn = 0.0f; + mStaticImagePath = path; } void VideoComponent::setDefaultVideo() { - setVideo(mConfig.defaultVideoPath); + setVideo(mConfig.defaultVideoPath); } void VideoComponent::setOpacity(unsigned char opacity) { - mOpacity = opacity; - // Update the embeded static image - mStaticImage.setOpacity(opacity); + mOpacity = opacity; + // Update the embeded static image. + mStaticImage.setOpacity(opacity); } void VideoComponent::render(const Transform4x4f& parentTrans) { - if (!isVisible()) - return; + if (!isVisible()) + return; - Transform4x4f trans = parentTrans * getTransform(); - GuiComponent::renderChildren(trans); + Transform4x4f trans = parentTrans * getTransform(); + GuiComponent::renderChildren(trans); - Renderer::setMatrix(trans); + Renderer::setMatrix(trans); - // Handle the case where the video is delayed - handleStartDelay(); + // Handle the case where the video is delayed. + handleStartDelay(); - // Handle looping of the video - handleLooping(); + // Handle looping of the video. + handleLooping(); } void VideoComponent::renderSnapshot(const Transform4x4f& parentTrans) { - // This is the case where the video is not currently being displayed. Work out - // if we need to display a static image - if ((mConfig.showSnapshotNoVideo && mVideoPath.empty()) || (mStartDelayed && mConfig.showSnapshotDelay)) - { - // Display the static image instead - mStaticImage.setOpacity((unsigned char)(mFadeIn * 255.0f)); - mStaticImage.render(parentTrans); - } + // This is the case where the video is not currently being displayed. Work out + // if we need to display a static image. + if ((mConfig.showSnapshotNoVideo && mVideoPath.empty()) || + (mStartDelayed && mConfig.showSnapshotDelay)) { + // Display the static image instead. + mStaticImage.setOpacity((unsigned char)(mFadeIn * 255.0f)); + mStaticImage.render(parentTrans); + } } -void VideoComponent::applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) +void VideoComponent::applyTheme(const std::shared_ptr& theme, const std::string& view, + const std::string& element, unsigned int properties) { - using namespace ThemeFlags; + using namespace ThemeFlags; - GuiComponent::applyTheme(theme, view, element, (properties ^ SIZE) | ((properties & (SIZE | POSITION)) ? ORIGIN : 0)); + GuiComponent::applyTheme(theme, view, element, (properties ^ SIZE) | + ((properties & (SIZE | POSITION)) ? ORIGIN : 0)); - const ThemeData::ThemeElement* elem = theme->getElement(view, element, "video"); - if(!elem) - return; + const ThemeData::ThemeElement* elem = theme->getElement(view, element, "video"); - Vector2f scale = getParent() ? getParent()->getSize() : Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); + if (!elem) + return; - if(properties & ThemeFlags::SIZE) - { - if(elem->has("size")) - setResize(elem->get("size") * scale); - else if(elem->has("maxSize")) - setMaxSize(elem->get("maxSize") * scale); - } + Vector2f scale = getParent() ? getParent()->getSize() + : Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); - if(elem->has("default")) - mConfig.defaultVideoPath = elem->get("default"); + if (properties & ThemeFlags::SIZE) { + if (elem->has("size")) + setResize(elem->get("size") * scale); + else if (elem->has("maxSize")) + setMaxSize(elem->get("maxSize") * scale); + } - if((properties & ThemeFlags::DELAY) && elem->has("delay")) - mConfig.startDelay = (unsigned)(elem->get("delay") * 1000.0f); + if (elem->has("default")) + mConfig.defaultVideoPath = elem->get("default"); - if (elem->has("showSnapshotNoVideo")) - mConfig.showSnapshotNoVideo = elem->get("showSnapshotNoVideo"); + if ((properties & ThemeFlags::DELAY) && elem->has("delay")) + mConfig.startDelay = (unsigned)(elem->get("delay") * 1000.0f); - if (elem->has("showSnapshotDelay")) - mConfig.showSnapshotDelay = elem->get("showSnapshotDelay"); + if (elem->has("showSnapshotNoVideo")) + mConfig.showSnapshotNoVideo = elem->get("showSnapshotNoVideo"); + + if (elem->has("showSnapshotDelay")) + mConfig.showSnapshotDelay = elem->get("showSnapshotDelay"); } std::vector VideoComponent::getHelpPrompts() { - std::vector ret; - ret.push_back(HelpPrompt("a", "select")); - return ret; + std::vector ret; + ret.push_back(HelpPrompt("a", "select")); + return ret; } void VideoComponent::handleStartDelay() { - // Only play if any delay has timed out - if (mStartDelayed) - { - if (mStartTime > SDL_GetTicks()) - { - // Timeout not yet completed - return; - } - // Completed - mStartDelayed = false; - // Clear the playing flag so startVideo works - mIsPlaying = false; - startVideo(); - } + // Only play if any delay has timed out. + if (mStartDelayed) { + if (mStartTime > SDL_GetTicks()) { + // Timeout not yet completed. + return; + } + // Completed. + mStartDelayed = false; + // Clear the playing flag so startVideo works. + mIsPlaying = false; + startVideo(); + } } void VideoComponent::handleLooping() @@ -245,119 +253,105 @@ void VideoComponent::handleLooping() void VideoComponent::startVideoWithDelay() { - // If not playing then either start the video or initiate the delay - if (!mIsPlaying) - { - // Set the video that we are going to be playing so we don't attempt to restart it - mPlayingVideoPath = mVideoPath; + // If not playing then either start the video or initiate the delay. + if (!mIsPlaying) { + // Set the video that we are going to be playing so we don't attempt to restart it. + mPlayingVideoPath = mVideoPath; - if (mConfig.startDelay == 0 || PowerSaver::getMode() == PowerSaver::INSTANT) - { - // No delay. Just start the video - mStartDelayed = false; - startVideo(); - } - else - { - // Configure the start delay - mStartDelayed = true; - mFadeIn = 0.0f; - mStartTime = SDL_GetTicks() + mConfig.startDelay; - } - mIsPlaying = true; - } + if (mConfig.startDelay == 0 || PowerSaver::getMode() == PowerSaver::INSTANT) { + // No delay. Just start the video. + mStartDelayed = false; + startVideo(); + } + else { + // Configure the start delay. + mStartDelayed = true; + mFadeIn = 0.0f; + mStartTime = SDL_GetTicks() + mConfig.startDelay; + } + mIsPlaying = true; + } } void VideoComponent::update(int deltaTime) { - manageState(); + manageState(); - // If the video start is delayed and there is less than the fade time then set the image fade - // accordingly - if (mStartDelayed) - { - Uint32 ticks = SDL_GetTicks(); - if (mStartTime > ticks) - { - Uint32 diff = mStartTime - ticks; - if (diff < FADE_TIME_MS) - { - mFadeIn = (float)diff / (float)FADE_TIME_MS; - return; - } - } - } - // If the fade in is less than 1 then increment it - if (mFadeIn < 1.0f) - { - mFadeIn += deltaTime / (float)FADE_TIME_MS; - if (mFadeIn > 1.0f) - mFadeIn = 1.0f; - } - GuiComponent::update(deltaTime); + // If the video start is delayed and there is less than the fade time, then set + // the image fade accordingly. + if (mStartDelayed) { + Uint32 ticks = SDL_GetTicks(); + if (mStartTime > ticks) { + Uint32 diff = mStartTime - ticks; + if (diff < FADE_TIME_MS) { + mFadeIn = (float)diff / (float)FADE_TIME_MS; + return; + } + } + } + // If the fade in is less than 1 then increment it. + if (mFadeIn < 1.0f) { + mFadeIn += deltaTime / (float)FADE_TIME_MS; + if (mFadeIn > 1.0f) + mFadeIn = 1.0f; + } + GuiComponent::update(deltaTime); } void VideoComponent::manageState() { - // We will only show if the component is on display and the screensaver - // is not active - bool show = mShowing && !mScreensaverActive && !mDisable; + // We will only show if the component is on display and the screensaver + // is not active. + bool show = mShowing && !mScreensaverActive && !mDisable; - // See if we're already playing - if (mIsPlaying) - { - // If we are not on display then stop the video from playing - if (!show) - { - stopVideo(); - } - else - { - if (mVideoPath != mPlayingVideoPath) - { - // Path changed. Stop the video. We will start it again below because - // mIsPlaying will be modified by stopVideo to be false - stopVideo(); - } - } - } - // Need to recheck variable rather than 'else' because it may be modified above - if (!mIsPlaying) - { - // If we are on display then see if we should start the video - if (show && !mVideoPath.empty()) - { - startVideoWithDelay(); - } - } + // See if we're already playing. + if (mIsPlaying) { + // If we are not on display then stop the video from playing. + if (!show) { + stopVideo(); + } + else { + if (mVideoPath != mPlayingVideoPath) { + // Path changed. Stop the video. We will start it again below because + // mIsPlaying will be modified by stopVideo to be false. + stopVideo(); + } + } + } + // Need to recheck variable rather than 'else' because it may be modified above. + if (!mIsPlaying) { + // If we are on display then see if we should start the video. + if (show && !mVideoPath.empty()) + startVideoWithDelay(); + } } void VideoComponent::onShow() { - mShowing = true; - manageState(); + mShowing = true; + manageState(); } void VideoComponent::onHide() { - mShowing = false; - manageState(); + mShowing = false; + manageState(); } void VideoComponent::onScreenSaverActivate() { - mScreensaverActive = true; - manageState(); + mScreensaverActive = true; + manageState(); } void VideoComponent::onScreenSaverDeactivate() { - mScreensaverActive = false; - manageState(); + mScreensaverActive = false; + manageState(); } void VideoComponent::topWindow(bool isTop) { - mDisable = !isTop; - manageState(); + mDisable = !isTop; + manageState(); } diff --git a/es-core/src/components/VideoComponent.h b/es-core/src/components/VideoComponent.h index 1c574a1fa..ac0a97cbb 100644 --- a/es-core/src/components/VideoComponent.h +++ b/es-core/src/components/VideoComponent.h @@ -1,9 +1,16 @@ +// +// VideoComponent.h +// +// Base class for playing videos. +// + #pragma once #ifndef ES_CORE_COMPONENTS_VIDEO_COMPONENT_H #define ES_CORE_COMPONENTS_VIDEO_COMPONENT_H #include "components/ImageComponent.h" #include "GuiComponent.h" + #include class TextureResource; @@ -14,101 +21,101 @@ void writeSubtitle(const char* gameName, const char* systemName, bool always); class VideoComponent : public GuiComponent { - // Structure that groups together the configuration of the video component - struct Configuration - { - unsigned startDelay; - bool showSnapshotNoVideo; - bool showSnapshotDelay; - std::string defaultVideoPath; - }; + // Structure that groups together the configuration of the video component. + struct Configuration { + unsigned startDelay; + bool showSnapshotNoVideo; + bool showSnapshotDelay; + std::string defaultVideoPath; + }; public: - VideoComponent(Window* window); - virtual ~VideoComponent(); + VideoComponent(Window* window); + virtual ~VideoComponent(); - // Loads the video at the given filepath - bool setVideo(std::string path); - // Loads a static image that is displayed if the video cannot be played - void setImage(std::string path); + // Loads the video at the given filepath. + bool setVideo(std::string path); + // Loads a static image that is displayed if the video cannot be played. + void setImage(std::string path); - // Configures the component to show the default video - void setDefaultVideo(); + // Configures the component to show the default video. + void setDefaultVideo(); - // sets whether it's going to render in screensaver mode - void setScreensaverMode(bool isScreensaver); + // Sets whether it's going to render in screensaver mode. + void setScreensaverMode(bool isScreensaver); - virtual void onShow() override; - virtual void onHide() override; - virtual void onScreenSaverActivate() override; - virtual void onScreenSaverDeactivate() override; - virtual void topWindow(bool isTop) override; + virtual void onShow() override; + virtual void onHide() override; + virtual void onScreenSaverActivate() override; + virtual void onScreenSaverDeactivate() override; + virtual void topWindow(bool isTop) override; - void onOriginChanged() override; - void onPositionChanged() override; - void onSizeChanged() override; - void setOpacity(unsigned char opacity) override; + void onOriginChanged() override; + void onPositionChanged() override; + void onSizeChanged() override; + void setOpacity(unsigned char opacity) override; - void render(const Transform4x4f& parentTrans) override; - void renderSnapshot(const Transform4x4f& parentTrans); + void render(const Transform4x4f& parentTrans) override; + void renderSnapshot(const Transform4x4f& parentTrans); - virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) override; + virtual void applyTheme(const std::shared_ptr& theme, const std::string& view, + const std::string& element, unsigned int properties) override; - virtual std::vector getHelpPrompts() override; + virtual std::vector getHelpPrompts() override; - virtual void update(int deltaTime) override; + virtual void update(int deltaTime) override; - // Resize the video to fit this size. If one axis is zero, scale that axis to maintain aspect ratio. - // If both are non-zero, potentially break the aspect ratio. If both are zero, no resizing. - // Can be set before or after a video is loaded. - // setMaxSize() and setResize() are mutually exclusive. - virtual void setResize(float width, float height) = 0; - inline void setResize(const Vector2f& size) { setResize(size.x(), size.y()); } + // Resize the video to fit this size. If one axis is zero, scale that axis to maintain + // aspect ratio. If both are non-zero, potentially break the aspect ratio. If both are + // zero, no resizing. This can be set before or after a video is loaded. + // setMaxSize() and setResize() are mutually exclusive. + virtual void setResize(float width, float height) = 0; + inline void setResize(const Vector2f& size) { setResize(size.x(), size.y()); } - // Resize the video to be as large as possible but fit within a box of this size. - // Can be set before or after a video is loaded. - // Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive. - virtual void setMaxSize(float width, float height) = 0; - inline void setMaxSize(const Vector2f& size) { setMaxSize(size.x(), size.y()); } + // Resize the video to be as large as possible but fit within a box of this size. + // This can be set before or after a video is loaded. + // Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive. + virtual void setMaxSize(float width, float height) = 0; + inline void setMaxSize(const Vector2f& size) { setMaxSize(size.x(), size.y()); } private: - // Start the video Immediately - virtual void startVideo() = 0; - // Stop the video - virtual void stopVideo() { }; - // Handle looping the video. Must be called periodically - virtual void handleLooping(); + // Start the video immediately. + virtual void startVideo() = 0; + // Stop the video. + virtual void stopVideo() { }; + // Handle looping the video. Must be called periodically. + virtual void handleLooping(); - // Start the video after any configured delay - void startVideoWithDelay(); + // Start the video after any configured delay. + void startVideoWithDelay(); - // Handle any delay to the start of playing the video clip. Must be called periodically - void handleStartDelay(); + // Handle any delay to the start of playing the video clip. Must be called periodically. + void handleStartDelay(); - // Manage the playing state of the component - void manageState(); + // Manage the playing state of the component. + void manageState(); protected: - unsigned mVideoWidth; - unsigned mVideoHeight; - Vector2f mTargetSize; - std::shared_ptr mTexture; - float mFadeIn; - std::string mStaticImagePath; - ImageComponent mStaticImage; + unsigned mVideoWidth; + unsigned mVideoHeight; + Vector2f mTargetSize; + std::shared_ptr mTexture; + float mFadeIn; + std::string mStaticImagePath; + ImageComponent mStaticImage; - std::string mVideoPath; - std::string mPlayingVideoPath; - bool mStartDelayed; - unsigned mStartTime; - bool mIsPlaying; - bool mShowing; - bool mDisable; - bool mScreensaverActive; - bool mScreensaverMode; - bool mTargetIsMax; + std::string mVideoPath; + std::string mPlayingVideoPath; + bool mStartDelayed; + unsigned mStartTime; + bool mIsPlaying; + bool mShowing; + bool mDisable; + bool mScreensaverActive; + bool mScreensaverMode; + bool mTargetIsMax; - Configuration mConfig; + Configuration mConfig; }; #endif // ES_CORE_COMPONENTS_VIDEO_COMPONENT_H diff --git a/es-core/src/components/VideoPlayerComponent.cpp b/es-core/src/components/VideoPlayerComponent.cpp index f6beeaa5b..b0c0cbcf7 100644 --- a/es-core/src/components/VideoPlayerComponent.cpp +++ b/es-core/src/components/VideoPlayerComponent.cpp @@ -1,3 +1,9 @@ +// +// VideoPlayerComponent.cpp +// +// OMXPlayer video playing for Raspberry Pi. +// + #ifdef _RPI_ #include "components/VideoPlayerComponent.h" @@ -5,6 +11,7 @@ #include "utils/StringUtil.h" #include "AudioManager.h" #include "Settings.h" + #include #include #include @@ -12,250 +19,235 @@ class VolumeControl { public: - static std::shared_ptr & getInstance(); - int getVolume() const; + static std::shared_ptr & getInstance(); + int getVolume() const; }; VideoPlayerComponent::VideoPlayerComponent(Window* window, std::string path) : - VideoComponent(window), - mPlayerPid(-1), - subtitlePath(path) + VideoComponent(window), + mPlayerPid(-1), + subtitlePath(path) { } VideoPlayerComponent::~VideoPlayerComponent() { - stopVideo(); + stopVideo(); } void VideoPlayerComponent::render(const Transform4x4f& parentTrans) { - if (!isVisible()) - return; + if (!isVisible()) + return; - VideoComponent::render(parentTrans); + VideoComponent::render(parentTrans); - if (!mIsPlaying || mPlayerPid == -1) - VideoComponent::renderSnapshot(parentTrans); + if (!mIsPlaying || mPlayerPid == -1) + VideoComponent::renderSnapshot(parentTrans); } void VideoPlayerComponent::setResize(float width, float height) { - setSize(width, height); - mTargetSize = Vector2f(width, height); - mTargetIsMax = false; - mStaticImage.setResize(width, height); - onSizeChanged(); + setSize(width, height); + mTargetSize = Vector2f(width, height); + mTargetIsMax = false; + mStaticImage.setResize(width, height); + onSizeChanged(); } void VideoPlayerComponent::setMaxSize(float width, float height) { - setSize(width, height); - mTargetSize = Vector2f(width, height); - mTargetIsMax = true; - mStaticImage.setMaxSize(width, height); - onSizeChanged(); + setSize(width, height); + mTargetSize = Vector2f(width, height); + mTargetIsMax = true; + mStaticImage.setMaxSize(width, height); + onSizeChanged(); } void VideoPlayerComponent::startVideo() { - if (!mIsPlaying) - { - mVideoWidth = 0; - mVideoHeight = 0; + if (!mIsPlaying) { + mVideoWidth = 0; + mVideoHeight = 0; - std::string path(mVideoPath.c_str()); + std::string path(mVideoPath.c_str()); - // Make sure we have a video path - if ((path.size() > 0) && (mPlayerPid == -1)) - { - // Set the video that we are going to be playing so we don't attempt to restart it - mPlayingVideoPath = mVideoPath; + // Make sure we have a video path. + if ((path.size() > 0) && (mPlayerPid == -1)) { + // Set the video that we are going to be playing so we don't attempt to restart it. + mPlayingVideoPath = mVideoPath; - // Disable AudioManager so video can play, in case we're requesting ALSA - if (Utils::String::startsWith(Settings::getInstance()->getString("OMXAudioDev").c_str(), "alsa")) - { - AudioManager::getInstance()->deinit(); - } + // Disable AudioManager so video can play, in case we're requesting ALSA. + if (Utils::String::startsWith(Settings::getInstance()-> + getString("OMXAudioDev").c_str(), "alsa")) + AudioManager::getInstance()->deinit(); - // Start the player process - pid_t pid = fork(); - if (pid == -1) - { - // Failed - mPlayingVideoPath = ""; - } - else if (pid > 0) - { - mPlayerPid = pid; - // Update the playing state - signal(SIGCHLD, catch_child); - mIsPlaying = true; - mFadeIn = 0.0f; - } - else - { + // Start the player process. + pid_t pid = fork(); + if (pid == -1) { + // Failed. + mPlayingVideoPath = ""; + } + else if (pid > 0) { + mPlayerPid = pid; + // Update the playing state. + signal(SIGCHLD, catch_child); + mIsPlaying = true; + mFadeIn = 0.0f; + } + else { + // Find out the pixel position of the video view and build a command line for + // OMXPlayer to position it in the right place. + char buf1[32]; + char buf2[32]; + float x = mPosition.x() - (mOrigin.x() * mSize.x()); + float y = mPosition.y() - (mOrigin.y() * mSize.y()); - // Find out the pixel position of the video view and build a command line for - // omxplayer to position it in the right place - char buf1[32]; - char buf2[32]; - float x = mPosition.x() - (mOrigin.x() * mSize.x()); - float y = mPosition.y() - (mOrigin.y() * mSize.y()); + // Fix x and y. + switch (Renderer::getScreenRotate()) { + case 0: { + const int x1 = (int)(Renderer::getScreenOffsetX() + x); + const int y1 = (int)(Renderer::getScreenOffsetY() + y); + const int x2 = (int)(x1 + mSize.x()); + const int y2 = (int)(y1 + mSize.y()); + sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2); + } + break; - // fix x and y - switch(Renderer::getScreenRotate()) - { - case 0: - { - const int x1 = (int)(Renderer::getScreenOffsetX() + x); - const int y1 = (int)(Renderer::getScreenOffsetY() + y); - const int x2 = (int)(x1 + mSize.x()); - const int y2 = (int)(y1 + mSize.y()); - sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2); - } - break; + case 1: { + const int x1 = (int)(Renderer::getWindowWidth() - + Renderer::getScreenOffsetY() - y - mSize.y()); + const int y1 = (int)(Renderer::getScreenOffsetX() + x); + const int x2 = (int)(x1 + mSize.y()); + const int y2 = (int)(y1 + mSize.x()); + sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2); + } + break; - case 1: - { - const int x1 = (int)(Renderer::getWindowWidth() - Renderer::getScreenOffsetY() - y - mSize.y()); - const int y1 = (int)(Renderer::getScreenOffsetX() + x); - const int x2 = (int)(x1 + mSize.y()); - const int y2 = (int)(y1 + mSize.x()); - sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2); - } - break; + case 2: { + const int x1 = (int)(Renderer::getWindowWidth() - + Renderer::getScreenOffsetX() - x - mSize.x()); + const int y1 = (int)(Renderer::getWindowHeight() - + Renderer::getScreenOffsetY() - y - mSize.y()); + const int x2 = (int)(x1 + mSize.x()); + const int y2 = (int)(y1 + mSize.y()); + sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2); + } + break; - case 2: - { - const int x1 = (int)(Renderer::getWindowWidth() - Renderer::getScreenOffsetX() - x - mSize.x()); - const int y1 = (int)(Renderer::getWindowHeight() - Renderer::getScreenOffsetY() - y - mSize.y()); - const int x2 = (int)(x1 + mSize.x()); - const int y2 = (int)(y1 + mSize.y()); - sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2); - } - break; + case 3: { + const int x1 = (int)(Renderer::getScreenOffsetY() + y); + const int y1 = (int)(Renderer::getWindowHeight() - + Renderer::getScreenOffsetX() - x - mSize.x()); + const int x2 = (int)(x1 + mSize.y()); + const int y2 = (int)(y1 + mSize.x()); + sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2); + } + break; + } - case 3: - { - const int x1 = (int)(Renderer::getScreenOffsetY() + y); - const int y1 = (int)(Renderer::getWindowHeight() - Renderer::getScreenOffsetX() - x - mSize.x()); - const int x2 = (int)(x1 + mSize.y()); - const int y2 = (int)(y1 + mSize.x()); - sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2); - } - break; - } + // Rotate the video. + switch (Renderer::getScreenRotate()) { + case 0: { sprintf(buf2, "%d", (int) 0); } break; + case 1: { sprintf(buf2, "%d", (int) 90); } break; + case 2: { sprintf(buf2, "%d", (int)180); } break; + case 3: { sprintf(buf2, "%d", (int)270); } break; + } - // rotate the video - switch(Renderer::getScreenRotate()) - { - case 0: { sprintf(buf2, "%d", (int) 0); } break; - case 1: { sprintf(buf2, "%d", (int) 90); } break; - case 2: { sprintf(buf2, "%d", (int)180); } break; - case 3: { sprintf(buf2, "%d", (int)270); } break; - } + // We need to specify the layer of 10000 or above to ensure the video is + // displayed on top of our SDL display. + const char* argv[] = { "", "--layer", "10010", "--loop", "--no-osd", + "--aspect-mode", "letterbox", "--vol", "0", "-o", "both", + "--win", buf1, "--orientation", buf2, "", "", "", "", "", "", + "", "", "", "", "", NULL }; - // We need to specify the layer of 10000 or above to ensure the video is displayed on top - // of our SDL display + // Check if we want to mute the audio. + if ((!Settings::getInstance()->getBool("VideoAudio") || + (float)VolumeControl::getInstance()->getVolume() == 0) || + (Settings::getInstance()->getBool("ScreenSaverVideoMute") && + mScreensaverMode)) { + argv[8] = "-1000000"; + } + else { + float percentVolume = (float)VolumeControl::getInstance()->getVolume(); + int OMXVolume = (int)((percentVolume-98)*105); + argv[8] = std::to_string(OMXVolume).c_str(); + } - const char* argv[] = { "", "--layer", "10010", "--loop", "--no-osd", "--aspect-mode", "letterbox", "--vol", "0", "-o", "both","--win", buf1, "--orientation", buf2, "", "", "", "", "", "", "", "", "", "", "", NULL }; + // Test if there's a path for possible subtitles, meaning we're a screensaver video. + if (!subtitlePath.empty()) { + // If we are rendering a screensaver. + // Check if we want to stretch the image. + if (Settings::getInstance()->getBool("StretchVideoOnScreenSaver")) + argv[6] = "stretch"; - // check if we want to mute the audio - if ((!Settings::getInstance()->getBool("VideoAudio") || (float)VolumeControl::getInstance()->getVolume() == 0) || - (Settings::getInstance()->getBool("ScreenSaverVideoMute") && mScreensaverMode)) - { - argv[8] = "-1000000"; - } - else - { - float percentVolume = (float)VolumeControl::getInstance()->getVolume(); - int OMXVolume = (int)((percentVolume-98)*105); - argv[8] = std::to_string(OMXVolume).c_str(); - } + if (Settings::getInstance()->getString("ScreenSaverGameInfo") != "never") { + // If we have chosen to render subtitles. + argv[15] = "--subtitles"; + argv[16] = subtitlePath.c_str(); + argv[17] = mPlayingVideoPath.c_str(); + argv[18] = "--font"; + argv[19] = Settings::getInstance()->getString("SubtitleFont").c_str(); + argv[20] = "--italic-font"; + argv[21] = Settings::getInstance()-> + getString("SubtitleItalicFont").c_str(); + argv[22] = "--font-size"; + argv[23] = std::to_string(Settings::getInstance()-> + getInt("SubtitleSize")).c_str(); + argv[24] = "--align"; + argv[25] = Settings::getInstance()-> + getString("SubtitleAlignment").c_str(); + } + else { + // If we have chosen NOT to render subtitles in the screensaver. + argv[15] = mPlayingVideoPath.c_str(); + } + } + else { + // If we are rendering a video gamelist. + if (!mTargetIsMax) + argv[6] = "stretch"; + argv[15] = mPlayingVideoPath.c_str(); + } - // test if there's a path for possible subtitles, meaning we're a screensaver video - if (!subtitlePath.empty()) - { - // if we are rendering a screensaver + argv[10] = Settings::getInstance()->getString("OMXAudioDev").c_str(); - // check if we want to stretch the image - if (Settings::getInstance()->getBool("StretchVideoOnScreenSaver")) - { - argv[6] = "stretch"; - } + //const char* argv[] = args; + const char* env[] = { "LD_LIBRARY_PATH=/opt/vc/libs:/usr/lib/omxplayer", NULL }; - if (Settings::getInstance()->getString("ScreenSaverGameInfo") != "never") - { - // if we have chosen to render subtitles - argv[15] = "--subtitles"; - argv[16] = subtitlePath.c_str(); - argv[17] = mPlayingVideoPath.c_str(); - argv[18] = "--font"; - argv[19] = Settings::getInstance()->getString("SubtitleFont").c_str(); - argv[20] = "--italic-font"; - argv[21] = Settings::getInstance()->getString("SubtitleItalicFont").c_str(); - argv[22] = "--font-size"; - argv[23] = std::to_string(Settings::getInstance()->getInt("SubtitleSize")).c_str(); - argv[24] = "--align"; - argv[25] = Settings::getInstance()->getString("SubtitleAlignment").c_str(); - } - else - { - // if we have chosen NOT to render subtitles in the screensaver - argv[15] = mPlayingVideoPath.c_str(); - } - } - else - { - // if we are rendering a video gamelist - if (!mTargetIsMax) - { - argv[6] = "stretch"; - } - argv[15] = mPlayingVideoPath.c_str(); - } + // Redirect stdout. + int fdin = open("/dev/null", O_RDONLY); + int fdout = open("/dev/null", O_WRONLY); + dup2(fdin, 0); + dup2(fdout, 1); + // Run the OMXPlayer binary. + execve("/usr/bin/omxplayer.bin", (char**)argv, (char**)env); - argv[10] = Settings::getInstance()->getString("OMXAudioDev").c_str(); - - //const char* argv[] = args; - const char* env[] = { "LD_LIBRARY_PATH=/opt/vc/libs:/usr/lib/omxplayer", NULL }; - - // Redirect stdout - int fdin = open("/dev/null", O_RDONLY); - int fdout = open("/dev/null", O_WRONLY); - dup2(fdin, 0); - dup2(fdout, 1); - // Run the omxplayer binary - execve("/usr/bin/omxplayer.bin", (char**)argv, (char**)env); - - _exit(EXIT_FAILURE); - } - } - } + _exit(EXIT_FAILURE); + } + } + } } void catch_child(int sig_num) { - /* when we get here, we know there's a zombie child waiting */ + // When we get here, we know there's a zombie child waiting. int child_status; wait(&child_status); } void VideoPlayerComponent::stopVideo() { - mIsPlaying = false; - mStartDelayed = false; + mIsPlaying = false; + mStartDelayed = false; - // Stop the player process - if (mPlayerPid != -1) - { - int status; - kill(mPlayerPid, SIGKILL); - waitpid(mPlayerPid, &status, WNOHANG); - mPlayerPid = -1; - } + // Stop the player process. + if (mPlayerPid != -1) { + int status; + kill(mPlayerPid, SIGKILL); + waitpid(mPlayerPid, &status, WNOHANG); + mPlayerPid = -1; + } } #endif - diff --git a/es-core/src/components/VideoPlayerComponent.h b/es-core/src/components/VideoPlayerComponent.h index a68c337a3..871570cd7 100644 --- a/es-core/src/components/VideoPlayerComponent.h +++ b/es-core/src/components/VideoPlayerComponent.h @@ -1,3 +1,9 @@ +// +// VideoPlayerComponent.h +// +// OMXPlayer video playing for Raspberry Pi. +// + #ifdef _RPI_ #pragma once #ifndef ES_CORE_COMPONENTS_VIDEO_PLAYER_COMPONENT_H @@ -10,31 +16,31 @@ void catch_child(int sig_num); class VideoPlayerComponent : public VideoComponent { public: - VideoPlayerComponent(Window* window, std::string path); - virtual ~VideoPlayerComponent(); + VideoPlayerComponent(Window* window, std::string path); + virtual ~VideoPlayerComponent(); - void render(const Transform4x4f& parentTrans) override; + void render(const Transform4x4f& parentTrans) override; - // Resize the video to fit this size. If one axis is zero, scale that axis to maintain aspect ratio. - // If both are non-zero, potentially break the aspect ratio. If both are zero, no resizing. - // Can be set before or after a video is loaded. - // setMaxSize() and setResize() are mutually exclusive. - void setResize(float width, float height); + // Resize the video to fit this size. If one axis is zero, scale that axis to maintain + // aspect ratio. If both are non-zero, potentially break the aspect ratio. If both are + // zero, no resizing. This can be set before or after a video is loaded. + // setMaxSize() and setResize() are mutually exclusive. + void setResize(float width, float height) override; - // Resize the video to be as large as possible but fit within a box of this size. - // Can be set before or after a video is loaded. - // Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive. - void setMaxSize(float width, float height); + // Resize the video to be as large as possible but fit within a box of this size. + // This can be set before or after a video is loaded. + // Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive. + void setMaxSize(float width, float height) override; private: - // Start the video Immediately - virtual void startVideo(); - // Stop the video - virtual void stopVideo(); + // Start the video Immediately. + virtual void startVideo() override; + // Stop the video. + virtual void stopVideo() override; private: - pid_t mPlayerPid; - std::string subtitlePath; + pid_t mPlayerPid; + std::string subtitlePath; }; #endif // ES_CORE_COMPONENTS_VIDEO_PLAYER_COMPONENT_H diff --git a/es-core/src/components/VideoVlcComponent.cpp b/es-core/src/components/VideoVlcComponent.cpp index 93bafdb10..7efca8a8b 100644 --- a/es-core/src/components/VideoVlcComponent.cpp +++ b/es-core/src/components/VideoVlcComponent.cpp @@ -1,3 +1,9 @@ +// +// VideoVlcComponent.cpp +// +// Video playing using libVLC. +// + #include "components/VideoVlcComponent.h" #include "renderers/Renderer.h" @@ -20,337 +26,322 @@ #include #endif -libvlc_instance_t* VideoVlcComponent::mVLC = NULL; +libvlc_instance_t* VideoVlcComponent::mVLC = nullptr; // VLC prepares to render a video frame. -static void *lock(void *data, void **p_pixels) { - struct VideoContext *c = (struct VideoContext *)data; - SDL_LockMutex(c->mutex); - SDL_LockSurface(c->surface); - *p_pixels = c->surface->pixels; - return NULL; // Picture identifier, not needed here. +static void* lock(void* data, void** p_pixels) { + struct VideoContext* c = (struct VideoContext*)data; + SDL_LockMutex(c->mutex); + SDL_LockSurface(c->surface); + *p_pixels = c->surface->pixels; + return nullptr; // Picture identifier, not needed here. } // VLC just rendered a video frame. -static void unlock(void *data, void* /*id*/, void *const* /*p_pixels*/) { - struct VideoContext *c = (struct VideoContext *)data; - SDL_UnlockSurface(c->surface); - SDL_UnlockMutex(c->mutex); +static void unlock(void* data, void* /*id*/, void *const* /*p_pixels*/) { + struct VideoContext* c = (struct VideoContext*)data; + SDL_UnlockSurface(c->surface); + SDL_UnlockMutex(c->mutex); } // VLC wants to display a video frame. static void display(void* /*data*/, void* /*id*/) { - //Data to be displayed + // Data to be displayed. } -VideoVlcComponent::VideoVlcComponent(Window* window, std::string subtitles) : - VideoComponent(window), - mMediaPlayer(nullptr) +VideoVlcComponent::VideoVlcComponent(Window* window, std::string subtitles) + : VideoComponent(window), mMediaPlayer(nullptr) { - memset(&mContext, 0, sizeof(mContext)); + memset(&mContext, 0, sizeof(mContext)); - // Get an empty texture for rendering the video - mTexture = TextureResource::get(""); + // Get an empty texture for rendering the video. + mTexture = TextureResource::get(""); - // Make sure VLC has been initialised - setupVLC(subtitles); + // Make sure VLC has been initialized. + setupVLC(subtitles); } VideoVlcComponent::~VideoVlcComponent() { - stopVideo(); + stopVideo(); } void VideoVlcComponent::setResize(float width, float height) { - mTargetSize = Vector2f(width, height); - mTargetIsMax = false; - mStaticImage.setResize(width, height); - resize(); + mTargetSize = Vector2f(width, height); + mTargetIsMax = false; + mStaticImage.setResize(width, height); + resize(); } void VideoVlcComponent::setMaxSize(float width, float height) { - mTargetSize = Vector2f(width, height); - mTargetIsMax = true; - mStaticImage.setMaxSize(width, height); - resize(); + mTargetSize = Vector2f(width, height); + mTargetIsMax = true; + mStaticImage.setMaxSize(width, height); + resize(); } void VideoVlcComponent::resize() { - if(!mTexture) - return; + if (!mTexture) + return; - const Vector2f textureSize((float)mVideoWidth, (float)mVideoHeight); + const Vector2f textureSize((float)mVideoWidth, (float)mVideoHeight); - if(textureSize == Vector2f::Zero()) - return; + if (textureSize == Vector2f::Zero()) + return; - // SVG rasterization is determined by height (see SVGResource.cpp), and rasterization is done in terms of pixels - // if rounding is off enough in the rasterization step (for images with extreme aspect ratios), it can cause cutoff when the aspect ratio breaks - // so, we always make sure the resultant height is an integer to make sure cutoff doesn't happen, and scale width from that - // (you'll see this scattered throughout the function) - // this is probably not the best way, so if you're familiar with this problem and have a better solution, please make a pull request! + // SVG rasterization is determined by height and rasterization is done in terms of pixels. + // If rounding is off enough in the rasterization step (for images with extreme aspect + // ratios), it can cause cutoff when the aspect ratio breaks. + // So we always make sure the resultant height is an integer to make sure cutoff doesn't + // happen, and scale width from that (you'll see this scattered throughout the function). + // This is probably not the best way, so if you're familiar with this problem and have a + // better solution, please make a pull request! + if (mTargetIsMax) { + mSize = textureSize; - if(mTargetIsMax) - { + Vector2f resizeScale((mTargetSize.x() / mSize.x()), (mTargetSize.y() / mSize.y())); - mSize = textureSize; + if (resizeScale.x() < resizeScale.y()) { + mSize[0] *= resizeScale.x(); + mSize[1] *= resizeScale.x(); + } + else { + mSize[0] *= resizeScale.y(); + mSize[1] *= resizeScale.y(); + } - Vector2f resizeScale((mTargetSize.x() / mSize.x()), (mTargetSize.y() / mSize.y())); + // For SVG rasterization, always calculate width from rounded height (see comment above). + mSize[1] = Math::round(mSize[1]); + mSize[0] = (mSize[1] / textureSize.y()) * textureSize.x(); - if(resizeScale.x() < resizeScale.y()) - { - mSize[0] *= resizeScale.x(); - mSize[1] *= resizeScale.x(); - }else{ - mSize[0] *= resizeScale.y(); - mSize[1] *= resizeScale.y(); - } + } + else { + // If both components are set, we just stretch. + // If no components are set, we don't resize at all. + mSize = mTargetSize == Vector2f::Zero() ? textureSize : mTargetSize; - // for SVG rasterization, always calculate width from rounded height (see comment above) - mSize[1] = Math::round(mSize[1]); - mSize[0] = (mSize[1] / textureSize.y()) * textureSize.x(); + // If only one component is set, we resize in a way that maintains aspect ratio. + // For SVG rasterization, we always calculate width from rounded height (see comment above). + if (!mTargetSize.x() && mTargetSize.y()) { + mSize[1] = Math::round(mTargetSize.y()); + mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); + } + else if (mTargetSize.x() && !mTargetSize.y()) { + mSize[1] = Math::round((mTargetSize.x() / textureSize.x()) * textureSize.y()); + mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); + } + } - }else{ - // if both components are set, we just stretch - // if no components are set, we don't resize at all - mSize = mTargetSize == Vector2f::Zero() ? textureSize : mTargetSize; + // mSize.y() should already be rounded. + mTexture->rasterizeAt((size_t)Math::round(mSize.x()), (size_t)Math::round(mSize.y())); - // if only one component is set, we resize in a way that maintains aspect ratio - // for SVG rasterization, we always calculate width from rounded height (see comment above) - if(!mTargetSize.x() && mTargetSize.y()) - { - mSize[1] = Math::round(mTargetSize.y()); - mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); - }else if(mTargetSize.x() && !mTargetSize.y()) - { - mSize[1] = Math::round((mTargetSize.x() / textureSize.x()) * textureSize.y()); - mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); - } - } - - // mSize.y() should already be rounded - mTexture->rasterizeAt((size_t)Math::round(mSize.x()), (size_t)Math::round(mSize.y())); - - onSizeChanged(); + onSizeChanged(); } void VideoVlcComponent::render(const Transform4x4f& parentTrans) { - if (!isVisible()) - return; + if (!isVisible()) + return; - VideoComponent::render(parentTrans); - Transform4x4f trans = parentTrans * getTransform(); - GuiComponent::renderChildren(trans); - Renderer::setMatrix(trans); + VideoComponent::render(parentTrans); + Transform4x4f trans = parentTrans * getTransform(); + GuiComponent::renderChildren(trans); + Renderer::setMatrix(trans); - if (mIsPlaying && mContext.valid) - { - const unsigned int fadeIn = (unsigned int)(Math::clamp(0.0f, mFadeIn, 1.0f) * 255.0f); - const unsigned int color = Renderer::convertColor((fadeIn << 24) | (fadeIn << 16) | (fadeIn << 8) | 255); - Renderer::Vertex vertices[4]; + if (mIsPlaying && mContext.valid) { + const unsigned int fadeIn = (unsigned int)(Math::clamp(0.0f, mFadeIn, 1.0f) * 255.0f); + const unsigned int color = + Renderer::convertColor((fadeIn << 24) | (fadeIn << 16) | (fadeIn << 8) | 255); + Renderer::Vertex vertices[4]; - vertices[0] = { { 0.0f , 0.0f }, { 0.0f, 0.0f }, color }; - vertices[1] = { { 0.0f , mSize.y() }, { 0.0f, 1.0f }, color }; - vertices[2] = { { mSize.x(), 0.0f }, { 1.0f, 0.0f }, color }; - vertices[3] = { { mSize.x(), mSize.y() }, { 1.0f, 1.0f }, color }; + vertices[0] = { { 0.0f , 0.0f }, { 0.0f, 0.0f }, color }; + vertices[1] = { { 0.0f , mSize.y() }, { 0.0f, 1.0f }, color }; + vertices[2] = { { mSize.x(), 0.0f }, { 1.0f, 0.0f }, color }; + vertices[3] = { { mSize.x(), mSize.y() }, { 1.0f, 1.0f }, color }; - // round vertices - for(int i = 0; i < 4; ++i) - vertices[i].pos.round(); + // Round vertices. + for (int i = 0; i < 4; ++i) + vertices[i].pos.round(); - // Build a texture for the video frame - mTexture->initFromPixels((unsigned char*)mContext.surface->pixels, mContext.surface->w, mContext.surface->h); - mTexture->bind(); + // Build a texture for the video frame. + mTexture->initFromPixels((unsigned char*)mContext.surface->pixels, + mContext.surface->w, mContext.surface->h); + mTexture->bind(); - // Render it - Renderer::drawTriangleStrips(&vertices[0], 4); - } - else - { - VideoComponent::renderSnapshot(parentTrans); - } + // Render it. + Renderer::drawTriangleStrips(&vertices[0], 4); + } + else { + VideoComponent::renderSnapshot(parentTrans); + } } void VideoVlcComponent::setupContext() { - if (!mContext.valid) - { - // Create an RGBA surface to render the video into - mContext.surface = SDL_CreateRGBSurface(SDL_SWSURFACE, (int)mVideoWidth, (int)mVideoHeight, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); - mContext.mutex = SDL_CreateMutex(); - mContext.valid = true; - resize(); - } + if (!mContext.valid) { + // Create an RGBA surface to render the video into. + mContext.surface = SDL_CreateRGBSurface(SDL_SWSURFACE, (int)mVideoWidth, + (int)mVideoHeight, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); + mContext.mutex = SDL_CreateMutex(); + mContext.valid = true; + resize(); + } } void VideoVlcComponent::freeContext() { - if (mContext.valid) - { - SDL_FreeSurface(mContext.surface); - SDL_DestroyMutex(mContext.mutex); - mContext.valid = false; - } + if (mContext.valid) { + SDL_FreeSurface(mContext.surface); + SDL_DestroyMutex(mContext.mutex); + mContext.valid = false; + } } void VideoVlcComponent::setupVLC(std::string subtitles) { - // If VLC hasn't been initialised yet then do it now - if (!mVLC) - { - const char** args; - const char* newargs[] = { "--quiet", "--sub-file", subtitles.c_str() }; - const char* singleargs[] = { "--quiet" }; - int argslen = 0; + // If VLC hasn't been initialised yet then do it now. + if (!mVLC) { + const char** args; + const char* newargs[] = { "--quiet", "--sub-file", subtitles.c_str() }; + const char* singleargs[] = { "--quiet" }; + int argslen = 0; - if (!subtitles.empty()) - { - argslen = sizeof(newargs) / sizeof(newargs[0]); - args = newargs; - } - else - { - argslen = sizeof(singleargs) / sizeof(singleargs[0]); - args = singleargs; - } - mVLC = libvlc_new(argslen, args); - } + if (!subtitles.empty()) { + argslen = sizeof(newargs) / sizeof(newargs[0]); + args = newargs; + } + else { + argslen = sizeof(singleargs) / sizeof(singleargs[0]); + args = singleargs; + } + mVLC = libvlc_new(argslen, args); + } } void VideoVlcComponent::handleLooping() { - if (mIsPlaying && mMediaPlayer) - { - libvlc_state_t state = libvlc_media_player_get_state(mMediaPlayer); - if (state == libvlc_Ended) - { - if (!Settings::getInstance()->getBool("VideoAudio") || - (Settings::getInstance()->getBool("ScreenSaverVideoMute") && mScreensaverMode)) - { - libvlc_audio_set_mute(mMediaPlayer, 1); - } - //libvlc_media_player_set_position(mMediaPlayer, 0.0f); - libvlc_media_player_set_media(mMediaPlayer, mMedia); - libvlc_media_player_play(mMediaPlayer); - } - } + if (mIsPlaying && mMediaPlayer) { + libvlc_state_t state = libvlc_media_player_get_state(mMediaPlayer); + if (state == libvlc_Ended) { + if (!Settings::getInstance()->getBool("VideoAudio") || + (Settings::getInstance()->getBool("ScreenSaverVideoMute") && mScreensaverMode)) + libvlc_audio_set_mute(mMediaPlayer, 1); + + //libvlc_media_player_set_position(mMediaPlayer, 0.0f); + libvlc_media_player_set_media(mMediaPlayer, mMedia); + libvlc_media_player_play(mMediaPlayer); + } + } } void VideoVlcComponent::startVideo() { - if (!mIsPlaying) { - mVideoWidth = 0; - mVideoHeight = 0; + if (!mIsPlaying) { + mVideoWidth = 0; + mVideoHeight = 0; -#ifdef WIN32 - std::string path(Utils::String::replace(mVideoPath, "/", "\\")); -#else - std::string path(mVideoPath); -#endif - // Make sure we have a video path - if (mVLC && (path.size() > 0)) - { - // Set the video that we are going to be playing so we don't attempt to restart it - mPlayingVideoPath = mVideoPath; + #ifdef WIN32 + std::string path(Utils::String::replace(mVideoPath, "/", "\\")); + #else + std::string path(mVideoPath); + #endif + // Make sure we have a video path. + if (mVLC && (path.size() > 0)) { + // Set the video that we are going to be playing so we don't attempt to restart it. + mPlayingVideoPath = mVideoPath; - // Open the media - mMedia = libvlc_media_new_path(mVLC, path.c_str()); - if (mMedia) - { - unsigned track_count; - int parseResult; - libvlc_event_t vlcEvent; + // Open the media. + mMedia = libvlc_media_new_path(mVLC, path.c_str()); + if (mMedia) { + unsigned track_count; + int parseResult; + libvlc_event_t vlcEvent; - // Asynchronous media parsing - libvlc_event_attach(libvlc_media_event_manager(mMedia), libvlc_MediaParsedChanged, VlcMediaParseCallback, 0); - parseResult = libvlc_media_parse_with_options(mMedia, libvlc_media_parse_local, -1); + // Asynchronous media parsing. + libvlc_event_attach(libvlc_media_event_manager( + mMedia), libvlc_MediaParsedChanged, VlcMediaParseCallback, 0); + parseResult = libvlc_media_parse_with_options(mMedia, libvlc_media_parse_local, -1); - if (!parseResult) - { - // Wait for a maximum of 1 second for the media parsing - for(int i=0; i<200; i++) - { - if ((libvlc_media_get_parsed_status(mMedia))) - break; - SDL_Delay(5); - }; - } + if (!parseResult) { + // Wait for a maximum of 1 second for the media parsing. + for (int i = 0; i < 200; i++) { + if (libvlc_media_get_parsed_status(mMedia)) + break; + SDL_Delay(5); + }; + } - libvlc_media_track_t** tracks; - track_count = libvlc_media_tracks_get(mMedia, &tracks); - for (unsigned track = 0; track < track_count; ++track) - { - if (tracks[track]->i_type == libvlc_track_video) - { - mVideoWidth = tracks[track]->video->i_width; - mVideoHeight = tracks[track]->video->i_height; - break; - } - } - libvlc_media_tracks_release(tracks, track_count); + libvlc_media_track_t** tracks; + track_count = libvlc_media_tracks_get(mMedia, &tracks); + for (unsigned track = 0; track < track_count; ++track) { + if (tracks[track]->i_type == libvlc_track_video) { + mVideoWidth = tracks[track]->video->i_width; + mVideoHeight = tracks[track]->video->i_height; + break; + } + } + libvlc_media_tracks_release(tracks, track_count); - // Make sure we found a valid video track - if ((mVideoWidth > 0) && (mVideoHeight > 0)) - { -#ifndef _RPI_ - if (mScreensaverMode) - { - if(!Settings::getInstance()->getBool("CaptionsCompatibility")) { + // Make sure we found a valid video track. + if ((mVideoWidth > 0) && (mVideoHeight > 0)) { + #ifndef _RPI_ + if (mScreensaverMode) { + if (!Settings::getInstance()->getBool("CaptionsCompatibility")) { - Vector2f resizeScale((Renderer::getScreenWidth() / (float)mVideoWidth), (Renderer::getScreenHeight() / (float)mVideoHeight)); + Vector2f resizeScale((Renderer::getScreenWidth() / (float)mVideoWidth), + (Renderer::getScreenHeight() / (float)mVideoHeight)); - if(resizeScale.x() < resizeScale.y()) - { - mVideoWidth = (unsigned int) (mVideoWidth * resizeScale.x()); - mVideoHeight = (unsigned int) (mVideoHeight * resizeScale.x()); - }else{ - mVideoWidth = (unsigned int) (mVideoWidth * resizeScale.y()); - mVideoHeight = (unsigned int) (mVideoHeight * resizeScale.y()); - } - } - } -#endif - PowerSaver::pause(); - setupContext(); + if (resizeScale.x() < resizeScale.y()) { + mVideoWidth = (unsigned int) (mVideoWidth * resizeScale.x()); + mVideoHeight = (unsigned int) (mVideoHeight * resizeScale.x()); + } + else { + mVideoWidth = (unsigned int) (mVideoWidth * resizeScale.y()); + mVideoHeight = (unsigned int) (mVideoHeight * resizeScale.y()); + } + } + } + #endif + PowerSaver::pause(); + setupContext(); - // Setup the media player - mMediaPlayer = libvlc_media_player_new_from_media(mMedia); + // Setup the media player. + mMediaPlayer = libvlc_media_player_new_from_media(mMedia); - if (!Settings::getInstance()->getBool("VideoAudio") || - (Settings::getInstance()->getBool("ScreenSaverVideoMute") && mScreensaverMode)) - { - libvlc_audio_set_mute(mMediaPlayer, 1); - } + if (!Settings::getInstance()->getBool("VideoAudio") || + (Settings::getInstance()->getBool("ScreenSaverVideoMute") && + mScreensaverMode)) + libvlc_audio_set_mute(mMediaPlayer, 1); - libvlc_media_player_play(mMediaPlayer); - libvlc_video_set_callbacks(mMediaPlayer, lock, unlock, display, (void*)&mContext); - libvlc_video_set_format(mMediaPlayer, "RGBA", (int)mVideoWidth, (int)mVideoHeight, (int)mVideoWidth * 4); + libvlc_media_player_play(mMediaPlayer); + libvlc_video_set_callbacks(mMediaPlayer, lock, unlock, display, + (void*)&mContext); + libvlc_video_set_format(mMediaPlayer, "RGBA", (int)mVideoWidth, + (int)mVideoHeight, (int)mVideoWidth * 4); - // Update the playing state - mIsPlaying = true; - mFadeIn = 0.0f; - } - } - } - } + // Update the playing state. + mIsPlaying = true; + mFadeIn = 0.0f; + } + } + } + } } void VideoVlcComponent::stopVideo() { - mIsPlaying = false; - mStartDelayed = false; - // Release the media player so it stops calling back to us - if (mMediaPlayer) - { - libvlc_media_player_stop(mMediaPlayer); - libvlc_media_player_release(mMediaPlayer); - libvlc_media_release(mMedia); - mMediaPlayer = NULL; - freeContext(); - PowerSaver::resume(); - } + mIsPlaying = false; + mStartDelayed = false; + // Release the media player so it stops calling back to us. + if (mMediaPlayer) { + libvlc_media_player_stop(mMediaPlayer); + libvlc_media_player_release(mMediaPlayer); + libvlc_media_release(mMedia); + mMediaPlayer = nullptr; + freeContext(); + PowerSaver::resume(); + } } diff --git a/es-core/src/components/VideoVlcComponent.h b/es-core/src/components/VideoVlcComponent.h index 72bf27f15..3f556d973 100644 --- a/es-core/src/components/VideoVlcComponent.h +++ b/es-core/src/components/VideoVlcComponent.h @@ -1,8 +1,15 @@ +// +// VideoVlcComponent.h +// +// Video playing using libVLC. +// + #pragma once #ifndef ES_CORE_COMPONENTS_VIDEO_VLC_COMPONENT_H #define ES_CORE_COMPONENTS_VIDEO_VLC_COMPONENT_H #include "VideoComponent.h" + #include struct SDL_mutex; @@ -12,64 +19,62 @@ struct libvlc_media_t; struct libvlc_media_player_t; struct VideoContext { - SDL_Surface* surface; - SDL_mutex* mutex; - bool valid; + SDL_Surface* surface; + SDL_mutex* mutex; + bool valid; }; class VideoVlcComponent : public VideoComponent { - // Structure that groups together the configuration of the video component - struct Configuration - { - unsigned startDelay; - bool showSnapshotNoVideo; - bool showSnapshotDelay; - std::string defaultVideoPath; - }; + // Structure that groups together the configuration of the video component. + struct Configuration { + unsigned startDelay; + bool showSnapshotNoVideo; + bool showSnapshotDelay; + std::string defaultVideoPath; + }; public: - static void setupVLC(std::string subtitles); + static void setupVLC(std::string subtitles); - VideoVlcComponent(Window* window, std::string subtitles); - virtual ~VideoVlcComponent(); + VideoVlcComponent(Window* window, std::string subtitles); + virtual ~VideoVlcComponent(); - void render(const Transform4x4f& parentTrans) override; + void render(const Transform4x4f& parentTrans) override; + // Resize the video to fit this size. If one axis is zero, scale that axis to maintain + // aspect ratio. If both are non-zero, potentially break the aspect ratio. If both are + // zero, no resizing. This can be set before or after a video is loaded. + // setMaxSize() and setResize() are mutually exclusive. + void setResize(float width, float height) override; - // Resize the video to fit this size. If one axis is zero, scale that axis to maintain aspect ratio. - // If both are non-zero, potentially break the aspect ratio. If both are zero, no resizing. - // Can be set before or after a video is loaded. - // setMaxSize() and setResize() are mutually exclusive. - void setResize(float width, float height) override; - - // Resize the video to be as large as possible but fit within a box of this size. - // Can be set before or after a video is loaded. - // Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive. - void setMaxSize(float width, float height) override; + // Resize the video to be as large as possible but fit within a box of this size. + // This can be set before or after a video is loaded. + // Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive. + void setMaxSize(float width, float height) override; private: - // Calculates the correct mSize from our resizing information (set by setResize/setMaxSize). - // Used internally whenever the resizing parameters or texture change. - void resize(); - // Start the video Immediately - virtual void startVideo() override; - // Stop the video - virtual void stopVideo() override; - // Handle looping the video. Must be called periodically - virtual void handleLooping() override; + // Calculates the correct mSize from our resizing information (set by setResize/setMaxSize). + // Used internally whenever the resizing parameters or texture change. + void resize(); + // Start the video immediately. + virtual void startVideo() override; + // Stop the video. + virtual void stopVideo() override; + // Handle looping the video. Must be called periodically. + virtual void handleLooping() override; - void setupContext(); - void freeContext(); + void setupContext(); + void freeContext(); - static void VlcMediaParseCallback(const libvlc_event_t *event, void *user_data) {}; + static void VlcMediaParseCallback(const libvlc_event_t *event, void *user_data) {}; private: - static libvlc_instance_t* mVLC; - libvlc_media_t* mMedia; - libvlc_media_player_t* mMediaPlayer; - VideoContext mContext; - std::shared_ptr mTexture; + static libvlc_instance_t* mVLC; + libvlc_media_t* mMedia; + libvlc_media_player_t* mMediaPlayer; + VideoContext mContext; + std::shared_ptr mTexture; }; #endif // ES_CORE_COMPONENTS_VIDEO_VLC_COMPONENT_H diff --git a/es-core/src/guis/GuiInputConfig.cpp b/es-core/src/guis/GuiInputConfig.cpp index 17ce6150c..909f639ed 100755 --- a/es-core/src/guis/GuiInputConfig.cpp +++ b/es-core/src/guis/GuiInputConfig.cpp @@ -211,29 +211,29 @@ GuiInputConfig::GuiInputConfig( Input input; okFunction(); // Temporarily commented out, needs to be properly cleaned up later. -// if (!mTargetConfig->getInputByName("HotKeyEnable", &input)) { -// mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), -// "YOU DIDN'T CHOOSE A HOTKEY ENABLE BUTTON. THIS IS REQUIRED FOR EXITING GAMES " +// if (!mTargetConfig->getInputByName("HotKeyEnable", &input)) { +// mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), +// "YOU DIDN'T CHOOSE A HOTKEY ENABLE BUTTON. THIS IS REQUIRED FOR EXITING GAMES " // "WITH A CONTROLLER. DO YOU WANT TO USE THE SELECT BUTTON DEFAULT ? PLEASE ANSWER " // "YES TO USE SELECT OR NO TO NOT SET A HOTKEY ENABLE BUTTON.", -// "YES", [this, okFunction] { -// Input input; -// mTargetConfig->getInputByName("Select", &input); -// mTargetConfig->mapInput("HotKeyEnable", input); -// okFunction(); -// }, -// "NO", [this, okFunction] { -// // for a disabled hotkey enable button, set to a key with id 0, -// // so the input configuration script can be backwards compatible. -// mTargetConfig->mapInput("HotKeyEnable", Input(DEVICE_KEYBOARD, +// "YES", [this, okFunction] { +// Input input; +// mTargetConfig->getInputByName("Select", &input); +// mTargetConfig->mapInput("HotKeyEnable", input); +// okFunction(); +// }, +// "NO", [this, okFunction] { +// // for a disabled hotkey enable button, set to a key with id 0, +// // so the input configuration script can be backwards compatible. +// mTargetConfig->mapInput("HotKeyEnable", Input(DEVICE_KEYBOARD, // TYPE_KEY, 0, 1, true)); -// okFunction(); -// } -// )); -// } +// okFunction(); +// } +// )); +// } // else { -// okFunction(); -// } +// okFunction(); +// } })); mButtonGrid = makeButtonGrid(mWindow, buttons); diff --git a/es-core/src/renderers/Renderer.cpp b/es-core/src/renderers/Renderer.cpp index 783c894e7..f58b1b30c 100644 --- a/es-core/src/renderers/Renderer.cpp +++ b/es-core/src/renderers/Renderer.cpp @@ -1,7 +1,7 @@ // // Renderer.cpp // -// Rendering functions. +// General rendering functions. // #include "renderers/Renderer.h" diff --git a/es-core/src/renderers/Renderer.h b/es-core/src/renderers/Renderer.h index a9a1ee29f..8b7abc544 100644 --- a/es-core/src/renderers/Renderer.h +++ b/es-core/src/renderers/Renderer.h @@ -1,7 +1,7 @@ // // Renderer.h // -// Rendering functions. +// General rendering functions. // #pragma once diff --git a/es-core/src/resources/ResourceManager.cpp b/es-core/src/resources/ResourceManager.cpp index 1d35fcbf2..e1a956440 100644 --- a/es-core/src/resources/ResourceManager.cpp +++ b/es-core/src/resources/ResourceManager.cpp @@ -60,7 +60,7 @@ const ResourceData ResourceManager::getFileData(const std::string& path) const } // If the file doesn't exist, return an "empty" ResourceData. - ResourceData data = {NULL, 0}; + ResourceData data = {nullptr, 0}; return data; } diff --git a/es-core/src/resources/TextureData.cpp b/es-core/src/resources/TextureData.cpp index 8897433e7..49517cfb5 100644 --- a/es-core/src/resources/TextureData.cpp +++ b/es-core/src/resources/TextureData.cpp @@ -54,7 +54,7 @@ bool TextureData::initSVGFromMemory(const unsigned char* fileData, size_t length // nsvgParse excepts a modifiable, null-terminated string. char* copy = (char*)malloc(length + 1); - assert(copy != NULL); + assert(copy != nullptr); memcpy(copy, fileData, length); copy[length] = '\0';