mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-21 21:55:38 +00:00
Added initial TextComponent.
Reworked GuiGameList to use a TextComponent for description. Changed set/clearClipRect to push/popClipRect. Fixed Y coordinate in the clip rect functions. Sorta fixed AnimationComponent being totally out of whack with VSync off.
This commit is contained in:
parent
bf84945010
commit
861297ae25
|
@ -133,6 +133,7 @@ set(ES_HEADERS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextListComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ThemeComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiBox.h
|
||||
|
@ -167,6 +168,7 @@ set(ES_SOURCES
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ThemeComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiBox.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiDetectDevice.cpp
|
||||
|
|
|
@ -35,9 +35,9 @@ 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 pushClipRect(int x, int y, unsigned int w, unsigned int h);
|
||||
void pushClipRect(Vector2i offset, Vector2u size);
|
||||
void popClipRect();
|
||||
|
||||
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);
|
||||
|
|
|
@ -5,10 +5,13 @@
|
|||
#include "Font.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "Log.h"
|
||||
#include <stack>
|
||||
|
||||
namespace Renderer {
|
||||
bool loadedFonts = false;
|
||||
|
||||
std::stack<Rect> clipStack;
|
||||
|
||||
void setColor4bArray(GLubyte* array, unsigned int color)
|
||||
{
|
||||
array[0] = (color & 0xff000000) / 0x1000000;
|
||||
|
@ -36,20 +39,44 @@ namespace Renderer {
|
|||
translatef((float)offset.x, (float)offset.y);
|
||||
}
|
||||
|
||||
void setClipRect(int x, int y, unsigned int w, unsigned int h)
|
||||
void pushClipRect(int x, int y, unsigned int w, unsigned int h)
|
||||
{
|
||||
glScissor(x, y, w, h);
|
||||
Rect rect(x, y, w, h);
|
||||
if(rect.size.x == 0)
|
||||
rect.size.x = Renderer::getScreenWidth() - rect.pos.x;
|
||||
if(rect.size.y == 0)
|
||||
rect.size.y = Renderer::getScreenHeight() - rect.pos.y;
|
||||
|
||||
//glScissor starts at the bottom left of the window
|
||||
//so (0, 0, 1, 1) is the bottom left pixel
|
||||
//everything else uses y+ = down, so flip it to be consistent
|
||||
rect.pos.y = Renderer::getScreenHeight() - rect.pos.y - rect.size.y;
|
||||
|
||||
clipStack.push(rect);
|
||||
glScissor(rect.pos.x, rect.pos.y, rect.size.x, rect.size.y);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void setClipRect(Vector2i offset, Vector2u size)
|
||||
void pushClipRect(Vector2i pos, Vector2u size)
|
||||
{
|
||||
setClipRect(offset.x, offset.y, size.x, size.y);
|
||||
pushClipRect(pos.x, pos.y, size.x, size.y);
|
||||
}
|
||||
|
||||
void clearClipRect()
|
||||
void popClipRect()
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
if(clipStack.empty())
|
||||
{
|
||||
LOG(LogError) << "Tried to popClipRect while the stack was empty!";
|
||||
return;
|
||||
}
|
||||
clipStack.pop();
|
||||
if(clipStack.empty())
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}else{
|
||||
Rect top = clipStack.top();
|
||||
glScissor(top.pos.x, top.pos.y, top.size.x, top.size.y);
|
||||
}
|
||||
}
|
||||
|
||||
void drawRect(int x, int y, int w, int h, unsigned int color)
|
||||
|
|
|
@ -27,7 +27,6 @@ public:
|
|||
T y;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
Vector2<T> operator -(const Vector2<T>& right)
|
||||
{
|
||||
|
@ -95,4 +94,14 @@ typedef Vector2<int> Vector2i;
|
|||
typedef Vector2<unsigned int> Vector2u;
|
||||
typedef Vector2<float> Vector2f;
|
||||
|
||||
class Rect
|
||||
{
|
||||
public:
|
||||
Vector2i pos;
|
||||
Vector2u size;
|
||||
|
||||
Rect() {};
|
||||
Rect(int x, int y, unsigned int w, unsigned int h) : pos(x, y), size(w, h) {};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,8 @@ AnimationComponent::AnimationComponent()
|
|||
mMoveY = 0;
|
||||
mMoveSpeed = 0;
|
||||
mFadeRate = 0;
|
||||
mOpacity = 0;
|
||||
mAccumulator = 0;
|
||||
}
|
||||
|
||||
void AnimationComponent::move(int x, int y, int speed)
|
||||
|
@ -31,41 +33,46 @@ void AnimationComponent::fadeOut(int time)
|
|||
mFadeRate = -time;
|
||||
}
|
||||
|
||||
//this should really be fixed at the system loop level...
|
||||
void AnimationComponent::update(int deltaTime)
|
||||
{
|
||||
float mult = deltaTime * 0.05f;
|
||||
|
||||
if(mMoveX != 0 || mMoveY != 0)
|
||||
mAccumulator += deltaTime;
|
||||
while(mAccumulator >= ANIMATION_TICK_SPEED)
|
||||
{
|
||||
int offsetx = (mMoveX > mMoveSpeed) ? mMoveSpeed : mMoveX;
|
||||
int offsety = (mMoveY > mMoveSpeed) ? mMoveSpeed : mMoveY;
|
||||
mAccumulator -= ANIMATION_TICK_SPEED;
|
||||
|
||||
offsetx = (int)(offsetx * mult);
|
||||
offsety = (int)(offsety * mult);
|
||||
|
||||
moveChildren(offsetx, offsety);
|
||||
|
||||
mMoveX -= offsetx;
|
||||
mMoveY -= offsety;
|
||||
}
|
||||
|
||||
if(mFadeRate != 0)
|
||||
{
|
||||
int opacity = (int)mOpacity + mFadeRate;
|
||||
if(opacity > 255)
|
||||
if(mMoveX != 0 || mMoveY != 0)
|
||||
{
|
||||
mFadeRate = 0;
|
||||
opacity = 255;
|
||||
Vector2i offset(mMoveX, mMoveY);
|
||||
if(abs(offset.x) > mMoveSpeed)
|
||||
offset.x = mMoveSpeed * (offset.x > 0 ? 1 : -1);
|
||||
if(abs(offset.y) > mMoveSpeed)
|
||||
offset.y = mMoveSpeed * (offset.y > 0 ? 1 : -1);
|
||||
|
||||
moveChildren(offset.x, offset.y);
|
||||
|
||||
mMoveX -= offset.x;
|
||||
mMoveY -= offset.y;
|
||||
}
|
||||
|
||||
if(opacity < 0)
|
||||
if(mFadeRate != 0)
|
||||
{
|
||||
mFadeRate = 0;
|
||||
opacity = 0;
|
||||
}
|
||||
int opacity = (int)mOpacity + mFadeRate;
|
||||
if(opacity > 255)
|
||||
{
|
||||
mFadeRate = 0;
|
||||
opacity = 255;
|
||||
}
|
||||
|
||||
mOpacity = (unsigned char)opacity;
|
||||
setChildrenOpacity((unsigned char)opacity);
|
||||
if(opacity < 0)
|
||||
{
|
||||
mFadeRate = 0;
|
||||
opacity = 0;
|
||||
}
|
||||
|
||||
mOpacity = (unsigned char)opacity;
|
||||
setChildrenOpacity((unsigned char)opacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "ImageComponent.h"
|
||||
#include <vector>
|
||||
|
||||
#define ANIMATION_TICK_SPEED 16
|
||||
|
||||
class AnimationComponent
|
||||
{
|
||||
public:
|
||||
|
@ -28,6 +30,8 @@ private:
|
|||
|
||||
int mFadeRate;
|
||||
int mMoveX, mMoveY, mMoveSpeed;
|
||||
|
||||
int mAccumulator;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,7 +6,12 @@
|
|||
#include <boost/filesystem.hpp>
|
||||
#include "../Log.h"
|
||||
|
||||
GuiGameList::GuiGameList(Window* window, bool useDetail) : GuiComponent(window)
|
||||
Vector2i GuiGameList::getImagePos()
|
||||
{
|
||||
return Vector2i((int)(Renderer::getScreenWidth() * mTheme->getFloat("gameImageOffsetX")), (int)(Renderer::getScreenHeight() * mTheme->getFloat("gameImageOffsetY")));
|
||||
}
|
||||
|
||||
GuiGameList::GuiGameList(Window* window, bool useDetail) : GuiComponent(window), mDescription(window)
|
||||
{
|
||||
mDetailed = useDetail;
|
||||
|
||||
|
@ -19,7 +24,7 @@ GuiGameList::GuiGameList(Window* window, bool useDetail) : GuiComponent(window)
|
|||
{
|
||||
mList = new TextListComponent<FileData*>(mWindow, (int)(Renderer::getScreenWidth() * mTheme->getFloat("listOffsetX")), Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2, Renderer::getDefaultFont(Renderer::MEDIUM));
|
||||
|
||||
mScreenshot = new ImageComponent(mWindow, (int)(Renderer::getScreenWidth() * mTheme->getFloat("gameImageOffsetX")), (int)(Renderer::getScreenHeight() * mTheme->getFloat("gameImageOffsetY")), "", (unsigned int)mTheme->getFloat("gameImageWidth"), (unsigned int)mTheme->getFloat("gameImageHeight"), false);
|
||||
mScreenshot = new ImageComponent(mWindow, getImagePos().x, getImagePos().y, "", (unsigned int)mTheme->getFloat("gameImageWidth"), (unsigned int)mTheme->getFloat("gameImageHeight"), false);
|
||||
mScreenshot->setOrigin(mTheme->getFloat("gameImageOriginX"), mTheme->getFloat("gameImageOriginY"));
|
||||
|
||||
mImageAnimation = new AnimationComponent();
|
||||
|
@ -30,6 +35,9 @@ GuiGameList::GuiGameList(Window* window, bool useDetail) : GuiComponent(window)
|
|||
mImageAnimation = NULL;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
setSystemId(0);
|
||||
}
|
||||
|
||||
|
@ -41,8 +49,9 @@ GuiGameList::~GuiGameList()
|
|||
{
|
||||
delete mImageAnimation;
|
||||
delete mScreenshot;
|
||||
delete mTheme;
|
||||
}
|
||||
|
||||
delete mTheme;
|
||||
}
|
||||
|
||||
void GuiGameList::setSystemId(int id)
|
||||
|
@ -86,18 +95,14 @@ void GuiGameList::render()
|
|||
//divider
|
||||
if(!mTheme->getBool("hideDividers"))
|
||||
Renderer::drawRect((int)(Renderer::getScreenWidth() * mTheme->getFloat("listOffsetX")) - 4, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2, 8, Renderer::getScreenHeight(), 0x0000FFFF);
|
||||
|
||||
//if we're not scrolling and we have selected a non-folder
|
||||
if(!mList->isScrolling() && mList->getSelectedObject() && !mList->getSelectedObject()->isFolder())
|
||||
{
|
||||
GameData* game = (GameData*)mList->getSelectedObject();
|
||||
|
||||
std::string desc = game->getDescription();
|
||||
if(!desc.empty())
|
||||
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();
|
||||
|
||||
//if we're not scrolling and we have selected a non-folder
|
||||
if(!mList->isScrolling() && !mList->getSelectedObject()->isFolder())
|
||||
{
|
||||
mDescription.render();
|
||||
}
|
||||
}
|
||||
|
||||
mList->render();
|
||||
|
@ -118,6 +123,7 @@ bool GuiGameList::input(InputConfig* config, Input input)
|
|||
mFolderStack.push(mFolder);
|
||||
mFolder = (FolderData*)file;
|
||||
updateList();
|
||||
updateDetailData();
|
||||
return true;
|
||||
}else{
|
||||
mList->stopScrolling();
|
||||
|
@ -251,6 +257,9 @@ void GuiGameList::updateTheme()
|
|||
mScreenshot->setOffset((int)(mTheme->getFloat("gameImageOffsetX") * Renderer::getScreenWidth()), (int)(mTheme->getFloat("gameImageOffsetY") * Renderer::getScreenHeight()));
|
||||
mScreenshot->setOrigin(mTheme->getFloat("gameImageOriginX"), mTheme->getFloat("gameImageOriginY"));
|
||||
mScreenshot->setResize((int)mTheme->getFloat("gameImageWidth"), (int)mTheme->getFloat("gameImageHeight"), false);
|
||||
|
||||
mDescription.setColor(mTheme->getColor("description"));
|
||||
mDescription.setFont(mTheme->getDescriptionFont());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,15 +270,19 @@ void GuiGameList::updateDetailData()
|
|||
|
||||
if(mList->getSelectedObject() && !mList->getSelectedObject()->isFolder())
|
||||
{
|
||||
mScreenshot->setOffset((int)((mTheme->getFloat("gameImageOffsetX") - 0.05) * Renderer::getScreenWidth()), (int)(mTheme->getFloat("gameImageOffsetY") * Renderer::getScreenHeight()));
|
||||
|
||||
if(((GameData*)mList->getSelectedObject())->getImagePath().empty())
|
||||
mScreenshot->setImage(mTheme->getString("imageNotFoundPath"));
|
||||
else
|
||||
mScreenshot->setImage(((GameData*)mList->getSelectedObject())->getImagePath());
|
||||
|
||||
mImageAnimation->fadeIn(15);
|
||||
mImageAnimation->move((int)(0.05 * Renderer::getScreenWidth()), 0, 5);
|
||||
Vector2i imgOffset = Vector2i((int)(Renderer::getScreenWidth() * 0.10f), 0);
|
||||
mScreenshot->setOffset(getImagePos() - imgOffset);
|
||||
|
||||
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.setText(((GameData*)mList->getSelectedObject())->getDescription());
|
||||
}else{
|
||||
mScreenshot->setImage("");
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "ImageComponent.h"
|
||||
#include "ThemeComponent.h"
|
||||
#include "AnimationComponent.h"
|
||||
#include "TextComponent.h"
|
||||
#include <string>
|
||||
#include <stack>
|
||||
#include "../SystemData.h"
|
||||
|
@ -13,7 +14,7 @@
|
|||
#include "../FolderData.h"
|
||||
|
||||
//This is where the magic happens - GuiGameList is the parent of almost every graphical element in ES at the moment.
|
||||
//It has a GuiList child that handles the game list, a GuiTheme that handles the theming system, and a GuiImage 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.
|
||||
class GuiGameList : public GuiComponent
|
||||
{
|
||||
public:
|
||||
|
@ -48,8 +49,11 @@ private:
|
|||
|
||||
TextListComponent<FileData*>* mList;
|
||||
ImageComponent* mScreenshot;
|
||||
TextComponent mDescription;
|
||||
AnimationComponent* mImageAnimation;
|
||||
ThemeComponent* mTheme;
|
||||
|
||||
Vector2i getImagePos();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
59
src/components/TextComponent.cpp
Normal file
59
src/components/TextComponent.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include "TextComponent.h"
|
||||
#include "../Renderer.h"
|
||||
#include "../Log.h"
|
||||
|
||||
TextComponent::TextComponent(Window* window) : GuiComponent(window), mFont(NULL), mColor(0x000000FF)
|
||||
{
|
||||
}
|
||||
|
||||
TextComponent::TextComponent(Window* window, const std::string& text, Font* font, Vector2i pos, Vector2u size) : GuiComponent(window),
|
||||
mFont(NULL), mColor(0x000000FF)
|
||||
{
|
||||
setText(text);
|
||||
setFont(font);
|
||||
setBox(pos, size);
|
||||
}
|
||||
|
||||
void TextComponent::setBox(Vector2i pos, Vector2u size)
|
||||
{
|
||||
setOffset(pos);
|
||||
setExtent(size);
|
||||
}
|
||||
|
||||
void TextComponent::setExtent(Vector2u size)
|
||||
{
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
void TextComponent::setFont(Font* font)
|
||||
{
|
||||
mFont = font;
|
||||
}
|
||||
|
||||
void TextComponent::setColor(unsigned int color)
|
||||
{
|
||||
mColor = color;
|
||||
}
|
||||
|
||||
void TextComponent::setText(const std::string& text)
|
||||
{
|
||||
mText = text;
|
||||
}
|
||||
|
||||
void TextComponent::onRender()
|
||||
{
|
||||
Font* font = (mFont ? mFont : Renderer::getDefaultFont(Renderer::MEDIUM));
|
||||
if(font == NULL)
|
||||
{
|
||||
LOG(LogError) << "TextComponent can't get a valid font!";
|
||||
return;
|
||||
}
|
||||
|
||||
Renderer::pushClipRect(getOffset(), getSize());
|
||||
|
||||
Renderer::drawWrappedText(mText, 0, 0, mSize.x, mColor, font);
|
||||
|
||||
Renderer::popClipRect();
|
||||
|
||||
GuiComponent::onRender();
|
||||
}
|
27
src/components/TextComponent.h
Normal file
27
src/components/TextComponent.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef _TEXTCOMPONENT_H_
|
||||
#define _TEXTCOMPONENT_H_
|
||||
|
||||
#include "../GuiComponent.h"
|
||||
#include "../Font.h"
|
||||
|
||||
class TextComponent : public GuiComponent
|
||||
{
|
||||
public:
|
||||
TextComponent(Window* window);
|
||||
TextComponent(Window* window, const std::string& text, Font* font, Vector2i pos, Vector2u size);
|
||||
|
||||
void setFont(Font* font);
|
||||
void setBox(Vector2i pos, Vector2u size);
|
||||
void setExtent(Vector2u size);
|
||||
void setText(const std::string& text);
|
||||
void setColor(unsigned int color);
|
||||
|
||||
void onRender();
|
||||
|
||||
private:
|
||||
unsigned int mColor;
|
||||
Font* mFont;
|
||||
std::string mText;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -141,6 +141,8 @@ void TextListComponent<T>::onRender()
|
|||
if(listCutoff > (int)mRowVector.size())
|
||||
listCutoff = mRowVector.size();
|
||||
|
||||
Renderer::pushClipRect(getOffset(), getSize());
|
||||
|
||||
for(int i = startEntry; i < listCutoff; i++)
|
||||
{
|
||||
//draw selector bar
|
||||
|
@ -154,18 +156,16 @@ void TextListComponent<T>::onRender()
|
|||
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, x, y, color, mFont);
|
||||
else
|
||||
Renderer::drawText(row.name, x, y, color, mFont);
|
||||
|
||||
Renderer::clearClipRect();
|
||||
|
||||
y += entrySize;
|
||||
}
|
||||
|
||||
Renderer::popClipRect();
|
||||
|
||||
GuiComponent::onRender();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue