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;
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.PerformLayouted += new EventHandler((s, e) => { });
95 this.PageBoundChanged += new EventHandler((s, e) => { });
98 public Document Document
102 return this._Document;
106 if(this._Document != null)
108 this._Document.UpdateCalledAlways -= new DocumentUpdateEventHandler(doc_Update);
109 this._Document.LineBreakChanged -= Document_LineBreakChanged;
110 this._Document.StatusUpdate -= Document_StatusUpdate;
113 this._Document = value;
115 this._Document.UpdateCalledAlways += new DocumentUpdateEventHandler(doc_Update);
116 this._Document.LineBreakChanged += Document_LineBreakChanged;
117 this._Document.StatusUpdate += Document_StatusUpdate;
119 this.Document_StatusUpdate(this, null);
123 private void Document_StatusUpdate(object sender, EventArgs e)
125 if (this.render == null)
127 if (this.render.TabWidthChar != this.Document.TabStops)
128 this.render.TabWidthChar = this.Document.TabStops;
129 if (this.render.RightToLeft != this.Document.RightToLeft)
130 this.render.RightToLeft = this.Document.RightToLeft;
131 if (this.render.ShowFullSpace != this.Document.ShowFullSpace)
132 this.render.ShowFullSpace = this.Document.ShowFullSpace;
133 if (this.render.ShowHalfSpace != this.Document.ShowHalfSpace)
134 this.render.ShowHalfSpace = this.Document.ShowHalfSpace;
135 if (this.render.ShowTab != this.Document.ShowTab)
136 this.render.ShowTab = this.Document.ShowTab;
137 if (this.render.ShowLineBreak != this.Document.ShowLineBreak)
138 this.render.ShowLineBreak = this.Document.ShowLineBreak;
140 CalculateLineCountOnScreen();
141 this._LayoutLines.ClearLayoutCache();
144 private void Document_LineBreakChanged(object sender, EventArgs e)
146 if (this.Document.LineBreak != LineBreakMethod.None)
147 this._LayoutLines.SpilitString = new SpilitStringEventHandler(LayoutLines_SpilitStringByPixelbase);
149 this._LayoutLines.SpilitString = new SpilitStringEventHandler(LayoutLines_SpilitStringByChar);
152 protected LineToIndexTable _LayoutLines
156 return this.Document.LayoutLines;
160 public event EventHandler SrcChanged;
162 public event EventHandler PerformLayouted;
164 public event EventHandler PageBoundChanged;
169 public ITextRender render
178 public int LineCountOnScreen
187 public double LineBreakingMarginWidth
196 public LineToIndexTable LayoutLines
198 get { return this._LayoutLines; }
204 public double LongestWidth
206 get { return this._LongestWidth; }
209 public double LineNumberMargin
213 return this.render.emSize.Width;
220 /// <remarks>差し替えた場合、再構築する必要があります</remarks>
221 public IHilighter Hilighter
223 get { return this._LayoutLines.Hilighter; }
224 set { this._LayoutLines.Hilighter = value; this._LayoutLines.ClearLayoutCache(); }
228 /// すべてのレイアウト行を破棄し、再度レイアウトをやり直す
230 public virtual void PerfomLayouts()
232 this.Document.FireUpdate(new DocumentUpdateEventArgs(UpdateType.Clear, -1, -1, -1));
233 this.Document.FireUpdate(new DocumentUpdateEventArgs(UpdateType.Replace, 0, 0, this.Document.Length));
234 CalculateLineCountOnScreen();
235 this.PerformLayouted(this, null);
241 public Padding Padding
244 return this._Padding;
247 this._Padding = value;
249 CalculateLineCountOnScreen();
250 if (this.Document.RightToLeft)
251 this._LayoutLines.ClearLayoutCache();
252 this.PageBoundChanged(this, null);
259 public Rectangle PageBound
261 get { return this._Rect; }
264 if (value.Width < 0 || value.Height < 0)
265 throw new ArgumentOutOfRangeException("");
268 CalculateLineCountOnScreen();
269 if (this.Document.RightToLeft)
270 this._LayoutLines.ClearLayoutCache();
271 this.PageBoundChanged(this, null);
276 /// Draw()の対象となる領域の左上を表す
280 get { return this.Document.Src; }
281 set { this.Document.Src = value; }
284 public virtual void Draw(Rectangle updateRect, bool force = false)
289 public virtual bool TryScroll(double x, int row)
293 if (row > this.LayoutLines.Count - 1)
295 this.Document.Src = new SrcPoint(x, row, row * this.render.emSize.Height);
296 this.SrcChanged(this,null);
300 Point total = new Point();
302 public virtual bool TryRelativeScroll(double delta_x, double delta_y, bool logical_scroll = true)
306 noti += Math.Abs(delta_y); //負の値が飛んでくる可能性がある
308 if (noti < this.render.emSize.Height && logical_scroll)
313 double totalHeight = this.LayoutLines.Count * this.render.emSize.Height;
314 if (total.Y > totalHeight)
315 total.Y = totalHeight - this.render.TextArea.Height;
323 row = (int)(total.Y / this.render.emSize.Height + 1.0); //レタリング時にオフセットするために切り上げる
325 row = 0; //0の時だけは切り上げると困るので何もしない
328 if (row > this.LayoutLines.Count - 1)
330 this.Document.Src = new SrcPoint(total.X, row, total.Y);
331 this.SrcChanged(this, null);
336 public void Dispose()
339 GC.SuppressFinalize(this);
342 public virtual void CalculateLineCountOnScreen()
346 protected virtual void Dispose(bool disposing)
350 this.Document.UpdateCalledAlways -= new DocumentUpdateEventHandler(this.doc_Update); //これをしないと複数のビューを作成した時に妙なエラーが発生する
352 this._LayoutLines.Clear();
355 protected virtual void CalculateClipRect()
360 protected virtual void OnSrcChanged(EventArgs e)
362 EventHandler handler = this.SrcChanged;
364 this.SrcChanged(this, e);
367 protected virtual void OnPerformLayoutedChanged(EventArgs e)
369 EventHandler handler = this.PerformLayouted;
371 this.PerformLayouted(this, e);
374 protected virtual void OnPageBoundChanged(EventArgs e)
376 EventHandler handler = this.PageBoundChanged;
378 this.PageBoundChanged(this, e);
381 void render_ChangedRightToLeft(object sender, EventArgs e)
383 this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Src.Y);
386 void render_ChangedRenderResource(object sender, ChangedRenderRsourceEventArgs e)
388 this._LayoutLines.ClearLayoutCache();
389 if (e.type == ResourceType.Font)
391 this.CalculateClipRect();
392 this.CalculateLineCountOnScreen();
396 void doc_Update(object sender, DocumentUpdateEventArgs e)
400 case UpdateType.Clear:
401 this._LongestWidth = 0;
406 IList<LineToIndexTableData> LayoutLines_SpilitStringByPixelbase(object sender, SpilitStringEventArgs e)
409 if (this.Document.LineBreak == LineBreakMethod.PageBound)
410 WrapWidth = this.render.TextArea.Width - LineBreakingMarginWidth; //余白を残さないと欠ける
412 WrapWidth = this.render.emSize.Width * this.Document.LineBreakCharCount;
414 if (WrapWidth < 0 && this.Document.LineBreak != LineBreakMethod.None)
415 throw new InvalidOperationException();
417 int startIndex = e.index;
418 int endIndex = e.index + e.length - 1;
420 LineToIndexTable layoutLineCollection = (LineToIndexTable)sender;
422 return this.render.BreakLine(e.buffer,layoutLineCollection, startIndex, endIndex, WrapWidth);
425 IList<LineToIndexTableData> LayoutLines_SpilitStringByChar(object sender, SpilitStringEventArgs e)
427 return this.Document.CreateLineList(e.index, e.length, Document.MaximumLineLength);