///////////////////////////////////////////////////////////////////////////////// // Paint.NET // // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. // // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. // // See src/Resources/Files/License.txt for full licensing and attribution // // details. // // . // ///////////////////////////////////////////////////////////////////////////////// using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; namespace PaintDotNet.Measurement.Tools { public class RoundedRectangleTool : ShapeTool { private ImageResource roundedRectangleToolIcon; private string statusTextFormat = PdnResources.GetString("RoundedRectangleTool.StatusText.Format"); private Cursor roundedRectangleCursor; protected override RectangleF[] GetOptimizedShapeOutlineRegion(PointF[] points, PdnGraphicsPath path) { return Utility.SimplifyTrace(path.PathPoints); } protected override List TrimShapePath(List points) { List array = new List(); if (points.Count > 0) { array.Add(points[0]); if (points.Count > 1) { array.Add(points[points.Count - 1]); } } return array; } protected override PdnGraphicsPath CreateShapePath(PointF[] points) { PointF a = points[0]; PointF b = points[points.Length - 1]; RectangleF rect; float radius = 10; if ((ModifierKeys & Keys.Shift) != 0) { rect = Utility.PointsToConstrainedRectangle(a, b); } else { rect = Utility.PointsToRectangle(a, b); } PdnGraphicsPath path = this.GetRoundedRect(rect, radius); path.Flatten(); if (path.PathPoints[0] != path.PathPoints[path.PathPoints.Length - 1]) { path.AddLine(path.PathPoints[0], path.PathPoints[path.PathPoints.Length - 1]); path.CloseFigure(); } MeasurementUnit units = AppWorkspace.GetUnits(); double widthPhysical = Math.Abs(Document.PixelToPhysicalX(rect.Width, units)); double heightPhysical = Math.Abs(Document.PixelToPhysicalY(rect.Height, units)); double areaPhysical = widthPhysical * heightPhysical; string numberFormat; string unitsAbbreviation; if (units != MeasurementUnit.Pixel) { string unitsAbbreviationName = "MeasurementUnit." + units.ToString() + ".Abbreviation"; unitsAbbreviation = PdnResources.GetString(unitsAbbreviationName); numberFormat = "F2"; } else { unitsAbbreviation = string.Empty; numberFormat = "F0"; } string unitsString = PdnResources.GetString("MeasurementUnit." + units.ToString() + ".Plural"); string statusText = string.Format( this.statusTextFormat, widthPhysical.ToString(numberFormat), unitsAbbreviation, heightPhysical.ToString(numberFormat), unitsAbbreviation, areaPhysical.ToString(numberFormat), unitsString); this.SetStatus(this.roundedRectangleToolIcon, statusText); return path; } protected override void OnActivate() { this.roundedRectangleCursor = new Cursor(PdnResources.GetResourceStream("Cursors.RoundedRectangleToolCursor.cur")); this.Cursor = this.roundedRectangleCursor; this.roundedRectangleToolIcon = this.Image; base.OnActivate(); } protected override void OnDeactivate() { if (this.roundedRectangleCursor != null) { this.roundedRectangleCursor.Dispose(); this.roundedRectangleCursor = null; } base.OnDeactivate(); } public RoundedRectangleTool(IDocumentWorkspace documentWorkspace) : base(documentWorkspace, PdnResources.GetImageResource("Icons.RoundedRectangleToolIcon.png"), PdnResources.GetString("RoundedRectangleTool.Name"), PdnResources.GetString("RoundedRectangleTool.HelpText")) { } // credit for the this function is given to Aaron Reginald http://www.codeproject.com/cs/media/ExtendedGraphics.asp protected PdnGraphicsPath GetRoundedRect(RectangleF baseRect, float radius) { // if corner radius is less than or equal to zero, // return the original rectangle if (radius <= 0.0f) { PdnGraphicsPath mPath = new PdnGraphicsPath(); mPath.AddRectangle(baseRect); mPath.CloseFigure(); return mPath; } // if the corner radius is greater than or equal to // half the width, or height (whichever is shorter) // then return a capsule instead of a lozenge if (radius >= (Math.Min(baseRect.Width, baseRect.Height)) / 2.0) { return GetCapsule(baseRect); } // create the arc for the rectangle sides and declare // a graphics path object for the drawing float diameter = radius * 2.0f; SizeF sizeF = new SizeF(diameter, diameter); RectangleF arc = new RectangleF(baseRect.Location, sizeF); PdnGraphicsPath path = new PdnGraphicsPath(); // top left arc path.AddArc(arc, 180, 90); // top right arc arc.X = baseRect.Right - diameter; path.AddArc(arc, 270, 90); // bottom right arc arc.Y = baseRect.Bottom - diameter; path.AddArc(arc, 0, 90); // bottom left arc arc.X = baseRect.Left; path.AddArc(arc, 90, 90); path.CloseFigure(); return path; } // credit for the this function is given to Aaron Reginald http://www.codeproject.com/cs/media/ExtendedGraphics.asp private PdnGraphicsPath GetCapsule(RectangleF baseRect) { float diameter; RectangleF arc; PdnGraphicsPath path = new PdnGraphicsPath(); try { if (baseRect.Width > baseRect.Height) { // return horizontal capsule diameter = baseRect.Height; SizeF sizeF = new SizeF(diameter, diameter); arc = new RectangleF(baseRect.Location, sizeF); path.AddArc(arc, 90, 180); arc.X = baseRect.Right - diameter; path.AddArc(arc, 270, 180); } else if (baseRect.Width < baseRect.Height) { // return vertical capsule diameter = baseRect.Width; SizeF sizeF = new SizeF(diameter, diameter); arc = new RectangleF(baseRect.Location, sizeF); path.AddArc(arc, 180, 180); arc.Y = baseRect.Bottom - diameter; path.AddArc(arc, 0, 180); } else { // return circle path.AddEllipse(baseRect); } } catch (Exception) { path.AddEllipse(baseRect); } finally { path.CloseFigure(); } return path; } } }