yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dashboard_panel.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <fstream>
5#include <sstream>
6
7#include "absl/strings/str_cat.h"
8#include "absl/strings/str_format.h"
10#include "app/gui/core/icons.h"
12#include "app/gui/core/style.h"
14#include "imgui/imgui.h"
15#include "imgui/imgui_internal.h"
16#include "util/file_util.h"
17
18namespace yaze {
19namespace editor {
20
22 : editor_manager_(editor_manager),
23 window_("Dashboard", ICON_MD_DASHBOARD) {
24 window_.SetDefaultSize(950, 650);
26
27 // Initialize editor list with colors matching EditorSelectionDialog
28 // Use platform-aware shortcut strings (Cmd on macOS, Ctrl elsewhere)
29 const char* ctrl = gui::GetCtrlDisplayName();
30 editors_ = {
31 {"Overworld", ICON_MD_MAP, "Edit overworld maps, entrances, and properties",
32 absl::StrFormat("%s+1", ctrl), EditorType::kOverworld,
33 ImVec4(0.133f, 0.545f, 0.133f, 1.0f)}, // Hyrule green
34 {"Dungeon", ICON_MD_CASTLE, "Design dungeon rooms, layouts, and mechanics",
35 absl::StrFormat("%s+2", ctrl), EditorType::kDungeon,
36 ImVec4(0.502f, 0.0f, 0.502f, 1.0f)}, // Ganon purple
37 {"Graphics", ICON_MD_PALETTE, "Modify tiles, palettes, and graphics sets",
38 absl::StrFormat("%s+3", ctrl), EditorType::kGraphics,
39 ImVec4(1.0f, 0.843f, 0.0f, 1.0f)}, // Triforce gold
40 {"Sprites", ICON_MD_EMOJI_EMOTIONS, "Edit sprite graphics and properties",
41 absl::StrFormat("%s+4", ctrl), EditorType::kSprite,
42 ImVec4(1.0f, 0.647f, 0.0f, 1.0f)}, // Spirit orange
43 {"Messages", ICON_MD_CHAT_BUBBLE, "Edit dialogue, signs, and text",
44 absl::StrFormat("%s+5", ctrl), EditorType::kMessage,
45 ImVec4(0.196f, 0.6f, 0.8f, 1.0f)}, // Master sword blue
46 {"Music", ICON_MD_MUSIC_NOTE, "Configure music and sound effects",
47 absl::StrFormat("%s+6", ctrl), EditorType::kMusic,
48 ImVec4(0.416f, 0.353f, 0.804f, 1.0f)}, // Shadow purple
49 {"Palettes", ICON_MD_COLOR_LENS, "Edit color palettes and animations",
50 absl::StrFormat("%s+7", ctrl), EditorType::kPalette,
51 ImVec4(0.863f, 0.078f, 0.235f, 1.0f)}, // Heart red
52 {"Screens", ICON_MD_TV, "Edit title screen and ending screens",
53 absl::StrFormat("%s+8", ctrl), EditorType::kScreen,
54 ImVec4(0.4f, 0.8f, 1.0f, 1.0f)}, // Sky blue
55 {"Assembly", ICON_MD_CODE, "Write and edit assembly code",
56 absl::StrFormat("%s+9", ctrl), EditorType::kAssembly,
57 ImVec4(0.8f, 0.8f, 0.8f, 1.0f)}, // Silver
58 {"Hex Editor", ICON_MD_DATA_ARRAY, "Direct ROM memory editing and comparison",
59 absl::StrFormat("%s+0", ctrl), EditorType::kHex,
60 ImVec4(0.2f, 0.8f, 0.4f, 1.0f)}, // Matrix green
61 {"Emulator", ICON_MD_VIDEOGAME_ASSET, "Test and debug your ROM in real-time",
62 absl::StrFormat("%s+Shift+E", ctrl), EditorType::kEmulator,
63 ImVec4(0.2f, 0.6f, 1.0f, 1.0f)}, // Emulator blue
64 {"AI Agent", ICON_MD_SMART_TOY, "Configure AI agent, collaboration, and automation",
65 absl::StrFormat("%s+Shift+A", ctrl), EditorType::kAgent,
66 ImVec4(0.8f, 0.4f, 1.0f, 1.0f)}, // Purple/magenta
67 };
68
70}
71
73 if (!show_) return;
74
75 // Set window properties immediately before Begin
76 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
77 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
78 ImGui::SetNextWindowSize(ImVec2(950, 650), ImGuiCond_Appearing);
79
80 if (window_.Begin(&show_)) {
82 ImGui::Separator();
83 ImGui::Spacing();
84
86 if (!recent_editors_.empty()) {
87 ImGui::Separator();
88 ImGui::Spacing();
89 }
90
92 }
93 window_.End();
94}
95
97 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[2]); // Large font
98 ImVec4 title_color = ImVec4(1.0f, 0.843f, 0.0f, 1.0f); // Triforce gold
99 ImGui::TextColored(title_color, ICON_MD_EDIT " Select an Editor");
100 ImGui::PopFont();
101
102 ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.8f, 1.0f),
103 "Choose an editor to begin working on your ROM. "
104 "You can open multiple editors simultaneously.");
105}
106
108 if (recent_editors_.empty()) return;
109
110 ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
111 ICON_MD_HISTORY " Recently Used");
112 ImGui::Spacing();
113
114 for (EditorType type : recent_editors_) {
115 // Find editor info
116 auto it = std::find_if(
117 editors_.begin(), editors_.end(),
118 [type](const EditorInfo& info) { return info.type == type; });
119
120 if (it != editors_.end()) {
121 // Use editor's theme color for button
122 ImVec4 color = it->color;
123 ImGui::PushStyleColor(
124 ImGuiCol_Button,
125 ImVec4(color.x * 0.5f, color.y * 0.5f, color.z * 0.5f, 0.7f));
126 ImGui::PushStyleColor(
127 ImGuiCol_ButtonHovered,
128 ImVec4(color.x * 0.7f, color.y * 0.7f, color.z * 0.7f, 0.9f));
129 ImGui::PushStyleColor(ImGuiCol_ButtonActive, color);
130
131 if (ImGui::Button(absl::StrCat(it->icon, " ", it->name).c_str(),
132 ImVec2(150, 35))) {
133 if (editor_manager_) {
134 MarkRecentlyUsed(type);
136 show_ = false;
137 }
138 }
139
140 ImGui::PopStyleColor(3);
141
142 if (ImGui::IsItemHovered()) {
143 ImGui::SetTooltip("%s", it->description.c_str());
144 }
145
146 ImGui::SameLine();
147 }
148 }
149
150 ImGui::NewLine();
151}
152
154 ImGui::Text(ICON_MD_APPS " All Editors");
155 ImGui::Spacing();
156
157 const float card_width = 180.0f;
158 const float spacing = ImGui::GetStyle().ItemSpacing.x;
159 const float window_width = ImGui::GetContentRegionAvail().x;
160 int columns = static_cast<int>(window_width / (card_width + spacing));
161 columns = std::max(columns, 1);
162
163 if (ImGui::BeginTable("EditorGrid", columns)) {
164 for (size_t i = 0; i < editors_.size(); ++i) {
165 ImGui::TableNextColumn();
166 DrawEditorPanel(editors_[i], static_cast<int>(i));
167 }
168 ImGui::EndTable();
169 }
170}
171
172void DashboardPanel::DrawEditorPanel(const EditorInfo& info, int index) {
173 ImGui::PushID(index);
174
175 ImVec2 button_size(180, 120);
176 ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
177 ImDrawList* draw_list = ImGui::GetWindowDrawList();
178
179 bool is_recent = std::find(recent_editors_.begin(), recent_editors_.end(),
180 info.type) != recent_editors_.end();
181
182 // Create gradient background
183 ImVec4 base_color = info.color;
184 ImU32 color_top = ImGui::GetColorU32(ImVec4(
185 base_color.x * 0.4f, base_color.y * 0.4f, base_color.z * 0.4f, 0.8f));
186 ImU32 color_bottom = ImGui::GetColorU32(ImVec4(
187 base_color.x * 0.2f, base_color.y * 0.2f, base_color.z * 0.2f, 0.9f));
188
189 // Draw gradient card background
190 draw_list->AddRectFilledMultiColor(
191 cursor_pos,
192 ImVec2(cursor_pos.x + button_size.x, cursor_pos.y + button_size.y),
193 color_top, color_top, color_bottom, color_bottom);
194
195 // Colored border
196 ImU32 border_color =
197 is_recent
198 ? ImGui::GetColorU32(
199 ImVec4(base_color.x, base_color.y, base_color.z, 1.0f))
200 : ImGui::GetColorU32(ImVec4(base_color.x * 0.6f, base_color.y * 0.6f,
201 base_color.z * 0.6f, 0.7f));
202 draw_list->AddRect(
203 cursor_pos,
204 ImVec2(cursor_pos.x + button_size.x, cursor_pos.y + button_size.y),
205 border_color, 4.0f, 0, is_recent ? 3.0f : 2.0f);
206
207 // Recent indicator badge
208 if (is_recent) {
209 ImVec2 badge_pos(cursor_pos.x + button_size.x - 25, cursor_pos.y + 5);
210 draw_list->AddCircleFilled(badge_pos, 12, ImGui::GetColorU32(base_color),
211 16);
212 ImGui::SetCursorScreenPos(ImVec2(badge_pos.x - 6, badge_pos.y - 8));
213 ImGui::TextColored(ImVec4(1, 1, 1, 1), ICON_MD_STAR);
214 }
215
216 // Make button transparent (we draw our own background)
217 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
218 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
219 ImVec4(base_color.x * 0.3f, base_color.y * 0.3f,
220 base_color.z * 0.3f, 0.5f));
221 ImGui::PushStyleColor(ImGuiCol_ButtonActive,
222 ImVec4(base_color.x * 0.5f, base_color.y * 0.5f,
223 base_color.z * 0.5f, 0.7f));
224
225 ImGui::SetCursorScreenPos(cursor_pos);
226 bool clicked =
227 ImGui::Button(absl::StrCat("##", info.name).c_str(), button_size);
228 bool is_hovered = ImGui::IsItemHovered();
229
230 ImGui::PopStyleColor(3);
231
232 // Draw icon with colored background circle
233 ImVec2 icon_center(cursor_pos.x + button_size.x / 2, cursor_pos.y + 30);
234 ImU32 icon_bg = ImGui::GetColorU32(base_color);
235 draw_list->AddCircleFilled(icon_center, 22, icon_bg, 32);
236
237 // Draw icon
238 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[2]); // Larger font for icon
239 ImVec2 icon_size = ImGui::CalcTextSize(info.icon.c_str());
240 ImGui::SetCursorScreenPos(
241 ImVec2(icon_center.x - icon_size.x / 2, icon_center.y - icon_size.y / 2));
242 ImGui::TextColored(ImVec4(1, 1, 1, 1), "%s", info.icon.c_str());
243 ImGui::PopFont();
244
245 // Draw name
246 ImGui::SetCursorScreenPos(ImVec2(cursor_pos.x + 10, cursor_pos.y + 65));
247 ImGui::PushTextWrapPos(cursor_pos.x + button_size.x - 10);
248 ImVec2 name_size = ImGui::CalcTextSize(info.name.c_str());
249 ImGui::SetCursorScreenPos(ImVec2(
250 cursor_pos.x + (button_size.x - name_size.x) / 2, cursor_pos.y + 65));
251 ImGui::TextColored(base_color, "%s", info.name.c_str());
252 ImGui::PopTextWrapPos();
253
254 // Draw shortcut hint if available
255 if (!info.shortcut.empty()) {
256 ImGui::SetCursorScreenPos(
257 ImVec2(cursor_pos.x + 10, cursor_pos.y + button_size.y - 20));
258 ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "%s", info.shortcut.c_str());
259 }
260
261 // Hover glow effect
262 if (is_hovered) {
263 ImU32 glow_color = ImGui::GetColorU32(
264 ImVec4(base_color.x, base_color.y, base_color.z, 0.2f));
265 draw_list->AddRectFilled(
266 cursor_pos,
267 ImVec2(cursor_pos.x + button_size.x, cursor_pos.y + button_size.y),
268 glow_color, 4.0f);
269 }
270
271 // Enhanced tooltip
272 if (is_hovered) {
273 ImGui::SetNextWindowSize(ImVec2(300, 0), ImGuiCond_Always);
274 ImGui::BeginTooltip();
275 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); // Medium font
276 ImGui::TextColored(base_color, "%s %s", info.icon.c_str(), info.name.c_str());
277 ImGui::PopFont();
278 ImGui::Separator();
279 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 280);
280 ImGui::TextWrapped("%s", info.description.c_str());
281 ImGui::PopTextWrapPos();
282 if (!info.shortcut.empty()) {
283 ImGui::Spacing();
284 ImGui::TextColored(base_color, ICON_MD_KEYBOARD " %s", info.shortcut.c_str());
285 }
286 if (is_recent) {
287 ImGui::Spacing();
288 ImGui::TextColored(ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
289 ICON_MD_STAR " Recently used");
290 }
291 ImGui::EndTooltip();
292 }
293
294 if (clicked) {
295 if (editor_manager_) {
298 show_ = false;
299 }
300 }
301
302 ImGui::PopID();
303}
304
306 // Remove if already in list
307 auto it = std::find(recent_editors_.begin(), recent_editors_.end(), type);
308 if (it != recent_editors_.end()) {
309 recent_editors_.erase(it);
310 }
311
312 // Add to front
313 recent_editors_.insert(recent_editors_.begin(), type);
314
315 // Limit size
316 if (recent_editors_.size() > kMaxRecentEditors) {
318 }
319
321}
322
324 try {
325 auto data = util::LoadFileFromConfigDir("recent_editors.txt");
326 if (!data.empty()) {
327 std::istringstream ss(data);
328 std::string line;
329 while (std::getline(ss, line) &&
331 int type_int = std::stoi(line);
332 if (type_int >= 0 &&
333 type_int < static_cast<int>(EditorType::kSettings)) {
334 recent_editors_.push_back(static_cast<EditorType>(type_int));
335 }
336 }
337 }
338 } catch (...) {
339 // Ignore errors
340 }
341}
342
344 try {
345 std::ostringstream ss;
346 for (EditorType type : recent_editors_) {
347 ss << static_cast<int>(type) << "\n";
348 }
349 util::SaveFile("recent_editors.txt", ss.str());
350 } catch (...) {
351 // Ignore save errors
352 }
353}
354
359
360} // namespace editor
361} // namespace yaze
std::vector< EditorInfo > editors_
DashboardPanel(EditorManager *editor_manager)
void DrawEditorPanel(const EditorInfo &info, int index)
static constexpr size_t kMaxRecentEditors
std::vector< EditorType > recent_editors_
void MarkRecentlyUsed(EditorType type)
The EditorManager controls the main editor window and manages the various editor classes.
void SwitchToEditor(EditorType editor_type, bool force_visible=false, bool from_dialog=false)
void SetPosition(Position pos)
bool Begin(bool *p_open=nullptr)
void SetDefaultSize(float width, float height)
#define ICON_MD_APPS
Definition icons.h:168
#define ICON_MD_EMOJI_EMOTIONS
Definition icons.h:672
#define ICON_MD_DATA_ARRAY
Definition icons.h:519
#define ICON_MD_STAR
Definition icons.h:1848
#define ICON_MD_MAP
Definition icons.h:1173
#define ICON_MD_CODE
Definition icons.h:434
#define ICON_MD_VIDEOGAME_ASSET
Definition icons.h:2076
#define ICON_MD_CHAT_BUBBLE
Definition icons.h:395
#define ICON_MD_EDIT
Definition icons.h:645
#define ICON_MD_CASTLE
Definition icons.h:380
#define ICON_MD_MUSIC_NOTE
Definition icons.h:1264
#define ICON_MD_KEYBOARD
Definition icons.h:1028
#define ICON_MD_DASHBOARD
Definition icons.h:517
#define ICON_MD_PALETTE
Definition icons.h:1370
#define ICON_MD_TV
Definition icons.h:2032
#define ICON_MD_COLOR_LENS
Definition icons.h:440
#define ICON_MD_SMART_TOY
Definition icons.h:1781
#define ICON_MD_HISTORY
Definition icons.h:946
const char * GetCtrlDisplayName()
Get the display name for the primary modifier key.
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