Commits

izdubar committed 58eaba6

* added information page (new option to enable it or not)
* overlay, cache and static image can be shared between main/info page
* code factorization for all image based elements
* added AttributeImage type, and AttributeText type
* add support for per-game config file (not used for the moment)

Comments (0)

Files changed (26)

include/dialogs.h

 #define UICFG_AUTOREFRESH		20
 #define UICFG_VMODE				21
 #define UICFG_VSYNC				22
+#define UICFG_INFOPAGE			23
 
 #define CFG_EXITTO				30
 #define CFG_DEFDEVICE			31
 
 typedef void (*gui_callback_t)(void);
 
-// called when filling the menu
-typedef void (*gui_menufill_callback_t)(submenu_list_t **menu);
+int guiInactiveFrames;
+int guiFrameId;
 
-// called when a menuitem with unknown id is encountered
-typedef void (*gui_menuexec_callback_t)(int id);
+#define GUI_SCREEN_MAIN		0
+#define GUI_SCREEN_MENU		1
+#define GUI_SCREEN_INFO		2
+
+void guiSwitchScreen(int target);
 
 void guiReloadScreenExtents();
 
 /** Hooks a single per-frame callback */
 void guiSetFrameHook(gui_callback_t cback);
 
-/** Hooks a single callback for main menu population */
-void guiSetMenuFillHook(gui_menufill_callback_t cback);
-
-/** Hooks a single callback for main menu execution - executed when invalid item is encountered */
-void guiSetMenuExecHook(gui_menuexec_callback_t cback);
-
 // Deffered update handling:
 /* Note:
 All the GUI operation requests can be deffered to the proper time
 void guiUpdateScreenScale(void);
 
 void guiDrawBGPlasma();
+void guiShowAbout();
+void guiShowConfig();
+void guiShowUIConfig();
+void guiShowIPConfig();
 
 /** Renders the given string on screen for the given function until it's io finishes 
 * @note The ptr pointer is watched for it's value. The IO is considered finished when the value becomes zero. 

include/iosupport.h

 #define COMPAT_MODE_8 		0x80
 
 // minimal inactive frames for cover display, can be pretty low since it means no button is pressed :)
-#define MENU_MIN_INACTIVE_FRAMES 3
+#define MENU_MIN_INACTIVE_FRAMES 8
 
 typedef struct
 {
 	
 	config_set_t* (*itemGetConfig)(int id);
 
-	int (*itemGetImage)(char* folder, int addSep, char* value, char* suffix, GSTEXTURE* resultTex, short psm);
+	int (*itemGetImage)(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm);
 
 	void (*itemCleanUp)(int exception);
 	
 #define _STR_VMODE						109
 #define _STR_UICOLOR					110
 #define _STR_SELCOLOR					111
+#define _STR_USE_INFO_SCREEN			112
 
-#define LANG_STR_COUNT 112
+#define LANG_STR_COUNT 113
 
 // Maximum external languages supported
 #define MAX_LANGUAGE_FILES 15

include/menusys.h

 	/// item description in localized form (used if value is not negative)
 	int text_id;
 	
-	/// item id
+	/// item id (MUST BE VALID, we assert it is != -1 to optimize rendering)
 	int id;
 	
-	config_set_t* config;
-
 	int* cache_id;
 	int* cache_uid;
 } submenu_item_t;
 	/// submenu, selection and page start (only used in static mode)
 	struct submenu_list *submenu, *current, *pagestart;
 	
-	void (*refresh)(struct menu_item *self);
+	void (*refresh)(struct menu_item *curMenu);
 
-	void (*execCross)(struct menu_item *self, int id);
+	void (*execCross)(struct menu_item *curMenu);
 	
-	void (*execTriangle)(struct menu_item *self, int id);
+	void (*execTriangle)(struct menu_item *curMenu);
 
-	void (*execCircle)(struct menu_item *self, int id);
+	void (*execCircle)(struct menu_item *curMenu);
 	
-	void (*execSquare)(struct menu_item *self, int id);
+	void (*execSquare)(struct menu_item *curMenu);
 	
 	/// hint list
 	struct menu_hint_item *hints;
 char *menuItemGetText(menu_item_t* it);
 void menuRefreshCache(menu_item_t *menu);
 
-void menuDrawStatic();
-
-void menuNextH();
-void menuPrevH();
-void menuNextV();
-void menuPrevV();
-void menuNextPage();
-void menuPrevPage();
-void menuFirstPage();
-void menuLastPage();
-menu_item_t* menuGetCurrent();
-void menuItemExecButton(void (*execActionButton)(menu_item_t *self, int id));
+void menuRenderMain();
+void menuRenderMenu();
+void menuRenderInfo();
+void menuHandleInputMain();
+void menuHandleInputMenu();
+void menuHandleInputInfo();
 
 // Sets the selected item if it is found in the menu list
 void menuSetSelectedItem(menu_item_t *item);

include/supportbase.h

 int sbPrepare(base_game_info_t* game, int mode, char* isoname, int size_cdvdman, void** cdvdman_irx, int* patchindex);
 void sbDelete(base_game_info_t **list, const char* prefix, const char* sep, int gamecount, int id);
 void sbRename(base_game_info_t **list, const char* prefix, const char* sep, int gamecount, int id, char* newname);
+void sbPopulateConfig(base_game_info_t* game, config_set_t* config);
 
 #endif
 unsigned int USBA_crc32(char *string);
 int sysGetDiscID(char *discID);
 void sysReset(int modload_mask);
+void sysExecExit();
 void sysPowerOff(void);
 int sysPcmciaCheck(void);
 void sysGetCDVDFSV(void **data_irx, int *size_irx);

include/texcache.h

 	
 	/// directory prefix for this cache (if any)
 	char* prefix;
-	int addSeparator;
+	int isPrefixRelative;
+	char* suffix;
 
 	int nextUID;
 	
 */
 void cacheEnd();
 
-/** sets a new frame id (call once every frame!)
+/** Initializes a single cache 
 */
-void cacheNextFrame(int inactives);
-
-/** Initializes a single cache 
-* @param cache the cache to initialize
-* @param prefix a string prefix that gets prepended to the path when loading the pixmap
-* @param count the count of items to cache (negative value = use default)
-*/
-image_cache_t* cacheInitCache(int userId, char* prefix, int addSeparator, int count);
+image_cache_t* cacheInitCache(int userId, char* prefix, int isPrefixRelative, char* suffix, int count);
 
 /** Destroys a given cache (unallocates all memory stored there, disconnects the pixmaps from the usage points).
 */
 void cacheDestroyCache(image_cache_t* cache);
 
-GSTEXTURE* cacheGetTexture(image_cache_t* cache, item_list_t* list, int* cacheId, int* UID, char* value, char* suffix);
+GSTEXTURE* cacheGetTexture(image_cache_t* cache, item_list_t* list, int* cacheId, int* UID, char* value);
 
 #endif
 #define THM_MAX_FONTS 16
 
 typedef struct {
+	// optional, only for overlays
 	int upperLeft_x;
 	int upperLeft_y;
 	int upperRight_x;
 	int lowerLeft_y;
 	int lowerRight_x;
 	int lowerRight_y;
-	GSTEXTURE texture;
-} image_overlay_t;
+
+	// basic texture information
+	char* name;
+	GSTEXTURE source;
+} image_texture_t;
 
 typedef struct {
+	// Attributes for: AttributeImage
+	int currentUid;
+	char currentName[32];
+
+	// Attributes  for: AttributeImage & GameImage
 	image_cache_t* cache;
-	GSTEXTURE defaultTex; // an optional default texture when the cache fails
-	int* attributeUid;
-	int* attributeId;
+	int cacheLinked;
 
-	char* attribute;
+	// Attributes for: AttributeImage & GameImage & StaticImage
+	image_texture_t* defaultTexture;
+	int defaultTextureLinked;
 
-	image_overlay_t* overlay; // an optional overlay
-} attribute_image_t;
-
-typedef struct {
-	image_cache_t* cache;
-	GSTEXTURE defaultTex; // an optional default texture when the cache fails
-
-	char* pattern;
-
-	image_overlay_t* overlay; // an optional overlay
-} game_image_t;
-
-typedef struct {
-	GSTEXTURE texture;
-
-	image_overlay_t* overlay; // an optional overlay
-} static_image_t;
+	image_texture_t* overlayTexture;
+	int overlayTextureLinked;
+} mutable_image_t;
 
 typedef struct {
 	int displayedItems;
 
 	char* decorator;
-	game_image_t* decoratorImage;
+	mutable_image_t* decoratorImage;
 } items_list_t;
 
 typedef struct theme_element {
 
 	void* extended;
 
-	void (*drawElem)(struct menu_list* curMenu, struct submenu_list* curItem, struct theme_element* elem);
+	void (*drawElem)(struct menu_list* menu, struct submenu_list* item, config_set_t* config, struct theme_element* elem);
 	void (*endElem)(struct theme_element* elem);
 
 	struct theme_element* next;
 } theme_element_t;
 
 typedef struct {
+	theme_element_t* first;
+	theme_element_t* last;
+} theme_elems_t;
+
+typedef struct {
 	char* filePath;
 	char* name;
 } theme_file_t;
 	u64 uiTextColor;
 	u64 selTextColor;
 
-	theme_element_t* elems;
+	theme_elems_t mainElems;
+	theme_elems_t infoElems;
+
 	int gameCacheCount;
 
 	theme_element_t* itemsList;
 int loadConfig(int types);
 int saveConfig(int types, int showUI);
 void applyConfig(int themeID, int langID, int newVMode, int newVSync);
+void handleHdlSrv();
 void shutdown();
 
 char *gBaseMCDir;
 int gHDDStartMode;
 int gETHStartMode;
 int gAPPStartMode;
-/// Sort the game lists automatically
 int gAutosort;
 int gAutoRefresh;
-/// true if icons and covers Art should be displayed
+int gUseInfoScreen;
 int gEnableArt;
 int gWideScreen;
 int gVMode; // 0 - Auto, 1 - PAL, 2 - NTSC
 
 int gRememberLastPlayed;
 
