mirror of
				https://github.com/kevinporetti/UnrealImGui.git
				synced 2025-11-04 07:33:18 +00:00 
			
		
		
		
	Added debug code to ImGui Widget:
- Added ImGui.Debug.Widget console variable to enable/disable widget state debugging. - Added ImGui ImGui debug for widget state. - Added logging for widget state transitions.
This commit is contained in:
		
							parent
							
								
									f7816ee1fd
								
							
						
					
					
						commit
						f696393089
					
				@ -12,6 +12,12 @@
 | 
				
			|||||||
#include "Utilities/ScopeGuards.h"
 | 
					#include "Utilities/ScopeGuards.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFINE_LOG_CATEGORY_STATIC(LogImGuiWidget, Warning, All);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TEXT_INPUT_MODE(Val) ((Val) == EInputMode::MouseAndKeyboard ? TEXT("MouseAndKeyboard") : (Val) == EInputMode::MouseOnly ? TEXT("MouseOnly") : TEXT("None"))
 | 
				
			||||||
 | 
					#define TEXT_BOOL(Val) ((Val) ? TEXT("true") : TEXT("false"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace CVars
 | 
					namespace CVars
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	TAutoConsoleVariable<int> InputEnabled(TEXT("ImGui.InputEnabled"), 0,
 | 
						TAutoConsoleVariable<int> InputEnabled(TEXT("ImGui.InputEnabled"), 0,
 | 
				
			||||||
@ -19,24 +25,44 @@ namespace CVars
 | 
				
			|||||||
		TEXT("0: disabled (default)\n")
 | 
							TEXT("0: disabled (default)\n")
 | 
				
			||||||
		TEXT("1: enabled, input is routed to ImGui and with a few exceptions is consumed."),
 | 
							TEXT("1: enabled, input is routed to ImGui and with a few exceptions is consumed."),
 | 
				
			||||||
		ECVF_Default);
 | 
							ECVF_Default);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TAutoConsoleVariable<int> DebugWidget(TEXT("ImGui.Debug.Widget"), 0,
 | 
				
			||||||
 | 
							TEXT("Show debug for SImGuiWidget.\n")
 | 
				
			||||||
 | 
							TEXT("0: disabled (default)\n")
 | 
				
			||||||
 | 
							TEXT("1: enabled."),
 | 
				
			||||||
 | 
							ECVF_Default);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
 | 
					BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
 | 
				
			||||||
