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
24 enum TextPointSearchRange
31 /// キャレットとドキュメントの表示を担当します。レイアウト関連もこちらで行います
33 sealed class EditView : ViewBase
36 internal const float LineMarkerThickness = 2;
39 internal const int LineNumberLength = 6;
40 const int UpdateAreaPaddingWidth = 2;
41 const int UpdateAreaWidth = 4;
42 const int UpdateAreaTotalWidth = UpdateAreaWidth + UpdateAreaPaddingWidth;
47 public EditView(Document doc, IEditorRender r, int MarginLeftAndRight = 5)
48 : this(doc, r, new Padding(MarginLeftAndRight, 0, MarginLeftAndRight, 0))
55 /// <param name="doc">ドキュメント</param>
56 /// <param name="r">レンダー</param>
57 /// <param name="margin">マージン(1番目:左、2番目:上、3番目:右、4番目:下)</param>
58 public EditView(Document doc, IEditorRender r, Padding margin)
59 : base(doc, r, margin)
61 this.CaretBlinkTime = 500;
62 this.CaretWidthOnInsertMode = 1;
63 this.CalculateClipRect();
64 this.CaretLocation = new Point(this.render.TextArea.X, this.render.TextArea.Y);
65 this.LayoutLines.FoldingCollection.StatusChanged += FoldingCollection_StatusChanged;
66 this.IsFocused = false;
72 internal SelectCollection Selections
74 get { return this.Document.Selections; }
75 set { this.Document.Selections = value; }
79 /// ラインマーカーを描くなら偽。そうでなければ真
81 public bool HideLineMarker
83 get { return this.Document.HideLineMarker; }
84 set { this.Document.HideLineMarker = value; }
88 /// キャレットを描くなら偽。そうでなければ真
92 get { return this.Document.HideCaret; }
93 set { this.Document.HideCaret = value; }
97 /// 挿入モードなら真を返し、上書きモードなら偽を返す
99 public bool InsertMode
101 get { return this.Document.InsertMode; }
102 set { this.Document.InsertMode = value; }
108 public int CaretBlinkTime
117 public double CaretWidthOnInsertMode
124 /// フォーカスがあるなら真をセットする
126 public bool IsFocused
133 /// キャレットを点滅させるなら真。そうでないなら偽
135 /// <remarks>キャレット点滅タイマーもリセットされます</remarks>
136 public bool CaretBlink
138 get { return this._CaretBlink; }
141 this._CaretBlink = value;
143 this.tickCount = DateTime.Now.Ticks + this.To100nsTime(this.CaretBlinkTime);
148 /// 一ページの高さに収まる行数を返す(こちらは表示されていない行も含みます)
150 public int LineCountOnScreenWithInVisible
159 public double ScrollMarginWidth
161 get { return this.PageBound.Width * 20 / 100; }
167 public Point CaretLocation
176 /// <param name="x">x座標</param>
177 /// <param name="y">y座標</param>
178 /// <returns>テキストエリア内にあれば真。そうでなければ偽</returns>
179 public bool HitTextArea(double x, double y)
181 if (x >= this.render.TextArea.X && x <= this.render.TextArea.Right &&
182 y >= this.render.TextArea.Y && y <= this.render.TextArea.Bottom)
188 public bool IsUpperTextArea(double x, double y)
190 if (x >= this.render.TextArea.X && x <= this.render.TextArea.Right && y < this.render.TextArea.Y)
196 public bool IsUnderTextArea(double x,double y)
198 if (x >= this.render.TextArea.X && x <= this.render.TextArea.Right && y > this.render.TextArea.Bottom)
207 /// <param name="x">x座標</param>
208 /// <param name="row">行</param>
209 /// <returns>ヒットした場合はFoldingDataオブジェクトが返され、そうでない場合はnullが返る</returns>
210 public FoldingItem HitFoldingData(double x, int row)
212 IEditorRender render = (IEditorRender)base.render;
214 if (x >= this.GetRealtiveX(AreaType.FoldingArea) && x <= this.GetRealtiveX(AreaType.FoldingArea) + render.FoldingWidth)
216 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(row);
217 int lineLength = this.LayoutLines.GetLengthFromLineNumber(row);
218 FoldingItem foldingData = this.LayoutLines.FoldingCollection.Get(lineHeadIndex, lineLength);
219 if (foldingData != null && foldingData.IsFirstLine(this.LayoutLines,row))
226 /// Rectで指定された範囲にドキュメントを描く
228 /// <param name="updateRect">描写する範囲</param>
229 /// <param name="force">キャッシュした内容を使用しない場合は真を指定する</param>
230 /// <remarks>描写する範囲がPageBoundより小さい場合、キャッシュされた内容を使用することがあります。なお、レタリング後にrender.CacheContent()を呼び出さなかった場合は更新範囲にかかわらずキャッシュを使用しません</remarks>
231 public override void Draw(Rectangle updateRect,bool force = false)
233 if (this.LayoutLines.Count == 0)
236 IEditorRender render = (IEditorRender)base.render;
238 if ((updateRect.Height < this.PageBound.Height ||
239 updateRect.Width < this.PageBound.Width) &&
240 render.IsVaildCache() &&
243 render.DrawCachedBitmap(updateRect);
247 Rectangle background = this.PageBound;
248 render.FillBackground(background);
250 if (this.Document.HideRuler == false)
253 this.DrawLineMarker(this.Document.CaretPostion.row);
255 Point pos = this.render.TextArea.TopLeft;
256 //画面上では(X,Y)が開始位置になるが、開始する行が決まっているのでオフセットを求める
257 pos.Y -= this.Src.GetOffsetY(this.render.emSize.Height);
259 double endposy = this.render.TextArea.Bottom;
260 Size lineNumberSize = new Size(this.render.LineNemberWidth, this.render.TextArea.Height);
262 this.render.BeginClipRect(new Rectangle(this.PageBound.X, this.render.TextArea.Y, this.PageBound.Width, this.render.TextArea.Height));
264 //パフォーマンス向上のため行番号などを先に描く
265 for (int i = this.Src.Row; i < this.LayoutLines.Count; i++)
267 int lineIndex = this.LayoutLines.GetIndexFromLineNumber(i);
268 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
269 ITextLayout layout = this.LayoutLines.GetLayout(i);
274 FoldingItem foldingData = this.LayoutLines.FoldingCollection.Get(lineIndex, lineLength);
276 if (foldingData != null)
278 if ((!this.LayoutLines.FoldingCollection.IsHasParent(foldingData) ||
279 !this.LayoutLines.FoldingCollection.IsParentHidden(foldingData))
280 && foldingData.IsFirstLine(this.LayoutLines, i))
281 render.DrawFoldingMark(foldingData.Expand, this.PageBound.X + this.GetRealtiveX(AreaType.FoldingArea), pos.Y);
282 if (this.LayoutLines.FoldingCollection.IsHidden(lineIndex))
286 if (this.Document.DrawLineNumber)
288 this.render.DrawString((i + 1).ToString(), this.PageBound.X + this.GetRealtiveX(AreaType.LineNumberArea), pos.Y, StringAlignment.Right, lineNumberSize,StringColorType.LineNumber);
291 DrawUpdateArea(i, pos.Y);
293 pos.Y += this.LayoutLines.GetLayout(i).Height;
294 //pos.Y += this.render.emSize.Height;
297 this.render.EndClipRect();
300 pos = this.render.TextArea.TopLeft;
302 pos.Y -= this.Src.GetOffsetY(this.render.emSize.Height);
304 this.render.BeginClipRect(this.render.TextArea);
306 for (int i = this.Src.Row; i < this.LayoutLines.Count; i++)
308 int lineIndex = this.LayoutLines.GetIndexFromLineNumber(i);
309 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
310 ITextLayout layout = this.LayoutLines.GetLayout(i);
315 FoldingItem foldingData = this.LayoutLines.FoldingCollection.Get(lineIndex, lineLength);
317 if (foldingData != null)
319 if (this.LayoutLines.FoldingCollection.IsHidden(lineIndex))
323 var selectRange = from s in this.Selections.Get(lineIndex, lineLength)
324 let n = Util.ConvertAbsIndexToRelIndex(s, lineIndex, lineLength)
327 this.render.DrawOneLine(this.LayoutLines, i, pos.X, pos.Y, selectRange);
329 pos.Y += this.LayoutLines.GetLayout(i).Height;
330 //pos.Y += this.render.emSize.Height;
333 this.render.EndClipRect();
335 this.DrawInsertPoint();
337 this.Document.SelectGrippers.BottomLeft.Draw(this.render);
338 this.Document.SelectGrippers.BottomRight.Draw(this.render);
340 render.CacheContent();
346 void DrawUpdateArea(int row,double ypos)
348 IEditorRender render = (IEditorRender)base.render;
349 if(this.LayoutLines.GetDirtyFlag(row))
351 Point pos = new Point(this.PageBound.X + this.GetRealtiveX(AreaType.UpdateArea), ypos);
352 Rectangle rect = new Rectangle(pos.X, pos.Y, UpdateAreaWidth, this.LayoutLines.GetLayout(row).Height);
353 render.FillRectangle(rect, FillRectType.UpdateArea);
359 IEditorRender render = (IEditorRender)base.render;
362 Size emSize = render.emSize;
363 Rectangle clipRect = this.render.TextArea;
365 double markerHeight = emSize.Height / 2;
366 if (this.Document.RightToLeft)
368 pos = new Point(clipRect.TopRight.X, clipRect.TopRight.Y - emSize.Height - LineMarkerThickness);
369 for (; pos.X >= clipRect.TopLeft.X; pos.X -= emSize.Width, count++)
372 to = new Point(pos.X, pos.Y + emSize.Height);
373 int mod = count % 10;
376 string countStr = (count / 10).ToString();
377 double counterWidth = emSize.Width * countStr.Length;
378 this.render.DrawString(countStr, pos.X - counterWidth, pos.Y, StringAlignment.Right, new Size(counterWidth, double.MaxValue));
381 from.Y = from.Y + emSize.Height / 2;
383 from.Y = from.Y + emSize.Height * 3 / 4;
384 render.DrawLine(from, to);
385 if (this.CaretLocation.X >= pos.X && this.CaretLocation.X < pos.X + emSize.Width)
386 render.FillRectangle(new Rectangle(pos.X, pos.Y + markerHeight, emSize.Width, markerHeight), FillRectType.OverwriteCaret);
391 pos = new Point(clipRect.TopLeft.X, clipRect.TopLeft.Y - emSize.Height - LineMarkerThickness);
392 for (; pos.X < clipRect.TopRight.X; pos.X += emSize.Width, count++)
395 to = new Point(pos.X, pos.Y + emSize.Height);
396 int mod = count % 10;
398 this.render.DrawString((count / 10).ToString(), pos.X, pos.Y, StringAlignment.Left, new Size(double.MaxValue, double.MaxValue));
400 from.Y = from.Y + emSize.Height / 2;
402 from.Y = from.Y + emSize.Height * 3 / 4;
403 render.DrawLine(from, to);
404 if (this.CaretLocation.X >= pos.X && this.CaretLocation.X < pos.X + emSize.Width)
405 render.FillRectangle(new Rectangle(pos.X, pos.Y + markerHeight, emSize.Width, markerHeight), FillRectType.OverwriteCaret);
408 from = clipRect.TopLeft;
409 from.Y -= LineMarkerThickness;
410 to = clipRect.TopRight;
411 to.Y -= LineMarkerThickness;
412 render.DrawLine(from, to);
415 void DrawInsertPoint()
417 //一つしかない場合は行選択の可能性がある
418 if (this.Selections.Count <= 1)
420 IEditorRender render = (IEditorRender)base.render;
421 foreach (Selection sel in this.Selections)
425 TextPoint tp = this.GetLayoutLineFromIndex(sel.start);
426 Point left = this.GetPostionFromTextPoint(tp);
427 double lineHeight = this.LayoutLines.GetLayout(tp.row).Height;
428 Rectangle InsertRect = new Rectangle(left.X,
430 CaretWidthOnInsertMode,
432 render.FillRectangle(InsertRect, FillRectType.InsertPoint);
439 if (this.HideCaret || !this.IsFocused)
442 long diff = DateTime.Now.Ticks - this.tickCount;
443 long blinkTime = this.To100nsTime(this.CaretBlinkTime);
445 if (this.CaretBlink && diff % blinkTime >= blinkTime / 2)
448 Rectangle CaretRect = new Rectangle();
450 IEditorRender render = (IEditorRender)base.render;
452 int row = this.Document.CaretPostion.row;
453 double lineHeight = this.LayoutLines.GetLayout(row).Height;
454 double charWidth = this.LayoutLines.GetLayout(row).GetWidthFromIndex(this.Document.CaretPostion.col);
456 if (this.InsertMode || charWidth == 0)
458 CaretRect.Size = new Size(CaretWidthOnInsertMode, lineHeight);
459 CaretRect.Location = new Point(this.CaretLocation.X, this.CaretLocation.Y);
460 render.FillRectangle(CaretRect, FillRectType.InsertCaret);
464 double height = lineHeight / 3;
465 CaretRect.Size = new Size(charWidth, height);
466 CaretRect.Location = new Point(this.CaretLocation.X, this.CaretLocation.Y + lineHeight - height);
467 render.FillRectangle(CaretRect, FillRectType.OverwriteCaret);
472 long To100nsTime(int ms)
477 public void DrawLineMarker(int row)
479 if (this.HideLineMarker || !this.IsFocused)
481 IEditorRender render = (IEditorRender)base.render;
482 Point p = this.CaretLocation;
483 double height = this.LayoutLines.GetLayout(this.Document.CaretPostion.row).Height;
484 double width = this.render.TextArea.Width;
485 render.FillRectangle(new Rectangle(this.PageBound.X + this.render.TextArea.X, this.CaretLocation.Y, width, height), FillRectType.LineMarker);
491 /// <returns>矩形領域を表すRectangle</returns>
492 public Rectangle GetCurrentCaretRect()
494 ITextLayout layout = this.LayoutLines.GetLayout(this.Document.CaretPostion.row);
495 double width = layout.GetWidthFromIndex(this.Document.CaretPostion.col);
497 width = this.CaretWidthOnInsertMode;
498 double height = layout.Height;
499 Rectangle updateRect = new Rectangle(
500 this.CaretLocation.X,
501 this.CaretLocation.Y,
508 /// 指定した座標の一番近くにあるTextPointを取得する
510 /// <param name="p">テキストエリアを左上とする相対位置</param>
511 /// <param name="searchRange">探索範囲</param>
512 /// <returns>レイアウトラインを指し示すTextPoint</returns>
513 public TextPoint GetTextPointFromPostion(Point p,TextPointSearchRange searchRange = TextPointSearchRange.TextAreaOnly)
515 if(searchRange == TextPointSearchRange.TextAreaOnly)
517 if (p.Y < this.render.TextArea.TopLeft.Y ||
518 p.Y > this.render.TextArea.BottomRight.Y)
519 return TextPoint.Null;
522 TextPoint tp = new TextPoint();
524 if (this.LayoutLines.Count == 0)
527 p.Y -= this.render.TextArea.Y;
529 int lineHeadIndex, lineLength;
531 if(p.Y >= this.render.TextArea.TopLeft.Y)
534 tp.row = this.LayoutLines.Count - 1;
535 for (int i = this.Src.Row; i < this.LayoutLines.Count; i++)
537 double height = this.LayoutLines.GetLayout(i).Height;
539 lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
540 lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
542 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
545 if (y + height > p.Y)
554 double y = this.render.TextArea.TopLeft.Y;
556 for (int i = this.Src.Row; i >= 0; i--)
558 double height = this.LayoutLines.GetLayout(i).Height;
560 lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
561 lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
563 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
566 if (y - height < p.Y)
575 if (searchRange == TextPointSearchRange.TextAreaOnly)
577 if (p.X < this.render.TextArea.X)
581 tp.col = GetIndexFromColPostion(tp.row, p.X);
583 lineLength = this.LayoutLines.GetLengthFromLineNumber(tp.row);
584 if (tp.col > lineLength)
591 /// 桁方向の座標に対応するインデックスを取得する
593 /// <param name="row">対象となる行</param>
594 /// <param name="x">テキストエリアからの相対位置</param>
595 /// <returns></returns>
596 public int GetIndexFromColPostion(int row, double x)
598 x -= this.render.TextArea.X;
599 int lineLength = this.LayoutLines.GetLengthFromLineNumber(row);
602 int index = this.LayoutLines.GetLayout(row).GetIndexFromColPostion(this.Src.X + x);
607 /// インデックスに対応する桁方向の座標を得る
609 /// <param name="row">対象となる行</param>
610 /// <param name="index">インデックス</param>
611 /// <returns>テキストエリアからの相対位置を返す</returns>
612 public double GetColPostionFromIndex(int row, int index)
614 double x = this.LayoutLines.GetLayout(row).GetColPostionFromIndex(index);
615 return x - Src.X + this.render.TextArea.X;
619 /// TextPointに対応する座標を得る
621 /// <param name="tp">レイアウトライン上の位置</param>
622 /// <returns>テキストエリアを左上とする相対位置</returns>
623 public Point GetPostionFromTextPoint(TextPoint tp)
625 Point p = new Point();
626 for (int i = this.Src.Row; i < tp.row; i++)
628 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
629 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
630 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
632 p.Y += this.LayoutLines.GetLayout(i).Height;
634 p.X = this.GetColPostionFromIndex(tp.row, tp.col);
635 p.Y += this.render.TextArea.Y;
639 public Gripper HitGripperFromPoint(Point p)
641 if (this.Document.SelectGrippers.BottomLeft.IsHit(p))
642 return this.Document.SelectGrippers.BottomLeft;
643 if (this.Document.SelectGrippers.BottomRight.IsHit(p))
644 return this.Document.SelectGrippers.BottomRight;
648 public Rectangle GetRectFromIndex(int index,int width,int height)
650 TextPoint tp = this.LayoutLines.GetTextPointFromIndex(index);
651 return this.GetRectFromTextPoint(tp, width, height);
654 public Rectangle GetRectFromTextPoint(TextPoint tp, int width, int height)
656 if (tp.row < this.Src.Row)
657 return Rectangle.Empty;
658 double radius = width / 2;
659 Point point = this.GetPostionFromTextPoint(tp);
660 double lineHeight = this.LayoutLines.GetLayout(tp.row).Height;
661 double srcOffsetY = this.Src.GetOffsetY(this.render.emSize.Height); //画面上ではずれているので引く必要がある
663 Rectangle rect = new Rectangle(point.X - radius, point.Y + lineHeight - srcOffsetY, width, height);
665 if (rect.BottomLeft.Y >= this.render.TextArea.BottomLeft.Y ||
666 rect.BottomRight.X < this.render.TextArea.BottomLeft.X ||
667 rect.BottomLeft.X > this.render.TextArea.BottomRight.X)
668 return Rectangle.Empty;
673 /// キャレットを指定した位置に移動させる
675 /// <param name="row"></param>
676 /// <param name="col"></param>
677 /// <param name="autoExpand">折り畳みを展開するなら真</param>
678 public void JumpCaret(int row, int col, bool autoExpand = true)
682 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(row);
683 int lineLength = this.LayoutLines.GetLengthFromLineNumber(row);
684 FoldingItem foldingData = this.LayoutLines.FoldingCollection.Get(lineHeadIndex, lineLength);
685 if(foldingData != null)
687 if (this.LayoutLines.FoldingCollection.IsParentHidden(foldingData) || !foldingData.IsFirstLine(this.LayoutLines, row))
689 this.LayoutLines.FoldingCollection.Expand(foldingData);
695 this.Document.SetCaretPostionWithoutEvent(new TextPoint(row, col));
699 /// index上の文字が表示されるようにSrcを調整する
701 /// <param name="index">インデックス</param>
702 /// <returns>調整されたら真。そうでなければ偽</returns>
703 public bool AdjustSrc(int index)
705 TextPoint startTextPoint = this.GetLayoutLineFromIndex(index);
706 double x = this.LayoutLines.GetLayout(startTextPoint.row).GetColPostionFromIndex(startTextPoint.col);
707 if (x < this.Src.X ||
708 x > this.Src.X + this.PageBound.Width)
710 this.TryScroll(x, this.Src.Row);
713 if (startTextPoint.row < this.Src.Row ||
714 startTextPoint.row > this.Src.Row + this.LineCountOnScreenWithInVisible)
716 this.TryScroll(this.Src.X, startTextPoint.row);
723 /// キャレットがあるところまでスクロールする
725 /// <return>再描写する必要があるなら真を返す</return>
726 /// <remarks>Document.Update(type == UpdateType.Clear)イベント時に呼び出した場合、例外が発生します</remarks>
727 public bool AdjustCaretAndSrc(AdjustFlow flow = AdjustFlow.Both)
729 IEditorRender render = (IEditorRender)base.render;
731 if (this.PageBound.Width == 0 || this.PageBound.Height == 0)
733 this.SetCaretPostion(this.Padding.Left + render.FoldingWidth, 0);
738 TextPoint tp = this.Document.CaretPostion;
739 double x = this.CaretLocation.X;
740 double y = this.CaretLocation.Y;
742 if (flow == AdjustFlow.Col || flow == AdjustFlow.Both)
744 x = this.LayoutLines.GetLayout(tp.row).GetColPostionFromIndex(tp.col);
746 double left = this.Src.X;
747 double right = this.Src.X + this.render.TextArea.Width;
749 if (x >= left && x <= right) //xは表示領域にないにある
753 else if (x > right) //xは表示領域の右側にある
755 this.Document.Src = new SrcPoint(x - this.render.TextArea.Width + this.ScrollMarginWidth,this.Document.Src.Row,this.Document.Src.Y);
756 if (this.Document.RightToLeft && this.Document.Src.X > 0)
758 System.Diagnostics.Debug.Assert(x > 0);
759 this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Document.Src.Y);
763 x = this.render.TextArea.Width - this.ScrollMarginWidth;
767 else if (x < left) //xは表示領域の左側にある
769 this.Document.Src = new SrcPoint(x - this.ScrollMarginWidth, this.Document.Src.Row, this.Document.Src.Y);
770 if (!this.Document.RightToLeft && this.Document.Src.X < this.render.TextArea.X)
772 this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Document.Src.Y);
776 x = this.ScrollMarginWidth;
780 x += this.render.TextArea.X;
783 if (flow == AdjustFlow.Row || flow == AdjustFlow.Both)
786 int lineCount = this.LineCountOnScreenWithInVisible;
787 if (tp.row >= this.Src.Row && tp.row < this.Src.Row + lineCount)
789 caretRow = tp.row - this.Src.Row;
790 y = -this.Src.GetOffsetY(this.render.emSize.Height); //画面上ではずれているので引く必要がある
792 else if (tp.row >= this.Src.Row + lineCount)
794 int srcRow = this.GetSrcRow(tp.row, this.LineCountOnScreen);
795 this.Document.Src = new SrcPoint(this.Document.Src.X, srcRow, srcRow * this.render.emSize.Height);
796 caretRow = tp.row - this.Document.Src.Row;
799 CalculateLineCountOnScreen();
801 else if (tp.row < this.Src.Row)
803 this.Document.Src = new SrcPoint(this.Document.Src.X, tp.row, tp.row * this.render.emSize.Height);
806 CalculateLineCountOnScreen();
811 for (int i = 0; i < caretRow; i++)
813 int currentRow = this.Src.Row + i;
814 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(currentRow);
815 int lineLength = this.LayoutLines.GetLengthFromLineNumber(currentRow);
817 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
820 y += this.LayoutLines.GetLayout(currentRow).Height;
823 y += this.render.TextArea.Y;
826 this.SetCaretPostion(x, y);
830 this.OnSrcChanged(null);
836 int GetSrcRow(int row,int count)
838 if (this.LayoutLines.FoldingStrategy == null)
840 for (int i = row; i >= 0; i--)
842 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
843 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
844 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
854 /// レイアウト行をテキストポイントからインデックスに変換する
856 /// <param name="tp">テキストポイント表す</param>
857 /// <returns>インデックスを返す</returns>
858 public int GetIndexFromLayoutLine(TextPoint tp)
860 return this.LayoutLines.GetIndexFromTextPoint(tp);
864 /// インデックスからレイアウト行を指し示すテキストポイントに変換する
866 /// <param name="index">インデックスを表す</param>
867 /// <returns>テキストポイント返す</returns>
868 public TextPoint GetLayoutLineFromIndex(int index)
870 return this.LayoutLines.GetTextPointFromIndex(index);
876 /// <param name="x"></param>
877 /// <param name="row"></param>
879 /// 範囲外の座標を指定した場合、範囲内に収まるように調整されます
881 public void Scroll(double x, int row)
887 int endRow = this.LayoutLines.Count - 1 - this.LineCountOnScreen;
892 base.TryScroll(x, row);
898 /// <param name="row">行</param>
899 /// <param name="alignTop">指定行を画面上に置くなら真。そうでないなら偽</param>
900 public void ScrollIntoView(int row, bool alignTop)
905 double y = this.render.TextArea.Height;
906 for (int i = row; i >= 0; i--)
908 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
909 int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
910 double height = this.LayoutLines.GetLayout(i).Height;
915 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
921 public int AdjustRow(int row, bool isMoveNext)
923 if (this.LayoutLines.FoldingStrategy == null)
925 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(row);
926 int lineLength = this.LayoutLines.GetLengthFromLineNumber(row);
927 FoldingItem foldingData = this.LayoutLines.FoldingCollection.GetFarestHiddenFoldingData(lineHeadIndex, lineLength);
928 if (foldingData != null && !foldingData.Expand)
930 if (foldingData.End == this.Document.Length)
932 if (isMoveNext && lineHeadIndex > foldingData.Start)
933 row = this.LayoutLines.GetLineNumberFromIndex(foldingData.End) + 1;
935 row = this.LayoutLines.GetLineNumberFromIndex(foldingData.Start);
936 if(row > this.LayoutLines.Count - 1)
937 row = this.LayoutLines.GetLineNumberFromIndex(foldingData.Start);
942 protected override void CalculateClipRect()
944 IEditorRender render = (IEditorRender)base.render;
945 double x, y, width, height;
947 if (this.Document.DrawLineNumber)
949 if (this.Document.RightToLeft)
950 x = this.Padding.Left;
952 x = this.Padding.Left + UpdateAreaTotalWidth + this.render.LineNemberWidth + this.LineNumberMargin + render.FoldingWidth;
953 width = this.PageBound.Width - this.render.LineNemberWidth - this.LineNumberMargin - this.Padding.Left - this.Padding.Right - render.FoldingWidth - UpdateAreaTotalWidth;
957 if (this.Document.RightToLeft)
958 x = this.Padding.Left;
960 x = this.Padding.Left + UpdateAreaTotalWidth + render.FoldingWidth;
961 width = this.PageBound.Width - this.Padding.Left - this.Padding.Right - render.FoldingWidth - UpdateAreaTotalWidth;
964 y = this.Padding.Top;
965 height = this.PageBound.Height - this.Padding.Top - this.Padding.Bottom;
967 if (this.Document.HideRuler == false)
969 double rulerHeight = this.render.emSize.Height + LineMarkerThickness;
971 height -= rulerHeight;
980 this.render.TextArea = new Rectangle(x, y, width, height);
982 this.LineBreakingMarginWidth = width * 5 / 100;
985 public override void CalculateLineCountOnScreen()
987 if (this.LayoutLines.Count == 0 || this.PageBound.Height == 0)
991 int i = this.Src.Row;
992 int visualCount = this.Src.Row;
995 int row = i < this.LayoutLines.Count ? i : this.LayoutLines.Count - 1;
997 int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(row);
998 int lineLength = this.LayoutLines.GetLengthFromLineNumber(row);
1000 if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex) && row < this.LayoutLines.Count - 1)
1003 ITextLayout layout = this.LayoutLines.GetLayout(row);
1005 double width = layout.Width;
1007 if (width > this._LongestWidth)
1008 this._LongestWidth = width;
1010 double lineHeight = layout.Height;
1014 if (y >= this.render.TextArea.Height)
1018 this.LineCountOnScreen = Math.Max(visualCount - this.Src.Row - 1, 0);
1019 this.LineCountOnScreenWithInVisible = Math.Max(i - this.Src.Row - 1, 0);
1022 void SetCaretPostion(double x, double y)
1024 this.CaretLocation = new Point(x + this.PageBound.X, y + this.PageBound.Y);
1027 void FoldingCollection_StatusChanged(object sender, FoldingItemStatusChangedEventArgs e)
1029 this.CalculateLineCountOnScreen();
1040 double GetRealtiveX(AreaType type)
1042 IEditorRender render = (IEditorRender)base.render;
1045 case AreaType.UpdateArea:
1046 if (this.Document.RightToLeft)
1047 return this.PageBound.TopRight.X - UpdateAreaTotalWidth;
1048 if (this.Document.DrawLineNumber)
1049 return this.render.TextArea.X - this.render.LineNemberWidth - this.LineNumberMargin - render.FoldingWidth - UpdateAreaTotalWidth;
1051 return this.render.TextArea.X - render.FoldingWidth - UpdateAreaTotalWidth;
1052 case AreaType.FoldingArea:
1053 if (this.Document.RightToLeft)
1054 return this.PageBound.TopRight.X - render.FoldingWidth;
1055 if (this.Document.DrawLineNumber)
1056 return this.render.TextArea.X - this.render.LineNemberWidth - this.LineNumberMargin - render.FoldingWidth;
1058 return this.render.TextArea.X - render.FoldingWidth;
1059 case AreaType.LineNumberArea:
1060 if (this.Document.DrawLineNumber == false)
1061 throw new InvalidOperationException();
1062 if (this.Document.RightToLeft)
1063 return this.PageBound.TopRight.X - UpdateAreaTotalWidth - render.FoldingWidth - this.render.LineNemberWidth;
1065 return this.render.TextArea.X - this.render.LineNemberWidth - this.LineNumberMargin;
1066 case AreaType.TextArea:
1067 return this.render.TextArea.X;
1069 throw new ArgumentOutOfRangeException();