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),
109 "Not configured");
110 } else {
111 // Show just the filename, full path on hover
112 std::string filename = project_->rom_filename;
113 size_t pos = filename.find_last_of("/\\");
114 if (pos != std::string::npos) {
115 filename = filename.substr(pos + 1);
116 }
117 ImGui::Text("%s", filename.c_str());
118 if (ImGui::IsItemHovered()) {
119 ImGui::SetTooltip("%s", project_->rom_filename.c_str());
120 }
121 }
122
123 // ROM status
124 if (rom_ && rom_->is_loaded()) {
125 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Title:");
126 ImGui::SameLine();
127 ImGui::Text("%s", rom_->title().c_str());
128
129 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Size:");
130 ImGui::SameLine();
131 ImGui::Text("%.2f MB", static_cast<float>(rom_->size()) / (1024 * 1024));
132
133 if (rom_->dirty()) {
134 const auto& theme2 = gui::ThemeManager::Get().GetCurrentTheme();
135 ImGui::TextColored(gui::ConvertColorToImVec4(theme2.warning),
136 "%s Unsaved changes", ICON_MD_WARNING);
137 }
138 }
139
140 ImGui::Spacing();
141
142 // Action buttons
143 float button_width = (ImGui::GetContentRegionAvail().x - 8) / 2;
144
145 if (ImGui::Button(ICON_MD_SWAP_HORIZ " Swap ROM", ImVec2(button_width, 0))) {
146 if (swap_rom_callback_) {
148 }
149 }
150 if (ImGui::IsItemHovered()) {
151 ImGui::SetTooltip("Replace the ROM file for this project");
152 }
153
154 ImGui::SameLine();
155
156 if (ImGui::Button(ICON_MD_REFRESH " Reload", ImVec2(button_width, 0))) {
159 }
160 }
161 if (ImGui::IsItemHovered()) {
162 ImGui::SetTooltip("Reload ROM from disk");
163 }
164
165 ImGui::Spacing();
166}
167
169 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetPrimaryVec4());
170 ImGui::Text("%s Version Control", ICON_MD_HISTORY);
171 ImGui::PopStyleColor();
172 ImGui::Spacing();
173
174 if (!version_manager_) {
175 ImGui::TextDisabled("Version manager not available");
176 return;
177 }
178
179 bool git_initialized = version_manager_->IsGitInitialized();
180
181 if (!git_initialized) {
182 ImGui::TextWrapped(
183 "Git is not initialized for this project. Initialize Git to enable "
184 "version control and snapshots.");
185 ImGui::Spacing();
186
187 if (ImGui::Button(ICON_MD_ADD " Initialize Git",
188 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
189 auto status = version_manager_->InitializeGit();
190 if (status.ok()) {
191 if (toast_manager_) {
192 toast_manager_->Show("Git repository initialized",
194 }
195 } else {
196 if (toast_manager_) {
198 absl::StrFormat("Failed to initialize Git: %s", status.message()),
200 }
201 }
202 }
203 return;
204 }
205
206 // Show current commit
207 std::string current_hash = version_manager_->GetCurrentHash();
208 if (!current_hash.empty()) {
209 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Current:");
210 ImGui::SameLine();
211 ImGui::Text("%s", current_hash.substr(0, 7).c_str());
212 }
213
214 ImGui::Spacing();
215
216 // Create snapshot section
217 ImGui::Text("Create Snapshot:");
218 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
219 ImGui::InputTextWithHint("##snapshot_msg", "Snapshot message...",
221
222 if (ImGui::Button(ICON_MD_CAMERA_ALT " Create Snapshot",
223 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
224 std::string msg =
225 snapshot_message_[0] ? snapshot_message_ : "Manual snapshot";
226 auto result = version_manager_->CreateSnapshot(msg);
227 if (result.ok()) {
228 if (toast_manager_) {
230 absl::StrFormat("Snapshot created: %s", result->commit_hash),
232 }
233 snapshot_message_[0] = '\0';
234 history_dirty_ = true;
235 } else {
236 if (toast_manager_) {
238 absl::StrFormat("Snapshot failed: %s", result.status().message()),
240 }
241 }
242 }
243 if (ImGui::IsItemHovered()) {
244 ImGui::SetTooltip(
245 "Create a snapshot of your project (Git commit + ROM backup)");
246 }
247
248 // Show recent history
250}
251
254 return;
255 }
256
257 ImGui::Spacing();
258 if (ImGui::CollapsingHeader(ICON_MD_LIST " Recent Snapshots",
259 ImGuiTreeNodeFlags_DefaultOpen)) {
260 // Refresh history if needed
261 if (history_dirty_) {
263 history_dirty_ = false;
264 }
265
266 if (history_cache_.empty()) {
267 ImGui::TextDisabled("No snapshots yet");
268 } else {
269 for (const auto& entry : history_cache_) {
270 // Format: "hash message"
271 size_t space_pos = entry.find(' ');
272 std::string hash =
273 space_pos != std::string::npos ? entry.substr(0, 7) : entry;
274 std::string message =
275 space_pos != std::string::npos ? entry.substr(space_pos + 1) : "";
276
277 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetTextSecondaryVec4());
278 ImGui::Text("%s", hash.c_str());
279 ImGui::PopStyleColor();
280 ImGui::SameLine();
281 ImGui::TextWrapped("%s", message.c_str());
282 }
283 }
284 }
285}
286
288 ImGui::PushStyleColor(ImGuiCol_Text, gui::GetPrimaryVec4());
289 ImGui::Text("%s Quick Actions", ICON_MD_BOLT);
290 ImGui::PopStyleColor();
291 ImGui::Spacing();
292
293 float button_width = ImGui::GetContentRegionAvail().x;
294
295 // Show unsaved indicator
296 if (project_dirty_) {
297 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
298 ImGui::TextColored(gui::ConvertColorToImVec4(theme.warning),
299 "%s Project has unsaved changes", ICON_MD_EDIT);
300 ImGui::Spacing();
301 }
302
303 if (ImGui::Button(ICON_MD_SAVE " Save Project", ImVec2(button_width, 0))) {
306 project_dirty_ = false;
307 }
308 }
309
310 ImGui::Spacing();
311
312 // Editable Code folder
313 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Code Folder:");
314 static char code_buffer[512] = {};
315 if (code_buffer[0] == '\0' && !project_->code_folder.empty()) {
316 strncpy(code_buffer, project_->code_folder.c_str(),
317 sizeof(code_buffer) - 1);
318 }
319 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 32);
320 if (ImGui::InputText("##code_folder", code_buffer, sizeof(code_buffer))) {
321 project_->code_folder = code_buffer;
322 project_dirty_ = true;
323 }
324 ImGui::SameLine();
325 if (ImGui::Button(ICON_MD_FOLDER_OPEN "##browse_code")) {
328 }
329 }
330 if (ImGui::IsItemHovered()) {
331 ImGui::SetTooltip("Browse for code folder");
332 }
333
334 // Editable Assets folder
335 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Assets Folder:");
336 static char assets_buffer[512] = {};
337 if (assets_buffer[0] == '\0' && !project_->assets_folder.empty()) {
338 strncpy(assets_buffer, project_->assets_folder.c_str(),
339 sizeof(assets_buffer) - 1);
340 }
341 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 32);
342 if (ImGui::InputText("##assets_folder", assets_buffer,
343 sizeof(assets_buffer))) {
344 project_->assets_folder = assets_buffer;
345 project_dirty_ = true;
346 }
347 ImGui::SameLine();
348 if (ImGui::Button(ICON_MD_FOLDER_OPEN "##browse_assets")) {
350 browse_folder_callback_("assets");
351 }
352 }
353 if (ImGui::IsItemHovered()) {
354 ImGui::SetTooltip("Browse for assets folder");
355 }
356
357 // Editable Build target
358 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Build Target:");
359 static char build_buffer[256] = {};
360 if (build_buffer[0] == '\0' && !project_->build_target.empty()) {
361 strncpy(build_buffer, project_->build_target.c_str(),
362 sizeof(build_buffer) - 1);
363 }
364 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
365 if (ImGui::InputText("##build_target", build_buffer, sizeof(build_buffer))) {
366 project_->build_target = build_buffer;
367 project_dirty_ = true;
368 }
369
370 // Build script
371 ImGui::TextColored(gui::GetTextSecondaryVec4(), "Build Script:");
372 static char script_buffer[512] = {};
373 if (script_buffer[0] == '\0' && !project_->build_script.empty()) {
374 strncpy(script_buffer, project_->build_script.c_str(),
375 sizeof(script_buffer) - 1);
376 }
377 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
378 if (ImGui::InputText("##build_script", script_buffer,
379 sizeof(script_buffer))) {
380 project_->build_script = script_buffer;
381 project_dirty_ = true;
382 }
383}
384
385} // namespace editor
386} // namespace yaze
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