THEMES.md 18.8 KB
Newer Older
root's avatar
root committed
1 2 3
Themes
======

4
EmulationStation allows each system to have its own "theme." A theme is a collection **views** that define some **elements**, each with their own **properties**.
root's avatar
root committed
5

6
The first place ES will check for a theme is in the system's `<path>` folder, for a theme.xml file:
7
* `[SYSTEM_PATH]/theme.xml`
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

If that file doesn't exist, ES will try to find the theme in the current **theme set**.  Theme sets are just a collection of individual system themes arranged in the "themes" folder under some name.  Here's an example:

```
...
   themes/
      my_theme_set/
         snes/
            theme.xml
            my_cool_background.jpg

         nes/
            theme.xml
            my_other_super_cool_background.jpg

         common_resources/
            scroll_sound.wav

      another_theme_set/
         snes/
            theme.xml
            some_resource.svg
```

The theme set system makes it easy for users to try different themes and allows distributions to include multiple theme options.  Users can change the currently active theme set in the "UI Settings" menu.  The option is only visible if at least one theme set exists.

There are two places ES can load theme sets from:
* `[HOME]/.emulationstation/themes/[CURRENT_THEME_SET]/[SYSTEM_NAME]/theme.xml`
* `/etc/emulationstation/themes/[CURRENT_THEME_SET]/[SYSTEM_NAME]/theme.xml`

If both files happen to exist, ES will pick the first one (the one located in the home directory).

Again, the `[CURRENT_THEME_SET]` value is set in the "UI Settings" menu.  If it has not been set yet or the previously selected theme set is missing, the first available theme set will be used as the default.
41

42 43
Simple Example
==============
44

45
Here is a very simple theme that changes the description text's color:
root's avatar
root committed
46

Aloshi's avatar
Aloshi committed
47
```xml
root's avatar
root committed
48
<theme>
49
	<formatVersion>3</formatVersion>
50 51 52 53 54 55 56 57 58 59 60
	<view name="detailed">
		<text name="description">
			<color>00FF00</color>
		</text>
		<image name="my_image" extra="true">
			<pos>0.5 0.5</pos>
			<origin>0.5 0.5</origin>
			<size>0.8 0.8</size>
			<path>./my_art/my_awesome_image.jpg</path>
		</image>
	</view>
61 62
</theme>
```
63

64 65 66 67
How it works
============

Everything must be inside a `<theme>` tag.
68

69
**The `<formatVersion>` tag *must* be specified**.  This is the version of the theming system the theme was designed for.  The current version is 3.
70

71

Aloshi's avatar
Aloshi committed
72

73
A *view* can be thought of as a particular "screen" within EmulationStation.  Views are defined like this:
Aloshi's avatar
Aloshi committed
74

Aloshi's avatar
Aloshi committed
75
```xml
76 77 78
<view name="ViewNameHere">
	... define elements here ...
</view>
Aloshi's avatar
Aloshi committed
79 80
```

81 82


83
An *element* is a particular visual element, such as an image or a piece of text.  You can either modify an element that already exists for a particular view (as is done in the "description" example), like this:
84

Aloshi's avatar
Aloshi committed
85
```xml
86 87 88 89
	<elementTypeHere name="ExistingElementNameHere">
		... define properties here ...
	</elementTypeHere>
```
Aloshi's avatar
Aloshi committed
90

91
Or, you can create your own elements by adding `extra="true"` (as is done in the "my_image" example) like this:
Aloshi's avatar
Aloshi committed
92

Aloshi's avatar
Aloshi committed
93
```xml
94 95 96 97
	<elementTypeHere name="YourUniqueElementNameHere" extra="true">
		... define properties here ...
	</elementTypeHere>
```
Aloshi's avatar
Aloshi committed
98

99
"Extra" elements will be drawn in the order they are defined (so define backgrounds first!).  When they get drawn relative to the pre-existing elements depends on the view.  Make sure "extra" element names do not clash with existing element names!  An easy way to protect against this is to just start all your extra element names with some prefix like "e_".
100 101 102



103
*Properties* control how a particular *element* looks - for example, its position, size, image path, etc.  The type of the property determines what kinds of values you can use.  You can read about the types below in the "Reference" section.  Properties are defined like this:
Aloshi's avatar
Aloshi committed
104

Aloshi's avatar
Aloshi committed
105
```xml
106 107
		<propertyNameHere>ValueHere</propertyNameHere>
```
108 109 110 111




112 113
Advanced Features
=================
114

