mgh: fix for default HDD DMA mode, that wasn't correctly set
[open-ps2-loader.git] / src / themes.c
blob6707f3d1ea59fd0d201fc880bf3e0d410944a8f5
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->currentConfigId = 0;
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->currentConfigId != config->uid) {
175 // force refresh
176 mutableText->currentConfigId = config->uid;
177 mutableText->currentValue = NULL;
178 if (configGetStr(config, mutableText->value, &mutableText->currentValue)) {
179 if (mutableText->sizingMode == SIZING_WRAP)
180 fntFitString(elem->font, mutableText->currentValue, elem->width);
183 if (mutableText->currentValue) {
184 if (mutableText->displayMode == DISPLAY_NEVER) {
185 if (mutableText->sizingMode == SIZING_NONE)
186 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, mutableText->currentValue, elem->color);
187 else
188 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, mutableText->currentValue, elem->color);
189 } else {
190 char result[300];
191 snprintf(result, 300, "%s%s", mutableText->alias, mutableText->currentValue);
192 if (mutableText->sizingMode == SIZING_NONE)
193 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, result, elem->color);
194 else
195 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, result, elem->color);
197 return;
200 if (mutableText->displayMode == DISPLAY_ALWAYS) {
201 if (mutableText->sizingMode == SIZING_NONE)
202 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, 0, 0, mutableText->alias, elem->color);
203 else
204 fntRenderString(elem->font, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, mutableText->alias, elem->color);
208 static void initAttributeText(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
209 char* attribute) {
211 char elemProp[64];
213 snprintf(elemProp, 64, "%s_attribute", name);
214 configGetStr(themeConfig, elemProp, &attribute);
215 if (attribute) {
216 elem->extended = initMutableText(themePath, themeConfig, theme, name, TYPE_ATTRIBUTE_TEXT, elem, attribute, NULL, DISPLAY_ALWAYS, SIZING_NONE);
217 elem->endElem = &endMutableText;
218 elem->drawElem = &drawAttributeText;
219 } else
220 LOG("THEMES AttributeText %s: NO attribute, elem disabled !!\n", name);
223 // Common functions for Image ///////////////////////////////////////////////////////////////////////////////////////////////
225 static void findDuplicate(theme_element_t* first, char* cachePattern, char* defaultTexture, char* overlayTexture, mutable_image_t* target) {
226 theme_element_t* elem = first;
227 while (elem) {
228 if ((elem->type == TYPE_STATIC_IMAGE) || (elem->type == TYPE_ATTRIBUTE_IMAGE) || (elem->type == TYPE_GAME_IMAGE) || (elem->type == TYPE_BACKGROUND)) {
229 mutable_image_t* source = (mutable_image_t*) elem->extended;
231 if (cachePattern && source->cache && !strcmp(cachePattern, source->cache->suffix)) {
232 target->cache = source->cache;
233 target->cacheLinked = 1;
234 LOG("THEMES Re-using a cache for pattern %s\n", cachePattern);
237 if (defaultTexture && source->defaultTexture && !strcmp(defaultTexture, source->defaultTexture->name)) {
238 target->defaultTexture = source->defaultTexture;
239 target->defaultTextureLinked = 1;
240 LOG("THEMES Re-using the default texture for %s\n", defaultTexture);
243 if (overlayTexture && source->overlayTexture && !strcmp(overlayTexture, source->overlayTexture->name)) {
244 target->overlayTexture = source->overlayTexture;
245 target->overlayTextureLinked = 1;
246 LOG("THEMES Re-using the overlay texture for %s\n", overlayTexture);
250 elem = elem->next;
254 static void freeImageTexture(image_texture_t* texture) {
255 if (texture) {
256 if (texture->source.Mem)
257 free(texture->source.Mem);
259 free(texture->name);
261 free(texture);
265 static image_texture_t* initImageTexture(char* themePath, config_set_t* themeConfig, char* name, char* imgName, int isOverlay) {
266 image_texture_t* texture = (image_texture_t*) malloc(sizeof(image_texture_t));
267 texPrepare(&texture->source, isOverlay ? GS_PSM_CT32 : GS_PSM_CT24);
268 texture->name = NULL;
270 char path[255];
271 snprintf(path, 255, "%s%s", themePath, imgName);
272 if (texDiscoverLoad(&texture->source, path, -1, isOverlay ? GS_PSM_CT32 : GS_PSM_CT24) >= 0) {
273 int length = strlen(imgName) + 1;
274 texture->name = (char*) malloc(length * sizeof(char));
275 memcpy(texture->name, imgName, length);
277 if (isOverlay) {
278 int intValue;
279 char elemProp[64];
280 snprintf(elemProp, 64, "%s_overlay_ulx", name);
281 if (configGetInt(themeConfig, elemProp, &intValue))
282 texture->upperLeft_x = intValue;
283 snprintf(elemProp, 64, "%s_overlay_uly", name);
284 if (configGetInt(themeConfig, elemProp, &intValue))
285 texture->upperLeft_y = intValue;
286 snprintf(elemProp, 64, "%s_overlay_urx", name);
287 if (configGetInt(themeConfig, elemProp, &intValue))
288 texture->upperRight_x = intValue;
289 snprintf(elemProp, 64, "%s_overlay_ury", name);
290 if (configGetInt(themeConfig, elemProp, &intValue))
291 texture->upperRight_y = intValue;
292 snprintf(elemProp, 64, "%s_overlay_llx", name);
293 if (configGetInt(themeConfig, elemProp, &intValue))
294 texture->lowerLeft_x = intValue;
295 snprintf(elemProp, 64, "%s_overlay_lly", name);
296 if (configGetInt(themeConfig, elemProp, &intValue))
297 texture->lowerLeft_y = intValue;
298 snprintf(elemProp, 64, "%s_overlay_lrx", name);
299 if (configGetInt(themeConfig, elemProp, &intValue))
300 texture->lowerRight_x = intValue;
301 snprintf(elemProp, 64, "%s_overlay_lry", name);
302 if (configGetInt(themeConfig, elemProp, &intValue))
303 texture->lowerRight_y = intValue;
305 } else {
306 freeImageTexture(texture);
307 texture = NULL;
310 return texture;
313 static void endMutableImage(struct theme_element* elem) {
314 mutable_image_t* mutableImage = (mutable_image_t*) elem->extended;
315 if (mutableImage) {
316 if (mutableImage->cache && !mutableImage->cacheLinked)
317 cacheDestroyCache(mutableImage->cache);
319 if (mutableImage->defaultTexture && !mutableImage->defaultTextureLinked)
320 freeImageTexture(mutableImage->defaultTexture);
322 if (mutableImage->overlayTexture && !mutableImage->overlayTextureLinked)
323 freeImageTexture(mutableImage->overlayTexture);
325 free(mutableImage);
328 free(elem);
331 static mutable_image_t* initMutableImage(char* themePath, config_set_t* themeConfig, theme_t* theme, char* name, int type,
332 char* cachePattern, int cacheCount, char* defaultTexture, char* overlayTexture) {
334 mutable_image_t* mutableImage = (mutable_image_t*) malloc(sizeof(mutable_image_t));
335 mutableImage->currentUid = -1;
336 mutableImage->currentConfigId = 0;
337 mutableImage->currentValue = NULL;
338 mutableImage->cache = NULL;
339 mutableImage->cacheLinked = 0;
340 mutableImage->defaultTexture = NULL;
341 mutableImage->defaultTextureLinked = 0;
342 mutableImage->overlayTexture = NULL;
343 mutableImage->overlayTextureLinked = 0;
345 char elemProp[64];
347 if (type == TYPE_ATTRIBUTE_IMAGE) {
348 snprintf(elemProp, 64, "%s_attribute", name);
349 configGetStr(themeConfig, elemProp, &cachePattern);
350 LOG("THEMES MutableImage %s: type: %s using cache pattern: %s\n", name, elementsType[type], cachePattern);
351 } else if ((type == TYPE_GAME_IMAGE) || type == (TYPE_BACKGROUND)) {
352 snprintf(elemProp, 64, "%s_pattern", name);
353 configGetStr(themeConfig, elemProp, &cachePattern);
354 snprintf(elemProp, 64, "%s_count", name);
355 configGetInt(themeConfig, elemProp, &cacheCount);
356 LOG("THEMES MutableImage %s: type: %s using cache pattern: %s count: %d\n", name, elementsType[type], cachePattern, cacheCount);
359 snprintf(elemProp, 64, "%s_default", name);
360 configGetStr(themeConfig, elemProp, &defaultTexture);
362 if (type != TYPE_BACKGROUND) {
363 snprintf(elemProp, 64, "%s_overlay", name);
364 configGetStr(themeConfig, elemProp, &overlayTexture);
367 findDuplicate(theme->mainElems.first, cachePattern, defaultTexture, overlayTexture, mutableImage);
368 findDuplicate(theme->infoElems.first, cachePattern, defaultTexture, overlayTexture, mutableImage);
370 if (cachePattern && !mutableImage->cache) {
371 if (type == TYPE_ATTRIBUTE_IMAGE)
372 mutableImage->cache = cacheInitCache(-1, themePath, 0, cachePattern, 1);
373 else
374 mutableImage->cache = cacheInitCache(theme->gameCacheCount++, "ART", 1, cachePattern, cacheCount);
377 if (defaultTexture && !mutableImage->defaultTexture)
378 mutableImage->defaultTexture = initImageTexture(themePath, themeConfig, name, defaultTexture, 0);
380 if (overlayTexture && !mutableImage->overlayTexture)
381 mutableImage->overlayTexture = initImageTexture(themePath, themeConfig, name, overlayTexture, 1);
383 return mutableImage;
386 // StaticImage //////////////////////////////////////////////////////////////////////////////////////////////////////////////
388 static void drawStaticImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
389 mutable_image_t* staticImage = (mutable_image_t*) elem->extended;
390 if (staticImage->overlayTexture) {
391 rmDrawOverlayPixmap(&staticImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
392 &staticImage->defaultTexture->source, staticImage->overlayTexture->upperLeft_x, staticImage->overlayTexture->upperLeft_y, staticImage->overlayTexture->upperRight_x, staticImage->overlayTexture->upperRight_y,
393 staticImage->overlayTexture->lowerLeft_x, staticImage->overlayTexture->lowerLeft_y, staticImage->overlayTexture->lowerRight_x, staticImage->overlayTexture->lowerRight_y);
394 } else
395 rmDrawPixmap(&staticImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
398 static void initStaticImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
399 char* imageName) {
401 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, NULL, 0, imageName, NULL);
402 elem->extended = mutableImage;
403 elem->endElem = &endMutableImage;
405 if (mutableImage->defaultTexture)
406 elem->drawElem = &drawStaticImage;
407 else
408 LOG("THEMES StaticImage %s: NO image name, elem disabled !!\n", name);
411 // GameImage ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
413 static GSTEXTURE* getGameImageTexture(image_cache_t* cache, void* support, struct submenu_item* item) {
414 if (gEnableArt) {
415 item_list_t * list = (item_list_t *) support;
416 char* startup = list->itemGetStartup(item->id);
417 return cacheGetTexture(cache, list, &item->cache_id[cache->userId], &item->cache_uid[cache->userId], startup);
420 return NULL;
423 static void drawGameImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
424 mutable_image_t* gameImage = (mutable_image_t*) elem->extended;
425 if (item) {
426 GSTEXTURE* texture = getGameImageTexture(gameImage->cache, menu->item->userdata, &item->item);
427 if (!texture || !texture->Mem) {
428 if (gameImage->defaultTexture)
429 texture = &gameImage->defaultTexture->source;
430 else {
431 if (elem->type == TYPE_BACKGROUND)
432 guiDrawBGPlasma();
433 return;
437 if (gameImage->overlayTexture) {
438 rmDrawOverlayPixmap(&gameImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
439 texture, gameImage->overlayTexture->upperLeft_x, gameImage->overlayTexture->upperLeft_y, gameImage->overlayTexture->upperRight_x, gameImage->overlayTexture->upperRight_y,
440 gameImage->overlayTexture->lowerLeft_x, gameImage->overlayTexture->lowerLeft_y, gameImage->overlayTexture->lowerRight_x, gameImage->overlayTexture->lowerRight_y);
441 } else
442 rmDrawPixmap(texture, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
444 } else if (elem->type == TYPE_BACKGROUND) {
445 if (gameImage->defaultTexture)
446 rmDrawPixmap(&gameImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
447 else
448 guiDrawBGPlasma();
452 static void initGameImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name,
453 char* pattern, int count, char* texture, char* overlay) {
455 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, pattern, count, texture, overlay);
456 elem->extended = mutableImage;
457 elem->endElem = &endMutableImage;
459 if (mutableImage->cache)
460 elem->drawElem = &drawGameImage;
461 else
462 LOG("THEMES GameImage %s: NO pattern, elem disabled !!\n", name);
465 // AttributeImage ///////////////////////////////////////////////////////////////////////////////////////////////////////////
467 static void drawAttributeImage(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem) {
468 mutable_image_t* attributeImage = (mutable_image_t*) elem->extended;
469 if (config) {
470 if (attributeImage->currentConfigId != config->uid) {
471 // force refresh
472 attributeImage->currentUid = -1;
473 attributeImage->currentConfigId = config->uid;
474 attributeImage->currentValue = NULL;
475 configGetStr(config, attributeImage->cache->suffix, &attributeImage->currentValue);
477 if (attributeImage->currentValue) {
478 int posZ = 0;
479 GSTEXTURE* texture = cacheGetTexture(attributeImage->cache, menu->item->userdata, &posZ, &attributeImage->currentUid, attributeImage->currentValue);
480 if (texture && texture->Mem) {
481 if (attributeImage->overlayTexture) {
482 rmDrawOverlayPixmap(&attributeImage->overlayTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol,
483 texture, attributeImage->overlayTexture->upperLeft_x, attributeImage->overlayTexture->upperLeft_y, attributeImage->overlayTexture->upperRight_x, attributeImage->overlayTexture->upperRight_y,
484 attributeImage->overlayTexture->lowerLeft_x, attributeImage->overlayTexture->lowerLeft_y, attributeImage->overlayTexture->lowerRight_x, attributeImage->overlayTexture->lowerRight_y);
485 } else
486 rmDrawPixmap(texture, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
488 return;
492 if (attributeImage->defaultTexture)
493 rmDrawPixmap(&attributeImage->defaultTexture->source, elem->posX, elem->posY, elem->aligned, elem->width, elem->height, elem->scaled, gDefaultCol);
496 static void initAttributeImage(char* themePath, config_set_t* themeConfig, theme_t* theme, theme_element_t* elem, char* name) {
497 mutable_image_t* mutableImage = initMutableImage(themePath, themeConfig, theme, name, elem->type, NULL, 1, NULL, NULL);
498 elem->extended = mutableImage;
499 elem->endElem = &endMutableImage;
501 if (mutableImage->cache)
502 elem->drawElem = &drawAttributeImage;
503 else
504 LOG("THEMES AttributeImage %s: NO attribute, elem disabled !!\n", name);
507 // BasicElement /////////////////////////////////////////////////////////////////////////////////////////////////////////////
509 static void endBasic(theme_element_t* elem) {
510 if (elem->extended)
511 free(elem->extended);
513 free(elem);
516 static theme_element_t* initBasic(char* themePath, config_set_t* themeConfig, theme_t* theme,
517 char* name, int type, int x, int y, short aligned, int w, int h, short scaled, u64 color, int font) {
519 int intValue;
520 unsigned char charColor[3];
521 char* temp;
522 char elemProp[64];
524 theme_element_t* elem = (theme_element_t*) malloc(sizeof(theme_element_t));
526 elem->type = type;
527 elem->extended = NULL;
528 elem->drawElem = NULL;
529 elem->endElem = &endBasic;
530 elem->next = NULL;
532 snprintf(elemProp, 64, "%s_x", name);
533 if (configGetStr(themeConfig, elemProp, &temp)) {
534 if (!strncmp(temp, "POS_MID", 7))
535 x = screenWidth >> 1;
536 else
537 x = atoi(temp);
539 if (x < 0)
540 elem->posX = screenWidth + x;
541 else
542 elem->posX = x;
544 snprintf(elemProp, 64, "%s_y", name);
545 if (configGetStr(themeConfig, elemProp, &temp)) {
546 if (!strncmp(temp, "POS_MID", 7))
547 y = screenHeight >> 1;
548 else
549 y = atoi(temp);
551 if (y < 0)
552 elem->posY = ceil((screenHeight + y) * theme->usedHeight / screenHeight);
553 else
554 elem->posY = y;
556 snprintf(elemProp, 64, "%s_width", name);
557 if (configGetStr(themeConfig, elemProp, &temp)) {
558 if (!strncmp(temp, "DIM_INF", 7))
559 elem->width = screenWidth;
560 else
561 elem->width = atoi(temp);
562 } else
563 elem->width = w;
565 snprintf(elemProp, 64, "%s_height", name);
566 if (configGetStr(themeConfig, elemProp, &temp)) {
567 if (!strncmp(temp, "DIM_INF", 7))
568 elem->height = screenHeight;
569 else
570 elem->height = atoi(temp);
571 } else
572 elem->height = h;
574 snprintf(elemProp, 64, "%s_aligned", name);
575 if (configGetInt(themeConfig, elemProp, &intValue))
576 elem->aligned = intValue;
577 else
578 elem->aligned = aligned;
580 snprintf(elemProp, 64, "%s_scaled", name);
581 if (configGetInt(themeConfig, elemProp, &intValue))
582 elem->scaled = intValue;
583 else
584 elem->scaled = scaled;
586 snprintf(elemProp, 64, "%s_color", name);
587 if (configGetColor(themeConfig, elemProp, charColor))
588 elem->color = GS_SETREG_RGBA(charColor[0], charColor[1], charColor[2], 0xff);
589 else
590 elem->color = color;
592 elem->font = font;
593 snprintf(elemProp, 64, "%s_font", name);
594 if (configGetInt(themeConfig, elemProp, &intValue)) {
595 if (intValue > 0 && intValue < THM_MAX_FONTS)
596 elem->font = theme->fonts[intValue];
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, theme->fonts[0]);
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, -40, -60, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, SCALING_RATIO, gDefaultCol, theme->fonts[0]);
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 fntRelease(theme->fonts[id]);
931 free(theme);
932 theme = NULL;
936 static int thmReadEntry(int index, char* path, char* separator, char* name, unsigned int mode) {
937 if (FIO_SO_ISDIR(mode) && strstr(name, "thm_")) {
938 theme_file_t* currTheme = &themes[nThemes + index];
940 int length = strlen(name) - 4 + 1;
941 currTheme->name = (char*) malloc(length * sizeof(char));
942 memcpy(currTheme->name, name + 4, length);
943 currTheme->name[length - 1] = '\0';
945 length = strlen(path) + 1 + strlen(name) + 1 + 1;
946 currTheme->filePath = (char*) malloc(length * sizeof(char));
947 sprintf(currTheme->filePath, "%s%s%s%s", path, separator, name, separator);
949 LOG("THEMES Theme found: %s\n", currTheme->filePath);
951 index++;
953 return index;
956 /* themePath must contains the leading separator (as it is dependent of the device, we can't know here) */
957 static int thmLoadResource(int texId, char* themePath, short psm, int useDefault) {
958 int success = -1;
959 GSTEXTURE* texture = &gTheme->textures[texId];
961 if (themePath != NULL)
962 success = texDiscoverLoad(texture, themePath, texId, psm); // only set success here
964 if ((success < 0) && useDefault)
965 texPngLoad(texture, NULL, texId, psm); // we don't mind the result of "default"
967 return success;
970 static void thmSetColors(theme_t* theme) {
971 memcpy(theme->bgColor, gDefaultBgColor, 3);
972 theme->textColor = GS_SETREG_RGBA(gDefaultTextColor[0], gDefaultTextColor[1], gDefaultTextColor[2], 0xff);
973 theme->uiTextColor = GS_SETREG_RGBA(gDefaultUITextColor[0], gDefaultUITextColor[1], gDefaultUITextColor[2], 0xff);
974 theme->selTextColor = GS_SETREG_RGBA(gDefaultSelTextColor[0], gDefaultSelTextColor[1], gDefaultSelTextColor[2], 0xff);
976 theme_element_t* elem = theme->mainElems.first;
977 while (elem) {
978 elem->color = theme->textColor;
979 elem = elem->next;
983 static void thmLoadFonts(config_set_t* themeConfig, const char* themePath, theme_t* theme) {
984 int fntID; // theme side font id, not the fntSys handle
985 for (fntID = 0; fntID < THM_MAX_FONTS; ++fntID) {
986 // does the font by the key exist?
987 char fntKey[16];
989 if (fntID == 0) {
990 snprintf(fntKey, 16, "default_font");
991 theme->fonts[0] = FNT_DEFAULT;
992 } else {
993 snprintf(fntKey, 16, "font%d", fntID);
994 theme->fonts[fntID] = theme->fonts[0];
997 char fullPath[128];
998 char *fntFile;
999 if (configGetStr(themeConfig, fntKey, &fntFile)) {
1000 snprintf(fullPath, 128, "%s%s", themePath, fntFile);
1001 int fntHandle = fntLoadFile(fullPath);
1003 // Do we have a valid font? Assign the font handle to the theme font slot
1004 if (fntHandle != FNT_ERROR)
1005 theme->fonts[fntID] = fntHandle;
1010 static void thmLoad(char* themePath) {
1011 LOG("THEMES Load theme path=%s\n", themePath);
1012 theme_t* curT = gTheme;
1013 theme_t* newT = (theme_t*) malloc(sizeof(theme_t));
1014 memset(newT, 0, sizeof(theme_t));
1016 newT->useDefault = 1;
1017 newT->usedHeight = 480;
1018 thmSetColors(newT);
1019 newT->mainElems.first = NULL;
1020 newT->mainElems.last = NULL;
1021 newT->infoElems.first = NULL;
1022 newT->infoElems.last = NULL;
1023 newT->gameCacheCount = 0;
1024 newT->itemsList = NULL;
1025 newT->loadingIcon = NULL;
1026 newT->loadingIconCount = LOAD7_ICON - LOAD0_ICON + 1;
1028 config_set_t* themeConfig = NULL;
1029 if (!themePath) {
1030 themeConfig = configAlloc(0, NULL, NULL);
1031 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_MENU_ICON], "_");
1032 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_MENU_TEXT], "_");
1033 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEMS_LIST], "_");
1034 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_ICON], "_");
1035 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_COVER], "_");
1036 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_ITEM_TEXT], "_");
1037 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_HINT_TEXT], "_");
1038 addGUIElem(themePath, themeConfig, newT, &newT->mainElems, elementsType[TYPE_LOADING_ICON], "_");
1039 } else {
1040 char path[255];
1041 snprintf(path, 255, "%sconf_theme.cfg", themePath);
1042 themeConfig = configAlloc(0, NULL, path);
1043 configRead(themeConfig); // try to load the theme config file
1045 int intValue;
1046 if (configGetInt(themeConfig, "use_default", &intValue))
1047 newT->useDefault = intValue;
1049 if (configGetInt(themeConfig, "use_real_height", &intValue)) {
1050 if (intValue)
1051 newT->usedHeight = screenHeight;
1054 configGetColor(themeConfig, "bg_color", newT->bgColor);
1056 unsigned char color[3];
1057 if (configGetColor(themeConfig, "text_color", color))
1058 newT->textColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1060 if (configGetColor(themeConfig, "ui_text_color", color))
1061 newT->uiTextColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1063 if (configGetColor(themeConfig, "sel_text_color", color))
1064 newT->selTextColor = GS_SETREG_RGBA(color[0], color[1], color[2], 0xff);
1066 // before loading the element definitions, we have to have the fonts prepared
1067 // for that, we load the fonts and a translation table
1068 thmLoadFonts(themeConfig, themePath, newT);
1070 int i = 1;
1071 snprintf(path, 255, "main0");
1072 while (addGUIElem(themePath, themeConfig, newT, &newT->mainElems, NULL, path))
1073 snprintf(path, 255, "main%d", i++);
1075 i = 1;
1076 snprintf(path, 255, "info0");
1077 while(addGUIElem(themePath, themeConfig, newT, &newT->infoElems, NULL, path))
1078 snprintf(path, 255, "info%d", i++);
1081 validateGUIElems(themePath, themeConfig, newT);
1082 configFree(themeConfig);
1084 LOG("THEMES Number of cache: %d\n", newT->gameCacheCount);
1085 LOG("THEMES Used height: %d\n", newT->usedHeight);
1087 /// Now swap theme and start loading textures
1088 if (newT->usedHeight == screenHeight)
1089 rmResetShiftRatio();
1090 else
1091 rmSetShiftRatio((float) screenHeight / newT->usedHeight);
1093 int i;
1094 // default all to not loaded...
1095 for (i = 0; i < TEXTURES_COUNT; i++) {
1096 newT->textures[i].Mem = NULL;
1099 // LOGO, loaded here to avoid flickering during startup with device in AUTO + theme set
1100 texPngLoad(&newT->textures[LOGO_PICTURE], NULL, LOGO_PICTURE, GS_PSM_CT24);
1102 gTheme = newT;
1103 thmFree(curT);
1105 // First start with busy icon
1106 char* path = themePath;
1107 int customBusy = 0;
1108 for (i = LOAD0_ICON; i <= LOAD7_ICON; i++) {
1109 if (thmLoadResource(i, path, GS_PSM_CT32, gTheme->useDefault) >= 0)
1110 customBusy = 1;
1111 else {
1112 if (customBusy)
1113 break;
1114 else
1115 path = NULL;
1118 gTheme->loadingIconCount = i;
1120 // Customizable icons
1121 for (i = USB_ICON; i <= START_ICON; i++)
1122 thmLoadResource(i, themePath, GS_PSM_CT32, gTheme->useDefault);
1124 // Not customizable icons
1125 for (i = L1_ICON; i <= R2_ICON; i++)
1126 thmLoadResource(i, NULL, GS_PSM_CT32, 1);
1129 static void thmRebuildGuiNames() {
1130 if (guiThemesNames)
1131 free(guiThemesNames);
1133 // build the languages name list
1134 guiThemesNames = (char**) malloc((nThemes + 2) * sizeof(char**));
1136 // add default internal
1137 guiThemesNames[0] = "<OPL>";
1139 int i = 0;
1140 for (; i < nThemes; i++) {
1141 guiThemesNames[i + 1] = themes[i].name;
1144 guiThemesNames[nThemes + 1] = NULL;
1147 void thmAddElements(char* path, char* separator, int mode) {
1148 nThemes += listDir(path, separator, THM_MAX_FILES - nThemes, &thmReadEntry);
1149 thmRebuildGuiNames();
1151 char* temp;
1152 if (configGetStr(configGetByType(CONFIG_OPL), "theme", &temp)) {
1153 LOG("THEMES Trying to set again theme: %s\n", temp);
1154 if (thmSetGuiValue(thmFindGuiID(temp), 0))
1155 moduleUpdateMenu(mode, 1);
1159 void thmInit() {
1160 LOG("THEMES Init\n");
1161 gTheme = NULL;
1163 thmReloadScreenExtents();
1165 // initialize default internal
1166 thmLoad(NULL);
1168 thmAddElements(gBaseMCDir, "/", -1);
1171 void thmReinit(char* path) {
1172 thmLoad(NULL);
1173 guiThemeID = 0;
1175 int i = 0;
1176 while (i < nThemes) {
1177 if (strncmp(themes[i].filePath, path, strlen(path)) == 0) {
1178 LOG("THEMES Remove theme: %s\n", themes[i].filePath);
1179 nThemes--;
1180 free(themes[i].name);
1181 themes[i].name = themes[nThemes].name;
1182 themes[nThemes].name = NULL;
1183 free(themes[i].filePath);
1184 themes[i].filePath = themes[nThemes].filePath;
1185 themes[nThemes].filePath = NULL;
1186 } else
1187 i++;
1190 thmRebuildGuiNames();
1193 void thmReloadScreenExtents() {
1194 rmGetScreenExtents(&screenWidth, &screenHeight);
1197 char* thmGetValue() {
1198 return guiThemesNames[guiThemeID];
1201 int thmSetGuiValue(int themeID, int reload) {
1202 if (themeID != -1) {
1203 if (guiThemeID != themeID || reload) {
1204 if (themeID != 0)
1205 thmLoad(themes[themeID - 1].filePath);
1206 else
1207 thmLoad(NULL);
1209 guiThemeID = themeID;
1210 configSetStr(configGetByType(CONFIG_OPL), "theme", thmGetValue());
1211 return 1;
1213 else if (guiThemeID == 0)
1214 thmSetColors(gTheme);
1216 return 0;
1219 int thmGetGuiValue() {
1220 return guiThemeID;
1223 int thmFindGuiID(char* theme) {
1224 if (theme) {
1225 int i = 0;
1226 for (; i < nThemes; i++) {
1227 if (stricmp(themes[i].name, theme) == 0)
1228 return i + 1;
1231 return 0;
1234 char **thmGetGuiList() {
1235 return guiThemesNames;
1238 void thmEnd() {
1239 thmFree(gTheme);
1241 int i = 0;
1242 for (; i < nThemes; i++) {
1243 free(themes[i].name);
1244 free(themes[i].filePath);
1247 free(guiThemesNames);