extracted code branching from ItemsList drawing and main drawing method
[open-ps2-loader.git] / src / themes.c
blob43864c713ca7b421ab4f0330f2f4d5c05119363d
1 #include "include/usbld.h"
2 #include "include/themes.h"
3 #include "include/util.h"
4 #include "include/gui.h"
5 #include "include/renderman.h"
6 #include "include/textures.h"
7 #include "include/ioman.h"
8 #include "include/fntsys.h"
9 #include "include/lang.h"
11 #define MENU_POS_V 50
12 #define HINT_HEIGHT 32
13 #define DECORATOR_SIZE 20
15 theme_t* gTheme;
17 static int screenWidth;
18 static int screenHeight;
19 static int guiThemeID = 0;
21 static int nThemes = 0;
22 static theme_file_t themes[THM_MAX_FILES];
23 static char **guiThemesNames = NULL;
25 #define TYPE_ATTRIBUTE_TEXT 0
26 #define TYPE_STATIC_TEXT 1
27 #define TYPE_ATTRIBUTE_IMAGE 2
28 #define TYPE_GAME_IMAGE 3
29 #define TYPE_STATIC_IMAGE 4
30 #define TYPE_BACKGROUND 5
31 #define TYPE_MENU_ICON 6
32 #define TYPE_MENU_TEXT 7
33 #define TYPE_ITEMS_LIST 8
34 #define TYPE_ITEM_ICON 9
35 #define TYPE_ITEM_COVER 10
36 #define TYPE_ITEM_TEXT 11
37 #define TYPE_HINT_TEXT 12
38 #define TYPE_LOADING_ICON 13
40 #define DISPLAY_ALWAYS 0
41 #define DISPLAY_DEFINED 1
42 #define DISPLAY_NEVER 2
44 #define SIZING_NONE -1
45 #define SIZING_CLIP 0
46 #define SIZING_WRAP 1
48 static char *elementsType[] = {
49 "AttributeText",
50 "StaticText",
51 "AttributeImage",
52 "GameImage",
53 "StaticImage",
54 "Background",
55 "MenuIcon",
56 "MenuText",
57 "ItemsList",
58 "ItemIcon",
59 "ItemCover",
60 "ItemText",
61 "HintText",
62 "LoadingIcon",
65 // Common functions for Text ////////////////////////////////////////////////////////////////////////////////////////////////
67 static void endMutableText(theme_element_t* elem) {
68 mutable_text_t* mutableText = (mutable_text_t*) elem->extended;
69 if (mutableText) {
70 if (mutableText->value)
71 free(mutableText->value);
73 if (mutableText->alias)
74 free(mutableText->alias);
76 free(mutableText);
79 free(elem);
82 static mutable_text_t* initMutableText(char* themePath, config_set_t* themeConfig, theme_t* theme, char* name, int type, struct theme_element* elem,
83 char* value, char* alias, int displayMode, int sizingMode) {
85 mutable_text_t* mutableText = (mutable_text_t*) malloc(sizeof(mutable_text_t));
86 mutableText->currentItemId = -1;
87 mutableText->currentValue = NULL;
88 mutableText->alias = NULL;
90 char elemProp[64];
92 snprintf(elemProp, 64, "%s_display", name);
93 configGetInt(themeConfig, elemProp, &displayMode);
94 mutableText->displayMode = displayMode;
96 int length = strlen(value) + 1;
97 mutableText->value = (char*) malloc(length * sizeof(char));
98 memcpy(mutableText->value, value, length);
100 snprintf(elemProp, 64, "%s_wrap", name);
101 if (configGetInt(themeConfig, elemProp, &sizingMode)) {
102 if (sizingMode > 0)
103 mutableText->sizingMode = SIZING_WRAP;
106 if ((elem->width != DIM_UNDEF) || (elem->height != DIM_UNDEF)) {
107 if (sizingMode == SIZING_NONE)
108 sizingMode = SIZING_CLIP;
110 if (elem->width == DIM_UNDEF)
111 elem->width = screenWidth;
113 if (elem->height == DIM_UNDEF)
114 elem->height = screenHeight;
115 } else
116 sizingMode = SIZING_NONE;
117 mutableText->sizingMode = sizingMode;
119 if (type == TYPE_ATTRIBUTE_TEXT) {
120 snprintf(elemProp, 64, "%s_title", name);
121 configGetStr(themeConfig, elemProp, &alias);
122 if (!alias) {
123 if (value[0] == '#')
124 alias = &value[1];
125 else
126 alias = value;
128 length = strlen(alias) + 1 + 3;
129 mutableText->alias = (char*) malloc(length * sizeof(char));
130 if (mutableText->sizingMode == SIZING_WRAP)
131 snprintf(mutableText->alias, length, "%s :\n", alias);
132 else
133 snprintf(mutableText->alias, length, "%s : ", alias);
134 } else {
135 if (mutableText->sizingMode == SIZING_WRAP)
136 fntFitString(elem->font, mutableText->value, elem->width);
139 return mutableText;
142 // StaticText ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
144 static void drawStaticText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
145 mutable_text_t* mutableText = (mutable_text_t*) elem->extended;
146 if (mutableText->sizingMode == SIZING_NONE)
147 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, mutableText->value, elem->color);
148 else
149 fntRenderText(elem->font, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, mutableText->value, elem->color);
152 static void initStaticText(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
153 char* value) {
155 char elemProp[64];
157 snprintf(elemProp, 64, "%s_value", name);
158 configGetStr(themeConfig, elemProp, &value);
159 if (value) {
160 elem->extended = initMutableText(themePath, themeConfig, theme, name, TYPE_STATIC_TEXT, elem, value, NULL, DISPLAY_ALWAYS, SIZING_NONE);
161 elem->endElem = &endMutableText;
162 elem->drawElem = &drawStaticText;
163 } else
164 LOG("elemStaticText %s: NO value, elem disabled !!\n", name);
167 // AttributeText ////////////////////////////////////////////////////////////////////////////////////////////////////////////
169 static void drawAttributeText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
170 if (config) {
171 mutable_text_t* mutableText = (mutable_text_t*) elem->extended;
172 if (mutableText->currentItemId != item->item.id) {
173 // force refresh
174 mutableText->currentItemId = item->item.id;
175 mutableText->currentValue = NULL;
176 if (configGetStr(config, mutableText->value, &mutableText->currentValue)) {
177 if (mutableText->sizingMode == SIZING_WRAP)
178 fntFitString(elem->font, mutableText->currentValue, elem->width);
181 if (mutableText->currentValue) {
182 if (mutableText->displayMode == DISPLAY_NEVER)
183 if (mutableText->sizingMode == SIZING_NONE)
184 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, mutableText->currentValue, elem->color);
185 else
186 fntRenderText(elem->font, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, mutableText->currentValue, elem->color);
187 else {
188 char result[300];
189 snprintf(result, 300, "%s%s", mutableText->alias, mutableText->currentValue);
190 if (mutableText->sizingMode == SIZING_NONE)
191 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, result, elem->color);
192 else
193 fntRenderText(elem->font, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, result, elem->color);
195 } else if (mutableText->displayMode == DISPLAY_ALWAYS)
196 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, mutableText->alias, elem->color);
200 static void initAttributeText(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
201 char* attribute) {
203 char elemProp[64];
205 snprintf(elemProp, 64, "%s_attribute", name);
206 configGetStr(themeConfig, elemProp, &attribute);
207 if (attribute) {
208 elem->extended = initMutableText(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_TEXT, elem, attribute, NULL, DISPLAY_ALWAYS, SIZING_NONE);
209 elem->endElem = &endMutableText;
210 elem->drawElem = &drawAttributeText;
211 } else
212 LOG("elemAttributeText %s: NO attribute, elem disabled !!\n", name);
215 // Common functions for Image ///////////////////////////////////////////////////////////////////////////////////////////////
217 static void findDuplicate(theme_element_t* first, char* cachePattern, char* defaultTexture, char* overlayTexture, mutable_image_t* target) {
218 theme_element_t* elem = first;
219 while (elem) {
220 if ((elem->type == TYPE_STATIC_IMAGE) || (elem->type == TYPE_ATTRIBUTE_IMAGE) || (elem->type == TYPE_GAME_IMAGE) || (elem->type == TYPE_BACKGROUND)) {
221 mutable_image_t* source = (mutable_image_t*) elem->extended;
223 if (cachePattern && source->cache && !strcmp(cachePattern, source->cache->suffix)) {
224 target->cache = source->cache;
225 target->cacheLinked = 1;
226 LOG("Re-using a cache for pattern %s\n", cachePattern);
229 if (defaultTexture && source->defaultTexture && !strcmp(defaultTexture, source->defaultTexture->name)) {
230 target->defaultTexture = source->defaultTexture;
231 target->defaultTextureLinked = 1;
232 LOG("Re-using the default texture for %s\n", defaultTexture);
235 if (overlayTexture && source->overlayTexture && !strcmp(overlayTexture, source->overlayTexture->name)) {
236 target->overlayTexture = source->overlayTexture;
237 target->overlayTextureLinked = 1;
238 LOG("Re-using the overlay texture for %s\n", overlayTexture);
242 elem = elem->next;
246 static void freeImageTexture(image_texture_t* texture) {
247 if (texture) {
248 if (texture->source.Mem)
249 free(texture->source.Mem);
251 free(texture->name);
253 free(texture);
257 static image_texture_t* initImageTexture(char* themePath, config_set_t* themeConfig, char* name, char* imgName, int isOverlay) {
258 image_texture_t* texture = (image_texture_t*) malloc(sizeof(image_texture_t));
259 texPrepare(&texture->source, isOverlay ? GS_PSM_CT32 : GS_PSM_CT24);
260 texture->name = NULL;
262 char path[255];
263 snprintf(path, 255, "%s%s", themePath, imgName);
264 if (texDiscoverLoad(&texture->source, path, -1, isOverlay ? GS_PSM_CT32 : GS_PSM_CT24) >= 0) {
265 int length = strlen(imgName) + 1;
266 texture->name = (char*) malloc(length * sizeof(char));
267 memcpy(texture->name, imgName, length);
269 if (isOverlay) {
270 int intValue;
271 char elemProp[64];
272 snprintf(elemProp, 64, "%s_overlay_ulx", name);
273 if (configGetInt(themeConfig, elemProp, &intValue))
274 texture->upperLeft_x = intValue;
275 snprintf(elemProp, 64, "%s_overlay_uly", name);
276 if (configGetInt(themeConfig, elemProp, &intValue))
277 texture->upperLeft_y = intValue;
278 snprintf(elemProp, 64, "%s_overlay_urx", name);
279 if (configGetInt(themeConfig, elemProp, &intValue))
280 texture->upperRight_x = intValue;
281 snprintf(elemProp, 64, "%s_overlay_ury", name);
282 if (configGetInt(themeConfig, elemProp, &intValue))
283 texture->upperRight_y = intValue;
284 snprintf(elemProp, 64, "%s_overlay_llx", name);
285 if (configGetInt(themeConfig, elemProp, &intValue))
286 texture->lowerLeft_x = intValue;
287 snprintf(elemProp, 64, "%s_overlay_lly", name);
288 if (configGetInt(themeConfig, elemProp, &intValue))
289 texture->lowerLeft_y = intValue;
290 snprintf(elemProp, 64, "%s_overlay_lrx", name);
291 if (configGetInt(themeConfig, elemProp, &intValue))
292 texture->lowerRight_x = intValue;
293 snprintf(elemProp, 64, "%s_overlay_lry", name);
294 if (configGetInt(themeConfig, elemProp, &intValue))
295 texture->lowerRight_y = intValue;
297 } else {
298 freeImageTexture(texture);
299 texture = NULL;
302 return texture;
305 static void endMutableImage(struct theme_element* elem) {
306 mutable_image_t* mutableImage = (mutable_image_t*) elem->extended;
307 if (mutableImage) {
308 if (mutableImage->cache && !mutableImage->cacheLinked)
309 cacheDestroyCache(mutableImage->cache);
311 if (mutableImage->defaultTexture && !mutableImage->defaultTextureLinked)
312 freeImageTexture(mutableImage->defaultTexture);
314 if (mutableImage->overlayTexture && !mutableImage->overlayTextureLinked)
315 freeImageTexture(mutableImage->overlayTexture);
317 free(mutableImage);
320 free(elem);
323 static mutable_image_t* initMutableImage(char* themePath, config_set_t* themeConfig, theme_t* theme, char* name, int type,
324 char* cachePattern, int cacheCount, char* defaultTexture, char* overlayTexture) {
326 mutable_image_t* mutableImage = (mutable_image_t*) malloc(sizeof(mutable_image_t));
327 mutableImage->currentUid = -1;
328 mutableImage->currentItemId = -1;
329 mutableImage->currentValue = NULL;
330 mutableImage->cache = NULL;
331 mutableImage->cacheLinked = 0;
332 mutableImage->defaultTexture = NULL;
333 mutableImage->defaultTextureLinked = 0;
334 mutableImage->overlayTexture = NULL;
335 mutableImage->overlayTextureLinked = 0;
337 char elemProp[64];
339 if (type == TYPE_ATTRIBUTE_IMAGE) {
340 snprintf(elemProp, 64, "%s_attribute", name);
341 configGetStr(themeConfig, elemProp, &cachePattern);
342 LOG("elemMutableImage %s: type: %d using cache pattern: %s\n", name, type, cachePattern);
343 } else if ((type == TYPE_GAME_IMAGE) || type == (TYPE_BACKGROUND)) {
344 snprintf(elemProp, 64, "%s_pattern", name);
345 configGetStr(themeConfig, elemProp, &cachePattern);
346 snprintf(elemProp, 64, "%s_count", name);
347 configGetInt(themeConfig, elemProp, &cacheCount);
348 LOG("elemMutableImage %s: type: %d using cache pattern: %s\n", name, type, cachePattern);
351 snprintf(elemProp, 64, "%s_default", name);
352 configGetStr(themeConfig, elemProp, &defaultTexture);
354 if (type != TYPE_BACKGROUND) {
355 snprintf(elemProp, 64, "%s_overlay", name);
356 configGetStr(themeConfig, elemProp, &overlayTexture);
359 findDuplicate(theme->mainElems.first, cachePattern, defaultTexture, overlayTexture, mutableImage);
360 findDuplicate(theme->infoElems.first, cachePattern, defaultTexture, overlayTexture, mutableImage);
362 if (cachePattern && !mutableImage->cache) {
363 if (type == TYPE_ATTRIBUTE_IMAGE)
364 mutableImage->cache = cacheInitCache(-1, themePath, 0, cachePattern, 1);
365 else
366 mutableImage->cache = cacheInitCache(theme->gameCacheCount++, "ART", 1, cachePattern, cacheCount);
369 if (defaultTexture && !mutableImage->defaultTexture)
370 mutableImage->defaultTexture = initImageTexture(themePath, themeConfig, name, defaultTexture, 0);
372 if (overlayTexture && !mutableImage->overlayTexture)
373 mutableImage->overlayTexture = initImageTexture(themePath, themeConfig, name, overlayTexture, 1);
375 return mutableImage;
378 // StaticImage //////////////////////////////////////////////////////////////////////////////////////////////////////////////
380 static void drawStaticImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
381 mutable_image_t* staticImage = (mutable_image_t*) elem->extended;
382 if (staticImage->overlayTexture) {
383 rmDrawOverlayPixmap(&staticImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
384 &staticImage->defaultTexture->source, staticImage->overlayTexture->upperLeft_x, staticImage->overlayTexture->upperLeft_y, staticImage->overlayTexture->upperRight_x, staticImage->overlayTexture->upperRight_y,
385 staticImage->overlayTexture->lowerLeft_x, staticImage->overlayTexture->lowerLeft_y, staticImage->overlayTexture->lowerRight_x, staticImage->overlayTexture->lowerRight_y);
386 } else
387 rmDrawPixmap(&staticImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
390 static void initStaticImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
391 char* imageName) {
393 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, NULL, 0, imageName, NULL);
394 elem->extended = mutableImage;
395 elem->endElem = &endMutableImage;
397 if (mutableImage->defaultTexture)
398 elem->drawElem = &drawStaticImage;
399 else
400 LOG("elemStaticImage %s: NO image name, elem disabled !!\n", name);
403 // GameImage ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
405 static GSTEXTURE* getGameImageTexture(image_cache_t* cache, void* support, struct submenu_item* item) {
406 if (gEnableArt) {
407 item_list_t * list = (item_list_t *) support;
408 char* startup = list->itemGetStartup(item->id);
409 //LOG("getGameCachedTex, prefix: %s addsep: %d value: %s suffix: %s\n", cache->prefix, cache->addSeparator, startup, suffix);
410 return cacheGetTexture(cache, list, &item->cache_id[cache->userId], &item->cache_uid[cache->userId], startup);
413 return NULL;
416 static void drawGameImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
417 mutable_image_t* gameImage = (mutable_image_t*) elem->extended;
418 if (item) {
419 GSTEXTURE* texture = getGameImageTexture(gameImage->cache, menu->item->userdata, &item->item);
420 if (!texture || !texture->Mem) {
421 if (gameImage->defaultTexture)
422 texture = &gameImage->defaultTexture->source;
423 else {
424 if (elem->type == TYPE_BACKGROUND)
425 guiDrawBGPlasma();
426 return;
430 if (gameImage->overlayTexture) {
431 rmDrawOverlayPixmap(&gameImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
432 texture, gameImage->overlayTexture->upperLeft_x, gameImage->overlayTexture->upperLeft_y, gameImage->overlayTexture->upperRight_x, gameImage->overlayTexture->upperRight_y,
433 gameImage->overlayTexture->lowerLeft_x, gameImage->overlayTexture->lowerLeft_y, gameImage->overlayTexture->lowerRight_x, gameImage->overlayTexture->lowerRight_y);
434 } else
435 rmDrawPixmap(texture, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
437 } else if (elem->type == TYPE_BACKGROUND) {
438 if (gameImage->defaultTexture)
439 rmDrawPixmap(&gameImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
440 else
441 guiDrawBGPlasma();
445 static void initGameImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
446 char* pattern, int count, char* texture, char* overlay) {
448 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, pattern, count, texture, overlay);
449 elem->extended = mutableImage;
450 elem->endElem = &endMutableImage;
452 if (mutableImage->cache)
453 elem->drawElem = &drawGameImage;
454 else
455 LOG("elemGameImage %s: NO pattern, elem disabled !!\n", name);
458 // AttributeImage ///////////////////////////////////////////////////////////////////////////////////////////////////////////
460 static void drawAttributeImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
461 if (config) {
462 mutable_image_t* attributeImage = (mutable_image_t*) elem->extended;
463 if (attributeImage->currentItemId != item->item.id) {
464 // force refresh
465 attributeImage->currentUid = -1;
466 attributeImage->currentItemId = item->item.id;
467 attributeImage->currentValue = NULL;
468 configGetStr(config, attributeImage->cache->suffix, &attributeImage->currentValue);
470 if (attributeImage->currentValue) {
471 int posZ = 0;
472 GSTEXTURE* texture = cacheGetTexture(attributeImage->cache, menu->item->userdata, &posZ, &attributeImage->currentUid, attributeImage->currentValue);
473 if (texture && texture->Mem) {
474 if (attributeImage->overlayTexture) {
475 rmDrawOverlayPixmap(&attributeImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
476 texture, attributeImage->overlayTexture->upperLeft_x, attributeImage->overlayTexture->upperLeft_y, attributeImage->overlayTexture->upperRight_x, attributeImage->overlayTexture->upperRight_y,
477 attributeImage->overlayTexture->lowerLeft_x, attributeImage->overlayTexture->lowerLeft_y, attributeImage->overlayTexture->lowerRight_x, attributeImage->overlayTexture->lowerRight_y);
478 } else
479 rmDrawPixmap(texture, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
481 return;
485 if (attributeImage->defaultTexture)
486 rmDrawPixmap(&attributeImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
490 static void initAttributeImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name) {
491 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, NULL, 1, NULL, NULL);
492 elem->extended = mutableImage;
493 elem->endElem = &endMutableImage;
495 if (mutableImage->cache)
496 elem->drawElem = &drawAttributeImage;
497 else
498 LOG("elemAttributeImage %s: NO attribute, elem disabled !!\n", name);
501 // BasicElement /////////////////////////////////////////////////////////////////////////////////////////////////////////////
503 static void endBasic(theme_element_t* elem) {
504 if (elem->extended)
505 free(elem->extended);
507 free(elem);
510 static theme_element_t* initBasic(char* themePath, config_set_t* themeConfig, theme_t* theme,
511 char* name, int type, int x, int y, short aligned, int w, int h, short scaled, u64 color, int font) {
513 int intValue;
514 unsigned char charColor[3];
515 char* temp;
516 char elemProp[64];
518 theme_element_t* elem = (theme_element_t*) malloc(sizeof(theme_element_t));
520 elem->type = type;
521 elem->extended = NULL;
522 elem->drawElem = NULL;
523 elem->endElem = &endBasic;
524 elem->next = NULL;
526 snprintf(elemProp, 64, "%s_x", name);
527 if (configGetStr(themeConfig, elemProp, &temp)) {
528 if (!strncmp(temp, "POS_MID", 7))
529 x = screenWidth >> 1;
530 else
531 x = atoi(temp);
533 if (x < 0)
534 elem->posX = screenWidth + x;
535 else
536 elem->posX = x;
538 snprintf(elemProp, 64, "%s_y", name);
539 if (configGetStr(themeConfig, elemProp, &temp)) {
540 if (!strncmp(temp, "POS_MID", 7))
541 y = screenHeight >> 1;
542 else
543 y = atoi(temp);
545 if (y < 0)
546 elem->posY = ceil((screenHeight + y) * theme->usedHeight / screenHeight);
547 else
548 elem->posY = y;
550 snprintf(elemProp, 64, "%s_width", name);
551 if (configGetStr(themeConfig, elemProp, &temp)) {
552 if (!strncmp(temp, "DIM_INF", 7))
553 elem->width = screenWidth;
554 else
555 elem->width = atoi(temp);
556 } else
557 elem->width = w;
559 snprintf(elemProp, 64, "%s_height", name);
560 if (configGetStr(themeConfig, elemProp, &temp)) {
561 if (!strncmp(temp, "DIM_INF", 7))
562 elem->height = screenHeight;
563 else
564 elem->height = atoi(temp);
565 } else
566 elem->height = h;
568 snprintf(elemProp, 64, "%s_aligned", name);
569 if (configGetInt(themeConfig, elemProp, &intValue))
570 elem->aligned = intValue;
571 else
572 elem->aligned = aligned;
574 snprintf(elemProp, 64, "%s_scaled", name);
575 if (configGetInt(themeConfig, elemProp, &intValue))
576 elem->scaled = intValue;
577 else
578 elem->scaled = scaled;
580 snprintf(elemProp, 64, "%s_color", name);
581 if (configGetColor(themeConfig, elemProp, charColor))
582 elem->color = GS_SETREG_RGBA(charColor[0], charColor[1], charColor[2], 0xff);
583 else
584 elem->color = color;
586 snprintf(elemProp, 64, "%s_font", name);
587 if (configGetInt(themeConfig, elemProp, &intValue))
588 font = intValue;
589 if (font >= 0 && font < THM_MAX_FONTS)
590 elem->font = theme->fonts[font];
591 else
592 elem->font = FNT_DEFAULT;
594 return elem;
597 // Internal elements ////////////////////////////////////////////////////////////////////////////////////////////////////////
599 static void drawBackground(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
600 guiDrawBGPlasma();
603 static void initBackground(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
604 char* pattern, int count, char* texture) {
606 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, pattern, count, texture, NULL);
607 elem->extended = mutableImage;
608 elem->endElem = &endMutableImage;
610 if (mutableImage->cache)
611 elem->drawElem = &drawGameImage;
612 else if (mutableImage->defaultTexture)
613 elem->drawElem = &drawStaticImage;
614 else
615 elem->drawElem = &drawBackground;
618 static void drawMenuIcon(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
619 GSTEXTURE* menuIconTex = thmGetTexture(menu->item->icon_id);
620 if (menuIconTex && menuIconTex->Mem)
621 rmDrawPixmap(menuIconTex, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
624 static void drawMenuText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
625 GSTEXTURE* leftIconTex = NULL, *rightIconTex = NULL;
626 if (menu->prev)
627 leftIconTex = thmGetTexture(LEFT_ICON);
628 if (menu->next)
629 rightIconTex = thmGetTexture(RIGHT_ICON);
631 if (elem->aligned) {
632 int offset = elem->width >> 1;
633 if (leftIconTex && leftIconTex->Mem)
634 rmDrawPixmap(leftIconTex, elem->posX - offset, elem->posY, elem->aligned, leftIconTex->Width, leftIconTex->Height, elem->scaled, gDefaultCol);
635 if (rightIconTex && rightIconTex->Mem)
636 rmDrawPixmap(rightIconTex, elem->posX + offset, elem->posY, elem->aligned, rightIconTex->Width, rightIconTex->Height, elem->scaled, gDefaultCol);
638 else {
639 if (leftIconTex && leftIconTex->Mem)
640 rmDrawPixmap(leftIconTex, elem->posX - leftIconTex->Width, elem->posY, elem->aligned, leftIconTex->Width, leftIconTex->Height, elem->scaled, gDefaultCol);
641 if (rightIconTex && rightIconTex->Mem)
642 rmDrawPixmap(rightIconTex, elem->posX + elem->width, elem->posY, elem->aligned, rightIconTex->Width, rightIconTex->Height, elem->scaled, gDefaultCol);
644 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, menuItemGetText(menu->item), elem->color);
647 static void drawItemsList(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
648 if (item) {
649 items_list_t* itemsList = (items_list_t*) elem->extended;
651 int posX = elem->posX, posY = elem->posY;
652 if (elem->aligned) {
653 posX -= elem->width >> 1;
654 posY -= elem->height >> 1;
657 submenu_list_t *ps = menu->item->pagestart;
658 int others = 0;
659 u64 color;
660 while (ps && (others++ < itemsList->displayedItems)) {
661 if (ps == item)
662 color = gTheme->selTextColor;
663 else
664 color = elem->color;
666 if (itemsList->decoratorImage) {
667 GSTEXTURE* itemIconTex = getGameImageTexture(itemsList->decoratorImage->cache, menu->item->userdata, &ps->item);
668 if (itemIconTex && itemIconTex->Mem)
669 rmDrawPixmap(itemIconTex, posX, posY, ALIGN_NONE, DECORATOR_SIZE, DECORATOR_SIZE, elem->scaled, gDefaultCol);
670 else {
671 if (itemsList->decoratorImage->defaultTexture)
672 rmDrawPixmap(&itemsList->decoratorImage->defaultTexture->source, posX, posY, ALIGN_NONE, DECORATOR_SIZE, DECORATOR_SIZE, elem->scaled, gDefaultCol);
674 fntRenderText(elem->font, posX + DECORATOR_SIZE, posY, ALIGN_NONE, elem->width, elem->height, submenuItemGetText(&ps->item), color);
675 } else
676 fntRenderText(elem->font, posX, posY, ALIGN_NONE, elem->width, elem->height, submenuItemGetText(&ps->item), color);
678 posY += MENU_ITEM_HEIGHT;
679 ps = ps->next;
684 static void initItemsList(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name, char* decorator) {
685 char elemProp[64];
687 items_list_t* itemsList = (items_list_t*) malloc(sizeof(items_list_t));
689 if (elem->width == DIM_UNDEF)
690 elem->width = screenWidth;
692 if (elem->height == DIM_UNDEF)
693 elem->height = theme->usedHeight - (MENU_POS_V + HINT_HEIGHT);
695 itemsList->displayedItems = elem->height / MENU_ITEM_HEIGHT;
696 LOG("elemItemsList %s: displaying %d elems, item height: %d\n", name, itemsList->displayedItems, elem->height);
698 itemsList->decorator = NULL;
699 snprintf(elemProp, 64, "%s_decorator", name);
700 configGetStr(themeConfig, elemProp, &decorator);
701 if (decorator)
702 itemsList->decorator = decorator; // Will be used later (thmValidate)
704 itemsList->decoratorImage = NULL;
706 elem->extended = itemsList;
707 // elem->endElem = &endBasic; does the job
709 elem->drawElem = &drawItemsList;
712 static void drawItemText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
713 if (item) {
714 item_list_t *support = menu->item->userdata;
715 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, support->itemGetStartup(item->item.id), elem->color);
719 static void drawHintText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
720 menu_hint_item_t* hint = menu->item->hints;
721 if (hint) {
722 int x = elem->posX;
724 for (; hint; hint = hint->next) {
725 x = guiDrawIconAndText(hint->icon_id, hint->text_id, elem->font, x, elem->posY, elem->color);
726 x += 12;
731 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
733 static void validateGUIElems(char* themePath, config_set_t* themeConfig, theme_t* theme) {
734 // 1. check we have a valid Background elements
735 if ( !theme->mainElems.first || (theme->mainElems.first->type != TYPE_BACKGROUND) ) {
736 LOG("No valid background found for main, add default BG_ART\n");
737 theme_element_t* backgroundElem = initBasic(themePath, themeConfig, theme, "bg", TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
738 if (themePath)
739 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, "background");
740 else
741 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, NULL);
742 backgroundElem->next = theme->mainElems.first;
743 theme->mainElems.first = backgroundElem;
746 if (theme->infoElems.first) {
747 if (theme->infoElems.first->type != TYPE_BACKGROUND) {
748 LOG("No valid background found for info, add default BG_ART\n");
749 theme_element_t* backgroundElem = initBasic(themePath, themeConfig, theme, "bg", TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
750 if (themePath)
751 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, "background");
752 else
753 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, NULL);
754 backgroundElem->next = theme->infoElems.first;
755 theme->infoElems.first = backgroundElem;
759 // 2. check we have a valid ItemsList element, and link its decorator to the target element
760 if (theme->itemsList) {
761 items_list_t* itemsList = (items_list_t*) theme->itemsList->extended;
762 if (itemsList->decorator) {
763 // Second pass to find the decorator
764 theme_element_t* decoratorElem = theme->mainElems.first;
765 while (decoratorElem) {
766 if (decoratorElem->type == TYPE_GAME_IMAGE) {
767 mutable_image_t* gameImage = (mutable_image_t*) decoratorElem->extended;
768 if (!strcmp(itemsList->decorator, gameImage->cache->suffix)) {
769 // if user want to cache less than displayed items, then disable itemslist icons, if not would load constantly
770 if (gameImage->cache->count >= itemsList->displayedItems)
771 itemsList->decoratorImage = gameImage;
772 break;
776 decoratorElem = decoratorElem->next;
778 itemsList->decorator = NULL;
780 } else {
781 LOG("No itemsList found, adding a default one\n");
782 theme->itemsList = initBasic(themePath, themeConfig, theme, "il", TYPE_ITEMS_LIST, 150, MENU_POS_V, ALIGN_NONE, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
783 initItemsList(themePath, themeConfig, theme, theme->itemsList, "il", NULL);
784 theme->itemsList->next = theme->mainElems.first->next; // Position the itemsList as second element (right after the Background)
785 theme->mainElems.first->next = theme->itemsList;
789 static int addGUIElem(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_elems_t* elems, char* type, char* name) {
791 int enabled = 1;
792 char elemProp[64];
793 theme_element_t* elem = NULL;
795 snprintf(elemProp, 64, "%s_enabled", name);
796 configGetInt(themeConfig, elemProp, &enabled);
798 if (enabled) {
799 snprintf(elemProp, 64, "%s_type", name);
800 configGetStr(themeConfig, elemProp, &type);
801 if (type) {
802 if (!strcmp(elementsType[TYPE_ATTRIBUTE_TEXT], type)) {
803 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_TEXT, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
804 initAttributeText(themePath, themeConfig, theme, elem, name, NULL);
805 } else if (!strcmp(elementsType[TYPE_STATIC_TEXT], type)) {
806 elem = initBasic(themePath, themeConfig, theme, name, TYPE_STATIC_TEXT, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
807 initStaticText(themePath, themeConfig, theme, elem, name, NULL);
808 } else if (!strcmp(elementsType[TYPE_ATTRIBUTE_IMAGE], type)) {
809 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
810 initAttributeImage(themePath, themeConfig, theme, elem, name);
811 } else if (!strcmp(elementsType[TYPE_GAME_IMAGE], type)) {
812 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
813 initGameImage(themePath, themeConfig, theme, elem, name, NULL, 1, NULL, NULL);
814 } else if (!strcmp(elementsType[TYPE_STATIC_IMAGE], type)) {
815 elem = initBasic(themePath, themeConfig, theme, name, TYPE_STATIC_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
816 initStaticImage(themePath, themeConfig, theme, elem, name, NULL);
817 } else if (!strcmp(elementsType[TYPE_BACKGROUND], type)) {
818 if (!elems->first) { // Background elem can only be the first one
819 elem = initBasic(themePath, themeConfig, theme, name, TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
820 initBackground(themePath, themeConfig, theme, elem, name, NULL, 1, NULL);
822 } else if (!strcmp(elementsType[TYPE_MENU_ICON], type)) {
823 elem = initBasic(themePath, themeConfig, theme, name, TYPE_MENU_ICON, 40, 40, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
824 elem->drawElem = &drawMenuIcon;
825 } else if (!strcmp(elementsType[TYPE_MENU_TEXT], type)) {
826 elem = initBasic(themePath, themeConfig, theme, name, TYPE_MENU_TEXT, screenWidth >> 1, 20, ALIGN_CENTER, 200, 20, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
827 elem->drawElem = &drawMenuText;
828 } else if (!strcmp(elementsType[TYPE_ITEMS_LIST], type)) {
829 if (!theme->itemsList) {
830 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ITEMS_LIST, 150, MENU_POS_V, ALIGN_NONE, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
831 initItemsList(themePath, themeConfig, theme, elem, name, NULL);
832 theme->itemsList = elem;
834 } else if (!strcmp(elementsType[TYPE_ITEM_ICON], type)) {
835 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 80, theme->usedHeight >> 1, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
836 initGameImage(themePath, themeConfig, theme, elem, name, "ICO", 20, NULL, NULL);
837 } else if (!strcmp(elementsType[TYPE_ITEM_COVER], type)) {
838 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 520, theme->usedHeight >> 1, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
839 initGameImage(themePath, themeConfig, theme, elem, name, "COV", 10, NULL, NULL);
840 } else if (!strcmp(elementsType[TYPE_ITEM_TEXT], type)) {
841 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ITEM_TEXT, 520, 370, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
842 elem->drawElem = &drawItemText;
843 } else if (!strcmp(elementsType[TYPE_HINT_TEXT], type)) {
844 elem = initBasic(themePath, themeConfig, theme, name, TYPE_HINT_TEXT, 16, -HINT_HEIGHT, ALIGN_NONE, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
845 elem->drawElem = &drawHintText;
846 } else if (!strcmp(elementsType[TYPE_LOADING_ICON], type)) {
847 if (!theme->loadingIcon)
848 theme->loadingIcon = initBasic(themePath, themeConfig, theme, name, TYPE_LOADING_ICON, -50, -50, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
851 if (elem) {
852 if (!elems->first)
853 elems->first = elem;
855 if (!elems->last)
856 elems->last = elem;
857 else {
858 elems->last->next = elem;
859 elems->last = elem;
862 } else
863 return 0; // ends the reading of elements
866 return 1;
869 static void freeGUIElems(theme_elems_t* elems) {
870 theme_element_t* elem = elems->first;
871 while (elem) {
872 elems->first = elem->next;
873 elem->endElem(elem);
874 elem = elems->first;
878 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
879 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
881 GSTEXTURE* thmGetTexture(unsigned int id) {
882 if (id >= TEXTURES_COUNT)
883 return NULL;
884 else {
885 // see if the texture is valid
886 GSTEXTURE* txt = &gTheme->textures[id];
888 if (txt->Mem)
889 return txt;
890 else
891 return NULL;
895 static void thmFree(theme_t* theme) {
896 if (theme) {
897 // free elements
898 freeGUIElems(&theme->mainElems);
899 freeGUIElems(&theme->infoElems);
901 // free textures
902 GSTEXTURE* texture;
903 int id = 0;
904 for(; id < TEXTURES_COUNT; id++) {
905 texture = &theme->textures[id];
906 if (texture->Mem != NULL) {
907 free(texture->Mem);
908 texture->Mem = NULL;
912 // free fonts
913 for (id = 0; id < THM_MAX_FONTS; ++id) {
914 int fntid = theme->fonts[id];
916 if (fntid != FNT_DEFAULT)
917 fntRelease(fntid);
920 free(theme);
921 theme = NULL;
925 static int thmReadEntry(int index, char* path, char* separator, char* name, unsigned int mode) {
926 LOG("thmReadEntry() path=%s sep=%s name=%s\n", path, separator, name);
927 if (FIO_SO_ISDIR(mode) && strstr(name, "thm_")) {
928 theme_file_t* currTheme = &themes[nThemes + index];
930 int length = strlen(name) - 4 + 1;
931 currTheme->name = (char*) malloc(length * sizeof(char));
932 memcpy(currTheme->name, name + 4, length);
933 currTheme->name[length - 1] = '\0';
935 length = strlen(path) + 1 + strlen(name) + 1 + 1;
936 currTheme->filePath = (char*) malloc(length * sizeof(char));
937 sprintf(currTheme->filePath, "%s%s%s%s", path, separator, name, separator);
939 LOG("Theme found: %s\n", currTheme->filePath);
941 index++;
943 return index;
946 /* themePath must contains the leading separator (as it is dependent of the device, we can't know here) */
947 static int thmLoadResource(int texId, char* themePath, short psm, int useDefault) {
948 int success = -1;
949 GSTEXTURE* texture = &gTheme->textures[texId];
951 if (themePath != NULL)
952 success = texDiscoverLoad(texture, themePath, texId, psm); // only set success here
954 if ((success < 0) && useDefault)
955 texPngLoad(texture, NULL, texId, psm); // we don't mind the result of "default"
957 return success;
960 static void thmSetColors(theme_t* theme) {
961 memcpy(theme->bgColor, gDefaultBgColor, 3);
962 theme->textColor = GS_SETREG_RGBA(gDefaultTextColor[0], gDefaultTextColor[1], gDefaultTextColor[2], 0xff);
963 theme->uiTextColor = GS_SETREG_RGBA(gDefaultUITextColor[0], gDefaultUITextColor[1], gDefaultUITextColor[2], 0xff);
964 theme->selTextColor = GS_SETREG_RGBA(gDefaultSelTextColor[0], gDefaultSelTextColor[1], gDefaultSelTextColor[2], 0xff);
966 theme_element_t* elem = theme->mainElems.first;
967 while (elem) {
968 elem->color = theme->textColor;
969 elem = elem->next;
973 static void thmLoadFonts(config_set_t* themeConfig, const char* themePath, theme_t* theme) {
974 int fntID; // theme side font id, not the fntSys handle
975 for (fntID = -1; fntID < THM_MAX_FONTS; ++fntID) {
976 // does the font by the key exist?
977 char fntKey[16];
979 // -1 is a placeholder for default font...
980 if (fntID >= 0) {
981 // Default font handle...
982 theme->fonts[fntID] = FNT_DEFAULT;
983 snprintf(fntKey, 16, "font%d", fntID);
984 } else {
985 snprintf(fntKey, 16, "default_font");
988 char *fntFile;
989 int cfgKeyOK = configGetStr(themeConfig, fntKey, &fntFile);
990 if (!cfgKeyOK && (fntID >= 0))
991 continue;
993 char fullPath[128];
995 if (fntID < 0) {
996 // replace the default font
997 if (cfgKeyOK) {
998 snprintf(fullPath, 128, "%s%s", themePath, fntFile);
1000 int size = -1;
1001 void* customFont = readFile(fullPath, -1, &size);
1003 if (customFont)
1004 fntReplace(FNT_DEFAULT, customFont, size, 1, 0);
1005 } else
1006 fntSetDefault(FNT_DEFAULT);
1007 } else {
1008 snprintf(fullPath, 128, "%s%s", themePath, fntFile);
1009 int fntHandle = fntLoadFile(fullPath);
1011 // Do we have a valid font? Assign the font handle to the theme font slot
1012 if (fntHandle != FNT_ERROR)
1013 theme->fonts[fntID] = fntHandle;
1018 static void thmLoad(char* themePath) {
1019 LOG("thmLoad() path=%s\n", themePath);
1020 theme_t* curT = gTheme;
1021 theme_t* newT = (theme_t*) malloc(sizeof(theme_t));
1022 memset(newT, 0, sizeof(theme_t));
1024 newT->useDefault = 1;
1025 newT->usedHeight = 480;
1026 thmSetColors(newT);
1027 newT->mainElems.first = NULL;
1028 newT->mainElems.last = NULL;
1029 newT->infoElems.first = NULL;
1030 newT->infoElems.last = NULL;
1031 newT->gameCacheCount = 0;
1032 newT->itemsList = NULL;
1033 newT->loadingIcon = NULL;
1034 newT->loadingIconCount = LOAD7_ICON - LOAD0_ICON + 1;
1036 config_set_t* themeConfig = NULL;
1037 if (!themePath) {
1038 themeConfig = configAlloc(0, NULL, NULL);
1039 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_MENU_ICON], "_");
1040 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_MENU_TEXT], "_");
1041 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEMS_LIST], "_");
1042 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_ICON], "_");
1043 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_COVER], "_");
1044 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_TEXT], "_");
1045 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_HINT_TEXT], "_");
1046 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_LOADING_ICON], "_");
1048 // reset the default font to be sure
1049 fntSetDefault(FNT_DEFAULT);
1050 } else {
1051 char path[255];
1052 snprintf(path, 255, "%sconf_theme.cfg", themePath);
1053 themeConfig = configAlloc(0, NULL, path);
1054 configRead(themeConfig); // try to load the theme config file
1056 int intValue;
1057 if (configGetInt(themeConfig, "use_default", &intValue))
1058 newT->useDefault = intValue;
1060 if (configGetInt(themeConfig, "use_real_height", &intValue)) {
1061 if (intValue)
1062 newT->usedHeight = screenHeight;
1065 configGetColor(themeConfig, "bg_color", newT->bgColor);
1067 unsigned char color[3];
1068 if (configGetColor(themeConfig, "text_color", color))
1069 newT->textColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1071 if (configGetColor(themeConfig, "ui_text_color", color))
1072 newT->uiTextColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1074 if (configGetColor(themeConfig, "sel_text_color", color))
1075 newT->selTextColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1077 // before loading the element definitions, we have to have the fonts prepared
1078 // for that, we load the fonts and a translation table
1079 thmLoadFonts(themeConfig, themePath, newT);
1081 int i = 1;
1082 snprintf(path, 255, "main0");
1083 while (addGUIElem(themePath, themeConfig, newT, &newT->mainElems, NULL, path))
1084 snprintf(path, 255, "main%d", i++);
1086 i = 1;
1087 snprintf(path, 255, "info0");
1088 while(addGUIElem(themePath, themeConfig, newT, &newT->infoElems, NULL, path))
1089 snprintf(path, 255, "info%d", i++);
1092 validateGUIElems(themePath, themeConfig, newT);
1093 configFree(themeConfig);
1095 LOG("theme loaded, number of cache: %d\n", newT->gameCacheCount);
1097 LOG("thmLoad() usedHeight=%d\n", newT->usedHeight);
1099 /// Now swap theme and start loading textures
1100 if (newT->usedHeight == screenHeight)
1101 rmResetShiftRatio();
1102 else
1103 rmSetShiftRatio((float) screenHeight / newT->usedHeight);
1105 gTheme = newT;
1106 thmFree(curT);
1108 int i;
1109 // default all to not loaded...
1110 for (i = 0; i < TEXTURES_COUNT; i++) {
1111 gTheme->textures[i].Mem = NULL;
1114 // First start with busy icon
1115 char* path = themePath;
1116 int customBusy = 0;
1117 for (i = LOAD0_ICON; i <= LOAD7_ICON; i++) {
1118 if (thmLoadResource(i, path, GS_PSM_CT32, gTheme->useDefault) >= 0)
1119 customBusy = 1;
1120 else {
1121 if (customBusy)
1122 break;
1123 else
1124 path = NULL;
1127 gTheme->loadingIconCount = i;
1129 // Customizable icons
1130 for (i = USB_ICON; i <= DOWN_ICON; i++)
1131 thmLoadResource(i, themePath, GS_PSM_CT32, gTheme->useDefault);
1133 // Not customizable icons
1134 for (i = L1_ICON; i <= START_ICON; i++)
1135 thmLoadResource(i, NULL, GS_PSM_CT32, 1);
1137 // LOGO is hardcoded
1138 thmLoadResource(LOGO_PICTURE, NULL, GS_PSM_CT24, 1);
1141 static void thmRebuildGuiNames() {
1142 if (guiThemesNames)
1143 free(guiThemesNames);
1145 // build the languages name list
1146 guiThemesNames = (char**) malloc((nThemes + 2) * sizeof(char**));
1148 // add default internal
1149 guiThemesNames[0] = "<OPL>";
1151 int i = 0;
1152 for (; i < nThemes; i++) {
1153 guiThemesNames[i + 1] = themes[i].name;
1156 guiThemesNames[nThemes + 1] = NULL;
1159 void thmAddElements(char* path, char* separator, int mode) {
1160 LOG("thmAddElements() path=%s sep=%s\n", path, separator);
1161 nThemes += listDir(path, separator, THM_MAX_FILES - nThemes, &thmReadEntry);
1162 LOG("thmAddElements() nThemes=%d\n", nThemes);
1163 thmRebuildGuiNames();
1165 char* temp;
1166 if (configGetStr(configGetByType(CONFIG_OPL), "theme", &temp)) {
1167 LOG("Trying to set again theme: %s\n", temp);
1168 if (thmSetGuiValue(thmFindGuiID(temp), 0))
1169 moduleUpdateMenu(mode, 1);
1173 void thmInit() {
1174 LOG("thmInit()\n");
1175 gTheme = NULL;
1177 thmReloadScreenExtents();
1179 // initialize default internal
1180 thmLoad(NULL);
1182 thmAddElements(gBaseMCDir, "/", -1);
1185 void thmReloadScreenExtents() {
1186 rmGetScreenExtents(&screenWidth, &screenHeight);
1189 char* thmGetValue() {
1190 //LOG("thmGetValue() id=%d name=%s\n", guiThemeID, guiThemesNames[guiThemeID]);
1191 return guiThemesNames[guiThemeID];
1194 int thmSetGuiValue(int themeID, int reload) {
1195 LOG("thmSetGuiValue() id=%d\n", themeID);
1196 if (themeID != -1) {
1197 if (guiThemeID != themeID || reload) {
1198 if (themeID != 0)
1199 thmLoad(themes[themeID - 1].filePath);
1200 else
1201 thmLoad(NULL);
1203 guiThemeID = themeID;
1204 configSetStr(configGetByType(CONFIG_OPL), "theme", thmGetValue());
1205 return 1;
1207 else if (guiThemeID == 0)
1208 thmSetColors(gTheme);
1210 return 0;
1213 int thmGetGuiValue() {
1214 //LOG("thmGetGuiValue() id=%d\n", guiThemeID);
1215 return guiThemeID;
1218 int thmFindGuiID(char* theme) {
1219 LOG("thmFindGuiID() theme=%s\n", theme);
1220 if (theme) {
1221 int i = 0;
1222 for (; i < nThemes; i++) {
1223 if (stricmp(themes[i].name, theme) == 0)
1224 return i + 1;
1227 return 0;
1230 char **thmGetGuiList() {
1231 return guiThemesNames;
1234 void thmEnd() {
1235 thmFree(gTheme);
1237 int i = 0;
1238 for (; i < nThemes; i++) {
1239 free(themes[i].name);
1240 free(themes[i].filePath);
1243 free(guiThemesNames);