| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619 |
- namespace Terminal.Gui.Views;
- /// <summary>Navigation functionality - cursor movement and scrolling</summary>
- public partial class TextView
- {
- #region Public Navigation Methods
- /// <summary>Will scroll the <see cref="TextView"/> to the last line and position the cursor there.</summary>
- public void MoveEnd ()
- {
- CurrentRow = _model.Count - 1;
- List<Cell> line = GetCurrentLine ();
- CurrentColumn = line.Count;
- TrackColumn ();
- DoNeededAction ();
- }
- /// <summary>Will scroll the <see cref="TextView"/> to the first line and position the cursor there.</summary>
- public void MoveHome ()
- {
- CurrentRow = 0;
- _topRow = 0;
- CurrentColumn = 0;
- _leftColumn = 0;
- TrackColumn ();
- DoNeededAction ();
- }
- /// <summary>
- /// Will scroll the <see cref="TextView"/> to display the specified row at the top if <paramref name="isRow"/> is
- /// true or will scroll the <see cref="TextView"/> to display the specified column at the left if
- /// <paramref name="isRow"/> is false.
- /// </summary>
- /// <param name="idx">
- /// Row that should be displayed at the top or Column that should be displayed at the left, if the value
- /// is negative it will be reset to zero
- /// </param>
- /// <param name="isRow">If true (default) the <paramref name="idx"/> is a row, column otherwise.</param>
- public void ScrollTo (int idx, bool isRow = true)
- {
- if (idx < 0)
- {
- idx = 0;
- }
- if (isRow)
- {
- _topRow = Math.Max (idx > _model.Count - 1 ? _model.Count - 1 : idx, 0);
- if (IsInitialized && Viewport.Y != _topRow)
- {
- Viewport = Viewport with { Y = _topRow };
- }
- }
- else if (!_wordWrap)
- {
- int maxlength = _model.GetMaxVisibleLine (_topRow, _topRow + Viewport.Height, TabWidth);
- _leftColumn = Math.Max (!_wordWrap && idx > maxlength - 1 ? maxlength - 1 : idx, 0);
- if (IsInitialized && Viewport.X != _leftColumn)
- {
- Viewport = Viewport with { X = _leftColumn };
- }
- }
- SetNeedsDraw ();
- }
- #endregion
- #region Private Navigation Methods
- private void MoveBottomEnd ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- MoveEnd ();
- }
- private void MoveBottomEndExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveEnd ();
- }
- private bool MoveDown ()
- {
- if (CurrentRow + 1 < _model.Count)
- {
- if (_columnTrack == -1)
- {
- _columnTrack = CurrentColumn;
- }
- CurrentRow++;
- if (CurrentRow >= _topRow + Viewport.Height)
- {
- _topRow++;
- SetNeedsDraw ();
- }
- TrackColumn ();
- PositionCursor ();
- }
- else if (CurrentRow > Viewport.Height)
- {
- AdjustScrollPosition ();
- }
- else
- {
- return false;
- }
- DoNeededAction ();
- return true;
- }
- private void MoveEndOfLine ()
- {
- List<Cell> currentLine = GetCurrentLine ();
- CurrentColumn = currentLine.Count;
- DoNeededAction ();
- }
- private bool MoveLeft ()
- {
- if (CurrentColumn > 0)
- {
- CurrentColumn--;
- }
- else
- {
- if (CurrentRow > 0)
- {
- CurrentRow--;
- if (CurrentRow < _topRow)
- {
- _topRow--;
- SetNeedsDraw ();
- }
- List<Cell> currentLine = GetCurrentLine ();
- CurrentColumn = Math.Max (currentLine.Count - (ReadOnly ? 1 : 0), 0);
- }
- else
- {
- return false;
- }
- }
- DoNeededAction ();
- return true;
- }
- private void MovePageDown ()
- {
- int nPageDnShift = Viewport.Height - 1;
- if (CurrentRow >= 0 && CurrentRow < _model.Count)
- {
- if (_columnTrack == -1)
- {
- _columnTrack = CurrentColumn;
- }
- CurrentRow = CurrentRow + nPageDnShift > _model.Count
- ? _model.Count > 0 ? _model.Count - 1 : 0
- : CurrentRow + nPageDnShift;
- if (_topRow < CurrentRow - nPageDnShift)
- {
- _topRow = CurrentRow >= _model.Count
- ? CurrentRow - nPageDnShift
- : _topRow + nPageDnShift;
- SetNeedsDraw ();
- }
- TrackColumn ();
- PositionCursor ();
- }
- DoNeededAction ();
- }
- private void MovePageUp ()
- {
- int nPageUpShift = Viewport.Height - 1;
- if (CurrentRow > 0)
- {
- if (_columnTrack == -1)
- {
- _columnTrack = CurrentColumn;
- }
- CurrentRow = CurrentRow - nPageUpShift < 0 ? 0 : CurrentRow - nPageUpShift;
- if (CurrentRow < _topRow)
- {
- _topRow = _topRow - nPageUpShift < 0 ? 0 : _topRow - nPageUpShift;
- SetNeedsDraw ();
- }
- TrackColumn ();
- PositionCursor ();
- }
- DoNeededAction ();
- }
- private bool MoveRight ()
- {
- List<Cell> currentLine = GetCurrentLine ();
- if ((ReadOnly ? CurrentColumn + 1 : CurrentColumn) < currentLine.Count)
- {
- CurrentColumn++;
- }
- else
- {
- if (CurrentRow + 1 < _model.Count)
- {
- CurrentRow++;
- CurrentColumn = 0;
- if (CurrentRow >= _topRow + Viewport.Height)
- {
- _topRow++;
- SetNeedsDraw ();
- }
- }
- else
- {
- return false;
- }
- }
- DoNeededAction ();
- return true;
- }
- private void MoveLeftStart ()
- {
- if (_leftColumn > 0)
- {
- SetNeedsDraw ();
- }
- CurrentColumn = 0;
- _leftColumn = 0;
- DoNeededAction ();
- }
- private void MoveTopHome ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- MoveHome ();
- }
- private void MoveTopHomeExtend ()
- {
- ResetColumnTrack ();
- StartSelecting ();
- MoveHome ();
- }
- private bool MoveUp ()
- {
- if (CurrentRow > 0)
- {
- if (_columnTrack == -1)
- {
- _columnTrack = CurrentColumn;
- }
- CurrentRow--;
- if (CurrentRow < _topRow)
- {
- _topRow--;
- SetNeedsDraw ();
- }
- TrackColumn ();
- PositionCursor ();
- }
- else
- {
- return false;
- }
- DoNeededAction ();
- return true;
- }
- private void MoveWordBackward ()
- {
- (int col, int row)? newPos = _model.WordBackward (CurrentColumn, CurrentRow, UseSameRuneTypeForWords);
- if (newPos.HasValue)
- {
- CurrentColumn = newPos.Value.col;
- CurrentRow = newPos.Value.row;
- }
- DoNeededAction ();
- }
- private void MoveWordForward ()
- {
- (int col, int row)? newPos = _model.WordForward (CurrentColumn, CurrentRow, UseSameRuneTypeForWords);
- if (newPos.HasValue)
- {
- CurrentColumn = newPos.Value.col;
- CurrentRow = newPos.Value.row;
- }
- DoNeededAction ();
- }
- #endregion
- #region Process Navigation Methods
- private bool ProcessMoveDown ()
- {
- ResetContinuousFindTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- return MoveDown ();
- }
- private void ProcessMoveDownExtend ()
- {
- ResetColumnTrack ();
- StartSelecting ();
- MoveDown ();
- }
- private void ProcessMoveEndOfLine ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- MoveEndOfLine ();
- }
- private void ProcessMoveRightEndExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveEndOfLine ();
- }
- private bool ProcessMoveLeft ()
- {
- // if the user presses Left (without any control keys) and they are at the start of the text
- if (CurrentColumn == 0 && CurrentRow == 0)
- {
- if (IsSelecting)
- {
- StopSelecting ();
- return true;
- }
- // do not respond (this lets the key press fall through to navigation system - which usually changes focus backward)
- return false;
- }
- ResetAllTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- MoveLeft ();
- return true;
- }
- private void ProcessMoveLeftExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveLeft ();
- }
- private bool ProcessMoveRight ()
- {
- // if the user presses Right (without any control keys)
- // determine where the last cursor position in the text is
- int lastRow = _model.Count - 1;
- int lastCol = _model.GetLine (lastRow).Count;
- // if they are at the very end of all the text do not respond (this lets the key press fall through to navigation system - which usually changes focus forward)
- if (CurrentColumn == lastCol && CurrentRow == lastRow)
- {
- // Unless they have text selected
- if (IsSelecting)
- {
- // In which case clear
- StopSelecting ();
- return true;
- }
- return false;
- }
- ResetAllTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- MoveRight ();
- return true;
- }
- private void ProcessMoveRightExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveRight ();
- }
- private void ProcessMoveLeftStart ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- MoveLeftStart ();
- }
- private void ProcessMoveLeftStartExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveLeftStart ();
- }
- private bool ProcessMoveUp ()
- {
- ResetContinuousFindTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- return MoveUp ();
- }
- private void ProcessMoveUpExtend ()
- {
- ResetColumnTrack ();
- StartSelecting ();
- MoveUp ();
- }
- private void ProcessMoveWordBackward ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- MoveWordBackward ();
- }
- private void ProcessMoveWordBackwardExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveWordBackward ();
- }
- private void ProcessMoveWordForward ()
- {
- ResetAllTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- MoveWordForward ();
- }
- private void ProcessMoveWordForwardExtend ()
- {
- ResetAllTrack ();
- StartSelecting ();
- MoveWordForward ();
- }
- private void ProcessPageDown ()
- {
- ResetColumnTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- MovePageDown ();
- }
- private void ProcessPageDownExtend ()
- {
- ResetColumnTrack ();
- StartSelecting ();
- MovePageDown ();
- }
- private void ProcessPageUp ()
- {
- ResetColumnTrack ();
- if (_shiftSelecting && IsSelecting)
- {
- StopSelecting ();
- }
- MovePageUp ();
- }
- private void ProcessPageUpExtend ()
- {
- ResetColumnTrack ();
- StartSelecting ();
- MovePageUp ();
- }
- #endregion
- #region Column Tracking
- // Tries to snap the cursor to the tracking column
- private void TrackColumn ()
- {
- // Now track the column
- List<Cell> line = GetCurrentLine ();
- if (line.Count < _columnTrack)
- {
- CurrentColumn = line.Count;
- }
- else if (_columnTrack != -1)
- {
- CurrentColumn = _columnTrack;
- }
- else if (CurrentColumn > line.Count)
- {
- CurrentColumn = line.Count;
- }
- AdjustScrollPosition ();
- }
- #endregion
- private void ResetAllTrack ()
- {
- // Handle some state here - whether the last command was a kill
- // operation and the column tracking (up/down)
- _lastWasKill = false;
- _columnTrack = -1;
- _continuousFind = false;
- }
- /// <summary>
- /// INTERNAL: Resets the cursor position and scroll offsets to the beginning of the document (0,0)
- /// and stops any active text selection.
- /// </summary>
- private void ResetPosition ()
- {
- _topRow = _leftColumn = CurrentRow = CurrentColumn = 0;
- StopSelecting ();
- }
- }
|