|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.Linq; |
| 4 | +using System.Text; |
| 5 | +using System.Threading.Tasks; |
| 6 | +using System.Windows; |
| 7 | +using System.Windows.Controls; |
| 8 | +using System.Windows.Input; |
| 9 | +using System.Windows.Media; |
| 10 | +using System.Windows.Media.Imaging; |
| 11 | +using System.Windows.Shapes; |
| 12 | + |
| 13 | +namespace WPFColorLib |
| 14 | +{ |
| 15 | + public partial class HSLColorSelector : UserControl |
| 16 | + { |
| 17 | + public HSLColorSelector() |
| 18 | + { |
| 19 | + InitializeComponent(); |
| 20 | + |
| 21 | + slidHue.ValueChanged += SlidHue_ValueChanged; |
| 22 | + } |
| 23 | + |
| 24 | + public event EventHandler<Tuple<byte, byte, byte>> ColorRGBChanged; |
| 25 | + public event EventHandler<Tuple<int, int, int>> ColorHSLChanged;// 0..360, 0..100, 0..100 |
| 26 | + |
| 27 | + void Control_Resized(object sender, SizeChangedEventArgs e) |
| 28 | + { |
| 29 | + #region recreate hue bar |
| 30 | + var imgW = (int)(brdHue.ActualWidth - 2); |
| 31 | + var imgH = (int)(brdHue.ActualHeight - 2); |
| 32 | + imgHue.Source = new WriteableBitmap(imgW, imgH, 96, 96, PixelFormats.Bgr32, null); |
| 33 | + DrawHueBar(); |
| 34 | + #endregion |
| 35 | + |
| 36 | + #region recreate Saturation/Lightness area |
| 37 | + imgW = (int)(brdSaturLight.ActualWidth - 2); |
| 38 | + imgH = (int)(brdSaturLight.ActualHeight - 2); |
| 39 | + imgSaturLight.Source = new WriteableBitmap(imgW, imgH, 96, 96, PixelFormats.Bgr32, null); |
| 40 | + RedrawSaturLight(slidHue.Value); |
| 41 | + #endregion |
| 42 | + } |
| 43 | + |
| 44 | + void DrawHueBar() |
| 45 | + { |
| 46 | + var recW = (int)(brdHue.ActualWidth - 2); |
| 47 | + var recH = (int)(brdHue.ActualHeight - 2); |
| 48 | + var k = 360.0 / recW; |
| 49 | + var bmp = (WriteableBitmap)imgHue.Source; |
| 50 | + bmp.Lock(); |
| 51 | + unsafe { |
| 52 | + var buf = bmp.BackBuffer; |
| 53 | + // fill the first line of hue bar |
| 54 | + for(int x=0; x < recW; x++){ |
| 55 | + int hue = (int)Math.Floor(x * k); |
| 56 | + *((int*)(buf + x * 4)) = ClrHlp.HSL2RGBInt(hue, 100, 100); |
| 57 | + } |
| 58 | + var origColorLine = new Span<byte>(buf.ToPointer(), bmp.BackBufferStride); |
| 59 | + for (int y = 1; y < recH; y++) { |
| 60 | + var destColorLine = new Span<byte>((buf + y * bmp.BackBufferStride).ToPointer(), bmp.BackBufferStride); |
| 61 | + origColorLine.CopyTo(destColorLine); |
| 62 | + } |
| 63 | + } |
| 64 | + bmp.AddDirtyRect(new Int32Rect(0, 0, recW, recH)); |
| 65 | + bmp.Unlock(); |
| 66 | + } |
| 67 | + |
| 68 | + void SlidHue_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) |
| 69 | + { |
| 70 | + RedrawSaturLight(e.NewValue); |
| 71 | + |
| 72 | + // calc contrast color for ellipse(target above color) |
| 73 | + var contrastHue = ((int)e.NewValue + 180) % 360;// opposite side of color ring |
| 74 | + var contrastColor = ClrHlp.HSL2RGB(contrastHue, 100, 100); |
| 75 | + ellClrTarget.Stroke = new SolidColorBrush(Color.FromRgb((byte)contrastColor[0], (byte)contrastColor[1], (byte)contrastColor[2])); |
| 76 | + } |
| 77 | + |
| 78 | + void RedrawSaturLight(double newHue) |
| 79 | + { |
| 80 | + var hue = (int)newHue; |
| 81 | + var recW = (int)(brdSaturLight.ActualWidth - 2); |
| 82 | + var recH = (int)(brdSaturLight.ActualHeight - 2); |
| 83 | + var kX = 100.0 / recW; |
| 84 | + var kY = 100.0 / recH; |
| 85 | + var bmp = (WriteableBitmap)imgSaturLight.Source; |
| 86 | + bmp.Lock(); |
| 87 | + unsafe { |
| 88 | + var buf = bmp.BackBuffer; |
| 89 | + for (int y = 0; y < recH; y++) { |
| 90 | + var lineStart = buf + y * bmp.BackBufferStride; |
| 91 | + for (int x = 0; x < recW; x++) { |
| 92 | + *((int*)(lineStart + x * 4)) = ClrHlp.HSL2RGBInt(hue, (int)(kX * x), (int)(kY * y)); |
| 93 | + } |
| 94 | + } |
| 95 | + } |
| 96 | + bmp.AddDirtyRect(new Int32Rect(0, 0, recW, recH)); |
| 97 | + bmp.Unlock(); |
| 98 | + } |
| 99 | + |
| 100 | + bool trackColorMode = false; |
| 101 | + |
| 102 | + void imgSaturLight_MouDown(object sender, MouseButtonEventArgs e) |
| 103 | + { |
| 104 | + trackColorMode = true; |
| 105 | + imgSaturLight.CaptureMouse(); |
| 106 | + |
| 107 | + SelectNewColor(e.GetPosition(imgSaturLight)); |
| 108 | + } |
| 109 | + |
| 110 | + void imgSaturLight_MouMove(object sender, MouseEventArgs e) |
| 111 | + { |
| 112 | + if (!trackColorMode) return; |
| 113 | + |
| 114 | + SelectNewColor(e.GetPosition(imgSaturLight)); |
| 115 | + } |
| 116 | + |
| 117 | + void SelectNewColor(Point mou) |
| 118 | + { |
| 119 | + var recW = (int)(brdSaturLight.ActualWidth - 2); |
| 120 | + var recH = (int)(brdSaturLight.ActualHeight - 2); |
| 121 | + var kX = 100.0 / recW; |
| 122 | + var kY = 100.0 / recH; |
| 123 | + |
| 124 | + if (mou.X < 0) |
| 125 | + mou.X = 0; |
| 126 | + else if (mou.X >= recW) |
| 127 | + mou.X = recW - 1; |
| 128 | + if (mou.Y < 0) |
| 129 | + mou.Y = 0; |
| 130 | + else if (mou.Y >= recH) |
| 131 | + mou.Y = recH - 1; |
| 132 | + |
| 133 | + Canvas.SetLeft(ellClrTarget, mou.X-2); |
| 134 | + Canvas.SetTop(ellClrTarget, mou.Y-2); |
| 135 | + |
| 136 | + var hue = (int)slidHue.Value; |
| 137 | + var sat = (int)(mou.X * kX); |
| 138 | + var lum = (int)(mou.Y * kY); |
| 139 | + ColorHSLChanged?.Invoke(this, new Tuple<int, int, int>(hue, sat, lum)); |
| 140 | + |
| 141 | + if (ColorRGBChanged != null) { |
| 142 | + var clr = ClrHlp.HSL2RGB(hue, sat, lum); |
| 143 | + ColorRGBChanged.Invoke(this, new Tuple<byte, byte, byte>((byte)clr[0], (byte)clr[1], (byte)clr[2])); |
| 144 | + } |
| 145 | + } |
| 146 | + |
| 147 | + void imgSaturLight_MouUp(object sender, MouseButtonEventArgs e) |
| 148 | + { |
| 149 | + trackColorMode = false; |
| 150 | + imgSaturLight.ReleaseMouseCapture(); |
| 151 | + } |
| 152 | + } |
| 153 | +} |
0 commit comments