Added custom property type layout for FImGuiKeyInfo.

This commit is contained in:
Sebastian 2018-07-31 22:09:01 +01:00
parent a90f217ab3
commit 9ab12850fb
7 changed files with 275 additions and 9 deletions

View File

@ -64,6 +64,7 @@ public class ImGui : ModuleRules
PrivateDependencyModuleNames.AddRange( PrivateDependencyModuleNames.AddRange(
new string[] new string[]
{ {
"EditorStyle",
"Settings", "Settings",
"UnrealEd", "UnrealEd",
} }

View File

@ -6,6 +6,7 @@
#include "ImGuiEditor.h" #include "ImGuiEditor.h"
#include "ImGuiKeyInfoCustomization.h"
#include "ImGuiSettings.h" #include "ImGuiSettings.h"
#include <ISettingsModule.h> #include <ISettingsModule.h>
@ -22,6 +23,11 @@ namespace
{ {
return FModuleManager::GetModulePtr<ISettingsModule>("Settings"); return FModuleManager::GetModulePtr<ISettingsModule>("Settings");
} }
FPropertyEditorModule* GetPropertyEditorModule()
{
return FModuleManager::GetModulePtr<FPropertyEditorModule>("PropertyEditor");
}
} }
FImGuiEditor::FImGuiEditor() FImGuiEditor::FImGuiEditor()
@ -56,6 +62,17 @@ void FImGuiEditor::Register()
GetMutableDefault<UImGuiSettings>()); GetMutableDefault<UImGuiSettings>());
} }
} }
if (!bCustomPropertyTypeLayoutsRegistered)
{
if (FPropertyEditorModule* PropertyModule = GetPropertyEditorModule())
{
bCustomPropertyTypeLayoutsRegistered = true;
PropertyModule->RegisterCustomPropertyTypeLayout("ImGuiKeyInfo",
FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FImGuiKeyInfoCustomization::MakeInstance));
}
}
} }
void FImGuiEditor::Unregister() void FImGuiEditor::Unregister()
@ -69,6 +86,16 @@ void FImGuiEditor::Unregister()
SettingsModule->UnregisterSettings(SETTINGS_CONTAINER); SettingsModule->UnregisterSettings(SETTINGS_CONTAINER);
} }
} }
if (bCustomPropertyTypeLayoutsRegistered)
{
bCustomPropertyTypeLayoutsRegistered = false;
if (FPropertyEditorModule* PropertyModule = GetPropertyEditorModule())
{
PropertyModule->UnregisterCustomPropertyTypeLayout("ImGuiKeyInfo");
}
}
} }
void FImGuiEditor::CreateRegistrator() void FImGuiEditor::CreateRegistrator()

View File

@ -14,7 +14,7 @@ public:
private: private:
bool IsRegistrationCompleted() const { return bSettingsRegistered; } bool IsRegistrationCompleted() const { return bSettingsRegistered && bCustomPropertyTypeLayoutsRegistered; }
void Register(); void Register();
void Unregister(); void Unregister();
@ -25,6 +25,7 @@ private:
FDelegateHandle RegistratorHandle; FDelegateHandle RegistratorHandle;
bool bSettingsRegistered = false; bool bSettingsRegistered = false;
bool bCustomPropertyTypeLayoutsRegistered = false;
}; };
#endif // WITH_EDITOR #endif // WITH_EDITOR

View File

