SilverBull: apply a delay to CDVDMAN functions (initially for Shadow Heart 2)
[open-ps2-loader.git] / src / themes.c
blobd0291e980d5669de5bc3754bc4d2e48ee93ff841
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_INFO_HINT_TEXT 13
39 #define TYPE_LOADING_ICON 14
41 #define DISPLAY_ALWAYS 0
42 #define DISPLAY_DEFINED 1
43 #define DISPLAY_NEVER 2
45 #define SIZING_NONE -1
46 #define SIZING_CLIP 0
47 #define SIZING_WRAP 1
49 static char *elementsType[] = {
50 "AttributeText",
51 "StaticText",
52 "AttributeImage",
53 "GameImage",
54 "StaticImage",
55 "Background",
56 "MenuIcon",
57 "MenuText",
58 "ItemsList",
59 "ItemIcon",
60 "ItemCover",
61 "ItemText",
62 "HintText",
63 "InfoHintText",
64 "LoadingIcon",
67 // Common functions for Text ////////////////////////////////////////////////////////////////////////////////////////////////
69 static void endMutableText(theme_element_t* elem) {
70 mutable_text_t* mutableText = (mutable_text_t*) elem->extended;
71 if (mutableText) {
72 if (mutableText->value)
73 free(mutableText->value);
75 if (mutableText->alias)
76 free(mutableText->alias);
78 free(mutableText);
81 free(elem);
84 static mutable_text_t* initMutableText(char* themePath, config_set_t* themeConfig, theme_t* theme, char* name, int type, struct theme_element* elem,
85 char* value, char* alias, int displayMode, int sizingMode) {
87 mutable_text_t* mutableText = (mutable_text_t*) malloc(sizeof(mutable_text_t));
88 mutableText->currentItemId = -1;
89 mutableText->currentValue = NULL;
90 mutableText->alias = NULL;
92 char elemProp[64];
94 snprintf(elemProp, 64, "%s_display", name);
95 configGetInt(themeConfig, elemProp, &displayMode);
96 mutableText->displayMode = displayMode;
98 int length = strlen(value) + 1;
99 mutableText->value = (char*) malloc(length * sizeof(char));
100 memcpy(mutableText->value, value, length);
102 snprintf(elemProp, 64, "%s_wrap", name);
103 if (configGetInt(themeConfig, elemProp, &sizingMode)) {
104 if (sizingMode > 0)
105 mutableText->sizingMode = SIZING_WRAP;
108 if ((elem->width != DIM_UNDEF) || (elem->height != DIM_UNDEF)) {
109 if (sizingMode == SIZING_NONE)
110 sizingMode = SIZING_CLIP;
112 if (elem->width == DIM_UNDEF)
113 elem->width = screenWidth;
115 if (elem->height == DIM_UNDEF)
116 elem->height = screenHeight;
117 } else
118 sizingMode = SIZING_NONE;
119 mutableText->sizingMode = sizingMode;
121 if (type == TYPE_ATTRIBUTE_TEXT) {
122 snprintf(elemProp, 64, "%s_title", name);
123 configGetStr(themeConfig, elemProp, &alias);
124 if (!alias) {
125 if (value[0] == '#')
126 alias = &value[1];
127 else
128 alias = value;
130 length = strlen(alias) + 1 + 3;
131 mutableText->alias = (char*) malloc(length * sizeof(char));
132 if (mutableText->sizingMode == SIZING_WRAP)
133 snprintf(mutableText->alias, length, "%s :\n", alias);
134 else
135 snprintf(mutableText->alias, length, "%s : ", alias);
136 } else {
137 if (mutableText->sizingMode == SIZING_WRAP)
138 fntFitString(elem->font, mutableText->value, elem->width);
141 return mutableText;
144 // StaticText ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
146 static void drawStaticText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
147 mutable_text_t* mutableText = (mutable_text_t*) elem->extended;
148 if (mutableText->sizingMode == SIZING_NONE)
149 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, mutableText->value, elem->color);
150 else
151 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, mutableText->value, elem->color);
154 static void initStaticText(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
155 char* value) {
157 char elemProp[64];
159 snprintf(elemProp, 64, "%s_value", name);
160 configGetStr(themeConfig, elemProp, &value);
161 if (value) {
162 elem->extended = initMutableText(themePath, themeConfig, theme, name, TYPE_STATIC_TEXT, elem, value, NULL, DISPLAY_ALWAYS, SIZING_NONE);
163 elem->endElem = &endMutableText;
164 elem->drawElem = &drawStaticText;
165 } else
166 LOG("THEMES StaticText %s: NO value, elem disabled !!\n", name);
169 // AttributeText ////////////////////////////////////////////////////////////////////////////////////////////////////////////
171 static void drawAttributeText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
172 mutable_text_t* mutableText = (mutable_text_t*) elem->extended;
173 if (config) {
174 if (mutableText->currentItemId != item->item.id) {
175 // force refresh
176 mutableText->currentItemId = item->item.id;
177 mutableText->currentValue = NULL;
178 if (configGetStr(config, mutableText->value, &mutableText->currentValue)) {
179 if (mutableText->sizingMode == SIZING_WRAP)
180 fntFitString(elem->font, mutableText->currentValue, elem->width);
183 if (mutableText->currentValue) {
184 if (mutableText->displayMode == DISPLAY_NEVER) {
185 if (mutableText->sizingMode == SIZING_NONE)
186 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, mutableText->currentValue, elem->color);
187 else
188 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, mutableText->currentValue, elem->color);
189 } else {
190 char result[300];
191 snprintf(result, 300, "%s%s", mutableText->alias, mutableText->currentValue);
192 if (mutableText->sizingMode == SIZING_NONE)
193 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, result, elem->color);
194 else
195 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, result, elem->color);
197 return;
200 if (mutableText->displayMode == DISPLAY_ALWAYS) {
201 if (mutableText->sizingMode == SIZING_NONE)
202 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, mutableText->alias, elem->color);
203 else
204 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, mutableText->alias, elem->color);
208 static void initAttributeText(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
209 char* attribute) {
211 char elemProp[64];
213 snprintf(elemProp, 64, "%s_attribute", name);
214 configGetStr(themeConfig, elemProp, &attribute);
215 if (attribute) {
216 elem->extended = initMutableText(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_TEXT, elem, attribute, NULL, DISPLAY_ALWAYS, SIZING_NONE);
217 elem->endElem = &endMutableText;
218 elem->drawElem = &drawAttributeText;
219 } else
220 LOG("THEMES AttributeText %s: NO attribute, elem disabled !!\n", name);
223 // Common functions for Image ///////////////////////////////////////////////////////////////////////////////////////////////
225 static void findDuplicate(theme_element_t* first, char* cachePattern, char* defaultTexture, char* overlayTexture, mutable_image_t* target) {
226 theme_element_t* elem = first;
227 while (elem) {
228 if ((elem->type == TYPE_STATIC_IMAGE) || (elem->type == TYPE_ATTRIBUTE_IMAGE) || (elem->type == TYPE_GAME_IMAGE) || (elem->type == TYPE_BACKGROUND)) {
229 mutable_image_t* source = (mutable_image_t*) elem->extended;
231 if (cachePattern && source->cache && !strcmp(cachePattern, source->cache->suffix)) {
232 target->cache = source->cache;
233 target->cacheLinked = 1;
234 LOG("THEMES Re-using a cache for pattern %s\n", cachePattern);
237 if (defaultTexture && source->defaultTexture && !strcmp(defaultTexture, source->defaultTexture->name)) {
238 target->defaultTexture = source->defaultTexture;
239 target->defaultTextureLinked = 1;
240 LOG("THEMES Re-using the default texture for %s\n", defaultTexture);
243 if (overlayTexture && source->overlayTexture && !strcmp(overlayTexture, source->overlayTexture->name)) {
244 target->overlayTexture = source->overlayTexture;
245 target->overlayTextureLinked = 1;
246 LOG("THEMES Re-using the overlay texture for %s\n", overlayTexture);
250 elem = elem->next;
254 static void freeImageTexture(image_texture_t* texture) {
255 if (texture) {
256 if (texture->source.Mem)
257 free(texture->source.Mem);
259 free(texture->name);
261 free(texture);
265 static image_texture_t* initImageTexture(char* themePath, config_set_t* themeConfig, char* name, char* imgName, int isOverlay) {
266 image_texture_t* texture = (image_texture_t*) malloc(sizeof(image_texture_t));
267 texPrepare(&texture->source, isOverlay ? GS_PSM_CT32 : GS_PSM_CT24);
268 texture->name = NULL;
270 char path[255];
271 snprintf(path, 255, "%s%s", themePath, imgName);
272 if (texDiscoverLoad(&texture->source, path, -1, isOverlay ? GS_PSM_CT32 : GS_PSM_CT24) >= 0) {
273 int length = strlen(imgName) + 1;
274 texture->name = (char*) malloc(length * sizeof(char));
275 memcpy(texture->name, imgName, length);
277 if (isOverlay) {
278 int intValue;
279 char elemProp[64];
280 snprintf(elemProp, 64, "%s_overlay_ulx", name);
281 if (configGetInt(themeConfig, elemProp, &intValue))
282 texture->upperLeft_x = intValue;
283 snprintf(elemProp, 64, "%s_overlay_uly", name);
284 if (configGetInt(themeConfig, elemProp, &intValue))
285 texture->upperLeft_y = intValue;
286 snprintf(elemProp, 64, "%s_overlay_urx", name);
287 if (configGetInt(themeConfig, elemProp, &intValue))
288 texture->upperRight_x = intValue;
289 snprintf(elemProp, 64, "%s_overlay_ury", name);
290 if (configGetInt(themeConfig, elemProp, &intValue))
291 texture->upperRight_y = intValue;
292 snprintf(elemProp, 64, "%s_overlay_llx", name);
293 if (configGetInt(themeConfig, elemProp, &intValue))
294 texture->lowerLeft_x = intValue;
295 snprintf(elemProp, 64, "%s_overlay_lly", name);
296 if (configGetInt(themeConfig, elemProp, &intValue))
297 texture->lowerLeft_y = intValue;
298 snprintf(elemProp, 64, "%s_overlay_lrx", name);
299 if (configGetInt(themeConfig, elemProp, &intValue))
300 texture->lowerRight_x = intValue;
301 snprintf(elemProp, 64, "%s_overlay_lry", name);
302 if (configGetInt(themeConfig, elemProp, &intValue))
303 texture->lowerRight_y = intValue;
305 } else {
306 freeImageTexture(texture);
307 texture = NULL;
310 return texture;
313 static void endMutableImage(struct theme_element* elem) {
314 mutable_image_t* mutableImage = (mutable_image_t*) elem->extended;
315 if (mutableImage) {
316 if (mutableImage->cache && !mutableImage->cacheLinked)
317 cacheDestroyCache(mutableImage->cache);
319 if (mutableImage->defaultTexture && !mutableImage->defaultTextureLinked)
320 freeImageTexture(mutableImage->defaultTexture);
322 if (mutableImage->overlayTexture && !mutableImage->overlayTextureLinked)
323 freeImageTexture(mutableImage->overlayTexture);
325 free(mutableImage);
328 free(elem);
331 static mutable_image_t* initMutableImage(char* themePath, config_set_t* themeConfig, theme_t* theme, char* name, int type,
332 char* cachePattern, int cacheCount, char* defaultTexture, char* overlayTexture) {
334 mutable_image_t* mutableImage = (mutable_image_t*) malloc(sizeof(mutable_image_t));
335 mutableImage->currentUid = -1;
336 mutableImage->currentItemId = -1;
337 mutableImage->currentValue = NULL;
338 mutableImage->cache = NULL;
339 mutableImage->cacheLinked = 0;
340 mutableImage->defaultTexture = NULL;
341 mutableImage->defaultTextureLinked = 0;
342 mutableImage->overlayTexture = NULL;
343 mutableImage->overlayTextureLinked = 0;
345 char elemProp[64];
347 if (type == TYPE_ATTRIBUTE_IMAGE) {
348 snprintf(elemProp, 64, "%s_attribute", name);
349 configGetStr(themeConfig, elemProp, &cachePattern);
350 LOG("THEMES MutableImage %s: type: %d using cache pattern: %s\n", name, type, cachePattern);
351 } else if ((type == TYPE_GAME_IMAGE) || type == (TYPE_BACKGROUND)) {
352 snprintf(elemProp, 64, "%s_pattern", name);
353 configGetStr(themeConfig, elemProp, &cachePattern);
354 snprintf(elemProp, 64, "%s_count", name);
355 configGetInt(themeConfig, elemProp, &cacheCount);
356 LOG("THEMES MutableImage %s: type: %d using cache pattern: %s\n", name, type, cachePattern);
359 snprintf(elemProp, 64, "%s_default", name);
360 configGetStr(themeConfig, elemProp, &defaultTexture);
362 if (type != TYPE_BACKGROUND) {
363 snprintf(elemProp, 64, "%s_overlay", name);
364 configGetStr(themeConfig, elemProp, &overlayTexture);
367 findDuplicate(theme->mainElems.first, cachePattern, defaultTexture, overlayTexture, mutableImage);
368 findDuplicate(theme->infoElems.first, cachePattern, defaultTexture, overlayTexture, mutableImage);
370 if (cachePattern && !mutableImage->cache) {
371 if (type == TYPE_ATTRIBUTE_IMAGE)
372 mutableImage->cache = cacheInitCache(-1, themePath, 0, cachePattern, 1);
373 else
374 mutableImage->cache = cacheInitCache(theme->gameCacheCount++, "ART", 1, cachePattern, cacheCount);
377 if (defaultTexture && !mutableImage->defaultTexture)
378 mutableImage->defaultTexture = initImageTexture(themePath, themeConfig, name, defaultTexture, 0);
380 if (overlayTexture && !mutableImage->overlayTexture)
381 mutableImage->overlayTexture = initImageTexture(themePath, themeConfig, name, overlayTexture, 1);
383 return mutableImage;
386 // StaticImage //////////////////////////////////////////////////////////////////////////////////////////////////////////////
388 static void drawStaticImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
389 mutable_image_t* staticImage = (mutable_image_t*) elem->extended;
390 if (staticImage->overlayTexture) {
391 rmDrawOverlayPixmap(&staticImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
392 &staticImage->defaultTexture->source, staticImage->overlayTexture->upperLeft_x, staticImage->overlayTexture->upperLeft_y, staticImage->overlayTexture->upperRight_x, staticImage->overlayTexture->upperRight_y,
393 staticImage->overlayTexture->lowerLeft_x, staticImage->overlayTexture->lowerLeft_y, staticImage->overlayTexture->lowerRight_x, staticImage->overlayTexture->lowerRight_y);
394 } else
395 rmDrawPixmap(&staticImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
398 static void initStaticImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
399 char* imageName) {
401 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, NULL, 0, imageName, NULL);
402 elem->extended = mutableImage;
403 elem->endElem = &endMutableImage;
405 if (mutableImage->defaultTexture)
406 elem->drawElem = &drawStaticImage;
407 else
408 LOG("THEMES StaticImage %s: NO image name, elem disabled !!\n", name);
411 // GameImage ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
413 static GSTEXTURE* getGameImageTexture(image_cache_t* cache, void* support, struct submenu_item* item) {
414 if (gEnableArt) {
415 item_list_t * list = (item_list_t *) support;
416 char* startup = list->itemGetStartup(item->id);
417 return cacheGetTexture(cache, list, &item->cache_id[cache->userId], &item->cache_uid[cache->userId], startup);
420 return NULL;
423 static void drawGameImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
424 mutable_image_t* gameImage = (mutable_image_t*) elem->extended;
425 if (item) {
426 GSTEXTURE* texture = getGameImageTexture(gameImage->cache, menu->item->userdata, &item->item);
427 if (!texture || !texture->Mem) {
428 if (gameImage->defaultTexture)
429 texture = &gameImage->defaultTexture->source;
430 else {
431 if (elem->type == TYPE_BACKGROUND)
432 guiDrawBGPlasma();
433 return;
437 if (gameImage->overlayTexture) {
438 rmDrawOverlayPixmap(&gameImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
439 texture, gameImage->overlayTexture->upperLeft_x, gameImage->overlayTexture->upperLeft_y, gameImage->overlayTexture->upperRight_x, gameImage->overlayTexture->upperRight_y,
440 gameImage->overlayTexture->lowerLeft_x, gameImage->overlayTexture->lowerLeft_y, gameImage->overlayTexture->lowerRight_x, gameImage->overlayTexture->lowerRight_y);
441 } else
442 rmDrawPixmap(texture, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
444 } else if (elem->type == TYPE_BACKGROUND) {
445 if (gameImage->defaultTexture)
446 rmDrawPixmap(&gameImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
447 else
448 guiDrawBGPlasma();
452 static void initGameImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
453 char* pattern, int count, char* texture, char* overlay) {
455 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, pattern, count, texture, overlay);
456 elem->extended = mutableImage;
457 elem->endElem = &endMutableImage;
459 if (mutableImage->cache)
460 elem->drawElem = &drawGameImage;
461 else
462 LOG("THEMES GameImage %s: NO pattern, elem disabled !!\n", name);
465 // AttributeImage ///////////////////////////////////////////////////////////////////////////////////////////////////////////
467 static void drawAttributeImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
468 mutable_image_t* attributeImage = (mutable_image_t*) elem->extended;
469 if (config) {
470 if (attributeImage->currentItemId != item->item.id) {
471 // force refresh
472 attributeImage->currentUid = -1;
473 attributeImage->currentItemId = item->item.id;
474 attributeImage->currentValue = NULL;
475 configGetStr(config, attributeImage->cache->suffix, &attributeImage->currentValue);
477 if (attributeImage->currentValue) {
478 int posZ = 0;
479 GSTEXTURE* texture = cacheGetTexture(attributeImage->cache, menu->item->userdata, &posZ, &attributeImage->currentUid, attributeImage->currentValue);
480 if (texture && texture->Mem) {
481 if (attributeImage->overlayTexture) {
482 rmDrawOverlayPixmap(&attributeImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
483 texture, attributeImage->overlayTexture->upperLeft_x, attributeImage->overlayTexture->upperLeft_y, attributeImage->overlayTexture->upperRight_x, attributeImage->overlayTexture->upperRight_y,
484 attributeImage->overlayTexture->lowerLeft_x, attributeImage->overlayTexture->lowerLeft_y, attributeImage->overlayTexture->lowerRight_x, attributeImage->overlayTexture->lowerRight_y);
485 } else
486 rmDrawPixmap(texture, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
488 return;
492 if (attributeImage->defaultTexture)
493 rmDrawPixmap(&attributeImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
496 static void initAttributeImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name) {
497 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, NULL, 1, NULL, NULL);
498 elem->extended = mutableImage;
499 elem->endElem = &endMutableImage;
501 if (mutableImage->cache)
502 elem->drawElem = &drawAttributeImage;
503 else
504 LOG("THEMES AttributeImage %s: NO attribute, elem disabled !!\n", name);
507 // BasicElement /////////////////////////////////////////////////////////////////////////////////////////////////////////////
509 static void endBasic(theme_element_t* elem) {
510 if (elem->extended)
511 free(elem->extended);
513 free(elem);
516 static theme_element_t* initBasic(char* themePath, config_set_t* themeConfig, theme_t* theme,
517 char* name, int type, int x, int y, short aligned, int w, int h, short scaled, u64 color, int font) {
519 int intValue;
520 unsigned char charColor[3];
521 char* temp;
522 char elemProp[64];
524 theme_element_t* elem = (theme_element_t*) malloc(sizeof(theme_element_t));
526 elem->type = type;
527 elem->extended = NULL;
528 elem->drawElem = NULL;
529 elem->endElem = &endBasic;
530 elem->next = NULL;
532 snprintf(elemProp, 64, "%s_x", name);
533 if (configGetStr(themeConfig, elemProp, &temp)) {
534 if (!strncmp(temp, "POS_MID", 7))
535 x = screenWidth >> 1;
536 else
537 x = atoi(temp);
539 if (x < 0)
540 elem->posX = screenWidth + x;
541 else
542 elem->posX = x;
544 snprintf(elemProp, 64, "%s_y", name);
545 if (configGetStr(themeConfig, elemProp, &temp)) {
546 if (!strncmp(temp, "POS_MID", 7))
547 y = screenHeight >> 1;
548 else
549 y = atoi(temp);
551 if (y < 0)
552 elem->posY = ceil((screenHeight + y) * theme->usedHeight / screenHeight);
553 else
554 elem->posY = y;
556 snprintf(elemProp, 64, "%s_width", name);
557 if (configGetStr(themeConfig, elemProp, &temp)) {
558 if (!strncmp(temp, "DIM_INF", 7))
559 elem->width = screenWidth;
560 else
561 elem->width = atoi(temp);
562 } else
563 elem->width = w;
565 snprintf(elemProp, 64, "%s_height", name);
566 if (configGetStr(themeConfig, elemProp, &temp)) {
567 if (!strncmp(temp, "DIM_INF", 7))
568 elem->height = screenHeight;
569 else
570 elem->height = atoi(temp);
571 } else
572 elem->height = h;
574 snprintf(elemProp, 64, "%s_aligned", name);
575 if (configGetInt(themeConfig, elemProp, &intValue))
576 elem->aligned = intValue;
577 else
578 elem->aligned = aligned;
580 snprintf(elemProp, 64, "%s_scaled", name);
581 if (configGetInt(themeConfig, elemProp, &intValue))
582 elem->scaled = intValue;
583 else
584 elem->scaled = scaled;
586 snprintf(elemProp, 64, "%s_color", name);
587 if (configGetColor(themeConfig, elemProp, charColor))
588 elem->color = GS_SETREG_RGBA(charColor[0], charColor[1], charColor[2], 0xff);
589 else
590 elem->color = color;
592 snprintf(elemProp, 64, "%s_font", name);
593 if (configGetInt(themeConfig, elemProp, &intValue))
594 font = intValue;
595 if (font >= 0 && font < THM_MAX_FONTS)
596 elem->font = theme->fonts[font];
597 else
598 elem->font = FNT_DEFAULT;
600 return elem;
603 // Internal elements ////////////////////////////////////////////////////////////////////////////////////////////////////////
605 static void drawBackground(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
606 guiDrawBGPlasma();
609 static void initBackground(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
610 char* pattern, int count, char* texture) {
612 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, pattern, count, texture, NULL);
613 elem->extended = mutableImage;
614 elem->endElem = &endMutableImage;
616 if (mutableImage->cache)
617 elem->drawElem = &drawGameImage;
618 else if (mutableImage->defaultTexture)
619 elem->drawElem = &drawStaticImage;
620 else
621 elem->drawElem = &drawBackground;
624 static void drawMenuIcon(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
625 GSTEXTURE* menuIconTex = thmGetTexture(menu->item->icon_id);
626 if (menuIconTex && menuIconTex->Mem)
627 rmDrawPixmap(menuIconTex, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
630 static void drawMenuText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
631 GSTEXTURE* leftIconTex = NULL, *rightIconTex = NULL;
632 if (menu->prev)
633 leftIconTex = thmGetTexture(LEFT_ICON);
634 if (menu->next)
635 rightIconTex = thmGetTexture(RIGHT_ICON);
637 if (elem->aligned) {
638 int offset = elem->width >> 1;
639 if (leftIconTex && leftIconTex->Mem)
640 rmDrawPixmap(leftIconTex, elem->posX - offset, elem->posY, elem->aligned, leftIconTex->Width, leftIconTex->Height, elem->scaled, gDefaultCol);
641 if (rightIconTex && rightIconTex->Mem)
642 rmDrawPixmap(rightIconTex, elem->posX + offset, elem->posY, elem->aligned, rightIconTex->Width, rightIconTex->Height, elem->scaled, gDefaultCol);
644 else {
645 if (leftIconTex && leftIconTex->Mem)
646 rmDrawPixmap(leftIconTex, elem->posX - leftIconTex->Width, elem->posY, elem->aligned, leftIconTex->Width, leftIconTex->Height, elem->scaled, gDefaultCol);
647 if (rightIconTex && rightIconTex->Mem)
648 rmDrawPixmap(rightIconTex, elem->posX + elem->width, elem->posY, elem->aligned, rightIconTex->Width, rightIconTex->Height, elem->scaled, gDefaultCol);
650 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, menuItemGetText(menu->item), elem->color);
653 static void drawItemsList(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
654 if (item) {
655 items_list_t* itemsList = (items_list_t*) elem->extended;
657 int posX = elem->posX, posY = elem->posY;
658 if (elem->aligned) {
659 posX -= elem->width >> 1;
660 posY -= elem->height >> 1;
663 submenu_list_t *ps = menu->item->pagestart;
664 int others = 0;
665 u64 color;
666 while (ps && (others++ < itemsList->displayedItems)) {
667 if (ps == item)
668 color = gTheme->selTextColor;
669 else
670 color = elem->color;
672 if (itemsList->decoratorImage) {
673 GSTEXTURE* itemIconTex = getGameImageTexture(itemsList->decoratorImage->cache, menu->item->userdata, &ps->item);
674 if (itemIconTex && itemIconTex->Mem)
675 rmDrawPixmap(itemIconTex, posX, posY, ALIGN_NONE, DECORATOR_SIZE, DECORATOR_SIZE, elem->scaled, gDefaultCol);
676 else {
677 if (itemsList->decoratorImage->defaultTexture)
678 rmDrawPixmap(&itemsList->decoratorImage->defaultTexture->source, posX, posY, ALIGN_NONE, DECORATOR_SIZE, DECORATOR_SIZE, elem->scaled, gDefaultCol);
680 fntRenderString(elem->font, posX + DECORATOR_SIZE, posY, ALIGN_NONE, elem->width, elem->height, submenuItemGetText(&ps->item), color);
681 } else
682 fntRenderString(elem->font, posX, posY, ALIGN_NONE, elem->width, elem->height, submenuItemGetText(&ps->item), color);
684 posY += MENU_ITEM_HEIGHT;
685 ps = ps->next;
690 static void initItemsList(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name, char* decorator) {
691 char elemProp[64];
693 items_list_t* itemsList = (items_list_t*) malloc(sizeof(items_list_t));
695 if (elem->width == DIM_UNDEF)
696 elem->width = screenWidth;
698 if (elem->height == DIM_UNDEF)
699 elem->height = theme->usedHeight - (MENU_POS_V + HINT_HEIGHT);
701 itemsList->displayedItems = elem->height / MENU_ITEM_HEIGHT;
702 LOG("THEMES ItemsList %s: displaying %d elems, item height: %d\n", name, itemsList->displayedItems, elem->height);
704 itemsList->decorator = NULL;
705 snprintf(elemProp, 64, "%s_decorator", name);
706 configGetStr(themeConfig, elemProp, &decorator);
707 if (decorator)
708 itemsList->decorator = decorator; // Will be used later (thmValidate)
710 itemsList->decoratorImage = NULL;
712 elem->extended = itemsList;
713 // elem->endElem = &endBasic; does the job
715 elem->drawElem = &drawItemsList;
718 static void drawItemText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
719 if (item) {
720 item_list_t *support = menu->item->userdata;
721 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, support->itemGetStartup(item->item.id), elem->color);
725 static void drawHintText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
726 menu_hint_item_t* hint = menu->item->hints;
727 if (hint) {
728 int x = elem->posX;
730 for (; hint; hint = hint->next) {
731 x = guiDrawIconAndText(hint->icon_id, hint->text_id, elem->font, x, elem->posY, elem->color);
732 x += elem->width;
737 static void drawInfoHintText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
738 int x = elem->posX;
739 x = guiDrawIconAndText(CROSS_ICON, _STR_RUN, elem->font, x, elem->posY, elem->color);
740 x += elem->width;
741 x = guiDrawIconAndText(CIRCLE_ICON, _STR_O_BACK, elem->font, x, elem->posY, elem->color);
744 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
746 static void validateGUIElems(char* themePath, config_set_t* themeConfig, theme_t* theme) {
747 // 1. check we have a valid Background elements
748 if ( !theme->mainElems.first || (theme->mainElems.first->type != TYPE_BACKGROUND) ) {
749 LOG("THEMES No valid background found for main, add default BG_ART\n");
750 theme_element_t* backgroundElem = initBasic(themePath, themeConfig, theme, "bg", TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
751 if (themePath)
752 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, "background");
753 else
754 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, NULL);
755 backgroundElem->next = theme->mainElems.first;
756 theme->mainElems.first = backgroundElem;
759 if (theme->infoElems.first) {
760 if (theme->infoElems.first->type != TYPE_BACKGROUND) {
761 LOG("THEMES No valid background found for info, add default BG_ART\n");
762 theme_element_t* backgroundElem = initBasic(themePath, themeConfig, theme, "bg", TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
763 if (themePath)
764 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, "background");
765 else
766 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, NULL);
767 backgroundElem->next = theme->infoElems.first;
768 theme->infoElems.first = backgroundElem;
772 // 2. check we have a valid ItemsList element, and link its decorator to the target element
773 if (theme->itemsList) {
774 items_list_t* itemsList = (items_list_t*) theme->itemsList->extended;
775 if (itemsList->decorator) {
776 // Second pass to find the decorator
777 theme_element_t* decoratorElem = theme->mainElems.first;
778 while (decoratorElem) {
779 if (decoratorElem->type == TYPE_GAME_IMAGE) {
780 mutable_image_t* gameImage = (mutable_image_t*) decoratorElem->extended;
781 if (!strcmp(itemsList->decorator, gameImage->cache->suffix)) {
782 // if user want to cache less than displayed items, then disable itemslist icons, if not would load constantly
783 if (gameImage->cache->count >= itemsList->displayedItems)
784 itemsList->decoratorImage = gameImage;
785 break;
789 decoratorElem = decoratorElem->next;
791 itemsList->decorator = NULL;
793 } else {
794 LOG("THEMES No itemsList found, adding a default one\n");
795 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);
796 initItemsList(themePath, themeConfig, theme, theme->itemsList, "il", NULL);
797 theme->itemsList->next = theme->mainElems.first->next; // Position the itemsList as second element (right after the Background)
798 theme->mainElems.first->next = theme->itemsList;
802 static int addGUIElem(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_elems_t* elems, char* type, char* name) {
804 int enabled = 1;
805 char elemProp[64];
806 theme_element_t* elem = NULL;
808 snprintf(elemProp, 64, "%s_enabled", name);
809 configGetInt(themeConfig, elemProp, &enabled);
811 if (enabled) {
812 snprintf(elemProp, 64, "%s_type", name);
813 configGetStr(themeConfig, elemProp, &type);
814 if (type) {
815 if (!strcmp(elementsType[TYPE_ATTRIBUTE_TEXT], type)) {
816 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_TEXT, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
817 initAttributeText(themePath, themeConfig, theme, elem, name, NULL);
818 } else if (!strcmp(elementsType[TYPE_STATIC_TEXT], type)) {
819 elem = initBasic(themePath, themeConfig, theme, name, TYPE_STATIC_TEXT, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
820 initStaticText(themePath, themeConfig, theme, elem, name, NULL);
821 } else if (!strcmp(elementsType[TYPE_ATTRIBUTE_IMAGE], type)) {
822 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
823 initAttributeImage(themePath, themeConfig, theme, elem, name);
824 } else if (!strcmp(elementsType[TYPE_GAME_IMAGE], type)) {
825 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
826 initGameImage(themePath, themeConfig, theme, elem, name, NULL, 1, NULL, NULL);
827 } else if (!strcmp(elementsType[TYPE_STATIC_IMAGE], type)) {
828 elem = initBasic(themePath, themeConfig, theme, name, TYPE_STATIC_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
829 initStaticImage(themePath, themeConfig, theme, elem, name, NULL);
830 } else if (!strcmp(elementsType[TYPE_BACKGROUND], type)) {
831 if (!elems->first) { // Background elem can only be the first one
832 elem = initBasic(themePath, themeConfig, theme, name, TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
833 initBackground(themePath, themeConfig, theme, elem, name, NULL, 1, NULL);
835 } else if (!strcmp(elementsType[TYPE_MENU_ICON], type)) {
836 elem = initBasic(themePath, themeConfig, theme, name, TYPE_MENU_ICON, 40, 40, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
837 elem->drawElem = &drawMenuIcon;
838 } else if (!strcmp(elementsType[TYPE_MENU_TEXT], type)) {
839 elem = initBasic(themePath, themeConfig, theme, name, TYPE_MENU_TEXT, screenWidth >> 1, 20, ALIGN_CENTER, 200, 20, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
840 elem->drawElem = &drawMenuText;
841 } else if (!strcmp(elementsType[TYPE_ITEMS_LIST], type)) {
842 if (!theme->itemsList) {
843 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);
844 initItemsList(themePath, themeConfig, theme, elem, name, NULL);
845 theme->itemsList = elem;
847 } else if (!strcmp(elementsType[TYPE_ITEM_ICON], type)) {
848 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 80, theme->usedHeight >> 1, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
849 initGameImage(themePath, themeConfig, theme, elem, name, "ICO", 20, NULL, NULL);
850 } else if (!strcmp(elementsType[TYPE_ITEM_COVER], type)) {
851 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 520, theme->usedHeight >> 1, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
852 initGameImage(themePath, themeConfig, theme, elem, name, "COV", 10, NULL, NULL);
853 } else if (!strcmp(elementsType[TYPE_ITEM_TEXT], type)) {
854 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ITEM_TEXT, 520, 370, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
855 elem->drawElem = &drawItemText;
856 } else if (!strcmp(elementsType[TYPE_HINT_TEXT], type)) {
857 elem = initBasic(themePath, themeConfig, theme, name, TYPE_HINT_TEXT, 16, -HINT_HEIGHT, ALIGN_NONE, 12, 20, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
858 elem->drawElem = &drawHintText;
859 } else if (!strcmp(elementsType[TYPE_INFO_HINT_TEXT], type)) {
860 elem = initBasic(themePath, themeConfig, theme, name, TYPE_INFO_HINT_TEXT, 16, -HINT_HEIGHT, ALIGN_NONE, 12, 20, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
861 elem->drawElem = &drawInfoHintText;
862 } else if (!strcmp(elementsType[TYPE_LOADING_ICON], type)) {
863 if (!theme->loadingIcon)
864 theme->loadingIcon = initBasic(themePath, themeConfig, theme, name, TYPE_LOADING_ICON, -50, -50, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
867 if (elem) {
868 if (!elems->first)
869 elems->first = elem;
871 if (!elems->last)
872 elems->last = elem;
873 else {
874 elems->last->next = elem;
875 elems->last = elem;
878 } else
879 return 0; // ends the reading of elements
882 return 1;
885 static void freeGUIElems(theme_elems_t* elems) {
886 theme_element_t* elem = elems->first;
887 while (elem) {
888 elems->first = elem->next;
889 elem->endElem(elem);
890 elem = elems->first;
894 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
895 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
897 GSTEXTURE* thmGetTexture(unsigned int id) {
898 if (id >= TEXTURES_COUNT)
899 return NULL;
900 else {
901 // see if the texture is valid
902 GSTEXTURE* txt = &gTheme->textures[id];
904 if (txt->Mem)
905 return txt;
906 else
907 return NULL;
911 static void thmFree(theme_t* theme) {
912 if (theme) {
913 // free elements
914 freeGUIElems(&theme->mainElems);
915 freeGUIElems(&theme->infoElems);
917 // free textures
918 GSTEXTURE* texture;
919 int id = 0;
920 for(; id < TEXTURES_COUNT; id++) {
921 texture = &theme->textures[id];
922 if (texture->Mem != NULL) {
923 free(texture->Mem);
924 texture->Mem = NULL;
928 // free fonts
929 for (id = 0; id < THM_MAX_FONTS; ++id) {
930 int fntid = theme->fonts[id];
932 if (fntid != FNT_DEFAULT)
933 fntRelease(fntid);
936 free(theme);
937 theme = NULL;
941 static int thmReadEntry(int index, char* path, char* separator, char* name, unsigned int mode) {
942 if (FIO_SO_ISDIR(mode) && strstr(name, "thm_")) {
943 theme_file_t* currTheme = &themes[nThemes + index];
945 int length = strlen(name) - 4 + 1;
946 currTheme->name = (char*) malloc(length * sizeof(char));
947 memcpy(currTheme->name, name + 4, length);
948 currTheme->name[length - 1] = '\0';
950 length = strlen(path) + 1 + strlen(name) + 1 + 1;
951 currTheme->filePath = (char*) malloc(length * sizeof(char));
952 sprintf(currTheme->filePath, "%s%s%s%s", path, separator, name, separator);
954 LOG("THEMES Theme found: %s\n", currTheme->filePath);
956 index++;
958 return index;
961 /* themePath must contains the leading separator (as it is dependent of the device, we can't know here) */
962 static int thmLoadResource(int texId, char* themePath, short psm, int useDefault) {
963 int success = -1;
964 GSTEXTURE* texture = &gTheme->textures[texId];
966 if (themePath != NULL)
967 success = texDiscoverLoad(texture, themePath, texId, psm); // only set success here
969 if ((success < 0) && useDefault)
970 texPngLoad(texture, NULL, texId, psm); // we don't mind the result of "default"
972 return success;
975 static void thmSetColors(theme_t* theme) {
976 memcpy(theme->bgColor, gDefaultBgColor, 3);
977 theme->textColor = GS_SETREG_RGBA(gDefaultTextColor[0], gDefaultTextColor[1], gDefaultTextColor[2], 0xff);
978 theme->uiTextColor = GS_SETREG_RGBA(gDefaultUITextColor[0], gDefaultUITextColor[1], gDefaultUITextColor[2], 0xff);
979 theme->selTextColor = GS_SETREG_RGBA(gDefaultSelTextColor[0], gDefaultSelTextColor[1], gDefaultSelTextColor[2], 0xff);
981 theme_element_t* elem = theme->mainElems.first;
982 while (elem) {
983 elem->color = theme->textColor;
984 elem = elem->next;
988 static void thmLoadFonts(config_set_t* themeConfig, const char* themePath, theme_t* theme) {
989 int fntID; // theme side font id, not the fntSys handle
990 for (fntID = -1; fntID < THM_MAX_FONTS; ++fntID) {
991 // does the font by the key exist?
992 char fntKey[16];
994 // -1 is a placeholder for default font...
995 if (fntID >= 0) {
996 // Default font handle...
997 theme->fonts[fntID] = FNT_DEFAULT;
998 snprintf(fntKey, 16, "font%d", fntID);
999 } else {
1000 snprintf(fntKey, 16, "default_font");
1003 char *fntFile;
1004 int cfgKeyOK = configGetStr(themeConfig, fntKey, &fntFile);
1005 if (!cfgKeyOK && (fntID >= 0))
1006 continue;
1008 char fullPath[128];
1010 if (fntID < 0) {
1011 // replace the default font
1012 if (cfgKeyOK) {
1013 snprintf(fullPath, 128, "%s%s", themePath, fntFile);
1015 int size = -1;
1016 void* customFont = readFile(fullPath, -1, &size);
1018 if (customFont)
1019 fntReplace(FNT_DEFAULT, customFont, size, 1, 0);
1020 } else {
1021 // TODO reload the language font file
1022 fntSetDefault(FNT_DEFAULT);
1024 } else {
1025 snprintf(fullPath, 128, "%s%s", themePath, fntFile);
1026 int fntHandle = fntLoadFile(fullPath);
1028 // Do we have a valid font? Assign the font handle to the theme font slot
1029 if (fntHandle != FNT_ERROR)
1030 theme->fonts[fntID] = fntHandle;
1035 static void thmLoad(char* themePath) {
1036 LOG("THEMES Load theme path=%s\n", themePath);
1037 theme_t* curT = gTheme;
1038 theme_t* newT = (theme_t*) malloc(sizeof(theme_t));
1039 memset(newT, 0, sizeof(theme_t));
1041 newT->useDefault = 1;
1042 newT->usedHeight = 480;
1043 thmSetColors(newT);
1044 newT->mainElems.first = NULL;
1045 newT->mainElems.last = NULL;
1046 newT->infoElems.first = NULL;
1047 newT->infoElems.last = NULL;
1048 newT->gameCacheCount = 0;
1049 newT->itemsList = NULL;
1050 newT->loadingIcon = NULL;
1051 newT->loadingIconCount = LOAD7_ICON - LOAD0_ICON + 1;
1053 config_set_t* themeConfig = NULL;
1054 if (!themePath) {
1055 themeConfig = configAlloc(0, NULL, NULL);
1056 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_MENU_ICON], "_");
1057 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_MENU_TEXT], "_");
1058 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEMS_LIST], "_");
1059 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_ICON], "_");
1060 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_COVER], "_");
1061 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_TEXT], "_");
1062 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_HINT_TEXT], "_");
1063 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_LOADING_ICON], "_");
1065 // reset the default font to be sure
1066 fntSetDefault(FNT_DEFAULT);
1067 } else {
1068 char path[255];
1069 snprintf(path, 255, "%sconf_theme.cfg", themePath);
1070 themeConfig = configAlloc(0, NULL, path);
1071 configRead(themeConfig); // try to load the theme config file
1073 int intValue;
1074 if (configGetInt(themeConfig, "use_default", &intValue))
1075 newT->useDefault = intValue;
1077 if (configGetInt(themeConfig, "use_real_height", &intValue)) {
1078 if (intValue)
1079 newT->usedHeight = screenHeight;
1082 configGetColor(themeConfig, "bg_color", newT->bgColor);
1084 unsigned char color[3];
1085 if (configGetColor(themeConfig, "text_color", color))
1086 newT->textColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1088 if (configGetColor(themeConfig, "ui_text_color", color))
1089 newT->uiTextColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1091 if (configGetColor(themeConfig, "sel_text_color", color))
1092 newT->selTextColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1094 // before loading the element definitions, we have to have the fonts prepared
1095 // for that, we load the fonts and a translation table
1096 thmLoadFonts(themeConfig, themePath, newT);
1098 int i = 1;
1099 snprintf(path, 255, "main0");
1100 while (addGUIElem(themePath, themeConfig, newT, &newT->mainElems, NULL, path))
1101 snprintf(path, 255, "main%d", i++);
1103 i = 1;
1104 snprintf(path, 255, "info0");
1105 while(addGUIElem(themePath, themeConfig, newT, &newT->infoElems, NULL, path))
1106 snprintf(path, 255, "info%d", i++);
1109 validateGUIElems(themePath, themeConfig, newT);
1110 configFree(themeConfig);
1112 LOG("THEMES Number of cache: %d\n", newT->gameCacheCount);
1113 LOG("THEMES Used height: %d\n", newT->usedHeight);
1115 /// Now swap theme and start loading textures
1116 if (newT->usedHeight == screenHeight)
1117 rmResetShiftRatio();
1118 else
1119 rmSetShiftRatio((float) screenHeight / newT->usedHeight);
1121 int i;
1122 // default all to not loaded...
1123 for (i = 0; i < TEXTURES_COUNT; i++) {
1124 newT->textures[i].Mem = NULL;
1127 // LOGO, loaded here to avoid flickering during startup with device in AUTO + theme set
1128 texPngLoad(&newT->textures[LOGO_PICTURE], NULL, LOGO_PICTURE, GS_PSM_CT24);
1130 gTheme = newT;
1131 thmFree(curT);
1133 // First start with busy icon
1134 char* path = themePath;
1135 int customBusy = 0;
1136 for (i = LOAD0_ICON; i <= LOAD7_ICON; i++) {
1137 if (thmLoadResource(i, path, GS_PSM_CT32, gTheme->useDefault) >= 0)
1138 customBusy = 1;
1139 else {
1140 if (customBusy)
1141 break;
1142 else
1143 path = NULL;
1146 gTheme->loadingIconCount = i;
1148 // Customizable icons
1149 for (i = USB_ICON; i <= START_ICON; i++)
1150 thmLoadResource(i, themePath, GS_PSM_CT32, gTheme->useDefault);
1152 // Not customizable icons
1153 for (i = L1_ICON; i <= R2_ICON; i++)
1154 thmLoadResource(i, NULL, GS_PSM_CT32, 1);
1157 static void thmRebuildGuiNames() {
1158 if (guiThemesNames)
1159 free(guiThemesNames);
1161 // build the languages name list
1162 guiThemesNames = (char**) malloc((nThemes + 2) * sizeof(char**));
1164 // add default internal
1165 guiThemesNames[0] = "<OPL>";
1167 int i = 0;
1168 for (; i < nThemes; i++) {
1169 guiThemesNames[i + 1] = themes[i].name;
1172 guiThemesNames[nThemes + 1] = NULL;
1175 void thmAddElements(char* path, char* separator, int mode) {
1176 nThemes += listDir(path, separator, THM_MAX_FILES - nThemes, &thmReadEntry);
1177 thmRebuildGuiNames();
1179 char* temp;
1180 if (configGetStr(configGetByType(CONFIG_OPL), "theme", &temp)) {
1181 LOG("THEMES Trying to set again theme: %s\n", temp);
1182 if (thmSetGuiValue(thmFindGuiID(temp), 0))
1183 moduleUpdateMenu(mode, 1);
1187 void thmInit() {
1188 LOG("THEMES Init\n");
1189 gTheme = NULL;
1191 thmReloadScreenExtents();
1193 // initialize default internal
1194 thmLoad(NULL);
1196 thmAddElements(gBaseMCDir, "/", -1);
1199 void thmReinit(char* path) {
1200 thmLoad(NULL);
1201 guiThemeID = 0;
1203 int i = 0;
1204 while (i < nThemes) {
1205 if (strncmp(themes[i].filePath, path, strlen(path)) == 0) {
1206 LOG("THEMES Remove theme: %s\n", themes[i].filePath);
1207 nThemes--;
1208 free(themes[i].name);
1209 themes[i].name = themes[nThemes].name;
1210 themes[nThemes].name = NULL;
1211 free(themes[i].filePath);
1212 themes[i].filePath = themes[nThemes].filePath;
1213 themes[nThemes].filePath = NULL;
1214 } else
1215 i++;
1218 thmRebuildGuiNames();
1221 void thmReloadScreenExtents() {
1222 rmGetScreenExtents(&screenWidth, &screenHeight);
1225 char* thmGetValue() {
1226 return guiThemesNames[guiThemeID];
1229 int thmSetGuiValue(int themeID, int reload) {
1230 if (themeID != -1) {
1231 if (guiThemeID != themeID || reload) {
1232 if (themeID != 0)
1233 thmLoad(themes[themeID - 1].filePath);
1234 else
1235 thmLoad(NULL);
1237 guiThemeID = themeID;
1238 configSetStr(configGetByType(CONFIG_OPL), "theme", thmGetValue());
1239 return 1;
1241 else if (guiThemeID == 0)
1242 thmSetColors(gTheme);
1244 return 0;
1247 int thmGetGuiValue() {
1248 return guiThemeID;
1251 int thmFindGuiID(char* theme) {
1252 if (theme) {
1253 int i = 0;
1254 for (; i < nThemes; i++) {
1255 if (stricmp(themes[i].name, theme) == 0)
1256 return i + 1;
1259 return 0;
1262 char **thmGetGuiList() {
1263 return guiThemesNames;
1266 void thmEnd() {
1267 thmFree(gTheme);
1269 int i = 0;
1270 for (; i < nThemes; i++) {
1271 free(themes[i].name);
1272 free(themes[i].filePath);
1275 free(guiThemesNames);