giz menu
[libpicofe.git] / common / menu.c
CommitLineData
c7a4ff64 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
7695af0a 23#define SCREEN_BUFFER menu_screen\r
24extern unsigned char menu_screen[321*240*2];\r
c7a4ff64 25#endif\r
26\r
27static unsigned char menu_font_data[10240];\r
28static int menu_text_color = 0xffff; // default to white\r
29static int menu_sel_color = -1; // disabled\r
30\r
31// draws text to current bbp16 screen\r
32static 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
80void 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
93void 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
125void 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
137void 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
157static 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
165void 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
226int 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
238void 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
244int 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
256menu_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
272void 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
295int 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