OSDN Git Service

715cd1cbe36887ae3d25e38d45afb5fcb0d92535
[fooeditengine/FooEditEngine.git] / Core / ViewBase.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 System.Linq;
14 using System.Text;
15 using System.Text.RegularExpressions;
16 using System.Threading.Tasks;
17
18 namespace FooEditEngine
19 {
20     /// <summary>
21     /// LineBreakMethod列挙体
22     /// </summary>
23     public enum LineBreakMethod
24     {
25         /// <summary>
26         /// 折り返さない
27         /// </summary>
28         None = 0,
29         /// <summary>
30         /// 右端で折り返す
31         /// </summary>
32         PageBound = 1,
33         /// <summary>
34         /// 文字数で折り返す
35         /// </summary>
36         CharUnit = 2
37     }
38
39     /// <summary>
40     /// 余白を表す
41     /// </summary>
42     public struct Padding
43     {
44         /// <summary>
45         /// 左余白
46         /// </summary>
47         public int Left;
48         /// <summary>
49         /// 上余白
50         /// </summary>
51         public int Top;
52         /// <summary>
53         /// 右余白
54         /// </summary>
55         public int Right;
56         /// <summary>
57         /// 下余白
58         /// </summary>
59         public int Bottom;
60         /// <summary>
61         /// コンストラクター
62         /// </summary>
63         /// <param name="left">左</param>
64         /// <param name="top">上</param>
65         /// <param name="right">右</param>
66         /// <param name="bottom">下</param>
67         public Padding(int left, int top, int right, int bottom)
68         {
69             this.Left = left;
70             this.Top = top;
71             this.Right = right;
72             this.Bottom = bottom;
73         }
74     }
75
76     abstract class ViewBase : IDisposable
77     {
78         const int SpiltCharCount = 1024;
79
80         Document _Document;
81         protected Rectangle _Rect;
82         protected double _LongestWidth;
83         Padding _Padding;
84
85         public ViewBase(Document doc, ITextRender r,Padding padding)
86         {
87             this._Padding = padding;
88             this.Document = doc;
89             this._LayoutLines.SpilitString = new SpilitStringEventHandler(LayoutLines_SpilitStringByChar);
90             this.render = r;
91             this.render.ChangedRenderResource += new ChangedRenderResourceEventHandler(render_ChangedRenderResource);
92             this.render.ChangedRightToLeft += render_ChangedRightToLeft;
93             this.SrcChanged += new EventHandler((s, e) => { });
94             this.PageBoundChanged += new EventHandler((s, e) => { });
95         }
96
97         public Document Document
98         {
99             get
100             {
101                 return this._Document;
102             }
103             set
104             {
105                 if(this._Document != null)
106                 {
107                     this._Document.UpdateCalledAlways -= new DocumentUpdateEventHandler(doc_Update);
108                     this._Document.LineBreakChanged -= Document_LineBreakChanged;
109                     this._Document.StatusUpdate -= Document_StatusUpdate;
110                     this._Document.PerformLayouted -= _Document_PerformLayouted;
111                 }
112
113                 this._Document = value;
114
115                 this._Document.UpdateCalledAlways += new DocumentUpdateEventHandler(doc_Update);
116                 this._Document.LineBreakChanged += Document_LineBreakChanged;
117                 this._Document.StatusUpdate += Document_StatusUpdate;
118                 this._Document.PerformLayouted += _Document_PerformLayouted;
119
120                 this.Document_LineBreakChanged(this, null);
121
122                 this.Document_StatusUpdate(this, null);
123             }
124         }
125
126         private void _Document_PerformLayouted(object sender, EventArgs e)
127         {
128             CalculateLineCountOnScreen();
129             if(this.PerformLayouted != null)
130                 this.PerformLayouted(this, e);
131         }
132
133         private void Document_StatusUpdate(object sender, EventArgs e)
134         {
135             if (this.render == null)
136                 return;
137             if (this.render.TabWidthChar != this.Document.TabStops)
138                 this.render.TabWidthChar = this.Document.TabStops;
139             if (this.render.RightToLeft != this.Document.RightToLeft)
140                 this.render.RightToLeft = this.Document.RightToLeft;
141             if (this.render.ShowFullSpace != this.Document.ShowFullSpace)
142                 this.render.ShowFullSpace = this.Document.ShowFullSpace;
143             if (this.render.ShowHalfSpace != this.Document.ShowHalfSpace)
144                 this.render.ShowHalfSpace = this.Document.ShowHalfSpace;
145             if (this.render.ShowTab != this.Document.ShowTab)
146                 this.render.ShowTab = this.Document.ShowTab;
147             if (this.render.ShowLineBreak != this.Document.ShowLineBreak)
148                 this.render.ShowLineBreak = this.Document.ShowLineBreak;
149             CalculateClipRect();
150             CalculateLineCountOnScreen();
151             this._LayoutLines.ClearLayoutCache();
152         }
153
154         private void Document_LineBreakChanged(object sender, EventArgs e)
155         {
156             if (this.Document.LineBreak != LineBreakMethod.None)
157                 this._LayoutLines.SpilitString = new SpilitStringEventHandler(LayoutLines_SpilitStringByPixelbase);
158             else
159                 this._LayoutLines.SpilitString = new SpilitStringEventHandler(LayoutLines_SpilitStringByChar);
160         }
161
162         protected LineToIndexTable _LayoutLines
163         {
164             get
165             {
166                 return this.Document.LayoutLines;
167             }
168         }
169
170         public event EventHandler SrcChanged;
171
172         [Obsolete]
173         public event EventHandler PerformLayouted;
174
175         public event EventHandler PageBoundChanged;
176
177         /// <summary>
178         /// テキストレンダラ―
179         /// </summary>
180         public ITextRender render
181         {
182             get;
183             set;
184         }
185
186         /// <summary>
187         /// 一ページの高さに収まる行数を返す
188         /// </summary>
189         public int LineCountOnScreen
190         {
191             get;
192             protected set;
193         }
194
195         /// <summary>
196         /// 折り返し時の右マージン
197         /// </summary>
198         public double LineBreakingMarginWidth
199         {
200             get;
201             protected set;
202         }
203
204         /// <summary>
205         /// 保持しているレイアウト行
206         /// </summary>
207         public LineToIndexTable LayoutLines
208         {
209             get { return this._LayoutLines; }
210         }
211
212         /// <summary>
213         /// 最も長い行の幅
214         /// </summary>
215         public double LongestWidth
216         {
217             get { return this._LongestWidth; }
218         }
219
220         public double LineNumberMargin
221         {
222             get
223             {
224                 return this.render.emSize.Width;
225             }
226         }
227
228         /// <summary>
229         /// シンタックスハイライター
230         /// </summary>
231         /// <remarks>差し替えた場合、再構築する必要があります</remarks>
232         public IHilighter Hilighter
233         {
234             get { return this._LayoutLines.Hilighter; }
235             set { this._LayoutLines.Hilighter = value; this._LayoutLines.ClearLayoutCache(); }
236         }
237
238         /// <summary>
239         /// すべてのレイアウト行を破棄し、再度レイアウトをやり直す
240         /// </summary>
241         [Obsolete]
242         public virtual void PerfomLayouts()
243         {
244             //互換性を保つために残しておく
245             this.Document.PerformLayout();
246         }
247
248         /// <summary>
249         /// 余白を表す
250         /// </summary>
251         public Padding Padding
252         {
253             get {
254                 return this._Padding;
255             }
256             set {
257                 this._Padding = value;
258                 CalculateClipRect();
259                 CalculateLineCountOnScreen();
260                 if (this.Document.RightToLeft)
261                     this._LayoutLines.ClearLayoutCache();
262                 this.PageBoundChanged(this, null);
263             }
264         }
265
266         /// <summary>
267         /// ページ全体を表す領域
268         /// </summary>
269         public Rectangle PageBound
270         {
271             get { return this._Rect; }
272             set
273             {
274                 if (value.Width < 0 || value.Height < 0)
275                     throw new ArgumentOutOfRangeException("");
276                 this._Rect = value;
277                 CalculateClipRect();
278                 CalculateLineCountOnScreen();
279                 if (this.Document.RightToLeft)
280                     this._LayoutLines.ClearLayoutCache();
281                 this.PageBoundChanged(this, null);
282             }
283         }
284
285         /// <summary>
286         /// Draw()の対象となる領域の左上を表す
287         /// </summary>
288         public SrcPoint Src
289         {
290             get { return this.Document.Src; }
291             set { this.Document.Src = value; }
292         }
293
294         public virtual void Draw(Rectangle updateRect, bool force = false)
295         {
296             return;
297         }
298
299         public virtual bool TryScroll(double x, int row)
300         {
301             if (row < 0)
302                 return true;
303             if (row > this.LayoutLines.Count - 1)
304                 return true;
305             this.Document.Src = new SrcPoint(x, row, row * this.render.emSize.Height);
306             this.SrcChanged(this,null);
307             return false;
308         }
309
310         public void Dispose()
311         {
312             this.Dispose(true);
313             GC.SuppressFinalize(this);
314         }
315
316         public virtual void CalculateLineCountOnScreen()
317         {
318         }
319
320         protected virtual void Dispose(bool disposing)
321         {
322             if (disposing)
323             {
324                 this._Document.UpdateCalledAlways -= new DocumentUpdateEventHandler(this.doc_Update);    //これをしないと複数のビューを作成した時に妙なエラーが発生する
325                 this._Document.LineBreakChanged -= Document_LineBreakChanged;
326                 this._Document.StatusUpdate -= Document_StatusUpdate;
327                 this._Document.PerformLayouted -= _Document_PerformLayouted;
328             }
329             this._LayoutLines.Clear();
330         }
331
332         protected virtual void CalculateClipRect()
333         {
334         }
335
336
337         protected virtual void OnSrcChanged(EventArgs e)
338         {
339             EventHandler handler = this.SrcChanged;
340             if (handler != null)
341                 this.SrcChanged(this, e);
342         }
343
344         protected virtual void OnPerformLayoutedChanged(EventArgs e)
345         {
346             EventHandler handler = this.PerformLayouted;
347             if (handler != null)
348                 this.PerformLayouted(this, e);
349         }
350
351         protected virtual void OnPageBoundChanged(EventArgs e)
352         {
353             EventHandler handler = this.PageBoundChanged;
354             if (handler != null)
355                 this.PageBoundChanged(this, e);
356         }
357
358         void render_ChangedRightToLeft(object sender, EventArgs e)
359         {
360             this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Src.Y);
361         }
362
363         void render_ChangedRenderResource(object sender, ChangedRenderRsourceEventArgs e)
364         {
365             this._LayoutLines.ClearLayoutCache();
366             if (e.type == ResourceType.Font)
367             {
368                 this.CalculateClipRect();
369                 this.CalculateLineCountOnScreen();
370             }
371         }
372
373         void doc_Update(object sender, DocumentUpdateEventArgs e)
374         {
375             switch (e.type)
376             {
377                 case UpdateType.Clear:
378                     this._LongestWidth = 0;
379                     break;
380             }
381         }
382
383         IList<LineToIndexTableData> LayoutLines_SpilitStringByPixelbase(object sender, SpilitStringEventArgs e)
384         {
385             double WrapWidth;
386             if (this.Document.LineBreak == LineBreakMethod.PageBound)
387                 WrapWidth = this.render.TextArea.Width - LineBreakingMarginWidth;  //余白を残さないと欠ける
388             else
389                 WrapWidth = this.render.emSize.Width * this.Document.LineBreakCharCount;
390
391             if (WrapWidth < 0 && this.Document.LineBreak != LineBreakMethod.None)
392                 throw new InvalidOperationException();
393
394             int startIndex = e.index;
395             int endIndex = e.index + e.length - 1;
396
397             LineToIndexTable layoutLineCollection = (LineToIndexTable)sender;
398
399             return this.render.BreakLine(e.buffer,layoutLineCollection, startIndex, endIndex, WrapWidth);
400         }
401
402         IList<LineToIndexTableData> LayoutLines_SpilitStringByChar(object sender, SpilitStringEventArgs e)
403         {
404             return this.Document.CreateLineList(e.index, e.length, Document.MaximumLineLength);
405         }
406     }
407 }