From 2189d4ff82cd7a48802fd5ce545a29d80e198adf Mon Sep 17 00:00:00 2001
From: nyamatongwe Scrolling and automatic scrolling
+
SCI_SCROLLRANGE(int secondary, int primary)
+ 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
+ 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.
SCI_SETXCARETPOLICY(int caretPolicy, int caretSlop)
SCI_SETYCARETPOLICY(int caretPolicy, int caretSlop)
These set the caret policy. The value of caretPolicy 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