mirror of
https://github.com/DarthAffe/RGB.NET.git
synced 2025-12-13 10:08:31 +00:00
Compare commits
No commits in common. "master" and "v0.1.33" have entirely different histories.
56
.github/workflows/ci.yml
vendored
56
.github/workflows/ci.yml
vendored
@ -1,56 +0,0 @@
|
|||||||
name: RGB.NET-CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: 'version'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
increment:
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: windows-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4.1.1
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup .NET
|
|
||||||
uses: actions/setup-dotnet@v4
|
|
||||||
with:
|
|
||||||
dotnet-version: |
|
|
||||||
9.0.x
|
|
||||||
8.0.x
|
|
||||||
- name: Restore dependencies
|
|
||||||
run: dotnet restore
|
|
||||||
- name: Build
|
|
||||||
run: dotnet build --no-restore --configuration Release /p:Version=${{ github.event.inputs.version }}-prerelease.${{ github.event.inputs.increment }}
|
|
||||||
- name: Test
|
|
||||||
run: dotnet test --no-build --verbosity normal --configuration Release
|
|
||||||
- name: Upload a Build Artifact NET9
|
|
||||||
uses: actions/upload-artifact@v4.3.1
|
|
||||||
with:
|
|
||||||
name: RGB.NET-NET9
|
|
||||||
path: bin/net9.0/RGB.NET.*.dll
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Upload a Build Artifact NET8
|
|
||||||
uses: actions/upload-artifact@v4.3.1
|
|
||||||
with:
|
|
||||||
name: RGB.NET-NET8
|
|
||||||
path: bin/net8.0/RGB.NET.*.dll
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Upload Nuget Build Artifact
|
|
||||||
uses: actions/upload-artifact@v4.3.1
|
|
||||||
with:
|
|
||||||
name: RGB.NET-Nugets
|
|
||||||
path: bin/*nupkg
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Nuget Push
|
|
||||||
run: dotnet nuget push **\*.nupkg --skip-duplicate --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json
|
|
||||||
- name: Symbols Push
|
|
||||||
run: dotnet nuget push **\*.snupkg --skip-duplicate --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json
|
|
||||||
26
.github/workflows/pr_verify.yml
vendored
26
.github/workflows/pr_verify.yml
vendored
@ -1,26 +0,0 @@
|
|||||||
name: PR-Verify
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches: [ master, Development ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: windows-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4.1.1
|
|
||||||
- name: Setup .NET
|
|
||||||
uses: actions/setup-dotnet@v4
|
|
||||||
with:
|
|
||||||
dotnet-version: |
|
|
||||||
9.0.x
|
|
||||||
8.0.x
|
|
||||||
- name: Restore dependencies
|
|
||||||
run: dotnet restore
|
|
||||||
- name: Build
|
|
||||||
run: dotnet build --no-restore --configuration Release /p:Version=0.0.0
|
|
||||||
- name: Test
|
|
||||||
run: dotnet test --no-build --verbosity normal --configuration Release
|
|
||||||
|
|
||||||
56
.github/workflows/release.yml
vendored
56
.github/workflows/release.yml
vendored
@ -1,56 +0,0 @@
|
|||||||
name: RGB.NET-Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: 'version'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: windows-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4.1.1
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup .NET
|
|
||||||
uses: actions/setup-dotnet@v4
|
|
||||||
with:
|
|
||||||
dotnet-version: |
|
|
||||||
9.0.x
|
|
||||||
8.0.x
|
|
||||||
- name: Restore dependencies
|
|
||||||
run: dotnet restore
|
|
||||||
- name: Build
|
|
||||||
run: dotnet build --no-restore --configuration Release /p:Version=${{ github.event.inputs.version }}
|
|
||||||
- name: Test
|
|
||||||
run: dotnet test --no-build --verbosity normal --configuration Release
|
|
||||||
- name: Upload a Build Artifact NET9
|
|
||||||
uses: actions/upload-artifact@v4.3.1
|
|
||||||
with:
|
|
||||||
name: RGB.NET-NET9
|
|
||||||
path: bin/net9.0/RGB.NET.*.dll
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Upload a Build Artifact NET8
|
|
||||||
uses: actions/upload-artifact@v4.3.1
|
|
||||||
with:
|
|
||||||
name: RGB.NET-NET8
|
|
||||||
path: bin/net8.0/RGB.NET.*.dll
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Upload Nuget Build Artifact
|
|
||||||
uses: actions/upload-artifact@v4.3.1
|
|
||||||
with:
|
|
||||||
name: RGB.NET-Nugets
|
|
||||||
path: bin/*nupkg
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Release
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
with:
|
|
||||||
tag_name: v${{ github.event.inputs.version }}
|
|
||||||
generate_release_notes: true
|
|
||||||
files: bin/net9.0/RGB.NET.*.dll
|
|
||||||
- name: Nuget Push
|
|
||||||
run: dotnet nuget push **\*.nupkg --skip-duplicate --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json
|
|
||||||
@ -7,22 +7,17 @@
|
|||||||
<xsd:element name="Description" type="xsd:string" />
|
<xsd:element name="Description" type="xsd:string" />
|
||||||
<xsd:element name="Author" type="xsd:string" />
|
<xsd:element name="Author" type="xsd:string" />
|
||||||
<xsd:element name="Type" type="xsd:string" />
|
<xsd:element name="Type" type="xsd:string" />
|
||||||
|
<xsd:element name="Lighting" type="xsd:string" />
|
||||||
<xsd:element name="Vendor" type="xsd:string" />
|
<xsd:element name="Vendor" type="xsd:string" />
|
||||||
<xsd:element name="Model" type="xsd:string" />
|
<xsd:element name="Model" type="xsd:string" />
|
||||||
<xsd:element name="Shape" type="xsd:string" />
|
<xsd:element name="Shape" type="xsd:string" />
|
||||||
<xsd:element name="Width" type="xsd:double" />
|
<xsd:element name="Width" type="xsd:double" />
|
||||||
<xsd:element name="Height" type="xsd:double" />
|
<xsd:element name="Height" type="xsd:double" />
|
||||||
|
<xsd:element name="ImageBasePath" type="xsd:string" />
|
||||||
|
<xsd:element name="DeviceImage" type="xsd:string" />
|
||||||
<xsd:element name="LedUnitWidth" type="xsd:double" />
|
<xsd:element name="LedUnitWidth" type="xsd:double" />
|
||||||
<xsd:element name="LedUnitHeight" type="xsd:double" />
|
<xsd:element name="LedUnitHeight" type="xsd:double" />
|
||||||
<xsd:element name="CustomData">
|
<xsd:element name="Leds">
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:any />
|
|
||||||
</xsd:sequence>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
|
|
||||||
<xsd:element name="Leds">
|
|
||||||
<xsd:complexType>
|
<xsd:complexType>
|
||||||
<xsd:sequence>
|
<xsd:sequence>
|
||||||
<xsd:element maxOccurs="unbounded" name="Led">
|
<xsd:element maxOccurs="unbounded" name="Led">
|
||||||
@ -33,13 +28,6 @@
|
|||||||
<xsd:element name="Y" type="xsd:string" />
|
<xsd:element name="Y" type="xsd:string" />
|
||||||
<xsd:element name="Width" type="xsd:string" />
|
<xsd:element name="Width" type="xsd:string" />
|
||||||
<xsd:element name="Height" type="xsd:string" />
|
<xsd:element name="Height" type="xsd:string" />
|
||||||
<xsd:element name="CustomData">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:any />
|
|
||||||
</xsd:sequence>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:sequence>
|
</xsd:sequence>
|
||||||
<xsd:attribute name="Id" type="xsd:string" use="required" />
|
<xsd:attribute name="Id" type="xsd:string" use="required" />
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
@ -47,7 +35,32 @@
|
|||||||
</xsd:sequence>
|
</xsd:sequence>
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
</xsd:element>
|
</xsd:element>
|
||||||
</xsd:sequence>
|
<xsd:element name="LedImageLayouts">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element maxOccurs="unbounded" name="LedImageLayout">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="LedImages">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element maxOccurs="unbounded" name="LedImage">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="Id" type="xsd:string" use="required" />
|
||||||
|
<xsd:attribute name="Image" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="Layout" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:sequence>
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
</xsd:element>
|
</xsd:element>
|
||||||
</xs:schema>
|
</xs:schema>
|
||||||
95
README.md
95
README.md
@ -1,87 +1,30 @@
|
|||||||
# RGB.NET
|
# RGB.NET
|
||||||
[](https://github.com/DarthAffe/RGB.NET/releases)
|
|
||||||
[](https://www.nuget.org/packages?q=rgb.net)
|
|
||||||
[](https://github.com/DarthAffe/RGB.NET/blob/master/LICENSE)
|
|
||||||
[](https://github.com/DarthAffe/RGB.NET/stargazers)
|
|
||||||
[](https://discord.gg/9kytURv)
|
|
||||||
|
|
||||||
> **IMPORTANT NOTE**
|
This project aims to unify the use of various RGB-devices.
|
||||||
This is a library to integrate RGB-devices into your own application. It does not contain any executables!
|
**It is currently under heavy development and will have breaking changes in the future!** Right now a lot of devices aren't working as expected and there are bugs/unfinished features. Please think about that when you consider using the library in this early stage.
|
||||||
If you're looking for a full blown software solution to manage your RGB-devices, take a look at [Artemis](https://artemis-rgb.com/).
|
|
||||||
|
If you want to help with layouting/testing devices or if you need support using the library feel free to join the [RGB.NET discord-channel](https://discord.gg/9kytURv).
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
### Setup
|
|
||||||
1. Add the [RGB.NET.Core](https://www.nuget.org/packages/RGB.NET.Core) and [Devices](https://www.nuget.org/packages?q=rgb.net.Devices)-Nugets for all devices you want to use.
|
|
||||||
2. For some of the vendors SDK-libraries are needed. Check the contained Readmes for more information in that case.
|
|
||||||
3. Create a new `RGBSurface`.
|
|
||||||
```csharp
|
|
||||||
RGBSurface surface = new RGBSurface();
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Initialize the providers for all devices you want to use and add the devices to the surface. For example:
|
## Adding prerelease packages using NuGet ##
|
||||||
```csharp
|
This is the easiest and therefore preferred way to include RGB.NET in your project.
|
||||||
CorsairDeviceProvider.Instance.Initialize(throwExceptions: true);
|
|
||||||
surface.Attach(CorsairDeviceProvider.Instance.Devices);
|
|
||||||
```
|
|
||||||
The `Initialize`-method allows to load only devices of specific types by setting a filter and for debugging purposes allows to enable exception throwing. (By default they are catched and provided through the `Exception`-event.)
|
|
||||||
You can also use the `Load`-Extension on the surface.
|
|
||||||
```csharp
|
|
||||||
surface.Load(CorsairDeviceProvider.Instance);
|
|
||||||
```
|
|
||||||
> While most device-providers are implemented in a way that supports fast loading like this some may have a different loading procedures. (For example the `WS281XDeviceProvider` requires device-definitions before loading.)
|
|
||||||
|
|
||||||
5. Add an update-trigger. In most cases the TimerUpdateTrigger is preferable, but you can also implement your own to fit your needs.
|
Since there aren't any release-packages right now you'll have to use the CI-feed from [http://nuget.arge.be](http://nuget.arge.be).
|
||||||
```csharp
|
You can include it either by adding ```http://nuget.arge.be/v3/index.json``` to your Visual Studio package sources or by adding this [NuGet.Config](https://github.com/DarthAffe/RGB.NET/tree/master/Documentation/NuGet.Config) to your project (at the same level as your solution).
|
||||||
surface.RegisterUpdateTrigger(new TimerUpdateTrigger());
|
|
||||||
```
|
|
||||||
> If you want to trigger updates manually the `ManualUpdateTrigger` should be used.
|
|
||||||
|
|
||||||
6. *This step is optional but recommended.* For rendering the location of each LED on the surface can be important. Since not all SDKs provide useful layout-information you might want to add Layouts to your devices. (TODO: add wiki article for this)
|
### .NET 4.5 Support ###
|
||||||
Same goes for the location of the device on the surface. If you don't care about the exact location of the devices you can use:
|
At the end of the year with the release of .NET 5 the support for old .NET-Framwork versions will be droppped!
|
||||||
```csharp
|
It's not recommended to use RGB.NET in projects targeting .NET 4.x that aren't planned to be moved to Core/.NET 5 in the future.
|
||||||
surface.AlignDevices();
|
|
||||||
```
|
|
||||||
|
|
||||||
The basic setup is now complete and you can start setting up your rendering.
|
|
||||||
|
|
||||||
### Basic Rendering
|
### Device-Layouts
|
||||||
As an example we'll add a moving rainbow over all devices on the surface.
|
To be able to have devices with correct LED-locations and sizes they need to be layouted. Pre-created layouts can be found at https://github.com/DarthAffe/RGB.NET-Resources.
|
||||||
1. Create a led-group containing all leds on the surface (all devices)
|
|
||||||
```csharp
|
|
||||||
ILedGroup allLeds = new ListLedGroup(surface, surface.Leds);
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Create a rainbow-gradient.
|
If you plan to create layouts for your own devices check out https://github.com/DarthAffe/RGB.NET/wiki/Creating-Layouts first. There's also a layout-editor which strongly simplifies most of the work: https://github.com/SpoinkyNL/RGB.NET-Layout-Editor
|
||||||
```csharp
|
|
||||||
RainbowGradient rainbow = new RainbowGradient();
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Add a decorator to the gradient to make it move. (Decorators are
|
### Example usage of RGB.NET
|
||||||
```csharp
|
[](http://www.youtube.com/watch?v=JLRa0Wv4qso)
|
||||||
rainbow.AddDecorator(new MoveGradientDecorator(surface));
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Create a texture (the size - in this example 10, 10 - is not important here since the gradient shoukd be stretched anyway)
|
#### Example Projects
|
||||||
```csharp
|
[https://github.com/DarthAffe/KeyboardAudioVisualizer](https://github.com/DarthAffe/KeyboardAudioVisualizer)
|
||||||
ITexture texture = new ConicalGradientTexture(new Size(10, 10), rainbow);
|
[https://github.com/DarthAffe/RGBSyncPlus](https://github.com/DarthAffe/RGBSyncPlus)
|
||||||
```
|
|
||||||
|
|
||||||
5. Add a brush rendering the texture to the led-group
|
|
||||||
```csharp
|
|
||||||
allLeds.Brush = new TextureBrush(texture);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Full example
|
|
||||||
```csharp
|
|
||||||
RGBSurface surface = new RGBSurface();
|
|
||||||
surface.Load(CorsairDeviceProvider.Instance);
|
|
||||||
surface.AlignDevices();
|
|
||||||
|
|
||||||
surface.RegisterUpdateTrigger(new TimerUpdateTrigger());
|
|
||||||
|
|
||||||
ILedGroup allLeds = new ListLedGroup(surface, surface.Leds);
|
|
||||||
RainbowGradient rainbow = new RainbowGradient();
|
|
||||||
rainbow.AddDecorator(new MoveGradientDecorator(surface));
|
|
||||||
ITexture texture = new ConicalGradientTexture(new Size(10, 10), rainbow);
|
|
||||||
allLeds.Brush = new TextureBrush(texture);
|
|
||||||
```
|
|
||||||
|
|||||||
119
RGB.NET.Brushes/Brushes/ConicalGradientBrush.cs
Normal file
119
RGB.NET.Brushes/Brushes/ConicalGradientBrush.cs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable MemberCanBeProtected.Global
|
||||||
|
// ReSharper disable ReturnTypeCanBeEnumerable.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
// ReSharper disable UnusedMember.Global
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using RGB.NET.Brushes.Gradients;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="AbstractBrush" />
|
||||||
|
/// <inheritdoc cref="IGradientBrush" />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a brush drawing a conical gradient.
|
||||||
|
/// </summary>
|
||||||
|
public class ConicalGradientBrush : AbstractBrush, IGradientBrush
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private float _origin = (float)Math.Atan2(-1, 0);
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the origin (radian-angle) this <see cref="ConicalGradientBrush"/> is drawn to. (default: -π/2)
|
||||||
|
/// </summary>
|
||||||
|
public float Origin
|
||||||
|
{
|
||||||
|
get => _origin;
|
||||||
|
set => SetProperty(ref _origin, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point _center = new Point(0.5, 0.5);
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the center <see cref="Point"/> (as percentage in the range [0..1]) of the <see cref="IGradient"/> drawn by this <see cref="ConicalGradientBrush"/>. (default: 0.5, 0.5)
|
||||||
|
/// </summary>
|
||||||
|
public Point Center
|
||||||
|
{
|
||||||
|
get => _center;
|
||||||
|
set => SetProperty(ref _center, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IGradient _gradient;
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the gradient drawn by the brush. If null it will default to full transparent.
|
||||||
|
/// </summary>
|
||||||
|
public IGradient Gradient
|
||||||
|
{
|
||||||
|
get => _gradient;
|
||||||
|
set => SetProperty(ref _gradient, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.ConicalGradientBrush" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public ConicalGradientBrush()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.ConicalGradientBrush" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gradient">The <see cref="T:RGB.NET.Brushes.Gradients.IGradient" /> drawn by this <see cref="T:RGB.NET.Brushes.ConicalGradientBrush" />.</param>
|
||||||
|
public ConicalGradientBrush(IGradient gradient)
|
||||||
|
{
|
||||||
|
this.Gradient = gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.ConicalGradientBrush" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="center">The center <see cref="T:RGB.NET.Core.Point" /> (as percentage in the range [0..1]).</param>
|
||||||
|
/// <param name="gradient">The <see cref="T:RGB.NET.Brushes.Gradients.IGradient" /> drawn by this <see cref="T:RGB.NET.Brushes.ConicalGradientBrush" />.</param>
|
||||||
|
public ConicalGradientBrush(Point center, IGradient gradient)
|
||||||
|
{
|
||||||
|
this.Center = center;
|
||||||
|
this.Gradient = gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.ConicalGradientBrush" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="center">The center <see cref="T:RGB.NET.Core.Point" /> (as percentage in the range [0..1]).</param>
|
||||||
|
/// <param name="origin">The origin (radian-angle) the <see cref="T:RGB.NET.Core.IBrush" /> is drawn to.</param>
|
||||||
|
/// <param name="gradient">The <see cref="T:RGB.NET.Brushes.Gradients.IGradient" /> drawn by this <see cref="T:RGB.NET.Brushes.ConicalGradientBrush" />.</param>
|
||||||
|
public ConicalGradientBrush(Point center, float origin, IGradient gradient)
|
||||||
|
{
|
||||||
|
this.Center = center;
|
||||||
|
this.Origin = origin;
|
||||||
|
this.Gradient = gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override Color GetColorAtPoint(Rectangle rectangle, BrushRenderTarget renderTarget)
|
||||||
|
{
|
||||||
|
double centerX = rectangle.Size.Width * Center.X;
|
||||||
|
double centerY = rectangle.Size.Height * Center.Y;
|
||||||
|
|
||||||
|
double angle = Math.Atan2(renderTarget.Point.Y - centerY, renderTarget.Point.X - centerX) - Origin;
|
||||||
|
if (angle < 0) angle += Math.PI * 2;
|
||||||
|
double offset = angle / (Math.PI * 2);
|
||||||
|
|
||||||
|
return Gradient.GetColor(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
17
RGB.NET.Brushes/Brushes/IGradientBrush.cs
Normal file
17
RGB.NET.Brushes/Brushes/IGradientBrush.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using RGB.NET.Brushes.Gradients;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a basic gradient-brush.
|
||||||
|
/// </summary>
|
||||||
|
public interface IGradientBrush : IBrush
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="IGradient"/> used by this <see cref="IGradientBrush"/>.
|
||||||
|
/// </summary>
|
||||||
|
IGradient Gradient { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
109
RGB.NET.Brushes/Brushes/LinearGradientBrush.cs
Normal file
109
RGB.NET.Brushes/Brushes/LinearGradientBrush.cs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// ReSharper disable CollectionNeverUpdated.Global
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable MemberCanBeProtected.Global
|
||||||
|
// ReSharper disable ReturnTypeCanBeEnumerable.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
// ReSharper disable UnusedMember.Global
|
||||||
|
|
||||||
|
using RGB.NET.Brushes.Gradients;
|
||||||
|
using RGB.NET.Brushes.Helper;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="AbstractBrush" />
|
||||||
|
/// <inheritdoc cref="IGradientBrush" />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a brush drawing a linear gradient.
|
||||||
|
/// </summary>
|
||||||
|
public class LinearGradientBrush : AbstractBrush, IGradientBrush
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private Point _startPoint = new Point(0, 0.5);
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the start <see cref="Point"/> (as percentage in the range [0..1]) of the <see cref="IGradient"/> drawn by this <see cref="LinearGradientBrush"/>. (default: 0.0, 0.5)
|
||||||
|
/// </summary>
|
||||||
|
public Point StartPoint
|
||||||
|
{
|
||||||
|
get => _startPoint;
|
||||||
|
set => SetProperty(ref _startPoint, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point _endPoint = new Point(1, 0.5);
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the end <see cref="Point"/> (as percentage in the range [0..1]) of the <see cref="IGradient"/> drawn by this <see cref="LinearGradientBrush"/>. (default: 1.0, 0.5)
|
||||||
|
/// </summary>
|
||||||
|
public Point EndPoint
|
||||||
|
{
|
||||||
|
get => _endPoint;
|
||||||
|
set => SetProperty(ref _endPoint, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IGradient _gradient;
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IGradient Gradient
|
||||||
|
{
|
||||||
|
get => _gradient;
|
||||||
|
set => SetProperty(ref _gradient, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.LinearGradientBrush" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public LinearGradientBrush()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.LinearGradientBrush" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gradient">The <see cref="T:RGB.NET.Brushes.Gradients.IGradient" /> drawn by this <see cref="T:RGB.NET.Brushes.LinearGradientBrush" />.</param>
|
||||||
|
public LinearGradientBrush(IGradient gradient)
|
||||||
|
{
|
||||||
|
this.Gradient = gradient;
|
||||||
|
}
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.LinearGradientBrush" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startPoint">The start <see cref="T:RGB.NET.Core.Point" /> (as percentage in the range [0..1]).</param>
|
||||||
|
/// <param name="endPoint">The end <see cref="T:RGB.NET.Core.Point" /> (as percentage in the range [0..1]).</param>
|
||||||
|
/// <param name="gradient">The <see cref="T:RGB.NET.Brushes.Gradients.IGradient" /> drawn by this <see cref="T:RGB.NET.Brushes.LinearGradientBrush" />.</param>
|
||||||
|
public LinearGradientBrush(Point startPoint, Point endPoint, IGradient gradient)
|
||||||
|
{
|
||||||
|
this.StartPoint = startPoint;
|
||||||
|
this.EndPoint = endPoint;
|
||||||
|
this.Gradient = gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
|
||||||
|
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
|
||||||
|
/// <returns>The color at the specified point.</returns>
|
||||||
|
protected override Color GetColorAtPoint(Rectangle rectangle, BrushRenderTarget renderTarget)
|
||||||
|
{
|
||||||
|
if (Gradient == null) return Color.Transparent;
|
||||||
|
|
||||||
|
Point startPoint = new Point(StartPoint.X * rectangle.Size.Width, StartPoint.Y * rectangle.Size.Height);
|
||||||
|
Point endPoint = new Point(EndPoint.X * rectangle.Size.Width, EndPoint.Y * rectangle.Size.Height);
|
||||||
|
|
||||||
|
double offset = GradientHelper.CalculateLinearGradientOffset(startPoint, endPoint, renderTarget.Point);
|
||||||
|
return Gradient.GetColor(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
97
RGB.NET.Brushes/Brushes/RadialGradientBrush.cs
Normal file
97
RGB.NET.Brushes/Brushes/RadialGradientBrush.cs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
// ReSharper disable UnusedMember.Global
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using RGB.NET.Brushes.Gradients;
|
||||||
|
using RGB.NET.Brushes.Helper;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="AbstractBrush" />
|
||||||
|
/// <inheritdoc cref="IGradientBrush" />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a brush drawing a radial gradient around a center point.
|
||||||
|
/// </summary>
|
||||||
|
public class RadialGradientBrush : AbstractBrush, IGradientBrush
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private Point _center = new Point(0.5, 0.5);
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the center <see cref="Point"/> (as percentage in the range [0..1]) around which the <see cref="RadialGradientBrush"/> should be drawn. (default: 0.5, 0.5)
|
||||||
|
/// </summary>
|
||||||
|
public Point Center
|
||||||
|
{
|
||||||
|
get => _center;
|
||||||
|
set => SetProperty(ref _center, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IGradient _gradient;
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IGradient Gradient
|
||||||
|
{
|
||||||
|
get => _gradient;
|
||||||
|
set => SetProperty(ref _gradient, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.RadialGradientBrush" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public RadialGradientBrush()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.RadialGradientBrush" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gradient">The gradient drawn by the brush.</param>
|
||||||
|
public RadialGradientBrush(IGradient gradient)
|
||||||
|
{
|
||||||
|
this.Gradient = gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.RadialGradientBrush" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="center">The center point (as percentage in the range [0..1]).</param>
|
||||||
|
/// <param name="gradient">The gradient drawn by the brush.</param>
|
||||||
|
public RadialGradientBrush(Point center, IGradient gradient)
|
||||||
|
{
|
||||||
|
this.Center = center;
|
||||||
|
this.Gradient = gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override Color GetColorAtPoint(Rectangle rectangle, BrushRenderTarget renderTarget)
|
||||||
|
{
|
||||||
|
if (Gradient == null) return Color.Transparent;
|
||||||
|
|
||||||
|
Point centerPoint = new Point(rectangle.Location.X + (rectangle.Size.Width * Center.X), rectangle.Location.Y + (rectangle.Size.Height * Center.Y));
|
||||||
|
|
||||||
|
// Calculate the distance to the farthest point from the center as reference (this has to be a corner)
|
||||||
|
// ReSharper disable once RedundantCast - never trust this ...
|
||||||
|
double refDistance = Math.Max(Math.Max(Math.Max(GradientHelper.CalculateDistance(rectangle.Location, centerPoint),
|
||||||
|
GradientHelper.CalculateDistance(new Point(rectangle.Location.X + rectangle.Size.Width, rectangle.Location.Y), centerPoint)),
|
||||||
|
GradientHelper.CalculateDistance(new Point(rectangle.Location.X, rectangle.Location.Y + rectangle.Size.Height), centerPoint)),
|
||||||
|
GradientHelper.CalculateDistance(new Point(rectangle.Location.X + rectangle.Size.Width, rectangle.Location.Y + rectangle.Size.Height), centerPoint));
|
||||||
|
|
||||||
|
double distance = GradientHelper.CalculateDistance(renderTarget.Point, centerPoint);
|
||||||
|
double offset = distance / refDistance;
|
||||||
|
return Gradient.GetColor(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
65
RGB.NET.Brushes/Brushes/SolidColorBrush.cs
Normal file
65
RGB.NET.Brushes/Brushes/SolidColorBrush.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a brush drawing only a single color.
|
||||||
|
/// </summary>
|
||||||
|
public class SolidColorBrush : AbstractBrush
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private Color _color;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="Color"/> drawn by this <see cref="SolidColorBrush"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Color Color
|
||||||
|
{
|
||||||
|
get => _color;
|
||||||
|
set => SetProperty(ref _color, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.SolidColorBrush" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="P:RGB.NET.Brushes.SolidColorBrush.Color" /> drawn by this <see cref="T:RGB.NET.Brushes.SolidColorBrush" />.</param>
|
||||||
|
public SolidColorBrush(Color color)
|
||||||
|
{
|
||||||
|
this.Color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override Color GetColorAtPoint(Rectangle rectangle, BrushRenderTarget renderTarget) => Color;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Operators
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="Color" /> to a <see cref="SolidColorBrush" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="Color"/> to convert.</param>
|
||||||
|
public static explicit operator SolidColorBrush(Color color) => new SolidColorBrush(color);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="SolidColorBrush" /> to a <see cref="Color" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="brush">The <see cref="Color"/> to convert.</param>
|
||||||
|
public static implicit operator Color(SolidColorBrush brush) => brush.Color;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
11
RGB.NET.Brushes/Decorators/IGradientDecorator.cs
Normal file
11
RGB.NET.Brushes/Decorators/IGradientDecorator.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a basic decorator decorating a <see cref="T:RGB.NET.Brushes.Gradients.IGradient" />.
|
||||||
|
/// </summary>
|
||||||
|
public interface IGradientDecorator : IDecorator
|
||||||
|
{ }
|
||||||
|
}
|
||||||
150
RGB.NET.Brushes/Gradients/AbstractGradient.cs
Normal file
150
RGB.NET.Brushes/Gradients/AbstractGradient.cs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// ReSharper disable MemberCanBeProtected.Global
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes.Gradients
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="AbstractDecoratable{T}" />
|
||||||
|
/// <inheritdoc cref="IGradient" />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a basic gradient.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class AbstractGradient : AbstractDecoratable<IGradientDecorator>, IGradient
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of the stops used by this <see cref="AbstractGradient"/>.
|
||||||
|
/// </summary>
|
||||||
|
public ObservableCollection<GradientStop> GradientStops { get; } = new ObservableCollection<GradientStop>();
|
||||||
|
|
||||||
|
private bool _wrapGradient;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets if the Gradient wraps around if there isn't a second stop to take.
|
||||||
|
/// Example: There is a stop at offset 0.0, 0.5 and 0.75.
|
||||||
|
/// Without wrapping offset 1.0 will be calculated the same as 0.75; with wrapping it would be the same as 0.0.
|
||||||
|
/// </summary>
|
||||||
|
public bool WrapGradient
|
||||||
|
{
|
||||||
|
get => _wrapGradient;
|
||||||
|
set => SetProperty(ref _wrapGradient, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event EventHandler GradientChanged;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AbstractGradient"/> class.
|
||||||
|
/// </summary>
|
||||||
|
protected AbstractGradient()
|
||||||
|
{
|
||||||
|
GradientStops.CollectionChanged += GradientCollectionChanged;
|
||||||
|
PropertyChanged += (sender, args) => OnGradientChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AbstractGradient"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gradientStops">The stops with which the gradient should be initialized.</param>
|
||||||
|
protected AbstractGradient(params GradientStop[] gradientStops)
|
||||||
|
{
|
||||||
|
GradientStops.CollectionChanged += GradientCollectionChanged;
|
||||||
|
PropertyChanged += (sender, args) => OnGradientChanged();
|
||||||
|
|
||||||
|
foreach (GradientStop gradientStop in gradientStops)
|
||||||
|
GradientStops.Add(gradientStop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AbstractGradient"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="wrapGradient">Specifies whether the gradient should wrapp or not (see <see cref="WrapGradient"/> for an example of what this means).</param>
|
||||||
|
/// <param name="gradientStops">The stops with which the gradient should be initialized.</param>
|
||||||
|
protected AbstractGradient(bool wrapGradient, params GradientStop[] gradientStops)
|
||||||
|
{
|
||||||
|
this.WrapGradient = wrapGradient;
|
||||||
|
|
||||||
|
GradientStops.CollectionChanged += GradientCollectionChanged;
|
||||||
|
PropertyChanged += (sender, args) => OnGradientChanged();
|
||||||
|
|
||||||
|
foreach (GradientStop gradientStop in gradientStops)
|
||||||
|
GradientStops.Add(gradientStop);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clips the offset and ensures, that it is inside the bounds of the stop list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected double ClipOffset(double offset)
|
||||||
|
{
|
||||||
|
double max = GradientStops.Max(n => n.Offset);
|
||||||
|
if (offset > max)
|
||||||
|
return max;
|
||||||
|
|
||||||
|
double min = GradientStops.Min(n => n.Offset);
|
||||||
|
return offset < min ? min : offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public abstract Color GetColor(double offset);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void Move(double offset)
|
||||||
|
{
|
||||||
|
offset /= 360.0;
|
||||||
|
|
||||||
|
foreach (GradientStop gradientStop in GradientStops)
|
||||||
|
gradientStop.Offset += offset;
|
||||||
|
|
||||||
|
while (GradientStops.All(x => x.Offset > 1))
|
||||||
|
foreach (GradientStop gradientStop in GradientStops)
|
||||||
|
gradientStop.Offset -= 1;
|
||||||
|
|
||||||
|
while (GradientStops.All(x => x.Offset < 0))
|
||||||
|
foreach (GradientStop gradientStop in GradientStops)
|
||||||
|
gradientStop.Offset += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should be called to indicate that the gradient was changed.
|
||||||
|
/// </summary>
|
||||||
|
protected void OnGradientChanged() => GradientChanged?.Invoke(this, null);
|
||||||
|
|
||||||
|
private void GradientCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.OldItems != null)
|
||||||
|
foreach (GradientStop gradientStop in e.OldItems)
|
||||||
|
gradientStop.PropertyChanged -= GradientStopChanged;
|
||||||
|
|
||||||
|
if (e.NewItems != null)
|
||||||
|
foreach (GradientStop gradientStop in e.NewItems)
|
||||||
|
gradientStop.PropertyChanged += GradientStopChanged;
|
||||||
|
|
||||||
|
OnGradientChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GradientStopChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) => OnGradientChanged();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
52
RGB.NET.Brushes/Gradients/GradientStop.cs
Normal file
52
RGB.NET.Brushes/Gradients/GradientStop.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes.Gradients
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a stop on a gradient.
|
||||||
|
/// </summary>
|
||||||
|
public class GradientStop : AbstractBindable
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private double _offset;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the percentage offset to place this <see cref="GradientStop"/>. This should be inside the range of [0..1] but it's not necessary.
|
||||||
|
/// </summary>
|
||||||
|
public double Offset
|
||||||
|
{
|
||||||
|
get => _offset;
|
||||||
|
set => SetProperty(ref _offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _color;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="Color"/> of this <see cref="GradientStop"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Color Color
|
||||||
|
{
|
||||||
|
get => _color;
|
||||||
|
set => SetProperty(ref _color, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GradientStop"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">The percentage offset to place this <see cref="GradientStop"/>.</param>
|
||||||
|
/// <param name="color">The <see cref="Color"/> of the <see cref="GradientStop"/>.</param>
|
||||||
|
public GradientStop(double offset, Color color)
|
||||||
|
{
|
||||||
|
this.Offset = offset;
|
||||||
|
this.Color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
30
RGB.NET.Brushes/Gradients/IGradient.cs
Normal file
30
RGB.NET.Brushes/Gradients/IGradient.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes.Gradients
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a basic gradient.
|
||||||
|
/// </summary>
|
||||||
|
public interface IGradient : IDecoratable<IGradientDecorator>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs if the <see cref="IGradient"/> is changed.
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler GradientChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Color"/> of the <see cref="IGradient"/> on the specified offset.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">The percentage offset to take the <see cref="Color"/> from.</param>
|
||||||
|
/// <returns>The <see cref="Color"/> at the specific offset.</returns>
|
||||||
|
Color GetColor(double offset);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Moves the <see cref="IGradient"/> by the provided offset.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">The offset the <see cref="IGradient"/> should be moved.</param>
|
||||||
|
void Move(double offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
152
RGB.NET.Brushes/Gradients/LinearGradient.cs
Normal file
152
RGB.NET.Brushes/Gradients/LinearGradient.cs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
// ReSharper disable UnusedMember.Global
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes.Gradients
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a linear interpolated gradient with n stops.
|
||||||
|
/// </summary>
|
||||||
|
public class LinearGradient : AbstractGradient
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private bool _isOrderedGradientListDirty = true;
|
||||||
|
private LinkedList<GradientStop> _orderedGradientStops;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.Gradients.LinearGradient" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public LinearGradient()
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.Gradients.LinearGradient" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gradientStops">The stops with which the gradient should be initialized.</param>
|
||||||
|
public LinearGradient(params GradientStop[] gradientStops)
|
||||||
|
: base(gradientStops)
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Brushes.Gradients.AbstractGradient" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="wrapGradient">Specifies whether the gradient should wrapp or not (see <see cref="P:RGB.NET.Brushes.Gradients.AbstractGradient.WrapGradient" /> for an example of what this means).</param>
|
||||||
|
/// <param name="gradientStops">The stops with which the gradient should be initialized.</param>
|
||||||
|
public LinearGradient(bool wrapGradient, params GradientStop[] gradientStops)
|
||||||
|
: base(wrapGradient, gradientStops)
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
private void Initialize()
|
||||||
|
{
|
||||||
|
void OnGradientStopOnPropertyChanged(object sender, PropertyChangedEventArgs args) => _isOrderedGradientListDirty = true;
|
||||||
|
|
||||||
|
foreach (GradientStop gradientStop in GradientStops)
|
||||||
|
gradientStop.PropertyChanged += OnGradientStopOnPropertyChanged;
|
||||||
|
|
||||||
|
GradientStops.CollectionChanged += (sender, args) =>
|
||||||
|
{
|
||||||
|
if (args.OldItems != null)
|
||||||
|
foreach (GradientStop gradientStop in args.OldItems)
|
||||||
|
gradientStop.PropertyChanged -= OnGradientStopOnPropertyChanged;
|
||||||
|
|
||||||
|
if (args.NewItems != null)
|
||||||
|
foreach (GradientStop gradientStop in args.NewItems)
|
||||||
|
gradientStop.PropertyChanged += OnGradientStopOnPropertyChanged;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the linear interpolated <see cref="T:RGB.NET.Core.Color" /> at the given offset.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">The percentage offset to take the color from.</param>
|
||||||
|
/// <returns>The <see cref="T:RGB.NET.Core.Color" /> at the specific offset.</returns>
|
||||||
|
public override Color GetColor(double offset)
|
||||||
|
{
|
||||||
|
if (GradientStops.Count == 0) return Color.Transparent;
|
||||||
|
if (GradientStops.Count == 1) return GradientStops[0].Color;
|
||||||
|
|
||||||
|
if (_isOrderedGradientListDirty)
|
||||||
|
_orderedGradientStops = new LinkedList<GradientStop>(GradientStops.OrderBy(x => x.Offset));
|
||||||
|
|
||||||
|
(GradientStop gsBefore, GradientStop gsAfter) = GetEnclosingGradientStops(offset, _orderedGradientStops, WrapGradient);
|
||||||
|
|
||||||
|
double blendFactor = 0;
|
||||||
|
if (!gsBefore.Offset.Equals(gsAfter.Offset))
|
||||||
|
blendFactor = ((offset - gsBefore.Offset) / (gsAfter.Offset - gsBefore.Offset));
|
||||||
|
|
||||||
|
double colA = ((gsAfter.Color.A - gsBefore.Color.A) * blendFactor) + gsBefore.Color.A;
|
||||||
|
double colR = ((gsAfter.Color.R - gsBefore.Color.R) * blendFactor) + gsBefore.Color.R;
|
||||||
|
double colG = ((gsAfter.Color.G - gsBefore.Color.G) * blendFactor) + gsBefore.Color.G;
|
||||||
|
double colB = ((gsAfter.Color.B - gsBefore.Color.B) * blendFactor) + gsBefore.Color.B;
|
||||||
|
|
||||||
|
return new Color(colA, colR, colG, colB);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the two <see cref="GradientStop"/>s encapsulating the given offset.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">The reference offset.</param>
|
||||||
|
/// <param name="orderedStops">The ordered list of <see cref="GradientStop"/> to choose from.</param>
|
||||||
|
/// <param name="wrap">Bool indicating if the gradient should be wrapped or not.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected virtual (GradientStop gsBefore, GradientStop gsAfter) GetEnclosingGradientStops(double offset, LinkedList<GradientStop> orderedStops, bool wrap)
|
||||||
|
{
|
||||||
|
LinkedList<GradientStop> gradientStops = new LinkedList<GradientStop>(orderedStops);
|
||||||
|
|
||||||
|
if (wrap)
|
||||||
|
{
|
||||||
|
GradientStop gsBefore, gsAfter;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
gsBefore = gradientStops.LastOrDefault(n => n.Offset <= offset);
|
||||||
|
if (gsBefore == null)
|
||||||
|
{
|
||||||
|
GradientStop lastStop = gradientStops.Last.Value;
|
||||||
|
gradientStops.AddFirst(new GradientStop(lastStop.Offset - 1, lastStop.Color));
|
||||||
|
gradientStops.RemoveLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
gsAfter = gradientStops.FirstOrDefault(n => n.Offset >= offset);
|
||||||
|
if (gsAfter == null)
|
||||||
|
{
|
||||||
|
GradientStop firstStop = gradientStops.First.Value;
|
||||||
|
gradientStops.AddLast(new GradientStop(firstStop.Offset + 1, firstStop.Color));
|
||||||
|
gradientStops.RemoveFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
} while ((gsBefore == null) || (gsAfter == null));
|
||||||
|
|
||||||
|
return (gsBefore, gsAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = ClipOffset(offset);
|
||||||
|
return (gradientStops.Last(n => n.Offset <= offset), gradientStops.First(n => n.Offset >= offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
108
RGB.NET.Brushes/Gradients/RainbowGradient.cs
Normal file
108
RGB.NET.Brushes/Gradients/RainbowGradient.cs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes.Gradients
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="AbstractDecoratable{T}" />
|
||||||
|
/// <inheritdoc cref="IGradient" />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a rainbow gradient which circles through all colors of the HUE-color-space.<br />
|
||||||
|
/// See <see href="http://upload.wikimedia.org/wikipedia/commons/a/ad/HueScale.svg" /> as reference.
|
||||||
|
/// </summary>
|
||||||
|
public class RainbowGradient : AbstractDecoratable<IGradientDecorator>, IGradient
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private double _startHue;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the hue (in degrees) to start from.
|
||||||
|
/// </summary>
|
||||||
|
public double StartHue
|
||||||
|
{
|
||||||
|
get => _startHue;
|
||||||
|
set => SetProperty(ref _startHue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double _endHue;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the hue (in degrees) to end the with.
|
||||||
|
/// </summary>
|
||||||
|
public double EndHue
|
||||||
|
{
|
||||||
|
get => _endHue;
|
||||||
|
set => SetProperty(ref _endHue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event EventHandler GradientChanged;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RainbowGradient"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startHue">The hue (in degrees) to start from (default: 0)</param>
|
||||||
|
/// <param name="endHue">The hue (in degrees) to end with (default: 360)</param>
|
||||||
|
public RainbowGradient(double startHue = 0, double endHue = 360)
|
||||||
|
{
|
||||||
|
this.StartHue = startHue;
|
||||||
|
this.EndHue = endHue;
|
||||||
|
|
||||||
|
PropertyChanged += (sender, args) => OnGradientChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the color on the rainbow at the given offset.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">The percentage offset to take the color from.</param>
|
||||||
|
/// <returns>The color at the specific offset.</returns>
|
||||||
|
public Color GetColor(double offset)
|
||||||
|
{
|
||||||
|
double range = EndHue - StartHue;
|
||||||
|
double hue = StartHue + (range * offset);
|
||||||
|
return HSVColor.Create(hue, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Move(double offset)
|
||||||
|
{
|
||||||
|
// RainbowGradient is calculated inverse
|
||||||
|
offset *= -1;
|
||||||
|
|
||||||
|
StartHue += offset;
|
||||||
|
EndHue += offset;
|
||||||
|
|
||||||
|
while ((StartHue > 360) && (EndHue > 360))
|
||||||
|
{
|
||||||
|
StartHue -= 360;
|
||||||
|
EndHue -= 360;
|
||||||
|
}
|
||||||
|
while ((StartHue < -360) && (EndHue < -360))
|
||||||
|
{
|
||||||
|
StartHue += 360;
|
||||||
|
EndHue += 360;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should be called to indicate that the gradient was changed.
|
||||||
|
/// </summary>
|
||||||
|
protected void OnGradientChanged() => GradientChanged?.Invoke(this, null);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
81
RGB.NET.Brushes/Helper/GradientHelper.cs
Normal file
81
RGB.NET.Brushes/Helper/GradientHelper.cs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
namespace RGB.NET.Brushes.Helper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Offers some extensions and helper-methods for gradient related things.
|
||||||
|
/// </summary>
|
||||||
|
public static class GradientHelper
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
// Based on https://web.archive.org/web/20170125201230/https://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the offset of an given <see cref="Point"/> on an gradient.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startPoint">The start <see cref="Point"/> of the gradient.</param>
|
||||||
|
/// <param name="endPoint">The end <see cref="Point"/> of the gradient.</param>
|
||||||
|
/// <param name="point">The <see cref="Point"/> on the gradient to which the offset is calculated.</param>
|
||||||
|
/// <returns>The offset of the <see cref="Point"/> on the gradient.</returns>
|
||||||
|
public static double CalculateLinearGradientOffset(Point startPoint, Point endPoint, Point point)
|
||||||
|
{
|
||||||
|
Point intersectingPoint;
|
||||||
|
if (startPoint.Y.Equals(endPoint.Y)) // Horizontal case
|
||||||
|
intersectingPoint = new Point(point.X, startPoint.Y);
|
||||||
|
|
||||||
|
else if (startPoint.X.Equals(endPoint.X)) // Vertical case
|
||||||
|
intersectingPoint = new Point(startPoint.X, point.Y);
|
||||||
|
|
||||||
|
else // Diagonal case
|
||||||
|
{
|
||||||
|
double slope = (endPoint.Y - startPoint.Y) / (endPoint.X - startPoint.X);
|
||||||
|
double orthogonalSlope = -1 / slope;
|
||||||
|
|
||||||
|
double startYIntercept = startPoint.Y - (slope * startPoint.X);
|
||||||
|
double pointYIntercept = point.Y - (orthogonalSlope * point.X);
|
||||||
|
|
||||||
|
double intersectingPointX = (pointYIntercept - startYIntercept) / (slope - orthogonalSlope);
|
||||||
|
double intersectingPointY = (slope * intersectingPointX) + startYIntercept;
|
||||||
|
intersectingPoint = new Point(intersectingPointX, intersectingPointY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate distances relative to the vector start
|
||||||
|
double intersectDistance = CalculateDistance(intersectingPoint, startPoint, endPoint);
|
||||||
|
double gradientLength = CalculateDistance(endPoint, startPoint, endPoint);
|
||||||
|
|
||||||
|
return intersectDistance / gradientLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on https://web.archive.org/web/20170125201230/https://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the signed magnitude of a <see cref="Point"/> on a vector.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The <see cref="Point"/> on the vector of which the magnitude should be calculated.</param>
|
||||||
|
/// <param name="origin">The origin of the vector.</param>
|
||||||
|
/// <param name="direction">The direction of the vector.</param>
|
||||||
|
/// <returns>The signed magnitude of a <see cref="Point"/> on a vector.</returns>
|
||||||
|
public static double CalculateDistance(Point point, Point origin, Point direction)
|
||||||
|
{
|
||||||
|
double distance = CalculateDistance(point, origin);
|
||||||
|
|
||||||
|
return (((point.Y < origin.Y) && (direction.Y > origin.Y)) ||
|
||||||
|
((point.Y > origin.Y) && (direction.Y < origin.Y)) ||
|
||||||
|
((point.Y.Equals(origin.Y)) && (point.X < origin.X) && (direction.X > origin.X)) ||
|
||||||
|
((point.Y.Equals(origin.Y)) && (point.X > origin.X) && (direction.X < origin.X)))
|
||||||
|
? -distance : distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculated the distance between two <see cref="Point"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point1">The first <see cref="Point"/>.</param>
|
||||||
|
/// <param name="point2">The second <see cref="Point"/>.</param>
|
||||||
|
/// <returns>The distance between the two <see cref="Point"/>.</returns>
|
||||||
|
public static double CalculateDistance(Point point1, Point point2) => Math.Sqrt(((point1.Y - point2.Y) * (point1.Y - point2.Y)) + ((point1.X - point2.X) * (point1.X - point2.X)));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
68
RGB.NET.Brushes/RGB.NET.Brushes.csproj
Normal file
68
RGB.NET.Brushes/RGB.NET.Brushes.csproj
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>netstandard2.0;net45</TargetFrameworks>
|
||||||
|
<RuntimeIdentifiers>win7-x86;win7-x64</RuntimeIdentifiers>
|
||||||
|
|
||||||
|
<Authors>Darth Affe</Authors>
|
||||||
|
<Company>Wyrez</Company>
|
||||||
|
<Language>en-US</Language>
|
||||||
|
<NeutralLanguage>en-US</NeutralLanguage>
|
||||||
|
<Title>RGB.NET.Brushes</Title>
|
||||||
|
<AssemblyName>RGB.NET.Brushes</AssemblyName>
|
||||||
|
<AssemblyTitle>RGB.NET.Brushes</AssemblyTitle>
|
||||||
|
<PackageId>RGB.NET.Brushes</PackageId>
|
||||||
|
<RootNamespace>RGB.NET.Brushes</RootNamespace>
|
||||||
|
<Description>Brushes-Presets of RGB.NET</Description>
|
||||||
|
<Summary>Brushes-Presets of RGB.NET, a C# (.NET) library for accessing various RGB-peripherals</Summary>
|
||||||
|
<Copyright>Copyright © Darth Affe 2020</Copyright>
|
||||||
|
<PackageCopyright>Copyright © Darth Affe 2020</PackageCopyright>
|
||||||
|
<PackageIconUrl>http://lib.arge.be/icon.png</PackageIconUrl>
|
||||||
|
<PackageProjectUrl>https://github.com/DarthAffe/RGB.NET</PackageProjectUrl>
|
||||||
|
<PackageLicenseUrl>https://raw.githubusercontent.com/DarthAffe/RGB.NET/master/LICENSE</PackageLicenseUrl>
|
||||||
|
<RepositoryType>Github</RepositoryType>
|
||||||
|
<RepositoryUrl>https://github.com/DarthAffe/RGB.NET</RepositoryUrl>
|
||||||
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
|
|
||||||
|
<PackageReleaseNotes></PackageReleaseNotes>
|
||||||
|
|
||||||
|
<Version>0.0.1</Version>
|
||||||
|
<AssemblyVersion>0.0.1</AssemblyVersion>
|
||||||
|
<FileVersion>0.0.1</FileVersion>
|
||||||
|
|
||||||
|
<OutputPath>..\bin\</OutputPath>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<IncludeSource>True</IncludeSource>
|
||||||
|
<IncludeSymbols>True</IncludeSymbols>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
||||||
|
<DefineConstants>NETCORE;NETSTANDARD;NETSTANDARD2_0</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(TargetFramework)' == 'net45'">
|
||||||
|
<DefineConstants>NET45;NETFULL</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
|
<DefineConstants>$(DefineConstants);TRACE;DEBUG</DefineConstants>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<NoWarn>$(NoWarn);CS1591;CS1572;CS1573</NoWarn>
|
||||||
|
<DefineConstants>$(DefineConstants);RELEASE</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\RGB.NET.Core\RGB.NET.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
|
||||||
|
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@ -1,3 +1,3 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=picopi/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=brushes/@EntryIndexedValue">True</s:Boolean>
|
||||||
</wpf:ResourceDictionary>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=decorators/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
131
RGB.NET.Core/Brushes/AbstractBrush.cs
Normal file
131
RGB.NET.Core/Brushes/AbstractBrush.cs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// ReSharper disable VirtualMemberNeverOverriden.Global
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable VirtualMemberNeverOverridden.Global
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="AbstractDecoratable{T}" />
|
||||||
|
/// <inheritdoc cref="IBrush" />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a basic brush.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class AbstractBrush : AbstractDecoratable<IBrushDecorator>, IBrush
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsEnabled { get; set; } = true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public BrushCalculationMode BrushCalculationMode { get; set; } = BrushCalculationMode.Relative;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public double Brightness { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public double Opacity { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IList<IColorCorrection> ColorCorrections { get; } = new List<IColorCorrection>();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Rectangle RenderedRectangle { get; protected set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Dictionary<BrushRenderTarget, Color> RenderedTargets { get; } = new Dictionary<BrushRenderTarget, Color>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AbstractBrush"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="brightness">The overall percentage brightness of the brush. (default: 1.0)</param>
|
||||||
|
/// <param name="opacity">The overall percentage opacity of the brush. (default: 1.0)</param>
|
||||||
|
protected AbstractBrush(double brightness = 1, double opacity = 1)
|
||||||
|
{
|
||||||
|
this.Brightness = brightness;
|
||||||
|
this.Opacity = opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void PerformRender(Rectangle rectangle, IEnumerable<BrushRenderTarget> renderTargets)
|
||||||
|
{
|
||||||
|
RenderedRectangle = rectangle;
|
||||||
|
RenderedTargets.Clear();
|
||||||
|
|
||||||
|
foreach (BrushRenderTarget renderTarget in renderTargets)
|
||||||
|
{
|
||||||
|
Color color = GetColorAtPoint(rectangle, renderTarget);
|
||||||
|
color = ApplyDecorators(rectangle, renderTarget, color);
|
||||||
|
RenderedTargets[renderTarget] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies all attached and enabled decorators to the brush.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
|
||||||
|
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
|
||||||
|
/// <param name="color">The <see cref="Color"/> to be modified.</param>
|
||||||
|
protected virtual Color ApplyDecorators(Rectangle rectangle, BrushRenderTarget renderTarget, Color color)
|
||||||
|
{
|
||||||
|
lock (Decorators)
|
||||||
|
foreach (IBrushDecorator decorator in Decorators)
|
||||||
|
if (decorator.IsEnabled)
|
||||||
|
color = decorator.ManipulateColor(rectangle, renderTarget, color);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void PerformFinalize()
|
||||||
|
{
|
||||||
|
List<BrushRenderTarget> renderTargets = RenderedTargets.Keys.ToList();
|
||||||
|
foreach (BrushRenderTarget renderTarget in renderTargets)
|
||||||
|
RenderedTargets[renderTarget] = FinalizeColor(RenderedTargets[renderTarget]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
|
||||||
|
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
|
||||||
|
/// <returns>The color at the specified point.</returns>
|
||||||
|
protected abstract Color GetColorAtPoint(Rectangle rectangle, BrushRenderTarget renderTarget);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finalizes the color by appliing the overall brightness and opacity.<br/>
|
||||||
|
/// This method should always be the last call of a <see cref="GetColorAtPoint" /> implementation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The color to finalize.</param>
|
||||||
|
/// <returns>The finalized color.</returns>
|
||||||
|
protected virtual Color FinalizeColor(Color color)
|
||||||
|
{
|
||||||
|
if (ColorCorrections.Count > 0)
|
||||||
|
foreach (IColorCorrection colorCorrection in ColorCorrections)
|
||||||
|
color = colorCorrection.ApplyTo(color);
|
||||||
|
|
||||||
|
// Since we use HSV to calculate there is no way to make a color 'brighter' than 100%
|
||||||
|
// Be carefull with the naming: Since we use HSV the correct term is 'value' but outside we call it 'brightness'
|
||||||
|
// THIS IS NOT A HSB CALCULATION!!!
|
||||||
|
if (Brightness < 1)
|
||||||
|
color = color.MultiplyHSV(value: Brightness.Clamp(0, 1));
|
||||||
|
|
||||||
|
if (Opacity < 1)
|
||||||
|
color = color.MultiplyA(Opacity.Clamp(0, 1));
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
20
RGB.NET.Core/Brushes/BrushCalculationMode.cs
Normal file
20
RGB.NET.Core/Brushes/BrushCalculationMode.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// ReSharper disable UnusedMember.Global
|
||||||
|
|
||||||
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains a list of all brush calculation modes.
|
||||||
|
/// </summary>
|
||||||
|
public enum BrushCalculationMode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The calculation <see cref="Rectangle"/> for <see cref="IBrush"/> will be the rectangle around the <see cref="ILedGroup"/> the <see cref="IBrush"/> is applied to.
|
||||||
|
/// </summary>
|
||||||
|
Relative,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The calculation <see cref="Rectangle"/> for <see cref="IBrush"/> will always be the rectangle completly containing all affected <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
Absolute
|
||||||
|
}
|
||||||
|
}
|
||||||
47
RGB.NET.Core/Brushes/BrushRenderTarget.cs
Normal file
47
RGB.NET.Core/Brushes/BrushRenderTarget.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
|
||||||
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a single target of a brush render.
|
||||||
|
/// </summary>
|
||||||
|
public class BrushRenderTarget
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the target-<see cref="Core.Led"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Led Led { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Core.Rectangle"/> representing the area to render the target-<see cref="Core.Led"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Rectangle Rectangle { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Core.Point"/> representing the position to render the target-<see cref="Core.Led"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Point Point { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BrushRenderTarget"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="led">The target-<see cref="Core.Led"/>.</param>
|
||||||
|
/// <param name="rectangle">The <see cref="Core.Rectangle"/> representing the area to render the target-<see cref="Core.Led"/>.</param>
|
||||||
|
public BrushRenderTarget(Led led, Rectangle rectangle)
|
||||||
|
{
|
||||||
|
this.Led = led;
|
||||||
|
this.Rectangle = rectangle;
|
||||||
|
|
||||||
|
this.Point = rectangle.Center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
61
RGB.NET.Core/Brushes/IBrush.cs
Normal file
61
RGB.NET.Core/Brushes/IBrush.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// ReSharper disable UnusedMemberInSuper.Global
|
||||||
|
// ReSharper disable UnusedMember.Global
|
||||||
|
// ReSharper disable ReturnTypeCanBeEnumerable.Global
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a basic brush.
|
||||||
|
/// </summary>
|
||||||
|
public interface IBrush : IDecoratable<IBrushDecorator>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets if the <see cref="IBrush"/> is enabled and will be drawn on an update.
|
||||||
|
/// </summary>
|
||||||
|
bool IsEnabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the calculation mode used for the rectangle/points used for color-selection in brushes.
|
||||||
|
/// </summary>
|
||||||
|
BrushCalculationMode BrushCalculationMode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the overall percentage brightness of the <see cref="IBrush"/>.
|
||||||
|
/// </summary>
|
||||||
|
double Brightness { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the overall percentage opacity of the <see cref="IBrush"/>.
|
||||||
|
/// </summary>
|
||||||
|
double Opacity { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of <see cref="IColorCorrection"/> used to correct the colors of the <see cref="IBrush"/>.
|
||||||
|
/// </summary>
|
||||||
|
IList<IColorCorrection> ColorCorrections { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="RenderedRectangle"/> used in the last render pass.
|
||||||
|
/// </summary>
|
||||||
|
Rectangle RenderedRectangle { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a dictionary containing all <see cref="Color"/> for <see cref="BrushRenderTarget"/> calculated in the last render pass.
|
||||||
|
/// </summary>
|
||||||
|
Dictionary<BrushRenderTarget, Color> RenderedTargets { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs the render pass of the <see cref="IBrush"/> and calculates the raw <see cref="Color"/> for all requested <see cref="BrushRenderTarget"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rectangle">The <see cref="Rectangle"/> in which the brush should be drawn.</param>
|
||||||
|
/// <param name="renderTargets">The <see cref="BrushRenderTarget"/> (keys/points) of which the color should be calculated.</param>
|
||||||
|
void PerformRender(Rectangle rectangle, IEnumerable<BrushRenderTarget> renderTargets);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs the finalize pass of the <see cref="IBrush"/> and calculates the final <see cref="ColorCorrections"/> for all previously calculated <see cref="BrushRenderTarget"/>.
|
||||||
|
/// </summary>
|
||||||
|
void PerformFinalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,65 +1,80 @@
|
|||||||
using System;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the default-behavior for the work with colors.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class DefaultColorBehavior : IColorBehavior
|
|
||||||
{
|
{
|
||||||
#region Methods
|
public class DefaultColorBehavior : IColorBehavior
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts the individual byte values of this <see cref="Color"/> to a human-readable string.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A string that contains the individual byte values of this <see cref="Color"/>. For example "[A: 255, R: 255, G: 0, B: 0]".</returns>
|
|
||||||
public string ToString(Color color) => $"[A: {color.GetA()}, R: {color.GetR()}, G: {color.GetG()}, B: {color.GetB()}]";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests whether the specified object is a <see cref="Color" /> and is equivalent to this <see cref="Color" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to test.</param>
|
|
||||||
/// <param name="obj">The object to test.</param>
|
|
||||||
/// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Color" /> equivalent to this <see cref="Color" />; otherwise, <c>false</c>.</returns>
|
|
||||||
public bool Equals(Color color, object? obj) => obj is Color color2 && Equals(color, color2);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests whether the specified object is a <see cref="Color" /> and is equivalent to this <see cref="Color" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The first color to test.</param>
|
|
||||||
/// <param name="color2">The second color to test.</param>
|
|
||||||
/// <returns><c>true</c> if <paramref name="color2" /> equivalent to this <see cref="Color" />; otherwise, <c>false</c>.</returns>
|
|
||||||
public bool Equals(Color color, Color color2) => color.A.EqualsInTolerance(color2.A)
|
|
||||||
&& color.R.EqualsInTolerance(color2.R)
|
|
||||||
&& color.G.EqualsInTolerance(color2.G)
|
|
||||||
&& color.B.EqualsInTolerance(color2.B);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hash code for this <see cref="Color" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>An integer value that specifies the hash code for this <see cref="Color" />.</returns>
|
|
||||||
public int GetHashCode(Color color) => HashCode.Combine(color.A, color.R, color.G, color.B);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Blends a <see cref="Color"/> over this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="baseColor">The <see cref="Color"/> to to blend over.</param>
|
|
||||||
/// <param name="blendColor">The <see cref="Color"/> to blend.</param>
|
|
||||||
public Color Blend(Color baseColor, Color blendColor)
|
|
||||||
{
|
{
|
||||||
if (blendColor.A.EqualsInTolerance(0)) return baseColor;
|
#region Properties & Fields
|
||||||
|
|
||||||
if (blendColor.A.EqualsInTolerance(1))
|
private static DefaultColorBehavior _instance = new DefaultColorBehavior();
|
||||||
return blendColor;
|
/// <summary>
|
||||||
|
/// Gets the singleton instance of <see cref="DefaultColorBehavior"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static DefaultColorBehavior Instance { get; } = _instance;
|
||||||
|
|
||||||
float resultA = (1.0f - ((1.0f - blendColor.A) * (1.0f - baseColor.A)));
|
#endregion
|
||||||
float resultR = (((blendColor.R * blendColor.A) / resultA) + ((baseColor.R * baseColor.A * (1.0f - blendColor.A)) / resultA));
|
|
||||||
float resultG = (((blendColor.G * blendColor.A) / resultA) + ((baseColor.G * baseColor.A * (1.0f - blendColor.A)) / resultA));
|
|
||||||
float resultB = (((blendColor.B * blendColor.A) / resultA) + ((baseColor.B * baseColor.A * (1.0f - blendColor.A)) / resultA));
|
|
||||||
|
|
||||||
return new Color(resultA, resultR, resultG, resultB);
|
#region Constructors
|
||||||
|
|
||||||
|
private DefaultColorBehavior()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the individual byte values of this <see cref="Color"/> to a human-readable string.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A string that contains the individual byte values of this <see cref="Color"/>. For example "[A: 255, R: 255, G: 0, B: 0]".</returns>
|
||||||
|
public virtual string ToString(Color color) => $"[A: {color.GetA()}, R: {color.GetR()}, G: {color.GetG()}, B: {color.GetB()}]";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests whether the specified object is a <see cref="Color" /> and is equivalent to this <see cref="Color" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to test.</param>
|
||||||
|
/// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Color" /> equivalent to this <see cref="Color" />; otherwise, <c>false</c>.</returns>
|
||||||
|
public virtual bool Equals(Color color, object obj)
|
||||||
|
{
|
||||||
|
if (!(obj is Color)) return false;
|
||||||
|
|
||||||
|
(double a, double r, double g, double b) = ((Color)obj).GetRGB();
|
||||||
|
return color.A.EqualsInTolerance(a) && color.R.EqualsInTolerance(r) && color.G.EqualsInTolerance(g) && color.B.EqualsInTolerance(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a hash code for this <see cref="Color" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An integer value that specifies the hash code for this <see cref="Color" />.</returns>
|
||||||
|
public virtual int GetHashCode(Color color)
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
int hashCode = color.A.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ color.R.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ color.G.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ color.B.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Blends a <see cref="Color"/> over this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="Color"/> to blend.</param>
|
||||||
|
public virtual Color Blend(Color baseColor, Color blendColor)
|
||||||
|
{
|
||||||
|
if (blendColor.A.EqualsInTolerance(0)) return baseColor;
|
||||||
|
|
||||||
|
if (blendColor.A.EqualsInTolerance(1))
|
||||||
|
return blendColor;
|
||||||
|
|
||||||
|
double resultA = (1.0 - ((1.0 - blendColor.A) * (1.0 - baseColor.A)));
|
||||||
|
double resultR = (((blendColor.R * blendColor.A) / resultA) + ((baseColor.R * baseColor.A * (1.0 - blendColor.A)) / resultA));
|
||||||
|
double resultG = (((blendColor.G * blendColor.A) / resultA) + ((baseColor.G * baseColor.A * (1.0 - blendColor.A)) / resultA));
|
||||||
|
double resultB = (((blendColor.B * blendColor.A) / resultA) + ((baseColor.B * baseColor.A * (1.0 - blendColor.A)) / resultA));
|
||||||
|
|
||||||
|
return new Color(resultA, resultR, resultG, resultB);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,43 +1,13 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a behavior of a color for base operations.
|
|
||||||
/// </summary>
|
|
||||||
public interface IColorBehavior
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
public interface IColorBehavior
|
||||||
/// Converts the specified <see cref="Color"/> to a string representation.
|
{
|
||||||
/// </summary>
|
string ToString(Color color);
|
||||||
/// <param name="color">The color to convert.</param>
|
|
||||||
/// <returns>The string representation of the specified color.</returns>
|
|
||||||
string ToString(Color color);
|
|
||||||
|
|
||||||
/// <summary>
|
bool Equals(Color color, object obj);
|
||||||
/// Tests whether the specified object is a <see cref="Color" /> and is equivalent to this <see cref="Color" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to test.</param>
|
|
||||||
/// <param name="obj">The object to test.</param>
|
|
||||||
/// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Color" /> equivalent to this <see cref="Color" />; otherwise, <c>false</c>.</returns>
|
|
||||||
bool Equals(Color color, object? obj);
|
|
||||||
|
|
||||||
/// <summary>
|
int GetHashCode(Color color);
|
||||||
/// Tests whether the specified object is a <see cref="Color" /> and is equivalent to this <see cref="Color" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The first color to test.</param>
|
|
||||||
/// <param name="color2">The second color to test.</param>
|
|
||||||
/// <returns><c>true</c> if <paramref name="color2" /> equivalent to this <see cref="Color" />; otherwise, <c>false</c>.</returns>
|
|
||||||
bool Equals(Color color, Color color2);
|
|
||||||
|
|
||||||
/// <summary>
|
Color Blend(Color baseColor, Color blendColor);
|
||||||
/// Returns a hash code for this <see cref="Color" />.
|
}
|
||||||
/// </summary>
|
}
|
||||||
/// <returns>An integer value that specifies the hash code for this <see cref="Color" />.</returns>
|
|
||||||
int GetHashCode(Color color);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Blends a <see cref="Color"/> over this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="baseColor">The <see cref="Color"/> to to blend over.</param>
|
|
||||||
/// <param name="blendColor">The <see cref="Color"/> to blend.</param>
|
|
||||||
Color Blend(Color baseColor, Color blendColor);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -5,286 +5,284 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an ARGB (alpha, red, green, blue) color.
|
|
||||||
/// </summary>
|
|
||||||
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
|
||||||
public readonly struct Color : IEquatable<Color>
|
|
||||||
{
|
{
|
||||||
#region Constants
|
|
||||||
|
|
||||||
private static readonly Color TRANSPARENT = new(0, 0, 0, 0);
|
|
||||||
/// <summary>
|
|
||||||
/// Gets an transparent color [A: 0, R: 0, G: 0, B: 0]
|
|
||||||
/// </summary>
|
|
||||||
public static ref readonly Color Transparent => ref TRANSPARENT;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the <see cref="IColorBehavior"/> used to perform operations on colors.
|
|
||||||
/// </summary>
|
|
||||||
public static IColorBehavior Behavior { get; set; } = new DefaultColorBehavior();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the alpha component value of this <see cref="Color"/> as percentage in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
public readonly float A;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the red component value of this <see cref="Color"/> as percentage in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
public readonly float R;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the green component value of this <see cref="Color"/> as percentage in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
public readonly float G;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the blue component value of this <see cref="Color"/> as percentage in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
public readonly float B;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using RGB-Values.
|
/// Represents an ARGB (alpha, red, green, blue) color.
|
||||||
/// Alpha defaults to 255.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="r">The red component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
/// <param name="g">The green component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
public struct Color
|
||||||
/// <param name="b">The blue component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
|
||||||
public Color(byte r, byte g, byte b)
|
|
||||||
: this(byte.MaxValue, r, g, b)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using RGB-Values.
|
|
||||||
/// Alpha defaults to 255.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="r">The red component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
|
||||||
/// <param name="g">The green component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
|
||||||
/// <param name="b">The blue component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
|
||||||
public Color(int r, int g, int b)
|
|
||||||
: this((byte)r.Clamp(0, byte.MaxValue), (byte)g.Clamp(0, byte.MaxValue), (byte)b.Clamp(0, byte.MaxValue))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
|
||||||
public Color(byte a, byte r, byte g, byte b)
|
|
||||||
: this(a.GetPercentageFromByteValue(), r.GetPercentageFromByteValue(), g.GetPercentageFromByteValue(), b.GetPercentageFromByteValue())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
|
||||||
public Color(int a, int r, int g, int b)
|
|
||||||
: this((byte)a.Clamp(0, byte.MaxValue), (byte)r.Clamp(0, byte.MaxValue), (byte)g.Clamp(0, byte.MaxValue), (byte)b.Clamp(0, byte.MaxValue))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Color"/> struct using RGB-percent values.
|
|
||||||
/// Alpha defaults to 1.0.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
|
||||||
public Color(float r, float g, float b)
|
|
||||||
: this(1.0f, r, g, b)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB-percent values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
|
||||||
public Color(float a, byte r, byte g, byte b)
|
|
||||||
: this(a, r.GetPercentageFromByteValue(), g.GetPercentageFromByteValue(), b.GetPercentageFromByteValue())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB-percent values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
|
||||||
public Color(float a, int r, int g, int b)
|
|
||||||
: this(a, (byte)r.Clamp(0, byte.MaxValue), (byte)g.Clamp(0, byte.MaxValue), (byte)b.Clamp(0, byte.MaxValue))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB-percent values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
|
||||||
public Color(int a, float r, float g, float b)
|
|
||||||
: this((byte)a.Clamp(0, byte.MaxValue), r, g, b)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB-percent values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
|
||||||
public Color(byte a, float r, float g, float b)
|
|
||||||
: this(a.GetPercentageFromByteValue(), r, g, b)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB-percent values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
|
||||||
public Color(float a, float r, float g, float b)
|
|
||||||
{
|
{
|
||||||
A = a.Clamp(0, 1);
|
#region Constants
|
||||||
R = r.Clamp(0, 1);
|
|
||||||
G = g.Clamp(0, 1);
|
/// <summary>
|
||||||
B = b.Clamp(0, 1);
|
/// Gets an transparent color [A: 0, R: 0, G: 0, B: 0]
|
||||||
|
/// </summary>
|
||||||
|
public static Color Transparent => new Color(0, 0, 0, 0);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private static IColorBehavior _behavior = DefaultColorBehavior.Instance;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="IColorBehavior"/> used to perform operations on colors.
|
||||||
|
/// </summary>
|
||||||
|
public static IColorBehavior Behavior
|
||||||
|
{
|
||||||
|
get => _behavior;
|
||||||
|
set => _behavior = value ?? DefaultColorBehavior.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the alpha component value of this <see cref="Color"/> as percentage in the range [0..1].
|
||||||
|
/// </summary>
|
||||||
|
public double A { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the red component value of this <see cref="Color"/> as percentage in the range [0..1].
|
||||||
|
/// </summary>
|
||||||
|
public double R { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the green component value of this <see cref="Color"/> as percentage in the range [0..1].
|
||||||
|
/// </summary>
|
||||||
|
public double G { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the blue component value of this <see cref="Color"/> as percentage in the range [0..1].
|
||||||
|
/// </summary>
|
||||||
|
public double B { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using RGB-Values.
|
||||||
|
/// Alpha defaults to 255.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
||||||
|
/// <param name="g">The green component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
||||||
|
/// <param name="b">The blue component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
||||||
|
public Color(byte r, byte g, byte b)
|
||||||
|
: this(byte.MaxValue, r, g, b)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using RGB-Values.
|
||||||
|
/// Alpha defaults to 255.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
||||||
|
/// <param name="g">The green component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
||||||
|
/// <param name="b">The blue component value of this <see cref="T:RGB.NET.Core.Color" />.</param>
|
||||||
|
public Color(int r, int g, int b)
|
||||||
|
: this((byte)r.Clamp(0, byte.MaxValue), (byte)g.Clamp(0, byte.MaxValue), (byte)b.Clamp(0, byte.MaxValue))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
||||||
|
public Color(byte a, byte r, byte g, byte b)
|
||||||
|
: this(a.GetPercentageFromByteValue(), r.GetPercentageFromByteValue(), g.GetPercentageFromByteValue(), b.GetPercentageFromByteValue())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
||||||
|
public Color(int a, int r, int g, int b)
|
||||||
|
: this((byte)a.Clamp(0, byte.MaxValue), (byte)r.Clamp(0, byte.MaxValue), (byte)g.Clamp(0, byte.MaxValue), (byte)b.Clamp(0, byte.MaxValue))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Color"/> struct using RGB-percent values.
|
||||||
|
/// Alpha defaults to 1.0.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
||||||
|
public Color(double r, double g, double b)
|
||||||
|
: this(1.0, r, g, b)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB-percent values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
||||||
|
public Color(double a, byte r, byte g, byte b)
|
||||||
|
: this(a, r.GetPercentageFromByteValue(), g.GetPercentageFromByteValue(), b.GetPercentageFromByteValue())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB-percent values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
||||||
|
public Color(double a, int r, int g, int b)
|
||||||
|
: this(a, (byte)r.Clamp(0, byte.MaxValue), (byte)g.Clamp(0, byte.MaxValue), (byte)b.Clamp(0, byte.MaxValue))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB-percent values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
||||||
|
public Color(int a, double r, double g, double b)
|
||||||
|
: this((byte)a.Clamp(0, byte.MaxValue), r, g, b)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB-percent values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
||||||
|
public Color(byte a, double r, double g, double b)
|
||||||
|
: this(a.GetPercentageFromByteValue(), r, g, b)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Color"/> struct using ARGB-percent values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="r">The red component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="g">The green component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="b">The blue component value of this <see cref="Color"/>.</param>
|
||||||
|
public Color(double a, double r, double g, double b)
|
||||||
|
{
|
||||||
|
A = a.Clamp(0, 1);
|
||||||
|
R = r.Clamp(0, 1);
|
||||||
|
G = g.Clamp(0, 1);
|
||||||
|
B = b.Clamp(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct by cloning a existing <see cref="T:RGB.NET.Core.Color" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="T:RGB.NET.Core.Color" /> the values are copied from.</param>
|
||||||
|
public Color(Color color)
|
||||||
|
: this(color.A, color.R, color.G, color.B)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a human-readable string, as defined by the current <see cref="Behavior"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A string that contains the individual byte values of this <see cref="Color"/>. Default format: "[A: 255, R: 255, G: 0, B: 0]".</returns>
|
||||||
|
public override string ToString() => Behavior.ToString(this);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests whether the specified object is a <see cref="Color" /> and is equivalent to this <see cref="Color" />, as defined by the current <see cref="Behavior"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to test.</param>
|
||||||
|
/// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Color" /> equivalent to this <see cref="Color" />; otherwise, <c>false</c>.</returns>
|
||||||
|
public override bool Equals(object obj) => Behavior.Equals(this, obj);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a hash code for this <see cref="Color" />, as defined by the current <see cref="Behavior"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An integer value that specifies the hash code for this <see cref="Color" />.</returns>
|
||||||
|
public override int GetHashCode() => Behavior.GetHashCode(this);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Blends a <see cref="Color"/> over this color, as defined by the current <see cref="Behavior"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="Color"/> to blend.</param>
|
||||||
|
public Color Blend(Color color) => Behavior.Blend(this, color);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Operators
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Blends the provided colors as if <see cref="Blend"/> would've been called on <paramref name="color1" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color1">The base color.</param>
|
||||||
|
/// <param name="color2">The color to blend.</param>
|
||||||
|
/// <returns>The blended color.</returns>
|
||||||
|
public static Color operator +(Color color1, Color color2) => color1.Blend(color2);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a value that indicates whether two specified <see cref="Color" /> are equal.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color1">The first <see cref="Color" /> to compare.</param>
|
||||||
|
/// <param name="color2">The second <see cref="Color" /> to compare.</param>
|
||||||
|
/// <returns><c>true</c> if <paramref name="color1" /> and <paramref name="color2" /> are equal; otherwise, <c>false</c>.</returns>
|
||||||
|
public static bool operator ==(Color color1, Color color2) => color1.Equals(color2);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a value that indicates whether two specified <see cref="Color" /> are equal.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color1">The first <see cref="Color" /> to compare.</param>
|
||||||
|
/// <param name="color2">The second <see cref="Color" /> to compare.</param>
|
||||||
|
/// <returns><c>true</c> if <paramref name="color1" /> and <paramref name="color2" /> are not equal; otherwise, <c>false</c>.</returns>
|
||||||
|
public static bool operator !=(Color color1, Color color2) => !(color1 == color2);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
||||||
|
/// <returns>The color.</returns>
|
||||||
|
public static implicit operator Color((byte r, byte g, byte b) components) => new Color(components.r, components.g, components.b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
||||||
|
/// <returns>The color.</returns>
|
||||||
|
public static implicit operator Color((byte a, byte r, byte g, byte b) components) => new Color(components.a, components.r, components.g, components.b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
||||||
|
/// <returns>The color.</returns>
|
||||||
|
public static implicit operator Color((int r, int g, int b) components) => new Color(components.r, components.g, components.b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
||||||
|
/// <returns>The color.</returns>
|
||||||
|
public static implicit operator Color((int a, int r, int g, int b) components) => new Color(components.a, components.r, components.g, components.b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
||||||
|
/// <returns>The color.</returns>
|
||||||
|
public static implicit operator Color((double r, double g, double b) components) => new Color(components.r, components.g, components.b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
||||||
|
/// <returns>The color.</returns>
|
||||||
|
public static implicit operator Color((double a, double r, double g, double b) components) => new Color(components.a, components.r, components.g, components.b);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct by cloning a existing <see cref="T:RGB.NET.Core.Color" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The <see cref="T:RGB.NET.Core.Color" /> the values are copied from.</param>
|
|
||||||
public Color(Color color)
|
|
||||||
: this(color.A, color.R, color.G, color.B)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a human-readable string, as defined by the current <see cref="Behavior"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A string that contains the individual byte values of this <see cref="Color"/>. Default format: "[A: 255, R: 255, G: 0, B: 0]".</returns>
|
|
||||||
public override string ToString() => Behavior.ToString(this);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests whether the specified object is a <see cref="Color" /> and is equivalent to this <see cref="Color" />, as defined by the current <see cref="Behavior"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj">The object to test.</param>
|
|
||||||
/// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Color" /> equivalent to this <see cref="Color" />; otherwise, <c>false</c>.</returns>
|
|
||||||
public override bool Equals(object? obj) => Behavior.Equals(this, obj);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests whether the specified <see cref="Color" /> is equivalent to this <see cref="Color" />, as defined by the current <see cref="Behavior"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="other">The color to test.</param>
|
|
||||||
/// <returns><c>true</c> if <paramref name="other" /> is equivalent to this <see cref="Color" />; otherwise, <c>false</c>.</returns>
|
|
||||||
public bool Equals(Color other) => Behavior.Equals(this, other);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hash code for this <see cref="Color" />, as defined by the current <see cref="Behavior"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>An integer value that specifies the hash code for this <see cref="Color" />.</returns>
|
|
||||||
// ReSharper disable once NonReadonlyMemberInGetHashCode
|
|
||||||
public override int GetHashCode() => Behavior.GetHashCode(this);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Blends a <see cref="Color"/> over this color, as defined by the current <see cref="Behavior"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The <see cref="Color"/> to blend.</param>
|
|
||||||
public Color Blend(Color color) => Behavior.Blend(this, color);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Operators
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Blends the provided colors as if <see cref="Blend"/> would've been called on <paramref name="color1" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color1">The base color.</param>
|
|
||||||
/// <param name="color2">The color to blend.</param>
|
|
||||||
/// <returns>The blended color.</returns>
|
|
||||||
public static Color operator +(Color color1, Color color2) => color1.Blend(color2);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a value that indicates whether two specified <see cref="Color" /> are equal.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color1">The first <see cref="Color" /> to compare.</param>
|
|
||||||
/// <param name="color2">The second <see cref="Color" /> to compare.</param>
|
|
||||||
/// <returns><c>true</c> if <paramref name="color1" /> and <paramref name="color2" /> are equal; otherwise, <c>false</c>.</returns>
|
|
||||||
public static bool operator ==(Color color1, Color color2) => color1.Equals(color2);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a value that indicates whether two specified <see cref="Color" /> are equal.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color1">The first <see cref="Color" /> to compare.</param>
|
|
||||||
/// <param name="color2">The second <see cref="Color" /> to compare.</param>
|
|
||||||
/// <returns><c>true</c> if <paramref name="color1" /> and <paramref name="color2" /> are not equal; otherwise, <c>false</c>.</returns>
|
|
||||||
public static bool operator !=(Color color1, Color color2) => !(color1 == color2);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
|
||||||
/// <returns>The color.</returns>
|
|
||||||
public static implicit operator Color((byte r, byte g, byte b) components) => new(components.r, components.g, components.b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
|
||||||
/// <returns>The color.</returns>
|
|
||||||
public static implicit operator Color((byte a, byte r, byte g, byte b) components) => new(components.a, components.r, components.g, components.b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
|
||||||
/// <returns>The color.</returns>
|
|
||||||
public static implicit operator Color((int r, int g, int b) components) => new(components.r, components.g, components.b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
|
||||||
/// <returns>The color.</returns>
|
|
||||||
public static implicit operator Color((int a, int r, int g, int b) components) => new(components.a, components.r, components.g, components.b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
|
||||||
/// <returns>The color.</returns>
|
|
||||||
public static implicit operator Color((float r, float g, float b) components) => new(components.r, components.g, components.b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="components">The <see cref="ValueTuple"/> containing the components.</param>
|
|
||||||
/// <returns>The color.</returns>
|
|
||||||
public static implicit operator Color((float a, float r, float g, float b) components) => new(components.a, components.r, components.g, components.b);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
@ -2,227 +2,226 @@
|
|||||||
// ReSharper disable UnusedMember.Global
|
// ReSharper disable UnusedMember.Global
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains helper-methods and extension for the <see cref="Color"/>-type to work in the HSV color space.
|
|
||||||
/// </summary>
|
|
||||||
public static class HSVColor
|
|
||||||
{
|
{
|
||||||
#region Getter
|
public static class HSVColor
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hue component value (HSV-color space) of this <see cref="Color"/> as degree in the range [0..360].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The hue component value of the color.</returns>
|
|
||||||
public static float GetHue(this Color color) => color.GetHSV().hue;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the saturation component value (HSV-color space) of this <see cref="Color"/> in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The saturation component value of the color.</returns>
|
|
||||||
public static float GetSaturation(this Color color) => color.GetHSV().saturation;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value component value (HSV-color space) of this <see cref="Color"/> in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The value component value of the color.</returns>
|
|
||||||
public static float GetValue(this Color color) => color.GetHSV().value;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hue, saturation and value component values (HSV-color space) of this <see cref="Color"/>.
|
|
||||||
/// Hue as degree in the range [0..1].
|
|
||||||
/// Saturation in the range [0..1].
|
|
||||||
/// Value in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>A tuple containing the hue, saturation and value component value of the color.</returns>
|
|
||||||
public static (float hue, float saturation, float value) GetHSV(this Color color)
|
|
||||||
=> CaclulateHSVFromRGB(color.R, color.G, color.B);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Manipulation
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified HSV values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="hue">The hue value to add.</param>
|
|
||||||
/// <param name="saturation">The saturation value to add.</param>
|
|
||||||
/// <param name="value">The value value to add.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color AddHSV(this Color color, float hue = 0, float saturation = 0, float value = 0)
|
|
||||||
{
|
{
|
||||||
(float cHue, float cSaturation, float cValue) = color.GetHSV();
|
#region Getter
|
||||||
return Create(color.A, cHue + hue, cSaturation + saturation, cValue + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Subtracts the specified HSV values to this color.
|
/// Gets the hue component value (HSV-color space) of this <see cref="Color"/> as degree in the range [0..360].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="color">The color to modify.</param>
|
/// <param name="color"></param>
|
||||||
/// <param name="hue">The hue value to subtract.</param>
|
/// <returns></returns>
|
||||||
/// <param name="saturation">The saturation value to subtract.</param>
|
public static double GetHue(this Color color) => color.GetHSV().hue;
|
||||||
/// <param name="value">The value value to subtract.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SubtractHSV(this Color color, float hue = 0, float saturation = 0, float value = 0)
|
|
||||||
{
|
|
||||||
(float cHue, float cSaturation, float cValue) = color.GetHSV();
|
|
||||||
return Create(color.A, cHue - hue, cSaturation - saturation, cValue - value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Multiplies the specified HSV values to this color.
|
/// Gets the saturation component value (HSV-color space) of this <see cref="Color"/> in the range [0..1].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="color">The color to modify.</param>
|
/// <param name="color"></param>
|
||||||
/// <param name="hue">The hue value to multiply.</param>
|
/// <returns></returns>
|
||||||
/// <param name="saturation">The saturation value to multiply.</param>
|
public static double GetSaturation(this Color color) => color.GetHSV().saturation;
|
||||||
/// <param name="value">The value value to multiply.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color MultiplyHSV(this Color color, float hue = 1, float saturation = 1, float value = 1)
|
|
||||||
{
|
|
||||||
(float cHue, float cSaturation, float cValue) = color.GetHSV();
|
|
||||||
return Create(color.A, cHue * hue, cSaturation * saturation, cValue * value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Divides the specified HSV values to this color.
|
/// Gets the value component value (HSV-color space) of this <see cref="Color"/> in the range [0..1].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="color">The color to modify.</param>
|
/// <param name="color"></param>
|
||||||
/// <param name="hue">The hue value to divide.</param>
|
/// <returns></returns>
|
||||||
/// <param name="saturation">The saturation value to divide.</param>
|
public static double GetValue(this Color color) => color.GetHSV().value;
|
||||||
/// <param name="value">The value value to divide.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color DivideHSV(this Color color, float hue = 1, float saturation = 1, float value = 1)
|
|
||||||
{
|
|
||||||
(float cHue, float cSaturation, float cValue) = color.GetHSV();
|
|
||||||
return Create(color.A, cHue / hue, cSaturation / saturation, cValue / value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the specified hue value of this color.
|
/// Gets the hue, saturation and value component values (HSV-color space) of this <see cref="Color"/>.
|
||||||
/// </summary>
|
/// Hue as degree in the range [0..1].
|
||||||
/// <param name="color">The color to modify.</param>
|
/// Saturation in the range [0..1].
|
||||||
/// <param name="hue">The hue value to set.</param>
|
/// Value in the range [0..1].
|
||||||
/// <param name="saturation">The saturation value to set.</param>
|
/// </summary>
|
||||||
/// <param name="value">The value value to set.</param>
|
/// <param name="color"></param>
|
||||||
/// <returns>The new color after the modification.</returns>
|
/// <returns></returns>
|
||||||
public static Color SetHSV(this Color color, float? hue = null, float? saturation = null, float? value = null)
|
public static (double hue, double saturation, double value) GetHSV(this Color color)
|
||||||
{
|
=> CaclulateHSVFromRGB(color.R, color.G, color.B);
|
||||||
(float cHue, float cSaturation, float cValue) = color.GetHSV();
|
|
||||||
return Create(color.A, hue ?? cHue, saturation ?? cSaturation, value ?? cValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Factory
|
#region Manipulation
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using HSV-Values.
|
/// Adds the given HSV values to this color.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hue">The hue component value of this <see cref="Color"/>.</param>
|
/// <param name="hue">The hue value to add.</param>
|
||||||
/// <param name="saturation">The saturation component value of this <see cref="Color"/>.</param>
|
/// <param name="saturation">The saturation value to add.</param>
|
||||||
/// <param name="value">The value component value of this <see cref="Color"/>.</param>
|
/// <param name="value">The value value to add.</param>
|
||||||
/// <returns>The color created from the values.</returns>
|
/// <returns>The new color after the modification.</returns>
|
||||||
public static Color Create(float hue, float saturation, float value)
|
public static Color AddHSV(this Color color, double hue = 0, double saturation = 0, double value = 0)
|
||||||
=> Create(1.0f, hue, saturation, value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using AHSV-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="hue">The hue component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="saturation">The saturation component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="value">The value component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(byte a, float hue, float saturation, float value)
|
|
||||||
=> Create((float)a / byte.MaxValue, hue, saturation, value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using AHSV-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="hue">The hue component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="saturation">The saturation component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="value">The value component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(int a, float hue, float saturation, float value)
|
|
||||||
=> Create((float)a / byte.MaxValue, hue, saturation, value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using AHSV-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="hue">The hue component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="saturation">The saturation component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="value">The value component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(float a, float hue, float saturation, float value)
|
|
||||||
{
|
|
||||||
(float r, float g, float b) = CalculateRGBFromHSV(hue, saturation, value);
|
|
||||||
return new Color(a, r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Helper
|
|
||||||
|
|
||||||
private static (float h, float s, float v) CaclulateHSVFromRGB(float r, float g, float b)
|
|
||||||
{
|
|
||||||
if (r.EqualsInTolerance(g) && g.EqualsInTolerance(b)) return (0, 0, r);
|
|
||||||
|
|
||||||
float min = Math.Min(Math.Min(r, g), b);
|
|
||||||
float max = Math.Max(Math.Max(r, g), b);
|
|
||||||
|
|
||||||
float hue;
|
|
||||||
if (max.EqualsInTolerance(min))
|
|
||||||
hue = 0;
|
|
||||||
else if (max.EqualsInTolerance(r)) // r is max
|
|
||||||
hue = (g - b) / (max - min);
|
|
||||||
else if (max.EqualsInTolerance(g)) // g is max
|
|
||||||
hue = 2.0f + ((b - r) / (max - min));
|
|
||||||
else // b is max
|
|
||||||
hue = 4.0f + ((r - g) / (max - min));
|
|
||||||
|
|
||||||
hue *= 60.0f;
|
|
||||||
hue = hue.Wrap(0, 360);
|
|
||||||
|
|
||||||
float saturation = max.EqualsInTolerance(0) ? 0 : 1.0f - (min / max);
|
|
||||||
float value = Math.Max(r, Math.Max(g, b));
|
|
||||||
|
|
||||||
return (hue, saturation, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (float r, float g, float b) CalculateRGBFromHSV(float h, float s, float v)
|
|
||||||
{
|
|
||||||
h = h.Wrap(0, 360);
|
|
||||||
s = s.Clamp(0, 1);
|
|
||||||
v = v.Clamp(0, 1);
|
|
||||||
|
|
||||||
if (s <= 0.0)
|
|
||||||
return (v, v, v);
|
|
||||||
|
|
||||||
float hh = h / 60.0f;
|
|
||||||
int i = (int)hh;
|
|
||||||
float ff = hh - i;
|
|
||||||
float p = v * (1.0f - s);
|
|
||||||
float q = v * (1.0f - (s * ff));
|
|
||||||
float t = v * (1.0f - (s * (1.0f - ff)));
|
|
||||||
|
|
||||||
return i switch
|
|
||||||
{
|
{
|
||||||
0 => (v, t, p),
|
(double cHue, double cSaturation, double cValue) = color.GetHSV();
|
||||||
1 => (q, v, p),
|
return Create(color.A, cHue + hue, cSaturation + saturation, cValue + value);
|
||||||
2 => (p, v, t),
|
}
|
||||||
3 => (p, q, v),
|
|
||||||
4 => (t, p, v),
|
|
||||||
_ => (v, p, q)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
}
|
/// Subtracts the given HSV values to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hue">The hue value to subtract.</param>
|
||||||
|
/// <param name="saturation">The saturation value to subtract.</param>
|
||||||
|
/// <param name="value">The value value to subtract.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color SubtractHSV(this Color color, double hue = 0, double saturation = 0, double value = 0)
|
||||||
|
{
|
||||||
|
(double cHue, double cSaturation, double cValue) = color.GetHSV();
|
||||||
|
return Create(color.A, cHue - hue, cSaturation - saturation, cValue - value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplies the given HSV values to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hue">The hue value to multiply.</param>
|
||||||
|
/// <param name="saturation">The saturation value to multiply.</param>
|
||||||
|
/// <param name="value">The value value to multiply.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color MultiplyHSV(this Color color, double hue = 1, double saturation = 1, double value = 1)
|
||||||
|
{
|
||||||
|
(double cHue, double cSaturation, double cValue) = color.GetHSV();
|
||||||
|
return Create(color.A, cHue * hue, cSaturation * saturation, cValue * value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Divides the given HSV values to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hue">The hue value to divide.</param>
|
||||||
|
/// <param name="saturation">The saturation value to divide.</param>
|
||||||
|
/// <param name="value">The value value to divide.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color DivideHSV(this Color color, double hue = 1, double saturation = 1, double value = 1)
|
||||||
|
{
|
||||||
|
(double cHue, double cSaturation, double cValue) = color.GetHSV();
|
||||||
|
return Create(color.A, cHue / hue, cSaturation / saturation, cValue / value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the given hue value of this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hue">The hue value to set.</param>
|
||||||
|
/// <param name="saturation">The saturation value to set.</param>
|
||||||
|
/// <param name="value">The value value to set.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color SetHSV(this Color color, double? hue = null, double? saturation = null, double? value = null)
|
||||||
|
{
|
||||||
|
(double cHue, double cSaturation, double cValue) = color.GetHSV();
|
||||||
|
return Create(color.A, hue ?? cHue, saturation ?? cSaturation, value ?? cValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Factory
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using HSV-Values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hue">The hue component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="saturation">The saturation component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="value">The value component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <returns>The color created from the values.</returns>
|
||||||
|
public static Color Create(double hue, double saturation, double value)
|
||||||
|
=> Create(1.0, hue, saturation, value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using AHSV-Values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="hue">The hue component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="saturation">The saturation component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="value">The value component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <returns>The color created from the values.</returns>
|
||||||
|
public static Color Create(byte a, double hue, double saturation, double value)
|
||||||
|
=> Create((double)a / byte.MaxValue, hue, saturation, value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using AHSV-Values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="hue">The hue component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="saturation">The saturation component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="value">The value component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <returns>The color created from the values.</returns>
|
||||||
|
public static Color Create(int a, double hue, double saturation, double value)
|
||||||
|
=> Create((double)a / byte.MaxValue, hue, saturation, value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using AHSV-Values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="hue">The hue component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="saturation">The saturation component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <param name="value">The value component value of this <see cref="Color"/>.</param>
|
||||||
|
/// <returns>The color created from the values.</returns>
|
||||||
|
public static Color Create(double a, double hue, double saturation, double value)
|
||||||
|
{
|
||||||
|
(double r, double g, double b) = CalculateRGBFromHSV(hue, saturation, value);
|
||||||
|
return new Color(a, r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Helper
|
||||||
|
|
||||||
|
private static (double h, double s, double v) CaclulateHSVFromRGB(double r, double g, double b)
|
||||||
|
{
|
||||||
|
if (r.EqualsInTolerance(g) && g.EqualsInTolerance(b)) return (0, 0, r);
|
||||||
|
|
||||||
|
double min = Math.Min(Math.Min(r, g), b);
|
||||||
|
double max = Math.Max(Math.Max(r, g), b);
|
||||||
|
|
||||||
|
double hue;
|
||||||
|
if (max.EqualsInTolerance(min))
|
||||||
|
hue = 0;
|
||||||
|
else if (max.EqualsInTolerance(r)) // r is max
|
||||||
|
hue = (g - b) / (max - min);
|
||||||
|
else if (max.EqualsInTolerance(g)) // g is max
|
||||||
|
hue = 2.0 + ((b - r) / (max - min));
|
||||||
|
else // b is max
|
||||||
|
hue = 4.0 + ((r - g) / (max - min));
|
||||||
|
|
||||||
|
hue = hue * 60.0;
|
||||||
|
hue = hue.Wrap(0, 360);
|
||||||
|
|
||||||
|
double saturation = max.EqualsInTolerance(0) ? 0 : 1.0 - (min / max);
|
||||||
|
double value = Math.Max(r, Math.Max(g, b));
|
||||||
|
|
||||||
|
return (hue, saturation, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (double r, double g, double b) CalculateRGBFromHSV(double h, double s, double v)
|
||||||
|
{
|
||||||
|
h = h.Wrap(0, 360);
|
||||||
|
s = s.Clamp(0, 1);
|
||||||
|
v = v.Clamp(0, 1);
|
||||||
|
|
||||||
|
if (s <= 0.0)
|
||||||
|
return (v, v, v);
|
||||||
|
|
||||||
|
double hh = h / 60.0;
|
||||||
|
int i = (int)hh;
|
||||||
|
double ff = hh - i;
|
||||||
|
double p = v * (1.0 - s);
|
||||||
|
double q = v * (1.0 - (s * ff));
|
||||||
|
double t = v * (1.0 - (s * (1.0 - ff)));
|
||||||
|
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return (v, t, p);
|
||||||
|
case 1:
|
||||||
|
return (q, v, p);
|
||||||
|
case 2:
|
||||||
|
return (p, v, t);
|
||||||
|
case 3:
|
||||||
|
return (p, q, v);
|
||||||
|
case 4:
|
||||||
|
return (t, p, v);
|
||||||
|
default:
|
||||||
|
return (v, p, q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,211 +0,0 @@
|
|||||||
// ReSharper disable MemberCanBePrivate.Global
|
|
||||||
// ReSharper disable UnusedMember.Global
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains helper-methods and extension for the <see cref="Color"/>-type to work in the Hcl color space.
|
|
||||||
/// </summary>
|
|
||||||
public static class HclColor
|
|
||||||
{
|
|
||||||
#region Getter
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the H component value (Hcl-color space) of this <see cref="Color"/> in the range [0..360].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The H component value of the color. </returns>
|
|
||||||
public static float GetHclH(this Color color) => color.GetHcl().h;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the c component value (Hcl-color space) of this <see cref="Color"/> in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The c component value of the color. </returns>
|
|
||||||
public static float GetHclC(this Color color) => color.GetHcl().c;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the l component value (Hcl-color space) of this <see cref="Color"/> in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The l component value of the color. </returns>
|
|
||||||
public static float GetHclL(this Color color) => color.GetHcl().l;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the H, c and l component values (Hcl-color space) of this <see cref="Color"/>.
|
|
||||||
/// H in the range [0..360].
|
|
||||||
/// c in the range [0..1].
|
|
||||||
/// l in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>A tuple containing the H, c and l component value of the color.</returns>
|
|
||||||
public static (float h, float c, float l) GetHcl(this Color color)
|
|
||||||
=> CalculateHclFromRGB(color.R, color.G, color.B);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Manipulation
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified Hcl values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="h">The H value to add.</param>
|
|
||||||
/// <param name="c">The c value to add.</param>
|
|
||||||
/// <param name="l">The l value to add.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color AddHcl(this Color color, float h = 0, float c = 0, float l = 0)
|
|
||||||
{
|
|
||||||
(float cH, float cC, float cL) = color.GetHcl();
|
|
||||||
return Create(color.A, cH + h, cC + c, cL + l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subtracts the specified Hcl values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="h">The H value to subtract.</param>
|
|
||||||
/// <param name="c">The c value to subtract.</param>
|
|
||||||
/// <param name="l">The l value to subtract.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SubtractHcl(this Color color, float h = 0, float c = 0, float l = 0)
|
|
||||||
{
|
|
||||||
(float cH, float cC, float cL) = color.GetHcl();
|
|
||||||
return Create(color.A, cH - h, cC - c, cL - l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Multiplies the specified Hcl values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="h">The H value to multiply.</param>
|
|
||||||
/// <param name="c">The c value to multiply.</param>
|
|
||||||
/// <param name="l">The l value to multiply.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color MultiplyHcl(this Color color, float h = 1, float c = 1, float l = 1)
|
|
||||||
{
|
|
||||||
(float cH, float cC, float cL) = color.GetHcl();
|
|
||||||
return Create(color.A, cH * h, cC * c, cL * l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Divides the specified Hcl values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="h">The H value to divide.</param>
|
|
||||||
/// <param name="c">The c value to divide.</param>
|
|
||||||
/// <param name="l">The l value to divide.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color DivideHcl(this Color color, float h = 1, float c = 1, float l = 1)
|
|
||||||
{
|
|
||||||
(float cH, float cC, float cL) = color.GetHcl();
|
|
||||||
return Create(color.A, cH / h, cC / c, cL / l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the specified X value of this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="h">The H value to set.</param>
|
|
||||||
/// <param name="c">The c value to set.</param>
|
|
||||||
/// <param name="l">The l value to set.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SetHcl(this Color color, float? h = null, float? c = null, float? l = null)
|
|
||||||
{
|
|
||||||
(float cH, float cC, float cL) = color.GetHcl();
|
|
||||||
return Create(color.A, h ?? cH, c ?? cC, l ?? cL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Factory
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using Hcl-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="h">The H component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="c">The c component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="l">The l component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(float h, float c, float l)
|
|
||||||
=> Create(1.0f, h, c, l);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using alpha and Hcl-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="alpha">The alphc component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="h">The H component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="c">The c component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="l">The l component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(byte alpha, float h, float c, float l)
|
|
||||||
=> Create((float)alpha / byte.MaxValue, h, c, l);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using alpha and Hcl-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="alpha">The alphc component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="h">The H component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="c">The c component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="l">The l component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(int alpha, float h, float c, float l)
|
|
||||||
=> Create((float)alpha / byte.MaxValue, h, c, l);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using alpha and Hcl-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="alpha">The alphc component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="h">The H component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="c">The c component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="l">The l component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(float alpha, float h, float c, float l)
|
|
||||||
{
|
|
||||||
(float r, float g, float b) = CalculateRGBFromHcl(h, c, l);
|
|
||||||
return new Color(alpha, r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Helper
|
|
||||||
|
|
||||||
private static (float h, float c, float l) CalculateHclFromRGB(float r, float g, float b)
|
|
||||||
{
|
|
||||||
const float RADIANS_DEGREES_CONVERSION = 180.0f / MathF.PI;
|
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming - b is used above
|
|
||||||
(float l, float a, float _b) = LabColor.CalculateLabFromRGB(r, g, b);
|
|
||||||
|
|
||||||
float h, c;
|
|
||||||
if (r.EqualsInTolerance(g) && r.EqualsInTolerance(b)) //DarthAffe 26.02.2021: The cumulated rounding errors are big enough to cause problems in that case
|
|
||||||
{
|
|
||||||
h = 0;
|
|
||||||
c = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
h = MathF.Atan2(_b, a);
|
|
||||||
if (h >= 0) h *= RADIANS_DEGREES_CONVERSION;
|
|
||||||
else h = 360 - (-h * RADIANS_DEGREES_CONVERSION);
|
|
||||||
|
|
||||||
c = MathF.Sqrt((a * a) + (_b * _b));
|
|
||||||
}
|
|
||||||
|
|
||||||
return (h, c, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (float r, float g, float b) CalculateRGBFromHcl(float h, float c, float l)
|
|
||||||
{
|
|
||||||
const float DEGREES_RADIANS_CONVERSION = MathF.PI / 180.0f;
|
|
||||||
|
|
||||||
h *= DEGREES_RADIANS_CONVERSION;
|
|
||||||
float a = c * MathF.Cos(h);
|
|
||||||
float b = c * MathF.Sin(h);
|
|
||||||
|
|
||||||
return LabColor.CalculateRGBFromLab(l, a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -1,227 +0,0 @@
|
|||||||
// ReSharper disable MemberCanBePrivate.Global
|
|
||||||
// ReSharper disable UnusedMember.Global
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains helper-methods and extension for the <see cref="Color"/>-type to work in the Lab color space.
|
|
||||||
/// </summary>
|
|
||||||
public static class LabColor
|
|
||||||
{
|
|
||||||
#region Getter
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the L component value (Lab-color space) of this <see cref="Color"/> in the range [0..100].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The L component value of the color.</returns>
|
|
||||||
public static float GetLabL(this Color color) => color.GetLab().l;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the a component value (Lab-color space) of this <see cref="Color"/> in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The a component value of the color.</returns>
|
|
||||||
public static float GetLabA(this Color color) => color.GetLab().a;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the b component value (Lab-color space) of this <see cref="Color"/> in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The b component value of the color.</returns>
|
|
||||||
public static float GetLabB(this Color color) => color.GetLab().b;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the L, a and b component values (Lab-color space) of this <see cref="Color"/>.
|
|
||||||
/// L in the range [0..100].
|
|
||||||
/// a in the range [0..1].
|
|
||||||
/// b in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>A tuple containing the L, a and b component value of the color.</returns>
|
|
||||||
public static (float l, float a, float b) GetLab(this Color color)
|
|
||||||
=> CalculateLabFromRGB(color.R, color.G, color.B);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Manipulation
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified Lab values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="l">The L value to add.</param>
|
|
||||||
/// <param name="a">The a value to add.</param>
|
|
||||||
/// <param name="b">The b value to add.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color AddLab(this Color color, float l = 0, float a = 0, float b = 0)
|
|
||||||
{
|
|
||||||
(float cL, float cA, float cB) = color.GetLab();
|
|
||||||
return Create(color.A, cL + l, cA + a, cB + b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subtracts the specified Lab values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="l">The L value to subtract.</param>
|
|
||||||
/// <param name="a">The a value to subtract.</param>
|
|
||||||
/// <param name="b">The b value to subtract.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SubtractLab(this Color color, float l = 0, float a = 0, float b = 0)
|
|
||||||
{
|
|
||||||
(float cL, float cA, float cB) = color.GetLab();
|
|
||||||
return Create(color.A, cL - l, cA - a, cB - b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Multiplies the specified Lab values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="l">The L value to multiply.</param>
|
|
||||||
/// <param name="a">The a value to multiply.</param>
|
|
||||||
/// <param name="b">The b value to multiply.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color MultiplyLab(this Color color, float l = 1, float a = 1, float b = 1)
|
|
||||||
{
|
|
||||||
(float cL, float cA, float cB) = color.GetLab();
|
|
||||||
return Create(color.A, cL * l, cA * a, cB * b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Divides the specified Lab values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="l">The L value to divide.</param>
|
|
||||||
/// <param name="a">The a value to divide.</param>
|
|
||||||
/// <param name="b">The b value to divide.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color DivideLab(this Color color, float l = 1, float a = 1, float b = 1)
|
|
||||||
{
|
|
||||||
(float cL, float cA, float cB) = color.GetLab();
|
|
||||||
return Create(color.A, cL / l, cA / a, cB / b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the specified X valueof this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="l">The L value to set.</param>
|
|
||||||
/// <param name="a">The a value to set.</param>
|
|
||||||
/// <param name="b">The b value to set.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SetLab(this Color color, float? l = null, float? a = null, float? b = null)
|
|
||||||
{
|
|
||||||
(float cL, float cA, float cB) = color.GetLab();
|
|
||||||
return Create(color.A, l ?? cL, a ?? cA, b ?? cB);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Factory
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using Lab-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="l">The L component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="a">The a component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The b component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(float l, float a, float b)
|
|
||||||
=> Create(1.0f, l, a, b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using alpha and Lab-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="alpha">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="l">The L component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="a">The a component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The b component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(byte alpha, float l, float a, float b)
|
|
||||||
=> Create((float)alpha / byte.MaxValue, l, a, b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using alpha and Lab-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="alpha">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="l">The L component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="a">The a component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The b component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(int alpha, float l, float a, float b)
|
|
||||||
=> Create((float)alpha / byte.MaxValue, l, a, b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using alpha and Lab-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="alpha">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="l">The L component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="a">The a component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="b">The b component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(float alpha, float l, float a, float b)
|
|
||||||
{
|
|
||||||
// ReSharper disable once InconsistentNaming - b is used above
|
|
||||||
(float r, float g, float _b) = CalculateRGBFromLab(l, a, b);
|
|
||||||
return new Color(alpha, r, g, _b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Helper
|
|
||||||
|
|
||||||
internal static (float l, float a, float b) CalculateLabFromRGB(float r, float g, float b)
|
|
||||||
{
|
|
||||||
(float x, float y, float z) = XYZColor.CaclulateXYZFromRGB(r, g, b);
|
|
||||||
return CaclulateLabFromXYZ(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static (float r, float g, float b) CalculateRGBFromLab(float l, float a, float b)
|
|
||||||
{
|
|
||||||
(float x, float y, float z) = CalculateXYZFromLab(l, a, b);
|
|
||||||
return XYZColor.CalculateRGBFromXYZ(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (float l, float a, float b) CaclulateLabFromXYZ(float x, float y, float z)
|
|
||||||
{
|
|
||||||
const float ONETHRID = 1.0f / 3.0f;
|
|
||||||
const float FACTOR2 = 16.0f / 116.0f;
|
|
||||||
|
|
||||||
x /= 95.047f;
|
|
||||||
y /= 100.0f;
|
|
||||||
z /= 108.883f;
|
|
||||||
|
|
||||||
x = ((x > 0.008856f) ? (MathF.Pow(x, ONETHRID)) : ((7.787f * x) + FACTOR2));
|
|
||||||
y = ((y > 0.008856f) ? (MathF.Pow(y, ONETHRID)) : ((7.787f * y) + FACTOR2));
|
|
||||||
z = ((z > 0.008856f) ? (MathF.Pow(z, ONETHRID)) : ((7.787f * z) + FACTOR2));
|
|
||||||
|
|
||||||
float l = (116.0f * y) - 16.0f;
|
|
||||||
float a = 500.0f * (x - y);
|
|
||||||
float b = 200.0f * (y - z);
|
|
||||||
|
|
||||||
return (l, a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (float x, float y, float z) CalculateXYZFromLab(float l, float a, float b)
|
|
||||||
{
|
|
||||||
const float FACTOR2 = 16.0f / 116.0f;
|
|
||||||
|
|
||||||
float y = (l + 16.0f) / 116.0f;
|
|
||||||
float x = (a / 500.0f) + y;
|
|
||||||
float z = y - (b / 200.0f);
|
|
||||||
|
|
||||||
float powX = MathF.Pow(x, 3.0f);
|
|
||||||
float powY = MathF.Pow(y, 3.0f);
|
|
||||||
float powZ = MathF.Pow(z, 3.0f);
|
|
||||||
|
|
||||||
x = ((powX > 0.008856f) ? (powX) : ((x - FACTOR2) / 7.787f));
|
|
||||||
y = ((powY > 0.008856f) ? (powY) : ((y - FACTOR2) / 7.787f));
|
|
||||||
z = ((powZ > 0.008856f) ? (powZ) : ((z - FACTOR2) / 7.787f));
|
|
||||||
|
|
||||||
return (x * 95.047f, y * 100.0f, z * 108.883f);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -2,294 +2,274 @@
|
|||||||
// ReSharper disable UnusedMember.Global
|
// ReSharper disable UnusedMember.Global
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains helper-methods and extension for the <see cref="Color"/>-type to work in the RGB color space.
|
|
||||||
/// </summary>
|
|
||||||
public static class RGBColor
|
|
||||||
{
|
{
|
||||||
#region Getter
|
public static class RGBColor
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the A component value of this <see cref="Color"/> as byte in the range [0..255].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The A component value of the color.</returns>
|
|
||||||
public static byte GetA(this Color color) => color.A.GetByteValueFromPercentage();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the R component value of this <see cref="Color"/> as byte in the range [0..255].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The R component value of the color.</returns>
|
|
||||||
public static byte GetR(this Color color) => color.R.GetByteValueFromPercentage();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the G component value of this <see cref="Color"/> as byte in the range [0..255].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The G component value of the color.</returns>
|
|
||||||
public static byte GetG(this Color color) => color.G.GetByteValueFromPercentage();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the B component value of this <see cref="Color"/> as byte in the range [0..255].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The B component value of the color.</returns>
|
|
||||||
public static byte GetB(this Color color) => color.B.GetByteValueFromPercentage();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the A, R, G and B component value of this <see cref="Color"/> as byte in the range [0..255].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>A tuple containing the A, R, G and B component value of the color.</returns>
|
|
||||||
public static (byte a, byte r, byte g, byte b) GetRGBBytes(this Color color)
|
|
||||||
=> (color.GetA(), color.GetR(), color.GetG(), color.GetB());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the A, R, G and B component value of this <see cref="Color"/> as percentage in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>A tuple containing the A, R, G and B component value of the color.</returns>
|
|
||||||
public static (float a, float r, float g, float b) GetRGB(this Color color)
|
|
||||||
=> (color.A, color.R, color.G, color.B);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Manipulation
|
|
||||||
|
|
||||||
#region Add
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified RGB values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="r">The red value to add.</param>
|
|
||||||
/// <param name="g">The green value to add.</param>
|
|
||||||
/// <param name="b">The blue value to add.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color AddRGB(this Color color, int r = 0, int g = 0, int b = 0)
|
|
||||||
=> new(color.A, color.GetR() + r, color.GetG() + g, color.GetB() + b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified RGB-percent values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="r">The red value to add.</param>
|
|
||||||
/// <param name="g">The green value to add.</param>
|
|
||||||
/// <param name="b">The blue value to add.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color AddRGB(this Color color, float r = 0, float g = 0, float b = 0)
|
|
||||||
=> new(color.A, color.R + r, color.G + g, color.B + b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified alpha value to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="a">The alpha value to add.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color AddA(this Color color, int a)
|
|
||||||
=> new(color.GetA() + a, color.R, color.G, color.B);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified alpha-percent value to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="a">The alpha value to add.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color AddA(this Color color, float a)
|
|
||||||
=> new(color.A + a, color.R, color.G, color.B);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Subtract
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subtracts the specified RGB values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="r">The red value to subtract.</param>
|
|
||||||
/// <param name="g">The green value to subtract.</param>
|
|
||||||
/// <param name="b">The blue value to subtract.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SubtractRGB(this Color color, int r = 0, int g = 0, int b = 0)
|
|
||||||
=> new(color.A, color.GetR() - r, color.GetG() - g, color.GetB() - b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subtracts the specified RGB values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="r">The red value to subtract.</param>
|
|
||||||
/// <param name="g">The green value to subtract.</param>
|
|
||||||
/// <param name="b">The blue value to subtract.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SubtractRGB(this Color color, float r = 0, float g = 0, float b = 0)
|
|
||||||
=> new(color.A, color.R - r, color.G - g, color.B - b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subtracts the specified alpha value to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="a">The alpha value to subtract.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SubtractA(this Color color, int a)
|
|
||||||
=> new(color.GetA() - a, color.R, color.G, color.B);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subtracts the specified alpha-percent value to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="aPercent">The alpha value to subtract.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SubtractA(this Color color, float aPercent)
|
|
||||||
=> new(color.A - aPercent, color.R, color.G, color.B);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Multiply
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Multiplies the specified RGB values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="r">The red value to multiply.</param>
|
|
||||||
/// <param name="g">The green value to multiply.</param>
|
|
||||||
/// <param name="b">The blue value to multiply.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color MultiplyRGB(this Color color, float r = 1, float g = 1, float b = 1)
|
|
||||||
=> new(color.A, color.R * r, color.G * g, color.B * b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Multiplies the specified alpha value to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="a">The alpha value to multiply.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color MultiplyA(this Color color, float a)
|
|
||||||
=> new(color.A * a, color.R, color.G, color.B);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Divide
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Divides the specified RGB values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="r">The red value to divide.</param>
|
|
||||||
/// <param name="g">The green value to divide.</param>
|
|
||||||
/// <param name="b">The blue value to divide.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color DivideRGB(this Color color, float r = 1, float g = 1, float b = 1)
|
|
||||||
=> new(color.A, color.R / r, color.G / g, color.B / b);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Divides the specified alpha value to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="a">The alpha value to divide.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color DivideA(this Color color, float a)
|
|
||||||
=> new(color.A / a, color.R, color.G, color.B);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Set
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the specified RGB value of this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="r">The red value to set.</param>
|
|
||||||
/// <param name="g">The green value to set.</param>
|
|
||||||
/// <param name="b">The blue value to set.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SetRGB(this Color color, byte? r = null, byte? g = null, byte? b = null)
|
|
||||||
=> new(color.A, r ?? color.GetR(), g ?? color.GetG(), b ?? color.GetB());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the specified RGB value of this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="r">The red value to set.</param>
|
|
||||||
/// <param name="g">The green value to set.</param>
|
|
||||||
/// <param name="b">The blue value to set.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SetRGB(this Color color, int? r = null, int? g = null, int? b = null)
|
|
||||||
=> new(color.A, r ?? color.GetR(), g ?? color.GetG(), b ?? color.GetB());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the specified RGB value of this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="r">The red value to set.</param>
|
|
||||||
/// <param name="g">The green value to set.</param>
|
|
||||||
/// <param name="b">The blue value to set.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SetRGB(this Color color, float? r = null, float? g = null, float? b = null)
|
|
||||||
=> new(color.A, r ?? color.R, g ?? color.G, b ?? color.B);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the specified alpha value of this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="a">The alpha value to set.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SetA(this Color color, int a) => new(a, color.R, color.G, color.B);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the specified alpha value of this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="a">The alpha value to set.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SetA(this Color color, float a) => new(a, color.R, color.G, color.B);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Conversion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the current color as a RGB-HEX-string.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The RGB-HEX-string.</returns>
|
|
||||||
public static string AsRGBHexString(this Color color, bool leadingHash = true) => (leadingHash ? "#" : "") + ConversionHelper.ToHex(color.GetR(), color.GetG(), color.GetB());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the current color as a ARGB-HEX-string.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The ARGB-HEX-string.</returns>
|
|
||||||
public static string AsARGBHexString(this Color color, bool leadingHash = true) => (leadingHash ? "#" : "") + ConversionHelper.ToHex(color.GetA(), color.GetR(), color.GetG(), color.GetB());
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Factory
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using a HEX-string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hexString">The HEX-representation of the color.</param>
|
|
||||||
/// <returns>The color created from the HEX-string.</returns>
|
|
||||||
public static Color FromHexString(string hexString)
|
|
||||||
{
|
{
|
||||||
if ((hexString == null) || (hexString.Length < 6))
|
#region Getter
|
||||||
throw new ArgumentException("Invalid hex string", nameof(hexString));
|
|
||||||
|
|
||||||
ReadOnlySpan<char> span = hexString.AsSpan();
|
/// <summary>
|
||||||
if (span[0] == '#')
|
/// Gets the A component value of this <see cref="Color"/> as byte in the range [0..255].
|
||||||
span = span[1..];
|
/// </summary>
|
||||||
|
/// <param name="color"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static byte GetA(this Color color) => color.A.GetByteValueFromPercentage();
|
||||||
|
|
||||||
byte[] data = ConversionHelper.HexToBytes(span);
|
/// <summary>
|
||||||
return data.Length switch
|
/// Gets the R component value of this <see cref="Color"/> as byte in the range [0..255].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static byte GetR(this Color color) => color.R.GetByteValueFromPercentage();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the G component value of this <see cref="Color"/> as byte in the range [0..255].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static byte GetG(this Color color) => color.G.GetByteValueFromPercentage();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the B component value of this <see cref="Color"/> as byte in the range [0..255].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static byte GetB(this Color color) => color.B.GetByteValueFromPercentage();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the A, R, G and B component value of this <see cref="Color"/> as byte in the range [0..255].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static (byte a, byte r, byte g, byte b) GetRGBBytes(this Color color)
|
||||||
|
=> (color.GetA(), color.GetR(), color.GetG(), color.GetB());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the A, R, G and B component value of this <see cref="Color"/> as percentage in the range [0..1].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static (double a, double r, double g, double b) GetRGB(this Color color)
|
||||||
|
=> (color.A, color.R, color.G, color.B);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Manipulation
|
||||||
|
|
||||||
|
#region Add
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the given RGB values to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red value to add.</param>
|
||||||
|
/// <param name="g">The green value to add.</param>
|
||||||
|
/// <param name="b">The blue value to add.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color AddRGB(this Color color, int r = 0, int g = 0, int b = 0)
|
||||||
|
=> new Color(color.A, color.GetR() + r, color.GetG() + g, color.GetB() + b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the given RGB-percent values to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red value to add.</param>
|
||||||
|
/// <param name="g">The green value to add.</param>
|
||||||
|
/// <param name="b">The blue value to add.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color AddRGB(this Color color, double r = 0, double g = 0, double b = 0)
|
||||||
|
=> new Color(color.A, color.R + r, color.G + g, color.B + b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the given alpha value to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha value to add.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color AddA(this Color color, int a)
|
||||||
|
=> new Color(color.GetA() + a, color.R, color.G, color.B);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the given alpha-percent value to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha value to add.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color AddA(this Color color, double a)
|
||||||
|
=> new Color(color.A + a, color.R, color.G, color.B);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Subtract
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts the given RGB values to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red value to subtract.</param>
|
||||||
|
/// <param name="g">The green value to subtract.</param>
|
||||||
|
/// <param name="b">The blue value to subtract.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color SubtractRGB(this Color color, int r = 0, int g = 0, int b = 0)
|
||||||
|
=> new Color(color.A, color.GetR() - r, color.GetG() - g, color.GetB() - b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts the given RGB values to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red value to subtract.</param>
|
||||||
|
/// <param name="g">The green value to subtract.</param>
|
||||||
|
/// <param name="b">The blue value to subtract.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color SubtractRGB(this Color color, double r = 0, double g = 0, double b = 0)
|
||||||
|
=> new Color(color.A, color.R - r, color.G - g, color.B - b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts the given alpha value to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha value to subtract.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color SubtractA(this Color color, int a)
|
||||||
|
=> new Color(color.GetA() - a, color.R, color.G, color.B);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts the given alpha-percent value to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha value to subtract.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color SubtractA(this Color color, double aPercent)
|
||||||
|
=> new Color(color.A - aPercent, color.R, color.G, color.B);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Multiply
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplies the given RGB values to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red value to multiply.</param>
|
||||||
|
/// <param name="g">The green value to multiply.</param>
|
||||||
|
/// <param name="b">The blue value to multiply.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color MultiplyRGB(this Color color, double r = 1, double g = 1, double b = 1)
|
||||||
|
=> new Color(color.A, color.R * r, color.G * g, color.B * b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplies the given alpha value to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha value to multiply.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color MultiplyA(this Color color, double a)
|
||||||
|
=> new Color(color.A * a, color.R, color.G, color.B);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Divide
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Divides the given RGB values to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red value to divide.</param>
|
||||||
|
/// <param name="g">The green value to divide.</param>
|
||||||
|
/// <param name="b">The blue value to divide.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color DivideRGB(this Color color, double r = 1, double g = 1, double b = 1)
|
||||||
|
=> new Color(color.A, color.R / r, color.G / g, color.B / b);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Divides the given alpha value to this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha value to divide.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color DivideA(this Color color, double a)
|
||||||
|
=> new Color(color.A / a, color.R, color.G, color.B);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Set
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the given RGB value of this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red value to set.</param>
|
||||||
|
/// <param name="g">The green value to set.</param>
|
||||||
|
/// <param name="b">The blue value to set.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color SetRGB(this Color color, byte? r = null, byte? g = null, byte? b = null)
|
||||||
|
=> new Color(color.A, r ?? color.GetR(), g ?? color.GetG(), b ?? color.GetB());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the given RGB value of this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red value to set.</param>
|
||||||
|
/// <param name="g">The green value to set.</param>
|
||||||
|
/// <param name="b">The blue value to set.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color SetRGB(this Color color, int? r = null, int? g = null, int? b = null)
|
||||||
|
=> new Color(color.A, r ?? color.GetR(), g ?? color.GetG(), b ?? color.GetB());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the given RGB value of this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The red value to set.</param>
|
||||||
|
/// <param name="g">The green value to set.</param>
|
||||||
|
/// <param name="b">The blue value to set.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color SetRGB(this Color color, double? r = null, double? g = null, double? b = null)
|
||||||
|
=> new Color(color.A, r ?? color.R, g ?? color.G, b ?? color.B);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the given alpha value of this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha value to set.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color SetA(this Color color, int a) => new Color(a, color.R, color.G, color.B);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the given alpha value of this color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The alpha value to set.</param>
|
||||||
|
/// <returns>The new color after the modification.</returns>
|
||||||
|
public static Color SetA(this Color color, double a) => new Color(a, color.R, color.G, color.B);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Conversion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current color as a RGB-HEX-string.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The RGB-HEX-string.</returns>
|
||||||
|
public static string AsRGBHexString(this Color color, bool leadingHash = true) => (leadingHash ? "#" : "") + ConversionHelper.ToHex(color.GetR(), color.GetG(), color.GetB());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current color as a ARGB-HEX-string.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The ARGB-HEX-string.</returns>
|
||||||
|
public static string AsARGBHexString(this Color color, bool leadingHash = true) => (leadingHash ? "#" : "") + ConversionHelper.ToHex(color.GetA(), color.GetR(), color.GetG(), color.GetB());
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Factory
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using a HEX-string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hexString">The HEX-representation of the color.</param>
|
||||||
|
/// <returns>The color created from the HEX-string.</returns>
|
||||||
|
public static Color FromHexString(string hexString)
|
||||||
{
|
{
|
||||||
3 => new Color(data[0], data[1], data[2]),
|
if ((hexString == null) || (hexString.Length < 6))
|
||||||
4 => new Color(data[0], data[1], data[2], data[3]),
|
throw new ArgumentException("Invalid hex string", nameof(hexString));
|
||||||
_ => throw new ArgumentException($"Invalid hex string '{hexString}'", nameof(hexString))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
if (hexString[0] == '#')
|
||||||
}
|
hexString = hexString.Substring(1);
|
||||||
|
|
||||||
|
byte[] data = ConversionHelper.HexToBytes(hexString);
|
||||||
|
if (data.Length == 3)
|
||||||
|
return new Color(data[0], data[1], data[2]);
|
||||||
|
if (data.Length == 4)
|
||||||
|
return new Color(data[0], data[1], data[2], data[3]);
|
||||||
|
|
||||||
|
throw new ArgumentException("Invalid hex string", nameof(hexString));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,207 +0,0 @@
|
|||||||
// ReSharper disable MemberCanBePrivate.Global
|
|
||||||
// ReSharper disable UnusedMember.Global
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains helper-methods and extension for the <see cref="Color"/>-type to work in the XYZ color space.
|
|
||||||
/// </summary>
|
|
||||||
public static class XYZColor
|
|
||||||
{
|
|
||||||
#region Getter
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the X component value (XYZ-color space) of this <see cref="Color"/> in the range [0..95.047].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The X component value of the color.</returns>
|
|
||||||
public static float GetX(this Color color) => color.GetXYZ().x;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Y component value (XYZ-color space) of this <see cref="Color"/> in the range [0..100].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The Y component value of the color.</returns>
|
|
||||||
public static float GetY(this Color color) => color.GetXYZ().y;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Z component value (XYZ-color space) of this <see cref="Color"/> in the range [0..108.883].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>The Z component value of the color.</returns>
|
|
||||||
public static float GetZ(this Color color) => color.GetXYZ().z;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the X, Y and Z component values (XYZ-color space) of this <see cref="Color"/>.
|
|
||||||
/// X in the range [0..95.047].
|
|
||||||
/// Y in the range [0..100].
|
|
||||||
/// Z in the range [0..108.883].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to get the value from.</param>
|
|
||||||
/// <returns>A tuple containing the X, Y and Z component value of the color.</returns>
|
|
||||||
public static (float x, float y, float z) GetXYZ(this Color color)
|
|
||||||
=> CaclulateXYZFromRGB(color.R, color.G, color.B);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Manipulation
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified XYZ values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="x">The X value to add.</param>
|
|
||||||
/// <param name="y">The Y value to add.</param>
|
|
||||||
/// <param name="z">The Z value to add.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color AddXYZ(this Color color, float x = 0, float y = 0, float z = 0)
|
|
||||||
{
|
|
||||||
(float cX, float cY, float cZ) = color.GetXYZ();
|
|
||||||
return Create(color.A, cX + x, cY + y, cZ + z);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subtracts the specified XYZ values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="x">The X value to subtract.</param>
|
|
||||||
/// <param name="y">The Y value to subtract.</param>
|
|
||||||
/// <param name="z">The Z value to subtract.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SubtractXYZ(this Color color, float x = 0, float y = 0, float z = 0)
|
|
||||||
{
|
|
||||||
(float cX, float cY, float cZ) = color.GetXYZ();
|
|
||||||
return Create(color.A, cX - x, cY - y, cZ - z);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Multiplies the specified XYZ values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="x">The X value to multiply.</param>
|
|
||||||
/// <param name="y">The Y value to multiply.</param>
|
|
||||||
/// <param name="z">The Z value to multiply.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color MultiplyXYZ(this Color color, float x = 1, float y = 1, float z = 1)
|
|
||||||
{
|
|
||||||
(float cX, float cY, float cZ) = color.GetXYZ();
|
|
||||||
return Create(color.A, cX * x, cY * y, cZ * z);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Divides the specified XYZ values to this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="x">The X value to divide.</param>
|
|
||||||
/// <param name="y">The Y value to divide.</param>
|
|
||||||
/// <param name="z">The Z value to divide.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color DivideXYZ(this Color color, float x = 1, float y = 1, float z = 1)
|
|
||||||
{
|
|
||||||
(float cX, float cY, float cZ) = color.GetXYZ();
|
|
||||||
return Create(color.A, cX / x, cY / y, cZ / z);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the specified X valueof this color.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">The color to modify.</param>
|
|
||||||
/// <param name="x">The X value to set.</param>
|
|
||||||
/// <param name="y">The Y value to set.</param>
|
|
||||||
/// <param name="z">The Z value to set.</param>
|
|
||||||
/// <returns>The new color after the modification.</returns>
|
|
||||||
public static Color SetXYZ(this Color color, float? x = null, float? y = null, float? z = null)
|
|
||||||
{
|
|
||||||
(float cX, float cY, float cZ) = color.GetXYZ();
|
|
||||||
return Create(color.A, x ?? cX, y ?? cY, z ?? cZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Factory
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using XYZ-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">The X component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="y">The Y component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="z">The Z component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(float x, float y, float z)
|
|
||||||
=> Create(1.0f, x, y, z);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using alpha and XYZ-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="x">The X component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="y">The Y component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="z">The Z component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(byte a, float x, float y, float z)
|
|
||||||
=> Create((float)a / byte.MaxValue, x, y, z);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using alpha and XYZ-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="x">The X component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="y">The Y component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="z">The Z component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(int a, float x, float y, float z)
|
|
||||||
=> Create((float)a / byte.MaxValue, x, y, z);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the <see cref="T:RGB.NET.Core.Color" /> struct using alpha and XYZ-Values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a">The alpha component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="x">The X component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="y">The Y component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <param name="z">The Z component value of this <see cref="Color"/>.</param>
|
|
||||||
/// <returns>The color created from the values.</returns>
|
|
||||||
public static Color Create(float a, float x, float y, float z)
|
|
||||||
{
|
|
||||||
(float r, float g, float b) = CalculateRGBFromXYZ(x, y, z);
|
|
||||||
return new Color(a, r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Helper
|
|
||||||
|
|
||||||
internal static (float x, float y, float z) CaclulateXYZFromRGB(float r, float g, float b)
|
|
||||||
{
|
|
||||||
r = ((r > 0.04045f) ? MathF.Pow(((r + 0.055f) / 1.055f), 2.4f) : (r / 12.92f)) * 100.0f;
|
|
||||||
g = ((g > 0.04045f) ? MathF.Pow(((g + 0.055f) / 1.055f), 2.4f) : (g / 12.92f)) * 100.0f;
|
|
||||||
b = ((b > 0.04045f) ? MathF.Pow(((b + 0.055f) / 1.055f), 2.4f) : (b / 12.92f)) * 100.0f;
|
|
||||||
|
|
||||||
float x = (r * 0.4124f) + (g * 0.3576f) + (b * 0.1805f);
|
|
||||||
float y = (r * 0.2126f) + (g * 0.7152f) + (b * 0.0722f);
|
|
||||||
float z = (r * 0.0193f) + (g * 0.1192f) + (b * 0.9505f);
|
|
||||||
|
|
||||||
return (x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static (float r, float g, float b) CalculateRGBFromXYZ(float x, float y, float z)
|
|
||||||
{
|
|
||||||
const float INVERSE_EXPONENT = 1.0f / 2.4f;
|
|
||||||
|
|
||||||
x /= 100.0f;
|
|
||||||
y /= 100.0f;
|
|
||||||
z /= 100.0f;
|
|
||||||
|
|
||||||
float r = (x * 3.2406f) + (y * -1.5372f) + (z * -0.4986f);
|
|
||||||
float g = (x * -0.9689f) + (y * 1.8758f) + (z * 0.0415f);
|
|
||||||
float b = (x * 0.0557f) + (y * -0.2040f) + (z * 1.0570f);
|
|
||||||
|
|
||||||
r = ((r > 0.0031308f) ? ((1.055f * (MathF.Pow(r, INVERSE_EXPONENT))) - 0.055f) : (12.92f * r));
|
|
||||||
g = ((g > 0.0031308f) ? ((1.055f * (MathF.Pow(g, INVERSE_EXPONENT))) - 0.055f) : (12.92f * g));
|
|
||||||
b = ((b > 0.0031308f) ? ((1.055f * (MathF.Pow(b, INVERSE_EXPONENT))) - 0.055f) : (12.92f * b));
|
|
||||||
|
|
||||||
return (r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -1,15 +1,16 @@
|
|||||||
// ReSharper disable UnusedMember.Global
|
// ReSharper disable UnusedMember.Global
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a generic color-correction.
|
|
||||||
/// </summary>
|
|
||||||
public interface IColorCorrection
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies the <see cref="IColorCorrection"/> to the specified <see cref="Color"/>.
|
/// Represents a generic color-correction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="color">The <see cref="Color"/> to correct.</param>
|
public interface IColorCorrection
|
||||||
void ApplyTo(ref Color color);
|
{
|
||||||
}
|
/// <summary>
|
||||||
|
/// Applies the <see cref="IColorCorrection"/> to the given <see cref="Color"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="Color"/> to correct.</param>
|
||||||
|
Color ApplyTo(Color color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
#if NET8_0
|
|
||||||
|
|
||||||
// ReSharper disable once CheckNamespace
|
|
||||||
namespace RGB.NET.Core.Compatibility.Net8;
|
|
||||||
|
|
||||||
public sealed class Lock;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -2,68 +2,64 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc cref="AbstractBindable" />
|
|
||||||
/// <inheritdoc cref="IDecoratable{T}" />
|
|
||||||
public abstract class AbstractDecoratable<T> : AbstractBindable, IDecoratable<T>
|
|
||||||
where T : IDecorator
|
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
/// <inheritdoc cref="AbstractBindable" />
|
||||||
|
/// <inheritdoc cref="IDecoratable{T}" />
|
||||||
private readonly List<T> _decorators = [];
|
public abstract class AbstractDecoratable<T> : AbstractBindable, IDecoratable<T>
|
||||||
|
where T : IDecorator
|
||||||
/// <inheritdoc />
|
|
||||||
public IReadOnlyList<T> Decorators { get; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="AbstractDecoratable{T}"/> class.
|
|
||||||
/// </summary>
|
|
||||||
protected AbstractDecoratable()
|
|
||||||
{
|
{
|
||||||
Decorators = new ReadOnlyCollection<T>(_decorators);
|
#region Properties & Fields
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
private readonly List<T> _decorators = new List<T>();
|
||||||
|
|
||||||
#region Methods
|
/// <inheritdoc />
|
||||||
|
public IReadOnlyCollection<T> Decorators
|
||||||
/// <inheritdoc />
|
|
||||||
public void AddDecorator(T decorator)
|
|
||||||
{
|
|
||||||
lock (Decorators)
|
|
||||||
{
|
{
|
||||||
_decorators.Add(decorator);
|
get
|
||||||
_decorators.Sort((d1, d2) => d1.Order.CompareTo(d2.Order));
|
{
|
||||||
|
lock (_decorators)
|
||||||
|
return new ReadOnlyCollection<T>(_decorators);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
decorator.OnAttached(this);
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void AddDecorator(T decorator)
|
||||||
|
{
|
||||||
|
lock (Decorators)
|
||||||
|
{
|
||||||
|
_decorators.Add(decorator);
|
||||||
|
_decorators.Sort((d1, d2) => d1.Order.CompareTo(d2.Order));
|
||||||
|
}
|
||||||
|
|
||||||
|
decorator.OnAttached(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void RemoveDecorator(T decorator)
|
||||||
|
{
|
||||||
|
lock (Decorators)
|
||||||
|
_decorators.Remove(decorator);
|
||||||
|
|
||||||
|
decorator.OnDetached(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void RemoveAllDecorators()
|
||||||
|
{
|
||||||
|
IEnumerable<T> decorators;
|
||||||
|
|
||||||
|
lock (Decorators)
|
||||||
|
decorators = Decorators.ToList();
|
||||||
|
|
||||||
|
foreach (T decorator in decorators)
|
||||||
|
RemoveDecorator(decorator);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/// <inheritdoc />
|
|
||||||
public void RemoveDecorator(T decorator)
|
|
||||||
{
|
|
||||||
lock (Decorators)
|
|
||||||
_decorators.Remove(decorator);
|
|
||||||
|
|
||||||
decorator.OnDetached(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void RemoveAllDecorators()
|
|
||||||
{
|
|
||||||
IEnumerable<T> decorators;
|
|
||||||
|
|
||||||
lock (Decorators)
|
|
||||||
decorators = Decorators.ToList();
|
|
||||||
|
|
||||||
foreach (T decorator in decorators)
|
|
||||||
RemoveDecorator(decorator);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
@ -2,60 +2,61 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc cref="AbstractBindable" />
|
|
||||||
/// <inheritdoc cref="IDecorator" />
|
|
||||||
public abstract class AbstractDecorator : AbstractBindable, IDecorator
|
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
/// <inheritdoc cref="AbstractBindable" />
|
||||||
|
/// <inheritdoc cref="IDecorator" />
|
||||||
private bool _isEnabled = true;
|
public abstract class AbstractDecorator : AbstractBindable, IDecorator
|
||||||
/// <inheritdoc />
|
|
||||||
public bool IsEnabled
|
|
||||||
{
|
{
|
||||||
get => _isEnabled;
|
#region Properties & Fields
|
||||||
set => SetProperty(ref _isEnabled, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int _order;
|
private bool _isEnabled = true;
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int Order
|
public bool IsEnabled
|
||||||
{
|
|
||||||
get => _order;
|
|
||||||
set => SetProperty(ref _order, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a readonly-list of all <see cref="IDecoratable"/> this decorator is attached to.
|
|
||||||
/// </summary>
|
|
||||||
protected List<IDecoratable> DecoratedObjects { get; } = [];
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual void OnAttached(IDecoratable decoratable) => DecoratedObjects.Add(decoratable);
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual void OnDetached(IDecoratable decoratable) => DecoratedObjects.Remove(decoratable);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Detaches the decorator from all <see cref="IDecoratable"/> it is currently attached to.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void Detach()
|
|
||||||
{
|
|
||||||
List<IDecoratable> decoratables = [..DecoratedObjects];
|
|
||||||
foreach (IDecoratable decoratable in decoratables)
|
|
||||||
{
|
{
|
||||||
IEnumerable<Type> types = decoratable.GetType().GetInterfaces().Where(t => t.IsGenericType
|
get => _isEnabled;
|
||||||
&& (t.Name == typeof(IDecoratable<>).Name)
|
set => SetProperty(ref _isEnabled, value);
|
||||||
&& t.GenericTypeArguments[0].IsInstanceOfType(this));
|
|
||||||
foreach (Type decoratableType in types)
|
|
||||||
decoratableType.GetMethod(nameof(IDecoratable<IDecorator>.RemoveDecorator))?.Invoke(decoratable, [this]);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
private int _order;
|
||||||
}
|
/// <inheritdoc />
|
||||||
|
public int Order
|
||||||
|
{
|
||||||
|
get => _order;
|
||||||
|
set => SetProperty(ref _order, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a readonly-list of all <see cref="IDecoratable"/> this decorator is attached to.
|
||||||
|
/// </summary>
|
||||||
|
protected List<IDecoratable> DecoratedObjects { get; } = new List<IDecoratable>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void OnAttached(IDecoratable decoratable) => DecoratedObjects.Add(decoratable);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void OnDetached(IDecoratable decoratable) => DecoratedObjects.Remove(decoratable);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Detaches the decorator from all <see cref="IDecoratable"/> it is currently attached to.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void Detach()
|
||||||
|
{
|
||||||
|
List<IDecoratable> decoratables = new List<IDecoratable>(DecoratedObjects);
|
||||||
|
foreach (IDecoratable decoratable in decoratables)
|
||||||
|
{
|
||||||
|
IEnumerable<Type> types = decoratable.GetType().GetInterfaces().Where(t => t.IsGenericType
|
||||||
|
&& (t.Name == typeof(IDecoratable<>).Name)
|
||||||
|
&& t.GenericTypeArguments[0].IsInstanceOfType(this));
|
||||||
|
foreach (Type decoratableType in types)
|
||||||
|
decoratableType.GetMethod(nameof(IDecoratable<IDecorator>.RemoveDecorator))?.Invoke(decoratable, new object[] { this });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,71 +1,65 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a basic decorator which is aware of the <see cref="E:RGB.NET.Core.RGBSurface.Updating" /> event.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class AbstractUpdateAwareDecorator : AbstractDecorator
|
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the surface this decorator is attached to.
|
|
||||||
/// </summary>
|
|
||||||
protected RGBSurface Surface { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets if the <see cref="AbstractUpdateAwareDecorator"/> should call <see cref="Update"/> even if the Decorator is disabled.
|
|
||||||
/// </summary>
|
|
||||||
protected bool UpdateIfDisabled { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="AbstractUpdateAwareDecorator"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="surface">The surface this decorator is attached to.</param>
|
|
||||||
/// <param name="updateIfDisabled">Bool indicating if the <see cref="AbstractUpdateAwareDecorator"/> should call <see cref="Update"/> even if the Decorator is disabled.</param>
|
|
||||||
protected AbstractUpdateAwareDecorator(RGBSurface surface, bool updateIfDisabled = false)
|
|
||||||
{
|
|
||||||
this.Surface = surface;
|
|
||||||
this.UpdateIfDisabled = updateIfDisabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnAttached(IDecoratable decoratable)
|
|
||||||
{
|
|
||||||
if (DecoratedObjects.Count == 0)
|
|
||||||
Surface.Updating += OnSurfaceUpdating;
|
|
||||||
|
|
||||||
base.OnAttached(decoratable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void OnDetached(IDecoratable decoratable)
|
|
||||||
{
|
|
||||||
base.OnDetached(decoratable);
|
|
||||||
|
|
||||||
if (DecoratedObjects.Count == 0)
|
|
||||||
Surface.Updating -= OnSurfaceUpdating;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSurfaceUpdating(UpdatingEventArgs args)
|
|
||||||
{
|
|
||||||
if (IsEnabled || UpdateIfDisabled)
|
|
||||||
Update(args.DeltaTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates this <see cref="AbstractUpdateAwareDecorator"/>.
|
/// Represents a basic decorator which is aware of the <see cref="E:RGB.NET.Core.RGBSurface.Updating" /> event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="deltaTime">The elapsed time (in seconds) since the last update.</param>
|
public abstract class AbstractUpdateAwareDecorator : AbstractDecorator
|
||||||
protected abstract void Update(double deltaTime);
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
}
|
/// Gets or sets if the <see cref="AbstractUpdateAwareDecorator"/> should call <see cref="Update"/> even if the Decorator is disabled.
|
||||||
|
/// </summary>
|
||||||
|
protected bool UpdateIfDisabled { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AbstractUpdateAwareDecorator"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="updateIfDisabled">Bool indicating if the <see cref="AbstractUpdateAwareDecorator"/> should call <see cref="Update"/> even if the Decorator is disabled.</param>
|
||||||
|
protected AbstractUpdateAwareDecorator(bool updateIfDisabled = false)
|
||||||
|
{
|
||||||
|
this.UpdateIfDisabled = updateIfDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnAttached(IDecoratable decoratable)
|
||||||
|
{
|
||||||
|
if (DecoratedObjects.Count == 0)
|
||||||
|
RGBSurface.Instance.Updating += OnSurfaceUpdating;
|
||||||
|
|
||||||
|
base.OnAttached(decoratable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnDetached(IDecoratable decoratable)
|
||||||
|
{
|
||||||
|
base.OnDetached(decoratable);
|
||||||
|
|
||||||
|
if (DecoratedObjects.Count == 0)
|
||||||
|
RGBSurface.Instance.Updating -= OnSurfaceUpdating;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSurfaceUpdating(UpdatingEventArgs args)
|
||||||
|
{
|
||||||
|
if (IsEnabled || UpdateIfDisabled)
|
||||||
|
Update(args.DeltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates this <see cref="AbstractUpdateAwareDecorator"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="deltaTime">The elapsed time (in seconds) since the last update.</param>
|
||||||
|
protected abstract void Update(double deltaTime);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,16 +1,17 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a <see cref="T:RGB.NET.Core.IDecorator" /> decorating a <see cref="T:RGB.NET.Core.IBrush" />.
|
|
||||||
/// </summary>
|
|
||||||
public interface IBrushDecorator : IDecorator
|
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decorator-Method called by the <see cref="IBrush"/>.
|
/// Represents a <see cref="T:RGB.NET.Core.IDecorator" /> decorating a <see cref="T:RGB.NET.Core.IBrush" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rectangle">The rectangle in which the <see cref="IBrush"/> should be drawn.</param>
|
public interface IBrushDecorator : IDecorator
|
||||||
/// <param name="renderTarget">The target (key/point) from which the <see cref="Color"/> should be taken.</param>
|
{
|
||||||
/// <param name="color">The <see cref="Color"/> to be modified.</param>
|
/// <summary>
|
||||||
void ManipulateColor(Rectangle rectangle, RenderTarget renderTarget, ref Color color);
|
/// Decorator-Method called by the <see cref="IBrush"/>.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <param name="rectangle">The rectangle in which the <see cref="IBrush"/> should be drawn.</param>
|
||||||
|
/// <param name="renderTarget">The target (key/point) from which the <see cref="Color"/> should be taken.</param>
|
||||||
|
/// <param name="color">The <see cref="Color"/> to be modified.</param>
|
||||||
|
Color ManipulateColor(Rectangle rectangle, BrushRenderTarget renderTarget, Color color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,40 +1,42 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a basic decoratable.
|
|
||||||
/// </summary>
|
|
||||||
public interface IDecoratable : INotifyPropertyChanged;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a basic decoratable for a specific type of <see cref="T:RGB.NET.Core.IDecorator" />
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of decorators this decoratable can be decorated with.</typeparam>
|
|
||||||
public interface IDecoratable<T> : IDecoratable
|
|
||||||
where T : IDecorator
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a readonly-list of all <see cref="IDecorator"/> attached to this <see cref="IDecoratable{T}"/>.
|
/// Represents a basic decoratable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IReadOnlyList<T> Decorators { get; }
|
public interface IDecoratable : INotifyPropertyChanged
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds an <see cref="IDecorator"/> to the <see cref="IDecoratable"/>.
|
/// Represents a basic decoratable for a specific type of <see cref="T:RGB.NET.Core.IDecorator" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="decorator">The <see cref="IDecorator"/> to be added.</param>
|
/// <typeparam name="T"></typeparam>
|
||||||
void AddDecorator(T decorator);
|
public interface IDecoratable<T> : IDecoratable
|
||||||
|
where T : IDecorator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a readonly-list of all <see cref="IDecorator"/> attached to this <see cref="IDecoratable{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlyCollection<T> Decorators { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes an <see cref="IDecorator"/> from the <see cref="IDecoratable"/>.
|
/// Adds an <see cref="IDecorator"/> to the <see cref="IDecoratable"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="decorator">The <see cref="IDecorator"/> to be removed.</param>
|
/// <param name="decorator">The <see cref="IDecorator"/> to be added.</param>
|
||||||
void RemoveDecorator(T decorator);
|
void AddDecorator(T decorator);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes all <see cref="IDecorator"/> from the <see cref="IDecoratable"/>.
|
/// Removes an <see cref="IDecorator"/> from the <see cref="IDecoratable"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void RemoveAllDecorators();
|
/// <param name="decorator">The <see cref="IDecorator"/> to be removed.</param>
|
||||||
}
|
void RemoveDecorator(T decorator);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all <see cref="IDecorator"/> from the <see cref="IDecoratable"/>.
|
||||||
|
/// </summary>
|
||||||
|
void RemoveAllDecorators();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,38 +1,39 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a basic decorator.
|
|
||||||
/// </summary>
|
|
||||||
public interface IDecorator
|
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets if the <see cref="IDecorator"/> is enabled and will be used.
|
/// Represents a basic decorator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsEnabled { get; set; }
|
public interface IDecorator
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the order in which multiple decorators should be applied on the same object.
|
/// Gets or sets if the <see cref="IDecorator"/> is enabled and will be used.
|
||||||
/// Higher orders are processed first.
|
/// </summary>
|
||||||
/// </summary>
|
bool IsEnabled { get; set; }
|
||||||
int Order { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
|
/// Gets or sets the order in which multiple decorators should be applied on the same object.
|
||||||
|
/// Higher orders are processed first.
|
||||||
|
/// </summary>
|
||||||
|
int Order { get; set; }
|
||||||
|
|
||||||
#region Methods
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
#region Methods
|
||||||
/// Attaches this <see cref="IDecorator"/> to the specified target.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="decoratable">The object this <see cref="IDecorator"/> should be attached to.</param>
|
|
||||||
void OnAttached(IDecoratable decoratable);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Detaches this <see cref="IDecorator"/> from the specified target.
|
/// Attaches this <see cref="IDecorator"/> to the given target.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="decoratable">The object this <see cref="IDecorator"/> should be detached from.</param>
|
/// <param name="decoratable">The object this <see cref="IDecorator"/> should be attached to.</param>
|
||||||
void OnDetached(IDecoratable decoratable);
|
void OnAttached(IDecoratable decoratable);
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
}
|
/// Detaches this <see cref="IDecorator"/> from the given target.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="decoratable">The object this <see cref="IDecorator"/> should be detached from.</param>
|
||||||
|
void OnDetached(IDecoratable decoratable);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a basic decorator decorating a <see cref="T:RGB.NET.Core.ILedGroup" />.
|
/// Represents a basic decorator decorating a <see cref="T:RGB.NET.Core.ILedGroup" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ILedGroupDecorator : IDecorator;
|
public interface ILedGroupDecorator : IDecorator
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -3,246 +3,296 @@
|
|||||||
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using RGB.NET.Core.Layout;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc cref="AbstractBindable" />
|
|
||||||
/// <inheritdoc cref="IRGBDevice{TDeviceInfo}" />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a generic RGB-device.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class AbstractRGBDevice<TDeviceInfo> : Placeable, IRGBDevice<TDeviceInfo>
|
|
||||||
where TDeviceInfo : class, IRGBDeviceInfo
|
|
||||||
{
|
{
|
||||||
private RGBSurface? _surface;
|
/// <inheritdoc cref="AbstractBindable" />
|
||||||
|
/// <inheritdoc cref="IRGBDevice{TDeviceInfo}" />
|
||||||
#region Properties & Fields
|
/// <summary>
|
||||||
|
/// Represents a generic RGB-device.
|
||||||
RGBSurface? IRGBDevice.Surface
|
/// </summary>
|
||||||
|
public abstract class AbstractRGBDevice<TDeviceInfo> : AbstractBindable, IRGBDevice<TDeviceInfo>
|
||||||
|
where TDeviceInfo : class, IRGBDeviceInfo
|
||||||
{
|
{
|
||||||
get => _surface;
|
#region Properties & Fields
|
||||||
set
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public abstract TDeviceInfo DeviceInfo { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
IRGBDeviceInfo IRGBDevice.DeviceInfo => DeviceInfo;
|
||||||
|
|
||||||
|
private Point _location = new Point(0, 0);
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Point Location
|
||||||
{
|
{
|
||||||
if (SetProperty(ref _surface, value))
|
get => _location;
|
||||||
|
set
|
||||||
{
|
{
|
||||||
if (value == null) OnDetached();
|
if (SetProperty(ref _location, value))
|
||||||
else OnAttached();
|
UpdateActualData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
private Size _size = Size.Invalid;
|
||||||
public TDeviceInfo DeviceInfo { get; }
|
/// <inheritdoc />
|
||||||
|
public Size Size
|
||||||
/// <inheritdoc />
|
|
||||||
IRGBDeviceInfo IRGBDevice.DeviceInfo => DeviceInfo;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IList<IColorCorrection> ColorCorrections { get; } = [];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets if the device needs to be flushed on every update.
|
|
||||||
/// </summary>
|
|
||||||
protected bool RequiresFlush { get; set; } = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a dictionary containing all <see cref="Led"/> of the <see cref="IRGBDevice"/>.
|
|
||||||
/// </summary>
|
|
||||||
protected Dictionary<LedId, Led> LedMapping { get; } = [];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the update queue used to update this device.
|
|
||||||
/// </summary>
|
|
||||||
protected IUpdateQueue UpdateQueue { get; }
|
|
||||||
|
|
||||||
#region Indexer
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
Led? IRGBDevice.this[LedId ledId] => LedMapping.GetValueOrDefault(ledId);
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
Led? IRGBDevice.this[Point location] => LedMapping.Values.FirstOrDefault(x => x.Boundary.Contains(location));
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
IEnumerable<Led> IRGBDevice.this[Rectangle referenceRect, double minOverlayPercentage]
|
|
||||||
=> LedMapping.Values.Where(x => referenceRect.CalculateIntersectPercentage(x.Boundary) >= minOverlayPercentage);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="AbstractRGBDevice{T}"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="deviceInfo">The device info of this device.</param>
|
|
||||||
/// <param name="updateQueue">The queue used to update this device.</param>
|
|
||||||
protected AbstractRGBDevice(TDeviceInfo deviceInfo, IUpdateQueue updateQueue)
|
|
||||||
{
|
|
||||||
this.DeviceInfo = deviceInfo;
|
|
||||||
this.UpdateQueue = updateQueue;
|
|
||||||
|
|
||||||
UpdateQueue.AddReferencingObject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual void Update(bool flushLeds = false)
|
|
||||||
{
|
|
||||||
// Device-specific updates
|
|
||||||
DeviceUpdate();
|
|
||||||
|
|
||||||
// Send LEDs to SDK
|
|
||||||
UpdateLeds(GetLedsToUpdate(flushLeds));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets an enumerable of LEDs that are changed and requires an update.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="flushLeds">Forces all LEDs to be treated as dirty.</param>
|
|
||||||
/// <returns>The collection LEDs to update.</returns>
|
|
||||||
protected virtual IEnumerable<Led> GetLedsToUpdate(bool flushLeds) => ((RequiresFlush || flushLeds || UpdateQueue.RequiresFlush) ? LedMapping.Values : LedMapping.Values.Where(x => x.IsDirty)).Where(led => led.RequestedColor?.A > 0);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets an enumerable of a custom data and color tuple for the specified leds.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Applies all <see cref="ColorCorrections"/>.
|
|
||||||
/// if no <see cref="Led.CustomData"/> ist specified the <see cref="Led.Id"/> is used.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="led">The of led to convert.</param>
|
|
||||||
/// <returns>The enumerable of custom data and color tuples for the specified leds.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
protected (object key, Color color) GetUpdateData(Led led)
|
|
||||||
{
|
|
||||||
Color color = led.Color;
|
|
||||||
object key = led.CustomData ?? led.Id;
|
|
||||||
|
|
||||||
// ReSharper disable once ForCanBeConvertedToForeach - This causes an allocation that's not really needed here
|
|
||||||
for (int i = 0; i < ColorCorrections.Count; i++)
|
|
||||||
ColorCorrections[i].ApplyTo(ref color);
|
|
||||||
|
|
||||||
return (key, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sends all the updated <see cref="Led"/> to the device.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void UpdateLeds(IEnumerable<Led> ledsToUpdate)
|
|
||||||
{
|
|
||||||
(object key, Color color)[] buffer = ArrayPool<(object, Color)>.Shared.Rent(LedMapping.Count);
|
|
||||||
|
|
||||||
int counter = 0;
|
|
||||||
foreach (Led led in ledsToUpdate)
|
|
||||||
{
|
{
|
||||||
led.Update();
|
get => _size;
|
||||||
|
protected set
|
||||||
buffer[counter] = GetUpdateData(led);
|
{
|
||||||
++counter;
|
if (SetProperty(ref _size, value))
|
||||||
|
UpdateActualData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateQueue.SetData(new ReadOnlySpan<(object, Color)>(buffer)[..counter]);
|
private Size _actualSize;
|
||||||
|
/// <inheritdoc />
|
||||||
ArrayPool<(object, Color)>.Shared.Return(buffer);
|
public Size ActualSize
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual void Dispose()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
UpdateQueue.RemoveReferencingObject(this);
|
get => _actualSize;
|
||||||
if (!UpdateQueue.HasActiveReferences())
|
private set => SetProperty(ref _actualSize, value);
|
||||||
UpdateQueue.Dispose();
|
|
||||||
}
|
}
|
||||||
catch { /* :( */ }
|
|
||||||
try { LedMapping.Clear(); } catch { /* this really shouldn't happen */ }
|
|
||||||
|
|
||||||
IdGenerator.ResetCounter(GetType().Assembly);
|
private Rectangle _deviceRectangle;
|
||||||
|
/// <inheritdoc />
|
||||||
GC.SuppressFinalize(this);
|
public Rectangle DeviceRectangle
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs device specific updates.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void DeviceUpdate()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual Led? AddLed(LedId ledId, Point location, Size size, object? customData = null)
|
|
||||||
{
|
|
||||||
if ((ledId == LedId.Invalid) || LedMapping.ContainsKey(ledId)) return null;
|
|
||||||
|
|
||||||
Led led = new(this, ledId, location, size, customData ?? GetLedCustomData(ledId));
|
|
||||||
LedMapping.Add(ledId, led);
|
|
||||||
return led;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual Led? RemoveLed(LedId ledId)
|
|
||||||
{
|
|
||||||
if (ledId == LedId.Invalid) return null;
|
|
||||||
if (!LedMapping.TryGetValue(ledId, out Led? led)) return null;
|
|
||||||
|
|
||||||
LedMapping.Remove(ledId);
|
|
||||||
return led;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the custom data associated with the specified LED.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledId">The id of the led.</param>
|
|
||||||
/// <returns>The custom data for the specified LED.</returns>
|
|
||||||
protected virtual object? GetLedCustomData(LedId ledId) => null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when the device is attached to a surface.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// When overriden base should be called to validate boundries.
|
|
||||||
/// </remarks>
|
|
||||||
protected virtual void OnAttached()
|
|
||||||
{
|
|
||||||
if (Location == Point.Invalid) Location = new Point(0, 0);
|
|
||||||
if (Size == Size.Invalid)
|
|
||||||
{
|
{
|
||||||
Rectangle ledRectangle = new(this.Select(x => x.Boundary));
|
get => _deviceRectangle;
|
||||||
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
|
private set => SetProperty(ref _deviceRectangle, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Scale _scale = new Scale(1);
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Scale Scale
|
||||||
|
{
|
||||||
|
get => _scale;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _scale, value))
|
||||||
|
UpdateActualData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rotation _rotation = new Rotation(0);
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Rotation Rotation
|
||||||
|
{
|
||||||
|
get => _rotation;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _rotation, value))
|
||||||
|
UpdateActualData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets if the device needs to be flushed on every update.
|
||||||
|
/// </summary>
|
||||||
|
protected bool RequiresFlush { get; set; } = false;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public DeviceUpdateMode UpdateMode { get; set; } = DeviceUpdateMode.Sync;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a dictionary containing all <see cref="Led"/> of the <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
protected Dictionary<LedId, Led> LedMapping { get; } = new Dictionary<LedId, Led>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a dictionary containing all <see cref="IRGBDeviceSpecialPart"/> associated with this <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
protected Dictionary<Type, IRGBDeviceSpecialPart> SpecialDeviceParts { get; } = new Dictionary<Type, IRGBDeviceSpecialPart>();
|
||||||
|
|
||||||
|
#region Indexer
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
Led IRGBDevice.this[LedId ledId] => LedMapping.TryGetValue(ledId, out Led led) ? led : null;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
Led IRGBDevice.this[Point location] => LedMapping.Values.FirstOrDefault(x => x.LedRectangle.Contains(location));
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
IEnumerable<Led> IRGBDevice.this[Rectangle referenceRect, double minOverlayPercentage]
|
||||||
|
=> LedMapping.Values.Where(x => referenceRect.CalculateIntersectPercentage(x.LedRectangle) >= minOverlayPercentage);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
private void UpdateActualData()
|
||||||
|
{
|
||||||
|
ActualSize = Size * Scale;
|
||||||
|
DeviceRectangle = new Rectangle(Location, new Rectangle(new Rectangle(Location, ActualSize).Rotate(Rotation)).Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void Update(bool flushLeds = false)
|
||||||
|
{
|
||||||
|
// Device-specific updates
|
||||||
|
DeviceUpdate();
|
||||||
|
|
||||||
|
// Send LEDs to SDK
|
||||||
|
List<Led> ledsToUpdate = GetLedsToUpdate(flushLeds)?.ToList() ?? new List<Led>();
|
||||||
|
foreach (Led ledToUpdate in ledsToUpdate)
|
||||||
|
ledToUpdate.Update();
|
||||||
|
|
||||||
|
if (UpdateMode.HasFlag(DeviceUpdateMode.Sync))
|
||||||
|
UpdateLeds(ledsToUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual IEnumerable<Led> GetLedsToUpdate(bool flushLeds) => ((RequiresFlush || flushLeds) ? LedMapping.Values : LedMapping.Values.Where(x => x.IsDirty));
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void SyncBack()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void Dispose()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SpecialDeviceParts.Clear();
|
||||||
|
LedMapping.Clear();
|
||||||
|
}
|
||||||
|
catch { /* this really shouldn't happen */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs device specific updates.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void DeviceUpdate()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends all the updated <see cref="Led"/> to the device.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract void UpdateLeds(IEnumerable<Led> ledsToUpdate);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the <see cref="Led"/> with the specified id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ledId">The <see cref="LedId"/> to initialize.</param>
|
||||||
|
/// <param name="ledRectangle">The <see cref="Rectangle"/> representing the position of the <see cref="Led"/> to initialize.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Obsolete("Use InitializeLed(LedId ledId, Point location, Size size) instead.")]
|
||||||
|
protected virtual Led InitializeLed(LedId ledId, Rectangle rectangle) => InitializeLed(ledId, rectangle.Location, rectangle.Size);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the <see cref="Led"/> with the specified id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ledId">The <see cref="LedId"/> to initialize.</param>
|
||||||
|
/// <param name="location">The location of the <see cref="Led"/> to initialize.</param>
|
||||||
|
/// <param name="size">The size of the <see cref="Led"/> to initialize.</param>
|
||||||
|
/// <returns>The initialized led.</returns>
|
||||||
|
protected virtual Led InitializeLed(LedId ledId, Point location, Size size)
|
||||||
|
{
|
||||||
|
if ((ledId == LedId.Invalid) || LedMapping.ContainsKey(ledId)) return null;
|
||||||
|
|
||||||
|
Led led = new Led(this, ledId, location, size, CreateLedCustomData(ledId));
|
||||||
|
LedMapping.Add(ledId, led);
|
||||||
|
return led;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the give <see cref="Color"/> to the <see cref="Led"/> ignoring internal workflows regarding locks and update-requests.
|
||||||
|
/// This should be only used for syncbacks!
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="led">The <see cref="Led"/> the <see cref="Color"/> should be aplied to.</param>
|
||||||
|
/// <param name="color">The <see cref="Color"/> to apply.</param>
|
||||||
|
protected virtual void SetLedColorWithoutRequest(Led led, Color color)
|
||||||
|
{
|
||||||
|
if (led == null) return;
|
||||||
|
|
||||||
|
led.InternalColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the given layout.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="layoutPath">The file containing the layout.</param>
|
||||||
|
/// <param name="imageLayout">The name of the layout used to get the images of the leds.</param>
|
||||||
|
/// <param name="createMissingLeds">If set to true a new led is initialized for every id in the layout if it doesn't already exist.</param>
|
||||||
|
protected virtual DeviceLayout ApplyLayoutFromFile(string layoutPath, string imageLayout, bool createMissingLeds = false)
|
||||||
|
{
|
||||||
|
DeviceLayout layout = DeviceLayout.Load(layoutPath);
|
||||||
|
if (layout != null)
|
||||||
|
{
|
||||||
|
string imageBasePath = string.IsNullOrWhiteSpace(layout.ImageBasePath) ? null : PathHelper.GetAbsolutePath(this, layout.ImageBasePath);
|
||||||
|
if ((imageBasePath != null) && !string.IsNullOrWhiteSpace(layout.DeviceImage) && (DeviceInfo != null))
|
||||||
|
DeviceInfo.Image = new Uri(Path.Combine(imageBasePath, layout.DeviceImage), UriKind.Absolute);
|
||||||
|
|
||||||
|
LedImageLayout ledImageLayout = layout.LedImageLayouts.FirstOrDefault(x => string.Equals(x.Layout, imageLayout, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
Size = new Size(layout.Width, layout.Height);
|
||||||
|
|
||||||
|
if (layout.Leds != null)
|
||||||
|
foreach (LedLayout layoutLed in layout.Leds)
|
||||||
|
{
|
||||||
|
if (Enum.TryParse(layoutLed.Id, true, out LedId ledId))
|
||||||
|
{
|
||||||
|
if (!LedMapping.TryGetValue(ledId, out Led led) && createMissingLeds)
|
||||||
|
led = InitializeLed(ledId, new Point(), new Size());
|
||||||
|
|
||||||
|
if (led != null)
|
||||||
|
{
|
||||||
|
led.Location = new Point(layoutLed.X, layoutLed.Y);
|
||||||
|
led.Size = new Size(layoutLed.Width, layoutLed.Height);
|
||||||
|
led.Shape = layoutLed.Shape;
|
||||||
|
led.ShapeData = layoutLed.ShapeData;
|
||||||
|
|
||||||
|
LedImage image = ledImageLayout?.LedImages.FirstOrDefault(x => x.Id == layoutLed.Id);
|
||||||
|
if ((imageBasePath != null) && !string.IsNullOrEmpty(image?.Image))
|
||||||
|
led.Image = new Uri(Path.Combine(imageBasePath, image.Image), UriKind.Absolute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates provider-specific data associated with this <see cref="LedId"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ledId">The <see cref="LedId"/>.</param>
|
||||||
|
protected virtual object CreateLedCustomData(LedId ledId) => null;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void AddSpecialDevicePart<T>(T specialDevicePart)
|
||||||
|
where T : class, IRGBDeviceSpecialPart
|
||||||
|
=> SpecialDeviceParts[typeof(T)] = specialDevicePart;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public T GetSpecialDevicePart<T>()
|
||||||
|
where T : class, IRGBDeviceSpecialPart
|
||||||
|
=> SpecialDeviceParts.TryGetValue(typeof(T), out IRGBDeviceSpecialPart devicePart) ? (T)devicePart : default;
|
||||||
|
|
||||||
|
#region Enumerator
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator that iterates over all <see cref="T:RGB.NET.Core.Led" /> of the <see cref="T:RGB.NET.Core.IRGBDevice" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An enumerator for all <see cref="T:RGB.NET.Core.Led" /> of the <see cref="T:RGB.NET.Core.IRGBDevice" />.</returns>
|
||||||
|
public IEnumerator<Led> GetEnumerator() => LedMapping.Values.GetEnumerator();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator that iterates over all <see cref="T:RGB.NET.Core.Led" /> of the <see cref="T:RGB.NET.Core.IRGBDevice" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An enumerator for all <see cref="T:RGB.NET.Core.Led" /> of the <see cref="T:RGB.NET.Core.IRGBDevice" />.</returns>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Called when the device is detached from a surface.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void OnDetached() { }
|
|
||||||
|
|
||||||
#region Enumerator
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Returns an enumerator that iterates over all <see cref="T:RGB.NET.Core.Led" /> of the <see cref="T:RGB.NET.Core.IRGBDevice" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>An enumerator for all <see cref="T:RGB.NET.Core.Led" /> of the <see cref="T:RGB.NET.Core.IRGBDevice" />.</returns>
|
|
||||||
public IEnumerator<Led> GetEnumerator() => LedMapping.Values.GetEnumerator();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Returns an enumerator that iterates over all <see cref="T:RGB.NET.Core.Led" /> of the <see cref="T:RGB.NET.Core.IRGBDevice" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>An enumerator for all <see cref="T:RGB.NET.Core.Led" /> of the <see cref="T:RGB.NET.Core.IRGBDevice" />.</returns>
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,282 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the abstract base implementation for a <see cref="IRGBDeviceProvider"/>.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
|
|
||||||
{
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
private bool _isDisposed = false;
|
|
||||||
|
|
||||||
private readonly double _defaultUpdateRateHardLimit;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool IsInitialized { get; protected set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool ThrowsExceptions { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The list of devices managed by this device-provider.
|
|
||||||
/// </summary>
|
|
||||||
protected List<IRGBDevice> InternalDevices { get; } = [];
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual IReadOnlyList<IRGBDevice> Devices => new ReadOnlyCollection<IRGBDevice>(InternalDevices);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the dictionary containing the registered update triggers.
|
|
||||||
/// Normally <see cref="UpdateTriggers"/> should be used to access them.
|
|
||||||
/// </summary>
|
|
||||||
protected Dictionary<int, IDeviceUpdateTrigger> UpdateTriggerMapping { get; } = [];
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IReadOnlyList<(int id, IDeviceUpdateTrigger trigger)> UpdateTriggers => new ReadOnlyCollection<(int id, IDeviceUpdateTrigger trigger)>(UpdateTriggerMapping.Select(x => (x.Key, x.Value)).ToList());
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Events
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public event EventHandler<ExceptionEventArgs>? Exception;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public event EventHandler<DevicesChangedEventArgs>? DevicesChanged;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="AbstractRGBDeviceProvider" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="defaultUpdateRateHardLimit">The update rate hard limit all update triggers for this device provider are initialized with.</param>
|
|
||||||
protected AbstractRGBDeviceProvider(double defaultUpdateRateHardLimit = 0)
|
|
||||||
{
|
|
||||||
this._defaultUpdateRateHardLimit = defaultUpdateRateHardLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
~AbstractRGBDeviceProvider() => Dispose(false);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool Initialize(RGBDeviceType loadFilter = RGBDeviceType.All, bool throwExceptions = false)
|
|
||||||
{
|
|
||||||
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
|
|
||||||
|
|
||||||
ThrowsExceptions = throwExceptions;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Reset();
|
|
||||||
|
|
||||||
InitializeSDK();
|
|
||||||
|
|
||||||
foreach (IRGBDevice device in GetLoadedDevices(loadFilter))
|
|
||||||
AddDevice(device);
|
|
||||||
|
|
||||||
foreach (IDeviceUpdateTrigger updateTrigger in UpdateTriggerMapping.Values)
|
|
||||||
updateTrigger.Start();
|
|
||||||
|
|
||||||
IsInitialized = true;
|
|
||||||
}
|
|
||||||
catch (DeviceProviderException)
|
|
||||||
{
|
|
||||||
Reset();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Reset();
|
|
||||||
Throw(ex, true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loads devices and returns a filtered list of them.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The underlying loading of the devices happens in <see cref="LoadDevices"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="loadFilter"><see cref="RGBDeviceType"/>-flags to filter the device with.</param>
|
|
||||||
/// <returns>The filtered collection of loaded devices.</returns>
|
|
||||||
protected virtual IEnumerable<IRGBDevice> GetLoadedDevices(RGBDeviceType loadFilter)
|
|
||||||
{
|
|
||||||
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
|
|
||||||
|
|
||||||
List<IRGBDevice> devices = [];
|
|
||||||
foreach (IRGBDevice device in LoadDevices())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (loadFilter.HasFlag(device.DeviceInfo.DeviceType))
|
|
||||||
devices.Add(device);
|
|
||||||
else
|
|
||||||
device.Dispose();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Throw(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the underlying SDK.
|
|
||||||
/// </summary>
|
|
||||||
protected abstract void InitializeSDK();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loads all devices this device provider is capable of loading.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Filtering happens in <see cref="GetLoadedDevices"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <returns>A collection of loaded devices.</returns>
|
|
||||||
protected abstract IEnumerable<IRGBDevice> LoadDevices();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="IDeviceUpdateTrigger"/> mapped to the specified id or a new one if the id wasn't requested before.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The creation of the update trigger happens in <see cref="CreateUpdateTrigger"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="id">The id of the update trigger.</param>
|
|
||||||
/// <param name="updateRateHardLimit">The update rate hard limit to be set in the update trigger.</param>
|
|
||||||
/// <returns>The update trigger mapped to the specified id.</returns>
|
|
||||||
protected virtual IDeviceUpdateTrigger GetUpdateTrigger(int id = -1, double? updateRateHardLimit = null)
|
|
||||||
{
|
|
||||||
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
|
|
||||||
|
|
||||||
if (!UpdateTriggerMapping.TryGetValue(id, out IDeviceUpdateTrigger? updaeTrigger))
|
|
||||||
UpdateTriggerMapping[id] = (updaeTrigger = CreateUpdateTrigger(id, updateRateHardLimit ?? _defaultUpdateRateHardLimit));
|
|
||||||
|
|
||||||
return updaeTrigger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a update trigger with the specified id and the specified update rate hard limit.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The id of the update trigger.</param>
|
|
||||||
/// <param name="updateRateHardLimit">The update rate hard limit tobe set in the update trigger.</param>
|
|
||||||
/// <returns>The newly created update trigger.</returns>
|
|
||||||
protected virtual IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) => new DeviceUpdateTrigger(updateRateHardLimit);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets the device provider and disposes all devices and update triggers.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void Reset()
|
|
||||||
{
|
|
||||||
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
|
|
||||||
|
|
||||||
foreach (IDeviceUpdateTrigger updateTrigger in UpdateTriggerMapping.Values)
|
|
||||||
updateTrigger.Dispose();
|
|
||||||
|
|
||||||
foreach (IRGBDevice device in Devices)
|
|
||||||
device.Dispose();
|
|
||||||
|
|
||||||
List<IRGBDevice> devices = [..InternalDevices];
|
|
||||||
foreach (IRGBDevice device in devices)
|
|
||||||
RemoveDevice(device);
|
|
||||||
|
|
||||||
UpdateTriggerMapping.Clear();
|
|
||||||
IsInitialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the provided device to the list of managed devices.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="device">The device to add.</param>
|
|
||||||
/// <returns><c>true</c> if the device was added successfully; otherwise <c>false</c>.</returns>
|
|
||||||
protected virtual bool AddDevice(IRGBDevice device)
|
|
||||||
{
|
|
||||||
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
|
|
||||||
|
|
||||||
if (InternalDevices.Contains(device)) return false;
|
|
||||||
|
|
||||||
InternalDevices.Add(device);
|
|
||||||
try { OnDevicesChanged(DevicesChangedEventArgs.CreateDevicesAddedArgs(device)); } catch { /* we don't want to throw due to bad event handlers */ }
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the provided device from the list of managed devices.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="device">The device to remove.</param>
|
|
||||||
/// <returns><c>true</c> if the device was removed successfully; otherwise <c>false</c>.</returns>
|
|
||||||
protected virtual bool RemoveDevice(IRGBDevice device)
|
|
||||||
{
|
|
||||||
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
|
|
||||||
|
|
||||||
if (!InternalDevices.Remove(device)) return false;
|
|
||||||
|
|
||||||
try { OnDevicesChanged(DevicesChangedEventArgs.CreateDevicesRemovedArgs(device)); } catch { /* we don't want to throw due to bad event handlers */ }
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggers the <see cref="Exception"/>-event and throws the specified exception if <see cref="ThrowsExceptions"/> is true and it is not overriden in the event.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ex">The exception to throw.</param>
|
|
||||||
/// <param name="isCritical">Indicates if the exception is critical for device provider to work correctly.</param>
|
|
||||||
public virtual void Throw(Exception ex, bool isCritical = false)
|
|
||||||
{
|
|
||||||
ExceptionEventArgs args = new(ex, isCritical, ThrowsExceptions);
|
|
||||||
try { OnException(args); } catch { /* we don't want to throw due to bad event handlers */ }
|
|
||||||
|
|
||||||
if (args.Throw)
|
|
||||||
throw new DeviceProviderException(ex, isCritical);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Throws the <see cref="Exception"/>.event.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args">The parameters passed to the event.</param>
|
|
||||||
protected virtual void OnException(ExceptionEventArgs args) => Exception?.Invoke(this, args);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Throws the <see cref="DevicesChanged"/>-event.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args">The parameters passed to the event.</param>
|
|
||||||
protected virtual void OnDevicesChanged(DevicesChangedEventArgs args) => DevicesChanged?.Invoke(this, args);
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_isDisposed) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
}
|
|
||||||
catch { /* don't throw in dispose! */ }
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
|
|
||||||
_isDisposed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disposes the object and frees all resources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing"><c>true</c> if explicitely called through the Dispose-Method, <c>false</c> if called by the destructor.</param>
|
|
||||||
protected virtual void Dispose(bool disposing) => Reset();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
32
RGB.NET.Core/Devices/DeviceUpdateMode.cs
Normal file
32
RGB.NET.Core/Devices/DeviceUpdateMode.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains a list of different device device update modes.
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum DeviceUpdateMode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents nothing.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a mode which updates the leds of the device.
|
||||||
|
/// </summary>
|
||||||
|
Sync = 1 << 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a mode which reads the color of the leds of the device.
|
||||||
|
/// This isn't supported by all devices!
|
||||||
|
/// </summary>
|
||||||
|
SyncBack = 1 << 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents all update modes.
|
||||||
|
/// </summary>
|
||||||
|
NoUpdate = 1 << 0xFF
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,98 +1,129 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc cref="IEnumerable{Led}" />
|
|
||||||
/// <inheritdoc cref="IBindable" />
|
|
||||||
/// <inheritdoc cref="IDisposable" />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a generic RGB-device.
|
|
||||||
/// </summary>
|
|
||||||
public interface IRGBDevice : IEnumerable<Led>, IPlaceable, IBindable, IDisposable
|
|
||||||
{
|
{
|
||||||
#region Properties
|
/// <inheritdoc cref="IEnumerable{T}" />
|
||||||
|
/// <inheritdoc cref="IBindable" />
|
||||||
|
/// <inheritdoc cref="IDisposable" />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the surface this device is attached to.
|
/// Represents a generic RGB-device.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
RGBSurface? Surface { get; internal set; }
|
public interface IRGBDevice : IEnumerable<Led>, IBindable, IDisposable
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets generic information about the <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
IRGBDeviceInfo DeviceInfo { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the location of the <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
Point Location { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Size"/> of the <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
Size Size { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the actual <see cref="Size"/> of the <see cref="IRGBDevice"/>.
|
||||||
|
/// This includes the <see cref="Scale"/>.
|
||||||
|
/// </summary>
|
||||||
|
Size ActualSize { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="Rectangle"/> representing the logical location of the <see cref="DeviceRectangle"/> relative to the <see cref="RGBSurface"/>.
|
||||||
|
/// </summary>
|
||||||
|
Rectangle DeviceRectangle { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the scale of the <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
Scale Scale { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the rotation of the <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
Rotation Rotation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="DeviceUpdateMode"/> of the <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
DeviceUpdateMode UpdateMode { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Indexer
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Led"/> with the specified <see cref="LedId"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ledId">The <see cref="LedId"/> of the <see cref="Led"/> to get.</param>
|
||||||
|
/// <returns>The <see cref="Led"/> with the specified <see cref="LedId"/> or null if no <see cref="Led"/> is found.</returns>
|
||||||
|
Led this[LedId ledId] { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Led" /> at the given physical location.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="location">The <see cref="Point"/> to get the location from.</param>
|
||||||
|
/// <returns>The <see cref="Led"/> at the given <see cref="Point"/> or null if no location is found.</returns>
|
||||||
|
Led this[Point location] { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of <see cref="Led" /> inside the given <see cref="Rectangle"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="referenceRect">The <see cref="Rectangle"/> to check.</param>
|
||||||
|
/// <param name="minOverlayPercentage">The minimal percentage overlay a <see cref="Led"/> must have with the <see cref="Rectangle" /> to be taken into the list.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IEnumerable<Led> this[Rectangle referenceRect, double minOverlayPercentage = 0.5] { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Perform an update for all dirty <see cref="Led"/>, or all <see cref="Led"/> if flushLeds is set to true.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="flushLeds">Specifies whether all <see cref="Led"/> (including clean ones) should be updated.</param>
|
||||||
|
void Update(bool flushLeds = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synchronizes the internal state of the device to the real (physical) state.
|
||||||
|
/// This isn't supported by all devices! Check <see cref="IRGBDeviceInfo.SupportsSyncBack"/> to see if it's supported or not.
|
||||||
|
/// </summary>
|
||||||
|
void SyncBack();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the given <see cref="IRGBDeviceSpecialPart"/> to the device.
|
||||||
|
/// This will override existing <see cref="IRGBDeviceSpecialPart"/> of the same type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="specialDevicePart">The <see cref="IRGBDeviceSpecialPart"/> to add.</param>
|
||||||
|
/// <typeparam name="T">The generic typeof of the <see cref="IRGBDeviceSpecialPart"/> to add.</typeparam>
|
||||||
|
void AddSpecialDevicePart<T>(T specialDevicePart) where T : class, IRGBDeviceSpecialPart;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the requested <see cref="IRGBDeviceSpecialPart"/> if available on this <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The generic type of the requested <see cref="IRGBDeviceSpecialPart"/>.</typeparam>
|
||||||
|
/// <returns>The requested <see cref="IRGBDeviceSpecialPart"/> or null if not available in this <see cref="IRGBDevice"/>.</returns>
|
||||||
|
T GetSpecialDevicePart<T>() where T : class, IRGBDeviceSpecialPart;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets generic information about the <see cref="IRGBDevice"/>.
|
/// Represents a generic RGB-device with an known device-info type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IRGBDeviceInfo DeviceInfo { get; }
|
public interface IRGBDevice<out TDeviceInfo> : IRGBDevice
|
||||||
|
where TDeviceInfo : IRGBDeviceInfo
|
||||||
/// <summary>
|
{
|
||||||
/// Gets a list of color corrections applied to this device.
|
/// <summary>
|
||||||
/// </summary>
|
/// Gets generic information about the <see cref="IRGBDevice"/>.
|
||||||
IList<IColorCorrection> ColorCorrections { get; }
|
/// </summary>
|
||||||
|
new TDeviceInfo DeviceInfo { get; }
|
||||||
#endregion
|
}
|
||||||
|
|
||||||
#region Indexer
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="Led"/> with the specified <see cref="LedId"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledId">The <see cref="LedId"/> of the <see cref="Led"/> to get.</param>
|
|
||||||
/// <returns>The <see cref="Led"/> with the specified <see cref="LedId"/> or null if no <see cref="Led"/> is found.</returns>
|
|
||||||
Led? this[LedId ledId] { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="Led" /> at the specified physical location.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="location">The <see cref="Point"/> to get the location from.</param>
|
|
||||||
/// <returns>The <see cref="Led"/> at the specified <see cref="Point"/> or null if no location is found.</returns>
|
|
||||||
Led? this[Point location] { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of <see cref="Led" /> inside the specified <see cref="Rectangle"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="referenceRect">The <see cref="Rectangle"/> to check.</param>
|
|
||||||
/// <param name="minOverlayPercentage">The minimal percentage overlay a <see cref="Led"/> must have with the <see cref="Rectangle" /> to be taken into the list.</param>
|
|
||||||
/// <returns>A enumerable of leds inside the specified rectangle.</returns>
|
|
||||||
IEnumerable<Led> this[Rectangle referenceRect, double minOverlayPercentage = 0.5] { get; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Perform an update for all dirty <see cref="Led"/>, or all <see cref="Led"/> if flushLeds is set to true.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="flushLeds">Specifies whether all <see cref="Led"/> (including clean ones) should be updated.</param>
|
|
||||||
void Update(bool flushLeds = false);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a led to the device.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledId">The id of the led.</param>
|
|
||||||
/// <param name="location">The location of the led on the device.</param>
|
|
||||||
/// <param name="size">The size of the led.</param>
|
|
||||||
/// <param name="customData">Custom data saved on the led.</param>
|
|
||||||
/// <returns>The newly added led or <c>null</c> if a led with this id is already added.</returns>
|
|
||||||
Led? AddLed(LedId ledId, Point location, Size size, object? customData = null);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the led with the specified id from the device.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledId">The id of the led to remove.</param>
|
|
||||||
/// <returns>The removed led or <c>null</c> if there was no led with the specified id.</returns>
|
|
||||||
Led? RemoveLed(LedId ledId);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a generic RGB-device with an known device-info type.
|
|
||||||
/// </summary>
|
|
||||||
public interface IRGBDevice<out TDeviceInfo> : IRGBDevice
|
|
||||||
where TDeviceInfo : IRGBDeviceInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets generic information about the <see cref="IRGBDevice"/>.
|
|
||||||
/// </summary>
|
|
||||||
new TDeviceInfo DeviceInfo { get; }
|
|
||||||
}
|
|
||||||
@ -1,36 +1,49 @@
|
|||||||
namespace RGB.NET.Core;
|
using System;
|
||||||
|
|
||||||
/// <summary>
|
namespace RGB.NET.Core
|
||||||
/// Represents a generic information for a <see cref="IRGBDevice"/>
|
|
||||||
/// </summary>
|
|
||||||
public interface IRGBDeviceInfo
|
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="RGBDeviceType"/> of the <see cref="IRGBDevice"/>.
|
/// Represents a generic information for a <see cref="IRGBDevice"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
RGBDeviceType DeviceType { get; }
|
public interface IRGBDeviceInfo
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unique name of the <see cref="IRGBDevice"/>.
|
/// Gets the <see cref="RGBDeviceType"/> of the <see cref="IRGBDevice"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string DeviceName { get; }
|
RGBDeviceType DeviceType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the manufacturer-name of the <see cref="IRGBDevice"/>.
|
/// Unique name of the <see cref="IRGBDevice"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Manufacturer { get; }
|
string DeviceName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the model-name of the <see cref="IRGBDevice"/>.
|
/// Gets the manufacturer-name of the <see cref="IRGBDevice"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Model { get; }
|
string Manufacturer { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets custom metadata added to the layout.
|
/// Gets the model-name of the <see cref="IRGBDevice"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
object? LayoutMetadata { get; set; }
|
string Model { get; }
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
}
|
/// Gets the lighting capability of the <see cref="IRGBDevice"/>
|
||||||
|
/// </summary>
|
||||||
|
RGBDeviceLighting Lighting { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a bool indicating, if the <see cref="IRGBDevice"/> supports SynBacks or not.
|
||||||
|
/// </summary>
|
||||||
|
bool SupportsSyncBack { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the URI of an image of the <see cref="IRGBDevice"/> or null if there is no image.
|
||||||
|
/// </summary>
|
||||||
|
Uri Image { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,66 +1,48 @@
|
|||||||
// ReSharper disable EventNeverSubscribedTo.Global
|
using System;
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a generic device provider.
|
|
||||||
/// </summary>
|
|
||||||
public interface IRGBDeviceProvider : IDisposable
|
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the used SDK is initialized and ready to use.
|
/// Represents a generic device provider.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsInitialized { get; }
|
public interface IRGBDeviceProvider : IDisposable
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if exceptions in the device provider are thrown or silently ignored.
|
/// Indicates if the used SDK is initialized and ready to use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
bool IsInitialized { get; }
|
||||||
/// This should only be set to <c>true</c> for debugging/development purposes.
|
|
||||||
/// Production code should use the <see cref="Exception"/>-Event to handle exceptions.
|
|
||||||
/// </remarks>
|
|
||||||
bool ThrowsExceptions { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a collection of <see cref="IRGBDevice"/> loaded by this <see cref="IRGBDeviceProvider"/>.
|
/// Gets a list of <see cref="IRGBDevice"/> loaded by this <see cref="IRGBDeviceProvider"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IReadOnlyList<IRGBDevice> Devices { get; }
|
IEnumerable<IRGBDevice> Devices { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a collection <see cref="IDeviceUpdateTrigger"/> registered to this device provider.
|
/// Gets whether the application has exclusive access to devices or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IReadOnlyList<(int id, IDeviceUpdateTrigger trigger)> UpdateTriggers { get; }
|
bool HasExclusiveAccess { get; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Events
|
#region Methods
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when an exception is thrown in the device provider.
|
/// Initializes the <see cref="IRGBDeviceProvider"/> if not already happened or reloads it if it is already initialized.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event EventHandler<ExceptionEventArgs>? Exception;
|
/// <param name="loadFilter">Specifies which types of devices to load.</param>
|
||||||
|
/// <param name="exclusiveAccessIfPossible">Specifies whether the application should request exclusive access of possible or not.</param>
|
||||||
|
/// <param name="throwExceptions">Specifies whether exception during the initialization sequence should be thrown or not.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool Initialize(RGBDeviceType loadFilter = RGBDeviceType.All, bool exclusiveAccessIfPossible = false, bool throwExceptions = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occures when the devices provided by this device provider changed.
|
/// Resets all handled <see cref="IRGBDevice"/> back top default.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event EventHandler<DevicesChangedEventArgs>? DevicesChanged;
|
void ResetDevices();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
}
|
||||||
#region Methods
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the device provider and loads available devices.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="loadFilter"><see cref="RGBDeviceType"/>-flags to filter the devices to load.</param>
|
|
||||||
/// <param name="throwExceptions">Specifies if exceptions should be thrown or silently be ignored.</param>
|
|
||||||
/// <returns><c>true</c> if the initialization was successful; <c>false</c> otherwise.</returns>
|
|
||||||
bool Initialize(RGBDeviceType loadFilter = RGBDeviceType.All, bool throwExceptions = false);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
20
RGB.NET.Core/Devices/IRGBDeviceProviderLoader.cs
Normal file
20
RGB.NET.Core/Devices/IRGBDeviceProviderLoader.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a generic device provider loaded used to dynamically load devices into an application.
|
||||||
|
/// This class should always provide an empty public constructor!
|
||||||
|
/// </summary>
|
||||||
|
public interface IRGBDeviceProviderLoader
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if the returned device-provider needs some specific initialization before use.
|
||||||
|
/// </summary>
|
||||||
|
bool RequiresInitialization { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the device-provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The device-provider.</returns>
|
||||||
|
IRGBDeviceProvider GetDeviceProvider();
|
||||||
|
}
|
||||||
|
}
|
||||||
11
RGB.NET.Core/Devices/IRGBDeviceSpecialPart.cs
Normal file
11
RGB.NET.Core/Devices/IRGBDeviceSpecialPart.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a special part of a <see cref="T:RGB.NET.Core.IRGBDevice" />.
|
||||||
|
/// </summary>
|
||||||
|
public interface IRGBDeviceSpecialPart : IEnumerable<Led>
|
||||||
|
{ }
|
||||||
|
}
|
||||||
@ -1,17 +0,0 @@
|
|||||||
// ReSharper disable InconsistentNaming
|
|
||||||
#pragma warning disable 1591
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains a list of available keyboard layout types.
|
|
||||||
/// </summary>
|
|
||||||
public enum KeyboardLayoutType
|
|
||||||
{
|
|
||||||
Unknown = 0,
|
|
||||||
ANSI = 1,
|
|
||||||
ISO = 2,
|
|
||||||
JIS = 3,
|
|
||||||
ABNT = 4,
|
|
||||||
KS = 5
|
|
||||||
}
|
|
||||||
151
RGB.NET.Core/Devices/Layout/DeviceLayout.cs
Normal file
151
RGB.NET.Core/Devices/Layout/DeviceLayout.cs
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core.Layout
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the serializable layout of a <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
[XmlRoot("Device")]
|
||||||
|
public class DeviceLayout
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the name of the <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the description of the <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Description")]
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="RGBDeviceType"/> of the <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Type")]
|
||||||
|
public RGBDeviceType Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="RGBDeviceLighting"/> of the <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Lighting")]
|
||||||
|
public RGBDeviceLighting Lighting { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the vendor of the <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Vendor")]
|
||||||
|
public string Vendor { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the model of the <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Model")]
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="Core.Shape"/> of the <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Shape")]
|
||||||
|
[DefaultValue(Shape.Rectangle)]
|
||||||
|
public Shape Shape { get; set; } = Shape.Rectangle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the width of the <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Width")]
|
||||||
|
public double Width { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the height of the <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Height")]
|
||||||
|
public double Height { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the width of one 'unit' used for the calculation of led positions and sizes.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("LedUnitWidth")]
|
||||||
|
[DefaultValue(19.0)]
|
||||||
|
public double LedUnitWidth { get; set; } = 19.0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the height of one 'unit' used for the calculation of led positions and sizes.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("LedUnitHeight")]
|
||||||
|
[DefaultValue(19.0)]
|
||||||
|
public double LedUnitHeight { get; set; } = 19.0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The path images for this device are collected in.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("ImageBasePath")]
|
||||||
|
public string ImageBasePath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The image file for this device.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("DeviceImage")]
|
||||||
|
public string DeviceImage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a list of <see cref="LedLayout"/> representing all the <see cref="Led"/> of the <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlArray("Leds")]
|
||||||
|
public List<LedLayout> Leds { get; set; } = new List<LedLayout>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a list of <see cref="LedImageLayout"/> representing the layouts for the images of all the <see cref="Led"/> of the <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlArray("LedImageLayouts")]
|
||||||
|
public List<LedImageLayout> LedImageLayouts { get; set; } = new List<LedImageLayout>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="DeviceLayout"/> from the given xml.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to the xml file.</param>
|
||||||
|
/// <returns>The deserialized <see cref="DeviceLayout"/>.</returns>
|
||||||
|
public static DeviceLayout Load(string path)
|
||||||
|
{
|
||||||
|
if (!File.Exists(path)) return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
XmlSerializer serializer = new XmlSerializer(typeof(DeviceLayout));
|
||||||
|
using (StreamReader reader = new StreamReader(path))
|
||||||
|
{
|
||||||
|
DeviceLayout layout = serializer.Deserialize(reader) as DeviceLayout;
|
||||||
|
if (layout?.Leds != null)
|
||||||
|
{
|
||||||
|
LedLayout lastLed = null;
|
||||||
|
foreach (LedLayout led in layout.Leds)
|
||||||
|
{
|
||||||
|
led.CalculateValues(layout, lastLed);
|
||||||
|
lastLed = led;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
25
RGB.NET.Core/Devices/Layout/LedImage.cs
Normal file
25
RGB.NET.Core/Devices/Layout/LedImage.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core.Layout
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the serializable image-data of a specific <see cref="Led"/>.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
[XmlRoot("LedImage")]
|
||||||
|
public class LedImage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Id of the <see cref="LedImage"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlAttribute("Id")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the image of the <see cref="LedImage"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlAttribute("Image")]
|
||||||
|
public string Image { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
28
RGB.NET.Core/Devices/Layout/LedImageLayout.cs
Normal file
28
RGB.NET.Core/Devices/Layout/LedImageLayout.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core.Layout
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the serializable collection of <see cref="LedImage"/> for a specific layout.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
[XmlRoot("LedImageLayout")]
|
||||||
|
public class LedImageLayout
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the layout of the <see cref="LedImage"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlAttribute("Layout")]
|
||||||
|
[DefaultValue(null)]
|
||||||
|
public string Layout { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a list of <see cref="LedImage"/> representing the images of all the <see cref="Led"/> of the represented layout.
|
||||||
|
/// </summary>
|
||||||
|
[XmlArray("LedImages")]
|
||||||
|
public List<LedImage> LedImages { get; set; } = new List<LedImage>();
|
||||||
|
}
|
||||||
|
}
|
||||||
182
RGB.NET.Core/Devices/Layout/LedLayout.cs
Normal file
182
RGB.NET.Core/Devices/Layout/LedLayout.cs
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core.Layout
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the serializable layout of a <see cref="Led"/>.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
[XmlType("Led")]
|
||||||
|
public class LedLayout
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Id of the <see cref="LedLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlAttribute("Id")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the descriptive <see cref="RGB.NET.Core.Shape"/> of the <see cref="LedLayout"/>.
|
||||||
|
/// This property is for XML-serialization only and should not be directly accessed.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Shape")]
|
||||||
|
[DefaultValue("Rectangle")]
|
||||||
|
public string DescriptiveShape { get; set; } = "Rectangle";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the descriptive x-position of the <see cref="LedLayout"/>.
|
||||||
|
/// This property is for XML-serialization only and should not be directly accessed.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("X")]
|
||||||
|
[DefaultValue("+")]
|
||||||
|
public string DescriptiveX { get; set; } = "+";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the descriptive y-position of the <see cref="LedLayout"/>.
|
||||||
|
/// This property is for XML-serialization only and should not be directly accessed.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Y")]
|
||||||
|
[DefaultValue("=")]
|
||||||
|
public string DescriptiveY { get; set; } = "=";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the descriptive width of the <see cref="LedLayout"/>.
|
||||||
|
/// This property is for XML-serialization only and should not be directly accessed.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Width")]
|
||||||
|
[DefaultValue("1.0")]
|
||||||
|
public string DescriptiveWidth { get; set; } = "1.0";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the descriptive height of the <see cref="LedLayout"/>.
|
||||||
|
/// This property is for XML-serialization only and should not be directly accessed.
|
||||||
|
/// </summary>
|
||||||
|
[XmlElement("Height")]
|
||||||
|
[DefaultValue("1.0")]
|
||||||
|
public string DescriptiveHeight { get; set; } = "1.0";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="RGB.NET.Core.Shape"/> of the <see cref="LedLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlIgnore]
|
||||||
|
public Shape Shape { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the vecor-data representing a custom-shape of the <see cref="LedLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlIgnore]
|
||||||
|
public string ShapeData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the x-position of the <see cref="LedLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlIgnore]
|
||||||
|
public double X { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the y-position of the <see cref="LedLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlIgnore]
|
||||||
|
public double Y { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the width of the <see cref="LedLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlIgnore]
|
||||||
|
public double Width { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the height of the <see cref="LedLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
[XmlIgnore]
|
||||||
|
public double Height { get; private set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the position- and size-data from the respective descriptive values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">The <see cref="DeviceLayout"/> this <see cref="LedLayout"/> belongs to.</param>
|
||||||
|
/// <param name="lastLed">The <see cref="LedLayout"/> previously calculated.</param>
|
||||||
|
public void CalculateValues(DeviceLayout device, LedLayout lastLed)
|
||||||
|
{
|
||||||
|
if (!Enum.TryParse(DescriptiveShape, true, out Shape shape))
|
||||||
|
{
|
||||||
|
shape = Shape.Custom;
|
||||||
|
ShapeData = DescriptiveShape;
|
||||||
|
}
|
||||||
|
Shape = shape;
|
||||||
|
|
||||||
|
Width = GetSizeValue(DescriptiveWidth, device.LedUnitWidth);
|
||||||
|
Height = GetSizeValue(DescriptiveHeight, device.LedUnitHeight);
|
||||||
|
|
||||||
|
X = GetLocationValue(DescriptiveX, lastLed?.X ?? 0, Width, lastLed?.Width ?? 0);
|
||||||
|
Y = GetLocationValue(DescriptiveY, lastLed?.Y ?? 0, Height, lastLed?.Height ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double GetLocationValue(string value, double lastValue, double currentSize, double lastSize)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value)) return 0;
|
||||||
|
|
||||||
|
value = value.Replace(" ", string.Empty);
|
||||||
|
|
||||||
|
if (string.Equals(value, "=", StringComparison.Ordinal))
|
||||||
|
return lastValue;
|
||||||
|
|
||||||
|
if (string.Equals(value, "+", StringComparison.Ordinal))
|
||||||
|
return lastValue + lastSize;
|
||||||
|
|
||||||
|
if (value.StartsWith("+", StringComparison.Ordinal))
|
||||||
|
return lastValue + lastSize + double.Parse(value.Substring(1), CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
if (string.Equals(value, "-", StringComparison.Ordinal))
|
||||||
|
return lastValue - currentSize;
|
||||||
|
|
||||||
|
if (value.StartsWith("-", StringComparison.Ordinal))
|
||||||
|
return lastValue - currentSize - double.Parse(value.Substring(1), CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
if (string.Equals(value, "~", StringComparison.Ordinal))
|
||||||
|
return (lastValue + lastSize) - currentSize;
|
||||||
|
|
||||||
|
if (value.StartsWith("~", StringComparison.Ordinal))
|
||||||
|
return (lastValue + lastSize) - currentSize - double.Parse(value.Substring(1), CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
return double.Parse(value, CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double GetSizeValue(string value, double unitSize)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value)) return 0;
|
||||||
|
|
||||||
|
value = value.Replace(" ", string.Empty);
|
||||||
|
|
||||||
|
if (value.EndsWith("mm", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return double.Parse(value.Substring(0, value.Length - 2), CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
return unitSize * double.Parse(value, CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
25
RGB.NET.Core/Devices/RGBDeviceLighting.cs
Normal file
25
RGB.NET.Core/Devices/RGBDeviceLighting.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using RGB.NET.Core.Layout;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains a list of different lightning-modes used by <see cref="DeviceLayout"/>.
|
||||||
|
/// </summary>
|
||||||
|
public enum RGBDeviceLighting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="IRGBDevice"/> doesn't support lighting,
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="IRGBDevice"/> supports per-key-lightning.
|
||||||
|
/// </summary>
|
||||||
|
Key = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="IRGBDevice"/> supports per-device-lightning.
|
||||||
|
/// </summary>
|
||||||
|
Device = 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,110 +1,96 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains a list of different types of device.
|
|
||||||
/// </summary>
|
|
||||||
[Flags]
|
|
||||||
public enum RGBDeviceType
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents nothing.
|
/// Contains a list of different types of device.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
None = 0,
|
[Flags]
|
||||||
|
public enum RGBDeviceType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents nothing.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a keyboard.
|
/// Represents a keyboard.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Keyboard = 1 << 0,
|
Keyboard = 1 << 0,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a mouse.
|
/// Represents a mouse.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Mouse = 1 << 1,
|
Mouse = 1 << 1,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a headset.
|
/// Represents a headset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Headset = 1 << 2,
|
Headset = 1 << 2,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a mousepad.
|
/// Represents a mousepad.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Mousepad = 1 << 3,
|
Mousepad = 1 << 3,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a LED-stipe.
|
/// Represents a LED-stipe.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
LedStripe = 1 << 4,
|
LedStripe = 1 << 4,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a LED-matrix.
|
/// Represents a LED-matrix.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
LedMatrix = 1 << 5,
|
LedMatrix = 1 << 5,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a Mainboard.
|
/// Represents a Mainboard.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Mainboard = 1 << 6,
|
Mainboard = 1 << 6,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a Graphics card.
|
/// Represents a Graphics card.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
GraphicsCard = 1 << 7,
|
GraphicsCard = 1 << 7,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a DRAM-bank.
|
/// Represents a DRAM-bank.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DRAM = 1 << 8,
|
DRAM = 1 << 8,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a headset stand.
|
/// Represents a headset stand.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
HeadsetStand = 1 << 9,
|
HeadsetStand = 1 << 9,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a keypad.
|
/// Represents a keypad.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Keypad = 1 << 10,
|
Keypad = 1 << 10,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a fan.
|
/// Represents a fan.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Fan = 1 << 11,
|
Fan = 1 << 11,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a speaker
|
/// Represents a speaker
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Speaker = 1 << 12,
|
Speaker = 1 << 12,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a cooler.
|
/// Represents a cooler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Cooler = 1 << 13,
|
Cooler = 1 << 13,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a monitor.
|
/// Represents a device where the type is not known or not present in the list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Monitor = 1 << 14,
|
Unknown = 1 << 31,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a generic led-controller.
|
/// Represents all devices.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
LedController = 1 << 15,
|
All = ~None
|
||||||
|
}
|
||||||
/// <summary>
|
}
|
||||||
/// Represents a game controller.
|
|
||||||
/// </summary>
|
|
||||||
GameController = 1 << 16,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a device where the type is not known or not present in the list.
|
|
||||||
/// </summary>
|
|
||||||
Unknown = 1 << 31,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents all devices.
|
|
||||||
/// </summary>
|
|
||||||
All = ~None
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a cooler-device
|
/// Represents a cooler-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICooler : IRGBDevice;
|
public interface ICooler : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a DRAM-device
|
/// Represents a DRAM-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IDRAM : IRGBDevice;
|
public interface IDRAM : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// represents a fan-device
|
/// represents a fan-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFan : IRGBDevice;
|
public interface IFan : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a gamecontroller-device
|
|
||||||
/// </summary>
|
|
||||||
public interface IGameController: IRGBDevice;
|
|
||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a graphics-card-device
|
/// Represents a graphics-card-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IGraphicsCard : IRGBDevice;
|
public interface IGraphicsCard : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a headset-device
|
/// Represents a headset-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHeadset : IRGBDevice;
|
public interface IHeadset : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a headset-stand-device
|
/// Represents a headset-stand-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHeadsetStand : IRGBDevice;
|
public interface IHeadsetStand : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,23 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a generic keyboard-device.
|
|
||||||
/// </summary>
|
|
||||||
public interface IKeyboard : IRGBDevice
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the device information assiciated with this device.
|
/// Represents a keyboard-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
new IKeyboardDeviceInfo DeviceInfo { get; }
|
public interface IKeyboard : IRGBDevice
|
||||||
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a generic keyboard device information.
|
|
||||||
/// </summary>
|
|
||||||
public interface IKeyboardDeviceInfo : IRGBDeviceInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="KeyboardLayoutType"/> of the keyboard.
|
|
||||||
/// </summary>
|
|
||||||
KeyboardLayoutType Layout { get; }
|
|
||||||
}
|
|
||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a keypad-device
|
/// Represents a keypad-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IKeypad : IRGBDevice;
|
public interface IKeypad : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a led-matrix-device
|
/// Represents a led-matrix-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ILedMatrix : IRGBDevice;
|
public interface ILedMatrix : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a led-stripe-device
|
/// Represents a led-stripe-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ILedStripe : IRGBDevice;
|
public interface ILedStripe : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a mainboard-device
|
/// Represents a mainboard-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IMainboard : IRGBDevice;
|
public interface IMainboard : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a mouse-device
|
/// Represents a mouse-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IMouse : IRGBDevice;
|
public interface IMouse : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a mousepad-device
|
/// Represents a mousepad-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IMousepad : IRGBDevice;
|
public interface IMousepad : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a speaker-device
|
/// Represents a speaker-device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISpeaker : IRGBDevice;
|
public interface ISpeaker : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a device with unkown or not specified type.
|
/// Represents a device with unkown or not specified type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IUnknownDevice : IRGBDevice;
|
public interface IUnknownDevice : IRGBDevice
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
public sealed class DevicesChangedEventArgs(IRGBDevice device, DevicesChangedEventArgs.DevicesChangedAction action)
|
|
||||||
: EventArgs
|
|
||||||
{
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
public IRGBDevice Device { get; } = device;
|
|
||||||
public DevicesChangedAction Action { get; } = action;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
public static DevicesChangedEventArgs CreateDevicesAddedArgs(IRGBDevice addedDevice) => new(addedDevice, DevicesChangedAction.Added);
|
|
||||||
public static DevicesChangedEventArgs CreateDevicesRemovedArgs(IRGBDevice removedDevice) => new(removedDevice, DevicesChangedAction.Removed);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public enum DevicesChangedAction
|
|
||||||
{
|
|
||||||
Added,
|
|
||||||
Removed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -3,48 +3,35 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the information supplied with an <see cref="E:RGB.NET.Core.RGBSurface.Exception" />-event.
|
|
||||||
/// </summary>
|
|
||||||
public class ExceptionEventArgs : EventArgs
|
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="System.Exception"/> which is responsible for the event-call.
|
|
||||||
/// </summary>
|
|
||||||
public Exception Exception { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a bool indicating if the exception is critical for the thrower.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsCritical { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets if the exception should be thrown after the event is handled.
|
|
||||||
/// </summary>
|
|
||||||
public bool Throw { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.ExceptionEventArgs" /> class.
|
/// Represents the information supplied with an <see cref="E:RGB.NET.Core.RGBSurface.Exception" />-event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="exception">The <see cref="T:System.Exception" /> which is responsible for the event-call.</param>
|
public class ExceptionEventArgs : EventArgs
|
||||||
/// <param name="isCritical">Indicates if the exception is critical for the thrower.</param>
|
|
||||||
/// <param name="throw">Indicates if the exception should be thrown after the event is handled.</param>
|
|
||||||
public ExceptionEventArgs(Exception exception, bool isCritical = false, bool @throw = false)
|
|
||||||
{
|
{
|
||||||
this.Exception = exception;
|
#region Properties & Fields
|
||||||
this.IsCritical = isCritical;
|
|
||||||
this.Throw = @throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
}
|
/// Gets the <see cref="System.Exception"/> which is responsible for the event-call.
|
||||||
|
/// </summary>
|
||||||
|
public Exception Exception { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.ExceptionEventArgs" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exception">The <see cref="T:System.Exception" /> which is responsible for the event-call.</param>
|
||||||
|
public ExceptionEventArgs(Exception exception)
|
||||||
|
{
|
||||||
|
this.Exception = exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
64
RGB.NET.Core/Events/ResolvePathEventArgs.cs
Normal file
64
RGB.NET.Core/Events/ResolvePathEventArgs.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
|
public class ResolvePathEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the filename used to resolve the path.
|
||||||
|
/// This has to be checked for null since it'S possible that only <see cref="FileName"/> is used.
|
||||||
|
/// Also check <see cref="RelativePath "/> before use.
|
||||||
|
/// </summary>
|
||||||
|
public string RelativePart { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the filename used to resolve the path.
|
||||||
|
/// This has to be checked for null since it'S possible that only <see cref="RelativePart"/> is used.
|
||||||
|
/// Also check <see cref="RelativePath "/> before use.
|
||||||
|
/// </summary>
|
||||||
|
public string FileName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the relative path used to resolve the path.
|
||||||
|
/// If this is set <see cref="RelativePart" /> and <see cref="FileName" /> are unused.
|
||||||
|
/// </summary>
|
||||||
|
public string RelativePath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the resolved path.
|
||||||
|
/// </summary>
|
||||||
|
public string FinalPath { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Corer.ResolvePathEventArgs" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="relativePart">The filename used to resolve the path.</param>
|
||||||
|
/// <param name="fileName">The filename used to resolve the path.</param>
|
||||||
|
/// <param name="finalPath">The relative part used to resolve the path.</param>
|
||||||
|
public ResolvePathEventArgs(string relativePart, string fileName, string finalPath)
|
||||||
|
{
|
||||||
|
this.RelativePart = relativePart;
|
||||||
|
this.FileName = fileName;
|
||||||
|
this.FinalPath = finalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Corer.ResolvePathEventArgs" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="relativePath">The relative path used to resolve the path.</param>
|
||||||
|
/// <param name="finalPath">The relative part used to resolve the path.</param>
|
||||||
|
public ResolvePathEventArgs(string relativePath, string finalPath)
|
||||||
|
{
|
||||||
|
this.RelativePath = relativePath;
|
||||||
|
this.FinalPath = finalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,65 +2,51 @@
|
|||||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the information supplied with an <see cref="E:RGB.NET.Core.RGBSurface.SurfaceLayoutChanged" />-event.
|
|
||||||
/// </summary>
|
|
||||||
public class SurfaceLayoutChangedEventArgs : EventArgs
|
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="IRGBDevice"/> that caused the change. Returns null if the change isn't caused by a <see cref="IRGBDevice"/>.
|
|
||||||
/// </summary>
|
|
||||||
public IRGBDevice? Devices { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating if the event is caused by the addition of a new <see cref="IRGBDevice"/> to the <see cref="RGBSurface"/>.
|
|
||||||
/// </summary>
|
|
||||||
public bool DeviceAdded { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating if the event is caused by the removal of a <see cref="IRGBDevice"/> to the <see cref="RGBSurface"/>.
|
|
||||||
/// </summary>
|
|
||||||
public bool DeviceRemoved { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating if the event is caused by a changed location or size of one of the <see cref="IRGBDevice"/> on the <see cref="RGBSurface"/>.
|
|
||||||
/// </summary>
|
|
||||||
public bool DeviceChanged { get; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.SurfaceLayoutChangedEventArgs" /> class.
|
/// Represents the information supplied with an <see cref="E:RGB.NET.Core.RGBSurface.SurfaceLayoutChanged" />-event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="devices">The <see cref="T:RGB.NET.Core.IRGBDevice" /> that caused the change.</param>
|
public class SurfaceLayoutChangedEventArgs : EventArgs
|
||||||
/// <param name="deviceAdded">A value indicating if the event is caused by the addition of a new <see cref="T:RGB.NET.Core.IRGBDevice" /> to the <see cref="T:RGB.NET.Core.RGBSurface" />.</param>
|
|
||||||
/// <param name="deviceRemoved">A value indicating if the event is caused by the removal of a <see cref="T:RGB.NET.Core.IRGBDevice" /> from the <see cref="T:RGB.NET.Core.RGBSurface" />.</param>
|
|
||||||
/// <param name="deviceChanged">A value indicating if the event is caused by a change to a <see cref="T:RGB.NET.Core.IRGBDevice" /> on the <see cref="T:RGB.NET.Core.RGBSurface" />.</param>
|
|
||||||
private SurfaceLayoutChangedEventArgs(IRGBDevice? devices, bool deviceAdded, bool deviceRemoved, bool deviceChanged)
|
|
||||||
{
|
{
|
||||||
this.Devices = devices;
|
#region Properties & Fields
|
||||||
this.DeviceAdded = deviceAdded;
|
|
||||||
this.DeviceRemoved = deviceRemoved;
|
/// <summary>
|
||||||
this.DeviceChanged = deviceChanged;
|
/// Gets the <see cref="IRGBDevice"/> that caused the change. Returns null if the change isn't caused by a <see cref="IRGBDevice"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<IRGBDevice> Devices { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating if the event is caused by the addition of a new <see cref="IRGBDevice"/> to the <see cref="RGBSurface"/>.
|
||||||
|
/// </summary>
|
||||||
|
public bool DeviceAdded { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating if the event is caused by a changed location of one of the devices on the <see cref="RGBSurface"/>.
|
||||||
|
/// </summary>
|
||||||
|
public bool DeviceLocationChanged { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.SurfaceLayoutChangedEventArgs" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="devices">The <see cref="T:RGB.NET.Core.IRGBDevice" /> that caused the change.</param>
|
||||||
|
/// <param name="deviceAdded">A value indicating if the event is caused by the addition of a new <see cref="T:RGB.NET.Core.IRGBDevice" /> to the <see cref="T:RGB.NET.Core.RGBSurface" />.</param>
|
||||||
|
/// <param name="deviceLocationChanged">A value indicating if the event is caused by a changed location of one of the devices on the <see cref="T:RGB.NET.Core.RGBSurface" />.</param>
|
||||||
|
public SurfaceLayoutChangedEventArgs(IEnumerable<IRGBDevice> devices, bool deviceAdded, bool deviceLocationChanged)
|
||||||
|
{
|
||||||
|
this.Devices = devices;
|
||||||
|
this.DeviceAdded = deviceAdded;
|
||||||
|
this.DeviceLocationChanged = deviceLocationChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Factory
|
|
||||||
|
|
||||||
internal static SurfaceLayoutChangedEventArgs FromAddedDevice(IRGBDevice device) => new(device, true, false, false);
|
|
||||||
internal static SurfaceLayoutChangedEventArgs FromRemovedDevice(IRGBDevice device) => new(device, false, true, false);
|
|
||||||
internal static SurfaceLayoutChangedEventArgs FromChangedDevice(IRGBDevice device) => new(device, false, false, true);
|
|
||||||
internal static SurfaceLayoutChangedEventArgs Misc() => new(null, false, false, false);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the information supplied with an <see cref="E:RGB.NET.Core.RGBSurface.Updated" />-event.
|
/// Represents the information supplied with an <see cref="E:RGB.NET.Core.RGBSurface.Updated" />-event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UpdatedEventArgs : EventArgs;
|
public class UpdatedEventArgs : EventArgs
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|||||||
@ -3,48 +3,49 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the information supplied with an <see cref="E:RGB.NET.Core.RGBSurface.Updating" />-event.
|
|
||||||
/// </summary>
|
|
||||||
public class UpdatingEventArgs : EventArgs
|
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the elapsed time (in seconds) since the last update.
|
|
||||||
/// </summary>
|
|
||||||
public double DeltaTime { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the trigger causing this update.
|
|
||||||
/// </summary>
|
|
||||||
public IUpdateTrigger? Trigger { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the custom-data provided by the trigger for this update.
|
|
||||||
/// </summary>
|
|
||||||
public ICustomUpdateData CustomData { get; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.UpdatingEventArgs" /> class.
|
/// Represents the information supplied with an <see cref="E:RGB.NET.Core.RGBSurface.Updating" />-event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="deltaTime">The elapsed time (in seconds) since the last update.</param>
|
public class UpdatingEventArgs : EventArgs
|
||||||
/// <param name="trigger">The trigger causing this update.</param>
|
|
||||||
/// <param name="customData">The custom-data provided by the trigger for this update.</param>
|
|
||||||
public UpdatingEventArgs(double deltaTime, IUpdateTrigger? trigger, ICustomUpdateData customData)
|
|
||||||
{
|
{
|
||||||
this.DeltaTime = deltaTime;
|
#region Properties & Fields
|
||||||
this.Trigger = trigger;
|
|
||||||
this.CustomData = customData;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
}
|
/// Gets the elapsed time (in seconds) since the last update.
|
||||||
|
/// </summary>
|
||||||
|
public double DeltaTime { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the trigger causing this update.
|
||||||
|
/// </summary>
|
||||||
|
public IUpdateTrigger Trigger { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the custom-data provided by the trigger for this update.
|
||||||
|
/// </summary>
|
||||||
|
public CustomUpdateData CustomData { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.UpdatingEventArgs" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="deltaTime">The elapsed time (in seconds) since the last update.</param>
|
||||||
|
/// <param name="trigger">The trigger causing this update.</param>
|
||||||
|
/// <param name="customData">The custom-data provided by the trigger for this update.</param>
|
||||||
|
public UpdatingEventArgs(double deltaTime, IUpdateTrigger trigger, CustomUpdateData customData)
|
||||||
|
{
|
||||||
|
this.DeltaTime = deltaTime;
|
||||||
|
this.Trigger = trigger;
|
||||||
|
this.CustomData = customData;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,34 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an exception thrown by a <see cref="IRGBDeviceProvider" />.
|
|
||||||
/// </summary>
|
|
||||||
public class DeviceProviderException : ApplicationException
|
|
||||||
{
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a bool indicating if the exception is critical and shouldn't be ingored.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsCritical { get; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="DeviceProviderException" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="innerException">The exception that is the casue of the current exception or null if this exception was thrown on purpose.</param>
|
|
||||||
/// <param name="isCritical">A value indicating if the exception is critical and shouldn't be ignored.</param>
|
|
||||||
public DeviceProviderException(Exception? innerException, bool isCritical)
|
|
||||||
: base(innerException?.Message, innerException)
|
|
||||||
{
|
|
||||||
this.IsCritical = isCritical;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -1,24 +1,25 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an exception thrown by an <see cref="T:RGB.NET.Core.IRGBDevice" />.
|
|
||||||
/// </summary>
|
|
||||||
public class RGBDeviceException : ApplicationException
|
|
||||||
{
|
{
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.RGBDeviceException" /> class.
|
/// Represents an exception thrown by an <see cref="T:RGB.NET.Core.IRGBDevice" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">The message which describes the reason of throwing this exception.</param>
|
public class RGBDeviceException : ApplicationException
|
||||||
/// <param name="innerException">Optional inner exception, which lead to this exception.</param>
|
{
|
||||||
public RGBDeviceException(string message, Exception? innerException = null)
|
#region Constructors
|
||||||
: base(message, innerException)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
#endregion
|
/// <inheritdoc />
|
||||||
}
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.RGBDeviceException" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message which describes the reason of throwing this exception.</param>
|
||||||
|
/// <param name="innerException">Optional inner exception, which lead to this exception.</param>
|
||||||
|
public RGBDeviceException(string message, Exception innerException = null)
|
||||||
|
: base(message, innerException)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an exception thrown by an <see cref="T:RGB.NET.Core.RGBSurface" />.
|
|
||||||
/// </summary>
|
|
||||||
public class RGBSurfaceException : ApplicationException
|
|
||||||
{
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.RGBSurfaceException" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">The message which describes the reason of throwing this exception.</param>
|
|
||||||
/// <param name="innerException">Optional inner exception, which lead to this exception.</param>
|
|
||||||
public RGBSurfaceException(string message, Exception? innerException = null)
|
|
||||||
: base(message, innerException)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -1,32 +1,30 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offers some extensions and helper-methods for <see cref="Color"/> related things.
|
|
||||||
/// </summary>
|
|
||||||
public static class ColorExtensions
|
|
||||||
{
|
{
|
||||||
#region Methods
|
public static class ColorExtensions
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Calculates the distance between the two specified colors using the redmean algorithm.
|
|
||||||
/// For more infos check https://www.compuphase.com/cmetric.htm
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color1">The start color of the distance calculation.</param>
|
|
||||||
/// <param name="color2">The end color fot the distance calculation.</param>
|
|
||||||
/// <returns>The redmean distance between the two specified colors.</returns>
|
|
||||||
public static double DistanceTo(this Color color1, Color color2)
|
|
||||||
{
|
{
|
||||||
(_, byte r1, byte g1, byte b1) = color1.GetRGBBytes();
|
#region Methods
|
||||||
(_, byte r2, byte g2, byte b2) = color2.GetRGBBytes();
|
|
||||||
|
|
||||||
long rmean = (r1 + r2) / 2;
|
/// <summary>
|
||||||
long r = r1 - r2;
|
/// Calculates the distance between the two given colors using the redmean algorithm.
|
||||||
long g = g1 - g2;
|
/// For more infos check https://www.compuphase.com/cmetric.htm
|
||||||
long b = b1 - b2;
|
/// </summary>
|
||||||
return Math.Sqrt((((512 + rmean) * r * r) >> 8) + (4 * g * g) + (((767 - rmean) * b * b) >> 8));
|
/// <param name="color1">The start color of the distance calculation.</param>
|
||||||
|
/// <param name="color2">The end color fot the distance calculation.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static double DistanceTo(this Color color1, Color color2)
|
||||||
|
{
|
||||||
|
(_, byte r1, byte g1, byte b1) = color1.GetRGBBytes();
|
||||||
|
(_, byte r2, byte g2, byte b2) = color2.GetRGBBytes();
|
||||||
|
|
||||||
|
long rmean = (r1 + r2) / 2;
|
||||||
|
long r = r1 - r2;
|
||||||
|
long g = g1 - g2;
|
||||||
|
long b = b1 - b2;
|
||||||
|
return Math.Sqrt((((512 + rmean) * r * r) >> 8) + (4 * g * g) + (((767 - rmean) * b * b) >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,55 +0,0 @@
|
|||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offers some extensions for easier use of <see cref="CustomUpdateData"/>.
|
|
||||||
/// </summary>
|
|
||||||
public static class CustomUpdateDataExtension
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the <see cref="CustomUpdateDataIndex.FLUSH_LEDS"/>-Parameter to the given value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="customUpdateData">The update-data to modify.</param>
|
|
||||||
/// <param name="value">The value to set.</param>
|
|
||||||
/// <returns>The modified update-data.</returns>
|
|
||||||
public static CustomUpdateData FlushLeds(this CustomUpdateData customUpdateData, bool value = true)
|
|
||||||
{
|
|
||||||
customUpdateData[CustomUpdateDataIndex.FLUSH_LEDS] = value;
|
|
||||||
return customUpdateData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the <see cref="CustomUpdateDataIndex.RENDER"/>-Parameter to the given value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="customUpdateData">The update-data to modify.</param>
|
|
||||||
/// <param name="value">The value to set.</param>
|
|
||||||
/// <returns>The modified update-data.</returns>
|
|
||||||
public static CustomUpdateData Render(this CustomUpdateData customUpdateData, bool value = true)
|
|
||||||
{
|
|
||||||
customUpdateData[CustomUpdateDataIndex.RENDER] = value;
|
|
||||||
return customUpdateData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the <see cref="CustomUpdateDataIndex.UPDATE_DEVICES"/>-Parameter to the given value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="customUpdateData">The update-data to modify.</param>
|
|
||||||
/// <param name="value">The value to set.</param>
|
|
||||||
/// <returns>The modified update-data.</returns>
|
|
||||||
public static CustomUpdateData UpdateDevices(this CustomUpdateData customUpdateData, bool value = true)
|
|
||||||
{
|
|
||||||
customUpdateData[CustomUpdateDataIndex.UPDATE_DEVICES] = value;
|
|
||||||
return customUpdateData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the <see cref="CustomUpdateDataIndex.HEARTBEAT"/>-Parameter to the given value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="customUpdateData">The update-data to modify.</param>
|
|
||||||
/// <param name="value">The value to set.</param>
|
|
||||||
/// <returns>The modified update-data.</returns>
|
|
||||||
public static CustomUpdateData Heartbeat(this CustomUpdateData customUpdateData, bool value = true)
|
|
||||||
{
|
|
||||||
customUpdateData[CustomUpdateDataIndex.HEARTBEAT] = value;
|
|
||||||
return customUpdateData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,111 +1,101 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offers some extensions and helper-methods for the work with floats.
|
|
||||||
/// </summary>
|
|
||||||
public static class FloatExtensions
|
|
||||||
{
|
{
|
||||||
#region Constants
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the precision RGB.NET processes floating point comparisons in.
|
/// Offers some extensions and helper-methods for the work with doubles
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const float TOLERANCE = 1E-7f;
|
public static class DoubleExtensions
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if two values are equal respecting the <see cref="TOLERANCE"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value1">The first value to compare.</param>
|
|
||||||
/// <param name="value2">The first value to compare.</param>
|
|
||||||
/// <returns><c>true</c> if the difference is smaller than the <see cref="TOLERANCE"/>; otherwise, <c>false</c>.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static bool EqualsInTolerance(this float value1, float value2) => Math.Abs(value1 - value2) < TOLERANCE;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clamps the provided value to be bigger or equal min and smaller or equal max.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value to clamp.</param>
|
|
||||||
/// <param name="min">The lower value of the range the value is clamped to.</param>
|
|
||||||
/// <param name="max">The higher value of the range the value is clamped to.</param>
|
|
||||||
/// <returns>The clamped value.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Clamp(this float value, float min, float max)
|
|
||||||
{
|
{
|
||||||
// ReSharper disable ConvertIfStatementToReturnStatement - I'm not sure why, but inlining this statement reduces performance by ~10%
|
#region Constants
|
||||||
if (value < min) return min;
|
|
||||||
if (value > max) return max;
|
/// <summary>
|
||||||
return value;
|
/// Defines the precision RGB.NET processes floating point comparisons in.
|
||||||
// ReSharper restore ConvertIfStatementToReturnStatement
|
/// </summary>
|
||||||
|
public const double TOLERANCE = 1E-10;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if two values are equal respecting the <see cref="TOLERANCE"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value1">The first value to compare.</param>
|
||||||
|
/// <param name="value2">The first value to compare.</param>
|
||||||
|
/// <returns><c>true</c> if the difference is smaller than the <see cref="TOLERANCE"/>; otherwise, <c>false</c>.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool EqualsInTolerance(this double value1, double value2) => Math.Abs(value1 - value2) < TOLERANCE;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clamps the provided value to be bigger or equal min and smaller or equal max.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to clamp.</param>
|
||||||
|
/// <param name="min">The lower value of the range the value is clamped to.</param>
|
||||||
|
/// <param name="max">The higher value of the range the value is clamped to.</param>
|
||||||
|
/// <returns>The clamped value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static double Clamp(this double value, double min, double max)
|
||||||
|
{
|
||||||
|
// ReSharper disable ConvertIfStatementToReturnStatement - I'm not sure why, but inlining this statement reduces performance by ~10%
|
||||||
|
if (value < min) return min;
|
||||||
|
if (value > max) return max;
|
||||||
|
return value;
|
||||||
|
// ReSharper restore ConvertIfStatementToReturnStatement
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clamps the provided value to be bigger or equal min and smaller or equal max.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to clamp.</param>
|
||||||
|
/// <param name="min">The lower value of the range the value is clamped to.</param>
|
||||||
|
/// <param name="max">The higher value of the range the value is clamped to.</param>
|
||||||
|
/// <returns>The clamped value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Clamp(this int value, int min, int max)
|
||||||
|
{
|
||||||
|
// ReSharper disable ConvertIfStatementToReturnStatement - I'm not sure why, but inlining this statement reduces performance by ~10%
|
||||||
|
if (value < min) return min;
|
||||||
|
if (value > max) return max;
|
||||||
|
return value;
|
||||||
|
// ReSharper restore ConvertIfStatementToReturnStatement
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enforces the provided value to be in the specified range by wrapping it around the edges if it exceeds them.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to wrap.</param>
|
||||||
|
/// <param name="min">The lower value of the range the value is wrapped into.</param>
|
||||||
|
/// <param name="max">The higher value of the range the value is wrapped into.</param>
|
||||||
|
/// <returns>The wrapped value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static double Wrap(this double value, double min, double max)
|
||||||
|
{
|
||||||
|
double range = max - min;
|
||||||
|
|
||||||
|
while (value >= max)
|
||||||
|
value -= range;
|
||||||
|
|
||||||
|
while (value < min)
|
||||||
|
value += range;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static byte GetByteValueFromPercentage(this double percentage)
|
||||||
|
{
|
||||||
|
if (double.IsNaN(percentage)) return 0;
|
||||||
|
|
||||||
|
percentage = percentage.Clamp(0, 1.0);
|
||||||
|
return (byte)(percentage >= 1.0 ? 255 : percentage * 256.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static double GetPercentageFromByteValue(this byte value)
|
||||||
|
=> ((double)value) / byte.MaxValue;
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Clamps the provided value to be bigger or equal min and smaller or equal max.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value to clamp.</param>
|
|
||||||
/// <param name="min">The lower value of the range the value is clamped to.</param>
|
|
||||||
/// <param name="max">The higher value of the range the value is clamped to.</param>
|
|
||||||
/// <returns>The clamped value.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static int Clamp(this int value, int min, int max)
|
|
||||||
{
|
|
||||||
// ReSharper disable ConvertIfStatementToReturnStatement - I'm not sure why, but inlining this statement reduces performance by ~10%
|
|
||||||
if (value < min) return min;
|
|
||||||
if (value > max) return max;
|
|
||||||
return value;
|
|
||||||
// ReSharper restore ConvertIfStatementToReturnStatement
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enforces the provided value to be in the specified range by wrapping it around the edges if it exceeds them.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value to wrap.</param>
|
|
||||||
/// <param name="min">The lower value of the range the value is wrapped into.</param>
|
|
||||||
/// <param name="max">The higher value of the range the value is wrapped into.</param>
|
|
||||||
/// <returns>The wrapped value.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Wrap(this float value, float min, float max)
|
|
||||||
{
|
|
||||||
float range = max - min;
|
|
||||||
|
|
||||||
while (value >= max)
|
|
||||||
value -= range;
|
|
||||||
|
|
||||||
while (value < min)
|
|
||||||
value += range;
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a normalized float value in the range [0..1] to a byte [0..255].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="percentage">The normalized float value to convert.</param>
|
|
||||||
/// <returns>The byte value.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static byte GetByteValueFromPercentage(this float percentage)
|
|
||||||
{
|
|
||||||
// ReSharper disable once ConvertIfStatementToSwitchStatement - This results in a bit more instructions
|
|
||||||
if (float.IsNaN(percentage) || (percentage <= 0)) return 0;
|
|
||||||
if (percentage >= 1.0f) return byte.MaxValue;
|
|
||||||
|
|
||||||
return (byte)(percentage * 256.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a byte value [0..255] to a normalized float value in the range [0..1].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The byte value to convert.</param>
|
|
||||||
/// <returns>The normalized float value.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float GetPercentageFromByteValue(this byte value)
|
|
||||||
=> value == 255 ? 1.0f : (value / 256.0f);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,43 +1,37 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offers some extensions and helper-methods for <see cref="Point"/> related things.
|
|
||||||
/// </summary>
|
|
||||||
public static class PointExtensions
|
|
||||||
{
|
{
|
||||||
#region Methods
|
public static class PointExtensions
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Moves the specified <see cref="Point"/> by the specified amount.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="point">The <see cref="Point"/> to move.</param>
|
|
||||||
/// <param name="x">The x-ammount to move.</param>
|
|
||||||
/// <param name="y">The y-ammount to move.</param>
|
|
||||||
/// <returns>The new location of the point.</returns>
|
|
||||||
public static Point Translate(this Point point, float x = 0, float y = 0) => new(point.X + x, point.Y + y);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Rotates the specified <see cref="Point"/> by the specified amuont around the specified origin.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="point">The <see cref="Point"/> to rotate.</param>
|
|
||||||
/// <param name="rotation">The rotation.</param>
|
|
||||||
/// <param name="origin">The origin to rotate around. [0,0] if not set.</param>
|
|
||||||
/// <returns>The new location of the point.</returns>
|
|
||||||
public static Point Rotate(this Point point, Rotation rotation, Point origin = new())
|
|
||||||
{
|
{
|
||||||
float sin = MathF.Sin(rotation.Radians);
|
#region Methods
|
||||||
float cos = MathF.Cos(rotation.Radians);
|
|
||||||
|
|
||||||
float x = point.X - origin.X;
|
/// <summary>
|
||||||
float y = point.Y - origin.Y;
|
/// Moves the specified <see cref="Point"/> by the given amount.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The <see cref="Point"/> to move.</param>
|
||||||
|
/// <param name="x">The x-ammount to move.</param>
|
||||||
|
/// <param name="y">The y-ammount to move.</param>
|
||||||
|
/// <returns>The new location of the point.</returns>
|
||||||
|
public static Point Translate(this Point point, double x = 0, double y = 0) => new Point(point.X + x, point.Y + y);
|
||||||
|
|
||||||
x = (x * cos) - (y * sin);
|
/// <summary>
|
||||||
y = (x * sin) + (y * cos);
|
/// Rotates the specified <see cref="Point"/> by the given amuont around the given origin.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The <see cref="Point"/> to rotate.</param>
|
||||||
|
/// <param name="rotation">The rotation.</param>
|
||||||
|
/// <param name="origin">The origin to rotate around. [0,0] if not set.</param>
|
||||||
|
/// <returns>The new location of the point.</returns>
|
||||||
|
public static Point Rotate(this Point point, Rotation rotation, Point origin = new Point())
|
||||||
|
{
|
||||||
|
double sin = Math.Sin(rotation.Radians);
|
||||||
|
double cos = Math.Cos(rotation.Radians);
|
||||||
|
|
||||||
return new Point(x + origin.X, y + origin.Y);
|
point = new Point(point.X - origin.X, point.Y - origin.Y);
|
||||||
|
point = new Point((point.X * cos) - (point.Y * sin), (point.X * sin) + (point.Y * cos));
|
||||||
|
return new Point(point.X + origin.X, point.Y + origin.Y); ;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,177 +1,169 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offers some extensions and helper-methods for the work with rectangles.
|
|
||||||
/// </summary>
|
|
||||||
public static class RectangleExtensions
|
|
||||||
{
|
{
|
||||||
#region Methods
|
public static class RectangleExtensions
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the <see cref="Rectangle.Location"/> of the specified rectangle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The rectangle to modify.</param>
|
|
||||||
/// <param name="location">The new location of the rectangle.</param>
|
|
||||||
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
|
||||||
public static Rectangle SetLocation(this Rectangle rect, Point location) => new(location, rect.Size);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the <see cref="Point.X"/> of the <see cref="Rectangle.Location"/> of the specified rectangle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The rectangle to modify.</param>
|
|
||||||
/// <param name="x">The new x-location of the rectangle.</param>
|
|
||||||
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
|
||||||
public static Rectangle SetX(this Rectangle rect, float x) => new(new Point(x, rect.Location.Y), rect.Size);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the <see cref="Point.Y"/> of the <see cref="Rectangle.Location"/> of the specified rectangle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The rectangle to modify.</param>
|
|
||||||
/// <param name="y">The new y-location of the rectangle.</param>
|
|
||||||
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
|
||||||
public static Rectangle SetY(this Rectangle rect, float y) => new(new Point(rect.Location.X, y), rect.Size);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the <see cref="Rectangle.Size"/> of the specified rectangle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The rectangle to modify.</param>
|
|
||||||
/// <param name="size">The new size of the rectangle.</param>
|
|
||||||
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
|
||||||
public static Rectangle SetSize(this Rectangle rect, Size size) => new(rect.Location, size);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the <see cref="Size.Width"/> of the <see cref="Rectangle.Size"/> of the specified rectangle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The rectangle to modify.</param>
|
|
||||||
/// <param name="width">The new width of the rectangle.</param>
|
|
||||||
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
|
||||||
public static Rectangle SetWidth(this Rectangle rect, float width) => new(rect.Location, new Size(width, rect.Size.Height));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the <see cref="Size.Height"/> of the <see cref="Rectangle.Size"/> of the specified rectangle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The rectangle to modify.</param>
|
|
||||||
/// <param name="height">The new height of the rectangle.</param>
|
|
||||||
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
|
||||||
public static Rectangle SetHeight(this Rectangle rect, float height) => new(rect.Location, new Size(rect.Size.Width, height));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Calculates the percentage of intersection of a rectangle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The rectangle to calculate the intersection for.</param>
|
|
||||||
/// <param name="intersectingRect">The intersecting rectangle.</param>
|
|
||||||
/// <returns>The percentage of intersection.</returns>
|
|
||||||
public static float CalculateIntersectPercentage(this Rectangle rect, Rectangle intersectingRect)
|
|
||||||
{
|
{
|
||||||
if (rect.IsEmpty || intersectingRect.IsEmpty) return 0;
|
#region Methods
|
||||||
|
|
||||||
Rectangle intersection = rect.CalculateIntersection(intersectingRect);
|
/// <summary>
|
||||||
return (intersection.Size.Width * intersection.Size.Height) / (rect.Size.Width * rect.Size.Height);
|
/// Sets the <see cref="Rectangle.Location"/> of the given rectangle.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <param name="rect">The rectangle to modify.</param>
|
||||||
|
/// <param name="location">The new location of the rectangle.</param>
|
||||||
|
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
||||||
|
public static Rectangle SetLocation(this Rectangle rect, Point location) => new Rectangle(location, rect.Size);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculates the <see cref="Rectangle"/> representing the intersection of this <see cref="Rectangle"/> and the one provided as parameter.
|
/// Sets the <see cref="Point.X"/> of the <see cref="Rectangle.Location"/> of the given rectangle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rect">The rectangle to calculate the intersection for.</param>
|
/// <param name="rect">The rectangle to modify.</param>
|
||||||
/// <param name="intersectingRectangle">The intersecting <see cref="Rectangle"/>.</param>
|
/// <param name="x">The new x-location of the rectangle.</param>
|
||||||
/// <returns>A new <see cref="Rectangle"/> representing the intersection this <see cref="Rectangle"/> and the one provided as parameter.</returns>
|
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
||||||
public static Rectangle CalculateIntersection(this Rectangle rect, Rectangle intersectingRectangle)
|
public static Rectangle SetX(this Rectangle rect, double x) => new Rectangle(new Point(x, rect.Location.Y), rect.Size);
|
||||||
{
|
|
||||||
float x1 = Math.Max(rect.Location.X, intersectingRectangle.Location.X);
|
|
||||||
float x2 = Math.Min(rect.Location.X + rect.Size.Width, intersectingRectangle.Location.X + intersectingRectangle.Size.Width);
|
|
||||||
|
|
||||||
float y1 = Math.Max(rect.Location.Y, intersectingRectangle.Location.Y);
|
/// <summary>
|
||||||
float y2 = Math.Min(rect.Location.Y + rect.Size.Height, intersectingRectangle.Location.Y + intersectingRectangle.Size.Height);
|
/// Sets the <see cref="Point.Y"/> of the <see cref="Rectangle.Location"/> of the given rectangle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rect">The rectangle to modify.</param>
|
||||||
|
/// <param name="y">The new y-location of the rectangle.</param>
|
||||||
|
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
||||||
|
public static Rectangle SetY(this Rectangle rect, double y) => new Rectangle(new Point(rect.Location.X, y), rect.Size);
|
||||||
|
|
||||||
if ((x2 >= x1) && (y2 >= y1))
|
/// <summary>
|
||||||
return new Rectangle(x1, y1, x2 - x1, y2 - y1);
|
/// Sets the <see cref="Rectangle.Size"/> of the given rectangle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rect">The rectangle to modify.</param>
|
||||||
|
/// <param name="size">The new size of the rectangle.</param>
|
||||||
|
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
||||||
|
public static Rectangle SetSize(this Rectangle rect, Size size) => new Rectangle(rect.Location, size);
|
||||||
|
|
||||||
return new Rectangle();
|
/// <summary>
|
||||||
}
|
/// Sets the <see cref="Size.Width"/> of the <see cref="Rectangle.Size"/> of the given rectangle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rect">The rectangle to modify.</param>
|
||||||
|
/// <param name="width">The new width of the rectangle.</param>
|
||||||
|
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
||||||
|
public static Rectangle SetWidth(this Rectangle rect, double width) => new Rectangle(rect.Location, new Size(width, rect.Size.Height));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if the specified <see cref="Point"/> is contained within this <see cref="Rectangle"/>.
|
/// Sets the <see cref="Size.Height"/> of the <see cref="Rectangle.Size"/> of the given rectangle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rect">The containing rectangle.</param>
|
/// <param name="rect">The rectangle to modify.</param>
|
||||||
/// <param name="point">The <see cref="Point"/> to test.</param>
|
/// <param name="height">The new height of the rectangle.</param>
|
||||||
/// <returns><c>true</c> if the rectangle contains the specified point; otherwise <c>false</c>.</returns>
|
/// <returns>The modified <see cref="Rectangle"/>.</returns>
|
||||||
public static bool Contains(this Rectangle rect, Point point) => rect.Contains(point.X, point.Y);
|
public static Rectangle SetHeight(this Rectangle rect, double height) => new Rectangle(rect.Location, new Size(rect.Size.Width, height));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if the specified location is contained within this <see cref="Rectangle"/>.
|
/// Calculates the percentage of intersection of a rectangle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rect">The containing rectangle.</param>
|
/// <param name="intersectingRect">The intersecting rectangle.</param>
|
||||||
/// <param name="x">The X-location to test.</param>
|
/// <returns>The percentage of intersection.</returns>
|
||||||
/// <param name="y">The Y-location to test.</param>
|
public static double CalculateIntersectPercentage(this Rectangle rect, Rectangle intersectingRect)
|
||||||
/// <returns><c>true</c> if the rectangle contains the specified coordinates; otherwise <c>false</c>.</returns>
|
|
||||||
public static bool Contains(this Rectangle rect, float x, float y) => (rect.Location.X <= x) && (x < (rect.Location.X + rect.Size.Width))
|
|
||||||
&& (rect.Location.Y <= y) && (y < (rect.Location.Y + rect.Size.Height));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines if the specified <see cref="Rectangle"/> is contained within this <see cref="Rectangle"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The containing rectangle.</param>
|
|
||||||
/// <param name="rect2">The <see cref="Rectangle"/> to test.</param>
|
|
||||||
/// <returns><c>true</c> if the rectangle contains the specified rect; otherwise <c>false</c>.</returns>
|
|
||||||
public static bool Contains(this Rectangle rect, Rectangle rect2) => (rect.Location.X <= rect2.Location.X) && ((rect2.Location.X + rect2.Size.Width) <= (rect.Location.X + rect.Size.Width))
|
|
||||||
&& (rect.Location.Y <= rect2.Location.Y) && ((rect2.Location.Y + rect2.Size.Height) <= (rect.Location.Y + rect.Size.Height));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Moves the specified <see cref="Rectangle"/> by the specified amount.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The <see cref="Rectangle"/> to move.</param>
|
|
||||||
/// <param name="point">The amount to move.</param>
|
|
||||||
/// <returns>The moved rectangle.</returns>
|
|
||||||
public static Rectangle Translate(this Rectangle rect, Point point) => rect.Translate(point.X, point.Y);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Moves the specified <see cref="Rectangle"/> by the specified amount.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rect">The <see cref="Rectangle"/> to move.</param>
|
|
||||||
/// <param name="x">The x-ammount to move.</param>
|
|
||||||
/// <param name="y">The y-ammount to move.</param>
|
|
||||||
/// <returns>The moved rectangle.</returns>
|
|
||||||
public static Rectangle Translate(this Rectangle rect, float x = 0, float y = 0) => new(rect.Location.Translate(x, y), rect.Size);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Rotates the specified <see cref="Rectangle"/> by the specified amuont around the specified origin.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The returned array of <see cref="Point"/> is filled with the new locations of the rectangle clockwise starting from the top left:
|
|
||||||
/// [0] = top left
|
|
||||||
/// [1] = top right
|
|
||||||
/// [2] = bottom right
|
|
||||||
/// [3] = bottom left
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="rect">The <see cref="Rectangle"/> to rotate.</param>
|
|
||||||
/// <param name="rotation">The rotation.</param>
|
|
||||||
/// <param name="origin">The origin to rotate around. [0,0] if not set.</param>
|
|
||||||
/// <returns>A array of <see cref="Point"/> containing the new locations of the corners of the original rectangle.</returns>
|
|
||||||
public static Point[] Rotate(this Rectangle rect, Rotation rotation, Point origin = new())
|
|
||||||
{
|
|
||||||
Point[] points =
|
|
||||||
[
|
|
||||||
rect.Location, // top left
|
|
||||||
new(rect.Location.X + rect.Size.Width, rect.Location.Y), // top right
|
|
||||||
new(rect.Location.X + rect.Size.Width, rect.Location.Y + rect.Size.Height), // bottom right
|
|
||||||
new(rect.Location.X, rect.Location.Y + rect.Size.Height), // bottom right
|
|
||||||
];
|
|
||||||
|
|
||||||
float sin = MathF.Sin(rotation.Radians);
|
|
||||||
float cos = MathF.Cos(rotation.Radians);
|
|
||||||
|
|
||||||
for (int i = 0; i < points.Length; i++)
|
|
||||||
{
|
{
|
||||||
Point point = points[i];
|
if (rect.IsEmpty || intersectingRect.IsEmpty) return 0;
|
||||||
point = new Point(point.X - origin.X, point.Y - origin.Y);
|
|
||||||
point = new Point((point.X * cos) - (point.Y * sin), (point.X * sin) + (point.Y * cos));
|
Rectangle intersection = rect.CalculateIntersection(intersectingRect);
|
||||||
points[i] = new Point(point.X + origin.X, point.Y + origin.Y);
|
return (intersection.Size.Width * intersection.Size.Height) / (rect.Size.Width * rect.Size.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
return points;
|
/// <summary>
|
||||||
}
|
/// Calculates the <see cref="Rectangle"/> representing the intersection of this <see cref="Rectangle"/> and the one provided as parameter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="intersectingRectangle">The intersecting <see cref="Rectangle"/></param>
|
||||||
|
/// <returns>A new <see cref="Rectangle"/> representing the intersection this <see cref="Rectangle"/> and the one provided as parameter.</returns>
|
||||||
|
public static Rectangle CalculateIntersection(this Rectangle rect, Rectangle intersectingRectangle)
|
||||||
|
{
|
||||||
|
double x1 = Math.Max(rect.Location.X, intersectingRectangle.Location.X);
|
||||||
|
double x2 = Math.Min(rect.Location.X + rect.Size.Width, intersectingRectangle.Location.X + intersectingRectangle.Size.Width);
|
||||||
|
|
||||||
#endregion
|
double y1 = Math.Max(rect.Location.Y, intersectingRectangle.Location.Y);
|
||||||
}
|
double y2 = Math.Min(rect.Location.Y + rect.Size.Height, intersectingRectangle.Location.Y + intersectingRectangle.Size.Height);
|
||||||
|
|
||||||
|
if ((x2 >= x1) && (y2 >= y1))
|
||||||
|
return new Rectangle(x1, y1, x2 - x1, y2 - y1);
|
||||||
|
|
||||||
|
return new Rectangle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the specified <see cref="Point"/> is contained within this <see cref="Rectangle"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The <see cref="Point"/> to test.</param>
|
||||||
|
/// <returns><c>true</c> if the rectangle contains the given point; otherwise <c>false</c>.</returns>
|
||||||
|
public static bool Contains(this Rectangle rect, Point point) => rect.Contains(point.X, point.Y);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the specified location is contained within this <see cref="Rectangle"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The X-location to test.</param>
|
||||||
|
/// <param name="y">The Y-location to test.</param>
|
||||||
|
/// <returns><c>true</c> if the rectangle contains the given coordinates; otherwise <c>false</c>.</returns>
|
||||||
|
public static bool Contains(this Rectangle rect, double x, double y) => (rect.Location.X <= x) && (x < (rect.Location.X + rect.Size.Width))
|
||||||
|
&& (rect.Location.Y <= y) && (y < (rect.Location.Y + rect.Size.Height));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the specified <see cref="Rectangle"/> is contained within this <see cref="Rectangle"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rect">The <see cref="Rectangle"/> to test.</param>
|
||||||
|
/// <returns><c>true</c> if the rectangle contains the given rect; otherwise <c>false</c>.</returns>
|
||||||
|
public static bool Contains(this Rectangle rect, Rectangle rect2) => (rect.Location.X <= rect2.Location.X) && ((rect2.Location.X + rect2.Size.Width) <= (rect.Location.X + rect.Size.Width))
|
||||||
|
&& (rect.Location.Y <= rect2.Location.Y) && ((rect2.Location.Y + rect2.Size.Height) <= (rect.Location.Y + rect.Size.Height));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Moves the specified <see cref="Rectangle"/> by the given amount.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rect">The <see cref="Rectangle"/> to move.</param>
|
||||||
|
/// <param name="point">The amount to move.</param>
|
||||||
|
/// <returns>The moved rectangle.</returns>
|
||||||
|
public static Rectangle Translate(this Rectangle rect, Point point) => rect.Translate(point.X, point.Y);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Moves the specified <see cref="Rectangle"/> by the given amount.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rect">The <see cref="Rectangle"/> to move.</param>
|
||||||
|
/// <param name="x">The x-ammount to move.</param>
|
||||||
|
/// <param name="y">The y-ammount to move.</param>
|
||||||
|
/// <returns>The moved rectangle.</returns>
|
||||||
|
public static Rectangle Translate(this Rectangle rect, double x = 0, double y = 0) => new Rectangle(rect.Location.Translate(x, y), rect.Size);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the specified <see cref="Rectangle"/> by the given amuont around the given origin.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The returned array of <see cref="Point"/> is filled with the new locations of the rectangle clockwise starting from the top left:
|
||||||
|
/// [0] = top left
|
||||||
|
/// [1] = top right
|
||||||
|
/// [2] = bottom right
|
||||||
|
/// [3] = bottom left
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="rect">The <see cref="Rectangle"/> to rotate.</param>
|
||||||
|
/// <param name="rotation">The rotation.</param>
|
||||||
|
/// <param name="origin">The origin to rotate around. [0,0] if not set.</param>
|
||||||
|
/// <returns>A array of <see cref="Point"/> containing the new locations of the corners of the original rectangle.</returns>
|
||||||
|
public static Point[] Rotate(this Rectangle rect, Rotation rotation, Point origin = new Point())
|
||||||
|
{
|
||||||
|
Point[] points = {
|
||||||
|
rect.Location, // top left
|
||||||
|
new Point(rect.Location.X + rect.Size.Width, rect.Location.Y), // top right
|
||||||
|
new Point(rect.Location.X + rect.Size.Width, rect.Location.Y + rect.Size.Height), // bottom right
|
||||||
|
new Point(rect.Location.X, rect.Location.Y + rect.Size.Height), // bottom right
|
||||||
|
};
|
||||||
|
|
||||||
|
double sin = Math.Sin(rotation.Radians);
|
||||||
|
double cos = Math.Cos(rotation.Radians);
|
||||||
|
|
||||||
|
for (int i = 0; i < points.Length; i++)
|
||||||
|
{
|
||||||
|
Point point = points[i];
|
||||||
|
point = new Point(point.X - origin.X, point.Y - origin.Y);
|
||||||
|
point = new Point((point.X * cos) - (point.Y * sin), (point.X * sin) + (point.Y * cos));
|
||||||
|
points[i] = new Point(point.X + origin.X, point.Y + origin.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
public static class ReferenceCountingExtension
|
|
||||||
{
|
|
||||||
public static bool HasActiveReferences(this IReferenceCounting target) => target.ActiveReferenceCount > 0;
|
|
||||||
}
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
// ReSharper disable UnusedMember.Global
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offers some extensions and helper-methods for the work with the surface.
|
|
||||||
/// </summary>
|
|
||||||
public static class SurfaceExtensions
|
|
||||||
{
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the specifiec device provider and attaches all devices.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="surface">The surface to attach the devices to.</param>
|
|
||||||
/// <param name="deviceProvider">The device provider to load.</param>
|
|
||||||
/// <param name="loadFilter"><see cref="RGBDeviceType"/>-flags to filter the devices to load.</param>
|
|
||||||
/// <param name="throwExceptions">Specifies if exceptions should be thrown or silently be ignored.</param>
|
|
||||||
public static void Load(this RGBSurface surface, IRGBDeviceProvider deviceProvider, RGBDeviceType loadFilter = RGBDeviceType.All, bool throwExceptions = false)
|
|
||||||
{
|
|
||||||
if (!deviceProvider.IsInitialized)
|
|
||||||
deviceProvider.Initialize(loadFilter, throwExceptions);
|
|
||||||
|
|
||||||
surface.Attach(deviceProvider.Devices);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attaches the specified devices to the surface.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="surface">The surface the devices are attached to.</param>
|
|
||||||
/// <param name="devices">The devices to attach.</param>
|
|
||||||
public static void Attach(this RGBSurface surface, IEnumerable<IRGBDevice> devices)
|
|
||||||
{
|
|
||||||
foreach (IRGBDevice device in devices)
|
|
||||||
surface.Attach(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Detaches the specified devices from the surface.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="surface">The surface the devices are detached from.</param>
|
|
||||||
/// <param name="devices">The devices to detach.</param>
|
|
||||||
public static void Detach(this RGBSurface surface, IEnumerable<IRGBDevice> devices)
|
|
||||||
{
|
|
||||||
foreach (IRGBDevice device in devices)
|
|
||||||
surface.Detach(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets all devices of a specific type.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of devices to get.</typeparam>
|
|
||||||
/// <returns>A collection of devices with the specified type.</returns>
|
|
||||||
public static IEnumerable<T> GetDevices<T>(this RGBSurface surface)
|
|
||||||
where T : class
|
|
||||||
=> surface.Devices.Where(x => x is T).Cast<T>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets all devices of the specified <see cref="RGBDeviceType"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="surface">The surface to get the devices from.</param>
|
|
||||||
/// <param name="deviceType">The <see cref="RGBDeviceType"/> of the devices to get.</param>
|
|
||||||
/// <returns>A collection of devices matching the specified <see cref="RGBDeviceType"/>.</returns>
|
|
||||||
public static IEnumerable<IRGBDevice> GetDevices(this RGBSurface surface, RGBDeviceType deviceType)
|
|
||||||
=> surface.Devices.Where(d => deviceType.HasFlag(d.DeviceInfo.DeviceType));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Automatically aligns all devices to prevent overlaps.
|
|
||||||
/// </summary>
|
|
||||||
public static void AlignDevices(this RGBSurface surface)
|
|
||||||
{
|
|
||||||
float posX = 0;
|
|
||||||
foreach (IRGBDevice device in surface.Devices)
|
|
||||||
{
|
|
||||||
device.Location += new Point(posX, 0);
|
|
||||||
posX += device.ActualSize.Width + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -1,75 +1,51 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc cref="AbstractDecoratable{T}" />
|
|
||||||
/// <inheritdoc cref="ILedGroup" />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a generic <see cref="T:RGB.NET.Core.AbstractLedGroup" />.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class AbstractLedGroup : AbstractDecoratable<ILedGroupDecorator>, ILedGroup
|
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
/// <inheritdoc cref="AbstractDecoratable{T}" />
|
||||||
|
/// <inheritdoc cref="ILedGroup" />
|
||||||
RGBSurface? ILedGroup.Surface { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc cref="ILedGroup.Surface" />
|
|
||||||
public RGBSurface? Surface => ((ILedGroup)this).Surface;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IBrush? Brush { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public int ZIndex { get; set; } = 0;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AbstractLedGroup"/> class.
|
/// Represents a generic <see cref="T:RGB.NET.Core.AbstractLedGroup" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected AbstractLedGroup(RGBSurface? attachTo)
|
public abstract class AbstractLedGroup : AbstractDecoratable<ILedGroupDecorator>, ILedGroup
|
||||||
{
|
{
|
||||||
attachTo?.Attach(this);
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IBrush Brush { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int ZIndex { get; set; } = 0;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AbstractLedGroup"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="autoAttach">Specifies whether this <see cref="AbstractLedGroup"/> should be automatically attached or not.</param>
|
||||||
|
protected AbstractLedGroup(bool autoAttach)
|
||||||
|
{
|
||||||
|
if (autoAttach)
|
||||||
|
RGBSurface.Instance.AttachLedGroup(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public abstract IList<Led> GetLeds();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void OnAttach()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void OnDetach()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a enumerable containing all leds in this group.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A enumerable containing all leds of this group.</returns>
|
|
||||||
protected abstract IEnumerable<Led> GetLeds();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual void OnAttach() { }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual void OnDetach() { }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual IList<Led> ToList() => GetLeds().ToList();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerator<Led> GetEnumerator() => GetLeds().GetEnumerator();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
IDisposable? ILedGroup.ToListUnsafe(out IList<Led> leds) => ToListUnsafe(out leds);
|
|
||||||
|
|
||||||
protected virtual IDisposable? ToListUnsafe(out IList<Led> leds)
|
|
||||||
{
|
|
||||||
leds = ToList();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,51 +1,40 @@
|
|||||||
// ReSharper disable UnusedMemberInSuper.Global
|
// ReSharper disable UnusedMemberInSuper.Global
|
||||||
// ReSharper disable UnusedMember.Global
|
// ReSharper disable UnusedMember.Global
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a generic ledgroup.
|
|
||||||
/// </summary>
|
|
||||||
public interface ILedGroup : IDecoratable<ILedGroupDecorator>, IEnumerable<Led>
|
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the surface this group is attached to or <c>null</c> if it is not attached to any surface.
|
/// Represents a generic ledgroup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
RGBSurface? Surface { get; internal set; }
|
public interface ILedGroup : IDecoratable<ILedGroupDecorator>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="IBrush"/> which should be drawn over this <see cref="ILedGroup"/>.
|
||||||
|
/// </summary>
|
||||||
|
IBrush Brush { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a bool indicating if the group is attached to a surface.
|
/// Gets or sets the z-index of this <see cref="ILedGroup"/> to allow ordering them before drawing. (lowest first) (default: 0)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsAttached => Surface != null;
|
int ZIndex { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="IBrush"/> which should be drawn over this <see cref="ILedGroup"/>.
|
/// Gets a list containing all <see cref="Led"/> of this <see cref="ILedGroup"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IBrush? Brush { get; set; }
|
/// <returns>The list containing all <see cref="Led"/> of this <see cref="ILedGroup"/>.</returns>
|
||||||
|
IList<Led> GetLeds();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the z-index of this <see cref="ILedGroup"/> to allow ordering them before drawing. (lowest first) (default: 0)
|
/// Called when the <see cref="ILedGroup"/> is attached to the <see cref="RGBSurface"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int ZIndex { get; set; }
|
void OnAttach();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when the <see cref="ILedGroup"/> is attached to the <see cref="RGBSurface"/>.
|
/// Called when the <see cref="ILedGroup"/> is detached from the <see cref="RGBSurface"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void OnAttach();
|
void OnDetach();
|
||||||
|
}
|
||||||
/// <summary>
|
}
|
||||||
/// Called when the <see cref="ILedGroup"/> is detached from the <see cref="RGBSurface"/>.
|
|
||||||
/// </summary>
|
|
||||||
void OnDetach();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a list containing all <see cref="Led"/> in this group.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A list containing all <see cref="Led"/> in this group.</returns>
|
|
||||||
IList<Led> ToList();
|
|
||||||
|
|
||||||
internal IDisposable? ToListUnsafe(out IList<Led> leds);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,57 +0,0 @@
|
|||||||
// ReSharper disable MemberCanBePrivate.Global
|
|
||||||
// ReSharper disable UnusedMember.Global
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offers some extensions and helper-methods for <see cref="ILedGroup"/> related things.
|
|
||||||
/// </summary>
|
|
||||||
public static class LedGroupExtension
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Converts the specified <see cref="ILedGroup" /> to a <see cref="ListLedGroup" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledGroup">The <see cref="ILedGroup" /> to convert.</param>
|
|
||||||
/// <returns>The converted <see cref="ListLedGroup" />.</returns>
|
|
||||||
public static ListLedGroup ToListLedGroup(this ILedGroup ledGroup)
|
|
||||||
{
|
|
||||||
// ReSharper disable once InvertIf
|
|
||||||
if (ledGroup is not ListLedGroup listLedGroup)
|
|
||||||
{
|
|
||||||
if (ledGroup.IsAttached)
|
|
||||||
ledGroup.Detach();
|
|
||||||
listLedGroup = new ListLedGroup(ledGroup.Surface, ledGroup) { Brush = ledGroup.Brush, ZIndex = ledGroup.ZIndex };
|
|
||||||
}
|
|
||||||
return listLedGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a new <see cref="ListLedGroup" /> which contains all <see cref="Led"/> from the specified <see cref="ILedGroup"/> excluding the specified ones.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledGroup">The base <see cref="ILedGroup"/>.</param>
|
|
||||||
/// <param name="ledIds">The <see cref="Led"/> to exclude.</param>
|
|
||||||
/// <returns>The new <see cref="ListLedGroup" />.</returns>
|
|
||||||
public static ListLedGroup Exclude(this ILedGroup ledGroup, params Led[] ledIds)
|
|
||||||
{
|
|
||||||
ListLedGroup listLedGroup = ledGroup.ToListLedGroup();
|
|
||||||
foreach (Led led in ledIds)
|
|
||||||
listLedGroup.RemoveLed(led);
|
|
||||||
return listLedGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReSharper disable once UnusedMethodReturnValue.Global
|
|
||||||
/// <summary>
|
|
||||||
/// Attaches the specified <see cref="ILedGroup"/> to the <see cref="RGBSurface"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledGroup">The <see cref="ILedGroup"/> to attach.</param>
|
|
||||||
/// <param name="surface">The <see cref="RGBSurface"/> to attach this group to.</param>
|
|
||||||
/// <returns><c>true</c> if the <see cref="ILedGroup"/> could be attached; otherwise, <c>false</c>.</returns>
|
|
||||||
public static bool Attach(this ILedGroup ledGroup, RGBSurface surface) => surface.Attach(ledGroup);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Detaches the specified <see cref="ILedGroup"/> from the <see cref="RGBSurface"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledGroup">The <see cref="ILedGroup"/> to attach.</param>
|
|
||||||
/// <returns><c>true</c> if the <see cref="ILedGroup"/> could be detached; otherwise, <c>false</c>.</returns>
|
|
||||||
public static bool Detach(this ILedGroup ledGroup) => ledGroup.Surface?.Detach(ledGroup) ?? false;
|
|
||||||
}
|
|
||||||
@ -1,158 +0,0 @@
|
|||||||
// ReSharper disable MemberCanBePrivate.Global
|
|
||||||
// ReSharper disable UnusedMember.Global
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a ledgroup containing arbitrary <see cref="T:RGB.NET.Core.Led" />.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class ListLedGroup : AbstractLedGroup
|
|
||||||
{
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
private readonly ActionDisposable _unlockDisposable;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the list containing the <see cref="Led"/> of this <see cref="ListLedGroup"/>.
|
|
||||||
/// </summary>
|
|
||||||
private readonly IList<Led> _groupLeds = [];
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Groups.ListLedGroup" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="surface">Specifies the surface to attach this group to or <c>null</c> if the group should not be attached on creation.</param>
|
|
||||||
public ListLedGroup(RGBSurface? surface)
|
|
||||||
: base(surface)
|
|
||||||
{
|
|
||||||
_unlockDisposable = new ActionDisposable(Unlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Groups.ListLedGroup" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="surface">Specifies the surface to attach this group to or <c>null</c> if the group should not be attached on creation.</param>
|
|
||||||
/// <param name="leds">The initial <see cref="T:RGB.NET.Core.Led" /> of this <see cref="T:RGB.NET.Groups.ListLedGroup" />.</param>
|
|
||||||
public ListLedGroup(RGBSurface? surface, IEnumerable<Led> leds)
|
|
||||||
: base(surface)
|
|
||||||
{
|
|
||||||
_unlockDisposable = new ActionDisposable(Unlock);
|
|
||||||
|
|
||||||
AddLeds(leds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Groups.ListLedGroup" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="surface">Specifies the surface to attach this group to or <c>null</c> if the group should not be attached on creation.</param>
|
|
||||||
/// <param name="leds">The initial <see cref="T:RGB.NET.Core.Led" /> of this <see cref="T:RGB.NET.Groups.ListLedGroup" />.</param>
|
|
||||||
public ListLedGroup(RGBSurface? surface, params Led[] leds)
|
|
||||||
: base(surface)
|
|
||||||
{
|
|
||||||
_unlockDisposable = new ActionDisposable(Unlock);
|
|
||||||
|
|
||||||
AddLeds(leds);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified LED(s) to this <see cref="ListLedGroup"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="leds">The LED(s) to add.</param>
|
|
||||||
public void AddLed(params Led[] leds) => AddLeds(leds);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified <see cref="Led"/> to this <see cref="ListLedGroup"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="leds">The <see cref="Led"/> to add.</param>
|
|
||||||
public void AddLeds(IEnumerable<Led> leds)
|
|
||||||
{
|
|
||||||
lock (_groupLeds)
|
|
||||||
foreach (Led led in leds)
|
|
||||||
if (!ContainsLed(led))
|
|
||||||
_groupLeds.Add(led);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the specified LED(s) from this <see cref="ListLedGroup"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="leds">The LED(s) to remove.</param>
|
|
||||||
public void RemoveLed(params Led[] leds) => RemoveLeds(leds);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the specified <see cref="Led"/> from this <see cref="ListLedGroup"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="leds">The <see cref="Led"/> to remove.</param>
|
|
||||||
public void RemoveLeds(IEnumerable<Led> leds)
|
|
||||||
{
|
|
||||||
lock (_groupLeds)
|
|
||||||
foreach (Led led in leds)
|
|
||||||
_groupLeds.Remove(led);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if a specified LED is contained by this ledgroup.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="led">The LED which should be checked.</param>
|
|
||||||
/// <returns><c>true</c> if the LED is contained by this ledgroup; otherwise, <c>false</c>.</returns>
|
|
||||||
public bool ContainsLed(Led led)
|
|
||||||
{
|
|
||||||
lock (_groupLeds)
|
|
||||||
return _groupLeds.Contains(led);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Merges the <see cref="Led"/> from the specified ledgroup in this ledgroup.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="groupToMerge">The ledgroup to merge.</param>
|
|
||||||
public void MergeLeds(ILedGroup groupToMerge)
|
|
||||||
{
|
|
||||||
lock (_groupLeds)
|
|
||||||
foreach (Led led in groupToMerge)
|
|
||||||
if (!_groupLeds.Contains(led))
|
|
||||||
_groupLeds.Add(led);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list containing the <see cref="T:RGB.NET.Core.Led" /> from this group.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The list containing the <see cref="T:RGB.NET.Core.Led" />.</returns>
|
|
||||||
protected override IEnumerable<Led> GetLeds() => ToList();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list containing the <see cref="T:RGB.NET.Core.Led" /> from this group.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The list containing the <see cref="T:RGB.NET.Core.Led" />.</returns>
|
|
||||||
public override IList<Led> ToList()
|
|
||||||
{
|
|
||||||
lock (_groupLeds)
|
|
||||||
return [.._groupLeds];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IDisposable ToListUnsafe(out IList<Led> leds)
|
|
||||||
{
|
|
||||||
Monitor.Enter(_groupLeds);
|
|
||||||
leds = _groupLeds;
|
|
||||||
return _unlockDisposable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Unlock() => Monitor.Exit(_groupLeds);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -1,61 +1,60 @@
|
|||||||
using System;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains helper methods for converting things.
|
|
||||||
/// </summary>
|
|
||||||
public static class ConversionHelper
|
|
||||||
{
|
{
|
||||||
#region Methods
|
|
||||||
|
|
||||||
// Source: https://web.archive.org/web/20180224104425/https://stackoverflow.com/questions/623104/byte-to-hex-string/3974535
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts an array of bytes to a HEX-representation.
|
/// Contains helper methods for converting things.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bytes">The array of bytes.</param>
|
public static class ConversionHelper
|
||||||
/// <returns>The HEX-representation of the provided bytes.</returns>
|
|
||||||
public static string ToHex(params byte[] bytes)
|
|
||||||
{
|
{
|
||||||
char[] c = new char[bytes.Length * 2];
|
#region Methods
|
||||||
|
|
||||||
for (int bx = 0, cx = 0; bx < bytes.Length; ++bx, ++cx)
|
// Source: https://web.archive.org/web/20180224104425/https://stackoverflow.com/questions/623104/byte-to-hex-string/3974535
|
||||||
|
/// <summary>
|
||||||
|
/// Converts an array of bytes to a HEX-representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bytes">The array of bytes.</param>
|
||||||
|
/// <returns>The HEX-representation of the provided bytes.</returns>
|
||||||
|
public static string ToHex(params byte[] bytes)
|
||||||
{
|
{
|
||||||
byte b = ((byte)(bytes[bx] >> 4));
|
char[] c = new char[bytes.Length * 2];
|
||||||
c[cx] = (char)(b > 9 ? b + 0x37 : b + 0x30);
|
|
||||||
|
|
||||||
b = ((byte)(bytes[bx] & 0x0F));
|
for (int bx = 0, cx = 0; bx < bytes.Length; ++bx, ++cx)
|
||||||
c[++cx] = (char)(b > 9 ? b + 0x37 : b + 0x30);
|
{
|
||||||
|
byte b = ((byte)(bytes[bx] >> 4));
|
||||||
|
c[cx] = (char)(b > 9 ? b + 0x37: b + 0x30);
|
||||||
|
|
||||||
|
b = ((byte)(bytes[bx] & 0x0F));
|
||||||
|
c[++cx] = (char)(b > 9 ? b + 0x37: b + 0x30);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new string(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new string(c);
|
// Source: https://web.archive.org/web/20180224104425/https://stackoverflow.com/questions/623104/byte-to-hex-string/3974535
|
||||||
}
|
/// <summary>
|
||||||
|
/// Converts the HEX-representation of a byte array to that array.
|
||||||
// Source: https://web.archive.org/web/20180224104425/https://stackoverflow.com/questions/623104/byte-to-hex-string/3974535
|
/// </summary>
|
||||||
/// <summary>
|
/// <param name="hexString">The HEX-string to convert.</param>
|
||||||
/// Converts the HEX-representation of a byte array to that array.
|
/// <returns>The correspondending byte array.</returns>
|
||||||
/// </summary>
|
public static byte[] HexToBytes(string hexString)
|
||||||
/// <param name="hexString">The HEX-string to convert.</param>
|
|
||||||
/// <returns>The correspondending byte array.</returns>
|
|
||||||
public static byte[] HexToBytes(ReadOnlySpan<char> hexString)
|
|
||||||
{
|
|
||||||
if ((hexString.Length == 0) || ((hexString.Length % 2) != 0))
|
|
||||||
return [];
|
|
||||||
|
|
||||||
byte[] buffer = new byte[hexString.Length / 2];
|
|
||||||
for (int bx = 0, sx = 0; bx < buffer.Length; ++bx, ++sx)
|
|
||||||
{
|
{
|
||||||
// Convert first half of byte
|
if ((hexString.Length == 0) || ((hexString.Length % 2) != 0))
|
||||||
char c = hexString[sx];
|
return new byte[0];
|
||||||
buffer[bx] = (byte)((c > '9' ? (c > 'Z' ? ((c - 'a') + 10) : ((c - 'A') + 10)) : (c - '0')) << 4);
|
|
||||||
|
|
||||||
// Convert second half of byte
|
byte[] buffer = new byte[hexString.Length / 2];
|
||||||
c = hexString[++sx];
|
for (int bx = 0, sx = 0; bx < buffer.Length; ++bx, ++sx)
|
||||||
buffer[bx] |= (byte)(c > '9' ? (c > 'Z' ? ((c - 'a') + 10) : ((c - 'A') + 10)) : (c - '0'));
|
{
|
||||||
|
// Convert first half of byte
|
||||||
|
char c = hexString[sx];
|
||||||
|
buffer[bx] = (byte)((c > '9' ? (c > 'Z' ? ((c - 'a') + 10) : ((c - 'A') + 10)) : (c - '0')) << 4);
|
||||||
|
|
||||||
|
// Convert second half of byte
|
||||||
|
c = hexString[++sx];
|
||||||
|
buffer[bx] |= (byte)(c > '9' ? (c > 'Z' ? ((c - 'a') + 10) : ((c - 'A') + 10)) : (c - '0'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
#endregion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
44
RGB.NET.Core/Helper/CultureHelper.cs
Normal file
44
RGB.NET.Core/Helper/CultureHelper.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Offers some helper-methods for culture related things.
|
||||||
|
/// </summary>
|
||||||
|
public static class CultureHelper
|
||||||
|
{
|
||||||
|
#region DLLImports
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern IntPtr GetKeyboardLayout(uint thread);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current keyboard-layout from the OS.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The current keyboard-layout</returns>
|
||||||
|
public static CultureInfo GetCurrentCulture()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int keyboardLayout = GetKeyboardLayout(0).ToInt32() & 0xFFFF;
|
||||||
|
return new CultureInfo(keyboardLayout);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new CultureInfo(1033); // en-US on error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,26 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offsers some helper methods for device creation.
|
|
||||||
/// </summary>
|
|
||||||
public static class DeviceHelper
|
|
||||||
{
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a unique device name from a manufacturer and model name.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The id is made unique based on the assembly calling this method.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="manufacturer">The manufacturer of the device.</param>
|
|
||||||
/// <param name="model">The model of the device.</param>
|
|
||||||
/// <returns>The unique identifier for this device.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
||||||
public static string CreateDeviceName(string manufacturer, string model) => IdGenerator.MakeUnique(Assembly.GetCallingAssembly(), $"{manufacturer} {model}");
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
83
RGB.NET.Core/Helper/PathHelper.cs
Normal file
83
RGB.NET.Core/Helper/PathHelper.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace RGB.NET.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Offers some helper-methods for file-path related things.
|
||||||
|
/// </summary>
|
||||||
|
public static class PathHelper
|
||||||
|
{
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a path is resolving.
|
||||||
|
/// </summary>
|
||||||
|
public static event EventHandler<ResolvePathEventArgs> ResolvingAbsolutePath;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an absolute path created from an relative path relatvie to the location of the executung assembly.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="relativePath">The relative part of the path to convert.</param>
|
||||||
|
/// <returns>The absolute path.</returns>
|
||||||
|
public static string GetAbsolutePath(string relativePath) => GetAbsolutePath((object)null, relativePath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an absolute path created from an relative path relatvie to the location of the executung assembly.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="relativePath">The relative part of the path to convert.</param>
|
||||||
|
/// <param name="fileName">The file name of the path to convert.</param>
|
||||||
|
/// <returns>The absolute path.</returns>
|
||||||
|
public static string GetAbsolutePath(string relativePath, string fileName) => GetAbsolutePath(null, relativePath, fileName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an absolute path created from an relative path relatvie to the location of the executung assembly.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The requester of this path. (Used for better control when using the event to override this behavior.)</param>
|
||||||
|
/// <param name="relativePath">The relative path to convert.</param>
|
||||||
|
/// <param name="fileName">The file name of the path to convert.</param>
|
||||||
|
/// <returns>The absolute path.</returns>
|
||||||
|
public static string GetAbsolutePath(object sender, string relativePath, string fileName)
|
||||||
|
{
|
||||||
|
string relativePart = Path.Combine(relativePath, fileName);
|
||||||
|
|
||||||
|
string assemblyLocation = Assembly.GetEntryAssembly()?.Location;
|
||||||
|
if (assemblyLocation == null) return relativePart;
|
||||||
|
|
||||||
|
string directoryName = Path.GetDirectoryName(assemblyLocation);
|
||||||
|
string path = directoryName == null ? null : Path.Combine(directoryName, relativePart);
|
||||||
|
|
||||||
|
ResolvePathEventArgs args = new ResolvePathEventArgs(relativePath, fileName, path);
|
||||||
|
ResolvingAbsolutePath?.Invoke(sender, args);
|
||||||
|
|
||||||
|
return args.FinalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an absolute path created from an relative path relatvie to the location of the executung assembly.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The requester of this path. (Used for better control when using the event to override this behavior.)</param>
|
||||||
|
/// <param name="relativePath">The relative path to convert.</param>
|
||||||
|
/// <returns>The absolute path.</returns>
|
||||||
|
public static string GetAbsolutePath(object sender, string relativePath)
|
||||||
|
{
|
||||||
|
string assemblyLocation = Assembly.GetEntryAssembly()?.Location;
|
||||||
|
if (assemblyLocation == null) return relativePath;
|
||||||
|
|
||||||
|
string directoryName = Path.GetDirectoryName(assemblyLocation);
|
||||||
|
string path = directoryName == null ? null : Path.Combine(directoryName, relativePath);
|
||||||
|
|
||||||
|
ResolvePathEventArgs args = new ResolvePathEventArgs(relativePath, path);
|
||||||
|
ResolvingAbsolutePath?.Invoke(sender, args);
|
||||||
|
|
||||||
|
return args.FinalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,178 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offers some helper methods for timed operations.
|
|
||||||
/// </summary>
|
|
||||||
public static class TimerHelper
|
|
||||||
{
|
|
||||||
#region DLL-Imports
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
|
|
||||||
private static extern void TimeBeginPeriod(int t);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod")]
|
|
||||||
private static extern void TimeEndPeriod(int t);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
private static readonly Lock HIGH_RESOLUTION_TIMER_LOCK = new();
|
|
||||||
|
|
||||||
private static bool _areHighResolutionTimersEnabled = false;
|
|
||||||
|
|
||||||
private static bool _useHighResolutionTimers = true;
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets if High Resolution Timers should be used.
|
|
||||||
/// </summary>
|
|
||||||
public static bool UseHighResolutionTimers
|
|
||||||
{
|
|
||||||
get => _useHighResolutionTimers;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
lock (HIGH_RESOLUTION_TIMER_LOCK)
|
|
||||||
{
|
|
||||||
_useHighResolutionTimers = value;
|
|
||||||
CheckHighResolutionTimerUsage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
|
||||||
private static readonly HashSet<HighResolutionTimerDisposable> _timerLeases = [];
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Executes the provided action and blocks if needed until the the <see param="targetExecuteTime"/> has passed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to execute.</param>
|
|
||||||
/// <param name="targetExecuteTime">The time in ms this method should block. default: 0</param>
|
|
||||||
/// <returns>The time in ms spent executing the <see param="action"/>.</returns>
|
|
||||||
public static double Execute(Action action, double targetExecuteTime = 0)
|
|
||||||
{
|
|
||||||
long preUpdateTicks = Stopwatch.GetTimestamp();
|
|
||||||
|
|
||||||
action();
|
|
||||||
|
|
||||||
double updateTime = GetElapsedTime(preUpdateTicks);
|
|
||||||
|
|
||||||
if (targetExecuteTime > 0)
|
|
||||||
{
|
|
||||||
int sleep = (int)(targetExecuteTime - updateTime);
|
|
||||||
if (sleep > 0)
|
|
||||||
Thread.Sleep(sleep);
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Calculates the elapsed time in ms from the provided timestamp until now.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="initialTimestamp">The initial timestamp to calculate the time from.</param>
|
|
||||||
/// <returns>The elapsed time in ms.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static double GetElapsedTime(long initialTimestamp) => ((Stopwatch.GetTimestamp() - initialTimestamp) / (Stopwatch.Frequency / 1000.0));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Requests to use to use High Resolution Timers if enabled.
|
|
||||||
/// IMPORTANT: Always dispose the returned disposable if High Resolution Timers are no longer needed for the caller.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A disposable to remove the request.</returns>
|
|
||||||
public static IDisposable RequestHighResolutionTimer()
|
|
||||||
{
|
|
||||||
HighResolutionTimerDisposable timerLease = new();
|
|
||||||
lock (HIGH_RESOLUTION_TIMER_LOCK)
|
|
||||||
{
|
|
||||||
_timerLeases.Add(timerLease);
|
|
||||||
CheckHighResolutionTimerUsage();
|
|
||||||
}
|
|
||||||
|
|
||||||
return timerLease;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CheckHighResolutionTimerUsage()
|
|
||||||
{
|
|
||||||
if (UseHighResolutionTimers && (_timerLeases.Count > 0))
|
|
||||||
EnableHighResolutionTimers();
|
|
||||||
else
|
|
||||||
DisableHighResolutionTimers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void EnableHighResolutionTimers()
|
|
||||||
{
|
|
||||||
lock (HIGH_RESOLUTION_TIMER_LOCK)
|
|
||||||
{
|
|
||||||
if (_areHighResolutionTimersEnabled) return;
|
|
||||||
|
|
||||||
// DarthAffe 06.05.2022: Linux should use 1ms timers by default
|
|
||||||
if (OperatingSystem.IsWindows())
|
|
||||||
TimeBeginPeriod(1);
|
|
||||||
|
|
||||||
_areHighResolutionTimersEnabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DisableHighResolutionTimers()
|
|
||||||
{
|
|
||||||
lock (HIGH_RESOLUTION_TIMER_LOCK)
|
|
||||||
{
|
|
||||||
if (!_areHighResolutionTimersEnabled) return;
|
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
|
||||||
TimeEndPeriod(1);
|
|
||||||
|
|
||||||
_areHighResolutionTimersEnabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disposes all open High Resolution Timer Requests.
|
|
||||||
/// This should be called once when exiting the application to make sure nothing remains open and the application correctly unregisters itself on OS level.
|
|
||||||
/// Shouldn't be needed if everything is disposed, but better safe then sorry.
|
|
||||||
/// </summary>
|
|
||||||
public static void DisposeAllHighResolutionTimerRequests()
|
|
||||||
{
|
|
||||||
List<HighResolutionTimerDisposable> timerLeases = [.._timerLeases];
|
|
||||||
foreach (HighResolutionTimerDisposable timer in timerLeases)
|
|
||||||
timer.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private class HighResolutionTimerDisposable : IDisposable
|
|
||||||
{
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
private bool _isDisposed = false;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_isDisposed) return;
|
|
||||||
|
|
||||||
_isDisposed = true;
|
|
||||||
|
|
||||||
lock (HIGH_RESOLUTION_TIMER_LOCK)
|
|
||||||
{
|
|
||||||
_timerLeases.Remove(this);
|
|
||||||
CheckHighResolutionTimerUsage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offers some methods to create and handle unique identifiers.
|
|
||||||
/// </summary>
|
|
||||||
public static class IdGenerator
|
|
||||||
{
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
// ReSharper disable InconsistentNaming
|
|
||||||
private static readonly HashSet<string> _registeredIds = [];
|
|
||||||
private static readonly Dictionary<Assembly, Dictionary<string, string>> _idMappings = [];
|
|
||||||
private static readonly Dictionary<Assembly, Dictionary<string, int>> _counter = [];
|
|
||||||
// ReSharper restore InconsistentNaming
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Makes the specified id unique based on the calling assembly by adding a counter if needed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The id to make unique.</param>
|
|
||||||
/// <returns>The unique id.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
||||||
public static string MakeUnique(string id) => MakeUnique(Assembly.GetCallingAssembly(), id);
|
|
||||||
|
|
||||||
internal static string MakeUnique(Assembly callingAssembly, string id)
|
|
||||||
{
|
|
||||||
if (!_idMappings.TryGetValue(callingAssembly, out Dictionary<string, string>? idMapping))
|
|
||||||
{
|
|
||||||
_idMappings.Add(callingAssembly, idMapping = []);
|
|
||||||
_counter.Add(callingAssembly, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary<string, int> counterMapping = _counter[callingAssembly];
|
|
||||||
|
|
||||||
if (!idMapping.TryGetValue(id, out string? mappedId))
|
|
||||||
{
|
|
||||||
mappedId = id;
|
|
||||||
int mappingCounter = 1;
|
|
||||||
while (_registeredIds.Contains(mappedId))
|
|
||||||
mappedId = $"{id} ({++mappingCounter})";
|
|
||||||
|
|
||||||
_registeredIds.Add(mappedId);
|
|
||||||
idMapping.Add(id, mappedId);
|
|
||||||
}
|
|
||||||
|
|
||||||
counterMapping.TryAdd(mappedId, 0);
|
|
||||||
|
|
||||||
int counter = ++counterMapping[mappedId];
|
|
||||||
return counter <= 1 ? mappedId : $"{mappedId} ({counter})";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets the counter used to create unique ids.
|
|
||||||
/// All previous generated ids are not garantueed to stay unique if this is called!
|
|
||||||
/// </summary>
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
||||||
public static void ResetCounter() => ResetCounter(Assembly.GetCallingAssembly());
|
|
||||||
|
|
||||||
internal static void ResetCounter(Assembly callingAssembly)
|
|
||||||
{
|
|
||||||
if (_counter.TryGetValue(callingAssembly, out Dictionary<string, int>? counter))
|
|
||||||
counter.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -1,175 +1,310 @@
|
|||||||
// ReSharper disable MemberCanBePrivate.Global
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
namespace RGB.NET.Core
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a single LED of a RGB-device.
|
|
||||||
/// </summary>
|
|
||||||
[DebuggerDisplay("{Id} {Color}")]
|
|
||||||
public sealed class Led : Placeable
|
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
/// <inheritdoc />
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="IRGBDevice"/> this <see cref="Led"/> is associated with.
|
/// Represents a single LED of a RGB-device.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IRGBDevice Device { get; }
|
[DebuggerDisplay("{Id} {Color}")]
|
||||||
|
public class Led : AbstractBindable
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="LedId"/> of the <see cref="Led" />.
|
|
||||||
/// </summary>
|
|
||||||
public LedId Id { get; }
|
|
||||||
|
|
||||||
private Shape _shape = Shape.Rectangle;
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the <see cref="Core.Shape"/> of the <see cref="Led"/>.
|
|
||||||
/// </summary>
|
|
||||||
public Shape Shape
|
|
||||||
{
|
{
|
||||||
get => _shape;
|
#region Properties & Fields
|
||||||
set => SetProperty(ref _shape, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string? _shapeData;
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets the <see cref="IRGBDevice"/> this <see cref="Led"/> is associated with.
|
||||||
/// Gets or sets the data used for by the <see cref="Core.Shape.Custom"/>-<see cref="Core.Shape"/>.
|
/// </summary>
|
||||||
/// </summary>
|
public IRGBDevice Device { get; }
|
||||||
public string? ShapeData
|
|
||||||
{
|
|
||||||
get => _shapeData;
|
|
||||||
set => SetProperty(ref _shapeData, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Rectangle _absoluteBoundary;
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets the <see cref="LedId"/> of the <see cref="Led" />.
|
||||||
/// Gets a rectangle representing the logical location of the <see cref="Led"/> on the <see cref="RGBSurface"/>.
|
/// </summary>
|
||||||
/// </summary>
|
public LedId Id { get; }
|
||||||
public Rectangle AbsoluteBoundary
|
|
||||||
{
|
|
||||||
get => _absoluteBoundary;
|
|
||||||
private set => SetProperty(ref _absoluteBoundary, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
private Shape _shape = Shape.Rectangle;
|
||||||
/// Indicates whether the <see cref="Led" /> is about to change it's color.
|
/// <summary>
|
||||||
/// </summary>
|
/// Gets or sets the <see cref="Core.Shape"/> of the <see cref="Led"/>.
|
||||||
public bool IsDirty => RequestedColor.HasValue && (RequestedColor != Color);
|
/// </summary>
|
||||||
|
public Shape Shape
|
||||||
private Color? _requestedColor;
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a copy of the <see cref="Core.Color"/> the LED should be set to on the next update.
|
|
||||||
/// Null if there is no update-request for the next update.
|
|
||||||
/// </summary>
|
|
||||||
public Color? RequestedColor
|
|
||||||
{
|
|
||||||
get => _requestedColor;
|
|
||||||
private set
|
|
||||||
{
|
{
|
||||||
SetProperty(ref _requestedColor, value);
|
get => _shape;
|
||||||
|
set => SetProperty(ref _shape, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _shapeData;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the data used for by the <see cref="Core.Shape.Custom"/>-<see cref="Core.Shape"/>.
|
||||||
|
/// </summary>
|
||||||
|
public string ShapeData
|
||||||
|
{
|
||||||
|
get => _shapeData;
|
||||||
|
set => SetProperty(ref _shapeData, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point _location;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the relative location of the <see cref="Led"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Point Location
|
||||||
|
{
|
||||||
|
get => _location;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _location, value))
|
||||||
|
{
|
||||||
|
UpdateActualData();
|
||||||
|
UpdateAbsoluteData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Size _size;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the size of the <see cref="Led"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Size Size
|
||||||
|
{
|
||||||
|
get => _size;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _size, value))
|
||||||
|
{
|
||||||
|
UpdateActualData();
|
||||||
|
UpdateAbsoluteData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point _actualLocation;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the actual location of the <see cref="Led"/>.
|
||||||
|
/// This includes device-scaling and rotation.
|
||||||
|
/// </summary>
|
||||||
|
public Point ActualLocation
|
||||||
|
{
|
||||||
|
get => _actualLocation;
|
||||||
|
private set => SetProperty(ref _actualLocation, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Size _actualSize;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the actual size of the <see cref="Led"/>.
|
||||||
|
/// This includes device-scaling.
|
||||||
|
/// </summary>
|
||||||
|
public Size ActualSize
|
||||||
|
{
|
||||||
|
get => _actualSize;
|
||||||
|
private set => SetProperty(ref _actualSize, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle _ledRectangle;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a rectangle representing the logical location of the <see cref="Led"/> relative to the <see cref="Device"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Rectangle LedRectangle
|
||||||
|
{
|
||||||
|
get => _ledRectangle;
|
||||||
|
private set => SetProperty(ref _ledRectangle, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle _absoluteLedRectangle;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a rectangle representing the logical location of the <see cref="Led"/> on the <see cref="RGBSurface"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Rectangle AbsoluteLedRectangle
|
||||||
|
{
|
||||||
|
get => _absoluteLedRectangle;
|
||||||
|
private set => SetProperty(ref _absoluteLedRectangle, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether the <see cref="Led" /> is about to change it's color.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsDirty => RequestedColor.HasValue && (RequestedColor != InternalColor);
|
||||||
|
|
||||||
|
private Color? _requestedColor;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a copy of the <see cref="Core.Color"/> the LED should be set to on the next update.
|
||||||
|
/// Null if there is no update-request for the next update.
|
||||||
|
/// </summary>
|
||||||
|
public Color? RequestedColor
|
||||||
|
{
|
||||||
|
get => _requestedColor;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
SetProperty(ref _requestedColor, value);
|
||||||
|
|
||||||
|
// ReSharper disable once ExplicitCallerInfoArgument
|
||||||
|
OnPropertyChanged(nameof(IsDirty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _color = Color.Transparent;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current <see cref="Core.Color"/> of the <see cref="Led"/>. Sets the <see cref="RequestedColor" /> for the next update.
|
||||||
|
/// </summary>
|
||||||
|
public Color Color
|
||||||
|
{
|
||||||
|
get => _color;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!IsLocked)
|
||||||
|
{
|
||||||
|
if (RequestedColor.HasValue)
|
||||||
|
RequestedColor += value;
|
||||||
|
else
|
||||||
|
RequestedColor = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or set the <see cref="Color"/> ignoring all workflows regarding locks and update-requests. />
|
||||||
|
/// </summary>
|
||||||
|
internal Color InternalColor
|
||||||
|
{
|
||||||
|
get => _color;
|
||||||
|
set => SetProperty(ref _color, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _isLocked;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets if the color of this LED can be changed.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsLocked
|
||||||
|
{
|
||||||
|
get => _isLocked;
|
||||||
|
set => SetProperty(ref _isLocked, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the URI of an image of the <see cref="Led"/> or null if there is no image.
|
||||||
|
/// </summary>
|
||||||
|
public Uri Image { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the provider-specific data associated with this led.
|
||||||
|
/// </summary>
|
||||||
|
public object CustomData { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Led"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">The <see cref="IRGBDevice"/> the <see cref="Led"/> is associated with.</param>
|
||||||
|
/// <param name="id">The <see cref="LedId"/> of the <see cref="Led"/>.</param>
|
||||||
|
/// <param name="location">The physical location of the <see cref="Led"/> relative to the <see cref="Device"/>.</param>
|
||||||
|
/// <param name="size">The size of the <see cref="Led"/>.</param>
|
||||||
|
/// <param name="customData">The provider-specific data associated with this led.</param>
|
||||||
|
internal Led(IRGBDevice device, LedId id, Point location, Size size, object customData = null)
|
||||||
|
{
|
||||||
|
this.Device = device;
|
||||||
|
this.Id = id;
|
||||||
|
this.Location = location;
|
||||||
|
this.Size = size;
|
||||||
|
this.CustomData = customData;
|
||||||
|
|
||||||
|
device.PropertyChanged += DevicePropertyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
private void DevicePropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if ((e.PropertyName == nameof(IRGBDevice.Location)))
|
||||||
|
UpdateAbsoluteData();
|
||||||
|
else if (e.PropertyName == nameof(IRGBDevice.DeviceRectangle))
|
||||||
|
{
|
||||||
|
UpdateActualData();
|
||||||
|
UpdateAbsoluteData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateActualData()
|
||||||
|
{
|
||||||
|
ActualSize = Size * Device.Scale;
|
||||||
|
|
||||||
|
Point actualLocation = (Location * Device.Scale);
|
||||||
|
Rectangle ledRectangle = new Rectangle(Location * Device.Scale, Size * Device.Scale);
|
||||||
|
|
||||||
|
if (Device.Rotation.IsRotated)
|
||||||
|
{
|
||||||
|
Point deviceCenter = new Rectangle(Device.ActualSize).Center;
|
||||||
|
Point actualDeviceCenter = new Rectangle(Device.DeviceRectangle.Size).Center;
|
||||||
|
Point centerOffset = new Point(actualDeviceCenter.X - deviceCenter.X, actualDeviceCenter.Y - deviceCenter.Y);
|
||||||
|
|
||||||
|
actualLocation = actualLocation.Rotate(Device.Rotation, new Rectangle(Device.ActualSize).Center) + centerOffset;
|
||||||
|
ledRectangle = new Rectangle(ledRectangle.Rotate(Device.Rotation, new Rectangle(Device.ActualSize).Center)).Translate(centerOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActualLocation = actualLocation;
|
||||||
|
LedRectangle = ledRectangle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAbsoluteData()
|
||||||
|
{
|
||||||
|
AbsoluteLedRectangle = LedRectangle.Translate(Device.Location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the <see cref="Id"/> and the <see cref="Color"/> of this <see cref="Led"/> to a human-readable string.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A string that contains the <see cref="Id"/> and the <see cref="Color"/> of this <see cref="Led"/>. For example "Enter [A: 255, R: 255, G: 0, B: 0]".</returns>
|
||||||
|
public override string ToString() => $"{Id} {Color}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the <see cref="Led"/> to the requested <see cref="Core.Color"/>.
|
||||||
|
/// </summary>
|
||||||
|
internal void Update()
|
||||||
|
{
|
||||||
|
if (!RequestedColor.HasValue) return;
|
||||||
|
|
||||||
|
_color = RequestedColor.Value;
|
||||||
|
RequestedColor = null;
|
||||||
|
|
||||||
// ReSharper disable once ExplicitCallerInfoArgument
|
// ReSharper disable once ExplicitCallerInfoArgument
|
||||||
OnPropertyChanged(nameof(IsDirty));
|
OnPropertyChanged(nameof(Color));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private Color _color = Color.Transparent;
|
/// <summary>
|
||||||
/// <summary>
|
/// Resets the <see cref="Led"/> back to default.
|
||||||
/// Gets the current <see cref="Core.Color"/> of the <see cref="Led"/>. Sets the <see cref="RequestedColor" /> for the next update.
|
/// </summary>
|
||||||
/// </summary>
|
internal void Reset()
|
||||||
public Color Color
|
|
||||||
{
|
|
||||||
get => _color;
|
|
||||||
set
|
|
||||||
{
|
{
|
||||||
if (RequestedColor.HasValue)
|
_color = Color.Transparent;
|
||||||
RequestedColor = RequestedColor.Value + value;
|
RequestedColor = null;
|
||||||
else
|
IsLocked = false;
|
||||||
RequestedColor = _color + value;
|
|
||||||
|
// ReSharper disable once ExplicitCallerInfoArgument
|
||||||
|
OnPropertyChanged(nameof(Color));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Operators
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="Led" /> to a <see cref="Core.Color" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="led">The <see cref="Led"/> to convert.</param>
|
||||||
|
public static implicit operator Color(Led led) => led?.Color ?? Color.Transparent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="Led" /> to a <see cref="Rectangle" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="led">The <see cref="Led"/> to convert.</param>
|
||||||
|
public static implicit operator Rectangle(Led led) => led?.LedRectangle ?? new Rectangle();
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Gets the provider-specific data associated with this led.
|
|
||||||
/// </summary>
|
|
||||||
public object? CustomData { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets some custom metadata of this led.
|
|
||||||
/// </summary>
|
|
||||||
public object? LayoutMetadata { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Led"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="device">The <see cref="IRGBDevice"/> the <see cref="Led"/> is associated with.</param>
|
|
||||||
/// <param name="id">The <see cref="LedId"/> of the <see cref="Led"/>.</param>
|
|
||||||
/// <param name="location">The physical location of the <see cref="Led"/> relative to the <see cref="Device"/>.</param>
|
|
||||||
/// <param name="size">The size of the <see cref="Led"/>.</param>
|
|
||||||
/// <param name="customData">The provider-specific data associated with this led.</param>
|
|
||||||
internal Led(IRGBDevice device, LedId id, Point location, Size size, object? customData = null)
|
|
||||||
: base(device)
|
|
||||||
{
|
|
||||||
this.Device = device;
|
|
||||||
this.Id = id;
|
|
||||||
this.Location = location;
|
|
||||||
this.Size = size;
|
|
||||||
this.CustomData = customData;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void UpdateActualPlaceableData()
|
|
||||||
{
|
|
||||||
base.UpdateActualPlaceableData();
|
|
||||||
|
|
||||||
AbsoluteBoundary = Boundary.Translate(Device.Location);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts the <see cref="Id"/> and the <see cref="Color"/> of this <see cref="Led"/> to a human-readable string.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A string that contains the <see cref="Id"/> and the <see cref="Color"/> of this <see cref="Led"/>. For example "Enter [A: 255, R: 255, G: 0, B: 0]".</returns>
|
|
||||||
public override string ToString() => $"{Id} {Color}";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the <see cref="Led"/> to the requested <see cref="Core.Color"/>.
|
|
||||||
/// </summary>
|
|
||||||
internal void Update()
|
|
||||||
{
|
|
||||||
if (!RequestedColor.HasValue) return;
|
|
||||||
|
|
||||||
_color = RequestedColor.Value;
|
|
||||||
RequestedColor = null;
|
|
||||||
|
|
||||||
// ReSharper disable once ExplicitCallerInfoArgument
|
|
||||||
OnPropertyChanged(nameof(Color));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Operators
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a <see cref="Led" /> to a <see cref="Core.Color" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="led">The <see cref="Led"/> to convert.</param>
|
|
||||||
public static implicit operator Color(Led led) => led.Color;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a <see cref="Led" /> to a <see cref="Rectangle" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="led">The <see cref="Led"/> to convert.</param>
|
|
||||||
public static implicit operator Rectangle(Led led) => led.Boundary;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,154 +0,0 @@
|
|||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a mapping from <see cref="LedId"/> to a custom identifier.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The identifier the <see cref="LedId"/> is mapped to.</typeparam>
|
|
||||||
public sealed class LedMapping<T> : IEnumerable<(LedId ledId, T mapping)>
|
|
||||||
where T : notnull
|
|
||||||
{
|
|
||||||
#region Constants
|
|
||||||
|
|
||||||
public static LedMapping<T> Empty { get; } = [];
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
private readonly Dictionary<LedId, T> _mapping = [];
|
|
||||||
private readonly Dictionary<T, LedId> _reverseMapping = [];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the number of entries in this mapping.
|
|
||||||
/// </summary>
|
|
||||||
public int Count => _mapping.Count;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a collection of all mapped ledids.
|
|
||||||
/// </summary>
|
|
||||||
public ICollection<LedId> LedIds => _mapping.Keys;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a collection of all mapped custom identifiers.
|
|
||||||
/// </summary>
|
|
||||||
public ICollection<T> Mappings => _reverseMapping.Keys;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Indexer
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the custom identifier mapped to the specified <see cref="LedId"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledId">The led id to get the mapped identifier.</param>
|
|
||||||
/// <returns>The mapped ifentifier.</returns>
|
|
||||||
public T this[LedId ledId]
|
|
||||||
{
|
|
||||||
get => _mapping[ledId];
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_mapping[ledId] = value;
|
|
||||||
_reverseMapping[value] = ledId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="LedId"/> mapped to the specified custom identifier.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mapping">The custom identifier to get the mapped led id.</param>
|
|
||||||
/// <returns>The led id.</returns>
|
|
||||||
public LedId this[T mapping]
|
|
||||||
{
|
|
||||||
get => _reverseMapping[mapping];
|
|
||||||
set => this[value] = mapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a new entry to the mapping.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledId">The <see cref="LedId"/> to map.</param>
|
|
||||||
/// <param name="mapping">The custom identifier to map.</param>
|
|
||||||
public void Add(LedId ledId, T mapping)
|
|
||||||
{
|
|
||||||
_mapping.Add(ledId, mapping);
|
|
||||||
_reverseMapping.Add(mapping, ledId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the specified <see cref="LedId"/> is mapped.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledId">The led id to check.</param>
|
|
||||||
/// <returns><c>true</c> if the led id is mapped; otherwise <c>false</c>.</returns>
|
|
||||||
public bool Contains(LedId ledId) => _mapping.ContainsKey(ledId);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the specified custom identifier is mapped.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mapping">The custom identifier to check.</param>
|
|
||||||
/// <returns><c>true</c> if the led id is mapped; otherwise <c>false</c>.</returns>
|
|
||||||
public bool Contains(T mapping) => _reverseMapping.ContainsKey(mapping);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the custom identifier mapped to the specified led id.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledId">The led id to get the custom identifier for.</param>
|
|
||||||
/// <param name="mapping">Contains the mapped custom identifier or null if there is no mapping for the specified led id.</param>
|
|
||||||
/// <returns><c>true</c> if there was a custom identifier for the specified led id; otherwise <c>false</c>.</returns>
|
|
||||||
public bool TryGetValue(LedId ledId, out T? mapping) => _mapping.TryGetValue(ledId, out mapping);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the led id mapped to the specified custom identifier.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mapping">The custom identifier to get the led id for.</param>
|
|
||||||
/// <param name="ledId">Contains the mapped led id or null if there is no mapping for the specified led id.</param>
|
|
||||||
/// <returns><c>true</c> if there was a led id for the specified custom identifier; otherwise <c>false</c>.</returns>
|
|
||||||
public bool TryGetValue(T mapping, out LedId ledId) => _reverseMapping.TryGetValue(mapping, out ledId);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the specified led id and the mapped custom identifier.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ledId">The led id to remove.</param>
|
|
||||||
/// <returns><c>true</c> if there was a mapping for the led id to remove; otherwise <c>false</c>.</returns>
|
|
||||||
public bool Remove(LedId ledId)
|
|
||||||
{
|
|
||||||
if (_mapping.TryGetValue(ledId, out T? mapping))
|
|
||||||
_reverseMapping.Remove(mapping);
|
|
||||||
return _mapping.Remove(ledId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the specified custom identifier and the mapped led id.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mapping">The custom identifier to remove.</param>
|
|
||||||
/// <returns><c>true</c> if there was a mapping for the custom identifier to remove; otherwise <c>false</c>.</returns>
|
|
||||||
public bool Remove(T mapping)
|
|
||||||
{
|
|
||||||
if (_reverseMapping.TryGetValue(mapping, out LedId ledId))
|
|
||||||
_mapping.Remove(ledId);
|
|
||||||
return _reverseMapping.Remove(mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes all registered mappings.
|
|
||||||
/// </summary>
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_mapping.Clear();
|
|
||||||
_reverseMapping.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerator<(LedId ledId, T mapping)> GetEnumerator() => _mapping.Select(x => (x.Key, x.Value)).GetEnumerator();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user