geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

Selection.cxx
Go to the documentation of this file.
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.
7
8#include <cstddef>
9#include <cstdlib>
10
11#include <stdexcept>
12#include <vector>
13#include <algorithm>
14#include <memory>
15
16#include "Platform.h"
17
18#include "Scintilla.h"
19
20#include "Position.h"
21#include "Selection.h"
22
23using namespace Scintilla;
24
25void SelectionPosition::MoveForInsertDelete(bool insertion, Sci::Position startChange, Sci::Position length, bool moveForEqual) noexcept {
26 if (insertion) {
27 if (position == startChange) {
28 // Always consume virtual space
29 const Sci::Position virtualLengthRemove = std::min(length, virtualSpace);
30 virtualSpace -= virtualLengthRemove;
31 position += virtualLengthRemove;
32 if (moveForEqual) {
33 const Sci::Position lengthAfterVirtualRemove = length - virtualLengthRemove;
34 position += lengthAfterVirtualRemove;
35 }
36 } else if (position > startChange) {
37 position += length;
38 }
39 } else {
40 if (position == startChange) {
41 virtualSpace = 0;
42 }
43 if (position > startChange) {
44 const Sci::Position endDeletion = startChange + length;
45 if (position > endDeletion) {
46 position -= length;
47 } else {
48 position = startChange;
49 virtualSpace = 0;
50 }
51 }
52 }
53}
54
55bool SelectionPosition::operator <(const SelectionPosition &other) const noexcept {
56 if (position == other.position)
57 return virtualSpace < other.virtualSpace;
58 else
59 return position < other.position;
60}
61
62bool SelectionPosition::operator >(const SelectionPosition &other) const noexcept {
63 if (position == other.position)
64 return virtualSpace > other.virtualSpace;
65 else
66 return position > other.position;
67}
68
69bool SelectionPosition::operator <=(const SelectionPosition &other) const noexcept {
70 if (position == other.position && virtualSpace == other.virtualSpace)
71 return true;
72 else
73 return other > *this;
74}
75
76bool SelectionPosition::operator >=(const SelectionPosition &other) const noexcept {
77 if (position == other.position && virtualSpace == other.virtualSpace)
78 return true;
79 else
80 return *this > other;
81}
82
83Sci::Position SelectionRange::Length() const noexcept {
84 if (anchor > caret) {
85 return anchor.Position() - caret.Position();
86 } else {
87 return caret.Position() - anchor.Position();
88 }
89}
90
91void SelectionRange::MoveForInsertDelete(bool insertion, Sci::Position startChange, Sci::Position length) noexcept {
92 // For insertions that occur at the start of the selection move both the start
93 // and end of the selection to preserve the selected length.
94 // The end will automatically move since it is after the insertion, so determine
95 // which position is the start and pass this into
96 // SelectionPosition::MoveForInsertDelete.
97 // There isn't any reason to move an empty selection so don't move it.
98 const bool caretStart = caret.Position() < anchor.Position();
99 const bool anchorStart = anchor.Position() < caret.Position();
100
101 caret.MoveForInsertDelete(insertion, startChange, length, caretStart);
102 anchor.MoveForInsertDelete(insertion, startChange, length, anchorStart);
103}
104
106 if (anchor > caret)
107 return (pos >= caret.Position()) && (pos <= anchor.Position());
108 else
109 return (pos >= anchor.Position()) && (pos <= caret.Position());
110}
111
113 if (anchor > caret)
114 return (sp >= caret) && (sp <= anchor);
115 else
116 return (sp >= anchor) && (sp <= caret);
117}
118
119bool SelectionRange::ContainsCharacter(Sci::Position posCharacter) const noexcept {
120 if (anchor > caret)
121 return (posCharacter >= caret.Position()) && (posCharacter < anchor.Position());
122 else
123 return (posCharacter >= anchor.Position()) && (posCharacter < caret.Position());
124}
125
127 const SelectionSegment inOrder(caret, anchor);
128 if ((inOrder.start <= check.end) || (inOrder.end >= check.start)) {
129 SelectionSegment portion = check;
130 if (portion.start < inOrder.start)
131 portion.start = inOrder.start;
132 if (portion.end > inOrder.end)
133 portion.end = inOrder.end;
134 if (portion.start > portion.end)
135 return SelectionSegment();
136 else
137 return portion;
138 } else {
139 return SelectionSegment();
140 }
141}
142
143void SelectionRange::Swap() noexcept {
144 std::swap(caret, anchor);
145}
146
148 const SelectionPosition startRange = range.Start();
149 const SelectionPosition endRange = range.End();
150 SelectionPosition start = Start();
151 SelectionPosition end = End();
152 PLATFORM_ASSERT(start <= end);
153 PLATFORM_ASSERT(startRange <= endRange);
154 if ((startRange <= end) && (endRange >= start)) {
155 if ((start > startRange) && (end < endRange)) {
156 // Completely covered by range -> empty at start
157 end = start;
158 } else if ((start < startRange) && (end > endRange)) {
159 // Completely covers range -> empty at start
160 end = start;
161 } else if (start <= startRange) {
162 // Trim end
163 end = startRange;
164 } else { //
165 PLATFORM_ASSERT(end >= endRange);
166 // Trim start
167 start = endRange;
168 }
169 if (anchor > caret) {
170 caret = start;
171 anchor = end;
172 } else {
173 anchor = start;
174 caret = end;
175 }
176 return Empty();
177 } else {
178 return false;
179 }
180}
181
182// If range is all virtual collapse to start of virtual space
184 if (caret.Position() == anchor.Position()) {
185 Sci::Position virtualSpace = caret.VirtualSpace();
186 if (virtualSpace > anchor.VirtualSpace())
187 virtualSpace = anchor.VirtualSpace();
188 caret.SetVirtualSpace(virtualSpace);
189 anchor.SetVirtualSpace(virtualSpace);
190 }
191}
192
193Selection::Selection() : mainRange(0), moveExtends(false), tentativeMain(false), selType(selStream) {
195}
196
198}
199
200bool Selection::IsRectangular() const noexcept {
201 return (selType == selRectangle) || (selType == selThin);
202}
203
205 return ranges[mainRange].caret.Position();
206}
207
209 return ranges[mainRange].anchor.Position();
210}
211
213 return rangeRectangular;
214}
215
217 if (ranges.empty()) {
218 return SelectionSegment();
219 } else {
220 SelectionSegment sr(ranges[0].anchor, ranges[0].caret);
221 for (size_t i=1; i<ranges.size(); i++) {
222 sr.Extend(ranges[i].anchor);
223 sr.Extend(ranges[i].caret);
224 }
225 return sr;
226 }
227}
228
230 if (IsRectangular()) {
231 return Limits();
232 } else {
233 return SelectionSegment(ranges[mainRange].caret, ranges[mainRange].anchor);
234 }
235}
236
237size_t Selection::Count() const noexcept {
238 return ranges.size();
239}
240
241size_t Selection::Main() const noexcept {
242 return mainRange;
243}
244
245void Selection::SetMain(size_t r) noexcept {
246 PLATFORM_ASSERT(r < ranges.size());
247 mainRange = r;
248}
249
250SelectionRange &Selection::Range(size_t r) noexcept {
251 return ranges[r];
252}
253
254const SelectionRange &Selection::Range(size_t r) const noexcept {
255 return ranges[r];
256}
257
259 return ranges[mainRange];
260}
261
262const SelectionRange &Selection::RangeMain() const noexcept {
263 return ranges[mainRange];
264}
265
267 if (IsRectangular()) {
268 return rangeRectangular.Start();
269 } else {
270 return ranges[mainRange].Start();
271 }
272}
273
274bool Selection::MoveExtends() const noexcept {
275 return moveExtends;
276}
277
278void Selection::SetMoveExtends(bool moveExtends_) noexcept {
279 moveExtends = moveExtends_;
280}
281
282bool Selection::Empty() const noexcept {
283 for (const SelectionRange &range : ranges) {
284 if (!range.Empty())
285 return false;
286 }
287 return true;
288}
289
291 SelectionPosition lastPosition;
292 for (const SelectionRange &range : ranges) {
293 if (lastPosition < range.caret)
294 lastPosition = range.caret;
295 if (lastPosition < range.anchor)
296 lastPosition = range.anchor;
297 }
298 return lastPosition;
299}
300
302 Sci::Position len = 0;
303 for (const SelectionRange &range : ranges) {
304 len += range.Length();
305 }
306 return len;
307}
308
309void Selection::MovePositions(bool insertion, Sci::Position startChange, Sci::Position length) noexcept {
310 for (SelectionRange &range : ranges) {
311 range.MoveForInsertDelete(insertion, startChange, length);
312 }
313 if (selType == selRectangle) {
314 rangeRectangular.MoveForInsertDelete(insertion, startChange, length);
315 }
316}
317
319 for (size_t i=0; i<ranges.size();) {
320 if ((i != mainRange) && (ranges[i].Trim(range))) {
321 // Trimmed to empty so remove
322 for (size_t j=i; j<ranges.size()-1; j++) {
323 ranges[j] = ranges[j+1];
324 if (j == mainRange-1)
325 mainRange--;
326 }
327 ranges.pop_back();
328 } else {
329 i++;
330 }
331 }
332}
333
334void Selection::TrimOtherSelections(size_t r, SelectionRange range) noexcept {
335 for (size_t i = 0; i<ranges.size(); ++i) {
336 if (i != r) {
337 ranges[i].Trim(range);
338 }
339 }
340}
341
343 ranges.clear();
344 ranges.push_back(range);
345 mainRange = ranges.size() - 1;
346}
347
349 TrimSelection(range);
350 ranges.push_back(range);
351 mainRange = ranges.size() - 1;
352}
353
355 ranges.push_back(range);
356 mainRange = ranges.size() - 1;
357}
358
360 if ((ranges.size() > 1) && (r < ranges.size())) {
361 size_t mainNew = mainRange;
362 if (mainNew >= r) {
363 if (mainNew == 0) {
364 mainNew = ranges.size() - 2;
365 } else {
366 mainNew--;
367 }
368 }
369 ranges.erase(ranges.begin() + r);
370 mainRange = mainNew;
371 }
372}
373
376}
377
379 if (!tentativeMain) {
381 }
383 AddSelection(range);
385 tentativeMain = true;
386}
387
389 rangesSaved.clear();
390 tentativeMain = false;
391}
392
393int Selection::CharacterInSelection(Sci::Position posCharacter) const noexcept {
394 for (size_t i=0; i<ranges.size(); i++) {
395 if (ranges[i].ContainsCharacter(posCharacter))
396 return i == mainRange ? 1 : 2;
397 }
398 return 0;
399}
400
402 for (size_t i=0; i<ranges.size(); i++) {
403 if (!ranges[i].Empty() && (pos > ranges[i].Start().Position()) && (pos <= ranges[i].End().Position()))
404 return i == mainRange ? 1 : 2;
405 }
406 return 0;
407}
408
410 Sci::Position virtualSpace = 0;
411 for (const SelectionRange &range : ranges) {
412 if ((range.caret.Position() == pos) && (virtualSpace < range.caret.VirtualSpace()))
413 virtualSpace = range.caret.VirtualSpace();
414 if ((range.anchor.Position() == pos) && (virtualSpace < range.anchor.VirtualSpace()))
415 virtualSpace = range.anchor.VirtualSpace();
416 }
417 return virtualSpace;
418}
419
421 ranges.clear();
422 ranges.emplace_back();
423 mainRange = ranges.size() - 1;
425 moveExtends = false;
426 ranges[mainRange].Reset();
428}
429
431 for (size_t i=0; i<ranges.size()-1; i++) {
432 if (ranges[i].Empty()) {
433 size_t j=i+1;
434 while (j<ranges.size()) {
435 if (ranges[i] == ranges[j]) {
436 ranges.erase(ranges.begin() + j);
437 if (mainRange >= j)
438 mainRange--;
439 } else {
440 j++;
441 }
442 }
443 }
444 }
445}
446
447void Selection::RotateMain() noexcept {
448 mainRange = (mainRange + 1) % ranges.size();
449}
450
Interface to platform facilities.
#define PLATFORM_ASSERT(c)
Definition: Platform.h:544
Defines global type name Position in the Sci internal namespace.
Interface to the edit control.
Classes maintaining the selection.
Sci::Position Position() const noexcept
Definition: Selection.h:34
Sci::Position VirtualSpace() const noexcept
Definition: Selection.h:41
void SetVirtualSpace(Sci::Position virtualSpace_) noexcept
Definition: Selection.h:44
SelectionPosition Start() const noexcept
Definition: Selection.cxx:266
int CharacterInSelection(Sci::Position posCharacter) const noexcept
Definition: Selection.cxx:393
Sci::Position MainAnchor() const noexcept
Definition: Selection.cxx:208
void SetMoveExtends(bool moveExtends_) noexcept
Definition: Selection.cxx:278
void TrimSelection(SelectionRange range) noexcept
Definition: Selection.cxx:318
SelectionRange & Rectangular() noexcept
Definition: Selection.cxx:212
void MovePositions(bool insertion, Sci::Position startChange, Sci::Position length) noexcept
Definition: Selection.cxx:309
SelectionRange & RangeMain() noexcept
Definition: Selection.cxx:258
void CommitTentative() noexcept
Definition: Selection.cxx:388
void AddSelectionWithoutTrim(SelectionRange range)
Definition: Selection.cxx:354
void SetSelection(SelectionRange range)
Definition: Selection.cxx:342
SelectionPosition Last() const noexcept
Definition: Selection.cxx:290
void DropSelection(size_t r)
Definition: Selection.cxx:359
SelectionSegment Limits() const noexcept
Definition: Selection.cxx:216
std::vector< SelectionRange > rangesSaved
Definition: Selection.h:138
SelectionSegment LimitsForRectangularElseMain() const
Definition: Selection.cxx:229
int InSelectionForEOL(Sci::Position pos) const noexcept
Definition: Selection.cxx:401
bool IsRectangular() const noexcept
Definition: Selection.cxx:200
Sci::Position VirtualSpaceFor(Sci::Position pos) const noexcept
Definition: Selection.cxx:409
void RotateMain() noexcept
Definition: Selection.cxx:447
size_t Main() const noexcept
Definition: Selection.cxx:241
Sci::Position Length() const noexcept
Definition: Selection.cxx:301
std::vector< SelectionRange > ranges
Definition: Selection.h:137
bool MoveExtends() const noexcept
Definition: Selection.cxx:274
size_t Count() const noexcept
Definition: Selection.cxx:237
void AddSelection(SelectionRange range)
Definition: Selection.cxx:348
SelectionRange & Range(size_t r) noexcept
Definition: Selection.cxx:250
bool Empty() const noexcept
Definition: Selection.cxx:282
Sci::Position MainCaret() const noexcept
Definition: Selection.cxx:204
void TentativeSelection(SelectionRange range)
Definition: Selection.cxx:378
void TrimOtherSelections(size_t r, SelectionRange range) noexcept
Definition: Selection.cxx:334
SelectionRange rangeRectangular
Definition: Selection.h:139
void SetMain(size_t r) noexcept
Definition: Selection.cxx:245
gint pos
Definition: editor.c:87
ptrdiff_t Position
Definition: Position.h:19
Styling buffer using one element for each run rather than using a filled buffer.
Definition: Converter.h:9
gint position[2]
Definition: search.c:120
void Reset() noexcept
Definition: Selection.h:111
SelectionPosition caret
Definition: Selection.h:87
void MinimizeVirtualSpace() noexcept
Definition: Selection.cxx:183
bool Contains(Sci::Position pos) const noexcept
Definition: Selection.cxx:105
SelectionSegment Intersect(SelectionSegment check) const noexcept
Definition: Selection.cxx:126
void Swap() noexcept
Definition: Selection.cxx:143
SelectionPosition Start() const noexcept
Definition: Selection.h:124
bool ContainsCharacter(Sci::Position posCharacter) const noexcept
Definition: Selection.cxx:119
void MoveForInsertDelete(bool insertion, Sci::Position startChange, Sci::Position length) noexcept
Definition: Selection.cxx:91
bool Trim(SelectionRange range) noexcept
Definition: Selection.cxx:147
SelectionPosition anchor
Definition: Selection.h:88
void Extend(SelectionPosition p) noexcept
Definition: Selection.h:78
SelectionPosition end
Definition: Selection.h:60
SelectionPosition start
Definition: Selection.h:59