OSDN Git Service

スクロールをピクセル単位で行うようにした
[fooeditengine/FooEditEngine.git] / Core / Controller.cs
index fb5f39f..4e5949b 100644 (file)
@@ -20,10 +20,27 @@ using System.Drawing;
 
 namespace FooEditEngine
 {
-    internal enum MoveFlow
+    /// <summary>
+    /// 移動量の単位を表す
+    /// </summary>
+    public enum MoveFlow
     {
-        Horizontical,
-        Vertical,
+        /// <summary>
+        /// 文字
+        /// </summary>
+        Character,
+        /// <summary>
+        /// 単語単位
+        /// </summary>
+        Word,
+        /// <summary>
+        /// 行単位
+        /// </summary>
+        Line,
+        /// <summary>
+        /// パラグラフ単位
+        /// </summary>
+        Paragraph
     }
     internal enum ScrollDirection
     {
@@ -405,31 +422,44 @@ namespace FooEditEngine
             this.SelectWithMoveCaret(isSelected);
         }
 
-        double noti;
-        public void ScrollByPixel(ScrollDirection dir,int delta, bool isSelected, bool withCaret)
+        /// <summary>
+        /// スクロールする
+        /// </summary>
+        /// <param name="dir">方向を指定する</param>
+        /// <param name="delta">ピクセル単位の値でスクロール量を指定する</param>
+        /// <param name="isSelected">選択状態にするなら真</param>
+        /// <param name="withCaret">同時にキャレットを移動させるなら真</param>
+        public void ScrollByPixel(ScrollDirection dir,double delta, bool isSelected, bool withCaret)
         {
             if (this.Document.FireUpdateEvent == false)
                 throw new InvalidOperationException("");
 
             if (dir == ScrollDirection.Left || dir == ScrollDirection.Right)
             {
-                this.Scroll(dir, delta, isSelected, withCaret);
+                this.View.TryScroll(delta, 0);
                 return;
             }
 
-            if(dir == ScrollDirection.Up || dir == ScrollDirection.Down)
+            if(dir == ScrollDirection.Up)
             {
-                noti += delta;
-
-                if (noti < this.View.render.emSize.Height)
-                    return;
-
-                int delta_row = (int)(noti / this.View.render.emSize.Height + 1.0);
-
-                noti = 0;
+                this.View.TryScroll(0, -delta);
+            }
+            else if (dir == ScrollDirection.Down)
+            {
+                this.View.TryScroll(0, delta);
+            }
 
-                this.Scroll(dir, delta_row, isSelected, withCaret);
+            if (withCaret)
+            {
+                //カーソルを適切な位置に移動させる必要がある
+                TextPoint tp = this.View.GetTextPointFromPostion(this.View.CaretLocation);
+                this.View.JumpCaret(tp.row, tp.col);
+                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>
@@ -501,38 +531,71 @@ namespace FooEditEngine
         /// <param name="alignWord">単語単位で移動するなら真。そうでないなら偽</param>
         public void MoveCaretHorizontical(int realLength, bool isSelected,bool alignWord = false)
         {
-            for (int i = Math.Abs(realLength); i > 0; i--)
-            {
-                bool MoveFlow = realLength > 0;
-                if (this.Document.RightToLeft)
-                    MoveFlow = !MoveFlow;
-                this.MoveCaretHorizontical(MoveFlow);
+            TextPoint caret = this.Document.CaretPostion;
+            int moved;
+            caret = GetNextCaret(caret, realLength, alignWord ? MoveFlow.Word : MoveFlow.Character,out moved);
+            this.View.JumpCaret(caret.row, caret.col, false);
+            this.View.AdjustCaretAndSrc(AdjustFlow.Both);
+            this.SelectWithMoveCaret(isSelected);
+        }
 
-                if (alignWord)
-                    this.AlignNearestWord(MoveFlow);
+        /// <summary>
+        /// 移動後のキャレット位置を求める
+        /// </summary>
+        /// <param name="caret">起点となるキャレット位置</param>
+        /// <param name="count">移動量</param>
+        /// <param name="method">移動方法</param>
+        /// <param name="moved">実際に移動した量</param>
+        /// <returns>移動後のキャレット位置</returns>
+        public TextPoint GetNextCaret(TextPoint caret, int count,MoveFlow method,out int moved)
+        {
+            moved = 0;
+            if(method == MoveFlow.Character || method == MoveFlow.Word)
+            {
+                for (int i = Math.Abs(count); i > 0; i--)
+                {
+                    bool moveFlow = count > 0;
+                    if (this.Document.RightToLeft)
+                        moveFlow = !moveFlow;
+                    caret = this.MoveCaretHorizontical(caret, moveFlow);
+
+                    if (method == FooEditEngine.MoveFlow.Word)
+                        caret = this.AlignNearestWord(caret, moveFlow);
+                    moved++;
+                }
             }
-            this.View.AdjustCaretAndSrc(AdjustFlow.Col);
-            this.SelectWithMoveCaret(isSelected);
+            if(method == MoveFlow.Line || method == MoveFlow.Paragraph)
+            {
+                for (int i = Math.Abs(count); i > 0; i--)
+                {
+                    caret = this.MoveCaretVertical(caret, count > 0, method == MoveFlow.Paragraph);
+                    moved++;
+                }
+            }
+            if (count < 0)
+                moved = -moved;
+            return caret;
         }
 
-        void AlignNearestWord(bool MoveFlow)
+        TextPoint AlignNearestWord(TextPoint caret,bool MoveFlow)
         {
-            string str = this.View.LayoutLines[this.Document.CaretPostion.row];
-            while (this.Document.CaretPostion.col > 0 &&
-                this.Document.CaretPostion.col < str.Length &&
-                str[this.Document.CaretPostion.col] != Document.NewLine)
+            string str = this.View.LayoutLines[caret.row];
+            while (caret.col > 0 &&
+                caret.col < str.Length &&
+                str[caret.col] != Document.NewLine)
             {
-                if (!Util.IsWordSeparator(str[this.Document.CaretPostion.col]))
+                if (!Util.IsWordSeparator(str[caret.col]))
                 {
-                    this.MoveCaretHorizontical(MoveFlow);
+                    caret = this.MoveCaretHorizontical(caret, MoveFlow);
                 }
                 else
                 {
                     if(MoveFlow)
-                        this.MoveCaretHorizontical(MoveFlow);
+                        caret = this.MoveCaretHorizontical(caret, MoveFlow);
                     break;
                 }
             }
+            return caret;
         }
 
         /// <summary>
@@ -543,8 +606,10 @@ namespace FooEditEngine
         /// <param name="isSelected"></param>
         public void MoveCaretVertical(int deltarow,bool isSelected)
         {
-            for (int i = Math.Abs(deltarow); i > 0; i--)
-                this.MoveCaretVertical(deltarow > 0);
+            TextPoint caret = this.Document.CaretPostion;
+            int moved;
+            caret = this.GetNextCaret(caret, deltarow, MoveFlow.Line,out moved);
+            this.View.JumpCaret(caret.row, caret.col, true);
             this.View.AdjustCaretAndSrc(AdjustFlow.Both);
             this.SelectWithMoveCaret(isSelected);
         }
@@ -827,34 +892,48 @@ namespace FooEditEngine
         }
 
         /// <summary>
-        /// キャレット位置を既定の位置に戻す
-        /// </summary>
-        public void ResetCaretPostion()
-        {
-            this.JumpCaret(0);
-        }
-
-        /// <summary>
         /// 行単位で移動後のキャレット位置を取得する
         /// </summary>
         /// <param name="count">移動量</param>
         /// <param name="current">現在のキャレット位置</param>
+        /// <param name="move_pargraph">パラグラフ単位で移動するなら真</param>
         /// <returns>移動後のキャレット位置</returns>
-        public TextPoint GetTextPointAfterMoveLine(int count, TextPoint current)
+        public TextPoint GetTextPointAfterMoveLine(int count, TextPoint current, bool move_pargraph = false)
         {
-            int row = current.row + count;
+            if(this.Document.LineBreak == LineBreakMethod.None || move_pargraph == true)
+            {
+                int row = current.row + count;
 
-            if (row < 0)
-                row = 0;
-            else if (row >= this.View.LayoutLines.Count)
-                row = this.View.LayoutLines.Count - 1;
+                if (row < 0)
+                    row = 0;
+                else if (row >= this.View.LayoutLines.Count)
+                    row = this.View.LayoutLines.Count - 1;
+
+                row = this.View.AdjustRow(row, count > 0);
 
-            row = this.View.AdjustRow(row, count > 0);
+                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);
+            }
+            else
+            {
+                Point pos = this.View.GetPostionFromTextPoint(current);
+                pos.Y += this.View.render.emSize.Height * count;
+                //この値を足さないとうまく動作しない
+                pos.Y += this.View.render.emSize.Height / 2;   
+                var new_tp = this.View.GetTextPointFromPostion(pos,TextPointSearchRange.Full);
+                return new_tp;
+
+            }
+        }
 
-            double colpos = this.View.GetColPostionFromIndex(current.row, current.col);
-            int col = this.View.GetIndexFromColPostion(row, colpos);
 
-            return new TextPoint(row, col);
+        /// <summary>
+        /// キャレット位置を既定の位置に戻す
+        /// </summary>
+        public void ResetCaretPostion()
+        {
+            this.JumpCaret(0);
         }
 
         /// <summary>
@@ -916,58 +995,56 @@ namespace FooEditEngine
         /// <summary>
         /// キャレットを一文字移動させる
         /// </summary>
+        /// <param name="caret">キャレット</param>
         /// <param name="isMoveNext">真なら1文字すすめ、そうでなければ戻す</param>
         /// <remarks>このメソッドを呼び出した後でScrollToCaretメソッドとSelectWithMoveCaretメソッドを呼び出す必要があります</remarks>
-        void MoveCaretHorizontical(bool isMoveNext)
+        TextPoint MoveCaretHorizontical(TextPoint caret,bool isMoveNext)
         {
             if (this.Document.FireUpdateEvent == false)
                 throw new InvalidOperationException("");
             int delta = isMoveNext ? 0 : -1;
-            int prevcol = this.Document.CaretPostion.col;
-            int col = this.Document.CaretPostion.col + delta;
-            string lineString = this.View.LayoutLines[this.Document.CaretPostion.row];
-            if (col < 0 || this.Document.CaretPostion.row >= this.View.LayoutLines.Count)
+            int prevcol = caret.col;
+            int col = caret.col + delta;
+            string lineString = this.View.LayoutLines[caret.row];
+            if (col < 0 || caret.row >= this.View.LayoutLines.Count)
             {
-                if (this.Document.CaretPostion.row == 0)
+                if (caret.row == 0)
                 {
-                    col = 0;
-                    return;
+                    caret.col = 0;
+                    return caret;
                 }
-                this.MoveCaretVertical(false);
-                this.View.AdjustCaretAndSrc(AdjustFlow.Row);  //この段階で調整しないとスクロールされない
-                col = this.View.LayoutLines.GetLengthFromLineNumber(this.Document.CaretPostion.row) - 1;  //最終行以外はすべて改行コードが付くはず
+                caret = this.MoveCaretVertical(caret,false);
+                caret.col = this.View.LayoutLines.GetLengthFromLineNumber(caret.row) - 1;  //最終行以外はすべて改行コードが付くはず
             }
             else if (col >= lineString.Length || lineString[col] == Document.NewLine)
             {
-                if (this.Document.CaretPostion.row < this.View.LayoutLines.Count - 1)
+                if (caret.row < this.View.LayoutLines.Count - 1)
                 {
-                    this.MoveCaretVertical(true);
-                    this.View.AdjustCaretAndSrc(AdjustFlow.Row);  //この段階で調整しないとスクロールされない
-                    col = 0;
+                    caret = this.MoveCaretVertical(caret, true);
+                    caret.col = 0;
                 }
             }
             else
             {
                 AlignDirection direction = isMoveNext ? AlignDirection.Forward : AlignDirection.Back;
-                col = this.View.LayoutLines.GetLayout(this.Document.CaretPostion.row).AlignIndexToNearestCluster(col, direction);
+                caret.col = this.View.LayoutLines.GetLayout(caret.row).AlignIndexToNearestCluster(col, direction);
             }
-
-            this.View.JumpCaret(this.Document.CaretPostion.row, col,false);
+            return caret;
         }
 
         /// <summary>
         /// キャレットを行方向に移動させる
         /// </summary>
+        /// <param name="caret">計算の起点となるテキストポイント</param>
         /// <param name="isMoveNext">プラス方向に移動するなら真</param>
+        /// <param name="move_pargraph">パラグラフ単位で移動するするなら真</param>
         /// <remarks>このメソッドを呼び出した後でScrollToCaretメソッドとSelectWithMoveCaretメソッドを呼び出す必要があります</remarks>
-        void MoveCaretVertical(bool isMoveNext)
+        TextPoint MoveCaretVertical(TextPoint caret,bool isMoveNext, bool move_pargraph = false)
         {
             if (this.Document.FireUpdateEvent == false)
                 throw new InvalidOperationException("");
 
-            TextPoint nextPoint = this.GetTextPointAfterMoveLine(isMoveNext ? 1 : -1, this.Document.CaretPostion);
-
-            this.View.JumpCaret(nextPoint.row, nextPoint.col,false);
+            return this.GetTextPointAfterMoveLine(isMoveNext ? 1 : -1, this.Document.CaretPostion, move_pargraph);
         }
 
         private void ReplaceBeforeSelectionArea(SelectCollection Selections, int removeLength, string insertStr)