mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-25 23:55:38 +00:00
Tons of new theming features!
Check out THEMES.md for more info.
This commit is contained in:
parent
c7349cd99a
commit
d842d67557
24
CREDITS.md
Normal file
24
CREDITS.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
Programming
|
||||||
|
Alec "Aloshi" Lofquist - http://www.aloshi.com
|
||||||
|
|
||||||
|
|
||||||
|
Resources
|
||||||
|
=========
|
||||||
|
|
||||||
|
LinLibertine.ttf
|
||||||
|
The Libertine Font Project - http://www.linuxlibertine.org/
|
||||||
|
|
||||||
|
PugiXML
|
||||||
|
http://pugixml.org/
|
||||||
|
|
||||||
|
SDL 1.2
|
||||||
|
http://www.libsdl.org/
|
||||||
|
|
||||||
|
SDL TTF
|
||||||
|
http://www.libsdl.org/projects/SDL_ttf/
|
||||||
|
|
||||||
|
SDL_image
|
||||||
|
http://www.libsdl.org/projects/SDL_image/
|
||||||
|
|
||||||
|
SDL_gfx
|
||||||
|
http://sourceforge.net/projects/sdlgfx/
|
17
README.md
17
README.md
|
@ -55,23 +55,8 @@ The switch `--gamelist-only` can be used to skip automatic searching, and only d
|
||||||
Themes
|
Themes
|
||||||
======
|
======
|
||||||
|
|
||||||
At the moment, theming is still in flux. But if you want to play around with what's here, feel free. ES will first check a system's search directory for a file named theme.xml. If that's not found, it'll check $HOME/.emulationstation/es_theme.xml.
|
If you want to know more about themes, read THEMES.md!
|
||||||
Themes are drawn before the rest of the game list. Here's the example I've been using to test a background:
|
|
||||||
|
|
||||||
```
|
|
||||||
<theme>
|
|
||||||
<component>
|
|
||||||
<type>image</type>
|
|
||||||
<path>/home/aloshi/EmulationStation/theme/background.png</path>
|
|
||||||
<pos>0 0</pos>
|
|
||||||
<dim>1 1</dim>
|
|
||||||
</component>
|
|
||||||
</theme>
|
|
||||||
```
|
|
||||||
|
|
||||||
You can add more than one component. You can use more than one component and components can be nested for your own personal use (but they won't inherit positions or anything). The only type thus far is image. Pos is short for position and dim is short for dimensions. Both work in screen percentages - a decimal from 0 to 1. A single space separates X/Y or width/height.
|
|
||||||
At the moment the X position is the horizontal center point for the image and Y is the top of the image.
|
|
||||||
Variable support is present, but the only variable defined right now is $headerHeight. You should be able to use addition/subtraction/multiplication/division.
|
|
||||||
|
|
||||||
-Aloshi
|
-Aloshi
|
||||||
http://www.aloshi.com
|
http://www.aloshi.com
|
||||||
|
|
74
THEMES.md
Normal file
74
THEMES.md
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
Themes
|
||||||
|
======
|
||||||
|
|
||||||
|
EmulationStation allows each system to have its own "theme." A theme is a collection of display settings and images defined in an XML document.
|
||||||
|
|
||||||
|
ES will check two places for a theme: first, the system's search directory for theme.xml. Then, if that's not found, $HOME/.emulationstation/es_theme.xml.
|
||||||
|
|
||||||
|
Almost all positions, dimensions, etc. work in percentages - that is, they are a decimal between 0 and 1, representing the percentage of the screen on that axis to use.
|
||||||
|
This ensures that themes look similar at every resolution.
|
||||||
|
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
|
||||||
|
Here's a simple theme that defines some colors and displays a background:
|
||||||
|
```
|
||||||
|
<theme>
|
||||||
|
<listPrimaryColor>0000FF</listPrimaryColor>
|
||||||
|
<listSecondaryColor>00FF00</listSecondaryColor>
|
||||||
|
|
||||||
|
<component>
|
||||||
|
<type>image</type>
|
||||||
|
<path>./theme/background.png</path>
|
||||||
|
<pos>0 0</pos>
|
||||||
|
<dim>1 1</dim>
|
||||||
|
<origin>0 0</origin>
|
||||||
|
</component>
|
||||||
|
</theme>
|
||||||
|
```
|
||||||
|
|
||||||
|
All themes must be enclosed in a `<theme>` tag.
|
||||||
|
|
||||||
|
|
||||||
|
Components
|
||||||
|
==========
|
||||||
|
A theme is made up of components, which have various types. At the moment, the only type is `image`. Components can be nested for your own organization. In the future, you may be able to get data from a parent.
|
||||||
|
|
||||||
|
|
||||||
|
The "image" component
|
||||||
|
=====================
|
||||||
|
Used to display an image.
|
||||||
|
|
||||||
|
`<path>` - path to the image file. Most common file types are supported, and . and ~ are properly expanded.
|
||||||
|
`<pos>` - the position, as two screen percentage, at which to display the image.
|
||||||
|
`<dim>` - the dimensions, as two screen percentages, that the image will be resized to. Leave one percentage 0 to keep the aspect ratio.
|
||||||
|
`<origin>` - the point on the image that <pos> defines, as an image percentage. "0.5 0.5", the center of the image, by default.
|
||||||
|
|
||||||
|
`<tiled />` - if present, the image is tiled instead of resized. Tiling isn't exact at the moment, but good enough for backgrounds.
|
||||||
|
`<useAlpha />` - if present, the image will not be stripped of its alpha channel. It will render much slower, but should have transparency.
|
||||||
|
|
||||||
|
|
||||||
|
Display tags
|
||||||
|
============
|
||||||
|
Display tags must be at the root of the <theme> tree - for example, they can't be inside a component tag. They are not required.
|
||||||
|
|
||||||
|
`<listPrimaryColor>` - the hex font color to use for games on the GuiGameList.
|
||||||
|
`<listSecondaryColor>` - the hex font color to use for folders on the GuiGameList.
|
||||||
|
`<descColor>` - the hex font color to use for the description on the GuiGameList.
|
||||||
|
`<listSelectorColor>` - the hex color to use for the "selector bar" on the GuiGameList.
|
||||||
|
`<hideHeader />` - if present, the system name header won't be displayed (useful for replacing it with an image).
|
||||||
|
`<hideDividers />` - if present, the divider between games on the detailed GuiGameList won't be displayed.
|
||||||
|
|
||||||
|
|
||||||
|
List of variables
|
||||||
|
=================
|
||||||
|
|
||||||
|
Variables can be used in position and dimension definitions. They can be added, subtracted, multiplied, and divided. Parenthesis are valid.
|
||||||
|
|
||||||
|
Currently, there's only one variable defined:
|
||||||
|
`$headerHeight` - height of the system name header.
|
||||||
|
|
||||||
|
|
||||||
|
-Aloshi
|
||||||
|
http://www.aloshi.com
|
|
@ -1,3 +1,8 @@
|
||||||
|
August 13
|
||||||
|
-Tons of new theming features!
|
||||||
|
-I've added a THEMES.md file for documentation on theming.
|
||||||
|
-A CREDITS.md file.
|
||||||
|
|
||||||
August 12
|
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.
|
-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.
|
-Themes can now be used without the detailed GuiGameList.
|
||||||
|
|
|
@ -10,6 +10,21 @@ bool Renderer::loadedFonts = false;
|
||||||
TTF_Font* Renderer::fonts[3];
|
TTF_Font* Renderer::fonts[3];
|
||||||
int Renderer::fontHeight[3];
|
int Renderer::fontHeight[3];
|
||||||
|
|
||||||
|
|
||||||
|
SDL_Color getSDLColor(int& color)
|
||||||
|
{
|
||||||
|
char* c = (char*)(&color);
|
||||||
|
|
||||||
|
SDL_Color ret;
|
||||||
|
ret.r = *(c + 2);
|
||||||
|
ret.g = *(c + 1);
|
||||||
|
ret.b = *(c + 0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Renderer::drawRect(int x, int y, int h, int w, int color)
|
void Renderer::drawRect(int x, int y, int h, int w, int color)
|
||||||
{
|
{
|
||||||
SDL_Rect rect = {x, y, h, w};
|
SDL_Rect rect = {x, y, h, w};
|
||||||
|
@ -67,9 +82,10 @@ void Renderer::drawText(std::string text, int x, int y, int color, FontSize font
|
||||||
|
|
||||||
//SDL_Color is a struct of four bytes, with the first three being colors. An int is four bytes.
|
//SDL_Color is a struct of four bytes, with the first three being colors. An int is four bytes.
|
||||||
//So, we can just pretend the int is an SDL_Color.
|
//So, we can just pretend the int is an SDL_Color.
|
||||||
SDL_Color* sdlcolor = (SDL_Color*)&color;
|
//SDL_Color* sdlcolor = (SDL_Color*)&color;
|
||||||
|
SDL_Color sdlcolor = getSDLColor(color);
|
||||||
|
|
||||||
SDL_Surface* textSurf = TTF_RenderText_Blended(font, text.c_str(), *sdlcolor);
|
SDL_Surface* textSurf = TTF_RenderText_Blended(font, text.c_str(), sdlcolor);
|
||||||
if(textSurf == NULL)
|
if(textSurf == NULL)
|
||||||
{
|
{
|
||||||
std::cerr << "Error - could not render text \"" << text << "\" to surface!\n";
|
std::cerr << "Error - could not render text \"" << text << "\" to surface!\n";
|
||||||
|
|
|
@ -24,6 +24,7 @@ GuiGameList::GuiGameList(bool useDetail)
|
||||||
mList = new GuiList<FileData*>(Renderer::getScreenWidth() * 0.4, Renderer::getFontHeight(Renderer::LARGE) + 2);
|
mList = new GuiList<FileData*>(Renderer::getScreenWidth() * 0.4, Renderer::getFontHeight(Renderer::LARGE) + 2);
|
||||||
|
|
||||||
mScreenshot = new GuiImage(Renderer::getScreenWidth() * 0.2, Renderer::getFontHeight(Renderer::LARGE) + 2, "", Renderer::getScreenWidth() * 0.3);
|
mScreenshot = new GuiImage(Renderer::getScreenWidth() * 0.2, Renderer::getFontHeight(Renderer::LARGE) + 2, "", Renderer::getScreenWidth() * 0.3);
|
||||||
|
mScreenshot->setOrigin(0.5, 0.0);
|
||||||
addChild(mScreenshot);
|
addChild(mScreenshot);
|
||||||
}else{
|
}else{
|
||||||
mList = new GuiList<FileData*>(0, Renderer::getFontHeight(Renderer::LARGE) + 2);
|
mList = new GuiList<FileData*>(0, Renderer::getFontHeight(Renderer::LARGE) + 2);
|
||||||
|
@ -96,12 +97,14 @@ void GuiGameList::onRender()
|
||||||
Renderer::drawText(fps, 0, 0, 0x00FF00);
|
Renderer::drawText(fps, 0, 0, 0x00FF00);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//header
|
||||||
Renderer::drawCenteredText(mSystem->getName(), 0, 1, 0x0000FF, Renderer::LARGE);
|
if(!mTheme->getHeaderHidden())
|
||||||
|
Renderer::drawCenteredText(mSystem->getName(), 0, 1, 0xFF0000, Renderer::LARGE);
|
||||||
|
|
||||||
if(mDetailed)
|
if(mDetailed)
|
||||||
{
|
{
|
||||||
Renderer::drawRect(Renderer::getScreenWidth() * 0.4, Renderer::getFontHeight(Renderer::LARGE) + 2, 8, Renderer::getScreenHeight(), 0x0000FF);
|
if(!mTheme->getDividersHidden())
|
||||||
|
Renderer::drawRect(Renderer::getScreenWidth() * 0.4, Renderer::getFontHeight(Renderer::LARGE) + 2, 8, Renderer::getScreenHeight(), 0x0000FF);
|
||||||
|
|
||||||
//if we have selected a non-folder
|
//if we have selected a non-folder
|
||||||
if(mList->getSelectedObject() && !mList->getSelectedObject()->isFolder())
|
if(mList->getSelectedObject() && !mList->getSelectedObject()->isFolder())
|
||||||
|
@ -111,7 +114,7 @@ void GuiGameList::onRender()
|
||||||
//todo: cache this
|
//todo: cache this
|
||||||
std::string desc = game->getDescription();
|
std::string desc = game->getDescription();
|
||||||
if(!desc.empty())
|
if(!desc.empty())
|
||||||
Renderer::drawWrappedText(desc, 2, Renderer::getFontHeight(Renderer::LARGE) + mScreenshot->getHeight() + 10, Renderer::getScreenWidth() * 0.4, 0xFF0000, Renderer::SMALL);
|
Renderer::drawWrappedText(desc, 2, Renderer::getFontHeight(Renderer::LARGE) + mScreenshot->getHeight() + 10, Renderer::getScreenWidth() * 0.4, mTheme->getDescColor(), Renderer::SMALL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,9 +181,9 @@ void GuiGameList::updateList()
|
||||||
FileData* file = mFolder->getFile(i);
|
FileData* file = mFolder->getFile(i);
|
||||||
|
|
||||||
if(file->isFolder())
|
if(file->isFolder())
|
||||||
mList->addObject(file->getName(), file, 0x00C000);
|
mList->addObject(file->getName(), file, mTheme->getSecondaryColor());
|
||||||
else
|
else
|
||||||
mList->addObject(file->getName(), file);
|
mList->addObject(file->getName(), file, mTheme->getPrimaryColor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,6 +202,8 @@ void GuiGameList::updateTheme()
|
||||||
mTheme->readXML(defaultPath);
|
mTheme->readXML(defaultPath);
|
||||||
else
|
else
|
||||||
mTheme->readXML(""); //clears any current theme
|
mTheme->readXML(""); //clears any current theme
|
||||||
|
|
||||||
|
mList->setSelectorColor(mTheme->getSelectorColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiGameList::updateDetailData()
|
void GuiGameList::updateDetailData()
|
||||||
|
|
|
@ -14,9 +14,17 @@ GuiImage::GuiImage(int offsetX, int offsetY, std::string path, unsigned int maxW
|
||||||
mOffsetX = offsetX;
|
mOffsetX = offsetX;
|
||||||
mOffsetY = offsetY;
|
mOffsetY = offsetY;
|
||||||
|
|
||||||
|
//default origin (center of image)
|
||||||
|
mOriginX = 0;
|
||||||
|
mOriginY = 0;
|
||||||
|
|
||||||
|
mTiled = false;
|
||||||
|
|
||||||
mMaxWidth = maxWidth;
|
mMaxWidth = maxWidth;
|
||||||
mMaxHeight = maxHeight;
|
mMaxHeight = maxHeight;
|
||||||
|
|
||||||
mResizeExact = resizeExact;
|
mResizeExact = resizeExact;
|
||||||
|
mUseAlpha = false;
|
||||||
|
|
||||||
if(!path.empty())
|
if(!path.empty())
|
||||||
setImage(path);
|
setImage(path);
|
||||||
|
@ -43,38 +51,15 @@ void GuiImage::loadImage(std::string path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//resize it
|
resizeSurface(&newSurf);
|
||||||
if(mResizeExact)
|
|
||||||
{
|
|
||||||
double scaleX = (double)mMaxWidth / (double)newSurf->w;
|
|
||||||
double scaleY = (double)mMaxHeight / (double)newSurf->h;
|
|
||||||
|
|
||||||
SDL_Surface* resSurf = zoomSurface(newSurf, scaleX, scaleY, SMOOTHING_OFF);
|
|
||||||
SDL_FreeSurface(newSurf);
|
|
||||||
newSurf = resSurf;
|
|
||||||
}else{
|
|
||||||
if(mMaxWidth && newSurf->w > mMaxWidth)
|
|
||||||
{
|
|
||||||
double scale = (double)mMaxWidth / (double)newSurf->w;
|
|
||||||
|
|
||||||
SDL_Surface* resSurf = zoomSurface(newSurf, scale, scale, SMOOTHING_OFF);
|
|
||||||
SDL_FreeSurface(newSurf);
|
|
||||||
newSurf = resSurf;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mMaxHeight && newSurf->h > mMaxHeight)
|
|
||||||
{
|
|
||||||
double scale = (double)mMaxHeight / (double)newSurf->h;
|
|
||||||
|
|
||||||
SDL_Surface* resSurf = zoomSurface(newSurf, scale, scale, SMOOTHING_OFF);
|
|
||||||
SDL_FreeSurface(newSurf);
|
|
||||||
newSurf = resSurf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//convert it into display format for faster rendering
|
//convert it into display format for faster rendering
|
||||||
SDL_Surface* dispSurf = SDL_DisplayFormat(newSurf);
|
SDL_Surface* dispSurf;
|
||||||
|
if(mUseAlpha)
|
||||||
|
dispSurf = SDL_DisplayFormatAlpha(newSurf);
|
||||||
|
else
|
||||||
|
dispSurf = SDL_DisplayFormat(newSurf);
|
||||||
|
|
||||||
SDL_FreeSurface(newSurf);
|
SDL_FreeSurface(newSurf);
|
||||||
newSurf = dispSurf;
|
newSurf = dispSurf;
|
||||||
|
|
||||||
|
@ -85,16 +70,56 @@ void GuiImage::loadImage(std::string path)
|
||||||
|
|
||||||
mSurface = newSurf;
|
mSurface = newSurf;
|
||||||
|
|
||||||
//Also update the rect
|
updateRect();
|
||||||
mRect.x = mOffsetX - (mSurface->w / 2);
|
|
||||||
mRect.y = mOffsetY;
|
|
||||||
mRect.w = mSurface->w;
|
|
||||||
mRect.h = mSurface->h;
|
|
||||||
}else{
|
}else{
|
||||||
std::cerr << "File \"" << path << "\" not found!\n";
|
std::cerr << "File \"" << path << "\" not found!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//enjoy this overly-complicated pointer stuff that results from splitting a function too late
|
||||||
|
void GuiImage::resizeSurface(SDL_Surface** surfRef)
|
||||||
|
{
|
||||||
|
if(mTiled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SDL_Surface* newSurf = *surfRef;
|
||||||
|
if(mResizeExact)
|
||||||
|
{
|
||||||
|
double scaleX = (double)mMaxWidth / (double)newSurf->w;
|
||||||
|
double scaleY = (double)mMaxHeight / (double)newSurf->h;
|
||||||
|
|
||||||
|
if(scaleX == 0)
|
||||||
|
scaleX = scaleY;
|
||||||
|
if(scaleY == 0)
|
||||||
|
scaleY = scaleX;
|
||||||
|
|
||||||
|
SDL_Surface* resSurf = zoomSurface(newSurf, scaleX, scaleY, SMOOTHING_OFF);
|
||||||
|
SDL_FreeSurface(newSurf);
|
||||||
|
newSurf = resSurf;
|
||||||
|
}else{
|
||||||
|
if(mMaxWidth && newSurf->w > mMaxWidth)
|
||||||
|
{
|
||||||
|
double scale = (double)mMaxWidth / (double)newSurf->w;
|
||||||
|
|
||||||
|
SDL_Surface* resSurf = zoomSurface(newSurf, scale, scale, SMOOTHING_OFF);
|
||||||
|
SDL_FreeSurface(newSurf);
|
||||||
|
newSurf = resSurf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mMaxHeight && newSurf->h > mMaxHeight)
|
||||||
|
{
|
||||||
|
double scale = (double)mMaxHeight / (double)newSurf->h;
|
||||||
|
|
||||||
|
SDL_Surface* resSurf = zoomSurface(newSurf, scale, scale, SMOOTHING_OFF);
|
||||||
|
SDL_FreeSurface(newSurf);
|
||||||
|
newSurf = resSurf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*surfRef = newSurf;
|
||||||
|
}
|
||||||
|
|
||||||
void GuiImage::setImage(std::string path)
|
void GuiImage::setImage(std::string path)
|
||||||
{
|
{
|
||||||
if(mPath == path)
|
if(mPath == path)
|
||||||
|
@ -113,8 +138,64 @@ void GuiImage::setImage(std::string path)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GuiImage::updateRect()
|
||||||
|
{
|
||||||
|
mRect.x = mOffsetX /*- mSurface->w*/ - (mSurface->w * mOriginX);
|
||||||
|
mRect.y = mOffsetY + (mSurface->h * mOriginY);
|
||||||
|
mRect.w = mSurface->w;
|
||||||
|
mRect.h = mSurface->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiImage::setOrigin(float originX, float originY)
|
||||||
|
{
|
||||||
|
mOriginX = originX;
|
||||||
|
mOriginY = originY;
|
||||||
|
|
||||||
|
if(mSurface)
|
||||||
|
updateRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiImage::setTiling(bool tile)
|
||||||
|
{
|
||||||
|
mTiled = tile;
|
||||||
|
|
||||||
|
if(mTiled)
|
||||||
|
mResizeExact = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiImage::setAlpha(bool useAlpha)
|
||||||
|
{
|
||||||
|
mUseAlpha = useAlpha;
|
||||||
|
|
||||||
|
if(mSurface)
|
||||||
|
{
|
||||||
|
SDL_FreeSurface(mSurface);
|
||||||
|
mSurface = NULL;
|
||||||
|
loadImage(mPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dbg = false;
|
||||||
|
|
||||||
void GuiImage::onRender()
|
void GuiImage::onRender()
|
||||||
{
|
{
|
||||||
if(mSurface)
|
if(mSurface)
|
||||||
SDL_BlitSurface(mSurface, NULL, Renderer::screen, &mRect);
|
{
|
||||||
|
if(mTiled)
|
||||||
|
{
|
||||||
|
SDL_Rect rect = mRect;
|
||||||
|
for(int x = 0; x < mMaxWidth / mSurface->w + 0.5; x++)
|
||||||
|
{
|
||||||
|
for(int y = 0; y < mMaxHeight / mSurface->h + 0.5; y++)
|
||||||
|
{
|
||||||
|
SDL_BlitSurface(mSurface, NULL, Renderer::screen, &rect);
|
||||||
|
rect.y += mSurface->h;
|
||||||
|
}
|
||||||
|
rect.x += mSurface->w;
|
||||||
|
rect.y = mRect.y;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
SDL_BlitSurface(mSurface, NULL, Renderer::screen, &mRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ public:
|
||||||
~GuiImage();
|
~GuiImage();
|
||||||
|
|
||||||
void setImage(std::string path);
|
void setImage(std::string path);
|
||||||
|
void setOrigin(float originX, float originY);
|
||||||
|
void setTiling(bool tile);
|
||||||
|
void setAlpha(bool useAlpha);
|
||||||
|
|
||||||
int getWidth();
|
int getWidth();
|
||||||
int getHeight();
|
int getHeight();
|
||||||
|
@ -21,9 +24,12 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int mMaxWidth, mMaxHeight;
|
int mMaxWidth, mMaxHeight;
|
||||||
bool mResizeExact;
|
float mOriginX, mOriginY;
|
||||||
|
bool mResizeExact, mTiled, mUseAlpha;
|
||||||
|
|
||||||
void loadImage(std::string path);
|
void loadImage(std::string path);
|
||||||
|
void resizeSurface(SDL_Surface** surfRef);
|
||||||
|
void updateRect();
|
||||||
|
|
||||||
std::string mPath;
|
std::string mPath;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ GuiList<listType>::GuiList(int offsetX, int offsetY, Renderer::FontSize fontsize
|
||||||
mOffsetY = offsetY;
|
mOffsetY = offsetY;
|
||||||
|
|
||||||
mFont = fontsize;
|
mFont = fontsize;
|
||||||
|
mSelectorColor = 0x000000;
|
||||||
|
|
||||||
InputManager::registerComponent(this);
|
InputManager::registerComponent(this);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +49,7 @@ void GuiList<listType>::onRender()
|
||||||
|
|
||||||
if(mRowVector.size() == 0)
|
if(mRowVector.size() == 0)
|
||||||
{
|
{
|
||||||
Renderer::drawCenteredText("The list is empty.", 0, y, 0xFF0000, mFont);
|
Renderer::drawCenteredText("The list is empty.", 0, y, 0x0000FF, mFont);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ void GuiList<listType>::onRender()
|
||||||
{
|
{
|
||||||
if(mSelection == i)
|
if(mSelection == i)
|
||||||
{
|
{
|
||||||
Renderer::drawRect(mOffsetX, y, Renderer::getScreenWidth(), Renderer::getFontHeight(mFont), 0x000000);
|
Renderer::drawRect(mOffsetX, y, Renderer::getScreenWidth(), Renderer::getFontHeight(mFont), mSelectorColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ListRow row = mRowVector.at((unsigned int)i);
|
ListRow row = mRowVector.at((unsigned int)i);
|
||||||
|
@ -188,3 +189,9 @@ void GuiList<listType>::onResume()
|
||||||
{
|
{
|
||||||
InputManager::registerComponent(this);
|
InputManager::registerComponent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename listType>
|
||||||
|
void GuiList<listType>::setSelectorColor(int selectorColor)
|
||||||
|
{
|
||||||
|
mSelectorColor = selectorColor;
|
||||||
|
}
|
||||||
|
|
|
@ -31,11 +31,14 @@ public:
|
||||||
std::string getSelectedName();
|
std::string getSelectedName();
|
||||||
listType getSelectedObject();
|
listType getSelectedObject();
|
||||||
int getSelection();
|
int getSelection();
|
||||||
|
|
||||||
|
void setSelectorColor(int selectorColor);
|
||||||
private:
|
private:
|
||||||
int mScrollDir, mScrollAccumulator;
|
int mScrollDir, mScrollAccumulator;
|
||||||
bool mScrolling;
|
bool mScrolling;
|
||||||
|
|
||||||
Renderer::FontSize mFont;
|
Renderer::FontSize mFont;
|
||||||
|
int mSelectorColor;
|
||||||
|
|
||||||
int mOffsetX, mOffsetY;
|
int mOffsetX, mOffsetY;
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,24 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "GuiImage.h"
|
#include "GuiImage.h"
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
int GuiTheme::getPrimaryColor() { return mListPrimaryColor; }
|
||||||
|
int GuiTheme::getSecondaryColor() { return mListSecondaryColor; }
|
||||||
|
int GuiTheme::getSelectorColor() { return mListSelectorColor; }
|
||||||
|
int GuiTheme::getDescColor() { return mDescColor; }
|
||||||
|
bool GuiTheme::getHeaderHidden() { return mHideHeader; }
|
||||||
|
bool GuiTheme::getDividersHidden() { return mHideDividers; }
|
||||||
|
|
||||||
GuiTheme::GuiTheme(std::string path)
|
GuiTheme::GuiTheme(std::string path)
|
||||||
{
|
{
|
||||||
|
mListPrimaryColor = 0x0000FF;
|
||||||
|
mListSecondaryColor = 0x00FF00;
|
||||||
|
mListSelectorColor = 0x000000;
|
||||||
|
mDescColor = 0x0000FF;
|
||||||
|
mHideHeader = false;
|
||||||
|
mHideDividers = false;
|
||||||
|
|
||||||
if(!path.empty())
|
if(!path.empty())
|
||||||
readXML(path);
|
readXML(path);
|
||||||
}
|
}
|
||||||
|
@ -55,6 +70,14 @@ void GuiTheme::readXML(std::string path)
|
||||||
|
|
||||||
pugi::xml_node root = doc.child("theme");
|
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);
|
||||||
|
mHideHeader = root.child("hideHeader");
|
||||||
|
mHideDividers = root.child("hideDividers");
|
||||||
|
|
||||||
for(pugi::xml_node data = root.child("component"); data; data = data.next_sibling("component"))
|
for(pugi::xml_node data = root.child("component"); data; data = data.next_sibling("component"))
|
||||||
{
|
{
|
||||||
createElement(data, this);
|
createElement(data, this);
|
||||||
|
@ -79,17 +102,22 @@ GuiComponent* GuiTheme::createElement(pugi::xml_node data, GuiComponent* parent)
|
||||||
|
|
||||||
std::string pos = data.child("pos").text().get();
|
std::string pos = data.child("pos").text().get();
|
||||||
std::string dim = data.child("dim").text().get();
|
std::string dim = data.child("dim").text().get();
|
||||||
|
std::string origin = data.child("origin").text().get();
|
||||||
|
|
||||||
|
bool useAlpha = data.child("useAlpha");
|
||||||
|
bool tiled = data.child("tiled");
|
||||||
|
|
||||||
//split position and dimension information
|
//split position and dimension information
|
||||||
size_t posSplit = pos.find(' ');
|
std::string posX, posY;
|
||||||
std::string posX = pos.substr(0, posSplit);
|
splitString(pos, ' ', &posX, &posY);
|
||||||
std::string posY = pos.substr(posSplit + 1, pos.length() - posSplit - 1);
|
|
||||||
|
|
||||||
size_t dimSplit = dim.find(' ');
|
std::string dimW, dimH;
|
||||||
std::string dimW = dim.substr(0, dimSplit);
|
splitString(dim, ' ', &dimW, &dimH);
|
||||||
std::string dimH = dim.substr(dimSplit + 1, dim.length() - dimSplit - 1);
|
|
||||||
|
|
||||||
std::cout << "image, x: " << posX << " y: " << posY << " w: " << dimW << " h: " << dimH << "\n";
|
std::string originX, originY;
|
||||||
|
splitString(origin, ' ', &originX, &originY);
|
||||||
|
|
||||||
|
std::cout << "image, x: " << posX << " y: " << posY << " w: " << dimW << " h: " << dimH << " ox: " << originX << " oy: " << originY << " alpha: " << useAlpha << " tiled: " << tiled << "\n";
|
||||||
|
|
||||||
//resolve to pixels from percentages/variables
|
//resolve to pixels from percentages/variables
|
||||||
int x = resolveExp(posX) * Renderer::getScreenWidth();
|
int x = resolveExp(posX) * Renderer::getScreenWidth();
|
||||||
|
@ -97,9 +125,17 @@ GuiComponent* GuiTheme::createElement(pugi::xml_node data, GuiComponent* parent)
|
||||||
int w = resolveExp(dimW) * Renderer::getScreenWidth();
|
int w = resolveExp(dimW) * Renderer::getScreenWidth();
|
||||||
int h = resolveExp(dimH) * Renderer::getScreenHeight();
|
int h = resolveExp(dimH) * Renderer::getScreenHeight();
|
||||||
|
|
||||||
|
int ox = strToInt(originX);
|
||||||
|
int oy = strToInt(originY);
|
||||||
|
|
||||||
std::cout << "w: " << w << "px, h: " << h << "px\n";
|
std::cout << "w: " << w << "px, h: " << h << "px\n";
|
||||||
|
|
||||||
GuiComponent* comp = new GuiImage(x, y, path, w, h, true);
|
GuiImage* comp = new GuiImage(x, y, "", w, h, true);
|
||||||
|
comp->setOrigin(ox, oy);
|
||||||
|
comp->setAlpha(useAlpha);
|
||||||
|
comp->setTiling(tiled);
|
||||||
|
comp->setImage(path);
|
||||||
|
|
||||||
parent->addChild(comp);
|
parent->addChild(comp);
|
||||||
mComponentVector.push_back(comp);
|
mComponentVector.push_back(comp);
|
||||||
return comp;
|
return comp;
|
||||||
|
@ -130,3 +166,39 @@ float GuiTheme::resolveExp(std::string str)
|
||||||
|
|
||||||
return exp.eval();
|
return exp.eval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GuiTheme::resolveColor(std::string str, int defaultColor)
|
||||||
|
{
|
||||||
|
if(str.empty())
|
||||||
|
return defaultColor;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::hex << str;
|
||||||
|
ss >> ret;
|
||||||
|
|
||||||
|
std::cout << "resolved " << str << " to " << ret << "\n";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiTheme::splitString(std::string str, char delim, std::string* before, std::string* after)
|
||||||
|
{
|
||||||
|
if(str.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t split = str.find(delim);
|
||||||
|
*before = str.substr(0, split);
|
||||||
|
*after = str.substr(split + 1, str.length() - split - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int GuiTheme::strToInt(std::string str)
|
||||||
|
{
|
||||||
|
if(str.empty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << str;
|
||||||
|
ss >> ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -12,14 +12,27 @@ public:
|
||||||
|
|
||||||
void readXML(std::string path);
|
void readXML(std::string path);
|
||||||
|
|
||||||
|
int getPrimaryColor();
|
||||||
|
int getSecondaryColor();
|
||||||
|
int getSelectorColor();
|
||||||
|
int getDescColor();
|
||||||
|
bool getHeaderHidden();
|
||||||
|
bool getDividersHidden();
|
||||||
private:
|
private:
|
||||||
void deleteComponents();
|
void deleteComponents();
|
||||||
GuiComponent* createElement(pugi::xml_node data, GuiComponent* parent);
|
GuiComponent* createElement(pugi::xml_node data, GuiComponent* parent);
|
||||||
|
|
||||||
|
//utility functions
|
||||||
std::string expandPath(std::string path);
|
std::string expandPath(std::string path);
|
||||||
float resolveExp(std::string str);
|
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);
|
||||||
|
int strToInt(std::string str);
|
||||||
|
|
||||||
std::vector<GuiComponent*> mComponentVector;
|
std::vector<GuiComponent*> mComponentVector;
|
||||||
std::string mPath;
|
std::string mPath;
|
||||||
|
int mListPrimaryColor, mListSecondaryColor, mListSelectorColor, mDescColor;
|
||||||
|
bool mHideHeader, mHideDividers;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,6 +17,8 @@ int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
bool running = true;
|
bool running = true;
|
||||||
|
|
||||||
|
//by the way, if anyone ever tries to port this to a different renderer but leave SDL as input -
|
||||||
|
//KEEP INITIALIZING VIDEO. It starts SDL's event system, and without it, input won't work.
|
||||||
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) != 0)
|
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) != 0)
|
||||||
{
|
{
|
||||||
std::cerr << "Error - could not initialize SDL!\n";
|
std::cerr << "Error - could not initialize SDL!\n";
|
||||||
|
|
Loading…
Reference in a new issue