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(
new string[]
{
"EditorStyle",
"Settings",
"UnrealEd",
}

View File

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

View File

@ -14,7 +14,7 @@ public:
private:
bool IsRegistrationCompleted() const { return bSettingsRegistered; }
bool IsRegistrationCompleted() const { return bSettingsRegistered && bCustomPropertyTypeLayoutsRegistered; }
void Register();
void Unregister();
@ -25,6 +25,7 @@ private:
FDelegateHandle RegistratorHandle;
bool bSettingsRegistered = false;
bool bCustomPropertyTypeLayoutsRegistered = false;
};
#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.
// 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;
// Define a custom key binding to 'ImGui.SwitchInputMode' command. Mapping will be only set if Key property in this
// structure is set to a valid key. Modifier keys can be either completely ignored (Undetermined), required to be
// pressed (Checked) or required to be not pressed (Unchecked).
UPROPERTY(EditAnywhere, config, Category = "Input")
// Define a custom key binding to 'ImGui.SwitchInputMode' command. Binding is only set if key 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 tested, checked means that it needs to be pressed and unchecked means that it cannot be pressed.
//
// This binding is using Player Input's DebugExecBindings which only works in non-shipment builds.
UPROPERTY(EditAnywhere, config, Category = "Keyboard Shortcuts")
FImGuiKeyInfo SwitchInputModeKey;
private:
void UpdateSwitchInputModeBinding();
#if WITH_EDITOR
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
* 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()
class IMGUI_API UImGuiInputHandler : public UObject