diff --git a/THEMES.md b/THEMES.md index 6264148a1..10749bab8 100644 --- a/THEMES.md +++ b/THEMES.md @@ -63,12 +63,17 @@ Display tags must be at the root of the tree - for example, they can't b `` - the hex color to use for the "selector bar" on the GuiGameList. -`` - if present, the games list names will be left aligned to $infoWidth. +`` - if present, the games list names will be left aligned to the value of `` (default 0.5). `` - if present, the system name header won't be displayed (useful for replacing it with an image). `` - if present, the divider between games on the detailed GuiGameList won't be displayed. +`` - the percentage to offset the list by. Default is 0.5 (half the screen). **Will also move the selector bar**. + +`` - the percentage to offset the text in the list by. Default is 0.005. Only works in combination with ``. + +`` - the percentage to offset the displayed game image by. Default is the height of the header font. List of variables ================= diff --git a/changelog.txt b/changelog.txt index ac2589ec2..85c620310 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +September 15 +-Added , , and theme tags. See THEMES.md for details. +-Fixed a bug causing gamelists to be read incorrectly. + September 14 -Joystick names are now saved during input configuration to es_input.cfg. -When loading an input config, if JOYNAME is defined, load the first joystick with that name. If it is not present, load the first joystick (old behavior). diff --git a/src/Font.cpp b/src/Font.cpp index df0889cf7..3beb0bcce 100644 --- a/src/Font.cpp +++ b/src/Font.cpp @@ -170,7 +170,6 @@ void Font::drawText(std::string text, int startx, int starty, int color) starty += mMaxGlyphHeight; //padding (another 0.5% is added to the bottom through the sizeText function) - //starty += Renderer::getScreenHeight() * 0.01; starty += mMaxGlyphHeight * 0.1; diff --git a/src/GuiComponent.cpp b/src/GuiComponent.cpp index 4f805d6ac..fbf0f19f4 100644 --- a/src/GuiComponent.cpp +++ b/src/GuiComponent.cpp @@ -7,6 +7,9 @@ std::vector GuiComponent::sComponentVector; GuiComponent::GuiComponent() { sComponentVector.push_back(this); + + mOffsetX = 0; + mOffsetY = 0; } GuiComponent::~GuiComponent() @@ -97,3 +100,8 @@ void GuiComponent::deinit() mChildren.at(i)->deinit(); } } + +void GuiComponent::setOffsetX(int val) { mOffsetX = val; } +void GuiComponent::setOffsetY(int val) { mOffsetY = val; } +int GuiComponent::getOffsetX() { return mOffsetX; } +int GuiComponent::getOffsetY() { return mOffsetY; } diff --git a/src/GuiComponent.h b/src/GuiComponent.h index dfaf77262..3d031abad 100644 --- a/src/GuiComponent.h +++ b/src/GuiComponent.h @@ -44,8 +44,16 @@ public: unsigned int getChildCount() { return mChildren.size(); } GuiComponent* getChild(unsigned int i) { return mChildren.at(i); } + + int getOffsetX(); + int getOffsetY(); + void setOffsetX(int val); + void setOffsetY(int val); + static void processTicks(int deltaTime); private: + int mOffsetX, mOffsetY; + static std::vector sComponentVector; std::vector mChildren; }; diff --git a/src/XMLReader.cpp b/src/XMLReader.cpp index 4e1874dc7..a0aff7352 100644 --- a/src/XMLReader.cpp +++ b/src/XMLReader.cpp @@ -49,8 +49,8 @@ GameData* createGameFromPath(std::string gameAbsPath, SystemData* system) //make our way through the directory tree finding each folder in our path or creating it if it doesn't exist FolderData* folder = system->getRootFolder(); - unsigned int separator = 0; - unsigned int nextSeparator = 0; + size_t separator = 0; + size_t nextSeparator = 0; unsigned int loops = 0; while(nextSeparator != std::string::npos) { @@ -83,7 +83,8 @@ GameData* createGameFromPath(std::string gameAbsPath, SystemData* system) folder = newFolder; } - if(loops > gamePath.length()) + //if for some reason this function is broken, break out of this while instead of freezing + if(loops > gamePath.length() * 2) { std::cerr << "breaking out of loop for path \"" << gamePath << "\"\n"; break; diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index 3e0c585d2..acfbea604 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -13,6 +13,9 @@ GuiGameList::GuiGameList(bool useDetail) std::cout << "Creating GuiGameList\n"; mDetailed = useDetail; + + mTheme = new GuiTheme(); //not a child because it's rendered manually by GuiGameList::onRender (to make sure it's rendered first) + //The GuiGameList can use the older, simple game list if so desired. //The old view only shows a list in the center of the screen; the new view can display an image and description. //Those with smaller displays may prefer the older view. @@ -20,7 +23,7 @@ GuiGameList::GuiGameList(bool useDetail) { mList = new GuiList(Renderer::getScreenWidth() * sInfoWidth, Renderer::getFontHeight(Renderer::LARGE) + 2); - mScreenshot = new GuiImage(Renderer::getScreenWidth() * sInfoWidth * 0.5, Renderer::getFontHeight(Renderer::LARGE) + 2, "", Renderer::getScreenWidth() * sInfoWidth * 0.7); + mScreenshot = new GuiImage(Renderer::getScreenWidth() * sInfoWidth * 0.5, Renderer::getScreenHeight() * mTheme->getGameImageOffsetY(), "", Renderer::getScreenWidth() * sInfoWidth * 0.7); mScreenshot->setOrigin(0.5, 0.0); addChild(mScreenshot); }else{ @@ -28,8 +31,6 @@ GuiGameList::GuiGameList(bool useDetail) mScreenshot = NULL; } - mTheme = new GuiTheme(); //not a child because it's rendered manually by GuiGameList::onRender (to make sure it's rendered first) - addChild(mList); setSystemId(0); @@ -99,10 +100,9 @@ void GuiGameList::onRender() { GameData* game = (GameData*)mList->getSelectedObject(); - //todo: cache this std::string desc = game->getDescription(); if(!desc.empty()) - Renderer::drawWrappedText(desc, Renderer::getScreenWidth() * 0.03, Renderer::getFontHeight(Renderer::LARGE) + mScreenshot->getHeight() + 10, Renderer::getScreenWidth() * (sInfoWidth - 0.03), mTheme->getDescColor(), Renderer::SMALL); + Renderer::drawWrappedText(desc, Renderer::getScreenWidth() * 0.03, mScreenshot->getOffsetY() + mScreenshot->getHeight() + 8, Renderer::getScreenWidth() * (sInfoWidth - 0.03), mTheme->getDescColor(), Renderer::SMALL); } } } @@ -200,6 +200,13 @@ void GuiGameList::updateTheme() mList->setSelectorColor(mTheme->getSelectorColor()); mList->setCentered(mTheme->getListCentered()); + + if(mDetailed) + { + mList->setOffsetX(mTheme->getListOffsetX() * Renderer::getScreenWidth()); + mList->setTextOffsetX(mTheme->getListTextOffsetX() * Renderer::getScreenWidth()); + mScreenshot->setOffsetY(mTheme->getGameImageOffsetY() * Renderer::getScreenHeight()); + } } void GuiGameList::updateDetailData() diff --git a/src/components/GuiImage.cpp b/src/components/GuiImage.cpp index 8084450f9..b1fe50577 100644 --- a/src/components/GuiImage.cpp +++ b/src/components/GuiImage.cpp @@ -10,8 +10,8 @@ GuiImage::GuiImage(int offsetX, int offsetY, std::string path, unsigned int resi { mTextureID = 0; - mOffsetX = offsetX; - mOffsetY = offsetY; + setOffsetX(offsetX); + setOffsetY(offsetY); //default origin is the center of image mOriginX = 0.5; @@ -245,7 +245,7 @@ void GuiImage::onRender() { for(unsigned int y = 0; y < yCount; y++) { - buildImageArray(mOffsetX + x*mWidth, mOffsetY + y*mHeight, points + (12 * (x*yCount + y)), texs + (12 * (x*yCount + y))); + buildImageArray(getOffsetX() + x*mWidth, getOffsetY() + y*mHeight, points + (12 * (x*yCount + y)), texs + (12 * (x*yCount + y))); } } drawImageArray(points, texs, xCount * yCount * 6); @@ -253,7 +253,7 @@ void GuiImage::onRender() delete[] texs; }else{ GLfloat points[12], texs[12]; - buildImageArray(mOffsetX, mOffsetY, points, texs); + buildImageArray(getOffsetX(), getOffsetY(), points, texs); drawImageArray(points, texs, 6); } } diff --git a/src/components/GuiImage.h b/src/components/GuiImage.h index 6c55a9f32..32b76f17b 100644 --- a/src/components/GuiImage.h +++ b/src/components/GuiImage.h @@ -41,7 +41,6 @@ private: std::string mPath; - int mOffsetX, mOffsetY; unsigned int mWidth, mHeight; //Our rendered size. GLuint mTextureID; diff --git a/src/components/GuiList.cpp b/src/components/GuiList.cpp index 257de14f3..3e99670e6 100644 --- a/src/components/GuiList.cpp +++ b/src/components/GuiList.cpp @@ -1,3 +1,5 @@ +//This is *actually* part of the GuiList header and not meant to be compiled. + #include "GuiList.h" #include @@ -9,8 +11,10 @@ GuiList::GuiList(int offsetX, int offsetY, Renderer::FontSize fontsize mScrolling = 0; mScrollAccumulator = 0; - mOffsetX = offsetX; - mOffsetY = offsetY; + setOffsetX(offsetX); + setOffsetY(offsetY); + + mTextOffsetX = 0; mFont = fontsize; mSelectorColor = 0x000000; @@ -28,7 +32,7 @@ GuiList::~GuiList() template void GuiList::onRender() { - const int cutoff = mOffsetY; + const int cutoff = getOffsetY(); const int entrySize = Renderer::getFontHeight(mFont) + 5; int startEntry = 0; @@ -62,15 +66,15 @@ void GuiList::onRender() { if(mSelection == i) { - Renderer::drawRect(mOffsetX, y, Renderer::getScreenWidth(), Renderer::getFontHeight(mFont), mSelectorColor); + Renderer::drawRect(getOffsetX(), y, Renderer::getScreenWidth(), Renderer::getFontHeight(mFont), mSelectorColor); } ListRow row = mRowVector.at((unsigned int)i); if(mDrawCentered) - Renderer::drawCenteredText(row.name, mOffsetX, y, row.color, mFont); + Renderer::drawCenteredText(row.name, getOffsetX(), y, row.color, mFont); else - Renderer::drawText(row.name, mOffsetX, y, row.color, mFont); + Renderer::drawText(row.name, getOffsetX() + mTextOffsetX, y, row.color, mFont); y += entrySize; } @@ -213,3 +217,9 @@ void GuiList::setCentered(bool centered) { mDrawCentered = centered; } + +template +void GuiList::setTextOffsetX(int textoffsetx) +{ + mTextOffsetX = textoffsetx; +} diff --git a/src/components/GuiList.h b/src/components/GuiList.h index fce555bf4..5b00a9596 100644 --- a/src/components/GuiList.h +++ b/src/components/GuiList.h @@ -36,6 +36,9 @@ public: void setSelectorColor(int selectorColor); void setCentered(bool centered); + + void setTextOffsetX(int textoffsetx); + private: int mScrollDir, mScrollAccumulator; bool mScrolling; @@ -44,7 +47,7 @@ private: int mSelectorColor; bool mDrawCentered; - int mOffsetX, mOffsetY; + int mTextOffsetX; struct ListRow { diff --git a/src/components/GuiTheme.cpp b/src/components/GuiTheme.cpp index 682a3ce3f..26eba1af5 100644 --- a/src/components/GuiTheme.cpp +++ b/src/components/GuiTheme.cpp @@ -5,6 +5,7 @@ #include "GuiImage.h" #include #include +#include "../Renderer.h" int GuiTheme::getPrimaryColor() { return mListPrimaryColor; } int GuiTheme::getSecondaryColor() { return mListSecondaryColor; } @@ -14,6 +15,11 @@ bool GuiTheme::getHeaderHidden() { return mHideHeader; } bool GuiTheme::getDividersHidden() { return mHideDividers; } bool GuiTheme::getListCentered() { return mListCentered; } +//not yet implemented +float GuiTheme::getListOffsetX() { return mListOffsetX; } +float GuiTheme::getGameImageOffsetY() { return mGameImageOffsetY; } +float GuiTheme::getListTextOffsetX() { return mListTextOffsetX; } + GuiTheme::GuiTheme(std::string path) { setDefaults(); @@ -36,6 +42,10 @@ void GuiTheme::setDefaults() mHideHeader = false; mHideDividers = false; mListCentered = true; + + mListOffsetX = 0.5; + mListTextOffsetX = 0.005; + mGameImageOffsetY = (float)Renderer::getFontHeight(Renderer::LARGE) / Renderer::getScreenHeight(); } void GuiTheme::deleteComponents() @@ -80,22 +90,35 @@ void GuiTheme::readXML(std::string path) pugi::xml_node root = doc.child("theme"); //load non-component theme stuff - mListPrimaryColor = resolveColor(root.child("listPrimaryColor").text().get(), 0x0000FF); - mListSecondaryColor = resolveColor(root.child("listSecondaryColor").text().get(), 0x00FF00); - mListSelectorColor = resolveColor(root.child("listSelectorColor").text().get(), 0x000000); - mDescColor = resolveColor(root.child("descColor").text().get(), 0x0000FF); + mListPrimaryColor = resolveColor(root.child("listPrimaryColor").text().get(), mListPrimaryColor); + mListSecondaryColor = resolveColor(root.child("listSecondaryColor").text().get(), mListSecondaryColor); + mListSelectorColor = resolveColor(root.child("listSelectorColor").text().get(), mListSelectorColor); + mDescColor = resolveColor(root.child("descColor").text().get(), mDescColor); mHideHeader = root.child("hideHeader"); mHideDividers = root.child("hideDividers"); mListCentered = !root.child("listLeftAlign"); - for(pugi::xml_node data = root.child("component"); data; data = data.next_sibling("component")) - { - createElement(data, this); - } + mListOffsetX = strToFloat(root.child("listOffsetX").text().get(), mListOffsetX); + mGameImageOffsetY = strToFloat(root.child("gameImageOffsetY").text().get(), mGameImageOffsetY); + mListTextOffsetX = strToFloat(root.child("listTextOffsetX").text().get(), mListTextOffsetX); + + //recursively create children for all with proper parenting + createComponentChildren(root, this); std::cout << "Finished parsing theme.\n"; } +void GuiTheme::createComponentChildren(pugi::xml_node node, GuiComponent* parent) +{ + for(pugi::xml_node data = node.child("component"); data; data = data.next_sibling("component")) + { + GuiComponent* nextComp = createElement(data, parent); + + if(nextComp) + createComponentChildren(data, nextComp); + } +} + GuiComponent* GuiTheme::createElement(pugi::xml_node data, GuiComponent* parent) { std::string type = data.child("type").text().get(); @@ -197,10 +220,10 @@ void GuiTheme::splitString(std::string str, char delim, std::string* before, std *after = str.substr(split + 1, str.length() - split - 1); } -float GuiTheme::strToFloat(std::string str) +float GuiTheme::strToFloat(std::string str, float defaultVal) { if(str.empty()) - return 0; + return defaultVal; float ret; std::stringstream ss; diff --git a/src/components/GuiTheme.h b/src/components/GuiTheme.h index fc6334a24..fced0c774 100644 --- a/src/components/GuiTheme.h +++ b/src/components/GuiTheme.h @@ -20,9 +20,14 @@ public: bool getHeaderHidden(); bool getDividersHidden(); bool getListCentered(); + + float getListOffsetX(); + float getListTextOffsetX(); + float getGameImageOffsetY(); private: void setDefaults(); void deleteComponents(); + void createComponentChildren(pugi::xml_node node, GuiComponent* parent); GuiComponent* createElement(pugi::xml_node data, GuiComponent* parent); //utility functions @@ -30,12 +35,14 @@ private: float resolveExp(std::string str); int resolveColor(std::string str, int defaultColor = 0x000000); void splitString(std::string str, char delim, std::string* before, std::string* after); - float strToFloat(std::string str); + float strToFloat(std::string str, float defaultVal = 0.0f); std::vector mComponentVector; std::string mPath; int mListPrimaryColor, mListSecondaryColor, mListSelectorColor, mDescColor; bool mHideHeader, mHideDividers, mListCentered; + + float mListOffsetX, mGameImageOffsetY, mListTextOffsetX; }; #endif