├── .gitignore ├── ColorWheelPlugin.uplugin ├── Config └── FilterPlugin.ini ├── LICENSE ├── README.md ├── Resources └── Icon128.png └── Source └── ColorWheelPlugin ├── ColorWheelPlugin.Build.cs ├── Private ├── ColorWheelHelper.cpp ├── ColorWheelPlugin.cpp ├── ColorWidget.cpp └── SWColorWheel.cpp └── Public ├── ColorWheelHelper.h ├── ColorWheelPlugin.h ├── ColorWidget.h └── SWColorWheel.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # UE4/5 35 | 36 | Binaries 37 | Intermediate -------------------------------------------------------------------------------- /ColorWheelPlugin.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "2023.1.1", 5 | "FriendlyName": "Color Wheel", 6 | "Description": "Simple no-nonsense bloated color wheel.", 7 | "Category": "Widget", 8 | "CreatedBy": "W2Wizard", 9 | "CreatedByURL": "https://w2wizard.myportfolio.com/", 10 | "DocsURL": "", 11 | "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/ce01648a2cde41338991bb855a624ffa", 12 | "SupportURL": "https://portfolio.w2wizard.dev/", 13 | "EngineVersion": "5.2", 14 | "CanContainContent": false, 15 | "Installed": false, 16 | "Modules": [ 17 | { 18 | "Name": "ColorWheelPlugin", 19 | "Type": "Runtime", 20 | "LoadingPhase": "PreDefault", 21 | "BlacklistPlatforms": [ 22 | "IOS", 23 | "Android", 24 | "Linux" 25 | ] 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /Config/FilterPlugin.ini: -------------------------------------------------------------------------------- 1 | [FilterPlugin] 2 | ; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and 3 | ; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. 4 | ; 5 | ; Examples: 6 | ; /README.txt 7 | ; /Extras/... 8 | ; /Binaries/ThirdParty/*.dll 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | “Commons Clause” License Condition v1.0 2 | 3 | The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition. 4 | Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, the right to Sell the Software. 5 | For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Clause License Condition notice. 6 | 7 | Software: SimpleColorWheel 8 | License: MIT 9 | Licensor: W2Wizard 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Simple Color Wheel

