6#include "absl/strings/str_format.h"
12#include "imgui/imgui.h"
15#include "yaze_config.h"
23void CopyToBuffer(std::array<char, N>* buffer,
const std::string& value) {
25 const size_t length = std::min(value.size(), N - 1);
26 std::copy_n(value.data(), length, buffer->data());
32 return ImVec4(0.45f, 0.70f, 0.95f, 1.0f);
34 return ImVec4(0.35f, 0.80f, 0.45f, 1.0f);
36 return ImVec4(0.90f, 0.35f, 0.35f, 1.0f);
58 const char* fallback_icon) {
64 WorkflowColor(status.
state),
"%s %s",
65 WorkflowIcon(status.
state, fallback_icon),
67 if (!status.
detail.empty()) {
68 ImGui::TextWrapped(
"%s", status.
detail.c_str());
71 ImGui::TextWrapped(
"%s", status.
output_tail.c_str());
109 return absl::FailedPreconditionError(
"Project save callback unavailable");
120 ImGui::TextDisabled(tr(
"No project loaded"));
123 tr(
"Open a .yaze project file or create a new project to access "
124 "project management features."));
154 if (project_version.empty()) {
160 project_version.c_str());
161 if (ImGui::IsItemHovered()) {
162 ImGui::SetTooltip(tr(
"Project saved with v%s; running v%s"),
166 ImGui::Text(
"%s", project_version.c_str());
177 ImGuiSelectableFlags_None,
178 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
184 if (ImGui::IsItemHovered()) {
185 ImGui::SetTooltip(tr(
"Click to copy path"));
192 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
193 if (ImGui::InputText(
"##project_name",
name_buffer_.data(),
201 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
210 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
224 ImGui::TextWrapped(tr(
225 "Primary data lives under the .yaze root. Click any path to copy it."));
229 if (!app_root.ok()) {
232 tr(
"Storage unavailable: %s"),
233 std::string(app_root.status().message()).c_str());
237 std::vector<std::pair<const char*, std::filesystem::path>> locations = {
239 {
"Projects", *app_root /
"projects"},
240 {
"Layouts", *app_root /
"layouts"},
241 {
"Workspaces", *app_root /
"workspaces"},
242 {
"Logs", *app_root /
"logs"},
243 {
"Agent", *app_root /
"agent"}};
246 if (temp_root.ok()) {
247 locations.emplace_back(
"Temp", *temp_root);
250 if (ImGui::BeginTable(
"##storage_locations", 2,
251 ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersInnerV |
252 ImGuiTableFlags_SizingStretchProp)) {
253 ImGui::TableSetupColumn(
"Location", ImGuiTableColumnFlags_WidthFixed,
255 ImGui::TableSetupColumn(
"Path", ImGuiTableColumnFlags_WidthStretch);
256 for (
const auto& entry : locations) {
257 ImGui::TableNextRow();
258 ImGui::TableNextColumn();
260 ImGui::TableNextColumn();
261 const std::string display_path =
263 ImGui::PushID(entry.first);
264 if (ImGui::Selectable(display_path.c_str(),
false,
265 ImGuiSelectableFlags_SpanAllColumns)) {
266 ImGui::SetClipboardText(display_path.c_str());
271 if (ImGui::IsItemHovered()) {
272 ImGui::SetTooltip(tr(
"Click to copy"));
291 tr(
"Not configured"));
295 size_t pos = filename.find_last_of(
"/\\");
296 if (pos != std::string::npos) {
297 filename = filename.substr(pos + 1);
299 ImGui::Text(
"%s", filename.c_str());
300 if (ImGui::IsItemHovered()) {
309 ImGui::Text(
"%s",
rom_->
title().c_str());
313 ImGui::Text(tr(
"%.2f MB"),
314 static_cast<float>(
rom_->
size()) / (1024 * 1024));
326 float button_width = (ImGui::GetContentRegionAvail().x - 8) / 2;
333 if (ImGui::IsItemHovered()) {
334 ImGui::SetTooltip(tr(
"Replace the ROM file for this project"));
339 if (ImGui::Button(
ICON_MD_REFRESH " Reload", ImVec2(button_width, 0))) {
344 if (ImGui::IsItemHovered()) {
345 ImGui::SetTooltip(tr(
"Reload ROM from disk"));
357 ImGui::TextDisabled(tr(
"Version manager not available"));
363 if (!git_initialized) {
365 tr(
"Git is not initialized for this project. Initialize Git to enable "
366 "version control and snapshots."));
370 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
380 absl::StrFormat(
"Failed to initialize Git: %s", status.message()),
390 if (!current_hash.empty()) {
393 ImGui::Text(
"%s", current_hash.substr(0, 7).c_str());
399 ImGui::Text(tr(
"Create Snapshot:"));
400 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
401 ImGui::InputTextWithHint(
"##snapshot_msg",
"Snapshot message...",
405 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
412 absl::StrFormat(
"Snapshot created: %s", result->commit_hash),
420 absl::StrFormat(
"Snapshot failed: %s", result.status().message()),
425 if (ImGui::IsItemHovered()) {
427 tr(
"Create a snapshot of your project (Git commit + ROM backup)"));
440 if (ImGui::CollapsingHeader(
ICON_MD_LIST " Recent Snapshots",
441 ImGuiTreeNodeFlags_DefaultOpen)) {
449 ImGui::TextDisabled(tr(
"No snapshots yet"));
453 size_t space_pos = entry.find(
' ');
455 space_pos != std::string::npos ? entry.substr(0, 7) : entry;
456 std::string message =
457 space_pos != std::string::npos ? entry.substr(space_pos + 1) :
"";
461 ImGui::TextWrapped(
"%s", message.c_str());
471 float button_width = ImGui::GetContentRegionAvail().x;
481 if (ImGui::Button(
ICON_MD_SAVE " Save Project", ImVec2(button_width, 0))) {
485 if (ImGui::Button(
ICON_MD_BUILD " Build Project", ImVec2(button_width, 0))) {
494 ImVec2(button_width, 0))) {
500 ImVec2(button_width, 0))) {
515 ImGui::BeginChild(
"##build_output_log", ImVec2(0, 140),
true,
516 ImGuiWindowFlags_HorizontalScrollbar);
518 if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
519 ImGui::SetScrollHereY(1.0f);
533 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 32);
534 if (ImGui::InputText(
"##code_folder",
code_buffer_.data(),
545 if (ImGui::IsItemHovered()) {
546 ImGui::SetTooltip(tr(
"Browse for code folder"));
551 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 32);
563 if (ImGui::IsItemHovered()) {
564 ImGui::SetTooltip(tr(
"Browse for assets folder"));
569 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
578 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
std::vector< std::string > GetHistory(int limit=10) const
absl::Status InitializeGit()
std::string GetCurrentHash() const
absl::StatusOr< SnapshotResult > CreateSnapshot(const std::string &message)
bool IsGitInitialized() const
BuildProjectCallback build_project_callback_
absl::Status SaveProjectEdits()
std::string build_log_output_
char snapshot_message_[256]
SwapRomCallback swap_rom_callback_
void DrawProjectOverview()
std::array< char, 1024 > description_buffer_
SaveProjectCallback save_project_callback_
core::VersionManager * version_manager_
void ReloadProjectBuffers()
void DrawVersionControl()
RunProjectCallback run_project_callback_
std::array< char, 512 > code_buffer_
std::array< char, 256 > author_buffer_
void SetProject(project::YazeProject *project, bool dirty=false)
std::array< char, 256 > build_buffer_
ToastManager * toast_manager_
project::YazeProject * project_
ReloadRomCallback reload_rom_callback_
CancelBuildCallback cancel_build_callback_
std::array< char, 256 > name_buffer_
ProjectWorkflowStatus build_status_
std::array< char, 512 > assets_buffer_
void DrawStorageLocations()
ProjectWorkflowStatus run_status_
void DrawSnapshotHistory()
std::vector< std::string > history_cache_
BrowseFolderCallback browse_folder_callback_
std::array< char, 512 > script_buffer_
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define YAZE_VERSION_STRING
#define ICON_MD_FOLDER_OPEN
#define ICON_MD_FOLDER_SPECIAL
#define ICON_MD_CAMERA_ALT
#define ICON_MD_PLAY_ARROW
#define ICON_MD_SWAP_HORIZ
#define ICON_MD_CHECK_CIRCLE
void DrawWorkflowCard(const ProjectWorkflowStatus &status, const char *fallback_icon)
void CopyToBuffer(std::array< char, N > *buffer, const std::string &value)
ImVec4 ConvertColorToImVec4(const Color &color)
void ColoredText(const char *text, const ImVec4 &color)
ImVec4 GetTextSecondaryVec4()
void ColoredTextF(const ImVec4 &color, const char *fmt,...)
ProjectWorkflowState state
Modern project structure with comprehensive settings consolidation.
std::string assets_folder