Files
integration/Source/Integration/RadialMenu.h
2026-05-15 18:14:38 -04:00

157 lines
4.7 KiB
C++

//
// This class implements the layout calculatations for a radial
// menu.
//
#pragma once
#include "CoreMinimal.h"
#include "Components/Widget.h"
#include "RadialMenu.generated.h"
class SRadialMenu;
class UTexture2D;
USTRUCT(BlueprintType)
struct FRadialMenuItem
{
GENERATED_BODY()
FVector2D Point1 = {0,0};
FVector2D Point2 = {0,0};
FVector2D Point3 = {0,0};
bool RightSide = false;
};
UCLASS(BlueprintType)
class URadialMenuLayout : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void Configure(int32 NItems, float ItemHeight, float InnerRadius, float MinSpoke, float Spread);
UFUNCTION(BlueprintCallable)
int32 LeftNum() const { return NumLeft; }
UFUNCTION(BlueprintCallable)
int32 RightNum() const { return NumRight; }
UFUNCTION(BlueprintCallable)
const TArray<FRadialMenuItem> &GetItems() const { return Items; }
private:
using View = TArrayView<FRadialMenuItem>;
// Give the unit vector for the selected spoke. NSide is
// the number of spokes on the side of the wheel that
// we're calculating, and NTotal is the total number of
// spokes on both sides. The spokes on a given side are
// organized top-to-bottom, and the angle between the
// spokes is always equal to (1/NTotal) of the circle.
FVector2D SpokeVector(int32 I, int32 NSide, int32 NTotal);
// Populate Point1 and Point2, these are the
// endpoints of the spoke segment. Spokes are
// designed to always be long enough to make room
// for MinSpoke, but also to make enough room to
// keep the menu items from overlapping.
void CalculateSpokes(View V, float ItemHeight, float InnerRadius, float MinSpoke);
// Search for the widest spoke, and return its X coordinate.
double WidestSpoke(View V);
// Populate Point3, this is the endpoint of the spread
// line that goes horizontal.
void CalculateSpread(View V, double Offset);
// Flip everything in the specified view horizontally.
void FlipHorizontal(View V);
// The array of items.
TArray<FRadialMenuItem> Items;
// Number of items on the left, and on the right.
int32 NumLeft = 0;
int32 NumRight = 0;
};
UCLASS(BlueprintType, Blueprintable)
class URadialMenuWidget : public UWidget
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void SetNumItems(int32 NewNumItems);
UFUNCTION(BlueprintCallable)
void SetItemHeight(float NewItemHeight);
UFUNCTION(BlueprintCallable)
void SetInnerRadius(float NewInnerRadius);
UFUNCTION(BlueprintCallable)
void SetMinSpoke(float NewMinSpoke);
UFUNCTION(BlueprintCallable)
void SetSpread(float NewSpread);
UFUNCTION(BlueprintCallable)
void SetLineThickness(float NewLineThickness);
UFUNCTION(BlueprintCallable)
void SetLineColor(FLinearColor NewLineColor);
UFUNCTION(BlueprintCallable)
void SetDotTexture(UTexture2D* NewDotTexture);
UFUNCTION(BlueprintCallable)
void SetDotRadius(float NewDotRadius);
UFUNCTION(BlueprintCallable)
URadialMenuLayout* GetLayout() const { return Layout; }
protected:
virtual TSharedRef<SWidget> RebuildWidget() override;
virtual void ReleaseSlateResources(bool bReleaseChildren) override;
virtual void SynchronizeProperties() override;
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Setter, Category="RadialMenu", meta=(ClampMin="0", AllowPrivateAccess="true"))
int32 NumItems = 8;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Setter, Category="RadialMenu", meta=(AllowPrivateAccess="true"))
float ItemHeight = 20.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Setter, Category="RadialMenu", meta=(AllowPrivateAccess="true"))
float InnerRadius = 20.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Setter, Category="RadialMenu", meta=(AllowPrivateAccess="true"))
float MinSpoke = 20.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Setter, Category="RadialMenu", meta=(AllowPrivateAccess="true"))
float Spread = 20.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Setter, Category="RadialMenu", meta=(AllowPrivateAccess="true"))
float LineThickness = 2.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Setter, Category="RadialMenu", meta=(AllowPrivateAccess="true"))
FLinearColor LineColor = FLinearColor::White;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Setter, Category="RadialMenu", meta=(AllowPrivateAccess="true"))
TObjectPtr<UTexture2D> DotTexture;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Setter, Category="RadialMenu", meta=(AllowPrivateAccess="true"))
float DotRadius = 0.0f;
UPROPERTY()
TObjectPtr<URadialMenuLayout> Layout;
TSharedPtr<SRadialMenu> MySlateWidget;
};