}
double noti;
+ /// <summary>
+ /// スクロールする
+ /// </summary>
+ /// <param name="dir">方向を指定する</param>
+ /// <param name="delta">ピクセル単位の値でスクロール量を指定する</param>
+ /// <param name="isSelected">選択状態にするなら真</param>
+ /// <param name="withCaret">同時にキャレットを移動させるなら真</param>
public void ScrollByPixel(ScrollDirection dir,int delta, bool isSelected, bool withCaret)
{
if (this.Document.FireUpdateEvent == false)
if (dir == ScrollDirection.Left || dir == ScrollDirection.Right)
{
- this.Scroll(dir, delta, isSelected, withCaret);
+ this.View.TryScroll(delta, 0);
return;
}
noti = 0;
- this.Scroll(dir, delta_row, isSelected, withCaret);
+ this.View.TryScroll(0, delta);
}
+
+ if (withCaret)
+ {
+ //カーソルを適切な位置に移動させる必要がある
+ this.View.AdjustCaretAndSrc();
+ this.SelectWithMoveCaret(isSelected);
+ }
+
+ this.Document.SelectGrippers.BottomLeft.MoveByIndex(this.View, this.SelectionStart);
+ this.Document.SelectGrippers.BottomRight.MoveByIndex(this.View, this.SelectionStart + this.SelectionLength);
}
/// <summary>
if (alignWord)
this.AlignNearestWord(MoveFlow);
}
- this.View.AdjustCaretAndSrc(AdjustFlow.Col);
+ if(this.Document.LayoutLines.WrapWidth == LineToIndexTable.NONE_BREAK_LINE)
+ this.View.AdjustCaretAndSrc(AdjustFlow.Col);
+ else
+ this.View.AdjustCaretAndSrc(AdjustFlow.Both);
this.SelectWithMoveCaret(isSelected);
}
}
/// <summary>
- /// キャレット位置を既定の位置に戻す
- /// </summary>
- public void ResetCaretPostion()
- {
- this.JumpCaret(0);
- }
-
- /// <summary>
/// 行単位で移動後のキャレット位置を取得する
/// </summary>
/// <param name="count">移動量</param>
row = this.View.AdjustRow(row, count > 0);
- double colpos = this.View.GetColPostionFromIndex(current.row, current.col);
- int col = this.View.GetIndexFromColPostion(row, colpos);
+ Point pos = this.View.LayoutLines.GetLayout(current.row).GetPostionFromIndex(current.col);
+ int col = this.View.LayoutLines.GetLayout(row).GetIndexFromPostion(pos.X, pos.Y);
return new TextPoint(row, col);
}
+
+ /// <summary>
+ /// キャレット位置を既定の位置に戻す
+ /// </summary>
+ public void ResetCaretPostion()
+ {
+ this.JumpCaret(0);
+ }
+
/// <summary>
/// 選択文字列のインデントを一つ増やす
/// </summary>
}
}
- public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> SelectRanges)
+ public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> SelectRanges,double WrapWidth)
{
float dpix,dpiy;
this.GetDpi(out dpix,out dpiy);
+ double layoutWidth = this.TextArea.Width;
+ if (WrapWidth != LineToIndexTable.NONE_BREAK_LINE)
+ {
+ this.format.WordWrapping = DW.WordWrapping.Wrap;
+ layoutWidth = WrapWidth;
+ }
+ else
+ {
+ this.format.WordWrapping = DW.WordWrapping.NoWrap;
+ }
+
bool hasNewLine = str.Length > 0 && str[str.Length - 1] == Document.NewLine;
MyTextLayout newLayout = new MyTextLayout(D2DRenderShared.DWFactory,
str,
this.format,
- this.TextArea.Width,
+ layoutWidth,
this.TextArea.Height,
dpiy,
hasNewLine && this._ShowLineBreak);
}
}
+ this.format.WordWrapping = DW.WordWrapping.NoWrap;
+
return newLayout;
}
public int GetIndexFromColPostion(double x)
{
- SharpDX.Mathematics.Interop.RawBool isTrailing, isInsed;
- DW.HitTestMetrics metrics;
- metrics = this.layout.HitTestPoint((float)x, 0, out isTrailing, out isInsed);
- int index;
- if(isTrailing)
- index = metrics.TextPosition + metrics.Length;
- else
- index = metrics.TextPosition;
- if (this.ShowLineBreak && index == this.lineBreakIndex + 1) //改行マークの後ろにヒットしたら
- index--;
- return index;
+ return this.GetIndexFromPostion(x, 0);
}
public double GetWidthFromIndex(int index)
public double GetColPostionFromIndex(int index)
{
+ Point p = this.GetPostionFromIndex(index);
+ return p.X;
+ }
+
+ public int GetIndexFromPostion(double x, double y)
+ {
+ SharpDX.Mathematics.Interop.RawBool isTrailing, isInsed;
+ DW.HitTestMetrics metrics;
+ metrics = this.layout.HitTestPoint((float)x, (float)y, out isTrailing, out isInsed);
+ int index;
+ if (isTrailing)
+ index = metrics.TextPosition + metrics.Length;
+ else
+ index = metrics.TextPosition;
+ if (this.ShowLineBreak && index == this.lineBreakIndex + 1) //改行マークの後ろにヒットしたら
+ index--;
+ return index;
+ }
+
+ public Point GetPostionFromIndex(int index)
+ {
float x, y;
DW.HitTestMetrics metrics;
metrics = this.layout.HitTestTextPosition(index, false, out x, out y);
- return x;
+ return new Point(x,y);
}
public int AlignIndexToNearestCluster(int index, AlignDirection flow)
{
if (!double.IsNaN(this._height))
return this._height;
- this._height = Util.RoundUp(layout.Metrics.Height);
+ this._height = Util.RoundUp(this.layout.Metrics.Height);
return this._height;
}
}
start--;
if (find_sep_func(str[start]))
+ {
start++;
+ }
int end = index;
while (end < this.Length && !find_sep_func(str[end]))
throw new NotImplementedException();
}
- public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> SelectRanges)
+ public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> SelectRanges, double wrapwidth)
{
return new DummyTextLayout();
}
{
this.Disposed = true;
}
+
+ public Point GetPostionFromIndex(int index)
+ {
+ return new Point();
+ }
+
+ public int GetIndexFromPostion(double x, double y)
+ {
+ return 0;
+ }
}
}
this.DrawLineMarker(this.Document.CaretPostion.row);
Point pos = this.render.TextArea.TopLeft;
- //画面上では(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);
//リセットしないと行が正しく描けない
pos = this.render.TextArea.TopLeft;
pos.X -= this.Src.X;
- pos.Y -= this.Src.GetOffsetY(this.render.emSize.Height);
+ pos.Y += this.Src.OffsetY;
this.render.BeginClipRect(this.render.TextArea);
this.render.DrawOneLine(this.Document, this.LayoutLines, i, pos.X, pos.Y);
pos.Y += layout.Height;
- //pos.Y += this.render.emSize.Height;
}
this.render.EndClipRect();
{
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,
int row = this.Document.CaretPostion.row;
ITextLayout layout = this.LayoutLines.GetLayout(row);
- double lineHeight = layout.Height;
+ double lineHeight = render.emSize.Height;
double charWidth = layout.GetWidthFromIndex(this.Document.CaretPostion.col);
if (this.InsertMode || charWidth == 0)
//表示領域から探索を始めるのでパディングの分だけ引く
p.Y -= this.render.TextArea.Y;
- int lineHeadIndex, lineLength;
-
- if(p.Y >= 0)
+ //p.Y に最も近い行を調べる
+ var t = this.GetNearstRowAndOffsetY(this.Src.Row, p.Y);
+ double relX = 0, relY;
+ if (t == null)
{
- double y = 0;
- tp.row = this.LayoutLines.Count - 1;
- for (int i = this.Src.Row; i < this.LayoutLines.Count; i++)
+ if(p.Y > 0)
{
- 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)
- {
- tp.row = i;
- break;
- }
- y += height;
+ tp.row = this.LayoutLines.Count - 1;
+ relY = this.LayoutLines.GetLayout(tp.row).Height - this.render.emSize.Height;
}
- }else{
- double y = 0;
- tp.row = 0;
- for (int i = this.Src.Row; i >= 0; i--)
+ else if(p.Y == 0)
{
- 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)
- {
- tp.row = i;
- break;
- }
- y -= height;
+ tp.row = this.Src.Row;
+ relY = 0;
}
+ else
+ {
+ tp.row = 0;
+ relY = 0;
+ }
+ }
+ else
+ {
+ tp.row = t.Item1;
+ relY = t.Item2; //相対位置がマイナスなので反転させる
}
if (searchRange == TextPointSearchRange.TextAreaOnly)
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;
}
/// <summary>
- /// 桁方向の座標に対応するインデックスを取得する
- /// </summary>
- /// <param name="row">対象となる行</param>
- /// <param name="x">テキストエリアからの相対位置</param>
- /// <returns></returns>
- 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;
- }
-
- /// <summary>
- /// インデックスに対応する桁方向の座標を得る
- /// </summary>
- /// <param name="row">対象となる行</param>
- /// <param name="index">インデックス</param>
- /// <returns>テキストエリアからの相対位置を返す</returns>
- public double GetColPostionFromIndex(int row, int index)
- {
- double x = this.LayoutLines.GetLayout(row).GetColPostionFromIndex(index);
- return x - Src.X + this.render.TextArea.X;
- }
-
- /// <summary>
/// TextPointに対応する座標を得る
/// </summary>
/// <param name="tp">レイアウトライン上の位置</param>
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;
}
return Rectangle.Empty;
double radius = width / 2;
Point point = this.GetPostionFromTextPoint(tp);
- double lineHeight = this.LayoutLines.GetLayout(tp.row).Height;
- double srcOffsetY = this.Src.GetOffsetY(this.render.emSize.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);
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;
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;
}
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
{
}
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
{
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)
+ //計算量を減らすため
+ if (tp.row < this.Src.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 = (int)(this.render.TextArea.Height / this.render.emSize.Height) * this.render.emSize.Height;
+ 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;
- }
+ double caretYFromTextArea = Math.Min(caret_y - alignedHeight, alignedHeight - lineHeight);
+ var newsrc = this.GetNearstRowAndOffsetY(tp.row, -caretYFromTextArea);
+ 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 = caretYFromTextArea;
}
y += this.render.TextArea.Y;
+ result = true;
}
this.SetCaretPostion(x, y);
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;
- }
-
/// <summary>
/// レイアウト行をテキストポイントからインデックスに変換する
/// </summary>
this.LineCountOnScreenWithInVisible = Math.Max(i - this.Src.Row - 1, 0);
}
+ public override void CalculateWhloeViewPort()
+ {
+ double width = 0, height = 0;
+ for(int i = 0; i < this.LayoutLines.Count; i++)
+ {
+ int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
+ int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
+
+ if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex) && i < this.LayoutLines.Count - 1)
+ continue;
+
+ ITextLayout layout = this.LayoutLines.GetLayout(i);
+ if (width > this._LongestWidth)
+ this._LongestWidth = width;
+ height += layout.Height;
+ }
+ }
+
void SetCaretPostion(double x, double y)
{
this.CaretLocation = new Point(x + this.PageBound.X, y + this.PageBound.Y);
/// <param name="syntaxCollection">ハイライト関連の情報を保持しているコレクション</param>
/// <param name="MarkerRanges">マーカーを保持しているコレクション。マーカーの開始位置は行の先頭を0とする相対位置としてください(位置が-1の場合表示しないこと)</param>
/// <param name="Selections">選択領域を保持しているコレクション。マーカーの開始位置は行の先頭を0とする相対位置としてください(位置が-1の場合表示しないこと)</param>
- ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> Selections);
+ /// <param name="WrapWidth">折り返しの幅</param>
+ ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> Selections,double WrapWidth);
/// <summary>
/// グリッパーを描く
double GetColPostionFromIndex(int index);
/// <summary>
+ /// 座標に対応するインデックスを取得する
+ /// </summary>
+ /// <param name="x">桁方向の座標</param>
+ /// <param name="y">行方向の座標</param>
+ /// <returns>インデックス</returns>
+ /// <remarks>行番号の幅は考慮されてないのでView以外のクラスは呼び出さないでください</remarks>
+ int GetIndexFromPostion(double x, double y);
+
+ /// <summary>
+ /// インデックスに対応する座標を得る
+ /// </summary>
+ /// <param name="index">インデックス</param>
+ /// <returns>行方向と桁方向の相対座標</returns>
+ /// <remarks>行頭にEOFが含まれている場合、0が返ります</remarks>
+ Point GetPostionFromIndex(int index);
+
+ /// <summary>
/// 適切な位置にインデックスを調整する
/// </summary>
/// <param name="index">インデックス</param>
this.Document.Markers.Updated += Markers_Updated;
this._generators[FOLDING_INDEX] = new FoldingGenerator();
this._generators[SYNTAX_HIGLITHER_INDEX] = new SyntaxHilightGenerator();
+ this.WrapWidth = NONE_BREAK_LINE;
#if DEBUG && !NETFX_CORE
if (!Debugger.IsAttached)
{
}
/// <summary>
+ /// ピクセル単位で折り返すかどうか
+ /// </summary>
+ public double WrapWidth
+ {
+ get;
+ set;
+ }
+
+ /// <summary>
+ /// 行を折り返さないことを表す
+ /// </summary>
+ public const double NONE_BREAK_LINE = -1;
+
+ /// <summary>
/// 保持しているレイアウトキャッシュをクリアーする
/// </summary>
public void ClearLayoutCache()
LineToIndexTableData lineData = this.Lines[row];
if (lineData.Length == 0)
{
- layout = this.render.CreateLaytout("", null, null, null);
+ layout = this.render.CreateLaytout("", null, null, null,this.WrapWidth);
}
else
{
let n = Util.ConvertAbsIndexToRelIndex(s, lineHeadIndex, lineData.Length)
select n;
- layout = this.render.CreateLaytout(content, lineData.Syntax, markerRange, selectRange);
+ layout = this.render.CreateLaytout(content, lineData.Syntax, markerRange, selectRange,this.WrapWidth);
}
return layout;
this.Hilighter.Reset();
Point pos = this.render.TextArea.TopLeft;
- pos.X -= Src.X;
-
- int endRow = Math.Min(this.LayoutLines.Count - 1, Src.Row + this.LineCountOnScreen - 1);
-
- Size lineNumberSize = new Size(this.render.LineNemberWidth, this.render.TextArea.Height);
+ pos.X = Src.X;
+ pos.Y = 0;
IPrintableTextRender render = (IPrintableTextRender)this.render;
if (this.Header != null && this.Header != string.Empty)
{
this.render.DrawString(this.Header, pos.X, pos.Y, StringAlignment.Center,
- new Size(render.TextArea.Width - this.GetRealtiveX(AreaType.TextArea),render.FooterHeight));
-
+ new Size(render.TextArea.Width - this.GetRealtiveX(AreaType.TextArea), render.FooterHeight));
pos.Y += (int)render.HeaderHeight;
}
//レイアウト行を印刷する
- for (int i = Src.Row; i <= endRow; i++)
+ Rectangle contentArea = new Rectangle(pos.X, pos.Y, this.PageBound.Width, this.render.TextArea.Height);
+ this.render.BeginClipRect(contentArea);
+
+ Size lineNumberSize = new Size(this.render.LineNemberWidth, this.render.TextArea.Height);
+ for (int i = Src.Row; pos.Y <= this.render.TextArea.Bottom; i++)
{
- double lineHeight = this.LayoutLines.GetLayout(i).Height;
+ if (i >= this.LayoutLines.Count)
+ break;
- this.render.DrawOneLine(this.Document, this.LayoutLines,i, pos.X + this.render.TextArea.X, pos.Y);
+ double layoutHeight = this.LayoutLines.GetLayout(i).Height;
+ this.render.DrawOneLine(this.Document, this.LayoutLines, i, pos.X + this.render.TextArea.X, pos.Y + this.Src.OffsetY);
if (this.Document.DrawLineNumber)
- this.render.DrawString((i + 1).ToString(), this.PageBound.X + this.GetRealtiveX(AreaType.LineNumberArea), pos.Y, StringAlignment.Right, lineNumberSize);
+ this.render.DrawString((i + 1).ToString(), this.PageBound.X + this.GetRealtiveX(AreaType.LineNumberArea), pos.Y + this.Src.OffsetY, StringAlignment.Right, lineNumberSize);
+
+ pos.Y += layoutHeight;
- pos.Y += lineHeight;
}
+ this.render.EndClipRect();
+
//フッターを印刷する
if (this.Footer != null && this.Footer != string.Empty)
{
public bool TryPageDown()
{
- return base.TryScroll(this.Src.X, this.Src.Row + this.LineCountOnScreen);
+ double alignedPage = (int)(this.render.TextArea.Height / this.render.emSize.Height) * this.render.emSize.Height;
+ return base.TryScroll(this.Src.X, alignedPage);
}
protected override void CalculateClipRect()
public override void CalculateLineCountOnScreen()
{
- if (this.LayoutLines.Count == 0)
- return;
-
- double y = 0;
- int i = this.Src.Row;
- for (; true; i++)
- {
- int row = i < this.LayoutLines.Count ? i : this.LayoutLines.Count - 1;
-
- ITextLayout layout = this.LayoutLines.GetLayout(row);
-
- double lineHeight = layout.Height;
-
- y += lineHeight;
-
- if (y >= this.render.TextArea.Height)
- break;
- }
- this.LineCountOnScreen = Math.Max(i - this.Src.Row - 1, 0); //ループを抜けると+1されている
}
enum AreaType
{
public double X;
public int Row;
- public double Y;
- public double GetOffsetY(double line_height)
- {
- return this.Row * line_height - this.Y;
- }
+ public double OffsetY;
public SrcPoint(double x, int row, double y)
{
if (row < 0)
throw new ArgumentOutOfRangeException("マイナスを値を指定することはできません");
this.X = x;
this.Row = row;
- this.Y = y;
+ this.OffsetY = y;
}
}
endTextPoint = view.GetLayoutLineFromIndex(endIndex);
endPos = view.GetPostionFromTextPoint(endTextPoint);
//アンダーラインを描くことがあるので少しずらす
- endPos.Y += view.LayoutLines.GetLayout(endTextPoint.row).Height + 5;
+ endPos.Y += view.render.emSize.Height + 5;
}
public static void GetSelection(Controller controller, SelectCollection selectons, out TextRange sel)
Document _Document;
protected Rectangle _Rect;
- protected double _LongestWidth;
+ protected double _LongestWidth,_LongestHeight;
Padding _Padding;
public ViewBase(Document doc, ITextRender r,Padding padding)
private void _Document_PerformLayouted(object sender, EventArgs e)
{
+ CalculateWhloeViewPort();
CalculateLineCountOnScreen();
if(this.PerformLayouted != null)
this.PerformLayouted(this, e);
this.render.ShowTab = this.Document.ShowTab;
if (this.render.ShowLineBreak != this.Document.ShowLineBreak)
this.render.ShowLineBreak = this.Document.ShowLineBreak;
+ CalculateWhloeViewPort();
CalculateClipRect();
CalculateLineCountOnScreen();
this._LayoutLines.ClearLayoutCache();
private void Document_LineBreakChanged(object sender, EventArgs e)
{
- if (this.Document.LineBreak != LineBreakMethod.None)
- this._LayoutLines.SpilitString = new SpilitStringEventHandler(LayoutLines_SpilitStringByPixelbase);
+ if (this.Document.LineBreak == LineBreakMethod.PageBound)
+ this._LayoutLines.WrapWidth = this.render.TextArea.Width - LineBreakingMarginWidth; //余白を残さないと欠ける
+ else if (this.Document.LineBreak == LineBreakMethod.CharUnit)
+ this._LayoutLines.WrapWidth = this.render.emSize.Width * this.Document.LineBreakCharCount;
else
- this._LayoutLines.SpilitString = new SpilitStringEventHandler(LayoutLines_SpilitStringByChar);
+ this._LayoutLines.WrapWidth = LineToIndexTable.NONE_BREAK_LINE;
+
+ this._LayoutLines.ClearLayoutCache();
}
protected LineToIndexTable _LayoutLines
get;
protected set;
}
-
+
/// <summary>
/// 折り返し時の右マージン
/// </summary>
get { return this._LongestWidth; }
}
+ public double LongestHeight
+ {
+ get { return this._LongestHeight; }
+ }
+
public double LineNumberMargin
{
get
return;
}
- public virtual bool TryScroll(double x, int row)
+ /// <summary>
+ /// スクロールを試行する
+ /// </summary>
+ /// <param name="x">X座標</param>
+ /// <param name="row">行</param>
+ /// <param name="rel_y">各行の左上を0とするY座標</param>
+ /// <returns>成功すれば偽、そうでなければ真</returns>
+ public virtual bool TryScroll(double x, int row,double rel_y = 0)
{
if (row < 0)
return true;
if (row > this.LayoutLines.Count - 1)
return true;
- this.Document.Src = new SrcPoint(x, row, row * this.render.emSize.Height);
+ double abs_y = 0;
+ for (int i = 0; i < row; i++)
+ abs_y += this.LayoutLines.GetLayout(i).Height;
+ this.Document.Src = new SrcPoint(x, row, rel_y);
this.SrcChanged(this,null);
return false;
}
+ /// <summary>
+ /// スクロールを試行する
+ /// </summary>
+ /// <param name="offset_x">X方向の移動量</param>
+ /// <param name="offset_y">Y方向の移動量</param>
+ /// <returns>成功すれば偽、そうでなければ真</returns>
+ public virtual bool TryScroll(double offset_x,double offset_y)
+ {
+ double x = this.Document.Src.X - offset_x;
+ if (x < 0)
+ return true;
+ var t = GetNearstRowAndOffsetY(this.Document.Src.Row, -this.Document.Src.OffsetY + offset_y);
+ if (t == null)
+ return true;
+ this.Document.Src = new SrcPoint(x, t.Item1, -t.Item2);
+ return false;
+ }
+
+ /// <summary>
+ /// srcRowを起点としてrect_heightが収まる行とオフセットYを求めます
+ /// </summary>
+ /// <param name="srcRow">起点となる行</param>
+ /// <param name="rect_hight">Y方向のバウンディングボックス</param>
+ /// <returns>失敗した場合、NULL。成功した場合、行とオフセットY</returns>
+ public Tuple<int,double> GetNearstRowAndOffsetY(int srcRow, double rect_hight)
+ {
+ if (rect_hight > 0)
+ {
+ for (int i = srcRow; i < this.Document.LayoutLines.Count; i++)
+ {
+ ITextLayout layout = this.Document.LayoutLines.GetLayout(i);
+
+ int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
+ int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
+ double layoutHeight = layout.Height;
+
+ if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
+ continue;
+
+ if (rect_hight == 0)
+ return new Tuple<int, double>(i, 0);
+
+ if (rect_hight - layoutHeight < 0)
+ return new Tuple<int, double>(i, rect_hight);
+
+ rect_hight -= layoutHeight;
+ }
+ }
+ else if(rect_hight < 0)
+ {
+ for (int i = srcRow - 1; i >= 0; i--)
+ {
+ ITextLayout layout = this.Document.LayoutLines.GetLayout(i);
+
+ int lineHeadIndex = this.LayoutLines.GetIndexFromLineNumber(i);
+ int lineLength = this.LayoutLines.GetLengthFromLineNumber(i);
+ double layoutHeight = layout.Height;
+
+ if (this.LayoutLines.FoldingCollection.IsHidden(lineHeadIndex))
+ continue;
+
+ if(rect_hight == 0)
+ return new Tuple<int, double>(i, 0);
+
+ if (rect_hight + layoutHeight >= 0)
+ return new Tuple<int, double>(i, layoutHeight + rect_hight);
+
+ rect_hight += layoutHeight;
+ }
+ return new Tuple<int, double>(0, 0);
+ }
+ return null;
+ }
+
public void Dispose()
{
this.Dispose(true);
{
}
+ public virtual void CalculateWhloeViewPort()
+ {
+ }
+
protected virtual void Dispose(bool disposing)
{
if (disposing)
void render_ChangedRightToLeft(object sender, EventArgs e)
{
- this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Src.Y);
+ this.Document.Src = new SrcPoint(0, this.Document.Src.Row, this.Src.OffsetY);
}
void render_ChangedRenderResource(object sender, ChangedRenderRsourceEventArgs e)
{
this.CalculateClipRect();
this.CalculateLineCountOnScreen();
+ this.CalculateWhloeViewPort();
}
}
}
}
- IList<LineToIndexTableData> LayoutLines_SpilitStringByPixelbase(object sender, SpilitStringEventArgs e)
- {
- double WrapWidth;
- if (this.Document.LineBreak == LineBreakMethod.PageBound)
- WrapWidth = this.render.TextArea.Width - LineBreakingMarginWidth; //余白を残さないと欠ける
- else
- WrapWidth = this.render.emSize.Width * this.Document.LineBreakCharCount;
-
- if (WrapWidth < 0 && this.Document.LineBreak != LineBreakMethod.None)
- throw new InvalidOperationException();
-
- int startIndex = e.index;
- int endIndex = e.index + e.length - 1;
-
- LineToIndexTable layoutLineCollection = (LineToIndexTable)sender;
-
- return this.render.BreakLine(e.buffer,layoutLineCollection, startIndex, endIndex, WrapWidth);
- }
-
IList<LineToIndexTableData> LayoutLines_SpilitStringByChar(object sender, SpilitStringEventArgs e)
{
return this.Document.CreateLineList(e.index, e.length, Document.MaximumLineLength);
this.verticalScrollBar = this.GetTemplateChild("PART_VerticalScrollBar") as ScrollBar;
if (this.verticalScrollBar != null)
{
- this.verticalScrollBar.SmallChange = 1;
- this.verticalScrollBar.LargeChange = 10;
- this.verticalScrollBar.Maximum = this.View.LayoutLines.Count;
+ this.verticalScrollBar.SmallChange = this.View.render.emSize.Height;
+ this.verticalScrollBar.LargeChange = this.View.render.emSize.Height * 10;
+ this.verticalScrollBar.Maximum = this.View.LongestHeight;
this.verticalScrollBar.Scroll += new ScrollEventHandler(verticalScrollBar_Scroll);
}
}
TextStoreHelper.NotifyTextChanged(this.textStore, 0, 0, this.Document.Length);
if (this.verticalScrollBar != null)
this.verticalScrollBar.Maximum = this.View.LayoutLines.Count;
+ this.View.CalculateWhloeViewPort();
this.View.CalculateLineCountOnScreen();
this.IsEnabled = true;
this.Refresh(this.View.PageBound);
toX = this.horizontalScrollBar.Value;
else
toX = -this.horizontalScrollBar.Value;
- this._Controller.Scroll(toX, this.View.Src.Row, false, false);
+ this.Controller.ScrollByPixel(ScrollDirection.Left, (int)toX, false, false);
this.Refresh();
}
+ double oldScrollValueY = 0;
void verticalScrollBar_Scroll(object sender, ScrollEventArgs e)
{
if (this.verticalScrollBar == null)
return;
- int newRow = (int)this.verticalScrollBar.Value;
- if (newRow >= this.View.LayoutLines.Count)
- return;
- this._Controller.Scroll(this.View.Src.X,newRow, false, false);
+ double delta = e.NewValue - oldScrollValueY;
+ oldScrollValueY = e.NewValue;
+ this.Controller.ScrollByPixel(ScrollDirection.Up, (int)delta, false, false);
this.Refresh();
}
return;
EditView view = this.View;
if (view.Src.Row > this.verticalScrollBar.Maximum)
- this.verticalScrollBar.Maximum = view.Src.Row + view.LineCountOnScreen + 1;
+ this.verticalScrollBar.Maximum += this.View.render.emSize.Height * 100 + 1;
double absoulteX = Math.Abs(view.Src.X);
if(absoulteX > this.horizontalScrollBar.Maximum)
this.horizontalScrollBar.Maximum = absoulteX + view.PageBound.Width + 1;
this._Document.AutoComplete.GetPostion = (tp, edoc) =>
{
var p = this.View.GetPostionFromTextPoint(tp);
- int height = (int)doc.LayoutLines.GetLayout(edoc.CaretPostion.row).Height;
+ int height = (int)this.Render.emSize.Height;
p.Y += height;
return PointToScreen(this.TranslatePoint(p.Scale(Util.GetScale()), this));
};
}
}
- this.lines[0].Draw(dc, new System.Windows.Point(x, y), InvertAxes.None);
+ double posY = y;
+ foreach(var line in this.lines)
+ {
+ line.Draw(dc, new System.Windows.Point(x, posY), InvertAxes.None);
+ posY += line.Height;
+ }
}
public void Dispose()
}
}
+ double _actualWidth = 0;
public double Width
{
- get { return this.Lines[0].Width; }
+ get
+ {
+ if (_actualWidth != 0)
+ return _actualWidth;
+ foreach (var line in this.Lines)
+ {
+ if(line.Width > _actualWidth)
+ _actualWidth = line.Width;
+ }
+ return _actualWidth;
+ }
}
+ double _height = 0;
public double Height
{
- get { return this.Lines[0].Height; }
+ get {
+ if (_height != 0)
+ return _height;
+ foreach (var line in this.Lines)
+ _height += line.Height;
+ return _height;
+ }
}
public int GetIndexFromColPostion(double x)
return this.Lines[0].GetDistanceFromCharacterHit(new CharacterHit(index, 0));
}
+ public int GetIndexFromPostion(double x, double y)
+ {
+ return 0;
+ }
+
+ public Point GetPostionFromIndex(int index)
+ {
+ throw new NotImplementedException();
+ }
+
public int AlignIndexToNearestCluster(int index, AlignDirection flow)
{
CharacterHit hit = this.Lines[0].GetNextCaretCharacterHit(new CharacterHit(index, 0));
public void BeginClipRect(Rectangle rect)
{
+ this.Context.PushClip(new RectangleGeometry(rect));
}
public void EndClipRect()
{
+ this.Context.Pop();
}
public List<LineToIndexTableData> BreakLine(Document doc, LineToIndexTable layoutLineCollection, int startIndex, int endIndex, double wrapwidth)
return output;
}
- public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> SelectRanges)
+ public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> SelectRanges, double wrapwidth)
{
- TextLayout layout = new TextLayout(str,this.FontFamily,this.FontSize,Brushes[this.Foreground],this.TextArea.Width);
- layout.TextWarpping = TextWrapping.NoWrap;
+ TextLayout layout;
+ if(wrapwidth == LineToIndexTable.NONE_BREAK_LINE)
+ {
+ layout = new TextLayout(str, this.FontFamily, this.FontSize, Brushes[this.Foreground], this.TextArea.Width);
+ layout.TextWarpping = TextWrapping.NoWrap;
+ }
+ else
+ {
+ layout = new TextLayout(str, this.FontFamily, this.FontSize, Brushes[this.Foreground], wrapwidth);
+ layout.TextWarpping = TextWrapping.Wrap;
+ }
layout.FlowDirection = this.RightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
if (syntaxCollection != null)
{
class PrintableTextLayout : ITextLayout
{
- public PrintableTextLayout(Font font)
+ List<String> lines = new List<string>();
+ Font font;
+ StringFormat sf;
+ public PrintableTextLayout(Font font, Graphics g, StringFormat sf, double maxwidth,String str)
{
this.Disposed = false;
+ this.sf = sf;
+ this.font = font;
this.Height = font.Height;
+
+ if (maxwidth == LineToIndexTable.NONE_BREAK_LINE)
+ {
+ lines.Add(str);
+ return;
+ }
+
+ int fitlen, index = 0;
+ do
+ {
+ int linesFilled;
+ SizeF metrics = g.MeasureString(str.Substring(index), font, new SizeF((float)maxwidth, font.Height + 1), sf, out fitlen, out linesFilled);
+ if (metrics.Width > Width)
+ this.Width = metrics.Width;
+ this.Height += metrics.Height;
+ lines.Add(str.Substring(index, fitlen));
+ index += fitlen;
+ } while (index < str.Length);
}
public double Width
{
- get { return 0; }
+ get;
+ private set;
}
public double Height
{
this.Disposed = true;
}
+
+ public int GetIndexFromPostion(double x, double y)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Point GetPostionFromIndex(int index)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Draw(Graphics g,double x, double y,System.Drawing.Color fore)
+ {
+ double posy = y;
+ foreach(string line in this.lines)
+ {
+ g.DrawString(line, this.font, new SolidBrush(fore), new PointF((float)x, (float)posy), this.sf);
+ var size = g.MeasureString(line,this.font);
+ posy += size.Height;
+ }
+ }
}
class PrintableTextRender : IPrintableTextRender
{
public ITextLayout CreateLaytout(string str)
{
- return new PrintableTextLayout(this.font);
+ return new PrintableTextLayout(this.font,this.g,this.sf,(float)LineToIndexTable.NONE_BREAK_LINE ,str);
}
public float HeaderHeight { get { return this.font.Height; } }
{
get
{
- return new Size(0, 0);
+ SizeF metrics = g.MeasureString("0", this.font, Int16.MaxValue, this.sf);
+ return new Size(metrics.Width, metrics.Height);
}
}
}
public void DrawOneLine(Document doc,LineToIndexTable lti, int row, double x, double y)
- {
- g.DrawString(lti[row], this.font, new SolidBrush(this.Foreground), new RectangleF((float)x, (float)y, (float)this.TextArea.Width, (float)this.TextArea.Height), this.sf);
+ {
+ PrintableTextLayout layout = (PrintableTextLayout)lti.GetLayout(row);
+ layout.Draw(g, x, y, this.Foreground);
}
public void BeginClipRect(Rectangle rect)
{
+ g.Clip = new Region(rect);
}
public void EndClipRect()
{
+ g.Clip = new Region();
}
public void FillRectangle(Rectangle rect, FillRectType type)
{
}
- public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> Selections)
- {
- return new PrintableTextLayout(this.font);
- }
-
public List<LineToIndexTableData> BreakLine(Document doc, LineToIndexTable layoutLineCollection, int startIndex, int endIndex, double maxwidth)
{
List<LineToIndexTableData> output = new List<LineToIndexTableData>();
throw new NotImplementedException();
}
+ public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> Selections, double WrapWidth)
+ {
+ return new PrintableTextLayout(this.font, this.g, this.sf, WrapWidth, str);
+ }
+
public System.Drawing.Color Foreground
{
get;
this.fooTextBox1.ShowTab = true;
this.fooTextBox1.ShowFullSpace = true;
this.fooTextBox1.ShowLineBreak = true;
+ this.fooTextBox1.LineBreakMethod = LineBreakMethod.CharUnit;
+ this.fooTextBox1.LineBreakCharCount = 10;
var collection = new CompleteCollection<ICompleteItem>();
collection.Add(new CompleteWord("int"));
collection.Add(new CompleteWord("float"));