using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using FastReport.Utils;
using System.Drawing.Design;
namespace FastReport
{
///
/// Represents a zip code object.
///
///
/// This object is mainly used in Russia to print postal index on envelopes. It complies with the
/// GOST R 51506-99.
///
public partial class ZipCodeObject : ReportComponentBase
{
#region Fields
private float segmentWidth;
private float segmentHeight;
private float spacing;
private int segmentCount;
private bool showMarkers;
private bool showGrid;
private string dataColumn;
private string expression;
private string text;
private static List FDigits;
#endregion
#region Properties
///
/// Gets or sets the width of a single zipcode segment, in pixels.
///
[Category("Layout")]
[TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
public float SegmentWidth
{
get { return segmentWidth; }
set { segmentWidth = value; }
}
///
/// Gets or sets the height of a single zipcode segment, in pixels.
///
[Category("Layout")]
[TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
public float SegmentHeight
{
get { return segmentHeight; }
set { segmentHeight = value; }
}
///
/// Gets or sets the spacing between origins of segments, in pixels.
///
[Category("Layout")]
[TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
public float Spacing
{
get { return spacing; }
set { spacing = value; }
}
///
/// Gets or sets the number of segments in zipcode.
///
[Category("Layout")]
[DefaultValue(6)]
public int SegmentCount
{
get { return segmentCount; }
set { segmentCount = value; }
}
///
/// Gets or sets a value indicating whether the reference markers should be drawn.
///
///
/// Reference markers are used by postal service to automatically read the zipcode.
///
[Category("Behavior")]
[DefaultValue(true)]
public bool ShowMarkers
{
get { return showMarkers; }
set { showMarkers = value; }
}
///
/// Gets or sets a value indicating whether the segment grid should be drawn.
///
[Category("Behavior")]
[DefaultValue(true)]
public bool ShowGrid
{
get { return showGrid; }
set { showGrid = value; }
}
///
/// Gets or sets a data column name bound to this control.
///
///
/// Value must be in the form "Datasource.Column".
///
[Category("Data")]
[Editor("FastReport.TypeEditors.DataColumnEditor, FastReport", typeof(UITypeEditor))]
public string DataColumn
{
get { return dataColumn; }
set { dataColumn = value; }
}
///
/// Gets or sets an expression that contains the zip code.
///
[Category("Data")]
[Editor("FastReport.TypeEditors.ExpressionEditor, FastReport", typeof(UITypeEditor))]
public string Expression
{
get { return expression; }
set { expression = value; }
}
///
/// Gets or sets the zip code.
///
[Category("Data")]
public string Text
{
get { return text; }
set { text = value; }
}
#endregion
#region Private Methods
private void DrawSegmentGrid(FRPaintEventArgs e, float offsetX, float offsetY)
{
IGraphics g = e.Graphics;
SmoothingMode saveSmoothing = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.AntiAlias;
Brush b = e.Cache.GetBrush(Border.Color);
int[] grid = new int[] { 111111, 110001, 101001, 100101, 100011, 111111, 110001, 101001, 100101, 100011, 111111 };
float ratioX = segmentWidth / (Units.Centimeters * 0.5f);
float ratioY = segmentHeight / (Units.Centimeters * 1);
float pointSize = Units.Millimeters * 0.25f;
float y = AbsTop;
foreach (int gridRow in grid)
{
int row = gridRow;
float x = AbsLeft;
while (row > 0)
{
if (row % 10 == 1)
g.FillEllipse(b, (x + offsetX - pointSize / 2) * e.ScaleX, (y + offsetY - pointSize / 2) * e.ScaleY,
pointSize * e.ScaleX, pointSize * e.ScaleY);
row /= 10;
x += Units.Millimeters * 1 * ratioX;
}
y += Units.Millimeters * 1 * ratioY;
}
g.SmoothingMode = saveSmoothing;
}
private void DrawReferenceLine(FRPaintEventArgs e, float offsetX)
{
IGraphics g = e.Graphics;
Brush b = e.Cache.GetBrush(Border.Color);
g.FillRectangle(b,
new RectangleF((AbsLeft + offsetX) * e.ScaleX, AbsTop * e.ScaleY,
Units.Millimeters * 7 * e.ScaleX, Units.Millimeters * 2 * e.ScaleY));
// draw start line
if (offsetX == 0)
{
g.FillRectangle(b,
new RectangleF((AbsLeft + offsetX) * e.ScaleX, (AbsTop + Units.Millimeters * 3) * e.ScaleY,
Units.Millimeters * 7 * e.ScaleX, Units.Millimeters * 1 * e.ScaleY));
}
}
private void DrawSegment(FRPaintEventArgs e, int symbol, float offsetX)
{
IGraphics g = e.Graphics;
float offsetY = 0;
// draw marker
if (showMarkers)
{
DrawReferenceLine(e, offsetX);
if (offsetX == 0)
return;
offsetX += Units.Millimeters * 1;
offsetY = Units.Millimeters * 4;
}
else
{
// draw inside the object's area - important when you export the object
offsetX += Border.Width / 2;
offsetY += Border.Width / 2;
}
// draw grid
if (showGrid)
DrawSegmentGrid(e, offsetX, offsetY);
// draw symbol
if (symbol != -1)
{
Point[] digit = FDigits[symbol];
PointF[] path = new PointF[digit.Length];
float ratioX = segmentWidth / (Units.Centimeters * 0.5f);
float ratioY = segmentHeight / (Units.Centimeters * 1);
for (int i = 0; i < digit.Length; i++)
{
path[i] = new PointF((AbsLeft + digit[i].X * Units.Millimeters * ratioX + offsetX) * e.ScaleX,
(AbsTop + digit[i].Y * Units.Millimeters * ratioY + offsetY) * e.ScaleY);
}
using (Pen pen = new Pen(Border.Color, Border.Width * e.ScaleX))
{
pen.StartCap = LineCap.Round;
pen.EndCap = LineCap.Round;
pen.LineJoin = LineJoin.Round;
g.DrawLines(pen, path);
}
}
}
#endregion
#region Public Methods
///
public override void Assign(Base source)
{
base.Assign(source);
ZipCodeObject src = source as ZipCodeObject;
SegmentWidth = src.SegmentWidth;
SegmentHeight = src.SegmentHeight;
Spacing = src.Spacing;
SegmentCount = src.SegmentCount;
ShowMarkers = src.ShowMarkers;
ShowGrid = src.ShowGrid;
DataColumn = src.DataColumn;
Expression = src.Expression;
Text = src.Text;
}
///
public override void Draw(FRPaintEventArgs e)
{
Width = ((showMarkers ? 1 : 0) + segmentCount) * spacing;
Height = (showMarkers ? segmentHeight + Units.Millimeters * 4 : segmentHeight) + Border.Width;
base.Draw(e);
float offsetX = 0;
if (showMarkers)
{
// draw starting marker
DrawSegment(e, -1, 0);
offsetX += spacing;
}
string text = Text.PadLeft(segmentCount, '0');
text = text.Substring(0, segmentCount);
foreach (char ch in text)
{
int symbol = -1;
if (ch >= '0' && ch <= '9')
symbol = (int)ch - (int)'0';
DrawSegment(e, symbol, offsetX);
offsetX += spacing;
}
}
///
public override void Serialize(FRWriter writer)
{
ZipCodeObject c = writer.DiffObject as ZipCodeObject;
Border.SimpleBorder = true;
base.Serialize(writer);
if (FloatDiff(SegmentWidth, c.SegmentWidth))
writer.WriteFloat("SegmentWidth", SegmentWidth);
if (FloatDiff(SegmentHeight, c.SegmentHeight))
writer.WriteFloat("SegmentHeight", SegmentHeight);
if (FloatDiff(Spacing, c.Spacing))
writer.WriteFloat("Spacing", Spacing);
if (SegmentCount != c.SegmentCount)
writer.WriteInt("SegmentCount", SegmentCount);
if (ShowMarkers != c.ShowMarkers)
writer.WriteBool("ShowMarkers", ShowMarkers);
if (ShowGrid != c.ShowGrid)
writer.WriteBool("ShowGrid", ShowGrid);
if (DataColumn != c.DataColumn)
writer.WriteStr("DataColumn", DataColumn);
if (Expression != c.Expression)
writer.WriteStr("Expression", Expression);
if (Text != c.Text)
writer.WriteStr("Text", Text);
}
#endregion
#region Report Engine
///
public override string[] GetExpressions()
{
List expressions = new List();
expressions.AddRange(base.GetExpressions());
if (!String.IsNullOrEmpty(DataColumn))
expressions.Add(DataColumn);
if (!String.IsNullOrEmpty(Expression))
expressions.Add(Expression);
return expressions.ToArray();
}
///
public override void GetData()
{
base.GetData();
if (!String.IsNullOrEmpty(DataColumn))
{
object value = Report.GetColumnValue(DataColumn);
Text = value == null ? "" : value.ToString();
}
else if (!String.IsNullOrEmpty(Expression))
{
object value = Report.Calc(Expression);
Text = value == null ? "" : value.ToString();
}
}
#endregion
///
/// Initializes a new instance of the with the default settings.
///
public ZipCodeObject()
{
segmentWidth = Units.Centimeters * 0.5f;
segmentHeight = Units.Centimeters * 1;
spacing = Units.Centimeters * 0.9f;
segmentCount = 6;
showMarkers = true;
showGrid = true;
text = "123456";
dataColumn = "";
expression = "";
FlagSimpleBorder = true;
Border.Width = 3;
SetFlags(Flags.HasSmartTag, true);
}
static ZipCodeObject()
{
FDigits = new List();
FDigits.Add(new Point[] { new Point(0, 0), new Point(5, 0), new Point(5, 10), new Point(0, 10), new Point(0, 0) });
FDigits.Add(new Point[] { new Point(0, 5), new Point(5, 0), new Point(5, 10) });
FDigits.Add(new Point[] { new Point(0, 0), new Point(5, 0), new Point(5, 5), new Point(0, 10), new Point(5, 10) });
FDigits.Add(new Point[] { new Point(0, 0), new Point(5, 0), new Point(0, 5), new Point(5, 5), new Point(0, 10) });
FDigits.Add(new Point[] { new Point(0, 0), new Point(0, 5), new Point(5, 5), new Point(5, 0), new Point(5, 10) });
FDigits.Add(new Point[] { new Point(5, 0), new Point(0, 0), new Point(0, 5), new Point(5, 5), new Point(5, 10), new Point(0, 10) });
FDigits.Add(new Point[] { new Point(5, 0), new Point(0, 5), new Point(0, 10), new Point(5, 10), new Point(5, 5), new Point(0, 5) });
FDigits.Add(new Point[] { new Point(0, 0), new Point(5, 0), new Point(0, 5), new Point(0, 10) });
FDigits.Add(new Point[] { new Point(0, 5), new Point(0, 0), new Point(5, 0), new Point(5, 10), new Point(0, 10), new Point(0, 5), new Point(5, 5) });
FDigits.Add(new Point[] { new Point(5, 5), new Point(0, 5), new Point(0, 0), new Point(5, 0), new Point(5, 5), new Point(0, 10) });
}
}
}