updated Scintilla to 2.29
[TortoiseGit.git] / ext / scintilla / src / Selection.cxx
blob7192a2a65207cac826aaa6eb62d8275567486fcf
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>
12 #include "Platform.h"
14 #include "Scintilla.h"
16 #include "Selection.h"
18 #ifdef SCI_NAMESPACE
19 using namespace Scintilla;
20 #endif
22 void SelectionPosition::MoveForInsertDelete(bool insertion, int startChange, int length) {
23 if (position == startChange) {
24 virtualSpace = 0;
26 if (insertion) {
27 if (position > startChange) {
28 position += length;
30 } else {
31 if (position > startChange) {
32 int endDeletion = startChange + length;
33 if (position > endDeletion) {
34 position -= length;
35 } else {
36 position = startChange;
37 virtualSpace = 0;
43 bool SelectionPosition::operator <(const SelectionPosition &other) const {
44 if (position == other.position)
45 return virtualSpace < other.virtualSpace;
46 else
47 return position < other.position;
50 bool SelectionPosition::operator >(const SelectionPosition &other) const {
51 if (position == other.position)
52 return virtualSpace > other.virtualSpace;
53 else
54 return position > other.position;
57 bool SelectionPosition::operator <=(const SelectionPosition &other) const {
58 if (position == other.position && virtualSpace == other.virtualSpace)
59 return true;
60 else
61 return other > *this;
64 bool SelectionPosition::operator >=(const SelectionPosition &other) const {
65 if (position == other.position && virtualSpace == other.virtualSpace)
66 return true;
67 else
68 return *this > other;
71 int SelectionRange::Length() const {
72 if (anchor > caret) {
73 return anchor.Position() - caret.Position();
74 } else {
75 return caret.Position() - anchor.Position();
79 bool SelectionRange::Contains(int pos) const {
80 if (anchor > caret)
81 return (pos >= caret.Position()) && (pos <= anchor.Position());
82 else
83 return (pos >= anchor.Position()) && (pos <= caret.Position());
86 bool SelectionRange::Contains(SelectionPosition sp) const {
87 if (anchor > caret)
88 return (sp >= caret) && (sp <= anchor);
89 else
90 return (sp >= anchor) && (sp <= caret);
93 bool SelectionRange::ContainsCharacter(int posCharacter) const {
94 if (anchor > caret)
95 return (posCharacter >= caret.Position()) && (posCharacter < anchor.Position());
96 else
97 return (posCharacter >= anchor.Position()) && (posCharacter < caret.Position());
100 SelectionSegment SelectionRange::Intersect(SelectionSegment check) const {
101 SelectionSegment inOrder(caret, anchor);
102 if ((inOrder.start <= check.end) || (inOrder.end >= check.start)) {
103 SelectionSegment portion = check;
104 if (portion.start < inOrder.start)
105 portion.start = inOrder.start;
106 if (portion.end > inOrder.end)
107 portion.end = inOrder.end;
108 if (portion.start > portion.end)
109 return SelectionSegment();
110 else
111 return portion;
112 } else {
113 return SelectionSegment();
117 bool SelectionRange::Trim(SelectionRange range) {
118 SelectionPosition startRange = range.Start();
119 SelectionPosition endRange = range.End();
120 SelectionPosition start = Start();
121 SelectionPosition end = End();
122 PLATFORM_ASSERT(start <= end);
123 PLATFORM_ASSERT(startRange <= endRange);
124 if ((startRange <= end) && (endRange >= start)) {
125 if ((start > startRange) && (end < endRange)) {
126 // Completely covered by range -> empty at start
127 end = start;
128 } else if ((start < startRange) && (end > endRange)) {
129 // Completely covers range -> empty at start
130 end = start;
131 } else if (start <= startRange) {
132 // Trim end
133 end = startRange;
134 } else { //
135 PLATFORM_ASSERT(end >= endRange);
136 // Trim start
137 start = endRange;
139 if (anchor > caret) {
140 caret = start;
141 anchor = end;
142 } else {
143 anchor = start;
144 caret = end;
146 return Empty();
147 } else {
148 return false;
152 // If range is all virtual collapse to start of virtual space
153 void SelectionRange::MinimizeVirtualSpace() {
154 if (caret.Position() == anchor.Position()) {
155 int virtualSpace = caret.VirtualSpace();
156 if (virtualSpace > anchor.VirtualSpace())
157 virtualSpace = anchor.VirtualSpace();
158 caret.SetVirtualSpace(virtualSpace);
159 anchor.SetVirtualSpace(virtualSpace);
163 Selection::Selection() : mainRange(0), moveExtends(false), tentativeMain(false), selType(selStream) {
164 AddSelection(SelectionPosition(0));
167 Selection::~Selection() {
170 bool Selection::IsRectangular() const {
171 return (selType == selRectangle) || (selType == selThin);
174 int Selection::MainCaret() const {
175 return ranges[mainRange].caret.Position();
178 int Selection::MainAnchor() const {
179 return ranges[mainRange].anchor.Position();
182 SelectionRange &Selection::Rectangular() {
183 return rangeRectangular;
186 SelectionSegment Selection::Limits() const {
187 if (ranges.empty()) {
188 return SelectionSegment();
189 } else {
190 SelectionSegment sr(ranges[0].anchor, ranges[0].caret);
191 for (size_t i=1; i<ranges.size(); i++) {
192 sr.Extend(ranges[i].anchor);
193 sr.Extend(ranges[i].caret);
195 return sr;
199 SelectionSegment Selection::LimitsForRectangularElseMain() const {
200 if (IsRectangular()) {
201 return Limits();
202 } else {
203 return SelectionSegment(ranges[mainRange].caret, ranges[mainRange].anchor);
207 size_t Selection::Count() const {
208 return ranges.size();
211 size_t Selection::Main() const {
212 return mainRange;
215 void Selection::SetMain(size_t r) {
216 PLATFORM_ASSERT(r < ranges.size());
217 mainRange = r;
220 SelectionRange &Selection::Range(size_t r) {
221 return ranges[r];
224 SelectionRange &Selection::RangeMain() {
225 return ranges[mainRange];
228 bool Selection::MoveExtends() const {
229 return moveExtends;
232 void Selection::SetMoveExtends(bool moveExtends_) {
233 moveExtends = moveExtends_;
236 bool Selection::Empty() const {
237 for (size_t i=0; i<ranges.size(); i++) {
238 if (!ranges[i].Empty())
239 return false;
241 return true;
244 SelectionPosition Selection::Last() const {
245 SelectionPosition lastPosition;
246 for (size_t i=0; i<ranges.size(); i++) {
247 if (lastPosition < ranges[i].caret)
248 lastPosition = ranges[i].caret;
249 if (lastPosition < ranges[i].anchor)
250 lastPosition = ranges[i].anchor;
252 return lastPosition;
255 int Selection::Length() const {
256 int len = 0;
257 for (size_t i=0; i<ranges.size(); i++) {
258 len += ranges[i].Length();
260 return len;
263 void Selection::MovePositions(bool insertion, int startChange, int length) {
264 for (size_t i=0; i<ranges.size(); i++) {
265 ranges[i].caret.MoveForInsertDelete(insertion, startChange, length);
266 ranges[i].anchor.MoveForInsertDelete(insertion, startChange, length);
270 void Selection::TrimSelection(SelectionRange range) {
271 for (size_t i=0; i<ranges.size();) {
272 if ((i != mainRange) && (ranges[i].Trim(range))) {
273 // Trimmed to empty so remove
274 for (size_t j=i; j<ranges.size()-1; j++) {
275 ranges[j] = ranges[j+1];
276 if (j == mainRange-1)
277 mainRange--;
279 ranges.pop_back();
280 } else {
281 i++;
286 void Selection::SetSelection(SelectionRange range) {
287 ranges.clear();
288 ranges.push_back(range);
289 mainRange = ranges.size() - 1;
292 void Selection::AddSelection(SelectionRange range) {
293 TrimSelection(range);
294 ranges.push_back(range);
295 mainRange = ranges.size() - 1;
298 void Selection::AddSelectionWithoutTrim(SelectionRange range) {
299 ranges.push_back(range);
300 mainRange = ranges.size() - 1;
303 void Selection::TentativeSelection(SelectionRange range) {
304 if (!tentativeMain) {
305 rangesSaved = ranges;
307 ranges = rangesSaved;
308 AddSelection(range);
309 TrimSelection(ranges[mainRange]);
310 tentativeMain = true;
313 void Selection::CommitTentative() {
314 rangesSaved.clear();
315 tentativeMain = false;
318 int Selection::CharacterInSelection(int posCharacter) const {
319 for (size_t i=0; i<ranges.size(); i++) {
320 if (ranges[i].ContainsCharacter(posCharacter))
321 return i == mainRange ? 1 : 2;
323 return 0;
326 int Selection::InSelectionForEOL(int pos) const {
327 for (size_t i=0; i<ranges.size(); i++) {
328 if (!ranges[i].Empty() && (pos > ranges[i].Start().Position()) && (pos <= ranges[i].End().Position()))
329 return i == mainRange ? 1 : 2;
331 return 0;
334 int Selection::VirtualSpaceFor(int pos) const {
335 int virtualSpace = 0;
336 for (size_t i=0; i<ranges.size(); i++) {
337 if ((ranges[i].caret.Position() == pos) && (virtualSpace < ranges[i].caret.VirtualSpace()))
338 virtualSpace = ranges[i].caret.VirtualSpace();
339 if ((ranges[i].anchor.Position() == pos) && (virtualSpace < ranges[i].anchor.VirtualSpace()))
340 virtualSpace = ranges[i].anchor.VirtualSpace();
342 return virtualSpace;
345 void Selection::Clear() {
346 ranges.clear();
347 ranges.push_back(SelectionRange());
348 mainRange = ranges.size() - 1;
349 selType = selStream;
350 moveExtends = false;
351 ranges[mainRange].Reset();
352 rangeRectangular.Reset();
355 void Selection::RemoveDuplicates() {
356 for (size_t i=0; i<ranges.size()-1; i++) {
357 if (ranges[i].Empty()) {
358 size_t j=i+1;
359 while (j<ranges.size()) {
360 if (ranges[i] == ranges[j]) {
361 ranges.erase(ranges.begin() + j);
362 if (mainRange >= j)
363 mainRange--;
364 } else {
365 j++;
372 void Selection::RotateMain() {
373 mainRange = (mainRange + 1) % ranges.size();