PageHeaders.cs
//
// This code is part of Document Solutions for PDF demos.
// Copyright (c) MESCIUS inc. All rights reserved.
//
using System;
using System.IO;
using System.Drawing;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Drawing;

namespace DsPdfWeb.Demos.Basics
{
    // Demonstrates a simple way to generate left/centered/right aligned page headers and footers.
    public class PageHeaders
    {
        // The document being generated:
        private GcPdfDocument _doc;

        // Utility method to draw a part of a page header or footer.
        // Parameters:
        // - text: The part's text.
        // - tf: The text format to use.
        // - pageIdx: The page index.
        // - header: True if this is a header, false if a footer.
        // - horzAlign: Horizontal alignment (left/center/right).
        private void RenderHeader(string text, TextFormat tf, int pageIdx, bool header, TextAlignment horzAlign)
        {
            var page = _doc.Pages[pageIdx];
            var tl = new TextLayout(page.Graphics.Resolution);
            tl.MaxWidth = page.Size.Width;
            tl.MaxHeight = page.Size.Height;
            // 1" margins, adjust as needed:
            tl.MarginLeft = tl.MarginRight = tl.Resolution;
            // 1/3" spacing above top/below bottom header, adjust as needed:
            tl.MarginTop = tl.MarginBottom = tl.Resolution / 3;
            // Vertical alignment:
            tl.ParagraphAlignment = header ? ParagraphAlignment.Near : ParagraphAlignment.Far;
            // Horizontal alignment:
            tl.TextAlignment = horzAlign;
            tl.Append(text, tf);
            // NOTE: if some part of a header or footer is static, we could cache the corresponding TextLayout
            // object and save some cycles by just drawing that cached TextLayout on each page w/out anything else:
            tl.PerformLayout(true);
            // Draw the header at (0,0) (header located by margins and alignment):
            page.Graphics.DrawTextLayout(tl, PointF.Empty);
        }

        // The main program.
        public int CreatePDF(Stream stream)
        {
            _doc = new GcPdfDocument();
            var page = _doc.NewPage();
            // Add a note about flipping landscape:
            var noteRect = Common.Util.AddNote(
                "We flip page orientation in this sample only to show that these page headers can adapt to the changing page size.",
                page);
            // Prepare a TextLayout with some long text and print it (see PaginatedText for details):
            var tl = page.Graphics.CreateTextLayout();
            tl.DefaultFormat.Font = StandardFonts.Times;
            tl.DefaultFormat.FontSize = 12;
            tl.MaxWidth = _doc.PageSize.Width;
            tl.MaxHeight = _doc.PageSize.Height;
            tl.MarginAll = tl.Resolution;
            tl.MarginTop = noteRect.Bottom + 18;
            // Add sample text:
            tl.Append(Common.Util.LoremIpsum(20));
            // Calculate glyphs and perform layout (see also PerformLayout call in the loop below):
            tl.PerformLayout(true);
            // In a loop, split and render the text:
            while (true)
            {
                var splitResult = tl.Split(null, out TextLayout rest);
                page.Graphics.DrawTextLayout(tl, PointF.Empty);
                if (splitResult != SplitResult.Split)
                    break;
                tl = rest;
                tl.MarginTop = tl.Resolution;
                page = _doc.Pages.Add();
                // For sample sake, toggle page orientation:
                page.Landscape = !_doc.Pages[_doc.Pages.Count - 2].Landscape;
                // Update layout size to reflect the new page orientation:
                tl.MaxWidth = page.Size.Width;
                tl.MaxHeight = page.Size.Height;
                // Because we changed layout size, we must perform layout again -
                // but can do it without recalculating glyphs:
                tl.PerformLayout(false);
            }
            // Render the headers in a separate loop (so that we can provide 'Page X of Y' header):
            var tf = new TextFormat() { Font = StandardFonts.Helvetica, FontSize = 10, ForeColor = Color.Gray };
            var now = Common.Util.TimeNow().ToString("u");
            for (int pageIdx = 0; pageIdx < _doc.Pages.Count; ++pageIdx)
            {
                RenderHeader(now, tf, pageIdx, true, TextAlignment.Leading);
                RenderHeader("Easy Page Headers Sample", tf, pageIdx, true, TextAlignment.Center);
                RenderHeader($"Page {pageIdx + 1} of {_doc.Pages.Count}", tf, pageIdx, true, TextAlignment.Trailing);
                RenderHeader("Page footer - left", tf, pageIdx, false, TextAlignment.Leading);
                RenderHeader("DsPdf", tf, pageIdx, false, TextAlignment.Center);
                RenderHeader("Page footer - right", tf, pageIdx, false, TextAlignment.Trailing);
            }
            // Done:
            _doc.Save(stream);
            return _doc.Pages.Count;
        }
    }
}