mirror of
https://github.com/DarthAffe/RGB.NET.git
synced 2025-12-12 17:48:31 +00:00
Compare commits
282 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b0acc61618 | |||
| 13f3dde185 | |||
| 845efb6929 | |||
|
|
02d695c4dd | ||
|
|
35a4033521 | ||
|
|
dc6715b236 | ||
|
|
34b04523de | ||
|
|
a96b994e61 | ||
|
|
f26b3c193a | ||
| c0828c1d01 | |||
| 7c65b1d0bf | |||
| 826a5104de | |||
|
|
80b2365c31 | ||
| 8756ec98f3 | |||
| d5ce5fcee7 | |||
|
|
6a47887c18 | ||
| eb4ea71d01 | |||
|
|
b0f05ab399 | ||
| e1475859c6 | |||
|
|
9499b31c13 | ||
| 7fabc71b28 | |||
|
|
01bad00d8a | ||
|
|
1deb1b9f2f | ||
|
|
66843a21e5 | ||
| 4e575e8d3d | |||
| f8e4cc6b49 | |||
| aae509b275 | |||
| 5633f82b3b | |||
| 47770c00b8 | |||
| 654a7624cd | |||
| f9fefe4667 | |||
| f40190da01 | |||
| f34033a3fe | |||
| e151b3f194 | |||
| 899fc697e4 | |||
| d97293ec87 | |||
| 12a353574a | |||
|
|
77f55d2eb3 | ||
| 9945a5f7cb | |||
| ed98714439 | |||
| 39da0fd59c | |||
| 1d47894dac | |||
| 197be1f986 | |||
|
|
a2a25bc40a | ||
| 505e5c6d80 | |||
| f8a530e313 | |||
|
|
aa7bfd3976 | ||
| 71f1115c31 | |||
|
|
da51871e04 | ||
| a26eaf9a9a | |||
| 54c09a1d6f | |||
| a0198e3991 | |||
| f2491038a3 | |||
| 5c864a03e5 | |||
|
|
7cfe08921e | ||
|
|
c34435b958 | ||
| 2bf081d16e | |||
| 466d136089 | |||
| 13a5a6162d | |||
|
|
54b4eac1f3 | ||
| 9346948bfb | |||
| 9a997694a5 | |||
| 1396e978db | |||
| 681adcb1cb | |||
| cfbbdc6069 | |||
| 0d41314f7e | |||
| b1cf26b1e6 | |||
| 4c3875e561 | |||
| 3e53b51bac | |||
| fdfd35eff8 | |||
| c39849949a | |||
|
|
d207fdf495 | ||
| 4e80764015 | |||
| 9de1233c93 | |||
|
|
976ee6d007 | ||
|
|
9f0c3be7bb | ||
|
|
5e895f5806 | ||
| 41a1d5d97b | |||
| 6f0711564c | |||
| f21acbd767 | |||
| da2c2a678b | |||
| 5a13fcef7f | |||
| bc7c2374f9 | |||
| ed7ff76210 | |||
| f4cf5c3286 | |||
| 83d1b2472b | |||
| 1b9531a86f | |||
| 5f71ffdf1f | |||
| 835987155c | |||
| 31db13cb3d | |||
| 51373e4441 | |||
| 8f7e24ba33 | |||
| c0adbad599 | |||
| 4773e0df74 | |||
| 29e68ae8fe | |||
| 5aac20e982 | |||
| d1e71ef827 | |||
| 08d526a7a4 | |||
| acd4462b2a | |||
| e58d26d58d | |||
| 417b9be3f9 | |||
| ced13e9ec2 | |||
| 4f0f25e34e | |||
| 58ed8bb2f1 | |||
|
|
d82eebd769 | ||
|
|
3ca782a6a7 | ||
| a4bd797912 | |||
|
|
b56a50ab08 | ||
| 50e20a7bdd | |||
|
|
4959c6e8ad | ||
| ef980f754c | |||
| 1df23a6b36 | |||
| 16b2877dce | |||
| 657bca29b0 | |||
| 6ba7e44e3c | |||
| 9004c50d78 | |||
| b2848cfbaa | |||
| 23bd1119f2 | |||
| 67672be54c | |||
| 3400edcf93 | |||
|
|
1fe8cab0a4 | ||
| 95f162de2d | |||
| f07d228408 | |||
| 1312566eb0 | |||
| 9aee9a1640 | |||
| c89bbfea96 | |||
| af43c0ae87 | |||
| 7898c50eed | |||
| 505e7481f7 | |||
| 4f478879c2 | |||
|
|
8b1c5927d3 | ||
| 5a104eaf24 | |||
| 79f71bab29 | |||
| aeab93001f | |||
| 2796acd775 | |||
| cc2c7bc973 | |||
| d85f1559b3 | |||
| 0444730aca | |||
| 8aaf602cdd | |||
|
|
1bd5b54892 | ||
|
|
c11965eb3a | ||
| 9575690efb | |||
| a0c90029eb | |||
| 5592fd9923 | |||
|
|
08fbb0e526 | ||
| 99225f04fc | |||
| fda89e74c2 | |||
| be252790d4 | |||
| 188de3c558 | |||
| 883d6cbea4 | |||
|
|
fcf86ff9da | ||
|
|
7ad1e595a9 | ||
|
|
69d320fca3 | ||
|
|
736d58c7a3 | ||
| d454f94b73 | |||
| 012fdf62a4 | |||
| c1a4fee189 | |||
| 2e0754f474 | |||
| 5707a247ee | |||
| 72da2b6bdf | |||
| 60892e4e81 | |||
|
|
c7abac5ecd | ||
| 745364495d | |||
| 9d1188ab33 | |||
| 3461674e17 | |||
| 5d3a3613e2 | |||
| aba0888bd9 | |||
| 3d9706ad0e | |||
| 1f0b1b0774 | |||
| d070f0bbcb | |||
| 2c8bc72dc9 | |||
| 4209905474 | |||
|
|
cadf96634e | ||
| 7415c6b4ef | |||
| b4bbc6a343 | |||
| 2a2053cc53 | |||
|
|
5483a7581d | ||
| fd6bfa05e3 | |||
| d85d289909 | |||
| 89ab79aecd | |||
| 8faedd1e26 | |||
| 6f91af9039 | |||
|
|
803acf2f99 | ||
|
|
ba99ecfbdc | ||
| 0609e49571 | |||
| fdc69fdac5 | |||
|
|
5cb5962c1e | ||
| 56d77dee35 | |||
| 88a0f0fa11 | |||
|
|
2b203b2308 | ||
| 4fb1dca55d | |||
|
|
bf711325cf | ||
| 83bdfea2f3 | |||
| d7fffb4213 | |||
|
|
ca3c9fc5d3 | ||
| a0bdd837e2 | |||
|
|
e547bae209 | ||
| e96e1d636f | |||
| 5dbcd9c81e | |||
| 79252d5b31 | |||
| 27018b34e3 | |||
| 0aca2d84b1 | |||
| 020f249f9a | |||
| 1532e31a33 | |||
| b90c47076a | |||
|
|
d53801117b | ||
| a196d2a0a4 | |||
| 73b7f1f24f | |||
| 124f76b382 | |||
| 4684e29610 | |||
| 67f3625993 | |||
| 7e72d3199b | |||
| acddfed2b1 | |||
|
|
184a5823e8 | ||
|
|
e9cd657eac | ||
|
|
0c8f48ea44 | ||
| 93cd8055a2 | |||
| 4a0ae1a185 | |||
| a2194849b6 | |||
| 346d502e0f | |||
| 9f8e64fbcb | |||
| 54f39f8023 | |||
| 928d5c2ef9 | |||
| 586734b44a | |||
| af3989aa73 | |||
| f5f81e74d7 | |||
| e8f168f64a | |||
| 25fef22218 | |||
| 2020992249 | |||
| d9c244a044 | |||
| ad75707645 | |||
| 260a820b80 | |||
| 4ee55c6725 | |||
| 70ccc4d575 | |||
| 0cf4f39ccf | |||
| 764fcd1b1d | |||
| 4216dacf4f | |||
| f6433af4b5 | |||
| 82050b8d5a | |||
| 02235a3f7f | |||
| aaabbc6a8d | |||
| 6bed6906d4 | |||
| 10183fb270 | |||
| b7df7e4d02 | |||
| 818678fdf2 | |||
| 5b514ff962 | |||
| d054d16c10 | |||
| 39cfcdb367 | |||
| 12d6b90c74 | |||
| f089c61e9d | |||
| 5eb39b1a07 | |||
|
|
1793d26166 | ||
|
|
b6342ea575 | ||
| 4675349621 | |||
| 4a9bbb64dc | |||
| 30ccfdcd85 | |||
| 1b4b92b44c | |||
| 37e4954583 | |||
| 6e313ea6a1 | |||
| bb3b74b919 | |||
| cc652a08a6 | |||
| d66e4d87d9 | |||
| 631c8d2047 | |||
| db2f16d371 | |||
|
|
b67294eb3c | ||
|
|
914bd8c0a1 | ||
|
|
df2f5620ee | ||
|
|
3dc4f45f66 | ||
|
|
38840ef6f4 | ||
| df73551497 | |||
| 8431a8cb5e | |||
| 3ff357212b | |||
| 3ffa834568 | |||
| 2ff7a65519 | |||
| d6aed5c5a2 | |||
| 180b0e4538 | |||
|
|
43ecc7374e | ||
|
|
3aba170d78 | ||
| 287e3937cf | |||
| b779b58a9f | |||
|
|
7c165f51af | ||
| d60d4833ca |
59
.github/workflows/ci.yml
vendored
59
.github/workflows/ci.yml
vendored
@ -1,61 +1,56 @@
|
||||
name: RGB.NET-CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ Development ]
|
||||
paths:
|
||||
- '**.cs'
|
||||
- '**.csproj'
|
||||
- '**.yml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'version'
|
||||
required: true
|
||||
type: string
|
||||
increment:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4.1.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v1
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Git Semantic Version
|
||||
id: versioning
|
||||
uses: PaulHatch/semantic-version@v4.0.3
|
||||
with:
|
||||
short_tags: false
|
||||
format: "${major}.${minor}.${patch}-prerelease.${increment}"
|
||||
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=${{ steps.versioning.outputs.version }}
|
||||
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 NET5
|
||||
uses: actions/upload-artifact@v2.2.4
|
||||
- name: Upload a Build Artifact NET9
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
with:
|
||||
name: RGB.NET-NET5
|
||||
path: bin/net5.0/RGB.NET.*.dll
|
||||
name: RGB.NET-NET9
|
||||
path: bin/net9.0/RGB.NET.*.dll
|
||||
if-no-files-found: error
|
||||
- name: Upload a Build Artifact NET6
|
||||
uses: actions/upload-artifact@v2.2.4
|
||||
- name: Upload a Build Artifact NET8
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
with:
|
||||
name: RGB.NET-NET6
|
||||
path: bin/net6.0/RGB.NET.*.dll
|
||||
if-no-files-found: error
|
||||
- name: Upload a Build Artifact NET7
|
||||
uses: actions/upload-artifact@v2.2.4
|
||||
with:
|
||||
name: RGB.NET-NET7
|
||||
path: bin/net7.0/RGB.NET.*.dll
|
||||
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@v2.2.4
|
||||
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
|
||||
|
||||
10
.github/workflows/pr_verify.yml
vendored
10
.github/workflows/pr_verify.yml
vendored
@ -7,14 +7,16 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4.1.1
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v1
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
dotnet-version: |
|
||||
9.0.x
|
||||
8.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
|
||||
58
.github/workflows/release.yml
vendored
58
.github/workflows/release.yml
vendored
@ -1,57 +1,47 @@
|
||||
name: RGB.NET-Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- '**.cs'
|
||||
- '**.csproj'
|
||||
- '**.yml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'version'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-2022
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4.1.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v1
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Git Semantic Version
|
||||
id: versioning
|
||||
uses: PaulHatch/semantic-version@v4.0.3
|
||||
with:
|
||||
short_tags: false
|
||||
format: "${major}.${minor}.${patch}"
|
||||
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=${{ steps.versioning.outputs.version }}
|
||||
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 NET5
|
||||
uses: actions/upload-artifact@v2.2.4
|
||||
- name: Upload a Build Artifact NET9
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
with:
|
||||
name: RGB.NET-NET5
|
||||
path: bin/net5.0/RGB.NET.*.dll
|
||||
name: RGB.NET-NET9
|
||||
path: bin/net9.0/RGB.NET.*.dll
|
||||
if-no-files-found: error
|
||||
- name: Upload a Build Artifact NET6
|
||||
uses: actions/upload-artifact@v2.2.4
|
||||
- name: Upload a Build Artifact NET8
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
with:
|
||||
name: RGB.NET-NET6
|
||||
path: bin/net6.0/RGB.NET.*.dll
|
||||
if-no-files-found: error
|
||||
- name: Upload a Build Artifact NET7
|
||||
uses: actions/upload-artifact@v2.2.4
|
||||
with:
|
||||
name: RGB.NET-NET7
|
||||
path: bin/net7.0/RGB.NET.*.dll
|
||||
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@v2.2.4
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
with:
|
||||
name: RGB.NET-Nugets
|
||||
path: bin/*nupkg
|
||||
@ -59,8 +49,8 @@ jobs:
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ steps.versioning.outputs.version_tag }}
|
||||
tag_name: v${{ github.event.inputs.version }}
|
||||
generate_release_notes: true
|
||||
files: bin/net7.0/RGB.NET.*.dll
|
||||
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
|
||||
|
||||
@ -6,7 +6,7 @@ namespace RGB.NET.Core;
|
||||
/// <summary>
|
||||
/// Represents the default-behavior for the work with colors.
|
||||
/// </summary>
|
||||
public class DefaultColorBehavior : IColorBehavior
|
||||
public sealed class DefaultColorBehavior : IColorBehavior
|
||||
{
|
||||
#region Methods
|
||||
|
||||
@ -14,7 +14,7 @@ public class DefaultColorBehavior : IColorBehavior
|
||||
/// 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(in Color color) => $"[A: {color.GetA()}, R: {color.GetR()}, G: {color.GetG()}, B: {color.GetB()}]";
|
||||
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" />.
|
||||
@ -22,28 +22,31 @@ public class DefaultColorBehavior : IColorBehavior
|
||||
/// <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 virtual bool Equals(in Color color, object? obj)
|
||||
{
|
||||
if (obj is not Color color2) return false;
|
||||
|
||||
return color.A.EqualsInTolerance(color2.A)
|
||||
&& color.R.EqualsInTolerance(color2.R)
|
||||
&& color.G.EqualsInTolerance(color2.G)
|
||||
&& color.B.EqualsInTolerance(color2.B);
|
||||
}
|
||||
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 virtual int GetHashCode(in Color color) => HashCode.Combine(color.A, color.R, color.G, color.B);
|
||||
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 virtual Color Blend(in Color baseColor, in Color blendColor)
|
||||
public Color Blend(Color baseColor, Color blendColor)
|
||||
{
|
||||
if (blendColor.A.EqualsInTolerance(0)) return baseColor;
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ public interface IColorBehavior
|
||||
/// </summary>
|
||||
/// <param name="color">The color to convert.</param>
|
||||
/// <returns>The string representation of the specified color.</returns>
|
||||
string ToString(in Color color);
|
||||
string ToString(Color color);
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the specified object is a <see cref="Color" /> and is equivalent to this <see cref="Color" />.
|
||||
@ -18,18 +18,26 @@ public interface IColorBehavior
|
||||
/// <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(in Color color, object? obj);
|
||||
bool Equals(Color color, object? obj);
|
||||
|
||||
/// <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>
|
||||
bool Equals(Color color, Color color2);
|
||||
|
||||
/// <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>
|
||||
int GetHashCode(in Color color);
|
||||
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(in Color baseColor, in Color blendColor);
|
||||
Color Blend(Color baseColor, Color blendColor);
|
||||
}
|
||||
@ -11,7 +11,7 @@ namespace RGB.NET.Core;
|
||||
/// Represents an ARGB (alpha, red, green, blue) color.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||
public readonly struct Color
|
||||
public readonly struct Color : IEquatable<Color>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
@ -175,7 +175,7 @@ public readonly struct Color
|
||||
/// 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(in Color color)
|
||||
public Color(Color color)
|
||||
: this(color.A, color.R, color.G, color.B)
|
||||
{ }
|
||||
|
||||
@ -196,6 +196,13 @@ public readonly struct Color
|
||||
/// <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>
|
||||
@ -207,7 +214,7 @@ public readonly struct Color
|
||||
/// 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(in Color color) => Behavior.Blend(this, color);
|
||||
public Color Blend(Color color) => Behavior.Blend(this, color);
|
||||
|
||||
#endregion
|
||||
|
||||
@ -219,7 +226,7 @@ public readonly struct Color
|
||||
/// <param name="color1">The base color.</param>
|
||||
/// <param name="color2">The color to blend.</param>
|
||||
/// <returns>The blended color.</returns>
|
||||
public static Color operator +(in Color color1, in Color color2) => color1.Blend(color2);
|
||||
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.
|
||||
@ -227,7 +234,7 @@ public readonly struct Color
|
||||
/// <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 ==(in Color color1, in Color color2) => color1.Equals(color2);
|
||||
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.
|
||||
@ -235,7 +242,7 @@ public readonly struct Color
|
||||
/// <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 !=(in Color color1, in Color color2) => !(color1 == color2);
|
||||
public static bool operator !=(Color color1, Color color2) => !(color1 == color2);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="ValueTuple"/> of ARGB-components to a <see cref="Color"/>.
|
||||
|
||||
@ -16,21 +16,21 @@ public static class HSVColor
|
||||
/// </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 in Color color) => color.GetHSV().hue;
|
||||
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 in Color color) => color.GetHSV().saturation;
|
||||
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 in Color color) => color.GetHSV().value;
|
||||
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"/>.
|
||||
@ -40,7 +40,7 @@ public static class HSVColor
|
||||
/// </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 in Color color)
|
||||
public static (float hue, float saturation, float value) GetHSV(this Color color)
|
||||
=> CaclulateHSVFromRGB(color.R, color.G, color.B);
|
||||
|
||||
#endregion
|
||||
@ -55,7 +55,7 @@ public static class HSVColor
|
||||
/// <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 in Color color, float hue = 0, float saturation = 0, float value = 0)
|
||||
public static Color AddHSV(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);
|
||||
@ -69,7 +69,7 @@ public static class HSVColor
|
||||
/// <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 in Color color, float hue = 0, float saturation = 0, float value = 0)
|
||||
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);
|
||||
@ -83,7 +83,7 @@ public static class HSVColor
|
||||
/// <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 in Color color, float hue = 1, float saturation = 1, float value = 1)
|
||||
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);
|
||||
@ -97,7 +97,7 @@ public static class HSVColor
|
||||
/// <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 in Color color, float hue = 1, float saturation = 1, float value = 1)
|
||||
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);
|
||||
@ -111,7 +111,7 @@ public static class HSVColor
|
||||
/// <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 in Color color, float? hue = null, float? saturation = null, float? value = null)
|
||||
public static Color SetHSV(this Color color, float? hue = null, float? saturation = null, float? value = null)
|
||||
{
|
||||
(float cHue, float cSaturation, float cValue) = color.GetHSV();
|
||||
return Create(color.A, hue ?? cHue, saturation ?? cSaturation, value ?? cValue);
|
||||
|
||||
@ -16,21 +16,21 @@ public static class HclColor
|
||||
/// </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 in Color color) => color.GetHcl().h;
|
||||
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 in Color color) => color.GetHcl().c;
|
||||
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 in Color color) => color.GetHcl().l;
|
||||
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"/>.
|
||||
@ -40,7 +40,7 @@ public static class HclColor
|
||||
/// </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 in Color color)
|
||||
public static (float h, float c, float l) GetHcl(this Color color)
|
||||
=> CalculateHclFromRGB(color.R, color.G, color.B);
|
||||
|
||||
#endregion
|
||||
@ -55,7 +55,7 @@ public static class HclColor
|
||||
/// <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 in Color color, float h = 0, float c = 0, float l = 0)
|
||||
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);
|
||||
@ -69,7 +69,7 @@ public static class HclColor
|
||||
/// <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 in Color color, float h = 0, float c = 0, float l = 0)
|
||||
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);
|
||||
@ -83,7 +83,7 @@ public static class HclColor
|
||||
/// <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 in Color color, float h = 1, float c = 1, float l = 1)
|
||||
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);
|
||||
@ -97,7 +97,7 @@ public static class HclColor
|
||||
/// <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 in Color color, float h = 1, float c = 1, float l = 1)
|
||||
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);
|
||||
@ -111,7 +111,7 @@ public static class HclColor
|
||||
/// <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 in Color color, float? h = null, float? c = null, float? l = null)
|
||||
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);
|
||||
|
||||
@ -16,21 +16,21 @@ public static class LabColor
|
||||
/// </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 in Color color) => color.GetLab().l;
|
||||
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 in Color color) => color.GetLab().a;
|
||||
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 in Color color) => color.GetLab().b;
|
||||
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"/>.
|
||||
@ -40,7 +40,7 @@ public static class LabColor
|
||||
/// </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 in Color color)
|
||||
public static (float l, float a, float b) GetLab(this Color color)
|
||||
=> CalculateLabFromRGB(color.R, color.G, color.B);
|
||||
|
||||
#endregion
|
||||
@ -55,7 +55,7 @@ public static class LabColor
|
||||
/// <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 in Color color, float l = 0, float a = 0, float b = 0)
|
||||
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);
|
||||
@ -69,7 +69,7 @@ public static class LabColor
|
||||
/// <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 in Color color, float l = 0, float a = 0, float b = 0)
|
||||
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);
|
||||
@ -83,7 +83,7 @@ public static class LabColor
|
||||
/// <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 in Color color, float l = 1, float a = 1, float b = 1)
|
||||
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);
|
||||
@ -97,7 +97,7 @@ public static class LabColor
|
||||
/// <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 in Color color, float l = 1, float a = 1, float b = 1)
|
||||
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);
|
||||
@ -111,7 +111,7 @@ public static class LabColor
|
||||
/// <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 in Color color, float? l = null, float? a = null, float? b = null)
|
||||
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);
|
||||
|
||||
@ -16,35 +16,35 @@ public static class RGBColor
|
||||
/// </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 in Color color) => color.A.GetByteValueFromPercentage();
|
||||
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 in Color color) => color.R.GetByteValueFromPercentage();
|
||||
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 in Color color) => color.G.GetByteValueFromPercentage();
|
||||
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 in Color color) => color.B.GetByteValueFromPercentage();
|
||||
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 in Color color)
|
||||
public static (byte a, byte r, byte g, byte b) GetRGBBytes(this Color color)
|
||||
=> (color.GetA(), color.GetR(), color.GetG(), color.GetB());
|
||||
|
||||
/// <summary>
|
||||
@ -52,7 +52,7 @@ public static class RGBColor
|
||||
/// </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 in Color color)
|
||||
public static (float a, float r, float g, float b) GetRGB(this Color color)
|
||||
=> (color.A, color.R, color.G, color.B);
|
||||
|
||||
#endregion
|
||||
@ -69,7 +69,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, int r = 0, int g = 0, int b = 0)
|
||||
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>
|
||||
@ -80,7 +80,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, float r = 0, float g = 0, float b = 0)
|
||||
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>
|
||||
@ -89,7 +89,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, int a)
|
||||
public static Color AddA(this Color color, int a)
|
||||
=> new(color.GetA() + a, color.R, color.G, color.B);
|
||||
|
||||
/// <summary>
|
||||
@ -98,7 +98,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, float a)
|
||||
public static Color AddA(this Color color, float a)
|
||||
=> new(color.A + a, color.R, color.G, color.B);
|
||||
|
||||
#endregion
|
||||
@ -113,7 +113,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, int r = 0, int g = 0, int b = 0)
|
||||
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>
|
||||
@ -124,7 +124,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, float r = 0, float g = 0, float b = 0)
|
||||
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>
|
||||
@ -133,7 +133,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, int a)
|
||||
public static Color SubtractA(this Color color, int a)
|
||||
=> new(color.GetA() - a, color.R, color.G, color.B);
|
||||
|
||||
/// <summary>
|
||||
@ -142,7 +142,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, float aPercent)
|
||||
public static Color SubtractA(this Color color, float aPercent)
|
||||
=> new(color.A - aPercent, color.R, color.G, color.B);
|
||||
|
||||
#endregion
|
||||
@ -157,7 +157,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, float r = 1, float g = 1, float b = 1)
|
||||
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>
|
||||
@ -166,7 +166,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, float a)
|
||||
public static Color MultiplyA(this Color color, float a)
|
||||
=> new(color.A * a, color.R, color.G, color.B);
|
||||
|
||||
#endregion
|
||||
@ -181,7 +181,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, float r = 1, float g = 1, float b = 1)
|
||||
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>
|
||||
@ -190,7 +190,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, float a)
|
||||
public static Color DivideA(this Color color, float a)
|
||||
=> new(color.A / a, color.R, color.G, color.B);
|
||||
|
||||
#endregion
|
||||
@ -205,7 +205,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, byte? r = null, byte? g = null, byte? b = null)
|
||||
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>
|
||||
@ -216,7 +216,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, int? r = null, int? g = null, int? b = null)
|
||||
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>
|
||||
@ -227,7 +227,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, float? r = null, float? g = null, float? b = null)
|
||||
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>
|
||||
@ -236,7 +236,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, int a) => new(a, color.R, color.G, color.B);
|
||||
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.
|
||||
@ -244,7 +244,7 @@ public static class RGBColor
|
||||
/// <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 in Color color, float a) => new(a, color.R, color.G, color.B);
|
||||
public static Color SetA(this Color color, float a) => new(a, color.R, color.G, color.B);
|
||||
|
||||
#endregion
|
||||
|
||||
@ -256,13 +256,13 @@ public static class RGBColor
|
||||
/// Gets the current color as a RGB-HEX-string.
|
||||
/// </summary>
|
||||
/// <returns>The RGB-HEX-string.</returns>
|
||||
public static string AsRGBHexString(this in Color color, bool leadingHash = true) => (leadingHash ? "#" : "") + ConversionHelper.ToHex(color.GetR(), color.GetG(), color.GetB());
|
||||
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 in Color color, bool leadingHash = true) => (leadingHash ? "#" : "") + ConversionHelper.ToHex(color.GetA(), color.GetR(), color.GetG(), color.GetB());
|
||||
public static string AsARGBHexString(this Color color, bool leadingHash = true) => (leadingHash ? "#" : "") + ConversionHelper.ToHex(color.GetA(), color.GetR(), color.GetG(), color.GetB());
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@ -16,21 +16,21 @@ public static class XYZColor
|
||||
/// </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 in Color color) => color.GetXYZ().x;
|
||||
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 in Color color) => color.GetXYZ().y;
|
||||
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 in Color color) => color.GetXYZ().z;
|
||||
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"/>.
|
||||
@ -40,7 +40,7 @@ public static class XYZColor
|
||||
/// </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 in Color color)
|
||||
public static (float x, float y, float z) GetXYZ(this Color color)
|
||||
=> CaclulateXYZFromRGB(color.R, color.G, color.B);
|
||||
|
||||
#endregion
|
||||
@ -55,7 +55,7 @@ public static class XYZColor
|
||||
/// <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 in Color color, float x = 0, float y = 0, float z = 0)
|
||||
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);
|
||||
@ -69,7 +69,7 @@ public static class XYZColor
|
||||
/// <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 in Color color, float x = 0, float y = 0, float z = 0)
|
||||
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);
|
||||
@ -83,7 +83,7 @@ public static class XYZColor
|
||||
/// <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 in Color color, float x = 1, float y = 1, float z = 1)
|
||||
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);
|
||||
@ -97,7 +97,7 @@ public static class XYZColor
|
||||
/// <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 in Color color, float x = 1, float y = 1, float z = 1)
|
||||
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);
|
||||
@ -111,7 +111,7 @@ public static class XYZColor
|
||||
/// <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 in Color color, float? x = null, float? y = null, float? z = null)
|
||||
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);
|
||||
|
||||
8
RGB.NET.Core/Compatibility/Lock.cs
Normal file
8
RGB.NET.Core/Compatibility/Lock.cs
Normal file
@ -0,0 +1,8 @@
|
||||
#if NET8_0
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace RGB.NET.Core.Compatibility.Net8;
|
||||
|
||||
public sealed class Lock;
|
||||
|
||||
#endif
|
||||
@ -11,7 +11,7 @@ public abstract class AbstractDecoratable<T> : AbstractBindable, IDecoratable<T>
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly List<T> _decorators = new();
|
||||
private readonly List<T> _decorators = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<T> Decorators { get; }
|
||||
|
||||
@ -29,7 +29,7 @@ public abstract class AbstractDecorator : AbstractBindable, IDecorator
|
||||
/// <summary>
|
||||
/// Gets a readonly-list of all <see cref="IDecoratable"/> this decorator is attached to.
|
||||
/// </summary>
|
||||
protected List<IDecoratable> DecoratedObjects { get; } = new();
|
||||
protected List<IDecoratable> DecoratedObjects { get; } = [];
|
||||
|
||||
#endregion
|
||||
|
||||
@ -46,14 +46,14 @@ public abstract class AbstractDecorator : AbstractBindable, IDecorator
|
||||
/// </summary>
|
||||
protected virtual void Detach()
|
||||
{
|
||||
List<IDecoratable> decoratables = new(DecoratedObjects);
|
||||
List<IDecoratable> decoratables = [..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 });
|
||||
decoratableType.GetMethod(nameof(IDecoratable<IDecorator>.RemoveDecorator))?.Invoke(decoratable, [this]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,5 +12,5 @@ public interface IBrushDecorator : IDecorator
|
||||
/// <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>
|
||||
void ManipulateColor(in Rectangle rectangle, in RenderTarget renderTarget, ref Color color);
|
||||
void ManipulateColor(Rectangle rectangle, RenderTarget renderTarget, ref Color color);
|
||||
}
|
||||
@ -6,8 +6,7 @@ namespace RGB.NET.Core;
|
||||
/// <summary>
|
||||
/// Represents a basic decoratable.
|
||||
/// </summary>
|
||||
public interface IDecoratable : INotifyPropertyChanged
|
||||
{ }
|
||||
public interface IDecoratable : INotifyPropertyChanged;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
|
||||
@ -4,5 +4,4 @@
|
||||
/// <summary>
|
||||
/// Represents a basic decorator decorating a <see cref="T:RGB.NET.Core.ILedGroup" />.
|
||||
/// </summary>
|
||||
public interface ILedGroupDecorator : IDecorator
|
||||
{ }
|
||||
public interface ILedGroupDecorator : IDecorator;
|
||||
@ -2,9 +2,12 @@
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
@ -40,7 +43,7 @@ public abstract class AbstractRGBDevice<TDeviceInfo> : Placeable, IRGBDevice<TDe
|
||||
IRGBDeviceInfo IRGBDevice.DeviceInfo => DeviceInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IList<IColorCorrection> ColorCorrections { get; } = new List<IColorCorrection>();
|
||||
public IList<IColorCorrection> ColorCorrections { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the device needs to be flushed on every update.
|
||||
@ -50,7 +53,7 @@ public abstract class AbstractRGBDevice<TDeviceInfo> : Placeable, IRGBDevice<TDe
|
||||
/// <summary>
|
||||
/// Gets a dictionary containing all <see cref="Led"/> of the <see cref="IRGBDevice"/>.
|
||||
/// </summary>
|
||||
protected Dictionary<LedId, Led> LedMapping { get; } = new();
|
||||
protected Dictionary<LedId, Led> LedMapping { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the update queue used to update this device.
|
||||
@ -60,7 +63,7 @@ public abstract class AbstractRGBDevice<TDeviceInfo> : Placeable, IRGBDevice<TDe
|
||||
#region Indexer
|
||||
|
||||
/// <inheritdoc />
|
||||
Led? IRGBDevice.this[LedId ledId] => LedMapping.TryGetValue(ledId, out Led? led) ? led : null;
|
||||
Led? IRGBDevice.this[LedId ledId] => LedMapping.GetValueOrDefault(ledId);
|
||||
|
||||
/// <inheritdoc />
|
||||
Led? IRGBDevice.this[Point location] => LedMapping.Values.FirstOrDefault(x => x.Boundary.Contains(location));
|
||||
@ -84,6 +87,8 @@ public abstract class AbstractRGBDevice<TDeviceInfo> : Placeable, IRGBDevice<TDe
|
||||
{
|
||||
this.DeviceInfo = deviceInfo;
|
||||
this.UpdateQueue = updateQueue;
|
||||
|
||||
UpdateQueue.AddReferencingObject(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -97,12 +102,7 @@ public abstract class AbstractRGBDevice<TDeviceInfo> : Placeable, IRGBDevice<TDe
|
||||
DeviceUpdate();
|
||||
|
||||
// Send LEDs to SDK
|
||||
List<Led> ledsToUpdate = GetLedsToUpdate(flushLeds).ToList();
|
||||
|
||||
foreach (Led led in ledsToUpdate)
|
||||
led.Update();
|
||||
|
||||
UpdateLeds(ledsToUpdate);
|
||||
UpdateLeds(GetLedsToUpdate(flushLeds));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -110,7 +110,7 @@ public abstract class AbstractRGBDevice<TDeviceInfo> : Placeable, IRGBDevice<TDe
|
||||
/// </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) ? LedMapping.Values : LedMapping.Values.Where(x => x.IsDirty)).Where(led => led.RequestedColor?.A > 0);
|
||||
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.
|
||||
@ -119,47 +119,57 @@ public abstract class AbstractRGBDevice<TDeviceInfo> : Placeable, IRGBDevice<TDe
|
||||
/// Applies all <see cref="ColorCorrections"/>.
|
||||
/// if no <see cref="Led.CustomData"/> ist specified the <see cref="Led.Id"/> is used.
|
||||
/// </remarks>
|
||||
/// <param name="leds">The enumerable of leds to convert.</param>
|
||||
/// <param name="led">The of led to convert.</param>
|
||||
/// <returns>The enumerable of custom data and color tuples for the specified leds.</returns>
|
||||
protected virtual IEnumerable<(object key, Color color)> GetUpdateData(IEnumerable<Led> leds)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected (object key, Color color) GetUpdateData(Led led)
|
||||
{
|
||||
if (ColorCorrections.Count > 0)
|
||||
{
|
||||
foreach (Led led in leds)
|
||||
{
|
||||
Color color = led.Color;
|
||||
object key = led.CustomData ?? led.Id;
|
||||
Color color = led.Color;
|
||||
object key = led.CustomData ?? led.Id;
|
||||
|
||||
foreach (IColorCorrection colorCorrection in ColorCorrections)
|
||||
colorCorrection.ApplyTo(ref color);
|
||||
// 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);
|
||||
|
||||
yield return (key, color);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Led led in leds)
|
||||
{
|
||||
Color color = led.Color;
|
||||
object key = led.CustomData ?? led.Id;
|
||||
|
||||
yield return (key, color);
|
||||
}
|
||||
}
|
||||
return (key, color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends all the updated <see cref="Led"/> to the device.
|
||||
/// </summary>
|
||||
protected virtual void UpdateLeds(IEnumerable<Led> ledsToUpdate) => UpdateQueue.SetData(GetUpdateData(ledsToUpdate));
|
||||
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();
|
||||
|
||||
buffer[counter] = GetUpdateData(led);
|
||||
++counter;
|
||||
}
|
||||
|
||||
UpdateQueue.SetData(new ReadOnlySpan<(object, Color)>(buffer)[..counter]);
|
||||
|
||||
ArrayPool<(object, Color)>.Shared.Return(buffer);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void Dispose()
|
||||
{
|
||||
try { UpdateQueue.Dispose(); } catch { /* :( */ }
|
||||
try
|
||||
{
|
||||
UpdateQueue.RemoveReferencingObject(this);
|
||||
if (!UpdateQueue.HasActiveReferences())
|
||||
UpdateQueue.Dispose();
|
||||
}
|
||||
catch { /* :( */ }
|
||||
try { LedMapping.Clear(); } catch { /* this really shouldn't happen */ }
|
||||
|
||||
IdGenerator.ResetCounter(GetType().Assembly);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -169,7 +179,7 @@ public abstract class AbstractRGBDevice<TDeviceInfo> : Placeable, IRGBDevice<TDe
|
||||
{ }
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Led? AddLed(LedId ledId, in Point location, in Size size, object? customData = null)
|
||||
public virtual Led? AddLed(LedId ledId, Point location, Size size, object? customData = null)
|
||||
{
|
||||
if ((ledId == LedId.Invalid) || LedMapping.ContainsKey(ledId)) return null;
|
||||
|
||||
|
||||
@ -12,6 +12,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private bool _isDisposed = false;
|
||||
|
||||
private readonly double _defaultUpdateRateHardLimit;
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -20,14 +22,19 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
|
||||
/// <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 IEnumerable<IRGBDevice> Devices { get; protected set; } = Enumerable.Empty<IRGBDevice>();
|
||||
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; } = new();
|
||||
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());
|
||||
@ -39,6 +46,9 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<ExceptionEventArgs>? Exception;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<DevicesChangedEventArgs>? DevicesChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
@ -52,6 +62,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
|
||||
this._defaultUpdateRateHardLimit = defaultUpdateRateHardLimit;
|
||||
}
|
||||
|
||||
~AbstractRGBDeviceProvider() => Dispose(false);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
@ -59,6 +71,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
|
||||
/// <inheritdoc />
|
||||
public bool Initialize(RGBDeviceType loadFilter = RGBDeviceType.All, bool throwExceptions = false)
|
||||
{
|
||||
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
|
||||
|
||||
ThrowsExceptions = throwExceptions;
|
||||
|
||||
try
|
||||
@ -67,7 +81,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
|
||||
|
||||
InitializeSDK();
|
||||
|
||||
Devices = new ReadOnlyCollection<IRGBDevice>(GetLoadedDevices(loadFilter).ToList());
|
||||
foreach (IRGBDevice device in GetLoadedDevices(loadFilter))
|
||||
AddDevice(device);
|
||||
|
||||
foreach (IDeviceUpdateTrigger updateTrigger in UpdateTriggerMapping.Values)
|
||||
updateTrigger.Start();
|
||||
@ -99,7 +114,9 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
|
||||
/// <returns>The filtered collection of loaded devices.</returns>
|
||||
protected virtual IEnumerable<IRGBDevice> GetLoadedDevices(RGBDeviceType loadFilter)
|
||||
{
|
||||
List<IRGBDevice> devices = new();
|
||||
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
|
||||
|
||||
List<IRGBDevice> devices = [];
|
||||
foreach (IRGBDevice device in LoadDevices())
|
||||
{
|
||||
try
|
||||
@ -143,6 +160,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
|
||||
/// <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));
|
||||
|
||||
@ -162,23 +181,61 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
|
||||
/// </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();
|
||||
|
||||
Devices = Enumerable.Empty<IRGBDevice>();
|
||||
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>
|
||||
protected virtual void Throw(Exception ex, bool isCritical = false)
|
||||
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 */ }
|
||||
@ -188,18 +245,38 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws the <see cref="Exception"/> event.
|
||||
/// 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 virtual void Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
Reset();
|
||||
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
|
||||
}
|
||||
@ -72,7 +72,7 @@ public interface IRGBDevice : IEnumerable<Led>, IPlaceable, IBindable, IDisposab
|
||||
/// <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, in Point location, in Size size, object? customData = null);
|
||||
Led? AddLed(LedId ledId, Point location, Size size, object? customData = null);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the led with the specified id from the device.
|
||||
|
||||
@ -20,12 +20,16 @@ public interface IRGBDeviceProvider : IDisposable
|
||||
/// <summary>
|
||||
/// Indicates if exceptions in the device provider are thrown or silently ignored.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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>
|
||||
/// Gets a collection of <see cref="IRGBDevice"/> loaded by this <see cref="IRGBDeviceProvider"/>.
|
||||
/// </summary>
|
||||
IEnumerable<IRGBDevice> Devices { get; }
|
||||
IReadOnlyList<IRGBDevice> Devices { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection <see cref="IDeviceUpdateTrigger"/> registered to this device provider.
|
||||
@ -41,6 +45,11 @@ public interface IRGBDeviceProvider : IDisposable
|
||||
/// </summary>
|
||||
event EventHandler<ExceptionEventArgs>? Exception;
|
||||
|
||||
/// <summary>
|
||||
/// Occures when the devices provided by this device provider changed.
|
||||
/// </summary>
|
||||
event EventHandler<DevicesChangedEventArgs>? DevicesChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
@ -93,6 +93,11 @@ public enum RGBDeviceType
|
||||
/// </summary>
|
||||
LedController = 1 << 15,
|
||||
|
||||
/// <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>
|
||||
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a cooler-device
|
||||
/// </summary>
|
||||
public interface ICooler : IRGBDevice
|
||||
{ }
|
||||
public interface ICooler : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a DRAM-device
|
||||
/// </summary>
|
||||
public interface IDRAM : IRGBDevice
|
||||
{ }
|
||||
public interface IDRAM : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// represents a fan-device
|
||||
/// </summary>
|
||||
public interface IFan : IRGBDevice
|
||||
{ }
|
||||
public interface IFan : IRGBDevice;
|
||||
6
RGB.NET.Core/Devices/TypeInterfaces/IGameController.cs
Normal file
6
RGB.NET.Core/Devices/TypeInterfaces/IGameController.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a gamecontroller-device
|
||||
/// </summary>
|
||||
public interface IGameController: IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a graphics-card-device
|
||||
/// </summary>
|
||||
public interface IGraphicsCard : IRGBDevice
|
||||
{ }
|
||||
public interface IGraphicsCard : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a headset-device
|
||||
/// </summary>
|
||||
public interface IHeadset : IRGBDevice
|
||||
{ }
|
||||
public interface IHeadset : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a headset-stand-device
|
||||
/// </summary>
|
||||
public interface IHeadsetStand : IRGBDevice
|
||||
{ }
|
||||
public interface IHeadsetStand : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a keypad-device
|
||||
/// </summary>
|
||||
public interface IKeypad : IRGBDevice
|
||||
{ }
|
||||
public interface IKeypad : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a led-matrix-device
|
||||
/// </summary>
|
||||
public interface ILedMatrix : IRGBDevice
|
||||
{ }
|
||||
public interface ILedMatrix : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a led-stripe-device
|
||||
/// </summary>
|
||||
public interface ILedStripe : IRGBDevice
|
||||
{ }
|
||||
public interface ILedStripe : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a mainboard-device
|
||||
/// </summary>
|
||||
public interface IMainboard : IRGBDevice
|
||||
{ }
|
||||
public interface IMainboard : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a mouse-device
|
||||
/// </summary>
|
||||
public interface IMouse : IRGBDevice
|
||||
{ }
|
||||
public interface IMouse : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a mousepad-device
|
||||
/// </summary>
|
||||
public interface IMousepad : IRGBDevice
|
||||
{ }
|
||||
public interface IMousepad : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a speaker-device
|
||||
/// </summary>
|
||||
public interface ISpeaker : IRGBDevice
|
||||
{ }
|
||||
public interface ISpeaker : IRGBDevice;
|
||||
@ -3,5 +3,4 @@
|
||||
/// <summary>
|
||||
/// Represents a device with unkown or not specified type.
|
||||
/// </summary>
|
||||
public interface IUnknownDevice : IRGBDevice
|
||||
{ }
|
||||
public interface IUnknownDevice : IRGBDevice;
|
||||
27
RGB.NET.Core/Events/DevicesChangedEventArgs.cs
Normal file
27
RGB.NET.Core/Events/DevicesChangedEventArgs.cs
Normal file
@ -0,0 +1,27 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -6,5 +6,4 @@ namespace RGB.NET.Core;
|
||||
/// <summary>
|
||||
/// Represents the information supplied with an <see cref="E:RGB.NET.Core.RGBSurface.Updated" />-event.
|
||||
/// </summary>
|
||||
public class UpdatedEventArgs : EventArgs
|
||||
{ }
|
||||
public class UpdatedEventArgs : EventArgs;
|
||||
@ -26,7 +26,7 @@ public class UpdatingEventArgs : EventArgs
|
||||
/// <summary>
|
||||
/// Gets the custom-data provided by the trigger for this update.
|
||||
/// </summary>
|
||||
public CustomUpdateData CustomData { get; }
|
||||
public ICustomUpdateData CustomData { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
@ -39,7 +39,7 @@ public class UpdatingEventArgs : EventArgs
|
||||
/// <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)
|
||||
public UpdatingEventArgs(double deltaTime, IUpdateTrigger? trigger, ICustomUpdateData customData)
|
||||
{
|
||||
this.DeltaTime = deltaTime;
|
||||
this.Trigger = trigger;
|
||||
|
||||
@ -16,7 +16,7 @@ public static class ColorExtensions
|
||||
/// <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 in Color color1, in Color color2)
|
||||
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();
|
||||
|
||||
@ -91,10 +91,11 @@ public static class FloatExtensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte GetByteValueFromPercentage(this float percentage)
|
||||
{
|
||||
if (float.IsNaN(percentage)) return 0;
|
||||
// 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;
|
||||
|
||||
percentage = percentage.Clamp(0, 1.0f);
|
||||
return (byte)(percentage >= 1.0f ? 255 : percentage * 256.0f);
|
||||
return (byte)(percentage * 256.0f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -16,7 +16,7 @@ public static class PointExtensions
|
||||
/// <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 in Point point, float x = 0, float y = 0) => new(point.X + x, point.Y + y);
|
||||
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.
|
||||
@ -25,7 +25,7 @@ public static class PointExtensions
|
||||
/// <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 in Point point, in Rotation rotation, in Point origin = new())
|
||||
public static Point Rotate(this Point point, Rotation rotation, Point origin = new())
|
||||
{
|
||||
float sin = MathF.Sin(rotation.Radians);
|
||||
float cos = MathF.Cos(rotation.Radians);
|
||||
|
||||
@ -15,7 +15,7 @@ public static class RectangleExtensions
|
||||
/// <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 in Rectangle rect, in Point location) => new(location, rect.Size);
|
||||
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.
|
||||
@ -23,7 +23,7 @@ public static class RectangleExtensions
|
||||
/// <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 in Rectangle rect, float x) => new(new Point(x, rect.Location.Y), rect.Size);
|
||||
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.
|
||||
@ -31,7 +31,7 @@ public static class RectangleExtensions
|
||||
/// <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 in Rectangle rect, float y) => new(new Point(rect.Location.X, y), rect.Size);
|
||||
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.
|
||||
@ -39,7 +39,7 @@ public static class RectangleExtensions
|
||||
/// <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 in Rectangle rect, in Size size) => new(rect.Location, size);
|
||||
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.
|
||||
@ -47,7 +47,7 @@ public static class RectangleExtensions
|
||||
/// <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 in Rectangle rect, float width) => new(rect.Location, new Size(width, rect.Size.Height));
|
||||
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.
|
||||
@ -55,7 +55,7 @@ public static class RectangleExtensions
|
||||
/// <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 in Rectangle rect, float height) => new(rect.Location, new Size(rect.Size.Width, height));
|
||||
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.
|
||||
@ -63,7 +63,7 @@ public static class RectangleExtensions
|
||||
/// <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 in Rectangle rect, in Rectangle intersectingRect)
|
||||
public static float CalculateIntersectPercentage(this Rectangle rect, Rectangle intersectingRect)
|
||||
{
|
||||
if (rect.IsEmpty || intersectingRect.IsEmpty) return 0;
|
||||
|
||||
@ -77,7 +77,7 @@ public static class RectangleExtensions
|
||||
/// <param name="rect">The rectangle to calculate the intersection for.</param>
|
||||
/// <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 in Rectangle rect, in Rectangle intersectingRectangle)
|
||||
public static Rectangle CalculateIntersection(this Rectangle rect, Rectangle intersectingRectangle)
|
||||
{
|
||||
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);
|
||||
@ -97,7 +97,7 @@ public static class RectangleExtensions
|
||||
/// <param name="rect">The containing rectangle.</param>
|
||||
/// <param name="point">The <see cref="Point"/> to test.</param>
|
||||
/// <returns><c>true</c> if the rectangle contains the specified point; otherwise <c>false</c>.</returns>
|
||||
public static bool Contains(this in Rectangle rect, in Point point) => rect.Contains(point.X, point.Y);
|
||||
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"/>.
|
||||
@ -106,7 +106,7 @@ public static class RectangleExtensions
|
||||
/// <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 specified coordinates; otherwise <c>false</c>.</returns>
|
||||
public static bool Contains(this in Rectangle rect, float x, float y) => (rect.Location.X <= x) && (x < (rect.Location.X + rect.Size.Width))
|
||||
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>
|
||||
@ -115,7 +115,7 @@ public static class RectangleExtensions
|
||||
/// <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 in Rectangle rect, in Rectangle rect2) => (rect.Location.X <= rect2.Location.X) && ((rect2.Location.X + rect2.Size.Width) <= (rect.Location.X + rect.Size.Width))
|
||||
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>
|
||||
@ -124,7 +124,7 @@ public static class RectangleExtensions
|
||||
/// <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 in Rectangle rect, in Point point) => rect.Translate(point.X, point.Y);
|
||||
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.
|
||||
@ -133,7 +133,7 @@ public static class RectangleExtensions
|
||||
/// <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 in Rectangle rect, float x = 0, float y = 0) => new(rect.Location.Translate(x, y), rect.Size);
|
||||
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.
|
||||
@ -149,14 +149,15 @@ public static class RectangleExtensions
|
||||
/// <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 in Rectangle rect, in Rotation rotation, in Point origin = new())
|
||||
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
|
||||
};
|
||||
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);
|
||||
|
||||
6
RGB.NET.Core/Extensions/ReferenceCountingExtension.cs
Normal file
6
RGB.NET.Core/Extensions/ReferenceCountingExtension.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
public static class ReferenceCountingExtension
|
||||
{
|
||||
public static bool HasActiveReferences(this IReferenceCounting target) => target.ActiveReferenceCount > 0;
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
@ -51,11 +53,23 @@ public abstract class AbstractLedGroup : AbstractDecoratable<ILedGroupDecorator>
|
||||
/// <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,6 +1,7 @@
|
||||
// ReSharper disable UnusedMemberInSuper.Global
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
@ -39,4 +40,12 @@ public interface ILedGroup : IDecoratable<ILedGroupDecorator>, IEnumerable<Led>
|
||||
/// 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,7 +1,9 @@
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
@ -9,14 +11,16 @@ namespace RGB.NET.Core;
|
||||
/// <summary>
|
||||
/// Represents a ledgroup containing arbitrary <see cref="T:RGB.NET.Core.Led" />.
|
||||
/// </summary>
|
||||
public class ListLedGroup : AbstractLedGroup
|
||||
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>
|
||||
protected IList<Led> GroupLeds { get; } = new List<Led>();
|
||||
private readonly IList<Led> _groupLeds = [];
|
||||
|
||||
#endregion
|
||||
|
||||
@ -29,7 +33,9 @@ public class ListLedGroup : AbstractLedGroup
|
||||
/// <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>
|
||||
@ -40,6 +46,8 @@ public class ListLedGroup : AbstractLedGroup
|
||||
public ListLedGroup(RGBSurface? surface, IEnumerable<Led> leds)
|
||||
: base(surface)
|
||||
{
|
||||
_unlockDisposable = new ActionDisposable(Unlock);
|
||||
|
||||
AddLeds(leds);
|
||||
}
|
||||
|
||||
@ -52,6 +60,8 @@ public class ListLedGroup : AbstractLedGroup
|
||||
public ListLedGroup(RGBSurface? surface, params Led[] leds)
|
||||
: base(surface)
|
||||
{
|
||||
_unlockDisposable = new ActionDisposable(Unlock);
|
||||
|
||||
AddLeds(leds);
|
||||
}
|
||||
|
||||
@ -71,10 +81,10 @@ public class ListLedGroup : AbstractLedGroup
|
||||
/// <param name="leds">The <see cref="Led"/> to add.</param>
|
||||
public void AddLeds(IEnumerable<Led> leds)
|
||||
{
|
||||
lock (GroupLeds)
|
||||
lock (_groupLeds)
|
||||
foreach (Led led in leds)
|
||||
if (!ContainsLed(led))
|
||||
GroupLeds.Add(led);
|
||||
_groupLeds.Add(led);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -89,9 +99,9 @@ public class ListLedGroup : AbstractLedGroup
|
||||
/// <param name="leds">The <see cref="Led"/> to remove.</param>
|
||||
public void RemoveLeds(IEnumerable<Led> leds)
|
||||
{
|
||||
lock (GroupLeds)
|
||||
lock (_groupLeds)
|
||||
foreach (Led led in leds)
|
||||
GroupLeds.Remove(led);
|
||||
_groupLeds.Remove(led);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -101,8 +111,8 @@ public class ListLedGroup : AbstractLedGroup
|
||||
/// <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);
|
||||
lock (_groupLeds)
|
||||
return _groupLeds.Contains(led);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -111,10 +121,10 @@ public class ListLedGroup : AbstractLedGroup
|
||||
/// <param name="groupToMerge">The ledgroup to merge.</param>
|
||||
public void MergeLeds(ILedGroup groupToMerge)
|
||||
{
|
||||
lock (GroupLeds)
|
||||
lock (_groupLeds)
|
||||
foreach (Led led in groupToMerge)
|
||||
if (!GroupLeds.Contains(led))
|
||||
GroupLeds.Add(led);
|
||||
if (!_groupLeds.Contains(led))
|
||||
_groupLeds.Add(led);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -122,11 +132,27 @@ public class ListLedGroup : AbstractLedGroup
|
||||
/// 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()
|
||||
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 new List<Led>(GroupLeds);
|
||||
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
|
||||
}
|
||||
@ -40,7 +40,7 @@ public static class ConversionHelper
|
||||
public static byte[] HexToBytes(ReadOnlySpan<char> hexString)
|
||||
{
|
||||
if ((hexString.Length == 0) || ((hexString.Length % 2) != 0))
|
||||
return Array.Empty<byte>();
|
||||
return [];
|
||||
|
||||
byte[] buffer = new byte[hexString.Length / 2];
|
||||
for (int bx = 0, sx = 0; bx < buffer.Length; ++bx, ++sx)
|
||||
|
||||
@ -24,7 +24,7 @@ public static class TimerHelper
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
private static readonly object HIGH_RESOLUTION_TIMER_LOCK = new();
|
||||
private static readonly Lock HIGH_RESOLUTION_TIMER_LOCK = new();
|
||||
|
||||
private static bool _areHighResolutionTimersEnabled = false;
|
||||
|
||||
@ -46,7 +46,7 @@ public static class TimerHelper
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static readonly HashSet<HighResolutionTimerDisposable> _timerLeases = new();
|
||||
private static readonly HashSet<HighResolutionTimerDisposable> _timerLeases = [];
|
||||
|
||||
#endregion
|
||||
|
||||
@ -143,7 +143,7 @@ public static class TimerHelper
|
||||
/// </summary>
|
||||
public static void DisposeAllHighResolutionTimerRequests()
|
||||
{
|
||||
List<HighResolutionTimerDisposable> timerLeases = new(_timerLeases);
|
||||
List<HighResolutionTimerDisposable> timerLeases = [.._timerLeases];
|
||||
foreach (HighResolutionTimerDisposable timer in timerLeases)
|
||||
timer.Dispose();
|
||||
}
|
||||
|
||||
@ -12,9 +12,9 @@ public static class IdGenerator
|
||||
#region Properties & Fields
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
private static readonly HashSet<string> _registeredIds = new();
|
||||
private static readonly Dictionary<Assembly, Dictionary<string, string>> _idMappings = new();
|
||||
private static readonly Dictionary<Assembly, Dictionary<string, int>> _counter = new();
|
||||
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
|
||||
@ -33,8 +33,8 @@ public static class IdGenerator
|
||||
{
|
||||
if (!_idMappings.TryGetValue(callingAssembly, out Dictionary<string, string>? idMapping))
|
||||
{
|
||||
_idMappings.Add(callingAssembly, idMapping = new Dictionary<string, string>());
|
||||
_counter.Add(callingAssembly, new Dictionary<string, int>());
|
||||
_idMappings.Add(callingAssembly, idMapping = []);
|
||||
_counter.Add(callingAssembly, []);
|
||||
}
|
||||
|
||||
Dictionary<string, int> counterMapping = _counter[callingAssembly];
|
||||
@ -50,8 +50,7 @@ public static class IdGenerator
|
||||
idMapping.Add(id, mappedId);
|
||||
}
|
||||
|
||||
if (!counterMapping.ContainsKey(mappedId))
|
||||
counterMapping.Add(mappedId, 0);
|
||||
counterMapping.TryAdd(mappedId, 0);
|
||||
|
||||
int counter = ++counterMapping[mappedId];
|
||||
return counter <= 1 ? mappedId : $"{mappedId} ({counter})";
|
||||
|
||||
@ -9,7 +9,7 @@ namespace RGB.NET.Core;
|
||||
/// Represents a single LED of a RGB-device.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{Id} {Color}")]
|
||||
public class Led : Placeable
|
||||
public sealed class Led : Placeable
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
|
||||
@ -372,6 +372,14 @@ public enum LedId
|
||||
Keyboard_Custom127 = 0x0000707F,
|
||||
Keyboard_Custom128 = 0x00007080,
|
||||
|
||||
Keyboard_IndicatorNumLock = 0x00008001,
|
||||
Keyboard_IndicatorCapsLock = 0x00008002,
|
||||
Keyboard_IndicatorScrollLock = 0x00008003,
|
||||
Keyboard_IndicatorWinLock = 0x00008004,
|
||||
Keyboard_IndicatorPower = 0x00008005,
|
||||
Keyboard_IndicatorMuted = 0x00008006,
|
||||
Keyboard_IndicatorMacro = 0x00008007,
|
||||
|
||||
/*### Mouse ###*/
|
||||
Mouse1 = 0x00100001,
|
||||
Mouse2 = 0x00100002,
|
||||
@ -6286,6 +6294,136 @@ public enum LedId
|
||||
Cooler127 = 0x00D0007F,
|
||||
Cooler128 = 0x00D00080,
|
||||
|
||||
/*### GameController ###*/
|
||||
GameController1 = 0x00E00001,
|
||||
GameController2 = 0x00E00002,
|
||||
GameController3 = 0x00E00003,
|
||||
GameController4 = 0x00E00004,
|
||||
GameController5 = 0x00E00005,
|
||||
GameController6 = 0x00E00006,
|
||||
GameController7 = 0x00E00007,
|
||||
GameController8 = 0x00E00008,
|
||||
GameController9 = 0x00E00009,
|
||||
GameController10 = 0x00E0000A,
|
||||
GameController11 = 0x00E0000B,
|
||||
GameController12 = 0x00E0000C,
|
||||
GameController13 = 0x00E0000D,
|
||||
GameController14 = 0x00E0000E,
|
||||
GameController15 = 0x00E0000F,
|
||||
GameController16 = 0x00E00010,
|
||||
GameController17 = 0x00E00011,
|
||||
GameController18 = 0x00E00012,
|
||||
GameController19 = 0x00E00013,
|
||||
GameController20 = 0x00E00014,
|
||||
GameController21 = 0x00E00015,
|
||||
GameController22 = 0x00E00016,
|
||||
GameController23 = 0x00E00017,
|
||||
GameController24 = 0x00E00018,
|
||||
GameController25 = 0x00E00019,
|
||||
GameController26 = 0x00E0001A,
|
||||
GameController27 = 0x00E0001B,
|
||||
GameController28 = 0x00E0001C,
|
||||
GameController29 = 0x00E0001D,
|
||||
GameController30 = 0x00E0001E,
|
||||
GameController31 = 0x00E0001F,
|
||||
GameController32 = 0x00E00020,
|
||||
GameController33 = 0x00E00021,
|
||||
GameController34 = 0x00E00022,
|
||||
GameController35 = 0x00E00023,
|
||||
GameController36 = 0x00E00024,
|
||||
GameController37 = 0x00E00025,
|
||||
GameController38 = 0x00E00026,
|
||||
GameController39 = 0x00E00027,
|
||||
GameController40 = 0x00E00028,
|
||||
GameController41 = 0x00E00029,
|
||||
GameController42 = 0x00E0002A,
|
||||
GameController43 = 0x00E0002B,
|
||||
GameController44 = 0x00E0002C,
|
||||
GameController45 = 0x00E0002D,
|
||||
GameController46 = 0x00E0002E,
|
||||
GameController47 = 0x00E0002F,
|
||||
GameController48 = 0x00E00030,
|
||||
GameController49 = 0x00E00031,
|
||||
GameController50 = 0x00E00032,
|
||||
GameController51 = 0x00E00033,
|
||||
GameController52 = 0x00E00034,
|
||||
GameController53 = 0x00E00035,
|
||||
GameController54 = 0x00E00036,
|
||||
GameController55 = 0x00E00037,
|
||||
GameController56 = 0x00E00038,
|
||||
GameController57 = 0x00E00039,
|
||||
GameController58 = 0x00E0003A,
|
||||
GameController59 = 0x00E0003B,
|
||||
GameController60 = 0x00E0003C,
|
||||
GameController61 = 0x00E0003D,
|
||||
GameController62 = 0x00E0003E,
|
||||
GameController63 = 0x00E0003F,
|
||||
GameController64 = 0x00E00040,
|
||||
GameController65 = 0x00E00041,
|
||||
GameController66 = 0x00E00042,
|
||||
GameController67 = 0x00E00043,
|
||||
GameController68 = 0x00E00044,
|
||||
GameController69 = 0x00E00045,
|
||||
GameController70 = 0x00E00046,
|
||||
GameController71 = 0x00E00047,
|
||||
GameController72 = 0x00E00048,
|
||||
GameController73 = 0x00E00049,
|
||||
GameController74 = 0x00E0004A,
|
||||
GameController75 = 0x00E0004B,
|
||||
GameController76 = 0x00E0004C,
|
||||
GameController77 = 0x00E0004D,
|
||||
GameController78 = 0x00E0004E,
|
||||
GameController79 = 0x00E0004F,
|
||||
GameController80 = 0x00E00050,
|
||||
GameController81 = 0x00E00051,
|
||||
GameController82 = 0x00E00052,
|
||||
GameController83 = 0x00E00053,
|
||||
GameController84 = 0x00E00054,
|
||||
GameController85 = 0x00E00055,
|
||||
GameController86 = 0x00E00056,
|
||||
GameController87 = 0x00E00057,
|
||||
GameController88 = 0x00E00058,
|
||||
GameController89 = 0x00E00059,
|
||||
GameController90 = 0x00E0005A,
|
||||
GameController91 = 0x00E0005B,
|
||||
GameController92 = 0x00E0005C,
|
||||
GameController93 = 0x00E0005D,
|
||||
GameController94 = 0x00E0005E,
|
||||
GameController95 = 0x00E0005F,
|
||||
GameController96 = 0x00E00060,
|
||||
GameController97 = 0x00E00061,
|
||||
GameController98 = 0x00E00062,
|
||||
GameController99 = 0x00E00063,
|
||||
GameController100 = 0x00E00064,
|
||||
GameController101 = 0x00E00065,
|
||||
GameController102 = 0x00E00066,
|
||||
GameController103 = 0x00E00067,
|
||||
GameController104 = 0x00E00068,
|
||||
GameController105 = 0x00E00069,
|
||||
GameController106 = 0x00E0006A,
|
||||
GameController107 = 0x00E0006B,
|
||||
GameController108 = 0x00E0006C,
|
||||
GameController109 = 0x00E0006D,
|
||||
GameController110 = 0x00E0006E,
|
||||
GameController111 = 0x00E0006F,
|
||||
GameController112 = 0x00E00070,
|
||||
GameController113 = 0x00E00071,
|
||||
GameController114 = 0x00E00072,
|
||||
GameController115 = 0x00E00073,
|
||||
GameController116 = 0x00E00074,
|
||||
GameController117 = 0x00E00075,
|
||||
GameController118 = 0x00E00076,
|
||||
GameController119 = 0x00E00077,
|
||||
GameController120 = 0x00E00078,
|
||||
GameController121 = 0x00E00079,
|
||||
GameController122 = 0x00E0007A,
|
||||
GameController123 = 0x00E0007B,
|
||||
GameController124 = 0x00E0007C,
|
||||
GameController125 = 0x00E0007D,
|
||||
GameController126 = 0x00E0007E,
|
||||
GameController127 = 0x00E0007F,
|
||||
GameController128 = 0x00E00080,
|
||||
|
||||
/*### Custom ###*/
|
||||
Custom1 = 0x0FE00001,
|
||||
Custom2 = 0x0FE00002,
|
||||
|
||||
@ -8,13 +8,19 @@ namespace RGB.NET.Core;
|
||||
/// 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 class LedMapping<T> : IEnumerable<(LedId ledId, T mapping)>
|
||||
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 = new();
|
||||
private readonly Dictionary<T, LedId> _reverseMapping = new();
|
||||
private readonly Dictionary<LedId, T> _mapping = [];
|
||||
private readonly Dictionary<T, LedId> _reverseMapping = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of entries in this mapping.
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System.ComponentModel;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
@ -26,9 +27,9 @@ public abstract class AbstractBindable : IBindable
|
||||
/// <typeparam name="T">Type of the property.</typeparam>
|
||||
/// <param name="storage">Reference to the backing-filed.</param>
|
||||
/// <param name="value">Value to apply.</param>
|
||||
/// <returns><c>true</c> if the value needs to be updated; otherweise <c>false</c>.</returns>
|
||||
/// <returns><c>true</c> if the value needs to be updated; otherwise <c>false</c>.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected virtual bool RequiresUpdate<T>(ref T storage, T value) => !Equals(storage, value);
|
||||
protected bool RequiresUpdate<T>(ref T storage, T value) => !EqualityComparer<T>.Default.Equals(storage, value);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the property already matches the desired value and updates it if not.
|
||||
@ -39,7 +40,7 @@ public abstract class AbstractBindable : IBindable
|
||||
/// <param name="propertyName">Name of the property used to notify listeners. This value is optional
|
||||
/// and can be provided automatically when invoked from compilers that support <see cref="CallerMemberNameAttribute"/>.</param>
|
||||
/// <returns><c>true</c> if the value was changed, <c>false</c> if the existing value matched the desired value.</returns>
|
||||
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string? propertyName = null)
|
||||
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
if (!RequiresUpdate(ref storage, value)) return false;
|
||||
|
||||
@ -54,7 +55,7 @@ public abstract class AbstractBindable : IBindable
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property used to notify listeners. This value is optional
|
||||
/// and can be provided automatically when invoked from compilers that support <see cref="CallerMemberNameAttribute"/>.</param>
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
|
||||
#endregion
|
||||
|
||||
@ -5,6 +5,4 @@ namespace RGB.NET.Core;
|
||||
/// <summary>
|
||||
/// Represents a basic bindable class which notifies when a property value changes.
|
||||
/// </summary>
|
||||
public interface IBindable : INotifyPropertyChanged
|
||||
{
|
||||
}
|
||||
public interface IBindable : INotifyPropertyChanged;
|
||||
40
RGB.NET.Core/Misc/AbstractReferenceCounting.cs
Normal file
40
RGB.NET.Core/Misc/AbstractReferenceCounting.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
public abstract class AbstractReferenceCounting : IReferenceCounting
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly HashSet<object> _referencingObjects = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public int ActiveReferenceCount
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_referencingObjects)
|
||||
return _referencingObjects.Count;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AddReferencingObject(object obj)
|
||||
{
|
||||
lock (_referencingObjects)
|
||||
_referencingObjects.Add(obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RemoveReferencingObject(object obj)
|
||||
{
|
||||
lock (_referencingObjects)
|
||||
_referencingObjects.Remove(obj);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
12
RGB.NET.Core/Misc/ActionDisposable.cs
Normal file
12
RGB.NET.Core/Misc/ActionDisposable.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
public sealed class ActionDisposable(Action onDispose) : IDisposable
|
||||
{
|
||||
#region Methods
|
||||
|
||||
public void Dispose() => onDispose();
|
||||
|
||||
#endregion
|
||||
}
|
||||
21
RGB.NET.Core/Misc/IReferenceCounting.cs
Normal file
21
RGB.NET.Core/Misc/IReferenceCounting.cs
Normal file
@ -0,0 +1,21 @@
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
public interface IReferenceCounting
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the amount of currently registered referencing objects.
|
||||
/// </summary>
|
||||
public int ActiveReferenceCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given object to the list of referencing objects.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to add.</param>
|
||||
public void AddReferencingObject(object obj);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the given object from the list of referencing objects.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to remove.</param>
|
||||
public void RemoveReferencingObject(object obj);
|
||||
}
|
||||
@ -211,7 +211,7 @@ public class Placeable : AbstractBindable, IPlaceable
|
||||
/// </summary>
|
||||
protected virtual void OnLocationChanged()
|
||||
{
|
||||
LocationChanged?.Invoke(this, new EventArgs());
|
||||
LocationChanged?.Invoke(this, EventArgs.Empty);
|
||||
UpdateActualPlaceableData();
|
||||
}
|
||||
|
||||
@ -220,7 +220,7 @@ public class Placeable : AbstractBindable, IPlaceable
|
||||
/// </summary>
|
||||
protected virtual void OnSizeChanged()
|
||||
{
|
||||
SizeChanged?.Invoke(this, new EventArgs());
|
||||
SizeChanged?.Invoke(this, EventArgs.Empty);
|
||||
UpdateActualPlaceableData();
|
||||
}
|
||||
|
||||
@ -229,7 +229,7 @@ public class Placeable : AbstractBindable, IPlaceable
|
||||
/// </summary>
|
||||
protected virtual void OnScaleChanged()
|
||||
{
|
||||
ScaleChanged?.Invoke(this, new EventArgs());
|
||||
ScaleChanged?.Invoke(this, EventArgs.Empty);
|
||||
UpdateActualPlaceableData();
|
||||
}
|
||||
|
||||
@ -238,24 +238,24 @@ public class Placeable : AbstractBindable, IPlaceable
|
||||
/// </summary>
|
||||
protected virtual void OnRotationChanged()
|
||||
{
|
||||
RotationChanged?.Invoke(this, new EventArgs());
|
||||
RotationChanged?.Invoke(this, EventArgs.Empty);
|
||||
UpdateActualPlaceableData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the <see cref="ActualLocation"/> property was changed.
|
||||
/// </summary>
|
||||
protected virtual void OnActualLocationChanged() => ActualLocationChanged?.Invoke(this, new EventArgs());
|
||||
protected virtual void OnActualLocationChanged() => ActualLocationChanged?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the <see cref="ActualLocation"/> property was changed.
|
||||
/// </summary>
|
||||
protected virtual void OnActualSizeChanged() => ActualSizeChanged?.Invoke(this, new EventArgs());
|
||||
protected virtual void OnActualSizeChanged() => ActualSizeChanged?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the <see cref="Boundary"/> property was changed.
|
||||
/// </summary>
|
||||
protected virtual void OnBoundaryChanged() => BoundaryChanged?.Invoke(this, new EventArgs());
|
||||
protected virtual void OnBoundaryChanged() => BoundaryChanged?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -10,7 +10,7 @@ namespace RGB.NET.Core;
|
||||
/// Represents a point consisting of a X- and a Y-position.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("[X: {X}, Y: {Y}]")]
|
||||
public readonly struct Point
|
||||
public readonly struct Point : IEquatable<Point>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
@ -59,18 +59,20 @@ public readonly struct Point
|
||||
/// <returns>A string that contains the <see cref="X"/> and <see cref="Y"/> of this <see cref="Point"/>. For example "[X: 100, Y: 20]".</returns>
|
||||
public override string ToString() => $"[X: {X}, Y: {Y}]";
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the specified <see cref="Point" /> is equivalent to this <see cref="Point" />.
|
||||
/// </summary>
|
||||
/// <param name="other">The point to test.</param>
|
||||
/// <returns><c>true</c> if <paramref name="other" /> is equivalent to this <see cref="Point" />; otherwise, <c>false</c>.</returns>
|
||||
public bool Equals(Point other) => ((float.IsNaN(X) && float.IsNaN(other.X)) || X.EqualsInTolerance(other.X))
|
||||
&& ((float.IsNaN(Y) && float.IsNaN(other.Y)) || Y.EqualsInTolerance(other.Y));
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the specified object is a <see cref="Point" /> and is equivalent to this <see cref="Point" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to test.</param>
|
||||
/// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Point" /> equivalent to this <see cref="Point" />; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is not Point comparePoint) return false;
|
||||
|
||||
return ((float.IsNaN(X) && float.IsNaN(comparePoint.X)) || X.EqualsInTolerance(comparePoint.X))
|
||||
&& ((float.IsNaN(Y) && float.IsNaN(comparePoint.Y)) || Y.EqualsInTolerance(comparePoint.Y));
|
||||
}
|
||||
public override bool Equals(object? obj) => obj is Point other && Equals(other);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this <see cref="Point" />.
|
||||
@ -88,7 +90,7 @@ public readonly struct Point
|
||||
/// <param name="point1">The first <see cref="Point" /> to compare.</param>
|
||||
/// <param name="point2">The second <see cref="Point" /> to compare.</param>
|
||||
/// <returns><c>true</c> if <paramref name="point1" /> and <paramref name="point2" /> are equal; otherwise, <c>false</c>.</returns>
|
||||
public static bool operator ==(in Point point1, in Point point2) => point1.Equals(point2);
|
||||
public static bool operator ==(Point point1, Point point2) => point1.Equals(point2);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value that indicates whether two specified <see cref="Point" /> are equal.
|
||||
@ -96,7 +98,7 @@ public readonly struct Point
|
||||
/// <param name="point1">The first <see cref="Point" /> to compare.</param>
|
||||
/// <param name="point2">The second <see cref="Point" /> to compare.</param>
|
||||
/// <returns><c>true</c> if <paramref name="point1" /> and <paramref name="point2" /> are not equal; otherwise, <c>false</c>.</returns>
|
||||
public static bool operator !=(in Point point1, in Point point2) => !(point1 == point2);
|
||||
public static bool operator !=(Point point1, Point point2) => !(point1 == point2);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Point"/> representing the addition of the two provided <see cref="Point"/>.
|
||||
@ -104,7 +106,7 @@ public readonly struct Point
|
||||
/// <param name="point1">The first <see cref="Point"/>.</param>
|
||||
/// <param name="point2">The second <see cref="Point"/>.</param>
|
||||
/// <returns>A new <see cref="Point"/> representing the addition of the two provided <see cref="Point"/>.</returns>
|
||||
public static Point operator +(in Point point1, in Point point2) => new(point1.X + point2.X, point1.Y + point2.Y);
|
||||
public static Point operator +(Point point1, Point point2) => new(point1.X + point2.X, point1.Y + point2.Y);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Rectangle"/> created from the provided <see cref="Point"/> and <see cref="Size"/>.
|
||||
@ -112,7 +114,7 @@ public readonly struct Point
|
||||
/// <param name="point">The <see cref="Point"/> of the rectangle.</param>
|
||||
/// <param name="size">The <see cref="Size"/> of the rectangle.</param>
|
||||
/// <returns>The rectangle created from the provided <see cref="Point"/> and <see cref="Size"/>.</returns>
|
||||
public static Rectangle operator +(in Point point, in Size size) => new(point, size);
|
||||
public static Rectangle operator +(Point point, Size size) => new(point, size);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Point"/> representing the subtraction of the two provided <see cref="Point"/>.
|
||||
@ -120,7 +122,7 @@ public readonly struct Point
|
||||
/// <param name="point1">The first <see cref="Point"/>.</param>
|
||||
/// <param name="point2">The second <see cref="Point"/>.</param>
|
||||
/// <returns>A new <see cref="Point"/> representing the subtraction of the two provided <see cref="Point"/>.</returns>
|
||||
public static Point operator -(in Point point1, in Point point2) => new(point1.X - point2.X, point1.Y - point2.Y);
|
||||
public static Point operator -(Point point1, Point point2) => new(point1.X - point2.X, point1.Y - point2.Y);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Point"/> representing the multiplication of the two provided <see cref="Point"/>.
|
||||
@ -128,7 +130,7 @@ public readonly struct Point
|
||||
/// <param name="point1">The first <see cref="Point"/>.</param>
|
||||
/// <param name="point2">The second <see cref="Point"/>.</param>
|
||||
/// <returns>A new <see cref="Point"/> representing the multiplication of the two provided <see cref="Point"/>.</returns>
|
||||
public static Point operator *(in Point point1, in Point point2) => new(point1.X * point2.X, point1.Y * point2.Y);
|
||||
public static Point operator *(Point point1, Point point2) => new(point1.X * point2.X, point1.Y * point2.Y);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Point"/> representing the division of the two provided <see cref="Point"/>.
|
||||
@ -136,7 +138,7 @@ public readonly struct Point
|
||||
/// <param name="point1">The first <see cref="Point"/>.</param>
|
||||
/// <param name="point2">The second <see cref="Point"/>.</param>
|
||||
/// <returns>A new <see cref="Point"/> representing the division of the two provided <see cref="Point"/>.</returns>
|
||||
public static Point operator /(in Point point1, in Point point2)
|
||||
public static Point operator /(Point point1, Point point2)
|
||||
{
|
||||
if (point2.X.EqualsInTolerance(0) || point2.Y.EqualsInTolerance(0)) return Invalid;
|
||||
return new Point(point1.X / point2.X, point1.Y / point2.Y);
|
||||
@ -148,7 +150,7 @@ public readonly struct Point
|
||||
/// <param name="point">The <see cref="Point"/>.</param>
|
||||
/// <param name="scale">The <see cref="Scale"/>.</param>
|
||||
/// <returns>A new <see cref="Point"/> representing the multiplication of the <see cref="Point"/> and the provided <see cref="Scale"/>.</returns>
|
||||
public static Point operator *(in Point point, in Scale scale) => new(point.X * scale.Horizontal, point.Y * scale.Vertical);
|
||||
public static Point operator *(Point point, Scale scale) => new(point.X * scale.Horizontal, point.Y * scale.Vertical);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -12,7 +12,7 @@ namespace RGB.NET.Core;
|
||||
/// Represents a rectangle defined by it's position and it's size.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("[Location: {Location}, Size: {Size}]")]
|
||||
public readonly struct Rectangle
|
||||
public readonly struct Rectangle : IEquatable<Rectangle>
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
@ -57,7 +57,8 @@ public readonly struct Rectangle
|
||||
/// Initializes a new instance of the <see cref="Rectangle"/> class using the <see cref="Location"/>(0,0) and the specified <see cref="Core.Size"/>.
|
||||
/// </summary>
|
||||
/// <param name="size">The size of of this <see cref="T:RGB.NET.Core.Rectangle" />.</param>
|
||||
public Rectangle(Size size) : this(new Point(), size)
|
||||
public Rectangle(Size size)
|
||||
: this(new Point(), size)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
@ -120,15 +121,13 @@ public readonly struct Rectangle
|
||||
public Rectangle(params Point[] points)
|
||||
: this(points.AsEnumerable())
|
||||
{ }
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Core.Rectangle" /> class using the specified list of <see cref="T:RGB.NET.Core.Point" />.
|
||||
/// The <see cref="P:RGB.NET.Core.Rectangle.Location" /> and <see cref="P:RGB.NET.Core.Rectangle.Size" /> is calculated to contain all points provided as parameters.
|
||||
/// </summary>
|
||||
/// <param name="points">The list of <see cref="T:RGB.NET.Core.Point" /> used to calculate the <see cref="P:RGB.NET.Core.Rectangle.Location" /> and <see cref="P:RGB.NET.Core.Rectangle.Size" />.</param>
|
||||
public Rectangle(IEnumerable<Point> points)
|
||||
: this()
|
||||
{
|
||||
bool hasPoint = false;
|
||||
float posX = float.MaxValue;
|
||||
@ -145,18 +144,42 @@ public readonly struct Rectangle
|
||||
posY2 = Math.Max(posY2, point.Y);
|
||||
}
|
||||
|
||||
(Point location, Size size) = hasPoint ? InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2)) : InitializeFromPoints(new Point(0, 0), new Point(0, 0));
|
||||
(Point location, Size size) = hasPoint ? InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2))
|
||||
: InitializeFromPoints(new Point(0, 0), new Point(0, 0));
|
||||
|
||||
Location = location;
|
||||
Size = size;
|
||||
Center = new Point(Location.X + (Size.Width / 2.0f), Location.Y + (Size.Height / 2.0f));
|
||||
}
|
||||
|
||||
internal Rectangle(IList<Led> leds)
|
||||
{
|
||||
float posX = float.MaxValue;
|
||||
float posY = float.MaxValue;
|
||||
float posX2 = float.MinValue;
|
||||
float posY2 = float.MinValue;
|
||||
|
||||
// ReSharper disable once ForCanBeConvertedToForeach
|
||||
for (int i = 0; i < leds.Count; i++)
|
||||
{
|
||||
Rectangle rectangle = leds[i].AbsoluteBoundary;
|
||||
posX = Math.Min(posX, rectangle.Location.X);
|
||||
posY = Math.Min(posY, rectangle.Location.Y);
|
||||
posX2 = Math.Max(posX2, rectangle.Location.X + rectangle.Size.Width);
|
||||
posY2 = Math.Max(posY2, rectangle.Location.Y + rectangle.Size.Height);
|
||||
}
|
||||
|
||||
(Point location, Size size) = leds.Count > 0 ? InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2)) : InitializeFromPoints(new Point(0, 0), new Point(0, 0));
|
||||
Location = location;
|
||||
Size = size;
|
||||
Center = new Point(Location.X + (Size.Width / 2.0f), Location.Y + (Size.Height / 2.0f));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
private static (Point location, Size size) InitializeFromPoints(in Point point1, in Point point2)
|
||||
private static (Point location, Size size) InitializeFromPoints(Point point1, Point point2)
|
||||
{
|
||||
float posX = Math.Min(point1.X, point2.X);
|
||||
float posY = Math.Min(point1.Y, point2.Y);
|
||||
@ -172,35 +195,25 @@ public readonly struct Rectangle
|
||||
/// <returns>A string that contains the <see cref="Location"/> and <see cref="Size"/> of this <see cref="Rectangle"/>. For example "[Location: [X: 100, Y: 10], Size: [Width: 20, Height: [40]]".</returns>
|
||||
public override string ToString() => $"[Location: {Location}, Size: {Size}]";
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the specified <see cref="Rectangle" /> is equivalent to this <see cref="Rectangle" />.
|
||||
/// </summary>
|
||||
/// <param name="other">The rectangle to test.</param>
|
||||
/// <returns><c>true</c> if <paramref name="other" /> is equivalent to this <see cref="Rectangle" />; otherwise, <c>false</c>.</returns>
|
||||
public bool Equals(Rectangle other) => (Location == other.Location) && (Size == other.Size);
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the specified object is a <see cref="Rectangle" /> and is equivalent to this <see cref="Rectangle" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to test.</param>
|
||||
/// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Rectangle" /> equivalent to this <see cref="Rectangle" />; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is not Rectangle compareRect)
|
||||
return false;
|
||||
|
||||
if (GetType() != compareRect.GetType())
|
||||
return false;
|
||||
|
||||
return (Location == compareRect.Location) && (Size == compareRect.Size);
|
||||
}
|
||||
public override bool Equals(object? obj) => obj is Rectangle other && Equals(other);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this <see cref="Rectangle" />.
|
||||
/// </summary>
|
||||
/// <returns>An integer value that specifies the hash code for this <see cref="Rectangle" />.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hashCode = Location.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ Size.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
public override int GetHashCode() => HashCode.Combine(Location, Size);
|
||||
|
||||
#endregion
|
||||
|
||||
@ -212,7 +225,7 @@ public readonly struct Rectangle
|
||||
/// <param name="rectangle1">The first <see cref="Rectangle" /> to compare.</param>
|
||||
/// <param name="rectangle2">The second <see cref="Rectangle" /> to compare.</param>
|
||||
/// <returns><c>true</c> if <paramref name="rectangle1" /> and <paramref name="rectangle2" /> are equal; otherwise, <c>false</c>.</returns>
|
||||
public static bool operator ==(in Rectangle rectangle1, in Rectangle rectangle2) => rectangle1.Equals(rectangle2);
|
||||
public static bool operator ==(Rectangle rectangle1, Rectangle rectangle2) => rectangle1.Equals(rectangle2);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value that indicates whether two specified <see cref="Rectangle" /> are equal.
|
||||
@ -220,7 +233,7 @@ public readonly struct Rectangle
|
||||
/// <param name="rectangle1">The first <see cref="Rectangle" /> to compare.</param>
|
||||
/// <param name="rectangle2">The second <see cref="Rectangle" /> to compare.</param>
|
||||
/// <returns><c>true</c> if <paramref name="rectangle1" /> and <paramref name="rectangle2" /> are not equal; otherwise, <c>false</c>.</returns>
|
||||
public static bool operator !=(in Rectangle rectangle1, in Rectangle rectangle2) => !(rectangle1 == rectangle2);
|
||||
public static bool operator !=(Rectangle rectangle1, Rectangle rectangle2) => !(rectangle1 == rectangle2);
|
||||
|
||||
// DarthAffe 20.02.2021: Used for normalization
|
||||
/// <summary>
|
||||
@ -229,7 +242,7 @@ public readonly struct Rectangle
|
||||
/// <param name="rectangle1">The rectangle to nromalize.</param>
|
||||
/// <param name="rectangle2">The reference used for normalization.</param>
|
||||
/// <returns>A normalized rectangle.</returns>
|
||||
public static Rectangle operator /(in Rectangle rectangle1, in Rectangle rectangle2)
|
||||
public static Rectangle operator /(Rectangle rectangle1, Rectangle rectangle2)
|
||||
{
|
||||
float x = rectangle1.Location.X / (rectangle2.Size.Width - rectangle2.Location.X);
|
||||
float y = rectangle1.Location.Y / (rectangle2.Size.Height - rectangle2.Location.Y);
|
||||
|
||||
@ -10,7 +10,7 @@ namespace RGB.NET.Core;
|
||||
/// Represents an angular rotation.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("[{" + nameof(Degrees) + "}°]")]
|
||||
public readonly struct Rotation
|
||||
public readonly struct Rotation : IEquatable<Rotation>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
@ -103,7 +103,7 @@ public readonly struct Rotation
|
||||
/// <param name="rotation1">The first <see cref="Rotation" /> to compare.</param>
|
||||
/// <param name="rotation2">The second <see cref="Rotation" /> to compare.</param>
|
||||
/// <returns><c>true</c> if <paramref name="rotation1" /> and <paramref name="rotation2" /> are equal; otherwise, <c>false</c>.</returns>
|
||||
public static bool operator ==(in Rotation rotation1, in Rotation rotation2) => rotation1.Equals(rotation2);
|
||||
public static bool operator ==(Rotation rotation1, Rotation rotation2) => rotation1.Equals(rotation2);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value that indicates whether two specified <see cref="Rotation" /> are equal.
|
||||
@ -111,7 +111,7 @@ public readonly struct Rotation
|
||||
/// <param name="rotation1">The first <see cref="Rotation" /> to compare.</param>
|
||||
/// <param name="rotation2">The second <see cref="Rotation" /> to compare.</param>
|
||||
/// <returns><c>true</c> if <paramref name="rotation1" /> and <paramref name="rotation2" /> are not equal; otherwise, <c>false</c>.</returns>
|
||||
public static bool operator !=(in Rotation rotation1, in Rotation rotation2) => !(rotation1 == rotation2);
|
||||
public static bool operator !=(Rotation rotation1, Rotation rotation2) => !(rotation1 == rotation2);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Rotation"/> representing the addition of the <see cref="Rotation"/> and the provided value.
|
||||
@ -119,7 +119,7 @@ public readonly struct Rotation
|
||||
/// <param name="rotation">The <see cref="Rotation"/>.</param>
|
||||
/// <param name="value">The value to add.</param>
|
||||
/// <returns>A new <see cref="Rotation"/> representing the addition of the <see cref="Rotation"/> and the provided value.</returns>
|
||||
public static Rotation operator +(in Rotation rotation, float value) => new(rotation.Degrees + value);
|
||||
public static Rotation operator +(Rotation rotation, float value) => new(rotation.Degrees + value);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Rotation"/> representing the subtraction of the <see cref="Rotation"/> and the provided value.
|
||||
@ -127,7 +127,7 @@ public readonly struct Rotation
|
||||
/// <param name="rotation">The <see cref="Rotation"/>.</param>
|
||||
/// <param name="value">The value to substract.</param>
|
||||
/// <returns>A new <see cref="Rotation"/> representing the subtraction of the <see cref="Rotation"/> and the provided value.</returns>
|
||||
public static Rotation operator -(in Rotation rotation, float value) => new(rotation.Degrees - value);
|
||||
public static Rotation operator -(Rotation rotation, float value) => new(rotation.Degrees - value);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Rotation"/> representing the multiplication of the <see cref="Rotation"/> and the provided value.
|
||||
@ -135,7 +135,7 @@ public readonly struct Rotation
|
||||
/// <param name="rotation">The <see cref="Rotation"/>.</param>
|
||||
/// <param name="value">The value to multiply with.</param>
|
||||
/// <returns>A new <see cref="Rotation"/> representing the multiplication of the <see cref="Rotation"/> and the provided value.</returns>
|
||||
public static Rotation operator *(in Rotation rotation, float value) => new(rotation.Degrees * value);
|
||||
public static Rotation operator *(Rotation rotation, float value) => new(rotation.Degrees * value);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Rotation"/> representing the division of the <see cref="Rotation"/> and the provided value.
|
||||
@ -143,7 +143,7 @@ public readonly struct Rotation
|
||||
/// <param name="rotation">The <see cref="Rotation"/>.</param>
|
||||
/// <param name="value">The value to device with.</param>
|
||||
/// <returns>A new <see cref="Rotation"/> representing the division of the <see cref="Rotation"/> and the provided value.</returns>
|
||||
public static Rotation operator /(in Rotation rotation, float value) => value.EqualsInTolerance(0) ? new Rotation(0) : new Rotation(rotation.Degrees / value);
|
||||
public static Rotation operator /(Rotation rotation, float value) => value.EqualsInTolerance(0) ? new Rotation(0) : new Rotation(rotation.Degrees / value);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a float to a <see cref="Rotation" />.
|
||||
@ -155,7 +155,7 @@ public readonly struct Rotation
|
||||
/// Converts <see cref="Rotation" /> to a float representing the rotation in degrees.
|
||||
/// </summary>
|
||||
/// <param name="rotation">The rotatio to convert.</param>
|
||||
public static implicit operator float(in Rotation rotation) => rotation.Degrees;
|
||||
public static implicit operator float(Rotation rotation) => rotation.Degrees;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
@ -9,7 +10,7 @@ namespace RGB.NET.Core;
|
||||
/// Represents a scaling.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("[Horizontal: {Horizontal}, Vertical: {Vertical}]")]
|
||||
public readonly struct Scale
|
||||
public readonly struct Scale : IEquatable<Scale>
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
@ -49,6 +50,12 @@ public readonly struct Scale
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Horizontal"/> and <see cref="Vertical"/> value of this <see cref="Scale"/> to a human-readable string.
|
||||
/// </summary>
|
||||
/// <returns>A string that contains the <see cref="Horizontal"/> and <see cref="Vertical"/> value of this <see cref="Scale"/>. For example "[Horizontal: 1, Vertical: 0.5]".</returns>
|
||||
public override string ToString() => $"[Horizontal: {Horizontal}, Vertical: {Vertical}]\"";
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the specified <see cref="Scale"/> is equivalent to this <see cref="Scale" />.
|
||||
/// </summary>
|
||||
@ -67,7 +74,7 @@ public readonly struct Scale
|
||||
/// Returns a hash code for this <see cref="Scale" />.
|
||||
/// </summary>
|
||||
/// <returns>An integer value that specifies the hash code for this <see cref="Scale" />.</returns>
|
||||
public override int GetHashCode() { unchecked { return (Horizontal.GetHashCode() * 397) ^ Vertical.GetHashCode(); } }
|
||||
public override int GetHashCode() => HashCode.Combine(Horizontal, Vertical);
|
||||
|
||||
/// <summary>
|
||||
/// Deconstructs the scale into the horizontal and vertical value.
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
@ -9,7 +10,7 @@ namespace RGB.NET.Core;
|
||||
/// Represents a size consisting of a width and a height.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("[Width: {Width}, Height: {Height}]")]
|
||||
public readonly struct Size
|
||||
public readonly struct Size : IEquatable<Size>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
@ -67,33 +68,26 @@ public readonly struct Size
|
||||
/// <returns>A string that contains the <see cref="Width"/> and <see cref="Height"/> of this <see cref="Size"/>. For example "[Width: 100, Height: 20]".</returns>
|
||||
public override string ToString() => $"[Width: {Width}, Height: {Height}]";
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the specified <see cref="Size" /> is equivalent to this <see cref="Size" />.
|
||||
/// </summary>
|
||||
/// <param name="other">The size to test.</param>
|
||||
/// <returns><c>true</c> if <paramref name="other" /> is equivalent to this <see cref="Size" />; otherwise, <c>false</c>.</returns>
|
||||
public bool Equals(Size other) => ((float.IsNaN(Width) && float.IsNaN(other.Width)) || Width.EqualsInTolerance(other.Width))
|
||||
&& ((float.IsNaN(Height) && float.IsNaN(other.Height)) || Height.EqualsInTolerance(other.Height));
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the specified object is a <see cref="Size" /> and is equivalent to this <see cref="Size" />.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to test.</param>
|
||||
/// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Size" /> equivalent to this <see cref="Size" />; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is not Size size) return false;
|
||||
|
||||
(float width, float height) = size;
|
||||
return ((float.IsNaN(Width) && float.IsNaN(width)) || Width.EqualsInTolerance(width))
|
||||
&& ((float.IsNaN(Height) && float.IsNaN(height)) || Height.EqualsInTolerance(height));
|
||||
}
|
||||
public override bool Equals(object? obj) => obj is Size other && Equals(other);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this <see cref="Size" />.
|
||||
/// </summary>
|
||||
/// <returns>An integer value that specifies the hash code for this <see cref="Size" />.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hashCode = Width.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ Height.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
public override int GetHashCode() => HashCode.Combine(Width, Height);
|
||||
|
||||
/// <summary>
|
||||
/// Deconstructs the size into the width and height value.
|
||||
@ -116,7 +110,7 @@ public readonly struct Size
|
||||
/// <param name="size1">The first <see cref="Size" /> to compare.</param>
|
||||
/// <param name="size2">The second <see cref="Size" /> to compare.</param>
|
||||
/// <returns><c>true</c> if <paramref name="size1" /> and <paramref name="size2" /> are equal; otherwise, <c>false</c>.</returns>
|
||||
public static bool operator ==(in Size size1, in Size size2) => size1.Equals(size2);
|
||||
public static bool operator ==(Size size1, Size size2) => size1.Equals(size2);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value that indicates whether two specified <see cref="Size" /> are equal.
|
||||
@ -124,7 +118,7 @@ public readonly struct Size
|
||||
/// <param name="size1">The first <see cref="Size" /> to compare.</param>
|
||||
/// <param name="size2">The second <see cref="Size" /> to compare.</param>
|
||||
/// <returns><c>true</c> if <paramref name="size1" /> and <paramref name="size2" /> are not equal; otherwise, <c>false</c>.</returns>
|
||||
public static bool operator !=(in Size size1, in Size size2) => !(size1 == size2);
|
||||
public static bool operator !=(Size size1, Size size2) => !(size1 == size2);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Size"/> representing the addition of the two provided <see cref="Size"/>.
|
||||
@ -132,7 +126,7 @@ public readonly struct Size
|
||||
/// <param name="size1">The first <see cref="Size"/>.</param>
|
||||
/// <param name="size2">The second <see cref="Size"/>.</param>
|
||||
/// <returns>A new <see cref="Size"/> representing the addition of the two provided <see cref="Size"/>.</returns>
|
||||
public static Size operator +(in Size size1, in Size size2) => new(size1.Width + size2.Width, size1.Height + size2.Height);
|
||||
public static Size operator +(Size size1, Size size2) => new(size1.Width + size2.Width, size1.Height + size2.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Rectangle"/> created from the provided <see cref="Point"/> and <see cref="Size"/>.
|
||||
@ -140,7 +134,7 @@ public readonly struct Size
|
||||
/// <param name="size">The <see cref="Size"/> of the rectangle.</param>
|
||||
/// <param name="point">The <see cref="Point"/> of the rectangle.</param>
|
||||
/// <returns>The rectangle created from the provided <see cref="Point"/> and <see cref="Size"/>.</returns>
|
||||
public static Rectangle operator +(in Size size, in Point point) => new(point, size);
|
||||
public static Rectangle operator +(Size size, Point point) => new(point, size);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Size"/> representing the subtraction of the two provided <see cref="Size"/>.
|
||||
@ -148,7 +142,7 @@ public readonly struct Size
|
||||
/// <param name="size1">The first <see cref="Size"/>.</param>
|
||||
/// <param name="size2">The second <see cref="Size"/>.</param>
|
||||
/// <returns>A new <see cref="Size"/> representing the subtraction of the two provided <see cref="Size"/>.</returns>
|
||||
public static Size operator -(in Size size1, in Size size2) => new(size1.Width - size2.Width, size1.Height - size2.Height);
|
||||
public static Size operator -(Size size1, Size size2) => new(size1.Width - size2.Width, size1.Height - size2.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Size"/> representing the multiplication of the two provided <see cref="Size"/>.
|
||||
@ -156,7 +150,7 @@ public readonly struct Size
|
||||
/// <param name="size1">The first <see cref="Size"/>.</param>
|
||||
/// <param name="size2">The second <see cref="Size"/>.</param>
|
||||
/// <returns>A new <see cref="Size"/> representing the multiplication of the two provided <see cref="Size"/>.</returns>
|
||||
public static Size operator *(in Size size1, in Size size2) => new(size1.Width * size2.Width, size1.Height * size2.Height);
|
||||
public static Size operator *(Size size1, Size size2) => new(size1.Width * size2.Width, size1.Height * size2.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Size"/> representing the multiplication of the <see cref="Size"/> and the provided factor.
|
||||
@ -164,7 +158,7 @@ public readonly struct Size
|
||||
/// <param name="size">The <see cref="Size"/>.</param>
|
||||
/// <param name="factor">The factor by which the <see cref="Size"/> should be multiplied.</param>
|
||||
/// <returns>A new <see cref="Size"/> representing the multiplication of the <see cref="Size"/> and the provided factor.</returns>
|
||||
public static Size operator *(in Size size, float factor) => new(size.Width * factor, size.Height * factor);
|
||||
public static Size operator *(Size size, float factor) => new(size.Width * factor, size.Height * factor);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Size"/> representing the division of the two provided <see cref="Size"/>.
|
||||
@ -172,7 +166,7 @@ public readonly struct Size
|
||||
/// <param name="size1">The first <see cref="Size"/>.</param>
|
||||
/// <param name="size2">The second <see cref="Size"/>.</param>
|
||||
/// <returns>A new <see cref="Size"/> representing the division of the two provided <see cref="Size"/>.</returns>
|
||||
public static Size operator /(in Size size1, in Size size2)
|
||||
public static Size operator /(Size size1, Size size2)
|
||||
=> size2.Width.EqualsInTolerance(0) || size2.Height.EqualsInTolerance(0)
|
||||
? Invalid : new Size(size1.Width / size2.Width, size1.Height / size2.Height);
|
||||
|
||||
@ -182,7 +176,7 @@ public readonly struct Size
|
||||
/// <param name="size">The <see cref="Size"/>.</param>
|
||||
/// <param name="factor">The factor by which the <see cref="Size"/> should be divided.</param>
|
||||
/// <returns>A new <see cref="Size"/> representing the division of the <see cref="Size"/> and the provided factor.</returns>
|
||||
public static Size operator /(in Size size, float factor) => factor.EqualsInTolerance(0) ? Invalid : new Size(size.Width / factor, size.Height / factor);
|
||||
public static Size operator /(Size size, float factor) => factor.EqualsInTolerance(0) ? Invalid : new Size(size.Width / factor, size.Height / factor);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="Size"/> representing the multiplication of the <see cref="Size"/> and the specified <see cref="Scale"/>.
|
||||
@ -190,7 +184,7 @@ public readonly struct Size
|
||||
/// <param name="size">The <see cref="Size"/> to scale.</param>
|
||||
/// <param name="scale">The scaling factor.</param>
|
||||
/// <returns>A new <see cref="Size"/> representing the multiplication of the <see cref="Size"/> and the specified <see cref="Scale"/>.</returns>
|
||||
public static Size operator *(in Size size, in Scale scale) => new(size.Width * scale.Horizontal, size.Height * scale.Vertical);
|
||||
public static Size operator *(Size size, Scale scale) => new(size.Width * scale.Horizontal, size.Height * scale.Vertical);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -17,7 +17,7 @@ surface.AlignDevices();
|
||||
surface.RegisterUpdateTrigger(new TimerUpdateTrigger());
|
||||
```
|
||||
|
||||
## Basis Rendering
|
||||
## Basic Rendering
|
||||
```csharp
|
||||
// Create a led-group containing all leds on the surface
|
||||
ILedGroup allLeds = new ListLedGroup(surface, surface.Leds);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net7.0;net6.0;net5.0</TargetFrameworks>
|
||||
<TargetFrameworks>net9.0;net8.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<DefineConstants>$(DefineConstants);TRACE;DEBUG</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<Optimize>false</Optimize>
|
||||
</PropertyGroup>
|
||||
@ -49,9 +49,13 @@
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>$(NoWarn);CS1591;CS1572;CS1573</NoWarn>
|
||||
<DefineConstants>$(DefineConstants);RELEASE</DefineConstants>
|
||||
<DefineConstants>RELEASE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
||||
<Using Include="RGB.NET.Core.Compatibility.Net8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="..\Resources\icon.png" Link="icon.png" Pack="true" PackagePath="\" />
|
||||
<None Include="README.md" Pack="true" PackagePath="\" />
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=helper/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ids/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=leds/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=misc/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=mvvm/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=positioning/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=rendering/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
@ -20,9 +20,9 @@ public sealed class RGBSurface : AbstractBindable, IDisposable
|
||||
|
||||
private readonly Stopwatch _deltaTimeCounter;
|
||||
|
||||
private readonly IList<IRGBDevice> _devices = new List<IRGBDevice>();
|
||||
private readonly IList<IUpdateTrigger> _updateTriggers = new List<IUpdateTrigger>();
|
||||
private readonly List<ILedGroup> _ledGroups = new();
|
||||
private readonly IList<IRGBDevice> _devices = [];
|
||||
private readonly IList<IUpdateTrigger> _updateTriggers = [];
|
||||
private readonly List<ILedGroup> _ledGroups = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets a readonly list containing all loaded <see cref="IRGBDevice"/>.
|
||||
@ -132,11 +132,12 @@ public sealed class RGBSurface : AbstractBindable, IDisposable
|
||||
/// Perform a full update for all devices. Updates only dirty <see cref="Led"/> by default, 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>
|
||||
public void Update(bool flushLeds = false) => Update(null, new CustomUpdateData((CustomUpdateDataIndex.FLUSH_LEDS, flushLeds)));
|
||||
//public void Update(bool flushLeds = false) => Update(null, new CustomUpdateData((CustomUpdateDataIndex.FLUSH_LEDS, flushLeds)));
|
||||
public void Update(bool flushLeds = false) => Update(null, flushLeds ? DefaultCustomUpdateData.FLUSH : DefaultCustomUpdateData.NO_FLUSH);
|
||||
|
||||
private void Update(object? updateTrigger, CustomUpdateData customData) => Update(updateTrigger as IUpdateTrigger, customData);
|
||||
private void Update(object? updateTrigger, ICustomUpdateData customData) => Update(updateTrigger as IUpdateTrigger, customData);
|
||||
|
||||
private void Update(IUpdateTrigger? updateTrigger, CustomUpdateData customData)
|
||||
private void Update(IUpdateTrigger? updateTrigger, ICustomUpdateData customData)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -149,19 +150,25 @@ public sealed class RGBSurface : AbstractBindable, IDisposable
|
||||
{
|
||||
OnUpdating(updateTrigger, customData);
|
||||
|
||||
// ReSharper disable ForCanBeConvertedToForeach - 'for' has a performance benefit (no enumerator allocation) here and since 'Update' is considered a hot path it's optimized
|
||||
if (render)
|
||||
lock (_ledGroups)
|
||||
{
|
||||
// Render brushes
|
||||
foreach (ILedGroup ledGroup in _ledGroups)
|
||||
try { Render(ledGroup); }
|
||||
for (int i = 0; i < _ledGroups.Count; i++)
|
||||
{
|
||||
try { Render(_ledGroups[i]); }
|
||||
catch (Exception ex) { OnException(ex); }
|
||||
}
|
||||
}
|
||||
|
||||
if (updateDevices)
|
||||
foreach (IRGBDevice device in _devices)
|
||||
try { device.Update(flushLeds); }
|
||||
for (int i = 0; i < _devices.Count; i++)
|
||||
{
|
||||
try { _devices[i].Update(flushLeds); }
|
||||
catch (Exception ex) { OnException(ex); }
|
||||
}
|
||||
// ReSharper restore ForCanBeConvertedToForeach
|
||||
|
||||
OnUpdated();
|
||||
}
|
||||
@ -177,7 +184,7 @@ public sealed class RGBSurface : AbstractBindable, IDisposable
|
||||
{
|
||||
List<IRGBDevice> devices;
|
||||
lock (Devices)
|
||||
devices = new List<IRGBDevice>(_devices);
|
||||
devices = [.._devices];
|
||||
|
||||
foreach (IRGBDevice device in devices)
|
||||
try { Detach(device); }
|
||||
@ -197,29 +204,31 @@ public sealed class RGBSurface : AbstractBindable, IDisposable
|
||||
/// <exception cref="ArgumentException">Thrown if the <see cref="IBrush.CalculationMode"/> of the Brush is not valid.</exception>
|
||||
private void Render(ILedGroup ledGroup)
|
||||
{
|
||||
IList<Led> leds = ledGroup.ToList();
|
||||
IBrush? brush = ledGroup.Brush;
|
||||
|
||||
if ((brush == null) || !brush.IsEnabled) return;
|
||||
|
||||
IEnumerable<(RenderTarget renderTarget, Color color)> render;
|
||||
switch (brush.CalculationMode)
|
||||
using (ledGroup.ToListUnsafe(out IList<Led> leds))
|
||||
{
|
||||
case RenderMode.Relative:
|
||||
Rectangle brushRectangle = new(leds.Select(led => led.AbsoluteBoundary));
|
||||
Point offset = new(-brushRectangle.Location.X, -brushRectangle.Location.Y);
|
||||
brushRectangle = brushRectangle.SetLocation(new Point(0, 0));
|
||||
render = brush.Render(brushRectangle, leds.Select(led => new RenderTarget(led, led.AbsoluteBoundary.Translate(offset))));
|
||||
break;
|
||||
case RenderMode.Absolute:
|
||||
render = brush.Render(Boundary, leds.Select(led => new RenderTarget(led, led.AbsoluteBoundary)));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException($"The CalculationMode '{brush.CalculationMode}' is not valid.");
|
||||
}
|
||||
IEnumerable<(RenderTarget renderTarget, Color color)> render;
|
||||
switch (brush.CalculationMode)
|
||||
{
|
||||
case RenderMode.Relative:
|
||||
Rectangle brushRectangle = new(leds);
|
||||
Point offset = new(-brushRectangle.Location.X, -brushRectangle.Location.Y);
|
||||
brushRectangle = brushRectangle.SetLocation(new Point(0, 0));
|
||||
render = brush.Render(brushRectangle, leds.Select(led => new RenderTarget(led, led.AbsoluteBoundary.Translate(offset))));
|
||||
break;
|
||||
case RenderMode.Absolute:
|
||||
render = brush.Render(Boundary, leds.Select(led => new RenderTarget(led, led.AbsoluteBoundary)));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException($"The CalculationMode '{brush.CalculationMode}' is not valid.");
|
||||
}
|
||||
|
||||
foreach ((RenderTarget renderTarget, Color c) in render)
|
||||
renderTarget.Led.Color = c;
|
||||
foreach ((RenderTarget renderTarget, Color c) in render)
|
||||
renderTarget.Led.Color = c;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -358,7 +367,7 @@ public sealed class RGBSurface : AbstractBindable, IDisposable
|
||||
/// <summary>
|
||||
/// Handles the needed event-calls before updating.
|
||||
/// </summary>
|
||||
private void OnUpdating(IUpdateTrigger? trigger, CustomUpdateData customData)
|
||||
private void OnUpdating(IUpdateTrigger? trigger, ICustomUpdateData customData)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@ -69,14 +69,18 @@ public abstract class AbstractBrush : AbstractDecoratable<IBrushDecorator>, IBru
|
||||
/// <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 void ApplyDecorators(in Rectangle rectangle, in RenderTarget renderTarget, ref Color color)
|
||||
protected virtual void ApplyDecorators(Rectangle rectangle, RenderTarget renderTarget, ref Color color)
|
||||
{
|
||||
if (Decorators.Count == 0) return;
|
||||
|
||||
lock (Decorators)
|
||||
foreach (IBrushDecorator decorator in Decorators)
|
||||
// ReSharper disable once ForCanBeConvertedToForeach - Sadly this does not get optimized reliably and causes allocations if foreached
|
||||
for (int i = 0; i < Decorators.Count; i++)
|
||||
{
|
||||
IBrushDecorator decorator = Decorators[i];
|
||||
if (decorator.IsEnabled)
|
||||
decorator.ManipulateColor(rectangle, renderTarget, ref color);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -85,7 +89,7 @@ public abstract class AbstractBrush : AbstractDecoratable<IBrushDecorator>, IBru
|
||||
/// <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(in Rectangle rectangle, in RenderTarget renderTarget);
|
||||
protected abstract Color GetColorAtPoint(Rectangle rectangle, RenderTarget renderTarget);
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes the color by appliing the overall brightness and opacity.<br/>
|
||||
|
||||
@ -7,7 +7,7 @@ namespace RGB.NET.Core;
|
||||
/// <summary>
|
||||
/// Represents a brush drawing only a single color.
|
||||
/// </summary>
|
||||
public class SolidColorBrush : AbstractBrush
|
||||
public sealed class SolidColorBrush : AbstractBrush
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
@ -32,6 +32,8 @@ public class SolidColorBrush : AbstractBrush
|
||||
public SolidColorBrush(Color color)
|
||||
{
|
||||
this.Color = color;
|
||||
|
||||
CalculationMode = RenderMode.Absolute;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -39,7 +41,7 @@ public class SolidColorBrush : AbstractBrush
|
||||
#region Methods
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Color GetColorAtPoint(in Rectangle rectangle, in RenderTarget renderTarget) => Color;
|
||||
protected override Color GetColorAtPoint(Rectangle rectangle, RenderTarget renderTarget) => Color;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
/// <summary>
|
||||
/// Represents a brush drawing a texture.
|
||||
/// </summary>
|
||||
public class TextureBrush : AbstractBrush
|
||||
public sealed class TextureBrush : AbstractBrush
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
@ -36,7 +36,7 @@ public class TextureBrush : AbstractBrush
|
||||
#region Methods
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Color GetColorAtPoint(in Rectangle rectangle, in RenderTarget renderTarget)
|
||||
protected override Color GetColorAtPoint(Rectangle rectangle, RenderTarget renderTarget)
|
||||
{
|
||||
Rectangle normalizedRect = renderTarget.Rectangle / rectangle;
|
||||
return Texture[normalizedRect];
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
internal class EmptyTexture : ITexture
|
||||
internal sealed class EmptyTexture : ITexture
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public Size Size { get; } = new(0, 0);
|
||||
public Color this[in Point point] => Color.Transparent;
|
||||
public Color this[in Rectangle rectangle] => Color.Transparent;
|
||||
public Color this[Point point] => Color.Transparent;
|
||||
public Color this[Rectangle rectangle] => Color.Transparent;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -20,12 +20,12 @@ public interface ITexture
|
||||
/// </summary>
|
||||
/// <param name="point">The location to get the color from.</param>
|
||||
/// <returns>The color at the specified location.</returns>
|
||||
Color this[in Point point] { get; }
|
||||
Color this[Point point] { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sampled color inside the specified rectangle.
|
||||
/// </summary>
|
||||
/// <param name="rectangle">The rectangle to get the color from.</param>
|
||||
/// <returns>The sampled color.</returns>
|
||||
Color this[in Rectangle rectangle] { get; }
|
||||
Color this[Rectangle rectangle] { get; }
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
@ -12,16 +13,22 @@ namespace RGB.NET.Core;
|
||||
public abstract class PixelTexture<T> : ITexture
|
||||
where T : unmanaged
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const int STACK_ALLOC_LIMIT = 1024;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly int _dataPerPixel;
|
||||
private readonly int _stride;
|
||||
/// <summary>
|
||||
/// Gets the underlying pixel data.
|
||||
/// </summary>
|
||||
protected abstract ReadOnlySpan<T> Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of data-entries per pixel.
|
||||
/// </summary>
|
||||
protected int DataPerPixel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stride of the data.
|
||||
/// </summary>
|
||||
protected int Stride { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sampler used to get the color of a region.
|
||||
@ -31,13 +38,8 @@ public abstract class PixelTexture<T> : ITexture
|
||||
/// <inheritdoc />
|
||||
public Size Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the underlying pixel data.
|
||||
/// </summary>
|
||||
protected abstract ReadOnlySpan<T> Data { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Color this[in Point point]
|
||||
public virtual Color this[Point point]
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -50,7 +52,7 @@ public abstract class PixelTexture<T> : ITexture
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Color this[in Rectangle rectangle]
|
||||
public virtual Color this[Rectangle rectangle]
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -85,31 +87,12 @@ public abstract class PixelTexture<T> : ITexture
|
||||
if ((width == 0) || (height == 0)) return Color.Transparent;
|
||||
if ((width == 1) && (height == 1)) return GetColor(GetPixelData(x, y));
|
||||
|
||||
int bufferSize = width * height * _dataPerPixel;
|
||||
if (bufferSize <= STACK_ALLOC_LIMIT)
|
||||
{
|
||||
Span<T> buffer = stackalloc T[bufferSize];
|
||||
GetRegionData(x, y, width, height, buffer);
|
||||
SamplerInfo<T> samplerInfo = new(x, y, width, height, Stride, DataPerPixel, Data);
|
||||
|
||||
Span<T> pixelData = stackalloc T[_dataPerPixel];
|
||||
Sampler.Sample(new SamplerInfo<T>(width, height, buffer), pixelData);
|
||||
Span<T> pixelData = stackalloc T[DataPerPixel];
|
||||
Sampler.Sample(samplerInfo, pixelData);
|
||||
|
||||
return GetColor(pixelData);
|
||||
}
|
||||
else
|
||||
{
|
||||
T[] rent = ArrayPool<T>.Shared.Rent(bufferSize);
|
||||
|
||||
Span<T> buffer = new Span<T>(rent)[..bufferSize];
|
||||
GetRegionData(x, y, width, height, buffer);
|
||||
|
||||
Span<T> pixelData = stackalloc T[_dataPerPixel];
|
||||
Sampler.Sample(new SamplerInfo<T>(width, height, buffer), pixelData);
|
||||
|
||||
ArrayPool<T>.Shared.Return(rent);
|
||||
|
||||
return GetColor(pixelData);
|
||||
}
|
||||
return GetColor(pixelData);
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,8 +110,8 @@ public abstract class PixelTexture<T> : ITexture
|
||||
/// <param name="stride">The stride of the data or -1 if the width should be used.</param>
|
||||
public PixelTexture(int with, int height, int dataPerPixel, ISampler<T> sampler, int stride = -1)
|
||||
{
|
||||
this._stride = stride == -1 ? with : stride;
|
||||
this._dataPerPixel = dataPerPixel;
|
||||
this.Stride = stride == -1 ? with : stride;
|
||||
this.DataPerPixel = dataPerPixel;
|
||||
this.Sampler = sampler;
|
||||
|
||||
Size = new Size(with, height);
|
||||
@ -143,7 +126,7 @@ public abstract class PixelTexture<T> : ITexture
|
||||
/// </summary>
|
||||
/// <param name="pixel">The pixel-data to convert.</param>
|
||||
/// <returns>The color represented by the specified pixel-data.</returns>
|
||||
protected abstract Color GetColor(in ReadOnlySpan<T> pixel);
|
||||
protected abstract Color GetColor(ReadOnlySpan<T> pixel);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pixel-data at the specified location.
|
||||
@ -152,27 +135,7 @@ public abstract class PixelTexture<T> : ITexture
|
||||
/// <param name="y">The y-location.</param>
|
||||
/// <returns>The pixel-data on the specified location.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected virtual ReadOnlySpan<T> GetPixelData(int x, int y) => Data.Slice((y * _stride) + x, _dataPerPixel);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the pixel-data of the specified region to the passed buffer.
|
||||
/// </summary>
|
||||
/// <param name="x">The x-location of the region to get the data for.</param>
|
||||
/// <param name="y">The y-location of the region to get the data for.</param>
|
||||
/// <param name="width">The width of the region to get the data for.</param>
|
||||
/// <param name="height">The height of the region to get the data for.</param>
|
||||
/// <param name="buffer">The buffer to write the data to.</param>
|
||||
protected virtual void GetRegionData(int x, int y, int width, int height, in Span<T> buffer)
|
||||
{
|
||||
int dataWidth = width * _dataPerPixel;
|
||||
ReadOnlySpan<T> data = Data;
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
ReadOnlySpan<T> dataSlice = data.Slice((((y + i) * _stride) + x) * _dataPerPixel, dataWidth);
|
||||
Span<T> destination = buffer.Slice(i * dataWidth, dataWidth);
|
||||
dataSlice.CopyTo(destination);
|
||||
}
|
||||
}
|
||||
private ReadOnlySpan<T> GetPixelData(int x, int y) => Data.Slice((y * Stride) + x, DataPerPixel);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -225,7 +188,8 @@ public sealed class PixelTexture : PixelTexture<Color>
|
||||
#region Methods
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Color GetColor(in ReadOnlySpan<Color> pixel) => pixel[0];
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override Color GetColor(ReadOnlySpan<Color> pixel) => pixel[0];
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
@ -10,7 +9,7 @@ namespace RGB.NET.Core;
|
||||
/// <remarks>
|
||||
/// Averages all components (A, R, G, B) of the colors separately which isn't ideal in cases where multiple different colors are combined.
|
||||
/// </remarks>
|
||||
public class AverageColorSampler : ISampler<Color>
|
||||
public sealed class AverageColorSampler : ISampler<Color>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
@ -23,27 +22,42 @@ public class AverageColorSampler : ISampler<Color>
|
||||
#region Methods
|
||||
|
||||
/// <inheritdoc />
|
||||
public unsafe void Sample(in SamplerInfo<Color> info, in Span<Color> pixelData)
|
||||
public unsafe void Sample(SamplerInfo<Color> info, Span<Color> pixelData)
|
||||
{
|
||||
int count = info.Width * info.Height;
|
||||
if (count == 0) return;
|
||||
|
||||
float a = 0, r = 0, g = 0, b = 0;
|
||||
|
||||
if (Vector.IsHardwareAccelerated && (info.Data.Length >= Vector<float>.Count))
|
||||
if (Vector.IsHardwareAccelerated && (info.Height > 1) && (info.Width >= ELEMENTS_PER_VECTOR))
|
||||
{
|
||||
int chunks = info.Data.Length / ELEMENTS_PER_VECTOR;
|
||||
int missingElements = info.Data.Length - (chunks * ELEMENTS_PER_VECTOR);
|
||||
int chunks = info.Width / ELEMENTS_PER_VECTOR;
|
||||
int missingElements = info.Width - (chunks * ELEMENTS_PER_VECTOR);
|
||||
|
||||
Vector<float> sum = Vector<float>.Zero;
|
||||
|
||||
fixed (Color* colorPtr = &MemoryMarshal.GetReference(info.Data))
|
||||
for (int y = 0; y < info.Height; y++)
|
||||
{
|
||||
Color* current = colorPtr;
|
||||
for (int i = 0; i < chunks; i++)
|
||||
ReadOnlySpan<Color> data = info[y];
|
||||
|
||||
fixed (Color* colorPtr = data)
|
||||
{
|
||||
sum = Vector.Add(sum, *(Vector<float>*)current);
|
||||
current += ELEMENTS_PER_VECTOR;
|
||||
Color* current = colorPtr;
|
||||
for (int i = 0; i < chunks; i++)
|
||||
{
|
||||
sum = Vector.Add(sum, *(Vector<float>*)current);
|
||||
current += ELEMENTS_PER_VECTOR;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < missingElements; i++)
|
||||
{
|
||||
Color color = data[^(i + 1)];
|
||||
|
||||
a += color.A;
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,26 +68,17 @@ public class AverageColorSampler : ISampler<Color>
|
||||
g += sum[i + 2];
|
||||
b += sum[i + 3];
|
||||
}
|
||||
|
||||
for (int i = 0; i < missingElements; i++)
|
||||
{
|
||||
Color color = info.Data[^(i + 1)];
|
||||
|
||||
a += color.A;
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Color color in info.Data)
|
||||
{
|
||||
a += color.A;
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
}
|
||||
for (int y = 0; y < info.Height; y++)
|
||||
foreach (Color color in info[y])
|
||||
{
|
||||
a += color.A;
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
}
|
||||
}
|
||||
|
||||
pixelData[0] = new Color(a / count, r / count, g / count, b / count);
|
||||
|
||||
@ -13,5 +13,5 @@ public interface ISampler<T>
|
||||
/// </summary>
|
||||
/// <param name="info">The information containing the data to sample.</param>
|
||||
/// <param name="pixelData">The buffer used to write the resulting pixel to.</param>
|
||||
void Sample(in SamplerInfo<T> info, in Span<T> pixelData);
|
||||
void Sample(SamplerInfo<T> info, Span<T> pixelData);
|
||||
}
|
||||
@ -10,20 +10,29 @@ public readonly ref struct SamplerInfo<T>
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly ReadOnlySpan<T> _data;
|
||||
private readonly int _x;
|
||||
private readonly int _y;
|
||||
private readonly int _stride;
|
||||
private readonly int _dataPerPixel;
|
||||
private readonly int _dataWidth;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the width of the region the data comes from.
|
||||
/// </summary>
|
||||
public int Width { get; }
|
||||
public readonly int Width;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height of region the data comes from.
|
||||
/// </summary>
|
||||
public int Height { get; }
|
||||
public readonly int Height;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data to sample.
|
||||
/// Gets the data for the requested row.
|
||||
/// </summary>
|
||||
public ReadOnlySpan<T> Data { get; }
|
||||
/// <param name="row">The row to get the data for.</param>
|
||||
/// <returns>A readonly span containing the data of the row.</returns>
|
||||
public ReadOnlySpan<T> this[int row] => _data.Slice((((_y + row) * _stride) + _x) * _dataPerPixel, _dataWidth);
|
||||
|
||||
#endregion
|
||||
|
||||
@ -35,11 +44,17 @@ public readonly ref struct SamplerInfo<T>
|
||||
/// <param name="width">The width of the region the data comes from.</param>
|
||||
/// <param name="height">The height of region the data comes from.</param>
|
||||
/// <param name="data">The data to sample.</param>
|
||||
public SamplerInfo(int width, int height, ReadOnlySpan<T> data)
|
||||
public SamplerInfo(int x, int y, int width, int height, int stride, int dataPerPixel, ReadOnlySpan<T> data)
|
||||
{
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._data = data;
|
||||
this._stride = stride;
|
||||
this._dataPerPixel = dataPerPixel;
|
||||
this.Width = width;
|
||||
this.Height = height;
|
||||
this.Data = data;
|
||||
|
||||
_dataWidth = width * dataPerPixel;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -29,13 +29,13 @@ public abstract class AbstractUpdateTrigger : AbstractBindable, IUpdateTrigger
|
||||
/// Invokes the <see cref="Starting"/>-event.
|
||||
/// </summary>
|
||||
/// <param name="updateData">Optional custom-data passed to the subscribers of the <see cref="Starting"/>.event.</param>
|
||||
protected virtual void OnStartup(CustomUpdateData? updateData = null) => Starting?.Invoke(this, updateData ?? new CustomUpdateData());
|
||||
protected virtual void OnStartup(CustomUpdateData? updateData = null) => Starting?.Invoke(this, updateData ?? CustomUpdateData.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the <see cref="Update"/>-event.
|
||||
/// </summary>
|
||||
/// <param name="updateData">Optional custom-data passed to the subscribers of the <see cref="Update"/>.event.</param>
|
||||
protected virtual void OnUpdate(CustomUpdateData? updateData = null) => Update?.Invoke(this, updateData ?? new CustomUpdateData());
|
||||
protected virtual void OnUpdate(CustomUpdateData? updateData = null) => Update?.Invoke(this, updateData ?? CustomUpdateData.Empty);
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract void Start();
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
@ -34,11 +35,27 @@ public static class CustomUpdateDataIndex
|
||||
/// <summary>
|
||||
/// Represents a set of custom data, each indexed by a string-key.
|
||||
/// </summary>
|
||||
public class CustomUpdateData
|
||||
public interface ICustomUpdateData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the value for a specific key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the value.</param>
|
||||
/// <returns>The value represented by the specified key.</returns>
|
||||
object? this[string key] { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a set of custom data, each indexed by a string-key.
|
||||
/// </summary>
|
||||
public sealed class CustomUpdateData : ICustomUpdateData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private Dictionary<string, object?> _data = new();
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static readonly CustomUpdateData Empty = new();
|
||||
|
||||
private readonly Dictionary<string, object?> _data = [];
|
||||
|
||||
#endregion
|
||||
|
||||
@ -51,8 +68,8 @@ public class CustomUpdateData
|
||||
/// <returns>The value represented by the specified key.</returns>
|
||||
public object? this[string key]
|
||||
{
|
||||
get => _data.TryGetValue(key.ToUpperInvariant(), out object? data) ? data : default;
|
||||
set => _data[key.ToUpperInvariant()] = value;
|
||||
get => _data.GetValueOrDefault(key);
|
||||
set => _data[key] = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -77,3 +94,39 @@ public class CustomUpdateData
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal sealed class DefaultCustomUpdateData : ICustomUpdateData
|
||||
{
|
||||
#region Constants
|
||||
|
||||
public static readonly DefaultCustomUpdateData FLUSH = new(true);
|
||||
public static readonly DefaultCustomUpdateData NO_FLUSH = new(false);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly bool _flushLeds;
|
||||
|
||||
public object? this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.Equals(key, CustomUpdateDataIndex.FLUSH_LEDS, StringComparison.Ordinal))
|
||||
return _flushLeds;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
private DefaultCustomUpdateData(bool flushLeds)
|
||||
{
|
||||
this._flushLeds = flushLeds;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -132,7 +133,7 @@ public class DeviceUpdateTrigger : AbstractUpdateTrigger, IDeviceUpdateTrigger
|
||||
/// <summary>
|
||||
/// Stops the trigger.
|
||||
/// </summary>
|
||||
public async void Stop()
|
||||
public virtual async void Stop()
|
||||
{
|
||||
if (!IsRunning) return;
|
||||
|
||||
@ -140,7 +141,9 @@ public class DeviceUpdateTrigger : AbstractUpdateTrigger, IDeviceUpdateTrigger
|
||||
|
||||
UpdateTokenSource?.Cancel();
|
||||
if (UpdateTask != null)
|
||||
await UpdateTask;
|
||||
try { await UpdateTask.ConfigureAwait(false); }
|
||||
catch (TaskCanceledException) { }
|
||||
catch (OperationCanceledException) { }
|
||||
|
||||
UpdateTask?.Dispose();
|
||||
UpdateTask = null;
|
||||
@ -156,11 +159,13 @@ public class DeviceUpdateTrigger : AbstractUpdateTrigger, IDeviceUpdateTrigger
|
||||
using (TimerHelper.RequestHighResolutionTimer())
|
||||
while (!UpdateToken.IsCancellationRequested)
|
||||
if (HasDataEvent.WaitOne(Timeout))
|
||||
LastUpdateTime = TimerHelper.Execute(() => OnUpdate(), UpdateFrequency * 1000);
|
||||
LastUpdateTime = TimerHelper.Execute(TimerExecute, UpdateFrequency * 1000);
|
||||
else if ((HeartbeatTimer > 0) && (LastUpdateTimestamp > 0) && (TimerHelper.GetElapsedTime(LastUpdateTimestamp) > HeartbeatTimer))
|
||||
OnUpdate(new CustomUpdateData().Heartbeat());
|
||||
}
|
||||
|
||||
private void TimerExecute() => OnUpdate();
|
||||
|
||||
protected override void OnUpdate(CustomUpdateData? updateData = null)
|
||||
{
|
||||
base.OnUpdate(updateData);
|
||||
@ -178,7 +183,12 @@ public class DeviceUpdateTrigger : AbstractUpdateTrigger, IDeviceUpdateTrigger
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose() => Stop();
|
||||
public override void Dispose()
|
||||
{
|
||||
Stop();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
@ -8,15 +7,20 @@ namespace RGB.NET.Core;
|
||||
/// </summary>
|
||||
/// <typeparam name="TIdentifier">The identifier used to identify the data processed by this queue.</typeparam>
|
||||
/// <typeparam name="TData">The type of the data processed by this queue.</typeparam>
|
||||
public interface IUpdateQueue<TIdentifier, TData> : IDisposable
|
||||
public interface IUpdateQueue<TIdentifier, TData> : IReferenceCounting, IDisposable
|
||||
where TIdentifier : notnull
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a bool indicating if the queue requires a flush of all data due to an internal error.
|
||||
/// </summary>
|
||||
bool RequiresFlush { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets or merges the provided data set in the current dataset and notifies the trigger that there is new data available.
|
||||
/// </summary>
|
||||
/// <param name="dataSet">The set of data.</param>
|
||||
// ReSharper disable once MemberCanBeProtected.Global
|
||||
void SetData(IEnumerable<(TIdentifier, TData)> dataSet);
|
||||
void SetData(ReadOnlySpan<(TIdentifier, TData)> dataSet);
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current data set.
|
||||
@ -27,5 +31,4 @@ public interface IUpdateQueue<TIdentifier, TData> : IDisposable
|
||||
/// <summary>
|
||||
/// Represents a generic update queue processing <see cref="Color"/>-data using <see cref="object"/>-identifiers.
|
||||
/// </summary>
|
||||
public interface IUpdateQueue : IUpdateQueue<object, Color>
|
||||
{ }
|
||||
public interface IUpdateQueue : IUpdateQueue<object, Color>;
|
||||
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace RGB.NET.Core;
|
||||
|
||||
@ -10,14 +10,17 @@ namespace RGB.NET.Core;
|
||||
/// </summary>
|
||||
/// <typeparam name="TIdentifier">The type of the key used to identify some data.</typeparam>
|
||||
/// <typeparam name="TData">The type of the data.</typeparam>
|
||||
public abstract class UpdateQueue<TIdentifier, TData> : IUpdateQueue<TIdentifier, TData>
|
||||
public abstract class UpdateQueue<TIdentifier, TData> : AbstractReferenceCounting, IUpdateQueue<TIdentifier, TData>
|
||||
where TIdentifier : notnull
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly object _dataLock = new();
|
||||
private readonly Lock _dataLock = new();
|
||||
private readonly IDeviceUpdateTrigger _updateTrigger;
|
||||
private readonly Dictionary<TIdentifier, TData> _currentDataSet = new();
|
||||
private readonly Dictionary<TIdentifier, TData> _currentDataSet = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool RequiresFlush { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@ -62,7 +65,7 @@ public abstract class UpdateQueue<TIdentifier, TData> : IUpdateQueue<TIdentifier
|
||||
_currentDataSet.Clear();
|
||||
}
|
||||
|
||||
Update(data);
|
||||
RequiresFlush = !Update(data);
|
||||
|
||||
ArrayPool<(TIdentifier, TData)>.Shared.Return(dataSet);
|
||||
}
|
||||
@ -78,17 +81,16 @@ public abstract class UpdateQueue<TIdentifier, TData> : IUpdateQueue<TIdentifier
|
||||
/// Performs the update this queue is responsible for.
|
||||
/// </summary>
|
||||
/// <param name="dataSet">The set of data that needs to be updated.</param>
|
||||
protected abstract void Update(in ReadOnlySpan<(TIdentifier key, TData color)> dataSet);
|
||||
protected abstract bool Update(ReadOnlySpan<(TIdentifier key, TData color)> dataSet);
|
||||
|
||||
/// <summary>
|
||||
/// Sets or merges the provided data set in the current dataset and notifies the trigger that there is new data available.
|
||||
/// </summary>
|
||||
/// <param name="dataSet">The set of data.</param>
|
||||
// ReSharper disable once MemberCanBeProtected.Global
|
||||
public virtual void SetData(IEnumerable<(TIdentifier, TData)> dataSet)
|
||||
public virtual void SetData(ReadOnlySpan<(TIdentifier, TData)> data)
|
||||
{
|
||||
IList<(TIdentifier, TData)> data = dataSet.ToList();
|
||||
if (data.Count == 0) return;
|
||||
if (data.Length == 0) return;
|
||||
|
||||
lock (_dataLock)
|
||||
{
|
||||
|
||||
@ -83,12 +83,12 @@ public sealed class ManualUpdateTrigger : AbstractUpdateTrigger
|
||||
OnStartup();
|
||||
|
||||
while (!UpdateToken.IsCancellationRequested)
|
||||
{
|
||||
if (_mutex.WaitOne(100))
|
||||
LastUpdateTime = TimerHelper.Execute(() => OnUpdate(_customUpdateData));
|
||||
}
|
||||
LastUpdateTime = TimerHelper.Execute(TimerExecute);
|
||||
}
|
||||
|
||||
private void TimerExecute() => OnUpdate(_customUpdateData);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose() => Stop();
|
||||
|
||||
|
||||
@ -10,28 +10,28 @@ namespace RGB.NET.Core;
|
||||
/// <summary>
|
||||
/// Represents an update trigger that triggers in a set interval.
|
||||
/// </summary>
|
||||
public class TimerUpdateTrigger : AbstractUpdateTrigger
|
||||
public sealed class TimerUpdateTrigger : AbstractUpdateTrigger
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly object _lock = new();
|
||||
private readonly Lock _lock = new();
|
||||
|
||||
private readonly CustomUpdateData? _customUpdateData;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the update loop of this trigger.
|
||||
/// </summary>
|
||||
protected Task? UpdateTask { get; set; }
|
||||
private Task? _updateTask;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the cancellation token source used to create the cancellation token checked by the <see cref="UpdateTask"/>.
|
||||
/// Gets or sets the cancellation token source used to create the cancellation token checked by the <see cref="_updateTask"/>.
|
||||
/// </summary>
|
||||
protected CancellationTokenSource? UpdateTokenSource { get; set; }
|
||||
private CancellationTokenSource? _updateTokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the cancellation token checked by the <see cref="UpdateTask"/>.
|
||||
/// Gets or sets the cancellation token checked by the <see cref="_updateTask"/>.
|
||||
/// </summary>
|
||||
protected CancellationToken UpdateToken { get; set; }
|
||||
private CancellationToken _updateToken;
|
||||
|
||||
private double _updateFrequency = 1.0 / 30.0;
|
||||
/// <summary>
|
||||
@ -88,11 +88,11 @@ public class TimerUpdateTrigger : AbstractUpdateTrigger
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (UpdateTask == null)
|
||||
if (_updateTask == null)
|
||||
{
|
||||
UpdateTokenSource?.Dispose();
|
||||
UpdateTokenSource = new CancellationTokenSource();
|
||||
UpdateTask = Task.Factory.StartNew(UpdateLoop, (UpdateToken = UpdateTokenSource.Token), TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||
_updateTokenSource?.Dispose();
|
||||
_updateTokenSource = new CancellationTokenSource();
|
||||
_updateTask = Task.Factory.StartNew(UpdateLoop, (_updateToken = _updateTokenSource.Token), TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,13 +104,13 @@ public class TimerUpdateTrigger : AbstractUpdateTrigger
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (UpdateTask != null)
|
||||
if (_updateTask != null)
|
||||
{
|
||||
UpdateTokenSource?.Cancel();
|
||||
_updateTokenSource?.Cancel();
|
||||
try
|
||||
{
|
||||
// ReSharper disable once MethodSupportsCancellation
|
||||
UpdateTask.Wait();
|
||||
_updateTask.Wait();
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
@ -118,8 +118,8 @@ public class TimerUpdateTrigger : AbstractUpdateTrigger
|
||||
}
|
||||
finally
|
||||
{
|
||||
UpdateTask.Dispose();
|
||||
UpdateTask = null;
|
||||
_updateTask.Dispose();
|
||||
_updateTask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,16 +130,16 @@ public class TimerUpdateTrigger : AbstractUpdateTrigger
|
||||
OnStartup();
|
||||
|
||||
using (TimerHelper.RequestHighResolutionTimer())
|
||||
while (!UpdateToken.IsCancellationRequested)
|
||||
LastUpdateTime = TimerHelper.Execute(() => OnUpdate(_customUpdateData), UpdateFrequency * 1000);
|
||||
|
||||
while (!_updateToken.IsCancellationRequested)
|
||||
LastUpdateTime = TimerHelper.Execute(TimerExecute, UpdateFrequency * 1000);
|
||||
}
|
||||
|
||||
private void TimerExecute() => OnUpdate(_customUpdateData);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose()
|
||||
{
|
||||
Stop();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using AuraServiceLib;
|
||||
using RGB.NET.Core;
|
||||
|
||||
@ -12,15 +13,25 @@ namespace RGB.NET.Devices.Asus;
|
||||
/// <summary>
|
||||
/// Represents a device provider responsible for Cooler Master devices.
|
||||
/// </summary>
|
||||
public class AsusDeviceProvider : AbstractRGBDeviceProvider
|
||||
public sealed class AsusDeviceProvider : AbstractRGBDeviceProvider
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static readonly Lock _lock = new();
|
||||
|
||||
private static AsusDeviceProvider? _instance;
|
||||
/// <summary>
|
||||
/// Gets the singleton <see cref="AsusDeviceProvider"/> instance.
|
||||
/// </summary>
|
||||
public static AsusDeviceProvider Instance => _instance ?? new AsusDeviceProvider();
|
||||
public static AsusDeviceProvider Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
return _instance ?? new AsusDeviceProvider();
|
||||
}
|
||||
}
|
||||
|
||||
private IAuraSdk2? _sdk;
|
||||
private IAuraSyncDeviceCollection? _devices; //HACK DarthAffe 05.04.2021: Due to some researches this might fix the access violation in the asus-sdk
|
||||
@ -35,8 +46,11 @@ public class AsusDeviceProvider : AbstractRGBDeviceProvider
|
||||
/// <exception cref="InvalidOperationException">Thrown if this constructor is called even if there is already an instance of this class.</exception>
|
||||
public AsusDeviceProvider()
|
||||
{
|
||||
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(AsusDeviceProvider)}");
|
||||
_instance = this;
|
||||
lock (_lock)
|
||||
{
|
||||
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(AsusDeviceProvider)}");
|
||||
_instance = this;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -60,34 +74,39 @@ public class AsusDeviceProvider : AbstractRGBDeviceProvider
|
||||
for (int i = 0; i < _devices.Count; i++)
|
||||
{
|
||||
IAuraSyncDevice device = _devices[i];
|
||||
|
||||
yield return (AsusDeviceType)device.Type switch
|
||||
{
|
||||
AsusDeviceType.MB_RGB => new AsusMainboardRGBDevice(new AsusRGBDeviceInfo(RGBDeviceType.Mainboard, device, WMIHelper.GetMainboardInfo()?.model ?? device.Name), GetUpdateTrigger()),
|
||||
AsusDeviceType.MB_RGB => new AsusMainboardRGBDevice(new AsusRGBDeviceInfo(RGBDeviceType.Mainboard, device, "Asus Motherboard"), GetUpdateTrigger()),
|
||||
AsusDeviceType.MB_ADDRESABLE => new AsusUnspecifiedRGBDevice(new AsusRGBDeviceInfo(RGBDeviceType.LedStripe, device), LedId.LedStripe1, GetUpdateTrigger()),
|
||||
AsusDeviceType.VGA_RGB => new AsusGraphicsCardRGBDevice(new AsusRGBDeviceInfo(RGBDeviceType.GraphicsCard, device), GetUpdateTrigger()),
|
||||
AsusDeviceType.HEADSET_RGB => new AsusHeadsetRGBDevice(new AsusRGBDeviceInfo(RGBDeviceType.Headset, device), GetUpdateTrigger()),
|
||||
AsusDeviceType.DRAM_RGB => new AsusDramRGBDevice(new AsusRGBDeviceInfo(RGBDeviceType.DRAM, device), GetUpdateTrigger()),
|
||||
AsusDeviceType.KEYBOARD_RGB => new AsusKeyboardRGBDevice(new AsusKeyboardRGBDeviceInfo(device), LedMappings.KeyboardMapping, GetUpdateTrigger()),
|
||||
AsusDeviceType.KEYBOARD_5ZONE_RGB => new AsusKeyboardRGBDevice(new AsusKeyboardRGBDeviceInfo(device), null, GetUpdateTrigger()),
|
||||
AsusDeviceType.NB_KB_RGB => new AsusKeyboardRGBDevice(new AsusKeyboardRGBDeviceInfo(device), LedMappings.KeyboardMapping, GetUpdateTrigger()),
|
||||
AsusDeviceType.NB_KB_4ZONE_RGB => new AsusKeyboardRGBDevice(new AsusKeyboardRGBDeviceInfo(device), null, GetUpdateTrigger()),
|
||||
AsusDeviceType.MOUSE_RGB => new AsusMouseRGBDevice(new AsusRGBDeviceInfo(RGBDeviceType.Mouse, device), GetUpdateTrigger()),
|
||||
_ => new AsusUnspecifiedRGBDevice(new AsusRGBDeviceInfo(RGBDeviceType.Unknown, device), LedId.Custom1, GetUpdateTrigger())
|
||||
AsusDeviceType.TERMINAL_RGB => new AsusUnspecifiedRGBDevice(new AsusRGBDeviceInfo(RGBDeviceType.LedController, device), LedId.Custom1, GetUpdateTrigger()),
|
||||
_ => new AsusUnspecifiedRGBDevice(new AsusRGBDeviceInfo(RGBDeviceType.Unknown, device), LedId.Unknown1, GetUpdateTrigger())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose()
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose();
|
||||
lock (_lock)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
try { _sdk?.ReleaseControl(0); }
|
||||
catch { /* at least we tried */ }
|
||||
try { _sdk?.ReleaseControl(0); }
|
||||
catch { /* at least we tried */ }
|
||||
|
||||
_devices = null;
|
||||
_sdk = null;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
_devices = null;
|
||||
_sdk = null;
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -16,9 +16,12 @@ internal enum AsusDeviceType : uint
|
||||
EXTERNAL_BLUE_RAY_RGB = 0x61000,
|
||||
DRAM_RGB = 0x70000,
|
||||
KEYBOARD_RGB = 0x80000,
|
||||
KEYBOARD_5ZONE_RGB = 0x80001,
|
||||
NB_KB_RGB = 0x81000,
|
||||
NB_KB_4ZONE_RGB = 0x81001,
|
||||
MOUSE_RGB = 0x90000,
|
||||
CHASSIS_RGB = 0xB0000,
|
||||
PROJECTOR_RGB = 0xC0000
|
||||
PROJECTOR_RGB = 0xC0000,
|
||||
WATERCOOLER_RGB = 0xD1000,
|
||||
TERMINAL_RGB = 0xE0000
|
||||
}
|
||||
@ -4,9 +4,9 @@ namespace RGB.NET.Devices.Asus;
|
||||
|
||||
/// <inheritdoc cref="AsusRGBDevice{TDeviceInfo}" />
|
||||
/// <summary>
|
||||
/// Represents a Asus headset.
|
||||
/// Represents a Asus device that is otherwise not handled by a more specific helper.
|
||||
/// </summary>
|
||||
public class AsusUnspecifiedRGBDevice : AsusRGBDevice<AsusRGBDeviceInfo>, IUnknownDevice
|
||||
public sealed class AsusUnspecifiedRGBDevice : AsusRGBDevice<AsusRGBDeviceInfo>, IUnknownDevice
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
@ -18,9 +18,9 @@ public class AsusUnspecifiedRGBDevice : AsusRGBDevice<AsusRGBDeviceInfo>, IUnkno
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Devices.Asus.AsusHeadsetRGBDevice" /> class.
|
||||
/// Initializes a new instance of the <see cref="T:RGB.NET.Devices.Asus.AsusUnspecifiedRGBDevice" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The specific information provided by Asus for the headset.</param>
|
||||
/// <param name="info">The specific information provided by Asus for the device.</param>
|
||||
/// <param name="baseLedId">The ledId of the first led of this device. All other leds are created by incrementing this base-id by 1.</param>
|
||||
/// <param name="updateTrigger">The update trigger used to update this device.</param>
|
||||
internal AsusUnspecifiedRGBDevice(AsusRGBDeviceInfo info, LedId baseLedId, IDeviceUpdateTrigger updateTrigger)
|
||||
|
||||
@ -8,7 +8,7 @@ namespace RGB.NET.Devices.Asus;
|
||||
/// <summary>
|
||||
/// Represents the update-queue performing updates for asus devices.
|
||||
/// </summary>
|
||||
public class AsusUpdateQueue : UpdateQueue
|
||||
public sealed class AsusUpdateQueue : UpdateQueue
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
@ -17,7 +17,7 @@ public class AsusUpdateQueue : UpdateQueue
|
||||
/// <summary>
|
||||
/// The device to be updated.
|
||||
/// </summary>
|
||||
protected IAuraSyncDevice Device { get; }
|
||||
private readonly IAuraSyncDevice _device;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -31,7 +31,7 @@ public class AsusUpdateQueue : UpdateQueue
|
||||
public AsusUpdateQueue(IDeviceUpdateTrigger updateTrigger, IAuraSyncDevice device)
|
||||
: base(updateTrigger)
|
||||
{
|
||||
this.Device = device;
|
||||
this._device = device;
|
||||
|
||||
this._lights = new IAuraRgbLight[device.Lights.Count];
|
||||
for (int i = 0; i < device.Lights.Count; i++)
|
||||
@ -43,14 +43,14 @@ public class AsusUpdateQueue : UpdateQueue
|
||||
#region Methods
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Update(in ReadOnlySpan<(object key, Color color)> dataSet)
|
||||
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ((Device.Type == (uint)AsusDeviceType.KEYBOARD_RGB) || (Device.Type == (uint)AsusDeviceType.NB_KB_RGB))
|
||||
if ((_device.Type == (uint)AsusDeviceType.KEYBOARD_RGB) || (_device.Type == (uint)AsusDeviceType.NB_KB_RGB))
|
||||
{
|
||||
if (Device is not IAuraSyncKeyboard keyboard)
|
||||
return;
|
||||
if (_device is not IAuraSyncKeyboard keyboard)
|
||||
return true;
|
||||
|
||||
foreach ((object customData, Color value) in dataSet)
|
||||
{
|
||||
@ -87,12 +87,17 @@ public class AsusUpdateQueue : UpdateQueue
|
||||
}
|
||||
}
|
||||
|
||||
Device.Apply();
|
||||
}
|
||||
catch
|
||||
{ /* "The server threw an exception." seems to be a thing here ... */
|
||||
}
|
||||
}
|
||||
_device.Apply();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AsusDeviceProvider.Instance.Throw(ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -5,5 +5,4 @@ namespace RGB.NET.Devices.Asus;
|
||||
/// <summary>
|
||||
/// Represents a asus RGB-device.
|
||||
/// </summary>
|
||||
public interface IAsusRGBDevice : IRGBDevice
|
||||
{ }
|
||||
public interface IAsusRGBDevice : IRGBDevice;
|
||||
@ -6,7 +6,7 @@ namespace RGB.NET.Devices.Asus;
|
||||
/// <summary>
|
||||
/// Represents a Asus graphicsCard.
|
||||
/// </summary>
|
||||
public class AsusGraphicsCardRGBDevice : AsusRGBDevice<AsusRGBDeviceInfo>, IGraphicsCard
|
||||
public sealed class AsusGraphicsCardRGBDevice : AsusRGBDevice<AsusRGBDeviceInfo>, IGraphicsCard
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ namespace RGB.NET.Devices.Asus;
|
||||
/// <summary>
|
||||
/// Represents a Asus headset.
|
||||
/// </summary>
|
||||
public class AsusHeadsetRGBDevice : AsusRGBDevice<AsusRGBDeviceInfo>, IHeadset
|
||||
public sealed class AsusHeadsetRGBDevice : AsusRGBDevice<AsusRGBDeviceInfo>, IHeadset
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
using System;
|
||||
using System.Management;
|
||||
|
||||
namespace RGB.NET.Devices.Asus;
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
internal static class WMIHelper
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
private static readonly ManagementObjectSearcher? _systemModelSearcher;
|
||||
private static readonly ManagementObjectSearcher? _mainboardSearcher;
|
||||
private static readonly ManagementObjectSearcher? _graphicsCardSearcher;
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
private static string? _systemModelInfo;
|
||||
private static (string manufacturer, string model)? _mainboardInfo;
|
||||
private static string? _graphicsCardInfo;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static WMIHelper()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
_systemModelSearcher = new ManagementObjectSearcher(@"root\CIMV2", "SELECT Model FROM Win32_ComputerSystem");
|
||||
_mainboardSearcher = new ManagementObjectSearcher(@"root\CIMV2", "SELECT Manufacturer,Product FROM Win32_BaseBoard");
|
||||
_graphicsCardSearcher = new ManagementObjectSearcher(@"root\CIMV2", "SELECT Name FROM Win32_VideoController");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
internal static string? GetSystemModelInfo()
|
||||
{
|
||||
if (!OperatingSystem.IsWindows()) return null;
|
||||
|
||||
if ((_systemModelInfo == null) && (_systemModelSearcher != null))
|
||||
foreach (ManagementBaseObject managementBaseObject in _systemModelSearcher.Get())
|
||||
{
|
||||
_systemModelInfo = managementBaseObject["Model"]?.ToString();
|
||||
break;
|
||||
}
|
||||
|
||||
return _systemModelInfo;
|
||||
}
|
||||
|
||||
internal static (string manufacturer, string model)? GetMainboardInfo()
|
||||
{
|
||||
if (!OperatingSystem.IsWindows()) return null;
|
||||
|
||||
if (!_mainboardInfo.HasValue && (_mainboardSearcher != null))
|
||||
foreach (ManagementBaseObject managementBaseObject in _mainboardSearcher.Get())
|
||||
{
|
||||
_mainboardInfo = (managementBaseObject["Manufacturer"]?.ToString() ?? string.Empty, managementBaseObject["Product"]?.ToString() ?? string.Empty);
|
||||
break;
|
||||
}
|
||||
|
||||
return _mainboardInfo;
|
||||
}
|
||||
|
||||
internal static string? GetGraphicsCardsInfo()
|
||||
{
|
||||
if (!OperatingSystem.IsWindows()) return null;
|
||||
|
||||
if ((_graphicsCardInfo == null) && (_graphicsCardSearcher != null))
|
||||
foreach (ManagementBaseObject managementBaseObject in _graphicsCardSearcher.Get())
|
||||
{
|
||||
_graphicsCardInfo = managementBaseObject["Name"]?.ToString();
|
||||
break;
|
||||
}
|
||||
|
||||
return _graphicsCardInfo;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -188,4 +188,49 @@ public static class LedMappings
|
||||
{ LedId.Keyboard_Custom59, 131 },
|
||||
{ LedId.Keyboard_Custom60, 133 },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A LED mapping containing extra lights for the ROG Strix G15 (2021)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// ASUS notebooks have extra lights under wide keys like space and backspace, these do not appear as keys on the device.
|
||||
/// Instead they only appear in the Lights enumerable, this mapping maps the matching keys to the index of these lights.
|
||||
/// There are also some keys which do not use the default key scan code mappings for LEDs, and instead rely on lights.
|
||||
/// </para>
|
||||
/// <para>You may add more of these by further populating <see cref="AsusKeyboardRGBDevice.ExtraLedMappings"/>.</para>
|
||||
/// </remarks>
|
||||
public static LedMapping<int> ROGStrixG15 { get; } = new()
|
||||
{
|
||||
{ LedId.Keyboard_Custom71, 4 }, //Mic Mute
|
||||
{ LedId.Keyboard_Custom72, 5 }, //Fan
|
||||
{ LedId.Keyboard_Custom73, 6 }, //ROG Logo
|
||||
//{ LedId.Keyboard_Function, 127 }, //commented out because adding a mapping fails if a mapping already exists for a key, even if it is incorrect for this device
|
||||
//use Keyboard_Custom36 in the default mapping to get the Fn key on this laptop
|
||||
|
||||
{ LedId.Keyboard_Custom52, 55 }, //backspace extra LEDs (x2) - these are named to match the appropriate LEDs in the previous ROG Zephyrus mapping
|
||||
{ LedId.Keyboard_Custom53, 57 },
|
||||
{ LedId.Keyboard_Custom54, 97 }, //enter extra LEDs (x2)
|
||||
{ LedId.Keyboard_Custom55, 99 },
|
||||
{ LedId.Keyboard_Custom56, 118 }, //right shift extra LEDs (x2)
|
||||
{ LedId.Keyboard_Custom57, 120 },
|
||||
{ LedId.Keyboard_Custom58, 130 }, //space bar extra LEDs (x3)
|
||||
{ LedId.Keyboard_Custom59, 131 }, //this one specifically is also exposed as Custom7 (AsusLedID.KEY_NOCONVERT) in the main map
|
||||
{ LedId.Keyboard_Custom60, 133 },
|
||||
|
||||
{ LedId.Keyboard_MediaVolumeDown, 2 },
|
||||
{ LedId.Keyboard_MediaVolumeUp, 3 },
|
||||
{ LedId.Keyboard_MediaPlay, 58 },
|
||||
{ LedId.Keyboard_MediaStop, 79 },
|
||||
{ LedId.Keyboard_MediaPreviousTrack, 100 },
|
||||
{ LedId.Keyboard_MediaNextTrack, 121 },
|
||||
|
||||
{ LedId.LedStripe1, 174 }, //front LED strip; yes, these are in reverse order, since the SDK exposes them from right to left
|
||||
{ LedId.LedStripe2, 173 },
|
||||
{ LedId.LedStripe3, 172 },
|
||||
{ LedId.LedStripe4, 171 },
|
||||
{ LedId.LedStripe5, 170 },
|
||||
{ LedId.LedStripe6, 169 },
|
||||
|
||||
};
|
||||
}
|
||||
@ -20,13 +20,13 @@ public record AsusKeyboardExtraMapping(Regex Regex, LedMapping<int> LedMapping);
|
||||
/// <summary>
|
||||
/// Represents a Asus keyboard.
|
||||
/// </summary>
|
||||
public class AsusKeyboardRGBDevice : AsusRGBDevice<AsusKeyboardRGBDeviceInfo>, IKeyboard
|
||||
public sealed class AsusKeyboardRGBDevice : AsusRGBDevice<AsusKeyboardRGBDeviceInfo>, IKeyboard
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly LedMapping<AsusLedId>? _ledMapping;
|
||||
private readonly Dictionary<LedId, AsusLedId> _ledAsusLed = new();
|
||||
private readonly Dictionary<LedId, int> _ledAsusLights = new();
|
||||
private readonly Dictionary<LedId, AsusLedId> _ledAsusLed = [];
|
||||
private readonly Dictionary<LedId, int> _ledAsusLights = [];
|
||||
|
||||
IKeyboardDeviceInfo IKeyboard.DeviceInfo => DeviceInfo;
|
||||
|
||||
@ -35,10 +35,11 @@ public class AsusKeyboardRGBDevice : AsusRGBDevice<AsusKeyboardRGBDeviceInfo>, I
|
||||
/// <para>Note: These LED mappings should be based on light indexes.</para>
|
||||
/// </summary>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static readonly List<AsusKeyboardExtraMapping> ExtraLedMappings = new()
|
||||
{
|
||||
new AsusKeyboardExtraMapping(new Regex("(ROG Zephyrus Duo 15).*?"), LedMappings.ROGZephyrusDuo15)
|
||||
};
|
||||
public static readonly List<AsusKeyboardExtraMapping> ExtraLedMappings =
|
||||
[
|
||||
new(new Regex("(ROG Zephyrus Duo 15).*?"), LedMappings.ROGZephyrusDuo15),
|
||||
new(new Regex("(ROG Strix G513QM).*?"), LedMappings.ROGStrixG15)
|
||||
];
|
||||
|
||||
#endregion
|
||||
|
||||
@ -65,7 +66,7 @@ public class AsusKeyboardRGBDevice : AsusRGBDevice<AsusKeyboardRGBDeviceInfo>, I
|
||||
|
||||
private void InitializeLayout()
|
||||
{
|
||||
if (DeviceInfo.Device.Type != (uint)AsusDeviceType.NB_KB_4ZONE_RGB)
|
||||
if ((DeviceInfo.Device.Type != (uint)AsusDeviceType.NB_KB_4ZONE_RGB) && (DeviceInfo.Device.Type !=(uint)AsusDeviceType.KEYBOARD_5ZONE_RGB))
|
||||
{
|
||||
int pos = 0;
|
||||
int unknownLed = (int)LedId.Unknown1;
|
||||
|
||||
@ -7,15 +7,14 @@ namespace RGB.NET.Devices.Asus;
|
||||
/// <summary>
|
||||
/// Represents a generic information for a <see cref="T:RGB.NET.Devices.Asus.AsusKeyboardRGBDevice" />.
|
||||
/// </summary>
|
||||
public class AsusKeyboardRGBDeviceInfo : AsusRGBDeviceInfo, IKeyboardDeviceInfo
|
||||
public sealed class AsusKeyboardRGBDeviceInfo : AsusRGBDeviceInfo, IKeyboardDeviceInfo
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
/// <summary>
|
||||
/// The ASUS SDK returns useless names for notebook keyboards, possibly for others as well.
|
||||
/// Keep a list of those and rely on <see cref="WMIHelper.GetSystemModelInfo()"/> to get the real model
|
||||
/// </summary>
|
||||
private static readonly List<string> GENERIC_DEVICE_NAMES = new() { "NotebookKeyboard" };
|
||||
private static readonly List<string> GENERIC_DEVICE_NAMES = ["NotebookKeyboard"];
|
||||
|
||||
/// <inheritdoc />
|
||||
public KeyboardLayoutType Layout => KeyboardLayoutType.Unknown;
|
||||
@ -37,7 +36,7 @@ public class AsusKeyboardRGBDeviceInfo : AsusRGBDeviceInfo, IKeyboardDeviceInfo
|
||||
|
||||
#region Methods
|
||||
|
||||
private static string? GetKeyboardModel(string deviceName) => GENERIC_DEVICE_NAMES.Contains(deviceName) ? WMIHelper.GetSystemModelInfo() : deviceName;
|
||||
private static string GetKeyboardModel(string deviceName) => GENERIC_DEVICE_NAMES.Contains(deviceName) ? "Asus Keyboard" : deviceName;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -6,7 +6,7 @@ namespace RGB.NET.Devices.Asus;
|
||||
/// <summary>
|
||||
/// Represents a Asus mainboard.
|
||||
/// </summary>
|
||||
public class AsusMainboardRGBDevice : AsusRGBDevice<AsusRGBDeviceInfo>, IMainboard
|
||||
public sealed class AsusMainboardRGBDevice : AsusRGBDevice<AsusRGBDeviceInfo>, IMainboard
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ namespace RGB.NET.Devices.Asus;
|
||||
/// <summary>
|
||||
/// Represents a Asus mouse.
|
||||
/// </summary>
|
||||
public class AsusMouseRGBDevice : AsusRGBDevice<AsusRGBDeviceInfo>, IMouse
|
||||
public sealed class AsusMouseRGBDevice : AsusRGBDevice<AsusRGBDeviceInfo>, IMouse
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net7.0;net6.0;net5.0</TargetFrameworks>
|
||||
<TargetFrameworks>net9.0;net8.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<DefineConstants>$(DefineConstants);TRACE;DEBUG</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<Optimize>false</Optimize>
|
||||
</PropertyGroup>
|
||||
@ -48,32 +48,18 @@
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>$(NoWarn);CS1591;CS1572;CS1573</NoWarn>
|
||||
<DefineConstants>$(DefineConstants);RELEASE</DefineConstants>
|
||||
<DefineConstants>RELEASE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
||||
<Using Include="RGB.NET.Core.Compatibility.Net8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="..\Resources\icon.png" Link="icon.png" Pack="true" PackagePath="\" />
|
||||
<None Include="README.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Management" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<_PackageFiles Include="$(OutputPath)\net6.0\Interop.AuraServiceLib.dll">
|
||||
<BuildAction>None</BuildAction>
|
||||
<PackagePath>lib\net6.0\</PackagePath>
|
||||
</_PackageFiles>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<_PackageFiles Include="$(OutputPath)\net5.0\Interop.AuraServiceLib.dll">
|
||||
<BuildAction>None</BuildAction>
|
||||
<PackagePath>lib\net5.0\</PackagePath>
|
||||
</_PackageFiles>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RGB.NET.Core\RGB.NET.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@ -8,7 +8,7 @@ namespace RGB.NET.Devices.CoolerMaster;
|
||||
/// Specifies the <see cref="T:RGB.NET.Core.RGBDeviceType" /> of a field.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class DeviceTypeAttribute : Attribute
|
||||
public sealed class DeviceTypeAttribute : Attribute
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
|
||||
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