PreviewPages.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. using System;
  2. using System.Collections;
  3. using System.Drawing;
  4. namespace FastReport.Preview
  5. {
  6. internal class PreviewPages : CollectionBase
  7. {
  8. private int FMaxWidth;
  9. private PageItem this[int index]
  10. {
  11. get { return List[index] as PageItem; }
  12. }
  13. private int Add(PageItem value)
  14. {
  15. return List.Add(value);
  16. }
  17. public void AddPage(SizeF pageSize, float zoom)
  18. {
  19. PageItem item = new PageItem();
  20. item.Width = (int)Math.Round(pageSize.Width * zoom);
  21. item.Height = (int)Math.Round(pageSize.Height * zoom);
  22. Add(item);
  23. }
  24. // Layouts the pages in the preview window: calculates each page's offset.
  25. public void LayoutPages(int clientWidth, Point pageOffset)
  26. {
  27. FMaxWidth = 0;
  28. int curY = pageOffset.Y;
  29. int i = 0;
  30. // Note that offset between page and window edges is pageOffset; gap between pages is 15
  31. while (i < Count)
  32. {
  33. int j = i;
  34. int curX = 0;
  35. int maxY = 0;
  36. // find series of pages that will fit in the clientWidth,
  37. // also calculate max height of series
  38. while (j < Count)
  39. {
  40. PageItem item = this[j];
  41. // check the width, allow at least one iteration
  42. if (curX > 0 && curX + item.Width > clientWidth)
  43. break;
  44. item.OffsetX = curX;
  45. item.OffsetY = curY;
  46. curX += item.Width + 15;
  47. if (item.Height > maxY)
  48. maxY = item.Height;
  49. j++;
  50. }
  51. if (curX > FMaxWidth)
  52. FMaxWidth = curX;
  53. // center series horizontally
  54. int offs = (clientWidth - curX + 15) / 2;
  55. if (offs < pageOffset.X)
  56. offs = pageOffset.X;
  57. while (i < j)
  58. {
  59. this[i].OffsetX += offs;
  60. i++;
  61. }
  62. curY += maxY + 15;
  63. }
  64. FMaxWidth -= 15 - pageOffset.X;
  65. }
  66. private int QuickSearch(int offsetY, bool useAdd)
  67. {
  68. int i0 = 0;
  69. int i1 = Count - 1;
  70. while (i0 <= i1)
  71. {
  72. int i = (i0 + i1) / 2;
  73. int add = useAdd ? this[i].Height / 5 : 0;
  74. if (this[i].OffsetY <= offsetY + add)
  75. i0 = i + 1;
  76. else
  77. i1 = i - 1;
  78. }
  79. if (i1 < 0)
  80. i1 = 0;
  81. return i1;
  82. }
  83. private int GetFirstPageInRow(int index)
  84. {
  85. int offs = this[index].OffsetY;
  86. while (index > 0)
  87. {
  88. if (this[index - 1].OffsetY != offs)
  89. break;
  90. index--;
  91. }
  92. return index;
  93. }
  94. // Finds first visible page which OffsetY is near offsetY. This method is used when scrolling the
  95. // preview window to find current page number.
  96. public int FindPage(int offsetY)
  97. {
  98. int index = QuickSearch(offsetY, true);
  99. return GetFirstPageInRow(index);
  100. }
  101. // Finds first visible page which OffsetY is near offsetY. This method is used when drawing the page.
  102. public int FindFirstVisiblePage(int offsetY)
  103. {
  104. int index = QuickSearch(offsetY, false);
  105. return GetFirstPageInRow(index);
  106. }
  107. // Finds last visible page which OffsetY is near offsetY. This method is used when drawing the page.
  108. public int FindLastVisiblePage(int offsetY)
  109. {
  110. return QuickSearch(offsetY, false);
  111. }
  112. // Finds the page which is clicked by the mouse.
  113. public int FindPage(int offsetX, int offsetY)
  114. {
  115. int lastIndex = QuickSearch(offsetY, false);
  116. if (this.Count <= lastIndex) return lastIndex;
  117. int firstIndex = GetFirstPageInRow(lastIndex);
  118. // find exact page
  119. for (int i = firstIndex; i <= lastIndex; i++)
  120. {
  121. PageItem item = this[i];
  122. if (new Rectangle(item.OffsetX, item.OffsetY, item.Width, item.Height).Contains(
  123. new Point(offsetX, offsetY)))
  124. return i;
  125. }
  126. return firstIndex;
  127. }
  128. // Returns the page bounds.
  129. public Rectangle GetPageBounds(int index)
  130. {
  131. if (Count <= index) return Rectangle.Empty;
  132. PageItem item = this[index];
  133. return new Rectangle(item.OffsetX, item.OffsetY, item.Width, item.Height);
  134. }
  135. // Returns max size of the pages. Used to determine the scroll range.
  136. public Size GetMaxSize(Point pageOffset)
  137. {
  138. if (Count == 0)
  139. return Size.Empty;
  140. int maxHeight = 0;
  141. int pageNo = Count - 1;
  142. while (pageNo >= 0 && IsSameRow(pageNo, Count - 1))
  143. {
  144. int pageBottom = this[pageNo].OffsetY + this[pageNo].Height;
  145. if (pageBottom > maxHeight)
  146. maxHeight = pageBottom;
  147. pageNo--;
  148. }
  149. return new Size(FMaxWidth + pageOffset.X, maxHeight + pageOffset.Y);
  150. }
  151. // Returns true if two pages are in the same row (OffsetY is the same)
  152. public bool IsSameRow(int page1, int page2)
  153. {
  154. if (page1 < 0 || page2 < 0 || page1 >= Count || page2 >= Count)
  155. return false;
  156. return this[page1].OffsetY == this[page2].OffsetY;
  157. }
  158. // Swaps two pages in preview. Should be used to place pages from right to left.
  159. public void SwapPageBounds(int pageIndex1, int pageIndex2)
  160. {
  161. PageItem temp = new PageItem();
  162. PageItem page1 = this[pageIndex1];
  163. PageItem page2 = this[pageIndex2];
  164. if (page1.OffsetX < page2.OffsetX)
  165. {
  166. temp.OffsetX = page1.OffsetX;
  167. page1.OffsetX = page2.OffsetX;
  168. page2.OffsetX = temp.OffsetX;
  169. }
  170. }
  171. private class PageItem
  172. {
  173. public int Height;
  174. public int Width;
  175. public int OffsetX;
  176. public int OffsetY;
  177. }
  178. }
  179. }