yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
editor_selection_dialog.cc
Go to the documentation of this file.
2
3#include <sstream>
4#include <fstream>
5#include <algorithm>
6
7#include "absl/strings/str_cat.h"
8#include "imgui/imgui.h"
9#include "app/gui/icons.h"
10#include "app/gui/style.h"
11#include "util/file_util.h"
12
13namespace yaze {
14namespace editor {
15
17 // Initialize editor metadata with distinct colors
18 editors_ = {
20 "Edit overworld maps, entrances, and properties", "Ctrl+1", false, true,
21 ImVec4(0.133f, 0.545f, 0.133f, 1.0f)}, // Hyrule green
22
24 "Design dungeon rooms, layouts, and mechanics", "Ctrl+2", false, true,
25 ImVec4(0.502f, 0.0f, 0.502f, 1.0f)}, // Ganon purple
26
28 "Modify tiles, palettes, and graphics sets", "Ctrl+3", false, true,
29 ImVec4(1.0f, 0.843f, 0.0f, 1.0f)}, // Triforce gold
30
32 "Edit sprite graphics and properties", "Ctrl+4", false, true,
33 ImVec4(1.0f, 0.647f, 0.0f, 1.0f)}, // Spirit orange
34
36 "Edit dialogue, signs, and text", "Ctrl+5", false, true,
37 ImVec4(0.196f, 0.6f, 0.8f, 1.0f)}, // Master sword blue
38
40 "Configure music and sound effects", "Ctrl+6", false, true,
41 ImVec4(0.416f, 0.353f, 0.804f, 1.0f)}, // Shadow purple
42
44 "Edit color palettes and animations", "Ctrl+7", false, true,
45 ImVec4(0.863f, 0.078f, 0.235f, 1.0f)}, // Heart red
46
48 "Edit title screen and ending screens", "Ctrl+8", false, true,
49 ImVec4(0.4f, 0.8f, 1.0f, 1.0f)}, // Sky blue
50
52 "Write and edit assembly code", "Ctrl+9", false, false,
53 ImVec4(0.8f, 0.8f, 0.8f, 1.0f)}, // Silver
54
56 "Direct ROM memory editing and comparison", "Ctrl+0", false, true,
57 ImVec4(0.2f, 0.8f, 0.4f, 1.0f)}, // Matrix green
58
60 "Test and debug your ROM in real-time with live debugging", "Ctrl+Shift+E", false, true,
61 ImVec4(0.2f, 0.6f, 1.0f, 1.0f)}, // Emulator blue
62
64 "Configure AI agent, collaboration, and automation", "Ctrl+Shift+A", false, false,
65 ImVec4(0.8f, 0.4f, 1.0f, 1.0f)}, // Purple/magenta
66
68 "Configure ROM and project settings", "", false, true,
69 ImVec4(0.6f, 0.6f, 0.6f, 1.0f)}, // Gray
70 };
71
73}
74
75bool EditorSelectionDialog::Show(bool* p_open) {
76 // Sync internal state with external flag
77 if (p_open && *p_open && !is_open_) {
78 is_open_ = true;
79 }
80
81 if (!is_open_) {
82 if (p_open) *p_open = false;
83 return false;
84 }
85
86 bool editor_selected = false;
87 bool* window_open = p_open ? p_open : &is_open_;
88
89 // Set window properties immediately before Begin to prevent them from affecting tooltips
90 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
91 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
92 ImGui::SetNextWindowSize(ImVec2(950, 650), ImGuiCond_Appearing); // Slightly larger for better layout
93
94 if (ImGui::Begin("Editor Selection", window_open,
95 ImGuiWindowFlags_NoCollapse)) {
97
98 ImGui::Separator();
99 ImGui::Spacing();
100
101 // Quick access buttons for recently used
102 if (!recent_editors_.empty()) {
104 ImGui::Separator();
105 ImGui::Spacing();
106 }
107
108 // Main editor grid
109 ImGui::Text(ICON_MD_APPS " All Editors");
110 ImGui::Spacing();
111
112 float button_size = 200.0f;
113 int columns = static_cast<int>(ImGui::GetContentRegionAvail().x / button_size);
114 columns = std::max(columns, 1);
115
116 if (ImGui::BeginTable("##EditorGrid", columns,
117 ImGuiTableFlags_None)) {
118 for (size_t i = 0; i < editors_.size(); ++i) {
119 ImGui::TableNextColumn();
120
121 EditorType prev_selection = selected_editor_;
122 DrawEditorCard(editors_[i], static_cast<int>(i));
123
124 // Check if an editor was just selected
125 if (selected_editor_ != prev_selection) {
126 editor_selected = true;
130 }
131 }
132 }
133 ImGui::EndTable();
134 }
135 }
136 ImGui::End();
137
138 // Sync state back
139 if (p_open && !(*p_open)) {
140 is_open_ = false;
141 }
142
143 if (editor_selected) {
144 is_open_ = false;
145 if (p_open) *p_open = false;
146 }
147
148 return editor_selected;
149}
150
152 ImDrawList* draw_list = ImGui::GetWindowDrawList();
153 ImVec2 header_start = ImGui::GetCursorScreenPos();
154
155 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[2]); // Large font
156
157 // Colorful gradient title
158 ImVec4 title_color = ImVec4(1.0f, 0.843f, 0.0f, 1.0f); // Triforce gold
159 ImGui::TextColored(title_color, ICON_MD_EDIT " Select an Editor");
160
161 ImGui::PopFont();
162
163 // Subtitle with gradient separator
164 ImVec2 subtitle_pos = ImGui::GetCursorScreenPos();
165 ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.8f, 1.0f),
166 "Choose an editor to begin working on your ROM. "
167 "You can open multiple editors simultaneously.");
168}
169
171 ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_HISTORY " Recently Used");
172 ImGui::Spacing();
173
174 for (EditorType type : recent_editors_) {
175 // Find editor info
176 auto it = std::find_if(editors_.begin(), editors_.end(),
177 [type](const EditorInfo& info) {
178 return info.type == type;
179 });
180
181 if (it != editors_.end()) {
182 // Use editor's theme color for button
183 ImVec4 color = it->color;
184 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(color.x * 0.5f, color.y * 0.5f,
185 color.z * 0.5f, 0.7f));
186 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(color.x * 0.7f, color.y * 0.7f,
187 color.z * 0.7f, 0.9f));
188 ImGui::PushStyleColor(ImGuiCol_ButtonActive, color);
189
190 if (ImGui::Button(absl::StrCat(it->icon, " ", it->name).c_str(),
191 ImVec2(150, 35))) {
192 selected_editor_ = type;
193 }
194
195 ImGui::PopStyleColor(3);
196
197 if (ImGui::IsItemHovered()) {
198 ImGui::SetTooltip("%s", it->description);
199 }
200
201 ImGui::SameLine();
202 }
203 }
204
205 ImGui::NewLine();
206}
207
209 ImGui::PushID(index);
210
211 ImVec2 button_size(180, 120);
212 ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
213 ImDrawList* draw_list = ImGui::GetWindowDrawList();
214
215 // Card styling with gradients
216 bool is_recent = std::find(recent_editors_.begin(), recent_editors_.end(),
217 info.type) != recent_editors_.end();
218
219 // Create gradient background
220 ImVec4 base_color = info.color;
221 ImU32 color_top = ImGui::GetColorU32(ImVec4(base_color.x * 0.4f, base_color.y * 0.4f,
222 base_color.z * 0.4f, 0.8f));
223 ImU32 color_bottom = ImGui::GetColorU32(ImVec4(base_color.x * 0.2f, base_color.y * 0.2f,
224 base_color.z * 0.2f, 0.9f));
225
226 // Draw gradient card background
227 draw_list->AddRectFilledMultiColor(
228 cursor_pos,
229 ImVec2(cursor_pos.x + button_size.x, cursor_pos.y + button_size.y),
230 color_top, color_top, color_bottom, color_bottom);
231
232 // Colored border
233 ImU32 border_color = is_recent
234 ? ImGui::GetColorU32(ImVec4(base_color.x, base_color.y, base_color.z, 1.0f))
235 : ImGui::GetColorU32(ImVec4(base_color.x * 0.6f, base_color.y * 0.6f,
236 base_color.z * 0.6f, 0.7f));
237 draw_list->AddRect(cursor_pos,
238 ImVec2(cursor_pos.x + button_size.x, cursor_pos.y + button_size.y),
239 border_color, 4.0f, 0, is_recent ? 3.0f : 2.0f);
240
241 // Recent indicator badge
242 if (is_recent) {
243 ImVec2 badge_pos(cursor_pos.x + button_size.x - 25, cursor_pos.y + 5);
244 draw_list->AddCircleFilled(badge_pos, 12, ImGui::GetColorU32(base_color), 16);
245 ImGui::SetCursorScreenPos(ImVec2(badge_pos.x - 6, badge_pos.y - 8));
246 ImGui::TextColored(ImVec4(1, 1, 1, 1), ICON_MD_STAR);
247 }
248
249 // Make button transparent (we draw our own background)
250 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
251 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(base_color.x * 0.3f, base_color.y * 0.3f,
252 base_color.z * 0.3f, 0.5f));
253 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(base_color.x * 0.5f, base_color.y * 0.5f,
254 base_color.z * 0.5f, 0.7f));
255
256 ImGui::SetCursorScreenPos(cursor_pos);
257 bool clicked = ImGui::Button(absl::StrCat("##", info.name).c_str(), button_size);
258 bool is_hovered = ImGui::IsItemHovered();
259
260 ImGui::PopStyleColor(3);
261
262 // Draw icon with colored background circle
263 ImVec2 icon_center(cursor_pos.x + button_size.x / 2, cursor_pos.y + 30);
264 ImU32 icon_bg = ImGui::GetColorU32(base_color);
265 draw_list->AddCircleFilled(icon_center, 22, icon_bg, 32);
266
267 // Draw icon
268 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[2]); // Larger font for icon
269 ImVec2 icon_size = ImGui::CalcTextSize(info.icon);
270 ImGui::SetCursorScreenPos(ImVec2(icon_center.x - icon_size.x / 2, icon_center.y - icon_size.y / 2));
271 ImGui::TextColored(ImVec4(1, 1, 1, 1), "%s", info.icon);
272 ImGui::PopFont();
273
274 // Draw name
275 ImGui::SetCursorScreenPos(ImVec2(cursor_pos.x + 10, cursor_pos.y + 65));
276 ImGui::PushTextWrapPos(cursor_pos.x + button_size.x - 10);
277 ImVec2 name_size = ImGui::CalcTextSize(info.name);
278 ImGui::SetCursorScreenPos(ImVec2(cursor_pos.x + (button_size.x - name_size.x) / 2,
279 cursor_pos.y + 65));
280 ImGui::TextColored(base_color, "%s", info.name);
281 ImGui::PopTextWrapPos();
282
283 // Draw shortcut hint if available
284 if (info.shortcut && info.shortcut[0]) {
285 ImGui::SetCursorScreenPos(ImVec2(cursor_pos.x + 10, cursor_pos.y + button_size.y - 20));
286 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "%s", info.shortcut);
287 }
288
289 // Hover glow effect
290 if (is_hovered) {
291 ImU32 glow_color = ImGui::GetColorU32(ImVec4(base_color.x, base_color.y, base_color.z, 0.2f));
292 draw_list->AddRectFilled(cursor_pos,
293 ImVec2(cursor_pos.x + button_size.x, cursor_pos.y + button_size.y),
294 glow_color, 4.0f);
295 }
296
297 // Enhanced tooltip with fixed sizing
298 if (is_hovered) {
299 // Force tooltip to have a fixed max width to prevent flickering
300 ImGui::SetNextWindowSize(ImVec2(300, 0), ImGuiCond_Always);
301 ImGui::BeginTooltip();
302 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); // Medium font
303 ImGui::TextColored(base_color, "%s %s", info.icon, info.name);
304 ImGui::PopFont();
305 ImGui::Separator();
306 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 280);
307 ImGui::TextWrapped("%s", info.description);
308 ImGui::PopTextWrapPos();
309 if (info.shortcut && info.shortcut[0]) {
310 ImGui::Spacing();
311 ImGui::TextColored(base_color, ICON_MD_KEYBOARD " %s", info.shortcut);
312 }
313 if (is_recent) {
314 ImGui::Spacing();
315 ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f), ICON_MD_STAR " Recently used");
316 }
317 ImGui::EndTooltip();
318 }
319
320 if (clicked) {
321 selected_editor_ = info.type;
322 }
323
324 ImGui::PopID();
325}
326
328 // Remove if already in list
329 auto it = std::find(recent_editors_.begin(), recent_editors_.end(), type);
330 if (it != recent_editors_.end()) {
331 recent_editors_.erase(it);
332 }
333
334 // Add to front
335 recent_editors_.insert(recent_editors_.begin(), type);
336
337 // Limit size
338 if (recent_editors_.size() > kMaxRecentEditors) {
340 }
341
343}
344
346 try {
347 auto data = util::LoadFileFromConfigDir("recent_editors.txt");
348 if (!data.empty()) {
349 std::istringstream ss(data);
350 std::string line;
351 while (std::getline(ss, line) &&
353 int type_int = std::stoi(line);
354 if (type_int >= 0 && type_int < static_cast<int>(EditorType::kSettings)) {
355 recent_editors_.push_back(static_cast<EditorType>(type_int));
356 }
357 }
358 }
359 } catch (...) {
360 // Ignore errors, just start with empty recent list
361 }
362}
363
365 try {
366 std::ostringstream ss;
367 for (EditorType type : recent_editors_) {
368 ss << static_cast<int>(type) << "\n";
369 }
370 util::SaveFile("recent_editors.txt", ss.str());
371 } catch (...) {
372 // Ignore save errors
373 }
374}
375
376} // namespace editor
377} // namespace yaze
void SaveRecentEditors()
Save recently used editors to settings.
void LoadRecentEditors()
Load recently used editors from settings.
std::function< void(EditorType)> selection_callback_
void DrawEditorCard(const EditorInfo &info, int index)
void MarkRecentlyUsed(EditorType type)
Mark an editor as recently used.
bool Show(bool *p_open=nullptr)
Show the dialog.
#define ICON_MD_SETTINGS
Definition icons.h:1697
#define ICON_MD_APPS
Definition icons.h:166
#define ICON_MD_EMOJI_EMOTIONS
Definition icons.h:670
#define ICON_MD_DATA_ARRAY
Definition icons.h:517
#define ICON_MD_STAR
Definition icons.h:1846
#define ICON_MD_MAP
Definition icons.h:1171
#define ICON_MD_CODE
Definition icons.h:432
#define ICON_MD_VIDEOGAME_ASSET
Definition icons.h:2074
#define ICON_MD_CHAT_BUBBLE
Definition icons.h:393
#define ICON_MD_EDIT
Definition icons.h:643
#define ICON_MD_CASTLE
Definition icons.h:378
#define ICON_MD_MUSIC_NOTE
Definition icons.h:1262
#define ICON_MD_KEYBOARD
Definition icons.h:1026
#define ICON_MD_PALETTE
Definition icons.h:1368
#define ICON_MD_TV
Definition icons.h:2030
#define ICON_MD_COLOR_LENS
Definition icons.h:438
#define ICON_MD_SMART_TOY
Definition icons.h:1779
#define ICON_MD_HISTORY
Definition icons.h:944
void SaveFile(const std::string &filename, const std::string &contents)
Definition file_util.cc:56
std::string LoadFileFromConfigDir(const std::string &filename)
Loads a file from the user's config directory.
Definition file_util.cc:38
Main namespace for the application.
Metadata about an available editor.