chore: sync workspace state
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user