-//// GUI
-
 char *infotxt;
 
 unsigned char gDefaultBgColor[3];
 static config_set_t* appGetConfig(int id) {
 	config_set_t* config = configAlloc(0, NULL, NULL);
 	struct config_value_t* cur = appGetConfigValue(id);
-
+	configSetStr(config, "#Name", appGetELFName(cur->val));
+	configSetStr(config, "#LongName", cur->key);
+	configSetStr(config, "#Startup", cur->val);
 	return config;
 }
 
-static int appGetImage(char* folder, int addSep, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
+static int appGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
 	value = appGetELFName(value);
 	// We search on ever devices from fatest to slowest (HDD > ETH > USB)
 	static item_list_t *listSupport = NULL;
 	if ( (listSupport = hddGetObject(1)) ) {
-		if (listSupport->itemGetImage(folder, addSep, value, suffix, resultTex, psm) >= 0)
+		if (listSupport->itemGetImage(folder, isRelative, value, suffix, resultTex, psm) >= 0)
 			return 0;
 	}
 
 	if ( (listSupport = ethGetObject(1)) ) {
-		if (listSupport->itemGetImage(folder, addSep, value, suffix, resultTex, psm) >= 0)
+		if (listSupport->itemGetImage(folder, isRelative, value, suffix, resultTex, psm) >= 0)
 			return 0;
 	}
 
 	if ( (listSupport = usbGetObject(1)) )
-		return listSupport->itemGetImage(folder, addSep, value, suffix, resultTex, psm);
+		return listSupport->itemGetImage(folder, isRelative, value, suffix, resultTex, psm);
 
 	return -1;
 }
 
 #include <stdio.h>
 #include "include/atlas.h"
-#include <draw_types.h>
-
 
 static inline struct atlas_allocation_t *allocNew(int x, int y, size_t width, size_t height) {
 	struct atlas_allocation_t *al = (struct atlas_allocation_t *)malloc(sizeof(struct atlas_allocation_t));
 		if (strncmp(it->val, value, 255) != 0) {
 			strncpy(it->val, value, 255);
 			it->val[min(strlen(value), 254)] = '\0';
-			configSet->modified = 1;
+			if (it->key[0] != '#')
+				configSet->modified = 1;
 		}
 	} else {
 		addConfigValue(configSet, key, value);
-		configSet->modified = 1;
+		if (key[0] != '#')
+			configSet->modified = 1;
 	}
 	
 	return 1;
 	
 	while (val) {
 		if (strncmp(val->key, key, 32) == 0) {
+			if (key[0] != '#')
+				configSet->modified = 1;
+
 			if (val == configSet->tail)
 				configSet->tail = prev;
 
 				free(configSet->head);
 				configSet->head = val;
 			}
-
-			configSet->modified = 1;
 		} else {
 			prev = val;
 			val = val->next;
 			struct config_value_t* cur = configSet->head;
 
 			while (cur) {
-				if (cur->key[0] != '\0') {
+				if ((cur->key[0] != '\0') && (cur->key[0] != '#')) {
 					snprintf(line, 512, "%s=%s\r\n", cur->key, cur->val); // add windows CR+LF (0x0D 0x0A)
 					writeFileBuffer(fileBuffer, line, strlen(line));
 				}
 		readPads();
 		
 		rmStartFrame();
-		guiDrawBGPlasma(); // TODO IZD gTheme->drawAltBackground();
-		
+		guiDrawBGPlasma();
 		rmDrawRect(0, 0, ALIGN_NONE, DIM_INF, DIM_INF, gColDarker);
 
 		//Text
 		readPads();
 		
 		rmStartFrame();
-	
-		guiDrawBGPlasma(); //gTheme->drawAltBackground();
-		
+		guiDrawBGPlasma();
 		rmDrawRect(0, 0, ALIGN_NONE, DIM_INF, DIM_INF, gColDarker);
 		
 		// "Color selection"
 
 /// renders whole ui screen (for given dialog setup)
 void diaRenderUI(struct UIItem *ui, short inMenu, struct UIItem *cur, int haveFocus) {
-	/*if (inMenu)
-		gTheme->drawAltBackground();
-	else
-		gTheme->drawBackground();*/ // TODO IZD
 	guiDrawBGPlasma();
 
 	int x0 = 20;
 	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_SCROLLING}}}, {UI_SPACER}, {UI_ENUM, UICFG_SCROLL, 1, -1, 0, 0, {.intvalue = {0, 0}}}, {UI_BREAK},
 	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_AUTOSORT}}}, {UI_SPACER}, {UI_BOOL, UICFG_AUTOSORT, 1, -1, 0, 0, {.intvalue = {0, 0}}}, {UI_BREAK},
 	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_AUTOREFRESH}}}, {UI_SPACER}, {UI_BOOL, UICFG_AUTOREFRESH, 1, -1, 0, 0, {.intvalue = {0, 0}}}, {UI_BREAK},
-	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_COVERART}}}, {UI_SPACER}, {UI_BOOL, UICFG_COVERART, 1, -1, 0, 0, {.intvalue = {0, 0}}},
+	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_COVERART}}}, {UI_SPACER}, {UI_BOOL, UICFG_COVERART, 1, -1, 0, 0, {.intvalue = {0, 0}}}, {UI_BREAK},
+	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_USE_INFO_SCREEN}}}, {UI_SPACER}, {UI_BOOL, UICFG_INFOPAGE, 1, -1, 0, 0, {.intvalue = {0, 0}}},
 	
 	{UI_SPLITTER},
 	
-	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_TXTCOLOR}}}, {UI_SPACER}, {UI_COLOUR, UICFG_TXTCOL, 1, -1, -10, 17, {.colourvalue = {0, 0}}}, // UIItem #28
+	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_TXTCOLOR}}}, {UI_SPACER}, {UI_COLOUR, UICFG_TXTCOL, 1, -1, -10, 17, {.colourvalue = {0, 0}}}, // UIItem #32
 	{UI_SPACER},
-	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_SELCOLOR}}}, {UI_SPACER}, {UI_COLOUR, UICFG_SELCOL, 1, -1, -10, 17, {.colourvalue = {0, 0}}}, // UIItem #32
+	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_SELCOLOR}}}, {UI_SPACER}, {UI_COLOUR, UICFG_SELCOL, 1, -1, -10, 17, {.colourvalue = {0, 0}}}, // UIItem #36
 	{UI_BREAK},
-	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_UICOLOR}}}, {UI_SPACER}, {UI_COLOUR, UICFG_UICOL, 1, -1, -10, 17, {.colourvalue = {0, 0}}}, // UIItem #36
+	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_UICOLOR}}}, {UI_SPACER}, {UI_COLOUR, UICFG_UICOL, 1, -1, -10, 17, {.colourvalue = {0, 0}}}, // UIItem #40
 	{UI_SPACER},
-	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_BGCOLOR}}}, {UI_SPACER}, {UI_COLOUR, UICFG_BGCOL, 1, -1, -10, 17, {.colourvalue = {0, 0}}}, // UIItem #40
+	{UI_LABEL, 0, 1, -1, -20, 0, {.label = {NULL, _STR_BGCOLOR}}}, {UI_SPACER}, {UI_COLOUR, UICFG_BGCOL, 1, -1, -10, 17, {.colourvalue = {0, 0}}}, // UIItem #44
 	{UI_BREAK},
 
 	{UI_SPLITTER},
 static config_set_t* ethGetConfig(int id) {
 	config_set_t* config = configAlloc(0, NULL, NULL);
 	base_game_info_t* game = &ethGames[id];
-
+	sbPopulateConfig(game, config);
 	return config;
 }
 
-static int ethGetImage(char* folder, int addSep, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
+static int ethGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
 	char path[255];
-	if (addSep)
+	if (isRelative)
 		sprintf(path, "%s%s\\%s_%s", ethPrefix, folder, value, suffix);
 	else
-		sprintf(path, "%s%s%s_%s", ethPrefix, folder, value, suffix);
+		sprintf(path, "%s%s_%s", folder, value, suffix);
 	return texDiscoverLoad(resultTex, path, -1, psm);
 }
 
 /*
-  Copyright 2010, Volca
-  Licenced under Academic Free License version 3.0
-  Review OpenUsbLd README & LICENSE files for further details.  
-*/
+ Copyright 2010, Volca
+ Licenced under Academic Free License version 3.0
+ Review OpenUsbLd README & LICENSE files for further details.
+ */
 
 #include "include/usbld.h"
 #include "include/gui.h"
 #include <stdlib.h>
 #include <libvux.h>
 
-#define MAX_GAME_HANDLERS 8
-
-// temp
-#define GS_BGCOLOUR *((volatile unsigned long int*)0x120000E0)
-
 static int gScheduledOps;
 static int gCompletedOps;
 static int gTerminate;
 static int gInitComplete;
 
 static gui_callback_t gFrameHook;
-static gui_menufill_callback_t gMenuFillHook;
-static gui_menuexec_callback_t gMenuExecHook;
 
 static s32 gSemaId;
 static s32 gGUILockSemaId;
 static ee_sema_t gQueueSema;
 
-static int gInactiveFrames;
-static int gFrameCounter;
-
-static GSTEXTURE gBackgroundTex;
-
 static int screenWidth;
 static float wideScreenScale;
 
 struct gui_update_list_t *gUpdateList;
 struct gui_update_list_t *gUpdateEnd;
 
-submenu_list_t *g_settings_submenu = NULL;
-submenu_list_t *g_games_submenu = NULL;
-
 typedef struct {
 	void (*handleInput)(void);
 	void (*renderScreen)(void);
 	short inMenu;
 } gui_screen_handler_t;
 
-// Main screen rendering/input
-static void guiMainHandleInput(void);
-static void guiMainRender(void);
+static gui_screen_handler_t screenHandlers[] = {{ &menuHandleInputMain, &menuRenderMain, 0 },
+												{ &menuHandleInputMenu, &menuRenderMenu, 1 },
+												{ &menuHandleInputInfo, &menuRenderInfo, 1 } };
 
