Added Tobii from 4.23 + updated

This commit is contained in:
2023-03-04 04:19:09 +11:00
parent 2d5b9008e5
commit 1cde391516
521 changed files with 11735 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
/******************************************************************************
* Copyright 2017- Tobii Technology AB. All rights reserved.
*
* @author Temaran | Fredrik Lindh | fredrik.lindh@tobii.com | https://github.com/Temaran
******************************************************************************/
#pragma once
#include "Slate/SRetainerWidget.h"
#include "TobiiGTOMTypes.h"
#include "STobiiRadialMenuWidget.h"
#include "CoreMinimal.h"
#include "DisplayDebugHelpers.h"
#include "Widgets/Layout/SBox.h"
class AHUD;
class UCanvas;
class UTobiiGazeFocusableWidget;
//This is the underlying slate widget.
//WARNING: Please note that we do not support using these directly yet.
class TOBIIGTOM_API STobiiGazeFocusableWidget : public SBox
{
public:
SLATE_BEGIN_ARGS(STobiiGazeFocusableWidget)
{
_Visibility = EVisibility::SelfHitTestInvisible;
}
SLATE_EVENT(FSimpleDelegate, OnHovered)
SLATE_EVENT(FSimpleDelegate, OnUnhovered)
/************************************************************************/
/* From SBox widget */
/************************************************************************/
//Horizontal alignment of content in the area allotted to the SBox by its parent
SLATE_ARGUMENT(EHorizontalAlignment, HAlign)
//Vertical alignment of content in the area allotted to the SBox by its parent
SLATE_ARGUMENT(EVerticalAlignment, VAlign)
//Padding between the SBox and the content that it presents. Padding affects desired size.
SLATE_ATTRIBUTE(FMargin, Padding)
//The widget content presented by the SBox
SLATE_DEFAULT_SLOT(FArguments, Content)
SLATE_END_ARGS()
/************************************************************************/
/* Tobii */
/************************************************************************/
public:
TWeakObjectPtr<UTobiiGazeFocusableWidget> UMGWidget;
STobiiGazeFocusableWidget();
void Construct(const FArguments& InArgs);
float GetCleanUIAlpha() { return CleanUIAlpha; }
bool IsHoveredByPointer() { return bIsHovered; }
bool HitByGaze();
void AddExtraCleanUIContainerToPollHitsFrom(STobiiGazeFocusableWidget* CleanUIContainerToPoll, bool PollGazeHits = true, bool PollMouseHits = true);
void RemoveExtraCleanUIContainerToPollHitsFrom(STobiiGazeFocusableWidget* CleanUIContainerToStopPolling);
static STobiiGazeFocusableWidget* TryCastToTobiiGazeFocusable(SWidget* Widget);
/************************************************************************/
/* SBox */
/************************************************************************/
public:
FSimpleDelegate OnHovered;
FSimpleDelegate OnUnhovered;
virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override;
private:
struct CleanUIPollingInfo
{
TWeakPtr<SWidget> CleanUIToPollFrom;
bool PollGaze;
bool PollPointer;
};
float CleanUIAlpha;
TArray<CleanUIPollingInfo> CleanUIContainersToPollHitsFrom;
};

View File

