Skip to content

Commit 4e2e14b

Browse files
committed
Moved AccentAnalyzer color properties into ColorPalette children
1 parent 5438e4d commit 4e2e14b

File tree

7 files changed

+272
-149
lines changed

7 files changed

+272
-149
lines changed

components/ColorAnalyzer/samples/AccentAnalyzerSample.xaml

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
1+
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
22
<Page x:Class="ColorAnalyzerExperiment.Samples.AccentAnalyzerSample"
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -12,7 +12,11 @@
1212

1313
<Page.Resources>
1414
<helpers:AccentAnalyzer x:Name="AccentAnalyzer"
15-
Source="{x:Bind AccentedImage}" />
15+
Source="{x:Bind AccentedImage}">
16+
<helpers:AccentPalette x:Name="AccentPalette" />
17+
<helpers:ProminencePalette x:Name="ProminencePalette" />
18+
<helpers:BasePalette x:Name="BasePalette" />
19+
</helpers:AccentAnalyzer>
1620
</Page.Resources>
1721

1822
<Grid>
@@ -60,7 +64,7 @@
6064
Margin="4"
6165
Padding="2">
6266
<Border.Background>
63-
<SolidColorBrush Color="{x:Bind AccentAnalyzer.DominantColor, Mode=OneWay}" />
67+
<SolidColorBrush Color="{x:Bind ProminencePalette.Primary, Mode=OneWay}" />
6468
</Border.Background>
6569
<TextBlock Foreground="Black"
6670
Text="Dominant" />
@@ -72,7 +76,7 @@
7276
Margin="4"
7377
Padding="2">
7478
<Border.Background>
75-
<SolidColorBrush Color="{x:Bind AccentAnalyzer.BaseColor, Mode=OneWay}" />
79+
<SolidColorBrush Color="{x:Bind BasePalette.Base, Mode=OneWay}" />
7680
</Border.Background>
7781
<TextBlock Foreground="Black"
7882
Text="Base" />
@@ -84,7 +88,7 @@
8488
Margin="4"
8589
Padding="2">
8690
<Border.Background>
87-
<SolidColorBrush Color="{x:Bind AccentAnalyzer.PrimaryAccentColor, Mode=OneWay}" />
91+
<SolidColorBrush Color="{x:Bind AccentPalette.Primary, Mode=OneWay}" />
8892
</Border.Background>
8993
<TextBlock Foreground="Black"
9094
Text="Primary" />
@@ -95,7 +99,7 @@
9599
Margin="4"
96100
Padding="2">
97101
<Border.Background>
98-
<SolidColorBrush Color="{x:Bind AccentAnalyzer.SecondaryAccentColor, Mode=OneWay}" />
102+
<SolidColorBrush Color="{x:Bind AccentPalette.Secondary, Mode=OneWay}" />
99103
</Border.Background>
100104
<TextBlock Foreground="Black"
101105
Text="Secondary" />
@@ -106,7 +110,7 @@
106110
Margin="4"
107111
Padding="2">
108112
<Border.Background>
109-
<SolidColorBrush Color="{x:Bind AccentAnalyzer.TertiaryAccentColor, Mode=OneWay}" />
113+
<SolidColorBrush Color="{x:Bind AccentPalette.Tertiary, Mode=OneWay}" />
110114
</Border.Background>
111115
<TextBlock Foreground="Black"
112116
Text="Tertiary" />
@@ -119,9 +123,9 @@
119123
<Rectangle.Fill>
120124
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
121125
<GradientStopCollection>
122-
<GradientStop Offset="0" Color="{x:Bind AccentAnalyzer.PrimaryAccentColor, Mode=OneWay}" />
123-
<GradientStop Offset="0.74" Color="{x:Bind AccentAnalyzer.SecondaryAccentColor, Mode=OneWay}" />
124-
<GradientStop Offset="1" Color="{x:Bind AccentAnalyzer.TertiaryAccentColor, Mode=OneWay}" />
126+
<GradientStop Offset="0" Color="{x:Bind AccentPalette.Primary, Mode=OneWay}" />
127+
<GradientStop Offset="0.74" Color="{x:Bind AccentPalette.Secondary, Mode=OneWay}" />
128+
<GradientStop Offset="1" Color="{x:Bind AccentPalette.Tertiary, Mode=OneWay}" />
125129
</GradientStopCollection>
126130
</LinearGradientBrush>
127131
</Rectangle.Fill>

