// // 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 FRadialMenuConfig { GENERATED_BODY() UPROPERTY(EditAnywhere, Category="RadialMenu") int32 NumItems = 8; UPROPERTY(EditAnywhere, Category="RadialMenu") float ItemHeight = 20.0f; UPROPERTY(EditAnywhere, Category="RadialMenu") float InnerRadius = 20.0f; UPROPERTY(EditAnywhere, Category="RadialMenu") float MinSpoke = 20.0f; UPROPERTY(EditAnywhere, Category="RadialMenu") float Spread = 20.0f; UPROPERTY(EditAnywhere, Category="RadialMenu") float LineThickness = 4.0f; UPROPERTY(EditAnywhere, Category="RadialMenu") FLinearColor LineColor = FLinearColor::White; UPROPERTY(EditAnywhere, Category="RadialMenu") TObjectPtr DotTexture; UPROPERTY(EditAnywhere, Category="RadialMenu") float DotRadius = 3.0f; UPROPERTY(EditAnywhere, Category="RadialMenu") int32 SelectedItem = -1; UPROPERTY(EditAnywhere, Category="RadialMenu") FLinearColor SelectedColor = FLinearColor::Yellow; UPROPERTY(EditAnywhere, Category="RadialMenu") float SelectedThickness = 2.0f; }; 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; static TArray Calculate(const FRadialMenuConfig &Config); 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. static 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. static void CalculateSpokes(View V, int32 TotalItems, float ItemHeight, float InnerRadius, float MinSpoke); // Search for the widest spoke, and return its X coordinate. static double WidestSpoke(View V); // Populate Point3, this is the endpoint of the spread // line that goes horizontal. static void CalculateSpread(View V, double Offset); // Flip everything in the specified view horizontally. static void FlipHorizontal(View V); }; 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) bool SetSelectedItem(int32 NewSelectedItem); UFUNCTION(BlueprintCallable) void SetSelectedColor(FLinearColor NewSelectedColor); UFUNCTION(BlueprintCallable) void SetSelectedThickness(float NewSelectedThickness); UFUNCTION(BlueprintCallable) const TArray &GetItems() const { return Items; } // Returns true if the selected item changed. UFUNCTION(BlueprintCallable) bool AddPointer(FVector2D Direction, float Scale); UFUNCTION(BlueprintCallable) FVector2D GetPointer() const { return PointerVector; } UFUNCTION(BlueprintCallable) FLinearColor GetItemColor(int N) const; protected: UPROPERTY(EditAnywhere) FRadialMenuConfig Config; TArray Items; FVector2D PointerVector = {0,0}; virtual TSharedRef RebuildWidget() override; virtual void ReleaseSlateResources(bool bReleaseChildren) override; virtual void SynchronizeProperties() override; TSharedPtr MySlateWidget; };