uncommited code for 151 release (PSP suspend, file browser, etc)
[libpicofe.git] / common / menu.c
CommitLineData
c7a4ff64 1// (c) Copyright 2006,2007 notaz, All rights reserved.\r
2// Free for non-commercial use.\r
3\r
4// For commercial use, separate licencing terms must be obtained.\r
5\r
6#include <stdio.h>\r
7#include <string.h>\r
8#include <stdlib.h>\r
9#include <stdarg.h>\r
10\r
11#include "menu.h"\r
12#include "fonts.h"\r
13#include "readpng.h"\r
14#include "lprintf.h"\r
b8464531 15#include "common.h"\r
16#include "emu.h"\r
c7a4ff64 17\r
c7a4ff64 18\r
f013066e 19char menuErrorMsg[64] = { 0, };\r
20\r
367b6f1f 21// PicoPad[] format: MXYZ SACB RLDU\r
6589c840 22me_bind_action me_ctrl_actions[15] =\r
367b6f1f 23{\r
6589c840 24 { "UP ", 0x0001 },\r
25 { "DOWN ", 0x0002 },\r
26 { "LEFT ", 0x0004 },\r
27 { "RIGHT ", 0x0008 },\r
28 { "A ", 0x0040 },\r
29 { "B ", 0x0010 },\r
30 { "C ", 0x0020 },\r
31 { "A turbo", 0x4000 },\r
32 { "B turbo", 0x1000 },\r
33 { "C turbo", 0x2000 },\r
34 { "START ", 0x0080 },\r
35 { "MODE ", 0x0800 },\r
36 { "X ", 0x0400 },\r
37 { "Y ", 0x0200 },\r
38 { "Z ", 0x0100 }\r
367b6f1f 39};\r
40\r
41\r
c7a4ff64 42static unsigned char menu_font_data[10240];\r
43static int menu_text_color = 0xffff; // default to white\r
44static int menu_sel_color = -1; // disabled\r
45\r
46// draws text to current bbp16 screen\r
47static void text_out16_(int x, int y, const char *text, int color)\r
48{\r
49 int i, l, u, tr, tg, tb, len;\r
50 unsigned short *dest = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;\r
51 tr = (color & 0xf800) >> 8;\r
52 tg = (color & 0x07e0) >> 3;\r
53 tb = (color & 0x001f) << 3;\r
54\r
55 if (text == (void *)1)\r
56 {\r
57 // selector symbol\r
58 text = "";\r
59 len = 1;\r
60 }\r
61 else\r
62 len = strlen(text);\r
63\r
64 for (i = 0; i < len; i++)\r
65 {\r
66 unsigned char *src = menu_font_data + (unsigned int)text[i]*4*10;\r
67 unsigned short *dst = dest;\r
68 for (l = 0; l < 10; l++, dst += SCREEN_WIDTH-8)\r
69 {\r
70 for (u = 8/2; u > 0; u--, src++)\r
71 {\r
72 int c, r, g, b;\r
73 c = *src >> 4;\r
74 r = (*dst & 0xf800) >> 8;\r
75 g = (*dst & 0x07e0) >> 3;\r
76 b = (*dst & 0x001f) << 3;\r
77 r = (c^0xf)*r/15 + c*tr/15;\r
78 g = (c^0xf)*g/15 + c*tg/15;\r
79 b = (c^0xf)*b/15 + c*tb/15;\r
80 *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r
81 c = *src & 0xf;\r
82 r = (*dst & 0xf800) >> 8;\r
83 g = (*dst & 0x07e0) >> 3;\r
84 b = (*dst & 0x001f) << 3;\r
85 r = (c^0xf)*r/15 + c*tr/15;\r
86 g = (c^0xf)*g/15 + c*tg/15;\r
87 b = (c^0xf)*b/15 + c*tb/15;\r
88 *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r
89 }\r
90 }\r
91 dest += 8;\r
92 }\r
93}\r
94\r
95void text_out16(int x, int y, const char *texto, ...)\r
96{\r
97 va_list args;\r
98 char buffer[512];\r
99\r
100 va_start(args,texto);\r
101 vsprintf(buffer,texto,args);\r
102 va_end(args);\r
103\r
104 text_out16_(x,y,buffer,menu_text_color);\r
105}\r
106\r
107\r
108void smalltext_out16(int x, int y, const char *texto, int color)\r
109{\r
110 int i;\r
111 unsigned char *src;\r
112 unsigned short *dst;\r
113\r
114 for (i = 0;; i++, x += 6)\r
115 {\r
116 unsigned char c = (unsigned char) texto[i];\r
117 int h = 8;\r
118\r
119 if (!c) break;\r
120\r
121 src = fontdata6x8[c];\r
122 dst = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;\r
123\r
124 while (h--)\r
125 {\r
126 int w = 0x20;\r
127 while (w)\r
128 {\r
129 if( *src & w ) *dst = color;\r
130 dst++;\r
131 w>>=1;\r
132 }\r
133 src++;\r
134\r
135 dst += SCREEN_WIDTH-6;\r
136 }\r
137 }\r
138}\r
139\r
140void smalltext_out16_lim(int x, int y, const char *texto, int color, int max)\r
141{\r
142 char buffer[SCREEN_WIDTH/6+1];\r
143\r
144 strncpy(buffer, texto, SCREEN_WIDTH/6);\r
145 if (max > SCREEN_WIDTH/6) max = SCREEN_WIDTH/6;\r
146 if (max < 0) max = 0;\r
147 buffer[max] = 0;\r
148\r
149 smalltext_out16(x, y, buffer, color);\r
150}\r
151\r
152void menu_draw_selection(int x, int y, int w)\r
153{\r
154 int i, h;\r
155 unsigned short *dst, *dest;\r
156\r
157 text_out16_(x, y, (void *)1, (menu_sel_color < 0) ? menu_text_color : menu_sel_color);\r
158\r
159 if (menu_sel_color < 0) return; // no selection hilight\r
160\r
161 if (y > 0) y--;\r
162 dest = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH + 14;\r
163 for (h = 11; h > 0; h--)\r
164 {\r
165 dst = dest;\r
166 for (i = w; i > 0; i--)\r
167 *dst++ = menu_sel_color;\r
168 dest += SCREEN_WIDTH;\r
169 }\r
170}\r
171\r
172static int parse_hex_color(char *buff)\r
173{\r
174 char *endp = buff;\r
175 int t = (int) strtoul(buff, &endp, 16);\r
703e4c7b 176 if (endp != buff)\r
177#ifdef PSP\r
178 return ((t<<8)&0xf800) | ((t>>5)&0x07e0) | ((t>>19)&0x1f);\r
179#else\r
180 return ((t>>8)&0xf800) | ((t>>5)&0x07e0) | ((t>>3)&0x1f);\r
181#endif\r
c7a4ff64 182 return -1;\r
183}\r
184\r
185void menu_init(void)\r
186{\r
187 int c, l;\r
188 unsigned char *fd = menu_font_data;\r
189 char buff[256];\r
190 FILE *f;\r
191\r
192 // generate default font from fontdata8x8\r
193 memset(menu_font_data, 0, sizeof(menu_font_data));\r
194 for (c = 0; c < 256; c++)\r
195 {\r
196 for (l = 0; l < 8; l++)\r
197 {\r
198 unsigned char fd8x8 = fontdata8x8[c*8+l];\r
199 if (fd8x8&0x80) *fd |= 0xf0;\r
200 if (fd8x8&0x40) *fd |= 0x0f; fd++;\r
201 if (fd8x8&0x20) *fd |= 0xf0;\r
202 if (fd8x8&0x10) *fd |= 0x0f; fd++;\r
203 if (fd8x8&0x08) *fd |= 0xf0;\r
204 if (fd8x8&0x04) *fd |= 0x0f; fd++;\r
205 if (fd8x8&0x02) *fd |= 0xf0;\r
206 if (fd8x8&0x01) *fd |= 0x0f; fd++;\r
207 }\r
208 fd += 8*2/2; // 2 empty lines\r
209 }\r
210\r
211 // load custom font and selector (stored as 1st symbol in font table)\r
212 readpng(menu_font_data, "skin/font.png", READPNG_FONT);\r
213 memcpy(menu_font_data, menu_font_data + ((int)'>')*4*10, 4*10); // default selector symbol is '>'\r
214 readpng(menu_font_data, "skin/selector.png", READPNG_SELECTOR);\r
215\r
216 // load custom colors\r
217 f = fopen("skin/skin.txt", "r");\r
218 if (f != NULL)\r
219 {\r
220 lprintf("found skin.txt\n");\r
221 while (!feof(f))\r
222 {\r
223 fgets(buff, sizeof(buff), f);\r
224 if (buff[0] == '#' || buff[0] == '/') continue; // comment\r
225 if (buff[0] == '\r' || buff[0] == '\n') continue; // empty line\r
226 if (strncmp(buff, "text_color=", 11) == 0)\r
227 {\r
228 int tmp = parse_hex_color(buff+11);\r
229 if (tmp >= 0) menu_text_color = tmp;\r
230 else lprintf("skin.txt: parse error for text_color\n");\r
231 }\r
232 else if (strncmp(buff, "selection_color=", 16) == 0)\r
233 {\r
234 int tmp = parse_hex_color(buff+16);\r
235 if (tmp >= 0) menu_sel_color = tmp;\r
236 else lprintf("skin.txt: parse error for selection_color\n");\r
237 }\r
238 else\r
239 lprintf("skin.txt: parse error: %s\n", buff);\r
240 }\r
241 fclose(f);\r
242 }\r
243}\r
244\r
245\r
246int me_id2offset(const menu_entry *entries, int count, menu_id id)\r
247{\r
248 int i;\r
249 for (i = 0; i < count; i++)\r
250 {\r
251 if (entries[i].id == id) return i;\r
252 }\r
253\r
254 lprintf("%s: id %i not found\n", __FUNCTION__, id);\r
255 return 0;\r
256}\r
257\r
258void me_enable(menu_entry *entries, int count, menu_id id, int enable)\r
259{\r
260 int i = me_id2offset(entries, count, id);\r
261 entries[i].enabled = enable;\r
262}\r
263\r
264int me_count_enabled(const menu_entry *entries, int count)\r
265{\r
266 int i, ret = 0;\r
267\r
268 for (i = 0; i < count; i++)\r
269 {\r
270 if (entries[i].enabled) ret++;\r
271 }\r
272\r
273 return ret;\r
274}\r
275\r
276menu_id me_index2id(const menu_entry *entries, int count, int index)\r
277{\r
278 int i;\r
279\r
280 for (i = 0; i < count; i++)\r
281 {\r
282 if (entries[i].enabled)\r
283 {\r
284 if (index == 0) break;\r
285 index--;\r
286 }\r
287 }\r
288 if (i >= count) i = count - 1;\r
289 return entries[i].id;\r
290}\r
291\r
292void me_draw(const menu_entry *entries, int count, int x, int y, me_draw_custom_f *cust_draw, void *param)\r
293{\r
294 int i, y1 = y;\r
295\r
296 for (i = 0; i < count; i++)\r
297 {\r
298 if (!entries[i].enabled) continue;\r
299 if (entries[i].name == NULL)\r
300 {\r
301 if (cust_draw != NULL)\r
302 cust_draw(&entries[i], x, y1, param);\r
303 y1 += 10;\r
304 continue;\r
305 }\r
306 text_out16(x, y1, entries[i].name);\r
307 if (entries[i].beh == MB_ONOFF)\r
308 text_out16(x + 27*8, y1, (*(int *)entries[i].var & entries[i].mask) ? "ON" : "OFF");\r
309 else if (entries[i].beh == MB_RANGE)\r
310 text_out16(x + 27*8, y1, "%i", *(int *)entries[i].var);\r
311 y1 += 10;\r
312 }\r
313}\r
314\r
315int me_process(menu_entry *entries, int count, menu_id id, int is_next)\r
316{\r
317 int i = me_id2offset(entries, count, id);\r
318 menu_entry *entry = &entries[i];\r
319 switch (entry->beh)\r
320 {\r
321 case MB_ONOFF:\r
322 *(int *)entry->var ^= entry->mask;\r
323 return 1;\r
324 case MB_RANGE:\r
325 *(int *)entry->var += is_next ? 1 : -1;\r
326 if (*(int *)entry->var < (int)entry->min) *(int *)entry->var = (int)entry->min;\r
327 if (*(int *)entry->var > (int)entry->max) *(int *)entry->var = (int)entry->max;\r
328 return 1;\r
329 default:\r
330 return 0;\r
331 }\r
332}\r
333\r
0ae25549 334const char *me_region_name(unsigned int code, int auto_order)\r
335{\r
336 static const char *names[] = { "Auto", " Japan NTSC", " Japan PAL", " USA", " Europe" };\r
337 static const char *names_short[] = { "", " JP", " JP", " US", " EU" };\r
338 int u, i = 0;\r
339 if (code) {\r
340 code <<= 1;\r
341 while((code >>= 1)) i++;\r
342 if (i > 4) return "unknown";\r
343 return names[i];\r
344 } else {\r
345 static char name[24];\r
346 strcpy(name, "Auto:");\r
347 for (u = 0; u < 3; u++) {\r
348 i = 0; code = ((auto_order >> u*4) & 0xf) << 1;\r
349 while((code >>= 1)) i++;\r
350 strcat(name, names_short[i]);\r
351 }\r
352 return name;\r
353 }\r
354}\r
c7a4ff64 355\r
b8464531 356// ------------ debug menu ------------\r
357\r
358#include <sys/stat.h>\r
359#include <sys/types.h>\r
360\r
361#include <Pico/Pico.h>\r
362#include <Pico/Debug.h>\r
363\r
364void SekStepM68k(void);\r
365\r
366static void draw_text_debug(const char *str, int skip, int from)\r
367{\r
368 const char *p;\r
369 int len, line;\r
370\r
371 p = str;\r
372 while (skip-- > 0)\r
373 {\r
374 while (*p && *p != '\n') p++;\r
375 if (*p == 0 || p[1] == 0) return;\r
376 p++;\r
377 }\r
378\r
379 str = p;\r
380 for (line = from; line < SCREEN_HEIGHT/10; line++)\r
381 {\r
382 while (*p && *p != '\n') p++;\r
383 len = p - str;\r
384 if (len > 55) len = 55;\r
385 smalltext_out16_lim(1, line*10, str, 0xffff, len);\r
386 if (*p == 0) break;\r
387 p++; str = p;\r
388 }\r
389}\r
390\r
391static void draw_frame_debug(void)\r
392{\r
393 char layer_str[48] = "layers: ";\r
394 if (PicoDrawMask & PDRAW_LAYERB_ON) memcpy(layer_str + 8, "B", 1);\r
395 if (PicoDrawMask & PDRAW_LAYERA_ON) memcpy(layer_str + 10, "A", 1);\r
396 if (PicoDrawMask & PDRAW_SPRITES_LOW_ON) memcpy(layer_str + 12, "spr_lo", 6);\r
397 if (PicoDrawMask & PDRAW_SPRITES_HI_ON) memcpy(layer_str + 19, "spr_hi", 6);\r
398\r
399 clear_screen();\r
400 emu_forcedFrame(0);\r
401 smalltext_out16(4, SCREEN_HEIGHT-8, layer_str, 0xffff);\r
402}\r
403\r
404void debug_menu_loop(void)\r
405{\r
406 int inp, mode = 0;\r
407 int spr_offs = 0, dumped = 0;\r
408\r
409 while (1)\r
410 {\r
411 switch (mode)\r
412 {\r
413 case 0: menu_draw_begin();\r
414 draw_text_debug(PDebugMain(), 0, 0);\r
415 if (dumped) {\r
416 smalltext_out16(SCREEN_WIDTH-6*10, SCREEN_HEIGHT-8, "dumped", 0xffff);\r
417 dumped = 0;\r
418 }\r
419 break;\r
420 case 1: draw_frame_debug(); break;\r
421 case 2: clear_screen();\r
422 emu_forcedFrame(0);\r
423 darken_screen();\r
dfa8d77a 424 PDebugShowSpriteStats((unsigned short *)SCREEN_BUFFER + (SCREEN_HEIGHT/2 - 240/2)*SCREEN_WIDTH +\r
425 SCREEN_WIDTH/2 - 320/2, SCREEN_WIDTH); break;\r
b8464531 426 case 3: clear_screen();\r
427 PDebugShowPalette(SCREEN_BUFFER, SCREEN_WIDTH);\r
428 PDebugShowSprite((unsigned short *)SCREEN_BUFFER + SCREEN_WIDTH*120+SCREEN_WIDTH/2+16,\r
429 SCREEN_WIDTH, spr_offs);\r
430 draw_text_debug(PDebugSpriteList(), spr_offs, 6);\r
431 break;\r
432 }\r
433 menu_draw_end();\r
434\r
435 inp = read_buttons(BTN_EAST|BTN_SOUTH|BTN_WEST|BTN_L|BTN_R|BTN_UP|BTN_DOWN|BTN_LEFT|BTN_RIGHT);\r
436 if (inp & BTN_SOUTH) return;\r
437 if (inp & BTN_L) { mode--; if (mode < 0) mode = 3; }\r
438 if (inp & BTN_R) { mode++; if (mode > 3) mode = 0; }\r
439 switch (mode)\r
440 {\r
441 case 0:\r
442 if (inp & BTN_EAST) SekStepM68k();\r
443 if ((inp & (BTN_WEST|BTN_LEFT)) == (BTN_WEST|BTN_LEFT)) {\r
444 mkdir("dumps", 0777);\r
445 PDebugDumpMem();\r
8e6cbce1 446 while (inp & BTN_WEST) inp = read_buttons_async(BTN_WEST);\r
b8464531 447 dumped = 1;\r
448 }\r
449 break;\r
450 case 1:\r
451 if (inp & BTN_LEFT) PicoDrawMask ^= PDRAW_LAYERB_ON;\r
452 if (inp & BTN_RIGHT) PicoDrawMask ^= PDRAW_LAYERA_ON;\r
453 if (inp & BTN_DOWN) PicoDrawMask ^= PDRAW_SPRITES_LOW_ON;\r
454 if (inp & BTN_UP) PicoDrawMask ^= PDRAW_SPRITES_HI_ON;\r
8e6cbce1 455 if (inp & BTN_EAST) {\r
456 PsndOut = NULL; // just in case\r
457 PicoSkipFrame = 1;\r
458 PicoFrame();\r
459 PicoSkipFrame = 0;\r
460 while (inp & BTN_EAST) inp = read_buttons_async(BTN_EAST);\r
461 }\r
b8464531 462 break;\r
463 case 3:\r
464 if (inp & BTN_DOWN) spr_offs++;\r
465 if (inp & BTN_UP) spr_offs--;\r
466 if (spr_offs < 0) spr_offs = 0;\r
467 break;\r
468 }\r
469 }\r
470}\r
471\r
472\r