Fix for space and punctuation characters. These one are weak/neutral and should not...
[open-ps2-loader.git] / src / gui.c
blob78e32a71f84808a10a80adc9fceea8ea7a4719b8
1 /*
2 Copyright 2010, Volca
3 Licenced under Academic Free License version 3.0
4 Review OpenUsbLd README & LICENSE files for further details.
5 */
7 #include "include/usbld.h"
8 #include "include/gui.h"
9 #include "include/renderman.h"
10 #include "include/menusys.h"
11 #include "include/fntsys.h"
12 #include "include/ioman.h"
13 #include "include/lang.h"
14 #include "include/themes.h"
15 #include "include/pad.h"
16 #include "include/util.h"
17 #include "include/config.h"
18 #include "include/system.h"
20 #include <stdlib.h>
21 #include <libvux.h>
23 static int gScheduledOps;
24 static int gCompletedOps;
25 static int gTerminate;
26 static int gInitComplete;
28 static gui_callback_t gFrameHook;
30 static s32 gSemaId;
31 static s32 gGUILockSemaId;
32 static ee_sema_t gQueueSema;
34 static int screenWidth;
35 static float wideScreenScale;
36 static int screenHeight;
38 // forward decl.
39 static void guiShow();
41 #ifdef __DEBUG
43 #include <timer.h>
45 #define CLOCKS_PER_MILISEC 147456
47 // debug version displays an FPS meter
48 static u32 curtime = 0;
49 static u32 time_since_last = 0;
50 static u32 time_render = 0;
52 #endif
54 struct gui_update_list_t {
55 struct gui_update_t* item;
56 struct gui_update_list_t* next;
59 struct gui_update_list_t *gUpdateList;
60 struct gui_update_list_t *gUpdateEnd;
62 typedef struct {
63 void (*handleInput)(void);
64 void (*renderScreen)(void);
65 short inMenu;
66 } gui_screen_handler_t;
68 static gui_screen_handler_t screenHandlers[] = {{ &menuHandleInputMain, &menuRenderMain, 0 },
69 { &menuHandleInputMenu, &menuRenderMenu, 1 },
70 { &menuHandleInputInfo, &menuRenderInfo, 1 } };
72 // default screen handler (menu screen)
73 static gui_screen_handler_t *screenHandler = &screenHandlers[GUI_SCREEN_MENU];
75 // screen transition handling
76 static gui_screen_handler_t *screenHandlerTarget = NULL;
77 static int transIndex, transMax, transitionX, transitionY;
79 // Helper perlin noise data
80 #define PLASMA_H 32
81 #define PLASMA_W 32
82 #define PLASMA_ROWS_PER_FRAME 6
83 #define FADE_SIZE 256
85 static GSTEXTURE gBackgroundTex;
86 static int pperm[512];
87 static float fadetbl[FADE_SIZE + 1];
89 static VU_VECTOR pgrad3[12] = {{ 1, 1, 0, 1 }, { -1, 1, 0, 1 }, { 1, -1, 0, 1 }, { -1, -1, 0, 1 },
90 { 1, 0, 1, 1 }, { -1, 0, 1, 1 }, { 1, 0, -1, 1 }, { -1, 0, -1, 1 },
91 { 0, 1, 1, 1 }, { 0, -1, 1, 1 }, { 0, 1, -1, 1 }, { 0, -1, -1, 1 } };
93 void guiReloadScreenExtents() {
94 rmGetScreenExtents(&screenWidth, &screenHeight);
97 void guiInit(void) {
98 guiFrameId = 0;
99 guiInactiveFrames = 0;
101 gFrameHook = NULL;
102 gTerminate = 0;
103 gInitComplete = 0;
104 gScheduledOps = 0;
105 gCompletedOps = 0;
107 gUpdateList = NULL;
108 gUpdateEnd = NULL;
110 gQueueSema.init_count = 1;
111 gQueueSema.max_count = 1;
112 gQueueSema.option = 0;
114 gSemaId = CreateSema(&gQueueSema);
115 gGUILockSemaId = CreateSema(&gQueueSema);
117 guiReloadScreenExtents();
119 // background texture - for perlin
120 gBackgroundTex.Width = PLASMA_W;
121 gBackgroundTex.Height = PLASMA_H;
122 gBackgroundTex.Mem = memalign(128, PLASMA_W * PLASMA_H * 4);
123 gBackgroundTex.PSM = GS_PSM_CT32;
124 gBackgroundTex.Filter = GS_FILTER_LINEAR;
125 gBackgroundTex.Vram = 0;
126 gBackgroundTex.VramClut = 0;
127 gBackgroundTex.Clut = NULL;
129 wideScreenScale = 1.0f;
131 // Precalculate the values for the perlin noise plasma
132 int i;
133 for (i = 0; i < 256; ++i) {
134 pperm[i] = rand() % 256;
135 pperm[i + 256] = pperm[i];
138 for (i = 0; i <= FADE_SIZE; ++i) {
139 float t = (float) (i) / FADE_SIZE;
141 fadetbl[i] = t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
145 void guiEnd() {
146 if (gBackgroundTex.Mem)
147 free(gBackgroundTex.Mem);
149 DeleteSema(gSemaId);
150 DeleteSema(gGUILockSemaId);
153 void guiLock(void) {
154 WaitSema(gGUILockSemaId);
157 void guiUnlock(void) {
158 SignalSema(gGUILockSemaId);
161 void guiStartFrame(void) {
162 #ifdef __DEBUG
163 u32 newtime = cpu_ticks() / CLOCKS_PER_MILISEC;
164 time_since_last = newtime - curtime;
165 curtime = newtime;
166 #endif
168 guiLock();
169 rmStartFrame();
170 guiFrameId++;
173 void guiEndFrame(void) {
174 guiUnlock();
175 rmFlush();
177 #ifdef __DEBUG
178 u32 newtime = cpu_ticks() / CLOCKS_PER_MILISEC;
179 time_render = newtime - curtime;
180 #endif
182 rmEndFrame();
185 void guiShowAbout() {
186 char OPLVersion[64];
187 snprintf(OPLVersion, 64, _l(_STR_OUL_VER), USBLD_VERSION);
189 #ifdef VMC
190 strcat(OPLVersion, " VMC");
191 #endif
192 #ifdef __RTL
193 strcat(OPLVersion, " RTL");
194 #endif
195 #ifdef __CHILDPROOF
196 strcat(OPLVersion, " CHILDPROOF");
197 #endif
199 diaSetLabel(diaAbout, 1, OPLVersion);
201 diaExecuteDialog(diaAbout, -1, 1, NULL);
204 void guiShowConfig() {
205 // configure the enumerations
206 const char* deviceNames[] = { _l(_STR_USB_GAMES), _l(_STR_NET_GAMES), _l(_STR_HDD_GAMES), NULL };
207 const char* deviceModes[] = { _l(_STR_OFF), _l(_STR_MANUAL), _l(_STR_AUTO), NULL };
209 diaSetEnum(diaConfig, CFG_DEFDEVICE, deviceNames);
210 diaSetEnum(diaConfig, CFG_USBMODE, deviceModes);
211 diaSetEnum(diaConfig, CFG_HDDMODE, deviceModes);
212 diaSetEnum(diaConfig, CFG_ETHMODE, deviceModes);
213 diaSetEnum(diaConfig, CFG_APPMODE, deviceModes);
215 diaSetInt(diaConfig, CFG_DEBUG, gDisableDebug);
216 diaSetString(diaConfig, CFG_EXITTO, gExitPath);
217 diaSetInt(diaConfig, CFG_DANDROP, gEnableDandR);
218 diaSetInt(diaConfig, CFG_HDDSPINDOWN, gHDDSpindown);
219 diaSetInt(diaConfig, CFG_CHECKUSBFRAG, gCheckUSBFragmentation);
220 diaSetInt(diaConfig, CFG_USBDELAY, gUSBDelay);
221 diaSetString(diaConfig, CFG_USBPREFIX, gUSBPrefix);
222 diaSetInt(diaConfig, CFG_LASTPLAYED, gRememberLastPlayed);
223 diaSetInt(diaConfig, CFG_DEFDEVICE, gDefaultDevice);
224 diaSetInt(diaConfig, CFG_USBMODE, gUSBStartMode);
225 diaSetInt(diaConfig, CFG_HDDMODE, gHDDStartMode);
226 diaSetInt(diaConfig, CFG_ETHMODE, gETHStartMode);
227 diaSetInt(diaConfig, CFG_APPMODE, gAPPStartMode);
229 int ret = diaExecuteDialog(diaConfig, -1, 1, NULL);
230 if (ret) {
231 diaGetString(diaConfig, CFG_EXITTO, gExitPath);
232 diaGetInt(diaConfig, CFG_DEBUG, &gDisableDebug);
233 diaGetInt(diaConfig, CFG_DANDROP, &gEnableDandR);
234 diaGetInt(diaConfig, CFG_HDDSPINDOWN, &gHDDSpindown);
235 diaGetInt(diaConfig, CFG_CHECKUSBFRAG, &gCheckUSBFragmentation);
236 diaGetInt(diaConfig, CFG_USBDELAY, &gUSBDelay);
237 diaGetString(diaConfig, CFG_USBPREFIX, gUSBPrefix);
238 diaGetInt(diaConfig, CFG_LASTPLAYED, &gRememberLastPlayed);
239 diaGetInt(diaConfig, CFG_DEFDEVICE, &gDefaultDevice);
240 diaGetInt(diaConfig, CFG_USBMODE, &gUSBStartMode);
241 diaGetInt(diaConfig, CFG_HDDMODE, &gHDDStartMode);
242 diaGetInt(diaConfig, CFG_ETHMODE, &gETHStartMode);
243 diaGetInt(diaConfig, CFG_APPMODE, &gAPPStartMode);
245 applyConfig(-1, -1, gVMode, gVSync);
249 static int curTheme = -1;
251 static int guiUIUpdater(int modified) {
252 if (modified) {
253 int temp;
254 diaGetInt(diaUIConfig, UICFG_THEME, &temp);
255 if (temp != curTheme) {
256 curTheme = temp;
257 if (temp == 0) {
258 diaUIConfig[32].type = UI_COLOUR; // Must be correctly set before doing the diaS/GetColor !!
259 diaUIConfig[36].type = UI_COLOUR;
260 diaUIConfig[40].type = UI_COLOUR;
261 diaUIConfig[44].type = UI_COLOUR;
262 diaSetColor(diaUIConfig, UICFG_BGCOL, gDefaultBgColor);
263 diaSetColor(diaUIConfig, UICFG_UICOL, gDefaultUITextColor);
264 diaSetColor(diaUIConfig, UICFG_TXTCOL, gDefaultTextColor);
265 diaSetColor(diaUIConfig, UICFG_SELCOL, gDefaultSelTextColor);
266 } else if (temp == thmGetGuiValue()) {
267 diaUIConfig[32].type = UI_COLOUR;
268 diaUIConfig[36].type = UI_COLOUR;
269 diaUIConfig[40].type = UI_COLOUR;
270 diaUIConfig[44].type = UI_COLOUR;
271 diaSetColor(diaUIConfig, UICFG_BGCOL, gTheme->bgColor);
272 diaSetU64Color(diaUIConfig, UICFG_UICOL, gTheme->uiTextColor);
273 diaSetU64Color(diaUIConfig, UICFG_TXTCOL, gTheme->textColor);
274 diaSetU64Color(diaUIConfig, UICFG_SELCOL, gTheme->selTextColor);
275 } else {
276 diaUIConfig[32].type = UI_SPACER;
277 diaUIConfig[36].type = UI_SPACER;
278 diaUIConfig[40].type = UI_SPACER;
279 diaUIConfig[44].type = UI_SPACER;
282 temp = !temp;
283 diaSetEnabled(diaUIConfig, UICFG_BGCOL, temp);
284 diaSetEnabled(diaUIConfig, UICFG_UICOL, temp);
285 diaSetEnabled(diaUIConfig, UICFG_TXTCOL, temp);
286 diaSetEnabled(diaUIConfig, UICFG_SELCOL, temp);
290 return 0;
293 void guiShowUIConfig() {
294 curTheme = -1;
296 // configure the enumerations
297 const char* scrollSpeeds[] = { _l(_STR_SLOW), _l(_STR_MEDIUM), _l(_STR_FAST), NULL };
298 const char* vmodeNames[] = { "AUTO", "PAL", "NTSC", NULL };
299 diaSetEnum(diaUIConfig, UICFG_SCROLL, scrollSpeeds);
300 diaSetEnum(diaUIConfig, UICFG_THEME, (const char **) thmGetGuiList());
301 diaSetEnum(diaUIConfig, UICFG_LANG, (const char **) lngGetGuiList());
302 diaSetEnum(diaUIConfig, UICFG_VMODE, vmodeNames);
304 diaSetInt(diaUIConfig, UICFG_SCROLL, gScrollSpeed);
305 diaSetInt(diaUIConfig, UICFG_THEME, thmGetGuiValue());
306 diaSetInt(diaUIConfig, UICFG_LANG, lngGetGuiValue());
307 guiUIUpdater(1);
308 diaSetInt(diaUIConfig, UICFG_AUTOSORT, gAutosort);
309 diaSetInt(diaUIConfig, UICFG_AUTOREFRESH, gAutoRefresh);
310 diaSetInt(diaUIConfig, UICFG_INFOPAGE, gUseInfoScreen);
311 diaSetInt(diaUIConfig, UICFG_COVERART, gEnableArt);
312 diaSetInt(diaUIConfig, UICFG_WIDESCREEN, gWideScreen);
313 diaSetInt(diaUIConfig, UICFG_VMODE, gVMode);
314 diaSetInt(diaUIConfig, UICFG_VSYNC, gVSync);
316 int ret = diaExecuteDialog(diaUIConfig, -1, 1, guiUIUpdater);
317 if (ret) {
318 int themeID = -1, langID = -1, newVMode = gVMode, newVSync = gVSync;
319 diaGetInt(diaUIConfig, UICFG_SCROLL, &gScrollSpeed);
320 diaGetInt(diaUIConfig, UICFG_LANG, &langID);
321 diaGetInt(diaUIConfig, UICFG_THEME, &themeID);
322 if (themeID == 0) {
323 diaGetColor(diaUIConfig, UICFG_BGCOL, gDefaultBgColor);
324 diaGetColor(diaUIConfig, UICFG_UICOL, gDefaultUITextColor);
325 diaGetColor(diaUIConfig, UICFG_TXTCOL, gDefaultTextColor);
326 diaGetColor(diaUIConfig, UICFG_SELCOL, gDefaultSelTextColor);
328 diaGetInt(diaUIConfig, UICFG_AUTOSORT, &gAutosort);
329 diaGetInt(diaUIConfig, UICFG_AUTOREFRESH, &gAutoRefresh);
330 diaGetInt(diaUIConfig, UICFG_INFOPAGE, &gUseInfoScreen);
331 diaGetInt(diaUIConfig, UICFG_COVERART, &gEnableArt);
332 diaGetInt(diaUIConfig, UICFG_WIDESCREEN, &gWideScreen);
333 diaGetInt(diaUIConfig, UICFG_VMODE, &newVMode);
334 diaGetInt(diaUIConfig, UICFG_VSYNC, &newVSync);
336 applyConfig(themeID, langID, newVMode, newVSync);
340 void guiShowIPConfig() {
341 size_t i;
342 // upload current values
343 for (i = 0; i < 4; ++i) {
344 diaSetInt(diaIPConfig, 2 + i, ps2_ip[i]);
345 diaSetInt(diaIPConfig, 6 + i, ps2_netmask[i]);
346 diaSetInt(diaIPConfig, 10 + i, ps2_gateway[i]);
347 diaSetInt(diaIPConfig, 14 + i, pc_ip[i]);
350 diaSetInt(diaIPConfig, 18, gPCPort);
351 diaSetString(diaIPConfig, 19, gPCShareName);
352 diaSetString(diaIPConfig, 20, gPCUserName);
353 diaSetString(diaIPConfig, 21, gPCPassword);
355 // show dialog
356 if (diaExecuteDialog(diaIPConfig, -1, 1, NULL)) {
357 // Ok pressed, store values
358 for (i = 0; i < 4; ++i) {
359 diaGetInt(diaIPConfig, 2 + i, &ps2_ip[i]);
360 diaGetInt(diaIPConfig, 6 + i, &ps2_netmask[i]);
361 diaGetInt(diaIPConfig, 10 + i, &ps2_gateway[i]);
362 diaGetInt(diaIPConfig, 14 + i, &pc_ip[i]);
365 diaGetInt(diaIPConfig, 18, &gPCPort);
366 diaGetString(diaIPConfig, 19, gPCShareName);
367 diaGetString(diaIPConfig, 20, gPCUserName);
368 diaGetString(diaIPConfig, 21, gPCPassword);
369 gIPConfigChanged = 1;
371 applyConfig(-1, -1, gVMode, gVSync);
375 int guiShowKeyboard(char* value, int maxLength) {
376 char tmp[maxLength];
377 strncpy(tmp, value, maxLength);
379 int result = diaShowKeyb(tmp, maxLength);
380 if (result) {
381 strncpy(value, tmp, maxLength);
382 value[maxLength - 1] = '\0';
385 return result;
388 #ifdef VMC
389 typedef struct { // size = 76
390 int VMC_status; // 0=available, 1=busy
391 int VMC_error;
392 int VMC_progress;
393 char VMC_msg[64];
394 }statusVMCparam_t;
396 #define OPERATION_CREATE 0
397 #define OPERATION_CREATING 1
398 #define OPERATION_ABORTING 2
399 #define OPERATION_ENDING 3
400 #define OPERATION_END 4
402 static short vmc_refresh;
403 static int vmc_operation;
404 static statusVMCparam_t vmc_status;
406 int guiVmcNameHandler(char* text, int maxLen) {
407 int result = diaShowKeyb(text, maxLen);
409 if (result)
410 vmc_refresh = 1;
412 return result;
415 static int guiRefreshVMCConfig(item_list_t *support, char* name) {
416 int size = support->itemCheckVMC(name, 0);
418 if (size != -1) {
419 diaSetLabel(diaVMC, VMC_BUTTON_CREATE, _l(_STR_MODIFY));
420 diaSetLabel(diaVMC, VMC_STATUS, _l(_STR_VMC_FILE_EXISTS));
422 if (size == 8)
423 diaSetInt(diaVMC, VMC_SIZE, 0);
424 else if (size == 16)
425 diaSetInt(diaVMC, VMC_SIZE, 1);
426 else if (size == 32)
427 diaSetInt(diaVMC, VMC_SIZE, 2);
428 else if (size == 64)
429 diaSetInt(diaVMC, VMC_SIZE, 3);
430 else {
431 diaSetInt(diaVMC, VMC_SIZE, 0);
432 diaSetLabel(diaVMC, VMC_STATUS, _l(_STR_VMC_FILE_ERROR));
435 if (gEnableDandR) {
436 diaSetEnabled(diaVMC, VMC_SIZE, 1);
437 diaVMC[20].type = UI_SPLITTER;
439 else {
440 diaSetEnabled(diaVMC, VMC_SIZE, 0);
441 diaVMC[20].type = UI_TERMINATOR;
444 else {
445 diaSetLabel(diaVMC, VMC_BUTTON_CREATE, _l(_STR_CREATE));
446 diaSetLabel(diaVMC, VMC_STATUS, _l(_STR_VMC_FILE_NEW));
448 diaSetInt(diaVMC, VMC_SIZE, 0);
449 diaSetEnabled(diaVMC, VMC_SIZE, 1);
450 diaVMC[20].type = UI_TERMINATOR;
453 return size;
456 static int guiVMCUpdater(int modified) {
457 if (vmc_refresh) {
458 vmc_refresh = 0;
459 return VMC_REFRESH;
462 if ((vmc_operation == OPERATION_CREATING) || (vmc_operation == OPERATION_ABORTING)) {
463 int result = fileXioDevctl("genvmc:", 0xC0DE0003, NULL, 0, (void*) &vmc_status, sizeof(vmc_status));
464 if (result == 0) {
465 diaSetLabel(diaVMC, VMC_STATUS, vmc_status.VMC_msg);
466 diaSetInt(diaVMC, VMC_PROGRESS, vmc_status.VMC_progress);
468 if (vmc_status.VMC_error != 0)
469 LOG("genvmc updater: %d\n", vmc_status.VMC_error);
471 if (vmc_status.VMC_status == 0x00) {
472 diaSetLabel(diaVMC, VMC_BUTTON_CREATE, _l(_STR_OK));
473 vmc_operation = OPERATION_ENDING;
474 return VMC_BUTTON_CREATE;
477 else
478 LOG("status result: %d\n", result);
481 return 0;
484 static int guiShowVMCConfig(int id, item_list_t *support, char *VMCName, int slot, int validate) {
485 int result = validate ? VMC_BUTTON_CREATE : 0;
486 char vmc[32];
488 if (strlen(VMCName))
489 strncpy(vmc, VMCName, 32);
490 else {
491 if (validate)
492 return 1; // nothing to validate if no user input
494 char* startup = support->itemGetStartup(id);
495 snprintf(vmc, 32, "%s_%d", startup, slot);
498 vmc_refresh = 0;
499 vmc_operation = OPERATION_CREATE;
500 diaSetEnabled(diaVMC, VMC_NAME, 1);
501 diaSetEnabled(diaVMC, VMC_SIZE, 1);
502 diaSetInt(diaVMC, VMC_PROGRESS, 0);
504 const char* VMCSizes[] = {"8 Mb", "16 Mb", "32 Mb", "64 Mb", NULL};
505 diaSetEnum(diaVMC, VMC_SIZE, VMCSizes);
506 int size = guiRefreshVMCConfig(support, vmc);
507 diaSetString(diaVMC, VMC_NAME, vmc);
509 do {
510 if (result == VMC_BUTTON_CREATE) {
511 if (vmc_operation == OPERATION_CREATE) { // User start creation of VMC
512 int sizeUI;
513 diaGetInt(diaVMC, VMC_SIZE, &sizeUI);
514 if (sizeUI == 1)
515 sizeUI = 16;
516 else if (sizeUI == 2)
517 sizeUI = 32;
518 else if (sizeUI == 3)
519 sizeUI = 64;
520 else
521 sizeUI = 8;
523 if (sizeUI != size) {
524 support->itemCheckVMC(vmc, sizeUI);
526 diaSetEnabled(diaVMC, VMC_NAME, 0);
527 diaSetEnabled(diaVMC, VMC_SIZE, 0);
528 diaSetLabel(diaVMC, VMC_BUTTON_CREATE, _l(_STR_ABORT));
529 vmc_operation = OPERATION_CREATING;
531 else
532 break;
534 else if (vmc_operation == OPERATION_ENDING) {
535 if (validate)
536 break; // directly close VMC config dialog
538 vmc_operation = OPERATION_END;
540 else if (vmc_operation == OPERATION_END) { // User closed creation dialog of VMC
541 break;
543 else if (vmc_operation == OPERATION_CREATING) { // User canceled creation of VMC
544 fileXioDevctl("genvmc:", 0xC0DE0002, NULL, 0, NULL, 0);
545 vmc_operation = OPERATION_ABORTING;
548 else if (result == VMC_BUTTON_DELETE) {
549 if (guiMsgBox(_l(_STR_DELETE_WARNING), 1, diaVMC)) {
550 support->itemCheckVMC(vmc, -1);
551 diaSetString(diaVMC, VMC_NAME, "");
552 break;
555 else if (result == VMC_REFRESH) { // User changed the VMC name
556 diaGetString(diaVMC, VMC_NAME, vmc);
557 size = guiRefreshVMCConfig(support, vmc);
560 result = diaExecuteDialog(diaVMC, result, 1, &guiVMCUpdater);
562 if ((result == 0) && (vmc_operation == OPERATION_CREATE))
563 break;
564 } while (1);
566 return result;
569 #endif
571 int guiAltStartupNameHandler(char* text, int maxLen) {
572 int i;
574 int result = diaShowKeyb(text, maxLen);
575 if (result) {
576 for (i = 0; text[i]; i++) {
577 if (text[i] > 96 && text[i] < 123)
578 text[i] -= 32;
582 return result;
585 int guiShowCompatConfig(int id, item_list_t *support, config_set_t* configSet) {
586 int dmaMode = 7; // defaulting to UDMA 4
587 if (support->haveCompatibilityMode == COMPAT_FULL) {
588 configGetInt(configSet, CONFIG_ITEM_DMA, &dmaMode);
589 const char* dmaModes[] = { "MDMA 0", "MDMA 1", "MDMA 2", "UDMA 0", "UDMA 1", "UDMA 2", "UDMA 3", "UDMA 4", "UDMA 5", "UDMA 6", NULL };
590 diaSetEnum(diaCompatConfig, COMPAT_MODE_BASE + COMPAT_MODE_COUNT, dmaModes);
591 diaSetInt(diaCompatConfig, COMPAT_MODE_BASE + COMPAT_MODE_COUNT, dmaMode);
592 } else {
593 const char* dmaModes[] = { NULL };
594 diaSetEnum(diaCompatConfig, COMPAT_MODE_BASE + COMPAT_MODE_COUNT, dmaModes);
595 diaSetInt(diaCompatConfig, COMPAT_MODE_BASE + COMPAT_MODE_COUNT, 0);
598 diaSetLabel(diaCompatConfig, COMPAT_GAME, support->itemGetName(id));
600 int compatMode = 0;
601 configGetInt(configSet, CONFIG_ITEM_COMPAT, &compatMode);
602 int i, result = -1;
603 for (i = 0; i < COMPAT_MODE_COUNT; ++i)
604 diaSetInt(diaCompatConfig, COMPAT_MODE_BASE + i, (compatMode & (1 << i)) > 0 ? 1 : 0);
606 // Find out the current game ID
607 char hexid[32];
608 configGetStrCopy(configSet, CONFIG_ITEM_DNAS, hexid);
609 diaSetString(diaCompatConfig, COMPAT_GAMEID, hexid);
611 char altStartup[32];
612 configGetStrCopy(configSet, CONFIG_ITEM_ALTSTARTUP, altStartup);
613 diaSetString(diaCompatConfig, COMPAT_ALTSTARTUP, altStartup);
615 #ifdef VMC
616 char vmc1[32];
617 configGetVMC(configSet, vmc1, 0);
618 diaSetLabel(diaCompatConfig, COMPAT_VMC1_DEFINE, vmc1);
620 char vmc2[32]; // required as diaSetLabel use pointer to value
621 configGetVMC(configSet, vmc2, 1);
622 diaSetLabel(diaCompatConfig, COMPAT_VMC2_DEFINE, vmc2);
623 #endif
625 // show dialog
626 do {
627 #ifdef VMC
628 if (strlen(vmc1))
629 diaSetLabel(diaCompatConfig, COMPAT_VMC1_ACTION, _l(_STR_RESET));
630 else
631 diaSetLabel(diaCompatConfig, COMPAT_VMC1_ACTION, _l(_STR_USE_GENERIC));
632 if (strlen(vmc2))
633 diaSetLabel(diaCompatConfig, COMPAT_VMC2_ACTION, _l(_STR_RESET));
634 else
635 diaSetLabel(diaCompatConfig, COMPAT_VMC2_ACTION, _l(_STR_USE_GENERIC));
636 #endif
638 result = diaExecuteDialog(diaCompatConfig, result, 1, NULL);
640 if (result == COMPAT_LOADFROMDISC) {
641 char hexDiscID[15];
642 if (sysGetDiscID(hexDiscID) >= 0)
643 diaSetString(diaCompatConfig, COMPAT_GAMEID, hexDiscID);
644 else
645 guiMsgBox(_l(_STR_ERROR_LOADING_ID), 0, NULL);
647 #ifdef VMC
648 else if (result == COMPAT_VMC1_DEFINE) {
649 if(guiShowVMCConfig(id, support, vmc1, 0, 0))
650 diaGetString(diaVMC, VMC_NAME, vmc1);
651 } else if (result == COMPAT_VMC2_DEFINE) {
652 if(guiShowVMCConfig(id, support, vmc2, 1, 0))
653 diaGetString(diaVMC, VMC_NAME, vmc2);
654 } else if (result == COMPAT_VMC1_ACTION) {
655 if (strlen(vmc1))
656 vmc1[0] = '\0';
657 else
658 snprintf(vmc1, 32, "generic_%d", 0);
659 } else if (result == COMPAT_VMC2_ACTION) {
660 if (strlen(vmc2))
661 vmc2[0] = '\0';
662 else
663 snprintf(vmc2, 32, "generic_%d", 1);
665 #endif
666 } while (result >= COMPAT_NOEXIT);
668 if (result == COMPAT_REMOVE) {
669 configRemoveKey(configSet, CONFIG_ITEM_DMA);
670 configRemoveKey(configSet, CONFIG_ITEM_COMPAT);
671 configRemoveKey(configSet, CONFIG_ITEM_DNAS);
672 configRemoveKey(configSet, CONFIG_ITEM_ALTSTARTUP);
673 #ifdef VMC
674 configRemoveVMC(configSet, 0);
675 configRemoveVMC(configSet, 1);
676 #endif
677 menuSaveConfig();
678 } else if (result > 0) { // test button pressed or save button
679 compatMode = 0;
680 for (i = 0; i < COMPAT_MODE_COUNT; ++i) {
681 int mdpart;
682 diaGetInt(diaCompatConfig, COMPAT_MODE_BASE + i, &mdpart);
683 compatMode |= (mdpart ? 1 : 0) << i;
686 if (support->haveCompatibilityMode == COMPAT_FULL) {
687 diaGetInt(diaCompatConfig, COMPAT_MODE_BASE + COMPAT_MODE_COUNT, &dmaMode);
688 if (dmaMode != 7)
689 configSetInt(configSet, CONFIG_ITEM_DMA, dmaMode);
690 else
691 configRemoveKey(configSet, CONFIG_ITEM_DMA);
694 if (compatMode != 0)
695 configSetInt(configSet, CONFIG_ITEM_COMPAT, compatMode);
696 else
697 configRemoveKey(configSet, CONFIG_ITEM_COMPAT);
699 diaGetString(diaCompatConfig, COMPAT_GAMEID, hexid);
700 if (hexid[0] != '\0')
701 configSetStr(configSet, CONFIG_ITEM_DNAS, hexid);
703 diaGetString(diaCompatConfig, COMPAT_ALTSTARTUP, altStartup);
704 if (altStartup[0] != '\0')
705 configSetStr(configSet, CONFIG_ITEM_ALTSTARTUP, altStartup);
706 else
707 configRemoveKey(configSet, CONFIG_ITEM_ALTSTARTUP);
709 #ifdef VMC
710 configSetVMC(configSet, vmc1, 0);
711 configSetVMC(configSet, vmc2, 1);
712 guiShowVMCConfig(id, support, vmc1, 0, 1);
713 guiShowVMCConfig(id, support, vmc2, 1, 1);
714 #endif
716 if (result == COMPAT_SAVE)
717 menuSaveConfig();
720 return result;
723 int guiGetOpCompleted(int opid) {
724 return gCompletedOps > opid;
727 int guiDeferUpdate(struct gui_update_t *op) {
728 WaitSema(gSemaId);
730 struct gui_update_list_t* up = (struct gui_update_list_t*) malloc(sizeof(struct gui_update_list_t));
731 up->item = op;
732 up->next = NULL;
734 if (!gUpdateList) {
735 gUpdateList = up;
736 gUpdateEnd = gUpdateList;
737 } else {
738 gUpdateEnd->next = up;
739 gUpdateEnd = up;
742 SignalSema(gSemaId);
744 return gScheduledOps++;
747 static void guiHandleOp(struct gui_update_t* item) {
748 submenu_list_t* result = NULL;
750 switch (item->type) {
751 case GUI_INIT_DONE:
752 gInitComplete = 1;
753 break;
755 case GUI_OP_ADD_MENU:
756 menuAppendItem(item->menu.menu);
757 break;
759 case GUI_OP_APPEND_MENU:
760 result = submenuAppendItem(item->menu.subMenu, item->submenu.icon_id,
761 item->submenu.text, item->submenu.id, item->submenu.text_id);
763 if (!item->menu.menu->submenu) { // first subitem in list
764 item->menu.menu->submenu = result;
765 item->menu.menu->current = result;
766 item->menu.menu->pagestart = result;
767 } else if (item->submenu.selected) { // remember last game feat.
768 item->menu.menu->current = result;
769 item->menu.menu->pagestart = result;
770 item->menu.menu->remindLast = 1;
773 break;
775 case GUI_OP_SELECT_MENU:
776 menuSetSelectedItem(item->menu.menu);
777 screenHandler = &screenHandlers[GUI_SCREEN_MAIN];
778 break;
780 case GUI_OP_CLEAR_SUBMENU:
781 submenuDestroy(item->menu.subMenu);
782 item->menu.menu->submenu = NULL;
783 item->menu.menu->current = NULL;
784 item->menu.menu->pagestart = NULL;
785 break;
787 case GUI_OP_SORT:
788 submenuSort(item->menu.subMenu);
789 item->menu.menu->submenu = *item->menu.subMenu;
791 if (!item->menu.menu->remindLast)
792 item->menu.menu->current = item->menu.menu->submenu;
794 item->menu.menu->pagestart = item->menu.menu->current;
795 break;
797 case GUI_OP_ADD_HINT:
798 // append the hint list in the menu item
799 menuAddHint(item->menu.menu, item->hint.text_id, item->hint.icon_id);
800 break;
802 default:
803 LOG("GUI: ??? (%d)\n", item->type);
807 static void guiHandleDeferredOps(void) {
808 // TODO: Fit into the given time interval, skip rest of operations of over limit
810 while (gUpdateList) {
811 WaitSema(gSemaId);
813 guiHandleOp(gUpdateList->item);
815 if (gNetworkStartup < 0) {
816 gNetworkStartup = 0;
817 guiMsgBox(_l(_STR_NETWORK_STARTUP_ERROR), 0, NULL);
820 struct gui_update_list_t* td = gUpdateList;
821 gUpdateList = gUpdateList->next;
823 free(td);
825 gCompletedOps++;
827 SignalSema(gSemaId);
830 gUpdateEnd = NULL;
833 static int bfadeout = 0x0;
834 static void guiDrawBusy() {
835 if (gTheme->loadingIcon) {
836 GSTEXTURE* texture = thmGetTexture(LOAD0_ICON + guiFrameId % gTheme->loadingIconCount);
837 if (texture && texture->Mem) {
838 u64 mycolor = GS_SETREG_RGBA(0x080, 0x080, 0x080, bfadeout);
839 rmDrawPixmap(texture, gTheme->loadingIcon->posX, gTheme->loadingIcon->posY, gTheme->loadingIcon->aligned, gTheme->loadingIcon->width, gTheme->loadingIcon->height, gTheme->loadingIcon->scaled, mycolor);
844 static int wfadeout = 0x0150;
845 static void guiRenderGreeting() {
846 int fade = wfadeout > 0xFF ? 0xFF : wfadeout;
847 u64 mycolor = GS_SETREG_RGBA(0x10, 0x10, 0x10, fade >> 1);
848 rmDrawRect(0, 0, screenWidth, screenHeight, mycolor);
849 /* char introtxt[255];
850 snprintf(introtxt, 255, _l(_STR_OUL_VER), USBLD_VERSION);
851 fntRenderString(screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, 0, 0, introtxt, GS_SETREG_RGBA(0x060, 0x060, 0x060, wfadeout));
854 GSTEXTURE* logo = thmGetTexture(LOGO_PICTURE);
855 if (logo) {
856 mycolor = GS_SETREG_RGBA(0x080, 0x080, 0x080, fade >> 1);
857 rmDrawPixmap(logo, screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, logo->Width, logo->Height, SCALING_RATIO, mycolor);
860 return;
863 static float mix(float a, float b, float t) {
864 return (1.0 - t) * a + t * b;
867 static float fade(float t) {
868 return fadetbl[(int) (t * FADE_SIZE)];
871 // The same as mix, but with 8 (2*4) values mixed at once
872 static void VU0MixVec(VU_VECTOR *a, VU_VECTOR *b, float mix, VU_VECTOR* res) {
873 asm (
874 "lqc2 vf1, 0(%0)\n" // load the first vector
875 "lqc2 vf2, 0(%1)\n" // load the second vector
876 "lw $2, 0(%2)\n" // load value from ptr to reg
877 "qmtc2 $2, vf3\n" // load the mix value from reg to VU
878 "vaddw.x vf5, vf00, vf00\n" // vf5.x = 1
879 "vsub.x vf4x, vf5x, vf3x\n" // subtract 1 - vf3,x, store the result in vf4.x
880 "vmulax.xyzw ACC, vf1, vf3x\n" // multiply vf1 by vf3.x, store the result in ACC
881 "vmaddx.xyzw vf1, vf2, vf4x\n" // multiply vf2 by vf4.x add ACC, store the result in vf1
882 "sqc2 vf1, 0(%3)\n" // transfer the result in acc to the ee
883 : : "r" (a), "r" (b), "r" (&mix), "r" (res)
887 static float guiCalcPerlin(float x, float y, float z) {
888 // Taken from: http://people.opera.com/patrickl/experiments/canvas/plasma/perlin-noise-classical.js
889 // By Sean McCullough
891 // Find unit grid cell containing point
892 int X = floor(x);
893 int Y = floor(y);
894 int Z = floor(z);
896 // Get relative xyz coordinates of point within that cell
897 x = x - X;
898 y = y - Y;
899 z = z - Z;
901 // Wrap the integer cells at 255 (smaller integer period can be introduced here)
902 X = X & 255;
903 Y = Y & 255;
904 Z = Z & 255;
906 // Calculate a set of eight hashed gradient indices
907 int gi000 = pperm[X + pperm[Y + pperm[Z]]] % 12;
908 int gi001 = pperm[X + pperm[Y + pperm[Z + 1]]] % 12;
909 int gi010 = pperm[X + pperm[Y + 1 + pperm[Z]]] % 12;
910 int gi011 = pperm[X + pperm[Y + 1 + pperm[Z + 1]]] % 12;
911 int gi100 = pperm[X + 1 + pperm[Y + pperm[Z]]] % 12;
912 int gi101 = pperm[X + 1 + pperm[Y + pperm[Z + 1]]] % 12;
913 int gi110 = pperm[X + 1 + pperm[Y + 1 + pperm[Z]]] % 12;
914 int gi111 = pperm[X + 1 + pperm[Y + 1 + pperm[Z + 1]]] % 12;
916 // The gradients of each corner are now:
917 // g000 = grad3[gi000];
918 // g001 = grad3[gi001];
919 // g010 = grad3[gi010];
920 // g011 = grad3[gi011];
921 // g100 = grad3[gi100];
922 // g101 = grad3[gi101];
923 // g110 = grad3[gi110];
924 // g111 = grad3[gi111];
925 // Calculate noise contributions from each of the eight corners
926 VU_VECTOR vec;
927 vec.x = x;
928 vec.y = y;
929 vec.z = z;
930 vec.w = 1;
932 VU_VECTOR a, b;
934 // float n000
935 a.x = Vu0DotProduct(&pgrad3[gi000], &vec);
937 vec.y -= 1;
939 // float n010
940 a.z = Vu0DotProduct(&pgrad3[gi010], &vec);
942 vec.x -= 1;
944 //float n110
945 b.z = Vu0DotProduct(&pgrad3[gi110], &vec);
947 vec.y += 1;
949 // float n100
950 b.x = Vu0DotProduct(&pgrad3[gi100], &vec);
952 vec.z -= 1;
954 // float n101
955 b.y = Vu0DotProduct(&pgrad3[gi101], &vec);
957 vec.y -= 1;
959 // float n111
960 b.w = Vu0DotProduct(&pgrad3[gi111], &vec);
962 vec.x += 1;
964 // float n011
965 a.w = Vu0DotProduct(&pgrad3[gi011], &vec);
967 vec.y += 1;
969 // float n001
970 a.y = Vu0DotProduct(&pgrad3[gi001], &vec);
972 // Compute the fade curve value for each of x, y, z
973 float u = fade(x);
974 float v = fade(y);
975 float w = fade(z);
977 // TODO: Low priority... This could be done on VU0 (xyzw for the first 4 mixes)
978 // The result in sw
979 // Interpolate along x the contributions from each of the corners
980 VU_VECTOR rv;
981 VU0MixVec(&b, &a, u, &rv);
983 // TODO: The VU0MixVec could as well mix the results (as follows) - might improve performance...
984 // Interpolate the four results along y
985 float nxy0 = mix(rv.x, rv.z, v);
986 float nxy1 = mix(rv.y, rv.w, v);
987 // Interpolate the two last results along z
988 float nxyz = mix(nxy0, nxy1, w);
990 return nxyz;
993 static float dir = 0.02;
994 static float perz = -100;
995 static int pery = 0;
996 static unsigned char curbgColor[3] = { 0, 0, 0 };
998 static int cdirection(unsigned char a, unsigned char b) {
999 if (a == b)
1000 return 0;
1001 else if (a > b)
1002 return -1;
1003 else
1004 return 1;
1007 void guiDrawBGPlasma() {
1008 int x, y;
1010 // transition the colors
1011 curbgColor[0] += cdirection(curbgColor[0], gTheme->bgColor[0]);
1012 curbgColor[1] += cdirection(curbgColor[1], gTheme->bgColor[1]);
1013 curbgColor[2] += cdirection(curbgColor[2], gTheme->bgColor[2]);
1015 // it's PLASMA_ROWS_PER_FRAME rows a frame to stop being a resource hog
1016 if (pery >= PLASMA_H) {
1017 pery = 0;
1018 perz += dir;
1020 if (perz > 100.0f || perz < -100.0f)
1021 dir = -dir;
1024 u32 *buf = gBackgroundTex.Mem + PLASMA_W * pery;
1025 int ymax = pery + PLASMA_ROWS_PER_FRAME;
1027 if (ymax > PLASMA_H)
1028 ymax = PLASMA_H;
1030 for (y = pery; y < ymax; y++) {
1031 for (x = 0; x < PLASMA_W; x++) {
1032 u32 fper = guiCalcPerlin((float) (2 * x) / PLASMA_W, (float) (2 * y) / PLASMA_H, perz) * 0x080 + 0x080;
1034 *buf = GS_SETREG_RGBA(
1035 (u32)(fper * curbgColor[0]) >> 8,
1036 (u32)(fper * curbgColor[1]) >> 8,
1037 (u32)(fper * curbgColor[2]) >> 8,
1038 0x080);
1040 ++buf;
1045 pery = ymax;
1046 rmDrawPixmap(&gBackgroundTex, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol);
1049 int guiDrawIconAndText(int iconId, int textId, int font, int x, int y, u64 color) {
1050 GSTEXTURE* iconTex = thmGetTexture(iconId);
1051 if (iconTex && iconTex->Mem) {
1052 rmDrawPixmap(iconTex, x, y, ALIGN_NONE, iconTex->Width, iconTex->Height, SCALING_RATIO, gDefaultCol);
1053 x += iconTex->Width + 2;
1056 x = fntRenderString(font, x, y, ALIGN_NONE, 0, 0, _l(textId), color);
1058 return x;
1061 static void guiDrawOverlays() {
1062 // are there any pending operations?
1063 int pending = ioHasPendingRequests();
1065 if (gInitComplete)
1066 wfadeout--;
1068 if (!pending) {
1069 if (bfadeout > 0x0)
1070 bfadeout -= 0x08;
1071 else
1072 bfadeout = 0x0;
1073 } else {
1074 if (bfadeout < 0x080)
1075 bfadeout += 0x20;
1078 // is init still running?
1079 if (wfadeout > 0)
1080 guiRenderGreeting();
1082 if (bfadeout > 0)
1083 guiDrawBusy();
1085 #ifdef __DEBUG
1086 // fps meter
1087 char fps[10];
1089 if (time_since_last != 0)
1090 snprintf(fps, 10, "%3.1f FPS", 1000.0f / (float) time_since_last);
1091 else
1092 snprintf(fps, 10, "---- FPS");
1094 fntRenderString(FNT_DEFAULT, screenWidth - 60, gTheme->usedHeight - 20, ALIGN_CENTER, 0, 0, fps, GS_SETREG_RGBA(0x060, 0x060, 0x060, 0x060));
1096 snprintf(fps, 10, "%3d ms", time_render);
1098 fntRenderString(FNT_DEFAULT, screenWidth - 60, gTheme->usedHeight - 45, ALIGN_CENTER, 0, 0, fps, GS_SETREG_RGBA(0x060, 0x060, 0x060, 0x060));
1099 #endif
1102 static void guiReadPads() {
1103 if (readPads())
1104 guiInactiveFrames = 0;
1105 else
1106 guiInactiveFrames++;
1109 // renders the screen and handles inputs. Also handles screen transitions between numerous
1110 // screen handlers. For now we only have left-to right screen transition
1111 static void guiShow() {
1112 // is there a transmission effect going on or are
1113 // we in a normal rendering state?
1114 if (screenHandlerTarget) {
1115 // advance the effect
1117 // render the old screen, transposed
1118 rmSetTransposition(transIndex * transitionX, transIndex * transitionY);
1119 screenHandler->renderScreen();
1121 // render new screen transposed again
1122 rmSetTransposition((transIndex - transMax) * transitionX, (transIndex - transMax) * transitionY);
1123 screenHandlerTarget->renderScreen();
1125 // reset transposition to zero
1126 rmSetTransposition(0, 0);
1128 // move the transition indicator forward
1129 transIndex += (min(transIndex, transMax - transIndex) >> 1) + 1;
1131 if (transIndex > transMax) {
1132 transitionX = 0;
1133 transitionY = 0;
1134 screenHandler = screenHandlerTarget;
1135 screenHandlerTarget = NULL;
1137 } else
1138 // render with the set screen handler
1139 screenHandler->renderScreen();
1142 void guiMainLoop(void) {
1143 while (!gTerminate) {
1144 guiStartFrame();
1146 // Read the pad states to prepare for input processing in the screen handler
1147 guiReadPads();
1149 // handle inputs and render screen
1150 if (wfadeout < 0x0FF)
1151 guiShow();
1153 // Render overlaying gui thingies :)
1154 guiDrawOverlays();
1156 // handle deferred operations
1157 guiHandleDeferredOps();
1159 if (gFrameHook)
1160 gFrameHook();
1162 guiEndFrame();
1164 // if not transiting, handle input
1165 // done here so we can use renderman if needed
1166 if (!screenHandlerTarget && screenHandler)
1167 screenHandler->handleInput();
1171 void guiSetFrameHook(gui_callback_t cback) {
1172 gFrameHook = cback;
1175 void guiSwitchScreen(int target, int transition) {
1176 if (transition == TRANSITION_LEFT) {
1177 transitionX = 1;
1178 transMax = screenWidth;
1179 } else if (transition == TRANSITION_RIGHT) {
1180 transitionX = -1;
1181 transMax = screenWidth;
1182 } else if (transition == TRANSITION_UP) {
1183 transitionY = 1;
1184 transMax = screenHeight;
1185 } else if (transition == TRANSITION_DOWN) {
1186 transitionY = -1;
1187 transMax = screenHeight;
1189 transIndex = 0;
1191 screenHandlerTarget = &screenHandlers[target];
1194 struct gui_update_t *guiOpCreate(gui_op_type_t type) {
1195 struct gui_update_t *op = (struct gui_update_t *) malloc(sizeof(struct gui_update_t));
1196 memset(op, 0, sizeof(struct gui_update_t));
1197 op->type = type;
1198 return op;
1201 void guiUpdateScrollSpeed(void) {
1202 // sanitize the settings
1203 if ((gScrollSpeed < 0) || (gScrollSpeed > 2))
1204 gScrollSpeed = 1;
1206 // update the pad delays for KEY_UP and KEY_DOWN
1207 // default delay is 7
1208 // fast - 100 ms
1209 // medium - 300 ms
1210 // slow - 500 ms
1211 setButtonDelay(KEY_UP, 500 - gScrollSpeed * 200); // 0,1,2 -> 500, 300, 100
1212 setButtonDelay(KEY_DOWN, 500 - gScrollSpeed * 200);
1215 void guiUpdateScreenScale(void) {
1216 if (gWideScreen)
1217 wideScreenScale = 0.75f;
1218 else
1219 wideScreenScale = 1.0f;
1221 // apply the scaling to renderman and font rendering
1222 rmSetAspectRatio(wideScreenScale, 1.0f);
1223 fntSetAspectRatio(wideScreenScale, 1.0f);
1226 int guiMsgBox(const char* text, int addAccept, struct UIItem *ui) {
1227 int terminate = 0;
1228 while (!terminate) {
1229 guiStartFrame();
1231 readPads();
1233 if (getKeyOn(KEY_CIRCLE))
1234 terminate = 1;
1235 else if (getKeyOn(KEY_CROSS))
1236 terminate = 2;
1238 if (ui)
1239 diaRenderUI(ui, screenHandler->inMenu, NULL, 0);
1240 else
1241 guiShow();
1243 rmDrawRect(0, 0, screenWidth, screenHeight, gColDarker);
1245 rmDrawLine(50, 75, screenWidth - 50, 75, gColWhite);
1246 rmDrawLine(50, 410, screenWidth - 50, 410, gColWhite);
1248 fntRenderString(FNT_DEFAULT, screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, 0, 0, text, gTheme->textColor);
1249 guiDrawIconAndText(CIRCLE_ICON, _STR_O_BACK, FNT_DEFAULT, 500, 417, gTheme->selTextColor);
1250 if (addAccept)
1251 guiDrawIconAndText(CROSS_ICON, _STR_X_ACCEPT, FNT_DEFAULT, 70, 417, gTheme->selTextColor);
1253 guiEndFrame();
1256 return terminate - 1;
1259 void guiHandleDefferedIO(int *ptr, const unsigned char* message, int type, void *data) {
1260 ioPutRequest(type, data);
1262 while (*ptr)
1263 guiRenderTextScreen(message);
1266 void guiRenderTextScreen(const unsigned char* message) {
1267 guiStartFrame();
1269 guiShow();
1271 rmDrawRect(0, 0, screenWidth, screenHeight, gColDarker);
1273 fntRenderString(FNT_DEFAULT, screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, 0, 0, message, gTheme->textColor);
1275 guiDrawOverlays();
1277 guiEndFrame();