public override UIHandleResult OnMouseDown(MouseEventArgs args)
        {
            if (args.Button != MouseButtons.Left || !_viewer.EnabledEx)
            {
                return(UIHandleResult.Pass);
            }

            //テキスト選択ではないのでちょっと柄悪いが。UserControl->Controlの置き換えに伴う
            if (!_viewer.Focused)
            {
                _viewer.Focus();
            }


            CharacterDocument document = _viewer.CharacterDocument;

            lock (document) {
                int col, row;
                _viewer.MousePosToTextPos(args.X, args.Y, out col, out row);
                int           target_id = _viewer.GetTopLine().ID + row;
                TextSelection sel       = _viewer.TextSelection;
                if (sel.State == SelectionState.Fixed)
                {
                    sel.Clear(); //変なところでMouseDownしたとしてもClearだけはする
                }
                if (target_id <= document.LastLineNumber)
                {
                    //if(InFreeSelectionMode) ExitFreeSelectionMode();
                    //if(InAutoSelectionMode) ExitAutoSelectionMode();
                    RangeType rt;
                    //Debug.WriteLine(String.Format("MouseDown {0} {1}", sel.State, sel.PivotType));

                    //同じ場所でポチポチと押すとChar->Word->Line->Charとモード変化する
                    if (sel.StartX != args.X || sel.StartY != args.Y)
                    {
                        rt = RangeType.Char;
                    }
                    else
                    {
                        rt = sel.PivotType == RangeType.Char ? RangeType.Word : sel.PivotType == RangeType.Word ? RangeType.Line : RangeType.Char;
                    }

                    //マウスを動かしていなくても、MouseDownとともにMouseMoveが来てしまうようだ
                    GLine tl = document.FindLine(target_id);
                    sel.StartSelection(tl, col, rt, args.X, args.Y);
                }
            }
            _viewer.Invalidate(); //NOTE 選択状態に変化のあった行のみ更新すればなおよし
            return(UIHandleResult.Capture);
        }
 //_documentのうちどれを先頭(1行目)として表示するかを返す
 public virtual GLine GetTopLine()
 {
     return(_document.FindLine(_document.FirstLine.ID + _VScrollBar.Value));
 }
        public override UIHandleResult OnMouseMove(MouseEventArgs args)
        {
            if (args.Button != MouseButtons.Left)
            {
                return(UIHandleResult.Pass);
            }
            TextSelection sel = _viewer.TextSelection;

            if (sel.State == SelectionState.Fixed || sel.State == SelectionState.Empty)
            {
                return(UIHandleResult.Pass);
            }
            //クリックだけでもなぜかMouseDownの直後にMouseMoveイベントが来るのでこのようにしてガード。でないと単発クリックでも選択状態になってしまう
            if (sel.StartX == args.X && sel.StartY == args.Y)
            {
                return(UIHandleResult.Capture);
            }

            CharacterDocument document = _viewer.CharacterDocument;

            lock (document) {
                int   topline_id = _viewer.GetTopLine().ID;
                SizeF pitch = _viewer.GetRenderProfile().Pitch;
                int   row, col;
                _viewer.MousePosToTextPos_AllowNegative(args.X, args.Y, out col, out row);
                int viewheight = (int)Math.Floor(_viewer.ClientSize.Height / pitch.Width);
                int target_id  = topline_id + row;

                GLine target_line             = document.FindLineOrEdge(target_id);
                TextSelection.TextPoint point = sel.ConvertSelectionPosition(target_line, col);

                point.Line = RuntimeUtil.AdjustIntRange(point.Line, document.FirstLineNumber, document.LastLineNumber);

                if (_viewer.VScrollBar.Enabled)   //スクロール可能なときは
                {
                    VScrollBar vsc = _viewer.VScrollBar;
                    if (target_id < topline_id) //前方スクロール
                    {
                        vsc.Value = point.Line - document.FirstLineNumber;
                    }
                    else if (point.Line >= topline_id + vsc.LargeChange)   //後方スクロール
                    {
                        int newval = point.Line - document.FirstLineNumber - vsc.LargeChange + 1;
                        if (newval < 0)
                        {
                            newval = 0;
                        }
                        if (newval > vsc.Maximum - vsc.LargeChange)
                        {
                            newval = vsc.Maximum - vsc.LargeChange + 1;
                        }
                        vsc.Value = newval;
                    }
                }
                else   //スクロール不可能なときは見えている範囲で
                {
                    point.Line = RuntimeUtil.AdjustIntRange(point.Line, topline_id, topline_id + viewheight - 1);
                } //ここさぼっている
                //Debug.WriteLine(String.Format("MouseMove {0} {1} {2}", sel.State, sel.PivotType, args.X));
                RangeType rt = sel.PivotType;
                if ((Control.ModifierKeys & Keys.Control) != Keys.None)
                {
                    rt = RangeType.Word;
                }
                else if ((Control.ModifierKeys & Keys.Shift) != Keys.None)
                {
                    rt = RangeType.Line;
                }

                GLine tl = document.FindLine(point.Line);
                sel.ExpandTo(tl, point.Column, rt);
            }
            _viewer.Invalidate(); //TODO 選択状態に変化のあった行のみ更新するようにすればなおよし
            return(UIHandleResult.Capture);
        }