@ -0,0 +1,211 @@
// Distributed under the MIT License (MIT) (see accompanying LICENSE file)
#include "ImGuiPrivatePCH.h"
#if WITH_EDITOR
#include "ImGuiKeyInfoCustomization.h"
#include "ImGuiSettings.h"
#include <PropertyCustomizationHelpers.h>
#include <SKeySelector.h>
#include <Widgets/SCompoundWidget.h>
#include <Widgets/Input/SCheckBox.h>
#define LOCTEXT_NAMESPACE "ImGuiEditor"
//----------------------------------------------------------------------------------------------------
// Helper widgets
//----------------------------------------------------------------------------------------------------
namespace
{
class SPropertyKeySelector : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SPropertyKeySelector)
{}
SLATE_ARGUMENT(TSharedPtr<IPropertyHandle>, KeyHandle)
SLATE_ATTRIBUTE(FSlateFontInfo, Font)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs)
{
KeyHandle = InArgs._KeyHandle;
ChildSlot
[
SNew(SKeySelector)
.CurrentKey(this, &SPropertyKeySelector::GetCurrentKey)
.OnKeyChanged(this, &SPropertyKeySelector::OnKeyChanged)
.Font(InArgs._Font)
];
}
TOptional<FKey> GetCurrentKey() const
{
TArray<void*> RawPtrs;
KeyHandle->AccessRawData(RawPtrs);
if (RawPtrs.Num())
{
FKey* KeyPtr = static_cast<FKey*>(RawPtrs[0]);
if (KeyPtr)
{
for (int32 Index = 1; Index < RawPtrs.Num(); Index++)
{
if (*static_cast<FKey*>(RawPtrs[Index]) != *KeyPtr)
{
return TOptional<FKey>();
}
}
return *KeyPtr;
}
}
return FKey();
}
void OnKeyChanged(TSharedPtr<FKey> SelectedKey)
{
KeyHandle->SetValueFromFormattedString(SelectedKey->ToString());
}
private:
TSharedPtr<IPropertyHandle> KeyHandle;
};
class SPropertyTriStateCheckBox : public SCompoundWidget
{
public:
using FCheckBoxStateRaw = std::underlying_type<ECheckBoxState>::type;
SLATE_BEGIN_ARGS(SPropertyTriStateCheckBox)
{}
SLATE_ARGUMENT(TSharedPtr<IPropertyHandle>, PropertyHandle)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs)
{
PropertyHandle = InArgs._PropertyHandle;
// We are abusing SCheckBox a bit but our GetPropertyValue with custom OnCheckBoxStateChanged implementation
// gives a checkbox that allows to cycle between all three states.
ChildSlot
[
SNew(SCheckBox)
.IsChecked(this, &SPropertyTriStateCheckBox::GetPropertyValue)
.OnCheckStateChanged(this, &SPropertyTriStateCheckBox::OnCheckBoxStateChanged)
];
}
FCheckBoxStateRaw GetPropertyRawValue() const
{
FCheckBoxStateRaw Value;
PropertyHandle.Get()->GetValue(Value);
return Value;
}
ECheckBoxState GetPropertyValue() const
{
return static_cast<ECheckBoxState>(GetPropertyRawValue());
}
void OnCheckBoxStateChanged(ECheckBoxState State)
{
const FCheckBoxStateRaw PrevEnumValue = (GetPropertyRawValue() + 2) % 3;
PropertyHandle.Get()->SetValue(PrevEnumValue);
}
private:
TSharedPtr<IPropertyHandle> PropertyHandle;
};
}
//----------------------------------------------------------------------------------------------------
// FImGuiKeyInfoCustomization implementation
//----------------------------------------------------------------------------------------------------
namespace InputConstants
{
static const FMargin PropertyPadding(2.0f, 0.0f, 2.0f, 0.0f);
}
TSharedRef<IPropertyTypeCustomization> FImGuiKeyInfoCustomization::MakeInstance()
{
return MakeShareable(new FImGuiKeyInfoCustomization);
}
void FImGuiKeyInfoCustomization::CustomizeHeader(TSharedRef<IPropertyHandle> InStructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
TSharedPtr<IPropertyHandle> KeyHandle = InStructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FImGuiKeyInfo, Key));
TSharedPtr<IPropertyHandle> ShiftHandle = InStructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FImGuiKeyInfo, Shift));
TSharedPtr<IPropertyHandle> CtrlHandle = InStructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FImGuiKeyInfo, Ctrl));
TSharedPtr<IPropertyHandle> AltHandle = InStructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FImGuiKeyInfo, Alt));
TSharedPtr<IPropertyHandle> CmdHandle = InStructPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FImGuiKeyInfo, Cmd));
#define ADD_CHECK_BOX_SLOT(Handle) \
+ SHorizontalBox::Slot()\
.Padding(InputConstants::PropertyPadding)\
.HAlign(HAlign_Left)\
.VAlign(VAlign_Center)\
.AutoWidth()\
[\
Handle->CreatePropertyNameWidget()\
]\
+ SHorizontalBox::Slot()\
.Padding(InputConstants::PropertyPadding)\
.HAlign(HAlign_Left)\
.VAlign(VAlign_Center)\
.AutoWidth()\
[\
SNew(SPropertyTriStateCheckBox).PropertyHandle(Handle)\
]
HeaderRow
.NameContent()
[
InStructPropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
.MaxDesiredWidth(400.f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(InputConstants::PropertyPadding)
.AutoWidth()
[
SNew(SBox)
.WidthOverride(200.f)
[
SNew(SPropertyKeySelector)
.KeyHandle(KeyHandle)
.Font(StructCustomizationUtils.GetRegularFont())
]
]
ADD_CHECK_BOX_SLOT(ShiftHandle)
ADD_CHECK_BOX_SLOT(CtrlHandle)
ADD_CHECK_BOX_SLOT(AltHandle)
ADD_CHECK_BOX_SLOT(CmdHandle)
];
#undef ADD_CHECK_BOX_SLOT
}
void FImGuiKeyInfoCustomization::CustomizeChildren(TSharedRef<IPropertyHandle> InStructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
}
#undef LOCTEXT_NAMESPACE
#endif // WITH_EDITOR

