|
9 | 9 | #include <fstream> |
10 | 10 | #include <iostream> |
11 | 11 | #include <regex> |
| 12 | +#include <utility> |
12 | 13 | #include <vector> |
13 | 14 | #include <tinyxml2.h> |
14 | 15 |
|
| 16 | +#include <OvCore/Global/ServiceLocator.h> |
15 | 17 | #include <OvCore/Helpers/GUIDrawer.h> |
16 | 18 | #include <OvCore/Helpers/GUIHelpers.h> |
17 | | -#include <OvCore/Global/ServiceLocator.h> |
| 19 | +#include <OvCore/ResourceManagement/MaterialManager.h> |
18 | 20 | #include <OvCore/ResourceManagement/ModelManager.h> |
19 | | -#include <OvCore/ResourceManagement/TextureManager.h> |
20 | 21 | #include <OvCore/ResourceManagement/ShaderManager.h> |
| 22 | +#include <OvCore/ResourceManagement/TextureManager.h> |
21 | 23 |
|
22 | 24 | #include <OvDebug/Logger.h> |
23 | 25 |
|
|
29 | 31 | #include <OvEditor/Panels/MaterialEditor.h> |
30 | 32 | #include <OvEditor/Settings/EditorSettings.h> |
31 | 33 |
|
| 34 | +#include <OvRendering/Resources/Parsers/EmbeddedAssetPath.h> |
| 35 | + |
32 | 36 | #include <OvTools/Utils/PathParser.h> |
33 | 37 | #include <OvTools/Utils/String.h> |
34 | 38 | #include <OvTools/Utils/SystemCalls.h> |
@@ -761,6 +765,69 @@ namespace |
761 | 765 | } |
762 | 766 | }; |
763 | 767 |
|
| 768 | + class EmbeddedFileContextualMenu : public OvUI::Plugins::ContextualMenu |
| 769 | + { |
| 770 | + public: |
| 771 | + EmbeddedFileContextualMenu(std::string p_resourcePath) : m_resourcePath(std::move(p_resourcePath)) {} |
| 772 | + |
| 773 | + void CreateList() |
| 774 | + { |
| 775 | + auto& openAction = CreateWidget<OvUI::Widgets::Menu::MenuItem>("Open"); |
| 776 | + openAction.ClickedEvent += [this] { |
| 777 | + OvCore::Helpers::GUIHelpers::Open(m_resourcePath); |
| 778 | + }; |
| 779 | + } |
| 780 | + |
| 781 | + virtual void Execute(OvUI::Plugins::EPluginExecutionContext p_context) override |
| 782 | + { |
| 783 | + if (!m_widgets.empty()) |
| 784 | + { |
| 785 | + OvUI::Plugins::ContextualMenu::Execute(p_context); |
| 786 | + } |
| 787 | + } |
| 788 | + |
| 789 | + protected: |
| 790 | + std::string m_resourcePath; |
| 791 | + }; |
| 792 | + |
| 793 | + void CreateEmbeddedModelAssetEntry( |
| 794 | + OvUI::Widgets::Layout::TreeNode& p_root, |
| 795 | + const std::string& p_resourcePath, |
| 796 | + OvTools::Utils::PathParser::EFileType p_fileType |
| 797 | + ) |
| 798 | + { |
| 799 | + const auto embeddedPath = OvRendering::Resources::Parsers::ParseEmbeddedAssetPath(p_resourcePath); |
| 800 | + if (!embeddedPath) |
| 801 | + { |
| 802 | + return; |
| 803 | + } |
| 804 | + |
| 805 | + const std::string itemName = embeddedPath->assetName; |
| 806 | + auto& itemGroup = p_root.CreateWidget<Layout::Group>(); |
| 807 | + const uint32_t iconTextureID = EDITOR_CONTEXT(editorResources)->GetFileIcon(itemName)->GetTexture().GetID(); |
| 808 | + itemGroup.CreateWidget<Visual::Image>(iconTextureID, OvMaths::FVector2{ 16, 16 }).lineBreak = false; |
| 809 | + |
| 810 | + auto& clickableText = itemGroup.CreateWidget<Texts::TextClickable>(itemName); |
| 811 | + clickableText.AddPlugin<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>( |
| 812 | + "File", |
| 813 | + OvTools::Utils::PathParser::GetFriendlyPath(p_resourcePath), |
| 814 | + std::make_pair(p_resourcePath, &itemGroup) |
| 815 | + ); |
| 816 | + |
| 817 | + if (p_fileType == OvTools::Utils::PathParser::EFileType::TEXTURE) |
| 818 | + { |
| 819 | + auto& texturePreview = clickableText.AddPlugin<TexturePreview>(); |
| 820 | + texturePreview.SetPath(p_resourcePath); |
| 821 | + } |
| 822 | + |
| 823 | + auto& contextMenu = clickableText.AddPlugin<EmbeddedFileContextualMenu>(p_resourcePath); |
| 824 | + contextMenu.CreateList(); |
| 825 | + |
| 826 | + clickableText.DoubleClickedEvent += [resourcePath = p_resourcePath] { |
| 827 | + OvCore::Helpers::GUIHelpers::Open(resourcePath); |
| 828 | + }; |
| 829 | + } |
| 830 | + |
764 | 831 | FileContextualMenu& CreateFileContextualMenu( |
765 | 832 | OvUI::Widgets::AWidget& p_root, |
766 | 833 | OvTools::Utils::PathParser::EFileType p_fileType, |
@@ -1104,86 +1171,202 @@ void OvEditor::Panels::AssetBrowser::ConsiderItem(OvUI::Widgets::Layout::TreeNod |
1104 | 1171 | } |
1105 | 1172 | else |
1106 | 1173 | { |
1107 | | - auto& clickableText = itemGroup.CreateWidget<Texts::TextClickable>(itemname); |
| 1174 | + if (fileType == OvTools::Utils::PathParser::EFileType::MODEL) |
| 1175 | + { |
| 1176 | + auto& treeNode = itemGroup.CreateWidget<Layout::TreeNode>(itemname); |
1108 | 1177 |
|
1109 | | - FileContextualMenu& contextMenu = CreateFileContextualMenu( |
1110 | | - clickableText, |
1111 | | - fileType, |
1112 | | - path, |
1113 | | - protectedItem |
1114 | | - ); |
| 1178 | + FileContextualMenu& contextMenu = CreateFileContextualMenu( |
| 1179 | + treeNode, |
| 1180 | + fileType, |
| 1181 | + path, |
| 1182 | + protectedItem |
| 1183 | + ); |
1115 | 1184 |
|
1116 | | - contextMenu.CreateList(); |
| 1185 | + contextMenu.CreateList(); |
1117 | 1186 |
|
1118 | | - contextMenu.DestroyedEvent += [&itemGroup](std::filesystem::path p_deletedPath) { |
1119 | | - itemGroup.Destroy(); |
| 1187 | + contextMenu.DestroyedEvent += [&itemGroup](std::filesystem::path p_deletedPath) { |
| 1188 | + itemGroup.Destroy(); |
1120 | 1189 |
|
1121 | | - if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_deletedPath) // Modify current scene source path if the renamed file is the current scene |
1122 | | - { |
1123 | | - EDITOR_CONTEXT(sceneManager).ForgetCurrentSceneSourcePath(); |
1124 | | - } |
1125 | | - }; |
| 1190 | + if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_deletedPath) |
| 1191 | + { |
| 1192 | + EDITOR_CONTEXT(sceneManager).ForgetCurrentSceneSourcePath(); |
| 1193 | + } |
| 1194 | + }; |
1126 | 1195 |
|
1127 | | - auto& ddSource = clickableText.AddPlugin<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>( |
1128 | | - "File", |
1129 | | - OvTools::Utils::PathParser::GetFriendlyPath(resourceFormatPath), |
1130 | | - std::make_pair(resourceFormatPath, &itemGroup) |
1131 | | - ); |
| 1196 | + auto& ddSource = treeNode.AddPlugin<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>( |
| 1197 | + "File", |
| 1198 | + OvTools::Utils::PathParser::GetFriendlyPath(resourceFormatPath), |
| 1199 | + std::make_pair(resourceFormatPath, &itemGroup) |
| 1200 | + ); |
1132 | 1201 |
|
1133 | | - contextMenu.RenamedEvent += [&ddSource, &clickableText, fileType]( |
1134 | | - std::filesystem::path p_prev, |
1135 | | - std::filesystem::path p_newPath |
1136 | | - ) { |
1137 | | - if (p_newPath != p_prev) |
1138 | | - { |
1139 | | - if (!std::filesystem::exists(p_newPath)) |
| 1202 | + contextMenu.RenamedEvent += [&ddSource, &treeNode, fileType]( |
| 1203 | + std::filesystem::path p_prev, |
| 1204 | + std::filesystem::path p_newPath |
| 1205 | + ) { |
| 1206 | + if (p_newPath != p_prev) |
1140 | 1207 | { |
1141 | | - RenameAsset(p_prev, p_newPath); |
1142 | | - const auto elementName = p_newPath.filename(); |
1143 | | - ddSource.data.first = (std::filesystem::path{ ddSource.data.first }.parent_path() / elementName).string(); |
1144 | | - ddSource.tooltip = OvTools::Utils::PathParser::GetFriendlyPath(ddSource.data.first); |
| 1208 | + if (!std::filesystem::exists(p_newPath)) |
| 1209 | + { |
| 1210 | + RenameAsset(p_prev, p_newPath); |
| 1211 | + const auto elementName = p_newPath.filename(); |
| 1212 | + ddSource.data.first = (std::filesystem::path{ ddSource.data.first }.parent_path() / elementName).string(); |
| 1213 | + ddSource.tooltip = OvTools::Utils::PathParser::GetFriendlyPath(ddSource.data.first); |
1145 | 1214 |
|
1146 | | - EDITOR_EXEC(PropagateFileRename(p_prev.string(), p_newPath.string())); |
| 1215 | + EDITOR_EXEC(PropagateFileRename(p_prev.string(), p_newPath.string())); |
1147 | 1216 |
|
1148 | | - if (fileType != OvTools::Utils::PathParser::EFileType::SCRIPT) |
1149 | | - { |
1150 | | - if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_prev) // Modify current scene source path if the renamed file is the current scene |
| 1217 | + if (fileType != OvTools::Utils::PathParser::EFileType::SCRIPT) |
1151 | 1218 | { |
1152 | | - EDITOR_CONTEXT(sceneManager).StoreCurrentSceneSourcePath(p_newPath.string()); |
| 1219 | + if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_prev) |
| 1220 | + { |
| 1221 | + EDITOR_CONTEXT(sceneManager).StoreCurrentSceneSourcePath(p_newPath.string()); |
| 1222 | + } |
1153 | 1223 | } |
1154 | | - } |
1155 | 1224 |
|
1156 | | - clickableText.content = elementName.string(); |
| 1225 | + treeNode.name = elementName.string(); |
| 1226 | + } |
| 1227 | + else |
| 1228 | + { |
| 1229 | + using namespace OvWindowing::Dialogs; |
| 1230 | + |
| 1231 | + MessageBox errorMessage( |
| 1232 | + "File already exists", |
| 1233 | + "You can't rename this file because the given name is already taken", |
| 1234 | + MessageBox::EMessageType::ERROR, |
| 1235 | + MessageBox::EButtonLayout::OK |
| 1236 | + ); |
| 1237 | + } |
1157 | 1238 | } |
1158 | | - else |
| 1239 | + }; |
| 1240 | + |
| 1241 | + contextMenu.DuplicateEvent += [this, p_root, p_isEngineItem](std::filesystem::path newItem) { |
| 1242 | + EDITOR_EXEC(DelayAction(std::bind(&AssetBrowser::ConsiderItem, this, p_root, std::filesystem::directory_entry{ newItem }, p_isEngineItem, false), 0)); |
| 1243 | + }; |
| 1244 | + |
| 1245 | + treeNode.DoubleClickedEvent += [&contextMenu, p_isEngineItem] { |
| 1246 | + OvCore::Helpers::GUIHelpers::Open(EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem))); |
| 1247 | + }; |
| 1248 | + |
| 1249 | + treeNode.OpenedEvent += [this, &treeNode, &contextMenu, p_isEngineItem] { |
| 1250 | + treeNode.RemoveAllWidgets(); |
| 1251 | + |
| 1252 | + const std::string modelResourcePath = EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem)); |
| 1253 | + const auto* model = OVSERVICE(OvCore::ResourceManagement::ModelManager).GetResource(modelResourcePath); |
| 1254 | + if (!model) |
1159 | 1255 | { |
1160 | | - using namespace OvWindowing::Dialogs; |
| 1256 | + return; |
| 1257 | + } |
1161 | 1258 |
|
1162 | | - MessageBox errorMessage( |
1163 | | - "File already exists", |
1164 | | - "You can't rename this file because the given name is already taken", |
1165 | | - MessageBox::EMessageType::ERROR, |
1166 | | - MessageBox::EButtonLayout::OK |
1167 | | - ); |
| 1259 | + const auto& embeddedMaterials = model->GetEmbeddedMaterials(); |
| 1260 | + for (size_t materialIndex = 0; materialIndex < embeddedMaterials.size(); ++materialIndex) |
| 1261 | + { |
| 1262 | + const std::string materialPath = OvRendering::Resources::Parsers::MakeEmbeddedMaterialPath(modelResourcePath, static_cast<uint32_t>(materialIndex)); |
| 1263 | + CreateEmbeddedModelAssetEntry(treeNode, materialPath, OvTools::Utils::PathParser::EFileType::MATERIAL); |
1168 | 1264 | } |
1169 | | - } |
1170 | | - }; |
1171 | 1265 |
|
1172 | | - contextMenu.DuplicateEvent += [this, &clickableText, p_root, p_isEngineItem] (std::filesystem::path newItem) { |
1173 | | - EDITOR_EXEC(DelayAction(std::bind(&AssetBrowser::ConsiderItem, this, p_root, std::filesystem::directory_entry{ newItem }, p_isEngineItem, false), 0)); |
1174 | | - }; |
| 1266 | + const auto& embeddedTextures = model->GetEmbeddedTextures(); |
| 1267 | + for (size_t textureIndex = 0; textureIndex < embeddedTextures.size(); ++textureIndex) |
| 1268 | + { |
| 1269 | + const auto& textureData = embeddedTextures[textureIndex]; |
1175 | 1270 |
|
1176 | | - if (fileType == OvTools::Utils::PathParser::EFileType::TEXTURE) |
1177 | | - { |
1178 | | - auto& texturePreview = clickableText.AddPlugin<TexturePreview>(); |
1179 | | - texturePreview.SetPath(resourceFormatPath); |
1180 | | - } |
| 1271 | + using ESourceType = OvRendering::Resources::EmbeddedTextureData::ESourceType; |
| 1272 | + if (textureData.sourceType == ESourceType::EXTERNAL_FILE) |
| 1273 | + { |
| 1274 | + continue; |
| 1275 | + } |
1181 | 1276 |
|
1182 | | - if (fileType != OvTools::Utils::PathParser::EFileType::UNKNOWN) |
| 1277 | + const std::string extension = textureData.extension.empty() ? "bin" : textureData.extension; |
| 1278 | + const std::string texturePath = OvRendering::Resources::Parsers::MakeEmbeddedTexturePath(modelResourcePath, static_cast<uint32_t>(textureIndex), extension); |
| 1279 | + CreateEmbeddedModelAssetEntry(treeNode, texturePath, OvTools::Utils::PathParser::EFileType::TEXTURE); |
| 1280 | + } |
| 1281 | + }; |
| 1282 | + |
| 1283 | + treeNode.ClosedEvent += [&treeNode] { |
| 1284 | + treeNode.RemoveAllWidgets(); |
| 1285 | + }; |
| 1286 | + } |
| 1287 | + else |
1183 | 1288 | { |
1184 | | - clickableText.DoubleClickedEvent += [&contextMenu, p_isEngineItem] { |
1185 | | - OvCore::Helpers::GUIHelpers::Open(EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem))); |
| 1289 | + auto& clickableText = itemGroup.CreateWidget<Texts::TextClickable>(itemname); |
| 1290 | + |
| 1291 | + FileContextualMenu& contextMenu = CreateFileContextualMenu( |
| 1292 | + clickableText, |
| 1293 | + fileType, |
| 1294 | + path, |
| 1295 | + protectedItem |
| 1296 | + ); |
| 1297 | + |
| 1298 | + contextMenu.CreateList(); |
| 1299 | + |
| 1300 | + contextMenu.DestroyedEvent += [&itemGroup](std::filesystem::path p_deletedPath) { |
| 1301 | + itemGroup.Destroy(); |
| 1302 | + |
| 1303 | + if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_deletedPath) // Modify current scene source path if the renamed file is the current scene |
| 1304 | + { |
| 1305 | + EDITOR_CONTEXT(sceneManager).ForgetCurrentSceneSourcePath(); |
| 1306 | + } |
1186 | 1307 | }; |
| 1308 | + |
| 1309 | + auto& ddSource = clickableText.AddPlugin<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>( |
| 1310 | + "File", |
| 1311 | + OvTools::Utils::PathParser::GetFriendlyPath(resourceFormatPath), |
| 1312 | + std::make_pair(resourceFormatPath, &itemGroup) |
| 1313 | + ); |
| 1314 | + |
| 1315 | + contextMenu.RenamedEvent += [&ddSource, &clickableText, fileType]( |
| 1316 | + std::filesystem::path p_prev, |
| 1317 | + std::filesystem::path p_newPath |
| 1318 | + ) { |
| 1319 | + if (p_newPath != p_prev) |
| 1320 | + { |
| 1321 | + if (!std::filesystem::exists(p_newPath)) |
| 1322 | + { |
| 1323 | + RenameAsset(p_prev, p_newPath); |
| 1324 | + const auto elementName = p_newPath.filename(); |
| 1325 | + ddSource.data.first = (std::filesystem::path{ ddSource.data.first }.parent_path() / elementName).string(); |
| 1326 | + ddSource.tooltip = OvTools::Utils::PathParser::GetFriendlyPath(ddSource.data.first); |
| 1327 | + |
| 1328 | + EDITOR_EXEC(PropagateFileRename(p_prev.string(), p_newPath.string())); |
| 1329 | + |
| 1330 | + if (fileType != OvTools::Utils::PathParser::EFileType::SCRIPT) |
| 1331 | + { |
| 1332 | + if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_prev) // Modify current scene source path if the renamed file is the current scene |
| 1333 | + { |
| 1334 | + EDITOR_CONTEXT(sceneManager).StoreCurrentSceneSourcePath(p_newPath.string()); |
| 1335 | + } |
| 1336 | + } |
| 1337 | + |
| 1338 | + clickableText.content = elementName.string(); |
| 1339 | + } |
| 1340 | + else |
| 1341 | + { |
| 1342 | + using namespace OvWindowing::Dialogs; |
| 1343 | + |
| 1344 | + MessageBox errorMessage( |
| 1345 | + "File already exists", |
| 1346 | + "You can't rename this file because the given name is already taken", |
| 1347 | + MessageBox::EMessageType::ERROR, |
| 1348 | + MessageBox::EButtonLayout::OK |
| 1349 | + ); |
| 1350 | + } |
| 1351 | + } |
| 1352 | + }; |
| 1353 | + |
| 1354 | + contextMenu.DuplicateEvent += [this, &clickableText, p_root, p_isEngineItem] (std::filesystem::path newItem) { |
| 1355 | + EDITOR_EXEC(DelayAction(std::bind(&AssetBrowser::ConsiderItem, this, p_root, std::filesystem::directory_entry{ newItem }, p_isEngineItem, false), 0)); |
| 1356 | + }; |
| 1357 | + |
| 1358 | + if (fileType == OvTools::Utils::PathParser::EFileType::TEXTURE) |
| 1359 | + { |
| 1360 | + auto& texturePreview = clickableText.AddPlugin<TexturePreview>(); |
| 1361 | + texturePreview.SetPath(resourceFormatPath); |
| 1362 | + } |
| 1363 | + |
| 1364 | + if (fileType != OvTools::Utils::PathParser::EFileType::UNKNOWN) |
| 1365 | + { |
| 1366 | + clickableText.DoubleClickedEvent += [&contextMenu, p_isEngineItem] { |
| 1367 | + OvCore::Helpers::GUIHelpers::Open(EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem))); |
| 1368 | + }; |
| 1369 | + } |
1187 | 1370 | } |
1188 | 1371 | } |
1189 | 1372 | } |
0 commit comments