DrawSlantedText.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;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;

namespace DsPdfWeb.Demos.Basics
{
    // This demo illustrates the results of using the GcGraphics.DrawSlantedText() method
    // with different combinations of arguments.
    // The DrawSlantedText() method draws text slanted within a specified rectangle
    // similar to how rotated text is drawn in MS Excel cells with borders.
    // See also the DrawRotatedText demo.
    public class DrawSlantedText
    {
        public int CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            var page = doc.Pages.Add();
            var g = page.Graphics;
            // Set up some values to manage layout:
            var gap = g.Resolution;
            var w = page.Size.Width / 3;
            var h = w;

            // Various text alignments with SlantedTextAlignment.BelowRotatedInside:
            Draw(g, q0(), angle: -70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Leading);
            Draw(g, q1(), angle: -70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Trailing);
            Draw(g, q2(), angle: -70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Center);
            Draw(g, q3(), angle: -70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Distributed);
            // Various text alignments with SlantedTextAlignment.BelowRotatedOutside:
            page = doc.Pages.Add();
            g = page.Graphics;
            Draw(g, q0(), angle: -70, false, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Leading);
            Draw(g, q1(), angle: -70, false, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Trailing);
            Draw(g, q2(), angle: -70, false, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Center);
            Draw(g, q3(), angle: -70, false, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Distributed);
            // Various text alignments with SlantedTextAlignment.AboveRotatedInside:
            page = doc.Pages.Add();
            g = page.Graphics;
            Draw(g, q0(), angle: -70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Leading);
            Draw(g, q1(), angle: -70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Trailing);
            Draw(g, q2(), angle: -70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Center);
            Draw(g, q3(), angle: -70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Distributed);
            // Various text alignments with SlantedTextAlignment.AboveRotatedOutside:
            page = doc.Pages.Add();
            g = page.Graphics;
            Draw(g, q0(), angle: -70, false, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Leading);
            Draw(g, q1(), angle: -70, false, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Trailing);
            Draw(g, q2(), angle: -70, false, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Center);
            Draw(g, q3(), angle: -70, false, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Distributed);
            // Various text alignments with SlantedTextAlignment.CenterInsideOutside:
            page = doc.Pages.Add();
            g = page.Graphics;
            Draw(g, q0(), angle: -70, false, SlantedTextAlignment.CenterInsideOutside, TextAlignment.Leading);
            Draw(g, q1(), angle: -70, false, SlantedTextAlignment.CenterInsideOutside, TextAlignment.Trailing);
            Draw(g, q2(), angle: -70, false, SlantedTextAlignment.CenterInsideOutside, TextAlignment.Center);
            Draw(g, q3(), angle: -70, false, SlantedTextAlignment.CenterInsideOutside, TextAlignment.Distributed);
            // Various text alignments with SlantedTextAlignment.CenterOutsideInside:
            page = doc.Pages.Add();
            g = page.Graphics;
            Draw(g, q0(), angle: -70, false, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Leading);
            Draw(g, q1(), angle: -70, false, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Trailing);
            Draw(g, q2(), angle: -70, false, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Center);
            Draw(g, q3(), angle: -70, false, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Distributed);
            // Examples with positive rotation angle using SlantedTextAlignment.BelowRotatedInside:
            page = doc.Pages.Add();
            g = page.Graphics;
            Draw(g, q0(), angle: 70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Leading);
            Draw(g, q1(), angle: 70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Trailing);
            Draw(g, q2(), angle: 70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Center);
            Draw(g, q3(), angle: 70, false, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Distributed);
            // Examples with positive rotation angle using SlantedTextAlignment.AboveRotatedInside:
            page = doc.Pages.Add();
            g = page.Graphics;
            Draw(g, q0(), angle: 70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Leading);
            Draw(g, q1(), angle: 70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Trailing);
            Draw(g, q2(), angle: 70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Center);
            Draw(g, q3(), angle: 70, false, SlantedTextAlignment.AboveRotatedInside, TextAlignment.Distributed);

            // Below are examples of vertically stacked text.

            // Vertically stacked text rotated to a negative angle using SlantedTextAlignment.BelowRotatedInside:
            page = doc.Pages.Add();
            g = page.Graphics;
            Draw(g, q0(), angle: -20, true, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Leading);
            Draw(g, q1(), angle: -20, true, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Trailing);
            Draw(g, q2(), angle: -20, true, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Center);
            Draw(g, q3(), angle: -20, true, SlantedTextAlignment.BelowRotatedInside, TextAlignment.Distributed);
            // Vertically stacked text rotated to a negative angle using SlantedTextAlignment.BelowRotatedOutside:
            page = doc.Pages.Add();
            g = page.Graphics;
            Draw(g, q0(), angle: -20, true, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Leading);
            Draw(g, q1(), angle: -20, true, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Trailing);
            Draw(g, q2(), angle: -20, true, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Center);
            Draw(g, q3(), angle: -20, true, SlantedTextAlignment.BelowRotatedOutside, TextAlignment.Distributed);
            // Vertically stacked text rotated to a positive angle using SlantedTextAlignment.AboveRotatedOutside:
            page = doc.Pages.Add();
            g = page.Graphics;
            Draw(g, q0(), angle: 20, true, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Leading);
            Draw(g, q1(), angle: 20, true, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Trailing);
            Draw(g, q2(), angle: 20, true, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Center);
            Draw(g, q3(), angle: 20, true, SlantedTextAlignment.AboveRotatedOutside, TextAlignment.Distributed);
            // Vertically stacked text rotated to a positive angle using SlantedTextAlignment.CenterOutsideInside:
            page = doc.Pages.Add();
            g = page.Graphics;
            Draw(g, q0(), angle: 20, true, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Leading);
            Draw(g, q1(), angle: 20, true, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Trailing);
            Draw(g, q2(), angle: 20, true, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Center);
            Draw(g, q3(), angle: 20, true, SlantedTextAlignment.CenterOutsideInside, TextAlignment.Distributed);