components/ColorAnalyzer/src/AccentAnalyzer.Properties.cs

Lines changed: 3 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using System.Windows.Input;
65
using Windows.UI;
76

87
namespace CommunityToolkit.WinUI.Helpers;
@@ -15,36 +14,6 @@ public partial class AccentAnalyzer
1514
public static readonly DependencyProperty SourceProperty =
1615
DependencyProperty.Register(nameof(Source), typeof(UIElement), typeof(AccentAnalyzer), new PropertyMetadata(null, OnSourceChanged));
1716

18-
/// <summary>
19-
/// Gets the <see cref="DependencyProperty"/> for the <see cref="PrimaryAccentColor"/> property.
20-
/// </summary>
21-
public static readonly DependencyProperty PrimaryAccentColorProperty =
22-
DependencyProperty.Register(nameof(PrimaryAccentColor), typeof(Color), typeof(AccentAnalyzer), new PropertyMetadata(Colors.Transparent));
23-
24-
/// <summary>
25-
/// Gets the <see cref="DependencyProperty"/> for the <see cref="SecondaryAccentColor"/> property.
26-
/// </summary>
27-
public static readonly DependencyProperty SecondaryAccentColorProperty =
28-
DependencyProperty.Register(nameof(SecondaryAccentColor), typeof(Color), typeof(AccentAnalyzer), new PropertyMetadata(Colors.Transparent));
29-
30-
/// <summary>
31-
/// Gets the <see cref="DependencyProperty"/> for the <see cref="TertiaryAccentColor"/> property.
32-
/// </summary>
33-
public static readonly DependencyProperty TertiaryAccentColorProperty =
34-
DependencyProperty.Register(nameof(TertiaryAccentColor), typeof(Color), typeof(AccentAnalyzer), new PropertyMetadata(Colors.Transparent));
35-
36-
/// <summary>
37-
/// Gets the <see cref="DependencyProperty"/> for the <see cref="BaseColor"/> property.
38-
/// </summary>
39-
public static readonly DependencyProperty BaseColorProperty =
40-
DependencyProperty.Register(nameof(BaseColor), typeof(Color), typeof(AccentAnalyzer), new PropertyMetadata(Colors.Transparent));
41-
42-
/// <summary>
43-
/// Gets the <see cref="DependencyProperty"/> for the <see cref="DominantColor"/> property.
44-
/// </summary>
45-
public static readonly DependencyProperty DominantColorProperty =
46-
DependencyProperty.Register(nameof(DominantColor), typeof(Color), typeof(AccentAnalyzer), new PropertyMetadata(Colors.Transparent));
47-
4817
/// <summary>
4918
/// Gets the <see cref="DependencyProperty"/> for the <see cref="Colorfulness"/> property.
5019
/// </summary>
@@ -54,7 +23,7 @@ public partial class AccentAnalyzer
5423
/// <summary>
5524
/// An event fired when the accent properties are updated.
5625
/// </summary>
57-
public event EventHandler? AccentsUpdated;
26+
public event EventHandler? PalettesUpdated;
5827

5928
/// <summary>
6029
/// Gets or sets the <see cref="UIElement"/> source for accent color analysis.
@@ -66,64 +35,9 @@ public UIElement? Source
6635
}
6736

