diff --git a/src/GuiComponent.cpp b/src/GuiComponent.cpp index 0ad40bbed..eef473de7 100644 --- a/src/GuiComponent.cpp +++ b/src/GuiComponent.cpp @@ -92,6 +92,11 @@ void GuiComponent::setOffset(int x, int y) mOffset.y = y; } +Vector2u GuiComponent::getSize() +{ + return mSize; +} + //Children stuff. void GuiComponent::addChild(GuiComponent* cmp) { diff --git a/src/GuiComponent.h b/src/GuiComponent.h index 5ab217295..14ae66868 100644 --- a/src/GuiComponent.h +++ b/src/GuiComponent.h @@ -20,7 +20,7 @@ public: virtual void update(int deltaTime); //Called when it's time to render. Translates the OpenGL matrix, calls onRender() (which renders children), then un-translates the OpenGL matrix. - //You probably don't need to override this, but instead want the protected method onRender. + //You probably don't need to override this, and should use the protected method onRender. virtual void render(); //Called when the Renderer initializes. Passes to children. @@ -34,6 +34,8 @@ public: void setOffset(Vector2i offset); void setOffset(int x, int y); + Vector2u getSize(); + void setParent(GuiComponent* parent); GuiComponent* getParent(); @@ -50,6 +52,7 @@ protected: Window* mWindow; GuiComponent* mParent; Vector2i mOffset; + Vector2u mSize; std::vector mChildren; }; diff --git a/src/Renderer.h b/src/Renderer.h index c75294256..f73f2939a 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -35,6 +35,10 @@ namespace Renderer void translatef(float x, float y); void translate(Vector2i offset); + void setClipRect(int x, int y, unsigned int w, unsigned int h); + void setClipRect(Vector2i offset, Vector2u size); + void clearClipRect(); + void drawRect(int x, int y, int w, int h, unsigned int color); 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); diff --git a/src/Renderer_draw_gl.cpp b/src/Renderer_draw_gl.cpp index 9b7120e64..d583bf2e4 100644 --- a/src/Renderer_draw_gl.cpp +++ b/src/Renderer_draw_gl.cpp @@ -36,6 +36,22 @@ namespace Renderer { translatef((float)offset.x, (float)offset.y); } + void setClipRect(int x, int y, unsigned int w, unsigned int h) + { + glScissor(x, y, w, h); + glEnable(GL_SCISSOR_TEST); + } + + void setClipRect(Vector2i offset, Vector2u size) + { + setClipRect(offset.x, offset.y, size.x, size.y); + } + + void clearClipRect() + { + glDisable(GL_SCISSOR_TEST); + } + void drawRect(int x, int y, int w, int h, unsigned int color) { #ifdef USE_OPENGL_ES diff --git a/src/Vector2.h b/src/Vector2.h index 925115eef..08e8b85b6 100644 --- a/src/Vector2.h +++ b/src/Vector2.h @@ -92,6 +92,7 @@ bool operator !=(const Vector2& left, const Vector2& right) } typedef Vector2 Vector2i; +typedef Vector2 Vector2u; typedef Vector2 Vector2f; #endif diff --git a/src/components/GuiBox.cpp b/src/components/GuiBox.cpp index 84d163b0f..3db364d88 100644 --- a/src/components/GuiBox.cpp +++ b/src/components/GuiBox.cpp @@ -5,8 +5,7 @@ GuiBox::GuiBox(Window* window, int offsetX, int offsetY, unsigned int width, uns { setOffset(Vector2i(offsetX, offsetY)); - mWidth = width; - mHeight = height; + mSize = Vector2u(width, height); } void GuiBox::setData(GuiBoxData data) @@ -23,7 +22,7 @@ void GuiBox::setHorizontalImage(std::string path, bool tiled) mHorizontalImage.setOrigin(0, 0); mHorizontalImage.setImage(path); - mHorizontalImage.setResize(mHorizontalImage.getHeight(), mHeight, true); + mHorizontalImage.setResize(getHorizontalBorderWidth(), mSize.y, true); } void GuiBox::setVerticalImage(std::string path, bool tiled) @@ -32,15 +31,15 @@ void GuiBox::setVerticalImage(std::string path, bool tiled) mVerticalImage.setOrigin(0, 0); mVerticalImage.setImage(path); - mVerticalImage.setResize(mWidth, mVerticalImage.getHeight(), true); + mVerticalImage.setResize(mSize.x, getVerticalBorderWidth(), true); } void GuiBox::setBackgroundImage(std::string path, bool tiled) { mBackgroundImage.setOrigin(0, 0); - mBackgroundImage.setResize(mWidth, mHeight, true); + mBackgroundImage.setResize(mSize.x, mSize.y, true); mBackgroundImage.setTiling(tiled); - mBackgroundImage.setOffset(getOffset()); + mBackgroundImage.setOffset(0, 0); mBackgroundImage.setImage(path); } @@ -53,51 +52,53 @@ void GuiBox::setCornerImage(std::string path) mCornerImage.setImage(path); } -void GuiBox::render() +void GuiBox::onRender() { mBackgroundImage.render(); //left border - mHorizontalImage.setOffset(getOffset().x - getHorizontalBorderWidth(), getOffset().y); + mHorizontalImage.setOffset(-getHorizontalBorderWidth(), 0); mHorizontalImage.setFlipX(false); mHorizontalImage.render(); //right border - mHorizontalImage.setOffset(getOffset().x + mWidth, getOffset().y); + mHorizontalImage.setOffset(mSize.x, 0); mHorizontalImage.setFlipX(true); mHorizontalImage.render(); //top border - mVerticalImage.setOffset(getOffset().x, getOffset().y - getVerticalBorderWidth()); + mVerticalImage.setOffset(0, -getVerticalBorderWidth()); mVerticalImage.setFlipY(false); mVerticalImage.render(); //bottom border - mVerticalImage.setOffset(getOffset().x, getOffset().y + mHeight); + mVerticalImage.setOffset(0, mSize.y); mVerticalImage.setFlipY(true); mVerticalImage.render(); //corner top left - mCornerImage.setOffset(getOffset().x - getHorizontalBorderWidth(), getOffset().y - getVerticalBorderWidth()); + mCornerImage.setOffset(-getHorizontalBorderWidth(), -getVerticalBorderWidth()); mCornerImage.setFlipX(false); mCornerImage.setFlipY(false); mCornerImage.render(); //top right - mCornerImage.setOffset(getOffset().x + mWidth, mCornerImage.getOffset().y); + mCornerImage.setOffset(mSize.x, mCornerImage.getOffset().y); mCornerImage.setFlipX(true); mCornerImage.render(); //bottom right - mCornerImage.setOffset(mCornerImage.getOffset().x, getOffset().y + mHeight); + mCornerImage.setOffset(mCornerImage.getOffset().x, mSize.y); mCornerImage.setFlipY(true); mCornerImage.render(); //bottom left - mCornerImage.setOffset(getOffset().x - getHorizontalBorderWidth(), mCornerImage.getOffset().y); + mCornerImage.setOffset(-getHorizontalBorderWidth(), mCornerImage.getOffset().y); mCornerImage.setFlipX(false); mCornerImage.render(); + + GuiComponent::onRender(); } void GuiBox::init() @@ -105,6 +106,8 @@ void GuiBox::init() mVerticalImage.init(); mHorizontalImage.init(); mCornerImage.init(); + + GuiComponent::init(); } void GuiBox::deinit() @@ -112,16 +115,18 @@ void GuiBox::deinit() mVerticalImage.deinit(); mHorizontalImage.deinit(); mCornerImage.deinit(); + + GuiComponent::deinit(); } int GuiBox::getHorizontalBorderWidth() { - return mHorizontalImage.getWidth(); + return mHorizontalImage.getTextureSize().x; } int GuiBox::getVerticalBorderWidth() { - return mVerticalImage.getHeight(); + return mVerticalImage.getTextureSize().y; } bool GuiBox::hasBackground() diff --git a/src/components/GuiBox.h b/src/components/GuiBox.h index 6308f33da..ad1325e5c 100644 --- a/src/components/GuiBox.h +++ b/src/components/GuiBox.h @@ -30,18 +30,17 @@ public: bool hasBackground(); - void render(); - void init(); void deinit(); +protected: + void onRender(); + private: ImageComponent mBackgroundImage, mHorizontalImage, mVerticalImage, mCornerImage; int getHorizontalBorderWidth(); int getVerticalBorderWidth(); - - unsigned int mWidth, mHeight; }; #endif diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index 17f655eeb..4b605f73e 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -94,7 +94,7 @@ void GuiGameList::render() std::string desc = game->getDescription(); if(!desc.empty()) - Renderer::drawWrappedText(desc, (int)(Renderer::getScreenWidth() * 0.03), mScreenshot->getOffset().y + mScreenshot->getHeight() + 12, (int)(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03)), mTheme->getColor("description"), mTheme->getDescriptionFont()); + Renderer::drawWrappedText(desc, (int)(Renderer::getScreenWidth() * 0.03), mScreenshot->getOffset().y + mScreenshot->getSize().y + 12, (int)(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03)), mTheme->getColor("description"), mTheme->getDescriptionFont()); } mScreenshot->render(); diff --git a/src/components/ImageComponent.cpp b/src/components/ImageComponent.cpp index 4f8ad075c..6edca1092 100644 --- a/src/components/ImageComponent.cpp +++ b/src/components/ImageComponent.cpp @@ -5,8 +5,7 @@ #include "../Log.h" #include "../Renderer.h" -unsigned int ImageComponent::getWidth() { return mSize.x; } -unsigned int ImageComponent::getHeight() { return mSize.y; } +Vector2u ImageComponent::getTextureSize() { return mTextureSize; } ImageComponent::ImageComponent(Window* window, int offsetX, int offsetY, std::string path, unsigned int resizeWidth, unsigned int resizeHeight, bool allowUpscale) : GuiComponent(window) { @@ -175,6 +174,11 @@ void ImageComponent::resize() if(resizeScale.y) mSize.y = (int)(mSize.y * resizeScale.y); } + + if(mTiled) + { + mSize = mTargetSize; + } } void ImageComponent::unloadImage() @@ -212,6 +216,8 @@ void ImageComponent::setTiling(bool tile) if(mTiled) mAllowUpscale = false; + + resize(); } void ImageComponent::setResize(unsigned int width, unsigned int height, bool allowUpscale) @@ -241,8 +247,8 @@ void ImageComponent::onRender() if(mTiled) { - float xCount = (float)mTargetSize.x / mTextureSize.x; - float yCount = (float)mTargetSize.y / mTextureSize.y; + float xCount = (float)mSize.x / mTextureSize.x; + float yCount = (float)mSize.y / mTextureSize.y; Renderer::buildGLColorArray(colors, 0xFFFFFF00 | (getOpacity()), 6); buildImageArray(0, 0, points, texs, xCount, yCount); @@ -259,13 +265,13 @@ void ImageComponent::onRender() void ImageComponent::buildImageArray(int posX, int posY, GLfloat* points, GLfloat* texs, float px, float py) { - points[0] = posX - (mSize.x * mOrigin.x) * px; points[1] = posY - (mSize.y * mOrigin.y) * py; - points[2] = posX - (mSize.x * mOrigin.x) * px; points[3] = posY + (mSize.y * (1 - mOrigin.y)) * py; - points[4] = posX + (mSize.x * (1 - mOrigin.x)) * px; points[5] = posY - (mSize.y * mOrigin.y) * py; + points[0] = posX - (mSize.x * mOrigin.x); points[1] = posY - (mSize.y * mOrigin.y); + points[2] = posX - (mSize.x * mOrigin.x); points[3] = posY + (mSize.y * (1 - mOrigin.y)); + points[4] = posX + (mSize.x * (1 - mOrigin.x)); points[5] = posY - (mSize.y * mOrigin.y); - points[6] = posX + (mSize.x * (1 - mOrigin.x)) * px; points[7] = posY - (mSize.y * mOrigin.y) * py; - points[8] = posX - (mSize.x * mOrigin.x) * px; points[9] = posY + (mSize.y * (1 - mOrigin.y)) * py; - points[10] = posX + (mSize.x * (1 -mOrigin.x)) * px; points[11] = posY + (mSize.y * (1 - mOrigin.y)) * py; + points[6] = posX + (mSize.x * (1 - mOrigin.x)); points[7] = posY - (mSize.y * mOrigin.y); + points[8] = posX - (mSize.x * mOrigin.x); points[9] = posY + (mSize.y * (1 - mOrigin.y)); + points[10] = posX + (mSize.x * (1 -mOrigin.x)); points[11] = posY + (mSize.y * (1 - mOrigin.y)); diff --git a/src/components/ImageComponent.h b/src/components/ImageComponent.h index dab89128d..cef220dae 100644 --- a/src/components/ImageComponent.h +++ b/src/components/ImageComponent.h @@ -26,8 +26,9 @@ public: void setFlipX(bool flip); void setFlipY(bool flip); - unsigned int getWidth(); //Returns render width in pixels. May be different than actual texture width. - unsigned int getHeight(); //Returns render height in pixels. May be different than actual texture height. + //You can get the rendered size of the ImageComponent with getSize(). + Vector2u getTextureSize(); + bool hasImage(); @@ -42,9 +43,8 @@ protected: void onRender(); private: - Vector2 mSize; - Vector2 mTargetSize; - Vector2 mTextureSize; + Vector2u mTargetSize; + Vector2u mTextureSize; Vector2f mOrigin; bool mAllowUpscale, mTiled, mFlipX, mFlipY; diff --git a/src/components/TextListComponent.h b/src/components/TextListComponent.h index 9999cfae6..a60b008e9 100644 --- a/src/components/TextListComponent.h +++ b/src/components/TextListComponent.h @@ -10,8 +10,12 @@ #include #include "../Sound.h" +#define MARQUEE_DELAY 600 +#define MARQUEE_SPEED 16 +#define MARQUEE_RATE 3 + //A graphical list. Supports multiple colors for rows and scrolling. -//TODO - add truncation to text rendering if name exceeds a maximum width (a trailing elipses, perhaps). +//TODO - add truncation to text rendering if name exceeds a maximum width (a trailing elipses, perhaps). Marquee would be nice too. template class TextListComponent : public GuiComponent { @@ -51,10 +55,14 @@ private: static const int SCROLLTIME = 200; void scroll(); //helper method, scrolls in whatever direction scrollDir is + void setScrollDir(int val); //helper method, set mScrollDir as well as reset marquee stuff int mScrollDir, mScrollAccumulator; bool mScrolling; + int mMarqueeOffset; + int mMarqueeTime; + Font* mFont; unsigned int mSelectorColor, mSelectedTextColorOverride; bool mDrawCentered; @@ -83,6 +91,9 @@ TextListComponent::TextListComponent(Window* window, int offsetX, int offsetY setOffset(Vector2i(offsetX, offsetY)); + mSize = Vector2u(Renderer::getScreenWidth() - getOffset().x, Renderer::getScreenHeight() - getOffset().y); + mMarqueeOffset = 0; + mMarqueeTime = -MARQUEE_DELAY; mTextOffsetX = 0; mFont = font; @@ -140,10 +151,17 @@ void TextListComponent::onRender() ListRow row = mRowVector.at((unsigned int)i); + int x = mTextOffsetX - (mSelection == i ? mMarqueeOffset : 0); + unsigned int color = (mSelection == i && mSelectedTextColorOverride != 0) ? mSelectedTextColorOverride : row.color; + + Renderer::setClipRect(getOffset(), getSize()); + if(mDrawCentered) - Renderer::drawCenteredText(row.name, mTextOffsetX, y, (mSelection == i && mSelectedTextColorOverride != 0) ? mSelectedTextColorOverride : row.color, mFont); + Renderer::drawCenteredText(row.name, x, y, color, mFont); else - Renderer::drawText(row.name, mTextOffsetX, y, (mSelection == i && mSelectedTextColorOverride != 0) ? mSelectedTextColorOverride : row.color, mFont); + Renderer::drawText(row.name, x, y, color, mFont); + + Renderer::clearClipRect(); y += entrySize; } @@ -160,27 +178,27 @@ bool TextListComponent::input(InputConfig* config, Input input) { if(config->isMappedTo("down", input)) { - mScrollDir = 1; + setScrollDir(1); scroll(); return true; } if(config->isMappedTo("up", input)) { - mScrollDir = -1; + setScrollDir(-1); scroll(); return true; } if(config->isMappedTo("pagedown", input)) { - mScrollDir = 10; + setScrollDir(10); scroll(); return true; } if(config->isMappedTo("pageup", input)) { - mScrollDir = -10; + setScrollDir(-10); scroll(); return true; } @@ -196,6 +214,14 @@ bool TextListComponent::input(InputConfig* config, Input input) return GuiComponent::input(config, input); } +template +void TextListComponent::setScrollDir(int val) +{ + mScrollDir = val; + mMarqueeOffset = 0; + mMarqueeTime = -MARQUEE_DELAY; +} + template void TextListComponent::stopScrolling() { @@ -231,6 +257,22 @@ void TextListComponent::update(int deltaTime) scroll(); } } + }else{ + //if we're not scrolling and this object's text goes outside our size, marquee it! + std::string text = getSelectedName(); + int w; + mFont->sizeText(text, &w, NULL); + + //it's long enough to marquee + if(w - mMarqueeOffset > (int)getSize().x - 12) + { + mMarqueeTime += deltaTime; + while(mMarqueeTime > MARQUEE_SPEED) + { + mMarqueeOffset += MARQUEE_RATE; + mMarqueeTime -= MARQUEE_SPEED; + } + } } GuiComponent::update(deltaTime);