Refine editor action shell and add regression tests
This commit is contained in:
@@ -24,6 +24,26 @@ inline void DrawConsoleToolbarActions(Debug::EditorConsoleSink& sink, UI::Consol
|
||||
DrawToolbarToggleAction(MakeConsoleErrorFilterAction(filterState.ShowError()), filterState.ShowError());
|
||||
}
|
||||
|
||||
inline void DrawConsoleLogRows(const Debug::EditorConsoleSink& sink, const UI::ConsoleFilterState& filterState) {
|
||||
const auto logs = sink.GetLogs();
|
||||
size_t logIndex = 0;
|
||||
for (const auto& log : logs) {
|
||||
if (!filterState.Allows(log.level)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ImGui::PushID(static_cast<int>(logIndex));
|
||||
|
||||
const std::string fullMessage = UI::BuildConsoleLogText(log);
|
||||
if (UI::DrawConsoleLogRow(fullMessage.c_str())) {
|
||||
ImGui::SetClipboardText(fullMessage.c_str());
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
++logIndex;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Actions
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
|
||||
@@ -31,96 +31,173 @@ inline ActionBinding MakeDisabledPasteAction() {
|
||||
return MakeAction("Paste", "Ctrl+V", false, false);
|
||||
}
|
||||
|
||||
inline void HandleProjectEditShortcuts(
|
||||
IEditorContext& context,
|
||||
const EditActionTarget& target,
|
||||
const ShortcutContext& shortcutContext) {
|
||||
auto& projectManager = context.GetProjectManager();
|
||||
|
||||
HandleShortcut(MakeNavigateBackAction(projectManager.CanNavigateBack()), shortcutContext, [&]() {
|
||||
projectManager.NavigateBack();
|
||||
});
|
||||
HandleShortcut(MakeOpenAssetAction(Commands::CanOpenAsset(target.selectedAssetItem)), shortcutContext, [&]() {
|
||||
Commands::OpenAsset(context, target.selectedAssetItem);
|
||||
});
|
||||
HandleShortcut(MakeDeleteAssetAction(target.selectedAssetItem != nullptr), shortcutContext, [&]() {
|
||||
Commands::DeleteAsset(projectManager, projectManager.GetSelectedIndex());
|
||||
});
|
||||
inline ActionBinding MakeOpenSelectionAction(const EditActionTarget& target) {
|
||||
return MakeOpenAssetAction(target.route == EditorActionRoute::Project && Commands::CanOpenAsset(target.selectedAssetItem));
|
||||
}
|
||||
|
||||
inline void HandleHierarchyEditShortcuts(
|
||||
IEditorContext& context,
|
||||
const EditActionTarget& target,
|
||||
const ShortcutContext& shortcutContext) {
|
||||
HandleShortcut(MakeDeleteEntityAction(target.selectedGameObject), shortcutContext, [&]() {
|
||||
Commands::DeleteEntity(context, target.selectedGameObject->GetID());
|
||||
});
|
||||
HandleShortcut(MakeRenameEntityAction(target.selectedGameObject), shortcutContext, [&]() {
|
||||
context.GetEventBus().Publish(EntityRenameRequestedEvent{ target.selectedGameObject->GetID() });
|
||||
});
|
||||
HandleShortcut(MakeCopyEntityAction(target.selectedGameObject), shortcutContext, [&]() {
|
||||
Commands::CopyEntity(context, target.selectedGameObject->GetID());
|
||||
});
|
||||
HandleShortcut(MakePasteEntityAction(context), shortcutContext, [&]() {
|
||||
Commands::PasteEntity(context, target.selectedGameObject ? target.selectedGameObject->GetID() : 0);
|
||||
});
|
||||
HandleShortcut(MakeDuplicateEntityAction(target.selectedGameObject), shortcutContext, [&]() {
|
||||
Commands::DuplicateEntity(context, target.selectedGameObject->GetID());
|
||||
});
|
||||
inline ActionBinding MakeDeleteSelectionAction(const EditActionTarget& target) {
|
||||
if (target.route == EditorActionRoute::Project) {
|
||||
return MakeDeleteAssetAction(target.selectedAssetItem != nullptr);
|
||||
}
|
||||
|
||||
return MakeDeleteEntityAction(target.route == EditorActionRoute::Hierarchy ? target.selectedGameObject : nullptr);
|
||||
}
|
||||
|
||||
inline ActionBinding MakeRenameSelectionAction(const EditActionTarget& target) {
|
||||
return MakeRenameEntityAction(target.route == EditorActionRoute::Hierarchy ? target.selectedGameObject : nullptr);
|
||||
}
|
||||
|
||||
inline ActionBinding MakeCopySelectionAction(const EditActionTarget& target) {
|
||||
return MakeCopyEntityAction(target.route == EditorActionRoute::Hierarchy ? target.selectedGameObject : nullptr);
|
||||
}
|
||||
|
||||
inline ActionBinding MakePasteSelectionAction(IEditorContext& context, const EditActionTarget& target) {
|
||||
return target.route == EditorActionRoute::Hierarchy ? MakePasteEntityAction(context) : MakeDisabledPasteAction();
|
||||
}
|
||||
|
||||
inline ActionBinding MakeDuplicateSelectionAction(const EditActionTarget& target) {
|
||||
return MakeDuplicateEntityAction(target.route == EditorActionRoute::Hierarchy ? target.selectedGameObject : nullptr);
|
||||
}
|
||||
|
||||
inline ActionBinding MakeNavigateBackSelectionAction(IEditorContext& context, const EditActionTarget& target) {
|
||||
const bool enabled =
|
||||
target.route == EditorActionRoute::Project && context.GetProjectManager().CanNavigateBack();
|
||||
return MakeNavigateBackAction(enabled);
|
||||
}
|
||||
|
||||
inline bool ExecuteOpenSelection(IEditorContext& context, const EditActionTarget& target) {
|
||||
if (target.route != EditorActionRoute::Project || !Commands::CanOpenAsset(target.selectedAssetItem)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Commands::OpenAsset(context, target.selectedAssetItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ExecuteDeleteSelection(IEditorContext& context, const EditActionTarget& target) {
|
||||
if (target.route == EditorActionRoute::Project) {
|
||||
auto& projectManager = context.GetProjectManager();
|
||||
if (!target.selectedAssetItem || projectManager.GetSelectedIndex() < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Commands::DeleteAsset(projectManager, projectManager.GetSelectedIndex());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target.route != EditorActionRoute::Hierarchy || !target.selectedGameObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Commands::DeleteEntity(context, target.selectedGameObject->GetID());
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ExecuteNavigateBackSelection(IEditorContext& context, const EditActionTarget& target) {
|
||||
if (target.route != EditorActionRoute::Project) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& projectManager = context.GetProjectManager();
|
||||
if (!projectManager.CanNavigateBack()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
projectManager.NavigateBack();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ExecuteRenameSelection(IEditorContext& context, const EditActionTarget& target) {
|
||||
if (target.route != EditorActionRoute::Hierarchy || !target.selectedGameObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
context.GetEventBus().Publish(EntityRenameRequestedEvent{ target.selectedGameObject->GetID() });
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ExecuteCopySelection(IEditorContext& context, const EditActionTarget& target) {
|
||||
if (target.route != EditorActionRoute::Hierarchy || !target.selectedGameObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Commands::CopyEntity(context, target.selectedGameObject->GetID());
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ExecutePasteSelection(IEditorContext& context, const EditActionTarget& target) {
|
||||
if (target.route != EditorActionRoute::Hierarchy || !context.GetSceneManager().HasClipboardData()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Commands::PasteEntity(context, target.selectedGameObject ? target.selectedGameObject->GetID() : 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ExecuteDuplicateSelection(IEditorContext& context, const EditActionTarget& target) {
|
||||
if (target.route != EditorActionRoute::Hierarchy || !target.selectedGameObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Commands::DuplicateEntity(context, target.selectedGameObject->GetID());
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void HandleEditShortcuts(IEditorContext& context, const ShortcutContext& shortcutContext) {
|
||||
const EditActionTarget target = ResolveEditActionTarget(context);
|
||||
|
||||
switch (target.route) {
|
||||
case EditorActionRoute::Project:
|
||||
HandleProjectEditShortcuts(context, target, shortcutContext);
|
||||
return;
|
||||
case EditorActionRoute::Hierarchy:
|
||||
HandleHierarchyEditShortcuts(context, target, shortcutContext);
|
||||
return;
|
||||
case EditorActionRoute::None:
|
||||
return;
|
||||
}
|
||||
HandleShortcut(MakeNavigateBackSelectionAction(context, target), shortcutContext, [&]() {
|
||||
ExecuteNavigateBackSelection(context, target);
|
||||
});
|
||||
HandleShortcut(MakeOpenSelectionAction(target), shortcutContext, [&]() {
|
||||
ExecuteOpenSelection(context, target);
|
||||
});
|
||||
HandleShortcut(MakeDeleteSelectionAction(target), shortcutContext, [&]() {
|
||||
ExecuteDeleteSelection(context, target);
|
||||
});
|
||||
HandleShortcut(MakeRenameSelectionAction(target), shortcutContext, [&]() {
|
||||
ExecuteRenameSelection(context, target);
|
||||
});
|
||||
HandleShortcut(MakeCopySelectionAction(target), shortcutContext, [&]() {
|
||||
ExecuteCopySelection(context, target);
|
||||
});
|
||||
HandleShortcut(MakePasteSelectionAction(context, target), shortcutContext, [&]() {
|
||||
ExecutePasteSelection(context, target);
|
||||
});
|
||||
HandleShortcut(MakeDuplicateSelectionAction(target), shortcutContext, [&]() {
|
||||
ExecuteDuplicateSelection(context, target);
|
||||
});
|
||||
}
|
||||
|
||||
inline void DrawProjectEditActions(IEditorContext& context, const EditActionTarget& target) {
|
||||
auto& projectManager = context.GetProjectManager();
|
||||
|
||||
DrawMenuAction(MakeOpenAssetAction(Commands::CanOpenAsset(target.selectedAssetItem)), [&]() {
|
||||
Commands::OpenAsset(context, target.selectedAssetItem);
|
||||
DrawMenuAction(MakeOpenSelectionAction(target), [&]() {
|
||||
ExecuteOpenSelection(context, target);
|
||||
});
|
||||
DrawMenuAction(MakeDeleteAssetAction(target.selectedAssetItem != nullptr), [&]() {
|
||||
Commands::DeleteAsset(projectManager, projectManager.GetSelectedIndex());
|
||||
DrawMenuAction(MakeDeleteSelectionAction(target), [&]() {
|
||||
ExecuteDeleteSelection(context, target);
|
||||
});
|
||||
DrawMenuSeparator();
|
||||
DrawMenuAction(MakeNavigateBackAction(projectManager.CanNavigateBack()), [&]() {
|
||||
projectManager.NavigateBack();
|
||||
DrawMenuAction(MakeNavigateBackSelectionAction(context, target), [&]() {
|
||||
ExecuteNavigateBackSelection(context, target);
|
||||
});
|
||||
}
|
||||
|
||||
inline void DrawHierarchyEditActions(IEditorContext& context, const EditActionTarget& target) {
|
||||
const bool hierarchyRouteActive = target.route == EditorActionRoute::Hierarchy;
|
||||
const ::XCEngine::Components::GameObject* activeObject =
|
||||
hierarchyRouteActive ? target.selectedGameObject : nullptr;
|
||||
|
||||
DrawMenuAction(MakeCutAction(false), []() {});
|
||||
DrawMenuAction(MakeCopyEntityAction(const_cast<::XCEngine::Components::GameObject*>(activeObject)), [&]() {
|
||||
Commands::CopyEntity(context, target.selectedGameObject->GetID());
|
||||
DrawMenuAction(MakeCopySelectionAction(target), [&]() {
|
||||
ExecuteCopySelection(context, target);
|
||||
});
|
||||
DrawMenuAction(
|
||||
hierarchyRouteActive ? MakePasteEntityAction(context) : MakeDisabledPasteAction(),
|
||||
[&]() {
|
||||
Commands::PasteEntity(context, target.selectedGameObject ? target.selectedGameObject->GetID() : 0);
|
||||
});
|
||||
DrawMenuAction(MakeDuplicateEntityAction(const_cast<::XCEngine::Components::GameObject*>(activeObject)), [&]() {
|
||||
Commands::DuplicateEntity(context, target.selectedGameObject->GetID());
|
||||
DrawMenuAction(MakePasteSelectionAction(context, target), [&]() {
|
||||
ExecutePasteSelection(context, target);
|
||||
});
|
||||
DrawMenuAction(MakeDeleteEntityAction(const_cast<::XCEngine::Components::GameObject*>(activeObject)), [&]() {
|
||||
Commands::DeleteEntity(context, target.selectedGameObject->GetID());
|
||||
DrawMenuAction(MakeDuplicateSelectionAction(target), [&]() {
|
||||
ExecuteDuplicateSelection(context, target);
|
||||
});
|
||||
DrawMenuAction(MakeRenameEntityAction(const_cast<::XCEngine::Components::GameObject*>(activeObject)), [&]() {
|
||||
context.GetEventBus().Publish(EntityRenameRequestedEvent{ target.selectedGameObject->GetID() });
|
||||
DrawMenuAction(MakeDeleteSelectionAction(target), [&]() {
|
||||
ExecuteDeleteSelection(context, target);
|
||||
});
|
||||
DrawMenuAction(MakeRenameSelectionAction(target), [&]() {
|
||||
ExecuteRenameSelection(context, target);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Core/EditorEvents.h"
|
||||
#include "Core/EventBus.h"
|
||||
#include "Core/IEditorContext.h"
|
||||
#include "UI/PopupState.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
@@ -22,6 +23,15 @@ inline void RequestEntityRename(IEditorContext& context, const ::XCEngine::Compo
|
||||
context.GetEventBus().Publish(EntityRenameRequestedEvent{ gameObject->GetID() });
|
||||
}
|
||||
|
||||
inline bool CommitEntityRename(IEditorContext& context, uint64_t entityId, const char* newName) {
|
||||
if (entityId == 0 || !newName || newName[0] == '\0' || !context.GetSceneManager().GetEntity(entityId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Commands::RenameEntity(context, entityId, newName);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void HandleHierarchySelectionClick(IEditorContext& context, uint64_t entityId, bool additive) {
|
||||
auto& selectionManager = context.GetSelectionManager();
|
||||
if (additive) {
|
||||
@@ -34,6 +44,59 @@ inline void HandleHierarchySelectionClick(IEditorContext& context, uint64_t enti
|
||||
selectionManager.SetSelectedEntity(entityId);
|
||||
}
|
||||
|
||||
template <size_t BufferCapacity>
|
||||
inline void HandleHierarchyBackgroundPrimaryClick(
|
||||
IEditorContext& context,
|
||||
const UI::InlineTextEditState<uint64_t, BufferCapacity>& renameState) {
|
||||
if (!ImGui::IsWindowHovered() || !ImGui::IsMouseDown(0) || ImGui::IsAnyItemHovered() || renameState.IsActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.GetSelectionManager().ClearSelection();
|
||||
}
|
||||
|
||||
inline void RequestHierarchyOptionsPopup(UI::DeferredPopupState& optionsPopup) {
|
||||
optionsPopup.RequestOpen();
|
||||
}
|
||||
|
||||
template <typename SortMode, typename SetSortModeFn>
|
||||
inline void DrawHierarchySortOptionsPopup(
|
||||
UI::DeferredPopupState& optionsPopup,
|
||||
SortMode currentMode,
|
||||
SortMode nameMode,
|
||||
SortMode componentCountMode,
|
||||
SortMode transformFirstMode,
|
||||
SetSortModeFn&& setSortMode) {
|
||||
optionsPopup.ConsumeOpenRequest("HierarchyOptions");
|
||||
|
||||
if (!UI::BeginPopup("HierarchyOptions")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const UI::MenuCommand commands[] = {
|
||||
UI::MenuCommand::Action("Sort By Name", nullptr, currentMode == nameMode),
|
||||
UI::MenuCommand::Action("Sort By Component Count", nullptr, currentMode == componentCountMode),
|
||||
UI::MenuCommand::Action("Transform First", nullptr, currentMode == transformFirstMode)
|
||||
};
|
||||
|
||||
UI::DrawMenuCommands(commands, [&](size_t index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
setSortMode(nameMode);
|
||||
break;
|
||||
case 1:
|
||||
setSortMode(componentCountMode);
|
||||
break;
|
||||
case 2:
|
||||
setSortMode(transformFirstMode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
UI::EndPopup();
|
||||
}
|
||||
|
||||
inline bool BeginHierarchyEntityDrag(::XCEngine::Components::GameObject* gameObject) {
|
||||
if (!gameObject || !ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||
return false;
|
||||
@@ -79,6 +142,11 @@ inline bool AcceptHierarchyEntityDropToRoot(IEditorContext& context) {
|
||||
return accepted;
|
||||
}
|
||||
|
||||
inline void DrawHierarchyRootDropTarget(IEditorContext& context) {
|
||||
ImGui::InvisibleButton("##DragTarget", ImVec2(-1, -1));
|
||||
AcceptHierarchyEntityDropToRoot(context);
|
||||
}
|
||||
|
||||
inline void DrawHierarchyCreateActions(IEditorContext& context, ::XCEngine::Components::GameObject* parent) {
|
||||
DrawMenuAction(MakeCreateEmptyEntityAction(), [&]() {
|
||||
Commands::CreateEmptyEntity(context, parent, "Create Entity", "GameObject");
|
||||
@@ -102,6 +170,15 @@ inline void DrawHierarchyCreateActions(IEditorContext& context, ::XCEngine::Comp
|
||||
});
|
||||
}
|
||||
|
||||
inline void DrawHierarchyBackgroundContextPopup(IEditorContext& context) {
|
||||
if (!UI::BeginPopupContextWindow("HierarchyContextMenu", ImGuiPopupFlags_MouseButtonRight)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DrawHierarchyCreateActions(context, nullptr);
|
||||
UI::EndPopup();
|
||||
}
|
||||
|
||||
inline void DrawHierarchyContextActions(IEditorContext& context, ::XCEngine::Components::GameObject* gameObject) {
|
||||
if (UI::DrawMenuScope("Create", [&]() {
|
||||
DrawHierarchyCreateActions(context, gameObject);
|
||||
@@ -133,6 +210,15 @@ inline void DrawHierarchyContextActions(IEditorContext& context, ::XCEngine::Com
|
||||
});
|
||||
}
|
||||
|
||||
inline void DrawHierarchyEntityContextPopup(IEditorContext& context, ::XCEngine::Components::GameObject* gameObject) {
|
||||
if (!UI::BeginPopupContextItem("EntityContextMenu")) {
|
||||
return;
|
||||
}
|
||||
|
||||
DrawHierarchyContextActions(context, gameObject);
|
||||
UI::EndPopup();
|
||||
}
|
||||
|
||||
} // namespace Actions
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#include "EditorActions.h"
|
||||
#include "Commands/ComponentCommands.h"
|
||||
#include "ComponentEditors/ComponentEditorRegistry.h"
|
||||
#include "Core/EditorEvents.h"
|
||||
#include "Core/IEditorContext.h"
|
||||
#include "UI/PopupState.h"
|
||||
#include "UI/UI.h"
|
||||
|
||||
#include <string>
|
||||
@@ -28,6 +30,28 @@ inline std::string BuildAddComponentMenuLabel(const IComponentEditor& editor, ::
|
||||
return label;
|
||||
}
|
||||
|
||||
inline void HandleInspectorSelectionChanged(
|
||||
IEditorContext& context,
|
||||
const SelectionChangedEvent& event,
|
||||
uint64_t& selectedEntityId,
|
||||
UI::DeferredPopupState& addComponentPopup) {
|
||||
if (context.GetUndoManager().HasPendingInteractiveChange()) {
|
||||
context.GetUndoManager().FinalizeInteractiveChange();
|
||||
}
|
||||
|
||||
selectedEntityId = event.primarySelection;
|
||||
addComponentPopup.Clear();
|
||||
}
|
||||
|
||||
inline bool DrawInspectorAddComponentButton(UI::DeferredPopupState& addComponentPopup, bool enabled = true) {
|
||||
if (!DrawInspectorAction(MakeAddComponentButtonAction(enabled))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
addComponentPopup.RequestOpen();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool DrawInspectorAddComponentMenu(IEditorContext& context, ::XCEngine::Components::GameObject* gameObject) {
|
||||
bool drewAnyEntry = false;
|
||||
|
||||
@@ -49,6 +73,23 @@ inline bool DrawInspectorAddComponentMenu(IEditorContext& context, ::XCEngine::C
|
||||
return drewAnyEntry;
|
||||
}
|
||||
|
||||
inline void DrawInspectorAddComponentPopup(
|
||||
IEditorContext& context,
|
||||
UI::DeferredPopupState& addComponentPopup,
|
||||
::XCEngine::Components::GameObject* gameObject) {
|
||||
addComponentPopup.ConsumeOpenRequest("AddComponent");
|
||||
|
||||
if (!UI::BeginTitledPopup("AddComponent", "Components")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DrawInspectorAddComponentMenu(context, gameObject)) {
|
||||
UI::DrawHintText("No registered component editors");
|
||||
}
|
||||
|
||||
UI::EndTitledPopup();
|
||||
}
|
||||
|
||||
inline bool DrawInspectorComponentMenu(
|
||||
IEditorContext& context,
|
||||
::XCEngine::Components::Component* component,
|
||||
@@ -60,6 +101,12 @@ inline bool DrawInspectorComponentMenu(
|
||||
});
|
||||
}
|
||||
|
||||
inline void FinalizeInspectorInteractiveChangeIfIdle(IEditorContext& context) {
|
||||
if (context.GetUndoManager().HasPendingInteractiveChange() && !ImGui::IsAnyItemActive()) {
|
||||
context.GetUndoManager().FinalizeInteractiveChange();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Actions
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
|
||||
@@ -7,42 +7,102 @@
|
||||
#include "Core/EventBus.h"
|
||||
#include "Core/IEditorContext.h"
|
||||
#include "UI/PopupState.h"
|
||||
#include "UI/UI.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
namespace Actions {
|
||||
|
||||
inline void ExecuteNewScene(IEditorContext& context) {
|
||||
Commands::NewScene(context);
|
||||
}
|
||||
|
||||
inline void ExecuteOpenScene(IEditorContext& context) {
|
||||
Commands::OpenSceneWithDialog(context);
|
||||
}
|
||||
|
||||
inline void ExecuteSaveScene(IEditorContext& context) {
|
||||
Commands::SaveCurrentScene(context);
|
||||
}
|
||||
|
||||
inline void ExecuteSaveSceneAs(IEditorContext& context) {
|
||||
Commands::SaveSceneAsWithDialog(context);
|
||||
}
|
||||
|
||||
inline void ExecuteUndo(IEditorContext& context) {
|
||||
context.GetUndoManager().Undo();
|
||||
}
|
||||
|
||||
inline void ExecuteRedo(IEditorContext& context) {
|
||||
context.GetUndoManager().Redo();
|
||||
}
|
||||
|
||||
inline void RequestEditorExit(IEditorContext& context) {
|
||||
context.GetEventBus().Publish(EditorExitRequestedEvent{});
|
||||
}
|
||||
|
||||
inline void RequestDockLayoutReset(IEditorContext& context) {
|
||||
context.GetEventBus().Publish(DockLayoutResetRequestedEvent{});
|
||||
}
|
||||
|
||||
inline void RequestAboutPopup(UI::DeferredPopupState& aboutPopup) {
|
||||
aboutPopup.RequestOpen();
|
||||
}
|
||||
|
||||
inline void HandleMainMenuShortcuts(IEditorContext& context, const ShortcutContext& shortcutContext) {
|
||||
HandleShortcut(MakeNewSceneAction(), shortcutContext, [&]() { Commands::NewScene(context); });
|
||||
HandleShortcut(MakeOpenSceneAction(), shortcutContext, [&]() { Commands::OpenSceneWithDialog(context); });
|
||||
HandleShortcut(MakeSaveSceneAction(), shortcutContext, [&]() { Commands::SaveCurrentScene(context); });
|
||||
HandleShortcut(MakeSaveSceneAsAction(), shortcutContext, [&]() { Commands::SaveSceneAsWithDialog(context); });
|
||||
HandleShortcut(MakeUndoAction(context), shortcutContext, [&]() { context.GetUndoManager().Undo(); });
|
||||
HandleShortcut(MakeRedoAction(context), shortcutContext, [&]() { context.GetUndoManager().Redo(); });
|
||||
HandleShortcut(MakeNewSceneAction(), shortcutContext, [&]() { ExecuteNewScene(context); });
|
||||
HandleShortcut(MakeOpenSceneAction(), shortcutContext, [&]() { ExecuteOpenScene(context); });
|
||||
HandleShortcut(MakeSaveSceneAction(), shortcutContext, [&]() { ExecuteSaveScene(context); });
|
||||
HandleShortcut(MakeSaveSceneAsAction(), shortcutContext, [&]() { ExecuteSaveSceneAs(context); });
|
||||
HandleShortcut(MakeUndoAction(context), shortcutContext, [&]() { ExecuteUndo(context); });
|
||||
HandleShortcut(MakeRedoAction(context), shortcutContext, [&]() { ExecuteRedo(context); });
|
||||
HandleEditShortcuts(context, shortcutContext);
|
||||
}
|
||||
|
||||
inline void DrawFileMenuActions(IEditorContext& context) {
|
||||
DrawMenuAction(MakeNewSceneAction(), [&]() { Commands::NewScene(context); });
|
||||
DrawMenuAction(MakeOpenSceneAction(), [&]() { Commands::OpenSceneWithDialog(context); });
|
||||
DrawMenuAction(MakeSaveSceneAction(), [&]() { Commands::SaveCurrentScene(context); });
|
||||
DrawMenuAction(MakeSaveSceneAsAction(), [&]() { Commands::SaveSceneAsWithDialog(context); });
|
||||
DrawMenuAction(MakeNewSceneAction(), [&]() { ExecuteNewScene(context); });
|
||||
DrawMenuAction(MakeOpenSceneAction(), [&]() { ExecuteOpenScene(context); });
|
||||
DrawMenuAction(MakeSaveSceneAction(), [&]() { ExecuteSaveScene(context); });
|
||||
DrawMenuAction(MakeSaveSceneAsAction(), [&]() { ExecuteSaveSceneAs(context); });
|
||||
DrawMenuSeparator();
|
||||
DrawMenuAction(MakeExitAction(), [&]() {
|
||||
context.GetEventBus().Publish(EditorExitRequestedEvent{});
|
||||
});
|
||||
DrawMenuAction(MakeExitAction(), [&]() { RequestEditorExit(context); });
|
||||
}
|
||||
|
||||
inline void DrawViewMenuActions(IEditorContext& context) {
|
||||
DrawMenuAction(MakeResetLayoutAction(), [&]() {
|
||||
context.GetEventBus().Publish(DockLayoutResetRequestedEvent{});
|
||||
});
|
||||
DrawMenuAction(MakeResetLayoutAction(), [&]() { RequestDockLayoutReset(context); });
|
||||
}
|
||||
|
||||
inline void DrawHelpMenuActions(UI::DeferredPopupState& aboutPopup) {
|
||||
DrawMenuAction(MakeAboutAction(), [&]() {
|
||||
aboutPopup.RequestOpen();
|
||||
DrawMenuAction(MakeAboutAction(), [&]() { RequestAboutPopup(aboutPopup); });
|
||||
}
|
||||
|
||||
inline void HandleMenuBarShortcuts(IEditorContext& context) {
|
||||
HandleMainMenuShortcuts(context, GlobalShortcutContext());
|
||||
}
|
||||
|
||||
inline void DrawMainMenuBar(IEditorContext& context, UI::DeferredPopupState& aboutPopup) {
|
||||
if (!ImGui::BeginMainMenuBar()) {
|
||||
return;
|
||||
}
|
||||
|
||||
UI::DrawMenuScope("File", [&]() {
|
||||
DrawFileMenuActions(context);
|
||||
});
|
||||
UI::DrawMenuScope("Edit", [&]() {
|
||||
DrawEditActions(context);
|
||||
});
|
||||
UI::DrawMenuScope("View", [&]() {
|
||||
DrawViewMenuActions(context);
|
||||
});
|
||||
UI::DrawMenuScope("Help", [&]() {
|
||||
DrawHelpMenuActions(aboutPopup);
|
||||
});
|
||||
UI::DrawSceneStatusWidget(context);
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
|
||||
inline void DrawMainMenuOverlays(IEditorContext* context, UI::DeferredPopupState& aboutPopup) {
|
||||
UI::DrawEditorAboutDialog(context, aboutPopup);
|
||||
}
|
||||
|
||||
} // namespace Actions
|
||||
|
||||
@@ -14,6 +14,8 @@ inline constexpr const char* ProjectAssetPayloadType() {
|
||||
return "ASSET_ITEM";
|
||||
}
|
||||
|
||||
inline void DrawProjectAssetContextActions(IEditorContext& context, const AssetItemPtr& item);
|
||||
|
||||
inline int FindProjectItemIndex(IProjectManager& projectManager, const AssetItemPtr& item) {
|
||||
if (!item) {
|
||||
return -1;
|
||||
@@ -77,6 +79,64 @@ inline bool BeginProjectAssetDrag(const AssetItemPtr& item, UI::AssetIconKind ic
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool OpenProjectAsset(IEditorContext& context, const AssetItemPtr& item) {
|
||||
if (!Commands::CanOpenAsset(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Commands::OpenAsset(context, item);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool DrawProjectNavigateBackAction(IProjectManager& projectManager) {
|
||||
const bool canGoBack = projectManager.CanNavigateBack();
|
||||
if (!DrawToolbarAction(MakeNavigateBackAction(canGoBack), UI::ProjectBackButtonSize())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
projectManager.NavigateBack();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void HandleProjectBackgroundPrimaryClick(IProjectManager& projectManager) {
|
||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered()) {
|
||||
projectManager.SetSelectedIndex(-1);
|
||||
}
|
||||
}
|
||||
|
||||
inline void RequestProjectEmptyContextPopup(UI::DeferredPopupState& emptyContextMenu) {
|
||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(1) && !ImGui::IsAnyItemHovered()) {
|
||||
emptyContextMenu.RequestOpen();
|
||||
}
|
||||
}
|
||||
|
||||
inline void HandleProjectItemSelection(IProjectManager& projectManager, int index) {
|
||||
projectManager.SetSelectedIndex(index);
|
||||
}
|
||||
|
||||
inline void HandleProjectItemContextRequest(
|
||||
IProjectManager& projectManager,
|
||||
int index,
|
||||
const AssetItemPtr& item,
|
||||
UI::TargetedPopupState<AssetItemPtr>& itemContextMenu) {
|
||||
projectManager.SetSelectedIndex(index);
|
||||
itemContextMenu.RequestOpen(item);
|
||||
}
|
||||
|
||||
inline void DrawProjectItemContextPopup(IEditorContext& context, UI::TargetedPopupState<AssetItemPtr>& itemContextMenu) {
|
||||
itemContextMenu.ConsumeOpenRequest("ItemContextMenu");
|
||||
if (UI::BeginPopup("ItemContextMenu")) {
|
||||
if (itemContextMenu.HasTarget()) {
|
||||
DrawProjectAssetContextActions(context, itemContextMenu.TargetValue());
|
||||
}
|
||||
UI::EndPopup();
|
||||
}
|
||||
|
||||
if (!ImGui::IsPopupOpen("ItemContextMenu") && !itemContextMenu.HasPendingOpenRequest()) {
|
||||
itemContextMenu.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
inline void DrawProjectAssetContextActions(IEditorContext& context, const AssetItemPtr& item) {
|
||||
auto& projectManager = context.GetProjectManager();
|
||||
const int itemIndex = FindProjectItemIndex(projectManager, item);
|
||||
@@ -97,6 +157,20 @@ inline void DrawProjectEmptyContextActions(UI::TextInputPopupState<BufferCapacit
|
||||
});
|
||||
}
|
||||
|
||||
template <size_t BufferCapacity>
|
||||
inline void DrawProjectEmptyContextPopup(
|
||||
UI::DeferredPopupState& emptyContextMenu,
|
||||
UI::TextInputPopupState<BufferCapacity>& createFolderDialog) {
|
||||
emptyContextMenu.ConsumeOpenRequest("EmptyContextMenu");
|
||||
|
||||
if (!UI::BeginPopup("EmptyContextMenu")) {
|
||||
return;
|
||||
}
|
||||
|
||||
DrawProjectEmptyContextActions(createFolderDialog);
|
||||
UI::EndPopup();
|
||||
}
|
||||
|
||||
template <size_t BufferCapacity>
|
||||
inline void DrawProjectCreateFolderDialog(IEditorContext& context, UI::TextInputPopupState<BufferCapacity>& createFolderDialog) {
|
||||
createFolderDialog.ConsumeOpenRequest("Create Folder");
|
||||
|
||||
@@ -17,6 +17,62 @@ Application& Application::Get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool Application::InitializeWindowRenderer(HWND hwnd) {
|
||||
if (m_windowRenderer.Initialize(hwnd, 1280, 720)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MessageBoxW(hwnd, L"Failed to create D3D12 device", L"Error", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
void Application::InitializeEditorContext(const std::string& projectPath) {
|
||||
m_editorContext = std::make_shared<EditorContext>();
|
||||
m_editorContext->SetProjectPath(projectPath);
|
||||
m_exitRequestedHandlerId = m_editorContext->GetEventBus().Subscribe<EditorExitRequestedEvent>(
|
||||
[this](const EditorExitRequestedEvent&) {
|
||||
if (m_hwnd) {
|
||||
PostMessageW(m_hwnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Application::InitializeImGui(HWND hwnd) {
|
||||
m_imguiSession.Initialize(m_editorContext->GetProjectPath());
|
||||
m_imguiBackend.Initialize(hwnd, m_windowRenderer.GetDevice(), m_windowRenderer.GetSrvHeap());
|
||||
}
|
||||
|
||||
void Application::AttachEditorLayer() {
|
||||
m_editorLayer = new EditorLayer();
|
||||
m_editorLayer->SetContext(m_editorContext);
|
||||
m_layerStack.pushLayer(std::unique_ptr<Core::Layer>(m_editorLayer));
|
||||
m_layerStack.onAttach();
|
||||
}
|
||||
|
||||
void Application::DetachEditorLayer() {
|
||||
m_layerStack.onDetach();
|
||||
m_editorLayer = nullptr;
|
||||
}
|
||||
|
||||
void Application::ShutdownEditorContext() {
|
||||
if (m_editorContext && m_exitRequestedHandlerId) {
|
||||
m_editorContext->GetEventBus().Unsubscribe<EditorExitRequestedEvent>(m_exitRequestedHandlerId);
|
||||
m_exitRequestedHandlerId = 0;
|
||||
}
|
||||
|
||||
m_editorContext.reset();
|
||||
}
|
||||
|
||||
void Application::RenderEditorFrame() {
|
||||
static constexpr float kClearColor[4] = { 0.22f, 0.22f, 0.22f, 1.0f };
|
||||
|
||||
m_imguiBackend.BeginFrame();
|
||||
m_layerStack.onImGuiRender();
|
||||
UpdateWindowTitle();
|
||||
ImGui::Render();
|
||||
m_windowRenderer.Render(m_imguiBackend, kClearColor);
|
||||
}
|
||||
|
||||
bool Application::Initialize(HWND hwnd) {
|
||||
Platform::InstallCrashExceptionFilter();
|
||||
Platform::RedirectStderrToExecutableLog();
|
||||
@@ -25,55 +81,27 @@ bool Application::Initialize(HWND hwnd) {
|
||||
ConfigureEditorLogging(exeDir);
|
||||
|
||||
m_hwnd = hwnd;
|
||||
|
||||
if (!m_windowRenderer.Initialize(hwnd, 1280, 720)) {
|
||||
MessageBoxW(hwnd, L"Failed to create D3D12 device", L"Error", MB_OK | MB_ICONERROR);
|
||||
|
||||
if (!InitializeWindowRenderer(hwnd)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_editorContext = std::make_shared<EditorContext>();
|
||||
m_editorContext->SetProjectPath(exeDir);
|
||||
m_exitRequestedHandlerId = m_editorContext->GetEventBus().Subscribe<EditorExitRequestedEvent>(
|
||||
[this](const EditorExitRequestedEvent&) {
|
||||
if (m_hwnd) {
|
||||
PostMessageW(m_hwnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
});
|
||||
m_imguiSession.Initialize(m_editorContext->GetProjectPath());
|
||||
|
||||
m_imguiBackend.Initialize(hwnd, m_windowRenderer.GetDevice(), m_windowRenderer.GetSrvHeap());
|
||||
|
||||
m_editorLayer = new EditorLayer();
|
||||
m_editorLayer->SetContext(m_editorContext);
|
||||
m_layerStack.pushLayer(std::unique_ptr<Core::Layer>(m_editorLayer));
|
||||
m_layerStack.onAttach();
|
||||
|
||||
InitializeEditorContext(exeDir);
|
||||
InitializeImGui(hwnd);
|
||||
AttachEditorLayer();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::Shutdown() {
|
||||
m_layerStack.onDetach();
|
||||
|
||||
if (m_editorContext && m_exitRequestedHandlerId) {
|
||||
m_editorContext->GetEventBus().Unsubscribe<EditorExitRequestedEvent>(m_exitRequestedHandlerId);
|
||||
m_exitRequestedHandlerId = 0;
|
||||
}
|
||||
|
||||
DetachEditorLayer();
|
||||
m_imguiBackend.Shutdown();
|
||||
m_imguiSession.Shutdown();
|
||||
ShutdownEditorContext();
|
||||
m_windowRenderer.Shutdown();
|
||||
}
|
||||
|
||||
void Application::Render() {
|
||||
m_imguiBackend.BeginFrame();
|
||||
|
||||
m_layerStack.onImGuiRender();
|
||||
UpdateWindowTitle();
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
float clearColor[4] = { 0.22f, 0.22f, 0.22f, 1.0f };
|
||||
m_windowRenderer.Render(m_imguiBackend, clearColor);
|
||||
RenderEditorFrame();
|
||||
}
|
||||
|
||||
void Application::UpdateWindowTitle() {
|
||||
|
||||
@@ -31,6 +31,13 @@ public:
|
||||
private:
|
||||
Application() = default;
|
||||
~Application() = default;
|
||||
bool InitializeWindowRenderer(HWND hwnd);
|
||||
void InitializeEditorContext(const std::string& projectPath);
|
||||
void InitializeImGui(HWND hwnd);
|
||||
void AttachEditorLayer();
|
||||
void DetachEditorLayer();
|
||||
void ShutdownEditorContext();
|
||||
void RenderEditorFrame();
|
||||
void UpdateWindowTitle();
|
||||
|
||||
HWND m_hwnd = nullptr;
|
||||
|
||||
@@ -32,25 +32,8 @@ void ConsolePanel::Render() {
|
||||
if (!content.IsOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto logs = sink->GetLogs();
|
||||
size_t logIndex = 0;
|
||||
for (const auto& log : logs) {
|
||||
if (!m_filterState.Allows(log.level)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ImGui::PushID(static_cast<int>(logIndex));
|
||||
|
||||
const std::string fullMessage = UI::BuildConsoleLogText(log);
|
||||
if (UI::DrawConsoleLogRow(fullMessage.c_str())) {
|
||||
ImGui::SetClipboardText(fullMessage.c_str());
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
logIndex++;
|
||||
}
|
||||
|
||||
Actions::DrawConsoleLogRows(*sink, m_filterState);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -87,21 +87,11 @@ void HierarchyPanel::Render() {
|
||||
for (auto* gameObject : rootEntities) {
|
||||
RenderEntity(gameObject, filter);
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseDown(0) && !ImGui::IsAnyItemHovered()) {
|
||||
if (!m_renameState.IsActive()) {
|
||||
m_context->GetSelectionManager().ClearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
if (UI::BeginPopupContextWindow("HierarchyContextMenu", ImGuiPopupFlags_MouseButtonRight)) {
|
||||
Actions::DrawHierarchyCreateActions(*m_context, nullptr);
|
||||
UI::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::InvisibleButton("##DragTarget", ImVec2(-1, -1));
|
||||
Actions::AcceptHierarchyEntityDropToRoot(*m_context);
|
||||
|
||||
|
||||
Actions::HandleHierarchyBackgroundPrimaryClick(*m_context, m_renameState);
|
||||
|
||||
Actions::DrawHierarchyBackgroundContextPopup(*m_context);
|
||||
Actions::DrawHierarchyRootDropTarget(*m_context);
|
||||
}
|
||||
|
||||
void HierarchyPanel::RenderSearchBar() {
|
||||
@@ -119,33 +109,18 @@ void HierarchyPanel::RenderSearchBar() {
|
||||
buttonWidth + UI::ToolbarSearchTrailingSpacing());
|
||||
ImGui::SameLine();
|
||||
if (UI::ToolbarButton("...", false, ImVec2(buttonWidth, 0.0f))) {
|
||||
ImGui::OpenPopup("HierarchyOptions");
|
||||
Actions::RequestHierarchyOptionsPopup(m_optionsPopup);
|
||||
}
|
||||
|
||||
if (UI::BeginPopup("HierarchyOptions")) {
|
||||
const UI::MenuCommand commands[] = {
|
||||
UI::MenuCommand::Action("Sort By Name", nullptr, m_sortMode == SortMode::Name),
|
||||
UI::MenuCommand::Action("Sort By Component Count", nullptr, m_sortMode == SortMode::ComponentCount),
|
||||
UI::MenuCommand::Action("Transform First", nullptr, m_sortMode == SortMode::TransformFirst)
|
||||
};
|
||||
|
||||
UI::DrawMenuCommands(commands, [&](size_t index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
m_sortMode = SortMode::Name;
|
||||
break;
|
||||
case 1:
|
||||
m_sortMode = SortMode::ComponentCount;
|
||||
break;
|
||||
case 2:
|
||||
m_sortMode = SortMode::TransformFirst;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Actions::DrawHierarchySortOptionsPopup(
|
||||
m_optionsPopup,
|
||||
m_sortMode,
|
||||
SortMode::Name,
|
||||
SortMode::ComponentCount,
|
||||
SortMode::TransformFirst,
|
||||
[this](SortMode mode) {
|
||||
m_sortMode = mode;
|
||||
});
|
||||
UI::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void HierarchyPanel::RenderEntity(::XCEngine::Components::GameObject* gameObject, const std::string& filter) {
|
||||
@@ -193,11 +168,8 @@ void HierarchyPanel::RenderEntity(::XCEngine::Components::GameObject* gameObject
|
||||
|
||||
Actions::BeginHierarchyEntityDrag(gameObject);
|
||||
Actions::AcceptHierarchyEntityDrop(*m_context, gameObject);
|
||||
|
||||
if (UI::BeginPopupContextItem("EntityContextMenu")) {
|
||||
Actions::DrawHierarchyContextActions(*m_context, gameObject);
|
||||
UI::EndPopup();
|
||||
}
|
||||
|
||||
Actions::DrawHierarchyEntityContextPopup(*m_context, gameObject);
|
||||
|
||||
if (node.open) {
|
||||
for (size_t i = 0; i < gameObject->GetChildCount(); i++) {
|
||||
@@ -225,10 +197,7 @@ void HierarchyPanel::CommitRename() {
|
||||
}
|
||||
|
||||
const uint64_t entityId = m_renameState.Item();
|
||||
if (!m_renameState.Empty() && m_context->GetSceneManager().GetEntity(entityId)) {
|
||||
Commands::RenameEntity(*m_context, entityId, m_renameState.Buffer());
|
||||
}
|
||||
|
||||
Actions::CommitEntityRename(*m_context, entityId, m_renameState.Buffer());
|
||||
CancelRename();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ private:
|
||||
|
||||
char m_searchBuffer[256] = "";
|
||||
UI::InlineTextEditState<uint64_t, 256> m_renameState;
|
||||
UI::DeferredPopupState m_optionsPopup;
|
||||
SortMode m_sortMode = SortMode::Name;
|
||||
uint64_t m_selectionHandlerId = 0;
|
||||
uint64_t m_renameRequestHandlerId = 0;
|
||||
|
||||
@@ -44,11 +44,7 @@ void InspectorPanel::OnDetach() {
|
||||
}
|
||||
|
||||
void InspectorPanel::OnSelectionChanged(const SelectionChangedEvent& event) {
|
||||
if (m_context && m_context->GetUndoManager().HasPendingInteractiveChange()) {
|
||||
m_context->GetUndoManager().FinalizeInteractiveChange();
|
||||
}
|
||||
m_selectedEntityId = event.primarySelection;
|
||||
m_addComponentPopup.Clear();
|
||||
Actions::HandleInspectorSelectionChanged(*m_context, event, m_selectedEntityId, m_addComponentPopup);
|
||||
}
|
||||
|
||||
void InspectorPanel::Render() {
|
||||
@@ -90,14 +86,10 @@ void InspectorPanel::RenderGameObject(::XCEngine::Components::GameObject* gameOb
|
||||
RenderComponent(component, gameObject);
|
||||
}
|
||||
|
||||
if (Actions::DrawInspectorAction(Actions::MakeAddComponentButtonAction(gameObject != nullptr))) {
|
||||
m_addComponentPopup.RequestOpen();
|
||||
}
|
||||
RenderAddComponentPopup(gameObject);
|
||||
Actions::DrawInspectorAddComponentButton(m_addComponentPopup, gameObject != nullptr);
|
||||
Actions::DrawInspectorAddComponentPopup(*m_context, m_addComponentPopup, gameObject);
|
||||
|
||||
if (m_context->GetUndoManager().HasPendingInteractiveChange() && !ImGui::IsAnyItemActive()) {
|
||||
m_context->GetUndoManager().FinalizeInteractiveChange();
|
||||
}
|
||||
Actions::FinalizeInspectorInteractiveChangeIfIdle(*m_context);
|
||||
}
|
||||
|
||||
void InspectorPanel::RenderEmptyState(const char* title, const char* subtitle) {
|
||||
@@ -109,20 +101,6 @@ void InspectorPanel::RenderEmptyState(const char* title, const char* subtitle) {
|
||||
UI::DrawEmptyState(title, subtitle);
|
||||
}
|
||||
|
||||
void InspectorPanel::RenderAddComponentPopup(::XCEngine::Components::GameObject* gameObject) {
|
||||
m_addComponentPopup.ConsumeOpenRequest("AddComponent");
|
||||
|
||||
if (!UI::BeginTitledPopup("AddComponent", "Components")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Actions::DrawInspectorAddComponentMenu(*m_context, gameObject)) {
|
||||
UI::DrawHintText("No registered component editors");
|
||||
}
|
||||
|
||||
UI::EndTitledPopup();
|
||||
}
|
||||
|
||||
void InspectorPanel::RenderComponent(::XCEngine::Components::Component* component, ::XCEngine::Components::GameObject* gameObject) {
|
||||
if (!component) return;
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ public:
|
||||
|
||||
private:
|
||||
void RenderGameObject(::XCEngine::Components::GameObject* gameObject);
|
||||
void RenderAddComponentPopup(::XCEngine::Components::GameObject* gameObject);
|
||||
void RenderComponent(::XCEngine::Components::Component* component, ::XCEngine::Components::GameObject* gameObject);
|
||||
void RenderEmptyState(const char* title, const char* subtitle = nullptr);
|
||||
void OnSelectionChanged(const struct SelectionChangedEvent& event);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "Actions/MainMenuActionRouter.h"
|
||||
#include "MenuBar.h"
|
||||
#include "Core/IEditorContext.h"
|
||||
#include "UI/UI.h"
|
||||
#include <imgui.h>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -12,61 +11,13 @@ namespace Editor {
|
||||
MenuBar::MenuBar() : Panel("MenuBar") {}
|
||||
|
||||
void MenuBar::Render() {
|
||||
HandleShortcuts();
|
||||
|
||||
if (ImGui::BeginMainMenuBar()) {
|
||||
ShowFileMenu();
|
||||
ShowEditMenu();
|
||||
ShowViewMenu();
|
||||
ShowHelpMenu();
|
||||
RenderSceneStatus();
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
|
||||
RenderAboutPopup();
|
||||
}
|
||||
|
||||
void MenuBar::HandleShortcuts() {
|
||||
if (!m_context) {
|
||||
return;
|
||||
}
|
||||
|
||||
Actions::HandleMainMenuShortcuts(*m_context, Actions::GlobalShortcutContext());
|
||||
}
|
||||
|
||||
void MenuBar::ShowFileMenu() {
|
||||
UI::DrawMenuScope("File", [&]() {
|
||||
Actions::DrawFileMenuActions(*m_context);
|
||||
});
|
||||
}
|
||||
|
||||
void MenuBar::ShowEditMenu() {
|
||||
UI::DrawMenuScope("Edit", [&]() {
|
||||
Actions::DrawEditActions(*m_context);
|
||||
});
|
||||
}
|
||||
|
||||
void MenuBar::ShowViewMenu() {
|
||||
UI::DrawMenuScope("View", [&]() {
|
||||
Actions::DrawViewMenuActions(*m_context);
|
||||
});
|
||||
}
|
||||
|
||||
void MenuBar::ShowHelpMenu() {
|
||||
UI::DrawMenuScope("Help", [&]() {
|
||||
Actions::DrawHelpMenuActions(m_aboutPopup);
|
||||
});
|
||||
}
|
||||
|
||||
void MenuBar::RenderAboutPopup() {
|
||||
UI::DrawEditorAboutDialog(m_context, m_aboutPopup);
|
||||
}
|
||||
|
||||
void MenuBar::RenderSceneStatus() {
|
||||
if (!m_context) {
|
||||
return;
|
||||
}
|
||||
UI::DrawSceneStatusWidget(*m_context);
|
||||
Actions::HandleMenuBarShortcuts(*m_context);
|
||||
Actions::DrawMainMenuBar(*m_context, m_aboutPopup);
|
||||
Actions::DrawMainMenuOverlays(m_context, m_aboutPopup);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,14 +12,6 @@ public:
|
||||
void Render() override;
|
||||
|
||||
private:
|
||||
void HandleShortcuts();
|
||||
void RenderSceneStatus();
|
||||
void RenderAboutPopup();
|
||||
void ShowFileMenu();
|
||||
void ShowEditMenu();
|
||||
void ShowViewMenu();
|
||||
void ShowHelpMenu();
|
||||
|
||||
UI::DeferredPopupState m_aboutPopup;
|
||||
};
|
||||
|
||||
|
||||
@@ -30,11 +30,7 @@ void ProjectPanel::Render() {
|
||||
|
||||
UI::PanelToolbarScope toolbar("ProjectToolbar", UI::ProjectPanelToolbarHeight());
|
||||
if (toolbar.IsOpen()) {
|
||||
|
||||
bool canGoBack = manager.CanNavigateBack();
|
||||
if (Actions::DrawToolbarAction(Actions::MakeNavigateBackAction(canGoBack), UI::ProjectBackButtonSize())) {
|
||||
manager.NavigateBack();
|
||||
}
|
||||
Actions::DrawProjectNavigateBackAction(manager);
|
||||
ImGui::SameLine();
|
||||
|
||||
size_t pathDepth = manager.GetPathDepth();
|
||||
@@ -88,29 +84,10 @@ void ProjectPanel::Render() {
|
||||
searchStr.empty() ? "Current folder is empty" : "No assets match the current search");
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered()) {
|
||||
manager.SetSelectedIndex(-1);
|
||||
}
|
||||
|
||||
m_itemContextMenu.ConsumeOpenRequest("ItemContextMenu");
|
||||
if (UI::BeginPopup("ItemContextMenu")) {
|
||||
if (m_itemContextMenu.HasTarget()) {
|
||||
Actions::DrawProjectAssetContextActions(*m_context, m_itemContextMenu.TargetValue());
|
||||
}
|
||||
UI::EndPopup();
|
||||
}
|
||||
if (!ImGui::IsPopupOpen("ItemContextMenu") && !m_itemContextMenu.HasPendingOpenRequest()) {
|
||||
m_itemContextMenu.Clear();
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(1) && !ImGui::IsAnyItemHovered()) {
|
||||
ImGui::OpenPopup("EmptyContextMenu");
|
||||
}
|
||||
|
||||
if (UI::BeginPopup("EmptyContextMenu")) {
|
||||
Actions::DrawProjectEmptyContextActions(m_createFolderDialog);
|
||||
UI::EndPopup();
|
||||
}
|
||||
Actions::HandleProjectBackgroundPrimaryClick(manager);
|
||||
Actions::DrawProjectItemContextPopup(*m_context, m_itemContextMenu);
|
||||
Actions::RequestProjectEmptyContextPopup(m_emptyContextMenu);
|
||||
Actions::DrawProjectEmptyContextPopup(m_emptyContextMenu, m_createFolderDialog);
|
||||
|
||||
Actions::DrawProjectCreateFolderDialog(*m_context, m_createFolderDialog);
|
||||
}
|
||||
@@ -132,19 +109,18 @@ void ProjectPanel::RenderAssetItem(const AssetItemPtr& item, int index) {
|
||||
});
|
||||
|
||||
if (tile.clicked) {
|
||||
manager.SetSelectedIndex(index);
|
||||
Actions::HandleProjectItemSelection(manager, index);
|
||||
}
|
||||
|
||||
if (tile.contextRequested) {
|
||||
manager.SetSelectedIndex(index);
|
||||
m_itemContextMenu.RequestOpen(item);
|
||||
Actions::HandleProjectItemContextRequest(manager, index, item, m_itemContextMenu);
|
||||
}
|
||||
|
||||
Actions::AcceptProjectAssetDrop(manager, item);
|
||||
Actions::BeginProjectAssetDrag(item, iconKind);
|
||||
|
||||
if (tile.openRequested) {
|
||||
Commands::OpenAsset(*m_context, item);
|
||||
Actions::OpenProjectAsset(*m_context, item);
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
@@ -18,6 +18,7 @@ private:
|
||||
|
||||
char m_searchBuffer[256] = "";
|
||||
UI::TextInputPopupState<256> m_createFolderDialog;
|
||||
UI::DeferredPopupState m_emptyContextMenu;
|
||||
UI::TargetedPopupState<AssetItemPtr> m_itemContextMenu;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user