LineObject.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.ComponentModel;
  5. using System.Drawing;
  6. using System.Drawing.Drawing2D;
  7. using FastReport.Utils;
  8. using System.Linq;
  9. namespace FastReport
  10. {
  11. /// <summary>
  12. /// Represents a line object.
  13. /// </summary>
  14. /// <remarks>
  15. /// Use the <b>Border.Width</b>, <b>Border.Style</b> and <b>Border.Color</b> properties to set
  16. /// the line width, style and color. Set the <see cref="Diagonal"/> property to <b>true</b>
  17. /// if you want to show a diagonal line.
  18. /// </remarks>
  19. public partial class LineObject : ReportComponentBase
  20. {
  21. #region Fields
  22. private bool diagonal;
  23. private CapSettings startCap;
  24. private CapSettings endCap;
  25. private FloatCollection dashPattern;
  26. #endregion
  27. #region Properties
  28. /// <summary>
  29. /// Gets or sets a value indicating that the line is diagonal.
  30. /// </summary>
  31. /// <remarks>
  32. /// If this property is <b>false</b>, the line can be only horizontal or vertical.
  33. /// </remarks>
  34. [DefaultValue(false)]
  35. [Category("Appearance")]
  36. public bool Diagonal
  37. {
  38. get { return diagonal; }
  39. set { diagonal = value; }
  40. }
  41. /// <summary>
  42. /// Gets or sets the start cap settings.
  43. /// </summary>
  44. [Category("Appearance")]
  45. public CapSettings StartCap
  46. {
  47. get { return startCap; }
  48. set { startCap = value; }
  49. }
  50. /// <summary>
  51. /// Gets or sets the end cap settings.
  52. /// </summary>
  53. [Category("Appearance")]
  54. public CapSettings EndCap
  55. {
  56. get { return endCap; }
  57. set { endCap = value; }
  58. }
  59. /// <summary>
  60. /// Gets or sets collection of values for custom dash pattern.
  61. /// </summary>
  62. /// <remarks>
  63. /// Each element should be a non-zero positive number.
  64. /// If the number is negative or zero, that number is replaced by one.
  65. /// </remarks>
  66. [Category("Appearance")]
  67. public FloatCollection DashPattern
  68. {
  69. get { return dashPattern; }
  70. set { dashPattern = value; }
  71. }
  72. #endregion
  73. #region Public Methods
  74. /// <inheritdoc/>
  75. public override void Assign(Base source)
  76. {
  77. base.Assign(source);
  78. LineObject src = source as LineObject;
  79. Diagonal = src.Diagonal;
  80. StartCap.Assign(src.StartCap);
  81. EndCap.Assign(src.EndCap);
  82. DashPattern.Assign(src.DashPattern);
  83. }
  84. /// <inheritdoc/>
  85. public override void Draw(FRPaintEventArgs e)
  86. {
  87. IGraphics g = e.Graphics;
  88. // draw marker when inserting a line
  89. if (Width == 0 && Height == 0)
  90. {
  91. g.DrawLine(Pens.Black, AbsLeft * e.ScaleX - 6, AbsTop * e.ScaleY, AbsLeft * e.ScaleX + 6, AbsTop * e.ScaleY);
  92. g.DrawLine(Pens.Black, AbsLeft * e.ScaleX, AbsTop * e.ScaleY - 6, AbsLeft * e.ScaleX, AbsTop * e.ScaleY + 6);
  93. return;
  94. }
  95. Report report = Report;
  96. if (report != null && report.SmoothGraphics)
  97. {
  98. g.InterpolationMode = InterpolationMode.HighQualityBicubic;
  99. g.SmoothingMode = SmoothingMode.AntiAlias;
  100. }
  101. Pen pen = e.Cache.GetPen(Border.Color, Border.Width * e.ScaleX, Border.DashStyle);
  102. DrawUtils.SetPenDashPatternOrStyle(DashPattern, pen, Border);
  103. if (!Diagonal)
  104. {
  105. if (Math.Abs(Width) > Math.Abs(Height))
  106. Height = 0;
  107. else
  108. Width = 0;
  109. }
  110. float x1 = AbsLeft * e.ScaleX;
  111. float y1 = AbsTop * e.ScaleY;
  112. float x2 = (AbsLeft + Width) * e.ScaleX;
  113. float y2 = (AbsTop + Height) * e.ScaleY;
  114. if (StartCap.Style == CapStyle.None && EndCap.Style == CapStyle.None)
  115. {
  116. g.DrawLine(pen, x1, y1, x2, y2);
  117. }
  118. else
  119. {
  120. // draw line caps manually. It is necessary for correct svg rendering
  121. float angle = (float)(Math.Atan2(x2 - x1, y2 - y1) / Math.PI * 180);
  122. float len = (float)Math.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
  123. float scale = Border.Width * e.ScaleX;
  124. IGraphicsState state = g.Save();
  125. g.TranslateTransform(x1, y1);
  126. g.RotateTransform(-angle);
  127. float y = 0;
  128. GraphicsPath startCapPath = null;
  129. GraphicsPath endCapPath = null;
  130. float inset = 0;
  131. if (StartCap.Style != CapStyle.None)
  132. {
  133. StartCap.GetCustomCapPath(out startCapPath, out inset);
  134. y += inset * scale;
  135. }
  136. if (EndCap.Style != CapStyle.None)
  137. {
  138. EndCap.GetCustomCapPath(out endCapPath, out inset);
  139. len -= inset * scale;
  140. }
  141. g.DrawLine(pen, 0, y, 0, len);
  142. g.Restore(state);
  143. pen = e.Cache.GetPen(Border.Color, 1, Border.DashStyle);
  144. if (StartCap.Style != CapStyle.None)
  145. {
  146. state = g.Save();
  147. g.TranslateTransform(x1, y1);
  148. g.RotateTransform(180 - angle);
  149. g.ScaleTransform(scale, scale);
  150. g.DrawPath(pen, startCapPath);
  151. g.Restore(state);
  152. }
  153. if (EndCap.Style != CapStyle.None)
  154. {
  155. state = g.Save();
  156. g.TranslateTransform(x2, y2);
  157. g.RotateTransform(-angle);
  158. g.ScaleTransform(scale, scale);
  159. g.DrawPath(pen, endCapPath);
  160. g.Restore(state);
  161. }
  162. }
  163. if (report != null && report.SmoothGraphics && Diagonal)
  164. {
  165. g.InterpolationMode = InterpolationMode.Default;
  166. g.SmoothingMode = SmoothingMode.Default;
  167. }
  168. }
  169. /// <inheritdoc/>
  170. public override List<ValidationError> Validate()
  171. {
  172. List<ValidationError> listError = new List<ValidationError>();
  173. if (Height == 0 && Width == 0)
  174. listError.Add(new ValidationError(Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,IncorrectSize"), this));
  175. if (Name == "")
  176. listError.Add(new ValidationError(Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,UnnamedObject"), this));
  177. if (Parent is ReportComponentBase && !Validator.RectContainInOtherRect((Parent as ReportComponentBase).AbsBounds, this.AbsBounds))
  178. listError.Add(new ValidationError(Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,OutOfBounds"), this));
  179. return listError;
  180. }
  181. /// <inheritdoc/>
  182. public override void Serialize(FRWriter writer)
  183. {
  184. Border.SimpleBorder = true;
  185. base.Serialize(writer);
  186. LineObject c = writer.DiffObject as LineObject;
  187. if (Diagonal != c.Diagonal)
  188. writer.WriteBool("Diagonal", Diagonal);
  189. StartCap.Serialize("StartCap", writer, c.StartCap);
  190. EndCap.Serialize("EndCap", writer, c.EndCap);
  191. if (DashPattern?.Count > 0)
  192. writer.WriteValue("DashPattern", DashPattern);
  193. }
  194. #endregion
  195. /// <summary>
  196. /// Initializes a new instance of the <see cref="LineObject"/> class with default settings.
  197. /// </summary>
  198. public LineObject()
  199. {
  200. startCap = new CapSettings();
  201. endCap = new CapSettings();
  202. FlagSimpleBorder = true;
  203. FlagUseFill = false;
  204. dashPattern = new FloatCollection();
  205. }
  206. }
  207. }