fix FS#8187 - charging breaks sleep timer. Now if the timer goes off and the player...
[Rockbox.git] / apps / plugins / rockboy / menu.c
blobfe0b72d1334e42d51a1a0034300301236859efe6
1 /*********************************************************************/
2 /* menu.c - user menu for rockboy */
3 /* */
4 /* Note: this file only exposes one function: do_user_menu(). */
5 /*********************************************************************/
7 #include "button.h"
8 #include "rockmacros.h"
9 #include "mem.h"
10 #include "save.h"
11 #include "lib/oldmenuapi.h"
12 #include "rtc-gb.h"
13 #include "pcm.h"
15 #if CONFIG_KEYPAD == IPOD_4G_PAD
16 #define MENU_BUTTON_UP BUTTON_SCROLL_BACK
17 #define MENU_BUTTON_DOWN BUTTON_SCROLL_FWD
18 #define MENU_BUTTON_LEFT BUTTON_LEFT
19 #define MENU_BUTTON_RIGHT BUTTON_RIGHT
21 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
22 #define MENU_BUTTON_UP BUTTON_SCROLL_UP
23 #define MENU_BUTTON_DOWN BUTTON_SCROLL_DOWN
24 #define MENU_BUTTON_LEFT BUTTON_LEFT
25 #define MENU_BUTTON_RIGHT BUTTON_RIGHT
27 #else
28 #define MENU_BUTTON_UP BUTTON_UP
29 #define MENU_BUTTON_DOWN BUTTON_DOWN
30 #define MENU_BUTTON_LEFT BUTTON_LEFT
31 #define MENU_BUTTON_RIGHT BUTTON_RIGHT
32 #endif
34 /* load/save state function declarations */
35 static void do_opt_menu(void);
36 static void do_slot_menu(bool is_load);
37 static void munge_name(char *buf, size_t bufsiz);
39 /* directory ROM save slots belong in */
40 #define STATE_DIR ROCKBOX_DIR "/rockboy"
42 static int getbutton(char *text)
44 int fw, fh;
45 rb->lcd_clear_display();
46 rb->font_getstringsize(text, &fw, &fh,0);
47 rb->lcd_putsxy(LCD_WIDTH/2-fw/2, LCD_HEIGHT/2-fh/2, text);
48 rb->lcd_update();
49 rb->sleep(30);
51 while (rb->button_get(false) != BUTTON_NONE)
52 rb->yield();
54 int button;
55 while(true)
57 button = rb->button_get(true);
58 button=button&0x00000FFF;
60 return button;
64 static void setupkeys(void)
66 options.UP=getbutton ("Press Up");
67 options.DOWN=getbutton ("Press Down");
68 options.LEFT=getbutton ("Press Left");
69 options.RIGHT=getbutton ("Press Right");
71 options.A=getbutton ("Press A");
72 options.B=getbutton ("Press B");
74 options.START=getbutton ("Press Start");
75 options.SELECT=getbutton("Press Select");
77 options.MENU=getbutton ("Press Menu");
81 * do_user_menu - create the user menu on the screen.
83 * Returns USER_MENU_QUIT if the user selected "quit", otherwise
84 * returns zero.
86 int do_user_menu(void) {
87 bool done=false;
88 int m, ret=0;
89 int result;
90 int time = 0;
92 #if CONFIG_RTC
93 time = rb->mktime(rb->get_time());
94 #endif
96 /* Clean out the button Queue */
97 while (rb->button_get(false) != BUTTON_NONE)
98 rb->yield();
100 static const struct menu_item items[] = {
101 {"Load Game", NULL },
102 {"Save Game", NULL },
103 {"Options", NULL },
104 {"Quit", NULL },
107 pcm_init();
109 m = menu_init(rb,items, sizeof(items) / sizeof(*items), NULL, NULL, NULL, NULL);
111 while(!done)
113 result=menu_show(m);
115 switch (result)
117 case 0: /* Load Game */
118 do_slot_menu(true);
119 break;
120 case 1: /* Save Game */
121 do_slot_menu(false);
122 break;
123 case 2: /* Options */
124 do_opt_menu();
125 break;
126 case 3: /* Quit */
127 ret = USER_MENU_QUIT;
128 done=true;
129 break;
130 default:
131 done=true;
132 break;
136 menu_exit(m);
138 rb->lcd_setfont(0); /* Reset the font */
139 rb->lcd_clear_display(); /* Clear display for screen size changes */
141 /* Keep the RTC in sync */
142 #if CONFIG_RTC
143 time = (rb->mktime(rb->get_time()) - time) * 60;
144 #endif
145 while (time-- > 0) rtc_tick();
147 return ret;
151 * munge_name - munge a string into a filesystem-safe name
153 static void munge_name(char *buf, const size_t bufsiz) {
154 unsigned int i, max;
156 /* check strlen */
157 max = strlen(buf);
158 max = (max < bufsiz) ? max : bufsiz;
160 /* iterate over characters and munge them (if necessary) */
161 for (i = 0; i < max; i++)
162 if (!isalnum(buf[i]))
163 buf[i] = '_';
167 * build_slot_path - build a path to an slot state file for this rom
169 * Note: uses rom.name. Is there a safer way of doing this? Like a ROM
170 * checksum or something like that?
172 static void build_slot_path(char *buf, size_t bufsiz, size_t slot_id) {
173 char name_buf[40];
175 /* munge state file name */
176 strncpy(name_buf, rom.name, 40);
177 name_buf[16] = '\0';
178 munge_name(name_buf, strlen(name_buf));
180 /* glom the whole mess together */
181 snprintf(buf, bufsiz, "%s/%s-%ld.rbs", STATE_DIR, name_buf, slot_id + 1);
185 * do_file - load or save game data in the given file
187 * Returns true on success and false on failure.
189 * @desc is a brief user-provided description (<20 bytes) of the state.
190 * If no description is provided, set @desc to NULL.
193 static bool do_file(char *path, char *desc, bool is_load) {
194 char buf[200], desc_buf[20];
195 int fd, file_mode;
197 /* set file mode */
198 file_mode = is_load ? O_RDONLY : (O_WRONLY | O_CREAT);
200 /* attempt to open file descriptor here */
201 if ((fd = open(path, file_mode)) <= 0)
202 return false;
204 /* load/save state */
205 if (is_load)
207 /* load description */
208 read(fd, desc_buf, 20);
210 /* load state */
211 loadstate(fd);
213 /* print out a status message so the user knows the state loaded */
214 snprintf(buf, 200, "Loaded state from \"%s\"", path);
215 rb->splash(HZ * 1, buf);
217 else
219 /* build description buffer */
220 memset(desc_buf, 0, 20);
221 if (desc)
222 strncpy(desc_buf, desc, 20);
224 /* save state */
225 write(fd, desc_buf, 20);
226 savestate(fd);
229 /* close file descriptor */
230 close(fd);
232 /* return true (for success) */
233 return true;
237 * do_slot - load or save game data in the given slot
239 * Returns true on success and false on failure.
241 static bool do_slot(size_t slot_id, bool is_load) {
242 char path_buf[256], desc_buf[20];
244 /* build slot filename, clear desc buf */
245 build_slot_path(path_buf, 256, slot_id);
246 memset(desc_buf, 0, 20);
248 /* if we're saving to a slot, then get a brief description */
249 if (!is_load)
250 if (rb->kbd_input(desc_buf, 20) || !strlen(desc_buf))
252 memset(desc_buf, 0, 20);
253 strncpy(desc_buf, "Untitled", 20);
256 /* load/save file */
257 return do_file(path_buf, desc_buf, is_load);
261 * get information on the given slot
263 static void slot_info(char *info_buf, size_t info_bufsiz, size_t slot_id) {
264 char buf[256];
265 int fd;
267 /* get slot file path */
268 build_slot_path(buf, 256, slot_id);
270 /* attempt to open slot */
271 if ((fd = open(buf, O_RDONLY)) >= 0)
273 /* this slot has a some data in it, read it */
274 if (read(fd, buf, 20) > 0)
276 buf[20] = '\0';
277 snprintf(info_buf, info_bufsiz, "%ld. %s", slot_id + 1, buf);
279 else
280 snprintf(info_buf, info_bufsiz, "%ld. ERROR", slot_id + 1);
282 close(fd);
284 else
286 /* if we couldn't open the file, then the slot is empty */
287 snprintf(info_buf, info_bufsiz, "%ld. %s", slot_id + 1, "<Empty>");
292 * do_slot_menu - prompt the user for a load/save memory slot
294 static void do_slot_menu(bool is_load) {
295 bool done=false;
297 char buf[5][20];
299 int m;
300 int result;
301 int i;
303 struct menu_item items[] = {
304 { buf[0] , NULL },
305 { buf[1] , NULL },
306 { buf[2] , NULL },
307 { buf[3] , NULL },
308 { buf[4] , NULL },
311 int num_items = sizeof(items) / sizeof(*items);
313 /* create menu items */
314 for (i = 0; i < num_items; i++)
315 slot_info(buf[i], 20, i);
317 m = menu_init(rb,items, num_items, NULL, NULL, NULL, NULL);
319 while(!done)
321 result=menu_show(m);
323 if (result<num_items && result >= 0 )
324 done = do_slot(result, is_load);
325 else
326 done = true;
328 menu_exit(m);
331 static void do_opt_menu(void)
333 bool done=false;
334 int m;
335 int result;
337 static const struct opt_items onoff[2] = {
338 { "Off", -1 },
339 { "On" , -1 },
342 static const struct opt_items frameskip[]= {
343 { "0 Max", -1 },
344 { "1 Max", -1 },
345 { "2 Max", -1 },
346 { "3 Max", -1 },
347 { "4 Max", -1 },
348 { "5 Max", -1 },
349 { "6 Max", -1 },
352 #ifdef HAVE_LCD_COLOR
353 static const struct opt_items scaling[]= {
354 { "Scaled", -1 },
355 { "Scaled - Maintain Ratio", -1 },
356 #if (LCD_WIDTH>=160) && (LCD_HEIGHT>=144)
357 { "Unscaled", -1 },
358 #endif
361 static const struct opt_items palette[]= {
362 { "Brown (Default)", -1 },
363 { "Gray", -1 },
364 { "Light Gray", -1 },
365 { "Multi-Color 1", -1 },
366 { "Multi-Color 2", -1 },
367 { "Adventure Island", -1 },
368 { "Adventure Island 2", -1 },
369 { "Balloon Kid", -1 },
370 { "Batman", -1 },
371 { "Batman: Return of Joker", -1 },
372 { "Bionic Commando", -1 },
373 { "Castlvania Adventure", -1 },
374 { "Donkey Kong Land", -1 },
375 { "Dr. Mario", -1 },
376 { "Kirby", -1 },
377 { "Metroid", -1 },
378 { "Zelda", -1 },
380 #endif
382 static const struct menu_item items[] = {
383 { "Max Frameskip", NULL },
384 { "Sound" , NULL },
385 { "Stats" , NULL },
386 { "Set Keys (Buggy)", NULL },
387 #ifdef HAVE_LCD_COLOR
388 { "Screen Size" , NULL },
389 { "Screen Rotate" , NULL },
390 { "Set Palette" , NULL },
391 #endif
394 m = menu_init(rb,items, sizeof(items) / sizeof(*items), NULL, NULL, NULL, NULL);
396 options.dirty=1; /* Assume that the settings have been changed */
398 while(!done)
401 result=menu_show(m);
403 switch (result)
405 case 0: /* Frameskip */
406 rb->set_option(items[0].desc, &options.maxskip, INT, frameskip,
407 sizeof(frameskip)/sizeof(*frameskip), NULL );
408 break;
409 case 1: /* Sound */
410 if(options.sound>1) options.sound=1;
411 rb->set_option(items[1].desc, &options.sound, INT, onoff, 2, NULL );
412 if(options.sound) sound_dirty();
413 break;
414 case 2: /* Stats */
415 rb->set_option(items[2].desc, &options.showstats, INT, onoff, 2, NULL );
416 break;
417 case 3: /* Keys */
418 setupkeys();
419 break;
420 #ifdef HAVE_LCD_COLOR
421 case 4: /* Screen Size */
422 rb->set_option(items[4].desc, &options.scaling, INT, scaling,
423 sizeof(scaling)/sizeof(*scaling), NULL );
424 setvidmode();
425 break;
426 case 5: /* Screen rotate */
427 rb->set_option(items[5].desc, &options.rotate, INT, onoff, 2, NULL );
428 setvidmode();
429 break;
430 case 6: /* Palette */
431 rb->set_option(items[6].desc, &options.pal, INT, palette, 17, NULL );
432 set_pal();
433 break;
434 #endif
435 default:
436 done=true;
437 break;
440 menu_exit(m);