void SImGuiWidget::Construct(const FArguments& InArgs)
 | 
					void SImGuiWidget::Construct(const FArguments& InArgs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	checkf(InArgs._ModuleManager, TEXT("Null Module Manager argument"));
 | 
						checkf(InArgs._ModuleManager, TEXT("Null Module Manager argument"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ModuleManager = InArgs._ModuleManager;
 | 
						ModuleManager = InArgs._ModuleManager;
 | 
				
			||||||
	ContextIndex = InArgs._ContextIndex;
 | 
						ContextIndex = InArgs._ContextIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ModuleManager->OnPostImGuiUpdate().AddRaw(this, &SImGuiWidget::OnPostImGuiUpdate);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Sync visibility with default input enabled state.
 | 
						// Sync visibility with default input enabled state.
 | 
				
			||||||
	SetVisibilityFromInputEnabled();
 | 
						SetVisibilityFromInputEnabled();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Register to get post-update notifications, so we can clean frame updates.
 | 
				
			||||||
 | 
						ModuleManager->OnPostImGuiUpdate().AddRaw(this, &SImGuiWidget::OnPostImGuiUpdate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Register self-debug function.
 | 
				
			||||||
 | 
						auto* ContextProxy = ModuleManager->GetContextManager().GetContextProxy(ContextIndex);
 | 
				
			||||||
 | 
						checkf(ContextProxy, TEXT("Missing context during widget construction: ContextIndex = %d"), ContextIndex);
 | 
				
			||||||
 | 
						ContextProxy->OnDraw().AddRaw(this, &SImGuiWidget::OnDebugDraw);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
 | 
					END_SLATE_FUNCTION_BUILD_OPTIMIZATION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SImGuiWidget::~SImGuiWidget()
 | 
					SImGuiWidget::~SImGuiWidget()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						// Remove binding between this widget and its context proxy.
 | 
				
			||||||
 | 
						if (auto* ContextProxy = ModuleManager->GetContextManager().GetContextProxy(ContextIndex))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ContextProxy->OnDraw().RemoveAll(this);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Unregister from post-update notifications.
 | 
				
			||||||
	ModuleManager->OnPostImGuiUpdate().RemoveAll(this);
 | 
						ModuleManager->OnPostImGuiUpdate().RemoveAll(this);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -122,6 +148,8 @@ FReply SImGuiWidget::OnFocusReceived(const FGeometry& MyGeometry, const FFocusEv
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	Super::OnFocusReceived(MyGeometry, FocusEvent);
 | 
						Super::OnFocusReceived(MyGeometry, FocusEvent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UE_LOG(LogImGuiWidget, VeryVerbose, TEXT("ImGui Widget %d - Focus Received."), ContextIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If widget has a keyboard focus we always maintain mouse input. Technically, if mouse is outside of the widget
 | 
						// If widget has a keyboard focus we always maintain mouse input. Technically, if mouse is outside of the widget
 | 
				
			||||||
	// area it won't generate events but we freeze its state until it either comes back or input is completely lost.
 | 
						// area it won't generate events but we freeze its state until it either comes back or input is completely lost.
 | 
				
			||||||
	UpdateInputMode(true, true);
 | 
						UpdateInputMode(true, true);
 | 
				
			||||||
@ -133,6 +161,8 @@ void SImGuiWidget::OnFocusLost(const FFocusEvent& FocusEvent)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	Super::OnFocusLost(FocusEvent);
 | 
						Super::OnFocusLost(FocusEvent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UE_LOG(LogImGuiWidget, VeryVerbose, TEXT("ImGui Widget %d - Focus Lost."), ContextIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	UpdateInputMode(false, IsHovered());
 | 
						UpdateInputMode(false, IsHovered());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -140,6 +170,8 @@ void SImGuiWidget::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	Super::OnMouseEnter(MyGeometry, MouseEvent);
 | 
						Super::OnMouseEnter(MyGeometry, MouseEvent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UE_LOG(LogImGuiWidget, VeryVerbose, TEXT("ImGui Widget %d - Mouse Enter."), ContextIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If mouse enters while input is active then we need to update mouse buttons because there is a chance that we
 | 
						// If mouse enters while input is active then we need to update mouse buttons because there is a chance that we
 | 
				
			||||||
	// missed some events.
 | 
						// missed some events.
 | 
				
			||||||
	if (InputMode != EInputMode::None)
 | 
						if (InputMode != EInputMode::None)
 | 
				
			||||||
@ -157,6 +189,8 @@ void SImGuiWidget::OnMouseLeave(const FPointerEvent& MouseEvent)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	Super::OnMouseLeave(MouseEvent);
 | 
						Super::OnMouseLeave(MouseEvent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UE_LOG(LogImGuiWidget, VeryVerbose, TEXT("ImGui Widget %d - Mouse Leave."), ContextIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	UpdateInputMode(HasKeyboardFocus(), false);
 | 
						UpdateInputMode(HasKeyboardFocus(), false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -179,6 +213,9 @@ void SImGuiWidget::SetVisibilityFromInputEnabled()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	// If we don't use input disable hit test to make this widget invisible for cursors hit detection.
 | 
						// If we don't use input disable hit test to make this widget invisible for cursors hit detection.
 | 
				
			||||||
	SetVisibility(bInputEnabled ? EVisibility::Visible : EVisibility::HitTestInvisible);
 | 
						SetVisibility(bInputEnabled ? EVisibility::Visible : EVisibility::HitTestInvisible);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UE_LOG(LogImGuiWidget, VeryVerbose, TEXT("ImGui Widget %d - Visibility updated to '%s'."),
 | 
				
			||||||
 | 
							ContextIndex, *GetVisibility().ToString());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SImGuiWidget::UpdateInputEnabled()
 | 
					void SImGuiWidget::UpdateInputEnabled()
 | 
				
			||||||
@ -188,6 +225,9 @@ void SImGuiWidget::UpdateInputEnabled()
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		bInputEnabled = bEnabled;
 | 
							bInputEnabled = bEnabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							UE_LOG(LogImGuiWidget, Log, TEXT("ImGui Widget %d - Input Enabled changed to '%s'."),
 | 
				
			||||||
 | 
								ContextIndex, TEXT_BOOL(bInputEnabled));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		SetVisibilityFromInputEnabled();
 | 
							SetVisibilityFromInputEnabled();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Setup input to show cursor and take focus when we use input or clear state and pass focus back to viewport
 | 
							// Setup input to show cursor and take focus when we use input or clear state and pass focus back to viewport
 | 
				
			||||||
@ -219,6 +259,9 @@ void SImGuiWidget::UpdateInputMode(bool bNeedKeyboard, bool bNeedMouse)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (InputMode != NewInputMode)
 | 
						if (InputMode != NewInputMode)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							UE_LOG(LogImGuiWidget, Verbose, TEXT("ImGui Widget %d - Input Mode changed from '%s' to '%s'."),
 | 
				
			||||||
 | 
								ContextIndex, TEXT_INPUT_MODE(InputMode), TEXT_INPUT_MODE(NewInputMode));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// We need to reset input components if we are either fully shutting down or we are downgrading from full to
 | 
							// We need to reset input components if we are either fully shutting down or we are downgrading from full to
 | 
				
			||||||
		// mouse-only input mode.
 | 
							// mouse-only input mode.
 | 
				
			||||||
		if (NewInputMode == EInputMode::None)
 | 
							if (NewInputMode == EInputMode::None)
 | 
				
			||||||
@ -291,3 +334,64 @@ FVector2D SImGuiWidget::ComputeDesiredSize(float) const
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	return FVector2D{ 3840.f, 2160.f };
 | 
						return FVector2D{ 3840.f, 2160.f };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Controls tweaked for 2-columns layout.
 | 
				
			||||||
 | 
					namespace TwoColumns
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static void Value(const char* Label, int Value)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ImGui::Text("%s:", Label); ImGui::NextColumn();
 | 
				
			||||||
 | 
							ImGui::Text("%d", Value); ImGui::NextColumn();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void Value(const char* Label, bool bValue)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ImGui::Text("%s:", Label); ImGui::NextColumn();
 | 
				
			||||||
 | 
							ImGui::Text("%ls", TEXT_BOOL(bValue)); ImGui::NextColumn();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void Value(const char* Label, const TCHAR* Value)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ImGui::Text("%s:", Label); ImGui::NextColumn();
 | 
				
			||||||
 | 
							ImGui::Text("%ls", Value); ImGui::NextColumn();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SImGuiWidget::OnDebugDraw()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bool bDebug = CVars::DebugWidget.GetValueOnGameThread() > 0;
 | 
				
			||||||
 | 
						if (bDebug)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ImGui::SetNextWindowSize(ImVec2(300, 200), ImGuiSetCond_Once);
 | 
				
			||||||
 | 
							if (ImGui::Begin("ImGui Widget Debug", &bDebug))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								ImGui::Columns(2, nullptr, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								TwoColumns::Value("Context Index", ContextIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ImGui::Separator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								TwoColumns::Value("Input Enabled", bInputEnabled);
 | 
				
			||||||
 | 
								TwoColumns::Value("Input Mode", TEXT_INPUT_MODE(InputMode));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ImGui::Separator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								TwoColumns::Value("Visibility", *GetVisibility().ToString());
 | 
				
			||||||
 | 
								TwoColumns::Value("Is Hovered", IsHovered());
 | 
				
			||||||
 | 
								TwoColumns::Value("Is Directly Hovered", IsDirectlyHovered());
 | 
				
			||||||
 | 
								TwoColumns::Value("Has Keyboard Input", HasKeyboardFocus());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ImGui::Columns(1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ImGui::End();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!bDebug)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								CVars::DebugWidget->ClearFlags(ECVF_SetByConsole);
 | 
				
			||||||
 | 
								CVars::DebugWidget->Set(0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef TEXT_INPUT_MODE
 | 
				
			||||||
 | 
					#undef TEXT_BOOL
 | 
				
			||||||
 | 
				
			|||||||
@ -91,6 +91,8 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	virtual FVector2D ComputeDesiredSize(float) const override;
 | 
						virtual FVector2D ComputeDesiredSize(float) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void OnDebugDraw();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FImGuiModuleManager* ModuleManager = nullptr;
 | 
						FImGuiModuleManager* ModuleManager = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutable TArray<FSlateVertex> VertexBuffer;
 | 
						mutable TArray<FSlateVertex> VertexBuffer;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user