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;
89 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 CalculateWhloeViewPort();
129 CalculateLineCountOnScreen();
130 if(this.PerformLayouted != null)
131 this.PerformLayouted(this, e);
134 private void Document_StatusUpdate(object sender, EventArgs e)
136 if (this.render == null)
138 if (this.render.TabWidthChar != this.Document.TabStops)
139 this.render.TabWidthChar = this.Document.TabStops;
140 if (this.render.RightToLeft != this.Document.RightToLeft)
141 this.render.RightToLeft = this.Document.RightToLeft;
142 if (this.render.ShowFullSpace != this.Document.ShowFullSpace)
143 this.render.ShowFullSpace = this.Document.ShowFullSpace;
144 if (this.render.ShowHalfSpace != this.Document.ShowHalfSpace)
145 this.render.ShowHalfSpace = this.Document.ShowHalfSpace;
146 if (this.render.ShowTab != this.Document.ShowTab)
147 this.render.ShowTab = this.Document.ShowTab;
148 if (this.render.ShowLineBreak != this.Document.ShowLineBreak)
149 this.render.ShowLineBreak = this.Document.ShowLineBreak;
150 CalculateWhloeViewPort();
152 CalculateLineCountOnScreen();
153 this._LayoutLines.ClearLayoutCache();
156 private void Document_LineBreakChanged(object sender, EventArgs e)
158 if (this.Document.LineBreak == LineBreakMethod.PageBound)
159 this._LayoutLines.WrapWidth = this.render.TextArea.Width - LineBreakingMarginWidth; //余白を残さないと欠ける
160 else if (this.Document.LineBreak == LineBreakMethod.CharUnit)
161 this._LayoutLines.WrapWidth = this.render.emSize.Width * this.Document.LineBreakCharCount;
163 this._LayoutLines.WrapWidth = LineToIndexTable.NONE_BREAK_LINE;
165 this._LayoutLines.ClearLayoutCache();
168 protected LineToIndexTable _LayoutLines
172 return this.Document.LayoutLines;
176 public event EventHandler SrcChanged;
179 public event EventHandler PerformLayouted;
181 public event EventHandler PageBoundChanged;
186 public ITextRender render
195 public int LineCountOnScreen
204 public double LineBreakingMarginWidth
213 public LineToIndexTable LayoutLines
215 get { return this._LayoutLines; }
221 public double LongestWidth
223 get { return this._LongestWidth; }
226 public double LongestHeight
228 get { return this._LongestHeight; }
231 public double LineNumberMargin
235 return this.render.emSize.Width;
242 /// <remarks>差し替えた場合、再構築する必要があります</remarks>
243 public IHilighter Hilighter
245 get { return this._LayoutLines.Hilighter; }
246 set { this._LayoutLines.Hilighter = value; this._LayoutLines.ClearLayoutCache(); }
250 /// すべてのレイアウト行を破棄し、再度レイアウトをやり直す
253 public virtual void PerfomLayouts()
256 this.Document.PerformLayout();
262 public Padding Padding
265 return this._Padding;
268 this._Padding = value;
270 CalculateLineCountOnScreen();
271 if (this.Document.RightToLeft)
272 this._LayoutLines.ClearLayoutCache();
273 this.PageBoundChanged(this, null);
280 public Rectangle PageBound
282 get { return this._Rect; }
285 if (value.Width < 0 || value.Height < 0)
286 throw new ArgumentOutOfRangeException("");
289 CalculateLineCountOnScreen();
290 if (this.Document.RightToLeft)
291 this._LayoutLines.ClearLayoutCache();
292 this.PageBoundChanged(this, null);
297 /// Draw()の対象となる領域の左上を表す
301 get { return this.Document.Src; }
302 set { this.Document.Src = value; }
305 public virtual void Draw(Rectangle updateRect, bool force = false)
313 /// <param name="x">X座標</param>
314 /// <param name="row">行</param>
315 /// <param name="rel_y">各行の左上を0とするY座標</param>
316 /// <returns>成功すれば偽、そうでなければ真</returns>
317 public virtual bool TryScroll(double x, int row,double rel_y = 0)
321 if (row > this.LayoutLines.Count - 1)
324 for (int i = 0; i < row; i++)
325 abs_y += this.LayoutLines.GetLayout(i).Height;
326 this.Document.Src = new SrcPoint(x, row, rel_y);
327 this.SrcChanged(this,null);
334 /// <param name="offset_x">X方向の移動量</param>
335 /// <param name="offset_y">Y方向の移動量</param>
336 /// <returns>成功すれば偽、そうでなければ真</returns>
337 public virtual bool TryScroll(double offset_x,double offset_y)
339 double x = this.Document.Src.X - offset_x;
342 var t = GetNearstRowAndOffsetY(this.Document.Src.Row, -this.Document.Src.OffsetY + offset_y);
345 this.Document.Src = new SrcPoint(x, t.Item1, -t.Item2);
350 /// srcRowを起点としてrect_heightが収まる行とオフセットYを求めます
352 /// <param name="srcRow">起点となる行</param>
353 /// <param name="rect_hight">Y方向のバウンディングボックス</param>
354 /// <returns>失敗した場合、NULL。成功した場合、行とオフセットY</returns>
355 public Tuple<int,double> GetNearstRowAndOffsetY(int srcRow, double rect_hight)
359 for (int i = srcRow; i < this.Document.LayoutLines.Count; i++)
361 ITextLayout layout = this.Document.LayoutLines.GetLayout(i);
363 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
364 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
365 double layoutHeight = layout.Height;
367 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
371 return new Tuple<int, double>(i, 0);
373 if (rect_hight - layoutHeight < 0)
374 return new Tuple<int, double>(i, rect_hight);
376 rect_hight -= layoutHeight;
379 else if(rect_hight < 0)
381 for (int i = srcRow - 1; i >= 0; i--)
383 ITextLayout layout = this.Document.LayoutLines.GetLayout(i);
385 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
386 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
387 double layoutHeight = layout.Height;
389 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
393 return new Tuple<int, double>(i, 0);
395 if (rect_hight + layoutHeight >= 0)
396 return new Tuple<int, double>(i, layoutHeight + rect_hight);
398 rect_hight += layoutHeight;
400 return new Tuple<int, double>(0, 0);
405 public void Dispose()
408 GC.SuppressFinalize(this);
411 public virtual void CalculateLineCountOnScreen()
415 public virtual void CalculateWhloeViewPort()
419 protected virtual void Dispose(bool disposing)
423 this._Document.Update -= new DocumentUpdateEventHandler(this.doc_Update); //これをしないと複数のビューを作成した時に妙なエラーが発生する
424 this._Document.LineBreakChanged -= Document_LineBreakChanged;
425 this._Document.StatusUpdate -= Document_StatusUpdate;
426 this._Document.PerformLayouted -= _Document_PerformLayouted;
428 this._LayoutLines.Clear();
431 protected virtual void CalculateClipRect()
436 protected virtual void OnSrcChanged(EventArgs e)
438 EventHandler handler = this.SrcChanged;
440 this.SrcChanged(this, e);
443 protected virtual void OnPerformLayoutedChanged(EventArgs e)
445 EventHandler handler = this.PerformLayouted;
447 this.PerformLayouted(this, e);
450 protected virtual void OnPageBoundChanged(EventArgs e)
452 EventHandler handler = this.PageBoundChanged;
454 this.PageBoundChanged(this, e);
457 void render_ChangedRightToLeft(object sender, EventArgs e)
459 this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Src.OffsetY);
462 void render_ChangedRenderResource(object sender, ChangedRenderRsourceEventArgs e)
464 this._LayoutLines.ClearLayoutCache();
465 if (e.type == ResourceType.Font)
467 this.CalculateClipRect();
468 this.CalculateLineCountOnScreen();
469 this.CalculateWhloeViewPort();
473 void doc_Update(object sender, DocumentUpdateEventArgs e)
477 case UpdateType.Clear:
478 this._LongestWidth = 0;
483 IList<LineToIndexTableData> LayoutLines_SpilitStringByChar(object sender, SpilitStringEventArgs e)
485 return this.Document.CreateLineList(e.index, e.length, Document.MaximumLineLength);