some work on PSP CLUT
[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)\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
173         return -1;\r
174 }\r
175 \r
176 void 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
237 int 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
249 void 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
255 int 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
267 menu_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
283 void 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
306 int 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
325 \r
326 \r