115
It is recommended that if you are writing a theme you launch EmulationStation with the `--debug` and `--windowed` switches.  This way you can read error messages without having to check the log file.  You can also reload the current gamelist view and system view with `Ctrl-R` if `--debug` is specified.
116

117
### The `<include>` tag
118

119
You can include theme files within theme files, similar to `#include` in C (though the internal mechanism is different, the effect is the same).  Example:
120

121
`~/.emulationstation/all_themes.xml`:
Aloshi's avatar
Aloshi committed
122
```xml
123
<theme>
124
	<formatVersion>3</formatVersion>
125 126 127 128 129 130 131 132
	<view name="detailed">
		<text name="description">
			<fontPath>./all_themes/myfont.ttf</fontPath>
			<color>00FF00</color>
		</text>
	</view>
</theme>
```
133

134
`~/.emulationstation/snes/theme.xml`:
Aloshi's avatar
Aloshi committed
135
```xml
136
<theme>
137
	<formatVersion>3</formatVersion>
138 139 140 141 142 143 144 145
	<include>./../all_themes.xml</include>
	<view name="detailed">
		<text name="description">
			<color>FF0000</color>
		</text>
	</view>
</theme>
```
146

147
Is equivalent to this `snes/theme.xml`:
Aloshi's avatar
Aloshi committed
148
```xml
149
<theme>
150
	<formatVersion>3</formatVersion>
151 152 153 154 155 156 157
	<view name="detailed">
		<text name="description">
			<fontPath>./all_themes/myfont.ttf</fontPath>
			<color>FF0000</color>
		</text>
	</view>
</theme>
158
```
159

160
Notice that properties that were not specified got merged (`<fontPath>`) and the `snes/theme.xml` could overwrite the included files' values (`<color>`).  Also notice the included file still needed the `<formatVersion>` tag.
161 162 163



164
### Theming multiple views simultaneously
165

166
Sometimes you want to apply the same properties to the same elements across multiple views.  The `name` attribute actually works as a list (delimited by any characters of `\t\r\n ,` - that is, whitespace and commas).  So, for example, to easily apply the same header to the basic, grid, and system views:
167

Aloshi's avatar
Aloshi committed
168
```xml
169
<theme>
170
	<formatVersion>3</formatVersion>
171
	<view name="basic, grid, system">
172
		<image name="logo">
173 174 175 176
			<path>./snes_art/snes_header.png</path>
		</image>
	</view>
	<view name="detailed">
177
		<image name="logo">
178 179 180 181 182
			<path>./snes_art/snes_header_detailed.png</path>
		</image>
	</view>
</theme>
```
183

184
This is equivalent to:
Aloshi's avatar
Aloshi committed
185
```xml
186
<theme>
187
	<formatVersion>3</formatVersion>
188
	<view name="basic">
189
		<image name="logo">
190 191 192 193
			<path>./snes_art/snes_header.png</path>
		</image>
	</view>
	<view name="detailed">
194
		<image name="logo">
195 196 197 198
			<path>./snes_art/snes_header_detailed.png</path>
		</image>
	</view>
	<view name="grid">
199
		<image name="logo">
200 201 202 203
			<path>./snes_art/snes_header.png</path>
		</image>
	</view>
	<view name="system">
204
		<image name="logo">
205 206 207
			<path>./snes_art/snes_header.png</path>
		</image>
	</view>
208
	... and any other view that might try to look up "logo" ...
209 210
</theme>
```
211 212


213

214
### Theming multiple elements simultaneously
215

216
You can theme multiple elements *of the same type* simultaneously.  The `name` attribute actually works as a list (delimited by any characters of `\t\r\n ,` - that is, whitespace and commas), just like it does for views, as long as the elements have the same type.  This is useful if you want to, say, apply the same color to all the metadata labels:
217 218 219

```xml
<theme>
220
    <formatVersion>3</formatVersion>
221
    <view name="detailed">
Aloshi's avatar
Aloshi committed
222
    	<!-- Weird spaces/newline on purpose! -->
223 224 225 226 227 228 229 230
    	<text name="md_lbl_rating, md_lbl_releasedate, md_lbl_developer, md_lbl_publisher, 
    	md_lbl_genre,    md_lbl_players,        md_lbl_lastplayed, md_lbl_playcount">
        	<color>48474D</color>
        </text>
    </view>
</theme>
```

