2026-03-26 21:18:33 +08:00
|
|
|
#include "Actions/EditorActions.h"
|
|
|
|
|
#include "Commands/EntityCommands.h"
|
|
|
|
|
#include "Commands/SceneCommands.h"
|
2026-03-20 17:08:06 +08:00
|
|
|
#include "MenuBar.h"
|
2026-03-26 21:18:33 +08:00
|
|
|
#include "Core/EditorEvents.h"
|
|
|
|
|
#include "Core/EventBus.h"
|
2026-03-26 01:26:26 +08:00
|
|
|
#include "Core/IEditorContext.h"
|
|
|
|
|
#include "Core/ISceneManager.h"
|
2026-03-26 01:59:14 +08:00
|
|
|
#include "Core/IUndoManager.h"
|
|
|
|
|
#include "Core/ISelectionManager.h"
|
2026-03-26 21:18:33 +08:00
|
|
|
#include "UI/UI.h"
|
2026-03-26 01:26:26 +08:00
|
|
|
#include <filesystem>
|
2026-03-20 17:08:06 +08:00
|
|
|
#include <imgui.h>
|
|
|
|
|
|
2026-03-24 20:02:38 +08:00
|
|
|
namespace XCEngine {
|
|
|
|
|
namespace Editor {
|
2026-03-20 17:08:06 +08:00
|
|
|
|
|
|
|
|
MenuBar::MenuBar() : Panel("MenuBar") {}
|
|
|
|
|
|
|
|
|
|
void MenuBar::Render() {
|
2026-03-26 01:26:26 +08:00
|
|
|
HandleShortcuts();
|
|
|
|
|
|
2026-03-20 17:08:06 +08:00
|
|
|
if (ImGui::BeginMainMenuBar()) {
|
|
|
|
|
ShowFileMenu();
|
|
|
|
|
ShowEditMenu();
|
|
|
|
|
ShowViewMenu();
|
|
|
|
|
ShowHelpMenu();
|
2026-03-26 01:26:26 +08:00
|
|
|
RenderSceneStatus();
|
2026-03-20 17:08:06 +08:00
|
|
|
ImGui::EndMainMenuBar();
|
|
|
|
|
}
|
2026-03-26 01:26:26 +08:00
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
RenderAboutPopup();
|
2026-03-26 01:26:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
void MenuBar::HandleShortcuts() {
|
|
|
|
|
if (!m_context) {
|
2026-03-26 01:26:26 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
Actions::HandleShortcut(Actions::MakeNewSceneAction(), [&]() { Commands::NewScene(*m_context); });
|
|
|
|
|
Actions::HandleShortcut(Actions::MakeOpenSceneAction(), [&]() { Commands::OpenSceneWithDialog(*m_context); });
|
|
|
|
|
Actions::HandleShortcut(Actions::MakeSaveSceneAction(), [&]() { Commands::SaveCurrentScene(*m_context); });
|
|
|
|
|
Actions::HandleShortcut(Actions::MakeSaveSceneAsAction(), [&]() { Commands::SaveSceneAsWithDialog(*m_context); });
|
|
|
|
|
Actions::HandleShortcut(Actions::MakeUndoAction(*m_context), [&]() { m_context->GetUndoManager().Undo(); });
|
|
|
|
|
Actions::HandleShortcut(Actions::MakeRedoAction(*m_context), [&]() { m_context->GetUndoManager().Redo(); });
|
2026-03-26 01:26:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
void MenuBar::ShowFileMenu() {
|
|
|
|
|
UI::DrawMenuScope("File", [&]() {
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakeNewSceneAction(), [&]() { Commands::NewScene(*m_context); });
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakeOpenSceneAction(), [&]() { Commands::OpenSceneWithDialog(*m_context); });
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakeSaveSceneAction(), [&]() { Commands::SaveCurrentScene(*m_context); });
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakeSaveSceneAsAction(), [&]() { Commands::SaveSceneAsWithDialog(*m_context); });
|
|
|
|
|
Actions::DrawMenuSeparator();
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakeExitAction(), [&]() {
|
|
|
|
|
m_context->GetEventBus().Publish(EditorExitRequestedEvent{});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
2026-03-26 01:26:26 +08:00
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
void MenuBar::ShowEditMenu() {
|
|
|
|
|
::XCEngine::Components::GameObject* selectedGameObject = Actions::GetSelectedGameObject(*m_context);
|
|
|
|
|
|
|
|
|
|
UI::DrawMenuScope("Edit", [&]() {
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakeUndoAction(*m_context), [&]() { m_context->GetUndoManager().Undo(); });
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakeRedoAction(*m_context), [&]() { m_context->GetUndoManager().Redo(); });
|
|
|
|
|
Actions::DrawMenuSeparator();
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakeCutAction(false), []() {});
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakeCopyEntityAction(selectedGameObject), [&]() {
|
|
|
|
|
Commands::CopyEntity(*m_context, selectedGameObject->GetID());
|
|
|
|
|
});
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakePasteEntityAction(*m_context), [&]() {
|
|
|
|
|
Commands::PasteEntity(*m_context, selectedGameObject ? selectedGameObject->GetID() : 0);
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-03-26 01:26:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
void MenuBar::ShowViewMenu() {
|
|
|
|
|
UI::DrawMenuScope("View", [&]() {
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakeResetLayoutAction(), [&]() {
|
|
|
|
|
m_context->GetEventBus().Publish(DockLayoutResetRequestedEvent{});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
2026-03-26 01:26:26 +08:00
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
void MenuBar::ShowHelpMenu() {
|
|
|
|
|
UI::DrawMenuScope("Help", [&]() {
|
|
|
|
|
Actions::DrawMenuAction(Actions::MakeAboutAction(), [&]() {
|
|
|
|
|
m_aboutPopup.RequestOpen();
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-03-26 01:26:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
void MenuBar::RenderAboutPopup() {
|
|
|
|
|
m_aboutPopup.ConsumeOpenRequest("About XCEngine Editor");
|
2026-03-26 01:26:26 +08:00
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
if (!UI::BeginModalPopup("About XCEngine Editor")) {
|
2026-03-26 01:26:26 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
ImGui::TextUnformatted("XCEngine Editor");
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
UI::DrawHintText("Unity-like editor shell built on Dear ImGui.");
|
|
|
|
|
ImGui::Spacing();
|
|
|
|
|
ImGui::Text("Date: 2026-03-26");
|
|
|
|
|
ImGui::Text("UI Refactor: Actions / Commands / Layout in progress");
|
|
|
|
|
if (m_context) {
|
|
|
|
|
ImGui::Text("Project: %s", m_context->GetProjectPath().c_str());
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
2026-03-26 21:18:33 +08:00
|
|
|
ImGui::Spacing();
|
2026-03-20 17:08:06 +08:00
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
if (Actions::DrawButtonAction(Actions::MakeAction("Close"), UI::DialogActionButtonSize())) {
|
|
|
|
|
ImGui::CloseCurrentPopup();
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 21:18:33 +08:00
|
|
|
UI::EndPopup();
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 01:26:26 +08:00
|
|
|
void MenuBar::RenderSceneStatus() {
|
|
|
|
|
if (!m_context) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto& sceneManager = m_context->GetSceneManager();
|
|
|
|
|
std::string sceneLabel = sceneManager.HasActiveScene() ? sceneManager.GetCurrentSceneName() : "No Scene";
|
|
|
|
|
if (sceneLabel.empty()) {
|
|
|
|
|
sceneLabel = "Untitled Scene";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string fileLabel = sceneManager.GetCurrentScenePath().empty()
|
|
|
|
|
? "Unsaved.xc"
|
|
|
|
|
: std::filesystem::path(sceneManager.GetCurrentScenePath()).filename().string();
|
|
|
|
|
|
|
|
|
|
const bool dirty = sceneManager.IsSceneDirty();
|
2026-03-26 21:18:33 +08:00
|
|
|
const std::string statusText = dirty ? (std::string("* ") + fileLabel) : fileLabel;
|
|
|
|
|
UI::DrawRightAlignedText(
|
|
|
|
|
statusText.c_str(),
|
|
|
|
|
dirty ? UI::MenuBarStatusDirtyColor() : UI::MenuBarStatusIdleColor());
|
2026-03-26 01:26:26 +08:00
|
|
|
|
|
|
|
|
if (ImGui::IsItemHovered()) {
|
2026-03-26 21:18:33 +08:00
|
|
|
UI::BeginTitledTooltip("Scene");
|
2026-03-26 01:26:26 +08:00
|
|
|
ImGui::Text("Name: %s", sceneLabel.c_str());
|
|
|
|
|
ImGui::Text("File: %s", fileLabel.c_str());
|
|
|
|
|
ImGui::Text("State: %s", dirty ? "Modified" : "Saved");
|
|
|
|
|
ImGui::Text("Path: %s", sceneManager.GetCurrentScenePath().empty() ? "(not saved yet)" : sceneManager.GetCurrentScenePath().c_str());
|
2026-03-26 21:18:33 +08:00
|
|
|
UI::EndTitledTooltip();
|
2026-03-26 01:26:26 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2026-03-24 20:02:38 +08:00
|
|
|
}
|