diff --git a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp index 6c31c927d..9f4289586 100644 --- a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp +++ b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp @@ -10,12 +10,14 @@ #include #include +#include #include #include -#include -#include +#include + #include +#include #include #include @@ -85,6 +87,8 @@ void OvEditor::Core::Editor::SetupUI() using EFileType = OvTools::Utils::PathParser::EFileType; const auto fileType = OvTools::Utils::PathParser::GetFileType(p_path); const auto path = OvTools::Utils::PathParser::MakeNonWindowsStyle(p_path); + const auto embeddedAssetPath = ParseEmbeddedAssetPath(path); + const bool isEmbeddedTexture = embeddedAssetPath && ParseEmbeddedTextureIndex(embeddedAssetPath->assetName).has_value(); auto openInAssetView = [&](auto* p_resource) { @@ -95,7 +99,7 @@ void OvEditor::Core::Editor::SetupUI() assetView.Focus(); }; - if (fileType == EFileType::TEXTURE) + if (fileType == EFileType::TEXTURE || isEmbeddedTexture) { openInAssetView(OVSERVICE(TextureManager).GetResource(path)); } diff --git a/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp b/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp index 1434881a8..109a70b4a 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp @@ -9,15 +9,17 @@ #include #include #include +#include #include #include +#include #include #include -#include +#include #include -#include #include +#include #include @@ -29,6 +31,8 @@ #include #include +#include + #include #include #include @@ -761,6 +765,69 @@ namespace } }; + class EmbeddedFileContextualMenu : public OvUI::Plugins::ContextualMenu + { + public: + EmbeddedFileContextualMenu(std::string p_resourcePath) : m_resourcePath(std::move(p_resourcePath)) {} + + void CreateList() + { + auto& openAction = CreateWidget("Open"); + openAction.ClickedEvent += [this] { + OvCore::Helpers::GUIHelpers::Open(m_resourcePath); + }; + } + + virtual void Execute(OvUI::Plugins::EPluginExecutionContext p_context) override + { + if (!m_widgets.empty()) + { + OvUI::Plugins::ContextualMenu::Execute(p_context); + } + } + + protected: + std::string m_resourcePath; + }; + + void CreateEmbeddedModelAssetEntry( + OvUI::Widgets::Layout::TreeNode& p_root, + const std::string& p_resourcePath, + OvTools::Utils::PathParser::EFileType p_fileType + ) + { + const auto embeddedPath = OvRendering::Resources::Parsers::ParseEmbeddedAssetPath(p_resourcePath); + if (!embeddedPath) + { + return; + } + + const std::string itemName = embeddedPath->assetName; + auto& itemGroup = p_root.CreateWidget(); + const uint32_t iconTextureID = EDITOR_CONTEXT(editorResources)->GetFileIcon(itemName)->GetTexture().GetID(); + itemGroup.CreateWidget(iconTextureID, OvMaths::FVector2{ 16, 16 }).lineBreak = false; + + auto& clickableText = itemGroup.CreateWidget(itemName); + clickableText.AddPlugin>>( + "File", + OvTools::Utils::PathParser::GetFriendlyPath(p_resourcePath), + std::make_pair(p_resourcePath, &itemGroup) + ); + + if (p_fileType == OvTools::Utils::PathParser::EFileType::TEXTURE) + { + auto& texturePreview = clickableText.AddPlugin(); + texturePreview.SetPath(p_resourcePath); + } + + auto& contextMenu = clickableText.AddPlugin(p_resourcePath); + contextMenu.CreateList(); + + clickableText.DoubleClickedEvent += [resourcePath = p_resourcePath] { + OvCore::Helpers::GUIHelpers::Open(resourcePath); + }; + } + FileContextualMenu& CreateFileContextualMenu( OvUI::Widgets::AWidget& p_root, OvTools::Utils::PathParser::EFileType p_fileType, @@ -1104,86 +1171,202 @@ void OvEditor::Panels::AssetBrowser::ConsiderItem(OvUI::Widgets::Layout::TreeNod } else { - auto& clickableText = itemGroup.CreateWidget(itemname); + if (fileType == OvTools::Utils::PathParser::EFileType::MODEL) + { + auto& treeNode = itemGroup.CreateWidget(itemname); - FileContextualMenu& contextMenu = CreateFileContextualMenu( - clickableText, - fileType, - path, - protectedItem - ); + FileContextualMenu& contextMenu = CreateFileContextualMenu( + treeNode, + fileType, + path, + protectedItem + ); - contextMenu.CreateList(); + contextMenu.CreateList(); - contextMenu.DestroyedEvent += [&itemGroup](std::filesystem::path p_deletedPath) { - itemGroup.Destroy(); + contextMenu.DestroyedEvent += [&itemGroup](std::filesystem::path p_deletedPath) { + itemGroup.Destroy(); - if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_deletedPath) // Modify current scene source path if the renamed file is the current scene - { - EDITOR_CONTEXT(sceneManager).ForgetCurrentSceneSourcePath(); - } - }; + if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_deletedPath) + { + EDITOR_CONTEXT(sceneManager).ForgetCurrentSceneSourcePath(); + } + }; - auto& ddSource = clickableText.AddPlugin>>( - "File", - OvTools::Utils::PathParser::GetFriendlyPath(resourceFormatPath), - std::make_pair(resourceFormatPath, &itemGroup) - ); + auto& ddSource = treeNode.AddPlugin>>( + "File", + OvTools::Utils::PathParser::GetFriendlyPath(resourceFormatPath), + std::make_pair(resourceFormatPath, &itemGroup) + ); - contextMenu.RenamedEvent += [&ddSource, &clickableText, fileType]( - std::filesystem::path p_prev, - std::filesystem::path p_newPath - ) { - if (p_newPath != p_prev) - { - if (!std::filesystem::exists(p_newPath)) + contextMenu.RenamedEvent += [&ddSource, &treeNode, fileType]( + std::filesystem::path p_prev, + std::filesystem::path p_newPath + ) { + if (p_newPath != p_prev) { - RenameAsset(p_prev, p_newPath); - const auto elementName = p_newPath.filename(); - ddSource.data.first = (std::filesystem::path{ ddSource.data.first }.parent_path() / elementName).string(); - ddSource.tooltip = OvTools::Utils::PathParser::GetFriendlyPath(ddSource.data.first); + if (!std::filesystem::exists(p_newPath)) + { + RenameAsset(p_prev, p_newPath); + const auto elementName = p_newPath.filename(); + ddSource.data.first = (std::filesystem::path{ ddSource.data.first }.parent_path() / elementName).string(); + ddSource.tooltip = OvTools::Utils::PathParser::GetFriendlyPath(ddSource.data.first); - EDITOR_EXEC(PropagateFileRename(p_prev.string(), p_newPath.string())); + EDITOR_EXEC(PropagateFileRename(p_prev.string(), p_newPath.string())); - if (fileType != OvTools::Utils::PathParser::EFileType::SCRIPT) - { - if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_prev) // Modify current scene source path if the renamed file is the current scene + if (fileType != OvTools::Utils::PathParser::EFileType::SCRIPT) { - EDITOR_CONTEXT(sceneManager).StoreCurrentSceneSourcePath(p_newPath.string()); + if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_prev) + { + EDITOR_CONTEXT(sceneManager).StoreCurrentSceneSourcePath(p_newPath.string()); + } } - } - clickableText.content = elementName.string(); + treeNode.name = elementName.string(); + } + else + { + using namespace OvWindowing::Dialogs; + + MessageBox errorMessage( + "File already exists", + "You can't rename this file because the given name is already taken", + MessageBox::EMessageType::ERROR, + MessageBox::EButtonLayout::OK + ); + } } - else + }; + + contextMenu.DuplicateEvent += [this, p_root, p_isEngineItem](std::filesystem::path newItem) { + EDITOR_EXEC(DelayAction(std::bind(&AssetBrowser::ConsiderItem, this, p_root, std::filesystem::directory_entry{ newItem }, p_isEngineItem, false), 0)); + }; + + treeNode.DoubleClickedEvent += [&contextMenu, p_isEngineItem] { + OvCore::Helpers::GUIHelpers::Open(EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem))); + }; + + treeNode.OpenedEvent += [this, &treeNode, &contextMenu, p_isEngineItem] { + treeNode.RemoveAllWidgets(); + + const std::string modelResourcePath = EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem)); + const auto* model = OVSERVICE(OvCore::ResourceManagement::ModelManager).GetResource(modelResourcePath); + if (!model) { - using namespace OvWindowing::Dialogs; + return; + } - MessageBox errorMessage( - "File already exists", - "You can't rename this file because the given name is already taken", - MessageBox::EMessageType::ERROR, - MessageBox::EButtonLayout::OK - ); + const auto& embeddedMaterials = model->GetEmbeddedMaterials(); + for (size_t materialIndex = 0; materialIndex < embeddedMaterials.size(); ++materialIndex) + { + const std::string materialPath = OvRendering::Resources::Parsers::MakeEmbeddedMaterialPath(modelResourcePath, static_cast(materialIndex)); + CreateEmbeddedModelAssetEntry(treeNode, materialPath, OvTools::Utils::PathParser::EFileType::MATERIAL); } - } - }; - contextMenu.DuplicateEvent += [this, &clickableText, p_root, p_isEngineItem] (std::filesystem::path newItem) { - EDITOR_EXEC(DelayAction(std::bind(&AssetBrowser::ConsiderItem, this, p_root, std::filesystem::directory_entry{ newItem }, p_isEngineItem, false), 0)); - }; + const auto& embeddedTextures = model->GetEmbeddedTextures(); + for (size_t textureIndex = 0; textureIndex < embeddedTextures.size(); ++textureIndex) + { + const auto& textureData = embeddedTextures[textureIndex]; - if (fileType == OvTools::Utils::PathParser::EFileType::TEXTURE) - { - auto& texturePreview = clickableText.AddPlugin(); - texturePreview.SetPath(resourceFormatPath); - } + using ESourceType = OvRendering::Resources::EmbeddedTextureData::ESourceType; + if (textureData.sourceType == ESourceType::EXTERNAL_FILE) + { + continue; + } - if (fileType != OvTools::Utils::PathParser::EFileType::UNKNOWN) + const std::string extension = textureData.extension.empty() ? "bin" : textureData.extension; + const std::string texturePath = OvRendering::Resources::Parsers::MakeEmbeddedTexturePath(modelResourcePath, static_cast(textureIndex), extension); + CreateEmbeddedModelAssetEntry(treeNode, texturePath, OvTools::Utils::PathParser::EFileType::TEXTURE); + } + }; + + treeNode.ClosedEvent += [&treeNode] { + treeNode.RemoveAllWidgets(); + }; + } + else { - clickableText.DoubleClickedEvent += [&contextMenu, p_isEngineItem] { - OvCore::Helpers::GUIHelpers::Open(EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem))); + auto& clickableText = itemGroup.CreateWidget(itemname); + + FileContextualMenu& contextMenu = CreateFileContextualMenu( + clickableText, + fileType, + path, + protectedItem + ); + + contextMenu.CreateList(); + + contextMenu.DestroyedEvent += [&itemGroup](std::filesystem::path p_deletedPath) { + itemGroup.Destroy(); + + if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_deletedPath) // Modify current scene source path if the renamed file is the current scene + { + EDITOR_CONTEXT(sceneManager).ForgetCurrentSceneSourcePath(); + } }; + + auto& ddSource = clickableText.AddPlugin>>( + "File", + OvTools::Utils::PathParser::GetFriendlyPath(resourceFormatPath), + std::make_pair(resourceFormatPath, &itemGroup) + ); + + contextMenu.RenamedEvent += [&ddSource, &clickableText, fileType]( + std::filesystem::path p_prev, + std::filesystem::path p_newPath + ) { + if (p_newPath != p_prev) + { + if (!std::filesystem::exists(p_newPath)) + { + RenameAsset(p_prev, p_newPath); + const auto elementName = p_newPath.filename(); + ddSource.data.first = (std::filesystem::path{ ddSource.data.first }.parent_path() / elementName).string(); + ddSource.tooltip = OvTools::Utils::PathParser::GetFriendlyPath(ddSource.data.first); + + EDITOR_EXEC(PropagateFileRename(p_prev.string(), p_newPath.string())); + + if (fileType != OvTools::Utils::PathParser::EFileType::SCRIPT) + { + if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_prev) // Modify current scene source path if the renamed file is the current scene + { + EDITOR_CONTEXT(sceneManager).StoreCurrentSceneSourcePath(p_newPath.string()); + } + } + + clickableText.content = elementName.string(); + } + else + { + using namespace OvWindowing::Dialogs; + + MessageBox errorMessage( + "File already exists", + "You can't rename this file because the given name is already taken", + MessageBox::EMessageType::ERROR, + MessageBox::EButtonLayout::OK + ); + } + } + }; + + contextMenu.DuplicateEvent += [this, &clickableText, p_root, p_isEngineItem] (std::filesystem::path newItem) { + EDITOR_EXEC(DelayAction(std::bind(&AssetBrowser::ConsiderItem, this, p_root, std::filesystem::directory_entry{ newItem }, p_isEngineItem, false), 0)); + }; + + if (fileType == OvTools::Utils::PathParser::EFileType::TEXTURE) + { + auto& texturePreview = clickableText.AddPlugin(); + texturePreview.SetPath(resourceFormatPath); + } + + if (fileType != OvTools::Utils::PathParser::EFileType::UNKNOWN) + { + clickableText.DoubleClickedEvent += [&contextMenu, p_isEngineItem] { + OvCore::Helpers::GUIHelpers::Open(EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem))); + }; + } } } }