More work on focus, and good docs
This commit is contained in:
@@ -7,10 +7,11 @@
|
||||
#include "LuprexViewportClient.h"
|
||||
#include "Common.h"
|
||||
#include "PlayerControllerBase.h"
|
||||
#include "RootCanvas.h"
|
||||
#include "Engine/GameInstance.h"
|
||||
#include "Framework/Application/SlateApplication.h"
|
||||
#include "Layout/WidgetPath.h"
|
||||
#include "Widgets/SViewport.h"
|
||||
#include "Slate/SObjectWidget.h"
|
||||
|
||||
UlxViewportClient::UlxViewportClient(const FObjectInitializer &ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
@@ -18,44 +19,44 @@ UlxViewportClient::UlxViewportClient(const FObjectInitializer &ObjectInitializer
|
||||
UE_LOG(LogLuprexIntegration, Display, TEXT("UlxViewportClient constructed"));
|
||||
}
|
||||
|
||||
bool UlxViewportClient::TryBringToFront(const FWidgetPath &Path)
|
||||
{
|
||||
UGameInstance *GI = GetGameInstance();
|
||||
if (!GI) return false;
|
||||
AlxPlayerControllerBase *PC = Cast<AlxPlayerControllerBase>(
|
||||
GI->GetFirstLocalPlayerController(GetWorld()));
|
||||
if (!PC) return false;
|
||||
|
||||
for (int32 Idx = 0; Idx < Path.Widgets.Num(); ++Idx)
|
||||
{
|
||||
SWidget &SW = Path.Widgets[Idx].Widget.Get();
|
||||
if (SW.GetType() != FName(TEXT("SObjectWidget"))) continue;
|
||||
UUserWidget *Widget = static_cast<SObjectWidget&>(SW).GetWidgetObject();
|
||||
if (Widget && Widget->GetParent() == PC->RootCanvas)
|
||||
{
|
||||
UlxRootCanvasPanel::BringToFront(Widget);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UlxViewportClient::InputKey(const FInputKeyEventArgs &EventArgs)
|
||||
{
|
||||
UE_LOG(LogLuprexIntegration, Display, TEXT("UlxViewportClient::InputKey key=%s event=%d"),
|
||||
*EventArgs.Key.ToString(), (int32)EventArgs.Event);
|
||||
|
||||
// Only act on left mouse button presses that bubbled up to the
|
||||
// viewport unhandled. Walk the widget path under the cursor and
|
||||
// find the nearest focusable ancestor of whatever was hit. If it
|
||||
// isn't the game viewport itself, hand it to the player controller
|
||||
// to apply on its next UpdateInputMode pass; that's the point in
|
||||
// the frame where we can override SViewport's own click-focus
|
||||
// behaviour without fighting it.
|
||||
// viewport unhandled. If the click landed on a descendant of a
|
||||
// top-level widget in the root canvas, bring that top-level widget
|
||||
// to the front.
|
||||
if ((EventArgs.Event == IE_Pressed) && (EventArgs.Key == EKeys::LeftMouseButton))
|
||||
{
|
||||
FSlateApplication &Slate = FSlateApplication::Get();
|
||||
FVector2D MousePos = Slate.GetCursorPos();
|
||||
FWidgetPath Path = Slate.LocateWindowUnderMouse(
|
||||
MousePos, Slate.GetInteractiveTopLevelWindows());
|
||||
|
||||
if (Path.IsValid())
|
||||
{
|
||||
TSharedPtr<SViewport> ViewportWidget = GetGameViewportWidget();
|
||||
for (int32 Idx = Path.Widgets.Num() - 1; Idx >= 0; --Idx)
|
||||
{
|
||||
TSharedRef<SWidget> Widget = Path.Widgets[Idx].Widget;
|
||||
if (!Widget->SupportsKeyboardFocus()) continue;
|
||||
if (ViewportWidget.IsValid() && Widget == ViewportWidget) break;
|
||||
if (UGameInstance *GI = GetGameInstance())
|
||||
{
|
||||
if (AlxPlayerControllerBase *PC = Cast<AlxPlayerControllerBase>(
|
||||
GI->GetFirstLocalPlayerController(GetWorld())))
|
||||
{
|
||||
PC->ClickToFocus(Widget);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Path.IsValid() && TryBringToFront(Path)) return true;
|
||||
}
|
||||
|
||||
return Super::InputKey(EventArgs);
|
||||
|
||||
Reference in New Issue
Block a user