NESe (pronounced "Nessie") is a NES emulator based on the e6502 emulator, also written in C with a focus on speed and portability for use on embedded platforms, especially ARM.
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

181 líneas
5.0KB

  1. #include "menu.h"
  2. #include "nes.h"
  3. #include "action.h"
  4. #include "port.h"
  5. #include "draw.h"
  6. static nese_Action wait_for_input(void* plat, uint8_t* new_buttons) {
  7. nes_Input input = {0};
  8. nese_Action action = nese_update_input(plat, &input);
  9. uint8_t changed = 0;
  10. while (0 == changed && Action_OK == action) {
  11. uint8_t buttons = input.gamepads[0].buttons;
  12. // Sleep is implicit in nese_update_input
  13. action = nese_update_input(plat, &input);
  14. changed = (~buttons & input.gamepads[0].buttons);
  15. }
  16. if (NULL != new_buttons) *new_buttons = input.gamepads[0].buttons;
  17. return action;
  18. }
  19. static nese_Action wait_for_input_quiet(void* plat) {
  20. nes_Input input = {0};
  21. nese_Action action = nese_update_input(plat, &input);
  22. uint8_t buttons = input.gamepads[0].buttons;
  23. while (Action_Quit != action && buttons) {
  24. action = nese_update_input(plat, &input);
  25. buttons = input.gamepads[0].buttons;
  26. }
  27. return action;
  28. }
  29. nese_Action modal_popup(void* plat, const char* message, uint32_t color) {
  30. int w = 0;
  31. int h = 0;
  32. nese_text_size(plat, message, &w, &h);
  33. int x = ((int)nes_ppu_render_w - w) / 2;
  34. int y = ((int)nes_ppu_render_h - h) / 2;
  35. if (x < 5) x = 5;
  36. if (y < 5) y = 5;
  37. nese_Action action = 0;
  38. uint8_t buttons = 0;
  39. while (0 == action && 0 == buttons) {
  40. nese_draw_begin(plat);
  41. nese_draw_text(plat, message, x, y, color);
  42. nese_draw_finish(plat);
  43. action = wait_for_input(plat, &buttons);
  44. }
  45. return action;
  46. }
  47. static void fix_filename(char* dst, int n, const char* src) {
  48. for ( int i = 0;
  49. i < n && *src && '.' != *src;
  50. ++i, ++dst, ++src) {
  51. *dst = ('_' == *src ? ' ' : *src);
  52. }
  53. *dst = '\0';
  54. }
  55. static inline int n_visible(void) {
  56. return ((nes_ppu_render_h - 20) / 11);
  57. }
  58. static const uint32_t menu_colors[6] = {
  59. color_red, color_orange, color_yellow,
  60. color_green, color_blue, color_purple,
  61. };
  62. static void show_menu(void* plat, const Menu_State* menu,
  63. const File_List* files, int x) {
  64. nese_draw_begin(plat);
  65. int bottom = menu->top + n_visible() - 1;
  66. int max = n_visible();
  67. if (max > files->count) max = files->count;
  68. int y = (nes_ppu_render_h - (max * 11)) / 2;
  69. for ( int n = menu->top;
  70. n < files->count && n <= bottom;
  71. ++n, y += 11 ) {
  72. char filename[100];
  73. fix_filename(filename, sizeof(filename) - 1,
  74. files->files[n]);
  75. nese_draw_text(
  76. plat,
  77. ( (menu->top == n && 0 != menu->top) ||
  78. (bottom == n && files->count - 1 > bottom) ) ?
  79. "..." : filename,
  80. x, y,
  81. (menu->cursor == n) ?
  82. color_white : menu_colors[n % 6]
  83. );
  84. if (menu->cursor == n) {
  85. nese_draw_text(plat, ">", x - 10, y, color_white);
  86. }
  87. }
  88. nese_draw_finish(plat);
  89. }
  90. nese_Action run_menu(void* plat, Menu_State* state,
  91. const File_List* files, int x) {
  92. Menu_State menu = {0};
  93. if (NULL != state) {
  94. menu = *state;
  95. if (menu.cursor < 0) {
  96. menu.cursor = 0;
  97. } else if (menu.cursor >= files->count) {
  98. menu.cursor = files->count - 1;
  99. }
  100. }
  101. nese_Action action = Action_OK;
  102. while (Action_OK == action) {
  103. // Scrolling (do this first to ensure menu is valid)
  104. const int visible = n_visible() - 1;
  105. menu.top = menu.cursor - (visible / 2);
  106. if (menu.top <= 0) {
  107. // We use <= so we don't readjust the top from 0
  108. menu.top = 0;
  109. } else if (menu.top + visible >= files->count) {
  110. menu.top = (files->count - 1) - visible;
  111. }
  112. show_menu(plat, &menu, files, x);
  113. uint8_t buttons = 0;
  114. action = wait_for_input(plat, &buttons);
  115. if (Action_Menu == action) {
  116. action = Action_Cancel;
  117. } else if (Action_OK == action) {
  118. if (buttons & (1 << Button_B)) {
  119. action = Action_Cancel;
  120. break;
  121. } else if (buttons & ( (1 << Button_A) |
  122. (1 << Button_Start) )) {
  123. // Select
  124. break;
  125. } else if (buttons & (1 << Button_Up)) {
  126. if (menu.cursor > 0) --menu.cursor;
  127. } else if (buttons & ( (1 << Button_Down) |
  128. (1 << Button_Select) )) {
  129. if (menu.cursor < (files->count - 1)) {
  130. ++menu.cursor;
  131. } else if (buttons & (1 << Button_Select)) {
  132. // Wrap around on Select
  133. menu.cursor = 0;
  134. }
  135. }
  136. } else if (Action_Quit != action && Action_Cancel != action) {
  137. // Ignore anything that isn't "Menu", "Cancel" or "Quit"
  138. action = Action_OK;
  139. }
  140. }
  141. if (NULL != state) *state = menu;
  142. wait_for_input_quiet(plat);
  143. return action;
  144. }