231
Which is equivalent to:
232 233
```xml
<theme>
234
    <formatVersion>3</formatVersion>
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
    <view name="detailed">
    	<text name="md_lbl_rating">
    		<color>48474D</color>
    	</text>
    	<text name="md_lbl_releasedate">
    		<color>48474D</color>
    	</text>
    	<text name="md_lbl_developer">
    		<color>48474D</color>
    	</text>
    	<text name="md_lbl_publisher">
    		<color>48474D</color>
    	</text>
    	<text name="md_lbl_genre">
    		<color>48474D</color>
    	</text>
    	<text name="md_lbl_players">
    		<color>48474D</color>
    	</text>
    	<text name="md_lbl_lastplayed">
    		<color>48474D</color>
    	</text>
    	<text name="md_lbl_playcount">
    		<color>48474D</color>
    	</text>
    </view>
</theme>
```

Just remember, *this only works if the elements have the same type!*


267 268
Reference
=========
269

270
## Views, their elements, and themable properties:
271

272
#### basic
Aloshi's avatar
Aloshi committed
273 274
* `helpsystem name="help"` - ALL
	- The help system style for this view.
275 276
* `image name="background"` - ALL
	- This is a background image that exists for convenience. It goes from (0, 0) to (1, 1).
277 278 279
* `text name="logoText"` - ALL
	- Displays the name of the system.  Only present if no "logo" image is specified.  Displayed at the top of the screen, centered by default.
* `image name="logo"` - ALL
280 281 282 283 284
	- A header image.  If a non-empty `path` is specified, `text name="headerText"` will be hidden and this image will be, by default, displayed roughly in its place.
* `textlist name="gamelist"` - ALL
	- The gamelist.  `primaryColor` is for games, `secondaryColor` is for folders.  Centered by default.

---
285

286
#### detailed
Aloshi's avatar
Aloshi committed
287 288
* `helpsystem name="help"` - ALL
	- The help system style for this view.
289 290
* `image name="background"` - ALL
	- This is a background image that exists for convenience. It goes from (0, 0) to (1, 1).
291 292 293
* `text name="logoText"` - ALL
	- Displays the name of the system.  Only present if no "logo" image is specified.  Displayed at the top of the screen, centered by default.
* `image name="logo"` - ALL
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
	- A header image.  If a non-empty `path` is specified, `text name="headerText"` will be hidden and this image will be, by default, displayed roughly in its place.
* `textlist name="gamelist"` - ALL
	- The gamelist.  `primaryColor` is for games, `secondaryColor` is for folders.  Left aligned by default.

* Metadata
	* Labels
		* `text name="md_lbl_rating"` - ALL
		* `text name="md_lbl_releasedate"` - ALL
		* `text name="md_lbl_developer"` - ALL
		* `text name="md_lbl_publisher"` - ALL
		* `text name="md_lbl_genre"` - ALL
		* `text name="md_lbl_players"` - ALL
		* `text name="md_lbl_lastplayed"` - ALL
		* `text name="md_lbl_playcount"` - ALL

	* Values
		* All values will follow to the right of their labels if a position isn't specified.

		* `image name="md_image"` - POSITION | SIZE
Aloshi's avatar
Aloshi committed
313
			- Path is the "image" metadata for the currently selected game.
314
		* `rating name="md_rating"` - ALL
Aloshi's avatar
Aloshi committed
315
			- The "rating" metadata.
316
		* `datetime name="md_releasedate"` - ALL
Aloshi's avatar
Aloshi committed
317
			- The "releasedate" metadata.
318
		* `text name="md_developer"` - ALL
Aloshi's avatar
Aloshi committed
319
			- The "developer" metadata.
320
		* `text name="md_publisher"` - ALL
Aloshi's avatar
Aloshi committed
321
			- The "publisher" metadata.
322
		* `text name="md_genre"` - ALL
Aloshi's avatar
Aloshi committed
323
			- The "genre" metadata.
324
		* `text name="md_players"` - ALL
Aloshi's avatar
Aloshi committed
325
			- The "players" metadata (number of players the game supports).
326
		* `datetime name="md_lastplayed"` - ALL
Aloshi's avatar
Aloshi committed
327
			- The "lastplayed" metadata.  Displayed as a string representing the time relative to "now" (e.g. "3 hours ago").
328
		* `text name="md_playcount"` - ALL
Aloshi's avatar
Aloshi committed
329
			- The "playcount" metadata (number of times the game has been played).
330
		* `text name="md_description"` - POSITION | SIZE | FONT_PATH | FONT_SIZE | COLOR
Aloshi's avatar
Aloshi committed
331
			- Text is the "desc" metadata.  If no `pos`/`size` is specified, will move and resize to fit under the lowest label and reach to the bottom of the screen.
