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