diff --git a/Source/ImGui/Private/Editor/ImGuiEditor.cpp b/Source/ImGui/Private/Editor/ImGuiEditor.cpp index 026e8c8..cf5b1f9 100644 --- a/Source/ImGui/Private/Editor/ImGuiEditor.cpp +++ b/Source/ImGui/Private/Editor/ImGuiEditor.cpp @@ -50,7 +50,7 @@ FImGuiEditor::~FImGuiEditor() void FImGuiEditor::Register() { // Only register after UImGuiSettings class is initialized (necessary to check in early loading stages). - if (!bSettingsRegistered && GImGuiSettings) + if (!bSettingsRegistered && UImGuiSettings::Get()) { if (ISettingsModule* SettingsModule = GetSettingsModule()) { @@ -59,7 +59,7 @@ void FImGuiEditor::Register() SettingsModule->RegisterSettings(SETTINGS_CONTAINER, LOCTEXT("ImGuiSettingsName", "ImGui"), LOCTEXT("ImGuiSettingsDescription", "Configure the Unreal ImGui plugin."), - GImGuiSettings); + UImGuiSettings::Get()); } } diff --git a/Source/ImGui/Private/ImGuiDemo.cpp b/Source/ImGui/Private/ImGuiDemo.cpp index 6d4d036..c6fd32f 100644 --- a/Source/ImGui/Private/ImGuiDemo.cpp +++ b/Source/ImGui/Private/ImGuiDemo.cpp @@ -4,13 +4,13 @@ #include "ImGuiDemo.h" -#include "ImGuiModuleManager.h" +#include "ImGuiModuleProperties.h" // Demo copied (with minor modifications) from ImGui examples. See https://github.com/ocornut/imgui. void FImGuiDemo::DrawControls(int32 ContextIndex) { - if (ModuleManager.GetProperties().ShowDemo()) + if (Properties.ShowDemo()) { const int32 ContextBit = ContextIndex < 0 ? 0 : 1 << ContextIndex; diff --git a/Source/ImGui/Private/ImGuiDemo.h b/Source/ImGui/Private/ImGuiDemo.h index 4507442..3992fb8 100644 --- a/Source/ImGui/Private/ImGuiDemo.h +++ b/Source/ImGui/Private/ImGuiDemo.h @@ -4,15 +4,15 @@ #include -class FImGuiModuleManager; +class FImGuiModuleProperties; // Widget drawing ImGui demo. class FImGuiDemo { public: - FImGuiDemo(FImGuiModuleManager& InModuleManager) - : ModuleManager(InModuleManager) + FImGuiDemo(FImGuiModuleProperties& InProperties) + : Properties(InProperties) { } @@ -20,7 +20,7 @@ public: private: - FImGuiModuleManager& ModuleManager; + FImGuiModuleProperties& Properties; ImVec4 ClearColor = ImColor{ 114, 144, 154 }; diff --git a/Source/ImGui/Private/ImGuiInputHandler.cpp b/Source/ImGui/Private/ImGuiInputHandler.cpp index 5f1b089..def5458 100644 --- a/Source/ImGui/Private/ImGuiInputHandler.cpp +++ b/Source/ImGui/Private/ImGuiInputHandler.cpp @@ -92,9 +92,10 @@ namespace return (CheckBoxState == ECheckBoxState::Undetermined) || ((CheckBoxState == ECheckBoxState::Checked) == bValue); } - bool AreModifiersMatching(const FImGuiKeyInfo& KeyInfo, const FKeyEvent& KeyEvent) + bool IsMatchingEvent(const FKeyEvent& KeyEvent, const FImGuiKeyInfo& KeyInfo) { - return IsMatching(KeyInfo.Shift, KeyEvent.IsShiftDown()) + return (KeyInfo.Key == KeyEvent.GetKey()) + && IsMatching(KeyInfo.Shift, KeyEvent.IsShiftDown()) && IsMatching(KeyInfo.Ctrl, KeyEvent.IsControlDown()) && IsMatching(KeyInfo.Alt, KeyEvent.IsAltDown()) && IsMatching(KeyInfo.Cmd, KeyEvent.IsCommandDown()); @@ -103,9 +104,7 @@ namespace bool UImGuiInputHandler::IsToggleInputEvent(const FKeyEvent& KeyEvent) const { - return GImGuiSettings - && (KeyEvent.GetKey() == GImGuiSettings->GetToggleInputKey().Key) - && AreModifiersMatching(GImGuiSettings->GetToggleInputKey(), KeyEvent); + return IsMatchingEvent(KeyEvent, ModuleManager->GetSettings().GetToggleInputKey()); } bool UImGuiInputHandler::HasImGuiActiveItem() const diff --git a/Source/ImGui/Private/ImGuiInputHandlerFactory.cpp b/Source/ImGui/Private/ImGuiInputHandlerFactory.cpp index 3e599a5..211e404 100644 --- a/Source/ImGui/Private/ImGuiInputHandlerFactory.cpp +++ b/Source/ImGui/Private/ImGuiInputHandlerFactory.cpp @@ -5,23 +5,18 @@ #include "ImGuiInputHandlerFactory.h" #include "ImGuiInputHandler.h" -#include "ImGuiSettings.h" -UImGuiInputHandler* FImGuiInputHandlerFactory::NewHandler(FImGuiModuleManager* ModuleManager, UGameViewportClient* GameViewport, int32 ContextIndex) +UImGuiInputHandler* FImGuiInputHandlerFactory::NewHandler(const FStringClassReference& HandlerClassReference, FImGuiModuleManager* ModuleManager, UGameViewportClient* GameViewport, int32 ContextIndex) { UClass* HandlerClass = nullptr; - if (GImGuiSettings) + if (HandlerClassReference.IsValid()) { - const auto& HandlerClassReference = GImGuiSettings->GetImGuiInputHandlerClass(); - if (HandlerClassReference.IsValid()) - { - HandlerClass = HandlerClassReference.TryLoadClass(); + HandlerClass = HandlerClassReference.TryLoadClass(); - if (!HandlerClass) - { - UE_LOG(LogImGuiInputHandler, Error, TEXT("Couldn't load ImGui Input Handler class '%s'."), *HandlerClassReference.ToString()); - } + if (!HandlerClass) + { + UE_LOG(LogImGuiInputHandler, Error, TEXT("Couldn't load ImGui Input Handler class '%s'."), *HandlerClassReference.ToString()); } } diff --git a/Source/ImGui/Private/ImGuiInputHandlerFactory.h b/Source/ImGui/Private/ImGuiInputHandlerFactory.h index 3186317..3ed9365 100644 --- a/Source/ImGui/Private/ImGuiInputHandlerFactory.h +++ b/Source/ImGui/Private/ImGuiInputHandlerFactory.h @@ -10,7 +10,7 @@ class FImGuiInputHandlerFactory { public: - static UImGuiInputHandler* NewHandler(FImGuiModuleManager* ModuleManager, UGameViewportClient* GameViewport, int32 ContextIndex); + static UImGuiInputHandler* NewHandler(const FStringClassReference& HandlerClassReference, FImGuiModuleManager* ModuleManager, UGameViewportClient* GameViewport, int32 ContextIndex); static void ReleaseHandler(UImGuiInputHandler* Handler); }; diff --git a/Source/ImGui/Private/ImGuiModuleCommands.cpp b/Source/ImGui/Private/ImGuiModuleCommands.cpp index 464e805..84f4179 100644 --- a/Source/ImGui/Private/ImGuiModuleCommands.cpp +++ b/Source/ImGui/Private/ImGuiModuleCommands.cpp @@ -4,118 +4,70 @@ #include "ImGuiModuleCommands.h" -#include "ImGuiModuleManager.h" -#include "ImGuiSettings.h" #include "Utilities/DebugExecBindings.h" -namespace CommandNames -{ - namespace - { - const TCHAR* ToggleInput = TEXT("ImGui.ToggleInput"); - const TCHAR* ToggleKeyboardNavigation = TEXT("ImGui.ToggleKeyboardNavigation"); - const TCHAR* ToggleGamepadNavigation = TEXT("ImGui.ToggleGamepadNavigation"); - const TCHAR* ToggleKeyboardInputSharing = TEXT("ImGui.ToggleKeyboardInputSharing"); - const TCHAR* ToggleGamepadInputSharing = TEXT("ImGui.ToggleGamepadInputSharing"); - const TCHAR* ToggleDemo = TEXT("ImGui.ToggleDemo"); - } -} +const TCHAR* const FImGuiModuleCommands::ToggleInput = TEXT("ImGui.ToggleInput"); +const TCHAR* const FImGuiModuleCommands::ToggleKeyboardNavigation = TEXT("ImGui.ToggleKeyboardNavigation"); +const TCHAR* const FImGuiModuleCommands::ToggleGamepadNavigation = TEXT("ImGui.ToggleGamepadNavigation"); +const TCHAR* const FImGuiModuleCommands::ToggleKeyboardInputSharing = TEXT("ImGui.ToggleKeyboardInputSharing"); +const TCHAR* const FImGuiModuleCommands::ToggleGamepadInputSharing = TEXT("ImGui.ToggleGamepadInputSharing"); +const TCHAR* const FImGuiModuleCommands::ToggleDemo = TEXT("ImGui.ToggleDemo"); -FImGuiModuleCommands::FImGuiModuleCommands(FImGuiModuleManager& InModuleManager) - : ModuleManager(InModuleManager) - , ToggleInputCommand(CommandNames::ToggleInput, +FImGuiModuleCommands::FImGuiModuleCommands(FImGuiModuleProperties& InProperties) + : Properties(InProperties) + , ToggleInputCommand(ToggleInput, TEXT("Toggle ImGui input mode."), - FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleInput)) - , ToggleKeyboardNavigationCommand(CommandNames::ToggleKeyboardNavigation, + FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleInputImpl)) + , ToggleKeyboardNavigationCommand(ToggleKeyboardNavigation, TEXT("Toggle ImGui keyboard navigation."), - FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleKeyboardNavigation)) - , ToggleGamepadNavigationCommand(CommandNames::ToggleGamepadNavigation, + FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleKeyboardNavigationImpl)) + , ToggleGamepadNavigationCommand(ToggleGamepadNavigation, TEXT("Toggle ImGui gamepad navigation."), - FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleGamepadNavigation)) - , ToggleKeyboardInputSharingCommand(CommandNames::ToggleKeyboardInputSharing, + FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleGamepadNavigationImpl)) + , ToggleKeyboardInputSharingCommand(ToggleKeyboardInputSharing, TEXT("Toggle ImGui keyboard input sharing."), - FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleKeyboardInputSharing)) - , ToggleGamepadInputSharingCommand(CommandNames::ToggleGamepadInputSharing, + FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleKeyboardInputSharingImpl)) + , ToggleGamepadInputSharingCommand(ToggleGamepadInputSharing, TEXT("Toggle ImGui gamepad input sharing."), - FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleGamepadInputSharing)) - , ToggleDemoCommand(CommandNames::ToggleDemo, + FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleGamepadInputSharingImpl)) + , ToggleDemoCommand(ToggleDemo, TEXT("Toggle ImGui demo."), - FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleDemo)) + FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleDemoImpl)) { - // Delegate initializer to support settings loaded after this object creation (in stand-alone builds) and potential - // reloading of settings. - UImGuiSettings::OnSettingsLoaded().AddRaw(this, &FImGuiModuleCommands::InitializeSettings); - - // Call initializer to support settings already loaded (editor). - InitializeSettings(); } -FImGuiModuleCommands::~FImGuiModuleCommands() +void FImGuiModuleCommands::SetKeyBinding(const TCHAR* CommandName, const FImGuiKeyInfo& KeyInfo) { - UImGuiSettings::OnSettingsLoaded().RemoveAll(this); - UnregisterSettingsDelegates(); + DebugExecBindings::UpdatePlayerInputs(KeyInfo, CommandName); } -void FImGuiModuleCommands::InitializeSettings() +void FImGuiModuleCommands::ToggleInputImpl() { - RegisterSettingsDelegates(); - - // We manually update key bindings based on ImGui settings rather than using input configuration. This works out - // of the box in packed and staged builds and it helps to avoid ambiguities where ImGui settings are stored. - UpdateToggleInputKeyBinding(); + Properties.ToggleInput(); } -void FImGuiModuleCommands::RegisterSettingsDelegates() +void FImGuiModuleCommands::ToggleKeyboardNavigationImpl() { - if (GImGuiSettings && !GImGuiSettings->OnToggleInputKeyChanged.IsBoundToObject(this)) - { - GImGuiSettings->OnToggleInputKeyChanged.AddRaw(this, &FImGuiModuleCommands::UpdateToggleInputKeyBinding); - } + Properties.ToggleKeyboardNavigation(); } -void FImGuiModuleCommands::UnregisterSettingsDelegates() +void FImGuiModuleCommands::ToggleGamepadNavigationImpl() { - if (GImGuiSettings) - { - GImGuiSettings->OnToggleInputKeyChanged.RemoveAll(this); - } + Properties.ToggleGamepadNavigation(); } -void FImGuiModuleCommands::UpdateToggleInputKeyBinding() +void FImGuiModuleCommands::ToggleKeyboardInputSharingImpl() { - if (GImGuiSettings) - { - DebugExecBindings::UpdatePlayerInputs(GImGuiSettings->GetToggleInputKey(), CommandNames::ToggleInput); - } + Properties.ToggleKeyboardInputSharing(); } -void FImGuiModuleCommands::ToggleInput() +void FImGuiModuleCommands::ToggleGamepadInputSharingImpl() { - ModuleManager.GetProperties().ToggleInput(); + Properties.ToggleGamepadInputSharing(); } -void FImGuiModuleCommands::ToggleKeyboardNavigation() +void FImGuiModuleCommands::ToggleDemoImpl() { - ModuleManager.GetProperties().ToggleKeyboardNavigation(); -} - -void FImGuiModuleCommands::ToggleGamepadNavigation() -{ - ModuleManager.GetProperties().ToggleGamepadNavigation(); -} - -void FImGuiModuleCommands::ToggleKeyboardInputSharing() -{ - ModuleManager.GetProperties().ToggleKeyboardInputSharing(); -} - -void FImGuiModuleCommands::ToggleGamepadInputSharing() -{ - ModuleManager.GetProperties().ToggleGamepadInputSharing(); -} - -void FImGuiModuleCommands::ToggleDemo() -{ - ModuleManager.GetProperties().ToggleDemo(); + Properties.ToggleDemo(); } diff --git a/Source/ImGui/Private/ImGuiModuleCommands.h b/Source/ImGui/Private/ImGuiModuleCommands.h index 7012715..6eba968 100644 --- a/Source/ImGui/Private/ImGuiModuleCommands.h +++ b/Source/ImGui/Private/ImGuiModuleCommands.h @@ -5,39 +5,35 @@ #include -class FImGuiModuleManager; +struct FImGuiKeyInfo; +class FImGuiModuleProperties; // Manges ImGui module console commands. class FImGuiModuleCommands { public: - FImGuiModuleCommands(FImGuiModuleManager& InModuleManager); - ~FImGuiModuleCommands(); + static const TCHAR* const ToggleInput; + static const TCHAR* const ToggleKeyboardNavigation; + static const TCHAR* const ToggleGamepadNavigation; + static const TCHAR* const ToggleKeyboardInputSharing; + static const TCHAR* const ToggleGamepadInputSharing; + static const TCHAR* const ToggleDemo; + + FImGuiModuleCommands(FImGuiModuleProperties& InProperties); + + void SetKeyBinding(const TCHAR* CommandName, const FImGuiKeyInfo& KeyInfo); private: - FImGuiModuleCommands(const FImGuiModuleCommands&) = delete; - FImGuiModuleCommands& operator=(const FImGuiModuleCommands&) = delete; + void ToggleInputImpl(); + void ToggleKeyboardNavigationImpl(); + void ToggleGamepadNavigationImpl(); + void ToggleKeyboardInputSharingImpl(); + void ToggleGamepadInputSharingImpl(); + void ToggleDemoImpl(); - FImGuiModuleCommands(FImGuiModuleCommands&&) = delete; - FImGuiModuleCommands& operator=(FImGuiModuleCommands&&) = delete; - - void InitializeSettings(); - - void RegisterSettingsDelegates(); - void UnregisterSettingsDelegates(); - - void UpdateToggleInputKeyBinding(); - - void ToggleInput(); - void ToggleKeyboardNavigation(); - void ToggleGamepadNavigation(); - void ToggleKeyboardInputSharing(); - void ToggleGamepadInputSharing(); - void ToggleDemo(); - - FImGuiModuleManager& ModuleManager; + FImGuiModuleProperties& Properties; FAutoConsoleCommand ToggleInputCommand; FAutoConsoleCommand ToggleKeyboardNavigationCommand; diff --git a/Source/ImGui/Private/ImGuiModuleManager.cpp b/Source/ImGui/Private/ImGuiModuleManager.cpp index a5a64e8..aefb94a 100644 --- a/Source/ImGui/Private/ImGuiModuleManager.cpp +++ b/Source/ImGui/Private/ImGuiModuleManager.cpp @@ -13,8 +13,9 @@ FImGuiModuleManager::FImGuiModuleManager() - : ModuleCommands(*this) - , ImGuiDemo(*this) + : Commands(Properties) + , Settings(Properties, Commands) + , ImGuiDemo(Properties) { // Register in context manager to get information whenever a new context proxy is created. ContextManager.OnContextProxyCreated().AddRaw(this, &FImGuiModuleManager::OnContextProxyCreated); diff --git a/Source/ImGui/Private/ImGuiModuleManager.h b/Source/ImGui/Private/ImGuiModuleManager.h index 4cd5077..21514e8 100644 --- a/Source/ImGui/Private/ImGuiModuleManager.h +++ b/Source/ImGui/Private/ImGuiModuleManager.h @@ -6,6 +6,7 @@ #include "ImGuiDemo.h" #include "ImGuiModuleCommands.h" #include "ImGuiModuleProperties.h" +#include "ImGuiSettings.h" #include "SImGuiWidget.h" #include "TextureManager.h" @@ -18,6 +19,9 @@ class FImGuiModuleManager public: + // Get interface to module settings. + FImGuiModuleSettings& GetSettings() { return Settings; } + // Get interface to module state properties. FImGuiModuleProperties& GetProperties() { return Properties; } @@ -68,7 +72,10 @@ private: FImGuiModuleProperties Properties; // Tying module console commands to life-cycle of this manager and module. - FImGuiModuleCommands ModuleCommands; + FImGuiModuleCommands Commands; + + // ImGui settings proxy (valid in every loading stage). + FImGuiModuleSettings Settings; // Widget that we add to all created contexts to draw ImGui demo. FImGuiDemo ImGuiDemo; diff --git a/Source/ImGui/Private/ImGuiModuleProperties.cpp b/Source/ImGui/Private/ImGuiModuleProperties.cpp deleted file mode 100644 index 3c3fa7b..0000000 --- a/Source/ImGui/Private/ImGuiModuleProperties.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Distributed under the MIT License (MIT) (see accompanying LICENSE file) - -#include "ImGuiPrivatePCH.h" - -#include "ImGuiModuleProperties.h" - -#include "ImGuiSettings.h" - - -FImGuiModuleProperties::FImGuiModuleProperties() -{ - // Delegate initializer to support settings loaded after this object creation (in stand-alone builds) and potential - // reloading of settings. - UImGuiSettings::OnSettingsLoaded().AddRaw(this, &FImGuiModuleProperties::InitializeSettings); - - // Call initializer to support already loaded settings (editor). - InitializeSettings(); -} - -FImGuiModuleProperties::~FImGuiModuleProperties() -{ - UImGuiSettings::OnSettingsLoaded().RemoveAll(this); - UnregisterSettingsDelegates(); -} - -void FImGuiModuleProperties::InitializeSettings() -{ - if (GImGuiSettings) - { - RegisterSettingsDelegates(); - - bKeyboardInputShared = GImGuiSettings->ShareKeyboardInput(); - bGamepadInputShared = GImGuiSettings->ShareGamepadInput(); - } -} - -void FImGuiModuleProperties::RegisterSettingsDelegates() -{ - if (GImGuiSettings) - { - if (!GImGuiSettings->OnShareKeyboardInputChanged.IsBoundToObject(this)) - { - GImGuiSettings->OnShareKeyboardInputChanged.AddRaw(this, &FImGuiModuleProperties::SetKeyboardInputShared); - } - if (!GImGuiSettings->OnShareGamepadInputChanged.IsBoundToObject(this)) - { - GImGuiSettings->OnShareGamepadInputChanged.AddRaw(this, &FImGuiModuleProperties::SetGamepadInputShared); - } - } -} - -void FImGuiModuleProperties::UnregisterSettingsDelegates() -{ - if (GImGuiSettings) - { - GImGuiSettings->OnShareKeyboardInputChanged.RemoveAll(this); - GImGuiSettings->OnShareGamepadInputChanged.RemoveAll(this); - } -} diff --git a/Source/ImGui/Private/ImGuiPrivatePCH.h b/Source/ImGui/Private/ImGuiPrivatePCH.h index e193a86..7ccf7f2 100644 --- a/Source/ImGui/Private/ImGuiPrivatePCH.h +++ b/Source/ImGui/Private/ImGuiPrivatePCH.h @@ -11,5 +11,13 @@ #include #include +// For backward compatibility we will use FStringClassReference which in newer engine versions is a typedef for +// FSoftClassPath. Include right soft class reference header to avoid warnings in newer engine version. +#if ENGINE_COMPATIBILITY_LEGACY_STRING_CLASS_REF +#include +#else +#include +#endif + // You should place include statements to your module's private header files here. You only need to // add includes for headers that are used in most of your module's source files though. diff --git a/Source/ImGui/Private/ImGuiSettings.cpp b/Source/ImGui/Private/ImGuiSettings.cpp index 8815597..b4610a7 100644 --- a/Source/ImGui/Private/ImGuiSettings.cpp +++ b/Source/ImGui/Private/ImGuiSettings.cpp @@ -4,29 +4,17 @@ #include "ImGuiSettings.h" - -UImGuiSettings* GImGuiSettings = nullptr; - -FSimpleMulticastDelegate& UImGuiSettings::OnSettingsLoaded() -{ - static FSimpleMulticastDelegate Instance; - return Instance; -} +#include "ImGuiModuleCommands.h" +#include "ImGuiModuleProperties.h" -UImGuiSettings::UImGuiSettings() -{ -#if WITH_EDITOR - RegisterPropertyChangedDelegate(); -#endif -} +//==================================================================================================== +// UImGuiSettings +//==================================================================================================== -UImGuiSettings::~UImGuiSettings() -{ -#if WITH_EDITOR - UnregisterPropertyChangedDelegate(); -#endif -} +UImGuiSettings* UImGuiSettings::DefaultInstance = nullptr; + +FSimpleMulticastDelegate UImGuiSettings::OnSettingsLoaded; void UImGuiSettings::PostInitProperties() { @@ -60,8 +48,8 @@ void UImGuiSettings::PostInitProperties() if (IsTemplate()) { - GImGuiSettings = this; - OnSettingsLoaded().Broadcast(); + DefaultInstance = this; + OnSettingsLoaded.Broadcast(); } } @@ -69,53 +57,106 @@ void UImGuiSettings::BeginDestroy() { Super::BeginDestroy(); - if (GImGuiSettings == this) + if (DefaultInstance == this) { - GImGuiSettings = nullptr; + DefaultInstance = nullptr; + } +} + +//==================================================================================================== +// FImGuiModuleSettings +//==================================================================================================== + +FImGuiModuleSettings::FImGuiModuleSettings(FImGuiModuleProperties& InProperties, FImGuiModuleCommands& InCommands) + : Properties(InProperties) + , Commands(InCommands) +{ +#if WITH_EDITOR + FCoreUObjectDelegates::OnObjectPropertyChanged.AddRaw(this, &FImGuiModuleSettings::OnPropertyChanged); +#endif + + // Delegate initializer to support settings loaded after this object creation (in stand-alone builds) and potential + // reloading of settings. + UImGuiSettings::OnSettingsLoaded.AddRaw(this, &FImGuiModuleSettings::UpdateSettings); + + // Call initializer to support settings already loaded (editor). + UpdateSettings(); +} + +FImGuiModuleSettings::~FImGuiModuleSettings() +{ + + UImGuiSettings::OnSettingsLoaded.RemoveAll(this); + +#if WITH_EDITOR + FCoreUObjectDelegates::OnObjectPropertyChanged.RemoveAll(this); +#endif +} + +void FImGuiModuleSettings::UpdateSettings() +{ + if (UImGuiSettings* SettingsObject = UImGuiSettings::Get()) + { + SetImGuiInputHandlerClass(SettingsObject->ImGuiInputHandlerClass); + SetShareKeyboardInput(SettingsObject->bShareKeyboardInput); + SetShareGamepadInput(SettingsObject->bShareGamepadInput); + SetUseSoftwareCursor(SettingsObject->bUseSoftwareCursor); + SetToggleInputKey(SettingsObject->ToggleInput); + } +} + +void FImGuiModuleSettings::SetImGuiInputHandlerClass(const FStringClassReference& ClassReference) +{ + if (ImGuiInputHandlerClass != ClassReference) + { + ImGuiInputHandlerClass = ClassReference; + OnImGuiInputHandlerClassChanged.Broadcast(ClassReference); + } +} + +void FImGuiModuleSettings::SetShareKeyboardInput(bool bShare) +{ + if (bShareKeyboardInput != bShare) + { + bShareKeyboardInput = bShare; + Properties.SetKeyboardInputShared(bShare); + } +} + +void FImGuiModuleSettings::SetShareGamepadInput(bool bShare) +{ + if (bShareGamepadInput != bShare) + { + bShareGamepadInput = bShare; + Properties.SetGamepadInputShared(bShare); + } +} + +void FImGuiModuleSettings::SetUseSoftwareCursor(bool bUse) +{ + if (bUseSoftwareCursor != bUse) + { + bUseSoftwareCursor = bUse; + OnUseSoftwareCursorChanged.Broadcast(bUse); + } +} + +void FImGuiModuleSettings::SetToggleInputKey(const FImGuiKeyInfo& KeyInfo) +{ + if (ToggleInputKey != KeyInfo) + { + ToggleInputKey = KeyInfo; + Commands.SetKeyBinding(FImGuiModuleCommands::ToggleInput, ToggleInputKey); } } #if WITH_EDITOR -void UImGuiSettings::RegisterPropertyChangedDelegate() +void FImGuiModuleSettings::OnPropertyChanged(class UObject* ObjectBeingModified, struct FPropertyChangedEvent& PropertyChangedEvent) { - if (!FCoreUObjectDelegates::OnObjectPropertyChanged.IsBoundToObject(this)) + if (ObjectBeingModified == UImGuiSettings::Get()) { - FCoreUObjectDelegates::OnObjectPropertyChanged.AddUObject(this, &UImGuiSettings::OnPropertyChanged); - } -} - -void UImGuiSettings::UnregisterPropertyChangedDelegate() -{ - FCoreUObjectDelegates::OnObjectPropertyChanged.RemoveAll(this); -} - -void UImGuiSettings::OnPropertyChanged(class UObject* ObjectBeingModified, struct FPropertyChangedEvent& PropertyChangedEvent) -{ - if (ObjectBeingModified == this) - { - const FName UpdatedPropertyName = PropertyChangedEvent.MemberProperty ? PropertyChangedEvent.MemberProperty->GetFName() : NAME_None; - - if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, ImGuiInputHandlerClass)) - { - OnImGuiInputHandlerClassChanged.Broadcast(); - } - else if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, bShareKeyboardInput)) - { - OnShareKeyboardInputChanged.Broadcast(bShareKeyboardInput); - } - else if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, bShareGamepadInput)) - { - OnShareGamepadInputChanged.Broadcast(bShareGamepadInput); - } - else if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, bUseSoftwareCursor)) - { - OnSoftwareCursorChanged.Broadcast(); - } - else if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, ToggleInput)) - { - OnToggleInputKeyChanged.Broadcast(); - } + UpdateSettings(); } } diff --git a/Source/ImGui/Private/ImGuiSettings.h b/Source/ImGui/Private/ImGuiSettings.h index dd50c1d..115fae2 100644 --- a/Source/ImGui/Private/ImGuiSettings.h +++ b/Source/ImGui/Private/ImGuiSettings.h @@ -2,18 +2,9 @@ #pragma once -#include "ImGuiInputHandler.h" - #include #include -// Select right soft class reference header to avoid warning. -#if ENGINE_COMPATIBILITY_LEGACY_STRING_CLASS_REF -#include -#else -#include -#endif - #include "ImGuiSettings.generated.h" @@ -40,9 +31,23 @@ struct FImGuiKeyInfo UPROPERTY(EditAnywhere) ECheckBoxState Cmd = ECheckBoxState::Undetermined; + + friend bool operator==(const FImGuiKeyInfo& Lhs, const FImGuiKeyInfo& Rhs) + { + return Lhs.Key == Rhs.Key + && Lhs.Shift == Rhs.Shift + && Lhs.Ctrl == Rhs.Ctrl + && Lhs.Alt == Rhs.Alt + && Lhs.Cmd == Rhs.Cmd; + } + + friend bool operator!=(const FImGuiKeyInfo& Lhs, const FImGuiKeyInfo& Rhs) + { + return !(Lhs == Rhs); + } }; -// Settings for ImGui module. +// UObject used for loading and saving ImGui settings. To access actual settings use FImGuiModuleSettings interface. UCLASS(config=ImGui, defaultconfig) class UImGuiSettings : public UObject { @@ -50,44 +55,11 @@ class UImGuiSettings : public UObject public: - // Generic delegate used to notify changes of boolean properties. - DECLARE_MULTICAST_DELEGATE_OneParam(FBoolChangeDelegate, bool); + // Get default instance or null if it is not loaded. + static UImGuiSettings* Get() { return DefaultInstance; } - // Delegate raised when settings instance is loaded. - static FSimpleMulticastDelegate& OnSettingsLoaded(); - - UImGuiSettings(); - ~UImGuiSettings(); - - // Get the path to custom implementation of ImGui Input Handler. - const FStringClassReference& GetImGuiInputHandlerClass() const { return ImGuiInputHandlerClass; } - - // Get the keyboard input sharing configuration. - bool ShareKeyboardInput() const { return bShareKeyboardInput; } - - // Get the gamepad input sharing configuration. - bool ShareGamepadInput() const { return bShareGamepadInput; } - - // Get the software cursor configuration. - bool UseSoftwareCursor() const { return bUseSoftwareCursor; } - - // Get the shortcut configuration for 'ImGui.ToggleInput' command. - const FImGuiKeyInfo& GetToggleInputKey() const { return ToggleInput; } - - // Delegate raised when ImGui Input Handle is changed. - FSimpleMulticastDelegate OnImGuiInputHandlerClassChanged; - - // Delegate raised when keyboard input sharing configuration is changed. - FBoolChangeDelegate OnShareKeyboardInputChanged; - - // Delegate raised when gamepad input sharing configuration is changed. - FBoolChangeDelegate OnShareGamepadInputChanged; - - // Delegate raised when software cursor configuration is changed. - FSimpleMulticastDelegate OnSoftwareCursorChanged; - - // Delegate raised when shortcut configuration for 'ImGui.ToggleInput' command is changed. - FSimpleMulticastDelegate OnToggleInputKeyChanged; + // Delegate raised when default instance is loaded. + static FSimpleMulticastDelegate OnSettingsLoaded; virtual void PostInitProperties() override; virtual void BeginDestroy() override; @@ -129,18 +101,73 @@ protected: UPROPERTY(config) FImGuiKeyInfo SwitchInputModeKey_DEPRECATED; -private: + static UImGuiSettings* DefaultInstance; -#if WITH_EDITOR - - void RegisterPropertyChangedDelegate(); - void UnregisterPropertyChangedDelegate(); - - void OnPropertyChanged(class UObject* ObjectBeingModified, struct FPropertyChangedEvent& PropertyChangedEvent); - -#endif // WITH_EDITOR + friend class FImGuiModuleSettings; }; -// Pointer to the settings instance (default class object) assigned right after it is initialized and valid until -// it is destroyed. -extern UImGuiSettings* GImGuiSettings; + +class FImGuiModuleCommands; +class FImGuiModuleProperties; + +// Interface for ImGui module settings. It shadows all the settings and keep them in sync after UImGuiSettings class is +// loaded, but it can also work before that time what simplifies workflow in early-loading scenarios. +// It binds to module properties and commands objects that need to be passed during construction. +class FImGuiModuleSettings +{ +public: + + // Generic delegate used to notify changes of boolean properties. + DECLARE_MULTICAST_DELEGATE_OneParam(FBoolChangeDelegate, bool); + DECLARE_MULTICAST_DELEGATE_OneParam(FStringClassReferenceChangeDelegate, const FStringClassReference&); + + // Constructor for ImGui module settings. It will bind to instances of module properties and commands and will + // update them every time when settings are changed. + // + // @param InProperties - Instance of module properties that will be bound and updated by this object. + // @param InCommands - Instance of module commands that will be bound and updated by this object. + FImGuiModuleSettings(FImGuiModuleProperties& InProperties, FImGuiModuleCommands& InCommands); + ~FImGuiModuleSettings(); + + // It doesn't offer interface for settings that define initial values for properties, as those are passed during + // start-up and should be accessed trough properties interface. Remaining settings can have getter and/or change + // event that are defined depending on needs. + + // Get the path to custom implementation of ImGui Input Handler. + const FStringClassReference& GetImGuiInputHandlerClass() const { return ImGuiInputHandlerClass; } + + // Get the software cursor configuration. + bool UseSoftwareCursor() const { return bUseSoftwareCursor; } + + // Get the shortcut configuration for 'ImGui.ToggleInput' command. + const FImGuiKeyInfo& GetToggleInputKey() const { return ToggleInputKey; } + + // Delegate raised when ImGui Input Handle is changed. + FStringClassReferenceChangeDelegate OnImGuiInputHandlerClassChanged; + + // Delegate raised when software cursor configuration is changed. + FBoolChangeDelegate OnUseSoftwareCursorChanged; + +private: + + void UpdateSettings(); + + void SetImGuiInputHandlerClass(const FStringClassReference& ClassReference); + void SetShareKeyboardInput(bool bShare); + void SetShareGamepadInput(bool bShare); + void SetUseSoftwareCursor(bool bUse); + void SetToggleInputKey(const FImGuiKeyInfo& KeyInfo); + +#if WITH_EDITOR + void OnPropertyChanged(class UObject* ObjectBeingModified, struct FPropertyChangedEvent& PropertyChangedEvent); +#endif // WITH_EDITOR + + FImGuiModuleProperties& Properties; + FImGuiModuleCommands& Commands; + + FStringClassReference ImGuiInputHandlerClass; + FImGuiKeyInfo ToggleInputKey; + bool bShareKeyboardInput = false; + bool bShareGamepadInput = false; + bool bUseSoftwareCursor = false; +}; diff --git a/Source/ImGui/Private/SImGuiWidget.cpp b/Source/ImGui/Private/SImGuiWidget.cpp index 16a9464..62c9472 100644 --- a/Source/ImGui/Private/SImGuiWidget.cpp +++ b/Source/ImGui/Private/SImGuiWidget.cpp @@ -102,14 +102,16 @@ void SImGuiWidget::Construct(const FArguments& InArgs) #endif // IMGUI_WIDGET_DEBUG ContextProxy->SetInputState(&InputState); - // Cache locally software cursor mode. - UpdateSoftwareCursorMode(); - - // Create ImGui Input Handler. - CreateInputHandler(); - // Register for settings change. RegisterImGuiSettingsDelegates(); + + const auto& Settings = ModuleManager->GetSettings(); + + // Cache locally software cursor mode. + SetUseSoftwareCursor(Settings.UseSoftwareCursor()); + + // Create ImGui Input Handler. + CreateInputHandler(Settings.GetImGuiInputHandlerClass()); } END_SLATE_FUNCTION_BUILD_OPTIMIZATION @@ -390,11 +392,13 @@ FCursorReply SImGuiWidget::OnCursorQuery(const FGeometry& MyGeometry, const FPoi return FCursorReply::Cursor(MouseCursor); } -void SImGuiWidget::CreateInputHandler() +void SImGuiWidget::CreateInputHandler(const FStringClassReference& HandlerClassReference) { + ReleaseInputHandler(); + if (!InputHandler.IsValid()) { - InputHandler = FImGuiInputHandlerFactory::NewHandler(ModuleManager, GameViewport.Get(), ContextIndex); + InputHandler = FImGuiInputHandlerFactory::NewHandler(HandlerClassReference, ModuleManager, GameViewport.Get(), ContextIndex); } } @@ -407,40 +411,26 @@ void SImGuiWidget::ReleaseInputHandler() } } -void SImGuiWidget::RecreateInputHandler() -{ - ReleaseInputHandler(); - CreateInputHandler(); -} - -void SImGuiWidget::UpdateSoftwareCursorMode() -{ - UImGuiSettings* Settings = GetMutableDefault(); - bUseSoftwareCursor = Settings && Settings->UseSoftwareCursor(); -} - void SImGuiWidget::RegisterImGuiSettingsDelegates() { - if (UImGuiSettings* Settings = GetMutableDefault()) + auto& Settings = ModuleManager->GetSettings(); + + if (!Settings.OnImGuiInputHandlerClassChanged.IsBoundToObject(this)) { - if (!Settings->OnImGuiInputHandlerClassChanged.IsBoundToObject(this)) - { - Settings->OnImGuiInputHandlerClassChanged.AddRaw(this, &SImGuiWidget::RecreateInputHandler); - } - if (!Settings->OnSoftwareCursorChanged.IsBoundToObject(this)) - { - Settings->OnSoftwareCursorChanged.AddRaw(this, &SImGuiWidget::UpdateSoftwareCursorMode); - } + Settings.OnImGuiInputHandlerClassChanged.AddRaw(this, &SImGuiWidget::CreateInputHandler); + } + if (!Settings.OnUseSoftwareCursorChanged.IsBoundToObject(this)) + { + Settings.OnUseSoftwareCursorChanged.AddRaw(this, &SImGuiWidget::SetUseSoftwareCursor); } } void SImGuiWidget::UnregisterImGuiSettingsDelegates() { - if (UImGuiSettings* Settings = GetMutableDefault()) - { - Settings->OnImGuiInputHandlerClassChanged.RemoveAll(this); - Settings->OnSoftwareCursorChanged.RemoveAll(this); - } + auto& Settings = ModuleManager->GetSettings(); + + Settings.OnImGuiInputHandlerClassChanged.RemoveAll(this); + Settings.OnUseSoftwareCursorChanged.RemoveAll(this); } FReply SImGuiWidget::WithMouseLockRequests(FReply&& Reply) diff --git a/Source/ImGui/Private/SImGuiWidget.h b/Source/ImGui/Private/SImGuiWidget.h index 311db07..24765ea 100644 --- a/Source/ImGui/Private/SImGuiWidget.h +++ b/Source/ImGui/Private/SImGuiWidget.h @@ -4,6 +4,7 @@ #include "ImGuiInputState.h" #include "ImGuiModuleDebug.h" +#include "ImGuiSettings.h" #include @@ -91,11 +92,10 @@ private: Full }; - void CreateInputHandler(); + void CreateInputHandler(const FStringClassReference& HandlerClassReference); void ReleaseInputHandler(); - void RecreateInputHandler(); - void UpdateSoftwareCursorMode(); + void SetUseSoftwareCursor(bool bUse) { bUseSoftwareCursor = bUse; } void RegisterImGuiSettingsDelegates(); void UnregisterImGuiSettingsDelegates(); diff --git a/Source/ImGui/Public/ImGuiModuleProperties.h b/Source/ImGui/Public/ImGuiModuleProperties.h index 8dcc77a..feb3737 100644 --- a/Source/ImGui/Public/ImGuiModuleProperties.h +++ b/Source/ImGui/Public/ImGuiModuleProperties.h @@ -64,23 +64,6 @@ public: private: - // Allow private state copying to support hot-reloading but otherwise it is disabled due to non-trivial constructor - // and destructor. - - FImGuiModuleProperties(); - ~FImGuiModuleProperties(); - - FImGuiModuleProperties(const FImGuiModuleProperties&) = default; - FImGuiModuleProperties& operator=(const FImGuiModuleProperties&) = default; - - FImGuiModuleProperties(FImGuiModuleProperties&&) = default; - FImGuiModuleProperties& operator=(FImGuiModuleProperties&&) = default; - - void InitializeSettings(); - - void RegisterSettingsDelegates(); - void UnregisterSettingsDelegates(); - bool bInputEnabled = false; bool bKeyboardNavigationEnabled = false; @@ -90,8 +73,4 @@ private: bool bGamepadInputShared = false; bool bShowDemo = false; - - // Allow FImGuiModuleManager and FImGuiModule to create and copy properties. - friend class FImGuiModule; - friend class FImGuiModuleManager; };