yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
project_management_panel.cc
Go to the documentation of this file.
2
3#include "absl/strings/str_format.h"
7#include "imgui/imgui.h"
8#include "rom/rom.h"
9
10namespace yaze {
11namespace editor {
12
14 if (!project_) {
15 ImGui::TextDisabled("No project loaded");
16 ImGui::Spacing();
17 ImGui::TextWrapped(
18 "Open a .yaze project file or create a new project to access "
19 "project management features.");
20 return;
21 }
22
24 ImGui::Separator();
26 ImGui::Separator();
28 ImGui::Separator();
30}
31
33 // Section header
34 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetPrimaryVec4());
35 ImGui::Text("%s Project", ICON_MD_FOLDER_SPECIAL);
36 ImGui::PopStyleColor();
37 ImGui::Spacing();
38
39 // Project file path (read-only, click to copy)
40 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Path:");
41 ImGui::SameLine();
42 if (ImGui::Selectable(project_->filepath.c_str(), false,
43 ImGuiSelectableFlags_None,
44 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
45 ImGui::SetClipboardText(project_->filepath.c_str());
46 if (toast_manager_) {
47 toast_manager_->Show("Path copied to clipboard", ToastType::kInfo);
48 }
49 }
50 if (ImGui::IsItemHovered()) {
51 ImGui::SetTooltip("Click to copy path");
52 }
53
54 ImGui::Spacing();
55
56 // Editable Project Name
57 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Project Name:");
58 static char name_buffer[256] = {};
59 if (name_buffer[0] == '\0' && !project_->name.empty()) {
60 strncpy(name_buffer, project_->name.c_str(), sizeof(name_buffer) - 1);
61 }
62 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
63 if (ImGui::InputText("##project_name", name_buffer, sizeof(name_buffer))) {
64 project_->name = name_buffer;
65 project_dirty_ = true;
66 }
67
68 // Editable Author
69 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Author:");
70 static char author_buffer[256] = {};
71 if (author_buffer[0] == '\0' && !project_->metadata.author.empty()) {
72 strncpy(author_buffer, project_->metadata.author.c_str(),
73 sizeof(author_buffer) - 1);
74 }
75 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
76 if (ImGui::InputText("##author", author_buffer, sizeof(author_buffer))) {
77 project_->metadata.author = author_buffer;
78 project_dirty_ = true;
79 }
80
81 // Editable Description
82 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Description:");
83 static char desc_buffer[1024] = {};
84 if (desc_buffer[0] == '\0' && !project_->metadata.description.empty()) {
85 strncpy(desc_buffer, project_->metadata.description.c_str(),
86 sizeof(desc_buffer) - 1);
87 }
88 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
89 if (ImGui::InputTextMultiline("##description", desc_buffer,
90 sizeof(desc_buffer), ImVec2(0, 60))) {
91 project_->metadata.description = desc_buffer;
92 project_dirty_ = true;
93 }
94
95 ImGui::Spacing();
96}
97
99 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetPrimaryVec4());
100 ImGui::Text("%s ROM File", ICON_MD_MEMORY);
101 ImGui::PopStyleColor();
102 ImGui::Spacing();
103
104 // Current ROM
105 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Current ROM:");
106 if (project_->rom_filename.empty()) {
107 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
108 ImGui::TextColored(gui::ConvertColorToImVec4(theme.warning), "Not configured");
109 } else {
110 // Show just the filename, full path on hover
111 std::string filename = project_->rom_filename;
112 size_t pos = filename.find_last_of("/\\");
113 if (pos != std::string::npos) {
114 filename = filename.substr(pos + 1);
115 }
116 ImGui::Text("%s", filename.c_str());
117 if (ImGui::IsItemHovered()) {
118 ImGui::SetTooltip("%s", project_->rom_filename.c_str());
119 }
120 }
121
122 // ROM status
123 if (rom_ && rom_->is_loaded()) {
124 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Title:");
125 ImGui::SameLine();
126 ImGui::Text("%s", rom_->title().c_str());
127
128 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Size:");
129 ImGui::SameLine();
130 ImGui::Text("%.2f MB", static_cast<float>(rom_->size()) / (1024 * 1024));
131
132 if (rom_->dirty()) {
133 const auto& theme2 = gui::ThemeManager::Get().GetCurrentTheme();
134 ImGui::TextColored(gui::ConvertColorToImVec4(theme2.warning),
135 "%s Unsaved changes", ICON_MD_WARNING);
136 }
137 }
138
139 ImGui::Spacing();
140
141 // Action buttons
142 float button_width = (ImGui::GetContentRegionAvail().x - 8) / 2;
143
144 if (ImGui::Button(ICON_MD_SWAP_HORIZ " Swap ROM", ImVec2(button_width, 0))) {
145 if (swap_rom_callback_) {
147 }
148 }
149 if (ImGui::IsItemHovered()) {
150 ImGui::SetTooltip("Replace the ROM file for this project");
151 }
152
153 ImGui::SameLine();
154
155 if (ImGui::Button(ICON_MD_REFRESH " Reload", ImVec2(button_width, 0))) {
158 }
159 }
160 if (ImGui::IsItemHovered()) {
161 ImGui::SetTooltip("Reload ROM from disk");
162 }
163
164 ImGui::Spacing();
165}
166
168 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetPrimaryVec4());
169 ImGui::Text("%s Version Control", ICON_MD_HISTORY);
170 ImGui::PopStyleColor();
171 ImGui::Spacing();
172
173 if (!version_manager_) {
174 ImGui::TextDisabled("Version manager not available");
175 return;
176 }
177
178 bool git_initialized = version_manager_->IsGitInitialized();
179
180 if (!git_initialized) {
181 ImGui::TextWrapped(
182 "Git is not initialized for this project. Initialize Git to enable "
183 "version control and snapshots.");
184 ImGui::Spacing();
185
186 if (ImGui::Button(ICON_MD_ADD " Initialize Git",
187 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
188 auto status = version_manager_->InitializeGit();
189 if (status.ok()) {
190 if (toast_manager_) {
191 toast_manager_->Show("Git repository initialized",
193 }
194 } else {
195 if (toast_manager_) {
197 absl::StrFormat("Failed to initialize Git: %s", status.message()),
199 }
200 }
201 }
202 return;
203 }
204
205 // Show current commit
206 std::string current_hash = version_manager_->GetCurrentHash();
207 if (!current_hash.empty()) {
208 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Current:");
209 ImGui::SameLine();
210 ImGui::Text("%s", current_hash.substr(0, 7).c_str());
211 }
212
213 ImGui::Spacing();
214
215 // Create snapshot section
216 ImGui::Text("Create Snapshot:");
217 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
218 ImGui::InputTextWithHint("##snapshot_msg", "Snapshot message...",
220
221 if (ImGui::Button(ICON_MD_CAMERA_ALT " Create Snapshot",
222 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
223 std::string msg =
224 snapshot_message_[0] ? snapshot_message_ : "Manual snapshot";
225 auto result = version_manager_->CreateSnapshot(msg);
226 if (result.ok()) {
227 if (toast_manager_) {
229 absl::StrFormat("Snapshot created: %s", result->commit_hash),
231 }
232 snapshot_message_[0] = '\0';
233 history_dirty_ = true;
234 } else {
235 if (toast_manager_) {
237 absl::StrFormat("Snapshot failed: %s", result.status().message()),
239 }
240 }
241 }
242 if (ImGui::IsItemHovered()) {
243 ImGui::SetTooltip(
244 "Create a snapshot of your project (Git commit + ROM backup)");
245 }
246
247 // Show recent history
249}
250
253 return;
254 }
255
256 ImGui::Spacing();
257 if (ImGui::CollapsingHeader(ICON_MD_LIST " Recent Snapshots",
258 ImGuiTreeNodeFlags_DefaultOpen)) {
259 // Refresh history if needed
260 if (history_dirty_) {
262 history_dirty_ = false;
263 }
264
265 if (history_cache_.empty()) {
266 ImGui::TextDisabled("No snapshots yet");
267 } else {
268 for (const auto& entry : history_cache_) {
269 // Format: "hash message"
270 size_t space_pos = entry.find(' ');
271 std::string hash =
272 space_pos != std::string::npos ? entry.substr(0, 7) : entry;
273 std::string message =
274 space_pos != std::string::npos ? entry.substr(space_pos + 1) : "";
275
276 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
277 ImGui::Text("%s", hash.c_str());
278 ImGui::PopStyleColor();
279 ImGui::SameLine();
280 ImGui::TextWrapped("%s", message.c_str());
281 }
282 }
283 }
284}
285
287 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetPrimaryVec4());
288 ImGui::Text("%s Quick Actions", ICON_MD_BOLT);
289 ImGui::PopStyleColor();
290 ImGui::Spacing();
291
292 float button_width = ImGui::GetContentRegionAvail().x;
293
294 // Show unsaved indicator
295 if (project_dirty_) {
296 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
297 ImGui::TextColored(gui::ConvertColorToImVec4(theme.warning),
298 "%s Project has unsaved changes", ICON_MD_EDIT);
299 ImGui::Spacing();
300 }
301
302 if (ImGui::Button(ICON_MD_SAVE " Save Project", ImVec2(button_width, 0))) {
305 project_dirty_ = false;
306 }
307 }
308
309 ImGui::Spacing();
310
311 // Editable Code folder
312 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Code Folder:");
313 static char code_buffer[512] = {};
314 if (code_buffer[0] == '\0' && !project_->code_folder.empty()) {
315 strncpy(code_buffer, project_->code_folder.c_str(),
316 sizeof(code_buffer) - 1);
317 }
318 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 32);
319 if (ImGui::InputText("##code_folder", code_buffer, sizeof(code_buffer))) {
320 project_->code_folder = code_buffer;
321 project_dirty_ = true;
322 }
323 ImGui::SameLine();
324 if (ImGui::Button(ICON_MD_FOLDER_OPEN "##browse_code")) {
327 }
328 }
329 if (ImGui::IsItemHovered()) {
330 ImGui::SetTooltip("Browse for code folder");
331 }
332
333 // Editable Assets folder
334 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Assets Folder:");
335 static char assets_buffer[512] = {};
336 if (assets_buffer[0] == '\0' && !project_->assets_folder.empty()) {
337 strncpy(assets_buffer, project_->assets_folder.c_str(),
338 sizeof(assets_buffer) - 1);
339 }
340 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 32);
341 if (ImGui::InputText("##assets_folder", assets_buffer,
342 sizeof(assets_buffer))) {
343 project_->assets_folder = assets_buffer;
344 project_dirty_ = true;
345 }
346 ImGui::SameLine();
347 if (ImGui::Button(ICON_MD_FOLDER_OPEN "##browse_assets")) {
349 browse_folder_callback_("assets");
350 }
351 }
352 if (ImGui::IsItemHovered()) {
353 ImGui::SetTooltip("Browse for assets folder");
354 }
355
356 // Editable Build target
357 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Build Target:");
358 static char build_buffer[256] = {};
359 if (build_buffer[0] == '\0' && !project_->build_target.empty()) {
360 strncpy(build_buffer, project_->build_target.c_str(),
361 sizeof(build_buffer) - 1);
362 }
363 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
364 if (ImGui::InputText("##build_target", build_buffer, sizeof(build_buffer))) {
365 project_->build_target = build_buffer;
366 project_dirty_ = true;
367 }
368
369 // Build script
370 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Build Script:");
371 static char script_buffer[512] = {};
372 if (script_buffer[0] == '\0' && !project_->build_script.empty()) {
373 strncpy(script_buffer, project_->build_script.c_str(),
374 sizeof(script_buffer) - 1);
375 }
376 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
377 if (ImGui::InputText("##build_script", script_buffer,
378 sizeof(script_buffer))) {
379 project_->build_script = script_buffer;
380 project_dirty_ = true;
381 }
382}
383
384} // namespace editor
385} // namespace yaze
386
auto size() const
Definition rom.h:134
bool dirty() const
Definition rom.h:129
bool is_loaded() const
Definition rom.h:128
auto title() const
Definition rom.h:133
std::vector< std::string > GetHistory(int limit=10) const
std::string GetCurrentHash() const
absl::StatusOr< SnapshotResult > CreateSnapshot(const std::string &message)
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define ICON_MD_FOLDER_OPEN
Definition icons.h:813
#define ICON_MD_MEMORY
Definition icons.h:1195
#define ICON_MD_WARNING
Definition icons.h:2123
#define ICON_MD_FOLDER_SPECIAL
Definition icons.h:815
#define ICON_MD_CAMERA_ALT
Definition icons.h:355
#define ICON_MD_SWAP_HORIZ
Definition icons.h:1896
#define ICON_MD_REFRESH
Definition icons.h:1572
#define ICON_MD_EDIT
Definition icons.h:645
#define ICON_MD_LIST
Definition icons.h:1094
#define ICON_MD_ADD
Definition icons.h:86
#define ICON_MD_BOLT
Definition icons.h:282
#define ICON_MD_SAVE
Definition icons.h:1644
#define ICON_MD_HISTORY
Definition icons.h:946
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:23
ImVec4 GetPrimaryVec4()
ImVec4 GetTextSecondaryVec4()
ProjectMetadata metadata
Definition project.h:86
std::string rom_filename
Definition project.h:92
std::string assets_folder
Definition project.h:98
std::string code_folder
Definition project.h:97