readme updated
[picodrive.git] / platform / common / menu.c
CommitLineData
e5f426aa 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
15\r
16#if defined(__GP2X__)\r
ea8c405f 17 #include "../gp2x/gp2x.h"\r
18 #define SCREEN_WIDTH 320\r
19 #define SCREEN_BUFFER gp2x_screen\r
e5f426aa 20#elif defined(__GIZ__)\r
ea8c405f 21 //#include "../gizmondo/giz.h"\r
22 #define SCREEN_WIDTH 321\r
23 #define SCREEN_BUFFER menu_screen\r
24 extern unsigned char *menu_screen;\r
1820b5a7 25#elif defined(PSP)\r
26 #include "../psp/psp.h"\r
27 #define SCREEN_WIDTH 512\r
28 #define SCREEN_BUFFER psp_screen\r
e5f426aa 29#endif\r
30\r
ea8c405f 31char menuErrorMsg[64] = { 0, };\r
32\r
1ca2ea4f 33// PicoPad[] format: MXYZ SACB RLDU\r
34me_bind_action me_ctrl_actions[12] =\r
35{\r
36 { "UP ", 0x001 },\r
37 { "DOWN ", 0x002 },\r
38 { "LEFT ", 0x004 },\r
39 { "RIGHT ", 0x008 },\r
40 { "A ", 0x040 },\r
41 { "B ", 0x010 },\r
42 { "C ", 0x020 },\r
43 { "START ", 0x080 },\r
44 { "MODE ", 0x800 },\r
45 { "X ", 0x400 },\r
46 { "Y ", 0x200 },\r
47 { "Z ", 0x100 }\r
48};\r
49\r
50\r
e5f426aa 51static unsigned char menu_font_data[10240];\r
52static int menu_text_color = 0xffff; // default to white\r
53static int menu_sel_color = -1; // disabled\r
54\r
55// draws text to current bbp16 screen\r
56static void text_out16_(int x, int y, const char *text, int color)\r
57{\r
58 int i, l, u, tr, tg, tb, len;\r
59 unsigned short *dest = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;\r
60 tr = (color & 0xf800) >> 8;\r
61 tg = (color & 0x07e0) >> 3;\r
62 tb = (color & 0x001f) << 3;\r
63\r
64 if (text == (void *)1)\r
65 {\r
66 // selector symbol\r
67 text = "";\r
68 len = 1;\r
69 }\r
70 else\r
71 len = strlen(text);\r
72\r
73 for (i = 0; i < len; i++)\r
74 {\r
75 unsigned char *src = menu_font_data + (unsigned int)text[i]*4*10;\r
76 unsigned short *dst = dest;\r
77 for (l = 0; l < 10; l++, dst += SCREEN_WIDTH-8)\r
78 {\r
79 for (u = 8/2; u > 0; u--, src++)\r
80 {\r
81 int c, r, g, b;\r
82 c = *src >> 4;\r
83 r = (*dst & 0xf800) >> 8;\r
84 g = (*dst & 0x07e0) >> 3;\r
85 b = (*dst & 0x001f) << 3;\r
86 r = (c^0xf)*r/15 + c*tr/15;\r
87 g = (c^0xf)*g/15 + c*tg/15;\r
88 b = (c^0xf)*b/15 + c*tb/15;\r
89 *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r
90 c = *src & 0xf;\r
91 r = (*dst & 0xf800) >> 8;\r
92 g = (*dst & 0x07e0) >> 3;\r
93 b = (*dst & 0x001f) << 3;\r
94 r = (c^0xf)*r/15 + c*tr/15;\r
95 g = (c^0xf)*g/15 + c*tg/15;\r
96 b = (c^0xf)*b/15 + c*tb/15;\r
97 *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r
98 }\r
99 }\r
100 dest += 8;\r
101 }\r
102}\r
103\r
104void text_out16(int x, int y, const char *texto, ...)\r
105{\r
106 va_list args;\r
107 char buffer[512];\r
108\r
109 va_start(args,texto);\r
110 vsprintf(buffer,texto,args);\r
111 va_end(args);\r
112\r
113 text_out16_(x,y,buffer,menu_text_color);\r
114}\r
115\r
116\r
117void smalltext_out16(int x, int y, const char *texto, int color)\r
118{\r
119 int i;\r
120 unsigned char *src;\r
121 unsigned short *dst;\r
122\r
123 for (i = 0;; i++, x += 6)\r
124 {\r
125 unsigned char c = (unsigned char) texto[i];\r
126 int h = 8;\r
127\r
128 if (!c) break;\r
129\r
130 src = fontdata6x8[c];\r
131 dst = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;\r
132\r
133 while (h--)\r
134 {\r
135 int w = 0x20;\r
136 while (w)\r
137 {\r
138 if( *src & w ) *dst = color;\r
139 dst++;\r
140 w>>=1;\r
141 }\r
142 src++;\r
143\r
144 dst += SCREEN_WIDTH-6;\r
145 }\r
146 }\r
147}\r
148\r
149void smalltext_out16_lim(int x, int y, const char *texto, int color, int max)\r
150{\r
151 char buffer[SCREEN_WIDTH/6+1];\r
152\r
153 strncpy(buffer, texto, SCREEN_WIDTH/6);\r
154 if (max > SCREEN_WIDTH/6) max = SCREEN_WIDTH/6;\r
155 if (max < 0) max = 0;\r
156 buffer[max] = 0;\r
157\r
158 smalltext_out16(x, y, buffer, color);\r
159}\r
160\r
161void menu_draw_selection(int x, int y, int w)\r
162{\r
163 int i, h;\r
164 unsigned short *dst, *dest;\r
165\r
166 text_out16_(x, y, (void *)1, (menu_sel_color < 0) ? menu_text_color : menu_sel_color);\r
167\r
168 if (menu_sel_color < 0) return; // no selection hilight\r
169\r
170 if (y > 0) y--;\r
171 dest = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH + 14;\r
172 for (h = 11; h > 0; h--)\r
173 {\r
174 dst = dest;\r
175 for (i = w; i > 0; i--)\r
176 *dst++ = menu_sel_color;\r
177 dest += SCREEN_WIDTH;\r
178 }\r
179}\r
180\r
181static int parse_hex_color(char *buff)\r
182{\r
183 char *endp = buff;\r
184 int t = (int) strtoul(buff, &endp, 16);\r
7d4906bf 185 if (endp != buff)\r
186#ifdef PSP\r
187 return ((t<<8)&0xf800) | ((t>>5)&0x07e0) | ((t>>19)&0x1f);\r
188#else\r
189 return ((t>>8)&0xf800) | ((t>>5)&0x07e0) | ((t>>3)&0x1f);\r
190#endif\r
e5f426aa 191 return -1;\r
192}\r
193\r
194void menu_init(void)\r
195{\r
196 int c, l;\r
197 unsigned char *fd = menu_font_data;\r
198 char buff[256];\r
199 FILE *f;\r
200\r
201 // generate default font from fontdata8x8\r
202 memset(menu_font_data, 0, sizeof(menu_font_data));\r
203 for (c = 0; c < 256; c++)\r
204 {\r
205 for (l = 0; l < 8; l++)\r
206 {\r
207 unsigned char fd8x8 = fontdata8x8[c*8+l];\r
208 if (fd8x8&0x80) *fd |= 0xf0;\r
209 if (fd8x8&0x40) *fd |= 0x0f; fd++;\r
210 if (fd8x8&0x20) *fd |= 0xf0;\r
211 if (fd8x8&0x10) *fd |= 0x0f; fd++;\r
212 if (fd8x8&0x08) *fd |= 0xf0;\r
213 if (fd8x8&0x04) *fd |= 0x0f; fd++;\r
214 if (fd8x8&0x02) *fd |= 0xf0;\r
215 if (fd8x8&0x01) *fd |= 0x0f; fd++;\r
216 }\r
217 fd += 8*2/2; // 2 empty lines\r
218 }\r
219\r
220 // load custom font and selector (stored as 1st symbol in font table)\r
221 readpng(menu_font_data, "skin/font.png", READPNG_FONT);\r
222 memcpy(menu_font_data, menu_font_data + ((int)'>')*4*10, 4*10); // default selector symbol is '>'\r
223 readpng(menu_font_data, "skin/selector.png", READPNG_SELECTOR);\r
224\r
225 // load custom colors\r
226 f = fopen("skin/skin.txt", "r");\r
227 if (f != NULL)\r
228 {\r
229 lprintf("found skin.txt\n");\r
230 while (!feof(f))\r
231 {\r
232 fgets(buff, sizeof(buff), f);\r
233 if (buff[0] == '#' || buff[0] == '/') continue; // comment\r
234 if (buff[0] == '\r' || buff[0] == '\n') continue; // empty line\r
235 if (strncmp(buff, "text_color=", 11) == 0)\r
236 {\r
237 int tmp = parse_hex_color(buff+11);\r
238 if (tmp >= 0) menu_text_color = tmp;\r
239 else lprintf("skin.txt: parse error for text_color\n");\r
240 }\r
241 else if (strncmp(buff, "selection_color=", 16) == 0)\r
242 {\r
243 int tmp = parse_hex_color(buff+16);\r
244 if (tmp >= 0) menu_sel_color = tmp;\r
245 else lprintf("skin.txt: parse error for selection_color\n");\r
246 }\r
247 else\r
248 lprintf("skin.txt: parse error: %s\n", buff);\r
249 }\r
250 fclose(f);\r
251 }\r
252}\r
253\r
254\r
255int me_id2offset(const menu_entry *entries, int count, menu_id id)\r
256{\r
257 int i;\r
258 for (i = 0; i < count; i++)\r
259 {\r
260 if (entries[i].id == id) return i;\r
261 }\r
262\r
263 lprintf("%s: id %i not found\n", __FUNCTION__, id);\r
264 return 0;\r
265}\r
266\r
267void me_enable(menu_entry *entries, int count, menu_id id, int enable)\r
268{\r
269 int i = me_id2offset(entries, count, id);\r
270 entries[i].enabled = enable;\r
271}\r
272\r
273int me_count_enabled(const menu_entry *entries, int count)\r
274{\r
275 int i, ret = 0;\r
276\r
277 for (i = 0; i < count; i++)\r
278 {\r
279 if (entries[i].enabled) ret++;\r
280 }\r
281\r
282 return ret;\r
283}\r
284\r
285menu_id me_index2id(const menu_entry *entries, int count, int index)\r
286{\r
287 int i;\r
288\r
289 for (i = 0; i < count; i++)\r
290 {\r
291 if (entries[i].enabled)\r
292 {\r
293 if (index == 0) break;\r
294 index--;\r
295 }\r
296 }\r
297 if (i >= count) i = count - 1;\r
298 return entries[i].id;\r
299}\r
300\r
301void me_draw(const menu_entry *entries, int count, int x, int y, me_draw_custom_f *cust_draw, void *param)\r
302{\r
303 int i, y1 = y;\r
304\r
305 for (i = 0; i < count; i++)\r
306 {\r
307 if (!entries[i].enabled) continue;\r
308 if (entries[i].name == NULL)\r
309 {\r
310 if (cust_draw != NULL)\r
311 cust_draw(&entries[i], x, y1, param);\r
312 y1 += 10;\r
313 continue;\r
314 }\r
315 text_out16(x, y1, entries[i].name);\r
316 if (entries[i].beh == MB_ONOFF)\r
317 text_out16(x + 27*8, y1, (*(int *)entries[i].var & entries[i].mask) ? "ON" : "OFF");\r
318 else if (entries[i].beh == MB_RANGE)\r
319 text_out16(x + 27*8, y1, "%i", *(int *)entries[i].var);\r
320 y1 += 10;\r
321 }\r
322}\r
323\r
324int me_process(menu_entry *entries, int count, menu_id id, int is_next)\r
325{\r
326 int i = me_id2offset(entries, count, id);\r
327 menu_entry *entry = &entries[i];\r
328 switch (entry->beh)\r
329 {\r
330 case MB_ONOFF:\r
331 *(int *)entry->var ^= entry->mask;\r
332 return 1;\r
333 case MB_RANGE:\r
334 *(int *)entry->var += is_next ? 1 : -1;\r
335 if (*(int *)entry->var < (int)entry->min) *(int *)entry->var = (int)entry->min;\r
336 if (*(int *)entry->var > (int)entry->max) *(int *)entry->var = (int)entry->max;\r
337 return 1;\r
338 default:\r
339 return 0;\r
340 }\r
341}\r
342\r
58c86d00 343const char *me_region_name(unsigned int code, int auto_order)\r
344{\r
345 static const char *names[] = { "Auto", " Japan NTSC", " Japan PAL", " USA", " Europe" };\r
346 static const char *names_short[] = { "", " JP", " JP", " US", " EU" };\r
347 int u, i = 0;\r
348 if (code) {\r
349 code <<= 1;\r
350 while((code >>= 1)) i++;\r
351 if (i > 4) return "unknown";\r
352 return names[i];\r
353 } else {\r
354 static char name[24];\r
355 strcpy(name, "Auto:");\r
356 for (u = 0; u < 3; u++) {\r
357 i = 0; code = ((auto_order >> u*4) & 0xf) << 1;\r
358 while((code >>= 1)) i++;\r
359 strcat(name, names_short[i]);\r
360 }\r
361 return name;\r
362 }\r
363}\r
e5f426aa 364\r