fix for wrapping artefact when display_mode=ALWAYS
[open-ps2-loader.git] / src / themes.c
blobbe3bc01c6cdc175898d4bc51c048f6bdbcd18f78
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);
207 static void initAttributeText(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
208 char* attribute) {
210 char elemProp[64];
212 snprintf(elemProp, 64, "%s_attribute", name);
213 configGetStr(themeConfig, elemProp, &attribute);
214 if (attribute) {
215 elem->extended = initMutableText(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_TEXT, elem, attribute, NULL, DISPLAY_ALWAYS, SIZING_NONE);
216 elem->endElem = &endMutableText;
217 elem->drawElem = &drawAttributeText;
218 } else
219 LOG("THEMES AttributeText %s: NO attribute, elem disabled !!\n", name);
222 // Common functions for Image ///////////////////////////////////////////////////////////////////////////////////////////////
224 static void findDuplicate(theme_element_t* first, char* cachePattern, char* defaultTexture, char* overlayTexture, mutable_image_t* target) {
225 theme_element_t* elem = first;
226 while (elem) {
227 if ((elem->type == TYPE_STATIC_IMAGE) || (elem->type == TYPE_ATTRIBUTE_IMAGE) || (elem->type == TYPE_GAME_IMAGE) || (elem->type == TYPE_BACKGROUND)) {
228 mutable_image_t* source = (mutable_image_t*) elem->extended;
230 if (cachePattern && source->cache && !strcmp(cachePattern, source->cache->suffix)) {
231 target->cache = source->cache;
232 target->cacheLinked = 1;
233 LOG("THEMES Re-using a cache for pattern %s\n", cachePattern);
236 if (defaultTexture && source->defaultTexture && !strcmp(defaultTexture, source->defaultTexture->name)) {
237 target->defaultTexture = source->defaultTexture;
238 target->defaultTextureLinked = 1;
239 LOG("THEMES Re-using the default texture for %s\n", defaultTexture);
242 if (overlayTexture && source->overlayTexture && !strcmp(overlayTexture, source->overlayTexture->name)) {
243 target->overlayTexture = source->overlayTexture;
244 target->overlayTextureLinked = 1;
245 LOG("THEMES Re-using the overlay texture for %s\n", overlayTexture);
249 elem = elem->next;
253 static void freeImageTexture(image_texture_t* texture) {
254 if (texture) {
255 if (texture->source.Mem)
256 free(texture->source.Mem);
258 free(texture->name);
260 free(texture);
264 static image_texture_t* initImageTexture(char* themePath, config_set_t* themeConfig, char* name, char* imgName, int isOverlay) {
265 image_texture_t* texture = (image_texture_t*) malloc(sizeof(image_texture_t));
266 texPrepare(&texture->source, isOverlay ? GS_PSM_CT32 : GS_PSM_CT24);
267 texture->name = NULL;
269 char path[255];
270 snprintf(path, 255, "%s%s", themePath, imgName);
271 if (texDiscoverLoad(&texture->source, path, -1, isOverlay ? GS_PSM_CT32 : GS_PSM_CT24) >= 0) {
272 int length = strlen(imgName) + 1;
273 texture->name = (char*) malloc(length * sizeof(char));
274 memcpy(texture->name, imgName, length);
276 if (isOverlay) {
277 int intValue;
278 char elemProp[64];
279 snprintf(elemProp, 64, "%s_overlay_ulx", name);
280 if (configGetInt(themeConfig, elemProp, &intValue))
281 texture->upperLeft_x = intValue;
282 snprintf(elemProp, 64, "%s_overlay_uly", name);
283 if (configGetInt(themeConfig, elemProp, &intValue))
284 texture->upperLeft_y = intValue;
285 snprintf(elemProp, 64, "%s_overlay_urx", name);
286 if (configGetInt(themeConfig, elemProp, &intValue))
287 texture->upperRight_x = intValue;
288 snprintf(elemProp, 64, "%s_overlay_ury", name);
289 if (configGetInt(themeConfig, elemProp, &intValue))
290 texture->upperRight_y = intValue;
291 snprintf(elemProp, 64, "%s_overlay_llx", name);
292 if (configGetInt(themeConfig, elemProp, &intValue))
293 texture->lowerLeft_x = intValue;
294 snprintf(elemProp, 64, "%s_overlay_lly", name);
295 if (configGetInt(themeConfig, elemProp, &intValue))
296 texture->lowerLeft_y = intValue;
297 snprintf(elemProp, 64, "%s_overlay_lrx", name);
298 if (configGetInt(themeConfig, elemProp, &intValue))
299 texture->lowerRight_x = intValue;
300 snprintf(elemProp, 64, "%s_overlay_lry", name);
301 if (configGetInt(themeConfig, elemProp, &intValue))
302 texture->lowerRight_y = intValue;
304 } else {
305 freeImageTexture(texture);
306 texture = NULL;
309 return texture;
312 static void endMutableImage(struct theme_element* elem) {
313 mutable_image_t* mutableImage = (mutable_image_t*) elem->extended;
314 if (mutableImage) {
315 if (mutableImage->cache && !mutableImage->cacheLinked)
316 cacheDestroyCache(mutableImage->cache);
318 if (mutableImage->defaultTexture && !mutableImage->defaultTextureLinked)
319 freeImageTexture(mutableImage->defaultTexture);
321 if (mutableImage->overlayTexture && !mutableImage->overlayTextureLinked)
322 freeImageTexture(mutableImage->overlayTexture);
324 free(mutableImage);
327 free(elem);
330 static mutable_image_t* initMutableImage(char* themePath, config_set_t* themeConfig, theme_t* theme, char* name, int type,
331 char* cachePattern, int cacheCount, char* defaultTexture, char* overlayTexture) {
333 mutable_image_t* mutableImage = (mutable_image_t*) malloc(sizeof(mutable_image_t));
334 mutableImage->currentUid = -1;
335 mutableImage->currentItemId = -1;
336 mutableImage->currentValue = NULL;
337 mutableImage->cache = NULL;
338 mutableImage->cacheLinked = 0;
339 mutableImage->defaultTexture = NULL;
340 mutableImage->defaultTextureLinked = 0;
341 mutableImage->overlayTexture = NULL;
342 mutableImage->overlayTextureLinked = 0;
344 char elemProp[64];
346 if (type == TYPE_ATTRIBUTE_IMAGE) {
347 snprintf(elemProp, 64, "%s_attribute", name);
348 configGetStr(themeConfig, elemProp, &cachePattern);
349 LOG("THEMES MutableImage %s: type: %d using cache pattern: %s\n", name, type, cachePattern);
350 } else if ((type == TYPE_GAME_IMAGE) || type == (TYPE_BACKGROUND)) {
351 snprintf(elemProp, 64, "%s_pattern", name);
352 configGetStr(themeConfig, elemProp, &cachePattern);
353 snprintf(elemProp, 64, "%s_count", name);
354 configGetInt(themeConfig, elemProp, &cacheCount);
355 LOG("THEMES MutableImage %s: type: %d using cache pattern: %s\n", name, type, cachePattern);
358 snprintf(elemProp, 64, "%s_default", name);
359 configGetStr(themeConfig, elemProp, &defaultTexture);
361 if (type != TYPE_BACKGROUND) {
362 snprintf(elemProp, 64, "%s_overlay", name);
363 configGetStr(themeConfig, elemProp, &overlayTexture);
366 findDuplicate(theme->mainElems.first, cachePattern, defaultTexture, overlayTexture, mutableImage);
367 findDuplicate(theme->infoElems.first, cachePattern, defaultTexture, overlayTexture, mutableImage);
369 if (cachePattern && !mutableImage->cache) {
370 if (type == TYPE_ATTRIBUTE_IMAGE)
371 mutableImage->cache = cacheInitCache(-1, themePath, 0, cachePattern, 1);
372 else
373 mutableImage->cache = cacheInitCache(theme->gameCacheCount++, "ART", 1, cachePattern, cacheCount);
376 if (defaultTexture && !mutableImage->defaultTexture)
377 mutableImage->defaultTexture = initImageTexture(themePath, themeConfig, name, defaultTexture, 0);
379 if (overlayTexture && !mutableImage->overlayTexture)
380 mutableImage->overlayTexture = initImageTexture(themePath, themeConfig, name, overlayTexture, 1);
382 return mutableImage;
385 // StaticImage //////////////////////////////////////////////////////////////////////////////////////////////////////////////
387 static void drawStaticImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
388 mutable_image_t* staticImage = (mutable_image_t*) elem->extended;
389 if (staticImage->overlayTexture) {
390 rmDrawOverlayPixmap(&staticImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
391 &staticImage->defaultTexture->source, staticImage->overlayTexture->upperLeft_x, staticImage->overlayTexture->upperLeft_y, staticImage->overlayTexture->upperRight_x, staticImage->overlayTexture->upperRight_y,
392 staticImage->overlayTexture->lowerLeft_x, staticImage->overlayTexture->lowerLeft_y, staticImage->overlayTexture->lowerRight_x, staticImage->overlayTexture->lowerRight_y);
393 } else
394 rmDrawPixmap(&staticImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
397 static void initStaticImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
398 char* imageName) {
400 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, NULL, 0, imageName, NULL);
401 elem->extended = mutableImage;
402 elem->endElem = &endMutableImage;
404 if (mutableImage->defaultTexture)
405 elem->drawElem = &drawStaticImage;
406 else
407 LOG("THEMES StaticImage %s: NO image name, elem disabled !!\n", name);
410 // GameImage ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
412 static GSTEXTURE* getGameImageTexture(image_cache_t* cache, void* support, struct submenu_item* item) {
413 if (gEnableArt) {
414 item_list_t * list = (item_list_t *) support;
415 char* startup = list->itemGetStartup(item->id);
416 return cacheGetTexture(cache, list, &item->cache_id[cache->userId], &item->cache_uid[cache->userId], startup);
419 return NULL;
422 static void drawGameImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
423 mutable_image_t* gameImage = (mutable_image_t*) elem->extended;
424 if (item) {
425 GSTEXTURE* texture = getGameImageTexture(gameImage->cache, menu->item->userdata, &item->item);
426 if (!texture || !texture->Mem) {
427 if (gameImage->defaultTexture)
428 texture = &gameImage->defaultTexture->source;
429 else {
430 if (elem->type == TYPE_BACKGROUND)
431 guiDrawBGPlasma();
432 return;
436 if (gameImage->overlayTexture) {
437 rmDrawOverlayPixmap(&gameImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
438 texture, gameImage->overlayTexture->upperLeft_x, gameImage->overlayTexture->upperLeft_y, gameImage->overlayTexture->upperRight_x, gameImage->overlayTexture->upperRight_y,
439 gameImage->overlayTexture->lowerLeft_x, gameImage->overlayTexture->lowerLeft_y, gameImage->overlayTexture->lowerRight_x, gameImage->overlayTexture->lowerRight_y);
440 } else
441 rmDrawPixmap(texture, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
443 } else if (elem->type == TYPE_BACKGROUND) {
444 if (gameImage->defaultTexture)
445 rmDrawPixmap(&gameImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
446 else
447 guiDrawBGPlasma();
451 static void initGameImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
452 char* pattern, int count, char* texture, char* overlay) {
454 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, pattern, count, texture, overlay);
455 elem->extended = mutableImage;
456 elem->endElem = &endMutableImage;
458 if (mutableImage->cache)
459 elem->drawElem = &drawGameImage;
460 else
461 LOG("THEMES GameImage %s: NO pattern, elem disabled !!\n", name);
464 // AttributeImage ///////////////////////////////////////////////////////////////////////////////////////////////////////////
466 static void drawAttributeImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
467 mutable_image_t* attributeImage = (mutable_image_t*) elem->extended;
468 if (config) {
469 if (attributeImage->currentItemId != item->item.id) {
470 // force refresh
471 attributeImage->currentUid = -1;
472 attributeImage->currentItemId = item->item.id;
473 attributeImage->currentValue = NULL;
474 configGetStr(config, attributeImage->cache->suffix, &attributeImage->currentValue);
476 if (attributeImage->currentValue) {
477 int posZ = 0;
478 GSTEXTURE* texture = cacheGetTexture(attributeImage->cache, menu->item->userdata, &posZ, &attributeImage->currentUid, attributeImage->currentValue);
479 if (texture && texture->Mem) {
480 if (attributeImage->overlayTexture) {
481 rmDrawOverlayPixmap(&attributeImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
482 texture, attributeImage->overlayTexture->upperLeft_x, attributeImage->overlayTexture->upperLeft_y, attributeImage->overlayTexture->upperRight_x, attributeImage->overlayTexture->upperRight_y,
483 attributeImage->overlayTexture->lowerLeft_x, attributeImage->overlayTexture->lowerLeft_y, attributeImage->overlayTexture->lowerRight_x, attributeImage->overlayTexture->lowerRight_y);
484 } else
485 rmDrawPixmap(texture, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
487 return;
491 if (attributeImage->defaultTexture)
492 rmDrawPixmap(&attributeImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
495 static void initAttributeImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name) {
496 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, NULL, 1, NULL, NULL);
497 elem->extended = mutableImage;
498 elem->endElem = &endMutableImage;
500 if (mutableImage->cache)
501 elem->drawElem = &drawAttributeImage;
502 else
503 LOG("THEMES AttributeImage %s: NO attribute, elem disabled !!\n", name);
506 // BasicElement /////////////////////////////////////////////////////////////////////////////////////////////////////////////
508 static void endBasic(theme_element_t* elem) {
509 if (elem->extended)
510 free(elem->extended);
512 free(elem);
515 static theme_element_t* initBasic(char* themePath, config_set_t* themeConfig, theme_t* theme,
516 char* name, int type, int x, int y, short aligned, int w, int h, short scaled, u64 color, int font) {
518 int intValue;
519 unsigned char charColor[3];
520 char* temp;
521 char elemProp[64];
523 theme_element_t* elem = (theme_element_t*) malloc(sizeof(theme_element_t));
525 elem->type = type;
526 elem->extended = NULL;
527 elem->drawElem = NULL;
528 elem->endElem = &endBasic;
529 elem->next = NULL;
531 snprintf(elemProp, 64, "%s_x", name);
532 if (configGetStr(themeConfig, elemProp, &temp)) {
533 if (!strncmp(temp, "POS_MID", 7))
534 x = screenWidth >> 1;
535 else
536 x = atoi(temp);
538 if (x < 0)
539 elem->posX = screenWidth + x;
540 else
541 elem->posX = x;
543 snprintf(elemProp, 64, "%s_y", name);
544 if (configGetStr(themeConfig, elemProp, &temp)) {
545 if (!strncmp(temp, "POS_MID", 7))
546 y = screenHeight >> 1;
547 else
548 y = atoi(temp);
550 if (y < 0)
551 elem->posY = ceil((screenHeight + y) * theme->usedHeight / screenHeight);
552 else
553 elem->posY = y;
555 snprintf(elemProp, 64, "%s_width", name);
556 if (configGetStr(themeConfig, elemProp, &temp)) {
557 if (!strncmp(temp, "DIM_INF", 7))
558 elem->width = screenWidth;
559 else
560 elem->width = atoi(temp);
561 } else
562 elem->width = w;
564 snprintf(elemProp, 64, "%s_height", name);
565 if (configGetStr(themeConfig, elemProp, &temp)) {
566 if (!strncmp(temp, "DIM_INF", 7))
567 elem->height = screenHeight;
568 else
569 elem->height = atoi(temp);
570 } else
571 elem->height = h;
573 snprintf(elemProp, 64, "%s_aligned", name);
574 if (configGetInt(themeConfig, elemProp, &intValue))
575 elem->aligned = intValue;
576 else
577 elem->aligned = aligned;
579 snprintf(elemProp, 64, "%s_scaled", name);
580 if (configGetInt(themeConfig, elemProp, &intValue))
581 elem->scaled = intValue;
582 else
583 elem->scaled = scaled;
585 snprintf(elemProp, 64, "%s_color", name);
586 if (configGetColor(themeConfig, elemProp, charColor))
587 elem->color = GS_SETREG_RGBA(charColor[0], charColor[1], charColor[2], 0xff);
588 else
589 elem->color = color;
591 snprintf(elemProp, 64, "%s_font", name);
592 if (configGetInt(themeConfig, elemProp, &intValue))
593 font = intValue;
594 if (font >= 0 && font < THM_MAX_FONTS)
595 elem->font = theme->fonts[font];
596 else
597 elem->font = FNT_DEFAULT;
599 return elem;
602 // Internal elements ////////////////////////////////////////////////////////////////////////////////////////////////////////
604 static void drawBackground(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
605 guiDrawBGPlasma();
608 static void initBackground(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
609 char* pattern, int count, char* texture) {
611 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, pattern, count, texture, NULL);
612 elem->extended = mutableImage;
613 elem->endElem = &endMutableImage;
615 if (mutableImage->cache)
616 elem->drawElem = &drawGameImage;
617 else if (mutableImage->defaultTexture)
618 elem->drawElem = &drawStaticImage;
619 else
620 elem->drawElem = &drawBackground;
623 static void drawMenuIcon(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
624 GSTEXTURE* menuIconTex = thmGetTexture(menu->item->icon_id);
625 if (menuIconTex && menuIconTex->Mem)
626 rmDrawPixmap(menuIconTex, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
629 static void drawMenuText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
630 GSTEXTURE* leftIconTex = NULL, *rightIconTex = NULL;
631 if (menu->prev)
632 leftIconTex = thmGetTexture(LEFT_ICON);
633 if (menu->next)
634 rightIconTex = thmGetTexture(RIGHT_ICON);
636 if (elem->aligned) {
637 int offset = elem->width >> 1;
638 if (leftIconTex && leftIconTex->Mem)
639 rmDrawPixmap(leftIconTex, elem->posX - offset, elem->posY, elem->aligned, leftIconTex->Width, leftIconTex->Height, elem->scaled, gDefaultCol);
640 if (rightIconTex && rightIconTex->Mem)
641 rmDrawPixmap(rightIconTex, elem->posX + offset, elem->posY, elem->aligned, rightIconTex->Width, rightIconTex->Height, elem->scaled, gDefaultCol);
643 else {
644 if (leftIconTex && leftIconTex->Mem)
645 rmDrawPixmap(leftIconTex, elem->posX - leftIconTex->Width, elem->posY, elem->aligned, leftIconTex->Width, leftIconTex->Height, elem->scaled, gDefaultCol);
646 if (rightIconTex && rightIconTex->Mem)
647 rmDrawPixmap(rightIconTex, elem->posX + elem->width, elem->posY, elem->aligned, rightIconTex->Width, rightIconTex->Height, elem->scaled, gDefaultCol);
649 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, menuItemGetText(menu->item), elem->color);
652 static void drawItemsList(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
653 if (item) {
654 items_list_t* itemsList = (items_list_t*) elem->extended;
656 int posX = elem->posX, posY = elem->posY;
657 if (elem->aligned) {
658 posX -= elem->width >> 1;
659 posY -= elem->height >> 1;
662 submenu_list_t *ps = menu->item->pagestart;
663 int others = 0;
664 u64 color;
665 while (ps && (others++ < itemsList->displayedItems)) {
666 if (ps == item)
667 color = gTheme->selTextColor;
668 else
669 color = elem->color;
671 if (itemsList->decoratorImage) {
672 GSTEXTURE* itemIconTex = getGameImageTexture(itemsList->decoratorImage->cache, menu->item->userdata, &ps->item);
673 if (itemIconTex && itemIconTex->Mem)
674 rmDrawPixmap(itemIconTex, posX, posY, ALIGN_NONE, DECORATOR_SIZE, DECORATOR_SIZE, elem->scaled, gDefaultCol);
675 else {
676 if (itemsList->decoratorImage->defaultTexture)
677 rmDrawPixmap(&itemsList->decoratorImage->defaultTexture->source, posX, posY, ALIGN_NONE, DECORATOR_SIZE, DECORATOR_SIZE, elem->scaled, gDefaultCol);
679 fntRenderString(elem->font, posX + DECORATOR_SIZE, posY, ALIGN_NONE, elem->width, elem->height, submenuItemGetText(&ps->item), color);
680 } else
681 fntRenderString(elem->font, posX, posY, ALIGN_NONE, elem->width, elem->height, submenuItemGetText(&ps->item), color);
683 posY += MENU_ITEM_HEIGHT;
684 ps = ps->next;
689 static void initItemsList(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name, char* decorator) {
690 char elemProp[64];
692 items_list_t* itemsList = (items_list_t*) malloc(sizeof(items_list_t));
694 if (elem->width == DIM_UNDEF)
695 elem->width = screenWidth;
697 if (elem->height == DIM_UNDEF)
698 elem->height = theme->usedHeight - (MENU_POS_V + HINT_HEIGHT);
700 itemsList->displayedItems = elem->height / MENU_ITEM_HEIGHT;
701 LOG("THEMES ItemsList %s: displaying %d elems, item height: %d\n", name, itemsList->displayedItems, elem->height);
703 itemsList->decorator = NULL;
704 snprintf(elemProp, 64, "%s_decorator", name);
705 configGetStr(themeConfig, elemProp, &decorator);
706 if (decorator)
707 itemsList->decorator = decorator; // Will be used later (thmValidate)
709 itemsList->decoratorImage = NULL;
711 elem->extended = itemsList;
712 // elem->endElem = &endBasic; does the job
714 elem->drawElem = &drawItemsList;
717 static void drawItemText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
718 if (item) {
719 item_list_t *support = menu->item->userdata;
720 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, support->itemGetStartup(item->item.id), elem->color);
724 static void drawHintText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
725 menu_hint_item_t* hint = menu->item->hints;
726 if (hint) {
727 int x = elem->posX;
729 for (; hint; hint = hint->next) {
730 x = guiDrawIconAndText(hint->icon_id, hint->text_id, elem->font, x, elem->posY, elem->color);
731 x += elem->width;
736 static void drawInfoHintText(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
737 int x = elem->posX;
738 x = guiDrawIconAndText(CROSS_ICON, _STR_RUN, elem->font, x, elem->posY, elem->color);
739 x += elem->width;
740 x = guiDrawIconAndText(CIRCLE_ICON, _STR_O_BACK, elem->font, x, elem->posY, elem->color);
743 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
745 static void validateGUIElems(char* themePath, config_set_t* themeConfig, theme_t* theme) {
746 // 1. check we have a valid Background elements
747 if ( !theme->mainElems.first || (theme->mainElems.first->type != TYPE_BACKGROUND) ) {
748 LOG("THEMES No valid background found for main, add default BG_ART\n");
749 theme_element_t* backgroundElem = initBasic(themePath, themeConfig, theme, "bg", TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
750 if (themePath)
751 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, "background");
752 else
753 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, NULL);
754 backgroundElem->next = theme->mainElems.first;
755 theme->mainElems.first = backgroundElem;
758 if (theme->infoElems.first) {
759 if (theme->infoElems.first->type != TYPE_BACKGROUND) {
760 LOG("THEMES No valid background found for info, add default BG_ART\n");
761 theme_element_t* backgroundElem = initBasic(themePath, themeConfig, theme, "bg", TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
762 if (themePath)
763 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, "background");
764 else
765 initBackground(themePath, themeConfig, theme, backgroundElem, "bg", "BG", 1, NULL);
766 backgroundElem->next = theme->infoElems.first;
767 theme->infoElems.first = backgroundElem;
771 // 2. check we have a valid ItemsList element, and link its decorator to the target element
772 if (theme->itemsList) {
773 items_list_t* itemsList = (items_list_t*) theme->itemsList->extended;
774 if (itemsList->decorator) {
775 // Second pass to find the decorator
776 theme_element_t* decoratorElem = theme->mainElems.first;
777 while (decoratorElem) {
778 if (decoratorElem->type == TYPE_GAME_IMAGE) {
779 mutable_image_t* gameImage = (mutable_image_t*) decoratorElem->extended;
780 if (!strcmp(itemsList->decorator, gameImage->cache->suffix)) {
781 // if user want to cache less than displayed items, then disable itemslist icons, if not would load constantly
782 if (gameImage->cache->count >= itemsList->displayedItems)
783 itemsList->decoratorImage = gameImage;
784 break;
788 decoratorElem = decoratorElem->next;
790 itemsList->decorator = NULL;
792 } else {
793 LOG("THEMES No itemsList found, adding a default one\n");
794 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);
795 initItemsList(themePath, themeConfig, theme, theme->itemsList, "il", NULL);
796 theme->itemsList->next = theme->mainElems.first->next; // Position the itemsList as second element (right after the Background)
797 theme->mainElems.first->next = theme->itemsList;
801 static int addGUIElem(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_elems_t* elems, char* type, char* name) {
803 int enabled = 1;
804 char elemProp[64];
805 theme_element_t* elem = NULL;
807 snprintf(elemProp, 64, "%s_enabled", name);
808 configGetInt(themeConfig, elemProp, &enabled);
810 if (enabled) {
811 snprintf(elemProp, 64, "%s_type", name);
812 configGetStr(themeConfig, elemProp, &type);
813 if (type) {
814 if (!strcmp(elementsType[TYPE_ATTRIBUTE_TEXT], type)) {
815 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_TEXT, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
816 initAttributeText(themePath, themeConfig, theme, elem, name, NULL);
817 } else if (!strcmp(elementsType[TYPE_STATIC_TEXT], type)) {
818 elem = initBasic(themePath, themeConfig, theme, name, TYPE_STATIC_TEXT, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
819 initStaticText(themePath, themeConfig, theme, elem, name, NULL);
820 } else if (!strcmp(elementsType[TYPE_ATTRIBUTE_IMAGE], type)) {
821 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
822 initAttributeImage(themePath, themeConfig, theme, elem, name);
823 } else if (!strcmp(elementsType[TYPE_GAME_IMAGE], type)) {
824 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
825 initGameImage(themePath, themeConfig, theme, elem, name, NULL, 1, NULL, NULL);
826 } else if (!strcmp(elementsType[TYPE_STATIC_IMAGE], type)) {
827 elem = initBasic(themePath, themeConfig, theme, name, TYPE_STATIC_IMAGE, 0, 0, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
828 initStaticImage(themePath, themeConfig, theme, elem, name, NULL);
829 } else if (!strcmp(elementsType[TYPE_BACKGROUND], type)) {
830 if (!elems->first) { // Background elem can only be the first one
831 elem = initBasic(themePath, themeConfig, theme, name, TYPE_BACKGROUND, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol, FNT_DEFAULT);
832 initBackground(themePath, themeConfig, theme, elem, name, NULL, 1, NULL);
834 } else if (!strcmp(elementsType[TYPE_MENU_ICON], type)) {
835 elem = initBasic(themePath, themeConfig, theme, name, TYPE_MENU_ICON, 40, 40, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
836 elem->drawElem = &drawMenuIcon;
837 } else if (!strcmp(elementsType[TYPE_MENU_TEXT], type)) {
838 elem = initBasic(themePath, themeConfig, theme, name, TYPE_MENU_TEXT, screenWidth >> 1, 20, ALIGN_CENTER, 200, 20, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
839 elem->drawElem = &drawMenuText;
840 } else if (!strcmp(elementsType[TYPE_ITEMS_LIST], type)) {
841 if (!theme->itemsList) {
842 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);
843 initItemsList(themePath, themeConfig, theme, elem, name, NULL);
844 theme->itemsList = elem;
846 } else if (!strcmp(elementsType[TYPE_ITEM_ICON], type)) {
847 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 80, theme->usedHeight >> 1, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
848 initGameImage(themePath, themeConfig, theme, elem, name, "ICO", 20, NULL, NULL);
849 } else if (!strcmp(elementsType[TYPE_ITEM_COVER], type)) {
850 elem = initBasic(themePath, themeConfig, theme, name, TYPE_GAME_IMAGE, 520, theme->usedHeight >> 1, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
851 initGameImage(themePath, themeConfig, theme, elem, name, "COV", 10, NULL, NULL);
852 } else if (!strcmp(elementsType[TYPE_ITEM_TEXT], type)) {
853 elem = initBasic(themePath, themeConfig, theme, name, TYPE_ITEM_TEXT, 520, 370, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
854 elem->drawElem = &drawItemText;
855 } else if (!strcmp(elementsType[TYPE_HINT_TEXT], type)) {
856 elem = initBasic(themePath, themeConfig, theme, name, TYPE_HINT_TEXT, 16, -HINT_HEIGHT, ALIGN_NONE, 12, 20, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
857 elem->drawElem = &drawHintText;
858 } else if (!strcmp(elementsType[TYPE_INFO_HINT_TEXT], type)) {
859 elem = initBasic(themePath, themeConfig, theme, name, TYPE_INFO_HINT_TEXT, 16, -HINT_HEIGHT, ALIGN_NONE, 12, 20, SCALING_RATIO, theme->textColor, FNT_DEFAULT);
860 elem->drawElem = &drawInfoHintText;
861 } else if (!strcmp(elementsType[TYPE_LOADING_ICON], type)) {
862 if (!theme->loadingIcon)
863 theme->loadingIcon = initBasic(themePath, themeConfig, theme, name, TYPE_LOADING_ICON, -50, -50, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, FNT_DEFAULT);
866 if (elem) {
867 if (!elems->first)
868 elems->first = elem;
870 if (!elems->last)
871 elems->last = elem;
872 else {
873 elems->last->next = elem;
874 elems->last = elem;
877 } else
878 return 0; // ends the reading of elements
881 return 1;
884 static void freeGUIElems(theme_elems_t* elems) {
885 theme_element_t* elem = elems->first;
886 while (elem) {
887 elems->first = elem->next;
888 elem->endElem(elem);
889 elem = elems->first;
893 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
894 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
896 GSTEXTURE* thmGetTexture(unsigned int id) {
897 if (id >= TEXTURES_COUNT)
898 return NULL;
899 else {
900 // see if the texture is valid
901 GSTEXTURE* txt = &gTheme->textures[id];
903 if (txt->Mem)
904 return txt;
905 else
906 return NULL;
910 static void thmFree(theme_t* theme) {
911 if (theme) {
912 // free elements
913 freeGUIElems(&theme->mainElems);
914 freeGUIElems(&theme->infoElems);
916 // free textures
917 GSTEXTURE* texture;
918 int id = 0;
919 for(; id < TEXTURES_COUNT; id++) {
920 texture = &theme->textures[id];
921 if (texture->Mem != NULL) {
922 free(texture->Mem);
923 texture->Mem = NULL;
927 // free fonts
928 for (id = 0; id < THM_MAX_FONTS; ++id) {
929 int fntid = theme->fonts[id];
931 if (fntid != FNT_DEFAULT)
932 fntRelease(fntid);
935 free(theme);
936 theme = NULL;
940 static int thmReadEntry(int index, char* path, char* separator, char* name, unsigned int mode) {
941 if (FIO_SO_ISDIR(mode) && strstr(name, "thm_")) {
942 theme_file_t* currTheme = &themes[nThemes + index];
944 int length = strlen(name) - 4 + 1;
945 currTheme->name = (char*) malloc(length * sizeof(char));
946 memcpy(currTheme->name, name + 4, length);
947 currTheme->name[length - 1] = '\0';
949 length = strlen(path) + 1 + strlen(name) + 1 + 1;
950 currTheme->filePath = (char*) malloc(length * sizeof(char));
951 sprintf(currTheme->filePath, "%s%s%s%s", path, separator, name, separator);
953 LOG("THEMES Theme found: %s\n", currTheme->filePath);
955 index++;
957 return index;
960 /* themePath must contains the leading separator (as it is dependent of the device, we can't know here) */
961 static int thmLoadResource(int texId, char* themePath, short psm, int useDefault) {
962 int success = -1;
963 GSTEXTURE* texture = &gTheme->textures[texId];
965 if (themePath != NULL)
966 success = texDiscoverLoad(texture, themePath, texId, psm); // only set success here
968 if ((success < 0) && useDefault)
969 texPngLoad(texture, NULL, texId, psm); // we don't mind the result of "default"
971 return success;
974 static void thmSetColors(theme_t* theme) {
975 memcpy(theme->bgColor, gDefaultBgColor, 3);
976 theme->textColor = GS_SETREG_RGBA(gDefaultTextColor[0], gDefaultTextColor[1], gDefaultTextColor[2], 0xff);
977 theme->uiTextColor = GS_SETREG_RGBA(gDefaultUITextColor[0], gDefaultUITextColor[1], gDefaultUITextColor[2], 0xff);
978 theme->selTextColor = GS_SETREG_RGBA(gDefaultSelTextColor[0], gDefaultSelTextColor[1], gDefaultSelTextColor[2], 0xff);
980 theme_element_t* elem = theme->mainElems.first;
981 while (elem) {
982 elem->color = theme->textColor;
983 elem = elem->next;
987 static void thmLoadFonts(config_set_t* themeConfig, const char* themePath, theme_t* theme) {
988 int fntID; // theme side font id, not the fntSys handle
989 for (fntID = -1; fntID < THM_MAX_FONTS; ++fntID) {
990 // does the font by the key exist?
991 char fntKey[16];
993 // -1 is a placeholder for default font...
994 if (fntID >= 0) {
995 // Default font handle...
996 theme->fonts[fntID] = FNT_DEFAULT;
997 snprintf(fntKey, 16, "font%d", fntID);
998 } else {
999 snprintf(fntKey, 16, "default_font");
1002 char *fntFile;
1003 int cfgKeyOK = configGetStr(themeConfig, fntKey, &fntFile);
1004 if (!cfgKeyOK && (fntID >= 0))
1005 continue;
1007 char fullPath[128];
1009 if (fntID < 0) {
1010 // replace the default font
1011 if (cfgKeyOK) {
1012 snprintf(fullPath, 128, "%s%s", themePath, fntFile);
1014 int size = -1;
1015 void* customFont = readFile(fullPath, -1, &size);
1017 if (customFont)
1018 fntReplace(FNT_DEFAULT, customFont, size, 1, 0);
1019 } else
1020 fntSetDefault(FNT_DEFAULT);
1021 } else {
1022 snprintf(fullPath, 128, "%s%s", themePath, fntFile);
1023 int fntHandle = fntLoadFile(fullPath);
1025 // Do we have a valid font? Assign the font handle to the theme font slot
1026 if (fntHandle != FNT_ERROR)
1027 theme->fonts[fntID] = fntHandle;
1032 static void thmLoad(char* themePath) {
1033 LOG("THEMES Load theme path=%s\n", themePath);
1034 theme_t* curT = gTheme;
1035 theme_t* newT = (theme_t*) malloc(sizeof(theme_t));
1036 memset(newT, 0, sizeof(theme_t));
1038 newT->useDefault = 1;
1039 newT->usedHeight = 480;
1040 thmSetColors(newT);
1041 newT->mainElems.first = NULL;
1042 newT->mainElems.last = NULL;
1043 newT->infoElems.first = NULL;
1044 newT->infoElems.last = NULL;
1045 newT->gameCacheCount = 0;
1046 newT->itemsList = NULL;
1047 newT->loadingIcon = NULL;
1048 newT->loadingIconCount = LOAD7_ICON - LOAD0_ICON + 1;
1050 config_set_t* themeConfig = NULL;
1051 if (!themePath) {
1052 themeConfig = configAlloc(0, NULL, NULL);
1053 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_MENU_ICON], "_");
1054 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_MENU_TEXT], "_");
1055 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEMS_LIST], "_");
1056 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_ICON], "_");
1057 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_COVER], "_");
1058 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_TEXT], "_");
1059 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_HINT_TEXT], "_");
1060 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_LOADING_ICON], "_");
1062 // reset the default font to be sure
1063 fntSetDefault(FNT_DEFAULT);
1064 } else {
1065 char path[255];
1066 snprintf(path, 255, "%sconf_theme.cfg", themePath);
1067 themeConfig = configAlloc(0, NULL, path);
1068 configRead(themeConfig); // try to load the theme config file
1070 int intValue;
1071 if (configGetInt(themeConfig, "use_default", &intValue))
1072 newT->useDefault = intValue;
1074 if (configGetInt(themeConfig, "use_real_height", &intValue)) {
1075 if (intValue)
1076 newT->usedHeight = screenHeight;
1079 configGetColor(themeConfig, "bg_color", newT->bgColor);
1081 unsigned char color[3];
1082 if (configGetColor(themeConfig, "text_color", color))
1083 newT->textColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1085 if (configGetColor(themeConfig, "ui_text_color", color))
1086 newT->uiTextColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1088 if (configGetColor(themeConfig, "sel_text_color", color))
1089 newT->selTextColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1091 // before loading the element definitions, we have to have the fonts prepared
1092 // for that, we load the fonts and a translation table
1093 thmLoadFonts(themeConfig, themePath, newT);
1095 int i = 1;
1096 snprintf(path, 255, "main0");
1097 while (addGUIElem(themePath, themeConfig, newT, &newT->mainElems, NULL, path))
1098 snprintf(path, 255, "main%d", i++);
1100 i = 1;
1101 snprintf(path, 255, "info0");
1102 while(addGUIElem(themePath, themeConfig, newT, &newT->infoElems, NULL, path))
1103 snprintf(path, 255, "info%d", i++);
1106 validateGUIElems(themePath, themeConfig, newT);
1107 configFree(themeConfig);
1109 LOG("THEMES Number of cache: %d\n", newT->gameCacheCount);
1110 LOG("THEMES Used height: %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 <= START_ICON; i++)
1147 thmLoadResource(i, themePath, GS_PSM_CT32, gTheme->useDefault);
1149 // Not customizable icons
1150 for (i = L1_ICON; i <= R2_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 nThemes += listDir(path, separator, THM_MAX_FILES - nThemes, &thmReadEntry);
1174 thmRebuildGuiNames();
1176 char* temp;
1177 if (configGetStr(configGetByType(CONFIG_OPL), "theme", &temp)) {
1178 LOG("THEMES Trying to set again theme: %s\n", temp);
1179 if (thmSetGuiValue(thmFindGuiID(temp), 0))
1180 moduleUpdateMenu(mode, 1);
1184 void thmInit() {
1185 LOG("THEMES Init\n");
1186 gTheme = NULL;
1188 thmReloadScreenExtents();
1190 // initialize default internal
1191 thmLoad(NULL);
1193 thmAddElements(gBaseMCDir, "/", -1);
1196 void thmReinit(char* path) {
1197 thmLoad(NULL);
1198 guiThemeID = 0;
1200 int i = 0;
1201 while (i < nThemes) {
1202 if (strncmp(themes[i].filePath, path, strlen(path)) == 0) {
1203 LOG("THEMES Remove theme: %s\n", themes[i].filePath);
1204 nThemes--;
1205 free(themes[i].name);
1206 themes[i].name = themes[nThemes].name;
1207 themes[nThemes].name = NULL;
1208 free(themes[i].filePath);
1209 themes[i].filePath = themes[nThemes].filePath;
1210 themes[nThemes].filePath = NULL;
1211 } else
1212 i++;
1215 thmRebuildGuiNames();
1218 void thmReloadScreenExtents() {
1219 rmGetScreenExtents(&screenWidth, &screenHeight);
1222 char* thmGetValue() {
1223 return guiThemesNames[guiThemeID];
1226 int thmSetGuiValue(int themeID, int reload) {
1227 if (themeID != -1) {
1228 if (guiThemeID != themeID || reload) {
1229 if (themeID != 0)
1230 thmLoad(themes[themeID - 1].filePath);
1231 else
1232 thmLoad(NULL);
1234 guiThemeID = themeID;
1235 configSetStr(configGetByType(CONFIG_OPL), "theme", thmGetValue());
1236 return 1;
1238 else if (guiThemeID == 0)
1239 thmSetColors(gTheme);
1241 return 0;
1244 int thmGetGuiValue() {
1245 return guiThemeID;
1248 int thmFindGuiID(char* theme) {
1249 if (theme) {
1250 int i = 0;
1251 for (; i < nThemes; i++) {
1252 if (stricmp(themes[i].name, theme) == 0)
1253 return i + 1;
1256 return 0;
1259 char **thmGetGuiList() {
1260 return guiThemesNames;
1263 void thmEnd() {
1264 thmFree(gTheme);
1266 int i = 0;
1267 for (; i < nThemes; i++) {
1268 free(themes[i].name);
1269 free(themes[i].filePath);
1272 free(guiThemesNames);