diff --git a/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp b/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp index f025886..32be2fa 100644 --- a/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp +++ b/Source/MetaCoreEditor/Private/MetaCoreBuiltinEditorModule.cpp @@ -82,6 +82,7 @@ static std::array AssetFilterBuffer_{}; static std::filesystem::path PendingRenamePath_{}; static std::array RenameBuffer_{}; static std::array 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 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(pathSegments.size()) - 1; i >= 0; --i) { + if (i < static_cast(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 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);