Files
XCEngine/docs/api/XCEngine/Editor/panels/ProjectPanel/ProjectPanel.md

7.7 KiB
Raw Blame History

ProjectPanel

命名空间: XCEngine::Editor

类型: class

源文件: editor/src/panels/ProjectPanel.h

描述: 项目资源浏览面板,负责把 IProjectManager 当前目录模型渲染成“目录树 + breadcrumb + 搜索 + 资源网格 + 上下文菜单 + 拖放”的 Project Browser。

概述

ProjectPanel 当前是 Editor 里项目资源浏览的前端外壳,但它不是资产数据库本身。

它的职责边界比较明确:

  • 项目目录模型与选择状态来自 IProjectManager
  • 资源打开、创建、删除、重命名、移动等语义落到 ProjectCommands
  • 少量通用交互协议由 ProjectActionRouter 提供
  • 面板自身主要负责布局、即时模式 UI 状态和延迟动作收口

生命周期与公开入口

  • Constructor 创建标题固定为 "Project" 的面板。
  • Initialize 把项目路径初始化工作委托给当前 IProjectManager
  • Render 执行完整的项目浏览器绘制与交互驱动。

面板内部状态

ProjectPanel 当前长期持有的主要是 UI 状态,而不是项目数据本体:

状态 作用
m_searchBuffer 当前目录搜索关键字
m_navigationWidth 左侧目录树宽度
m_folderTreeState 目录树展开状态
m_renameState 行内重命名状态
m_assetDragDropState 本帧拖放源 / 目标状态
m_deferredContextAction 延迟到本帧末尾执行的上下文菜单动作

初始化与每帧主流程

Initialize(projectPath)

当前实现只有一行:

m_context->GetProjectManager().Initialize(projectPath);

这说明 ProjectPanel 不自己扫描目录,也不自己构建项目树。

Render()

当前每帧主要顺序是:

  1. 打开 PanelWindowScope
  2. 调用 ObserveFocusedActionRoute(*m_context, EditorActionRoute::Project)
  3. BeginAssetDragDropFrame()
  4. 渲染顶部 toolbar
  5. 渲染左侧目录树与右侧浏览区
  6. FinalizeAssetDragDrop(manager)
  7. 在帧末执行 m_deferredContextAction

这里最关键的两个点是:

  • Project 面板会显式声明当前焦点 route
  • 拖放提交和上下文菜单命令都在本帧尾部统一收口,避免打断当前 UI 遍历

顶部工具栏

RenderToolbar() 当前负责两件事:

  • 左侧显示当前 ResourceManager 的 project asset import 状态
  • 右侧提供当前目录搜索框

导入状态文本和 tooltip 来自:

  • ResourceManager::GetProjectAssetImportStatus()
  • AssetImportService::ImportStatusSnapshot

搜索行为则比较克制:

  • 只过滤 manager.GetCurrentItems() 返回的当前目录条目
  • 匹配逻辑使用 UI::SearchQuery::Matches(item->name)
  • 不做全项目搜索、类型过滤或标签过滤

左侧目录树

数据来源

目录树主要消费:

  • GetRootFolder()
  • GetCurrentFolder()

节点绘制与交互

每个目录节点当前通过 UI::DrawTreeNode(...) 绘制,并带有:

  • 当前目录高亮
  • 基于 IsCurrentTreeBranch(...) 的默认展开
  • 自定义 folder icon prefix

当前支持的主要交互包括:

  • 左键点击目录 -> NavigateToFolder(folder)
  • 目录作为资源拖放目标
  • 空白区右键弹出项目上下文菜单

若根目录不可用,则显示 No Assets Folder 空状态。

右侧浏览区

右侧浏览区分成两部分:

  • RenderBrowserHeader(manager)
  • RenderBrowserPane(manager) 的资源网格主体

Breadcrumb

Header 当前通过 UI::DrawToolbarBreadcrumbs(...) 渲染路径,并消费:

  • manager.GetPathDepth()
  • manager.GetPathName(index)
  • manager.NavigateToIndex(index)

