Moved console variables and commands to wrapper objects:

- Moved property variables to ImGui Module Properties.
- Moved console command to ImGui Module Commands (one for now but more will be added).
- ImGui Module Commands is created by ImGui Module Manager, what means that commands are registered after module is loaded and unregistered when it is unloaded.
- Updated settings to allow more convenient use: Added global pointer to default object and event raised when it is loaded.
This commit is contained in:
Sebastian 2018-11-24 19:54:01 +00:00
parent f67cabbe93
commit c5f3759664
14 changed files with 299 additions and 80 deletions

View File

@ -50,7 +50,7 @@ FImGuiEditor::~FImGuiEditor()
void FImGuiEditor::Register() void FImGuiEditor::Register()
{ {
// Only register after UImGuiSettings class is initialized (necessary to check in early loading stages). // Only register after UImGuiSettings class is initialized (necessary to check in early loading stages).
if (!bSettingsRegistered && UImGuiSettings::StaticClass()->IsValidLowLevelFast()) if (!bSettingsRegistered && GImGuiSettings)
{ {
if (ISettingsModule* SettingsModule = GetSettingsModule()) if (ISettingsModule* SettingsModule = GetSettingsModule())
{ {
@ -59,7 +59,7 @@ void FImGuiEditor::Register()
SettingsModule->RegisterSettings(SETTINGS_CONTAINER, SettingsModule->RegisterSettings(SETTINGS_CONTAINER,
LOCTEXT("ImGuiSettingsName", "ImGui"), LOCTEXT("ImGuiSettingsName", "ImGui"),
LOCTEXT("ImGuiSettingsDescription", "Configure the Unreal ImGui plugin."), LOCTEXT("ImGuiSettingsDescription", "Configure the Unreal ImGui plugin."),
GetMutableDefault<UImGuiSettings>()); GImGuiSettings);
} }
} }

View File

@ -3,23 +3,12 @@
#include "ImGuiPrivatePCH.h" #include "ImGuiPrivatePCH.h"
#include "ImGuiDemo.h" #include "ImGuiDemo.h"
#include "ImGuiModuleManager.h"
#include "Utilities/ScopeGuards.h"
namespace CVars
{
TAutoConsoleVariable<int> ShowDemo(TEXT("ImGui.ShowDemo"), 0,
TEXT("Show ImGui demo.\n")
TEXT("0: disabled (default)\n")
TEXT("1: enabled."),
ECVF_Default);
}
// Demo copied (with minor modifications) from ImGui examples. See https://github.com/ocornut/imgui. // Demo copied (with minor modifications) from ImGui examples. See https://github.com/ocornut/imgui.
void FImGuiDemo::DrawControls(int32 ContextIndex) void FImGuiDemo::DrawControls(int32 ContextIndex)
{ {
if (CVars::ShowDemo.GetValueOnGameThread() > 0) if (FImGuiModuleProperties::Get().ShowDemo())
{ {
const int32 ContextBit = ContextIndex < 0 ? 0 : 1 << ContextIndex; const int32 ContextBit = ContextIndex < 0 ? 0 : 1 << ContextIndex;

View File

@ -26,7 +26,7 @@ FImGuiInputResponse UImGuiInputHandler::OnKeyDown(const FKeyEvent& KeyEvent)
// If this is an input mode switch event then handle it here and consume. // If this is an input mode switch event then handle it here and consume.
if (IsSwitchInputModeEvent(KeyEvent)) if (IsSwitchInputModeEvent(KeyEvent))
{ {
FImGuiModule::Get().ToggleInputMode(); FImGuiModuleProperties::Get().ToggleInput(ECVF_SetByConsole);
return FImGuiInputResponse().RequestConsume(); return FImGuiInputResponse().RequestConsume();
} }
@ -91,8 +91,9 @@ namespace
bool UImGuiInputHandler::IsSwitchInputModeEvent(const FKeyEvent& KeyEvent) const bool UImGuiInputHandler::IsSwitchInputModeEvent(const FKeyEvent& KeyEvent) const
{ {
const FImGuiKeyInfo KeyInfo = GetDefault<UImGuiSettings>()->GetSwitchInputModeKey(); return GImGuiSettings
return (KeyEvent.GetKey() == KeyInfo.Key) && AreModifiersMatching(KeyInfo, KeyEvent); && (KeyEvent.GetKey() == GImGuiSettings->GetSwitchInputModeKey().Key)
&& AreModifiersMatching(GImGuiSettings->GetSwitchInputModeKey(), KeyEvent);
} }
bool UImGuiInputHandler::HasImGuiActiveItem() const bool UImGuiInputHandler::HasImGuiActiveItem() const

View File

@ -11,9 +11,9 @@
UImGuiInputHandler* FImGuiInputHandlerFactory::NewHandler(FImGuiModuleManager* ModuleManager, UGameViewportClient* GameViewport, int32 ContextIndex) UImGuiInputHandler* FImGuiInputHandlerFactory::NewHandler(FImGuiModuleManager* ModuleManager, UGameViewportClient* GameViewport, int32 ContextIndex)
{ {
UClass* HandlerClass = nullptr; UClass* HandlerClass = nullptr;
if (UImGuiSettings* Settings = GetMutableDefault<UImGuiSettings>()) if (GImGuiSettings)
{ {
const auto& HandlerClassReference = Settings->GetImGuiInputHandlerClass(); const auto& HandlerClassReference = GImGuiSettings->GetImGuiInputHandlerClass();
if (HandlerClassReference.IsValid()) if (HandlerClassReference.IsValid())
{ {
HandlerClass = HandlerClassReference.TryLoadClass<UImGuiInputHandler>(); HandlerClass = HandlerClassReference.TryLoadClass<UImGuiInputHandler>();

View File

@ -20,27 +20,6 @@
#define LOCTEXT_NAMESPACE "FImGuiModule" #define LOCTEXT_NAMESPACE "FImGuiModule"
namespace CVars
{
extern TAutoConsoleVariable<int32> InputEnabled;
extern TAutoConsoleVariable<int32> ShowDemo;
}
namespace Commands
{
const TCHAR* SwitchInputMode = TEXT("ImGui.SwitchInputMode");
}
void SwitchImGuiInputMode()
{
FImGuiModule::Get().ToggleInputMode();
}
FAutoConsoleCommand SwitchInputModeCommand = FAutoConsoleCommand(
Commands::SwitchInputMode,
TEXT("Changes ImGui input mode."),
FConsoleCommandDelegate::CreateStatic(SwitchImGuiInputMode));
struct EDelegateCategory struct EDelegateCategory
{ {
enum enum
@ -191,34 +170,32 @@ ImGuiContext** FImGuiModule::GetImGuiContextHandle()
bool FImGuiModule::IsInputMode() const bool FImGuiModule::IsInputMode() const
{ {
return CVars::InputEnabled.GetValueOnAnyThread() > 0; return FImGuiModuleProperties::Get().IsInputEnabled();
} }
void FImGuiModule::SetInputMode(bool bEnabled) void FImGuiModule::SetInputMode(bool bEnabled)
{ {
// This function is for supporting shortcut or subsitiute for console command, so we are using the same priority. return FImGuiModuleProperties::Get().SetInputEnabled(bEnabled);
CVars::InputEnabled->Set(bEnabled ? 1 : 0, ECVF_SetByConsole);
} }
void FImGuiModule::ToggleInputMode() void FImGuiModule::ToggleInputMode()
{ {
SetInputMode(!IsInputMode()); FImGuiModuleProperties::Get().ToggleInput();
} }
bool FImGuiModule::IsShowingDemo() const bool FImGuiModule::IsShowingDemo() const
{ {
return CVars::ShowDemo.GetValueOnAnyThread() > 0; return FImGuiModuleProperties::Get().ShowDemo();
} }
void FImGuiModule::SetShowDemo(bool bShow) void FImGuiModule::SetShowDemo(bool bShow)
{ {
// This function is for supporting shortcut or subsitiute for console command, so we are using the same priority. return FImGuiModuleProperties::Get().SetShowDemo(bShow);
CVars::ShowDemo->Set(bShow ? 1 : 0, ECVF_SetByConsole);
} }
void FImGuiModule::ToggleShowDemo() void FImGuiModule::ToggleShowDemo()
{ {
SetShowDemo(!IsShowingDemo()); return FImGuiModuleProperties::Get().ToggleDemo();
} }

View File

@ -0,0 +1,74 @@
// Distributed under the MIT License (MIT) (see accompanying LICENSE file)
#include "ImGuiPrivatePCH.h"
#include "ImGuiModuleCommands.h"
#include "ImGuiSettings.h"
#include "Utilities/DebugExecBindings.h"
namespace CommandNames
{
namespace
{
const TCHAR* SwitchInputMode = TEXT("ImGui.SwitchInputMode");
}
}
FImGuiModuleCommands::FImGuiModuleCommands()
: ToggleInputCommand(CommandNames::SwitchInputMode,
TEXT("Switch ImGui input mode."),
FConsoleCommandDelegate::CreateRaw(this, &FImGuiModuleCommands::ToggleInput))
{
// 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()
{
UImGuiSettings::OnSettingsLoaded().RemoveAll(this);
UnregisterSettingsDelegates();
}
void FImGuiModuleCommands::InitializeSettings()
{
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();
}
void FImGuiModuleCommands::RegisterSettingsDelegates()
{
if (GImGuiSettings && !GImGuiSettings->OnSwitchInputModeKeyChanged.IsBoundToObject(this))
{
GImGuiSettings->OnSwitchInputModeKeyChanged.AddRaw(this, &FImGuiModuleCommands::UpdateToggleInputKeyBinding);
}
}
void FImGuiModuleCommands::UnregisterSettingsDelegates()
{
if (GImGuiSettings)
{
GImGuiSettings->OnSwitchInputModeKeyChanged.RemoveAll(this);
}
}
void FImGuiModuleCommands::UpdateToggleInputKeyBinding()
{
if (GImGuiSettings)
{
DebugExecBindings::UpdatePlayerInputs(GImGuiSettings->GetSwitchInputModeKey(), CommandNames::SwitchInputMode);
}
}
void FImGuiModuleCommands::ToggleInput()
{
FImGuiModuleProperties::Get().ToggleInput(ECVF_SetByConsole);
}

View File

@ -0,0 +1,35 @@
// Distributed under the MIT License (MIT) (see accompanying LICENSE file)
#pragma once
#include <IConsoleManager.h>
// Wrapper for ImGui console commands.
class FImGuiModuleCommands
{
// Allow module manager to control life-cycle of this class.
friend class FImGuiModuleManager;
FImGuiModuleCommands();
~FImGuiModuleCommands();
// Disable copy semantics.
FImGuiModuleCommands(const FImGuiModuleCommands&) = default;
FImGuiModuleCommands& operator=(const FImGuiModuleCommands&) = default;
// Disable move semantics.
FImGuiModuleCommands(FImGuiModuleCommands&&) = default;
FImGuiModuleCommands& operator=(FImGuiModuleCommands&&) = default;
void InitializeSettings();
void RegisterSettingsDelegates();
void UnregisterSettingsDelegates();
void UpdateToggleInputKeyBinding();
void ToggleInput();
FAutoConsoleCommand ToggleInputCommand;
};

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "ImGuiContextManager.h" #include "ImGuiContextManager.h"
#include "ImGuiModuleCommands.h"
#include "SImGuiWidget.h" #include "SImGuiWidget.h"
#include "TextureManager.h" #include "TextureManager.h"
@ -56,6 +57,9 @@ private:
// Event that we call after ImGui is updated. // Event that we call after ImGui is updated.
FSimpleMulticastDelegate PostImGuiUpdateEvent; FSimpleMulticastDelegate PostImGuiUpdateEvent;
// Tying module console commands to life-cycle of this manager and module.
FImGuiModuleCommands Commands;
// Manager for ImGui contexts. // Manager for ImGui contexts.
FImGuiContextManager ContextManager; FImGuiContextManager ContextManager;

View File

@ -0,0 +1,73 @@
// Distributed under the MIT License (MIT) (see accompanying LICENSE file)
#include "ImGuiPrivatePCH.h"
#include "ImGuiModuleProperties.h"
FImGuiModuleProperties& FImGuiModuleProperties::Get()
{
static FImGuiModuleProperties Instance;
return Instance;
}
FImGuiModuleProperties::FImGuiModuleProperties()
: InputEnabledVariable(TEXT("ImGui.InputEnabled"), 0,
TEXT("Enable or disable ImGui input mode.\n")
TEXT("0: disabled (default)\n")
TEXT("1: enabled, input is routed to ImGui and with a few exceptions is consumed"),
ECVF_Default)
, InputNavigationVariable(TEXT("ImGui.InputNavigation"), 0,
TEXT("EXPERIMENTAL Set ImGui navigation mode.\n")
TEXT("0: navigation is disabled\n")
TEXT("1: keyboard navigation\n")
TEXT("2: gamepad navigation (gamepad input is consumed)\n")
TEXT("3: keyboard and gamepad navigation (gamepad input is consumed)"),
ECVF_Default)
, ShowDemoVariable(TEXT("ImGui.ShowDemo"), 0,
TEXT("Show ImGui demo.\n")
TEXT("0: disabled (default)\n")
TEXT("1: enabled."),
ECVF_Default)
{
}
bool FImGuiModuleProperties::IsInputEnabled() const
{
return InputEnabledVariable->GetInt() > 0;
}
void FImGuiModuleProperties::SetInputEnabled(bool bEnabled, EConsoleVariableFlags SetBy)
{
InputEnabledVariable->Set(bEnabled ? 1 : 0, SetBy);
}
void FImGuiModuleProperties::ToggleInput(EConsoleVariableFlags SetBy)
{
SetInputEnabled(!IsInputEnabled(), SetBy);
}
bool FImGuiModuleProperties::IsKeyboardNavigationEnabled() const
{
return (InputNavigationVariable->GetInt() & 1) != 0;
}
bool FImGuiModuleProperties::IsGamepadNavigationEnabled() const
{
return (InputNavigationVariable->GetInt() & 2) != 0;
}
bool FImGuiModuleProperties::ShowDemo() const
{
return ShowDemoVariable->GetInt() > 0;
}
void FImGuiModuleProperties::SetShowDemo(bool bEnabled, EConsoleVariableFlags SetBy)
{
ShowDemoVariable->Set(bEnabled ? 1 : 0, SetBy);
}
void FImGuiModuleProperties::ToggleDemo(EConsoleVariableFlags SetBy)
{
SetShowDemo(!ShowDemo(), SetBy);
}

View File

@ -0,0 +1,57 @@
// Distributed under the MIT License (MIT) (see accompanying LICENSE file)
#pragma once
#include <IConsoleManager.h>
// Collects and give access to module properties.
// TODO: For now singleton instance is initialized on the first use. Try to move it to the ImGui Manager.
class FImGuiModuleProperties
{
public:
// Get the instance of the ImGui properties.
static FImGuiModuleProperties& Get();
// Check whether input is enabled.
bool IsInputEnabled() const;
// Set whether input should be enabled.
void SetInputEnabled(bool bEnabled, EConsoleVariableFlags SetBy = ECVF_SetByCode);
// Toggle input state.
void ToggleInput(EConsoleVariableFlags SetBy = ECVF_SetByCode);
// Check whether keyboard navigation is enabled.
bool IsKeyboardNavigationEnabled() const;
// Check whether gamepad navigation is enabled.
bool IsGamepadNavigationEnabled() const;
// Check whether demo should be visible.
bool ShowDemo() const;
// Set whether demo should be visible.
void SetShowDemo(bool bEnabled, EConsoleVariableFlags SetBy = ECVF_SetByCode);
// Toggle demo visibility.
void ToggleDemo(EConsoleVariableFlags SetBy = ECVF_SetByCode);
private:
FImGuiModuleProperties();
// Disable copy and move semantics.
FImGuiModuleProperties(const FImGuiModuleProperties&) = delete;
FImGuiModuleProperties& operator=(const FImGuiModuleProperties&) = delete;
FImGuiModuleProperties(FImGuiModuleProperties&&) = delete;
FImGuiModuleProperties& operator=(FImGuiModuleProperties&&) = delete;
TAutoConsoleVariable<int32> InputEnabledVariable;
TAutoConsoleVariable<int32> InputNavigationVariable;
TAutoConsoleVariable<int32> ShowDemoVariable;
};

View File

@ -3,6 +3,7 @@
// Module-wide macros // Module-wide macros
#include "VersionCompatibility.h" #include "VersionCompatibility.h"
#include "ImGuiModuleDebug.h" #include "ImGuiModuleDebug.h"
#include "ImGuiModuleProperties.h"
// Module // Module
#include "ImGuiModule.h" #include "ImGuiModule.h"

View File

@ -3,7 +3,15 @@
#include "ImGuiPrivatePCH.h" #include "ImGuiPrivatePCH.h"
#include "ImGuiSettings.h" #include "ImGuiSettings.h"
#include "Utilities/DebugExecBindings.h"
UImGuiSettings* GImGuiSettings = nullptr;
FSimpleMulticastDelegate& UImGuiSettings::OnSettingsLoaded()
{
static FSimpleMulticastDelegate Instance;
return Instance;
}
UImGuiSettings::UImGuiSettings() UImGuiSettings::UImGuiSettings()
@ -20,19 +28,25 @@ UImGuiSettings::~UImGuiSettings()
#endif #endif
} }
namespace Commands
{
extern const TCHAR* SwitchInputMode;
}
void UImGuiSettings::PostInitProperties() void UImGuiSettings::PostInitProperties()
{ {
Super::PostInitProperties(); Super::PostInitProperties();
// Instead of saving binding to input config, we manually update DebugExecBindings from here. This has an advantage if (IsTemplate())
// that there is no ambiguity where settings are stored and more importantly, it works out of the box in packed {
// and staged builds. GImGuiSettings = this;
DebugExecBindings::UpdatePlayerInputs(SwitchInputModeKey, Commands::SwitchInputMode); OnSettingsLoaded().Broadcast();
}
}
void UImGuiSettings::BeginDestroy()
{
Super::BeginDestroy();
if (GImGuiSettings == this)
{
GImGuiSettings = nullptr;
}
} }
#if WITH_EDITOR #if WITH_EDITOR
@ -62,7 +76,7 @@ void UImGuiSettings::OnPropertyChanged(class UObject* ObjectBeingModified, struc
} }
else if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, SwitchInputModeKey)) else if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, SwitchInputModeKey))
{ {
DebugExecBindings::UpdatePlayerInputs(SwitchInputModeKey, Commands::SwitchInputMode); OnSwitchInputModeKeyChanged.Broadcast();
} }
else if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, bUseSoftwareCursor)) else if (UpdatedPropertyName == GET_MEMBER_NAME_CHECKED(UImGuiSettings, bUseSoftwareCursor))
{ {

View File

@ -50,6 +50,9 @@ class UImGuiSettings : public UObject
public: public:
// Delegate raised when settings instance is loaded.
static FSimpleMulticastDelegate& OnSettingsLoaded();
UImGuiSettings(); UImGuiSettings();
~UImGuiSettings(); ~UImGuiSettings();
@ -65,10 +68,14 @@ public:
// Delegate raised when ImGuiInputHandlerClass property has changed. // Delegate raised when ImGuiInputHandlerClass property has changed.
FSimpleMulticastDelegate OnImGuiInputHandlerClassChanged; FSimpleMulticastDelegate OnImGuiInputHandlerClassChanged;
// Delegate raised when SwitchInputModeKey property has changed.
FSimpleMulticastDelegate OnSwitchInputModeKeyChanged;
// Delegate raised when SoftwareCursorEnabled property has changed. // Delegate raised when SoftwareCursorEnabled property has changed.
FSimpleMulticastDelegate OnSoftwareCursorChanged; FSimpleMulticastDelegate OnSoftwareCursorChanged;
virtual void PostInitProperties() override; virtual void PostInitProperties() override;
virtual void BeginDestroy() override;
protected: protected:
@ -102,3 +109,7 @@ private:
#endif // WITH_EDITOR #endif // WITH_EDITOR
}; };
// Pointer to the settings instance (default class object) assigned right after it is initialized and valid until
// it is destroyed.
extern UImGuiSettings* GImGuiSettings;

View File

@ -54,24 +54,6 @@ namespace
constexpr const char* FontAtlasTextureName = "ImGuiModule_FontAtlas"; constexpr const char* FontAtlasTextureName = "ImGuiModule_FontAtlas";
} }
namespace CVars
{
TAutoConsoleVariable<int> InputEnabled(TEXT("ImGui.InputEnabled"), 0,
TEXT("Enable or disable ImGui input mode.\n")
TEXT("0: disabled (default)\n")
TEXT("1: enabled, input is routed to ImGui and with a few exceptions is consumed"),
ECVF_Default);
TAutoConsoleVariable<int> InputNavigation(TEXT("ImGui.InputNavigation"), 0,
TEXT("EXPERIMENTAL Set ImGui navigation mode.\n")
TEXT("0: navigation is disabled\n")
TEXT("1: keyboard navigation\n")
TEXT("2: gamepad navigation (gamepad input is consumed)\n")
TEXT("3: keyboard and gamepad navigation (gamepad input is consumed)"),
ECVF_Default);
}
#if IMGUI_WIDGET_DEBUG #if IMGUI_WIDGET_DEBUG
namespace CVars namespace CVars
{ {
@ -521,7 +503,7 @@ void SImGuiWidget::SetVisibilityFromInputEnabled()
void SImGuiWidget::UpdateInputEnabled() void SImGuiWidget::UpdateInputEnabled()
{ {
const bool bEnabled = CVars::InputEnabled.GetValueOnGameThread() > 0; const bool bEnabled = FImGuiModuleProperties::Get().IsInputEnabled();
if (bInputEnabled != bEnabled) if (bInputEnabled != bEnabled)
{ {
bInputEnabled = bEnabled; bInputEnabled = bEnabled;
@ -570,8 +552,9 @@ void SImGuiWidget::UpdateInputEnabled()
if (bInputEnabled) if (bInputEnabled)
{ {
InputState.SetKeyboardNavigationEnabled((CVars::InputNavigation.GetValueOnGameThread() & 1) != 0); const auto& Properties = FImGuiModuleProperties::Get();
InputState.SetGamepadNavigationEnabled((CVars::InputNavigation.GetValueOnGameThread() & 2) != 0); InputState.SetKeyboardNavigationEnabled(Properties.IsKeyboardNavigationEnabled());
InputState.SetGamepadNavigationEnabled(Properties.IsGamepadNavigationEnabled());
const auto& Application = FSlateApplication::Get().GetPlatformApplication(); const auto& Application = FSlateApplication::Get().GetPlatformApplication();
InputState.SetGamepad(Application.IsValid() && Application->IsGamepadAttached()); InputState.SetGamepad(Application.IsValid() && Application->IsGamepadAttached());
} }