LineObject.cs 7.6 KB

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