LayoutDemos.cs
//
// このコードは、DioDocs for PDF のサンプルの一部として提供されています。
// © MESCIUS inc. All rights reserved.
//
using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using GrapeCity.Documents.Pdf;
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 DsPdfWeb.Demos
{
// この統合サンプルでは、GrapeCity.Documents.Layout.Composition 名前空間の
// ヘルパークラスを使用して、独自の Z オーダーやクリッピングを持つ
// 複雑で柔軟な制約ベースのレイアウトを作成する方法を紹介しています。
public class LayoutDemos
{
static readonly Color
PageColor = Color.FromArgb(39, 41, 43),
BoxColor = Color.FromArgb(230, 230, 230),
CodeColor = Color.FromArgb(0, 77, 102),
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 int CreatePDF(Stream stream, int paramsIdx = 0)
{
return CreatePDF(stream, GetSampleParamsList()[paramsIdx]);
}
public int CreatePDF(Stream stream, string[] sampleParams)
{
if (!c_samples.TryGetValue(sampleParams[3], out DrawLayoutSample drawSample))
throw new Exception($"不明なパラメータのサンプル:{sampleParams[3]}");
var doc = new GcPdfDocument();
var page = doc.NewPage();
if (sampleParams[3] == "DrawSample1")
page.Landscape = true;
var g = page.Graphics;
g.Resolution = 96;
drawSample(g, g.CanvasSize.ToSize());
// PDF を保存します。
doc.Save(stream);
return doc.Pages.Count;
}
public GcBitmap GenerateImage(Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
{
if (!c_samples.TryGetValue(sampleParams[3], out DrawLayoutSample drawSample))
throw new Exception($"不明なパラメータのサンプル:{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[]>()
{
// この文字列は、各サンプルの名前、説明、サンプルIDです。
new string[] { "図 1-4", "図 1-4:水平および垂直の配置制約",
null,
"DrawSample1" },
new string[] { "図 5", "図 5:2 つの Visual に固定された境界制約",
null,
"DrawSample2" },
new string[] { "図 6", "図 6:比率指定の幅を含む水平方向のチェーン",
null,
"DrawSample3" },
new string[] { "図 7", "図 7:長方形と余白が均等に配置された水平方向のチェーン",
null,
"DrawSample4" },
new string[] { "図 8", "図 8:長方形が均等に配置された水平方向のチェーン(余白なし)",
null,
"DrawSample5" },
new string[] { "図 9", "図 9:余白なしの比率による水平方向のチェーン",
null,
"DrawSample6" },
new string[] { "図 10", "図 10:比率指定の余白と一纏めにされた長方形を含む水平方向のチェーン",
null,
"DrawSample7" },
new string[] { "テキストフロー", "非矩形の輪郭の中や周囲にテキストを描画",
null,
"DrawSample8" },
};
}
// 図 1-4:水平および垂直の配置制約
static void DrawSample1(GcGraphics g, Size _)
{
g.Transform = Matrix3x2.CreateScale(1.4f);
// Surface オブジェクトは Visual をレイアウトしグラフィックス上に描画することができます。
var surf = new Surface();
// View1
// View オブジェクトは、変換行列を持つ Visual のグループを表します。
var view1 = surf.CreateView(250, 150).Translate(50, 40);
// Visual は、その配置に使用される関連する LayoutRect と、
// そのコンテンツをグラフィックス上に描画するデリゲートを含む要素です。
var v = view1.CreateVisual(DrawView);
v.Tag = new FigureCaption(1, "親に対する水平方向の配置制約:",
"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, "オフセットされた水平方向の配置制約:",
"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, "水平方向と垂直方向の配置制約:",
"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, "ガイドラインに制約された矩形:",
"var anchorPoint = layoutView.CreatePoint(0.25f, 0);\n" +
"rA.SetLeft(anchorPoint, 60);");
v.LayoutRect.AnchorExact(null);
// AnchorPoint は、X軸またはY軸のガイドラインとして機能します。
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);
}
// 図 5:2 つの Visual に固定された境界制約
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;
// 同じ矩形に複数の MinLeft 制約を追加すると、
// 他の矩形のベースとして使用される境界が作成されます。
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 は境界に制約され、\n" +
"A と 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);
}
// 図 6:比率指定の幅を含む水平方向のチェーン
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, "比率指定の幅を持つ 2 つの長方形と\n" +
"その間に固定スペースを含む水平方向のチェーン:",
"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);
// SetStarWidth メソッドは、同じチェーンに属し、
// 比率幅を持つ他の矩形の幅に対する、
// その特定の矩形の幅の比率を設定します。
// SetLeftAndOpposite メソッドは、両方向で互いの位置に
// 影響を与える矩形のチェーンを作成します。
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);
}
// 図 7:長方形と余白が均等に配置された水平方向のチェーン
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, "余白を考慮した上で、\n" +
"3 つの長方形が均等に配置された水平方向のチェーン:",
"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);
}
// 図 8:長方形が均等に配置された水平方向のチェーン(余白なし)
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, "図 7 と同じだが余白は考慮しない:",
"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);
}
// 図 9:余白なしの比率による水平方向のチェーン
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, "余白なしの比率による水平方向のチェーン:",
"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);
}
// 図 10:比率指定の余白と一纏めにされた長方形を含む水平方向のチェーン
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, "比率指定の余白を考慮したうえで\n長方形を一纏めにする:",
"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);
}
// 非矩形の輪郭の中や周囲にテキストを描画
static void DrawSample8(GcGraphics g, Size pageSize)
{
g.FillRectangle(new RectangleF(0, 0, pageSize.Width, pageSize.Height), Color.White);
var surf = new Surface();
// Contour オブジェクトは、テキスト矩形に定義された制約で参照することができます。
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;
// 横書きテキストを表示するメインの View オブジェクトです。
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", "calibri.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)
{
// ObjectRects プロパティに null でない値(空のリストが有効)を設定し、
// AllowOverhangingWords プロパティに 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);
// 楕円の中にテキストを表示する2番目の View です。
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);
}
//
// 共通のユーティリティクラスとメソッド
//
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)
{
// 黄色い多角形の View です。
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);
// Contour から外側のオフセットを作るために、Contour を
// GraphicsPath に変換し、太いペンにて Widen メソッドを適用します。
// 出来上がった図形は、外側の 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)
{
// 回転した楕円の View です。
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);
});
// 楕円の内側と外側のオフセットを作るために、楕円の図形を点の配列に変換し、
// GraphicsPath を作成するために使用します。
// そして、太いペンにて GraphicsPath.Widen メソッドを呼び出します。
// 出来上がった外側と内側の図形は、後で制約に使用するために
// 新しい Contour に変換することができます。
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", "segoeui.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", "cour.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($"図 {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);
}
}
}