6837
/// <summary>
69-
/// Gets the primary accent color as extracted from the <see cref="Source"/>.
70-
/// </summary>
71-
/// <remarks>
72-
/// The most "colorful" found in the image.
73-
/// </remarks>
74-
public Color PrimaryAccentColor
75-
{
76-
get => (Color)GetValue(PrimaryAccentColorProperty);
77-
protected set => SetValue(PrimaryAccentColorProperty, value);
78-
}
79-
80-
/// <summary>
81-
/// Gets the secondary accent color as extracted from the <see cref="Source"/>.
82-
/// </summary>
83-
/// <remarks>
84-
/// The second most "colorful" color found in the image.
85-
/// </remarks>
86-
public Color SecondaryAccentColor
87-
{
88-
get => (Color)GetValue(SecondaryAccentColorProperty);
89-
protected set => SetValue(SecondaryAccentColorProperty, value);
90-
}
91-
92-
/// <summary>
93-
/// Gets the tertiary accent color as extracted from the <see cref="Source"/>.
94-
/// </summary>
95-
/// <remarks>
96-
/// The third most "colorful" color found in the image.
97-
/// </remarks>
98-
public Color TertiaryAccentColor
99-
{
100-
get => (Color)GetValue(TertiaryAccentColorProperty);
101-
protected set => SetValue(TertiaryAccentColorProperty, value);
102-
}
103-
104-
/// <summary>
105-
/// Gets the base color as extracted from the <see cref="Source"/>.
38+
/// The list of <see cref="ColorPalette"/> to update when the <see cref="Source"/> is set or changed.
10639
/// </summary>
107-
/// <remarks>
108-
/// The least "colorful" color found in the image.
109-
/// </remarks>
110-
public Color BaseColor
111-
{
112-
get => (Color)GetValue(BaseColorProperty);
113-
protected set => SetValue(BaseColorProperty, value);
114-
}
115-
116-
/// <summary>
117-
/// Gets the dominant color as extracted from the <see cref="Source"/>.
118-
/// </summary>
119-
/// <remarks>
120-
/// The color that takes up the most of the image.
121-
/// </remarks>
122-
public Color DominantColor
123-
{
124-
get => (Color)GetValue(DominantColorProperty);
125-
protected set => SetValue(DominantColorProperty, value);
126-
}
40+
public IList<ColorPalette> Palettes { get; set; }
12741

12842
/// <summary>
12943
/// Gets the "colorfulness" of the <see cref="Source"/>.

components/ColorAnalyzer/src/AccentAnalyzer.cs

