initial psp code, functional menu
[libpicofe.git] / common / menu.c
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
17  #include "../gp2x/gp2x.h"\r
18  #define SCREEN_WIDTH 320\r
19  #define SCREEN_BUFFER gp2x_screen\r
20 #elif defined(__GIZ__)\r
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
25 #elif defined(PSP)\r
26  #include "../psp/psp.h"\r
27  #define SCREEN_WIDTH 512\r
28  #define SCREEN_BUFFER psp_screen\r
29 #endif\r
30 \r
31 char menuErrorMsg[64] = { 0, };\r
32 \r
33 static unsigned char menu_font_data[10240];\r
34 static int menu_text_color = 0xffff; // default to white\r
35 static int menu_sel_color = -1; // disabled\r
36 \r
37 // draws text to current bbp16 screen\r
38 static 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
86 void 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
99 void 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
131 void 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
143 void 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
163 static int parse_hex_color(char *buff)\r
164 {\r
165         char *endp = buff;\r
166         int t = (int) strtoul(buff, &endp, 16);\r
167         if (endp != buff) return ((t>>8)&0xf800) | ((t>>5)&0x07e0) | ((t>>3)&0x1f);\r
168         return -1;\r
169 }\r
170 \r
171 void menu_init(void)\r
172 {\r
173         int c, l;\r
174         unsigned char *fd = menu_font_data;\r
175         char buff[256];\r
176         FILE *f;\r
177 \r
178         // generate default font from fontdata8x8\r
179         memset(menu_font_data, 0, sizeof(menu_font_data));\r
180         for (c = 0; c < 256; c++)\r
181         {\r
182                 for (l = 0; l < 8; l++)\r
183                 {\r
184                         unsigned char fd8x8 = fontdata8x8[c*8+l];\r
185                         if (fd8x8&0x80) *fd |= 0xf0;\r
186                         if (fd8x8&0x40) *fd |= 0x0f; fd++;\r
187                         if (fd8x8&0x20) *fd |= 0xf0;\r
188                         if (fd8x8&0x10) *fd |= 0x0f; fd++;\r
189                         if (fd8x8&0x08) *fd |= 0xf0;\r
190                         if (fd8x8&0x04) *fd |= 0x0f; fd++;\r
191                         if (fd8x8&0x02) *fd |= 0xf0;\r
192                         if (fd8x8&0x01) *fd |= 0x0f; fd++;\r
193                 }\r
194                 fd += 8*2/2; // 2 empty lines\r
195         }\r
196 \r
197         // load custom font and selector (stored as 1st symbol in font table)\r
198         readpng(menu_font_data, "skin/font.png", READPNG_FONT);\r
199         memcpy(menu_font_data, menu_font_data + ((int)'>')*4*10, 4*10); // default selector symbol is '>'\r
200         readpng(menu_font_data, "skin/selector.png", READPNG_SELECTOR);\r
201 \r
202         // load custom colors\r
203         f = fopen("skin/skin.txt", "r");\r
204         if (f != NULL)\r
205         {\r
206                 lprintf("found skin.txt\n");\r
207                 while (!feof(f))\r
208                 {\r
209                         fgets(buff, sizeof(buff), f);\r
210                         if (buff[0] == '#'  || buff[0] == '/')  continue; // comment\r
211                         if (buff[0] == '\r' || buff[0] == '\n') continue; // empty line\r
212                         if (strncmp(buff, "text_color=", 11) == 0)\r
213                         {\r
214                                 int tmp = parse_hex_color(buff+11);\r
215                                 if (tmp >= 0) menu_text_color = tmp;\r
216                                 else lprintf("skin.txt: parse error for text_color\n");\r
217                         }\r
218                         else if (strncmp(buff, "selection_color=", 16) == 0)\r
219                         {\r
220                                 int tmp = parse_hex_color(buff+16);\r
221                                 if (tmp >= 0) menu_sel_color = tmp;\r
222                                 else lprintf("skin.txt: parse error for selection_color\n");\r
223                                 lprintf("sel color: %04x\n", menu_sel_color);\r
224                         }\r
225                         else\r
226                                 lprintf("skin.txt: parse error: %s\n", buff);\r
227                 }\r
228                 fclose(f);\r
229         }\r
230 }\r
231 \r
232 \r
233 int me_id2offset(const menu_entry *entries, int count, menu_id id)\r
234 {\r
235         int i;\r
236         for (i = 0; i < count; i++)\r
237         {\r
238                 if (entries[i].id == id) return i;\r
239         }\r
240 \r
241         lprintf("%s: id %i not found\n", __FUNCTION__, id);\r
242         return 0;\r
243 }\r
244 \r
245 void me_enable(menu_entry *entries, int count, menu_id id, int enable)\r
246 {\r
247         int i = me_id2offset(entries, count, id);\r
248         entries[i].enabled = enable;\r
249 }\r
250 \r
251 int me_count_enabled(const menu_entry *entries, int count)\r
252 {\r
253         int i, ret = 0;\r
254 \r
255         for (i = 0; i < count; i++)\r
256         {\r
257                 if (entries[i].enabled) ret++;\r
258         }\r
259 \r
260         return ret;\r
261 }\r
262 \r
263 menu_id me_index2id(const menu_entry *entries, int count, int index)\r
264 {\r
265         int i;\r
266 \r
267         for (i = 0; i < count; i++)\r
268         {\r
269                 if (entries[i].enabled)\r
270                 {\r
271                         if (index == 0) break;\r
272                         index--;\r
273                 }\r
274         }\r
275         if (i >= count) i = count - 1;\r
276         return entries[i].id;\r
277 }\r
278 \r
279 void me_draw(const menu_entry *entries, int count, int x, int y, me_draw_custom_f *cust_draw, void *param)\r
280 {\r
281         int i, y1 = y;\r
282 \r
283         for (i = 0; i < count; i++)\r
284         {\r
285                 if (!entries[i].enabled) continue;\r
286                 if (entries[i].name == NULL)\r
287                 {\r
288                         if (cust_draw != NULL)\r
289                                 cust_draw(&entries[i], x, y1, param);\r
290                         y1 += 10;\r
291                         continue;\r
292                 }\r
293                 text_out16(x, y1, entries[i].name);\r
294                 if (entries[i].beh == MB_ONOFF)\r
295                         text_out16(x + 27*8, y1, (*(int *)entries[i].var & entries[i].mask) ? "ON" : "OFF");\r
296                 else if (entries[i].beh == MB_RANGE)\r
297                         text_out16(x + 27*8, y1, "%i", *(int *)entries[i].var);\r
298                 y1 += 10;\r
299         }\r
300 }\r
301 \r
302 int me_process(menu_entry *entries, int count, menu_id id, int is_next)\r
303 {\r
304         int i = me_id2offset(entries, count, id);\r
305         menu_entry *entry = &entries[i];\r
306         switch (entry->beh)\r
307         {\r
308                 case MB_ONOFF:\r
309                         *(int *)entry->var ^= entry->mask;\r
310                         return 1;\r
311                 case MB_RANGE:\r
312                         *(int *)entry->var += is_next ? 1 : -1;\r
313                         if (*(int *)entry->var < (int)entry->min) *(int *)entry->var = (int)entry->min;\r
314                         if (*(int *)entry->var > (int)entry->max) *(int *)entry->var = (int)entry->max;\r
315                         return 1;\r
316                 default:\r
317                         return 0;\r
318         }\r
319 }\r
320 \r
321 \r
322 \r