View File

@ -0,0 +1,26 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#pragma once
#if WITH_EDITOR
#include <IPropertyTypeCustomization.h>
#include <PropertyHandle.h>
class FDetailWidgetRow;
class IDetailChildrenBuilder;
class IPropertyHandle;
// Property type customization for FImGuiKeyInfo.
class FImGuiKeyInfoCustomization : public IPropertyTypeCustomization
{
public:
static TSharedRef<IPropertyTypeCustomization> MakeInstance();
// IPropertyTypeCustomization interface
virtual void CustomizeHeader(TSharedRef<IPropertyHandle> InStructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override;
virtual void CustomizeChildren(TSharedRef<IPropertyHandle> InStructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override;
};
#endif // WITH_EDITOR

View File

@ -70,19 +70,19 @@ protected:
// Path to own implementation of ImGui Input Handler allowing to customize handling of keyboard and gamepad input. // Path to own implementation of ImGui Input Handler allowing to customize handling of keyboard and gamepad input.
// If not set then default handler is used. // If not set then default handler is used.
UPROPERTY(EditAnywhere, config, Category = "Input", meta = (MetaClass = "ImGuiInputHandler")) UPROPERTY(EditAnywhere, config, Category = "Extensions", meta = (MetaClass = "ImGuiInputHandler"))
FStringClassReference ImGuiInputHandlerClass; FStringClassReference ImGuiInputHandlerClass;
// Define a custom key binding to 'ImGui.SwitchInputMode' command. Mapping will be only set if Key property in this // Define a custom key binding to 'ImGui.SwitchInputMode' command. Binding is only set if key is valid.
// structure is set to a valid key. Modifier keys can be either completely ignored (Undetermined), required to be // Note that modifier key properties can be set to one of the three values: undetermined means that state of the given
// pressed (Checked) or required to be not pressed (Unchecked). // modifier is not tested, checked means that it needs to be pressed and unchecked means that it cannot be pressed.
UPROPERTY(EditAnywhere, config, Category = "Input") //
// This binding is using Player Input's DebugExecBindings which only works in non-shipment builds.
UPROPERTY(EditAnywhere, config, Category = "Keyboard Shortcuts")
FImGuiKeyInfo SwitchInputModeKey; FImGuiKeyInfo SwitchInputModeKey;
private: private:
void UpdateSwitchInputModeBinding();
#if WITH_EDITOR #if WITH_EDITOR
void RegisterPropertyChangedDelegate(); void RegisterPropertyChangedDelegate();

View File

@ -90,7 +90,7 @@ private:
* Also note that input handler functions are only called when ImGui Widget is receiving input events, what can be for * Also note that input handler functions are only called when ImGui Widget is receiving input events, what can be for
* instance suppressed by opening console. * instance suppressed by opening console.
* *
* See @ Project Settings/Plugins/ImGui/Input/ImGuiInputHandlerClass property to set custom implementation. * See @ Project Settings/Plugins/ImGui/Extensions/ImGuiInputHandlerClass property to set custom implementation.
*/ */
UCLASS() UCLASS()
class IMGUI_API UImGuiInputHandler : public UObject class IMGUI_API UImGuiInputHandler : public UObject