feat: implement double-column Project panel with breadcrumbs, IconSize slider, folders-first sorting, list/grid auto-switching, and wrap-layout
This commit is contained in:
parent
d7590c53b6
commit
5b4095f049
@ -82,6 +82,7 @@ static std::array<char, 256> AssetFilterBuffer_{};
|
||||
static std::filesystem::path PendingRenamePath_{};
|
||||
static std::array<char, 256> RenameBuffer_{};
|
||||
static std::array<char, 256> NewFolderBuffer_{};
|
||||
static float IconSize_ = 64.0f;
|
||||
static HANDLE PlayerProcessHandle_ = NULL;
|
||||
static HANDLE PlayerStdoutRead_ = NULL;
|
||||
|
||||
@ -4573,132 +4574,241 @@ public:
|
||||
ImGui::NextColumn();
|
||||
|
||||
const std::filesystem::path selectedDirectory = editorContext.GetSelectedProjectDirectory();
|
||||
ImGui::TextDisabled("目录: %s", selectedDirectory.generic_string().c_str());
|
||||
ImGui::Separator();
|
||||
for (const auto& d : assetDatabaseService->GetDirectoriesUnder(selectedDirectory)) {
|
||||
const bool isSelected = selectedDirectory == d;
|
||||
if (isSelected) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.173F, 0.365F, 0.529F, 1.0F));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.173F, 0.365F, 0.529F, 1.0F));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.173F, 0.365F, 0.529F, 1.0F));
|
||||
|
||||
// 1. 绘制面包屑导航 (Breadcrumbs)
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4, 2));
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::TextDisabled("路径:");
|
||||
ImGui::SameLine();
|
||||
|
||||
std::vector<std::filesystem::path> pathSegments;
|
||||
{
|
||||
std::filesystem::path p = selectedDirectory;
|
||||
while (p != "Assets" && p != "Scenes" && p != "Ui" && p != "Runtime" && p.has_relative_path() && !p.empty()) {
|
||||
pathSegments.push_back(p);
|
||||
p = p.parent_path();
|
||||
}
|
||||
const bool clicked = MatchesAssetFilter(d.filename().string()) && ImGui::Selectable(("[Dir] " + d.filename().string()).c_str(), isSelected);
|
||||
if (isSelected) {
|
||||
ImGui::PopStyleColor(3);
|
||||
pathSegments.push_back(p);
|
||||
}
|
||||
|
||||
for (int i = static_cast<int>(pathSegments.size()) - 1; i >= 0; --i) {
|
||||
if (i < static_cast<int>(pathSegments.size()) - 1) {
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled(">");
|
||||
ImGui::SameLine();
|
||||
}
|
||||
if (clicked) {
|
||||
editorContext.SetSelectedProjectDirectory(d);
|
||||
std::string segName = pathSegments[i].filename().string();
|
||||
if (segName.empty()) {
|
||||
segName = pathSegments[i].string();
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem(nullptr, ImGuiPopupFlags_MouseButtonRight)) {
|
||||
if (ImGui::MenuItem("Reveal in Explorer")) {
|
||||
MetaCoreRevealInExplorer(assetDatabaseService->GetProjectDescriptor().RootPath / d);
|
||||
|
||||
if (pathSegments[i] == selectedDirectory) {
|
||||
ImGui::Text("%s", segName.c_str());
|
||||
} else {
|
||||
if (ImGui::SmallButton(segName.c_str())) {
|
||||
editorContext.SetSelectedProjectDirectory(pathSegments[i]);
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Rename...")) {
|
||||
PendingRenamePath_ = d;
|
||||
std::snprintf(RenameBuffer_.data(), RenameBuffer_.size(), "%s", d.filename().string().c_str());
|
||||
openRenamePopup = true;
|
||||
}
|
||||
if (ImGui::MenuItem("Delete")) {
|
||||
(void)assetDatabaseService->DeletePath(d);
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
const MetaCoreAssetGuid selectedAssetGuid = editorContext.GetSelectedAsset().Guid;
|
||||
|
||||
// 2. 绘制图标尺寸滑块
|
||||
ImGui::SameLine(ImGui::GetContentRegionMax().x - 120.0f);
|
||||
ImGui::PushItemWidth(100.0f);
|
||||
ImGui::SliderFloat("##IconSize", &IconSize_, 16.0f, 128.0f, "");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("图标大小: %.0f px", IconSize_);
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
// 3. 收集并过滤当前目录下的子项 (文件夹在前,文件在后)
|
||||
struct ProjectItem {
|
||||
bool IsDirectory = false;
|
||||
std::filesystem::path Path{};
|
||||
MetaCoreAssetGuid Guid{};
|
||||
std::string Type{};
|
||||
MetaCoreAssetStorageKind StorageKind = MetaCoreAssetStorageKind::SourcePackage;
|
||||
};
|
||||
|
||||
std::vector<ProjectItem> items;
|
||||
|
||||
for (const auto& d : assetDatabaseService->GetDirectoriesUnder(selectedDirectory)) {
|
||||
if (MatchesAssetFilter(d.filename().string())) {
|
||||
ProjectItem item{};
|
||||
item.IsDirectory = true;
|
||||
item.Path = d;
|
||||
items.push_back(item);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& a : assetDatabaseService->GetAssetsUnder(selectedDirectory)) {
|
||||
if (!MatchesAssetFilter(a.RelativePath.filename().string()) && !MatchesAssetFilter(a.Type)) continue;
|
||||
const std::string label = a.RelativePath.filename().string() + " [" + a.Type + "]";
|
||||
const bool selected = selectedAssetGuid == a.Guid;
|
||||
if (selected) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.173F, 0.365F, 0.529F, 1.0F));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.173F, 0.365F, 0.529F, 1.0F));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.173F, 0.365F, 0.529F, 1.0F));
|
||||
}
|
||||
const bool clicked = ImGui::Selectable(label.c_str(), selected);
|
||||
if (selected) {
|
||||
ImGui::PopStyleColor(3);
|
||||
}
|
||||
if (clicked) {
|
||||
editorContext.SelectAsset(MetaCoreSelectedAssetState{
|
||||
a.Guid,
|
||||
a.RelativePath,
|
||||
a.Type,
|
||||
a.StorageKind
|
||||
});
|
||||
editorContext.ClearSelectedAssetSubId();
|
||||
editorContext.ClearSelection();
|
||||
if (ImGui::IsMouseDoubleClicked(0)) {
|
||||
if (a.Type == "scene" && scenePersistenceService) (void)scenePersistenceService->LoadScene(editorContext, a.RelativePath);
|
||||
else if (a.Type == "model") (void)MetaCoreInstantiateModelAsset(editorContext, a.Guid, std::nullopt);
|
||||
else if (a.Type == "prefab") (void)MetaCoreInstantiatePrefab(editorContext, a.Guid, std::nullopt);
|
||||
ProjectItem item{};
|
||||
item.IsDirectory = false;
|
||||
item.Path = a.RelativePath;
|
||||
item.Guid = a.Guid;
|
||||
item.Type = a.Type;
|
||||
item.StorageKind = a.StorageKind;
|
||||
items.push_back(item);
|
||||
}
|
||||
|
||||
// 4. 渲染视图项
|
||||
if (IconSize_ <= 32.0f) {
|
||||
// 列表视图模式 (List View)
|
||||
for (const auto& item : items) {
|
||||
std::string label;
|
||||
ImVec4 iconColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
const char* iconStr = "📄";
|
||||
|
||||
if (item.IsDirectory) {
|
||||
iconStr = "📁";
|
||||
iconColor = ImVec4(0.95f, 0.75f, 0.25f, 1.0f);
|
||||
label = std::string(iconStr) + " " + item.Path.filename().string();
|
||||
} else {
|
||||
if (item.Type == "material") {
|
||||
iconStr = "🔮";
|
||||
iconColor = ImVec4(0.65f, 0.45f, 0.95f, 1.0f);
|
||||
} else if (item.Type == "model") {
|
||||
iconStr = "📦";
|
||||
iconColor = ImVec4(0.25f, 0.85f, 0.45f, 1.0f);
|
||||
} else if (item.Type == "scene") {
|
||||
iconStr = "🎬";
|
||||
iconColor = ImVec4(0.95f, 0.35f, 0.35f, 1.0f);
|
||||
} else if (item.Type == "ui_document") {
|
||||
iconStr = "📄";
|
||||
iconColor = ImVec4(0.25f, 0.75f, 0.95f, 1.0f);
|
||||
}
|
||||
label = std::string(iconStr) + " " + item.Path.filename().string() + " [" + item.Type + "]";
|
||||
}
|
||||
}
|
||||
MetaCoreBeginProjectAssetDragDropSource(a);
|
||||
if (ImGui::BeginPopupContextItem(nullptr, ImGuiPopupFlags_MouseButtonRight)) {
|
||||
if (ImGui::MenuItem("Open")) {
|
||||
if (a.Type == "scene" && scenePersistenceService) {
|
||||
(void)scenePersistenceService->LoadScene(editorContext, a.RelativePath);
|
||||
} else if (a.Type == "model") {
|
||||
(void)MetaCoreInstantiateModelAsset(editorContext, a.Guid, std::nullopt);
|
||||
} else if (a.Type == "prefab") {
|
||||
(void)MetaCoreInstantiatePrefab(editorContext, a.Guid, std::nullopt);
|
||||
|
||||
bool isSelected = false;
|
||||
if (item.IsDirectory) {
|
||||
isSelected = (selectedDirectory == item.Path);
|
||||
} else {
|
||||
isSelected = (editorContext.GetSelectedAsset().Guid == item.Guid);
|
||||
}
|
||||
|
||||
if (isSelected) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.173F, 0.365F, 0.529F, 1.0F));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.173F, 0.365F, 0.529F, 1.0F));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.173F, 0.365F, 0.529F, 1.0F));
|
||||
}
|
||||
|
||||
ImGui::PushID(item.IsDirectory ? item.Path.string().c_str() : item.Guid.ToString().c_str());
|
||||
const bool clicked = ImGui::Selectable(label.c_str(), isSelected);
|
||||
if (isSelected) {
|
||||
ImGui::PopStyleColor(3);
|
||||
}
|
||||
|
||||
if (clicked) {
|
||||
if (item.IsDirectory) {
|
||||
editorContext.SetSelectedProjectDirectory(item.Path);
|
||||
} else {
|
||||
editorContext.SelectAsset(MetaCoreSelectedAssetState{
|
||||
a.Guid,
|
||||
a.RelativePath,
|
||||
a.Type,
|
||||
a.StorageKind
|
||||
item.Guid,
|
||||
item.Path,
|
||||
item.Type,
|
||||
item.StorageKind
|
||||
});
|
||||
editorContext.ClearSelectedAssetSubId();
|
||||
editorContext.ClearSelection();
|
||||
|
||||
if (ImGui::IsMouseDoubleClicked(0)) {
|
||||
if (item.Type == "scene" && scenePersistenceService) (void)scenePersistenceService->LoadScene(editorContext, item.Path);
|
||||
else if (item.Type == "model") (void)MetaCoreInstantiateModelAsset(editorContext, item.Guid, std::nullopt);
|
||||
else if (item.Type == "prefab") (void)MetaCoreInstantiatePrefab(editorContext, item.Guid, std::nullopt);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ImGui::MenuItem("Reveal in Explorer")) {
|
||||
MetaCoreRevealInExplorer(assetDatabaseService->GetProjectDescriptor().RootPath / a.RelativePath);
|
||||
}
|
||||
if (ImGui::MenuItem("Copy GUID")) {
|
||||
const std::string guidText = a.Guid.ToString();
|
||||
ImGui::SetClipboardText(guidText.c_str());
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Reimport", nullptr, false, !a.SourcePath.empty())) {
|
||||
MetaCoreReimportProjectAsset(editorContext, a.Guid);
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Rename...")) {
|
||||
PendingRenamePath_ = a.RelativePath;
|
||||
std::snprintf(RenameBuffer_.data(), RenameBuffer_.size(), "%s", a.RelativePath.filename().string().c_str());
|
||||
openRenamePopup = true;
|
||||
}
|
||||
if (ImGui::MenuItem("Delete")) {
|
||||
(void)assetDatabaseService->DeletePath(a.RelativePath);
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (selected && a.Type == "model") {
|
||||
const auto modelDocument = MetaCoreLoadModelAssetDocument(editorContext, a);
|
||||
if (modelDocument.has_value()) {
|
||||
if (!item.IsDirectory) {
|
||||
MetaCoreAssetRecord a{};
|
||||
a.Guid = item.Guid;
|
||||
a.RelativePath = item.Path;
|
||||
a.Type = item.Type;
|
||||
a.StorageKind = item.StorageKind;
|
||||
MetaCoreBeginProjectAssetDragDropSource(a);
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupContextItem(nullptr, ImGuiPopupFlags_MouseButtonRight)) {
|
||||
if (item.IsDirectory) {
|
||||
if (ImGui::MenuItem("Reveal in Explorer")) {
|
||||
MetaCoreRevealInExplorer(assetDatabaseService->GetProjectDescriptor().RootPath / item.Path);
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Rename...")) {
|
||||
PendingRenamePath_ = item.Path;
|
||||
std::snprintf(RenameBuffer_.data(), RenameBuffer_.size(), "%s", item.Path.filename().string().c_str());
|
||||
openRenamePopup = true;
|
||||
}
|
||||
if (ImGui::MenuItem("Delete")) {
|
||||
(void)assetDatabaseService->DeletePath(item.Path);
|
||||
}
|
||||
} else {
|
||||
if (ImGui::MenuItem("Open")) {
|
||||
if (item.Type == "scene" && scenePersistenceService) {
|
||||
(void)scenePersistenceService->LoadScene(editorContext, item.Path);
|
||||
} else if (item.Type == "model") {
|
||||
(void)MetaCoreInstantiateModelAsset(editorContext, item.Guid, std::nullopt);
|
||||
} else if (item.Type == "prefab") {
|
||||
(void)MetaCoreInstantiatePrefab(editorContext, item.Guid, std::nullopt);
|
||||
} else {
|
||||
editorContext.SelectAsset(MetaCoreSelectedAssetState{
|
||||
item.Guid,
|
||||
item.Path,
|
||||
item.Type,
|
||||
item.StorageKind
|
||||
});
|
||||
editorContext.ClearSelectedAssetSubId();
|
||||
editorContext.ClearSelection();
|
||||
}
|
||||
}
|
||||
if (ImGui::MenuItem("Reveal in Explorer")) {
|
||||
MetaCoreRevealInExplorer(assetDatabaseService->GetProjectDescriptor().RootPath / item.Path);
|
||||
}
|
||||
if (ImGui::MenuItem("Copy GUID")) {
|
||||
const std::string guidText = item.Guid.ToString();
|
||||
ImGui::SetClipboardText(guidText.c_str());
|
||||
}
|
||||
ImGui::Separator();
|
||||
const auto fullRecord = assetDatabaseService->FindAssetByGuid(item.Guid);
|
||||
const bool canReimport = fullRecord.has_value() && !fullRecord->SourcePath.empty();
|
||||
if (ImGui::MenuItem("Reimport", nullptr, false, canReimport)) {
|
||||
MetaCoreReimportProjectAsset(editorContext, item.Guid);
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Rename...")) {
|
||||
PendingRenamePath_ = item.Path;
|
||||
std::snprintf(RenameBuffer_.data(), RenameBuffer_.size(), "%s", item.Path.filename().string().c_str());
|
||||
openRenamePopup = true;
|
||||
}
|
||||
if (ImGui::MenuItem("Delete")) {
|
||||
(void)assetDatabaseService->DeletePath(item.Path);
|
||||
}
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (!item.IsDirectory && isSelected && item.Type == "model") {
|
||||
MetaCoreAssetRecord a{};
|
||||
a.Guid = item.Guid;
|
||||
a.RelativePath = item.Path;
|
||||
a.Type = item.Type;
|
||||
a.StorageKind = item.StorageKind;
|
||||
const auto modelDocument = MetaCoreLoadModelAssetDocument(editorContext, a);
|
||||
if (modelDocument.has_value()) {
|
||||
ImGui::Indent(18.0F);
|
||||
for (const auto& generatedEntry : BuildGeneratedResourceListEntries(*modelDocument)) {
|
||||
if (!MatchesGeneratedResourceKindFilter(generatedEntry.Kind)) {
|
||||
continue;
|
||||
}
|
||||
if (!MatchesGeneratedResourceKindFilter(generatedEntry.Kind)) continue;
|
||||
const std::string filterLabel = generatedEntry.Name + " " + generatedEntry.SecondaryText;
|
||||
if (!MatchesGeneratedResourceFilter(filterLabel)) {
|
||||
continue;
|
||||
}
|
||||
if (!MatchesGeneratedResourceFilter(filterLabel)) continue;
|
||||
|
||||
const std::string subId = MetaCoreBuildGeneratedResourceSubId(
|
||||
generatedEntry.Kind,
|
||||
generatedEntry.AssetGuid
|
||||
);
|
||||
const bool generatedSelected =
|
||||
editorContext.GetSelectedAsset().Guid == a.Guid &&
|
||||
editorContext.GetSelectedAssetSubId() == subId;
|
||||
const std::string generatedLabel =
|
||||
"↳ " + generatedEntry.Name + " [" + generatedEntry.SecondaryText + "]";
|
||||
const std::string subId = MetaCoreBuildGeneratedResourceSubId(generatedEntry.Kind, generatedEntry.AssetGuid);
|
||||
const bool generatedSelected = editorContext.GetSelectedAsset().Guid == a.Guid && editorContext.GetSelectedAssetSubId() == subId;
|
||||
const std::string generatedLabel = "↳ " + generatedEntry.Name + " [" + generatedEntry.SecondaryText + "]";
|
||||
if (generatedSelected) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.173F, 0.365F, 0.529F, 1.0F));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.173F, 0.365F, 0.529F, 1.0F));
|
||||
@ -4720,8 +4830,201 @@ public:
|
||||
}
|
||||
}
|
||||
ImGui::Unindent(18.0F);
|
||||
}
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
} else {
|
||||
// 网格卡片视图模式 (Grid View)
|
||||
const float windowVisibleX2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
|
||||
const ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8.0f, 8.0f));
|
||||
|
||||
for (const auto& item : items) {
|
||||
std::string filename = item.Path.filename().string();
|
||||
|
||||
bool isSelected = false;
|
||||
if (item.IsDirectory) {
|
||||
isSelected = (selectedDirectory == item.Path);
|
||||
} else {
|
||||
isSelected = (editorContext.GetSelectedAsset().Guid == item.Guid);
|
||||
}
|
||||
|
||||
ImGui::PushID(item.IsDirectory ? item.Path.string().c_str() : item.Guid.ToString().c_str());
|
||||
|
||||
const ImVec2 cardSize(IconSize_ + 16.0f, IconSize_ + 36.0f);
|
||||
ImGui::BeginGroup();
|
||||
|
||||
const ImVec2 startPos = ImGui::GetCursorPos();
|
||||
|
||||
if (isSelected) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.173F, 0.365F, 0.529F, 0.40F));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.173F, 0.365F, 0.529F, 0.60F));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.173F, 0.365F, 0.529F, 0.80F));
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(1.0f, 1.0f, 1.0f, 0.08f));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(1.0f, 1.0f, 1.0f, 0.12f));
|
||||
}
|
||||
|
||||
const bool clicked = ImGui::Selectable("##card", isSelected, 0, cardSize);
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
const ImVec2 currentPos = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::SetCursorPos(startPos);
|
||||
ImGui::SetCursorPosY(startPos.y + 6.0f);
|
||||
|
||||
ImVec4 iconColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
const char* iconStr = "📄";
|
||||
if (item.IsDirectory) {
|
||||
iconStr = "📁";
|
||||
iconColor = ImVec4(0.95f, 0.75f, 0.25f, 1.0f);
|
||||
} else if (item.Type == "material") {
|
||||
iconStr = "🔮";
|
||||
iconColor = ImVec4(0.65f, 0.45f, 0.95f, 1.0f);
|
||||
} else if (item.Type == "model") {
|
||||
iconStr = "📦";
|
||||
iconColor = ImVec4(0.25f, 0.85f, 0.45f, 1.0f);
|
||||
} else if (item.Type == "scene") {
|
||||
iconStr = "🎬";
|
||||
iconColor = ImVec4(0.95f, 0.35f, 0.35f, 1.0f);
|
||||
} else if (item.Type == "ui_document") {
|
||||
iconStr = "📄";
|
||||
iconColor = ImVec4(0.25f, 0.75f, 0.95f, 1.0f);
|
||||
}
|
||||
|
||||
float scaleFactor = IconSize_ / 32.0f;
|
||||
if (scaleFactor < 1.0f) scaleFactor = 1.0f;
|
||||
if (scaleFactor > 3.0f) scaleFactor = 3.0f;
|
||||
|
||||
ImGui::SetWindowFontScale(scaleFactor);
|
||||
const float textWidth = ImGui::CalcTextSize(iconStr).x;
|
||||
ImGui::SetCursorPosX(startPos.x + (cardSize.x - textWidth) * 0.5f);
|
||||
ImGui::TextColored(iconColor, "%s", iconStr);
|
||||
ImGui::SetWindowFontScale(1.0f);
|
||||
|
||||
ImGui::SetCursorPosY(startPos.y + IconSize_ + 8.0f);
|
||||
std::string displayName = filename;
|
||||
if (ImGui::CalcTextSize(displayName.c_str()).x > cardSize.x - 4.0f) {
|
||||
while (!displayName.empty() && ImGui::CalcTextSize((displayName + "...").c_str()).x > cardSize.x - 4.0f) {
|
||||
displayName.pop_back();
|
||||
}
|
||||
displayName += "...";
|
||||
}
|
||||
const float nameWidth = ImGui::CalcTextSize(displayName.c_str()).x;
|
||||
ImGui::SetCursorPosX(startPos.x + (cardSize.x - nameWidth) * 0.5f);
|
||||
ImGui::TextUnformatted(displayName.c_str());
|
||||
|
||||
ImGui::SetCursorPos(currentPos);
|
||||
ImGui::EndGroup();
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s\n类型: %s", item.Path.string().c_str(), item.IsDirectory ? "Folder" : item.Type.c_str());
|
||||
}
|
||||
|
||||
if (clicked) {
|
||||
if (item.IsDirectory) {
|
||||
if (ImGui::IsMouseDoubleClicked(0)) {
|
||||
editorContext.SetSelectedProjectDirectory(item.Path);
|
||||
}
|
||||
} else {
|
||||
editorContext.SelectAsset(MetaCoreSelectedAssetState{
|
||||
item.Guid,
|
||||
item.Path,
|
||||
item.Type,
|
||||
item.StorageKind
|
||||
});
|
||||
editorContext.ClearSelectedAssetSubId();
|
||||
editorContext.ClearSelection();
|
||||
|
||||
if (ImGui::IsMouseDoubleClicked(0)) {
|
||||
if (item.Type == "scene" && scenePersistenceService) (void)scenePersistenceService->LoadScene(editorContext, item.Path);
|
||||
else if (item.Type == "model") (void)MetaCoreInstantiateModelAsset(editorContext, item.Guid, std::nullopt);
|
||||
else if (item.Type == "prefab") (void)MetaCoreInstantiatePrefab(editorContext, item.Guid, std::nullopt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!item.IsDirectory) {
|
||||
MetaCoreAssetRecord a{};
|
||||
a.Guid = item.Guid;
|
||||
a.RelativePath = item.Path;
|
||||
a.Type = item.Type;
|
||||
a.StorageKind = item.StorageKind;
|
||||
MetaCoreBeginProjectAssetDragDropSource(a);
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupContextItem(nullptr, ImGuiPopupFlags_MouseButtonRight)) {
|
||||
if (item.IsDirectory) {
|
||||
if (ImGui::MenuItem("Reveal in Explorer")) {
|
||||
MetaCoreRevealInExplorer(assetDatabaseService->GetProjectDescriptor().RootPath / item.Path);
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Rename...")) {
|
||||
PendingRenamePath_ = item.Path;
|
||||
std::snprintf(RenameBuffer_.data(), RenameBuffer_.size(), "%s", item.Path.filename().string().c_str());
|
||||
openRenamePopup = true;
|
||||
}
|
||||
if (ImGui::MenuItem("Delete")) {
|
||||
(void)assetDatabaseService->DeletePath(item.Path);
|
||||
}
|
||||
} else {
|
||||
if (ImGui::MenuItem("Open")) {
|
||||
if (item.Type == "scene" && scenePersistenceService) {
|
||||
(void)scenePersistenceService->LoadScene(editorContext, item.Path);
|
||||
} else if (item.Type == "model") {
|
||||
(void)MetaCoreInstantiateModelAsset(editorContext, item.Guid, std::nullopt);
|
||||
} else if (item.Type == "prefab") {
|
||||
(void)MetaCoreInstantiatePrefab(editorContext, item.Guid, std::nullopt);
|
||||
} else {
|
||||
editorContext.SelectAsset(MetaCoreSelectedAssetState{
|
||||
item.Guid,
|
||||
item.Path,
|
||||
item.Type,
|
||||
item.StorageKind
|
||||
});
|
||||
editorContext.ClearSelectedAssetSubId();
|
||||
editorContext.ClearSelection();
|
||||
}
|
||||
}
|
||||
if (ImGui::MenuItem("Reveal in Explorer")) {
|
||||
MetaCoreRevealInExplorer(assetDatabaseService->GetProjectDescriptor().RootPath / item.Path);
|
||||
}
|
||||
if (ImGui::MenuItem("Copy GUID")) {
|
||||
const std::string guidText = item.Guid.ToString();
|
||||
ImGui::SetClipboardText(guidText.c_str());
|
||||
}
|
||||
ImGui::Separator();
|
||||
const auto fullRecord = assetDatabaseService->FindAssetByGuid(item.Guid);
|
||||
const bool canReimport = fullRecord.has_value() && !fullRecord->SourcePath.empty();
|
||||
if (ImGui::MenuItem("Reimport", nullptr, false, canReimport)) {
|
||||
MetaCoreReimportProjectAsset(editorContext, item.Guid);
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Rename...")) {
|
||||
PendingRenamePath_ = item.Path;
|
||||
std::snprintf(RenameBuffer_.data(), RenameBuffer_.size(), "%s", item.Path.filename().string().c_str());
|
||||
openRenamePopup = true;
|
||||
}
|
||||
if (ImGui::MenuItem("Delete")) {
|
||||
(void)assetDatabaseService->DeletePath(item.Path);
|
||||
}
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
const float lastButtonX2 = ImGui::GetItemRectMax().x;
|
||||
const float nextButtonX2 = lastButtonX2 + cardSize.x + style.ItemSpacing.x;
|
||||
if (nextButtonX2 < windowVisibleX2) {
|
||||
ImGui::SameLine();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
ImGui::Columns(1);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user