From 2d34582ccfb128dde627e170b9d39d47272fc7ce Mon Sep 17 00:00:00 2001 From: Adrien GIVRY Date: Thu, 9 Apr 2026 16:04:08 -0400 Subject: [PATCH 1/9] initial implementation --- .../OvCore/include/OvCore/Helpers/GUIDrawer.h | 16 +++ .../OvCore/src/OvCore/Helpers/GUIDrawer.cpp | 106 ++++++++++++++++ .../OvEditor/include/OvEditor/Core/Editor.h | 4 + .../include/OvEditor/Panels/AssetPicker.h | 61 +++++++++ Sources/OvEditor/src/OvEditor/Core/Editor.cpp | 20 +++ .../src/OvEditor/Panels/AssetPicker.cpp | 116 ++++++++++++++++++ 6 files changed, 323 insertions(+) create mode 100644 Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h create mode 100644 Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp diff --git a/Sources/OvCore/include/OvCore/Helpers/GUIDrawer.h b/Sources/OvCore/include/OvCore/Helpers/GUIDrawer.h index d234f8823..40a406ae3 100644 --- a/Sources/OvCore/include/OvCore/Helpers/GUIDrawer.h +++ b/Sources/OvCore/include/OvCore/Helpers/GUIDrawer.h @@ -6,11 +6,16 @@ #pragma once +#include +#include + #include #include #include #include +#include + #include #include #include @@ -56,6 +61,16 @@ namespace OvCore::Helpers */ static void ProvideEmptyTexture(OvRendering::Resources::Texture& p_emptyTexture); + /** + * Register the function that opens the asset picker window. + * The provider receives the desired file type and a callback to invoke with the chosen path. + * Call this once during editor startup. + * @param p_provider + */ + static void SetAssetPickerProvider( + std::function)> p_provider + ); + /** * Draw a title with the title color * @param p_root @@ -98,6 +113,7 @@ namespace OvCore::Helpers private: static OvRendering::Resources::Texture* __EMPTY_TEXTURE; + static std::function)> s_assetPickerProvider; }; } diff --git a/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp b/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp index 2f1304e90..581e823c4 100644 --- a/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp +++ b/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp @@ -34,12 +34,19 @@ const OvUI::Types::Color OvCore::Helpers::GUIDrawer::ClearButtonColor = { 0.5f, const float OvCore::Helpers::GUIDrawer::_MIN_FLOAT = -999999999.f; const float OvCore::Helpers::GUIDrawer::_MAX_FLOAT = +999999999.f; OvRendering::Resources::Texture* OvCore::Helpers::GUIDrawer::__EMPTY_TEXTURE = nullptr; +std::function)> OvCore::Helpers::GUIDrawer::s_assetPickerProvider; void OvCore::Helpers::GUIDrawer::ProvideEmptyTexture(OvRendering::Resources::Texture& p_emptyTexture) { __EMPTY_TEXTURE = &p_emptyTexture; } +void OvCore::Helpers::GUIDrawer::SetAssetPickerProvider( + std::function)> p_provider) +{ + s_assetPickerProvider = std::move(p_provider); +} + void OvCore::Helpers::GUIDrawer::CreateTitle(OvUI::Internal::WidgetContainer& p_root, const std::string & p_name) { p_root.CreateWidget(p_name, TitleColor); @@ -126,6 +133,23 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawMesh(OvUI::Internal: widget.lineBreak = false; + auto& selectButton = rightSide.CreateWidget("..."); + selectButton.lineBreak = false; + selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] + { + if (GUIDrawer::s_assetPickerProvider) + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::MODEL, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + { + if (auto resource = OVSERVICE(OvCore::ResourceManagement::ModelManager).GetResource(p_path); resource) + { + p_data = resource; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); + }; + auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] @@ -164,6 +188,23 @@ OvUI::Widgets::Visual::Image& OvCore::Helpers::GUIDrawer::DrawTexture(OvUI::Inte widget.lineBreak = false; + auto& selectButton = rightSide.CreateWidget("..."); + selectButton.lineBreak = false; + selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] + { + if (GUIDrawer::s_assetPickerProvider) + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::TEXTURE, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + { + if (auto resource = OVSERVICE(OvCore::ResourceManagement::TextureManager).GetResource(p_path); resource) + { + p_data = resource; + widget.textureID.id = resource->GetTexture().GetID(); + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); + }; + auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] @@ -202,6 +243,23 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawShader(OvUI::Interna widget.lineBreak = false; + auto& selectButton = rightSide.CreateWidget("..."); + selectButton.lineBreak = false; + selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] + { + if (GUIDrawer::s_assetPickerProvider) + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::SHADER, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + { + if (auto resource = OVSERVICE(OvCore::ResourceManagement::ShaderManager).GetResource(p_path); resource) + { + p_data = resource; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); + }; + auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] @@ -240,6 +298,23 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawMaterial(OvUI::Inter widget.lineBreak = false; + auto& selectButton = rightSide.CreateWidget("..."); + selectButton.lineBreak = false; + selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] + { + if (GUIDrawer::s_assetPickerProvider) + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::MATERIAL, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + { + if (auto resource = OVSERVICE(OvCore::ResourceManagement::MaterialManager).GetResource(p_path); resource) + { + p_data = resource; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); + }; + auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] @@ -278,6 +353,23 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawSound(OvUI::Internal widget.lineBreak = false; + auto& selectButtonSound = rightSide.CreateWidget("..."); + selectButtonSound.lineBreak = false; + selectButtonSound.ClickedEvent += [&widget, &p_data, p_updateNotifier] + { + if (GUIDrawer::s_assetPickerProvider) + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::SOUND, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + { + if (auto resource = OVSERVICE(OvCore::ResourceManagement::SoundManager).GetResource(p_path); resource) + { + p_data = resource; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); + }; + auto & resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] @@ -310,6 +402,20 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawAsset(OvUI::Internal widget.lineBreak = false; + auto& selectButton = rightSide.CreateWidget("..."); + selectButton.lineBreak = false; + selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] + { + if (GUIDrawer::s_assetPickerProvider) + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::UNKNOWN, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + { + p_data = p_path; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + }); + }; + auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] diff --git a/Sources/OvEditor/include/OvEditor/Core/Editor.h b/Sources/OvEditor/include/OvEditor/Core/Editor.h index 9b97cfd30..ba5e2316a 100644 --- a/Sources/OvEditor/include/OvEditor/Core/Editor.h +++ b/Sources/OvEditor/include/OvEditor/Core/Editor.h @@ -6,10 +6,13 @@ #pragma once +#include + #include #include #include #include +#include #include #include @@ -103,5 +106,6 @@ namespace OvEditor::Core OvEditor::Core::PanelsManager m_panelsManager; OvEditor::Core::EditorActions m_editorActions; OvTools::Utils::OptRef m_lastFocusedView; + std::unique_ptr m_assetPicker; }; } \ No newline at end of file diff --git a/Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h b/Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h new file mode 100644 index 000000000..3fe169584 --- /dev/null +++ b/Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h @@ -0,0 +1,61 @@ +/** +* @project: Overload +* @author: Overload Tech. +* @licence: MIT +*/ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace OvUI::Widgets +{ + namespace InputFields { class InputText; } + namespace Layout { class Group; } + namespace Texts { class TextClickable; } +} + +namespace OvEditor::Panels +{ + /** + * A floating panel that lets the user pick an asset of a given type. + * Open it with Open(fileType, callback) — on selection the callback receives the + * resource-format path and the window closes automatically. + */ + class AssetPicker : public OvUI::Panels::PanelWindow + { + public: + AssetPicker( + const std::string& p_title, + bool p_opened, + const OvUI::Settings::PanelWindowSettings& p_windowSettings + ); + + /** + * Open the picker filtered by the given file type. + * @param p_fileType Asset type to show (UNKNOWN = all known types) + * @param p_callback Called with the selected resource path when the user picks an asset + */ + void Open(OvTools::Utils::PathParser::EFileType p_fileType, std::function p_callback); + + private: + void Populate(); + void FilterList(const std::string& p_search); + + private: + OvTools::Utils::PathParser::EFileType m_fileType = OvTools::Utils::PathParser::EFileType::UNKNOWN; + std::function m_callback; + + OvUI::Widgets::InputFields::InputText* m_searchField = nullptr; + OvUI::Widgets::Layout::Group* m_assetListGroup = nullptr; + + /* Each entry: (resource-format path, corresponding widget) */ + std::vector> m_items; + }; +} diff --git a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp index 6b41884b3..1084f2770 100644 --- a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp +++ b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp @@ -6,8 +6,11 @@ #include +#include + #include #include +#include #include #include #include @@ -74,6 +77,23 @@ void OvEditor::Core::Editor::SetupUI() m_canvas.MakeDockspace(true); m_context.uiManager->SetCanvas(m_canvas); + + OvUI::Settings::PanelWindowSettings pickerSettings; + pickerSettings.closable = true; + pickerSettings.resizable = true; + pickerSettings.movable = true; + pickerSettings.dockable = false; + pickerSettings.scrollable = true; + + m_assetPicker = std::make_unique("Asset Picker", false, pickerSettings); + m_canvas.AddPanel(*m_assetPicker); + + OvCore::Helpers::GUIDrawer::SetAssetPickerProvider( + [this](OvTools::Utils::PathParser::EFileType p_type, std::function p_callback) + { + m_assetPicker->Open(p_type, std::move(p_callback)); + } + ); } void OvEditor::Core::Editor::PreUpdate() diff --git a/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp b/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp new file mode 100644 index 000000000..b82d3f6a6 --- /dev/null +++ b/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp @@ -0,0 +1,116 @@ +/** +* @project: Overload +* @author: Overload Tech. +* @licence: MIT +*/ + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +using namespace OvEditor::Panels; +using namespace OvTools::Utils; + +namespace +{ + bool ContainsCaseInsensitive(const std::string& p_str, const std::string& p_search) + { + if (p_search.empty()) + return true; + + return std::search( + p_str.begin(), p_str.end(), + p_search.begin(), p_search.end(), + [](char a, char b) { return std::tolower(static_cast(a)) == std::tolower(static_cast(b)); } + ) != p_str.end(); + } +} + +AssetPicker::AssetPicker( + const std::string& p_title, + bool p_opened, + const OvUI::Settings::PanelWindowSettings& p_windowSettings) + : PanelWindow(p_title, p_opened, p_windowSettings) +{ + minSize = { 300.f, 400.f }; + + m_searchField = &CreateWidget("", "Search"); + m_searchField->ContentChangedEvent += [this](const std::string& p_text) + { + FilterList(p_text); + }; + + CreateWidget(); + m_assetListGroup = &CreateWidget(); +} + +void AssetPicker::Open(PathParser::EFileType p_fileType, std::function p_callback) +{ + m_fileType = p_fileType; + m_callback = std::move(p_callback); + m_searchField->content = ""; + Populate(); + PanelWindow::Open(); + Focus(); +} + +void AssetPicker::Populate() +{ + m_assetListGroup->RemoveAllWidgets(); + m_items.clear(); + + const auto collectFromDirectory = [&](const std::filesystem::path& p_directory, bool p_isEngine) + { + if (!std::filesystem::exists(p_directory)) + return; + + std::error_code ec; + for (const auto& entry : std::filesystem::recursive_directory_iterator( + p_directory, std::filesystem::directory_options::skip_permission_denied, ec)) + { + if (!entry.is_regular_file()) + continue; + + const std::string path = entry.path().string(); + const PathParser::EFileType fileType = PathParser::GetFileType(path); + + if (fileType == PathParser::EFileType::UNKNOWN) + continue; + + if (m_fileType != PathParser::EFileType::UNKNOWN && fileType != m_fileType) + continue; + + const std::string resourcePath = EDITOR_EXEC(GetResourcePath(path, p_isEngine)); + const std::string filename = PathParser::GetElementName(resourcePath); + + auto& item = m_assetListGroup->CreateWidget(filename); + item.tooltip = resourcePath; + item.ClickedEvent += [this, resourcePath] + { + if (m_callback) + m_callback(resourcePath); + Close(); + }; + + m_items.emplace_back(resourcePath, &item); + } + }; + + collectFromDirectory(EDITOR_CONTEXT(engineAssetsPath), true); + collectFromDirectory(EDITOR_CONTEXT(projectAssetsPath), false); +} + +void AssetPicker::FilterList(const std::string& p_search) +{ + for (auto& [path, widget] : m_items) + widget->enabled = ContainsCaseInsensitive(path, p_search); +} From a34322dd414d127a6220d7457f8bf493bfa5c81c Mon Sep 17 00:00:00 2001 From: Adrien GIVRY Date: Thu, 9 Apr 2026 16:08:14 -0400 Subject: [PATCH 2/9] fixed crash when inspector changes and an asset is selected --- .../OvCore/src/OvCore/Helpers/GUIDrawer.cpp | 172 +++++++++++------- 1 file changed, 108 insertions(+), 64 deletions(-) diff --git a/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp b/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp index 581e823c4..a284cfaea 100644 --- a/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp +++ b/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp @@ -5,6 +5,7 @@ */ #include +#include #include @@ -135,20 +136,28 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawMesh(OvUI::Internal: auto& selectButton = rightSide.CreateWidget("..."); selectButton.lineBreak = false; - selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] { - if (GUIDrawer::s_assetPickerProvider) - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::MODEL, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + auto token = std::make_shared(true); + std::weak_ptr weakToken = token; + selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] + { + if (GUIDrawer::s_assetPickerProvider) { - if (auto resource = OVSERVICE(OvCore::ResourceManagement::ModelManager).GetResource(p_path); resource) + std::weak_ptr weak = token; + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::MODEL, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) { - p_data = resource; - widget.content = p_path; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - }); - }; + if (weak.expired()) return; + if (auto resource = OVSERVICE(OvCore::ResourceManagement::ModelManager).GetResource(p_path); resource) + { + p_data = resource; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); + } + }; + } auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; @@ -190,20 +199,27 @@ OvUI::Widgets::Visual::Image& OvCore::Helpers::GUIDrawer::DrawTexture(OvUI::Inte auto& selectButton = rightSide.CreateWidget("..."); selectButton.lineBreak = false; - selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] { - if (GUIDrawer::s_assetPickerProvider) - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::TEXTURE, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + auto token = std::make_shared(true); + selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] + { + if (GUIDrawer::s_assetPickerProvider) { - if (auto resource = OVSERVICE(OvCore::ResourceManagement::TextureManager).GetResource(p_path); resource) + std::weak_ptr weak = token; + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::TEXTURE, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) { - p_data = resource; - widget.textureID.id = resource->GetTexture().GetID(); - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - }); - }; + if (weak.expired()) return; + if (auto resource = OVSERVICE(OvCore::ResourceManagement::TextureManager).GetResource(p_path); resource) + { + p_data = resource; + widget.textureID.id = resource->GetTexture().GetID(); + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); + } + }; + } auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; @@ -245,20 +261,27 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawShader(OvUI::Interna auto& selectButton = rightSide.CreateWidget("..."); selectButton.lineBreak = false; - selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] { - if (GUIDrawer::s_assetPickerProvider) - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::SHADER, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + auto token = std::make_shared(true); + selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] + { + if (GUIDrawer::s_assetPickerProvider) { - if (auto resource = OVSERVICE(OvCore::ResourceManagement::ShaderManager).GetResource(p_path); resource) + std::weak_ptr weak = token; + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::SHADER, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) { - p_data = resource; - widget.content = p_path; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - }); - }; + if (weak.expired()) return; + if (auto resource = OVSERVICE(OvCore::ResourceManagement::ShaderManager).GetResource(p_path); resource) + { + p_data = resource; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); + } + }; + } auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; @@ -300,20 +323,27 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawMaterial(OvUI::Inter auto& selectButton = rightSide.CreateWidget("..."); selectButton.lineBreak = false; - selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] { - if (GUIDrawer::s_assetPickerProvider) - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::MATERIAL, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + auto token = std::make_shared(true); + selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] + { + if (GUIDrawer::s_assetPickerProvider) { - if (auto resource = OVSERVICE(OvCore::ResourceManagement::MaterialManager).GetResource(p_path); resource) + std::weak_ptr weak = token; + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::MATERIAL, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) { - p_data = resource; - widget.content = p_path; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - }); - }; + if (weak.expired()) return; + if (auto resource = OVSERVICE(OvCore::ResourceManagement::MaterialManager).GetResource(p_path); resource) + { + p_data = resource; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); + } + }; + } auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; @@ -355,20 +385,27 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawSound(OvUI::Internal auto& selectButtonSound = rightSide.CreateWidget("..."); selectButtonSound.lineBreak = false; - selectButtonSound.ClickedEvent += [&widget, &p_data, p_updateNotifier] { - if (GUIDrawer::s_assetPickerProvider) - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::SOUND, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + auto token = std::make_shared(true); + selectButtonSound.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] + { + if (GUIDrawer::s_assetPickerProvider) { - if (auto resource = OVSERVICE(OvCore::ResourceManagement::SoundManager).GetResource(p_path); resource) + std::weak_ptr weak = token; + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::SOUND, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) { - p_data = resource; - widget.content = p_path; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - }); - }; + if (weak.expired()) return; + if (auto resource = OVSERVICE(OvCore::ResourceManagement::SoundManager).GetResource(p_path); resource) + { + p_data = resource; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); + } + }; + } auto & resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; @@ -404,17 +441,24 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawAsset(OvUI::Internal auto& selectButton = rightSide.CreateWidget("..."); selectButton.lineBreak = false; - selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] { - if (GUIDrawer::s_assetPickerProvider) - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::UNKNOWN, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + auto token = std::make_shared(true); + selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] + { + if (GUIDrawer::s_assetPickerProvider) { - p_data = p_path; - widget.content = p_path; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - }); - }; + std::weak_ptr weak = token; + GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::UNKNOWN, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) + { + if (weak.expired()) return; + p_data = p_path; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + }); + } + }; + } auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; From 3146af694d414b8edaf5d297e26f8a77d314b544 Mon Sep 17 00:00:00 2001 From: Adrien GIVRY Date: Thu, 9 Apr 2026 16:20:52 -0400 Subject: [PATCH 3/9] Code cleanup --- .../OvCore/include/OvCore/Helpers/GUIDrawer.h | 10 +- .../OvCore/src/OvCore/Helpers/GUIDrawer.cpp | 306 +++++------------- 2 files changed, 81 insertions(+), 235 deletions(-) diff --git a/Sources/OvCore/include/OvCore/Helpers/GUIDrawer.h b/Sources/OvCore/include/OvCore/Helpers/GUIDrawer.h index 40a406ae3..532e41743 100644 --- a/Sources/OvCore/include/OvCore/Helpers/GUIDrawer.h +++ b/Sources/OvCore/include/OvCore/Helpers/GUIDrawer.h @@ -49,6 +49,8 @@ namespace OvCore::Helpers class GUIDrawer { public: + using AssetPickerProviderCallback = std::function)>; + static const OvUI::Types::Color TitleColor; static const OvUI::Types::Color ClearButtonColor; @@ -68,7 +70,7 @@ namespace OvCore::Helpers * @param p_provider */ static void SetAssetPickerProvider( - std::function)> p_provider + AssetPickerProviderCallback p_provider ); /** @@ -110,11 +112,7 @@ namespace OvCore::Helpers template static std::string GetFormat(); - - private: - static OvRendering::Resources::Texture* __EMPTY_TEXTURE; - static std::function)> s_assetPickerProvider; }; } -#include "OvCore/Helpers/GUIDrawer.inl" \ No newline at end of file +#include "OvCore/Helpers/GUIDrawer.inl" diff --git a/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp b/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp index a284cfaea..fbb14fd57 100644 --- a/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp +++ b/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp @@ -34,8 +34,12 @@ const OvUI::Types::Color OvCore::Helpers::GUIDrawer::TitleColor = { 0.85f, 0.65f const OvUI::Types::Color OvCore::Helpers::GUIDrawer::ClearButtonColor = { 0.5f, 0.0f, 0.0f }; const float OvCore::Helpers::GUIDrawer::_MIN_FLOAT = -999999999.f; const float OvCore::Helpers::GUIDrawer::_MAX_FLOAT = +999999999.f; -OvRendering::Resources::Texture* OvCore::Helpers::GUIDrawer::__EMPTY_TEXTURE = nullptr; -std::function)> OvCore::Helpers::GUIDrawer::s_assetPickerProvider; + +namespace +{ + OvRendering::Resources::Texture* __EMPTY_TEXTURE = nullptr; + OvCore::Helpers::GUIDrawer::AssetPickerProviderCallback __ASSET_PICKER_PROVIDER; +} void OvCore::Helpers::GUIDrawer::ProvideEmptyTexture(OvRendering::Resources::Texture& p_emptyTexture) { @@ -43,9 +47,10 @@ void OvCore::Helpers::GUIDrawer::ProvideEmptyTexture(OvRendering::Resources::Tex } void OvCore::Helpers::GUIDrawer::SetAssetPickerProvider( - std::function)> p_provider) + AssetPickerProviderCallback p_provider +) { - s_assetPickerProvider = std::move(p_provider); + __ASSET_PICKER_PROVIDER = std::move(p_provider); } void OvCore::Helpers::GUIDrawer::CreateTitle(OvUI::Internal::WidgetContainer& p_root, const std::string & p_name) @@ -109,67 +114,81 @@ void OvCore::Helpers::GUIDrawer::DrawColor(OvUI::Internal::WidgetContainer & p_r dispatcher.RegisterReference(p_color); } -OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawMesh(OvUI::Internal::WidgetContainer & p_root, const std::string & p_name, OvRendering::Resources::Model *& p_data, OvTools::Eventing::Event<>* p_updateNotifier) +namespace { - CreateTitle(p_root, p_name); + template + OvUI::Widgets::Texts::Text& DrawResourceWidget( + OvUI::Internal::WidgetContainer& p_root, + const std::string& p_name, + TResource*& p_data, + OvTools::Utils::PathParser::EFileType p_fileType, + OvTools::Eventing::Event<>* p_updateNotifier) + { + OvCore::Helpers::GUIDrawer::CreateTitle(p_root, p_name); - std::string displayedText = (p_data ? p_data->path : std::string("Empty")); - auto& rightSide = p_root.CreateWidget(); + std::string displayedText = (p_data ? p_data->path : std::string("Empty")); + auto& rightSide = p_root.CreateWidget(); - auto& widget = rightSide.CreateWidget(displayedText); + auto& widget = rightSide.CreateWidget(displayedText); - widget.AddPlugin>>("File").DataReceivedEvent += [&widget, &p_data, p_updateNotifier](auto p_receivedData) - { - if (OvTools::Utils::PathParser::GetFileType(p_receivedData.first) == OvTools::Utils::PathParser::EFileType::MODEL) + widget.AddPlugin>>("File").DataReceivedEvent += + [&widget, &p_data, p_updateNotifier, p_fileType](auto p_receivedData) { - if (auto resource = OVSERVICE(OvCore::ResourceManagement::ModelManager).GetResource(p_receivedData.first); resource) + if (OvTools::Utils::PathParser::GetFileType(p_receivedData.first) == p_fileType) { - p_data = resource; - widget.content = p_receivedData.first; - if (p_updateNotifier) - p_updateNotifier->Invoke(); + if (auto resource = OVSERVICE(TResourceManager).GetResource(p_receivedData.first); resource) + { + p_data = resource; + widget.content = p_receivedData.first; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } } - } - }; + }; - widget.lineBreak = false; + widget.lineBreak = false; - auto& selectButton = rightSide.CreateWidget("..."); - selectButton.lineBreak = false; - { - auto token = std::make_shared(true); - std::weak_ptr weakToken = token; - selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] + auto& selectButton = rightSide.CreateWidget("..."); + selectButton.lineBreak = false; { - if (GUIDrawer::s_assetPickerProvider) + auto token = std::make_shared(true); + selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, p_fileType, token = std::move(token)] { - std::weak_ptr weak = token; - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::MODEL, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) + if (__ASSET_PICKER_PROVIDER) { - if (weak.expired()) return; - if (auto resource = OVSERVICE(OvCore::ResourceManagement::ModelManager).GetResource(p_path); resource) + std::weak_ptr weak = token; + __ASSET_PICKER_PROVIDER(p_fileType, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) { - p_data = resource; - widget.content = p_path; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - }); - } + if (weak.expired()) return; + if (auto resource = OVSERVICE(TResourceManager).GetResource(p_path); resource) + { + p_data = resource; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); + } + }; + } + + auto& resetButton = rightSide.CreateWidget("Clear"); + resetButton.idleBackgroundColor = OvCore::Helpers::GUIDrawer::ClearButtonColor; + resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] + { + p_data = nullptr; + widget.content = "Empty"; + if (p_updateNotifier) + p_updateNotifier->Invoke(); }; - } - auto& resetButton = rightSide.CreateWidget("Clear"); - resetButton.idleBackgroundColor = ClearButtonColor; - resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] - { - p_data = nullptr; - widget.content = "Empty"; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - }; + return widget; + } +} - return widget; +OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawMesh(OvUI::Internal::WidgetContainer& p_root, const std::string& p_name, OvRendering::Resources::Model*& p_data, OvTools::Eventing::Event<>* p_updateNotifier) +{ + return DrawResourceWidget(p_root, p_name, p_data, OvTools::Utils::PathParser::EFileType::MODEL, p_updateNotifier); } OvUI::Widgets::Visual::Image& OvCore::Helpers::GUIDrawer::DrawTexture(OvUI::Internal::WidgetContainer & p_root, const std::string & p_name, OvRendering::Resources::Texture *& p_data, OvTools::Eventing::Event<>* p_updateNotifier) @@ -203,10 +222,10 @@ OvUI::Widgets::Visual::Image& OvCore::Helpers::GUIDrawer::DrawTexture(OvUI::Inte auto token = std::make_shared(true); selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] { - if (GUIDrawer::s_assetPickerProvider) + if (__ASSET_PICKER_PROVIDER) { std::weak_ptr weak = token; - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::TEXTURE, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) + __ASSET_PICKER_PROVIDER(OvTools::Utils::PathParser::EFileType::TEXTURE, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) { if (weak.expired()) return; if (auto resource = OVSERVICE(OvCore::ResourceManagement::TextureManager).GetResource(p_path); resource) @@ -234,190 +253,19 @@ OvUI::Widgets::Visual::Image& OvCore::Helpers::GUIDrawer::DrawTexture(OvUI::Inte return widget; } -OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawShader(OvUI::Internal::WidgetContainer & p_root, const std::string & p_name, OvRendering::Resources::Shader *& p_data, OvTools::Eventing::Event<>* p_updateNotifier) +OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawShader(OvUI::Internal::WidgetContainer& p_root, const std::string& p_name, OvRendering::Resources::Shader*& p_data, OvTools::Eventing::Event<>* p_updateNotifier) { - CreateTitle(p_root, p_name); - - std::string displayedText = (p_data ? p_data->path : std::string("Empty")); - auto& rightSide = p_root.CreateWidget(); - - auto& widget = rightSide.CreateWidget(displayedText); - - widget.AddPlugin>>("File").DataReceivedEvent += [&widget, &p_data, p_updateNotifier](auto p_receivedData) - { - if (OvTools::Utils::PathParser::GetFileType(p_receivedData.first) == OvTools::Utils::PathParser::EFileType::SHADER) - { - if (auto resource = OVSERVICE(OvCore::ResourceManagement::ShaderManager).GetResource(p_receivedData.first); resource) - { - p_data = resource; - widget.content = p_receivedData.first; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - } - }; - - widget.lineBreak = false; - - auto& selectButton = rightSide.CreateWidget("..."); - selectButton.lineBreak = false; - { - auto token = std::make_shared(true); - selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] - { - if (GUIDrawer::s_assetPickerProvider) - { - std::weak_ptr weak = token; - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::SHADER, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) - { - if (weak.expired()) return; - if (auto resource = OVSERVICE(OvCore::ResourceManagement::ShaderManager).GetResource(p_path); resource) - { - p_data = resource; - widget.content = p_path; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - }); - } - }; - } - - auto& resetButton = rightSide.CreateWidget("Clear"); - resetButton.idleBackgroundColor = ClearButtonColor; - resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] - { - p_data = nullptr; - widget.content = "Empty"; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - }; - - return widget; + return DrawResourceWidget(p_root, p_name, p_data, OvTools::Utils::PathParser::EFileType::SHADER, p_updateNotifier); } -OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawMaterial(OvUI::Internal::WidgetContainer & p_root, const std::string & p_name, OvCore::Resources::Material *& p_data, OvTools::Eventing::Event<>* p_updateNotifier) +OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawMaterial(OvUI::Internal::WidgetContainer& p_root, const std::string& p_name, OvCore::Resources::Material*& p_data, OvTools::Eventing::Event<>* p_updateNotifier) { - CreateTitle(p_root, p_name); - - std::string displayedText = (p_data ? p_data->path : std::string("Empty")); - auto& rightSide = p_root.CreateWidget(); - - auto& widget = rightSide.CreateWidget(displayedText); - - widget.AddPlugin>>("File").DataReceivedEvent += [&widget, &p_data, p_updateNotifier](auto p_receivedData) - { - if (OvTools::Utils::PathParser::GetFileType(p_receivedData.first) == OvTools::Utils::PathParser::EFileType::MATERIAL) - { - if (auto resource = OVSERVICE(OvCore::ResourceManagement::MaterialManager).GetResource(p_receivedData.first); resource) - { - p_data = resource; - widget.content = p_receivedData.first; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - } - }; - - widget.lineBreak = false; - - auto& selectButton = rightSide.CreateWidget("..."); - selectButton.lineBreak = false; - { - auto token = std::make_shared(true); - selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] - { - if (GUIDrawer::s_assetPickerProvider) - { - std::weak_ptr weak = token; - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::MATERIAL, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) - { - if (weak.expired()) return; - if (auto resource = OVSERVICE(OvCore::ResourceManagement::MaterialManager).GetResource(p_path); resource) - { - p_data = resource; - widget.content = p_path; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - }); - } - }; - } - - auto& resetButton = rightSide.CreateWidget("Clear"); - resetButton.idleBackgroundColor = ClearButtonColor; - resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] - { - p_data = nullptr; - widget.content = "Empty"; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - }; - - return widget; + return DrawResourceWidget(p_root, p_name, p_data, OvTools::Utils::PathParser::EFileType::MATERIAL, p_updateNotifier); } OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawSound(OvUI::Internal::WidgetContainer& p_root, const std::string& p_name, OvAudio::Resources::Sound*& p_data, OvTools::Eventing::Event<>* p_updateNotifier) { - CreateTitle(p_root, p_name); - - std::string displayedText = (p_data ? p_data->path : std::string("Empty")); - auto & rightSide = p_root.CreateWidget(); - - auto & widget = rightSide.CreateWidget(displayedText); - - widget.AddPlugin>>("File").DataReceivedEvent += [&widget, &p_data, p_updateNotifier](auto p_receivedData) - { - if (OvTools::Utils::PathParser::GetFileType(p_receivedData.first) == OvTools::Utils::PathParser::EFileType::SOUND) - { - if (auto resource = OVSERVICE(OvCore::ResourceManagement::SoundManager).GetResource(p_receivedData.first); resource) - { - p_data = resource; - widget.content = p_receivedData.first; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - } - }; - - widget.lineBreak = false; - - auto& selectButtonSound = rightSide.CreateWidget("..."); - selectButtonSound.lineBreak = false; - { - auto token = std::make_shared(true); - selectButtonSound.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] - { - if (GUIDrawer::s_assetPickerProvider) - { - std::weak_ptr weak = token; - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::SOUND, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) - { - if (weak.expired()) return; - if (auto resource = OVSERVICE(OvCore::ResourceManagement::SoundManager).GetResource(p_path); resource) - { - p_data = resource; - widget.content = p_path; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - }); - } - }; - } - - auto & resetButton = rightSide.CreateWidget("Clear"); - resetButton.idleBackgroundColor = ClearButtonColor; - resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] - { - p_data = nullptr; - widget.content = "Empty"; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - }; - - return widget; + return DrawResourceWidget(p_root, p_name, p_data, OvTools::Utils::PathParser::EFileType::SOUND, p_updateNotifier); } OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawAsset(OvUI::Internal::WidgetContainer& p_root, const std::string& p_name, std::string& p_data, OvTools::Eventing::Event<>* p_updateNotifier) @@ -445,10 +293,10 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawAsset(OvUI::Internal auto token = std::make_shared(true); selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] { - if (GUIDrawer::s_assetPickerProvider) + if (__ASSET_PICKER_PROVIDER) { std::weak_ptr weak = token; - GUIDrawer::s_assetPickerProvider(OvTools::Utils::PathParser::EFileType::UNKNOWN, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) + __ASSET_PICKER_PROVIDER(OvTools::Utils::PathParser::EFileType::UNKNOWN, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) { if (weak.expired()) return; p_data = p_path; From e3645d91ffb721850f619a3a4ac9fabb295f45a7 Mon Sep 17 00:00:00 2001 From: Adrien GIVRY Date: Thu, 9 Apr 2026 16:30:58 -0400 Subject: [PATCH 4/9] Improved window sizing and positioning --- .../include/OvEditor/Panels/AssetPicker.h | 14 +++++++-- Sources/OvEditor/src/OvEditor/Core/Editor.cpp | 6 +++- .../src/OvEditor/Panels/AssetPicker.cpp | 29 +++++++++++++++++-- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h b/Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h index 3fe169584..37d5f9898 100644 --- a/Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h +++ b/Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -39,10 +40,17 @@ namespace OvEditor::Panels /** * Open the picker filtered by the given file type. - * @param p_fileType Asset type to show (UNKNOWN = all known types) - * @param p_callback Called with the selected resource path when the user picks an asset + * @param p_fileType Asset type to show (UNKNOWN = all known types) + * @param p_buttonMin Screen-space top-left of the button that triggered the picker + * @param p_buttonMax Screen-space bottom-right of the button that triggered the picker + * @param p_callback Called with the selected resource path when the user picks an asset */ - void Open(OvTools::Utils::PathParser::EFileType p_fileType, std::function p_callback); + void Open( + OvTools::Utils::PathParser::EFileType p_fileType, + OvMaths::FVector2 p_buttonMin, + OvMaths::FVector2 p_buttonMax, + std::function p_callback + ); private: void Populate(); diff --git a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp index 1084f2770..ec71ee712 100644 --- a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp +++ b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp @@ -6,6 +6,8 @@ #include +#include + #include #include @@ -91,7 +93,9 @@ void OvEditor::Core::Editor::SetupUI() OvCore::Helpers::GUIDrawer::SetAssetPickerProvider( [this](OvTools::Utils::PathParser::EFileType p_type, std::function p_callback) { - m_assetPicker->Open(p_type, std::move(p_callback)); + const ImVec2 min = ImGui::GetItemRectMin(); + const ImVec2 max = ImGui::GetItemRectMax(); + m_assetPicker->Open(p_type, { min.x, min.y }, { max.x, max.y }, std::move(p_callback)); } ); } diff --git a/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp b/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp index b82d3f6a6..d001ecc37 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include #include @@ -41,7 +43,7 @@ AssetPicker::AssetPicker( const OvUI::Settings::PanelWindowSettings& p_windowSettings) : PanelWindow(p_title, p_opened, p_windowSettings) { - minSize = { 300.f, 400.f }; + minSize = { 250.f, 250.f }; m_searchField = &CreateWidget("", "Search"); m_searchField->ContentChangedEvent += [this](const std::string& p_text) @@ -53,12 +55,35 @@ AssetPicker::AssetPicker( m_assetListGroup = &CreateWidget(); } -void AssetPicker::Open(PathParser::EFileType p_fileType, std::function p_callback) +void AssetPicker::Open(PathParser::EFileType p_fileType, OvMaths::FVector2 p_buttonMin, OvMaths::FVector2 p_buttonMax, std::function p_callback) { m_fileType = p_fileType; m_callback = std::move(p_callback); m_searchField->content = ""; Populate(); + + const ImVec2 display = ImGui::GetIO().DisplaySize; + const float winW = minSize.x; + const float winH = minSize.y; + + // Default: top-left corner of the window aligned with the bottom-left of the button + float x = p_buttonMin.x; + float y = p_buttonMax.y; + + // Not enough room below → open above the button instead + if (y + winH > display.y) + y = p_buttonMin.y - winH; + + // Not enough room to the right → right-align to button's right edge + if (x + winW > display.x) + x = p_buttonMax.x - winW; + + // Keep fully on-screen + x = std::max(0.f, x); + y = std::max(0.f, y); + + SetPosition({ x, y }); + PanelWindow::Open(); Focus(); } From bd2b9950b40869d4d6c191818cf9040c84fd8311 Mon Sep 17 00:00:00 2001 From: Adrien GIVRY Date: Thu, 9 Apr 2026 16:52:05 -0400 Subject: [PATCH 5/9] Fixed material renderer to properly use GUIDrawer --- .../OvCore/ECS/Components/CMaterialRenderer.h | 2 +- .../ECS/Components/CMaterialRenderer.cpp | 62 ++++--------------- 2 files changed, 12 insertions(+), 52 deletions(-) diff --git a/Sources/OvCore/include/OvCore/ECS/Components/CMaterialRenderer.h b/Sources/OvCore/include/OvCore/ECS/Components/CMaterialRenderer.h index ac18d92c2..aae8fd870 100644 --- a/Sources/OvCore/include/OvCore/ECS/Components/CMaterialRenderer.h +++ b/Sources/OvCore/include/OvCore/ECS/Components/CMaterialRenderer.h @@ -27,7 +27,7 @@ namespace OvCore::ECS::Components { public: using MaterialList = std::array; - using MaterialField = std::array, kMaxMaterialCount>; + using MaterialField = std::array, kMaxMaterialCount>; /** * Constructor diff --git a/Sources/OvCore/src/OvCore/ECS/Components/CMaterialRenderer.cpp b/Sources/OvCore/src/OvCore/ECS/Components/CMaterialRenderer.cpp index a9f154e93..ac1859401 100644 --- a/Sources/OvCore/src/OvCore/ECS/Components/CMaterialRenderer.cpp +++ b/Sources/OvCore/src/OvCore/ECS/Components/CMaterialRenderer.cpp @@ -11,17 +11,11 @@ #include #include #include +#include #include -#include - -#include -#include -#include -#include #include -#include -#include +#include #include OvCore::ECS::Components::CMaterialRenderer::CMaterialRenderer(ECS::Actor & p_owner) : AComponent(p_owner) @@ -146,46 +140,13 @@ void OvCore::ECS::Components::CMaterialRenderer::OnDeserialize(tinyxml2::XMLDocu OvCore::Helpers::Serializer::DeserializeUint32(p_doc, p_node, "visibility_flags", reinterpret_cast(m_visibilityFlags)); } -std::array CustomMaterialDrawer(OvUI::Internal::WidgetContainer& p_root, const std::string& p_name, OvCore::Resources::Material*& p_data) +std::array CustomMaterialDrawer(OvUI::Internal::WidgetContainer& p_root, const std::string& p_name, OvCore::Resources::Material*& p_data) { - using namespace OvCore::Helpers; - - std::array widgets; - - widgets[0] = &p_root.CreateWidget(p_name, GUIDrawer::TitleColor); - - std::string displayedText = (p_data ? p_data->path : std::string("Empty")); - auto & rightSide = p_root.CreateWidget(); - - auto& widget = rightSide.CreateWidget(displayedText); - - widgets[1] = &widget; - - widget.AddPlugin>>("File").DataReceivedEvent += [&widget, &p_data](auto p_receivedData) - { - if (OvTools::Utils::PathParser::GetFileType(p_receivedData.first) == OvTools::Utils::PathParser::EFileType::MATERIAL) - { - if (auto resource = OVSERVICE(OvCore::ResourceManagement::MaterialManager).GetResource(p_receivedData.first); resource) - { - p_data = resource; - widget.content = p_receivedData.first; - } - } - }; - - widget.lineBreak = false; - - auto & resetButton = rightSide.CreateWidget("Clear"); - resetButton.idleBackgroundColor = GUIDrawer::ClearButtonColor; - resetButton.ClickedEvent += [&widget, &p_data] - { - p_data = nullptr; - widget.content = "Empty"; - }; - - widgets[2] = &resetButton; - - return widgets; + const size_t before = p_root.GetWidgets().size(); + OvCore::Helpers::GUIDrawer::DrawMaterial(p_root, p_name, p_data, nullptr); + auto& widgets = p_root.GetWidgets(); + // DrawMaterial adds exactly 2 widgets: [before]=TextColored title, [before+1]=Group rightSide + return { widgets[before].first, widgets[before + 1].first }; } void OvCore::ECS::Components::CMaterialRenderer::OnInspector(OvUI::Internal::WidgetContainer & p_root) @@ -239,12 +200,11 @@ void OvCore::ECS::Components::CMaterialRenderer::UpdateMaterialList() { if (m_materialFields[i][0]) { - bool enabled = !m_materialNames[i].empty(); + const bool enabled = !m_materialNames[i].empty(); m_materialFields[i][0]->enabled = enabled; m_materialFields[i][1]->enabled = enabled; - m_materialFields[i][2]->enabled = enabled; - const auto formattedName = std::format("Material [{}]: <{}>", i, m_materialNames[i]); - reinterpret_cast(m_materialFields[i][0]) ->content = formattedName; + static_cast(m_materialFields[i][0])->content = + std::format("Material [{}]: <{}>", i, m_materialNames[i]); } } } From b9ce7c0102c846019612d0bcbbd3d3867301a1b3 Mon Sep 17 00:00:00 2001 From: Adrien GIVRY Date: Thu, 9 Apr 2026 17:03:09 -0400 Subject: [PATCH 6/9] More cleanup --- .../OvCore/src/OvCore/Helpers/GUIDrawer.cpp | 163 ++++++++---------- Sources/OvEditor/src/OvEditor/Core/Editor.cpp | 4 - 2 files changed, 75 insertions(+), 92 deletions(-) diff --git a/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp b/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp index fbb14fd57..febf96e48 100644 --- a/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp +++ b/Sources/OvCore/src/OvCore/Helpers/GUIDrawer.cpp @@ -29,6 +29,7 @@ #include #include "OvCore/Helpers/GUIDrawer.h" +#include "OvUI/Widgets/Buttons/AButton.h" const OvUI::Types::Color OvCore::Helpers::GUIDrawer::TitleColor = { 0.85f, 0.65f, 0.0f }; const OvUI::Types::Color OvCore::Helpers::GUIDrawer::ClearButtonColor = { 0.5f, 0.0f, 0.0f }; @@ -116,6 +117,25 @@ void OvCore::Helpers::GUIDrawer::DrawColor(OvUI::Internal::WidgetContainer & p_r namespace { + void AddSelectButton( + OvUI::Widgets::Buttons::AButton& p_button, + OvTools::Utils::PathParser::EFileType p_fileType, + std::function p_onSelect) + { + auto token = std::make_shared(true); + p_button.ClickedEvent += [p_fileType, p_onSelect = std::move(p_onSelect), token = std::move(token)] + { + if (__ASSET_PICKER_PROVIDER) + { + std::weak_ptr weak = token; + __ASSET_PICKER_PROVIDER(p_fileType, [p_onSelect, weak](const std::string& p_path) + { + if (!weak.expired()) p_onSelect(p_path); + }); + } + }; + } + template OvUI::Widgets::Texts::Text& DrawResourceWidget( OvUI::Internal::WidgetContainer& p_root, @@ -150,27 +170,16 @@ namespace auto& selectButton = rightSide.CreateWidget("..."); selectButton.lineBreak = false; + AddSelectButton(selectButton, p_fileType, [&widget, &p_data, p_updateNotifier](const std::string& p_path) { - auto token = std::make_shared(true); - selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, p_fileType, token = std::move(token)] + if (auto resource = OVSERVICE(TResourceManager).GetResource(p_path); resource) { - if (__ASSET_PICKER_PROVIDER) - { - std::weak_ptr weak = token; - __ASSET_PICKER_PROVIDER(p_fileType, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) - { - if (weak.expired()) return; - if (auto resource = OVSERVICE(TResourceManager).GetResource(p_path); resource) - { - p_data = resource; - widget.content = p_path; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - }); - } - }; - } + p_data = resource; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = OvCore::Helpers::GUIDrawer::ClearButtonColor; @@ -218,29 +227,18 @@ OvUI::Widgets::Visual::Image& OvCore::Helpers::GUIDrawer::DrawTexture(OvUI::Inte auto& selectButton = rightSide.CreateWidget("..."); selectButton.lineBreak = false; + AddSelectButton(selectButton, OvTools::Utils::PathParser::EFileType::TEXTURE, [&widget, &p_data, p_updateNotifier](const std::string& p_path) { - auto token = std::make_shared(true); - selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] + if (auto resource = OVSERVICE(OvCore::ResourceManagement::TextureManager).GetResource(p_path); resource) { - if (__ASSET_PICKER_PROVIDER) - { - std::weak_ptr weak = token; - __ASSET_PICKER_PROVIDER(OvTools::Utils::PathParser::EFileType::TEXTURE, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) - { - if (weak.expired()) return; - if (auto resource = OVSERVICE(OvCore::ResourceManagement::TextureManager).GetResource(p_path); resource) - { - p_data = resource; - widget.textureID.id = resource->GetTexture().GetID(); - if (p_updateNotifier) - p_updateNotifier->Invoke(); - } - }); - } - }; - } + p_data = resource; + widget.textureID.id = resource->GetTexture().GetID(); + if (p_updateNotifier) + p_updateNotifier->Invoke(); + } + }); - auto& resetButton = rightSide.CreateWidget("Clear"); + auto& resetButton = rightSide.CreateWidget("Clear"); resetButton.idleBackgroundColor = ClearButtonColor; resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] { @@ -270,55 +268,44 @@ OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawSound(OvUI::Internal OvUI::Widgets::Texts::Text& OvCore::Helpers::GUIDrawer::DrawAsset(OvUI::Internal::WidgetContainer& p_root, const std::string& p_name, std::string& p_data, OvTools::Eventing::Event<>* p_updateNotifier) { - CreateTitle(p_root, p_name); - - const std::string displayedText = (p_data.empty() ? std::string("Empty") : p_data); - auto& rightSide = p_root.CreateWidget(); - - auto& widget = rightSide.CreateWidget(displayedText); - - widget.AddPlugin>>("File").DataReceivedEvent += [&widget, &p_data, p_updateNotifier](auto p_receivedData) - { - p_data = p_receivedData.first; - widget.content = p_receivedData.first; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - }; - - widget.lineBreak = false; - - auto& selectButton = rightSide.CreateWidget("..."); - selectButton.lineBreak = false; - { - auto token = std::make_shared(true); - selectButton.ClickedEvent += [&widget, &p_data, p_updateNotifier, token = std::move(token)] - { - if (__ASSET_PICKER_PROVIDER) - { - std::weak_ptr weak = token; - __ASSET_PICKER_PROVIDER(OvTools::Utils::PathParser::EFileType::UNKNOWN, [&widget, &p_data, p_updateNotifier, weak](const std::string& p_path) - { - if (weak.expired()) return; - p_data = p_path; - widget.content = p_path; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - }); - } - }; - } - - auto& resetButton = rightSide.CreateWidget("Clear"); - resetButton.idleBackgroundColor = ClearButtonColor; - resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] - { - p_data = ""; - widget.content = "Empty"; - if (p_updateNotifier) - p_updateNotifier->Invoke(); - }; - - return widget; + CreateTitle(p_root, p_name); + + const std::string displayedText = (p_data.empty() ? std::string("Empty") : p_data); + auto& rightSide = p_root.CreateWidget(); + + auto& widget = rightSide.CreateWidget(displayedText); + + widget.AddPlugin>>("File").DataReceivedEvent += [&widget, &p_data, p_updateNotifier](auto p_receivedData) + { + p_data = p_receivedData.first; + widget.content = p_receivedData.first; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + }; + + widget.lineBreak = false; + + auto& selectButton = rightSide.CreateWidget("..."); + selectButton.lineBreak = false; + AddSelectButton(selectButton, OvTools::Utils::PathParser::EFileType::UNKNOWN, [&widget, &p_data, p_updateNotifier](const std::string& p_path) + { + p_data = p_path; + widget.content = p_path; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + }); + + auto& resetButton = rightSide.CreateWidget("Clear"); + resetButton.idleBackgroundColor = ClearButtonColor; + resetButton.ClickedEvent += [&widget, &p_data, p_updateNotifier] + { + p_data = ""; + widget.content = "Empty"; + if (p_updateNotifier) + p_updateNotifier->Invoke(); + }; + + return widget; } void OvCore::Helpers::GUIDrawer::DrawBoolean(OvUI::Internal::WidgetContainer & p_root, const std::string & p_name, std::function p_gatherer, std::function p_provider) diff --git a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp index ec71ee712..3b5fa3f6a 100644 --- a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp +++ b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp @@ -82,10 +82,6 @@ void OvEditor::Core::Editor::SetupUI() OvUI::Settings::PanelWindowSettings pickerSettings; pickerSettings.closable = true; - pickerSettings.resizable = true; - pickerSettings.movable = true; - pickerSettings.dockable = false; - pickerSettings.scrollable = true; m_assetPicker = std::make_unique("Asset Picker", false, pickerSettings); m_canvas.AddPanel(*m_assetPicker); From 02e52db48d73d1fd8d91acf87cdebe00b5811797 Mon Sep 17 00:00:00 2001 From: Adrien GIVRY Date: Thu, 9 Apr 2026 17:17:23 -0400 Subject: [PATCH 7/9] Added scroll to top when opening --- Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp b/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp index d001ecc37..60ccd536d 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp @@ -61,6 +61,7 @@ void AssetPicker::Open(PathParser::EFileType p_fileType, OvMaths::FVector2 p_but m_callback = std::move(p_callback); m_searchField->content = ""; Populate(); + ScrollToTop(); const ImVec2 display = ImGui::GetIO().DisplaySize; const float winW = minSize.x; From 03b2400fe51f8a269fa95e6eba727b9d58a9997d Mon Sep 17 00:00:00 2001 From: Adrien GIVRY Date: Thu, 9 Apr 2026 19:50:35 -0400 Subject: [PATCH 8/9] Cleaned up asset picker providing --- Sources/OvEditor/src/OvEditor/Core/Editor.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp index 3b5fa3f6a..b0d7e09d6 100644 --- a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp +++ b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp @@ -4,6 +4,7 @@ * @licence: MIT */ +#include "OvUI/Settings/PanelWindowSettings.h" #include #include @@ -80,15 +81,16 @@ void OvEditor::Core::Editor::SetupUI() m_canvas.MakeDockspace(true); m_context.uiManager->SetCanvas(m_canvas); - OvUI::Settings::PanelWindowSettings pickerSettings; - pickerSettings.closable = true; + m_assetPicker = std::make_unique( + "Asset Picker", + false, + OvUI::Settings::PanelWindowSettings{ .closable = true } + ); - m_assetPicker = std::make_unique("Asset Picker", false, pickerSettings); m_canvas.AddPanel(*m_assetPicker); OvCore::Helpers::GUIDrawer::SetAssetPickerProvider( - [this](OvTools::Utils::PathParser::EFileType p_type, std::function p_callback) - { + [this](OvTools::Utils::PathParser::EFileType p_type, std::function p_callback) { const ImVec2 min = ImGui::GetItemRectMin(); const ImVec2 max = ImGui::GetItemRectMax(); m_assetPicker->Open(p_type, { min.x, min.y }, { max.x, max.y }, std::move(p_callback)); From 1215c9e94fb0e03ee693c213aa5289b807e11df8 Mon Sep 17 00:00:00 2001 From: Adrien GIVRY Date: Thu, 9 Apr 2026 20:19:03 -0400 Subject: [PATCH 9/9] More code cleanup --- .../include/OvEditor/Panels/AssetPicker.h | 3 --- Sources/OvEditor/src/OvEditor/Core/Editor.cpp | 23 +++++-------------- .../src/OvEditor/Panels/AssetPicker.cpp | 13 +++++++---- Sources/OvUI/include/OvUI/Core/UIManager.h | 7 ++++++ Sources/OvUI/src/OvUI/Core/UIManager.cpp | 8 +++++++ 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h b/Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h index 37d5f9898..5e7534eeb 100644 --- a/Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h +++ b/Sources/OvEditor/include/OvEditor/Panels/AssetPicker.h @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -47,8 +46,6 @@ namespace OvEditor::Panels */ void Open( OvTools::Utils::PathParser::EFileType p_fileType, - OvMaths::FVector2 p_buttonMin, - OvMaths::FVector2 p_buttonMax, std::function p_callback ); diff --git a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp index b0d7e09d6..5d7986f4d 100644 --- a/Sources/OvEditor/src/OvEditor/Core/Editor.cpp +++ b/Sources/OvEditor/src/OvEditor/Core/Editor.cpp @@ -4,11 +4,8 @@ * @licence: MIT */ -#include "OvUI/Settings/PanelWindowSettings.h" #include -#include - #include #include @@ -30,13 +27,14 @@ #include #include #include +#include using namespace OvCore::ResourceManagement; using namespace OvEditor::Panels; using namespace OvRendering::Resources::Loaders; using namespace OvRendering::Resources::Parsers; -OvEditor::Core::Editor::Editor(Context& p_context) : +OvEditor::Core::Editor::Editor(Context& p_context) : m_context(p_context), m_panelsManager(m_canvas), m_editorActions(m_context, m_panelsManager) @@ -91,9 +89,7 @@ void OvEditor::Core::Editor::SetupUI() OvCore::Helpers::GUIDrawer::SetAssetPickerProvider( [this](OvTools::Utils::PathParser::EFileType p_type, std::function p_callback) { - const ImVec2 min = ImGui::GetItemRectMin(); - const ImVec2 max = ImGui::GetItemRectMax(); - m_assetPicker->Open(p_type, { min.x, min.y }, { max.x, max.y }, std::move(p_callback)); + m_assetPicker->Open(p_type, std::move(p_callback)); } ); } @@ -106,16 +102,9 @@ void OvEditor::Core::Editor::PreUpdate() void OvEditor::Core::Editor::Update(float p_deltaTime) { - // Disable ImGui mouse update if the mouse cursor is disabled. - // i.e. when locked during gameplay, or when a view is being interacted - if (m_context.window->GetCursorMode() == OvWindowing::Cursor::ECursorMode::DISABLED) - { - ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouse; - } - else - { - ImGui::GetIO().ConfigFlags &= ~(ImGuiConfigFlags_NoMouse); - } + // Disable mouse input when the cursor is locked during gameplay or view interaction. + const bool mouseEnabled = m_context.window->GetCursorMode() != OvWindowing::Cursor::ECursorMode::DISABLED; + m_context.uiManager->EnableMouse(mouseEnabled); HandleGlobalShortcuts(); UpdateCurrentEditorMode(p_deltaTime); diff --git a/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp b/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp index 60ccd536d..25b8ead45 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/AssetPicker.cpp @@ -55,7 +55,7 @@ AssetPicker::AssetPicker( m_assetListGroup = &CreateWidget(); } -void AssetPicker::Open(PathParser::EFileType p_fileType, OvMaths::FVector2 p_buttonMin, OvMaths::FVector2 p_buttonMax, std::function p_callback) +void AssetPicker::Open(PathParser::EFileType p_fileType, std::function p_callback) { m_fileType = p_fileType; m_callback = std::move(p_callback); @@ -67,17 +67,20 @@ void AssetPicker::Open(PathParser::EFileType p_fileType, OvMaths::FVector2 p_but const float winW = minSize.x; const float winH = minSize.y; + const ImVec2 buttonMin = ImGui::GetItemRectMin(); + const ImVec2 buttonMax = ImGui::GetItemRectMax(); + // Default: top-left corner of the window aligned with the bottom-left of the button - float x = p_buttonMin.x; - float y = p_buttonMax.y; + float x = buttonMin.x; + float y = buttonMax.y; // Not enough room below → open above the button instead if (y + winH > display.y) - y = p_buttonMin.y - winH; + y = buttonMin.y - winH; // Not enough room to the right → right-align to button's right edge if (x + winW > display.x) - x = p_buttonMax.x - winW; + x = buttonMax.x - winW; // Keep fully on-screen x = std::max(0.f, x); diff --git a/Sources/OvUI/include/OvUI/Core/UIManager.h b/Sources/OvUI/include/OvUI/Core/UIManager.h index 1c4e44d91..f8fa7608c 100644 --- a/Sources/OvUI/include/OvUI/Core/UIManager.h +++ b/Sources/OvUI/include/OvUI/Core/UIManager.h @@ -102,6 +102,13 @@ namespace OvUI::Core */ void ResetLayout(const std::string & p_config) const; + /** + * Enable or disable mouse input in ImGui. + * Typically disabled when the cursor is locked during gameplay. + * @param p_value + */ + void EnableMouse(bool p_value); + /** * Return true if the docking system is enabled */ diff --git a/Sources/OvUI/src/OvUI/Core/UIManager.cpp b/Sources/OvUI/src/OvUI/Core/UIManager.cpp index c2d757c7a..b6362b6bc 100644 --- a/Sources/OvUI/src/OvUI/Core/UIManager.cpp +++ b/Sources/OvUI/src/OvUI/Core/UIManager.cpp @@ -129,6 +129,14 @@ float OvUI::Core::UIManager::GetEditorLayoutAutosaveFrequency(float p_frequeny) return ImGui::GetIO().IniSavingRate; } +void OvUI::Core::UIManager::EnableMouse(bool p_value) +{ + if (p_value) + ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouse; + else + ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouse; +} + void OvUI::Core::UIManager::EnableDocking(bool p_value) { m_dockingState = p_value;