forked from CommunityToolkit/Lottie-Windows
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPaletteColorPicker.xaml.cs
202 lines (177 loc) · 7.77 KB
/
PaletteColorPicker.xaml.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// 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.
#nullable enable
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Numerics;
using CommunityToolkit.WinUI.Lottie.CompMetadata;
using CommunityToolkit.WinUI.Lottie.WinCompData.MetaData;
using LottieViewer.ViewModel;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
namespace LottieViewer
{
/// <summary>
/// Displays a color picker for multiple colors in a palette.
/// </summary>
public sealed partial class PaletteColorPicker : UserControl
{
LottieVisualDiagnosticsViewModel? _diagnosticsViewModel;
// Used to prevent infinite recursion when the color picker is updated.
// Needed because we have 2-way binding between 2 color pickers and they
// try to set each others values.
bool m_isColorPickerChanging = false;
internal CheckBox ShowSolidBackground => _showSolidBackground;
public PaletteColorPicker()
{
this.InitializeComponent();
PaletteEntries.CollectionChanged += PaletteEntries_CollectionChanged;
}
internal LottieVisualDiagnosticsViewModel? DiagnosticsViewModel
{
get => _diagnosticsViewModel;
set
{
if (value is null)
{
return;
}
if (_diagnosticsViewModel is not null)
{
// Unhook form the previous DiagnosticsViewModel.
value.ThemePropertyBindings.CollectionChanged -= Value_CollectionChanged;
}
_diagnosticsViewModel = value;
if (_diagnosticsViewModel is not null)
{
value.ThemePropertyBindings.CollectionChanged += Value_CollectionChanged;
}
}
}
public ObservableCollection<ColorPaletteEntry> PaletteEntries { get; } = new ObservableCollection<ColorPaletteEntry>();
void PaletteEntries_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
// These are the only cases we expect becasue of the way we modify the collection.
case NotifyCollectionChangedAction.Add:
case NotifyCollectionChangedAction.Remove:
break;
// These are never expected because of the way we modify the collection.
case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Reset:
default:
throw new InvalidOperationException();
}
// Ensure something is selected if there are any items in the list.
if ((_listBox.SelectedIndex == -1 || _listBox.SelectedIndex >= PaletteEntries.Count)
&& PaletteEntries.Count > 0)
{
_listBox.SelectedIndex = PaletteEntries.Count - 1;
}
}
void Value_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
// Add the entry to the list, and hook it up so that changing the entry will update
// the entry in the theming property set.
foreach (PropertyBinding item in e.NewItems)
{
if (item.ExposedType == PropertySetValueType.Color)
{
var color = (CommunityToolkit.WinUI.Lottie.WinCompData.Wui.Color)item.DefaultValue;
var entry = new ColorPaletteEntry(Color.FromArgb(color.A, color.R, color.G, color.B), item.DisplayName);
PaletteEntries.Add(entry);
entry.PropertyChanged += (_, args) =>
{
var newColor = entry.Color;
_diagnosticsViewModel?.ThemingPropertySet?.InsertVector4(item.BindingName, ColorAsVector4(entry.Color));
};
}
}
break;
case NotifyCollectionChangedAction.Reset:
// Remove all except the first item in PaletteEntries (first item is Background).
while (PaletteEntries.Count > 1)
{
PaletteEntries.Remove(PaletteEntries[PaletteEntries.Count - 1]);
}
break;
// These are all unexpected. Don't try to handle them.
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Remove:
case NotifyCollectionChangedAction.Move:
default:
throw new InvalidOperationException();
}
}
// Synchronizes the color picker's color with the selected item in the list.
void PaletteListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_listBox.SelectedItem is ColorPaletteEntry selectedEntry)
{
MyColorPicker.Color = selectedEntry.Color;
MyColorPicker.IsEnabled = true;
}
else
{
MyColorPicker.Color = Color.FromArgb(0, 0, 0, 0);
MyColorPicker.IsEnabled = false;
}
}
void MyColorPicker_ColorChanged(ColorPicker sender, ColorChangedEventArgs args)
{
if (m_isColorPickerChanging)
{
// Ignore if we're in the middle of changing the color already.
return;
}
if (_listBox.SelectedItem is ColorPaletteEntry selectedEntry)
{
m_isColorPickerChanging = true;
selectedEntry.Color = args.NewColor;
TextColorPicker.Color = args.NewColor;
m_isColorPickerChanging = false;
}
}
void TextColorPicker_ColorChanged(ColorPicker sender, ColorChangedEventArgs args)
{
// Update the main color picker.
MyColorPicker.Color = args.NewColor;
}
// Handle double-click on an entry. Restore the original color.
void PaletteListBox_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
if (GetDataContext((DependencyObject)e.OriginalSource) is ColorPaletteEntry colorPaletteEntry)
{
// Reset the color to the original color.
colorPaletteEntry.Color = colorPaletteEntry.InitialColor;
MyColorPicker.Color = colorPaletteEntry.Color;
}
// Search up the tree for an object with a data context, and returns
// the data context.
static object? GetDataContext(DependencyObject obj)
{
if (obj is FrameworkElement fe && fe.DataContext is not null)
{
return fe.DataContext;
}
else
{
return obj is null ? null : GetDataContext(VisualTreeHelper.GetParent(obj));
}
}
}
// Converts a color to the Vector4 representation used in a CompositionPropertySet for
// color binding.
static Vector4 ColorAsVector4(Color color) => new Vector4(color.R, color.G, color.B, color.A);
}
}