final adjustments for Giz release
[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
f013066e 17 #include "../gp2x/gp2x.h"\r
18 #define SCREEN_WIDTH 320\r
19 #define SCREEN_BUFFER gp2x_screen\r
c7a4ff64 20#elif defined(__GIZ__)\r
f013066e 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
c7a4ff64 25#endif\r
26\r
f013066e 27char menuErrorMsg[64] = { 0, };\r
28\r
c7a4ff64 29static unsigned char menu_font_data[10240];\r
30static int menu_text_color = 0xffff; // default to white\r
31static int menu_sel_color = -1; // disabled\r
32\r
33// draws text to current bbp16 screen\r
34static 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
82void 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
95void 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
127void 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
139void 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
159static 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
167void 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
228int 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
240void 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
246int 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
258menu_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
274void 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
297int 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