mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 20:17:06 +03:00
851 lines
22 KiB
C++
851 lines
22 KiB
C++
#include "content.h"
|
|
#include "../builtin_resources.h"
|
|
#include "dockspace.h"
|
|
|
|
#include <asset/asset_texture.h>
|
|
#include <asset/asset_manager.h>
|
|
#include <nfd.h>
|
|
#include <scene/scene_manager.h>
|
|
|
|
using namespace engine;
|
|
using namespace engine::ui;
|
|
|
|
static const std::string kIconContentImport = std::string(" ") + ICON_FA_FILE_IMPORT + std::string(" Import ") ;
|
|
static const std::string kIconContentNew = std::string(" ") + ICON_FA_FILE_CIRCLE_PLUS + std::string(" New ") ;
|
|
static const std::string kIconContentSave = std::string(" ") + ICON_FA_FILE_EXPORT + std::string(" Save ") ;
|
|
static const std::string kIconContentSaveAll = std::string(" ") + ICON_FA_FILE_SIGNATURE + std::string(" Save All ");
|
|
static const std::string kIconContentSearch = ICON_FA_MAGNIFYING_GLASS ;
|
|
static const std::string kIconContentTitle = ICON_FA_FOLDER_CLOSED ;
|
|
|
|
|
|
static const std::string kRightClickedMenuName = "##RightClickedMenu";
|
|
|
|
static const float kMinSnapShotIconSize = 2.0f;
|
|
static const float kMaxSnapShotIconSize = 8.0f;
|
|
|
|
WidgetContent::WidgetContent(size_t index, ProjectContentModel* model)
|
|
: WidgetBase(
|
|
combineIcon("Content", kIconContentTitle).c_str(),
|
|
combineIcon(combineIndex("Content", index), kIconContentTitle).c_str())
|
|
, m_model(model)
|
|
, m_index(index)
|
|
{
|
|
|
|
}
|
|
|
|
void WidgetContent::onInit()
|
|
{
|
|
m_bShow = false;
|
|
CHECK(getAssetManager()->isProjectSetup());
|
|
|
|
setupProject();
|
|
|
|
m_onTreeViewRebuildHandle = m_model->onProjectTreeRebuild.addRaw(this, &WidgetContent::onContentTreeRebuild);
|
|
}
|
|
|
|
void WidgetContent::onRelease()
|
|
{
|
|
m_model->onProjectTreeRebuild.remove(m_onTreeViewRebuildHandle);
|
|
}
|
|
|
|
void WidgetContent::onTick(const RuntimeModuleTickData& tickData, VulkanContext* context)
|
|
{
|
|
|
|
}
|
|
|
|
void WidgetContent::setActiveEntry(std::shared_ptr<ProjectAssetTreeEntry> entry)
|
|
{
|
|
if (entry->isFoleder())
|
|
{
|
|
m_activeFolder = entry->getPath();
|
|
}
|
|
else
|
|
{
|
|
m_activeFolder = entry->getParent().lock()->getPath();
|
|
}
|
|
|
|
// Update selections in model.
|
|
const AssetSelector newSelector(entry);
|
|
m_selections.clear();
|
|
m_selections.add(newSelector);
|
|
}
|
|
|
|
void WidgetContent::drawRightClickedMenu()
|
|
{
|
|
CHECK(getSelections().existElement());
|
|
|
|
ImGui::TextDisabled("Assets Menu");
|
|
ImGui::Separator();
|
|
|
|
static const std::string kNewItemName = combineIcon("New ...", ICON_NONE);
|
|
static const std::string kImportItemName = combineIcon("Import ...", ICON_NONE);
|
|
static const std::string kCopyItemName = combineIcon(" Copy", ICON_FA_COPY);
|
|
static const std::string kPasteItemName = combineIcon(" Paste", ICON_FA_PASTE);
|
|
static const std::string kDeleteItemName = combineIcon("Delete", ICON_NONE);
|
|
|
|
const bool bSingleSelected = getSelections().getNum() == 1;
|
|
const bool bSingleFolderSelected = getSelections().getSelections().at(0).entry.lock()->isFoleder();
|
|
|
|
if (bSingleSelected)
|
|
{
|
|
if (bSingleFolderSelected)
|
|
{
|
|
if (ImGui::BeginMenu(kNewItemName.c_str()))
|
|
{
|
|
|
|
|
|
ImGui::EndMenu();
|
|
}
|
|
|
|
if (ImGui::BeginMenu(kImportItemName.c_str()))
|
|
{
|
|
drawAssetImport();
|
|
ImGui::EndMenu();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ImGui::Selectable(kDeleteItemName.c_str()))
|
|
{
|
|
|
|
|
|
}
|
|
|
|
ImGui::Separator();
|
|
if (ImGui::Selectable(kCopyItemName.c_str()))
|
|
{
|
|
|
|
}
|
|
if (ImGui::Selectable(kPasteItemName.c_str()))
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
void WidgetContent::drawAssetImport()
|
|
{
|
|
ZoneScoped;
|
|
|
|
ImGui::TextDisabled("Import Assets:");
|
|
ImGui::Separator();
|
|
|
|
auto assetList = rttr::type::get<AssetInterface>().get_derived_classes();
|
|
for (auto& assetType : assetList)
|
|
{
|
|
const auto& method = assetType.get_method("uiGetAssetReflectionInfo");
|
|
if (method.is_static() && method.is_valid())
|
|
{
|
|
rttr::variant returnValue = method.invoke({});
|
|
if (returnValue.is_valid() && returnValue.is_type<AssetReflectionInfo>())
|
|
{
|
|
const auto& meta = returnValue.get_value<AssetReflectionInfo>();
|
|
if (meta.importConfig.bImportable)
|
|
{
|
|
ImGui::PushID(assetType.get_name().data());
|
|
if (ImGui::Selectable(meta.decoratedName.c_str()))
|
|
{
|
|
nfdpathset_t pathSet;
|
|
nfdresult_t result = NFD_OpenDialogMultiple(meta.importConfig.importRawAssetExtension.c_str(), NULL, &pathSet);
|
|
if (result == NFD_OKAY)
|
|
{
|
|
const auto count = NFD_PathSet_GetCount(&pathSet);
|
|
if (count > 0)
|
|
{
|
|
auto& contentImport = Editor::get()->getDockSpaceAndMenu()->contentAssetImport;
|
|
if (contentImport.open())
|
|
{
|
|
CHECK(contentImport.importConfigs.empty());
|
|
CHECK(contentImport.typeName.empty());
|
|
contentImport.typeName = assetType.get_name();
|
|
|
|
CHECK(meta.importConfig.buildAssetImportConfig);
|
|
for (size_t i = 0; i < NFD_PathSet_GetCount(&pathSet); ++i)
|
|
{
|
|
nfdchar_t* path = NFD_PathSet_GetPath(&pathSet, i);
|
|
std::string utf8Path = path;
|
|
|
|
const std::filesystem::path u16Path = utf8::utf8to16(utf8Path);
|
|
auto folderPath = m_activeFolder / u16Path.filename().replace_extension();
|
|
folderPath = buildStillNonExistPath(folderPath);
|
|
|
|
auto config = meta.importConfig.buildAssetImportConfig();
|
|
config->path = { u16Path, folderPath };
|
|
|
|
contentImport.importConfigs.push_back(config);
|
|
}
|
|
}
|
|
}
|
|
NFD_PathSet_Free(&pathSet);
|
|
}
|
|
}
|
|
ImGui::PopID();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void WidgetContent::onVisibleTick(const RuntimeModuleTickData& tickData)
|
|
{
|
|
ZoneScoped;
|
|
|
|
ImGui::Separator();
|
|
{
|
|
drawMenu(tickData);
|
|
}
|
|
|
|
ImGui::Separator();
|
|
const auto& projectConfig = getAssetManager()->getProjectConfig();
|
|
{
|
|
std::string projectName = utf8::utf16to8(projectConfig.projectName);
|
|
std::string rootName = utf8::utf16to8(projectConfig.rootPath);
|
|
std::string activeFolderName = utf8::utf16to8(m_activeFolder.u16string());
|
|
|
|
ImGui::TextDisabled("Working project: %s and working path: %s.", projectName.c_str(), rootName.c_str());
|
|
|
|
ImGui::SameLine();
|
|
ImGui::Text("Inspecting folder path: %s.", activeFolderName.c_str());
|
|
}
|
|
|
|
drawContent(tickData);
|
|
}
|
|
|
|
void WidgetContent::onContentTreeRebuild()
|
|
{
|
|
m_selections.clear();
|
|
m_treeviewHoverEntry = {};
|
|
}
|
|
|
|
void WidgetContent::setupProject()
|
|
{
|
|
const auto& projectConfig = getAssetManager()->getProjectConfig();
|
|
m_activeFolder = projectConfig.assetPath;
|
|
|
|
|
|
}
|
|
|
|
void WidgetContent::drawMenu(const RuntimeModuleTickData& tickData)
|
|
{
|
|
const float sizeLable = ImGui::GetFontSize();
|
|
if (ImGui::BeginTable("Import UIC##", 5))
|
|
{
|
|
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, sizeLable * 5.0f);
|
|
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, sizeLable * 4.0f);
|
|
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, sizeLable * 4.0f);
|
|
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, sizeLable * 6.0f);
|
|
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_None);
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
static const char* kImport = "##XAssetMenu_Import";
|
|
static const char* kCreate = "##XAssetMenu_Create";
|
|
|
|
if (ImGui::Button((kIconContentImport).c_str()))
|
|
{
|
|
ImGui::OpenPopup(kImport);
|
|
}
|
|
hoverTip("Import new asset from disk.");
|
|
|
|
if (ImGui::BeginPopup(kImport))
|
|
{
|
|
drawAssetImport();
|
|
|
|
ImGui::EndPopup();
|
|
}
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
if (ImGui::Button((kIconContentNew).c_str()))
|
|
{
|
|
ImGui::OpenPopup(kCreate);
|
|
|
|
}
|
|
hoverTip("Create new asset.");
|
|
|
|
if (ImGui::BeginPopup(kCreate))
|
|
{
|
|
ImGui::TextDisabled("Create Assets:");
|
|
ImGui::Separator();
|
|
|
|
// TODO:
|
|
// drawAssetCreate();
|
|
|
|
ImGui::EndPopup();
|
|
}
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
if (ImGui::Button((kIconContentSave).c_str()))
|
|
{
|
|
// TODO:
|
|
/*
|
|
const auto& assets = m_editor->getAssetSelected();
|
|
for (const auto& assetPath : assets)
|
|
{
|
|
auto pathCopy = assetPath;
|
|
const auto relativePath = buildRelativePathUtf8(m_editor->getProjectRootPathUtf16(), pathCopy.replace_extension());
|
|
getAssetSystem()->getAssetByRelativeMap(relativePath)->saveAction();
|
|
}
|
|
*/
|
|
}
|
|
hoverTip("Save select asset.");
|
|
ImGui::TableNextColumn();
|
|
|
|
if (ImGui::Button((kIconContentSaveAll).c_str()))
|
|
{
|
|
|
|
}
|
|
hoverTip("Save all assets.");
|
|
ImGui::TableNextColumn();
|
|
|
|
m_filter.Draw((kIconContentSearch).c_str());
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
|
|
}
|
|
|
|
void WidgetContent::drawContentTreeView(std::shared_ptr<ProjectAssetTreeEntry> entry)
|
|
{
|
|
// Should we draw with tree node.
|
|
const bool bTreeNode = entry->isFoleder() && (!entry->isChildrenEmpty());
|
|
|
|
// Get node flags.
|
|
ImGuiTreeNodeFlags nodeFlags = ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_SpanFullWidth;
|
|
nodeFlags |= bTreeNode ? ImGuiTreeNodeFlags_OpenOnArrow : ImGuiTreeNodeFlags_Leaf;
|
|
|
|
const AssetSelector assetSelector(entry);
|
|
if (getSelections().isSelected(assetSelector))
|
|
{
|
|
nodeFlags |= ImGuiTreeNodeFlags_Selected;
|
|
}
|
|
|
|
// Add icon decorate.
|
|
u8str showName = entry->getName();
|
|
if (entry->isFoleder())
|
|
{
|
|
if (entry->isChildrenEmpty())
|
|
{
|
|
showName = ICON_FA_FOLDER_CLOSED" " + showName;
|
|
}
|
|
else
|
|
{
|
|
bool bOpen = entry->isFolderOpen();
|
|
if (bOpen)
|
|
{
|
|
showName = ICON_FA_FOLDER_OPEN" " + showName;
|
|
}
|
|
else
|
|
{
|
|
showName = ICON_FA_FOLDER_CLOSED" " + showName;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
showName = ICON_FA_FILE" " + showName;
|
|
}
|
|
|
|
// Draw tree node.
|
|
bool bNodeOpen = ui::treeNodeEx(entry->getName().c_str(), showName.c_str(), nodeFlags);
|
|
entry->setFolderOpenState(bNodeOpen);
|
|
|
|
// Action tick.
|
|
if (ImGui::IsItemClicked(0))
|
|
{
|
|
if (ImGui::GetIO().KeyCtrl)
|
|
{
|
|
if (getSelections().isSelected(assetSelector))
|
|
{
|
|
getSelections().remove(assetSelector);
|
|
}
|
|
else
|
|
{
|
|
getSelections().add(assetSelector);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Switch active entry.
|
|
setActiveEntry(entry);
|
|
}
|
|
}
|
|
|
|
const bool bItemHover = ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly);
|
|
if (bItemHover)
|
|
{
|
|
m_treeviewHoverEntry = entry;
|
|
}
|
|
|
|
// Recursive draw.
|
|
if (bNodeOpen)
|
|
{
|
|
if (bTreeNode)
|
|
{
|
|
for (const auto& child : entry->getChildren())
|
|
{
|
|
drawContentTreeView(child);
|
|
}
|
|
}
|
|
ImGui::TreePop();
|
|
}
|
|
}
|
|
|
|
void WidgetContent::drawContentSnapShot(std::shared_ptr<ProjectAssetTreeEntry> workingEntry)
|
|
{
|
|
const auto& children = workingEntry->getChildren();
|
|
const auto inspectItemNum = children.size();
|
|
|
|
const auto availRegion = ImGui::GetContentRegionAvail();
|
|
const float itemDimSize = ImGui::GetTextLineHeightWithSpacing() * m_snapshotItemIconSize;
|
|
|
|
const float kPadFirstColumDimX = 1.0f;
|
|
|
|
const uint32_t drawItemPerRow = uint32_t(math::max(1.0f, (availRegion.x - kPadFirstColumDimX - ImGui::GetTextLineHeightWithSpacing() * 2.0f) / (itemDimSize + ImGui::GetStyle().ItemSpacing.x)));
|
|
|
|
const size_t minDrawRowNum = size_t(math::max(1.0f, math::ceil(availRegion.y / itemDimSize)));
|
|
const uint32_t drawRowNum = uint32_t(math::max(minDrawRowNum, inspectItemNum / drawItemPerRow + 1));
|
|
|
|
|
|
if (ImGui::BeginTable("##table_scrolly_snapshot", drawItemPerRow + 1,
|
|
ImGuiTableFlags_ScrollY |
|
|
ImGuiTableFlags_Hideable |
|
|
ImGuiTableFlags_NoClip |
|
|
ImGuiTableFlags_NoBordersInBody, availRegion))
|
|
{
|
|
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, kPadFirstColumDimX);
|
|
for (size_t i = 1; i < drawItemPerRow + 1; i++)
|
|
{
|
|
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, itemDimSize);
|
|
}
|
|
|
|
ImGuiListClipper clipper;
|
|
clipper.Begin(int(drawRowNum));
|
|
while (clipper.Step())
|
|
{
|
|
for (size_t row = clipper.DisplayStart; row < clipper.DisplayEnd; row++)
|
|
{
|
|
ImGui::TableNextRow();
|
|
ImGui::PushID(int(row));
|
|
|
|
for (size_t colum = 1; colum < drawItemPerRow + 1; colum++)
|
|
{
|
|
size_t drawId = row * drawItemPerRow + (colum - 1);
|
|
if (drawId < inspectItemNum)
|
|
{
|
|
ImGui::TableSetColumnIndex(int(colum));
|
|
drawItemSnapshot(itemDimSize, children.at(drawId));
|
|
}
|
|
}
|
|
ImGui::PopID();
|
|
}
|
|
}
|
|
ImGui::EndTable();
|
|
}
|
|
|
|
|
|
if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
|
|
{
|
|
m_snapshotItemIconSize += ImGui::GetIO().MouseWheel;
|
|
m_snapshotItemIconSize = math::clamp(m_snapshotItemIconSize, kMinSnapShotIconSize, kMaxSnapShotIconSize);
|
|
}
|
|
|
|
if (ImGui::IsMouseClicked(1) &&
|
|
ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()) &&
|
|
getSelections().existElement())
|
|
{
|
|
ImGui::OpenPopup(kRightClickedMenuName.c_str());
|
|
}
|
|
if (ImGui::BeginPopup(kRightClickedMenuName.c_str()))
|
|
{
|
|
drawRightClickedMenu();
|
|
ImGui::EndPopup();
|
|
}
|
|
}
|
|
|
|
void WidgetContent::drawItemSnapshot(float drawDimSize, std::shared_ptr<ProjectAssetTreeEntry> entry)
|
|
{
|
|
const AssetSelector entrySelector(entry);
|
|
|
|
static std::hash<uint64_t> haser;
|
|
float textH = ImGui::GetTextLineHeightWithSpacing();
|
|
|
|
const bool bItemSeleted = getSelections().isSelected(entrySelector);
|
|
|
|
ImGui::PushID(int(haser(entry->getRuntimeUUID())));
|
|
ImGui::BeginChild(
|
|
entry->getName().c_str(),
|
|
{ drawDimSize , drawDimSize + textH * 3.0f },
|
|
false,
|
|
ImGuiWindowFlags_NoScrollWithMouse |
|
|
ImGuiWindowFlags_NoScrollbar);
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0);
|
|
{
|
|
bool bItemHover = ImGui::IsMouseHoveringRect(ImGui::GetCursorScreenPos(),
|
|
ImVec2(ImGui::GetCursorScreenPos().x + drawDimSize, ImGui::GetCursorScreenPos().y + drawDimSize));
|
|
|
|
if (bItemHover)
|
|
{
|
|
// Double clicked
|
|
if (ImGui::IsMouseDoubleClicked(0))
|
|
{
|
|
if (entry->isFoleder())
|
|
{
|
|
setActiveEntry(entry);
|
|
}
|
|
else
|
|
{
|
|
auto copyPath = entry->getPath();
|
|
if (Scene::assetIsScene(copyPath.extension().string().c_str()))
|
|
{
|
|
if (!getAssetManager()->getDirtyAsset<Scene>().empty())
|
|
{
|
|
if (Editor::get()->getDockSpaceAndMenu()->sceneAssetSave.open())
|
|
{
|
|
CHECK(!Editor::get()->getDockSpaceAndMenu()->sceneAssetSave.afterEventAccept);
|
|
Editor::get()->getDockSpaceAndMenu()->sceneAssetSave.afterEventAccept = [copyPath]()
|
|
{
|
|
getSceneManager()->loadScene(copyPath);
|
|
};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
getSceneManager()->loadScene(copyPath);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO: Asset edit.
|
|
// const auto relativePath = buildRelativePathUtf8(m_editor->getProjectRootPathUtf16(), copyPath.replace_extension());
|
|
// m_editor->getAssetConfigManager()->openWidget(utf8::utf8to16(relativePath));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Single click
|
|
if (ImGui::IsMouseClicked(0))
|
|
{
|
|
if (ImGui::GetIO().KeyCtrl)
|
|
{
|
|
if (getSelections().isSelected(entrySelector))
|
|
{
|
|
getSelections().remove(entrySelector);
|
|
}
|
|
else
|
|
{
|
|
getSelections().add(entrySelector);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
getSelections().clear();
|
|
getSelections().add(entrySelector);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bItemSeleted && ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
|
|
{
|
|
auto& dragDropAssets = Editor::get()->getDragDropAssets();
|
|
|
|
dragDropAssets.selectAssets.clear();
|
|
for (const auto& selector : getSelections().getSelections())
|
|
{
|
|
if (auto entry = selector.entry.lock())
|
|
{
|
|
dragDropAssets.selectAssets.insert(entry->getPath());
|
|
}
|
|
}
|
|
|
|
ImGui::SetDragDropPayload(
|
|
Editor::getDragDropAssetsName(),
|
|
(void*)&dragDropAssets,
|
|
sizeof(void*));
|
|
|
|
for (const auto& id : dragDropAssets.selectAssets)
|
|
{
|
|
std::string showName = utf8::utf16to8(id.u16string());
|
|
ImGui::Text(showName.c_str());
|
|
}
|
|
|
|
ImGui::EndDragDropSource();
|
|
}
|
|
|
|
// Decorated fill
|
|
{
|
|
ImGui::GetWindowDrawList()->AddRectFilled(
|
|
ImGui::GetCursorScreenPos(),
|
|
ImVec2(ImGui::GetCursorScreenPos().x + drawDimSize, ImGui::GetCursorScreenPos().y + drawDimSize + textH * 3.0f),
|
|
bItemSeleted ? IM_COL32(88, 150, 250, 81) : IM_COL32(51, 51, 51, 190));
|
|
|
|
ImGui::GetWindowDrawList()->AddRect(
|
|
ImGui::GetCursorScreenPos(),
|
|
ImVec2(ImGui::GetCursorScreenPos().x + drawDimSize, ImGui::GetCursorScreenPos().y + drawDimSize + textH * 3.0f),
|
|
IM_COL32(255, 255, 255, 39));
|
|
|
|
ImGui::GetWindowDrawList()->AddRect(
|
|
ImGui::GetCursorScreenPos(),
|
|
ImVec2(ImGui::GetCursorScreenPos().x + drawDimSize, ImGui::GetCursorScreenPos().y + drawDimSize),
|
|
bItemHover ? IM_COL32(250, 244, 11, 255) : IM_COL32(255, 255, 255, 80), bItemHover ? 1.0f : 0.0f, 0, bItemHover ? 1.5f : 1.0f);
|
|
}
|
|
|
|
ImVec2 uv0{ 0.0f, 0.0f };
|
|
ImVec2 uv1{ 1.0f, 1.0f };
|
|
|
|
auto set = entry->getSet(uv0, uv1);
|
|
ImGui::Image(set, { drawDimSize , drawDimSize }, uv0, uv1);
|
|
|
|
const float indentSize = ImGui::GetFontSize() * 0.25f;
|
|
ImGui::Indent(indentSize);
|
|
{
|
|
ImGui::Spacing();
|
|
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + drawDimSize - indentSize);
|
|
ImGui::Text(entry->getName().c_str());
|
|
ImGui::PopTextWrapPos();
|
|
}
|
|
ImGui::Unindent();
|
|
}
|
|
ImGui::PopStyleVar();
|
|
ImGui::EndChild();
|
|
|
|
ui::hoverTip(entry->getName().c_str());
|
|
ImGui::PopID();
|
|
ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMin(), IM_COL32(88, 150, 250, 81));
|
|
}
|
|
|
|
void WidgetContent::drawContent(const engine::RuntimeModuleTickData& tickData)
|
|
{
|
|
const float footerHeightToReserve = ImGui::GetTextLineHeight() * 1.2f;
|
|
const float sizeLable = ImGui::GetFontSize();
|
|
|
|
// Reset tree view hovering entry.
|
|
m_treeviewHoverEntry.reset();
|
|
|
|
auto workingEntry = m_model->getTree().getEntry(m_activeFolder).lock();
|
|
|
|
if (ImGui::BeginTable("AssetContentTable", 2, ImGuiTableFlags_BordersInner | ImGuiTableFlags_Resizable))
|
|
{
|
|
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, sizeLable * 14.0f);
|
|
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_None);
|
|
|
|
// Row #0 is tree view.
|
|
ImGui::TableNextRow();
|
|
ImGui::TableSetColumnIndex(0);
|
|
{
|
|
ImGui::PushID("##ContentViewItemTreeView");
|
|
ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footerHeightToReserve), false, ImGuiWindowFlags_HorizontalScrollbar);
|
|
{
|
|
drawContentTreeView(m_model->getTree().getRoot());
|
|
}
|
|
ImGui::EndChild();
|
|
if (ImGui::IsItemClicked() && (!m_treeviewHoverEntry.lock()) && (!ImGui::GetIO().KeyCtrl))
|
|
{
|
|
setActiveEntry(m_model->getTree().getRoot());
|
|
}
|
|
if (ImGui::IsItemClicked(1) && getSelections().existElement())
|
|
{
|
|
ImGui::OpenPopup(kRightClickedMenuName.c_str());
|
|
}
|
|
if (ImGui::BeginPopup(kRightClickedMenuName.c_str()))
|
|
{
|
|
drawRightClickedMenu();
|
|
ImGui::EndPopup();
|
|
}
|
|
ImGui::PopID();
|
|
}
|
|
|
|
// Row #1 is content snap shot.
|
|
ImGui::TableSetColumnIndex(1);
|
|
{
|
|
ImGui::PushID("##ContentViewItemInspector");
|
|
ImGui::BeginChild("ScrollingRegion2", ImVec2(0, -footerHeightToReserve), false);
|
|
if (workingEntry)
|
|
{
|
|
drawContentSnapShot(workingEntry);
|
|
}
|
|
ImGui::EndChild();
|
|
ImGui::PopID();
|
|
}
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
|
|
ImGui::Separator();
|
|
size_t itemNum = 0;
|
|
if (workingEntry)
|
|
{
|
|
itemNum = workingEntry->getChildren().size();
|
|
}
|
|
ImGui::Text(" %d items.", itemNum);
|
|
}
|
|
|
|
void ProjectAssetTree::build()
|
|
{
|
|
CHECK(getAssetManager()->isProjectSetup());
|
|
|
|
const auto& projectConfig = getAssetManager()->getProjectConfig();
|
|
m_projectAssetTreeRoot = std::make_shared<ProjectAssetTreeEntry>("asset", true, projectConfig.assetPath, nullptr);
|
|
|
|
m_pathEntryMap.clear();
|
|
|
|
m_pathEntryMap[projectConfig.assetPath] = m_projectAssetTreeRoot;
|
|
m_projectAssetTreeRoot->buildTreeRecursive(this);
|
|
}
|
|
|
|
ProjectAssetTreeEntry::ProjectAssetTreeEntry(
|
|
u8str name
|
|
, bool bFolder
|
|
, const std::filesystem::path& path
|
|
, std::shared_ptr<ProjectAssetTreeEntry> parent)
|
|
: m_name(name)
|
|
, m_bFolder(bFolder)
|
|
, m_path(path)
|
|
, m_parent(parent)
|
|
, m_runtimeUUID(engine::buildRuntimeUUID64u())
|
|
, m_bFolderOpen(false)
|
|
{
|
|
|
|
}
|
|
|
|
// Build set for sanpshot.
|
|
ImTextureID ProjectAssetTreeEntry::getSet(ImVec2& outUv0, ImVec2& outUv1)
|
|
{
|
|
ImTextureID result;
|
|
ImVec2 uv0, uv1;
|
|
{
|
|
uv0 = { 0.0f, 0.0f };
|
|
uv1 = { 1.0f, 1.0f };
|
|
static const float kUvScale = 0.02f;
|
|
|
|
uv0.x = -kUvScale;
|
|
uv1.x = 1.0f + kUvScale;
|
|
uv0.y = -kUvScale;
|
|
uv1.y = 1.0f + kUvScale;
|
|
|
|
const auto* builtinResources = Editor::get()->getBuiltinResources();
|
|
if (m_bFolder)
|
|
{
|
|
result = Editor::get()->getClampToTransparentBorderImGuiTexture(builtinResources->folderImage.get());
|
|
}
|
|
else
|
|
{
|
|
result = Editor::get()->getClampToTransparentBorderImGuiTexture(builtinResources->fileImage.get());
|
|
if (m_path.extension().string().starts_with(".dark"))
|
|
{
|
|
if (auto asset = getAssetManager()->getOrLoadAsset<AssetInterface>(m_path).lock())
|
|
{
|
|
result =
|
|
Editor::get()->getClampToTransparentBorderImGuiTexture(asset->getSnapshotImage());
|
|
|
|
const auto w = asset->getSnapshotImage()->getExtent().width;
|
|
const auto h = asset->getSnapshotImage()->getExtent().height;
|
|
|
|
if (w < h)
|
|
{
|
|
uv0.x = 0.0f - (1.0f - float(w) / float(h)) * 0.5f;
|
|
uv1.x = 1.0f + (1.0f - float(w) / float(h)) * 0.5f;
|
|
|
|
uv0.y = -kUvScale;
|
|
uv1.y = 1.0f + kUvScale;
|
|
|
|
}
|
|
else if (w > h)
|
|
{
|
|
uv0.y = 0.0f - (1.0f - float(h) / float(w)) * 0.5f;
|
|
uv1.y = 1.0f + (1.0f - float(h) / float(w)) * 0.5f;
|
|
|
|
uv0.x = -kUvScale;
|
|
uv1.x = 1.0f + kUvScale;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
outUv0 = uv0;
|
|
outUv1 = uv1;
|
|
return result;
|
|
}
|
|
|
|
void ProjectAssetTreeEntry::buildTreeRecursive(ProjectAssetTree* tree)
|
|
{
|
|
if (m_bFolder)
|
|
{
|
|
for (const auto& entry : std::filesystem::directory_iterator(m_path))
|
|
{
|
|
const bool bFolder = std::filesystem::is_directory(entry);
|
|
|
|
const bool bSkip = (!bFolder) && (!entry.path().extension().string().starts_with(".dark"));
|
|
if (!bSkip)
|
|
{
|
|
auto u16FileNameString = entry.path().filename().replace_extension().u16string();
|
|
|
|
auto child = std::make_shared<ProjectAssetTreeEntry>(
|
|
utf8::utf16to8(u16FileNameString),
|
|
bFolder,
|
|
entry.path(),
|
|
shared_from_this());
|
|
|
|
m_children.push_back(child);
|
|
|
|
tree->m_pathEntryMap[entry.path()] = child;
|
|
|
|
child->buildTreeRecursive(tree);
|
|
}
|
|
}
|
|
|
|
std::sort(m_children.begin(), m_children.end(), [](const auto& A, const auto& B)
|
|
{
|
|
if ((A->isFoleder() && B->isFoleder()) || (!A->isFoleder() && !B->isFoleder()))
|
|
{
|
|
return A->getName() < B->getName();
|
|
}
|
|
return A->isFoleder();
|
|
});
|
|
}
|
|
}
|
|
|
|
ProjectContentModel::ProjectContentModel()
|
|
{
|
|
rebuild();
|
|
|
|
m_onAssetNewlySaveToDisk = getAssetManager()->onAssetNewlySavedToDisk.addLambda([this](std::shared_ptr<AssetInterface> asset)
|
|
{
|
|
m_bDirty = true;
|
|
});
|
|
}
|
|
|
|
void ProjectContentModel::rebuild()
|
|
{
|
|
m_projectAssetTree.build();
|
|
onProjectTreeRebuild.broadcast();
|
|
}
|
|
|
|
ProjectContentModel::~ProjectContentModel()
|
|
{
|
|
release();
|
|
}
|
|
|
|
void ProjectContentModel::release()
|
|
{
|
|
if (m_onAssetNewlySaveToDisk.isValid())
|
|
{
|
|
getAssetManager()->onAssetNewlySavedToDisk.remove(m_onAssetNewlySaveToDisk);
|
|
m_onAssetNewlySaveToDisk = {};
|
|
}
|
|
}
|
|
|
|
void ProjectContentModel::tick()
|
|
{
|
|
if (m_bDirty)
|
|
{
|
|
rebuild();
|
|
|
|
m_bDirty = false;
|
|
}
|
|
}
|