112 lines
3.5 KiB
C
112 lines
3.5 KiB
C
|
|
#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>
|
||
|
|
|
||
|
|
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<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;
|
||
|
|
|
||
|
|
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();
|
||
|
|
|
||
|
|
return false;
|
||
|
|
});
|
||
|
|
|
||
|
|
return interaction;
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace ComponentEditorAssetUI
|
||
|
|
} // namespace Editor
|
||
|
|
} // namespace XCEngine
|