@@ -0,0 +1,159 @@
/******************************************************************************
* Copyright 2017- Tobii Technology AB. All rights reserved.
*
* @author Temaran | Fredrik Lindh | fredrik.lindh@tobii.com | https://github.com/Temaran
******************************************************************************/
#pragma once
#include "CoreMinimal.h"
#include "DisplayDebugHelpers.h"
#include "Slate/SRetainerWidget.h"
#include "Widgets/Layout/SBox.h"
class FArrangedChildren;
class FPaintArgs;
class FSlateWindowElementList;
struct FTobiiRadialMenuPanelRenderData
{
TArray<FSlateVertex> PanelVertexData;
TArray<SlateIndex> PanelIndexData;
TArray<FSlateVertex> BorderVertexData; //This also contains the PanelVertexData in the end.
TArray<SlateIndex> BorderIndexData;
};
//This is the underlying slate widget.
class TOBIIGTOM_API STobiiRadialMenuWidget : public SPanel
{
public:
class FSlot : public TSlotBase<FSlot>
{
public:
FSlot& Offset(const TAttribute<FVector2D>& InOffset)
{
OffsetAttr = InOffset;
return *this;
}
FSlot& Scale(const TAttribute<float>& InScale)
{
ScaleAttr = InScale;
return *this;
}
FSlot& Alpha(const TAttribute<float>& InAlpha)
{
AlphaAttr = InAlpha;
return *this;
}
/** Offset */
TAttribute<FVector2D> OffsetAttr;
/** Scale */
TAttribute<float> ScaleAttr;
/** Alpha */
TAttribute<float> AlphaAttr;
/** Default values for a slot. */
FSlot()
: TSlotBase<FSlot>()
, OffsetAttr(FVector2D(0.0f, 0.0f))
, ScaleAttr(1.0f)
, AlphaAttr(1.0f)
{ }
};
SLATE_BEGIN_ARGS(STobiiRadialMenuWidget)
: _UseHardBorder(true)
, _BorderColor(FColor(230, 230, 230))
, _PanelColor(FColor(70, 70, 70))
, _BorderThicknessPx(5.0f)
, _SegmentSeparationPx(10.0f)
, _AngularDisplacementDeg(0.0f)
, _RadiusPx(500.0f)
, _VertexCount(360)
{
_Visibility = EVisibility::SelfHitTestInvisible;
}
SLATE_SUPPORTS_SLOT(STobiiRadialMenuWidget::FSlot)
SLATE_ARGUMENT(bool, UseHardBorder)
SLATE_ARGUMENT(FColor, BorderColor)
SLATE_ARGUMENT(FColor, PanelColor)
SLATE_ARGUMENT(float, BorderThicknessPx)
SLATE_ARGUMENT(float, SegmentSeparationPx)
SLATE_ARGUMENT(float, AngularDisplacementDeg)
SLATE_ARGUMENT(float, RadiusPx)
SLATE_ARGUMENT(int32, VertexCount)
SLATE_END_ARGS()
STobiiRadialMenuWidget();
void Construct(const FArguments& InArgs);
static FSlot& Slot()
{
return *(new FSlot());
}
/**
* Adds a content slot.
*
* @return The added slot.
*/
FSlot& AddSlot()
{
Invalidate(EInvalidateWidget::Layout);
STobiiRadialMenuWidget::FSlot& NewSlot = *(new FSlot());
this->Children.Add(&NewSlot);
return NewSlot;
}
/**
* Removes a particular content slot.
*
* @param SlotWidget The widget in the slot to remove.
*/
int32 RemoveSlot(const TSharedRef<SWidget>& SlotWidget);
/**
* Removes all slots from the panel.
*/
void ClearChildren();
public:
// Begin SWidget overrides
virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override;
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
virtual FChildren* GetChildren() override;
// End SWidget overrides
protected:
// Begin SWidget overrides.
virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const override;
// End SWidget overrides.
protected:
/** The ConstraintCanvas widget's children. */
TPanelChildren<FSlot> Children;
public:
FSlateResourceHandle BrushResourceHandle;
bool bUseHardBorder;
FColor BorderColor;
FColor PanelColor;
float BorderThicknessPx;
float SegmentSeparationPx;
float AngularDisplacementDeg;
float RadiusPx;
int32 VertexCount;
private:
void GeneratePanelRenderData(const FGeometry& AllottedGeometry, int32 NrChildren, TArray<FTobiiRadialMenuPanelRenderData>& OutChildRenderData) const;
};

View File

