]>
Commit | Line | Data |
---|---|---|
9ce192d4 | 1 | // Scintilla source code edit control |
65ec6247 RD |
2 | /** @file Editor.cxx |
3 | ** Main code for the edit control. | |
4 | **/ | |
1dcf666d | 5 | // Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org> |
9ce192d4 RD |
6 | // The License.txt file describes the conditions under which this software may be distributed. |
7 | ||
8 | #include <stdlib.h> | |
9 | #include <string.h> | |
10 | #include <stdio.h> | |
11 | #include <ctype.h> | |
1dcf666d | 12 | #include <assert.h> |
9ce192d4 | 13 | |
9e96e16f | 14 | #include <string> |
1dcf666d RD |
15 | #include <vector> |
16 | #include <map> | |
17 | #include <algorithm> | |
18 | #include <memory> | |
9e96e16f RD |
19 | |
20 | #include "Platform.h" | |
21 | ||
1dcf666d | 22 | #include "ILexer.h" |
9ce192d4 | 23 | #include "Scintilla.h" |
d134f170 | 24 | |
7e0c58e9 RD |
25 | #include "SplitVector.h" |
26 | #include "Partitioning.h" | |
27 | #include "RunStyles.h" | |
9ce192d4 | 28 | #include "ContractionState.h" |
9ce192d4 RD |
29 | #include "CellBuffer.h" |
30 | #include "KeyMap.h" | |
31 | #include "Indicator.h" | |
9e730a78 | 32 | #include "XPM.h" |
9ce192d4 RD |
33 | #include "LineMarker.h" |
34 | #include "Style.h" | |
35 | #include "ViewStyle.h" | |
b8193d80 | 36 | #include "CharClassify.h" |
7e0c58e9 | 37 | #include "Decoration.h" |
9ce192d4 | 38 | #include "Document.h" |
1dcf666d | 39 | #include "UniConversion.h" |
9e96e16f | 40 | #include "Selection.h" |
7e0c58e9 | 41 | #include "PositionCache.h" |
9ce192d4 RD |
42 | #include "Editor.h" |
43 | ||
7e0c58e9 RD |
44 | #ifdef SCI_NAMESPACE |
45 | using namespace Scintilla; | |
46 | #endif | |
47 | ||
1e9bafca RD |
48 | /* |
49 | return whether this modification represents an operation that | |
50 | may reasonably be deferred (not done now OR [possibly] at all) | |
51 | */ | |
1dcf666d | 52 | static bool CanDeferToLastStep(const DocModification &mh) { |
7e0c58e9 | 53 | if (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) |
1e9bafca | 54 | return true; // CAN skip |
7e0c58e9 | 55 | if (!(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO))) |
1e9bafca RD |
56 | return false; // MUST do |
57 | if (mh.modificationType & SC_MULTISTEPUNDOREDO) | |
58 | return true; // CAN skip | |
59 | return false; // PRESUMABLY must do | |
60 | } | |
61 | ||
1dcf666d | 62 | static bool CanEliminate(const DocModification &mh) { |
1e9bafca | 63 | return |
7e0c58e9 | 64 | (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) != 0; |
1e9bafca RD |
65 | } |
66 | ||
67 | /* | |
68 | return whether this modification represents the FINAL step | |
69 | in a [possibly lengthy] multi-step Undo/Redo sequence | |
70 | */ | |
1dcf666d | 71 | static bool IsLastStep(const DocModification &mh) { |
1e9bafca | 72 | return |
7e0c58e9 RD |
73 | (mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) != 0 |
74 | && (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0 | |
75 | && (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0 | |
76 | && (mh.modificationType & SC_MULTILINEUNDOREDO) != 0; | |
1e9bafca RD |
77 | } |
78 | ||
9ce192d4 | 79 | Caret::Caret() : |
7e0c58e9 | 80 | active(false), on(false), period(500) {} |
9ce192d4 RD |
81 | |
82 | Timer::Timer() : | |
7e0c58e9 | 83 | ticking(false), ticksToWait(0), tickerID(0) {} |
9ce192d4 | 84 | |
8e54aaed | 85 | Idler::Idler() : |
7e0c58e9 | 86 | state(false), idlerID(0) {} |
1a2fb4cd | 87 | |
7e0c58e9 RD |
88 | static inline bool IsControlCharacter(int ch) { |
89 | // iscntrl returns true for lots of chars > 127 which are displayable | |
90 | return ch >= 0 && ch < ' '; | |
1a2fb4cd RD |
91 | } |
92 | ||
1dcf666d RD |
93 | static inline bool IsAllSpacesOrTabs(char *s, unsigned int len) { |
94 | for (unsigned int i = 0; i < len; i++) { | |
95 | // This is safe because IsSpaceOrTab() will return false for null terminators | |
96 | if (!IsSpaceOrTab(s[i])) | |
97 | return false; | |
98 | } | |
99 | return true; | |
100 | } | |
101 | ||
9ce192d4 RD |
102 | Editor::Editor() { |
103 | ctrlID = 0; | |
104 | ||
105 | stylesValid = false; | |
1dcf666d RD |
106 | technology = SC_TECHNOLOGY_DEFAULT; |
107 | ||
d134f170 RD |
108 | printMagnification = 0; |
109 | printColourMode = SC_PRINT_NORMAL; | |
9e730a78 | 110 | printWrapState = eWrapWord; |
65ec6247 | 111 | cursorMode = SC_CURSORNORMAL; |
1a2fb4cd | 112 | controlCharSymbol = 0; /* Draw the control characters */ |
d134f170 | 113 | |
65ec6247 | 114 | hasFocus = false; |
9ce192d4 RD |
115 | hideSelection = false; |
116 | inOverstrike = false; | |
65ec6247 RD |
117 | errorStatus = 0; |
118 | mouseDownCaptures = true; | |
9ce192d4 RD |
119 | |
120 | bufferedDraw = true; | |
9e730a78 | 121 | twoPhaseDraw = true; |
9ce192d4 RD |
122 | |
123 | lastClickTime = 0; | |
65ec6247 RD |
124 | dwellDelay = SC_TIME_FOREVER; |
125 | ticksToDwell = SC_TIME_FOREVER; | |
126 | dwelling = false; | |
9ce192d4 RD |
127 | ptMouseLast.x = 0; |
128 | ptMouseLast.y = 0; | |
7e0c58e9 | 129 | inDragDrop = ddNone; |
9ce192d4 | 130 | dropWentOutside = false; |
9e96e16f RD |
131 | posDrag = SelectionPosition(invalidPosition); |
132 | posDrop = SelectionPosition(invalidPosition); | |
1dcf666d | 133 | hotSpotClickPos = INVALID_POSITION; |
9ce192d4 RD |
134 | selectionType = selChar; |
135 | ||
136 | lastXChosen = 0; | |
1dcf666d | 137 | lineAnchorPos = 0; |
9ce192d4 | 138 | originalAnchorPos = 0; |
1dcf666d RD |
139 | wordSelectAnchorStartPos = 0; |
140 | wordSelectAnchorEndPos = 0; | |
141 | wordSelectInitialCaretPos = -1; | |
9ce192d4 | 142 | |
d134f170 | 143 | primarySelection = true; |
9ce192d4 | 144 | |
a834585d RD |
145 | caretXPolicy = CARET_SLOP | CARET_EVEN; |
146 | caretXSlop = 50; | |
9ce192d4 | 147 | |
a834585d RD |
148 | caretYPolicy = CARET_EVEN; |
149 | caretYSlop = 0; | |
1dcf666d RD |
150 | |
151 | visiblePolicy = 0; | |
152 | visibleSlop = 0; | |
65ec6247 | 153 | |
9ce192d4 | 154 | searchAnchor = 0; |
d134f170 | 155 | |
9ce192d4 RD |
156 | xOffset = 0; |
157 | xCaretMargin = 50; | |
f6bcfd97 | 158 | horizontalScrollBarVisible = true; |
a834585d | 159 | scrollWidth = 2000; |
7e0c58e9 RD |
160 | trackLineWidth = false; |
161 | lineWidthMaxSeen = 0; | |
9e730a78 | 162 | verticalScrollBarVisible = true; |
a834585d | 163 | endAtLastLine = true; |
1dcf666d RD |
164 | caretSticky = SC_CARETSTICKY_OFF; |
165 | marginOptions = SC_MARGINOPTION_NONE; | |
9e96e16f RD |
166 | multipleSelection = false; |
167 | additionalSelectionTyping = false; | |
1dcf666d | 168 | multiPasteMode = SC_MULTIPASTE_ONCE; |
9e96e16f RD |
169 | additionalCaretsBlink = true; |
170 | additionalCaretsVisible = true; | |
171 | virtualSpaceOptions = SCVS_NONE; | |
d134f170 | 172 | |
1dcf666d RD |
173 | pixmapLine = 0; |
174 | pixmapSelMargin = 0; | |
175 | pixmapSelPattern = 0; | |
176 | pixmapIndentGuide = 0; | |
177 | pixmapIndentGuideHighlight = 0; | |
1a2fb4cd | 178 | |
65ec6247 RD |
179 | targetStart = 0; |
180 | targetEnd = 0; | |
181 | searchFlags = 0; | |
182 | ||
9ce192d4 RD |
183 | topLine = 0; |
184 | posTopLine = 0; | |
d134f170 | 185 | |
1e9bafca | 186 | lengthForEncode = -1; |
a33203cb | 187 | |
1dcf666d RD |
188 | needUpdateUI = 0; |
189 | ContainerNeedsUpdate(SC_UPDATE_CONTENT); | |
d134f170 RD |
190 | braces[0] = invalidPosition; |
191 | braces[1] = invalidPosition; | |
9ce192d4 | 192 | bracesMatchStyle = STYLE_BRACEBAD; |
d134f170 RD |
193 | highlightGuideColumn = 0; |
194 | ||
9ce192d4 | 195 | theEdge = 0; |
d134f170 | 196 | |
9ce192d4 | 197 | paintState = notPainting; |
1dcf666d | 198 | willRedrawAll = false; |
d134f170 | 199 | |
9ce192d4 RD |
200 | modEventMask = SC_MODEVENTMASKALL; |
201 | ||
202 | pdoc = new Document(); | |
9e730a78 | 203 | pdoc->AddRef(); |
9ce192d4 RD |
204 | pdoc->AddWatcher(this, 0); |
205 | ||
b8b0e402 | 206 | recordingMacro = false; |
9ce192d4 | 207 | foldFlags = 0; |
1a2fb4cd RD |
208 | |
209 | wrapState = eWrapNone; | |
210 | wrapWidth = LineLayout::wrapWidthInfinite; | |
b8193d80 RD |
211 | wrapStart = wrapLineLarge; |
212 | wrapEnd = wrapLineLarge; | |
591d01be RD |
213 | wrapVisualFlags = 0; |
214 | wrapVisualFlagsLocation = 0; | |
215 | wrapVisualStartIndent = 0; | |
9e96e16f | 216 | wrapIndentMode = SC_WRAPINDENT_FIXED; |
1a2fb4cd | 217 | |
1e9bafca RD |
218 | convertPastes = true; |
219 | ||
9e730a78 RD |
220 | hsStart = -1; |
221 | hsEnd = -1; | |
222 | ||
223 | llc.SetLevel(LineLayoutCache::llcCaret); | |
7e0c58e9 | 224 | posCache.SetSize(0x400); |
9ce192d4 RD |
225 | } |
226 | ||
227 | Editor::~Editor() { | |
228 | pdoc->RemoveWatcher(this, 0); | |
229 | pdoc->Release(); | |
230 | pdoc = 0; | |
1dcf666d | 231 | DropGraphics(true); |
9ce192d4 RD |
232 | } |
233 | ||
234 | void Editor::Finalise() { | |
8e54aaed | 235 | SetIdle(false); |
d134f170 | 236 | CancelModes(); |
9ce192d4 RD |
237 | } |
238 | ||
1dcf666d RD |
239 | void Editor::DropGraphics(bool freeObjects) { |
240 | if (freeObjects) { | |
241 | delete pixmapLine; | |
242 | pixmapLine = 0; | |
243 | delete pixmapSelMargin; | |
244 | pixmapSelMargin = 0; | |
245 | delete pixmapSelPattern; | |
246 | pixmapSelPattern = 0; | |
247 | delete pixmapIndentGuide; | |
248 | pixmapIndentGuide = 0; | |
249 | delete pixmapIndentGuideHighlight; | |
250 | pixmapIndentGuideHighlight = 0; | |
251 | } else { | |
252 | if (pixmapLine) | |
253 | pixmapLine->Release(); | |
254 | if (pixmapSelMargin) | |
255 | pixmapSelMargin->Release(); | |
256 | if (pixmapSelPattern) | |
257 | pixmapSelPattern->Release(); | |
258 | if (pixmapIndentGuide) | |
259 | pixmapIndentGuide->Release(); | |
260 | if (pixmapIndentGuideHighlight) | |
261 | pixmapIndentGuideHighlight->Release(); | |
262 | } | |
263 | } | |
264 | ||
265 | void Editor::AllocateGraphics() { | |
266 | if (!pixmapLine) | |
267 | pixmapLine = Surface::Allocate(technology); | |
268 | if (!pixmapSelMargin) | |
269 | pixmapSelMargin = Surface::Allocate(technology); | |
270 | if (!pixmapSelPattern) | |
271 | pixmapSelPattern = Surface::Allocate(technology); | |
272 | if (!pixmapIndentGuide) | |
273 | pixmapIndentGuide = Surface::Allocate(technology); | |
274 | if (!pixmapIndentGuideHighlight) | |
275 | pixmapIndentGuideHighlight = Surface::Allocate(technology); | |
9ce192d4 RD |
276 | } |
277 | ||
278 | void Editor::InvalidateStyleData() { | |
279 | stylesValid = false; | |
1dcf666d RD |
280 | vs.technology = technology; |
281 | DropGraphics(false); | |
282 | AllocateGraphics(); | |
1a2fb4cd | 283 | llc.Invalidate(LineLayout::llInvalid); |
7e0c58e9 | 284 | posCache.Clear(); |
9ce192d4 RD |
285 | } |
286 | ||
287 | void Editor::InvalidateStyleRedraw() { | |
f114b858 | 288 | NeedWrapping(); |
9ce192d4 RD |
289 | InvalidateStyleData(); |
290 | Redraw(); | |
291 | } | |
292 | ||
9ce192d4 RD |
293 | void Editor::RefreshStyleData() { |
294 | if (!stylesValid) { | |
295 | stylesValid = true; | |
9e730a78 | 296 | AutoSurface surface(this); |
1a2fb4cd RD |
297 | if (surface) { |
298 | vs.Refresh(*surface); | |
9e96e16f | 299 | } |
9ce192d4 | 300 | SetScrollBars(); |
9e96e16f | 301 | SetRectangularRange(); |
9ce192d4 RD |
302 | } |
303 | } | |
304 | ||
305 | PRectangle Editor::GetClientRectangle() { | |
65ec6247 | 306 | return wMain.GetClientPosition(); |
9ce192d4 RD |
307 | } |
308 | ||
309 | PRectangle Editor::GetTextRectangle() { | |
310 | PRectangle rc = GetClientRectangle(); | |
311 | rc.left += vs.fixedColumnWidth; | |
312 | rc.right -= vs.rightMarginWidth; | |
313 | return rc; | |
314 | } | |
315 | ||
316 | int Editor::LinesOnScreen() { | |
317 | PRectangle rcClient = GetClientRectangle(); | |
318 | int htClient = rcClient.bottom - rcClient.top; | |
319 | //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1); | |
7e0c58e9 | 320 | return htClient / vs.lineHeight; |
9ce192d4 RD |
321 | } |
322 | ||
323 | int Editor::LinesToScroll() { | |
324 | int retVal = LinesOnScreen() - 1; | |
325 | if (retVal < 1) | |
326 | return 1; | |
327 | else | |
328 | return retVal; | |
329 | } | |
330 | ||
331 | int Editor::MaxScrollPos() { | |
332 | //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n", | |
333 | //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1); | |
a834585d RD |
334 | int retVal = cs.LinesDisplayed(); |
335 | if (endAtLastLine) { | |
336 | retVal -= LinesOnScreen(); | |
337 | } else { | |
338 | retVal--; | |
339 | } | |
340 | if (retVal < 0) { | |
9ce192d4 | 341 | return 0; |
a834585d | 342 | } else { |
9ce192d4 | 343 | return retVal; |
a834585d | 344 | } |
9ce192d4 RD |
345 | } |
346 | ||
f6bcfd97 | 347 | const char *ControlCharacterString(unsigned char ch) { |
9ce192d4 | 348 | const char *reps[] = { |
9e730a78 RD |
349 | "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", |
350 | "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", | |
351 | "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", | |
352 | "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" | |
9ce192d4 RD |
353 | }; |
354 | if (ch < (sizeof(reps) / sizeof(reps[0]))) { | |
355 | return reps[ch]; | |
356 | } else { | |
357 | return "BAD"; | |
358 | } | |
359 | } | |
360 | ||
8e54aaed RD |
361 | /** |
362 | * Convenience class to ensure LineLayout objects are always disposed. | |
363 | */ | |
9e730a78 RD |
364 | class AutoLineLayout { |
365 | LineLayoutCache &llc; | |
366 | LineLayout *ll; | |
9e96e16f | 367 | AutoLineLayout &operator=(const AutoLineLayout &); |
9e730a78 RD |
368 | public: |
369 | AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {} | |
370 | ~AutoLineLayout() { | |
371 | llc.Dispose(ll); | |
372 | ll = 0; | |
373 | } | |
374 | LineLayout *operator->() const { | |
375 | return ll; | |
376 | } | |
377 | operator LineLayout *() const { | |
378 | return ll; | |
379 | } | |
380 | void Set(LineLayout *ll_) { | |
381 | llc.Dispose(ll); | |
382 | ll = ll_; | |
383 | } | |
384 | }; | |
385 | ||
9e96e16f RD |
386 | SelectionPosition Editor::ClampPositionIntoDocument(SelectionPosition sp) const { |
387 | if (sp.Position() < 0) { | |
388 | return SelectionPosition(0); | |
389 | } else if (sp.Position() > pdoc->Length()) { | |
390 | return SelectionPosition(pdoc->Length()); | |
391 | } else { | |
392 | // If not at end of line then set offset to 0 | |
393 | if (!pdoc->IsLineEndPosition(sp.Position())) | |
394 | sp.SetVirtualSpace(0); | |
395 | return sp; | |
8e54aaed | 396 | } |
7e0c58e9 | 397 | } |
7e0c58e9 | 398 | |
9e96e16f | 399 | Point Editor::LocationFromPosition(SelectionPosition pos) { |
65ec6247 | 400 | Point pt; |
9ce192d4 | 401 | RefreshStyleData(); |
9e96e16f | 402 | if (pos.Position() == INVALID_POSITION) |
65ec6247 | 403 | return pt; |
9e96e16f | 404 | int line = pdoc->LineFromPosition(pos.Position()); |
9ce192d4 RD |
405 | int lineVisible = cs.DisplayFromDoc(line); |
406 | //Platform::DebugPrintf("line=%d\n", line); | |
9e730a78 RD |
407 | AutoSurface surface(this); |
408 | AutoLineLayout ll(llc, RetrieveLineLayout(line)); | |
1a2fb4cd RD |
409 | if (surface && ll) { |
410 | // -1 because of adding in for visible lines in following loop. | |
411 | pt.y = (lineVisible - topLine - 1) * vs.lineHeight; | |
412 | pt.x = 0; | |
413 | unsigned int posLineStart = pdoc->LineStart(line); | |
414 | LayoutLine(line, surface, vs, ll, wrapWidth); | |
9e96e16f | 415 | int posInLine = pos.Position() - posLineStart; |
1a2fb4cd RD |
416 | // In case of very long line put x at arbitrary large position |
417 | if (posInLine > ll->maxLineLength) { | |
418 | pt.x = ll->positions[ll->maxLineLength] - ll->positions[ll->LineStart(ll->lines)]; | |
419 | } | |
591d01be | 420 | |
9e730a78 RD |
421 | for (int subLine = 0; subLine < ll->lines; subLine++) { |
422 | if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) { | |
1a2fb4cd | 423 | pt.x = ll->positions[posInLine] - ll->positions[ll->LineStart(subLine)]; |
9e96e16f | 424 | if (ll->wrapIndent != 0) { |
591d01be RD |
425 | int lineStart = ll->LineStart(subLine); |
426 | if (lineStart != 0) // Wrapped | |
9e96e16f | 427 | pt.x += ll->wrapIndent; |
591d01be | 428 | } |
1a2fb4cd RD |
429 | } |
430 | if (posInLine >= ll->LineStart(subLine)) { | |
431 | pt.y += vs.lineHeight; | |
432 | } | |
433 | } | |
434 | pt.x += vs.fixedColumnWidth - xOffset; | |
9ce192d4 | 435 | } |
1dcf666d | 436 | pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth; |
9ce192d4 RD |
437 | return pt; |
438 | } | |
439 | ||
9e96e16f RD |
440 | Point Editor::LocationFromPosition(int pos) { |
441 | return LocationFromPosition(SelectionPosition(pos)); | |
442 | } | |
443 | ||
65ec6247 | 444 | int Editor::XFromPosition(int pos) { |
9ce192d4 RD |
445 | Point pt = LocationFromPosition(pos); |
446 | return pt.x - vs.fixedColumnWidth + xOffset; | |
447 | } | |
d134f170 | 448 | |
9e96e16f RD |
449 | int Editor::XFromPosition(SelectionPosition sp) { |
450 | Point pt = LocationFromPosition(sp); | |
451 | return pt.x - vs.fixedColumnWidth + xOffset; | |
452 | } | |
453 | ||
9ce192d4 RD |
454 | int Editor::LineFromLocation(Point pt) { |
455 | return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine); | |
456 | } | |
457 | ||
458 | void Editor::SetTopLine(int topLineNew) { | |
1dcf666d RD |
459 | if (topLine != topLineNew) { |
460 | topLine = topLineNew; | |
461 | ContainerNeedsUpdate(SC_UPDATE_V_SCROLL); | |
462 | } | |
a33203cb | 463 | posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine)); |
9ce192d4 RD |
464 | } |
465 | ||
9e96e16f | 466 | SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace) { |
9ce192d4 | 467 | RefreshStyleData(); |
9e96e16f RD |
468 | if (canReturnInvalid) { |
469 | PRectangle rcClient = GetTextRectangle(); | |
470 | if (!rcClient.Contains(pt)) | |
471 | return SelectionPosition(INVALID_POSITION); | |
472 | if (pt.x < vs.fixedColumnWidth) | |
473 | return SelectionPosition(INVALID_POSITION); | |
474 | if (pt.y < 0) | |
475 | return SelectionPosition(INVALID_POSITION); | |
476 | } | |
9ce192d4 | 477 | pt.x = pt.x - vs.fixedColumnWidth + xOffset; |
1a2fb4cd | 478 | int visibleLine = pt.y / vs.lineHeight + topLine; |
9ce192d4 | 479 | if (pt.y < 0) { // Division rounds towards 0 |
1dcf666d | 480 | visibleLine = (static_cast<int>(pt.y) - (vs.lineHeight - 1)) / vs.lineHeight + topLine; |
9ce192d4 | 481 | } |
9e96e16f | 482 | if (!canReturnInvalid && (visibleLine < 0)) |
1a2fb4cd RD |
483 | visibleLine = 0; |
484 | int lineDoc = cs.DocFromDisplay(visibleLine); | |
9e96e16f RD |
485 | if (canReturnInvalid && (lineDoc < 0)) |
486 | return SelectionPosition(INVALID_POSITION); | |
1a2fb4cd | 487 | if (lineDoc >= pdoc->LinesTotal()) |
9e96e16f | 488 | return SelectionPosition(canReturnInvalid ? INVALID_POSITION : pdoc->Length()); |
9e730a78 | 489 | unsigned int posLineStart = pdoc->LineStart(lineDoc); |
9e96e16f | 490 | SelectionPosition retVal(canReturnInvalid ? INVALID_POSITION : static_cast<int>(posLineStart)); |
9e730a78 RD |
491 | AutoSurface surface(this); |
492 | AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); | |
1a2fb4cd RD |
493 | if (surface && ll) { |
494 | LayoutLine(lineDoc, surface, vs, ll, wrapWidth); | |
1a2fb4cd RD |
495 | int lineStartSet = cs.DisplayFromDoc(lineDoc); |
496 | int subLine = visibleLine - lineStartSet; | |
497 | if (subLine < ll->lines) { | |
498 | int lineStart = ll->LineStart(subLine); | |
7e0c58e9 | 499 | int lineEnd = ll->LineLastVisible(subLine); |
1dcf666d | 500 | XYPOSITION subLineStart = ll->positions[lineStart]; |
591d01be | 501 | |
9e96e16f | 502 | if (ll->wrapIndent != 0) { |
591d01be | 503 | if (lineStart != 0) // Wrapped |
9e96e16f | 504 | pt.x -= ll->wrapIndent; |
591d01be | 505 | } |
7e0c58e9 RD |
506 | int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd); |
507 | while (i < lineEnd) { | |
9e96e16f RD |
508 | if (charPosition) { |
509 | if ((pt.x + subLineStart) < (ll->positions[i + 1])) { | |
510 | return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1)); | |
511 | } | |
512 | } else { | |
513 | if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) { | |
514 | return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1)); | |
515 | } | |
1a2fb4cd | 516 | } |
7e0c58e9 | 517 | i++; |
1a2fb4cd | 518 | } |
9e96e16f | 519 | if (virtualSpace) { |
1dcf666d | 520 | const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; |
9e96e16f RD |
521 | int spaceOffset = (pt.x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) / |
522 | spaceWidth; | |
523 | return SelectionPosition(lineEnd + posLineStart, spaceOffset); | |
524 | } else if (canReturnInvalid) { | |
525 | if (pt.x < (ll->positions[lineEnd] - subLineStart)) { | |
526 | return SelectionPosition(pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1)); | |
527 | } | |
528 | } else { | |
529 | return SelectionPosition(lineEnd + posLineStart); | |
530 | } | |
9ce192d4 | 531 | } |
9e96e16f RD |
532 | if (!canReturnInvalid) |
533 | return SelectionPosition(ll->numCharsInLine + posLineStart); | |
9ce192d4 | 534 | } |
1a2fb4cd | 535 | return retVal; |
9ce192d4 RD |
536 | } |
537 | ||
9e96e16f RD |
538 | int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) { |
539 | return SPositionFromLocation(pt, canReturnInvalid, charPosition, false).Position(); | |
540 | } | |
541 | ||
a834585d RD |
542 | /** |
543 | * Find the document position corresponding to an x coordinate on a particular document line. | |
544 | * Ensure is between whole characters when document is in multi-byte or UTF-8 mode. | |
545 | */ | |
9e96e16f | 546 | SelectionPosition Editor::SPositionFromLineX(int lineDoc, int x) { |
9ce192d4 | 547 | RefreshStyleData(); |
1a2fb4cd | 548 | if (lineDoc >= pdoc->LinesTotal()) |
9e96e16f | 549 | return SelectionPosition(pdoc->Length()); |
9ce192d4 | 550 | //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); |
9e730a78 RD |
551 | AutoSurface surface(this); |
552 | AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); | |
1a2fb4cd RD |
553 | int retVal = 0; |
554 | if (surface && ll) { | |
555 | unsigned int posLineStart = pdoc->LineStart(lineDoc); | |
556 | LayoutLine(lineDoc, surface, vs, ll, wrapWidth); | |
1a2fb4cd RD |
557 | int subLine = 0; |
558 | int lineStart = ll->LineStart(subLine); | |
7e0c58e9 | 559 | int lineEnd = ll->LineLastVisible(subLine); |
1dcf666d RD |
560 | XYPOSITION subLineStart = ll->positions[lineStart]; |
561 | XYPOSITION newX = x; | |
591d01be | 562 | |
9e96e16f | 563 | if (ll->wrapIndent != 0) { |
591d01be | 564 | if (lineStart != 0) // Wrapped |
1dcf666d | 565 | newX -= ll->wrapIndent; |
591d01be | 566 | } |
1dcf666d | 567 | int i = ll->FindBefore(newX + subLineStart, lineStart, lineEnd); |
7e0c58e9 | 568 | while (i < lineEnd) { |
1dcf666d | 569 | if ((newX + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) { |
1a2fb4cd | 570 | retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1); |
9e96e16f | 571 | return SelectionPosition(retVal); |
1a2fb4cd | 572 | } |
7e0c58e9 | 573 | i++; |
9ce192d4 | 574 | } |
1dcf666d RD |
575 | const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; |
576 | int spaceOffset = (newX + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) / spaceWidth; | |
9e96e16f | 577 | return SelectionPosition(lineEnd + posLineStart, spaceOffset); |
9ce192d4 | 578 | } |
9e96e16f | 579 | return SelectionPosition(retVal); |
9ce192d4 RD |
580 | } |
581 | ||
1dcf666d RD |
582 | int Editor::PositionFromLineX(int lineDoc, int x) { |
583 | return SPositionFromLineX(lineDoc, x).Position(); | |
584 | } | |
585 | ||
8e54aaed RD |
586 | /** |
587 | * If painting then abandon the painting because a wider redraw is needed. | |
588 | * @return true if calling code should stop drawing. | |
589 | */ | |
a834585d RD |
590 | bool Editor::AbandonPaint() { |
591 | if ((paintState == painting) && !paintingAllText) { | |
592 | paintState = paintAbandoned; | |
593 | } | |
594 | return paintState == paintAbandoned; | |
595 | } | |
596 | ||
9ce192d4 | 597 | void Editor::RedrawRect(PRectangle rc) { |
65ec6247 | 598 | //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom); |
ce1ecc6d | 599 | |
65ec6247 RD |
600 | // Clip the redraw rectangle into the client area |
601 | PRectangle rcClient = GetClientRectangle(); | |
602 | if (rc.top < rcClient.top) | |
603 | rc.top = rcClient.top; | |
604 | if (rc.bottom > rcClient.bottom) | |
605 | rc.bottom = rcClient.bottom; | |
606 | if (rc.left < rcClient.left) | |
607 | rc.left = rcClient.left; | |
608 | if (rc.right > rcClient.right) | |
609 | rc.right = rcClient.right; | |
610 | ||
611 | if ((rc.bottom > rc.top) && (rc.right > rc.left)) { | |
612 | wMain.InvalidateRectangle(rc); | |
613 | } | |
9ce192d4 RD |
614 | } |
615 | ||
616 | void Editor::Redraw() { | |
617 | //Platform::DebugPrintf("Redraw all\n"); | |
e14d10b0 RD |
618 | PRectangle rcClient = GetClientRectangle(); |
619 | wMain.InvalidateRectangle(rcClient); | |
620 | //wMain.InvalidateAll(); | |
9ce192d4 RD |
621 | } |
622 | ||
1dcf666d | 623 | void Editor::RedrawSelMargin(int line, bool allAfter) { |
a834585d RD |
624 | if (!AbandonPaint()) { |
625 | if (vs.maskInLine) { | |
626 | Redraw(); | |
627 | } else { | |
628 | PRectangle rcSelMargin = GetClientRectangle(); | |
629 | rcSelMargin.right = vs.fixedColumnWidth; | |
1e9bafca RD |
630 | if (line != -1) { |
631 | int position = pdoc->LineStart(line); | |
632 | PRectangle rcLine = RectangleFromRange(position, position); | |
1dcf666d RD |
633 | |
634 | // Inflate line rectangle if there are image markers with height larger than line height | |
635 | if (vs.largestMarkerHeight > vs.lineHeight) { | |
636 | int delta = (vs.largestMarkerHeight - vs.lineHeight + 1) / 2; | |
637 | rcLine.top -= delta; | |
638 | rcLine.bottom += delta; | |
639 | if (rcLine.top < rcSelMargin.top) | |
640 | rcLine.top = rcSelMargin.top; | |
641 | if (rcLine.bottom > rcSelMargin.bottom) | |
642 | rcLine.bottom = rcSelMargin.bottom; | |
643 | } | |
644 | ||
1e9bafca | 645 | rcSelMargin.top = rcLine.top; |
1dcf666d RD |
646 | if (!allAfter) |
647 | rcSelMargin.bottom = rcLine.bottom; | |
1e9bafca | 648 | } |
a834585d RD |
649 | wMain.InvalidateRectangle(rcSelMargin); |
650 | } | |
9ce192d4 RD |
651 | } |
652 | } | |
653 | ||
654 | PRectangle Editor::RectangleFromRange(int start, int end) { | |
655 | int minPos = start; | |
656 | if (minPos > end) | |
657 | minPos = end; | |
658 | int maxPos = start; | |
659 | if (maxPos < end) | |
660 | maxPos = end; | |
661 | int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos)); | |
1a2fb4cd RD |
662 | int lineDocMax = pdoc->LineFromPosition(maxPos); |
663 | int maxLine = cs.DisplayFromDoc(lineDocMax) + cs.GetHeight(lineDocMax) - 1; | |
9ce192d4 RD |
664 | PRectangle rcClient = GetTextRectangle(); |
665 | PRectangle rc; | |
1dcf666d RD |
666 | const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0; |
667 | rc.left = vs.fixedColumnWidth - leftTextOverlap; | |
9ce192d4 RD |
668 | rc.top = (minLine - topLine) * vs.lineHeight; |
669 | if (rc.top < 0) | |
670 | rc.top = 0; | |
671 | rc.right = rcClient.right; | |
672 | rc.bottom = (maxLine - topLine + 1) * vs.lineHeight; | |
673 | // Ensure PRectangle is within 16 bit space | |
674 | rc.top = Platform::Clamp(rc.top, -32000, 32000); | |
675 | rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000); | |
676 | ||
677 | return rc; | |
678 | } | |
679 | ||
680 | void Editor::InvalidateRange(int start, int end) { | |
681 | RedrawRect(RectangleFromRange(start, end)); | |
682 | } | |
683 | ||
684 | int Editor::CurrentPosition() { | |
9e96e16f | 685 | return sel.MainCaret(); |
9ce192d4 RD |
686 | } |
687 | ||
688 | bool Editor::SelectionEmpty() { | |
9e96e16f | 689 | return sel.Empty(); |
9ce192d4 RD |
690 | } |
691 | ||
9e96e16f RD |
692 | SelectionPosition Editor::SelectionStart() { |
693 | return sel.RangeMain().Start(); | |
9ce192d4 RD |
694 | } |
695 | ||
9e96e16f RD |
696 | SelectionPosition Editor::SelectionEnd() { |
697 | return sel.RangeMain().End(); | |
8e54aaed RD |
698 | } |
699 | ||
1e9bafca | 700 | void Editor::SetRectangularRange() { |
9e96e16f RD |
701 | if (sel.IsRectangular()) { |
702 | int xAnchor = XFromPosition(sel.Rectangular().anchor); | |
703 | int xCaret = XFromPosition(sel.Rectangular().caret); | |
704 | if (sel.selType == Selection::selThin) { | |
705 | xCaret = xAnchor; | |
706 | } | |
86cf0018 | 707 | int lineAnchorRect = pdoc->LineFromPosition(sel.Rectangular().anchor.Position()); |
9e96e16f | 708 | int lineCaret = pdoc->LineFromPosition(sel.Rectangular().caret.Position()); |
86cf0018 VZ |
709 | int increment = (lineCaret > lineAnchorRect) ? 1 : -1; |
710 | for (int line=lineAnchorRect; line != lineCaret+increment; line += increment) { | |
9e96e16f RD |
711 | SelectionRange range(SPositionFromLineX(line, xCaret), SPositionFromLineX(line, xAnchor)); |
712 | if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) == 0) | |
713 | range.ClearVirtualSpace(); | |
86cf0018 | 714 | if (line == lineAnchorRect) |
9e96e16f RD |
715 | sel.SetSelection(range); |
716 | else | |
1dcf666d | 717 | sel.AddSelectionWithoutTrim(range); |
9e96e16f RD |
718 | } |
719 | } | |
720 | } | |
721 | ||
722 | void Editor::ThinRectangularRange() { | |
723 | if (sel.IsRectangular()) { | |
724 | sel.selType = Selection::selThin; | |
725 | if (sel.Rectangular().caret < sel.Rectangular().anchor) { | |
726 | sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).caret, sel.Range(0).anchor); | |
727 | } else { | |
728 | sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).anchor, sel.Range(0).caret); | |
729 | } | |
730 | SetRectangularRange(); | |
731 | } | |
732 | } | |
733 | ||
734 | void Editor::InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection) { | |
735 | if (sel.Count() > 1 || !(sel.RangeMain().anchor == newMain.anchor) || sel.IsRectangular()) { | |
736 | invalidateWholeSelection = true; | |
737 | } | |
738 | int firstAffected = Platform::Minimum(sel.RangeMain().Start().Position(), newMain.Start().Position()); | |
739 | // +1 for lastAffected ensures caret repainted | |
740 | int lastAffected = Platform::Maximum(newMain.caret.Position()+1, newMain.anchor.Position()); | |
741 | lastAffected = Platform::Maximum(lastAffected, sel.RangeMain().End().Position()); | |
742 | if (invalidateWholeSelection) { | |
743 | for (size_t r=0; r<sel.Count(); r++) { | |
744 | firstAffected = Platform::Minimum(firstAffected, sel.Range(r).caret.Position()); | |
745 | firstAffected = Platform::Minimum(firstAffected, sel.Range(r).anchor.Position()); | |
746 | lastAffected = Platform::Maximum(lastAffected, sel.Range(r).caret.Position()+1); | |
747 | lastAffected = Platform::Maximum(lastAffected, sel.Range(r).anchor.Position()); | |
748 | } | |
749 | } | |
1dcf666d | 750 | ContainerNeedsUpdate(SC_UPDATE_SELECTION); |
8e54aaed | 751 | InvalidateRange(firstAffected, lastAffected); |
9ce192d4 RD |
752 | } |
753 | ||
9e96e16f | 754 | void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_) { |
1dcf666d RD |
755 | currentPos_ = ClampPositionIntoDocument(currentPos_); |
756 | anchor_ = ClampPositionIntoDocument(anchor_); | |
757 | int currentLine = pdoc->LineFromPosition(currentPos_.Position()); | |
758 | /* For Line selection - ensure the anchor and caret are always | |
759 | at the beginning and end of the region lines. */ | |
760 | if (sel.selType == Selection::selLines) { | |
761 | if (currentPos_ > anchor_) { | |
762 | anchor_ = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(anchor_.Position()))); | |
763 | currentPos_ = SelectionPosition(pdoc->LineEnd(pdoc->LineFromPosition(currentPos_.Position()))); | |
764 | } else { | |
765 | currentPos_ = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(currentPos_.Position()))); | |
766 | anchor_ = SelectionPosition(pdoc->LineEnd(pdoc->LineFromPosition(anchor_.Position()))); | |
767 | } | |
768 | } | |
769 | SelectionRange rangeNew(currentPos_, anchor_); | |
9e96e16f RD |
770 | if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) { |
771 | InvalidateSelection(rangeNew); | |
8e54aaed | 772 | } |
9e96e16f | 773 | sel.RangeMain() = rangeNew; |
1e9bafca | 774 | SetRectangularRange(); |
9ce192d4 | 775 | ClaimSelection(); |
1dcf666d RD |
776 | |
777 | if (highlightDelimiter.NeedsDrawing(currentLine)) { | |
778 | RedrawSelMargin(); | |
779 | } | |
9ce192d4 RD |
780 | } |
781 | ||
9e96e16f RD |
782 | void Editor::SetSelection(int currentPos_, int anchor_) { |
783 | SetSelection(SelectionPosition(currentPos_), SelectionPosition(anchor_)); | |
784 | } | |
785 | ||
786 | // Just move the caret on the main selection | |
787 | void Editor::SetSelection(SelectionPosition currentPos_) { | |
788 | currentPos_ = ClampPositionIntoDocument(currentPos_); | |
1dcf666d | 789 | int currentLine = pdoc->LineFromPosition(currentPos_.Position()); |
9e96e16f RD |
790 | if (sel.Count() > 1 || !(sel.RangeMain().caret == currentPos_)) { |
791 | InvalidateSelection(SelectionRange(currentPos_)); | |
792 | } | |
793 | if (sel.IsRectangular()) { | |
794 | sel.Rectangular() = | |
795 | SelectionRange(SelectionPosition(currentPos_), sel.Rectangular().anchor); | |
796 | SetRectangularRange(); | |
797 | } else { | |
798 | sel.RangeMain() = | |
799 | SelectionRange(SelectionPosition(currentPos_), sel.RangeMain().anchor); | |
800 | } | |
801 | ClaimSelection(); | |
1dcf666d RD |
802 | |
803 | if (highlightDelimiter.NeedsDrawing(currentLine)) { | |
804 | RedrawSelMargin(); | |
805 | } | |
9e96e16f RD |
806 | } |
807 | ||
9ce192d4 | 808 | void Editor::SetSelection(int currentPos_) { |
9e96e16f RD |
809 | SetSelection(SelectionPosition(currentPos_)); |
810 | } | |
811 | ||
812 | void Editor::SetEmptySelection(SelectionPosition currentPos_) { | |
1dcf666d | 813 | int currentLine = pdoc->LineFromPosition(currentPos_.Position()); |
9e96e16f RD |
814 | SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_)); |
815 | if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) { | |
816 | InvalidateSelection(rangeNew); | |
8e54aaed | 817 | } |
9e96e16f RD |
818 | sel.Clear(); |
819 | sel.RangeMain() = rangeNew; | |
1e9bafca | 820 | SetRectangularRange(); |
9ce192d4 | 821 | ClaimSelection(); |
9e96e16f | 822 | |
1dcf666d RD |
823 | if (highlightDelimiter.NeedsDrawing(currentLine)) { |
824 | RedrawSelMargin(); | |
825 | } | |
9ce192d4 RD |
826 | } |
827 | ||
828 | void Editor::SetEmptySelection(int currentPos_) { | |
9e96e16f | 829 | SetEmptySelection(SelectionPosition(currentPos_)); |
9ce192d4 RD |
830 | } |
831 | ||
9e730a78 RD |
832 | bool Editor::RangeContainsProtected(int start, int end) const { |
833 | if (vs.ProtectionActive()) { | |
834 | if (start > end) { | |
835 | int t = start; | |
836 | start = end; | |
837 | end = t; | |
838 | } | |
839 | int mask = pdoc->stylingBitsMask; | |
840 | for (int pos = start; pos < end; pos++) { | |
841 | if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected()) | |
842 | return true; | |
843 | } | |
844 | } | |
845 | return false; | |
846 | } | |
847 | ||
8e54aaed | 848 | bool Editor::SelectionContainsProtected() { |
9e96e16f RD |
849 | for (size_t r=0; r<sel.Count(); r++) { |
850 | if (RangeContainsProtected(sel.Range(r).Start().Position(), | |
851 | sel.Range(r).End().Position())) { | |
852 | return true; | |
8e54aaed RD |
853 | } |
854 | } | |
9e96e16f | 855 | return false; |
9e730a78 RD |
856 | } |
857 | ||
8e54aaed RD |
858 | /** |
859 | * Asks document to find a good position and then moves out of any invisible positions. | |
860 | */ | |
9e96e16f RD |
861 | int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) const { |
862 | return MovePositionOutsideChar(SelectionPosition(pos), moveDir, checkLineEnd).Position(); | |
863 | } | |
864 | ||
865 | SelectionPosition Editor::MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd) const { | |
866 | int posMoved = pdoc->MovePositionOutsideChar(pos.Position(), moveDir, checkLineEnd); | |
867 | if (posMoved != pos.Position()) | |
868 | pos.SetPosition(posMoved); | |
9e730a78 RD |
869 | if (vs.ProtectionActive()) { |
870 | int mask = pdoc->stylingBitsMask; | |
871 | if (moveDir > 0) { | |
9e96e16f RD |
872 | if ((pos.Position() > 0) && vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected()) { |
873 | while ((pos.Position() < pdoc->Length()) && | |
874 | (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected())) | |
875 | pos.Add(1); | |
9e730a78 RD |
876 | } |
877 | } else if (moveDir < 0) { | |
9e96e16f RD |
878 | if (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected()) { |
879 | while ((pos.Position() > 0) && | |
880 | (vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected())) | |
881 | pos.Add(-1); | |
9e730a78 RD |
882 | } |
883 | } | |
d134f170 RD |
884 | } |
885 | return pos; | |
886 | } | |
887 | ||
9e96e16f | 888 | int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, bool ensureVisible) { |
1dcf666d RD |
889 | bool simpleCaret = (sel.Count() == 1) && sel.Empty(); |
890 | SelectionPosition spCaret = sel.Last(); | |
891 | ||
9e96e16f RD |
892 | int delta = newPos.Position() - sel.MainCaret(); |
893 | newPos = ClampPositionIntoDocument(newPos); | |
d134f170 | 894 | newPos = MovePositionOutsideChar(newPos, delta); |
1dcf666d RD |
895 | if (!multipleSelection && sel.IsRectangular() && (selt == Selection::selStream)) { |
896 | // Can't turn into multiple selection so clear additional selections | |
897 | InvalidateSelection(SelectionRange(newPos), true); | |
898 | SelectionRange rangeMain = sel.RangeMain(); | |
899 | sel.SetSelection(rangeMain); | |
900 | } | |
9e96e16f RD |
901 | if (!sel.IsRectangular() && (selt == Selection::selRectangle)) { |
902 | // Switching to rectangular | |
903 | SelectionRange rangeMain = sel.RangeMain(); | |
904 | sel.Clear(); | |
905 | sel.Rectangular() = rangeMain; | |
8e54aaed | 906 | } |
9e96e16f RD |
907 | if (selt != Selection::noSel) { |
908 | sel.selType = selt; | |
909 | } | |
910 | if (selt != Selection::noSel || sel.MoveExtends()) { | |
9ce192d4 RD |
911 | SetSelection(newPos); |
912 | } else { | |
913 | SetEmptySelection(newPos); | |
914 | } | |
9e730a78 | 915 | ShowCaretAtCurrentPosition(); |
1dcf666d RD |
916 | |
917 | int currentLine = pdoc->LineFromPosition(newPos.Position()); | |
8e54aaed | 918 | if (ensureVisible) { |
1dcf666d RD |
919 | // In case in need of wrapping to ensure DisplayFromDoc works. |
920 | if (currentLine >= wrapStart) | |
921 | WrapLines(true, -1); | |
922 | XYScrollPosition newXY = XYScrollToMakeVisible(true, true, true); | |
923 | if (simpleCaret && (newXY.xOffset == xOffset)) { | |
924 | // simple vertical scroll then invalidate | |
925 | ScrollTo(newXY.topLine); | |
926 | InvalidateSelection(SelectionRange(spCaret), true); | |
927 | } else { | |
928 | SetXYScroll(newXY); | |
929 | } | |
930 | } | |
931 | ||
932 | if (highlightDelimiter.NeedsDrawing(currentLine)) { | |
933 | RedrawSelMargin(); | |
8e54aaed | 934 | } |
9ce192d4 RD |
935 | return 0; |
936 | } | |
937 | ||
9e96e16f RD |
938 | int Editor::MovePositionTo(int newPos, Selection::selTypes selt, bool ensureVisible) { |
939 | return MovePositionTo(SelectionPosition(newPos), selt, ensureVisible); | |
940 | } | |
941 | ||
942 | SelectionPosition Editor::MovePositionSoVisible(SelectionPosition pos, int moveDir) { | |
943 | pos = ClampPositionIntoDocument(pos); | |
d134f170 | 944 | pos = MovePositionOutsideChar(pos, moveDir); |
9e96e16f | 945 | int lineDoc = pdoc->LineFromPosition(pos.Position()); |
9ce192d4 RD |
946 | if (cs.GetVisible(lineDoc)) { |
947 | return pos; | |
948 | } else { | |
949 | int lineDisplay = cs.DisplayFromDoc(lineDoc); | |
950 | if (moveDir > 0) { | |
1a2fb4cd RD |
951 | // lineDisplay is already line before fold as lines in fold use display line of line after fold |
952 | lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed()); | |
9e96e16f | 953 | return SelectionPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay))); |
9ce192d4 | 954 | } else { |
1a2fb4cd | 955 | lineDisplay = Platform::Clamp(lineDisplay - 1, 0, cs.LinesDisplayed()); |
9e96e16f | 956 | return SelectionPosition(pdoc->LineEnd(cs.DocFromDisplay(lineDisplay))); |
9ce192d4 RD |
957 | } |
958 | } | |
959 | } | |
960 | ||
9e96e16f RD |
961 | SelectionPosition Editor::MovePositionSoVisible(int pos, int moveDir) { |
962 | return MovePositionSoVisible(SelectionPosition(pos), moveDir); | |
963 | } | |
964 | ||
965 | Point Editor::PointMainCaret() { | |
966 | return LocationFromPosition(sel.Range(sel.Main()).caret); | |
967 | } | |
968 | ||
8e54aaed RD |
969 | /** |
970 | * Choose the x position that the caret will try to stick to | |
971 | * as it moves up and down. | |
972 | */ | |
9ce192d4 | 973 | void Editor::SetLastXChosen() { |
9e96e16f | 974 | Point pt = PointMainCaret(); |
1dcf666d | 975 | lastXChosen = pt.x + xOffset; |
9ce192d4 RD |
976 | } |
977 | ||
9e730a78 | 978 | void Editor::ScrollTo(int line, bool moveThumb) { |
9ce192d4 RD |
979 | int topLineNew = Platform::Clamp(line, 0, MaxScrollPos()); |
980 | if (topLineNew != topLine) { | |
981 | // Try to optimise small scrolls | |
1dcf666d | 982 | #ifndef UNDER_CE |
9ce192d4 | 983 | int linesToMove = topLine - topLineNew; |
1dcf666d RD |
984 | bool performBlit = (abs(linesToMove) <= 10) && (paintState == notPainting); |
985 | willRedrawAll = !performBlit; | |
986 | #endif | |
9ce192d4 | 987 | SetTopLine(topLineNew); |
1dcf666d RD |
988 | // Optimize by styling the view as this will invalidate any needed area |
989 | // which could abort the initial paint if discovered later. | |
990 | StyleToPositionInView(PositionAfterArea(GetClientRectangle())); | |
1e9bafca | 991 | #ifndef UNDER_CE |
1dcf666d RD |
992 | // Perform redraw rather than scroll if many lines would be redrawn anyway. |
993 | if (performBlit) { | |
9ce192d4 RD |
994 | ScrollText(linesToMove); |
995 | } else { | |
996 | Redraw(); | |
997 | } | |
1dcf666d | 998 | willRedrawAll = false; |
1e9bafca RD |
999 | #else |
1000 | Redraw(); | |
1001 | #endif | |
9e730a78 RD |
1002 | if (moveThumb) { |
1003 | SetVerticalScrollPos(); | |
1004 | } | |
9ce192d4 RD |
1005 | } |
1006 | } | |
1007 | ||
f6bcfd97 | 1008 | void Editor::ScrollText(int /* linesToMove */) { |
9ce192d4 RD |
1009 | //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove); |
1010 | Redraw(); | |
1011 | } | |
1012 | ||
1013 | void Editor::HorizontalScrollTo(int xPos) { | |
1014 | //Platform::DebugPrintf("HorizontalScroll %d\n", xPos); | |
1a2fb4cd RD |
1015 | if (xPos < 0) |
1016 | xPos = 0; | |
1017 | if ((wrapState == eWrapNone) && (xOffset != xPos)) { | |
1018 | xOffset = xPos; | |
1dcf666d | 1019 | ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); |
1a2fb4cd RD |
1020 | SetHorizontalScrollPos(); |
1021 | RedrawRect(GetClientRectangle()); | |
1022 | } | |
9ce192d4 RD |
1023 | } |
1024 | ||
1dcf666d RD |
1025 | void Editor::VerticalCentreCaret() { |
1026 | int lineDoc = pdoc->LineFromPosition(sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret()); | |
1027 | int lineDisplay = cs.DisplayFromDoc(lineDoc); | |
1028 | int newTop = lineDisplay - (LinesOnScreen() / 2); | |
1029 | if (topLine != newTop) { | |
1030 | SetTopLine(newTop > 0 ? newTop : 0); | |
1031 | RedrawRect(GetClientRectangle()); | |
1032 | } | |
1033 | } | |
1034 | ||
1035 | // Avoid 64 bit compiler warnings. | |
1036 | // Scintilla does not support text buffers larger than 2**31 | |
1037 | static int istrlen(const char *s) { | |
1038 | return static_cast<int>(strlen(s)); | |
1039 | } | |
1040 | ||
1041 | void Editor::MoveSelectedLines(int lineDelta) { | |
1042 | ||
1043 | // if selection doesn't start at the beginning of the line, set the new start | |
1044 | int selectionStart = SelectionStart().Position(); | |
1045 | int startLine = pdoc->LineFromPosition(selectionStart); | |
1046 | int beginningOfStartLine = pdoc->LineStart(startLine); | |
1047 | selectionStart = beginningOfStartLine; | |
1048 | ||
1049 | // if selection doesn't end at the beginning of a line greater than that of the start, | |
1050 | // then set it at the beginning of the next one | |
1051 | int selectionEnd = SelectionEnd().Position(); | |
1052 | int endLine = pdoc->LineFromPosition(selectionEnd); | |
1053 | int beginningOfEndLine = pdoc->LineStart(endLine); | |
1054 | bool appendEol = false; | |
1055 | if (selectionEnd > beginningOfEndLine | |
1056 | || selectionStart == selectionEnd) { | |
1057 | selectionEnd = pdoc->LineStart(endLine + 1); | |
1058 | appendEol = (selectionEnd == pdoc->Length() && pdoc->LineFromPosition(selectionEnd) == endLine); | |
1059 | } | |
1060 | ||
1061 | // if there's nowhere for the selection to move | |
1062 | // (i.e. at the beginning going up or at the end going down), | |
1063 | // stop it right there! | |
1064 | if ((selectionStart == 0 && lineDelta < 0) | |
1065 | || (selectionEnd == pdoc->Length() && lineDelta > 0) | |
1066 | || selectionStart == selectionEnd) { | |
1067 | return; | |
1068 | } | |
1069 | ||
1070 | UndoGroup ug(pdoc); | |
1071 | ||
1072 | if (lineDelta > 0 && selectionEnd == pdoc->LineStart(pdoc->LinesTotal() - 1)) { | |
1073 | SetSelection(pdoc->MovePositionOutsideChar(selectionEnd - 1, -1), selectionEnd); | |
1074 | ClearSelection(); | |
1075 | selectionEnd = CurrentPosition(); | |
1076 | } | |
1077 | SetSelection(selectionStart, selectionEnd); | |
1078 | ||
1079 | SelectionText selectedText; | |
1080 | CopySelectionRange(&selectedText); | |
1081 | ||
1082 | int selectionLength = SelectionRange(selectionStart, selectionEnd).Length(); | |
1083 | Point currentLocation = LocationFromPosition(CurrentPosition()); | |
1084 | int currentLine = LineFromLocation(currentLocation); | |
1085 | ||
1086 | if (appendEol) | |
1087 | SetSelection(pdoc->MovePositionOutsideChar(selectionStart - 1, -1), selectionEnd); | |
1088 | ClearSelection(); | |
1089 | ||
1090 | const char *eol = StringFromEOLMode(pdoc->eolMode); | |
1091 | if (currentLine + lineDelta >= pdoc->LinesTotal()) | |
1092 | pdoc->InsertCString(pdoc->Length(), eol); | |
1093 | GoToLine(currentLine + lineDelta); | |
1094 | ||
1095 | pdoc->InsertCString(CurrentPosition(), selectedText.s); | |
1096 | if (appendEol) { | |
1097 | pdoc->InsertCString(CurrentPosition() + selectionLength, eol); | |
1098 | selectionLength += istrlen(eol); | |
1099 | } | |
1100 | SetSelection(CurrentPosition(), CurrentPosition() + selectionLength); | |
1101 | } | |
1102 | ||
1103 | void Editor::MoveSelectedLinesUp() { | |
1104 | MoveSelectedLines(-1); | |
1105 | } | |
1106 | ||
1107 | void Editor::MoveSelectedLinesDown() { | |
1108 | MoveSelectedLines(1); | |
1109 | } | |
1110 | ||
f114b858 | 1111 | void Editor::MoveCaretInsideView(bool ensureVisible) { |
f6bcfd97 | 1112 | PRectangle rcClient = GetTextRectangle(); |
9e96e16f | 1113 | Point pt = PointMainCaret(); |
f6bcfd97 | 1114 | if (pt.y < rcClient.top) { |
9e96e16f | 1115 | MovePositionTo(SPositionFromLocation( |
1dcf666d RD |
1116 | Point(lastXChosen - xOffset, rcClient.top), |
1117 | false, false, UserVirtualSpace()), | |
9e96e16f | 1118 | Selection::noSel, ensureVisible); |
f6bcfd97 | 1119 | } else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) { |
d134f170 | 1120 | int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight; |
9e96e16f | 1121 | MovePositionTo(SPositionFromLocation( |
1dcf666d RD |
1122 | Point(lastXChosen - xOffset, rcClient.top + yOfLastLineFullyDisplayed), |
1123 | false, false, UserVirtualSpace()), | |
9e96e16f | 1124 | Selection::noSel, ensureVisible); |
f6bcfd97 BP |
1125 | } |
1126 | } | |
1127 | ||
1a2fb4cd RD |
1128 | int Editor::DisplayFromPosition(int pos) { |
1129 | int lineDoc = pdoc->LineFromPosition(pos); | |
1130 | int lineDisplay = cs.DisplayFromDoc(lineDoc); | |
9e730a78 RD |
1131 | AutoSurface surface(this); |
1132 | AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); | |
1a2fb4cd RD |
1133 | if (surface && ll) { |
1134 | LayoutLine(lineDoc, surface, vs, ll, wrapWidth); | |
1135 | unsigned int posLineStart = pdoc->LineStart(lineDoc); | |
1136 | int posInLine = pos - posLineStart; | |
1137 | lineDisplay--; // To make up for first increment ahead. | |
9e730a78 RD |
1138 | for (int subLine = 0; subLine < ll->lines; subLine++) { |
1139 | if (posInLine >= ll->LineStart(subLine)) { | |
1a2fb4cd RD |
1140 | lineDisplay++; |
1141 | } | |
1142 | } | |
1143 | } | |
1a2fb4cd RD |
1144 | return lineDisplay; |
1145 | } | |
1146 | ||
a834585d RD |
1147 | /** |
1148 | * Ensure the caret is reasonably visible in context. | |
1149 | * | |
1150 | Caret policy in SciTE | |
1151 | ||
1152 | If slop is set, we can define a slop value. | |
1153 | This value defines an unwanted zone (UZ) where the caret is... unwanted. | |
1154 | This zone is defined as a number of pixels near the vertical margins, | |
1155 | and as a number of lines near the horizontal margins. | |
1156 | By keeping the caret away from the edges, it is seen within its context, | |
1157 | so it is likely that the identifier that the caret is on can be completely seen, | |
1158 | and that the current line is seen with some of the lines following it which are | |
1159 | often dependent on that line. | |
1160 | ||
1161 | If strict is set, the policy is enforced... strictly. | |
1162 | The caret is centred on the display if slop is not set, | |
1163 | and cannot go in the UZ if slop is set. | |
1164 | ||
1165 | If jumps is set, the display is moved more energetically | |
1166 | so the caret can move in the same direction longer before the policy is applied again. | |
1167 | '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin. | |
1168 | ||
1169 | If even is not set, instead of having symmetrical UZs, | |
1170 | the left and bottom UZs are extended up to right and top UZs respectively. | |
1171 | This way, we favour the displaying of useful information: the begining of lines, | |
1172 | where most code reside, and the lines after the caret, eg. the body of a function. | |
1173 | ||
1174 | | | | | | | |
9e96e16f | 1175 | slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of |
a834585d RD |
1176 | | | | | | visibility or going into the UZ) display is... |
1177 | -----+--------+-------+------+--------------------------------------------+-------------------------------------------------------------- | |
1178 | 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right | |
1179 | 0 | 0 | 0 | 1 | Yes | moved by one position | |
1180 | 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right | |
1181 | 0 | 0 | 1 | 1 | Yes | centred on the caret | |
1182 | 0 | 1 | - | 0 | Caret is always on top/on right of display | - | |
1183 | 0 | 1 | - | 1 | No, caret is always centred | - | |
1184 | 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ | |
1185 | 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ | |
1186 | 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin | |
1187 | 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin | |
1188 | 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | - | |
1189 | 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position | |
1190 | 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin | |
1191 | */ | |
1dcf666d RD |
1192 | |
1193 | Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz) { | |
9ce192d4 | 1194 | PRectangle rcClient = GetTextRectangle(); |
1dcf666d RD |
1195 | const SelectionPosition posCaret = posDrag.IsValid() ? posDrag : sel.RangeMain().caret; |
1196 | const Point pt = LocationFromPosition(posCaret); | |
1197 | const Point ptBottomCaret(pt.x, pt.y + vs.lineHeight - 1); | |
1198 | const int lineCaret = DisplayFromPosition(posCaret.Position()); | |
1199 | ||
1200 | XYScrollPosition newXY(xOffset, topLine); | |
d134f170 | 1201 | |
65ec6247 | 1202 | // Vertical positioning |
1dcf666d RD |
1203 | if (vert && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) { |
1204 | const int linesOnScreen = LinesOnScreen(); | |
1205 | const int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2; | |
1206 | const bool bSlop = (caretYPolicy & CARET_SLOP) != 0; | |
1207 | const bool bStrict = (caretYPolicy & CARET_STRICT) != 0; | |
1208 | const bool bJump = (caretYPolicy & CARET_JUMPS) != 0; | |
1209 | const bool bEven = (caretYPolicy & CARET_EVEN) != 0; | |
a834585d | 1210 | |
9ce192d4 RD |
1211 | // It should be possible to scroll the window to show the caret, |
1212 | // but this fails to remove the caret on GTK+ | |
a834585d RD |
1213 | if (bSlop) { // A margin is defined |
1214 | int yMoveT, yMoveB; | |
1215 | if (bStrict) { | |
1216 | int yMarginT, yMarginB; | |
1217 | if (!useMargin) { | |
1218 | // In drag mode, avoid moves | |
1219 | // otherwise, a double click will select several lines. | |
1220 | yMarginT = yMarginB = 0; | |
1221 | } else { | |
1222 | // yMarginT must equal to caretYSlop, with a minimum of 1 and | |
1223 | // a maximum of slightly less than half the heigth of the text area. | |
1224 | yMarginT = Platform::Clamp(caretYSlop, 1, halfScreen); | |
1225 | if (bEven) { | |
1226 | yMarginB = yMarginT; | |
1227 | } else { | |
1228 | yMarginB = linesOnScreen - yMarginT - 1; | |
1229 | } | |
1230 | } | |
1231 | yMoveT = yMarginT; | |
1232 | if (bEven) { | |
1233 | if (bJump) { | |
1234 | yMoveT = Platform::Clamp(caretYSlop * 3, 1, halfScreen); | |
1235 | } | |
1236 | yMoveB = yMoveT; | |
1237 | } else { | |
1238 | yMoveB = linesOnScreen - yMoveT - 1; | |
1239 | } | |
1240 | if (lineCaret < topLine + yMarginT) { | |
1241 | // Caret goes too high | |
1dcf666d | 1242 | newXY.topLine = lineCaret - yMoveT; |
a834585d RD |
1243 | } else if (lineCaret > topLine + linesOnScreen - 1 - yMarginB) { |
1244 | // Caret goes too low | |
1dcf666d | 1245 | newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB; |
a834585d RD |
1246 | } |
1247 | } else { // Not strict | |
1248 | yMoveT = bJump ? caretYSlop * 3 : caretYSlop; | |
1249 | yMoveT = Platform::Clamp(yMoveT, 1, halfScreen); | |
1250 | if (bEven) { | |
1251 | yMoveB = yMoveT; | |
1252 | } else { | |
1253 | yMoveB = linesOnScreen - yMoveT - 1; | |
1254 | } | |
1255 | if (lineCaret < topLine) { | |
1256 | // Caret goes too high | |
1dcf666d | 1257 | newXY.topLine = lineCaret - yMoveT; |
a834585d RD |
1258 | } else if (lineCaret > topLine + linesOnScreen - 1) { |
1259 | // Caret goes too low | |
1dcf666d | 1260 | newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB; |
a834585d | 1261 | } |
9ce192d4 | 1262 | } |
a834585d RD |
1263 | } else { // No slop |
1264 | if (!bStrict && !bJump) { | |
1265 | // Minimal move | |
1266 | if (lineCaret < topLine) { | |
1267 | // Caret goes too high | |
1dcf666d | 1268 | newXY.topLine = lineCaret; |
a834585d RD |
1269 | } else if (lineCaret > topLine + linesOnScreen - 1) { |
1270 | // Caret goes too low | |
1271 | if (bEven) { | |
1dcf666d | 1272 | newXY.topLine = lineCaret - linesOnScreen + 1; |
a834585d | 1273 | } else { |
1dcf666d | 1274 | newXY.topLine = lineCaret; |
a834585d RD |
1275 | } |
1276 | } | |
1277 | } else { // Strict or going out of display | |
1278 | if (bEven) { | |
1279 | // Always center caret | |
1dcf666d | 1280 | newXY.topLine = lineCaret - halfScreen; |
a834585d RD |
1281 | } else { |
1282 | // Always put caret on top of display | |
1dcf666d | 1283 | newXY.topLine = lineCaret; |
a834585d | 1284 | } |
9ce192d4 RD |
1285 | } |
1286 | } | |
1dcf666d | 1287 | newXY.topLine = Platform::Clamp(newXY.topLine, 0, MaxScrollPos()); |
65ec6247 RD |
1288 | } |
1289 | ||
1290 | // Horizontal positioning | |
1a2fb4cd | 1291 | if (horiz && (wrapState == eWrapNone)) { |
1dcf666d RD |
1292 | const int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2; |
1293 | const bool bSlop = (caretXPolicy & CARET_SLOP) != 0; | |
1294 | const bool bStrict = (caretXPolicy & CARET_STRICT) != 0; | |
1295 | const bool bJump = (caretXPolicy & CARET_JUMPS) != 0; | |
1296 | const bool bEven = (caretXPolicy & CARET_EVEN) != 0; | |
a834585d RD |
1297 | |
1298 | if (bSlop) { // A margin is defined | |
1299 | int xMoveL, xMoveR; | |
1300 | if (bStrict) { | |
1301 | int xMarginL, xMarginR; | |
1302 | if (!useMargin) { | |
1303 | // In drag mode, avoid moves unless very near of the margin | |
1304 | // otherwise, a simple click will select text. | |
1305 | xMarginL = xMarginR = 2; | |
1306 | } else { | |
1307 | // xMargin must equal to caretXSlop, with a minimum of 2 and | |
1308 | // a maximum of slightly less than half the width of the text area. | |
1309 | xMarginR = Platform::Clamp(caretXSlop, 2, halfScreen); | |
1310 | if (bEven) { | |
1311 | xMarginL = xMarginR; | |
1312 | } else { | |
1313 | xMarginL = rcClient.Width() - xMarginR - 4; | |
1314 | } | |
1315 | } | |
1316 | if (bJump && bEven) { | |
1317 | // Jump is used only in even mode | |
1318 | xMoveL = xMoveR = Platform::Clamp(caretXSlop * 3, 1, halfScreen); | |
1319 | } else { | |
1320 | xMoveL = xMoveR = 0; // Not used, avoid a warning | |
1321 | } | |
1322 | if (pt.x < rcClient.left + xMarginL) { | |
1323 | // Caret is on the left of the display | |
1324 | if (bJump && bEven) { | |
1dcf666d | 1325 | newXY.xOffset -= xMoveL; |
a834585d RD |
1326 | } else { |
1327 | // Move just enough to allow to display the caret | |
1dcf666d | 1328 | newXY.xOffset -= (rcClient.left + xMarginL) - pt.x; |
a834585d RD |
1329 | } |
1330 | } else if (pt.x >= rcClient.right - xMarginR) { | |
1331 | // Caret is on the right of the display | |
1332 | if (bJump && bEven) { | |
1dcf666d | 1333 | newXY.xOffset += xMoveR; |
a834585d RD |
1334 | } else { |
1335 | // Move just enough to allow to display the caret | |
1dcf666d | 1336 | newXY.xOffset += pt.x - (rcClient.right - xMarginR) + 1; |
a834585d RD |
1337 | } |
1338 | } | |
1339 | } else { // Not strict | |
1340 | xMoveR = bJump ? caretXSlop * 3 : caretXSlop; | |
1341 | xMoveR = Platform::Clamp(xMoveR, 1, halfScreen); | |
1342 | if (bEven) { | |
1343 | xMoveL = xMoveR; | |
1344 | } else { | |
1345 | xMoveL = rcClient.Width() - xMoveR - 4; | |
1346 | } | |
1347 | if (pt.x < rcClient.left) { | |
1348 | // Caret is on the left of the display | |
1dcf666d | 1349 | newXY.xOffset -= xMoveL; |
a834585d RD |
1350 | } else if (pt.x >= rcClient.right) { |
1351 | // Caret is on the right of the display | |
1dcf666d | 1352 | newXY.xOffset += xMoveR; |
a834585d RD |
1353 | } |
1354 | } | |
1355 | } else { // No slop | |
1356 | if (bStrict || | |
9e730a78 | 1357 | (bJump && (pt.x < rcClient.left || pt.x >= rcClient.right))) { |
a834585d RD |
1358 | // Strict or going out of display |
1359 | if (bEven) { | |
1360 | // Center caret | |
1dcf666d | 1361 | newXY.xOffset += pt.x - rcClient.left - halfScreen; |
a834585d RD |
1362 | } else { |
1363 | // Put caret on right | |
1dcf666d | 1364 | newXY.xOffset += pt.x - rcClient.right + 1; |
a834585d RD |
1365 | } |
1366 | } else { | |
1367 | // Move just enough to allow to display the caret | |
1368 | if (pt.x < rcClient.left) { | |
1369 | // Caret is on the left of the display | |
1370 | if (bEven) { | |
1dcf666d | 1371 | newXY.xOffset -= rcClient.left - pt.x; |
a834585d | 1372 | } else { |
1dcf666d | 1373 | newXY.xOffset += pt.x - rcClient.right + 1; |
a834585d RD |
1374 | } |
1375 | } else if (pt.x >= rcClient.right) { | |
1376 | // Caret is on the right of the display | |
1dcf666d | 1377 | newXY.xOffset += pt.x - rcClient.right + 1; |
a834585d RD |
1378 | } |
1379 | } | |
1380 | } | |
1381 | // In case of a jump (find result) largely out of display, adjust the offset to display the caret | |
1dcf666d RD |
1382 | if (pt.x + xOffset < rcClient.left + newXY.xOffset) { |
1383 | newXY.xOffset = pt.x + xOffset - rcClient.left; | |
1384 | } else if (pt.x + xOffset >= rcClient.right + newXY.xOffset) { | |
1385 | newXY.xOffset = pt.x + xOffset - rcClient.right + 1; | |
7e0c58e9 RD |
1386 | if (vs.caretStyle == CARETSTYLE_BLOCK) { |
1387 | // Ensure we can see a good portion of the block caret | |
1dcf666d | 1388 | newXY.xOffset += static_cast<int>(vs.aveCharWidth); |
7e0c58e9 | 1389 | } |
a834585d | 1390 | } |
1dcf666d RD |
1391 | if (newXY.xOffset < 0) { |
1392 | newXY.xOffset = 0; | |
1393 | } | |
1394 | } | |
1395 | ||
1396 | return newXY; | |
1397 | } | |
1398 | ||
1399 | void Editor::SetXYScroll(XYScrollPosition newXY) { | |
1400 | if ((newXY.topLine != topLine) || (newXY.xOffset != xOffset)) { | |
1401 | if (newXY.topLine != topLine) { | |
1402 | SetTopLine(newXY.topLine); | |
1403 | SetVerticalScrollPos(); | |
a834585d | 1404 | } |
1dcf666d RD |
1405 | if (newXY.xOffset != xOffset) { |
1406 | xOffset = newXY.xOffset; | |
1407 | ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); | |
1408 | if (newXY.xOffset > 0) { | |
9e730a78 | 1409 | PRectangle rcText = GetTextRectangle(); |
7e0c58e9 | 1410 | if (horizontalScrollBarVisible && |
1dcf666d | 1411 | rcText.Width() + xOffset > scrollWidth) { |
9e730a78 RD |
1412 | scrollWidth = xOffset + rcText.Width(); |
1413 | SetScrollBars(); | |
1414 | } | |
1415 | } | |
9ce192d4 | 1416 | SetHorizontalScrollPos(); |
9ce192d4 | 1417 | } |
1dcf666d RD |
1418 | Redraw(); |
1419 | UpdateSystemCaret(); | |
9ce192d4 | 1420 | } |
1dcf666d RD |
1421 | } |
1422 | ||
1423 | void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { | |
1424 | SetXYScroll(XYScrollToMakeVisible(useMargin, vert, horiz)); | |
9ce192d4 RD |
1425 | } |
1426 | ||
1427 | void Editor::ShowCaretAtCurrentPosition() { | |
1a2fb4cd RD |
1428 | if (hasFocus) { |
1429 | caret.active = true; | |
1430 | caret.on = true; | |
1431 | SetTicking(true); | |
1432 | } else { | |
9ce192d4 RD |
1433 | caret.active = false; |
1434 | caret.on = false; | |
9ce192d4 | 1435 | } |
1a2fb4cd | 1436 | InvalidateCaret(); |
9ce192d4 RD |
1437 | } |
1438 | ||
1439 | void Editor::DropCaret() { | |
1440 | caret.active = false; | |
1441 | InvalidateCaret(); | |
1442 | } | |
1443 | ||
1444 | void Editor::InvalidateCaret() { | |
9e96e16f RD |
1445 | if (posDrag.IsValid()) { |
1446 | InvalidateRange(posDrag.Position(), posDrag.Position() + 1); | |
1447 | } else { | |
1448 | for (size_t r=0; r<sel.Count(); r++) { | |
1449 | InvalidateRange(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1); | |
1450 | } | |
1451 | } | |
a33203cb RD |
1452 | UpdateSystemCaret(); |
1453 | } | |
1454 | ||
1455 | void Editor::UpdateSystemCaret() { | |
9ce192d4 RD |
1456 | } |
1457 | ||
b8193d80 RD |
1458 | void Editor::NeedWrapping(int docLineStart, int docLineEnd) { |
1459 | docLineStart = Platform::Clamp(docLineStart, 0, pdoc->LinesTotal()); | |
1460 | if (wrapStart > docLineStart) { | |
1461 | wrapStart = docLineStart; | |
a834585d RD |
1462 | llc.Invalidate(LineLayout::llPositions); |
1463 | } | |
b8193d80 RD |
1464 | if (wrapEnd < docLineEnd) { |
1465 | wrapEnd = docLineEnd; | |
8e54aaed | 1466 | } |
b8193d80 | 1467 | wrapEnd = Platform::Clamp(wrapEnd, 0, pdoc->LinesTotal()); |
8e54aaed | 1468 | // Wrap lines during idle. |
b8193d80 | 1469 | if ((wrapState != eWrapNone) && (wrapEnd != wrapStart)) { |
8e54aaed RD |
1470 | SetIdle(true); |
1471 | } | |
1a2fb4cd RD |
1472 | } |
1473 | ||
7e0c58e9 RD |
1474 | bool Editor::WrapOneLine(Surface *surface, int lineToWrap) { |
1475 | AutoLineLayout ll(llc, RetrieveLineLayout(lineToWrap)); | |
1476 | int linesWrapped = 1; | |
1477 | if (ll) { | |
1478 | LayoutLine(lineToWrap, surface, vs, ll, wrapWidth); | |
1479 | linesWrapped = ll->lines; | |
1480 | } | |
9e96e16f RD |
1481 | return cs.SetHeight(lineToWrap, linesWrapped + |
1482 | (vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0)); | |
7e0c58e9 RD |
1483 | } |
1484 | ||
1a2fb4cd | 1485 | // Check if wrapping needed and perform any needed wrapping. |
8e54aaed RD |
1486 | // fullwrap: if true, all lines which need wrapping will be done, |
1487 | // in this single call. | |
9e96e16f | 1488 | // priorityWrapLineStart: If greater than or equal to zero, all lines starting from |
b8193d80 | 1489 | // here to 1 page + 100 lines past will be wrapped (even if there are |
8e54aaed | 1490 | // more lines under wrapping process in idle). |
b8193d80 | 1491 | // If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be |
8e54aaed RD |
1492 | // wrapped, if there are any wrapping going on in idle. (Generally this |
1493 | // condition is called only from idler). | |
1a2fb4cd | 1494 | // Return true if wrapping occurred. |
8e54aaed RD |
1495 | bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) { |
1496 | // If there are any pending wraps, do them during idle if possible. | |
b8193d80 | 1497 | int linesInOneCall = LinesOnScreen() + 100; |
1dcf666d RD |
1498 | if (priorityWrapLineStart >= 0) { |
1499 | // Using DocFromDisplay() here may result in chicken and egg problem in certain corner cases, | |
1500 | // which will hopefully be handled by added 100 lines. If some lines are still missed, idle wrapping will catch on. | |
1501 | int docLinesInOneCall = cs.DocFromDisplay(topLine + LinesOnScreen() + 100) - cs.DocFromDisplay(topLine); | |
1502 | linesInOneCall = Platform::Maximum(linesInOneCall, docLinesInOneCall); | |
1503 | } | |
8e54aaed | 1504 | if (wrapState != eWrapNone) { |
b8193d80 RD |
1505 | if (wrapStart < wrapEnd) { |
1506 | if (!SetIdle(true)) { | |
1507 | // Idle processing not supported so full wrap required. | |
8e54aaed RD |
1508 | fullWrap = true; |
1509 | } | |
1510 | } | |
1511 | if (!fullWrap && priorityWrapLineStart >= 0 && | |
7e0c58e9 RD |
1512 | // .. and if the paint window is outside pending wraps |
1513 | (((priorityWrapLineStart + linesInOneCall) < wrapStart) || | |
1514 | (priorityWrapLineStart > wrapEnd))) { | |
8e54aaed RD |
1515 | // No priority wrap pending |
1516 | return false; | |
1517 | } | |
1518 | } | |
1a2fb4cd RD |
1519 | int goodTopLine = topLine; |
1520 | bool wrapOccurred = false; | |
b8193d80 | 1521 | if (wrapStart <= pdoc->LinesTotal()) { |
1a2fb4cd RD |
1522 | if (wrapState == eWrapNone) { |
1523 | if (wrapWidth != LineLayout::wrapWidthInfinite) { | |
1524 | wrapWidth = LineLayout::wrapWidthInfinite; | |
9e730a78 | 1525 | for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) { |
9e96e16f RD |
1526 | cs.SetHeight(lineDoc, 1 + |
1527 | (vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0)); | |
1a2fb4cd RD |
1528 | } |
1529 | wrapOccurred = true; | |
1530 | } | |
b8193d80 RD |
1531 | wrapStart = wrapLineLarge; |
1532 | wrapEnd = wrapLineLarge; | |
1a2fb4cd | 1533 | } else { |
b8193d80 RD |
1534 | if (wrapEnd >= pdoc->LinesTotal()) |
1535 | wrapEnd = pdoc->LinesTotal(); | |
a834585d | 1536 | //ElapsedTime et; |
1a2fb4cd RD |
1537 | int lineDocTop = cs.DocFromDisplay(topLine); |
1538 | int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop); | |
1539 | PRectangle rcTextArea = GetClientRectangle(); | |
1540 | rcTextArea.left = vs.fixedColumnWidth; | |
1541 | rcTextArea.right -= vs.rightMarginWidth; | |
1542 | wrapWidth = rcTextArea.Width(); | |
8e54aaed | 1543 | RefreshStyleData(); |
9e730a78 | 1544 | AutoSurface surface(this); |
1a2fb4cd | 1545 | if (surface) { |
8e54aaed | 1546 | bool priorityWrap = false; |
b8193d80 RD |
1547 | int lastLineToWrap = wrapEnd; |
1548 | int lineToWrap = wrapStart; | |
8e54aaed RD |
1549 | if (!fullWrap) { |
1550 | if (priorityWrapLineStart >= 0) { | |
1551 | // This is a priority wrap. | |
b8193d80 RD |
1552 | lineToWrap = priorityWrapLineStart; |
1553 | lastLineToWrap = priorityWrapLineStart + linesInOneCall; | |
8e54aaed RD |
1554 | priorityWrap = true; |
1555 | } else { | |
1556 | // This is idle wrap. | |
b8193d80 | 1557 | lastLineToWrap = wrapStart + linesInOneCall; |
8e54aaed | 1558 | } |
b8193d80 RD |
1559 | if (lastLineToWrap >= wrapEnd) |
1560 | lastLineToWrap = wrapEnd; | |
8e54aaed RD |
1561 | } // else do a fullWrap. |
1562 | ||
1dcf666d RD |
1563 | // Ensure all lines being wrapped are styled. |
1564 | pdoc->EnsureStyledTo(pdoc->LineEnd(lastLineToWrap)); | |
1565 | ||
b8193d80 RD |
1566 | // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap); |
1567 | // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd); | |
1568 | while (lineToWrap < lastLineToWrap) { | |
7e0c58e9 | 1569 | if (WrapOneLine(surface, lineToWrap)) { |
1a2fb4cd RD |
1570 | wrapOccurred = true; |
1571 | } | |
b8193d80 | 1572 | lineToWrap++; |
1a2fb4cd | 1573 | } |
b8193d80 RD |
1574 | if (!priorityWrap) |
1575 | wrapStart = lineToWrap; | |
8e54aaed | 1576 | // If wrapping is done, bring it to resting position |
b8193d80 RD |
1577 | if (wrapStart >= wrapEnd) { |
1578 | wrapStart = wrapLineLarge; | |
1579 | wrapEnd = wrapLineLarge; | |
8e54aaed | 1580 | } |
1a2fb4cd RD |
1581 | } |
1582 | goodTopLine = cs.DisplayFromDoc(lineDocTop); | |
1583 | if (subLineTop < cs.GetHeight(lineDocTop)) | |
1584 | goodTopLine += subLineTop; | |
1585 | else | |
1586 | goodTopLine += cs.GetHeight(lineDocTop); | |
a834585d | 1587 | //double durWrap = et.Duration(true); |
e4f0b986 | 1588 | //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap); |
1a2fb4cd RD |
1589 | } |
1590 | } | |
1591 | if (wrapOccurred) { | |
1592 | SetScrollBars(); | |
1593 | SetTopLine(Platform::Clamp(goodTopLine, 0, MaxScrollPos())); | |
1594 | SetVerticalScrollPos(); | |
1595 | } | |
1596 | return wrapOccurred; | |
1597 | } | |
1598 | ||
9e730a78 RD |
1599 | void Editor::LinesJoin() { |
1600 | if (!RangeContainsProtected(targetStart, targetEnd)) { | |
9e96e16f | 1601 | UndoGroup ug(pdoc); |
9e730a78 RD |
1602 | bool prevNonWS = true; |
1603 | for (int pos = targetStart; pos < targetEnd; pos++) { | |
1604 | if (IsEOLChar(pdoc->CharAt(pos))) { | |
1605 | targetEnd -= pdoc->LenChar(pos); | |
1606 | pdoc->DelChar(pos); | |
1607 | if (prevNonWS) { | |
1608 | // Ensure at least one space separating previous lines | |
1609 | pdoc->InsertChar(pos, ' '); | |
7e0c58e9 | 1610 | targetEnd++; |
9e730a78 RD |
1611 | } |
1612 | } else { | |
1613 | prevNonWS = pdoc->CharAt(pos) != ' '; | |
1614 | } | |
1615 | } | |
9e730a78 RD |
1616 | } |
1617 | } | |
1618 | ||
9e96e16f | 1619 | const char *Editor::StringFromEOLMode(int eolMode) { |
9e730a78 RD |
1620 | if (eolMode == SC_EOL_CRLF) { |
1621 | return "\r\n"; | |
1622 | } else if (eolMode == SC_EOL_CR) { | |
1623 | return "\r"; | |
1624 | } else { | |
1625 | return "\n"; | |
1626 | } | |
1627 | } | |
1628 | ||
1629 | void Editor::LinesSplit(int pixelWidth) { | |
1630 | if (!RangeContainsProtected(targetStart, targetEnd)) { | |
1631 | if (pixelWidth == 0) { | |
1632 | PRectangle rcText = GetTextRectangle(); | |
1633 | pixelWidth = rcText.Width(); | |
1634 | } | |
1635 | int lineStart = pdoc->LineFromPosition(targetStart); | |
1636 | int lineEnd = pdoc->LineFromPosition(targetEnd); | |
1637 | const char *eol = StringFromEOLMode(pdoc->eolMode); | |
9e96e16f | 1638 | UndoGroup ug(pdoc); |
9e730a78 RD |
1639 | for (int line = lineStart; line <= lineEnd; line++) { |
1640 | AutoSurface surface(this); | |
1641 | AutoLineLayout ll(llc, RetrieveLineLayout(line)); | |
1642 | if (surface && ll) { | |
1643 | unsigned int posLineStart = pdoc->LineStart(line); | |
1644 | LayoutLine(line, surface, vs, ll, pixelWidth); | |
1645 | for (int subLine = 1; subLine < ll->lines; subLine++) { | |
1dcf666d RD |
1646 | pdoc->InsertCString( |
1647 | static_cast<int>(posLineStart + (subLine - 1) * strlen(eol) + | |
1648 | ll->LineStart(subLine)), | |
1649 | eol); | |
88a8b04e | 1650 | targetEnd += static_cast<int>(strlen(eol)); |
9e730a78 RD |
1651 | } |
1652 | } | |
b8193d80 | 1653 | lineEnd = pdoc->LineFromPosition(targetEnd); |
9e730a78 | 1654 | } |
9e730a78 RD |
1655 | } |
1656 | } | |
1657 | ||
65ec6247 RD |
1658 | int Editor::SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) { |
1659 | if (vs.markers[markerCheck].markType == SC_MARK_EMPTY) | |
1660 | return markerDefault; | |
1661 | return markerCheck; | |
1662 | } | |
1663 | ||
9e96e16f RD |
1664 | bool ValidStyledText(ViewStyle &vs, size_t styleOffset, const StyledText &st) { |
1665 | if (st.multipleStyles) { | |
1dcf666d | 1666 | for (size_t iStyle=0; iStyle<st.length; iStyle++) { |
9e96e16f RD |
1667 | if (!vs.ValidStyle(styleOffset + st.styles[iStyle])) |
1668 | return false; | |
1669 | } | |
1670 | } else { | |
1671 | if (!vs.ValidStyle(styleOffset + st.style)) | |
1672 | return false; | |
1673 | } | |
1674 | return true; | |
1675 | } | |
1676 | ||
1677 | static int WidthStyledText(Surface *surface, ViewStyle &vs, int styleOffset, | |
1678 | const char *text, const unsigned char *styles, size_t len) { | |
1679 | int width = 0; | |
1680 | size_t start = 0; | |
1681 | while (start < len) { | |
1682 | size_t style = styles[start]; | |
1683 | size_t endSegment = start; | |
1684 | while ((endSegment+1 < len) && (static_cast<size_t>(styles[endSegment+1]) == style)) | |
1685 | endSegment++; | |
1dcf666d RD |
1686 | width += surface->WidthText(vs.styles[style+styleOffset].font, text + start, |
1687 | static_cast<int>(endSegment - start + 1)); | |
9e96e16f RD |
1688 | start = endSegment + 1; |
1689 | } | |
1690 | return width; | |
1691 | } | |
1692 | ||
1693 | static int WidestLineWidth(Surface *surface, ViewStyle &vs, int styleOffset, const StyledText &st) { | |
1694 | int widthMax = 0; | |
1695 | size_t start = 0; | |
1696 | while (start < st.length) { | |
1697 | size_t lenLine = st.LineLength(start); | |
1698 | int widthSubLine; | |
1699 | if (st.multipleStyles) { | |
1700 | widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine); | |
1701 | } else { | |
1dcf666d RD |
1702 | widthSubLine = surface->WidthText(vs.styles[styleOffset + st.style].font, |
1703 | st.text + start, static_cast<int>(lenLine)); | |
9e96e16f RD |
1704 | } |
1705 | if (widthSubLine > widthMax) | |
1706 | widthMax = widthSubLine; | |
1707 | start += lenLine + 1; | |
1708 | } | |
1709 | return widthMax; | |
1710 | } | |
1711 | ||
1712 | void DrawStyledText(Surface *surface, ViewStyle &vs, int styleOffset, PRectangle rcText, int ascent, | |
1713 | const StyledText &st, size_t start, size_t length) { | |
1714 | ||
1715 | if (st.multipleStyles) { | |
1716 | int x = rcText.left; | |
1717 | size_t i = 0; | |
1718 | while (i < length) { | |
1719 | size_t end = i; | |
1720 | int style = st.styles[i + start]; | |
1721 | while (end < length-1 && st.styles[start+end+1] == style) | |
1722 | end++; | |
1723 | style += styleOffset; | |
1dcf666d RD |
1724 | int width = surface->WidthText(vs.styles[style].font, |
1725 | st.text + start + i, static_cast<int>(end - i + 1)); | |
9e96e16f RD |
1726 | PRectangle rcSegment = rcText; |
1727 | rcSegment.left = x; | |
1728 | rcSegment.right = x + width + 1; | |
1729 | surface->DrawTextNoClip(rcSegment, vs.styles[style].font, | |
1dcf666d RD |
1730 | ascent, st.text + start + i, |
1731 | static_cast<int>(end - i + 1), | |
1732 | vs.styles[style].fore, | |
1733 | vs.styles[style].back); | |
9e96e16f RD |
1734 | x += width; |
1735 | i = end + 1; | |
1736 | } | |
1737 | } else { | |
1dcf666d | 1738 | size_t style = st.style + styleOffset; |
9e96e16f | 1739 | surface->DrawTextNoClip(rcText, vs.styles[style].font, |
1dcf666d RD |
1740 | rcText.top + vs.maxAscent, st.text + start, |
1741 | static_cast<int>(length), | |
1742 | vs.styles[style].fore, | |
1743 | vs.styles[style].back); | |
9e96e16f RD |
1744 | } |
1745 | } | |
1746 | ||
9ce192d4 RD |
1747 | void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { |
1748 | if (vs.fixedColumnWidth == 0) | |
65ec6247 | 1749 | return; |
9ce192d4 RD |
1750 | |
1751 | PRectangle rcMargin = GetClientRectangle(); | |
1752 | rcMargin.right = vs.fixedColumnWidth; | |
1753 | ||
1754 | if (!rc.Intersects(rcMargin)) | |
65ec6247 | 1755 | return; |
9ce192d4 RD |
1756 | |
1757 | Surface *surface; | |
1758 | if (bufferedDraw) { | |
1a2fb4cd | 1759 | surface = pixmapSelMargin; |
9ce192d4 RD |
1760 | } else { |
1761 | surface = surfWindow; | |
1762 | } | |
1763 | ||
1dcf666d RD |
1764 | // Clip vertically to paint area to avoid drawing line numbers |
1765 | if (rcMargin.bottom > rc.bottom) | |
1766 | rcMargin.bottom = rc.bottom; | |
1767 | if (rcMargin.top < rc.top) | |
1768 | rcMargin.top = rc.top; | |
1769 | ||
9ce192d4 RD |
1770 | PRectangle rcSelMargin = rcMargin; |
1771 | rcSelMargin.right = rcMargin.left; | |
1772 | ||
d134f170 | 1773 | for (int margin = 0; margin < vs.margins; margin++) { |
9ce192d4 | 1774 | if (vs.ms[margin].width > 0) { |
d134f170 | 1775 | |
9ce192d4 RD |
1776 | rcSelMargin.left = rcSelMargin.right; |
1777 | rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width; | |
1778 | ||
b8193d80 | 1779 | if (vs.ms[margin].style != SC_MARGIN_NUMBER) { |
9ce192d4 RD |
1780 | if (vs.ms[margin].mask & SC_MASK_FOLDERS) |
1781 | // Required because of special way brush is created for selection margin | |
1a2fb4cd | 1782 | surface->FillRectangle(rcSelMargin, *pixmapSelPattern); |
b8193d80 | 1783 | else { |
1dcf666d | 1784 | ColourDesired colour; |
b8193d80 RD |
1785 | switch (vs.ms[margin].style) { |
1786 | case SC_MARGIN_BACK: | |
1dcf666d | 1787 | colour = vs.styles[STYLE_DEFAULT].back; |
b8193d80 RD |
1788 | break; |
1789 | case SC_MARGIN_FORE: | |
1dcf666d | 1790 | colour = vs.styles[STYLE_DEFAULT].fore; |
b8193d80 RD |
1791 | break; |
1792 | default: | |
1dcf666d | 1793 | colour = vs.styles[STYLE_LINENUMBER].back; |
b8193d80 RD |
1794 | break; |
1795 | } | |
1796 | surface->FillRectangle(rcSelMargin, colour); | |
1797 | } | |
9ce192d4 | 1798 | } else { |
1dcf666d | 1799 | surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back); |
9ce192d4 | 1800 | } |
d134f170 | 1801 | |
1dcf666d RD |
1802 | const int lineStartPaint = rcMargin.top / vs.lineHeight; |
1803 | int visibleLine = topLine + lineStartPaint; | |
1804 | int yposScreen = lineStartPaint * vs.lineHeight; | |
1a2fb4cd | 1805 | // Work out whether the top line is whitespace located after a |
65ec6247 RD |
1806 | // lessening of fold level which implies a 'fold tail' but which should not |
1807 | // be displayed until the last of a sequence of whitespace. | |
1a2fb4cd | 1808 | bool needWhiteClosure = false; |
1dcf666d RD |
1809 | if (vs.ms[margin].mask & SC_MASK_FOLDERS) { |
1810 | int level = pdoc->GetLevel(cs.DocFromDisplay(visibleLine)); | |
1811 | if (level & SC_FOLDLEVELWHITEFLAG) { | |
1812 | int lineBack = cs.DocFromDisplay(visibleLine); | |
1813 | int levelPrev = level; | |
1814 | while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) { | |
1815 | lineBack--; | |
1816 | levelPrev = pdoc->GetLevel(lineBack); | |
1817 | } | |
1818 | if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) { | |
1819 | if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK)) | |
1820 | needWhiteClosure = true; | |
1821 | } | |
65ec6247 | 1822 | } |
1dcf666d RD |
1823 | if (highlightDelimiter.isEnabled) { |
1824 | int lastLine = cs.DocFromDisplay(topLine + LinesOnScreen()) + 1; | |
1825 | pdoc->GetHighlightDelimiters(highlightDelimiter, pdoc->LineFromPosition(CurrentPosition()), lastLine); | |
65ec6247 RD |
1826 | } |
1827 | } | |
1a2fb4cd | 1828 | |
65ec6247 | 1829 | // Old code does not know about new markers needed to distinguish all cases |
1a2fb4cd | 1830 | int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID, |
7e0c58e9 | 1831 | SC_MARKNUM_FOLDEROPEN); |
1a2fb4cd | 1832 | int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND, |
7e0c58e9 | 1833 | SC_MARKNUM_FOLDER); |
1a2fb4cd | 1834 | |
f6bcfd97 | 1835 | while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) { |
65ec6247 | 1836 | |
1a2fb4cd | 1837 | PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed()); |
1a2fb4cd RD |
1838 | int lineDoc = cs.DocFromDisplay(visibleLine); |
1839 | PLATFORM_ASSERT(cs.GetVisible(lineDoc)); | |
1840 | bool firstSubLine = visibleLine == cs.DisplayFromDoc(lineDoc); | |
1dcf666d | 1841 | bool lastSubLine = visibleLine == (cs.DisplayFromDoc(lineDoc + 1) - 1); |
1a2fb4cd | 1842 | |
1a2fb4cd RD |
1843 | int marks = pdoc->GetMark(lineDoc); |
1844 | if (!firstSubLine) | |
1845 | marks = 0; | |
1dcf666d RD |
1846 | |
1847 | bool headWithTail = false; | |
1848 | ||
1849 | if (vs.ms[margin].mask & SC_MASK_FOLDERS) { | |
1850 | // Decide which fold indicator should be displayed | |
1851 | int level = pdoc->GetLevel(lineDoc); | |
1852 | int levelNext = pdoc->GetLevel(lineDoc + 1); | |
1853 | int levelNum = level & SC_FOLDLEVELNUMBERMASK; | |
1854 | int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK; | |
1855 | if (level & SC_FOLDLEVELHEADERFLAG) { | |
1856 | if (firstSubLine) { | |
1857 | if (levelNum < levelNextNum) { | |
1858 | if (cs.GetExpanded(lineDoc)) { | |
1859 | if (levelNum == SC_FOLDLEVELBASE) | |
1860 | marks |= 1 << SC_MARKNUM_FOLDEROPEN; | |
1861 | else | |
1862 | marks |= 1 << folderOpenMid; | |
1863 | } else { | |
1864 | if (levelNum == SC_FOLDLEVELBASE) | |
1865 | marks |= 1 << SC_MARKNUM_FOLDER; | |
1866 | else | |
1867 | marks |= 1 << folderEnd; | |
1868 | } | |
1869 | } else if (levelNum > SC_FOLDLEVELBASE) { | |
1870 | marks |= 1 << SC_MARKNUM_FOLDERSUB; | |
1871 | } | |
1a2fb4cd | 1872 | } else { |
1dcf666d RD |
1873 | if (levelNum < levelNextNum) { |
1874 | if (cs.GetExpanded(lineDoc)) { | |
1875 | marks |= 1 << SC_MARKNUM_FOLDERSUB; | |
1876 | } else if (levelNum > SC_FOLDLEVELBASE) { | |
1877 | marks |= 1 << SC_MARKNUM_FOLDERSUB; | |
1878 | } | |
1879 | } else if (levelNum > SC_FOLDLEVELBASE) { | |
1880 | marks |= 1 << SC_MARKNUM_FOLDERSUB; | |
1881 | } | |
1a2fb4cd | 1882 | } |
1dcf666d RD |
1883 | needWhiteClosure = false; |
1884 | int firstFollowupLine = cs.DocFromDisplay(cs.DisplayFromDoc(lineDoc + 1)); | |
1885 | int firstFollowupLineLevel = pdoc->GetLevel(firstFollowupLine); | |
1886 | int secondFollowupLineLevelNum = pdoc->GetLevel(firstFollowupLine + 1) & SC_FOLDLEVELNUMBERMASK; | |
1887 | if (!cs.GetExpanded(lineDoc)) { | |
1888 | if ((firstFollowupLineLevel & SC_FOLDLEVELWHITEFLAG) && | |
1889 | (levelNum > secondFollowupLineLevelNum)) | |
1890 | needWhiteClosure = true; | |
1891 | ||
1892 | if (highlightDelimiter.IsFoldBlockHighlighted(firstFollowupLine)) | |
1893 | headWithTail = true; | |
1894 | } | |
1895 | } else if (level & SC_FOLDLEVELWHITEFLAG) { | |
1896 | if (needWhiteClosure) { | |
1897 | if (levelNext & SC_FOLDLEVELWHITEFLAG) { | |
1898 | marks |= 1 << SC_MARKNUM_FOLDERSUB; | |
1899 | } else if (levelNextNum > SC_FOLDLEVELBASE) { | |
1900 | marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; | |
1901 | needWhiteClosure = false; | |
1902 | } else { | |
1903 | marks |= 1 << SC_MARKNUM_FOLDERTAIL; | |
1904 | needWhiteClosure = false; | |
1905 | } | |
65ec6247 | 1906 | } else if (levelNum > SC_FOLDLEVELBASE) { |
1dcf666d RD |
1907 | if (levelNextNum < levelNum) { |
1908 | if (levelNextNum > SC_FOLDLEVELBASE) { | |
1909 | marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; | |
1910 | } else { | |
1911 | marks |= 1 << SC_MARKNUM_FOLDERTAIL; | |
1912 | } | |
1913 | } else { | |
1914 | marks |= 1 << SC_MARKNUM_FOLDERSUB; | |
1915 | } | |
65ec6247 RD |
1916 | } |
1917 | } else if (levelNum > SC_FOLDLEVELBASE) { | |
1918 | if (levelNextNum < levelNum) { | |
1dcf666d RD |
1919 | needWhiteClosure = false; |
1920 | if (levelNext & SC_FOLDLEVELWHITEFLAG) { | |
1921 | marks |= 1 << SC_MARKNUM_FOLDERSUB; | |
1922 | needWhiteClosure = true; | |
1923 | } else if (lastSubLine) { | |
1924 | if (levelNextNum > SC_FOLDLEVELBASE) { | |
1925 | marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; | |
1926 | } else { | |
1927 | marks |= 1 << SC_MARKNUM_FOLDERTAIL; | |
1928 | } | |
65ec6247 | 1929 | } else { |
1dcf666d | 1930 | marks |= 1 << SC_MARKNUM_FOLDERSUB; |
65ec6247 RD |
1931 | } |
1932 | } else { | |
1933 | marks |= 1 << SC_MARKNUM_FOLDERSUB; | |
1934 | } | |
1935 | } | |
9ce192d4 | 1936 | } |
65ec6247 | 1937 | |
9ce192d4 | 1938 | marks &= vs.ms[margin].mask; |
1dcf666d | 1939 | |
9ce192d4 RD |
1940 | PRectangle rcMarker = rcSelMargin; |
1941 | rcMarker.top = yposScreen; | |
1942 | rcMarker.bottom = yposScreen + vs.lineHeight; | |
b8193d80 | 1943 | if (vs.ms[margin].style == SC_MARGIN_NUMBER) { |
1dcf666d RD |
1944 | if (firstSubLine) { |
1945 | char number[100]; | |
1a2fb4cd | 1946 | sprintf(number, "%d", lineDoc + 1); |
1dcf666d RD |
1947 | if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) { |
1948 | int lev = pdoc->GetLevel(lineDoc); | |
1949 | sprintf(number, "%c%c %03X %03X", | |
1950 | (lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_', | |
1951 | (lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_', | |
1952 | lev & SC_FOLDLEVELNUMBERMASK, | |
1953 | lev >> 16 | |
1954 | ); | |
1955 | } | |
1956 | PRectangle rcNumber = rcMarker; | |
1957 | // Right justify | |
1958 | XYPOSITION width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, istrlen(number)); | |
1959 | XYPOSITION xpos = rcNumber.right - width - 3; | |
1960 | rcNumber.left = xpos; | |
1961 | surface->DrawTextNoClip(rcNumber, vs.styles[STYLE_LINENUMBER].font, | |
1962 | rcNumber.top + vs.maxAscent, number, istrlen(number), | |
1963 | vs.styles[STYLE_LINENUMBER].fore, | |
1964 | vs.styles[STYLE_LINENUMBER].back); | |
1965 | } else if (wrapVisualFlags & SC_WRAPVISUALFLAG_MARGIN) { | |
1966 | PRectangle rcWrapMarker = rcMarker; | |
1967 | rcWrapMarker.right -= 3; | |
1968 | rcWrapMarker.left = rcWrapMarker.right - vs.styles[STYLE_LINENUMBER].aveCharWidth; | |
1969 | DrawWrapMarker(surface, rcWrapMarker, false, vs.styles[STYLE_LINENUMBER].fore); | |
e14d10b0 | 1970 | } |
9e96e16f RD |
1971 | } else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) { |
1972 | if (firstSubLine) { | |
1973 | const StyledText stMargin = pdoc->MarginStyledText(lineDoc); | |
1974 | if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) { | |
1975 | surface->FillRectangle(rcMarker, | |
1dcf666d | 1976 | vs.styles[stMargin.StyleAt(0)+vs.marginStyleOffset].back); |
9e96e16f RD |
1977 | if (vs.ms[margin].style == SC_MARGIN_RTEXT) { |
1978 | int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin); | |
1979 | rcMarker.left = rcMarker.right - width - 3; | |
1980 | } | |
1981 | DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, rcMarker.top + vs.maxAscent, | |
1982 | stMargin, 0, stMargin.length); | |
1983 | } | |
1984 | } | |
9ce192d4 | 1985 | } |
d134f170 | 1986 | |
9ce192d4 RD |
1987 | if (marks) { |
1988 | for (int markBit = 0; (markBit < 32) && marks; markBit++) { | |
1989 | if (marks & 1) { | |
1dcf666d RD |
1990 | LineMarker::typeOfFold tFold = LineMarker::undefined; |
1991 | if ((vs.ms[margin].mask & SC_MASK_FOLDERS) && highlightDelimiter.IsFoldBlockHighlighted(lineDoc)) { | |
1992 | if (highlightDelimiter.IsBodyOfFoldBlock(lineDoc)) { | |
1993 | tFold = LineMarker::body; | |
1994 | } else if (highlightDelimiter.IsHeadOfFoldBlock(lineDoc)) { | |
1995 | if (firstSubLine) { | |
1996 | tFold = headWithTail ? LineMarker::headWithTail : LineMarker::head; | |
1997 | } else { | |
1998 | if (cs.GetExpanded(lineDoc) || headWithTail) { | |
1999 | tFold = LineMarker::body; | |
2000 | } else { | |
2001 | tFold = LineMarker::undefined; | |
2002 | } | |
2003 | } | |
2004 | } else if (highlightDelimiter.IsTailOfFoldBlock(lineDoc)) { | |
2005 | tFold = LineMarker::tail; | |
2006 | } | |
2007 | } | |
2008 | vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font, tFold, vs.ms[margin].style); | |
9ce192d4 RD |
2009 | } |
2010 | marks >>= 1; | |
2011 | } | |
2012 | } | |
d134f170 | 2013 | |
9ce192d4 | 2014 | visibleLine++; |
9ce192d4 RD |
2015 | yposScreen += vs.lineHeight; |
2016 | } | |
2017 | } | |
2018 | } | |
2019 | ||
2020 | PRectangle rcBlankMargin = rcMargin; | |
2021 | rcBlankMargin.left = rcSelMargin.right; | |
1dcf666d | 2022 | surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back); |
d134f170 | 2023 | |
9ce192d4 | 2024 | if (bufferedDraw) { |
1dcf666d | 2025 | surfWindow->Copy(rcMargin, Point(rcMargin.left, rcMargin.top), *pixmapSelMargin); |
9ce192d4 RD |
2026 | } |
2027 | } | |
2028 | ||
2029 | void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) { | |
2030 | int ydiff = (rcTab.bottom - rcTab.top) / 2; | |
2031 | int xhead = rcTab.right - 1 - ydiff; | |
1a2fb4cd RD |
2032 | if (xhead <= rcTab.left) { |
2033 | ydiff -= rcTab.left - xhead - 1; | |
2034 | xhead = rcTab.left - 1; | |
2035 | } | |
9ce192d4 RD |
2036 | if ((rcTab.left + 2) < (rcTab.right - 1)) |
2037 | surface->MoveTo(rcTab.left + 2, ymid); | |
2038 | else | |
2039 | surface->MoveTo(rcTab.right - 1, ymid); | |
2040 | surface->LineTo(rcTab.right - 1, ymid); | |
2041 | surface->LineTo(xhead, ymid - ydiff); | |
2042 | surface->MoveTo(rcTab.right - 1, ymid); | |
2043 | surface->LineTo(xhead, ymid + ydiff); | |
2044 | } | |
2045 | ||
1a2fb4cd RD |
2046 | LineLayout *Editor::RetrieveLineLayout(int lineNumber) { |
2047 | int posLineStart = pdoc->LineStart(lineNumber); | |
2048 | int posLineEnd = pdoc->LineStart(lineNumber + 1); | |
7e0c58e9 | 2049 | PLATFORM_ASSERT(posLineEnd >= posLineStart); |
9e96e16f | 2050 | int lineCaret = pdoc->LineFromPosition(sel.MainCaret()); |
e4f0b986 | 2051 | return llc.Retrieve(lineNumber, lineCaret, |
7e0c58e9 RD |
2052 | posLineEnd - posLineStart, pdoc->GetStyleClock(), |
2053 | LinesOnScreen() + 1, pdoc->LinesTotal()); | |
2054 | } | |
2055 | ||
7e0c58e9 | 2056 | bool BadUTF(const char *s, int len, int &trailBytes) { |
1dcf666d | 2057 | // For the rules: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 |
7e0c58e9 RD |
2058 | if (trailBytes) { |
2059 | trailBytes--; | |
2060 | return false; | |
2061 | } | |
1dcf666d RD |
2062 | int utf8status = UTF8Classify(reinterpret_cast<const unsigned char *>(s), len); |
2063 | if (utf8status & UTF8MaskInvalid) { | |
7e0c58e9 RD |
2064 | return true; |
2065 | } else { | |
1dcf666d RD |
2066 | trailBytes = (utf8status & UTF8MaskWidth) - 1; |
2067 | return false; | |
7e0c58e9 | 2068 | } |
1a2fb4cd RD |
2069 | } |
2070 | ||
65ec6247 RD |
2071 | /** |
2072 | * Fill in the LineLayout data for the given line. | |
2073 | * Copy the given @a line and its styles from the document into local arrays. | |
2074 | * Also determine the x position at which each character starts. | |
2075 | */ | |
1a2fb4cd RD |
2076 | void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, int width) { |
2077 | if (!ll) | |
2078 | return; | |
7e0c58e9 | 2079 | |
8e54aaed | 2080 | PLATFORM_ASSERT(line < pdoc->LinesTotal()); |
7e0c58e9 | 2081 | PLATFORM_ASSERT(ll->chars != NULL); |
9ce192d4 | 2082 | int posLineStart = pdoc->LineStart(line); |
a834585d RD |
2083 | int posLineEnd = pdoc->LineStart(line + 1); |
2084 | // If the line is very long, limit the treatment to a length that should fit in the viewport | |
2085 | if (posLineEnd > (posLineStart + ll->maxLineLength)) { | |
2086 | posLineEnd = posLineStart + ll->maxLineLength; | |
2087 | } | |
2088 | if (ll->validity == LineLayout::llCheckTextAndStyle) { | |
1e9bafca RD |
2089 | int lineLength = posLineEnd - posLineStart; |
2090 | if (!vstyle.viewEOL) { | |
1dcf666d | 2091 | lineLength = pdoc->LineEnd(line) - posLineStart; |
a834585d RD |
2092 | } |
2093 | if (lineLength == ll->numCharsInLine) { | |
a834585d RD |
2094 | // See if chars, styles, indicators, are all the same |
2095 | bool allSame = true; | |
8e54aaed | 2096 | const int styleMask = pdoc->stylingBitsMask; |
a834585d | 2097 | // Check base line layout |
1e9bafca RD |
2098 | char styleByte = 0; |
2099 | int numCharsInLine = 0; | |
2100 | while (numCharsInLine < lineLength) { | |
2101 | int charInDoc = numCharsInLine + posLineStart; | |
a834585d | 2102 | char chDoc = pdoc->CharAt(charInDoc); |
1e9bafca RD |
2103 | styleByte = pdoc->StyleAt(charInDoc); |
2104 | allSame = allSame && | |
7e0c58e9 | 2105 | (ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte & styleMask)); |
1e9bafca | 2106 | allSame = allSame && |
7e0c58e9 | 2107 | (ll->indicators[numCharsInLine] == static_cast<char>(styleByte & ~styleMask)); |
1e9bafca | 2108 | if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed) |
9e730a78 | 2109 | allSame = allSame && |
7e0c58e9 | 2110 | (ll->chars[numCharsInLine] == chDoc); |
1e9bafca | 2111 | else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower) |
9e730a78 | 2112 | allSame = allSame && |
7e0c58e9 | 2113 | (ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc))); |
1e9bafca RD |
2114 | else // Style::caseUpper |
2115 | allSame = allSame && | |
7e0c58e9 | 2116 | (ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc))); |
1e9bafca | 2117 | numCharsInLine++; |
a834585d | 2118 | } |
1e9bafca | 2119 | allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled |
a834585d RD |
2120 | if (allSame) { |
2121 | ll->validity = LineLayout::llPositions; | |
2122 | } else { | |
2123 | ll->validity = LineLayout::llInvalid; | |
2124 | } | |
2125 | } else { | |
2126 | ll->validity = LineLayout::llInvalid; | |
2127 | } | |
2128 | } | |
1a2fb4cd RD |
2129 | if (ll->validity == LineLayout::llInvalid) { |
2130 | ll->widthLine = LineLayout::wrapWidthInfinite; | |
2131 | ll->lines = 1; | |
1a2fb4cd RD |
2132 | if (vstyle.edgeState == EDGE_BACKGROUND) { |
2133 | ll->edgeColumn = pdoc->FindColumn(line, theEdge); | |
2134 | if (ll->edgeColumn >= posLineStart) { | |
2135 | ll->edgeColumn -= posLineStart; | |
2136 | } | |
2137 | } else { | |
2138 | ll->edgeColumn = -1; | |
2139 | } | |
e4f0b986 | 2140 | |
1dcf666d RD |
2141 | char styleByte; |
2142 | const int styleMask = pdoc->stylingBitsMask; | |
1e9bafca | 2143 | ll->styleBitsSet = 0; |
1a2fb4cd | 2144 | // Fill base line layout |
1dcf666d RD |
2145 | const int lineLength = posLineEnd - posLineStart; |
2146 | pdoc->GetCharRange(ll->chars, posLineStart, lineLength); | |
2147 | pdoc->GetStyleRange(ll->styles, posLineStart, lineLength); | |
2148 | int numCharsBeforeEOL = pdoc->LineEnd(line) - posLineStart; | |
2149 | const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL; | |
2150 | for (int styleInLine = 0; styleInLine < numCharsInLine; styleInLine++) { | |
2151 | styleByte = ll->styles[styleInLine]; | |
1e9bafca | 2152 | ll->styleBitsSet |= styleByte; |
1dcf666d RD |
2153 | ll->styles[styleInLine] = static_cast<char>(styleByte & styleMask); |
2154 | ll->indicators[styleInLine] = static_cast<char>(styleByte & ~styleMask); | |
2155 | } | |
2156 | styleByte = static_cast<char>(((lineLength > 0) ? ll->styles[lineLength-1] : 0) & styleMask); | |
2157 | if (vstyle.someStylesForceCase) { | |
2158 | for (int charInLine = 0; charInLine<lineLength; charInLine++) { | |
2159 | char chDoc = ll->chars[charInLine]; | |
2160 | if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseUpper) | |
2161 | ll->chars[charInLine] = static_cast<char>(toupper(chDoc)); | |
2162 | else if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseLower) | |
2163 | ll->chars[charInLine] = static_cast<char>(tolower(chDoc)); | |
1a2fb4cd RD |
2164 | } |
2165 | } | |
a834585d | 2166 | ll->xHighlightGuide = 0; |
1a2fb4cd RD |
2167 | // Extra element at the end of the line to hold end x position and act as |
2168 | ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character | |
2169 | ll->styles[numCharsInLine] = styleByte; // For eolFilled | |
2170 | ll->indicators[numCharsInLine] = 0; | |
e4f0b986 | 2171 | |
1a2fb4cd RD |
2172 | // Layout the line, determining the position of each character, |
2173 | // with an extra element at the end for the end of the line. | |
2174 | int startseg = 0; // Start of the current segment, in char. number | |
1dcf666d | 2175 | XYACCUMULATOR startsegx = 0; // Start of the current segment, in pixels |
1a2fb4cd | 2176 | ll->positions[0] = 0; |
1dcf666d | 2177 | XYPOSITION tabWidth = vstyle.spaceWidth * pdoc->tabInChars; |
1a2fb4cd | 2178 | bool lastSegItalics = false; |
a834585d | 2179 | Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font; |
e4f0b986 | 2180 | |
1dcf666d | 2181 | XYPOSITION ctrlCharWidth[32] = {0}; |
f114b858 | 2182 | bool isControlNext = IsControlCharacter(ll->chars[0]); |
7e0c58e9 RD |
2183 | int trailBytes = 0; |
2184 | bool isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars, numCharsInLine, trailBytes); | |
1a2fb4cd | 2185 | for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) { |
f114b858 RD |
2186 | bool isControl = isControlNext; |
2187 | isControlNext = IsControlCharacter(ll->chars[charInLine + 1]); | |
7e0c58e9 RD |
2188 | bool isBadUTF = isBadUTFNext; |
2189 | isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes); | |
1a2fb4cd | 2190 | if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) || |
7e0c58e9 | 2191 | isControl || isControlNext || isBadUTF || isBadUTFNext) { |
1a2fb4cd RD |
2192 | ll->positions[startseg] = 0; |
2193 | if (vstyle.styles[ll->styles[charInLine]].visible) { | |
f114b858 | 2194 | if (isControl) { |
1a2fb4cd | 2195 | if (ll->chars[charInLine] == '\t') { |
1dcf666d RD |
2196 | ll->positions[charInLine + 1] = |
2197 | ((static_cast<int>((startsegx + 2) / tabWidth) + 1) * tabWidth) - startsegx; | |
1a2fb4cd | 2198 | } else if (controlCharSymbol < 32) { |
1e9bafca RD |
2199 | if (ctrlCharWidth[ll->chars[charInLine]] == 0) { |
2200 | const char *ctrlChar = ControlCharacterString(ll->chars[charInLine]); | |
2201 | // +3 For a blank on front and rounded edge each side: | |
2202 | ctrlCharWidth[ll->chars[charInLine]] = | |
7e0c58e9 | 2203 | surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + 3; |
1e9bafca RD |
2204 | } |
2205 | ll->positions[charInLine + 1] = ctrlCharWidth[ll->chars[charInLine]]; | |
1a2fb4cd RD |
2206 | } else { |
2207 | char cc[2] = { static_cast<char>(controlCharSymbol), '\0' }; | |
2208 | surface->MeasureWidths(ctrlCharsFont, cc, 1, | |
7e0c58e9 | 2209 | ll->positions + startseg + 1); |
1a2fb4cd RD |
2210 | } |
2211 | lastSegItalics = false; | |
7e0c58e9 | 2212 | } else if (isBadUTF) { |
1dcf666d RD |
2213 | char hexits[4]; |
2214 | sprintf(hexits, "x%2X", ll->chars[charInLine] & 0xff); | |
7e0c58e9 RD |
2215 | ll->positions[charInLine + 1] = |
2216 | surface->WidthText(ctrlCharsFont, hexits, istrlen(hexits)) + 3; | |
1a2fb4cd | 2217 | } else { // Regular character |
1a2fb4cd RD |
2218 | int lenSeg = charInLine - startseg + 1; |
2219 | if ((lenSeg == 1) && (' ' == ll->chars[startseg])) { | |
f114b858 | 2220 | lastSegItalics = false; |
1a2fb4cd RD |
2221 | // Over half the segments are single characters and of these about half are space characters. |
2222 | ll->positions[charInLine + 1] = vstyle.styles[ll->styles[charInLine]].spaceWidth; | |
2223 | } else { | |
f114b858 | 2224 | lastSegItalics = vstyle.styles[ll->styles[charInLine]].italic; |
7e0c58e9 | 2225 | posCache.MeasureWidths(surface, vstyle, ll->styles[charInLine], ll->chars + startseg, |
1dcf666d | 2226 | lenSeg, ll->positions + startseg + 1, pdoc); |
1a2fb4cd | 2227 | } |
d134f170 | 2228 | } |
1a2fb4cd RD |
2229 | } else { // invisible |
2230 | for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) { | |
2231 | ll->positions[posToZero] = 0; | |
d134f170 RD |
2232 | } |
2233 | } | |
1a2fb4cd RD |
2234 | for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) { |
2235 | ll->positions[posToIncrease] += startsegx; | |
9ce192d4 | 2236 | } |
1a2fb4cd RD |
2237 | startsegx = ll->positions[charInLine + 1]; |
2238 | startseg = charInLine + 1; | |
9ce192d4 | 2239 | } |
9ce192d4 | 2240 | } |
1a2fb4cd RD |
2241 | // Small hack to make lines that end with italics not cut off the edge of the last character |
2242 | if ((startseg > 0) && lastSegItalics) { | |
2243 | ll->positions[startseg] += 2; | |
2244 | } | |
2245 | ll->numCharsInLine = numCharsInLine; | |
9e96e16f | 2246 | ll->numCharsBeforeEOL = numCharsBeforeEOL; |
1a2fb4cd RD |
2247 | ll->validity = LineLayout::llPositions; |
2248 | } | |
2249 | // Hard to cope when too narrow, so just assume there is space | |
2250 | if (width < 20) { | |
2251 | width = 20; | |
9ce192d4 | 2252 | } |
1a2fb4cd RD |
2253 | if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) { |
2254 | ll->widthLine = width; | |
2255 | if (width == LineLayout::wrapWidthInfinite) { | |
2256 | ll->lines = 1; | |
a834585d RD |
2257 | } else if (width > ll->positions[ll->numCharsInLine]) { |
2258 | // Simple common case where line does not need wrapping. | |
2259 | ll->lines = 1; | |
1a2fb4cd | 2260 | } else { |
591d01be | 2261 | if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) { |
1dcf666d RD |
2262 | width -= static_cast<int>(vstyle.aveCharWidth); // take into account the space for end wrap mark |
2263 | } | |
2264 | XYPOSITION wrapAddIndent = 0; // This will be added to initial indent of line | |
2265 | if (wrapIndentMode == SC_WRAPINDENT_INDENT) { | |
2266 | wrapAddIndent = pdoc->IndentSize() * vstyle.spaceWidth; | |
2267 | } else if (wrapIndentMode == SC_WRAPINDENT_FIXED) { | |
2268 | wrapAddIndent = wrapVisualStartIndent * vstyle.aveCharWidth; | |
591d01be | 2269 | } |
9e96e16f RD |
2270 | ll->wrapIndent = wrapAddIndent; |
2271 | if (wrapIndentMode != SC_WRAPINDENT_FIXED) | |
2272 | for (int i = 0; i < ll->numCharsInLine; i++) { | |
2273 | if (!IsSpaceOrTab(ll->chars[i])) { | |
2274 | ll->wrapIndent += ll->positions[i]; // Add line indent | |
2275 | break; | |
2276 | } | |
2277 | } | |
2278 | // Check for text width minimum | |
2279 | if (ll->wrapIndent > width - static_cast<int>(vstyle.aveCharWidth) * 15) | |
2280 | ll->wrapIndent = wrapAddIndent; | |
2281 | // Check for wrapIndent minimum | |
1dcf666d | 2282 | if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < vstyle.aveCharWidth)) |
9e96e16f | 2283 | ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual |
1a2fb4cd RD |
2284 | ll->lines = 0; |
2285 | // Calculate line start positions based upon width. | |
1a2fb4cd RD |
2286 | int lastGoodBreak = 0; |
2287 | int lastLineStart = 0; | |
1dcf666d | 2288 | XYACCUMULATOR startOffset = 0; |
9e730a78 | 2289 | int p = 0; |
1a2fb4cd | 2290 | while (p < ll->numCharsInLine) { |
9e730a78 | 2291 | if ((ll->positions[p + 1] - startOffset) >= width) { |
1a2fb4cd RD |
2292 | if (lastGoodBreak == lastLineStart) { |
2293 | // Try moving to start of last character | |
2294 | if (p > 0) { | |
2295 | lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1) | |
7e0c58e9 | 2296 | - posLineStart; |
1a2fb4cd RD |
2297 | } |
2298 | if (lastGoodBreak == lastLineStart) { | |
2299 | // Ensure at least one character on line. | |
9e730a78 | 2300 | lastGoodBreak = pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1) |
7e0c58e9 | 2301 | - posLineStart; |
1a2fb4cd RD |
2302 | } |
2303 | } | |
2304 | lastLineStart = lastGoodBreak; | |
2305 | ll->lines++; | |
2306 | ll->SetLineStart(ll->lines, lastGoodBreak); | |
2307 | startOffset = ll->positions[lastGoodBreak]; | |
591d01be | 2308 | // take into account the space for start wrap mark and indent |
9e96e16f | 2309 | startOffset -= ll->wrapIndent; |
1a2fb4cd RD |
2310 | p = lastGoodBreak + 1; |
2311 | continue; | |
2312 | } | |
2313 | if (p > 0) { | |
b8193d80 | 2314 | if (wrapState == eWrapChar) { |
1e9bafca | 2315 | lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1) |
7e0c58e9 | 2316 | - posLineStart; |
1e9bafca RD |
2317 | p = pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart; |
2318 | continue; | |
2319 | } else if (ll->styles[p] != ll->styles[p - 1]) { | |
1a2fb4cd | 2320 | lastGoodBreak = p; |
9e730a78 | 2321 | } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) { |
1a2fb4cd RD |
2322 | lastGoodBreak = p; |
2323 | } | |
2324 | } | |
2325 | p++; | |
2326 | } | |
2327 | ll->lines++; | |
2328 | } | |
2329 | ll->validity = LineLayout::llLines; | |
65ec6247 | 2330 | } |
9ce192d4 RD |
2331 | } |
2332 | ||
1dcf666d | 2333 | ColourDesired Editor::SelectionBackground(ViewStyle &vsDraw, bool main) { |
9e96e16f | 2334 | return main ? |
1dcf666d RD |
2335 | (primarySelection ? vsDraw.selbackground : vsDraw.selbackground2) : |
2336 | vsDraw.selAdditionalBackground; | |
b8193d80 RD |
2337 | } |
2338 | ||
1dcf666d RD |
2339 | ColourDesired Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground, |
2340 | ColourDesired background, int inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) { | |
9e96e16f | 2341 | if (inSelection == 1) { |
b8193d80 | 2342 | if (vsDraw.selbackset && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { |
9e96e16f RD |
2343 | return SelectionBackground(vsDraw, true); |
2344 | } | |
2345 | } else if (inSelection == 2) { | |
2346 | if (vsDraw.selbackset && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) { | |
2347 | return SelectionBackground(vsDraw, false); | |
9e730a78 RD |
2348 | } |
2349 | } else { | |
2350 | if ((vsDraw.edgeState == EDGE_BACKGROUND) && | |
2351 | (i >= ll->edgeColumn) && | |
1dcf666d RD |
2352 | (i < ll->numCharsBeforeEOL)) |
2353 | return vsDraw.edgecolour; | |
8e54aaed | 2354 | if (inHotspot && vsDraw.hotspotBackgroundSet) |
1dcf666d RD |
2355 | return vsDraw.hotspotBackground; |
2356 | } | |
2357 | if (overrideBackground && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD)) { | |
2358 | return background; | |
2359 | } else { | |
2360 | return vsDraw.styles[styleMain].back; | |
9e730a78 | 2361 | } |
9e730a78 RD |
2362 | } |
2363 | ||
2364 | void Editor::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) { | |
2365 | Point from(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0); | |
2366 | PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom); | |
2367 | surface->Copy(rcCopyArea, from, | |
7e0c58e9 | 2368 | highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide); |
9e730a78 RD |
2369 | } |
2370 | ||
591d01be | 2371 | void Editor::DrawWrapMarker(Surface *surface, PRectangle rcPlace, |
1dcf666d | 2372 | bool isEndMarker, ColourDesired wrapColour) { |
591d01be RD |
2373 | surface->PenColour(wrapColour); |
2374 | ||
2375 | enum { xa = 1 }; // gap before start | |
2376 | int w = rcPlace.right - rcPlace.left - xa - 1; | |
2377 | ||
2378 | bool xStraight = isEndMarker; // x-mirrored symbol for start marker | |
2379 | bool yStraight = true; | |
2380 | //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed | |
2381 | ||
2382 | int x0 = xStraight ? rcPlace.left : rcPlace.right - 1; | |
2383 | int y0 = yStraight ? rcPlace.top : rcPlace.bottom - 1; | |
2384 | ||
2385 | int dy = (rcPlace.bottom - rcPlace.top) / 5; | |
2386 | int y = (rcPlace.bottom - rcPlace.top) / 2 + dy; | |
2387 | ||
2388 | struct Relative { | |
2389 | Surface *surface; | |
2390 | int xBase; | |
2391 | int xDir; | |
2392 | int yBase; | |
2393 | int yDir; | |
2394 | void MoveTo(int xRelative, int yRelative) { | |
7e0c58e9 | 2395 | surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative); |
591d01be RD |
2396 | } |
2397 | void LineTo(int xRelative, int yRelative) { | |
7e0c58e9 | 2398 | surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative); |
591d01be RD |
2399 | } |
2400 | }; | |
b8193d80 | 2401 | Relative rel = {surface, x0, xStraight ? 1 : -1, y0, yStraight ? 1 : -1}; |
591d01be RD |
2402 | |
2403 | // arrow head | |
2404 | rel.MoveTo(xa, y); | |
2405 | rel.LineTo(xa + 2*w / 3, y - dy); | |
2406 | rel.MoveTo(xa, y); | |
2407 | rel.LineTo(xa + 2*w / 3, y + dy); | |
2408 | ||
2409 | // arrow body | |
2410 | rel.MoveTo(xa, y); | |
2411 | rel.LineTo(xa + w, y); | |
2412 | rel.LineTo(xa + w, y - 2 * dy); | |
2413 | rel.LineTo(xa - 1, // on windows lineto is exclusive endpoint, perhaps GTK not... | |
7e0c58e9 | 2414 | y - 2 * dy); |
591d01be RD |
2415 | } |
2416 | ||
1dcf666d | 2417 | static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourDesired fill, int alpha) { |
b8193d80 RD |
2418 | if (alpha != SC_ALPHA_NOALPHA) { |
2419 | surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0); | |
2420 | } | |
2421 | } | |
2422 | ||
9e96e16f | 2423 | void DrawTextBlob(Surface *surface, ViewStyle &vsDraw, PRectangle rcSegment, |
1dcf666d | 2424 | const char *s, ColourDesired textBack, ColourDesired textFore, bool twoPhaseDraw) { |
9e96e16f RD |
2425 | if (!twoPhaseDraw) { |
2426 | surface->FillRectangle(rcSegment, textBack); | |
2427 | } | |
2428 | Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; | |
2429 | int normalCharHeight = surface->Ascent(ctrlCharsFont) - | |
2430 | surface->InternalLeading(ctrlCharsFont); | |
2431 | PRectangle rcCChar = rcSegment; | |
2432 | rcCChar.left = rcCChar.left + 1; | |
2433 | rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight; | |
2434 | rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1; | |
2435 | PRectangle rcCentral = rcCChar; | |
2436 | rcCentral.top++; | |
2437 | rcCentral.bottom--; | |
2438 | surface->FillRectangle(rcCentral, textFore); | |
2439 | PRectangle rcChar = rcCChar; | |
2440 | rcChar.left++; | |
2441 | rcChar.right--; | |
2442 | surface->DrawTextClipped(rcChar, ctrlCharsFont, | |
2443 | rcSegment.top + vsDraw.maxAscent, s, istrlen(s), | |
2444 | textBack, textFore); | |
2445 | } | |
2446 | ||
9e730a78 | 2447 | void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll, |
1dcf666d RD |
2448 | int line, int lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, |
2449 | bool overrideBackground, ColourDesired background, | |
2450 | bool drawWrapMarkEnd, ColourDesired wrapColour) { | |
9e730a78 | 2451 | |
9e96e16f RD |
2452 | const int posLineStart = pdoc->LineStart(line); |
2453 | const int styleMask = pdoc->stylingBitsMask; | |
9e730a78 RD |
2454 | PRectangle rcSegment = rcLine; |
2455 | ||
9e96e16f | 2456 | const bool lastSubLine = subLine == (ll->lines - 1); |
1dcf666d | 2457 | XYPOSITION virtualSpace = 0; |
9e96e16f | 2458 | if (lastSubLine) { |
1dcf666d | 2459 | const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; |
9e96e16f RD |
2460 | virtualSpace = sel.VirtualSpaceFor(pdoc->LineEnd(line)) * spaceWidth; |
2461 | } | |
1dcf666d | 2462 | XYPOSITION xEol = ll->positions[lineEnd] - subLineStart; |
591d01be | 2463 | |
9e96e16f RD |
2464 | // Fill the virtual space and show selections within it |
2465 | if (virtualSpace) { | |
2466 | rcSegment.left = xEol + xStart; | |
2467 | rcSegment.right = xEol + xStart + virtualSpace; | |
1dcf666d | 2468 | surface->FillRectangle(rcSegment, overrideBackground ? background : vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back); |
9e96e16f RD |
2469 | if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) { |
2470 | SelectionSegment virtualSpaceRange(SelectionPosition(pdoc->LineEnd(line)), SelectionPosition(pdoc->LineEnd(line), sel.VirtualSpaceFor(pdoc->LineEnd(line)))); | |
2471 | for (size_t r=0; r<sel.Count(); r++) { | |
2472 | int alpha = (r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; | |
2473 | if (alpha == SC_ALPHA_NOALPHA) { | |
2474 | SelectionSegment portion = sel.Range(r).Intersect(virtualSpaceRange); | |
2475 | if (!portion.Empty()) { | |
1dcf666d | 2476 | const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; |
9e96e16f RD |
2477 | rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth; |
2478 | rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * spaceWidth; | |
1dcf666d RD |
2479 | rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; |
2480 | rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; | |
9e96e16f RD |
2481 | surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == sel.Main())); |
2482 | } | |
2483 | } | |
2484 | } | |
2485 | } | |
2486 | } | |
2487 | ||
1dcf666d RD |
2488 | int eolInSelection = 0; |
2489 | int alpha = SC_ALPHA_NOALPHA; | |
2490 | if (!hideSelection) { | |
2491 | int posAfterLineEnd = pdoc->LineStart(line + 1); | |
2492 | eolInSelection = (subLine == (ll->lines - 1)) ? sel.InSelectionForEOL(posAfterLineEnd) : 0; | |
2493 | alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; | |
2494 | } | |
9e96e16f RD |
2495 | |
2496 | // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on | |
1dcf666d | 2497 | XYPOSITION blobsWidth = 0; |
9e96e16f RD |
2498 | if (lastSubLine) { |
2499 | for (int eolPos=ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine; eolPos++) { | |
2500 | rcSegment.left = xStart + ll->positions[eolPos] - subLineStart + virtualSpace; | |
2501 | rcSegment.right = xStart + ll->positions[eolPos+1] - subLineStart + virtualSpace; | |
2502 | blobsWidth += rcSegment.Width(); | |
2503 | const char *ctrlChar = ControlCharacterString(ll->chars[eolPos]); | |
9e96e16f | 2504 | int styleMain = ll->styles[eolPos]; |
1dcf666d RD |
2505 | ColourDesired textBack = TextBackground(vsDraw, overrideBackground, background, eolInSelection, false, styleMain, eolPos, ll); |
2506 | ColourDesired textFore = vsDraw.styles[styleMain].fore; | |
2507 | if (eolInSelection && vsDraw.selforeset) { | |
2508 | textFore = (eolInSelection == 1) ? vsDraw.selforeground : vsDraw.selAdditionalForeground; | |
2509 | } | |
2510 | if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1)) { | |
9e96e16f RD |
2511 | if (alpha == SC_ALPHA_NOALPHA) { |
2512 | surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); | |
2513 | } else { | |
2514 | surface->FillRectangle(rcSegment, textBack); | |
9e96e16f RD |
2515 | } |
2516 | } else { | |
2517 | surface->FillRectangle(rcSegment, textBack); | |
2518 | } | |
2519 | DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw); | |
1dcf666d RD |
2520 | if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { |
2521 | SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); | |
2522 | } | |
9e96e16f RD |
2523 | } |
2524 | } | |
2525 | ||
2526 | // Draw the eol-is-selected rectangle | |
2527 | rcSegment.left = xEol + xStart + virtualSpace + blobsWidth; | |
1dcf666d | 2528 | rcSegment.right = rcSegment.left + vsDraw.aveCharWidth; |
9e96e16f | 2529 | |
1dcf666d | 2530 | if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { |
9e96e16f | 2531 | surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); |
9e730a78 | 2532 | } else { |
b8193d80 RD |
2533 | if (overrideBackground) { |
2534 | surface->FillRectangle(rcSegment, background); | |
9e96e16f | 2535 | } else if (line < pdoc->LinesTotal() - 1) { |
1dcf666d | 2536 | surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back); |
9e96e16f | 2537 | } else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) { |
1dcf666d | 2538 | surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back); |
9e96e16f | 2539 | } else { |
1dcf666d | 2540 | surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); |
b8193d80 | 2541 | } |
1dcf666d | 2542 | if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { |
9e96e16f | 2543 | SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); |
b8193d80 | 2544 | } |
9e730a78 RD |
2545 | } |
2546 | ||
9e96e16f | 2547 | // Fill the remainder of the line |
1dcf666d RD |
2548 | rcSegment.left = rcSegment.right; |
2549 | if (rcSegment.left < rcLine.left) | |
2550 | rcSegment.left = rcLine.left; | |
9e730a78 | 2551 | rcSegment.right = rcLine.right; |
591d01be | 2552 | |
1dcf666d | 2553 | if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { |
9e96e16f | 2554 | surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); |
7e0c58e9 RD |
2555 | } else { |
2556 | if (overrideBackground) { | |
2557 | surface->FillRectangle(rcSegment, background); | |
2558 | } else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) { | |
1dcf666d | 2559 | surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back); |
7e0c58e9 | 2560 | } else { |
1dcf666d | 2561 | surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); |
7e0c58e9 | 2562 | } |
1dcf666d | 2563 | if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { |
9e96e16f | 2564 | SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); |
7e0c58e9 RD |
2565 | } |
2566 | } | |
2567 | ||
591d01be RD |
2568 | if (drawWrapMarkEnd) { |
2569 | PRectangle rcPlace = rcSegment; | |
2570 | ||
2571 | if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) { | |
9e96e16f | 2572 | rcPlace.left = xEol + xStart + virtualSpace; |
591d01be RD |
2573 | rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; |
2574 | } else { | |
1dcf666d RD |
2575 | // rcLine is clipped to text area |
2576 | rcPlace.right = rcLine.right; | |
591d01be RD |
2577 | rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; |
2578 | } | |
2579 | DrawWrapMarker(surface, rcPlace, true, wrapColour); | |
2580 | } | |
9e730a78 RD |
2581 | } |
2582 | ||
1dcf666d RD |
2583 | void Editor::DrawIndicator(int indicNum, int startPos, int endPos, Surface *surface, ViewStyle &vsDraw, |
2584 | int xStart, PRectangle rcLine, LineLayout *ll, int subLine) { | |
2585 | const XYPOSITION subLineStart = ll->positions[ll->LineStart(subLine)]; | |
2586 | PRectangle rcIndic( | |
2587 | ll->positions[startPos] + xStart - subLineStart, | |
2588 | rcLine.top + vsDraw.maxAscent, | |
2589 | ll->positions[endPos] + xStart - subLineStart, | |
2590 | rcLine.top + vsDraw.maxAscent + 3); | |
2591 | vsDraw.indicators[indicNum].Draw(surface, rcIndic, rcLine); | |
2592 | } | |
2593 | ||
7e0c58e9 RD |
2594 | void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart, |
2595 | PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under) { | |
2596 | // Draw decorators | |
2597 | const int posLineStart = pdoc->LineStart(line); | |
2598 | const int lineStart = ll->LineStart(subLine); | |
7e0c58e9 RD |
2599 | const int posLineEnd = posLineStart + lineEnd; |
2600 | ||
2601 | if (!under) { | |
2602 | // Draw indicators | |
2603 | // foreach indicator... | |
2604 | for (int indicnum = 0, mask = 1 << pdoc->stylingBits; mask < 0x100; indicnum++) { | |
2605 | if (!(mask & ll->styleBitsSet)) { | |
2606 | mask <<= 1; | |
2607 | continue; | |
2608 | } | |
2609 | int startPos = -1; | |
2610 | // foreach style pos in line... | |
2611 | for (int indicPos = lineStart; indicPos <= lineEnd; indicPos++) { | |
2612 | // look for starts... | |
2613 | if (startPos < 0) { | |
2614 | // NOT in indicator run, looking for START | |
2615 | if (indicPos < lineEnd && (ll->indicators[indicPos] & mask)) | |
2616 | startPos = indicPos; | |
2617 | } | |
2618 | // ... or ends | |
2619 | if (startPos >= 0) { | |
2620 | // IN indicator run, looking for END | |
2621 | if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) { | |
2622 | // AT end of indicator run, DRAW it! | |
1dcf666d | 2623 | DrawIndicator(indicnum, startPos, indicPos, surface, vsDraw, xStart, rcLine, ll, subLine); |
7e0c58e9 RD |
2624 | // RESET control var |
2625 | startPos = -1; | |
2626 | } | |
2627 | } | |
2628 | } | |
2629 | mask <<= 1; | |
2630 | } | |
2631 | } | |
2632 | ||
2633 | for (Decoration *deco = pdoc->decorations.root; deco; deco = deco->next) { | |
2634 | if (under == vsDraw.indicators[deco->indicator].under) { | |
2635 | int startPos = posLineStart + lineStart; | |
2636 | if (!deco->rs.ValueAt(startPos)) { | |
2637 | startPos = deco->rs.EndRun(startPos); | |
2638 | } | |
2639 | while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) { | |
2640 | int endPos = deco->rs.EndRun(startPos); | |
2641 | if (endPos > posLineEnd) | |
2642 | endPos = posLineEnd; | |
1dcf666d RD |
2643 | DrawIndicator(deco->indicator, startPos - posLineStart, endPos - posLineStart, |
2644 | surface, vsDraw, xStart, rcLine, ll, subLine); | |
7e0c58e9 RD |
2645 | startPos = deco->rs.EndRun(endPos); |
2646 | } | |
2647 | } | |
2648 | } | |
1dcf666d RD |
2649 | |
2650 | // Use indicators to highlight matching braces | |
2651 | if ((vs.braceHighlightIndicatorSet && (bracesMatchStyle == STYLE_BRACELIGHT)) || | |
2652 | (vs.braceBadLightIndicatorSet && (bracesMatchStyle == STYLE_BRACEBAD))) { | |
2653 | int braceIndicator = (bracesMatchStyle == STYLE_BRACELIGHT) ? vs.braceHighlightIndicator : vs.braceBadLightIndicator; | |
2654 | if (under == vsDraw.indicators[braceIndicator].under) { | |
2655 | Range rangeLine(posLineStart + lineStart, posLineEnd); | |
2656 | if (rangeLine.ContainsCharacter(braces[0])) { | |
2657 | int braceOffset = braces[0] - posLineStart; | |
2658 | if (braceOffset < ll->numCharsInLine) { | |
2659 | DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, xStart, rcLine, ll, subLine); | |
2660 | } | |
2661 | } | |
2662 | if (rangeLine.ContainsCharacter(braces[1])) { | |
2663 | int braceOffset = braces[1] - posLineStart; | |
2664 | if (braceOffset < ll->numCharsInLine) { | |
2665 | DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, xStart, rcLine, ll, subLine); | |
2666 | } | |
2667 | } | |
2668 | } | |
2669 | } | |
7e0c58e9 RD |
2670 | } |
2671 | ||
9e96e16f RD |
2672 | void Editor::DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart, |
2673 | PRectangle rcLine, LineLayout *ll, int subLine) { | |
2674 | int indent = pdoc->GetLineIndentation(line) * vsDraw.spaceWidth; | |
2675 | PRectangle rcSegment = rcLine; | |
2676 | int annotationLine = subLine - ll->lines; | |
2677 | const StyledText stAnnotation = pdoc->AnnotationStyledText(line); | |
2678 | if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) { | |
1dcf666d | 2679 | surface->FillRectangle(rcSegment, vsDraw.styles[0].back); |
9e96e16f RD |
2680 | if (vs.annotationVisible == ANNOTATION_BOXED) { |
2681 | // Only care about calculating width if need to draw box | |
2682 | int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation); | |
2683 | widthAnnotation += vsDraw.spaceWidth * 2; // Margins | |
2684 | rcSegment.left = xStart + indent; | |
2685 | rcSegment.right = rcSegment.left + widthAnnotation; | |
9e96e16f RD |
2686 | } else { |
2687 | rcSegment.left = xStart; | |
2688 | } | |
2689 | const int annotationLines = pdoc->AnnotationLines(line); | |
2690 | size_t start = 0; | |
2691 | size_t lengthAnnotation = stAnnotation.LineLength(start); | |
2692 | int lineInAnnotation = 0; | |
2693 | while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) { | |
2694 | start += lengthAnnotation + 1; | |
2695 | lengthAnnotation = stAnnotation.LineLength(start); | |
2696 | lineInAnnotation++; | |
2697 | } | |
2698 | PRectangle rcText = rcSegment; | |
2699 | if (vs.annotationVisible == ANNOTATION_BOXED) { | |
2700 | surface->FillRectangle(rcText, | |
1dcf666d | 2701 | vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back); |
9e96e16f RD |
2702 | rcText.left += vsDraw.spaceWidth; |
2703 | } | |
2704 | DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, rcText.top + vsDraw.maxAscent, | |
2705 | stAnnotation, start, lengthAnnotation); | |
2706 | if (vs.annotationVisible == ANNOTATION_BOXED) { | |
1dcf666d | 2707 | surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore); |
9e96e16f RD |
2708 | surface->MoveTo(rcSegment.left, rcSegment.top); |
2709 | surface->LineTo(rcSegment.left, rcSegment.bottom); | |
2710 | surface->MoveTo(rcSegment.right, rcSegment.top); | |
2711 | surface->LineTo(rcSegment.right, rcSegment.bottom); | |
1dcf666d | 2712 | if (subLine == ll->lines) { |
9e96e16f RD |
2713 | surface->MoveTo(rcSegment.left, rcSegment.top); |
2714 | surface->LineTo(rcSegment.right, rcSegment.top); | |
2715 | } | |
2716 | if (subLine == ll->lines+annotationLines-1) { | |
2717 | surface->MoveTo(rcSegment.left, rcSegment.bottom - 1); | |
2718 | surface->LineTo(rcSegment.right, rcSegment.bottom - 1); | |
2719 | } | |
2720 | } | |
7e0c58e9 | 2721 | } |
7e0c58e9 RD |
2722 | } |
2723 | ||
d134f170 | 2724 | void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart, |
7e0c58e9 | 2725 | PRectangle rcLine, LineLayout *ll, int subLine) { |
d134f170 | 2726 | |
9ce192d4 | 2727 | PRectangle rcSegment = rcLine; |
d134f170 | 2728 | |
9ce192d4 RD |
2729 | // Using one font for all control characters so it can be controlled independently to ensure |
2730 | // the box goes around the characters tightly. Seems to be no way to work out what height | |
2731 | // is taken by an individual character - internal leading gives varying results. | |
2732 | Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; | |
2733 | ||
1a2fb4cd RD |
2734 | // See if something overrides the line background color: Either if caret is on the line |
2735 | // and background color is set for that, or if a marker is defined that forces its background | |
2736 | // color onto the line, or if a marker is defined but has no selection margin in which to | |
a33203cb RD |
2737 | // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order |
2738 | // with the earlier taking precedence. When multiple markers cause background override, | |
2739 | // the color for the highest numbered one is used. | |
65ec6247 | 2740 | bool overrideBackground = false; |
1dcf666d | 2741 | ColourDesired background; |
b8193d80 | 2742 | if (caret.active && vsDraw.showCaretLineBackground && (vsDraw.caretLineAlpha == SC_ALPHA_NOALPHA) && ll->containsCaret) { |
65ec6247 | 2743 | overrideBackground = true; |
1dcf666d | 2744 | background = vsDraw.caretLineBackground; |
65ec6247 | 2745 | } |
1a2fb4cd RD |
2746 | if (!overrideBackground) { |
2747 | int marks = pdoc->GetMark(line); | |
2748 | for (int markBit = 0; (markBit < 32) && marks; markBit++) { | |
b8193d80 | 2749 | if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) && |
7e0c58e9 | 2750 | (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) { |
1dcf666d | 2751 | background = vsDraw.markers[markBit].back; |
1a2fb4cd RD |
2752 | overrideBackground = true; |
2753 | } | |
2754 | marks >>= 1; | |
2755 | } | |
2756 | } | |
2757 | if (!overrideBackground) { | |
2758 | if (vsDraw.maskInLine) { | |
b8193d80 RD |
2759 | int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine; |
2760 | if (marksMasked) { | |
2761 | for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) { | |
2762 | if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY) && | |
7e0c58e9 | 2763 | (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) { |
a33203cb | 2764 | overrideBackground = true; |
1dcf666d | 2765 | background = vsDraw.markers[markBit].back; |
1a2fb4cd | 2766 | } |
b8193d80 | 2767 | marksMasked >>= 1; |
9ce192d4 | 2768 | } |
9ce192d4 RD |
2769 | } |
2770 | } | |
9ce192d4 RD |
2771 | } |
2772 | ||
9e730a78 | 2773 | bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) && |
7e0c58e9 | 2774 | (!overrideBackground) && (vsDraw.whitespaceBackgroundSet); |
9e730a78 | 2775 | |
1a2fb4cd | 2776 | bool inIndentation = subLine == 0; // Do not handle indentation except on first subline. |
1dcf666d RD |
2777 | const XYPOSITION indentWidth = pdoc->IndentSize() * vsDraw.spaceWidth; |
2778 | const XYPOSITION epsilon = 0.0001f; // A small nudge to avoid floating point precision issues | |
d134f170 | 2779 | |
9ce192d4 | 2780 | int posLineStart = pdoc->LineStart(line); |
9ce192d4 | 2781 | |
1a2fb4cd | 2782 | int startseg = ll->LineStart(subLine); |
1dcf666d | 2783 | XYACCUMULATOR subLineStart = ll->positions[startseg]; |
9e96e16f RD |
2784 | if (subLine >= ll->lines) { |
2785 | DrawAnnotation(surface, vsDraw, line, xStart, rcLine, ll, subLine); | |
2786 | return; // No further drawing | |
2787 | } | |
1a2fb4cd RD |
2788 | int lineStart = 0; |
2789 | int lineEnd = 0; | |
2790 | if (subLine < ll->lines) { | |
2791 | lineStart = ll->LineStart(subLine); | |
9e730a78 | 2792 | lineEnd = ll->LineStart(subLine + 1); |
9e96e16f RD |
2793 | if (subLine == ll->lines - 1) { |
2794 | lineEnd = ll->numCharsBeforeEOL; | |
2795 | } | |
9e730a78 | 2796 | } |
591d01be | 2797 | |
1dcf666d | 2798 | ColourDesired wrapColour = vsDraw.styles[STYLE_DEFAULT].fore; |
7e0c58e9 | 2799 | if (vsDraw.whitespaceForegroundSet) |
1dcf666d | 2800 | wrapColour = vsDraw.whitespaceForeground; |
7e0c58e9 | 2801 | |
591d01be RD |
2802 | bool drawWrapMarkEnd = false; |
2803 | ||
2804 | if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) { | |
2805 | if (subLine + 1 < ll->lines) { | |
2806 | drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0; | |
2807 | } | |
2808 | } | |
2809 | ||
9e96e16f | 2810 | if (ll->wrapIndent != 0) { |
591d01be RD |
2811 | |
2812 | bool continuedWrapLine = false; | |
2813 | if (subLine < ll->lines) { | |
2814 | continuedWrapLine = ll->LineStart(subLine) != 0; | |
2815 | } | |
2816 | ||
2817 | if (continuedWrapLine) { | |
2818 | // draw continuation rect | |
2819 | PRectangle rcPlace = rcSegment; | |
2820 | ||
2821 | rcPlace.left = ll->positions[startseg] + xStart - subLineStart; | |
9e96e16f | 2822 | rcPlace.right = rcPlace.left + ll->wrapIndent; |
591d01be RD |
2823 | |
2824 | // default bgnd here.. | |
7e0c58e9 | 2825 | surface->FillRectangle(rcSegment, overrideBackground ? background : |
1dcf666d | 2826 | vsDraw.styles[STYLE_DEFAULT].back); |
591d01be RD |
2827 | |
2828 | // main line style would be below but this would be inconsistent with end markers | |
2829 | // also would possibly not be the style at wrap point | |
2830 | //int styleMain = ll->styles[lineStart]; | |
1dcf666d | 2831 | //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back); |
591d01be RD |
2832 | |
2833 | if (wrapVisualFlags & SC_WRAPVISUALFLAG_START) { | |
2834 | ||
2835 | if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT) | |
2836 | rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; | |
2837 | else | |
2838 | rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; | |
2839 | ||
7e0c58e9 | 2840 | DrawWrapMarker(surface, rcPlace, false, wrapColour); |
591d01be RD |
2841 | } |
2842 | ||
1dcf666d | 2843 | xStart += static_cast<int>(ll->wrapIndent); |
591d01be RD |
2844 | } |
2845 | } | |
2846 | ||
9e96e16f RD |
2847 | bool selBackDrawn = vsDraw.selbackset && |
2848 | ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)); | |
2849 | ||
7e0c58e9 | 2850 | // Does not take margin into account but not significant |
1dcf666d | 2851 | int xStartVisible = static_cast<int>(subLineStart) - xStart; |
7e0c58e9 | 2852 | |
9e96e16f RD |
2853 | ll->psel = &sel; |
2854 | ||
1dcf666d | 2855 | BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, xStartVisible, selBackDrawn, pdoc); |
7e0c58e9 | 2856 | int next = bfBack.First(); |
9e730a78 RD |
2857 | |
2858 | // Background drawing loop | |
7e0c58e9 | 2859 | while (twoPhaseDraw && (next < lineEnd)) { |
9e730a78 | 2860 | |
7e0c58e9 RD |
2861 | startseg = next; |
2862 | next = bfBack.Next(); | |
2863 | int i = next - 1; | |
9e730a78 | 2864 | int iDoc = i + posLineStart; |
7e0c58e9 RD |
2865 | |
2866 | rcSegment.left = ll->positions[startseg] + xStart - subLineStart; | |
2867 | rcSegment.right = ll->positions[i + 1] + xStart - subLineStart; | |
2868 | // Only try to draw if really visible - enhances performance by not calling environment to | |
2869 | // draw strings that are completely past the right side of the window. | |
2870 | if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) { | |
2871 | // Clip to line rectangle, since may have a huge position which will not work with some platforms | |
1dcf666d RD |
2872 | if (rcSegment.left < rcLine.left) |
2873 | rcSegment.left = rcLine.left; | |
2874 | if (rcSegment.right > rcLine.right) | |
2875 | rcSegment.right = rcLine.right; | |
7e0c58e9 RD |
2876 | |
2877 | int styleMain = ll->styles[i]; | |
9e96e16f | 2878 | const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc); |
7e0c58e9 | 2879 | bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd); |
1dcf666d | 2880 | ColourDesired textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll); |
7e0c58e9 RD |
2881 | if (ll->chars[i] == '\t') { |
2882 | // Tab display | |
2883 | if (drawWhitespaceBackground && | |
2884 | (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) | |
1dcf666d | 2885 | textBack = vsDraw.whitespaceBackground; |
7e0c58e9 RD |
2886 | surface->FillRectangle(rcSegment, textBack); |
2887 | } else if (IsControlCharacter(ll->chars[i])) { | |
2888 | // Control character display | |
2889 | inIndentation = false; | |
2890 | surface->FillRectangle(rcSegment, textBack); | |
2891 | } else { | |
2892 | // Normal text display | |
2893 | surface->FillRectangle(rcSegment, textBack); | |
2894 | if (vsDraw.viewWhitespace != wsInvisible || | |
2895 | (inIndentation && vsDraw.viewIndentationGuides == ivReal)) { | |
2896 | for (int cpos = 0; cpos <= i - startseg; cpos++) { | |
2897 | if (ll->chars[cpos + startseg] == ' ') { | |
2898 | if (drawWhitespaceBackground && | |
2899 | (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { | |
9e96e16f RD |
2900 | PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart, |
2901 | rcSegment.top, | |
2902 | ll->positions[cpos + startseg + 1] + xStart - subLineStart, | |
2903 | rcSegment.bottom); | |
1dcf666d | 2904 | surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground); |
9e730a78 | 2905 | } |
7e0c58e9 RD |
2906 | } else { |
2907 | inIndentation = false; | |
9e730a78 RD |
2908 | } |
2909 | } | |
2910 | } | |
2911 | } | |
7e0c58e9 RD |
2912 | } else if (rcSegment.left > rcLine.right) { |
2913 | break; | |
9e730a78 | 2914 | } |
1a2fb4cd | 2915 | } |
9e730a78 RD |
2916 | |
2917 | if (twoPhaseDraw) { | |
2918 | DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd, | |
591d01be | 2919 | xStart, subLine, subLineStart, overrideBackground, background, |
7e0c58e9 RD |
2920 | drawWrapMarkEnd, wrapColour); |
2921 | } | |
2922 | ||
2923 | DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, true); | |
2924 | ||
2925 | if (vsDraw.edgeState == EDGE_LINE) { | |
2926 | int edgeX = theEdge * vsDraw.spaceWidth; | |
2927 | rcSegment.left = edgeX + xStart; | |
1dcf666d RD |
2928 | if ((ll->wrapIndent != 0) && (lineStart != 0)) |
2929 | rcSegment.left -= ll->wrapIndent; | |
7e0c58e9 | 2930 | rcSegment.right = rcSegment.left + 1; |
1dcf666d | 2931 | surface->FillRectangle(rcSegment, vsDraw.edgecolour); |
9e730a78 RD |
2932 | } |
2933 | ||
9e96e16f RD |
2934 | // Draw underline mark as part of background if not transparent |
2935 | int marks = pdoc->GetMark(line); | |
2936 | int markBit; | |
2937 | for (markBit = 0; (markBit < 32) && marks; markBit++) { | |
2938 | if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) && | |
2939 | (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) { | |
2940 | PRectangle rcUnderline = rcLine; | |
2941 | rcUnderline.top = rcUnderline.bottom - 2; | |
1dcf666d | 2942 | surface->FillRectangle(rcUnderline, vsDraw.markers[markBit].back); |
9e96e16f RD |
2943 | } |
2944 | marks >>= 1; | |
2945 | } | |
2946 | ||
9e730a78 | 2947 | inIndentation = subLine == 0; // Do not handle indentation except on first subline. |
9e730a78 | 2948 | // Foreground drawing loop |
1dcf666d RD |
2949 | BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, xStartVisible, |
2950 | ((!twoPhaseDraw && selBackDrawn) || vsDraw.selforeset), pdoc); | |
7e0c58e9 RD |
2951 | next = bfFore.First(); |
2952 | ||
2953 | while (next < lineEnd) { | |
2954 | ||
2955 | startseg = next; | |
2956 | next = bfFore.Next(); | |
2957 | int i = next - 1; | |
9ce192d4 RD |
2958 | |
2959 | int iDoc = i + posLineStart; | |
7e0c58e9 RD |
2960 | |
2961 | rcSegment.left = ll->positions[startseg] + xStart - subLineStart; | |
2962 | rcSegment.right = ll->positions[i + 1] + xStart - subLineStart; | |
2963 | // Only try to draw if really visible - enhances performance by not calling environment to | |
2964 | // draw strings that are completely past the right side of the window. | |
2965 | if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) { | |
2966 | int styleMain = ll->styles[i]; | |
1dcf666d | 2967 | ColourDesired textFore = vsDraw.styles[styleMain].fore; |
7e0c58e9 RD |
2968 | Font &textFont = vsDraw.styles[styleMain].font; |
2969 | //hotspot foreground | |
2970 | if (ll->hsStart != -1 && iDoc >= ll->hsStart && iDoc < hsEnd) { | |
2971 | if (vsDraw.hotspotForegroundSet) | |
1dcf666d | 2972 | textFore = vsDraw.hotspotForeground; |
7e0c58e9 | 2973 | } |
9e96e16f | 2974 | const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc); |
7e0c58e9 | 2975 | if (inSelection && (vsDraw.selforeset)) { |
1dcf666d | 2976 | textFore = (inSelection == 1) ? vsDraw.selforeground : vsDraw.selAdditionalForeground; |
7e0c58e9 RD |
2977 | } |
2978 | bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd); | |
1dcf666d | 2979 | ColourDesired textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll); |
7e0c58e9 RD |
2980 | if (ll->chars[i] == '\t') { |
2981 | // Tab display | |
2982 | if (!twoPhaseDraw) { | |
2983 | if (drawWhitespaceBackground && | |
2984 | (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) | |
1dcf666d | 2985 | textBack = vsDraw.whitespaceBackground; |
7e0c58e9 | 2986 | surface->FillRectangle(rcSegment, textBack); |
9e730a78 | 2987 | } |
7e0c58e9 RD |
2988 | if ((vsDraw.viewWhitespace != wsInvisible) || |
2989 | (inIndentation && vsDraw.viewIndentationGuides != ivNone)) { | |
2990 | if (vsDraw.whitespaceForegroundSet) | |
1dcf666d | 2991 | textFore = vsDraw.whitespaceForeground; |
7e0c58e9 | 2992 | surface->PenColour(textFore); |
9ce192d4 | 2993 | } |
7e0c58e9 | 2994 | if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { |
1dcf666d RD |
2995 | for (int indentCount = (ll->positions[i] + epsilon) / indentWidth; |
2996 | indentCount <= (ll->positions[i + 1] - epsilon) / indentWidth; | |
2997 | indentCount++) { | |
2998 | if (indentCount > 0) { | |
2999 | int xIndent = indentCount * indentWidth; | |
3000 | DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, | |
3001 | (ll->xHighlightGuide == xIndent)); | |
1a2fb4cd | 3002 | } |
d134f170 | 3003 | } |
7e0c58e9 RD |
3004 | } |
3005 | if (vsDraw.viewWhitespace != wsInvisible) { | |
3006 | if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { | |
3007 | PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4, | |
3008 | rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent); | |
3009 | DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2); | |
1a2fb4cd | 3010 | } |
7e0c58e9 RD |
3011 | } |
3012 | } else if (IsControlCharacter(ll->chars[i])) { | |
3013 | // Control character display | |
3014 | inIndentation = false; | |
3015 | if (controlCharSymbol < 32) { | |
3016 | // Draw the character | |
3017 | const char *ctrlChar = ControlCharacterString(ll->chars[i]); | |
3018 | DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw); | |
1a2fb4cd | 3019 | } else { |
7e0c58e9 RD |
3020 | char cc[2] = { static_cast<char>(controlCharSymbol), '\0' }; |
3021 | surface->DrawTextNoClip(rcSegment, ctrlCharsFont, | |
3022 | rcSegment.top + vsDraw.maxAscent, | |
3023 | cc, 1, textBack, textFore); | |
3024 | } | |
3025 | } else if ((i == startseg) && (static_cast<unsigned char>(ll->chars[i]) >= 0x80) && IsUnicodeMode()) { | |
1dcf666d RD |
3026 | // A single byte >= 0x80 in UTF-8 is a bad byte and is displayed as its hex value |
3027 | char hexits[4]; | |
3028 | sprintf(hexits, "x%2X", ll->chars[i] & 0xff); | |
7e0c58e9 RD |
3029 | DrawTextBlob(surface, vsDraw, rcSegment, hexits, textBack, textFore, twoPhaseDraw); |
3030 | } else { | |
3031 | // Normal text display | |
3032 | if (vsDraw.styles[styleMain].visible) { | |
3033 | if (twoPhaseDraw) { | |
3034 | surface->DrawTextTransparent(rcSegment, textFont, | |
3035 | rcSegment.top + vsDraw.maxAscent, ll->chars + startseg, | |
3036 | i - startseg + 1, textFore); | |
3037 | } else { | |
3038 | surface->DrawTextNoClip(rcSegment, textFont, | |
3039 | rcSegment.top + vsDraw.maxAscent, ll->chars + startseg, | |
3040 | i - startseg + 1, textFore, textBack); | |
9e730a78 | 3041 | } |
7e0c58e9 RD |
3042 | } |
3043 | if (vsDraw.viewWhitespace != wsInvisible || | |
3044 | (inIndentation && vsDraw.viewIndentationGuides != ivNone)) { | |
3045 | for (int cpos = 0; cpos <= i - startseg; cpos++) { | |
3046 | if (ll->chars[cpos + startseg] == ' ') { | |
3047 | if (vsDraw.viewWhitespace != wsInvisible) { | |
3048 | if (vsDraw.whitespaceForegroundSet) | |
1dcf666d | 3049 | textFore = vsDraw.whitespaceForeground; |
7e0c58e9 | 3050 | if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { |
1dcf666d | 3051 | XYPOSITION xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2; |
7e0c58e9 RD |
3052 | if (!twoPhaseDraw && drawWhitespaceBackground && |
3053 | (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { | |
1dcf666d | 3054 | textBack = vsDraw.whitespaceBackground; |
9e96e16f RD |
3055 | PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart, |
3056 | rcSegment.top, | |
3057 | ll->positions[cpos + startseg + 1] + xStart - subLineStart, | |
3058 | rcSegment.bottom); | |
7e0c58e9 | 3059 | surface->FillRectangle(rcSpace, textBack); |
d134f170 | 3060 | } |
7e0c58e9 | 3061 | PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0); |
9e96e16f RD |
3062 | rcDot.right = rcDot.left + vs.whitespaceSize; |
3063 | rcDot.bottom = rcDot.top + vs.whitespaceSize; | |
7e0c58e9 | 3064 | surface->FillRectangle(rcDot, textFore); |
d134f170 | 3065 | } |
7e0c58e9 RD |
3066 | } |
3067 | if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { | |
1dcf666d RD |
3068 | for (int indentCount = (ll->positions[cpos + startseg] + epsilon) / indentWidth; |
3069 | indentCount <= (ll->positions[cpos + startseg + 1] - epsilon) / indentWidth; | |
3070 | indentCount++) { | |
3071 | if (indentCount > 0) { | |
3072 | int xIndent = indentCount * indentWidth; | |
3073 | DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, | |
3074 | (ll->xHighlightGuide == xIndent)); | |
3075 | } | |
d134f170 | 3076 | } |
9ce192d4 | 3077 | } |
7e0c58e9 RD |
3078 | } else { |
3079 | inIndentation = false; | |
9ce192d4 RD |
3080 | } |
3081 | } | |
3082 | } | |
7e0c58e9 | 3083 | } |
1dcf666d | 3084 | if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd) { |
7e0c58e9 RD |
3085 | PRectangle rcUL = rcSegment; |
3086 | rcUL.top = rcUL.top + vsDraw.maxAscent + 1; | |
3087 | rcUL.bottom = rcUL.top + 1; | |
3088 | if (vsDraw.hotspotForegroundSet) | |
1dcf666d | 3089 | surface->FillRectangle(rcUL, vsDraw.hotspotForeground); |
7e0c58e9 | 3090 | else |
f6bcfd97 | 3091 | surface->FillRectangle(rcUL, textFore); |
7e0c58e9 RD |
3092 | } else if (vsDraw.styles[styleMain].underline) { |
3093 | PRectangle rcUL = rcSegment; | |
3094 | rcUL.top = rcUL.top + vsDraw.maxAscent + 1; | |
3095 | rcUL.bottom = rcUL.top + 1; | |
3096 | surface->FillRectangle(rcUL, textFore); | |
9ce192d4 | 3097 | } |
7e0c58e9 RD |
3098 | } else if (rcSegment.left > rcLine.right) { |
3099 | break; | |
9ce192d4 RD |
3100 | } |
3101 | } | |
7e0c58e9 RD |
3102 | if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth) |
3103 | && (subLine == 0)) { | |
3104 | int indentSpace = pdoc->GetLineIndentation(line); | |
9e96e16f RD |
3105 | int xStartText = ll->positions[pdoc->GetLineIndentPosition(line) - posLineStart]; |
3106 | ||
7e0c58e9 | 3107 | // Find the most recent line with some text |
9ce192d4 | 3108 | |
7e0c58e9 | 3109 | int lineLastWithText = line; |
9e96e16f | 3110 | while (lineLastWithText > Platform::Maximum(line-20, 0) && pdoc->IsWhiteLine(lineLastWithText)) { |
7e0c58e9 RD |
3111 | lineLastWithText--; |
3112 | } | |
3113 | if (lineLastWithText < line) { | |
9e96e16f | 3114 | xStartText = 100000; // Don't limit to visible indentation on empty line |
7e0c58e9 RD |
3115 | // This line is empty, so use indentation of last line with text |
3116 | int indentLastWithText = pdoc->GetLineIndentation(lineLastWithText); | |
3117 | int isFoldHeader = pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG; | |
3118 | if (isFoldHeader) { | |
3119 | // Level is one more level than parent | |
3120 | indentLastWithText += pdoc->IndentSize(); | |
1e9bafca | 3121 | } |
7e0c58e9 RD |
3122 | if (vsDraw.viewIndentationGuides == ivLookForward) { |
3123 | // In viLookForward mode, previous line only used if it is a fold header | |
3124 | if (isFoldHeader) { | |
3125 | indentSpace = Platform::Maximum(indentSpace, indentLastWithText); | |
9ce192d4 | 3126 | } |
7e0c58e9 RD |
3127 | } else { // viLookBoth |
3128 | indentSpace = Platform::Maximum(indentSpace, indentLastWithText); | |
9ce192d4 RD |
3129 | } |
3130 | } | |
7e0c58e9 RD |
3131 | |
3132 | int lineNextWithText = line; | |
9e96e16f | 3133 | while (lineNextWithText < Platform::Minimum(line+20, pdoc->LinesTotal()) && pdoc->IsWhiteLine(lineNextWithText)) { |
7e0c58e9 RD |
3134 | lineNextWithText++; |
3135 | } | |
3136 | if (lineNextWithText > line) { | |
1dcf666d RD |
3137 | xStartText = 100000; // Don't limit to visible indentation on empty line |
3138 | // This line is empty, so use indentation of first next line with text | |
7e0c58e9 RD |
3139 | indentSpace = Platform::Maximum(indentSpace, |
3140 | pdoc->GetLineIndentation(lineNextWithText)); | |
3141 | } | |
3142 | ||
3143 | for (int indentPos = pdoc->IndentSize(); indentPos < indentSpace; indentPos += pdoc->IndentSize()) { | |
3144 | int xIndent = indentPos * vsDraw.spaceWidth; | |
9e96e16f RD |
3145 | if (xIndent < xStartText) { |
3146 | DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, | |
3147 | (ll->xHighlightGuide == xIndent)); | |
3148 | } | |
7e0c58e9 | 3149 | } |
9ce192d4 | 3150 | } |
7e0c58e9 RD |
3151 | |
3152 | DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, false); | |
3153 | ||
9ce192d4 | 3154 | // End of the drawing of the current line |
9e730a78 RD |
3155 | if (!twoPhaseDraw) { |
3156 | DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd, | |
591d01be | 3157 | xStart, subLine, subLineStart, overrideBackground, background, |
7e0c58e9 | 3158 | drawWrapMarkEnd, wrapColour); |
9ce192d4 | 3159 | } |
9e96e16f RD |
3160 | if (!hideSelection && ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA))) { |
3161 | // For each selection draw | |
3162 | int virtualSpaces = 0; | |
3163 | if (subLine == (ll->lines - 1)) { | |
3164 | virtualSpaces = sel.VirtualSpaceFor(pdoc->LineEnd(line)); | |
3165 | } | |
1dcf666d | 3166 | SelectionPosition posStart(posLineStart + lineStart); |
9e96e16f RD |
3167 | SelectionPosition posEnd(posLineStart + lineEnd, virtualSpaces); |
3168 | SelectionSegment virtualSpaceRange(posStart, posEnd); | |
3169 | for (size_t r=0; r<sel.Count(); r++) { | |
3170 | int alpha = (r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; | |
3171 | if (alpha != SC_ALPHA_NOALPHA) { | |
3172 | SelectionSegment portion = sel.Range(r).Intersect(virtualSpaceRange); | |
3173 | if (!portion.Empty()) { | |
1dcf666d | 3174 | const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; |
9e96e16f RD |
3175 | rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth; |
3176 | rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * spaceWidth; | |
1dcf666d RD |
3177 | if ((ll->wrapIndent != 0) && (lineStart != 0)) { |
3178 | if ((portion.start.Position() - posLineStart) == lineStart && sel.Range(r).ContainsCharacter(portion.start.Position() - 1)) | |
3179 | rcSegment.left -= static_cast<int>(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here | |
3180 | } | |
3181 | rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; | |
3182 | rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; | |
3183 | if (rcSegment.right > rcLine.left) | |
3184 | SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == sel.Main()), alpha); | |
9e96e16f RD |
3185 | } |
3186 | } | |
b8193d80 RD |
3187 | } |
3188 | } | |
d134f170 | 3189 | |
b8193d80 | 3190 | // Draw any translucent whole line states |
1dcf666d | 3191 | rcSegment = rcLine; |
b8193d80 | 3192 | if (caret.active && vsDraw.showCaretLineBackground && ll->containsCaret) { |
1dcf666d | 3193 | SimpleAlphaRectangle(surface, rcSegment, vsDraw.caretLineBackground, vsDraw.caretLineAlpha); |
b8193d80 | 3194 | } |
9e96e16f RD |
3195 | marks = pdoc->GetMark(line); |
3196 | for (markBit = 0; (markBit < 32) && marks; markBit++) { | |
b8193d80 | 3197 | if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND)) { |
1dcf666d | 3198 | SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); |
9e96e16f RD |
3199 | } else if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE)) { |
3200 | PRectangle rcUnderline = rcSegment; | |
3201 | rcUnderline.top = rcUnderline.bottom - 2; | |
1dcf666d | 3202 | SimpleAlphaRectangle(surface, rcUnderline, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); |
b8193d80 RD |
3203 | } |
3204 | marks >>= 1; | |
3205 | } | |
3206 | if (vsDraw.maskInLine) { | |
3207 | int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine; | |
3208 | if (marksMasked) { | |
9e96e16f | 3209 | for (markBit = 0; (markBit < 32) && marksMasked; markBit++) { |
b8193d80 | 3210 | if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY)) { |
1dcf666d | 3211 | SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); |
b8193d80 RD |
3212 | } |
3213 | marksMasked >>= 1; | |
3214 | } | |
3215 | } | |
3216 | } | |
9ce192d4 RD |
3217 | } |
3218 | ||
9e96e16f | 3219 | void Editor::DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, |
1dcf666d | 3220 | int xStart, int offset, int posCaret, PRectangle rcCaret, ColourDesired caretColour) { |
7e0c58e9 RD |
3221 | |
3222 | int lineStart = ll->LineStart(subLine); | |
3223 | int posBefore = posCaret; | |
3224 | int posAfter = MovePositionOutsideChar(posCaret + 1, 1); | |
3225 | int numCharsToDraw = posAfter - posCaret; | |
3226 | ||
3227 | // Work out where the starting and ending offsets are. We need to | |
3228 | // see if the previous character shares horizontal space, such as a | |
3229 | // glyph / combining character. If so we'll need to draw that too. | |
3230 | int offsetFirstChar = offset; | |
3231 | int offsetLastChar = offset + (posAfter - posCaret); | |
1dcf666d | 3232 | while ((posBefore > 0) && ((offsetLastChar - numCharsToDraw) >= lineStart)) { |
7e0c58e9 RD |
3233 | if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) { |
3234 | // The char does not share horizontal space | |
3235 | break; | |
3236 | } | |
3237 | // Char shares horizontal space, update the numChars to draw | |
3238 | // Update posBefore to point to the prev char | |
3239 | posBefore = MovePositionOutsideChar(posBefore - 1, -1); | |
3240 | numCharsToDraw = posAfter - posBefore; | |
3241 | offsetFirstChar = offset - (posCaret - posBefore); | |
3242 | } | |
3243 | ||
3244 | // See if the next character shares horizontal space, if so we'll | |
3245 | // need to draw that too. | |
1dcf666d RD |
3246 | if (offsetFirstChar < 0) |
3247 | offsetFirstChar = 0; | |
7e0c58e9 RD |
3248 | numCharsToDraw = offsetLastChar - offsetFirstChar; |
3249 | while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) { | |
3250 | // Update posAfter to point to the 2nd next char, this is where | |
3251 | // the next character ends, and 2nd next begins. We'll need | |
3252 | // to compare these two | |
3253 | posBefore = posAfter; | |
3254 | posAfter = MovePositionOutsideChar(posAfter + 1, 1); | |
3255 | offsetLastChar = offset + (posAfter - posCaret); | |
3256 | if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) { | |
3257 | // The char does not share horizontal space | |
3258 | break; | |
3259 | } | |
3260 | // Char shares horizontal space, update the numChars to draw | |
3261 | numCharsToDraw = offsetLastChar - offsetFirstChar; | |
3262 | } | |
3263 | ||
3264 | // We now know what to draw, update the caret drawing rectangle | |
9e96e16f RD |
3265 | rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart; |
3266 | rcCaret.right = ll->positions[offsetFirstChar+numCharsToDraw] - ll->positions[lineStart] + xStart; | |
3267 | ||
3268 | // Adjust caret position to take into account any word wrapping symbols. | |
3269 | if ((ll->wrapIndent != 0) && (lineStart != 0)) { | |
1dcf666d | 3270 | XYPOSITION wordWrapCharWidth = ll->wrapIndent; |
9e96e16f RD |
3271 | rcCaret.left += wordWrapCharWidth; |
3272 | rcCaret.right += wordWrapCharWidth; | |
3273 | } | |
7e0c58e9 RD |
3274 | |
3275 | // This character is where the caret block is, we override the colours | |
3276 | // (inversed) for drawing the caret here. | |
3277 | int styleMain = ll->styles[offsetFirstChar]; | |
3278 | surface->DrawTextClipped(rcCaret, vsDraw.styles[styleMain].font, | |
3279 | rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar, | |
1dcf666d | 3280 | numCharsToDraw, vsDraw.styles[styleMain].back, |
9e96e16f | 3281 | caretColour); |
7e0c58e9 RD |
3282 | } |
3283 | ||
9e730a78 | 3284 | void Editor::RefreshPixMaps(Surface *surfaceWindow) { |
1a2fb4cd | 3285 | if (!pixmapSelPattern->Initialised()) { |
9e730a78 RD |
3286 | const int patternSize = 8; |
3287 | pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID()); | |
3288 | // This complex procedure is to reproduce the checkerboard dithered pattern used by windows | |
9ce192d4 RD |
3289 | // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half |
3290 | // way between the chrome colour and the chrome highlight colour making a nice transition | |
3291 | // between the window chrome and the content area. And it works in low colour depths. | |
9e730a78 RD |
3292 | PRectangle rcPattern(0, 0, patternSize, patternSize); |
3293 | ||
3294 | // Initialize default colours based on the chrome colour scheme. Typically the highlight is white. | |
1dcf666d RD |
3295 | ColourDesired colourFMFill = vs.selbar; |
3296 | ColourDesired colourFMStripes = vs.selbarlight; | |
9e730a78 | 3297 | |
1dcf666d | 3298 | if (!(vs.selbarlight == ColourDesired(0xff, 0xff, 0xff))) { |
9ce192d4 | 3299 | // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. |
9e730a78 | 3300 | // (Typically, the highlight colour is white.) |
1dcf666d | 3301 | colourFMFill = vs.selbarlight; |
9e730a78 RD |
3302 | } |
3303 | ||
3304 | if (vs.foldmarginColourSet) { | |
3305 | // override default fold margin colour | |
1dcf666d | 3306 | colourFMFill = vs.foldmarginColour; |
9e730a78 RD |
3307 | } |
3308 | if (vs.foldmarginHighlightColourSet) { | |
3309 | // override default fold margin highlight colour | |
1dcf666d | 3310 | colourFMStripes = vs.foldmarginHighlightColour; |
9e730a78 RD |
3311 | } |
3312 | ||
3313 | pixmapSelPattern->FillRectangle(rcPattern, colourFMFill); | |
1dcf666d RD |
3314 | for (int y = 0; y < patternSize; y++) { |
3315 | for (int x = y % 2; x < patternSize; x+=2) { | |
3316 | PRectangle rcPixel(x, y, x+1, y+1); | |
3317 | pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes); | |
3318 | } | |
9ce192d4 RD |
3319 | } |
3320 | } | |
9e730a78 | 3321 | |
1a2fb4cd | 3322 | if (!pixmapIndentGuide->Initialised()) { |
d134f170 | 3323 | // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line |
9e730a78 RD |
3324 | pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID()); |
3325 | pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID()); | |
d134f170 | 3326 | PRectangle rcIG(0, 0, 1, vs.lineHeight); |
1dcf666d RD |
3327 | pixmapIndentGuide->FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back); |
3328 | pixmapIndentGuide->PenColour(vs.styles[STYLE_INDENTGUIDE].fore); | |
3329 | pixmapIndentGuideHighlight->FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back); | |
3330 | pixmapIndentGuideHighlight->PenColour(vs.styles[STYLE_BRACELIGHT].fore); | |
d134f170 | 3331 | for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) { |
1dcf666d RD |
3332 | PRectangle rcPixel(0, stripe, 1, stripe+1); |
3333 | pixmapIndentGuide->FillRectangle(rcPixel, vs.styles[STYLE_INDENTGUIDE].fore); | |
3334 | pixmapIndentGuideHighlight->FillRectangle(rcPixel, vs.styles[STYLE_BRACELIGHT].fore); | |
d134f170 RD |
3335 | } |
3336 | } | |
9ce192d4 RD |
3337 | |
3338 | if (bufferedDraw) { | |
1a2fb4cd | 3339 | if (!pixmapLine->Initialised()) { |
9e730a78 | 3340 | PRectangle rcClient = GetClientRectangle(); |
1e9bafca | 3341 | pixmapLine->InitPixMap(rcClient.Width(), vs.lineHeight, |
7e0c58e9 | 3342 | surfaceWindow, wMain.GetID()); |
1a2fb4cd | 3343 | pixmapSelMargin->InitPixMap(vs.fixedColumnWidth, |
7e0c58e9 | 3344 | rcClient.Height(), surfaceWindow, wMain.GetID()); |
9ce192d4 RD |
3345 | } |
3346 | } | |
9e730a78 RD |
3347 | } |
3348 | ||
9e96e16f RD |
3349 | void Editor::DrawCarets(Surface *surface, ViewStyle &vsDraw, int lineDoc, int xStart, |
3350 | PRectangle rcLine, LineLayout *ll, int subLine) { | |
3351 | // When drag is active it is the only caret drawn | |
3352 | bool drawDrag = posDrag.IsValid(); | |
3353 | if (hideSelection && !drawDrag) | |
3354 | return; | |
3355 | const int posLineStart = pdoc->LineStart(lineDoc); | |
3356 | // For each selection draw | |
3357 | for (size_t r=0; (r<sel.Count()) || drawDrag; r++) { | |
3358 | const bool mainCaret = r == sel.Main(); | |
3359 | const SelectionPosition posCaret = (drawDrag ? posDrag : sel.Range(r).caret); | |
3360 | const int offset = posCaret.Position() - posLineStart; | |
1dcf666d RD |
3361 | const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; |
3362 | const XYPOSITION virtualOffset = posCaret.VirtualSpace() * spaceWidth; | |
9e96e16f | 3363 | if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) { |
1dcf666d | 3364 | XYPOSITION xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)]; |
9e96e16f RD |
3365 | if (ll->wrapIndent != 0) { |
3366 | int lineStart = ll->LineStart(subLine); | |
3367 | if (lineStart != 0) // Wrapped | |
3368 | xposCaret += ll->wrapIndent; | |
3369 | } | |
3370 | bool caretBlinkState = (caret.active && caret.on) || (!additionalCaretsBlink && !mainCaret); | |
3371 | bool caretVisibleState = additionalCaretsVisible || mainCaret; | |
3372 | if ((xposCaret >= 0) && (vsDraw.caretWidth > 0) && (vsDraw.caretStyle != CARETSTYLE_INVISIBLE) && | |
3373 | ((posDrag.IsValid()) || (caretBlinkState && caretVisibleState))) { | |
3374 | bool caretAtEOF = false; | |
3375 | bool caretAtEOL = false; | |
3376 | bool drawBlockCaret = false; | |
1dcf666d | 3377 | XYPOSITION widthOverstrikeCaret; |
9e96e16f RD |
3378 | int caretWidthOffset = 0; |
3379 | PRectangle rcCaret = rcLine; | |
3380 | ||
3381 | if (posCaret.Position() == pdoc->Length()) { // At end of document | |
3382 | caretAtEOF = true; | |
3383 | widthOverstrikeCaret = vsDraw.aveCharWidth; | |
3384 | } else if ((posCaret.Position() - posLineStart) >= ll->numCharsInLine) { // At end of line | |
3385 | caretAtEOL = true; | |
3386 | widthOverstrikeCaret = vsDraw.aveCharWidth; | |
3387 | } else { | |
3388 | widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset]; | |
3389 | } | |
3390 | if (widthOverstrikeCaret < 3) // Make sure its visible | |
3391 | widthOverstrikeCaret = 3; | |
3392 | ||
3393 | if (xposCaret > 0) | |
3394 | caretWidthOffset = 1; // Move back so overlaps both character cells. | |
3395 | xposCaret += xStart; | |
3396 | if (posDrag.IsValid()) { | |
3397 | /* Dragging text, use a line caret */ | |
3398 | rcCaret.left = xposCaret - caretWidthOffset; | |
3399 | rcCaret.right = rcCaret.left + vsDraw.caretWidth; | |
3400 | } else if (inOverstrike) { | |
3401 | /* Overstrike (insert mode), use a modified bar caret */ | |
3402 | rcCaret.top = rcCaret.bottom - 2; | |
3403 | rcCaret.left = xposCaret + 1; | |
3404 | rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1; | |
3405 | } else if (vsDraw.caretStyle == CARETSTYLE_BLOCK) { | |
3406 | /* Block caret */ | |
3407 | rcCaret.left = xposCaret; | |
3408 | if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) { | |
3409 | drawBlockCaret = true; | |
3410 | rcCaret.right = xposCaret + widthOverstrikeCaret; | |
3411 | } else { | |
3412 | rcCaret.right = xposCaret + vsDraw.aveCharWidth; | |
3413 | } | |
3414 | } else { | |
3415 | /* Line caret */ | |
3416 | rcCaret.left = xposCaret - caretWidthOffset; | |
3417 | rcCaret.right = rcCaret.left + vsDraw.caretWidth; | |
3418 | } | |
1dcf666d | 3419 | ColourDesired caretColour = mainCaret ? vsDraw.caretcolour : vsDraw.additionalCaretColour; |
9e96e16f RD |
3420 | if (drawBlockCaret) { |
3421 | DrawBlockCaret(surface, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour); | |
3422 | } else { | |
3423 | surface->FillRectangle(rcCaret, caretColour); | |
3424 | } | |
3425 | } | |
3426 | } | |
3427 | if (drawDrag) | |
3428 | break; | |
3429 | } | |
3430 | } | |
3431 | ||
9e730a78 RD |
3432 | void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { |
3433 | //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n", | |
3434 | // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); | |
1dcf666d | 3435 | AllocateGraphics(); |
9e730a78 RD |
3436 | |
3437 | RefreshStyleData(); | |
9e730a78 RD |
3438 | RefreshPixMaps(surfaceWindow); |
3439 | ||
1dcf666d RD |
3440 | StyleToPositionInView(PositionAfterArea(rcArea)); |
3441 | ||
9e730a78 RD |
3442 | PRectangle rcClient = GetClientRectangle(); |
3443 | //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n", | |
3444 | // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); | |
9ce192d4 | 3445 | |
9ce192d4 | 3446 | int screenLinePaintFirst = rcArea.top / vs.lineHeight; |
9ce192d4 RD |
3447 | |
3448 | int xStart = vs.fixedColumnWidth - xOffset; | |
3449 | int ypos = 0; | |
3450 | if (!bufferedDraw) | |
3451 | ypos += screenLinePaintFirst * vs.lineHeight; | |
3452 | int yposScreen = screenLinePaintFirst * vs.lineHeight; | |
3453 | ||
1a2fb4cd | 3454 | bool paintAbandonedByStyling = paintState == paintAbandoned; |
9ce192d4 RD |
3455 | if (needUpdateUI) { |
3456 | NotifyUpdateUI(); | |
1dcf666d | 3457 | needUpdateUI = 0; |
9e96e16f | 3458 | |
b8193d80 RD |
3459 | RefreshStyleData(); |
3460 | RefreshPixMaps(surfaceWindow); | |
9ce192d4 | 3461 | } |
d134f170 | 3462 | |
8e54aaed RD |
3463 | // Call priority lines wrap on a window of lines which are likely |
3464 | // to rendered with the following paint (that is wrap the visible | |
3465 | // lines first). | |
3466 | int startLineToWrap = cs.DocFromDisplay(topLine) - 5; | |
3467 | if (startLineToWrap < 0) | |
9e96e16f | 3468 | startLineToWrap = 0; |
8e54aaed RD |
3469 | if (WrapLines(false, startLineToWrap)) { |
3470 | // The wrapping process has changed the height of some lines so | |
3471 | // abandon this paint for a complete repaint. | |
9e730a78 RD |
3472 | if (AbandonPaint()) { |
3473 | return; | |
3474 | } | |
88a8b04e | 3475 | RefreshPixMaps(surfaceWindow); // In case pixmaps invalidated by scrollbar change |
9e730a78 | 3476 | } |
88a8b04e | 3477 | PLATFORM_ASSERT(pixmapSelPattern->Initialised()); |
9e730a78 | 3478 | |
1dcf666d RD |
3479 | if (!bufferedDraw) |
3480 | surfaceWindow->SetClip(rcArea); | |
3481 | ||
3482 | if (paintState != paintAbandoned) { | |
3483 | PaintSelMargin(surfaceWindow, rcArea); | |
8e54aaed | 3484 | |
1dcf666d RD |
3485 | PRectangle rcRightMargin = rcClient; |
3486 | rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth; | |
3487 | if (rcArea.Intersects(rcRightMargin)) { | |
3488 | surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back); | |
3489 | } | |
9ce192d4 RD |
3490 | } |
3491 | ||
3492 | if (paintState == paintAbandoned) { | |
f6bcfd97 | 3493 | // Either styling or NotifyUpdateUI noticed that painting is needed |
9ce192d4 RD |
3494 | // outside the current painting rectangle |
3495 | //Platform::DebugPrintf("Abandoning paint\n"); | |
1a2fb4cd RD |
3496 | if (wrapState != eWrapNone) { |
3497 | if (paintAbandonedByStyling) { | |
e4f0b986 | 3498 | // Styling has spilled over a line end, such as occurs by starting a multiline |
1a2fb4cd RD |
3499 | // comment. The width of subsequent text may have changed, so rewrap. |
3500 | NeedWrapping(cs.DocFromDisplay(topLine)); | |
3501 | } | |
3502 | } | |
65ec6247 | 3503 | return; |
9ce192d4 RD |
3504 | } |
3505 | //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset); | |
3506 | ||
1dcf666d RD |
3507 | // Allow text at start of line to overlap 1 pixel into the margin as this displays |
3508 | // serifs and italic stems for aliased text. | |
3509 | const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0; | |
3510 | ||
65ec6247 | 3511 | // Do the painting |
1dcf666d | 3512 | if (rcArea.right > vs.fixedColumnWidth - leftTextOverlap) { |
9ce192d4 | 3513 | |
f6bcfd97 | 3514 | Surface *surface = surfaceWindow; |
9ce192d4 | 3515 | if (bufferedDraw) { |
1a2fb4cd | 3516 | surface = pixmapLine; |
88a8b04e | 3517 | PLATFORM_ASSERT(pixmapLine->Initialised()); |
9ce192d4 | 3518 | } |
1a2fb4cd | 3519 | surface->SetUnicodeMode(IsUnicodeMode()); |
9e730a78 | 3520 | surface->SetDBCSMode(CodePage()); |
9ce192d4 RD |
3521 | |
3522 | int visibleLine = topLine + screenLinePaintFirst; | |
9ce192d4 | 3523 | |
9e96e16f RD |
3524 | SelectionPosition posCaret = sel.RangeMain().caret; |
3525 | if (posDrag.IsValid()) | |
9ce192d4 | 3526 | posCaret = posDrag; |
9e96e16f | 3527 | int lineCaret = pdoc->LineFromPosition(posCaret.Position()); |
9ce192d4 | 3528 | |
9ce192d4 RD |
3529 | PRectangle rcTextArea = rcClient; |
3530 | rcTextArea.left = vs.fixedColumnWidth; | |
3531 | rcTextArea.right -= vs.rightMarginWidth; | |
1dcf666d RD |
3532 | |
3533 | // Remove selection margin from drawing area so text will not be drawn | |
3534 | // on it in unbuffered mode. | |
3535 | if (!bufferedDraw) { | |
3536 | PRectangle rcClipText = rcTextArea; | |
3537 | rcClipText.left -= leftTextOverlap; | |
3538 | surfaceWindow->SetClip(rcClipText); | |
3539 | } | |
65ec6247 RD |
3540 | |
3541 | // Loop on visible lines | |
1a2fb4cd RD |
3542 | //double durLayout = 0.0; |
3543 | //double durPaint = 0.0; | |
3544 | //double durCopy = 0.0; | |
3545 | //ElapsedTime etWhole; | |
3546 | int lineDocPrevious = -1; // Used to avoid laying out one document line multiple times | |
9e730a78 | 3547 | AutoLineLayout ll(llc, 0); |
d134f170 | 3548 | while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) { |
1a2fb4cd RD |
3549 | |
3550 | int lineDoc = cs.DocFromDisplay(visibleLine); | |
1a2fb4cd RD |
3551 | // Only visible lines should be handled by the code within the loop |
3552 | PLATFORM_ASSERT(cs.GetVisible(lineDoc)); | |
3553 | int lineStartSet = cs.DisplayFromDoc(lineDoc); | |
3554 | int subLine = visibleLine - lineStartSet; | |
9ce192d4 | 3555 | |
65ec6247 RD |
3556 | // Copy this line and its styles from the document into local arrays |
3557 | // and determine the x position at which each character starts. | |
1a2fb4cd RD |
3558 | //ElapsedTime et; |
3559 | if (lineDoc != lineDocPrevious) { | |
591d01be | 3560 | ll.Set(0); |
9e730a78 | 3561 | ll.Set(RetrieveLineLayout(lineDoc)); |
1a2fb4cd RD |
3562 | LayoutLine(lineDoc, surface, vs, ll, wrapWidth); |
3563 | lineDocPrevious = lineDoc; | |
65ec6247 | 3564 | } |
1a2fb4cd RD |
3565 | //durLayout += et.Duration(true); |
3566 | ||
3567 | if (ll) { | |
1a2fb4cd RD |
3568 | ll->containsCaret = lineDoc == lineCaret; |
3569 | if (hideSelection) { | |
1a2fb4cd | 3570 | ll->containsCaret = false; |
9ce192d4 | 3571 | } |
e4f0b986 | 3572 | |
9e730a78 RD |
3573 | GetHotSpotRange(ll->hsStart, ll->hsEnd); |
3574 | ||
1dcf666d | 3575 | PRectangle rcLine = rcTextArea; |
1a2fb4cd RD |
3576 | rcLine.top = ypos; |
3577 | rcLine.bottom = ypos + vs.lineHeight; | |
3578 | ||
1dcf666d RD |
3579 | bool bracesIgnoreStyle = false; |
3580 | if ((vs.braceHighlightIndicatorSet && (bracesMatchStyle == STYLE_BRACELIGHT)) || | |
3581 | (vs.braceBadLightIndicatorSet && (bracesMatchStyle == STYLE_BRACEBAD))) { | |
3582 | bracesIgnoreStyle = true; | |
3583 | } | |
1a2fb4cd RD |
3584 | Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1)); |
3585 | // Highlight the current braces if any | |
3586 | ll->SetBracesHighlight(rangeLine, braces, static_cast<char>(bracesMatchStyle), | |
1dcf666d RD |
3587 | highlightGuideColumn * vs.spaceWidth, bracesIgnoreStyle); |
3588 | ||
3589 | if (leftTextOverlap && bufferedDraw) { | |
3590 | PRectangle rcSpacer = rcLine; | |
3591 | rcSpacer.right = rcSpacer.left; | |
3592 | rcSpacer.left -= 1; | |
3593 | surface->FillRectangle(rcSpacer, vs.styles[STYLE_DEFAULT].back); | |
3594 | } | |
e4f0b986 | 3595 | |
1a2fb4cd RD |
3596 | // Draw the line |
3597 | DrawLine(surface, vs, lineDoc, visibleLine, xStart, rcLine, ll, subLine); | |
3598 | //durPaint += et.Duration(true); | |
e4f0b986 | 3599 | |
8e54aaed | 3600 | // Restore the previous styles for the brace highlights in case layout is in cache. |
1dcf666d | 3601 | ll->RestoreBracesHighlight(rangeLine, braces, bracesIgnoreStyle); |
1a2fb4cd RD |
3602 | |
3603 | bool expanded = cs.GetExpanded(lineDoc); | |
1dcf666d RD |
3604 | const int level = pdoc->GetLevel(lineDoc); |
3605 | const int levelNext = pdoc->GetLevel(lineDoc + 1); | |
3606 | if ((level & SC_FOLDLEVELHEADERFLAG) && | |
3607 | ((level & SC_FOLDLEVELNUMBERMASK) < (levelNext & SC_FOLDLEVELNUMBERMASK))) { | |
3608 | // Paint the line above the fold | |
3609 | if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED)) | |
3610 | || | |
3611 | (!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) { | |
1a2fb4cd RD |
3612 | PRectangle rcFoldLine = rcLine; |
3613 | rcFoldLine.bottom = rcFoldLine.top + 1; | |
1dcf666d | 3614 | surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore); |
1a2fb4cd | 3615 | } |
1dcf666d RD |
3616 | // Paint the line below the fold |
3617 | if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED)) | |
3618 | || | |
3619 | (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) { | |
1a2fb4cd RD |
3620 | PRectangle rcFoldLine = rcLine; |
3621 | rcFoldLine.top = rcFoldLine.bottom - 1; | |
1dcf666d | 3622 | surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore); |
1a2fb4cd | 3623 | } |
d134f170 | 3624 | } |
e4f0b986 | 3625 | |
9e96e16f | 3626 | DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine); |
e4f0b986 | 3627 | |
9ce192d4 | 3628 | if (bufferedDraw) { |
1dcf666d RD |
3629 | Point from(vs.fixedColumnWidth-leftTextOverlap, 0); |
3630 | PRectangle rcCopyArea(vs.fixedColumnWidth-leftTextOverlap, yposScreen, | |
3631 | rcClient.right - vs.rightMarginWidth, yposScreen + vs.lineHeight); | |
1a2fb4cd | 3632 | surfaceWindow->Copy(rcCopyArea, from, *pixmapLine); |
9ce192d4 | 3633 | } |
9e96e16f RD |
3634 | |
3635 | lineWidthMaxSeen = Platform::Maximum( | |
3636 | lineWidthMaxSeen, ll->positions[ll->numCharsInLine]); | |
1a2fb4cd | 3637 | //durCopy += et.Duration(true); |
9ce192d4 | 3638 | } |
e4f0b986 | 3639 | |
9ce192d4 RD |
3640 | if (!bufferedDraw) { |
3641 | ypos += vs.lineHeight; | |
3642 | } | |
3643 | ||
3644 | yposScreen += vs.lineHeight; | |
3645 | visibleLine++; | |
7e0c58e9 | 3646 | |
9ce192d4 | 3647 | //gdk_flush(); |
9ce192d4 | 3648 | } |
1e9bafca | 3649 | ll.Set(0); |
1a2fb4cd RD |
3650 | //if (durPaint < 0.00000001) |
3651 | // durPaint = 0.00000001; | |
d134f170 | 3652 | |
65ec6247 | 3653 | // Right column limit indicator |
9ce192d4 RD |
3654 | PRectangle rcBeyondEOF = rcClient; |
3655 | rcBeyondEOF.left = vs.fixedColumnWidth; | |
1dcf666d | 3656 | rcBeyondEOF.right = rcBeyondEOF.right - vs.rightMarginWidth; |
9ce192d4 RD |
3657 | rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight; |
3658 | if (rcBeyondEOF.top < rcBeyondEOF.bottom) { | |
1dcf666d | 3659 | surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back); |
d134f170 | 3660 | if (vs.edgeState == EDGE_LINE) { |
9ce192d4 RD |
3661 | int edgeX = theEdge * vs.spaceWidth; |
3662 | rcBeyondEOF.left = edgeX + xStart; | |
3663 | rcBeyondEOF.right = rcBeyondEOF.left + 1; | |
1dcf666d | 3664 | surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour); |
9ce192d4 RD |
3665 | } |
3666 | } | |
1a2fb4cd | 3667 | //Platform::DebugPrintf( |
e4f0b986 | 3668 | //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n", |
1a2fb4cd | 3669 | //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration()); |
65ec6247 | 3670 | NotifyPainted(); |
9ce192d4 RD |
3671 | } |
3672 | } | |
3673 | ||
3674 | // Space (3 space characters) between line numbers and text when printing. | |
3675 | #define lineNumberPrintSpace " " | |
3676 | ||
1a2fb4cd | 3677 | ColourDesired InvertedLight(ColourDesired orig) { |
d134f170 RD |
3678 | unsigned int r = orig.GetRed(); |
3679 | unsigned int g = orig.GetGreen(); | |
3680 | unsigned int b = orig.GetBlue(); | |
3681 | unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye | |
3682 | unsigned int il = 0xff - l; | |
3683 | if (l == 0) | |
1a2fb4cd | 3684 | return ColourDesired(0xff, 0xff, 0xff); |
d134f170 RD |
3685 | r = r * il / l; |
3686 | g = g * il / l; | |
3687 | b = b * il / l; | |
1a2fb4cd | 3688 | return ColourDesired(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff)); |
d134f170 RD |
3689 | } |
3690 | ||
9ce192d4 RD |
3691 | // This is mostly copied from the Paint method but with some things omitted |
3692 | // such as the margin markers, line numbers, selection and caret | |
3693 | // Should be merged back into a combined Draw method. | |
9e96e16f | 3694 | long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) { |
9ce192d4 RD |
3695 | if (!pfr) |
3696 | return 0; | |
3697 | ||
1dcf666d | 3698 | AutoSurface surface(pfr->hdc, this, SC_TECHNOLOGY_DEFAULT); |
1a2fb4cd RD |
3699 | if (!surface) |
3700 | return 0; | |
1dcf666d | 3701 | AutoSurface surfaceMeasure(pfr->hdcTarget, this, SC_TECHNOLOGY_DEFAULT); |
1a2fb4cd RD |
3702 | if (!surfaceMeasure) { |
3703 | return 0; | |
3704 | } | |
d134f170 | 3705 | |
7e0c58e9 RD |
3706 | // Can't use measurements cached for screen |
3707 | posCache.Clear(); | |
3708 | ||
9ce192d4 | 3709 | ViewStyle vsPrint(vs); |
1dcf666d | 3710 | vsPrint.technology = SC_TECHNOLOGY_DEFAULT; |
d134f170 | 3711 | |
9ce192d4 RD |
3712 | // Modify the view style for printing as do not normally want any of the transient features to be printed |
3713 | // Printing supports only the line number margin. | |
3714 | int lineNumberIndex = -1; | |
d134f170 | 3715 | for (int margin = 0; margin < ViewStyle::margins; margin++) { |
b8193d80 | 3716 | if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) { |
9ce192d4 RD |
3717 | lineNumberIndex = margin; |
3718 | } else { | |
3719 | vsPrint.ms[margin].width = 0; | |
3720 | } | |
3721 | } | |
9ce192d4 | 3722 | vsPrint.fixedColumnWidth = 0; |
d134f170 | 3723 | vsPrint.zoomLevel = printMagnification; |
1dcf666d RD |
3724 | // Don't show indentation guides |
3725 | // If this ever gets changed, cached pixmap would need to be recreated if technology != SC_TECHNOLOGY_DEFAULT | |
7e0c58e9 | 3726 | vsPrint.viewIndentationGuides = ivNone; |
9ce192d4 RD |
3727 | // Don't show the selection when printing |
3728 | vsPrint.selbackset = false; | |
3729 | vsPrint.selforeset = false; | |
b8193d80 | 3730 | vsPrint.selAlpha = SC_ALPHA_NOALPHA; |
9e96e16f | 3731 | vsPrint.selAdditionalAlpha = SC_ALPHA_NOALPHA; |
f114b858 RD |
3732 | vsPrint.whitespaceBackgroundSet = false; |
3733 | vsPrint.whitespaceForegroundSet = false; | |
65ec6247 | 3734 | vsPrint.showCaretLineBackground = false; |
1dcf666d RD |
3735 | // Don't highlight matching braces using indicators |
3736 | vsPrint.braceHighlightIndicatorSet = false; | |
3737 | vsPrint.braceBadLightIndicatorSet = false; | |
65ec6247 RD |
3738 | |
3739 | // Set colours for printing according to users settings | |
1dcf666d | 3740 | for (size_t sty = 0; sty < vsPrint.stylesSize; sty++) { |
d134f170 | 3741 | if (printColourMode == SC_PRINT_INVERTLIGHT) { |
1dcf666d RD |
3742 | vsPrint.styles[sty].fore = InvertedLight(vsPrint.styles[sty].fore); |
3743 | vsPrint.styles[sty].back = InvertedLight(vsPrint.styles[sty].back); | |
d134f170 | 3744 | } else if (printColourMode == SC_PRINT_BLACKONWHITE) { |
1dcf666d RD |
3745 | vsPrint.styles[sty].fore = ColourDesired(0, 0, 0); |
3746 | vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); | |
65ec6247 | 3747 | } else if (printColourMode == SC_PRINT_COLOURONWHITE) { |
1dcf666d | 3748 | vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); |
65ec6247 RD |
3749 | } else if (printColourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) { |
3750 | if (sty <= STYLE_DEFAULT) { | |
1dcf666d | 3751 | vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); |
65ec6247 | 3752 | } |
d134f170 RD |
3753 | } |
3754 | } | |
65ec6247 | 3755 | // White background for the line numbers |
1dcf666d RD |
3756 | vsPrint.styles[STYLE_LINENUMBER].back = ColourDesired(0xff, 0xff, 0xff); |
3757 | ||
3758 | // Printing uses different margins, so reset screen margins | |
3759 | vsPrint.leftMarginWidth = 0; | |
3760 | vsPrint.rightMarginWidth = 0; | |
d134f170 | 3761 | |
9ce192d4 | 3762 | vsPrint.Refresh(*surfaceMeasure); |
9ce192d4 RD |
3763 | // Determining width must hapen after fonts have been realised in Refresh |
3764 | int lineNumberWidth = 0; | |
3765 | if (lineNumberIndex >= 0) { | |
9e730a78 | 3766 | lineNumberWidth = surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, |
7e0c58e9 | 3767 | "99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace)); |
9ce192d4 | 3768 | vsPrint.ms[lineNumberIndex].width = lineNumberWidth; |
7e0c58e9 | 3769 | vsPrint.Refresh(*surfaceMeasure); // Recalculate fixedColumnWidth |
9ce192d4 RD |
3770 | } |
3771 | ||
3772 | int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin); | |
3773 | int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1; | |
3774 | if (linePrintLast < linePrintStart) | |
3775 | linePrintLast = linePrintStart; | |
9e730a78 | 3776 | int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax); |
9ce192d4 RD |
3777 | if (linePrintLast > linePrintMax) |
3778 | linePrintLast = linePrintMax; | |
3779 | //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n", | |
9e730a78 RD |
3780 | // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight, |
3781 | // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font)); | |
9ce192d4 RD |
3782 | int endPosPrint = pdoc->Length(); |
3783 | if (linePrintLast < pdoc->LinesTotal()) | |
3784 | endPosPrint = pdoc->LineStart(linePrintLast + 1); | |
3785 | ||
f6bcfd97 BP |
3786 | // Ensure we are styled to where we are formatting. |
3787 | pdoc->EnsureStyledTo(endPosPrint); | |
3788 | ||
7e0c58e9 | 3789 | int xStart = vsPrint.fixedColumnWidth + pfr->rc.left; |
9ce192d4 | 3790 | int ypos = pfr->rc.top; |
9ce192d4 | 3791 | |
9e730a78 RD |
3792 | int lineDoc = linePrintStart; |
3793 | ||
3794 | int nPrintPos = pfr->chrg.cpMin; | |
3795 | int visibleLine = 0; | |
1dcf666d | 3796 | int widthPrint = pfr->rc.right - pfr->rc.left - vsPrint.fixedColumnWidth; |
9e730a78 RD |
3797 | if (printWrapState == eWrapNone) |
3798 | widthPrint = LineLayout::wrapWidthInfinite; | |
3799 | ||
3800 | while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) { | |
3801 | ||
3802 | // When printing, the hdc and hdcTarget may be the same, so | |
3803 | // changing the state of surfaceMeasure may change the underlying | |
3804 | // state of surface. Therefore, any cached state is discarded before | |
3805 | // using each surface. | |
3806 | surfaceMeasure->FlushCachedState(); | |
3807 | ||
3808 | // Copy this line and its styles from the document into local arrays | |
3809 | // and determine the x position at which each character starts. | |
3810 | LineLayout ll(8000); | |
3811 | LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint); | |
3812 | ||
9e730a78 RD |
3813 | ll.containsCaret = false; |
3814 | ||
3815 | PRectangle rcLine; | |
7e0c58e9 | 3816 | rcLine.left = pfr->rc.left; |
9e730a78 RD |
3817 | rcLine.top = ypos; |
3818 | rcLine.right = pfr->rc.right - 1; | |
3819 | rcLine.bottom = ypos + vsPrint.lineHeight; | |
3820 | ||
3821 | // When document line is wrapped over multiple display lines, find where | |
3822 | // to start printing from to ensure a particular position is on the first | |
3823 | // line of the page. | |
3824 | if (visibleLine == 0) { | |
3825 | int startWithinLine = nPrintPos - pdoc->LineStart(lineDoc); | |
3826 | for (int iwl = 0; iwl < ll.lines - 1; iwl++) { | |
3827 | if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) { | |
3828 | visibleLine = -iwl; | |
3829 | } | |
3830 | } | |
65ec6247 | 3831 | |
9e730a78 RD |
3832 | if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) { |
3833 | visibleLine = -(ll.lines - 1); | |
9ce192d4 | 3834 | } |
9e730a78 | 3835 | } |
f6bcfd97 | 3836 | |
9e730a78 RD |
3837 | if (draw && lineNumberWidth && |
3838 | (ypos + vsPrint.lineHeight <= pfr->rc.bottom) && | |
3839 | (visibleLine >= 0)) { | |
3840 | char number[100]; | |
3841 | sprintf(number, "%d" lineNumberPrintSpace, lineDoc + 1); | |
3842 | PRectangle rcNumber = rcLine; | |
3843 | rcNumber.right = rcNumber.left + lineNumberWidth; | |
3844 | // Right justify | |
7e0c58e9 RD |
3845 | rcNumber.left = rcNumber.right - surfaceMeasure->WidthText( |
3846 | vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number)); | |
f6bcfd97 | 3847 | surface->FlushCachedState(); |
9e730a78 | 3848 | surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font, |
7e0c58e9 | 3849 | ypos + vsPrint.maxAscent, number, istrlen(number), |
1dcf666d RD |
3850 | vsPrint.styles[STYLE_LINENUMBER].fore, |
3851 | vsPrint.styles[STYLE_LINENUMBER].back); | |
9e730a78 RD |
3852 | } |
3853 | ||
3854 | // Draw the line | |
3855 | surface->FlushCachedState(); | |
3856 | ||
3857 | for (int iwl = 0; iwl < ll.lines; iwl++) { | |
3858 | if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) { | |
3859 | if (visibleLine >= 0) { | |
3860 | if (draw) { | |
3861 | rcLine.top = ypos; | |
3862 | rcLine.bottom = ypos + vsPrint.lineHeight; | |
3863 | DrawLine(surface, vsPrint, lineDoc, visibleLine, xStart, rcLine, &ll, iwl); | |
3864 | } | |
3865 | ypos += vsPrint.lineHeight; | |
3866 | } | |
3867 | visibleLine++; | |
3868 | if (iwl == ll.lines - 1) | |
3869 | nPrintPos = pdoc->LineStart(lineDoc + 1); | |
3870 | else | |
3871 | nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl); | |
3872 | } | |
9ce192d4 | 3873 | } |
9e730a78 RD |
3874 | |
3875 | ++lineDoc; | |
9ce192d4 RD |
3876 | } |
3877 | ||
7e0c58e9 RD |
3878 | // Clear cache so measurements are not used for screen |
3879 | posCache.Clear(); | |
3880 | ||
9e730a78 | 3881 | return nPrintPos; |
9ce192d4 RD |
3882 | } |
3883 | ||
a834585d RD |
3884 | int Editor::TextWidth(int style, const char *text) { |
3885 | RefreshStyleData(); | |
9e730a78 | 3886 | AutoSurface surface(this); |
a834585d | 3887 | if (surface) { |
88a8b04e | 3888 | return surface->WidthText(vs.styles[style].font, text, istrlen(text)); |
a834585d RD |
3889 | } else { |
3890 | return 1; | |
3891 | } | |
3892 | } | |
3893 | ||
f6bcfd97 | 3894 | // Empty method is overridden on GTK+ to show / hide scrollbars |
9e730a78 | 3895 | void Editor::ReconfigureScrollBars() {} |
d134f170 | 3896 | |
1a2fb4cd | 3897 | void Editor::SetScrollBars() { |
9ce192d4 RD |
3898 | RefreshStyleData(); |
3899 | ||
a834585d RD |
3900 | int nMax = MaxScrollPos(); |
3901 | int nPage = LinesOnScreen(); | |
3902 | bool modified = ModifyScrollBars(nMax + nPage - 1, nPage); | |
1e9bafca RD |
3903 | if (modified) { |
3904 | DwellEnd(true); | |
3905 | } | |
9ce192d4 RD |
3906 | |
3907 | // TODO: ensure always showing as many lines as possible | |
3908 | // May not be, if, for example, window made larger | |
3909 | if (topLine > MaxScrollPos()) { | |
3910 | SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos())); | |
3911 | SetVerticalScrollPos(); | |
3912 | Redraw(); | |
3913 | } | |
a834585d RD |
3914 | if (modified) { |
3915 | if (!AbandonPaint()) | |
3916 | Redraw(); | |
3917 | } | |
9ce192d4 RD |
3918 | //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage); |
3919 | } | |
3920 | ||
1a2fb4cd | 3921 | void Editor::ChangeSize() { |
1dcf666d | 3922 | DropGraphics(false); |
1a2fb4cd RD |
3923 | SetScrollBars(); |
3924 | if (wrapState != eWrapNone) { | |
3925 | PRectangle rcTextArea = GetClientRectangle(); | |
3926 | rcTextArea.left = vs.fixedColumnWidth; | |
3927 | rcTextArea.right -= vs.rightMarginWidth; | |
3928 | if (wrapWidth != rcTextArea.Width()) { | |
3929 | NeedWrapping(); | |
3930 | Redraw(); | |
3931 | } | |
3932 | } | |
9ce192d4 RD |
3933 | } |
3934 | ||
9e96e16f RD |
3935 | int Editor::InsertSpace(int position, unsigned int spaces) { |
3936 | if (spaces > 0) { | |
3937 | std::string spaceText(spaces, ' '); | |
3938 | pdoc->InsertString(position, spaceText.c_str(), spaces); | |
3939 | position += spaces; | |
3940 | } | |
3941 | return position; | |
3942 | } | |
3943 | ||
9ce192d4 | 3944 | void Editor::AddChar(char ch) { |
f6bcfd97 BP |
3945 | char s[2]; |
3946 | s[0] = ch; | |
3947 | s[1] = '\0'; | |
3948 | AddCharUTF(s, 1); | |
3949 | } | |
3950 | ||
9e96e16f RD |
3951 | void Editor::FilterSelections() { |
3952 | if (!additionalSelectionTyping && (sel.Count() > 1)) { | |
3953 | SelectionRange rangeOnly = sel.RangeMain(); | |
3954 | InvalidateSelection(rangeOnly, true); | |
3955 | sel.SetSelection(rangeOnly); | |
3956 | } | |
3957 | } | |
3958 | ||
1dcf666d RD |
3959 | static bool cmpSelPtrs(const SelectionRange *a, const SelectionRange *b) { |
3960 | return *a < *b; | |
3961 | } | |
3962 | ||
7e0c58e9 | 3963 | // AddCharUTF inserts an array of bytes which may or may not be in UTF-8. |
1a2fb4cd | 3964 | void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { |
9e96e16f RD |
3965 | FilterSelections(); |
3966 | { | |
3967 | UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty() || inOverstrike); | |
1dcf666d RD |
3968 | |
3969 | std::vector<SelectionRange *> selPtrs; | |
3970 | for (size_t r = 0; r < sel.Count(); r++) { | |
3971 | selPtrs.push_back(&sel.Range(r)); | |
3972 | } | |
3973 | std::sort(selPtrs.begin(), selPtrs.end(), cmpSelPtrs); | |
3974 | ||
3975 | for (std::vector<SelectionRange *>::reverse_iterator rit = selPtrs.rbegin(); | |
3976 | rit != selPtrs.rend(); ++rit) { | |
3977 | SelectionRange *currentSel = *rit; | |
3978 | if (!RangeContainsProtected(currentSel->Start().Position(), | |
3979 | currentSel->End().Position())) { | |
3980 | int positionInsert = currentSel->Start().Position(); | |
3981 | if (!currentSel->Empty()) { | |
3982 | if (currentSel->Length()) { | |
3983 | pdoc->DeleteChars(positionInsert, currentSel->Length()); | |
3984 | currentSel->ClearVirtualSpace(); | |
9e96e16f RD |
3985 | } else { |
3986 | // Range is all virtual so collapse to start of virtual space | |
1dcf666d | 3987 | currentSel->MinimizeVirtualSpace(); |
9e96e16f RD |
3988 | } |
3989 | } else if (inOverstrike) { | |
3990 | if (positionInsert < pdoc->Length()) { | |
3991 | if (!IsEOLChar(pdoc->CharAt(positionInsert))) { | |
3992 | pdoc->DelChar(positionInsert); | |
1dcf666d | 3993 | currentSel->ClearVirtualSpace(); |
9e96e16f RD |
3994 | } |
3995 | } | |
3996 | } | |
1dcf666d | 3997 | positionInsert = InsertSpace(positionInsert, currentSel->caret.VirtualSpace()); |
9e96e16f | 3998 | if (pdoc->InsertString(positionInsert, s, len)) { |
1dcf666d RD |
3999 | currentSel->caret.SetPosition(positionInsert + len); |
4000 | currentSel->anchor.SetPosition(positionInsert + len); | |
9e96e16f | 4001 | } |
1dcf666d | 4002 | currentSel->ClearVirtualSpace(); |
9e96e16f RD |
4003 | // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information |
4004 | if (wrapState != eWrapNone) { | |
4005 | AutoSurface surface(this); | |
4006 | if (surface) { | |
1dcf666d RD |
4007 | if (WrapOneLine(surface, pdoc->LineFromPosition(positionInsert))) { |
4008 | SetScrollBars(); | |
4009 | SetVerticalScrollPos(); | |
4010 | Redraw(); | |
4011 | } | |
9e96e16f RD |
4012 | } |
4013 | } | |
9ce192d4 RD |
4014 | } |
4015 | } | |
4016 | } | |
7e0c58e9 | 4017 | if (wrapState != eWrapNone) { |
7e0c58e9 RD |
4018 | SetScrollBars(); |
4019 | } | |
9e96e16f RD |
4020 | ThinRectangularRange(); |
4021 | // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information | |
9ce192d4 | 4022 | EnsureCaretVisible(); |
d134f170 RD |
4023 | // Avoid blinking during rapid typing: |
4024 | ShowCaretAtCurrentPosition(); | |
1dcf666d RD |
4025 | if ((caretSticky == SC_CARETSTICKY_OFF) || |
4026 | ((caretSticky == SC_CARETSTICKY_WHITESPACE) && !IsAllSpacesOrTabs(s, len))) { | |
1e9bafca RD |
4027 | SetLastXChosen(); |
4028 | } | |
65ec6247 | 4029 | |
1a2fb4cd | 4030 | if (treatAsDBCS) { |
e4f0b986 | 4031 | NotifyChar((static_cast<unsigned char>(s[0]) << 8) | |
7e0c58e9 | 4032 | static_cast<unsigned char>(s[1])); |
65ec6247 | 4033 | } else { |
1a2fb4cd RD |
4034 | int byte = static_cast<unsigned char>(s[0]); |
4035 | if ((byte < 0xC0) || (1 == len)) { | |
4036 | // Handles UTF-8 characters between 0x01 and 0x7F and single byte | |
4037 | // characters when not in UTF-8 mode. | |
4038 | // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid | |
4039 | // characters representing themselves. | |
4040 | } else { | |
4041 | // Unroll 1 to 3 byte UTF-8 sequences. See reference data at: | |
4042 | // http://www.cl.cam.ac.uk/~mgk25/unicode.html | |
4043 | // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt | |
4044 | if (byte < 0xE0) { | |
4045 | int byte2 = static_cast<unsigned char>(s[1]); | |
4046 | if ((byte2 & 0xC0) == 0x80) { | |
4047 | // Two-byte-character lead-byte followed by a trail-byte. | |
4048 | byte = (((byte & 0x1F) << 6) | (byte2 & 0x3F)); | |
4049 | } | |
4050 | // A two-byte-character lead-byte not followed by trail-byte | |
4051 | // represents itself. | |
4052 | } else if (byte < 0xF0) { | |
4053 | int byte2 = static_cast<unsigned char>(s[1]); | |
4054 | int byte3 = static_cast<unsigned char>(s[2]); | |
4055 | if (((byte2 & 0xC0) == 0x80) && ((byte3 & 0xC0) == 0x80)) { | |
4056 | // Three-byte-character lead byte followed by two trail bytes. | |
4057 | byte = (((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | | |
9e730a78 | 4058 | (byte3 & 0x3F)); |
1a2fb4cd RD |
4059 | } |
4060 | // A three-byte-character lead-byte not followed by two trail-bytes | |
4061 | // represents itself. | |
65ec6247 | 4062 | } |
65ec6247 | 4063 | } |
1a2fb4cd | 4064 | NotifyChar(byte); |
65ec6247 | 4065 | } |
9e96e16f RD |
4066 | |
4067 | if (recordingMacro) { | |
4068 | NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(s)); | |
4069 | } | |
9ce192d4 RD |
4070 | } |
4071 | ||
1dcf666d RD |
4072 | void Editor::InsertPaste(SelectionPosition selStart, const char *text, int len) { |
4073 | if (multiPasteMode == SC_MULTIPASTE_ONCE) { | |
4074 | selStart = SelectionPosition(InsertSpace(selStart.Position(), selStart.VirtualSpace())); | |
4075 | if (pdoc->InsertString(selStart.Position(), text, len)) { | |
4076 | SetEmptySelection(selStart.Position() + len); | |
4077 | } | |
4078 | } else { | |
4079 | // SC_MULTIPASTE_EACH | |
4080 | for (size_t r=0; r<sel.Count(); r++) { | |
4081 | if (!RangeContainsProtected(sel.Range(r).Start().Position(), | |
4082 | sel.Range(r).End().Position())) { | |
4083 | int positionInsert = sel.Range(r).Start().Position(); | |
4084 | if (!sel.Range(r).Empty()) { | |
4085 | if (sel.Range(r).Length()) { | |
4086 | pdoc->DeleteChars(positionInsert, sel.Range(r).Length()); | |
4087 | sel.Range(r).ClearVirtualSpace(); | |
4088 | } else { | |
4089 | // Range is all virtual so collapse to start of virtual space | |
4090 | sel.Range(r).MinimizeVirtualSpace(); | |
4091 | } | |
4092 | } | |
4093 | positionInsert = InsertSpace(positionInsert, sel.Range(r).caret.VirtualSpace()); | |
4094 | if (pdoc->InsertString(positionInsert, text, len)) { | |
4095 | sel.Range(r).caret.SetPosition(positionInsert + len); | |
4096 | sel.Range(r).anchor.SetPosition(positionInsert + len); | |
4097 | } | |
4098 | sel.Range(r).ClearVirtualSpace(); | |
4099 | } | |
4100 | } | |
4101 | } | |
4102 | } | |
4103 | ||
4104 | void Editor::ClearSelection(bool retainMultipleSelections) { | |
4105 | if (!sel.IsRectangular() && !retainMultipleSelections) | |
9e96e16f RD |
4106 | FilterSelections(); |
4107 | UndoGroup ug(pdoc); | |
4108 | for (size_t r=0; r<sel.Count(); r++) { | |
4109 | if (!sel.Range(r).Empty()) { | |
4110 | if (!RangeContainsProtected(sel.Range(r).Start().Position(), | |
4111 | sel.Range(r).End().Position())) { | |
4112 | pdoc->DeleteChars(sel.Range(r).Start().Position(), | |
4113 | sel.Range(r).Length()); | |
4114 | sel.Range(r) = sel.Range(r).Start(); | |
8e54aaed | 4115 | } |
9ce192d4 | 4116 | } |
9ce192d4 | 4117 | } |
9e96e16f RD |
4118 | ThinRectangularRange(); |
4119 | sel.RemoveDuplicates(); | |
4120 | ClaimSelection(); | |
9ce192d4 RD |
4121 | } |
4122 | ||
4123 | void Editor::ClearAll() { | |
9e96e16f RD |
4124 | { |
4125 | UndoGroup ug(pdoc); | |
4126 | if (0 != pdoc->Length()) { | |
4127 | pdoc->DeleteChars(0, pdoc->Length()); | |
4128 | } | |
4129 | if (!pdoc->IsReadOnly()) { | |
4130 | cs.Clear(); | |
4131 | pdoc->AnnotationClearAll(); | |
4132 | pdoc->MarginClearAll(); | |
4133 | } | |
a834585d | 4134 | } |
9e96e16f | 4135 | sel.Clear(); |
9ce192d4 RD |
4136 | SetTopLine(0); |
4137 | SetVerticalScrollPos(); | |
1e9bafca | 4138 | InvalidateStyleRedraw(); |
9ce192d4 RD |
4139 | } |
4140 | ||
d134f170 | 4141 | void Editor::ClearDocumentStyle() { |
9e96e16f RD |
4142 | Decoration *deco = pdoc->decorations.root; |
4143 | while (deco) { | |
4144 | // Save next in case deco deleted | |
4145 | Decoration *decoNext = deco->next; | |
4146 | if (deco->indicator < INDIC_CONTAINER) { | |
4147 | pdoc->decorations.SetCurrentIndicator(deco->indicator); | |
4148 | pdoc->DecorationFillRange(0, 0, pdoc->Length()); | |
4149 | } | |
4150 | deco = decoNext; | |
4151 | } | |
d134f170 RD |
4152 | pdoc->StartStyling(0, '\377'); |
4153 | pdoc->SetStyleFor(pdoc->Length(), 0); | |
4154 | cs.ShowAll(); | |
4155 | pdoc->ClearLevels(); | |
4156 | } | |
4157 | ||
9e96e16f RD |
4158 | void Editor::CopyAllowLine() { |
4159 | SelectionText selectedText; | |
4160 | CopySelectionRange(&selectedText, true); | |
4161 | CopyToClipboard(selectedText); | |
4162 | } | |
4163 | ||
9ce192d4 | 4164 | void Editor::Cut() { |
7e0c58e9 | 4165 | pdoc->CheckReadOnly(); |
9e730a78 | 4166 | if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) { |
65ec6247 RD |
4167 | Copy(); |
4168 | ClearSelection(); | |
4169 | } | |
9ce192d4 RD |
4170 | } |
4171 | ||
9e96e16f | 4172 | void Editor::PasteRectangular(SelectionPosition pos, const char *ptr, int len) { |
9e730a78 | 4173 | if (pdoc->IsReadOnly() || SelectionContainsProtected()) { |
65ec6247 RD |
4174 | return; |
4175 | } | |
9e96e16f RD |
4176 | sel.Clear(); |
4177 | sel.RangeMain() = SelectionRange(pos); | |
4178 | int line = pdoc->LineFromPosition(sel.MainCaret()); | |
4179 | UndoGroup ug(pdoc); | |
4180 | sel.RangeMain().caret = SelectionPosition( | |
4181 | InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); | |
4182 | int xInsert = XFromPosition(sel.RangeMain().caret); | |
9ce192d4 | 4183 | bool prevCr = false; |
9e96e16f RD |
4184 | while ((len > 0) && IsEOLChar(ptr[len-1])) |
4185 | len--; | |
d134f170 | 4186 | for (int i = 0; i < len; i++) { |
9e730a78 | 4187 | if (IsEOLChar(ptr[i])) { |
d134f170 | 4188 | if ((ptr[i] == '\r') || (!prevCr)) |
9ce192d4 RD |
4189 | line++; |
4190 | if (line >= pdoc->LinesTotal()) { | |
4191 | if (pdoc->eolMode != SC_EOL_LF) | |
4192 | pdoc->InsertChar(pdoc->Length(), '\r'); | |
4193 | if (pdoc->eolMode != SC_EOL_CR) | |
4194 | pdoc->InsertChar(pdoc->Length(), '\n'); | |
4195 | } | |
65ec6247 | 4196 | // Pad the end of lines with spaces if required |
9e96e16f RD |
4197 | sel.RangeMain().caret.SetPosition(PositionFromLineX(line, xInsert)); |
4198 | if ((XFromPosition(sel.MainCaret()) < xInsert) && (i + 1 < len)) { | |
4199 | while (XFromPosition(sel.MainCaret()) < xInsert) { | |
4200 | pdoc->InsertChar(sel.MainCaret(), ' '); | |
4201 | sel.RangeMain().caret.Add(1); | |
65ec6247 | 4202 | } |
65ec6247 | 4203 | } |
9ce192d4 RD |
4204 | prevCr = ptr[i] == '\r'; |
4205 | } else { | |
9e96e16f RD |
4206 | pdoc->InsertString(sel.MainCaret(), ptr + i, 1); |
4207 | sel.RangeMain().caret.Add(1); | |
9ce192d4 RD |
4208 | prevCr = false; |
4209 | } | |
4210 | } | |
1a2fb4cd | 4211 | SetEmptySelection(pos); |
9ce192d4 RD |
4212 | } |
4213 | ||
65ec6247 | 4214 | bool Editor::CanPaste() { |
9e730a78 | 4215 | return !pdoc->IsReadOnly() && !SelectionContainsProtected(); |
65ec6247 RD |
4216 | } |
4217 | ||
9ce192d4 | 4218 | void Editor::Clear() { |
9e96e16f RD |
4219 | // If multiple selections, don't delete EOLS |
4220 | if (sel.Empty()) { | |
1dcf666d RD |
4221 | bool singleVirtual = false; |
4222 | if ((sel.Count() == 1) && | |
4223 | !RangeContainsProtected(sel.MainCaret(), sel.MainCaret() + 1) && | |
4224 | sel.RangeMain().Start().VirtualSpace()) { | |
4225 | singleVirtual = true; | |
4226 | } | |
4227 | UndoGroup ug(pdoc, (sel.Count() > 1) || singleVirtual); | |
9e96e16f RD |
4228 | for (size_t r=0; r<sel.Count(); r++) { |
4229 | if (!RangeContainsProtected(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1)) { | |
4230 | if (sel.Range(r).Start().VirtualSpace()) { | |
4231 | if (sel.Range(r).anchor < sel.Range(r).caret) | |
4232 | sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).anchor.Position(), sel.Range(r).anchor.VirtualSpace())); | |
4233 | else | |
4234 | sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).caret.Position(), sel.Range(r).caret.VirtualSpace())); | |
4235 | } | |
4236 | if ((sel.Count() == 1) || !IsEOLChar(pdoc->CharAt(sel.Range(r).caret.Position()))) { | |
4237 | pdoc->DelChar(sel.Range(r).caret.Position()); | |
4238 | sel.Range(r).ClearVirtualSpace(); | |
4239 | } // else multiple selection so don't eat line ends | |
4240 | } else { | |
4241 | sel.Range(r).ClearVirtualSpace(); | |
4242 | } | |
9e730a78 | 4243 | } |
9ce192d4 RD |
4244 | } else { |
4245 | ClearSelection(); | |
4246 | } | |
9e96e16f | 4247 | sel.RemoveDuplicates(); |
9ce192d4 RD |
4248 | } |
4249 | ||
4250 | void Editor::SelectAll() { | |
9e96e16f | 4251 | sel.Clear(); |
9ce192d4 RD |
4252 | SetSelection(0, pdoc->Length()); |
4253 | Redraw(); | |
4254 | } | |
4255 | ||
4256 | void Editor::Undo() { | |
4257 | if (pdoc->CanUndo()) { | |
65ec6247 | 4258 | InvalidateCaret(); |
9ce192d4 | 4259 | int newPos = pdoc->Undo(); |
1e9bafca RD |
4260 | if (newPos >= 0) |
4261 | SetEmptySelection(newPos); | |
9ce192d4 RD |
4262 | EnsureCaretVisible(); |
4263 | } | |
4264 | } | |
4265 | ||
4266 | void Editor::Redo() { | |
4267 | if (pdoc->CanRedo()) { | |
4268 | int newPos = pdoc->Redo(); | |
1e9bafca RD |
4269 | if (newPos >= 0) |
4270 | SetEmptySelection(newPos); | |
9ce192d4 RD |
4271 | EnsureCaretVisible(); |
4272 | } | |
4273 | } | |
4274 | ||
4275 | void Editor::DelChar() { | |
9e96e16f RD |
4276 | if (!RangeContainsProtected(sel.MainCaret(), sel.MainCaret() + 1)) { |
4277 | pdoc->DelChar(sel.MainCaret()); | |
9e730a78 | 4278 | } |
d134f170 RD |
4279 | // Avoid blinking during rapid typing: |
4280 | ShowCaretAtCurrentPosition(); | |
9ce192d4 RD |
4281 | } |
4282 | ||
1a2fb4cd | 4283 | void Editor::DelCharBack(bool allowLineStartDeletion) { |
9e96e16f RD |
4284 | if (!sel.IsRectangular()) |
4285 | FilterSelections(); | |
4286 | if (sel.IsRectangular()) | |
4287 | allowLineStartDeletion = false; | |
4288 | UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty()); | |
4289 | if (sel.Empty()) { | |
4290 | for (size_t r=0; r<sel.Count(); r++) { | |
1dcf666d | 4291 | if (!RangeContainsProtected(sel.Range(r).caret.Position() - 1, sel.Range(r).caret.Position())) { |
9e96e16f RD |
4292 | if (sel.Range(r).caret.VirtualSpace()) { |
4293 | sel.Range(r).caret.SetVirtualSpace(sel.Range(r).caret.VirtualSpace() - 1); | |
4294 | sel.Range(r).anchor.SetVirtualSpace(sel.Range(r).caret.VirtualSpace()); | |
1a2fb4cd | 4295 | } else { |
9e96e16f RD |
4296 | int lineCurrentPos = pdoc->LineFromPosition(sel.Range(r).caret.Position()); |
4297 | if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != sel.Range(r).caret.Position())) { | |
4298 | if (pdoc->GetColumn(sel.Range(r).caret.Position()) <= pdoc->GetLineIndentation(lineCurrentPos) && | |
4299 | pdoc->GetColumn(sel.Range(r).caret.Position()) > 0 && pdoc->backspaceUnindents) { | |
4300 | UndoGroup ugInner(pdoc, !ug.Needed()); | |
4301 | int indentation = pdoc->GetLineIndentation(lineCurrentPos); | |
4302 | int indentationStep = pdoc->IndentSize(); | |
4303 | if (indentation % indentationStep == 0) { | |
4304 | pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep); | |
4305 | } else { | |
4306 | pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep)); | |
4307 | } | |
4308 | // SetEmptySelection | |
4309 | sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos), | |
4310 | pdoc->GetLineIndentPosition(lineCurrentPos)); | |
4311 | } else { | |
4312 | pdoc->DelCharBack(sel.Range(r).caret.Position()); | |
4313 | } | |
4314 | } | |
1a2fb4cd | 4315 | } |
9e96e16f RD |
4316 | } else { |
4317 | sel.Range(r).ClearVirtualSpace(); | |
65ec6247 | 4318 | } |
65ec6247 | 4319 | } |
9ce192d4 RD |
4320 | } else { |
4321 | ClearSelection(); | |
9ce192d4 | 4322 | } |
9e96e16f | 4323 | sel.RemoveDuplicates(); |
d134f170 RD |
4324 | // Avoid blinking during rapid typing: |
4325 | ShowCaretAtCurrentPosition(); | |
9ce192d4 RD |
4326 | } |
4327 | ||
d134f170 RD |
4328 | void Editor::NotifyFocus(bool) {} |
4329 | ||
1dcf666d RD |
4330 | void Editor::SetCtrlID(int identifier) { |
4331 | ctrlID = identifier; | |
4332 | } | |
4333 | ||
f6bcfd97 | 4334 | void Editor::NotifyStyleToNeeded(int endStyleNeeded) { |
1e9bafca | 4335 | SCNotification scn = {0}; |
9ce192d4 RD |
4336 | scn.nmhdr.code = SCN_STYLENEEDED; |
4337 | scn.position = endStyleNeeded; | |
4338 | NotifyParent(scn); | |
4339 | } | |
4340 | ||
1dcf666d | 4341 | void Editor::NotifyStyleNeeded(Document *, void *, int endStyleNeeded) { |
f6bcfd97 BP |
4342 | NotifyStyleToNeeded(endStyleNeeded); |
4343 | } | |
4344 | ||
1dcf666d RD |
4345 | void Editor::NotifyLexerChanged(Document *, void *) { |
4346 | } | |
4347 | ||
4348 | void Editor::NotifyErrorOccurred(Document *, void *, int status) { | |
4349 | errorStatus = status; | |
4350 | } | |
4351 | ||
65ec6247 | 4352 | void Editor::NotifyChar(int ch) { |
1e9bafca | 4353 | SCNotification scn = {0}; |
9ce192d4 RD |
4354 | scn.nmhdr.code = SCN_CHARADDED; |
4355 | scn.ch = ch; | |
4356 | NotifyParent(scn); | |
9ce192d4 RD |
4357 | } |
4358 | ||
4359 | void Editor::NotifySavePoint(bool isSavePoint) { | |
1e9bafca | 4360 | SCNotification scn = {0}; |
9ce192d4 RD |
4361 | if (isSavePoint) { |
4362 | scn.nmhdr.code = SCN_SAVEPOINTREACHED; | |
4363 | } else { | |
4364 | scn.nmhdr.code = SCN_SAVEPOINTLEFT; | |
4365 | } | |
4366 | NotifyParent(scn); | |
4367 | } | |
4368 | ||
4369 | void Editor::NotifyModifyAttempt() { | |
1e9bafca | 4370 | SCNotification scn = {0}; |
9ce192d4 RD |
4371 | scn.nmhdr.code = SCN_MODIFYATTEMPTRO; |
4372 | NotifyParent(scn); | |
4373 | } | |
4374 | ||
7e0c58e9 | 4375 | void Editor::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt) { |
1e9bafca | 4376 | SCNotification scn = {0}; |
9ce192d4 | 4377 | scn.nmhdr.code = SCN_DOUBLECLICK; |
7e0c58e9 | 4378 | scn.line = LineFromLocation(pt); |
9e96e16f | 4379 | scn.position = PositionFromLocation(pt, true); |
7e0c58e9 RD |
4380 | scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | |
4381 | (alt ? SCI_ALT : 0); | |
9ce192d4 RD |
4382 | NotifyParent(scn); |
4383 | } | |
4384 | ||
9e730a78 | 4385 | void Editor::NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt) { |
1e9bafca | 4386 | SCNotification scn = {0}; |
9e730a78 RD |
4387 | scn.nmhdr.code = SCN_HOTSPOTDOUBLECLICK; |
4388 | scn.position = position; | |
4389 | scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | | |
7e0c58e9 | 4390 | (alt ? SCI_ALT : 0); |
9e730a78 RD |
4391 | NotifyParent(scn); |
4392 | } | |
4393 | ||
4394 | void Editor::NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt) { | |
1e9bafca | 4395 | SCNotification scn = {0}; |
9e730a78 RD |
4396 | scn.nmhdr.code = SCN_HOTSPOTCLICK; |
4397 | scn.position = position; | |
4398 | scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | | |
7e0c58e9 | 4399 | (alt ? SCI_ALT : 0); |
9e730a78 RD |
4400 | NotifyParent(scn); |
4401 | } | |
4402 | ||
1dcf666d RD |
4403 | void Editor::NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool alt) { |
4404 | SCNotification scn = {0}; | |
4405 | scn.nmhdr.code = SCN_HOTSPOTRELEASECLICK; | |
4406 | scn.position = position; | |
4407 | scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | | |
4408 | (alt ? SCI_ALT : 0); | |
4409 | NotifyParent(scn); | |
4410 | } | |
4411 | ||
9ce192d4 | 4412 | void Editor::NotifyUpdateUI() { |
1e9bafca | 4413 | SCNotification scn = {0}; |
9ce192d4 | 4414 | scn.nmhdr.code = SCN_UPDATEUI; |
1dcf666d | 4415 | scn.updated = needUpdateUI; |
9ce192d4 RD |
4416 | NotifyParent(scn); |
4417 | } | |
4418 | ||
65ec6247 | 4419 | void Editor::NotifyPainted() { |
1e9bafca | 4420 | SCNotification scn = {0}; |
65ec6247 RD |
4421 | scn.nmhdr.code = SCN_PAINTED; |
4422 | NotifyParent(scn); | |
4423 | } | |
4424 | ||
7e0c58e9 RD |
4425 | void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt) { |
4426 | int mask = pdoc->decorations.AllOnFor(position); | |
4427 | if ((click && mask) || pdoc->decorations.clickNotified) { | |
4428 | SCNotification scn = {0}; | |
4429 | pdoc->decorations.clickNotified = click; | |
4430 | scn.nmhdr.code = click ? SCN_INDICATORCLICK : SCN_INDICATORRELEASE; | |
4431 | scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0); | |
4432 | scn.position = position; | |
4433 | NotifyParent(scn); | |
4434 | } | |
4435 | } | |
4436 | ||
9ce192d4 RD |
4437 | bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) { |
4438 | int marginClicked = -1; | |
4439 | int x = 0; | |
d134f170 | 4440 | for (int margin = 0; margin < ViewStyle::margins; margin++) { |
1dcf666d | 4441 | if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width)) |
9ce192d4 RD |
4442 | marginClicked = margin; |
4443 | x += vs.ms[margin].width; | |
4444 | } | |
4445 | if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) { | |
1e9bafca | 4446 | SCNotification scn = {0}; |
9ce192d4 RD |
4447 | scn.nmhdr.code = SCN_MARGINCLICK; |
4448 | scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | | |
7e0c58e9 | 4449 | (alt ? SCI_ALT : 0); |
9ce192d4 RD |
4450 | scn.position = pdoc->LineStart(LineFromLocation(pt)); |
4451 | scn.margin = marginClicked; | |
4452 | NotifyParent(scn); | |
4453 | return true; | |
4454 | } else { | |
4455 | return false; | |
4456 | } | |
4457 | } | |
4458 | ||
4459 | void Editor::NotifyNeedShown(int pos, int len) { | |
1e9bafca | 4460 | SCNotification scn = {0}; |
9ce192d4 RD |
4461 | scn.nmhdr.code = SCN_NEEDSHOWN; |
4462 | scn.position = pos; | |
4463 | scn.length = len; | |
4464 | NotifyParent(scn); | |
4465 | } | |
4466 | ||
65ec6247 | 4467 | void Editor::NotifyDwelling(Point pt, bool state) { |
1e9bafca | 4468 | SCNotification scn = {0}; |
65ec6247 | 4469 | scn.nmhdr.code = state ? SCN_DWELLSTART : SCN_DWELLEND; |
9e96e16f | 4470 | scn.position = PositionFromLocation(pt, true); |
65ec6247 RD |
4471 | scn.x = pt.x; |
4472 | scn.y = pt.y; | |
4473 | NotifyParent(scn); | |
4474 | } | |
4475 | ||
a834585d | 4476 | void Editor::NotifyZoom() { |
1e9bafca | 4477 | SCNotification scn = {0}; |
a834585d RD |
4478 | scn.nmhdr.code = SCN_ZOOM; |
4479 | NotifyParent(scn); | |
4480 | } | |
4481 | ||
9ce192d4 | 4482 | // Notifications from document |
1dcf666d | 4483 | void Editor::NotifyModifyAttempt(Document *, void *) { |
9ce192d4 RD |
4484 | //Platform::DebugPrintf("** Modify Attempt\n"); |
4485 | NotifyModifyAttempt(); | |
4486 | } | |
4487 | ||
1dcf666d | 4488 | void Editor::NotifySavePoint(Document *, void *, bool atSavePoint) { |
9ce192d4 RD |
4489 | //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off"); |
4490 | NotifySavePoint(atSavePoint); | |
4491 | } | |
4492 | ||
1a2fb4cd | 4493 | void Editor::CheckModificationForWrap(DocModification mh) { |
7e0c58e9 | 4494 | if (mh.modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) { |
a834585d | 4495 | llc.Invalidate(LineLayout::llCheckTextAndStyle); |
1dcf666d RD |
4496 | int lineDoc = pdoc->LineFromPosition(mh.position); |
4497 | int lines = Platform::Maximum(0, mh.linesAdded); | |
1a2fb4cd | 4498 | if (wrapState != eWrapNone) { |
b8193d80 | 4499 | NeedWrapping(lineDoc, lineDoc + lines + 1); |
1a2fb4cd | 4500 | } |
1dcf666d | 4501 | RefreshStyleData(); |
9e96e16f | 4502 | // Fix up annotation heights |
9e96e16f | 4503 | SetAnnotationHeights(lineDoc, lineDoc + lines + 2); |
1a2fb4cd RD |
4504 | } |
4505 | } | |
4506 | ||
4507 | // Move a position so it is still after the same character as before the insertion. | |
4508 | static inline int MovePositionForInsertion(int position, int startInsertion, int length) { | |
4509 | if (position > startInsertion) { | |
4510 | return position + length; | |
4511 | } | |
4512 | return position; | |
4513 | } | |
4514 | ||
4515 | // Move a position so it is still after the same character as before the deletion if that | |
4516 | // character is still present else after the previous surviving character. | |
4517 | static inline int MovePositionForDeletion(int position, int startDeletion, int length) { | |
4518 | if (position > startDeletion) { | |
4519 | int endDeletion = startDeletion + length; | |
4520 | if (position > endDeletion) { | |
4521 | return position - length; | |
4522 | } else { | |
4523 | return startDeletion; | |
4524 | } | |
4525 | } else { | |
4526 | return position; | |
4527 | } | |
4528 | } | |
4529 | ||
1dcf666d RD |
4530 | void Editor::NotifyModified(Document *, DocModification mh, void *) { |
4531 | ContainerNeedsUpdate(SC_UPDATE_CONTENT); | |
9ce192d4 RD |
4532 | if (paintState == painting) { |
4533 | CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length)); | |
a834585d | 4534 | } |
7e0c58e9 RD |
4535 | if (mh.modificationType & SC_MOD_CHANGELINESTATE) { |
4536 | if (paintState == painting) { | |
4537 | CheckForChangeOutsidePaint( | |
1dcf666d RD |
4538 | Range(pdoc->LineStart(mh.line), pdoc->LineStart(mh.line + 1))); |
4539 | } else { | |
4540 | // Could check that change is before last visible line. | |
4541 | Redraw(); | |
4542 | } | |
4543 | } | |
4544 | if (mh.modificationType & SC_MOD_LEXERSTATE) { | |
4545 | if (paintState == painting) { | |
4546 | CheckForChangeOutsidePaint( | |
4547 | Range(mh.position, mh.position + mh.length)); | |
7e0c58e9 | 4548 | } else { |
7e0c58e9 RD |
4549 | Redraw(); |
4550 | } | |
4551 | } | |
4552 | if (mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) { | |
4553 | if (mh.modificationType & SC_MOD_CHANGESTYLE) { | |
4554 | pdoc->IncrementStyleClock(); | |
4555 | } | |
a834585d | 4556 | if (paintState == notPainting) { |
9ce192d4 RD |
4557 | if (mh.position < pdoc->LineStart(topLine)) { |
4558 | // Styling performed before this view | |
4559 | Redraw(); | |
4560 | } else { | |
4561 | InvalidateRange(mh.position, mh.position + mh.length); | |
4562 | } | |
a834585d | 4563 | } |
7e0c58e9 RD |
4564 | if (mh.modificationType & SC_MOD_CHANGESTYLE) { |
4565 | llc.Invalidate(LineLayout::llCheckTextAndStyle); | |
4566 | } | |
a834585d RD |
4567 | } else { |
4568 | // Move selection and brace highlights | |
4569 | if (mh.modificationType & SC_MOD_INSERTTEXT) { | |
9e96e16f | 4570 | sel.MovePositions(true, mh.position, mh.length); |
a834585d RD |
4571 | braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length); |
4572 | braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length); | |
4573 | } else if (mh.modificationType & SC_MOD_DELETETEXT) { | |
9e96e16f | 4574 | sel.MovePositions(false, mh.position, mh.length); |
a834585d RD |
4575 | braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length); |
4576 | braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length); | |
4577 | } | |
1dcf666d | 4578 | if ((mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) && cs.HiddenLines()) { |
a834585d RD |
4579 | // Some lines are hidden so may need shown. |
4580 | // TODO: check if the modified area is hidden. | |
4581 | if (mh.modificationType & SC_MOD_BEFOREINSERT) { | |
1dcf666d RD |
4582 | int lineOfPos = pdoc->LineFromPosition(mh.position); |
4583 | bool insertingNewLine = false; | |
4584 | for (int i=0; i < mh.length; i++) { | |
4585 | if ((mh.text[i] == '\n') || (mh.text[i] == '\r')) | |
4586 | insertingNewLine = true; | |
4587 | } | |
4588 | if (insertingNewLine && (mh.position != pdoc->LineStart(lineOfPos))) | |
4589 | NotifyNeedShown(mh.position, pdoc->LineStart(lineOfPos+1) - mh.position); | |
4590 | else | |
4591 | NotifyNeedShown(mh.position, 0); | |
a834585d RD |
4592 | } else if (mh.modificationType & SC_MOD_BEFOREDELETE) { |
4593 | NotifyNeedShown(mh.position, mh.length); | |
9ce192d4 | 4594 | } |
a834585d RD |
4595 | } |
4596 | if (mh.linesAdded != 0) { | |
4597 | // Update contraction state for inserted and removed lines | |
4598 | // lineOfPos should be calculated in context of state before modification, shouldn't it | |
4599 | int lineOfPos = pdoc->LineFromPosition(mh.position); | |
4600 | if (mh.linesAdded > 0) { | |
4601 | cs.InsertLines(lineOfPos, mh.linesAdded); | |
4602 | } else { | |
4603 | cs.DeleteLines(lineOfPos, -mh.linesAdded); | |
d134f170 | 4604 | } |
8e54aaed | 4605 | } |
9e96e16f RD |
4606 | if (mh.modificationType & SC_MOD_CHANGEANNOTATION) { |
4607 | int lineDoc = pdoc->LineFromPosition(mh.position); | |
4608 | if (vs.annotationVisible) { | |
4609 | cs.SetHeight(lineDoc, cs.GetHeight(lineDoc) + mh.annotationLinesAdded); | |
1dcf666d | 4610 | Redraw(); |
9e96e16f RD |
4611 | } |
4612 | } | |
8e54aaed RD |
4613 | CheckModificationForWrap(mh); |
4614 | if (mh.linesAdded != 0) { | |
a834585d | 4615 | // Avoid scrolling of display if change before current display |
1e9bafca | 4616 | if (mh.position < posTopLine && !CanDeferToLastStep(mh)) { |
a834585d RD |
4617 | int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos()); |
4618 | if (newTop != topLine) { | |
4619 | SetTopLine(newTop); | |
4620 | SetVerticalScrollPos(); | |
9ce192d4 | 4621 | } |
a834585d | 4622 | } |
d134f170 | 4623 | |
a834585d RD |
4624 | //Platform::DebugPrintf("** %x Doc Changed\n", this); |
4625 | // TODO: could invalidate from mh.startModification to end of screen | |
4626 | //InvalidateRange(mh.position, mh.position + mh.length); | |
1e9bafca | 4627 | if (paintState == notPainting && !CanDeferToLastStep(mh)) { |
1dcf666d | 4628 | QueueStyling(pdoc->Length()); |
9ce192d4 | 4629 | Redraw(); |
a834585d RD |
4630 | } |
4631 | } else { | |
4632 | //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this, | |
4633 | // mh.position, mh.position + mh.length); | |
1e9bafca | 4634 | if (paintState == notPainting && mh.length && !CanEliminate(mh)) { |
1dcf666d | 4635 | QueueStyling(mh.position + mh.length); |
9ce192d4 RD |
4636 | InvalidateRange(mh.position, mh.position + mh.length); |
4637 | } | |
4638 | } | |
a834585d | 4639 | } |
9ce192d4 | 4640 | |
1e9bafca | 4641 | if (mh.linesAdded != 0 && !CanDeferToLastStep(mh)) { |
9ce192d4 RD |
4642 | SetScrollBars(); |
4643 | } | |
4644 | ||
9e96e16f | 4645 | if ((mh.modificationType & SC_MOD_CHANGEMARKER) || (mh.modificationType & SC_MOD_CHANGEMARGIN)) { |
1dcf666d | 4646 | if ((!willRedrawAll) && ((paintState == notPainting) || !PaintContainsMargin())) { |
1e9bafca RD |
4647 | if (mh.modificationType & SC_MOD_CHANGEFOLD) { |
4648 | // Fold changes can affect the drawing of following lines so redraw whole margin | |
1dcf666d | 4649 | RedrawSelMargin(highlightDelimiter.isEnabled ? -1 : mh.line-1, true); |
1e9bafca RD |
4650 | } else { |
4651 | RedrawSelMargin(mh.line); | |
4652 | } | |
a834585d | 4653 | } |
f6bcfd97 | 4654 | } |
d134f170 | 4655 | |
1e9bafca RD |
4656 | // NOW pay the piper WRT "deferred" visual updates |
4657 | if (IsLastStep(mh)) { | |
4658 | SetScrollBars(); | |
4659 | Redraw(); | |
4660 | } | |
4661 | ||
9ce192d4 RD |
4662 | // If client wants to see this modification |
4663 | if (mh.modificationType & modEventMask) { | |
7e0c58e9 | 4664 | if ((mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) == 0) { |
9ce192d4 RD |
4665 | // Real modification made to text of document. |
4666 | NotifyChange(); // Send EN_CHANGE | |
4667 | } | |
d134f170 | 4668 | |
1e9bafca | 4669 | SCNotification scn = {0}; |
9ce192d4 RD |
4670 | scn.nmhdr.code = SCN_MODIFIED; |
4671 | scn.position = mh.position; | |
4672 | scn.modificationType = mh.modificationType; | |
4673 | scn.text = mh.text; | |
4674 | scn.length = mh.length; | |
4675 | scn.linesAdded = mh.linesAdded; | |
4676 | scn.line = mh.line; | |
4677 | scn.foldLevelNow = mh.foldLevelNow; | |
4678 | scn.foldLevelPrev = mh.foldLevelPrev; | |
9e96e16f RD |
4679 | scn.token = mh.token; |
4680 | scn.annotationLinesAdded = mh.annotationLinesAdded; | |
9ce192d4 RD |
4681 | NotifyParent(scn); |
4682 | } | |
4683 | } | |
4684 | ||
f6bcfd97 | 4685 | void Editor::NotifyDeleted(Document *, void *) { |
9ce192d4 RD |
4686 | /* Do nothing */ |
4687 | } | |
4688 | ||
1e9bafca | 4689 | void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { |
9ce192d4 RD |
4690 | |
4691 | // Enumerates all macroable messages | |
4692 | switch (iMessage) { | |
d134f170 RD |
4693 | case SCI_CUT: |
4694 | case SCI_COPY: | |
4695 | case SCI_PASTE: | |
4696 | case SCI_CLEAR: | |
4697 | case SCI_REPLACESEL: | |
9ce192d4 RD |
4698 | case SCI_ADDTEXT: |
4699 | case SCI_INSERTTEXT: | |
9e730a78 | 4700 | case SCI_APPENDTEXT: |
9ce192d4 RD |
4701 | case SCI_CLEARALL: |
4702 | case SCI_SELECTALL: | |
4703 | case SCI_GOTOLINE: | |
4704 | case SCI_GOTOPOS: | |
4705 | case SCI_SEARCHANCHOR: | |
4706 | case SCI_SEARCHNEXT: | |
4707 | case SCI_SEARCHPREV: | |
4708 | case SCI_LINEDOWN: | |
4709 | case SCI_LINEDOWNEXTEND: | |
9e730a78 RD |
4710 | case SCI_PARADOWN: |
4711 | case SCI_PARADOWNEXTEND: | |
9ce192d4 RD |
4712 | case SCI_LINEUP: |
4713 | case SCI_LINEUPEXTEND: | |
9e730a78 RD |
4714 | case SCI_PARAUP: |
4715 | case SCI_PARAUPEXTEND: | |
9ce192d4 RD |
4716 | case SCI_CHARLEFT: |
4717 | case SCI_CHARLEFTEXTEND: | |
4718 | case SCI_CHARRIGHT: | |
4719 | case SCI_CHARRIGHTEXTEND: | |
4720 | case SCI_WORDLEFT: | |
4721 | case SCI_WORDLEFTEXTEND: | |
4722 | case SCI_WORDRIGHT: | |
4723 | case SCI_WORDRIGHTEXTEND: | |
65ec6247 RD |
4724 | case SCI_WORDPARTLEFT: |
4725 | case SCI_WORDPARTLEFTEXTEND: | |
4726 | case SCI_WORDPARTRIGHT: | |
4727 | case SCI_WORDPARTRIGHTEXTEND: | |
8e54aaed RD |
4728 | case SCI_WORDLEFTEND: |
4729 | case SCI_WORDLEFTENDEXTEND: | |
4730 | case SCI_WORDRIGHTEND: | |
4731 | case SCI_WORDRIGHTENDEXTEND: | |
9ce192d4 RD |
4732 | case SCI_HOME: |
4733 | case SCI_HOMEEXTEND: | |
4734 | case SCI_LINEEND: | |
4735 | case SCI_LINEENDEXTEND: | |
9e730a78 RD |
4736 | case SCI_HOMEWRAP: |
4737 | case SCI_HOMEWRAPEXTEND: | |
4738 | case SCI_LINEENDWRAP: | |
4739 | case SCI_LINEENDWRAPEXTEND: | |
9ce192d4 RD |
4740 | case SCI_DOCUMENTSTART: |
4741 | case SCI_DOCUMENTSTARTEXTEND: | |
4742 | case SCI_DOCUMENTEND: | |
4743 | case SCI_DOCUMENTENDEXTEND: | |
8e54aaed RD |
4744 | case SCI_STUTTEREDPAGEUP: |
4745 | case SCI_STUTTEREDPAGEUPEXTEND: | |
4746 | case SCI_STUTTEREDPAGEDOWN: | |
4747 | case SCI_STUTTEREDPAGEDOWNEXTEND: | |
9ce192d4 RD |
4748 | case SCI_PAGEUP: |
4749 | case SCI_PAGEUPEXTEND: | |
4750 | case SCI_PAGEDOWN: | |
4751 | case SCI_PAGEDOWNEXTEND: | |
4752 | case SCI_EDITTOGGLEOVERTYPE: | |
4753 | case SCI_CANCEL: | |
4754 | case SCI_DELETEBACK: | |
4755 | case SCI_TAB: | |
4756 | case SCI_BACKTAB: | |
9ce192d4 RD |
4757 | case SCI_FORMFEED: |
4758 | case SCI_VCHOME: | |
4759 | case SCI_VCHOMEEXTEND: | |
9e730a78 RD |
4760 | case SCI_VCHOMEWRAP: |
4761 | case SCI_VCHOMEWRAPEXTEND: | |
9ce192d4 RD |
4762 | case SCI_DELWORDLEFT: |
4763 | case SCI_DELWORDRIGHT: | |
7e0c58e9 | 4764 | case SCI_DELWORDRIGHTEND: |
65ec6247 RD |
4765 | case SCI_DELLINELEFT: |
4766 | case SCI_DELLINERIGHT: | |
e14d10b0 | 4767 | case SCI_LINECOPY: |
f6bcfd97 BP |
4768 | case SCI_LINECUT: |
4769 | case SCI_LINEDELETE: | |
4770 | case SCI_LINETRANSPOSE: | |
9e730a78 | 4771 | case SCI_LINEDUPLICATE: |
f6bcfd97 BP |
4772 | case SCI_LOWERCASE: |
4773 | case SCI_UPPERCASE: | |
1a2fb4cd RD |
4774 | case SCI_LINESCROLLDOWN: |
4775 | case SCI_LINESCROLLUP: | |
4776 | case SCI_DELETEBACKNOTLINE: | |
f114b858 RD |
4777 | case SCI_HOMEDISPLAY: |
4778 | case SCI_HOMEDISPLAYEXTEND: | |
4779 | case SCI_LINEENDDISPLAY: | |
4780 | case SCI_LINEENDDISPLAYEXTEND: | |
8e54aaed RD |
4781 | case SCI_SETSELECTIONMODE: |
4782 | case SCI_LINEDOWNRECTEXTEND: | |
4783 | case SCI_LINEUPRECTEXTEND: | |
4784 | case SCI_CHARLEFTRECTEXTEND: | |
4785 | case SCI_CHARRIGHTRECTEXTEND: | |
4786 | case SCI_HOMERECTEXTEND: | |
4787 | case SCI_VCHOMERECTEXTEND: | |
4788 | case SCI_LINEENDRECTEXTEND: | |
4789 | case SCI_PAGEUPRECTEXTEND: | |
4790 | case SCI_PAGEDOWNRECTEXTEND: | |
1e9bafca | 4791 | case SCI_SELECTIONDUPLICATE: |
9e96e16f | 4792 | case SCI_COPYALLOWLINE: |
1dcf666d RD |
4793 | case SCI_VERTICALCENTRECARET: |
4794 | case SCI_MOVESELECTEDLINESUP: | |
4795 | case SCI_MOVESELECTEDLINESDOWN: | |
4796 | case SCI_SCROLLTOSTART: | |
4797 | case SCI_SCROLLTOEND: | |
8e54aaed RD |
4798 | break; |
4799 | ||
7e0c58e9 RD |
4800 | // Filter out all others like display changes. Also, newlines are redundant |
4801 | // with char insert messages. | |
65ec6247 | 4802 | case SCI_NEWLINE: |
9ce192d4 | 4803 | default: |
d134f170 | 4804 | // printf("Filtered out %ld of macro recording\n", iMessage); |
9e730a78 | 4805 | return ; |
9ce192d4 RD |
4806 | } |
4807 | ||
4808 | // Send notification | |
1e9bafca | 4809 | SCNotification scn = {0}; |
9ce192d4 RD |
4810 | scn.nmhdr.code = SCN_MACRORECORD; |
4811 | scn.message = iMessage; | |
4812 | scn.wParam = wParam; | |
4813 | scn.lParam = lParam; | |
4814 | NotifyParent(scn); | |
4815 | } | |
9ce192d4 | 4816 | |
1dcf666d RD |
4817 | // Something has changed that the container should know about |
4818 | void Editor::ContainerNeedsUpdate(int flags) { | |
4819 | needUpdateUI |= flags; | |
4820 | } | |
4821 | ||
8e54aaed RD |
4822 | /** |
4823 | * Force scroll and keep position relative to top of window. | |
4824 | * | |
4825 | * If stuttered = true and not already at first/last row, move to first/last row of window. | |
4826 | * If stuttered = true and already at first/last row, scroll as normal. | |
4827 | */ | |
9e96e16f | 4828 | void Editor::PageMove(int direction, Selection::selTypes selt, bool stuttered) { |
1dcf666d RD |
4829 | int topLineNew; |
4830 | SelectionPosition newPos; | |
8e54aaed | 4831 | |
9e96e16f | 4832 | int currentLine = pdoc->LineFromPosition(sel.MainCaret()); |
8e54aaed | 4833 | int topStutterLine = topLine + caretYSlop; |
7e0c58e9 RD |
4834 | int bottomStutterLine = |
4835 | pdoc->LineFromPosition(PositionFromLocation( | |
1dcf666d | 4836 | Point(lastXChosen - xOffset, direction * vs.lineHeight * LinesToScroll()))) |
7e0c58e9 | 4837 | - caretYSlop - 1; |
8e54aaed RD |
4838 | |
4839 | if (stuttered && (direction < 0 && currentLine > topStutterLine)) { | |
4840 | topLineNew = topLine; | |
1dcf666d RD |
4841 | newPos = SPositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * caretYSlop), |
4842 | false, false, UserVirtualSpace()); | |
8e54aaed RD |
4843 | |
4844 | } else if (stuttered && (direction > 0 && currentLine < bottomStutterLine)) { | |
4845 | topLineNew = topLine; | |
1dcf666d RD |
4846 | newPos = SPositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * (LinesToScroll() - caretYSlop)), |
4847 | false, false, UserVirtualSpace()); | |
8e54aaed RD |
4848 | |
4849 | } else { | |
9e96e16f | 4850 | Point pt = LocationFromPosition(sel.MainCaret()); |
8e54aaed RD |
4851 | |
4852 | topLineNew = Platform::Clamp( | |
7e0c58e9 | 4853 | topLine + direction * LinesToScroll(), 0, MaxScrollPos()); |
1dcf666d RD |
4854 | newPos = SPositionFromLocation( |
4855 | Point(lastXChosen - xOffset, pt.y + direction * (vs.lineHeight * LinesToScroll())), | |
4856 | false, false, UserVirtualSpace()); | |
8e54aaed RD |
4857 | } |
4858 | ||
9ce192d4 RD |
4859 | if (topLineNew != topLine) { |
4860 | SetTopLine(topLineNew); | |
1dcf666d | 4861 | MovePositionTo(newPos, selt); |
9ce192d4 RD |
4862 | Redraw(); |
4863 | SetVerticalScrollPos(); | |
4864 | } else { | |
1dcf666d | 4865 | MovePositionTo(newPos, selt); |
9ce192d4 RD |
4866 | } |
4867 | } | |
4868 | ||
1dcf666d | 4869 | void Editor::ChangeCaseOfSelection(int caseMapping) { |
9e96e16f RD |
4870 | UndoGroup ug(pdoc); |
4871 | for (size_t r=0; r<sel.Count(); r++) { | |
4872 | SelectionRange current = sel.Range(r); | |
1dcf666d RD |
4873 | SelectionRange currentNoVS = current; |
4874 | currentNoVS.ClearVirtualSpace(); | |
4875 | char *text = CopyRange(currentNoVS.Start().Position(), currentNoVS.End().Position()); | |
4876 | size_t rangeBytes = currentNoVS.Length(); | |
4877 | if (rangeBytes > 0) { | |
4878 | std::string sText(text, rangeBytes); | |
4879 | ||
4880 | std::string sMapped = CaseMapString(sText, caseMapping); | |
4881 | ||
4882 | if (sMapped != sText) { | |
4883 | size_t firstDifference = 0; | |
4884 | while (sMapped[firstDifference] == sText[firstDifference]) | |
4885 | firstDifference++; | |
4886 | size_t lastDifference = sMapped.size() - 1; | |
4887 | while (sMapped[lastDifference] == sText[lastDifference]) | |
4888 | lastDifference--; | |
4889 | size_t endSame = sMapped.size() - 1 - lastDifference; | |
4890 | pdoc->DeleteChars( | |
4891 | static_cast<int>(currentNoVS.Start().Position() + firstDifference), | |
4892 | static_cast<int>(rangeBytes - firstDifference - endSame)); | |
4893 | pdoc->InsertString( | |
4894 | static_cast<int>(currentNoVS.Start().Position() + firstDifference), | |
4895 | sMapped.c_str() + firstDifference, | |
4896 | static_cast<int>(lastDifference - firstDifference + 1)); | |
4897 | // Automatic movement changes selection so reset to exactly the same as it was. | |
4898 | sel.Range(r) = current; | |
4899 | } | |
4900 | } | |
4901 | delete []text; | |
f6bcfd97 | 4902 | } |
f6bcfd97 BP |
4903 | } |
4904 | ||
f6bcfd97 | 4905 | void Editor::LineTranspose() { |
9e96e16f | 4906 | int line = pdoc->LineFromPosition(sel.MainCaret()); |
f6bcfd97 | 4907 | if (line > 0) { |
9e96e16f | 4908 | UndoGroup ug(pdoc); |
d134f170 RD |
4909 | int startPrev = pdoc->LineStart(line - 1); |
4910 | int endPrev = pdoc->LineEnd(line - 1); | |
f6bcfd97 BP |
4911 | int start = pdoc->LineStart(line); |
4912 | int end = pdoc->LineEnd(line); | |
7e0c58e9 RD |
4913 | char *line1 = CopyRange(startPrev, endPrev); |
4914 | int len1 = endPrev - startPrev; | |
4915 | char *line2 = CopyRange(start, end); | |
4916 | int len2 = end - start; | |
4917 | pdoc->DeleteChars(start, len2); | |
4918 | pdoc->DeleteChars(startPrev, len1); | |
4919 | pdoc->InsertString(startPrev, line2, len2); | |
4920 | pdoc->InsertString(start - len1 + len2, line1, len1); | |
9e96e16f | 4921 | MovePositionTo(SelectionPosition(start - len1 + len2)); |
7e0c58e9 RD |
4922 | delete []line1; |
4923 | delete []line2; | |
f6bcfd97 BP |
4924 | } |
4925 | } | |
4926 | ||
1e9bafca | 4927 | void Editor::Duplicate(bool forLine) { |
9e96e16f | 4928 | if (sel.Empty()) { |
1e9bafca RD |
4929 | forLine = true; |
4930 | } | |
1dcf666d | 4931 | UndoGroup ug(pdoc); |
9e96e16f RD |
4932 | const char *eol = ""; |
4933 | int eolLen = 0; | |
1e9bafca | 4934 | if (forLine) { |
9e96e16f RD |
4935 | eol = StringFromEOLMode(pdoc->eolMode); |
4936 | eolLen = istrlen(eol); | |
4937 | } | |
4938 | for (size_t r=0; r<sel.Count(); r++) { | |
4939 | SelectionPosition start = sel.Range(r).Start(); | |
4940 | SelectionPosition end = sel.Range(r).End(); | |
4941 | if (forLine) { | |
4942 | int line = pdoc->LineFromPosition(sel.Range(r).caret.Position()); | |
4943 | start = SelectionPosition(pdoc->LineStart(line)); | |
4944 | end = SelectionPosition(pdoc->LineEnd(line)); | |
4945 | } | |
4946 | char *text = CopyRange(start.Position(), end.Position()); | |
4947 | if (forLine) | |
4948 | pdoc->InsertString(end.Position(), eol, eolLen); | |
4949 | pdoc->InsertString(end.Position() + eolLen, text, SelectionRange(end, start).Length()); | |
4950 | delete []text; | |
1e9bafca | 4951 | } |
9e96e16f RD |
4952 | if (sel.Count() && sel.IsRectangular()) { |
4953 | SelectionPosition last = sel.Last(); | |
4954 | if (forLine) { | |
4955 | int line = pdoc->LineFromPosition(last.Position()); | |
4956 | last = SelectionPosition(last.Position() + pdoc->LineStart(line+1) - pdoc->LineStart(line)); | |
4957 | } | |
4958 | if (sel.Rectangular().anchor > sel.Rectangular().caret) | |
4959 | sel.Rectangular().anchor = last; | |
4960 | else | |
4961 | sel.Rectangular().caret = last; | |
4962 | SetRectangularRange(); | |
1e9bafca | 4963 | } |
9e730a78 RD |
4964 | } |
4965 | ||
8e54aaed | 4966 | void Editor::CancelModes() { |
9e96e16f | 4967 | sel.SetMoveExtends(false); |
8e54aaed | 4968 | } |
d134f170 | 4969 | |
a834585d | 4970 | void Editor::NewLine() { |
1dcf666d RD |
4971 | // Remove non-main ranges |
4972 | InvalidateSelection(sel.RangeMain(), true); | |
4973 | sel.SetSelection(sel.RangeMain()); | |
4974 | ||
4975 | // Clear main range and insert line end | |
4976 | bool needGroupUndo = !sel.Empty(); | |
4977 | if (needGroupUndo) | |
4978 | pdoc->BeginUndoAction(); | |
4979 | ||
4980 | if (!sel.Empty()) | |
4981 | ClearSelection(); | |
a834585d RD |
4982 | const char *eol = "\n"; |
4983 | if (pdoc->eolMode == SC_EOL_CRLF) { | |
4984 | eol = "\r\n"; | |
4985 | } else if (pdoc->eolMode == SC_EOL_CR) { | |
4986 | eol = "\r"; | |
4987 | } // else SC_EOL_LF -> "\n" already set | |
1dcf666d RD |
4988 | bool inserted = pdoc->InsertCString(sel.MainCaret(), eol); |
4989 | // Want to end undo group before NotifyChar as applications often modify text here | |
4990 | if (needGroupUndo) | |
4991 | pdoc->EndUndoAction(); | |
4992 | if (inserted) { | |
9e96e16f | 4993 | SetEmptySelection(sel.MainCaret() + istrlen(eol)); |
a834585d RD |
4994 | while (*eol) { |
4995 | NotifyChar(*eol); | |
9e96e16f RD |
4996 | if (recordingMacro) { |
4997 | char txt[2]; | |
4998 | txt[0] = *eol; | |
4999 | txt[1] = '\0'; | |
5000 | NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(txt)); | |
5001 | } | |
a834585d RD |
5002 | eol++; |
5003 | } | |
5004 | } | |
5005 | SetLastXChosen(); | |
7e0c58e9 | 5006 | SetScrollBars(); |
a834585d | 5007 | EnsureCaretVisible(); |
1e9bafca RD |
5008 | // Avoid blinking during rapid typing: |
5009 | ShowCaretAtCurrentPosition(); | |
a834585d RD |
5010 | } |
5011 | ||
9e96e16f RD |
5012 | void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) { |
5013 | SelectionPosition caretToUse = sel.Range(sel.Main()).caret; | |
5014 | if (sel.IsRectangular()) { | |
5015 | if (selt == Selection::noSel) { | |
5016 | caretToUse = (direction > 0) ? sel.Limits().end : sel.Limits().start; | |
5017 | } else { | |
5018 | caretToUse = sel.Rectangular().caret; | |
5019 | } | |
5020 | } | |
1dcf666d | 5021 | |
9e96e16f | 5022 | Point pt = LocationFromPosition(caretToUse); |
1dcf666d RD |
5023 | int skipLines = 0; |
5024 | ||
5025 | if (vs.annotationVisible) { | |
5026 | int lineDoc = pdoc->LineFromPosition(caretToUse.Position()); | |
5027 | Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc)); | |
5028 | int subLine = (pt.y - ptStartLine.y) / vs.lineHeight; | |
5029 | ||
5030 | if (direction < 0 && subLine == 0) { | |
5031 | int lineDisplay = cs.DisplayFromDoc(lineDoc); | |
5032 | if (lineDisplay > 0) { | |
5033 | skipLines = pdoc->AnnotationLines(cs.DocFromDisplay(lineDisplay - 1)); | |
5034 | } | |
5035 | } else if (direction > 0 && subLine >= (cs.GetHeight(lineDoc) - 1 - pdoc->AnnotationLines(lineDoc))) { | |
5036 | skipLines = pdoc->AnnotationLines(lineDoc); | |
5037 | } | |
9e96e16f | 5038 | } |
1dcf666d RD |
5039 | |
5040 | int newY = pt.y + (1 + skipLines) * direction * vs.lineHeight; | |
5041 | SelectionPosition posNew = SPositionFromLocation( | |
5042 | Point(lastXChosen - xOffset, newY), false, false, UserVirtualSpace()); | |
5043 | ||
a834585d RD |
5044 | if (direction < 0) { |
5045 | // Line wrapping may lead to a location on the same line, so | |
5046 | // seek back if that is the case. | |
9e96e16f RD |
5047 | Point ptNew = LocationFromPosition(posNew.Position()); |
5048 | while ((posNew.Position() > 0) && (pt.y == ptNew.y)) { | |
1dcf666d RD |
5049 | posNew.Add(-1); |
5050 | posNew.SetVirtualSpace(0); | |
5051 | ptNew = LocationFromPosition(posNew.Position()); | |
5052 | } | |
5053 | } else if (direction > 0 && posNew.Position() != pdoc->Length()) { | |
5054 | // There is an equivalent case when moving down which skips | |
5055 | // over a line. | |
5056 | Point ptNew = LocationFromPosition(posNew.Position()); | |
5057 | while ((posNew.Position() > caretToUse.Position()) && (ptNew.y > newY)) { | |
5058 | posNew.Add(-1); | |
9e96e16f RD |
5059 | posNew.SetVirtualSpace(0); |
5060 | ptNew = LocationFromPosition(posNew.Position()); | |
a834585d RD |
5061 | } |
5062 | } | |
1dcf666d RD |
5063 | |
5064 | MovePositionTo(MovePositionSoVisible(posNew, direction), selt); | |
a834585d | 5065 | } |
9ce192d4 | 5066 | |
9e96e16f RD |
5067 | void Editor::ParaUpOrDown(int direction, Selection::selTypes selt) { |
5068 | int lineDoc, savedPos = sel.MainCaret(); | |
1e9bafca | 5069 | do { |
9e96e16f RD |
5070 | MovePositionTo(SelectionPosition(direction > 0 ? pdoc->ParaDown(sel.MainCaret()) : pdoc->ParaUp(sel.MainCaret())), selt); |
5071 | lineDoc = pdoc->LineFromPosition(sel.MainCaret()); | |
1e9bafca | 5072 | if (direction > 0) { |
9e96e16f RD |
5073 | if (sel.MainCaret() >= pdoc->Length() && !cs.GetVisible(lineDoc)) { |
5074 | if (selt == Selection::noSel) { | |
5075 | MovePositionTo(SelectionPosition(pdoc->LineEndPosition(savedPos))); | |
1e9bafca RD |
5076 | } |
5077 | break; | |
5078 | } | |
5079 | } | |
5080 | } while (!cs.GetVisible(lineDoc)); | |
5081 | } | |
5082 | ||
f114b858 RD |
5083 | int Editor::StartEndDisplayLine(int pos, bool start) { |
5084 | RefreshStyleData(); | |
5085 | int line = pdoc->LineFromPosition(pos); | |
9e730a78 RD |
5086 | AutoSurface surface(this); |
5087 | AutoLineLayout ll(llc, RetrieveLineLayout(line)); | |
f114b858 RD |
5088 | int posRet = INVALID_POSITION; |
5089 | if (surface && ll) { | |
5090 | unsigned int posLineStart = pdoc->LineStart(line); | |
5091 | LayoutLine(line, surface, vs, ll, wrapWidth); | |
5092 | int posInLine = pos - posLineStart; | |
5093 | if (posInLine <= ll->maxLineLength) { | |
9e730a78 RD |
5094 | for (int subLine = 0; subLine < ll->lines; subLine++) { |
5095 | if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) { | |
f114b858 RD |
5096 | if (start) { |
5097 | posRet = ll->LineStart(subLine) + posLineStart; | |
5098 | } else { | |
5099 | if (subLine == ll->lines - 1) | |
9e730a78 | 5100 | posRet = ll->LineStart(subLine + 1) + posLineStart; |
f114b858 | 5101 | else |
9e730a78 | 5102 | posRet = ll->LineStart(subLine + 1) + posLineStart - 1; |
f114b858 RD |
5103 | } |
5104 | } | |
5105 | } | |
5106 | } | |
5107 | } | |
f114b858 RD |
5108 | if (posRet == INVALID_POSITION) { |
5109 | return pos; | |
5110 | } else { | |
5111 | return posRet; | |
5112 | } | |
5113 | } | |
5114 | ||
a834585d | 5115 | int Editor::KeyCommand(unsigned int iMessage) { |
9ce192d4 RD |
5116 | switch (iMessage) { |
5117 | case SCI_LINEDOWN: | |
a834585d | 5118 | CursorUpOrDown(1); |
9ce192d4 RD |
5119 | break; |
5120 | case SCI_LINEDOWNEXTEND: | |
9e96e16f | 5121 | CursorUpOrDown(1, Selection::selStream); |
8e54aaed RD |
5122 | break; |
5123 | case SCI_LINEDOWNRECTEXTEND: | |
9e96e16f | 5124 | CursorUpOrDown(1, Selection::selRectangle); |
9ce192d4 | 5125 | break; |
9e730a78 | 5126 | case SCI_PARADOWN: |
1e9bafca | 5127 | ParaUpOrDown(1); |
9e730a78 RD |
5128 | break; |
5129 | case SCI_PARADOWNEXTEND: | |
9e96e16f | 5130 | ParaUpOrDown(1, Selection::selStream); |
9e730a78 | 5131 | break; |
f6bcfd97 BP |
5132 | case SCI_LINESCROLLDOWN: |
5133 | ScrollTo(topLine + 1); | |
f114b858 | 5134 | MoveCaretInsideView(false); |
f6bcfd97 | 5135 | break; |
9ce192d4 | 5136 | case SCI_LINEUP: |
a834585d | 5137 | CursorUpOrDown(-1); |
9ce192d4 RD |
5138 | break; |
5139 | case SCI_LINEUPEXTEND: | |
9e96e16f | 5140 | CursorUpOrDown(-1, Selection::selStream); |
8e54aaed RD |
5141 | break; |
5142 | case SCI_LINEUPRECTEXTEND: | |
9e96e16f | 5143 | CursorUpOrDown(-1, Selection::selRectangle); |
9ce192d4 | 5144 | break; |
9e730a78 | 5145 | case SCI_PARAUP: |
1e9bafca | 5146 | ParaUpOrDown(-1); |
9e730a78 RD |
5147 | break; |
5148 | case SCI_PARAUPEXTEND: | |
9e96e16f | 5149 | ParaUpOrDown(-1, Selection::selStream); |
9e730a78 | 5150 | break; |
f6bcfd97 BP |
5151 | case SCI_LINESCROLLUP: |
5152 | ScrollTo(topLine - 1); | |
f114b858 | 5153 | MoveCaretInsideView(false); |
f6bcfd97 | 5154 | break; |
9ce192d4 | 5155 | case SCI_CHARLEFT: |
9e96e16f RD |
5156 | if (SelectionEmpty() || sel.MoveExtends()) { |
5157 | if ((sel.Count() == 1) && pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { | |
5158 | SelectionPosition spCaret = sel.RangeMain().caret; | |
5159 | spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); | |
5160 | MovePositionTo(spCaret); | |
5161 | } else { | |
5162 | MovePositionTo(MovePositionSoVisible( | |
5163 | SelectionPosition((sel.LimitsForRectangularElseMain().start).Position() - 1), -1)); | |
5164 | } | |
9ce192d4 | 5165 | } else { |
9e96e16f | 5166 | MovePositionTo(sel.LimitsForRectangularElseMain().start); |
9ce192d4 RD |
5167 | } |
5168 | SetLastXChosen(); | |
5169 | break; | |
5170 | case SCI_CHARLEFTEXTEND: | |
9e96e16f RD |
5171 | if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { |
5172 | SelectionPosition spCaret = sel.RangeMain().caret; | |
5173 | spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); | |
5174 | MovePositionTo(spCaret, Selection::selStream); | |
5175 | } else { | |
5176 | MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selStream); | |
5177 | } | |
8e54aaed RD |
5178 | SetLastXChosen(); |
5179 | break; | |
5180 | case SCI_CHARLEFTRECTEXTEND: | |
9e96e16f RD |
5181 | if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { |
5182 | SelectionPosition spCaret = sel.RangeMain().caret; | |
5183 | spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); | |
5184 | MovePositionTo(spCaret, Selection::selRectangle); | |
5185 | } else { | |
5186 | MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selRectangle); | |
5187 | } | |
9ce192d4 RD |
5188 | SetLastXChosen(); |
5189 | break; | |
5190 | case SCI_CHARRIGHT: | |
9e96e16f RD |
5191 | if (SelectionEmpty() || sel.MoveExtends()) { |
5192 | if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) { | |
5193 | SelectionPosition spCaret = sel.RangeMain().caret; | |
5194 | spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); | |
5195 | MovePositionTo(spCaret); | |
5196 | } else { | |
5197 | MovePositionTo(MovePositionSoVisible( | |
5198 | SelectionPosition((sel.LimitsForRectangularElseMain().end).Position() + 1), 1)); | |
5199 | } | |
9ce192d4 | 5200 | } else { |
9e96e16f | 5201 | MovePositionTo(sel.LimitsForRectangularElseMain().end); |
9ce192d4 RD |
5202 | } |
5203 | SetLastXChosen(); | |
5204 | break; | |
5205 | case SCI_CHARRIGHTEXTEND: | |
9e96e16f RD |
5206 | if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) { |
5207 | SelectionPosition spCaret = sel.RangeMain().caret; | |
5208 | spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); | |
5209 | MovePositionTo(spCaret, Selection::selStream); | |
5210 | } else { | |
5211 | MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selStream); | |
5212 | } | |
8e54aaed RD |
5213 | SetLastXChosen(); |
5214 | break; | |
5215 | case SCI_CHARRIGHTRECTEXTEND: | |
9e96e16f RD |
5216 | if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) && pdoc->IsLineEndPosition(sel.MainCaret())) { |
5217 | SelectionPosition spCaret = sel.RangeMain().caret; | |
5218 | spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); | |
5219 | MovePositionTo(spCaret, Selection::selRectangle); | |
5220 | } else { | |
5221 | MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selRectangle); | |
5222 | } | |
9ce192d4 RD |
5223 | SetLastXChosen(); |
5224 | break; | |
5225 | case SCI_WORDLEFT: | |
9e96e16f | 5226 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1)); |
9ce192d4 RD |
5227 | SetLastXChosen(); |
5228 | break; | |
5229 | case SCI_WORDLEFTEXTEND: | |
9e96e16f | 5230 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1), Selection::selStream); |
9ce192d4 RD |
5231 | SetLastXChosen(); |
5232 | break; | |
5233 | case SCI_WORDRIGHT: | |
9e96e16f | 5234 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1)); |
9ce192d4 RD |
5235 | SetLastXChosen(); |
5236 | break; | |
5237 | case SCI_WORDRIGHTEXTEND: | |
9e96e16f | 5238 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1), Selection::selStream); |
8e54aaed RD |
5239 | SetLastXChosen(); |
5240 | break; | |
5241 | ||
5242 | case SCI_WORDLEFTEND: | |
9e96e16f | 5243 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1)); |
8e54aaed RD |
5244 | SetLastXChosen(); |
5245 | break; | |
5246 | case SCI_WORDLEFTENDEXTEND: | |
9e96e16f | 5247 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1), Selection::selStream); |
8e54aaed RD |
5248 | SetLastXChosen(); |
5249 | break; | |
5250 | case SCI_WORDRIGHTEND: | |
9e96e16f | 5251 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1)); |
9ce192d4 RD |
5252 | SetLastXChosen(); |
5253 | break; | |
8e54aaed | 5254 | case SCI_WORDRIGHTENDEXTEND: |
9e96e16f | 5255 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1), Selection::selStream); |
8e54aaed RD |
5256 | SetLastXChosen(); |
5257 | break; | |
5258 | ||
9ce192d4 | 5259 | case SCI_HOME: |
9e96e16f | 5260 | MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret()))); |
9ce192d4 RD |
5261 | SetLastXChosen(); |
5262 | break; | |
5263 | case SCI_HOMEEXTEND: | |
9e96e16f | 5264 | MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selStream); |
8e54aaed RD |
5265 | SetLastXChosen(); |
5266 | break; | |
5267 | case SCI_HOMERECTEXTEND: | |
9e96e16f | 5268 | MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selRectangle); |
9ce192d4 RD |
5269 | SetLastXChosen(); |
5270 | break; | |
5271 | case SCI_LINEEND: | |
9e96e16f | 5272 | MovePositionTo(pdoc->LineEndPosition(sel.MainCaret())); |
9ce192d4 RD |
5273 | SetLastXChosen(); |
5274 | break; | |
5275 | case SCI_LINEENDEXTEND: | |
9e96e16f | 5276 | MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selStream); |
8e54aaed RD |
5277 | SetLastXChosen(); |
5278 | break; | |
5279 | case SCI_LINEENDRECTEXTEND: | |
9e96e16f | 5280 | MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selRectangle); |
9ce192d4 RD |
5281 | SetLastXChosen(); |
5282 | break; | |
9e730a78 | 5283 | case SCI_HOMEWRAP: { |
9e96e16f RD |
5284 | SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); |
5285 | if (sel.RangeMain().caret <= homePos) | |
5286 | homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret()))); | |
9e730a78 RD |
5287 | MovePositionTo(homePos); |
5288 | SetLastXChosen(); | |
5289 | } | |
5290 | break; | |
5291 | case SCI_HOMEWRAPEXTEND: { | |
9e96e16f RD |
5292 | SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); |
5293 | if (sel.RangeMain().caret <= homePos) | |
5294 | homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret()))); | |
5295 | MovePositionTo(homePos, Selection::selStream); | |
9e730a78 RD |
5296 | SetLastXChosen(); |
5297 | } | |
5298 | break; | |
5299 | case SCI_LINEENDWRAP: { | |
9e96e16f RD |
5300 | SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1); |
5301 | SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret())); | |
a33203cb | 5302 | if (endPos > realEndPos // if moved past visible EOLs |
9e96e16f | 5303 | || sel.RangeMain().caret >= endPos) // if at end of display line already |
a33203cb | 5304 | endPos = realEndPos; |
9e730a78 RD |
5305 | MovePositionTo(endPos); |
5306 | SetLastXChosen(); | |
5307 | } | |
5308 | break; | |
5309 | case SCI_LINEENDWRAPEXTEND: { | |
9e96e16f RD |
5310 | SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1); |
5311 | SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret())); | |
a33203cb | 5312 | if (endPos > realEndPos // if moved past visible EOLs |
9e96e16f | 5313 | || sel.RangeMain().caret >= endPos) // if at end of display line already |
a33203cb | 5314 | endPos = realEndPos; |
9e96e16f | 5315 | MovePositionTo(endPos, Selection::selStream); |
9e730a78 RD |
5316 | SetLastXChosen(); |
5317 | } | |
5318 | break; | |
9ce192d4 RD |
5319 | case SCI_DOCUMENTSTART: |
5320 | MovePositionTo(0); | |
5321 | SetLastXChosen(); | |
5322 | break; | |
5323 | case SCI_DOCUMENTSTARTEXTEND: | |
9e96e16f | 5324 | MovePositionTo(0, Selection::selStream); |
9ce192d4 RD |
5325 | SetLastXChosen(); |
5326 | break; | |
5327 | case SCI_DOCUMENTEND: | |
5328 | MovePositionTo(pdoc->Length()); | |
5329 | SetLastXChosen(); | |
5330 | break; | |
5331 | case SCI_DOCUMENTENDEXTEND: | |
9e96e16f | 5332 | MovePositionTo(pdoc->Length(), Selection::selStream); |
9ce192d4 RD |
5333 | SetLastXChosen(); |
5334 | break; | |
8e54aaed | 5335 | case SCI_STUTTEREDPAGEUP: |
9e96e16f | 5336 | PageMove(-1, Selection::noSel, true); |
8e54aaed RD |
5337 | break; |
5338 | case SCI_STUTTEREDPAGEUPEXTEND: | |
9e96e16f | 5339 | PageMove(-1, Selection::selStream, true); |
8e54aaed RD |
5340 | break; |
5341 | case SCI_STUTTEREDPAGEDOWN: | |
9e96e16f | 5342 | PageMove(1, Selection::noSel, true); |
8e54aaed RD |
5343 | break; |
5344 | case SCI_STUTTEREDPAGEDOWNEXTEND: | |
9e96e16f | 5345 | PageMove(1, Selection::selStream, true); |
8e54aaed | 5346 | break; |
9ce192d4 | 5347 | case SCI_PAGEUP: |
9e730a78 | 5348 | PageMove(-1); |
9ce192d4 RD |
5349 | break; |
5350 | case SCI_PAGEUPEXTEND: | |
9e96e16f | 5351 | PageMove(-1, Selection::selStream); |
8e54aaed RD |
5352 | break; |
5353 | case SCI_PAGEUPRECTEXTEND: | |
9e96e16f | 5354 | PageMove(-1, Selection::selRectangle); |
9ce192d4 RD |
5355 | break; |
5356 | case SCI_PAGEDOWN: | |
5357 | PageMove(1); | |
5358 | break; | |
5359 | case SCI_PAGEDOWNEXTEND: | |
9e96e16f | 5360 | PageMove(1, Selection::selStream); |
8e54aaed RD |
5361 | break; |
5362 | case SCI_PAGEDOWNRECTEXTEND: | |
9e96e16f | 5363 | PageMove(1, Selection::selRectangle); |
9ce192d4 RD |
5364 | break; |
5365 | case SCI_EDITTOGGLEOVERTYPE: | |
5366 | inOverstrike = !inOverstrike; | |
5367 | DropCaret(); | |
5368 | ShowCaretAtCurrentPosition(); | |
1dcf666d | 5369 | ContainerNeedsUpdate(SC_UPDATE_CONTENT); |
d134f170 | 5370 | NotifyUpdateUI(); |
9ce192d4 | 5371 | break; |
9e730a78 | 5372 | case SCI_CANCEL: // Cancel any modes - handled in subclass |
9ce192d4 | 5373 | // Also unselect text |
d134f170 | 5374 | CancelModes(); |
9ce192d4 RD |
5375 | break; |
5376 | case SCI_DELETEBACK: | |
1a2fb4cd | 5377 | DelCharBack(true); |
1dcf666d | 5378 | if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { |
1e9bafca RD |
5379 | SetLastXChosen(); |
5380 | } | |
1a2fb4cd RD |
5381 | EnsureCaretVisible(); |
5382 | break; | |
5383 | case SCI_DELETEBACKNOTLINE: | |
5384 | DelCharBack(false); | |
1dcf666d | 5385 | if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { |
1e9bafca RD |
5386 | SetLastXChosen(); |
5387 | } | |
9ce192d4 RD |
5388 | EnsureCaretVisible(); |
5389 | break; | |
5390 | case SCI_TAB: | |
5391 | Indent(true); | |
1dcf666d | 5392 | if (caretSticky == SC_CARETSTICKY_OFF) { |
1e9bafca RD |
5393 | SetLastXChosen(); |
5394 | } | |
d134f170 | 5395 | EnsureCaretVisible(); |
9e96e16f | 5396 | ShowCaretAtCurrentPosition(); // Avoid blinking |
9ce192d4 RD |
5397 | break; |
5398 | case SCI_BACKTAB: | |
5399 | Indent(false); | |
1dcf666d | 5400 | if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { |
1e9bafca RD |
5401 | SetLastXChosen(); |
5402 | } | |
d134f170 | 5403 | EnsureCaretVisible(); |
9e96e16f | 5404 | ShowCaretAtCurrentPosition(); // Avoid blinking |
9ce192d4 RD |
5405 | break; |
5406 | case SCI_NEWLINE: | |
a834585d | 5407 | NewLine(); |
9ce192d4 RD |
5408 | break; |
5409 | case SCI_FORMFEED: | |
5410 | AddChar('\f'); | |
5411 | break; | |
5412 | case SCI_VCHOME: | |
9e96e16f | 5413 | MovePositionTo(pdoc->VCHomePosition(sel.MainCaret())); |
9ce192d4 RD |
5414 | SetLastXChosen(); |
5415 | break; | |
5416 | case SCI_VCHOMEEXTEND: | |
9e96e16f | 5417 | MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selStream); |
8e54aaed RD |
5418 | SetLastXChosen(); |
5419 | break; | |
5420 | case SCI_VCHOMERECTEXTEND: | |
9e96e16f | 5421 | MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selRectangle); |
9ce192d4 RD |
5422 | SetLastXChosen(); |
5423 | break; | |
9e730a78 | 5424 | case SCI_VCHOMEWRAP: { |
9e96e16f RD |
5425 | SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret())); |
5426 | SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); | |
5427 | if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos)) | |
9e730a78 RD |
5428 | homePos = viewLineStart; |
5429 | ||
5430 | MovePositionTo(homePos); | |
5431 | SetLastXChosen(); | |
5432 | } | |
5433 | break; | |
5434 | case SCI_VCHOMEWRAPEXTEND: { | |
9e96e16f RD |
5435 | SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret())); |
5436 | SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); | |
5437 | if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos)) | |
9e730a78 RD |
5438 | homePos = viewLineStart; |
5439 | ||
9e96e16f | 5440 | MovePositionTo(homePos, Selection::selStream); |
9e730a78 RD |
5441 | SetLastXChosen(); |
5442 | } | |
5443 | break; | |
9ce192d4 | 5444 | case SCI_ZOOMIN: |
a834585d | 5445 | if (vs.zoomLevel < 20) { |
9ce192d4 | 5446 | vs.zoomLevel++; |
a834585d RD |
5447 | InvalidateStyleRedraw(); |
5448 | NotifyZoom(); | |
5449 | } | |
9ce192d4 RD |
5450 | break; |
5451 | case SCI_ZOOMOUT: | |
a834585d | 5452 | if (vs.zoomLevel > -10) { |
9ce192d4 | 5453 | vs.zoomLevel--; |
a834585d RD |
5454 | InvalidateStyleRedraw(); |
5455 | NotifyZoom(); | |
5456 | } | |
9ce192d4 RD |
5457 | break; |
5458 | case SCI_DELWORDLEFT: { | |
9e96e16f RD |
5459 | int startWord = pdoc->NextWordStart(sel.MainCaret(), -1); |
5460 | pdoc->DeleteChars(startWord, sel.MainCaret() - startWord); | |
5461 | sel.RangeMain().ClearVirtualSpace(); | |
f6bcfd97 | 5462 | SetLastXChosen(); |
9ce192d4 RD |
5463 | } |
5464 | break; | |
5465 | case SCI_DELWORDRIGHT: { | |
9e96e16f RD |
5466 | UndoGroup ug(pdoc); |
5467 | sel.RangeMain().caret = SelectionPosition( | |
5468 | InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); | |
1dcf666d | 5469 | sel.RangeMain().anchor = sel.RangeMain().caret; |
9e96e16f RD |
5470 | int endWord = pdoc->NextWordStart(sel.MainCaret(), 1); |
5471 | pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret()); | |
f6bcfd97 BP |
5472 | } |
5473 | break; | |
7e0c58e9 | 5474 | case SCI_DELWORDRIGHTEND: { |
9e96e16f RD |
5475 | UndoGroup ug(pdoc); |
5476 | sel.RangeMain().caret = SelectionPosition( | |
5477 | InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); | |
5478 | int endWord = pdoc->NextWordEnd(sel.MainCaret(), 1); | |
5479 | pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret()); | |
7e0c58e9 RD |
5480 | } |
5481 | break; | |
65ec6247 | 5482 | case SCI_DELLINELEFT: { |
9e96e16f | 5483 | int line = pdoc->LineFromPosition(sel.MainCaret()); |
65ec6247 | 5484 | int start = pdoc->LineStart(line); |
9e96e16f RD |
5485 | pdoc->DeleteChars(start, sel.MainCaret() - start); |
5486 | sel.RangeMain().ClearVirtualSpace(); | |
65ec6247 RD |
5487 | SetLastXChosen(); |
5488 | } | |
5489 | break; | |
5490 | case SCI_DELLINERIGHT: { | |
9e96e16f | 5491 | int line = pdoc->LineFromPosition(sel.MainCaret()); |
65ec6247 | 5492 | int end = pdoc->LineEnd(line); |
9e96e16f | 5493 | pdoc->DeleteChars(sel.MainCaret(), end - sel.MainCaret()); |
65ec6247 RD |
5494 | } |
5495 | break; | |
e14d10b0 | 5496 | case SCI_LINECOPY: { |
9e96e16f RD |
5497 | int lineStart = pdoc->LineFromPosition(SelectionStart().Position()); |
5498 | int lineEnd = pdoc->LineFromPosition(SelectionEnd().Position()); | |
e14d10b0 | 5499 | CopyRangeToClipboard(pdoc->LineStart(lineStart), |
7e0c58e9 | 5500 | pdoc->LineStart(lineEnd + 1)); |
e14d10b0 RD |
5501 | } |
5502 | break; | |
f6bcfd97 | 5503 | case SCI_LINECUT: { |
9e96e16f RD |
5504 | int lineStart = pdoc->LineFromPosition(SelectionStart().Position()); |
5505 | int lineEnd = pdoc->LineFromPosition(SelectionEnd().Position()); | |
f6bcfd97 | 5506 | int start = pdoc->LineStart(lineStart); |
d134f170 RD |
5507 | int end = pdoc->LineStart(lineEnd + 1); |
5508 | SetSelection(start, end); | |
f6bcfd97 | 5509 | Cut(); |
e14d10b0 | 5510 | SetLastXChosen(); |
f6bcfd97 BP |
5511 | } |
5512 | break; | |
5513 | case SCI_LINEDELETE: { | |
9e96e16f | 5514 | int line = pdoc->LineFromPosition(sel.MainCaret()); |
f6bcfd97 | 5515 | int start = pdoc->LineStart(line); |
d134f170 RD |
5516 | int end = pdoc->LineStart(line + 1); |
5517 | pdoc->DeleteChars(start, end - start); | |
9ce192d4 RD |
5518 | } |
5519 | break; | |
f6bcfd97 BP |
5520 | case SCI_LINETRANSPOSE: |
5521 | LineTranspose(); | |
5522 | break; | |
9e730a78 | 5523 | case SCI_LINEDUPLICATE: |
1e9bafca RD |
5524 | Duplicate(true); |
5525 | break; | |
5526 | case SCI_SELECTIONDUPLICATE: | |
5527 | Duplicate(false); | |
9e730a78 | 5528 | break; |
f6bcfd97 | 5529 | case SCI_LOWERCASE: |
1dcf666d | 5530 | ChangeCaseOfSelection(cmLower); |
f6bcfd97 BP |
5531 | break; |
5532 | case SCI_UPPERCASE: | |
1dcf666d | 5533 | ChangeCaseOfSelection(cmUpper); |
f6bcfd97 | 5534 | break; |
65ec6247 | 5535 | case SCI_WORDPARTLEFT: |
9e96e16f | 5536 | MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1)); |
65ec6247 RD |
5537 | SetLastXChosen(); |
5538 | break; | |
5539 | case SCI_WORDPARTLEFTEXTEND: | |
9e96e16f | 5540 | MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1), Selection::selStream); |
65ec6247 RD |
5541 | SetLastXChosen(); |
5542 | break; | |
5543 | case SCI_WORDPARTRIGHT: | |
9e96e16f | 5544 | MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1)); |
65ec6247 RD |
5545 | SetLastXChosen(); |
5546 | break; | |
5547 | case SCI_WORDPARTRIGHTEXTEND: | |
9e96e16f | 5548 | MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1), Selection::selStream); |
65ec6247 RD |
5549 | SetLastXChosen(); |
5550 | break; | |
f114b858 RD |
5551 | case SCI_HOMEDISPLAY: |
5552 | MovePositionTo(MovePositionSoVisible( | |
9e96e16f | 5553 | StartEndDisplayLine(sel.MainCaret(), true), -1)); |
f114b858 RD |
5554 | SetLastXChosen(); |
5555 | break; | |
5556 | case SCI_HOMEDISPLAYEXTEND: | |
5557 | MovePositionTo(MovePositionSoVisible( | |
9e96e16f | 5558 | StartEndDisplayLine(sel.MainCaret(), true), -1), Selection::selStream); |
f114b858 RD |
5559 | SetLastXChosen(); |
5560 | break; | |
5561 | case SCI_LINEENDDISPLAY: | |
5562 | MovePositionTo(MovePositionSoVisible( | |
9e96e16f | 5563 | StartEndDisplayLine(sel.MainCaret(), false), 1)); |
f114b858 RD |
5564 | SetLastXChosen(); |
5565 | break; | |
5566 | case SCI_LINEENDDISPLAYEXTEND: | |
5567 | MovePositionTo(MovePositionSoVisible( | |
9e96e16f | 5568 | StartEndDisplayLine(sel.MainCaret(), false), 1), Selection::selStream); |
f114b858 RD |
5569 | SetLastXChosen(); |
5570 | break; | |
1dcf666d RD |
5571 | case SCI_SCROLLTOSTART: |
5572 | ScrollTo(0); | |
5573 | break; | |
5574 | case SCI_SCROLLTOEND: | |
5575 | ScrollTo(MaxScrollPos()); | |
5576 | break; | |
9ce192d4 RD |
5577 | } |
5578 | return 0; | |
5579 | } | |
5580 | ||
5581 | int Editor::KeyDefault(int, int) { | |
5582 | return 0; | |
5583 | } | |
5584 | ||
1dcf666d | 5585 | int Editor::KeyDownWithModifiers(int key, int modifiers, bool *consumed) { |
65ec6247 | 5586 | DwellEnd(false); |
9ce192d4 | 5587 | int msg = kmap.Find(key, modifiers); |
65ec6247 RD |
5588 | if (msg) { |
5589 | if (consumed) | |
5590 | *consumed = true; | |
9ce192d4 | 5591 | return WndProc(msg, 0, 0); |
65ec6247 RD |
5592 | } else { |
5593 | if (consumed) | |
5594 | *consumed = false; | |
9ce192d4 | 5595 | return KeyDefault(key, modifiers); |
65ec6247 | 5596 | } |
9ce192d4 RD |
5597 | } |
5598 | ||
1dcf666d RD |
5599 | int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed) { |
5600 | int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | | |
5601 | (alt ? SCI_ALT : 0); | |
5602 | return KeyDownWithModifiers(key, modifiers, consumed); | |
9ce192d4 RD |
5603 | } |
5604 | ||
5605 | void Editor::Indent(bool forwards) { | |
9e96e16f RD |
5606 | for (size_t r=0; r<sel.Count(); r++) { |
5607 | int lineOfAnchor = pdoc->LineFromPosition(sel.Range(r).anchor.Position()); | |
5608 | int caretPosition = sel.Range(r).caret.Position(); | |
5609 | int lineCurrentPos = pdoc->LineFromPosition(caretPosition); | |
5610 | if (lineOfAnchor == lineCurrentPos) { | |
5611 | if (forwards) { | |
5612 | UndoGroup ug(pdoc); | |
5613 | pdoc->DeleteChars(sel.Range(r).Start().Position(), sel.Range(r).Length()); | |
5614 | caretPosition = sel.Range(r).caret.Position(); | |
5615 | if (pdoc->GetColumn(caretPosition) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) && | |
5616 | pdoc->tabIndents) { | |
5617 | int indentation = pdoc->GetLineIndentation(lineCurrentPos); | |
5618 | int indentationStep = pdoc->IndentSize(); | |
5619 | pdoc->SetLineIndentation(lineCurrentPos, indentation + indentationStep - indentation % indentationStep); | |
5620 | sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos)); | |
65ec6247 | 5621 | } else { |
9e96e16f RD |
5622 | if (pdoc->useTabs) { |
5623 | pdoc->InsertChar(caretPosition, '\t'); | |
5624 | sel.Range(r) = SelectionRange(caretPosition+1); | |
5625 | } else { | |
5626 | int numSpaces = (pdoc->tabInChars) - | |
5627 | (pdoc->GetColumn(caretPosition) % (pdoc->tabInChars)); | |
5628 | if (numSpaces < 1) | |
5629 | numSpaces = pdoc->tabInChars; | |
5630 | for (int i = 0; i < numSpaces; i++) { | |
5631 | pdoc->InsertChar(caretPosition + i, ' '); | |
5632 | } | |
5633 | sel.Range(r) = SelectionRange(caretPosition+numSpaces); | |
65ec6247 | 5634 | } |
9e96e16f RD |
5635 | } |
5636 | } else { | |
5637 | if (pdoc->GetColumn(caretPosition) <= pdoc->GetLineIndentation(lineCurrentPos) && | |
5638 | pdoc->tabIndents) { | |
5639 | UndoGroup ug(pdoc); | |
5640 | int indentation = pdoc->GetLineIndentation(lineCurrentPos); | |
5641 | int indentationStep = pdoc->IndentSize(); | |
5642 | pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep); | |
1dcf666d | 5643 | sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos)); |
9e96e16f RD |
5644 | } else { |
5645 | int newColumn = ((pdoc->GetColumn(caretPosition) - 1) / pdoc->tabInChars) * | |
5646 | pdoc->tabInChars; | |
5647 | if (newColumn < 0) | |
5648 | newColumn = 0; | |
5649 | int newPos = caretPosition; | |
5650 | while (pdoc->GetColumn(newPos) > newColumn) | |
5651 | newPos--; | |
5652 | sel.Range(r) = SelectionRange(newPos); | |
65ec6247 RD |
5653 | } |
5654 | } | |
9e96e16f RD |
5655 | } else { // Multiline |
5656 | int anchorPosOnLine = sel.Range(r).anchor.Position() - pdoc->LineStart(lineOfAnchor); | |
5657 | int currentPosPosOnLine = caretPosition - pdoc->LineStart(lineCurrentPos); | |
5658 | // Multiple lines selected so indent / dedent | |
5659 | int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos); | |
5660 | int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos); | |
5661 | if (pdoc->LineStart(lineBottomSel) == sel.Range(r).anchor.Position() || pdoc->LineStart(lineBottomSel) == caretPosition) | |
5662 | lineBottomSel--; // If not selecting any characters on a line, do not indent | |
5663 | { | |
5664 | UndoGroup ug(pdoc); | |
5665 | pdoc->Indent(forwards, lineBottomSel, lineTopSel); | |
5666 | } | |
5667 | if (lineOfAnchor < lineCurrentPos) { | |
5668 | if (currentPosPosOnLine == 0) | |
5669 | sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor)); | |
5670 | else | |
5671 | sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor)); | |
65ec6247 | 5672 | } else { |
9e96e16f RD |
5673 | if (anchorPosOnLine == 0) |
5674 | sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor)); | |
5675 | else | |
5676 | sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1)); | |
d134f170 | 5677 | } |
d134f170 | 5678 | } |
9ce192d4 RD |
5679 | } |
5680 | } | |
5681 | ||
1dcf666d RD |
5682 | class CaseFolderASCII : public CaseFolderTable { |
5683 | public: | |
5684 | CaseFolderASCII() { | |
5685 | StandardASCII(); | |
5686 | } | |
5687 | ~CaseFolderASCII() { | |
5688 | } | |
5689 | }; | |
5690 | ||
5691 | ||
5692 | CaseFolder *Editor::CaseFolderForEncoding() { | |
5693 | // Simple default that only maps ASCII upper case to lower case. | |
5694 | return new CaseFolderASCII(); | |
5695 | } | |
5696 | ||
65ec6247 RD |
5697 | /** |
5698 | * Search of a text in the document, in the given range. | |
5699 | * @return The position of the found text, -1 if not found. | |
5700 | */ | |
5701 | long Editor::FindText( | |
7e0c58e9 RD |
5702 | uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD, |
5703 | ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX. | |
5704 | sptr_t lParam) { ///< @c TextToFind structure: The text to search for in the given range. | |
65ec6247 | 5705 | |
9e96e16f | 5706 | Sci_TextToFind *ft = reinterpret_cast<Sci_TextToFind *>(lParam); |
88a8b04e | 5707 | int lengthFound = istrlen(ft->lpstrText); |
1dcf666d | 5708 | std::auto_ptr<CaseFolder> pcf(CaseFolderForEncoding()); |
9ce192d4 | 5709 | int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText, |
7e0c58e9 RD |
5710 | (wParam & SCFIND_MATCHCASE) != 0, |
5711 | (wParam & SCFIND_WHOLEWORD) != 0, | |
5712 | (wParam & SCFIND_WORDSTART) != 0, | |
5713 | (wParam & SCFIND_REGEXP) != 0, | |
9e96e16f | 5714 | wParam, |
1dcf666d RD |
5715 | &lengthFound, |
5716 | pcf.get()); | |
9ce192d4 | 5717 | if (pos != -1) { |
b8b0e402 RD |
5718 | ft->chrgText.cpMin = pos; |
5719 | ft->chrgText.cpMax = pos + lengthFound; | |
9ce192d4 RD |
5720 | } |
5721 | return pos; | |
5722 | } | |
5723 | ||
65ec6247 RD |
5724 | /** |
5725 | * Relocatable search support : Searches relative to current selection | |
5726 | * point and sets the selection to the found text range with | |
5727 | * each search. | |
5728 | */ | |
5729 | /** | |
5730 | * Anchor following searches at current selection start: This allows | |
5731 | * multiple incremental interactive searches to be macro recorded | |
5732 | * while still setting the selection to found text so the find/select | |
5733 | * operation is self-contained. | |
5734 | */ | |
9ce192d4 | 5735 | void Editor::SearchAnchor() { |
9e96e16f | 5736 | searchAnchor = SelectionStart().Position(); |
9ce192d4 RD |
5737 | } |
5738 | ||
1dcf666d RD |
5739 | // Simple RAII wrapper for CaseFolder as std::auto_ptr is now deprecated |
5740 | class ScopedCaseFolder { | |
5741 | CaseFolder *pcf; | |
5742 | public: | |
5743 | ScopedCaseFolder(CaseFolder *pcf_) : pcf(pcf_) { | |
5744 | } | |
5745 | ~ScopedCaseFolder() { | |
5746 | delete pcf; | |
5747 | pcf = 0; | |
5748 | } | |
5749 | CaseFolder *get() const { return pcf; } | |
5750 | }; | |
5751 | ||
65ec6247 RD |
5752 | /** |
5753 | * Find text from current search anchor: Must call @c SearchAnchor first. | |
5754 | * Used for next text and previous text requests. | |
5755 | * @return The position of the found text, -1 if not found. | |
5756 | */ | |
5757 | long Editor::SearchText( | |
8e54aaed RD |
5758 | unsigned int iMessage, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV. |
5759 | uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD, | |
7e0c58e9 | 5760 | ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX. |
a834585d | 5761 | sptr_t lParam) { ///< The text to search for. |
65ec6247 | 5762 | |
9ce192d4 RD |
5763 | const char *txt = reinterpret_cast<char *>(lParam); |
5764 | int pos; | |
88a8b04e | 5765 | int lengthFound = istrlen(txt); |
1dcf666d | 5766 | ScopedCaseFolder pcf(CaseFolderForEncoding()); |
9ce192d4 | 5767 | if (iMessage == SCI_SEARCHNEXT) { |
d134f170 | 5768 | pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt, |
7e0c58e9 RD |
5769 | (wParam & SCFIND_MATCHCASE) != 0, |
5770 | (wParam & SCFIND_WHOLEWORD) != 0, | |
5771 | (wParam & SCFIND_WORDSTART) != 0, | |
5772 | (wParam & SCFIND_REGEXP) != 0, | |
9e96e16f | 5773 | wParam, |
1dcf666d RD |
5774 | &lengthFound, |
5775 | pcf.get()); | |
9ce192d4 | 5776 | } else { |
d134f170 | 5777 | pos = pdoc->FindText(searchAnchor, 0, txt, |
7e0c58e9 RD |
5778 | (wParam & SCFIND_MATCHCASE) != 0, |
5779 | (wParam & SCFIND_WHOLEWORD) != 0, | |
5780 | (wParam & SCFIND_WORDSTART) != 0, | |
5781 | (wParam & SCFIND_REGEXP) != 0, | |
9e96e16f | 5782 | wParam, |
1dcf666d RD |
5783 | &lengthFound, |
5784 | pcf.get()); | |
9ce192d4 | 5785 | } |
9ce192d4 | 5786 | if (pos != -1) { |
65ec6247 | 5787 | SetSelection(pos, pos + lengthFound); |
9ce192d4 RD |
5788 | } |
5789 | ||
5790 | return pos; | |
5791 | } | |
5792 | ||
1dcf666d RD |
5793 | std::string Editor::CaseMapString(const std::string &s, int caseMapping) { |
5794 | std::string ret(s); | |
5795 | for (size_t i=0; i<ret.size(); i++) { | |
5796 | switch (caseMapping) { | |
5797 | case cmUpper: | |
5798 | if (ret[i] >= 'a' && ret[i] <= 'z') | |
5799 | ret[i] = static_cast<char>(ret[i] - 'a' + 'A'); | |
5800 | break; | |
5801 | case cmLower: | |
5802 | if (ret[i] >= 'A' && ret[i] <= 'Z') | |
5803 | ret[i] = static_cast<char>(ret[i] - 'A' + 'a'); | |
5804 | break; | |
5805 | } | |
5806 | } | |
5807 | return ret; | |
5808 | } | |
5809 | ||
65ec6247 RD |
5810 | /** |
5811 | * Search for text in the target range of the document. | |
5812 | * @return The position of the found text, -1 if not found. | |
5813 | */ | |
5814 | long Editor::SearchInTarget(const char *text, int length) { | |
5815 | int lengthFound = length; | |
1dcf666d RD |
5816 | |
5817 | ScopedCaseFolder pcf(CaseFolderForEncoding()); | |
65ec6247 | 5818 | int pos = pdoc->FindText(targetStart, targetEnd, text, |
7e0c58e9 RD |
5819 | (searchFlags & SCFIND_MATCHCASE) != 0, |
5820 | (searchFlags & SCFIND_WHOLEWORD) != 0, | |
5821 | (searchFlags & SCFIND_WORDSTART) != 0, | |
5822 | (searchFlags & SCFIND_REGEXP) != 0, | |
9e96e16f | 5823 | searchFlags, |
1dcf666d RD |
5824 | &lengthFound, |
5825 | pcf.get()); | |
65ec6247 RD |
5826 | if (pos != -1) { |
5827 | targetStart = pos; | |
5828 | targetEnd = pos + lengthFound; | |
5829 | } | |
5830 | return pos; | |
5831 | } | |
5832 | ||
9ce192d4 RD |
5833 | void Editor::GoToLine(int lineNo) { |
5834 | if (lineNo > pdoc->LinesTotal()) | |
5835 | lineNo = pdoc->LinesTotal(); | |
5836 | if (lineNo < 0) | |
5837 | lineNo = 0; | |
5838 | SetEmptySelection(pdoc->LineStart(lineNo)); | |
5839 | ShowCaretAtCurrentPosition(); | |
5840 | EnsureCaretVisible(); | |
5841 | } | |
5842 | ||
5843 | static bool Close(Point pt1, Point pt2) { | |
5844 | if (abs(pt1.x - pt2.x) > 3) | |
5845 | return false; | |
5846 | if (abs(pt1.y - pt2.y) > 3) | |
5847 | return false; | |
5848 | return true; | |
5849 | } | |
5850 | ||
5851 | char *Editor::CopyRange(int start, int end) { | |
5852 | char *text = 0; | |
5853 | if (start < end) { | |
5854 | int len = end - start; | |
5855 | text = new char[len + 1]; | |
9e96e16f RD |
5856 | for (int i = 0; i < len; i++) { |
5857 | text[i] = pdoc->CharAt(start + i); | |
9ce192d4 | 5858 | } |
9e96e16f | 5859 | text[len] = '\0'; |
9ce192d4 RD |
5860 | } |
5861 | return text; | |
5862 | } | |
5863 | ||
1dcf666d RD |
5864 | std::string Editor::RangeText(int start, int end) const { |
5865 | if (start < end) { | |
5866 | int len = end - start; | |
5867 | std::string ret(len, '\0'); | |
5868 | for (int i = 0; i < len; i++) { | |
5869 | ret[i] = pdoc->CharAt(start + i); | |
5870 | } | |
5871 | return ret; | |
5872 | } | |
5873 | return std::string(); | |
5874 | } | |
5875 | ||
9e96e16f RD |
5876 | void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) { |
5877 | if (sel.Empty()) { | |
5878 | if (allowLineCopy) { | |
5879 | int currentLine = pdoc->LineFromPosition(sel.MainCaret()); | |
5880 | int start = pdoc->LineStart(currentLine); | |
5881 | int end = pdoc->LineEnd(currentLine); | |
5882 | ||
5883 | char *text = CopyRange(start, end); | |
1dcf666d | 5884 | size_t textLen = text ? strlen(text) : 0; |
9e96e16f RD |
5885 | // include room for \r\n\0 |
5886 | textLen += 3; | |
5887 | char *textWithEndl = new char[textLen]; | |
5888 | textWithEndl[0] = '\0'; | |
5889 | if (text) | |
5890 | strncat(textWithEndl, text, textLen); | |
5891 | if (pdoc->eolMode != SC_EOL_LF) | |
5892 | strncat(textWithEndl, "\r", textLen); | |
5893 | if (pdoc->eolMode != SC_EOL_CR) | |
5894 | strncat(textWithEndl, "\n", textLen); | |
1dcf666d | 5895 | ss->Set(textWithEndl, static_cast<int>(strlen(textWithEndl) + 1), |
9e96e16f RD |
5896 | pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true); |
5897 | delete []text; | |
5898 | } | |
8e54aaed | 5899 | } else { |
9e96e16f RD |
5900 | int delimiterLength = 0; |
5901 | if (sel.selType == Selection::selRectangle) { | |
5902 | if (pdoc->eolMode == SC_EOL_CRLF) { | |
5903 | delimiterLength = 2; | |
5904 | } else { | |
5905 | delimiterLength = 1; | |
8e54aaed | 5906 | } |
9ce192d4 | 5907 | } |
1dcf666d | 5908 | size_t size = sel.Length() + delimiterLength * sel.Count(); |
9e96e16f RD |
5909 | char *text = new char[size + 1]; |
5910 | int j = 0; | |
1dcf666d | 5911 | std::vector<SelectionRange> rangesInOrder = sel.RangesCopy(); |
9e96e16f | 5912 | if (sel.selType == Selection::selRectangle) |
1dcf666d | 5913 | std::sort(rangesInOrder.begin(), rangesInOrder.end()); |
9e96e16f RD |
5914 | for (size_t r=0; r<rangesInOrder.size(); r++) { |
5915 | SelectionRange current = rangesInOrder[r]; | |
5916 | for (int i = current.Start().Position(); | |
5917 | i < current.End().Position(); | |
5918 | i++) { | |
5919 | text[j++] = pdoc->CharAt(i); | |
5920 | } | |
5921 | if (sel.selType == Selection::selRectangle) { | |
5922 | if (pdoc->eolMode != SC_EOL_LF) { | |
5923 | text[j++] = '\r'; | |
5924 | } | |
5925 | if (pdoc->eolMode != SC_EOL_CR) { | |
5926 | text[j++] = '\n'; | |
9ce192d4 | 5927 | } |
9ce192d4 RD |
5928 | } |
5929 | } | |
9e96e16f | 5930 | text[size] = '\0'; |
1dcf666d | 5931 | ss->Set(text, static_cast<int>(size + 1), pdoc->dbcsCodePage, |
9e96e16f | 5932 | vs.styles[STYLE_DEFAULT].characterSet, sel.IsRectangular(), sel.selType == Selection::selLines); |
9ce192d4 | 5933 | } |
e14d10b0 RD |
5934 | } |
5935 | ||
5936 | void Editor::CopyRangeToClipboard(int start, int end) { | |
5937 | start = pdoc->ClampPositionIntoDocument(start); | |
5938 | end = pdoc->ClampPositionIntoDocument(end); | |
5939 | SelectionText selectedText; | |
591d01be | 5940 | selectedText.Set(CopyRange(start, end), end - start + 1, |
9e96e16f | 5941 | pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false); |
e14d10b0 RD |
5942 | CopyToClipboard(selectedText); |
5943 | } | |
5944 | ||
5945 | void Editor::CopyText(int length, const char *text) { | |
5946 | SelectionText selectedText; | |
b8193d80 | 5947 | selectedText.Copy(text, length + 1, |
9e96e16f | 5948 | pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false); |
e14d10b0 | 5949 | CopyToClipboard(selectedText); |
9ce192d4 RD |
5950 | } |
5951 | ||
9e96e16f RD |
5952 | void Editor::SetDragPosition(SelectionPosition newPos) { |
5953 | if (newPos.Position() >= 0) { | |
d134f170 | 5954 | newPos = MovePositionOutsideChar(newPos, 1); |
9ce192d4 RD |
5955 | posDrop = newPos; |
5956 | } | |
9e96e16f | 5957 | if (!(posDrag == newPos)) { |
9ce192d4 RD |
5958 | caret.on = true; |
5959 | SetTicking(true); | |
5960 | InvalidateCaret(); | |
5961 | posDrag = newPos; | |
5962 | InvalidateCaret(); | |
5963 | } | |
5964 | } | |
5965 | ||
65ec6247 RD |
5966 | void Editor::DisplayCursor(Window::Cursor c) { |
5967 | if (cursorMode == SC_CURSORNORMAL) | |
5968 | wMain.SetCursor(c); | |
5969 | else | |
5970 | wMain.SetCursor(static_cast<Window::Cursor>(cursorMode)); | |
5971 | } | |
5972 | ||
7e0c58e9 RD |
5973 | bool Editor::DragThreshold(Point ptStart, Point ptNow) { |
5974 | int xMove = ptStart.x - ptNow.x; | |
5975 | int yMove = ptStart.y - ptNow.y; | |
5976 | int distanceSquared = xMove * xMove + yMove * yMove; | |
5977 | return distanceSquared > 16; | |
5978 | } | |
5979 | ||
9ce192d4 RD |
5980 | void Editor::StartDrag() { |
5981 | // Always handled by subclasses | |
5982 | //SetMouseCapture(true); | |
65ec6247 | 5983 | //DisplayCursor(Window::cursorArrow); |
9ce192d4 RD |
5984 | } |
5985 | ||
9e96e16f | 5986 | void Editor::DropAt(SelectionPosition position, const char *value, bool moving, bool rectangular) { |
7e0c58e9 RD |
5987 | //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position); |
5988 | if (inDragDrop == ddDragging) | |
9ce192d4 RD |
5989 | dropWentOutside = false; |
5990 | ||
9e96e16f | 5991 | bool positionWasInSelection = PositionInSelection(position.Position()); |
9ce192d4 | 5992 | |
d134f170 RD |
5993 | bool positionOnEdgeOfSelection = |
5994 | (position == SelectionStart()) || (position == SelectionEnd()); | |
f6bcfd97 | 5995 | |
9e96e16f | 5996 | if ((inDragDrop != ddDragging) || !(positionWasInSelection) || |
d134f170 | 5997 | (positionOnEdgeOfSelection && !moving)) { |
9ce192d4 | 5998 | |
9e96e16f RD |
5999 | SelectionPosition selStart = SelectionStart(); |
6000 | SelectionPosition selEnd = SelectionEnd(); | |
d134f170 | 6001 | |
9e96e16f | 6002 | UndoGroup ug(pdoc); |
9ce192d4 | 6003 | |
9e96e16f | 6004 | SelectionPosition positionAfterDeletion = position; |
7e0c58e9 | 6005 | if ((inDragDrop == ddDragging) && moving) { |
9ce192d4 | 6006 | // Remove dragged out text |
9e96e16f RD |
6007 | if (rectangular || sel.selType == Selection::selLines) { |
6008 | for (size_t r=0; r<sel.Count(); r++) { | |
6009 | if (position >= sel.Range(r).Start()) { | |
6010 | if (position > sel.Range(r).End()) { | |
6011 | positionAfterDeletion.Add(-sel.Range(r).Length()); | |
9ce192d4 | 6012 | } else { |
9e96e16f | 6013 | positionAfterDeletion.Add(-SelectionRange(position, sel.Range(r).Start()).Length()); |
9ce192d4 RD |
6014 | } |
6015 | } | |
6016 | } | |
6017 | } else { | |
6018 | if (position > selStart) { | |
9e96e16f | 6019 | positionAfterDeletion.Add(-SelectionRange(selEnd, selStart).Length()); |
9ce192d4 RD |
6020 | } |
6021 | } | |
6022 | ClearSelection(); | |
6023 | } | |
6024 | position = positionAfterDeletion; | |
d134f170 | 6025 | |
9ce192d4 | 6026 | if (rectangular) { |
88a8b04e | 6027 | PasteRectangular(position, value, istrlen(value)); |
9ce192d4 | 6028 | // Should try to select new rectangle but it may not be a rectangle now so just select the drop position |
9e96e16f | 6029 | SetEmptySelection(position); |
8e54aaed | 6030 | } else { |
9e96e16f RD |
6031 | position = MovePositionOutsideChar(position, sel.MainCaret() - position.Position()); |
6032 | position = SelectionPosition(InsertSpace(position.Position(), position.VirtualSpace())); | |
6033 | if (pdoc->InsertCString(position.Position(), value)) { | |
6034 | SelectionPosition posAfterInsertion = position; | |
6035 | posAfterInsertion.Add(istrlen(value)); | |
6036 | SetSelection(posAfterInsertion, position); | |
6037 | } | |
9ce192d4 | 6038 | } |
9e96e16f RD |
6039 | } else if (inDragDrop == ddDragging) { |
6040 | SetEmptySelection(position); | |
6041 | } | |
6042 | } | |
6043 | ||
6044 | /** | |
6045 | * @return true if given position is inside the selection, | |
6046 | */ | |
6047 | bool Editor::PositionInSelection(int pos) { | |
6048 | pos = MovePositionOutsideChar(pos, sel.MainCaret() - pos); | |
6049 | for (size_t r=0; r<sel.Count(); r++) { | |
6050 | if (sel.Range(r).Contains(pos)) | |
6051 | return true; | |
9ce192d4 | 6052 | } |
9e96e16f | 6053 | return false; |
9ce192d4 RD |
6054 | } |
6055 | ||
6056 | bool Editor::PointInSelection(Point pt) { | |
1dcf666d RD |
6057 | SelectionPosition pos = SPositionFromLocation(pt, false, true); |
6058 | Point ptPos = LocationFromPosition(pos); | |
9e96e16f RD |
6059 | for (size_t r=0; r<sel.Count(); r++) { |
6060 | SelectionRange range = sel.Range(r); | |
6061 | if (range.Contains(pos)) { | |
6062 | bool hit = true; | |
6063 | if (pos == range.Start()) { | |
6064 | // see if just before selection | |
1dcf666d | 6065 | if (pt.x < ptPos.x) { |
9e96e16f RD |
6066 | hit = false; |
6067 | } | |
8e54aaed | 6068 | } |
9e96e16f RD |
6069 | if (pos == range.End()) { |
6070 | // see if just after selection | |
1dcf666d | 6071 | if (pt.x > ptPos.x) { |
9e96e16f RD |
6072 | hit = false; |
6073 | } | |
8e54aaed | 6074 | } |
9e96e16f RD |
6075 | if (hit) |
6076 | return true; | |
9ce192d4 | 6077 | } |
9ce192d4 RD |
6078 | } |
6079 | return false; | |
6080 | } | |
6081 | ||
6082 | bool Editor::PointInSelMargin(Point pt) { | |
6083 | // Really means: "Point in a margin" | |
6084 | if (vs.fixedColumnWidth > 0) { // There is a margin | |
6085 | PRectangle rcSelMargin = GetClientRectangle(); | |
6086 | rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth; | |
6087 | return rcSelMargin.Contains(pt); | |
6088 | } else { | |
6089 | return false; | |
6090 | } | |
6091 | } | |
6092 | ||
1dcf666d RD |
6093 | Window::Cursor Editor::GetMarginCursor(Point pt) { |
6094 | int x = 0; | |
6095 | for (int margin = 0; margin < ViewStyle::margins; margin++) { | |
6096 | if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width)) | |
6097 | return static_cast<Window::Cursor>(vs.ms[margin].cursor); | |
6098 | x += vs.ms[margin].width; | |
6099 | } | |
6100 | return Window::cursorReverseArrow; | |
6101 | } | |
6102 | ||
6103 | void Editor::TrimAndSetSelection(int currentPos_, int anchor_) { | |
6104 | sel.TrimSelection(SelectionRange(currentPos_, anchor_)); | |
6105 | SetSelection(currentPos_, anchor_); | |
6106 | } | |
6107 | ||
6108 | void Editor::LineSelection(int lineCurrentPos_, int lineAnchorPos_, bool wholeLine) { | |
6109 | int selCurrentPos, selAnchorPos; | |
6110 | if (wholeLine) { | |
6111 | int lineCurrent_ = pdoc->LineFromPosition(lineCurrentPos_); | |
6112 | int lineAnchor_ = pdoc->LineFromPosition(lineAnchorPos_); | |
6113 | if (lineAnchorPos_ < lineCurrentPos_) { | |
6114 | selCurrentPos = pdoc->LineStart(lineCurrent_ + 1); | |
6115 | selAnchorPos = pdoc->LineStart(lineAnchor_); | |
6116 | } else if (lineAnchorPos_ > lineCurrentPos_) { | |
6117 | selCurrentPos = pdoc->LineStart(lineCurrent_); | |
6118 | selAnchorPos = pdoc->LineStart(lineAnchor_ + 1); | |
6119 | } else { // Same line, select it | |
6120 | selCurrentPos = pdoc->LineStart(lineAnchor_ + 1); | |
6121 | selAnchorPos = pdoc->LineStart(lineAnchor_); | |
6122 | } | |
6123 | } else { | |
6124 | if (lineAnchorPos_ < lineCurrentPos_) { | |
6125 | selCurrentPos = StartEndDisplayLine(lineCurrentPos_, false) + 1; | |
6126 | selCurrentPos = pdoc->MovePositionOutsideChar(selCurrentPos, 1); | |
6127 | selAnchorPos = StartEndDisplayLine(lineAnchorPos_, true); | |
6128 | } else if (lineAnchorPos_ > lineCurrentPos_) { | |
6129 | selCurrentPos = StartEndDisplayLine(lineCurrentPos_, true); | |
6130 | selAnchorPos = StartEndDisplayLine(lineAnchorPos_, false) + 1; | |
6131 | selAnchorPos = pdoc->MovePositionOutsideChar(selAnchorPos, 1); | |
6132 | } else { // Same line, select it | |
6133 | selCurrentPos = StartEndDisplayLine(lineAnchorPos_, false) + 1; | |
6134 | selCurrentPos = pdoc->MovePositionOutsideChar(selCurrentPos, 1); | |
6135 | selAnchorPos = StartEndDisplayLine(lineAnchorPos_, true); | |
6136 | } | |
6137 | } | |
6138 | TrimAndSetSelection(selCurrentPos, selAnchorPos); | |
6139 | } | |
6140 | ||
6141 | void Editor::WordSelection(int pos) { | |
6142 | if (pos < wordSelectAnchorStartPos) { | |
6143 | // Extend backward to the word containing pos. | |
6144 | // Skip ExtendWordSelect if the line is empty or if pos is after the last character. | |
6145 | // This ensures that a series of empty lines isn't counted as a single "word". | |
6146 | if (!pdoc->IsLineEndPosition(pos)) | |
6147 | pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos + 1, 1), -1); | |
6148 | TrimAndSetSelection(pos, wordSelectAnchorEndPos); | |
6149 | } else if (pos > wordSelectAnchorEndPos) { | |
6150 | // Extend forward to the word containing the character to the left of pos. | |
6151 | // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line. | |
6152 | // This ensures that a series of empty lines isn't counted as a single "word". | |
6153 | if (pos > pdoc->LineStart(pdoc->LineFromPosition(pos))) | |
6154 | pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos - 1, -1), 1); | |
6155 | TrimAndSetSelection(pos, wordSelectAnchorStartPos); | |
6156 | } else { | |
6157 | // Select only the anchored word | |
6158 | if (pos >= originalAnchorPos) | |
6159 | TrimAndSetSelection(wordSelectAnchorEndPos, wordSelectAnchorStartPos); | |
6160 | else | |
6161 | TrimAndSetSelection(wordSelectAnchorStartPos, wordSelectAnchorEndPos); | |
65ec6247 RD |
6162 | } |
6163 | } | |
6164 | ||
6165 | void Editor::DwellEnd(bool mouseMoved) { | |
6166 | if (mouseMoved) | |
6167 | ticksToDwell = dwellDelay; | |
6168 | else | |
6169 | ticksToDwell = SC_TIME_FOREVER; | |
6170 | if (dwelling && (dwellDelay < SC_TIME_FOREVER)) { | |
6171 | dwelling = false; | |
6172 | NotifyDwelling(ptMouseLast, dwelling); | |
6173 | } | |
6174 | } | |
6175 | ||
1dcf666d RD |
6176 | void Editor::MouseLeave() { |
6177 | SetHotSpotRange(NULL); | |
6178 | if (!HaveMouseCapture()) { | |
6179 | ptMouseLast = Point(-1,-1); | |
6180 | DwellEnd(true); | |
6181 | } | |
6182 | } | |
6183 | ||
6184 | static bool AllowVirtualSpace(int virtualSpaceOptions, bool rectangular) { | |
6185 | return (!rectangular && ((virtualSpaceOptions & SCVS_USERACCESSIBLE) != 0)) | |
9e96e16f RD |
6186 | || (rectangular && ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) != 0)); |
6187 | } | |
6188 | ||
9ce192d4 | 6189 | void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { |
7e0c58e9 | 6190 | //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop); |
9ce192d4 | 6191 | ptMouseLast = pt; |
9e96e16f RD |
6192 | SelectionPosition newPos = SPositionFromLocation(pt, false, false, AllowVirtualSpace(virtualSpaceOptions, alt)); |
6193 | newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position()); | |
7e0c58e9 | 6194 | inDragDrop = ddNone; |
9e96e16f | 6195 | sel.SetMoveExtends(false); |
d134f170 | 6196 | |
1dcf666d | 6197 | if (NotifyMarginClick(pt, shift, ctrl, alt)) |
65ec6247 | 6198 | return; |
d134f170 | 6199 | |
9e96e16f | 6200 | NotifyIndicatorClick(true, newPos.Position(), shift, ctrl, alt); |
7e0c58e9 | 6201 | |
65ec6247 | 6202 | bool inSelMargin = PointInSelMargin(pt); |
1dcf666d RD |
6203 | // In margin ctrl+(double)click should always select everything |
6204 | if (ctrl && inSelMargin) { | |
6205 | SelectAll(); | |
6206 | lastClickTime = curTime; | |
6207 | lastClick = pt; | |
6208 | return; | |
6209 | } | |
6210 | if (shift && !inSelMargin) { | |
6211 | SetSelection(newPos); | |
9ce192d4 RD |
6212 | } |
6213 | if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) { | |
6214 | //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime); | |
6215 | SetMouseCapture(true); | |
1dcf666d RD |
6216 | if (!ctrl || !multipleSelection || (selectionType != selChar && selectionType != selWord)) |
6217 | SetEmptySelection(newPos.Position()); | |
9ce192d4 RD |
6218 | bool doubleClick = false; |
6219 | // Stop mouse button bounce changing selection type | |
9e730a78 | 6220 | if (!Platform::MouseButtonBounce() || curTime != lastClickTime) { |
1dcf666d RD |
6221 | if (inSelMargin) { |
6222 | // Inside margin selection type should be either selSubLine or selWholeLine. | |
6223 | if (selectionType == selSubLine) { | |
6224 | // If it is selSubLine, we're inside a *double* click and word wrap is enabled, | |
6225 | // so we switch to selWholeLine in order to select whole line. | |
6226 | selectionType = selWholeLine; | |
6227 | } else if (selectionType != selSubLine && selectionType != selWholeLine) { | |
6228 | // If it is neither, reset selection type to line selection. | |
6229 | selectionType = ((wrapState != eWrapNone) && (marginOptions & SC_MARGINOPTION_SUBLINESELECT)) ? selSubLine : selWholeLine; | |
6230 | } | |
9ce192d4 | 6231 | } else { |
1dcf666d RD |
6232 | if (selectionType == selChar) { |
6233 | selectionType = selWord; | |
6234 | doubleClick = true; | |
6235 | } else if (selectionType == selWord) { | |
6236 | // Since we ended up here, we're inside a *triple* click, which should always select | |
6237 | // whole line irregardless of word wrap being enabled or not. | |
6238 | selectionType = selWholeLine; | |
6239 | } else { | |
6240 | selectionType = selChar; | |
6241 | originalAnchorPos = sel.MainCaret(); | |
6242 | } | |
9ce192d4 RD |
6243 | } |
6244 | } | |
6245 | ||
6246 | if (selectionType == selWord) { | |
1dcf666d RD |
6247 | int charPos = originalAnchorPos; |
6248 | if (sel.MainCaret() == originalAnchorPos) { | |
6249 | charPos = PositionFromLocation(pt, false, true); | |
6250 | charPos = MovePositionOutsideChar(charPos, -1); | |
6251 | } | |
6252 | ||
6253 | int startWord, endWord; | |
6254 | if ((sel.MainCaret() >= originalAnchorPos) && !pdoc->IsLineEndPosition(charPos)) { | |
6255 | startWord = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(charPos + 1, 1), -1); | |
6256 | endWord = pdoc->ExtendWordSelect(charPos, 1); | |
6257 | } else { | |
6258 | // Selecting backwards, or anchor beyond last character on line. In these cases, | |
6259 | // we select the word containing the character to the *left* of the anchor. | |
6260 | if (charPos > pdoc->LineStart(pdoc->LineFromPosition(charPos))) { | |
6261 | startWord = pdoc->ExtendWordSelect(charPos, -1); | |
6262 | endWord = pdoc->ExtendWordSelect(startWord, 1); | |
6263 | } else { | |
6264 | // Anchor at start of line; select nothing to begin with. | |
6265 | startWord = charPos; | |
6266 | endWord = charPos; | |
6267 | } | |
6268 | } | |
6269 | ||
6270 | wordSelectAnchorStartPos = startWord; | |
6271 | wordSelectAnchorEndPos = endWord; | |
6272 | wordSelectInitialCaretPos = sel.MainCaret(); | |
6273 | WordSelection(wordSelectInitialCaretPos); | |
6274 | } else if (selectionType == selSubLine || selectionType == selWholeLine) { | |
6275 | lineAnchorPos = newPos.Position(); | |
6276 | LineSelection(lineAnchorPos, lineAnchorPos, selectionType == selWholeLine); | |
9ce192d4 | 6277 | //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos); |
9e730a78 | 6278 | } else { |
9e96e16f | 6279 | SetEmptySelection(sel.MainCaret()); |
9ce192d4 RD |
6280 | } |
6281 | //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos); | |
9e730a78 | 6282 | if (doubleClick) { |
7e0c58e9 | 6283 | NotifyDoubleClick(pt, shift, ctrl, alt); |
9e96e16f RD |
6284 | if (PositionIsHotspot(newPos.Position())) |
6285 | NotifyHotSpotDoubleClicked(newPos.Position(), shift, ctrl, alt); | |
9e730a78 | 6286 | } |
9ce192d4 | 6287 | } else { // Single click |
65ec6247 | 6288 | if (inSelMargin) { |
9e96e16f | 6289 | sel.selType = Selection::selStream; |
9ce192d4 | 6290 | if (!shift) { |
1dcf666d RD |
6291 | // Single click in margin: select whole line or only subline if word wrap is enabled |
6292 | lineAnchorPos = newPos.Position(); | |
6293 | selectionType = ((wrapState != eWrapNone) && (marginOptions & SC_MARGINOPTION_SUBLINESELECT)) ? selSubLine : selWholeLine; | |
6294 | LineSelection(lineAnchorPos, lineAnchorPos, selectionType == selWholeLine); | |
9ce192d4 | 6295 | } else { |
65ec6247 | 6296 | // Single shift+click in margin: select from line anchor to clicked line |
9e96e16f | 6297 | if (sel.MainAnchor() > sel.MainCaret()) |
1dcf666d | 6298 | lineAnchorPos = sel.MainAnchor() - 1; |
65ec6247 | 6299 | else |
1dcf666d RD |
6300 | lineAnchorPos = sel.MainAnchor(); |
6301 | // Reset selection type if there is an empty selection. | |
6302 | // This ensures that we don't end up stuck in previous selection mode, which is no longer valid. | |
6303 | // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine. | |
6304 | // This ensures that we continue selecting in the same selection mode. | |
6305 | if (sel.Empty() || (selectionType != selSubLine && selectionType != selWholeLine)) | |
6306 | selectionType = ((wrapState != eWrapNone) && (marginOptions & SC_MARGINOPTION_SUBLINESELECT)) ? selSubLine : selWholeLine; | |
6307 | LineSelection(newPos.Position(), lineAnchorPos, selectionType == selWholeLine); | |
9ce192d4 | 6308 | } |
65ec6247 | 6309 | |
9e96e16f | 6310 | SetDragPosition(SelectionPosition(invalidPosition)); |
9ce192d4 | 6311 | SetMouseCapture(true); |
9ce192d4 | 6312 | } else { |
8e54aaed | 6313 | if (PointIsHotspot(pt)) { |
9e96e16f | 6314 | NotifyHotSpotClicked(newPos.Position(), shift, ctrl, alt); |
1dcf666d | 6315 | hotSpotClickPos = PositionFromLocation(pt,true,false); |
9e730a78 | 6316 | } |
9ce192d4 | 6317 | if (!shift) { |
7e0c58e9 RD |
6318 | if (PointInSelection(pt) && !SelectionEmpty()) |
6319 | inDragDrop = ddInitial; | |
6320 | else | |
6321 | inDragDrop = ddNone; | |
9ce192d4 | 6322 | } |
7e0c58e9 RD |
6323 | SetMouseCapture(true); |
6324 | if (inDragDrop != ddInitial) { | |
9e96e16f | 6325 | SetDragPosition(SelectionPosition(invalidPosition)); |
8e54aaed | 6326 | if (!shift) { |
9e96e16f RD |
6327 | if (ctrl && multipleSelection) { |
6328 | SelectionRange range(newPos); | |
6329 | sel.TentativeSelection(range); | |
6330 | InvalidateSelection(range, true); | |
6331 | } else { | |
6332 | InvalidateSelection(SelectionRange(newPos), true); | |
6333 | if (sel.Count() > 1) | |
6334 | Redraw(); | |
1dcf666d RD |
6335 | if ((sel.Count() > 1) || (sel.selType != Selection::selStream)) |
6336 | sel.Clear(); | |
9e96e16f RD |
6337 | sel.selType = alt ? Selection::selRectangle : Selection::selStream; |
6338 | SetSelection(newPos, newPos); | |
6339 | } | |
8e54aaed | 6340 | } |
9e96e16f RD |
6341 | SelectionPosition anchorCurrent = newPos; |
6342 | if (shift) | |
6343 | anchorCurrent = sel.IsRectangular() ? | |
6344 | sel.Rectangular().anchor : sel.RangeMain().anchor; | |
6345 | sel.selType = alt ? Selection::selRectangle : Selection::selStream; | |
9ce192d4 | 6346 | selectionType = selChar; |
9e96e16f RD |
6347 | originalAnchorPos = sel.MainCaret(); |
6348 | sel.Rectangular() = SelectionRange(newPos, anchorCurrent); | |
1e9bafca | 6349 | SetRectangularRange(); |
9ce192d4 RD |
6350 | } |
6351 | } | |
6352 | } | |
6353 | lastClickTime = curTime; | |
1dcf666d RD |
6354 | lastClick = pt; |
6355 | lastXChosen = pt.x + xOffset; | |
9ce192d4 RD |
6356 | ShowCaretAtCurrentPosition(); |
6357 | } | |
6358 | ||
9e730a78 | 6359 | bool Editor::PositionIsHotspot(int position) { |
8e54aaed | 6360 | return vs.styles[pdoc->StyleAt(position) & pdoc->stylingBitsMask].hotspot; |
9e730a78 RD |
6361 | } |
6362 | ||
6363 | bool Editor::PointIsHotspot(Point pt) { | |
9e96e16f | 6364 | int pos = PositionFromLocation(pt, true); |
8e54aaed RD |
6365 | if (pos == INVALID_POSITION) |
6366 | return false; | |
9e730a78 RD |
6367 | return PositionIsHotspot(pos); |
6368 | } | |
6369 | ||
6370 | void Editor::SetHotSpotRange(Point *pt) { | |
6371 | if (pt) { | |
6372 | int pos = PositionFromLocation(*pt); | |
6373 | ||
6374 | // If we don't limit this to word characters then the | |
6375 | // range can encompass more than the run range and then | |
6376 | // the underline will not be drawn properly. | |
8e54aaed RD |
6377 | int hsStart_ = pdoc->ExtendStyleRange(pos, -1, vs.hotspotSingleLine); |
6378 | int hsEnd_ = pdoc->ExtendStyleRange(pos, 1, vs.hotspotSingleLine); | |
9e730a78 RD |
6379 | |
6380 | // Only invalidate the range if the hotspot range has changed... | |
6381 | if (hsStart_ != hsStart || hsEnd_ != hsEnd) { | |
6382 | if (hsStart != -1) { | |
6383 | InvalidateRange(hsStart, hsEnd); | |
6384 | } | |
6385 | hsStart = hsStart_; | |
6386 | hsEnd = hsEnd_; | |
6387 | InvalidateRange(hsStart, hsEnd); | |
6388 | } | |
6389 | } else { | |
6390 | if (hsStart != -1) { | |
6391 | int hsStart_ = hsStart; | |
6392 | int hsEnd_ = hsEnd; | |
6393 | hsStart = -1; | |
6394 | hsEnd = -1; | |
6395 | InvalidateRange(hsStart_, hsEnd_); | |
6396 | } else { | |
6397 | hsStart = -1; | |
6398 | hsEnd = -1; | |
6399 | } | |
6400 | } | |
6401 | } | |
6402 | ||
1dcf666d | 6403 | void Editor::GetHotSpotRange(int &hsStart_, int &hsEnd_) { |
9e730a78 RD |
6404 | hsStart_ = hsStart; |
6405 | hsEnd_ = hsEnd; | |
6406 | } | |
6407 | ||
9ce192d4 | 6408 | void Editor::ButtonMove(Point pt) { |
65ec6247 RD |
6409 | if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) { |
6410 | DwellEnd(true); | |
6411 | } | |
7e0c58e9 | 6412 | |
9e96e16f RD |
6413 | SelectionPosition movePos = SPositionFromLocation(pt, false, false, |
6414 | AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular())); | |
6415 | movePos = MovePositionOutsideChar(movePos, sel.MainCaret() - movePos.Position()); | |
7e0c58e9 RD |
6416 | |
6417 | if (inDragDrop == ddInitial) { | |
6418 | if (DragThreshold(ptMouseLast, pt)) { | |
6419 | SetMouseCapture(false); | |
6420 | SetDragPosition(movePos); | |
6421 | CopySelectionRange(&drag); | |
6422 | StartDrag(); | |
6423 | } | |
6424 | return; | |
6425 | } | |
6426 | ||
65ec6247 | 6427 | ptMouseLast = pt; |
9ce192d4 RD |
6428 | //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y); |
6429 | if (HaveMouseCapture()) { | |
65ec6247 RD |
6430 | |
6431 | // Slow down autoscrolling/selection | |
6432 | autoScrollTimer.ticksToWait -= timer.tickSize; | |
6433 | if (autoScrollTimer.ticksToWait > 0) | |
6434 | return; | |
6435 | autoScrollTimer.ticksToWait = autoScrollDelay; | |
6436 | ||
6437 | // Adjust selection | |
9e96e16f | 6438 | if (posDrag.IsValid()) { |
9ce192d4 RD |
6439 | SetDragPosition(movePos); |
6440 | } else { | |
6441 | if (selectionType == selChar) { | |
9e96e16f RD |
6442 | if (sel.IsRectangular()) { |
6443 | sel.Rectangular() = SelectionRange(movePos, sel.Rectangular().anchor); | |
6444 | SetSelection(movePos, sel.RangeMain().anchor); | |
6445 | } else if (sel.Count() > 1) { | |
6446 | SelectionRange range(movePos, sel.RangeMain().anchor); | |
6447 | sel.TentativeSelection(range); | |
6448 | InvalidateSelection(range, true); | |
6449 | } else { | |
6450 | SetSelection(movePos, sel.RangeMain().anchor); | |
6451 | } | |
9ce192d4 RD |
6452 | } else if (selectionType == selWord) { |
6453 | // Continue selecting by word | |
1dcf666d | 6454 | if (movePos.Position() == wordSelectInitialCaretPos) { // Didn't move |
8e54aaed RD |
6455 | // No need to do anything. Previously this case was lumped |
6456 | // in with "Moved forward", but that can be harmful in this | |
6457 | // case: a handler for the NotifyDoubleClick re-adjusts | |
6458 | // the selection for a fancier definition of "word" (for | |
6459 | // example, in Perl it is useful to include the leading | |
6460 | // '$', '%' or '@' on variables for word selection). In this | |
6461 | // the ButtonMove() called via Tick() for auto-scrolling | |
6462 | // could result in the fancier word selection adjustment | |
6463 | // being unmade. | |
1dcf666d RD |
6464 | } else { |
6465 | wordSelectInitialCaretPos = -1; | |
6466 | WordSelection(movePos.Position()); | |
9ce192d4 RD |
6467 | } |
6468 | } else { | |
6469 | // Continue selecting by line | |
1dcf666d | 6470 | LineSelection(movePos.Position(), lineAnchorPos, selectionType == selWholeLine); |
9ce192d4 RD |
6471 | } |
6472 | } | |
65ec6247 RD |
6473 | |
6474 | // Autoscroll | |
6475 | PRectangle rcClient = GetClientRectangle(); | |
1dcf666d | 6476 | int lineMove = DisplayFromPosition(movePos.Position()); |
65ec6247 | 6477 | if (pt.y > rcClient.bottom) { |
9e96e16f | 6478 | ScrollTo(lineMove - LinesOnScreen() + 1); |
65ec6247 RD |
6479 | Redraw(); |
6480 | } else if (pt.y < rcClient.top) { | |
1dcf666d | 6481 | ScrollTo(lineMove); |
65ec6247 RD |
6482 | Redraw(); |
6483 | } | |
6484 | EnsureCaretVisible(false, false, true); | |
6485 | ||
9e96e16f | 6486 | if (hsStart != -1 && !PositionIsHotspot(movePos.Position())) |
9e730a78 RD |
6487 | SetHotSpotRange(NULL); |
6488 | ||
1dcf666d RD |
6489 | if (hotSpotClickPos != INVALID_POSITION && PositionFromLocation(pt,true,false) != hotSpotClickPos) { |
6490 | if (inDragDrop == ddNone) { | |
6491 | DisplayCursor(Window::cursorText); | |
6492 | } | |
6493 | hotSpotClickPos = INVALID_POSITION; | |
6494 | } | |
6495 | ||
9ce192d4 RD |
6496 | } else { |
6497 | if (vs.fixedColumnWidth > 0) { // There is a margin | |
6498 | if (PointInSelMargin(pt)) { | |
1dcf666d RD |
6499 | DisplayCursor(GetMarginCursor(pt)); |
6500 | SetHotSpotRange(NULL); | |
65ec6247 | 6501 | return; // No need to test for selection |
9ce192d4 RD |
6502 | } |
6503 | } | |
6504 | // Display regular (drag) cursor over selection | |
1e9bafca | 6505 | if (PointInSelection(pt) && !SelectionEmpty()) { |
65ec6247 | 6506 | DisplayCursor(Window::cursorArrow); |
9e730a78 RD |
6507 | } else if (PointIsHotspot(pt)) { |
6508 | DisplayCursor(Window::cursorHand); | |
6509 | SetHotSpotRange(&pt); | |
6510 | } else { | |
65ec6247 | 6511 | DisplayCursor(Window::cursorText); |
9e730a78 RD |
6512 | SetHotSpotRange(NULL); |
6513 | } | |
9ce192d4 | 6514 | } |
9ce192d4 RD |
6515 | } |
6516 | ||
6517 | void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) { | |
7e0c58e9 | 6518 | //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop); |
9e96e16f RD |
6519 | SelectionPosition newPos = SPositionFromLocation(pt, false, false, |
6520 | AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular())); | |
6521 | newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position()); | |
7e0c58e9 RD |
6522 | if (inDragDrop == ddInitial) { |
6523 | inDragDrop = ddNone; | |
1dcf666d RD |
6524 | SetEmptySelection(newPos); |
6525 | selectionType = selChar; | |
6526 | originalAnchorPos = sel.MainCaret(); | |
6527 | } | |
6528 | if (hotSpotClickPos != INVALID_POSITION && PointIsHotspot(pt)) { | |
6529 | hotSpotClickPos = INVALID_POSITION; | |
6530 | NotifyHotSpotReleaseClick(newPos.Position(), false, ctrl, false); | |
7e0c58e9 | 6531 | } |
9ce192d4 RD |
6532 | if (HaveMouseCapture()) { |
6533 | if (PointInSelMargin(pt)) { | |
1dcf666d | 6534 | DisplayCursor(GetMarginCursor(pt)); |
9ce192d4 | 6535 | } else { |
65ec6247 | 6536 | DisplayCursor(Window::cursorText); |
9e730a78 | 6537 | SetHotSpotRange(NULL); |
9ce192d4 | 6538 | } |
9ce192d4 RD |
6539 | ptMouseLast = pt; |
6540 | SetMouseCapture(false); | |
9e96e16f | 6541 | NotifyIndicatorClick(false, newPos.Position(), false, false, false); |
7e0c58e9 | 6542 | if (inDragDrop == ddDragging) { |
9e96e16f RD |
6543 | SelectionPosition selStart = SelectionStart(); |
6544 | SelectionPosition selEnd = SelectionEnd(); | |
9ce192d4 | 6545 | if (selStart < selEnd) { |
b8b0e402 | 6546 | if (drag.len) { |
9ce192d4 | 6547 | if (ctrl) { |
9e96e16f RD |
6548 | if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) { |
6549 | SetSelection(newPos.Position(), newPos.Position() + drag.len); | |
a834585d | 6550 | } |
9ce192d4 | 6551 | } else if (newPos < selStart) { |
9e96e16f RD |
6552 | pdoc->DeleteChars(selStart.Position(), drag.len); |
6553 | if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) { | |
6554 | SetSelection(newPos.Position(), newPos.Position() + drag.len); | |
a834585d | 6555 | } |
9ce192d4 | 6556 | } else if (newPos > selEnd) { |
9e96e16f RD |
6557 | pdoc->DeleteChars(selStart.Position(), drag.len); |
6558 | newPos.Add(-drag.len); | |
6559 | if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) { | |
6560 | SetSelection(newPos.Position(), newPos.Position() + drag.len); | |
a834585d | 6561 | } |
9ce192d4 | 6562 | } else { |
9e96e16f | 6563 | SetEmptySelection(newPos.Position()); |
9ce192d4 | 6564 | } |
591d01be | 6565 | drag.Free(); |
9ce192d4 RD |
6566 | } |
6567 | selectionType = selChar; | |
6568 | } | |
6569 | } else { | |
6570 | if (selectionType == selChar) { | |
9e96e16f RD |
6571 | if (sel.Count() > 1) { |
6572 | sel.RangeMain() = | |
6573 | SelectionRange(newPos, sel.Range(sel.Count() - 1).anchor); | |
6574 | InvalidateSelection(sel.RangeMain(), true); | |
6575 | } else { | |
6576 | SetSelection(newPos, sel.RangeMain().anchor); | |
6577 | } | |
9ce192d4 | 6578 | } |
9e96e16f | 6579 | sel.CommitTentative(); |
9ce192d4 | 6580 | } |
1e9bafca | 6581 | SetRectangularRange(); |
9ce192d4 RD |
6582 | lastClickTime = curTime; |
6583 | lastClick = pt; | |
1dcf666d | 6584 | lastXChosen = pt.x + xOffset; |
9e96e16f | 6585 | if (sel.selType == Selection::selStream) { |
1a2fb4cd RD |
6586 | SetLastXChosen(); |
6587 | } | |
7e0c58e9 | 6588 | inDragDrop = ddNone; |
9ce192d4 RD |
6589 | EnsureCaretVisible(false); |
6590 | } | |
6591 | } | |
6592 | ||
6593 | // Called frequently to perform background UI including | |
6594 | // caret blinking and automatic scrolling. | |
6595 | void Editor::Tick() { | |
6596 | if (HaveMouseCapture()) { | |
6597 | // Auto scroll | |
6598 | ButtonMove(ptMouseLast); | |
6599 | } | |
6600 | if (caret.period > 0) { | |
6601 | timer.ticksToWait -= timer.tickSize; | |
6602 | if (timer.ticksToWait <= 0) { | |
6603 | caret.on = !caret.on; | |
6604 | timer.ticksToWait = caret.period; | |
1e9bafca RD |
6605 | if (caret.active) { |
6606 | InvalidateCaret(); | |
6607 | } | |
9ce192d4 RD |
6608 | } |
6609 | } | |
7e0c58e9 RD |
6610 | if (horizontalScrollBarVisible && trackLineWidth && (lineWidthMaxSeen > scrollWidth)) { |
6611 | scrollWidth = lineWidthMaxSeen; | |
6612 | SetScrollBars(); | |
6613 | } | |
1a2fb4cd | 6614 | if ((dwellDelay < SC_TIME_FOREVER) && |
9e730a78 | 6615 | (ticksToDwell > 0) && |
1dcf666d RD |
6616 | (!HaveMouseCapture()) && |
6617 | (ptMouseLast.y >= 0)) { | |
65ec6247 RD |
6618 | ticksToDwell -= timer.tickSize; |
6619 | if (ticksToDwell <= 0) { | |
6620 | dwelling = true; | |
6621 | NotifyDwelling(ptMouseLast, dwelling); | |
6622 | } | |
6623 | } | |
6624 | } | |
6625 | ||
8e54aaed RD |
6626 | bool Editor::Idle() { |
6627 | ||
6628 | bool idleDone; | |
6629 | ||
b8193d80 | 6630 | bool wrappingDone = wrapState == eWrapNone; |
8e54aaed RD |
6631 | |
6632 | if (!wrappingDone) { | |
6633 | // Wrap lines during idle. | |
6634 | WrapLines(false, -1); | |
6635 | // No more wrapping | |
b8193d80 | 6636 | if (wrapStart == wrapEnd) |
8e54aaed RD |
6637 | wrappingDone = true; |
6638 | } | |
6639 | ||
6640 | // Add more idle things to do here, but make sure idleDone is | |
6641 | // set correctly before the function returns. returning | |
6642 | // false will stop calling this idle funtion until SetIdle() is | |
6643 | // called again. | |
6644 | ||
6645 | idleDone = wrappingDone; // && thatDone && theOtherThingDone... | |
6646 | ||
6647 | return !idleDone; | |
6648 | } | |
6649 | ||
65ec6247 RD |
6650 | void Editor::SetFocusState(bool focusState) { |
6651 | hasFocus = focusState; | |
6652 | NotifyFocus(hasFocus); | |
6653 | if (hasFocus) { | |
6654 | ShowCaretAtCurrentPosition(); | |
65ec6247 | 6655 | } else { |
9e730a78 | 6656 | CancelModes(); |
65ec6247 RD |
6657 | DropCaret(); |
6658 | } | |
9ce192d4 RD |
6659 | } |
6660 | ||
1dcf666d RD |
6661 | int Editor::PositionAfterArea(PRectangle rcArea) { |
6662 | // The start of the document line after the display line after the area | |
6663 | // This often means that the line after a modification is restyled which helps | |
6664 | // detect multiline comment additions and heals single line comments | |
6665 | int lineAfter = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1; | |
6666 | if (lineAfter < cs.LinesDisplayed()) | |
6667 | return pdoc->LineStart(cs.DocFromDisplay(lineAfter) + 1); | |
6668 | else | |
6669 | return pdoc->Length(); | |
6670 | } | |
6671 | ||
6672 | // Style to a position within the view. If this causes a change at end of last line then | |
6673 | // affects later lines so style all the viewed text. | |
6674 | void Editor::StyleToPositionInView(Position pos) { | |
6675 | int endWindow = PositionAfterArea(GetClientRectangle()); | |
6676 | if (pos > endWindow) | |
6677 | pos = endWindow; | |
6678 | int styleAtEnd = pdoc->StyleAt(pos-1); | |
6679 | pdoc->EnsureStyledTo(pos); | |
6680 | if ((endWindow > pos) && (styleAtEnd != pdoc->StyleAt(pos-1))) { | |
6681 | // Style at end of line changed so is multi-line change like starting a comment | |
6682 | // so require rest of window to be styled. | |
6683 | pdoc->EnsureStyledTo(endWindow); | |
6684 | } | |
6685 | } | |
6686 | ||
6687 | void Editor::IdleStyling() { | |
6688 | // Style the line after the modification as this allows modifications that change just the | |
6689 | // line of the modification to heal instead of propagating to the rest of the window. | |
6690 | StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(styleNeeded.upTo) + 2)); | |
6691 | ||
6692 | if (needUpdateUI) { | |
6693 | NotifyUpdateUI(); | |
6694 | needUpdateUI = 0; | |
6695 | } | |
6696 | styleNeeded.Reset(); | |
6697 | } | |
6698 | ||
6699 | void Editor::QueueStyling(int upTo) { | |
6700 | styleNeeded.NeedUpTo(upTo); | |
6701 | } | |
6702 | ||
1e9bafca | 6703 | bool Editor::PaintContains(PRectangle rc) { |
7e0c58e9 RD |
6704 | if (rc.Empty()) { |
6705 | return true; | |
6706 | } else { | |
6707 | return rcPaint.Contains(rc); | |
6708 | } | |
9ce192d4 RD |
6709 | } |
6710 | ||
1e9bafca RD |
6711 | bool Editor::PaintContainsMargin() { |
6712 | PRectangle rcSelMargin = GetClientRectangle(); | |
6713 | rcSelMargin.right = vs.fixedColumnWidth; | |
6714 | return PaintContains(rcSelMargin); | |
9ce192d4 RD |
6715 | } |
6716 | ||
6717 | void Editor::CheckForChangeOutsidePaint(Range r) { | |
6718 | if (paintState == painting && !paintingAllText) { | |
6719 | //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end); | |
6720 | if (!r.Valid()) | |
65ec6247 | 6721 | return; |
d134f170 | 6722 | |
1e9bafca | 6723 | PRectangle rcRange = RectangleFromRange(r.start, r.end); |
9ce192d4 | 6724 | PRectangle rcText = GetTextRectangle(); |
1e9bafca RD |
6725 | if (rcRange.top < rcText.top) { |
6726 | rcRange.top = rcText.top; | |
9ce192d4 | 6727 | } |
1e9bafca RD |
6728 | if (rcRange.bottom > rcText.bottom) { |
6729 | rcRange.bottom = rcText.bottom; | |
9ce192d4 | 6730 | } |
1e9bafca RD |
6731 | |
6732 | if (!PaintContains(rcRange)) { | |
6733 | AbandonPaint(); | |
9ce192d4 RD |
6734 | } |
6735 | } | |
6736 | } | |
6737 | ||
9ce192d4 RD |
6738 | void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) { |
6739 | if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) { | |
d134f170 | 6740 | if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) { |
9ce192d4 RD |
6741 | CheckForChangeOutsidePaint(Range(braces[0])); |
6742 | CheckForChangeOutsidePaint(Range(pos0)); | |
6743 | braces[0] = pos0; | |
6744 | } | |
d134f170 | 6745 | if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) { |
9ce192d4 RD |
6746 | CheckForChangeOutsidePaint(Range(braces[1])); |
6747 | CheckForChangeOutsidePaint(Range(pos1)); | |
6748 | braces[1] = pos1; | |
6749 | } | |
6750 | bracesMatchStyle = matchStyle; | |
6751 | if (paintState == notPainting) { | |
6752 | Redraw(); | |
6753 | } | |
6754 | } | |
6755 | } | |
6756 | ||
9e96e16f RD |
6757 | void Editor::SetAnnotationHeights(int start, int end) { |
6758 | if (vs.annotationVisible) { | |
1dcf666d RD |
6759 | bool changedHeight = false; |
6760 | for (int line=start; line<end && line<pdoc->LinesTotal(); line++) { | |
6761 | int linesWrapped = 1; | |
6762 | if (wrapState != eWrapNone) { | |
6763 | AutoSurface surface(this); | |
6764 | AutoLineLayout ll(llc, RetrieveLineLayout(line)); | |
6765 | if (surface && ll) { | |
6766 | LayoutLine(line, surface, vs, ll, wrapWidth); | |
6767 | linesWrapped = ll->lines; | |
6768 | } | |
6769 | } | |
6770 | if (cs.SetHeight(line, pdoc->AnnotationLines(line) + linesWrapped)) | |
6771 | changedHeight = true; | |
6772 | } | |
6773 | if (changedHeight) { | |
6774 | Redraw(); | |
9e96e16f RD |
6775 | } |
6776 | } | |
6777 | } | |
6778 | ||
9ce192d4 RD |
6779 | void Editor::SetDocPointer(Document *document) { |
6780 | //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document); | |
6781 | pdoc->RemoveWatcher(this, 0); | |
6782 | pdoc->Release(); | |
6783 | if (document == NULL) { | |
6784 | pdoc = new Document(); | |
6785 | } else { | |
6786 | pdoc = document; | |
6787 | } | |
6788 | pdoc->AddRef(); | |
9e730a78 RD |
6789 | |
6790 | // Ensure all positions within document | |
9e96e16f | 6791 | sel.Clear(); |
9e730a78 RD |
6792 | targetStart = 0; |
6793 | targetEnd = 0; | |
6794 | ||
591d01be RD |
6795 | braces[0] = invalidPosition; |
6796 | braces[1] = invalidPosition; | |
6797 | ||
f6bcfd97 BP |
6798 | // Reset the contraction state to fully shown. |
6799 | cs.Clear(); | |
d134f170 | 6800 | cs.InsertLines(0, pdoc->LinesTotal() - 1); |
9e96e16f | 6801 | SetAnnotationHeights(0, pdoc->LinesTotal()); |
1a2fb4cd RD |
6802 | llc.Deallocate(); |
6803 | NeedWrapping(); | |
f6bcfd97 | 6804 | |
9ce192d4 | 6805 | pdoc->AddWatcher(this, 0); |
e14d10b0 | 6806 | SetScrollBars(); |
1e9bafca | 6807 | Redraw(); |
9ce192d4 RD |
6808 | } |
6809 | ||
9e96e16f RD |
6810 | void Editor::SetAnnotationVisible(int visible) { |
6811 | if (vs.annotationVisible != visible) { | |
6812 | bool changedFromOrToHidden = ((vs.annotationVisible != 0) != (visible != 0)); | |
6813 | vs.annotationVisible = visible; | |
6814 | if (changedFromOrToHidden) { | |
6815 | int dir = vs.annotationVisible ? 1 : -1; | |
6816 | for (int line=0; line<pdoc->LinesTotal(); line++) { | |
6817 | int annotationLines = pdoc->AnnotationLines(line); | |
6818 | if (annotationLines > 0) { | |
6819 | cs.SetHeight(line, cs.GetHeight(line) + annotationLines * dir); | |
6820 | } | |
6821 | } | |
6822 | } | |
1dcf666d | 6823 | Redraw(); |
9e96e16f RD |
6824 | } |
6825 | } | |
6826 | ||
8e54aaed RD |
6827 | /** |
6828 | * Recursively expand a fold, making lines visible except where they have an unexpanded parent. | |
6829 | */ | |
9ce192d4 RD |
6830 | void Editor::Expand(int &line, bool doExpand) { |
6831 | int lineMaxSubord = pdoc->GetLastChild(line); | |
6832 | line++; | |
6833 | while (line <= lineMaxSubord) { | |
6834 | if (doExpand) | |
6835 | cs.SetVisible(line, line, true); | |
6836 | int level = pdoc->GetLevel(line); | |
6837 | if (level & SC_FOLDLEVELHEADERFLAG) { | |
6838 | if (doExpand && cs.GetExpanded(line)) { | |
6839 | Expand(line, true); | |
6840 | } else { | |
6841 | Expand(line, false); | |
6842 | } | |
6843 | } else { | |
6844 | line++; | |
6845 | } | |
6846 | } | |
6847 | } | |
6848 | ||
6849 | void Editor::ToggleContraction(int line) { | |
591d01be RD |
6850 | if (line >= 0) { |
6851 | if ((pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) == 0) { | |
6852 | line = pdoc->GetFoldParent(line); | |
6853 | if (line < 0) | |
6854 | return; | |
6855 | } | |
6856 | ||
9ce192d4 RD |
6857 | if (cs.GetExpanded(line)) { |
6858 | int lineMaxSubord = pdoc->GetLastChild(line); | |
9ce192d4 | 6859 | if (lineMaxSubord > line) { |
1dcf666d | 6860 | cs.SetExpanded(line, 0); |
d134f170 | 6861 | cs.SetVisible(line + 1, lineMaxSubord, false); |
591d01be | 6862 | |
9e96e16f | 6863 | int lineCurrent = pdoc->LineFromPosition(sel.MainCaret()); |
591d01be RD |
6864 | if (lineCurrent > line && lineCurrent <= lineMaxSubord) { |
6865 | // This does not re-expand the fold | |
6866 | EnsureCaretVisible(); | |
6867 | } | |
6868 | ||
9ce192d4 RD |
6869 | SetScrollBars(); |
6870 | Redraw(); | |
6871 | } | |
591d01be | 6872 | |
9ce192d4 | 6873 | } else { |
591d01be RD |
6874 | if (!(cs.GetVisible(line))) { |
6875 | EnsureLineVisible(line, false); | |
6876 | GoToLine(line); | |
6877 | } | |
9ce192d4 RD |
6878 | cs.SetExpanded(line, 1); |
6879 | Expand(line, true); | |
6880 | SetScrollBars(); | |
6881 | Redraw(); | |
6882 | } | |
6883 | } | |
6884 | } | |
6885 | ||
1dcf666d RD |
6886 | int Editor::ContractedFoldNext(int lineStart) { |
6887 | for (int line = lineStart; line<pdoc->LinesTotal();) { | |
6888 | if (!cs.GetExpanded(line) && (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG)) | |
6889 | return line; | |
6890 | line = cs.ContractedNext(line+1); | |
6891 | if (line < 0) | |
6892 | return -1; | |
6893 | } | |
6894 | ||
6895 | return -1; | |
6896 | } | |
6897 | ||
8e54aaed RD |
6898 | /** |
6899 | * Recurse up from this line to find any folds that prevent this line from being visible | |
6900 | * and unfold them all. | |
6901 | */ | |
65ec6247 | 6902 | void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) { |
1a2fb4cd RD |
6903 | |
6904 | // In case in need of wrapping to ensure DisplayFromDoc works. | |
1dcf666d RD |
6905 | if (lineDoc >= wrapStart) |
6906 | WrapLines(true, -1); | |
1a2fb4cd | 6907 | |
65ec6247 | 6908 | if (!cs.GetVisible(lineDoc)) { |
1dcf666d RD |
6909 | int lookLine = lineDoc; |
6910 | int lookLineLevel = pdoc->GetLevel(lookLine); | |
6911 | while ((lookLine > 0) && (lookLineLevel & SC_FOLDLEVELWHITEFLAG)) { | |
6912 | lookLineLevel = pdoc->GetLevel(--lookLine); | |
6913 | } | |
6914 | int lineParent = pdoc->GetFoldParent(lookLine); | |
9ce192d4 | 6915 | if (lineParent >= 0) { |
65ec6247 RD |
6916 | if (lineDoc != lineParent) |
6917 | EnsureLineVisible(lineParent, enforcePolicy); | |
9ce192d4 RD |
6918 | if (!cs.GetExpanded(lineParent)) { |
6919 | cs.SetExpanded(lineParent, 1); | |
6920 | Expand(lineParent, true); | |
6921 | } | |
6922 | } | |
6923 | SetScrollBars(); | |
6924 | Redraw(); | |
6925 | } | |
65ec6247 RD |
6926 | if (enforcePolicy) { |
6927 | int lineDisplay = cs.DisplayFromDoc(lineDoc); | |
6928 | if (visiblePolicy & VISIBLE_SLOP) { | |
6929 | if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) { | |
6930 | SetTopLine(Platform::Clamp(lineDisplay - visibleSlop, 0, MaxScrollPos())); | |
6931 | SetVerticalScrollPos(); | |
6932 | Redraw(); | |
6933 | } else if ((lineDisplay > topLine + LinesOnScreen() - 1) || | |
7e0c58e9 | 6934 | ((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) { |
65ec6247 RD |
6935 | SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, 0, MaxScrollPos())); |
6936 | SetVerticalScrollPos(); | |
6937 | Redraw(); | |
6938 | } | |
6939 | } else { | |
6940 | if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) { | |
6941 | SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() / 2 + 1, 0, MaxScrollPos())); | |
6942 | SetVerticalScrollPos(); | |
6943 | Redraw(); | |
6944 | } | |
6945 | } | |
6946 | } | |
6947 | } | |
6948 | ||
1dcf666d RD |
6949 | int Editor::GetTag(char *tagValue, int tagNumber) { |
6950 | const char *text = 0; | |
6951 | int length = 0; | |
6952 | if ((tagNumber >= 1) && (tagNumber <= 9)) { | |
6953 | char name[3] = "\\?"; | |
6954 | name[1] = static_cast<char>(tagNumber + '0'); | |
6955 | length = 2; | |
6956 | text = pdoc->SubstituteByPosition(name, &length); | |
6957 | } | |
6958 | if (tagValue) { | |
6959 | if (text) | |
6960 | memcpy(tagValue, text, length + 1); | |
6961 | else | |
6962 | *tagValue = '\0'; | |
6963 | } | |
6964 | return length; | |
6965 | } | |
6966 | ||
65ec6247 | 6967 | int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) { |
9e96e16f | 6968 | UndoGroup ug(pdoc); |
65ec6247 | 6969 | if (length == -1) |
88a8b04e | 6970 | length = istrlen(text); |
65ec6247 RD |
6971 | if (replacePatterns) { |
6972 | text = pdoc->SubstituteByPosition(text, &length); | |
7e0c58e9 | 6973 | if (!text) { |
65ec6247 | 6974 | return 0; |
7e0c58e9 | 6975 | } |
65ec6247 RD |
6976 | } |
6977 | if (targetStart != targetEnd) | |
6978 | pdoc->DeleteChars(targetStart, targetEnd - targetStart); | |
6979 | targetEnd = targetStart; | |
6980 | pdoc->InsertString(targetStart, text, length); | |
6981 | targetEnd = targetStart + length; | |
65ec6247 | 6982 | return length; |
9ce192d4 RD |
6983 | } |
6984 | ||
1a2fb4cd RD |
6985 | bool Editor::IsUnicodeMode() const { |
6986 | return pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage); | |
6987 | } | |
6988 | ||
9e730a78 RD |
6989 | int Editor::CodePage() const { |
6990 | if (pdoc) | |
6991 | return pdoc->dbcsCodePage; | |
6992 | else | |
6993 | return 0; | |
6994 | } | |
6995 | ||
1e9bafca RD |
6996 | int Editor::WrapCount(int line) { |
6997 | AutoSurface surface(this); | |
6998 | AutoLineLayout ll(llc, RetrieveLineLayout(line)); | |
6999 | ||
7000 | if (surface && ll) { | |
7001 | LayoutLine(line, surface, vs, ll, wrapWidth); | |
7002 | return ll->lines; | |
7003 | } else { | |
7004 | return 1; | |
7005 | } | |
7006 | } | |
7007 | ||
7e0c58e9 RD |
7008 | void Editor::AddStyledText(char *buffer, int appendLength) { |
7009 | // The buffer consists of alternating character bytes and style bytes | |
1dcf666d | 7010 | int textLength = appendLength / 2; |
7e0c58e9 | 7011 | char *text = new char[textLength]; |
1dcf666d RD |
7012 | int i; |
7013 | for (i = 0; i < textLength; i++) { | |
9e96e16f | 7014 | text[i] = buffer[i*2]; |
7e0c58e9 | 7015 | } |
9e96e16f | 7016 | pdoc->InsertString(CurrentPosition(), text, textLength); |
1dcf666d | 7017 | for (i = 0; i < textLength; i++) { |
9e96e16f RD |
7018 | text[i] = buffer[i*2+1]; |
7019 | } | |
7020 | pdoc->StartStyling(CurrentPosition(), static_cast<char>(0xff)); | |
7021 | pdoc->SetStyles(textLength, text); | |
7022 | delete []text; | |
7023 | SetEmptySelection(sel.MainCaret() + textLength); | |
7e0c58e9 RD |
7024 | } |
7025 | ||
d134f170 | 7026 | static bool ValidMargin(unsigned long wParam) { |
f6bcfd97 BP |
7027 | return wParam < ViewStyle::margins; |
7028 | } | |
7029 | ||
a834585d RD |
7030 | static char *CharPtrFromSPtr(sptr_t lParam) { |
7031 | return reinterpret_cast<char *>(lParam); | |
7032 | } | |
7033 | ||
7e0c58e9 RD |
7034 | void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { |
7035 | vs.EnsureStyle(wParam); | |
7036 | switch (iMessage) { | |
7037 | case SCI_STYLESETFORE: | |
1dcf666d | 7038 | vs.styles[wParam].fore = ColourDesired(lParam); |
7e0c58e9 RD |
7039 | break; |
7040 | case SCI_STYLESETBACK: | |
1dcf666d | 7041 | vs.styles[wParam].back = ColourDesired(lParam); |
7e0c58e9 RD |
7042 | break; |
7043 | case SCI_STYLESETBOLD: | |
1dcf666d RD |
7044 | vs.styles[wParam].weight = lParam != 0 ? SC_WEIGHT_BOLD : SC_WEIGHT_NORMAL; |
7045 | break; | |
7046 | case SCI_STYLESETWEIGHT: | |
7047 | vs.styles[wParam].weight = lParam; | |
7e0c58e9 RD |
7048 | break; |
7049 | case SCI_STYLESETITALIC: | |
7050 | vs.styles[wParam].italic = lParam != 0; | |
7051 | break; | |
7052 | case SCI_STYLESETEOLFILLED: | |
7053 | vs.styles[wParam].eolFilled = lParam != 0; | |
7054 | break; | |
7055 | case SCI_STYLESETSIZE: | |
1dcf666d RD |
7056 | vs.styles[wParam].size = lParam * SC_FONT_SIZE_MULTIPLIER; |
7057 | break; | |
7058 | case SCI_STYLESETSIZEFRACTIONAL: | |
7e0c58e9 RD |
7059 | vs.styles[wParam].size = lParam; |
7060 | break; | |
7061 | case SCI_STYLESETFONT: | |
7062 | if (lParam != 0) { | |
7063 | vs.SetStyleFontName(wParam, CharPtrFromSPtr(lParam)); | |
7064 | } | |
7065 | break; | |
7066 | case SCI_STYLESETUNDERLINE: | |
7067 | vs.styles[wParam].underline = lParam != 0; | |
7068 | break; | |
7069 | case SCI_STYLESETCASE: | |
7070 | vs.styles[wParam].caseForce = static_cast<Style::ecaseForced>(lParam); | |
7071 | break; | |
7072 | case SCI_STYLESETCHARACTERSET: | |
7073 | vs.styles[wParam].characterSet = lParam; | |
7074 | break; | |
7075 | case SCI_STYLESETVISIBLE: | |
7076 | vs.styles[wParam].visible = lParam != 0; | |
7077 | break; | |
7078 | case SCI_STYLESETCHANGEABLE: | |
7079 | vs.styles[wParam].changeable = lParam != 0; | |
7080 | break; | |
7081 | case SCI_STYLESETHOTSPOT: | |
7082 | vs.styles[wParam].hotspot = lParam != 0; | |
7083 | break; | |
7084 | } | |
7085 | InvalidateStyleRedraw(); | |
7086 | } | |
7087 | ||
7088 | sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { | |
7089 | vs.EnsureStyle(wParam); | |
7090 | switch (iMessage) { | |
7091 | case SCI_STYLEGETFORE: | |
1dcf666d | 7092 | return vs.styles[wParam].fore.AsLong(); |
7e0c58e9 | 7093 | case SCI_STYLEGETBACK: |
1dcf666d | 7094 | return vs.styles[wParam].back.AsLong(); |
7e0c58e9 | 7095 | case SCI_STYLEGETBOLD: |
1dcf666d RD |
7096 | return vs.styles[wParam].weight > SC_WEIGHT_NORMAL; |
7097 | case SCI_STYLEGETWEIGHT: | |
7098 | return vs.styles[wParam].weight; | |
7e0c58e9 RD |
7099 | case SCI_STYLEGETITALIC: |
7100 | return vs.styles[wParam].italic ? 1 : 0; | |
7101 | case SCI_STYLEGETEOLFILLED: | |
7102 | return vs.styles[wParam].eolFilled ? 1 : 0; | |
7103 | case SCI_STYLEGETSIZE: | |
1dcf666d RD |
7104 | return vs.styles[wParam].size / SC_FONT_SIZE_MULTIPLIER; |
7105 | case SCI_STYLEGETSIZEFRACTIONAL: | |
7e0c58e9 RD |
7106 | return vs.styles[wParam].size; |
7107 | case SCI_STYLEGETFONT: | |
9e96e16f RD |
7108 | if (!vs.styles[wParam].fontName) |
7109 | return 0; | |
7e0c58e9 RD |
7110 | if (lParam != 0) |
7111 | strcpy(CharPtrFromSPtr(lParam), vs.styles[wParam].fontName); | |
7112 | return strlen(vs.styles[wParam].fontName); | |
7113 | case SCI_STYLEGETUNDERLINE: | |
7114 | return vs.styles[wParam].underline ? 1 : 0; | |
7115 | case SCI_STYLEGETCASE: | |
7116 | return static_cast<int>(vs.styles[wParam].caseForce); | |
7117 | case SCI_STYLEGETCHARACTERSET: | |
7118 | return vs.styles[wParam].characterSet; | |
7119 | case SCI_STYLEGETVISIBLE: | |
7120 | return vs.styles[wParam].visible ? 1 : 0; | |
7121 | case SCI_STYLEGETCHANGEABLE: | |
7122 | return vs.styles[wParam].changeable ? 1 : 0; | |
7123 | case SCI_STYLEGETHOTSPOT: | |
7124 | return vs.styles[wParam].hotspot ? 1 : 0; | |
7125 | } | |
7126 | return 0; | |
7127 | } | |
7128 | ||
9e96e16f | 7129 | sptr_t Editor::StringResult(sptr_t lParam, const char *val) { |
1dcf666d | 7130 | const size_t n = strlen(val); |
9e96e16f RD |
7131 | if (lParam != 0) { |
7132 | char *ptr = reinterpret_cast<char *>(lParam); | |
7133 | strcpy(ptr, val); | |
7134 | } | |
7135 | return n; // Not including NUL | |
7136 | } | |
7137 | ||
65ec6247 | 7138 | sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { |
9ce192d4 RD |
7139 | //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam); |
7140 | ||
7141 | // Optional macro recording hook | |
9ce192d4 RD |
7142 | if (recordingMacro) |
7143 | NotifyMacroRecord(iMessage, wParam, lParam); | |
9ce192d4 RD |
7144 | |
7145 | switch (iMessage) { | |
7146 | ||
9e730a78 | 7147 | case SCI_GETTEXT: { |
9ce192d4 | 7148 | if (lParam == 0) |
591d01be | 7149 | return pdoc->Length() + 1; |
a834585d RD |
7150 | if (wParam == 0) |
7151 | return 0; | |
7152 | char *ptr = CharPtrFromSPtr(lParam); | |
9ce192d4 | 7153 | unsigned int iChar = 0; |
d134f170 | 7154 | for (; iChar < wParam - 1; iChar++) |
9ce192d4 RD |
7155 | ptr[iChar] = pdoc->CharAt(iChar); |
7156 | ptr[iChar] = '\0'; | |
7157 | return iChar; | |
7158 | } | |
7159 | ||
9e730a78 | 7160 | case SCI_SETTEXT: { |
9ce192d4 | 7161 | if (lParam == 0) |
1a2fb4cd | 7162 | return 0; |
9e96e16f | 7163 | UndoGroup ug(pdoc); |
9ce192d4 RD |
7164 | pdoc->DeleteChars(0, pdoc->Length()); |
7165 | SetEmptySelection(0); | |
7e0c58e9 | 7166 | pdoc->InsertCString(0, CharPtrFromSPtr(lParam)); |
1a2fb4cd | 7167 | return 1; |
9ce192d4 RD |
7168 | } |
7169 | ||
d134f170 | 7170 | case SCI_GETTEXTLENGTH: |
9ce192d4 RD |
7171 | return pdoc->Length(); |
7172 | ||
d134f170 | 7173 | case SCI_CUT: |
9ce192d4 RD |
7174 | Cut(); |
7175 | SetLastXChosen(); | |
7176 | break; | |
7177 | ||
d134f170 | 7178 | case SCI_COPY: |
9ce192d4 RD |
7179 | Copy(); |
7180 | break; | |
7181 | ||
9e96e16f RD |
7182 | case SCI_COPYALLOWLINE: |
7183 | CopyAllowLine(); | |
7184 | break; | |
7185 | ||
1dcf666d RD |
7186 | case SCI_VERTICALCENTRECARET: |
7187 | VerticalCentreCaret(); | |
7188 | break; | |
7189 | ||
7190 | case SCI_MOVESELECTEDLINESUP: | |
7191 | MoveSelectedLinesUp(); | |
7192 | break; | |
7193 | ||
7194 | case SCI_MOVESELECTEDLINESDOWN: | |
7195 | MoveSelectedLinesDown(); | |
7196 | break; | |
7197 | ||
e14d10b0 RD |
7198 | case SCI_COPYRANGE: |
7199 | CopyRangeToClipboard(wParam, lParam); | |
7200 | break; | |
7201 | ||
7202 | case SCI_COPYTEXT: | |
7203 | CopyText(wParam, CharPtrFromSPtr(lParam)); | |
7204 | break; | |
7205 | ||
d134f170 | 7206 | case SCI_PASTE: |
9ce192d4 | 7207 | Paste(); |
1dcf666d | 7208 | if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { |
1e9bafca RD |
7209 | SetLastXChosen(); |
7210 | } | |
f6bcfd97 | 7211 | EnsureCaretVisible(); |
9ce192d4 RD |
7212 | break; |
7213 | ||
d134f170 | 7214 | case SCI_CLEAR: |
9ce192d4 RD |
7215 | Clear(); |
7216 | SetLastXChosen(); | |
a834585d | 7217 | EnsureCaretVisible(); |
9ce192d4 RD |
7218 | break; |
7219 | ||
d134f170 | 7220 | case SCI_UNDO: |
9ce192d4 RD |
7221 | Undo(); |
7222 | SetLastXChosen(); | |
7223 | break; | |
7224 | ||
d134f170 | 7225 | case SCI_CANUNDO: |
1e9bafca | 7226 | return (pdoc->CanUndo() && !pdoc->IsReadOnly()) ? 1 : 0; |
9ce192d4 | 7227 | |
d134f170 | 7228 | case SCI_EMPTYUNDOBUFFER: |
9ce192d4 RD |
7229 | pdoc->DeleteUndoHistory(); |
7230 | return 0; | |
7231 | ||
d134f170 | 7232 | case SCI_GETFIRSTVISIBLELINE: |
9ce192d4 RD |
7233 | return topLine; |
7234 | ||
9e96e16f RD |
7235 | case SCI_SETFIRSTVISIBLELINE: |
7236 | ScrollTo(wParam); | |
7237 | break; | |
7238 | ||
b8b0e402 | 7239 | case SCI_GETLINE: { // Risk of overwriting the end of the buffer |
d134f170 RD |
7240 | int lineStart = pdoc->LineStart(wParam); |
7241 | int lineEnd = pdoc->LineStart(wParam + 1); | |
591d01be RD |
7242 | if (lParam == 0) { |
7243 | return lineEnd - lineStart; | |
7244 | } | |
a834585d | 7245 | char *ptr = CharPtrFromSPtr(lParam); |
d134f170 | 7246 | int iPlace = 0; |
65ec6247 | 7247 | for (int iChar = lineStart; iChar < lineEnd; iChar++) { |
d134f170 | 7248 | ptr[iPlace++] = pdoc->CharAt(iChar); |
65ec6247 | 7249 | } |
d134f170 RD |
7250 | return iPlace; |
7251 | } | |
7252 | ||
d134f170 | 7253 | case SCI_GETLINECOUNT: |
9ce192d4 RD |
7254 | if (pdoc->LinesTotal() == 0) |
7255 | return 1; | |
7256 | else | |
7257 | return pdoc->LinesTotal(); | |
7258 | ||
d134f170 | 7259 | case SCI_GETMODIFY: |
9ce192d4 RD |
7260 | return !pdoc->IsSavePoint(); |
7261 | ||
d134f170 | 7262 | case SCI_SETSEL: { |
9ce192d4 RD |
7263 | int nStart = static_cast<int>(wParam); |
7264 | int nEnd = static_cast<int>(lParam); | |
7265 | if (nEnd < 0) | |
7266 | nEnd = pdoc->Length(); | |
7267 | if (nStart < 0) | |
7268 | nStart = nEnd; // Remove selection | |
9e96e16f RD |
7269 | InvalidateSelection(SelectionRange(nStart, nEnd)); |
7270 | sel.Clear(); | |
7271 | sel.selType = Selection::selStream; | |
9ce192d4 RD |
7272 | SetSelection(nEnd, nStart); |
7273 | EnsureCaretVisible(); | |
7274 | } | |
7275 | break; | |
7276 | ||
d134f170 | 7277 | case SCI_GETSELTEXT: { |
b8b0e402 RD |
7278 | SelectionText selectedText; |
7279 | CopySelectionRange(&selectedText); | |
9e96e16f RD |
7280 | if (lParam == 0) { |
7281 | return selectedText.len ? selectedText.len : 1; | |
65ec6247 | 7282 | } else { |
9e96e16f RD |
7283 | char *ptr = CharPtrFromSPtr(lParam); |
7284 | int iChar = 0; | |
7285 | if (selectedText.len) { | |
7286 | for (; iChar < selectedText.len; iChar++) | |
7287 | ptr[iChar] = selectedText.s[iChar]; | |
7288 | } else { | |
7289 | ptr[0] = '\0'; | |
7290 | } | |
7291 | return iChar; | |
9ce192d4 | 7292 | } |
9ce192d4 RD |
7293 | } |
7294 | ||
d134f170 RD |
7295 | case SCI_LINEFROMPOSITION: |
7296 | if (static_cast<int>(wParam) < 0) | |
7297 | return 0; | |
7298 | return pdoc->LineFromPosition(wParam); | |
7299 | ||
d134f170 | 7300 | case SCI_POSITIONFROMLINE: |
9ce192d4 | 7301 | if (static_cast<int>(wParam) < 0) |
9e96e16f | 7302 | wParam = pdoc->LineFromPosition(SelectionStart().Position()); |
9ce192d4 RD |
7303 | if (wParam == 0) |
7304 | return 0; // Even if there is no text, there is a first line that starts at 0 | |
7305 | if (static_cast<int>(wParam) > pdoc->LinesTotal()) | |
65ec6247 | 7306 | return -1; |
9ce192d4 RD |
7307 | //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway... |
7308 | // return -1; | |
7309 | return pdoc->LineStart(wParam); | |
7310 | ||
9e730a78 | 7311 | // Replacement of the old Scintilla interpretation of EM_LINELENGTH |
9ce192d4 RD |
7312 | case SCI_LINELENGTH: |
7313 | if ((static_cast<int>(wParam) < 0) || | |
7314 | (static_cast<int>(wParam) > pdoc->LineFromPosition(pdoc->Length()))) | |
7315 | return 0; | |
7316 | return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam); | |
7317 | ||
d134f170 | 7318 | case SCI_REPLACESEL: { |
9ce192d4 RD |
7319 | if (lParam == 0) |
7320 | return 0; | |
9e96e16f | 7321 | UndoGroup ug(pdoc); |
9ce192d4 | 7322 | ClearSelection(); |
a834585d | 7323 | char *replacement = CharPtrFromSPtr(lParam); |
9e96e16f RD |
7324 | pdoc->InsertCString(sel.MainCaret(), replacement); |
7325 | SetEmptySelection(sel.MainCaret() + istrlen(replacement)); | |
9ce192d4 RD |
7326 | EnsureCaretVisible(); |
7327 | } | |
7328 | break; | |
7329 | ||
65ec6247 RD |
7330 | case SCI_SETTARGETSTART: |
7331 | targetStart = wParam; | |
7332 | break; | |
7333 | ||
7334 | case SCI_GETTARGETSTART: | |
7335 | return targetStart; | |
7336 | ||
7337 | case SCI_SETTARGETEND: | |
7338 | targetEnd = wParam; | |
7339 | break; | |
7340 | ||
7341 | case SCI_GETTARGETEND: | |
7342 | return targetEnd; | |
7343 | ||
9e730a78 | 7344 | case SCI_TARGETFROMSELECTION: |
9e96e16f RD |
7345 | if (sel.MainCaret() < sel.MainAnchor()) { |
7346 | targetStart = sel.MainCaret(); | |
7347 | targetEnd = sel.MainAnchor(); | |
9e730a78 | 7348 | } else { |
9e96e16f RD |
7349 | targetStart = sel.MainAnchor(); |
7350 | targetEnd = sel.MainCaret(); | |
9e730a78 RD |
7351 | } |
7352 | break; | |
7353 | ||
65ec6247 RD |
7354 | case SCI_REPLACETARGET: |
7355 | PLATFORM_ASSERT(lParam); | |
a834585d | 7356 | return ReplaceTarget(false, CharPtrFromSPtr(lParam), wParam); |
65ec6247 RD |
7357 | |
7358 | case SCI_REPLACETARGETRE: | |
7359 | PLATFORM_ASSERT(lParam); | |
a834585d | 7360 | return ReplaceTarget(true, CharPtrFromSPtr(lParam), wParam); |
65ec6247 RD |
7361 | |
7362 | case SCI_SEARCHINTARGET: | |
7363 | PLATFORM_ASSERT(lParam); | |
a834585d | 7364 | return SearchInTarget(CharPtrFromSPtr(lParam), wParam); |
65ec6247 RD |
7365 | |
7366 | case SCI_SETSEARCHFLAGS: | |
7367 | searchFlags = wParam; | |
7368 | break; | |
7369 | ||
7370 | case SCI_GETSEARCHFLAGS: | |
7371 | return searchFlags; | |
7372 | ||
1dcf666d RD |
7373 | case SCI_GETTAG: |
7374 | return GetTag(CharPtrFromSPtr(lParam), wParam); | |
7375 | ||
e14d10b0 | 7376 | case SCI_POSITIONBEFORE: |
7e0c58e9 | 7377 | return pdoc->MovePositionOutsideChar(wParam - 1, -1, true); |
e14d10b0 RD |
7378 | |
7379 | case SCI_POSITIONAFTER: | |
7e0c58e9 | 7380 | return pdoc->MovePositionOutsideChar(wParam + 1, 1, true); |
e14d10b0 | 7381 | |
d134f170 | 7382 | case SCI_LINESCROLL: |
9ce192d4 RD |
7383 | ScrollTo(topLine + lParam); |
7384 | HorizontalScrollTo(xOffset + wParam * vs.spaceWidth); | |
1a2fb4cd RD |
7385 | return 1; |
7386 | ||
7387 | case SCI_SETXOFFSET: | |
7388 | xOffset = wParam; | |
1dcf666d | 7389 | ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); |
9e730a78 | 7390 | SetHorizontalScrollPos(); |
1a2fb4cd RD |
7391 | Redraw(); |
7392 | break; | |
7393 | ||
7394 | case SCI_GETXOFFSET: | |
7395 | return xOffset; | |
9ce192d4 | 7396 | |
9e730a78 RD |
7397 | case SCI_CHOOSECARETX: |
7398 | SetLastXChosen(); | |
7399 | break; | |
7400 | ||
d134f170 | 7401 | case SCI_SCROLLCARET: |
9ce192d4 RD |
7402 | EnsureCaretVisible(); |
7403 | break; | |
7404 | ||
d134f170 | 7405 | case SCI_SETREADONLY: |
1a2fb4cd RD |
7406 | pdoc->SetReadOnly(wParam != 0); |
7407 | return 1; | |
9ce192d4 | 7408 | |
d134f170 RD |
7409 | case SCI_GETREADONLY: |
7410 | return pdoc->IsReadOnly(); | |
7411 | ||
d134f170 | 7412 | case SCI_CANPASTE: |
65ec6247 | 7413 | return CanPaste(); |
9ce192d4 | 7414 | |
d134f170 RD |
7415 | case SCI_POINTXFROMPOSITION: |
7416 | if (lParam < 0) { | |
7417 | return 0; | |
7418 | } else { | |
7419 | Point pt = LocationFromPosition(lParam); | |
7420 | return pt.x; | |
7421 | } | |
7422 | ||
7423 | case SCI_POINTYFROMPOSITION: | |
7424 | if (lParam < 0) { | |
7425 | return 0; | |
7426 | } else { | |
7427 | Point pt = LocationFromPosition(lParam); | |
7428 | return pt.y; | |
7429 | } | |
7430 | ||
d134f170 | 7431 | case SCI_FINDTEXT: |
b8b0e402 | 7432 | return FindText(wParam, lParam); |
9ce192d4 | 7433 | |
d134f170 | 7434 | case SCI_GETTEXTRANGE: { |
9ce192d4 RD |
7435 | if (lParam == 0) |
7436 | return 0; | |
9e96e16f | 7437 | Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam); |
9ce192d4 RD |
7438 | int cpMax = tr->chrg.cpMax; |
7439 | if (cpMax == -1) | |
7440 | cpMax = pdoc->Length(); | |
8e54aaed | 7441 | PLATFORM_ASSERT(cpMax <= pdoc->Length()); |
9ce192d4 RD |
7442 | int len = cpMax - tr->chrg.cpMin; // No -1 as cpMin and cpMax are referring to inter character positions |
7443 | pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len); | |
7444 | // Spec says copied text is terminated with a NUL | |
7445 | tr->lpstrText[len] = '\0'; | |
7446 | return len; // Not including NUL | |
7447 | } | |
7448 | ||
b8b0e402 | 7449 | case SCI_HIDESELECTION: |
1a2fb4cd | 7450 | hideSelection = wParam != 0; |
9ce192d4 RD |
7451 | Redraw(); |
7452 | break; | |
7453 | ||
d134f170 | 7454 | case SCI_FORMATRANGE: |
9e96e16f | 7455 | return FormatRange(wParam != 0, reinterpret_cast<Sci_RangeToFormat *>(lParam)); |
9ce192d4 | 7456 | |
d134f170 RD |
7457 | case SCI_GETMARGINLEFT: |
7458 | return vs.leftMarginWidth; | |
7459 | ||
7460 | case SCI_GETMARGINRIGHT: | |
7461 | return vs.rightMarginWidth; | |
7462 | ||
d134f170 RD |
7463 | case SCI_SETMARGINLEFT: |
7464 | vs.leftMarginWidth = lParam; | |
7465 | InvalidateStyleRedraw(); | |
7466 | break; | |
7467 | ||
7468 | case SCI_SETMARGINRIGHT: | |
7469 | vs.rightMarginWidth = lParam; | |
7470 | InvalidateStyleRedraw(); | |
7471 | break; | |
7472 | ||
9ce192d4 RD |
7473 | // Control specific mesages |
7474 | ||
7475 | case SCI_ADDTEXT: { | |
7476 | if (lParam == 0) | |
7477 | return 0; | |
a834585d | 7478 | pdoc->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam), wParam); |
9e96e16f | 7479 | SetEmptySelection(sel.MainCaret() + wParam); |
9ce192d4 RD |
7480 | return 0; |
7481 | } | |
7482 | ||
7e0c58e9 RD |
7483 | case SCI_ADDSTYLEDTEXT: |
7484 | if (lParam) | |
7485 | AddStyledText(CharPtrFromSPtr(lParam), wParam); | |
7486 | return 0; | |
9ce192d4 RD |
7487 | |
7488 | case SCI_INSERTTEXT: { | |
7489 | if (lParam == 0) | |
7490 | return 0; | |
7491 | int insertPos = wParam; | |
8e54aaed | 7492 | if (static_cast<int>(wParam) == -1) |
9ce192d4 RD |
7493 | insertPos = CurrentPosition(); |
7494 | int newCurrent = CurrentPosition(); | |
a834585d | 7495 | char *sz = CharPtrFromSPtr(lParam); |
7e0c58e9 | 7496 | pdoc->InsertCString(insertPos, sz); |
9ce192d4 | 7497 | if (newCurrent > insertPos) |
88a8b04e | 7498 | newCurrent += istrlen(sz); |
9ce192d4 RD |
7499 | SetEmptySelection(newCurrent); |
7500 | return 0; | |
7501 | } | |
7502 | ||
9e730a78 RD |
7503 | case SCI_APPENDTEXT: |
7504 | pdoc->InsertString(pdoc->Length(), CharPtrFromSPtr(lParam), wParam); | |
7505 | return 0; | |
7506 | ||
9ce192d4 RD |
7507 | case SCI_CLEARALL: |
7508 | ClearAll(); | |
7509 | return 0; | |
7510 | ||
1dcf666d RD |
7511 | case SCI_DELETERANGE: |
7512 | pdoc->DeleteChars(wParam, lParam); | |
7513 | return 0; | |
7514 | ||
d134f170 RD |
7515 | case SCI_CLEARDOCUMENTSTYLE: |
7516 | ClearDocumentStyle(); | |
9ce192d4 RD |
7517 | return 0; |
7518 | ||
d134f170 | 7519 | case SCI_SETUNDOCOLLECTION: |
1a2fb4cd | 7520 | pdoc->SetUndoCollection(wParam != 0); |
9ce192d4 | 7521 | return 0; |
d134f170 RD |
7522 | |
7523 | case SCI_GETUNDOCOLLECTION: | |
7524 | return pdoc->IsCollectingUndo(); | |
9ce192d4 RD |
7525 | |
7526 | case SCI_BEGINUNDOACTION: | |
7527 | pdoc->BeginUndoAction(); | |
7528 | return 0; | |
7529 | ||
7530 | case SCI_ENDUNDOACTION: | |
7531 | pdoc->EndUndoAction(); | |
7532 | return 0; | |
7533 | ||
7534 | case SCI_GETCARETPERIOD: | |
7535 | return caret.period; | |
7536 | ||
7537 | case SCI_SETCARETPERIOD: | |
7538 | caret.period = wParam; | |
7539 | break; | |
7540 | ||
1dcf666d RD |
7541 | case SCI_GETWORDCHARS: |
7542 | return pdoc->GetCharsOfClass(CharClassify::ccWord, reinterpret_cast<unsigned char *>(lParam)); | |
7543 | ||
9ce192d4 | 7544 | case SCI_SETWORDCHARS: { |
591d01be | 7545 | pdoc->SetDefaultCharClasses(false); |
9ce192d4 RD |
7546 | if (lParam == 0) |
7547 | return 0; | |
b8193d80 | 7548 | pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccWord); |
9ce192d4 RD |
7549 | } |
7550 | break; | |
7551 | ||
1dcf666d RD |
7552 | case SCI_GETWHITESPACECHARS: |
7553 | return pdoc->GetCharsOfClass(CharClassify::ccSpace, reinterpret_cast<unsigned char *>(lParam)); | |
7554 | ||
8e54aaed RD |
7555 | case SCI_SETWHITESPACECHARS: { |
7556 | if (lParam == 0) | |
7557 | return 0; | |
b8193d80 | 7558 | pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccSpace); |
8e54aaed RD |
7559 | } |
7560 | break; | |
7561 | ||
1dcf666d RD |
7562 | case SCI_GETPUNCTUATIONCHARS: |
7563 | return pdoc->GetCharsOfClass(CharClassify::ccPunctuation, reinterpret_cast<unsigned char *>(lParam)); | |
7564 | ||
7565 | case SCI_SETPUNCTUATIONCHARS: { | |
7566 | if (lParam == 0) | |
7567 | return 0; | |
7568 | pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccPunctuation); | |
7569 | } | |
7570 | break; | |
7571 | ||
8e54aaed | 7572 | case SCI_SETCHARSDEFAULT: |
591d01be | 7573 | pdoc->SetDefaultCharClasses(true); |
8e54aaed RD |
7574 | break; |
7575 | ||
9ce192d4 RD |
7576 | case SCI_GETLENGTH: |
7577 | return pdoc->Length(); | |
7578 | ||
591d01be RD |
7579 | case SCI_ALLOCATE: |
7580 | pdoc->Allocate(wParam); | |
7581 | break; | |
7582 | ||
9ce192d4 RD |
7583 | case SCI_GETCHARAT: |
7584 | return pdoc->CharAt(wParam); | |
7585 | ||
d134f170 | 7586 | case SCI_SETCURRENTPOS: |
9e96e16f RD |
7587 | if (sel.IsRectangular()) { |
7588 | sel.Rectangular().caret.SetPosition(wParam); | |
7589 | SetRectangularRange(); | |
7590 | Redraw(); | |
7591 | } else { | |
7592 | SetSelection(wParam, sel.MainAnchor()); | |
7593 | } | |
d134f170 RD |
7594 | break; |
7595 | ||
9ce192d4 | 7596 | case SCI_GETCURRENTPOS: |
9e96e16f | 7597 | return sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret(); |
9ce192d4 | 7598 | |
d134f170 | 7599 | case SCI_SETANCHOR: |
9e96e16f RD |
7600 | if (sel.IsRectangular()) { |
7601 | sel.Rectangular().anchor.SetPosition(wParam); | |
7602 | SetRectangularRange(); | |
7603 | Redraw(); | |
7604 | } else { | |
7605 | SetSelection(sel.MainCaret(), wParam); | |
7606 | } | |
d134f170 RD |
7607 | break; |
7608 | ||
9ce192d4 | 7609 | case SCI_GETANCHOR: |
9e96e16f | 7610 | return sel.IsRectangular() ? sel.Rectangular().anchor.Position() : sel.MainAnchor(); |
9ce192d4 | 7611 | |
d134f170 | 7612 | case SCI_SETSELECTIONSTART: |
9e96e16f | 7613 | SetSelection(Platform::Maximum(sel.MainCaret(), wParam), wParam); |
d134f170 RD |
7614 | break; |
7615 | ||
7616 | case SCI_GETSELECTIONSTART: | |
1dcf666d | 7617 | return sel.LimitsForRectangularElseMain().start.Position(); |
d134f170 RD |
7618 | |
7619 | case SCI_SETSELECTIONEND: | |
9e96e16f | 7620 | SetSelection(wParam, Platform::Minimum(sel.MainAnchor(), wParam)); |
d134f170 RD |
7621 | break; |
7622 | ||
7623 | case SCI_GETSELECTIONEND: | |
1dcf666d RD |
7624 | return sel.LimitsForRectangularElseMain().end.Position(); |
7625 | ||
7626 | case SCI_SETEMPTYSELECTION: | |
7627 | SetEmptySelection(wParam); | |
7628 | break; | |
d134f170 RD |
7629 | |
7630 | case SCI_SETPRINTMAGNIFICATION: | |
7631 | printMagnification = wParam; | |
7632 | break; | |
7633 | ||
7634 | case SCI_GETPRINTMAGNIFICATION: | |
7635 | return printMagnification; | |
7636 | ||
7637 | case SCI_SETPRINTCOLOURMODE: | |
7638 | printColourMode = wParam; | |
7639 | break; | |
7640 | ||
7641 | case SCI_GETPRINTCOLOURMODE: | |
7642 | return printColourMode; | |
7643 | ||
9e730a78 RD |
7644 | case SCI_SETPRINTWRAPMODE: |
7645 | printWrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone; | |
7646 | break; | |
7647 | ||
7648 | case SCI_GETPRINTWRAPMODE: | |
7649 | return printWrapState; | |
7650 | ||
9ce192d4 | 7651 | case SCI_GETSTYLEAT: |
8e54aaed | 7652 | if (static_cast<int>(wParam) >= pdoc->Length()) |
9ce192d4 RD |
7653 | return 0; |
7654 | else | |
7655 | return pdoc->StyleAt(wParam); | |
7656 | ||
7657 | case SCI_REDO: | |
7658 | Redo(); | |
7659 | break; | |
7660 | ||
7661 | case SCI_SELECTALL: | |
7662 | SelectAll(); | |
7663 | break; | |
7664 | ||
7665 | case SCI_SETSAVEPOINT: | |
7666 | pdoc->SetSavePoint(); | |
9ce192d4 RD |
7667 | break; |
7668 | ||
7669 | case SCI_GETSTYLEDTEXT: { | |
7670 | if (lParam == 0) | |
7671 | return 0; | |
9e96e16f | 7672 | Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam); |
9ce192d4 RD |
7673 | int iPlace = 0; |
7674 | for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) { | |
7675 | tr->lpstrText[iPlace++] = pdoc->CharAt(iChar); | |
7676 | tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar); | |
7677 | } | |
7678 | tr->lpstrText[iPlace] = '\0'; | |
7679 | tr->lpstrText[iPlace + 1] = '\0'; | |
7680 | return iPlace; | |
7681 | } | |
7682 | ||
7683 | case SCI_CANREDO: | |
1e9bafca | 7684 | return (pdoc->CanRedo() && !pdoc->IsReadOnly()) ? 1 : 0; |
9ce192d4 RD |
7685 | |
7686 | case SCI_MARKERLINEFROMHANDLE: | |
7687 | return pdoc->LineFromHandle(wParam); | |
7688 | ||
7689 | case SCI_MARKERDELETEHANDLE: | |
7690 | pdoc->DeleteMarkFromHandle(wParam); | |
7691 | break; | |
7692 | ||
7693 | case SCI_GETVIEWWS: | |
7694 | return vs.viewWhitespace; | |
7695 | ||
7696 | case SCI_SETVIEWWS: | |
d134f170 | 7697 | vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(wParam); |
9ce192d4 RD |
7698 | Redraw(); |
7699 | break; | |
7700 | ||
9e96e16f RD |
7701 | case SCI_GETWHITESPACESIZE: |
7702 | return vs.whitespaceSize; | |
7703 | ||
7704 | case SCI_SETWHITESPACESIZE: | |
7705 | vs.whitespaceSize = static_cast<int>(wParam); | |
7706 | Redraw(); | |
7707 | break; | |
7708 | ||
d134f170 | 7709 | case SCI_POSITIONFROMPOINT: |
9e96e16f | 7710 | return PositionFromLocation(Point(wParam, lParam), false, false); |
d134f170 | 7711 | |
65ec6247 | 7712 | case SCI_POSITIONFROMPOINTCLOSE: |
9e96e16f RD |
7713 | return PositionFromLocation(Point(wParam, lParam), true, false); |
7714 | ||
7715 | case SCI_CHARPOSITIONFROMPOINT: | |
7716 | return PositionFromLocation(Point(wParam, lParam), false, true); | |
7717 | ||
7718 | case SCI_CHARPOSITIONFROMPOINTCLOSE: | |
7719 | return PositionFromLocation(Point(wParam, lParam), true, true); | |
65ec6247 | 7720 | |
9ce192d4 RD |
7721 | case SCI_GOTOLINE: |
7722 | GoToLine(wParam); | |
7723 | break; | |
7724 | ||
7725 | case SCI_GOTOPOS: | |
7726 | SetEmptySelection(wParam); | |
7727 | EnsureCaretVisible(); | |
9ce192d4 RD |
7728 | break; |
7729 | ||
9ce192d4 | 7730 | case SCI_GETCURLINE: { |
9e96e16f | 7731 | int lineCurrentPos = pdoc->LineFromPosition(sel.MainCaret()); |
9ce192d4 RD |
7732 | int lineStart = pdoc->LineStart(lineCurrentPos); |
7733 | unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1); | |
591d01be RD |
7734 | if (lParam == 0) { |
7735 | return 1 + lineEnd - lineStart; | |
7736 | } | |
1e9bafca | 7737 | PLATFORM_ASSERT(wParam > 0); |
a834585d | 7738 | char *ptr = CharPtrFromSPtr(lParam); |
9ce192d4 | 7739 | unsigned int iPlace = 0; |
65ec6247 | 7740 | for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam - 1; iChar++) { |
9ce192d4 | 7741 | ptr[iPlace++] = pdoc->CharAt(iChar); |
65ec6247 | 7742 | } |
9ce192d4 | 7743 | ptr[iPlace] = '\0'; |
9e96e16f | 7744 | return sel.MainCaret() - lineStart; |
9ce192d4 RD |
7745 | } |
7746 | ||
7747 | case SCI_GETENDSTYLED: | |
7748 | return pdoc->GetEndStyled(); | |
7749 | ||
7750 | case SCI_GETEOLMODE: | |
7751 | return pdoc->eolMode; | |
7752 | ||
7753 | case SCI_SETEOLMODE: | |
7754 | pdoc->eolMode = wParam; | |
7755 | break; | |
7756 | ||
7757 | case SCI_STARTSTYLING: | |
f6bcfd97 | 7758 | pdoc->StartStyling(wParam, static_cast<char>(lParam)); |
9ce192d4 RD |
7759 | break; |
7760 | ||
7761 | case SCI_SETSTYLING: | |
f6bcfd97 | 7762 | pdoc->SetStyleFor(wParam, static_cast<char>(lParam)); |
9ce192d4 RD |
7763 | break; |
7764 | ||
9e730a78 | 7765 | case SCI_SETSTYLINGEX: // Specify a complete styling buffer |
9ce192d4 RD |
7766 | if (lParam == 0) |
7767 | return 0; | |
a834585d | 7768 | pdoc->SetStyles(wParam, CharPtrFromSPtr(lParam)); |
9ce192d4 RD |
7769 | break; |
7770 | ||
9ce192d4 | 7771 | case SCI_SETBUFFEREDDRAW: |
1a2fb4cd | 7772 | bufferedDraw = wParam != 0; |
9ce192d4 RD |
7773 | break; |
7774 | ||
d134f170 RD |
7775 | case SCI_GETBUFFEREDDRAW: |
7776 | return bufferedDraw; | |
7777 | ||
9e730a78 RD |
7778 | case SCI_GETTWOPHASEDRAW: |
7779 | return twoPhaseDraw; | |
7780 | ||
7781 | case SCI_SETTWOPHASEDRAW: | |
7782 | twoPhaseDraw = wParam != 0; | |
7783 | InvalidateStyleRedraw(); | |
7784 | break; | |
7785 | ||
9e96e16f RD |
7786 | case SCI_SETFONTQUALITY: |
7787 | vs.extraFontFlag &= ~SC_EFF_QUALITY_MASK; | |
7788 | vs.extraFontFlag |= (wParam & SC_EFF_QUALITY_MASK); | |
7789 | InvalidateStyleRedraw(); | |
7790 | break; | |
7791 | ||
7792 | case SCI_GETFONTQUALITY: | |
7793 | return (vs.extraFontFlag & SC_EFF_QUALITY_MASK); | |
7794 | ||
9ce192d4 | 7795 | case SCI_SETTABWIDTH: |
591d01be | 7796 | if (wParam > 0) { |
9ce192d4 | 7797 | pdoc->tabInChars = wParam; |
591d01be RD |
7798 | if (pdoc->indentInChars == 0) |
7799 | pdoc->actualIndentInChars = pdoc->tabInChars; | |
7800 | } | |
9ce192d4 RD |
7801 | InvalidateStyleRedraw(); |
7802 | break; | |
7803 | ||
f6bcfd97 BP |
7804 | case SCI_GETTABWIDTH: |
7805 | return pdoc->tabInChars; | |
d134f170 | 7806 | |
f6bcfd97 BP |
7807 | case SCI_SETINDENT: |
7808 | pdoc->indentInChars = wParam; | |
591d01be RD |
7809 | if (pdoc->indentInChars != 0) |
7810 | pdoc->actualIndentInChars = pdoc->indentInChars; | |
7811 | else | |
7812 | pdoc->actualIndentInChars = pdoc->tabInChars; | |
f6bcfd97 BP |
7813 | InvalidateStyleRedraw(); |
7814 | break; | |
d134f170 | 7815 | |
f6bcfd97 BP |
7816 | case SCI_GETINDENT: |
7817 | return pdoc->indentInChars; | |
7818 | ||
7819 | case SCI_SETUSETABS: | |
1a2fb4cd | 7820 | pdoc->useTabs = wParam != 0; |
f6bcfd97 BP |
7821 | InvalidateStyleRedraw(); |
7822 | break; | |
7823 | ||
7824 | case SCI_GETUSETABS: | |
7825 | return pdoc->useTabs; | |
d134f170 | 7826 | |
f6bcfd97 BP |
7827 | case SCI_SETLINEINDENTATION: |
7828 | pdoc->SetLineIndentation(wParam, lParam); | |
7829 | break; | |
d134f170 | 7830 | |
f6bcfd97 BP |
7831 | case SCI_GETLINEINDENTATION: |
7832 | return pdoc->GetLineIndentation(wParam); | |
d134f170 | 7833 | |
f6bcfd97 BP |
7834 | case SCI_GETLINEINDENTPOSITION: |
7835 | return pdoc->GetLineIndentPosition(wParam); | |
d134f170 | 7836 | |
65ec6247 | 7837 | case SCI_SETTABINDENTS: |
1a2fb4cd | 7838 | pdoc->tabIndents = wParam != 0; |
65ec6247 RD |
7839 | break; |
7840 | ||
7841 | case SCI_GETTABINDENTS: | |
7842 | return pdoc->tabIndents; | |
7843 | ||
7844 | case SCI_SETBACKSPACEUNINDENTS: | |
1a2fb4cd | 7845 | pdoc->backspaceUnindents = wParam != 0; |
65ec6247 RD |
7846 | break; |
7847 | ||
7848 | case SCI_GETBACKSPACEUNINDENTS: | |
7849 | return pdoc->backspaceUnindents; | |
7850 | ||
7851 | case SCI_SETMOUSEDWELLTIME: | |
7852 | dwellDelay = wParam; | |
7853 | ticksToDwell = dwellDelay; | |
7854 | break; | |
1a2fb4cd | 7855 | |
65ec6247 RD |
7856 | case SCI_GETMOUSEDWELLTIME: |
7857 | return dwellDelay; | |
1a2fb4cd RD |
7858 | |
7859 | case SCI_WORDSTARTPOSITION: | |
7860 | return pdoc->ExtendWordSelect(wParam, -1, lParam != 0); | |
7861 | ||
7862 | case SCI_WORDENDPOSITION: | |
7863 | return pdoc->ExtendWordSelect(wParam, 1, lParam != 0); | |
7864 | ||
7865 | case SCI_SETWRAPMODE: | |
b8193d80 RD |
7866 | switch (wParam) { |
7867 | case SC_WRAP_WORD: | |
7868 | wrapState = eWrapWord; | |
7869 | break; | |
7870 | case SC_WRAP_CHAR: | |
7871 | wrapState = eWrapChar; | |
7872 | break; | |
7873 | default: | |
7874 | wrapState = eWrapNone; | |
7875 | break; | |
1e9bafca | 7876 | } |
1a2fb4cd | 7877 | xOffset = 0; |
1dcf666d | 7878 | ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); |
1a2fb4cd RD |
7879 | InvalidateStyleRedraw(); |
7880 | ReconfigureScrollBars(); | |
7881 | break; | |
7882 | ||
7883 | case SCI_GETWRAPMODE: | |
7884 | return wrapState; | |
7885 | ||
591d01be | 7886 | case SCI_SETWRAPVISUALFLAGS: |
1dcf666d RD |
7887 | if (wrapVisualFlags != static_cast<int>(wParam)) { |
7888 | wrapVisualFlags = wParam; | |
7889 | InvalidateStyleRedraw(); | |
7890 | ReconfigureScrollBars(); | |
7891 | } | |
591d01be RD |
7892 | break; |
7893 | ||
7894 | case SCI_GETWRAPVISUALFLAGS: | |
7895 | return wrapVisualFlags; | |
7896 | ||
7897 | case SCI_SETWRAPVISUALFLAGSLOCATION: | |
7898 | wrapVisualFlagsLocation = wParam; | |
7899 | InvalidateStyleRedraw(); | |
7900 | break; | |
7901 | ||
7902 | case SCI_GETWRAPVISUALFLAGSLOCATION: | |
7903 | return wrapVisualFlagsLocation; | |
7904 | ||
7905 | case SCI_SETWRAPSTARTINDENT: | |
1dcf666d RD |
7906 | if (wrapVisualStartIndent != static_cast<int>(wParam)) { |
7907 | wrapVisualStartIndent = wParam; | |
7908 | InvalidateStyleRedraw(); | |
7909 | ReconfigureScrollBars(); | |
7910 | } | |
591d01be RD |
7911 | break; |
7912 | ||
7913 | case SCI_GETWRAPSTARTINDENT: | |
7914 | return wrapVisualStartIndent; | |
7915 | ||
9e96e16f | 7916 | case SCI_SETWRAPINDENTMODE: |
1dcf666d RD |
7917 | if (wrapIndentMode != static_cast<int>(wParam)) { |
7918 | wrapIndentMode = wParam; | |
7919 | InvalidateStyleRedraw(); | |
7920 | ReconfigureScrollBars(); | |
7921 | } | |
9e96e16f RD |
7922 | break; |
7923 | ||
7924 | case SCI_GETWRAPINDENTMODE: | |
7925 | return wrapIndentMode; | |
7926 | ||
1a2fb4cd RD |
7927 | case SCI_SETLAYOUTCACHE: |
7928 | llc.SetLevel(wParam); | |
7929 | break; | |
7930 | ||
7931 | case SCI_GETLAYOUTCACHE: | |
7932 | return llc.GetLevel(); | |
7933 | ||
7e0c58e9 RD |
7934 | case SCI_SETPOSITIONCACHE: |
7935 | posCache.SetSize(wParam); | |
7936 | break; | |
7937 | ||
7938 | case SCI_GETPOSITIONCACHE: | |
7939 | return posCache.GetSize(); | |
7940 | ||
a834585d RD |
7941 | case SCI_SETSCROLLWIDTH: |
7942 | PLATFORM_ASSERT(wParam > 0); | |
7943 | if ((wParam > 0) && (wParam != static_cast<unsigned int >(scrollWidth))) { | |
7e0c58e9 | 7944 | lineWidthMaxSeen = 0; |
a834585d RD |
7945 | scrollWidth = wParam; |
7946 | SetScrollBars(); | |
7947 | } | |
7948 | break; | |
7949 | ||
7950 | case SCI_GETSCROLLWIDTH: | |
7951 | return scrollWidth; | |
7952 | ||
7e0c58e9 RD |
7953 | case SCI_SETSCROLLWIDTHTRACKING: |
7954 | trackLineWidth = wParam != 0; | |
7955 | break; | |
7956 | ||
7957 | case SCI_GETSCROLLWIDTHTRACKING: | |
7958 | return trackLineWidth; | |
7959 | ||
9e730a78 RD |
7960 | case SCI_LINESJOIN: |
7961 | LinesJoin(); | |
7962 | break; | |
7963 | ||
7964 | case SCI_LINESSPLIT: | |
7965 | LinesSplit(wParam); | |
7966 | break; | |
7967 | ||
a834585d | 7968 | case SCI_TEXTWIDTH: |
7e0c58e9 | 7969 | PLATFORM_ASSERT(wParam < vs.stylesSize); |
a834585d RD |
7970 | PLATFORM_ASSERT(lParam); |
7971 | return TextWidth(wParam, CharPtrFromSPtr(lParam)); | |
7972 | ||
7973 | case SCI_TEXTHEIGHT: | |
7974 | return vs.lineHeight; | |
7975 | ||
7976 | case SCI_SETENDATLASTLINE: | |
9e730a78 | 7977 | PLATFORM_ASSERT((wParam == 0) || (wParam == 1)); |
a834585d RD |
7978 | if (endAtLastLine != (wParam != 0)) { |
7979 | endAtLastLine = wParam != 0; | |
7980 | SetScrollBars(); | |
7981 | } | |
7982 | break; | |
7983 | ||
7984 | case SCI_GETENDATLASTLINE: | |
7985 | return endAtLastLine; | |
7986 | ||
1e9bafca | 7987 | case SCI_SETCARETSTICKY: |
1dcf666d RD |
7988 | PLATFORM_ASSERT(wParam <= SC_CARETSTICKY_WHITESPACE); |
7989 | if (wParam <= SC_CARETSTICKY_WHITESPACE) { | |
7990 | caretSticky = wParam; | |
1e9bafca RD |
7991 | } |
7992 | break; | |
7993 | ||
7994 | case SCI_GETCARETSTICKY: | |
7995 | return caretSticky; | |
7996 | ||
7997 | case SCI_TOGGLECARETSTICKY: | |
7998 | caretSticky = !caretSticky; | |
7999 | break; | |
8000 | ||
d134f170 RD |
8001 | case SCI_GETCOLUMN: |
8002 | return pdoc->GetColumn(wParam); | |
8003 | ||
a33203cb RD |
8004 | case SCI_FINDCOLUMN: |
8005 | return pdoc->FindColumn(wParam, lParam); | |
8006 | ||
f6bcfd97 | 8007 | case SCI_SETHSCROLLBAR : |
1a2fb4cd RD |
8008 | if (horizontalScrollBarVisible != (wParam != 0)) { |
8009 | horizontalScrollBarVisible = wParam != 0; | |
8010 | SetScrollBars(); | |
8011 | ReconfigureScrollBars(); | |
8012 | } | |
f6bcfd97 | 8013 | break; |
d134f170 | 8014 | |
f6bcfd97 BP |
8015 | case SCI_GETHSCROLLBAR: |
8016 | return horizontalScrollBarVisible; | |
d134f170 | 8017 | |
9e730a78 RD |
8018 | case SCI_SETVSCROLLBAR: |
8019 | if (verticalScrollBarVisible != (wParam != 0)) { | |
8020 | verticalScrollBarVisible = wParam != 0; | |
8021 | SetScrollBars(); | |
8022 | ReconfigureScrollBars(); | |
8023 | } | |
8024 | break; | |
8025 | ||
8026 | case SCI_GETVSCROLLBAR: | |
8027 | return verticalScrollBarVisible; | |
8028 | ||
d134f170 | 8029 | case SCI_SETINDENTATIONGUIDES: |
7e0c58e9 | 8030 | vs.viewIndentationGuides = IndentView(wParam); |
d134f170 | 8031 | Redraw(); |
9ce192d4 RD |
8032 | break; |
8033 | ||
d134f170 RD |
8034 | case SCI_GETINDENTATIONGUIDES: |
8035 | return vs.viewIndentationGuides; | |
8036 | ||
8037 | case SCI_SETHIGHLIGHTGUIDE: | |
8038 | if ((highlightGuideColumn != static_cast<int>(wParam)) || (wParam > 0)) { | |
8039 | highlightGuideColumn = wParam; | |
8040 | Redraw(); | |
9ce192d4 | 8041 | } |
9ce192d4 | 8042 | break; |
d134f170 RD |
8043 | |
8044 | case SCI_GETHIGHLIGHTGUIDE: | |
8045 | return highlightGuideColumn; | |
8046 | ||
8047 | case SCI_GETLINEENDPOSITION: | |
8048 | return pdoc->LineEnd(wParam); | |
8049 | ||
8050 | case SCI_SETCODEPAGE: | |
b8193d80 RD |
8051 | if (ValidCodePage(wParam)) { |
8052 | pdoc->dbcsCodePage = wParam; | |
8053 | InvalidateStyleRedraw(); | |
8054 | } | |
d134f170 RD |
8055 | break; |
8056 | ||
8057 | case SCI_GETCODEPAGE: | |
8058 | return pdoc->dbcsCodePage; | |
9ce192d4 | 8059 | |
1dcf666d | 8060 | #ifdef INCLUDE_DEPRECATED_FEATURES |
9ce192d4 | 8061 | case SCI_SETUSEPALETTE: |
9ce192d4 RD |
8062 | InvalidateStyleRedraw(); |
8063 | break; | |
8064 | ||
d134f170 | 8065 | case SCI_GETUSEPALETTE: |
1dcf666d RD |
8066 | return 0; |
8067 | #endif | |
d134f170 | 8068 | |
9ce192d4 RD |
8069 | // Marker definition and setting |
8070 | case SCI_MARKERDEFINE: | |
1dcf666d | 8071 | if (wParam <= MARKER_MAX) { |
9ce192d4 | 8072 | vs.markers[wParam].markType = lParam; |
1dcf666d RD |
8073 | vs.CalcLargestMarkerHeight(); |
8074 | } | |
9ce192d4 RD |
8075 | InvalidateStyleData(); |
8076 | RedrawSelMargin(); | |
8077 | break; | |
9e96e16f RD |
8078 | |
8079 | case SCI_MARKERSYMBOLDEFINED: | |
8080 | if (wParam <= MARKER_MAX) | |
8081 | return vs.markers[wParam].markType; | |
8082 | else | |
8083 | return 0; | |
8084 | ||
9ce192d4 RD |
8085 | case SCI_MARKERSETFORE: |
8086 | if (wParam <= MARKER_MAX) | |
1dcf666d RD |
8087 | vs.markers[wParam].fore = ColourDesired(lParam); |
8088 | InvalidateStyleData(); | |
8089 | RedrawSelMargin(); | |
8090 | break; | |
8091 | case SCI_MARKERSETBACKSELECTED: | |
8092 | if (wParam <= MARKER_MAX) | |
8093 | vs.markers[wParam].backSelected = ColourDesired(lParam); | |
9ce192d4 RD |
8094 | InvalidateStyleData(); |
8095 | RedrawSelMargin(); | |
8096 | break; | |
1dcf666d RD |
8097 | case SCI_MARKERENABLEHIGHLIGHT: |
8098 | highlightDelimiter.isEnabled = wParam == 1; | |
8099 | RedrawSelMargin(); | |
8100 | break; | |
9ce192d4 RD |
8101 | case SCI_MARKERSETBACK: |
8102 | if (wParam <= MARKER_MAX) | |
1dcf666d | 8103 | vs.markers[wParam].back = ColourDesired(lParam); |
9ce192d4 RD |
8104 | InvalidateStyleData(); |
8105 | RedrawSelMargin(); | |
8106 | break; | |
b8193d80 RD |
8107 | case SCI_MARKERSETALPHA: |
8108 | if (wParam <= MARKER_MAX) | |
8109 | vs.markers[wParam].alpha = lParam; | |
8110 | InvalidateStyleRedraw(); | |
8111 | break; | |
9ce192d4 RD |
8112 | case SCI_MARKERADD: { |
8113 | int markerID = pdoc->AddMark(wParam, lParam); | |
9ce192d4 RD |
8114 | return markerID; |
8115 | } | |
1e9bafca RD |
8116 | case SCI_MARKERADDSET: |
8117 | if (lParam != 0) | |
8118 | pdoc->AddMarkSet(wParam, lParam); | |
8119 | break; | |
9ce192d4 RD |
8120 | |
8121 | case SCI_MARKERDELETE: | |
8122 | pdoc->DeleteMark(wParam, lParam); | |
9ce192d4 RD |
8123 | break; |
8124 | ||
8125 | case SCI_MARKERDELETEALL: | |
8126 | pdoc->DeleteAllMarks(static_cast<int>(wParam)); | |
9ce192d4 RD |
8127 | break; |
8128 | ||
8129 | case SCI_MARKERGET: | |
8130 | return pdoc->GetMark(wParam); | |
8131 | ||
1dcf666d RD |
8132 | case SCI_MARKERNEXT: |
8133 | return pdoc->MarkerNext(wParam, lParam); | |
9ce192d4 RD |
8134 | |
8135 | case SCI_MARKERPREVIOUS: { | |
8136 | for (int iLine = wParam; iLine >= 0; iLine--) { | |
8137 | if ((pdoc->GetMark(iLine) & lParam) != 0) | |
8138 | return iLine; | |
8139 | } | |
8140 | } | |
8141 | return -1; | |
8142 | ||
9e730a78 RD |
8143 | case SCI_MARKERDEFINEPIXMAP: |
8144 | if (wParam <= MARKER_MAX) { | |
8145 | vs.markers[wParam].SetXPM(CharPtrFromSPtr(lParam)); | |
1dcf666d RD |
8146 | vs.CalcLargestMarkerHeight(); |
8147 | }; | |
8148 | InvalidateStyleData(); | |
8149 | RedrawSelMargin(); | |
8150 | break; | |
8151 | ||
8152 | case SCI_RGBAIMAGESETWIDTH: | |
8153 | sizeRGBAImage.x = wParam; | |
8154 | break; | |
8155 | ||
8156 | case SCI_RGBAIMAGESETHEIGHT: | |
8157 | sizeRGBAImage.y = wParam; | |
8158 | break; | |
8159 | ||
8160 | case SCI_MARKERDEFINERGBAIMAGE: | |
8161 | if (wParam <= MARKER_MAX) { | |
8162 | vs.markers[wParam].SetRGBAImage(sizeRGBAImage, reinterpret_cast<unsigned char *>(lParam)); | |
8163 | vs.CalcLargestMarkerHeight(); | |
9e730a78 RD |
8164 | }; |
8165 | InvalidateStyleData(); | |
8166 | RedrawSelMargin(); | |
8167 | break; | |
8168 | ||
9ce192d4 | 8169 | case SCI_SETMARGINTYPEN: |
f6bcfd97 | 8170 | if (ValidMargin(wParam)) { |
b8193d80 | 8171 | vs.ms[wParam].style = lParam; |
9ce192d4 RD |
8172 | InvalidateStyleRedraw(); |
8173 | } | |
8174 | break; | |
d134f170 | 8175 | |
9ce192d4 | 8176 | case SCI_GETMARGINTYPEN: |
d134f170 | 8177 | if (ValidMargin(wParam)) |
b8193d80 | 8178 | return vs.ms[wParam].style; |
9ce192d4 RD |
8179 | else |
8180 | return 0; | |
d134f170 | 8181 | |
9ce192d4 | 8182 | case SCI_SETMARGINWIDTHN: |
f6bcfd97 | 8183 | if (ValidMargin(wParam)) { |
8e54aaed RD |
8184 | // Short-circuit if the width is unchanged, to avoid unnecessary redraw. |
8185 | if (vs.ms[wParam].width != lParam) { | |
8186 | vs.ms[wParam].width = lParam; | |
8187 | InvalidateStyleRedraw(); | |
8188 | } | |
9ce192d4 RD |
8189 | } |
8190 | break; | |
d134f170 | 8191 | |
9ce192d4 | 8192 | case SCI_GETMARGINWIDTHN: |
d134f170 | 8193 | if (ValidMargin(wParam)) |
9ce192d4 RD |
8194 | return vs.ms[wParam].width; |
8195 | else | |
8196 | return 0; | |
d134f170 | 8197 | |
9ce192d4 | 8198 | case SCI_SETMARGINMASKN: |
f6bcfd97 | 8199 | if (ValidMargin(wParam)) { |
9ce192d4 RD |
8200 | vs.ms[wParam].mask = lParam; |
8201 | InvalidateStyleRedraw(); | |
8202 | } | |
8203 | break; | |
d134f170 | 8204 | |
9ce192d4 | 8205 | case SCI_GETMARGINMASKN: |
d134f170 | 8206 | if (ValidMargin(wParam)) |
9ce192d4 RD |
8207 | return vs.ms[wParam].mask; |
8208 | else | |
8209 | return 0; | |
d134f170 | 8210 | |
9ce192d4 | 8211 | case SCI_SETMARGINSENSITIVEN: |
f6bcfd97 | 8212 | if (ValidMargin(wParam)) { |
1a2fb4cd | 8213 | vs.ms[wParam].sensitive = lParam != 0; |
9ce192d4 RD |
8214 | InvalidateStyleRedraw(); |
8215 | } | |
8216 | break; | |
d134f170 | 8217 | |
9ce192d4 | 8218 | case SCI_GETMARGINSENSITIVEN: |
d134f170 | 8219 | if (ValidMargin(wParam)) |
9ce192d4 RD |
8220 | return vs.ms[wParam].sensitive ? 1 : 0; |
8221 | else | |
8222 | return 0; | |
8223 | ||
1dcf666d RD |
8224 | case SCI_SETMARGINCURSORN: |
8225 | if (ValidMargin(wParam)) | |
8226 | vs.ms[wParam].cursor = lParam; | |
8227 | break; | |
8228 | ||
8229 | case SCI_GETMARGINCURSORN: | |
8230 | if (ValidMargin(wParam)) | |
8231 | return vs.ms[wParam].cursor; | |
8232 | else | |
8233 | return 0; | |
8234 | ||
9ce192d4 RD |
8235 | case SCI_STYLECLEARALL: |
8236 | vs.ClearStyles(); | |
8237 | InvalidateStyleRedraw(); | |
8238 | break; | |
8239 | ||
8240 | case SCI_STYLESETFORE: | |
9ce192d4 | 8241 | case SCI_STYLESETBACK: |
9ce192d4 | 8242 | case SCI_STYLESETBOLD: |
1dcf666d | 8243 | case SCI_STYLESETWEIGHT: |
9ce192d4 | 8244 | case SCI_STYLESETITALIC: |
9ce192d4 | 8245 | case SCI_STYLESETEOLFILLED: |
9ce192d4 | 8246 | case SCI_STYLESETSIZE: |
1dcf666d | 8247 | case SCI_STYLESETSIZEFRACTIONAL: |
9ce192d4 | 8248 | case SCI_STYLESETFONT: |
f6bcfd97 | 8249 | case SCI_STYLESETUNDERLINE: |
65ec6247 | 8250 | case SCI_STYLESETCASE: |
f6bcfd97 | 8251 | case SCI_STYLESETCHARACTERSET: |
d134f170 | 8252 | case SCI_STYLESETVISIBLE: |
1a2fb4cd | 8253 | case SCI_STYLESETCHANGEABLE: |
9e730a78 | 8254 | case SCI_STYLESETHOTSPOT: |
7e0c58e9 RD |
8255 | StyleSetMessage(iMessage, wParam, lParam); |
8256 | break; | |
8257 | ||
8258 | case SCI_STYLEGETFORE: | |
8259 | case SCI_STYLEGETBACK: | |
8260 | case SCI_STYLEGETBOLD: | |
1dcf666d | 8261 | case SCI_STYLEGETWEIGHT: |
7e0c58e9 RD |
8262 | case SCI_STYLEGETITALIC: |
8263 | case SCI_STYLEGETEOLFILLED: | |
8264 | case SCI_STYLEGETSIZE: | |
1dcf666d | 8265 | case SCI_STYLEGETSIZEFRACTIONAL: |
7e0c58e9 RD |
8266 | case SCI_STYLEGETFONT: |
8267 | case SCI_STYLEGETUNDERLINE: | |
8268 | case SCI_STYLEGETCASE: | |
8269 | case SCI_STYLEGETCHARACTERSET: | |
8270 | case SCI_STYLEGETVISIBLE: | |
8271 | case SCI_STYLEGETCHANGEABLE: | |
8272 | case SCI_STYLEGETHOTSPOT: | |
8273 | return StyleGetMessage(iMessage, wParam, lParam); | |
d134f170 | 8274 | |
9ce192d4 RD |
8275 | case SCI_STYLERESETDEFAULT: |
8276 | vs.ResetDefaultStyle(); | |
8277 | InvalidateStyleRedraw(); | |
8278 | break; | |
9ce192d4 | 8279 | case SCI_SETSTYLEBITS: |
7e0c58e9 | 8280 | vs.EnsureStyle((1 << wParam) - 1); |
9ce192d4 RD |
8281 | pdoc->SetStylingBits(wParam); |
8282 | break; | |
d134f170 | 8283 | |
9ce192d4 RD |
8284 | case SCI_GETSTYLEBITS: |
8285 | return pdoc->stylingBits; | |
d134f170 | 8286 | |
9ce192d4 RD |
8287 | case SCI_SETLINESTATE: |
8288 | return pdoc->SetLineState(wParam, lParam); | |
d134f170 | 8289 | |
9ce192d4 RD |
8290 | case SCI_GETLINESTATE: |
8291 | return pdoc->GetLineState(wParam); | |
d134f170 | 8292 | |
9ce192d4 RD |
8293 | case SCI_GETMAXLINESTATE: |
8294 | return pdoc->GetMaxLineState(); | |
d134f170 | 8295 | |
65ec6247 RD |
8296 | case SCI_GETCARETLINEVISIBLE: |
8297 | return vs.showCaretLineBackground; | |
8298 | case SCI_SETCARETLINEVISIBLE: | |
1a2fb4cd | 8299 | vs.showCaretLineBackground = wParam != 0; |
65ec6247 RD |
8300 | InvalidateStyleRedraw(); |
8301 | break; | |
8302 | case SCI_GETCARETLINEBACK: | |
1dcf666d | 8303 | return vs.caretLineBackground.AsLong(); |
65ec6247 | 8304 | case SCI_SETCARETLINEBACK: |
1dcf666d | 8305 | vs.caretLineBackground = wParam; |
65ec6247 RD |
8306 | InvalidateStyleRedraw(); |
8307 | break; | |
b8193d80 RD |
8308 | case SCI_GETCARETLINEBACKALPHA: |
8309 | return vs.caretLineAlpha; | |
8310 | case SCI_SETCARETLINEBACKALPHA: | |
8311 | vs.caretLineAlpha = wParam; | |
8312 | InvalidateStyleRedraw(); | |
8313 | break; | |
65ec6247 | 8314 | |
d134f170 RD |
8315 | // Folding messages |
8316 | ||
9ce192d4 RD |
8317 | case SCI_VISIBLEFROMDOCLINE: |
8318 | return cs.DisplayFromDoc(wParam); | |
d134f170 | 8319 | |
9ce192d4 RD |
8320 | case SCI_DOCLINEFROMVISIBLE: |
8321 | return cs.DocFromDisplay(wParam); | |
8322 | ||
1e9bafca RD |
8323 | case SCI_WRAPCOUNT: |
8324 | return WrapCount(wParam); | |
8325 | ||
9ce192d4 RD |
8326 | case SCI_SETFOLDLEVEL: { |
8327 | int prev = pdoc->SetLevel(wParam, lParam); | |
8328 | if (prev != lParam) | |
8329 | RedrawSelMargin(); | |
8330 | return prev; | |
8331 | } | |
d134f170 | 8332 | |
9ce192d4 RD |
8333 | case SCI_GETFOLDLEVEL: |
8334 | return pdoc->GetLevel(wParam); | |
d134f170 | 8335 | |
9ce192d4 RD |
8336 | case SCI_GETLASTCHILD: |
8337 | return pdoc->GetLastChild(wParam, lParam); | |
d134f170 | 8338 | |
9ce192d4 RD |
8339 | case SCI_GETFOLDPARENT: |
8340 | return pdoc->GetFoldParent(wParam); | |
d134f170 | 8341 | |
9ce192d4 RD |
8342 | case SCI_SHOWLINES: |
8343 | cs.SetVisible(wParam, lParam, true); | |
8344 | SetScrollBars(); | |
8345 | Redraw(); | |
8346 | break; | |
d134f170 | 8347 | |
9ce192d4 | 8348 | case SCI_HIDELINES: |
9e96e16f RD |
8349 | if (wParam > 0) |
8350 | cs.SetVisible(wParam, lParam, false); | |
9ce192d4 RD |
8351 | SetScrollBars(); |
8352 | Redraw(); | |
8353 | break; | |
d134f170 | 8354 | |
9ce192d4 RD |
8355 | case SCI_GETLINEVISIBLE: |
8356 | return cs.GetVisible(wParam); | |
d134f170 | 8357 | |
1dcf666d RD |
8358 | case SCI_GETALLLINESVISIBLE: |
8359 | return cs.HiddenLines() ? 0 : 1; | |
8360 | ||
9ce192d4 | 8361 | case SCI_SETFOLDEXPANDED: |
1a2fb4cd | 8362 | if (cs.SetExpanded(wParam, lParam != 0)) { |
9ce192d4 RD |
8363 | RedrawSelMargin(); |
8364 | } | |
8365 | break; | |
d134f170 | 8366 | |
9ce192d4 RD |
8367 | case SCI_GETFOLDEXPANDED: |
8368 | return cs.GetExpanded(wParam); | |
d134f170 | 8369 | |
9ce192d4 RD |
8370 | case SCI_SETFOLDFLAGS: |
8371 | foldFlags = wParam; | |
8372 | Redraw(); | |
8373 | break; | |
8374 | ||
8375 | case SCI_TOGGLEFOLD: | |
8376 | ToggleContraction(wParam); | |
8377 | break; | |
d134f170 | 8378 | |
1dcf666d RD |
8379 | case SCI_CONTRACTEDFOLDNEXT: |
8380 | return ContractedFoldNext(wParam); | |
8381 | ||
9ce192d4 | 8382 | case SCI_ENSUREVISIBLE: |
65ec6247 RD |
8383 | EnsureLineVisible(wParam, false); |
8384 | break; | |
8385 | ||
8386 | case SCI_ENSUREVISIBLEENFORCEPOLICY: | |
8387 | EnsureLineVisible(wParam, true); | |
9ce192d4 | 8388 | break; |
d134f170 | 8389 | |
9ce192d4 RD |
8390 | case SCI_SEARCHANCHOR: |
8391 | SearchAnchor(); | |
8392 | break; | |
8393 | ||
8394 | case SCI_SEARCHNEXT: | |
8395 | case SCI_SEARCHPREV: | |
8396 | return SearchText(iMessage, wParam, lParam); | |
9ce192d4 | 8397 | |
a834585d RD |
8398 | case SCI_SETXCARETPOLICY: |
8399 | caretXPolicy = wParam; | |
8400 | caretXSlop = lParam; | |
8401 | break; | |
8402 | ||
8403 | case SCI_SETYCARETPOLICY: | |
8404 | caretYPolicy = wParam; | |
8405 | caretYSlop = lParam; | |
9ce192d4 RD |
8406 | break; |
8407 | ||
65ec6247 RD |
8408 | case SCI_SETVISIBLEPOLICY: |
8409 | visiblePolicy = wParam; | |
8410 | visibleSlop = lParam; | |
8411 | break; | |
8412 | ||
f6bcfd97 BP |
8413 | case SCI_LINESONSCREEN: |
8414 | return LinesOnScreen(); | |
8415 | ||
9ce192d4 | 8416 | case SCI_SETSELFORE: |
1a2fb4cd | 8417 | vs.selforeset = wParam != 0; |
1dcf666d RD |
8418 | vs.selforeground = ColourDesired(lParam); |
8419 | vs.selAdditionalForeground = ColourDesired(lParam); | |
9ce192d4 RD |
8420 | InvalidateStyleRedraw(); |
8421 | break; | |
8422 | ||
8423 | case SCI_SETSELBACK: | |
1a2fb4cd | 8424 | vs.selbackset = wParam != 0; |
1dcf666d RD |
8425 | vs.selbackground = ColourDesired(lParam); |
8426 | vs.selAdditionalBackground = ColourDesired(lParam); | |
9ce192d4 RD |
8427 | InvalidateStyleRedraw(); |
8428 | break; | |
8429 | ||
b8193d80 RD |
8430 | case SCI_SETSELALPHA: |
8431 | vs.selAlpha = wParam; | |
9e96e16f | 8432 | vs.selAdditionalAlpha = wParam; |
b8193d80 RD |
8433 | InvalidateStyleRedraw(); |
8434 | break; | |
8435 | ||
8436 | case SCI_GETSELALPHA: | |
8437 | return vs.selAlpha; | |
8438 | ||
7e0c58e9 RD |
8439 | case SCI_GETSELEOLFILLED: |
8440 | return vs.selEOLFilled; | |
8441 | ||
8442 | case SCI_SETSELEOLFILLED: | |
8443 | vs.selEOLFilled = wParam != 0; | |
8444 | InvalidateStyleRedraw(); | |
8445 | break; | |
8446 | ||
f114b858 RD |
8447 | case SCI_SETWHITESPACEFORE: |
8448 | vs.whitespaceForegroundSet = wParam != 0; | |
1dcf666d | 8449 | vs.whitespaceForeground = ColourDesired(lParam); |
f114b858 RD |
8450 | InvalidateStyleRedraw(); |
8451 | break; | |
8452 | ||
8453 | case SCI_SETWHITESPACEBACK: | |
8454 | vs.whitespaceBackgroundSet = wParam != 0; | |
1dcf666d | 8455 | vs.whitespaceBackground = ColourDesired(lParam); |
f114b858 RD |
8456 | InvalidateStyleRedraw(); |
8457 | break; | |
8458 | ||
9ce192d4 | 8459 | case SCI_SETCARETFORE: |
1dcf666d | 8460 | vs.caretcolour = ColourDesired(wParam); |
9ce192d4 RD |
8461 | InvalidateStyleRedraw(); |
8462 | break; | |
8463 | ||
d134f170 | 8464 | case SCI_GETCARETFORE: |
1dcf666d | 8465 | return vs.caretcolour.AsLong(); |
d134f170 | 8466 | |
7e0c58e9 | 8467 | case SCI_SETCARETSTYLE: |
1dcf666d | 8468 | if (wParam <= CARETSTYLE_BLOCK) |
7e0c58e9 RD |
8469 | vs.caretStyle = wParam; |
8470 | else | |
8471 | /* Default to the line caret */ | |
8472 | vs.caretStyle = CARETSTYLE_LINE; | |
8473 | InvalidateStyleRedraw(); | |
8474 | break; | |
8475 | ||
8476 | case SCI_GETCARETSTYLE: | |
8477 | return vs.caretStyle; | |
8478 | ||
65ec6247 | 8479 | case SCI_SETCARETWIDTH: |
1dcf666d | 8480 | if (static_cast<int>(wParam) <= 0) |
9e730a78 | 8481 | vs.caretWidth = 0; |
65ec6247 RD |
8482 | else if (wParam >= 3) |
8483 | vs.caretWidth = 3; | |
8484 | else | |
8485 | vs.caretWidth = wParam; | |
8486 | InvalidateStyleRedraw(); | |
8487 | break; | |
8488 | ||
8489 | case SCI_GETCARETWIDTH: | |
8490 | return vs.caretWidth; | |
8491 | ||
9ce192d4 | 8492 | case SCI_ASSIGNCMDKEY: |
d134f170 | 8493 | kmap.AssignCmdKey(Platform::LowShortFromLong(wParam), |
7e0c58e9 | 8494 | Platform::HighShortFromLong(wParam), lParam); |
9ce192d4 RD |
8495 | break; |
8496 | ||
8497 | case SCI_CLEARCMDKEY: | |
d134f170 | 8498 | kmap.AssignCmdKey(Platform::LowShortFromLong(wParam), |
7e0c58e9 | 8499 | Platform::HighShortFromLong(wParam), SCI_NULL); |
9ce192d4 RD |
8500 | break; |
8501 | ||
8502 | case SCI_CLEARALLCMDKEYS: | |
8503 | kmap.Clear(); | |
8504 | break; | |
8505 | ||
8506 | case SCI_INDICSETSTYLE: | |
8507 | if (wParam <= INDIC_MAX) { | |
8508 | vs.indicators[wParam].style = lParam; | |
8509 | InvalidateStyleRedraw(); | |
8510 | } | |
8511 | break; | |
8512 | ||
8513 | case SCI_INDICGETSTYLE: | |
8514 | return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0; | |
8515 | ||
8516 | case SCI_INDICSETFORE: | |
8517 | if (wParam <= INDIC_MAX) { | |
1dcf666d | 8518 | vs.indicators[wParam].fore = ColourDesired(lParam); |
9ce192d4 RD |
8519 | InvalidateStyleRedraw(); |
8520 | } | |
8521 | break; | |
8522 | ||
8523 | case SCI_INDICGETFORE: | |
1dcf666d | 8524 | return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.AsLong() : 0; |
9ce192d4 | 8525 | |
7e0c58e9 RD |
8526 | case SCI_INDICSETUNDER: |
8527 | if (wParam <= INDIC_MAX) { | |
8528 | vs.indicators[wParam].under = lParam != 0; | |
8529 | InvalidateStyleRedraw(); | |
8530 | } | |
8531 | break; | |
8532 | ||
8533 | case SCI_INDICGETUNDER: | |
8534 | return (wParam <= INDIC_MAX) ? vs.indicators[wParam].under : 0; | |
8535 | ||
9e96e16f | 8536 | case SCI_INDICSETALPHA: |
1dcf666d | 8537 | if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 255) { |
9e96e16f RD |
8538 | vs.indicators[wParam].fillAlpha = lParam; |
8539 | InvalidateStyleRedraw(); | |
8540 | } | |
8541 | break; | |
8542 | ||
8543 | case SCI_INDICGETALPHA: | |
8544 | return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fillAlpha : 0; | |
8545 | ||
1dcf666d RD |
8546 | case SCI_INDICSETOUTLINEALPHA: |
8547 | if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 255) { | |
8548 | vs.indicators[wParam].outlineAlpha = lParam; | |
8549 | InvalidateStyleRedraw(); | |
8550 | } | |
8551 | break; | |
8552 | ||
8553 | case SCI_INDICGETOUTLINEALPHA: | |
8554 | return (wParam <= INDIC_MAX) ? vs.indicators[wParam].outlineAlpha : 0; | |
8555 | ||
7e0c58e9 RD |
8556 | case SCI_SETINDICATORCURRENT: |
8557 | pdoc->decorations.SetCurrentIndicator(wParam); | |
8558 | break; | |
8559 | case SCI_GETINDICATORCURRENT: | |
8560 | return pdoc->decorations.GetCurrentIndicator(); | |
8561 | case SCI_SETINDICATORVALUE: | |
8562 | pdoc->decorations.SetCurrentValue(wParam); | |
8563 | break; | |
8564 | case SCI_GETINDICATORVALUE: | |
8565 | return pdoc->decorations.GetCurrentValue(); | |
8566 | ||
8567 | case SCI_INDICATORFILLRANGE: | |
8568 | pdoc->DecorationFillRange(wParam, pdoc->decorations.GetCurrentValue(), lParam); | |
8569 | break; | |
8570 | ||
8571 | case SCI_INDICATORCLEARRANGE: | |
8572 | pdoc->DecorationFillRange(wParam, 0, lParam); | |
8573 | break; | |
8574 | ||
8575 | case SCI_INDICATORALLONFOR: | |
8576 | return pdoc->decorations.AllOnFor(wParam); | |
8577 | ||
8578 | case SCI_INDICATORVALUEAT: | |
8579 | return pdoc->decorations.ValueAt(wParam, lParam); | |
8580 | ||
8581 | case SCI_INDICATORSTART: | |
8582 | return pdoc->decorations.Start(wParam, lParam); | |
8583 | ||
8584 | case SCI_INDICATOREND: | |
8585 | return pdoc->decorations.End(wParam, lParam); | |
8586 | ||
9ce192d4 RD |
8587 | case SCI_LINEDOWN: |
8588 | case SCI_LINEDOWNEXTEND: | |
9e730a78 RD |
8589 | case SCI_PARADOWN: |
8590 | case SCI_PARADOWNEXTEND: | |
9ce192d4 RD |
8591 | case SCI_LINEUP: |
8592 | case SCI_LINEUPEXTEND: | |
9e730a78 RD |
8593 | case SCI_PARAUP: |
8594 | case SCI_PARAUPEXTEND: | |
9ce192d4 RD |
8595 | case SCI_CHARLEFT: |
8596 | case SCI_CHARLEFTEXTEND: | |
8597 | case SCI_CHARRIGHT: | |
8598 | case SCI_CHARRIGHTEXTEND: | |
8599 | case SCI_WORDLEFT: | |
8600 | case SCI_WORDLEFTEXTEND: | |
8601 | case SCI_WORDRIGHT: | |
8602 | case SCI_WORDRIGHTEXTEND: | |
8e54aaed RD |
8603 | case SCI_WORDLEFTEND: |
8604 | case SCI_WORDLEFTENDEXTEND: | |
8605 | case SCI_WORDRIGHTEND: | |
8606 | case SCI_WORDRIGHTENDEXTEND: | |
9ce192d4 RD |
8607 | case SCI_HOME: |
8608 | case SCI_HOMEEXTEND: | |
8609 | case SCI_LINEEND: | |
8610 | case SCI_LINEENDEXTEND: | |
9e730a78 RD |
8611 | case SCI_HOMEWRAP: |
8612 | case SCI_HOMEWRAPEXTEND: | |
8613 | case SCI_LINEENDWRAP: | |
8614 | case SCI_LINEENDWRAPEXTEND: | |
9ce192d4 RD |
8615 | case SCI_DOCUMENTSTART: |
8616 | case SCI_DOCUMENTSTARTEXTEND: | |
8617 | case SCI_DOCUMENTEND: | |
8618 | case SCI_DOCUMENTENDEXTEND: | |
1dcf666d RD |
8619 | case SCI_SCROLLTOSTART: |
8620 | case SCI_SCROLLTOEND: | |
8e54aaed RD |
8621 | |
8622 | case SCI_STUTTEREDPAGEUP: | |
8623 | case SCI_STUTTEREDPAGEUPEXTEND: | |
8624 | case SCI_STUTTEREDPAGEDOWN: | |
8625 | case SCI_STUTTEREDPAGEDOWNEXTEND: | |
8626 | ||
9ce192d4 RD |
8627 | case SCI_PAGEUP: |
8628 | case SCI_PAGEUPEXTEND: | |
8629 | case SCI_PAGEDOWN: | |
8630 | case SCI_PAGEDOWNEXTEND: | |
8631 | case SCI_EDITTOGGLEOVERTYPE: | |
8632 | case SCI_CANCEL: | |
8633 | case SCI_DELETEBACK: | |
8634 | case SCI_TAB: | |
8635 | case SCI_BACKTAB: | |
8636 | case SCI_NEWLINE: | |
8637 | case SCI_FORMFEED: | |
8638 | case SCI_VCHOME: | |
8639 | case SCI_VCHOMEEXTEND: | |
9e730a78 RD |
8640 | case SCI_VCHOMEWRAP: |
8641 | case SCI_VCHOMEWRAPEXTEND: | |
9ce192d4 RD |
8642 | case SCI_ZOOMIN: |
8643 | case SCI_ZOOMOUT: | |
8644 | case SCI_DELWORDLEFT: | |
8645 | case SCI_DELWORDRIGHT: | |
7e0c58e9 | 8646 | case SCI_DELWORDRIGHTEND: |
65ec6247 RD |
8647 | case SCI_DELLINELEFT: |
8648 | case SCI_DELLINERIGHT: | |
e14d10b0 | 8649 | case SCI_LINECOPY: |
f6bcfd97 BP |
8650 | case SCI_LINECUT: |
8651 | case SCI_LINEDELETE: | |
8652 | case SCI_LINETRANSPOSE: | |
9e730a78 | 8653 | case SCI_LINEDUPLICATE: |
f6bcfd97 BP |
8654 | case SCI_LOWERCASE: |
8655 | case SCI_UPPERCASE: | |
8656 | case SCI_LINESCROLLDOWN: | |
8657 | case SCI_LINESCROLLUP: | |
65ec6247 RD |
8658 | case SCI_WORDPARTLEFT: |
8659 | case SCI_WORDPARTLEFTEXTEND: | |
8660 | case SCI_WORDPARTRIGHT: | |
8661 | case SCI_WORDPARTRIGHTEXTEND: | |
1a2fb4cd | 8662 | case SCI_DELETEBACKNOTLINE: |
f114b858 RD |
8663 | case SCI_HOMEDISPLAY: |
8664 | case SCI_HOMEDISPLAYEXTEND: | |
8665 | case SCI_LINEENDDISPLAY: | |
8666 | case SCI_LINEENDDISPLAYEXTEND: | |
8e54aaed RD |
8667 | case SCI_LINEDOWNRECTEXTEND: |
8668 | case SCI_LINEUPRECTEXTEND: | |
8669 | case SCI_CHARLEFTRECTEXTEND: | |
8670 | case SCI_CHARRIGHTRECTEXTEND: | |
8671 | case SCI_HOMERECTEXTEND: | |
8672 | case SCI_VCHOMERECTEXTEND: | |
8673 | case SCI_LINEENDRECTEXTEND: | |
8674 | case SCI_PAGEUPRECTEXTEND: | |
8675 | case SCI_PAGEDOWNRECTEXTEND: | |
1e9bafca | 8676 | case SCI_SELECTIONDUPLICATE: |
9ce192d4 RD |
8677 | return KeyCommand(iMessage); |
8678 | ||
8679 | case SCI_BRACEHIGHLIGHT: | |
8680 | SetBraceHighlight(static_cast<int>(wParam), lParam, STYLE_BRACELIGHT); | |
8681 | break; | |
d134f170 | 8682 | |
1dcf666d RD |
8683 | case SCI_BRACEHIGHLIGHTINDICATOR: |
8684 | if (lParam >= 0 && lParam <= INDIC_MAX) { | |
8685 | vs.braceHighlightIndicatorSet = wParam != 0; | |
8686 | vs.braceHighlightIndicator = lParam; | |
8687 | } | |
8688 | break; | |
8689 | ||
9ce192d4 RD |
8690 | case SCI_BRACEBADLIGHT: |
8691 | SetBraceHighlight(static_cast<int>(wParam), -1, STYLE_BRACEBAD); | |
8692 | break; | |
8693 | ||
1dcf666d RD |
8694 | case SCI_BRACEBADLIGHTINDICATOR: |
8695 | if (lParam >= 0 && lParam <= INDIC_MAX) { | |
8696 | vs.braceBadLightIndicatorSet = wParam != 0; | |
8697 | vs.braceBadLightIndicator = lParam; | |
8698 | } | |
8699 | break; | |
8700 | ||
9ce192d4 RD |
8701 | case SCI_BRACEMATCH: |
8702 | // wParam is position of char to find brace for, | |
8703 | // lParam is maximum amount of text to restyle to find it | |
1e9bafca | 8704 | return pdoc->BraceMatch(wParam, lParam); |
9ce192d4 RD |
8705 | |
8706 | case SCI_GETVIEWEOL: | |
8707 | return vs.viewEOL; | |
8708 | ||
8709 | case SCI_SETVIEWEOL: | |
1a2fb4cd | 8710 | vs.viewEOL = wParam != 0; |
a834585d | 8711 | InvalidateStyleRedraw(); |
9ce192d4 RD |
8712 | break; |
8713 | ||
f6bcfd97 BP |
8714 | case SCI_SETZOOM: |
8715 | vs.zoomLevel = wParam; | |
8716 | InvalidateStyleRedraw(); | |
a834585d | 8717 | NotifyZoom(); |
f6bcfd97 BP |
8718 | break; |
8719 | ||
8720 | case SCI_GETZOOM: | |
8721 | return vs.zoomLevel; | |
d134f170 | 8722 | |
9ce192d4 RD |
8723 | case SCI_GETEDGECOLUMN: |
8724 | return theEdge; | |
d134f170 | 8725 | |
9ce192d4 RD |
8726 | case SCI_SETEDGECOLUMN: |
8727 | theEdge = wParam; | |
8728 | InvalidateStyleRedraw(); | |
8729 | break; | |
d134f170 | 8730 | |
9ce192d4 | 8731 | case SCI_GETEDGEMODE: |
d134f170 RD |
8732 | return vs.edgeState; |
8733 | ||
9ce192d4 | 8734 | case SCI_SETEDGEMODE: |
d134f170 | 8735 | vs.edgeState = wParam; |
9ce192d4 RD |
8736 | InvalidateStyleRedraw(); |
8737 | break; | |
d134f170 | 8738 | |
9ce192d4 | 8739 | case SCI_GETEDGECOLOUR: |
1dcf666d | 8740 | return vs.edgecolour.AsLong(); |
d134f170 | 8741 | |
9ce192d4 | 8742 | case SCI_SETEDGECOLOUR: |
1dcf666d | 8743 | vs.edgecolour = ColourDesired(wParam); |
9ce192d4 RD |
8744 | InvalidateStyleRedraw(); |
8745 | break; | |
d134f170 | 8746 | |
9ce192d4 | 8747 | case SCI_GETDOCPOINTER: |
1a2fb4cd | 8748 | return reinterpret_cast<sptr_t>(pdoc); |
9ce192d4 RD |
8749 | |
8750 | case SCI_SETDOCPOINTER: | |
9e730a78 | 8751 | CancelModes(); |
9ce192d4 RD |
8752 | SetDocPointer(reinterpret_cast<Document *>(lParam)); |
8753 | return 0; | |
8754 | ||
d134f170 RD |
8755 | case SCI_CREATEDOCUMENT: { |
8756 | Document *doc = new Document(); | |
9e730a78 RD |
8757 | if (doc) { |
8758 | doc->AddRef(); | |
8759 | } | |
1a2fb4cd | 8760 | return reinterpret_cast<sptr_t>(doc); |
d134f170 RD |
8761 | } |
8762 | ||
8763 | case SCI_ADDREFDOCUMENT: | |
f6bcfd97 BP |
8764 | (reinterpret_cast<Document *>(lParam))->AddRef(); |
8765 | break; | |
d134f170 RD |
8766 | |
8767 | case SCI_RELEASEDOCUMENT: | |
f6bcfd97 BP |
8768 | (reinterpret_cast<Document *>(lParam))->Release(); |
8769 | break; | |
d134f170 | 8770 | |
1dcf666d RD |
8771 | case SCI_CREATELOADER: { |
8772 | Document *doc = new Document(); | |
8773 | if (doc) { | |
8774 | doc->AddRef(); | |
8775 | doc->Allocate(wParam); | |
8776 | doc->SetUndoCollection(false); | |
8777 | } | |
8778 | return reinterpret_cast<sptr_t>(static_cast<ILoader *>(doc)); | |
8779 | } | |
8780 | ||
9ce192d4 RD |
8781 | case SCI_SETMODEVENTMASK: |
8782 | modEventMask = wParam; | |
8783 | return 0; | |
d134f170 RD |
8784 | |
8785 | case SCI_GETMODEVENTMASK: | |
8786 | return modEventMask; | |
8787 | ||
9ce192d4 RD |
8788 | case SCI_CONVERTEOLS: |
8789 | pdoc->ConvertLineEnds(wParam); | |
9e96e16f | 8790 | SetSelection(sel.MainCaret(), sel.MainAnchor()); // Ensure selection inside document |
9ce192d4 RD |
8791 | return 0; |
8792 | ||
a33203cb RD |
8793 | case SCI_SETLENGTHFORENCODE: |
8794 | lengthForEncode = wParam; | |
8795 | return 0; | |
8796 | ||
f6bcfd97 | 8797 | case SCI_SELECTIONISRECTANGLE: |
9e96e16f | 8798 | return sel.selType == Selection::selRectangle ? 1 : 0; |
8e54aaed RD |
8799 | |
8800 | case SCI_SETSELECTIONMODE: { | |
8801 | switch (wParam) { | |
8802 | case SC_SEL_STREAM: | |
9e96e16f RD |
8803 | sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream)); |
8804 | sel.selType = Selection::selStream; | |
8e54aaed RD |
8805 | break; |
8806 | case SC_SEL_RECTANGLE: | |
9e96e16f RD |
8807 | sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selRectangle)); |
8808 | sel.selType = Selection::selRectangle; | |
8e54aaed RD |
8809 | break; |
8810 | case SC_SEL_LINES: | |
9e96e16f RD |
8811 | sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selLines)); |
8812 | sel.selType = Selection::selLines; | |
8813 | break; | |
8814 | case SC_SEL_THIN: | |
8815 | sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selThin)); | |
8816 | sel.selType = Selection::selThin; | |
8e54aaed RD |
8817 | break; |
8818 | default: | |
9e96e16f RD |
8819 | sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream)); |
8820 | sel.selType = Selection::selStream; | |
8e54aaed | 8821 | } |
9e96e16f | 8822 | InvalidateSelection(sel.RangeMain(), true); |
8e54aaed RD |
8823 | } |
8824 | case SCI_GETSELECTIONMODE: | |
9e96e16f RD |
8825 | switch (sel.selType) { |
8826 | case Selection::selStream: | |
8e54aaed | 8827 | return SC_SEL_STREAM; |
9e96e16f | 8828 | case Selection::selRectangle: |
8e54aaed | 8829 | return SC_SEL_RECTANGLE; |
9e96e16f | 8830 | case Selection::selLines: |
8e54aaed | 8831 | return SC_SEL_LINES; |
9e96e16f RD |
8832 | case Selection::selThin: |
8833 | return SC_SEL_THIN; | |
8e54aaed RD |
8834 | default: // ?! |
8835 | return SC_SEL_STREAM; | |
8836 | } | |
9e96e16f | 8837 | case SCI_GETLINESELSTARTPOSITION: |
8e54aaed | 8838 | case SCI_GETLINESELENDPOSITION: { |
9e96e16f RD |
8839 | SelectionSegment segmentLine(SelectionPosition(pdoc->LineStart(wParam)), |
8840 | SelectionPosition(pdoc->LineEnd(wParam))); | |
8841 | for (size_t r=0; r<sel.Count(); r++) { | |
8842 | SelectionSegment portion = sel.Range(r).Intersect(segmentLine); | |
8843 | if (portion.start.IsValid()) { | |
8844 | return (iMessage == SCI_GETLINESELSTARTPOSITION) ? portion.start.Position() : portion.end.Position(); | |
8845 | } | |
8846 | } | |
8847 | return INVALID_POSITION; | |
8e54aaed | 8848 | } |
f6bcfd97 | 8849 | |
d134f170 | 8850 | case SCI_SETOVERTYPE: |
1a2fb4cd | 8851 | inOverstrike = wParam != 0; |
d134f170 | 8852 | break; |
ce1ecc6d | 8853 | |
d134f170 | 8854 | case SCI_GETOVERTYPE: |
1a2fb4cd | 8855 | return inOverstrike ? 1 : 0; |
ce1ecc6d | 8856 | |
65ec6247 | 8857 | case SCI_SETFOCUS: |
1a2fb4cd | 8858 | SetFocusState(wParam != 0); |
65ec6247 RD |
8859 | break; |
8860 | ||
8861 | case SCI_GETFOCUS: | |
8862 | return hasFocus; | |
8863 | ||
8864 | case SCI_SETSTATUS: | |
8865 | errorStatus = wParam; | |
8866 | break; | |
8867 | ||
8868 | case SCI_GETSTATUS: | |
8869 | return errorStatus; | |
8870 | ||
8871 | case SCI_SETMOUSEDOWNCAPTURES: | |
1a2fb4cd | 8872 | mouseDownCaptures = wParam != 0; |
65ec6247 RD |
8873 | break; |
8874 | ||
8875 | case SCI_GETMOUSEDOWNCAPTURES: | |
8876 | return mouseDownCaptures; | |
8877 | ||
8878 | case SCI_SETCURSOR: | |
8879 | cursorMode = wParam; | |
8880 | DisplayCursor(Window::cursorText); | |
8881 | break; | |
8882 | ||
8883 | case SCI_GETCURSOR: | |
8884 | return cursorMode; | |
8885 | ||
1a2fb4cd RD |
8886 | case SCI_SETCONTROLCHARSYMBOL: |
8887 | controlCharSymbol = wParam; | |
8888 | break; | |
8889 | ||
8890 | case SCI_GETCONTROLCHARSYMBOL: | |
8891 | return controlCharSymbol; | |
8892 | ||
9ce192d4 | 8893 | case SCI_STARTRECORD: |
b8b0e402 | 8894 | recordingMacro = true; |
9ce192d4 RD |
8895 | return 0; |
8896 | ||
8897 | case SCI_STOPRECORD: | |
b8b0e402 | 8898 | recordingMacro = false; |
9ce192d4 | 8899 | return 0; |
65ec6247 RD |
8900 | |
8901 | case SCI_MOVECARETINSIDEVIEW: | |
8902 | MoveCaretInsideView(); | |
8903 | break; | |
d134f170 | 8904 | |
9e730a78 RD |
8905 | case SCI_SETFOLDMARGINCOLOUR: |
8906 | vs.foldmarginColourSet = wParam != 0; | |
1dcf666d | 8907 | vs.foldmarginColour = ColourDesired(lParam); |
9e730a78 RD |
8908 | InvalidateStyleRedraw(); |
8909 | break; | |
8910 | ||
8911 | case SCI_SETFOLDMARGINHICOLOUR: | |
8912 | vs.foldmarginHighlightColourSet = wParam != 0; | |
1dcf666d | 8913 | vs.foldmarginHighlightColour = ColourDesired(lParam); |
9e730a78 RD |
8914 | InvalidateStyleRedraw(); |
8915 | break; | |
8916 | ||
8917 | case SCI_SETHOTSPOTACTIVEFORE: | |
8918 | vs.hotspotForegroundSet = wParam != 0; | |
1dcf666d | 8919 | vs.hotspotForeground = ColourDesired(lParam); |
9e730a78 RD |
8920 | InvalidateStyleRedraw(); |
8921 | break; | |
8922 | ||
7e0c58e9 | 8923 | case SCI_GETHOTSPOTACTIVEFORE: |
1dcf666d | 8924 | return vs.hotspotForeground.AsLong(); |
7e0c58e9 | 8925 | |
9e730a78 RD |
8926 | case SCI_SETHOTSPOTACTIVEBACK: |
8927 | vs.hotspotBackgroundSet = wParam != 0; | |
1dcf666d | 8928 | vs.hotspotBackground = ColourDesired(lParam); |
9e730a78 RD |
8929 | InvalidateStyleRedraw(); |
8930 | break; | |
8931 | ||
7e0c58e9 | 8932 | case SCI_GETHOTSPOTACTIVEBACK: |
1dcf666d | 8933 | return vs.hotspotBackground.AsLong(); |
7e0c58e9 | 8934 | |
9e730a78 RD |
8935 | case SCI_SETHOTSPOTACTIVEUNDERLINE: |
8936 | vs.hotspotUnderline = wParam != 0; | |
8937 | InvalidateStyleRedraw(); | |
8938 | break; | |
8939 | ||
7e0c58e9 RD |
8940 | case SCI_GETHOTSPOTACTIVEUNDERLINE: |
8941 | return vs.hotspotUnderline ? 1 : 0; | |
8942 | ||
8e54aaed RD |
8943 | case SCI_SETHOTSPOTSINGLELINE: |
8944 | vs.hotspotSingleLine = wParam != 0; | |
8945 | InvalidateStyleRedraw(); | |
8946 | break; | |
8947 | ||
7e0c58e9 RD |
8948 | case SCI_GETHOTSPOTSINGLELINE: |
8949 | return vs.hotspotSingleLine ? 1 : 0; | |
8950 | ||
1e9bafca RD |
8951 | case SCI_SETPASTECONVERTENDINGS: |
8952 | convertPastes = wParam != 0; | |
8953 | break; | |
8954 | ||
8955 | case SCI_GETPASTECONVERTENDINGS: | |
8956 | return convertPastes ? 1 : 0; | |
8957 | ||
9e96e16f RD |
8958 | case SCI_GETCHARACTERPOINTER: |
8959 | return reinterpret_cast<sptr_t>(pdoc->BufferPointer()); | |
8960 | ||
1dcf666d RD |
8961 | case SCI_GETRANGEPOINTER: |
8962 | return reinterpret_cast<sptr_t>(pdoc->RangePointer(wParam, lParam)); | |
8963 | ||
8964 | case SCI_GETGAPPOSITION: | |
8965 | return pdoc->GapPosition(); | |
8966 | ||
9e96e16f RD |
8967 | case SCI_SETEXTRAASCENT: |
8968 | vs.extraAscent = wParam; | |
8969 | InvalidateStyleRedraw(); | |
8970 | break; | |
8971 | ||
8972 | case SCI_GETEXTRAASCENT: | |
8973 | return vs.extraAscent; | |
8974 | ||
8975 | case SCI_SETEXTRADESCENT: | |
8976 | vs.extraDescent = wParam; | |
8977 | InvalidateStyleRedraw(); | |
8978 | break; | |
8979 | ||
8980 | case SCI_GETEXTRADESCENT: | |
8981 | return vs.extraDescent; | |
8982 | ||
8983 | case SCI_MARGINSETSTYLEOFFSET: | |
8984 | vs.marginStyleOffset = wParam; | |
8985 | InvalidateStyleRedraw(); | |
8986 | break; | |
8987 | ||
8988 | case SCI_MARGINGETSTYLEOFFSET: | |
8989 | return vs.marginStyleOffset; | |
8990 | ||
1dcf666d RD |
8991 | case SCI_SETMARGINOPTIONS: |
8992 | marginOptions = wParam; | |
8993 | break; | |
8994 | ||
8995 | case SCI_GETMARGINOPTIONS: | |
8996 | return marginOptions; | |
8997 | ||
9e96e16f RD |
8998 | case SCI_MARGINSETTEXT: |
8999 | pdoc->MarginSetText(wParam, CharPtrFromSPtr(lParam)); | |
9000 | break; | |
9001 | ||
9002 | case SCI_MARGINGETTEXT: { | |
9003 | const StyledText st = pdoc->MarginStyledText(wParam); | |
9004 | if (lParam) { | |
9005 | if (st.text) | |
9006 | memcpy(CharPtrFromSPtr(lParam), st.text, st.length); | |
9007 | else | |
9008 | strcpy(CharPtrFromSPtr(lParam), ""); | |
9009 | } | |
9010 | return st.length; | |
9011 | } | |
9012 | ||
9013 | case SCI_MARGINSETSTYLE: | |
9014 | pdoc->MarginSetStyle(wParam, lParam); | |
9015 | break; | |
9016 | ||
9017 | case SCI_MARGINGETSTYLE: { | |
9018 | const StyledText st = pdoc->MarginStyledText(wParam); | |
9019 | return st.style; | |
9020 | } | |
9021 | ||
9022 | case SCI_MARGINSETSTYLES: | |
9023 | pdoc->MarginSetStyles(wParam, reinterpret_cast<const unsigned char *>(lParam)); | |
9024 | break; | |
9025 | ||
9026 | case SCI_MARGINGETSTYLES: { | |
9027 | const StyledText st = pdoc->MarginStyledText(wParam); | |
9028 | if (lParam) { | |
9029 | if (st.styles) | |
9030 | memcpy(CharPtrFromSPtr(lParam), st.styles, st.length); | |
9031 | else | |
9032 | strcpy(CharPtrFromSPtr(lParam), ""); | |
9033 | } | |
9034 | return st.styles ? st.length : 0; | |
9035 | } | |
9036 | ||
9037 | case SCI_MARGINTEXTCLEARALL: | |
9038 | pdoc->MarginClearAll(); | |
9039 | break; | |
9040 | ||
9041 | case SCI_ANNOTATIONSETTEXT: | |
9042 | pdoc->AnnotationSetText(wParam, CharPtrFromSPtr(lParam)); | |
9043 | break; | |
9044 | ||
9045 | case SCI_ANNOTATIONGETTEXT: { | |
9046 | const StyledText st = pdoc->AnnotationStyledText(wParam); | |
9047 | if (lParam) { | |
9048 | if (st.text) | |
9049 | memcpy(CharPtrFromSPtr(lParam), st.text, st.length); | |
9050 | else | |
9051 | strcpy(CharPtrFromSPtr(lParam), ""); | |
9052 | } | |
9053 | return st.length; | |
9054 | } | |
9055 | ||
9056 | case SCI_ANNOTATIONGETSTYLE: { | |
9057 | const StyledText st = pdoc->AnnotationStyledText(wParam); | |
9058 | return st.style; | |
9059 | } | |
9060 | ||
9061 | case SCI_ANNOTATIONSETSTYLE: | |
9062 | pdoc->AnnotationSetStyle(wParam, lParam); | |
9063 | break; | |
9064 | ||
9065 | case SCI_ANNOTATIONSETSTYLES: | |
9066 | pdoc->AnnotationSetStyles(wParam, reinterpret_cast<const unsigned char *>(lParam)); | |
9067 | break; | |
9068 | ||
9069 | case SCI_ANNOTATIONGETSTYLES: { | |
9070 | const StyledText st = pdoc->AnnotationStyledText(wParam); | |
9071 | if (lParam) { | |
9072 | if (st.styles) | |
9073 | memcpy(CharPtrFromSPtr(lParam), st.styles, st.length); | |
9074 | else | |
9075 | strcpy(CharPtrFromSPtr(lParam), ""); | |
9076 | } | |
9077 | return st.styles ? st.length : 0; | |
9078 | } | |
9079 | ||
9080 | case SCI_ANNOTATIONGETLINES: | |
9081 | return pdoc->AnnotationLines(wParam); | |
9082 | ||
9083 | case SCI_ANNOTATIONCLEARALL: | |
9084 | pdoc->AnnotationClearAll(); | |
9085 | break; | |
9086 | ||
9087 | case SCI_ANNOTATIONSETVISIBLE: | |
9088 | SetAnnotationVisible(wParam); | |
9089 | break; | |
9090 | ||
9091 | case SCI_ANNOTATIONGETVISIBLE: | |
9092 | return vs.annotationVisible; | |
9093 | ||
9094 | case SCI_ANNOTATIONSETSTYLEOFFSET: | |
9095 | vs.annotationStyleOffset = wParam; | |
9096 | InvalidateStyleRedraw(); | |
9097 | break; | |
9098 | ||
9099 | case SCI_ANNOTATIONGETSTYLEOFFSET: | |
9100 | return vs.annotationStyleOffset; | |
9101 | ||
9102 | case SCI_ADDUNDOACTION: | |
9103 | pdoc->AddUndoAction(wParam, lParam & UNDO_MAY_COALESCE); | |
9104 | break; | |
9105 | ||
9106 | case SCI_SETMULTIPLESELECTION: | |
9107 | multipleSelection = wParam != 0; | |
9108 | InvalidateCaret(); | |
9109 | break; | |
9110 | ||
9111 | case SCI_GETMULTIPLESELECTION: | |
9112 | return multipleSelection; | |
9113 | ||
9114 | case SCI_SETADDITIONALSELECTIONTYPING: | |
9115 | additionalSelectionTyping = wParam != 0; | |
9116 | InvalidateCaret(); | |
9117 | break; | |
9118 | ||
9119 | case SCI_GETADDITIONALSELECTIONTYPING: | |
9120 | return additionalSelectionTyping; | |
9121 | ||
1dcf666d RD |
9122 | case SCI_SETMULTIPASTE: |
9123 | multiPasteMode = wParam; | |
9124 | break; | |
9125 | ||
9126 | case SCI_GETMULTIPASTE: | |
9127 | return multiPasteMode; | |
9128 | ||
9e96e16f RD |
9129 | case SCI_SETADDITIONALCARETSBLINK: |
9130 | additionalCaretsBlink = wParam != 0; | |
9131 | InvalidateCaret(); | |
9132 | break; | |
9133 | ||
9134 | case SCI_GETADDITIONALCARETSBLINK: | |
9135 | return additionalCaretsBlink; | |
9136 | ||
9137 | case SCI_SETADDITIONALCARETSVISIBLE: | |
9138 | additionalCaretsVisible = wParam != 0; | |
9139 | InvalidateCaret(); | |
9140 | break; | |
9141 | ||
9142 | case SCI_GETADDITIONALCARETSVISIBLE: | |
9143 | return additionalCaretsVisible; | |
9144 | ||
9145 | case SCI_GETSELECTIONS: | |
9146 | return sel.Count(); | |
9147 | ||
9148 | case SCI_CLEARSELECTIONS: | |
9149 | sel.Clear(); | |
9150 | Redraw(); | |
9151 | break; | |
9152 | ||
9153 | case SCI_SETSELECTION: | |
9154 | sel.SetSelection(SelectionRange(wParam, lParam)); | |
9155 | Redraw(); | |
9156 | break; | |
9157 | ||
9158 | case SCI_ADDSELECTION: | |
9159 | sel.AddSelection(SelectionRange(wParam, lParam)); | |
9160 | Redraw(); | |
9161 | break; | |
9162 | ||
9163 | case SCI_SETMAINSELECTION: | |
9164 | sel.SetMain(wParam); | |
9165 | Redraw(); | |
9166 | break; | |
9167 | ||
9168 | case SCI_GETMAINSELECTION: | |
9169 | return sel.Main(); | |
9170 | ||
9171 | case SCI_SETSELECTIONNCARET: | |
9172 | sel.Range(wParam).caret.SetPosition(lParam); | |
9173 | Redraw(); | |
9174 | break; | |
9175 | ||
9176 | case SCI_GETSELECTIONNCARET: | |
9177 | return sel.Range(wParam).caret.Position(); | |
9178 | ||
9179 | case SCI_SETSELECTIONNANCHOR: | |
9180 | sel.Range(wParam).anchor.SetPosition(lParam); | |
9181 | Redraw(); | |
9182 | break; | |
9183 | case SCI_GETSELECTIONNANCHOR: | |
9184 | return sel.Range(wParam).anchor.Position(); | |
9185 | ||
9186 | case SCI_SETSELECTIONNCARETVIRTUALSPACE: | |
9187 | sel.Range(wParam).caret.SetVirtualSpace(lParam); | |
9188 | Redraw(); | |
9189 | break; | |
9190 | ||
9191 | case SCI_GETSELECTIONNCARETVIRTUALSPACE: | |
9192 | return sel.Range(wParam).caret.VirtualSpace(); | |
9193 | ||
9194 | case SCI_SETSELECTIONNANCHORVIRTUALSPACE: | |
9195 | sel.Range(wParam).anchor.SetVirtualSpace(lParam); | |
9196 | Redraw(); | |
9197 | break; | |
9198 | ||
9199 | case SCI_GETSELECTIONNANCHORVIRTUALSPACE: | |
9200 | return sel.Range(wParam).anchor.VirtualSpace(); | |
9201 | ||
9202 | case SCI_SETSELECTIONNSTART: | |
9203 | sel.Range(wParam).anchor.SetPosition(lParam); | |
9204 | Redraw(); | |
9205 | break; | |
9206 | ||
9207 | case SCI_GETSELECTIONNSTART: | |
9208 | return sel.Range(wParam).Start().Position(); | |
9209 | ||
9210 | case SCI_SETSELECTIONNEND: | |
9211 | sel.Range(wParam).caret.SetPosition(lParam); | |
9212 | Redraw(); | |
9213 | break; | |
9214 | ||
9215 | case SCI_GETSELECTIONNEND: | |
9216 | return sel.Range(wParam).End().Position(); | |
9217 | ||
9218 | case SCI_SETRECTANGULARSELECTIONCARET: | |
9219 | if (!sel.IsRectangular()) | |
9220 | sel.Clear(); | |
9221 | sel.selType = Selection::selRectangle; | |
9222 | sel.Rectangular().caret.SetPosition(wParam); | |
9223 | SetRectangularRange(); | |
9224 | Redraw(); | |
9225 | break; | |
9226 | ||
9227 | case SCI_GETRECTANGULARSELECTIONCARET: | |
9228 | return sel.Rectangular().caret.Position(); | |
9229 | ||
9230 | case SCI_SETRECTANGULARSELECTIONANCHOR: | |
9231 | if (!sel.IsRectangular()) | |
9232 | sel.Clear(); | |
9233 | sel.selType = Selection::selRectangle; | |
9234 | sel.Rectangular().anchor.SetPosition(wParam); | |
9235 | SetRectangularRange(); | |
9236 | Redraw(); | |
9237 | break; | |
9238 | ||
9239 | case SCI_GETRECTANGULARSELECTIONANCHOR: | |
9240 | return sel.Rectangular().anchor.Position(); | |
9241 | ||
9242 | case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE: | |
9243 | if (!sel.IsRectangular()) | |
9244 | sel.Clear(); | |
9245 | sel.selType = Selection::selRectangle; | |
9246 | sel.Rectangular().caret.SetVirtualSpace(wParam); | |
9247 | SetRectangularRange(); | |
9248 | Redraw(); | |
9249 | break; | |
9250 | ||
9251 | case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE: | |
9252 | return sel.Rectangular().caret.VirtualSpace(); | |
9253 | ||
9254 | case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE: | |
9255 | if (!sel.IsRectangular()) | |
9256 | sel.Clear(); | |
9257 | sel.selType = Selection::selRectangle; | |
9258 | sel.Rectangular().anchor.SetVirtualSpace(wParam); | |
9259 | SetRectangularRange(); | |
9260 | Redraw(); | |
9261 | break; | |
9262 | ||
9263 | case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE: | |
9264 | return sel.Rectangular().anchor.VirtualSpace(); | |
9265 | ||
9266 | case SCI_SETVIRTUALSPACEOPTIONS: | |
9267 | virtualSpaceOptions = wParam; | |
9268 | break; | |
9269 | ||
9270 | case SCI_GETVIRTUALSPACEOPTIONS: | |
9271 | return virtualSpaceOptions; | |
9272 | ||
9273 | case SCI_SETADDITIONALSELFORE: | |
1dcf666d | 9274 | vs.selAdditionalForeground = ColourDesired(wParam); |
9e96e16f RD |
9275 | InvalidateStyleRedraw(); |
9276 | break; | |
9277 | ||
9278 | case SCI_SETADDITIONALSELBACK: | |
1dcf666d | 9279 | vs.selAdditionalBackground = ColourDesired(wParam); |
9e96e16f RD |
9280 | InvalidateStyleRedraw(); |
9281 | break; | |
9282 | ||
9283 | case SCI_SETADDITIONALSELALPHA: | |
9284 | vs.selAdditionalAlpha = wParam; | |
9285 | InvalidateStyleRedraw(); | |
9286 | break; | |
9287 | ||
9288 | case SCI_GETADDITIONALSELALPHA: | |
9289 | return vs.selAdditionalAlpha; | |
9290 | ||
9291 | case SCI_SETADDITIONALCARETFORE: | |
1dcf666d | 9292 | vs.additionalCaretColour = ColourDesired(wParam); |
9e96e16f RD |
9293 | InvalidateStyleRedraw(); |
9294 | break; | |
9295 | ||
9296 | case SCI_GETADDITIONALCARETFORE: | |
1dcf666d | 9297 | return vs.additionalCaretColour.AsLong(); |
9e96e16f RD |
9298 | |
9299 | case SCI_ROTATESELECTION: | |
9300 | sel.RotateMain(); | |
9301 | InvalidateSelection(sel.RangeMain(), true); | |
9302 | break; | |
9303 | ||
9304 | case SCI_SWAPMAINANCHORCARET: | |
9305 | InvalidateSelection(sel.RangeMain()); | |
9306 | sel.RangeMain() = SelectionRange(sel.RangeMain().anchor, sel.RangeMain().caret); | |
9307 | break; | |
9308 | ||
1dcf666d RD |
9309 | case SCI_CHANGELEXERSTATE: |
9310 | pdoc->ChangeLexerState(wParam, lParam); | |
9311 | break; | |
9312 | ||
9313 | case SCI_SETIDENTIFIER: | |
9314 | SetCtrlID(wParam); | |
9315 | break; | |
9316 | ||
9317 | case SCI_GETIDENTIFIER: | |
9318 | return GetCtrlID(); | |
9319 | ||
9320 | case SCI_SETTECHNOLOGY: | |
9321 | // No action by default | |
9322 | break; | |
9323 | ||
9324 | case SCI_GETTECHNOLOGY: | |
9325 | return technology; | |
9326 | ||
9327 | case SCI_COUNTCHARACTERS: | |
9328 | return pdoc->CountCharacters(wParam, lParam); | |
9329 | ||
9ce192d4 RD |
9330 | default: |
9331 | return DefWndProc(iMessage, wParam, lParam); | |
9332 | } | |
9333 | //Platform::DebugPrintf("end wnd proc\n"); | |
9334 | return 0l; | |
9335 | } |