* don't display a share connection error when listing share
[open-ps2-loader.git] / src / themes.c
blob0c45ebdc600236ccb1a1bb5c22f13c4fdc2f50ba
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("elemStaticText %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 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, mutableText->alias, elem->color);
204 static void initAttributeText(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
205 char* attribute) {
207 char elemProp[64];
209 snprintf(elemProp, 64, "%s_attribute", name);
210 configGetStr(themeConfig, elemProp, &attribute);
211 if (attribute) {
212 elem->extended = initMutableText(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_TEXT, elem, attribute, NULL, DISPLAY_ALWAYS, SIZING_NONE);
213 elem->endElem = &endMutableText;
214 elem->drawElem = &drawAttributeText;
215 } else
216 LOG("elemAttributeText %s: NO attribute, elem disabled !!\n", name);
219 // Common functions for Image ///////////////////////////////////////////////////////////////////////////////////////////////
221 static void findDuplicate(theme_element_t* first, char* cachePattern, char* defaultTexture, char* overlayTexture, mutable_image_t* target) {
222 theme_element_t* elem = first;
223 while (elem) {
224 if ((elem->type == TYPE_STATIC_IMAGE) || (elem->type == TYPE_ATTRIBUTE_IMAGE) || (elem->type == TYPE_GAME_IMAGE) || (elem->type == TYPE_BACKGROUND)) {
225 mutable_image_t* source = (mutable_image_t*) elem->extended;
227 if (cachePattern && source->cache && !strcmp(cachePattern, source->cache->suffix)) {
228 target->cache = source->cache;
229 target->cacheLinked = 1;
230 LOG("Re-using a cache for pattern %s\n", cachePattern);
233 if (defaultTexture && source->defaultTexture && !strcmp(defaultTexture, source->defaultTexture->name)) {
234 target->defaultTexture = source->defaultTexture;
235 target->defaultTextureLinked = 1;
236 LOG("Re-using the default texture for %s\n", defaultTexture);
239 if (overlayTexture && source->overlayTexture && !strcmp(overlayTexture, source->overlayTexture->name)) {
240 target->overlayTexture = source->overlayTexture;
241 target->overlayTextureLinked = 1;
242 LOG("Re-using the overlay texture for %s\n", overlayTexture);
246 elem = elem->next;
250 static void freeImageTexture(image_texture_t* texture) {
251 if (texture) {
252 if (texture->source.Mem)
253 free(texture->source.Mem);
255 free(texture->name);
257 free(texture);
261 static image_texture_t* initImageTexture(char* themePath, config_set_t* themeConfig, char* name, char* imgName, int isOverlay) {
262 image_texture_t* texture = (image_texture_t*) malloc(sizeof(image_texture_t));
263 texPrepare(&texture->source, isOverlay ? GS_PSM_CT32 : GS_PSM_CT24);
264 texture->name = NULL;
266 char path[255];
267 snprintf(path, 255, "%s%s", themePath, imgName);
268 if (texDiscoverLoad(&texture->source, path, -1, isOverlay ? GS_PSM_CT32 : GS_PSM_CT24) >= 0) {
269 int length = strlen(imgName) + 1;
270 texture->name = (char*) malloc(length * sizeof(char));
271 memcpy(texture->name, imgName, length);
273 if (isOverlay) {
274 int intValue;
275 char elemProp[64];
276 snprintf(elemProp, 64, "%s_overlay_ulx", name);
277 if (configGetInt(themeConfig, elemProp, &intValue))
278 texture->upperLeft_x = intValue;
279 snprintf(elemProp, 64, "%s_overlay_uly", name);
280 if (configGetInt(themeConfig, elemProp, &intValue))
281 texture->upperLeft_y = intValue;
282 snprintf(elemProp, 64, "%s_overlay_urx", name);
283 if (configGetInt(themeConfig, elemProp, &intValue))
284 texture->upperRight_x = intValue;
285 snprintf(elemProp, 64, "%s_overlay_ury", name);
286 if (configGetInt(themeConfig, elemProp, &intValue))
287 texture->upperRight_y = intValue;
288 snprintf(elemProp, 64, "%s_overlay_llx", name);
289 if (configGetInt(themeConfig, elemProp, &intValue))
290 texture->lowerLeft_x = intValue;
291 snprintf(elemProp, 64, "%s_overlay_lly", name);
292 if (configGetInt(themeConfig, elemProp, &intValue))
293 texture->lowerLeft_y = intValue;
294 snprintf(elemProp, 64, "%s_overlay_lrx", name);
295 if (configGetInt(themeConfig, elemProp, &intValue))
296 texture->lowerRight_x = intValue;
297 snprintf(elemProp, 64, "%s_overlay_lry", name);
298 if (configGetInt(themeConfig, elemProp, &intValue))
299 texture->lowerRight_y = intValue;
301 } else {
302 freeImageTexture(texture);
303 texture = NULL;
306 return texture;
309 static void endMutableImage(struct theme_element* elem) {
310 mutable_image_t* mutableImage = (mutable_image_t*) elem->extended;
311 if (mutableImage) {
312 if (mutableImage->cache && !mutableImage->cacheLinked)
313 cacheDestroyCache(mutableImage->cache);
315 if (mutableImage->defaultTexture && !mutableImage->defaultTextureLinked)
316 freeImageTexture(mutableImage->defaultTexture);
318 if (mutableImage->overlayTexture && !mutableImage->overlayTextureLinked)
319 freeImageTexture(mutableImage->overlayTexture);
321 free(mutableImage);
324 free(elem);
327 static mutable_image_t* initMutableImage(char* themePath, config_set_t* themeConfig, theme_t* theme, char* name, int type,
328 char* cachePattern, int cacheCount, char* defaultTexture, char* overlayTexture) {
330 mutable_image_t* mutableImage = (mutable_image_t*) malloc(sizeof(mutable_image_t));
331 mutableImage->currentUid = -1;
332 mutableImage->currentItemId = -1;
333 mutableImage->currentValue = NULL;
334 mutableImage->cache = NULL;
335 mutableImage->cacheLinked = 0;
336 mutableImage->defaultTexture = NULL;
337 mutableImage->defaultTextureLinked = 0;
338 mutableImage->overlayTexture = NULL;
339 mutableImage->overlayTextureLinked = 0;
341 char elemProp[64];
343 if (type == TYPE_ATTRIBUTE_IMAGE) {
344 snprintf(elemProp, 64, "%s_attribute", name);
345 configGetStr(themeConfig, elemProp, &cachePattern);
346 LOG("elemMutableImage %s: type: %d using cache pattern: %s\n", name, type, cachePattern);
347 } else if ((type == TYPE_GAME_IMAGE) || type == (TYPE_BACKGROUND)) {
348 snprintf(elemProp, 64, "%s_pattern", name);
349 configGetStr(themeConfig, elemProp, &cachePattern);
350 snprintf(elemProp, 64, "%s_count", name);
351 configGetInt(themeConfig, elemProp, &cacheCount);
352 LOG("elemMutableImage %s: type: %d using cache pattern: %s\n", name, type, cachePattern);
355 snprintf(elemProp, 64, "%s_default", name);
356 configGetStr(themeConfig, elemProp, &defaultTexture);
358 if (type != TYPE_BACKGROUND) {
359 snprintf(elemProp, 64, "%s_overlay", name);
360 configGetStr(themeConfig, elemProp, &overlayTexture);
363 findDuplicate(theme->mainElems.first, cachePattern, defaultTexture, overlayTexture, mutableImage);
364 findDuplicate(theme->infoElems.first, cachePattern, defaultTexture, overlayTexture, mutableImage);
366 if (cachePattern && !mutableImage->cache) {
367 if (type == TYPE_ATTRIBUTE_IMAGE)
368 mutableImage->cache = cacheInitCache(-1, themePath, 0, cachePattern, 1);
369 else
370 mutableImage->cache = cacheInitCache(theme->gameCacheCount++, "ART", 1, cachePattern, cacheCount);
373 if (defaultTexture && !mutableImage->defaultTexture)
374 mutableImage->defaultTexture = initImageTexture(themePath, themeConfig, name, defaultTexture, 0);
376 if (overlayTexture && !mutableImage->overlayTexture)
377 mutableImage->overlayTexture = initImageTexture(themePath, themeConfig, name, overlayTexture, 1);
379 return mutableImage;
382 // StaticImage //////////////////////////////////////////////////////////////////////////////////////////////////////////////
384 static void drawStaticImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
385 mutable_image_t* staticImage = (mutable_image_t*) elem->extended;
386 if (staticImage->overlayTexture) {
387 rmDrawOverlayPixmap(&staticImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
388 &staticImage->defaultTexture->source, staticImage->overlayTexture->upperLeft_x, staticImage->overlayTexture->upperLeft_y, staticImage->overlayTexture->upperRight_x, staticImage->overlayTexture->upperRight_y,
389 staticImage->overlayTexture->lowerLeft_x, staticImage->overlayTexture->lowerLeft_y, staticImage->overlayTexture->lowerRight_x, staticImage->overlayTexture->lowerRight_y);
390 } else
391 rmDrawPixmap(&staticImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
394 static void initStaticImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
395 char* imageName) {
397 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, NULL, 0, imageName, NULL);
398 elem->extended = mutableImage;
399 elem->endElem = &endMutableImage;
401 if (mutableImage->defaultTexture)
402 elem->drawElem = &drawStaticImage;
403 else
404 LOG("elemStaticImage %s: NO image name, elem disabled !!\n", name);
407 // GameImage ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
409 static GSTEXTURE* getGameImageTexture(image_cache_t* cache, void* support, struct submenu_item* item) {
410 if (gEnableArt) {
411 item_list_t * list = (item_list_t *) support;
412 char* startup = list->itemGetStartup(item->id);
413 //LOG("getGameCachedTex, prefix: %s addsep: %d value: %s suffix: %s\n", cache->prefix, cache->addSeparator, startup, suffix);
414 return cacheGetTexture(cache, list, &item->cache_id[cache->userId], &item->cache_uid[cache->userId], startup);
417 return NULL;
420 static void drawGameImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
421 mutable_image_t* gameImage = (mutable_image_t*) elem->extended;
422 if (item) {
423 GSTEXTURE* texture = getGameImageTexture(gameImage->cache, menu->item->userdata, &item->item);
424 if (!texture || !texture->Mem) {
425 if (gameImage->defaultTexture)
426 texture = &gameImage->defaultTexture->source;
427 else {
428 if (elem->type == TYPE_BACKGROUND)
429 guiDrawBGPlasma();
430 return;
434 if (gameImage->overlayTexture) {
435 rmDrawOverlayPixmap(&gameImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
436 texture, gameImage->overlayTexture->upperLeft_x, gameImage->overlayTexture->upperLeft_y, gameImage->overlayTexture->upperRight_x, gameImage->overlayTexture->upperRight_y,
437 gameImage->overlayTexture->lowerLeft_x, gameImage->overlayTexture->lowerLeft_y, gameImage->overlayTexture->lowerRight_x, gameImage->overlayTexture->lowerRight_y);
438 } else
439 rmDrawPixmap(texture, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
441 } else if (elem->type == TYPE_BACKGROUND) {
442 if (gameImage->defaultTexture)
443 rmDrawPixmap(&gameImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
444 else
445 guiDrawBGPlasma();
449 static void initGameImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
450 char* pattern, int count, char* texture, char* overlay) {
452 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, pattern, count, texture, overlay);
453 elem->extended = mutableImage;
454 elem->endElem = &endMutableImage;
456 if (mutableImage->cache)
457 elem->drawElem = &drawGameImage;
458 else
459 LOG("elemGameImage %s: NO pattern, elem disabled !!\n", name);
462 // AttributeImage ///////////////////////////////////////////////////////////////////////////////////////////////////////////
464 static void drawAttributeImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
465 mutable_image_t* attributeImage = (mutable_image_t*) elem->extended;
466 if (config) {
467 if (attributeImage->currentItemId != item->item.id) {
468 // force refresh
469 attributeImage->currentUid = -1;
470 attributeImage->currentItemId = item->item.id;
471 attributeImage->currentValue = NULL;
472 configGetStr(config, attributeImage->cache->suffix, &attributeImage->currentValue);
474 if (attributeImage->currentValue) {
475 int posZ = 0;
476 GSTEXTURE* texture = cacheGetTexture(attributeImage->cache, menu->item->userdata, &posZ, &attributeImage->currentUid, attributeImage->currentValue);
477 if (texture && texture->Mem) {
478 if (attributeImage->overlayTexture) {
479 rmDrawOverlayPixmap(&attributeImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
480 texture, attributeImage->overlayTexture->upperLeft_x, attributeImage->overlayTexture->upperLeft_y, attributeImage->overlayTexture->upperRight_x, attributeImage->overlayTexture->upperRight_y,
481 attributeImage->overlayTexture->lowerLeft_x, attributeImage->overlayTexture->lowerLeft_y, attributeImage->overlayTexture->lowerRight_x, attributeImage->overlayTexture->lowerRight_y);
482 } else
483 rmDrawPixmap(texture, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
485 return;
489 if (attributeImage->defaultTexture)
490 rmDrawPixmap(&attributeImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
493 static void initAttributeImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name) {
494 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, NULL, 1, NULL, NULL);
495 elem->extended = mutableImage;
496 elem->endElem = &endMutableImage;
498 if (mutableImage->cache)
499 elem->drawElem = &drawAttributeImage;
500 else
501 LOG("elemAttributeImage %s: NO attribute, elem disabled !!\n", name);
504 // BasicElement /////////////////////////////////////////////////////////////////////////////////////////////////////////////
506 static void endBasic(theme_element_t* elem) {
507 if (elem->extended)
508 free(elem->extended);
510 free(elem);
513 static theme_element_t* initBasic(char* themePath, config_set_t* themeConfig, theme_t* theme,
514 char* name, int type, int x, int y, short aligned, int w, int h, short scaled, u64 color, int font) {
516 int intValue;
517 unsigned char charColor[3];
518 char* temp;
519 char elemProp[64];
521 theme_element_t* elem = (theme_element_t*) malloc(sizeof(theme_element_t));
523 elem->type = type;
524 elem->extended = NULL;
525 elem->drawElem = NULL;
526 elem->endElem = &endBasic;
527 elem->next = NULL;
529 snprintf(elemProp, 64, "%s_x", name);
530 if (configGetStr(themeConfig, elemProp, &temp)) {
531 if (!strncmp(temp, "POS_MID", 7))
532 x = screenWidth >> 1;
533 else
534 x = atoi(temp);
536 if (x < 0)
537 elem->posX = screenWidth + x;
538 else
539 elem->posX = x;
541 snprintf(elemProp, 64, "%s_y", name);
542 if (configGetStr(themeConfig, elemProp, &temp)) {
543 if (!strncmp(temp, "POS_MID", 7))
544 y = screenHeight >> 1;
545 else
546 y = atoi(temp);
548 if (y < 0)
549 elem->posY = ceil((screenHeight + y) * theme->usedHeight / screenHeight);
550 else
551 elem->posY = y;
553 snprintf(elemProp, 64, "%s_width", name);
554 if (configGetStr(themeConfig, elemProp, &temp)) {
555 if (!strncmp(temp, "DIM_INF", 7))
556 elem->width = screenWidth;
557 else
558 elem->width = atoi(temp);
559 } else
560 elem->width = w;
562 snprintf(elemProp, 64, "%s_height", name);
563 if (configGetStr(themeConfig, elemProp, &temp)) {
564 if (!strncmp(temp, "DIM_INF", 7))
565 elem->height = screenHeight;
566 else
567 elem->height = atoi(temp);
568 } else
569 elem->height = h;
571 snprintf(elemProp, 64, "%s_aligned", name);
572 if (configGetInt(themeConfig, elemProp, &intValue))
573 elem->aligned = intValue;
574 else
575 elem->aligned = aligned;
577 snprintf(elemProp, 64, "%s_scaled", name);
578 if (configGetInt(themeConfig, elemProp, &intValue))
579 elem->scaled = intValue;
580 else
581 elem->scaled = scaled;
583 snprintf(elemProp, 64, "%s_color", name);
584 if (configGetColor(themeConfig, elemProp, charColor))
585 elem->color = GS_SETREG_RGBA(charColor[0], charColor[1], charColor[2], 0xff);
586 else
587 elem->color = color;
589 snprintf(elemProp, 64, "%s_font", name);
590 if (configGetInt(themeConfig, elemProp, &intValue))
591 font = intValue;
592 if (font >= 0 && font < THM_MAX_FONTS)
593 elem->font = theme->fonts[font];
594 else
595 elem->font = FNT_DEFAULT;
597 return elem;
600 // Internal elements ////////////////////////////////////////////////////////////////////////////////////////////////////////
602 static void drawBackground(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
603 guiDrawBGPlasma();
606 static void initBackground(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
607 char* pattern, int count, char* texture) {
609 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, pattern, count, texture, NULL);
610 elem->extended = mutableImage;
611 elem->endElem = &endMutableImage;
613 if (mutableImage->cache)
614 elem->drawElem = &drawGameImage;
615 else if (mutableImage->defaultTexture)
616 elem->drawElem = &drawStaticImage;
617 else
618 elem->drawElem = &drawBackground;
621 static void drawMenuIcon(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
622 GSTEXTURE* menuIconTex = thmGetTexture(menu->item->icon_id);
623 if (menuIconTex && menuIconTex->Mem)
624 rmDrawPixmap(menuIconTex, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
627 static void drawMenuText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
628 GSTEXTURE* leftIconTex = NULL, *rightIconTex = NULL;
629 if (menu->prev)
630 leftIconTex = thmGetTexture(LEFT_ICON);
631 if (menu->next)
632 rightIconTex = thmGetTexture(RIGHT_ICON);
634 if (elem->aligned) {
635 int offset = elem->width >> 1;
636 if (leftIconTex && leftIconTex->Mem)
637 rmDrawPixmap(leftIconTex, elem->posX - offset, elem->posY, elem->aligned, leftIconTex->Width, leftIconTex->Height, elem->scaled, gDefaultCol);
638 if (rightIconTex && rightIconTex->Mem)
639 rmDrawPixmap(rightIconTex, elem->posX + offset, elem->posY, elem->aligned, rightIconTex->Width, rightIconTex->Height, elem->scaled, gDefaultCol);
641 else {
642 if (leftIconTex && leftIconTex->Mem)
643 rmDrawPixmap(leftIconTex, elem->posX - leftIconTex->Width, elem->posY, elem->aligned, leftIconTex->Width, leftIconTex->Height, elem->scaled, gDefaultCol);
644 if (rightIconTex && rightIconTex->Mem)
645 rmDrawPixmap(rightIconTex, elem->posX + elem->width, elem->posY, elem->aligned, rightIconTex->Width, rightIconTex->Height, elem->scaled, gDefaultCol);
647 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, menuItemGetText(menu->item), elem->color);
650 static void drawItemsList(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
651 if (item) {
652 items_list_t* itemsList = (items_list_t*) elem->extended;
654 int posX = elem->posX, posY = elem->posY;
655 if (elem->aligned) {
656 posX -= elem->width >> 1;
657 posY -= elem->height >> 1;
660 submenu_list_t *ps = menu->item->pagestart;
661 int others = 0;
662 u64 color;
663 while (ps && (others++ < itemsList->displayedItems)) {
664 if (ps == item)
665 color = gTheme->selTextColor;
666 else
667 color = elem->color;
669 if (itemsList->decoratorImage) {
670 GSTEXTURE* itemIconTex = getGameImageTexture(itemsList->decoratorImage->cache, menu->item->userdata, &ps->item);
671 if (itemIconTex && itemIconTex->Mem)
672 rmDrawPixmap(itemIconTex, posX, posY, ALIGN_NONE, DECORATOR_SIZE, DECORATOR_SIZE, elem->scaled, gDefaultCol);
673 else {
674 if (itemsList->decoratorImage->defaultTexture)
675 rmDrawPixmap(&itemsList->decoratorImage->defaultTexture->source, posX, posY, ALIGN_NONE, DECORATOR_SIZE, DECORATOR_SIZE, elem->scaled, gDefaultCol);
677 fntRenderString(elem->font, posX + DECORATOR_SIZE, posY, ALIGN_NONE, elem->width, elem->height, submenuItemGetText(&ps->item), color);
678 } else
679 fntRenderString(elem->font, posX, posY, ALIGN_NONE, elem->width, elem->height, submenuItemGetText(&ps->item), color);
681 posY += MENU_ITEM_HEIGHT;
682 ps = ps->next;
687 static void initItemsList(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name, char* decorator) {
688 char elemProp[64];
690 items_list_t* itemsList = (items_list_t*) malloc(sizeof(items_list_t));
692 if (elem->width == DIM_UNDEF)
693 elem->width = screenWidth;
695 if (elem->height == DIM_UNDEF)
696 elem->height = theme->usedHeight - (MENU_POS_V + HINT_HEIGHT);
698 itemsList->displayedItems = elem->height / MENU_ITEM_HEIGHT;
699 LOG("elemItemsList %s: displaying %d elems, item height: %d\n", name, itemsList->displayedItems, elem->height);
701 itemsList->decorator = NULL;
702 snprintf(elemProp, 64, "%s_decorator", name);
703 configGetStr(themeConfig, elemProp, &decorator);
704 if (decorator)
705 itemsList->decorator = decorator; // Will be used later (thmValidate)
707 itemsList->decoratorImage = NULL;
709 elem->extended = itemsList;
710 // elem->endElem = &endBasic; does the job
712 elem->drawElem = &drawItemsList;
715 static void drawItemText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
716 if (item) {
717 item_list_t *support = menu->item->userdata;
718 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, support->itemGetStartup(item->item.id), elem->color);
722 static void drawHintText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
723 menu_hint_item_t* hint = menu->item->hints;
724 if (hint) {
725 int x = elem->posX;
727 for (; hint; hint = hint->next) {
728 x = guiDrawIconAndText(hint->icon_id, hint->text_id, elem->font, x, elem->posY, elem->color);
729 x += elem->width;
734 static void drawInfoHintText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
735 int x = elem->posX;
736 x = guiDrawIconAndText(CROSS_ICON, _STR_RUN, elem->font, x, elem->posY, elem->color);
737 x += elem->width;
738 x = guiDrawIconAndText(CIRCLE_ICON, _STR_O_BACK, elem->font, x, elem->posY, elem->color);
741 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
743 static void validateGUIElems(char* themePath, config_set_t* themeConfig, theme_t* theme) {
744 // 1. check we have a valid Background elements
745 if ( !theme->mainElems.first || (theme->mainElems.first->type != TYPE_BACKGROUND) ) {
746 LOG("No valid background found for main, add default BG_ART\n");
747 theme_element_t* backgroundElem = initBasic(themePath, themeConfig, theme, "bg", TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
748 if (themePath)
749 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, "background");
750 else
751 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, NULL);
752 backgroundElem->next = theme->mainElems.first;
753 theme->mainElems.first = backgroundElem;
756 if (theme->infoElems.first) {
757 if (theme->infoElems.first->type != TYPE_BACKGROUND) {
758 LOG("No valid background found for info, add default BG_ART\n");
759 theme_element_t* backgroundElem = initBasic(themePath, themeConfig, theme, "bg", TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
760 if (themePath)
761 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, "background");
762 else
763 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, NULL);
764 backgroundElem->next = theme->infoElems.first;
765 theme->infoElems.first = backgroundElem;
769 // 2. check we have a valid ItemsList element, and link its decorator to the target element
770 if (theme->itemsList) {
771 items_list_t* itemsList = (items_list_t*) theme->itemsList->extended;
772 if (itemsList->decorator) {
773 // Second pass to find the decorator
774 theme_element_t* decoratorElem = theme->mainElems.first;
775 while (decoratorElem) {
776 if (decoratorElem->type == TYPE_GAME_IMAGE) {
777 mutable_image_t* gameImage = (mutable_image_t*) decoratorElem->extended;
778 if (!strcmp(itemsList->decorator, gameImage->cache->suffix)) {
779 // if user want to cache less than displayed items, then disable itemslist icons, if not would load constantly
780 if (gameImage->cache->count >= itemsList->displayedItems)
781 itemsList->decoratorImage = gameImage;
782 break;
786 decoratorElem = decoratorElem->next;
788 itemsList->decorator = NULL;
790 } else {
791 LOG("No itemsList found, adding a default one\n");
792 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);
793 initItemsList(themePath, themeConfig, theme, theme->itemsList, "il", NULL);
794 theme->itemsList->next = theme->mainElems.first->next; // Position the itemsList as second element (right after the Background)
795 theme->mainElems.first->next = theme->itemsList;
799 static int addGUIElem(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_elems_t* elems, char* type, char* name) {
801 int enabled = 1;
802 char elemProp[64];
803 theme_element_t* elem = NULL;
805 snprintf(elemProp, 64, "%s_enabled", name);
806 configGetInt(themeConfig, elemProp, &enabled);
808 if (enabled) {
809 snprintf(elemProp, 64, "%s_type", name);
810 configGetStr(themeConfig, elemProp, &type);
811 if (type) {
812 if (!strcmp(elementsType[TYPE_ATTRIBUTE_TEXT], type)) {
813 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_TEXT, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
814 initAttributeText(themePath, themeConfig, theme, elem, name, NULL);
815 } else if (!strcmp(elementsType[TYPE_STATIC_TEXT], type)) {
816 elem = initBasic(themePath, themeConfig, theme, name, TYPE_STATIC_TEXT, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
817 initStaticText(themePath, themeConfig, theme, elem, name, NULL);
818 } else if (!strcmp(elementsType[TYPE_ATTRIBUTE_IMAGE], type)) {
819 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
820 initAttributeImage(themePath, themeConfig, theme, elem, name);
821 } else if (!strcmp(elementsType[TYPE_GAME_IMAGE], type)) {
822 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
823 initGameImage(themePath, themeConfig, theme, elem, name, NULL, 1, NULL, NULL);
824 } else if (!strcmp(elementsType[TYPE_STATIC_IMAGE], type)) {
825 elem = initBasic(themePath, themeConfig, theme, name, TYPE_STATIC_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
826 initStaticImage(themePath, themeConfig, theme, elem, name, NULL);
827 } else if (!strcmp(elementsType[TYPE_BACKGROUND], type)) {
828 if (!elems->first) { // Background elem can only be the first one
829 elem = initBasic(themePath, themeConfig, theme, name, TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
830 initBackground(themePath, themeConfig, theme, elem, name, NULL, 1, NULL);
832 } else if (!strcmp(elementsType[TYPE_MENU_ICON], type)) {
833 elem = initBasic(themePath, themeConfig, theme, name, TYPE_MENU_ICON, 40, 40, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
834 elem->drawElem = &drawMenuIcon;
835 } else if (!strcmp(elementsType[TYPE_MENU_TEXT], type)) {
836 elem = initBasic(themePath, themeConfig, theme, name, TYPE_MENU_TEXT, screenWidth >> 1, 20, ALIGN_CENTER, 200, 20, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
837 elem->drawElem = &drawMenuText;
838 } else if (!strcmp(elementsType[TYPE_ITEMS_LIST], type)) {
839 if (!theme->itemsList) {
840 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);
841 initItemsList(themePath, themeConfig, theme, elem, name, NULL);
842 theme->itemsList = elem;
844 } else if (!strcmp(elementsType[TYPE_ITEM_ICON], type)) {
845 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 80, theme->usedHeight >> 1, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
846 initGameImage(themePath, themeConfig, theme, elem, name, "ICO", 20, NULL, NULL);
847 } else if (!strcmp(elementsType[TYPE_ITEM_COVER], type)) {
848 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 520, theme->usedHeight >> 1, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
849 initGameImage(themePath, themeConfig, theme, elem, name, "COV", 10, NULL, NULL);
850 } else if (!strcmp(elementsType[TYPE_ITEM_TEXT], type)) {
851 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ITEM_TEXT, 520, 370, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
852 elem->drawElem = &drawItemText;
853 } else if (!strcmp(elementsType[TYPE_HINT_TEXT], type)) {
854 elem = initBasic(themePath, themeConfig, theme, name, TYPE_HINT_TEXT, 16, -HINT_HEIGHT, ALIGN_NONE, 12, 20, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
855 elem->drawElem = &drawHintText;
856 } else if (!strcmp(elementsType[TYPE_INFO_HINT_TEXT], type)) {
857 elem = initBasic(themePath, themeConfig, theme, name, TYPE_INFO_HINT_TEXT, 16, -HINT_HEIGHT, ALIGN_NONE, 12, 20, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
858 elem->drawElem = &drawInfoHintText;
859 } else if (!strcmp(elementsType[TYPE_LOADING_ICON], type)) {
860 if (!theme->loadingIcon)
861 theme->loadingIcon = initBasic(themePath, themeConfig, theme, name, TYPE_LOADING_ICON, -50, -50, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
864 if (elem) {
865 if (!elems->first)
866 elems->first = elem;
868 if (!elems->last)
869 elems->last = elem;
870 else {
871 elems->last->next = elem;
872 elems->last = elem;
875 } else
876 return 0; // ends the reading of elements
879 return 1;
882 static void freeGUIElems(theme_elems_t* elems) {
883 theme_element_t* elem = elems->first;
884 while (elem) {
885 elems->first = elem->next;
886 elem->endElem(elem);
887 elem = elems->first;
891 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
892 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
894 GSTEXTURE* thmGetTexture(unsigned int id) {
895 if (id >= TEXTURES_COUNT)
896 return NULL;
897 else {
898 // see if the texture is valid
899 GSTEXTURE* txt = &gTheme->textures[id];
901 if (txt->Mem)
902 return txt;
903 else
904 return NULL;
908 static void thmFree(theme_t* theme) {
909 if (theme) {
910 // free elements
911 freeGUIElems(&theme->mainElems);
912 freeGUIElems(&theme->infoElems);
914 // free textures
915 GSTEXTURE* texture;
916 int id = 0;
917 for(; id < TEXTURES_COUNT; id++) {
918 texture = &theme->textures[id];
919 if (texture->Mem != NULL) {
920 free(texture->Mem);
921 texture->Mem = NULL;
925 // free fonts
926 for (id = 0; id < THM_MAX_FONTS; ++id) {
927 int fntid = theme->fonts[id];
929 if (fntid != FNT_DEFAULT)
930 fntRelease(fntid);
933 free(theme);
934 theme = NULL;
938 static int thmReadEntry(int index, char* path, char* separator, char* name, unsigned int mode) {
939 if (FIO_SO_ISDIR(mode) && strstr(name, "thm_")) {
940 LOG("thmReadEntry() path=%s sep=%s name=%s\n", path, separator, name);
941 theme_file_t* currTheme = &themes[nThemes + index];
943 int length = strlen(name) - 4 + 1;
944 currTheme->name = (char*) malloc(length * sizeof(char));
945 memcpy(currTheme->name, name + 4, length);
946 currTheme->name[length - 1] = '\0';
948 length = strlen(path) + 1 + strlen(name) + 1 + 1;
949 currTheme->filePath = (char*) malloc(length * sizeof(char));
950 sprintf(currTheme->filePath, "%s%s%s%s", path, separator, name, separator);
952 LOG("Theme found: %s\n", currTheme->filePath);
954 index++;
956 return index;
959 /* themePath must contains the leading separator (as it is dependent of the device, we can't know here) */
960 static int thmLoadResource(int texId, char* themePath, short psm, int useDefault) {
961 int success = -1;
962 GSTEXTURE* texture = &gTheme->textures[texId];
964 if (themePath != NULL)
965 success = texDiscoverLoad(texture, themePath, texId, psm); // only set success here
967 if ((success < 0) && useDefault)
968 texPngLoad(texture, NULL, texId, psm); // we don't mind the result of "default"
970 return success;
973 static void thmSetColors(theme_t* theme) {
974 memcpy(theme->bgColor, gDefaultBgColor, 3);
975 theme->textColor = GS_SETREG_RGBA(gDefaultTextColor[0], gDefaultTextColor[1], gDefaultTextColor[2], 0xff);
976 theme->uiTextColor = GS_SETREG_RGBA(gDefaultUITextColor[0], gDefaultUITextColor[1], gDefaultUITextColor[2], 0xff);
977 theme->selTextColor = GS_SETREG_RGBA(gDefaultSelTextColor[0], gDefaultSelTextColor[1], gDefaultSelTextColor[2], 0xff);
979 theme_element_t* elem = theme->mainElems.first;
980 while (elem) {
981 elem->color = theme->textColor;
982 elem = elem->next;
986 static void thmLoadFonts(config_set_t* themeConfig, const char* themePath, theme_t* theme) {
987 int fntID; // theme side font id, not the fntSys handle
988 for (fntID = -1; fntID < THM_MAX_FONTS; ++fntID) {
989 // does the font by the key exist?
990 char fntKey[16];
992 // -1 is a placeholder for default font...
993 if (fntID >= 0) {
994 // Default font handle...
995 theme->fonts[fntID] = FNT_DEFAULT;
996 snprintf(fntKey, 16, "font%d", fntID);
997 } else {
998 snprintf(fntKey, 16, "default_font");
1001 char *fntFile;
1002 int cfgKeyOK = configGetStr(themeConfig, fntKey, &fntFile);
1003 if (!cfgKeyOK && (fntID >= 0))
1004 continue;
1006 char fullPath[128];
1008 if (fntID < 0) {
1009 // replace the default font
1010 if (cfgKeyOK) {
1011 snprintf(fullPath, 128, "%s%s", themePath, fntFile);
1013 int size = -1;
1014 void* customFont = readFile(fullPath, -1, &size);
1016 if (customFont)
1017 fntReplace(FNT_DEFAULT, customFont, size, 1, 0);
1018 } else
1019 fntSetDefault(FNT_DEFAULT);
1020 } else {
1021 snprintf(fullPath, 128, "%s%s", themePath, fntFile);
1022 int fntHandle = fntLoadFile(fullPath);
1024 // Do we have a valid font? Assign the font handle to the theme font slot
1025 if (fntHandle != FNT_ERROR)
1026 theme->fonts[fntID] = fntHandle;
1031 static void thmLoad(char* themePath) {
1032 LOG("thmLoad() path=%s\n", themePath);
1033 theme_t* curT = gTheme;
1034 theme_t* newT = (theme_t*) malloc(sizeof(theme_t));
1035 memset(newT, 0, sizeof(theme_t));
1037 newT->useDefault = 1;
1038 newT->usedHeight = 480;
1039 thmSetColors(newT);
1040 newT->mainElems.first = NULL;
1041 newT->mainElems.last = NULL;
1042 newT->infoElems.first = NULL;
1043 newT->infoElems.last = NULL;
1044 newT->gameCacheCount = 0;
1045 newT->itemsList = NULL;
1046 newT->loadingIcon = NULL;
1047 newT->loadingIconCount = LOAD7_ICON - LOAD0_ICON + 1;
1049 config_set_t* themeConfig = NULL;
1050 if (!themePath) {
1051 themeConfig = configAlloc(0, NULL, NULL);
1052 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_MENU_ICON], "_");
1053 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_MENU_TEXT], "_");
1054 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEMS_LIST], "_");
1055 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_ICON], "_");
1056 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_COVER], "_");
1057 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_TEXT], "_");
1058 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_HINT_TEXT], "_");
1059 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_LOADING_ICON], "_");
1061 // reset the default font to be sure
1062 fntSetDefault(FNT_DEFAULT);
1063 } else {
1064 char path[255];
1065 snprintf(path, 255, "%sconf_theme.cfg", themePath);
1066 themeConfig = configAlloc(0, NULL, path);
1067 configRead(themeConfig); // try to load the theme config file
1069 int intValue;
1070 if (configGetInt(themeConfig, "use_default", &intValue))
1071 newT->useDefault = intValue;
1073 if (configGetInt(themeConfig, "use_real_height", &intValue)) {
1074 if (intValue)
1075 newT->usedHeight = screenHeight;
1078 configGetColor(themeConfig, "bg_color", newT->bgColor);
1080 unsigned char color[3];
1081 if (configGetColor(themeConfig, "text_color", color))
1082 newT->textColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1084 if (configGetColor(themeConfig, "ui_text_color", color))
1085 newT->uiTextColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1087 if (configGetColor(themeConfig, "sel_text_color", color))
1088 newT->selTextColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1090 // before loading the element definitions, we have to have the fonts prepared
1091 // for that, we load the fonts and a translation table
1092 thmLoadFonts(themeConfig, themePath, newT);
1094 int i = 1;
1095 snprintf(path, 255, "main0");
1096 while (addGUIElem(themePath, themeConfig, newT, &newT->mainElems, NULL, path))
1097 snprintf(path, 255, "main%d", i++);
1099 i = 1;
1100 snprintf(path, 255, "info0");
1101 while(addGUIElem(themePath, themeConfig, newT, &newT->infoElems, NULL, path))
1102 snprintf(path, 255, "info%d", i++);
1105 validateGUIElems(themePath, themeConfig, newT);
1106 configFree(themeConfig);
1108 LOG("theme loaded, number of cache: %d\n", newT->gameCacheCount);
1110 LOG("thmLoad() usedHeight=%d\n", newT->usedHeight);
1112 /// Now swap theme and start loading textures
1113 if (newT->usedHeight == screenHeight)
1114 rmResetShiftRatio();
1115 else
1116 rmSetShiftRatio((float) screenHeight / newT->usedHeight);
1118 int i;
1119 // default all to not loaded...
1120 for (i = 0; i < TEXTURES_COUNT; i++) {
1121 newT->textures[i].Mem = NULL;
1124 // LOGO, loaded here to avoid flickering during startup with device in AUTO + theme set
1125 texPngLoad(&newT->textures[LOGO_PICTURE], NULL, LOGO_PICTURE, GS_PSM_CT24);
1127 gTheme = newT;
1128 thmFree(curT);
1130 // First start with busy icon
1131 char* path = themePath;
1132 int customBusy = 0;
1133 for (i = LOAD0_ICON; i <= LOAD7_ICON; i++) {
1134 if (thmLoadResource(i, path, GS_PSM_CT32, gTheme->useDefault) >= 0)
1135 customBusy = 1;
1136 else {
1137 if (customBusy)
1138 break;
1139 else
1140 path = NULL;
1143 gTheme->loadingIconCount = i;
1145 // Customizable icons
1146 for (i = USB_ICON; i <= DOWN_ICON; i++)
1147 thmLoadResource(i, themePath, GS_PSM_CT32, gTheme->useDefault);
1149 // Not customizable icons
1150 for (i = L1_ICON; i <= START_ICON; i++)
1151 thmLoadResource(i, NULL, GS_PSM_CT32, 1);
1154 static void thmRebuildGuiNames() {
1155 if (guiThemesNames)
1156 free(guiThemesNames);
1158 // build the languages name list
1159 guiThemesNames = (char**) malloc((nThemes + 2) * sizeof(char**));
1161 // add default internal
1162 guiThemesNames[0] = "<OPL>";
1164 int i = 0;
1165 for (; i < nThemes; i++) {
1166 guiThemesNames[i + 1] = themes[i].name;
1169 guiThemesNames[nThemes + 1] = NULL;
1172 void thmAddElements(char* path, char* separator, int mode) {
1173 LOG("thmAddElements() path=%s sep=%s\n", path, separator);
1174 nThemes += listDir(path, separator, THM_MAX_FILES - nThemes, &thmReadEntry);
1175 LOG("thmAddElements() nThemes=%d\n", nThemes);
1176 thmRebuildGuiNames();
1178 char* temp;
1179 if (configGetStr(configGetByType(CONFIG_OPL), "theme", &temp)) {
1180 LOG("Trying to set again theme: %s\n", temp);
1181 if (thmSetGuiValue(thmFindGuiID(temp), 0))
1182 moduleUpdateMenu(mode, 1);
1186 void thmInit() {
1187 LOG("thmInit()\n");
1188 gTheme = NULL;
1190 thmReloadScreenExtents();
1192 // initialize default internal
1193 thmLoad(NULL);
1195 thmAddElements(gBaseMCDir, "/", -1);
1198 void thmReloadScreenExtents() {
1199 rmGetScreenExtents(&screenWidth, &screenHeight);
1202 char* thmGetValue() {
1203 //LOG("thmGetValue() id=%d name=%s\n", guiThemeID, guiThemesNames[guiThemeID]);
1204 return guiThemesNames[guiThemeID];
1207 int thmSetGuiValue(int themeID, int reload) {
1208 LOG("thmSetGuiValue() id=%d\n", themeID);
1209 if (themeID != -1) {
1210 if (guiThemeID != themeID || reload) {
1211 if (themeID != 0)
1212 thmLoad(themes[themeID - 1].filePath);
1213 else
1214 thmLoad(NULL);
1216 guiThemeID = themeID;
1217 configSetStr(configGetByType(CONFIG_OPL), "theme", thmGetValue());
1218 return 1;
1220 else if (guiThemeID == 0)
1221 thmSetColors(gTheme);
1223 return 0;
1226 int thmGetGuiValue() {
1227 //LOG("thmGetGuiValue() id=%d\n", guiThemeID);
1228 return guiThemeID;
1231 int thmFindGuiID(char* theme) {
1232 LOG("thmFindGuiID() theme=%s\n", theme);
1233 if (theme) {
1234 int i = 0;
1235 for (; i < nThemes; i++) {
1236 if (stricmp(themes[i].name, theme) == 0)
1237 return i + 1;
1240 return 0;
1243 char **thmGetGuiList() {
1244 return guiThemesNames;
1247 void thmEnd() {
1248 thmFree(gTheme);
1250 int i = 0;
1251 for (; i < nThemes; i++) {
1252 free(themes[i].name);
1253 free(themes[i].filePath);
1256 free(guiThemesNames);