diff --git a/CUE.NET.csproj b/CUE.NET.csproj index 9cd2868..61448c7 100644 --- a/CUE.NET.csproj +++ b/CUE.NET.csproj @@ -63,8 +63,10 @@ - - + + + + diff --git a/Devices/Keyboard/Brushes/GradientStop.cs b/Devices/Keyboard/Brushes/GradientStop.cs new file mode 100644 index 0000000..761eb05 --- /dev/null +++ b/Devices/Keyboard/Brushes/GradientStop.cs @@ -0,0 +1,26 @@ +using System.Drawing; + +namespace CUE.NET.Devices.Keyboard.Brushes +{ + public class GradientStop + { + + #region Properties & Fields + + public float Offset { get; set; } + + public Color Color { get; set; } + + #endregion + + #region Constructors + + public GradientStop(float offset, Color color) + { + this.Offset = offset; + this.Color = color; + } + + #endregion + } +} diff --git a/Devices/Keyboard/ColorBrushes/IBrush.cs b/Devices/Keyboard/Brushes/IBrush.cs similarity index 73% rename from Devices/Keyboard/ColorBrushes/IBrush.cs rename to Devices/Keyboard/Brushes/IBrush.cs index e90c6dd..7e23773 100644 --- a/Devices/Keyboard/ColorBrushes/IBrush.cs +++ b/Devices/Keyboard/Brushes/IBrush.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace CUE.NET.Devices.Keyboard.ColorBrushes +namespace CUE.NET.Devices.Keyboard.Brushes { public interface IBrush { diff --git a/Devices/Keyboard/Brushes/LinearGradientBrush.cs b/Devices/Keyboard/Brushes/LinearGradientBrush.cs new file mode 100644 index 0000000..31a169a --- /dev/null +++ b/Devices/Keyboard/Brushes/LinearGradientBrush.cs @@ -0,0 +1,132 @@ +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable ReturnTypeCanBeEnumerable.Global + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace CUE.NET.Devices.Keyboard.Brushes +{ + public class LinearGradientBrush : IBrush + { + #region Properties & Fields + + public PointF StartPoint { get; set; } = new PointF(0f, 0.5f); + public PointF EndPoint { get; set; } = new PointF(1f, 0.5f); + public IList GradientStops { get; } = new List(); + + #endregion + + #region Constructor + + public LinearGradientBrush() + { } + + public LinearGradientBrush(PointF startPoint, PointF endPoint, params GradientStop[] gradientStops) + { + this.StartPoint = startPoint; + this.EndPoint = endPoint; + + foreach (GradientStop gradientStop in gradientStops) + GradientStops.Add(gradientStop); + } + + public LinearGradientBrush(params GradientStop[] gradientStops) + { + foreach (GradientStop gradientStop in gradientStops) + GradientStops.Add(gradientStop); + } + + #endregion + + #region Methods + + public Color GetColorAtPoint(RectangleF rectangle, PointF point) + { + if (!GradientStops.Any()) return Color.Transparent; + if (GradientStops.Count == 1) return GradientStops.First().Color; + + // Taken from https://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/ + + float x3 = point.X; + float y3 = point.Y; + + float x1 = StartPoint.X * rectangle.Width; + float y1 = StartPoint.Y * rectangle.Height; + PointF p1 = new PointF(x1, y1); // Starting point + + float x2 = EndPoint.X * rectangle.Width; + float y2 = EndPoint.Y * rectangle.Height; + PointF p2 = new PointF(x2, y2); //End point + + // Calculate intersecting points + PointF p4; + + if (y1.Equals(y2)) // Horizontal case + p4 = new PointF(x3, y1); + + else if (x1.Equals(x2)) // Vertical case + p4 = new PointF(x1, y3); + + else // Diagnonal case + { + float m = (y2 - y1) / (x2 - x1); + float m2 = -1 / m; + float b = y1 - m * x1; + float c = y3 - m2 * x3; + + float x4 = (c - b) / (m - m2); + float y4 = m * x4 + b; + p4 = new PointF(x4, y4); + } + + // Calculate distances relative to the vector start + float d4 = Dist(p4, p1, p2); + float d2 = Dist(p2, p1, p2); + + float x = d4 / d2; + + // Clip the input if before or after the max/min offset values + float max = GradientStops.Max(n => n.Offset); + if (x > max) + x = max; + + float min = GradientStops.Min(n => n.Offset); + if (x < min) + x = min; + + // Find gradient stops that surround the input value + GradientStop gs0 = GradientStops.Where(n => n.Offset <= x).OrderBy(n => n.Offset).Last(); + GradientStop gs1 = GradientStops.Where(n => n.Offset >= x).OrderBy(n => n.Offset).First(); + + float y = 0f; + if (!gs0.Offset.Equals(gs1.Offset)) + y = ((x - gs0.Offset) / (gs1.Offset - gs0.Offset)); + + byte colA = (byte)((gs1.Color.A - gs0.Color.A) * y + gs0.Color.A); + byte colR = (byte)((gs1.Color.R - gs0.Color.R) * y + gs0.Color.R); + byte colG = (byte)((gs1.Color.G - gs0.Color.G) * y + gs0.Color.G); + byte colB = (byte)((gs1.Color.B - gs0.Color.B) * y + gs0.Color.B); + return Color.FromArgb(colA, colR, colG, colB); + } + + // Taken from https://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/ + /// + /// Returns the signed magnitude of a point on a vector with origin po and pointing to pf + /// + private float Dist(PointF px, PointF po, PointF pf) + { + float d = (float)Math.Sqrt((px.Y - po.Y) * (px.Y - po.Y) + (px.X - po.X) * (px.X - po.X)); + + return (((px.Y < po.Y) && (pf.Y > po.Y)) || + ((px.Y > po.Y) && (pf.Y < po.Y)) || + ((px.Y.Equals(po.Y)) && (px.X < po.X) && (pf.X > po.X)) || + ((px.Y.Equals(po.Y)) && (px.X > po.X) && (pf.X < po.X))) + ? -d : d; + } + + #endregion + } +} diff --git a/Devices/Keyboard/ColorBrushes/SolidColorBrush.cs b/Devices/Keyboard/Brushes/SolidColorBrush.cs similarity index 92% rename from Devices/Keyboard/ColorBrushes/SolidColorBrush.cs rename to Devices/Keyboard/Brushes/SolidColorBrush.cs index 66057cf..148f949 100644 --- a/Devices/Keyboard/ColorBrushes/SolidColorBrush.cs +++ b/Devices/Keyboard/Brushes/SolidColorBrush.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace CUE.NET.Devices.Keyboard.ColorBrushes +namespace CUE.NET.Devices.Keyboard.Brushes { public class SolidColorBrush : IBrush { diff --git a/Devices/Keyboard/CorsairKeyboard.cs b/Devices/Keyboard/CorsairKeyboard.cs index b0be27b..27fa6a0 100644 --- a/Devices/Keyboard/CorsairKeyboard.cs +++ b/Devices/Keyboard/CorsairKeyboard.cs @@ -6,7 +6,7 @@ using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using CUE.NET.Devices.Generic; -using CUE.NET.Devices.Keyboard.ColorBrushes; +using CUE.NET.Devices.Keyboard.Brushes; using CUE.NET.Devices.Keyboard.Enums; using CUE.NET.Devices.Keyboard.Keys; using CUE.NET.Helper; diff --git a/Devices/Keyboard/Keys/BaseKeyGroup.cs b/Devices/Keyboard/Keys/BaseKeyGroup.cs index 1eca0de..bb39884 100644 --- a/Devices/Keyboard/Keys/BaseKeyGroup.cs +++ b/Devices/Keyboard/Keys/BaseKeyGroup.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; -using CUE.NET.Devices.Keyboard.ColorBrushes; +using CUE.NET.Devices.Keyboard.Brushes; using CUE.NET.Devices.Keyboard.Extensions; namespace CUE.NET.Devices.Keyboard.Keys diff --git a/Devices/Keyboard/Keys/IKeyGroup.cs b/Devices/Keyboard/Keys/IKeyGroup.cs index e962bee..4fbc569 100644 --- a/Devices/Keyboard/Keys/IKeyGroup.cs +++ b/Devices/Keyboard/Keys/IKeyGroup.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using CUE.NET.Devices.Keyboard.ColorBrushes; +using CUE.NET.Devices.Keyboard.Brushes; namespace CUE.NET.Devices.Keyboard.Keys { diff --git a/Examples/SimpleDevTest/Program.cs b/Examples/SimpleDevTest/Program.cs index b3685b2..687ac9e 100644 --- a/Examples/SimpleDevTest/Program.cs +++ b/Examples/SimpleDevTest/Program.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using CUE.NET; using CUE.NET.Devices.Generic.Enums; using CUE.NET.Devices.Keyboard; -using CUE.NET.Devices.Keyboard.ColorBrushes; +using CUE.NET.Devices.Keyboard.Brushes; using CUE.NET.Devices.Keyboard.Enums; using CUE.NET.Devices.Keyboard.Extensions; using CUE.NET.Devices.Keyboard.Keys; @@ -18,6 +18,7 @@ namespace SimpleDevTest public static void Main(string[] args) { Console.WriteLine("Press any key to exit ..."); + Console.WriteLine(); Task.Factory.StartNew( () => { @@ -35,6 +36,11 @@ namespace SimpleDevTest if (keyboard == null) throw new WrapperException("No keyboard found"); + + // --------------------------------------------------------------------------- + // First we'll look at some basic coloring + + Console.WriteLine("Basic color-test ..."); // Ink all numbers on the keypad except the '5' purple, we want that to be gray ListKeyGroup purpleGroup = new RectangleKeyGroup(keyboard, CorsairKeyboardKeyId.Keypad7, CorsairKeyboardKeyId.Keypad3) { Brush = new SolidColorBrush(Color.Purple) } @@ -63,27 +69,68 @@ namespace SimpleDevTest // Update the keyboard to show the configured colors, (your CUE settings defines the rest) keyboard.UpdateLeds(); - // Wait 5 sec - for (int i = 5; i > 0; i--) + Wait(3); + + // Remove all the groups we created above to clear the keyboard + purpleGroup.Detach(); + whiteGroup.Detach(); + yellowGroup.Detach(); + + + // --------------------------------------------------------------------------- + // Next we add a nice linear gradient brush over the keyboard and play around with the offset of one stop + + Console.WriteLine("gradient-brush-test"); + + // Create our gradient stop to play with + GradientStop moveableStop = new GradientStop(0, Color.FromArgb(0, 255, 0)); + + //Create a basic (by default horizontal) brush ... + LinearGradientBrush linearBrush = new LinearGradientBrush(new GradientStop(0, Color.Blue), moveableStop, new GradientStop(1f, Color.Red)); + + // ... and add it as the keyboard background + keyboard.Brush = linearBrush; + + // Move the brush from left to right + for (float offset = 0; offset <= 1f; offset += 0.02f) { - Console.WriteLine(i); - Thread.Sleep(1000); + moveableStop.Offset = offset; + keyboard.UpdateLeds(); + Thread.Sleep(100); } + // And back to center + for (float offset = 1f; offset >= 0.5f; offset -= 0.02f) + { + moveableStop.Offset = offset; + keyboard.UpdateLeds(); + Thread.Sleep(100); + } + + // "Rotate" the brush (this is of course not the best implementation for this but you see the point) + for (float rotateX = 0, rotateY = 0; rotateX <= 1f; rotateX += 0.02f, rotateY = 0.04f) + { + if (rotateY > 1f) + rotateY = 1f - (rotateY - 1f); + + linearBrush.StartPoint = new PointF(rotateX, rotateY); + linearBrush.EndPoint = new PointF(1f - rotateX, 1f - rotateY); + + keyboard.UpdateLeds(); + Thread.Sleep(100); + } + + Wait(2); + // --------------------------------------------------------------------------- // Now let us move some points random over the keyboard // Something like this could become some sort of effect // Initialize needed stuff - const float SPEED = 4f; // mm/tick + const float SPEED = 6f; // mm/tick Random random = new Random(); - // Remove all the groups we created above to clear the keyboard - purpleGroup.Detach(); - whiteGroup.Detach(); - yellowGroup.Detach(); - // Flash whole keyboard three times to ... well ... just to make it happen for (int i = 0; i < 3; i++) { @@ -168,6 +215,15 @@ namespace SimpleDevTest Thread.Sleep(1000); // Don't exit after exception } + private static void Wait(int sec) + { + for (int i = sec; i > 0; i--) + { + Console.WriteLine(i); + Thread.Sleep(1000); + } + } + private static PointF Interpolate(PointF p1, PointF p2, float length) { float distance = (float)(Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2))); diff --git a/Helper/ColorHelper.cs b/Helper/ColorHelper.cs index 7ba2140..16be988 100644 --- a/Helper/ColorHelper.cs +++ b/Helper/ColorHelper.cs @@ -49,8 +49,8 @@ namespace CUE.NET.Helper private static byte GetIntColorFromFloat(float f) { - float calcF = (float)Math.Max(0.0, Math.Min(1.0, f)); - return (byte)(calcF == 1.0 ? 255 : calcF * 256.0); + float calcF = (float)Math.Max(0f, Math.Min(1f, f)); + return (byte)(calcF.Equals(1f) ? 255 : calcF * 256.0); } } }