]>
Commit | Line | Data |
---|---|---|
9ce192d4 RD |
1 | // Scintilla source code edit control |
2 | // Editor.cxx - main code for the edit control | |
3 | // Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org> | |
4 | // The License.txt file describes the conditions under which this software may be distributed. | |
5 | ||
6 | #include <stdlib.h> | |
7 | #include <string.h> | |
8 | #include <stdio.h> | |
9 | #include <ctype.h> | |
10 | ||
11 | #include "Platform.h" | |
12 | ||
13 | #include "Scintilla.h" | |
d134f170 RD |
14 | |
15 | #if PLAT_WX || PLAT_GTK | |
16 | #include "WinDefs.h" | |
17 | #endif | |
18 | ||
9ce192d4 RD |
19 | #include "ContractionState.h" |
20 | #include "SVector.h" | |
21 | #include "CellBuffer.h" | |
22 | #include "KeyMap.h" | |
23 | #include "Indicator.h" | |
24 | #include "LineMarker.h" | |
25 | #include "Style.h" | |
26 | #include "ViewStyle.h" | |
27 | #include "Document.h" | |
28 | #include "Editor.h" | |
29 | ||
30 | Caret::Caret() : | |
31 | active(true), on(true), period(500) {} | |
32 | ||
33 | Timer::Timer() : | |
34 | ticking(false), ticksToWait(0), tickerID(0) {} | |
35 | ||
36 | Editor::Editor() { | |
37 | ctrlID = 0; | |
38 | ||
39 | stylesValid = false; | |
40 | ||
d134f170 RD |
41 | printMagnification = 0; |
42 | printColourMode = SC_PRINT_NORMAL; | |
43 | ||
9ce192d4 RD |
44 | hideSelection = false; |
45 | inOverstrike = false; | |
46 | ||
47 | bufferedDraw = true; | |
48 | ||
49 | lastClickTime = 0; | |
50 | ptMouseLast.x = 0; | |
51 | ptMouseLast.y = 0; | |
52 | firstExpose = true; | |
53 | inDragDrop = false; | |
54 | dropWentOutside = false; | |
55 | posDrag = invalidPosition; | |
56 | posDrop = invalidPosition; | |
57 | selectionType = selChar; | |
58 | ||
59 | lastXChosen = 0; | |
60 | lineAnchor = 0; | |
61 | originalAnchorPos = 0; | |
62 | ||
63 | dragChars = 0; | |
64 | lenDrag = 0; | |
65 | dragIsRectangle = false; | |
66 | selType = selStream; | |
67 | xStartSelect = 0; | |
68 | xEndSelect = 0; | |
d134f170 | 69 | primarySelection = true; |
9ce192d4 RD |
70 | |
71 | caretPolicy = CARET_SLOP; | |
72 | caretSlop = 0; | |
73 | ||
74 | searchAnchor = 0; | |
d134f170 | 75 | |
9ce192d4 RD |
76 | ucWheelScrollLines = 0; |
77 | cWheelDelta = 0; //wheel delta from roll | |
78 | ||
79 | xOffset = 0; | |
80 | xCaretMargin = 50; | |
f6bcfd97 | 81 | horizontalScrollBarVisible = true; |
d134f170 | 82 | |
9ce192d4 RD |
83 | currentPos = 0; |
84 | anchor = 0; | |
85 | ||
86 | topLine = 0; | |
87 | posTopLine = 0; | |
d134f170 | 88 | |
9ce192d4 | 89 | needUpdateUI = true; |
d134f170 RD |
90 | braces[0] = invalidPosition; |
91 | braces[1] = invalidPosition; | |
9ce192d4 | 92 | bracesMatchStyle = STYLE_BRACEBAD; |
d134f170 RD |
93 | highlightGuideColumn = 0; |
94 | ||
9ce192d4 | 95 | theEdge = 0; |
d134f170 | 96 | |
9ce192d4 | 97 | paintState = notPainting; |
d134f170 | 98 | |
9ce192d4 RD |
99 | modEventMask = SC_MODEVENTMASKALL; |
100 | ||
f6bcfd97 | 101 | displayPopupMenu = true; |
d134f170 | 102 | |
9ce192d4 RD |
103 | pdoc = new Document(); |
104 | pdoc ->AddRef(); | |
105 | pdoc->AddWatcher(this, 0); | |
106 | ||
107 | #ifdef MACRO_SUPPORT | |
108 | recordingMacro = 0; | |
d134f170 | 109 | #endif |
9ce192d4 RD |
110 | foldFlags = 0; |
111 | } | |
112 | ||
113 | Editor::~Editor() { | |
114 | pdoc->RemoveWatcher(this, 0); | |
115 | pdoc->Release(); | |
116 | pdoc = 0; | |
117 | DropGraphics(); | |
118 | ||
119 | delete []dragChars; | |
120 | dragChars = 0; | |
121 | lenDrag = 0; | |
122 | } | |
123 | ||
124 | void Editor::Finalise() { | |
d134f170 | 125 | CancelModes(); |
9ce192d4 RD |
126 | } |
127 | ||
128 | void Editor::DropGraphics() { | |
129 | pixmapLine.Release(); | |
130 | pixmapSelMargin.Release(); | |
131 | pixmapSelPattern.Release(); | |
d134f170 | 132 | pixmapIndentGuide.Release(); |
9ce192d4 RD |
133 | } |
134 | ||
135 | void Editor::InvalidateStyleData() { | |
136 | stylesValid = false; | |
137 | palette.Release(); | |
138 | DropGraphics(); | |
139 | } | |
140 | ||
141 | void Editor::InvalidateStyleRedraw() { | |
142 | InvalidateStyleData(); | |
143 | Redraw(); | |
144 | } | |
145 | ||
146 | void Editor::RefreshColourPalette(Palette &pal, bool want) { | |
147 | vs.RefreshColourPalette(pal, want); | |
148 | } | |
149 | ||
150 | void Editor::RefreshStyleData() { | |
151 | if (!stylesValid) { | |
152 | stylesValid = true; | |
153 | Surface surface; | |
154 | surface.Init(); | |
155 | vs.Refresh(surface); | |
156 | RefreshColourPalette(palette, true); | |
157 | palette.Allocate(wMain); | |
158 | RefreshColourPalette(palette, false); | |
159 | SetScrollBars(); | |
160 | } | |
161 | } | |
162 | ||
163 | PRectangle Editor::GetClientRectangle() { | |
164 | return wDraw.GetClientPosition(); | |
165 | } | |
166 | ||
167 | PRectangle Editor::GetTextRectangle() { | |
168 | PRectangle rc = GetClientRectangle(); | |
169 | rc.left += vs.fixedColumnWidth; | |
170 | rc.right -= vs.rightMarginWidth; | |
171 | return rc; | |
172 | } | |
173 | ||
174 | int Editor::LinesOnScreen() { | |
175 | PRectangle rcClient = GetClientRectangle(); | |
176 | int htClient = rcClient.bottom - rcClient.top; | |
177 | //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1); | |
178 | return htClient / vs.lineHeight; | |
179 | } | |
180 | ||
181 | int Editor::LinesToScroll() { | |
182 | int retVal = LinesOnScreen() - 1; | |
183 | if (retVal < 1) | |
184 | return 1; | |
185 | else | |
186 | return retVal; | |
187 | } | |
188 | ||
189 | int Editor::MaxScrollPos() { | |
190 | //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n", | |
191 | //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1); | |
192 | int retVal = cs.LinesDisplayed() - LinesOnScreen(); | |
193 | if (retVal < 0) | |
194 | return 0; | |
195 | else | |
196 | return retVal; | |
197 | } | |
198 | ||
d134f170 | 199 | static inline bool IsControlCharacter(char ch) { |
9ce192d4 RD |
200 | // iscntrl returns true for lots of chars > 127 which are displayable |
201 | return ch >= 0 && ch < ' '; | |
202 | } | |
203 | ||
f6bcfd97 | 204 | const char *ControlCharacterString(unsigned char ch) { |
9ce192d4 RD |
205 | const char *reps[] = { |
206 | "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", | |
207 | "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", | |
208 | "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", | |
209 | "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" | |
210 | }; | |
211 | if (ch < (sizeof(reps) / sizeof(reps[0]))) { | |
212 | return reps[ch]; | |
213 | } else { | |
214 | return "BAD"; | |
215 | } | |
216 | } | |
217 | ||
218 | Point Editor::LocationFromPosition(unsigned int pos) { | |
219 | RefreshStyleData(); | |
220 | int line = pdoc->LineFromPosition(pos); | |
221 | int lineVisible = cs.DisplayFromDoc(line); | |
222 | //Platform::DebugPrintf("line=%d\n", line); | |
223 | Surface surface; | |
224 | surface.Init(); | |
f6bcfd97 | 225 | surface.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); |
9ce192d4 RD |
226 | Point pt; |
227 | pt.y = (lineVisible - topLine) * vs.lineHeight; // + half a lineheight? | |
228 | unsigned int posLineStart = pdoc->LineStart(line); | |
d134f170 RD |
229 | LineLayout ll; |
230 | LayoutLine(line, &surface, vs, ll); | |
9ce192d4 RD |
231 | if ((pos - posLineStart) > LineLayout::maxLineLength) { |
232 | // very long line so put x at arbitrary large position | |
d134f170 | 233 | pt.x = ll.positions[LineLayout::maxLineLength] + vs.fixedColumnWidth - xOffset; |
9ce192d4 | 234 | } else { |
9ce192d4 RD |
235 | pt.x = ll.positions[pos - posLineStart] + vs.fixedColumnWidth - xOffset; |
236 | } | |
237 | return pt; | |
238 | } | |
239 | ||
240 | int Editor::XFromPosition(unsigned int pos) { | |
241 | Point pt = LocationFromPosition(pos); | |
242 | return pt.x - vs.fixedColumnWidth + xOffset; | |
243 | } | |
d134f170 | 244 | |
9ce192d4 RD |
245 | int Editor::LineFromLocation(Point pt) { |
246 | return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine); | |
247 | } | |
248 | ||
249 | void Editor::SetTopLine(int topLineNew) { | |
250 | topLine = topLineNew; | |
251 | posTopLine = pdoc->LineStart(topLine); | |
252 | } | |
253 | ||
254 | int Editor::PositionFromLocation(Point pt) { | |
255 | RefreshStyleData(); | |
256 | pt.x = pt.x - vs.fixedColumnWidth + xOffset; | |
257 | int line = cs.DocFromDisplay(pt.y / vs.lineHeight + topLine); | |
258 | if (pt.y < 0) { // Division rounds towards 0 | |
259 | line = cs.DocFromDisplay((pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine); | |
260 | } | |
261 | if (line < 0) | |
262 | return 0; | |
263 | if (line >= pdoc->LinesTotal()) | |
264 | return pdoc->Length(); | |
d134f170 | 265 | //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); |
9ce192d4 RD |
266 | Surface surface; |
267 | surface.Init(); | |
f6bcfd97 | 268 | surface.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); |
9ce192d4 RD |
269 | unsigned int posLineStart = pdoc->LineStart(line); |
270 | ||
271 | LineLayout ll; | |
272 | LayoutLine(line, &surface, vs, ll); | |
273 | for (int i = 0; i < ll.numCharsInLine; i++) { | |
d134f170 RD |
274 | if (pt.x < ((ll.positions[i] + ll.positions[i + 1]) / 2) || |
275 | ll.chars[i] == '\r' || ll.chars[i] == '\n') { | |
9ce192d4 RD |
276 | return i + posLineStart; |
277 | } | |
278 | } | |
279 | ||
280 | return ll.numCharsInLine + posLineStart; | |
281 | } | |
282 | ||
283 | int Editor::PositionFromLineX(int line, int x) { | |
284 | RefreshStyleData(); | |
285 | if (line >= pdoc->LinesTotal()) | |
286 | return pdoc->Length(); | |
287 | //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); | |
288 | Surface surface; | |
289 | surface.Init(); | |
f6bcfd97 | 290 | surface.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); |
9ce192d4 RD |
291 | unsigned int posLineStart = pdoc->LineStart(line); |
292 | ||
293 | LineLayout ll; | |
294 | LayoutLine(line, &surface, vs, ll); | |
295 | for (int i = 0; i < ll.numCharsInLine; i++) { | |
d134f170 RD |
296 | if (x < ((ll.positions[i] + ll.positions[i + 1]) / 2) || |
297 | ll.chars[i] == '\r' || ll.chars[i] == '\n') { | |
9ce192d4 RD |
298 | return i + posLineStart; |
299 | } | |
300 | } | |
301 | ||
302 | return ll.numCharsInLine + posLineStart; | |
303 | } | |
304 | ||
305 | void Editor::RedrawRect(PRectangle rc) { | |
306 | //Platform::DebugPrintf("Redraw %d %d - %d %d\n", rc.left, rc.top, rc.right, rc.bottom); | |
307 | wDraw.InvalidateRectangle(rc); | |
308 | } | |
309 | ||
310 | void Editor::Redraw() { | |
311 | //Platform::DebugPrintf("Redraw all\n"); | |
312 | wDraw.InvalidateAll(); | |
313 | } | |
314 | ||
315 | void Editor::RedrawSelMargin() { | |
316 | if (vs.maskInLine) { | |
317 | Redraw(); | |
318 | } else { | |
319 | PRectangle rcSelMargin = GetClientRectangle(); | |
320 | rcSelMargin.right = vs.fixedColumnWidth; | |
321 | wDraw.InvalidateRectangle(rcSelMargin); | |
322 | } | |
323 | } | |
324 | ||
325 | PRectangle Editor::RectangleFromRange(int start, int end) { | |
326 | int minPos = start; | |
327 | if (minPos > end) | |
328 | minPos = end; | |
329 | int maxPos = start; | |
330 | if (maxPos < end) | |
331 | maxPos = end; | |
332 | int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos)); | |
333 | int maxLine = cs.DisplayFromDoc(pdoc->LineFromPosition(maxPos)); | |
334 | PRectangle rcClient = GetTextRectangle(); | |
335 | PRectangle rc; | |
336 | rc.left = vs.fixedColumnWidth; | |
337 | rc.top = (minLine - topLine) * vs.lineHeight; | |
338 | if (rc.top < 0) | |
339 | rc.top = 0; | |
340 | rc.right = rcClient.right; | |
341 | rc.bottom = (maxLine - topLine + 1) * vs.lineHeight; | |
342 | // Ensure PRectangle is within 16 bit space | |
343 | rc.top = Platform::Clamp(rc.top, -32000, 32000); | |
344 | rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000); | |
345 | ||
346 | return rc; | |
347 | } | |
348 | ||
349 | void Editor::InvalidateRange(int start, int end) { | |
350 | RedrawRect(RectangleFromRange(start, end)); | |
351 | } | |
352 | ||
353 | int Editor::CurrentPosition() { | |
354 | return currentPos; | |
355 | } | |
356 | ||
357 | bool Editor::SelectionEmpty() { | |
358 | return anchor == currentPos; | |
359 | } | |
360 | ||
361 | int Editor::SelectionStart(int line) { | |
362 | if ((line == -1) || (selType == selStream)) { | |
363 | return Platform::Minimum(currentPos, anchor); | |
364 | } else { // selType == selRectangle | |
365 | int selStart = SelectionStart(); | |
366 | int selEnd = SelectionEnd(); | |
367 | int lineStart = pdoc->LineFromPosition(selStart); | |
368 | int lineEnd = pdoc->LineFromPosition(selEnd); | |
369 | if (line < lineStart || line > lineEnd) { | |
370 | return -1; | |
371 | } else { | |
372 | int minX = Platform::Minimum(xStartSelect, xEndSelect); | |
373 | //return PositionFromLineX(line, minX + vs.fixedColumnWidth - xOffset); | |
374 | return PositionFromLineX(line, minX); | |
375 | } | |
d134f170 | 376 | } |
9ce192d4 RD |
377 | } |
378 | ||
379 | int Editor::SelectionEnd(int line) { | |
380 | if ((line == -1) || (selType == selStream)) { | |
381 | return Platform::Maximum(currentPos, anchor); | |
382 | } else { // selType == selRectangle | |
383 | int selStart = SelectionStart(); | |
384 | int selEnd = SelectionEnd(); | |
385 | int lineStart = pdoc->LineFromPosition(selStart); | |
386 | int lineEnd = pdoc->LineFromPosition(selEnd); | |
387 | if (line < lineStart || line > lineEnd) { | |
388 | return -1; | |
389 | } else { | |
390 | int maxX = Platform::Maximum(xStartSelect, xEndSelect); | |
391 | // measure line and return character closest to minx | |
392 | return PositionFromLineX(line, maxX); | |
393 | } | |
394 | } | |
395 | } | |
396 | ||
397 | void Editor::SetSelection(int currentPos_, int anchor_) { | |
398 | currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_); | |
399 | anchor_ = pdoc->ClampPositionIntoDocument(anchor_); | |
400 | if ((currentPos != currentPos_) || (anchor != anchor_)) { | |
401 | int firstAffected = anchor; | |
402 | if (firstAffected > currentPos) | |
403 | firstAffected = currentPos; | |
404 | if (firstAffected > anchor_) | |
405 | firstAffected = anchor_; | |
406 | if (firstAffected > currentPos_) | |
407 | firstAffected = currentPos_; | |
408 | int lastAffected = anchor; | |
409 | if (lastAffected < currentPos) | |
410 | lastAffected = currentPos; | |
411 | if (lastAffected < anchor_) | |
412 | lastAffected = anchor_; | |
413 | if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted | |
414 | lastAffected = (currentPos_ + 1); | |
415 | currentPos = currentPos_; | |
416 | anchor = anchor_; | |
417 | needUpdateUI = true; | |
418 | InvalidateRange(firstAffected, lastAffected); | |
419 | } | |
420 | ClaimSelection(); | |
421 | } | |
422 | ||
423 | void Editor::SetSelection(int currentPos_) { | |
424 | currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_); | |
425 | if (currentPos != currentPos_) { | |
426 | int firstAffected = anchor; | |
427 | if (firstAffected > currentPos) | |
428 | firstAffected = currentPos; | |
429 | if (firstAffected > currentPos_) | |
430 | firstAffected = currentPos_; | |
431 | int lastAffected = anchor; | |
432 | if (lastAffected < currentPos) | |
433 | lastAffected = currentPos; | |
434 | if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted | |
435 | lastAffected = (currentPos_ + 1); | |
436 | currentPos = currentPos_; | |
437 | needUpdateUI = true; | |
438 | InvalidateRange(firstAffected, lastAffected); | |
439 | } | |
440 | ClaimSelection(); | |
441 | } | |
442 | ||
443 | void Editor::SetEmptySelection(int currentPos_) { | |
444 | SetSelection(currentPos_, currentPos_); | |
445 | } | |
446 | ||
d134f170 RD |
447 | int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) { |
448 | // Asks document to find a good position and then moves out of any invisible positions | |
449 | pos = pdoc->MovePositionOutsideChar(pos, moveDir, checkLineEnd); | |
450 | int mask = pdoc->stylingBitsMask; | |
451 | if (moveDir > 0) { | |
452 | while ((pos < pdoc->Length()) && | |
453 | (!vs.styles[pdoc->StyleAt(pos - 1) & mask].visible)) | |
454 | pos++; | |
455 | } else { | |
456 | while ((pos > 0) && | |
457 | (!vs.styles[pdoc->StyleAt(pos - 1) & mask].visible)) | |
458 | pos--; | |
459 | } | |
460 | return pos; | |
461 | } | |
462 | ||
9ce192d4 RD |
463 | int Editor::MovePositionTo(int newPos, bool extend) { |
464 | int delta = newPos - currentPos; | |
465 | newPos = pdoc->ClampPositionIntoDocument(newPos); | |
d134f170 | 466 | newPos = MovePositionOutsideChar(newPos, delta); |
9ce192d4 RD |
467 | if (extend) { |
468 | SetSelection(newPos); | |
469 | } else { | |
470 | SetEmptySelection(newPos); | |
471 | } | |
472 | EnsureCaretVisible(); | |
473 | ShowCaretAtCurrentPosition(); | |
474 | return 0; | |
475 | } | |
476 | ||
477 | int Editor::MovePositionSoVisible(int pos, int moveDir) { | |
478 | pos = pdoc->ClampPositionIntoDocument(pos); | |
d134f170 | 479 | pos = MovePositionOutsideChar(pos, moveDir); |
9ce192d4 RD |
480 | int lineDoc = pdoc->LineFromPosition(pos); |
481 | if (cs.GetVisible(lineDoc)) { | |
482 | return pos; | |
483 | } else { | |
484 | int lineDisplay = cs.DisplayFromDoc(lineDoc); | |
485 | if (moveDir > 0) { | |
486 | lineDisplay = Platform::Clamp(lineDisplay + 1, 0, cs.LinesDisplayed()); | |
487 | return pdoc->LineStart(cs.DocFromDisplay(lineDisplay)); | |
488 | } else { | |
489 | // lineDisplay is already line before fold as lines in fold use display line of line before fold | |
490 | lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed()); | |
491 | return pdoc->LineEndPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay))); | |
492 | } | |
493 | } | |
494 | } | |
495 | ||
496 | // Choose the x position that the caret will try to stick to as it is moves up and down | |
497 | void Editor::SetLastXChosen() { | |
498 | Point pt = LocationFromPosition(currentPos); | |
499 | lastXChosen = pt.x; | |
500 | } | |
501 | ||
502 | void Editor::ScrollTo(int line) { | |
503 | int topLineNew = Platform::Clamp(line, 0, MaxScrollPos()); | |
504 | if (topLineNew != topLine) { | |
505 | // Try to optimise small scrolls | |
506 | int linesToMove = topLine - topLineNew; | |
507 | SetTopLine(topLineNew); | |
508 | ShowCaretAtCurrentPosition(); | |
509 | // Perform redraw rather than scroll if many lines would be redrawn anyway. | |
510 | if (abs(linesToMove) <= 10) { | |
511 | ScrollText(linesToMove); | |
512 | } else { | |
513 | Redraw(); | |
514 | } | |
515 | SetVerticalScrollPos(); | |
516 | } | |
517 | } | |
518 | ||
f6bcfd97 | 519 | void Editor::ScrollText(int /* linesToMove */) { |
9ce192d4 RD |
520 | //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove); |
521 | Redraw(); | |
522 | } | |
523 | ||
524 | void Editor::HorizontalScrollTo(int xPos) { | |
525 | //Platform::DebugPrintf("HorizontalScroll %d\n", xPos); | |
526 | xOffset = xPos; | |
527 | if (xOffset < 0) | |
528 | xOffset = 0; | |
529 | SetHorizontalScrollPos(); | |
530 | Redraw(); | |
531 | } | |
532 | ||
f6bcfd97 BP |
533 | void Editor::MoveCaretInsideView() { |
534 | PRectangle rcClient = GetTextRectangle(); | |
535 | Point pt = LocationFromPosition(currentPos); | |
536 | if (pt.y < rcClient.top) { | |
537 | MovePositionTo(PositionFromLocation( | |
538 | Point(lastXChosen, rcClient.top))); | |
539 | } else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) { | |
d134f170 | 540 | int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight; |
f6bcfd97 BP |
541 | MovePositionTo(PositionFromLocation( |
542 | Point(lastXChosen, rcClient.top + yOfLastLineFullyDisplayed))); | |
543 | } | |
544 | } | |
545 | ||
9ce192d4 RD |
546 | void Editor::EnsureCaretVisible(bool useMargin) { |
547 | //Platform::DebugPrintf("EnsureCaretVisible %d\n", xOffset); | |
548 | PRectangle rcClient = GetTextRectangle(); | |
549 | int posCaret = currentPos; | |
550 | if (posDrag >= 0) | |
551 | posCaret = posDrag; | |
552 | Point pt = LocationFromPosition(posCaret); | |
553 | Point ptEOL = LocationFromPosition(pdoc->LineEndPosition(posCaret)); | |
554 | Point ptBottomCaret = pt; | |
555 | int lineCaret = cs.DisplayFromDoc(pdoc->LineFromPosition(posCaret)); | |
556 | ptBottomCaret.y += vs.lineHeight - 1; | |
557 | ||
558 | // Ensure the caret is reasonably visible in context. | |
559 | int xMargin = Platform::Clamp(xCaretMargin, 2, Platform::Maximum(rcClient.Width() - 10, 4) / 2); | |
560 | if (!useMargin) | |
561 | xMargin = 2; | |
d134f170 | 562 | |
9ce192d4 RD |
563 | // Ensure certain amount of text visible on both sides of caretSo move if caret just on edge |
564 | rcClient.left = rcClient.left + xMargin; | |
565 | rcClient.right = rcClient.right - xMargin; | |
d134f170 | 566 | |
9ce192d4 RD |
567 | if (!rcClient.Contains(pt) || !rcClient.Contains(ptBottomCaret) || (caretPolicy & CARET_STRICT)) { |
568 | //Platform::DebugPrintf("EnsureCaretVisible move, (%d,%d) (%d,%d)\n", pt.x, pt.y, rcClient.left, rcClient.right); | |
569 | // It should be possible to scroll the window to show the caret, | |
570 | // but this fails to remove the caret on GTK+ | |
571 | if (caretPolicy & CARET_SLOP) { | |
572 | if ((topLine > lineCaret) || ((caretPolicy & CARET_STRICT) && (topLine + caretSlop > lineCaret))) { | |
573 | SetTopLine(Platform::Clamp(lineCaret - caretSlop, 0, MaxScrollPos())); | |
574 | SetVerticalScrollPos(); | |
575 | Redraw(); | |
d134f170 RD |
576 | } else if ((lineCaret > topLine + LinesOnScreen() - 1) || |
577 | ((caretPolicy & CARET_STRICT) && (lineCaret > topLine + LinesOnScreen() - 1 - caretSlop))) { | |
9ce192d4 RD |
578 | SetTopLine(Platform::Clamp(lineCaret - LinesOnScreen() + 1 + caretSlop, 0, MaxScrollPos())); |
579 | SetVerticalScrollPos(); | |
580 | Redraw(); | |
581 | } | |
582 | } else { | |
583 | if ((topLine > lineCaret) || (lineCaret > topLine + LinesOnScreen() - 1) || (caretPolicy & CARET_STRICT)) { | |
584 | SetTopLine(Platform::Clamp(lineCaret - LinesOnScreen() / 2 + 1, 0, MaxScrollPos())); | |
585 | SetVerticalScrollPos(); | |
586 | Redraw(); | |
587 | } | |
588 | } | |
589 | int xOffsetNew = xOffset; | |
590 | if (pt.x < rcClient.left) { | |
591 | xOffsetNew = xOffset - (rcClient.left - pt.x); | |
592 | } else if (pt.x >= rcClient.right) { | |
593 | xOffsetNew = xOffset + (pt.x - rcClient.right); | |
594 | int xOffsetEOL = xOffset + (ptEOL.x - rcClient.right) - xMargin + 2; | |
595 | //Platform::DebugPrintf("Margin %d %d\n", xOffsetNew, xOffsetEOL); | |
596 | // Ensure don't scroll out into empty space | |
597 | if (xOffsetNew > xOffsetEOL) | |
598 | xOffsetNew = xOffsetEOL; | |
599 | } | |
600 | if (xOffsetNew < 0) | |
601 | xOffsetNew = 0; | |
602 | if (xOffset != xOffsetNew) { | |
603 | xOffset = xOffsetNew; | |
604 | SetHorizontalScrollPos(); | |
605 | Redraw(); | |
606 | } | |
607 | } | |
608 | } | |
609 | ||
610 | void Editor::ShowCaretAtCurrentPosition() { | |
611 | if (!wMain.HasFocus()) { | |
612 | caret.active = false; | |
613 | caret.on = false; | |
d134f170 | 614 | return ; |
9ce192d4 RD |
615 | } |
616 | caret.active = true; | |
617 | caret.on = true; | |
618 | SetTicking(true); | |
619 | } | |
620 | ||
621 | void Editor::DropCaret() { | |
622 | caret.active = false; | |
623 | InvalidateCaret(); | |
624 | } | |
625 | ||
626 | void Editor::InvalidateCaret() { | |
627 | if (posDrag >= 0) | |
628 | InvalidateRange(posDrag, posDrag + 1); | |
629 | else | |
630 | InvalidateRange(currentPos, currentPos + 1); | |
631 | } | |
632 | ||
633 | void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { | |
634 | if (vs.fixedColumnWidth == 0) | |
d134f170 | 635 | return ; |
9ce192d4 RD |
636 | |
637 | PRectangle rcMargin = GetClientRectangle(); | |
638 | rcMargin.right = vs.fixedColumnWidth; | |
639 | ||
640 | if (!rc.Intersects(rcMargin)) | |
d134f170 | 641 | return ; |
9ce192d4 RD |
642 | |
643 | Surface *surface; | |
644 | if (bufferedDraw) { | |
645 | surface = &pixmapSelMargin; | |
646 | } else { | |
647 | surface = surfWindow; | |
648 | } | |
649 | ||
650 | PRectangle rcSelMargin = rcMargin; | |
651 | rcSelMargin.right = rcMargin.left; | |
652 | ||
d134f170 | 653 | for (int margin = 0; margin < vs.margins; margin++) { |
9ce192d4 | 654 | if (vs.ms[margin].width > 0) { |
d134f170 | 655 | |
9ce192d4 RD |
656 | rcSelMargin.left = rcSelMargin.right; |
657 | rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width; | |
658 | ||
659 | if (vs.ms[margin].symbol) { | |
660 | /* alternate scheme: | |
661 | if (vs.ms[margin].mask & SC_MASK_FOLDERS) | |
662 | surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated); | |
663 | else | |
664 | // Required because of special way brush is created for selection margin | |
665 | surface->FillRectangle(rcSelMargin, pixmapSelPattern); | |
666 | */ | |
667 | if (vs.ms[margin].mask & SC_MASK_FOLDERS) | |
668 | // Required because of special way brush is created for selection margin | |
d134f170 | 669 | surface->FillRectangle(rcSelMargin, pixmapSelPattern); |
9ce192d4 | 670 | else |
d134f170 | 671 | surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated); |
9ce192d4 RD |
672 | } else { |
673 | surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated); | |
674 | } | |
d134f170 | 675 | |
9ce192d4 RD |
676 | int visibleLine = topLine; |
677 | int line = cs.DocFromDisplay(visibleLine); | |
678 | int yposScreen = 0; | |
679 | ||
f6bcfd97 | 680 | while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) { |
9ce192d4 RD |
681 | int marks = pdoc->GetMark(line); |
682 | if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) { | |
683 | if (cs.GetExpanded(line)) { | |
684 | marks |= 1 << SC_MARKNUM_FOLDEROPEN; | |
685 | } else { | |
686 | marks |= 1 << SC_MARKNUM_FOLDER; | |
687 | } | |
688 | } | |
689 | marks &= vs.ms[margin].mask; | |
690 | PRectangle rcMarker = rcSelMargin; | |
691 | rcMarker.top = yposScreen; | |
692 | rcMarker.bottom = yposScreen + vs.lineHeight; | |
693 | if (!vs.ms[margin].symbol) { | |
694 | char number[100]; | |
695 | number[0] = '\0'; | |
696 | sprintf(number, "%d", line + 1); | |
f6bcfd97 | 697 | if (foldFlags & 64) |
9ce192d4 | 698 | sprintf(number, "%X", pdoc->GetLevel(line)); |
d134f170 | 699 | PRectangle rcNumber = rcMarker; |
9ce192d4 RD |
700 | // Right justify |
701 | int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, strlen(number)); | |
f6bcfd97 | 702 | int xpos = rcNumber.right - width - 3; |
9ce192d4 RD |
703 | rcNumber.left = xpos; |
704 | if ((visibleLine < cs.LinesDisplayed()) && cs.GetVisible(line)) { | |
705 | surface->DrawText(rcNumber, vs.styles[STYLE_LINENUMBER].font, | |
706 | rcNumber.top + vs.maxAscent, number, strlen(number), | |
d134f170 RD |
707 | vs.styles[STYLE_LINENUMBER].fore.allocated, |
708 | vs.styles[STYLE_LINENUMBER].back.allocated); | |
9ce192d4 RD |
709 | } |
710 | } | |
d134f170 | 711 | |
9ce192d4 RD |
712 | if (marks) { |
713 | for (int markBit = 0; (markBit < 32) && marks; markBit++) { | |
714 | if (marks & 1) { | |
715 | rcMarker.top++; | |
716 | rcMarker.bottom--; | |
717 | vs.markers[markBit].Draw(surface, rcMarker); | |
718 | } | |
719 | marks >>= 1; | |
720 | } | |
721 | } | |
d134f170 | 722 | |
9ce192d4 RD |
723 | visibleLine++; |
724 | line = cs.DocFromDisplay(visibleLine); | |
725 | yposScreen += vs.lineHeight; | |
726 | } | |
727 | } | |
728 | } | |
729 | ||
730 | PRectangle rcBlankMargin = rcMargin; | |
731 | rcBlankMargin.left = rcSelMargin.right; | |
d134f170 RD |
732 | surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back.allocated); |
733 | ||
9ce192d4 RD |
734 | if (bufferedDraw) { |
735 | surfWindow->Copy(rcMargin, Point(), pixmapSelMargin); | |
736 | } | |
737 | } | |
738 | ||
739 | void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) { | |
740 | int ydiff = (rcTab.bottom - rcTab.top) / 2; | |
741 | int xhead = rcTab.right - 1 - ydiff; | |
742 | if ((rcTab.left + 2) < (rcTab.right - 1)) | |
743 | surface->MoveTo(rcTab.left + 2, ymid); | |
744 | else | |
745 | surface->MoveTo(rcTab.right - 1, ymid); | |
746 | surface->LineTo(rcTab.right - 1, ymid); | |
747 | surface->LineTo(xhead, ymid - ydiff); | |
748 | surface->MoveTo(rcTab.right - 1, ymid); | |
749 | surface->LineTo(xhead, ymid + ydiff); | |
750 | } | |
751 | ||
752 | void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout &ll) { | |
753 | int numCharsInLine = 0; | |
754 | int posLineStart = pdoc->LineStart(line); | |
755 | int posLineEnd = pdoc->LineStart(line + 1); | |
756 | Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font; | |
757 | char styleByte = 0; | |
758 | int styleMask = pdoc->stylingBitsMask; | |
d134f170 RD |
759 | ll.xHighlightGuide = 0; |
760 | if (posLineEnd > (posLineStart + LineLayout::maxLineLength)) { | |
761 | posLineEnd = posLineStart + LineLayout::maxLineLength; | |
762 | } | |
763 | for (int charInDoc = posLineStart; charInDoc < posLineEnd; charInDoc++) { | |
9ce192d4 RD |
764 | char chDoc = pdoc->CharAt(charInDoc); |
765 | styleByte = pdoc->StyleAt(charInDoc); | |
766 | if (vstyle.viewEOL || ((chDoc != '\r') && (chDoc != '\n'))) { | |
767 | ll.chars[numCharsInLine] = chDoc; | |
f6bcfd97 BP |
768 | ll.styles[numCharsInLine] = static_cast<char>(styleByte & styleMask); |
769 | ll.indicators[numCharsInLine] = static_cast<char>(styleByte & ~styleMask); | |
9ce192d4 RD |
770 | numCharsInLine++; |
771 | } | |
772 | } | |
d134f170 RD |
773 | // Extra element at the end of the line to hold end x position and act as |
774 | ll.chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character | |
9ce192d4 RD |
775 | ll.styles[numCharsInLine] = styleByte; // For eolFilled |
776 | ll.indicators[numCharsInLine] = 0; | |
777 | ||
d134f170 RD |
778 | // Layout the line, determining the position of each character, |
779 | // with an extra element at the end for the end of the line. | |
9ce192d4 RD |
780 | int startseg = 0; |
781 | int startsegx = 0; | |
782 | ll.positions[0] = 0; | |
783 | unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars; | |
d134f170 | 784 | |
9ce192d4 RD |
785 | for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) { |
786 | if ((ll.styles[charInLine] != ll.styles[charInLine + 1]) || | |
787 | IsControlCharacter(ll.chars[charInLine]) || IsControlCharacter(ll.chars[charInLine + 1])) { | |
788 | ll.positions[startseg] = 0; | |
d134f170 RD |
789 | if (vstyle.styles[ll.styles[charInLine]].visible) { |
790 | if (IsControlCharacter(ll.chars[charInLine])) { | |
791 | if (ll.chars[charInLine] == '\t') { | |
792 | ll.positions[charInLine + 1] = ((((startsegx + 2) / | |
793 | tabWidth) + 1) * tabWidth) - startsegx; | |
794 | } else { | |
795 | const char *ctrlChar = ControlCharacterString(ll.chars[charInLine]); | |
796 | // +3 For a blank on front and rounded edge each side: | |
797 | ll.positions[charInLine + 1] = surface->WidthText(ctrlCharsFont, ctrlChar, strlen(ctrlChar)) + 3; | |
798 | } | |
9ce192d4 | 799 | } else { |
d134f170 RD |
800 | int lenSeg = charInLine - startseg + 1; |
801 | if ((lenSeg == 1) && (' ' == ll.chars[startseg])) { | |
802 | // Over half the segments are single characters and of these about half are space characters. | |
803 | ll.positions[charInLine + 1] = vstyle.styles[ll.styles[charInLine]].spaceWidth; | |
804 | } else { | |
805 | surface->MeasureWidths(vstyle.styles[ll.styles[charInLine]].font, ll.chars + startseg, | |
806 | charInLine - startseg + 1, ll.positions + startseg + 1); | |
807 | } | |
808 | } | |
809 | } else { // invisible | |
810 | for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) { | |
811 | ll.positions[posToZero] = 0; | |
9ce192d4 | 812 | } |
9ce192d4 RD |
813 | } |
814 | for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) { | |
815 | ll.positions[posToIncrease] += startsegx; | |
816 | } | |
817 | startsegx = ll.positions[charInLine + 1]; | |
818 | startseg = charInLine + 1; | |
819 | } | |
820 | } | |
821 | ll.numCharsInLine = numCharsInLine; | |
822 | } | |
823 | ||
d134f170 RD |
824 | void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart, |
825 | PRectangle rcLine, LineLayout &ll) { | |
826 | ||
9ce192d4 | 827 | PRectangle rcSegment = rcLine; |
d134f170 | 828 | |
9ce192d4 RD |
829 | // Using one font for all control characters so it can be controlled independently to ensure |
830 | // the box goes around the characters tightly. Seems to be no way to work out what height | |
831 | // is taken by an individual character - internal leading gives varying results. | |
832 | Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; | |
833 | ||
834 | int marks = 0; | |
835 | Colour markBack = Colour(0, 0, 0); | |
836 | if (vsDraw.maskInLine) { | |
837 | marks = pdoc->GetMark(line) & vsDraw.maskInLine; | |
838 | if (marks) { | |
839 | for (int markBit = 0; (markBit < 32) && marks; markBit++) { | |
840 | if (marks & 1) { | |
841 | markBack = vsDraw.markers[markBit].back.allocated; | |
842 | } | |
843 | marks >>= 1; | |
844 | } | |
845 | } | |
846 | marks = pdoc->GetMark(line) & vsDraw.maskInLine; | |
847 | } | |
848 | ||
d134f170 RD |
849 | bool inIndentation = true; |
850 | int indentWidth = pdoc->indentInChars * vsDraw.spaceWidth; | |
851 | if (indentWidth == 0) | |
852 | indentWidth = pdoc->tabInChars * vsDraw.spaceWidth; | |
853 | ||
9ce192d4 RD |
854 | int posLineStart = pdoc->LineStart(line); |
855 | int posLineEnd = pdoc->LineStart(line + 1); | |
856 | ||
9ce192d4 RD |
857 | int styleMask = pdoc->stylingBitsMask; |
858 | int startseg = 0; | |
859 | for (int i = 0; i < ll.numCharsInLine; i++) { | |
860 | ||
861 | int iDoc = i + posLineStart; | |
862 | // If there is the end of a style run for any reason | |
863 | if ((ll.styles[i] != ll.styles[i + 1]) || | |
864 | IsControlCharacter(ll.chars[i]) || IsControlCharacter(ll.chars[i + 1]) || | |
d134f170 RD |
865 | ((ll.selStart != ll.selEnd) && ((iDoc + 1 == ll.selStart) || (iDoc + 1 == ll.selEnd))) || |
866 | (i == (ll.edgeColumn - 1))) { | |
9ce192d4 RD |
867 | int styleMain = ll.styles[i]; |
868 | Colour textBack = vsDraw.styles[styleMain].back.allocated; | |
869 | Colour textFore = vsDraw.styles[styleMain].fore.allocated; | |
870 | Font &textFont = vsDraw.styles[styleMain].font; | |
d134f170 RD |
871 | bool inSelection = (iDoc >= ll.selStart) && (iDoc < ll.selEnd) && (ll.selStart != ll.selEnd); |
872 | if (inSelection) { | |
873 | if (vsDraw.selbackset) { | |
874 | if (primarySelection) | |
875 | textBack = vsDraw.selbackground.allocated; | |
876 | else | |
877 | textBack = vsDraw.selbackground2.allocated; | |
878 | } | |
9ce192d4 RD |
879 | if (vsDraw.selforeset) |
880 | textFore = vsDraw.selforeground.allocated; | |
881 | } else { | |
882 | if (marks) | |
883 | textBack = markBack; | |
d134f170 RD |
884 | if ((vsDraw.edgeState == EDGE_BACKGROUND) && (i >= ll.edgeColumn) && (ll.chars[i] != '\n') && (ll.chars[i] != '\r')) |
885 | textBack = vsDraw.edgecolour.allocated; | |
9ce192d4 RD |
886 | } |
887 | // Manage tab display | |
888 | if (ll.chars[i] == '\t') { | |
889 | rcSegment.left = ll.positions[i] + xStart; | |
890 | rcSegment.right = ll.positions[i + 1] + xStart; | |
891 | surface->FillRectangle(rcSegment, textBack); | |
d134f170 | 892 | if ((vsDraw.viewWhitespace != wsInvisible) || ((inIndentation && vsDraw.viewIndentationGuides))) { |
9ce192d4 | 893 | surface->PenColour(textFore); |
9ce192d4 | 894 | } |
d134f170 RD |
895 | if (inIndentation && vsDraw.viewIndentationGuides) { |
896 | for (int xIG = ll.positions[i] / indentWidth * indentWidth; xIG < ll.positions[i + 1]; xIG += indentWidth) { | |
897 | if (xIG >= ll.positions[i] && xIG > 0) { | |
898 | Point from(0, ((lineVisible & 1) && (vsDraw.lineHeight & 1)) ? 1 : 0); | |
899 | PRectangle rcCopyArea(xIG + xStart + 1, rcSegment.top, xIG + xStart + 2, rcSegment.bottom); | |
900 | surface->Copy(rcCopyArea, from, (ll.xHighlightGuide == xIG) ? | |
901 | pixmapIndentGuideHighlight : pixmapIndentGuide); | |
902 | } | |
903 | } | |
904 | } | |
905 | if (vsDraw.viewWhitespace != wsInvisible) { | |
906 | if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { | |
907 | PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4, | |
908 | rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent); | |
909 | DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2); | |
910 | } | |
911 | } | |
912 | // Manage control character display | |
913 | } | |
914 | else if (IsControlCharacter(ll.chars[i])) { | |
915 | inIndentation = false; | |
9ce192d4 RD |
916 | const char *ctrlChar = ControlCharacterString(ll.chars[i]); |
917 | rcSegment.left = ll.positions[i] + xStart; | |
918 | rcSegment.right = ll.positions[i + 1] + xStart; | |
919 | surface->FillRectangle(rcSegment, textBack); | |
920 | int normalCharHeight = surface->Ascent(ctrlCharsFont) - | |
921 | surface->InternalLeading(ctrlCharsFont); | |
922 | PRectangle rcCChar = rcSegment; | |
923 | rcCChar.left = rcCChar.left + 1; | |
924 | rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight; | |
925 | rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1; | |
926 | PRectangle rcCentral = rcCChar; | |
927 | rcCentral.top++; | |
928 | rcCentral.bottom--; | |
929 | surface->FillRectangle(rcCentral, textFore); | |
930 | PRectangle rcChar = rcCChar; | |
931 | rcChar.left++; | |
932 | rcChar.right--; | |
933 | surface->DrawTextClipped(rcChar, ctrlCharsFont, | |
d134f170 RD |
934 | rcSegment.top + vsDraw.maxAscent, ctrlChar, strlen(ctrlChar), |
935 | textBack, textFore); | |
936 | // Manage normal display | |
9ce192d4 RD |
937 | } else { |
938 | rcSegment.left = ll.positions[startseg] + xStart; | |
939 | rcSegment.right = ll.positions[i + 1] + xStart; | |
d134f170 | 940 | // Only try to draw if really visible - enhances performance by not calling environment to |
9ce192d4 RD |
941 | // draw strings that are completely past the right side of the window. |
942 | if (rcSegment.left <= rcLine.right) { | |
943 | surface->DrawText(rcSegment, textFont, | |
944 | rcSegment.top + vsDraw.maxAscent, ll.chars + startseg, | |
945 | i - startseg + 1, textFore, textBack); | |
d134f170 RD |
946 | if (vsDraw.viewWhitespace != wsInvisible || |
947 | (inIndentation && vsDraw.viewIndentationGuides)) { | |
9ce192d4 RD |
948 | for (int cpos = 0; cpos <= i - startseg; cpos++) { |
949 | if (ll.chars[cpos + startseg] == ' ') { | |
d134f170 RD |
950 | if (vsDraw.viewWhitespace != wsInvisible) { |
951 | if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { | |
952 | int xmid = (ll.positions[cpos + startseg] + ll.positions[cpos + startseg + 1]) / 2; | |
953 | PRectangle rcDot(xmid + xStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0); | |
954 | rcDot.right = rcDot.left + 1; | |
955 | rcDot.bottom = rcDot.top + 1; | |
956 | surface->FillRectangle(rcDot, textFore); | |
957 | } | |
958 | } | |
959 | if (inIndentation && vsDraw.viewIndentationGuides) { | |
960 | int startSpace = ll.positions[cpos + startseg]; | |
961 | if (startSpace > 0 && (startSpace % indentWidth == 0)) { | |
962 | Point from(0, ((lineVisible & 1) && (vsDraw.lineHeight & 1)) ? 1 : 0); | |
963 | PRectangle rcCopyArea(startSpace + xStart + 1, rcSegment.top, startSpace + xStart + 2, rcSegment.bottom); | |
964 | surface->Copy(rcCopyArea, from, (ll.xHighlightGuide == ll.positions[cpos + startseg]) ? | |
965 | pixmapIndentGuideHighlight : pixmapIndentGuide); | |
966 | } | |
967 | } | |
968 | } else { | |
969 | inIndentation = false; | |
9ce192d4 RD |
970 | } |
971 | } | |
972 | } | |
973 | } | |
f6bcfd97 BP |
974 | if (vsDraw.styles[styleMain].underline) { |
975 | PRectangle rcUL = rcSegment; | |
976 | rcUL.top = rcUL.top + vsDraw.maxAscent + 1; | |
977 | rcUL.bottom = rcUL.top + 1; | |
978 | surface->FillRectangle(rcUL, textFore); | |
979 | } | |
9ce192d4 RD |
980 | } |
981 | startseg = i + 1; | |
982 | } | |
983 | } | |
984 | ||
985 | // Draw indicators | |
986 | int indStart[INDIC_MAX + 1] = {0}; | |
987 | for (int indica = 0; indica <= INDIC_MAX; indica++) | |
988 | indStart[indica] = 0; | |
989 | ||
d134f170 | 990 | for (int indicPos = 0; indicPos < ll.numCharsInLine; indicPos++) { |
9ce192d4 RD |
991 | if (ll.indicators[indicPos] != ll.indicators[indicPos + 1]) { |
992 | int mask = 1 << pdoc->stylingBits; | |
d134f170 | 993 | for (int indicnum = 0; mask < 0x100; indicnum++) { |
9ce192d4 RD |
994 | if ((ll.indicators[indicPos + 1] & mask) && !(ll.indicators[indicPos] & mask)) { |
995 | indStart[indicnum] = ll.positions[indicPos + 1]; | |
996 | } | |
997 | if (!(ll.indicators[indicPos + 1] & mask) && (ll.indicators[indicPos] & mask)) { | |
998 | PRectangle rcIndic( | |
999 | indStart[indicnum] + xStart, | |
1000 | rcLine.top + vsDraw.maxAscent, | |
1001 | ll.positions[indicPos + 1] + xStart, | |
1002 | rcLine.top + vsDraw.maxAscent + 3); | |
1003 | vsDraw.indicators[indicnum].Draw(surface, rcIndic); | |
1004 | } | |
1005 | mask = mask << 1; | |
1006 | } | |
1007 | } | |
1008 | } | |
1009 | // End of the drawing of the current line | |
1010 | ||
1011 | // Fill in a PRectangle representing the end of line characters | |
1012 | int xEol = ll.positions[ll.numCharsInLine]; | |
1013 | rcSegment.left = xEol + xStart; | |
1014 | rcSegment.right = xEol + vsDraw.aveCharWidth + xStart; | |
d134f170 RD |
1015 | bool eolInSelection = (posLineEnd > ll.selStart) && (posLineEnd <= ll.selEnd) && (ll.selStart != ll.selEnd); |
1016 | if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1)) { | |
1017 | if (primarySelection) | |
1018 | surface->FillRectangle(rcSegment, vsDraw.selbackground.allocated); | |
1019 | else | |
1020 | surface->FillRectangle(rcSegment, vsDraw.selbackground2.allocated); | |
9ce192d4 RD |
1021 | } else if (marks) { |
1022 | surface->FillRectangle(rcSegment, markBack); | |
1023 | } else { | |
1024 | surface->FillRectangle(rcSegment, vsDraw.styles[ll.styles[ll.numCharsInLine] & styleMask].back.allocated); | |
1025 | } | |
1026 | ||
1027 | rcSegment.left = xEol + vsDraw.aveCharWidth + xStart; | |
1028 | rcSegment.right = rcLine.right; | |
1029 | if (marks) { | |
1030 | surface->FillRectangle(rcSegment, markBack); | |
1031 | } else if (vsDraw.styles[ll.styles[ll.numCharsInLine] & styleMask].eolFilled) { | |
1032 | surface->FillRectangle(rcSegment, vsDraw.styles[ll.styles[ll.numCharsInLine] & styleMask].back.allocated); | |
1033 | } else { | |
1034 | surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated); | |
1035 | } | |
d134f170 RD |
1036 | |
1037 | if (vsDraw.edgeState == EDGE_LINE) { | |
1038 | int edgeX = ll.edgeColumn * vsDraw.spaceWidth; | |
9ce192d4 RD |
1039 | rcSegment.left = edgeX + xStart; |
1040 | rcSegment.right = rcSegment.left + 1; | |
d134f170 | 1041 | surface->FillRectangle(rcSegment, vsDraw.edgecolour.allocated); |
9ce192d4 RD |
1042 | } |
1043 | } | |
1044 | ||
1045 | void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { | |
1046 | //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); | |
1047 | RefreshStyleData(); | |
1048 | ||
1049 | PRectangle rcClient = GetClientRectangle(); | |
1050 | //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n", | |
1051 | // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); | |
1052 | ||
1053 | if (!pixmapSelPattern.Initialised()) { | |
1054 | pixmapSelPattern.InitPixMap(8, 8, surfaceWindow); | |
1055 | // This complex procedure is to reproduce the checker board dithered pattern used by windows | |
1056 | // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half | |
1057 | // way between the chrome colour and the chrome highlight colour making a nice transition | |
1058 | // between the window chrome and the content area. And it works in low colour depths. | |
1059 | PRectangle rcPattern(0, 0, 8, 8); | |
1060 | if (vs.selbarlight.desired == Colour(0xff, 0xff, 0xff)) { | |
1061 | pixmapSelPattern.FillRectangle(rcPattern, vs.selbar.allocated); | |
1062 | pixmapSelPattern.PenColour(vs.selbarlight.allocated); | |
1063 | for (int stripe = 0; stripe < 8; stripe++) { | |
1064 | pixmapSelPattern.MoveTo(0, stripe * 2); | |
1065 | pixmapSelPattern.LineTo(8, stripe * 2 - 8); | |
1066 | } | |
1067 | } else { | |
1068 | // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. | |
1069 | pixmapSelPattern.FillRectangle(rcPattern, vs.selbarlight.allocated); | |
1070 | } | |
1071 | } | |
d134f170 RD |
1072 | if (!pixmapIndentGuide.Initialised()) { |
1073 | // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line | |
1074 | pixmapIndentGuide.InitPixMap(1, vs.lineHeight + 1, surfaceWindow); | |
1075 | pixmapIndentGuideHighlight.InitPixMap(1, vs.lineHeight + 1, surfaceWindow); | |
1076 | PRectangle rcIG(0, 0, 1, vs.lineHeight); | |
1077 | pixmapIndentGuide.FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back.allocated); | |
1078 | pixmapIndentGuide.PenColour(vs.styles[STYLE_INDENTGUIDE].fore.allocated); | |
1079 | pixmapIndentGuideHighlight.FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back.allocated); | |
1080 | pixmapIndentGuideHighlight.PenColour(vs.styles[STYLE_BRACELIGHT].fore.allocated); | |
1081 | for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) { | |
1082 | pixmapIndentGuide.MoveTo(0, stripe); | |
1083 | pixmapIndentGuide.LineTo(2, stripe); | |
1084 | pixmapIndentGuideHighlight.MoveTo(0, stripe); | |
1085 | pixmapIndentGuideHighlight.LineTo(2, stripe); | |
1086 | } | |
1087 | } | |
9ce192d4 RD |
1088 | |
1089 | if (bufferedDraw) { | |
1090 | if (!pixmapLine.Initialised()) { | |
1091 | pixmapLine.InitPixMap(rcClient.Width(), rcClient.Height(), | |
1092 | surfaceWindow); | |
1093 | pixmapSelMargin.InitPixMap(vs.fixedColumnWidth, | |
1094 | rcClient.Height(), surfaceWindow); | |
1095 | } | |
1096 | } | |
1097 | ||
1098 | surfaceWindow->SetPalette(&palette, true); | |
1099 | pixmapLine.SetPalette(&palette, !wMain.HasFocus()); | |
1100 | ||
1101 | //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n", | |
1102 | // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); | |
1103 | ||
1104 | int screenLinePaintFirst = rcArea.top / vs.lineHeight; | |
1105 | // The area to be painted plus one extra line is styled. | |
1106 | // The extra line is to determine when a style change, such as statrting a comment flows on to other lines. | |
d134f170 | 1107 | int lineStyleLast = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1; |
9ce192d4 RD |
1108 | //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast); |
1109 | int endPosPaint = pdoc->Length(); | |
1110 | if (lineStyleLast < cs.LinesDisplayed()) | |
1111 | endPosPaint = pdoc->LineStart(cs.DocFromDisplay(lineStyleLast + 1)); | |
1112 | ||
1113 | int xStart = vs.fixedColumnWidth - xOffset; | |
1114 | int ypos = 0; | |
1115 | if (!bufferedDraw) | |
1116 | ypos += screenLinePaintFirst * vs.lineHeight; | |
1117 | int yposScreen = screenLinePaintFirst * vs.lineHeight; | |
1118 | ||
f6bcfd97 BP |
1119 | // Ensure we are styled as far as we are painting. |
1120 | pdoc->EnsureStyledTo(endPosPaint); | |
1121 | ||
9ce192d4 RD |
1122 | if (needUpdateUI) { |
1123 | NotifyUpdateUI(); | |
1124 | needUpdateUI = false; | |
1125 | } | |
d134f170 | 1126 | |
9ce192d4 RD |
1127 | PaintSelMargin(surfaceWindow, rcArea); |
1128 | ||
1129 | PRectangle rcRightMargin = rcClient; | |
1130 | rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth; | |
1131 | if (rcArea.Intersects(rcRightMargin)) { | |
d134f170 | 1132 | surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated); |
9ce192d4 RD |
1133 | } |
1134 | ||
1135 | if (paintState == paintAbandoned) { | |
f6bcfd97 | 1136 | // Either styling or NotifyUpdateUI noticed that painting is needed |
9ce192d4 RD |
1137 | // outside the current painting rectangle |
1138 | //Platform::DebugPrintf("Abandoning paint\n"); | |
d134f170 | 1139 | return ; |
9ce192d4 RD |
1140 | } |
1141 | //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset); | |
1142 | ||
9ce192d4 RD |
1143 | if (rcArea.right > vs.fixedColumnWidth) { |
1144 | ||
f6bcfd97 | 1145 | Surface *surface = surfaceWindow; |
9ce192d4 RD |
1146 | if (bufferedDraw) { |
1147 | surface = &pixmapLine; | |
9ce192d4 | 1148 | } |
f6bcfd97 | 1149 | surface->SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); |
9ce192d4 RD |
1150 | |
1151 | int visibleLine = topLine + screenLinePaintFirst; | |
1152 | int line = cs.DocFromDisplay(visibleLine); | |
1153 | ||
1154 | int posCaret = currentPos; | |
1155 | if (posDrag >= 0) | |
1156 | posCaret = posDrag; | |
1157 | int lineCaret = pdoc->LineFromPosition(posCaret); | |
1158 | ||
1159 | // Remove selection margin from drawing area so text will not be drawn | |
1160 | // on it in unbuffered mode. | |
1161 | PRectangle rcTextArea = rcClient; | |
1162 | rcTextArea.left = vs.fixedColumnWidth; | |
1163 | rcTextArea.right -= vs.rightMarginWidth; | |
1164 | surfaceWindow->SetClip(rcTextArea); | |
1165 | //GTimer *tim=g_timer_new(); | |
d134f170 | 1166 | while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) { |
9ce192d4 RD |
1167 | //g_timer_start(tim); |
1168 | //Platform::DebugPrintf("Painting line %d\n", line); | |
1169 | ||
1170 | int posLineStart = pdoc->LineStart(line); | |
1171 | int posLineEnd = pdoc->LineStart(line + 1); | |
1172 | //Platform::DebugPrintf("line %d %d - %d\n", line, posLineStart, posLineEnd); | |
1173 | ||
1174 | PRectangle rcLine = rcClient; | |
1175 | rcLine.top = ypos; | |
1176 | rcLine.bottom = ypos + vs.lineHeight; | |
1177 | ||
1178 | // Copy this line and its styles from the document into local arrays | |
1179 | // and determine the x position at which each character starts. | |
1180 | LineLayout ll; | |
1181 | LayoutLine(line, surface, vs, ll); | |
d134f170 | 1182 | |
9ce192d4 | 1183 | // Highlight the current braces if any |
d134f170 RD |
1184 | if ((braces[0] >= posLineStart) && (braces[0] < posLineEnd)) { |
1185 | int braceOffset = braces[0] - posLineStart; | |
1186 | if (braceOffset < ll.numCharsInLine) | |
1187 | ll.styles[braceOffset] = static_cast<char>(bracesMatchStyle); | |
1188 | } | |
1189 | if ((braces[1] >= posLineStart) && (braces[1] < posLineEnd)) { | |
1190 | int braceOffset = braces[1] - posLineStart; | |
1191 | if (braceOffset < ll.numCharsInLine) | |
1192 | ll.styles[braceOffset] = static_cast<char>(bracesMatchStyle); | |
1193 | } | |
1194 | if ((braces[0] >= posLineStart && braces[1] <= posLineEnd) || | |
1195 | (braces[1] >= posLineStart && braces[0] <= posLineEnd)) { | |
1196 | ll.xHighlightGuide = highlightGuideColumn * vs.spaceWidth; | |
1197 | } | |
1198 | ||
1199 | ll.selStart = SelectionStart(line); | |
1200 | ll.selEnd = SelectionEnd(line); | |
1201 | if (hideSelection) { | |
1202 | ll.selStart = -1; | |
1203 | ll.selEnd = -1; | |
1204 | } | |
1205 | // Need to fix this up so takes account of Unicode and DBCS | |
1206 | ll.edgeColumn = theEdge; | |
1207 | ||
9ce192d4 RD |
1208 | // Draw the line |
1209 | if (cs.GetVisible(line)) | |
d134f170 | 1210 | DrawLine(surface, vs, line, visibleLine, xStart, rcLine, ll); |
9ce192d4 | 1211 | |
f6bcfd97 BP |
1212 | bool expanded = cs.GetExpanded(line); |
1213 | if ( (expanded && (foldFlags & 2)) || (!expanded && (foldFlags & 4)) ) { | |
9ce192d4 RD |
1214 | if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) { |
1215 | PRectangle rcFoldLine = rcLine; | |
1216 | rcFoldLine.bottom = rcFoldLine.top + 1; | |
1217 | surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); | |
1218 | } | |
1219 | } | |
f6bcfd97 BP |
1220 | if ( (expanded && (foldFlags & 8)) || (!expanded && (foldFlags & 16)) ) { |
1221 | if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) { | |
1222 | PRectangle rcFoldLine = rcLine; | |
1223 | rcFoldLine.top = rcFoldLine.bottom - 1; | |
1224 | surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); | |
1225 | } | |
1226 | } | |
d134f170 | 1227 | |
9ce192d4 RD |
1228 | // Draw the Caret |
1229 | if (line == lineCaret) { | |
f6bcfd97 BP |
1230 | int offset = Platform::Minimum(posCaret - posLineStart, LineLayout::maxLineLength); |
1231 | int xposCaret = ll.positions[offset] + xStart; | |
d134f170 RD |
1232 | int widthOverstrikeCaret; |
1233 | if (posCaret == pdoc->Length()) { // At end of document | |
9ce192d4 | 1234 | widthOverstrikeCaret = vs.aveCharWidth; |
d134f170 | 1235 | } else if ((posCaret - posLineStart) >= ll.numCharsInLine) { // At end of line |
9ce192d4 | 1236 | widthOverstrikeCaret = vs.aveCharWidth; |
d134f170 RD |
1237 | } else { |
1238 | widthOverstrikeCaret = ll.positions[offset + 1] - ll.positions[offset]; | |
1239 | } | |
9ce192d4 RD |
1240 | if (widthOverstrikeCaret < 3) // Make sure its visible |
1241 | widthOverstrikeCaret = 3; | |
1242 | if (((caret.active && caret.on) || (posDrag >= 0)) && xposCaret >= 0) { | |
1243 | PRectangle rcCaret = rcLine; | |
1244 | if (posDrag >= 0) { | |
1245 | rcCaret.left = xposCaret; | |
1246 | rcCaret.right = xposCaret + 1; | |
1247 | } else { | |
1248 | if (inOverstrike) { | |
1249 | rcCaret.top = rcCaret.bottom - 2; | |
1250 | rcCaret.left = xposCaret + 1; | |
1251 | rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1; | |
1252 | } else { | |
1253 | rcCaret.left = xposCaret; | |
1254 | rcCaret.right = xposCaret + 1; | |
1255 | } | |
1256 | } | |
1257 | surface->FillRectangle(rcCaret, vs.caretcolour.allocated); | |
1258 | } | |
1259 | } | |
d134f170 | 1260 | |
9ce192d4 RD |
1261 | if (cs.GetVisible(line)) { |
1262 | if (bufferedDraw) { | |
1263 | Point from(vs.fixedColumnWidth, 0); | |
1264 | PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen, | |
d134f170 | 1265 | rcClient.right, yposScreen + vs.lineHeight); |
9ce192d4 RD |
1266 | surfaceWindow->Copy(rcCopyArea, from, pixmapLine); |
1267 | } | |
1268 | } | |
1269 | ||
1270 | if (!bufferedDraw) { | |
1271 | ypos += vs.lineHeight; | |
1272 | } | |
1273 | ||
1274 | yposScreen += vs.lineHeight; | |
1275 | visibleLine++; | |
1276 | line = cs.DocFromDisplay(visibleLine); | |
1277 | //gdk_flush(); | |
1278 | //g_timer_stop(tim); | |
1279 | //Platform::DebugPrintf("Paint [%0d] took %g\n", line, g_timer_elapsed(tim, 0)); | |
1280 | } | |
1281 | //g_timer_destroy(tim); | |
d134f170 | 1282 | |
9ce192d4 RD |
1283 | PRectangle rcBeyondEOF = rcClient; |
1284 | rcBeyondEOF.left = vs.fixedColumnWidth; | |
1285 | rcBeyondEOF.right = rcBeyondEOF.right; | |
1286 | rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight; | |
1287 | if (rcBeyondEOF.top < rcBeyondEOF.bottom) { | |
1288 | surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back.allocated); | |
d134f170 | 1289 | if (vs.edgeState == EDGE_LINE) { |
9ce192d4 RD |
1290 | int edgeX = theEdge * vs.spaceWidth; |
1291 | rcBeyondEOF.left = edgeX + xStart; | |
1292 | rcBeyondEOF.right = rcBeyondEOF.left + 1; | |
1293 | surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated); | |
1294 | } | |
1295 | } | |
1296 | } | |
1297 | } | |
1298 | ||
1299 | // Space (3 space characters) between line numbers and text when printing. | |
1300 | #define lineNumberPrintSpace " " | |
1301 | ||
d134f170 RD |
1302 | Colour InvertedLight(Colour orig) { |
1303 | unsigned int r = orig.GetRed(); | |
1304 | unsigned int g = orig.GetGreen(); | |
1305 | unsigned int b = orig.GetBlue(); | |
1306 | unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye | |
1307 | unsigned int il = 0xff - l; | |
1308 | if (l == 0) | |
1309 | return Colour(0xff, 0xff, 0xff); | |
1310 | r = r * il / l; | |
1311 | g = g * il / l; | |
1312 | b = b * il / l; | |
1313 | return Colour(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff)); | |
1314 | } | |
1315 | ||
9ce192d4 RD |
1316 | // This is mostly copied from the Paint method but with some things omitted |
1317 | // such as the margin markers, line numbers, selection and caret | |
1318 | // Should be merged back into a combined Draw method. | |
d134f170 | 1319 | long Editor::FormatRange(bool draw, RangeToFormat *pfr) { |
9ce192d4 RD |
1320 | if (!pfr) |
1321 | return 0; | |
1322 | ||
1323 | Surface *surface = new Surface(); | |
1324 | surface->Init(pfr->hdc); | |
f6bcfd97 | 1325 | surface->SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); |
9ce192d4 RD |
1326 | Surface *surfaceMeasure = new Surface(); |
1327 | surfaceMeasure->Init(pfr->hdcTarget); | |
f6bcfd97 | 1328 | surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); |
d134f170 | 1329 | |
9ce192d4 | 1330 | ViewStyle vsPrint(vs); |
d134f170 | 1331 | |
9ce192d4 RD |
1332 | // Modify the view style for printing as do not normally want any of the transient features to be printed |
1333 | // Printing supports only the line number margin. | |
1334 | int lineNumberIndex = -1; | |
d134f170 | 1335 | for (int margin = 0; margin < ViewStyle::margins; margin++) { |
9ce192d4 RD |
1336 | if ((!vsPrint.ms[margin].symbol) && (vsPrint.ms[margin].width > 0)) { |
1337 | lineNumberIndex = margin; | |
1338 | } else { | |
1339 | vsPrint.ms[margin].width = 0; | |
1340 | } | |
1341 | } | |
1342 | vsPrint.showMarkedLines = false; | |
1343 | vsPrint.fixedColumnWidth = 0; | |
d134f170 RD |
1344 | vsPrint.zoomLevel = printMagnification; |
1345 | vsPrint.viewIndentationGuides = false; | |
9ce192d4 RD |
1346 | // Don't show the selection when printing |
1347 | vsPrint.selbackset = false; | |
1348 | vsPrint.selforeset = false; | |
1349 | // White background for the line numbers | |
d134f170 RD |
1350 | vsPrint.styles[STYLE_LINENUMBER].back.desired = Colour(0xff, 0xff, 0xff); |
1351 | for (int sty = 0;sty <= STYLE_MAX;sty++) { | |
1352 | if (printColourMode == SC_PRINT_INVERTLIGHT) { | |
1353 | vsPrint.styles[sty].fore.desired = InvertedLight(vsPrint.styles[sty].fore.desired); | |
1354 | vsPrint.styles[sty].back.desired = InvertedLight(vsPrint.styles[sty].back.desired); | |
1355 | } else if (printColourMode == SC_PRINT_BLACKONWHITE) { | |
1356 | vsPrint.styles[sty].fore.desired = Colour(0, 0, 0); | |
1357 | vsPrint.styles[sty].back.desired = Colour(0xff, 0xff, 0xff); | |
1358 | } | |
1359 | } | |
1360 | vsPrint.styles[STYLE_LINENUMBER].back.desired = Colour(0xff, 0xff, 0xff); | |
1361 | ||
9ce192d4 RD |
1362 | vsPrint.Refresh(*surfaceMeasure); |
1363 | // Ensure colours are set up | |
1364 | vsPrint.RefreshColourPalette(palette, true); | |
1365 | vsPrint.RefreshColourPalette(palette, false); | |
1366 | // Determining width must hapen after fonts have been realised in Refresh | |
1367 | int lineNumberWidth = 0; | |
1368 | if (lineNumberIndex >= 0) { | |
d134f170 RD |
1369 | lineNumberWidth = surface->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, |
1370 | "9999" lineNumberPrintSpace, 4 + strlen(lineNumberPrintSpace)); | |
9ce192d4 RD |
1371 | vsPrint.ms[lineNumberIndex].width = lineNumberWidth; |
1372 | } | |
1373 | ||
1374 | int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin); | |
1375 | int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1; | |
1376 | if (linePrintLast < linePrintStart) | |
1377 | linePrintLast = linePrintStart; | |
1378 | int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax - 1); | |
1379 | if (linePrintLast > linePrintMax) | |
1380 | linePrintLast = linePrintMax; | |
1381 | //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n", | |
1382 | // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight, | |
1383 | // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font)); | |
1384 | int endPosPrint = pdoc->Length(); | |
1385 | if (linePrintLast < pdoc->LinesTotal()) | |
1386 | endPosPrint = pdoc->LineStart(linePrintLast + 1); | |
1387 | ||
f6bcfd97 BP |
1388 | // Ensure we are styled to where we are formatting. |
1389 | pdoc->EnsureStyledTo(endPosPrint); | |
1390 | ||
9ce192d4 RD |
1391 | int xStart = vsPrint.fixedColumnWidth + pfr->rc.left + lineNumberWidth; |
1392 | int ypos = pfr->rc.top; | |
1393 | int line = linePrintStart; | |
1394 | ||
1395 | if (draw) { // Otherwise just measuring | |
1396 | ||
1397 | while (line <= linePrintLast && ypos < pfr->rc.bottom) { | |
1398 | ||
1399 | PRectangle rcLine; | |
1400 | rcLine.left = pfr->rc.left + lineNumberWidth; | |
1401 | rcLine.top = ypos; | |
1402 | rcLine.right = pfr->rc.right; | |
1403 | rcLine.bottom = ypos + vsPrint.lineHeight; | |
d134f170 | 1404 | |
9ce192d4 RD |
1405 | if (lineNumberWidth) { |
1406 | char number[100]; | |
1407 | sprintf(number, "%d" lineNumberPrintSpace, line + 1); | |
1408 | PRectangle rcNumber = rcLine; | |
1409 | rcNumber.right = rcNumber.left + lineNumberWidth; | |
1410 | // Right justify | |
d134f170 RD |
1411 | rcNumber.left -= |
1412 | surface->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, number, strlen(number)); | |
9ce192d4 RD |
1413 | surface->DrawText(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font, |
1414 | ypos + vsPrint.maxAscent, number, strlen(number), | |
d134f170 RD |
1415 | vsPrint.styles[STYLE_LINENUMBER].fore.allocated, |
1416 | vsPrint.styles[STYLE_LINENUMBER].back.allocated); | |
9ce192d4 | 1417 | } |
f6bcfd97 BP |
1418 | |
1419 | // When printing, the hdc and hdcTarget may be the same, so | |
1420 | // changing the state of surfaceMeasure may change the underlying | |
d134f170 | 1421 | // state of surface. Therefore, any cached state is discarded before |
f6bcfd97 | 1422 | // using each surface. |
d134f170 | 1423 | |
9ce192d4 RD |
1424 | // Copy this line and its styles from the document into local arrays |
1425 | // and determine the x position at which each character starts. | |
f6bcfd97 | 1426 | surfaceMeasure->FlushCachedState(); |
9ce192d4 RD |
1427 | LineLayout ll; |
1428 | LayoutLine(line, surfaceMeasure, vsPrint, ll); | |
d134f170 RD |
1429 | ll.selStart = -1; |
1430 | ll.selEnd = -1; | |
1431 | // Need to fix this up so takes account of Unicode and DBCS | |
1432 | ll.edgeColumn = theEdge; | |
1433 | ||
9ce192d4 | 1434 | // Draw the line |
f6bcfd97 | 1435 | surface->FlushCachedState(); |
d134f170 | 1436 | DrawLine(surface, vsPrint, line, line, xStart, rcLine, ll); |
9ce192d4 RD |
1437 | |
1438 | ypos += vsPrint.lineHeight; | |
1439 | line++; | |
1440 | } | |
1441 | } | |
1442 | ||
1443 | delete surface; | |
1444 | delete surfaceMeasure; | |
1445 | ||
1446 | return endPosPrint; | |
1447 | } | |
1448 | ||
f6bcfd97 | 1449 | // Empty method is overridden on GTK+ to show / hide scrollbars |
d134f170 RD |
1450 | void Editor::ReconfigureScrollBars() {} |
1451 | ||
f6bcfd97 | 1452 | |
9ce192d4 RD |
1453 | void Editor::SetScrollBarsTo(PRectangle) { |
1454 | RefreshStyleData(); | |
1455 | ||
1456 | int nMax = cs.LinesDisplayed(); | |
1457 | int nPage = cs.LinesDisplayed() - MaxScrollPos() + 1; | |
1458 | bool modified = ModifyScrollBars(nMax, nPage); | |
1459 | ||
1460 | // TODO: ensure always showing as many lines as possible | |
1461 | // May not be, if, for example, window made larger | |
1462 | if (topLine > MaxScrollPos()) { | |
1463 | SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos())); | |
1464 | SetVerticalScrollPos(); | |
1465 | Redraw(); | |
1466 | } | |
1467 | if (modified) | |
1468 | Redraw(); | |
1469 | //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage); | |
1470 | } | |
1471 | ||
d134f170 | 1472 | |
9ce192d4 RD |
1473 | void Editor::SetScrollBars() { |
1474 | PRectangle rsClient = GetClientRectangle(); | |
1475 | SetScrollBarsTo(rsClient); | |
1476 | } | |
1477 | ||
1478 | void Editor::AddChar(char ch) { | |
f6bcfd97 BP |
1479 | char s[2]; |
1480 | s[0] = ch; | |
1481 | s[1] = '\0'; | |
1482 | AddCharUTF(s, 1); | |
1483 | } | |
1484 | ||
1485 | void Editor::AddCharUTF(char *s, unsigned int len) { | |
9ce192d4 RD |
1486 | bool wasSelection = currentPos != anchor; |
1487 | ClearSelection(); | |
1488 | if (inOverstrike && !wasSelection) { | |
1489 | if (currentPos < (pdoc->Length() - 1)) { | |
1490 | if ((pdoc->CharAt(currentPos) != '\r') && (pdoc->CharAt(currentPos) != '\n')) { | |
1491 | pdoc->DelChar(currentPos); | |
1492 | } | |
1493 | } | |
1494 | } | |
f6bcfd97 BP |
1495 | pdoc->InsertString(currentPos, s, len); |
1496 | SetEmptySelection(currentPos + len); | |
9ce192d4 | 1497 | EnsureCaretVisible(); |
d134f170 RD |
1498 | // Avoid blinking during rapid typing: |
1499 | ShowCaretAtCurrentPosition(); | |
9ce192d4 | 1500 | SetLastXChosen(); |
f6bcfd97 | 1501 | NotifyChar(s[0]); |
9ce192d4 RD |
1502 | } |
1503 | ||
1504 | void Editor::ClearSelection() { | |
1505 | if (selType == selRectangle) { | |
1506 | pdoc->BeginUndoAction(); | |
1507 | int lineStart = pdoc->LineFromPosition(SelectionStart()); | |
1508 | int lineEnd = pdoc->LineFromPosition(SelectionEnd()); | |
1509 | int startPos = SelectionStart(); | |
d134f170 | 1510 | for (int line = lineEnd; line >= lineStart; line--) { |
9ce192d4 RD |
1511 | startPos = SelectionStart(line); |
1512 | unsigned int chars = SelectionEnd(line) - startPos; | |
1513 | if (0 != chars) { | |
1514 | pdoc->DeleteChars(startPos, chars); | |
1515 | } | |
1516 | } | |
1517 | SetEmptySelection(startPos); | |
1518 | selType = selStream; | |
1519 | pdoc->EndUndoAction(); | |
1520 | } else { | |
1521 | int startPos = SelectionStart(); | |
1522 | unsigned int chars = SelectionEnd() - startPos; | |
1523 | SetEmptySelection(startPos); | |
1524 | if (0 != chars) { | |
1525 | pdoc->DeleteChars(startPos, chars); | |
1526 | } | |
1527 | } | |
1528 | } | |
1529 | ||
1530 | void Editor::ClearAll() { | |
1531 | if (0 != pdoc->Length()) { | |
1532 | pdoc->DeleteChars(0, pdoc->Length()); | |
1533 | } | |
1534 | cs.Clear(); | |
1535 | anchor = 0; | |
1536 | currentPos = 0; | |
1537 | SetTopLine(0); | |
1538 | SetVerticalScrollPos(); | |
1539 | } | |
1540 | ||
d134f170 RD |
1541 | void Editor::ClearDocumentStyle() { |
1542 | pdoc->StartStyling(0, '\377'); | |
1543 | pdoc->SetStyleFor(pdoc->Length(), 0); | |
1544 | cs.ShowAll(); | |
1545 | pdoc->ClearLevels(); | |
1546 | } | |
1547 | ||
9ce192d4 RD |
1548 | void Editor::Cut() { |
1549 | Copy(); | |
1550 | ClearSelection(); | |
1551 | } | |
1552 | ||
1553 | void Editor::PasteRectangular(int pos, const char *ptr, int len) { | |
1554 | currentPos = pos; | |
1555 | int insertPos = currentPos; | |
1556 | int xInsert = XFromPosition(currentPos); | |
1557 | int line = pdoc->LineFromPosition(currentPos); | |
1558 | bool prevCr = false; | |
d134f170 | 1559 | for (int i = 0; i < len; i++) { |
9ce192d4 | 1560 | if ((ptr[i] == '\r') || (ptr[i] == '\n')) { |
d134f170 | 1561 | if ((ptr[i] == '\r') || (!prevCr)) |
9ce192d4 RD |
1562 | line++; |
1563 | if (line >= pdoc->LinesTotal()) { | |
1564 | if (pdoc->eolMode != SC_EOL_LF) | |
1565 | pdoc->InsertChar(pdoc->Length(), '\r'); | |
1566 | if (pdoc->eolMode != SC_EOL_CR) | |
1567 | pdoc->InsertChar(pdoc->Length(), '\n'); | |
1568 | } | |
1569 | currentPos = PositionFromLineX(line, xInsert); | |
1570 | prevCr = ptr[i] == '\r'; | |
1571 | } else { | |
d134f170 | 1572 | pdoc->InsertString(currentPos, ptr + i, 1); |
9ce192d4 RD |
1573 | currentPos++; |
1574 | insertPos = currentPos; | |
1575 | prevCr = false; | |
1576 | } | |
1577 | } | |
1578 | SetEmptySelection(insertPos); | |
1579 | } | |
1580 | ||
1581 | void Editor::Clear() { | |
1582 | if (currentPos == anchor) { | |
1583 | DelChar(); | |
1584 | } else { | |
1585 | ClearSelection(); | |
1586 | } | |
1587 | SetEmptySelection(currentPos); | |
1588 | } | |
1589 | ||
1590 | void Editor::SelectAll() { | |
1591 | SetSelection(0, pdoc->Length()); | |
1592 | Redraw(); | |
1593 | } | |
1594 | ||
1595 | void Editor::Undo() { | |
1596 | if (pdoc->CanUndo()) { | |
d134f170 | 1597 | InvalidateCaret(); |
9ce192d4 RD |
1598 | int newPos = pdoc->Undo(); |
1599 | SetEmptySelection(newPos); | |
1600 | EnsureCaretVisible(); | |
1601 | } | |
1602 | } | |
1603 | ||
1604 | void Editor::Redo() { | |
1605 | if (pdoc->CanRedo()) { | |
1606 | int newPos = pdoc->Redo(); | |
1607 | SetEmptySelection(newPos); | |
1608 | EnsureCaretVisible(); | |
1609 | } | |
1610 | } | |
1611 | ||
1612 | void Editor::DelChar() { | |
1613 | pdoc->DelChar(currentPos); | |
d134f170 RD |
1614 | // Avoid blinking during rapid typing: |
1615 | ShowCaretAtCurrentPosition(); | |
9ce192d4 RD |
1616 | } |
1617 | ||
1618 | void Editor::DelCharBack() { | |
1619 | if (currentPos == anchor) { | |
1620 | int newPos = pdoc->DelCharBack(currentPos); | |
1621 | SetEmptySelection(newPos); | |
1622 | } else { | |
1623 | ClearSelection(); | |
1624 | SetEmptySelection(currentPos); | |
1625 | } | |
d134f170 RD |
1626 | // Avoid blinking during rapid typing: |
1627 | ShowCaretAtCurrentPosition(); | |
9ce192d4 RD |
1628 | } |
1629 | ||
d134f170 RD |
1630 | void Editor::NotifyFocus(bool) {} |
1631 | ||
9ce192d4 | 1632 | |
f6bcfd97 | 1633 | void Editor::NotifyStyleToNeeded(int endStyleNeeded) { |
9ce192d4 RD |
1634 | SCNotification scn; |
1635 | scn.nmhdr.code = SCN_STYLENEEDED; | |
1636 | scn.position = endStyleNeeded; | |
1637 | NotifyParent(scn); | |
1638 | } | |
1639 | ||
f6bcfd97 BP |
1640 | void Editor::NotifyStyleNeeded(Document*, void *, int endStyleNeeded) { |
1641 | NotifyStyleToNeeded(endStyleNeeded); | |
1642 | } | |
1643 | ||
9ce192d4 RD |
1644 | void Editor::NotifyChar(char ch) { |
1645 | SCNotification scn; | |
1646 | scn.nmhdr.code = SCN_CHARADDED; | |
1647 | scn.ch = ch; | |
1648 | NotifyParent(scn); | |
1649 | #ifdef MACRO_SUPPORT | |
1650 | if (recordingMacro) { | |
1651 | char txt[2]; | |
1652 | txt[0] = ch; | |
1653 | txt[1] = '\0'; | |
d134f170 | 1654 | NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<long>(txt)); |
9ce192d4 | 1655 | } |
d134f170 | 1656 | #endif |
9ce192d4 RD |
1657 | } |
1658 | ||
1659 | void Editor::NotifySavePoint(bool isSavePoint) { | |
1660 | SCNotification scn; | |
1661 | if (isSavePoint) { | |
1662 | scn.nmhdr.code = SCN_SAVEPOINTREACHED; | |
1663 | } else { | |
1664 | scn.nmhdr.code = SCN_SAVEPOINTLEFT; | |
1665 | } | |
1666 | NotifyParent(scn); | |
1667 | } | |
1668 | ||
1669 | void Editor::NotifyModifyAttempt() { | |
1670 | SCNotification scn; | |
1671 | scn.nmhdr.code = SCN_MODIFYATTEMPTRO; | |
1672 | NotifyParent(scn); | |
1673 | } | |
1674 | ||
1675 | void Editor::NotifyDoubleClick(Point, bool) { | |
1676 | SCNotification scn; | |
1677 | scn.nmhdr.code = SCN_DOUBLECLICK; | |
1678 | NotifyParent(scn); | |
1679 | } | |
1680 | ||
1681 | void Editor::NotifyUpdateUI() { | |
1682 | SCNotification scn; | |
1683 | scn.nmhdr.code = SCN_UPDATEUI; | |
1684 | NotifyParent(scn); | |
1685 | } | |
1686 | ||
1687 | bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) { | |
1688 | int marginClicked = -1; | |
1689 | int x = 0; | |
d134f170 | 1690 | for (int margin = 0; margin < ViewStyle::margins; margin++) { |
9ce192d4 RD |
1691 | if ((pt.x > x) && (pt.x < x + vs.ms[margin].width)) |
1692 | marginClicked = margin; | |
1693 | x += vs.ms[margin].width; | |
1694 | } | |
1695 | if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) { | |
1696 | SCNotification scn; | |
1697 | scn.nmhdr.code = SCN_MARGINCLICK; | |
1698 | scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | | |
1699 | (alt ? SCI_ALT : 0); | |
1700 | scn.position = pdoc->LineStart(LineFromLocation(pt)); | |
1701 | scn.margin = marginClicked; | |
1702 | NotifyParent(scn); | |
1703 | return true; | |
1704 | } else { | |
1705 | return false; | |
1706 | } | |
1707 | } | |
1708 | ||
1709 | void Editor::NotifyNeedShown(int pos, int len) { | |
1710 | SCNotification scn; | |
1711 | scn.nmhdr.code = SCN_NEEDSHOWN; | |
1712 | scn.position = pos; | |
1713 | scn.length = len; | |
1714 | NotifyParent(scn); | |
1715 | } | |
1716 | ||
1717 | // Notifications from document | |
1718 | void Editor::NotifyModifyAttempt(Document*, void *) { | |
1719 | //Platform::DebugPrintf("** Modify Attempt\n"); | |
1720 | NotifyModifyAttempt(); | |
1721 | } | |
1722 | ||
d134f170 RD |
1723 | void Editor::NotifyMove(int position) { |
1724 | SCNotification scn; | |
1725 | scn.nmhdr.code = SCN_POSCHANGED; | |
1726 | scn.position = position; | |
1727 | NotifyParent(scn); | |
1728 | } | |
1729 | ||
9ce192d4 RD |
1730 | void Editor::NotifySavePoint(Document*, void *, bool atSavePoint) { |
1731 | //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off"); | |
1732 | NotifySavePoint(atSavePoint); | |
1733 | } | |
1734 | ||
1735 | void Editor::NotifyModified(Document*, DocModification mh, void *) { | |
1736 | needUpdateUI = true; | |
1737 | if (paintState == painting) { | |
1738 | CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length)); | |
1739 | } else if (paintState == notPainting) { | |
1740 | if (mh.modificationType & SC_MOD_CHANGESTYLE) { | |
1741 | if (mh.position < pdoc->LineStart(topLine)) { | |
1742 | // Styling performed before this view | |
1743 | Redraw(); | |
1744 | } else { | |
1745 | InvalidateRange(mh.position, mh.position + mh.length); | |
1746 | } | |
1747 | } else { | |
1748 | // Move selection and brace highlights | |
1749 | if (mh.modificationType & SC_MOD_INSERTTEXT) { | |
1750 | if (currentPos > mh.position) { | |
1751 | currentPos += mh.length; | |
1752 | } | |
1753 | if (anchor > mh.position) { | |
1754 | anchor += mh.length; | |
1755 | } | |
1756 | if (braces[0] > mh.position) { | |
1757 | braces[0] += mh.length; | |
1758 | } | |
1759 | if (braces[1] > mh.position) { | |
1760 | braces[1] += mh.length; | |
1761 | } | |
1762 | } else { // SC_MOD_DELETETEXT | |
1763 | int endPos = mh.position + mh.length; | |
1764 | if (currentPos > mh.position) { | |
1765 | if (currentPos > endPos) { | |
1766 | currentPos -= mh.length; | |
1767 | } else { | |
1768 | currentPos = endPos; | |
1769 | } | |
1770 | } | |
1771 | if (anchor > mh.position) { | |
1772 | if (anchor > endPos) { | |
1773 | anchor -= mh.length; | |
1774 | } else { | |
1775 | anchor = endPos; | |
1776 | } | |
1777 | } | |
1778 | if (braces[0] > mh.position) { | |
1779 | if (braces[0] > endPos) { | |
1780 | braces[0] -= mh.length; | |
1781 | } else { | |
1782 | braces[0] = endPos; | |
1783 | } | |
1784 | } | |
1785 | if (braces[1] > mh.position) { | |
1786 | if (braces[1] > endPos) { | |
1787 | braces[1] -= mh.length; | |
1788 | } else { | |
1789 | braces[1] = endPos; | |
1790 | } | |
1791 | } | |
1792 | } | |
d134f170 RD |
1793 | if (cs.LinesDisplayed() < cs.LinesInDoc()) { |
1794 | // Some lines are hidden so may need shown. | |
1795 | // TODO: check if the modified area is hidden. | |
1796 | if (mh.modificationType & SC_MOD_BEFOREINSERT) { | |
1797 | NotifyNeedShown(mh.position, 0); | |
1798 | } else if (mh.modificationType & SC_MOD_BEFOREDELETE) { | |
1799 | NotifyNeedShown(mh.position, mh.length); | |
1800 | } | |
1801 | } | |
9ce192d4 RD |
1802 | if (mh.linesAdded != 0) { |
1803 | ||
1804 | // Update contraction state for inserted and removed lines | |
1805 | // lineOfPos should be calculated in context of state before modification, shouldn't it | |
1806 | int lineOfPos = pdoc->LineFromPosition(mh.position); | |
1807 | if (mh.linesAdded > 0) { | |
9ce192d4 RD |
1808 | cs.InsertLines(lineOfPos, mh.linesAdded); |
1809 | } else { | |
1810 | cs.DeleteLines(lineOfPos, -mh.linesAdded); | |
1811 | } | |
1812 | // Avoid scrolling of display if change before current display | |
1813 | if (mh.position < posTopLine) { | |
1814 | int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos()); | |
1815 | if (newTop != topLine) { | |
1816 | SetTopLine(newTop); | |
1817 | SetVerticalScrollPos(); | |
1818 | } | |
1819 | } | |
d134f170 | 1820 | |
9ce192d4 RD |
1821 | //Platform::DebugPrintf("** %x Doc Changed\n", this); |
1822 | // TODO: could invalidate from mh.startModification to end of screen | |
1823 | //InvalidateRange(mh.position, mh.position + mh.length); | |
1824 | Redraw(); | |
1825 | } else { | |
1826 | //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this, | |
1827 | // mh.position, mh.position + mh.length); | |
1828 | InvalidateRange(mh.position, mh.position + mh.length); | |
1829 | } | |
1830 | } | |
1831 | } // else paintState == paintAbandoned so no need to do anything | |
1832 | ||
1833 | if (mh.linesAdded != 0) { | |
1834 | SetScrollBars(); | |
1835 | } | |
1836 | ||
f6bcfd97 BP |
1837 | if (mh.modificationType & SC_MOD_CHANGEMARKER) { |
1838 | RedrawSelMargin(); | |
1839 | } | |
d134f170 | 1840 | |
9ce192d4 RD |
1841 | // If client wants to see this modification |
1842 | if (mh.modificationType & modEventMask) { | |
1843 | if ((mh.modificationType & SC_MOD_CHANGESTYLE) == 0) { | |
1844 | // Real modification made to text of document. | |
1845 | NotifyChange(); // Send EN_CHANGE | |
1846 | } | |
d134f170 | 1847 | |
9ce192d4 RD |
1848 | SCNotification scn; |
1849 | scn.nmhdr.code = SCN_MODIFIED; | |
1850 | scn.position = mh.position; | |
1851 | scn.modificationType = mh.modificationType; | |
1852 | scn.text = mh.text; | |
1853 | scn.length = mh.length; | |
1854 | scn.linesAdded = mh.linesAdded; | |
1855 | scn.line = mh.line; | |
1856 | scn.foldLevelNow = mh.foldLevelNow; | |
1857 | scn.foldLevelPrev = mh.foldLevelPrev; | |
1858 | NotifyParent(scn); | |
1859 | } | |
1860 | } | |
1861 | ||
f6bcfd97 | 1862 | void Editor::NotifyDeleted(Document *, void *) { |
9ce192d4 RD |
1863 | /* Do nothing */ |
1864 | } | |
1865 | ||
1866 | #ifdef MACRO_SUPPORT | |
d134f170 | 1867 | void Editor::NotifyMacroRecord(unsigned int iMessage, unsigned long wParam, long lParam) { |
9ce192d4 RD |
1868 | |
1869 | // Enumerates all macroable messages | |
1870 | switch (iMessage) { | |
d134f170 RD |
1871 | case SCI_CUT: |
1872 | case SCI_COPY: | |
1873 | case SCI_PASTE: | |
1874 | case SCI_CLEAR: | |
1875 | case SCI_REPLACESEL: | |
9ce192d4 RD |
1876 | case SCI_ADDTEXT: |
1877 | case SCI_INSERTTEXT: | |
1878 | case SCI_CLEARALL: | |
1879 | case SCI_SELECTALL: | |
1880 | case SCI_GOTOLINE: | |
1881 | case SCI_GOTOPOS: | |
1882 | case SCI_SEARCHANCHOR: | |
1883 | case SCI_SEARCHNEXT: | |
1884 | case SCI_SEARCHPREV: | |
1885 | case SCI_LINEDOWN: | |
1886 | case SCI_LINEDOWNEXTEND: | |
1887 | case SCI_LINEUP: | |
1888 | case SCI_LINEUPEXTEND: | |
1889 | case SCI_CHARLEFT: | |
1890 | case SCI_CHARLEFTEXTEND: | |
1891 | case SCI_CHARRIGHT: | |
1892 | case SCI_CHARRIGHTEXTEND: | |
1893 | case SCI_WORDLEFT: | |
1894 | case SCI_WORDLEFTEXTEND: | |
1895 | case SCI_WORDRIGHT: | |
1896 | case SCI_WORDRIGHTEXTEND: | |
1897 | case SCI_HOME: | |
1898 | case SCI_HOMEEXTEND: | |
1899 | case SCI_LINEEND: | |
1900 | case SCI_LINEENDEXTEND: | |
1901 | case SCI_DOCUMENTSTART: | |
1902 | case SCI_DOCUMENTSTARTEXTEND: | |
1903 | case SCI_DOCUMENTEND: | |
1904 | case SCI_DOCUMENTENDEXTEND: | |
1905 | case SCI_PAGEUP: | |
1906 | case SCI_PAGEUPEXTEND: | |
1907 | case SCI_PAGEDOWN: | |
1908 | case SCI_PAGEDOWNEXTEND: | |
1909 | case SCI_EDITTOGGLEOVERTYPE: | |
1910 | case SCI_CANCEL: | |
1911 | case SCI_DELETEBACK: | |
1912 | case SCI_TAB: | |
1913 | case SCI_BACKTAB: | |
1914 | case SCI_NEWLINE: | |
1915 | case SCI_FORMFEED: | |
1916 | case SCI_VCHOME: | |
1917 | case SCI_VCHOMEEXTEND: | |
1918 | case SCI_DELWORDLEFT: | |
1919 | case SCI_DELWORDRIGHT: | |
f6bcfd97 BP |
1920 | case SCI_LINECUT: |
1921 | case SCI_LINEDELETE: | |
1922 | case SCI_LINETRANSPOSE: | |
1923 | case SCI_LOWERCASE: | |
1924 | case SCI_UPPERCASE: | |
9ce192d4 RD |
1925 | break; |
1926 | ||
d134f170 | 1927 | // Filter out all others (display changes, etc) |
9ce192d4 | 1928 | default: |
d134f170 RD |
1929 | // printf("Filtered out %ld of macro recording\n", iMessage); |
1930 | ||
1931 | return ; | |
9ce192d4 RD |
1932 | } |
1933 | ||
1934 | // Send notification | |
1935 | SCNotification scn; | |
1936 | scn.nmhdr.code = SCN_MACRORECORD; | |
1937 | scn.message = iMessage; | |
1938 | scn.wParam = wParam; | |
1939 | scn.lParam = lParam; | |
1940 | NotifyParent(scn); | |
1941 | } | |
d134f170 | 1942 | #endif |
9ce192d4 RD |
1943 | |
1944 | // Force scroll and keep position relative to top of window | |
1945 | void Editor::PageMove(int direction, bool extend) { | |
1946 | Point pt = LocationFromPosition(currentPos); | |
1947 | int topLineNew = Platform::Clamp( | |
d134f170 | 1948 | topLine + direction * LinesToScroll(), 0, MaxScrollPos()); |
9ce192d4 RD |
1949 | int newPos = PositionFromLocation( |
1950 | Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll()))); | |
1951 | if (topLineNew != topLine) { | |
1952 | SetTopLine(topLineNew); | |
1953 | MovePositionTo(newPos, extend); | |
1954 | Redraw(); | |
1955 | SetVerticalScrollPos(); | |
1956 | } else { | |
1957 | MovePositionTo(newPos, extend); | |
1958 | } | |
1959 | } | |
1960 | ||
f6bcfd97 BP |
1961 | void Editor::ChangeCaseOfSelection(bool makeUpperCase) { |
1962 | pdoc->BeginUndoAction(); | |
1963 | int startCurrent = currentPos; | |
1964 | int startAnchor = anchor; | |
1965 | if (selType == selRectangle) { | |
1966 | int lineStart = pdoc->LineFromPosition(SelectionStart()); | |
1967 | int lineEnd = pdoc->LineFromPosition(SelectionEnd()); | |
d134f170 | 1968 | for (int line = lineEnd; line >= lineStart; line--) { |
f6bcfd97 | 1969 | pdoc->ChangeCase( |
d134f170 RD |
1970 | Range(SelectionStart(line), SelectionEnd(line)), |
1971 | makeUpperCase); | |
f6bcfd97 BP |
1972 | } |
1973 | // Would be nicer to keep the rectangular selection but this is complex | |
1974 | selType = selStream; | |
1975 | SetSelection(startCurrent, startCurrent); | |
1976 | } else { | |
d134f170 RD |
1977 | pdoc->ChangeCase(Range(SelectionStart(), SelectionEnd()), |
1978 | makeUpperCase); | |
f6bcfd97 BP |
1979 | SetSelection(startCurrent, startAnchor); |
1980 | } | |
1981 | pdoc->EndUndoAction(); | |
1982 | } | |
1983 | ||
1984 | ||
1985 | void Editor::LineTranspose() { | |
1986 | int line = pdoc->LineFromPosition(currentPos); | |
1987 | if (line > 0) { | |
d134f170 RD |
1988 | int startPrev = pdoc->LineStart(line - 1); |
1989 | int endPrev = pdoc->LineEnd(line - 1); | |
f6bcfd97 BP |
1990 | int start = pdoc->LineStart(line); |
1991 | int end = pdoc->LineEnd(line); | |
d134f170 | 1992 | int startNext = pdoc->LineStart(line + 1); |
f6bcfd97 BP |
1993 | if (end < pdoc->Length()) { |
1994 | end = startNext; | |
1995 | char *thisLine = CopyRange(start, end); | |
d134f170 RD |
1996 | pdoc->DeleteChars(start, end - start); |
1997 | pdoc->InsertString(startPrev, thisLine, end - start); | |
1998 | MovePositionTo(startPrev + end - start); | |
f6bcfd97 BP |
1999 | delete []thisLine; |
2000 | } else { | |
2001 | // Last line so line has no line end | |
2002 | char *thisLine = CopyRange(start, end); | |
2003 | char *prevEnd = CopyRange(endPrev, start); | |
d134f170 RD |
2004 | pdoc->DeleteChars(endPrev, end - endPrev); |
2005 | pdoc->InsertString(startPrev, thisLine, end - start); | |
2006 | pdoc->InsertString(startPrev + end - start, prevEnd, start - endPrev); | |
2007 | MovePositionTo(startPrev + end - endPrev); | |
f6bcfd97 BP |
2008 | delete []thisLine; |
2009 | delete []prevEnd; | |
2010 | } | |
d134f170 | 2011 | |
f6bcfd97 BP |
2012 | } |
2013 | } | |
2014 | ||
d134f170 RD |
2015 | void Editor::CancelModes() {} |
2016 | ||
2017 | ||
2018 | int Editor::KeyCommand(unsigned int iMessage) { | |
9ce192d4 RD |
2019 | Point pt = LocationFromPosition(currentPos); |
2020 | ||
2021 | switch (iMessage) { | |
2022 | case SCI_LINEDOWN: | |
2023 | MovePositionTo(PositionFromLocation( | |
2024 | Point(lastXChosen, pt.y + vs.lineHeight))); | |
2025 | break; | |
2026 | case SCI_LINEDOWNEXTEND: | |
2027 | MovePositionTo(PositionFromLocation( | |
2028 | Point(lastXChosen, pt.y + vs.lineHeight)), true); | |
2029 | break; | |
f6bcfd97 BP |
2030 | case SCI_LINESCROLLDOWN: |
2031 | ScrollTo(topLine + 1); | |
2032 | MoveCaretInsideView(); | |
2033 | break; | |
9ce192d4 RD |
2034 | case SCI_LINEUP: |
2035 | MovePositionTo(PositionFromLocation( | |
2036 | Point(lastXChosen, pt.y - vs.lineHeight))); | |
2037 | break; | |
2038 | case SCI_LINEUPEXTEND: | |
2039 | MovePositionTo(PositionFromLocation( | |
2040 | Point(lastXChosen, pt.y - vs.lineHeight)), true); | |
2041 | break; | |
f6bcfd97 BP |
2042 | case SCI_LINESCROLLUP: |
2043 | ScrollTo(topLine - 1); | |
2044 | MoveCaretInsideView(); | |
2045 | break; | |
9ce192d4 RD |
2046 | case SCI_CHARLEFT: |
2047 | if (SelectionEmpty()) { | |
2048 | MovePositionTo(MovePositionSoVisible(currentPos - 1, -1)); | |
2049 | } else { | |
2050 | MovePositionTo(SelectionStart()); | |
2051 | } | |
2052 | SetLastXChosen(); | |
2053 | break; | |
2054 | case SCI_CHARLEFTEXTEND: | |
2055 | MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), true); | |
2056 | SetLastXChosen(); | |
2057 | break; | |
2058 | case SCI_CHARRIGHT: | |
2059 | if (SelectionEmpty()) { | |
2060 | MovePositionTo(MovePositionSoVisible(currentPos + 1, 1)); | |
2061 | } else { | |
2062 | MovePositionTo(SelectionEnd()); | |
2063 | } | |
2064 | SetLastXChosen(); | |
2065 | break; | |
2066 | case SCI_CHARRIGHTEXTEND: | |
2067 | MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), true); | |
2068 | SetLastXChosen(); | |
2069 | break; | |
2070 | case SCI_WORDLEFT: | |
2071 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1)); | |
2072 | SetLastXChosen(); | |
2073 | break; | |
2074 | case SCI_WORDLEFTEXTEND: | |
2075 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1), true); | |
2076 | SetLastXChosen(); | |
2077 | break; | |
2078 | case SCI_WORDRIGHT: | |
2079 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1)); | |
2080 | SetLastXChosen(); | |
2081 | break; | |
2082 | case SCI_WORDRIGHTEXTEND: | |
2083 | MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1), true); | |
2084 | SetLastXChosen(); | |
2085 | break; | |
2086 | case SCI_HOME: | |
2087 | MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos))); | |
2088 | SetLastXChosen(); | |
2089 | break; | |
2090 | case SCI_HOMEEXTEND: | |
2091 | MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), true); | |
2092 | SetLastXChosen(); | |
2093 | break; | |
2094 | case SCI_LINEEND: | |
2095 | MovePositionTo(pdoc->LineEndPosition(currentPos)); | |
2096 | SetLastXChosen(); | |
2097 | break; | |
2098 | case SCI_LINEENDEXTEND: | |
2099 | MovePositionTo(pdoc->LineEndPosition(currentPos), true); | |
2100 | SetLastXChosen(); | |
2101 | break; | |
2102 | case SCI_DOCUMENTSTART: | |
2103 | MovePositionTo(0); | |
2104 | SetLastXChosen(); | |
2105 | break; | |
2106 | case SCI_DOCUMENTSTARTEXTEND: | |
2107 | MovePositionTo(0, true); | |
2108 | SetLastXChosen(); | |
2109 | break; | |
2110 | case SCI_DOCUMENTEND: | |
2111 | MovePositionTo(pdoc->Length()); | |
2112 | SetLastXChosen(); | |
2113 | break; | |
2114 | case SCI_DOCUMENTENDEXTEND: | |
2115 | MovePositionTo(pdoc->Length(), true); | |
2116 | SetLastXChosen(); | |
2117 | break; | |
2118 | case SCI_PAGEUP: | |
2119 | PageMove( -1); | |
2120 | break; | |
2121 | case SCI_PAGEUPEXTEND: | |
2122 | PageMove( -1, true); | |
2123 | break; | |
2124 | case SCI_PAGEDOWN: | |
2125 | PageMove(1); | |
2126 | break; | |
2127 | case SCI_PAGEDOWNEXTEND: | |
2128 | PageMove(1, true); | |
2129 | break; | |
2130 | case SCI_EDITTOGGLEOVERTYPE: | |
2131 | inOverstrike = !inOverstrike; | |
2132 | DropCaret(); | |
2133 | ShowCaretAtCurrentPosition(); | |
d134f170 | 2134 | NotifyUpdateUI(); |
9ce192d4 | 2135 | break; |
d134f170 | 2136 | case SCI_CANCEL: // Cancel any modes - handled in subclass |
9ce192d4 | 2137 | // Also unselect text |
d134f170 | 2138 | CancelModes(); |
9ce192d4 RD |
2139 | break; |
2140 | case SCI_DELETEBACK: | |
2141 | DelCharBack(); | |
f6bcfd97 | 2142 | SetLastXChosen(); |
9ce192d4 RD |
2143 | EnsureCaretVisible(); |
2144 | break; | |
2145 | case SCI_TAB: | |
2146 | Indent(true); | |
d134f170 RD |
2147 | SetLastXChosen(); |
2148 | EnsureCaretVisible(); | |
9ce192d4 RD |
2149 | break; |
2150 | case SCI_BACKTAB: | |
2151 | Indent(false); | |
d134f170 RD |
2152 | SetLastXChosen(); |
2153 | EnsureCaretVisible(); | |
9ce192d4 RD |
2154 | break; |
2155 | case SCI_NEWLINE: | |
2156 | ClearSelection(); | |
2157 | if (pdoc->eolMode == SC_EOL_CRLF) { | |
2158 | pdoc->InsertString(currentPos, "\r\n"); | |
2159 | SetEmptySelection(currentPos + 2); | |
2160 | NotifyChar('\r'); | |
2161 | NotifyChar('\n'); | |
2162 | } else if (pdoc->eolMode == SC_EOL_CR) { | |
2163 | pdoc->InsertChar(currentPos, '\r'); | |
2164 | SetEmptySelection(currentPos + 1); | |
2165 | NotifyChar('\r'); | |
2166 | } else if (pdoc->eolMode == SC_EOL_LF) { | |
2167 | pdoc->InsertChar(currentPos, '\n'); | |
2168 | SetEmptySelection(currentPos + 1); | |
2169 | NotifyChar('\n'); | |
2170 | } | |
2171 | SetLastXChosen(); | |
2172 | EnsureCaretVisible(); | |
2173 | break; | |
2174 | case SCI_FORMFEED: | |
2175 | AddChar('\f'); | |
2176 | break; | |
2177 | case SCI_VCHOME: | |
2178 | MovePositionTo(pdoc->VCHomePosition(currentPos)); | |
2179 | SetLastXChosen(); | |
2180 | break; | |
2181 | case SCI_VCHOMEEXTEND: | |
2182 | MovePositionTo(pdoc->VCHomePosition(currentPos), true); | |
2183 | SetLastXChosen(); | |
2184 | break; | |
2185 | case SCI_ZOOMIN: | |
2186 | if (vs.zoomLevel < 20) | |
2187 | vs.zoomLevel++; | |
2188 | InvalidateStyleRedraw(); | |
2189 | break; | |
2190 | case SCI_ZOOMOUT: | |
2191 | if (vs.zoomLevel > -10) | |
2192 | vs.zoomLevel--; | |
2193 | InvalidateStyleRedraw(); | |
2194 | break; | |
2195 | case SCI_DELWORDLEFT: { | |
2196 | int startWord = pdoc->NextWordStart(currentPos, -1); | |
2197 | pdoc->DeleteChars(startWord, currentPos - startWord); | |
2198 | MovePositionTo(startWord); | |
f6bcfd97 | 2199 | SetLastXChosen(); |
9ce192d4 RD |
2200 | } |
2201 | break; | |
2202 | case SCI_DELWORDRIGHT: { | |
2203 | int endWord = pdoc->NextWordStart(currentPos, 1); | |
2204 | pdoc->DeleteChars(currentPos, endWord - currentPos); | |
f6bcfd97 BP |
2205 | MovePositionTo(currentPos); |
2206 | } | |
2207 | break; | |
2208 | case SCI_LINECUT: { | |
2209 | int lineStart = pdoc->LineFromPosition(currentPos); | |
2210 | int lineEnd = pdoc->LineFromPosition(anchor); | |
2211 | if (lineStart > lineEnd) { | |
2212 | int t = lineEnd; | |
2213 | lineEnd = lineStart; | |
2214 | lineStart = t; | |
2215 | } | |
2216 | int start = pdoc->LineStart(lineStart); | |
d134f170 RD |
2217 | int end = pdoc->LineStart(lineEnd + 1); |
2218 | SetSelection(start, end); | |
f6bcfd97 BP |
2219 | Cut(); |
2220 | } | |
2221 | break; | |
2222 | case SCI_LINEDELETE: { | |
2223 | int line = pdoc->LineFromPosition(currentPos); | |
2224 | int start = pdoc->LineStart(line); | |
d134f170 RD |
2225 | int end = pdoc->LineStart(line + 1); |
2226 | pdoc->DeleteChars(start, end - start); | |
f6bcfd97 | 2227 | MovePositionTo(start); |
9ce192d4 RD |
2228 | } |
2229 | break; | |
f6bcfd97 BP |
2230 | case SCI_LINETRANSPOSE: |
2231 | LineTranspose(); | |
2232 | break; | |
2233 | case SCI_LOWERCASE: | |
2234 | ChangeCaseOfSelection(false); | |
2235 | break; | |
2236 | case SCI_UPPERCASE: | |
2237 | ChangeCaseOfSelection(true); | |
2238 | break; | |
9ce192d4 RD |
2239 | } |
2240 | return 0; | |
2241 | } | |
2242 | ||
2243 | int Editor::KeyDefault(int, int) { | |
2244 | return 0; | |
2245 | } | |
2246 | ||
2247 | int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt) { | |
2248 | int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | | |
2249 | (alt ? SCI_ALT : 0); | |
2250 | int msg = kmap.Find(key, modifiers); | |
2251 | if (msg) | |
2252 | return WndProc(msg, 0, 0); | |
2253 | else | |
2254 | return KeyDefault(key, modifiers); | |
2255 | } | |
2256 | ||
d134f170 RD |
2257 | void Editor::SetWhitespaceVisible(int view) { |
2258 | vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(view); | |
9ce192d4 RD |
2259 | } |
2260 | ||
d134f170 | 2261 | int Editor::GetWhitespaceVisible() { |
9ce192d4 RD |
2262 | return vs.viewWhitespace; |
2263 | } | |
2264 | ||
2265 | void Editor::Indent(bool forwards) { | |
2266 | //Platform::DebugPrintf("INdent %d\n", forwards); | |
2267 | int lineOfAnchor = pdoc->LineFromPosition(anchor); | |
2268 | int lineCurrentPos = pdoc->LineFromPosition(currentPos); | |
2269 | if (lineOfAnchor == lineCurrentPos) { | |
2270 | ClearSelection(); | |
d134f170 RD |
2271 | if (pdoc->useTabs) { |
2272 | pdoc->InsertChar(currentPos, '\t'); | |
2273 | SetEmptySelection(currentPos + 1); | |
2274 | } else { | |
2275 | for (int i = 0; i < pdoc->tabInChars; i++) { | |
2276 | pdoc->InsertChar(currentPos, ' '); | |
2277 | } | |
2278 | SetEmptySelection(currentPos + pdoc->tabInChars); | |
2279 | } | |
9ce192d4 RD |
2280 | } else { |
2281 | int anchorPosOnLine = anchor - pdoc->LineStart(lineOfAnchor); | |
2282 | int currentPosPosOnLine = currentPos - pdoc->LineStart(lineCurrentPos); | |
2283 | // Multiple lines selected so indent / dedent | |
2284 | int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos); | |
2285 | int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos); | |
2286 | if (pdoc->LineStart(lineBottomSel) == anchor || pdoc->LineStart(lineBottomSel) == currentPos) | |
2287 | lineBottomSel--; // If not selecting any characters on a line, do not indent | |
2288 | pdoc->BeginUndoAction(); | |
2289 | pdoc->Indent(forwards, lineBottomSel, lineTopSel); | |
2290 | pdoc->EndUndoAction(); | |
2291 | if (lineOfAnchor < lineCurrentPos) { | |
2292 | if (currentPosPosOnLine == 0) | |
2293 | SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor)); | |
2294 | else | |
2295 | SetSelection(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor)); | |
2296 | } else { | |
2297 | if (anchorPosOnLine == 0) | |
2298 | SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor)); | |
2299 | else | |
2300 | SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1)); | |
2301 | } | |
2302 | } | |
2303 | } | |
2304 | ||
d134f170 RD |
2305 | long Editor::FindText(unsigned int iMessage, unsigned long wParam, long lParam) { |
2306 | TextToFind *ft = reinterpret_cast<TextToFind *>(lParam); | |
9ce192d4 | 2307 | int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText, |
d134f170 RD |
2308 | wParam & SCFIND_MATCHCASE, wParam & SCFIND_WHOLEWORD, |
2309 | wParam & SCFIND_WORDSTART); | |
9ce192d4 | 2310 | if (pos != -1) { |
d134f170 | 2311 | if (iMessage != EM_FINDTEXT) { |
9ce192d4 RD |
2312 | ft->chrgText.cpMin = pos; |
2313 | ft->chrgText.cpMax = pos + strlen(ft->lpstrText); | |
2314 | } | |
2315 | } | |
2316 | return pos; | |
2317 | } | |
2318 | ||
d134f170 RD |
2319 | // Relocatable search support : Searches relative to current selection |
2320 | // point and sets the selection to the found text range with | |
9ce192d4 RD |
2321 | // each search. |
2322 | ||
2323 | // Anchor following searches at current selection start: This allows | |
2324 | // multiple incremental interactive searches to be macro recorded | |
2325 | // while still setting the selection to found text so the find/select | |
2326 | // operation is self-contained. | |
2327 | void Editor::SearchAnchor() { | |
2328 | searchAnchor = SelectionStart(); | |
2329 | } | |
2330 | ||
2331 | // Find text from current search anchor: Must call SearchAnchor first. | |
2332 | // Accepts both SCI_SEARCHNEXT and SCI_SEARCHPREV. | |
2333 | // wParam contains search modes : ORed FR_MATCHCASE and FR_WHOLEWORD. | |
2334 | // lParam contains the text to search for. | |
d134f170 | 2335 | long Editor::SearchText(unsigned int iMessage, unsigned long wParam, long lParam) { |
9ce192d4 RD |
2336 | const char *txt = reinterpret_cast<char *>(lParam); |
2337 | int pos; | |
2338 | ||
2339 | if (iMessage == SCI_SEARCHNEXT) { | |
d134f170 RD |
2340 | pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt, |
2341 | wParam & SCFIND_MATCHCASE, | |
2342 | wParam & SCFIND_WHOLEWORD, | |
2343 | wParam & SCFIND_WORDSTART); | |
9ce192d4 | 2344 | } else { |
d134f170 RD |
2345 | pos = pdoc->FindText(searchAnchor, 0, txt, |
2346 | wParam & SCFIND_MATCHCASE, | |
2347 | wParam & SCFIND_WHOLEWORD, | |
2348 | wParam & SCFIND_WORDSTART); | |
9ce192d4 RD |
2349 | } |
2350 | ||
2351 | if (pos != -1) { | |
2352 | SetSelection(pos, pos + strlen(txt)); | |
2353 | } | |
2354 | ||
2355 | return pos; | |
2356 | } | |
2357 | ||
2358 | void Editor::GoToLine(int lineNo) { | |
2359 | if (lineNo > pdoc->LinesTotal()) | |
2360 | lineNo = pdoc->LinesTotal(); | |
2361 | if (lineNo < 0) | |
2362 | lineNo = 0; | |
2363 | SetEmptySelection(pdoc->LineStart(lineNo)); | |
2364 | ShowCaretAtCurrentPosition(); | |
2365 | EnsureCaretVisible(); | |
2366 | } | |
2367 | ||
2368 | static bool Close(Point pt1, Point pt2) { | |
2369 | if (abs(pt1.x - pt2.x) > 3) | |
2370 | return false; | |
2371 | if (abs(pt1.y - pt2.y) > 3) | |
2372 | return false; | |
2373 | return true; | |
2374 | } | |
2375 | ||
2376 | char *Editor::CopyRange(int start, int end) { | |
2377 | char *text = 0; | |
2378 | if (start < end) { | |
2379 | int len = end - start; | |
2380 | text = new char[len + 1]; | |
2381 | if (text) { | |
2382 | for (int i = 0; i < len; i++) { | |
2383 | text[i] = pdoc->CharAt(start + i); | |
2384 | } | |
2385 | text[len] = '\0'; | |
2386 | } | |
2387 | } | |
2388 | return text; | |
2389 | } | |
2390 | ||
2391 | int Editor::SelectionRangeLength() { | |
2392 | if (selType == selRectangle) { | |
2393 | int lineStart = pdoc->LineFromPosition(SelectionStart()); | |
2394 | int lineEnd = pdoc->LineFromPosition(SelectionEnd()); | |
2395 | int totalSize = 0; | |
d134f170 | 2396 | for (int line = lineStart; line <= lineEnd; line++) { |
9ce192d4 RD |
2397 | totalSize += SelectionEnd(line) - SelectionStart(line) + 1; |
2398 | if (pdoc->eolMode == SC_EOL_CRLF) | |
2399 | totalSize++; | |
2400 | } | |
2401 | return totalSize; | |
2402 | } else { | |
2403 | return SelectionEnd() - SelectionStart(); | |
2404 | } | |
2405 | } | |
2406 | ||
2407 | char *Editor::CopySelectionRange() { | |
2408 | if (selType == selRectangle) { | |
2409 | char *text = 0; | |
2410 | int lineStart = pdoc->LineFromPosition(SelectionStart()); | |
2411 | int lineEnd = pdoc->LineFromPosition(SelectionEnd()); | |
2412 | int totalSize = SelectionRangeLength(); | |
2413 | if (totalSize > 0) { | |
2414 | text = new char[totalSize + 1]; | |
2415 | if (text) { | |
2416 | int j = 0; | |
d134f170 RD |
2417 | for (int line = lineStart; line <= lineEnd; line++) { |
2418 | for (int i = SelectionStart(line);i < SelectionEnd(line);i++) { | |
9ce192d4 RD |
2419 | text[j++] = pdoc->CharAt(i); |
2420 | } | |
2421 | if (pdoc->eolMode != SC_EOL_LF) | |
2422 | text[j++] = '\r'; | |
2423 | if (pdoc->eolMode != SC_EOL_CR) | |
2424 | text[j++] = '\n'; | |
2425 | } | |
2426 | text[totalSize] = '\0'; | |
2427 | } | |
2428 | } | |
2429 | return text; | |
2430 | } else { | |
2431 | return CopyRange(SelectionStart(), SelectionEnd()); | |
2432 | } | |
2433 | } | |
2434 | ||
2435 | void Editor::CopySelectionIntoDrag() { | |
2436 | delete []dragChars; | |
2437 | dragChars = 0; | |
2438 | lenDrag = SelectionRangeLength(); | |
2439 | dragChars = CopySelectionRange(); | |
2440 | dragIsRectangle = selType == selRectangle; | |
2441 | if (!dragChars) { | |
2442 | lenDrag = 0; | |
2443 | } | |
2444 | } | |
2445 | ||
2446 | void Editor::SetDragPosition(int newPos) { | |
2447 | if (newPos >= 0) { | |
d134f170 | 2448 | newPos = MovePositionOutsideChar(newPos, 1); |
9ce192d4 RD |
2449 | posDrop = newPos; |
2450 | } | |
2451 | if (posDrag != newPos) { | |
2452 | caret.on = true; | |
2453 | SetTicking(true); | |
2454 | InvalidateCaret(); | |
2455 | posDrag = newPos; | |
2456 | InvalidateCaret(); | |
2457 | } | |
2458 | } | |
2459 | ||
2460 | void Editor::StartDrag() { | |
2461 | // Always handled by subclasses | |
2462 | //SetMouseCapture(true); | |
2463 | //wDraw.SetCursor(Window::cursorArrow); | |
2464 | } | |
2465 | ||
d134f170 | 2466 | |
9ce192d4 RD |
2467 | void Editor::DropAt(int position, const char *value, bool moving, bool rectangular) { |
2468 | //Platform::DebugPrintf("DropAt %d\n", inDragDrop); | |
2469 | if (inDragDrop) | |
2470 | dropWentOutside = false; | |
2471 | ||
2472 | int positionWasInSelection = PositionInSelection(position); | |
2473 | ||
d134f170 RD |
2474 | bool positionOnEdgeOfSelection = |
2475 | (position == SelectionStart()) || (position == SelectionEnd()); | |
f6bcfd97 | 2476 | |
d134f170 RD |
2477 | if ((!inDragDrop) || !(0 == positionWasInSelection) || |
2478 | (positionOnEdgeOfSelection && !moving)) { | |
9ce192d4 RD |
2479 | |
2480 | int selStart = SelectionStart(); | |
2481 | int selEnd = SelectionEnd(); | |
d134f170 | 2482 | |
9ce192d4 RD |
2483 | pdoc->BeginUndoAction(); |
2484 | ||
2485 | int positionAfterDeletion = position; | |
2486 | if (inDragDrop && moving) { | |
2487 | // Remove dragged out text | |
2488 | if (rectangular) { | |
2489 | int lineStart = pdoc->LineFromPosition(SelectionStart()); | |
2490 | int lineEnd = pdoc->LineFromPosition(SelectionEnd()); | |
d134f170 | 2491 | for (int line = lineStart; line <= lineEnd; line++) { |
9ce192d4 RD |
2492 | int startPos = SelectionStart(line); |
2493 | int endPos = SelectionEnd(line); | |
2494 | if (position >= startPos) { | |
2495 | if (position > endPos) { | |
2496 | positionAfterDeletion -= endPos - startPos; | |
2497 | } else { | |
2498 | positionAfterDeletion -= position - startPos; | |
2499 | } | |
2500 | } | |
2501 | } | |
2502 | } else { | |
2503 | if (position > selStart) { | |
2504 | positionAfterDeletion -= selEnd - selStart; | |
2505 | } | |
2506 | } | |
2507 | ClearSelection(); | |
2508 | } | |
2509 | position = positionAfterDeletion; | |
d134f170 | 2510 | |
9ce192d4 RD |
2511 | if (rectangular) { |
2512 | PasteRectangular(position, value, strlen(value)); | |
2513 | pdoc->EndUndoAction(); | |
2514 | // Should try to select new rectangle but it may not be a rectangle now so just select the drop position | |
d134f170 | 2515 | SetSelection(position, position); |
9ce192d4 | 2516 | } else { |
d134f170 | 2517 | position = MovePositionOutsideChar(position, currentPos - position); |
9ce192d4 RD |
2518 | pdoc->InsertString(position, value); |
2519 | pdoc->EndUndoAction(); | |
2520 | SetSelection(position + strlen(value), position); | |
2521 | } | |
2522 | } else if (inDragDrop) { | |
2523 | SetSelection(position, position); | |
2524 | } | |
2525 | } | |
2526 | ||
2527 | static int BeforeInOrAfter(int val, int minim, int maxim) { | |
2528 | if (val < minim) | |
2529 | return -1; | |
2530 | else if (val > maxim) | |
2531 | return 1; | |
2532 | else | |
2533 | return 0; | |
2534 | } | |
2535 | ||
2536 | int Editor::PositionInSelection(int pos) { | |
d134f170 | 2537 | pos = MovePositionOutsideChar(pos, currentPos - pos); |
9ce192d4 RD |
2538 | if (selType == selRectangle) { |
2539 | if (pos < SelectionStart()) | |
2540 | return -1; | |
2541 | if (pos > SelectionEnd()) | |
2542 | return 1; | |
2543 | int linePos = pdoc->LineFromPosition(pos); | |
2544 | return BeforeInOrAfter(pos, SelectionStart(linePos), SelectionEnd(linePos)); | |
2545 | } else { | |
2546 | if (currentPos > anchor) { | |
2547 | return BeforeInOrAfter(pos, anchor, currentPos); | |
2548 | } else if (currentPos < anchor) { | |
2549 | return BeforeInOrAfter(pos, currentPos, anchor); | |
2550 | } | |
2551 | } | |
2552 | return 1; | |
2553 | } | |
2554 | ||
2555 | bool Editor::PointInSelection(Point pt) { | |
2556 | // TODO: fix up for rectangular selection | |
2557 | int pos = PositionFromLocation(pt); | |
2558 | if (0 == PositionInSelection(pos)) { | |
2559 | if (pos == SelectionStart()) { | |
2560 | // see if just before selection | |
2561 | Point locStart = LocationFromPosition(pos); | |
2562 | if (pt.x < locStart.x) | |
2563 | return false; | |
2564 | } | |
2565 | if (pos == SelectionEnd()) { | |
2566 | // see if just after selection | |
2567 | Point locEnd = LocationFromPosition(pos); | |
2568 | if (pt.x > locEnd.x) | |
2569 | return false; | |
2570 | } | |
2571 | return true; | |
2572 | } | |
2573 | return false; | |
2574 | } | |
2575 | ||
2576 | bool Editor::PointInSelMargin(Point pt) { | |
2577 | // Really means: "Point in a margin" | |
2578 | if (vs.fixedColumnWidth > 0) { // There is a margin | |
2579 | PRectangle rcSelMargin = GetClientRectangle(); | |
2580 | rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth; | |
2581 | return rcSelMargin.Contains(pt); | |
2582 | } else { | |
2583 | return false; | |
2584 | } | |
2585 | } | |
2586 | ||
2587 | void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { | |
2588 | //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt); | |
2589 | ptMouseLast = pt; | |
2590 | int newPos = PositionFromLocation(pt); | |
d134f170 | 2591 | newPos = MovePositionOutsideChar(newPos, currentPos - newPos); |
9ce192d4 | 2592 | inDragDrop = false; |
d134f170 | 2593 | |
9ce192d4 RD |
2594 | bool processed = NotifyMarginClick(pt, shift, ctrl, alt); |
2595 | if (processed) | |
d134f170 RD |
2596 | return ; |
2597 | ||
9ce192d4 RD |
2598 | if (shift) { |
2599 | SetSelection(newPos); | |
2600 | } | |
2601 | if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) { | |
2602 | //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime); | |
2603 | SetMouseCapture(true); | |
2604 | SetEmptySelection(newPos); | |
2605 | bool doubleClick = false; | |
2606 | // Stop mouse button bounce changing selection type | |
2607 | if (curTime != lastClickTime) { | |
2608 | if (selectionType == selChar) { | |
2609 | selectionType = selWord; | |
2610 | doubleClick = true; | |
2611 | } else if (selectionType == selWord) { | |
2612 | selectionType = selLine; | |
2613 | } else { | |
2614 | selectionType = selChar; | |
2615 | originalAnchorPos = currentPos; | |
2616 | } | |
2617 | } | |
2618 | ||
2619 | if (selectionType == selWord) { | |
2620 | if (currentPos >= originalAnchorPos) { // Moved forward | |
2621 | SetSelection(pdoc->ExtendWordSelect(currentPos, 1), | |
2622 | pdoc->ExtendWordSelect(originalAnchorPos, -1)); | |
2623 | } else { // Moved backward | |
2624 | SetSelection(pdoc->ExtendWordSelect(currentPos, -1), | |
2625 | pdoc->ExtendWordSelect(originalAnchorPos, 1)); | |
2626 | } | |
2627 | } else if (selectionType == selLine) { | |
2628 | lineAnchor = LineFromLocation(pt); | |
2629 | SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor)); | |
2630 | //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos); | |
2631 | } | |
2632 | else { | |
2633 | SetEmptySelection(currentPos); | |
2634 | } | |
2635 | //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos); | |
2636 | if (doubleClick) | |
2637 | NotifyDoubleClick(pt, shift); | |
2638 | } else { // Single click | |
2639 | if (PointInSelMargin(pt)) { | |
2640 | if (ctrl) { | |
2641 | SelectAll(); | |
2642 | lastClickTime = curTime; | |
d134f170 | 2643 | return ; |
9ce192d4 RD |
2644 | } |
2645 | lineAnchor = LineFromLocation(pt); | |
2646 | // While experimenting with folding turn off line selection | |
2647 | if (!shift) { | |
2648 | // Single click in margin: select whole line | |
2649 | SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor)); | |
2650 | } else { | |
2651 | // Single shift+click in margin: select from anchor to beginning of clicked line | |
2652 | SetSelection(pdoc->LineStart(lineAnchor), anchor); | |
2653 | } | |
2654 | SetDragPosition(invalidPosition); | |
2655 | SetMouseCapture(true); | |
2656 | selectionType = selLine; | |
2657 | } else { | |
2658 | if (!shift) { | |
2659 | inDragDrop = PointInSelection(pt); | |
2660 | } | |
2661 | if (inDragDrop) { | |
2662 | SetMouseCapture(false); | |
2663 | SetDragPosition(newPos); | |
2664 | CopySelectionIntoDrag(); | |
2665 | StartDrag(); | |
2666 | } else { | |
2667 | selType = alt ? selRectangle : selStream; | |
2668 | xStartSelect = pt.x - vs.fixedColumnWidth + xOffset; | |
2669 | xEndSelect = pt.x - vs.fixedColumnWidth + xOffset; | |
2670 | SetDragPosition(invalidPosition); | |
2671 | SetMouseCapture(true); | |
2672 | if (!shift) | |
2673 | SetEmptySelection(newPos); | |
2674 | selectionType = selChar; | |
2675 | originalAnchorPos = currentPos; | |
2676 | } | |
2677 | } | |
2678 | } | |
2679 | lastClickTime = curTime; | |
2680 | lastXChosen = pt.x; | |
2681 | ShowCaretAtCurrentPosition(); | |
2682 | } | |
2683 | ||
2684 | void Editor::ButtonMove(Point pt) { | |
2685 | //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y); | |
2686 | if (HaveMouseCapture()) { | |
2687 | xEndSelect = pt.x - vs.fixedColumnWidth + xOffset; | |
2688 | ptMouseLast = pt; | |
2689 | int movePos = PositionFromLocation(pt); | |
d134f170 | 2690 | movePos = MovePositionOutsideChar(movePos, currentPos - movePos); |
9ce192d4 RD |
2691 | if (posDrag >= 0) { |
2692 | SetDragPosition(movePos); | |
2693 | } else { | |
2694 | if (selectionType == selChar) { | |
2695 | SetSelection(movePos); | |
2696 | } else if (selectionType == selWord) { | |
2697 | // Continue selecting by word | |
2698 | if (currentPos > originalAnchorPos) { // Moved forward | |
2699 | SetSelection(pdoc->ExtendWordSelect(movePos, 1), | |
2700 | pdoc->ExtendWordSelect(originalAnchorPos, -1)); | |
2701 | } else { // Moved backward | |
2702 | SetSelection(pdoc->ExtendWordSelect(movePos, -1), | |
2703 | pdoc->ExtendWordSelect(originalAnchorPos, 1)); | |
2704 | } | |
2705 | } else { | |
2706 | // Continue selecting by line | |
2707 | int lineMove = LineFromLocation(pt); | |
2708 | if (lineAnchor < lineMove) { | |
2709 | SetSelection(pdoc->LineStart(lineMove + 1), | |
d134f170 | 2710 | pdoc->LineStart(lineAnchor)); |
9ce192d4 RD |
2711 | } else { |
2712 | SetSelection(pdoc->LineStart(lineMove), | |
d134f170 | 2713 | pdoc->LineStart(lineAnchor + 1)); |
9ce192d4 RD |
2714 | } |
2715 | } | |
2716 | } | |
2717 | EnsureCaretVisible(false); | |
2718 | } else { | |
2719 | if (vs.fixedColumnWidth > 0) { // There is a margin | |
2720 | if (PointInSelMargin(pt)) { | |
2721 | wDraw.SetCursor(Window::cursorReverseArrow); | |
d134f170 | 2722 | return ; // No need to test for selection |
9ce192d4 | 2723 | } |
d134f170 | 2724 | |
9ce192d4 RD |
2725 | } |
2726 | // Display regular (drag) cursor over selection | |
2727 | if (PointInSelection(pt)) | |
2728 | wDraw.SetCursor(Window::cursorArrow); | |
2729 | else | |
2730 | wDraw.SetCursor(Window::cursorText); | |
2731 | } | |
2732 | ||
2733 | } | |
2734 | ||
2735 | void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) { | |
2736 | //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture()); | |
2737 | if (HaveMouseCapture()) { | |
2738 | if (PointInSelMargin(pt)) { | |
2739 | wDraw.SetCursor(Window::cursorReverseArrow); | |
2740 | } else { | |
2741 | wDraw.SetCursor(Window::cursorText); | |
2742 | } | |
2743 | xEndSelect = pt.x - vs.fixedColumnWidth + xOffset; | |
2744 | ptMouseLast = pt; | |
2745 | SetMouseCapture(false); | |
2746 | int newPos = PositionFromLocation(pt); | |
d134f170 | 2747 | newPos = MovePositionOutsideChar(newPos, currentPos - newPos); |
9ce192d4 RD |
2748 | if (inDragDrop) { |
2749 | int selStart = SelectionStart(); | |
2750 | int selEnd = SelectionEnd(); | |
2751 | if (selStart < selEnd) { | |
2752 | if (dragChars && lenDrag) { | |
2753 | if (ctrl) { | |
2754 | pdoc->InsertString(newPos, dragChars, lenDrag); | |
2755 | SetSelection(newPos, newPos + lenDrag); | |
2756 | } else if (newPos < selStart) { | |
2757 | pdoc->DeleteChars(selStart, lenDrag); | |
2758 | pdoc->InsertString(newPos, dragChars, lenDrag); | |
2759 | SetSelection(newPos, newPos + lenDrag); | |
2760 | } else if (newPos > selEnd) { | |
2761 | pdoc->DeleteChars(selStart, lenDrag); | |
2762 | newPos -= lenDrag; | |
2763 | pdoc->InsertString(newPos, dragChars, lenDrag); | |
2764 | SetSelection(newPos, newPos + lenDrag); | |
2765 | } else { | |
2766 | SetEmptySelection(newPos); | |
2767 | } | |
2768 | delete []dragChars; | |
2769 | dragChars = 0; | |
2770 | lenDrag = 0; | |
2771 | } | |
2772 | selectionType = selChar; | |
2773 | } | |
2774 | } else { | |
2775 | if (selectionType == selChar) { | |
2776 | SetSelection(newPos); | |
2777 | } | |
2778 | } | |
2779 | lastClickTime = curTime; | |
2780 | lastClick = pt; | |
2781 | lastXChosen = pt.x; | |
2782 | inDragDrop = false; | |
2783 | EnsureCaretVisible(false); | |
2784 | } | |
2785 | } | |
2786 | ||
2787 | // Called frequently to perform background UI including | |
2788 | // caret blinking and automatic scrolling. | |
2789 | void Editor::Tick() { | |
2790 | if (HaveMouseCapture()) { | |
2791 | // Auto scroll | |
2792 | ButtonMove(ptMouseLast); | |
2793 | } | |
2794 | if (caret.period > 0) { | |
2795 | timer.ticksToWait -= timer.tickSize; | |
2796 | if (timer.ticksToWait <= 0) { | |
2797 | caret.on = !caret.on; | |
2798 | timer.ticksToWait = caret.period; | |
2799 | InvalidateCaret(); | |
2800 | } | |
2801 | } | |
2802 | } | |
2803 | ||
2804 | static bool IsIn(int a, int minimum, int maximum) { | |
2805 | return (a >= minimum) && (a <= maximum); | |
2806 | } | |
2807 | ||
2808 | static bool IsOverlap(int mina, int maxa, int minb, int maxb) { | |
d134f170 RD |
2809 | return |
2810 | IsIn(mina, minb, maxb) || | |
2811 | IsIn(maxa, minb, maxb) || | |
2812 | IsIn(minb, mina, maxa) || | |
2813 | IsIn(maxb, mina, maxa); | |
9ce192d4 RD |
2814 | } |
2815 | ||
2816 | void Editor::CheckForChangeOutsidePaint(Range r) { | |
2817 | if (paintState == painting && !paintingAllText) { | |
2818 | //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end); | |
2819 | if (!r.Valid()) | |
d134f170 RD |
2820 | return ; |
2821 | ||
9ce192d4 RD |
2822 | PRectangle rcText = GetTextRectangle(); |
2823 | // Determine number of lines displayed including a possible partially displayed last line | |
2824 | int linesDisplayed = (rcText.bottom - rcText.top - 1) / vs.lineHeight + 1; | |
2825 | int bottomLine = topLine + linesDisplayed - 1; | |
d134f170 | 2826 | |
9ce192d4 RD |
2827 | int lineRangeStart = cs.DisplayFromDoc(pdoc->LineFromPosition(r.start)); |
2828 | int lineRangeEnd = cs.DisplayFromDoc(pdoc->LineFromPosition(r.end)); | |
2829 | if (!IsOverlap(topLine, bottomLine, lineRangeStart, lineRangeEnd)) { | |
2830 | //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n", | |
2831 | // lineRangeStart, lineRangeEnd, topLine, bottomLine); | |
d134f170 | 2832 | return ; |
9ce192d4 | 2833 | } |
d134f170 | 2834 | |
9ce192d4 RD |
2835 | // Assert rcPaint contained within or equal to rcText |
2836 | if (rcPaint.top > rcText.top) { | |
d134f170 RD |
2837 | // does range intersect rcText.top .. rcPaint.top |
2838 | int paintTopLine = ((rcPaint.top - rcText.top - 1) / vs.lineHeight) + topLine; | |
9ce192d4 RD |
2839 | // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle |
2840 | if (IsOverlap(topLine, paintTopLine, lineRangeStart, lineRangeEnd)) { | |
d134f170 | 2841 | //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n", |
9ce192d4 RD |
2842 | // lineRangeStart, lineRangeEnd, topLine, paintTopLine); |
2843 | paintState = paintAbandoned; | |
d134f170 | 2844 | return ; |
9ce192d4 RD |
2845 | } |
2846 | } | |
2847 | if (rcPaint.bottom < rcText.bottom) { | |
2848 | // does range intersect rcPaint.bottom .. rcText.bottom | |
d134f170 | 2849 | int paintBottomLine = ((rcPaint.bottom - rcText.top - 1) / vs.lineHeight + 1) + topLine; |
9ce192d4 RD |
2850 | // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle |
2851 | if (IsOverlap(paintBottomLine, bottomLine, lineRangeStart, lineRangeEnd)) { | |
d134f170 | 2852 | //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n", |
9ce192d4 RD |
2853 | // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine); |
2854 | paintState = paintAbandoned; | |
d134f170 | 2855 | return ; |
9ce192d4 RD |
2856 | } |
2857 | } | |
2858 | } | |
2859 | } | |
2860 | ||
2861 | char BraceOpposite(char ch) { | |
2862 | switch (ch) { | |
d134f170 RD |
2863 | case '(': |
2864 | return ')'; | |
2865 | case ')': | |
2866 | return '('; | |
2867 | case '[': | |
2868 | return ']'; | |
2869 | case ']': | |
2870 | return '['; | |
2871 | case '{': | |
2872 | return '}'; | |
2873 | case '}': | |
2874 | return '{'; | |
2875 | case '<': | |
2876 | return '>'; | |
2877 | case '>': | |
2878 | return '<'; | |
2879 | default: | |
2880 | return '\0'; | |
9ce192d4 RD |
2881 | } |
2882 | } | |
2883 | ||
2884 | // TODO: should be able to extend styled region to find matching brace | |
2885 | // TODO: may need to make DBCS safe | |
2886 | // so should be moved into Document | |
f6bcfd97 | 2887 | int Editor::BraceMatch(int position, int /*maxReStyle*/) { |
9ce192d4 RD |
2888 | char chBrace = pdoc->CharAt(position); |
2889 | char chSeek = BraceOpposite(chBrace); | |
f6bcfd97 | 2890 | if (chSeek == '\0') |
9ce192d4 | 2891 | return - 1; |
f6bcfd97 | 2892 | char styBrace = static_cast<char>( |
d134f170 | 2893 | pdoc->StyleAt(position) & pdoc->stylingBitsMask); |
9ce192d4 RD |
2894 | int direction = -1; |
2895 | if (chBrace == '(' || chBrace == '[' || chBrace == '{' || chBrace == '<') | |
2896 | direction = 1; | |
2897 | int depth = 1; | |
2898 | position = position + direction; | |
2899 | while ((position >= 0) && (position < pdoc->Length())) { | |
2900 | char chAtPos = pdoc->CharAt(position); | |
f6bcfd97 | 2901 | char styAtPos = static_cast<char>(pdoc->StyleAt(position) & pdoc->stylingBitsMask); |
9ce192d4 RD |
2902 | if ((position > pdoc->GetEndStyled()) || (styAtPos == styBrace)) { |
2903 | if (chAtPos == chBrace) | |
2904 | depth++; | |
2905 | if (chAtPos == chSeek) | |
2906 | depth--; | |
2907 | if (depth == 0) | |
2908 | return position; | |
2909 | } | |
2910 | position = position + direction; | |
2911 | } | |
2912 | return - 1; | |
2913 | } | |
2914 | ||
2915 | void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) { | |
2916 | if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) { | |
d134f170 | 2917 | if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) { |
9ce192d4 RD |
2918 | CheckForChangeOutsidePaint(Range(braces[0])); |
2919 | CheckForChangeOutsidePaint(Range(pos0)); | |
2920 | braces[0] = pos0; | |
2921 | } | |
d134f170 | 2922 | if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) { |
9ce192d4 RD |
2923 | CheckForChangeOutsidePaint(Range(braces[1])); |
2924 | CheckForChangeOutsidePaint(Range(pos1)); | |
2925 | braces[1] = pos1; | |
2926 | } | |
2927 | bracesMatchStyle = matchStyle; | |
2928 | if (paintState == notPainting) { | |
2929 | Redraw(); | |
2930 | } | |
2931 | } | |
2932 | } | |
2933 | ||
2934 | void Editor::SetDocPointer(Document *document) { | |
2935 | //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document); | |
2936 | pdoc->RemoveWatcher(this, 0); | |
2937 | pdoc->Release(); | |
2938 | if (document == NULL) { | |
2939 | pdoc = new Document(); | |
2940 | } else { | |
2941 | pdoc = document; | |
2942 | } | |
2943 | pdoc->AddRef(); | |
f6bcfd97 BP |
2944 | // Reset the contraction state to fully shown. |
2945 | cs.Clear(); | |
d134f170 | 2946 | cs.InsertLines(0, pdoc->LinesTotal() - 1); |
f6bcfd97 | 2947 | |
9ce192d4 RD |
2948 | pdoc->AddWatcher(this, 0); |
2949 | Redraw(); | |
2950 | SetScrollBars(); | |
2951 | } | |
2952 | ||
2953 | // Recursively expand a fold, making lines visible except where they have an unexpanded parent | |
2954 | void Editor::Expand(int &line, bool doExpand) { | |
2955 | int lineMaxSubord = pdoc->GetLastChild(line); | |
2956 | line++; | |
2957 | while (line <= lineMaxSubord) { | |
2958 | if (doExpand) | |
2959 | cs.SetVisible(line, line, true); | |
2960 | int level = pdoc->GetLevel(line); | |
2961 | if (level & SC_FOLDLEVELHEADERFLAG) { | |
2962 | if (doExpand && cs.GetExpanded(line)) { | |
2963 | Expand(line, true); | |
2964 | } else { | |
2965 | Expand(line, false); | |
2966 | } | |
2967 | } else { | |
2968 | line++; | |
2969 | } | |
2970 | } | |
2971 | } | |
2972 | ||
2973 | void Editor::ToggleContraction(int line) { | |
2974 | if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) { | |
2975 | if (cs.GetExpanded(line)) { | |
2976 | int lineMaxSubord = pdoc->GetLastChild(line); | |
2977 | cs.SetExpanded(line, 0); | |
2978 | if (lineMaxSubord > line) { | |
d134f170 | 2979 | cs.SetVisible(line + 1, lineMaxSubord, false); |
9ce192d4 RD |
2980 | SetScrollBars(); |
2981 | Redraw(); | |
2982 | } | |
2983 | } else { | |
2984 | cs.SetExpanded(line, 1); | |
2985 | Expand(line, true); | |
2986 | SetScrollBars(); | |
2987 | Redraw(); | |
2988 | } | |
2989 | } | |
2990 | } | |
2991 | ||
2992 | // Recurse up from this line to find any folds that prevent this line from being visible | |
2993 | // and unfold them all. | |
2994 | void Editor::EnsureLineVisible(int line) { | |
2995 | if (!cs.GetVisible(line)) { | |
2996 | int lineParent = pdoc->GetFoldParent(line); | |
2997 | if (lineParent >= 0) { | |
2998 | if (line != lineParent) | |
2999 | EnsureLineVisible(lineParent); | |
3000 | if (!cs.GetExpanded(lineParent)) { | |
3001 | cs.SetExpanded(lineParent, 1); | |
3002 | Expand(lineParent, true); | |
3003 | } | |
3004 | } | |
3005 | SetScrollBars(); | |
3006 | Redraw(); | |
3007 | } | |
3008 | } | |
3009 | ||
d134f170 | 3010 | static bool ValidMargin(unsigned long wParam) { |
f6bcfd97 BP |
3011 | return wParam < ViewStyle::margins; |
3012 | } | |
3013 | ||
3014 | ||
d134f170 | 3015 | long Editor::WndProc(unsigned int iMessage, unsigned long wParam, long lParam) { |
9ce192d4 RD |
3016 | //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam); |
3017 | ||
3018 | // Optional macro recording hook | |
3019 | #ifdef MACRO_SUPPORT | |
3020 | if (recordingMacro) | |
3021 | NotifyMacroRecord(iMessage, wParam, lParam); | |
d134f170 | 3022 | #endif |
9ce192d4 RD |
3023 | |
3024 | switch (iMessage) { | |
3025 | ||
3026 | case WM_GETTEXT: | |
d134f170 | 3027 | case SCI_GETTEXT: |
9ce192d4 RD |
3028 | { |
3029 | if (lParam == 0) | |
3030 | return 0; | |
3031 | char *ptr = reinterpret_cast<char *>(lParam); | |
3032 | unsigned int iChar = 0; | |
d134f170 | 3033 | for (; iChar < wParam - 1; iChar++) |
9ce192d4 RD |
3034 | ptr[iChar] = pdoc->CharAt(iChar); |
3035 | ptr[iChar] = '\0'; | |
3036 | return iChar; | |
3037 | } | |
3038 | ||
3039 | case WM_SETTEXT: | |
d134f170 | 3040 | case SCI_SETTEXT: |
9ce192d4 RD |
3041 | { |
3042 | if (lParam == 0) | |
3043 | return FALSE; | |
3044 | pdoc->DeleteChars(0, pdoc->Length()); | |
3045 | SetEmptySelection(0); | |
3046 | pdoc->InsertString(0, reinterpret_cast<char *>(lParam)); | |
3047 | return TRUE; | |
3048 | } | |
3049 | ||
3050 | case WM_GETTEXTLENGTH: | |
d134f170 | 3051 | case SCI_GETTEXTLENGTH: |
9ce192d4 RD |
3052 | return pdoc->Length(); |
3053 | ||
9ce192d4 | 3054 | case WM_CUT: |
d134f170 | 3055 | case SCI_CUT: |
9ce192d4 RD |
3056 | Cut(); |
3057 | SetLastXChosen(); | |
3058 | break; | |
3059 | ||
3060 | case WM_COPY: | |
d134f170 | 3061 | case SCI_COPY: |
9ce192d4 RD |
3062 | Copy(); |
3063 | break; | |
3064 | ||
3065 | case WM_PASTE: | |
d134f170 | 3066 | case SCI_PASTE: |
9ce192d4 RD |
3067 | Paste(); |
3068 | SetLastXChosen(); | |
f6bcfd97 | 3069 | EnsureCaretVisible(); |
9ce192d4 RD |
3070 | break; |
3071 | ||
3072 | case WM_CLEAR: | |
d134f170 | 3073 | case SCI_CLEAR: |
9ce192d4 RD |
3074 | Clear(); |
3075 | SetLastXChosen(); | |
3076 | break; | |
3077 | ||
3078 | case WM_UNDO: | |
d134f170 | 3079 | case SCI_UNDO: |
9ce192d4 RD |
3080 | Undo(); |
3081 | SetLastXChosen(); | |
3082 | break; | |
3083 | ||
3084 | // Edit control mesages | |
3085 | ||
3086 | // Not supported (no-ops): | |
3087 | // EM_GETWORDBREAKPROC | |
3088 | // EM_GETWORDBREAKPROCEX | |
3089 | // EM_SETWORDBREAKPROC | |
3090 | // EM_SETWORDBREAKPROCEX | |
3091 | // EM_GETWORDWRAPMODE | |
3092 | // EM_SETWORDWRAPMODE | |
3093 | // EM_LIMITTEXT | |
3094 | // EM_EXLIMITTEXT | |
3095 | // EM_SETRECT | |
3096 | // EM_SETRECTNP | |
3097 | // EM_FMTLINES | |
3098 | // EM_GETHANDLE | |
3099 | // EM_SETHANDLE | |
3100 | // EM_GETPASSWORDCHAR | |
3101 | // EM_SETPASSWORDCHAR | |
3102 | // EM_SETTABSTOPS | |
3103 | // EM_FINDWORDBREAK | |
3104 | // EM_GETCHARFORMAT | |
3105 | // EM_SETCHARFORMAT | |
3106 | // EM_GETOLEINTERFACE | |
3107 | // EM_SETOLEINTERFACE | |
3108 | // EM_SETOLECALLBACK | |
3109 | // EM_GETPARAFORMAT | |
3110 | // EM_SETPARAFORMAT | |
3111 | // EM_PASTESPECIAL | |
3112 | // EM_REQUESTRESIZE | |
3113 | // EM_GETBKGNDCOLOR | |
3114 | // EM_SETBKGNDCOLOR | |
3115 | // EM_STREAMIN | |
3116 | // EM_STREAMOUT | |
3117 | // EM_GETIMECOLOR | |
3118 | // EM_SETIMECOLOR | |
3119 | // EM_GETIMEOPTIONS | |
3120 | // EM_SETIMEOPTIONS | |
3121 | // EM_GETOPTIONS | |
3122 | // EM_SETOPTIONS | |
3123 | // EM_GETPUNCTUATION | |
3124 | // EM_SETPUNCTUATION | |
3125 | // EM_GETTHUMB | |
f6bcfd97 | 3126 | // EM_SETTARGETDEVICE |
9ce192d4 RD |
3127 | |
3128 | // Not supported but should be: | |
3129 | // EM_GETEVENTMASK | |
3130 | // EM_SETEVENTMASK | |
3131 | // For printing: | |
3132 | // EM_DISPLAYBAND | |
9ce192d4 RD |
3133 | |
3134 | case EM_CANUNDO: | |
d134f170 | 3135 | case SCI_CANUNDO: |
9ce192d4 RD |
3136 | return pdoc->CanUndo() ? TRUE : FALSE; |
3137 | ||
3138 | case EM_UNDO: | |
3139 | Undo(); | |
f6bcfd97 | 3140 | SetLastXChosen(); |
9ce192d4 RD |
3141 | break; |
3142 | ||
3143 | case EM_EMPTYUNDOBUFFER: | |
d134f170 | 3144 | case SCI_EMPTYUNDOBUFFER: |
9ce192d4 RD |
3145 | pdoc->DeleteUndoHistory(); |
3146 | return 0; | |
3147 | ||
3148 | case EM_GETFIRSTVISIBLELINE: | |
d134f170 | 3149 | case SCI_GETFIRSTVISIBLELINE: |
9ce192d4 RD |
3150 | return topLine; |
3151 | ||
3152 | case EM_GETLINE: { | |
3153 | if (lParam == 0) | |
3154 | return 0; | |
3155 | int lineStart = pdoc->LineStart(wParam); | |
3156 | int lineEnd = pdoc->LineStart(wParam + 1); | |
3157 | char *ptr = reinterpret_cast<char *>(lParam); | |
d134f170 | 3158 | short *pBufSize = reinterpret_cast<short *>(lParam); |
9ce192d4 RD |
3159 | if (*pBufSize < lineEnd - lineStart) { |
3160 | ptr[0] = '\0'; // If no characters copied have to put a NUL into buffer | |
3161 | return 0; | |
3162 | } | |
3163 | int iPlace = 0; | |
3164 | for (int iChar = lineStart; iChar < lineEnd; iChar++) | |
3165 | ptr[iPlace++] = pdoc->CharAt(iChar); | |
3166 | return iPlace; | |
3167 | } | |
3168 | ||
d134f170 RD |
3169 | case SCI_GETLINE: { |
3170 | if (lParam == 0) | |
3171 | return 0; | |
3172 | int lineStart = pdoc->LineStart(wParam); | |
3173 | int lineEnd = pdoc->LineStart(wParam + 1); | |
3174 | char *ptr = reinterpret_cast<char *>(lParam); | |
3175 | int iPlace = 0; | |
3176 | for (int iChar = lineStart; iChar < lineEnd; iChar++) | |
3177 | ptr[iPlace++] = pdoc->CharAt(iChar); | |
3178 | return iPlace; | |
3179 | } | |
3180 | ||
9ce192d4 | 3181 | case EM_GETLINECOUNT: |
d134f170 | 3182 | case SCI_GETLINECOUNT: |
9ce192d4 RD |
3183 | if (pdoc->LinesTotal() == 0) |
3184 | return 1; | |
3185 | else | |
3186 | return pdoc->LinesTotal(); | |
3187 | ||
3188 | case EM_GETMODIFY: | |
d134f170 | 3189 | case SCI_GETMODIFY: |
9ce192d4 RD |
3190 | return !pdoc->IsSavePoint(); |
3191 | ||
9ce192d4 RD |
3192 | case EM_GETRECT: |
3193 | if (lParam == 0) | |
3194 | return 0; | |
3195 | *(reinterpret_cast<PRectangle *>(lParam)) = GetClientRectangle(); | |
3196 | break; | |
3197 | ||
3198 | case EM_GETSEL: | |
3199 | if (wParam) | |
3200 | *reinterpret_cast<int *>(wParam) = SelectionStart(); | |
3201 | if (lParam) | |
3202 | *reinterpret_cast<int *>(lParam) = SelectionEnd(); | |
d134f170 RD |
3203 | return Platform::LongFromTwoShorts( |
3204 | static_cast<short>(SelectionStart()), | |
3205 | static_cast<short>(SelectionEnd())); | |
9ce192d4 RD |
3206 | |
3207 | case EM_EXGETSEL: { | |
3208 | if (lParam == 0) | |
3209 | return 0; | |
d134f170 | 3210 | CharacterRange *pCR = reinterpret_cast<CharacterRange *>(lParam); |
9ce192d4 RD |
3211 | pCR->cpMin = SelectionStart(); |
3212 | pCR->cpMax = SelectionEnd(); | |
3213 | } | |
3214 | break; | |
3215 | ||
d134f170 RD |
3216 | case EM_SETSEL: |
3217 | case SCI_SETSEL: { | |
9ce192d4 RD |
3218 | int nStart = static_cast<int>(wParam); |
3219 | int nEnd = static_cast<int>(lParam); | |
3220 | if (nEnd < 0) | |
3221 | nEnd = pdoc->Length(); | |
3222 | if (nStart < 0) | |
3223 | nStart = nEnd; // Remove selection | |
d134f170 | 3224 | selType = selStream; |
9ce192d4 RD |
3225 | SetSelection(nEnd, nStart); |
3226 | EnsureCaretVisible(); | |
3227 | } | |
3228 | break; | |
3229 | ||
3230 | case EM_EXSETSEL: { | |
3231 | if (lParam == 0) | |
3232 | return 0; | |
d134f170 RD |
3233 | CharacterRange *pCR = reinterpret_cast<CharacterRange *>(lParam); |
3234 | selType = selStream; | |
9ce192d4 RD |
3235 | if (pCR->cpMax == -1) { |
3236 | SetSelection(pCR->cpMin, pdoc->Length()); | |
3237 | } else { | |
3238 | SetSelection(pCR->cpMin, pCR->cpMax); | |
3239 | } | |
3240 | EnsureCaretVisible(); | |
3241 | return pdoc->LineFromPosition(SelectionStart()); | |
3242 | } | |
3243 | ||
d134f170 RD |
3244 | case EM_GETSELTEXT: |
3245 | case SCI_GETSELTEXT: { | |
9ce192d4 RD |
3246 | if (lParam == 0) |
3247 | return 0; | |
3248 | char *ptr = reinterpret_cast<char *>(lParam); | |
3249 | int selSize = SelectionRangeLength(); | |
3250 | char *text = CopySelectionRange(); | |
3251 | int iChar = 0; | |
3252 | if (text) { | |
3253 | for (; iChar < selSize; iChar++) | |
3254 | ptr[iChar] = text[iChar]; | |
3255 | ptr[iChar] = '\0'; | |
3256 | delete []text; | |
3257 | } | |
3258 | return iChar; | |
3259 | } | |
3260 | ||
9ce192d4 RD |
3261 | case EM_LINEFROMCHAR: |
3262 | if (static_cast<int>(wParam) < 0) | |
3263 | wParam = SelectionStart(); | |
3264 | return pdoc->LineFromPosition(wParam); | |
3265 | ||
3266 | case EM_EXLINEFROMCHAR: | |
3267 | if (static_cast<int>(lParam) < 0) | |
3268 | lParam = SelectionStart(); // Not specified, but probably OK | |
3269 | return pdoc->LineFromPosition(lParam); | |
3270 | ||
d134f170 RD |
3271 | case SCI_LINEFROMPOSITION: |
3272 | if (static_cast<int>(wParam) < 0) | |
3273 | return 0; | |
3274 | return pdoc->LineFromPosition(wParam); | |
3275 | ||
9ce192d4 | 3276 | case EM_LINEINDEX: |
d134f170 | 3277 | case SCI_POSITIONFROMLINE: |
9ce192d4 RD |
3278 | if (static_cast<int>(wParam) < 0) |
3279 | wParam = pdoc->LineFromPosition(SelectionStart()); | |
3280 | if (wParam == 0) | |
3281 | return 0; // Even if there is no text, there is a first line that starts at 0 | |
3282 | if (static_cast<int>(wParam) > pdoc->LinesTotal()) | |
3283 | return - 1; | |
3284 | //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway... | |
3285 | // return -1; | |
3286 | return pdoc->LineStart(wParam); | |
3287 | ||
d134f170 | 3288 | case EM_LINELENGTH: { |
9ce192d4 RD |
3289 | if (static_cast<int>(wParam) < 0) // Who use this anyway? |
3290 | return 0; // Should be... Too complex to describe here, see MS specs! | |
3291 | if (static_cast<int>(wParam) > pdoc->Length()) // Useful test, anyway... | |
3292 | return 0; | |
3293 | int line = pdoc->LineFromPosition(wParam); | |
3294 | int charsOnLine = 0; | |
3295 | for (int pos = pdoc->LineStart(line); pos < pdoc->LineStart(line + 1); pos++) { | |
3296 | if ((pdoc->CharAt(pos) != '\r') && (pdoc->CharAt(pos) != '\n')) | |
3297 | charsOnLine++; | |
3298 | } | |
3299 | return charsOnLine; | |
3300 | } | |
3301 | ||
3302 | // Replacement of the old Scintilla interpretation of EM_LINELENGTH | |
3303 | case SCI_LINELENGTH: | |
3304 | if ((static_cast<int>(wParam) < 0) || | |
3305 | (static_cast<int>(wParam) > pdoc->LineFromPosition(pdoc->Length()))) | |
3306 | return 0; | |
3307 | return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam); | |
3308 | ||
d134f170 RD |
3309 | case EM_REPLACESEL: |
3310 | case SCI_REPLACESEL: { | |
9ce192d4 RD |
3311 | if (lParam == 0) |
3312 | return 0; | |
3313 | pdoc->BeginUndoAction(); | |
3314 | ClearSelection(); | |
3315 | char *replacement = reinterpret_cast<char *>(lParam); | |
3316 | pdoc->InsertString(currentPos, replacement); | |
3317 | pdoc->EndUndoAction(); | |
3318 | SetEmptySelection(currentPos + strlen(replacement)); | |
3319 | EnsureCaretVisible(); | |
3320 | } | |
3321 | break; | |
3322 | ||
3323 | case EM_LINESCROLL: | |
d134f170 | 3324 | case SCI_LINESCROLL: |
9ce192d4 RD |
3325 | ScrollTo(topLine + lParam); |
3326 | HorizontalScrollTo(xOffset + wParam * vs.spaceWidth); | |
3327 | return TRUE; | |
3328 | ||
3329 | case EM_SCROLLCARET: | |
d134f170 | 3330 | case SCI_SCROLLCARET: |
9ce192d4 RD |
3331 | EnsureCaretVisible(); |
3332 | break; | |
3333 | ||
3334 | case EM_SETREADONLY: | |
d134f170 | 3335 | case SCI_SETREADONLY: |
9ce192d4 RD |
3336 | pdoc->SetReadOnly(wParam); |
3337 | return TRUE; | |
3338 | ||
d134f170 RD |
3339 | case SCI_GETREADONLY: |
3340 | return pdoc->IsReadOnly(); | |
3341 | ||
9ce192d4 | 3342 | case EM_CANPASTE: |
d134f170 | 3343 | case SCI_CANPASTE: |
9ce192d4 RD |
3344 | return 1; |
3345 | ||
3346 | case EM_CHARFROMPOS: { | |
3347 | if (lParam == 0) | |
3348 | return 0; | |
3349 | Point *ppt = reinterpret_cast<Point *>(lParam); | |
3350 | int pos = PositionFromLocation(*ppt); | |
3351 | int line = pdoc->LineFromPosition(pos); | |
d134f170 RD |
3352 | return Platform::LongFromTwoShorts( |
3353 | static_cast<short>(pos), static_cast < short > (line)); | |
9ce192d4 RD |
3354 | } |
3355 | ||
3356 | case EM_POSFROMCHAR: { | |
3357 | // The MS specs for this have changed 3 times: using the RichEdit 3 version | |
3358 | if (wParam == 0) | |
3359 | return 0; | |
3360 | Point *ppt = reinterpret_cast<Point *>(wParam); | |
3361 | if (lParam < 0) { | |
3362 | *ppt = Point(0, 0); | |
3363 | } else { | |
3364 | *ppt = LocationFromPosition(lParam); | |
3365 | } | |
3366 | return 0; | |
3367 | } | |
3368 | ||
d134f170 RD |
3369 | case SCI_POINTXFROMPOSITION: |
3370 | if (lParam < 0) { | |
3371 | return 0; | |
3372 | } else { | |
3373 | Point pt = LocationFromPosition(lParam); | |
3374 | return pt.x; | |
3375 | } | |
3376 | ||
3377 | case SCI_POINTYFROMPOSITION: | |
3378 | if (lParam < 0) { | |
3379 | return 0; | |
3380 | } else { | |
3381 | Point pt = LocationFromPosition(lParam); | |
3382 | return pt.y; | |
3383 | } | |
3384 | ||
9ce192d4 RD |
3385 | case EM_FINDTEXT: |
3386 | return FindText(iMessage, wParam, lParam); | |
3387 | ||
3388 | case EM_FINDTEXTEX: | |
d134f170 | 3389 | case SCI_FINDTEXT: |
9ce192d4 RD |
3390 | return FindText(iMessage, wParam, lParam); |
3391 | ||
d134f170 RD |
3392 | case EM_GETTEXTRANGE: |
3393 | case SCI_GETTEXTRANGE: { | |
9ce192d4 RD |
3394 | if (lParam == 0) |
3395 | return 0; | |
d134f170 | 3396 | TextRange *tr = reinterpret_cast<TextRange *>(lParam); |
9ce192d4 RD |
3397 | int cpMax = tr->chrg.cpMax; |
3398 | if (cpMax == -1) | |
3399 | cpMax = pdoc->Length(); | |
3400 | int len = cpMax - tr->chrg.cpMin; // No -1 as cpMin and cpMax are referring to inter character positions | |
3401 | pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len); | |
3402 | // Spec says copied text is terminated with a NUL | |
3403 | tr->lpstrText[len] = '\0'; | |
3404 | return len; // Not including NUL | |
3405 | } | |
3406 | ||
d134f170 | 3407 | |
9ce192d4 | 3408 | case EM_SELECTIONTYPE: |
d134f170 | 3409 | #ifdef SEL_EMPTY |
9ce192d4 RD |
3410 | if (currentPos == anchor) |
3411 | return SEL_EMPTY; | |
3412 | else | |
3413 | return SEL_TEXT; | |
d134f170 RD |
3414 | #else |
3415 | return 0; | |
3416 | #endif | |
9ce192d4 RD |
3417 | |
3418 | case EM_HIDESELECTION: | |
3419 | hideSelection = wParam; | |
3420 | Redraw(); | |
3421 | break; | |
3422 | ||
3423 | case EM_FORMATRANGE: | |
d134f170 RD |
3424 | case SCI_FORMATRANGE: |
3425 | return FormatRange(wParam, reinterpret_cast<RangeToFormat *>(lParam)); | |
9ce192d4 RD |
3426 | |
3427 | case EM_GETMARGINS: | |
d134f170 RD |
3428 | return Platform::LongFromTwoShorts(static_cast<short>(vs.leftMarginWidth), |
3429 | static_cast<short>(vs.rightMarginWidth)); | |
3430 | ||
3431 | case SCI_GETMARGINLEFT: | |
3432 | return vs.leftMarginWidth; | |
3433 | ||
3434 | case SCI_GETMARGINRIGHT: | |
3435 | return vs.rightMarginWidth; | |
3436 | ||
9ce192d4 | 3437 | case EM_SETMARGINS: |
d134f170 | 3438 | #ifdef EC_LEFTMARGIN |
9ce192d4 | 3439 | if (wParam & EC_LEFTMARGIN) { |
d134f170 | 3440 | vs.leftMarginWidth = Platform::LowShortFromLong(lParam); |
9ce192d4 RD |
3441 | } |
3442 | if (wParam & EC_RIGHTMARGIN) { | |
d134f170 | 3443 | vs.rightMarginWidth = Platform::HighShortFromLong(lParam); |
9ce192d4 RD |
3444 | } |
3445 | if (wParam == EC_USEFONTINFO) { | |
3446 | vs.leftMarginWidth = vs.aveCharWidth / 2; | |
3447 | vs.rightMarginWidth = vs.aveCharWidth / 2; | |
3448 | } | |
3449 | InvalidateStyleRedraw(); | |
d134f170 | 3450 | #endif |
9ce192d4 | 3451 | break; |
d134f170 RD |
3452 | |
3453 | case SCI_SETMARGINLEFT: | |
3454 | vs.leftMarginWidth = lParam; | |
3455 | InvalidateStyleRedraw(); | |
3456 | break; | |
3457 | ||
3458 | case SCI_SETMARGINRIGHT: | |
3459 | vs.rightMarginWidth = lParam; | |
3460 | InvalidateStyleRedraw(); | |
3461 | break; | |
3462 | ||
9ce192d4 RD |
3463 | // Control specific mesages |
3464 | ||
3465 | case SCI_ADDTEXT: { | |
3466 | if (lParam == 0) | |
3467 | return 0; | |
3468 | pdoc->InsertString(CurrentPosition(), reinterpret_cast<char *>(lParam), wParam); | |
3469 | SetEmptySelection(currentPos + wParam); | |
3470 | return 0; | |
3471 | } | |
3472 | ||
3473 | case SCI_ADDSTYLEDTEXT: { | |
3474 | if (lParam == 0) | |
3475 | return 0; | |
3476 | pdoc->InsertStyledString(CurrentPosition() * 2, reinterpret_cast<char *>(lParam), wParam); | |
3477 | SetEmptySelection(currentPos + wParam / 2); | |
3478 | return 0; | |
3479 | } | |
3480 | ||
3481 | case SCI_INSERTTEXT: { | |
3482 | if (lParam == 0) | |
3483 | return 0; | |
3484 | int insertPos = wParam; | |
3485 | if (static_cast<short>(wParam) == -1) | |
3486 | insertPos = CurrentPosition(); | |
3487 | int newCurrent = CurrentPosition(); | |
3488 | int newAnchor = anchor; | |
3489 | char *sz = reinterpret_cast<char *>(lParam); | |
3490 | pdoc->InsertString(insertPos, sz); | |
3491 | if (newCurrent > insertPos) | |
3492 | newCurrent += strlen(sz); | |
3493 | if (newAnchor > insertPos) | |
3494 | newAnchor += strlen(sz); | |
3495 | SetEmptySelection(newCurrent); | |
3496 | return 0; | |
3497 | } | |
3498 | ||
3499 | case SCI_CLEARALL: | |
3500 | ClearAll(); | |
3501 | return 0; | |
3502 | ||
d134f170 RD |
3503 | case SCI_CLEARDOCUMENTSTYLE: |
3504 | ClearDocumentStyle(); | |
9ce192d4 RD |
3505 | return 0; |
3506 | ||
d134f170 RD |
3507 | case SCI_SETUNDOCOLLECTION: |
3508 | pdoc->SetUndoCollection(wParam); | |
9ce192d4 | 3509 | return 0; |
d134f170 RD |
3510 | |
3511 | case SCI_GETUNDOCOLLECTION: | |
3512 | return pdoc->IsCollectingUndo(); | |
9ce192d4 RD |
3513 | |
3514 | case SCI_BEGINUNDOACTION: | |
3515 | pdoc->BeginUndoAction(); | |
3516 | return 0; | |
3517 | ||
3518 | case SCI_ENDUNDOACTION: | |
3519 | pdoc->EndUndoAction(); | |
3520 | return 0; | |
3521 | ||
3522 | case SCI_GETCARETPERIOD: | |
3523 | return caret.period; | |
3524 | ||
3525 | case SCI_SETCARETPERIOD: | |
3526 | caret.period = wParam; | |
3527 | break; | |
3528 | ||
3529 | case SCI_SETWORDCHARS: { | |
3530 | if (lParam == 0) | |
3531 | return 0; | |
3532 | pdoc->SetWordChars(reinterpret_cast<unsigned char *>(lParam)); | |
3533 | } | |
3534 | break; | |
3535 | ||
3536 | case SCI_GETLENGTH: | |
3537 | return pdoc->Length(); | |
3538 | ||
3539 | case SCI_GETCHARAT: | |
3540 | return pdoc->CharAt(wParam); | |
3541 | ||
d134f170 RD |
3542 | case SCI_SETCURRENTPOS: |
3543 | SetSelection(wParam, anchor); | |
3544 | break; | |
3545 | ||
9ce192d4 RD |
3546 | case SCI_GETCURRENTPOS: |
3547 | return currentPos; | |
3548 | ||
d134f170 RD |
3549 | case SCI_SETANCHOR: |
3550 | SetSelection(currentPos, wParam); | |
3551 | break; | |
3552 | ||
9ce192d4 RD |
3553 | case SCI_GETANCHOR: |
3554 | return anchor; | |
3555 | ||
d134f170 RD |
3556 | case SCI_SETSELECTIONSTART: |
3557 | SetSelection(Platform::Maximum(currentPos, wParam), wParam); | |
3558 | break; | |
3559 | ||
3560 | case SCI_GETSELECTIONSTART: | |
3561 | return Platform::Minimum(anchor, currentPos); | |
3562 | ||
3563 | case SCI_SETSELECTIONEND: | |
3564 | SetSelection(wParam, Platform::Minimum(anchor, wParam)); | |
3565 | break; | |
3566 | ||
3567 | case SCI_GETSELECTIONEND: | |
3568 | return Platform::Maximum(anchor, currentPos); | |
3569 | ||
3570 | case SCI_SETPRINTMAGNIFICATION: | |
3571 | printMagnification = wParam; | |
3572 | break; | |
3573 | ||
3574 | case SCI_GETPRINTMAGNIFICATION: | |
3575 | return printMagnification; | |
3576 | ||
3577 | case SCI_SETPRINTCOLOURMODE: | |
3578 | printColourMode = wParam; | |
3579 | break; | |
3580 | ||
3581 | case SCI_GETPRINTCOLOURMODE: | |
3582 | return printColourMode; | |
3583 | ||
9ce192d4 RD |
3584 | case SCI_GETSTYLEAT: |
3585 | if (static_cast<short>(wParam) >= pdoc->Length()) | |
3586 | return 0; | |
3587 | else | |
3588 | return pdoc->StyleAt(wParam); | |
3589 | ||
3590 | case SCI_REDO: | |
3591 | Redo(); | |
3592 | break; | |
3593 | ||
3594 | case SCI_SELECTALL: | |
3595 | SelectAll(); | |
3596 | break; | |
3597 | ||
3598 | case SCI_SETSAVEPOINT: | |
3599 | pdoc->SetSavePoint(); | |
3600 | NotifySavePoint(true); | |
3601 | break; | |
3602 | ||
3603 | case SCI_GETSTYLEDTEXT: { | |
3604 | if (lParam == 0) | |
3605 | return 0; | |
d134f170 | 3606 | TextRange *tr = reinterpret_cast<TextRange *>(lParam); |
9ce192d4 RD |
3607 | int iPlace = 0; |
3608 | for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) { | |
3609 | tr->lpstrText[iPlace++] = pdoc->CharAt(iChar); | |
3610 | tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar); | |
3611 | } | |
3612 | tr->lpstrText[iPlace] = '\0'; | |
3613 | tr->lpstrText[iPlace + 1] = '\0'; | |
3614 | return iPlace; | |
3615 | } | |
3616 | ||
3617 | case SCI_CANREDO: | |
3618 | return pdoc->CanRedo() ? TRUE : FALSE; | |
3619 | ||
3620 | case SCI_MARKERLINEFROMHANDLE: | |
3621 | return pdoc->LineFromHandle(wParam); | |
3622 | ||
3623 | case SCI_MARKERDELETEHANDLE: | |
3624 | pdoc->DeleteMarkFromHandle(wParam); | |
3625 | break; | |
3626 | ||
3627 | case SCI_GETVIEWWS: | |
3628 | return vs.viewWhitespace; | |
3629 | ||
3630 | case SCI_SETVIEWWS: | |
d134f170 | 3631 | vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(wParam); |
9ce192d4 RD |
3632 | Redraw(); |
3633 | break; | |
3634 | ||
d134f170 RD |
3635 | case SCI_POSITIONFROMPOINT: |
3636 | return PositionFromLocation(Point(wParam, lParam)); | |
3637 | ||
9ce192d4 RD |
3638 | case SCI_GOTOLINE: |
3639 | GoToLine(wParam); | |
3640 | break; | |
3641 | ||
3642 | case SCI_GOTOPOS: | |
3643 | SetEmptySelection(wParam); | |
3644 | EnsureCaretVisible(); | |
3645 | Redraw(); | |
3646 | break; | |
3647 | ||
9ce192d4 RD |
3648 | case SCI_GETCURLINE: { |
3649 | if (lParam == 0) | |
3650 | return 0; | |
3651 | int lineCurrentPos = pdoc->LineFromPosition(currentPos); | |
3652 | int lineStart = pdoc->LineStart(lineCurrentPos); | |
3653 | unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1); | |
3654 | char *ptr = reinterpret_cast<char *>(lParam); | |
3655 | unsigned int iPlace = 0; | |
3656 | for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam; iChar++) | |
3657 | ptr[iPlace++] = pdoc->CharAt(iChar); | |
3658 | ptr[iPlace] = '\0'; | |
3659 | return currentPos - lineStart; | |
3660 | } | |
3661 | ||
3662 | case SCI_GETENDSTYLED: | |
3663 | return pdoc->GetEndStyled(); | |
3664 | ||
3665 | case SCI_GETEOLMODE: | |
3666 | return pdoc->eolMode; | |
3667 | ||
3668 | case SCI_SETEOLMODE: | |
3669 | pdoc->eolMode = wParam; | |
3670 | break; | |
3671 | ||
3672 | case SCI_STARTSTYLING: | |
f6bcfd97 | 3673 | pdoc->StartStyling(wParam, static_cast<char>(lParam)); |
9ce192d4 RD |
3674 | break; |
3675 | ||
3676 | case SCI_SETSTYLING: | |
f6bcfd97 | 3677 | pdoc->SetStyleFor(wParam, static_cast<char>(lParam)); |
9ce192d4 RD |
3678 | break; |
3679 | ||
d134f170 | 3680 | case SCI_SETSTYLINGEX: // Specify a complete styling buffer |
9ce192d4 RD |
3681 | if (lParam == 0) |
3682 | return 0; | |
3683 | pdoc->SetStyles(wParam, reinterpret_cast<char *>(lParam)); | |
3684 | break; | |
3685 | ||
9ce192d4 RD |
3686 | case SCI_SETBUFFEREDDRAW: |
3687 | bufferedDraw = wParam; | |
3688 | break; | |
3689 | ||
d134f170 RD |
3690 | case SCI_GETBUFFEREDDRAW: |
3691 | return bufferedDraw; | |
3692 | ||
9ce192d4 RD |
3693 | case SCI_SETTABWIDTH: |
3694 | if (wParam > 0) | |
3695 | pdoc->tabInChars = wParam; | |
3696 | InvalidateStyleRedraw(); | |
3697 | break; | |
3698 | ||
f6bcfd97 BP |
3699 | case SCI_GETTABWIDTH: |
3700 | return pdoc->tabInChars; | |
d134f170 | 3701 | |
f6bcfd97 BP |
3702 | case SCI_SETINDENT: |
3703 | pdoc->indentInChars = wParam; | |
3704 | InvalidateStyleRedraw(); | |
3705 | break; | |
d134f170 | 3706 | |
f6bcfd97 BP |
3707 | case SCI_GETINDENT: |
3708 | return pdoc->indentInChars; | |
3709 | ||
3710 | case SCI_SETUSETABS: | |
3711 | pdoc->useTabs = wParam; | |
3712 | InvalidateStyleRedraw(); | |
3713 | break; | |
3714 | ||
3715 | case SCI_GETUSETABS: | |
3716 | return pdoc->useTabs; | |
d134f170 | 3717 | |
f6bcfd97 BP |
3718 | case SCI_SETLINEINDENTATION: |
3719 | pdoc->SetLineIndentation(wParam, lParam); | |
3720 | break; | |
d134f170 | 3721 | |
f6bcfd97 BP |
3722 | case SCI_GETLINEINDENTATION: |
3723 | return pdoc->GetLineIndentation(wParam); | |
d134f170 | 3724 | |
f6bcfd97 BP |
3725 | case SCI_GETLINEINDENTPOSITION: |
3726 | return pdoc->GetLineIndentPosition(wParam); | |
d134f170 RD |
3727 | |
3728 | case SCI_GETCOLUMN: | |
3729 | return pdoc->GetColumn(wParam); | |
3730 | ||
f6bcfd97 BP |
3731 | case SCI_SETHSCROLLBAR : |
3732 | horizontalScrollBarVisible = wParam; | |
3733 | SetScrollBars(); | |
3734 | ReconfigureScrollBars(); | |
3735 | break; | |
d134f170 | 3736 | |
f6bcfd97 BP |
3737 | case SCI_GETHSCROLLBAR: |
3738 | return horizontalScrollBarVisible; | |
d134f170 RD |
3739 | |
3740 | case SCI_SETINDENTATIONGUIDES: | |
3741 | vs.viewIndentationGuides = wParam; | |
3742 | Redraw(); | |
9ce192d4 RD |
3743 | break; |
3744 | ||
d134f170 RD |
3745 | case SCI_GETINDENTATIONGUIDES: |
3746 | return vs.viewIndentationGuides; | |
3747 | ||
3748 | case SCI_SETHIGHLIGHTGUIDE: | |
3749 | if ((highlightGuideColumn != static_cast<int>(wParam)) || (wParam > 0)) { | |
3750 | highlightGuideColumn = wParam; | |
3751 | Redraw(); | |
9ce192d4 | 3752 | } |
9ce192d4 | 3753 | break; |
d134f170 RD |
3754 | |
3755 | case SCI_GETHIGHLIGHTGUIDE: | |
3756 | return highlightGuideColumn; | |
3757 | ||
3758 | case SCI_GETLINEENDPOSITION: | |
3759 | return pdoc->LineEnd(wParam); | |
3760 | ||
3761 | case SCI_SETCODEPAGE: | |
3762 | pdoc->dbcsCodePage = wParam; | |
3763 | break; | |
3764 | ||
3765 | case SCI_GETCODEPAGE: | |
3766 | return pdoc->dbcsCodePage; | |
9ce192d4 RD |
3767 | |
3768 | case SCI_SETUSEPALETTE: | |
3769 | palette.allowRealization = wParam; | |
3770 | InvalidateStyleRedraw(); | |
3771 | break; | |
3772 | ||
d134f170 RD |
3773 | case SCI_GETUSEPALETTE: |
3774 | return palette.allowRealization; | |
3775 | ||
9ce192d4 RD |
3776 | // Marker definition and setting |
3777 | case SCI_MARKERDEFINE: | |
3778 | if (wParam <= MARKER_MAX) | |
3779 | vs.markers[wParam].markType = lParam; | |
3780 | InvalidateStyleData(); | |
3781 | RedrawSelMargin(); | |
3782 | break; | |
3783 | case SCI_MARKERSETFORE: | |
3784 | if (wParam <= MARKER_MAX) | |
3785 | vs.markers[wParam].fore.desired = Colour(lParam); | |
3786 | InvalidateStyleData(); | |
3787 | RedrawSelMargin(); | |
3788 | break; | |
3789 | case SCI_MARKERSETBACK: | |
3790 | if (wParam <= MARKER_MAX) | |
3791 | vs.markers[wParam].back.desired = Colour(lParam); | |
3792 | InvalidateStyleData(); | |
3793 | RedrawSelMargin(); | |
3794 | break; | |
3795 | case SCI_MARKERADD: { | |
3796 | int markerID = pdoc->AddMark(wParam, lParam); | |
9ce192d4 RD |
3797 | return markerID; |
3798 | } | |
3799 | ||
3800 | case SCI_MARKERDELETE: | |
3801 | pdoc->DeleteMark(wParam, lParam); | |
9ce192d4 RD |
3802 | break; |
3803 | ||
3804 | case SCI_MARKERDELETEALL: | |
3805 | pdoc->DeleteAllMarks(static_cast<int>(wParam)); | |
9ce192d4 RD |
3806 | break; |
3807 | ||
3808 | case SCI_MARKERGET: | |
3809 | return pdoc->GetMark(wParam); | |
3810 | ||
3811 | case SCI_MARKERNEXT: { | |
3812 | int lt = pdoc->LinesTotal(); | |
3813 | for (int iLine = wParam; iLine < lt; iLine++) { | |
3814 | if ((pdoc->GetMark(iLine) & lParam) != 0) | |
3815 | return iLine; | |
3816 | } | |
3817 | } | |
3818 | return -1; | |
3819 | ||
3820 | case SCI_MARKERPREVIOUS: { | |
3821 | for (int iLine = wParam; iLine >= 0; iLine--) { | |
3822 | if ((pdoc->GetMark(iLine) & lParam) != 0) | |
3823 | return iLine; | |
3824 | } | |
3825 | } | |
3826 | return -1; | |
3827 | ||
3828 | case SCI_SETMARGINTYPEN: | |
f6bcfd97 | 3829 | if (ValidMargin(wParam)) { |
9ce192d4 RD |
3830 | vs.ms[wParam].symbol = (lParam == SC_MARGIN_SYMBOL); |
3831 | InvalidateStyleRedraw(); | |
3832 | } | |
3833 | break; | |
d134f170 | 3834 | |
9ce192d4 | 3835 | case SCI_GETMARGINTYPEN: |
d134f170 | 3836 | if (ValidMargin(wParam)) |
9ce192d4 RD |
3837 | return vs.ms[wParam].symbol ? SC_MARGIN_SYMBOL : SC_MARGIN_NUMBER; |
3838 | else | |
3839 | return 0; | |
d134f170 | 3840 | |
9ce192d4 | 3841 | case SCI_SETMARGINWIDTHN: |
f6bcfd97 | 3842 | if (ValidMargin(wParam)) { |
9ce192d4 RD |
3843 | vs.ms[wParam].width = lParam; |
3844 | InvalidateStyleRedraw(); | |
3845 | } | |
3846 | break; | |
d134f170 | 3847 | |
9ce192d4 | 3848 | case SCI_GETMARGINWIDTHN: |
d134f170 | 3849 | if (ValidMargin(wParam)) |
9ce192d4 RD |
3850 | return vs.ms[wParam].width; |
3851 | else | |
3852 | return 0; | |
d134f170 | 3853 | |
9ce192d4 | 3854 | case SCI_SETMARGINMASKN: |
f6bcfd97 | 3855 | if (ValidMargin(wParam)) { |
9ce192d4 RD |
3856 | vs.ms[wParam].mask = lParam; |
3857 | InvalidateStyleRedraw(); | |
3858 | } | |
3859 | break; | |
d134f170 | 3860 | |
9ce192d4 | 3861 | case SCI_GETMARGINMASKN: |
d134f170 | 3862 | if (ValidMargin(wParam)) |
9ce192d4 RD |
3863 | return vs.ms[wParam].mask; |
3864 | else | |
3865 | return 0; | |
d134f170 | 3866 | |
9ce192d4 | 3867 | case SCI_SETMARGINSENSITIVEN: |
f6bcfd97 | 3868 | if (ValidMargin(wParam)) { |
9ce192d4 RD |
3869 | vs.ms[wParam].sensitive = lParam; |
3870 | InvalidateStyleRedraw(); | |
3871 | } | |
3872 | break; | |
d134f170 | 3873 | |
9ce192d4 | 3874 | case SCI_GETMARGINSENSITIVEN: |
d134f170 | 3875 | if (ValidMargin(wParam)) |
9ce192d4 RD |
3876 | return vs.ms[wParam].sensitive ? 1 : 0; |
3877 | else | |
3878 | return 0; | |
3879 | ||
3880 | case SCI_STYLECLEARALL: | |
3881 | vs.ClearStyles(); | |
3882 | InvalidateStyleRedraw(); | |
3883 | break; | |
3884 | ||
3885 | case SCI_STYLESETFORE: | |
3886 | if (wParam <= STYLE_MAX) { | |
3887 | vs.styles[wParam].fore.desired = Colour(lParam); | |
3888 | InvalidateStyleRedraw(); | |
3889 | } | |
3890 | break; | |
3891 | case SCI_STYLESETBACK: | |
3892 | if (wParam <= STYLE_MAX) { | |
3893 | vs.styles[wParam].back.desired = Colour(lParam); | |
3894 | InvalidateStyleRedraw(); | |
3895 | } | |
3896 | break; | |
3897 | case SCI_STYLESETBOLD: | |
3898 | if (wParam <= STYLE_MAX) { | |
3899 | vs.styles[wParam].bold = lParam; | |
3900 | InvalidateStyleRedraw(); | |
3901 | } | |
3902 | break; | |
3903 | case SCI_STYLESETITALIC: | |
3904 | if (wParam <= STYLE_MAX) { | |
3905 | vs.styles[wParam].italic = lParam; | |
3906 | InvalidateStyleRedraw(); | |
3907 | } | |
3908 | break; | |
3909 | case SCI_STYLESETEOLFILLED: | |
3910 | if (wParam <= STYLE_MAX) { | |
3911 | vs.styles[wParam].eolFilled = lParam; | |
3912 | InvalidateStyleRedraw(); | |
3913 | } | |
3914 | break; | |
3915 | case SCI_STYLESETSIZE: | |
3916 | if (wParam <= STYLE_MAX) { | |
3917 | vs.styles[wParam].size = lParam; | |
3918 | InvalidateStyleRedraw(); | |
3919 | } | |
3920 | break; | |
3921 | case SCI_STYLESETFONT: | |
3922 | if (lParam == 0) | |
3923 | return 0; | |
3924 | if (wParam <= STYLE_MAX) { | |
f6bcfd97 BP |
3925 | vs.SetStyleFontName(wParam, reinterpret_cast<const char *>(lParam)); |
3926 | InvalidateStyleRedraw(); | |
3927 | } | |
3928 | break; | |
3929 | case SCI_STYLESETUNDERLINE: | |
3930 | if (wParam <= STYLE_MAX) { | |
3931 | vs.styles[wParam].underline = lParam; | |
3932 | InvalidateStyleRedraw(); | |
3933 | } | |
3934 | break; | |
3935 | case SCI_STYLESETCHARACTERSET: | |
3936 | if (wParam <= STYLE_MAX) { | |
3937 | vs.styles[wParam].characterSet = lParam; | |
9ce192d4 RD |
3938 | InvalidateStyleRedraw(); |
3939 | } | |
3940 | break; | |
d134f170 RD |
3941 | case SCI_STYLESETVISIBLE: |
3942 | if (wParam <= STYLE_MAX) { | |
3943 | vs.styles[wParam].visible = lParam; | |
3944 | InvalidateStyleRedraw(); | |
3945 | } | |
3946 | break; | |
3947 | ||
9ce192d4 RD |
3948 | case SCI_STYLERESETDEFAULT: |
3949 | vs.ResetDefaultStyle(); | |
3950 | InvalidateStyleRedraw(); | |
3951 | break; | |
9ce192d4 RD |
3952 | case SCI_SETSTYLEBITS: |
3953 | pdoc->SetStylingBits(wParam); | |
3954 | break; | |
d134f170 | 3955 | |
9ce192d4 RD |
3956 | case SCI_GETSTYLEBITS: |
3957 | return pdoc->stylingBits; | |
d134f170 | 3958 | |
9ce192d4 RD |
3959 | case SCI_SETLINESTATE: |
3960 | return pdoc->SetLineState(wParam, lParam); | |
d134f170 | 3961 | |
9ce192d4 RD |
3962 | case SCI_GETLINESTATE: |
3963 | return pdoc->GetLineState(wParam); | |
d134f170 | 3964 | |
9ce192d4 RD |
3965 | case SCI_GETMAXLINESTATE: |
3966 | return pdoc->GetMaxLineState(); | |
d134f170 RD |
3967 | |
3968 | // Folding messages | |
3969 | ||
9ce192d4 RD |
3970 | case SCI_VISIBLEFROMDOCLINE: |
3971 | return cs.DisplayFromDoc(wParam); | |
d134f170 | 3972 | |
9ce192d4 RD |
3973 | case SCI_DOCLINEFROMVISIBLE: |
3974 | return cs.DocFromDisplay(wParam); | |
3975 | ||
3976 | case SCI_SETFOLDLEVEL: { | |
3977 | int prev = pdoc->SetLevel(wParam, lParam); | |
3978 | if (prev != lParam) | |
3979 | RedrawSelMargin(); | |
3980 | return prev; | |
3981 | } | |
d134f170 | 3982 | |
9ce192d4 RD |
3983 | case SCI_GETFOLDLEVEL: |
3984 | return pdoc->GetLevel(wParam); | |
d134f170 | 3985 | |
9ce192d4 RD |
3986 | case SCI_GETLASTCHILD: |
3987 | return pdoc->GetLastChild(wParam, lParam); | |
d134f170 | 3988 | |
9ce192d4 RD |
3989 | case SCI_GETFOLDPARENT: |
3990 | return pdoc->GetFoldParent(wParam); | |
d134f170 | 3991 | |
9ce192d4 RD |
3992 | case SCI_SHOWLINES: |
3993 | cs.SetVisible(wParam, lParam, true); | |
3994 | SetScrollBars(); | |
3995 | Redraw(); | |
3996 | break; | |
d134f170 | 3997 | |
9ce192d4 RD |
3998 | case SCI_HIDELINES: |
3999 | cs.SetVisible(wParam, lParam, false); | |
4000 | SetScrollBars(); | |
4001 | Redraw(); | |
4002 | break; | |
d134f170 | 4003 | |
9ce192d4 RD |
4004 | case SCI_GETLINEVISIBLE: |
4005 | return cs.GetVisible(wParam); | |
d134f170 | 4006 | |
9ce192d4 RD |
4007 | case SCI_SETFOLDEXPANDED: |
4008 | if (cs.SetExpanded(wParam, lParam)) { | |
4009 | RedrawSelMargin(); | |
4010 | } | |
4011 | break; | |
d134f170 | 4012 | |
9ce192d4 RD |
4013 | case SCI_GETFOLDEXPANDED: |
4014 | return cs.GetExpanded(wParam); | |
d134f170 | 4015 | |
9ce192d4 RD |
4016 | case SCI_SETFOLDFLAGS: |
4017 | foldFlags = wParam; | |
4018 | Redraw(); | |
4019 | break; | |
4020 | ||
4021 | case SCI_TOGGLEFOLD: | |
4022 | ToggleContraction(wParam); | |
4023 | break; | |
d134f170 | 4024 | |
9ce192d4 RD |
4025 | case SCI_ENSUREVISIBLE: |
4026 | EnsureLineVisible(wParam); | |
4027 | break; | |
d134f170 | 4028 | |
9ce192d4 RD |
4029 | case SCI_SEARCHANCHOR: |
4030 | SearchAnchor(); | |
4031 | break; | |
4032 | ||
4033 | case SCI_SEARCHNEXT: | |
4034 | case SCI_SEARCHPREV: | |
4035 | return SearchText(iMessage, wParam, lParam); | |
9ce192d4 RD |
4036 | |
4037 | case SCI_SETCARETPOLICY: | |
4038 | caretPolicy = wParam; | |
4039 | caretSlop = lParam; | |
4040 | break; | |
4041 | ||
f6bcfd97 BP |
4042 | case SCI_LINESONSCREEN: |
4043 | return LinesOnScreen(); | |
4044 | ||
4045 | case SCI_USEPOPUP: | |
4046 | displayPopupMenu = wParam; | |
4047 | break; | |
4048 | ||
9ce192d4 RD |
4049 | case SCI_SETSELFORE: |
4050 | vs.selforeset = wParam; | |
4051 | vs.selforeground.desired = Colour(lParam); | |
4052 | InvalidateStyleRedraw(); | |
4053 | break; | |
4054 | ||
4055 | case SCI_SETSELBACK: | |
4056 | vs.selbackset = wParam; | |
4057 | vs.selbackground.desired = Colour(lParam); | |
4058 | InvalidateStyleRedraw(); | |
4059 | break; | |
4060 | ||
4061 | case SCI_SETCARETFORE: | |
4062 | vs.caretcolour.desired = Colour(wParam); | |
4063 | InvalidateStyleRedraw(); | |
4064 | break; | |
4065 | ||
d134f170 RD |
4066 | case SCI_GETCARETFORE: |
4067 | return vs.caretcolour.desired.AsLong(); | |
4068 | ||
9ce192d4 | 4069 | case SCI_ASSIGNCMDKEY: |
d134f170 RD |
4070 | kmap.AssignCmdKey(Platform::LowShortFromLong(wParam), |
4071 | Platform::HighShortFromLong(wParam), lParam); | |
9ce192d4 RD |
4072 | break; |
4073 | ||
4074 | case SCI_CLEARCMDKEY: | |
d134f170 RD |
4075 | kmap.AssignCmdKey(Platform::LowShortFromLong(wParam), |
4076 | Platform::HighShortFromLong(wParam), WM_NULL); | |
9ce192d4 RD |
4077 | break; |
4078 | ||
4079 | case SCI_CLEARALLCMDKEYS: | |
4080 | kmap.Clear(); | |
4081 | break; | |
4082 | ||
4083 | case SCI_INDICSETSTYLE: | |
4084 | if (wParam <= INDIC_MAX) { | |
4085 | vs.indicators[wParam].style = lParam; | |
4086 | InvalidateStyleRedraw(); | |
4087 | } | |
4088 | break; | |
4089 | ||
4090 | case SCI_INDICGETSTYLE: | |
4091 | return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0; | |
4092 | ||
4093 | case SCI_INDICSETFORE: | |
4094 | if (wParam <= INDIC_MAX) { | |
4095 | vs.indicators[wParam].fore.desired = Colour(lParam); | |
4096 | InvalidateStyleRedraw(); | |
4097 | } | |
4098 | break; | |
4099 | ||
4100 | case SCI_INDICGETFORE: | |
4101 | return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0; | |
4102 | ||
4103 | case SCI_LINEDOWN: | |
4104 | case SCI_LINEDOWNEXTEND: | |
4105 | case SCI_LINEUP: | |
4106 | case SCI_LINEUPEXTEND: | |
4107 | case SCI_CHARLEFT: | |
4108 | case SCI_CHARLEFTEXTEND: | |
4109 | case SCI_CHARRIGHT: | |
4110 | case SCI_CHARRIGHTEXTEND: | |
4111 | case SCI_WORDLEFT: | |
4112 | case SCI_WORDLEFTEXTEND: | |
4113 | case SCI_WORDRIGHT: | |
4114 | case SCI_WORDRIGHTEXTEND: | |
4115 | case SCI_HOME: | |
4116 | case SCI_HOMEEXTEND: | |
4117 | case SCI_LINEEND: | |
4118 | case SCI_LINEENDEXTEND: | |
4119 | case SCI_DOCUMENTSTART: | |
4120 | case SCI_DOCUMENTSTARTEXTEND: | |
4121 | case SCI_DOCUMENTEND: | |
4122 | case SCI_DOCUMENTENDEXTEND: | |
4123 | case SCI_PAGEUP: | |
4124 | case SCI_PAGEUPEXTEND: | |
4125 | case SCI_PAGEDOWN: | |
4126 | case SCI_PAGEDOWNEXTEND: | |
4127 | case SCI_EDITTOGGLEOVERTYPE: | |
4128 | case SCI_CANCEL: | |
4129 | case SCI_DELETEBACK: | |
4130 | case SCI_TAB: | |
4131 | case SCI_BACKTAB: | |
4132 | case SCI_NEWLINE: | |
4133 | case SCI_FORMFEED: | |
4134 | case SCI_VCHOME: | |
4135 | case SCI_VCHOMEEXTEND: | |
4136 | case SCI_ZOOMIN: | |
4137 | case SCI_ZOOMOUT: | |
4138 | case SCI_DELWORDLEFT: | |
4139 | case SCI_DELWORDRIGHT: | |
f6bcfd97 BP |
4140 | case SCI_LINECUT: |
4141 | case SCI_LINEDELETE: | |
4142 | case SCI_LINETRANSPOSE: | |
4143 | case SCI_LOWERCASE: | |
4144 | case SCI_UPPERCASE: | |
4145 | case SCI_LINESCROLLDOWN: | |
4146 | case SCI_LINESCROLLUP: | |
9ce192d4 RD |
4147 | return KeyCommand(iMessage); |
4148 | ||
4149 | case SCI_BRACEHIGHLIGHT: | |
4150 | SetBraceHighlight(static_cast<int>(wParam), lParam, STYLE_BRACELIGHT); | |
4151 | break; | |
d134f170 | 4152 | |
9ce192d4 RD |
4153 | case SCI_BRACEBADLIGHT: |
4154 | SetBraceHighlight(static_cast<int>(wParam), -1, STYLE_BRACEBAD); | |
4155 | break; | |
4156 | ||
4157 | case SCI_BRACEMATCH: | |
4158 | // wParam is position of char to find brace for, | |
4159 | // lParam is maximum amount of text to restyle to find it | |
4160 | return BraceMatch(wParam, lParam); | |
4161 | ||
4162 | case SCI_GETVIEWEOL: | |
4163 | return vs.viewEOL; | |
4164 | ||
4165 | case SCI_SETVIEWEOL: | |
4166 | vs.viewEOL = wParam; | |
4167 | Redraw(); | |
4168 | break; | |
4169 | ||
f6bcfd97 BP |
4170 | case SCI_SETZOOM: |
4171 | vs.zoomLevel = wParam; | |
4172 | InvalidateStyleRedraw(); | |
4173 | break; | |
4174 | ||
4175 | case SCI_GETZOOM: | |
4176 | return vs.zoomLevel; | |
d134f170 | 4177 | |
9ce192d4 RD |
4178 | case SCI_GETEDGECOLUMN: |
4179 | return theEdge; | |
d134f170 | 4180 | |
9ce192d4 RD |
4181 | case SCI_SETEDGECOLUMN: |
4182 | theEdge = wParam; | |
4183 | InvalidateStyleRedraw(); | |
4184 | break; | |
d134f170 | 4185 | |
9ce192d4 | 4186 | case SCI_GETEDGEMODE: |
d134f170 RD |
4187 | return vs.edgeState; |
4188 | ||
9ce192d4 | 4189 | case SCI_SETEDGEMODE: |
d134f170 | 4190 | vs.edgeState = wParam; |
9ce192d4 RD |
4191 | InvalidateStyleRedraw(); |
4192 | break; | |
d134f170 | 4193 | |
9ce192d4 RD |
4194 | case SCI_GETEDGECOLOUR: |
4195 | return vs.edgecolour.desired.AsLong(); | |
d134f170 | 4196 | |
9ce192d4 RD |
4197 | case SCI_SETEDGECOLOUR: |
4198 | vs.edgecolour.desired = Colour(wParam); | |
4199 | InvalidateStyleRedraw(); | |
4200 | break; | |
d134f170 | 4201 | |
9ce192d4 | 4202 | case SCI_GETDOCPOINTER: |
d134f170 | 4203 | return reinterpret_cast<long>(pdoc); |
9ce192d4 RD |
4204 | |
4205 | case SCI_SETDOCPOINTER: | |
4206 | SetDocPointer(reinterpret_cast<Document *>(lParam)); | |
4207 | return 0; | |
4208 | ||
d134f170 RD |
4209 | case SCI_CREATEDOCUMENT: { |
4210 | Document *doc = new Document(); | |
4211 | doc->AddRef(); | |
4212 | return reinterpret_cast<long>(doc); | |
4213 | } | |
4214 | ||
4215 | case SCI_ADDREFDOCUMENT: | |
f6bcfd97 BP |
4216 | (reinterpret_cast<Document *>(lParam))->AddRef(); |
4217 | break; | |
d134f170 RD |
4218 | |
4219 | case SCI_RELEASEDOCUMENT: | |
f6bcfd97 BP |
4220 | (reinterpret_cast<Document *>(lParam))->Release(); |
4221 | break; | |
d134f170 | 4222 | |
9ce192d4 RD |
4223 | case SCI_SETMODEVENTMASK: |
4224 | modEventMask = wParam; | |
4225 | return 0; | |
d134f170 RD |
4226 | |
4227 | case SCI_GETMODEVENTMASK: | |
4228 | return modEventMask; | |
4229 | ||
9ce192d4 RD |
4230 | case SCI_CONVERTEOLS: |
4231 | pdoc->ConvertLineEnds(wParam); | |
4232 | SetSelection(currentPos, anchor); // Ensure selection inside document | |
4233 | return 0; | |
4234 | ||
f6bcfd97 BP |
4235 | case SCI_SELECTIONISRECTANGLE: |
4236 | return (selType == selRectangle) ? 1 : 0; | |
4237 | ||
d134f170 RD |
4238 | case SCI_SETOVERTYPE: |
4239 | inOverstrike = wParam; | |
4240 | break; | |
4241 | ||
4242 | case SCI_GETOVERTYPE: | |
4243 | return inOverstrike ? TRUE : FALSE; | |
4244 | ||
9ce192d4 RD |
4245 | #ifdef MACRO_SUPPORT |
4246 | case SCI_STARTRECORD: | |
4247 | recordingMacro = 1; | |
4248 | return 0; | |
4249 | ||
4250 | case SCI_STOPRECORD: | |
4251 | recordingMacro = 0; | |
4252 | return 0; | |
d134f170 RD |
4253 | #endif |
4254 | ||
9ce192d4 RD |
4255 | default: |
4256 | return DefWndProc(iMessage, wParam, lParam); | |
4257 | } | |
4258 | //Platform::DebugPrintf("end wnd proc\n"); | |
4259 | return 0l; | |
4260 | } |