diff --git a/src/Renderer.h b/src/Renderer.h index f70b8c83b..80e2ab437 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -43,6 +43,7 @@ namespace Renderer void drawText(std::string text, int x, int y, unsigned int color, Font* font); void drawCenteredText(std::string text, int xOffset, int y, unsigned int color, Font* font); void drawWrappedText(std::string text, int xStart, int yStart, int xLen, unsigned int color, Font* font); + void sizeWrappedText(std::string text, int xLen, Font* font, int* xOut, int* yOut); } #endif diff --git a/src/Renderer_draw_gl.cpp b/src/Renderer_draw_gl.cpp index afa0b1d4b..10fa92f33 100644 --- a/src/Renderer_draw_gl.cpp +++ b/src/Renderer_draw_gl.cpp @@ -252,4 +252,61 @@ namespace Renderer { } } + void sizeWrappedText(std::string text, int xLen, Font* font, int* xOut, int* yOut) + { + *xOut = xLen; + + int y = 0; + + std::string line, word, temp; + int w, h; + size_t space, newline; + + while(text.length() > 0 || !line.empty()) //while there's text or we still have text to render + { + space = text.find(' ', 0); + if(space == std::string::npos) + space = text.length() - 1; + + word = text.substr(0, space + 1); + + //check if the next word contains a newline + newline = word.find('\n', 0); + if(newline != std::string::npos) + { + word = word.substr(0, newline); + text.erase(0, newline + 1); + }else{ + text.erase(0, space + 1); + } + + temp = line + word; + + font->sizeText(temp, &w, &h); + + //if we're on the last word and it'll fit on the line, just add it to the line + if((w <= xLen && text.length() == 0) || newline != std::string::npos) + { + line = temp; + word = ""; + } + + //if the next line will be too long or we're on the last of the text, render it + if(w > xLen || text.length() == 0 || newline != std::string::npos) + { + //increment y by height and some extra padding for the next line + y += h + 4; + + //move the word we skipped to the next line + line = word; + }else{ + //there's still space, continue building the line + line = temp; + } + + } + + *yOut = y; + } + }; diff --git a/src/Vector2.h b/src/Vector2.h index 672c8ab3e..ddb6e1fd7 100644 --- a/src/Vector2.h +++ b/src/Vector2.h @@ -93,6 +93,7 @@ bool operator !=(const Vector2& left, const Vector2& right) typedef Vector2 Vector2i; typedef Vector2 Vector2u; typedef Vector2 Vector2f; +typedef Vector2 Vector2d; class Rect { diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index c91d48ade..d6b2cd60d 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -36,9 +36,11 @@ GuiGameList::GuiGameList(Window* window, bool useDetail) : GuiComponent(window), mScreenshot->setOrigin(mTheme->getFloat("gameImageOriginX"), mTheme->getFloat("gameImageOriginY")); - mDescription.setOffset(Vector2i((int)(Renderer::getScreenWidth() * 0.03), mScreenshot->getOffset().y + mScreenshot->getSize().y + 12)); - mDescription.setExtent(Vector2u((int)(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03)), 0)); - + mDescription.setOffset(Vector2i((int)(Renderer::getScreenWidth() * 0.03), getImagePos().y + mScreenshot->getSize().y + 12)); + //scale delay with screen width (higher width = more text per line) + //the scroll speed is automatically scrolled by component size + mDescription.setAutoScroll((int)(1500 + (Renderer::getScreenWidth() * 0.5)), 0.025f); + mTransitionImage.setOffset(Renderer::getScreenWidth(), 0); mTransitionImage.setOrigin(0, 0); mTransitionAnimation.addChild(&mTransitionImage); @@ -307,7 +309,8 @@ void GuiGameList::updateDetailData() mImageAnimation->fadeIn(35); mImageAnimation->move(imgOffset.x, imgOffset.y, 20); - mDescription.setOffset(Vector2i((int)(Renderer::getScreenWidth() * 0.03), mScreenshot->getOffset().y + mScreenshot->getSize().y + 12)); + 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)); mDescription.setText(((GameData*)mList->getSelectedObject())->getDescription()); }else{ mScreenshot->setImage(""); @@ -373,6 +376,8 @@ void GuiGameList::update(int deltaTime) mTransitionAnimation.update(deltaTime); mList->update(deltaTime); + + mDescription.update(deltaTime); } void GuiGameList::doTransition(int dir) diff --git a/src/components/TextComponent.cpp b/src/components/TextComponent.cpp index 76312e80c..477a19417 100644 --- a/src/components/TextComponent.cpp +++ b/src/components/TextComponent.cpp @@ -2,12 +2,13 @@ #include "../Renderer.h" #include "../Log.h" -TextComponent::TextComponent(Window* window) : GuiComponent(window), mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true) +TextComponent::TextComponent(Window* window) : GuiComponent(window), + mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true), mAutoScrollDelay(0), mAutoScrollSpeed(0), mAutoScrollTimer(0) { } TextComponent::TextComponent(Window* window, const std::string& text, Font* font, Vector2i pos, Vector2u size) : GuiComponent(window), - mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true) + mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true), mAutoScrollDelay(0), mAutoScrollSpeed(0), mAutoScrollTimer(0) { setText(text); setFont(font); @@ -51,11 +52,20 @@ void TextComponent::setText(const std::string& text) if(mAutoCalcExtent) calculateExtent(); + + mScrollPos = Vector2d(0, 0); + mScrollDir = Vector2d(0, 0); + resetAutoScrollTimer(); +} + +Font* TextComponent::getFont() const +{ + return (mFont ? mFont : Renderer::getDefaultFont(Renderer::MEDIUM));; } void TextComponent::onRender() { - Font* font = (mFont ? mFont : Renderer::getDefaultFont(Renderer::MEDIUM)); + Font* font = getFont(); if(font == NULL) { LOG(LogError) << "TextComponent can't get a valid font!"; @@ -64,7 +74,7 @@ void TextComponent::onRender() Renderer::pushClipRect(getGlobalOffset(), getSize()); - Renderer::drawWrappedText(mText, 0, 0, mSize.x, mColor, font); + Renderer::drawWrappedText(mText, (int)-mScrollPos.x, (int)-mScrollPos.y, mSize.x, mColor, font); Renderer::popClipRect(); @@ -73,7 +83,7 @@ void TextComponent::onRender() void TextComponent::calculateExtent() { - Font* font = (mFont ? mFont : Renderer::getDefaultFont(Renderer::MEDIUM)); + Font* font = getFont(); if(font == NULL) { LOG(LogError) << "TextComponent can't get a valid font!"; @@ -82,3 +92,73 @@ void TextComponent::calculateExtent() 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); +} diff --git a/src/components/TextComponent.h b/src/components/TextComponent.h index 67a6f9b5d..a77a7ee5a 100644 --- a/src/components/TextComponent.h +++ b/src/components/TextComponent.h @@ -16,15 +16,29 @@ public: void setText(const std::string& text); void setColor(unsigned int color); - void onRender(); + 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; std::string mText; + + //scrolling + Vector2d mScrollPos; + Vector2d mScrollDir; + int mAutoScrollDelay; + double mAutoScrollSpeed; + int mAutoScrollTimer; }; #endif