X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=Core%2FEditView.cs;h=ee5252634f3e00a3815ab01da9e0dddccc65d8c1;hb=450b22e9241eea1a294b4eb819114baa89cd67a8;hp=14423b0101af2145c3162537d40339f1cd1301c5;hpb=b8781bb7d15031261c47cd559c703c9a865756cb;p=fooeditengine%2FFooEditEngine.git diff --git a/Core/EditView.cs b/Core/EditView.cs index 14423b0..ee52526 100644 --- a/Core/EditView.cs +++ b/Core/EditView.cs @@ -21,6 +21,12 @@ namespace FooEditEngine Both, } + enum TextPointSearchRange + { + TextAreaOnly, + Full + } + /// /// キャレットとドキュメントの表示を担当します。レイアウト関連もこちらで行います /// @@ -29,7 +35,7 @@ namespace FooEditEngine { internal const float LineMarkerThickness = 2; long tickCount; - bool _CaretBlink, _HideRuler = true; + bool _CaretBlink; internal const int LineNumberLength = 6; const int UpdateAreaPaddingWidth = 2; const int UpdateAreaWidth = 4; @@ -179,6 +185,22 @@ namespace FooEditEngine return false; } + public bool IsUpperTextArea(double x, double y) + { + if (x >= this.render.TextArea.X && x <= this.render.TextArea.Right && y < this.render.TextArea.Y) + return true; + else + return false; + } + + public bool IsUnderTextArea(double x,double y) + { + if (x >= this.render.TextArea.X && x <= this.render.TextArea.Right && y > this.render.TextArea.Bottom) + return true; + else + return false; + } + /// /// ヒットテストを行う /// @@ -204,8 +226,9 @@ namespace FooEditEngine /// Rectで指定された範囲にドキュメントを描く /// /// 描写する範囲 - /// キャレットを点滅させる場合、定期的のこのメソッドを呼び出してください - public override void Draw(Rectangle updateRect) + /// キャッシュした内容を使用しない場合は真を指定する + /// 描写する範囲がPageBoundより小さい場合、キャッシュされた内容を使用することがあります。なお、レタリング後にrender.CacheContent()を呼び出さなかった場合は更新範囲にかかわらずキャッシュを使用しません + public override void Draw(Rectangle updateRect,bool force = false) { if (this.LayoutLines.Count == 0) return; @@ -214,7 +237,8 @@ namespace FooEditEngine if ((updateRect.Height < this.PageBound.Height || updateRect.Width < this.PageBound.Width) && - render.IsVaildCache()) + render.IsVaildCache() && + !force) { render.DrawCachedBitmap(updateRect); } @@ -229,11 +253,15 @@ namespace FooEditEngine this.DrawLineMarker(this.Document.CaretPostion.row); Point pos = this.render.TextArea.TopLeft; - pos.X -= this.Src.X; - //画面上では(X,Y)が開始位置になるが、開始する行が決まっているのでオフセットを求める - pos.Y -= this.Src.GetOffsetY(this.render.emSize.Height); + //画面上では行をずらして表示する + pos.Y += this.Src.OffsetY; + double endposy = this.render.TextArea.Bottom; - Size lineNumberSize = new Size(this.render.LineNemberWidth,this.render.TextArea.Height); + Size lineNumberSize = new Size(this.render.LineNemberWidth, this.render.TextArea.Height); + + this.render.BeginClipRect(new Rectangle(this.PageBound.X, this.render.TextArea.Y, this.PageBound.Width, this.render.TextArea.Height)); + + //パフォーマンス向上のため行番号などを先に描く for (int i = this.Src.Row; i < this.LayoutLines.Count; i++) { int lineIndex = this.LayoutLines.GetIndexFromLineNumber(i); @@ -247,20 +275,12 @@ namespace FooEditEngine if (foldingData != null) { - if ((!this.LayoutLines.FoldingCollection.IsHasParent(foldingData) || - !this.LayoutLines.FoldingCollection.IsParentHidden(foldingData)) - && foldingData.IsFirstLine(this.LayoutLines, i)) - render.DrawFoldingMark(foldingData.Expand, this.PageBound.X + this.GetRealtiveX(AreaType.FoldingArea), pos.Y); if (this.LayoutLines.FoldingCollection.IsHidden(lineIndex)) continue; + if (foldingData.IsFirstLine(this.LayoutLines, i) && foldingData.End >= lineIndex + lineLength) + render.DrawFoldingMark(foldingData.Expand, this.PageBound.X + this.GetRealtiveX(AreaType.FoldingArea), pos.Y); } - var selectRange = from s in this.Selections.Get(lineIndex, lineLength) - let n = Util.ConvertAbsIndexToRelIndex(s, lineIndex, lineLength) - select n; - - this.render.DrawOneLine(this.LayoutLines, i, pos.X, pos.Y, selectRange); - if (this.Document.DrawLineNumber) { this.render.DrawString((i + 1).ToString(), this.PageBound.X + this.GetRealtiveX(AreaType.LineNumberArea), pos.Y, StringAlignment.Right, lineNumberSize,StringColorType.LineNumber); @@ -268,18 +288,52 @@ namespace FooEditEngine DrawUpdateArea(i, pos.Y); - pos.Y += this.LayoutLines.GetLayout(i).Height; + pos.Y += layout.Height; + //pos.Y += this.render.emSize.Height; } + this.render.EndClipRect(); + + //リセットしないと行が正しく描けない + pos = this.render.TextArea.TopLeft; + pos.X -= this.Src.X; + pos.Y += this.Src.OffsetY; + + this.render.BeginClipRect(this.render.TextArea); + + for (int i = this.Src.Row; i < this.LayoutLines.Count; i++) + { + int lineIndex = this.LayoutLines.GetIndexFromLineNumber(i); + int lineLength = this.LayoutLines.GetLengthFromLineNumber(i); + ITextLayout layout = this.LayoutLines.GetLayout(i); + + if (pos.Y > endposy) + break; + + FoldingItem foldingData = this.LayoutLines.FoldingCollection.Get(lineIndex, lineLength); + + if (foldingData != null) + { + if (this.LayoutLines.FoldingCollection.IsHidden(lineIndex)) + continue; + } + + this.render.DrawOneLine(this.Document, this.LayoutLines, i, pos.X, pos.Y); + + pos.Y += layout.Height; + } + + this.render.EndClipRect(); + this.DrawInsertPoint(); + this.Document.SelectGrippers.BottomLeft.Draw(this.render); + this.Document.SelectGrippers.BottomRight.Draw(this.render); + render.CacheContent(); } - this.DrawCaret(); - - this.Document.SelectGrippers.BottomLeft.Draw(this.render); - this.Document.SelectGrippers.BottomRight.Draw(this.render); + this.DrawCaret(); } void DrawUpdateArea(int row,double ypos) @@ -363,7 +417,7 @@ namespace FooEditEngine { TextPoint tp = this.GetLayoutLineFromIndex(sel.start); Point left = this.GetPostionFromTextPoint(tp); - double lineHeight = this.LayoutLines.GetLayout(tp.row).Height; + double lineHeight = render.emSize.Height; Rectangle InsertRect = new Rectangle(left.X, left.Y, CaretWidthOnInsertMode, @@ -373,24 +427,25 @@ namespace FooEditEngine } } - void DrawCaret() + bool DrawCaret() { if (this.HideCaret || !this.IsFocused) - return; + return false; long diff = DateTime.Now.Ticks - this.tickCount; long blinkTime = this.To100nsTime(this.CaretBlinkTime); if (this.CaretBlink && diff % blinkTime >= blinkTime / 2) - return; + return false; Rectangle CaretRect = new Rectangle(); IEditorRender render = (IEditorRender)base.render; int row = this.Document.CaretPostion.row; - double lineHeight = this.LayoutLines.GetLayout(row).Height; - double charWidth = this.LayoutLines.GetLayout(row).GetWidthFromIndex(this.Document.CaretPostion.col); + ITextLayout layout = this.LayoutLines.GetLayout(row); + double lineHeight = render.emSize.Height; + double charWidth = layout.GetWidthFromIndex(this.Document.CaretPostion.col); if (this.InsertMode || charWidth == 0) { @@ -405,6 +460,7 @@ namespace FooEditEngine CaretRect.Location = new Point(this.CaretLocation.X, this.CaretLocation.Y + lineHeight - height); render.FillRectangle(CaretRect, FillRectType.OverwriteCaret); } + return true; } long To100nsTime(int ms) @@ -418,7 +474,7 @@ namespace FooEditEngine return; IEditorRender render = (IEditorRender)base.render; Point p = this.CaretLocation; - double height = this.LayoutLines.GetLayout(this.Document.CaretPostion.row).Height; + double height = this.LayoutLines.GetLineHeight(this.Document.CaretPostion); double width = this.render.TextArea.Width; render.FillRectangle(new Rectangle(this.PageBound.X + this.render.TextArea.X, this.CaretLocation.Y, width, height), FillRectType.LineMarker); } @@ -433,7 +489,7 @@ namespace FooEditEngine double width = layout.GetWidthFromIndex(this.Document.CaretPostion.col); if (width == 0.0) width = this.CaretWidthOnInsertMode; - double height = layout.Height; + double height = this.LayoutLines.GetLineHeight(this.Document.CaretPostion); Rectangle updateRect = new Rectangle( this.CaretLocation.X, this.CaretLocation.Y, @@ -445,47 +501,63 @@ namespace FooEditEngine /// /// 指定した座標の一番近くにあるTextPointを取得する /// - /// テキストエリアを左上とする相対位置 + /// ビューエリアを左上とする相対位置 + /// 探索範囲 /// レイアウトラインを指し示すTextPoint - public TextPoint GetTextPointFromPostion(Point p) + public TextPoint GetTextPointFromPostion(Point p,TextPointSearchRange searchRange = TextPointSearchRange.TextAreaOnly) { - if (p.Y < this.render.TextArea.TopLeft.Y || - p.Y > this.render.TextArea.BottomRight.Y) - return TextPoint.Null; + if(searchRange == TextPointSearchRange.TextAreaOnly) + { + if (p.Y < this.render.TextArea.TopLeft.Y || + p.Y > this.render.TextArea.BottomRight.Y) + return TextPoint.Null; + } + TextPoint tp = new TextPoint(); if (this.LayoutLines.Count == 0) return tp; + //表示領域から探索を始めるのでパディングの分だけ引く p.Y -= this.render.TextArea.Y; - int lineHeadIndex, lineLength; - double y = 0; - tp.row = this.LayoutLines.Count - 1; - for (int i = this.Src.Row; i < this.LayoutLines.Count; i++) + //p.Y に最も近い行を調べる + var t = this.GetNearstRowAndOffsetY(this.Src.Row, p.Y); + double relX = 0, relY; + if (t == null) { - double height = this.LayoutLines.GetLayout(i).Height; - - lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i); - lineLength = this.LayoutLines.GetLengthFromLineNumber(i); - - if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex)) - continue; - - if (y + height > p.Y) + if(p.Y > 0) { - tp.row = i; - break; + tp.row = this.LayoutLines.Count - 1; + relY = this.LayoutLines.GetLayout(tp.row).Height - this.render.emSize.Height; + } + else if(p.Y == 0) + { + tp.row = this.Src.Row; + relY = 0; } - y += height; + else + { + tp.row = 0; + relY = 0; + } + } + else + { + tp.row = t.Item1; + relY = t.Item2; //相対位置がマイナスなので反転させる } - if (p.X < this.render.TextArea.X) - return tp; + if (searchRange == TextPointSearchRange.TextAreaOnly) + { + if (p.X < this.render.TextArea.X) + return tp; + } - tp.col = GetIndexFromColPostion(tp.row, p.X); + relX = p.X - this.render.TextArea.X; + tp.col = this.LayoutLines.GetLayout(tp.row).GetIndexFromPostion(relX,relY); - lineLength = this.LayoutLines.GetLengthFromLineNumber(tp.row); + int lineLength = this.LayoutLines.GetLengthFromLineNumber(tp.row); if (tp.col > lineLength) tp.col = lineLength; @@ -493,34 +565,6 @@ namespace FooEditEngine } /// - /// 桁方向の座標に対応するインデックスを取得する - /// - /// 対象となる行 - /// テキストエリアからの相対位置 - /// - public int GetIndexFromColPostion(int row, double x) - { - x -= this.render.TextArea.X; - int lineLength = this.LayoutLines.GetLengthFromLineNumber(row); - if (lineLength == 0) - return 0; - int index = this.LayoutLines.GetLayout(row).GetIndexFromColPostion(this.Src.X + x); - return index; - } - - /// - /// インデックスに対応する桁方向の座標を得る - /// - /// 対象となる行 - /// インデックス - /// テキストエリアからの相対位置を返す - public double GetColPostionFromIndex(int row, int index) - { - double x = this.LayoutLines.GetLayout(row).GetColPostionFromIndex(index); - return x - Src.X + this.render.TextArea.X; - } - - /// /// TextPointに対応する座標を得る /// /// レイアウトライン上の位置 @@ -536,8 +580,9 @@ namespace FooEditEngine continue; p.Y += this.LayoutLines.GetLayout(i).Height; } - p.X = this.GetColPostionFromIndex(tp.row, tp.col); - p.Y += this.render.TextArea.Y; + Point relP = this.LayoutLines.GetLayout(tp.row).GetPostionFromIndex(tp.col); + p.X += relP.X - Src.X + this.render.TextArea.X; + p.Y += this.render.TextArea.Y + relP.Y; return p; } @@ -558,11 +603,23 @@ namespace FooEditEngine public Rectangle GetRectFromTextPoint(TextPoint tp, int width, int height) { + if (tp.row < this.Src.Row) + return Rectangle.Empty; + //画面外にある時は計算する必要がそもそもない + if (tp.row - this.Src.Row > this.LineCountOnScreen) + return Rectangle.Empty; double radius = width / 2; Point point = this.GetPostionFromTextPoint(tp); - double lineHeight = this.LayoutLines.GetLayout(tp.row).Height; + double lineHeight = this.render.emSize.Height; + double srcOffsetY = this.Src.OffsetY; //画面上ではずれているので引く必要がある + + Rectangle rect = new Rectangle(point.X - radius, point.Y + lineHeight - srcOffsetY, width, height); - return new Rectangle(point.X - radius, point.Y + lineHeight, width, height); + if (rect.BottomLeft.Y >= this.render.TextArea.BottomLeft.Y || + rect.BottomRight.X < this.render.TextArea.BottomLeft.X || + rect.BottomLeft.X > this.render.TextArea.BottomRight.X) + return Rectangle.Empty; + return rect; } /// @@ -587,7 +644,8 @@ namespace FooEditEngine } } - this.Document.CaretPostion = new TextPoint(row, col); + //イベント呼び出しの再入防止のため + this.Document.SetCaretPostionWithoutEvent(new TextPoint(row, col)); } /// @@ -598,17 +656,17 @@ namespace FooEditEngine public bool AdjustSrc(int index) { TextPoint startTextPoint = this.GetLayoutLineFromIndex(index); - double x = this.LayoutLines.GetLayout(startTextPoint.row).GetColPostionFromIndex(startTextPoint.col); - if (x < this.Src.X || - x > this.Src.X + this.PageBound.Width) + Point relP = this.LayoutLines.GetLayout(startTextPoint.row).GetPostionFromIndex(startTextPoint.col); + if (relP.X < this.Src.X || + relP.X > this.Src.X + this.PageBound.Width) { - this.TryScroll(x, this.Src.Row); + this.TryScroll(relP.X, this.Src.Row); return true; } if (startTextPoint.row < this.Src.Row || startTextPoint.row > this.Src.Row + this.LineCountOnScreenWithInVisible) { - this.TryScroll(this.Src.X, startTextPoint.row); + this.TryScroll(this.Src.X, startTextPoint.row, relP.Y); return true; } return false; @@ -633,10 +691,11 @@ namespace FooEditEngine TextPoint tp = this.Document.CaretPostion; double x = this.CaretLocation.X; double y = this.CaretLocation.Y; + Point relPoint = this.LayoutLines.GetLayout(tp.row).GetPostionFromIndex(tp.col); if (flow == AdjustFlow.Col || flow == AdjustFlow.Both) { - x = this.LayoutLines.GetLayout(tp.row).GetColPostionFromIndex(tp.col); + x = relPoint.X; double left = this.Src.X; double right = this.Src.X + this.render.TextArea.Width; @@ -647,11 +706,11 @@ namespace FooEditEngine } else if (x > right) //xは表示領域の右側にある { - this.Document.Src = new SrcPoint(x - this.render.TextArea.Width + this.ScrollMarginWidth,this.Document.Src.Row,this.Document.Src.Y); + this.Document.Src = new SrcPoint(x - this.render.TextArea.Width + this.ScrollMarginWidth,this.Document.Src.Row,this.Document.Src.OffsetY); if (this.Document.RightToLeft && this.Document.Src.X > 0) { System.Diagnostics.Debug.Assert(x > 0); - this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Document.Src.Y); + this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Document.Src.OffsetY); } else { @@ -661,10 +720,10 @@ namespace FooEditEngine } else if (x < left) //xは表示領域の左側にある { - this.Document.Src = new SrcPoint(x - this.ScrollMarginWidth, this.Document.Src.Row, this.Document.Src.Y); + this.Document.Src = new SrcPoint(x - this.ScrollMarginWidth, this.Document.Src.Row, this.Document.Src.OffsetY); if (!this.Document.RightToLeft && this.Document.Src.X < this.render.TextArea.X) { - this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Document.Src.Y); + this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Document.Src.OffsetY); } else { @@ -677,45 +736,46 @@ namespace FooEditEngine if (flow == AdjustFlow.Row || flow == AdjustFlow.Both) { - int caretRow = 0; - int lineCount = this.LineCountOnScreenWithInVisible; - if (tp.row >= this.Src.Row && tp.row < this.Src.Row + lineCount) + int PhyLineCountOnScreen = (int)(this.render.TextArea.Height / this.render.emSize.Height); + //計算量を減らすため + if (tp.row < this.Src.Row || this.Src.Row + PhyLineCountOnScreen * 2 < tp.row) + this.Document.Src = new SrcPoint(this.Src.X, tp.row, -relPoint.Y); + + //キャレットのY座標を求める + double lineHeight = this.render.emSize.Height; + double caret_y = this.Src.OffsetY; //src.rowからキャレット位置 + double alignedHeight = PhyLineCountOnScreen * lineHeight - lineHeight; + for (int i = this.Src.Row; i < tp.row; i++) { - caretRow = tp.row - this.Src.Row; - y = -this.Src.GetOffsetY(this.render.emSize.Height); //画面上ではずれているので引く必要がある + int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i); + int lineLength = this.LayoutLines.GetLengthFromLineNumber(i); + + if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex)) + continue; + caret_y += this.LayoutLines.GetLayout(i).Height; } - else if (tp.row >= this.Src.Row + lineCount) + caret_y += relPoint.Y; + + if (caret_y < 0) { - int srcRow = this.GetSrcRow(tp.row, this.LineCountOnScreen); - this.Document.Src = new SrcPoint(this.Document.Src.X, srcRow, srcRow * this.render.emSize.Height); - caretRow = tp.row - this.Document.Src.Row; + this.Document.Src = new SrcPoint(this.Src.X, tp.row, -relPoint.Y); y = 0; - result = true; - CalculateLineCountOnScreen(); } - else if (tp.row < this.Src.Row) + else if (caret_y >= 0 && caret_y < alignedHeight) { - this.Document.Src = new SrcPoint(this.Document.Src.X, tp.row, tp.row * this.render.emSize.Height); - y = 0; - result = true; - CalculateLineCountOnScreen(); + y = caret_y; } - - if (caretRow > 0) + else if(caret_y >= alignedHeight) { - for (int i = 0; i < caretRow; i++) - { - int currentRow = this.Src.Row + i; - int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(currentRow); - int lineLength = this.LayoutLines.GetLengthFromLineNumber(currentRow); - - if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex)) - continue; - - y += this.LayoutLines.GetLayout(currentRow).Height; - } + var newsrc = this.GetNearstRowAndOffsetY(tp.row, -(alignedHeight - relPoint.Y)); + if(newsrc == null) + this.Document.Src = new SrcPoint(this.Src.X, tp.row, 0); + else + this.Document.Src = new SrcPoint(this.Src.X, newsrc.Item1, -newsrc.Item2); + y = alignedHeight; } y += this.render.TextArea.Y; + result = true; } this.SetCaretPostion(x, y); @@ -728,23 +788,6 @@ namespace FooEditEngine return result; } - int GetSrcRow(int row,int count) - { - if (this.LayoutLines.FoldingStrategy == null) - return row - count; - for (int i = row; i >= 0; i--) - { - int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i); - int lineLength = this.LayoutLines.GetLengthFromLineNumber(i); - if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex)) - continue; - if (count <= 0) - return i; - count--; - } - return 0; - } - /// /// レイアウト行をテキストポイントからインデックスに変換する /// @@ -788,26 +831,6 @@ namespace FooEditEngine } /// - /// 指定した座標までスクロールする - /// - /// - /// - /// - /// 範囲外の座標を指定した場合、範囲内に収まるように調整されます - /// - public void Scroll(double x, double y) - { - if (x < 0) - x = 0; - if (y < 0) - y = 0; - double totalHeight = this.LayoutLines.Count * this.render.emSize.Height; - if (y > totalHeight) - y = totalHeight - this.render.TextArea.Height; - base.TryScroll(x, y); - } - - /// /// 指定行までスクロールする /// /// 行