Unify panel search behavior and polish console UI
This commit is contained in:
@@ -8,10 +8,37 @@
|
||||
#include "Core/EditorEvents.h"
|
||||
#include "Core/EventBus.h"
|
||||
#include "UI/UI.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr float kHierarchyToolbarHeight = 26.0f;
|
||||
constexpr float kHierarchyToolbarPaddingY = 3.0f;
|
||||
constexpr float kHierarchySearchWidth = 220.0f;
|
||||
|
||||
bool HierarchyNodeMatchesSearch(
|
||||
XCEngine::Components::GameObject* gameObject,
|
||||
const XCEngine::Editor::UI::SearchQuery& searchQuery) {
|
||||
if (!gameObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (searchQuery.Matches(gameObject->GetName().c_str())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < gameObject->GetChildCount(); ++i) {
|
||||
if (HierarchyNodeMatchesSearch(gameObject->GetChild(i), searchQuery)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DrawHierarchyTreePrefix(const XCEngine::Editor::UI::TreeNodePrefixContext& context) {
|
||||
if (!context.drawList) {
|
||||
return;
|
||||
@@ -157,6 +184,33 @@ void HierarchyPanel::Render() {
|
||||
|
||||
Actions::ObserveFocusedActionRoute(*m_context, EditorActionRoute::Hierarchy);
|
||||
|
||||
{
|
||||
UI::PanelToolbarScope toolbar(
|
||||
"HierarchyToolbar",
|
||||
kHierarchyToolbarHeight,
|
||||
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse,
|
||||
true,
|
||||
ImVec2(UI::ToolbarPadding().x, kHierarchyToolbarPaddingY),
|
||||
UI::ToolbarItemSpacing(),
|
||||
UI::HierarchyInspectorPanelBackgroundColor());
|
||||
if (toolbar.IsOpen()) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.0f, 0.0f));
|
||||
if (ImGui::BeginTable("##HierarchyToolbarLayout", 2, ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_SizingStretchProp)) {
|
||||
ImGui::TableSetupColumn("##Spacer", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("##Search", ImGuiTableColumnFlags_WidthFixed, kHierarchySearchWidth);
|
||||
ImGui::TableNextRow();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
UI::ToolbarSearchField("##HierarchySearch", "Search", m_searchBuffer, sizeof(m_searchBuffer));
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
}
|
||||
|
||||
UI::PanelContentScope content("EntityList", UI::HierarchyPanelContentPadding());
|
||||
if (!content.IsOpen()) {
|
||||
ImGui::PopStyleColor(2);
|
||||
@@ -165,10 +219,18 @@ void HierarchyPanel::Render() {
|
||||
|
||||
auto& sceneManager = m_context->GetSceneManager();
|
||||
auto rootEntities = sceneManager.GetRootEntities();
|
||||
const UI::SearchQuery searchQuery(m_searchBuffer);
|
||||
size_t visibleEntityCount = 0;
|
||||
UI::ResetTreeLayout();
|
||||
|
||||
for (auto* gameObject : rootEntities) {
|
||||
RenderEntity(gameObject);
|
||||
if (RenderEntity(gameObject, searchQuery)) {
|
||||
++visibleEntityCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (!searchQuery.Empty() && visibleEntityCount == 0) {
|
||||
UI::DrawEmptyState("No matching entities", "Try a different search term");
|
||||
}
|
||||
|
||||
Actions::DrawHierarchyBackgroundInteraction(*m_context, m_renameState);
|
||||
@@ -179,7 +241,7 @@ void HierarchyPanel::Render() {
|
||||
Actions::TraceHierarchyPopup("Hierarchy background popup opened via background surface");
|
||||
s_backgroundContextOpen = true;
|
||||
}
|
||||
Actions::DrawHierarchyCreateActions(*m_context, nullptr);
|
||||
Actions::DrawHierarchyContextActions(*m_context, nullptr, true);
|
||||
UI::EndContextMenu();
|
||||
} else if (s_backgroundContextOpen) {
|
||||
Actions::TraceHierarchyPopup("Hierarchy background popup closed");
|
||||
@@ -189,18 +251,32 @@ void HierarchyPanel::Render() {
|
||||
ImGui::PopStyleColor(2);
|
||||
}
|
||||
|
||||
void HierarchyPanel::RenderEntity(::XCEngine::Components::GameObject* gameObject) {
|
||||
if (!gameObject) return;
|
||||
bool HierarchyPanel::RenderEntity(::XCEngine::Components::GameObject* gameObject, const UI::SearchQuery& searchQuery) {
|
||||
if (!gameObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool visibleInSearch = HierarchyNodeMatchesSearch(gameObject, searchQuery);
|
||||
if (!visibleInSearch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool searching = !searchQuery.Empty();
|
||||
|
||||
ImGui::PushID(static_cast<int>(gameObject->GetID()));
|
||||
|
||||
UI::TreeNodeDefinition nodeDefinition =
|
||||
BuildHierarchyNodeDefinition(*m_context, gameObject, m_itemContextMenu);
|
||||
const std::string persistenceKey = std::to_string(gameObject->GetUUID());
|
||||
nodeDefinition.persistenceKey = persistenceKey;
|
||||
const std::string persistenceKey = searching ? std::string() : std::to_string(gameObject->GetUUID());
|
||||
if (searching) {
|
||||
nodeDefinition.options.defaultOpen = gameObject->GetChildCount() > 0;
|
||||
nodeDefinition.persistenceKey = {};
|
||||
} else {
|
||||
nodeDefinition.persistenceKey = persistenceKey;
|
||||
}
|
||||
const bool editing = m_renameState.IsEditing(gameObject->GetID());
|
||||
const UI::TreeNodeResult node = UI::DrawTreeNode(
|
||||
&m_treeState,
|
||||
searching ? nullptr : &m_treeState,
|
||||
(void*)gameObject->GetUUID(),
|
||||
editing ? "" : gameObject->GetName().c_str(),
|
||||
nodeDefinition);
|
||||
@@ -220,12 +296,13 @@ void HierarchyPanel::RenderEntity(::XCEngine::Components::GameObject* gameObject
|
||||
|
||||
if (node.open) {
|
||||
for (size_t i = 0; i < gameObject->GetChildCount(); i++) {
|
||||
RenderEntity(gameObject->GetChild(i));
|
||||
RenderEntity(gameObject->GetChild(i), searchQuery);
|
||||
}
|
||||
UI::EndTreeNode();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
return true;
|
||||
}
|
||||
|
||||
void HierarchyPanel::BeginRename(::XCEngine::Components::GameObject* gameObject) {
|
||||
|
||||
Reference in New Issue
Block a user