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/>.
13 using System.Collections.Generic;
15 namespace FooEditEngine
25 /// キャレットとドキュメントの表示を担当します。レイアウト関連もこちらで行います
27 sealed class EditView : ViewBase
30 internal const float LineMarkerThickness = 2;
32 bool _CaretBlink, _HideRuler = true;
33 internal const int LineNumberLength = 6;
34 const int UpdateAreaPaddingWidth = 2;
35 const int UpdateAreaWidth = 4;
36 const int UpdateAreaTotalWidth = UpdateAreaWidth + UpdateAreaPaddingWidth;
41 public EditView(Document doc, IEditorRender r, int MarginLeftAndRight = 5)
42 : this(doc, r, new Padding(MarginLeftAndRight, 0, MarginLeftAndRight, 0))
49 /// <param name="doc">ドキュメント</param>
50 /// <param name="r">レンダー</param>
51 /// <param name="margin">マージン(1番目:左、2番目:上、3番目:右、4番目:下)</param>
52 public EditView(Document doc, IEditorRender r, Padding margin)
53 : base(doc, r, margin)
55 this.CaretBlinkTime = 500;
56 this.CaretWidthOnInsertMode = 1;
57 this.CalculateClipRect();
58 this.CaretLocation = new Point(this.render.TextArea.X, this.render.TextArea.Y);
59 this.LayoutLines.FoldingCollection.StatusChanged += FoldingCollection_StatusChanged;
60 this.IsFocused = false;
66 internal SelectCollection Selections
68 get { return this.Document.Selections; }
69 set { this.Document.Selections = value; }
73 /// ラインマーカーを描くなら偽。そうでなければ真
75 public bool HideLineMarker
77 get { return this.Document.HideLineMarker; }
78 set { this.Document.HideLineMarker = value; }
82 /// キャレットを描くなら偽。そうでなければ真
86 get { return this.Document.HideCaret; }
87 set { this.Document.HideCaret = value; }
91 /// 挿入モードなら真を返し、上書きモードなら偽を返す
93 public bool InsertMode
95 get { return this.Document.InsertMode; }
96 set { this.Document.InsertMode = value; }
102 public int CaretBlinkTime
111 public double CaretWidthOnInsertMode
118 /// フォーカスがあるなら真をセットする
120 public bool IsFocused
127 /// キャレットを点滅させるなら真。そうでないなら偽
129 /// <remarks>キャレット点滅タイマーもリセットされます</remarks>
130 public bool CaretBlink
132 get { return this._CaretBlink; }
135 this._CaretBlink = value;
137 this.tickCount = DateTime.Now.Ticks + this.To100nsTime(this.CaretBlinkTime);
142 /// 一ページの高さに収まる行数を返す(こちらは表示されていない行も含みます)
144 public int LineCountOnScreenWithInVisible
153 public double ScrollMarginWidth
155 get { return this.PageBound.Width * 20 / 100; }
161 public Point CaretLocation
170 /// <param name="x">x座標</param>
171 /// <param name="y">y座標</param>
172 /// <returns>テキストエリア内にあれば真。そうでなければ偽</returns>
173 public bool HitTextArea(double x, double y)
175 if (x >= this.render.TextArea.X && x <= this.render.TextArea.Right &&
176 y >= this.render.TextArea.Y && y <= this.render.TextArea.Bottom)
185 /// <param name="x">x座標</param>
186 /// <param name="row">行</param>
187 /// <returns>ヒットした場合はFoldingDataオブジェクトが返され、そうでない場合はnullが返る</returns>
188 public FoldingItem HitFoldingData(double x, int row)
190 IEditorRender render = (IEditorRender)base.render;
192 if (x >= this.GetRealtiveX(AreaType.FoldingArea) && x <= this.GetRealtiveX(AreaType.FoldingArea) + render.FoldingWidth)
194 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(row);
195 int lineLength = this.LayoutLines.GetLengthFromLineNumber(row);
196 FoldingItem foldingData = this.LayoutLines.FoldingCollection.Get(lineHeadIndex, lineLength);
197 if (foldingData != null && foldingData.IsFirstLine(this.LayoutLines,row))
204 /// Rectで指定された範囲にドキュメントを描く
206 /// <param name="updateRect">描写する範囲</param>
207 /// <returns>キャッシュしてはならない場合は真を返し、そうでない場合は偽を返します</returns>
208 /// <remarks>描写する範囲がPageBoundより小さい場合、キャッシュされた内容を使用することがあります。なお、レタリング後にrender.CacheContent()を呼び出さなかった場合は更新範囲にかかわらずキャッシュを使用しません</remarks>
209 public override bool Draw(Rectangle updateRect)
211 if (this.LayoutLines.Count == 0)
214 IEditorRender render = (IEditorRender)base.render;
216 if ((updateRect.Height < this.PageBound.Height ||
217 updateRect.Width < this.PageBound.Width) &&
218 render.IsVaildCache())
220 render.DrawCachedBitmap(updateRect);
224 Rectangle background = this.PageBound;
225 render.FillBackground(background);
227 if (this.Document.HideRuler == false)
230 this.DrawLineMarker(this.Document.CaretPostion.row);
232 Point pos = this.render.TextArea.TopLeft;
233 //画面上では(X,Y)が開始位置になるが、開始する行が決まっているのでオフセットを求める
234 pos.Y -= this.Src.GetOffsetY(this.render.emSize.Height);
236 double endposy = this.render.TextArea.Bottom;
237 Size lineNumberSize = new Size(this.render.LineNemberWidth, this.render.TextArea.Height);
239 this.render.BeginClipRect(new Rectangle(this.PageBound.X, this.render.TextArea.Y, this.PageBound.Width, this.render.TextArea.Height));
241 //パフォーマンス向上のため行番号などを先に描く
242 for (int i = this.Src.Row; i < this.LayoutLines.Count; i++)
244 int lineIndex = this.LayoutLines.GetIndexFromLineNumber(i);
245 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
246 ITextLayout layout = this.LayoutLines.GetLayout(i);
251 FoldingItem foldingData = this.LayoutLines.FoldingCollection.Get(lineIndex, lineLength);
253 if (foldingData != null)
255 if ((!this.LayoutLines.FoldingCollection.IsHasParent(foldingData) ||
256 !this.LayoutLines.FoldingCollection.IsParentHidden(foldingData))
257 && foldingData.IsFirstLine(this.LayoutLines, i))
258 render.DrawFoldingMark(foldingData.Expand, this.PageBound.X + this.GetRealtiveX(AreaType.FoldingArea), pos.Y);
259 if (this.LayoutLines.FoldingCollection.IsHidden(lineIndex))
263 if (this.Document.DrawLineNumber)
265 this.render.DrawString((i + 1).ToString(), this.PageBound.X + this.GetRealtiveX(AreaType.LineNumberArea), pos.Y, StringAlignment.Right, lineNumberSize,StringColorType.LineNumber);
268 DrawUpdateArea(i, pos.Y);
270 //pos.Y += this.LayoutLines.GetLayout(i).Height;
271 pos.Y += this.render.emSize.Height;
274 this.render.EndClipRect();
277 pos = this.render.TextArea.TopLeft;
279 pos.Y -= this.Src.GetOffsetY(this.render.emSize.Height);
281 this.render.BeginClipRect(this.render.TextArea);
283 for (int i = this.Src.Row; i < this.LayoutLines.Count; i++)
285 int lineIndex = this.LayoutLines.GetIndexFromLineNumber(i);
286 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
287 ITextLayout layout = this.LayoutLines.GetLayout(i);
292 var selectRange = from s in this.Selections.Get(lineIndex, lineLength)
293 let n = Util.ConvertAbsIndexToRelIndex(s, lineIndex, lineLength)
296 this.render.DrawOneLine(this.LayoutLines, i, pos.X, pos.Y, selectRange);
298 //pos.Y += this.LayoutLines.GetLayout(i).Height;
299 pos.Y += this.render.emSize.Height;
302 this.render.EndClipRect();
304 this.DrawInsertPoint();
306 this.Document.SelectGrippers.BottomLeft.Draw(this.render);
307 this.Document.SelectGrippers.BottomRight.Draw(this.render);
309 return this.DrawCaret(); //キャレットを描いた場合はキャッシュしてはならない
312 void DrawUpdateArea(int row,double ypos)
314 IEditorRender render = (IEditorRender)base.render;
315 if(this.LayoutLines.GetDirtyFlag(row))
317 Point pos = new Point(this.PageBound.X + this.GetRealtiveX(AreaType.UpdateArea), ypos);
318 Rectangle rect = new Rectangle(pos.X, pos.Y, UpdateAreaWidth, this.LayoutLines.GetLayout(row).Height);
319 render.FillRectangle(rect, FillRectType.UpdateArea);
325 IEditorRender render = (IEditorRender)base.render;
328 Size emSize = render.emSize;
329 Rectangle clipRect = this.render.TextArea;
331 double markerHeight = emSize.Height / 2;
332 if (this.Document.RightToLeft)
334 pos = new Point(clipRect.TopRight.X, clipRect.TopRight.Y - emSize.Height - LineMarkerThickness);
335 for (; pos.X >= clipRect.TopLeft.X; pos.X -= emSize.Width, count++)
338 to = new Point(pos.X, pos.Y + emSize.Height);
339 int mod = count % 10;
342 string countStr = (count / 10).ToString();
343 double counterWidth = emSize.Width * countStr.Length;
344 this.render.DrawString(countStr, pos.X - counterWidth, pos.Y, StringAlignment.Right, new Size(counterWidth, double.MaxValue));
347 from.Y = from.Y + emSize.Height / 2;
349 from.Y = from.Y + emSize.Height * 3 / 4;
350 render.DrawLine(from, to);
351 if (this.CaretLocation.X >= pos.X && this.CaretLocation.X < pos.X + emSize.Width)
352 render.FillRectangle(new Rectangle(pos.X, pos.Y + markerHeight, emSize.Width, markerHeight), FillRectType.OverwriteCaret);
357 pos = new Point(clipRect.TopLeft.X, clipRect.TopLeft.Y - emSize.Height - LineMarkerThickness);
358 for (; pos.X < clipRect.TopRight.X; pos.X += emSize.Width, count++)
361 to = new Point(pos.X, pos.Y + emSize.Height);
362 int mod = count % 10;
364 this.render.DrawString((count / 10).ToString(), pos.X, pos.Y, StringAlignment.Left, new Size(double.MaxValue, double.MaxValue));
366 from.Y = from.Y + emSize.Height / 2;
368 from.Y = from.Y + emSize.Height * 3 / 4;
369 render.DrawLine(from, to);
370 if (this.CaretLocation.X >= pos.X && this.CaretLocation.X < pos.X + emSize.Width)
371 render.FillRectangle(new Rectangle(pos.X, pos.Y + markerHeight, emSize.Width, markerHeight), FillRectType.OverwriteCaret);
374 from = clipRect.TopLeft;
375 from.Y -= LineMarkerThickness;
376 to = clipRect.TopRight;
377 to.Y -= LineMarkerThickness;
378 render.DrawLine(from, to);
381 void DrawInsertPoint()
383 //一つしかない場合は行選択の可能性がある
384 if (this.Selections.Count <= 1)
386 IEditorRender render = (IEditorRender)base.render;
387 foreach (Selection sel in this.Selections)
391 TextPoint tp = this.GetLayoutLineFromIndex(sel.start);
392 Point left = this.GetPostionFromTextPoint(tp);
393 double lineHeight = this.LayoutLines.GetLayout(tp.row).Height;
394 Rectangle InsertRect = new Rectangle(left.X,
396 CaretWidthOnInsertMode,
398 render.FillRectangle(InsertRect, FillRectType.InsertPoint);
405 if (this.HideCaret || !this.IsFocused)
408 long diff = DateTime.Now.Ticks - this.tickCount;
409 long blinkTime = this.To100nsTime(this.CaretBlinkTime);
411 if (this.CaretBlink && diff % blinkTime >= blinkTime / 2)
414 Rectangle CaretRect = new Rectangle();
416 IEditorRender render = (IEditorRender)base.render;
418 int row = this.Document.CaretPostion.row;
419 double lineHeight = this.LayoutLines.GetLayout(row).Height;
420 double charWidth = this.LayoutLines.GetLayout(row).GetWidthFromIndex(this.Document.CaretPostion.col);
422 if (this.InsertMode || charWidth == 0)
424 CaretRect.Size = new Size(CaretWidthOnInsertMode, lineHeight);
425 CaretRect.Location = new Point(this.CaretLocation.X, this.CaretLocation.Y);
426 render.FillRectangle(CaretRect, FillRectType.InsertCaret);
430 double height = lineHeight / 3;
431 CaretRect.Size = new Size(charWidth, height);
432 CaretRect.Location = new Point(this.CaretLocation.X, this.CaretLocation.Y + lineHeight - height);
433 render.FillRectangle(CaretRect, FillRectType.OverwriteCaret);
438 long To100nsTime(int ms)
443 public void DrawLineMarker(int row)
445 if (this.HideLineMarker || !this.IsFocused)
447 IEditorRender render = (IEditorRender)base.render;
448 Point p = this.CaretLocation;
449 double height = this.LayoutLines.GetLayout(this.Document.CaretPostion.row).Height;
450 double width = this.render.TextArea.Width;
451 render.FillRectangle(new Rectangle(this.PageBound.X + this.render.TextArea.X, this.CaretLocation.Y, width, height), FillRectType.LineMarker);
457 /// <returns>矩形領域を表すRectangle</returns>
458 public Rectangle GetCurrentCaretRect()
460 ITextLayout layout = this.LayoutLines.GetLayout(this.Document.CaretPostion.row);
461 double width = layout.GetWidthFromIndex(this.Document.CaretPostion.col);
463 width = this.CaretWidthOnInsertMode;
464 double height = layout.Height;
465 Rectangle updateRect = new Rectangle(
466 this.CaretLocation.X,
467 this.CaretLocation.Y,
474 /// 指定した座標の一番近くにあるTextPointを取得する
476 /// <param name="p">テキストエリアを左上とする相対位置</param>
477 /// <returns>レイアウトラインを指し示すTextPoint</returns>
478 public TextPoint GetTextPointFromPostion(Point p)
480 if (p.Y < this.render.TextArea.TopLeft.Y ||
481 p.Y > this.render.TextArea.BottomRight.Y)
482 return TextPoint.Null;
483 TextPoint tp = new TextPoint();
485 if (this.LayoutLines.Count == 0)
488 p.Y -= this.render.TextArea.Y;
490 int lineHeadIndex, lineLength;
492 tp.row = this.LayoutLines.Count - 1;
493 for (int i = this.Src.Row; i < this.LayoutLines.Count; i++)
495 double height = this.LayoutLines.GetLayout(i).Height;
497 lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
498 lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
500 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
503 if (y + height > p.Y)
511 if (p.X < this.render.TextArea.X)
514 tp.col = GetIndexFromColPostion(tp.row, p.X);
516 lineLength = this.LayoutLines.GetLengthFromLineNumber(tp.row);
517 if (tp.col > lineLength)
524 /// 桁方向の座標に対応するインデックスを取得する
526 /// <param name="row">対象となる行</param>
527 /// <param name="x">テキストエリアからの相対位置</param>
528 /// <returns></returns>
529 public int GetIndexFromColPostion(int row, double x)
531 x -= this.render.TextArea.X;
532 int lineLength = this.LayoutLines.GetLengthFromLineNumber(row);
535 int index = this.LayoutLines.GetLayout(row).GetIndexFromColPostion(this.Src.X + x);
540 /// インデックスに対応する桁方向の座標を得る
542 /// <param name="row">対象となる行</param>
543 /// <param name="index">インデックス</param>
544 /// <returns>テキストエリアからの相対位置を返す</returns>
545 public double GetColPostionFromIndex(int row, int index)
547 double x = this.LayoutLines.GetLayout(row).GetColPostionFromIndex(index);
548 return x - Src.X + this.render.TextArea.X;
552 /// TextPointに対応する座標を得る
554 /// <param name="tp">レイアウトライン上の位置</param>
555 /// <returns>テキストエリアを左上とする相対位置</returns>
556 public Point GetPostionFromTextPoint(TextPoint tp)
558 Point p = new Point();
559 for (int i = this.Src.Row; i < tp.row; i++)
561 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
562 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
563 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
565 p.Y += this.LayoutLines.GetLayout(i).Height;
567 p.X = this.GetColPostionFromIndex(tp.row, tp.col);
568 p.Y += this.render.TextArea.Y;
572 public Gripper HitGripperFromPoint(Point p)
574 if (this.Document.SelectGrippers.BottomLeft.IsHit(p))
575 return this.Document.SelectGrippers.BottomLeft;
576 if (this.Document.SelectGrippers.BottomRight.IsHit(p))
577 return this.Document.SelectGrippers.BottomRight;
581 public Rectangle GetRectFromIndex(int index,int width,int height)
583 TextPoint tp = this.LayoutLines.GetTextPointFromIndex(index);
584 return this.GetRectFromTextPoint(tp, width, height);
587 public Rectangle GetRectFromTextPoint(TextPoint tp, int width, int height)
589 double radius = width / 2;
590 Point point = this.GetPostionFromTextPoint(tp);
591 double lineHeight = this.LayoutLines.GetLayout(tp.row).Height;
592 double srcOffsetY = this.Src.GetOffsetY(this.render.emSize.Height); //画面上ではずれているので引く必要がある
594 return new Rectangle(point.X - radius, point.Y + lineHeight - srcOffsetY, width, height);
598 /// キャレットを指定した位置に移動させる
600 /// <param name="row"></param>
601 /// <param name="col"></param>
602 /// <param name="autoExpand">折り畳みを展開するなら真</param>
603 public void JumpCaret(int row, int col, bool autoExpand = true)
607 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(row);
608 int lineLength = this.LayoutLines.GetLengthFromLineNumber(row);
609 FoldingItem foldingData = this.LayoutLines.FoldingCollection.Get(lineHeadIndex, lineLength);
610 if(foldingData != null)
612 if (this.LayoutLines.FoldingCollection.IsParentHidden(foldingData) || !foldingData.IsFirstLine(this.LayoutLines, row))
614 this.LayoutLines.FoldingCollection.Expand(foldingData);
619 this.Document.CaretPostion = new TextPoint(row, col);
623 /// index上の文字が表示されるようにSrcを調整する
625 /// <param name="index">インデックス</param>
626 /// <returns>調整されたら真。そうでなければ偽</returns>
627 public bool AdjustSrc(int index)
629 TextPoint startTextPoint = this.GetLayoutLineFromIndex(index);
630 double x = this.LayoutLines.GetLayout(startTextPoint.row).GetColPostionFromIndex(startTextPoint.col);
631 if (x < this.Src.X ||
632 x > this.Src.X + this.PageBound.Width)
634 this.TryScroll(x, this.Src.Row);
637 if (startTextPoint.row < this.Src.Row ||
638 startTextPoint.row > this.Src.Row + this.LineCountOnScreenWithInVisible)
640 this.TryScroll(this.Src.X, startTextPoint.row);
647 /// キャレットがあるところまでスクロールする
649 /// <return>再描写する必要があるなら真を返す</return>
650 /// <remarks>Document.Update(type == UpdateType.Clear)イベント時に呼び出した場合、例外が発生します</remarks>
651 public bool AdjustCaretAndSrc(AdjustFlow flow = AdjustFlow.Both)
653 IEditorRender render = (IEditorRender)base.render;
655 if (this.PageBound.Width == 0 || this.PageBound.Height == 0)
657 this.SetCaretPostion(this.Padding.Left + render.FoldingWidth, 0);
662 TextPoint tp = this.Document.CaretPostion;
663 double x = this.CaretLocation.X;
664 double y = this.CaretLocation.Y;
666 if (flow == AdjustFlow.Col || flow == AdjustFlow.Both)
668 x = this.LayoutLines.GetLayout(tp.row).GetColPostionFromIndex(tp.col);
670 double left = this.Src.X;
671 double right = this.Src.X + this.render.TextArea.Width;
673 if (x >= left && x <= right) //xは表示領域にないにある
677 else if (x > right) //xは表示領域の右側にある
679 this.Document.Src = new SrcPoint(x - this.render.TextArea.Width + this.ScrollMarginWidth,this.Document.Src.Row,this.Document.Src.Y);
680 if (this.Document.RightToLeft && this.Document.Src.X > 0)
682 System.Diagnostics.Debug.Assert(x > 0);
683 this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Document.Src.Y);
687 x = this.render.TextArea.Width - this.ScrollMarginWidth;
691 else if (x < left) //xは表示領域の左側にある
693 this.Document.Src = new SrcPoint(x - this.ScrollMarginWidth, this.Document.Src.Row, this.Document.Src.Y);
694 if (!this.Document.RightToLeft && this.Document.Src.X < this.render.TextArea.X)
696 this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Document.Src.Y);
700 x = this.ScrollMarginWidth;
704 x += this.render.TextArea.X;
707 if (flow == AdjustFlow.Row || flow == AdjustFlow.Both)
710 int lineCount = this.LineCountOnScreenWithInVisible;
711 if (tp.row >= this.Src.Row && tp.row < this.Src.Row + lineCount)
713 caretRow = tp.row - this.Src.Row;
714 y = -this.Src.GetOffsetY(this.render.emSize.Height); //画面上ではずれているので引く必要がある
716 else if (tp.row >= this.Src.Row + lineCount)
718 int srcRow = this.GetSrcRow(tp.row, this.LineCountOnScreen);
719 this.Document.Src = new SrcPoint(this.Document.Src.X, srcRow, srcRow * this.render.emSize.Height);
720 caretRow = tp.row - this.Document.Src.Row;
723 CalculateLineCountOnScreen();
725 else if (tp.row < this.Src.Row)
727 this.Document.Src = new SrcPoint(this.Document.Src.X, tp.row, tp.row * this.render.emSize.Height);
730 CalculateLineCountOnScreen();
735 for (int i = 0; i < caretRow; i++)
737 int currentRow = this.Src.Row + i;
738 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(currentRow);
739 int lineLength = this.LayoutLines.GetLengthFromLineNumber(currentRow);
741 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
744 y += this.LayoutLines.GetLayout(currentRow).Height;
747 y += this.render.TextArea.Y;
750 this.SetCaretPostion(x, y);
754 this.OnSrcChanged(null);
760 int GetSrcRow(int row,int count)
762 if (this.LayoutLines.FoldingStrategy == null)
764 for (int i = row; i >= 0; i--)
766 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
767 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
768 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
778 /// レイアウト行をテキストポイントからインデックスに変換する
780 /// <param name="tp">テキストポイント表す</param>
781 /// <returns>インデックスを返す</returns>
782 public int GetIndexFromLayoutLine(TextPoint tp)
784 return this.LayoutLines.GetIndexFromTextPoint(tp);
788 /// インデックスからレイアウト行を指し示すテキストポイントに変換する
790 /// <param name="index">インデックスを表す</param>
791 /// <returns>テキストポイント返す</returns>
792 public TextPoint GetLayoutLineFromIndex(int index)
794 return this.LayoutLines.GetTextPointFromIndex(index);
800 /// <param name="x"></param>
801 /// <param name="row"></param>
803 /// 範囲外の座標を指定した場合、範囲内に収まるように調整されます
805 public void Scroll(double x, int row)
811 int endRow = this.LayoutLines.Count - 1 - this.LineCountOnScreen;
816 base.TryScroll(x, row);
822 /// <param name="x"></param>
823 /// <param name="row"></param>
825 /// 範囲外の座標を指定した場合、範囲内に収まるように調整されます
827 public void Scroll(double x, double y)
833 double totalHeight = this.LayoutLines.Count * this.render.emSize.Height;
835 y = totalHeight - this.render.TextArea.Height;
836 base.TryScroll(x, y);
842 /// <param name="row">行</param>
843 /// <param name="alignTop">指定行を画面上に置くなら真。そうでないなら偽</param>
844 public void ScrollIntoView(int row, bool alignTop)
849 double y = this.render.TextArea.Height;
850 for (int i = row; i >= 0; i--)
852 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
853 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
854 double height = this.LayoutLines.GetLayout(i).Height;
859 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
865 public int AdjustRow(int row, bool isMoveNext)
867 if (this.LayoutLines.FoldingStrategy == null)
869 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(row);
870 int lineLength = this.LayoutLines.GetLengthFromLineNumber(row);
871 FoldingItem foldingData = this.LayoutLines.FoldingCollection.GetFarestHiddenFoldingData(lineHeadIndex, lineLength);
872 if (foldingData != null && !foldingData.Expand)
874 if (foldingData.End == this.Document.Length)
876 if (isMoveNext && lineHeadIndex > foldingData.Start)
877 row = this.LayoutLines.GetLineNumberFromIndex(foldingData.End) + 1;
879 row = this.LayoutLines.GetLineNumberFromIndex(foldingData.Start);
880 if(row > this.LayoutLines.Count - 1)
881 row = this.LayoutLines.GetLineNumberFromIndex(foldingData.Start);
886 protected override void CalculateClipRect()
888 IEditorRender render = (IEditorRender)base.render;
889 double x, y, width, height;
891 if (this.Document.DrawLineNumber)
893 if (this.Document.RightToLeft)
894 x = this.Padding.Left;
896 x = this.Padding.Left + UpdateAreaTotalWidth + this.render.LineNemberWidth + this.LineNumberMargin + render.FoldingWidth;
897 width = this.PageBound.Width - this.render.LineNemberWidth - this.LineNumberMargin - this.Padding.Left - this.Padding.Right - render.FoldingWidth - UpdateAreaTotalWidth;
901 if (this.Document.RightToLeft)
902 x = this.Padding.Left;
904 x = this.Padding.Left + UpdateAreaTotalWidth + render.FoldingWidth;
905 width = this.PageBound.Width - this.Padding.Left - this.Padding.Right - render.FoldingWidth - UpdateAreaTotalWidth;
908 y = this.Padding.Top;
909 height = this.PageBound.Height - this.Padding.Top - this.Padding.Bottom;
911 if (this.Document.HideRuler == false)
913 double rulerHeight = this.render.emSize.Height + LineMarkerThickness;
915 height -= rulerHeight;
924 this.render.TextArea = new Rectangle(x, y, width, height);
926 this.LineBreakingMarginWidth = width * 5 / 100;
929 public override void CalculateLineCountOnScreen()
931 if (this.LayoutLines.Count == 0 || this.PageBound.Height == 0)
935 int i = this.Src.Row;
936 int visualCount = this.Src.Row;
939 int row = i < this.LayoutLines.Count ? i : this.LayoutLines.Count - 1;
941 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(row);
942 int lineLength = this.LayoutLines.GetLengthFromLineNumber(row);
944 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex) && row < this.LayoutLines.Count - 1)
947 ITextLayout layout = this.LayoutLines.GetLayout(row);
949 double width = layout.Width;
951 if (width > this._LongestWidth)
952 this._LongestWidth = width;
954 double lineHeight = layout.Height;
958 if (y >= this.render.TextArea.Height)
962 this.LineCountOnScreen = Math.Max(visualCount - this.Src.Row - 1, 0);
963 this.LineCountOnScreenWithInVisible = Math.Max(i - this.Src.Row - 1, 0);
966 void SetCaretPostion(double x, double y)
968 this.CaretLocation = new Point(x + this.PageBound.X, y + this.PageBound.Y);
971 void FoldingCollection_StatusChanged(object sender, FoldingItemStatusChangedEventArgs e)
973 this.CalculateLineCountOnScreen();
984 double GetRealtiveX(AreaType type)
986 IEditorRender render = (IEditorRender)base.render;
989 case AreaType.UpdateArea:
990 if (this.Document.RightToLeft)
991 return this.PageBound.TopRight.X - UpdateAreaTotalWidth;
992 if (this.Document.DrawLineNumber)
993 return this.render.TextArea.X - this.render.LineNemberWidth - this.LineNumberMargin - render.FoldingWidth - UpdateAreaTotalWidth;
995 return this.render.TextArea.X - render.FoldingWidth - UpdateAreaTotalWidth;
996 case AreaType.FoldingArea:
997 if (this.Document.RightToLeft)
998 return this.PageBound.TopRight.X - render.FoldingWidth;
999 if (this.Document.DrawLineNumber)
1000 return this.render.TextArea.X - this.render.LineNemberWidth - this.LineNumberMargin - render.FoldingWidth;
1002 return this.render.TextArea.X - render.FoldingWidth;
1003 case AreaType.LineNumberArea:
1004 if (this.Document.DrawLineNumber == false)
1005 throw new InvalidOperationException();
1006 if (this.Document.RightToLeft)
1007 return this.PageBound.TopRight.X - UpdateAreaTotalWidth - render.FoldingWidth - this.render.LineNemberWidth;
1009 return this.render.TextArea.X - this.render.LineNemberWidth - this.LineNumberMargin;
1010 case AreaType.TextArea:
1011 return this.render.TextArea.X;
1013 throw new ArgumentOutOfRangeException();