imgui-frontend-engineer: refine agent editor wiring
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
#include "app/service/canvas_automation_service.h"
|
#include "app/service/canvas_automation_service.h"
|
||||||
#include "app/service/unified_grpc_server.h"
|
#include "app/service/unified_grpc_server.h"
|
||||||
#include "app/test/test_manager.h"
|
#include "app/test/test_manager.h"
|
||||||
|
#include "cli/service/agent/emulator_service_impl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
@@ -26,47 +27,8 @@ void Application::Initialize(const AppConfig& config) {
|
|||||||
config_ = config;
|
config_ = config;
|
||||||
LOG_INFO("App", "Initializing Application instance...");
|
LOG_INFO("App", "Initializing Application instance...");
|
||||||
|
|
||||||
#ifdef YAZE_WITH_GRPC
|
|
||||||
// Initialize gRPC server if enabled
|
|
||||||
if (config_.enable_test_harness) {
|
|
||||||
LOG_INFO("App", "Initializing gRPC automation services...");
|
|
||||||
canvas_automation_service_ = std::make_unique<CanvasAutomationServiceImpl>();
|
|
||||||
grpc_server_ = std::make_unique<YazeGRPCServer>();
|
|
||||||
|
|
||||||
// Initialize server with all services
|
|
||||||
// Note: RomService and ProposalApprovalManager will be connected later
|
|
||||||
// when we have a session context, but we can start the server now.
|
|
||||||
auto status = grpc_server_->Initialize(
|
|
||||||
config_.test_harness_port,
|
|
||||||
&yaze::test::TestManager::Get(),
|
|
||||||
nullptr, // ROM not loaded yet
|
|
||||||
nullptr, // Version manager not ready
|
|
||||||
nullptr, // Approval manager not ready
|
|
||||||
canvas_automation_service_.get()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (status.ok()) {
|
|
||||||
status = grpc_server_->StartAsync(); // Start in background thread
|
|
||||||
if (!status.ok()) {
|
|
||||||
LOG_ERROR("App", "Failed to start gRPC server: %s", std::string(status.message()).c_str());
|
|
||||||
} else {
|
|
||||||
LOG_INFO("App", "gRPC server started on port %d", config_.test_harness_port);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG_ERROR("App", "Failed to initialize gRPC server: %s", std::string(status.message()).c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
controller_ = std::make_unique<Controller>();
|
controller_ = std::make_unique<Controller>();
|
||||||
|
|
||||||
#ifdef YAZE_WITH_GRPC
|
|
||||||
// Connect services to controller/editor manager
|
|
||||||
if (canvas_automation_service_) {
|
|
||||||
controller_->SetCanvasAutomationService(canvas_automation_service_.get());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Process pending ROM load if we have one (from flags/config - non-WASM only)
|
// Process pending ROM load if we have one (from flags/config - non-WASM only)
|
||||||
std::string start_path = config_.rom_file;
|
std::string start_path = config_.rom_file;
|
||||||
|
|
||||||
@@ -102,6 +64,58 @@ void Application::Initialize(const AppConfig& config) {
|
|||||||
if (!start_path.empty() && controller_->editor_manager()) {
|
if (!start_path.empty() && controller_->editor_manager()) {
|
||||||
RunStartupActions();
|
RunStartupActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef YAZE_WITH_GRPC
|
||||||
|
// Initialize gRPC server if enabled
|
||||||
|
if (config_.enable_test_harness) {
|
||||||
|
LOG_INFO("App", "Initializing gRPC automation services...");
|
||||||
|
canvas_automation_service_ = std::make_unique<CanvasAutomationServiceImpl>();
|
||||||
|
grpc_server_ = std::make_unique<YazeGRPCServer>();
|
||||||
|
|
||||||
|
auto rom_getter = [this]() { return controller_->GetCurrentRom(); };
|
||||||
|
|
||||||
|
if (controller_->editor_manager()) {
|
||||||
|
auto emulator_service =
|
||||||
|
std::make_unique<yaze::net::EmulatorServiceImpl>(
|
||||||
|
&controller_->editor_manager()->emulator(),
|
||||||
|
rom_getter);
|
||||||
|
auto add_status =
|
||||||
|
grpc_server_->AddService(std::move(emulator_service));
|
||||||
|
if (!add_status.ok()) {
|
||||||
|
LOG_ERROR("App", "Failed to attach emulator service: %s",
|
||||||
|
std::string(add_status.message()).c_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_WARN("App", "EditorManager not ready; emulator gRPC disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize server with all services
|
||||||
|
auto status = grpc_server_->Initialize(
|
||||||
|
config_.test_harness_port,
|
||||||
|
&yaze::test::TestManager::Get(),
|
||||||
|
rom_getter,
|
||||||
|
nullptr, // Version manager not ready
|
||||||
|
nullptr, // Approval manager not ready
|
||||||
|
canvas_automation_service_.get()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (status.ok()) {
|
||||||
|
status = grpc_server_->StartAsync(); // Start in background thread
|
||||||
|
if (!status.ok()) {
|
||||||
|
LOG_ERROR("App", "Failed to start gRPC server: %s", std::string(status.message()).c_str());
|
||||||
|
} else {
|
||||||
|
LOG_INFO("App", "gRPC server started on port %d", config_.test_harness_port);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("App", "Failed to initialize gRPC server: %s", std::string(status.message()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect services to controller/editor manager
|
||||||
|
if (canvas_automation_service_) {
|
||||||
|
controller_->SetCanvasAutomationService(canvas_automation_service_.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
#include "app/platform/sdl_compat.h"
|
#include "app/platform/sdl_compat.h"
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "absl/status/status.h"
|
#include "absl/status/status.h"
|
||||||
@@ -21,8 +25,17 @@ namespace yaze {
|
|||||||
|
|
||||||
absl::Status Controller::OnEntry(std::string filename) {
|
absl::Status Controller::OnEntry(std::string filename) {
|
||||||
// Create window backend using factory (auto-selects SDL2 or SDL3)
|
// Create window backend using factory (auto-selects SDL2 or SDL3)
|
||||||
window_backend_ = platform::WindowBackendFactory::Create(
|
auto backend_type = platform::WindowBackendFactory::GetDefaultType();
|
||||||
platform::WindowBackendFactory::GetDefaultType());
|
auto renderer_type = gfx::RendererFactory::GetDefaultBackendType();
|
||||||
|
#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
|
||||||
|
backend_type = platform::WindowBackendType::IOS;
|
||||||
|
renderer_type = gfx::RendererBackendType::Metal;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
window_backend_ = platform::WindowBackendFactory::Create(backend_type);
|
||||||
|
if (!window_backend_) {
|
||||||
|
return absl::InternalError("Failed to create window backend");
|
||||||
|
}
|
||||||
|
|
||||||
platform::WindowConfig config;
|
platform::WindowConfig config;
|
||||||
config.title = "Yet Another Zelda3 Editor";
|
config.title = "Yet Another Zelda3 Editor";
|
||||||
@@ -32,7 +45,7 @@ absl::Status Controller::OnEntry(std::string filename) {
|
|||||||
RETURN_IF_ERROR(window_backend_->Initialize(config));
|
RETURN_IF_ERROR(window_backend_->Initialize(config));
|
||||||
|
|
||||||
// Create renderer via factory (auto-selects SDL2 or SDL3)
|
// Create renderer via factory (auto-selects SDL2 or SDL3)
|
||||||
renderer_ = gfx::RendererFactory::Create();
|
renderer_ = gfx::RendererFactory::Create(renderer_type);
|
||||||
if (!window_backend_->InitializeRenderer(renderer_.get())) {
|
if (!window_backend_->InitializeRenderer(renderer_.get())) {
|
||||||
return absl::InternalError("Failed to initialize renderer");
|
return absl::InternalError("Failed to initialize renderer");
|
||||||
}
|
}
|
||||||
@@ -162,6 +175,11 @@ absl::Status Controller::OnLoad() {
|
|||||||
if (!show_menu_bar && editor_manager_.ui_coordinator()) {
|
if (!show_menu_bar && editor_manager_.ui_coordinator()) {
|
||||||
editor_manager_.ui_coordinator()->DrawMenuBarRestoreButton();
|
editor_manager_.ui_coordinator()->DrawMenuBarRestoreButton();
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (window_backend_) {
|
||||||
|
window_backend_->NewImGuiFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
gui::WidgetIdRegistry::Instance().BeginFrame();
|
gui::WidgetIdRegistry::Instance().BeginFrame();
|
||||||
absl::Status update_status = editor_manager_.Update();
|
absl::Status update_status = editor_manager_.Update();
|
||||||
@@ -192,7 +210,9 @@ void Controller::DoRender() const {
|
|||||||
// Gentle frame rate cap to prevent excessive CPU usage
|
// Gentle frame rate cap to prevent excessive CPU usage
|
||||||
// Only delay if we're rendering faster than 144 FPS (< 7ms per frame)
|
// Only delay if we're rendering faster than 144 FPS (< 7ms per frame)
|
||||||
if (delta_time < 0.007f) {
|
if (delta_time < 0.007f) {
|
||||||
|
#if TARGET_OS_IPHONE != 1
|
||||||
SDL_Delay(1); // Tiny delay to yield CPU without affecting ImGui timing
|
SDL_Delay(1); // Tiny delay to yield CPU without affecting ImGui timing
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "app/editor/agent/agent_chat.h"
|
#include "app/editor/agent/agent_chat.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
#include "app/gui/core/theme_manager.h"
|
#include "app/gui/core/theme_manager.h"
|
||||||
#include "imgui/imgui.h"
|
#include "imgui/imgui.h"
|
||||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||||
|
#include "util/platform_paths.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
|
|
||||||
#ifdef YAZE_WITH_JSON
|
#ifdef YAZE_WITH_JSON
|
||||||
@@ -22,6 +24,27 @@
|
|||||||
namespace yaze {
|
namespace yaze {
|
||||||
namespace editor {
|
namespace editor {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::string ResolveAgentChatHistoryPath() {
|
||||||
|
auto agent_dir = util::PlatformPaths::GetAppDataSubdirectory("agent");
|
||||||
|
if (agent_dir.ok()) {
|
||||||
|
return (*agent_dir / "agent_chat_history.json").string();
|
||||||
|
}
|
||||||
|
auto docs_dir = util::PlatformPaths::GetUserDocumentsSubdirectory("agent");
|
||||||
|
if (docs_dir.ok()) {
|
||||||
|
return (*docs_dir / "agent_chat_history.json").string();
|
||||||
|
}
|
||||||
|
auto temp_dir = util::PlatformPaths::GetTempDirectory();
|
||||||
|
if (temp_dir.ok()) {
|
||||||
|
return (*temp_dir / "agent_chat_history.json").string();
|
||||||
|
}
|
||||||
|
return (std::filesystem::current_path() / "agent_chat_history.json")
|
||||||
|
.string();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
AgentChat::AgentChat() {
|
AgentChat::AgentChat() {
|
||||||
// Default initialization
|
// Default initialization
|
||||||
}
|
}
|
||||||
@@ -119,7 +142,7 @@ void AgentChat::RenderToolbar() {
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
if (ImGui::Button(ICON_MD_SAVE " Save")) {
|
if (ImGui::Button(ICON_MD_SAVE " Save")) {
|
||||||
std::string filepath = ".yaze/agent_chat_history.json";
|
std::string filepath = ResolveAgentChatHistoryPath();
|
||||||
if (auto status = SaveHistory(filepath); !status.ok()) {
|
if (auto status = SaveHistory(filepath); !status.ok()) {
|
||||||
if (toast_manager_) {
|
if (toast_manager_) {
|
||||||
toast_manager_->Show("Failed to save history: " + std::string(status.message()), ToastType::kError);
|
toast_manager_->Show("Failed to save history: " + std::string(status.message()), ToastType::kError);
|
||||||
@@ -133,7 +156,7 @@ void AgentChat::RenderToolbar() {
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
if (ImGui::Button(ICON_MD_FOLDER_OPEN " Load")) {
|
if (ImGui::Button(ICON_MD_FOLDER_OPEN " Load")) {
|
||||||
std::string filepath = ".yaze/agent_chat_history.json";
|
std::string filepath = ResolveAgentChatHistoryPath();
|
||||||
if (auto status = LoadHistory(filepath); !status.ok()) {
|
if (auto status = LoadHistory(filepath); !status.ok()) {
|
||||||
if (toast_manager_) {
|
if (toast_manager_) {
|
||||||
toast_manager_->Show("Failed to load history: " + std::string(status.message()), ToastType::kError);
|
toast_manager_->Show("Failed to load history: " + std::string(status.message()), ToastType::kError);
|
||||||
@@ -480,7 +503,13 @@ absl::Status AgentChat::SaveHistory(const std::string& filepath) {
|
|||||||
// Create directory if needed
|
// Create directory if needed
|
||||||
std::filesystem::path path(filepath);
|
std::filesystem::path path(filepath);
|
||||||
if (path.has_parent_path()) {
|
if (path.has_parent_path()) {
|
||||||
std::filesystem::create_directories(path.parent_path());
|
std::error_code ec;
|
||||||
|
std::filesystem::create_directories(path.parent_path(), ec);
|
||||||
|
if (ec) {
|
||||||
|
return absl::InternalError(
|
||||||
|
absl::StrFormat("Failed to create history directory: %s",
|
||||||
|
ec.message()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ofstream file(filepath);
|
std::ofstream file(filepath);
|
||||||
|
|||||||
@@ -262,12 +262,19 @@ std::string AgentCollaborationCoordinator::GenerateSessionCode() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path AgentCollaborationCoordinator::SessionsDirectory() const {
|
std::filesystem::path AgentCollaborationCoordinator::SessionsDirectory() const {
|
||||||
auto config_dir = util::PlatformPaths::GetConfigDirectory();
|
auto agent_dir = util::PlatformPaths::GetAppDataSubdirectory("agent");
|
||||||
if (!config_dir.ok()) {
|
if (agent_dir.ok()) {
|
||||||
// Fallback to a local directory if config can't be determined.
|
return *agent_dir / "sessions";
|
||||||
return fs::current_path() / ".yaze" / "agent" / "sessions";
|
|
||||||
}
|
}
|
||||||
return *config_dir / "agent" / "sessions";
|
auto docs_dir = util::PlatformPaths::GetUserDocumentsSubdirectory("agent");
|
||||||
|
if (docs_dir.ok()) {
|
||||||
|
return *docs_dir / "sessions";
|
||||||
|
}
|
||||||
|
auto temp_dir = util::PlatformPaths::GetTempDirectory();
|
||||||
|
if (temp_dir.ok()) {
|
||||||
|
return *temp_dir / "agent" / "sessions";
|
||||||
|
}
|
||||||
|
return fs::current_path() / "agent" / "sessions";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path AgentCollaborationCoordinator::SessionFilePath(
|
std::filesystem::path AgentCollaborationCoordinator::SessionFilePath(
|
||||||
|
|||||||
@@ -1453,11 +1453,20 @@ absl::Status AgentEditor::ImportProfile(const std::filesystem::path& path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path AgentEditor::GetProfilesDirectory() const {
|
std::filesystem::path AgentEditor::GetProfilesDirectory() const {
|
||||||
auto config_dir = yaze::util::PlatformPaths::GetConfigDirectory();
|
auto agent_dir = yaze::util::PlatformPaths::GetAppDataSubdirectory("agent");
|
||||||
if (!config_dir.ok()) {
|
if (agent_dir.ok()) {
|
||||||
return std::filesystem::current_path() / ".yaze" / "agent" / "profiles";
|
return *agent_dir / "profiles";
|
||||||
}
|
}
|
||||||
return *config_dir / "agent" / "profiles";
|
auto docs_dir =
|
||||||
|
yaze::util::PlatformPaths::GetUserDocumentsSubdirectory("agent");
|
||||||
|
if (docs_dir.ok()) {
|
||||||
|
return *docs_dir / "profiles";
|
||||||
|
}
|
||||||
|
auto temp_dir = yaze::util::PlatformPaths::GetTempDirectory();
|
||||||
|
if (temp_dir.ok()) {
|
||||||
|
return *temp_dir / "agent" / "profiles";
|
||||||
|
}
|
||||||
|
return std::filesystem::current_path() / "agent" / "profiles";
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Status AgentEditor::EnsureProfilesDirectory() {
|
absl::Status AgentEditor::EnsureProfilesDirectory() {
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
#include "app/gui/core/input.h"
|
#include "app/gui/core/input.h"
|
||||||
#include "dungeon_canvas_viewer.h"
|
#include "dungeon_canvas_viewer.h"
|
||||||
#include "dungeon_coordinates.h"
|
#include "dungeon_coordinates.h"
|
||||||
#include "canvas/canvas_menu.h"
|
#include "app/gui/canvas/canvas_menu.h"
|
||||||
#include "core/icons.h"
|
#include "app/gui/core/icons.h"
|
||||||
#include "absl/status/status.h"
|
#include "absl/status/status.h"
|
||||||
#include "editor/dungeon/object_selection.h"
|
#include "editor/dungeon/object_selection.h"
|
||||||
#include "imgui/imgui.h"
|
#include "imgui/imgui.h"
|
||||||
|
|||||||
@@ -17,6 +17,10 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// Third-party library headers
|
// Third-party library headers
|
||||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
#include "absl/status/status.h"
|
#include "absl/status/status.h"
|
||||||
@@ -270,7 +274,8 @@ EditorManager::EditorManager()
|
|||||||
project_management_panel_->SetToastManager(&toast_manager_);
|
project_management_panel_->SetToastManager(&toast_manager_);
|
||||||
project_management_panel_->SetSwapRomCallback([this]() {
|
project_management_panel_->SetSwapRomCallback([this]() {
|
||||||
// Prompt user to select a new ROM for the project
|
// Prompt user to select a new ROM for the project
|
||||||
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog();
|
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog(
|
||||||
|
util::MakeRomFileDialogOptions(false));
|
||||||
if (!rom_path.empty()) {
|
if (!rom_path.empty()) {
|
||||||
current_project_.rom_filename = rom_path;
|
current_project_.rom_filename = rom_path;
|
||||||
auto status = current_project_.Save();
|
auto status = current_project_.Save();
|
||||||
@@ -1480,7 +1485,7 @@ void EditorManager::DrawMenuBar() {
|
|||||||
* 8. Update UI state and recent files
|
* 8. Update UI state and recent files
|
||||||
*/
|
*/
|
||||||
absl::Status EditorManager::LoadRom() {
|
absl::Status EditorManager::LoadRom() {
|
||||||
auto file_name = util::FileDialogWrapper::ShowOpenFileDialog();
|
auto load_from_path = [this](const std::string& file_name) -> absl::Status {
|
||||||
if (file_name.empty()) {
|
if (file_name.empty()) {
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
@@ -1535,6 +1540,25 @@ absl::Status EditorManager::LoadRom() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && TARGET_OS_IOS == 1
|
||||||
|
util::FileDialogWrapper::ShowOpenFileDialogAsync(
|
||||||
|
util::MakeRomFileDialogOptions(false),
|
||||||
|
[this, load_from_path](const std::string& file_name) {
|
||||||
|
auto status = load_from_path(file_name);
|
||||||
|
if (!status.ok()) {
|
||||||
|
toast_manager_.Show(
|
||||||
|
absl::StrFormat("Failed to load ROM: %s", status.message()),
|
||||||
|
ToastType::kError);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return absl::OkStatus();
|
||||||
|
#else
|
||||||
|
auto file_name = util::FileDialogWrapper::ShowOpenFileDialog(
|
||||||
|
util::MakeRomFileDialogOptions(false));
|
||||||
|
return load_from_path(file_name);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Status EditorManager::LoadAssets(uint64_t passed_handle) {
|
absl::Status EditorManager::LoadAssets(uint64_t passed_handle) {
|
||||||
@@ -1900,16 +1924,19 @@ absl::Status EditorManager::CreateNewProject(const std::string& template_name) {
|
|||||||
// Trigger ROM selection dialog - projects need a ROM to be useful
|
// Trigger ROM selection dialog - projects need a ROM to be useful
|
||||||
// LoadRom() opens file dialog and shows ROM load options when ROM is loaded
|
// LoadRom() opens file dialog and shows ROM load options when ROM is loaded
|
||||||
status = LoadRom();
|
status = LoadRom();
|
||||||
|
#if !(defined(__APPLE__) && TARGET_OS_IOS == 1)
|
||||||
if (status.ok() && ui_coordinator_) {
|
if (status.ok() && ui_coordinator_) {
|
||||||
ui_coordinator_->SetWelcomeScreenVisible(false);
|
ui_coordinator_->SetWelcomeScreenVisible(false);
|
||||||
ui_coordinator_->SetWelcomeScreenManuallyClosed(true);
|
ui_coordinator_->SetWelcomeScreenManuallyClosed(true);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Status EditorManager::OpenProject() {
|
absl::Status EditorManager::OpenProject() {
|
||||||
auto file_path = util::FileDialogWrapper::ShowOpenFileDialog();
|
auto open_project_from_path =
|
||||||
|
[this](const std::string& file_path) -> absl::Status {
|
||||||
if (file_path.empty()) {
|
if (file_path.empty()) {
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
@@ -1931,10 +1958,29 @@ absl::Status EditorManager::OpenProject() {
|
|||||||
current_project_ = std::move(new_project);
|
current_project_ = std::move(new_project);
|
||||||
|
|
||||||
// Initialize VersionManager for the project
|
// Initialize VersionManager for the project
|
||||||
version_manager_ = std::make_unique<core::VersionManager>(¤t_project_);
|
version_manager_ =
|
||||||
|
std::make_unique<core::VersionManager>(¤t_project_);
|
||||||
version_manager_->InitializeGit();
|
version_manager_->InitializeGit();
|
||||||
|
|
||||||
return LoadProjectWithRom();
|
return LoadProjectWithRom();
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && TARGET_OS_IOS == 1
|
||||||
|
util::FileDialogWrapper::ShowOpenFileDialogAsync(
|
||||||
|
util::FileDialogOptions{},
|
||||||
|
[this, open_project_from_path](const std::string& file_path) {
|
||||||
|
auto status = open_project_from_path(file_path);
|
||||||
|
if (!status.ok()) {
|
||||||
|
toast_manager_.Show(
|
||||||
|
absl::StrFormat("Failed to open project: %s", status.message()),
|
||||||
|
ToastType::kError);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return absl::OkStatus();
|
||||||
|
#else
|
||||||
|
auto file_path = util::FileDialogWrapper::ShowOpenFileDialog();
|
||||||
|
return open_project_from_path(file_path);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Status EditorManager::LoadProjectWithRom() {
|
absl::Status EditorManager::LoadProjectWithRom() {
|
||||||
@@ -1944,13 +1990,41 @@ absl::Status EditorManager::LoadProjectWithRom() {
|
|||||||
toast_manager_.Show(
|
toast_manager_.Show(
|
||||||
"Project has no ROM file configured. Please select a ROM.",
|
"Project has no ROM file configured. Please select a ROM.",
|
||||||
editor::ToastType::kInfo);
|
editor::ToastType::kInfo);
|
||||||
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog();
|
#if defined(__APPLE__) && TARGET_OS_IOS == 1
|
||||||
|
util::FileDialogWrapper::ShowOpenFileDialogAsync(
|
||||||
|
util::MakeRomFileDialogOptions(false),
|
||||||
|
[this](const std::string& rom_path) {
|
||||||
|
if (rom_path.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current_project_.rom_filename = rom_path;
|
||||||
|
auto save_status = current_project_.Save();
|
||||||
|
if (!save_status.ok()) {
|
||||||
|
toast_manager_.Show(
|
||||||
|
absl::StrFormat("Failed to update project ROM: %s",
|
||||||
|
save_status.message()),
|
||||||
|
ToastType::kError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto status = LoadProjectWithRom();
|
||||||
|
if (!status.ok()) {
|
||||||
|
toast_manager_.Show(
|
||||||
|
absl::StrFormat("Failed to load project ROM: %s",
|
||||||
|
status.message()),
|
||||||
|
ToastType::kError);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return absl::OkStatus();
|
||||||
|
#else
|
||||||
|
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog(
|
||||||
|
util::MakeRomFileDialogOptions(false));
|
||||||
if (rom_path.empty()) {
|
if (rom_path.empty()) {
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
current_project_.rom_filename = rom_path;
|
current_project_.rom_filename = rom_path;
|
||||||
// Save updated project
|
// Save updated project
|
||||||
RETURN_IF_ERROR(current_project_.Save());
|
RETURN_IF_ERROR(current_project_.Save());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load ROM from project
|
// Load ROM from project
|
||||||
@@ -1963,14 +2037,41 @@ absl::Status EditorManager::LoadProjectWithRom() {
|
|||||||
absl::StrFormat("Could not load ROM '%s': %s. Please select a new ROM.",
|
absl::StrFormat("Could not load ROM '%s': %s. Please select a new ROM.",
|
||||||
current_project_.rom_filename, load_status.message()),
|
current_project_.rom_filename, load_status.message()),
|
||||||
editor::ToastType::kWarning, 5.0f);
|
editor::ToastType::kWarning, 5.0f);
|
||||||
|
#if defined(__APPLE__) && TARGET_OS_IOS == 1
|
||||||
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog();
|
util::FileDialogWrapper::ShowOpenFileDialogAsync(
|
||||||
|
util::MakeRomFileDialogOptions(false),
|
||||||
|
[this](const std::string& rom_path) {
|
||||||
|
if (rom_path.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current_project_.rom_filename = rom_path;
|
||||||
|
auto save_status = current_project_.Save();
|
||||||
|
if (!save_status.ok()) {
|
||||||
|
toast_manager_.Show(
|
||||||
|
absl::StrFormat("Failed to update project ROM: %s",
|
||||||
|
save_status.message()),
|
||||||
|
ToastType::kError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto status = LoadProjectWithRom();
|
||||||
|
if (!status.ok()) {
|
||||||
|
toast_manager_.Show(
|
||||||
|
absl::StrFormat("Failed to load project ROM: %s",
|
||||||
|
status.message()),
|
||||||
|
ToastType::kError);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return absl::OkStatus();
|
||||||
|
#else
|
||||||
|
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog(
|
||||||
|
util::MakeRomFileDialogOptions(false));
|
||||||
if (rom_path.empty()) {
|
if (rom_path.empty()) {
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
current_project_.rom_filename = rom_path;
|
current_project_.rom_filename = rom_path;
|
||||||
RETURN_IF_ERROR(current_project_.Save());
|
RETURN_IF_ERROR(current_project_.Save());
|
||||||
RETURN_IF_ERROR(rom_file_manager_.LoadRom(&temp_rom, rom_path));
|
RETURN_IF_ERROR(rom_file_manager_.LoadRom(&temp_rom, rom_path));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
auto session_or = session_coordinator_->CreateSessionFromRom(
|
auto session_or = session_coordinator_->CreateSessionFromRom(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "app/gui/app/agent_chat_widget.h"
|
#include "app/gui/app/agent_chat_widget.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@@ -8,6 +9,7 @@
|
|||||||
#include "absl/time/time.h"
|
#include "absl/time/time.h"
|
||||||
#include "imgui/imgui.h"
|
#include "imgui/imgui.h"
|
||||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||||
|
#include "util/platform_paths.h"
|
||||||
|
|
||||||
#ifdef YAZE_WITH_JSON
|
#ifdef YAZE_WITH_JSON
|
||||||
#include "nlohmann/json.hpp"
|
#include "nlohmann/json.hpp"
|
||||||
@@ -17,6 +19,27 @@ namespace yaze {
|
|||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::string ResolveAgentChatHistoryPath() {
|
||||||
|
auto agent_dir = util::PlatformPaths::GetAppDataSubdirectory("agent");
|
||||||
|
if (agent_dir.ok()) {
|
||||||
|
return (*agent_dir / "agent_chat_history.json").string();
|
||||||
|
}
|
||||||
|
auto docs_dir = util::PlatformPaths::GetUserDocumentsSubdirectory("agent");
|
||||||
|
if (docs_dir.ok()) {
|
||||||
|
return (*docs_dir / "agent_chat_history.json").string();
|
||||||
|
}
|
||||||
|
auto temp_dir = util::PlatformPaths::GetTempDirectory();
|
||||||
|
if (temp_dir.ok()) {
|
||||||
|
return (*temp_dir / "agent_chat_history.json").string();
|
||||||
|
}
|
||||||
|
return (std::filesystem::current_path() / "agent_chat_history.json")
|
||||||
|
.string();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
AgentChatWidget::AgentChatWidget()
|
AgentChatWidget::AgentChatWidget()
|
||||||
: scroll_to_bottom_(false),
|
: scroll_to_bottom_(false),
|
||||||
auto_scroll_(true),
|
auto_scroll_(true),
|
||||||
@@ -99,7 +122,7 @@ void AgentChatWidget::RenderToolbar() {
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
if (ImGui::Button("Save History")) {
|
if (ImGui::Button("Save History")) {
|
||||||
std::string filepath = ".yaze/agent_chat_history.json";
|
std::string filepath = ResolveAgentChatHistoryPath();
|
||||||
if (auto status = SaveHistory(filepath); !status.ok()) {
|
if (auto status = SaveHistory(filepath); !status.ok()) {
|
||||||
std::cerr << "Failed to save history: " << status.message() << std::endl;
|
std::cerr << "Failed to save history: " << status.message() << std::endl;
|
||||||
} else {
|
} else {
|
||||||
@@ -109,7 +132,7 @@ void AgentChatWidget::RenderToolbar() {
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
if (ImGui::Button("Load History")) {
|
if (ImGui::Button("Load History")) {
|
||||||
std::string filepath = ".yaze/agent_chat_history.json";
|
std::string filepath = ResolveAgentChatHistoryPath();
|
||||||
if (auto status = LoadHistory(filepath); !status.ok()) {
|
if (auto status = LoadHistory(filepath); !status.ok()) {
|
||||||
std::cerr << "Failed to load history: " << status.message() << std::endl;
|
std::cerr << "Failed to load history: " << status.message() << std::endl;
|
||||||
}
|
}
|
||||||
@@ -297,6 +320,17 @@ absl::Status AgentChatWidget::SaveHistory(const std::string& filepath) {
|
|||||||
return absl::FailedPreconditionError("Agent service not initialized");
|
return absl::FailedPreconditionError("Agent service not initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path path(filepath);
|
||||||
|
if (path.has_parent_path()) {
|
||||||
|
std::error_code ec;
|
||||||
|
std::filesystem::create_directories(path.parent_path(), ec);
|
||||||
|
if (ec) {
|
||||||
|
return absl::InternalError(
|
||||||
|
absl::StrFormat("Failed to create history directory: %s",
|
||||||
|
ec.message()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::ofstream file(filepath);
|
std::ofstream file(filepath);
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
return absl::InternalError(
|
return absl::InternalError(
|
||||||
|
|||||||
Reference in New Issue
Block a user