#pragma once #include "Application.h" #include "Actions/ProjectActionRouter.h" #include "UI/UI.h" #include "Utils/ProjectFileUtils.h" #include #include #include #include #include #include #include namespace XCEngine { namespace Editor { namespace ComponentEditorAssetUI { struct AssetReferenceInteraction { std::string assignedPath; 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 supportedExtensions) { std::string extension = std::filesystem::path(path).extension().string(); std::transform(extension.begin(), extension.end(), extension.begin(), [](unsigned char ch) { return static_cast(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 supportedExtensions) { AssetReferenceInteraction interaction; UI::DrawPropertyRow(label, UI::InspectorPropertyLayout(), [&](const UI::PropertyLayoutMetrics& layout) { constexpr float kClearButtonWidth = 52.0f; std::array 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(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(); return false; }); return interaction; } } // namespace ComponentEditorAssetUI } // namespace Editor } // namespace XCEngine