Bump version numbers for 3.13
[maemo-rb.git] / apps / plugins / rockboy / menu.c
blob3cd231c06c0fd64aab97be7b46745ee13f68c1b0
1 /*********************************************************************/
2 /* menu.c - user menu for rockboy */
3 /* */
4 /* Note: this file only exposes one function: do_user_menu(). */
5 /*********************************************************************/
7 #include "lib/helper.h"
8 #include "button.h"
9 #include "rockmacros.h"
10 #include "mem.h"
11 #include "save.h"
12 #include "rtc-gb.h"
13 #include "pcm.h"
14 #include "emu.h"
15 #include "loader.h"
17 #define SLOT_COUNT 50
18 #define DESC_SIZE 20
20 /* load/save state function declarations */
21 static void do_opt_menu(void);
22 static void do_slot_menu(bool is_load);
23 static void munge_name(char *buf, size_t bufsiz);
25 /* directory ROM save slots belong in */
26 #define STATE_DIR ROCKBOX_DIR "/rockboy"
28 static int getbutton(char *text)
30 int fw, fh;
31 int button;
32 rb->lcd_clear_display();
33 rb->font_getstringsize(text, &fw, &fh,0);
34 rb->lcd_putsxy(LCD_WIDTH/2-fw/2, LCD_HEIGHT/2-fh/2, text);
35 rb->lcd_update();
36 rb->sleep(30);
38 while (rb->button_get(false) != BUTTON_NONE)
39 rb->yield();
41 while(true)
43 button = rb->button_get(true);
44 button = button&(BUTTON_MAIN|BUTTON_REMOTE);
46 return button;
50 static void setupkeys(void)
52 options.UP = getbutton("Press Up");
53 options.DOWN = getbutton("Press Down");
54 options.LEFT = getbutton("Press Left");
55 options.RIGHT = getbutton("Press Right");
57 options.A = getbutton("Press A");
58 options.B = getbutton("Press B");
60 options.START = getbutton("Press Start");
61 options.SELECT = getbutton("Press Select");
63 options.MENU = getbutton("Press Menu");
67 * do_user_menu - create the user menu on the screen.
69 * Returns USER_MENU_QUIT if the user selected "quit", otherwise
70 * returns zero.
72 int do_user_menu(void) {
73 bool done=false;
74 int selected=0, ret=0;
75 int result;
76 int time = 0;
78 #if CONFIG_RTC
79 time = rb->mktime(rb->get_time());
80 #endif
82 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
83 rb->lcd_set_mode(LCD_MODE_RGB565);
84 #endif
86 backlight_use_settings();
88 /* Clean out the button Queue */
89 while (rb->button_get(false) != BUTTON_NONE)
90 rb->yield();
92 MENUITEM_STRINGLIST(menu, "Rockboy Menu", NULL,
93 "Load Game", "Save Game",
94 "Options", "Reset", "Quit");
96 rockboy_pcm_init();
98 while(!done)
100 result = rb->do_menu(&menu, &selected, NULL, false);
102 switch (result)
104 case 0: /* Load Game */
105 do_slot_menu(true);
106 break;
107 case 1: /* Save Game */
108 do_slot_menu(false);
109 break;
110 case 2: /* Options */
111 do_opt_menu();
112 break;
113 case 3: /* Reset */
114 emu_reset();
115 done=true;
116 break;
117 case 4: /* Quit */
118 ret = USER_MENU_QUIT;
119 if(options.autosave) sn_save();
120 done=true;
121 break;
122 default:
123 done=true;
124 break;
128 rb->lcd_setfont(FONT_SYSFIXED); /* Reset the font */
129 rb->lcd_clear_display(); /* Clear display for screen size changes */
131 /* Keep the RTC in sync */
132 #if CONFIG_RTC
133 time = (rb->mktime(rb->get_time()) - time) * 60;
134 #endif
135 while (time-- > 0) rtc_tick();
137 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
138 rb->lcd_set_mode(LCD_MODE_PAL256);
139 #endif
141 /* ignore backlight time out */
142 backlight_ignore_timeout();
144 return ret;
148 * munge_name - munge a string into a filesystem-safe name
150 static void munge_name(char *buf, const size_t bufsiz) {
151 unsigned int i, max;
153 /* check strlen */
154 max = strlen(buf);
155 max = (max < bufsiz) ? max : bufsiz;
157 /* iterate over characters and munge them (if necessary) */
158 for (i = 0; i < max; i++)
159 if (!isalnum(buf[i]))
160 buf[i] = '_';
164 * build_slot_path - build a path to an slot state file for this rom
166 * Note: uses rom.name. Is there a safer way of doing this? Like a ROM
167 * checksum or something like that?
169 static void build_slot_path(char *buf, size_t bufsiz, int slot_id) {
170 char name_buf[17];
172 /* munge state file name */
173 strlcpy(name_buf, rom.name, sizeof(name_buf));
174 munge_name(name_buf, strlen(name_buf));
176 /* glom the whole mess together */
177 snprintf(buf, bufsiz, "%s/%s-%d.rbs", STATE_DIR, name_buf, slot_id + 1);
181 * do_file - load or save game data in the given file
183 * Returns true on success and false on failure.
185 * @desc is a brief user-provided description of the state.
186 * If no description is provided, set @desc to NULL.
189 static bool do_file(char *path, char *desc, bool is_load) {
190 char desc_buf[DESC_SIZE];
191 int fd, file_mode;
193 /* set file mode */
194 file_mode = is_load ? O_RDONLY : (O_WRONLY | O_CREAT);
196 /* attempt to open file descriptor here */
197 if ((fd = open(path, file_mode, 0666)) < 0)
198 return false;
200 /* load/save state */
201 if (is_load)
203 /* load description */
204 read(fd, desc_buf, sizeof(desc_buf));
206 /* load state */
207 loadstate(fd);
209 /* print out a status message so the user knows the state loaded */
210 rb->splashf(HZ * 1, "Loaded state from \"%s\"", path);
212 else
214 /* build description buffer */
215 memset(desc_buf, 0, sizeof(desc_buf));
216 if (desc)
217 strlcpy(desc_buf, desc, sizeof(desc_buf));
219 /* save state */
220 write(fd, desc_buf, sizeof(desc_buf));
221 savestate(fd);
224 /* close file descriptor */
225 close(fd);
227 /* return true (for success) */
228 return true;
232 * get information on the given slot
234 static void slot_info(char *info_buf, size_t info_bufsiz, int slot_id,
235 bool number) {
236 char buf[256];
237 int fd;
239 /* get slot file path */
240 build_slot_path(buf, sizeof(buf), slot_id);
242 /* attempt to open slot */
243 if ((fd = open(buf, O_RDONLY)) >= 0)
245 /* this slot has a some data in it, read it */
246 if (read(fd, buf, DESC_SIZE) == DESC_SIZE)
248 buf[DESC_SIZE] = '\0';
249 strlcpy(info_buf, buf, info_bufsiz);
251 else if(number)
252 strlcpy(info_buf, "ERROR", info_bufsiz);
254 close(fd);
256 else if(number)
258 /* if we couldn't open the file, then the slot is empty */
259 strlcpy(info_buf, "<Empty>", info_bufsiz);
264 * do_slot - load or save game data in the given slot
266 * Returns true on success and false on failure.
268 static bool do_slot(int slot_id, bool is_load) {
269 char path_buf[256], desc_buf[DESC_SIZE];
271 /* build slot filename, clear desc buf */
272 build_slot_path(path_buf, sizeof(path_buf), slot_id);
273 memset(desc_buf, 0, sizeof(desc_buf));
275 /* if we're saving to a slot, then get a brief description */
276 if (!is_load)
278 slot_info(desc_buf, sizeof(desc_buf), slot_id, false);
279 if ( rb->kbd_input(desc_buf, sizeof(desc_buf)) < 0 )
280 return false;
281 if ( !strlen(desc_buf) )
282 strlcpy(desc_buf, "Untitled", sizeof(desc_buf));
285 /* load/save file */
286 return do_file(path_buf, desc_buf, is_load);
290 * slot_get_name
292 static const char* slot_get_name(int selected_item, void * data,
293 char * buffer, size_t buffer_len)
295 const char (*items)[DESC_SIZE] = data;
296 snprintf(buffer, buffer_len, "%d. %s",
297 selected_item + 1, items[selected_item]);
298 return buffer;
302 * list_action_callback
304 static int list_action_callback(int action, struct gui_synclist *lists)
306 (void) lists;
307 if (action == ACTION_STD_OK)
308 return ACTION_STD_CANCEL;
309 return action;
313 * do_slot_menu - prompt the user for a load/save memory slot
315 static void do_slot_menu(bool is_load) {
316 bool done=false;
317 char items[SLOT_COUNT][DESC_SIZE];
318 int result;
319 int i;
320 struct simplelist_info info;
322 /* create menu items */
323 for (i = 0; i < SLOT_COUNT; i++)
324 slot_info(items[i], sizeof(*items), i, true);
326 rb->simplelist_info_init(&info, NULL, SLOT_COUNT, (void *)items);
327 info.get_name = slot_get_name;
328 info.action_callback = list_action_callback;
330 while(!done)
332 if(rb->simplelist_show_list(&info))
333 break;
335 result = info.selection;
336 if (result<SLOT_COUNT && result >= 0 )
337 done = do_slot(result, is_load);
338 else
339 done = true;
343 static void do_opt_menu(void)
345 bool done=false;
346 int selected=0;
347 int result;
349 static const struct opt_items onoff[2] = {
350 { "Off", -1 },
351 { "On" , -1 },
354 static const struct opt_items stats[3] = {
355 { "Off", -1 },
356 { "Short" , -1 },
357 { "Full" , -1 },
360 static const struct opt_items frameskip[]= {
361 { "0 Max", -1 },
362 { "1 Max", -1 },
363 { "2 Max", -1 },
364 { "3 Max", -1 },
365 { "4 Max", -1 },
366 { "5 Max", -1 },
367 { "6 Max", -1 },
368 { "7 Max", -1 },
369 { "8 Max", -1 },
370 { "9 Max", -1 },
371 { "10 Max", -1 },
372 { "11 Max", -1 },
373 { "12 Max", -1 },
374 { "13 Max", -1 },
375 { "14 Max", -1 },
376 { "15 Max", -1 },
377 { "16 Max", -1 },
378 { "17 Max", -1 },
379 { "18 Max", -1 },
380 { "19 Max", -1 },
381 { "20 Max", -1 },
384 #ifdef HAVE_LCD_COLOR
385 static const struct opt_items rotate[] = {
386 { "No rotation", -1 },
387 { "Rotate Right" , -1 },
388 { "Rotate Left" , -1 },
391 static const struct opt_items scaling[]= {
392 { "Scaled", -1 },
393 { "Scaled - Maintain Ratio", -1 },
394 #if (LCD_WIDTH>=160) && (LCD_HEIGHT>=144)
395 { "Unscaled", -1 },
396 #endif
399 static const struct opt_items palette[]= {
400 { "Brown (Default)", -1 },
401 { "Gray", -1 },
402 { "Light Gray", -1 },
403 { "Multi-Color 1", -1 },
404 { "Multi-Color 2", -1 },
405 { "Adventure Island", -1 },
406 { "Adventure Island 2", -1 },
407 { "Balloon Kid", -1 },
408 { "Batman", -1 },
409 { "Batman: Return of Joker", -1 },
410 { "Bionic Commando", -1 },
411 { "Castlvania Adventure", -1 },
412 { "Donkey Kong Land", -1 },
413 { "Dr. Mario", -1 },
414 { "Kirby", -1 },
415 { "Metroid", -1 },
416 { "Zelda", -1 },
418 #endif
420 MENUITEM_STRINGLIST(menu, "Options", NULL,
421 "Max Frameskip", "Autosave", "Sound", "Volume",
422 "Stats", "Set Keys (Buggy)",
423 #ifdef HAVE_LCD_COLOR
424 "Screen Size", "Screen Rotate", "Set Palette",
425 #endif
428 options.dirty=1; /* Assume that the settings have been changed */
430 struct viewport *parentvp = NULL;
431 const struct settings_list* vol = rb->find_setting(&rb->global_settings->volume, NULL);
433 while(!done)
435 result = rb->do_menu(&menu, &selected, NULL, false);
437 switch (result)
439 case 0: /* Frameskip */
440 rb->set_option("Max Frameskip", &options.maxskip, INT, frameskip,
441 sizeof(frameskip)/sizeof(*frameskip), NULL );
442 break;
443 case 1: /* Autosave */
444 rb->set_option("Autosave", &options.autosave, INT, onoff, 2, NULL );
445 break;
446 case 2: /* Sound */
447 if(options.sound>1) options.sound=1;
448 rb->set_option("Sound", &options.sound, INT, onoff, 2, NULL );
449 if(options.sound) sound_dirty();
450 break;
451 case 3: /* Volume */
452 rb->option_screen((struct settings_list*)vol, parentvp, false, "Volume");
453 break;
454 case 4: /* Stats */
455 rb->set_option("Stats", &options.showstats, INT, stats, 3, NULL );
456 break;
457 case 5: /* Keys */
458 setupkeys();
459 break;
460 #ifdef HAVE_LCD_COLOR
461 case 6: /* Screen Size */
462 rb->set_option("Screen Size", &options.scaling, INT, scaling,
463 sizeof(scaling)/sizeof(*scaling), NULL );
464 setvidmode();
465 break;
466 case 7: /* Screen rotate */
467 rb->set_option("Screen Rotate", &options.rotate, INT, rotate,
468 sizeof(rotate)/sizeof(*rotate), NULL );
469 setvidmode();
470 break;
471 case 8: /* Palette */
472 rb->set_option("Set Palette", &options.pal, INT, palette, 17, NULL );
473 set_pal();
474 break;
475 #endif
476 default:
477 done=true;
478 break;