LongTable.cs
  1. //
  2. // This code is part of Document Solutions for PDF demos.
  3. // Copyright (c) MESCIUS inc. All rights reserved.
  4. //
  5. using System;
  6. using System.IO;
  7. using System.Drawing;
  8. using System.Linq;
  9. using System.Collections.Generic;
  10. using GrapeCity.Documents.Pdf;
  11. using GrapeCity.Documents.Text;
  12. using GrapeCity.Documents.Layout;
  13. using GrapeCity.Documents.Layout.Composition;
  14. using GCTEXT = GrapeCity.Documents.Text;
  15. using GCDRAW = GrapeCity.Documents.Drawing;
  16.  
  17. namespace DsPdfWeb.Demos
  18. {
  19. // This demo creates a table with variable row height and spanning many pages,
  20. // using classes from the GrapeCity.Documents.Layout.Composition namespace.
  21. public class LongTable
  22. {
  23. string[] _headers;
  24. TextFormat _thFormat;
  25. TextFormat _tdFormat;
  26. float _resolution;
  27.  
  28. readonly List<LayoutRect> _rows = new();
  29. readonly List<LayoutRect> _columns = new();
  30. readonly List<Visual> _cells = new();
  31. readonly List<TextLayout> _texts = new();
  32.  
  33. GcPdfGraphics _g;
  34. View _pageView;
  35. Layer _textLayer;
  36. LayoutRect _bounds;
  37. Surface _sf;
  38.  
  39. public int CreatePDF(Stream stream)
  40. {
  41. var doc = new GcPdfDocument();
  42.  
  43. var page = doc.NewPage();
  44. var pageSize = page.Size;
  45. _g = page.Graphics;
  46.  
  47. _sf = new Surface();
  48. _pageView = _sf.CreateView(pageSize.Width, pageSize.Height);
  49. _textLayer = _pageView.CreateSubLayer();
  50. _resolution = _g.Resolution;
  51.  
  52. var marginsVisual = _pageView.CreateVisual((g, v) =>
  53. {
  54. g.FillRectangle(v.AsRectF(), Color.FromArgb(0xFF, 0xF8, 0xF8));
  55. });
  56. _bounds = marginsVisual.LayoutRect;
  57. _bounds.AnchorInflate(null, -_resolution);
  58. _sf.PerformLayout();
  59.  
  60. var noteBounds = AddNote("We create a table with a large number of variable height rows. " +
  61. "The table starts at a specified position on the first page, and spans multiple pages.");
  62.  
  63. var fc = FontCollection.SystemFonts;
  64. _thFormat = new TextFormat
  65. {
  66. Font = fc.FindFamilyName("Trebuchet MS", true) ?? fc.FindFamilyName("Arial", true),
  67. FontBold = true,
  68. ForeColor = Color.White
  69. };
  70. _tdFormat = new TextFormat
  71. {
  72. Font = fc.FindFamilyName("Trebuchet MS") ?? fc.FindFamilyName("Arial")
  73. };
  74.  
  75. _headers = new string[] { "#", "Lorem", "Ipsum" };
  76. CreateColumns();
  77.  
  78. var headerRowRect = CreateHeaderRow();
  79. headerRowRect.SetTop(noteBounds, AnchorParam.Bottom, _resolution / 2);
  80. FillHeaderRow(headerRowRect);
  81.  
  82. var prevRowRect = headerRowRect;
  83. var numberOfRows = Common.Util.NewRandom().Next(100, 500);
  84.  
  85. for (int i = 0; i < numberOfRows; i++)
  86. {
  87. var row = CreateRow((i & 1) != 0);
  88. var rc = row.LayoutRect;
  89. rc.SetTop(prevRowRect, AnchorParam.Bottom);
  90. if (!FillRow(i, rc))
  91. {
  92. row.Detach();
  93. CreateTableGrid();
  94. _sf.Render(_g);
  95.  
  96. _columns.Clear();
  97. _rows.Clear();
  98.  
  99. page = doc.NewPage();
  100. pageSize = page.Size;
  101. _g = page.Graphics;
  102.  
  103. _sf = new Surface();
  104. _pageView = _sf.CreateView(pageSize.Width, pageSize.Height);
  105. _textLayer = _pageView.CreateSubLayer();
  106.  
  107. marginsVisual = _pageView.CreateVisual((g, v) =>
  108. {
  109. g.FillRectangle(v.AsRectF(), Color.FromArgb(0xFF, 0xF8, 0xF8));
  110. });
  111. _bounds = marginsVisual.LayoutRect;
  112. _bounds.AnchorInflate(null, -_resolution);
  113. _sf.PerformLayout();
  114.  
  115. CreateColumns();
  116. headerRowRect = CreateHeaderRow();
  117. headerRowRect.SetTop(_bounds, AnchorParam.Top);
  118. FillHeaderRow(headerRowRect);
  119.  
  120. row = CreateRow((i & 1) != 0);
  121. rc = row.LayoutRect;
  122. rc.SetTop(headerRowRect, AnchorParam.Bottom);
  123.  
  124. RestoreRow(rc);
  125. }
  126. prevRowRect = rc;
  127. }
  128.  
  129. CreateTableGrid();
  130. _sf.Render(_g);
  131.  
  132. doc.Save(stream);
  133. return doc.Pages.Count;
  134. }
  135.  
  136. class TableGridInfo
  137. {
  138. public TableGridInfo(LayoutRect[] columns, LayoutRect[] rows)
  139. {
  140. Columns = columns;
  141. Rows = rows;
  142. }
  143. public readonly LayoutRect[] Columns;
  144. public readonly LayoutRect[] Rows;
  145. }
  146.  
  147. void CreateTableGrid()
  148. {
  149. var grid = _pageView.CreateVisual(false);
  150. grid.Tag = new TableGridInfo(_columns.ToArray(), _rows.ToArray());
  151. grid.Draw = (g, v) =>
  152. {
  153. var pen = new GCDRAW::Pen(Color.FromArgb(0xDD, 0xDD, 0xDD), 1);
  154. var tgi = (TableGridInfo)v.Tag;
  155. int lastColumnIndex = tgi.Columns.Length - 1;
  156. int lastRowIndex = tgi.Rows.Length - 1;
  157.  
  158. float xMin = tgi.Columns[0].P0X;
  159. float yMin = tgi.Rows[0].P0Y;
  160. float xMax = tgi.Columns[lastColumnIndex].P1X;
  161. float yMax = tgi.Rows[lastRowIndex].P2Y;
  162.  
  163. g.DrawRectangle(new RectangleF(xMin, yMin, xMax - xMin, yMax - yMin), pen);
  164. for (int i = 0; i < lastColumnIndex; i++)
  165. {
  166. float x = tgi.Columns[i].P1X;
  167. g.DrawLine(new PointF(x, yMin), new PointF(x, yMax), pen);
  168. }
  169. for (int i = 0; i < lastRowIndex; i++)
  170. {
  171. float y = tgi.Rows[i].P2Y;
  172. g.DrawLine(new PointF(xMin, y), new PointF(xMax, y), pen);
  173. }
  174. };
  175. }
  176.  
  177. void CreateColumns()
  178. {
  179. LayoutRect column1 = _pageView.CreateSpace().LayoutRect;
  180. LayoutRect column2 = _pageView.CreateSpace().LayoutRect;
  181. LayoutRect column3 = _pageView.CreateSpace().LayoutRect;
  182.  
  183. column1.AnchorTopBottom(_bounds, 0, 0);
  184. column2.AnchorTopBottom(_bounds, 0, 0);
  185. column3.AnchorTopBottom(_bounds, 0, 0);
  186.  
  187. column1.SetLeft(_bounds, AnchorParam.Left);
  188. column2.SetLeftAndOpposite(column1, AnchorParam.Right);
  189. column3.SetLeftAndOpposite(column2, AnchorParam.Right);
  190. column3.SetRight(_bounds, AnchorParam.Right);
  191.  
  192. column1.SetStarWidth(1);
  193. column2.SetStarWidth(3);
  194. column3.SetStarWidth(3);
  195.  
  196. _sf.PerformLayout();
  197.  
  198. _columns.Add(column1);
  199. _columns.Add(column2);
  200. _columns.Add(column3);
  201. }
  202.  
  203. LayoutRect CreateHeaderRow()
  204. {
  205. var rc = _pageView.CreateVisual((g, v) =>
  206. {
  207. g.FillRectangle(v.AsRectF(), Color.FromArgb(0x33, 0x77, 0xFF));
  208. }).LayoutRect;
  209. rc.AnchorLeftRight(_bounds, 0, 0);
  210. return rc;
  211. }
  212.  
  213. void FillHeaderRow(LayoutRect headerRowRect)
  214. {
  215. for (int i = 0; i < _columns.Count; i++)
  216. {
  217. var column = _columns[i];
  218. var tl = new TextLayout(_resolution)
  219. {
  220. MaxWidth = column.Width,
  221. TextAlignment = TextAlignment.Center,
  222. MarginLeft = 8,
  223. MarginRight = 8,
  224. MarginTop = 12
  225. };
  226. tl.Append(_headers[i], _thFormat);
  227. tl.PerformLayout();
  228.  
  229. var cell = _textLayer.CreateVisual();
  230. cell.Tag = tl;
  231. cell.Draw = (g, v) =>
  232. {
  233. g.DrawTextLayout((TextLayout)v.Tag, new PointF(0, 0));
  234. };
  235. var rc = cell.LayoutRect;
  236. rc.AnchorLeftRight(column, 0, 0);
  237. rc.SetTop(headerRowRect, AnchorParam.Top, 0);
  238. rc.SetHeight(tl.ContentHeight + 12 + 12);
  239. headerRowRect.AppendMinBottom(rc, AnchorParam.Bottom);
  240. }
  241. _rows.Add(headerRowRect);
  242. _sf.PerformLayout();
  243. }
  244.  
  245. Visual CreateRow(bool even)
  246. {
  247. var row = _pageView.CreateVisual();
  248. if (even)
  249. row.Draw = (g, v) => g.FillRectangle(v.AsRectF(), Color.FromArgb(0xF2, 0xF2, 0xF2));
  250. else
  251. row.Draw = (g, v) => g.FillRectangle(v.AsRectF(), Color.White);
  252. row.LayoutRect.AnchorLeftRight(_bounds, 0, 0);
  253. return row;
  254. }
  255.  
  256. bool FillRow(int index, LayoutRect rowRect)
  257. {
  258. _cells.Clear();
  259. _texts.Clear();
  260. for (int i = 0; i < _columns.Count; i++)
  261. {
  262. var column = _columns[i];
  263. var tl = new TextLayout(_resolution)
  264. {
  265. MaxWidth = column.Width,
  266. MarginAll = 8
  267. };
  268. if (i == 0)
  269. {
  270. tl.TextAlignment = TextAlignment.Center;
  271. tl.Append((index + 1).ToString(), _tdFormat);
  272. }
  273. else
  274. {
  275. // Add random data:
  276. tl.Append(Common.Util.LoremIpsum(1, 1, 2, 1, 15), _tdFormat);
  277. }
  278. tl.PerformLayout();
  279. _texts.Add(tl);
  280.  
  281. var cell = _textLayer.CreateVisual();
  282. cell.Tag = tl;
  283. cell.Draw = (g, v) =>
  284. {
  285. g.DrawTextLayout((TextLayout)v.Tag, new PointF(0, 0));
  286. };
  287. var rc = cell.LayoutRect;
  288. rc.AnchorLeftRight(column, 0, 0);
  289. rc.SetTop(rowRect, AnchorParam.Top, 0);
  290. rc.SetHeight(tl.ContentHeight + 8 + 8);
  291. rowRect.AppendMinBottom(rc, AnchorParam.Bottom);
  292. _cells.Add(cell);
  293. }
  294. _sf.PerformLayout();
  295.  
  296. if (rowRect.P2Y > _bounds.P2Y)
  297. {
  298. for (int i = 0; i < _cells.Count; i++)
  299. {
  300. _cells[i].Detach();
  301. }
  302. _cells.Clear();
  303. return false;
  304. }
  305.  
  306. _rows.Add(rowRect);
  307. return true;
  308. }
  309.  
  310. void RestoreRow(LayoutRect rowRect)
  311. {
  312. for (int i = 0; i < _columns.Count; i++)
  313. {
  314. var tl = _texts[i];
  315. var cell = _textLayer.CreateVisual();
  316. cell.Tag = tl;
  317. cell.Draw = (g, v) =>
  318. {
  319. g.DrawTextLayout((TextLayout)v.Tag, new PointF(0, 0));
  320. };
  321. var rc = cell.LayoutRect;
  322. rc.AnchorLeftRight(_columns[i], 0, 0);
  323. rc.SetTop(rowRect, AnchorParam.Top, 0);
  324. rc.SetHeight(tl.ContentHeight + 8 + 8);
  325. rowRect.AppendMinBottom(rc, AnchorParam.Bottom);
  326. }
  327. _sf.PerformLayout();
  328. _rows.Add(rowRect);
  329. }
  330.  
  331. LayoutRect AddNote(string text)
  332. {
  333. var pad = _resolution / 8f;
  334. var tl = new TextLayout(_resolution)
  335. {
  336. MaxWidth = _bounds.Width,
  337. MaxHeight = _bounds.Height,
  338. MarginAll = pad
  339. };
  340. tl.Append(text, new TextFormat { Font = StandardFonts.Helvetica });
  341. tl.PerformLayout();
  342.  
  343. var noteVisual = _pageView.CreateVisual();
  344. noteVisual.Tag = tl;
  345. noteVisual.Draw = (g, v) =>
  346. {
  347. var rect = v.AsRectF();
  348. g.FillRectangle(rect, Color.FromArgb(213, 221, 240));
  349. g.DrawRectangle(rect, Color.FromArgb(59, 92, 170), 0.5f);
  350. g.DrawTextLayout((TextLayout)v.Tag, new PointF(0, 0));
  351. };
  352.  
  353. var textRect = tl.ContentRectangle;
  354. textRect.Inflate(pad, pad);
  355. var rc = noteVisual.LayoutRect;
  356. rc.AnchorTopLeft(_bounds, 0, 0, textRect.Width, textRect.Height);
  357. return rc;
  358. }
  359. }
  360. }
  361.