chore: sync workspace state

This commit is contained in:
2026-03-29 01:36:53 +08:00
parent eb5de3e3d4
commit e5cb79f3ce
4935 changed files with 35593 additions and 360696 deletions

View File

@@ -33,6 +33,49 @@ void DrawProjectFolderTreePrefix(const UI::TreeNodePrefixContext& context) {
UI::AssetIconKind::Folder);
}
UI::AssetIconKind ResolveProjectAssetIconKind(const AssetItemPtr& item) {
if (!item) {
return UI::AssetIconKind::File;
}
if (item->isFolder) {
return UI::AssetIconKind::Folder;
}
if (item->type == "Scene") {
return UI::AssetIconKind::Scene;
}
return UI::AssetIconKind::File;
}
std::string GetProjectAssetDisplayName(const AssetItemPtr& item) {
if (!item) {
return {};
}
if (item->isFolder) {
return item->name;
}
const size_t extensionPos = item->name.find_last_of('.');
if (extensionPos == std::string::npos || extensionPos == 0) {
return item->name;
}
return item->name.substr(0, extensionPos);
}
UI::AssetTileOptions MakeProjectAssetTileOptions() {
UI::AssetTileOptions options;
options.drawIdleFrame = false;
options.drawSelectionBorder = false;
options.iconOffset = UI::ProjectAssetTileIconOffset();
options.iconSize = UI::ProjectAssetTileIconSize();
return options;
}
} // namespace
ProjectPanel::ProjectPanel() : Panel("Project") {
@@ -42,6 +85,97 @@ void ProjectPanel::Initialize(const std::string& projectPath) {
m_context->GetProjectManager().Initialize(projectPath);
}
void ProjectPanel::BeginAssetDragDropFrame() {
m_assetDragDropState.Reset();
if (const char* draggedPath = Actions::GetDraggedProjectAssetPath()) {
m_assetDragDropState.dragging = true;
m_assetDragDropState.sourcePath = draggedPath;
}
}
void ProjectPanel::RegisterFolderDropTarget(IProjectManager& manager, const AssetItemPtr& folder) {
if (!m_assetDragDropState.dragging || !folder || !folder->isFolder || !ImGui::BeginDragDropTarget()) {
return;
}
const ImGuiPayload* payload = ImGui::GetDragDropPayload();
if (!payload || !payload->IsDataType(Actions::ProjectAssetPayloadType())) {
ImGui::EndDragDropTarget();
return;
}
m_assetDragDropState.hoveredTarget = true;
const bool canDrop = Commands::CanMoveAssetToFolder(manager, m_assetDragDropState.sourcePath, folder);
if (canDrop) {
m_assetDragDropState.hoveredValidTarget = true;
if (const ImGuiPayload* accepted = ImGui::AcceptDragDropPayload(
Actions::ProjectAssetPayloadType(),
ImGuiDragDropFlags_AcceptNoDrawDefaultRect))
{
if (accepted->Delivery) {
m_assetDragDropState.deliveredSourcePath = m_assetDragDropState.sourcePath;
m_assetDragDropState.deliveredTarget = folder;
}
}
}
ImGui::EndDragDropTarget();
}
void ProjectPanel::FinalizeAssetDragDrop(IProjectManager& manager) {
if (m_assetDragDropState.dragging) {
ImGui::SetMouseCursor(
m_assetDragDropState.hoveredValidTarget ? ImGuiMouseCursor_Arrow : ImGuiMouseCursor_NotAllowed);
}
if (!m_assetDragDropState.deliveredSourcePath.empty() && m_assetDragDropState.deliveredTarget) {
Commands::MoveAssetToFolder(
manager,
m_assetDragDropState.deliveredSourcePath,
m_assetDragDropState.deliveredTarget);
}
}
void ProjectPanel::BeginRename(const AssetItemPtr& item) {
if (!item) {
CancelRename();
return;
}
m_renameState.Begin(item->fullPath, GetProjectAssetDisplayName(item).c_str());
}
bool ProjectPanel::CommitRename(IProjectManager& manager) {
if (!m_renameState.IsActive()) {
return false;
}
const std::string sourcePath = m_renameState.Item();
std::string currentDisplayName;
for (const auto& item : manager.GetCurrentItems()) {
if (item && item->fullPath == sourcePath) {
currentDisplayName = GetProjectAssetDisplayName(item);
break;
}
}
if (!currentDisplayName.empty() && currentDisplayName == m_renameState.Buffer()) {
CancelRename();
return true;
}
if (!Commands::RenameAsset(manager, sourcePath, m_renameState.Buffer())) {
return false;
}
CancelRename();
return true;
}
void ProjectPanel::CancelRename() {
m_renameState.Cancel();
}
void ProjectPanel::Render() {
UI::PanelWindowScope panel(m_name.c_str());
if (!panel.IsOpen()) {
@@ -51,6 +185,7 @@ void ProjectPanel::Render() {
Actions::ObserveFocusedActionRoute(*m_context, EditorActionRoute::Project);
auto& manager = m_context->GetProjectManager();
BeginAssetDragDropFrame();
RenderToolbar();
ImGui::PushStyleColor(ImGuiCol_ChildBg, UI::ProjectBrowserSurfaceColor());
@@ -78,7 +213,7 @@ void ProjectPanel::Render() {
ImGui::SameLine(0.0f, 0.0f);
RenderBrowserPane(manager);
Actions::DrawProjectCreateFolderDialog(*m_context, m_createFolderDialog);
FinalizeAssetDragDrop(manager);
ImGui::PopStyleColor();
}
@@ -174,6 +309,8 @@ void ProjectPanel::RenderFolderTreeNode(
folder->name.c_str(),
nodeDefinition);
RegisterFolderDropTarget(manager, folder);
if (node.open) {
for (const auto& child : folder->children) {
if (!child || !child->isFolder) {
@@ -199,9 +336,12 @@ void ProjectPanel::RenderBrowserPane(IProjectManager& manager) {
std::vector<AssetItemPtr> visibleItems;
const auto& items = manager.GetCurrentItems();
const std::string search = m_searchBuffer;
if (m_renameState.IsActive() && manager.FindCurrentItemIndex(m_renameState.Item()) < 0) {
CancelRename();
}
visibleItems.reserve(items.size());
for (const auto& item : items) {
if (MatchesSearch(item, search)) {
if ((m_renameState.IsActive() && item && item->fullPath == m_renameState.Item()) || MatchesSearch(item, search)) {
visibleItems.push_back(item);
}
}
@@ -231,9 +371,6 @@ void ProjectPanel::RenderBrowserPane(IProjectManager& manager) {
AssetItemPtr pendingSelection;
AssetItemPtr pendingContextTarget;
AssetItemPtr pendingOpenTarget;
AssetItemPtr pendingMoveTarget;
std::string pendingMoveSourcePath;
const std::string selectedItemPath = manager.GetSelectedItemPath();
for (int visibleIndex = 0; visibleIndex < static_cast<int>(visibleItems.size()); ++visibleIndex) {
if (visibleIndex > 0 && visibleIndex % columns != 0) {
@@ -248,11 +385,6 @@ void ProjectPanel::RenderBrowserPane(IProjectManager& manager) {
if (interaction.contextRequested) {
pendingContextTarget = item;
}
if (!interaction.droppedSourcePath.empty()) {
pendingMoveSourcePath = interaction.droppedSourcePath;
pendingMoveTarget = item;
break;
}
if (interaction.openRequested) {
pendingOpenTarget = item;
break;
@@ -265,22 +397,23 @@ void ProjectPanel::RenderBrowserPane(IProjectManager& manager) {
"No assets match the current search");
}
Actions::HandleProjectBackgroundPrimaryClick(manager);
Actions::HandleProjectBackgroundPrimaryClick(manager, m_renameState);
if (pendingSelection) {
manager.SetSelectedItem(pendingSelection);
}
if (pendingContextTarget) {
Actions::HandleProjectItemContextRequest(manager, pendingContextTarget, m_itemContextMenu);
}
if (!pendingMoveSourcePath.empty() && pendingMoveTarget) {
Commands::MoveAssetToFolder(manager, pendingMoveSourcePath, pendingMoveTarget);
}
if (pendingOpenTarget) {
Actions::OpenProjectAsset(*m_context, pendingOpenTarget);
}
Actions::DrawProjectItemContextPopup(*m_context, m_itemContextMenu);
Actions::RequestProjectEmptyContextPopup(m_emptyContextMenu);
Actions::DrawProjectEmptyContextPopup(m_emptyContextMenu, m_createFolderDialog);
Actions::DrawProjectEmptyContextPopup(m_emptyContextMenu, [&]() {
if (AssetItemPtr createdFolder = Commands::CreateFolder(manager, "New Folder")) {
BeginRename(createdFolder);
}
});
ImGui::EndChild();
ImGui::EndChild();
@@ -305,7 +438,7 @@ void ProjectPanel::RenderBrowserHeader(IProjectManager& manager) {
const float startY = ImGui::GetCursorPosY();
const float availableHeight = ImGui::GetContentRegionAvail().y;
if (availableHeight > rowHeight) {
ImGui::SetCursorPosY(startY + (availableHeight - rowHeight) * 0.5f);
ImGui::SetCursorPosY(startY + (availableHeight - rowHeight) * 0.5f - 1.0f);
}
UI::DrawToolbarBreadcrumbs(
@@ -326,40 +459,65 @@ ProjectPanel::AssetItemInteraction ProjectPanel::RenderAssetItem(const AssetItem
AssetItemInteraction interaction;
ImGui::PushID(item ? item->fullPath.c_str() : "ProjectItem");
const bool isDraggingThisItem = Actions::IsProjectAssetBeingDragged(item);
const UI::AssetIconKind iconKind = item->isFolder ? UI::AssetIconKind::Folder : UI::AssetIconKind::File;
UI::AssetTileOptions tileOptions;
tileOptions.drawIdleFrame = false;
tileOptions.drawSelectionBorder = false;
if (item->isFolder) {
tileOptions.iconOffset = UI::FolderAssetTileIconOffset();
tileOptions.iconSize = UI::FolderAssetTileIconSize();
}
const bool isRenaming = item && m_renameState.IsEditing(item->fullPath);
const bool isDraggingThisItem = !isRenaming && Actions::IsProjectAssetBeingDragged(item);
const UI::AssetIconKind iconKind = ResolveProjectAssetIconKind(item);
const std::string displayName = GetProjectAssetDisplayName(item);
UI::AssetTileOptions tileOptions = MakeProjectAssetTileOptions();
tileOptions.drawLabel = !isRenaming;
const UI::AssetTileResult tile = UI::DrawAssetTile(
item->name.c_str(),
displayName.c_str(),
isSelected,
isDraggingThisItem,
[&](ImDrawList* drawList, const ImVec2& iconMin, const ImVec2& iconMax) {
if (item && item->type == "Texture" &&
UI::DrawTextureAssetPreview(drawList, iconMin, iconMax, item->fullPath)) {
return;
}
UI::DrawAssetIcon(drawList, iconMin, iconMax, iconKind);
},
tileOptions);
if (tile.clicked) {
interaction.clicked = true;
if (isRenaming) {
const ImVec2 restoreCursor = ImGui::GetCursorPos();
ImGui::SetCursorScreenPos(tile.labelMin);
ImGui::SetNextItemWidth(tile.labelMax.x - tile.labelMin.x);
if (m_renameState.ConsumeFocusRequest()) {
ImGui::SetKeyboardFocusHere();
}
const bool submitted = ImGui::InputText(
"##Rename",
m_renameState.Buffer(),
m_renameState.BufferSize(),
ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll);
const bool cancelRequested = ImGui::IsItemActive() && ImGui::IsKeyPressed(ImGuiKey_Escape);
const bool deactivated = ImGui::IsItemDeactivated();
ImGui::SetCursorPos(restoreCursor);
if (cancelRequested) {
CancelRename();
} else if (submitted || deactivated) {
CommitRename(m_context->GetProjectManager());
}
} else {
if (tile.clicked) {
interaction.clicked = true;
}
if (tile.contextRequested) {
interaction.contextRequested = true;
}
RegisterFolderDropTarget(m_context->GetProjectManager(), item);
Actions::BeginProjectAssetDrag(item, iconKind);
if (tile.openRequested) {
interaction.openRequested = true;
}
}
if (tile.contextRequested) {
interaction.contextRequested = true;
}
interaction.droppedSourcePath = Actions::AcceptProjectAssetDropPayload(item);
Actions::BeginProjectAssetDrag(item, iconKind);
if (tile.openRequested) {
interaction.openRequested = true;
}
ImGui::PopID();
return interaction;
}