-// Main menu rendering/input 
-static void guiMenuHandleInput(void);
-static void guiMenuRender(void);
-
-// default screen handler (main screen)
-static gui_screen_handler_t mainScreenHandler = {
-	&guiMainHandleInput,
-	&guiMainRender,
-	0
-};
-
-static gui_screen_handler_t menuScreenHandler = {
-	&guiMenuHandleInput,
-	&guiMenuRender,
-	1
-};
-
-static gui_screen_handler_t *screenHandler = &menuScreenHandler;
+// default screen handler (menu screen)
+static gui_screen_handler_t *screenHandler = &screenHandlers[GUI_SCREEN_MENU];
 
 // screen transition handling
 static gui_screen_handler_t *screenHandlerTarget = NULL;
 static int transition = 0;
 
-// "main menu submenu"
-static submenu_list_t *mainMenu;
-// active item in the main menu
-static submenu_list_t *mainMenuCurrent;
-
 // Helper perlin noise data
 #define PLASMA_H 32
 #define PLASMA_W 32
 #define PLASMA_ROWS_PER_FRAME 6
 #define FADE_SIZE 256
 
+static GSTEXTURE gBackgroundTex;
 static int pperm[512];
 static float fadetbl[FADE_SIZE + 1];
 
-static VU_VECTOR pgrad3[12] = {
-	{1,1,0,1},{-1,1,0,1},{1,-1,0,1},{-1,-1,0,1}, 
-	{1,0,1,1},{-1,0,1,1},{1,0,-1,1},{-1,0,-1,1}, 
-	{0,1,1,1},{0,-1,1,1},{0,1,-1,1},{0,-1,-1,1}
-};
-
-static void guiInitMainMenu() {
-	if (mainMenu)
-		submenuDestroy(&mainMenu);
-
-	// initialize the menu
-#ifndef __CHILDPROOF
-	submenuAppendItem(&mainMenu, -1, "Settings", 1, _STR_SETTINGS);
-	submenuAppendItem(&mainMenu, -1, "Display Settings", 2, _STR_GFX_SETTINGS);
-	submenuAppendItem(&mainMenu, -1, "Network settings", 3, _STR_IPCONFIG);
-	submenuAppendItem(&mainMenu, -1, "Save Changes", 7, _STR_SAVE_CHANGES);
-#endif
-	
-	// Callback to fill in other items
-	if (gMenuFillHook) // if found
-		gMenuFillHook(&mainMenu);
-
-	submenuAppendItem(&mainMenu, -1, "About", 8, _STR_ABOUT);
-	submenuAppendItem(&mainMenu, -1, "Exit", 9, _STR_EXIT);
-	submenuAppendItem(&mainMenu, -1, "Power off", 11, _STR_POWEROFF);
-
-	mainMenuCurrent = mainMenu;
-}
+static VU_VECTOR pgrad3[12] = {{ 1, 1, 0, 1 }, { -1, 1, 0, 1 }, { 1, -1, 0, 1 }, { -1, -1, 0, 1 },
+								{ 1, 0, 1, 1 }, { -1, 0, 1, 1 }, { 1, 0, -1, 1 }, { -1, 0, -1, 1 },
+								{ 0, 1, 1, 1 },	{ 0, -1, 1, 1 }, { 0, 1, -1, 1 }, { 0, -1, -1, 1 } };
 
 void guiReloadScreenExtents() {
 	int screenHeight;
 }
 
 void guiInit(void) {
-	gFrameCounter = 0;
+	guiFrameId = 0;
+	guiInactiveFrames = 0;
+
 	gFrameHook = NULL;
-	gMenuFillHook = NULL;
-	gMenuExecHook = NULL;
 	gTerminate = 0;
 	gInitComplete = 0;
 	gScheduledOps = 0;
 
 	gUpdateList = NULL;
 	gUpdateEnd = NULL;
-	
-	gInactiveFrames = 0;
-	
+
 	gQueueSema.init_count = 1;
 	gQueueSema.max_count = 1;
 	gQueueSema.option = 0;
-	
-	mainMenu = NULL;
-	
+
 	gSemaId = CreateSema(&gQueueSema);
 	gGUILockSemaId = CreateSema(&gQueueSema);
-	
+
 	guiReloadScreenExtents();
 	menuInit();
-	
-	guiInitMainMenu();
-	
+
 	// background texture - for perlin
 	gBackgroundTex.Width = PLASMA_W;
 	gBackgroundTex.Height = PLASMA_H;
 	gBackgroundTex.PSM = GS_PSM_CT32;
 	gBackgroundTex.Filter = GS_FILTER_LINEAR;
 	gBackgroundTex.Vram = 0;
-	
+
 	wideScreenScale = 1.0f;
-	
+
 	// Precalculate the values for the perlin noise plasma
 	int i;
 	for (i = 0; i < 256; ++i) {
 		pperm[i] = rand() % 256;
 		pperm[i + 256] = pperm[i];
 	}
-	
+
 	for (i = 0; i <= FADE_SIZE; ++i) {
-		float t = (float)(i) / FADE_SIZE;
-		
-		fadetbl[i] = t*t*t*(t*(t*6.0-15.0)+10.0); 
+		float t = (float) (i) / FADE_SIZE;
+
+		fadetbl[i] = t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
 	}
-	
+
 	// Render single screen
 	guiShow();
 }
 
 void guiEnd() {
-	mainMenuCurrent = NULL;
-	submenuDestroy(&mainMenu);
+	if (gBackgroundTex.Mem)
+		free(gBackgroundTex.Mem);
+
+	menuEnd();
 }
 
 void guiLock(void) {
 
 	guiLock();
 	rmStartFrame();
-	gFrameCounter++;
+	guiFrameId++;
 }
 
 void guiEndFrame(void) {
 	guiUnlock();
 	rmFlush();
-	
+
 #ifdef __DEBUG
 	u32 newtime = cpu_ticks() / CLOCKS_PER_MILISEC;
 	time_render = newtime - curtime;
 #endif
-		
+
 	rmEndFrame();
 }
 