Lines changed: 16 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ namespace CommunityToolkit.WinUI.Helpers;
1919
/// <summary>
2020
/// A resource that can be used to extract color palettes out of any UIElement.
2121
/// </summary>
22+
[ContentProperty(Name = nameof(Palettes))]
2223
public partial class AccentAnalyzer : DependencyObject
2324
{
2425
/// <summary>
2526
/// Initialize an instance of the <see cref="AccentAnalyzer"/> class.
2627
/// </summary>
2728
public AccentAnalyzer()
2829
{
30+
Palettes = [];
2931
}
3032

3133
/// <summary>
@@ -38,6 +40,11 @@ public void UpdateAccent()
3840

3941
private async Task UpdateAccentAsync()
4042
{
43+
// No palettes to update.
44+
// Skip a lot of unnecessary computation
45+
if (Palettes.Count is 0)
46+
return;
47+
4148
const int sampleCount = 4096;
4249
const int k = 8;
4350

@@ -59,8 +66,14 @@ private async Task UpdateAccentAsync()
5966
// TODO: Should this be weighted by cluster sizes?
6067
var overallColorfulness = FindColorfulness(clusters);
6168

62-
// Select accent colors
63-
SelectAccentColors(colorData, overallColorfulness);
69+
// Update palettes on the UI thread
70+
foreach (var palette in Palettes)
71+
{
72+
DispatcherQueue.GetForCurrentThread().TryEnqueue(() =>
73+
{
74+
palette.SelectColors(colorData, overallColorfulness);
75+
});
76+
}
6477

6578
// Update accent colors property
6679
// Not a dependency property, so no need to update from the UI Thread
@@ -75,54 +88,7 @@ private async Task UpdateAccentAsync()
7588
DispatcherQueue.GetForCurrentThread().TryEnqueue(() =>
7689
{
7790
Colorfulness = overallColorfulness;
78-
AccentsUpdated?.Invoke(this, EventArgs.Empty);
79-
});
80-
}
81-
82-
/// <summary>
83-
/// This method takes the processed color information and selects the accent colors from it.
84-
/// </summary>
85-
/// <remarks>
86-
/// There is no guarentee that this method will be called from the UI Thread.
87-
/// Dependency properties should be updated using a dispatcher.
88-
/// </remarks>
89-
/// <param name="colorData">The analyzed accent color info from the image.</param>
90-
/// <param name="imageColorfulness">The overall colorfulness of the image.</param>
91-
protected virtual void SelectAccentColors(IEnumerable<AccentColorInfo> colorData, float imageColorfulness)
92-
{
93-
// Select accent colors
94-
var accentColors = colorData
95-
.OrderByDescending(x => x.Colorfulness)
96-
.Select(x => x.Color);
97-
98-
// Get primary/secondary/tertiary accents
99-
var primary = accentColors.First();
100-
var secondary = accentColors.ElementAtOrDefault(1);
101-
secondary = secondary != default ? secondary : primary;
102-
var tertiary = accentColors.ElementAtOrDefault(2);
103-
tertiary = tertiary != default ? tertiary : secondary;
104-
105-
// Get base color
106-
var baseColor = accentColors.Last();
107-
108-
// Get dominant color by prominence
109-
#if NET6_0_OR_GREATER
110-
var dominantColor = colorData
111-
.MaxBy(x => x.Prominence).Color;
112-
#else
113-
var dominantColor = colorData
114-
.OrderByDescending((x) => x.Prominence)
115-
.First().Color;
116-
#endif
117-
118-
// Batch update the dependency properties in the UI Thread
119-
DispatcherQueue.GetForCurrentThread().TryEnqueue(() =>
120-
{
121-
PrimaryAccentColor = primary;
122-
SecondaryAccentColor = secondary;
123-
TertiaryAccentColor = tertiary;
124-
BaseColor = baseColor;
125-
DominantColor = dominantColor;
91+
PalettesUpdated?.Invoke(this, EventArgs.Empty);
12692
});
12793
}
12894

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
6+
using Windows.UI;
7+
8+
namespace CommunityToolkit.WinUI.Helpers;
9+
10+
/// <summary>
11+
/// A <see cref="ColorPalette"/> based on the three most "colorful" colors.
12+
/// </summary>
13+
public class AccentPalette : ColorPalette
14+
{
15+
/// <summary>
16+
/// Gets the <see cref="DependencyProperty"/> for the <see cref="Primary"/> property.
17+
/// </summary>
18+
public static readonly DependencyProperty PrimaryProperty =
19+
DependencyProperty.Register(nameof(Primary), typeof(Color), typeof(AccentPalette), new PropertyMetadata(Colors.Transparent));
20+
21+
/// <summary>
22+
/// Gets the <see cref="DependencyProperty"/> for the <see cref="Secondary"/> property.
23+
/// </summary>
24+
public static readonly DependencyProperty SecondaryProperty =
25+
DependencyProperty.Register(nameof(Secondary), typeof(Color), typeof(AccentPalette), new PropertyMetadata(Colors.Transparent));
26+
27+
/// <summary>
28+
/// Gets the <see cref="DependencyProperty"/> for the <see cref="Tertiary"/> property.
29+
/// </summary>
30+
public static readonly DependencyProperty TertiaryProperty =
31+
DependencyProperty.Register(nameof(Tertiary), typeof(Color), typeof(AccentPalette), new PropertyMetadata(Colors.Transparent));
32+
33+
/// <summary>
34+
/// Gets the primary accent color.
35+
/// </summary>
36+
/// <remarks>
37+
/// The most "colorful" found in the palette.
38+
/// </remarks>
39+
public Color Primary
40+
{
41+
get => (Color)GetValue(PrimaryProperty);
42+
protected set => SetValue(PrimaryProperty, value);
43+
}
44+
45+
/// <summary>
46+
/// Gets the secondary accent color.
47+
/// </summary>
48+
/// <remarks>
49+
/// The second most "colorful" color found in the palette.
50+
/// </remarks>
51+
public Color Secondary
52+
{
53+
get => (Color)GetValue(SecondaryProperty);
54+
protected set => SetValue(SecondaryProperty, value);
55+
}
56+
57+
/// <summary>
58+
/// Gets the tertiary accent color.
59+
/// </summary>
60+
/// <remarks>
61+
/// The third most "colorful" color found in the palette.
62+
/// </remarks>
63+
public Color Tertiary
64+
{
65+
get => (Color)GetValue(TertiaryProperty);
66+
protected set => SetValue(TertiaryProperty, value);
67+
}
68+
69+
/// <inheritdoc/>
70+
public override void SelectColors(IEnumerable<AccentColorInfo> colors, float imageColorfulness)
71+
{
72+
// Select accent colors
73+
var accentColors = colors
74+
.OrderByDescending(x => x.Colorfulness)
75+
.Select(x => x.Color);
76+
77+
// Get primary/secondary/tertiary accents
78+
var primary = accentColors.First();
79+
var secondary = accentColors.ElementAtOrDefault(1);
80+
secondary = secondary != default ? secondary : primary;
81+
var tertiary = accentColors.ElementAtOrDefault(2);
82+
tertiary = tertiary != default ? tertiary : secondary;
83+
84+
// Update DPs
85+
Primary = primary;
86+
Secondary = secondary;
87+
Tertiary = tertiary;
88+
}
89+
}

0 commit comments

Comments
 (0)