using System; using System.Drawing; using System.ComponentModel; using FastReport.Utils; using FastReport.Table; namespace FastReport { /// /// Represents a text object which draws each symbol of text in its own cell. /// /// /// The text may be aligned to left or right side, or centered. Use the /// property to do this. The "justify" align is not supported now, as well as vertical alignment. /// The cell size is defined in the and properties. /// These properties are 0 by default, in this case the size of cell is calculated automatically based /// on the object's Font. /// To define a spacing (gap) between cells, use the and /// properties. /// public partial class CellularTextObject : TextObject { #region Fields private float cellWidth; private float cellHeight; private float horzSpacing; private float vertSpacing; #endregion #region Properties /// /// Gets or sets the width of cell, in pixels. /// /// /// If zero width and/or height specified, the object will calculate the cell size /// automatically based on its font. /// [Category("Appearance")] [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")] public float CellWidth { get { return cellWidth; } set { cellWidth = value; } } /// /// Gets or sets the height of cell, in pixels. /// /// /// If zero width and/or height specified, the object will calculate the cell size /// automatically based on its font. /// [Category("Appearance")] [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")] public float CellHeight { get { return cellHeight; } set { cellHeight = value; } } /// /// Gets or sets the horizontal spacing between cells, in pixels. /// [Category("Appearance")] [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")] public float HorzSpacing { get { return horzSpacing; } set { horzSpacing = value; } } /// /// Gets or sets the vertical spacing between cells, in pixels. /// [Category("Appearance")] [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")] public float VertSpacing { get { return vertSpacing; } set { vertSpacing = value; } } #endregion #region Private Methods // use the TableObject to represent the contents. It's easier to export it later. private TableObject GetTable(bool autoRows) { TableObject table = new TableObject(); table.SetPrinting(IsPrinting); table.SetReport(Report); float cellWidth = CellWidth; float cellHeight = CellHeight; // calculate cellWidth, cellHeight automatically if (cellWidth == 0 || cellHeight == 0) { float fontHeight = Font.GetHeight() * 96f / DrawUtils.ScreenDpi; cellWidth = GetCellWidthInternal(fontHeight); cellHeight = cellWidth; } int colCount = (int)((Width + HorzSpacing + 1) / (cellWidth + HorzSpacing)); if (colCount == 0) colCount = 1; int rowCount = (int)((Height + VertSpacing + 1) / (cellHeight + VertSpacing)); if (rowCount == 0 || autoRows) rowCount = 1; table.ColumnCount = colCount; table.RowCount = rowCount; // process the text int row = 0; int lineBegin = 0; int lastSpace = 0; string text = Text.Replace("\r\n", "\n"); for (int i = 0; i < text.Length; i++) { bool isCRLF = text[i] == '\n'; if (text[i] == ' ' || isCRLF) lastSpace = i; if (i - lineBegin + 1 > colCount || isCRLF) { if (WordWrap && lastSpace > lineBegin) { AddText(table, row, text.Substring(lineBegin, lastSpace - lineBegin)); lineBegin = lastSpace + 1; } else if (i - lineBegin > 0) { AddText(table, row, text.Substring(lineBegin, i - lineBegin)); lineBegin = i; } else lineBegin = i + 1; lastSpace = lineBegin; row++; if (autoRows && row >= rowCount) { rowCount++; table.RowCount++; } } } // finish the last line if (lineBegin < text.Length) AddText(table, row, text.Substring(lineBegin, text.Length - lineBegin)); // set up cells appearance for (int i = 0; i < colCount; i++) { for (int j = 0; j < rowCount; j++) { TableCell cell = table[i, j]; cell.Border = Border.Clone(); cell.Fill = Fill.Clone(); cell.Font = Font; cell.TextFill = TextFill.Clone(); cell.HorzAlign = HorzAlign.Center; cell.VertAlign = VertAlign.Center; } } // set cell's width and height for (int i = 0; i < colCount; i++) { table.Columns[i].Width = cellWidth; } for (int i = 0; i < rowCount; i++) { table.Rows[i].Height = cellHeight; } // insert spacing between cells if (HorzSpacing > 0) { for (int i = 0; i < colCount - 1; i++) { TableColumn newColumn = new TableColumn(); newColumn.Width = HorzSpacing; table.Columns.Insert(i * 2 + 1, newColumn); } } if (VertSpacing > 0) { for (int i = 0; i < rowCount - 1; i++) { TableRow newRow = new TableRow(); newRow.Height = VertSpacing; table.Rows.Insert(i * 2 + 1, newRow); } } table.Left = AbsLeft; table.Top = AbsTop; table.Width = table.Columns[table.ColumnCount - 1].Right; table.Height = table.Rows[table.RowCount - 1].Bottom; return table; } private void AddText(TableObject table, int row, string text) { if (row >= table.RowCount) return; text = text.TrimEnd(' '); if (text.Length > table.ColumnCount) text = text.Substring(0, table.ColumnCount); int offset = 0; if (HorzAlign == HorzAlign.Right) offset = table.ColumnCount - text.Length; else if (HorzAlign == HorzAlign.Center) offset = (table.ColumnCount - text.Length) / 2; for (int i = 0; i < text.Length; i++) { table[i + offset, row].Text = text[i].ToString(); } } #endregion #region Public Methods /// public override void Assign(Base source) { base.Assign(source); CellularTextObject src = source as CellularTextObject; CellWidth = src.CellWidth; CellHeight = src.CellHeight; HorzSpacing = src.HorzSpacing; VertSpacing = src.VertSpacing; } /// public override void Serialize(FRWriter writer) { CellularTextObject c = writer.DiffObject as CellularTextObject; base.Serialize(writer); if (FloatDiff(CellWidth, c.CellWidth)) writer.WriteFloat("CellWidth", CellWidth); if (FloatDiff(CellHeight, c.CellHeight)) writer.WriteFloat("CellHeight", CellHeight); if (FloatDiff(HorzSpacing, c.HorzSpacing)) writer.WriteFloat("HorzSpacing", HorzSpacing); if (FloatDiff(VertSpacing, c.VertSpacing)) writer.WriteFloat("VertSpacing", VertSpacing); } /// public override void Draw(FRPaintEventArgs e) { using (TableObject table = GetTable()) { table.Draw(e); } } public TableObject GetTable() { return GetTable(false); } #endregion #region Report Engine /// public override float CalcHeight() { using (TableObject table = GetTable(true)) { return table.Height; } } #endregion /// /// Initializes a new instance of the class with the default settings. /// public CellularTextObject() { CanBreak = false; Border.Lines = BorderLines.All; } } }