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()
{
// 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())
{
@ -59,7 +59,7 @@ void FImGuiEditor::Register()
SettingsModule->RegisterSettings(SETTINGS_CONTAINER,
LOCTEXT("ImGuiSettingsName", "ImGui"),
LOCTEXT("ImGuiSettingsDescription", "Configure the Unreal ImGui plugin."),
GetMutableDefault<UImGuiSettings>());
GImGuiSettings);
}
}

View File

@ -3,23 +3,12 @@
#include "ImGuiPrivatePCH.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.
void FImGuiDemo::DrawControls(int32 ContextIndex)
{
if (CVars::ShowDemo.GetValueOnGameThread() > 0)
if (FImGuiModuleProperties::Get().ShowDemo())
{
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 (IsSwitchInputModeEvent(KeyEvent))
{
FImGuiModule::Get().ToggleInputMode();
FImGuiModuleProperties::Get().ToggleInput(ECVF_SetByConsole);
return FImGuiInputResponse().RequestConsume();
}
@ -91,8 +91,9 @@ namespace
bool UImGuiInputHandler::IsSwitchInputModeEvent(const FKeyEvent& KeyEvent) const
{
const FImGuiKeyInfo KeyInfo = GetDefault<UImGuiSettings>()->GetSwitchInputModeKey();
return (KeyEvent.GetKey() == KeyInfo.Key) && AreModifiersMatching(KeyInfo, KeyEvent);
return GImGuiSettings
&& (KeyEvent.GetKey() == GImGuiSettings->GetSwitchInputModeKey().Key)
&& AreModifiersMatching(GImGuiSettings->GetSwitchInputModeKey(), KeyEvent);
}
bool UImGuiInputHandler::HasImGuiActiveItem() const

View File

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

View File

@ -20,27 +20,6 @@
#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
{
enum
@ -191,34 +170,32 @@ ImGuiContext** FImGuiModule::GetImGuiContextHandle()
bool FImGuiModule::IsInputMode() const
{
return CVars::InputEnabled.GetValueOnAnyThread() > 0;
return FImGuiModuleProperties::Get().IsInputEnabled();
}
void FImGuiModule::SetInputMode(bool bEnabled)
{
// This function is for supporting shortcut or subsitiute for console command, so we are using the same priority.
CVars::InputEnabled->Set(bEnabled ? 1 : 0, ECVF_SetByConsole);
return FImGuiModuleProperties::Get().SetInputEnabled(bEnabled);
}
void FImGuiModule::ToggleInputMode()
{
SetInputMode(!IsInputMode());
FImGuiModuleProperties::Get().ToggleInput();
}
bool FImGuiModule::IsShowingDemo() const
{
return CVars::ShowDemo.GetValueOnAnyThread() > 0;
return FImGuiModuleProperties::Get().ShowDemo();
}
void FImGuiModule::SetShowDemo(bool bShow)
{
// This function is for supporting shortcut or subsitiute for console command, so we are using the same priority.
CVars::ShowDemo->Set(bShow ? 1 : 0, ECVF_SetByConsole);
return FImGuiModuleProperties::Get().SetShowDemo(bShow);
}
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
#include "ImGuiContextManager.h"
#include "ImGuiModuleCommands.h"
#include "SImGuiWidget.h"
#include "TextureManager.h"
@ -56,6 +57,9 @@ private:
// Event that we call after ImGui is updated.
FSimpleMulticastDelegate PostImGuiUpdateEvent;
// Tying module console commands to life-cycle of this manager and module.
FImGuiModuleCommands Commands;
// Manager for ImGui contexts.
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
#include "VersionCompatibility.h"
#include "ImGuiModuleDebug.h"
#include "ImGuiModuleProperties.h"
// Module
#include "ImGuiModule.h"

View File

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

View File

@ -50,6 +50,9 @@ class UImGuiSettings : public UObject
public:
// Delegate raised when settings instance is loaded.
static FSimpleMulticastDelegate& OnSettingsLoaded();
UImGuiSettings();
~UImGuiSettings();
@ -65,10 +68,14 @@ public:
// Delegate raised when ImGuiInputHandlerClass property has changed.
FSimpleMulticastDelegate OnImGuiInputHandlerClassChanged;
// Delegate raised when SwitchInputModeKey property has changed.
FSimpleMulticastDelegate OnSwitchInputModeKeyChanged;
// Delegate raised when SoftwareCursorEnabled property has changed.
FSimpleMulticastDelegate OnSoftwareCursorChanged;
virtual void PostInitProperties() override;
virtual void BeginDestroy() override;
protected:
@ -102,3 +109,7 @@ private:
#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";
}
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
namespace CVars
{
@ -521,7 +503,7 @@ void SImGuiWidget::SetVisibilityFromInputEnabled()
void SImGuiWidget::UpdateInputEnabled()
{
const bool bEnabled = CVars::InputEnabled.GetValueOnGameThread() > 0;
const bool bEnabled = FImGuiModuleProperties::Get().IsInputEnabled();
if (bInputEnabled != bEnabled)
{
bInputEnabled = bEnabled;
@ -570,8 +552,9 @@ void SImGuiWidget::UpdateInputEnabled()
if (bInputEnabled)
{
InputState.SetKeyboardNavigationEnabled((CVars::InputNavigation.GetValueOnGameThread() & 1) != 0);
InputState.SetGamepadNavigationEnabled((CVars::InputNavigation.GetValueOnGameThread() & 2) != 0);
const auto& Properties = FImGuiModuleProperties::Get();
InputState.SetKeyboardNavigationEnabled(Properties.IsKeyboardNavigationEnabled());
InputState.SetGamepadNavigationEnabled(Properties.IsGamepadNavigationEnabled());
const auto& Application = FSlateApplication::Get().GetPlatformApplication();
InputState.SetGamepad(Application.IsValid() && Application->IsGamepadAttached());
}