Move scrolling out of TextComponent and into a generic

ScrollableContainer.
This commit is contained in:
Aloshi 2013-07-02 20:01:58 -05:00
parent df78b5352d
commit ed384e057b
8 changed files with 178 additions and 114 deletions

View file

@ -135,6 +135,7 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.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/SliderComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.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/AnimationComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.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/SliderComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.cpp

View file

@ -254,6 +254,7 @@ namespace Renderer {
void sizeWrappedText(std::string text, int xLen, Font* font, int* xOut, int* yOut) void sizeWrappedText(std::string text, int xLen, Font* font, int* xOut, int* yOut)
{ {
if(xOut != NULL)
*xOut = xLen; *xOut = xLen;
int y = 0; int y = 0;
@ -306,6 +307,7 @@ namespace Renderer {
} }
if(yOut != NULL)
*yOut = y; *yOut = y;
} }

View file

@ -25,13 +25,15 @@ GuiGameList::GuiGameList(Window* window) : GuiComponent(window),
mList(window, 0, 0, Renderer::getDefaultFont(Renderer::MEDIUM)), mList(window, 0, 0, Renderer::getDefaultFont(Renderer::MEDIUM)),
mScreenshot(window), mScreenshot(window),
mDescription(window), mDescription(window),
mDescContainer(window),
mTransitionImage(window, 0, 0, "", Renderer::getScreenWidth(), Renderer::getScreenHeight(), true) mTransitionImage(window, 0, 0, "", Renderer::getScreenWidth(), Renderer::getScreenHeight(), true)
{ {
mImageAnimation.addChild(&mScreenshot); mImageAnimation.addChild(&mScreenshot);
mDescContainer.addChild(&mDescription);
//scale delay with screen width (higher width = more text per line) //scale delay with screen width (higher width = more text per line)
//the scroll speed is automatically scaled by component size //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.setOffset(Renderer::getScreenWidth(), 0);
mTransitionImage.setOrigin(0, 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); Renderer::drawRect((int)(Renderer::getScreenWidth() * mTheme->getFloat("listOffsetX")) - 4, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2, 8, Renderer::getScreenHeight(), 0x0000FFFF);
mScreenshot.render(); mScreenshot.render();
mDescription.render(); mDescContainer.render();
} }
mList.render(); mList.render();
@ -290,8 +292,13 @@ void GuiGameList::updateDetailData()
mImageAnimation.fadeIn(35); mImageAnimation.fadeIn(35);
mImageAnimation.move(imgOffset.x, imgOffset.y, 20); mImageAnimation.move(imgOffset.x, imgOffset.y, 20);
mDescription.setOffset(Vector2i((int)(Renderer::getScreenWidth() * 0.03), getImagePos().y + mScreenshot.getSize().y + 12)); mDescContainer.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.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()); mDescription.setText(((GameData*)mList.getSelectedObject())->getDescription());
}else{ }else{
mScreenshot.setImage(""); mScreenshot.setImage("");
@ -340,7 +347,7 @@ void GuiGameList::update(int deltaTime)
mList.update(deltaTime); mList.update(deltaTime);
mDescription.update(deltaTime); mDescContainer.update(deltaTime);
} }
void GuiGameList::doTransition(int dir) void GuiGameList::doTransition(int dir)

View file

@ -12,6 +12,7 @@
#include "../SystemData.h" #include "../SystemData.h"
#include "../GameData.h" #include "../GameData.h"
#include "../FolderData.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. //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. //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<FileData*> mList; TextListComponent<FileData*> mList;
ImageComponent mScreenshot; ImageComponent mScreenshot;
TextComponent mDescription; TextComponent mDescription;
ScrollableContainer mDescContainer;
AnimationComponent mImageAnimation; AnimationComponent mImageAnimation;
ThemeComponent* mTheme; ThemeComponent* mTheme;

View file

@ -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;
}

View file

@ -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;
};

View file

@ -3,12 +3,12 @@
#include "../Log.h" #include "../Log.h"
TextComponent::TextComponent(Window* window) : GuiComponent(window), 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), 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); setText(text);
setFont(font); setFont(font);
@ -23,21 +23,15 @@ void TextComponent::setBox(Vector2i pos, Vector2u size)
void TextComponent::setExtent(Vector2u size) void TextComponent::setExtent(Vector2u size)
{ {
if(size == Vector2u(0, 0))
{
mAutoCalcExtent = true;
calculateExtent();
}else{
mAutoCalcExtent = false;
mSize = size; mSize = size;
} mAutoCalcExtent = Vector2<bool>(size.x == 0, size.y == 0);
calculateExtent();
} }
void TextComponent::setFont(Font* font) void TextComponent::setFont(Font* font)
{ {
mFont = font; mFont = font;
if(mAutoCalcExtent)
calculateExtent(); calculateExtent();
} }
@ -50,12 +44,7 @@ void TextComponent::setText(const std::string& text)
{ {
mText = text; mText = text;
if(mAutoCalcExtent)
calculateExtent(); calculateExtent();
mScrollPos = Vector2d(0, 0);
mScrollDir = Vector2d(0, 0);
resetAutoScrollTimer();
} }
Font* TextComponent::getFont() const Font* TextComponent::getFont() const
@ -72,11 +61,11 @@ void TextComponent::onRender()
return; 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(); GuiComponent::onRender();
} }
@ -90,75 +79,9 @@ void TextComponent::calculateExtent()
return; return;
} }
if(mAutoCalcExtent.x)
font->sizeText(mText, (int*)&mSize.x, (int*)&mSize.y); font->sizeText(mText, (int*)&mSize.x, (int*)&mSize.y);
} else
if(mAutoCalcExtent.y)
void TextComponent::setAutoScroll(int delay, double speed) Renderer::sizeWrappedText(mText, getSize().x, mFont, NULL, (int*)&mSize.y);
{
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);
} }

View file

@ -12,33 +12,21 @@ public:
void setFont(Font* font); void setFont(Font* font);
void setBox(Vector2i pos, Vector2u size); 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 setText(const std::string& text);
void setColor(unsigned int color); 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; void onRender() override;
private: private:
Font* getFont() const; Font* getFont() const;
void calculateExtent(); void calculateExtent();
unsigned int mColor; unsigned int mColor;
Font* mFont; Font* mFont;
bool mAutoCalcExtent; Vector2<bool> mAutoCalcExtent;
std::string mText; std::string mText;
//scrolling
Vector2d mScrollPos;
Vector2d mScrollDir;
int mAutoScrollDelay;
double mAutoScrollSpeed;
int mAutoScrollTimer;
}; };
#endif #endif