-
Notifications
You must be signed in to change notification settings - Fork 1
/
ColorVariable.cs
225 lines (198 loc) · 7.13 KB
/
ColorVariable.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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
namespace AntTweakBar
{
public sealed class ColorValidationEventArgs : EventArgs
{
/// <summary>
/// Whether to accept this RGB color value.
/// </summary>
public bool Valid { get; set; }
public float R { get; private set; }
public float G { get; private set; }
public float B { get; private set; }
public ColorValidationEventArgs(float r, float g, float b)
{
R = r;
G = g;
B = b;
}
}
/// <summary>
/// An AntTweakBar variable which can hold an RGB color value.
/// </summary>
public sealed class ColorVariable : Variable, IValueVariable
{
/// <summary>
/// Occurs when the user changes this variable's value.
/// </summary>
public event EventHandler Changed;
/// <summary>
/// Occurs when the new value of this variable is validated.
/// </summary>
public event EventHandler<ColorValidationEventArgs> Validating;
/// <summary>
/// Raises the Changed event.
/// </summary>
public void OnChanged(EventArgs e)
{
ThrowIfDisposed();
if (Changed != null) {
Changed(this, e);
}
}
/// <summary>
/// Gets or sets this color's red channel component.
/// </summary>
public float R
{
get { ThrowIfDisposed(); return r; }
set { ValidateAndSet(value, G, B); }
}
/// <summary>
/// Gets or sets this color's green channel component.
/// </summary>
public float G
{
get { ThrowIfDisposed(); return g; }
set { ValidateAndSet(R, value, B); }
}
/// <summary>
/// Gets or sets this color's blue channel component.
/// </summary>
public float B
{
get { ThrowIfDisposed(); return b; }
set { ValidateAndSet(R, G, value); }
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private float r;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private float g;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private float b;
/// <summary>
/// Initialization delegate, which creates the RGB color variable.
/// </summary>
private static void InitColorVariable(Variable var, String id)
{
var it = var as ColorVariable;
Variable.SetCallbacks.Add(id, new Tw.SetVarCallback(it.SetCallback));
Variable.GetCallbacks.Add(id, new Tw.GetVarCallback(it.GetCallback));
Tw.AddVarCB(var.ParentBar.Pointer, id,
Tw.VariableType.Color3F,
Variable.SetCallbacks[id],
Variable.GetCallbacks[id],
IntPtr.Zero, null);
}
/// <summary>
/// Creates a new RGB color variable in a given bar.
/// </summary>
/// <param name="bar">The bar to create the RGB color variable in.</param>
/// <param name="r">The initial red channel value of the variable.</param>
/// <param name="g">The initial green channel value of the variable.</param>
/// <param name="b">The initial blue channel value of the variable.</param>
/// <param name="def">An optional definition string for the new variable.</param>
public ColorVariable(Bar bar, float r = 0, float g = 0, float b = 0, String def = null)
: base(bar, InitColorVariable, def)
{
Validating += (s, e) => { e.Valid = (0 <= e.R) && (e.R <= 1); };
Validating += (s, e) => { e.Valid = (0 <= e.G) && (e.G <= 1); };
Validating += (s, e) => { e.Valid = (0 <= e.B) && (e.B <= 1); };
ValidateAndSet(r, g, b);
}
/// <summary>
/// Checks if this variable can hold this value.
/// </summary>
private bool IsValid(float r, float g, float b)
{
ThrowIfDisposed();
return !Validating.GetInvocationList().Select(h => {
var check = new ColorValidationEventArgs(r, g, b);
h.DynamicInvoke(new object[] { this, check });
return !check.Valid;
}).Any(failed => failed);
}
/// <summary>
/// Tries to set this variable's value, validating it.
/// </summary>
private void ValidateAndSet(float r, float g, float b)
{
if (!IsValid(r, g, b)) {
throw new ArgumentException("Invalid variable value.");
} else {
this.r = r;
this.g = g;
this.b = b;
}
}
/// <summary>
/// Called by AntTweakBar when the user changes the variable's value.
/// </summary>
private void SetCallback(IntPtr pointer, IntPtr clientData)
{
float[] data = new float[3]; /* R, G, B */
Marshal.Copy(pointer, data, 0, data.Length);
if (IsValid(data[0], data[1], data[2]))
{
bool changed = (data[0] != r)
|| (data[1] != g)
|| (data[2] != b);
r = data[0];
g = data[1];
b = data[2];
if (changed) {
OnChanged(EventArgs.Empty);
}
}
}
/// <summary>
/// Called by AntTweakBar when AntTweakBar needs the variable's value.
/// </summary>
private void GetCallback(IntPtr pointer, IntPtr clientData)
{
float[] data = new float[] { R, G, B };
Marshal.Copy(data, 0, pointer, data.Length);
}
#region Customization
/// <summary>
/// Gets or sets this variable's color selection mode.
/// </summary>
public ColorMode Mode
{
get
{
switch (Tw.GetStringParam(ParentBar.Pointer, ID, "colormode"))
{
case "rgb":
return ColorMode.RGB;
case "hls":
return ColorMode.HLS;
default:
throw new InvalidOperationException("Invalid color mode.");
}
}
set
{
switch (value)
{
case ColorMode.RGB:
Tw.SetParam(ParentBar.Pointer, ID, "colormode", "rgb");
break;
case ColorMode.HLS:
Tw.SetParam(ParentBar.Pointer, ID, "colormode", "hls");
break;
default:
throw new ArgumentException("Invalid color mode.");
}
}
}
#endregion
public override String ToString()
{
return String.Format("[ColorVariable: Label={0}, Value=({1}, {2}, {3})]", Label, R, G, B);
}
}
}