2017-03-26 20:32:57 +00:00
|
|
|
// Distributed under the MIT License (MIT) (see accompanying LICENSE file)
|
|
|
|
|
|
|
|
#include "ImGuiPrivatePCH.h"
|
|
|
|
|
|
|
|
#include "SImGuiWidget.h"
|
2019-03-13 20:40:13 +00:00
|
|
|
#include "SImGuiCanvasControl.h"
|
2017-03-26 20:32:57 +00:00
|
|
|
|
2017-08-28 19:29:07 +00:00
|
|
|
#include "ImGuiContextManager.h"
|
2017-04-22 15:38:04 +00:00
|
|
|
#include "ImGuiContextProxy.h"
|
2018-07-10 16:40:57 +00:00
|
|
|
#include "ImGuiInputHandler.h"
|
|
|
|
#include "ImGuiInputHandlerFactory.h"
|
2017-04-22 15:38:04 +00:00
|
|
|
#include "ImGuiInteroperability.h"
|
2017-03-26 20:32:57 +00:00
|
|
|
#include "ImGuiModuleManager.h"
|
2018-12-08 21:15:20 +00:00
|
|
|
#include "ImGuiModuleSettings.h"
|
2017-03-26 20:32:57 +00:00
|
|
|
#include "TextureManager.h"
|
2018-04-21 21:43:15 +00:00
|
|
|
#include "Utilities/Arrays.h"
|
2017-03-26 20:32:57 +00:00
|
|
|
#include "Utilities/ScopeGuards.h"
|
|
|
|
|
2017-09-16 20:52:14 +00:00
|
|
|
#include <Engine/Console.h>
|
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
#include <utility>
|
|
|
|
|
2017-03-26 20:32:57 +00:00
|
|
|
|
2018-10-30 22:25:48 +00:00
|
|
|
#if IMGUI_WIDGET_DEBUG
|
|
|
|
|
2017-09-09 10:40:44 +00:00
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LogImGuiWidget, Warning, All);
|
|
|
|
|
2018-10-30 22:25:48 +00:00
|
|
|
#define IMGUI_WIDGET_LOG(Verbosity, Format, ...) UE_LOG(LogImGuiWidget, Verbosity, Format, __VA_ARGS__)
|
|
|
|
|
2017-09-21 21:09:03 +00:00
|
|
|
#define TEXT_INPUT_MODE(Val) (\
|
2018-05-17 22:25:47 +00:00
|
|
|
(Val) == EInputMode::Full ? TEXT("Full") :\
|
2017-09-21 21:09:03 +00:00
|
|
|
(Val) == EInputMode::MousePointerOnly ? TEXT("MousePointerOnly") :\
|
|
|
|
TEXT("None"))
|
|
|
|
|
2017-09-09 10:40:44 +00:00
|
|
|
#define TEXT_BOOL(Val) ((Val) ? TEXT("true") : TEXT("false"))
|
|
|
|
|
2018-10-30 22:25:48 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
#define IMGUI_WIDGET_LOG(...)
|
|
|
|
|
|
|
|
#endif // IMGUI_WIDGET_DEBUG
|
2017-09-09 10:40:44 +00:00
|
|
|
|
2018-10-30 22:25:48 +00:00
|
|
|
#if IMGUI_WIDGET_DEBUG
|
|
|
|
namespace CVars
|
|
|
|
{
|
2017-09-09 10:40:44 +00:00
|
|
|
TAutoConsoleVariable<int> DebugWidget(TEXT("ImGui.Debug.Widget"), 0,
|
|
|
|
TEXT("Show debug for SImGuiWidget.\n")
|
|
|
|
TEXT("0: disabled (default)\n")
|
2018-03-13 23:42:37 +00:00
|
|
|
TEXT("1: enabled"),
|
2017-09-09 10:40:44 +00:00
|
|
|
ECVF_Default);
|
2018-01-15 22:07:28 +00:00
|
|
|
|
|
|
|
TAutoConsoleVariable<int> DebugInput(TEXT("ImGui.Debug.Input"), 0,
|
|
|
|
TEXT("Show debug for input state.\n")
|
|
|
|
TEXT("0: disabled (default)\n")
|
2018-03-13 23:42:37 +00:00
|
|
|
TEXT("1: enabled"),
|
2018-01-15 22:07:28 +00:00
|
|
|
ECVF_Default);
|
2017-09-02 17:42:41 +00:00
|
|
|
}
|
2018-10-30 22:25:48 +00:00
|
|
|
#endif // IMGUI_WIDGET_DEBUG
|
2017-09-02 17:42:41 +00:00
|
|
|
|
2017-03-26 20:32:57 +00:00
|
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
void SImGuiWidget::Construct(const FArguments& InArgs)
|
|
|
|
{
|
|
|
|
checkf(InArgs._ModuleManager, TEXT("Null Module Manager argument"));
|
2017-09-27 20:16:54 +00:00
|
|
|
checkf(InArgs._GameViewport, TEXT("Null Game Viewport argument"));
|
2017-09-09 10:40:44 +00:00
|
|
|
|
2017-03-26 20:32:57 +00:00
|
|
|
ModuleManager = InArgs._ModuleManager;
|
2017-09-27 20:16:54 +00:00
|
|
|
GameViewport = InArgs._GameViewport;
|
2017-08-28 19:29:07 +00:00
|
|
|
ContextIndex = InArgs._ContextIndex;
|
2017-04-22 15:38:04 +00:00
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
// Register to get post-update notifications.
|
2017-09-09 10:40:44 +00:00
|
|
|
ModuleManager->OnPostImGuiUpdate().AddRaw(this, &SImGuiWidget::OnPostImGuiUpdate);
|
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
// Register debug delegate.
|
2017-09-09 10:40:44 +00:00
|
|
|
auto* ContextProxy = ModuleManager->GetContextManager().GetContextProxy(ContextIndex);
|
|
|
|
checkf(ContextProxy, TEXT("Missing context during widget construction: ContextIndex = %d"), ContextIndex);
|
2018-10-30 22:25:48 +00:00
|
|
|
#if IMGUI_WIDGET_DEBUG
|
2017-09-09 10:40:44 +00:00
|
|
|
ContextProxy->OnDraw().AddRaw(this, &SImGuiWidget::OnDebugDraw);
|
2018-10-30 22:25:48 +00:00
|
|
|
#endif // IMGUI_WIDGET_DEBUG
|
2018-07-10 16:40:57 +00:00
|
|
|
|
2018-12-08 21:03:18 +00:00
|
|
|
// Register for settings change.
|
|
|
|
RegisterImGuiSettingsDelegates();
|
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
// Get initial settings.
|
2018-12-08 21:03:18 +00:00
|
|
|
const auto& Settings = ModuleManager->GetSettings();
|
2019-06-30 17:25:58 +00:00
|
|
|
SetHideMouseCursor(Settings.UseSoftwareCursor());
|
2018-12-08 21:03:18 +00:00
|
|
|
CreateInputHandler(Settings.GetImGuiInputHandlerClass());
|
2019-03-13 20:40:13 +00:00
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
// Initialize state.
|
|
|
|
UpdateVisibility();
|
|
|
|
UpdateMouseCursor();
|
|
|
|
|
2019-03-13 20:40:13 +00:00
|
|
|
ChildSlot
|
|
|
|
[
|
|
|
|
SAssignNew(CanvasControlWidget, SImGuiCanvasControl).OnTransformChanged(this, &SImGuiWidget::SetImGuiTransform)
|
|
|
|
];
|
|
|
|
|
|
|
|
ImGuiTransform = CanvasControlWidget->GetTransform();
|
2017-03-26 20:32:57 +00:00
|
|
|
}
|
|
|
|
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
|
2017-04-22 15:38:04 +00:00
|
|
|
SImGuiWidget::~SImGuiWidget()
|
|
|
|
{
|
2018-10-28 21:15:02 +00:00
|
|
|
// Stop listening for settings change.
|
|
|
|
UnregisterImGuiSettingsDelegates();
|
|
|
|
|
2018-07-10 16:40:57 +00:00
|
|
|
// Release ImGui Input Handler.
|
|
|
|
ReleaseInputHandler();
|
|
|
|
|
2017-09-09 10:40:44 +00:00
|
|
|
// Remove binding between this widget and its context proxy.
|
|
|
|
if (auto* ContextProxy = ModuleManager->GetContextManager().GetContextProxy(ContextIndex))
|
|
|
|
{
|
2018-10-30 22:25:48 +00:00
|
|
|
#if IMGUI_WIDGET_DEBUG
|
2017-09-09 10:40:44 +00:00
|
|
|
ContextProxy->OnDraw().RemoveAll(this);
|
2018-10-30 22:25:48 +00:00
|
|
|
#endif // IMGUI_WIDGET_DEBUG
|
2017-09-09 10:40:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Unregister from post-update notifications.
|
2017-04-22 15:38:04 +00:00
|
|
|
ModuleManager->OnPostImGuiUpdate().RemoveAll(this);
|
|
|
|
}
|
|
|
|
|
2017-09-02 17:42:41 +00:00
|
|
|
void SImGuiWidget::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
|
|
|
|
{
|
|
|
|
Super::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
|
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
UpdateInputState();
|
|
|
|
HandleWindowFocusLost();
|
2018-07-10 16:40:57 +00:00
|
|
|
}
|
2017-09-16 20:52:14 +00:00
|
|
|
|
2018-07-10 16:40:57 +00:00
|
|
|
FReply SImGuiWidget::OnKeyChar(const FGeometry& MyGeometry, const FCharacterEvent& CharacterEvent)
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
return InputHandler->OnKeyChar(CharacterEvent);
|
2017-04-22 15:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FReply SImGuiWidget::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent)
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
UpdateCanvasControlMode(KeyEvent);
|
|
|
|
return InputHandler->OnKeyDown(KeyEvent);
|
2017-04-22 15:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FReply SImGuiWidget::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent)
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
UpdateCanvasControlMode(KeyEvent);
|
|
|
|
return InputHandler->OnKeyUp(KeyEvent);
|
2018-05-17 22:25:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FReply SImGuiWidget::OnAnalogValueChanged(const FGeometry& MyGeometry, const FAnalogInputEvent& AnalogInputEvent)
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
return InputHandler->OnAnalogValueChanged(AnalogInputEvent);
|
2017-04-22 15:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FReply SImGuiWidget::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
return InputHandler->OnMouseButtonDown(MouseEvent).LockMouseToWidget(SharedThis(this));
|
2017-04-22 15:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FReply SImGuiWidget::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
return InputHandler->OnMouseButtonDoubleClick(MouseEvent).LockMouseToWidget(SharedThis(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
bool NeedMouseLock(const FPointerEvent& MouseEvent)
|
|
|
|
{
|
|
|
|
#if FROM_ENGINE_VERSION(4, 20)
|
|
|
|
return FSlateApplication::Get().GetPressedMouseButtons().Num() > 0;
|
|
|
|
#else
|
|
|
|
return MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton) || MouseEvent.IsMouseButtonDown(EKeys::MiddleMouseButton)
|
|
|
|
|| MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton);
|
|
|
|
#endif
|
|
|
|
}
|
2017-04-22 15:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FReply SImGuiWidget::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
FReply Reply = InputHandler->OnMouseButtonUp(MouseEvent);
|
|
|
|
if (!NeedMouseLock(MouseEvent))
|
|
|
|
{
|
|
|
|
Reply.ReleaseMouseLock();
|
|
|
|
}
|
|
|
|
return Reply;
|
2017-04-22 15:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FReply SImGuiWidget::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
return InputHandler->OnMouseWheel(MouseEvent);
|
2017-04-22 15:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FReply SImGuiWidget::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
|
|
|
{
|
2019-03-13 20:40:13 +00:00
|
|
|
const FSlateRenderTransform ImGuiToScreen = ImGuiTransform.Concatenate(MyGeometry.GetAccumulatedRenderTransform());
|
2019-06-30 17:25:58 +00:00
|
|
|
return InputHandler->OnMouseMove(ImGuiToScreen.Inverse().TransformPoint(MouseEvent.GetScreenSpacePosition()));
|
2017-04-22 15:38:04 +00:00
|
|
|
}
|
|
|
|
|
2017-08-28 19:29:07 +00:00
|
|
|
FReply SImGuiWidget::OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& FocusEvent)
|
|
|
|
{
|
|
|
|
Super::OnFocusReceived(MyGeometry, FocusEvent);
|
|
|
|
|
2018-10-30 22:25:48 +00:00
|
|
|
IMGUI_WIDGET_LOG(VeryVerbose, TEXT("ImGui Widget %d - Focus Received."), ContextIndex);
|
2017-09-09 10:40:44 +00:00
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
bForegroundWindow = GameViewport->Viewport->IsForegroundWindow();
|
|
|
|
InputHandler->OnKeyboardInputEnabled();
|
|
|
|
InputHandler->OnGamepadInputEnabled();
|
2017-08-28 19:29:07 +00:00
|
|
|
|
2017-09-16 20:52:14 +00:00
|
|
|
FSlateApplication::Get().ResetToDefaultPointerInputSettings();
|
2019-03-13 20:40:13 +00:00
|
|
|
return FReply::Handled();
|
2017-08-28 19:29:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SImGuiWidget::OnFocusLost(const FFocusEvent& FocusEvent)
|
|
|
|
{
|
|
|
|
Super::OnFocusLost(FocusEvent);
|
|
|
|
|
2018-10-30 22:25:48 +00:00
|
|
|
IMGUI_WIDGET_LOG(VeryVerbose, TEXT("ImGui Widget %d - Focus Lost."), ContextIndex);
|
2017-09-09 10:40:44 +00:00
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
InputHandler->OnKeyboardInputDisabled();
|
|
|
|
InputHandler->OnGamepadInputDisabled();
|
2017-08-28 19:29:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SImGuiWidget::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
|
|
|
|
{
|
|
|
|
Super::OnMouseEnter(MyGeometry, MouseEvent);
|
|
|
|
|
2018-10-30 22:25:48 +00:00
|
|
|
IMGUI_WIDGET_LOG(VeryVerbose, TEXT("ImGui Widget %d - Mouse Enter."), ContextIndex);
|
2017-09-09 10:40:44 +00:00
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
InputHandler->OnMouseInputEnabled();
|
2017-08-28 19:29:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SImGuiWidget::OnMouseLeave(const FPointerEvent& MouseEvent)
|
|
|
|
{
|
|
|
|
Super::OnMouseLeave(MouseEvent);
|
|
|
|
|
2018-10-30 22:25:48 +00:00
|
|
|
IMGUI_WIDGET_LOG(VeryVerbose, TEXT("ImGui Widget %d - Mouse Leave."), ContextIndex);
|
2017-09-09 10:40:44 +00:00
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
InputHandler->OnMouseInputDisabled();
|
2018-07-10 16:40:57 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 21:03:18 +00:00
|
|
|
void SImGuiWidget::CreateInputHandler(const FStringClassReference& HandlerClassReference)
|
2018-07-10 16:40:57 +00:00
|
|
|
{
|
2018-12-08 21:03:18 +00:00
|
|
|
ReleaseInputHandler();
|
|
|
|
|
2018-07-10 16:40:57 +00:00
|
|
|
if (!InputHandler.IsValid())
|
|
|
|
{
|
2018-12-08 21:03:18 +00:00
|
|
|
InputHandler = FImGuiInputHandlerFactory::NewHandler(HandlerClassReference, ModuleManager, GameViewport.Get(), ContextIndex);
|
2018-07-10 16:40:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SImGuiWidget::ReleaseInputHandler()
|
|
|
|
{
|
|
|
|
if (InputHandler.IsValid())
|
|
|
|
{
|
|
|
|
FImGuiInputHandlerFactory::ReleaseHandler(InputHandler.Get());
|
|
|
|
InputHandler.Reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-28 21:15:02 +00:00
|
|
|
void SImGuiWidget::RegisterImGuiSettingsDelegates()
|
2018-07-10 16:40:57 +00:00
|
|
|
{
|
2018-12-08 21:03:18 +00:00
|
|
|
auto& Settings = ModuleManager->GetSettings();
|
|
|
|
|
|
|
|
if (!Settings.OnImGuiInputHandlerClassChanged.IsBoundToObject(this))
|
2018-07-10 16:40:57 +00:00
|
|
|
{
|
2018-12-08 21:03:18 +00:00
|
|
|
Settings.OnImGuiInputHandlerClassChanged.AddRaw(this, &SImGuiWidget::CreateInputHandler);
|
|
|
|
}
|
|
|
|
if (!Settings.OnUseSoftwareCursorChanged.IsBoundToObject(this))
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
Settings.OnUseSoftwareCursorChanged.AddRaw(this, &SImGuiWidget::SetHideMouseCursor);
|
2018-07-10 16:40:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-28 21:15:02 +00:00
|
|
|
void SImGuiWidget::UnregisterImGuiSettingsDelegates()
|
2018-07-10 16:40:57 +00:00
|
|
|
{
|
2018-12-08 21:03:18 +00:00
|
|
|
auto& Settings = ModuleManager->GetSettings();
|
|
|
|
|
|
|
|
Settings.OnImGuiInputHandlerClassChanged.RemoveAll(this);
|
|
|
|
Settings.OnUseSoftwareCursorChanged.RemoveAll(this);
|
2018-07-10 16:40:57 +00:00
|
|
|
}
|
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
void SImGuiWidget::SetHideMouseCursor(bool bHide)
|
2017-08-19 20:19:38 +00:00
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
if (bHideMouseCursor != bHide)
|
|
|
|
{
|
|
|
|
bHideMouseCursor = bHide;
|
|
|
|
UpdateMouseCursor();
|
|
|
|
}
|
2017-08-19 20:19:38 +00:00
|
|
|
}
|
|
|
|
|
2017-09-16 20:52:14 +00:00
|
|
|
bool SImGuiWidget::IsConsoleOpened() const
|
|
|
|
{
|
|
|
|
return GameViewport->ViewportConsole && GameViewport->ViewportConsole->ConsoleState != NAME_None;
|
|
|
|
}
|
|
|
|
|
2019-03-13 20:40:13 +00:00
|
|
|
void SImGuiWidget::UpdateVisibility()
|
2017-09-02 17:42:41 +00:00
|
|
|
{
|
|
|
|
// If we don't use input disable hit test to make this widget invisible for cursors hit detection.
|
|
|
|
SetVisibility(bInputEnabled ? EVisibility::Visible : EVisibility::HitTestInvisible);
|
2017-09-09 10:40:44 +00:00
|
|
|
|
2018-10-30 22:25:48 +00:00
|
|
|
IMGUI_WIDGET_LOG(VeryVerbose, TEXT("ImGui Widget %d - Visibility updated to '%s'."),
|
2017-09-09 10:40:44 +00:00
|
|
|
ContextIndex, *GetVisibility().ToString());
|
2017-09-02 17:42:41 +00:00
|
|
|
}
|
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
void SImGuiWidget::UpdateMouseCursor()
|
|
|
|
{
|
|
|
|
if (!bHideMouseCursor)
|
|
|
|
{
|
|
|
|
const FImGuiContextProxy* ContextProxy = ModuleManager->GetContextManager().GetContextProxy(ContextIndex);
|
|
|
|
SetCursor(ContextProxy ? ContextProxy->GetMouseCursor() : EMouseCursor::Default);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetCursor(EMouseCursor::None);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-05 20:48:19 +00:00
|
|
|
ULocalPlayer* SImGuiWidget::GetLocalPlayer() const
|
|
|
|
{
|
|
|
|
if (GameViewport.IsValid())
|
|
|
|
{
|
|
|
|
if (UWorld* World = GameViewport->GetWorld())
|
|
|
|
{
|
|
|
|
if (ULocalPlayer* LocalPlayer = World->GetFirstLocalPlayerFromController())
|
|
|
|
{
|
|
|
|
return World->GetFirstLocalPlayerFromController();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SImGuiWidget::TakeFocus()
|
|
|
|
{
|
|
|
|
auto& SlateApplication = FSlateApplication::Get();
|
|
|
|
|
|
|
|
PreviousUserFocusedWidget = SlateApplication.GetUserFocusedWidget(SlateApplication.GetUserIndexForKeyboard());
|
|
|
|
|
|
|
|
if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
|
|
|
|
{
|
|
|
|
TSharedRef<SWidget> FocusWidget = SharedThis(this);
|
|
|
|
LocalPlayer->GetSlateOperations().CaptureMouse(FocusWidget);
|
|
|
|
LocalPlayer->GetSlateOperations().SetUserFocus(FocusWidget);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SlateApplication.SetKeyboardFocus(SharedThis(this));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SImGuiWidget::ReturnFocus()
|
|
|
|
{
|
|
|
|
if (HasKeyboardFocus())
|
|
|
|
{
|
|
|
|
auto FocusWidgetPtr = PreviousUserFocusedWidget.IsValid()
|
|
|
|
? PreviousUserFocusedWidget.Pin()
|
|
|
|
: GameViewport->GetGameViewportWidget();
|
|
|
|
|
|
|
|
if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
|
|
|
|
{
|
|
|
|
auto FocusWidgetRef = FocusWidgetPtr.ToSharedRef();
|
|
|
|
LocalPlayer->GetSlateOperations().CaptureMouse(FocusWidgetRef);
|
|
|
|
LocalPlayer->GetSlateOperations().SetUserFocus(FocusWidgetRef);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto& SlateApplication = FSlateApplication::Get();
|
|
|
|
SlateApplication.ResetToDefaultPointerInputSettings();
|
|
|
|
SlateApplication.SetUserFocus(SlateApplication.GetUserIndexForKeyboard(), FocusWidgetPtr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PreviousUserFocusedWidget.Reset();
|
|
|
|
}
|
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
void SImGuiWidget::UpdateInputState()
|
2017-09-02 17:42:41 +00:00
|
|
|
{
|
2018-11-25 20:36:55 +00:00
|
|
|
const bool bEnabled = ModuleManager && ModuleManager->GetProperties().IsInputEnabled();
|
2017-09-02 17:42:41 +00:00
|
|
|
if (bInputEnabled != bEnabled)
|
|
|
|
{
|
2018-10-30 22:25:48 +00:00
|
|
|
IMGUI_WIDGET_LOG(Log, TEXT("ImGui Widget %d - Input Enabled changed to '%s'."),
|
2019-06-30 17:25:58 +00:00
|
|
|
ContextIndex, TEXT_BOOL(bEnabled));
|
|
|
|
|
|
|
|
bInputEnabled = bEnabled;
|
2017-09-09 10:40:44 +00:00
|
|
|
|
2019-03-13 20:40:13 +00:00
|
|
|
UpdateVisibility();
|
2019-06-30 17:25:58 +00:00
|
|
|
UpdateMouseCursor();
|
2017-09-02 17:42:41 +00:00
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
if (bInputEnabled)
|
|
|
|
{
|
|
|
|
// We won't get mouse enter, if viewport is already hovered.
|
|
|
|
if (GameViewport->GetGameViewportWidget()->IsHovered())
|
|
|
|
{
|
|
|
|
InputHandler->OnMouseInputEnabled();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Focus is handled later as it can depend on additional factors.
|
|
|
|
}
|
|
|
|
else
|
2017-09-02 17:42:41 +00:00
|
|
|
{
|
2019-02-05 20:48:19 +00:00
|
|
|
ReturnFocus();
|
2017-09-02 17:42:41 +00:00
|
|
|
}
|
|
|
|
}
|
2017-09-16 20:52:14 +00:00
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
// We should request a focus, if we are in the input mode and don't have one. But we should wait, if this is not
|
|
|
|
// a foreground window (application), if viewport doesn't have a focus or if console is opened. Note that this
|
|
|
|
// will keep this widget from releasing focus to viewport or other widgets as long as we are in the input mode.
|
|
|
|
if (bInputEnabled && GameViewport->Viewport->IsForegroundWindow() && !HasKeyboardFocus() && !IsConsoleOpened())
|
2017-09-16 20:52:14 +00:00
|
|
|
{
|
|
|
|
const auto& ViewportWidget = GameViewport->GetGameViewportWidget();
|
|
|
|
if (ViewportWidget->HasKeyboardFocus() || ViewportWidget->HasFocusedDescendants())
|
|
|
|
{
|
2019-02-05 20:48:19 +00:00
|
|
|
TakeFocus();
|
2017-09-16 20:52:14 +00:00
|
|
|
}
|
|
|
|
}
|
2017-09-02 17:42:41 +00:00
|
|
|
}
|
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
void SImGuiWidget::HandleWindowFocusLost()
|
2017-08-28 19:29:07 +00:00
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
// We can use window foreground status to notify about application losing or receiving focus. In some situations
|
|
|
|
// we get mouse leave or enter events, but they are only sent if mouse pointer is inside of the viewport.
|
|
|
|
if (bInputEnabled && HasKeyboardFocus())
|
2017-08-28 19:29:07 +00:00
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
if (bForegroundWindow != GameViewport->Viewport->IsForegroundWindow())
|
2017-08-28 19:29:07 +00:00
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
bForegroundWindow = !bForegroundWindow;
|
2017-08-28 19:29:07 +00:00
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
IMGUI_WIDGET_LOG(VeryVerbose, TEXT("ImGui Widget %d - Updating input after %s foreground window status."),
|
|
|
|
ContextIndex, bForegroundWindow ? TEXT("getting") : TEXT("losing"));
|
2017-09-21 21:09:03 +00:00
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
if (bForegroundWindow)
|
|
|
|
{
|
|
|
|
InputHandler->OnKeyboardInputEnabled();
|
|
|
|
InputHandler->OnGamepadInputEnabled();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
InputHandler->OnKeyboardInputDisabled();
|
|
|
|
InputHandler->OnGamepadInputDisabled();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-21 21:09:03 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 20:40:13 +00:00
|
|
|
void SImGuiWidget::UpdateCanvasControlMode(const FInputEvent& InputEvent)
|
2018-04-21 21:43:15 +00:00
|
|
|
{
|
2019-03-13 20:40:13 +00:00
|
|
|
CanvasControlWidget->SetActive(InputEvent.IsLeftAltDown() && InputEvent.IsLeftShiftDown());
|
2018-04-21 21:43:15 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 20:40:13 +00:00
|
|
|
void SImGuiWidget::OnPostImGuiUpdate()
|
2018-04-21 21:43:15 +00:00
|
|
|
{
|
2019-03-13 20:40:13 +00:00
|
|
|
ImGuiRenderTransform = ImGuiTransform;
|
2019-06-30 17:25:58 +00:00
|
|
|
UpdateMouseCursor();
|
2018-04-21 21:43:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2019-03-13 20:40:13 +00:00
|
|
|
FORCEINLINE FSlateRenderTransform RoundTranslation(const FSlateRenderTransform& Transform)
|
2018-04-21 21:43:15 +00:00
|
|
|
{
|
2019-03-13 20:40:13 +00:00
|
|
|
const FVector2D& Translation = Transform.GetTranslation();
|
|
|
|
return FSlateRenderTransform{ Transform.GetMatrix(),
|
|
|
|
FVector2D{ FMath::RoundToFloat(Translation.X), FMath::RoundToFloat(Translation.Y) } };
|
2018-04-21 21:43:15 +00:00
|
|
|
}
|
2017-04-22 15:38:04 +00:00
|
|
|
}
|
|
|
|
|
2017-03-26 20:32:57 +00:00
|
|
|
int32 SImGuiWidget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect,
|
|
|
|
FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& WidgetStyle, bool bParentEnabled) const
|
|
|
|
{
|
2017-08-28 19:29:07 +00:00
|
|
|
if (FImGuiContextProxy* ContextProxy = ModuleManager->GetContextManager().GetContextProxy(ContextIndex))
|
|
|
|
{
|
2018-03-18 19:45:08 +00:00
|
|
|
// Manually update ImGui context to minimise lag between creating and rendering ImGui output. This will also
|
|
|
|
// keep frame tearing at minimum because it is executed at the very end of the frame.
|
|
|
|
ContextProxy->Tick(FSlateApplication::Get().GetDeltaTime());
|
|
|
|
|
2019-03-13 20:40:13 +00:00
|
|
|
// Calculate transform from ImGui to screen space. Rounding translation is necessary to keep it pixel-perfect
|
|
|
|
// in older engine versions.
|
|
|
|
const FSlateRenderTransform& WidgetToScreen = AllottedGeometry.GetAccumulatedRenderTransform();
|
|
|
|
const FSlateRenderTransform ImGuiToScreen = RoundTranslation(ImGuiRenderTransform.Concatenate(WidgetToScreen));
|
2017-03-26 20:32:57 +00:00
|
|
|
|
2018-08-10 21:20:33 +00:00
|
|
|
#if ENGINE_COMPATIBILITY_LEGACY_CLIPPING_API
|
2017-08-28 19:29:07 +00:00
|
|
|
// Convert clipping rectangle to format required by Slate vertex.
|
|
|
|
const FSlateRotatedRect VertexClippingRect{ MyClippingRect };
|
2018-08-10 21:20:33 +00:00
|
|
|
#endif // ENGINE_COMPATIBILITY_LEGACY_CLIPPING_API
|
2018-04-17 19:28:29 +00:00
|
|
|
|
2017-08-28 19:29:07 +00:00
|
|
|
for (const auto& DrawList : ContextProxy->GetDrawData())
|
|
|
|
{
|
2018-08-10 21:20:33 +00:00
|
|
|
#if ENGINE_COMPATIBILITY_LEGACY_CLIPPING_API
|
2019-03-13 20:40:13 +00:00
|
|
|
DrawList.CopyVertexData(VertexBuffer, ImGuiToScreen, VertexClippingRect);
|
2017-03-26 20:32:57 +00:00
|
|
|
|
2017-08-28 19:29:07 +00:00
|
|
|
// Get access to the Slate scissor rectangle defined in Slate Core API, so we can customize elements drawing.
|
|
|
|
extern SLATECORE_API TOptional<FShortRect> GSlateScissorRect;
|
|
|
|
auto GSlateScissorRectSaver = ScopeGuards::MakeStateSaver(GSlateScissorRect);
|
2017-11-05 19:41:34 +00:00
|
|
|
#else
|
2019-03-13 20:40:13 +00:00
|
|
|
DrawList.CopyVertexData(VertexBuffer, ImGuiToScreen);
|
2018-08-10 21:20:33 +00:00
|
|
|
#endif // ENGINE_COMPATIBILITY_LEGACY_CLIPPING_API
|
2017-03-26 20:32:57 +00:00
|
|
|
|
2017-08-28 19:29:07 +00:00
|
|
|
int IndexBufferOffset = 0;
|
|
|
|
for (int CommandNb = 0; CommandNb < DrawList.NumCommands(); CommandNb++)
|
|
|
|
{
|
2019-03-13 20:40:13 +00:00
|
|
|
const auto& DrawCommand = DrawList.GetCommand(CommandNb, ImGuiToScreen);
|
2017-03-26 20:32:57 +00:00
|
|
|
|
2017-08-28 19:29:07 +00:00
|
|
|
DrawList.CopyIndexData(IndexBuffer, IndexBufferOffset, DrawCommand.NumElements);
|
2017-03-26 20:32:57 +00:00
|
|
|
|
2017-08-28 19:29:07 +00:00
|
|
|
// Advance offset by number of copied elements to position it for the next command.
|
|
|
|
IndexBufferOffset += DrawCommand.NumElements;
|
2017-03-26 20:32:57 +00:00
|
|
|
|
2017-08-28 19:29:07 +00:00
|
|
|
// Get texture resource handle for this draw command (null index will be also mapped to a valid texture).
|
|
|
|
const FSlateResourceHandle& Handle = ModuleManager->GetTextureManager().GetTextureHandle(DrawCommand.TextureId);
|
2017-03-26 20:32:57 +00:00
|
|
|
|
2017-11-05 19:41:34 +00:00
|
|
|
// Transform clipping rectangle to screen space and apply to elements that we draw.
|
2018-04-17 19:28:29 +00:00
|
|
|
const FSlateRect ClippingRect = DrawCommand.ClippingRect.IntersectionWith(MyClippingRect);
|
2017-11-05 19:41:34 +00:00
|
|
|
|
2018-08-10 21:20:33 +00:00
|
|
|
#if ENGINE_COMPATIBILITY_LEGACY_CLIPPING_API
|
2017-11-05 19:41:34 +00:00
|
|
|
GSlateScissorRect = FShortRect{ ClippingRect };
|
|
|
|
#else
|
|
|
|
OutDrawElements.PushClip(FSlateClippingZone{ ClippingRect });
|
2018-08-10 21:20:33 +00:00
|
|
|
#endif // ENGINE_COMPATIBILITY_LEGACY_CLIPPING_API
|
2017-03-26 20:32:57 +00:00
|
|
|
|
2017-08-28 19:29:07 +00:00
|
|
|
// Add elements to the list.
|
|
|
|
FSlateDrawElement::MakeCustomVerts(OutDrawElements, LayerId, Handle, VertexBuffer, IndexBuffer, nullptr, 0, 0);
|
2017-11-05 19:41:34 +00:00
|
|
|
|
2018-08-10 21:20:33 +00:00
|
|
|
#if !ENGINE_COMPATIBILITY_LEGACY_CLIPPING_API
|
2017-11-05 19:41:34 +00:00
|
|
|
OutDrawElements.PopClip();
|
2018-08-10 21:20:33 +00:00
|
|
|
#endif // ENGINE_COMPATIBILITY_LEGACY_CLIPPING_API
|
2017-08-28 19:29:07 +00:00
|
|
|
}
|
2017-03-26 20:32:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-13 20:40:13 +00:00
|
|
|
return Super::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, WidgetStyle, bParentEnabled);
|
2017-03-26 20:32:57 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 20:40:13 +00:00
|
|
|
FVector2D SImGuiWidget::ComputeDesiredSize(float Scale) const
|
2017-03-26 20:32:57 +00:00
|
|
|
{
|
2019-03-13 20:40:13 +00:00
|
|
|
return FVector2D{ 3840.f, 2160.f } * Scale;
|
2017-03-26 20:32:57 +00:00
|
|
|
}
|
2017-09-09 10:40:44 +00:00
|
|
|
|
2018-10-30 22:25:48 +00:00
|
|
|
#if IMGUI_WIDGET_DEBUG
|
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
static TArray<FKey> GetImGuiMappedKeys()
|
|
|
|
{
|
|
|
|
TArray<FKey> Keys;
|
|
|
|
Keys.Reserve(Utilities::ArraySize<ImGuiInterops::ImGuiTypes::FKeyMap>::value + 8);
|
|
|
|
|
|
|
|
// ImGui IO key map.
|
|
|
|
Keys.Emplace(EKeys::Tab);
|
|
|
|
Keys.Emplace(EKeys::Left);
|
|
|
|
Keys.Emplace(EKeys::Right);
|
|
|
|
Keys.Emplace(EKeys::Up);
|
|
|
|
Keys.Emplace(EKeys::Down);
|
|
|
|
Keys.Emplace(EKeys::PageUp);
|
|
|
|
Keys.Emplace(EKeys::PageDown);
|
|
|
|
Keys.Emplace(EKeys::Home);
|
|
|
|
Keys.Emplace(EKeys::End);
|
|
|
|
Keys.Emplace(EKeys::Delete);
|
|
|
|
Keys.Emplace(EKeys::BackSpace);
|
|
|
|
Keys.Emplace(EKeys::Enter);
|
|
|
|
Keys.Emplace(EKeys::Escape);
|
|
|
|
Keys.Emplace(EKeys::A);
|
|
|
|
Keys.Emplace(EKeys::C);
|
|
|
|
Keys.Emplace(EKeys::V);
|
|
|
|
Keys.Emplace(EKeys::X);
|
|
|
|
Keys.Emplace(EKeys::Y);
|
|
|
|
Keys.Emplace(EKeys::Z);
|
|
|
|
|
|
|
|
// Modifier keys.
|
|
|
|
Keys.Emplace(EKeys::LeftShift);
|
|
|
|
Keys.Emplace(EKeys::RightShift);
|
|
|
|
Keys.Emplace(EKeys::LeftControl);
|
|
|
|
Keys.Emplace(EKeys::RightControl);
|
|
|
|
Keys.Emplace(EKeys::LeftAlt);
|
|
|
|
Keys.Emplace(EKeys::RightAlt);
|
|
|
|
Keys.Emplace(EKeys::LeftCommand);
|
|
|
|
Keys.Emplace(EKeys::RightCommand);
|
|
|
|
|
|
|
|
return Keys;
|
|
|
|
}
|
|
|
|
|
2018-04-17 19:28:29 +00:00
|
|
|
// Column layout utilities.
|
2018-01-15 22:07:28 +00:00
|
|
|
namespace Columns
|
|
|
|
{
|
|
|
|
template<typename FunctorType>
|
|
|
|
static void CollapsingGroup(const char* Name, int Columns, FunctorType&& DrawContent)
|
|
|
|
{
|
|
|
|
if (ImGui::CollapsingHeader(Name, ImGuiTreeNodeFlags_DefaultOpen))
|
|
|
|
{
|
|
|
|
const int LastColumns = ImGui::GetColumnsCount();
|
|
|
|
ImGui::Columns(Columns, nullptr, false);
|
|
|
|
DrawContent();
|
|
|
|
ImGui::Columns(LastColumns);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-09 10:40:44 +00:00
|
|
|
// Controls tweaked for 2-columns layout.
|
|
|
|
namespace TwoColumns
|
|
|
|
{
|
2018-01-15 22:07:28 +00:00
|
|
|
template<typename FunctorType>
|
|
|
|
static inline void CollapsingGroup(const char* Name, FunctorType&& DrawContent)
|
|
|
|
{
|
|
|
|
Columns::CollapsingGroup(Name, 2, std::forward<FunctorType>(DrawContent));
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace
|
2017-09-10 20:05:37 +00:00
|
|
|
{
|
2018-01-15 22:07:28 +00:00
|
|
|
void LabelText(const char* Label)
|
|
|
|
{
|
|
|
|
ImGui::Text("%s:", Label);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelText(const wchar_t* Label)
|
|
|
|
{
|
|
|
|
ImGui::Text("%ls:", Label);
|
|
|
|
}
|
2017-09-10 20:05:37 +00:00
|
|
|
}
|
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
template<typename LabelType>
|
|
|
|
static void Value(LabelType&& Label, int32 Value)
|
2017-09-09 10:40:44 +00:00
|
|
|
{
|
2018-01-15 22:07:28 +00:00
|
|
|
LabelText(Label); ImGui::NextColumn();
|
2017-09-09 10:40:44 +00:00
|
|
|
ImGui::Text("%d", Value); ImGui::NextColumn();
|
|
|
|
}
|
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
template<typename LabelType>
|
|
|
|
static void Value(LabelType&& Label, uint32 Value)
|
|
|
|
{
|
|
|
|
LabelText(Label); ImGui::NextColumn();
|
|
|
|
ImGui::Text("%u", Value); ImGui::NextColumn();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename LabelType>
|
|
|
|
static void Value(LabelType&& Label, float Value)
|
|
|
|
{
|
|
|
|
LabelText(Label); ImGui::NextColumn();
|
|
|
|
ImGui::Text("%f", Value); ImGui::NextColumn();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename LabelType>
|
|
|
|
static void Value(LabelType&& Label, bool bValue)
|
2017-09-09 10:40:44 +00:00
|
|
|
{
|
2018-01-15 22:07:28 +00:00
|
|
|
LabelText(Label); ImGui::NextColumn();
|
2017-09-09 10:40:44 +00:00
|
|
|
ImGui::Text("%ls", TEXT_BOOL(bValue)); ImGui::NextColumn();
|
|
|
|
}
|
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
template<typename LabelType>
|
|
|
|
static void Value(LabelType&& Label, const TCHAR* Value)
|
2017-09-09 10:40:44 +00:00
|
|
|
{
|
2018-01-15 22:07:28 +00:00
|
|
|
LabelText(Label); ImGui::NextColumn();
|
2017-09-09 10:40:44 +00:00
|
|
|
ImGui::Text("%ls", Value); ImGui::NextColumn();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
namespace Styles
|
|
|
|
{
|
|
|
|
template<typename FunctorType>
|
|
|
|
static void TextHighlight(bool bHighlight, FunctorType&& DrawContent)
|
|
|
|
{
|
|
|
|
if (bHighlight)
|
|
|
|
{
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_Text, { 1.f, 1.f, 0.5f, 1.f });
|
|
|
|
}
|
|
|
|
DrawContent();
|
|
|
|
if (bHighlight)
|
|
|
|
{
|
|
|
|
ImGui::PopStyleColor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-09 10:40:44 +00:00
|
|
|
void SImGuiWidget::OnDebugDraw()
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
FImGuiContextProxy* ContextProxy = ModuleManager->GetContextManager().GetContextProxy(ContextIndex);
|
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
if (CVars::DebugWidget.GetValueOnGameThread() > 0)
|
2017-09-09 10:40:44 +00:00
|
|
|
{
|
2018-01-15 22:07:28 +00:00
|
|
|
bool bDebug = true;
|
|
|
|
ImGui::SetNextWindowSize(ImVec2(380, 480), ImGuiSetCond_Once);
|
2017-09-09 10:40:44 +00:00
|
|
|
if (ImGui::Begin("ImGui Widget Debug", &bDebug))
|
|
|
|
{
|
2018-01-15 22:07:28 +00:00
|
|
|
ImGui::Spacing();
|
2017-09-09 10:40:44 +00:00
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
TwoColumns::CollapsingGroup("Context", [&]()
|
|
|
|
{
|
|
|
|
TwoColumns::Value("Context Index", ContextIndex);
|
|
|
|
TwoColumns::Value("Context Name", ContextProxy ? *ContextProxy->GetName() : TEXT("< Null >"));
|
|
|
|
TwoColumns::Value("Game Viewport", *GameViewport->GetName());
|
|
|
|
});
|
2017-09-09 10:40:44 +00:00
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
TwoColumns::CollapsingGroup("Input Mode", [&]()
|
|
|
|
{
|
|
|
|
TwoColumns::Value("Input Enabled", bInputEnabled);
|
|
|
|
});
|
2017-09-10 20:05:37 +00:00
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
TwoColumns::CollapsingGroup("Widget", [&]()
|
2017-09-10 20:05:37 +00:00
|
|
|
{
|
|
|
|
TwoColumns::Value("Visibility", *GetVisibility().ToString());
|
|
|
|
TwoColumns::Value("Is Hovered", IsHovered());
|
|
|
|
TwoColumns::Value("Is Directly Hovered", IsDirectlyHovered());
|
|
|
|
TwoColumns::Value("Has Keyboard Input", HasKeyboardFocus());
|
2018-01-15 22:07:28 +00:00
|
|
|
});
|
2017-09-10 20:05:37 +00:00
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
TwoColumns::CollapsingGroup("Viewport", [&]()
|
2017-09-10 20:05:37 +00:00
|
|
|
{
|
|
|
|
const auto& ViewportWidget = GameViewport->GetGameViewportWidget();
|
2018-01-15 22:07:28 +00:00
|
|
|
TwoColumns::Value("Is Foreground Window", GameViewport->Viewport->IsForegroundWindow());
|
2017-09-10 20:05:37 +00:00
|
|
|
TwoColumns::Value("Is Hovered", ViewportWidget->IsHovered());
|
|
|
|
TwoColumns::Value("Is Directly Hovered", ViewportWidget->IsDirectlyHovered());
|
|
|
|
TwoColumns::Value("Has Mouse Capture", ViewportWidget->HasMouseCapture());
|
|
|
|
TwoColumns::Value("Has Keyboard Input", ViewportWidget->HasKeyboardFocus());
|
|
|
|
TwoColumns::Value("Has Focused Descendants", ViewportWidget->HasFocusedDescendants());
|
|
|
|
auto Widget = PreviousUserFocusedWidget.Pin();
|
|
|
|
TwoColumns::Value("Previous User Focused", Widget.IsValid() ? *Widget->GetTypeAsString() : TEXT("None"));
|
2018-01-15 22:07:28 +00:00
|
|
|
});
|
2017-09-09 10:40:44 +00:00
|
|
|
}
|
|
|
|
ImGui::End();
|
|
|
|
|
|
|
|
if (!bDebug)
|
|
|
|
{
|
2018-01-15 22:07:28 +00:00
|
|
|
CVars::DebugWidget->Set(0, ECVF_SetByConsole);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-30 17:25:58 +00:00
|
|
|
if (ContextProxy && CVars::DebugInput.GetValueOnGameThread() > 0)
|
2018-01-15 22:07:28 +00:00
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
FImGuiInputState& InputState = ContextProxy->GetInputState();
|
|
|
|
|
2018-01-15 22:07:28 +00:00
|
|
|
bool bDebug = true;
|
|
|
|
ImGui::SetNextWindowSize(ImVec2(460, 480), ImGuiSetCond_Once);
|
|
|
|
if (ImGui::Begin("ImGui Input State", &bDebug))
|
|
|
|
{
|
|
|
|
const ImVec4 HiglightColor{ 1.f, 1.f, 0.5f, 1.f };
|
|
|
|
Columns::CollapsingGroup("Mapped Keys", 4, [&]()
|
|
|
|
{
|
|
|
|
static const auto& Keys = GetImGuiMappedKeys();
|
|
|
|
|
|
|
|
const int32 Num = Keys.Num();
|
|
|
|
|
|
|
|
// Simplified when slicing for two 2.
|
|
|
|
const int32 RowsNum = (Num + 1) / 2;
|
|
|
|
|
|
|
|
for (int32 Row = 0; Row < RowsNum; Row++)
|
|
|
|
{
|
|
|
|
for (int32 Col = 0; Col < 2; Col++)
|
|
|
|
{
|
|
|
|
const int32 Idx = Row + Col * RowsNum;
|
|
|
|
if (Idx < Num)
|
|
|
|
{
|
|
|
|
const FKey& Key = Keys[Idx];
|
|
|
|
const uint32 KeyIndex = ImGuiInterops::GetKeyIndex(Key);
|
2019-06-30 17:25:58 +00:00
|
|
|
Styles::TextHighlight(InputState.GetKeys()[KeyIndex], [&]()
|
2018-01-15 22:07:28 +00:00
|
|
|
{
|
|
|
|
TwoColumns::Value(*Key.GetDisplayName().ToString(), KeyIndex);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ImGui::NextColumn(); ImGui::NextColumn();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Columns::CollapsingGroup("Modifier Keys", 4, [&]()
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
Styles::TextHighlight(InputState.IsShiftDown(), [&]() { ImGui::Text("Shift"); }); ImGui::NextColumn();
|
|
|
|
Styles::TextHighlight(InputState.IsControlDown(), [&]() { ImGui::Text("Control"); }); ImGui::NextColumn();
|
|
|
|
Styles::TextHighlight(InputState.IsAltDown(), [&]() { ImGui::Text("Alt"); }); ImGui::NextColumn();
|
2018-01-15 22:07:28 +00:00
|
|
|
ImGui::NextColumn();
|
|
|
|
});
|
|
|
|
|
|
|
|
Columns::CollapsingGroup("Mouse Buttons", 4, [&]()
|
|
|
|
{
|
|
|
|
static const FKey Buttons[] = { EKeys::LeftMouseButton, EKeys::RightMouseButton,
|
|
|
|
EKeys::MiddleMouseButton, EKeys::ThumbMouseButton, EKeys::ThumbMouseButton2 };
|
|
|
|
|
|
|
|
const int32 Num = Utilities::GetArraySize(Buttons);
|
|
|
|
|
|
|
|
// Simplified when slicing for two 2.
|
|
|
|
const int32 RowsNum = (Num + 1) / 2;
|
|
|
|
|
|
|
|
for (int32 Row = 0; Row < RowsNum; Row++)
|
|
|
|
{
|
|
|
|
for (int32 Col = 0; Col < 2; Col++)
|
|
|
|
{
|
|
|
|
const int32 Idx = Row + Col * RowsNum;
|
|
|
|
if (Idx < Num)
|
|
|
|
{
|
|
|
|
const FKey& Button = Buttons[Idx];
|
|
|
|
const uint32 MouseIndex = ImGuiInterops::GetMouseIndex(Button);
|
2019-06-30 17:25:58 +00:00
|
|
|
Styles::TextHighlight(InputState.GetMouseButtons()[MouseIndex], [&]()
|
2018-01-15 22:07:28 +00:00
|
|
|
{
|
|
|
|
TwoColumns::Value(*Button.GetDisplayName().ToString(), MouseIndex);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ImGui::NextColumn(); ImGui::NextColumn();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Columns::CollapsingGroup("Mouse Axes", 4, [&]()
|
|
|
|
{
|
2019-06-30 17:25:58 +00:00
|
|
|
TwoColumns::Value("Position X", InputState.GetMousePosition().X);
|
|
|
|
TwoColumns::Value("Position Y", InputState.GetMousePosition().Y);
|
|
|
|
TwoColumns::Value("Wheel Delta", InputState.GetMouseWheelDelta());
|
2018-01-15 22:07:28 +00:00
|
|
|
ImGui::NextColumn(); ImGui::NextColumn();
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!bDebug)
|
|
|
|
{
|
|
|
|
CVars::DebugInput->Set(0, ECVF_SetByConsole);
|
|
|
|
}
|
2017-09-09 10:40:44 +00:00
|
|
|
}
|
2018-01-15 22:07:28 +00:00
|
|
|
ImGui::End();
|
2017-09-09 10:40:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef TEXT_INPUT_MODE
|
|
|
|
#undef TEXT_BOOL
|
2018-10-30 22:25:48 +00:00
|
|
|
|
|
|
|
#endif // IMGUI_WIDGET_DEBUG
|
|
|
|
|
|
|
|
#undef IMGUI_WIDGET_LOG
|