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.
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.
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/>.
12 using System.Collections.Generic;
15 using System.Text.RegularExpressions;
16 using System.Threading.Tasks;
18 namespace FooEditEngine
21 /// LineBreakMethod列挙体
23 public enum LineBreakMethod
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)
76 abstract class ViewBase : IDisposable
78 const int SpiltCharCount = 1024;
81 protected Rectangle _Rect;
82 protected double _LongestWidth,_LongestHeight;
85 public ViewBase(Document doc, ITextRender r,Padding padding)
87 this._Padding = padding;
90 this._LayoutLines.SpilitString = new SpilitStringEventHandler(LayoutLines_SpilitStringByChar);
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) => { });
97 public Document Document
101 return this._Document;
105 if(this._Document != null)
107 this._Document.Update -= new DocumentUpdateEventHandler(doc_Update);
108 this._Document.LineBreakChanged -= Document_LineBreakChanged;
109 this._Document.StatusUpdate -= Document_StatusUpdate;
110 this._Document.PerformLayouted -= _Document_PerformLayouted;
113 this._Document = value;
115 this._Document.Update += new DocumentUpdateEventHandler(doc_Update);
116 this._Document.LineBreakChanged += Document_LineBreakChanged;
117 this._Document.StatusUpdate += Document_StatusUpdate;
118 this._Document.PerformLayouted += _Document_PerformLayouted;
120 this.Document_LineBreakChanged(this, null);
122 this.Document_StatusUpdate(this, null);
126 private void _Document_PerformLayouted(object sender, EventArgs e)
128 CalculateLineCountOnScreen();
131 private void Document_StatusUpdate(object sender, EventArgs e)
133 if (this.render == null)
135 if (this.render.TabWidthChar != this.Document.TabStops)
136 this.render.TabWidthChar = this.Document.TabStops;
137 if (this.render.RightToLeft != this.Document.RightToLeft)
138 this.render.RightToLeft = this.Document.RightToLeft;
139 if (this.render.ShowFullSpace != this.Document.ShowFullSpace)
140 this.render.ShowFullSpace = this.Document.ShowFullSpace;
141 if (this.render.ShowHalfSpace != this.Document.ShowHalfSpace)
142 this.render.ShowHalfSpace = this.Document.ShowHalfSpace;
143 if (this.render.ShowTab != this.Document.ShowTab)
144 this.render.ShowTab = this.Document.ShowTab;
145 if (this.render.ShowLineBreak != this.Document.ShowLineBreak)
146 this.render.ShowLineBreak = this.Document.ShowLineBreak;
148 CalculateLineCountOnScreen();
149 this._LayoutLines.ClearLayoutCache();
152 private void Document_LineBreakChanged(object sender, EventArgs e)
154 this.CalculateLineBreak();
157 protected LineToIndexTable _LayoutLines
161 return this.Document.LayoutLines;
165 public event EventHandler SrcChanged;
167 public event EventHandler PageBoundChanged;
172 public ITextRender render
181 public int LineCountOnScreen
190 public double LineBreakingMarginWidth
199 public LineToIndexTable LayoutLines
201 get { return this._LayoutLines; }
207 public double LongestWidth
209 get { return this._LongestWidth; }
212 public double LineNumberMargin
216 return this.render.emSize.Width;
223 /// <remarks>差し替えた場合、再構築する必要があります</remarks>
224 public IHilighter Hilighter
226 get { return this._LayoutLines.Hilighter; }
227 set { this._LayoutLines.Hilighter = value; this._LayoutLines.ClearLayoutCache(); }
233 public Padding Padding
236 return this._Padding;
239 this._Padding = value;
241 CalculateLineBreak();
242 CalculateLineCountOnScreen();
243 if (this.Document.RightToLeft)
244 this._LayoutLines.ClearLayoutCache();
245 this.PageBoundChanged(this, null);
252 public Rectangle PageBound
254 get { return this._Rect; }
257 if (value.Width < 0 || value.Height < 0)
258 throw new ArgumentOutOfRangeException("");
261 CalculateLineBreak();
262 CalculateLineCountOnScreen();
263 if (this.Document.RightToLeft)
264 this._LayoutLines.ClearLayoutCache();
265 this.PageBoundChanged(this, null);
270 /// Draw()の対象となる領域の左上を表す
274 get { return this.Document.Src; }
275 set { this.Document.Src = value; }
278 public virtual void Draw(Rectangle updateRect, bool force = false)
286 /// <param name="x">X座標</param>
287 /// <param name="row">行</param>
288 /// <param name="rel_y">各行の左上を0とするY座標</param>
289 /// <returns>成功すれば偽、そうでなければ真</returns>
290 public virtual bool TryScroll(double x, int row,double rel_y = 0)
294 if (row > this.LayoutLines.Count - 1)
296 this.Document.Src = new SrcPoint(x, row, rel_y);
297 this.SrcChanged(this,null);
304 /// <param name="offset_x">X方向の移動量</param>
305 /// <param name="offset_y">Y方向の移動量</param>
306 /// <returns>成功すれば偽、そうでなければ真</returns>
307 public virtual bool TryScroll(double offset_x,double offset_y)
309 double x = this.Document.Src.X - offset_x;
312 var t = GetNearstRowAndOffsetY(this.Document.Src.Row, -this.Document.Src.OffsetY + offset_y);
315 this.Document.Src = new SrcPoint(x, t.Item1, -t.Item2);
320 /// srcRowを起点としてrect_heightが収まる行とオフセットYを求めます
322 /// <param name="srcRow">起点となる行</param>
323 /// <param name="rect_hight">Y方向のバウンディングボックス</param>
324 /// <returns>失敗した場合、NULL。成功した場合、行とオフセットY</returns>
325 public Tuple<int,double> GetNearstRowAndOffsetY(int srcRow, double rect_hight)
329 for (int i = srcRow; i < this.Document.LayoutLines.Count; i++)
331 ITextLayout layout = this.Document.LayoutLines.GetLayout(i);
333 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
334 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
335 double layoutHeight = layout.Height;
337 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
341 return new Tuple<int, double>(i, 0);
343 if (rect_hight - layoutHeight < 0)
344 return new Tuple<int, double>(i, rect_hight);
346 rect_hight -= layoutHeight;
349 else if(rect_hight < 0)
351 for (int i = srcRow - 1; i >= 0; i--)
353 ITextLayout layout = this.Document.LayoutLines.GetLayout(i);
355 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
356 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
357 double layoutHeight = layout.Height;
359 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
363 return new Tuple<int, double>(i, 0);
365 if (rect_hight + layoutHeight >= 0)
366 return new Tuple<int, double>(i, layoutHeight + rect_hight);
368 rect_hight += layoutHeight;
370 return new Tuple<int, double>(0, 0);
375 public void Dispose()
378 GC.SuppressFinalize(this);
381 public virtual void CalculateLineBreak()
383 if (this.Document.LineBreak == LineBreakMethod.PageBound)
384 this._LayoutLines.WrapWidth = this.render.TextArea.Width - LineBreakingMarginWidth; //余白を残さないと欠ける
385 else if (this.Document.LineBreak == LineBreakMethod.CharUnit)
386 this._LayoutLines.WrapWidth = this.render.emSize.Width * this.Document.LineBreakCharCount;
388 this._LayoutLines.WrapWidth = LineToIndexTable.NONE_BREAK_LINE;
391 public virtual void CalculateLineCountOnScreen()
395 public virtual void CalculateWhloeViewPort()
399 protected virtual void Dispose(bool disposing)
403 this._Document.Update -= new DocumentUpdateEventHandler(this.doc_Update); //これをしないと複数のビューを作成した時に妙なエラーが発生する
404 this._Document.LineBreakChanged -= Document_LineBreakChanged;
405 this._Document.StatusUpdate -= Document_StatusUpdate;
406 this._Document.PerformLayouted -= _Document_PerformLayouted;
408 this._LayoutLines.Clear();
411 protected virtual void CalculateClipRect()
416 protected virtual void OnSrcChanged(EventArgs e)
418 EventHandler handler = this.SrcChanged;
420 this.SrcChanged(this, e);
423 protected virtual void OnPageBoundChanged(EventArgs e)
425 EventHandler handler = this.PageBoundChanged;
427 this.PageBoundChanged(this, e);
430 void render_ChangedRightToLeft(object sender, EventArgs e)
432 this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Src.OffsetY);
435 void render_ChangedRenderResource(object sender, ChangedRenderRsourceEventArgs e)
437 this._LayoutLines.ClearLayoutCache();
438 if (e.type == ResourceType.Font)
440 this.CalculateClipRect();
441 this.CalculateLineCountOnScreen();
442 this.CalculateWhloeViewPort();
446 void doc_Update(object sender, DocumentUpdateEventArgs e)
450 case UpdateType.RebuildLayout:
451 case UpdateType.Clear:
452 this._LongestWidth = 0;
457 IList<LineToIndexTableData> LayoutLines_SpilitStringByChar(object sender, SpilitStringEventArgs e)
459 return this.Document.CreateLineList(e.index, e.length, Document.MaximumLineLength);