mirror of
https://github.com/DarthAffe/CUE.NET.git
synced 2025-12-13 09:08:34 +00:00
Refactored brushes and gradients
This commit is contained in:
parent
3c449b272d
commit
f7b8fe130c
@ -46,10 +46,12 @@
|
|||||||
<Compile Include="Devices\Generic\Enums\CorsairDeviceCaps.cs" />
|
<Compile Include="Devices\Generic\Enums\CorsairDeviceCaps.cs" />
|
||||||
<Compile Include="Devices\Generic\Enums\CorsairDeviceType.cs" />
|
<Compile Include="Devices\Generic\Enums\CorsairDeviceType.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Brushes\AbstractBrush.cs" />
|
<Compile Include="Devices\Keyboard\Brushes\AbstractBrush.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Brushes\GradientStop.cs" />
|
<Compile Include="Devices\Keyboard\Brushes\Gradient\AbstractGradient.cs" />
|
||||||
|
<Compile Include="Devices\Keyboard\Brushes\Gradient\GradientStop.cs" />
|
||||||
|
<Compile Include="Devices\Keyboard\Brushes\Gradient\IGradient.cs" />
|
||||||
|
<Compile Include="Devices\Keyboard\Brushes\Gradient\RainbowGradient.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Brushes\IBrush.cs" />
|
<Compile Include="Devices\Keyboard\Brushes\IBrush.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Brushes\LinearGradientBrush.cs" />
|
<Compile Include="Devices\Keyboard\Brushes\LinearGradientBrush.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Brushes\RainbowBrush.cs" />
|
|
||||||
<Compile Include="Devices\Keyboard\Brushes\SolidColorBrush.cs" />
|
<Compile Include="Devices\Keyboard\Brushes\SolidColorBrush.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Enums\CorsairLogicalKeyboardLayout.cs" />
|
<Compile Include="Devices\Keyboard\Enums\CorsairLogicalKeyboardLayout.cs" />
|
||||||
<Compile Include="Devices\Headset\Enums\CorsairHeadsetLedId.cs" />
|
<Compile Include="Devices\Headset\Enums\CorsairHeadsetLedId.cs" />
|
||||||
@ -75,6 +77,7 @@
|
|||||||
<Compile Include="Devices\Mouse\CorsairMouse.cs" />
|
<Compile Include="Devices\Mouse\CorsairMouse.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Extensions\KeyGroupExtension.cs" />
|
<Compile Include="Devices\Keyboard\Extensions\KeyGroupExtension.cs" />
|
||||||
<Compile Include="Helper\ColorHelper.cs" />
|
<Compile Include="Helper\ColorHelper.cs" />
|
||||||
|
<Compile Include="Devices\Keyboard\Brushes\Gradient\LinearGradient.cs" />
|
||||||
<Compile Include="Helper\GradientHelper.cs" />
|
<Compile Include="Helper\GradientHelper.cs" />
|
||||||
<Compile Include="Helper\RectangleHelper.cs" />
|
<Compile Include="Helper\RectangleHelper.cs" />
|
||||||
<Compile Include="Native\_CorsairDeviceInfo.cs" />
|
<Compile Include="Native\_CorsairDeviceInfo.cs" />
|
||||||
|
|||||||
47
Devices/Keyboard/Brushes/Gradient/AbstractGradient.cs
Normal file
47
Devices/Keyboard/Brushes/Gradient/AbstractGradient.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace CUE.NET.Devices.Keyboard.Brushes.Gradient
|
||||||
|
{
|
||||||
|
public abstract class AbstractGradient : IGradient
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public IList<GradientStop> GradientStops { get; } = new List<GradientStop>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public AbstractGradient()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public AbstractGradient(params GradientStop[] gradientStops)
|
||||||
|
{
|
||||||
|
foreach (GradientStop gradientStop in gradientStops)
|
||||||
|
GradientStops.Add(gradientStop);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
protected float ClipOffset(float offset)
|
||||||
|
{
|
||||||
|
float max = GradientStops.Max(n => n.Offset);
|
||||||
|
if (offset > max)
|
||||||
|
return max;
|
||||||
|
|
||||||
|
float min = GradientStops.Min(n => n.Offset);
|
||||||
|
if (offset < min)
|
||||||
|
return min;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Color GetColor(float offset);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace CUE.NET.Devices.Keyboard.Brushes
|
namespace CUE.NET.Devices.Keyboard.Brushes.Gradient
|
||||||
{
|
{
|
||||||
public class GradientStop
|
public class GradientStop
|
||||||
{
|
{
|
||||||
9
Devices/Keyboard/Brushes/Gradient/IGradient.cs
Normal file
9
Devices/Keyboard/Brushes/Gradient/IGradient.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace CUE.NET.Devices.Keyboard.Brushes.Gradient
|
||||||
|
{
|
||||||
|
public interface IGradient
|
||||||
|
{
|
||||||
|
Color GetColor(float offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
45
Devices/Keyboard/Brushes/Gradient/LinearGradient.cs
Normal file
45
Devices/Keyboard/Brushes/Gradient/LinearGradient.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace CUE.NET.Devices.Keyboard.Brushes.Gradient
|
||||||
|
{
|
||||||
|
public class LinearGradient : AbstractGradient
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public LinearGradient()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public LinearGradient(params GradientStop[] gradientStops)
|
||||||
|
: base(gradientStops)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public override Color GetColor(float offset)
|
||||||
|
{
|
||||||
|
if (!GradientStops.Any()) return Color.Transparent;
|
||||||
|
if (GradientStops.Count == 1) return GradientStops.First().Color;
|
||||||
|
|
||||||
|
offset = ClipOffset(offset);
|
||||||
|
|
||||||
|
GradientStop gsBefore = GradientStops.Where(n => n.Offset <= offset).OrderBy(n => n.Offset).Last();
|
||||||
|
GradientStop gsAfter = GradientStops.Where(n => n.Offset >= offset).OrderBy(n => n.Offset).First();
|
||||||
|
|
||||||
|
float blendFactor = 0f;
|
||||||
|
if (!gsBefore.Offset.Equals(gsAfter.Offset))
|
||||||
|
blendFactor = ((offset - gsBefore.Offset) / (gsAfter.Offset - gsBefore.Offset));
|
||||||
|
|
||||||
|
byte colA = (byte)((gsAfter.Color.A - gsBefore.Color.A) * blendFactor + gsBefore.Color.A);
|
||||||
|
byte colR = (byte)((gsAfter.Color.R - gsBefore.Color.R) * blendFactor + gsBefore.Color.R);
|
||||||
|
byte colG = (byte)((gsAfter.Color.G - gsBefore.Color.G) * blendFactor + gsBefore.Color.G);
|
||||||
|
byte colB = (byte)((gsAfter.Color.B - gsBefore.Color.B) * blendFactor + gsBefore.Color.B);
|
||||||
|
|
||||||
|
return Color.FromArgb(colA, colR, colG, colB);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
40
Devices/Keyboard/Brushes/Gradient/RainbowGradient.cs
Normal file
40
Devices/Keyboard/Brushes/Gradient/RainbowGradient.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
|
using CUE.NET.Helper;
|
||||||
|
|
||||||
|
namespace CUE.NET.Devices.Keyboard.Brushes.Gradient
|
||||||
|
{
|
||||||
|
public class RainbowGradient : IGradient
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public float StartHue { get; set; }
|
||||||
|
public float EndHue { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public RainbowGradient(float startHue = 0f, float endHue = 360f)
|
||||||
|
{
|
||||||
|
this.StartHue = startHue;
|
||||||
|
this.EndHue = endHue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public Color GetColor(float offset)
|
||||||
|
{
|
||||||
|
float range = EndHue - StartHue;
|
||||||
|
float hue = (StartHue + (range * offset)) % 360f;
|
||||||
|
if (hue < 0)
|
||||||
|
hue += 360;
|
||||||
|
return ColorHelper.ColorFromHSV(hue, 1f, 1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,9 +2,8 @@
|
|||||||
// ReSharper disable MemberCanBePrivate.Global
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
// ReSharper disable ReturnTypeCanBeEnumerable.Global
|
// ReSharper disable ReturnTypeCanBeEnumerable.Global
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using CUE.NET.Devices.Keyboard.Brushes.Gradient;
|
||||||
using CUE.NET.Helper;
|
using CUE.NET.Helper;
|
||||||
|
|
||||||
namespace CUE.NET.Devices.Keyboard.Brushes
|
namespace CUE.NET.Devices.Keyboard.Brushes
|
||||||
@ -15,7 +14,7 @@ namespace CUE.NET.Devices.Keyboard.Brushes
|
|||||||
|
|
||||||
public PointF StartPoint { get; set; } = new PointF(0f, 0.5f);
|
public PointF StartPoint { get; set; } = new PointF(0f, 0.5f);
|
||||||
public PointF EndPoint { get; set; } = new PointF(1f, 0.5f);
|
public PointF EndPoint { get; set; } = new PointF(1f, 0.5f);
|
||||||
public IList<GradientStop> GradientStops { get; } = new List<GradientStop>();
|
public IGradient Gradient { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -24,19 +23,16 @@ namespace CUE.NET.Devices.Keyboard.Brushes
|
|||||||
public LinearGradientBrush()
|
public LinearGradientBrush()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public LinearGradientBrush(PointF startPoint, PointF endPoint, params GradientStop[] gradientStops)
|
public LinearGradientBrush(IGradient gradient)
|
||||||
|
{
|
||||||
|
this.Gradient = gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LinearGradientBrush(PointF startPoint, PointF endPoint, IGradient gradient)
|
||||||
{
|
{
|
||||||
this.StartPoint = startPoint;
|
this.StartPoint = startPoint;
|
||||||
this.EndPoint = endPoint;
|
this.EndPoint = endPoint;
|
||||||
|
this.Gradient = gradient;
|
||||||
foreach (GradientStop gradientStop in gradientStops)
|
|
||||||
GradientStops.Add(gradientStop);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LinearGradientBrush(params GradientStop[] gradientStops)
|
|
||||||
{
|
|
||||||
foreach (GradientStop gradientStop in gradientStops)
|
|
||||||
GradientStops.Add(gradientStop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -45,37 +41,13 @@ namespace CUE.NET.Devices.Keyboard.Brushes
|
|||||||
|
|
||||||
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
|
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
|
||||||
{
|
{
|
||||||
if (!GradientStops.Any()) return Color.Transparent;
|
if (Gradient == null) return Color.Transparent;
|
||||||
if (GradientStops.Count == 1) return GradientStops.First().Color;
|
|
||||||
|
|
||||||
PointF startPoint = new PointF(StartPoint.X * rectangle.Width, StartPoint.Y * rectangle.Height);
|
PointF startPoint = new PointF(StartPoint.X * rectangle.Width, StartPoint.Y * rectangle.Height);
|
||||||
PointF endPoint = new PointF(EndPoint.X * rectangle.Width, EndPoint.Y * rectangle.Height);
|
PointF endPoint = new PointF(EndPoint.X * rectangle.Width, EndPoint.Y * rectangle.Height);
|
||||||
|
|
||||||
float offset = GradientHelper.CalculateGradientOffset(startPoint, endPoint, point);
|
float offset = GradientHelper.CalculateLinearGradientOffset(startPoint, endPoint, point);
|
||||||
|
return FinalizeColor(Gradient.GetColor(offset));
|
||||||
// Clip the input if before or after the max/min offset values
|
|
||||||
float max = GradientStops.Max(n => n.Offset);
|
|
||||||
if (offset > max)
|
|
||||||
offset = max;
|
|
||||||
|
|
||||||
float min = GradientStops.Min(n => n.Offset);
|
|
||||||
if (offset < min)
|
|
||||||
offset = min;
|
|
||||||
|
|
||||||
// Find gradient stops that surround the input value
|
|
||||||
GradientStop gsBefore = GradientStops.Where(n => n.Offset <= offset).OrderBy(n => n.Offset).Last();
|
|
||||||
GradientStop gsAfter = GradientStops.Where(n => n.Offset >= offset).OrderBy(n => n.Offset).First();
|
|
||||||
|
|
||||||
float blendFactor = 0f;
|
|
||||||
if (!gsBefore.Offset.Equals(gsAfter.Offset))
|
|
||||||
blendFactor = ((offset - gsBefore.Offset) / (gsAfter.Offset - gsBefore.Offset));
|
|
||||||
|
|
||||||
byte colA = (byte)((gsAfter.Color.A - gsBefore.Color.A) * blendFactor + gsBefore.Color.A);
|
|
||||||
byte colR = (byte)((gsAfter.Color.R - gsBefore.Color.R) * blendFactor + gsBefore.Color.R);
|
|
||||||
byte colG = (byte)((gsAfter.Color.G - gsBefore.Color.G) * blendFactor + gsBefore.Color.G);
|
|
||||||
byte colB = (byte)((gsAfter.Color.B - gsBefore.Color.B) * blendFactor + gsBefore.Color.B);
|
|
||||||
|
|
||||||
return FinalizeColor(Color.FromArgb(colA, colR, colG, colB));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -1,53 +0,0 @@
|
|||||||
// ReSharper disable MemberCanBePrivate.Global
|
|
||||||
|
|
||||||
using System.Drawing;
|
|
||||||
using CUE.NET.Helper;
|
|
||||||
|
|
||||||
namespace CUE.NET.Devices.Keyboard.Brushes
|
|
||||||
{
|
|
||||||
public class RainbowBrush : AbstractBrush
|
|
||||||
{
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
public PointF StartPoint { get; set; } = new PointF(0f, 0.5f);
|
|
||||||
public PointF EndPoint { get; set; } = new PointF(1f, 0.5f);
|
|
||||||
public float StartHue { get; set; }
|
|
||||||
public float EndHue { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
public RainbowBrush(float startHue = 0f, float endHue = 360f)
|
|
||||||
{
|
|
||||||
this.StartHue = startHue;
|
|
||||||
this.EndHue = endHue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RainbowBrush(PointF startPoint, PointF endPoint, float startHue = 0f, float endHue = 360f)
|
|
||||||
{
|
|
||||||
this.StartPoint = startPoint;
|
|
||||||
this.EndPoint = endPoint;
|
|
||||||
this.StartHue = startHue;
|
|
||||||
this.EndHue = endHue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
|
|
||||||
{
|
|
||||||
PointF startPoint = new PointF(StartPoint.X * rectangle.Width, StartPoint.Y * rectangle.Height);
|
|
||||||
PointF endPoint = new PointF(EndPoint.X * rectangle.Width, EndPoint.Y * rectangle.Height);
|
|
||||||
|
|
||||||
float offset = GradientHelper.CalculateGradientOffset(startPoint, endPoint, point);
|
|
||||||
float range = EndHue - StartHue;
|
|
||||||
|
|
||||||
float hue = (StartHue + (range * offset)) % 360f;
|
|
||||||
return FinalizeColor(ColorHelper.ColorFromHSV(hue, 1f, 1f));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,6 +6,7 @@ using CUE.NET;
|
|||||||
using CUE.NET.Devices.Generic.Enums;
|
using CUE.NET.Devices.Generic.Enums;
|
||||||
using CUE.NET.Devices.Keyboard;
|
using CUE.NET.Devices.Keyboard;
|
||||||
using CUE.NET.Devices.Keyboard.Brushes;
|
using CUE.NET.Devices.Keyboard.Brushes;
|
||||||
|
using CUE.NET.Devices.Keyboard.Brushes.Gradient;
|
||||||
using CUE.NET.Devices.Keyboard.Enums;
|
using CUE.NET.Devices.Keyboard.Enums;
|
||||||
using CUE.NET.Devices.Keyboard.Extensions;
|
using CUE.NET.Devices.Keyboard.Extensions;
|
||||||
using CUE.NET.Devices.Keyboard.Keys;
|
using CUE.NET.Devices.Keyboard.Keys;
|
||||||
@ -87,7 +88,7 @@ namespace SimpleDevTest
|
|||||||
GradientStop moveableStop = new GradientStop(0, Color.FromArgb(0, 255, 0));
|
GradientStop moveableStop = new GradientStop(0, Color.FromArgb(0, 255, 0));
|
||||||
|
|
||||||
// Create a basic (by default horizontal) brush ...
|
// Create a basic (by default horizontal) brush ...
|
||||||
LinearGradientBrush linearBrush = new LinearGradientBrush(new GradientStop(0, Color.Blue), moveableStop, new GradientStop(1f, Color.White));
|
LinearGradientBrush linearBrush = new LinearGradientBrush(new LinearGradient(new GradientStop(0, Color.Blue), moveableStop, new GradientStop(1f, Color.White)));
|
||||||
|
|
||||||
// ... and add it as the keyboard background
|
// ... and add it as the keyboard background
|
||||||
keyboard.Brush = linearBrush;
|
keyboard.Brush = linearBrush;
|
||||||
@ -129,17 +130,17 @@ namespace SimpleDevTest
|
|||||||
Console.WriteLine("rainbow-test");
|
Console.WriteLine("rainbow-test");
|
||||||
|
|
||||||
// Create an simple horizontal rainbow containing two times the full spectrum
|
// Create an simple horizontal rainbow containing two times the full spectrum
|
||||||
RainbowBrush rainbowBrush = new RainbowBrush(0, 720);
|
RainbowGradient rainbowGradient = new RainbowGradient(0, 720);
|
||||||
|
|
||||||
// Add the rainbow to the keyboard and perform an initial update
|
// Add the rainbow to the keyboard and perform an initial update
|
||||||
keyboard.Brush = rainbowBrush;
|
keyboard.Brush = new LinearGradientBrush(rainbowGradient);
|
||||||
keyboard.UpdateLeds();
|
keyboard.UpdateLeds();
|
||||||
|
|
||||||
// Let the rainbow move around for 10 secs
|
// Let the rainbow move around for 10 secs
|
||||||
for (int i = 0; i < 100; i++)
|
for (int i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
rainbowBrush.StartHue += 10f;
|
rainbowGradient.StartHue += 10f;
|
||||||
rainbowBrush.EndHue += 10f;
|
rainbowGradient.EndHue += 10f;
|
||||||
keyboard.UpdateLeds();
|
keyboard.UpdateLeds();
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace CUE.NET.Helper
|
|||||||
public static class GradientHelper
|
public static class GradientHelper
|
||||||
{
|
{
|
||||||
// Based on https://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/
|
// Based on https://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/
|
||||||
public static float CalculateGradientOffset(PointF startPoint, PointF endPoint, PointF point)
|
public static float CalculateLinearGradientOffset(PointF startPoint, PointF endPoint, PointF point)
|
||||||
{
|
{
|
||||||
PointF intersectingPoint;
|
PointF intersectingPoint;
|
||||||
if (startPoint.Y.Equals(endPoint.Y)) // Horizontal case
|
if (startPoint.Y.Equals(endPoint.Y)) // Horizontal case
|
||||||
@ -39,7 +39,7 @@ namespace CUE.NET.Helper
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the signed magnitude of a point on a vector
|
/// Returns the signed magnitude of a point on a vector
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static float CalculateDistance(PointF point, PointF origin, PointF direction)
|
public static float CalculateDistance(PointF point, PointF origin, PointF direction)
|
||||||
{
|
{
|
||||||
float distance = (float)Math.Sqrt((point.Y - origin.Y) * (point.Y - origin.Y) + (point.X - origin.X) * (point.X - origin.X));
|
float distance = (float)Math.Sqrt((point.Y - origin.Y) * (point.Y - origin.Y) + (point.X - origin.X) * (point.X - origin.X));
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user