1 // Scintilla source code edit control
2 /** @file Selection.cxx
3 ** Classes maintaining the selection.
5 // Copyright 2009 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
16 #include "Scintilla.h"
19 #include "Selection.h"
22 using namespace Scintilla
;
25 void SelectionPosition::MoveForInsertDelete(bool insertion
, int startChange
, int length
) {
27 if (position
== startChange
) {
28 int virtualLengthRemove
= std::min(length
, virtualSpace
);
29 virtualSpace
-= virtualLengthRemove
;
30 position
+= virtualLengthRemove
;
31 } else if (position
> startChange
) {
35 if (position
== startChange
) {
38 if (position
> startChange
) {
39 int endDeletion
= startChange
+ length
;
40 if (position
> endDeletion
) {
43 position
= startChange
;
50 bool SelectionPosition::operator <(const SelectionPosition
&other
) const {
51 if (position
== other
.position
)
52 return virtualSpace
< other
.virtualSpace
;
54 return position
< other
.position
;
57 bool SelectionPosition::operator >(const SelectionPosition
&other
) const {
58 if (position
== other
.position
)
59 return virtualSpace
> other
.virtualSpace
;
61 return position
> other
.position
;
64 bool SelectionPosition::operator <=(const SelectionPosition
&other
) const {
65 if (position
== other
.position
&& virtualSpace
== other
.virtualSpace
)
71 bool SelectionPosition::operator >=(const SelectionPosition
&other
) const {
72 if (position
== other
.position
&& virtualSpace
== other
.virtualSpace
)
78 int SelectionRange::Length() const {
80 return anchor
.Position() - caret
.Position();
82 return caret
.Position() - anchor
.Position();
86 void SelectionRange::MoveForInsertDelete(bool insertion
, int startChange
, int length
) {
87 caret
.MoveForInsertDelete(insertion
, startChange
, length
);
88 anchor
.MoveForInsertDelete(insertion
, startChange
, length
);
91 bool SelectionRange::Contains(int pos
) const {
93 return (pos
>= caret
.Position()) && (pos
<= anchor
.Position());
95 return (pos
>= anchor
.Position()) && (pos
<= caret
.Position());
98 bool SelectionRange::Contains(SelectionPosition sp
) const {
100 return (sp
>= caret
) && (sp
<= anchor
);
102 return (sp
>= anchor
) && (sp
<= caret
);
105 bool SelectionRange::ContainsCharacter(int posCharacter
) const {
107 return (posCharacter
>= caret
.Position()) && (posCharacter
< anchor
.Position());
109 return (posCharacter
>= anchor
.Position()) && (posCharacter
< caret
.Position());
112 SelectionSegment
SelectionRange::Intersect(SelectionSegment check
) const {
113 SelectionSegment
inOrder(caret
, anchor
);
114 if ((inOrder
.start
<= check
.end
) || (inOrder
.end
>= check
.start
)) {
115 SelectionSegment portion
= check
;
116 if (portion
.start
< inOrder
.start
)
117 portion
.start
= inOrder
.start
;
118 if (portion
.end
> inOrder
.end
)
119 portion
.end
= inOrder
.end
;
120 if (portion
.start
> portion
.end
)
121 return SelectionSegment();
125 return SelectionSegment();
129 void SelectionRange::Swap() {
130 std::swap(caret
, anchor
);
133 bool SelectionRange::Trim(SelectionRange range
) {
134 SelectionPosition startRange
= range
.Start();
135 SelectionPosition endRange
= range
.End();
136 SelectionPosition start
= Start();
137 SelectionPosition end
= End();
138 PLATFORM_ASSERT(start
<= end
);
139 PLATFORM_ASSERT(startRange
<= endRange
);
140 if ((startRange
<= end
) && (endRange
>= start
)) {
141 if ((start
> startRange
) && (end
< endRange
)) {
142 // Completely covered by range -> empty at start
144 } else if ((start
< startRange
) && (end
> endRange
)) {
145 // Completely covers range -> empty at start
147 } else if (start
<= startRange
) {
151 PLATFORM_ASSERT(end
>= endRange
);
155 if (anchor
> caret
) {
168 // If range is all virtual collapse to start of virtual space
169 void SelectionRange::MinimizeVirtualSpace() {
170 if (caret
.Position() == anchor
.Position()) {
171 int virtualSpace
= caret
.VirtualSpace();
172 if (virtualSpace
> anchor
.VirtualSpace())
173 virtualSpace
= anchor
.VirtualSpace();
174 caret
.SetVirtualSpace(virtualSpace
);
175 anchor
.SetVirtualSpace(virtualSpace
);
179 Selection::Selection() : mainRange(0), moveExtends(false), tentativeMain(false), selType(selStream
) {
180 AddSelection(SelectionRange(SelectionPosition(0)));
183 Selection::~Selection() {
186 bool Selection::IsRectangular() const {
187 return (selType
== selRectangle
) || (selType
== selThin
);
190 int Selection::MainCaret() const {
191 return ranges
[mainRange
].caret
.Position();
194 int Selection::MainAnchor() const {
195 return ranges
[mainRange
].anchor
.Position();
198 SelectionRange
&Selection::Rectangular() {
199 return rangeRectangular
;
202 SelectionSegment
Selection::Limits() const {
203 if (ranges
.empty()) {
204 return SelectionSegment();
206 SelectionSegment
sr(ranges
[0].anchor
, ranges
[0].caret
);
207 for (size_t i
=1; i
<ranges
.size(); i
++) {
208 sr
.Extend(ranges
[i
].anchor
);
209 sr
.Extend(ranges
[i
].caret
);
215 SelectionSegment
Selection::LimitsForRectangularElseMain() const {
216 if (IsRectangular()) {
219 return SelectionSegment(ranges
[mainRange
].caret
, ranges
[mainRange
].anchor
);
223 size_t Selection::Count() const {
224 return ranges
.size();
227 size_t Selection::Main() const {
231 void Selection::SetMain(size_t r
) {
232 PLATFORM_ASSERT(r
< ranges
.size());
236 SelectionRange
&Selection::Range(size_t r
) {
240 const SelectionRange
&Selection::Range(size_t r
) const {
244 SelectionRange
&Selection::RangeMain() {
245 return ranges
[mainRange
];
248 const SelectionRange
&Selection::RangeMain() const {
249 return ranges
[mainRange
];
252 SelectionPosition
Selection::Start() const {
253 if (IsRectangular()) {
254 return rangeRectangular
.Start();
256 return ranges
[mainRange
].Start();
260 bool Selection::MoveExtends() const {
264 void Selection::SetMoveExtends(bool moveExtends_
) {
265 moveExtends
= moveExtends_
;
268 bool Selection::Empty() const {
269 for (size_t i
=0; i
<ranges
.size(); i
++) {
270 if (!ranges
[i
].Empty())
276 SelectionPosition
Selection::Last() const {
277 SelectionPosition lastPosition
;
278 for (size_t i
=0; i
<ranges
.size(); i
++) {
279 if (lastPosition
< ranges
[i
].caret
)
280 lastPosition
= ranges
[i
].caret
;
281 if (lastPosition
< ranges
[i
].anchor
)
282 lastPosition
= ranges
[i
].anchor
;
287 int Selection::Length() const {
289 for (size_t i
=0; i
<ranges
.size(); i
++) {
290 len
+= ranges
[i
].Length();
295 void Selection::MovePositions(bool insertion
, int startChange
, int length
) {
296 for (size_t i
=0; i
<ranges
.size(); i
++) {
297 ranges
[i
].MoveForInsertDelete(insertion
, startChange
, length
);
299 if (selType
== selRectangle
) {
300 rangeRectangular
.MoveForInsertDelete(insertion
, startChange
, length
);
304 void Selection::TrimSelection(SelectionRange range
) {
305 for (size_t i
=0; i
<ranges
.size();) {
306 if ((i
!= mainRange
) && (ranges
[i
].Trim(range
))) {
307 // Trimmed to empty so remove
308 for (size_t j
=i
; j
<ranges
.size()-1; j
++) {
309 ranges
[j
] = ranges
[j
+1];
310 if (j
== mainRange
-1)
320 void Selection::TrimOtherSelections(size_t r
, SelectionRange range
) {
321 for (size_t i
= 0; i
<ranges
.size(); ++i
) {
323 ranges
[i
].Trim(range
);
328 void Selection::SetSelection(SelectionRange range
) {
330 ranges
.push_back(range
);
331 mainRange
= ranges
.size() - 1;
334 void Selection::AddSelection(SelectionRange range
) {
335 TrimSelection(range
);
336 ranges
.push_back(range
);
337 mainRange
= ranges
.size() - 1;
340 void Selection::AddSelectionWithoutTrim(SelectionRange range
) {
341 ranges
.push_back(range
);
342 mainRange
= ranges
.size() - 1;
345 void Selection::DropSelection(size_t r
) {
346 if ((ranges
.size() > 1) && (r
< ranges
.size())) {
347 size_t mainNew
= mainRange
;
350 mainNew
= ranges
.size() - 2;
355 ranges
.erase(ranges
.begin() + r
);
360 void Selection::DropAdditionalRanges() {
361 SetSelection(RangeMain());
364 void Selection::TentativeSelection(SelectionRange range
) {
365 if (!tentativeMain
) {
366 rangesSaved
= ranges
;
368 ranges
= rangesSaved
;
370 TrimSelection(ranges
[mainRange
]);
371 tentativeMain
= true;
374 void Selection::CommitTentative() {
376 tentativeMain
= false;
379 int Selection::CharacterInSelection(int posCharacter
) const {
380 for (size_t i
=0; i
<ranges
.size(); i
++) {
381 if (ranges
[i
].ContainsCharacter(posCharacter
))
382 return i
== mainRange
? 1 : 2;
387 int Selection::InSelectionForEOL(int pos
) const {
388 for (size_t i
=0; i
<ranges
.size(); i
++) {
389 if (!ranges
[i
].Empty() && (pos
> ranges
[i
].Start().Position()) && (pos
<= ranges
[i
].End().Position()))
390 return i
== mainRange
? 1 : 2;
395 int Selection::VirtualSpaceFor(int pos
) const {
396 int virtualSpace
= 0;
397 for (size_t i
=0; i
<ranges
.size(); i
++) {
398 if ((ranges
[i
].caret
.Position() == pos
) && (virtualSpace
< ranges
[i
].caret
.VirtualSpace()))
399 virtualSpace
= ranges
[i
].caret
.VirtualSpace();
400 if ((ranges
[i
].anchor
.Position() == pos
) && (virtualSpace
< ranges
[i
].anchor
.VirtualSpace()))
401 virtualSpace
= ranges
[i
].anchor
.VirtualSpace();
406 void Selection::Clear() {
408 ranges
.push_back(SelectionRange());
409 mainRange
= ranges
.size() - 1;
412 ranges
[mainRange
].Reset();
413 rangeRectangular
.Reset();
416 void Selection::RemoveDuplicates() {
417 for (size_t i
=0; i
<ranges
.size()-1; i
++) {
418 if (ranges
[i
].Empty()) {
420 while (j
<ranges
.size()) {
421 if (ranges
[i
] == ranges
[j
]) {
422 ranges
.erase(ranges
.begin() + j
);
433 void Selection::RotateMain() {
434 mainRange
= (mainRange
+ 1) % ranges
.size();