├── .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 |

5 |
6 |
7 |
UE4/5 Plugin for a free, simple and extendible color wheel.
8 |
9 |
Written by W2.Wizard
10 |
11 |
12 | 
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 |
--------------------------------------------------------------------------------