1 /*********************************************************************/
2 /* menu.c - user menu for rockboy */
4 /* Note: this file only exposes one function: do_user_menu(). */
5 /*********************************************************************/
7 #include "lib/helper.h"
9 #include "rockmacros.h"
19 /* load/save state function declarations */
20 static void do_opt_menu(void);
21 static void do_slot_menu(bool is_load
);
22 static void munge_name(char *buf
, size_t bufsiz
);
24 /* directory ROM save slots belong in */
25 #define STATE_DIR ROCKBOX_DIR "/rockboy"
27 static int getbutton(char *text
)
31 rb
->lcd_clear_display();
32 rb
->font_getstringsize(text
, &fw
, &fh
,0);
33 rb
->lcd_putsxy(LCD_WIDTH
/2-fw
/2, LCD_HEIGHT
/2-fh
/2, text
);
37 while (rb
->button_get(false) != BUTTON_NONE
)
42 button
= rb
->button_get(true);
43 button
= button
&(BUTTON_MAIN
|BUTTON_REMOTE
);
49 static void setupkeys(void)
51 options
.UP
= getbutton("Press Up");
52 options
.DOWN
= getbutton("Press Down");
53 options
.LEFT
= getbutton("Press Left");
54 options
.RIGHT
= getbutton("Press Right");
56 options
.A
= getbutton("Press A");
57 options
.B
= getbutton("Press B");
59 options
.START
= getbutton("Press Start");
60 options
.SELECT
= getbutton("Press Select");
62 options
.MENU
= getbutton("Press Menu");
66 * do_user_menu - create the user menu on the screen.
68 * Returns USER_MENU_QUIT if the user selected "quit", otherwise
71 int do_user_menu(void) {
73 int selected
=0, ret
=0;
78 time
= rb
->mktime(rb
->get_time());
81 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
82 rb
->lcd_set_mode(LCD_MODE_RGB565
);
85 backlight_use_settings();
87 /* Clean out the button Queue */
88 while (rb
->button_get(false) != BUTTON_NONE
)
91 MENUITEM_STRINGLIST(menu
, "Rockboy Menu", NULL
,
92 "Load Game", "Save Game",
93 "Options", "Reset", "Quit");
99 result
= rb
->do_menu(&menu
, &selected
, NULL
, false);
103 case 0: /* Load Game */
106 case 1: /* Save Game */
109 case 2: /* Options */
117 ret
= USER_MENU_QUIT
;
126 rb
->lcd_setfont(0); /* Reset the font */
127 rb
->lcd_clear_display(); /* Clear display for screen size changes */
129 /* Keep the RTC in sync */
131 time
= (rb
->mktime(rb
->get_time()) - time
) * 60;
133 while (time
-- > 0) rtc_tick();
135 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
136 rb
->lcd_set_mode(LCD_MODE_PAL256
);
139 /* ignore backlight time out */
140 backlight_force_on();
146 * munge_name - munge a string into a filesystem-safe name
148 static void munge_name(char *buf
, const size_t bufsiz
) {
153 max
= (max
< bufsiz
) ? max
: bufsiz
;
155 /* iterate over characters and munge them (if necessary) */
156 for (i
= 0; i
< max
; i
++)
157 if (!isalnum(buf
[i
]))
162 * build_slot_path - build a path to an slot state file for this rom
164 * Note: uses rom.name. Is there a safer way of doing this? Like a ROM
165 * checksum or something like that?
167 static void build_slot_path(char *buf
, size_t bufsiz
, int slot_id
) {
170 /* munge state file name */
171 strlcpy(name_buf
, rom
.name
, sizeof(name_buf
));
172 munge_name(name_buf
, strlen(name_buf
));
174 /* glom the whole mess together */
175 snprintf(buf
, bufsiz
, "%s/%s-%d.rbs", STATE_DIR
, name_buf
, slot_id
+ 1);
179 * do_file - load or save game data in the given file
181 * Returns true on success and false on failure.
183 * @desc is a brief user-provided description of the state.
184 * If no description is provided, set @desc to NULL.
187 static bool do_file(char *path
, char *desc
, bool is_load
) {
188 char desc_buf
[DESC_SIZE
];
192 file_mode
= is_load
? O_RDONLY
: (O_WRONLY
| O_CREAT
);
194 /* attempt to open file descriptor here */
195 if ((fd
= open(path
, file_mode
, 0666)) < 0)
198 /* load/save state */
201 /* load description */
202 read(fd
, desc_buf
, sizeof(desc_buf
));
207 /* print out a status message so the user knows the state loaded */
208 rb
->splashf(HZ
* 1, "Loaded state from \"%s\"", path
);
212 /* build description buffer */
213 memset(desc_buf
, 0, sizeof(desc_buf
));
215 strlcpy(desc_buf
, desc
, sizeof(desc_buf
));
218 write(fd
, desc_buf
, sizeof(desc_buf
));
222 /* close file descriptor */
225 /* return true (for success) */
230 * get information on the given slot
232 static void slot_info(char *info_buf
, size_t info_bufsiz
, int slot_id
,
237 /* get slot file path */
238 build_slot_path(buf
, sizeof(buf
), slot_id
);
240 /* attempt to open slot */
241 if ((fd
= open(buf
, O_RDONLY
)) >= 0)
243 /* this slot has a some data in it, read it */
244 if (read(fd
, buf
, DESC_SIZE
) == DESC_SIZE
)
246 buf
[DESC_SIZE
] = '\0';
247 strlcpy(info_buf
, buf
, info_bufsiz
);
250 strlcpy(info_buf
, "ERROR", info_bufsiz
);
256 /* if we couldn't open the file, then the slot is empty */
257 strlcpy(info_buf
, "<Empty>", info_bufsiz
);
262 * do_slot - load or save game data in the given slot
264 * Returns true on success and false on failure.
266 static bool do_slot(int slot_id
, bool is_load
) {
267 char path_buf
[256], desc_buf
[DESC_SIZE
];
269 /* build slot filename, clear desc buf */
270 build_slot_path(path_buf
, sizeof(path_buf
), slot_id
);
271 memset(desc_buf
, 0, sizeof(desc_buf
));
273 /* if we're saving to a slot, then get a brief description */
276 slot_info(desc_buf
, sizeof(desc_buf
), slot_id
, false);
277 if ( rb
->kbd_input(desc_buf
, sizeof(desc_buf
)) < 0 )
279 if ( !strlen(desc_buf
) )
280 strlcpy(desc_buf
, "Untitled", sizeof(desc_buf
));
284 return do_file(path_buf
, desc_buf
, is_load
);
290 static const char* slot_get_name(int selected_item
, void * data
,
291 char * buffer
, size_t buffer_len
)
293 const char (*items
)[DESC_SIZE
] = data
;
294 snprintf(buffer
, buffer_len
, "%d. %s",
295 selected_item
+ 1, items
[selected_item
]);
300 * list_action_callback
302 static int list_action_callback(int action
, struct gui_synclist
*lists
)
305 if (action
== ACTION_STD_OK
)
306 return ACTION_STD_CANCEL
;
311 * do_slot_menu - prompt the user for a load/save memory slot
313 static void do_slot_menu(bool is_load
) {
315 char items
[SLOT_COUNT
][DESC_SIZE
];
318 struct simplelist_info info
;
320 /* create menu items */
321 for (i
= 0; i
< SLOT_COUNT
; i
++)
322 slot_info(items
[i
], sizeof(*items
), i
, true);
324 rb
->simplelist_info_init(&info
, NULL
, SLOT_COUNT
, (void *)items
);
325 info
.get_name
= slot_get_name
;
326 info
.action_callback
= list_action_callback
;
330 if(rb
->simplelist_show_list(&info
))
333 result
= info
.selection
;
334 if (result
<SLOT_COUNT
&& result
>= 0 )
335 done
= do_slot(result
, is_load
);
341 static void do_opt_menu(void)
347 static const struct opt_items onoff
[2] = {
352 static const struct opt_items stats
[3] = {
358 static const struct opt_items frameskip
[]= {
382 #ifdef HAVE_LCD_COLOR
383 static const struct opt_items rotate
[] = {
384 { "No rotation", -1 },
385 { "Rotate Right" , -1 },
386 { "Rotate Left" , -1 },
389 static const struct opt_items scaling
[]= {
391 { "Scaled - Maintain Ratio", -1 },
392 #if (LCD_WIDTH>=160) && (LCD_HEIGHT>=144)
397 static const struct opt_items palette
[]= {
398 { "Brown (Default)", -1 },
400 { "Light Gray", -1 },
401 { "Multi-Color 1", -1 },
402 { "Multi-Color 2", -1 },
403 { "Adventure Island", -1 },
404 { "Adventure Island 2", -1 },
405 { "Balloon Kid", -1 },
407 { "Batman: Return of Joker", -1 },
408 { "Bionic Commando", -1 },
409 { "Castlvania Adventure", -1 },
410 { "Donkey Kong Land", -1 },
418 MENUITEM_STRINGLIST(menu
, "Options", NULL
,
419 "Max Frameskip", "Sound", "Volume", "Stats", "Set Keys (Buggy)",
420 #ifdef HAVE_LCD_COLOR
421 "Screen Size", "Screen Rotate", "Set Palette",
425 options
.dirty
=1; /* Assume that the settings have been changed */
427 struct viewport
*parentvp
= NULL
;
428 const struct settings_list
* vol
= rb
->find_setting(&rb
->global_settings
->volume
, NULL
);
432 result
= rb
->do_menu(&menu
, &selected
, NULL
, false);
436 case 0: /* Frameskip */
437 rb
->set_option("Max Frameskip", &options
.maxskip
, INT
, frameskip
,
438 sizeof(frameskip
)/sizeof(*frameskip
), NULL
);
441 if(options
.sound
>1) options
.sound
=1;
442 rb
->set_option("Sound", &options
.sound
, INT
, onoff
, 2, NULL
);
443 if(options
.sound
) sound_dirty();
446 rb
->option_screen((struct settings_list
*)vol
, parentvp
, false, "Volume");
449 rb
->set_option("Stats", &options
.showstats
, INT
, stats
, 3, NULL
);
454 #ifdef HAVE_LCD_COLOR
455 case 5: /* Screen Size */
456 rb
->set_option("Screen Size", &options
.scaling
, INT
, scaling
,
457 sizeof(scaling
)/sizeof(*scaling
), NULL
);
460 case 6: /* Screen rotate */
461 rb
->set_option("Screen Rotate", &options
.rotate
, INT
, rotate
,
462 sizeof(rotate
)/sizeof(*rotate
), NULL
);
465 case 7: /* Palette */
466 rb
->set_option("Set Palette", &options
.pal
, INT
, palette
, 17, NULL
);