Support more folding icon styles: arrows, +/- and no lines
[geany-mirror.git] / scintilla / Selection.cxx
blob2cdbe60f2ee8772a31d88f24bff5c52dc6d33af4
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 (insertion) {
24 if (position > startChange) {
25 position += length;
27 } else {
28 if (position > startChange) {
29 int endDeletion = startChange + length;
30 if (position > endDeletion) {
31 position -= length;
32 } else {
33 position = startChange;
39 bool SelectionPosition::operator <(const SelectionPosition &other) const {
40 if (position == other.position)
41 return virtualSpace < other.virtualSpace;
42 else
43 return position < other.position;
46 bool SelectionPosition::operator >(const SelectionPosition &other) const {
47 if (position == other.position)
48 return virtualSpace > other.virtualSpace;
49 else
50 return position > other.position;
53 bool SelectionPosition::operator <=(const SelectionPosition &other) const {
54 if (position == other.position && virtualSpace == other.virtualSpace)
55 return true;
56 else
57 return other > *this;
60 bool SelectionPosition::operator >=(const SelectionPosition &other) const {
61 if (position == other.position && virtualSpace == other.virtualSpace)
62 return true;
63 else
64 return *this > other;
67 int SelectionRange::Length() const {
68 if (anchor > caret) {
69 return anchor.Position() - caret.Position();
70 } else {
71 return caret.Position() - anchor.Position();
75 bool SelectionRange::Contains(int pos) const {
76 if (anchor > caret)
77 return (pos >= caret.Position()) && (pos <= anchor.Position());
78 else
79 return (pos >= anchor.Position()) && (pos <= caret.Position());
82 bool SelectionRange::Contains(SelectionPosition sp) const {
83 if (anchor > caret)
84 return (sp >= caret) && (sp <= anchor);
85 else
86 return (sp >= anchor) && (sp <= caret);
89 bool SelectionRange::ContainsCharacter(int posCharacter) const {
90 if (anchor > caret)
91 return (posCharacter >= caret.Position()) && (posCharacter < anchor.Position());
92 else
93 return (posCharacter >= anchor.Position()) && (posCharacter < caret.Position());
96 SelectionSegment SelectionRange::Intersect(SelectionSegment check) const {
97 SelectionSegment inOrder(caret, anchor);
98 if ((inOrder.start <= check.end) || (inOrder.end >= check.start)) {
99 SelectionSegment portion = check;
100 if (portion.start < inOrder.start)
101 portion.start = inOrder.start;
102 if (portion.end > inOrder.end)
103 portion.end = inOrder.end;
104 if (portion.start > portion.end)
105 return SelectionSegment();
106 else
107 return portion;
108 } else {
109 return SelectionSegment();
113 bool SelectionRange::Trim(SelectionRange range) {
114 SelectionPosition startRange = range.Start();
115 SelectionPosition endRange = range.End();
116 SelectionPosition start = Start();
117 SelectionPosition end = End();
118 PLATFORM_ASSERT(start <= end);
119 PLATFORM_ASSERT(startRange <= endRange);
120 if ((startRange <= end) && (endRange >= start)) {
121 if ((start > startRange) && (end < endRange)) {
122 // Completely covered by range -> empty at start
123 end = start;
124 } else if ((start < startRange) && (end > endRange)) {
125 // Completely covers range -> empty at start
126 end = start;
127 } else if (start <= startRange) {
128 // Trim end
129 end = startRange;
130 } else { //
131 PLATFORM_ASSERT(end >= endRange);
132 // Trim start
133 start = endRange;
135 if (anchor > caret) {
136 caret = start;
137 anchor = end;
138 } else {
139 anchor = start;
140 caret = end;
142 return Empty();
143 } else {
144 return false;
148 // If range is all virtual collapse to start of virtual space
149 void SelectionRange::MinimizeVirtualSpace() {
150 if (caret.Position() == anchor.Position()) {
151 int virtualSpace = caret.VirtualSpace();
152 if (virtualSpace > anchor.VirtualSpace())
153 virtualSpace = anchor.VirtualSpace();
154 caret.SetVirtualSpace(virtualSpace);
155 anchor.SetVirtualSpace(virtualSpace);
159 Selection::Selection() : mainRange(0), moveExtends(false), tentativeMain(false), selType(selStream) {
160 AddSelection(SelectionPosition(0));
163 Selection::~Selection() {
166 bool Selection::IsRectangular() const {
167 return (selType == selRectangle) || (selType == selThin);
170 int Selection::MainCaret() const {
171 return ranges[mainRange].caret.Position();
174 int Selection::MainAnchor() const {
175 return ranges[mainRange].anchor.Position();
178 SelectionRange &Selection::Rectangular() {
179 return rangeRectangular;
182 SelectionSegment Selection::Limits() const {
183 if (ranges.empty()) {
184 return SelectionSegment();
185 } else {
186 SelectionSegment sr(ranges[0].anchor, ranges[0].caret);
187 for (size_t i=1; i<ranges.size(); i++) {
188 sr.Extend(ranges[i].anchor);
189 sr.Extend(ranges[i].caret);
191 return sr;
195 SelectionSegment Selection::LimitsForRectangularElseMain() const {
196 if (IsRectangular()) {
197 return Limits();
198 } else {
199 return SelectionSegment(ranges[mainRange].caret, ranges[mainRange].anchor);
203 size_t Selection::Count() const {
204 return ranges.size();
207 size_t Selection::Main() const {
208 return mainRange;
211 void Selection::SetMain(size_t r) {
212 PLATFORM_ASSERT(r < ranges.size());
213 mainRange = r;
216 SelectionRange &Selection::Range(size_t r) {
217 return ranges[r];
220 SelectionRange &Selection::RangeMain() {
221 return ranges[mainRange];
224 bool Selection::MoveExtends() const {
225 return moveExtends;
228 void Selection::SetMoveExtends(bool moveExtends_) {
229 moveExtends = moveExtends_;
232 bool Selection::Empty() const {
233 for (size_t i=0; i<ranges.size(); i++) {
234 if (!ranges[i].Empty())
235 return false;
237 return true;
240 SelectionPosition Selection::Last() const {
241 SelectionPosition lastPosition;
242 for (size_t i=0; i<ranges.size(); i++) {
243 if (lastPosition < ranges[i].caret)
244 lastPosition = ranges[i].caret;
245 if (lastPosition < ranges[i].anchor)
246 lastPosition = ranges[i].anchor;
248 return lastPosition;
251 int Selection::Length() const {
252 int len = 0;
253 for (size_t i=0; i<ranges.size(); i++) {
254 len += ranges[i].Length();
256 return len;
259 void Selection::MovePositions(bool insertion, int startChange, int length) {
260 for (size_t i=0; i<ranges.size(); i++) {
261 ranges[i].caret.MoveForInsertDelete(insertion, startChange, length);
262 ranges[i].anchor.MoveForInsertDelete(insertion, startChange, length);
266 void Selection::TrimSelection(SelectionRange range) {
267 for (size_t i=0; i<ranges.size();) {
268 if ((i != mainRange) && (ranges[i].Trim(range))) {
269 // Trimmed to empty so remove
270 for (size_t j=i;j<ranges.size()-1;j++) {
271 ranges[j] = ranges[j+1];
272 if (j == mainRange-1)
273 mainRange--;
275 ranges.pop_back();
276 } else {
277 i++;
282 void Selection::SetSelection(SelectionRange range) {
283 ranges.clear();
284 ranges.push_back(range);
285 mainRange = ranges.size() - 1;
288 void Selection::AddSelection(SelectionRange range) {
289 TrimSelection(range);
290 ranges.push_back(range);
291 mainRange = ranges.size() - 1;
294 void Selection::TentativeSelection(SelectionRange range) {
295 if (!tentativeMain) {
296 rangesSaved = ranges;
298 ranges = rangesSaved;
299 AddSelection(range);
300 TrimSelection(ranges[mainRange]);
301 tentativeMain = true;
304 void Selection::CommitTentative() {
305 rangesSaved.clear();
306 tentativeMain = false;
309 int Selection::CharacterInSelection(int posCharacter) const {
310 for (size_t i=0; i<ranges.size(); i++) {
311 if (ranges[i].ContainsCharacter(posCharacter))
312 return i == mainRange ? 1 : 2;
314 return 0;
317 int Selection::InSelectionForEOL(int pos) const {
318 for (size_t i=0; i<ranges.size(); i++) {
319 if (!ranges[i].Empty() && (pos > ranges[i].Start().Position()) && (pos <= ranges[i].End().Position()))
320 return i == mainRange ? 1 : 2;
322 return 0;
325 int Selection::VirtualSpaceFor(int pos) const {
326 int virtualSpace = 0;
327 for (size_t i=0; i<ranges.size(); i++) {
328 if ((ranges[i].caret.Position() == pos) && (virtualSpace < ranges[i].caret.VirtualSpace()))
329 virtualSpace = ranges[i].caret.VirtualSpace();
330 if ((ranges[i].anchor.Position() == pos) && (virtualSpace < ranges[i].anchor.VirtualSpace()))
331 virtualSpace = ranges[i].anchor.VirtualSpace();
333 return virtualSpace;
336 void Selection::Clear() {
337 ranges.clear();
338 ranges.push_back(SelectionRange());
339 mainRange = ranges.size() - 1;
340 selType = selStream;
341 moveExtends = false;
342 ranges[mainRange].Reset();
343 rangeRectangular.Reset();
346 void Selection::RemoveDuplicates() {
347 for (size_t i=0; i<ranges.size()-1; i++) {
348 if (ranges[i].Empty()) {
349 size_t j=i+1;
350 while (j<ranges.size()) {
351 if (ranges[i] == ranges[j]) {
352 ranges.erase(ranges.begin() + j);
353 if (mainRange >= j)
354 mainRange--;
355 } else {
356 j++;
363 void Selection::RotateMain() {
364 mainRange = (mainRange + 1) % ranges.size();