using System; using System.Drawing; using System.Drawing.Drawing2D; using System.ComponentModel; using FastReport.Utils; using System.Drawing.Design; namespace FastReport { /// /// Specifies the style of a border line. /// public enum LineStyle { /// /// Specifies a solid line. /// Solid, /// /// Specifies a line consisting of dashes. /// Dash, /// /// Specifies a line consisting of dots. /// Dot, /// /// Specifies a line consisting of a repeating pattern of dash-dot. /// DashDot, /// /// Specifies a line consisting of a repeating pattern of dash-dot-dot. /// DashDotDot, /// /// Specifies a double line. /// Double, /// /// Specifies a custom line. /// Custom } /// /// Specifies the sides of a border. /// [Flags] public enum BorderLines { /// /// Specifies no border lines. /// None = 0, /// /// Specifies the left border line. /// Left = 1, /// /// Specifies the right border line. /// Right = 2, /// /// Specifies the top border line. /// Top = 4, /// /// Specifies the bottom border line. /// Bottom = 8, /// /// Specifies all border lines. /// All = 15 } /// /// Represents a single border line. /// [TypeConverter(typeof(FastReport.TypeConverters.FRExpandableObjectConverter))] public class BorderLine { #region Fields private Color color; private LineStyle style; private float width; #endregion #region Properties /// /// Gets or sets a color of the line. /// [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))] public Color Color { get { return color; } set { color = value; } } /// /// Gets or sets a style of the line. /// [DefaultValue(LineStyle.Solid)] [Editor("FastReport.TypeEditors.LineStyleEditor, FastReport", typeof(UITypeEditor))] public LineStyle Style { get { return style; } set { style = value; } } /// /// Gets or sets a width of the line, in pixels. /// [DefaultValue(1f)] public float Width { get { return width; } set { width = value; } } internal DashStyle DashStyle { get { DashStyle[] styles = new DashStyle[] { DashStyle.Solid, DashStyle.Dash, DashStyle.Dot, DashStyle.DashDot, DashStyle.DashDotDot, DashStyle.Solid }; return styles[(int)Style]; } } #endregion #region Private Methods private bool ShouldSerializeColor() { return Color != Color.Black; } internal bool ShouldSerialize() { return Width != 1 || Style != LineStyle.Solid || Color != Color.Black; } #endregion #region Public Methods internal BorderLine Clone() { BorderLine result = new BorderLine(); result.Assign(this); return result; } internal void Assign(BorderLine src) { Color = src.Color; Style = src.Style; Width = src.Width; } /// public override bool Equals(object obj) { BorderLine line = obj as BorderLine; return line != null && Width == line.Width && Color == line.Color && Style == line.Style; } /// public override int GetHashCode() { return Color.GetHashCode() ^ Style.GetHashCode() ^ Width.GetHashCode(); } internal void Draw(FRPaintEventArgs e, float x, float y, float x1, float y1, bool reverseGaps, bool gap1, bool gap2) { IGraphics g = e.Graphics; int penWidth = (int)Math.Round(Width * e.ScaleX); if (penWidth <= 0) penWidth = 1; using (Pen pen = new Pen(Color, penWidth)) { pen.DashStyle = DashStyle; pen.StartCap = LineCap.Square; pen.EndCap = LineCap.Square; if (pen.DashStyle != DashStyle.Solid) { float patternWidth = 0; foreach (float w in pen.DashPattern) patternWidth += w * pen.Width; if (y == y1) pen.DashOffset = (x - ((int)(x / patternWidth)) * patternWidth) / pen.Width; else pen.DashOffset = (y - ((int)(y / patternWidth)) * patternWidth) / pen.Width; } if (Style != LineStyle.Double) g.DrawLine(pen, x, y, x1, y1); else { // we have to correctly draw inner and outer lines of a double line float g1 = gap1 ? pen.Width : 0; float g2 = gap2 ? pen.Width : 0; float g3 = -g1; float g4 = -g2; if (reverseGaps) { g1 = -g1; g2 = -g2; g3 = -g3; g4 = -g4; } if (x == x1) { g.DrawLine(pen, x - pen.Width, y + g1, x1 - pen.Width, y1 - g2); g.DrawLine(pen, x + pen.Width, y + g3, x1 + pen.Width, y1 - g4); } else { g.DrawLine(pen, x + g1, y - pen.Width, x1 - g2, y1 - pen.Width); g.DrawLine(pen, x + g3, y + pen.Width, x1 - g4, y1 + pen.Width); } } } } internal void Serialize(FRWriter writer, string prefix, BorderLine c) { if (Color != c.Color) writer.WriteValue(prefix + ".Color", Color); if (Style != c.Style) writer.WriteValue(prefix + ".Style", Style); if (Width != c.Width) writer.WriteFloat(prefix + ".Width", Width); } public BorderLine() { color = Color.Black; width = 1; } #endregion } /// /// Represents a border around the report object. /// /// /// Border consists of four lines. Each line has own color, style and width. Lines are accessible through /// , , , properties. /// /// To turn on and off the lines, use the property. To set the same color, style or width /// for each line, use , , properties of the Border. /// [TypeConverter(typeof(FastReport.TypeConverters.FRExpandableObjectConverter))] [Editor("FastReport.TypeEditors.BorderEditor, FastReport", typeof(UITypeEditor))] public class Border { #region Fields private bool shadow; private float shadowWidth; private Color shadowColor; private BorderLines lines; private BorderLine leftLine; private BorderLine topLine; private BorderLine rightLine; private BorderLine bottomLine; private bool simpleBorder; #endregion #region Properties /// /// Gets or sets a color of the border. /// /// /// This property actually returns a color of the . When you assign a value /// to this property, the value will be set to each border line. /// [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))] public Color Color { get { return leftLine.Color; } set { leftLine.Color = value; rightLine.Color = value; topLine.Color = value; bottomLine.Color = value; } } /// /// Gets or sets a value determines whether to draw a shadow. /// [DefaultValue(false)] public bool Shadow { get { return shadow; } set { shadow = value; } } /// /// Gets or sets a shadow width, in pixels. /// [DefaultValue(4f)] public float ShadowWidth { get { return shadowWidth; } set { shadowWidth = value; } } /// /// Gets or sets a shadow color. /// [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))] public Color ShadowColor { get { return shadowColor; } set { shadowColor = value; } } /// /// Gets or sets a style of the border. /// /// /// This property actually returns a style of the . When you assign a value /// to this property, the value will be set to each border line. /// [DefaultValue(LineStyle.Solid)] [Editor("FastReport.TypeEditors.LineStyleEditor, FastReport", typeof(UITypeEditor))] public LineStyle Style { get { return leftLine.Style; } set { leftLine.Style = value; rightLine.Style = value; topLine.Style = value; bottomLine.Style = value; } } /// /// Gets or sets a visible lines of a border. /// [DefaultValue(BorderLines.None)] [Editor("FastReport.TypeEditors.BorderLinesEditor, FastReport", typeof(UITypeEditor))] public BorderLines Lines { get { return lines; } set { lines = value; } } /// /// Gets or sets a width of the border, in pixels. /// /// /// This property actually returns a width of the . When you assign a value /// to this property, the value will be set to each border line. /// [DefaultValue(1f)] public float Width { get { return leftLine.Width; } set { leftLine.Width = value; rightLine.Width = value; topLine.Width = value; bottomLine.Width = value; } } /// /// Gets or sets the left line of the border. /// public BorderLine LeftLine { get { return leftLine; } set { leftLine = value; } } /// /// Gets or sets the top line of the border. /// public BorderLine TopLine { get { return topLine; } set { topLine = value; } } /// /// Gets or sets the right line of the border. /// public BorderLine RightLine { get { return rightLine; } set { rightLine = value; } } /// /// Gets or sets the bottom line of the border. /// public BorderLine BottomLine { get { return bottomLine; } set { bottomLine = value; } } /// /// Gets or sets a value determines that Border must serialize only one line. /// /// /// This property is for internal use only. /// [Browsable(false)] public bool SimpleBorder { get { return simpleBorder; } set { simpleBorder = value; } } internal DashStyle DashStyle { get { return leftLine.DashStyle; } } #endregion #region Private Methods private bool ShouldSerializeLeftLine() { return LeftLine.ShouldSerialize(); } private bool ShouldSerializeTopLine() { return TopLine.ShouldSerialize(); } private bool ShouldSerializeRightLine() { return RightLine.ShouldSerialize(); } private bool ShouldSerializeBottomLine() { return BottomLine.ShouldSerialize(); } private bool ShouldSerializeColor() { return Color != Color.Black; } private bool ShouldSerializeShadowColor() { return ShadowColor != Color.Black; } #endregion #region Internal Methods internal void ZoomBorder(float zoom) { LeftLine.Width *= zoom; if (leftLine.Width > 0 && leftLine.Width < 1) LeftLine.Width = 1; RightLine.Width *= zoom; if (rightLine.Width > 0 && rightLine.Width < 1) RightLine.Width = 1; TopLine.Width *= zoom; if (topLine.Width > 0 && topLine.Width < 1) TopLine.Width = 1; BottomLine.Width *= zoom; if (bottomLine.Width > 0 && bottomLine.Width < 1) BottomLine.Width = 1; } #endregion #region Public Methods /// /// Creates the exact copy of this Border. /// /// A copy of this border. public Border Clone() { Border result = new Border(this); return result; } /// public override bool Equals(object obj) { Border b = obj as Border; return b != null && Lines == b.Lines && LeftLine.Equals(b.LeftLine) && TopLine.Equals(b.TopLine) && RightLine.Equals(b.RightLine) && BottomLine.Equals(b.BottomLine) && Shadow == b.Shadow && ShadowColor == b.ShadowColor && ShadowWidth == b.ShadowWidth; } /// public override int GetHashCode() { return Lines.GetHashCode() ^ (Shadow.GetHashCode() + 16) ^ ShadowColor.GetHashCode() ^ (ShadowWidth.GetHashCode() + 32) ^ (LeftLine.GetHashCode() << 1) ^ (TopLine.GetHashCode() << 2) ^ (RightLine.GetHashCode() << 3) ^ (BottomLine.GetHashCode() << 4); } /// /// Serializes the border. /// /// Writer object. /// Border property name. /// Another Border to compare with. /// /// This method is for internal use only. /// public void Serialize(FRWriter writer, string prefix, Border c) { if (Shadow != c.Shadow) writer.WriteBool(prefix + ".Shadow", Shadow); if (ShadowWidth != c.ShadowWidth) writer.WriteFloat(prefix + ".ShadowWidth", ShadowWidth); if (ShadowColor != c.ShadowColor) writer.WriteValue(prefix + ".ShadowColor", ShadowColor); if (!SimpleBorder) { if (Lines != c.Lines) writer.WriteValue(prefix + ".Lines", Lines); if (Lines != BorderLines.None || Color != Color.Black) { if (LeftLine.Equals(RightLine) && LeftLine.Equals(TopLine) && LeftLine.Equals(BottomLine) && c.LeftLine.Equals(c.RightLine) && c.LeftLine.Equals(c.TopLine) && c.LeftLine.Equals(c.BottomLine)) LeftLine.Serialize(writer, prefix, c.LeftLine); else { LeftLine.Serialize(writer, prefix + ".LeftLine", c.LeftLine); TopLine.Serialize(writer, prefix + ".TopLine", c.TopLine); RightLine.Serialize(writer, prefix + ".RightLine", c.RightLine); BottomLine.Serialize(writer, prefix + ".BottomLine", c.BottomLine); } } } else LeftLine.Serialize(writer, prefix, c.LeftLine); } /// /// Draw the border using draw event arguments and specified bounding rectangle. /// /// Draw event arguments. /// Bounding rectangle. /// /// This method is for internal use only. /// public void Draw(FRPaintEventArgs e, RectangleF rect) { IGraphics g = e.Graphics; rect.X *= e.ScaleX; rect.Y *= e.ScaleY; rect.Width *= e.ScaleX; rect.Height *= e.ScaleY; if (Shadow) { //int d = (int)Math.Round(ShadowWidth * e.ScaleX); //Pen pen = e.Cache.GetPen(ShadowColor, d, DashStyle.Solid); //g.DrawLine(pen, rect.Right + d / 2, rect.Top + d, rect.Right + d / 2, rect.Bottom); //g.DrawLine(pen, rect.Left + d, rect.Bottom + d / 2, rect.Right + d, rect.Bottom + d / 2); float d = ShadowWidth * e.ScaleX; Brush brush = e.Cache.GetBrush(ShadowColor); g.FillRectangle(brush, rect.Left + d, rect.Bottom, rect.Width, d); g.FillRectangle(brush, rect.Right, rect.Top + d, d, rect.Height); } if (Lines != BorderLines.None) { // draw full frame as a rectangle with solid line only. Non-solid lines // should be drawn separately to avoid overlapping effect if (Lines == BorderLines.All && LeftLine.Equals(TopLine) && LeftLine.Equals(RightLine) && LeftLine.Equals(BottomLine) && LeftLine.Style == LineStyle.Solid) { Pen pen = e.Cache.GetPen(LeftLine.Color, (int)Math.Round(LeftLine.Width * e.ScaleX), LeftLine.DashStyle); g.DrawRectangle(pen, rect.Left, rect.Top, rect.Width, rect.Height); } else { if ((Lines & BorderLines.Left) != 0) LeftLine.Draw(e, rect.Left, rect.Top, rect.Left, rect.Bottom, true, (Lines & BorderLines.Top) != 0, (Lines & BorderLines.Bottom) != 0); if ((Lines & BorderLines.Right) != 0) RightLine.Draw(e, rect.Right, rect.Top, rect.Right, rect.Bottom, false, (Lines & BorderLines.Top) != 0, (Lines & BorderLines.Bottom) != 0); if ((Lines & BorderLines.Top) != 0) TopLine.Draw(e, rect.Left, rect.Top, rect.Right, rect.Top, true, (Lines & BorderLines.Left) != 0, (Lines & BorderLines.Right) != 0); if ((Lines & BorderLines.Bottom) != 0) BottomLine.Draw(e, rect.Left, rect.Bottom, rect.Right, rect.Bottom, false, (Lines & BorderLines.Left) != 0, (Lines & BorderLines.Right) != 0); } } } #endregion /// /// Initializes a new instance of the class with default settings. /// public Border() { leftLine = new BorderLine(); topLine = new BorderLine(); rightLine = new BorderLine(); bottomLine = new BorderLine(); shadowWidth = 4; shadowColor = Color.Black; } private Border(Border src) { lines = src.Lines; shadow = src.Shadow; shadowColor = src.ShadowColor; shadowWidth = src.ShadowWidth; leftLine = src.LeftLine.Clone(); topLine = src.TopLine.Clone(); rightLine = src.RightLine.Clone(); bottomLine = src.BottomLine.Clone(); //Fix 1513 //Width = src.Width; //1513 } } }