using System; using System.Collections; using System.Drawing; namespace FastReport.Preview { internal class PreviewPages : CollectionBase { private int FMaxWidth; private PageItem this[int index] { get { return List[index] as PageItem; } } private int Add(PageItem value) { return List.Add(value); } public void AddPage(SizeF pageSize, float zoom) { PageItem item = new PageItem(); item.Width = (int)Math.Round(pageSize.Width * zoom); item.Height = (int)Math.Round(pageSize.Height * zoom); Add(item); } // Layouts the pages in the preview window: calculates each page's offset. public void LayoutPages(int clientWidth, Point pageOffset) { FMaxWidth = 0; int curY = pageOffset.Y; int i = 0; // Note that offset between page and window edges is pageOffset; gap between pages is 15 while (i < Count) { int j = i; int curX = 0; int maxY = 0; // find series of pages that will fit in the clientWidth, // also calculate max height of series while (j < Count) { PageItem item = this[j]; // check the width, allow at least one iteration if (curX > 0 && curX + item.Width > clientWidth) break; item.OffsetX = curX; item.OffsetY = curY; curX += item.Width + 15; if (item.Height > maxY) maxY = item.Height; j++; } if (curX > FMaxWidth) FMaxWidth = curX; // center series horizontally int offs = (clientWidth - curX + 15) / 2; if (offs < pageOffset.X) offs = pageOffset.X; while (i < j) { this[i].OffsetX += offs; i++; } curY += maxY + 15; } FMaxWidth -= 15 - pageOffset.X; } private int QuickSearch(int offsetY, bool useAdd) { int i0 = 0; int i1 = Count - 1; while (i0 <= i1) { int i = (i0 + i1) / 2; int add = useAdd ? this[i].Height / 5 : 0; if (this[i].OffsetY <= offsetY + add) i0 = i + 1; else i1 = i - 1; } if (i1 < 0) i1 = 0; return i1; } private int GetFirstPageInRow(int index) { int offs = this[index].OffsetY; while (index > 0) { if (this[index - 1].OffsetY != offs) break; index--; } return index; } // Finds first visible page which OffsetY is near offsetY. This method is used when scrolling the // preview window to find current page number. public int FindPage(int offsetY) { int index = QuickSearch(offsetY, true); return GetFirstPageInRow(index); } // Finds first visible page which OffsetY is near offsetY. This method is used when drawing the page. public int FindFirstVisiblePage(int offsetY) { int index = QuickSearch(offsetY, false); return GetFirstPageInRow(index); } // Finds last visible page which OffsetY is near offsetY. This method is used when drawing the page. public int FindLastVisiblePage(int offsetY) { return QuickSearch(offsetY, false); } // Finds the page which is clicked by the mouse. public int FindPage(int offsetX, int offsetY) { int lastIndex = QuickSearch(offsetY, false); if (this.Count <= lastIndex) return lastIndex; int firstIndex = GetFirstPageInRow(lastIndex); // find exact page for (int i = firstIndex; i <= lastIndex; i++) { PageItem item = this[i]; if (new Rectangle(item.OffsetX, item.OffsetY, item.Width, item.Height).Contains( new Point(offsetX, offsetY))) return i; } return firstIndex; } // Returns the page bounds. public Rectangle GetPageBounds(int index) { if (Count <= index) return Rectangle.Empty; PageItem item = this[index]; return new Rectangle(item.OffsetX, item.OffsetY, item.Width, item.Height); } // Returns max size of the pages. Used to determine the scroll range. public Size GetMaxSize(Point pageOffset) { if (Count == 0) return Size.Empty; int maxHeight = 0; int pageNo = Count - 1; while (pageNo >= 0 && IsSameRow(pageNo, Count - 1)) { int pageBottom = this[pageNo].OffsetY + this[pageNo].Height; if (pageBottom > maxHeight) maxHeight = pageBottom; pageNo--; } return new Size(FMaxWidth + pageOffset.X, maxHeight + pageOffset.Y); } // Returns true if two pages are in the same row (OffsetY is the same) public bool IsSameRow(int page1, int page2) { if (page1 < 0 || page2 < 0 || page1 >= Count || page2 >= Count) return false; return this[page1].OffsetY == this[page2].OffsetY; } // Swaps two pages in preview. Should be used to place pages from right to left. public void SwapPageBounds(int pageIndex1, int pageIndex2) { PageItem temp = new PageItem(); PageItem page1 = this[pageIndex1]; PageItem page2 = this[pageIndex2]; if (page1.OffsetX < page2.OffsetX) { temp.OffsetX = page1.OffsetX; page1.OffsetX = page2.OffsetX; page2.OffsetX = temp.OffsetX; } } private class PageItem { public int Height; public int Width; public int OffsetX; public int OffsetY; } } }