Unify panel search behavior and polish console UI

This commit is contained in:
2026-04-01 16:40:54 +08:00
parent e03f17146a
commit 4e8ad9a706
11 changed files with 998 additions and 172 deletions

View File

@@ -1,15 +1,7 @@
#pragma once
#include "Application.h"
#include "Actions/ProjectActionRouter.h"
#include "UI/UI.h"
#include "Utils/ProjectFileUtils.h"
#include <algorithm>
#include <array>
#include <cctype>
#include <cstring>
#include <filesystem>
#include <initializer_list>
#include <string>
@@ -22,83 +14,35 @@ struct AssetReferenceInteraction {
bool clearRequested = false;
};
inline std::string ToProjectRelativeAssetPath(const std::string& assetPath) {
if (assetPath.empty()) {
return {};
}
const std::string& projectPath = Application::Get().GetEditorContext().GetProjectPath();
if (projectPath.empty()) {
return assetPath;
}
return ProjectFileUtils::MakeProjectRelativePath(projectPath, assetPath);
}
inline bool HasSupportedExtension(
const std::string& path,
std::initializer_list<const char*> supportedExtensions) {
std::string extension = std::filesystem::path(path).extension().string();
std::transform(extension.begin(), extension.end(), extension.begin(), [](unsigned char ch) {
return static_cast<char>(std::tolower(ch));
});
for (const char* supportedExtension : supportedExtensions) {
if (supportedExtension != nullptr && extension == supportedExtension) {
return true;
}
}
return false;
}
inline AssetReferenceInteraction DrawAssetReferenceProperty(
const char* label,
const std::string& currentPath,
const char* emptyHint,
std::initializer_list<const char*> supportedExtensions) {
AssetReferenceInteraction interaction;
const std::string popupTitle = std::string("Select ") + (label ? label : "Object");
UI::ReferencePickerOptions pickerOptions;
pickerOptions.popupTitle = popupTitle.c_str();
pickerOptions.emptyHint = emptyHint;
pickerOptions.searchHint = "Search";
pickerOptions.noAssetsText = "No compatible assets.";
pickerOptions.noSceneText = "No compatible scene objects.";
pickerOptions.assetsTabLabel = "Assets";
pickerOptions.sceneTabLabel = "Scene";
pickerOptions.showAssetsTab = true;
pickerOptions.showSceneTab = true;
pickerOptions.supportedAssetExtensions = supportedExtensions;
UI::DrawPropertyRow(label, UI::InspectorPropertyLayout(), [&](const UI::PropertyLayoutMetrics& layout) {
constexpr float kClearButtonWidth = 52.0f;
std::array<char, 512> buffer{};
if (!currentPath.empty()) {
strncpy_s(buffer.data(), buffer.size(), currentPath.c_str(), _TRUNCATE);
}
const float spacing = ImGui::GetStyle().ItemSpacing.x;
const float fieldWidth = (std::max)(layout.controlWidth - kClearButtonWidth - spacing, 1.0f);
ImGui::SetNextItemWidth(fieldWidth);
ImGui::InputTextWithHint(
"##AssetPath",
emptyHint,
buffer.data(),
buffer.size(),
ImGuiInputTextFlags_ReadOnly);
if (ImGui::IsItemHovered() && !currentPath.empty()) {
ImGui::SetTooltip("%s", currentPath.c_str());
}
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(
Actions::ProjectAssetPayloadType(),
ImGuiDragDropFlags_AcceptNoDrawDefaultRect)) {
if (payload->Data != nullptr) {
const std::string droppedPath(static_cast<const char*>(payload->Data));
if (HasSupportedExtension(droppedPath, supportedExtensions)) {
interaction.assignedPath = ToProjectRelativeAssetPath(droppedPath);
}
}
}
ImGui::EndDragDropTarget();
}
ImGui::SameLine(0.0f, spacing);
ImGui::BeginDisabled(currentPath.empty());
interaction.clearRequested = UI::InspectorActionButton("Clear", ImVec2(kClearButtonWidth, 0.0f));
ImGui::EndDisabled();
UI::AlignPropertyControlVertically(layout, ImGui::GetFrameHeight());
const UI::ReferencePickerInteraction pickerInteraction =
UI::DrawReferencePickerControl(
currentPath,
::XCEngine::Components::GameObject::INVALID_ID,
pickerOptions,
layout.controlWidth);
interaction.assignedPath = pickerInteraction.assignedAssetPath;
interaction.clearRequested = pickerInteraction.clearRequested;
return false;
});