3b38a9569f2922a65d6e82b83a8d41dafb16652d
[pcsx_rearmed.git] / frontend / menu.c
1 /*
2  * (C) GraÅžvydas "notaz" Ignotas, 2010
3  *
4  * This work is licensed under the terms of any of these licenses
5  * (at your option):
6  *  - GNU GPL, version 2 or later.
7  *  - GNU LGPL, version 2.1 or later.
8  * See the COPYING file in the top-level directory.
9  */
10
11 #include <stdio.h>
12 #include <string.h>
13
14 #include "config.h"
15 #include "plugin_lib.h"
16 #include "omap.h"
17 #include "common/plat.h"
18 #include "../libpcsxcore/misc.h"
19
20 #define MENU_X2 1
21 #define array_size(x) (sizeof(x) / sizeof(x[0]))
22
23 typedef enum
24 {
25         MA_NONE = 1,
26         MA_MAIN_RESUME_GAME,
27         MA_MAIN_SAVE_STATE,
28         MA_MAIN_LOAD_STATE,
29         MA_MAIN_RESET_GAME,
30         MA_MAIN_LOAD_ROM,
31         MA_MAIN_CONTROLS,
32         MA_MAIN_CREDITS,
33         MA_MAIN_EXIT,
34         MA_CTRL_PLAYER1,
35         MA_CTRL_PLAYER2,
36         MA_CTRL_EMU,
37         MA_CTRL_DEV_FIRST,
38         MA_CTRL_DEV_NEXT,
39         MA_CTRL_DONE,
40         MA_OPT_SAVECFG,
41         MA_OPT_SAVECFG_GAME,
42         MA_OPT_CPU_CLOCKS,
43 } menu_id;
44
45 extern int ready_to_go;
46
47 static int dummy, state_slot;
48 static char rom_fname_reload[MAXPATHLEN];
49 static char last_selected_fname[MAXPATHLEN];
50
51 void emu_make_path(char *buff, const char *end, int size)
52 {
53         int pos, end_len;
54
55         end_len = strlen(end);
56         pos = plat_get_root_dir(buff, size);
57         strncpy(buff + pos, end, size - pos);
58         buff[size - 1] = 0;
59         if (pos + end_len > size - 1)
60                 printf("Warning: path truncated: %s\n", buff);
61 }
62
63 static int emu_check_save_file(int slot)
64 {
65         return 0;
66 }
67
68 static int emu_save_load_game(int load, int sram)
69 {
70         return 0;
71 }
72
73 static int emu_write_config(int is_game)
74 {
75         return 0;
76 }
77
78 static void emu_set_defconfig(void)
79 {
80 }
81
82 #include "common/menu.c"
83
84 static void draw_savestate_bg(int slot)
85 {
86 }
87
88 // -------------- key config --------------
89
90 me_bind_action me_ctrl_actions[] =
91 {
92         { "UP      ", 1 << DKEY_UP},
93         { "DOWN    ", 1 << DKEY_DOWN },
94         { "LEFT    ", 1 << DKEY_LEFT },
95         { "RIGHT   ", 1 << DKEY_RIGHT },
96         { "TRIANGLE", 1 << DKEY_TRIANGLE },
97         { "CIRCLE  ", 1 << DKEY_SQUARE },
98         { "CROSS   ", 1 << DKEY_CROSS },
99         { "SQUARE  ", 1 << DKEY_SQUARE },
100         { "L1      ", 1 << DKEY_L1 },
101         { "R1      ", 1 << DKEY_R1 },
102         { "L2      ", 1 << DKEY_L2 },
103         { "R2      ", 1 << DKEY_R2 },
104         { "START   ", 1 << DKEY_START },
105         { "SELECT  ", 1 << DKEY_SELECT },
106         { NULL,       0 }
107 };
108
109 me_bind_action emuctrl_actions[] =
110 {
111         { "Load State       ", PEV_STATE_LOAD },
112         { "Save State       ", PEV_STATE_SAVE },
113         { "Prev Save Slot   ", PEV_SSLOT_PREV },
114         { "Next Save Slot   ", PEV_SSLOT_NEXT },
115         { "Enter Menu       ", PEV_MENU },
116         { NULL,                0 }
117 };
118
119 static int key_config_loop_wrap(int id, int keys)
120 {
121         switch (id) {
122                 case MA_CTRL_PLAYER1:
123                         key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
124                         break;
125                 case MA_CTRL_PLAYER2:
126                         key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
127                         break;
128                 case MA_CTRL_EMU:
129                         key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
130                         break;
131                 default:
132                         break;
133         }
134         return 0;
135 }
136
137 static const char *mgn_dev_name(int id, int *offs)
138 {
139         const char *name = NULL;
140         static int it = 0;
141
142         if (id == MA_CTRL_DEV_FIRST)
143                 it = 0;
144
145         for (; it < IN_MAX_DEVS; it++) {
146                 name = in_get_dev_name(it, 1, 1);
147                 if (name != NULL)
148                         break;
149         }
150
151         it++;
152         return name;
153 }
154
155 static const char *mgn_saveloadcfg(int id, int *offs)
156 {
157         return "";
158 }
159
160 static int mh_saveloadcfg(int id, int keys)
161 {
162         switch (id) {
163         case MA_OPT_SAVECFG:
164         case MA_OPT_SAVECFG_GAME:
165                 if (emu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0))
166                         me_update_msg("config saved");
167                 else
168                         me_update_msg("failed to write config");
169                 break;
170         default:
171                 return 0;
172         }
173
174         return 1;
175 }
176
177 static menu_entry e_menu_keyconfig[] =
178 {
179         mee_handler_id("Player 1",          MA_CTRL_PLAYER1,    key_config_loop_wrap),
180         mee_handler_id("Player 2",          MA_CTRL_PLAYER2,    key_config_loop_wrap),
181         mee_handler_id("Emulator controls", MA_CTRL_EMU,        key_config_loop_wrap),
182         mee_cust_nosave("Save global config",       MA_OPT_SAVECFG, mh_saveloadcfg, mgn_saveloadcfg),
183         mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_saveloadcfg, mgn_saveloadcfg),
184         mee_label     (""),
185         mee_label     ("Input devices:"),
186         mee_label_mk  (MA_CTRL_DEV_FIRST, mgn_dev_name),
187         mee_label_mk  (MA_CTRL_DEV_NEXT,  mgn_dev_name),
188         mee_label_mk  (MA_CTRL_DEV_NEXT,  mgn_dev_name),
189         mee_label_mk  (MA_CTRL_DEV_NEXT,  mgn_dev_name),
190         mee_label_mk  (MA_CTRL_DEV_NEXT,  mgn_dev_name),
191         mee_label_mk  (MA_CTRL_DEV_NEXT,  mgn_dev_name),
192         mee_label_mk  (MA_CTRL_DEV_NEXT,  mgn_dev_name),
193         mee_end,
194 };
195
196 static int menu_loop_keyconfig(int id, int keys)
197 {
198         static int sel = 0;
199
200         me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go);
201         me_loop(e_menu_keyconfig, &sel, NULL);
202         return 0;
203 }
204
205 // ------------ adv options menu ------------
206
207 static menu_entry e_menu_adv_options[] =
208 {
209         mee_onoff     ("captain placeholder", 0, dummy, 1),
210         mee_end,
211 };
212
213 static int menu_loop_adv_options(int id, int keys)
214 {
215         static int sel = 0;
216         me_loop(e_menu_adv_options, &sel, NULL);
217         return 0;
218 }
219
220 // ------------ gfx options menu ------------
221
222 static menu_entry e_menu_gfx_options[] =
223 {
224         mee_end,
225 };
226
227 static int menu_loop_gfx_options(int id, int keys)
228 {
229         static int sel = 0;
230
231         me_loop(e_menu_gfx_options, &sel, NULL);
232
233         return 0;
234 }
235
236 // ------------ options menu ------------
237
238 static menu_entry e_menu_options[];
239
240 static int mh_restore_defaults(int id, int keys)
241 {
242         emu_set_defconfig();
243         me_update_msg("defaults restored");
244         return 1;
245 }
246
247 static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
248 static const char h_confirm_save[]    = "Ask for confirmation when overwriting save,\n"
249                                         "loading state or both";
250
251 static menu_entry e_menu_options[] =
252 {
253         mee_range     ("Save slot",                0, state_slot, 0, 9),
254         mee_enum_h    ("Confirm savestate",        0, dummy, men_confirm_save, h_confirm_save),
255         mee_range     ("",                         MA_OPT_CPU_CLOCKS, dummy, 20, 5000),
256         mee_handler   ("[Display]",                menu_loop_gfx_options),
257         mee_handler   ("[Advanced]",               menu_loop_adv_options),
258         mee_cust_nosave("Save global config",      MA_OPT_SAVECFG,      mh_saveloadcfg, mgn_saveloadcfg),
259         mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_saveloadcfg, mgn_saveloadcfg),
260         mee_handler   ("Restore defaults",         mh_restore_defaults),
261         mee_end,
262 };
263
264 static int menu_loop_options(int id, int keys)
265 {
266         static int sel = 0;
267         int i;
268
269         i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
270         e_menu_options[i].enabled = e_menu_options[i].name[0] ? 1 : 0;
271         me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go);
272
273         me_loop(e_menu_options, &sel, NULL);
274
275         return 0;
276 }
277
278 // ------------ debug menu ------------
279
280 #ifdef __GNUC__
281 #define COMPILER "gcc " __VERSION__
282 #else
283 #define COMPILER
284 #endif
285
286 static void draw_frame_debug(void)
287 {
288         smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " COMPILER, 0xffff);
289 }
290
291 static void debug_menu_loop(void)
292 {
293         int inp;
294
295         while (1)
296         {
297                 menu_draw_begin(1);
298                 draw_frame_debug();
299                 menu_draw_end();
300
301                 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
302                                         PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
303                 if (inp & PBTN_MBACK)
304                         return;
305         }
306 }
307
308 // ------------ main menu ------------
309
310 const char *plat_get_credits(void)
311 {
312         return  "(C) 1999-2003 PCSX Team\n"
313                 "(C) 2005-2009 PCSX-df Team\n"
314                 "(C) 2009-2010 PCSX-Reloaded Team\n\n"
315                 "GPU and SPU code by Pete Bernert\n"
316                 "  and the P.E.Op.S. team\n"
317                 "ARM recompiler by Ari64\n\n"
318                 "integration, optimization and\n"
319                 "  frontend by (C) notaz, 2010\n";
320 }
321
322 static char *romsel_run(void)
323 {
324         char *ret;
325
326         ret = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
327         if (ret == NULL)
328                 return NULL;
329
330         lprintf("selected file: %s\n", ret);
331         ready_to_go = 0;
332
333         SetIsoFile(ret);
334         LoadPlugins();
335         NetOpened = 0;
336         if (OpenPlugins() == -1) {
337                 me_update_msg("failed to open plugins");
338                 return NULL;
339         }
340
341         SysReset();
342
343         if (CheckCdrom() == -1) {
344                 // Only check the CD if we are starting the console with a CD
345                 ClosePlugins();
346                 me_update_msg("unsupported/invalid CD image");
347                 return NULL;
348         }
349
350         // Read main executable directly from CDRom and start it
351         if (LoadCdrom() == -1) {
352                 ClosePlugins();
353                 me_update_msg("failed to load CD image");
354                 return NULL;
355         }
356
357         ready_to_go = 1;
358         return ret;
359 }
360
361 static int main_menu_handler(int id, int keys)
362 {
363         char *ret_name;
364
365         switch (id)
366         {
367         case MA_MAIN_RESUME_GAME:
368                 break;
369         case MA_MAIN_SAVE_STATE:
370                 if (ready_to_go)
371                         return menu_loop_savestate(0);
372                 break;
373         case MA_MAIN_LOAD_STATE:
374                 if (ready_to_go)
375                         return menu_loop_savestate(1);
376                 break;
377         case MA_MAIN_RESET_GAME:
378                 break;
379         case MA_MAIN_LOAD_ROM:
380                 ret_name = romsel_run();
381                 if (ret_name != NULL)
382                         return 1;
383                 break;
384         case MA_MAIN_CREDITS:
385                 draw_menu_credits();
386                 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
387                 break;
388         case MA_MAIN_EXIT:
389                 exit(1); // FIXME
390         default:
391                 lprintf("%s: something unknown selected\n", __FUNCTION__);
392                 break;
393         }
394
395         return 0;
396 }
397
398 static menu_entry e_menu_main[] =
399 {
400         mee_label     (""),
401         mee_label     (""),
402         mee_handler_id("Resume game",        MA_MAIN_RESUME_GAME, main_menu_handler),
403         mee_handler_id("Save State",         MA_MAIN_SAVE_STATE,  main_menu_handler),
404         mee_handler_id("Load State",         MA_MAIN_LOAD_STATE,  main_menu_handler),
405         mee_handler_id("Reset game",         MA_MAIN_RESET_GAME,  main_menu_handler),
406         mee_handler_id("Load CD image",      MA_MAIN_LOAD_ROM,    main_menu_handler),
407         mee_handler   ("Options",            menu_loop_options),
408         mee_handler   ("Controls",           menu_loop_keyconfig),
409         mee_handler_id("Credits",            MA_MAIN_CREDITS,     main_menu_handler),
410         mee_handler_id("Exit",               MA_MAIN_EXIT,        main_menu_handler),
411         mee_end,
412 };
413
414 void menu_loop(void)
415 {
416         static int sel = 0;
417
418         omap_enable_layer(0);
419
420         me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
421         me_enable(e_menu_main, MA_MAIN_SAVE_STATE,  ready_to_go);
422         me_enable(e_menu_main, MA_MAIN_LOAD_STATE,  ready_to_go);
423         me_enable(e_menu_main, MA_MAIN_RESET_GAME,  ready_to_go);
424
425 strcpy(last_selected_fname, "/mnt/ntz/stuff/psx");
426         menu_enter(ready_to_go);
427         in_set_config_int(0, IN_CFG_BLOCKING, 1);
428
429         do {
430                 me_loop(e_menu_main, &sel, NULL);
431         } while (!ready_to_go);
432
433         /* wait until menu, ok, back is released */
434         while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
435                 ;
436
437         in_set_config_int(0, IN_CFG_BLOCKING, 0);
438
439         memset(g_menuscreen_ptr, 0, g_menuscreen_w * g_menuscreen_h * 2);
440         menu_draw_end();
441         omap_enable_layer(1);
442 }
443
444 void me_update_msg(const char *msg)
445 {
446         strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
447         menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
448
449         menu_error_time = plat_get_ticks_ms();
450         lprintf("msg: %s\n", menu_error_msg);
451 }
452