332 333

---
334

335
#### grid
Aloshi's avatar
Aloshi committed
336 337
* `helpsystem name="help"` - ALL
	- The help system style for this view.
338 339
* `image name="background"` - ALL
	- This is a background image that exists for convenience. It goes from (0, 0) to (1, 1).
340 341 342
* `text name="logoText"` - ALL
	- Displays the name of the system.  Only present if no "logo" image is specified.  Displayed at the top of the screen, centered by default.
* `image name="logo"` - ALL
343 344 345
	- A header image.  If a non-empty `path` is specified, `text name="headerText"` will be hidden and this image will be, by default, displayed roughly in its place.

---
346

347
#### system
Aloshi's avatar
Aloshi committed
348 349
* `helpsystem name="help"` - ALL
	- The help system style for this view.
350 351
* `image name="logo"` - PATH
	- A logo image, to be displayed in the system logo carousel.
352
* You can use extra elements (elements with `extra="true"`) to add your own backgrounds, etc.  They will be displayed behind the carousel, and scroll relative to the carousel.
353

354

Aloshi's avatar
Aloshi committed
355 356
## Types of properties:

357
* NORMALIZED_PAIR - two decimals, in the range [0..1], delimited by a space.  For example, `0.25 0.5`.  Most commonly used for position (x and y coordinates) and size (width and height).
358
* PATH - a path.  If the first character is a `~`, it will be expanded into the environment variable for the home path (`$HOME` for Linux or `%HOMEPATH%` for Windows).  If the first character is a `.`, it will be expanded to the theme file's directory, allowing you to specify resources relative to the theme file, like so: `./../general_art/myfont.ttf`.
Aloshi's avatar
Aloshi committed
359 360 361 362 363 364
* BOOLEAN - `true`/`1` or `false`/`0`.
* COLOR - a hexidecimal RGB or RGBA color (6 or 8 digits).  If 6 digits, will assume the alpha channel is `FF` (not transparent).
* FLOAT - a decimal.
* STRING - a string of text.


365 366
## Types of elements and their properties:

367 368 369 370
Common to almost all elements is a `pos` and `size` property of the NORMALIZED_PAIR type.  They are normalized in terms of their "parent" object's size; 99% of the time, this is just the size of the screen.  In this case, `<pos>0 0</pos>` would correspond to the top left corner, and `<pos>1 1</pos>` the bottom right corner (a positive Y value points further down).  `pos` almost always refers to the top left corner of your element.  You *can* use numbers outside of the [0..1] range if you want to place an element partially or completely off-screen.

The order you define properties in does not matter.
Remember, you do *not* need to specify every property!
371
*Note that a view may choose to only make only certain properties on a particular element themable!*
372

373
#### image
374 375 376 377 378

Can be created as an extra.

* `pos` - type: NORMALIZED_PAIR.
* `size` - type: NORMALIZED_PAIR.
379
	- If only one axis is specified (and the other is zero), the other will be automatically calculated in accordance with the image's aspect ratio.
380 381 382
* `maxSize` - type: NORMALIZED_PAIR.
	- The image will be resized as large as possible so that it fits within this size and maintains its aspect ratio.  Use this instead of `size` when you don't know what kind of image you're using so it doesn't get grossly oversized on one axis (e.g. with a game's image metadata).
* `origin` - type: NORMALIZED_PAIR.
383
	- Where on the image `pos` refers to.  For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the image exactly in the middle of the screen.  If the "POSITION" and "SIZE" attributes are themable, "ORIGIN" is implied.
384 385 386 387
* `path` - type: PATH.
	- Path to the image file.  Most common extensions are supported (including .jpg, .png, and unanimated .gif).
* `tile` - type: BOOLEAN.
	- If true, the image will be tiled instead of stretched to fit its size.  Useful for backgrounds.
388
* `color` - type: COLOR.
389
	- Multiply each pixel's color by this color. For example, an all-white image with `<color>FF0000</color>` would become completely red.  You can also control the transparency of an image with `<color>FFFFFFAA</color>` - keeping all the pixels their normal color and only affecting the alpha channel.
390 391

#### text
392 393 394 395 396

Can be created as an extra.

* `pos` - type: NORMALIZED_PAIR.
* `size` - type: NORMALIZED_PAIR.
397 398 399 400
	- Possible combinations:
	- `0 0` - automatically size so text fits on one line (expanding horizontally).
	- `w 0` - automatically wrap text so it doesn't go beyond `w` (expanding vertically).
	- `w h` - works like a "text box."  If `h` is non-zero and `h` <= `fontSize` (implying it should be a single line of text), text that goes beyond `w` will be truncated with an elipses (...).
