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();
}
}
}