ColorWheel.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. using SmartCoalApplication.Core;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Data;
  6. using System.Drawing;
  7. using System.Drawing.Drawing2D;
  8. using System.Drawing.Imaging;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. using System.Windows.Forms;
  13. namespace SmartCoalApplication.PluginAssemblys
  14. {
  15. internal class ColorWheel : UserControl
  16. {
  17. /// <summary>
  18. /// Required designer variable.
  19. /// </summary>
  20. private System.ComponentModel.Container components = null;
  21. private Bitmap renderBitmap = null;
  22. private bool tracking = false;
  23. private Point lastMouseXY;
  24. // this number controls what you might call the tesselation of the color wheel. higher #'s = slower, lower #'s = looks worse
  25. private const int colorTesselation = 60;
  26. private PictureBox wheelPictureBox;
  27. private HsvColor hsvColor;
  28. public HsvColor HsvColor
  29. {
  30. get
  31. {
  32. return hsvColor;
  33. }
  34. set
  35. {
  36. if (hsvColor != value)
  37. {
  38. HsvColor oldColor = hsvColor;
  39. hsvColor = value;
  40. this.OnColorChanged();
  41. Refresh();
  42. }
  43. }
  44. }
  45. public ColorWheel()
  46. {
  47. // This call is required by the Windows.Forms Form Designer.
  48. InitializeComponent();
  49. //wheelRegion = new PdnRegion();
  50. hsvColor = new HsvColor(0, 0, 0);
  51. }
  52. private static PointF SphericalToCartesian(float r, float theta)
  53. {
  54. float x;
  55. float y;
  56. x = r * (float)Math.Cos(theta);
  57. y = r * (float)Math.Sin(theta);
  58. return new PointF(x, y);
  59. }
  60. private static PointF[] GetCirclePoints(float r, PointF center)
  61. {
  62. PointF[] points = new PointF[colorTesselation];
  63. for (int i = 0; i < colorTesselation; i++)
  64. {
  65. float theta = ((float)i / (float)colorTesselation) * 2 * (float)Math.PI;
  66. points[i] = SphericalToCartesian(r, theta);
  67. points[i].X += center.X;
  68. points[i].Y += center.Y;
  69. }
  70. return points;
  71. }
  72. private Color[] GetColors()
  73. {
  74. Color[] colors = new Color[colorTesselation];
  75. for (int i = 0; i < colorTesselation; i++)
  76. {
  77. int hue = (i * 360) / colorTesselation;
  78. colors[i] = new HsvColor(hue, 100, 100).ToColor();
  79. }
  80. return colors;
  81. }
  82. protected override void OnLoad(EventArgs e)
  83. {
  84. InitRendering();
  85. base.OnLoad(e);
  86. }
  87. protected override void OnPaint(PaintEventArgs e)
  88. {
  89. InitRendering();
  90. base.OnPaint(e);
  91. }
  92. private void InitRendering()
  93. {
  94. if (this.renderBitmap == null)
  95. {
  96. InitRenderSurface();
  97. this.wheelPictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
  98. int size = (int)Math.Ceiling(ComputeDiameter(this.Size));
  99. this.wheelPictureBox.Size = new Size(size, size);
  100. this.wheelPictureBox.Image = this.renderBitmap;
  101. }
  102. }
  103. private void WheelPictureBox_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
  104. {
  105. float radius = ComputeRadius(Size);
  106. float theta = ((float)HsvColor.Hue / 360.0f) * 2.0f * (float)Math.PI;
  107. float alpha = ((float)HsvColor.Saturation / 100.0f);
  108. float x = (alpha * (radius - 1) * (float)Math.Cos(theta)) + radius;
  109. float y = (alpha * (radius - 1) * (float)Math.Sin(theta)) + radius;
  110. int ix = (int)x;
  111. int iy = (int)y;
  112. // Draw the 'target rectangle'
  113. GraphicsContainer container = e.Graphics.BeginContainer();
  114. e.Graphics.PixelOffsetMode = PixelOffsetMode.None;
  115. e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
  116. e.Graphics.DrawRectangle(Pens.Black, ix - 1, iy - 1, 3, 3);
  117. e.Graphics.DrawRectangle(Pens.White, ix, iy, 1, 1);
  118. e.Graphics.EndContainer(container);
  119. }
  120. private void InitRenderSurface()
  121. {
  122. if (renderBitmap != null)
  123. {
  124. renderBitmap.Dispose();
  125. }
  126. int wheelDiameter = (int)ComputeDiameter(Size);
  127. renderBitmap = new Bitmap(Math.Max(1, (wheelDiameter * 4) / 3),
  128. Math.Max(1, (wheelDiameter * 4) / 3), PixelFormat.Format24bppRgb);
  129. using (Graphics g1 = Graphics.FromImage(renderBitmap))
  130. {
  131. g1.Clear(this.BackColor);
  132. DrawWheel(g1, renderBitmap.Width, renderBitmap.Height);
  133. }
  134. }
  135. private void DrawWheel(Graphics g, int width, int height)
  136. {
  137. float radius = ComputeRadius(new Size(width, height));
  138. PointF[] points = GetCirclePoints(Math.Max(1.0f, (float)radius - 1), new PointF(radius, radius));
  139. using (PathGradientBrush pgb = new PathGradientBrush(points))
  140. {
  141. pgb.CenterColor = new HsvColor(0, 0, 100).ToColor();
  142. pgb.CenterPoint = new PointF(radius, radius);
  143. pgb.SurroundColors = GetColors();
  144. g.FillEllipse(pgb, 0, 0, radius * 2, radius * 2);
  145. }
  146. }
  147. private static float ComputeRadius(Size size)
  148. {
  149. return Math.Min((float)size.Width / 2, (float)size.Height / 2);
  150. }
  151. private static float ComputeDiameter(Size size)
  152. {
  153. return Math.Min((float)size.Width, (float)size.Height);
  154. }
  155. protected override void OnResize(EventArgs e)
  156. {
  157. base.OnResize(e);
  158. if (renderBitmap != null && (ComputeRadius(Size) != ComputeRadius(renderBitmap.Size)))
  159. {
  160. renderBitmap.Dispose();
  161. renderBitmap = null;
  162. }
  163. Invalidate();
  164. }
  165. public event EventHandler ColorChanged;
  166. protected virtual void OnColorChanged()
  167. {
  168. if (ColorChanged != null)
  169. {
  170. ColorChanged(this, EventArgs.Empty);
  171. }
  172. }
  173. private void GrabColor(Point mouseXY)
  174. {
  175. // center our coordinate system so the middle is (0,0), and positive Y is facing up
  176. int cx = mouseXY.X - (Width / 2);
  177. int cy = mouseXY.Y - (Height / 2);
  178. double theta = Math.Atan2(cy, cx);
  179. if (theta < 0)
  180. {
  181. theta += 2 * Math.PI;
  182. }
  183. double alpha = Math.Sqrt((cx * cx) + (cy * cy));
  184. int h = (int)((theta / (Math.PI * 2)) * 360.0);
  185. int s = (int)Math.Min(100.0, (alpha / (double)(Width / 2)) * 100);
  186. int v = 100;
  187. hsvColor = new HsvColor(h, s, v);
  188. OnColorChanged();
  189. Invalidate(true);
  190. }
  191. protected override void OnMouseDown(MouseEventArgs e)
  192. {
  193. base.OnMouseDown(e);
  194. if (e.Button == MouseButtons.Left)
  195. {
  196. tracking = true;
  197. }
  198. }
  199. protected override void OnMouseUp(MouseEventArgs e)
  200. {
  201. base.OnMouseUp(e);
  202. if (tracking)
  203. {
  204. GrabColor(new Point(e.X, e.Y));
  205. }
  206. tracking = false;
  207. }
  208. protected override void OnMouseMove(MouseEventArgs e)
  209. {
  210. base.OnMouseMove(e);
  211. lastMouseXY = new Point(e.X, e.Y);
  212. if (tracking)
  213. {
  214. GrabColor(new Point(e.X, e.Y));
  215. }
  216. }
  217. /// <summary>
  218. /// Clean up any resources being used.
  219. /// </summary>
  220. protected override void Dispose(bool disposing)
  221. {
  222. if (disposing)
  223. {
  224. if (components != null)
  225. {
  226. components.Dispose();
  227. components = null;
  228. }
  229. }
  230. base.Dispose(disposing);
  231. }
  232. #region Component Designer generated code
  233. /// <summary>
  234. /// Required method for Designer support - do not modify
  235. /// the contents of this method with the code editor.
  236. /// </summary>
  237. private void InitializeComponent()
  238. {
  239. this.wheelPictureBox = new System.Windows.Forms.PictureBox();
  240. this.SuspendLayout();
  241. //
  242. // wheelPictureBox
  243. //
  244. this.wheelPictureBox.Location = new System.Drawing.Point(0, 0);
  245. this.wheelPictureBox.Name = "wheelPictureBox";
  246. this.wheelPictureBox.TabIndex = 0;
  247. this.wheelPictureBox.TabStop = false;
  248. this.wheelPictureBox.Click += new System.EventHandler(this.wheelPictureBox_Click);
  249. this.wheelPictureBox.Paint += new System.Windows.Forms.PaintEventHandler(this.WheelPictureBox_Paint);
  250. this.wheelPictureBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.wheelPictureBox_MouseUp);
  251. this.wheelPictureBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.wheelPictureBox_MouseMove);
  252. this.wheelPictureBox.MouseDown += new System.Windows.Forms.MouseEventHandler(this.wheelPictureBox_MouseDown);
  253. //
  254. // ColorWheel
  255. //
  256. this.Controls.Add(this.wheelPictureBox);
  257. this.Name = "ColorWheel";
  258. this.ResumeLayout(false);
  259. }
  260. #endregion
  261. private void wheelPictureBox_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
  262. {
  263. OnMouseMove(e);
  264. }
  265. private void wheelPictureBox_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
  266. {
  267. OnMouseUp(e);
  268. }
  269. private void wheelPictureBox_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
  270. {
  271. OnMouseDown(e);
  272. }
  273. private void wheelPictureBox_Click(object sender, System.EventArgs e)
  274. {
  275. OnClick(e);
  276. }
  277. }
  278. }