// // 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() UPROPERTY(BlueprintReadOnly) FVector2D Point1 = {0,0}; UPROPERTY(BlueprintReadOnly) FVector2D Point2 = {0,0}; UPROPERTY(BlueprintReadOnly) FVector2D Point3 = {0,0}; UPROPERTY(BlueprintReadOnly) 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 &GetItems() const { return Items; } private: using View = TArrayView; // 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 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 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 DotTexture; UPROPERTY(EditAnywhere, BlueprintReadWrite, Setter, Category="RadialMenu", meta=(AllowPrivateAccess="true")) float DotRadius = 0.0f; UPROPERTY() TObjectPtr Layout; TSharedPtr MySlateWidget; };