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