aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authornyamatongwe <unknown>2009-07-03 05:48:47 +0000
committernyamatongwe <unknown>2009-07-03 05:48:47 +0000
commit43deaf5e127a3bb92e1e2c72fa9cd8f8233578a9 (patch)
treef88ba56f27bd5111e0b9c9aaf12426f33dc992d5 /src
parent2c6815995a898438dd58aaa05af9261fc8b85da6 (diff)
downloadscintilla-mirror-43deaf5e127a3bb92e1e2c72fa9cd8f8233578a9.tar.gz
Discontiguoues selection and virtual space initial commit.
Diffstat (limited to 'src')
-rw-r--r--src/Document.cxx4
-rw-r--r--src/Document.h1
-rw-r--r--src/Editor.cxx1767
-rw-r--r--src/Editor.h46
-rw-r--r--src/PositionCache.cxx22
-rw-r--r--src/PositionCache.h6
-rw-r--r--src/ScintillaBase.cxx41
-rw-r--r--src/Selection.cxx345
-rw-r--r--src/Selection.h142
9 files changed, 1600 insertions, 774 deletions
diff --git a/src/Document.cxx b/src/Document.cxx
index 211d19315..eca4511de 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -217,6 +217,10 @@ int Document::LineEndPosition(int position) const {
return LineEnd(LineFromPosition(position));
}
+bool Document::IsLineEndPosition(int position) const {
+ return LineEnd(LineFromPosition(position)) == position;
+}
+
int Document::VCHomePosition(int position) const {
int line = LineFromPosition(position);
int startPosition = LineStart(line);
diff --git a/src/Document.h b/src/Document.h
index 58615bb19..4751cd2c8 100644
--- a/src/Document.h
+++ b/src/Document.h
@@ -239,6 +239,7 @@ public:
int LineStart(int line) const;
int LineEnd(int line) const;
int LineEndPosition(int position) const;
+ bool IsLineEndPosition(int position) const;
int VCHomePosition(int position) const;
int SetLevel(int line, int level);
diff --git a/src/Editor.cxx b/src/Editor.cxx
index 6f7e6eb4b..7af0e7325 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -28,6 +28,7 @@
#include "CharClassify.h"
#include "Decoration.h"
#include "Document.h"
+#include "Selection.h"
#include "PositionCache.h"
#include "Editor.h"
@@ -116,10 +117,6 @@ Editor::Editor() {
lineAnchor = 0;
originalAnchorPos = 0;
- selType = selStream;
- moveExtendsSelection = false;
- xStartSelect = 0;
- xEndSelect = 0;
primarySelection = true;
caretXPolicy = CARET_SLOP | CARET_EVEN;
@@ -139,6 +136,10 @@ Editor::Editor() {
verticalScrollBarVisible = true;
endAtLastLine = true;
caretSticky = false;
+ multiLineCaret = false;
+ multiLineCaretBlinks = true;
+ virtualSpaceOptions = SCVS_NONE;
+ virtualSpaceOptions = SCVS_USERACCESSIBLE;
pixmapLine = Surface::Allocate();
pixmapSelMargin = Surface::Allocate();
@@ -146,9 +147,6 @@ Editor::Editor() {
pixmapIndentGuide = Surface::Allocate();
pixmapIndentGuideHighlight = Surface::Allocate();
- currentPos = 0;
- anchor = 0;
-
targetStart = 0;
targetEnd = 0;
searchFlags = 0;
@@ -227,10 +225,7 @@ void Editor::InvalidateStyleData() {
palette.Release();
llc.Invalidate(LineLayout::llInvalid);
posCache.Clear();
- if (selType == selRectangle) {
- xStartSelect = XFromPosition(anchor);
- xEndSelect = XFromPosition(currentPos);
- }
+ SetRectangularRange();
}
void Editor::InvalidateStyleRedraw() {
@@ -347,91 +342,18 @@ public:
}
};
-#ifdef SCI_NAMESPACE
-namespace Scintilla {
-#endif
-
-/**
- * Allows to iterate through the lines of a selection.
- * Althought it can be called for a stream selection, in most cases
- * it is inefficient and it should be used only for
- * a rectangular or a line selection.
- */
-class SelectionLineIterator {
-private:
- Editor *ed;
- int line; ///< Current line within the iteration.
- bool forward; ///< True if iterating by increasing line number, false otherwise.
- int selStart, selEnd; ///< Positions of the start and end of the selection relative to the start of the document.
- int minX, maxX; ///< Left and right of selection rectangle.
-
-public:
- int lineStart, lineEnd; ///< Line numbers, first and last lines of the selection.
- int startPos, endPos; ///< Positions of the beginning and end of the selection on the current line.
-
- void Reset() {
- if (forward) {
- line = lineStart;
- } else {
- line = lineEnd;
- }
- }
-
- SelectionLineIterator(Editor *ed_, bool forward_ = true) : line(0), startPos(0), endPos(0) {
- ed = ed_;
- forward = forward_;
- selStart = ed->SelectionStart();
- selEnd = ed->SelectionEnd();
- lineStart = ed->pdoc->LineFromPosition(selStart);
- lineEnd = ed->pdoc->LineFromPosition(selEnd);
- // Left of rectangle
- minX = Platform::Minimum(ed->xStartSelect, ed->xEndSelect);
- // Right of rectangle
- maxX = Platform::Maximum(ed->xStartSelect, ed->xEndSelect);
- Reset();
- }
- ~SelectionLineIterator() {}
-
- void SetAt(int line) {
- if (line < lineStart || line > lineEnd) {
- startPos = endPos = INVALID_POSITION;
- } else {
- if (ed->selType == ed->selRectangle) {
- // Measure line and return character closest to minX
- startPos = ed->PositionFromLineX(line, minX);
- // Measure line and return character closest to maxX
- endPos = ed->PositionFromLineX(line, maxX);
- } else if (ed->selType == ed->selLines) {
- startPos = ed->pdoc->LineStart(line);
- endPos = ed->pdoc->LineStart(line + 1);
- } else { // Stream selection, here only for completion
- if (line == lineStart) {
- startPos = selStart;
- } else {
- startPos = ed->pdoc->LineStart(line);
- }
- if (line == lineEnd) {
- endPos = selEnd;
- } else {
- endPos = ed->pdoc->LineStart(line + 1);
- }
- }
- }
- }
- bool Iterate() {
- SetAt(line);
- if (forward) {
- line++;
- } else {
- line--;
- }
- return startPos != INVALID_POSITION;
+SelectionPosition Editor::ClampPositionIntoDocument(SelectionPosition sp) const {
+ if (sp.Position() < 0) {
+ return SelectionPosition(0);
+ } else if (sp.Position() > pdoc->Length()) {
+ return SelectionPosition(pdoc->Length());
+ } else {
+ // If not at end of line then set offset to 0
+ if (!pdoc->IsLineEndPosition(sp.Position()))
+ sp.SetVirtualSpace(0);
+ return sp;
}
-};
-
-#ifdef SCI_NAMESPACE
}
-#endif
Point Editor::LocationFromPosition(int pos) {
Point pt;
@@ -478,6 +400,11 @@ int Editor::XFromPosition(int pos) {
return pt.x - vs.fixedColumnWidth + xOffset;
}
+int Editor::XFromPosition(SelectionPosition sp) {
+ Point pt = LocationFromPosition(sp.Position());
+ return pt.x + sp.VirtualSpace() * vs.spaceWidth - vs.fixedColumnWidth + xOffset;
+}
+
int Editor::LineFromLocation(Point pt) {
return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
}
@@ -487,16 +414,16 @@ void Editor::SetTopLine(int topLineNew) {
posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine));
}
-int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) {
+SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace) {
RefreshStyleData();
if (canReturnInvalid) {
PRectangle rcClient = GetTextRectangle();
if (!rcClient.Contains(pt))
- return INVALID_POSITION;
+ return SelectionPosition(INVALID_POSITION);
if (pt.x < vs.fixedColumnWidth)
- return INVALID_POSITION;
+ return SelectionPosition(INVALID_POSITION);
if (pt.y < 0)
- return INVALID_POSITION;
+ return SelectionPosition(INVALID_POSITION);
}
pt.x = pt.x - vs.fixedColumnWidth + xOffset;
int visibleLine = pt.y / vs.lineHeight + topLine;
@@ -507,11 +434,11 @@ int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosit
visibleLine = 0;
int lineDoc = cs.DocFromDisplay(visibleLine);
if (canReturnInvalid && (lineDoc < 0))
- return INVALID_POSITION;
+ return SelectionPosition(INVALID_POSITION);
if (lineDoc >= pdoc->LinesTotal())
- return canReturnInvalid ? INVALID_POSITION : pdoc->Length();
+ return SelectionPosition(canReturnInvalid ? INVALID_POSITION : pdoc->Length());
unsigned int posLineStart = pdoc->LineStart(lineDoc);
- int retVal = canReturnInvalid ? INVALID_POSITION : static_cast<int>(posLineStart);
+ SelectionPosition retVal(canReturnInvalid ? INVALID_POSITION : static_cast<int>(posLineStart));
AutoSurface surface(this);
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
if (surface && ll) {
@@ -531,29 +458,38 @@ int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosit
while (i < lineEnd) {
if (charPosition) {
if ((pt.x + subLineStart) < (ll->positions[i + 1])) {
- return pdoc->MovePositionOutsideChar(i + posLineStart, 1);
+ return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1));
}
} else {
if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
- return pdoc->MovePositionOutsideChar(i + posLineStart, 1);
+ return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1));
}
}
i++;
}
- if (canReturnInvalid) {
+ if (virtualSpace) {
+ const int spaceWidth = static_cast<int>(vs.spaceWidth);
+ int spaceOffset = (pt.x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) /
+ spaceWidth;
+ return SelectionPosition(lineEnd + posLineStart, spaceOffset);
+ } else if (canReturnInvalid) {
if (pt.x < (ll->positions[lineEnd] - subLineStart)) {
- return pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1);
+ return SelectionPosition(pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1));
}
} else {
- return lineEnd + posLineStart;
+ return SelectionPosition(lineEnd + posLineStart);
}
}
if (!canReturnInvalid)
- return ll->numCharsInLine + posLineStart;
+ return SelectionPosition(ll->numCharsInLine + posLineStart);
}
return retVal;
}
+int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) {
+ return SPositionFromLocation(pt, canReturnInvalid, charPosition, false).Position();
+}
+
/**
* Find the document position corresponding to an x coordinate on a particular document line.
* Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
@@ -592,6 +528,45 @@ int Editor::PositionFromLineX(int lineDoc, int x) {
}
/**
+ * Find the document position corresponding to an x coordinate on a particular document line.
+ * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
+ */
+SelectionPosition Editor::SPositionFromLineX(int lineDoc, int x) {
+ RefreshStyleData();
+ if (lineDoc >= pdoc->LinesTotal())
+ return SelectionPosition(pdoc->Length());
+ //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
+ AutoSurface surface(this);
+ AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
+ int retVal = 0;
+ if (surface && ll) {
+ unsigned int posLineStart = pdoc->LineStart(lineDoc);
+ LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
+ int subLine = 0;
+ int lineStart = ll->LineStart(subLine);
+ int lineEnd = ll->LineLastVisible(subLine);
+ int subLineStart = ll->positions[lineStart];
+
+ if (ll->wrapIndent != 0) {
+ if (lineStart != 0) // Wrapped
+ x -= ll->wrapIndent;
+ }
+ int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd);
+ while (i < lineEnd) {
+ if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
+ retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1);
+ return SelectionPosition(retVal);
+ }
+ i++;
+ }
+ const int spaceWidth = static_cast<int>(vs.spaceWidth);
+ int spaceOffset = (x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) / spaceWidth;
+ return SelectionPosition(lineEnd + posLineStart, spaceOffset);
+ }
+ return SelectionPosition(retVal);
+}
+
+/**
* If painting then abandon the painting because a wider redraw is needed.
* @return true if calling code should stop drawing.
*/
@@ -676,80 +651,124 @@ void Editor::InvalidateRange(int start, int end) {
}
int Editor::CurrentPosition() {
- return currentPos;
+ return sel.MainCaret();
}
bool Editor::SelectionEmpty() {
- return anchor == currentPos;
+ return sel.Empty();
}
int Editor::SelectionStart() {
- return Platform::Minimum(currentPos, anchor);
+ return sel.RangeMain().Start().Position();
}
int Editor::SelectionEnd() {
- return Platform::Maximum(currentPos, anchor);
+ return sel.RangeMain().End().Position();
}
void Editor::SetRectangularRange() {
- if (selType == selRectangle) {
- xStartSelect = XFromPosition(anchor);
- xEndSelect = XFromPosition(currentPos);
+ if (sel.IsRectangular()) {
+ int xAnchor = XFromPosition(sel.Rectangular().anchor);
+ int xCaret = XFromPosition(sel.Rectangular().caret);
+ bool anchorTop = sel.Rectangular().anchor < sel.Rectangular().caret;
+ bool anchorLeft = xAnchor < xCaret;
+ if (sel.selType == Selection::selThin) {
+ xCaret = xAnchor;
+ }
+ SelectionPosition selStart = sel.Rectangular().Start();
+ SelectionPosition selEnd = sel.Rectangular().End();
+ int lineStart = pdoc->LineFromPosition(selStart.Position());
+ int lineEnd = pdoc->LineFromPosition(selEnd.Position());
+ // Left of rectangle
+ int minX = Platform::Minimum(xAnchor, xCaret);
+ // Right of rectangle
+ int maxX = Platform::Maximum(xAnchor, xCaret);
+ sel.EmptyRanges();
+ if (anchorTop) {
+ for (int line=lineStart; line<=lineEnd; line++) {
+ SelectionPosition spMin(SPositionFromLineX(line, minX));
+ SelectionPosition spMax(SPositionFromLineX(line, maxX));
+ sel.AddSelection(spMin, spMax, anchorLeft);
+ }
+ } else {
+ for (int line=lineEnd; line>=lineStart; line--) {
+ SelectionPosition spMin(SPositionFromLineX(line, minX));
+ SelectionPosition spMax(SPositionFromLineX(line, maxX));
+ sel.AddSelection(spMin, spMax, anchorLeft);
+ }
+ }
}
}
-void Editor::InvalidateSelection(int currentPos_, int anchor_, bool invalidateWholeSelection) {
- if (anchor != anchor_ || selType == selRectangle) {
+void Editor::InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection) {
+ if (sel.Count() > 1 || !(sel.RangeMain().anchor == newMain.anchor) || sel.IsRectangular()) {
invalidateWholeSelection = true;
}
- int firstAffected = currentPos;
+ int firstAffected = newMain.Start().Position();
+ // +1 for lastAffected ensures caret repainted
+ int lastAffected = Platform::Maximum(newMain.caret.Position()+1, newMain.anchor.Position());
if (invalidateWholeSelection) {
- if (firstAffected > anchor)
- firstAffected = anchor;
- if (firstAffected > anchor_)
- firstAffected = anchor_;
- }
- if (firstAffected > currentPos_)
- firstAffected = currentPos_;
- int lastAffected = currentPos;
- if (invalidateWholeSelection) {
- if (lastAffected < anchor)
- lastAffected = anchor;
- if (lastAffected < anchor_)
- lastAffected = anchor_;
+ for (size_t r=0; r<sel.Count(); r++) {
+ firstAffected = Platform::Minimum(firstAffected, sel.Range(r).caret.Position());
+ firstAffected = Platform::Minimum(firstAffected, sel.Range(r).anchor.Position());
+ lastAffected = Platform::Maximum(lastAffected, sel.Range(r).caret.Position()+1);
+ lastAffected = Platform::Maximum(lastAffected, sel.Range(r).anchor.Position());
+ }
}
- if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted
- lastAffected = (currentPos_ + 1);
needUpdateUI = true;
InvalidateRange(firstAffected, lastAffected);
}
-void Editor::SetSelection(int currentPos_, int anchor_) {
- currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
- anchor_ = pdoc->ClampPositionIntoDocument(anchor_);
- if ((currentPos != currentPos_) || (anchor != anchor_)) {
- InvalidateSelection(currentPos_, anchor_, true);
- currentPos = currentPos_;
- anchor = anchor_;
+void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_) {
+ SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_),
+ ClampPositionIntoDocument(anchor_));
+ if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) {
+ InvalidateSelection(rangeNew);
}
+ sel.RangeMain() = rangeNew;
SetRectangularRange();
ClaimSelection();
}
+void Editor::SetSelection(int currentPos_, int anchor_) {
+ SetSelection(SelectionPosition(currentPos_), SelectionPosition(anchor_));
+}
+
+// Just move the caret on the main selection
+void Editor::SetSelection(SelectionPosition currentPos_) {
+ currentPos_ = ClampPositionIntoDocument(currentPos_);
+ if (sel.Count() > 1 || !(sel.RangeMain().caret == currentPos_)) {
+ InvalidateSelection(SelectionRange(currentPos_));
+ }
+ if (sel.IsRectangular()) {
+ sel.Rectangular() =
+ SelectionRange(SelectionPosition(currentPos_), sel.Rectangular().anchor);
+ SetRectangularRange();
+ } else {
+ sel.RangeMain() =
+ SelectionRange(SelectionPosition(currentPos_), sel.RangeMain().anchor);
+ }
+ ClaimSelection();
+}
+
void Editor::SetSelection(int currentPos_) {
- currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
- if (currentPos != currentPos_) {
- InvalidateSelection(currentPos_, anchor, false);
- currentPos = currentPos_;
+ SetSelection(SelectionPosition(currentPos_));
+}
+
+void Editor::SetEmptySelection(SelectionPosition currentPos_) {
+ SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_));
+ if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) {
+ InvalidateSelection(rangeNew);
}
+ sel.Clear();
+ sel.RangeMain() = rangeNew;
SetRectangularRange();
ClaimSelection();
+
}
void Editor::SetEmptySelection(int currentPos_) {
- selType = selStream;
- moveExtendsSelection = false;
- SetSelection(currentPos_, currentPos_);
+ SetEmptySelection(SelectionPosition(currentPos_));
}
bool Editor::RangeContainsProtected(int start, int end) const {
@@ -769,20 +788,13 @@ bool Editor::RangeContainsProtected(int start, int end) const {
}
bool Editor::SelectionContainsProtected() {
- // DONE, but untested...: make support rectangular selection
- bool scp = false;
- if (selType == selStream) {
- scp = RangeContainsProtected(anchor, currentPos);
- } else {
- SelectionLineIterator lineIterator(this);
- while (lineIterator.Iterate()) {
- if (RangeContainsProtected(lineIterator.startPos, lineIterator.endPos)) {
- scp = true;
- break;
- }
+ for (size_t r=0; r<sel.Count(); r++) {
+ if (RangeContainsProtected(sel.Range(r).Start().Position(),
+ sel.Range(r).End().Position())) {
+ return true;
}
}
- return scp;
+ return false;
}
/**
@@ -809,14 +821,43 @@ int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) con
return pos;
}
-int Editor::MovePositionTo(int newPos, selTypes sel, bool ensureVisible) {
- int delta = newPos - currentPos;
- newPos = pdoc->ClampPositionIntoDocument(newPos);
- newPos = MovePositionOutsideChar(newPos, delta);
- if (sel != noSel) {
- selType = sel;
+SelectionPosition Editor::MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd) const {
+ int posMoved = pdoc->MovePositionOutsideChar(pos.Position(), moveDir, checkLineEnd);
+ if (posMoved != pos.Position())
+ pos.SetPosition(posMoved);
+ if (vs.ProtectionActive()) {
+ int mask = pdoc->stylingBitsMask;
+ if (moveDir > 0) {
+ if ((pos.Position() > 0) && vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected()) {
+ while ((pos.Position() < pdoc->Length()) &&
+ (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected()))
+ pos.Add(1);
+ }
+ } else if (moveDir < 0) {
+ if (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected()) {
+ while ((pos.Position() > 0) &&
+ (vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected()))
+ pos.Add(-1);
+ }
+ }
+ }
+ return pos;
+}
+
+int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, bool ensureVisible) {
+ //int delta = newPos.Position() - sel.MainCaret();
+ newPos = ClampPositionIntoDocument(newPos);
+ //newPos = MovePositionOutsideChar(newPos, delta);
+ if (!sel.IsRectangular() && (selt == Selection::selRectangle)) {
+ // Switching to rectangular
+ SelectionRange rangeMain = sel.RangeMain();
+ sel.Clear();
+ sel.Rectangular() = rangeMain;
+ }
+ if (selt != Selection::noSel) {
+ sel.selType = selt;
}
- if (sel != noSel || moveExtendsSelection) {
+ if (selt != Selection::noSel || sel.MoveExtends()) {
SetSelection(newPos);
} else {
SetEmptySelection(newPos);
@@ -828,10 +869,14 @@ int Editor::MovePositionTo(int newPos, selTypes sel, bool ensureVisible) {
return 0;
}
-int Editor::MovePositionSoVisible(int pos, int moveDir) {
- pos = pdoc->ClampPositionIntoDocument(pos);
- pos = MovePositionOutsideChar(pos, moveDir);
- int lineDoc = pdoc->LineFromPosition(pos);
+int Editor::MovePositionTo(int newPos, Selection::selTypes selt, bool ensureVisible) {
+ return MovePositionTo(SelectionPosition(newPos), selt, ensureVisible);
+}
+
+SelectionPosition Editor::MovePositionSoVisible(SelectionPosition pos, int moveDir) {
+ pos = ClampPositionIntoDocument(pos);
+ //pos = MovePositionOutsideChar(pos, moveDir);
+ int lineDoc = pdoc->LineFromPosition(pos.Position());
if (cs.GetVisible(lineDoc)) {
return pos;
} else {
@@ -839,20 +884,24 @@ int Editor::MovePositionSoVisible(int pos, int moveDir) {
if (moveDir > 0) {
// lineDisplay is already line before fold as lines in fold use display line of line after fold
lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed());
- return pdoc->LineStart(cs.DocFromDisplay(lineDisplay));
+ return SelectionPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay)));
} else {
lineDisplay = Platform::Clamp(lineDisplay - 1, 0, cs.LinesDisplayed());
- return pdoc->LineEnd(cs.DocFromDisplay(lineDisplay));
+ return SelectionPosition(pdoc->LineEnd(cs.DocFromDisplay(lineDisplay)));
}
}
}
+SelectionPosition Editor::MovePositionSoVisible(int pos, int moveDir) {
+ return MovePositionSoVisible(SelectionPosition(pos), moveDir);
+}
+
/**
* Choose the x position that the caret will try to stick to
* as it moves up and down.
*/
void Editor::SetLastXChosen() {
- Point pt = LocationFromPosition(currentPos);
+ Point pt = LocationFromPosition(sel.MainCaret());
lastXChosen = pt.x;
}
@@ -897,16 +946,16 @@ void Editor::HorizontalScrollTo(int xPos) {
void Editor::MoveCaretInsideView(bool ensureVisible) {
PRectangle rcClient = GetTextRectangle();
- Point pt = LocationFromPosition(currentPos);
+ Point pt = LocationFromPosition(sel.MainCaret());
if (pt.y < rcClient.top) {
- MovePositionTo(PositionFromLocation(
+ MovePositionTo(SPositionFromLocation(
Point(lastXChosen, rcClient.top)),
- noSel, ensureVisible);
+ Selection::noSel, ensureVisible);
} else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) {
int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight;
- MovePositionTo(PositionFromLocation(
+ MovePositionTo(SPositionFromLocation(
Point(lastXChosen, rcClient.top + yOfLastLineFullyDisplayed)),
- noSel, ensureVisible);
+ Selection::noSel, ensureVisible);
}
}
@@ -978,7 +1027,7 @@ void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {
//Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");
PRectangle rcClient = GetTextRectangle();
//int rcClientFullWidth = rcClient.Width();
- int posCaret = currentPos;
+ int posCaret = sel.MainCaret();
if (posDrag >= 0) {
posCaret = posDrag;
}
@@ -1222,10 +1271,13 @@ void Editor::DropCaret() {
}
void Editor::InvalidateCaret() {
- if (posDrag >= 0)
+ if (posDrag >= 0) {
InvalidateRange(posDrag, posDrag + 1);
- else
- InvalidateRange(currentPos, currentPos + 1);
+ } else {
+ for (size_t r=0; r<sel.Count(); r++) {
+ InvalidateRange(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1);
+ }
+ }
UpdateSystemCaret();
}
@@ -1757,7 +1809,7 @@ LineLayout *Editor::RetrieveLineLayout(int lineNumber) {
int posLineStart = pdoc->LineStart(lineNumber);
int posLineEnd = pdoc->LineStart(lineNumber + 1);
PLATFORM_ASSERT(posLineEnd >= posLineStart);
- int lineCaret = pdoc->LineFromPosition(currentPos);
+ int lineCaret = pdoc->LineFromPosition(sel.MainCaret());
return llc.Retrieve(lineNumber, lineCaret,
posLineEnd - posLineStart, pdoc->GetStyleClock(),
LinesOnScreen() + 1, pdoc->LinesTotal());
@@ -1884,6 +1936,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou
ll->widthLine = LineLayout::wrapWidthInfinite;
ll->lines = 1;
int numCharsInLine = 0;
+ int numCharsBeforeEOL = 0;
if (vstyle.edgeState == EDGE_BACKGROUND) {
ll->edgeColumn = pdoc->FindColumn(line, theEdge);
if (ll->edgeColumn >= posLineStart) {
@@ -1910,6 +1963,8 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou
else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
ll->chars[numCharsInLine] = static_cast<char>(tolower(chDoc));
numCharsInLine++;
+ if (!IsEOLChar(chDoc))
+ numCharsBeforeEOL++;
}
}
ll->xHighlightGuide = 0;
@@ -1992,6 +2047,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou
ll->positions[startseg] += 2;
}
ll->numCharsInLine = numCharsInLine;
+ ll->numCharsBeforeEOL = numCharsBeforeEOL;
ll->validity = LineLayout::llPositions;
}
// Hard to cope when too narrow, so just assume there is space
@@ -2186,15 +2242,49 @@ void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, Lin
int styleMask = pdoc->stylingBitsMask;
PRectangle rcSegment = rcLine;
+ int virtualSpace = 0;
+ if (subLine == (ll->lines - 1))
+ virtualSpace = sel.VirtualSpaceFor(pdoc->LineEnd(line)) * vsDraw.spaceWidth;
+
// Fill in a PRectangle representing the end of line characters
int xEol = ll->positions[lineEnd] - subLineStart;
- rcSegment.left = xEol + xStart;
- rcSegment.right = xEol + vsDraw.aveCharWidth + xStart;
- int posLineEnd = pdoc->LineStart(line + 1);
- bool eolInSelection = (subLine == (ll->lines - 1)) &&
- (posLineEnd > ll->selStart) && (posLineEnd <= ll->selEnd) && (ll->selStart != ll->selEnd);
- if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
+ if (virtualSpace) {
+ rcSegment.left = xEol + xStart;
+ rcSegment.right = xEol + xStart + virtualSpace;
+ // TODO: draw selection where needed
+ surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
+ }
+
+ int posAfterLineEnd = pdoc->LineStart(line + 1);
+ bool eolInSelection = (subLine == (ll->lines - 1)) && sel.InSelectionForEOL(posAfterLineEnd);
+
+ for (int eolPos=ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine; eolPos++) {
+ rcSegment.left = xStart + ll->positions[eolPos] + virtualSpace;
+ rcSegment.right = xStart + ll->positions[eolPos+1] + virtualSpace;
+ const char *ctrlChar = ControlCharacterString(ll->chars[eolPos]);
+ bool inSelection = false;
+ bool inHotspot = false;
+ int styleMain = ll->styles[eolPos];
+ ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, eolPos, ll);
+ ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
+ if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1)) {
+ if (vsDraw.selAlpha == SC_ALPHA_NOALPHA) {
+ surface->FillRectangle(rcSegment, SelectionBackground(vsDraw));
+ } else {
+ surface->FillRectangle(rcSegment, textBack);
+ SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);
+ }
+ } else {
+ surface->FillRectangle(rcSegment, textBack);
+ }
+ DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw);
+ }
+
+ rcSegment.left = ll->positions[ll->numCharsInLine] + xStart + virtualSpace;
+ rcSegment.right = ll->positions[ll->numCharsInLine] + vsDraw.aveCharWidth + xStart + virtualSpace;
+
+ if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw));
} else {
if (overrideBackground) {
@@ -2202,15 +2292,15 @@ void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, Lin
} else {
surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
}
- if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) {
+ if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) {
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);
}
}
- rcSegment.left = xEol + vsDraw.aveCharWidth + xStart;
+ rcSegment.left = ll->positions[ll->numCharsInLine] + vsDraw.aveCharWidth + xStart + virtualSpace;
rcSegment.right = rcLine.right;
- if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
+ if (!hideSelection && vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw));
} else {
if (overrideBackground) {
@@ -2229,7 +2319,7 @@ void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, Lin
PRectangle rcPlace = rcSegment;
if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) {
- rcPlace.left = xEol + xStart;
+ rcPlace.left = ll->positions[ll->numCharsInLine] + xStart + virtualSpace;
rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
} else {
// draw left of the right text margin, to avoid clipping by the current clip rect
@@ -2427,6 +2517,9 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
if (subLine < ll->lines) {
lineStart = ll->LineStart(subLine);
lineEnd = ll->LineStart(subLine + 1);
+ if (subLine == ll->lines - 1) {
+ lineEnd = ll->numCharsBeforeEOL;
+ }
}
ColourAllocated wrapColour = vsDraw.styles[STYLE_DEFAULT].fore.allocated;
@@ -2481,6 +2574,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
// Does not take margin into account but not significant
int xStartVisible = subLineStart - xStart;
+ ll->psel = &sel;
BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible);
int next = bfBack.First();
@@ -2502,7 +2596,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
int styleMain = ll->styles[i];
- bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
+ const bool inSelection = !hideSelection && sel.CharacterInSelection(iDoc);
bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
if (ll->chars[i] == '\t') {
@@ -2595,7 +2689,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
if (vsDraw.hotspotForegroundSet)
textFore = vsDraw.hotspotForeground.allocated;
}
- bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
+ const bool inSelection = !hideSelection && sel.CharacterInSelection(iDoc);
if (inSelection && (vsDraw.selforeset)) {
textFore = vsDraw.selforeground.allocated;
}
@@ -2767,15 +2861,21 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis
xStart, subLine, subLineStart, overrideBackground, background,
drawWrapMarkEnd, wrapColour);
}
- if ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) && (ll->selStart >= 0) && (ll->selEnd >= 0)) {
- int startPosSel = (ll->selStart < posLineStart) ? posLineStart : ll->selStart;
- int endPosSel = (ll->selEnd < (lineEnd + posLineStart)) ? ll->selEnd : (lineEnd + posLineStart);
- if (startPosSel < endPosSel) {
- rcSegment.left = xStart + ll->positions[startPosSel - posLineStart] - subLineStart;
- rcSegment.right = xStart + ll->positions[endPosSel - posLineStart] - subLineStart;
- rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
- rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
- SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);
+ if (!hideSelection && vsDraw.selAlpha != SC_ALPHA_NOALPHA) {
+ // For each selection draw
+ for (size_t r=0; r<sel.Count(); r++) {
+ SelectionPosition spStart;
+ SelectionPosition spEnd;
+ if (sel.Range(r).Intersect(posLineStart, posLineStart + lineEnd, spStart, spEnd)) {
+ if (!(spStart == spEnd)) {
+ rcSegment.left = xStart + ll->positions[spStart.Position() - posLineStart] - subLineStart + spStart.VirtualSpace() * vsDraw.spaceWidth;
+ rcSegment.right = xStart + ll->positions[spEnd.Position() - posLineStart] - subLineStart + spEnd.VirtualSpace() * vsDraw.spaceWidth;
+ rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
+ rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
+ SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw),
+ (r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAlpha / 2);
+ }
+ }
}
}
@@ -2937,6 +3037,84 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) {
}
}
+void Editor::DrawCarets(Surface *surface, ViewStyle &vsDraw, int lineDoc, int xStart,
+ PRectangle rcLine, LineLayout *ll, int subLine) {
+ // When drag is active it is the only caret drawn
+ bool drawDrag = posDrag != INVALID_POSITION;
+ if (hideSelection && !drawDrag)
+ return;
+ Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1));
+ // For each selection draw
+ for (size_t r=0; (r<sel.Count()) || drawDrag; r++) {
+ const bool mainCaret = r == sel.Main();
+ const int posCaret = (drawDrag ? posDrag : sel.Range(r).caret.Position());
+ const int offset = posCaret - rangeLine.start;
+ const int virtualOffset = drawDrag ? 0 : sel.Range(r).caret.VirtualSpace() * vsDraw.spaceWidth;
+ if (ll->InLine(offset, subLine) && offset <= ll->numCharsInLine) {
+ int xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)] + xStart;
+ if (ll->wrapIndent != 0) {
+ int lineStart = ll->LineStart(subLine);
+ if (lineStart != 0) // Wrapped
+ xposCaret += ll->wrapIndent;
+ }
+ if ((xposCaret >= 0) && (vsDraw.caretWidth > 0) && (vsDraw.caretStyle != CARETSTYLE_INVISIBLE) &&
+ ((posDrag >= 0) || ((caret.active && caret.on) || (!multiLineCaretBlinks && !mainCaret)))) {
+ bool caretAtEOF = false;
+ bool caretAtEOL = false;
+ bool drawBlockCaret = false;
+ int widthOverstrikeCaret;
+ int caretWidthOffset = 0;
+ PRectangle rcCaret = rcLine;
+
+ if (posCaret == pdoc->Length()) { // At end of document
+ caretAtEOF = true;
+ widthOverstrikeCaret = vsDraw.aveCharWidth;
+ } else if ((posCaret - rangeLine.start) >= ll->numCharsInLine) { // At end of line
+ caretAtEOL = true;
+ widthOverstrikeCaret = vsDraw.aveCharWidth;
+ } else {
+ widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset];
+ }
+ if (widthOverstrikeCaret < 3) // Make sure its visible
+ widthOverstrikeCaret = 3;
+
+ if (offset > ll->LineStart(subLine))
+ caretWidthOffset = 1; // Move back so overlaps both character cells.
+ if (posDrag >= 0) {
+ /* Dragging text, use a line caret */
+ rcCaret.left = xposCaret - caretWidthOffset;
+ rcCaret.right = rcCaret.left + vsDraw.caretWidth;
+ } else if (inOverstrike) {
+ /* Overstrike (insert mode), use a modified bar caret */
+ rcCaret.top = rcCaret.bottom - 2;
+ rcCaret.left = xposCaret + 1;
+ rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
+ } else if (vsDraw.caretStyle == CARETSTYLE_BLOCK) {
+ /* Block caret */
+ rcCaret.left = xposCaret;
+ if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) {
+ drawBlockCaret = true;
+ rcCaret.right = xposCaret + widthOverstrikeCaret;
+ } else {
+ rcCaret.right = xposCaret + vsDraw.aveCharWidth;
+ }
+ } else {
+ /* Line caret */
+ rcCaret.left = xposCaret - caretWidthOffset;
+ rcCaret.right = rcCaret.left + vsDraw.caretWidth;
+ }
+ if (drawBlockCaret) {
+ DrawBlockCaret(surface, vsDraw, ll, subLine, xStart, offset, posCaret, rcCaret);
+ } else {
+ surface->FillRectangle(rcCaret, mainCaret ? vsDraw.caretcolour.allocated : vsDraw.selbackground2.allocated);
+ }
+ }
+ }
+ if (drawDrag)
+ break;
+ }
+}
+
void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
//Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
// paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
@@ -3036,7 +3214,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
int visibleLine = topLine + screenLinePaintFirst;
- int posCaret = currentPos;
+ int posCaret = sel.MainCaret();
if (posDrag >= 0)
posCaret = posDrag;
int lineCaret = pdoc->LineFromPosition(posCaret);
@@ -3055,7 +3233,6 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
//ElapsedTime etWhole;
int lineDocPrevious = -1; // Used to avoid laying out one document line multiple times
AutoLineLayout ll(llc, 0);
- SelectionLineIterator lineIterator(this);
while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) {
int lineDoc = cs.DocFromDisplay(visibleLine);
@@ -3069,8 +3246,6 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
//ElapsedTime et;
if (lineDoc != lineDocPrevious) {
ll.Set(0);
- // For rectangular selection this accesses the layout cache so should be after layout returned.
- lineIterator.SetAt(lineDoc);
ll.Set(RetrieveLineLayout(lineDoc));
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
lineDocPrevious = lineDoc;
@@ -3078,17 +3253,8 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
//durLayout += et.Duration(true);
if (ll) {
- if (selType == selStream) {
- ll->selStart = SelectionStart();
- ll->selEnd = SelectionEnd();
- } else {
- ll->selStart = lineIterator.startPos;
- ll->selEnd = lineIterator.endPos;
- }
ll->containsCaret = lineDoc == lineCaret;
if (hideSelection) {
- ll->selStart = -1;
- ll->selEnd = -1;
ll->containsCaret = false;
}
@@ -3132,71 +3298,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
}
}
- // Draw the Caret
- if (lineDoc == lineCaret) {
- int offset = Platform::Minimum(posCaret - rangeLine.start, ll->maxLineLength);
- if (ll->InLine(offset, subLine)) {
- int xposCaret = ll->positions[offset] - ll->positions[ll->LineStart(subLine)] + xStart;
-
- if (ll->wrapIndent != 0) {
- int lineStart = ll->LineStart(subLine);
- if (lineStart != 0) // Wrapped
- xposCaret += ll->wrapIndent;
- }
- if ((xposCaret >= 0) && (vs.caretWidth > 0) && (vs.caretStyle != CARETSTYLE_INVISIBLE) &&
- ((posDrag >= 0) || (caret.active && caret.on))) {
- bool caretAtEOF = false;
- bool caretAtEOL = false;
- bool drawBlockCaret = false;
- int widthOverstrikeCaret;
- int caretWidthOffset = 0;
- PRectangle rcCaret = rcLine;
-
- if (posCaret == pdoc->Length()) { // At end of document
- caretAtEOF = true;
- widthOverstrikeCaret = vs.aveCharWidth;
- } else if ((posCaret - rangeLine.start) >= ll->numCharsInLine) { // At end of line
- caretAtEOL = true;
- widthOverstrikeCaret = vs.aveCharWidth;
- } else {
- widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset];
- }
- if (widthOverstrikeCaret < 3) // Make sure its visible
- widthOverstrikeCaret = 3;
-
- if (offset > ll->LineStart(subLine))
- caretWidthOffset = 1; // Move back so overlaps both character cells.
- if (posDrag >= 0) {
- /* Dragging text, use a line caret */
- rcCaret.left = xposCaret - caretWidthOffset;
- rcCaret.right = rcCaret.left + vs.caretWidth;
- } else if (inOverstrike) {
- /* Overstrike (insert mode), use a modified bar caret */
- rcCaret.top = rcCaret.bottom - 2;
- rcCaret.left = xposCaret + 1;
- rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
- } else if (vs.caretStyle == CARETSTYLE_BLOCK) {
- /* Block caret */
- rcCaret.left = xposCaret;
- if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) {
- drawBlockCaret = true;
- rcCaret.right = xposCaret + widthOverstrikeCaret;
- } else {
- rcCaret.right = xposCaret + vs.aveCharWidth;
- }
- } else {
- /* Line caret */
- rcCaret.left = xposCaret - caretWidthOffset;
- rcCaret.right = rcCaret.left + vs.caretWidth;
- }
- if (drawBlockCaret) {
- DrawBlockCaret(surface, vs, ll, subLine, xStart, offset, posCaret, rcCaret);
- } else {
- surface->FillRectangle(rcCaret, vs.caretcolour.allocated);
- }
- }
- }
- }
+ DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine);
if (bufferedDraw) {
Point from(vs.fixedColumnWidth, 0);
@@ -3375,8 +3477,6 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) {
LineLayout ll(8000);
LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
- ll.selStart = -1;
- ll.selEnd = -1;
ll.containsCaret = false;
PRectangle rcLine;
@@ -3508,32 +3608,61 @@ void Editor::AddChar(char ch) {
// AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) {
- bool wasSelection = currentPos != anchor;
- ClearSelection();
- bool charReplaceAction = false;
- if (inOverstrike && !wasSelection && !RangeContainsProtected(currentPos, currentPos + 1)) {
- if (currentPos < (pdoc->Length())) {
- if (!IsEOLChar(pdoc->CharAt(currentPos))) {
- charReplaceAction = true;
- pdoc->BeginUndoAction();
- pdoc->DelChar(currentPos);
+ const bool undoBracketNeeded = (sel.Count() > 1) || !sel.Empty() || inOverstrike;
+ if (undoBracketNeeded)
+ pdoc->BeginUndoAction();
+ for (size_t r=0; r<sel.Count(); r++) {
+ if (!RangeContainsProtected(sel.Range(r).Start().Position(),
+ sel.Range(r).End().Position())) {
+ int positionInsert = sel.Range(r).Start().Position();
+ if (!sel.Range(r).Empty()) {
+ if (sel.Range(r).Length()) {
+ pdoc->DeleteChars(positionInsert, sel.Range(r).Length());
+ sel.ClearVirtualSpace(r);
+ } else {
+ // Range is all virtual so collapse to start of virtual space
+ sel.Range(r).MinimizeVirtualSpace();
+ }
+ } else if (inOverstrike) {
+ if (positionInsert < pdoc->Length()) {
+ if (!IsEOLChar(pdoc->CharAt(positionInsert))) {
+ pdoc->DelChar(positionInsert);
+ sel.ClearVirtualSpace(r);
+ }
+ }
+ }
+ const unsigned int spaces = sel.Range(r).caret.VirtualSpace();
+ if (spaces > 0) {
+ char *spaceText = new char[spaces];
+ memset(spaceText, ' ', spaces);
+ pdoc->InsertString(positionInsert, spaceText, spaces);
+ positionInsert += spaces;
+ delete []spaceText;
+ }
+ if (pdoc->InsertString(positionInsert, s, len)) {
+ sel.Range(r).caret.SetPosition(positionInsert + len);
+ sel.Range(r).anchor.SetPosition(positionInsert + len);
+ }
+ sel.ClearVirtualSpace(r);
+ // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
+ if (wrapState != eWrapNone) {
+ AutoSurface surface(this);
+ if (surface) {
+ WrapOneLine(surface, pdoc->LineFromPosition(positionInsert));
+ }
}
}
}
- if (pdoc->InsertString(currentPos, s, len)) {
- SetEmptySelection(currentPos + len);
- }
- if (charReplaceAction) {
+ if (undoBracketNeeded)
pdoc->EndUndoAction();
- }
- // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
if (wrapState != eWrapNone) {
- AutoSurface surface(this);
- if (surface) {
- WrapOneLine(surface, pdoc->LineFromPosition(currentPos));
- }
SetScrollBars();
}
+ if (sel.IsRectangular()) {
+ sel.selType = Selection::selThin;
+ sel.Rectangular() = SelectionRange(sel.Rectangular().caret, sel.Range(0).anchor);
+ }
+ // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
EnsureCaretVisible();
// Avoid blinking during rapid typing:
ShowCaretAtCurrentPosition();
@@ -3580,30 +3709,19 @@ void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) {
}
void Editor::ClearSelection() {
- if (!SelectionContainsProtected()) {
- int startPos = SelectionStart();
- if (selType == selStream) {
- unsigned int chars = SelectionEnd() - startPos;
- if (0 != chars) {
- pdoc->BeginUndoAction();
- pdoc->DeleteChars(startPos, chars);
- pdoc->EndUndoAction();
- }
- } else {
- pdoc->BeginUndoAction();
- SelectionLineIterator lineIterator(this, false);
- while (lineIterator.Iterate()) {
- startPos = lineIterator.startPos;
- unsigned int chars = lineIterator.endPos - startPos;
- if (0 != chars) {
- pdoc->DeleteChars(startPos, chars);
- }
+ pdoc->BeginUndoAction();
+ for (size_t r=0; r<sel.Count(); r++) {
+ if (!sel.Range(r).Empty()) {
+ if (!RangeContainsProtected(sel.Range(r).Start().Position(),
+ sel.Range(r).End().Position())) {
+ pdoc->DeleteChars(sel.Range(r).Start().Position(),
+ sel.Range(r).Length());
+ sel.ClearVirtualSpace(r);
}
- pdoc->EndUndoAction();
- selType = selStream;
}
- SetEmptySelection(startPos);
}
+ pdoc->EndUndoAction();
+
}
void Editor::ClearAll() {
@@ -3617,8 +3735,7 @@ void Editor::ClearAll() {
pdoc->MarginClearAll();
}
pdoc->EndUndoAction();
- anchor = 0;
- currentPos = 0;
+ sel.Clear();
SetTopLine(0);
SetVerticalScrollPos();
InvalidateStyleRedraw();
@@ -3655,13 +3772,14 @@ void Editor::Cut() {
}
}
-void Editor::PasteRectangular(int pos, const char *ptr, int len) {
+void Editor::PasteRectangular(SelectionPosition pos, const char *ptr, int len) {
if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
return;
}
- currentPos = pos;
- int xInsert = XFromPosition(currentPos);
- int line = pdoc->LineFromPosition(currentPos);
+ sel.Clear();
+ sel.RangeMain() = SelectionRange(pos, pos);
+ int xInsert = XFromPosition(sel.RangeMain().caret);
+ int line = pdoc->LineFromPosition(sel.MainCaret());
bool prevCr = false;
pdoc->BeginUndoAction();
for (int i = 0; i < len; i++) {
@@ -3675,17 +3793,17 @@ void Editor::PasteRectangular(int pos, const char *ptr, int len) {
pdoc->InsertChar(pdoc->Length(), '\n');
}
// Pad the end of lines with spaces if required
- currentPos = PositionFromLineX(line, xInsert);
- if ((XFromPosition(currentPos) < xInsert) && (i + 1 < len)) {
- while (XFromPosition(currentPos) < xInsert) {
- pdoc->InsertChar(currentPos, ' ');
- currentPos++;
+ sel.RangeMain().caret.SetPosition(PositionFromLineX(line, xInsert));
+ if ((XFromPosition(sel.MainCaret()) < xInsert) && (i + 1 < len)) {
+ while (XFromPosition(sel.MainCaret()) < xInsert) {
+ pdoc->InsertChar(sel.MainCaret(), ' ');
+ sel.RangeMain().caret.Add(1);
}
}
prevCr = ptr[i] == '\r';
} else {
- pdoc->InsertString(currentPos, ptr + i, 1);
- currentPos++;
+ pdoc->InsertString(sel.MainCaret(), ptr + i, 1);
+ sel.RangeMain().caret.Add(1);
prevCr = false;
}
}
@@ -3698,14 +3816,28 @@ bool Editor::CanPaste() {
}
void Editor::Clear() {
- if (currentPos == anchor) {
- if (!RangeContainsProtected(currentPos, currentPos + 1)) {
- DelChar();
+ const bool undoBracketNeeded = (sel.Count() > 1) || !sel.Empty();
+ // If multiple selections, don't delete EOLS
+ if (undoBracketNeeded)
+ pdoc->BeginUndoAction();
+ if (sel.Empty()) {
+ pdoc->BeginUndoAction();
+ for (size_t r=0; r<sel.Count(); r++) {
+ if (!RangeContainsProtected(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1)) {
+ if ((sel.Count() == 1) || !IsEOLChar(pdoc->CharAt(sel.Range(r).caret.Position()))) {
+ pdoc->DelChar(sel.Range(r).caret.Position());
+ sel.ClearVirtualSpace(r);
+ } // else multiple selection so don't eat line ends
+ } else {
+ sel.ClearVirtualSpace(r);
+ }
}
+ pdoc->EndUndoAction();
} else {
ClearSelection();
}
- SetEmptySelection(currentPos);
+ if (undoBracketNeeded)
+ pdoc->EndUndoAction();
}
void Editor::SelectAll() {
@@ -3733,20 +3865,57 @@ void Editor::Redo() {
}
void Editor::DelChar() {
- if (!RangeContainsProtected(currentPos, currentPos + 1)) {
- pdoc->DelChar(currentPos);
+ if (!RangeContainsProtected(sel.MainCaret(), sel.MainCaret() + 1)) {
+ pdoc->DelChar(sel.MainCaret());
}
// Avoid blinking during rapid typing:
ShowCaretAtCurrentPosition();
}
void Editor::DelCharBack(bool allowLineStartDeletion) {
- if (currentPos == anchor) {
- if (!RangeContainsProtected(currentPos - 1, currentPos)) {
- int lineCurrentPos = pdoc->LineFromPosition(currentPos);
- if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != currentPos)) {
- if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) &&
- pdoc->GetColumn(currentPos) > 0 && pdoc->backspaceUnindents) {
+ const bool undoBracketNeeded = (sel.Count() > 1) || !sel.Empty();
+ if (undoBracketNeeded)
+ pdoc->BeginUndoAction();
+ if (sel.Empty()) {
+ for (size_t r=0; r<sel.Count(); r++) {
+ if (!RangeContainsProtected(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1)) {
+ if (sel.Range(r).caret.VirtualSpace()) {
+ sel.Range(r).caret.SetVirtualSpace(sel.Range(r).caret.VirtualSpace() - 1);
+ sel.Range(r).anchor.SetVirtualSpace(sel.Range(r).caret.VirtualSpace());
+ } else {
+ int lineCurrentPos = pdoc->LineFromPosition(sel.Range(r).caret.Position());
+ if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != sel.Range(r).caret.Position())) {
+ if (pdoc->GetColumn(sel.Range(r).caret.Position()) <= pdoc->GetLineIndentation(lineCurrentPos) &&
+ pdoc->GetColumn(sel.Range(r).caret.Position()) > 0 && pdoc->backspaceUnindents) {
+ if (!undoBracketNeeded)
+ pdoc->BeginUndoAction();
+ int indentation = pdoc->GetLineIndentation(lineCurrentPos);
+ int indentationStep = pdoc->IndentSize();
+ if (indentation % indentationStep == 0) {
+ pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
+ } else {
+ pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep));
+ }
+ // SetEmptySelection
+ sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos),
+ pdoc->GetLineIndentPosition(lineCurrentPos));
+ if (!undoBracketNeeded)
+ pdoc->EndUndoAction();
+ } else {
+ pdoc->DelCharBack(sel.Range(r).caret.Position());
+ }
+ }
+ }
+ } else {
+ sel.ClearVirtualSpace(r);
+ }
+ }
+ /*
+ if (!RangeContainsProtected(sel.MainCaret() - 1, sel.MainCaret())) {
+ int lineCurrentPos = pdoc->LineFromPosition(sel.MainCaret());
+ if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != sel.MainCaret())) {
+ if (pdoc->GetColumn(sel.MainCaret()) <= pdoc->GetLineIndentation(lineCurrentPos) &&
+ pdoc->GetColumn(sel.MainCaret()) > 0 && pdoc->backspaceUnindents) {
pdoc->BeginUndoAction();
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
int indentationStep = pdoc->IndentSize();
@@ -3758,14 +3927,17 @@ void Editor::DelCharBack(bool allowLineStartDeletion) {
SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
pdoc->EndUndoAction();
} else {
- pdoc->DelCharBack(currentPos);
+ pdoc->DelCharBack(sel.MainCaret());
}
}
}
+ */
} else {
ClearSelection();
- SetEmptySelection(currentPos);
+ SetEmptySelection(sel.MainCaret());
}
+ if (undoBracketNeeded)
+ pdoc->EndUndoAction();
// Avoid blinking during rapid typing:
ShowCaretAtCurrentPosition();
}
@@ -3990,13 +4162,11 @@ void Editor::NotifyModified(Document*, DocModification mh, void *) {
} else {
// Move selection and brace highlights
if (mh.modificationType & SC_MOD_INSERTTEXT) {
- currentPos = MovePositionForInsertion(currentPos, mh.position, mh.length);
- anchor = MovePositionForInsertion(anchor, mh.position, mh.length);
+ sel.MovePositions(true, mh.position, mh.length);
braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length);
braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length);
} else if (mh.modificationType & SC_MOD_DELETETEXT) {
- currentPos = MovePositionForDeletion(currentPos, mh.position, mh.length);
- anchor = MovePositionForDeletion(anchor, mh.position, mh.length);
+ sel.MovePositions(false, mh.position, mh.length);
braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length);
braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length);
}
@@ -4228,11 +4398,11 @@ void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lPar
* If stuttered = true and not already at first/last row, move to first/last row of window.
* If stuttered = true and already at first/last row, scroll as normal.
*/
-void Editor::PageMove(int direction, selTypes sel, bool stuttered) {
+void Editor::PageMove(int direction, Selection::selTypes selt, bool stuttered) {
int topLineNew, newPos;
// I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem?
- int currentLine = pdoc->LineFromPosition(currentPos);
+ int currentLine = pdoc->LineFromPosition(sel.MainCaret());
int topStutterLine = topLine + caretYSlop;
int bottomStutterLine =
pdoc->LineFromPosition(PositionFromLocation(
@@ -4248,7 +4418,7 @@ void Editor::PageMove(int direction, selTypes sel, bool stuttered) {
newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * (LinesToScroll() - caretYSlop)));
} else {
- Point pt = LocationFromPosition(currentPos);
+ Point pt = LocationFromPosition(sel.MainCaret());
topLineNew = Platform::Clamp(
topLine + direction * LinesToScroll(), 0, MaxScrollPos());
@@ -4258,37 +4428,28 @@ void Editor::PageMove(int direction, selTypes sel, bool stuttered) {
if (topLineNew != topLine) {
SetTopLine(topLineNew);
- MovePositionTo(newPos, sel);
+ MovePositionTo(SelectionPosition(newPos), selt);
Redraw();
SetVerticalScrollPos();
} else {
- MovePositionTo(newPos, sel);
+ MovePositionTo(SelectionPosition(newPos), selt);
}
}
void Editor::ChangeCaseOfSelection(bool makeUpperCase) {
pdoc->BeginUndoAction();
- int startCurrent = currentPos;
- int startAnchor = anchor;
- if (selType == selStream) {
- pdoc->ChangeCase(Range(SelectionStart(), SelectionEnd()),
- makeUpperCase);
- SetSelection(startCurrent, startAnchor);
- } else {
- SelectionLineIterator lineIterator(this, false);
- while (lineIterator.Iterate()) {
- pdoc->ChangeCase(
- Range(lineIterator.startPos, lineIterator.endPos),
- makeUpperCase);
- }
- // Would be nicer to keep the rectangular selection but this is complex
- SetEmptySelection(startCurrent);
+ for (size_t r=0; r<sel.Count(); r++) {
+ SelectionRange current = sel.Range(r);
+ pdoc->ChangeCase(Range(current.Start().Position(), current.End().Position()),
+ makeUpperCase);
+ // Automatic movement cuts off last character so reset to exactly the same as it was.
+ sel.Range(r) = current;
}
pdoc->EndUndoAction();
}
void Editor::LineTranspose() {
- int line = pdoc->LineFromPosition(currentPos);
+ int line = pdoc->LineFromPosition(sel.MainCaret());
if (line > 0) {
pdoc->BeginUndoAction();
int startPrev = pdoc->LineStart(line - 1);
@@ -4303,7 +4464,7 @@ void Editor::LineTranspose() {
pdoc->DeleteChars(startPrev, len1);
pdoc->InsertString(startPrev, line2, len2);
pdoc->InsertString(start - len1 + len2, line1, len1);
- MovePositionTo(start - len1 + len2);
+ MovePositionTo(SelectionPosition(start - len1 + len2));
delete []line1;
delete []line2;
pdoc->EndUndoAction();
@@ -4311,13 +4472,14 @@ void Editor::LineTranspose() {
}
void Editor::Duplicate(bool forLine) {
+ // TODO: multiple selection by duplicating each selection
int start = SelectionStart();
int end = SelectionEnd();
- if (start == end) {
+ if (sel.Empty()) {
forLine = true;
}
if (forLine) {
- int line = pdoc->LineFromPosition(currentPos);
+ int line = pdoc->LineFromPosition(sel.MainCaret());
start = pdoc->LineStart(line);
end = pdoc->LineEnd(line);
}
@@ -4333,7 +4495,7 @@ void Editor::Duplicate(bool forLine) {
}
void Editor::CancelModes() {
- moveExtendsSelection = false;
+ sel.SetMoveExtends(false);
}
void Editor::NewLine() {
@@ -4344,8 +4506,8 @@ void Editor::NewLine() {
} else if (pdoc->eolMode == SC_EOL_CR) {
eol = "\r";
} // else SC_EOL_LF -> "\n" already set
- if (pdoc->InsertCString(currentPos, eol)) {
- SetEmptySelection(currentPos + istrlen(eol));
+ if (pdoc->InsertCString(sel.MainCaret(), eol)) {
+ SetEmptySelection(sel.MainCaret() + istrlen(eol));
while (*eol) {
NotifyChar(*eol);
eol++;
@@ -4358,16 +4520,16 @@ void Editor::NewLine() {
ShowCaretAtCurrentPosition();
}
-void Editor::CursorUpOrDown(int direction, selTypes sel) {
- Point pt = LocationFromPosition(currentPos);
- int lineDoc = pdoc->LineFromPosition(currentPos);
+void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) {
+ Point pt = LocationFromPosition(sel.MainCaret());
+ int lineDoc = pdoc->LineFromPosition(sel.MainCaret());
Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc));
int subLine = (pt.y - ptStartLine.y) / vs.lineHeight;
int commentLines = vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0;
- int posNew = PositionFromLocation(
+ SelectionPosition posNew = SPositionFromLocation(
Point(lastXChosen, pt.y + direction * vs.lineHeight));
if ((direction > 0) && (subLine >= (cs.GetHeight(lineDoc) - 1 - commentLines))) {
- posNew = PositionFromLocation(
+ posNew = SPositionFromLocation(
Point(lastXChosen, pt.y + (commentLines + 1) * vs.lineHeight));
}
if (direction < 0) {
@@ -4375,24 +4537,25 @@ void Editor::CursorUpOrDown(int direction, selTypes sel) {
// seek back if that is the case.
// There is an equivalent case when moving down which skips
// over a line but as that does not trap the user it is fine.
- Point ptNew = LocationFromPosition(posNew);
- while ((posNew > 0) && (pt.y == ptNew.y)) {
- posNew--;
- ptNew = LocationFromPosition(posNew);
+ Point ptNew = LocationFromPosition(posNew.Position());
+ while ((posNew.Position() > 0) && (pt.y == ptNew.y)) {
+ posNew.Add(- 1);
+ posNew.SetVirtualSpace(0);
+ ptNew = LocationFromPosition(posNew.Position());
}
}
- MovePositionTo(posNew, sel);
+ MovePositionTo(posNew, selt);
}
-void Editor::ParaUpOrDown(int direction, selTypes sel) {
- int lineDoc, savedPos = currentPos;
+void Editor::ParaUpOrDown(int direction, Selection::selTypes selt) {
+ int lineDoc, savedPos = sel.MainCaret();
do {
- MovePositionTo(direction > 0 ? pdoc->ParaDown(currentPos) : pdoc->ParaUp(currentPos), sel);
- lineDoc = pdoc->LineFromPosition(currentPos);
+ MovePositionTo(SelectionPosition(direction > 0 ? pdoc->ParaDown(sel.MainCaret()) : pdoc->ParaUp(sel.MainCaret())), selt);
+ lineDoc = pdoc->LineFromPosition(sel.MainCaret());
if (direction > 0) {
- if (currentPos >= pdoc->Length() && !cs.GetVisible(lineDoc)) {
- if (sel == noSel) {
- MovePositionTo(pdoc->LineEndPosition(savedPos));
+ if (sel.MainCaret() >= pdoc->Length() && !cs.GetVisible(lineDoc)) {
+ if (selt == Selection::noSel) {
+ MovePositionTo(SelectionPosition(pdoc->LineEndPosition(savedPos)));
}
break;
}
@@ -4438,16 +4601,16 @@ int Editor::KeyCommand(unsigned int iMessage) {
CursorUpOrDown(1);
break;
case SCI_LINEDOWNEXTEND:
- CursorUpOrDown(1, selStream);
+ CursorUpOrDown(1, Selection::selStream);
break;
case SCI_LINEDOWNRECTEXTEND:
- CursorUpOrDown(1, selRectangle);
+ CursorUpOrDown(1, Selection::selRectangle);
break;
case SCI_PARADOWN:
ParaUpOrDown(1);
break;
case SCI_PARADOWNEXTEND:
- ParaUpOrDown(1, selStream);
+ ParaUpOrDown(1, Selection::selStream);
break;
case SCI_LINESCROLLDOWN:
ScrollTo(topLine + 1);
@@ -4457,144 +4620,180 @@ int Editor::KeyCommand(unsigned int iMessage) {
CursorUpOrDown(-1);
break;
case SCI_LINEUPEXTEND:
- CursorUpOrDown(-1, selStream);
+ CursorUpOrDown(-1, Selection::selStream);
break;
case SCI_LINEUPRECTEXTEND:
- CursorUpOrDown(-1, selRectangle);
+ CursorUpOrDown(-1, Selection::selRectangle);
break;
case SCI_PARAUP:
ParaUpOrDown(-1);
break;
case SCI_PARAUPEXTEND:
- ParaUpOrDown(-1, selStream);
+ ParaUpOrDown(-1, Selection::selStream);
break;
case SCI_LINESCROLLUP:
ScrollTo(topLine - 1);
MoveCaretInsideView(false);
break;
case SCI_CHARLEFT:
- if (SelectionEmpty() || moveExtendsSelection) {
- MovePositionTo(MovePositionSoVisible(currentPos - 1, -1));
+ if (SelectionEmpty() || sel.MoveExtends()) {
+ if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
+ SelectionPosition spCaret = sel.RangeMain().caret;
+ spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
+ MovePositionTo(spCaret);
+ } else {
+ MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1));
+ }
} else {
- MovePositionTo(SelectionStart());
+ MovePositionTo(sel.RangeMain().Start());
}
SetLastXChosen();
break;
case SCI_CHARLEFTEXTEND:
- MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selStream);
+ if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
+ SelectionPosition spCaret = sel.RangeMain().caret;
+ spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
+ MovePositionTo(spCaret, Selection::selStream);
+ } else {
+ MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selStream);
+ }
SetLastXChosen();
break;
case SCI_CHARLEFTRECTEXTEND:
- MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selRectangle);
+ if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) {
+ SelectionPosition spCaret = sel.RangeMain().caret;
+ spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1);
+ MovePositionTo(spCaret, Selection::selRectangle);
+ } else {
+ MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selRectangle);
+ }
SetLastXChosen();
break;
case SCI_CHARRIGHT:
- if (SelectionEmpty() || moveExtendsSelection) {
- MovePositionTo(MovePositionSoVisible(currentPos + 1, 1));
+ if (SelectionEmpty() || sel.MoveExtends()) {
+ if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) {
+ SelectionPosition spCaret = sel.RangeMain().caret;
+ spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
+ MovePositionTo(spCaret);
+ } else {
+ MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1));
+ }
} else {
- MovePositionTo(SelectionEnd());
+ MovePositionTo(sel.RangeMain().End());
}
SetLastXChosen();
break;
case SCI_CHARRIGHTEXTEND:
- MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selStream);
+ if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) {
+ SelectionPosition spCaret = sel.RangeMain().caret;
+ spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
+ MovePositionTo(spCaret, Selection::selStream);
+ } else {
+ MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selStream);
+ }
SetLastXChosen();
break;
case SCI_CHARRIGHTRECTEXTEND:
- MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selRectangle);
+ if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) && pdoc->IsLineEndPosition(sel.MainCaret())) {
+ SelectionPosition spCaret = sel.RangeMain().caret;
+ spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1);
+ MovePositionTo(spCaret, Selection::selRectangle);
+ } else {
+ MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selRectangle);
+ }
SetLastXChosen();
break;
case SCI_WORDLEFT:
- MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1));
+ MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1));
SetLastXChosen();
break;
case SCI_WORDLEFTEXTEND:
- MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1), selStream);
+ MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1), Selection::selStream);
SetLastXChosen();
break;
case SCI_WORDRIGHT:
- MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1));
+ MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1));
SetLastXChosen();
break;
case SCI_WORDRIGHTEXTEND:
- MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1), selStream);
+ MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1), Selection::selStream);
SetLastXChosen();
break;
case SCI_WORDLEFTEND:
- MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1));
+ MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1));
SetLastXChosen();
break;
case SCI_WORDLEFTENDEXTEND:
- MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1), selStream);
+ MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1), Selection::selStream);
SetLastXChosen();
break;
case SCI_WORDRIGHTEND:
- MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1));
+ MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1));
SetLastXChosen();
break;
case SCI_WORDRIGHTENDEXTEND:
- MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1), selStream);
+ MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1), Selection::selStream);
SetLastXChosen();
break;
case SCI_HOME:
- MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)));
+ MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
SetLastXChosen();
break;
case SCI_HOMEEXTEND:
- MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selStream);
+ MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selStream);
SetLastXChosen();
break;
case SCI_HOMERECTEXTEND:
- MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selRectangle);
+ MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selRectangle);
SetLastXChosen();
break;
case SCI_LINEEND:
- MovePositionTo(pdoc->LineEndPosition(currentPos));
+ MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()));
SetLastXChosen();
break;
case SCI_LINEENDEXTEND:
- MovePositionTo(pdoc->LineEndPosition(currentPos), selStream);
+ MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selStream);
SetLastXChosen();
break;
case SCI_LINEENDRECTEXTEND:
- MovePositionTo(pdoc->LineEndPosition(currentPos), selRectangle);
+ MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selRectangle);
SetLastXChosen();
break;
case SCI_HOMEWRAP: {
- int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
- if (currentPos <= homePos)
- homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos));
+ SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
+ if (sel.RangeMain().caret <= homePos)
+ homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
MovePositionTo(homePos);
SetLastXChosen();
}
break;
case SCI_HOMEWRAPEXTEND: {
- int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
- if (currentPos <= homePos)
- homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos));
- MovePositionTo(homePos, selStream);
+ SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
+ if (sel.RangeMain().caret <= homePos)
+ homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));
+ MovePositionTo(homePos, Selection::selStream);
SetLastXChosen();
}
break;
case SCI_LINEENDWRAP: {
- int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1);
- int realEndPos = pdoc->LineEndPosition(currentPos);
+ SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1);
+ SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret()));
if (endPos > realEndPos // if moved past visible EOLs
- || currentPos >= endPos) // if at end of display line already
+ || sel.RangeMain().caret >= endPos) // if at end of display line already
endPos = realEndPos;
MovePositionTo(endPos);
SetLastXChosen();
}
break;
case SCI_LINEENDWRAPEXTEND: {
- int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1);
- int realEndPos = pdoc->LineEndPosition(currentPos);
+ SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1);
+ SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret()));
if (endPos > realEndPos // if moved past visible EOLs
- || currentPos >= endPos) // if at end of display line already
+ || sel.RangeMain().caret >= endPos) // if at end of display line already
endPos = realEndPos;
- MovePositionTo(endPos, selStream);
+ MovePositionTo(endPos, Selection::selStream);
SetLastXChosen();
}
break;
@@ -4603,7 +4802,7 @@ int Editor::KeyCommand(unsigned int iMessage) {
SetLastXChosen();
break;
case SCI_DOCUMENTSTARTEXTEND:
- MovePositionTo(0, selStream);
+ MovePositionTo(0, Selection::selStream);
SetLastXChosen();
break;
case SCI_DOCUMENTEND:
@@ -4611,38 +4810,38 @@ int Editor::KeyCommand(unsigned int iMessage) {
SetLastXChosen();
break;
case SCI_DOCUMENTENDEXTEND:
- MovePositionTo(pdoc->Length(), selStream);
+ MovePositionTo(pdoc->Length(), Selection::selStream);
SetLastXChosen();
break;
case SCI_STUTTEREDPAGEUP:
- PageMove(-1, noSel, true);
+ PageMove(-1, Selection::noSel, true);
break;
case SCI_STUTTEREDPAGEUPEXTEND:
- PageMove(-1, selStream, true);
+ PageMove(-1, Selection::selStream, true);
break;
case SCI_STUTTEREDPAGEDOWN:
- PageMove(1, noSel, true);
+ PageMove(1, Selection::noSel, true);
break;
case SCI_STUTTEREDPAGEDOWNEXTEND:
- PageMove(1, selStream, true);
+ PageMove(1, Selection::selStream, true);
break;
case SCI_PAGEUP:
PageMove(-1);
break;
case SCI_PAGEUPEXTEND:
- PageMove(-1, selStream);
+ PageMove(-1, Selection::selStream);
break;
case SCI_PAGEUPRECTEXTEND:
- PageMove(-1, selRectangle);
+ PageMove(-1, Selection::selRectangle);
break;
case SCI_PAGEDOWN:
PageMove(1);
break;
case SCI_PAGEDOWNEXTEND:
- PageMove(1, selStream);
+ PageMove(1, Selection::selStream);
break;
case SCI_PAGEDOWNRECTEXTEND:
- PageMove(1, selRectangle);
+ PageMove(1, Selection::selRectangle);
break;
case SCI_EDITTOGGLEOVERTYPE:
inOverstrike = !inOverstrike;
@@ -4691,21 +4890,21 @@ int Editor::KeyCommand(unsigned int iMessage) {
AddChar('\f');
break;
case SCI_VCHOME:
- MovePositionTo(pdoc->VCHomePosition(currentPos));
+ MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()));
SetLastXChosen();
break;
case SCI_VCHOMEEXTEND:
- MovePositionTo(pdoc->VCHomePosition(currentPos), selStream);
+ MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selStream);
SetLastXChosen();
break;
case SCI_VCHOMERECTEXTEND:
- MovePositionTo(pdoc->VCHomePosition(currentPos), selRectangle);
+ MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selRectangle);
SetLastXChosen();
break;
case SCI_VCHOMEWRAP: {
- int homePos = pdoc->VCHomePosition(currentPos);
- int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
- if ((viewLineStart < currentPos) && (viewLineStart > homePos))
+ SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret()));
+ SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
+ if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos))
homePos = viewLineStart;
MovePositionTo(homePos);
@@ -4713,12 +4912,12 @@ int Editor::KeyCommand(unsigned int iMessage) {
}
break;
case SCI_VCHOMEWRAPEXTEND: {
- int homePos = pdoc->VCHomePosition(currentPos);
- int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
- if ((viewLineStart < currentPos) && (viewLineStart > homePos))
+ SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret()));
+ SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1);
+ if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos))
homePos = viewLineStart;
- MovePositionTo(homePos, selStream);
+ MovePositionTo(homePos, Selection::selStream);
SetLastXChosen();
}
break;
@@ -4737,32 +4936,32 @@ int Editor::KeyCommand(unsigned int iMessage) {
}
break;
case SCI_DELWORDLEFT: {
- int startWord = pdoc->NextWordStart(currentPos, -1);
- pdoc->DeleteChars(startWord, currentPos - startWord);
+ int startWord = pdoc->NextWordStart(sel.MainCaret(), -1);
+ pdoc->DeleteChars(startWord, sel.MainCaret() - startWord);
SetLastXChosen();
}
break;
case SCI_DELWORDRIGHT: {
- int endWord = pdoc->NextWordStart(currentPos, 1);
- pdoc->DeleteChars(currentPos, endWord - currentPos);
+ int endWord = pdoc->NextWordStart(sel.MainCaret(), 1);
+ pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret());
}
break;
case SCI_DELWORDRIGHTEND: {
- int endWord = pdoc->NextWordEnd(currentPos, 1);
- pdoc->DeleteChars(currentPos, endWord - currentPos);
+ int endWord = pdoc->NextWordEnd(sel.MainCaret(), 1);
+ pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret());
}
break;
case SCI_DELLINELEFT: {
- int line = pdoc->LineFromPosition(currentPos);
+ int line = pdoc->LineFromPosition(sel.MainCaret());
int start = pdoc->LineStart(line);
- pdoc->DeleteChars(start, currentPos - start);
+ pdoc->DeleteChars(start, sel.MainCaret() - start);
SetLastXChosen();
}
break;
case SCI_DELLINERIGHT: {
- int line = pdoc->LineFromPosition(currentPos);
+ int line = pdoc->LineFromPosition(sel.MainCaret());
int end = pdoc->LineEnd(line);
- pdoc->DeleteChars(currentPos, end - currentPos);
+ pdoc->DeleteChars(sel.MainCaret(), end - sel.MainCaret());
}
break;
case SCI_LINECOPY: {
@@ -4783,7 +4982,7 @@ int Editor::KeyCommand(unsigned int iMessage) {
}
break;
case SCI_LINEDELETE: {
- int line = pdoc->LineFromPosition(currentPos);
+ int line = pdoc->LineFromPosition(sel.MainCaret());
int start = pdoc->LineStart(line);
int end = pdoc->LineStart(line + 1);
pdoc->DeleteChars(start, end - start);
@@ -4805,39 +5004,39 @@ int Editor::KeyCommand(unsigned int iMessage) {
ChangeCaseOfSelection(true);
break;
case SCI_WORDPARTLEFT:
- MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1));
+ MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1));
SetLastXChosen();
break;
case SCI_WORDPARTLEFTEXTEND:
- MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1), selStream);
+ MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1), Selection::selStream);
SetLastXChosen();
break;
case SCI_WORDPARTRIGHT:
- MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1));
+ MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1));
SetLastXChosen();
break;
case SCI_WORDPARTRIGHTEXTEND:
- MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1), selStream);
+ MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1), Selection::selStream);
SetLastXChosen();
break;
case SCI_HOMEDISPLAY:
MovePositionTo(MovePositionSoVisible(
- StartEndDisplayLine(currentPos, true), -1));
+ StartEndDisplayLine(sel.MainCaret(), true), -1));
SetLastXChosen();
break;
case SCI_HOMEDISPLAYEXTEND:
MovePositionTo(MovePositionSoVisible(
- StartEndDisplayLine(currentPos, true), -1), selStream);
+ StartEndDisplayLine(sel.MainCaret(), true), -1), Selection::selStream);
SetLastXChosen();
break;
case SCI_LINEENDDISPLAY:
MovePositionTo(MovePositionSoVisible(
- StartEndDisplayLine(currentPos, false), 1));
+ StartEndDisplayLine(sel.MainCaret(), false), 1));
SetLastXChosen();
break;
case SCI_LINEENDDISPLAYEXTEND:
MovePositionTo(MovePositionSoVisible(
- StartEndDisplayLine(currentPos, false), 1), selStream);
+ StartEndDisplayLine(sel.MainCaret(), false), 1), Selection::selStream);
SetLastXChosen();
break;
}
@@ -4874,13 +5073,13 @@ int Editor::GetWhitespaceVisible() {
void Editor::Indent(bool forwards) {
//Platform::DebugPrintf("INdent %d\n", forwards);
- int lineOfAnchor = pdoc->LineFromPosition(anchor);
- int lineCurrentPos = pdoc->LineFromPosition(currentPos);
+ int lineOfAnchor = pdoc->LineFromPosition(sel.MainAnchor());
+ int lineCurrentPos = pdoc->LineFromPosition(sel.MainCaret());
if (lineOfAnchor == lineCurrentPos) {
if (forwards) {
pdoc->BeginUndoAction();
ClearSelection();
- if (pdoc->GetColumn(currentPos) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) &&
+ if (pdoc->GetColumn(sel.MainCaret()) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) &&
pdoc->tabIndents) {
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
int indentationStep = pdoc->IndentSize();
@@ -4888,22 +5087,22 @@ void Editor::Indent(bool forwards) {
SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
} else {
if (pdoc->useTabs) {
- pdoc->InsertChar(currentPos, '\t');
- SetEmptySelection(currentPos + 1);
+ pdoc->InsertChar(sel.MainCaret(), '\t');
+ SetEmptySelection(sel.MainCaret() + 1);
} else {
int numSpaces = (pdoc->tabInChars) -
- (pdoc->GetColumn(currentPos) % (pdoc->tabInChars));
+ (pdoc->GetColumn(sel.MainCaret()) % (pdoc->tabInChars));
if (numSpaces < 1)
numSpaces = pdoc->tabInChars;
for (int i = 0; i < numSpaces; i++) {
- pdoc->InsertChar(currentPos + i, ' ');
+ pdoc->InsertChar(sel.MainCaret() + i, ' ');
}
- SetEmptySelection(currentPos + numSpaces);
+ SetEmptySelection(sel.MainCaret() + numSpaces);
}
}
pdoc->EndUndoAction();
} else {
- if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) &&
+ if (pdoc->GetColumn(sel.MainCaret()) <= pdoc->GetLineIndentation(lineCurrentPos) &&
pdoc->tabIndents) {
pdoc->BeginUndoAction();
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
@@ -4912,23 +5111,23 @@ void Editor::Indent(bool forwards) {
SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
pdoc->EndUndoAction();
} else {
- int newColumn = ((pdoc->GetColumn(currentPos) - 1) / pdoc->tabInChars) *
+ int newColumn = ((pdoc->GetColumn(sel.MainCaret()) - 1) / pdoc->tabInChars) *
pdoc->tabInChars;
if (newColumn < 0)
newColumn = 0;
- int newPos = currentPos;
+ int newPos = sel.MainCaret();
while (pdoc->GetColumn(newPos) > newColumn)
newPos--;
SetEmptySelection(newPos);
}
}
} else {
- int anchorPosOnLine = anchor - pdoc->LineStart(lineOfAnchor);
- int currentPosPosOnLine = currentPos - pdoc->LineStart(lineCurrentPos);
+ int anchorPosOnLine = sel.MainAnchor() - pdoc->LineStart(lineOfAnchor);
+ int currentPosPosOnLine = sel.MainCaret() - pdoc->LineStart(lineCurrentPos);
// Multiple lines selected so indent / dedent
int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos);
int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos);
- if (pdoc->LineStart(lineBottomSel) == anchor || pdoc->LineStart(lineBottomSel) == currentPos)
+ if (pdoc->LineStart(lineBottomSel) == sel.MainAnchor() || pdoc->LineStart(lineBottomSel) == sel.MainCaret())
lineBottomSel--; // If not selecting any characters on a line, do not indent
pdoc->BeginUndoAction();
pdoc->Indent(forwards, lineBottomSel, lineTopSel);
@@ -5079,75 +5278,60 @@ char *Editor::CopyRange(int start, int end) {
return text;
}
-void Editor::CopySelectionFromRange(SelectionText *ss, bool allowLineCopy, int start, int end) {
- bool isLine = allowLineCopy && (start == end);
- if (isLine) {
- int currentLine = pdoc->LineFromPosition(currentPos);
- start = pdoc->LineStart(currentLine);
- end = pdoc->LineEnd(currentLine);
-
- char *text = CopyRange(start, end);
- int textLen = text ? strlen(text) : 0;
- // include room for \r\n\0
- textLen += 3;
- char *textWithEndl = new char[textLen];
- textWithEndl[0] = '\0';
- if (text)
- strncat(textWithEndl, text, textLen);
- if (pdoc->eolMode != SC_EOL_LF)
- strncat(textWithEndl, "\r", textLen);
- if (pdoc->eolMode != SC_EOL_CR)
- strncat(textWithEndl, "\n", textLen);
- ss->Set(textWithEndl, strlen(textWithEndl),
- pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true);
- delete []text;
- } else {
- ss->Set(CopyRange(start, end), end - start + 1,
- pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
- }
-}
-
void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) {
- if (selType == selStream) {
- CopySelectionFromRange(ss, allowLineCopy, SelectionStart(), SelectionEnd());
+ if (sel.Empty()) {
+ if (allowLineCopy) {
+ int currentLine = pdoc->LineFromPosition(sel.MainCaret());
+ int start = pdoc->LineStart(currentLine);
+ int end = pdoc->LineEnd(currentLine);
+
+ char *text = CopyRange(start, end);
+ int textLen = text ? strlen(text) : 0;
+ // include room for \r\n\0
+ textLen += 3;
+ char *textWithEndl = new char[textLen];
+ textWithEndl[0] = '\0';
+ if (text)
+ strncat(textWithEndl, text, textLen);
+ if (pdoc->eolMode != SC_EOL_LF)
+ strncat(textWithEndl, "\r", textLen);
+ if (pdoc->eolMode != SC_EOL_CR)
+ strncat(textWithEndl, "\n", textLen);
+ ss->Set(textWithEndl, strlen(textWithEndl),
+ pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true);
+ delete []text;
+ }
} else {
- char *text = 0;
- int size = 0;
- SelectionLineIterator lineIterator(this);
- while (lineIterator.Iterate()) {
- size += lineIterator.endPos - lineIterator.startPos;
- if (selType != selLines) {
- size++;
- if (pdoc->eolMode == SC_EOL_CRLF) {
- size++;
- }
+ int delimiterLength = 0;
+ if (sel.selType == Selection::selRectangle) {
+ if (pdoc->eolMode == SC_EOL_CRLF) {
+ delimiterLength = 2;
+ } else {
+ delimiterLength = 1;
}
}
- if (size > 0) {
- text = new char[size + 1];
- if (text) {
- int j = 0;
- lineIterator.Reset();
- while (lineIterator.Iterate()) {
- for (int i = lineIterator.startPos;
- i < lineIterator.endPos;
- i++) {
- text[j++] = pdoc->CharAt(i);
- }
- if (selType != selLines) {
- if (pdoc->eolMode != SC_EOL_LF) {
- text[j++] = '\r';
- }
- if (pdoc->eolMode != SC_EOL_CR) {
- text[j++] = '\n';
- }
- }
+ int size = sel.Length() + delimiterLength * sel.Count();
+ char *text = new char[size + 1];
+ int j = 0;
+ for (size_t r=0; r<sel.Count(); r++) {
+ SelectionRange current = sel.Range(r);
+ for (int i = current.Start().Position();
+ i < current.End().Position();
+ i++) {
+ text[j++] = pdoc->CharAt(i);
+ }
+ if (sel.selType == Selection::selRectangle) {
+ if (pdoc->eolMode != SC_EOL_LF) {
+ text[j++] = '\r';
+ }
+ if (pdoc->eolMode != SC_EOL_CR) {
+ text[j++] = '\n';
}
- text[size] = '\0';
}
}
+ text[size] = '\0';
ss->Set(text, size + 1, pdoc->dbcsCodePage,
- vs.styles[STYLE_DEFAULT].characterSet, selType == selRectangle, selType == selLines);
+ vs.styles[STYLE_DEFAULT].characterSet, sel.IsRectangular(), sel.selType == Selection::selLines);
}
}
@@ -5206,12 +5390,12 @@ void Editor::DropAt(int position, const char *value, bool moving, bool rectangul
if (inDragDrop == ddDragging)
dropWentOutside = false;
- int positionWasInSelection = PositionInSelection(position);
+ bool positionWasInSelection = PositionInSelection(position);
bool positionOnEdgeOfSelection =
(position == SelectionStart()) || (position == SelectionEnd());
- if ((inDragDrop != ddDragging) || !(0 == positionWasInSelection) ||
+ if ((inDragDrop != ddDragging) || !(positionWasInSelection) ||
(positionOnEdgeOfSelection && !moving)) {
int selStart = SelectionStart();
@@ -5222,14 +5406,13 @@ void Editor::DropAt(int position, const char *value, bool moving, bool rectangul
int positionAfterDeletion = position;
if ((inDragDrop == ddDragging) && moving) {
// Remove dragged out text
- if (rectangular || selType == selLines) {
- SelectionLineIterator lineIterator(this);
- while (lineIterator.Iterate()) {
- if (position >= lineIterator.startPos) {
- if (position > lineIterator.endPos) {
- positionAfterDeletion -= lineIterator.endPos - lineIterator.startPos;
+ if (rectangular || sel.selType == Selection::selLines) {
+ for (size_t r=0; r<sel.Count(); r++) {
+ if (position >= sel.Range(r).Start().Position()) {
+ if (position > sel.Range(r).End().Position()) {
+ positionAfterDeletion -= sel.Range(r).End().Position() - sel.Range(r).Start().Position();
} else {
- positionAfterDeletion -= position - lineIterator.startPos;
+ positionAfterDeletion -= position - sel.Range(r).Start().Position();
}
}
}
@@ -5243,12 +5426,12 @@ void Editor::DropAt(int position, const char *value, bool moving, bool rectangul
position = positionAfterDeletion;
if (rectangular) {
- PasteRectangular(position, value, istrlen(value));
+ PasteRectangular(SelectionPosition(position), value, istrlen(value));
pdoc->EndUndoAction();
// Should try to select new rectangle but it may not be a rectangle now so just select the drop position
SetEmptySelection(position);
} else {
- position = MovePositionOutsideChar(position, currentPos - position);
+ position = MovePositionOutsideChar(position, sel.MainCaret() - position);
if (pdoc->InsertCString(position, value)) {
SetSelection(position + istrlen(value), position);
}
@@ -5260,62 +5443,39 @@ void Editor::DropAt(int position, const char *value, bool moving, bool rectangul
}
/**
- * @return -1 if given position is before the selection,
- * 1 if position is after the selection,
- * 0 if position is inside the selection,
+ * @return true if given position is inside the selection,
*/
-int Editor::PositionInSelection(int pos) {
- pos = MovePositionOutsideChar(pos, currentPos - pos);
- if (pos < SelectionStart()) {
- return -1;
- }
- if (pos > SelectionEnd()) {
- return 1;
- }
- if (selType == selStream) {
- return 0;
- } else {
- SelectionLineIterator lineIterator(this);
- lineIterator.SetAt(pdoc->LineFromPosition(pos));
- if (pos < lineIterator.startPos) {
- return -1;
- } else if (pos > lineIterator.endPos) {
- return 1;
- } else {
- return 0;
- }
+bool Editor::PositionInSelection(int pos) {
+ pos = MovePositionOutsideChar(pos, sel.MainCaret() - pos);
+ for (size_t r=0; r<sel.Count(); r++) {
+ if (sel.Range(r).Contains(pos))
+ return true;
}
+ return false;
}
bool Editor::PointInSelection(Point pt) {
- int pos = PositionFromLocation(pt);
- if (0 == PositionInSelection(pos)) {
- // Probably inside, but we must make a finer test
- int selStart, selEnd;
- if (selType == selStream) {
- selStart = SelectionStart();
- selEnd = SelectionEnd();
- } else {
- SelectionLineIterator lineIterator(this);
- lineIterator.SetAt(pdoc->LineFromPosition(pos));
- selStart = lineIterator.startPos;
- selEnd = lineIterator.endPos;
- }
- if (pos == selStart) {
- // see if just before selection
- Point locStart = LocationFromPosition(pos);
- if (pt.x < locStart.x) {
- return false;
+ SelectionPosition pos = SPositionFromLocation(pt);
+ int xPos = XFromPosition(pos);
+ for (size_t r=0; r<sel.Count(); r++) {
+ SelectionRange range = sel.Range(r);
+ if (range.Contains(pos)) {
+ bool hit = true;
+ if (pos == range.Start()) {
+ // see if just before selection
+ if (pt.x < xPos) {
+ hit = false;
+ }
}
- }
- if (pos == selEnd) {
- // see if just after selection
- Point locEnd = LocationFromPosition(pos);
- if (pt.x > locEnd.x) {
- return false;
+ if (pos == range.End()) {
+ // see if just after selection
+ if (pt.x > xPos) {
+ hit = false;
+ }
}
+ if (hit)
+ return true;
}
- return true;
}
return false;
}
@@ -5358,25 +5518,25 @@ void Editor::DwellEnd(bool mouseMoved) {
void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
//Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
ptMouseLast = pt;
- int newPos = PositionFromLocation(pt);
- newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
+ SelectionPosition newPos = SPositionFromLocation(pt);
+ newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position());
inDragDrop = ddNone;
- moveExtendsSelection = false;
+ sel.SetMoveExtends(false);
bool processed = NotifyMarginClick(pt, shift, ctrl, alt);
if (processed)
return;
- NotifyIndicatorClick(true, newPos, shift, ctrl, alt);
+ NotifyIndicatorClick(true, newPos.Position(), shift, ctrl, alt);
bool inSelMargin = PointInSelMargin(pt);
if (shift & !inSelMargin) {
- SetSelection(newPos);
+ SetSelection(newPos.Position());
}
if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) {
//Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
SetMouseCapture(true);
- SetEmptySelection(newPos);
+ SetEmptySelection(newPos.Position());
bool doubleClick = false;
// Stop mouse button bounce changing selection type
if (!Platform::MouseButtonBounce() || curTime != lastClickTime) {
@@ -5387,16 +5547,16 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b
selectionType = selLine;
} else {
selectionType = selChar;
- originalAnchorPos = currentPos;
+ originalAnchorPos = sel.MainCaret();
}
}
if (selectionType == selWord) {
- if (currentPos >= originalAnchorPos) { // Moved forward
- SetSelection(pdoc->ExtendWordSelect(currentPos, 1),
+ if (sel.MainCaret() >= originalAnchorPos) { // Moved forward
+ SetSelection(pdoc->ExtendWordSelect(sel.MainCaret(), 1),
pdoc->ExtendWordSelect(originalAnchorPos, -1));
} else { // Moved backward
- SetSelection(pdoc->ExtendWordSelect(currentPos, -1),
+ SetSelection(pdoc->ExtendWordSelect(sel.MainCaret(), -1),
pdoc->ExtendWordSelect(originalAnchorPos, 1));
}
} else if (selectionType == selLine) {
@@ -5404,17 +5564,17 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b
SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor));
//Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
} else {
- SetEmptySelection(currentPos);
+ SetEmptySelection(sel.MainCaret());
}
//Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
if (doubleClick) {
NotifyDoubleClick(pt, shift, ctrl, alt);
- if (PositionIsHotspot(newPos))
- NotifyHotSpotDoubleClicked(newPos, shift, ctrl, alt);
+ if (PositionIsHotspot(newPos.Position()))
+ NotifyHotSpotDoubleClicked(newPos.Position(), shift, ctrl, alt);
}
} else { // Single click
if (inSelMargin) {
- selType = selStream;
+ sel.selType = Selection::selStream;
if (ctrl) {
SelectAll();
lastClickTime = curTime;
@@ -5428,10 +5588,10 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b
pdoc->LineStart(lineAnchor));
} else {
// Single shift+click in margin: select from line anchor to clicked line
- if (anchor > currentPos)
- lineAnchor = pdoc->LineFromPosition(anchor - 1);
+ if (sel.MainAnchor() > sel.MainCaret())
+ lineAnchor = pdoc->LineFromPosition(sel.MainAnchor() - 1);
else
- lineAnchor = pdoc->LineFromPosition(anchor);
+ lineAnchor = pdoc->LineFromPosition(sel.MainAnchor());
int lineStart = LineFromLocation(pt);
LineSelection(lineStart, lineAnchor);
//lineAnchor = lineStart; // Keep the same anchor for ButtonMove
@@ -5442,7 +5602,7 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b
selectionType = selLine;
} else {
if (PointIsHotspot(pt)) {
- NotifyHotSpotClicked(newPos, shift, ctrl, alt);
+ NotifyHotSpotClicked(newPos.Position(), shift, ctrl, alt);
}
if (!shift) {
if (PointInSelection(pt) && !SelectionEmpty())
@@ -5453,12 +5613,21 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b
SetMouseCapture(true);
if (inDragDrop != ddInitial) {
SetDragPosition(invalidPosition);
- if (!shift) {
- SetEmptySelection(newPos);
+ if (ctrl) {
+ InvalidateSelection(SelectionRange(newPos), true);
+ sel.AddSelection(newPos);
+ } else if (!shift) {
+ InvalidateSelection(SelectionRange(newPos), true);
+ if (sel.Count() > 1)
+ Redraw();
+ sel.Clear();
+ sel.selType = alt ? Selection::selRectangle : Selection::selStream;
+ SetSelection(newPos, newPos);
}
- selType = alt ? selRectangle : selStream;
+ sel.selType = alt ? Selection::selRectangle : Selection::selStream;
selectionType = selChar;
- originalAnchorPos = currentPos;
+ originalAnchorPos = sel.MainCaret();
+ sel.Rectangular() = SelectionRange(newPos, newPos);
SetRectangularRange();
}
}
@@ -5522,13 +5691,13 @@ void Editor::ButtonMove(Point pt) {
DwellEnd(true);
}
- int movePos = PositionFromLocation(pt);
- movePos = MovePositionOutsideChar(movePos, currentPos - movePos);
+ SelectionPosition movePos = SPositionFromLocation(pt);
+ movePos = MovePositionOutsideChar(movePos, sel.MainCaret() - movePos.Position());
if (inDragDrop == ddInitial) {
if (DragThreshold(ptMouseLast, pt)) {
SetMouseCapture(false);
- SetDragPosition(movePos);
+ SetDragPosition(movePos.Position());
CopySelectionRange(&drag);
StartDrag();
}
@@ -5547,13 +5716,22 @@ void Editor::ButtonMove(Point pt) {
// Adjust selection
if (posDrag >= 0) {
- SetDragPosition(movePos);
+ SetDragPosition(movePos.Position());
} else {
if (selectionType == selChar) {
- SetSelection(movePos);
+ if (sel.IsRectangular()) {
+ sel.Rectangular() = SelectionRange(movePos, sel.Rectangular().anchor);
+ SetSelection(movePos, sel.RangeMain().anchor);
+ } else if (sel.Count() > 1) {
+ sel.TrimSelection(sel.RangeMain().anchor, movePos);
+ sel.RangeMain() = SelectionRange(movePos, sel.RangeMain().anchor);
+ InvalidateSelection(SelectionRange(movePos, sel.RangeMain().anchor), true);
+ } else {
+ SetSelection(movePos, sel.RangeMain().anchor);
+ }
} else if (selectionType == selWord) {
// Continue selecting by word
- if (movePos == originalAnchorPos) { // Didn't move
+ if (movePos.Position() == originalAnchorPos) { // Didn't move
// No need to do anything. Previously this case was lumped
// in with "Moved forward", but that can be harmful in this
// case: a handler for the NotifyDoubleClick re-adjusts
@@ -5563,11 +5741,11 @@ void Editor::ButtonMove(Point pt) {
// the ButtonMove() called via Tick() for auto-scrolling
// could result in the fancier word selection adjustment
// being unmade.
- } else if (movePos > originalAnchorPos) { // Moved forward
- SetSelection(pdoc->ExtendWordSelect(movePos, 1),
+ } else if (movePos.Position() > originalAnchorPos) { // Moved forward
+ SetSelection(pdoc->ExtendWordSelect(movePos.Position(), 1),
pdoc->ExtendWordSelect(originalAnchorPos, -1));
} else { // Moved backward
- SetSelection(pdoc->ExtendWordSelect(movePos, -1),
+ SetSelection(pdoc->ExtendWordSelect(movePos.Position(), -1),
pdoc->ExtendWordSelect(originalAnchorPos, 1));
}
} else {
@@ -5576,10 +5754,6 @@ void Editor::ButtonMove(Point pt) {
LineSelection(lineMove, lineAnchor);
}
}
- // While dragging to make rectangular selection, we don't want the current
- // position to jump to the end of smaller or empty lines.
- //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset;
- xEndSelect = XFromPosition(movePos);
// Autoscroll
PRectangle rcClient = GetClientRectangle();
@@ -5597,7 +5771,7 @@ void Editor::ButtonMove(Point pt) {
}
EnsureCaretVisible(false, false, true);
- if (hsStart != -1 && !PositionIsHotspot(movePos))
+ if (hsStart != -1 && !PositionIsHotspot(movePos.Position()))
SetHotSpotRange(NULL);
} else {
@@ -5622,11 +5796,11 @@ void Editor::ButtonMove(Point pt) {
void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
//Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
- int newPos = PositionFromLocation(pt);
- newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
+ SelectionPosition newPos = SPositionFromLocation(pt);
+ newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position());
if (inDragDrop == ddInitial) {
inDragDrop = ddNone;
- SetEmptySelection(newPos);
+ SetEmptySelection(newPos.Position());
}
if (HaveMouseCapture()) {
if (PointInSelMargin(pt)) {
@@ -5637,31 +5811,29 @@ void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
}
ptMouseLast = pt;
SetMouseCapture(false);
- int newPos = PositionFromLocation(pt);
- newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
- NotifyIndicatorClick(false, newPos, false, false, false);
+ NotifyIndicatorClick(false, newPos.Position(), false, false, false);
if (inDragDrop == ddDragging) {
int selStart = SelectionStart();
int selEnd = SelectionEnd();
if (selStart < selEnd) {
if (drag.len) {
if (ctrl) {
- if (pdoc->InsertString(newPos, drag.s, drag.len)) {
- SetSelection(newPos, newPos + drag.len);
+ if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
+ SetSelection(newPos.Position(), newPos.Position() + drag.len);
}
- } else if (newPos < selStart) {
+ } else if (newPos.Position() < selStart) {
pdoc->DeleteChars(selStart, drag.len);
- if (pdoc->InsertString(newPos, drag.s, drag.len)) {
- SetSelection(newPos, newPos + drag.len);
+ if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
+ SetSelection(newPos.Position(), newPos.Position() + drag.len);
}
- } else if (newPos > selEnd) {
+ } else if (newPos.Position() > selEnd) {
pdoc->DeleteChars(selStart, drag.len);
- newPos -= drag.len;
- if (pdoc->InsertString(newPos, drag.s, drag.len)) {
- SetSelection(newPos, newPos + drag.len);
+ newPos.Add(-drag.len);
+ if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) {
+ SetSelection(newPos.Position(), newPos.Position() + drag.len);
}
} else {
- SetEmptySelection(newPos);
+ SetEmptySelection(newPos.Position());
}
drag.Free();
}
@@ -5669,14 +5841,20 @@ void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
}
} else {
if (selectionType == selChar) {
- SetSelection(newPos);
+ if (sel.Count() > 1) {
+ sel.RangeMain() =
+ SelectionRange(newPos, sel.Range(sel.Count() - 1).anchor);
+ InvalidateSelection(sel.RangeMain(), true);
+ } else {
+ SetSelection(newPos, sel.RangeMain().anchor);
+ }
}
}
SetRectangularRange();
lastClickTime = curTime;
lastClick = pt;
lastXChosen = pt.x;
- if (selType == selStream) {
+ if (sel.selType == Selection::selStream) {
SetLastXChosen();
}
inDragDrop = ddNone;
@@ -5825,9 +6003,7 @@ void Editor::SetDocPointer(Document *document) {
pdoc->AddRef();
// Ensure all positions within document
- selType = selStream;
- currentPos = 0;
- anchor = 0;
+ sel.Clear();
targetStart = 0;
targetEnd = 0;
@@ -5898,7 +6074,7 @@ void Editor::ToggleContraction(int line) {
if (lineMaxSubord > line) {
cs.SetVisible(line + 1, lineMaxSubord, false);
- int lineCurrent = pdoc->LineFromPosition(currentPos);
+ int lineCurrent = pdoc->LineFromPosition(sel.MainCaret());
if (lineCurrent > line && lineCurrent <= lineMaxSubord) {
// This does not re-expand the fold
EnsureCaretVisible();
@@ -6026,7 +6202,7 @@ void Editor::AddStyledText(char *buffer, int appendLength) {
pdoc->SetStyles(textLength, text);
delete []text;
}
- SetEmptySelection(currentPos + textLength);
+ SetEmptySelection(sel.MainCaret() + textLength);
}
static bool ValidMargin(unsigned long wParam) {
@@ -6236,7 +6412,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
nEnd = pdoc->Length();
if (nStart < 0)
nStart = nEnd; // Remove selection
- selType = selStream;
+ sel.selType = Selection::selStream;
SetSelection(nEnd, nStart);
EnsureCaretVisible();
}
@@ -6244,17 +6420,16 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
case SCI_GETSELTEXT: {
if (lParam == 0) {
- if (selType == selStream) {
+ if (sel.selType == Selection::selStream) {
return 1 + SelectionEnd() - SelectionStart();
} else {
// TODO: why is selLines handled the slow way?
int size = 0;
int extraCharsPerLine = 0;
- if (selType != selLines)
+ if (sel.selType != Selection::selLines)
extraCharsPerLine = (pdoc->eolMode == SC_EOL_CRLF) ? 2 : 1;
- SelectionLineIterator lineIterator(this);
- while (lineIterator.Iterate()) {
- size += lineIterator.endPos + extraCharsPerLine - lineIterator.startPos;
+ for (size_t r=0; r<sel.Count(); r++) {
+ size += sel.Range(r).Length() + extraCharsPerLine;
}
return 1 + size;
@@ -6302,9 +6477,9 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
pdoc->BeginUndoAction();
ClearSelection();
char *replacement = CharPtrFromSPtr(lParam);
- pdoc->InsertCString(currentPos, replacement);
+ pdoc->InsertCString(sel.MainCaret(), replacement);
pdoc->EndUndoAction();
- SetEmptySelection(currentPos + istrlen(replacement));
+ SetEmptySelection(sel.MainCaret() + istrlen(replacement));
EnsureCaretVisible();
}
break;
@@ -6324,12 +6499,12 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
return targetEnd;
case SCI_TARGETFROMSELECTION:
- if (currentPos < anchor) {
- targetStart = currentPos;
- targetEnd = anchor;
+ if (sel.MainCaret() < sel.MainAnchor()) {
+ targetStart = sel.MainCaret();
+ targetEnd = sel.MainAnchor();
} else {
- targetStart = anchor;
- targetEnd = currentPos;
+ targetStart = sel.MainAnchor();
+ targetEnd = sel.MainCaret();
}
break;
@@ -6454,7 +6629,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
if (lParam == 0)
return 0;
pdoc->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam), wParam);
- SetEmptySelection(currentPos + wParam);
+ SetEmptySelection(sel.MainCaret() + wParam);
return 0;
}
@@ -6542,32 +6717,32 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
return pdoc->CharAt(wParam);
case SCI_SETCURRENTPOS:
- SetSelection(wParam, anchor);
+ SetSelection(wParam, sel.MainAnchor());
break;
case SCI_GETCURRENTPOS:
- return currentPos;
+ return sel.MainCaret();
case SCI_SETANCHOR:
- SetSelection(currentPos, wParam);
+ SetSelection(sel.MainCaret(), wParam);
break;
case SCI_GETANCHOR:
- return anchor;
+ return sel.MainAnchor();
case SCI_SETSELECTIONSTART:
- SetSelection(Platform::Maximum(currentPos, wParam), wParam);
+ SetSelection(Platform::Maximum(sel.MainCaret(), wParam), wParam);
break;
case SCI_GETSELECTIONSTART:
- return Platform::Minimum(anchor, currentPos);
+ return Platform::Minimum(sel.MainAnchor(), sel.MainCaret());
case SCI_SETSELECTIONEND:
- SetSelection(wParam, Platform::Minimum(anchor, wParam));
+ SetSelection(wParam, Platform::Minimum(sel.MainAnchor(), wParam));
break;
case SCI_GETSELECTIONEND:
- return Platform::Maximum(anchor, currentPos);
+ return Platform::Maximum(sel.MainAnchor(), sel.MainCaret());
case SCI_SETPRINTMAGNIFICATION:
printMagnification = wParam;
@@ -6663,7 +6838,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
break;
case SCI_GETCURLINE: {
- int lineCurrentPos = pdoc->LineFromPosition(currentPos);
+ int lineCurrentPos = pdoc->LineFromPosition(sel.MainCaret());
int lineStart = pdoc->LineStart(lineCurrentPos);
unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1);
if (lParam == 0) {
@@ -6676,7 +6851,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
ptr[iPlace++] = pdoc->CharAt(iChar);
}
ptr[iPlace] = '\0';
- return currentPos - lineStart;
+ return sel.MainCaret() - lineStart;
}
case SCI_GETENDSTYLED:
@@ -7621,7 +7796,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
case SCI_CONVERTEOLS:
pdoc->ConvertLineEnds(wParam);
- SetSelection(currentPos, anchor); // Ensure selection inside document
+ SetSelection(sel.MainCaret(), sel.MainAnchor()); // Ensure selection inside document
return 0;
case SCI_SETLENGTHFORENCODE:
@@ -7629,48 +7804,57 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
return 0;
case SCI_SELECTIONISRECTANGLE:
- return selType == selRectangle ? 1 : 0;
+ return sel.selType == Selection::selRectangle ? 1 : 0;
case SCI_SETSELECTIONMODE: {
switch (wParam) {
case SC_SEL_STREAM:
- moveExtendsSelection = !moveExtendsSelection || (selType != selStream);
- selType = selStream;
+ sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream));
+ sel.selType = Selection::selStream;
break;
case SC_SEL_RECTANGLE:
- moveExtendsSelection = !moveExtendsSelection || (selType != selRectangle);
- selType = selRectangle;
+ sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selRectangle));
+ sel.selType = Selection::selRectangle;
break;
case SC_SEL_LINES:
- moveExtendsSelection = !moveExtendsSelection || (selType != selLines);
- selType = selLines;
+ sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selLines));
+ sel.selType = Selection::selLines;
+ break;
+ case SC_SEL_THIN:
+ sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selThin));
+ sel.selType = Selection::selThin;
break;
default:
- moveExtendsSelection = !moveExtendsSelection || (selType != selStream);
- selType = selStream;
+ sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream));
+ sel.selType = Selection::selStream;
}
- InvalidateSelection(currentPos, anchor, true);
+ InvalidateSelection(sel.RangeMain(), true);
}
case SCI_GETSELECTIONMODE:
- switch (selType) {
- case selStream:
+ switch (sel.selType) {
+ case Selection::selStream:
return SC_SEL_STREAM;
- case selRectangle:
+ case Selection::selRectangle:
return SC_SEL_RECTANGLE;
- case selLines:
+ case Selection::selLines:
return SC_SEL_LINES;
+ case Selection::selThin:
+ return SC_SEL_THIN;
default: // ?!
return SC_SEL_STREAM;
}
- case SCI_GETLINESELSTARTPOSITION: {
- SelectionLineIterator lineIterator(this);
- lineIterator.SetAt(wParam);
- return lineIterator.startPos;
- }
+ case SCI_GETLINESELSTARTPOSITION:
case SCI_GETLINESELENDPOSITION: {
- SelectionLineIterator lineIterator(this);
- lineIterator.SetAt(wParam);
- return lineIterator.endPos;
+ for (size_t r=0; r<sel.Count(); r++) {
+ int posLineStart = pdoc->LineStart(wParam);
+ int posLineEnd = pdoc->LineEnd(wParam);
+ SelectionPosition spStart;
+ SelectionPosition spEnd;
+ if (sel.Range(r).Intersect(posLineStart, posLineEnd, spStart, spEnd)) {
+ return (iMessage == SCI_GETLINESELSTARTPOSITION) ? spStart.Position() : spEnd.Position();
+ }
+ }
+ return INVALID_POSITION;
}
case SCI_SETOVERTYPE:
@@ -7916,6 +8100,147 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
pdoc->AddUndoAction(wParam, lParam & UNDO_MAY_COALESCE);
break;
+ case SCI_SETMULTILINECARET:
+ multiLineCaret = wParam != 0;
+ InvalidateCaret();
+ break;
+
+ case SCI_GETMULTILINECARET:
+ return multiLineCaret;
+
+ case SCI_SETMULTILINECARETBLINKS:
+ multiLineCaretBlinks = wParam != 0;
+ InvalidateCaret();
+ break;
+
+ case SCI_GETMULTILINECARETBLINKS:
+ return multiLineCaretBlinks;
+
+ case SCI_GETSELECTIONS:
+ return sel.Count();
+
+ case SCI_CLEARSELECTIONS:
+ sel.Clear();
+ Redraw();
+ break;
+
+ case SCI_SETSELECTION:
+ sel.Clear();
+ sel.RangeMain() = SelectionRange(wParam, lParam);
+ Redraw();
+ break;
+
+ case SCI_ADDSELECTION:
+ sel.AddSelection(SelectionPosition(wParam), SelectionPosition(lParam), false);
+ Redraw();
+ break;
+
+ case SCI_SETMAINSELECTION:
+ sel.SetMain(wParam);
+ Redraw();
+ break;
+
+ case SCI_GETMAINSELECTION:
+ return sel.Main();
+
+ case SCI_SETSELECTIONNCARET:
+ sel.Range(wParam).caret.SetPosition(lParam);
+ Redraw();
+ break;
+
+ case SCI_GETSELECTIONNCARET:
+ return sel.Range(wParam).caret.Position();
+
+ case SCI_SETSELECTIONNANCHOR:
+ sel.Range(wParam).anchor.SetPosition(lParam);
+ Redraw();
+ break;
+ case SCI_GETSELECTIONNANCHOR:
+ return sel.Range(wParam).anchor.Position();
+
+ case SCI_SETSELECTIONNCARETVIRTUALSPACE:
+ sel.Range(wParam).caret.SetVirtualSpace(lParam);
+ Redraw();
+ break;
+
+ case SCI_GETSELECTIONNCARETVIRTUALSPACE:
+ return sel.Range(wParam).caret.VirtualSpace();
+
+ case SCI_SETSELECTIONNANCHORVIRTUALSPACE:
+ sel.Range(wParam).anchor.SetVirtualSpace(lParam);
+ Redraw();
+ break;
+
+ case SCI_GETSELECTIONNANCHORVIRTUALSPACE:
+ return sel.Range(wParam).anchor.VirtualSpace();
+
+ case SCI_SETSELECTIONNSTART:
+ sel.Range(wParam).anchor.SetPosition(lParam);
+ Redraw();
+ break;
+
+ case SCI_GETSELECTIONNSTART:
+ return sel.Range(wParam).Start().Position();
+
+ case SCI_SETSELECTIONNEND:
+ sel.Range(wParam).caret.SetPosition(lParam);
+ Redraw();
+ break;
+
+ case SCI_GETSELECTIONNEND:
+ return sel.Range(wParam).End().Position();
+
+ case SCI_SETRECTANGULARSELECTIONCARET:
+ if (!sel.IsRectangular())
+ sel.Clear();
+ sel.selType = Selection::selRectangle;
+ sel.Rectangular().caret.SetPosition(wParam);
+ Redraw();
+ break;
+
+ case SCI_GETRECTANGULARSELECTIONCARET:
+ return sel.Rectangular().caret.Position();
+
+ case SCI_SETRECTANGULARSELECTIONANCHOR:
+ if (!sel.IsRectangular())
+ sel.Clear();
+ sel.selType = Selection::selRectangle;
+ sel.Rectangular().anchor.SetPosition(wParam);
+ Redraw();
+ break;
+
+ case SCI_GETRECTANGULARSELECTIONANCHOR:
+ return sel.Rectangular().anchor.Position();
+
+ case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE:
+ if (!sel.IsRectangular())
+ sel.Clear();
+ sel.selType = Selection::selRectangle;
+ sel.Rectangular().caret.SetVirtualSpace(wParam);
+ Redraw();
+ break;
+
+ case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE:
+ return sel.Rectangular().caret.VirtualSpace();
+
+ case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE:
+ if (!sel.IsRectangular())
+ sel.Clear();
+ sel.selType = Selection::selRectangle;
+ sel.Rectangular().anchor.SetVirtualSpace(wParam);
+ Redraw();
+ break;
+
+ case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE:
+ return sel.Rectangular().anchor.VirtualSpace();
+
+ case SCI_SETVIRTUALSPACEOPTIONS:
+ virtualSpaceOptions = wParam;
+ break;
+
+ case SCI_GETVIRTUALSPACEOPTIONS:
+ return virtualSpaceOptions;
+
default:
return DefWndProc(iMessage, wParam, lParam);
}
diff --git a/src/Editor.h b/src/Editor.h
index a318e6282..ab1e9a1e8 100644
--- a/src/Editor.h
+++ b/src/Editor.h
@@ -143,6 +143,10 @@ protected: // ScintillaBase subclass needs access to much of Editor
bool verticalScrollBarVisible;
bool endAtLastLine;
bool caretSticky;
+ bool multiLineCaret;
+ bool multiLineCaretBlinks;
+
+ int virtualSpaceOptions;
Surface *pixmapLine;
Surface *pixmapSelMargin;
@@ -176,8 +180,6 @@ protected: // ScintillaBase subclass needs access to much of Editor
int lastXChosen;
int lineAnchor;
int originalAnchorPos;
- int currentPos;
- int anchor;
int targetStart;
int targetEnd;
int searchFlags;
@@ -199,11 +201,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
int modEventMask;
SelectionText drag;
- enum selTypes { noSel, selStream, selRectangle, selLines };
- selTypes selType;
- bool moveExtendsSelection;
- int xStartSelect; ///< x position of start of rectangular selection
- int xEndSelect; ///< x position of end of rectangular selection
+ Selection sel;
bool primarySelection;
int caretXPolicy;
@@ -259,9 +257,13 @@ protected: // ScintillaBase subclass needs access to much of Editor
int LinesOnScreen();
int LinesToScroll();
int MaxScrollPos();
+ SelectionPosition ClampPositionIntoDocument(SelectionPosition sp) const;
Point LocationFromPosition(int pos);
int XFromPosition(int pos);
+ int XFromPosition(SelectionPosition sp);
+ SelectionPosition SPositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false, bool virtualSpace=true);
int PositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false);
+ SelectionPosition SPositionFromLineX(int lineDoc, int x);
int PositionFromLineX(int line, int x);
int LineFromLocation(Point pt);
void SetTopLine(int topLineNew);
@@ -278,15 +280,21 @@ protected: // ScintillaBase subclass needs access to much of Editor
int SelectionStart();
int SelectionEnd();
void SetRectangularRange();
- void InvalidateSelection(int currentPos_, int anchor_, bool invalidateWholeSelection);
+ void InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection=false);
+ void SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_);
void SetSelection(int currentPos_, int anchor_);
+ void SetSelection(SelectionPosition currentPos_);
void SetSelection(int currentPos_);
+ void SetEmptySelection(SelectionPosition currentPos_);
void SetEmptySelection(int currentPos_);
bool RangeContainsProtected(int start, int end) const;
bool SelectionContainsProtected();
int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true) const;
- int MovePositionTo(int newPos, selTypes sel=noSel, bool ensureVisible=true);
- int MovePositionSoVisible(int pos, int moveDir);
+ SelectionPosition MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd=true) const;
+ int MovePositionTo(SelectionPosition newPos, Selection::selTypes sel=Selection::noSel, bool ensureVisible=true);
+ int MovePositionTo(int newPos, Selection::selTypes sel=Selection::noSel, bool ensureVisible=true);
+ SelectionPosition MovePositionSoVisible(SelectionPosition pos, int moveDir);
+ SelectionPosition MovePositionSoVisible(int pos, int moveDir);
void SetLastXChosen();
void ScrollTo(int line, bool moveThumb=true);
@@ -324,8 +332,10 @@ protected: // ScintillaBase subclass needs access to much of Editor
void DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart,
PRectangle rcLine, LineLayout *ll, int subLine);
void DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart,
- PRectangle rcLine, LineLayout *ll, int subLine=0);
+ PRectangle rcLine, LineLayout *ll, int subLine);
void DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret);
+ void DrawCarets(Surface *surface, ViewStyle &vsDraw, int line, int xStart,
+ PRectangle rcLine, LineLayout *ll, int subLine);
void RefreshPixMaps(Surface *surfaceWindow);
void Paint(Surface *surfaceWindow, PRectangle rcArea);
long FormatRange(bool draw, Sci_RangeToFormat *pfr);
@@ -344,7 +354,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
void ClearAll();
void ClearDocumentStyle();
void Cut();
- void PasteRectangular(int pos, const char *ptr, int len);
+ void PasteRectangular(SelectionPosition pos, const char *ptr, int len);
virtual void Copy() = 0;
virtual void CopyAllowLine();
virtual bool CanPaste();
@@ -384,14 +394,14 @@ protected: // ScintillaBase subclass needs access to much of Editor
void NotifyStyleNeeded(Document *doc, void *userData, int endPos);
void NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
- void PageMove(int direction, selTypes sel=noSel, bool stuttered = false);
+ void PageMove(int direction, Selection::selTypes sel=Selection::noSel, bool stuttered = false);
void ChangeCaseOfSelection(bool makeUpperCase);
void LineTranspose();
void Duplicate(bool forLine);
virtual void CancelModes();
void NewLine();
- void CursorUpOrDown(int direction, selTypes sel=noSel);
- void ParaUpOrDown(int direction, selTypes sel=noSel);
+ void CursorUpOrDown(int direction, Selection::selTypes sel=Selection::noSel);
+ void ParaUpOrDown(int direction, Selection::selTypes sel=Selection::noSel);
int StartEndDisplayLine(int pos, bool start);
virtual int KeyCommand(unsigned int iMessage);
virtual int KeyDefault(int /* key */, int /*modifiers*/);
@@ -410,7 +420,6 @@ protected: // ScintillaBase subclass needs access to much of Editor
virtual void CopyToClipboard(const SelectionText &selectedText) = 0;
char *CopyRange(int start, int end);
- void CopySelectionFromRange(SelectionText *ss, bool allowLineCopy, int start, int end);
void CopySelectionRange(SelectionText *ss, bool allowLineCopy=false);
void CopyRangeToClipboard(int start, int end);
void CopyText(int length, const char *text);
@@ -419,9 +428,8 @@ protected: // ScintillaBase subclass needs access to much of Editor
virtual bool DragThreshold(Point ptStart, Point ptNow);
virtual void StartDrag();
void DropAt(int position, const char *value, bool moving, bool rectangular);
- /** PositionInSelection returns 0 if position in selection, -1 if position before selection, and 1 if after.
- * Before means either before any line of selection or before selection on its line, with a similar meaning to after. */
- int PositionInSelection(int pos);
+ /** PositionInSelection returns true if position in selection. */
+ bool PositionInSelection(int pos);
bool PointInSelection(Point pt);
bool PointInSelMargin(Point pt);
void LineSelection(int lineCurrent_, int lineAnchor_);
diff --git a/src/PositionCache.cxx b/src/PositionCache.cxx
index 71b408236..258a14860 100644
--- a/src/PositionCache.cxx
+++ b/src/PositionCache.cxx
@@ -28,6 +28,7 @@
#include "CharClassify.h"
#include "Decoration.h"
#include "Document.h"
+#include "Selection.h"
#include "PositionCache.h"
#ifdef SCI_NAMESPACE
@@ -46,11 +47,11 @@ LineLayout::LineLayout(int maxLineLength_) :
inCache(false),
maxLineLength(-1),
numCharsInLine(0),
+ numCharsBeforeEOL(0),
validity(llInvalid),
xHighlightGuide(0),
highlightColumn(0),
- selStart(0),
- selEnd(0),
+ psel(NULL),
containsCaret(false),
edgeColumn(0),
chars(0),
@@ -115,12 +116,7 @@ int LineLayout::LineLastVisible(int line) const {
if (line < 0) {
return 0;
} else if ((line >= lines-1) || !lineStarts) {
- int startLine = LineStart(line);
- int endLine = numCharsInLine;
- while ((endLine > startLine) && IsEOLChar(chars[endLine-1])) {
- endLine--;
- }
- return endLine;
+ return numCharsBeforeEOL;
} else {
return lineStarts[line+1];
}
@@ -412,9 +408,13 @@ BreakFinder::BreakFinder(LineLayout *ll_, int lineStart_, int lineEnd_, int posL
nextBreak--;
}
- if (ll->selStart != ll->selEnd) {
- Insert(ll->selStart - posLineStart - 1);
- Insert(ll->selEnd - posLineStart - 1);
+ for (size_t r=0; r<ll->psel->Count(); r++) {
+ SelectionPosition spStart;
+ SelectionPosition spEnd;
+ if (ll->psel->Range(r).Intersect(posLineStart, posLineStart + lineEnd, spStart, spEnd)) {
+ Insert(spStart.Position() - posLineStart - 1);
+ Insert(spEnd.Position() - posLineStart - 1);
+ }
}
Insert(ll->edgeColumn - 1);
diff --git a/src/PositionCache.h b/src/PositionCache.h
index 6c4c62efd..bd984d40b 100644
--- a/src/PositionCache.h
+++ b/src/PositionCache.h
@@ -2,7 +2,7 @@
/** @file PositionCache.h
** Classes for caching layout information.
**/
-// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
+// Copyright 1998-2009 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#ifndef POSITIONCACHE_H
@@ -30,11 +30,11 @@ public:
enum { wrapWidthInfinite = 0x7ffffff };
int maxLineLength;
int numCharsInLine;
+ int numCharsBeforeEOL;
enum validLevel { llInvalid, llCheckTextAndStyle, llPositions, llLines } validity;
int xHighlightGuide;
bool highlightColumn;
- int selStart;
- int selEnd;
+ Selection *psel;
bool containsCaret;
int edgeColumn;
char *chars;
diff --git a/src/ScintillaBase.cxx b/src/ScintillaBase.cxx
index 31e580336..b47986ff0 100644
--- a/src/ScintillaBase.cxx
+++ b/src/ScintillaBase.cxx
@@ -36,6 +36,7 @@
#include "CharClassify.h"
#include "Decoration.h"
#include "Document.h"
+#include "Selection.h"
#include "PositionCache.h"
#include "Editor.h"
#include "ScintillaBase.h"
@@ -190,7 +191,7 @@ int ScintillaBase::KeyCommand(unsigned int iMessage) {
ct.CallTipCancel();
}
if ((iMessage == SCI_DELETEBACK) || (iMessage == SCI_DELETEBACKNOTLINE)) {
- if (currentPos <= ct.posStartCallTip) {
+ if (sel.MainCaret() <= ct.posStartCallTip) {
ct.CallTipCancel();
}
}
@@ -212,24 +213,24 @@ void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) {
const char *typeSep = strchr(list, ac.GetTypesep());
size_t lenInsert = (typeSep) ? (typeSep-list) : strlen(list);
if (ac.ignoreCase) {
- SetEmptySelection(currentPos - lenEntered);
- pdoc->DeleteChars(currentPos, lenEntered);
- SetEmptySelection(currentPos);
- pdoc->InsertString(currentPos, list, lenInsert);
- SetEmptySelection(currentPos + lenInsert);
+ SetEmptySelection(sel.MainCaret() - lenEntered);
+ pdoc->DeleteChars(sel.MainCaret(), lenEntered);
+ SetEmptySelection(sel.MainCaret());
+ pdoc->InsertString(sel.MainCaret(), list, lenInsert);
+ SetEmptySelection(sel.MainCaret() + lenInsert);
} else {
- SetEmptySelection(currentPos);
- pdoc->InsertString(currentPos, list + lenEntered, lenInsert - lenEntered);
- SetEmptySelection(currentPos + lenInsert - lenEntered);
+ SetEmptySelection(sel.MainCaret());
+ pdoc->InsertString(sel.MainCaret(), list + lenEntered, lenInsert - lenEntered);
+ SetEmptySelection(sel.MainCaret() + lenInsert - lenEntered);
}
return;
}
}
- ac.Start(wMain, idAutoComplete, currentPos, LocationFromPosition(currentPos),
+ ac.Start(wMain, idAutoComplete, sel.MainCaret(), LocationFromPosition(sel.MainCaret()),
lenEntered, vs.lineHeight, IsUnicodeMode());
PRectangle rcClient = GetClientRectangle();
- Point pt = LocationFromPosition(currentPos - lenEntered);
+ Point pt = LocationFromPosition(sel.MainCaret() - lenEntered);
PRectangle rcPopupBounds = wMain.GetMonitorRect(pt);
if (rcPopupBounds.Height() == 0)
rcPopupBounds = rcClient;
@@ -239,7 +240,7 @@ void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) {
if (pt.x >= rcClient.right - widthLB) {
HorizontalScrollTo(xOffset + pt.x - rcClient.right + widthLB);
Redraw();
- pt = LocationFromPosition(currentPos);
+ pt = LocationFromPosition(sel.MainCaret());
}
PRectangle rcac;
rcac.left = pt.x - ac.lb->CaretFromEdge();
@@ -305,7 +306,7 @@ void ScintillaBase::AutoCompleteMoveToCurrentWord() {
char wordCurrent[1000];
int i;
int startWord = ac.posStart - ac.startLen;
- for (i = startWord; i < currentPos && i - startWord < 1000; i++)
+ for (i = startWord; i < sel.MainCaret() && i - startWord < 1000; i++)
wordCurrent[i - startWord] = pdoc->CharAt(i);
wordCurrent[Platform::Minimum(i - startWord, 999)] = '\0';
ac.Select(wordCurrent);
@@ -322,9 +323,9 @@ void ScintillaBase::AutoCompleteCharacterAdded(char ch) {
}
void ScintillaBase::AutoCompleteCharacterDeleted() {
- if (currentPos < ac.posStart - ac.startLen) {
+ if (sel.MainCaret() < ac.posStart - ac.startLen) {
AutoCompleteCancel();
- } else if (ac.cancelAtStartPos && (currentPos <= ac.posStart)) {
+ } else if (ac.cancelAtStartPos && (sel.MainCaret() <= ac.posStart)) {
AutoCompleteCancel();
} else {
AutoCompleteMoveToCurrentWord();
@@ -367,7 +368,7 @@ void ScintillaBase::AutoCompleteCompleted() {
if (listType > 0)
return;
- Position endPos = currentPos;
+ Position endPos = sel.MainCaret();
if (ac.dropRestOfWord)
endPos = pdoc->ExtendWordSelect(endPos, 1, true);
if (endPos < firstPos)
@@ -401,7 +402,7 @@ void ScintillaBase::CallTipShow(Point pt, const char *defn) {
if (ct.UseStyleCallTip()) {
ct.SetForeBack(vs.styles[STYLE_CALLTIP].fore, vs.styles[STYLE_CALLTIP].back);
}
- PRectangle rc = ct.CallTipStart(currentPos, pt,
+ PRectangle rc = ct.CallTipStart(sel.MainCaret(), pt,
defn,
vs.styles[ctStyle].fontName,
vs.styles[ctStyle].sizeZoomed,
@@ -436,10 +437,10 @@ void ScintillaBase::ContextMenu(Point pt) {
AddToPopUp("Undo", idcmdUndo, writable && pdoc->CanUndo());
AddToPopUp("Redo", idcmdRedo, writable && pdoc->CanRedo());
AddToPopUp("");
- AddToPopUp("Cut", idcmdCut, writable && currentPos != anchor);
- AddToPopUp("Copy", idcmdCopy, currentPos != anchor);
+ AddToPopUp("Cut", idcmdCut, writable && !sel.Empty());
+ AddToPopUp("Copy", idcmdCopy, !sel.Empty());
AddToPopUp("Paste", idcmdPaste, writable && WndProc(SCI_CANPASTE, 0, 0));
- AddToPopUp("Delete", idcmdDelete, writable && currentPos != anchor);
+ AddToPopUp("Delete", idcmdDelete, writable && !sel.Empty());
AddToPopUp("");
AddToPopUp("Select All", idcmdSelectAll);
popup.Show(pt, wMain);
diff --git a/src/Selection.cxx b/src/Selection.cxx
new file mode 100644
index 000000000..224fafc69
--- /dev/null
+++ b/src/Selection.cxx
@@ -0,0 +1,345 @@
+// Scintilla source code edit control
+/** @file Selection.cxx
+ ** Classes maintaining the selection.
+ **/
+// Copyright 2009 by Neil Hodgson <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#include <stdlib.h>
+
+#include "Platform.h"
+
+#include "Scintilla.h"
+
+#include "Selection.h"
+
+#ifdef SCI_NAMESPACE
+using namespace Scintilla;
+#endif
+
+void SelectionPosition::MoveForInsertDelete(bool insertion, int startChange, int length) {
+ if (insertion) {
+ if (position > startChange) {
+ position += length;
+ }
+ } else {
+ if (position > startChange) {
+ int endDeletion = startChange + length;
+ if (position > endDeletion) {
+ position -= length;
+ } else {
+ position = startChange;
+ }
+ }
+ }
+}
+
+bool SelectionPosition::operator <(const SelectionPosition &other) const {
+ if (position == other.position)
+ return virtualSpace < other.virtualSpace;
+ else
+ return position < other.position;
+}
+
+bool SelectionPosition::operator >(const SelectionPosition &other) const {
+ if (position == other.position)
+ return virtualSpace > other.virtualSpace;
+ else
+ return position > other.position;
+}
+
+bool SelectionPosition::operator <=(const SelectionPosition &other) const {
+ if (position == other.position && virtualSpace == other.virtualSpace)
+ return true;
+ else
+ return other > *this;
+}
+
+bool SelectionPosition::operator >=(const SelectionPosition &other) const {
+ if (position == other.position && virtualSpace == other.virtualSpace)
+ return true;
+ else
+ return *this > other;
+}
+
+int SelectionRange::Length() const {
+ if (anchor > caret) {
+ return anchor.Position() - caret.Position();
+ } else {
+ return caret.Position() - anchor.Position();
+ }
+}
+
+bool SelectionRange::Contains(int pos) const {
+ if (anchor > caret)
+ return (pos >= caret.Position()) && (pos <= anchor.Position());
+ else
+ return (pos >= anchor.Position()) && (pos <= caret.Position());
+}
+
+bool SelectionRange::Contains(SelectionPosition sp) const {
+ if (anchor > caret)
+ return (sp >= caret) && (sp <= anchor);
+ else
+ return (sp >= anchor) && (sp <= caret);
+}
+
+bool SelectionRange::ContainsCharacter(int posCharacter) const {
+ if (anchor > caret)
+ return (posCharacter >= caret.Position()) && (posCharacter < anchor.Position());
+ else
+ return (posCharacter >= anchor.Position()) && (posCharacter < caret.Position());
+}
+
+bool SelectionRange::Intersect(int start, int end, SelectionPosition &selStart, SelectionPosition &selEnd) const {
+ SelectionPosition spEnd(end, 100000); // Large amount of virtual space
+ SelectionPosition first;
+ SelectionPosition last;
+ if (anchor > caret) {
+ first = caret;
+ last = anchor;
+ } else {
+ first = anchor;
+ last = caret;
+ }
+ if ((first < spEnd) && (last.Position() > start)) {
+ if (start > first.Position())
+ selStart = SelectionPosition(start);
+ else
+ selStart = first;
+ if (spEnd < last)
+ selEnd = SelectionPosition(end);
+ else
+ selEnd = last;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool SelectionRange::Trim(SelectionPosition startPos, SelectionPosition endPos) {
+ SelectionPosition startRange = startPos;
+ SelectionPosition endRange = endPos;
+ if (startPos > endPos) {
+ startRange = endPos;
+ endRange = startPos;
+ }
+ SelectionPosition start = Start();
+ SelectionPosition end = End();
+ PLATFORM_ASSERT(start <= end);
+ PLATFORM_ASSERT(startRange <= endRange);
+ if ((startRange <= end) && (endRange >= start)) {
+ if ((start > startRange) && (end < endRange)) {
+ // Completely covered by range -> empty at start
+ end = start;
+ } else if ((start < startRange) && (end > endRange)) {
+ // Completely covers range -> empty at start
+ end = start;
+ } else if (start <= startRange) {
+ // Trim end
+ end = startRange;
+ } else { //
+ PLATFORM_ASSERT(end >= endRange);
+ // Trim start
+ start = endRange;
+ }
+ if (anchor > caret) {
+ caret = start;
+ anchor = end;
+ } else {
+ anchor = start;
+ caret = end;
+ }
+ return Empty();
+ } else {
+ return false;
+ }
+}
+
+// If range is all virtual collapse to start of virtual space
+void SelectionRange::MinimizeVirtualSpace() {
+ if (caret.Position() == anchor.Position()) {
+ int virtualSpace = caret.VirtualSpace();
+ if (virtualSpace > anchor.VirtualSpace())
+ virtualSpace = anchor.VirtualSpace();
+ caret.SetVirtualSpace(virtualSpace);
+ anchor.SetVirtualSpace(virtualSpace);
+ }
+}
+
+void Selection::Allocate() {
+ if (nRanges >= allocated) {
+ size_t allocateNew = (allocated + 1) * 2;
+ SelectionRange *rangesNew = new SelectionRange[allocateNew];
+ for (size_t r=0; r<Count(); r++)
+ rangesNew[r] = ranges[r];
+ delete []ranges;
+ ranges = rangesNew;
+ allocated = allocateNew;
+ }
+}
+
+Selection::Selection() : ranges(0), allocated(0), nRanges(0), mainRange(0), moveExtends(false), selType(selStream) {
+ AddSelection(SelectionPosition(0));
+}
+
+Selection::~Selection() {
+ delete []ranges;
+}
+
+bool Selection::IsRectangular() const {
+ return (selType == selRectangle) || (selType == selThin);
+}
+
+int Selection::MainCaret() const {
+ return ranges[mainRange].caret.Position();
+}
+
+int Selection::MainAnchor() const {
+ return ranges[mainRange].anchor.Position();
+}
+
+SelectionRange &Selection::Rectangular() {
+ return rangeRectangular;
+}
+
+size_t Selection::Count() const {
+ return nRanges;
+}
+
+size_t Selection::Main() const {
+ return mainRange;
+}
+
+void Selection::SetMain(size_t r) {
+ PLATFORM_ASSERT(r < nRanges);
+ mainRange = r;
+}
+
+SelectionRange &Selection::Range(size_t r) {
+ return ranges[r];
+}
+
+SelectionRange &Selection::RangeMain() {
+ return ranges[mainRange];
+}
+
+void Selection::ClearVirtualSpace(size_t r) {
+ ranges[r].ClearVirtualSpace();
+}
+
+bool Selection::MoveExtends() const {
+ return moveExtends;
+}
+
+void Selection::SetMoveExtends(bool moveExtends_) {
+ moveExtends = moveExtends_;
+}
+
+bool Selection::Empty() const {
+ for (size_t i=0; i<nRanges; i++) {
+ if (!ranges[i].Empty())
+ return false;
+ }
+ return true;
+}
+
+SelectionPosition Selection::Last() const {
+ SelectionPosition lastPosition;
+ for (size_t i=0; i<nRanges; i++) {
+ if (lastPosition < ranges[i].caret)
+ lastPosition = ranges[i].caret;
+ if (lastPosition < ranges[i].anchor)
+ lastPosition = ranges[i].anchor;
+ }
+ return lastPosition;
+}
+
+int Selection::Length() const {
+ int len = 0;
+ for (size_t i=0; i<nRanges; i++) {
+ len += ranges[i].Length();
+ }
+ return len;
+}
+
+void Selection::MovePositions(bool insertion, int startChange, int length) {
+ for (size_t i=0; i<nRanges; i++) {
+ ranges[i].caret.MoveForInsertDelete(insertion, startChange, length);
+ ranges[i].anchor.MoveForInsertDelete(insertion, startChange, length);
+ }
+}
+
+void Selection::TrimSelection(SelectionPosition startPos, SelectionPosition endPos) {
+ for (size_t i=0; i<nRanges;) {
+ if ((i != mainRange) && (ranges[i].Trim(startPos, endPos))) {
+ // Trimmed to empty so remove
+ for (size_t j=i;j<nRanges-1;j++) {
+ ranges[j] = ranges[j+1];
+ if (j == mainRange-1)
+ mainRange--;
+ }
+ nRanges--;
+ } else {
+ i++;
+ }
+ }
+}
+
+void Selection::AddSelection(SelectionPosition spPos) {
+ Allocate();
+ TrimSelection(spPos, spPos);
+ ranges[nRanges] = SelectionRange(spPos);
+ mainRange = nRanges;
+ nRanges++;
+}
+
+void Selection::AddSelection(SelectionPosition spStartPos, SelectionPosition spEndPos, bool anchorLeft) {
+ Allocate();
+ TrimSelection(spStartPos, spEndPos);
+ ranges[nRanges].caret = anchorLeft ? spEndPos : spStartPos;
+ ranges[nRanges].anchor = anchorLeft ? spStartPos : spEndPos;
+ mainRange = nRanges;
+ nRanges++;
+}
+
+bool Selection::CharacterInSelection(int posCharacter) const {
+ for (size_t i=0; i<nRanges; i++) {
+ if (ranges[i].ContainsCharacter(posCharacter))
+ return true;
+ }
+ return false;
+}
+
+bool Selection::InSelectionForEOL(int pos) const {
+ for (size_t i=0; i<nRanges; i++) {
+ if (!ranges[i].Empty() && (pos > ranges[i].Start().Position()) && (pos <= ranges[i].End().Position()))
+ return true;
+ }
+ return false;
+}
+
+int Selection::VirtualSpaceFor(int pos) const {
+ int virtualSpace = 0;
+ for (size_t i=0; i<nRanges; i++) {
+ if ((ranges[i].caret.Position() == pos) && (virtualSpace < ranges[i].caret.VirtualSpace()))
+ virtualSpace = ranges[i].caret.VirtualSpace();
+ if ((ranges[i].anchor.Position() == pos) && (virtualSpace < ranges[i].anchor.VirtualSpace()))
+ virtualSpace = ranges[i].anchor.VirtualSpace();
+ }
+ return virtualSpace;
+}
+
+void Selection::Clear() {
+ nRanges = 1;
+ mainRange = 0;
+ selType = selStream;
+ moveExtends = false;
+ ranges[mainRange].Reset();
+ rangeRectangular.Reset();
+}
+
+void Selection::EmptyRanges() {
+ nRanges = 0;
+ mainRange = 0;
+}
diff --git a/src/Selection.h b/src/Selection.h
new file mode 100644
index 000000000..fe6a1c464
--- /dev/null
+++ b/src/Selection.h
@@ -0,0 +1,142 @@
+// Scintilla source code edit control
+/** @file Selection.h
+ ** Classes maintaining the selection.
+ **/
+// Copyright 2009 by Neil Hodgson <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#ifndef SELECTION_H
+#define SELECTION_H
+
+#ifdef SCI_NAMESPACE
+namespace Scintilla {
+#endif
+
+class SelectionPosition {
+ int position;
+ int virtualSpace;
+public:
+ explicit SelectionPosition(int position_=INVALID_POSITION, int virtualSpace_=0) : position(position_), virtualSpace(virtualSpace_) {
+ PLATFORM_ASSERT(virtualSpace < 800000);
+ if (virtualSpace < 0)
+ virtualSpace = 0;
+ }
+ void Reset() {
+ position = 0;
+ virtualSpace = 0;
+ }
+ void MoveForInsertDelete(bool insertion, int startChange, int length);
+ bool operator ==(const SelectionPosition &other) const {
+ return position == other.position && virtualSpace == other.virtualSpace;
+ }
+ bool operator <(const SelectionPosition &other) const;
+ bool operator >(const SelectionPosition &other) const;
+ bool operator <=(const SelectionPosition &other) const;
+ bool operator >=(const SelectionPosition &other) const;
+ int Position() const {
+ return position;
+ }
+ void SetPosition(int position_) {
+ position = position_;
+ virtualSpace = 0;
+ }
+ int VirtualSpace() const {
+ return virtualSpace;
+ }
+ void SetVirtualSpace(int virtualSpace_) {
+ PLATFORM_ASSERT(virtualSpace_ < 800000);
+ if (virtualSpace_ >= 0)
+ virtualSpace = virtualSpace_;
+ }
+ void Add(int increment) {
+ position = position + increment;
+ }
+};
+
+struct SelectionRange {
+ SelectionPosition caret;
+ SelectionPosition anchor;
+
+ SelectionRange() {
+ }
+ SelectionRange(SelectionPosition single) : caret(single), anchor(single) {
+ }
+ SelectionRange(SelectionPosition caret_, SelectionPosition anchor_) : caret(caret_), anchor(anchor_) {
+ }
+ SelectionRange(int caret_, int anchor_) : caret(caret_), anchor(anchor_) {
+ }
+ bool Empty() const {
+ return anchor == caret;
+ }
+ int Length() const;
+ bool operator ==(const SelectionRange &other) const {
+ return caret == other.caret && anchor == other.anchor;
+ }
+ void Reset() {
+ anchor.Reset();
+ caret.Reset();
+ }
+ void ClearVirtualSpace() {
+ anchor.SetVirtualSpace(0);
+ caret.SetVirtualSpace(0);
+ }
+ bool Contains(int pos) const;
+ bool Contains(SelectionPosition sp) const;
+ bool ContainsCharacter(int posCharacter) const;
+ bool Intersect(int start, int end, SelectionPosition &selStart, SelectionPosition &selEnd) const;
+ SelectionPosition Start() const {
+ return (anchor < caret) ? anchor : caret;
+ }
+ SelectionPosition End() const {
+ return (anchor < caret) ? caret : anchor;
+ }
+ bool Trim(SelectionPosition startPos, SelectionPosition endPos);
+ // If range is all virtual collapse to start of virtual space
+ void MinimizeVirtualSpace();
+};
+
+class Selection {
+ SelectionRange *ranges;
+ SelectionRange rangeRectangular;
+ size_t allocated;
+ size_t nRanges;
+ size_t mainRange;
+ bool moveExtends;
+ void Allocate();
+public:
+ enum selTypes { noSel, selStream, selRectangle, selLines, selThin };
+ selTypes selType;
+
+ Selection();
+ ~Selection();
+ bool IsRectangular() const;
+ int MainCaret() const;
+ int MainAnchor() const;
+ SelectionRange &Rectangular();
+ size_t Count() const;
+ size_t Main() const;
+ void SetMain(size_t r);
+ SelectionRange &Range(size_t r);
+ SelectionRange &RangeMain();
+ void ClearVirtualSpace(size_t r);
+ bool MoveExtends() const;
+ void SetMoveExtends(bool moveExtends_);
+ bool Empty() const;
+ SelectionPosition Last() const;
+ int Length() const;
+ void MovePositions(bool insertion, int startChange, int length);
+ void TrimSelection(SelectionPosition startPos, SelectionPosition endPos);
+ void AddSelection(SelectionPosition spPos);
+ void AddSelection(SelectionPosition spStartPos, SelectionPosition spEndPos, bool anchorLeft);
+ bool CharacterInSelection(int posCharacter) const;
+ bool InSelectionForEOL(int pos) const;
+ int VirtualSpaceFor(int pos) const;
+ void Clear();
+ void EmptyRanges();
+};
+
+#ifdef SCI_NAMESPACE
+}
+#endif
+
+#endif