//// This code is part of Document Solutions for Imaging demos.// Copyright (c) MESCIUS inc. All rights reserved.//using System;using System.IO;using System.Drawing;using System.Collections.Generic;using System.Numerics;using GrapeCity.Documents.Drawing;using GrapeCity.Documents.Text;using GrapeCity.Documents.Imaging;using GrapeCity.Documents.Layout;using GrapeCity.Documents.Layout.Composition;using GCTEXT = GrapeCity.Documents.Text;using GCDRAW = GrapeCity.Documents.Drawing;
namespace DsImagingWeb.Demos{ // This integrated demo shows how to use helper classes // in the GrapeCity.Documents.Layout.Composition namespace // to create complex and flexible constraint-based layouts // with custom z-order and clipping. public class LayoutDemos { static readonly Color PageColor = Color.FromArgb(39, 41, 43), BoxColor = Color.FromArgb(230, 230, 230), CodeColor = Color.FromArgb(132, 211, 232), RectColor = Color.FromArgb(64, 126, 148), DescColor = Color.White; delegate void DrawLayoutSample(GcGraphics g, Size pageSize); static readonly Dictionary<string, DrawLayoutSample> c_samples = new Dictionary<string, DrawLayoutSample>() { { "DrawSample1", DrawSample1 }, { "DrawSample2", DrawSample2 }, { "DrawSample3", DrawSample3 }, { "DrawSample4", DrawSample4 }, { "DrawSample5", DrawSample5 }, { "DrawSample6", DrawSample6 }, { "DrawSample7", DrawSample7 }, { "DrawSample8", DrawSample8 }, };
public GcBitmap GenerateImage(Size pixelSize, float dpi, bool opaque, string[] sampleParams = null) { if (!c_samples.TryGetValue(sampleParams[3], out DrawLayoutSample drawSample)) throw new Exception($"Unknown parameterized sample: {sampleParams[3]}");
var bmp = new GcBitmap(pixelSize.Width, pixelSize.Height, opaque, dpi, dpi); using var g = bmp.CreateGraphics(PageColor); drawSample(g, pixelSize);
return bmp; }
public static List<string[]> GetSampleParamsList() { return new List<string[]>() { // Strings are name, description, info. Rest are arbitrary strings: new string[] { "Figures 1-4", "Figures 1-4: horizontal, vertical, alignment constraint and guidelines", null, "DrawSample1" }, new string[] { "Figure 5", "Figure 5: Barrier constraint anchored to two visuals", null, "DrawSample2" }, new string[] { "Figure 6", "Figure 6: Horizontal chain with weighted widths", null, "DrawSample3" }, new string[] { "Figure 7", "Figure 7: Horizontal chain with evenly distributed rectangles and margins", null, "DrawSample4" }, new string[] { "Figure 8", "Figure 8: Horizontal chain with evenly distributed rectangles, no margins", null, "DrawSample5" }, new string[] { "Figure 9", "Figure 9: Weighted horizontal chain without margins", null, "DrawSample6" }, new string[] { "Figure 10", "Figure 10: Horizontal chain with weighted margins and packed rectangles", null, "DrawSample7" }, new string[] { "Text Flow", "Text flow in and around non-rectangular contours", null, "DrawSample8" }, }; }
// Figures 1-4: horizontal, vertical, alignment constraint and guidelines. static void DrawSample1(GcGraphics g, Size _) { g.Transform = Matrix3x2.CreateScale(1.4f);
// The Surface object can layout Visuals and draw them on the graphics. var surf = new Surface();
// view1
// The View object represents a group of Visuals with a transformation matrix. var view1 = surf.CreateView(250, 150).Translate(50, 40);
// Visual is an element with the associated LayoutRect used for its // positioning/ and a delegate that draws its content on the graphics. var v = view1.CreateVisual(DrawView); v.Tag = new FigureCaption(1, "A horizontal constraint to the parent:", "rA.SetLeft(null, AnchorParam.Left, 90);"); v.LayoutRect.AnchorExact(null);
v = view1.CreateVisual(DrawRect); var rA = v.LayoutRect; rA.SetLeft(null, AnchorParam.Left, 90); rA.SetWidth(70); rA.SetHeight(40); rA.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "A";
var r = view1.CreateVisual(DrawLineWithLeftArrow).LayoutRect; r.AnchorTopBottom(rA, 0, 0); r.SetLeft(null, AnchorParam.Left); r.SetRight(rA, AnchorParam.Left);
// view2 var view2 = surf.CreateView(250, 150).Translate(350, 40); v = view2.CreateVisual(DrawView); v.Tag = new FigureCaption(2, "An offset horizontal alignment constraint:", "rB.SetLeft(rA, AnchorParam.Left, 40);"); v.LayoutRect.AnchorExact(null);
v = view2.CreateVisual(DrawRect); rA = v.LayoutRect; rA.AnchorTopLeft(null, 15, 70, 110, 60); v.Tag = "A";
v = view2.CreateVisual(DrawRect); var rB = v.LayoutRect; rB.SetLeft(rA, AnchorParam.Left, 40); rB.SetWidth(60); rB.SetHeight(35); rB.SetTop(rA, AnchorParam.Bottom, 20); v.Tag = "B";
r = view2.CreateVisual(DrawVertLineWithLeftArrow).LayoutRect; r.SetTop(rA, AnchorParam.VerticalCenter); r.SetBottom(rB, AnchorParam.VerticalCenter); r.SetLeft(rA, AnchorParam.Left); r.SetRight(rB, AnchorParam.Left);
// view3 var view3 = surf.CreateView(250, 150).Translate(50, 260); v = view3.CreateVisual(DrawView); v.Tag = new FigureCaption(3, "Horizontal and vertical constraints:", "rB.SetLeft(rA, AnchorParam.Right, 50);\n" + "rC.SetTop(rA, AnchorParam.Bottom, 40);"); v.LayoutRect.AnchorExact(null);
v = view3.CreateVisual(DrawRect); rA = v.LayoutRect; rA.AnchorTopLeft(null, 15, 30, 70, 40); v.Tag = "A";
v = view3.CreateVisual(DrawRect); rB = v.LayoutRect; rB.SetLeft(rA, AnchorParam.Right, 50); rB.SetWidth(70); rB.SetHeight(40); rB.SetTop(rA, AnchorParam.Top); v.Tag = "B";
v = view3.CreateVisual(DrawRect); var rC = v.LayoutRect; rC.SetTop(rA, AnchorParam.Bottom, 40); rC.SetWidth(70); rC.SetHeight(40); rC.SetLeft(rA, AnchorParam.Left); v.Tag = "C";
r = view3.CreateVisual(DrawLineWithLeftArrow).LayoutRect; r.AnchorTopBottom(rA, 0, 0); r.SetLeft(rA, AnchorParam.Right); r.SetRight(rB, AnchorParam.Left);
r = view3.CreateVisual(DrawLineWithUpArrow).LayoutRect; r.AnchorLeftRight(rA, 0, 0); r.SetTop(rA, AnchorParam.Bottom); r.SetBottom(rC, AnchorParam.Top);
// view4 var view4 = surf.CreateView(250, 150).Translate(350, 260); var layoutView = view4.LayoutView; v = view4.CreateVisual(DrawView); v.Tag = new FigureCaption(4, "A rectangle constrained to a guideline:", "var anchorPoint = layoutView.CreatePoint(0.25f, 0);\n" + "rA.SetLeft(anchorPoint, 60);"); v.LayoutRect.AnchorExact(null);
// An anchor point can work as the guideline on the X or the Y axes. var anchorPoint = layoutView.CreatePoint(0.25f, 0);
v = view4.CreateVisual(DrawVertGuideline); var rG = v.LayoutRect; rG.SetLeft(anchorPoint); rG.AnchorVerticalLine(null); v.Tag = "25 %";
v = view4.CreateVisual(DrawRect); rA = v.LayoutRect; rA.SetLeft(anchorPoint, 60); rA.SetWidth(70); rA.SetHeight(40); rA.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "A";
r = view4.CreateVisual(DrawLineWithLeftArrow).LayoutRect; r.AnchorTopBottom(rA, 0, 0); r.SetLeft(rG, AnchorParam.Left); r.SetRight(rA, AnchorParam.Left);
surf.Render(g); }
// Figure 5: Barrier constraint anchored to two visuals. static void DrawSample2(GcGraphics g, Size _) { g.Transform = Matrix3x2.CreateScale(2);
var surf = new Surface();
// View1 var view1 = surf.CreateView(350, 160).Translate(30, 30); view1.CreateVisual(DrawView).LayoutRect.AnchorExact(null);
var v = view1.CreateVisual(DrawRect); var rA = v.LayoutRect; rA.AnchorTopLeft(null, 30, 50, 60, 40); v.Tag = "A";
v = view1.CreateVisual(DrawRect); var rB = v.LayoutRect; rB.AnchorTopLeft(null, 90, 50, 90, 40); v.Tag = "B";
v = view1.CreateVisual(DrawVertGuideline); var rG = v.LayoutRect;
// Adding multiple MinLeft constraints to the same rectangle creates // a barrier to be used as the base for other rectangles. rG.AppendMinLeft(rA, AnchorParam.Right); rG.AppendMinLeft(rB, AnchorParam.Right);
rG.AnchorVerticalLine(null);
v = view1.CreateVisual(DrawRect); var rC = v.LayoutRect; rC.AppendMinLeft(rA, AnchorParam.Right, 50); rC.AppendMinLeft(rB, AnchorParam.Right, 50); rC.SetWidth(70); rC.SetHeight(40); rC.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "C";
var r = view1.CreateVisual(DrawLineWithLeftArrow).LayoutRect; r.AnchorTopBottom(rC, 0, 0); r.SetLeft(rG, AnchorParam.Right); r.SetRight(rC, AnchorParam.Left);
// View2 var view2 = surf.CreateView(350, 160).Translate(30, 210); v = view2.CreateVisual(DrawView); v.Tag = new FigureCaption(5, "C is constrained to a barrier, which moves based on\n" + "the position and size of both A and B:", "rC.AppendMinLeft(rA, AnchorParam.Right, 50);\n" + "rC.AppendMinLeft(rB, AnchorParam.Right, 50);"); v.LayoutRect.AnchorExact(null);
v = view2.CreateVisual(DrawRect); rA = v.LayoutRect; rA.AnchorTopLeft(null, 30, 50, 130, 40); v.Tag = "A";
v = view2.CreateVisual(DrawRect); rB = v.LayoutRect; rB.AnchorTopLeft(null, 90, 50, 90, 40); v.Tag = "B";
v = view2.CreateVisual(DrawVertGuideline); rG = v.LayoutRect; rG.AppendMinLeft(rA, AnchorParam.Right); rG.AppendMinLeft(rB, AnchorParam.Right); rG.AnchorVerticalLine(null);
v = view2.CreateVisual(DrawRect); rC = v.LayoutRect; rC.AppendMinLeft(rA, AnchorParam.Right, 50); rC.AppendMinLeft(rB, AnchorParam.Right, 50); rC.SetWidth(70); rC.SetHeight(40); rC.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "C";
r = view2.CreateVisual(DrawLineWithLeftArrow).LayoutRect; r.AnchorTopBottom(rC, 0, 0); r.SetLeft(rG, AnchorParam.Right); r.SetRight(rC, AnchorParam.Left);
surf.Render(g); }
// Figure 6: Horizontal chain with weighted widths. static void DrawSample3(GcGraphics g, Size _) { g.Transform = Matrix3x2.CreateScale(2);
var surf = new Surface();
var view = surf.CreateView(350, 120).Translate(30, 40); var v = view.CreateVisual(DrawView); v.Tag = new FigureCaption(6, "A horizontal chain with two rectangles having weighted\nwidths and a fixed space between them:", "rA.SetLeft(null, AnchorParam.Left, 60);\n" + "rA.SetStarWidth(1);\n" + "rAB.SetLeftAndOpposite(rA, AnchorParam.Right);\n" + "rAB.SetWidth(50);\n" + "rB.SetLeftAndOpposite(rAB, AnchorParam.Right);\n" + "rB.SetStarWidth(2);\n" + "rB.SetRight(null, AnchorParam.Right, -60);"); v.LayoutRect.AnchorExact(null);
v = view.CreateVisual(DrawRect); var rA = v.LayoutRect; rA.SetHeight(40); rA.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "A";
v = view.CreateVisual(DrawRect); var rB = v.LayoutRect; rB.SetHeight(40); rB.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "B";
var rAB = view.CreateVisual(DrawLeftRightLines).LayoutRect; rAB.AnchorTopBottom(rA, 0, 0);
// The SetStarWidth method sets the weight of width of that specific // rectangle relative to the width of other rectangles that belong // to the same chain and have the "star" width.
// SetLeftAndOpposite method makes a chain of rectangles that affect // the position of each other in both directions.
rA.SetLeft(null, AnchorParam.Left, 60); rA.SetStarWidth(1); rAB.SetLeftAndOpposite(rA, AnchorParam.Right); rAB.SetWidth(50); rB.SetLeftAndOpposite(rAB, AnchorParam.Right); rB.SetStarWidth(2); rB.SetRight(null, AnchorParam.Right, -60);
var r = view.CreateVisual(DrawLineWithLeftArrow).LayoutRect; r.AnchorTopBottom(rA, 0, 0); r.SetLeft(null, AnchorParam.Left); r.SetRight(rA, AnchorParam.Left);
r = view.CreateVisual(DrawLineWithRightArrow).LayoutRect; r.AnchorTopBottom(rB, 0, 0); r.SetLeft(rB, AnchorParam.Right); r.SetRight(null, AnchorParam.Right);
surf.Render(g); }
// Figure 7: Horizontal chain with evenly distributed rectangles and margins. static void DrawSample4(GcGraphics g, Size _) { g.Transform = Matrix3x2.CreateScale(1.8f);
var surf = new Surface();
var view = surf.CreateView(430, 120).Translate(30, 40); var v = view.CreateVisual(DrawView); v.Tag = new FigureCaption(7, "A horizontal chain with three evenly distributed rectangles\nafter margins are accounted for:", "rA.SetLeft(null, AnchorParam.Left, 60);\n" + "rA.SetWidth(70);\n" + "rAB.SetLeftAndOpposite(rA, AnchorParam.Right);\n" + "rAB.SetStarWidth(1);\n" + "rAB.SetRightAndOpposite(rB, AnchorParam.Left);\n" + "rB.SetWidth(70);\n" + "rBC.SetLeftAndOpposite(rB, AnchorParam.Right);\n" + "rBC.SetStarWidth(1);\n" + "rC.SetLeftAndOpposite(rBC, AnchorParam.Right);\n" + "rC.SetWidth(70);\n" + "rC.SetRight(null, AnchorParam.Right, -60);"); v.LayoutRect.AnchorExact(null);
v = view.CreateVisual(DrawRect); var rA = v.LayoutRect; rA.SetHeight(40); rA.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "A";
v = view.CreateVisual(DrawRect); var rB = v.LayoutRect; rB.SetHeight(40); rB.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "B";
v = view.CreateVisual(DrawRect); var rC = v.LayoutRect; rC.SetHeight(40); rC.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "C";
var rAB = view.CreateVisual(DrawLeftRightLines).LayoutRect; rAB.AnchorTopBottom(rA, 0, 0);
var rBC = view.CreateVisual(DrawLeftRightLines).LayoutRect; rBC.AnchorTopBottom(rB, 0, 0);
rA.SetLeft(null, AnchorParam.Left, 60); rA.SetWidth(70); rAB.SetLeftAndOpposite(rA, AnchorParam.Right); rAB.SetStarWidth(1); rAB.SetRightAndOpposite(rB, AnchorParam.Left); rB.SetWidth(70); rBC.SetLeftAndOpposite(rB, AnchorParam.Right); rBC.SetStarWidth(1); rC.SetLeftAndOpposite(rBC, AnchorParam.Right); rC.SetWidth(70); rC.SetRight(null, AnchorParam.Right, -60);
var r = view.CreateVisual(DrawLineWithLeftArrow).LayoutRect; r.AnchorTopBottom(rA, 0, 0); r.SetLeft(null, AnchorParam.Left); r.SetRight(rA, AnchorParam.Left);
r = view.CreateVisual(DrawLineWithRightArrow).LayoutRect; r.AnchorTopBottom(rC, 0, 0); r.SetLeft(rC, AnchorParam.Right); r.SetRight(null, AnchorParam.Right);
surf.Render(g); }
// Figure 8: Horizontal chain with evenly distributed rectangles, no margins. static void DrawSample5(GcGraphics g, Size _) { g.Transform = Matrix3x2.CreateScale(2);
var surf = new Surface();
var view = surf.CreateView(340, 120).Translate(30, 40); var v = view.CreateVisual(DrawView); v.Tag = new FigureCaption(8, "Same as Figure 7, without accounting for the margins:", "rA.SetLeft(null, AnchorParam.Left);\n" + "rA.SetWidth(70);\n" + "rA.SetRightAndOpposite(rAB, AnchorParam.Left);\n" + "rAB.SetStarWidth(1);\n" + "rB.SetLeftAndOpposite(rAB, AnchorParam.Right);\n" + "rB.SetWidth(70);\n" + "rB.SetRightAndOpposite(rBC, AnchorParam.Left);\n" + "rBC.SetStarWidth(1);\n" + "rC.SetLeftAndOpposite(rBC, AnchorParam.Right);\n" + "rC.SetWidth(70);\n" + "rC.SetRight(null, AnchorParam.Right);"); v.LayoutRect.AnchorExact(null);
v = view.CreateVisual(DrawRect); var rA = v.LayoutRect; rA.SetHeight(40); rA.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "A";
v = view.CreateVisual(DrawRect); var rB = v.LayoutRect; rB.SetHeight(40); rB.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "B";
v = view.CreateVisual(DrawRect); var rC = v.LayoutRect; rC.SetHeight(40); rC.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "C";
var rAB = view.CreateVisual(DrawLeftRightLines).LayoutRect; rAB.AnchorTopBottom(rA, 0, 0);
var rBC = view.CreateVisual(DrawLeftRightLines).LayoutRect; rBC.AnchorTopBottom(rB, 0, 0);
rA.SetLeft(null, AnchorParam.Left); rA.SetWidth(70); rA.SetRightAndOpposite(rAB, AnchorParam.Left); rAB.SetStarWidth(1); rB.SetLeftAndOpposite(rAB, AnchorParam.Right); rB.SetWidth(70); rB.SetRightAndOpposite(rBC, AnchorParam.Left); rBC.SetStarWidth(1); rC.SetLeftAndOpposite(rBC, AnchorParam.Right); rC.SetWidth(70); rC.SetRight(null, AnchorParam.Right);
surf.Render(g); }
// Figure 9: Weighted horizontal chain without margins. static void DrawSample6(GcGraphics g, Size _) { g.Transform = Matrix3x2.CreateScale(2);
var surf = new Surface();
var view = surf.CreateView(340, 120).Translate(30, 40); var v = view.CreateVisual(DrawView); v.Tag = new FigureCaption(9, "A weighted horizontal chain without margins:", "rA.SetLeft(null, AnchorParam.Left);\n" + "rA.SetStarWidth(1);\n" + "rA.SetRightAndOpposite(rB, AnchorParam.Left);\n" + "rB.SetStarWidth(2);\n" + "rB.SetRightAndOpposite(rC, AnchorParam.Left);\n" + "rC.SetStarWidth(2);\n" + "rC.SetRight(null, AnchorParam.Right);"); v.LayoutRect.AnchorExact(null);
v = view.CreateVisual(DrawRect); var rA = v.LayoutRect; rA.SetHeight(40); rA.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "A";
v = view.CreateVisual(DrawRect); var rB = v.LayoutRect; rB.SetHeight(40); rB.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "B";
v = view.CreateVisual(DrawRect); var rC = v.LayoutRect; rC.SetHeight(40); rC.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "C";
rA.SetLeft(null, AnchorParam.Left); rA.SetStarWidth(1); rA.SetRightAndOpposite(rB, AnchorParam.Left); rB.SetStarWidth(2); rB.SetRightAndOpposite(rC, AnchorParam.Left); rC.SetStarWidth(2); rC.SetRight(null, AnchorParam.Right);
surf.Render(g); }
// Figure 10: Horizontal chain with weighted margins and packed rectangles. static void DrawSample7(GcGraphics g, Size _) { g.Transform = Matrix3x2.CreateScale(2);
var surf = new Surface();
var view = surf.CreateView(370, 120).Translate(30, 40); var v = view.CreateVisual(DrawView); v.Tag = new FigureCaption(10, "Rectangles are packed together after margins with weights\nare accounted for:", "rBeforeA.SetLeft(null, AnchorParam.Left);\n" + "rBeforeA.SetStarWidth(3);\n" + "rA.SetLeftAndOpposite(rBeforeA, AnchorParam.Right);\n" + "rA.SetWidth(70);\n" + "rB.SetLeftAndOpposite(rA, AnchorParam.Right);\n" + "rB.SetWidth(70);\n" + "rC.SetLeftAndOpposite(rB, AnchorParam.Right);\n" + "rC.SetWidth(70);\n" + "rAfterC.SetLeftAndOpposite(rC, AnchorParam.Right);\n" + "rAfterC.SetStarWidth(1);\n" + "rAfterC.SetRight(null, AnchorParam.Right);"); v.LayoutRect.AnchorExact(null);
v = view.CreateVisual(DrawRect); var rA = v.LayoutRect; rA.SetHeight(40); rA.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "A";
v = view.CreateVisual(DrawRect); var rB = v.LayoutRect; rB.SetHeight(40); rB.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "B";
v = view.CreateVisual(DrawRect); var rC = v.LayoutRect; rC.SetHeight(40); rC.SetVerticalCenter(null, AnchorParam.VerticalCenter); v.Tag = "C";
var rBeforeA = view.CreateVisual(DrawLineWithLeftArrow).LayoutRect; rBeforeA.AnchorTopBottom(rA, 0, 0);
var rAfterC = view.CreateVisual(DrawLineWithRightArrow).LayoutRect; rAfterC.AnchorTopBottom(rC, 0, 0);
rBeforeA.SetLeft(null, AnchorParam.Left); rBeforeA.SetStarWidth(3); rA.SetLeftAndOpposite(rBeforeA, AnchorParam.Right); rA.SetWidth(70); rB.SetLeftAndOpposite(rA, AnchorParam.Right); rB.SetWidth(70); rC.SetLeftAndOpposite(rB, AnchorParam.Right); rC.SetWidth(70); rAfterC.SetLeftAndOpposite(rC, AnchorParam.Right); rAfterC.SetStarWidth(1); rAfterC.SetRight(null, AnchorParam.Right);
surf.Render(g); }
// Text flow in and around non-rectangular contours. static void DrawSample8(GcGraphics g, Size pageSize) { g.FillRectangle(new RectangleF(0, 0, pageSize.Width, pageSize.Height), Color.White);
var surf = new Surface();
// Contour objects can be referenced in constraints defined for text rectangles. CreateFigure1(surf, out Contour c1_outer); CreateFigure2(surf, out Contour c2_outer, out Contour c2_inner);
const float rowHeight = 24f; const float lineSpacing = 5f; const float paragraphSpacing = 10f; const float fontSize = 18f;
// The main View object that displays horizontal text. var view = surf.CreateView(pageSize.Width, pageSize.Height); var rcMargin = view.CreateSpace().LayoutRect; rcMargin.AnchorDeflate(null, 20);
var tf = new TextFormat { Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSans.ttf")), FontSizeInGraphicUnits = true, FontSize = fontSize, FontFeatures = new FontFeature[] { new FontFeature(FeatureTag.liga, false) } }; var noRects = new List<ObjectRect>();
TextLayout tl = null;
var tso = new TextSplitOptions { RestObjectRects = noRects, AllowMovingAllToRest = true };
LayoutRect rcPrevTop = null; LayoutRect rcPrevLeft = null; bool paragraphStarted = false;
while (true) { var r0 = view.CreateVisual(DrawTextFragment).LayoutRect; if (rcPrevLeft != null) r0.SetTop(rcPrevLeft, AnchorParam.Top); else if (rcPrevTop != null) r0.SetTop(rcPrevTop, AnchorParam.Bottom, paragraphStarted ? lineSpacing : paragraphSpacing); else r0.SetTop(rcMargin, AnchorParam.Top); if (rcPrevLeft is null) r0.SetLeft(rcMargin, AnchorParam.Left); else r0.SetLeft(rcPrevLeft, AnchorParam.Right);
r0.SetHeight(rowHeight); r0.AppendMaxRight(rcMargin, AnchorParam.Right);
var r1 = view.CreateSpace().LayoutRect; r1.SetTop(r0, AnchorParam.Top); r1.SetHeight(rowHeight); r1.SetLeft(r0, AnchorParam.Right); r1.AppendMaxRight(rcMargin, AnchorParam.Right);
r0.AppendMaxRight(c1_outer, ContourPosition.FirstInOutside); r0.AppendMaxRight(c2_outer, ContourPosition.FirstInOutside);
r1.AppendMaxRight(c1_outer, ContourPosition.NextOutOutside); r1.AppendMaxRight(c2_outer, ContourPosition.NextOutOutside);
surf.PerformLayout();
if (!paragraphStarted) { // It is important to have the ObjectRects property set // to a not null value (an empty list works well) and // the AllowOverhangingWords property set to true.
tl = g.CreateTextLayout(); tl.ObjectRects = noRects; tl.TextAlignment = TextAlignment.Justified; tl.AllowOverhangingWords = true; tl.FirstLineIndent = 40f; tl.JustifiedTextExtension = 0.1f;
tl.Append(Common.Util.LoremIpsum(1), tf);
tl.MaxWidth = r0.Width; tl.MaxHeight = r0.Height; ((Visual)r0.Tag).Tag = tl;
if (!tl.PerformLayout()) { paragraphStarted = true; } } else { tso.RestMaxWidth = r0.Width; tso.RestMaxHeight = r0.Height; var res = tl.Split(tso, out TextLayout rest); if (res != SplitResult.CannotSplit) { tl = rest; ((Visual)r0.Tag).Tag = rest; if (tl.PerformLayout()) { paragraphStarted = false; } } }
if (paragraphStarted && r1.Width > 0f) rcPrevLeft = r1; else { ((Space)r1.Tag).Detach(); var spacing = paragraphStarted ? lineSpacing : paragraphSpacing; if (rcMargin.P2Y - r0.P2Y < spacing + rowHeight) { break; } rcPrevLeft = null; rcPrevTop = r0; } }
tl.Truncate(TrimmingGranularity.Word);
// The second View showing text in the ellipse. var view2 = surf.CreateView(pageSize.Width / 3, pageSize.Height / 2).Translate(520, 260).Rotate(15);
tf = new TextFormat(tf) { ForeColor = Color.Purple, FontSize = 14, }; tl = g.CreateTextLayout(); tl.ObjectRects = noRects; tl.TextAlignment = TextAlignment.Center; tl.AllowOverhangingWords = true;
tl.Append(Common.Util.LoremIpsum(1), tf);
rcPrevTop = null; paragraphStarted = false;
while (true) { var r0 = view2.CreateSpace().LayoutRect; if (rcPrevTop != null) r0.SetTop(rcPrevTop, AnchorParam.Bottom, 4); else r0.SetTop(null, AnchorParam.Top); r0.SetLeft(null, AnchorParam.Left);
r0.SetHeight(18); r0.AppendMaxRight(null, AnchorParam.Right);
var r1 = view2.CreateVisual(DrawTextFragment).LayoutRect; r1.SetTop(r0, AnchorParam.Top); r1.SetHeight(18); r1.SetLeft(r0, AnchorParam.Right); r1.AppendMaxRight(null, AnchorParam.Right);
r0.AppendMaxRight(c2_inner, ContourPosition.FirstInInside); r1.AppendMaxRight(c2_inner, ContourPosition.NextOutInside);
surf.PerformLayout(); if (r1.Width == 0f) { ((Space)r1.Tag).Detach(); if (paragraphStarted) { break; } } else if (!paragraphStarted) { tl.MaxWidth = r1.Width; tl.MaxHeight = r1.Height; ((Visual)r1.Tag).Tag = tl; if (tl.PerformLayout()) { break; } paragraphStarted = true; } else { tso.RestMaxWidth = r1.Width; tso.RestMaxHeight = r1.Height; var res = tl.Split(tso, out TextLayout rest); if (res == SplitResult.FitAll) { ((Space)r1.Tag).Detach(); break; } if (res == SplitResult.Split) { ((Visual)r1.Tag).Tag = rest; tl = rest; } } rcPrevTop = r0; }
tl.Truncate(TrimmingGranularity.Word);
surf.Render(g); }
// // Common utility classes and methods. //
class FigureCaption { public FigureCaption(int number, string description, string code = null) { Number = number; Description = description; Code = code; } public int Number { get; } public string Description { get; } public string Code { get; } }
static void DrawTextFragment(GcGraphics g, Visual v) { if (v.Tag is TextLayout tl) { g.DrawTextLayout(tl, new PointF(0, 0)); } }
static void CreateFigure1(Surface surf, out Contour c_outer) { // A View for the yellow polygon. var view = surf.CreateView(0, 0).Translate(120, -40).Rotate(40); var lv = view.LayoutView;
var c = lv.CreateContour();
var v = view.CreateVisual(c, true, (g, v) => { g.FillPolygon(v.Points, Color.LemonChiffon); g.DrawPolygon(v.Points, Color.Green, 3); }); var rect = v.LayoutRect; rect.AnchorTopLeft(null, 100, 150, 170, 70);
c.AddPoints(new AnchorPoint[] { rect.CreatePoint(0, 0, -20, -20), rect.CreatePoint(1, 0, 20, -20), rect.CreatePoint(1, 0, 20, -120), rect.CreatePoint(1, 0, 120, -120), rect.CreatePoint(1, 1, 120, 20), rect.CreatePoint(0, 1, -20, 20) });
surf.PerformLayout();
var points = c.MapToView(lv);
// To make the outer offset from the Contour we convert // the Contour to a GraphicsPath, then apply the Widen // method with a thick pen. The resulting figure is // used for creating the outer Contour. var gp = new GraphicsPath(new FreeFormPolygon(points)); var gp2 = gp.Widen(new GCDRAW.Pen(Color.White, 7 * 2));
var fig_outer = gp2.Figures[0];
fig_outer.Flatten(); var outer_points = fig_outer.TransformedPoints;
c_outer = lv.CreateContour(); for (int i = 0; i < outer_points.Length; i++) { var p = outer_points[i]; c_outer.AddPoint(lv.CreatePoint(0f, 0f, p.X, p.Y)); } }
static void CreateFigure2(Surface surf, out Contour c_outer, out Contour c_inner) { // A View for the rotated ellipse. var view = surf.CreateView(360, 150).Translate(450, 530).Rotate(-40); var lv = view.LayoutView;
var c = lv.CreateContour();
view.CreateVisual(c, false, (g, v) => { g.DrawPolygon(v.Points, Color.DeepPink, 3); });
// To make the inner and the outer offsets from the ellipse // we convert the elliptic figure to an array of points which // is used later for creating a GraphicsPath. Then, we call // the GraphicsPath.Widen method with a thick pen. // The resulting outer and inner figures can be converted // into new contours for later use in constraints. IFigure ef = new EllipticFigure(lv.AsRectF()); ef.Flatten(); var points = ef.TransformedPoints; int count = points.Length; var list = new List<AnchorPoint>(count); for (int i = 0; i < count; i++) { var p = points[i]; list.Add(lv.CreatePoint(0, 0, p.X, p.Y)); } c.AddPoints(list);
var gp = new GraphicsPath(ef); var gp2 = gp.Widen(new GCDRAW.Pen(Color.White, 7 * 2));
var fig_outer = gp2.Figures[0]; var fig_inner = gp2.Figures[1];
fig_outer.Flatten(); var outer_points = fig_outer.TransformedPoints;
c_outer = lv.CreateContour(); for (int i = 0; i < outer_points.Length; i++) { var p = outer_points[i]; c_outer.AddPoint(lv.CreatePoint(0f, 0f, p.X, p.Y)); }
fig_inner.Flatten(); var inner_points = fig_inner.TransformedPoints;
c_inner = lv.CreateContour(); for (int i = 0; i < inner_points.Length; i++) { var p = inner_points[i]; c_inner.AddPoint(lv.CreatePoint(0f, 0f, p.X, p.Y)); } }
static readonly TextFormat FormatBox = new TextFormat() { Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSans.ttf")), FontSize = 14, FontSizeInGraphicUnits = true, ForeColor = BoxColor };
static readonly TextFormat FormatDesc = new TextFormat(FormatBox) { FontSize = 12, ForeColor = DescColor };
static readonly TextFormat FormatCaption = new TextFormat(FormatDesc) { FontBold = true };
static readonly TextFormat FormatCode = new TextFormat(FormatDesc) { Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeMono.ttf")), ForeColor = CodeColor };
static void DrawView(GcGraphics g, Visual v) { var rect = v.AsRectF(); g.FillRectangle(rect, Color.FromArgb(31, 82, 100)); g.DrawRectangle(rect, new GCDRAW.Pen(Color.FromArgb(200, 200, 200), 1) { DashPattern = new float[] { 7, 3 } }); if (v.Tag is FigureCaption fc) { var tl = g.CreateTextLayout(); tl.Append($"Figure {fc.Number}. ", FormatCaption); tl.AppendLine(fc.Description, FormatDesc); if (fc.Code != null) { tl.Append(fc.Code, FormatCode); } g.DrawTextLayout(tl, new PointF(0, v.Height + 5)); } }
static void DrawVertGuideline(GcGraphics g, Visual v) { g.DrawLine(new PointF(0, 0), new PointF(0, v.Height), new GCDRAW.Pen(BoxColor, 1) { DashPattern = new float[] { 1, 2 } }); if (v.Tag is string s) { var tl = g.CreateTextLayout(); tl.Append(s, FormatDesc); tl.PerformLayout(); var rect = tl.ContentRectangle; rect.X = -rect.Width * 0.5f; rect.Y = 10; rect.Inflate(3, 1); g.FillRoundRect(rect, 3, RectColor); g.DrawTextLayout(tl, new PointF(rect.X + 3, rect.Y + 1)); } }
static void DrawRect(GcGraphics g, Visual v) { var rect = v.AsRectF(); g.FillRectangle(rect, RectColor); g.DrawRectangle(rect, new GCDRAW.Pen(BoxColor, 1)); if (v.Tag is string s) { var tl = g.CreateTextLayout(); tl.MaxWidth = v.Width; tl.MaxHeight = v.Height; tl.TextAlignment = TextAlignment.Center; tl.ParagraphAlignment = ParagraphAlignment.Center; tl.Append(s, FormatBox); g.DrawTextLayout(tl, new PointF(0, 0)); } }
static void DrawLineWithLeftArrow(GcGraphics g, Visual v) { var y = v.Height * 0.5f; g.DrawLine(new PointF(5, y), new PointF(v.Width, y), new GCDRAW.Pen(BoxColor, 0.7f)); DrawLeftArrow(g, 0, y); }
static void DrawLineWithRightArrow(GcGraphics g, Visual v) { var y = v.Height * 0.5f; g.DrawLine(new PointF(0, y), new PointF(v.Width - 5, y), new GCDRAW.Pen(BoxColor, 0.7f)); DrawRightArrow(g, v.Width, y); }
static void DrawLeftRightLines(GcGraphics g, Visual v) { var y = v.Height * 0.33f; g.DrawLine(new PointF(5, y), new PointF(v.Width, y), new GCDRAW.Pen(BoxColor, 0.7f)); DrawLeftArrow(g, 0, y); y = v.Height * 0.66f; g.DrawLine(new PointF(0, y), new PointF(v.Width - 5, y), new GCDRAW.Pen(BoxColor, 0.7f)); DrawRightArrow(g, v.Width, y); }
static void DrawVertLineWithLeftArrow(GcGraphics g, Visual v) { var x = v.Width * 0.5f; g.DrawLines(new PointF[] { new PointF(5, 0), new PointF(x, 0), new PointF(x, v.Height), new PointF(v.Width, v.Height) }, new GCDRAW.Pen(BoxColor, 0.7f)); DrawLeftArrow(g, 0, 0); }
static void DrawLineWithUpArrow(GcGraphics g, Visual v) { var x = v.Width * 0.5f; g.DrawLine(new PointF(x, 5), new PointF(x, v.Height), new GCDRAW.Pen(BoxColor, 0.7f)); DrawUpArrow(g, x, 0); }
static void DrawLeftArrow(GcGraphics g, float x, float y) { var pts = new PointF[] { new PointF(x, y), new PointF(x + 8, y - 2.5f), new PointF(x + 8, y + 2.5f), }; g.FillPolygon(pts, BoxColor); }
static void DrawRightArrow(GcGraphics g, float x, float y) { var pts = new PointF[] { new PointF(x, y), new PointF(x - 8, y + 2.5f), new PointF(x - 8, y - 2.5f), }; g.FillPolygon(pts, BoxColor); }
static void DrawUpArrow(GcGraphics g, float x, float y) { var pts = new PointF[] { new PointF(x, y), new PointF(x + 2.5f, y + 8), new PointF(x - 2.5f, y + 8), }; g.FillPolygon(pts, BoxColor); } }}