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