5
// Lluis Sanchez <lluis@xamarin.com>
7
// Copyright (c) 2012 Xamarin Inc
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
using System.Collections.Generic;
34
public class ColorSelector: Widget
36
protected new class WidgetBackendHost: Widget.WidgetBackendHost, IColorSelectorEventSink
38
protected override IBackend OnCreateBackend ()
40
var b = base.OnCreateBackend ();
41
if (b is ICustomWidgetBackend)
42
b = new DefaultColorSelectorBackend ();
46
public void OnColorChanged ()
48
((ColorSelector)Parent).OnColorChanged (EventArgs.Empty);
52
public ColorSelector ()
56
protected override Xwt.Backends.BackendHost CreateBackendHost ()
58
return new WidgetBackendHost ();
61
IColorSelectorBackend Backend {
62
get { return (IColorSelectorBackend) BackendHost.Backend; }
66
/// Gets or sets the selected color
69
get { return Backend.Color; }
70
set { Backend.Color = value; }
73
public bool SupportsAlpha {
74
get { return Backend.SupportsAlpha; }
75
set { Backend.SupportsAlpha = value; }
78
protected virtual void OnColorChanged (EventArgs args)
80
if (colorChanged != null)
81
colorChanged (this, args);
84
EventHandler colorChanged;
86
public event EventHandler ColorChanged {
88
BackendHost.OnBeforeEventAdd (ColorSelectorEvent.ColorChanged, colorChanged);
89
colorChanged += value;
92
colorChanged -= value;
93
BackendHost.OnAfterEventRemove (ColorSelectorEvent.ColorChanged, colorChanged);
98
class DefaultColorSelectorBackend: XwtWidgetBackend, IColorSelectorBackend
102
ColorSelectionBox colorBox;
105
TextEntry lightEntry;
107
TextEntry greenEntry;
109
TextEntry alphaEntry;
110
HSeparator alphaSeparator;
113
List<Widget> alphaControls = new List<Widget> ();
115
public DefaultColorSelectorBackend ()
117
HBox box = new HBox ();
118
Table selBox = new Table ();
119
hsBox = new HueBox ();
121
lightBox = new LightBox ();
122
hsBox.SelectionChanged += delegate {
123
lightBox.Hue = hsBox.SelectedColor.Hue;
124
lightBox.Saturation = hsBox.SelectedColor.Saturation;
127
colorBox = new ColorSelectionBox () { MinHeight = 20 };
129
selBox.Attach (hsBox, 0, 0);
130
selBox.Attach (lightBox, 1, 0);
132
box.PackStart (selBox);
135
VBox entryBox = new VBox ();
136
Table entryTable = new Table ();
138
entryTable.Attach (new Label ("Color:"), 0, 0);
139
entryTable.Attach (colorBox, 1, 5, 0, 1);
140
entryTable.Attach (new HSeparator (), 0, 5, 1, 2);
143
entryTable.Attach (new Label ("Hue:"), 0, r);
144
entryTable.Attach (hueEntry = new TextEntry () { MinWidth = entryWidth }, 1, r++);
146
entryTable.Attach (new Label ("Saturation:"), 0, r);
147
entryTable.Attach (satEntry = new TextEntry () { MinWidth = entryWidth }, 1, r++);
149
entryTable.Attach (new Label ("Light:"), 0, r);
150
entryTable.Attach (lightEntry = new TextEntry () { MinWidth = entryWidth }, 1, r++);
153
entryTable.Attach (new Label ("Red:"), 3, r);
154
entryTable.Attach (redEntry = new TextEntry () { MinWidth = entryWidth }, 4, r++);
156
entryTable.Attach (new Label ("Green:"), 3, r);
157
entryTable.Attach (greenEntry = new TextEntry () { MinWidth = entryWidth }, 4, r++);
159
entryTable.Attach (new Label ("Blue:"), 3, r);
160
entryTable.Attach (blueEntry = new TextEntry () { MinWidth = entryWidth }, 4, r++);
163
entryTable.Attach (alphaSeparator = new HSeparator (), 0, 5, r, ++r);
164
entryTable.Attach (label = new Label ("Opacity:"), 0, r);
165
entryTable.Attach (alphaEntry = new TextEntry () { MinWidth = entryWidth }, 1, r);
167
alphaControls.Add (alphaSeparator);
168
alphaControls.Add (label);
169
alphaControls.Add (alphaEntry);
171
entryBox.PackStart (entryTable);
172
box.PackStart (entryBox);
175
hsBox.SelectionChanged += delegate {
176
HandleColorBoxSelectionChanged ();
178
lightBox.SelectionChanged += delegate {
179
HandleColorBoxSelectionChanged ();
182
hueEntry.Changed += HandleHslChanged;
183
satEntry.Changed += HandleHslChanged;
184
lightEntry.Changed += HandleHslChanged;
185
redEntry.Changed += HandleRgbChanged;
186
greenEntry.Changed += HandleRgbChanged;
187
blueEntry.Changed += HandleRgbChanged;
188
alphaEntry.Changed += HandleAlphaChanged;
190
Color = Colors.White;
193
void HandleAlphaChanged (object sender, EventArgs e)
199
if (!int.TryParse (alphaEntry.Text, out a))
202
currentColor = currentColor.WithAlpha ((double)a / 255d);
203
LoadColorBoxSelection ();
206
void HandleHslChanged (object sender, EventArgs e)
212
if (!int.TryParse (hueEntry.Text, out h))
214
if (!int.TryParse (satEntry.Text, out s))
216
if (!int.TryParse (lightEntry.Text, out l))
219
currentColor = Color.FromHsl ((double)h / 255d, (double)s / 255d, (double)l / 255d, currentColor.Alpha);
220
LoadColorBoxSelection ();
224
void HandleRgbChanged (object sender, EventArgs e)
230
if (!int.TryParse (redEntry.Text, out r))
232
if (!int.TryParse (greenEntry.Text, out g))
234
if (!int.TryParse (blueEntry.Text, out b))
237
currentColor = new Color ((double)r / 255d, (double)g / 255d, (double)b / 255d, currentColor.Alpha);
238
LoadColorBoxSelection ();
242
void HandleColorBoxSelectionChanged ()
244
currentColor = Color.FromHsl (
245
hsBox.SelectedColor.Hue,
246
hsBox.SelectedColor.Saturation,
250
colorBox.Color = currentColor;
255
void LoadAlphaEntry ()
257
alphaEntry.Text = ((int)(currentColor.Alpha * 255)).ToString ();
260
void LoadHslEntries ()
262
loadingEntries = true;
263
hueEntry.Text = ((int)(currentColor.Hue * 255)).ToString ();
264
satEntry.Text = ((int)(currentColor.Saturation * 255)).ToString ();
265
lightEntry.Text = ((int)(currentColor.Light * 255)).ToString ();
266
loadingEntries = false;
269
void LoadRgbEntries ()
271
loadingEntries = true;
272
redEntry.Text = ((int)(currentColor.Red * 255)).ToString ();
273
greenEntry.Text = ((int)(currentColor.Green * 255)).ToString ();
274
blueEntry.Text = ((int)(currentColor.Blue * 255)).ToString ();
275
loadingEntries = false;
278
void LoadColorBoxSelection ()
280
hsBox.SelectedColor = currentColor;
281
lightBox.Light = currentColor.Light;
282
lightBox.Hue = hsBox.SelectedColor.Hue;
283
lightBox.Saturation = hsBox.SelectedColor.Saturation;
284
colorBox.Color = currentColor;
287
#region IColorSelectorBackend implementation
293
currentColor = value;
294
LoadColorBoxSelection ();
301
public bool SupportsAlpha {
303
return alphaControls [0].Visible;
306
foreach (var w in alphaControls)
315
const int size = 150;
316
const int padding = 3;
322
public double Light {
328
if (colorBox != null) {
336
public Color SelectedColor {
337
get { return GetColor ((int)selection.X, (int)selection.Y); }
339
selection.X = (size - 1) * value.Hue;
340
selection.Y = (size - 1) * (1 - value.Saturation);
347
MinWidth = size + padding * 2;
348
MinHeight = size + padding * 2;
351
protected override void OnDraw (Context ctx, Rectangle dirtyRect)
353
if (colorBox == null) {
354
ImageBuilder ib = new ImageBuilder (size, size);
355
for (int i=0; i<size; i++) {
356
for (int j=0; j<size; j++) {
357
ib.Context.Rectangle (i, j, 1, 1);
358
ib.Context.SetColor (GetColor (i,j));
362
colorBox = ib.ToImage ();
365
ctx.DrawImage (colorBox, padding, padding);
366
ctx.SetLineWidth (1);
367
ctx.SetColor (Colors.Black);
368
ctx.Rectangle (selection.X + padding - 2 + 0.5, selection.Y + padding - 2 + 0.5, 4, 4);
372
Color GetColor (int x, int y)
374
return Color.FromHsl ((double)x / (double)(size-1), (double)(size - 1 - y) / (double)(size-1), Light);
377
protected override void OnButtonPressed (ButtonEventArgs args)
379
base.OnButtonPressed (args);
381
selection = new Point (args.X - padding, args.Y - padding);
382
OnSelectionChanged ();
386
protected override void OnButtonReleased (ButtonEventArgs args)
388
base.OnButtonReleased (args);
393
protected override void OnMouseMoved (MouseMovedEventArgs args)
395
base.OnMouseMoved (args);
398
selection = new Point (args.X - padding, args.Y - padding);
399
OnSelectionChanged ();
403
void OnSelectionChanged ()
409
if (selection.X >= size)
410
selection.X = size - 1;
411
if (selection.Y >= size)
412
selection.Y = size - 1;
413
if (SelectionChanged != null)
414
SelectionChanged (this, EventArgs.Empty);
417
public event EventHandler SelectionChanged;
420
class LightBox: Canvas
422
const int padding = 3;
438
public double Saturation {
448
public double Light {
464
protected override void OnDraw (Context ctx, Rectangle dirtyRect)
466
double width = Size.Width - padding * 2;
467
int range = (int)Size.Height - padding * 2;
468
for (int n=0; n < range; n++) {
469
ctx.Rectangle (padding, padding + n, width, 1);
470
ctx.SetColor (Color.FromHsl (hue, saturation, (double)(range - n - 1) / (double)(range - 1)));
473
ctx.Rectangle (0.5, padding + (int)(((double)range) * (1-light)) + 0.5 - 2, Size.Width - 1, 4);
474
ctx.SetColor (Colors.Black);
475
ctx.SetLineWidth (1);
479
protected override void OnButtonPressed (ButtonEventArgs args)
481
base.OnButtonPressed (args);
482
buttonPressed = true;
483
OnSelectionChanged ((int)args.Y - padding);
487
protected override void OnButtonReleased (ButtonEventArgs args)
489
base.OnButtonReleased (args);
490
buttonPressed = false;
494
protected override void OnMouseMoved (MouseMovedEventArgs args)
496
base.OnMouseMoved (args);
498
OnSelectionChanged ((int)args.Y - padding);
503
void OnSelectionChanged (int y)
505
int range = (int)Size.Height - padding * 2;
510
light = 1 - ((double) y / (double)(range - 1));
511
if (SelectionChanged != null)
512
SelectionChanged (this, EventArgs.Empty);
515
public event EventHandler SelectionChanged;
518
class ColorSelectionBox: Canvas
532
protected override void OnDraw (Context ctx, Rectangle dirtyRect)
534
ctx.Rectangle (Bounds);
535
ctx.SetColor (Colors.White);
539
ctx.LineTo (Size.Width, 0);
540
ctx.LineTo (0, Size.Height);
542
ctx.SetColor (Colors.Black);
545
ctx.Rectangle (Bounds);
546
ctx.SetColor (color);