因此目录导航当前主要依赖目录树和 breadcrumb而不是单独的“后退按钮”。

资源网格

主体区域当前会:

  1. 先基于搜索关键字计算 visibleItems
  2. 动态估算卡片高度与列数
  3. 逐项调用 RenderAssetItem(...)
  4. 在帧末统一处理选中、打开与空白区清选

RenderAssetItem(...) 当前支持:

  • 单击选中
  • 双击打开
  • 右键选中并弹出上下文菜单
  • 纹理预览与图标 fallback
  • 行内重命名
  • 拖放源 / 目录拖放目标

若搜索结果为空,会显示:

  • No Search Results
  • No assets match the current search

上下文菜单与重命名

行内重命名

当前重命名由 m_renameState 驱动:

  1. BeginRename(item) 激活编辑状态
  2. DrawInlineRenameFieldAt(...) 覆盖卡片 label 区
  3. 提交时调用 CommitRename(...)
  4. 真正的重命名落到 Commands::RenameAsset(...)

若用户没有实际修改显示名称,CommitRename(...) 会直接结束重命名,而不会重复提交文件操作。

右键菜单

DrawProjectContextMenu(...) 当前支持:

  • Create -> Folder
  • Create -> Material
  • Show in Explore
  • Open
  • Delete
  • Rename
  • Copy Path

其中创建资源采用 deferred action

  1. 必要时先导航到目标目录
  2. 调用 Commands::CreateFolder(...)Commands::CreateMaterial(...)
  3. 新建成功后自动进入重命名状态

拖放与移动资源

当前拖放逻辑被收口成一套帧内状态机,而不是散落在每个 tile 里。

帧开始

BeginAssetDragDropFrame() 会:

  • 清空 m_assetDragDropState
  • 通过 Actions::GetDraggedProjectAssetPath() 识别当前拖拽源

目录作为 drop target

RegisterFolderDropTarget(...) 会:

  • 只接受目录目标
  • 校验 payload 类型为 ProjectAssetPayloadType()
  • Commands::CanMoveAssetToFolder(...) 判断是否合法
  • 在真正投递时记录源路径与目标目录

帧结束统一提交

FinalizeAssetDragDrop(...) 会:

  • 根据当前悬停是否合法切换鼠标样式
  • 若本帧成功投递,则统一调用 Commands::MoveAssetToFolder(...)

这样可以避免在 UI 遍历过程中直接修改底层目录树。

与项目工作流命令的关系

ProjectPanel 当前直接消费的主要是资源级命令:

  • CreateFolder
  • CreateMaterial
  • DeleteAsset
  • RenameAsset
  • MoveAssetToFolder
  • OpenAsset

负责发起以下项目级入口:

  • Save Project
  • Open Project...
  • New Project...
  • Rebuild Script Assemblies

这些工作流分别由主菜单和命令层收口。

当外部命令触发 RefreshCurrentFolder() 时,面板会在下一帧反映新的目录树状态。

测试锚点

tests/Editor/test_action_routing.cpp 当前与这条资源链路直接相关的测试包括:

  • ProjectCommandsCreateFolderMoveAssetAndOpenFolderHelper
  • ProjectCommandsCreateFolderUsesUniqueDefaultName
  • ProjectCommandsRenameAssetUpdatesSelectionAndPreservesFileExtension
  • ProjectCommandsRejectInvalidMoveTargets
  • ProjectSelectionSurvivesRefreshWhenItemOrderChanges
  • ProjectCommandsRejectMovingFolderIntoItsDescendant

当前限制

  • 搜索当前只覆盖当前目录的名称匹配。
  • 目录树展开状态当前只保存在内存里。
  • 拖拽预览 tooltip 被关闭,拖放反馈比较轻量。
  • 资源上下文菜单仍偏基础,没有批量操作或复杂预览。
  • 面板本身不是项目保存或脚本重建入口。

相关文档