diff options
-rw-r--r-- | doc/ScintillaDoc.html | 9 | ||||
-rw-r--r-- | include/Scintilla.h | 1 | ||||
-rw-r--r-- | include/Scintilla.iface | 5 | ||||
-rw-r--r-- | src/Editor.cxx | 58 | ||||
-rw-r--r-- | src/Editor.h | 11 |
5 files changed, 73 insertions, 11 deletions
diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index 7e362ffb9..cfa13bfdc 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -1730,6 +1730,7 @@ struct Sci_TextToFind { <h2 id="ScrollingAndAutomaticScrolling">Scrolling and automatic scrolling</h2> <code><a class="message" href="#SCI_LINESCROLL">SCI_LINESCROLL(int column, int line)</a><br /> <a class="message" href="#SCI_SCROLLCARET">SCI_SCROLLCARET</a><br /> + <a class="message" href="#SCI_SCROLLRANGE">SCI_SCROLLRANGE(int secondary, int primary)</a><br /> <a class="message" href="#SCI_SETXCARETPOLICY">SCI_SETXCARETPOLICY(int caretPolicy, int caretSlop)</a><br /> <a class="message" href="#SCI_SETYCARETPOLICY">SCI_SETYCARETPOLICY(int caretPolicy, int @@ -1766,6 +1767,14 @@ struct Sci_TextToFind { If the current position (this is the caret if there is no selection) is not visible, the view is scrolled to make it visible according to the current caret policy.</p> + <p><b id="SCI_SCROLLRANGE">SCI_SCROLLRANGE(int secondary, int primary)</b><br /> + Scroll the argument positions and the range between them into view giving + priority to the primary position then the secondary position. + The behaviour is similar to <a class="message" href="#SCI_SCROLLCARET"><code>SCI_SCROLLCARET</code></a> + with the primary position used instead of the caret. An effort is then made to ensure that the secondary + position and range between are also visible. + This may be used to make a search match visible.</p> + <p><b id="SCI_SETXCARETPOLICY">SCI_SETXCARETPOLICY(int caretPolicy, int caretSlop)</b><br /> <b id="SCI_SETYCARETPOLICY">SCI_SETYCARETPOLICY(int caretPolicy, int caretSlop)</b><br /> These set the caret policy. The value of <code>caretPolicy</code> is a combination of diff --git a/include/Scintilla.h b/include/Scintilla.h index 15a86682e..48c7ff379 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -382,6 +382,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_POSITIONFROMLINE 2167 #define SCI_LINESCROLL 2168 #define SCI_SCROLLCARET 2169 +#define SCI_SCROLLRANGE 2569 #define SCI_REPLACESEL 2170 #define SCI_SETREADONLY 2171 #define SCI_NULL 2172 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index 670d3937f..496f472ae 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -924,6 +924,11 @@ fun void LineScroll=2168(int columns, int lines) # Ensure the caret is visible. fun void ScrollCaret=2169(,) +# Scroll the argument positions and the range between them into view giving +# priority to the primary position then the secondary position. +# This may be used to make a search match visible. +fun void ScrollRange=2569(position secondary, position primary) + # Replace the selected text with the argument text. fun void ReplaceSel=2170(, string text) diff --git a/src/Editor.cxx b/src/Editor.cxx index 98d98d38f..d02f095cb 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -962,7 +962,8 @@ int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, b // In case in need of wrapping to ensure DisplayFromDoc works. if (currentLine >= wrapStart) WrapLines(true, -1); - XYScrollPosition newXY = XYScrollToMakeVisible(true, true, true); + XYScrollPosition newXY = XYScrollToMakeVisible( + SelectionRange(posDrag.IsValid() ? posDrag : sel.RangeMain().caret), xysDefault); if (simpleCaret && (newXY.xOffset == xOffset)) { // simple vertical scroll then invalidate ScrollTo(newXY.topLine); @@ -1233,19 +1234,20 @@ slop | strict | jumps | even | Caret can go to the margin | When 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin */ -Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz) { +Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const SelectionRange range, const XYScrollOptions options) { PRectangle rcClient = GetTextRectangle(); - const SelectionPosition posCaret = posDrag.IsValid() ? posDrag : sel.RangeMain().caret; - Point pt = LocationFromPosition(posCaret); + Point pt = LocationFromPosition(range.caret); + Point ptAnchor = LocationFromPosition(range.anchor); const Point ptOrigin = GetVisibleOriginInMain(); pt.x += ptOrigin.x; + ptAnchor.x += ptOrigin.x; const Point ptBottomCaret(pt.x, pt.y + vs.lineHeight - 1); - const int lineCaret = DisplayFromPosition(posCaret.Position()); XYScrollPosition newXY(xOffset, topLine); // Vertical positioning - if (vert && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) { + if ((options & xysVertical) && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) { + const int lineCaret = DisplayFromPosition(range.caret.Position()); const int linesOnScreen = LinesOnScreen(); const int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2; const bool bSlop = (caretYPolicy & CARET_SLOP) != 0; @@ -1259,7 +1261,7 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con int yMoveT, yMoveB; if (bStrict) { int yMarginT, yMarginB; - if (!useMargin) { + if (!(options & xysUseMargin)) { // In drag mode, avoid moves // otherwise, a double click will select several lines. yMarginT = yMarginB = 0; @@ -1329,11 +1331,23 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con } } } + if (!(range.caret == range.anchor)) { + const int lineAnchor = DisplayFromPosition(range.anchor.Position()); + if (lineAnchor < lineCaret) { + // Shift up to show anchor or as much of range as possible + newXY.topLine = std::min(newXY.topLine, lineAnchor); + newXY.topLine = std::max(newXY.topLine, lineCaret - LinesOnScreen()); + } else { + // Shift down to show anchor or as much of range as possible + newXY.topLine = std::max(newXY.topLine, lineAnchor - LinesOnScreen()); + newXY.topLine = std::min(newXY.topLine, lineCaret); + } + } newXY.topLine = Platform::Clamp(newXY.topLine, 0, MaxScrollPos()); } // Horizontal positioning - if (horiz && (wrapState == eWrapNone)) { + if ((options & xysHorizontal) && (wrapState == eWrapNone)) { const int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2; const bool bSlop = (caretXPolicy & CARET_SLOP) != 0; const bool bStrict = (caretXPolicy & CARET_STRICT) != 0; @@ -1344,7 +1358,7 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con int xMoveL, xMoveR; if (bStrict) { int xMarginL, xMarginR; - if (!useMargin) { + if (!(options & xysUseMargin)) { // In drag mode, avoid moves unless very near of the margin // otherwise, a simple click will select text. xMarginL = xMarginR = 2; @@ -1433,6 +1447,21 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con newXY.xOffset += static_cast<int>(vs.aveCharWidth); } } + if (!(range.caret == range.anchor)) { + if (ptAnchor.x < pt.x) { + // Shift to left to show anchor or as much of range as possible + int maxOffset = ptAnchor.x + xOffset - rcClient.left - 1; + int minOffset = pt.x + xOffset - rcClient.right + 1; + newXY.xOffset = std::min(newXY.xOffset, maxOffset); + newXY.xOffset = std::max(newXY.xOffset, minOffset); + } else { + // Shift to right to show anchor or as much of range as possible + int minOffset = ptAnchor.x + xOffset - rcClient.right + 1; + int maxOffset = pt.x + xOffset - rcClient.left - 1; + newXY.xOffset = std::max(newXY.xOffset, minOffset); + newXY.xOffset = std::min(newXY.xOffset, maxOffset); + } + } if (newXY.xOffset < 0) { newXY.xOffset = 0; } @@ -1465,8 +1494,13 @@ void Editor::SetXYScroll(XYScrollPosition newXY) { } } +void Editor::ScrollRange(SelectionRange range) { + SetXYScroll(XYScrollToMakeVisible(range, xysDefault)); +} + void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { - SetXYScroll(XYScrollToMakeVisible(useMargin, vert, horiz)); + SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag.IsValid() ? posDrag : sel.RangeMain().caret), + static_cast<XYScrollOptions>((useMargin?xysUseMargin:0)|(vert?xysVertical:0)|(horiz?xysHorizontal:0)))); } void Editor::ShowCaretAtCurrentPosition() { @@ -8525,6 +8559,10 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { EnsureLineVisible(wParam, true); break; + case SCI_SCROLLRANGE: + ScrollRange(SelectionRange(lParam, wParam)); + break; + case SCI_SEARCHANCHOR: SearchAnchor(); break; diff --git a/src/Editor.h b/src/Editor.h index 91cbd59a4..f2b452a77 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -381,10 +381,19 @@ protected: // ScintillaBase subclass needs access to much of Editor int xOffset; int topLine; XYScrollPosition(int xOffset_, int topLine_) : xOffset(xOffset_), topLine(topLine_) {} + bool operator==(const XYScrollPosition &other) const { + return (xOffset == other.xOffset) && (topLine == other.topLine); + } }; - XYScrollPosition XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz); + enum XYScrollOptions { + xysUseMargin=0x1, + xysVertical=0x2, + xysHorizontal=0x4, + xysDefault=xysUseMargin|xysVertical|xysHorizontal}; + XYScrollPosition XYScrollToMakeVisible(const SelectionRange range, const XYScrollOptions options); void SetXYScroll(XYScrollPosition newXY); void EnsureCaretVisible(bool useMargin=true, bool vert=true, bool horiz=true); + void ScrollRange(SelectionRange range); void ShowCaretAtCurrentPosition(); void DropCaret(); void InvalidateCaret(); |