Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Sources/OvEditor/src/OvEditor/Core/Editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
#include <OvCore/Helpers/GUIDrawer.h>
#include <OvCore/Helpers/GUIHelpers.h>

#include <OvCore/ResourceManagement/MaterialManager.h>
#include <OvCore/ResourceManagement/ModelManager.h>
#include <OvCore/ResourceManagement/TextureManager.h>
#include <OvCore/ResourceManagement/MaterialManager.h>

#include <OvTools/Utils/SystemCalls.h>
#include <OvRendering/Resources/Parsers/EmbeddedAssetPath.h>

#include <OvTools/Utils/PathParser.h>
#include <OvTools/Utils/SystemCalls.h>

#include <OvEditor/Core/Editor.h>
#include <OvEditor/Panels/AssetBrowser.h>
Expand Down Expand Up @@ -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)
{
Expand All @@ -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));
}
Expand Down
305 changes: 244 additions & 61 deletions Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@
#include <fstream>
#include <iostream>
#include <regex>
#include <utility>
#include <vector>
#include <tinyxml2.h>

#include <OvCore/Global/ServiceLocator.h>
#include <OvCore/Helpers/GUIDrawer.h>
#include <OvCore/Helpers/GUIHelpers.h>
#include <OvCore/Global/ServiceLocator.h>
#include <OvCore/ResourceManagement/MaterialManager.h>
#include <OvCore/ResourceManagement/ModelManager.h>
#include <OvCore/ResourceManagement/TextureManager.h>
#include <OvCore/ResourceManagement/ShaderManager.h>
#include <OvCore/ResourceManagement/TextureManager.h>

#include <OvDebug/Logger.h>

Expand All @@ -29,6 +31,8 @@
#include <OvEditor/Panels/MaterialEditor.h>
#include <OvEditor/Settings/EditorSettings.h>

#include <OvRendering/Resources/Parsers/EmbeddedAssetPath.h>

#include <OvTools/Utils/PathParser.h>
#include <OvTools/Utils/String.h>
#include <OvTools/Utils/SystemCalls.h>
Expand Down Expand Up @@ -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<OvUI::Widgets::Menu::MenuItem>("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<Layout::Group>();
const uint32_t iconTextureID = EDITOR_CONTEXT(editorResources)->GetFileIcon(itemName)->GetTexture().GetID();
itemGroup.CreateWidget<Visual::Image>(iconTextureID, OvMaths::FVector2{ 16, 16 }).lineBreak = false;

auto& clickableText = itemGroup.CreateWidget<Texts::TextClickable>(itemName);
clickableText.AddPlugin<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>(
"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>();
texturePreview.SetPath(p_resourcePath);
}

auto& contextMenu = clickableText.AddPlugin<EmbeddedFileContextualMenu>(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,
Expand Down Expand Up @@ -1104,86 +1171,202 @@ void OvEditor::Panels::AssetBrowser::ConsiderItem(OvUI::Widgets::Layout::TreeNod
}
else
{
auto& clickableText = itemGroup.CreateWidget<Texts::TextClickable>(itemname);
if (fileType == OvTools::Utils::PathParser::EFileType::MODEL)
{
auto& treeNode = itemGroup.CreateWidget<Layout::TreeNode>(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<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>(
"File",
OvTools::Utils::PathParser::GetFriendlyPath(resourceFormatPath),
std::make_pair(resourceFormatPath, &itemGroup)
);
auto& ddSource = treeNode.AddPlugin<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>(
"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<uint32_t>(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>();
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<uint32_t>(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<Texts::TextClickable>(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<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>(
"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>();
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)));
};
}
}
}
}