@@ -0,0 +1,167 @@
/******************************************************************************
* Copyright 2017- Tobii Technology AB. All rights reserved.
*
* @author Temaran | Fredrik Lindh | fredrik.lindh@tobii.com | https://github.com/Temaran
******************************************************************************/
#pragma once
#include "TobiiGTOMTypes.h"
#include "STobiiGazeFocusableWidget.h"
#include "CoreMinimal.h"
#include "ObjectEditorUtils.h"
#include "Components/WidgetComponent.h"
#include "Components/SizeBox.h"
#include "TobiiGazeFocusableWidget.generated.h"
class UPrimitiveComponent;
class UTobiiGazeFocusManagerComponent;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWidgetGazeFocusSignature, UTobiiGazeFocusableWidget*, FocusedWidget);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWidgetHoverSignature, UTobiiGazeFocusableWidget*, FocusedWidget);
/**
* Use this widget to wrap other widgets you want to mark as gaze focusable.
* In contrast to gaze focusable components, each widget you want to make focusable needs to be wrapped by its own UTobiiGazeFocusableWidget. There is more info below on why this is the case.
* Please note that while this wraps a raw slate widget, we currently do not officially support using the slate widgets directly. Please use the UMG wrapper.
*
* There are some major differences to how gaze focusable widgets versus components work:
* 1. Since widgets don't support tags, widgets can only participate in GTOM by being wrapped by this widget.
* 2. Actor component hierarchies can be very rigid since they can be partially constructed in cpp, both by the developer and the engine. This means that designating gaze focusability via component parenting wouldn't be reliable.
* 3. It is very common to want to make it so that every primitive component on an actor should contribute to focusing that actor. This is not true for widgets, here it is more common that each individual widget wants to know if it has been individually focused.
*
* All of these things should help to illustrate why using different models for gaze focus in slate/UMG and actors is to be preferred.
*/
UCLASS(BlueprintType, Blueprintable, meta = (BlueprintSpawnableComponent, DisplayName= "Tobii Gaze Focusable"))
class TOBIIGTOM_API UTobiiGazeFocusableWidget : public USizeBox
{
GENERATED_UCLASS_BODY()
/************************************************************************/
/* USizeBox */
/************************************************************************/
public:
// UVisual interface
virtual void ReleaseSlateResources(bool bReleaseChildren) override;
protected:
// UWidget interface
virtual TSharedRef<SWidget> RebuildWidget() override;
public:
//These are for pointer hovering
UPROPERTY(BlueprintAssignable, Category = "Event")
FWidgetHoverSignature OnHovered;
UPROPERTY(BlueprintAssignable, Category = "Event")
FWidgetHoverSignature OnUnhovered;
//This function must be called to make the widget participate in GTOM.
//WARNING: For screen space widgets, you must do this manually by sending in a nullptr HostWidget! For worldspace widgets, the UTobiiGazeFocusableComponent will do this for you though.
UFUNCTION(BlueprintCallable, Category = "Gaze Focus")
void RegisterWidgetToGTOM(UWidgetComponent* HostWidget);
UFUNCTION(BlueprintPure, Category = "General")
UWidgetComponent* GetWorldSpaceHostWidgetComponent();
UFUNCTION(BlueprintPure, Category = "General")
bool IsHoveredByPointer();
UFUNCTION(BlueprintPure, Category = "General")
bool IsWorldSpaceWidget();
/************************************************************************/
/* Tobii */
/************************************************************************/
public:
//This will be true if this is the most likely widget to currently have focus irregardless of layer filters.
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Gaze Focus")
bool bHasGazeFocus;
//Set this to false if you want to stop this widget participating in GTOM.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gaze Focus")
bool bIsGazeFocusable;
//The gaze focus priority is optional input that you can provide to GTOM. Objects with higher focus priority are more "important" and are therefore more likely to be construed as being in focus. If this is negative, it will not be enforced.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gaze Focus")
float GazeFocusPriority;
//If this object is at least this far away from the player, it will not participate in GTOM. If this is less or equal to zero, it will not be enforced.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gaze Focus")
float MaxFocusDistance;
//A focus manager can opt to only query a subset of focusables by using a focus layer. If this is empty, the default layer will be used (Either from a gaze focusable component, or the global default).
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gaze Focus")
FString FocusLayer;
//This delegate will fire when this widget receives user focus
UPROPERTY(BlueprintAssignable, Category = "Gaze Focus|Event")
FWidgetGazeFocusSignature ReceivedGazeFocus;
//This delegate will fire when this widget loses user focus
UPROPERTY(BlueprintAssignable, Category = "Gaze Focus|Event")
FWidgetGazeFocusSignature LostGazeFocus;
//This will return true if this widget has user focus
UFUNCTION(BlueprintPure, Category = "Gaze Focus")
bool HasFocus();
//This will return true if this widget is close enough to the user's gaze to be considered in focus, even though it might not be the object the user is actively focusing on.
UFUNCTION(BlueprintPure, Category = "Gaze Focus")
bool IsInFocusCollection();
public:
//How should we apply CleanUI?
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CleanUI")
ETobiiCleanUIMode CleanUIMode;
//If this is larger than 0, CleanUI is currently being suppressed.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CleanUI")
float TimeCleanUIIsSuppressedForSecs;
//If you want this cleanUI panel to behave differently from the default governed by CVars you can override properties here. Any negative value will result in the CVar value being used.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CleanUI")
float CleanUIFadeInTimeSecsOverride;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CleanUI")
float CleanUIFadeOutTimeSecsOverride;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CleanUI")
float CleanUIMinAlphaOverride;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CleanUI")
float CleanUIMaxAlphaOverride;
//If you have a game where you want this cleanUI widget to fade in on mouse over, set this to true.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CleanUI")
bool bTriggerCleanUIOnMouseOver;
UFUNCTION(BlueprintPure, Category = "CleanUI")
float GetCleanUIAlpha();
public:
//If this widget should fade out when another container is being looked at, use these functions to make that happen. This requires bUseFastHitTesting to be off.
UFUNCTION(BlueprintCallable, Category = "Dependent Widgets")
void AddGazeFocusableWidgetToPollHitsFrom(UTobiiGazeFocusableWidget* GazeFocusableWidgetToPoll, bool PollGazeHits = true, bool PollMouseHits = true);
UFUNCTION(BlueprintCallable, Category = "Dependent Widgets")
void RemoveGazeFocusableWidgetToPollHitsFrom(UTobiiGazeFocusableWidget* GazeFocusableWidgetToStopPolling);
public:
STobiiGazeFocusableWidget* GetSlateGazeFocusableWidget();
virtual void ReceiveFocus();
virtual void LoseFocus();
static TMap<FTobiiFocusableUID, TWeakObjectPtr<UTobiiGazeFocusableWidget>>& GetTobiiScreenSpaceFocusableWidgets();
public:
#if WITH_EDITOR
virtual const FText GetPaletteCategory() override;
#endif
protected:
//This is set during run time by a UTobiiGazeFocusableComponent if this is a world space widget.
TWeakObjectPtr<UWidgetComponent> WorldSpaceHostWidgetComponent;
TSharedPtr<class STobiiGazeFocusableWidget> MySlateWidget;
void SlateHandleHovered();
void SlateHandleUnhovered();
};