            // Done:
            doc.Save(stream);
            return doc.Pages.Count;

            RectangleF q0()
            {
                return new RectangleF(gap, gap, w, h);
            }
            RectangleF q1()
            {
                return new RectangleF(gap + w + gap, gap, w, h);
            }
            RectangleF q2()
            {
                return new RectangleF(gap, gap + h + gap, w, h);
            }
            RectangleF q3()
            {
                return new RectangleF(gap + w + gap, gap + h + gap, w, h);
            }
        }

        static void Draw(GcGraphics g, RectangleF rect, int angle, bool verticalStacking,
            SlantedTextAlignment slantedAlign, TextAlignment textAlign)
        {
            // Draw a legend stating the current DrawRotatedText arguments' values:
            var tlLegend = g.CreateTextLayout();
            tlLegend.DefaultFormat.FontName = "Calibri";
            tlLegend.DefaultFormat.FontSize = 9;
            tlLegend.AppendLine($"Rotation angle: {angle}°");
            tlLegend.AppendLine($"Text alignment: {textAlign}");
            tlLegend.AppendLine($"Slanted text alignment: {slantedAlign}");
            tlLegend.AppendLine($"Is vertical stacking: {verticalStacking}");
            g.DrawTextLayout(tlLegend, rect.Location);

            // The target rectangle for the DrawRotatedText call:
            var d = tlLegend.ContentHeight + g.Resolution;
            rect.Y += d;
            rect.Height -= d;
            rect.Width -= d / 2;
            var x = rect.X;
            var y = rect.Y;
            var w = rect.Width;
            var h = rect.Height;

            // Draw the target rectangle:
            g.DrawRectangle(rect, new GCDRAW::Pen(Color.PaleGreen, 3));

            if (!verticalStacking)
            {
                float dx = (float)(h / Math.Tan(Math.PI * angle / -180.0));
                switch (slantedAlign)
                {
                    case SlantedTextAlignment.BelowRotatedInside:
                    case SlantedTextAlignment.AboveRotatedOutside:
                    case SlantedTextAlignment.CenterInsideOutside:
                        g.DrawPolygon(new[] {
                            new PointF(x + dx, y), new PointF(x + dx + w, y),
                            new PointF(x + w, y + h), new PointF(x, y + h)},
                            new GCDRAW::Pen(Color.Red, 1));
                        break;
                    case SlantedTextAlignment.BelowRotatedOutside:
                    case SlantedTextAlignment.AboveRotatedInside:
                    case SlantedTextAlignment.CenterOutsideInside:
                        g.DrawPolygon(new[] {
                            new PointF(x, y), new PointF(x + w, y),
                            new PointF(x - dx + w, y + h), new PointF(x - dx, y + h)},
                            new GCDRAW::Pen(Color.Red, 1));
                        break;
                }
            }
            else
            {
                float dy = (float)(w * Math.Tan(Math.PI * angle / 180.0));
                switch (slantedAlign)
                {
                    case SlantedTextAlignment.BelowRotatedInside:
                    case SlantedTextAlignment.AboveRotatedOutside:
                    case SlantedTextAlignment.CenterInsideOutside:
                        if (angle >= 0)
                            g.DrawPolygon(new[] {
                                new PointF(x, y), new PointF(x + w, y + dy), new PointF(x + w, y + dy + h), new PointF(x, y + h)},
                                new GCDRAW::Pen(Color.Red, 1));
                        else
                            g.DrawPolygon(new[] {
                                new PointF(x, y - dy), new PointF(x + w, y), new PointF(x + w, y + h), new PointF(x, y - dy + h)},
                                new GCDRAW::Pen(Color.Red, 1));
                        break;
                    case SlantedTextAlignment.BelowRotatedOutside:
                    case SlantedTextAlignment.AboveRotatedInside:
                    case SlantedTextAlignment.CenterOutsideInside:
                        if (angle >= 0)
                            g.DrawPolygon(new[] {
                                new PointF(x, y - dy), new PointF(x + w, y), new PointF(x + w, y + h), new PointF(x, y - dy + h)},
                                new GCDRAW::Pen(Color.Red, 1));
                        else
                            g.DrawPolygon(new[] {
                                new PointF(x, y), new PointF(x + w, y + dy), new PointF(x + w, y + dy + h), new PointF(x, y + h)},
                                new GCDRAW::Pen(Color.Red, 1));
                        break;
                }
            }
            // Draw slanted text:
            var tl = g.CreateTextLayout();
            tl.DefaultFormat.FontName = "Calibri";
            tl.DefaultFormat.FontSize = 12;
            tl.TextAlignment = textAlign;
            tl.Append("The quick brown fox jumps over the lazy dog. ");
            tl.Append("The quick brown fox jumps over the lazy dog.");
            g.DrawSlantedText(tl, angle, verticalStacking, rect, slantedAlign);
        }        
    }
}