// Scintilla source code edit control /** @file Selection.cxx ** Classes maintaining the selection. **/ // Copyright 2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "Position.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) { int virtualLengthRemove = std::min(length, virtualSpace); virtualSpace -= virtualLengthRemove; position += virtualLengthRemove; } else if (position > startChange) { position += length; } } else { if (position == startChange) { virtualSpace = 0; } if (position > startChange) { int endDeletion = startChange + length; if (position > endDeletion) { position -= length; } else { position = startChange; virtualSpace = 0; } } } } 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(); } } void SelectionRange::MoveForInsertDelete(bool insertion, int startChange, int length) { caret.MoveForInsertDelete(insertion, startChange, length); anchor.MoveForInsertDelete(insertion, startChange, length); } 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()); } SelectionSegment SelectionRange::Intersect(SelectionSegment check) const { SelectionSegment inOrder(caret, anchor); if ((inOrder.start <= check.end) || (inOrder.end >= check.start)) { SelectionSegment portion = check; if (portion.start < inOrder.start) portion.start = inOrder.start; if (portion.end > inOrder.end) portion.end = inOrder.end; if (portion.start > portion.end) return SelectionSegment(); else return portion; } else { return SelectionSegment(); } } void SelectionRange::Swap() { std::swap(caret, anchor); } bool SelectionRange::Trim(SelectionRange range) { SelectionPosition startRange = range.Start(); SelectionPosition endRange = range.End(); 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); } } Selection::Selection() : mainRange(0), moveExtends(false), tentativeMain(false), selType(selStream) { AddSelection(SelectionRange(SelectionPosition(0))); } Selection::~Selection() { } 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; } SelectionSegment Selection::Limits() const { if (ranges.empty()) { return SelectionSegment(); } else { SelectionSegment sr(ranges[0].anchor, ranges[0].caret); for (size_t i=1; i 1) && (r < ranges.size())) { size_t mainNew = mainRange; if (mainNew >= r) { if (mainNew == 0) { mainNew = ranges.size() - 2; } else { mainNew--; } } ranges.erase(ranges.begin() + r); mainRange = mainNew; } } void Selection::DropAdditionalRanges() { SetSelection(RangeMain()); } void Selection::TentativeSelection(SelectionRange range) { if (!tentativeMain) { rangesSaved = ranges; } ranges = rangesSaved; AddSelection(range); TrimSelection(ranges[mainRange]); tentativeMain = true; } void Selection::CommitTentative() { rangesSaved.clear(); tentativeMain = false; } int Selection::CharacterInSelection(int posCharacter) const { for (size_t i=0; i ranges[i].Start().Position()) && (pos <= ranges[i].End().Position())) return i == mainRange ? 1 : 2; } return 0; } int Selection::VirtualSpaceFor(int pos) const { int virtualSpace = 0; for (size_t i=0; i= j) mainRange--; } else { j++; } } } } } void Selection::RotateMain() { mainRange = (mainRange + 1) % ranges.size(); }