-static void guiShowAbout() {
+void guiShowAbout() {
 	char OPLVersion[64];
 	snprintf(OPLVersion, 64, _l(_STR_OUL_VER), USBLD_VERSION);
 
 	diaExecuteDialog(diaAbout, -1, 1, NULL);
 }
 
-static void guiExecExit() {
-	__asm__ __volatile__(
-		"	li $3, 0x04;"
-		"	syscall;"
-		"	nop;"
-	);
-}
-
-static void guiShowConfig() {
+void guiShowConfig() {
 	// configure the enumerations
 	const char* deviceNames[] = { _l(_STR_USB_GAMES), _l(_STR_NET_GAMES), _l(_STR_HDD_GAMES), NULL };
 	const char* deviceModes[] = { _l(_STR_OFF), _l(_STR_MANUAL), _l(_STR_AUTO), NULL };
 		if (temp != curTheme) {
 			curTheme = temp;
 			if (temp == 0) {
-				diaUIConfig[28].type = UI_COLOUR; // Must be correctly set before doing the diaS/GetColor !!
-				diaUIConfig[32].type = UI_COLOUR;
+				diaUIConfig[32].type = UI_COLOUR; // Must be correctly set before doing the diaS/GetColor !!
 				diaUIConfig[36].type = UI_COLOUR;
 				diaUIConfig[40].type = UI_COLOUR;
+				diaUIConfig[44].type = UI_COLOUR;
 				diaSetColor(diaUIConfig, UICFG_BGCOL, gDefaultBgColor);
 				diaSetColor(diaUIConfig, UICFG_UICOL, gDefaultUITextColor);
 				diaSetColor(diaUIConfig, UICFG_TXTCOL, gDefaultTextColor);
 				diaSetColor(diaUIConfig, UICFG_SELCOL, gDefaultSelTextColor);
-			} else	if (temp == thmGetGuiValue()) {
-				diaUIConfig[28].type = UI_COLOUR;
+			} else if (temp == thmGetGuiValue()) {
 				diaUIConfig[32].type = UI_COLOUR;
 				diaUIConfig[36].type = UI_COLOUR;
 				diaUIConfig[40].type = UI_COLOUR;
+				diaUIConfig[44].type = UI_COLOUR;
 				diaSetColor(diaUIConfig, UICFG_BGCOL, gTheme->bgColor);
 				diaSetU64Color(diaUIConfig, UICFG_UICOL, gTheme->uiTextColor);
 				diaSetU64Color(diaUIConfig, UICFG_TXTCOL, gTheme->textColor);
 				diaSetU64Color(diaUIConfig, UICFG_SELCOL, gTheme->selTextColor);
 			} else {
-				diaUIConfig[28].type = UI_SPACER;
 				diaUIConfig[32].type = UI_SPACER;
 				diaUIConfig[36].type = UI_SPACER;
 				diaUIConfig[40].type = UI_SPACER;
+				diaUIConfig[44].type = UI_SPACER;
 			}
 
 			temp = !temp;
 	return 0;
 }
 
-static void guiShowUIConfig() {
+void guiShowUIConfig() {
 	curTheme = -1;
 
 	// configure the enumerations
-	const char* scrollSpeeds[] = {	_l(_STR_SLOW), _l(_STR_MEDIUM), _l(_STR_FAST), NULL };
-	const char* vmodeNames[] = {"AUTO", "PAL", "NTSC", NULL};
+	const char* scrollSpeeds[] = { _l(_STR_SLOW), _l(_STR_MEDIUM),	_l(_STR_FAST), NULL };
+	const char* vmodeNames[] = { "AUTO", "PAL", "NTSC", NULL };
 	diaSetEnum(diaUIConfig, UICFG_SCROLL, scrollSpeeds);
-	diaSetEnum(diaUIConfig, UICFG_THEME, (const char **)thmGetGuiList());
-	diaSetEnum(diaUIConfig, UICFG_LANG, (const char **)lngGetGuiList());
+	diaSetEnum(diaUIConfig, UICFG_THEME, (const char **) thmGetGuiList());
+	diaSetEnum(diaUIConfig, UICFG_LANG, (const char **) lngGetGuiList());
 	diaSetEnum(diaUIConfig, UICFG_VMODE, vmodeNames);
 
 	diaSetInt(diaUIConfig, UICFG_SCROLL, gScrollSpeed);
 	guiUIUpdater(1);
 	diaSetInt(diaUIConfig, UICFG_AUTOSORT, gAutosort);
 	diaSetInt(diaUIConfig, UICFG_AUTOREFRESH, gAutoRefresh);
+	diaSetInt(diaUIConfig, UICFG_INFOPAGE, gUseInfoScreen);
 	diaSetInt(diaUIConfig, UICFG_COVERART, gEnableArt);
 	diaSetInt(diaUIConfig, UICFG_WIDESCREEN, gWideScreen);
 	diaSetInt(diaUIConfig, UICFG_VMODE, gVMode);
 		}
 		diaGetInt(diaUIConfig, UICFG_AUTOSORT, &gAutosort);
 		diaGetInt(diaUIConfig, UICFG_AUTOREFRESH, &gAutoRefresh);
+		diaGetInt(diaUIConfig, UICFG_INFOPAGE, &gUseInfoScreen);
 		diaGetInt(diaUIConfig, UICFG_COVERART, &gEnableArt);
 		diaGetInt(diaUIConfig, UICFG_WIDESCREEN, &gWideScreen);
 		diaGetInt(diaUIConfig, UICFG_VMODE, &newVMode);
 	}
 }
 
-static void guiShowIPConfig() {
+void guiShowIPConfig() {
 	size_t i;
 	// upload current values
 	for (i = 0; i < 4; ++i) {
 }
 
 #ifdef VMC
-typedef struct {		// size = 76
-	int  VMC_status;	// 0=available, 1=busy
-	int  VMC_error;
-	int  VMC_progress;
+typedef struct { // size = 76
+	int VMC_status; // 0=available, 1=busy
+	int VMC_error;
+	int VMC_progress;
 	char VMC_msg[64];
-} statusVMCparam_t;
+}statusVMCparam_t;
 
 #define OPERATION_CREATE	0
 #define OPERATION_CREATING	1
 	int result = diaShowKeyb(text, maxLen);
 
 	if (result)
-		vmc_refresh = 1;
+	vmc_refresh = 1;
 
 	return result;
 }
 static int guiRefreshVMCConfig(item_list_t *support, char* name) {
 	int size = support->itemCheckVMC(name, 0);
 
-
 	if (size != -1) {
 		diaSetLabel(diaVMC, VMC_BUTTON_CREATE, _l(_STR_MODIFY));
 		diaSetLabel(diaVMC, VMC_STATUS, _l(_STR_VMC_FILE_EXISTS));
 
 		if (size == 8)
-			diaSetInt(diaVMC, VMC_SIZE, 0);
+		diaSetInt(diaVMC, VMC_SIZE, 0);
 		else if (size == 16)
-			diaSetInt(diaVMC, VMC_SIZE, 1);
+		diaSetInt(diaVMC, VMC_SIZE, 1);
 		else if (size == 32)
-			diaSetInt(diaVMC, VMC_SIZE, 2);
+		diaSetInt(diaVMC, VMC_SIZE, 2);
 		else if (size == 64)
-			diaSetInt(diaVMC, VMC_SIZE, 3);
+		diaSetInt(diaVMC, VMC_SIZE, 3);
 		else {
 			diaSetInt(diaVMC, VMC_SIZE, 0);
 			diaSetLabel(diaVMC, VMC_STATUS, _l(_STR_VMC_FILE_ERROR));
 			diaSetInt(diaVMC, VMC_PROGRESS, vmc_status.VMC_progress);
 
 			if (vmc_status.VMC_error != 0)
-				LOG("genvmc updater: %d\n", vmc_status.VMC_error);
+			LOG("genvmc updater: %d\n", vmc_status.VMC_error);
 
 			if (vmc_status.VMC_status == 0x00) {
 				diaSetLabel(diaVMC, VMC_BUTTON_CREATE, _l(_STR_OK));
 			}
 		}
 		else
-			LOG("status result: %d\n", result);
+		LOG("status result: %d\n", result);
 	}
 
 	return 0;
 	char vmc[32];
 
 	if (strlen(VMCName))
-		strncpy(vmc, VMCName, 32);
+	strncpy(vmc, VMCName, 32);
 	else {
 		if (validate)
-			return 1; // nothing to validate if no user input
+		return 1; // nothing to validate if no user input
 
 		char* startup = support->itemGetStartup(id);
 		snprintf(vmc, 32, "%s_%d", startup, slot);
 	diaSetEnabled(diaVMC, VMC_SIZE, 1);
 	diaSetInt(diaVMC, VMC_PROGRESS, 0);
 
-	const char* VMCSizes[] = { "8 Mb", "16 Mb", "32 Mb", "64 Mb", NULL };
+	const char* VMCSizes[] = {"8 Mb", "16 Mb", "32 Mb", "64 Mb", NULL};
 	diaSetEnum(diaVMC, VMC_SIZE, VMCSizes);
 	int size = guiRefreshVMCConfig(support, vmc);
 	diaSetString(diaVMC, VMC_NAME, vmc);
 				int sizeUI;
 				diaGetInt(diaVMC, VMC_SIZE, &sizeUI);
 				if (sizeUI == 1)
-					sizeUI = 16;
+				sizeUI = 16;
 				else if (sizeUI == 2)
-					sizeUI = 32;
+				sizeUI = 32;
 				else if (sizeUI == 3)
-					sizeUI = 64;
+				sizeUI = 64;
 				else
-					sizeUI = 8;
+				sizeUI = 8;
 
 				if (sizeUI != size) {
 					support->itemCheckVMC(vmc, sizeUI);
 					vmc_operation = OPERATION_CREATING;
 				}
 				else
-					break;
+				break;
 			}
 			else if (vmc_operation == OPERATION_ENDING) {
 				if (validate)
-					break; // directly close VMC config dialog
+				break; // directly close VMC config dialog
 
 				vmc_operation = OPERATION_END;
 			}
 		result = diaExecuteDialog(diaVMC, result, 1, &guiVMCUpdater);
 
 		if ((result == 0) && (vmc_operation == OPERATION_CREATE))
-			break;
-	} while (1);
+		break;
+	}while (1);
 
 	return result;
 }
 	char* startup = support->itemGetStartup(id);
 	compatMode = support->itemGetCompatibility(id, &dmaMode);
 
-	if(dmaMode != -1) {
-		const char* dmaModes[] = { "MDMA 0", "MDMA 1", "MDMA 2", "UDMA 0", "UDMA 1", "UDMA 2", "UDMA 3", "UDMA 4", "UDMA 5", "UDMA 6", NULL };
+	if (dmaMode != -1) {
+		const char* dmaModes[] = { "MDMA 0", "MDMA 1", "MDMA 2", "UDMA 0",	"UDMA 1", "UDMA 2", "UDMA 3", "UDMA 4", "UDMA 5", "UDMA 6",	NULL };
 		diaSetEnum(diaCompatConfig, COMPAT_MODE_BASE + COMPAT_MODE_COUNT, dmaModes);
 		diaSetInt(diaCompatConfig, COMPAT_MODE_BASE + COMPAT_MODE_COUNT, dmaMode);
-	}
-	else {
+	} else {
 		const char* dmaModes[] = { NULL };
 		diaSetEnum(diaCompatConfig, COMPAT_MODE_BASE + COMPAT_MODE_COUNT, dmaModes);
 		diaSetInt(diaCompatConfig, COMPAT_MODE_BASE + COMPAT_MODE_COUNT, 0);
 		configRemoveVMC(startup, mode, 1);
 #endif
 		support->itemSetCompatibility(id, 0, 7);
-		saveConfig(CONFIG_COMPAT|CONFIG_DNAS|CONFIG_VMC, 1);
+		saveConfig(CONFIG_COMPAT | CONFIG_DNAS | CONFIG_VMC, 1);
 	} else if (result > 0) { // test button pressed or save button
 		compatMode = 0;
 		for (i = 0; i < COMPAT_MODE_COUNT; ++i) {
 #endif
 
 		if (result == COMPAT_SAVE)
-			saveConfig(CONFIG_COMPAT|CONFIG_DNAS|CONFIG_VMC, 1);
+			saveConfig(CONFIG_COMPAT | CONFIG_DNAS | CONFIG_VMC, 1);
 	}
 
 	return result;
 
 int guiDeferUpdate(struct gui_update_t *op) {
 	WaitSema(gSemaId);
-	
-	struct gui_update_list_t* up = (struct gui_update_list_t*)malloc(sizeof(struct gui_update_list_t));
+
+	struct gui_update_list_t* up = (struct gui_update_list_t*) malloc(sizeof(struct gui_update_list_t));
 	up->item = op;
 	up->next = NULL;
-	
+
 	if (!gUpdateList) {
 		gUpdateList = up;
 		gUpdateEnd = gUpdateList;
 	submenu_list_t* result = NULL;
 
 	switch (item->type) {
-		case GUI_INIT_DONE:
-			gInitComplete = 1;
-			break;
-			
-		case GUI_OP_ADD_MENU:
-			menuAppendItem(item->menu.menu);
-			break;
-			
-		case GUI_OP_APPEND_MENU:
-			result = submenuAppendItem(item->menu.subMenu,
-									   item->submenu.icon_id,
-									   item->submenu.text,
-									   item->submenu.id,
-									   item->submenu.text_id);
+	case GUI_INIT_DONE:
+		gInitComplete = 1;
+		break;
 
-			if (!item->menu.menu->submenu)
-				item->menu.menu->submenu = *item->menu.subMenu;
+	case GUI_OP_ADD_MENU:
+		menuAppendItem(item->menu.menu);
+		break;
 
-			if (item->submenu.selected)
-				item->menu.menu->current = result;
+	case GUI_OP_APPEND_MENU:
+		result = submenuAppendItem(item->menu.subMenu, item->submenu.icon_id,
+				item->submenu.text, item->submenu.id, item->submenu.text_id);
 
-			break;
-			
-		case GUI_OP_SELECT_MENU:
-			menuSetSelectedItem(item->menu.menu);
-			screenHandler = &mainScreenHandler;
-			break;
-			
-		case GUI_OP_CLEAR_SUBMENU:
-			submenuDestroy(item->menu.subMenu);
-			item->menu.menu->submenu = NULL;
-			item->menu.menu->current = NULL;
-			item->menu.menu->pagestart = NULL;
-			break;
-			
-		case GUI_OP_SORT:
-			submenuSort(item->menu.subMenu);
-			item->menu.menu->pagestart = NULL;
+		if (!item->menu.menu->submenu)
 			item->menu.menu->submenu = *item->menu.subMenu;
-			break;
-		
-		case GUI_OP_ADD_HINT:
-			// append the hint list in the menu item
-			menuAddHint(item->menu.menu, item->hint.text_id, item->hint.icon_id);
-			break;
-			
-		default:
-			LOG("GUI: ??? (%d)\n", item->type);
+
+		if (item->submenu.selected)
+			item->menu.menu->current = result;
+
+		break;
+
+	case GUI_OP_SELECT_MENU:
+		menuSetSelectedItem(item->menu.menu);
+		screenHandler = &screenHandlers[GUI_SCREEN_MAIN];
+		break;
+
+	case GUI_OP_CLEAR_SUBMENU:
+		submenuDestroy(item->menu.subMenu);
+		item->menu.menu->submenu = NULL;
+		item->menu.menu->current = NULL;
+		item->menu.menu->pagestart = NULL;
+		break;
+
+	case GUI_OP_SORT:
+		submenuSort(item->menu.subMenu);
+		item->menu.menu->pagestart = NULL;
+		item->menu.menu->submenu = *item->menu.subMenu;
+		break;
+
+	case GUI_OP_ADD_HINT:
+		// append the hint list in the menu item
+		menuAddHint(item->menu.menu, item->hint.text_id, item->hint.icon_id);
+		break;
+
+	default:
+		LOG("GUI: ??? (%d)\n", item->type);
 	}
 }
 
 static void guiHandleDeferredOps(void) {
 	// TODO: Fit into the given time interval, skip rest of operations of over limit
-	
+
 	while (gUpdateList) {
 		WaitSema(gSemaId);
-		
+
 		guiHandleOp(gUpdateList->item);
-		
+
 		if (gNetworkStartup < 0) {
 			gNetworkStartup = 0;
 			guiMsgBox(_l(_STR_NETWORK_STARTUP_ERROR), 0, NULL);
 		}
-		
+
 		struct gui_update_list_t* td = gUpdateList;
 		gUpdateList = gUpdateList->next;
-		
+
 		free(td);
-		
+
 		gCompletedOps++;
-			
+
 		SignalSema(gSemaId);
 	}
-	
+
 	gUpdateEnd = NULL;
 }
 
 static int bfadeout = 0x0;
 static void guiDrawBusy() {
 	if (gTheme->loadingIcon) {
-		GSTEXTURE* texture = thmGetTexture(LOAD0_ICON + (gFrameCounter >> 1) % gTheme->loadingIconCount);
+		GSTEXTURE* texture = thmGetTexture(LOAD0_ICON + guiFrameId % gTheme->loadingIconCount);
 		if (texture && texture->Mem) {
 			u64 mycolor = GS_SETREG_RGBA(0x080, 0x080, 0x080, bfadeout);
 			rmDrawPixmap(texture, gTheme->loadingIcon->posX, gTheme->loadingIcon->posY, gTheme->loadingIcon->aligned, gTheme->loadingIcon->width, gTheme->loadingIcon->height, mycolor);
 
 static int wfadeout = 0x0150;
 static void guiRenderGreeting() {
-	rmUnclip();
-	
 	int fade = wfadeout > 0xFF ? 0xFF : wfadeout;
+	u64 mycolor = GS_SETREG_RGBA(0x10, 0x10, 0x10, fade >> 1);
+	rmDrawRect(0, 0, ALIGN_NONE, DIM_INF, DIM_INF, mycolor);
+	/* char introtxt[255];
+	 snprintf(introtxt, 255, _l(_STR_OUL_VER), USBLD_VERSION);
+	 fntRenderString(screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, introtxt, GS_SETREG_RGBA(0x060, 0x060, 0x060, wfadeout));
+	 */
 
-	u64 mycolor = GS_SETREG_RGBA(0x10, 0x10, 0x10, fade >> 1);
-	
-	
-	rmDrawRect(0, 0, ALIGN_NONE, DIM_INF, DIM_INF, mycolor);
-	/*
-	char introtxt[255];
-	snprintf(introtxt, 255, _l(_STR_OUL_VER), USBLD_VERSION);
-	fntRenderString(screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, introtxt, GS_SETREG_RGBA(0x060, 0x060, 0x060, wfadeout));
-	*/
-	
 	GSTEXTURE* logo = thmGetTexture(LOGO_PICTURE);
-	
 	if (logo) {
 		mycolor = GS_SETREG_RGBA(0x080, 0x080, 0x080, fade >> 1);
 		rmDrawPixmap(logo, screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, DIM_UNDEF, DIM_UNDEF, mycolor);
 	}
-	
+
 	return;
 }
 
 static float mix(float a, float b, float t) {
-	return (1.0-t)*a + t*b; 
-};
+	return (1.0 - t) * a + t * b;
+}
 
 static float fade(float t) {
-	return fadetbl[(int)(t*FADE_SIZE)];
-};
+	return fadetbl[(int) (t * FADE_SIZE)];
+}
 
 // The same as mix, but with 8 (2*4) values mixed at once
 static void VU0MixVec(VU_VECTOR *a, VU_VECTOR *b, float mix, VU_VECTOR* res) {
 	asm (
-		"lqc2	vf1, 0(%0)\n" // load the first vector
-		"lqc2	vf2, 0(%1)\n" // load the second vector
-		"lw	$2, 0(%2)\n" // load value from ptr to reg
-		"qmtc2	$2, vf3\n" // load the mix value from reg to VU
-		"vaddw.x vf5, vf00, vf00\n" // vf5.x = 1
-		"vsub.x vf4x, vf5x, vf3x\n" // subtract 1 - vf3,x, store the result in vf4.x
-		"vmulax.xyzw ACC, vf1, vf3x\n" // multiply vf1 by vf3.x, store the result in ACC
-		"vmaddx.xyzw vf1, vf2, vf4x\n" // multiply vf2 by vf4.x add ACC, store the result in vf1
-		"sqc2	vf1, 0(%3)\n" // transfer the result in acc to the ee
-		: : "r" (a), "r" (b), "r" (&mix), "r" (res)
+			"lqc2	vf1, 0(%0)\n" // load the first vector
+			"lqc2	vf2, 0(%1)\n" // load the second vector
+			"lw	$2, 0(%2)\n" // load value from ptr to reg
+			"qmtc2	$2, vf3\n" // load the mix value from reg to VU
+			"vaddw.x vf5, vf00, vf00\n" // vf5.x = 1
+			"vsub.x vf4x, vf5x, vf3x\n" // subtract 1 - vf3,x, store the result in vf4.x
+			"vmulax.xyzw ACC, vf1, vf3x\n" // multiply vf1 by vf3.x, store the result in ACC
+			"vmaddx.xyzw vf1, vf2, vf4x\n" // multiply vf2 by vf4.x add ACC, store the result in vf1
+			"sqc2	vf1, 0(%3)\n" // transfer the result in acc to the ee
+			: : "r" (a), "r" (b), "r" (&mix), "r" (res)
 	);
 }
 
 static float guiCalcPerlin(float x, float y, float z) {
 	// Taken from: http://people.opera.com/patrickl/experiments/canvas/plasma/perlin-noise-classical.js
 	// By Sean McCullough
-	
+
 	// Find unit grid cell containing point 
-	int X = floor(x); 
-	int Y = floor(y); 
-	int Z = floor(z); 
+	int X = floor(x);
+	int Y = floor(y);
+	int Z = floor(z);
 
 	// Get relative xyz coordinates of point within that cell 
-	x = x - X; 
-	y = y - Y; 
-	z = z - Z; 
+	x = x - X;
+	y = y - Y;
+	z = z - Z;
 
 	// Wrap the integer cells at 255 (smaller integer period can be introduced here) 
-	X = X & 255; 
-	Y = Y & 255; 
+	X = X & 255;
+	Y = Y & 255;
 	Z = Z & 255;
 
 	// Calculate a set of eight hashed gradient indices 
-	int gi000 = pperm[X+pperm[Y+pperm[Z]]] % 12; 
-	int gi001 = pperm[X+pperm[Y+pperm[Z+1]]] % 12; 
-	int gi010 = pperm[X+pperm[Y+1+pperm[Z]]] % 12; 
-	int gi011 = pperm[X+pperm[Y+1+pperm[Z+1]]] % 12; 
-	int gi100 = pperm[X+1+pperm[Y+pperm[Z]]] % 12; 
-	int gi101 = pperm[X+1+pperm[Y+pperm[Z+1]]] % 12; 
-	int gi110 = pperm[X+1+pperm[Y+1+pperm[Z]]] % 12; 
-	int gi111 = pperm[X+1+pperm[Y+1+pperm[Z+1]]] % 12; 
+	int gi000 = pperm[X + pperm[Y + pperm[Z]]] % 12;
+	int gi001 = pperm[X + pperm[Y + pperm[Z + 1]]] % 12;
+	int gi010 = pperm[X + pperm[Y + 1 + pperm[Z]]] % 12;
+	int gi011 = pperm[X + pperm[Y + 1 + pperm[Z + 1]]] % 12;
+	int gi100 = pperm[X + 1 + pperm[Y + pperm[Z]]] % 12;
+	int gi101 = pperm[X + 1 + pperm[Y + pperm[Z + 1]]] % 12;
+	int gi110 = pperm[X + 1 + pperm[Y + 1 + pperm[Z]]] % 12;
+	int gi111 = pperm[X + 1 + pperm[Y + 1 + pperm[Z + 1]]] % 12;
 
 	// The gradients of each corner are now: 
 	// g000 = grad3[gi000]; 
 	vec.y = y;
 	vec.z = z;
 	vec.w = 1;
-	
+
 	VU_VECTOR a, b;
-	
+
 	// float n000 
-	a.x = Vu0DotProduct(&pgrad3[gi000], &vec); 
-	
+	a.x = Vu0DotProduct(&pgrad3[gi000], &vec);
+
 	vec.y -= 1;
-	
+
 	// float n010
-	a.z  = Vu0DotProduct(&pgrad3[gi010], &vec); 
-	
+	a.z = Vu0DotProduct(&pgrad3[gi010], &vec);
+
 	vec.x -= 1;
-	
+
 	//float n110 
-	b.z = Vu0DotProduct(&pgrad3[gi110], &vec); 
-	
+	b.z = Vu0DotProduct(&pgrad3[gi110], &vec);
+
 	vec.y += 1;
-	
+
 	// float n100 
-	b.x = Vu0DotProduct(&pgrad3[gi100], &vec); 
-	
+	b.x = Vu0DotProduct(&pgrad3[gi100], &vec);
+
 	vec.z -= 1;
-	
+
 	// float n101
-	b.y = Vu0DotProduct(&pgrad3[gi101], &vec); 
-	
+	b.y = Vu0DotProduct(&pgrad3[gi101], &vec);
+
 	vec.y -= 1;
-	
+
 	// float n111 
-	b.w = Vu0DotProduct(&pgrad3[gi111], &vec); 
-	
+	b.w = Vu0DotProduct(&pgrad3[gi111], &vec);
+
 	vec.x += 1;
-	
+
 	// float n011 
-	a.w = Vu0DotProduct(&pgrad3[gi011], &vec); 
-	
+	a.w = Vu0DotProduct(&pgrad3[gi011], &vec);
+
 	vec.y += 1;
-	
+
 	// float n001 
-	a.y = Vu0DotProduct(&pgrad3[gi001], &vec); 
-	
-	
+	a.y = Vu0DotProduct(&pgrad3[gi001], &vec);
+
 	// Compute the fade curve value for each of x, y, z 
 	float u = fade(x);
 	float v = fade(y);
 	float w = fade(z);
-	
+
 	// TODO: Low priority... This could be done on VU0 (xyzw for the first 4 mixes)
 	// The result in sw
 	// Interpolate along x the contributions from each of the corners 
 	VU_VECTOR rv;
 	VU0MixVec(&b, &a, u, &rv);
-	
+
 	// TODO: The VU0MixVec could as well mix the results (as follows) - might improve performance...
 	// Interpolate the four results along y 
-	float nxy0 = mix(rv.x, rv.z, v); 
+	float nxy0 = mix(rv.x, rv.z, v);
 	float nxy1 = mix(rv.y, rv.w, v);
 	// Interpolate the two last results along z 
-	float nxyz = mix(nxy0, nxy1, w); 
+	float nxyz = mix(nxy0, nxy1, w);
 
-	return nxyz; 
+	return nxyz;
 }
 
 static float dir = 0.02;
 static float perz = -100;
 static int pery = 0;
-static unsigned char curbgColor[3] = {0,0,0};
+static unsigned char curbgColor[3] = { 0, 0, 0 };
 
 static int cdirection(unsigned char a, unsigned char b) {
 	if (a == b)
 	if (pery >= PLASMA_H) {
 		pery = 0;
 		perz += dir;
-		
+
 		if (perz > 100.0f || perz < -100.0f)
 			dir = -dir;
 	}
 
 	for (y = pery; y < ymax; y++) {
 		for (x = 0; x < PLASMA_W; x++) {
-			u32 fper = guiCalcPerlin((float)(2*x) / PLASMA_W, (float)(2*y) / PLASMA_H, perz) * 0x080 + 0x080;
+			u32 fper = guiCalcPerlin((float) (2 * x) / PLASMA_W, (float) (2 * y) / PLASMA_H, perz) * 0x080 + 0x080;
 
 			*buf = GS_SETREG_RGBA(
-				(u32)(fper * curbgColor[0]) >> 8,
-				(u32)(fper * curbgColor[1]) >> 8,
-				(u32)(fper * curbgColor[2]) >> 8,
-				0x080);
+					(u32)(fper * curbgColor[0]) >> 8,
+					(u32)(fper * curbgColor[1]) >> 8,
+					(u32)(fper * curbgColor[2]) >> 8,
+					0x080);
 
 			++buf;
 		}
 
 	if (gInitComplete)
 		wfadeout--;
-	
+
 	if (!pending) {
 		if (bfadeout > 0x0)
 			bfadeout -= 0x08;
 	// is init still running?
 	if (wfadeout > 0)
 		guiRenderGreeting();
-	
+
 	if (bfadeout > 0)
 		guiDrawBusy();
-	
+
 #ifdef __DEBUG
 	// fps meter
 	char fps[10];
-	
+
 	if (time_since_last != 0)
 		snprintf(fps, 10, "%3.1f FPS", 1000.0f / (float) time_since_last);
 	else
 		snprintf(fps, 10, "---- FPS");
-	
+
 	fntRenderString(FNT_DEFAULT, screenWidth - 60, gTheme->usedHeight - 20, ALIGN_CENTER, fps, GS_SETREG_RGBA(0x060, 0x060, 0x060, 0x060));
-	
+
 	snprintf(fps, 10, "%3d ms", time_render);
-	
+
 	fntRenderString(FNT_DEFAULT, screenWidth - 60, gTheme->usedHeight - 45, ALIGN_CENTER, fps, GS_SETREG_RGBA(0x060, 0x060, 0x060, 0x060));
 #endif
 }
 
 static void guiReadPads() {
 	if (readPads())
-		gInactiveFrames = 0;
+		guiInactiveFrames = 0;
 	else
-		gInactiveFrames++;
+		guiInactiveFrames++;
 }
 
-static void guiMainRender() {
-	menuDrawStatic();
-}
-
-static void guiMainHandleInput() {
-	if(getKey(KEY_LEFT)){
-		menuPrevH();
-	} else if(getKey(KEY_RIGHT)){
-		menuNextH();
-	} else if(getKey(KEY_UP)) {
-		menuPrevV();
-	} else if(getKey(KEY_DOWN)){
-		menuNextV();
-	} else if(getKey(KEY_L1)) {
-		menuPrevPage();
-	} else if(getKey(KEY_R1)){
-		menuNextPage();
-	} else if (getKeyOn(KEY_L2)) { // home
-		menuFirstPage();
-	} else if (getKeyOn(KEY_R2)) { // end
-		menuLastPage();
-	}
-
-	menu_item_t* cur = menuGetCurrent();
-	if (!cur)
-		return;
-	
-	if(getKeyOn(KEY_START)) {
-		// reinit main menu - show/hide items valid in the active context
-		guiInitMainMenu();
-		screenHandlerTarget = &menuScreenHandler;
-	} else if(getKeyOn(KEY_SELECT)){
-		cur->refresh(cur);
-	} else if(getKeyOn(KEY_CROSS)){
-		menuItemExecButton(cur->execCross);
-	} else if(getKeyOn(KEY_TRIANGLE)){
-		menuItemExecButton(cur->execTriangle);
-	} else if(getKeyOn(KEY_CIRCLE)){
-		menuItemExecButton(cur->execCircle);
-	} else if(getKeyOn(KEY_SQUARE)){
-		menuItemExecButton(cur->execSquare);
-	}
-}
-
-static void guiMenuRender() {
-	guiDrawBGPlasma();
-
-	if (!mainMenu)
-		return;
-	
-	// draw the animated menu
-	if (!mainMenuCurrent)
-		mainMenuCurrent = mainMenu;
-	
-	// iterate few items behind, few items forward
-	submenu_list_t* it = mainMenu;
-
-	// coordinate, etc
-	// we start at center
-	int w, h;
-	
-	int spacing = 25;
-	int count = 0; int sitem = 0;
-	
-	// calculate the number of items
-	for (; it; count++, it=it->next) {
-		if (it == mainMenuCurrent)
-			sitem = count;
-	}
-	
-	it = mainMenu;
-	
-	const char* text = NULL;
-	int x = screenWidth >> 1;
-	int y = (gTheme->usedHeight >> 1) - (spacing * (count / 2));
-	
-	int fadeout = 0x080;
-	int cp = 0; // current position
-	
-	for (;it; it = it->next, cp++) {
-		text = submenuItemGetText(&it->item);
-		fntCalcDimensions(FNT_DEFAULT, text, &w, &h);
-		
-		fadeout = 0x080 - abs(sitem - cp) * 0x20;
-		
-		if (fadeout < 0x20)
-			fadeout = 0x20;
-		
-		u64 colour = gTheme->textColor;
-		if (it == mainMenuCurrent)
-			colour = gTheme->selTextColor;
-		
-		// render, advance
-		// TODO: Theme support for main menu (font)
-		fntRenderString(FNT_DEFAULT, x - (w >> 1), y, ALIGN_NONE, text, colour);
-		
-		y += spacing;
-	}
-}
-
-static void guiMenuHandleInput() {
-	if (!mainMenu)
-		return;
-	
-	if (!mainMenuCurrent)
-		mainMenuCurrent = mainMenu;
-	
-	if (getKey(KEY_UP)) {
-		if (mainMenuCurrent->prev)
-			mainMenuCurrent = mainMenuCurrent->prev;
-		else	// rewind to the last item
-			while (mainMenuCurrent->next)
-				mainMenuCurrent = mainMenuCurrent->next;
-	}
-	
-	if (getKey(KEY_DOWN)) {
-		if (mainMenuCurrent->next)
-			mainMenuCurrent = mainMenuCurrent->next;
-		else
-			mainMenuCurrent = mainMenu;
-	}
-	
-	if (getKeyOn(KEY_CROSS)) {
-		// execute the item via looking at the id of it
-		int id = mainMenuCurrent->item.id;
-		
-		if (id == 1) {
-			guiShowConfig();
-		} else if (id == 2) {
-			guiShowUIConfig();
-		} else if (id == 3) {
-			// ipconfig
-			guiShowIPConfig();
-		} else if (id == 7) {
-			saveConfig(CONFIG_OPL | CONFIG_VMODE, 1);
-		} else if (id == 8) {
-			guiShowAbout();
-		} else if (id == 9) {
-			guiExecExit();
-		} else if (id == 11) {
-			sysPowerOff();
-		} else {
-			if (gMenuExecHook)
-				gMenuExecHook(id);
-		}
-		
-		// so the exit press wont propagate twice
-		guiReadPads();
-	}
-	
-	if(getKeyOn(KEY_START) || getKeyOn(KEY_CIRCLE)) {
-		if (gAPPStartMode || gETHStartMode || gUSBStartMode || gHDDStartMode)
-			screenHandlerTarget = &mainScreenHandler;
-	}
-		
-}
-
-// renders the screen and handles inputs. Also handles screen transitions between
-// numerous screen handlers.
-// for now we only have left-to right screen transition
+// renders the screen and handles inputs. Also handles screen transitions between numerous
+// screen handlers. For now we only have left-to right screen transition
 static void guiShow() {
 	// is there a transmission effect going on or are
 	// we in a normal rendering state?
 	if (screenHandlerTarget) {
 		// advance the effect
-		
+
 		// render the old screen, transposed
 		rmSetTransposition(-transition, 0);
 		screenHandler->renderScreen();
-		
+
 		// render new screen transposed again
 		rmSetTransposition(screenWidth - transition, 0);
 		screenHandlerTarget->renderScreen();
-		
+
 		// reset transposition to zero
-		rmSetTransposition(0,0);
-		
+		rmSetTransposition(0, 0);
+
 		// move the transition indicator forward
 		transition += min(transition / 2, (screenWidth - transition) / 2) + 1;
-		
+
 		if (transition > screenWidth) {
 			transition = 0;
 			screenHandler = screenHandlerTarget;
 			screenHandlerTarget = NULL;
 		}
-	} else // render with the set screen handler
+	} else
+		// render with the set screen handler
 		screenHandler->renderScreen();
 }
 
 void guiMainLoop(void) {
 	while (!gTerminate) {
 		guiStartFrame();
-		
-		cacheNextFrame(gInactiveFrames);
-		
+
 		// Read the pad states to prepare for input processing in the screen handler
 		guiReadPads();
-		
+
 		// handle inputs and render screen
 		if (wfadeout < 0x0FF)
 			guiShow();
-		
+
 		// Render overlaying gui thingies :)
 		guiDrawOverlays();
-		
+
 		// handle deferred operations
 		guiHandleDeferredOps();
-		
+
 		if (gFrameHook)
 			gFrameHook();
-		
+
 		guiEndFrame();
-		
+
 		// if not transiting, handle input
 		// done here so we can use renderman if needed
 		if (!screenHandlerTarget && screenHandler)
 	gFrameHook = cback;
 }
 
-void guiSetMenuFillHook(gui_menufill_callback_t cback) {
-	gMenuFillHook = cback;
-}
-
-void guiSetMenuExecHook(gui_menuexec_callback_t cback) {
-	gMenuExecHook = cback;
+void guiSwitchScreen(int target) {
+	screenHandlerTarget = &screenHandlers[target];
 }
 
 struct gui_update_t *guiOpCreate(gui_op_type_t type) {
-	struct gui_update_t *op = (struct gui_update_t *)malloc(sizeof(struct gui_update_t));
+	struct gui_update_t *op = (struct gui_update_t *) malloc(
+			sizeof(struct gui_update_t));
 	memset(op, 0, sizeof(struct gui_update_t));
 	op->type = type;
 	return op;
 }
 
-
 void guiUpdateScrollSpeed(void) {
 	// sanitize the settings
 	if ((gScrollSpeed < 0) || (gScrollSpeed > 2))
 
 int guiMsgBox(const char* text, int addAccept, struct UIItem *ui) {
 	int terminate = 0;
-	while(!terminate) {
+	while (!terminate) {
 		guiStartFrame();
-		
+
 		readPads();
 
-		if(getKeyOn(KEY_CIRCLE)) 
+		if (getKeyOn(KEY_CIRCLE))
 			terminate = 1;
-		else if(getKeyOn(KEY_CROSS))
+		else if (getKeyOn(KEY_CROSS))
 			terminate = 2;
-		
+
 		if (ui)
 			diaRenderUI(ui, screenHandler->inMenu, NULL, 0);
 		else
 			guiShow();
-		
+
 		rmDrawRect(0, 0, ALIGN_NONE, DIM_INF, DIM_INF, gColDarker);
 
 		rmDrawLine(50, 75, screenWidth - 50, 75, gColWhite);
 		rmDrawLine(50, 410, screenWidth - 50, 410, gColWhite);
-		
-		fntRenderString(FNT_DEFAULT, screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, text, gTheme->textColor);
-		fntRenderString(FNT_DEFAULT, 500, 417, ALIGN_NONE, _l(_STR_O_BACK), gTheme->selTextColor);
+
+		fntRenderString(FNT_DEFAULT, screenWidth >> 1, gTheme->usedHeight >> 1,
+				ALIGN_CENTER, text, gTheme->textColor);
+		fntRenderString(FNT_DEFAULT, 500, 417, ALIGN_NONE, _l(_STR_O_BACK),
+				gTheme->selTextColor);
 		if (addAccept)
-			fntRenderString(FNT_DEFAULT, 70, 417, ALIGN_NONE, _l(_STR_X_ACCEPT), gTheme->selTextColor);
+			fntRenderString(FNT_DEFAULT, 70, 417, ALIGN_NONE,
+					_l(_STR_X_ACCEPT), gTheme->selTextColor);
 
 		guiEndFrame();
 	}
 	return terminate - 1;
 }
 
-void guiHandleDefferedIO(int *ptr, const unsigned char* message, int type, void *data) {
+void guiHandleDefferedIO(int *ptr, const unsigned char* message, int type,
+		void *data) {
 	ioPutRequest(type, data);
-	
-	while(*ptr) {
+
+	while (*ptr) {
 		guiStartFrame();
-		
+
 		readPads();
-		
+
 		guiShow();
-		
+
 		rmDrawRect(0, 0, ALIGN_NONE, DIM_INF, DIM_INF, gColDarker);
-		
-		fntRenderString(FNT_DEFAULT, screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, message, gTheme->textColor);
-		
+
+		fntRenderString(FNT_DEFAULT, screenWidth >> 1, gTheme->usedHeight >> 1,
+				ALIGN_CENTER, message, gTheme->textColor);
+
 		// so the io status icon will be rendered
 		guiDrawOverlays();
-		
+
 		guiEndFrame();
 	}
 }
 
 void guiRenderTextScreen(const unsigned char* message) {
 	guiStartFrame();
-	
+
 	guiShow();
-	
+
 	rmDrawRect(0, 0, ALIGN_NONE, DIM_INF, DIM_INF, gColDarker);
-	
-	fntRenderString(FNT_DEFAULT, screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, message, gTheme->textColor);
-	
+
+	fntRenderString(FNT_DEFAULT, screenWidth >> 1, gTheme->usedHeight >> 1,
+			ALIGN_CENTER, message, gTheme->textColor);
+
 	// so the io status icon will be rendered
 	guiDrawOverlays();
-	
+
 	guiEndFrame();
 }
 static config_set_t* hddGetConfig(int id) {
 	config_set_t* config = configAlloc(0, NULL, NULL);
 	hdl_game_info_t* game = &hddGames->games[id];
-
+	configSetStr(config, "#Format", "HDL");
+	/*if (game->disctype == 0x12)
+		configSetStr(config, "#Media", "CD");
+	else
+		configSetStr(config, "#Media", "DVD");*/ // TODO must ask Jimmi/Polo about the HDL header format
+	configSetStr(config, "#Name", game->name);
+	configSetStr(config, "#Startup", game->startup);
+	configSetInt(config, "#Size", game->total_size_in_kb / 1024);
 	return config;
 }
 
-static int hddGetImage(char* folder, int addSep, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
+static int hddGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
 	char path[255];
-	if (addSep)
+	if (isRelative)
 		sprintf(path, "%s%s/%s_%s", hddPrefix, folder, value, suffix);
 	else
-		sprintf(path, "%s%s%s_%s", hddPrefix, folder, value, suffix);
+		sprintf(path, "%s%s_%s", folder, value, suffix);
 	return texDiscoverLoad(resultTex, path, -1, psm);
 }
 
 #endif
 
 static item_list_t hddGameList = {
-		HDD_MODE, 0, 0, 0, "HDD Games", _STR_HDD_GAMES, &hddInit, &hddNeedsUpdate, &hddUpdateGameList,
+		HDD_MODE, 0, 0, MENU_MIN_INACTIVE_FRAMES, "HDD Games", _STR_HDD_GAMES, &hddInit, &hddNeedsUpdate, &hddUpdateGameList,
 #ifdef __CHILDPROOF
 		&hddGetGameCount, &hddGetGame, &hddGetGameName, &hddGetGameNameLength, &hddGetGameStartup, NULL, NULL, &hddGetGameCompatibility,
 #else
 	"Video mode",
 	"Dialog color",
 	"Selected color",
+	"Display info page",
 };
 
 static int guiLangID = 0;
 #include "include/fntsys.h"
 #include "include/lang.h"
 #include "include/themes.h"
+#include "include/pad.h"
+#include "include/gui.h"
+#include "include/system.h"
+#include "include/ioman.h"
 #include "assert.h"
 
+#define MENU_SETTINGS		0
+#define MENU_GFX_SETTINGS	1
+#define MENU_IP_CONFIG		2
+#define MENU_SAVE_CHANGES	3
+#define MENU_START_HDL		4
+#define MENU_ABOUT			5
+#define MENU_EXIT			6
+#define MENU_POWER_OFF		7
+
 // global menu variables
-static menu_list_t *menu;
-static menu_list_t *selected_item;
+static menu_list_t* menu;
+static menu_list_t* selected_item;
+
+static int itemIdConfig;
+static config_set_t* itemConfig;
+
+// "main menu submenu"
+static submenu_list_t* mainMenu;
+// active item in the main menu
+static submenu_list_t* mainMenuCurrent;
+
+static void menuInitMainMenu() {
+	if (mainMenu)
+		submenuDestroy(&mainMenu);
+
+	// initialize the menu
+#ifndef __CHILDPROOF
+	submenuAppendItem(&mainMenu, -1, NULL, MENU_SETTINGS, _STR_SETTINGS);
+	submenuAppendItem(&mainMenu, -1, NULL, MENU_GFX_SETTINGS, _STR_GFX_SETTINGS);
+	submenuAppendItem(&mainMenu, -1, NULL, MENU_IP_CONFIG, _STR_IPCONFIG);
+	submenuAppendItem(&mainMenu, -1, NULL, MENU_SAVE_CHANGES, _STR_SAVE_CHANGES);
+	if (gHDDStartMode) // enabled at all?
+		submenuAppendItem(&mainMenu, -1, NULL, MENU_START_HDL, _STR_STARTHDL);
+#endif
+	submenuAppendItem(&mainMenu, -1, NULL, MENU_ABOUT, _STR_ABOUT);
+	submenuAppendItem(&mainMenu, -1, NULL, MENU_EXIT, _STR_EXIT);
+	submenuAppendItem(&mainMenu, -1, NULL, MENU_POWER_OFF, _STR_POWEROFF);
+
+	mainMenuCurrent = mainMenu;
+}
 
 // -------------------------------------------------------------------------------------------
 // ---------------------------------------- Menu manipulation --------------------------------
 void menuInit() {
 	menu = NULL;
 	selected_item = NULL;
+	itemIdConfig = -1;
+	itemConfig = NULL;
+	mainMenu = NULL;
+	mainMenuCurrent = NULL;
+	menuInitMainMenu();
 }
 
 void menuEnd() {
 		
 		free(td);
 	}
+
+	submenuDestroy(&mainMenu);
+
+	if (itemConfig)
+		configFree(itemConfig);
 }
 
 static menu_list_t* AllocMenuItem(menu_item_t* item) {
 	it->item.text = text;
 	it->item.text_id = text_id;
 	it->item.id = id;
-	it->item.config = NULL;
 	
 	// no cache entry yet
 	int size = gTheme->gameCacheCount * sizeof(int);
 }
 
 static void submenuDestroyItem(submenu_list_t* submenu) {
-	if (submenu->item.config)
-		configFree(submenu->item.config);
-
 	free(submenu->item.cache_id);
 	free(submenu->item.cache_uid);
 
 	*submenu = NULL;
 }
 
+void menuAddHint(menu_item_t *menu, int text_id, int icon_id) {
+	// allocate a new hint item
+	menu_hint_item_t* hint = malloc(sizeof(menu_hint_item_t));
+
+	hint->text_id = text_id;
+	hint->icon_id = icon_id;
+	hint->next = NULL;
+
+	if (menu->hints) {
+		menu_hint_item_t* top = menu->hints;
+
+		// rewind to end
+		for (; top->next; top = top->next);
+
+		top->next = hint;
+	} else {
+		menu->hints = hint;
+	}
+}
+
+void menuRemoveHints(menu_item_t *menu) {
+	while (menu->hints) {
+		menu_hint_item_t* hint = menu->hints;
+		menu->hints = hint->next;
+		free(hint);
+	}
+}
+
+void menuInitHints(menu_item_t* menu) {
+	menuRemoveHints(menu);
+
+	menuAddHint(menu, _STR_SETTINGS, START_ICON);
+	item_list_t *support = menu->userdata;
+	if (!support->enabled)
+		menuAddHint(menu, _STR_START_DEVICE, CROSS_ICON);
+	else {
+		menuAddHint(menu, _STR_RUN, CROSS_ICON);
+		if (support->itemGetCompatibility)
+			menuAddHint(menu, _STR_COMPAT_SETTINGS, TRIANGLE_ICON);
+		if (gEnableDandR) {
+			if (support->itemRename)
+				menuAddHint(menu, _STR_RENAME, CIRCLE_ICON);
+			if (support->itemDelete)
+				menuAddHint(menu, _STR_DELETE, SQUARE_ICON);
+		}
+	}
+}
+
 char *menuItemGetText(menu_item_t* it) {
 	if (it->text_id >= 0)
 		return _l(it->text_id);
 	*submenu = head;
 }
 
-void menuNextH() {
+static void menuNextH() {
 	if (!selected_item) {
 		selected_item = menu;
 	}
 	}
 }
 
-void menuPrevH() {
+static void menuPrevH() {
 	if (!selected_item) {
 		selected_item = menu;
 	}
 	}
 }
 
-void menuNextV() {
+static void menuNextV() {
 	if (!selected_item)
 		return;
 	
 		selected_item->item->current = cur->next;
 }
 
-void menuPrevV() {
+static void menuPrevV() {
 	if (!selected_item)
 		return;
 
 	}
 }
 
-void menuNextPage() {
+static void menuNextPage() {
 	if (!selected_item)
 		return;
 
 	}
 }
 
-void menuPrevPage() {
+static void menuPrevPage() {
 	if (!selected_item)
 		return;
 
 	}
 }
 
-void menuFirstPage() {
+static void menuFirstPage() {
 	if (!selected_item)
 		return;
 
 	selected_item->item->current = selected_item->item->submenu;
 }
 
-void menuLastPage() {
+static void menuLastPage() {
 	if (!selected_item)
 		return;
 
 	}
 }
 
-menu_item_t* menuGetCurrent() {
-	if (!selected_item)
-		return NULL;
-
-	return selected_item->item;
-}
-
-void menuItemExecButton(void (*execActionButton)(menu_item_t *self, int id)) {
-	if (execActionButton) {
-
-		// selected submenu id. default -1 = no selection
-		int subid = -1;
-
-		submenu_list_t *cur = selected_item->item->current;
-		if (cur)
-			subid = cur->item.id;
-
-		execActionButton(selected_item->item, subid);
-	}
-}
-
 void menuSetSelectedItem(menu_item_t* item) {
 	menu_list_t* itm = menu;
 	
 	}
 }
 
-void menuDrawStatic() {
+void menuRenderMenu() {
+	guiDrawBGPlasma();
+
+	if (!mainMenu)
+		return;
+
+	// draw the animated menu
+	if (!mainMenuCurrent)
+		mainMenuCurrent = mainMenu;
+
+	submenu_list_t* it = mainMenu;
+
+	// calculate the number of items
+	int count = 0; int sitem = 0;
+	for (; it; count++, it=it->next) {
+		if (it == mainMenuCurrent)
+			sitem = count;
+	}
+
+	int spacing = 25;
+	int y = (gTheme->usedHeight >> 1) - (spacing * (count >> 1));
+	int cp = 0; // current position
+	for (it = mainMenu; it; it = it->next, cp++) {
+		// render, advance
+		// TODO: Theme support for main menu (font)
+		fntRenderString(FNT_DEFAULT, 320, y, ALIGN_CENTER, submenuItemGetText(&it->item), (cp == sitem) ? gTheme->selTextColor : gTheme->textColor);
+
+		y += spacing;
+	}
+}
+
+void menuHandleInputMenu() {
+	if (!mainMenu)
+		return;
+
+	if (!mainMenuCurrent)
+		mainMenuCurrent = mainMenu;
+
+	if (getKey(KEY_UP)) {
+		if (mainMenuCurrent->prev)
+			mainMenuCurrent = mainMenuCurrent->prev;
+		else	// rewind to the last item
+			while (mainMenuCurrent->next)
+				mainMenuCurrent = mainMenuCurrent->next;
+	}
+
+	if (getKey(KEY_DOWN)) {
+		if (mainMenuCurrent->next)
+			mainMenuCurrent = mainMenuCurrent->next;
+		else
+			mainMenuCurrent = mainMenu;
+	}
+
+	if (getKeyOn(KEY_CROSS)) {
+		// execute the item via looking at the id of it
+		int id = mainMenuCurrent->item.id;
+
+		if (id == MENU_SETTINGS) {
+			guiShowConfig();
+		} else if (id == MENU_GFX_SETTINGS) {
+			guiShowUIConfig();
+		} else if (id == MENU_IP_CONFIG) {
+			guiShowIPConfig();
+		} else if (id == MENU_SAVE_CHANGES) {
+			saveConfig(CONFIG_OPL | CONFIG_VMODE, 1);
+		} else if (id == MENU_START_HDL) {
+			handleHdlSrv();
+		} else if (id == MENU_ABOUT) {
+			guiShowAbout();
+		} else if (id == MENU_EXIT) {
+			sysExecExit();
+		} else if (id == MENU_POWER_OFF) {
+			sysPowerOff();
+		}
+
+		// so the exit press wont propagate twice
+		readPads();
+	}
+
+	if(getKeyOn(KEY_START) || getKeyOn(KEY_CIRCLE)) {
+		if (gAPPStartMode || gETHStartMode || gUSBStartMode || gHDDStartMode)
+			guiSwitchScreen(GUI_SCREEN_MAIN);
+	}
+}
+
+void menuRenderMain() {
 	if (!menu)
 		return;
-	
-	if (!selected_item) 
+
+	if (!selected_item)
 		selected_item = menu;
 
 	if (!selected_item->item->current)
 
 	submenu_list_t* cur = selected_item->item->current;
 
-	theme_element_t* elem = gTheme->elems;
+	theme_element_t* elem = gTheme->mainElems.first;
 	while (elem) {
 		if (elem->drawElem)
-			elem->drawElem(selected_item, cur, elem);
+			elem->drawElem(selected_item, cur, NULL, elem);
 
 		elem = elem->next;
 	}
 }
 
-void menuAddHint(menu_item_t *menu, int text_id, int icon_id) {
-	// allocate a new hint item
-	menu_hint_item_t* hint = malloc(sizeof(menu_hint_item_t));
-	
-	hint->text_id = text_id;
-	hint->icon_id = icon_id;
-	hint->next = NULL;