2 * Copyright (C) 2013 FooProject
\r
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
\r
4 * the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
\r
6 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
\r
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/>.
\r
12 using System.Collections.Generic;
\r
15 using System.Threading.Tasks;
\r
17 namespace FooEditEngine
\r
20 /// LineBreakMethod列挙体
\r
22 public enum LineBreakMethod
\r
38 abstract class ViewBase : IDisposable
\r
40 const int SpiltCharCount = 1024;
\r
42 protected Document Document;
\r
43 protected LineToIndexTable _LayoutLines;
\r
44 protected Point2 _Src = new Point2();
\r
45 protected Rectangle _Rect;
\r
46 protected double _LongestWidth;
\r
47 bool _DrawLineNumber;
\r
48 LineBreakMethod _LineBreak;
\r
49 int _LineBreakCharCount = 80;
\r
51 public ViewBase(Document doc, ITextRender r)
\r
53 this.Document = doc;
\r
54 this.Document.UpdateCalledAlways += new DocumentUpdateEventHandler(doc_Update);
\r
55 this._LayoutLines = new LineToIndexTable(this.Document, r);
\r
56 this._LayoutLines.SpilitString = new SpilitStringEventHandler(LayoutLines_SpilitStringByChar);
\r
58 this.render.ChangedRenderResource += new ChangedRenderResourceEventHandler(render_ChangedRenderResource);
\r
59 this.render.ChangedRightToLeft += render_ChangedRightToLeft;
\r
60 this.SrcChanged += new EventHandler((s, e) => { });
\r
61 this.PerformLayouted += new EventHandler((s, e) => { });
\r
62 this.PageBoundChanged += new EventHandler((s, e) => { });
\r
65 public event EventHandler SrcChanged;
\r
67 public event EventHandler PerformLayouted;
\r
69 public event EventHandler PageBoundChanged;
\r
72 /// URLをハイパーリンクとして表示するなら真。そうでないなら偽
\r
76 get { return this.LayoutLines.UrlMark; }
\r
77 set { this.LayoutLines.UrlMark = value; }
\r
83 public ITextRender render
\r
90 /// 一ページの高さに収まる行数を返す
\r
92 public int LineCountOnScreen
\r
101 public double LineBreakingMarginWidth
\r
110 public LineToIndexTable LayoutLines
\r
112 get { return this._LayoutLines; }
\r
118 public double LongestWidth
\r
120 get { return this._LongestWidth; }
\r
127 /// 変更した場合、呼び出し側で再描写とレイアウトの再構築を行う必要があります
\r
129 public LineBreakMethod LineBreak
\r
133 return this._LineBreak;
\r
137 this._LineBreak = value;
\r
138 if (value != LineBreakMethod.None)
\r
139 this._LayoutLines.SpilitString = new SpilitStringEventHandler(LayoutLines_SpilitStringByPixelbase);
\r
141 this._LayoutLines.SpilitString = new SpilitStringEventHandler(LayoutLines_SpilitStringByChar);
\r
146 /// 折り返し行う文字数。実際に折り返しが行われる幅はem単位×この値となります
\r
148 public int LineBreakCharCount
\r
152 return this._LineBreakCharCount;
\r
156 this._LineBreakCharCount = value;
\r
163 public IHilighter Hilighter
\r
165 get { return this._LayoutLines.Hilighter; }
\r
166 set { this._LayoutLines.Hilighter = value; }
\r
172 /// <remarks>変更した場合、呼び出し側で再描写する必要があります</remarks>
\r
173 public int TabStops
\r
175 get { return this.render.TabWidthChar; }
\r
176 set { this.render.TabWidthChar = value; }
\r
180 /// すべてのレイアウト行を破棄し、再度レイアウトをやり直す
\r
182 public virtual void PerfomLayouts()
\r
184 this.doc_Update(this.Document, new DocumentUpdateEventArgs(UpdateType.Clear, -1, -1, -1));
\r
185 this.doc_Update(this.Document, new DocumentUpdateEventArgs(UpdateType.Replace, 0, 0, this.Document.Length));
\r
186 CalculateLineCountOnScreen();
\r
187 this.PerformLayouted(this, null);
\r
193 public Rectangle PageBound
\r
195 get { return this._Rect; }
\r
198 if (value.Width < 0 || value.Height < 0)
\r
199 throw new ArgumentOutOfRangeException("");
\r
200 this._Rect = value;
\r
201 CalculateClipRect();
\r
202 CalculateLineCountOnScreen();
\r
203 if (this.render.RightToLeft)
\r
204 this._LayoutLines.ClearLayoutCache();
\r
205 this.PageBoundChanged(this, null);
\r
210 /// Draw()の対象となる領域の左上を表す
\r
214 get { return this._Src; }
\r
215 set { this._Src = value; }
\r
221 public bool DrawLineNumber
\r
223 get { return this._DrawLineNumber; }
\r
226 this._DrawLineNumber = value;
\r
227 this._LayoutLines.ClearLayoutCache();
\r
228 CalculateClipRect();
\r
232 public virtual void Draw(Rectangle updateRect)
\r
236 public virtual bool TryScroll(double x, int row)
\r
240 if (row > this.LayoutLines.Count - 1)
\r
243 this._Src.Row = row;
\r
244 CalculateLineCountOnScreen();
\r
245 this.SrcChanged(this,null);
\r
249 public void Dispose()
\r
251 this.Dispose(true);
\r
252 GC.SuppressFinalize(this);
\r
255 public virtual void CalculateLineCountOnScreen()
\r
259 protected virtual void Dispose(bool disposing)
\r
263 this.Document.UpdateCalledAlways -= new DocumentUpdateEventHandler(this.doc_Update); //これをしないと複数のビューを作成した時に妙なエラーが発生する
\r
265 this._LayoutLines.Clear();
\r
268 protected virtual void CalculateClipRect()
\r
273 protected virtual void OnSrcChanged(EventArgs e)
\r
275 EventHandler handler = this.SrcChanged;
\r
276 if (handler != null)
\r
277 this.SrcChanged(this, e);
\r
280 protected virtual void OnPerformLayoutedChanged(EventArgs e)
\r
282 EventHandler handler = this.PerformLayouted;
\r
283 if (handler != null)
\r
284 this.PerformLayouted(this, e);
\r
287 protected virtual void OnPageBoundChanged(EventArgs e)
\r
289 EventHandler handler = this.PageBoundChanged;
\r
290 if (handler != null)
\r
291 this.PageBoundChanged(this, e);
\r
294 void render_ChangedRightToLeft(object sender, EventArgs e)
\r
297 this._LayoutLines.ClearLayoutCache();
\r
298 this.CalculateClipRect();
\r
301 void render_ChangedRenderResource(object sender, ChangedRenderRsourceEventArgs e)
\r
303 this._LayoutLines.ClearLayoutCache();
\r
304 if (e.type == ResourceType.Font)
\r
306 this.CalculateClipRect();
\r
307 this.CalculateLineCountOnScreen();
\r
311 void doc_Update(object sender, DocumentUpdateEventArgs e)
\r
315 case UpdateType.Replace:
\r
316 this._LayoutLines.UpdateAsReplace(e.startIndex, e.removeLength, e.insertLength);
\r
318 case UpdateType.Clear:
\r
319 this._LayoutLines.Clear();
\r
320 this._LongestWidth = 0;
\r
325 IList<LineToIndexTableData> LayoutLines_SpilitStringByPixelbase(object sender, SpilitStringEventArgs e)
\r
328 if (_LineBreak == LineBreakMethod.PageBound)
\r
329 WrapWidth = this.render.TextArea.Width - LineBreakingMarginWidth; //余白を残さないと欠ける
\r
331 WrapWidth = this.render.emSize.Width * this._LineBreakCharCount;
\r
333 if (WrapWidth < 0 && this._LineBreak != LineBreakMethod.None)
\r
334 throw new InvalidOperationException();
\r
336 int startIndex = e.index;
\r
337 int endIndex = e.index + e.length - 1;
\r
339 LineToIndexTable layoutLineCollection = (LineToIndexTable)sender;
\r
341 return this.render.BreakLine(e.buffer,layoutLineCollection, startIndex, endIndex, WrapWidth);
\r
344 IList<LineToIndexTableData> LayoutLines_SpilitStringByChar(object sender, SpilitStringEventArgs e)
\r
346 LineToIndexTable layoutLineCollection = (LineToIndexTable)sender;
\r
347 int startIndex = e.index;
\r
348 int endIndex = e.index + e.length - 1;
\r
349 List<LineToIndexTableData> output = new List<LineToIndexTableData>();
\r
351 foreach (Tuple<int, int> range in this.Document.ForEachLines(startIndex, endIndex, 1000))
\r
353 int lineHeadIndex = range.Item1;
\r
354 int lineLength = range.Item2;
\r
355 char c = this.Document[lineHeadIndex + lineLength - 1];
\r
356 bool hasNewLine = c == Document.NewLine;
\r
357 output.Add(layoutLineCollection.CreateLineToIndexTableData(lineHeadIndex, lineLength, hasNewLine, null));
\r
360 if (output.Count > 0)
\r
361 output.Last().LineEnd = true;
\r