RoundedRectangleTool.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /////////////////////////////////////////////////////////////////////////////////
  2. // Paint.NET //
  3. // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
  4. // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
  5. // See src/Resources/Files/License.txt for full licensing and attribution //
  6. // details. //
  7. // . //
  8. /////////////////////////////////////////////////////////////////////////////////
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Drawing;
  12. using System.Windows.Forms;
  13. namespace PaintDotNet.Measurement.Tools
  14. {
  15. public class RoundedRectangleTool : ShapeTool
  16. {
  17. private ImageResource roundedRectangleToolIcon;
  18. private string statusTextFormat = PdnResources.GetString("RoundedRectangleTool.StatusText.Format");
  19. private Cursor roundedRectangleCursor;
  20. protected override RectangleF[] GetOptimizedShapeOutlineRegion(PointF[] points, PdnGraphicsPath path)
  21. {
  22. return Utility.SimplifyTrace(path.PathPoints);
  23. }
  24. protected override List<PointF> TrimShapePath(List<PointF> points)
  25. {
  26. List<PointF> array = new List<PointF>();
  27. if (points.Count > 0)
  28. {
  29. array.Add(points[0]);
  30. if (points.Count > 1)
  31. {
  32. array.Add(points[points.Count - 1]);
  33. }
  34. }
  35. return array;
  36. }
  37. protected override PdnGraphicsPath CreateShapePath(PointF[] points)
  38. {
  39. PointF a = points[0];
  40. PointF b = points[points.Length - 1];
  41. RectangleF rect;
  42. float radius = 10;
  43. if ((ModifierKeys & Keys.Shift) != 0)
  44. {
  45. rect = Utility.PointsToConstrainedRectangle(a, b);
  46. }
  47. else
  48. {
  49. rect = Utility.PointsToRectangle(a, b);
  50. }
  51. PdnGraphicsPath path = this.GetRoundedRect(rect, radius);
  52. path.Flatten();
  53. if (path.PathPoints[0] != path.PathPoints[path.PathPoints.Length - 1])
  54. {
  55. path.AddLine(path.PathPoints[0], path.PathPoints[path.PathPoints.Length - 1]);
  56. path.CloseFigure();
  57. }
  58. MeasurementUnit units = AppWorkspace.GetUnits();
  59. double widthPhysical = Math.Abs(Document.PixelToPhysicalX(rect.Width, units));
  60. double heightPhysical = Math.Abs(Document.PixelToPhysicalY(rect.Height, units));
  61. double areaPhysical = widthPhysical * heightPhysical;
  62. string numberFormat;
  63. string unitsAbbreviation;
  64. if (units != MeasurementUnit.Pixel)
  65. {
  66. string unitsAbbreviationName = "MeasurementUnit." + units.ToString() + ".Abbreviation";
  67. unitsAbbreviation = PdnResources.GetString(unitsAbbreviationName);
  68. numberFormat = "F2";
  69. }
  70. else
  71. {
  72. unitsAbbreviation = string.Empty;
  73. numberFormat = "F0";
  74. }
  75. string unitsString = PdnResources.GetString("MeasurementUnit." + units.ToString() + ".Plural");
  76. string statusText = string.Format(
  77. this.statusTextFormat,
  78. widthPhysical.ToString(numberFormat),
  79. unitsAbbreviation,
  80. heightPhysical.ToString(numberFormat),
  81. unitsAbbreviation,
  82. areaPhysical.ToString(numberFormat),
  83. unitsString);
  84. this.SetStatus(this.roundedRectangleToolIcon, statusText);
  85. return path;
  86. }
  87. protected override void OnActivate()
  88. {
  89. this.roundedRectangleCursor = new Cursor(PdnResources.GetResourceStream("Cursors.RoundedRectangleToolCursor.cur"));
  90. this.Cursor = this.roundedRectangleCursor;
  91. this.roundedRectangleToolIcon = this.Image;
  92. base.OnActivate();
  93. }
  94. protected override void OnDeactivate()
  95. {
  96. if (this.roundedRectangleCursor != null)
  97. {
  98. this.roundedRectangleCursor.Dispose();
  99. this.roundedRectangleCursor = null;
  100. }
  101. base.OnDeactivate();
  102. }
  103. public RoundedRectangleTool(IDocumentWorkspace documentWorkspace)
  104. : base(documentWorkspace,
  105. PdnResources.GetImageResource("Icons.RoundedRectangleToolIcon.png"),
  106. PdnResources.GetString("RoundedRectangleTool.Name"),
  107. PdnResources.GetString("RoundedRectangleTool.HelpText"))
  108. {
  109. }
  110. // credit for the this function is given to Aaron Reginald http://www.codeproject.com/cs/media/ExtendedGraphics.asp
  111. protected PdnGraphicsPath GetRoundedRect(RectangleF baseRect, float radius)
  112. {
  113. // if corner radius is less than or equal to zero,
  114. // return the original rectangle
  115. if (radius <= 0.0f)
  116. {
  117. PdnGraphicsPath mPath = new PdnGraphicsPath();
  118. mPath.AddRectangle(baseRect);
  119. mPath.CloseFigure();
  120. return mPath;
  121. }
  122. // if the corner radius is greater than or equal to
  123. // half the width, or height (whichever is shorter)
  124. // then return a capsule instead of a lozenge
  125. if (radius >= (Math.Min(baseRect.Width, baseRect.Height)) / 2.0)
  126. {
  127. return GetCapsule(baseRect);
  128. }
  129. // create the arc for the rectangle sides and declare
  130. // a graphics path object for the drawing
  131. float diameter = radius * 2.0f;
  132. SizeF sizeF = new SizeF(diameter, diameter);
  133. RectangleF arc = new RectangleF(baseRect.Location, sizeF);
  134. PdnGraphicsPath path = new PdnGraphicsPath();
  135. // top left arc
  136. path.AddArc(arc, 180, 90);
  137. // top right arc
  138. arc.X = baseRect.Right - diameter;
  139. path.AddArc(arc, 270, 90);
  140. // bottom right arc
  141. arc.Y = baseRect.Bottom - diameter;
  142. path.AddArc(arc, 0, 90);
  143. // bottom left arc
  144. arc.X = baseRect.Left;
  145. path.AddArc(arc, 90, 90);
  146. path.CloseFigure();
  147. return path;
  148. }
  149. // credit for the this function is given to Aaron Reginald http://www.codeproject.com/cs/media/ExtendedGraphics.asp
  150. private PdnGraphicsPath GetCapsule(RectangleF baseRect)
  151. {
  152. float diameter;
  153. RectangleF arc;
  154. PdnGraphicsPath path = new PdnGraphicsPath();
  155. try
  156. {
  157. if (baseRect.Width > baseRect.Height)
  158. {
  159. // return horizontal capsule
  160. diameter = baseRect.Height;
  161. SizeF sizeF = new SizeF(diameter, diameter);
  162. arc = new RectangleF(baseRect.Location, sizeF);
  163. path.AddArc(arc, 90, 180);
  164. arc.X = baseRect.Right - diameter;
  165. path.AddArc(arc, 270, 180);
  166. }
  167. else if (baseRect.Width < baseRect.Height)
  168. {
  169. // return vertical capsule
  170. diameter = baseRect.Width;
  171. SizeF sizeF = new SizeF(diameter, diameter);
  172. arc = new RectangleF(baseRect.Location, sizeF);
  173. path.AddArc(arc, 180, 180);
  174. arc.Y = baseRect.Bottom - diameter;
  175. path.AddArc(arc, 0, 180);
  176. }
  177. else
  178. { // return circle
  179. path.AddEllipse(baseRect);
  180. }
  181. }
  182. catch (Exception)
  183. {
  184. path.AddEllipse(baseRect);
  185. }
  186. finally
  187. {
  188. path.CloseFigure();
  189. }
  190. return path;
  191. }
  192. }
  193. }