diff --git a/Source/ImGui/Private/ImGuiModule.cpp b/Source/ImGui/Private/ImGuiModule.cpp index 802e744..6a619c2 100644 --- a/Source/ImGui/Private/ImGuiModule.cpp +++ b/Source/ImGui/Private/ImGuiModule.cpp @@ -133,7 +133,8 @@ void FImGuiModule::ShutdownModule() // In editor store data that we want to move to hot-reloaded module. #if WITH_EDITOR - static TOptional PropertiesToMove = ImGuiModuleManager->GetProperties(); + static bool bMoveProperties = true; + static FImGuiModuleProperties PropertiesToMove = ImGuiModuleManager->GetProperties(); #endif // Before we shutdown we need to delete managers that will do all the necessary cleanup. @@ -162,10 +163,10 @@ void FImGuiModule::ShutdownModule() { ImGuiImplementation::SetImGuiContextHandle(LoadedModule.GetImGuiContextHandle()); - if (PropertiesToMove.IsSet()) + if (bMoveProperties) { - LoadedModule.SetProperties(PropertiesToMove.GetValue()); - PropertiesToMove.Reset(); + bMoveProperties = false; + LoadedModule.SetProperties(PropertiesToMove); } } } diff --git a/Source/ImGui/Private/ImGuiModuleProperties.cpp b/Source/ImGui/Private/ImGuiModuleProperties.cpp index 2c65bd6..3c3fa7b 100644 --- a/Source/ImGui/Private/ImGuiModuleProperties.cpp +++ b/Source/ImGui/Private/ImGuiModuleProperties.cpp @@ -4,5 +4,56 @@ #include "ImGuiModuleProperties.h" +#include "ImGuiSettings.h" -// TODO: Initialize relevant properties from settings. + +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/ImGuiSettings.cpp b/Source/ImGui/Private/ImGuiSettings.cpp index f17d449..8815597 100644 --- a/Source/ImGui/Private/ImGuiSettings.cpp +++ b/Source/ImGui/Private/ImGuiSettings.cpp @@ -100,14 +100,22 @@ void UImGuiSettings::OnPropertyChanged(class UObject* ObjectBeingModified, struc { OnImGuiInputHandlerClassChanged.Broadcast(); } - else if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, ToggleInput)) + else if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, bShareKeyboardInput)) { - OnToggleInputKeyChanged.Broadcast(); + 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(); + } } } diff --git a/Source/ImGui/Private/ImGuiSettings.h b/Source/ImGui/Private/ImGuiSettings.h index 560138c..dd50c1d 100644 --- a/Source/ImGui/Private/ImGuiSettings.h +++ b/Source/ImGui/Private/ImGuiSettings.h @@ -50,30 +50,45 @@ class UImGuiSettings : public UObject public: + // Generic delegate used to notify changes of boolean properties. + DECLARE_MULTICAST_DELEGATE_OneParam(FBoolChangeDelegate, bool); + // Delegate raised when settings instance is loaded. static FSimpleMulticastDelegate& OnSettingsLoaded(); UImGuiSettings(); ~UImGuiSettings(); - // Path to custom implementation of ImGui Input Handler. + // Get the path to custom implementation of ImGui Input Handler. const FStringClassReference& GetImGuiInputHandlerClass() const { return ImGuiInputHandlerClass; } - // Get the shortcut key info for 'ImGui.ToggleInput' command. - const FImGuiKeyInfo& GetToggleInputKey() const { return ToggleInput; } + // Get the keyboard input sharing configuration. + bool ShareKeyboardInput() const { return bShareKeyboardInput; } - // Check whether ImGui should draw its own software cursor. + // Get the gamepad input sharing configuration. + bool ShareGamepadInput() const { return bShareGamepadInput; } + + // Get the software cursor configuration. bool UseSoftwareCursor() const { return bUseSoftwareCursor; } - // Delegate raised when ImGuiInputHandlerClass is changed. + // 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 ToggleInput key is changed. - FSimpleMulticastDelegate OnToggleInputKeyChanged; + // Delegate raised when keyboard input sharing configuration is changed. + FBoolChangeDelegate OnShareKeyboardInputChanged; - // Delegate raised when SoftwareCursorEnabled property is changed. + // 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; + virtual void PostInitProperties() override; virtual void BeginDestroy() override; @@ -84,6 +99,24 @@ protected: UPROPERTY(EditAnywhere, config, Category = "Extensions", meta = (MetaClass = "ImGuiInputHandler")) FStringClassReference ImGuiInputHandlerClass; + // Whether ImGui should share keyboard input with game. + // This defines initial behaviour which can be later changed using 'ImGui.ToggleKeyboardInputSharing' command or + // module properties interface. + UPROPERTY(EditAnywhere, config, Category = "Input") + bool bShareKeyboardInput = false; + + // Whether ImGui should share gamepad input with game. + // This defines initial behaviour which can be later changed using 'ImGui.ToggleGamepadInputSharing' command or + // module properties interface. + UPROPERTY(EditAnywhere, config, Category = "Input") + bool bShareGamepadInput = false; + + // If true, then in input mode ImGui will draw its own cursor in place of the hardware one. + // When disabled (default) there is a noticeable difference between cursor position seen by ImGui and position on + // the screen. Enabling this option removes that effect but with lower frame-rates UI becomes quickly unusable. + UPROPERTY(EditAnywhere, config, Category = "Input", AdvancedDisplay) + bool bUseSoftwareCursor = false; + // Define a shortcut key to 'ImGui.ToggleInput' command. Binding is only set if the key field is valid. // Note that modifier key properties can be set to one of the three values: undetermined means that state of the given // modifier is not important, checked means that it needs to be pressed and unchecked means that it cannot be pressed. @@ -96,12 +129,6 @@ protected: UPROPERTY(config) FImGuiKeyInfo SwitchInputModeKey_DEPRECATED; - // If true, then in input mode ImGui will draw its own cursor in place of the hardware one. - // When disabled (default) there is a noticeable difference between cursor position seen by ImGui and position on - // the screen. Enabling this option removes that effect but with lower frame-rates UI becomes quickly unusable. - UPROPERTY(EditAnywhere, config, Category = "Input") - bool bUseSoftwareCursor = false; - private: #if WITH_EDITOR diff --git a/Source/ImGui/Public/ImGuiModuleProperties.h b/Source/ImGui/Public/ImGuiModuleProperties.h index feb3737..8dcc77a 100644 --- a/Source/ImGui/Public/ImGuiModuleProperties.h +++ b/Source/ImGui/Public/ImGuiModuleProperties.h @@ -64,6 +64,23 @@ 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; @@ -73,4 +90,8 @@ private: bool bGamepadInputShared = false; bool bShowDemo = false; + + // Allow FImGuiModuleManager and FImGuiModule to create and copy properties. + friend class FImGuiModule; + friend class FImGuiModuleManager; };