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