TextFrames.cs
//
// This code is part of GrapeCity Documents for Word samples.
// Copyright (c) GrapeCity, Inc. All rights reserved.
//
using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using GrapeCity.Documents.Word;

namespace GcWordWeb.Samples
{
    // This sample demonstrates how to add linked text frames to a DOCX,
    // with text spanning the frames.
    public class TextFrames
    {
        public GcWordDocument CreateDocx()
        {
            GcWordDocument doc = new GcWordDocument();

            doc.Load(Path.Combine("Resources", "WordDocs", "SampleParagraphs.docx"));

            // Locate the paragraphs for inserting text frames:
            const string p1start = "This is the first paragraph of the original document";
            const string p2start = "This is the second paragraph of the original document";
            const string p3start = "This is the third paragraph of the original document";
            const string p4start = "This is the fourth paragraph of the original document";

            // Find individual paragraphs inside the document:
            Paragraph p1 = null, p2 = null, p3 = null, p4 = null;
            foreach (var p in doc.Body.Paragraphs)
            {
                var t = p.GetRange().Text;
                if (t.StartsWith(p1start))
                    p1 = p;
                else if (t.StartsWith(p2start))
                    p2 = p;
                else if (t.StartsWith(p3start))
                    p3 = p;
                else if (t.StartsWith(p4start))
                    p4 = p;
            }
            if (p1 == null || p2 == null || p3 == null || p4 == null)
                throw new Exception("Unexpected: could not find paragraphs.");

            // Add new style for text in frames:
            var style = doc.Styles.Add("FrameTextStyle", StyleType.Character);
            style.Font.Color.RGB = Color.DarkBlue;
            style.Font.Bold = true;

            // Generate a long text that we will put into linked text frames:
            string ts = "";
            for (int i = 0; i < 12; ++i)
                ts += $"Text frame content {i}. ";

            // NOTE: shapes (including text frames) can be added to text runs only
            // (e.g. we cannot add a shape directly to a paragraph).

            // Add a text run at the end of the first paragraph:
            Run r1 = p1.GetRange().Runs.Add(" Text run added to paragraph 1. The first shape is inserted inline after this. ");

            // Add a shape to the new text run:
            Shape s1 = r1.GetRange().Shapes.Add(96, 72);

            // Add a text frame with the generated text to the new shape:
            TextFrame tf1 = s1.AddTextFrame(ts);
            tf1.Format.Margin.AllEdges = 4;

            foreach (var r in tf1.GetRange().Runs)
                if (r1 != r)
                    r.Style = style;

            // The text in the frame is rather long, and will not fit inside s1.
            // Text frames can be linked so that a long text can span several frames.
            // We add two linked frames, one to 2nd paragraph, and one to the first
            // paragraph on the page:
            var r2 = p2.GetRange().Runs.Add(" Text run added to paragraph 2. The second shape is inserted inline after this. ");
            var shapes = r2.GetRange().Shapes;

            var s2 = r2.GetRange().Shapes.Add(192, 72);
            var ltf2 = s2.AddLinkedTextFrame(tf1);

            // Default wrap format type for new shapes is inline.
            // Here we change the 3rd shape's wrap to square with absolute position
            // relative to the very first paragraph in the document:
            var s3 = doc.Body.Paragraphs.First.GetRange().Runs.First.GetRange().Shapes.Add(144, 96);
            var ltf3 = s3.AddLinkedTextFrame(tf1);

            s3.WrapFormat.Type = WrapType.Square;
            s3.Position.Vertical.Type = ShapePositionType.Points;
            s3.Position.Vertical.Offset = 0;
            s3.Position.Horizontal.Type = ShapePositionType.Points;
            s3.Position.Horizontal.Offset = doc.Body.Sections.First.PageSetup.ClientWidth - 144;

            return doc;
        }
    }
}