CellularTextObject.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. using System;
  2. using System.Drawing;
  3. using System.ComponentModel;
  4. using FastReport.Utils;
  5. using FastReport.Table;
  6. namespace FastReport
  7. {
  8. /// <summary>
  9. /// Represents a text object which draws each symbol of text in its own cell.
  10. /// </summary>
  11. /// <remarks>
  12. /// <para/>The text may be aligned to left or right side, or centered. Use the <see cref="HorzAlign"/>
  13. /// property to do this. The "justify" align is not supported now, as well as vertical alignment.
  14. /// <para/>The cell size is defined in the <see cref="CellWidth"/> and <see cref="CellHeight"/> properties.
  15. /// These properties are 0 by default, in this case the size of cell is calculated automatically based
  16. /// on the object's <b>Font</b>.
  17. /// <para/>To define a spacing (gap) between cells, use the <see cref="HorzSpacing"/> and
  18. /// <see cref="VertSpacing"/> properties.
  19. /// </remarks>
  20. public partial class CellularTextObject : TextObject
  21. {
  22. #region Fields
  23. private float cellWidth;
  24. private float cellHeight;
  25. private float horzSpacing;
  26. private float vertSpacing;
  27. #endregion
  28. #region Properties
  29. /// <summary>
  30. /// Gets or sets the width of cell, in pixels.
  31. /// </summary>
  32. /// <remarks>
  33. /// If zero width and/or height specified, the object will calculate the cell size
  34. /// automatically based on its font.
  35. /// </remarks>
  36. [Category("Appearance")]
  37. [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
  38. public float CellWidth
  39. {
  40. get { return cellWidth; }
  41. set { cellWidth = value; }
  42. }
  43. /// <summary>
  44. /// Gets or sets the height of cell, in pixels.
  45. /// </summary>
  46. /// <remarks>
  47. /// If zero width and/or height specified, the object will calculate the cell size
  48. /// automatically based on its font.
  49. /// </remarks>
  50. [Category("Appearance")]
  51. [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
  52. public float CellHeight
  53. {
  54. get { return cellHeight; }
  55. set { cellHeight = value; }
  56. }
  57. /// <summary>
  58. /// Gets or sets the horizontal spacing between cells, in pixels.
  59. /// </summary>
  60. [Category("Appearance")]
  61. [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
  62. public float HorzSpacing
  63. {
  64. get { return horzSpacing; }
  65. set { horzSpacing = value; }
  66. }
  67. /// <summary>
  68. /// Gets or sets the vertical spacing between cells, in pixels.
  69. /// </summary>
  70. [Category("Appearance")]
  71. [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
  72. public float VertSpacing
  73. {
  74. get { return vertSpacing; }
  75. set { vertSpacing = value; }
  76. }
  77. #endregion
  78. #region Private Methods
  79. // use the TableObject to represent the contents. It's easier to export it later.
  80. private TableObject GetTable(bool autoRows)
  81. {
  82. TableObject table = new TableObject();
  83. table.SetPrinting(IsPrinting);
  84. table.SetReport(Report);
  85. float cellWidth = CellWidth;
  86. float cellHeight = CellHeight;
  87. // calculate cellWidth, cellHeight automatically
  88. if (cellWidth == 0 || cellHeight == 0)
  89. {
  90. float fontHeight = Font.GetHeight() * 96f / DrawUtils.ScreenDpi;
  91. cellWidth = GetCellWidthInternal(fontHeight);
  92. cellHeight = cellWidth;
  93. }
  94. int colCount = (int)((Width + HorzSpacing + 1) / (cellWidth + HorzSpacing));
  95. if (colCount == 0)
  96. colCount = 1;
  97. int rowCount = (int)((Height + VertSpacing + 1) / (cellHeight + VertSpacing));
  98. if (rowCount == 0 || autoRows)
  99. rowCount = 1;
  100. table.ColumnCount = colCount;
  101. table.RowCount = rowCount;
  102. // process the text
  103. int row = 0;
  104. int lineBegin = 0;
  105. int lastSpace = 0;
  106. string text = Text.Replace("\r\n", "\n");
  107. for (int i = 0; i < text.Length; i++)
  108. {
  109. bool isCRLF = text[i] == '\n';
  110. if (text[i] == ' ' || isCRLF)
  111. lastSpace = i;
  112. if (i - lineBegin + 1 > colCount || isCRLF)
  113. {
  114. if (WordWrap && lastSpace > lineBegin)
  115. {
  116. AddText(table, row, text.Substring(lineBegin, lastSpace - lineBegin));
  117. lineBegin = lastSpace + 1;
  118. }
  119. else if (i - lineBegin > 0)
  120. {
  121. AddText(table, row, text.Substring(lineBegin, i - lineBegin));
  122. lineBegin = i;
  123. }
  124. else
  125. lineBegin = i + 1;
  126. lastSpace = lineBegin;
  127. row++;
  128. if (autoRows && row >= rowCount)
  129. {
  130. rowCount++;
  131. table.RowCount++;
  132. }
  133. }
  134. }
  135. // finish the last line
  136. if (lineBegin < text.Length)
  137. AddText(table, row, text.Substring(lineBegin, text.Length - lineBegin));
  138. // set up cells appearance
  139. for (int i = 0; i < colCount; i++)
  140. {
  141. for (int j = 0; j < rowCount; j++)
  142. {
  143. TableCell cell = table[i, j];
  144. cell.Border = Border.Clone();
  145. cell.Fill = Fill.Clone();
  146. cell.Font = Font;
  147. cell.TextFill = TextFill.Clone();
  148. cell.HorzAlign = HorzAlign.Center;
  149. cell.VertAlign = VertAlign.Center;
  150. }
  151. }
  152. // set cell's width and height
  153. for (int i = 0; i < colCount; i++)
  154. {
  155. table.Columns[i].Width = cellWidth;
  156. }
  157. for (int i = 0; i < rowCount; i++)
  158. {
  159. table.Rows[i].Height = cellHeight;
  160. }
  161. // insert spacing between cells
  162. if (HorzSpacing > 0)
  163. {
  164. for (int i = 0; i < colCount - 1; i++)
  165. {
  166. TableColumn newColumn = new TableColumn();
  167. newColumn.Width = HorzSpacing;
  168. table.Columns.Insert(i * 2 + 1, newColumn);
  169. }
  170. }
  171. if (VertSpacing > 0)
  172. {
  173. for (int i = 0; i < rowCount - 1; i++)
  174. {
  175. TableRow newRow = new TableRow();
  176. newRow.Height = VertSpacing;
  177. table.Rows.Insert(i * 2 + 1, newRow);
  178. }
  179. }
  180. table.Left = AbsLeft;
  181. table.Top = AbsTop;
  182. table.Width = table.Columns[table.ColumnCount - 1].Right;
  183. table.Height = table.Rows[table.RowCount - 1].Bottom;
  184. return table;
  185. }
  186. private void AddText(TableObject table, int row, string text)
  187. {
  188. if (row >= table.RowCount)
  189. return;
  190. text = text.TrimEnd(' ');
  191. if (text.Length > table.ColumnCount)
  192. text = text.Substring(0, table.ColumnCount);
  193. int offset = 0;
  194. if (HorzAlign == HorzAlign.Right)
  195. offset = table.ColumnCount - text.Length;
  196. else if (HorzAlign == HorzAlign.Center)
  197. offset = (table.ColumnCount - text.Length) / 2;
  198. for (int i = 0; i < text.Length; i++)
  199. {
  200. table[i + offset, row].Text = text[i].ToString();
  201. }
  202. }
  203. #endregion
  204. #region Public Methods
  205. /// <inheritdoc/>
  206. public override void Assign(Base source)
  207. {
  208. base.Assign(source);
  209. CellularTextObject src = source as CellularTextObject;
  210. CellWidth = src.CellWidth;
  211. CellHeight = src.CellHeight;
  212. HorzSpacing = src.HorzSpacing;
  213. VertSpacing = src.VertSpacing;
  214. }
  215. /// <inheritdoc/>
  216. public override void Serialize(FRWriter writer)
  217. {
  218. CellularTextObject c = writer.DiffObject as CellularTextObject;
  219. base.Serialize(writer);
  220. if (FloatDiff(CellWidth, c.CellWidth))
  221. writer.WriteFloat("CellWidth", CellWidth);
  222. if (FloatDiff(CellHeight, c.CellHeight))
  223. writer.WriteFloat("CellHeight", CellHeight);
  224. if (FloatDiff(HorzSpacing, c.HorzSpacing))
  225. writer.WriteFloat("HorzSpacing", HorzSpacing);
  226. if (FloatDiff(VertSpacing, c.VertSpacing))
  227. writer.WriteFloat("VertSpacing", VertSpacing);
  228. }
  229. /// <inheritdoc/>
  230. public override void Draw(FRPaintEventArgs e)
  231. {
  232. using (TableObject table = GetTable())
  233. {
  234. table.Draw(e);
  235. }
  236. }
  237. public TableObject GetTable()
  238. {
  239. return GetTable(false);
  240. }
  241. #endregion
  242. #region Report Engine
  243. /// <inheritdoc/>
  244. public override float CalcHeight()
  245. {
  246. using (TableObject table = GetTable(true))
  247. {
  248. return table.Height;
  249. }
  250. }
  251. #endregion
  252. /// <summary>
  253. /// Initializes a new instance of the <see cref="CellularTextObject"/> class with the default settings.
  254. /// </summary>
  255. public CellularTextObject()
  256. {
  257. CanBreak = false;
  258. Border.Lines = BorderLines.All;
  259. }
  260. }
  261. }