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 CalculateLineCountOnScreen();
129 if(this.PerformLayouted != null)
130 this.PerformLayouted(this, e);
133 private void Document_StatusUpdate(object sender, EventArgs e)
135 if (this.render == null)
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;
150 CalculateLineCountOnScreen();
151 this._LayoutLines.ClearLayoutCache();
154 private void Document_LineBreakChanged(object sender, EventArgs e)
156 if (this.Document.LineBreak == LineBreakMethod.PageBound)
157 this._LayoutLines.WrapWidth = this.render.TextArea.Width - LineBreakingMarginWidth; //余白を残さないと欠ける
158 else if (this.Document.LineBreak == LineBreakMethod.CharUnit)
159 this._LayoutLines.WrapWidth = this.render.emSize.Width * this.Document.LineBreakCharCount;
161 this._LayoutLines.WrapWidth = LineToIndexTable.NONE_BREAK_LINE;
163 this._LayoutLines.ClearLayoutCache();
166 protected LineToIndexTable _LayoutLines
170 return this.Document.LayoutLines;
174 public event EventHandler SrcChanged;
177 public event EventHandler PerformLayouted;
179 public event EventHandler PageBoundChanged;
184 public ITextRender render
193 public int LineCountOnScreen
202 public double LineBreakingMarginWidth
211 public LineToIndexTable LayoutLines
213 get { return this._LayoutLines; }
219 public double LongestWidth
221 get { return this._LongestWidth; }
224 public double LineNumberMargin
228 return this.render.emSize.Width;
235 /// <remarks>差し替えた場合、再構築する必要があります</remarks>
236 public IHilighter Hilighter
238 get { return this._LayoutLines.Hilighter; }
239 set { this._LayoutLines.Hilighter = value; this._LayoutLines.ClearLayoutCache(); }
243 /// すべてのレイアウト行を破棄し、再度レイアウトをやり直す
246 public virtual void PerfomLayouts()
249 this.Document.PerformLayout();
255 public Padding Padding
258 return this._Padding;
261 this._Padding = value;
263 CalculateLineCountOnScreen();
264 if (this.Document.RightToLeft)
265 this._LayoutLines.ClearLayoutCache();
266 this.PageBoundChanged(this, null);
273 public Rectangle PageBound
275 get { return this._Rect; }
278 if (value.Width < 0 || value.Height < 0)
279 throw new ArgumentOutOfRangeException("");
282 CalculateLineCountOnScreen();
283 if (this.Document.RightToLeft)
284 this._LayoutLines.ClearLayoutCache();
285 this.PageBoundChanged(this, null);
290 /// Draw()の対象となる領域の左上を表す
294 get { return this.Document.Src; }
295 set { this.Document.Src = value; }
298 public virtual void Draw(Rectangle updateRect, bool force = false)
306 /// <param name="x">X座標</param>
307 /// <param name="row">行</param>
308 /// <param name="rel_y">各行の左上を0とするY座標</param>
309 /// <returns>成功すれば偽、そうでなければ真</returns>
310 public virtual bool TryScroll(double x, int row,double rel_y = 0)
314 if (row > this.LayoutLines.Count - 1)
316 this.Document.Src = new SrcPoint(x, row, rel_y);
317 this.SrcChanged(this,null);
324 /// <param name="offset_x">X方向の移動量</param>
325 /// <param name="offset_y">Y方向の移動量</param>
326 /// <returns>成功すれば偽、そうでなければ真</returns>
327 public virtual bool TryScroll(double offset_x,double offset_y)
329 double x = this.Document.Src.X - offset_x;
332 var t = GetNearstRowAndOffsetY(this.Document.Src.Row, -this.Document.Src.OffsetY + offset_y);
335 this.Document.Src = new SrcPoint(x, t.Item1, -t.Item2);
340 /// srcRowを起点としてrect_heightが収まる行とオフセットYを求めます
342 /// <param name="srcRow">起点となる行</param>
343 /// <param name="rect_hight">Y方向のバウンディングボックス</param>
344 /// <returns>失敗した場合、NULL。成功した場合、行とオフセットY</returns>
345 public Tuple<int,double> GetNearstRowAndOffsetY(int srcRow, double rect_hight)
349 for (int i = srcRow; i < this.Document.LayoutLines.Count; i++)
351 ITextLayout layout = this.Document.LayoutLines.GetLayout(i);
353 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
354 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
355 double layoutHeight = layout.Height;
357 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
361 return new Tuple<int, double>(i, 0);
363 if (rect_hight - layoutHeight < 0)
364 return new Tuple<int, double>(i, rect_hight);
366 rect_hight -= layoutHeight;
369 else if(rect_hight < 0)
371 for (int i = srcRow - 1; i >= 0; i--)
373 ITextLayout layout = this.Document.LayoutLines.GetLayout(i);
375 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
376 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
377 double layoutHeight = layout.Height;
379 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
383 return new Tuple<int, double>(i, 0);
385 if (rect_hight + layoutHeight >= 0)
386 return new Tuple<int, double>(i, layoutHeight + rect_hight);
388 rect_hight += layoutHeight;
390 return new Tuple<int, double>(0, 0);
395 public void Dispose()
398 GC.SuppressFinalize(this);
401 public virtual void CalculateLineCountOnScreen()
405 public virtual void CalculateWhloeViewPort()
409 protected virtual void Dispose(bool disposing)
413 this._Document.Update -= new DocumentUpdateEventHandler(this.doc_Update); //これをしないと複数のビューを作成した時に妙なエラーが発生する
414 this._Document.LineBreakChanged -= Document_LineBreakChanged;
415 this._Document.StatusUpdate -= Document_StatusUpdate;
416 this._Document.PerformLayouted -= _Document_PerformLayouted;
418 this._LayoutLines.Clear();
421 protected virtual void CalculateClipRect()
426 protected virtual void OnSrcChanged(EventArgs e)
428 EventHandler handler = this.SrcChanged;
430 this.SrcChanged(this, e);
433 protected virtual void OnPerformLayoutedChanged(EventArgs e)
435 EventHandler handler = this.PerformLayouted;
437 this.PerformLayouted(this, e);
440 protected virtual void OnPageBoundChanged(EventArgs e)
442 EventHandler handler = this.PageBoundChanged;
444 this.PageBoundChanged(this, e);
447 void render_ChangedRightToLeft(object sender, EventArgs e)
449 this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Src.OffsetY);
452 void render_ChangedRenderResource(object sender, ChangedRenderRsourceEventArgs e)
454 this._LayoutLines.ClearLayoutCache();
455 if (e.type == ResourceType.Font)
457 this.CalculateClipRect();
458 this.CalculateLineCountOnScreen();
459 this.CalculateWhloeViewPort();
463 void doc_Update(object sender, DocumentUpdateEventArgs e)
467 case UpdateType.RebuildLayout:
468 case UpdateType.Clear:
469 this._LongestWidth = 0;
474 IList<LineToIndexTableData> LayoutLines_SpilitStringByChar(object sender, SpilitStringEventArgs e)
476 return this.Document.CreateLineList(e.index, e.length, Document.MaximumLineLength);