Update Scintilla to version 3.5.7
[TortoiseGit.git] / ext / scintilla / src / Selection.cxx
blob498c4c0b2c721ef4bc165b86749e0c2dfbd1d522
1 // Scintilla source code edit control
2 /** @file Selection.cxx
3 ** Classes maintaining the selection.
4 **/
5 // Copyright 2009 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
8 #include <stdlib.h>
10 #include <vector>
11 #include <algorithm>
13 #include "Platform.h"
15 #include "Scintilla.h"
17 #include "Selection.h"
19 #ifdef SCI_NAMESPACE
20 using namespace Scintilla;
21 #endif
23 void SelectionPosition::MoveForInsertDelete(bool insertion, int startChange, int length) {
24 if (insertion) {
25 if (position == startChange) {
26 int virtualLengthRemove = std::min(length, virtualSpace);
27 virtualSpace -= virtualLengthRemove;
28 position += virtualLengthRemove;
29 } else if (position > startChange) {
30 position += length;
32 } else {
33 if (position == startChange) {
34 virtualSpace = 0;
36 if (position > startChange) {
37 int endDeletion = startChange + length;
38 if (position > endDeletion) {
39 position -= length;
40 } else {
41 position = startChange;
42 virtualSpace = 0;
48 bool SelectionPosition::operator <(const SelectionPosition &other) const {
49 if (position == other.position)
50 return virtualSpace < other.virtualSpace;
51 else
52 return position < other.position;
55 bool SelectionPosition::operator >(const SelectionPosition &other) const {
56 if (position == other.position)
57 return virtualSpace > other.virtualSpace;
58 else
59 return position > other.position;
62 bool SelectionPosition::operator <=(const SelectionPosition &other) const {
63 if (position == other.position && virtualSpace == other.virtualSpace)
64 return true;
65 else
66 return other > *this;
69 bool SelectionPosition::operator >=(const SelectionPosition &other) const {
70 if (position == other.position && virtualSpace == other.virtualSpace)
71 return true;
72 else
73 return *this > other;
76 int SelectionRange::Length() const {
77 if (anchor > caret) {
78 return anchor.Position() - caret.Position();
79 } else {
80 return caret.Position() - anchor.Position();
84 void SelectionRange::MoveForInsertDelete(bool insertion, int startChange, int length) {
85 caret.MoveForInsertDelete(insertion, startChange, length);
86 anchor.MoveForInsertDelete(insertion, startChange, length);
89 bool SelectionRange::Contains(int pos) const {
90 if (anchor > caret)
91 return (pos >= caret.Position()) && (pos <= anchor.Position());
92 else
93 return (pos >= anchor.Position()) && (pos <= caret.Position());
96 bool SelectionRange::Contains(SelectionPosition sp) const {
97 if (anchor > caret)
98 return (sp >= caret) && (sp <= anchor);
99 else
100 return (sp >= anchor) && (sp <= caret);
103 bool SelectionRange::ContainsCharacter(int posCharacter) const {
104 if (anchor > caret)
105 return (posCharacter >= caret.Position()) && (posCharacter < anchor.Position());
106 else
107 return (posCharacter >= anchor.Position()) && (posCharacter < caret.Position());
110 SelectionSegment SelectionRange::Intersect(SelectionSegment check) const {
111 SelectionSegment inOrder(caret, anchor);
112 if ((inOrder.start <= check.end) || (inOrder.end >= check.start)) {
113 SelectionSegment portion = check;
114 if (portion.start < inOrder.start)
115 portion.start = inOrder.start;
116 if (portion.end > inOrder.end)
117 portion.end = inOrder.end;
118 if (portion.start > portion.end)
119 return SelectionSegment();
120 else
121 return portion;
122 } else {
123 return SelectionSegment();
127 bool SelectionRange::Trim(SelectionRange range) {
128 SelectionPosition startRange = range.Start();
129 SelectionPosition endRange = range.End();
130 SelectionPosition start = Start();
131 SelectionPosition end = End();
132 PLATFORM_ASSERT(start <= end);
133 PLATFORM_ASSERT(startRange <= endRange);
134 if ((startRange <= end) && (endRange >= start)) {
135 if ((start > startRange) && (end < endRange)) {
136 // Completely covered by range -> empty at start
137 end = start;
138 } else if ((start < startRange) && (end > endRange)) {
139 // Completely covers range -> empty at start
140 end = start;
141 } else if (start <= startRange) {
142 // Trim end
143 end = startRange;
144 } else { //
145 PLATFORM_ASSERT(end >= endRange);
146 // Trim start
147 start = endRange;
149 if (anchor > caret) {
150 caret = start;
151 anchor = end;
152 } else {
153 anchor = start;
154 caret = end;
156 return Empty();
157 } else {
158 return false;
162 // If range is all virtual collapse to start of virtual space
163 void SelectionRange::MinimizeVirtualSpace() {
164 if (caret.Position() == anchor.Position()) {
165 int virtualSpace = caret.VirtualSpace();
166 if (virtualSpace > anchor.VirtualSpace())
167 virtualSpace = anchor.VirtualSpace();
168 caret.SetVirtualSpace(virtualSpace);
169 anchor.SetVirtualSpace(virtualSpace);
173 Selection::Selection() : mainRange(0), moveExtends(false), tentativeMain(false), selType(selStream) {
174 AddSelection(SelectionRange(SelectionPosition(0)));
177 Selection::~Selection() {
180 bool Selection::IsRectangular() const {
181 return (selType == selRectangle) || (selType == selThin);
184 int Selection::MainCaret() const {
185 return ranges[mainRange].caret.Position();
188 int Selection::MainAnchor() const {
189 return ranges[mainRange].anchor.Position();
192 SelectionRange &Selection::Rectangular() {
193 return rangeRectangular;
196 SelectionSegment Selection::Limits() const {
197 if (ranges.empty()) {
198 return SelectionSegment();
199 } else {
200 SelectionSegment sr(ranges[0].anchor, ranges[0].caret);
201 for (size_t i=1; i<ranges.size(); i++) {
202 sr.Extend(ranges[i].anchor);
203 sr.Extend(ranges[i].caret);
205 return sr;
209 SelectionSegment Selection::LimitsForRectangularElseMain() const {
210 if (IsRectangular()) {
211 return Limits();
212 } else {
213 return SelectionSegment(ranges[mainRange].caret, ranges[mainRange].anchor);
217 size_t Selection::Count() const {
218 return ranges.size();
221 size_t Selection::Main() const {
222 return mainRange;
225 void Selection::SetMain(size_t r) {
226 PLATFORM_ASSERT(r < ranges.size());
227 mainRange = r;
230 SelectionRange &Selection::Range(size_t r) {
231 return ranges[r];
234 const SelectionRange &Selection::Range(size_t r) const {
235 return ranges[r];
238 SelectionRange &Selection::RangeMain() {
239 return ranges[mainRange];
242 const SelectionRange &Selection::RangeMain() const {
243 return ranges[mainRange];
246 SelectionPosition Selection::Start() const {
247 if (IsRectangular()) {
248 return rangeRectangular.Start();
249 } else {
250 return ranges[mainRange].Start();
254 bool Selection::MoveExtends() const {
255 return moveExtends;
258 void Selection::SetMoveExtends(bool moveExtends_) {
259 moveExtends = moveExtends_;
262 bool Selection::Empty() const {
263 for (size_t i=0; i<ranges.size(); i++) {
264 if (!ranges[i].Empty())
265 return false;
267 return true;
270 SelectionPosition Selection::Last() const {
271 SelectionPosition lastPosition;
272 for (size_t i=0; i<ranges.size(); i++) {
273 if (lastPosition < ranges[i].caret)
274 lastPosition = ranges[i].caret;
275 if (lastPosition < ranges[i].anchor)
276 lastPosition = ranges[i].anchor;
278 return lastPosition;
281 int Selection::Length() const {
282 int len = 0;
283 for (size_t i=0; i<ranges.size(); i++) {
284 len += ranges[i].Length();
286 return len;
289 void Selection::MovePositions(bool insertion, int startChange, int length) {
290 for (size_t i=0; i<ranges.size(); i++) {
291 ranges[i].MoveForInsertDelete(insertion, startChange, length);
293 if (selType == selRectangle) {
294 rangeRectangular.MoveForInsertDelete(insertion, startChange, length);
298 void Selection::TrimSelection(SelectionRange range) {
299 for (size_t i=0; i<ranges.size();) {
300 if ((i != mainRange) && (ranges[i].Trim(range))) {
301 // Trimmed to empty so remove
302 for (size_t j=i; j<ranges.size()-1; j++) {
303 ranges[j] = ranges[j+1];
304 if (j == mainRange-1)
305 mainRange--;
307 ranges.pop_back();
308 } else {
309 i++;
314 void Selection::SetSelection(SelectionRange range) {
315 ranges.clear();
316 ranges.push_back(range);
317 mainRange = ranges.size() - 1;
320 void Selection::AddSelection(SelectionRange range) {
321 TrimSelection(range);
322 ranges.push_back(range);
323 mainRange = ranges.size() - 1;
326 void Selection::AddSelectionWithoutTrim(SelectionRange range) {
327 ranges.push_back(range);
328 mainRange = ranges.size() - 1;
331 void Selection::DropSelection(size_t r) {
332 if ((ranges.size() > 1) && (r < ranges.size())) {
333 size_t mainNew = mainRange;
334 if (mainNew >= r) {
335 if (mainNew == 0) {
336 mainNew = ranges.size() - 2;
337 } else {
338 mainNew--;
341 ranges.erase(ranges.begin() + r);
342 mainRange = mainNew;
346 void Selection::DropAdditionalRanges() {
347 SetSelection(RangeMain());
350 void Selection::TentativeSelection(SelectionRange range) {
351 if (!tentativeMain) {
352 rangesSaved = ranges;
354 ranges = rangesSaved;
355 AddSelection(range);
356 TrimSelection(ranges[mainRange]);
357 tentativeMain = true;
360 void Selection::CommitTentative() {
361 rangesSaved.clear();
362 tentativeMain = false;
365 int Selection::CharacterInSelection(int posCharacter) const {
366 for (size_t i=0; i<ranges.size(); i++) {
367 if (ranges[i].ContainsCharacter(posCharacter))
368 return i == mainRange ? 1 : 2;
370 return 0;
373 int Selection::InSelectionForEOL(int pos) const {
374 for (size_t i=0; i<ranges.size(); i++) {
375 if (!ranges[i].Empty() && (pos > ranges[i].Start().Position()) && (pos <= ranges[i].End().Position()))
376 return i == mainRange ? 1 : 2;
378 return 0;
381 int Selection::VirtualSpaceFor(int pos) const {
382 int virtualSpace = 0;
383 for (size_t i=0; i<ranges.size(); i++) {
384 if ((ranges[i].caret.Position() == pos) && (virtualSpace < ranges[i].caret.VirtualSpace()))
385 virtualSpace = ranges[i].caret.VirtualSpace();
386 if ((ranges[i].anchor.Position() == pos) && (virtualSpace < ranges[i].anchor.VirtualSpace()))
387 virtualSpace = ranges[i].anchor.VirtualSpace();
389 return virtualSpace;
392 void Selection::Clear() {
393 ranges.clear();
394 ranges.push_back(SelectionRange());
395 mainRange = ranges.size() - 1;
396 selType = selStream;
397 moveExtends = false;
398 ranges[mainRange].Reset();
399 rangeRectangular.Reset();
402 void Selection::RemoveDuplicates() {
403 for (size_t i=0; i<ranges.size()-1; i++) {
404 if (ranges[i].Empty()) {
405 size_t j=i+1;
406 while (j<ranges.size()) {
407 if (ranges[i] == ranges[j]) {
408 ranges.erase(ranges.begin() + j);
409 if (mainRange >= j)
410 mainRange--;
411 } else {
412 j++;
419 void Selection::RotateMain() {
420 mainRange = (mainRange + 1) % ranges.size();