using System; using System.Collections.Generic; using System.Text; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using FastReport.Utils; using System.Linq; namespace FastReport { /// /// Represents a line object. /// /// /// Use the Border.Width, Border.Style and Border.Color properties to set /// the line width, style and color. Set the property to true /// if you want to show a diagonal line. /// public partial class LineObject : ReportComponentBase { #region Fields private bool diagonal; private CapSettings startCap; private CapSettings endCap; private FloatCollection dashPattern; #endregion #region Properties /// /// Gets or sets a value indicating that the line is diagonal. /// /// /// If this property is false, the line can be only horizontal or vertical. /// [DefaultValue(false)] [Category("Appearance")] public bool Diagonal { get { return diagonal; } set { diagonal = value; } } /// /// Gets or sets the start cap settings. /// [Category("Appearance")] public CapSettings StartCap { get { return startCap; } set { startCap = value; } } /// /// Gets or sets the end cap settings. /// [Category("Appearance")] public CapSettings EndCap { get { return endCap; } set { endCap = value; } } /// /// Gets or sets collection of values for custom dash pattern. /// /// /// Each element should be a non-zero positive number. /// If the number is negative or zero, that number is replaced by one. /// [Category("Appearance")] public FloatCollection DashPattern { get { return dashPattern; } set { dashPattern = value; } } #endregion #region Public Methods /// public override void Assign(Base source) { base.Assign(source); LineObject src = source as LineObject; Diagonal = src.Diagonal; StartCap.Assign(src.StartCap); EndCap.Assign(src.EndCap); DashPattern.Assign(src.DashPattern); } /// public override void Draw(FRPaintEventArgs e) { IGraphics g = e.Graphics; // draw marker when inserting a line if (Width == 0 && Height == 0) { g.DrawLine(Pens.Black, AbsLeft * e.ScaleX - 6, AbsTop * e.ScaleY, AbsLeft * e.ScaleX + 6, AbsTop * e.ScaleY); g.DrawLine(Pens.Black, AbsLeft * e.ScaleX, AbsTop * e.ScaleY - 6, AbsLeft * e.ScaleX, AbsTop * e.ScaleY + 6); return; } Report report = Report; if (report != null && report.SmoothGraphics) { g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.SmoothingMode = SmoothingMode.AntiAlias; } Pen pen = e.Cache.GetPen(Border.Color, Border.Width * e.ScaleX, Border.DashStyle); DrawUtils.SetPenDashPatternOrStyle(DashPattern, pen, Border); if (!Diagonal) { if (Math.Abs(Width) > Math.Abs(Height)) Height = 0; else Width = 0; } float x1 = AbsLeft * e.ScaleX; float y1 = AbsTop * e.ScaleY; float x2 = (AbsLeft + Width) * e.ScaleX; float y2 = (AbsTop + Height) * e.ScaleY; if (StartCap.Style == CapStyle.None && EndCap.Style == CapStyle.None) { g.DrawLine(pen, x1, y1, x2, y2); } else { // draw line caps manually. It is necessary for correct svg rendering float angle = (float)(Math.Atan2(x2 - x1, y2 - y1) / Math.PI * 180); float len = (float)Math.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); float scale = Border.Width * e.ScaleX; IGraphicsState state = g.Save(); g.TranslateTransform(x1, y1); g.RotateTransform(-angle); float y = 0; GraphicsPath startCapPath = null; GraphicsPath endCapPath = null; float inset = 0; if (StartCap.Style != CapStyle.None) { StartCap.GetCustomCapPath(out startCapPath, out inset); y += inset * scale; } if (EndCap.Style != CapStyle.None) { EndCap.GetCustomCapPath(out endCapPath, out inset); len -= inset * scale; } g.DrawLine(pen, 0, y, 0, len); g.Restore(state); pen = e.Cache.GetPen(Border.Color, 1, Border.DashStyle); if (StartCap.Style != CapStyle.None) { state = g.Save(); g.TranslateTransform(x1, y1); g.RotateTransform(180 - angle); g.ScaleTransform(scale, scale); g.DrawPath(pen, startCapPath); g.Restore(state); } if (EndCap.Style != CapStyle.None) { state = g.Save(); g.TranslateTransform(x2, y2); g.RotateTransform(-angle); g.ScaleTransform(scale, scale); g.DrawPath(pen, endCapPath); g.Restore(state); } } if (report != null && report.SmoothGraphics && Diagonal) { g.InterpolationMode = InterpolationMode.Default; g.SmoothingMode = SmoothingMode.Default; } } /// public override List Validate() { List listError = new List(); if (Height == 0 && Width == 0) listError.Add(new ValidationError(Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,IncorrectSize"), this)); if (Name == "") listError.Add(new ValidationError(Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,UnnamedObject"), this)); if (Parent is ReportComponentBase && !Validator.RectContainInOtherRect((Parent as ReportComponentBase).AbsBounds, this.AbsBounds)) listError.Add(new ValidationError(Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,OutOfBounds"), this)); return listError; } /// public override void Serialize(FRWriter writer) { Border.SimpleBorder = true; base.Serialize(writer); LineObject c = writer.DiffObject as LineObject; if (Diagonal != c.Diagonal) writer.WriteBool("Diagonal", Diagonal); StartCap.Serialize("StartCap", writer, c.StartCap); EndCap.Serialize("EndCap", writer, c.EndCap); if (DashPattern?.Count > 0) writer.WriteValue("DashPattern", DashPattern); } #endregion /// /// Initializes a new instance of the class with default settings. /// public LineObject() { startCap = new CapSettings(); endCap = new CapSettings(); FlagSimpleBorder = true; FlagUseFill = false; dashPattern = new FloatCollection(); } } }