diff --git a/CMakeLists.txt b/CMakeLists.txt index ab88f5c13..132ee4752 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,7 @@ set(ES_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScrollableContainer.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.h @@ -175,6 +176,7 @@ set(ES_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScrollableContainer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.cpp diff --git a/src/Renderer_draw_gl.cpp b/src/Renderer_draw_gl.cpp index 10fa92f33..05b8f4ae5 100644 --- a/src/Renderer_draw_gl.cpp +++ b/src/Renderer_draw_gl.cpp @@ -254,7 +254,8 @@ namespace Renderer { void sizeWrappedText(std::string text, int xLen, Font* font, int* xOut, int* yOut) { - *xOut = xLen; + if(xOut != NULL) + *xOut = xLen; int y = 0; @@ -306,7 +307,8 @@ namespace Renderer { } - *yOut = y; + if(yOut != NULL) + *yOut = y; } }; diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index 265d8da59..f2f8875dd 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -25,13 +25,15 @@ GuiGameList::GuiGameList(Window* window) : GuiComponent(window), mList(window, 0, 0, Renderer::getDefaultFont(Renderer::MEDIUM)), mScreenshot(window), mDescription(window), + mDescContainer(window), mTransitionImage(window, 0, 0, "", Renderer::getScreenWidth(), Renderer::getScreenHeight(), true) { mImageAnimation.addChild(&mScreenshot); + mDescContainer.addChild(&mDescription); //scale delay with screen width (higher width = more text per line) //the scroll speed is automatically scaled by component size - mDescription.setAutoScroll((int)(1500 + (Renderer::getScreenWidth() * 0.5)), 0.025f); + mDescContainer.setAutoScroll((int)(1500 + (Renderer::getScreenWidth() * 0.5)), 0.025f); mTransitionImage.setOffset(Renderer::getScreenWidth(), 0); mTransitionImage.setOrigin(0, 0); @@ -104,7 +106,7 @@ void GuiGameList::render() Renderer::drawRect((int)(Renderer::getScreenWidth() * mTheme->getFloat("listOffsetX")) - 4, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2, 8, Renderer::getScreenHeight(), 0x0000FFFF); mScreenshot.render(); - mDescription.render(); + mDescContainer.render(); } mList.render(); @@ -290,8 +292,13 @@ void GuiGameList::updateDetailData() mImageAnimation.fadeIn(35); mImageAnimation.move(imgOffset.x, imgOffset.y, 20); - mDescription.setOffset(Vector2i((int)(Renderer::getScreenWidth() * 0.03), getImagePos().y + mScreenshot.getSize().y + 12)); - mDescription.setExtent(Vector2u((int)(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03)), Renderer::getScreenHeight() - mDescription.getOffset().y)); + mDescContainer.setOffset(Vector2i((int)(Renderer::getScreenWidth() * 0.03), getImagePos().y + mScreenshot.getSize().y + 12)); + mDescContainer.setSize(Vector2u((int)(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03)), Renderer::getScreenHeight() - mDescContainer.getOffset().y)); + mDescContainer.setScrollPos(Vector2d(0, 0)); + mDescContainer.resetAutoScrollTimer(); + + mDescription.setOffset(0, 0); + mDescription.setExtent(Vector2u((int)(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03)), 0)); mDescription.setText(((GameData*)mList.getSelectedObject())->getDescription()); }else{ mScreenshot.setImage(""); @@ -340,7 +347,7 @@ void GuiGameList::update(int deltaTime) mList.update(deltaTime); - mDescription.update(deltaTime); + mDescContainer.update(deltaTime); } void GuiGameList::doTransition(int dir) diff --git a/src/components/GuiGameList.h b/src/components/GuiGameList.h index 51e581bbe..610900ff8 100644 --- a/src/components/GuiGameList.h +++ b/src/components/GuiGameList.h @@ -12,6 +12,7 @@ #include "../SystemData.h" #include "../GameData.h" #include "../FolderData.h" +#include "ScrollableContainer.h" //This is where the magic happens - GuiGameList is the parent of almost every graphical element in ES at the moment. //It has a TextListComponent child that handles the game list, a ThemeComponent that handles the theming system, and an ImageComponent for game images. @@ -53,6 +54,7 @@ private: TextListComponent mList; ImageComponent mScreenshot; TextComponent mDescription; + ScrollableContainer mDescContainer; AnimationComponent mImageAnimation; ThemeComponent* mTheme; diff --git a/src/components/ScrollableContainer.cpp b/src/components/ScrollableContainer.cpp new file mode 100644 index 000000000..38f05f56f --- /dev/null +++ b/src/components/ScrollableContainer.cpp @@ -0,0 +1,111 @@ +#include "ScrollableContainer.h" +#include "../Renderer.h" +#include "../Log.h" + +ScrollableContainer::ScrollableContainer(Window* window) : GuiComponent(window), + mAutoScrollDelay(0), mAutoScrollSpeed(0), mAutoScrollTimer(0) +{ +} + +void ScrollableContainer::render() +{ + Renderer::pushClipRect(getGlobalOffset(), getSize()); + + Vector2f translate = (Vector2f)mOffset - (Vector2f)mScrollPos; + + Renderer::translatef(translate.x, translate.y); + + Renderer::drawRect(0, 0, 800, 800, 0xFF0000FF); + + GuiComponent::onRender(); + + Renderer::translatef(-translate.x, -translate.y); + + Renderer::popClipRect(); +} + +void ScrollableContainer::setAutoScroll(int delay, double speed) +{ + mAutoScrollDelay = delay; + mAutoScrollSpeed = speed; + mAutoScrollTimer = 0; +} + +Vector2d ScrollableContainer::getScrollPos() const +{ + return mScrollPos; +} + +void ScrollableContainer::setScrollPos(const Vector2d& pos) +{ + mScrollPos = pos; +} + +void ScrollableContainer::update(int deltaTime) +{ + double scrollAmt = (double)deltaTime; + + if(mAutoScrollSpeed != 0) + { + mAutoScrollTimer += deltaTime; + + scrollAmt = (float)(mAutoScrollTimer - mAutoScrollDelay); + + if(scrollAmt > 0) + { + //scroll the amount of time left over from the delay + mAutoScrollTimer = mAutoScrollDelay; + + //scale speed by our width! more text per line = slower scrolling + const double widthMod = (680.0 / getSize().x); + mScrollDir = Vector2d(0, mAutoScrollSpeed * widthMod); + }else{ + //not enough to pass the delay, do nothing + scrollAmt = 0; + } + } + + Vector2d scroll = mScrollDir * scrollAmt; + mScrollPos += scroll; + + //clip scrolling within bounds + if(mScrollPos.x < 0) + mScrollPos.x = 0; + if(mScrollPos.y < 0) + mScrollPos.y = 0; + + + Vector2i contentSize = getContentSize(); + if(mScrollPos.x + getSize().x > contentSize.x) + mScrollPos.x = (double)contentSize.x - getSize().x; + if(mScrollPos.y + getSize().y > contentSize.y) + mScrollPos.y = (double)contentSize.y - getSize().y; + + GuiComponent::update(deltaTime); +} + +//this should probably return a box to allow for when controls don't start at 0,0 +Vector2i ScrollableContainer::getContentSize() +{ + Vector2i max; + for(unsigned int i = 0; i < mChildren.size(); i++) + { + Vector2i bottomRight = (Vector2i)mChildren.at(i)->getSize() + mChildren.at(i)->getOffset(); + if(bottomRight.x > max.x) + max.x = bottomRight.x; + if(bottomRight.y > max.y) + max.y = bottomRight.y; + } + + return max; +} + +void ScrollableContainer::setSize(Vector2u size) +{ + mSize = size; +} + +void ScrollableContainer::resetAutoScrollTimer() +{ + mAutoScrollTimer = 0; +} diff --git a/src/components/ScrollableContainer.h b/src/components/ScrollableContainer.h new file mode 100644 index 000000000..2e139bd7a --- /dev/null +++ b/src/components/ScrollableContainer.h @@ -0,0 +1,29 @@ +#pragma once + +#include "../GuiComponent.h" + +class ScrollableContainer : public GuiComponent +{ +public: + ScrollableContainer(Window* window); + + void setSize(Vector2u size); + + Vector2d getScrollPos() const; + void setScrollPos(const Vector2d& pos); + void setAutoScroll(int delay, double speed); //Use 0 for speed to disable. + void resetAutoScrollTimer(); + + void update(int deltaTime) override; + void render() override; + + //Vector2i getGlobalOffset() override; +private: + Vector2i getContentSize(); + + Vector2d mScrollPos; + Vector2d mScrollDir; + int mAutoScrollDelay; + double mAutoScrollSpeed; + int mAutoScrollTimer; +}; diff --git a/src/components/TextComponent.cpp b/src/components/TextComponent.cpp index 6b455881c..fc8dec8f3 100644 --- a/src/components/TextComponent.cpp +++ b/src/components/TextComponent.cpp @@ -3,12 +3,12 @@ #include "../Log.h" TextComponent::TextComponent(Window* window) : GuiComponent(window), - mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true), mAutoScrollDelay(0), mAutoScrollSpeed(0), mAutoScrollTimer(0) + mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true, true) { } TextComponent::TextComponent(Window* window, const std::string& text, Font* font, Vector2i pos, Vector2u size) : GuiComponent(window), - mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true), mAutoScrollDelay(0), mAutoScrollSpeed(0), mAutoScrollTimer(0) + mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true, true) { setText(text); setFont(font); @@ -23,22 +23,16 @@ void TextComponent::setBox(Vector2i pos, Vector2u size) void TextComponent::setExtent(Vector2u size) { - if(size == Vector2u(0, 0)) - { - mAutoCalcExtent = true; - calculateExtent(); - }else{ - mAutoCalcExtent = false; - mSize = size; - } + mSize = size; + mAutoCalcExtent = Vector2(size.x == 0, size.y == 0); + calculateExtent(); } void TextComponent::setFont(Font* font) { mFont = font; - if(mAutoCalcExtent) - calculateExtent(); + calculateExtent(); } void TextComponent::setColor(unsigned int color) @@ -50,12 +44,7 @@ void TextComponent::setText(const std::string& text) { mText = text; - if(mAutoCalcExtent) - calculateExtent(); - - mScrollPos = Vector2d(0, 0); - mScrollDir = Vector2d(0, 0); - resetAutoScrollTimer(); + calculateExtent(); } Font* TextComponent::getFont() const @@ -72,11 +61,11 @@ void TextComponent::onRender() return; } - Renderer::pushClipRect(getGlobalOffset(), getSize()); + //Renderer::pushClipRect(getGlobalOffset(), getSize()); - Renderer::drawWrappedText(mText, (int)-mScrollPos.x, (int)-mScrollPos.y, mSize.x, mColor >> 8 << 8 | getOpacity(), font); + Renderer::drawWrappedText(mText, 0, 0, mSize.x, mColor >> 8 << 8 | getOpacity(), font); - Renderer::popClipRect(); + //Renderer::popClipRect(); GuiComponent::onRender(); } @@ -90,75 +79,9 @@ void TextComponent::calculateExtent() return; } - font->sizeText(mText, (int*)&mSize.x, (int*)&mSize.y); -} - -void TextComponent::setAutoScroll(int delay, double speed) -{ - mAutoScrollDelay = delay; - mAutoScrollSpeed = speed; - resetAutoScrollTimer(); -} - -void TextComponent::resetAutoScrollTimer() -{ - mAutoScrollTimer = 0; -} - -Vector2d TextComponent::getScrollPos() const -{ - return mScrollPos; -} - -void TextComponent::setScrollPos(const Vector2d& pos) -{ - mScrollPos = pos; -} - -void TextComponent::update(int deltaTime) -{ - double scrollAmt = (double)deltaTime; - - if(mAutoScrollSpeed != 0) - { - mAutoScrollTimer += deltaTime; - - scrollAmt = (float)(mAutoScrollTimer - mAutoScrollDelay); - - if(scrollAmt > 0) - { - //scroll the amount of time left over from the delay - mAutoScrollTimer = mAutoScrollDelay; - - //scale speed by our width! more text per line = slower scrolling - const double widthMod = (680.0 / getSize().x); - mScrollDir = Vector2d(0, mAutoScrollSpeed * widthMod); - }else{ - //not enough to pass the delay, do nothing - scrollAmt = 0; - } - } - - Vector2d scroll = mScrollDir * scrollAmt; - mScrollPos += scroll; - - //clip scrolling within bounds - if(mScrollPos.x < 0) - mScrollPos.x = 0; - if(mScrollPos.y < 0) - mScrollPos.y = 0; - - Font* font = getFont(); - if(font != NULL) - { - Vector2i textSize; - Renderer::sizeWrappedText(mText, getSize().x, getFont(), &textSize.x, &textSize.y); - - if(mScrollPos.x + getSize().x > textSize.x) - mScrollPos.x = (double)textSize.x - getSize().x; - if(mScrollPos.y + getSize().y > textSize.y) - mScrollPos.y = (double)textSize.y - getSize().y; - } - - GuiComponent::update(deltaTime); + if(mAutoCalcExtent.x) + font->sizeText(mText, (int*)&mSize.x, (int*)&mSize.y); + else + if(mAutoCalcExtent.y) + Renderer::sizeWrappedText(mText, getSize().x, mFont, NULL, (int*)&mSize.y); } diff --git a/src/components/TextComponent.h b/src/components/TextComponent.h index a77a7ee5a..1a1c90eb4 100644 --- a/src/components/TextComponent.h +++ b/src/components/TextComponent.h @@ -12,33 +12,21 @@ public: void setFont(Font* font); void setBox(Vector2i pos, Vector2u size); - void setExtent(Vector2u size); //Use Vector2u(0, 0) to automatically generate extent. + void setExtent(Vector2u size); //Use Vector2u(0, 0) to automatically generate extent on a single line. Use Vector2(value, 0) to automatically generate extent for wrapped text. void setText(const std::string& text); void setColor(unsigned int color); - Vector2d getScrollPos() const; - void setScrollPos(const Vector2d& pos); - void setAutoScroll(int delay, double speed); //Use 0 for speed to disable. - void resetAutoScrollTimer(); - - void update(int deltaTime) override; void onRender() override; private: Font* getFont() const; + void calculateExtent(); unsigned int mColor; Font* mFont; - bool mAutoCalcExtent; + Vector2 mAutoCalcExtent; std::string mText; - - //scrolling - Vector2d mScrollPos; - Vector2d mScrollDir; - int mAutoScrollDelay; - double mAutoScrollSpeed; - int mAutoScrollTimer; }; #endif