Border.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. using System;
  2. using System.Drawing;
  3. using System.Drawing.Drawing2D;
  4. using System.ComponentModel;
  5. using FastReport.Utils;
  6. using System.Drawing.Design;
  7. namespace FastReport
  8. {
  9. /// <summary>
  10. /// Specifies the style of a border line.
  11. /// </summary>
  12. public enum LineStyle
  13. {
  14. /// <summary>
  15. /// Specifies a solid line.
  16. /// </summary>
  17. Solid,
  18. /// <summary>
  19. /// Specifies a line consisting of dashes.
  20. /// </summary>
  21. Dash,
  22. /// <summary>
  23. /// Specifies a line consisting of dots.
  24. /// </summary>
  25. Dot,
  26. /// <summary>
  27. /// Specifies a line consisting of a repeating pattern of dash-dot.
  28. /// </summary>
  29. DashDot,
  30. /// <summary>
  31. /// Specifies a line consisting of a repeating pattern of dash-dot-dot.
  32. /// </summary>
  33. DashDotDot,
  34. /// <summary>
  35. /// Specifies a double line.
  36. /// </summary>
  37. Double,
  38. /// <summary>
  39. /// Specifies a custom line.
  40. /// </summary>
  41. Custom
  42. }
  43. /// <summary>
  44. /// Specifies the sides of a border.
  45. /// </summary>
  46. [Flags]
  47. public enum BorderLines
  48. {
  49. /// <summary>
  50. /// Specifies no border lines.
  51. /// </summary>
  52. None = 0,
  53. /// <summary>
  54. /// Specifies the left border line.
  55. /// </summary>
  56. Left = 1,
  57. /// <summary>
  58. /// Specifies the right border line.
  59. /// </summary>
  60. Right = 2,
  61. /// <summary>
  62. /// Specifies the top border line.
  63. /// </summary>
  64. Top = 4,
  65. /// <summary>
  66. /// Specifies the bottom border line.
  67. /// </summary>
  68. Bottom = 8,
  69. /// <summary>
  70. /// Specifies all border lines.
  71. /// </summary>
  72. All = 15
  73. }
  74. /// <summary>
  75. /// Represents a single border line.
  76. /// </summary>
  77. [TypeConverter(typeof(FastReport.TypeConverters.FRExpandableObjectConverter))]
  78. public class BorderLine
  79. {
  80. #region Fields
  81. private Color color;
  82. private LineStyle style;
  83. private float width;
  84. #endregion
  85. #region Properties
  86. /// <summary>
  87. /// Gets or sets a color of the line.
  88. /// </summary>
  89. [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]
  90. public Color Color
  91. {
  92. get { return color; }
  93. set { color = value; }
  94. }
  95. /// <summary>
  96. /// Gets or sets a style of the line.
  97. /// </summary>
  98. [DefaultValue(LineStyle.Solid)]
  99. [Editor("FastReport.TypeEditors.LineStyleEditor, FastReport", typeof(UITypeEditor))]
  100. public LineStyle Style
  101. {
  102. get { return style; }
  103. set { style = value; }
  104. }
  105. /// <summary>
  106. /// Gets or sets a width of the line, in pixels.
  107. /// </summary>
  108. [DefaultValue(1f)]
  109. public float Width
  110. {
  111. get { return width; }
  112. set { width = value; }
  113. }
  114. internal DashStyle DashStyle
  115. {
  116. get
  117. {
  118. DashStyle[] styles = new DashStyle[] {
  119. DashStyle.Solid, DashStyle.Dash, DashStyle.Dot, DashStyle.DashDot, DashStyle.DashDotDot, DashStyle.Solid };
  120. return styles[(int)Style];
  121. }
  122. }
  123. #endregion
  124. #region Private Methods
  125. private bool ShouldSerializeColor()
  126. {
  127. return Color != Color.Black;
  128. }
  129. internal bool ShouldSerialize()
  130. {
  131. return Width != 1 || Style != LineStyle.Solid || Color != Color.Black;
  132. }
  133. #endregion
  134. #region Public Methods
  135. internal BorderLine Clone()
  136. {
  137. BorderLine result = new BorderLine();
  138. result.Assign(this);
  139. return result;
  140. }
  141. internal void Assign(BorderLine src)
  142. {
  143. Color = src.Color;
  144. Style = src.Style;
  145. Width = src.Width;
  146. }
  147. /// <inheritdoc/>
  148. public override bool Equals(object obj)
  149. {
  150. BorderLine line = obj as BorderLine;
  151. return line != null && Width == line.Width && Color == line.Color && Style == line.Style;
  152. }
  153. /// <inheritdoc/>
  154. public override int GetHashCode()
  155. {
  156. return Color.GetHashCode() ^ Style.GetHashCode() ^ Width.GetHashCode();
  157. }
  158. internal void Draw(FRPaintEventArgs e, float x, float y, float x1, float y1,
  159. bool reverseGaps, bool gap1, bool gap2)
  160. {
  161. IGraphics g = e.Graphics;
  162. int penWidth = (int)Math.Round(Width * e.ScaleX);
  163. if (penWidth <= 0)
  164. penWidth = 1;
  165. using (Pen pen = new Pen(Color, penWidth))
  166. {
  167. pen.DashStyle = DashStyle;
  168. pen.StartCap = LineCap.Square;
  169. pen.EndCap = LineCap.Square;
  170. if (pen.DashStyle != DashStyle.Solid)
  171. {
  172. float patternWidth = 0;
  173. foreach (float w in pen.DashPattern)
  174. patternWidth += w * pen.Width;
  175. if (y == y1)
  176. pen.DashOffset = (x - ((int)(x / patternWidth)) * patternWidth) / pen.Width;
  177. else
  178. pen.DashOffset = (y - ((int)(y / patternWidth)) * patternWidth) / pen.Width;
  179. }
  180. if (Style != LineStyle.Double)
  181. g.DrawLine(pen, x, y, x1, y1);
  182. else
  183. {
  184. // we have to correctly draw inner and outer lines of a double line
  185. float g1 = gap1 ? pen.Width : 0;
  186. float g2 = gap2 ? pen.Width : 0;
  187. float g3 = -g1;
  188. float g4 = -g2;
  189. if (reverseGaps)
  190. {
  191. g1 = -g1;
  192. g2 = -g2;
  193. g3 = -g3;
  194. g4 = -g4;
  195. }
  196. if (x == x1)
  197. {
  198. g.DrawLine(pen, x - pen.Width, y + g1, x1 - pen.Width, y1 - g2);
  199. g.DrawLine(pen, x + pen.Width, y + g3, x1 + pen.Width, y1 - g4);
  200. }
  201. else
  202. {
  203. g.DrawLine(pen, x + g1, y - pen.Width, x1 - g2, y1 - pen.Width);
  204. g.DrawLine(pen, x + g3, y + pen.Width, x1 - g4, y1 + pen.Width);
  205. }
  206. }
  207. }
  208. }
  209. internal void Serialize(FRWriter writer, string prefix, BorderLine c)
  210. {
  211. if (Color != c.Color)
  212. writer.WriteValue(prefix + ".Color", Color);
  213. if (Style != c.Style)
  214. writer.WriteValue(prefix + ".Style", Style);
  215. if (Width != c.Width)
  216. writer.WriteFloat(prefix + ".Width", Width);
  217. }
  218. public BorderLine()
  219. {
  220. color = Color.Black;
  221. width = 1;
  222. }
  223. #endregion
  224. }
  225. /// <summary>
  226. /// Represents a border around the report object.
  227. /// </summary>
  228. /// <remarks>
  229. /// Border consists of four lines. Each line has own color, style and width. Lines are accessible through
  230. /// <see cref="LeftLine"/>, <see cref="RightLine"/>, <see cref="TopLine"/>, <see cref="BottomLine"/> properties.
  231. /// <para/>
  232. /// To turn on and off the lines, use the <see cref="Lines"/> property. To set the same color, style or width
  233. /// for each line, use <see cref="Color"/>, <see cref="Style"/>, <see cref="Width"/> properties of the <b>Border</b>.
  234. /// </remarks>
  235. [TypeConverter(typeof(FastReport.TypeConverters.FRExpandableObjectConverter))]
  236. [Editor("FastReport.TypeEditors.BorderEditor, FastReport", typeof(UITypeEditor))]
  237. public class Border
  238. {
  239. #region Fields
  240. private bool shadow;
  241. private float shadowWidth;
  242. private Color shadowColor;
  243. private BorderLines lines;
  244. private BorderLine leftLine;
  245. private BorderLine topLine;
  246. private BorderLine rightLine;
  247. private BorderLine bottomLine;
  248. private bool simpleBorder;
  249. #endregion
  250. #region Properties
  251. /// <summary>
  252. /// Gets or sets a color of the border.
  253. /// </summary>
  254. /// <remarks>
  255. /// This property actually returns a color of the <see cref="LeftLine"/>. When you assign a value
  256. /// to this property, the value will be set to each border line.
  257. /// </remarks>
  258. [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]
  259. public Color Color
  260. {
  261. get { return leftLine.Color; }
  262. set
  263. {
  264. leftLine.Color = value;
  265. rightLine.Color = value;
  266. topLine.Color = value;
  267. bottomLine.Color = value;
  268. }
  269. }
  270. /// <summary>
  271. /// Gets or sets a value determines whether to draw a shadow.
  272. /// </summary>
  273. [DefaultValue(false)]
  274. public bool Shadow
  275. {
  276. get { return shadow; }
  277. set { shadow = value; }
  278. }
  279. /// <summary>
  280. /// Gets or sets a shadow width, in pixels.
  281. /// </summary>
  282. [DefaultValue(4f)]
  283. public float ShadowWidth
  284. {
  285. get { return shadowWidth; }
  286. set { shadowWidth = value; }
  287. }
  288. /// <summary>
  289. /// Gets or sets a shadow color.
  290. /// </summary>
  291. [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))]
  292. public Color ShadowColor
  293. {
  294. get { return shadowColor; }
  295. set { shadowColor = value; }
  296. }
  297. /// <summary>
  298. /// Gets or sets a style of the border.
  299. /// </summary>
  300. /// <remarks>
  301. /// This property actually returns a style of the <see cref="LeftLine"/>. When you assign a value
  302. /// to this property, the value will be set to each border line.
  303. /// </remarks>
  304. [DefaultValue(LineStyle.Solid)]
  305. [Editor("FastReport.TypeEditors.LineStyleEditor, FastReport", typeof(UITypeEditor))]
  306. public LineStyle Style
  307. {
  308. get { return leftLine.Style; }
  309. set
  310. {
  311. leftLine.Style = value;
  312. rightLine.Style = value;
  313. topLine.Style = value;
  314. bottomLine.Style = value;
  315. }
  316. }
  317. /// <summary>
  318. /// Gets or sets a visible lines of a border.
  319. /// </summary>
  320. [DefaultValue(BorderLines.None)]
  321. [Editor("FastReport.TypeEditors.BorderLinesEditor, FastReport", typeof(UITypeEditor))]
  322. public BorderLines Lines
  323. {
  324. get { return lines; }
  325. set { lines = value; }
  326. }
  327. /// <summary>
  328. /// Gets or sets a width of the border, in pixels.
  329. /// </summary>
  330. /// <remarks>
  331. /// This property actually returns a width of the <see cref="LeftLine"/>. When you assign a value
  332. /// to this property, the value will be set to each border line.
  333. /// </remarks>
  334. [DefaultValue(1f)]
  335. public float Width
  336. {
  337. get { return leftLine.Width; }
  338. set
  339. {
  340. leftLine.Width = value;
  341. rightLine.Width = value;
  342. topLine.Width = value;
  343. bottomLine.Width = value;
  344. }
  345. }
  346. /// <summary>
  347. /// Gets or sets the left line of the border.
  348. /// </summary>
  349. public BorderLine LeftLine
  350. {
  351. get { return leftLine; }
  352. set { leftLine = value; }
  353. }
  354. /// <summary>
  355. /// Gets or sets the top line of the border.
  356. /// </summary>
  357. public BorderLine TopLine
  358. {
  359. get { return topLine; }
  360. set { topLine = value; }
  361. }
  362. /// <summary>
  363. /// Gets or sets the right line of the border.
  364. /// </summary>
  365. public BorderLine RightLine
  366. {
  367. get { return rightLine; }
  368. set { rightLine = value; }
  369. }
  370. /// <summary>
  371. /// Gets or sets the bottom line of the border.
  372. /// </summary>
  373. public BorderLine BottomLine
  374. {
  375. get { return bottomLine; }
  376. set { bottomLine = value; }
  377. }
  378. /// <summary>
  379. /// Gets or sets a value determines that <b>Border</b> must serialize only one line.
  380. /// </summary>
  381. /// <remarks>
  382. /// This property is for internal use only.
  383. /// </remarks>
  384. [Browsable(false)]
  385. public bool SimpleBorder
  386. {
  387. get { return simpleBorder; }
  388. set { simpleBorder = value; }
  389. }
  390. internal DashStyle DashStyle
  391. {
  392. get { return leftLine.DashStyle; }
  393. }
  394. #endregion
  395. #region Private Methods
  396. private bool ShouldSerializeLeftLine()
  397. {
  398. return LeftLine.ShouldSerialize();
  399. }
  400. private bool ShouldSerializeTopLine()
  401. {
  402. return TopLine.ShouldSerialize();
  403. }
  404. private bool ShouldSerializeRightLine()
  405. {
  406. return RightLine.ShouldSerialize();
  407. }
  408. private bool ShouldSerializeBottomLine()
  409. {
  410. return BottomLine.ShouldSerialize();
  411. }
  412. private bool ShouldSerializeColor()
  413. {
  414. return Color != Color.Black;
  415. }
  416. private bool ShouldSerializeShadowColor()
  417. {
  418. return ShadowColor != Color.Black;
  419. }
  420. #endregion
  421. #region Internal Methods
  422. internal void ZoomBorder(float zoom)
  423. {
  424. LeftLine.Width *= zoom;
  425. if (leftLine.Width > 0 && leftLine.Width < 1)
  426. LeftLine.Width = 1;
  427. RightLine.Width *= zoom;
  428. if (rightLine.Width > 0 && rightLine.Width < 1)
  429. RightLine.Width = 1;
  430. TopLine.Width *= zoom;
  431. if (topLine.Width > 0 && topLine.Width < 1)
  432. TopLine.Width = 1;
  433. BottomLine.Width *= zoom;
  434. if (bottomLine.Width > 0 && bottomLine.Width < 1)
  435. BottomLine.Width = 1;
  436. }
  437. #endregion
  438. #region Public Methods
  439. /// <summary>
  440. /// Creates the exact copy of this <b>Border</b>.
  441. /// </summary>
  442. /// <returns>A copy of this border.</returns>
  443. public Border Clone()
  444. {
  445. Border result = new Border(this);
  446. return result;
  447. }
  448. /// <inheritdoc/>
  449. public override bool Equals(object obj)
  450. {
  451. Border b = obj as Border;
  452. return b != null && Lines == b.Lines &&
  453. LeftLine.Equals(b.LeftLine) && TopLine.Equals(b.TopLine) &&
  454. RightLine.Equals(b.RightLine) && BottomLine.Equals(b.BottomLine) &&
  455. Shadow == b.Shadow && ShadowColor == b.ShadowColor && ShadowWidth == b.ShadowWidth;
  456. }
  457. /// <inheritdoc/>
  458. public override int GetHashCode()
  459. {
  460. return Lines.GetHashCode() ^ (Shadow.GetHashCode() + 16) ^ ShadowColor.GetHashCode() ^
  461. (ShadowWidth.GetHashCode() + 32) ^ (LeftLine.GetHashCode() << 1) ^ (TopLine.GetHashCode() << 2) ^
  462. (RightLine.GetHashCode() << 3) ^ (BottomLine.GetHashCode() << 4);
  463. }
  464. /// <summary>
  465. /// Serializes the border.
  466. /// </summary>
  467. /// <param name="writer">Writer object.</param>
  468. /// <param name="prefix">Border property name.</param>
  469. /// <param name="c">Another Border to compare with.</param>
  470. /// <remarks>
  471. /// This method is for internal use only.
  472. /// </remarks>
  473. public void Serialize(FRWriter writer, string prefix, Border c)
  474. {
  475. if (Shadow != c.Shadow)
  476. writer.WriteBool(prefix + ".Shadow", Shadow);
  477. if (ShadowWidth != c.ShadowWidth)
  478. writer.WriteFloat(prefix + ".ShadowWidth", ShadowWidth);
  479. if (ShadowColor != c.ShadowColor)
  480. writer.WriteValue(prefix + ".ShadowColor", ShadowColor);
  481. if (!SimpleBorder)
  482. {
  483. if (Lines != c.Lines)
  484. writer.WriteValue(prefix + ".Lines", Lines);
  485. if (Lines != BorderLines.None || Color != Color.Black)
  486. {
  487. if (LeftLine.Equals(RightLine) && LeftLine.Equals(TopLine) && LeftLine.Equals(BottomLine) &&
  488. c.LeftLine.Equals(c.RightLine) && c.LeftLine.Equals(c.TopLine) && c.LeftLine.Equals(c.BottomLine))
  489. LeftLine.Serialize(writer, prefix, c.LeftLine);
  490. else
  491. {
  492. LeftLine.Serialize(writer, prefix + ".LeftLine", c.LeftLine);
  493. TopLine.Serialize(writer, prefix + ".TopLine", c.TopLine);
  494. RightLine.Serialize(writer, prefix + ".RightLine", c.RightLine);
  495. BottomLine.Serialize(writer, prefix + ".BottomLine", c.BottomLine);
  496. }
  497. }
  498. }
  499. else
  500. LeftLine.Serialize(writer, prefix, c.LeftLine);
  501. }
  502. /// <summary>
  503. /// Draw the border using draw event arguments and specified bounding rectangle.
  504. /// </summary>
  505. /// <param name="e">Draw event arguments.</param>
  506. /// <param name="rect">Bounding rectangle.</param>
  507. /// <remarks>
  508. /// This method is for internal use only.
  509. /// </remarks>
  510. public void Draw(FRPaintEventArgs e, RectangleF rect)
  511. {
  512. IGraphics g = e.Graphics;
  513. rect.X *= e.ScaleX;
  514. rect.Y *= e.ScaleY;
  515. rect.Width *= e.ScaleX;
  516. rect.Height *= e.ScaleY;
  517. if (Shadow)
  518. {
  519. //int d = (int)Math.Round(ShadowWidth * e.ScaleX);
  520. //Pen pen = e.Cache.GetPen(ShadowColor, d, DashStyle.Solid);
  521. //g.DrawLine(pen, rect.Right + d / 2, rect.Top + d, rect.Right + d / 2, rect.Bottom);
  522. //g.DrawLine(pen, rect.Left + d, rect.Bottom + d / 2, rect.Right + d, rect.Bottom + d / 2);
  523. float d = ShadowWidth * e.ScaleX;
  524. Brush brush = e.Cache.GetBrush(ShadowColor);
  525. g.FillRectangle(brush, rect.Left + d, rect.Bottom, rect.Width, d);
  526. g.FillRectangle(brush, rect.Right, rect.Top + d, d, rect.Height);
  527. }
  528. if (Lines != BorderLines.None)
  529. {
  530. // draw full frame as a rectangle with solid line only. Non-solid lines
  531. // should be drawn separately to avoid overlapping effect
  532. if (Lines == BorderLines.All && LeftLine.Equals(TopLine) && LeftLine.Equals(RightLine) &&
  533. LeftLine.Equals(BottomLine) && LeftLine.Style == LineStyle.Solid)
  534. {
  535. Pen pen = e.Cache.GetPen(LeftLine.Color, (int)Math.Round(LeftLine.Width * e.ScaleX), LeftLine.DashStyle);
  536. g.DrawRectangle(pen, rect.Left, rect.Top, rect.Width, rect.Height);
  537. }
  538. else
  539. {
  540. if ((Lines & BorderLines.Left) != 0)
  541. LeftLine.Draw(e, rect.Left, rect.Top, rect.Left, rect.Bottom,
  542. true, (Lines & BorderLines.Top) != 0, (Lines & BorderLines.Bottom) != 0);
  543. if ((Lines & BorderLines.Right) != 0)
  544. RightLine.Draw(e, rect.Right, rect.Top, rect.Right, rect.Bottom,
  545. false, (Lines & BorderLines.Top) != 0, (Lines & BorderLines.Bottom) != 0);
  546. if ((Lines & BorderLines.Top) != 0)
  547. TopLine.Draw(e, rect.Left, rect.Top, rect.Right, rect.Top,
  548. true, (Lines & BorderLines.Left) != 0, (Lines & BorderLines.Right) != 0);
  549. if ((Lines & BorderLines.Bottom) != 0)
  550. BottomLine.Draw(e, rect.Left, rect.Bottom, rect.Right, rect.Bottom,
  551. false, (Lines & BorderLines.Left) != 0, (Lines & BorderLines.Right) != 0);
  552. }
  553. }
  554. }
  555. #endregion
  556. /// <summary>
  557. /// Initializes a new instance of the <see cref="Border"/> class with default settings.
  558. /// </summary>
  559. public Border()
  560. {
  561. leftLine = new BorderLine();
  562. topLine = new BorderLine();
  563. rightLine = new BorderLine();
  564. bottomLine = new BorderLine();
  565. shadowWidth = 4;
  566. shadowColor = Color.Black;
  567. }
  568. private Border(Border src)
  569. {
  570. lines = src.Lines;
  571. shadow = src.Shadow;
  572. shadowColor = src.ShadowColor;
  573. shadowWidth = src.ShadowWidth;
  574. leftLine = src.LeftLine.Clone();
  575. topLine = src.TopLine.Clone();
  576. rightLine = src.RightLine.Clone();
  577. bottomLine = src.BottomLine.Clone();
  578. //Fix 1513
  579. //Width = src.Width;
  580. //1513
  581. }
  582. }
  583. }