diff --git a/THEMES.md b/THEMES.md index f1b7fa2a6..e6845c852 100644 --- a/THEMES.md +++ b/THEMES.md @@ -673,17 +673,32 @@ EmulationStation borrows the concept of "nine patches" from Android (or "9-Slice #### carousel * `type` - type: STRING. - - Accepted values are "horizontal" or "vertical". Sets the scoll direction of the carousel. - - Default is "horizontal". + - Sets the scoll direction of the carousel. + - Accepted values are "horizontal", "vertical" or "vertical_wheel". + - Default is "horizontal". * `size` - type: NORMALIZED_PAIR. Default is "1 0.2325" * `pos` - type: NORMALIZED_PAIR. Default is "0 0.38375". +* `origin` - type: NORMALIZED_PAIR. + - Where on the carousel `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the carousel exactly in the middle of the screen. If the "POSITION" and "SIZE" attributes are themable, "ORIGIN" is implied. * `color` - type: COLOR. - Controls the color of the carousel background. - Default is FFFFFFD8 * `logoSize` - type: NORMALIZED_PAIR. Default is "0.25 0.155" * `logoScale` - type: FLOAT. - * Selected logo is increased in size by this scale - * Default is 1.2 + - Selected logo is increased in size by this scale + - Default is 1.2 +* `logoRotation` - type: FLOAT. + - Angle in degrees that the logos should be rotated. Value should be positive. + - Default is 7.5 + - This property only applies when `type` is "vertical_wheel". +* `logoRotationOrigin` - type: NORMALIZED_PAIR. + - Point around which the logos will be rotated. Defaults to `-5 0.5`. + - This property only applies when `type` is "vertical_wheel". +* `logoAlignment` - type: STRING. + - Sets the alignment of the logos relative to the carousel. + - Accepted values are "top", "bottom" or "center" when `type` is "horizontal". + - Accepted values are "left", "right" or "center" when `type` is "vertical" or "vertical_wheel". + - Default is "center" * `maxLogoCount` - type: FLOAT. - Sets the number of logos to display in the carousel. - Default is 3 diff --git a/es-app/src/guis/GuiFastSelect.cpp b/es-app/src/guis/GuiFastSelect.cpp index 75b7fbe62..59715e9ff 100644 --- a/es-app/src/guis/GuiFastSelect.cpp +++ b/es-app/src/guis/GuiFastSelect.cpp @@ -19,14 +19,14 @@ GuiFastSelect::GuiFastSelect(Window* window, IGameListView* gamelist) : GuiCompo addChild(&mBackground); mLetterText.setSize(mSize.x(), mSize.y() * 0.75f); - mLetterText.setAlignment(ALIGN_CENTER); + mLetterText.setHorizontalAlignment(ALIGN_CENTER); mLetterText.applyTheme(theme, "fastSelect", "letter", FONT_PATH | COLOR); // TODO - set font size addChild(&mLetterText); mSortText.setPosition(0, mSize.y() * 0.75f); mSortText.setSize(mSize.x(), mSize.y() * 0.25f); - mSortText.setAlignment(ALIGN_CENTER); + mSortText.setHorizontalAlignment(ALIGN_CENTER); mSortText.applyTheme(theme, "fastSelect", "subtext", FONT_PATH | COLOR); // TODO - set font size addChild(&mSortText); diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index 696e444e2..c46a56e64 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -418,7 +418,7 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN mVersion.setFont(Font::get(FONT_SIZE_SMALL)); mVersion.setColor(0x5E5E5EFF); mVersion.setText("EMULATIONSTATION V" + strToUpper(PROGRAM_VERSION_STRING)); - mVersion.setAlignment(ALIGN_CENTER); + mVersion.setHorizontalAlignment(ALIGN_CENTER); addChild(&mMenu); addChild(&mVersion); diff --git a/es-app/src/views/SystemView.cpp b/es-app/src/views/SystemView.cpp index acb14c8cf..999ac79ca 100644 --- a/es-app/src/views/SystemView.cpp +++ b/es-app/src/views/SystemView.cpp @@ -49,18 +49,10 @@ void SystemView::populate() if(!path.empty() && ResourceManager::getInstance()->fileExists(path)) { ImageComponent* logo = new ImageComponent(mWindow, false, false); - logo->setMaxSize(Eigen::Vector2f(mCarousel.logoSize.x(), mCarousel.logoSize.y())); + logo->setMaxSize(mCarousel.logoSize * mCarousel.logoScale); logo->applyTheme((*it)->getTheme(), "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR); - logo->setPosition((mCarousel.logoSize.x() - logo->getSize().x()) / 2, - (mCarousel.logoSize.y() - logo->getSize().y()) / 2); // center - e.data.logo = std::shared_ptr(logo); - ImageComponent* logoSelected = new ImageComponent(mWindow, false, false); - logoSelected->setMaxSize(Eigen::Vector2f(mCarousel.logoSize.x() * mCarousel.logoScale, mCarousel.logoSize.y() * mCarousel.logoScale)); - logoSelected->applyTheme((*it)->getTheme(), "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR); - logoSelected->setPosition((mCarousel.logoSize.x() - logoSelected->getSize().x()) / 2, - (mCarousel.logoSize.y() - logoSelected->getSize().y()) / 2); // center - e.data.logoSelected = std::shared_ptr(logoSelected); + e.data.logo = std::shared_ptr(logo); } } if (!e.data.logo) @@ -71,20 +63,36 @@ void SystemView::populate() Font::get(FONT_SIZE_LARGE), 0x000000FF, ALIGN_CENTER); - text->setSize(mCarousel.logoSize); - text->applyTheme((*it)->getTheme(), "system", "logoText", ThemeFlags::FONT_PATH | ThemeFlags::COLOR | ThemeFlags::FORCE_UPPERCASE); + text->setSize(mCarousel.logoSize * mCarousel.logoScale); + text->applyTheme((*it)->getTheme(), "system", "logoText", ThemeFlags::FONT_PATH | ThemeFlags::FONT_SIZE | ThemeFlags::COLOR | ThemeFlags::FORCE_UPPERCASE); e.data.logo = std::shared_ptr(text); - TextComponent* textSelected = new TextComponent(mWindow, - (*it)->getName(), - Font::get((int)(FONT_SIZE_LARGE * mCarousel.logoScale)), - 0x000000FF, - ALIGN_CENTER); - textSelected->setSize(mCarousel.logoSize); - textSelected->applyTheme((*it)->getTheme(), "system", "logoText", ThemeFlags::FONT_PATH | ThemeFlags::COLOR | ThemeFlags::FORCE_UPPERCASE); - e.data.logoSelected = std::shared_ptr(textSelected); + if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL) + text->setHorizontalAlignment(mCarousel.logoAlignment); + else + text->setVerticalAlignment(mCarousel.logoAlignment); } + if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL) + { + if (mCarousel.logoAlignment == ALIGN_LEFT) + e.data.logo->setOrigin(0, 0.5); + else if (mCarousel.logoAlignment == ALIGN_RIGHT) + e.data.logo->setOrigin(1.0, 0.5); + else + e.data.logo->setOrigin(0.5, 0.5); + } else { + if (mCarousel.logoAlignment == ALIGN_TOP) + e.data.logo->setOrigin(0.5, 0); + else if (mCarousel.logoAlignment == ALIGN_BOTTOM) + e.data.logo->setOrigin(0.5, 1); + else + e.data.logo->setOrigin(0.5, 0.5); + } + + Eigen::Vector2f denormalized = mCarousel.logoSize.cwiseProduct(e.data.logo->getOrigin()); + e.data.logo->setPosition(denormalized.x(), denormalized.y(), 0.0); + // delete any existing extras for (auto extra : e.data.backgroundExtras) delete extra; @@ -94,7 +102,7 @@ void SystemView::populate() e.data.backgroundExtras = ThemeData::makeExtras((*it)->getTheme(), "system", mWindow); // sort the extras by z-index - std:stable_sort(e.data.backgroundExtras.begin(), e.data.backgroundExtras.end(), [](GuiComponent* a, GuiComponent* b) { + std::stable_sort(e.data.backgroundExtras.begin(), e.data.backgroundExtras.end(), [](GuiComponent* a, GuiComponent* b) { return b->getZIndex() > a->getZIndex(); }); @@ -124,6 +132,7 @@ bool SystemView::input(InputConfig* config, Input input) switch (mCarousel.type) { case VERTICAL: + case VERTICAL_WHEEL: if (config->isMappedTo("up", input)) { listInput(-1); @@ -400,14 +409,16 @@ void SystemView::getViewElements(const std::shared_ptr& theme) // Render system carousel void SystemView::renderCarousel(const Eigen::Affine3f& trans) { - Eigen::Vector2i clipPos((int)mCarousel.pos.x(), (int)mCarousel.pos.y()); - Eigen::Vector2i clipSize((int)mCarousel.size.x(), (int)mCarousel.size.y()); - - Renderer::pushClipRect(clipPos, clipSize); - // background box behind logos - Renderer::setMatrix(trans); - Renderer::drawRect(mCarousel.pos.x(), mCarousel.pos.y(), mCarousel.size.x(), mCarousel.size.y(), mCarousel.color); + Eigen::Affine3f carouselTrans = trans; + carouselTrans.translate(Eigen::Vector3f(mCarousel.pos.x(), mCarousel.pos.y(), 0.0)); + carouselTrans.translate(Eigen::Vector3f(mCarousel.origin.x() * mCarousel.size.x() * -1, mCarousel.origin.y() * mCarousel.size.y() * -1, 0.0f)); + + Eigen::Vector2f clipPos(carouselTrans.translation().x(), carouselTrans.translation().y()); + Renderer::pushClipRect(clipPos.cast(), mCarousel.size.cast()); + + Renderer::setMatrix(carouselTrans); + Renderer::drawRect(0.0, 0.0, mCarousel.size.x(), mCarousel.size.y(), mCarousel.color); // draw logos Eigen::Vector2f logoSpacing(0.0, 0.0); // NB: logoSpacing will include the size of the logo itself as well! @@ -416,20 +427,40 @@ void SystemView::renderCarousel(const Eigen::Affine3f& trans) switch (mCarousel.type) { + case VERTICAL_WHEEL: + yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2 - (mCamOffset * logoSpacing[1]); + if (mCarousel.logoAlignment == ALIGN_LEFT) + xOff = mCarousel.logoSize.x() / 10; + else if (mCarousel.logoAlignment == ALIGN_RIGHT) + xOff = mCarousel.size.x() - (mCarousel.logoSize.x() * 1.1); + else + xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2; + break; case VERTICAL: logoSpacing[1] = ((mCarousel.size.y() - (mCarousel.logoSize.y() * mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.y(); - xOff = mCarousel.pos.x() + (mCarousel.size.x() / 2) - (mCarousel.logoSize.x() / 2); - yOff = mCarousel.pos.y() + (mCarousel.size.y() - mCarousel.logoSize.y()) / 2 - (mCamOffset * logoSpacing[1]); + yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2 - (mCamOffset * logoSpacing[1]); + + if (mCarousel.logoAlignment == ALIGN_LEFT) + xOff = mCarousel.logoSize.x() / 10; + else if (mCarousel.logoAlignment == ALIGN_RIGHT) + xOff = mCarousel.size.x() - (mCarousel.logoSize.x() * 1.1); + else + xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2; break; case HORIZONTAL: default: logoSpacing[0] = ((mCarousel.size.x() - (mCarousel.logoSize.x() * mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.x(); - xOff = mCarousel.pos.x() + (mCarousel.size.x() - mCarousel.logoSize.x()) / 2 - (mCamOffset * logoSpacing[0]); - yOff = mCarousel.pos.y() + (mCarousel.size.y() / 2) - (mCarousel.logoSize.y() / 2); + xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2 - (mCamOffset * logoSpacing[0]); + + if (mCarousel.logoAlignment == ALIGN_TOP) + yOff = mCarousel.logoSize.y() / 10; + else if (mCarousel.logoAlignment == ALIGN_BOTTOM) + yOff = mCarousel.size.y() - (mCarousel.logoSize.y() * 1.1); + else + yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2; break; } - Eigen::Affine3f logoTrans = trans; int center = (int)(mCamOffset); int logoCount = std::min(mCarousel.maxLogoCount, (int)mEntries.size()); @@ -444,19 +475,26 @@ void SystemView::renderCarousel(const Eigen::Affine3f& trans) while (index >= (int)mEntries.size()) index -= mEntries.size(); - logoTrans.translation() = trans.translation() + Eigen::Vector3f(i * logoSpacing[0] + xOff, i * logoSpacing [1] + yOff, 0); + Eigen::Affine3f logoTrans = carouselTrans; + logoTrans.translate(Eigen::Vector3f(i * logoSpacing[0] + xOff, i * logoSpacing[1] + yOff, 0)); - if (index == mCursor) //Selected System - { - const std::shared_ptr& comp = mEntries.at(index).data.logoSelected; - comp->setOpacity(0xFF); - comp->render(logoTrans); - } - else { // not selected systems - const std::shared_ptr& comp = mEntries.at(index).data.logo; - comp->setOpacity(0x80); - comp->render(logoTrans); + float distance = i - mCamOffset; + + float scale = 1.0 + ((mCarousel.logoScale - 1.0) * (1 - fabs(distance))); + scale = std::min(mCarousel.logoScale, std::max(1.0f, scale)); + scale /= mCarousel.logoScale; + + int opacity = round(0x80 + ((0xFF - 0x80) * (1 - fabs(distance)))); + opacity = std::max((int) 0x80, opacity); + + const std::shared_ptr &comp = mEntries.at(index).data.logo; + if (mCarousel.type == VERTICAL_WHEEL) { + comp->setRotationDegrees(mCarousel.logoRotation * distance); + comp->setRotationOrigin(mCarousel.logoRotationOrigin); } + comp->setScale(scale); + comp->setOpacity(opacity); + comp->render(logoTrans); } Renderer::popClipRect(); } @@ -475,7 +513,7 @@ void SystemView::renderExtras(const Eigen::Affine3f& trans, float lower, float u // Adding texture loading buffers depending on scrolling speed and status int bufferIndex = getScrollingVelocity() + 1; - Renderer::pushClipRect(Eigen::Vector2i(0, 0), mSize.cast()); + Renderer::pushClipRect(Eigen::Vector2i::Zero(), mSize.cast()); for (int i = extrasCenter + logoBuffersLeft[bufferIndex]; i <= extrasCenter + logoBuffersRight[bufferIndex]; i++) { @@ -485,22 +523,26 @@ void SystemView::renderExtras(const Eigen::Affine3f& trans, float lower, float u while (index >= (int)mEntries.size()) index -= mEntries.size(); - Eigen::Affine3f extrasTrans = trans; - if (mCarousel.type == HORIZONTAL) - extrasTrans.translate(Eigen::Vector3f((i - mExtrasCamOffset) * mSize.x(), 0, 0)); - else - extrasTrans.translate(Eigen::Vector3f(0, (i - mExtrasCamOffset) * mSize.y(), 0)); - - Renderer::pushClipRect(Eigen::Vector2i(extrasTrans.translation()[0], extrasTrans.translation()[1]), mSize.cast()); - SystemViewData data = mEntries.at(index).data; - for(unsigned int j = 0; j < data.backgroundExtras.size(); j++) + //Only render selected system when not showing + if (mShowing || index == mCursor) { - GuiComponent* extra = data.backgroundExtras[j]; - if (extra->getZIndex() >= lower && extra->getZIndex() < upper) { - extra->render(extrasTrans); + Eigen::Affine3f extrasTrans = trans; + if (mCarousel.type == HORIZONTAL) + extrasTrans.translate(Eigen::Vector3f((i - mExtrasCamOffset) * mSize.x(), 0, 0)); + else + extrasTrans.translate(Eigen::Vector3f(0, (i - mExtrasCamOffset) * mSize.y(), 0)); + + Renderer::pushClipRect(Eigen::Vector2i(extrasTrans.translation()[0], extrasTrans.translation()[1]), + mSize.cast()); + SystemViewData data = mEntries.at(index).data; + for (unsigned int j = 0; j < data.backgroundExtras.size(); j++) { + GuiComponent *extra = data.backgroundExtras[j]; + if (extra->getZIndex() >= lower && extra->getZIndex() < upper) { + extra->render(extrasTrans); + } } + Renderer::popClipRect(); } - Renderer::popClipRect(); } Renderer::popClipRect(); } @@ -520,12 +562,18 @@ void SystemView::getDefaultElements(void) { // Carousel mCarousel.type = HORIZONTAL; + mCarousel.logoAlignment = ALIGN_CENTER; mCarousel.size.x() = mSize.x(); mCarousel.size.y() = 0.2325f * mSize.y(); mCarousel.pos.x() = 0.0f; mCarousel.pos.y() = 0.5f * (mSize.y() - mCarousel.size.y()); + mCarousel.origin.x() = 0.0f; + mCarousel.origin.y() = 0.0f; mCarousel.color = 0xFFFFFFD8; mCarousel.logoScale = 1.2f; + mCarousel.logoRotation = 7.5; + mCarousel.logoRotationOrigin.x() = -5; + mCarousel.logoRotationOrigin.y() = 0.5; mCarousel.logoSize.x() = 0.25f * mSize.x(); mCarousel.logoSize.y() = 0.155f * mSize.y(); mCarousel.maxLogoCount = 3; @@ -545,11 +593,20 @@ void SystemView::getDefaultElements(void) void SystemView::getCarouselFromTheme(const ThemeData::ThemeElement* elem) { if (elem->has("type")) - mCarousel.type = !(elem->get("type").compare("vertical")) ? VERTICAL : HORIZONTAL; + { + if (!(elem->get("type").compare("vertical"))) + mCarousel.type = VERTICAL; + else if (!(elem->get("type").compare("vertical_wheel"))) + mCarousel.type = VERTICAL_WHEEL; + else + mCarousel.type = HORIZONTAL; + } if (elem->has("size")) mCarousel.size = elem->get("size").cwiseProduct(mSize); if (elem->has("pos")) mCarousel.pos = elem->get("pos").cwiseProduct(mSize); + if (elem->has("origin")) + mCarousel.origin = elem->get("origin"); if (elem->has("color")) mCarousel.color = elem->get("color"); if (elem->has("logoScale")) @@ -560,4 +617,31 @@ void SystemView::getCarouselFromTheme(const ThemeData::ThemeElement* elem) mCarousel.maxLogoCount = std::round(elem->get("maxLogoCount")); if (elem->has("zIndex")) mCarousel.zIndex = elem->get("zIndex"); + if (elem->has("logoRotation")) + mCarousel.logoRotation = elem->get("logoRotation"); + if (elem->has("logoRotationOrigin")) + mCarousel.logoRotationOrigin = elem->get("logoRotationOrigin"); + if (elem->has("logoAlignment")) + { + if (!(elem->get("logoAlignment").compare("left"))) + mCarousel.logoAlignment = ALIGN_LEFT; + else if (!(elem->get("logoAlignment").compare("right"))) + mCarousel.logoAlignment = ALIGN_RIGHT; + else if (!(elem->get("logoAlignment").compare("top"))) + mCarousel.logoAlignment = ALIGN_TOP; + else if (!(elem->get("logoAlignment").compare("bottom"))) + mCarousel.logoAlignment = ALIGN_BOTTOM; + else + mCarousel.logoAlignment = ALIGN_CENTER; + } +} + +void SystemView::onShow() +{ + mShowing = true; +} + +void SystemView::onHide() +{ + mShowing = false; } diff --git a/es-app/src/views/SystemView.h b/es-app/src/views/SystemView.h index c766c5902..50689eb92 100644 --- a/es-app/src/views/SystemView.h +++ b/es-app/src/views/SystemView.h @@ -13,13 +13,13 @@ class AnimatedImageComponent; enum CarouselType : unsigned int { HORIZONTAL = 0, - VERTICAL = 1 + VERTICAL = 1, + VERTICAL_WHEEL = 2 }; struct SystemViewData { std::shared_ptr logo; - std::shared_ptr logoSelected; std::vector backgroundExtras; }; @@ -28,8 +28,11 @@ struct SystemViewCarousel CarouselType type; Eigen::Vector2f pos; Eigen::Vector2f size; + Eigen::Vector2f origin; float logoScale; - Eigen::Vector2f logoSpacing; + float logoRotation; + Eigen::Vector2f logoRotationOrigin; + Alignment logoAlignment; unsigned int color; int maxLogoCount; // number of logos shown on the carousel Eigen::Vector2f logoSize; @@ -41,6 +44,9 @@ class SystemView : public IList public: SystemView(Window* window); + virtual void onShow() override; + virtual void onHide() override; + void goToSystem(SystemData* system, bool animate); bool input(InputConfig* config, Input input) override; @@ -76,4 +82,5 @@ private: float mExtrasFadeOpacity; bool mViewNeedsReload; + bool mShowing; }; diff --git a/es-app/src/views/ViewController.cpp b/es-app/src/views/ViewController.cpp index cb7b66a49..729c1b493 100644 --- a/es-app/src/views/ViewController.cpp +++ b/es-app/src/views/ViewController.cpp @@ -72,6 +72,7 @@ void ViewController::goToSystemView(SystemData* system) systemList->goToSystem(system, false); mCurrentView = systemList; + mCurrentView->onShow(); PowerSaver::setState(true); playViewTransition(); diff --git a/es-app/src/views/gamelist/ISimpleGameListView.cpp b/es-app/src/views/gamelist/ISimpleGameListView.cpp index 3b468f445..064aa6796 100644 --- a/es-app/src/views/gamelist/ISimpleGameListView.cpp +++ b/es-app/src/views/gamelist/ISimpleGameListView.cpp @@ -13,7 +13,7 @@ ISimpleGameListView::ISimpleGameListView(Window* window, FileData* root) : IGame mHeaderText.setText("Logo Text"); mHeaderText.setSize(mSize.x(), 0); mHeaderText.setPosition(0, 0); - mHeaderText.setAlignment(ALIGN_CENTER); + mHeaderText.setHorizontalAlignment(ALIGN_CENTER); mHeaderText.setDefaultZIndex(50); mHeaderImage.setResize(0, mSize.y() * 0.185f); diff --git a/es-core/src/GuiComponent.cpp b/es-core/src/GuiComponent.cpp index 07feb0afc..43a79b41a 100644 --- a/es-core/src/GuiComponent.cpp +++ b/es-core/src/GuiComponent.cpp @@ -132,7 +132,6 @@ float GuiComponent::getScale() const void GuiComponent::setScale(float scale) { mScale = scale; - onSizeChanged(); } float GuiComponent::getZIndex() const diff --git a/es-core/src/ThemeData.cpp b/es-core/src/ThemeData.cpp index ed5b240e3..dc5c6deae 100644 --- a/es-core/src/ThemeData.cpp +++ b/es-core/src/ThemeData.cpp @@ -127,9 +127,13 @@ std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign:: ("type", STRING) ("size", NORMALIZED_PAIR) ("pos", NORMALIZED_PAIR) + ("origin", NORMALIZED_PAIR) ("color", COLOR) ("logoScale", FLOAT) + ("logoRotation", FLOAT) + ("logoRotationOrigin", NORMALIZED_PAIR) ("logoSize", NORMALIZED_PAIR) + ("logoAlignment", STRING) ("maxLogoCount", FLOAT) ("zIndex", FLOAT))); diff --git a/es-core/src/components/MenuComponent.cpp b/es-core/src/components/MenuComponent.cpp index 58462dd9c..376ebca78 100644 --- a/es-core/src/components/MenuComponent.cpp +++ b/es-core/src/components/MenuComponent.cpp @@ -18,7 +18,7 @@ MenuComponent::MenuComponent(Window* window, const char* title, const std::share // set up title mTitle = std::make_shared(mWindow); - mTitle->setAlignment(ALIGN_CENTER); + mTitle->setHorizontalAlignment(ALIGN_CENTER); mTitle->setColor(0x555555FF); setTitle(title, titleFont); mGrid.setEntry(mTitle, Vector2i(0, 0), false); diff --git a/es-core/src/components/OptionListComponent.h b/es-core/src/components/OptionListComponent.h index 9f3eec521..5ba88fca1 100644 --- a/es-core/src/components/OptionListComponent.h +++ b/es-core/src/components/OptionListComponent.h @@ -144,7 +144,7 @@ public: auto font = Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT); mText.setFont(font); mText.setColor(0x777777FF); - mText.setAlignment(ALIGN_CENTER); + mText.setHorizontalAlignment(ALIGN_CENTER); addChild(&mText); if(mMultiSelect) diff --git a/es-core/src/components/TextComponent.cpp b/es-core/src/components/TextComponent.cpp index bb1edfb5d..c718f9926 100644 --- a/es-core/src/components/TextComponent.cpp +++ b/es-core/src/components/TextComponent.cpp @@ -8,13 +8,17 @@ #include "Settings.h" TextComponent::TextComponent(Window* window) : GuiComponent(window), - mFont(Font::get(FONT_SIZE_MEDIUM)), mUppercase(false), mColor(0x000000FF), mAutoCalcExtent(true, true), mAlignment(ALIGN_LEFT), mLineSpacing(1.5f), mBgColor(0), mRenderBackground(false) + 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, Eigen::Vector3f pos, Eigen::Vector2f size, unsigned int bgcolor) : GuiComponent(window), - mFont(NULL), mUppercase(false), mColor(0x000000FF), mAutoCalcExtent(true, true), mAlignment(align), mLineSpacing(1.5f), mBgColor(0), mRenderBackground(false) + mFont(NULL), mUppercase(false), mColor(0x000000FF), mAutoCalcExtent(true, true), + mHorizontalAlignment(align), mVerticalAlignment(ALIGN_CENTER), mLineSpacing(1.5f), mBgColor(0), + mRenderBackground(false) { setFont(font); setColor(color); @@ -104,7 +108,20 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans) if(mTextCache) { const Eigen::Vector2f& textSize = mTextCache->metrics.size; - Eigen::Vector3f off(0, (getSize().y() - textSize.y()) / 2.0f, 0); + float yOff; + 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; + } + Eigen::Vector3f off(0, yOff, 0); if(Settings::getInstance()->getBool("DebugText")) { @@ -120,7 +137,7 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans) // draw the text area, where the text actually is going if(Settings::getInstance()->getBool("DebugText")) { - switch(mAlignment) + switch(mHorizontalAlignment) { case ALIGN_LEFT: Renderer::drawRect(0.0f, 0.0f, mTextCache->metrics.size.x(), mTextCache->metrics.size.y(), 0x00000033); @@ -189,9 +206,9 @@ void TextComponent::onTextChanged() text.append(abbrev); - mTextCache = std::shared_ptr(f->buildTextCache(text, Eigen::Vector2f(0, 0), (mColor >> 8 << 8) | mOpacity, mSize.x(), mAlignment, mLineSpacing)); + mTextCache = std::shared_ptr(f->buildTextCache(text, Eigen::Vector2f(0, 0), (mColor >> 8 << 8) | mOpacity, mSize.x(), mHorizontalAlignment, mLineSpacing)); }else{ - mTextCache = std::shared_ptr(f->buildTextCache(f->wrapText(text, mSize.x()), Eigen::Vector2f(0, 0), (mColor >> 8 << 8) | mOpacity, mSize.x(), mAlignment, mLineSpacing)); + mTextCache = std::shared_ptr(f->buildTextCache(f->wrapText(text, mSize.x()), Eigen::Vector2f(0, 0), (mColor >> 8 << 8) | mOpacity, mSize.x(), mHorizontalAlignment, mLineSpacing)); } } @@ -203,12 +220,17 @@ void TextComponent::onColorChanged() } } -void TextComponent::setAlignment(Alignment align) +void TextComponent::setHorizontalAlignment(Alignment align) { - mAlignment = align; + mHorizontalAlignment = align; onTextChanged(); } +void TextComponent::setVerticalAlignment(Alignment align) +{ + mVerticalAlignment = align; +} + void TextComponent::setLineSpacing(float spacing) { mLineSpacing = spacing; @@ -248,11 +270,11 @@ void TextComponent::applyTheme(const std::shared_ptr& theme, const st { std::string str = elem->get("alignment"); if(str == "left") - setAlignment(ALIGN_LEFT); + setHorizontalAlignment(ALIGN_LEFT); else if(str == "center") - setAlignment(ALIGN_CENTER); + setHorizontalAlignment(ALIGN_CENTER); else if(str == "right") - setAlignment(ALIGN_RIGHT); + setHorizontalAlignment(ALIGN_RIGHT); else LOG(LogError) << "Unknown text alignment string: " << str; } diff --git a/es-core/src/components/TextComponent.h b/es-core/src/components/TextComponent.h index 2f2f8e4e6..2e9938c58 100644 --- a/es-core/src/components/TextComponent.h +++ b/es-core/src/components/TextComponent.h @@ -23,7 +23,8 @@ public: void onSizeChanged() override; void setText(const std::string& text); void setColor(unsigned int color); - void setAlignment(Alignment align); + void setHorizontalAlignment(Alignment align); + void setVerticalAlignment(Alignment align); void setLineSpacing(float spacing); void setBackgroundColor(unsigned int color); void setRenderBackground(bool render); @@ -57,7 +58,8 @@ private: Eigen::Matrix mAutoCalcExtent; std::string mText; std::shared_ptr mTextCache; - Alignment mAlignment; + Alignment mHorizontalAlignment; + Alignment mVerticalAlignment; float mLineSpacing; }; diff --git a/es-core/src/resources/Font.h b/es-core/src/resources/Font.h index 376a7d639..0dee2aa6c 100644 --- a/es-core/src/resources/Font.h +++ b/es-core/src/resources/Font.h @@ -25,7 +25,9 @@ enum Alignment { ALIGN_LEFT, ALIGN_CENTER, // centers both horizontally and vertically - ALIGN_RIGHT + ALIGN_RIGHT, + ALIGN_TOP, + ALIGN_BOTTOM }; //A TrueType Font renderer that uses FreeType and OpenGL.