From 06dd1a9f60763058450b746f3bf3e730dd2ca447 Mon Sep 17 00:00:00 2001 From: Aloshi Date: Mon, 13 Aug 2012 20:27:39 -0500 Subject: [PATCH] Bug fixes and a few minor requested changes. See changelog.txt (August 13, part 2) for specifics. --- README.md | 3 +++ THEMES.md | 7 ++++--- changelog.txt | 9 ++++++++ src/Renderer_draw.cpp | 38 ++++++++++++++++++++++------------ src/components/GuiGameList.cpp | 15 +++++++++----- src/components/GuiGameList.h | 1 + src/components/GuiList.cpp | 14 ++++++++++++- src/components/GuiList.h | 2 ++ src/components/GuiTheme.cpp | 24 ++++++++++++++------- src/components/GuiTheme.h | 4 +++- 10 files changed, 87 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 48f5bebd5..ca5212373 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ A simple front-end for emulators made with SDL, designed for controller navigati RetroArch for the Raspberry Pi can be found here: https://github.com/ToadKing/RetroArch-Rpi I'm not associated with RetroArch in any way! +If you're lazy, a cool guy named petrockblog made a script which automatically installs RetroArch, its cores, and ES: https://github.com/petrockblog/RetroPie-Setup + Building ======== @@ -51,6 +53,7 @@ The path element should be the absolute path of the ROM. Special characters SHOU The switch `--gamelist-only` can be used to skip automatic searching, and only display games defined in the system's gamelist.xml. +A cool guy named Pendor made a scraper which automatically generates a gamelist.xml for you, with boxart automatically downloaded: https://github.com/jpzapa/ES-thegamesdb-scraper Themes ====== diff --git a/THEMES.md b/THEMES.md index eb7f6c90f..cb3b0c98b 100644 --- a/THEMES.md +++ b/THEMES.md @@ -66,6 +66,8 @@ 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 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. @@ -74,11 +76,10 @@ Display tags must be at the root of the tree - for example, they can't b List of variables ================= -Variables can be used in position and dimension definitions. They can be added, subtracted, multiplied, and divided. Parenthesis are valid. +Variables can be used in position and dimension definitions. They can be added, subtracted, multiplied, and divided. Parenthesis are valid. They are a percentage of the screen. -Currently, there's only one variable defined: `$headerHeight` - height of the system name header. - +`$infoWidth` - where the center of the horizontal divider is drawn. -Aloshi http://www.aloshi.com diff --git a/changelog.txt b/changelog.txt index f10073102..c0a9e16e9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,15 @@ August 13 -I've added a THEMES.md file for documentation on theming. -A CREDITS.md file. +-Fixed theme defaults not resetting when theme changes. +-The game image on the GuiGameList now maintains its alpha channel. +-Descriptions can now contain newline characters. +-Changed the size of the game info column to be 50% of the screen (previously 40%). +-Adjusted description to have a 3% left and right margins. +-Added $infoWidth variable for playing with the size of the game info column. +-Added tag that makes the game list left aligned instead of centered. +-Made Renderer::LARGE (header) fontsize slightly bigger + August 12 -If a theme.xml is not found in a system's directory, ES will now check for $HOME/.emulationstation/es_theme.xml. If present, it will load that. -Themes can now be used without the detailed GuiGameList. diff --git a/src/Renderer_draw.cpp b/src/Renderer_draw.cpp index 8073f3dd1..183cf15a5 100644 --- a/src/Renderer_draw.cpp +++ b/src/Renderer_draw.cpp @@ -11,6 +11,7 @@ TTF_Font* Renderer::fonts[3]; int Renderer::fontHeight[3]; +//a utility function to convert an int (usually defined as hex) to the SDL color struct SDL_Color getSDLColor(int& color) { char* c = (char*)(&color); @@ -23,8 +24,6 @@ SDL_Color getSDLColor(int& color) return ret; } - - void Renderer::drawRect(int x, int y, int h, int w, int color) { SDL_Rect rect = {x, y, h, w}; @@ -43,8 +42,7 @@ bool Renderer::loadFonts() std::cerr << fontPath << " (which may not exist).\n"; } - //int sizeArray[] = {Renderer::getScreenHeight() * 0.025, Renderer::getScreenHeight() * 0.05, Renderer::getScreenHeight() * 0.075}; - int sizeArray[] = {Renderer::getScreenWidth() * 0.015, Renderer::getScreenWidth() * 0.03, Renderer::getScreenWidth() * 0.05}; + int sizeArray[] = {Renderer::getScreenWidth() * 0.015, Renderer::getScreenWidth() * 0.03, Renderer::getScreenWidth() * 0.062}; //the three here should be the font count but, again, I don't remember the syntax @@ -117,6 +115,7 @@ void Renderer::drawCenteredText(std::string text, int xOffset, int y, int color, } //this could probably be optimized +//draws text and ensures it's never longer than xLen void Renderer::drawWrappedText(std::string text, int xStart, int yStart, int xLen, int color, FontSize fontsize) { if(!loadedFonts) @@ -128,40 +127,53 @@ void Renderer::drawWrappedText(std::string text, int xStart, int yStart, int xLe std::string line, word, temp; int w, h; - size_t space; + size_t space, newline; - while(text.length() > 0 || !line.empty()) + 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); - text.erase(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; TTF_SizeText(font, temp.c_str(), &w, &h); - - if(w <= xLen && text.length() == 0) + //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(w > xLen || text.length() == 0) + + //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) { //render line now - drawText(line, xStart, y, color, fontsize); + if(w > 0) //make sure it's not blank + drawText(line, xStart, y, color, fontsize); //increment y by height and some extra padding for the next line y += h + 4; - //draw the word we skipped on the next line + //move the word we skipped to the next line line = word; }else{ - //there's still space, continue + //there's still space, continue building the line line = temp; } diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index 947c52ff1..a6e7bcf81 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -11,6 +11,8 @@ extern float FRAMERATE; #endif +const float GuiGameList::sInfoWidth = 0.5; + GuiGameList::GuiGameList(bool useDetail) { std::cout << "Creating GuiGameList\n"; @@ -21,10 +23,11 @@ GuiGameList::GuiGameList(bool useDetail) //Those with smaller displays may prefer the older view. if(mDetailed) { - mList = new GuiList(Renderer::getScreenWidth() * 0.4, Renderer::getFontHeight(Renderer::LARGE) + 2); + mList = new GuiList(Renderer::getScreenWidth() * sInfoWidth, Renderer::getFontHeight(Renderer::LARGE) + 2); mScreenshot = new GuiImage(Renderer::getScreenWidth() * 0.2, Renderer::getFontHeight(Renderer::LARGE) + 2, "", Renderer::getScreenWidth() * 0.3); mScreenshot->setOrigin(0.5, 0.0); + mScreenshot->setAlpha(true); //slower, but requested addChild(mScreenshot); }else{ mList = new GuiList(0, Renderer::getFontHeight(Renderer::LARGE) + 2); @@ -103,8 +106,9 @@ void GuiGameList::onRender() if(mDetailed) { + //divider if(!mTheme->getDividersHidden()) - Renderer::drawRect(Renderer::getScreenWidth() * 0.4, Renderer::getFontHeight(Renderer::LARGE) + 2, 8, Renderer::getScreenHeight(), 0x0000FF); + Renderer::drawRect(Renderer::getScreenWidth() * sInfoWidth - 4, Renderer::getFontHeight(Renderer::LARGE) + 2, 8, Renderer::getScreenHeight(), 0x0000FF); //if we have selected a non-folder if(mList->getSelectedObject() && !mList->getSelectedObject()->isFolder()) @@ -114,7 +118,7 @@ void GuiGameList::onRender() //todo: cache this std::string desc = game->getDescription(); if(!desc.empty()) - Renderer::drawWrappedText(desc, 2, Renderer::getFontHeight(Renderer::LARGE) + mScreenshot->getHeight() + 10, Renderer::getScreenWidth() * 0.4, mTheme->getDescColor(), Renderer::SMALL); + Renderer::drawWrappedText(desc, Renderer::getScreenWidth() * 0.03, Renderer::getFontHeight(Renderer::LARGE) + mScreenshot->getHeight() + 10, Renderer::getScreenWidth() * 0.47, mTheme->getDescColor(), Renderer::SMALL); } } } @@ -126,9 +130,8 @@ void GuiGameList::onInput(InputManager::InputButton button, bool keyDown) if(!keyDown) { FileData* file = mList->getSelectedObject(); - if(file->isFolder()) + if(file->isFolder()) //if you selected a folder, add this directory to the stack, and use the selected one { - //set current directory to this or something mFolderStack.push(mFolder); mFolder = (FolderData*)file; updateList(); @@ -138,6 +141,7 @@ void GuiGameList::onInput(InputManager::InputButton button, bool keyDown) } } + //if there's something on the directory stack, return to it if(button == InputManager::BUTTON2 && keyDown && mFolderStack.size()) { mFolder = mFolderStack.top(); @@ -204,6 +208,7 @@ void GuiGameList::updateTheme() mTheme->readXML(""); //clears any current theme mList->setSelectorColor(mTheme->getSelectorColor()); + mList->setCentered(mTheme->getListCentered()); } void GuiGameList::updateDetailData() diff --git a/src/components/GuiGameList.h b/src/components/GuiGameList.h index 864e59b74..d5536cf34 100644 --- a/src/components/GuiGameList.h +++ b/src/components/GuiGameList.h @@ -24,6 +24,7 @@ public: void onPause(); void onResume(); + static const float sInfoWidth; private: void updateList(); void updateTheme(); diff --git a/src/components/GuiList.cpp b/src/components/GuiList.cpp index 3820d9daa..458d1ed37 100644 --- a/src/components/GuiList.cpp +++ b/src/components/GuiList.cpp @@ -14,6 +14,7 @@ GuiList::GuiList(int offsetX, int offsetY, Renderer::FontSize fontsize mFont = fontsize; mSelectorColor = 0x000000; + mDrawCentered = true; InputManager::registerComponent(this); } @@ -65,7 +66,12 @@ void GuiList::onRender() } ListRow row = mRowVector.at((unsigned int)i); - Renderer::drawCenteredText(row.name, mOffsetX, y, row.color, mFont); + + if(mDrawCentered) + Renderer::drawCenteredText(row.name, mOffsetX, y, row.color, mFont); + else + Renderer::drawText(row.name, mOffsetX, y, row.color, mFont); + y += entrySize; } } @@ -195,3 +201,9 @@ void GuiList::setSelectorColor(int selectorColor) { mSelectorColor = selectorColor; } + +template +void GuiList::setCentered(bool centered) +{ + mDrawCentered = centered; +} diff --git a/src/components/GuiList.h b/src/components/GuiList.h index 7d2056e68..11fec8802 100644 --- a/src/components/GuiList.h +++ b/src/components/GuiList.h @@ -33,12 +33,14 @@ public: int getSelection(); void setSelectorColor(int selectorColor); + void setCentered(bool centered); private: int mScrollDir, mScrollAccumulator; bool mScrolling; Renderer::FontSize mFont; int mSelectorColor; + bool mDrawCentered; int mOffsetX, mOffsetY; diff --git a/src/components/GuiTheme.cpp b/src/components/GuiTheme.cpp index 08e86bc20..cd73d3350 100644 --- a/src/components/GuiTheme.cpp +++ b/src/components/GuiTheme.cpp @@ -1,6 +1,7 @@ #include "GuiTheme.h" #include "../MathExp.h" #include +#include "GuiGameList.h" #include "GuiImage.h" #include #include @@ -11,15 +12,11 @@ int GuiTheme::getSelectorColor() { return mListSelectorColor; } int GuiTheme::getDescColor() { return mDescColor; } bool GuiTheme::getHeaderHidden() { return mHideHeader; } bool GuiTheme::getDividersHidden() { return mHideDividers; } +bool GuiTheme::getListCentered() { return mListCentered; } GuiTheme::GuiTheme(std::string path) { - mListPrimaryColor = 0x0000FF; - mListSecondaryColor = 0x00FF00; - mListSelectorColor = 0x000000; - mDescColor = 0x0000FF; - mHideHeader = false; - mHideDividers = false; + setDefaults(); if(!path.empty()) readXML(path); @@ -30,6 +27,17 @@ GuiTheme::~GuiTheme() deleteComponents(); } +void GuiTheme::setDefaults() +{ + mListPrimaryColor = 0x0000FF; + mListSecondaryColor = 0x00FF00; + mListSelectorColor = 0x000000; + mDescColor = 0x0000FF; + mHideHeader = false; + mHideDividers = false; + mListCentered = true; +} + void GuiTheme::deleteComponents() { for(unsigned int i = 0; i < mComponentVector.size(); i++) @@ -49,6 +57,7 @@ void GuiTheme::readXML(std::string path) if(mPath == path) return; + setDefaults(); deleteComponents(); mPath = path; @@ -77,6 +86,7 @@ void GuiTheme::readXML(std::string path) mDescColor = resolveColor(root.child("descColor").text().get(), 0x0000FF); 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")) { @@ -163,6 +173,7 @@ float GuiTheme::resolveExp(std::string str) //set variables exp.setVariable("headerHeight", Renderer::getFontHeight(Renderer::LARGE) / Renderer::getScreenHeight()); + exp.setVariable("infoWidth", GuiGameList::sInfoWidth); return exp.eval(); } @@ -177,7 +188,6 @@ int GuiTheme::resolveColor(std::string str, int defaultColor) ss << std::hex << str; ss >> ret; - std::cout << "resolved " << str << " to " << ret << "\n"; return ret; } diff --git a/src/components/GuiTheme.h b/src/components/GuiTheme.h index f26ef397f..9ea3fe551 100644 --- a/src/components/GuiTheme.h +++ b/src/components/GuiTheme.h @@ -18,7 +18,9 @@ public: int getDescColor(); bool getHeaderHidden(); bool getDividersHidden(); + bool getListCentered(); private: + void setDefaults(); void deleteComponents(); GuiComponent* createElement(pugi::xml_node data, GuiComponent* parent); @@ -32,7 +34,7 @@ private: std::vector mComponentVector; std::string mPath; int mListPrimaryColor, mListSecondaryColor, mListSelectorColor, mDescColor; - bool mHideHeader, mHideDividers; + bool mHideHeader, mHideDividers, mListCentered; }; #endif