Fix hierarchy rename field behavior
This commit is contained in:
@@ -354,6 +354,18 @@ inline float InlineRenameFieldRounding() {
|
||||
return 2.0f;
|
||||
}
|
||||
|
||||
inline ImVec4 InlineRenameFieldBackgroundColor() {
|
||||
return ImVec4(0.25f, 0.25f, 0.25f, 1.0f);
|
||||
}
|
||||
|
||||
inline ImVec4 InlineRenameFieldHoveredColor() {
|
||||
return InlineRenameFieldBackgroundColor();
|
||||
}
|
||||
|
||||
inline ImVec4 InlineRenameFieldActiveColor() {
|
||||
return InlineRenameFieldBackgroundColor();
|
||||
}
|
||||
|
||||
inline float InlineRenameFieldHeight() {
|
||||
return ImGui::GetFontSize() + InlineRenameFieldFramePadding().y * 2.0f;
|
||||
}
|
||||
|
||||
@@ -210,6 +210,9 @@ inline InlineRenameFieldResult DrawInlineRenameField(
|
||||
ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, InlineRenameFieldFramePadding());
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, InlineRenameFieldRounding());
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, InlineRenameFieldBackgroundColor());
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, InlineRenameFieldHoveredColor());
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, InlineRenameFieldActiveColor());
|
||||
ImGui::SetNextItemWidth(width);
|
||||
if (requestFocus) {
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
@@ -219,6 +222,7 @@ inline InlineRenameFieldResult DrawInlineRenameField(
|
||||
const bool active = ImGui::IsItemActive();
|
||||
const bool deactivated = ImGui::IsItemDeactivated();
|
||||
const bool cancelRequested = active && ImGui::IsKeyPressed(ImGuiKey_Escape);
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
return InlineRenameFieldResult{ submitted, cancelRequested, deactivated, active };
|
||||
|
||||
@@ -29,6 +29,65 @@ void DrawHierarchyTreePrefix(const XCEngine::Editor::UI::TreeNodePrefixContext&
|
||||
XCEngine::Editor::UI::AssetIconKind::GameObject);
|
||||
}
|
||||
|
||||
XCEngine::Editor::UI::TreeNodeDefinition BuildHierarchyNodeDefinition(
|
||||
XCEngine::Editor::IEditorContext& context,
|
||||
XCEngine::Components::GameObject* gameObject,
|
||||
XCEngine::Editor::UI::TargetedPopupState<XCEngine::Components::GameObject*>& itemContextMenu) {
|
||||
XCEngine::Editor::UI::TreeNodeDefinition nodeDefinition;
|
||||
nodeDefinition.options.selected = context.GetSelectionManager().IsSelected(gameObject->GetID());
|
||||
nodeDefinition.options.leaf = gameObject->GetChildCount() == 0;
|
||||
nodeDefinition.style = XCEngine::Editor::UI::HierarchyTreeStyle();
|
||||
nodeDefinition.prefix.width = XCEngine::Editor::UI::NavigationTreePrefixWidth();
|
||||
nodeDefinition.prefix.draw = DrawHierarchyTreePrefix;
|
||||
nodeDefinition.callbacks.onInteraction = [&context, &itemContextMenu, gameObject](const XCEngine::Editor::UI::TreeNodeResult& node) {
|
||||
if (node.clicked) {
|
||||
XCEngine::Editor::Actions::HandleHierarchySelectionClick(
|
||||
context,
|
||||
gameObject->GetID(),
|
||||
ImGui::GetIO().KeyCtrl);
|
||||
}
|
||||
|
||||
if (node.secondaryClicked) {
|
||||
XCEngine::Editor::Actions::HandleHierarchyItemContextRequest(
|
||||
context,
|
||||
gameObject,
|
||||
itemContextMenu);
|
||||
}
|
||||
};
|
||||
nodeDefinition.callbacks.onRenderExtras = [&context, gameObject]() {
|
||||
XCEngine::Editor::Actions::BeginHierarchyEntityDrag(gameObject);
|
||||
XCEngine::Editor::Actions::AcceptHierarchyEntityDrop(context, gameObject);
|
||||
};
|
||||
return nodeDefinition;
|
||||
}
|
||||
|
||||
void DrawHierarchyRenameFieldAtCurrentRow(
|
||||
XCEngine::Editor::UI::InlineTextEditState<uint64_t, 256>& renameState,
|
||||
const XCEngine::Editor::UI::TreeViewStyle& style) {
|
||||
const ImVec2 itemMin = ImGui::GetItemRectMin();
|
||||
const ImVec2 itemMax = ImGui::GetItemRectMax();
|
||||
const float arrowSlotWidth = ImGui::GetTreeNodeToLabelSpacing();
|
||||
const float prefixWidth = XCEngine::Editor::UI::NavigationTreePrefixWidth();
|
||||
const float prefixGap = XCEngine::Editor::UI::NavigationTreePrefixLabelGap();
|
||||
const float labelMinX =
|
||||
itemMin.x +
|
||||
arrowSlotWidth +
|
||||
style.prefixStartOffset +
|
||||
prefixWidth +
|
||||
prefixGap;
|
||||
const float renameWidth = (std::max)(0.0f, itemMax.x - labelMinX);
|
||||
const float renameY = itemMin.y +
|
||||
(std::max)(0.0f, (itemMax.y - itemMin.y - XCEngine::Editor::UI::InlineRenameFieldHeight()) * 0.5f);
|
||||
|
||||
XCEngine::Editor::UI::DrawInlineRenameFieldAt(
|
||||
"##Rename",
|
||||
ImVec2(labelMinX, renameY),
|
||||
renameState.Buffer(),
|
||||
renameState.BufferSize(),
|
||||
renameWidth,
|
||||
renameState.ConsumeFocusRequest());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -134,56 +193,37 @@ void HierarchyPanel::RenderEntity(::XCEngine::Components::GameObject* gameObject
|
||||
|
||||
ImGui::PushID(static_cast<int>(gameObject->GetID()));
|
||||
|
||||
if (m_renameState.IsEditing(gameObject->GetID())) {
|
||||
const UI::InlineRenameFieldResult renameField = UI::DrawInlineRenameField(
|
||||
"##Rename",
|
||||
m_renameState.Buffer(),
|
||||
m_renameState.BufferSize(),
|
||||
-1.0f,
|
||||
m_renameState.ConsumeFocusRequest());
|
||||
UI::TreeNodeDefinition nodeDefinition =
|
||||
BuildHierarchyNodeDefinition(*m_context, gameObject, m_itemContextMenu);
|
||||
const std::string persistenceKey = std::to_string(gameObject->GetUUID());
|
||||
nodeDefinition.persistenceKey = persistenceKey;
|
||||
const bool editing = m_renameState.IsEditing(gameObject->GetID());
|
||||
const UI::TreeNodeResult node = UI::DrawTreeNode(
|
||||
&m_treeState,
|
||||
(void*)gameObject->GetUUID(),
|
||||
editing ? "" : gameObject->GetName().c_str(),
|
||||
nodeDefinition);
|
||||
|
||||
if (renameField.cancelRequested) {
|
||||
if (editing) {
|
||||
DrawHierarchyRenameFieldAtCurrentRow(m_renameState, nodeDefinition.style);
|
||||
|
||||
const bool active = ImGui::IsItemActive();
|
||||
const bool deactivated = ImGui::IsItemDeactivated();
|
||||
const bool cancelRequested = active && ImGui::IsKeyPressed(ImGuiKey_Escape);
|
||||
if (cancelRequested) {
|
||||
CancelRename();
|
||||
} else if (renameField.submitted || renameField.deactivated) {
|
||||
} else if (deactivated || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter)) {
|
||||
CommitRename();
|
||||
}
|
||||
} else {
|
||||
UI::TreeNodeDefinition nodeDefinition;
|
||||
nodeDefinition.options.selected = m_context->GetSelectionManager().IsSelected(gameObject->GetID());
|
||||
nodeDefinition.options.leaf = gameObject->GetChildCount() == 0;
|
||||
const std::string persistenceKey = std::to_string(gameObject->GetUUID());
|
||||
nodeDefinition.persistenceKey = persistenceKey;
|
||||
nodeDefinition.style = UI::HierarchyTreeStyle();
|
||||
nodeDefinition.prefix.width = UI::NavigationTreePrefixWidth();
|
||||
nodeDefinition.prefix.draw = DrawHierarchyTreePrefix;
|
||||
nodeDefinition.callbacks.onInteraction = [this, gameObject](const UI::TreeNodeResult& node) {
|
||||
if (node.clicked) {
|
||||
Actions::HandleHierarchySelectionClick(*m_context, gameObject->GetID(), ImGui::GetIO().KeyCtrl);
|
||||
}
|
||||
|
||||
if (node.secondaryClicked) {
|
||||
Actions::HandleHierarchyItemContextRequest(*m_context, gameObject, m_itemContextMenu);
|
||||
}
|
||||
};
|
||||
nodeDefinition.callbacks.onRenderExtras = [this, gameObject]() {
|
||||
Actions::BeginHierarchyEntityDrag(gameObject);
|
||||
Actions::AcceptHierarchyEntityDrop(*m_context, gameObject);
|
||||
};
|
||||
|
||||
const UI::TreeNodeResult node = UI::DrawTreeNode(
|
||||
&m_treeState,
|
||||
(void*)gameObject->GetUUID(),
|
||||
gameObject->GetName().c_str(),
|
||||
nodeDefinition);
|
||||
|
||||
if (node.open) {
|
||||
for (size_t i = 0; i < gameObject->GetChildCount(); i++) {
|
||||
RenderEntity(gameObject->GetChild(i));
|
||||
}
|
||||
UI::EndTreeNode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (node.open) {
|
||||
for (size_t i = 0; i < gameObject->GetChildCount(); i++) {
|
||||
RenderEntity(gameObject->GetChild(i));
|
||||
}
|
||||
UI::EndTreeNode();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user