OSDN Git Service

6d90504a3d1836bfcc352d93b1e14c13d1580c2f
[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             SharpDX.Mathematics.Interop.RawBool isTrailing, isInsed;
101             DW.HitTestMetrics metrics;
102             metrics = this.layout.HitTestPoint((float)x, 0, out isTrailing, out isInsed);
103             int index;
104             if(isTrailing)
105                 index = metrics.TextPosition + metrics.Length;
106             else
107                 index = metrics.TextPosition;
108             if (this.ShowLineBreak && index == this.lineBreakIndex + 1) //改行マークの後ろにヒットしたら
109                 index--;
110             return index;
111         }
112
113         public double GetWidthFromIndex(int index)
114         {
115             float x, y;
116             DW.HitTestMetrics metrics;
117             metrics = this.layout.HitTestTextPosition(index, false, out x, out y);
118             float x2;
119             layout.HitTestTextPosition(index, true, out x2, out y);
120
121             return x2 - x;
122         }
123
124         public double GetColPostionFromIndex(int index)
125         {
126             float x, y;
127             DW.HitTestMetrics metrics;
128             metrics = this.layout.HitTestTextPosition(index, false, out x, out y);
129             return x;
130         }
131
132         public int AlignIndexToNearestCluster(int index, AlignDirection flow)
133         {
134             float x, y;
135             DW.HitTestMetrics metrics;
136             metrics = this.layout.HitTestTextPosition(index, false, out x, out y);
137
138             if (flow == AlignDirection.Forward)
139                 return Util.RoundUp(metrics.TextPosition + metrics.Length);
140             else if (flow == AlignDirection.Back)
141                 return Util.RoundUp(metrics.TextPosition);
142             throw new ArgumentOutOfRangeException();
143         }
144
145         public double Width
146         {
147             get
148             {
149                 if(double.IsNaN(this._width))
150                     this._width = Util.RoundUp(this.layout.Metrics.WidthIncludingTrailingWhitespace);
151                 return this._width;
152             }
153         }
154
155         public double Height
156         {
157             get
158             {
159                 if (!double.IsNaN(this._height))
160                     return this._height;
161                 this._height = Util.RoundUp(layout.Metrics.Height);
162                 return this._height;
163             }
164         }
165
166         public StringAlignment StringAlignment
167         {
168             get
169             {
170                 return this._strAlign;
171             }
172             set
173             {
174                 this._strAlign = value;
175                 switch (value)
176                 {
177                     case StringAlignment.Left:
178                         layout.TextAlignment = DW.TextAlignment.Leading;
179                         break;
180                     case StringAlignment.Center:
181                         layout.TextAlignment = DW.TextAlignment.Center;
182                         break;
183                     case StringAlignment.Right:
184                         layout.TextAlignment = DW.TextAlignment.Trailing;
185                         break;
186                 }
187             }
188         }
189
190         public void Draw(DW.TextRenderer render, float x, float y)
191         {
192             this.layout.Draw(render, x, y);
193         }
194
195         public void Draw(D2D.RenderTarget render, float x, float y, D2D.Brush brush)
196         {
197             render.DrawTextLayout(new Vector2((float)x, (float)y), this.layout, brush);
198         }
199
200         public void Dispose()
201         {
202             this.layout.Dispose();
203             this.Disposed = true;
204         }
205
206         public void SetDrawingEffect(ComObject resource, DW.TextRange range)
207         {
208             this.layout.SetDrawingEffect(resource, range);
209         }
210
211         public void SetLineBreakBrush(D2D.Brush brush)
212         {
213             if(this.ShowLineBreak)
214                 this.layout.SetDrawingEffect(brush, new DW.TextRange(lineBreakIndex, 1));
215         }
216
217         public void SetUnderline(bool underline, DW.TextRange range)
218         {
219             this.layout.SetUnderline(underline, range);
220         }
221
222         public DW.HitTestMetrics[] HitTestTextRange(int start, int length, float x, float y)
223         {
224             return this.layout.HitTestTextRange(start, length, x, y);
225         }
226
227         public void SetInlineObject(DW.InlineObject o, DW.TextRange range)
228         {
229             this.layout.SetInlineObject(o, range);
230         }
231     }
232 }