RealtimeStyleTransferRuntime/Source/LyraGame/UI/IndicatorSystem/SActorCanvas.h

255 lines
7.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Widgets/SWidget.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "SlotBase.h"
#include "Layout/Children.h"
#include "Widgets/SPanel.h"
#include "GameplayTaskTypes.h"
#include "UObject/WeakInterfacePtr.h"
#include "IndicatorDescriptor.h"
#include "AsyncMixin.h"
#include "Blueprint/UserWidgetPool.h"
class FArrangedChildren;
class SActorCanvas;
class ULyraIndicatorManagerComponent;
class SActorCanvas : public SPanel, public FAsyncMixin, public FGCObject
{
public:
/** ActorCanvas-specific slot class */
class FSlot : public TSlotBase<FSlot>
{
public:
FSlot(UIndicatorDescriptor* InIndicator)
: TSlotBase<FSlot>()
, Indicator(InIndicator)
, ScreenPosition(FVector2D::ZeroVector)
, Depth(0)
, Priority(0.f)
, bIsIndicatorVisible(true)
, bInFrontOfCamera(true)
, bHasValidScreenPosition(false)
, bDirty(true)
, bWasIndicatorClamped(false)
, bWasIndicatorClampedStatusChanged(false)
{
}
SLATE_SLOT_BEGIN_ARGS(FSlot, TSlotBase<FSlot>)
SLATE_SLOT_END_ARGS()
using TSlotBase<FSlot>::Construct;
bool GetIsIndicatorVisible() const { return bIsIndicatorVisible; }
void SetIsIndicatorVisible(bool bVisible)
{
if (bIsIndicatorVisible != bVisible)
{
bIsIndicatorVisible = bVisible;
bDirty = true;
}
RefreshVisibility();
}
FVector2D GetScreenPosition() const { return ScreenPosition; }
void SetScreenPosition(FVector2D InScreenPosition)
{
if (ScreenPosition != InScreenPosition)
{
ScreenPosition = InScreenPosition;
bDirty = true;
}
}
double GetDepth() const { return Depth; }
void SetDepth(double InDepth)
{
if (Depth != InDepth)
{
Depth = InDepth;
bDirty = true;
}
}
int32 GetPriority() const { return Priority; }
void SetPriority(int32 InPriority)
{
if (Priority != InPriority)
{
Priority = InPriority;
bDirty = true;
}
}
bool GetInFrontOfCamera() const { return bInFrontOfCamera; }
void SetInFrontOfCamera(bool bInFront)
{
if (bInFrontOfCamera != bInFront)
{
bInFrontOfCamera = bInFront;
bDirty = true;
}
RefreshVisibility();
}
bool HasValidScreenPosition() const { return bHasValidScreenPosition; }
void SetHasValidScreenPosition(bool bValidScreenPosition)
{
if (bHasValidScreenPosition != bValidScreenPosition)
{
bHasValidScreenPosition = bValidScreenPosition;
bDirty = true;
}
RefreshVisibility();
}
bool bIsDirty() const { return bDirty; }
void ClearDirtyFlag()
{
bDirty = false;
}
bool WasIndicatorClamped() const { return bWasIndicatorClamped; }
void SetWasIndicatorClamped(bool bWasClamped) const
{
if (bWasClamped != bWasIndicatorClamped)
{
bWasIndicatorClamped = bWasClamped;
bWasIndicatorClampedStatusChanged = true;
}
}
bool WasIndicatorClampedStatusChanged() const { return bWasIndicatorClampedStatusChanged; }
void ClearIndicatorClampedStatusChangedFlag()
{
bWasIndicatorClampedStatusChanged = false;
}
private:
void RefreshVisibility()
{
const bool bIsVisible = bIsIndicatorVisible && bHasValidScreenPosition;
GetWidget()->SetVisibility(bIsVisible ? EVisibility::SelfHitTestInvisible : EVisibility::Collapsed);
}
//Kept Alive by SActorCanvas::AddReferencedObjects
UIndicatorDescriptor* Indicator;
FVector2D ScreenPosition;
double Depth;
int32 Priority;
uint8 bIsIndicatorVisible : 1;
uint8 bInFrontOfCamera : 1;
uint8 bHasValidScreenPosition : 1;
uint8 bDirty : 1;
/**
* Cached & frame-deferred value of whether the indicator was visually screen clamped last frame or not;
* Semi-hacky mutable implementation as it is cached during a const paint operation
*/
mutable uint8 bWasIndicatorClamped : 1;
mutable uint8 bWasIndicatorClampedStatusChanged : 1;
friend class SActorCanvas;
};
/** ActorCanvas-specific slot class */
class FArrowSlot : public TSlotBase<FArrowSlot>
{
};
/** Begin the arguments for this slate widget */
SLATE_BEGIN_ARGS(SActorCanvas) {
_Visibility = EVisibility::HitTestInvisible;
}
/** Indicates that we have a slot that this widget supports */
SLATE_SLOT_ARGUMENT(SActorCanvas::FSlot, Slots)
/** This always goes at the end */
SLATE_END_ARGS()
SActorCanvas()
: CanvasChildren(this)
, ArrowChildren(this)
, AllChildren(this)
{
AllChildren.AddChildren(CanvasChildren);
AllChildren.AddChildren(ArrowChildren);
}
void Construct(const FArguments& InArgs, const FLocalPlayerContext& InCtx, const FSlateBrush* ActorCanvasArrowBrush);
// SWidget Interface
virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override;
virtual FVector2D ComputeDesiredSize(float) const override { return FVector2D::ZeroVector; }
virtual FChildren* GetChildren() override { return &AllChildren; }
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const;
// End SWidget
void SetDrawElementsInOrder(bool bInDrawElementsInOrder) { bDrawElementsInOrder = bInDrawElementsInOrder; }
virtual FString GetReferencerName() const override;
virtual void AddReferencedObjects( FReferenceCollector& Collector ) override;
private:
void OnIndicatorAdded(UIndicatorDescriptor* Indicator);
void OnIndicatorRemoved(UIndicatorDescriptor* Indicator);
void AddIndicatorForEntry(UIndicatorDescriptor* Indicator);
void RemoveIndicatorForEntry(UIndicatorDescriptor* Indicator);
using FScopedWidgetSlotArguments = TPanelChildren<FSlot>::FScopedWidgetSlotArguments;
FScopedWidgetSlotArguments AddActorSlot(UIndicatorDescriptor* Indicator);
int32 RemoveActorSlot(const TSharedRef<SWidget>& SlotWidget);
void SetShowAnyIndicators(bool bIndicators);
EActiveTimerReturnType UpdateCanvas(double InCurrentTime, float InDeltaTime);
/** Helper function for calculating the offset */
void GetOffsetAndSize(const UIndicatorDescriptor* Indicator,
FVector2D& OutSize,
FVector2D& OutOffset,
FVector2D& OutPaddingMin,
FVector2D& OutPaddingMax) const;
void UpdateActiveTimer();
private:
TArray<UIndicatorDescriptor*> AllIndicators;
TArray<UIndicatorDescriptor*> InactiveIndicators;
FLocalPlayerContext LocalPlayerContext;
TWeakObjectPtr<ULyraIndicatorManagerComponent> IndicatorComponentPtr;
/** All the slots in this canvas */
TPanelChildren<FSlot> CanvasChildren;
mutable TPanelChildren<FArrowSlot> ArrowChildren;
FCombinedChildren AllChildren;
FUserWidgetPool IndicatorPool;
const FSlateBrush* ActorCanvasArrowBrush = nullptr;
mutable int32 NextArrowIndex = 0;
mutable int32 ArrowIndexLastUpdate = 0;
/** Whether to draw elements in the order they were added to canvas. Note: Enabling this will disable batching and will cause a greater number of drawcalls */
bool bDrawElementsInOrder = false;
bool bShowAnyIndicators = false;
mutable TOptional<FGeometry> OptionalPaintGeometry;
TSharedPtr<FActiveTimerHandle> TickHandle;
};