255 lines
7.2 KiB
C++
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;
|
|
};
|