OSDN Git Service

読み込み時に行分割を行わず、レタリング時に行分割を行うようにした
[fooeditengine/FooEditEngine.git] / Core / Direct2D / MyTextLayout.cs
1 /*
2  * Copyright (C) 2013 FooProject
3  * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
5
6  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 
7  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8
9 You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
10  */
11 using System;
12 using System.Collections.Generic;
13 using SharpDX;
14 using D2D = SharpDX.Direct2D1;
15 using DW = SharpDX.DirectWrite;
16
17 namespace FooEditEngine
18 {
19     sealed class MyTextLayout : ITextLayout
20     {
21         double _height = double.NaN;
22         double _width = double.NaN;
23         int lineBreakIndex = 0;
24         StringAlignment _strAlign;
25
26         internal MyTextLayout(DW.Factory dwFactory,string str,DW.TextFormat format,double width,double height,float dip,bool showLineBreak)
27         {
28             if (dwFactory.IsDisposed)
29             {
30                 throw new InvalidOperationException();
31             }
32             str = str.Trim(Document.NewLine);   //取り除かないとキャレットの動きがおかしくなる
33             if (showLineBreak)
34             {
35                 this.lineBreakIndex = str.Length;
36                 str = str + "↵";
37             }
38             this.layout = new DW.TextLayout(dwFactory,
39                 str,
40                 format,
41                 (float)width,
42                 (float)height);
43             this.Disposed = false;
44             this.ShowLineBreak = showLineBreak;
45         }
46
47         DW.TextLayout layout;
48
49         public bool ShowLineBreak
50         {
51             get;
52             private set;
53         }
54
55         public bool Disposed
56         {
57             get;
58             private set;
59         }
60
61         public bool Invaild
62         {
63             get;
64             set;
65         }
66
67         public float MaxWidth
68         {
69             get
70             {
71                 return this.layout.MaxWidth;
72             }
73         }
74
75         public float MaxHeight
76         {
77             get
78             {
79                 return this.layout.MaxHeight;
80             }
81         }
82
83         public bool RightToLeft
84         {
85             get
86             {
87                 return this.layout.ReadingDirection == DW.ReadingDirection.RightToLeft;
88             }
89             set
90             {
91                 if (value)
92                     this.layout.ReadingDirection = DW.ReadingDirection.RightToLeft;
93                 else
94                     this.layout.ReadingDirection = DW.ReadingDirection.LeftToRight;
95             }
96         }
97         
98         public int GetIndexFromColPostion(double x)
99         {
100             return this.GetIndexFromPostion(x, 0);
101         }
102
103         public double GetWidthFromIndex(int index)
104         {
105             float x, y;
106             DW.HitTestMetrics metrics;
107             metrics = this.layout.HitTestTextPosition(index, false, out x, out y);
108             float x2;
109             layout.HitTestTextPosition(index, true, out x2, out y);
110
111             return x2 - x;
112         }
113
114         public double GetColPostionFromIndex(int index)
115         {
116             Point p = this.GetPostionFromIndex(index);
117             return p.X;
118         }
119
120         public int GetIndexFromPostion(double x, double y)
121         {
122             SharpDX.Mathematics.Interop.RawBool isTrailing, isInsed;
123             DW.HitTestMetrics metrics;
124             metrics = this.layout.HitTestPoint((float)x, (float)y, out isTrailing, out isInsed);
125             int index;
126             if (isTrailing)
127                 index = metrics.TextPosition + metrics.Length;
128             else
129                 index = metrics.TextPosition;
130             if (this.ShowLineBreak && index == this.lineBreakIndex + 1) //改行マークの後ろにヒットしたら
131                 index--;
132             return index;
133         }
134
135         public Point GetPostionFromIndex(int index)
136         {
137             float x, y;
138             DW.HitTestMetrics metrics;
139             metrics = this.layout.HitTestTextPosition(index, false, out x, out y);
140             return new Point(x,y);
141         }
142
143         public int AlignIndexToNearestCluster(int index, AlignDirection flow)
144         {
145             float x, y;
146             DW.HitTestMetrics metrics;
147             metrics = this.layout.HitTestTextPosition(index, false, out x, out y);
148
149             if (flow == AlignDirection.Forward)
150                 return Util.RoundUp(metrics.TextPosition + metrics.Length);
151             else if (flow == AlignDirection.Back)
152                 return Util.RoundUp(metrics.TextPosition);
153             throw new ArgumentOutOfRangeException();
154         }
155
156         public double Width
157         {
158             get
159             {
160                 if(double.IsNaN(this._width))
161                     this._width = Util.RoundUp(this.layout.Metrics.WidthIncludingTrailingWhitespace);
162                 return this._width;
163             }
164         }
165
166         public double Height
167         {
168             get
169             {
170                 if (!double.IsNaN(this._height))
171                     return this._height;
172                 this._height = Util.RoundUp(this.layout.Metrics.Height);
173                 return this._height;
174             }
175         }
176
177         public StringAlignment StringAlignment
178         {
179             get
180             {
181                 return this._strAlign;
182             }
183             set
184             {
185                 this._strAlign = value;
186                 switch (value)
187                 {
188                     case StringAlignment.Left:
189                         layout.TextAlignment = DW.TextAlignment.Leading;
190                         break;
191                     case StringAlignment.Center:
192                         layout.TextAlignment = DW.TextAlignment.Center;
193                         break;
194                     case StringAlignment.Right:
195                         layout.TextAlignment = DW.TextAlignment.Trailing;
196                         break;
197                 }
198             }
199         }
200
201         public void Draw(D2D.RenderTarget d2drender, DW.TextRenderer render, float x, float y)
202         {
203             this.layout.Draw(d2drender, render, x, y);
204         }
205
206         public void Draw(D2D.RenderTarget render, float x, float y, D2D.Brush brush)
207         {
208             render.DrawTextLayout(new Vector2((float)x, (float)y), this.layout, brush);
209         }
210
211         public void Dispose()
212         {
213             this.layout.Dispose();
214             this.Disposed = true;
215         }
216
217         public void SetDrawingEffect(ComObject resource, DW.TextRange range)
218         {
219             this.layout.SetDrawingEffect(resource, range);
220         }
221
222         public void SetLineBreakBrush(D2D.Brush brush)
223         {
224             if(this.ShowLineBreak)
225                 this.layout.SetDrawingEffect(brush, new DW.TextRange(lineBreakIndex, 1));
226         }
227
228         public void SetUnderline(bool underline, DW.TextRange range)
229         {
230             this.layout.SetUnderline(underline, range);
231         }
232
233         public DW.HitTestMetrics[] HitTestTextRange(int start, int length, float x, float y)
234         {
235             return this.layout.HitTestTextRange(start, length, x, y);
236         }
237
238         public void SetInlineObject(DW.InlineObject o, DW.TextRange range)
239         {
240             this.layout.SetInlineObject(o, range);
241         }
242     }
243 }