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