1 | #include <algorithm> |
2 | #include <dirent.h> |
3 | #include <unistd.h> |
4 | #include "cartridge.hpp" |
5 | #include "menu.hpp" |
6 | |
7 | namespace GUI { |
8 | |
9 | using namespace std; |
10 | |
11 | |
12 | Entry::Entry(string label, function<void()> callback) : callback(callback) |
13 | { |
14 | set_label(label); |
15 | } |
16 | |
17 | Entry::~Entry() |
18 | { |
19 | SDL_DestroyTexture(whiteTexture); |
20 | SDL_DestroyTexture(redTexture); |
21 | } |
22 | |
23 | void Entry::set_label(string label) |
24 | { |
25 | this->label = label; |
26 | |
27 | if (whiteTexture != nullptr) SDL_DestroyTexture(whiteTexture); |
28 | if (redTexture != nullptr) SDL_DestroyTexture(redTexture); |
29 | |
30 | whiteTexture = gen_text(label, { 255, 255, 255 }); |
31 | redTexture = gen_text(label, { 255, 0, 0 }); |
32 | } |
33 | |
34 | void Entry::render(int x, int y) { |
35 | render_texture(selected ? redTexture : whiteTexture, x, y); |
36 | } |
37 | |
38 | ControlEntry::ControlEntry(string action, SDL_Scancode* key) : key(key), |
39 | Entry::Entry( |
40 | action, |
41 | [&]{ keyEntry->set_label(SDL_GetScancodeName(*(this->key) = query_key())); }) |
42 | { |
43 | this->keyEntry = new Entry(SDL_GetScancodeName(*key), []{}); |
44 | } |
45 | |
46 | ControlEntry::ControlEntry(string action, int* button) : button(button), |
47 | Entry::Entry( |
48 | action, |
49 | [&]{ keyEntry->set_label(to_string(*(this->button) = query_button())); }) |
50 | { |
51 | this->keyEntry = new Entry(to_string(*button), []{}); |
52 | } |
53 | |
54 | |
55 | void Menu::(Entry* entry) |
56 | { |
57 | if (entries.empty()) |
58 | entry->select(); |
59 | entries.push_back(entry); |
60 | } |
61 | |
62 | void Menu::() |
63 | { |
64 | for (auto entry : entries) |
65 | delete entry; |
66 | entries.clear(); |
67 | clear_error(); |
68 | cursor = 0; |
69 | } |
70 | |
71 | void Menu::() |
72 | { |
73 | delete errorMessage; |
74 | errorMessage = nullptr; |
75 | } |
76 | |
77 | void Menu::() |
78 | { |
79 | if (entries.empty()) |
80 | return; |
81 | entries[0]->unselect(); |
82 | sort(entries.begin(), entries.end(), [](Entry* a, Entry* b) { |
83 | return a->get_label() < b->get_label(); |
84 | }); |
85 | entries[0]->select(); |
86 | } |
87 | |
88 | void Menu::(u8 const* keys) |
89 | { |
90 | int oldCursor = cursor; |
91 | |
92 | if (keys[SDL_SCANCODE_DOWN] and cursor < entries.size() - 1) |
93 | { |
94 | cursor++; |
95 | if (cursor == bottom) { |
96 | bottom += 1; |
97 | top += 1; |
98 | } |
99 | clear_error(); |
100 | } |
101 | else if (keys[SDL_SCANCODE_UP] and cursor > 0) |
102 | { |
103 | cursor--; |
104 | if (cursor < top) { |
105 | top -= 1; |
106 | bottom -= 1; |
107 | } |
108 | clear_error(); |
109 | } |
110 | entries[oldCursor]->unselect(); |
111 | entries[cursor]->select(); |
112 | |
113 | if (keys[SDL_SCANCODE_RETURN]) |
114 | entries[cursor]->trigger(); |
115 | } |
116 | |
117 | void Menu::() |
118 | { |
119 | for (int i = top; i < entries.size() && i < bottom; ++i) |
120 | { |
121 | int y = (i - top) * FONT_SZ; |
122 | entries[i]->render(TEXT_CENTER, y); |
123 | } |
124 | |
125 | if (errorMessage != nullptr) |
126 | errorMessage->render(TEXT_CENTER, HEIGHT - FONT_SZ * 3 / 2); |
127 | } |
128 | |
129 | void FileMenu::(string dir) |
130 | { |
131 | clear(); |
132 | |
133 | struct dirent* dirp; |
134 | DIR* dp = opendir(dir.c_str()); |
135 | |
136 | while ((dirp = readdir(dp)) != NULL) |
137 | { |
138 | string name = dirp->d_name; |
139 | string path = dir + "/" + name; |
140 | |
141 | if (name[0] == '.' and name != ".." ) continue; |
142 | |
143 | if (dirp->d_type == DT_DIR) |
144 | add(new Entry(name + "/" , |
145 | [=]{ change_dir(path); })); |
146 | |
147 | else if (name.size() > 4 and name.substr(name.size() - 4) == ".nes" ) |
148 | add(new Entry(name, |
149 | [=]{ load_rom(path); })); |
150 | } |
151 | closedir(dp); |
152 | sort_by_label(); |
153 | } |
154 | |
155 | void FileMenu::(string path) |
156 | { |
157 | clear_error(); |
158 | Cartridge::load(path.c_str()); |
159 | if (!Cartridge::loaded()) |
160 | { |
161 | errorMessage = new Entry("Load failed" ); |
162 | return errorMessage->select(); |
163 | } |
164 | toggle_pause(); |
165 | } |
166 | |
167 | FileMenu::() |
168 | { |
169 | char cwd[512]; |
170 | change_dir(getcwd(cwd, 512)); |
171 | } |
172 | |
173 | |
174 | } |
175 | |