View File

@@ -0,0 +1,166 @@
/******************************************************************************
* Copyright 2017- Tobii Technology AB. All rights reserved.
*
* @author Temaran | Fredrik Lindh | fredrik.lindh@tobii.com | https://github.com/Temaran
******************************************************************************/
#pragma once
#include "TobiiGTOMTypes.h"
#include "STobiiRadialMenuWidget.h"
#include "CoreMinimal.h"
#include "ObjectEditorUtils.h"
#include "Components/SizeBox.h"
#include "Components/WidgetComponent.h"
#include "TobiiRadialMenuWidget.generated.h"
UCLASS()
class TOBIIGTOM_API UTobiiRadialMenuSlot : public UPanelSlot
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Layout|Radial Menu Slot")
FVector2D Offset;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Layout|Radial Menu Slot")
float Scale;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Layout|Radial Menu Slot")
float Alpha;
public:
#if WITH_EDITOR
virtual bool NudgeByDesigner(const FVector2D& NudgeDirection, const TOptional<int32>& GridSnapSize) override;
virtual bool DragDropPreviewByDesigner(const FVector2D& LocalCursorPosition, const TOptional<int32>& XGridSnapSize, const TOptional<int32>& YGridSnapSize) override;
virtual void SynchronizeFromTemplate(const UPanelSlot* const TemplateSlot) override;
#endif //WITH_EDITOR
UFUNCTION(BlueprintCallable, Category = "Layout|Radial Menu Slot")
void SetOffset(FVector2D InOffset);
UFUNCTION(BlueprintCallable, Category = "Layout|Radial Menu Slot")
FVector2D GetOffset() const;
UFUNCTION(BlueprintCallable, Category = "Layout|Radial Menu Slot")
void SetScale(float InScale);
UFUNCTION(BlueprintCallable, Category = "Layout|Radial Menu Slot")
float GetScale() const;
UFUNCTION(BlueprintCallable, Category = "Layout|Radial Menu Slot")
void SetAlpha(float InAlpha);
UFUNCTION(BlueprintCallable, Category = "Layout|Radial Menu Slot")
float GetAlpha() const;
public:
STobiiRadialMenuWidget::FSlot* GetSlateSlot() { return Slot; }
void BuildSlot(TSharedRef<STobiiRadialMenuWidget> RadialMenu);
// UPanelSlot interface
virtual void SynchronizeProperties() override;
// End of UPanelSlot interface
virtual void ReleaseSlateResources(bool bReleaseChildren) override;
#if WITH_EDITOR
// UObject interface
virtual void PreEditChange(class FEditPropertyChain& PropertyAboutToChange) override;
virtual void PostEditChangeChainProperty(struct FPropertyChangedChainEvent& PropertyChangedEvent) override;
// End of UObject interface
#endif
private:
STobiiRadialMenuWidget::FSlot* Slot;
};
/**
*/
UCLASS(BlueprintType, Blueprintable, meta = (BlueprintSpawnableComponent, DisplayName= "Tobii Radial Menu"))
class TOBIIGTOM_API UTobiiRadialMenuWidget : public UPanelWidget
{
GENERATED_UCLASS_BODY()
public:
//A hard border will not be blended with the panel, while a soft border will be blended
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
bool bUseHardBorder;
//The color of the borders around each panel
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
FColor BorderColor;
//The color of the panels themselves
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
FColor PanelColor;
//The thickness of the border area
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
float BorderThicknessPx;
//The amount of pixels separating each segment
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
float SegmentSeparationPx;
//This is how rotated the panel is. Useful if you want another orientation.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
float AngularDisplacementDeg;
//This is the preferred radius. This will inform the desired size of the widget
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
float RadiusPx;
//The amount of vertices that will be used for the outside of the circle segments in total.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
int32 VertexCount;
public:
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
void SetUseHardBorder(bool bNewUseHardBorder);
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
void SetBorderColor(FColor NewBorderColor);
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
void SetPanelColor(FColor NewPanelColor);
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
void SetBorderThicknessPx(float NewBorderThicknessPx);
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
void SetSegmentSeparationPx(float NewSegmentSeparationPx);
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
void SetAngularDisplacementDeg(float NewAngularDisplacementDeg);
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
void SetRadiusPx(float NewRadiusPx);
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
void SetVertexCount(int32 NewVertexCount);
public:
/** */
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
UTobiiRadialMenuSlot* AddRadialMenuChild(UWidget* Content);
/** Computes the geometry for a particular slot based on the current geometry of the canvas. */
bool GetGeometryForSlot(int32 SlotIndex, FGeometry& ArrangedGeometry) const;
bool GetGeometryForSlot(UTobiiRadialMenuSlot* InSlot, FGeometry& ArrangedGeometry) const;
void ReleaseSlateResources(bool bReleaseChildren) override;
#if WITH_EDITOR
// UWidget interface
virtual const FText GetPaletteCategory() override;
// End UWidget interface
// UWidget interface
virtual bool LockToPanelOnDrag() const override
{
return true;
}
// End UWidget interface
#endif
protected:
// UPanelWidget
virtual UClass* GetSlotClass() const override;
virtual void OnSlotAdded(UPanelSlot* Slot) override;
virtual void OnSlotRemoved(UPanelSlot* Slot) override;
// End UPanelWidget
protected:
TSharedPtr<class STobiiRadialMenuWidget> MyRadialMenu;
protected:
// UWidget interface
virtual TSharedRef<SWidget> RebuildWidget() override;
// End of UWidget interface
};