401 402 403 404 405 406
* `text` - type: STRING.
* `color` - type: COLOR.
* `fontPath` - type: PATH.
	- Path to a truetype font (.ttf).
* `fontSize` - type: FLOAT.
	- Size of the font as a percentage of screen height (e.g. for a value of `0.1`, the text's height would be 10% of the screen height).
407 408
* `alignment` - type: STRING.
	- Valid values are "left", "center", or "right".  Controls alignment on the X axis.  "center" will also align vertically.
409
* `forceUppercase` - type: BOOLEAN.  Draw text in uppercase.
410
* `lineSpacing` - type: FLOAT.  Controls the space between lines (as a multiple of font height).  Default is 1.5.
411 412

#### textlist
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427

* `pos` - type: NORMALIZED_PAIR.
* `size` - type: NORMALIZED_PAIR.
* `selectorColor` - type: COLOR.
	- Color of the "selector bar."
* `selectedColor` - type: COLOR.
	- Color of the highlighted entry text.
* `primaryColor` - type: COLOR.
	- Primary color; what this means depends on the text list.  For example, for game lists, it is the color of a game.
* `secondaryColor` - type: COLOR.
	- Secondary color; what this means depends on the text list.  For example, for game lists, it is the color of a folder.
* `fontPath` - type: PATH.
* `fontSize` - type: FLOAT.
* `scrollSound` - type: PATH.
	- Sound that is played when the list is scrolled.
428 429 430 431
* `alignment` - type: STRING.
	- Valid values are "left", "center", or "right".  Controls alignment on the X axis.
* `horizontalMargin` - type: FLOAT.
	- Horizontal offset for text from the alignment point.  If `alignment` is "left", offsets the text to the right.  If `alignment` is "right", offsets text to the left.  No effect if `alignment` is "center".  Given as a percentage of the element's parent's width (same unit as `size`'s X value).
432
* `forceUppercase` - type: BOOLEAN.  Draw text in uppercase.
433
* `lineSpacing` - type: FLOAT.  Controls the space between lines (as a multiple of font height).  Default is 1.5.
434 435 436

#### ninepatch

437 438 439 440 441
* `pos` - type: NORMALIZED_PAIR.
* `size` - type: NORMALIZED_PAIR.
* `path` - type: PATH.

EmulationStation borrows the concept of "nine patches" from Android (or "9-Slices"). Currently the implementation is very simple and hard-coded to only use 48x48px images (16x16px for each "patch"). Check the `data/resources` directory for some examples (button.png, frame.png).
442

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
#### rating

* `pos` - type: NORMALIZED_PAIR.
* `size` - type: NORMALIZED_PAIR.
	- Only one value is actually used. The other value should be zero.  (e.g. specify width OR height, but not both.  This is done to maintain the aspect ratio.)
* `filledPath` - type: PATH.
	- Path to the "filled star" image.  Image must be square (width equals height).
* `unfilledPath` - type: PATH.
	- Path to the "unfilled star" image.  Image must be square (width equals height).

#### datetime

* `pos` - type: NORMALIZED_PAIR.
* `size` - type: NORMALIZED_PAIR.
	- You should probably not set this.  Leave it to `fontSize`.
* `color` - type: COLOR.
* `fontPath` - type: PATH.
* `fontSize` - type: FLOAT.
461
* `forceUppercase` - type: BOOLEAN.  Draw text in uppercase.
462

463
#### sound
464 465 466

* `path` - type: PATH.
	- Path to the sound file.  Only .wav files are currently supported.
467

Aloshi's avatar
Aloshi committed
468 469
#### helpsystem

470
* `pos` - type: NORMALIZED_PAIR.  Default is "0.012 0.9515"
471 472
* `textColor` - type: COLOR.  Default is 777777FF.
* `iconColor` - type: COLOR.  Default is 777777FF.
Aloshi's avatar
Aloshi committed
473 474
* `fontPath` - type: PATH.
* `fontSize` - type: FLOAT.
475

Aloshi's avatar
Aloshi committed
476
The help system is a special element that displays a context-sensitive list of actions the user can take at any time.  You should try and keep the position constant throughout every screen.  Keep in mind the "default" settings (including position) are used whenever the user opens a menu.
477

Aloshi's avatar
Aloshi committed
478
[*Check out the "official" themes for some more examples!*](http://aloshi.com/emulationstation#themes)