Extract editor interaction states
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
- hierarchy tree node
|
||||
- asset tile
|
||||
- deferred popup / modal state
|
||||
- inline text edit state
|
||||
- inspector component section
|
||||
- dialog action row
|
||||
- property grid / scalar / vector 控件
|
||||
@@ -146,10 +147,10 @@
|
||||
- 创建 / 删除 / 重命名 / 复制 / 粘贴 / Duplicate / 重挂接走 command
|
||||
- 快捷键已接 action 层
|
||||
- 重命名状态已收成 `Begin / Commit / Cancel`
|
||||
- 重命名交互已从 panel 局部字段收口到 shared inline edit state
|
||||
|
||||
仍待完成:
|
||||
|
||||
- 重命名状态机进一步下沉
|
||||
- 拖拽 / 空白区域目标等细节继续统一
|
||||
|
||||
### Project
|
||||
@@ -175,6 +176,7 @@
|
||||
- 组件增删已走 command
|
||||
- 组件内容编辑大部分已走 property grid
|
||||
- Add Component 按钮与 popup 项已接 action 层
|
||||
- Add Component popup 已接 shared popup state
|
||||
|
||||
仍待完成:
|
||||
|
||||
@@ -213,10 +215,9 @@
|
||||
|
||||
2. 继续将 panel 的本地状态机抽离
|
||||
包括:
|
||||
- hierarchy rename state
|
||||
- project popup / dialog state
|
||||
- inspector component popup state
|
||||
- console filter state
|
||||
- 其他仍散落在 panel 内的临时交互状态
|
||||
|
||||
3. 将剩余少量视觉硬编码继续下沉到 token / widget 层
|
||||
尤其是 `ProjectPanel` 中的 icon color 和一部分 panel 局部尺寸。
|
||||
|
||||
@@ -27,6 +27,10 @@ public:
|
||||
return m_openRequested;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
m_openRequested = false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_openRequested = false;
|
||||
};
|
||||
@@ -77,6 +81,76 @@ private:
|
||||
char m_buffer[BufferCapacity] = {};
|
||||
};
|
||||
|
||||
template <typename ItemId, size_t BufferCapacity>
|
||||
class InlineTextEditState {
|
||||
public:
|
||||
void Begin(ItemId itemId, const char* initialValue = "") {
|
||||
m_active = true;
|
||||
m_itemId = itemId;
|
||||
SetValue(initialValue);
|
||||
m_focusRequested = true;
|
||||
}
|
||||
|
||||
bool IsActive() const {
|
||||
return m_active;
|
||||
}
|
||||
|
||||
bool IsEditing(ItemId itemId) const {
|
||||
return m_active && m_itemId == itemId;
|
||||
}
|
||||
|
||||
ItemId Item() const {
|
||||
return m_itemId;
|
||||
}
|
||||
|
||||
bool ConsumeFocusRequest() {
|
||||
if (!m_focusRequested) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_focusRequested = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetValue(const char* value) {
|
||||
if (value && value[0] != '\0') {
|
||||
strcpy_s(m_buffer, value);
|
||||
return;
|
||||
}
|
||||
|
||||
m_buffer[0] = '\0';
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
return m_buffer[0] == '\0';
|
||||
}
|
||||
|
||||
char* Buffer() {
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
const char* Buffer() const {
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
constexpr size_t BufferSize() const {
|
||||
return BufferCapacity;
|
||||
}
|
||||
|
||||
void Cancel() {
|
||||
m_active = false;
|
||||
m_itemId = ItemId{};
|
||||
m_buffer[0] = '\0';
|
||||
m_focusRequested = false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_active = false;
|
||||
ItemId m_itemId = ItemId{};
|
||||
char m_buffer[BufferCapacity] = {};
|
||||
bool m_focusRequested = false;
|
||||
};
|
||||
|
||||
} // namespace UI
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
|
||||
@@ -32,7 +32,9 @@ void HierarchyPanel::OnAttach() {
|
||||
}
|
||||
|
||||
void HierarchyPanel::OnSelectionChanged(const SelectionChangedEvent& event) {
|
||||
m_needsRefresh = true;
|
||||
if (m_renameState.IsActive() && event.primarySelection != m_renameState.Item()) {
|
||||
CancelRename();
|
||||
}
|
||||
}
|
||||
|
||||
void HierarchyPanel::Render() {
|
||||
@@ -61,7 +63,7 @@ void HierarchyPanel::Render() {
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseDown(0) && !ImGui::IsAnyItemHovered()) {
|
||||
if (!m_renaming) {
|
||||
if (!m_renameState.IsActive()) {
|
||||
m_context->GetSelectionManager().ClearSelection();
|
||||
}
|
||||
}
|
||||
@@ -137,14 +139,17 @@ void HierarchyPanel::RenderEntity(::XCEngine::Components::GameObject* gameObject
|
||||
|
||||
ImGui::PushID(static_cast<int>(gameObject->GetID()));
|
||||
|
||||
if (m_renaming && m_renamingEntity == gameObject) {
|
||||
if (m_renameJustStarted) {
|
||||
if (m_renameState.IsEditing(gameObject->GetID())) {
|
||||
if (m_renameState.ConsumeFocusRequest()) {
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
m_renameJustStarted = false;
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
if (ImGui::InputText("##Rename", m_renameBuffer, sizeof(m_renameBuffer), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
|
||||
if (ImGui::InputText(
|
||||
"##Rename",
|
||||
m_renameState.Buffer(),
|
||||
m_renameState.BufferSize(),
|
||||
ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
|
||||
CommitRename();
|
||||
}
|
||||
|
||||
@@ -253,25 +258,24 @@ void HierarchyPanel::BeginRename(::XCEngine::Components::GameObject* gameObject)
|
||||
return;
|
||||
}
|
||||
|
||||
m_renaming = true;
|
||||
m_renamingEntity = gameObject;
|
||||
strcpy_s(m_renameBuffer, gameObject->GetName().c_str());
|
||||
m_renameJustStarted = true;
|
||||
m_renameState.Begin(gameObject->GetID(), gameObject->GetName().c_str());
|
||||
}
|
||||
|
||||
void HierarchyPanel::CommitRename() {
|
||||
if (m_renamingEntity && strlen(m_renameBuffer) > 0) {
|
||||
Commands::RenameEntity(*m_context, m_renamingEntity->GetID(), m_renameBuffer);
|
||||
if (!m_renameState.IsActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint64_t entityId = m_renameState.Item();
|
||||
if (!m_renameState.Empty() && m_context->GetSceneManager().GetEntity(entityId)) {
|
||||
Commands::RenameEntity(*m_context, entityId, m_renameState.Buffer());
|
||||
}
|
||||
|
||||
CancelRename();
|
||||
}
|
||||
|
||||
void HierarchyPanel::CancelRename() {
|
||||
m_renaming = false;
|
||||
m_renamingEntity = nullptr;
|
||||
m_renameBuffer[0] = '\0';
|
||||
m_renameJustStarted = false;
|
||||
m_renameState.Cancel();
|
||||
}
|
||||
|
||||
void HierarchyPanel::HandleDragDrop(::XCEngine::Components::GameObject* gameObject) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Panel.h"
|
||||
#include "UI/PopupState.h"
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
#include "Core/ISceneManager.h"
|
||||
|
||||
@@ -32,13 +33,9 @@ private:
|
||||
void SortEntities(std::vector<::XCEngine::Components::GameObject*>& entities);
|
||||
|
||||
char m_searchBuffer[256] = "";
|
||||
bool m_renaming = false;
|
||||
::XCEngine::Components::GameObject* m_renamingEntity = nullptr;
|
||||
char m_renameBuffer[256] = "";
|
||||
bool m_renameJustStarted = false;
|
||||
UI::InlineTextEditState<uint64_t, 256> m_renameState;
|
||||
SortMode m_sortMode = SortMode::Name;
|
||||
uint64_t m_selectionHandlerId = 0;
|
||||
bool m_needsRefresh = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ void InspectorPanel::OnSelectionChanged(const SelectionChangedEvent& event) {
|
||||
m_context->GetUndoManager().FinalizeInteractiveChange();
|
||||
}
|
||||
m_selectedEntityId = event.primarySelection;
|
||||
m_addComponentPopup.Clear();
|
||||
}
|
||||
|
||||
void InspectorPanel::Render() {
|
||||
@@ -78,7 +79,7 @@ void InspectorPanel::RenderGameObject(::XCEngine::Components::GameObject* gameOb
|
||||
}
|
||||
|
||||
if (Actions::DrawInspectorAction(Actions::MakeAddComponentButtonAction(gameObject != nullptr))) {
|
||||
ImGui::OpenPopup("AddComponent");
|
||||
m_addComponentPopup.RequestOpen();
|
||||
}
|
||||
RenderAddComponentPopup(gameObject);
|
||||
|
||||
@@ -97,6 +98,8 @@ void InspectorPanel::RenderEmptyState(const char* title, const char* subtitle) {
|
||||
}
|
||||
|
||||
void InspectorPanel::RenderAddComponentPopup(::XCEngine::Components::GameObject* gameObject) {
|
||||
m_addComponentPopup.ConsumeOpenRequest("AddComponent");
|
||||
|
||||
if (!UI::BeginTitledPopup("AddComponent", "Components")) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Panel.h"
|
||||
#include "UI/PopupState.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -28,6 +29,7 @@ private:
|
||||
|
||||
uint64_t m_selectionHandlerId = 0;
|
||||
uint64_t m_selectedEntityId = 0;
|
||||
UI::DeferredPopupState m_addComponentPopup;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user