4 | 42MLX_Logo 5 |
6 |
7 | UE4/5 Plugin for a free, simple and extendible color wheel. 8 |
9 | Written by W2.Wizard 10 |
11 | 12 | ![colorwheel](https://github.com/W2Wizard/SimpleColorWheel/assets/63303990/2d701954-c93f-4fbf-a10b-1aa4b35021b6) 13 | -------------------------------------------------------------------------------- /Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/W2Wizard/SimpleColorWheel/eb8fe6fd416fa63b3d087bf8e6944726ab641500/Resources/Icon128.png -------------------------------------------------------------------------------- /Source/ColorWheelPlugin/ColorWheelPlugin.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) W2.Wizard 2020-2021. All Rights Reserved. 2 | 3 | using System.IO; 4 | using UnrealBuildTool; 5 | 6 | public class ColorWheelPlugin : ModuleRules 7 | { 8 | public ColorWheelPlugin(ReadOnlyTargetRules Target) : base(Target) 9 | { 10 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 11 | 12 | PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Public")); 13 | PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "Private")); 14 | 15 | PrivateDependencyModuleNames.AddRange( 16 | new string[] 17 | { 18 | "Core", 19 | "ApplicationCore", 20 | "CoreUObject", 21 | "InputCore", 22 | "Engine", 23 | "UMG", 24 | "Slate", 25 | "SlateCore" 26 | } 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Source/ColorWheelPlugin/Private/ColorWheelHelper.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) W2.Wizard 2020-2021. All Rights Reserved. 2 | 3 | #include "ColorWheelHelper.h" 4 | 5 | uint8 UColorWheelHelper::HexToByte(FString Hex) 6 | { 7 | uint8 OutDec; 8 | 9 | Hex.StartsWith("#") ? Hex = Hex.Mid(1,Hex.Len()-1) : Hex; 10 | 11 | HexToBytes(Hex.ToUpper(), &OutDec); 12 | return OutDec; 13 | 14 | // Old Method, if you're looking for a way without using functions. 15 | // const int len = Hex.Len(); 16 | // uint8 Out = 0; 17 | // 18 | // for (int i = 0; i < len; i++) 19 | // { 20 | // char digit = Hex[len - 1 - i]; 21 | // if (digit >= '0' && digit <= '9') 22 | // { 23 | // Out += (digit - '0') * FMath::Pow(16,i); 24 | // } 25 | // else 26 | // { 27 | // Out += (digit - 'A' + 10) * FMath::Pow(16,i); 28 | // } 29 | // } 30 | // 31 | // return Out; 32 | } 33 | 34 | FLinearColor UColorWheelHelper::RandomLinearColor(bool RandomAlpha, bool TrueRandom) 35 | { 36 | FLinearColor OutColor; 37 | 38 | // True random color 39 | if (TrueRandom) 40 | { 41 | OutColor = FLinearColor 42 | ( 43 | FMath::FRand(), 44 | FMath::FRand(), 45 | FMath::FRand(), 46 | RandomAlpha ? FMath::FRand() : 1 47 | ); 48 | 49 | return OutColor; 50 | } 51 | 52 | // Simple random color 53 | OutColor = FLinearColor::MakeRandomColor(); 54 | if (RandomAlpha) OutColor.A = FMath::FRand(); 55 | 56 | return OutColor; 57 | } 58 | 59 | FColor UColorWheelHelper::RandomColor(bool RandomAlpha, bool TrueRandom) 60 | { 61 | FColor OutColor; 62 | 63 | // True random color 64 | if (TrueRandom) 65 | { 66 | OutColor = FColor 67 | ( 68 | FMath::RandRange(0,255), 69 | FMath::RandRange(0,255), 70 | FMath::RandRange(0,255), 71 | RandomAlpha ? FMath::Rand() : 1 72 | ); 73 | 74 | return OutColor; 75 | } 76 | 77 | // Simple random color 78 | OutColor = FColor::MakeRandomColor(); 79 | if (RandomAlpha) OutColor.A = FMath::Rand(); 80 | 81 | return OutColor; 82 | } 83 | -------------------------------------------------------------------------------- /Source/ColorWheelPlugin/Private/ColorWheelPlugin.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) W2.Wizard 2020-2021. All Rights Reserved. 2 | 3 | #include "ColorWheelPlugin.h" 4 | 5 | #define LOCTEXT_NAMESPACE "FColorWheelPluginModule" 6 | 7 | void FColorWheelPluginModule::StartupModule() 8 | { 9 | 10 | } 11 | 12 | void FColorWheelPluginModule::ShutdownModule() 13 | { 14 | 15 | } 16 | 17 | #undef LOCTEXT_NAMESPACE 18 | 19 | IMPLEMENT_MODULE(FColorWheelPluginModule, ColorWheelPlugin) -------------------------------------------------------------------------------- /Source/ColorWheelPlugin/Private/ColorWidget.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) W2.Wizard 2020-2021. All Rights Reserved. 2 | 3 | #include "ColorWidget.h" 4 | 5 | /// Slate Overrides /// 6 | 7 | TSharedRef UColorWidget::RebuildWidget() 8 | { 9 | ColorWheel = SNew(SWColorWheel) 10 | .SelectedColor_UObject(this, &UColorWidget::GetColor) 11 | .SelectorPin(&SelectorPin) 12 | .HueCircle(&HueCircle) 13 | .OnMouseCaptureBegin_UObject(this, &UColorWidget::MouseDown) 14 | .OnMouseCaptureEnd_UObject(this, &UColorWidget::MouseUp) 15 | .OnValueChanged(FOnLinearColorValueChanged::CreateUObject(this, &UColorWidget::OnValueChanged)) 16 | .OnPositionChanged(FOnPositionChanged::CreateUObject(this, &UColorWidget::OnPositionUpdated)); 17 | 18 | return ColorWheel.ToSharedRef(); 19 | } 20 | 21 | void UColorWidget::ReleaseSlateResources(bool bReleaseChildren) 22 | { 23 | Super::ReleaseSlateResources(bReleaseChildren); 24 | 25 | ColorWheel.Reset(); 26 | } 27 | 28 | void UColorWidget::OnValueChanged(FLinearColor NewValue) 29 | { 30 | Color = NewValue.HSVToLinearRGB(); 31 | OnColorChanged.Broadcast(Color); 32 | } 33 | 34 | 35 | void UColorWidget::OnPositionUpdated(FVector2D NewPosition) 36 | { 37 | //UE_LOG(LogTemp, Warning, TEXT("D - X: %f - Y: %f"), NewPosition.X, NewPosition.Y) 38 | OnPositionChanged.Broadcast(NewPosition); 39 | } 40 | 41 | /// Main Functions /// 42 | 43 | void UColorWidget::SetColor(const FLinearColor NewColor) 44 | { 45 | // Incase of Black, the wheel gets fucked ヽ(`Д´)ノ︵ ┻━┻. 46 | if (NewColor.IsAlmostBlack()) 47 | { 48 | // We pass in a false value 49 | Color = FLinearColor::White; 50 | 51 | // Preserve alpha. 52 | Color.A = NewColor.A; 53 | IsNull = true; 54 | 55 | return; 56 | } 57 | 58 | Color = NewColor; 59 | IsNull = false; 60 | } 61 | 62 | FLinearColor UColorWidget::GetCurrentColor() 63 | { 64 | // Was input black? 65 | if (IsNull) 66 | { 67 | // Return black color 68 | auto FallbackVal = FLinearColor::Black; 69 | FallbackVal.A = Color.A; 70 | 71 | return FallbackVal; 72 | } 73 | 74 | return Color; 75 | } 76 | 77 | /// Generics /// 78 | 79 | void UColorWidget::SetColorAndOpacity(FLinearColor InColorAndOpacity, TEnumAsByte Target) 80 | { 81 | // Update the values themselves, again this doesnt look good so change it later perhaps. 82 | auto ColorVal = FSlateColor(InColorAndOpacity); 83 | switch (Target) 84 | { 85 | case EWheelBrushTarget::All: 86 | SelectorPin.TintColor = ColorVal; 87 | HueCircle.TintColor = ColorVal; 88 | break; 89 | 90 | case EWheelBrushTarget::SelectorPin: 91 | SelectorPin.TintColor = ColorVal; 92 | break; 93 | 94 | case EWheelBrushTarget::HueCircle: 95 | HueCircle.TintColor = ColorVal; 96 | break; 97 | } 98 | 99 | // Update the visual widget itself 100 | if (ColorWheel.IsValid()) 101 | { 102 | ColorWheel->SetColorAndOpacity(InColorAndOpacity, Target); 103 | } 104 | } 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /Source/ColorWheelPlugin/Private/SWColorWheel.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) W2.Wizard 2020-2021. All Rights Reserved. 2 | // modified code of SColorWheel, Original by Copyright Epic Games, Inc. All Rights Reserved. 3 | 4 | #include "SWColorWheel.h" 5 | 6 | /*===========================================================================*\ 7 | | Construct | 8 | \*===========================================================================*/ 9 | 10 | void SWColorWheel::Construct(const FArguments& InArgs) 11 | { 12 | // Arguments passed onto the slate widget 13 | Image = InArgs._HueCircle; 14 | SelectorImage = InArgs._SelectorPin; 15 | SelectedColor = InArgs._SelectedColor; 16 | OnMouseCaptureBegin = InArgs._OnMouseCaptureBegin; 17 | OnMouseCaptureEnd = InArgs._OnMouseCaptureEnd; 18 | OnValueChanged = InArgs._OnValueChanged; 19 | OnPositionChanged = InArgs._OnPositionChanged; 20 | } 21 | 22 | void SWColorWheel::SetColorAndOpacity(FLinearColor InColorAndOpacity, TEnumAsByte TargetBrush) 23 | { 24 | // TODO: Perhaps clean this up in some way? 25 | switch (TargetBrush) 26 | { 27 | case All: 28 | SetAttribute(HueCircleColorAndOpacity, TAttribute(InColorAndOpacity), EInvalidateWidgetReason::None); 29 | SetAttribute(PinColorAndOpacity, TAttribute(InColorAndOpacity), EInvalidateWidgetReason::Paint); 30 | break; 31 | 32 | case SelectorPin: 33 | SetAttribute(PinColorAndOpacity, TAttribute(InColorAndOpacity), EInvalidateWidgetReason::Paint); 34 | break; 35 | 36 | case HueCircle: 37 | SetAttribute(HueCircleColorAndOpacity, TAttribute(InColorAndOpacity), EInvalidateWidgetReason::Paint); 38 | break; 39 | } 40 | } 41 | 42 | /*===========================================================================*\ 43 | | Overrides | 44 | \*===========================================================================*/ 45 | 46 | FVector2D SWColorWheel::ComputeDesiredSize(float) const 47 | { 48 | return Image->ImageSize + SelectorImage->ImageSize; 49 | } 50 | 51 | FReply SWColorWheel::OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent) 52 | { 53 | return FReply::Handled(); 54 | } 55 | 56 | FReply SWColorWheel::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 57 | { 58 | if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton) 59 | { 60 | OnMouseCaptureBegin.ExecuteIfBound(); 61 | 62 | if (!ProcessMouseAction(MyGeometry, MouseEvent, false)) 63 | { 64 | OnMouseCaptureEnd.ExecuteIfBound(); 65 | return FReply::Unhandled(); 66 | } 67 | 68 | return FReply::Handled().CaptureMouse(SharedThis(this)); 69 | } 70 | 71 | return FReply::Unhandled(); 72 | } 73 | 74 | FReply SWColorWheel::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 75 | { 76 | if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && HasMouseCapture()) 77 | { 78 | OnMouseCaptureEnd.ExecuteIfBound(); 79 | 80 | return FReply::Handled().ReleaseMouseCapture(); 81 | } 82 | 83 | return FReply::Unhandled(); 84 | } 85 | 86 | FReply SWColorWheel::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 87 | { 88 | if (!HasMouseCapture()) return FReply::Unhandled(); 89 | 90 | ProcessMouseAction(MyGeometry, MouseEvent, true); 91 | 92 | return FReply::Handled(); 93 | } 94 | 95 | int32 SWColorWheel::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const 96 | { 97 | const bool bIsEnabled = ShouldBeEnabled(bParentEnabled); 98 | const ESlateDrawEffect DrawEffects = bIsEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; 99 | const FVector2f SelectorSize = SelectorImage->ImageSize; 100 | const FVector2f CircleSize = AllottedGeometry.GetLocalSize() - SelectorSize; 101 | 102 | FSlateDrawElement::MakeBox( 103 | OutDrawElements, 104 | LayerId, 105 | AllottedGeometry.ToPaintGeometry(CircleSize, FSlateLayoutTransform(0.5f * SelectorSize)), 106 | Image, 107 | DrawEffects, 108 | InWidgetStyle.GetColorAndOpacityTint() * Image->GetTint(InWidgetStyle) 109 | ); 110 | 111 | FSlateDrawElement::MakeBox( 112 | OutDrawElements, 113 | LayerId + 1, 114 | AllottedGeometry.ToPaintGeometry(SelectorSize, FSlateLayoutTransform(0.5f * (AllottedGeometry.GetLocalSize() + CalcRelativePositionFromCenter() * FVector2D(CircleSize - SelectorSize)))), 115 | SelectorImage, 116 | DrawEffects, 117 | InWidgetStyle.GetColorAndOpacityTint() * SelectorImage->GetTint(InWidgetStyle) 118 | ); 119 | 120 | return LayerId + 1; 121 | } 122 | 123 | /*===========================================================================*\ 124 | | Main Implementation | 125 | \*===========================================================================*/ 126 | 127 | FVector2D SWColorWheel::CalcRelativePositionFromCenter() const 128 | { 129 | /** 130 | * R = Hue 131 | * G = Saturation / Radius 132 | */ 133 | float Angle = SelectedColor.Get().R / 180.0f * PI; 134 | return FVector2D(FMath::Cos(Angle), FMath::Sin(Angle)) * SelectedColor.Get().G; 135 | } 136 | 137 | 138 | bool SWColorWheel::ProcessMouseAction(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bProcessWhenOutsideColorWheel) 139 | { 140 | const FVector2D LocalMouseCoordinate = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()); 141 | const FVector2D RelativePositionFromCenter = (2.0f * LocalMouseCoordinate - MyGeometry.GetLocalSize()) / (MyGeometry.GetLocalSize() - SelectorImage->ImageSize); 142 | 143 | OnPositionChanged.ExecuteIfBound(FVector2D(FMath::Clamp(RelativePositionFromCenter.X, -1.0, 1.0), -1.0 * FMath::Clamp(RelativePositionFromCenter.Y, -1.0, 1.0))); 144 | //UE_LOG(LogTemp, Warning, TEXT("X: %f - Y: %f"), RelativePositionFromCenter.X, RelativePositionFromCenter.Y) 145 | 146 | const float RelativeRadius = RelativePositionFromCenter.Size(); 147 | 148 | if (RelativeRadius <= 1.0f || bProcessWhenOutsideColorWheel) 149 | { 150 | float Angle = FMath::Atan2(RelativePositionFromCenter.Y, RelativePositionFromCenter.X); 151 | 152 | if (Angle < 0.0f) 153 | Angle += 2.0f * PI; 154 | 155 | FLinearColor NewColor = SelectedColor.Get(); 156 | { 157 | NewColor.R = Angle * 180.0f * INV_PI; 158 | NewColor.G = FMath::Min(RelativeRadius, 1.0f); 159 | } 160 | 161 | OnValueChanged.ExecuteIfBound(NewColor); 162 | } 163 | 164 | return (RelativeRadius <= 1.0f); 165 | } 166 | -------------------------------------------------------------------------------- /Source/ColorWheelPlugin/Public/ColorWheelHelper.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) W2.Wizard 2020-2021. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | // Core 6 | #include "CoreMinimal.h" 7 | #include "Kismet/BlueprintFunctionLibrary.h" 8 | #include "HAL/PlatformApplicationMisc.h" 9 | #include "Framework/Application/SlateApplication.h" 10 | 11 | // Generated.h 12 | #include "ColorWheelHelper.generated.h" 13 | 14 | /** 15 | * A Helper BP Library for various additional functions that someone might need, like hexadecimal conversion, random color, etc... 16 | */ 17 | UCLASS() 18 | class COLORWHEELPLUGIN_API UColorWheelHelper : public UBlueprintFunctionLibrary 19 | { 20 | public: 21 | 22 | GENERATED_BODY() 23 | 24 | /** 25 | * Converts a hexadecimal string value to a byte value. 26 | * @param Hex The Hexadecimal value 27 | * @return The value as a byte 28 | */ 29 | UFUNCTION(BlueprintPure, Category = "Color Wheel Helper|Conversion", meta=(DisplayName="Hex ➜ Byte", Keywords = "hex byte convert")) 30 | static uint8 HexToByte(FString Hex); 31 | 32 | /** 33 | * Converts a byte value to a Hexadecimal value represented as a string. 34 | * @param Byte The byte value 35 | * @return The value as a hexadecimal represented in a string 36 | */ 37 | UFUNCTION(BlueprintPure, Category = "Color Wheel Helper|Conversion", meta=(DisplayName="Byte ➜ Hex", Keywords = "hex byte convert")) 38 | static FORCEINLINE FString ByteToHex(uint8 Byte) { return FString::Printf(TEXT("%02X"), Byte); } 39 | 40 | /** 41 | * Converts a Hex from an FString value to a FColor value, needs to contain all channels so simply writing #FF won't 42 | * work! 43 | * @param Hex The Hexadecimal string value 44 | * @return Returns the RGBA value of the Hexadecimal value 45 | */ 46 | UFUNCTION(BlueprintPure, Category = "Color Wheel Helper|Conversion", meta=(DisplayName="Hex ➜ Color", Keywords = "hex convert rgb")) 47 | static FORCEINLINE FColor HexToColor(FString Hex) { return FColor::FromHex(Hex); } 48 | 49 | /** 50 | * Converts a Hex from an FString value to a FLinearColor value, needs to contain all channels so simply writing #FF won't 51 | * work! 52 | * @param Hex The Hexadecimal string value 53 | * @return Returns the linear color values of the Hexadecimal value 54 | */ 55 | UFUNCTION(BlueprintPure, Category = "Color Wheel Helper|Conversion", meta=(DisplayName="Hex ➜ LinearColor", Keywords = "hex convert rgb linear")) 56 | static FORCEINLINE FLinearColor HexToLinearColor(FString Hex) { return FLinearColor(FColor::FromHex(Hex)); } 57 | 58 | /** 59 | * Converts a FColor value to a FString value in Hexadecimal. 60 | * @param Color The RGBA Color 61 | * @return The Hex value as string 62 | */ 63 | UFUNCTION(BlueprintPure, Category = "Color Wheel Helper|Conversion", meta=(DisplayName="Color ➜ Hex", Keywords = "hex convert rgb")) 64 | static FORCEINLINE FString ColorToHex(const FColor Color) { return Color.ToHex(); } 65 | 66 | /** 67 | * Converts a FLinearColor value to a FString value in Hexadecimal. 68 | * @param Color The linear color 69 | * @param IsSRGB Is the linear color in SRGB? 70 | * @return The Hex value as string 71 | */ 72 | UFUNCTION(BlueprintPure, Category = "Color Wheel Helper|Conversion", meta=(DisplayName="LinearColor ➜ Hex", Keywords = "hex convert rgb linear")) 73 | static FORCEINLINE FString LinearColorToHex(const FLinearColor Color, const bool IsSRGB) { return Color.ToFColor(IsSRGB).ToHex(); } 74 | 75 | 76 | /** 77 | * Returns a randomized linear color value 78 | * @param RandomAlpha Randomize the Alpha value aswell ? 79 | * @param TrueRandom Should each channel of the color be randomized ? 80 | * @return A random linear color 81 | */ 82 | UFUNCTION(BlueprintPure, Category = "Color Wheel Helper|Misc", meta=(DisplayName="Random Linear Color", Keywords = "random linear color")) 83 | static FLinearColor RandomLinearColor(bool RandomAlpha, bool TrueRandom); 84 | 85 | /** 86 | * Returns a randomized color value 87 | * @param RandomAlpha Randomize the Alpha value aswell ? 88 | * @param TrueRandom Should each channel of the color be randomized ? 89 | * @return A random color 90 | */ 91 | UFUNCTION(BlueprintPure, Category = "Color Wheel Helper|Misc", meta=(DisplayName="Random Color", Keywords = "random color")) 92 | static FColor RandomColor(bool RandomAlpha, bool TrueRandom); 93 | 94 | /** 95 | * Returns the current color under which the cursor is currently residing. 96 | * @return The current color under the cursor 97 | */ 98 | UFUNCTION(BlueprintPure, Category = "Color Wheel Helper|Misc", meta=(DisplayName="Get Color under Cursor", Keywords = " get cursor color")) 99 | static FORCEINLINE FLinearColor GetColorUnderCursor() 100 | { 101 | // Not sure if FSlateApplication is a safe way of getting the cursor position, but it does work. 102 | return FPlatformApplicationMisc::GetScreenPixelColor(FSlateApplication::Get().GetCursorPos(), 2.2f); 103 | }; 104 | }; 105 | -------------------------------------------------------------------------------- /Source/ColorWheelPlugin/Public/ColorWheelPlugin.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) W2.Wizard 2020-2021. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "Modules/ModuleManager.h" 6 | 7 | class FColorWheelPluginModule : public IModuleInterface 8 | { 9 | public: 10 | 11 | /** IModuleInterface implementation */ 12 | virtual void StartupModule() override; 13 | virtual void ShutdownModule() override; 14 | }; 15 | -------------------------------------------------------------------------------- /Source/ColorWheelPlugin/Public/ColorWidget.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) W2.Wizard 2020-2021. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | // Core 6 | #include "CoreMinimal.h" 7 | #include "Components/Widget.h" 8 | 9 | // Misc 10 | #include "SWColorWheel.h" 11 | #include "Styling/CoreStyle.h" 12 | #include "ColorWheelHelper.h" 13 | 14 | // Generated.h 15 | #include "ColorWidget.generated.h" 16 | 17 | class SWColorWheel; 18 | 19 | /* 20 | Delegate: Broadcasted when a color change has occured. 21 | Param 1: FLinearColor | The new Color that has been set. 22 | */ 23 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FColorChangedEvent, const FLinearColor&, NewColor); 24 | 25 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPositionUpdatedEvent, const FVector2D&, NewPosition); 26 | 27 | /** Delegate: Broadcasted when the mouse is down on the Wheel. */ 28 | DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMouseDownEvent); 29 | 30 | /** Delegate: Broadcasted when the mouse is lifted from the Wheel. */ 31 | DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMouseUpEvent); 32 | 33 | /** 34 | * A simple color wheel that can be used to select a specific color using a Pin 35 | * 36 | * * No Children 37 | */ 38 | UCLASS(meta=(DisplayName="Color Wheel")) 39 | class COLORWHEELPLUGIN_API UColorWidget final : public UWidget 40 | { 41 | GENERATED_BODY() 42 | 43 | public: 44 | 45 | /*============================================================================\ 46 | | Properties | 47 | \============================================================================*/ 48 | 49 | /** The image used for the pin */ 50 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Style") 51 | FSlateBrush SelectorPin = *FCoreStyle::Get().GetBrush("ColorWheel.Selector"); 52 | 53 | /** The image used for the wheel */ 54 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Style") 55 | FSlateBrush HueCircle = *FCoreStyle::Get().GetBrush("ColorWheel.HueValueCircle"); 56 | 57 | /*============================================================================\ 58 | | Events | 59 | \============================================================================*/ 60 | 61 | /** Event called when color value is changed */ 62 | UPROPERTY(BlueprintAssignable, Category="Color Wheel|Event") 63 | FColorChangedEvent OnColorChanged; 64 | 65 | /** Event called when value is changed */ 66 | UPROPERTY(BlueprintAssignable, Category = "Color Wheel|Event") 67 | FPositionUpdatedEvent OnPositionChanged; 68 | 69 | /** Event called when the mouse is being pressed on the wheel */ 70 | UPROPERTY(BlueprintAssignable, Category="Color Wheel|Event") 71 | FMouseDownEvent OnMouseDown; 72 | 73 | /** Event called when the mouse is being lifted from the wheel */ 74 | UPROPERTY(BlueprintAssignable, Category="Color Wheel|Event") 75 | FMouseUpEvent OnMouseUp; 76 | 77 | /*============================================================================\ 78 | | Blueprint Functions | 79 | \============================================================================*/ 80 | 81 | /** 82 | * Sets the color of the colorwheel 83 | * @param NewColor A new linear color value 84 | */ 85 | UFUNCTION(BlueprintCallable, Category = "Color Wheel|Functions", meta=(DisplayName="Set Color", Keywords = "set color wheel")) 86 | void SetColor(const FLinearColor NewColor); 87 | 88 | /** 89 | * Gets the color of the colorwheel 90 | * @return The current color of the colorwheel 91 | */ 92 | UFUNCTION(BlueprintPure, Category = "Color Wheel|Functions", meta=(DisplayName="Get Color", Keywords = "get color wheel")) 93 | FLinearColor GetCurrentColor(); 94 | 95 | ///Generics/// 96 | 97 | /** Sets the color and opacity of the specified brush */ 98 | UFUNCTION(BlueprintCallable, Category = "Appearance") 99 | void SetColorAndOpacity(FLinearColor InColorAndOpacity, TEnumAsByte Target); 100 | 101 | /*============================================================================\ 102 | | Misc Unreal Engine Slate | 103 | \============================================================================*/ 104 | 105 | protected: 106 | 107 | // Construct the widget 108 | virtual TSharedRef RebuildWidget() override; 109 | 110 | // Destroy the widget 111 | virtual void ReleaseSlateResources(bool bReleaseChildren) override; 112 | 113 | #if WITH_EDITOR 114 | 115 | // For the editor to set the name category in the Widget Explorer. 116 | virtual inline const FText GetPaletteCategory() override { return NSLOCTEXT("Input", "Input", "Input"); }; 117 | 118 | #endif 119 | 120 | /*============================================================================\ 121 | | Private Variables | 122 | \============================================================================*/ 123 | 124 | private: 125 | 126 | /* 127 | * TODO: Hack to avoid inactive colorwheel. 128 | * In order to avoid a issue where when we detect that the color is completely null we send in a false value to the color wheel 129 | * while when we retrieve the value we return actually the null value. 130 | * 131 | * For now this helps avoid this issue, but I must look deeper into it. 132 | */ 133 | bool IsNull; 134 | 135 | // Shared Ptr to the colorwheel. 136 | TSharedPtr ColorWheel; 137 | 138 | // Default color the widget gets constructed with. 139 | FLinearColor Color = FLinearColor::White; 140 | 141 | // Callback Function: Handles the broadcasting of the delegate once a color changes. 142 | void OnValueChanged(FLinearColor NewValue); 143 | 144 | void OnPositionUpdated(FVector2D NewPosition); 145 | 146 | // Callback Function: Handles the broadcasting for when the Mouse is lifted from the wheel. 147 | inline void MouseUp() { OnMouseUp.Broadcast(); }; 148 | 149 | // Callback Function: Handles the broadcasting once the Mouse is held down on the wheel. 150 | inline void MouseDown() { OnMouseDown.Broadcast(); }; 151 | 152 | // Callback Function: For when the widget gets constructed, passes the color, gets set on line 102. 153 | inline FLinearColor GetColor() const { return Color.LinearRGBToHSV(); }; 154 | 155 | 156 | }; 157 | -------------------------------------------------------------------------------- /Source/ColorWheelPlugin/Public/SWColorWheel.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) W2.Wizard 2020-2021. All Rights Reserved. 2 | // modified code of SColorWheel, Original by Copyright Epic Games, Inc. All Rights Reserved. 3 | 4 | #pragma once 5 | 6 | // Core Include 7 | #include "CoreMinimal.h" 8 | #include "Widgets/SLeafWidget.h" 9 | 10 | // Misc Includes 11 | #include "Misc/Attribute.h" 12 | #include "Input/Reply.h" 13 | #include "Widgets/DeclarativeSyntaxSupport.h" 14 | #include "Framework/SlateDelegates.h" 15 | #include "Rendering/DrawElements.h" 16 | #include "Styling/CoreStyle.h" 17 | #include "ColorWheelHelper.h" 18 | 19 | class FPaintArgs; 20 | class FSlateWindowElementList; 21 | struct FSlateBrush; 22 | 23 | DECLARE_DELEGATE_OneParam(FOnPositionChanged, FVector2D) 24 | 25 | // Used for some of the Color wheels UFUNCTIONS to specify the target brush. 26 | UENUM() 27 | enum EWheelBrushTarget 28 | { 29 | // Apply brush to pin and wheel 30 | All, 31 | 32 | // Apply only to the pin 33 | SelectorPin, 34 | 35 | // Apply only to the wheel 36 | HueCircle 37 | }; 38 | 39 | /** 40 | * Just like SColorWheel except it adds a slate argument for the selector pin to be changed 41 | * 42 | * @Note: Because someone thought hardcoding it is reasonable? 43 | */ 44 | class COLORWHEELPLUGIN_API SWColorWheel : public SLeafWidget 45 | { 46 | public: 47 | 48 | SLATE_BEGIN_ARGS(SWColorWheel) 49 | : _SelectedColor() 50 | , _SelectorPin() 51 | , _HueCircle() 52 | , _OnMouseCaptureBegin() 53 | , _OnMouseCaptureEnd() 54 | , _OnValueChanged() 55 | , _OnPositionChanged() 56 | { } 57 | 58 | /// Attributes /// 59 | 60 | /** The current color selected by the user. */ 61 | SLATE_ATTRIBUTE(FLinearColor, SelectedColor) 62 | 63 | /// Arguments /// 64 | 65 | /** The brush used for the selector pin */ 66 | SLATE_ARGUMENT(const FSlateBrush*, SelectorPin) 67 | 68 | /** The brush used for the selector HueCircle */ 69 | SLATE_ARGUMENT(const FSlateBrush*, HueCircle) 70 | 71 | /// Events /// 72 | 73 | /** Invoked when the mouse is pressed and a capture begins. */ 74 | SLATE_EVENT(FSimpleDelegate, OnMouseCaptureBegin) 75 | 76 | /** Invoked when the mouse is released and a capture ends. */ 77 | SLATE_EVENT(FSimpleDelegate, OnMouseCaptureEnd) 78 | 79 | /** Invoked when a new value is selected on the color wheel. */ 80 | SLATE_EVENT(FOnLinearColorValueChanged, OnValueChanged) 81 | 82 | /** Invoked when a new value is selected on the widget wheel. */ 83 | SLATE_EVENT(FOnPositionChanged, OnPositionChanged); 84 | 85 | SLATE_END_ARGS() 86 | 87 | public: 88 | 89 | /** 90 | * Construct this widget. 91 | * 92 | * @param InArgs The declaration data for this widget. 93 | */ 94 | void Construct(const FArguments& InArgs); 95 | 96 | /** See the ColorAndOpacity attribute */ 97 | void SetColorAndOpacity(FLinearColor InColorAndOpacity, TEnumAsByte TargetBrush); 98 | 99 | #pragma region Overrides 100 | 101 | // SWidget overrides 102 | virtual FVector2D ComputeDesiredSize(float) const override; 103 | 104 | virtual FReply OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent) override; 105 | 106 | virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; 107 | 108 | virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; 109 | 110 | virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; 111 | 112 | virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, 113 | FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, 114 | bool bParentEnabled) const override; 115 | 116 | #pragma endregion Overrides 117 | 118 | protected: 119 | 120 | /** 121 | * Calculates the position of the color selection indicator. 122 | * 123 | * @return The position relative to the widget. 124 | */ 125 | FVector2D CalcRelativePositionFromCenter() const; 126 | 127 | /** 128 | * Performs actions according to mouse click / move 129 | * 130 | * @return True if the mouse action occurred within the color wheel radius 131 | */ 132 | bool ProcessMouseAction(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent, bool bProcessWhenOutsideColorWheel); 133 | 134 | private: 135 | 136 | /** The color wheel image to show. */ 137 | const FSlateBrush* Image; 138 | 139 | /** The color selector pin brush */ 140 | const FSlateBrush* SelectorImage; 141 | 142 | /** The current color selected by the user. */ 143 | TAttribute SelectedColor; 144 | 145 | /** Color and opacity scale for the selector pin */ 146 | TAttribute PinColorAndOpacity = FLinearColor::White; 147 | 148 | /** Color and opacity scale for the hue circle */ 149 | TAttribute HueCircleColorAndOpacity = FLinearColor::White; 150 | 151 | 152 | private: 153 | 154 | /** Invoked when the mouse is pressed and a capture begins. */ 155 | FSimpleDelegate OnMouseCaptureBegin; 156 | 157 | /** Invoked when the mouse is let up and a capture ends. */ 158 | FSimpleDelegate OnMouseCaptureEnd; 159 | 160 | /** Invoked when a new value is selected on the color wheel. */ 161 | FOnLinearColorValueChanged OnValueChanged; 162 | 163 | /** Invoked when a new value is selected on the color wheel. */ 164 | FOnPositionChanged OnPositionChanged; 165 | 166 | }; 167 | --------------------------------------------------------------------------------