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

EditView.cxx
Go to the documentation of this file.
1// Scintilla source code edit control
2/** @file EditView.cxx
3 ** Defines the appearance of the main text area of the editor window.
4 **/
5// Copyright 1998-2014 by Neil Hodgson <neilh@scintilla.org>
6// The License.txt file describes the conditions under which this software may be distributed.
7
8#include <cstddef>
9#include <cstdlib>
10#include <cassert>
11#include <cstring>
12#include <cstdio>
13#include <cmath>
14
15#include <stdexcept>
16#include <string>
17#include <vector>
18#include <map>
19#include <forward_list>
20#include <algorithm>
21#include <iterator>
22#include <memory>
23#include <chrono>
24
25#include "Platform.h"
26
27#include "ILoader.h"
28#include "ILexer.h"
29#include "Scintilla.h"
30
31#include "CharacterSet.h"
32#include "CharacterCategory.h"
33#include "Position.h"
34#include "IntegerRectangle.h"
35#include "UniqueString.h"
36#include "SplitVector.h"
37#include "Partitioning.h"
38#include "RunStyles.h"
39#include "ContractionState.h"
40#include "CellBuffer.h"
41#include "PerLine.h"
42#include "KeyMap.h"
43#include "Indicator.h"
44#include "LineMarker.h"
45#include "Style.h"
46#include "ViewStyle.h"
47#include "CharClassify.h"
48#include "Decoration.h"
49#include "CaseFolder.h"
50#include "Document.h"
51#include "UniConversion.h"
52#include "Selection.h"
53#include "PositionCache.h"
54#include "EditModel.h"
55#include "MarginView.h"
56#include "EditView.h"
57#include "ElapsedPeriod.h"
58
59using namespace Scintilla;
60
61PrintParameters::PrintParameters() noexcept {
62 magnification = 0;
65}
66
67namespace Scintilla {
68
69bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st) noexcept {
70 if (st.multipleStyles) {
71 for (size_t iStyle = 0; iStyle<st.length; iStyle++) {
72 if (!vs.ValidStyle(styleOffset + st.styles[iStyle]))
73 return false;
74 }
75 } else {
76 if (!vs.ValidStyle(styleOffset + st.style))
77 return false;
78 }
79 return true;
80}
81
82static int WidthStyledText(Surface *surface, const ViewStyle &vs, int styleOffset,
83 const char *text, const unsigned char *styles, size_t len) {
84 int width = 0;
85 size_t start = 0;
86 while (start < len) {
87 const unsigned char style = styles[start];
88 size_t endSegment = start;
89 while ((endSegment + 1 < len) && (styles[endSegment + 1] == style))
90 endSegment++;
91 FontAlias fontText = vs.styles[style + styleOffset].font;
92 width += static_cast<int>(surface->WidthText(fontText, text + start,
93 static_cast<int>(endSegment - start + 1)));
94 start = endSegment + 1;
95 }
96 return width;
97}
98
99int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st) {
100 int widthMax = 0;
101 size_t start = 0;
102 while (start < st.length) {
103 const size_t lenLine = st.LineLength(start);
104 int widthSubLine;
105 if (st.multipleStyles) {
106 widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine);
107 } else {
108 FontAlias fontText = vs.styles[styleOffset + st.style].font;
109 widthSubLine = static_cast<int>(surface->WidthText(fontText,
110 st.text + start, static_cast<int>(lenLine)));
111 }
112 if (widthSubLine > widthMax)
113 widthMax = widthSubLine;
114 start += lenLine + 1;
115 }
116 return widthMax;
117}
118
119void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XYPOSITION ybase,
120 const char *s, int len, DrawPhase phase) {
121 FontAlias fontText = style.font;
122 if (phase & drawBack) {
123 if (phase & drawText) {
124 // Drawing both
125 surface->DrawTextNoClip(rc, fontText, ybase, s, len,
126 style.fore, style.back);
127 } else {
128 surface->FillRectangle(rc, style.back);
129 }
130 } else if (phase & drawText) {
131 surface->DrawTextTransparent(rc, fontText, ybase, s, len, style.fore);
132 }
133}
134
135void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText,
136 const StyledText &st, size_t start, size_t length, DrawPhase phase) {
137
138 if (st.multipleStyles) {
139 int x = static_cast<int>(rcText.left);
140 size_t i = 0;
141 while (i < length) {
142 size_t end = i;
143 size_t style = st.styles[i + start];
144 while (end < length - 1 && st.styles[start + end + 1] == style)
145 end++;
146 style += styleOffset;
147 FontAlias fontText = vs.styles[style].font;
148 const int width = static_cast<int>(surface->WidthText(fontText,
149 st.text + start + i, static_cast<int>(end - i + 1)));
150 PRectangle rcSegment = rcText;
151 rcSegment.left = static_cast<XYPOSITION>(x);
152 rcSegment.right = static_cast<XYPOSITION>(x + width + 1);
153 DrawTextNoClipPhase(surface, rcSegment, vs.styles[style],
154 rcText.top + vs.maxAscent, st.text + start + i,
155 static_cast<int>(end - i + 1), phase);
156 x += width;
157 i = end + 1;
158 }
159 } else {
160 const size_t style = st.style + styleOffset;
161 DrawTextNoClipPhase(surface, rcText, vs.styles[style],
162 rcText.top + vs.maxAscent, st.text + start,
163 static_cast<int>(length), phase);
164 }
165}
166
167}
168
170 tabWidthMinimumPixels = 2; // needed for calculating tab stops for fractional proportional fonts
171 hideSelection = false;
172 drawOverstrikeCaret = true;
173 bufferedDraw = true;
178 imeCaretBlockOverride = false;
180 posCache.SetSize(0x400);
181 tabArrowHeight = 4;
182 customDrawTabArrow = nullptr;
183 customDrawWrapMarker = nullptr;
184}
185
187}
188
189bool EditView::SetTwoPhaseDraw(bool twoPhaseDraw) noexcept {
190 const PhasesDraw phasesDrawNew = twoPhaseDraw ? phasesTwo : phasesOne;
191 const bool redraw = phasesDraw != phasesDrawNew;
192 phasesDraw = phasesDrawNew;
193 return redraw;
194}
195
196bool EditView::SetPhasesDraw(int phases) noexcept {
197 const PhasesDraw phasesDrawNew = static_cast<PhasesDraw>(phases);
198 const bool redraw = phasesDraw != phasesDrawNew;
199 phasesDraw = phasesDrawNew;
200 return redraw;
201}
202
203bool EditView::LinesOverlap() const noexcept {
204 return phasesDraw == phasesMultiple;
205}
206
208 ldTabstops.reset();
209}
210
212 const int next = GetNextTabstop(line, static_cast<int>(x + tabWidthMinimumPixels));
213 if (next > 0)
214 return static_cast<XYPOSITION>(next);
215 return (static_cast<int>((x + tabWidthMinimumPixels) / tabWidth) + 1) * tabWidth;
216}
217
219 return ldTabstops && ldTabstops->ClearTabstops(line);
220}
221
223 if (!ldTabstops) {
224 ldTabstops = Sci::make_unique<LineTabstops>();
225 }
226 return ldTabstops && ldTabstops->AddTabstop(line, x);
227}
228
229int EditView::GetNextTabstop(Sci::Line line, int x) const noexcept {
230 if (ldTabstops) {
231 return ldTabstops->GetNextTabstop(line, x);
232 } else {
233 return 0;
234 }
235}
236
238 if (ldTabstops) {
239 if (linesAdded > 0) {
240 for (Sci::Line line = lineOfPos; line < lineOfPos + linesAdded; line++) {
241 ldTabstops->InsertLine(line);
242 }
243 } else {
244 for (Sci::Line line = (lineOfPos + -linesAdded) - 1; line >= lineOfPos; line--) {
245 ldTabstops->RemoveLine(line);
246 }
247 }
248 }
249}
250
251void EditView::DropGraphics(bool freeObjects) {
252 if (freeObjects) {
253 pixmapLine.reset();
254 pixmapIndentGuide.reset();
256 } else {
257 if (pixmapLine)
258 pixmapLine->Release();
260 pixmapIndentGuide->Release();
263 }
264}
265
267 if (!pixmapLine)
273}
274
275static const char *ControlCharacterString(unsigned char ch) noexcept {
276 const char * const reps[] = {
277 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
278 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
279 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
280 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
281 };
282 if (ch < Sci::size(reps)) {
283 return reps[ch];
284 } else {
285 return "BAD";
286 }
287}
288
289static void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid, const ViewStyle &vsDraw) {
290 const IntegerRectangle ircTab(rcTab);
291 if ((rcTab.left + 2) < (rcTab.right - 1))
292 surface->MoveTo(ircTab.left + 2, ymid);
293 else
294 surface->MoveTo(ircTab.right - 1, ymid);
295 surface->LineTo(ircTab.right - 1, ymid);
296
297 // Draw the arrow head if needed
298 if (vsDraw.tabDrawMode == tdLongArrow) {
299 int ydiff = (ircTab.bottom - ircTab.top) / 2;
300 int xhead = ircTab.right - 1 - ydiff;
301 if (xhead <= rcTab.left) {
302 ydiff -= ircTab.left - xhead - 1;
303 xhead = ircTab.left - 1;
304 }
305 surface->LineTo(xhead, ymid - ydiff);
306 surface->MoveTo(ircTab.right - 1, ymid);
307 surface->LineTo(xhead, ymid + ydiff);
308 }
309}
310
311void EditView::RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw) {
312 if (!pixmapIndentGuide->Initialised()) {
313 // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line
314 pixmapIndentGuide->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid);
315 pixmapIndentGuideHighlight->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid);
316 const PRectangle rcIG = PRectangle::FromInts(0, 0, 1, vsDraw.lineHeight);
317 pixmapIndentGuide->FillRectangle(rcIG, vsDraw.styles[STYLE_INDENTGUIDE].back);
318 pixmapIndentGuideHighlight->FillRectangle(rcIG, vsDraw.styles[STYLE_BRACELIGHT].back);
319 for (int stripe = 1; stripe < vsDraw.lineHeight + 1; stripe += 2) {
320 const PRectangle rcPixel = PRectangle::FromInts(0, stripe, 1, stripe + 1);
321 pixmapIndentGuide->FillRectangle(rcPixel, vsDraw.styles[STYLE_INDENTGUIDE].fore);
322 pixmapIndentGuideHighlight->FillRectangle(rcPixel, vsDraw.styles[STYLE_BRACELIGHT].fore);
323 }
324 }
325}
326
328 const Sci::Position posLineStart = model.pdoc->LineStart(lineNumber);
329 const Sci::Position posLineEnd = model.pdoc->LineStart(lineNumber + 1);
330 PLATFORM_ASSERT(posLineEnd >= posLineStart);
331 const Sci::Line lineCaret = model.pdoc->SciLineFromPosition(model.sel.MainCaret());
332 return llc.Retrieve(lineNumber, lineCaret,
333 static_cast<int>(posLineEnd - posLineStart), model.pdoc->GetStyleClock(),
334 model.LinesOnScreen() + 1, model.pdoc->LinesTotal());
335}
336
337namespace {
338
339constexpr XYPOSITION epsilon = 0.0001f; // A small nudge to avoid floating point precision issues
340
341/**
342* Return the chDoc argument with case transformed as indicated by the caseForce argument.
343* chPrevious is needed for camel casing.
344* This only affects ASCII characters and is provided for languages with case-insensitive
345* ASCII keywords where the user wishes to view keywords in a preferred case.
346*/
347inline char CaseForce(Style::ecaseForced caseForce, char chDoc, char chPrevious) {
348 switch (caseForce) {
349 case Style::caseMixed:
350 return chDoc;
351 case Style::caseLower:
352 return MakeLowerCase(chDoc);
353 case Style::caseUpper:
354 return MakeUpperCase(chDoc);
355 case Style::caseCamel:
356 default: // default should not occur, included to avoid warnings
357 if (IsUpperOrLowerCase(chDoc) && !IsUpperOrLowerCase(chPrevious)) {
358 return MakeUpperCase(chDoc);
359 } else {
360 return MakeLowerCase(chDoc);
361 }
362 }
363}
364
365constexpr bool IsControlCharacter(int ch) noexcept {
366 // iscntrl returns true for lots of chars > 127 which are displayable,
367 // currently only check C0 control characters.
368 return (ch >= 0 && ch < ' ') || (ch == 127);
369}
370
371}
372
373/**
374* Fill in the LineLayout data for the given line.
375* Copy the given @a line and its styles from the document into local arrays.
376* Also determine the x position at which each character starts.
377*/
378void EditView::LayoutLine(const EditModel &model, Sci::Line line, Surface *surface, const ViewStyle &vstyle, LineLayout *ll, int width) {
379 if (!ll)
380 return;
381
382 PLATFORM_ASSERT(line < model.pdoc->LinesTotal());
383 PLATFORM_ASSERT(ll->chars != NULL);
384 const Sci::Position posLineStart = model.pdoc->LineStart(line);
385 Sci::Position posLineEnd = model.pdoc->LineStart(line + 1);
386 // If the line is very long, limit the treatment to a length that should fit in the viewport
387 if (posLineEnd >(posLineStart + ll->maxLineLength)) {
388 posLineEnd = posLineStart + ll->maxLineLength;
389 }
390 // Hard to cope when too narrow, so just assume there is space
391 width = std::max(width, 20);
392
394 Sci::Position lineLength = posLineEnd - posLineStart;
395 if (!vstyle.viewEOL) {
396 lineLength = model.pdoc->LineEnd(line) - posLineStart;
397 }
398 if (lineLength == ll->numCharsInLine) {
399 // See if chars, styles, indicators, are all the same
400 bool allSame = true;
401 // Check base line layout
402 char chPrevious = 0;
403 for (Sci::Position numCharsInLine = 0; numCharsInLine < lineLength; numCharsInLine++) {
404 const Sci::Position charInDoc = numCharsInLine + posLineStart;
405 const char chDoc = model.pdoc->CharAt(charInDoc);
406 const int styleByte = model.pdoc->StyleIndexAt(charInDoc);
407 allSame = allSame &&
408 (ll->styles[numCharsInLine] == styleByte);
409 allSame = allSame &&
410 (ll->chars[numCharsInLine] == CaseForce(vstyle.styles[styleByte].caseForce, chDoc, chPrevious));
411 chPrevious = chDoc;
412 }
413 const int styleByteLast = (posLineEnd > posLineStart) ? model.pdoc->StyleIndexAt(posLineEnd - 1) : 0;
414 allSame = allSame && (ll->styles[lineLength] == styleByteLast); // For eolFilled
415 if (allSame) {
417 } else {
419 }
420 } else {
422 }
423 }
426 ll->lines = 1;
427 if (vstyle.edgeState == EDGE_BACKGROUND) {
428 Sci::Position edgePosition = model.pdoc->FindColumn(line, vstyle.theEdge.column);
429 if (edgePosition >= posLineStart) {
430 edgePosition -= posLineStart;
431 }
432 ll->edgeColumn = static_cast<int>(edgePosition);
433 } else {
434 ll->edgeColumn = -1;
435 }
436
437 // Fill base line layout
438 const int lineLength = static_cast<int>(posLineEnd - posLineStart);
439 model.pdoc->GetCharRange(ll->chars.get(), posLineStart, lineLength);
440 model.pdoc->GetStyleRange(ll->styles.get(), posLineStart, lineLength);
441 const int numCharsBeforeEOL = static_cast<int>(model.pdoc->LineEnd(line) - posLineStart);
442 const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL;
443 const unsigned char styleByteLast = (lineLength > 0) ? ll->styles[lineLength - 1] : 0;
444 if (vstyle.someStylesForceCase) {
445 char chPrevious = 0;
446 for (int charInLine = 0; charInLine<lineLength; charInLine++) {
447 const char chDoc = ll->chars[charInLine];
448 ll->chars[charInLine] = CaseForce(vstyle.styles[ll->styles[charInLine]].caseForce, chDoc, chPrevious);
449 chPrevious = chDoc;
450 }
451 }
452 ll->xHighlightGuide = 0;
453 // Extra element at the end of the line to hold end x position and act as
454 ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character
455 ll->styles[numCharsInLine] = styleByteLast; // For eolFilled
456
457 // Layout the line, determining the position of each character,
458 // with an extra element at the end for the end of the line.
459 ll->positions[0] = 0;
460 bool lastSegItalics = false;
461
462 BreakFinder bfLayout(ll, nullptr, Range(0, numCharsInLine), posLineStart, 0, false, model.pdoc, &model.reprs, nullptr);
463 while (bfLayout.More()) {
464
465 const TextSegment ts = bfLayout.Next();
466
467 std::fill(&ll->positions[ts.start + 1], &ll->positions[ts.end() + 1], 0.0f);
468 if (vstyle.styles[ll->styles[ts.start]].visible) {
469 if (ts.representation) {
470 XYPOSITION representationWidth = vstyle.controlCharWidth;
471 if (ll->chars[ts.start] == '\t') {
472 // Tab is a special case of representation, taking a variable amount of space
473 const XYPOSITION x = ll->positions[ts.start];
474 representationWidth = NextTabstopPos(line, x, vstyle.tabWidth) - ll->positions[ts.start];
475 } else {
476 if (representationWidth <= 0.0) {
477 XYPOSITION positionsRepr[256]; // Should expand when needed
479 static_cast<unsigned int>(ts.representation->stringRep.length()), positionsRepr, model.pdoc);
480 representationWidth = positionsRepr[ts.representation->stringRep.length() - 1] + vstyle.ctrlCharPadding;
481 }
482 }
483 for (int ii = 0; ii < ts.length; ii++)
484 ll->positions[ts.start + 1 + ii] = representationWidth;
485 } else {
486 if ((ts.length == 1) && (' ' == ll->chars[ts.start])) {
487 // Over half the segments are single characters and of these about half are space characters.
488 ll->positions[ts.start + 1] = vstyle.styles[ll->styles[ts.start]].spaceWidth;
489 } else {
490 posCache.MeasureWidths(surface, vstyle, ll->styles[ts.start], &ll->chars[ts.start],
491 ts.length, &ll->positions[ts.start + 1], model.pdoc);
492 }
493 }
494 lastSegItalics = (!ts.representation) && ((ll->chars[ts.end() - 1] != ' ') && vstyle.styles[ll->styles[ts.start]].italic);
495 }
496
497 for (Sci::Position posToIncrease = ts.start + 1; posToIncrease <= ts.end(); posToIncrease++) {
498 ll->positions[posToIncrease] += ll->positions[ts.start];
499 }
500 }
501
502 // Small hack to make lines that end with italics not cut off the edge of the last character
503 if (lastSegItalics) {
504 ll->positions[numCharsInLine] += vstyle.lastSegItalicsOffset;
505 }
506 ll->numCharsInLine = numCharsInLine;
507 ll->numCharsBeforeEOL = numCharsBeforeEOL;
509 }
510 if ((ll->validity == LineLayout::ValidLevel::positions) || (ll->widthLine != width)) {
511 ll->widthLine = width;
512 if (width == LineLayout::wrapWidthInfinite) {
513 ll->lines = 1;
514 } else if (width > ll->positions[ll->numCharsInLine]) {
515 // Simple common case where line does not need wrapping.
516 ll->lines = 1;
517 } else {
519 width -= static_cast<int>(vstyle.aveCharWidth); // take into account the space for end wrap mark
520 }
521 XYPOSITION wrapAddIndent = 0; // This will be added to initial indent of line
522 switch (vstyle.wrapIndentMode) {
524 wrapAddIndent = vstyle.wrapVisualStartIndent * vstyle.aveCharWidth;
525 break;
527 wrapAddIndent = model.pdoc->IndentSize() * vstyle.spaceWidth;
528 break;
530 wrapAddIndent = model.pdoc->IndentSize() * 2 * vstyle.spaceWidth;
531 break;
532 }
533 ll->wrapIndent = wrapAddIndent;
534 if (vstyle.wrapIndentMode != SC_WRAPINDENT_FIXED) {
535 for (int i = 0; i < ll->numCharsInLine; i++) {
536 if (!IsSpaceOrTab(ll->chars[i])) {
537 ll->wrapIndent += ll->positions[i]; // Add line indent
538 break;
539 }
540 }
541 }
542 // Check for text width minimum
543 if (ll->wrapIndent > width - static_cast<int>(vstyle.aveCharWidth) * 15)
544 ll->wrapIndent = wrapAddIndent;
545 // Check for wrapIndent minimum
547 ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual
548 ll->lines = 0;
549 // Calculate line start positions based upon width.
550 Sci::Position lastGoodBreak = 0;
551 Sci::Position lastLineStart = 0;
552 XYACCUMULATOR startOffset = 0;
553 Sci::Position p = 0;
554 while (p < ll->numCharsInLine) {
555 if ((ll->positions[p + 1] - startOffset) >= width) {
556 if (lastGoodBreak == lastLineStart) {
557 // Try moving to start of last character
558 if (p > 0) {
559 lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1)
560 - posLineStart;
561 }
562 if (lastGoodBreak == lastLineStart) {
563 // Ensure at least one character on line.
564 lastGoodBreak = model.pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1)
565 - posLineStart;
566 }
567 }
568 lastLineStart = lastGoodBreak;
569 ll->lines++;
570 ll->SetLineStart(ll->lines, static_cast<int>(lastGoodBreak));
571 startOffset = ll->positions[lastGoodBreak];
572 // take into account the space for start wrap mark and indent
573 startOffset -= ll->wrapIndent;
574 p = lastGoodBreak + 1;
575 continue;
576 }
577 if (p > 0) {
578 if (vstyle.wrapState == WrapMode::character) {
579 lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1)
580 - posLineStart;
581 p = model.pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart;
582 continue;
583 } else if ((vstyle.wrapState == WrapMode::word) && (ll->styles[p] != ll->styles[p - 1])) {
584 lastGoodBreak = p;
585 } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) {
586 lastGoodBreak = p;
587 }
588 }
589 p++;
590 }
591 ll->lines++;
592 }
594 }
595}
596
598 const ViewStyle &vs, PointEnd pe) {
599 Point pt;
600 if (pos.Position() == INVALID_POSITION)
601 return pt;
602 Sci::Line lineDoc = model.pdoc->SciLineFromPosition(pos.Position());
603 Sci::Position posLineStart = model.pdoc->LineStart(lineDoc);
604 if ((pe & peLineEnd) && (lineDoc > 0) && (pos.Position() == posLineStart)) {
605 // Want point at end of first line
606 lineDoc--;
607 posLineStart = model.pdoc->LineStart(lineDoc);
608 }
609 const Sci::Line lineVisible = model.pcs->DisplayFromDoc(lineDoc);
610 AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
611 if (surface && ll) {
612 LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
613 const int posInLine = static_cast<int>(pos.Position() - posLineStart);
614 pt = ll->PointFromPosition(posInLine, vs.lineHeight, pe);
615 pt.y += (lineVisible - topLine) * vs.lineHeight;
616 pt.x += vs.textStart - model.xOffset;
617 }
618 pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth;
619 return pt;
620}
621
622Range EditView::RangeDisplayLine(Surface *surface, const EditModel &model, Sci::Line lineVisible, const ViewStyle &vs) {
623 Range rangeSubLine = Range(0, 0);
624 if (lineVisible < 0) {
625 return rangeSubLine;
626 }
627 const Sci::Line lineDoc = model.pcs->DocFromDisplay(lineVisible);
628 const Sci::Position positionLineStart = model.pdoc->LineStart(lineDoc);
629 AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
630 if (surface && ll) {
631 LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
632 const Sci::Line lineStartSet = model.pcs->DisplayFromDoc(lineDoc);
633 const int subLine = static_cast<int>(lineVisible - lineStartSet);
634 if (subLine < ll->lines) {
635 rangeSubLine = ll->SubLineRange(subLine, LineLayout::Scope::visibleOnly);
636 if (subLine == ll->lines-1) {
637 rangeSubLine.end = model.pdoc->LineStart(lineDoc + 1) -
638 positionLineStart;
639 }
640 }
641 }
642 rangeSubLine.start += positionLineStart;
643 rangeSubLine.end += positionLineStart;
644 return rangeSubLine;
645}
646
647SelectionPosition EditView::SPositionFromLocation(Surface *surface, const EditModel &model, PointDocument pt, bool canReturnInvalid, bool charPosition, bool virtualSpace, const ViewStyle &vs) {
648 pt.x = pt.x - vs.textStart;
649 Sci::Line visibleLine = static_cast<int>(std::floor(pt.y / vs.lineHeight));
650 if (!canReturnInvalid && (visibleLine < 0))
651 visibleLine = 0;
652 const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine);
653 if (canReturnInvalid && (lineDoc < 0))
655 if (lineDoc >= model.pdoc->LinesTotal())
656 return SelectionPosition(canReturnInvalid ? INVALID_POSITION :
657 model.pdoc->Length());
658 const Sci::Position posLineStart = model.pdoc->LineStart(lineDoc);
659 AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
660 if (surface && ll) {
661 LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
662 const Sci::Line lineStartSet = model.pcs->DisplayFromDoc(lineDoc);
663 const int subLine = static_cast<int>(visibleLine - lineStartSet);
664 if (subLine < ll->lines) {
665 const Range rangeSubLine = ll->SubLineRange(subLine, LineLayout::Scope::visibleOnly);
666 const XYPOSITION subLineStart = ll->positions[rangeSubLine.start];
667 if (subLine > 0) // Wrapped
668 pt.x -= ll->wrapIndent;
669 const Sci::Position positionInLine = ll->FindPositionFromX(static_cast<XYPOSITION>(pt.x + subLineStart),
670 rangeSubLine, charPosition);
671 if (positionInLine < rangeSubLine.end) {
672 return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1));
673 }
674 if (virtualSpace) {
675 const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth;
676 const int spaceOffset = static_cast<int>(
677 (pt.x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth);
678 return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset);
679 } else if (canReturnInvalid) {
680 if (pt.x < (ll->positions[rangeSubLine.end] - subLineStart)) {
681 return SelectionPosition(model.pdoc->MovePositionOutsideChar(rangeSubLine.end + posLineStart, 1));
682 }
683 } else {
684 return SelectionPosition(rangeSubLine.end + posLineStart);
685 }
686 }
687 if (!canReturnInvalid)
688 return SelectionPosition(ll->numCharsInLine + posLineStart);
689 }
690 return SelectionPosition(canReturnInvalid ? INVALID_POSITION : posLineStart);
691}
692
693/**
694* Find the document position corresponding to an x coordinate on a particular document line.
695* Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
696* This method is used for rectangular selections and does not work on wrapped lines.
697*/
698SelectionPosition EditView::SPositionFromLineX(Surface *surface, const EditModel &model, Sci::Line lineDoc, int x, const ViewStyle &vs) {
699 AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
700 if (surface && ll) {
701 const Sci::Position posLineStart = model.pdoc->LineStart(lineDoc);
702 LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
703 const Range rangeSubLine = ll->SubLineRange(0, LineLayout::Scope::visibleOnly);
704 const XYPOSITION subLineStart = ll->positions[rangeSubLine.start];
705 const Sci::Position positionInLine = ll->FindPositionFromX(x + subLineStart, rangeSubLine, false);
706 if (positionInLine < rangeSubLine.end) {
707 return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1));
708 }
709 const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth;
710 const int spaceOffset = static_cast<int>(
711 (x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth);
712 return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset);
713 }
714 return SelectionPosition(0);
715}
716
718 const Sci::Line lineDoc = model.pdoc->SciLineFromPosition(pos);
719 Sci::Line lineDisplay = model.pcs->DisplayFromDoc(lineDoc);
720 AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
721 if (surface && ll) {
722 LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
723 const Sci::Position posLineStart = model.pdoc->LineStart(lineDoc);
724 const Sci::Position posInLine = pos - posLineStart;
725 lineDisplay--; // To make up for first increment ahead.
726 for (int subLine = 0; subLine < ll->lines; subLine++) {
727 if (posInLine >= ll->LineStart(subLine)) {
728 lineDisplay++;
729 }
730 }
731 }
732 return lineDisplay;
733}
734
736 const Sci::Line line = model.pdoc->SciLineFromPosition(pos);
739 if (surface && ll) {
740 const Sci::Position posLineStart = model.pdoc->LineStart(line);
741 LayoutLine(model, line, surface, vs, ll, model.wrapWidth);
742 const Sci::Position posInLine = pos - posLineStart;
743 if (posInLine <= ll->maxLineLength) {
744 for (int subLine = 0; subLine < ll->lines; subLine++) {
745 if ((posInLine >= ll->LineStart(subLine)) &&
746 (posInLine <= ll->LineStart(subLine + 1)) &&
747 (posInLine <= ll->numCharsBeforeEOL)) {
748 if (start) {
749 posRet = ll->LineStart(subLine) + posLineStart;
750 } else {
751 if (subLine == ll->lines - 1)
752 posRet = ll->numCharsBeforeEOL + posLineStart;
753 else
754 posRet = ll->LineStart(subLine + 1) + posLineStart - 1;
755 }
756 }
757 }
758 }
759 }
760 return posRet;
761}
762
763static ColourDesired SelectionBackground(const ViewStyle &vsDraw, bool main, bool primarySelection) noexcept {
764 return main ?
765 (primarySelection ? vsDraw.selColours.back : vsDraw.selBackground2) :
766 vsDraw.selAdditionalBackground;
767}
768
769static ColourDesired TextBackground(const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
770 ColourOptional background, int inSelection, bool inHotspot, int styleMain, Sci::Position i) noexcept {
771 if (inSelection == 1) {
772 if (vsDraw.selColours.back.isSet && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
773 return SelectionBackground(vsDraw, true, model.primarySelection);
774 }
775 } else if (inSelection == 2) {
776 if (vsDraw.selColours.back.isSet && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) {
777 return SelectionBackground(vsDraw, false, model.primarySelection);
778 }
779 } else {
780 if ((vsDraw.edgeState == EDGE_BACKGROUND) &&
781 (i >= ll->edgeColumn) &&
782 (i < ll->numCharsBeforeEOL))
783 return vsDraw.theEdge.colour;
784 if (inHotspot && vsDraw.hotspotColours.back.isSet)
785 return vsDraw.hotspotColours.back;
786 }
787 if (background.isSet && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD)) {
788 return background;
789 } else {
790 return vsDraw.styles[styleMain].back;
791 }
792}
793
794void EditView::DrawIndentGuide(Surface *surface, Sci::Line lineVisible, int lineHeight, XYPOSITION start, PRectangle rcSegment, bool highlight) {
795 const Point from = Point::FromInts(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0);
796 const PRectangle rcCopyArea(start + 1, rcSegment.top,
797 start + 2, rcSegment.bottom);
798 surface->Copy(rcCopyArea, from,
800}
801
802static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourDesired fill, int alpha) {
803 if (alpha != SC_ALPHA_NOALPHA) {
804 surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0);
805 }
806}
807
808static void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegment,
809 const char *s, ColourDesired textBack, ColourDesired textFore, bool fillBackground) {
810 if (rcSegment.Empty())
811 return;
812 if (fillBackground) {
813 surface->FillRectangle(rcSegment, textBack);
814 }
815 FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
816 const int normalCharHeight = static_cast<int>(std::ceil(vsDraw.styles[STYLE_CONTROLCHAR].capitalHeight));
817 PRectangle rcCChar = rcSegment;
818 rcCChar.left = rcCChar.left + 1;
819 rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
820 rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
821 PRectangle rcCentral = rcCChar;
822 rcCentral.top++;
823 rcCentral.bottom--;
824 surface->FillRectangle(rcCentral, textFore);
825 PRectangle rcChar = rcCChar;
826 rcChar.left++;
827 rcChar.right--;
828 surface->DrawTextClipped(rcChar, ctrlCharsFont,
829 rcSegment.top + vsDraw.maxAscent, s, static_cast<int>(s ? strlen(s) : 0),
830 textBack, textFore);
831}
832
833static void DrawFrame(Surface *surface, ColourDesired colour, int alpha, PRectangle rcFrame) {
834 if (alpha != SC_ALPHA_NOALPHA)
835 surface->AlphaRectangle(rcFrame, 0, colour, alpha, colour, alpha, 0);
836 else
837 surface->FillRectangle(rcFrame, colour);
838}
839
840static void DrawCaretLineFramed(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, int subLine) {
841 const int width = vsDraw.GetFrameWidth();
842 if (subLine == 0 || ll->wrapIndent == 0 || vsDraw.caretLineAlpha != SC_ALPHA_NOALPHA) {
843 // Left
844 DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha,
845 PRectangle(rcLine.left, rcLine.top, rcLine.left + width, rcLine.bottom));
846 }
847 if (subLine == 0) {
848 // Top
849 DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha,
850 PRectangle(rcLine.left + width, rcLine.top, rcLine.right - width, rcLine.top + width));
851 }
852 if (subLine == ll->lines - 1 || vsDraw.caretLineAlpha != SC_ALPHA_NOALPHA) {
853 // Right
854 DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha,
855 PRectangle(rcLine.right - width, rcLine.top, rcLine.right, rcLine.bottom));
856 }
857 if (subLine == ll->lines - 1) {
858 // Bottom
859 DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha,
860 PRectangle(rcLine.left + width, rcLine.bottom - width, rcLine.right - width, rcLine.bottom));
861 }
862}
863
864void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
865 PRectangle rcLine, Sci::Line line, Sci::Position lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart,
866 ColourOptional background) {
867
868 const Sci::Position posLineStart = model.pdoc->LineStart(line);
869 PRectangle rcSegment = rcLine;
870
871 const bool lastSubLine = subLine == (ll->lines - 1);
872 XYPOSITION virtualSpace = 0;
873 if (lastSubLine) {
874 const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth;
875 virtualSpace = model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)) * spaceWidth;
876 }
877 const XYPOSITION xEol = static_cast<XYPOSITION>(ll->positions[lineEnd] - subLineStart);
878
879 // Fill the virtual space and show selections within it
880 if (virtualSpace > 0.0f) {
881 rcSegment.left = xEol + xStart;
882 rcSegment.right = xEol + xStart + virtualSpace;
883 surface->FillRectangle(rcSegment, background.isSet ? background : vsDraw.styles[ll->styles[ll->numCharsInLine]].back);
884 if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) {
885 const SelectionSegment virtualSpaceRange(SelectionPosition(model.pdoc->LineEnd(line)),
887 model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line))));
888 for (size_t r = 0; r<model.sel.Count(); r++) {
889 const int alpha = (r == model.sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
890 if (alpha == SC_ALPHA_NOALPHA) {
891 const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange);
892 if (!portion.Empty()) {
893 const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth;
894 rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] -
895 static_cast<XYPOSITION>(subLineStart)+portion.start.VirtualSpace() * spaceWidth;
896 rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] -
897 static_cast<XYPOSITION>(subLineStart)+portion.end.VirtualSpace() * spaceWidth;
898 rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left;
899 rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right;
900 surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection));
901 }
902 }
903 }
904 }
905 }
906
907 int eolInSelection = 0;
908 int alpha = SC_ALPHA_NOALPHA;
909 if (!hideSelection) {
910 const Sci::Position posAfterLineEnd = model.pdoc->LineStart(line + 1);
911 eolInSelection = lastSubLine ? model.sel.InSelectionForEOL(posAfterLineEnd) : 0;
912 alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
913 }
914
915 // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on
916 XYPOSITION blobsWidth = 0;
917 if (lastSubLine) {
918 for (Sci::Position eolPos = ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine; eolPos++) {
919 rcSegment.left = xStart + ll->positions[eolPos] - static_cast<XYPOSITION>(subLineStart)+virtualSpace;
920 rcSegment.right = xStart + ll->positions[eolPos + 1] - static_cast<XYPOSITION>(subLineStart)+virtualSpace;
921 blobsWidth += rcSegment.Width();
922 char hexits[4] = "";
923 const char *ctrlChar;
924 const unsigned char chEOL = ll->chars[eolPos];
925 const int styleMain = ll->styles[eolPos];
926 const ColourDesired textBack = TextBackground(model, vsDraw, ll, background, eolInSelection, false, styleMain, eolPos);
927 if (UTF8IsAscii(chEOL)) {
928 ctrlChar = ControlCharacterString(chEOL);
929 } else {
930 const Representation *repr = model.reprs.RepresentationFromCharacter(&ll->chars[eolPos], ll->numCharsInLine - eolPos);
931 if (repr) {
932 ctrlChar = repr->stringRep.c_str();
933 eolPos = ll->numCharsInLine;
934 } else {
935 sprintf(hexits, "x%2X", chEOL);
936 ctrlChar = hexits;
937 }
938 }
939 ColourDesired textFore = vsDraw.styles[styleMain].fore;
940 if (eolInSelection && vsDraw.selColours.fore.isSet) {
941 textFore = (eolInSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground;
942 }
943 if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1)) {
944 if (alpha == SC_ALPHA_NOALPHA) {
945 surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection));
946 } else {
947 surface->FillRectangle(rcSegment, textBack);
948 }
949 } else {
950 surface->FillRectangle(rcSegment, textBack);
951 }
952 DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, phasesDraw == phasesOne);
953 if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
954 SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha);
955 }
956 }
957 }
958
959 // Draw the eol-is-selected rectangle
960 rcSegment.left = xEol + xStart + virtualSpace + blobsWidth;
961 rcSegment.right = rcSegment.left + vsDraw.aveCharWidth;
962
963 if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) {
964 surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection));
965 } else {
966 if (background.isSet) {
967 surface->FillRectangle(rcSegment, background);
968 } else if (line < model.pdoc->LinesTotal() - 1) {
969 surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back);
970 } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) {
971 surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back);
972 } else {
973 surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back);
974 }
975 if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
976 SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha);
977 }
978 }
979
980 rcSegment.left = rcSegment.right;
981 if (rcSegment.left < rcLine.left)
982 rcSegment.left = rcLine.left;
983 rcSegment.right = rcLine.right;
984
985 const bool drawEOLAnnotationStyledText = (vsDraw.eolAnnotationVisible != EOLANNOTATION_HIDDEN) && model.pdoc->EOLAnnotationStyledText(line).text;
986 const bool fillRemainder = (!lastSubLine || (!model.GetFoldDisplayText(line) && !drawEOLAnnotationStyledText));
987 if (fillRemainder) {
988 // Fill the remainder of the line
989 FillLineRemainder(surface, model, vsDraw, ll, line, rcSegment, subLine);
990 }
991
992 bool drawWrapMarkEnd = false;
993
994 if (subLine + 1 < ll->lines) {
996 drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0;
997 }
998 if (vsDraw.IsLineFrameOpaque(model.caret.active, ll->containsCaret)) {
999 const int width = vsDraw.GetFrameWidth();
1000 // Draw right of frame under marker
1001 DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha,
1002 PRectangle(rcLine.right - width, rcLine.top, rcLine.right, rcLine.bottom));
1003 }
1004 }
1005
1006 if (drawWrapMarkEnd) {
1007 PRectangle rcPlace = rcSegment;
1008
1010 rcPlace.left = xEol + xStart + virtualSpace;
1011 rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
1012 } else {
1013 // rcLine is clipped to text area
1014 rcPlace.right = rcLine.right;
1015 rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
1016 }
1017 if (!customDrawWrapMarker) {
1018 DrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour());
1019 } else {
1020 customDrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour());
1021 }
1022 }
1023}
1024
1025static void DrawIndicator(int indicNum, Sci::Position startPos, Sci::Position endPos, Surface *surface, const ViewStyle &vsDraw,
1026 const LineLayout *ll, int xStart, PRectangle rcLine, Sci::Position secondCharacter, int subLine, Indicator::State state, int value) {
1027 const XYPOSITION subLineStart = ll->positions[ll->LineStart(subLine)];
1028 const PRectangle rcIndic(
1029 ll->positions[startPos] + xStart - subLineStart,
1030 rcLine.top + vsDraw.maxAscent,
1031 ll->positions[endPos] + xStart - subLineStart,
1032 rcLine.top + vsDraw.maxAscent + 3);
1033 PRectangle rcFirstCharacter = rcIndic;
1034 // Allow full descent space for character indicators
1035 rcFirstCharacter.bottom = rcLine.top + vsDraw.maxAscent + vsDraw.maxDescent;
1036 if (secondCharacter >= 0) {
1037 rcFirstCharacter.right = ll->positions[secondCharacter] + xStart - subLineStart;
1038 } else {
1039 // Indicator continued from earlier line so make an empty box and don't draw
1040 rcFirstCharacter.right = rcFirstCharacter.left;
1041 }
1042 vsDraw.indicators[indicNum].Draw(surface, rcIndic, rcLine, rcFirstCharacter, state, value);
1043}
1044
1045static void DrawIndicators(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
1046 Sci::Line line, int xStart, PRectangle rcLine, int subLine, Sci::Position lineEnd, bool under, Sci::Position hoverIndicatorPos) {
1047 // Draw decorators
1048 const Sci::Position posLineStart = model.pdoc->LineStart(line);
1049 const Sci::Position lineStart = ll->LineStart(subLine);
1050 const Sci::Position posLineEnd = posLineStart + lineEnd;
1051
1052 for (const IDecoration *deco : model.pdoc->decorations->View()) {
1053 if (under == vsDraw.indicators[deco->Indicator()].under) {
1054 Sci::Position startPos = posLineStart + lineStart;
1055 if (!deco->ValueAt(startPos)) {
1056 startPos = deco->EndRun(startPos);
1057 }
1058 while ((startPos < posLineEnd) && (deco->ValueAt(startPos))) {
1059 const Range rangeRun(deco->StartRun(startPos), deco->EndRun(startPos));
1060 const Sci::Position endPos = std::min(rangeRun.end, posLineEnd);
1061 const bool hover = vsDraw.indicators[deco->Indicator()].IsDynamic() &&
1062 rangeRun.ContainsCharacter(hoverIndicatorPos);
1063 const int value = deco->ValueAt(startPos);
1065 const Sci::Position posSecond = model.pdoc->MovePositionOutsideChar(rangeRun.First() + 1, 1);
1066 DrawIndicator(deco->Indicator(), startPos - posLineStart, endPos - posLineStart,
1067 surface, vsDraw, ll, xStart, rcLine, posSecond - posLineStart, subLine, state, value);
1068 startPos = endPos;
1069 if (!deco->ValueAt(startPos)) {
1070 startPos = deco->EndRun(startPos);
1071 }
1072 }
1073 }
1074 }
1075
1076 // Use indicators to highlight matching braces
1079 const int braceIndicator = (model.bracesMatchStyle == STYLE_BRACELIGHT) ? vsDraw.braceHighlightIndicator : vsDraw.braceBadLightIndicator;
1080 if (under == vsDraw.indicators[braceIndicator].under) {
1081 const Range rangeLine(posLineStart + lineStart, posLineEnd);
1082 if (rangeLine.ContainsCharacter(model.braces[0])) {
1083 const Sci::Position braceOffset = model.braces[0] - posLineStart;
1084 if (braceOffset < ll->numCharsInLine) {
1085 const Sci::Position secondOffset = model.pdoc->MovePositionOutsideChar(model.braces[0] + 1, 1) - posLineStart;
1086 DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, secondOffset, subLine, Indicator::State::normal, 1);
1087 }
1088 }
1089 if (rangeLine.ContainsCharacter(model.braces[1])) {
1090 const Sci::Position braceOffset = model.braces[1] - posLineStart;
1091 if (braceOffset < ll->numCharsInLine) {
1092 const Sci::Position secondOffset = model.pdoc->MovePositionOutsideChar(model.braces[1] + 1, 1) - posLineStart;
1093 DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, secondOffset, subLine, Indicator::State::normal, 1);
1094 }
1095 }
1096 }
1097 }
1098}
1099
1100void EditView::DrawFoldDisplayText(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
1101 Sci::Line line, int xStart, PRectangle rcLine, int subLine, XYACCUMULATOR subLineStart, DrawPhase phase) {
1102 const bool lastSubLine = subLine == (ll->lines - 1);
1103 if (!lastSubLine)
1104 return;
1105
1106 const char *text = model.GetFoldDisplayText(line);
1107 if (!text)
1108 return;
1109
1110 PRectangle rcSegment = rcLine;
1111 const char *foldDisplayText = text;
1112 const int lengthFoldDisplayText = static_cast<int>(strlen(foldDisplayText));
1113 FontAlias fontText = vsDraw.styles[STYLE_FOLDDISPLAYTEXT].font;
1114 const int widthFoldDisplayText = static_cast<int>(surface->WidthText(fontText, foldDisplayText, lengthFoldDisplayText));
1115
1116 int eolInSelection = 0;
1117 int alpha = SC_ALPHA_NOALPHA;
1118 if (!hideSelection) {
1119 const Sci::Position posAfterLineEnd = model.pdoc->LineStart(line + 1);
1120 eolInSelection = (subLine == (ll->lines - 1)) ? model.sel.InSelectionForEOL(posAfterLineEnd) : 0;
1121 alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
1122 }
1123
1124 const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth;
1125 const XYPOSITION virtualSpace = model.sel.VirtualSpaceFor(
1126 model.pdoc->LineEnd(line)) * spaceWidth;
1127 rcSegment.left = xStart + static_cast<XYPOSITION>(ll->positions[ll->numCharsInLine] - subLineStart) + virtualSpace + vsDraw.aveCharWidth;
1128 rcSegment.right = rcSegment.left + static_cast<XYPOSITION>(widthFoldDisplayText);
1129
1130 const ColourOptional background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret);
1131 ColourDesired textFore = vsDraw.styles[STYLE_FOLDDISPLAYTEXT].fore;
1132 if (eolInSelection && (vsDraw.selColours.fore.isSet)) {
1133 textFore = (eolInSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground;
1134 }
1135 const ColourDesired textBack = TextBackground(model, vsDraw, ll, background, eolInSelection,
1136 false, STYLE_FOLDDISPLAYTEXT, -1);
1137
1138 if (model.trackLineWidth) {
1139 if (rcSegment.right + 1> lineWidthMaxSeen) {
1140 // Fold display text border drawn on rcSegment.right with width 1 is the last visible object of the line
1141 lineWidthMaxSeen = static_cast<int>(rcSegment.right + 1);
1142 }
1143 }
1144
1145 if (phase & drawBack) {
1146 surface->FillRectangle(rcSegment, textBack);
1147
1148 // Fill Remainder of the line
1149 PRectangle rcRemainder = rcSegment;
1150 rcRemainder.left = rcRemainder.right;
1151 if (rcRemainder.left < rcLine.left)
1152 rcRemainder.left = rcLine.left;
1153 rcRemainder.right = rcLine.right;
1154 FillLineRemainder(surface, model, vsDraw, ll, line, rcRemainder, subLine);
1155 }
1156
1157 if (phase & drawText) {
1158 if (phasesDraw != phasesOne) {
1159 surface->DrawTextTransparent(rcSegment, fontText,
1160 rcSegment.top + vsDraw.maxAscent, foldDisplayText,
1161 lengthFoldDisplayText, textFore);
1162 } else {
1163 surface->DrawTextNoClip(rcSegment, fontText,
1164 rcSegment.top + vsDraw.maxAscent, foldDisplayText,
1165 lengthFoldDisplayText, textFore, textBack);
1166 }
1167 }
1168
1169 if (phase & drawIndicatorsFore) {
1171 surface->PenColour(textFore);
1172 PRectangle rcBox = rcSegment;
1173 rcBox.left = Sci::round(rcSegment.left);
1174 rcBox.right = Sci::round(rcSegment.right);
1175 const IntegerRectangle ircBox(rcBox);
1176 surface->MoveTo(ircBox.left, ircBox.top);
1177 surface->LineTo(ircBox.left, ircBox.bottom);
1178 surface->MoveTo(ircBox.right, ircBox.top);
1179 surface->LineTo(ircBox.right, ircBox.bottom);
1180 surface->MoveTo(ircBox.left, ircBox.top);
1181 surface->LineTo(ircBox.right, ircBox.top);
1182 surface->MoveTo(ircBox.left, ircBox.bottom - 1);
1183 surface->LineTo(ircBox.right, ircBox.bottom - 1);
1184 }
1185 }
1186
1187 if (phase & drawSelectionTranslucent) {
1188 if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && alpha != SC_ALPHA_NOALPHA) {
1189 SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha);
1190 }
1191 }
1192}
1193
1194void EditView::DrawEOLAnnotationText(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, int xStart, PRectangle rcLine, int subLine, XYACCUMULATOR subLineStart, DrawPhase phase) {
1195
1196 const bool lastSubLine = subLine == (ll->lines - 1);
1197 if (!lastSubLine)
1198 return;
1199
1201 return;
1202 }
1203 const StyledText stEOLAnnotation = model.pdoc->EOLAnnotationStyledText(line);
1204 if (!stEOLAnnotation.text || !ValidStyledText(vsDraw, vsDraw.eolAnnotationStyleOffset, stEOLAnnotation)) {
1205 return;
1206 }
1207 const size_t style = stEOLAnnotation.style + vsDraw.eolAnnotationStyleOffset;
1208
1209 PRectangle rcSegment = rcLine;
1210 FontAlias fontText = vsDraw.styles[style].font;
1211 const int widthEOLAnnotationText = static_cast<int>(surface->WidthText(fontText, stEOLAnnotation.text, stEOLAnnotation.length));
1212
1213 const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth;
1214 const XYPOSITION virtualSpace = model.sel.VirtualSpaceFor(
1215 model.pdoc->LineEnd(line)) * spaceWidth;
1216 rcSegment.left = xStart +
1217 static_cast<XYPOSITION>(ll->positions[ll->numCharsInLine] - subLineStart)
1218 + virtualSpace + vsDraw.aveCharWidth;
1219
1220 const char *textFoldDisplay = model.GetFoldDisplayText(line);
1221 if (textFoldDisplay) {
1222 rcSegment.left += (static_cast<int>(surface->WidthText(fontText, textFoldDisplay, static_cast<int>(strlen(textFoldDisplay)))) + vsDraw.aveCharWidth);
1223 }
1224 rcSegment.right = rcSegment.left + static_cast<XYPOSITION>(widthEOLAnnotationText);
1225
1226 const ColourOptional background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret);
1227 ColourDesired textFore = vsDraw.styles[style].fore;
1228 const ColourDesired textBack = TextBackground(model, vsDraw, ll, background, false,
1229 false, static_cast<int>(style), -1);
1230
1231 if (model.trackLineWidth) {
1232 if (rcSegment.right + 1> lineWidthMaxSeen) {
1233 // EOL Annotation text border drawn on rcSegment.right with width 1 is the last visible object of the line
1234 lineWidthMaxSeen = static_cast<int>(rcSegment.right + 1);
1235 }
1236 }
1237
1238 if (phase & drawBack) {
1239 surface->FillRectangle(rcSegment, textBack);
1240
1241 // Fill Remainder of the line
1242 PRectangle rcRemainder = rcSegment;
1243 rcRemainder.left = rcRemainder.right;
1244 if (rcRemainder.left < rcLine.left)
1245 rcRemainder.left = rcLine.left;
1246 rcRemainder.right = rcLine.right;
1247 FillLineRemainder(surface, model, vsDraw, ll, line, rcRemainder, subLine);
1248 }
1249
1250 if (phase & drawText) {
1251 if (phasesDraw != phasesOne) {
1252 surface->DrawTextTransparent(rcSegment, fontText,
1253 rcSegment.top + vsDraw.maxAscent, stEOLAnnotation.text, stEOLAnnotation.length,
1254 textFore);
1255 } else {
1256 surface->DrawTextNoClip(rcSegment, fontText,
1257 rcSegment.top + vsDraw.maxAscent, stEOLAnnotation.text, stEOLAnnotation.length,
1258 textFore, textBack);
1259 }
1260 }
1261
1262 if (phase & drawIndicatorsFore) {
1264 surface->PenColour(textFore);
1265 PRectangle rcBox = rcSegment;
1266 rcBox.left = Sci::round(rcSegment.left);
1267 rcBox.right = Sci::round(rcSegment.right);
1268 const IntegerRectangle ircBox(rcBox);
1269 surface->MoveTo(ircBox.left, ircBox.top);
1270 surface->LineTo(ircBox.left, ircBox.bottom);
1271 surface->MoveTo(ircBox.right, ircBox.top);
1272 surface->LineTo(ircBox.right, ircBox.bottom);
1273 surface->MoveTo(ircBox.left, ircBox.top);
1274 surface->LineTo(ircBox.right, ircBox.top);
1275 surface->MoveTo(ircBox.left, ircBox.bottom - 1);
1276 surface->LineTo(ircBox.right, ircBox.bottom - 1);
1277 }
1278 }
1279}
1280
1281static constexpr bool AnnotationBoxedOrIndented(int annotationVisible) noexcept {
1282 return annotationVisible == ANNOTATION_BOXED || annotationVisible == ANNOTATION_INDENTED;
1283}
1284
1285void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
1286 Sci::Line line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) {
1287 const int indent = static_cast<int>(model.pdoc->GetLineIndentation(line) * vsDraw.spaceWidth);
1288 PRectangle rcSegment = rcLine;
1289 const int annotationLine = subLine - ll->lines;
1290 const StyledText stAnnotation = model.pdoc->AnnotationStyledText(line);
1291 if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) {
1292 if (phase & drawBack) {
1293 surface->FillRectangle(rcSegment, vsDraw.styles[0].back);
1294 }
1295 rcSegment.left = static_cast<XYPOSITION>(xStart);
1297 // Only care about calculating width if tracking or need to draw indented box
1298 int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation);
1300 widthAnnotation += static_cast<int>(vsDraw.spaceWidth * 2); // Margins
1301 rcSegment.left = static_cast<XYPOSITION>(xStart + indent);
1302 rcSegment.right = rcSegment.left + widthAnnotation;
1303 }
1304 if (widthAnnotation > lineWidthMaxSeen)
1305 lineWidthMaxSeen = widthAnnotation;
1306 }
1307 const int annotationLines = model.pdoc->AnnotationLines(line);
1308 size_t start = 0;
1309 size_t lengthAnnotation = stAnnotation.LineLength(start);
1310 int lineInAnnotation = 0;
1311 while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) {
1312 start += lengthAnnotation + 1;
1313 lengthAnnotation = stAnnotation.LineLength(start);
1314 lineInAnnotation++;
1315 }
1316 PRectangle rcText = rcSegment;
1317 if ((phase & drawBack) && AnnotationBoxedOrIndented(vsDraw.annotationVisible)) {
1318 surface->FillRectangle(rcText,
1319 vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back);
1320 rcText.left += vsDraw.spaceWidth;
1321 }
1322 DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText,
1323 stAnnotation, start, lengthAnnotation, phase);
1324 if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) {
1325 surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore);
1326 const IntegerRectangle ircSegment(rcSegment);
1327 surface->MoveTo(ircSegment.left, ircSegment.top);
1328 surface->LineTo(ircSegment.left, ircSegment.bottom);
1329 surface->MoveTo(ircSegment.right, ircSegment.top);
1330 surface->LineTo(ircSegment.right, ircSegment.bottom);
1331 if (subLine == ll->lines) {
1332 surface->MoveTo(ircSegment.left, ircSegment.top);
1333 surface->LineTo(ircSegment.right, ircSegment.top);
1334 }
1335 if (subLine == ll->lines + annotationLines - 1) {
1336 surface->MoveTo(ircSegment.left, ircSegment.bottom - 1);
1337 surface->LineTo(ircSegment.right, ircSegment.bottom - 1);
1338 }
1339 }
1340 }
1341}
1342
1343static void DrawBlockCaret(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
1344 int subLine, int xStart, Sci::Position offset, Sci::Position posCaret, PRectangle rcCaret, ColourDesired caretColour) {
1345
1346 const Sci::Position lineStart = ll->LineStart(subLine);
1347 Sci::Position posBefore = posCaret;
1348 Sci::Position posAfter = model.pdoc->MovePositionOutsideChar(posCaret + 1, 1);
1349 Sci::Position numCharsToDraw = posAfter - posCaret;
1350
1351 // Work out where the starting and ending offsets are. We need to
1352 // see if the previous character shares horizontal space, such as a
1353 // glyph / combining character. If so we'll need to draw that too.
1354 Sci::Position offsetFirstChar = offset;
1355 Sci::Position offsetLastChar = offset + (posAfter - posCaret);
1356 while ((posBefore > 0) && ((offsetLastChar - numCharsToDraw) >= lineStart)) {
1357 if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) {
1358 // The char does not share horizontal space
1359 break;
1360 }
1361 // Char shares horizontal space, update the numChars to draw
1362 // Update posBefore to point to the prev char
1363 posBefore = model.pdoc->MovePositionOutsideChar(posBefore - 1, -1);
1364 numCharsToDraw = posAfter - posBefore;
1365 offsetFirstChar = offset - (posCaret - posBefore);
1366 }
1367
1368 // See if the next character shares horizontal space, if so we'll
1369 // need to draw that too.
1370 if (offsetFirstChar < 0)
1371 offsetFirstChar = 0;
1372 numCharsToDraw = offsetLastChar - offsetFirstChar;
1373 while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) {
1374 // Update posAfter to point to the 2nd next char, this is where
1375 // the next character ends, and 2nd next begins. We'll need
1376 // to compare these two
1377 posBefore = posAfter;
1378 posAfter = model.pdoc->MovePositionOutsideChar(posAfter + 1, 1);
1379 offsetLastChar = offset + (posAfter - posCaret);
1380 if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) {
1381 // The char does not share horizontal space
1382 break;
1383 }
1384 // Char shares horizontal space, update the numChars to draw
1385 numCharsToDraw = offsetLastChar - offsetFirstChar;
1386 }
1387
1388 // We now know what to draw, update the caret drawing rectangle
1389 rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart;
1390 rcCaret.right = ll->positions[offsetFirstChar + numCharsToDraw] - ll->positions[lineStart] + xStart;
1391
1392 // Adjust caret position to take into account any word wrapping symbols.
1393 if ((ll->wrapIndent != 0) && (lineStart != 0)) {
1394 const XYPOSITION wordWrapCharWidth = ll->wrapIndent;
1395 rcCaret.left += wordWrapCharWidth;
1396 rcCaret.right += wordWrapCharWidth;
1397 }
1398
1399 // This character is where the caret block is, we override the colours
1400 // (inversed) for drawing the caret here.
1401 const int styleMain = ll->styles[offsetFirstChar];
1402 FontAlias fontText = vsDraw.styles[styleMain].font;
1403 surface->DrawTextClipped(rcCaret, fontText,
1404 rcCaret.top + vsDraw.maxAscent, &ll->chars[offsetFirstChar],
1405 static_cast<int>(numCharsToDraw), vsDraw.styles[styleMain].back,
1406 caretColour);
1407}
1408
1409void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
1410 Sci::Line lineDoc, int xStart, PRectangle rcLine, int subLine) const {
1411 // When drag is active it is the only caret drawn
1412 const bool drawDrag = model.posDrag.IsValid();
1413 if (hideSelection && !drawDrag)
1414 return;
1415 const Sci::Position posLineStart = model.pdoc->LineStart(lineDoc);
1416 // For each selection draw
1417 for (size_t r = 0; (r<model.sel.Count()) || drawDrag; r++) {
1418 const bool mainCaret = r == model.sel.Main();
1419 SelectionPosition posCaret = (drawDrag ? model.posDrag : model.sel.Range(r).caret);
1421 !drawDrag &&
1422 posCaret > model.sel.Range(r).anchor) {
1423 if (posCaret.VirtualSpace() > 0)
1424 posCaret.SetVirtualSpace(posCaret.VirtualSpace() - 1);
1425 else
1426 posCaret.SetPosition(model.pdoc->MovePositionOutsideChar(posCaret.Position()-1, -1));
1427 }
1428 const int offset = static_cast<int>(posCaret.Position() - posLineStart);
1429 const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth;
1430 const XYPOSITION virtualOffset = posCaret.VirtualSpace() * spaceWidth;
1431 if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) {
1432 XYPOSITION xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)];
1433 if (ll->wrapIndent != 0) {
1434 const Sci::Position lineStart = ll->LineStart(subLine);
1435 if (lineStart != 0) // Wrapped
1436 xposCaret += ll->wrapIndent;
1437 }
1438 const bool caretBlinkState = (model.caret.active && model.caret.on) || (!additionalCaretsBlink && !mainCaret);
1439 const bool caretVisibleState = additionalCaretsVisible || mainCaret;
1440 if ((xposCaret >= 0) && vsDraw.IsCaretVisible() &&
1441 (drawDrag || (caretBlinkState && caretVisibleState))) {
1442 bool canDrawBlockCaret = true;
1443 bool drawBlockCaret = false;
1444 XYPOSITION widthOverstrikeCaret;
1445 XYPOSITION caretWidthOffset = 0;
1446 PRectangle rcCaret = rcLine;
1447
1448 if (posCaret.Position() == model.pdoc->Length()) { // At end of document
1449 canDrawBlockCaret = false;
1450 widthOverstrikeCaret = vsDraw.aveCharWidth;
1451 } else if ((posCaret.Position() - posLineStart) >= ll->numCharsInLine) { // At end of line
1452 canDrawBlockCaret = false;
1453 widthOverstrikeCaret = vsDraw.aveCharWidth;
1454 } else {
1455 const int widthChar = model.pdoc->LenChar(posCaret.Position());
1456 widthOverstrikeCaret = ll->positions[offset + widthChar] - ll->positions[offset];
1457 }
1458 if (widthOverstrikeCaret < 3) // Make sure its visible
1459 widthOverstrikeCaret = 3;
1460
1461 if (xposCaret > 0)
1462 caretWidthOffset = 0.51f; // Move back so overlaps both character cells.
1463 xposCaret += xStart;
1464 const ViewStyle::CaretShape caretShape = drawDrag ? ViewStyle::CaretShape::line : vsDraw.CaretShapeForMode(model.inOverstrike);
1465 if (drawDrag) {
1466 /* Dragging text, use a line caret */
1467 rcCaret.left = Sci::round(xposCaret - caretWidthOffset);
1468 rcCaret.right = rcCaret.left + vsDraw.caretWidth;
1469 } else if ((caretShape == ViewStyle::CaretShape::bar) && drawOverstrikeCaret) {
1470 /* Overstrike (insert mode), use a modified bar caret */
1471 rcCaret.top = rcCaret.bottom - 2;
1472 rcCaret.left = xposCaret + 1;
1473 rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
1474 } else if ((caretShape == ViewStyle::CaretShape::block) || imeCaretBlockOverride) {
1475 /* Block caret */
1476 rcCaret.left = xposCaret;
1477 if (canDrawBlockCaret && !(IsControlCharacter(ll->chars[offset]))) {
1478 drawBlockCaret = true;
1479 rcCaret.right = xposCaret + widthOverstrikeCaret;
1480 } else {
1481 rcCaret.right = xposCaret + vsDraw.aveCharWidth;
1482 }
1483 } else {
1484 /* Line caret */
1485 rcCaret.left = Sci::round(xposCaret - caretWidthOffset);
1486 rcCaret.right = rcCaret.left + vsDraw.caretWidth;
1487 }
1488 const ColourDesired caretColour = mainCaret ? vsDraw.caretcolour : vsDraw.additionalCaretColour;
1489 if (drawBlockCaret) {
1490 DrawBlockCaret(surface, model, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour);
1491 } else {
1492 surface->FillRectangle(rcCaret, caretColour);
1493 }
1494 }
1495 }
1496 if (drawDrag)
1497 break;
1498 }
1499}
1500
1501static void DrawWrapIndentAndMarker(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll,
1502 int xStart, PRectangle rcLine, ColourOptional background, DrawWrapMarkerFn customDrawWrapMarker,
1503 bool caretActive) {
1504 // default bgnd here..
1505 surface->FillRectangle(rcLine, background.isSet ? background :
1506 vsDraw.styles[STYLE_DEFAULT].back);
1507
1508 if (vsDraw.IsLineFrameOpaque(caretActive, ll->containsCaret)) {
1509 const int width = vsDraw.GetFrameWidth();
1510 // Draw left of frame under marker
1511 DrawFrame(surface, vsDraw.caretLineBackground, vsDraw.caretLineAlpha,
1512 PRectangle(rcLine.left, rcLine.top, rcLine.left + width, rcLine.bottom));
1513 }
1514
1516
1517 // draw continuation rect
1518 PRectangle rcPlace = rcLine;
1519
1520 rcPlace.left = static_cast<XYPOSITION>(xStart);
1521 rcPlace.right = rcPlace.left + ll->wrapIndent;
1522
1524 rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
1525 else
1526 rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
1527
1528 if (!customDrawWrapMarker) {
1529 DrawWrapMarker(surface, rcPlace, false, vsDraw.WrapColour());
1530 } else {
1531 customDrawWrapMarker(surface, rcPlace, false, vsDraw.WrapColour());
1532 }
1533 }
1534}
1535
1536void EditView::DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
1537 PRectangle rcLine, Range lineRange, Sci::Position posLineStart, int xStart,
1538 int subLine, ColourOptional background) const {
1539
1540 const bool selBackDrawn = vsDraw.SelectionBackgroundDrawn();
1541 bool inIndentation = subLine == 0; // Do not handle indentation except on first subline.
1542 const XYACCUMULATOR subLineStart = ll->positions[lineRange.start];
1543 // Does not take margin into account but not significant
1544 const int xStartVisible = static_cast<int>(subLineStart)-xStart;
1545
1546 BreakFinder bfBack(ll, &model.sel, lineRange, posLineStart, xStartVisible, selBackDrawn, model.pdoc, &model.reprs, nullptr);
1547
1548 const bool drawWhitespaceBackground = vsDraw.WhitespaceBackgroundDrawn() && !background.isSet;
1549
1550 // Background drawing loop
1551 while (bfBack.More()) {
1552
1553 const TextSegment ts = bfBack.Next();
1554 const Sci::Position i = ts.end() - 1;
1555 const Sci::Position iDoc = i + posLineStart;
1556
1557 PRectangle rcSegment = rcLine;
1558 rcSegment.left = ll->positions[ts.start] + xStart - static_cast<XYPOSITION>(subLineStart);
1559 rcSegment.right = ll->positions[ts.end()] + xStart - static_cast<XYPOSITION>(subLineStart);
1560 // Only try to draw if really visible - enhances performance by not calling environment to
1561 // draw strings that are completely past the right side of the window.
1562 if (!rcSegment.Empty() && rcSegment.Intersects(rcLine)) {
1563 // Clip to line rectangle, since may have a huge position which will not work with some platforms
1564 if (rcSegment.left < rcLine.left)
1565 rcSegment.left = rcLine.left;
1566 if (rcSegment.right > rcLine.right)
1567 rcSegment.right = rcLine.right;
1568
1569 const int inSelection = hideSelection ? 0 : model.sel.CharacterInSelection(iDoc);
1570 const bool inHotspot = (ll->hotspot.Valid()) && ll->hotspot.ContainsCharacter(iDoc);
1571 ColourDesired textBack = TextBackground(model, vsDraw, ll, background, inSelection,
1572 inHotspot, ll->styles[i], i);
1573 if (ts.representation) {
1574 if (ll->chars[i] == '\t') {
1575 // Tab display
1576 if (drawWhitespaceBackground && vsDraw.WhiteSpaceVisible(inIndentation))
1577 textBack = vsDraw.whitespaceColours.back;
1578 } else {
1579 // Blob display
1580 inIndentation = false;
1581 }
1582 surface->FillRectangle(rcSegment, textBack);
1583 } else {
1584 // Normal text display
1585 surface->FillRectangle(rcSegment, textBack);
1586 if (vsDraw.viewWhitespace != wsInvisible) {
1587 for (int cpos = 0; cpos <= i - ts.start; cpos++) {
1588 if (ll->chars[cpos + ts.start] == ' ') {
1589 if (drawWhitespaceBackground && vsDraw.WhiteSpaceVisible(inIndentation)) {
1590 const PRectangle rcSpace(
1591 ll->positions[cpos + ts.start] + xStart - static_cast<XYPOSITION>(subLineStart),
1592 rcSegment.top,
1593 ll->positions[cpos + ts.start + 1] + xStart - static_cast<XYPOSITION>(subLineStart),
1594 rcSegment.bottom);
1595 surface->FillRectangle(rcSpace, vsDraw.whitespaceColours.back);
1596 }
1597 } else {
1598 inIndentation = false;
1599 }
1600 }
1601 }
1602 }
1603 } else if (rcSegment.left > rcLine.right) {
1604 break;
1605 }
1606 }
1607}
1608
1609static void DrawEdgeLine(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine,
1610 Range lineRange, int xStart) {
1611 if (vsDraw.edgeState == EDGE_LINE) {
1612 PRectangle rcSegment = rcLine;
1613 const int edgeX = static_cast<int>(vsDraw.theEdge.column * vsDraw.spaceWidth);
1614 rcSegment.left = static_cast<XYPOSITION>(edgeX + xStart);
1615 if ((ll->wrapIndent != 0) && (lineRange.start != 0))
1616 rcSegment.left -= ll->wrapIndent;
1617 rcSegment.right = rcSegment.left + 1;
1618 surface->FillRectangle(rcSegment, vsDraw.theEdge.colour);
1619 } else if (vsDraw.edgeState == EDGE_MULTILINE) {
1620 for (size_t edge = 0; edge < vsDraw.theMultiEdge.size(); edge++) {
1621 if (vsDraw.theMultiEdge[edge].column >= 0) {
1622 PRectangle rcSegment = rcLine;
1623 const int edgeX = static_cast<int>(vsDraw.theMultiEdge[edge].column * vsDraw.spaceWidth);
1624 rcSegment.left = static_cast<XYPOSITION>(edgeX + xStart);
1625 if ((ll->wrapIndent != 0) && (lineRange.start != 0))
1626 rcSegment.left -= ll->wrapIndent;
1627 rcSegment.right = rcSegment.left + 1;
1628 surface->FillRectangle(rcSegment, vsDraw.theMultiEdge[edge].colour);
1629 }
1630 }
1631 }
1632}
1633
1634// Draw underline mark as part of background if not transparent
1635static void DrawMarkUnderline(Surface *surface, const EditModel &model, const ViewStyle &vsDraw,
1636 Sci::Line line, PRectangle rcLine) {
1637 int marks = model.pdoc->GetMark(line);
1638 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
1639 if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) &&
1640 (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
1641 PRectangle rcUnderline = rcLine;
1642 rcUnderline.top = rcUnderline.bottom - 2;
1643 surface->FillRectangle(rcUnderline, vsDraw.markers[markBit].back);
1644 }
1645 marks >>= 1;
1646 }
1647}
1648
1649static void DrawTranslucentSelection(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
1650 Sci::Line line, PRectangle rcLine, int subLine, Range lineRange, int xStart) {
1651 if ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA)) {
1652 const Sci::Position posLineStart = model.pdoc->LineStart(line);
1653 const XYACCUMULATOR subLineStart = ll->positions[lineRange.start];
1654 // For each selection draw
1655 Sci::Position virtualSpaces = 0;
1656 if (subLine == (ll->lines - 1)) {
1657 virtualSpaces = model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line));
1658 }
1659 const SelectionPosition posStart(posLineStart + lineRange.start);
1660 const SelectionPosition posEnd(posLineStart + lineRange.end, virtualSpaces);
1661 const SelectionSegment virtualSpaceRange(posStart, posEnd);
1662 for (size_t r = 0; r < model.sel.Count(); r++) {
1663 const int alpha = (r == model.sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
1664 if (alpha != SC_ALPHA_NOALPHA) {
1665 const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange);
1666 if (!portion.Empty()) {
1667 const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth;
1668 PRectangle rcSegment = rcLine;
1669 rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] -
1670 static_cast<XYPOSITION>(subLineStart)+portion.start.VirtualSpace() * spaceWidth;
1671 rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] -
1672 static_cast<XYPOSITION>(subLineStart)+portion.end.VirtualSpace() * spaceWidth;
1673 if ((ll->wrapIndent != 0) && (lineRange.start != 0)) {
1674 if ((portion.start.Position() - posLineStart) == lineRange.start && model.sel.Range(r).ContainsCharacter(portion.start.Position() - 1))
1675 rcSegment.left -= static_cast<int>(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here
1676 }
1677 rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left;
1678 rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right;
1679 if (rcSegment.right > rcLine.left)
1680 SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection), alpha);
1681 }
1682 }
1683 }
1684 }
1685}
1686
1687// Draw any translucent whole line states
1688static void DrawTranslucentLineState(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
1689 Sci::Line line, PRectangle rcLine, int subLine) {
1690 if ((model.caret.active || vsDraw.alwaysShowCaretLineBackground) && vsDraw.showCaretLineBackground && ll->containsCaret &&
1691 vsDraw.caretLineAlpha != SC_ALPHA_NOALPHA) {
1692 if (vsDraw.caretLineFrame) {
1693 DrawCaretLineFramed(surface, vsDraw, ll, rcLine, subLine);
1694 } else {
1695 SimpleAlphaRectangle(surface, rcLine, vsDraw.caretLineBackground, vsDraw.caretLineAlpha);
1696 }
1697 }
1698 const int marksOfLine = model.pdoc->GetMark(line);
1699 int marksDrawnInText = marksOfLine & vsDraw.maskDrawInText;
1700 for (int markBit = 0; (markBit < 32) && marksDrawnInText; markBit++) {
1701 if (marksDrawnInText & 1) {
1702 if (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) {
1703 SimpleAlphaRectangle(surface, rcLine, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha);
1704 } else if (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) {
1705 PRectangle rcUnderline = rcLine;
1706 rcUnderline.top = rcUnderline.bottom - 2;
1707 SimpleAlphaRectangle(surface, rcUnderline, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha);
1708 }
1709 }
1710 marksDrawnInText >>= 1;
1711 }
1712 int marksDrawnInLine = marksOfLine & vsDraw.maskInLine;
1713 for (int markBit = 0; (markBit < 32) && marksDrawnInLine; markBit++) {
1714 if (marksDrawnInLine & 1) {
1715 SimpleAlphaRectangle(surface, rcLine, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha);
1716 }
1717 marksDrawnInLine >>= 1;
1718 }
1719}
1720
1721void EditView::DrawForeground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
1722 Sci::Line lineVisible, PRectangle rcLine, Range lineRange, Sci::Position posLineStart, int xStart,
1723 int subLine, ColourOptional background) {
1724
1725 const bool selBackDrawn = vsDraw.SelectionBackgroundDrawn();
1726 const bool drawWhitespaceBackground = vsDraw.WhitespaceBackgroundDrawn() && !background.isSet;
1727 bool inIndentation = subLine == 0; // Do not handle indentation except on first subline.
1728
1729 const XYACCUMULATOR subLineStart = ll->positions[lineRange.start];
1730 const XYPOSITION indentWidth = model.pdoc->IndentSize() * vsDraw.spaceWidth;
1731
1732 // Does not take margin into account but not significant
1733 const int xStartVisible = static_cast<int>(subLineStart)-xStart;
1734
1735 // Foreground drawing loop
1736 BreakFinder bfFore(ll, &model.sel, lineRange, posLineStart, xStartVisible,
1737 (((phasesDraw == phasesOne) && selBackDrawn) || vsDraw.selColours.fore.isSet), model.pdoc, &model.reprs, &vsDraw);
1738
1739 while (bfFore.More()) {
1740
1741 const TextSegment ts = bfFore.Next();
1742 const Sci::Position i = ts.end() - 1;
1743 const Sci::Position iDoc = i + posLineStart;
1744
1745 PRectangle rcSegment = rcLine;
1746 rcSegment.left = ll->positions[ts.start] + xStart - static_cast<XYPOSITION>(subLineStart);
1747 rcSegment.right = ll->positions[ts.end()] + xStart - static_cast<XYPOSITION>(subLineStart);
1748 // Only try to draw if really visible - enhances performance by not calling environment to
1749 // draw strings that are completely past the right side of the window.
1750 if (rcSegment.Intersects(rcLine)) {
1751 const int styleMain = ll->styles[i];
1752 ColourDesired textFore = vsDraw.styles[styleMain].fore;
1753 FontAlias textFont = vsDraw.styles[styleMain].font;
1754 //hotspot foreground
1755 const bool inHotspot = (ll->hotspot.Valid()) && ll->hotspot.ContainsCharacter(iDoc);
1756 if (inHotspot) {
1757 if (vsDraw.hotspotColours.fore.isSet)
1758 textFore = vsDraw.hotspotColours.fore;
1759 }
1760 if (vsDraw.indicatorsSetFore) {
1761 // At least one indicator sets the text colour so see if it applies to this segment
1762 for (const IDecoration *deco : model.pdoc->decorations->View()) {
1763 const int indicatorValue = deco->ValueAt(ts.start + posLineStart);
1764 if (indicatorValue) {
1765 const Indicator &indicator = vsDraw.indicators[deco->Indicator()];
1766 bool hover = false;
1767 if (indicator.IsDynamic()) {
1768 const Sci::Position startPos = ts.start + posLineStart;
1769 const Range rangeRun(deco->StartRun(startPos), deco->EndRun(startPos));
1770 hover = rangeRun.ContainsCharacter(model.hoverIndicatorPos);
1771 }
1772 if (hover) {
1773 if (indicator.sacHover.style == INDIC_TEXTFORE) {
1774 textFore = indicator.sacHover.fore;
1775 }
1776 } else {
1777 if (indicator.sacNormal.style == INDIC_TEXTFORE) {
1778 if (indicator.Flags() & SC_INDICFLAG_VALUEFORE)
1779 textFore = ColourDesired(indicatorValue & SC_INDICVALUEMASK);
1780 else
1781 textFore = indicator.sacNormal.fore;
1782 }
1783 }
1784 }
1785 }
1786 }
1787 const int inSelection = hideSelection ? 0 : model.sel.CharacterInSelection(iDoc);
1788 if (inSelection && (vsDraw.selColours.fore.isSet)) {
1789 textFore = (inSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground;
1790 }
1791 ColourDesired textBack = TextBackground(model, vsDraw, ll, background, inSelection, inHotspot, styleMain, i);
1792 if (ts.representation) {
1793 if (ll->chars[i] == '\t') {
1794 // Tab display
1795 if (phasesDraw == phasesOne) {
1796 if (drawWhitespaceBackground && vsDraw.WhiteSpaceVisible(inIndentation))
1797 textBack = vsDraw.whitespaceColours.back;
1798 surface->FillRectangle(rcSegment, textBack);
1799 }
1800 if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
1801 for (int indentCount = static_cast<int>((ll->positions[i] + epsilon) / indentWidth);
1802 indentCount <= (ll->positions[i + 1] - epsilon) / indentWidth;
1803 indentCount++) {
1804 if (indentCount > 0) {
1805 const XYPOSITION xIndent = std::floor(indentCount * indentWidth);
1806 DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment,
1807 (ll->xHighlightGuide == xIndent));
1808 }
1809 }
1810 }
1811 if (vsDraw.viewWhitespace != wsInvisible) {
1812 if (vsDraw.WhiteSpaceVisible(inIndentation)) {
1813 if (vsDraw.whitespaceColours.fore.isSet)
1814 textFore = vsDraw.whitespaceColours.fore;
1815 surface->PenColour(textFore);
1816 const PRectangle rcTab(rcSegment.left + 1, rcSegment.top + tabArrowHeight,
1817 rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
1818 const int segmentTop = static_cast<int>(rcSegment.top + vsDraw.lineHeight / 2);
1819 if (!customDrawTabArrow)
1820 DrawTabArrow(surface, rcTab, segmentTop, vsDraw);
1821 else
1822 customDrawTabArrow(surface, rcTab, segmentTop);
1823 }
1824 }
1825 } else {
1826 inIndentation = false;
1827 if (vsDraw.controlCharSymbol >= 32) {
1828 // Using one font for all control characters so it can be controlled independently to ensure
1829 // the box goes around the characters tightly. Seems to be no way to work out what height
1830 // is taken by an individual character - internal leading gives varying results.
1831 FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
1832 const char cc[2] = { static_cast<char>(vsDraw.controlCharSymbol), '\0' };
1833 surface->DrawTextNoClip(rcSegment, ctrlCharsFont,
1834 rcSegment.top + vsDraw.maxAscent,
1835 cc, 1, textBack, textFore);
1836 } else {
1837 DrawTextBlob(surface, vsDraw, rcSegment, ts.representation->stringRep.c_str(),
1838 textBack, textFore, phasesDraw == phasesOne);
1839 }
1840 }
1841 } else {
1842 // Normal text display
1843 if (vsDraw.styles[styleMain].visible) {
1844 if (phasesDraw != phasesOne) {
1845 surface->DrawTextTransparent(rcSegment, textFont,
1846 rcSegment.top + vsDraw.maxAscent, &ll->chars[ts.start],
1847 static_cast<int>(i - ts.start + 1), textFore);
1848 } else {
1849 surface->DrawTextNoClip(rcSegment, textFont,
1850 rcSegment.top + vsDraw.maxAscent, &ll->chars[ts.start],
1851 static_cast<int>(i - ts.start + 1), textFore, textBack);
1852 }
1853 }
1854 if (vsDraw.viewWhitespace != wsInvisible ||
1855 (inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
1856 for (int cpos = 0; cpos <= i - ts.start; cpos++) {
1857 if (ll->chars[cpos + ts.start] == ' ') {
1858 if (vsDraw.viewWhitespace != wsInvisible) {
1859 if (vsDraw.whitespaceColours.fore.isSet)
1860 textFore = vsDraw.whitespaceColours.fore;
1861 if (vsDraw.WhiteSpaceVisible(inIndentation)) {
1862 const XYPOSITION xmid = (ll->positions[cpos + ts.start] + ll->positions[cpos + ts.start + 1]) / 2;
1863 if ((phasesDraw == phasesOne) && drawWhitespaceBackground) {
1864 textBack = vsDraw.whitespaceColours.back;
1865 const PRectangle rcSpace(
1866 ll->positions[cpos + ts.start] + xStart - static_cast<XYPOSITION>(subLineStart),
1867 rcSegment.top,
1868 ll->positions[cpos + ts.start + 1] + xStart - static_cast<XYPOSITION>(subLineStart),
1869 rcSegment.bottom);
1870 surface->FillRectangle(rcSpace, textBack);
1871 }
1872 const int halfDotWidth = vsDraw.whitespaceSize / 2;
1873 PRectangle rcDot(xmid + xStart - halfDotWidth - static_cast<XYPOSITION>(subLineStart),
1874 rcSegment.top + vsDraw.lineHeight / 2, 0.0f, 0.0f);
1875 rcDot.right = rcDot.left + vsDraw.whitespaceSize;
1876 rcDot.bottom = rcDot.top + vsDraw.whitespaceSize;
1877 surface->FillRectangle(rcDot, textFore);
1878 }
1879 }
1880 if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
1881 for (int indentCount = static_cast<int>((ll->positions[cpos + ts.start] + epsilon) / indentWidth);
1882 indentCount <= (ll->positions[cpos + ts.start + 1] - epsilon) / indentWidth;
1883 indentCount++) {
1884 if (indentCount > 0) {
1885 const XYPOSITION xIndent = std::floor(indentCount * indentWidth);
1886 DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment,
1887 (ll->xHighlightGuide == xIndent));
1888 }
1889 }
1890 }
1891 } else {
1892 inIndentation = false;
1893 }
1894 }
1895 }
1896 }
1897 if (ll->hotspot.Valid() && vsDraw.hotspotUnderline && ll->hotspot.ContainsCharacter(iDoc)) {
1898 PRectangle rcUL = rcSegment;
1899 rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
1900 rcUL.bottom = rcUL.top + 1;
1901 if (vsDraw.hotspotColours.fore.isSet)
1902 surface->FillRectangle(rcUL, vsDraw.hotspotColours.fore);
1903 else
1904 surface->FillRectangle(rcUL, textFore);
1905 } else if (vsDraw.styles[styleMain].underline) {
1906 PRectangle rcUL = rcSegment;
1907 rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
1908 rcUL.bottom = rcUL.top + 1;
1909 surface->FillRectangle(rcUL, textFore);
1910 }
1911 } else if (rcSegment.left > rcLine.right) {
1912 break;
1913 }
1914 }
1915}
1916
1917void EditView::DrawIndentGuidesOverEmpty(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
1918 Sci::Line line, Sci::Line lineVisible, PRectangle rcLine, int xStart, int subLine) {
1920 && (subLine == 0)) {
1921 const Sci::Position posLineStart = model.pdoc->LineStart(line);
1922 int indentSpace = model.pdoc->GetLineIndentation(line);
1923 int xStartText = static_cast<int>(ll->positions[model.pdoc->GetLineIndentPosition(line) - posLineStart]);
1924
1925 // Find the most recent line with some text
1926
1927 Sci::Line lineLastWithText = line;
1928 while (lineLastWithText > std::max(line - 20, static_cast<Sci::Line>(0)) && model.pdoc->IsWhiteLine(lineLastWithText)) {
1929 lineLastWithText--;
1930 }
1931 if (lineLastWithText < line) {
1932 xStartText = 100000; // Don't limit to visible indentation on empty line
1933 // This line is empty, so use indentation of last line with text
1934 int indentLastWithText = model.pdoc->GetLineIndentation(lineLastWithText);
1935 const int isFoldHeader = model.pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG;
1936 if (isFoldHeader) {
1937 // Level is one more level than parent
1938 indentLastWithText += model.pdoc->IndentSize();
1939 }
1940 if (vsDraw.viewIndentationGuides == ivLookForward) {
1941 // In viLookForward mode, previous line only used if it is a fold header
1942 if (isFoldHeader) {
1943 indentSpace = std::max(indentSpace, indentLastWithText);
1944 }
1945 } else { // viLookBoth
1946 indentSpace = std::max(indentSpace, indentLastWithText);
1947 }
1948 }
1949
1950 Sci::Line lineNextWithText = line;
1951 while (lineNextWithText < std::min(line + 20, model.pdoc->LinesTotal()) && model.pdoc->IsWhiteLine(lineNextWithText)) {
1952 lineNextWithText++;
1953 }
1954 if (lineNextWithText > line) {
1955 xStartText = 100000; // Don't limit to visible indentation on empty line
1956 // This line is empty, so use indentation of first next line with text
1957 indentSpace = std::max(indentSpace,
1958 model.pdoc->GetLineIndentation(lineNextWithText));
1959 }
1960
1961 for (int indentPos = model.pdoc->IndentSize(); indentPos < indentSpace; indentPos += model.pdoc->IndentSize()) {
1962 const XYPOSITION xIndent = std::floor(indentPos * vsDraw.spaceWidth);
1963 if (xIndent < xStartText) {
1964 DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcLine,
1965 (ll->xHighlightGuide == xIndent));
1966 }
1967 }
1968 }
1969}
1970
1971void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
1972 Sci::Line line, Sci::Line lineVisible, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) {
1973
1974 if (subLine >= ll->lines) {
1975 DrawAnnotation(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, phase);
1976 return; // No further drawing
1977 }
1978
1979 // See if something overrides the line background colour.
1980 const ColourOptional background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret);
1981
1982 const Sci::Position posLineStart = model.pdoc->LineStart(line);
1983
1984 const Range lineRange = ll->SubLineRange(subLine, LineLayout::Scope::visibleOnly);
1985 const Range lineRangeIncludingEnd = ll->SubLineRange(subLine, LineLayout::Scope::includeEnd);
1986 const XYACCUMULATOR subLineStart = ll->positions[lineRange.start];
1987
1988 if ((ll->wrapIndent != 0) && (subLine > 0)) {
1989 if (phase & drawBack) {
1990 DrawWrapIndentAndMarker(surface, vsDraw, ll, xStart, rcLine, background, customDrawWrapMarker, model.caret.active);
1991 }
1992 xStart += static_cast<int>(ll->wrapIndent);
1993 }
1994
1995 if (phasesDraw != phasesOne) {
1996 if (phase & drawBack) {
1997 DrawBackground(surface, model, vsDraw, ll, rcLine, lineRange, posLineStart, xStart,
1998 subLine, background);
1999 DrawFoldDisplayText(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, subLineStart, drawBack);
2000 DrawEOLAnnotationText(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, subLineStart, drawBack);
2001 phase = static_cast<DrawPhase>(phase & ~drawBack); // Remove drawBack to not draw again in DrawFoldDisplayText
2002 DrawEOL(surface, model, vsDraw, ll, rcLine, line, lineRange.end,
2003 xStart, subLine, subLineStart, background);
2004 if (vsDraw.IsLineFrameOpaque(model.caret.active, ll->containsCaret))
2005 DrawCaretLineFramed(surface, vsDraw, ll, rcLine, subLine);
2006 }
2007
2008 if (phase & drawIndicatorsBack) {
2009 DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRangeIncludingEnd.end, true, model.hoverIndicatorPos);
2010 DrawEdgeLine(surface, vsDraw, ll, rcLine, lineRange, xStart);
2011 DrawMarkUnderline(surface, model, vsDraw, line, rcLine);
2012 }
2013 }
2014
2015 if (phase & drawText) {
2016 DrawForeground(surface, model, vsDraw, ll, lineVisible, rcLine, lineRange, posLineStart, xStart,
2017 subLine, background);
2018 }
2019
2020 if (phase & drawIndentationGuides) {
2021 DrawIndentGuidesOverEmpty(surface, model, vsDraw, ll, line, lineVisible, rcLine, xStart, subLine);
2022 }
2023
2024 if (phase & drawIndicatorsFore) {
2025 DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRangeIncludingEnd.end, false, model.hoverIndicatorPos);
2026 }
2027
2028 DrawFoldDisplayText(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, subLineStart, phase);
2029 DrawEOLAnnotationText(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, subLineStart, phase);
2030
2031 if (phasesDraw == phasesOne) {
2032 DrawEOL(surface, model, vsDraw, ll, rcLine, line, lineRange.end,
2033 xStart, subLine, subLineStart, background);
2034 if (vsDraw.IsLineFrameOpaque(model.caret.active, ll->containsCaret))
2035 DrawCaretLineFramed(surface, vsDraw, ll, rcLine, subLine);
2036 DrawEdgeLine(surface, vsDraw, ll, rcLine, lineRange, xStart);
2037 DrawMarkUnderline(surface, model, vsDraw, line, rcLine);
2038 }
2039
2040 if (!hideSelection && (phase & drawSelectionTranslucent)) {
2041 DrawTranslucentSelection(surface, model, vsDraw, ll, line, rcLine, subLine, lineRange, xStart);
2042 }
2043
2044 if (phase & drawLineTranslucent) {
2045 DrawTranslucentLineState(surface, model, vsDraw, ll, line, rcLine, subLine);
2046 }
2047}
2048
2049static void DrawFoldLines(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, Sci::Line line, PRectangle rcLine) {
2050 const bool expanded = model.pcs->GetExpanded(line);
2051 const int level = model.pdoc->GetLevel(line);
2052 const int levelNext = model.pdoc->GetLevel(line + 1);
2053 if ((level & SC_FOLDLEVELHEADERFLAG) &&
2054 (LevelNumber(level) < LevelNumber(levelNext))) {
2055 // Paint the line above the fold
2056 if ((expanded && (model.foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED))
2057 ||
2058 (!expanded && (model.foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) {
2059 PRectangle rcFoldLine = rcLine;
2060 rcFoldLine.bottom = rcFoldLine.top + 1;
2061 surface->FillRectangle(rcFoldLine, vsDraw.styles[STYLE_DEFAULT].fore);
2062 }
2063 // Paint the line below the fold
2064 if ((expanded && (model.foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED))
2065 ||
2066 (!expanded && (model.foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) {
2067 PRectangle rcFoldLine = rcLine;
2068 rcFoldLine.top = rcFoldLine.bottom - 1;
2069 surface->FillRectangle(rcFoldLine, vsDraw.styles[STYLE_DEFAULT].fore);
2070 }
2071 }
2072}
2073
2074void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectangle rcArea,
2075 PRectangle rcClient, const ViewStyle &vsDraw) {
2076 // Allow text at start of line to overlap 1 pixel into the margin as this displays
2077 // serifs and italic stems for aliased text.
2078 const int leftTextOverlap = ((model.xOffset == 0) && (vsDraw.leftMarginWidth > 0)) ? 1 : 0;
2079
2080 // Do the painting
2081 if (rcArea.right > vsDraw.textStart - leftTextOverlap) {
2082
2083 Surface *surface = surfaceWindow;
2084 if (bufferedDraw) {
2085 surface = pixmapLine.get();
2086 PLATFORM_ASSERT(pixmapLine->Initialised());
2087 }
2088 surface->SetUnicodeMode(SC_CP_UTF8 == model.pdoc->dbcsCodePage);
2089 surface->SetDBCSMode(model.pdoc->dbcsCodePage);
2090
2091 const Point ptOrigin = model.GetVisibleOriginInMain();
2092
2093 const int screenLinePaintFirst = static_cast<int>(rcArea.top) / vsDraw.lineHeight;
2094 const int xStart = vsDraw.textStart - model.xOffset + static_cast<int>(ptOrigin.x);
2095
2096 SelectionPosition posCaret = model.sel.RangeMain().caret;
2097 if (model.posDrag.IsValid())
2098 posCaret = model.posDrag;
2099 const Sci::Line lineCaret = model.pdoc->SciLineFromPosition(posCaret.Position());
2100
2101 PRectangle rcTextArea = rcClient;
2102 if (vsDraw.marginInside) {
2103 rcTextArea.left += vsDraw.textStart;
2104 rcTextArea.right -= vsDraw.rightMarginWidth;
2105 } else {
2106 rcTextArea = rcArea;
2107 }
2108
2109 // Remove selection margin from drawing area so text will not be drawn
2110 // on it in unbuffered mode.
2111 if (!bufferedDraw && vsDraw.marginInside) {
2112 PRectangle rcClipText = rcTextArea;
2113 rcClipText.left -= leftTextOverlap;
2114 surfaceWindow->SetClip(rcClipText);
2115 }
2116
2117 // Loop on visible lines
2118#if defined(TIME_PAINTING)
2119 double durLayout = 0.0;
2120 double durPaint = 0.0;
2121 double durCopy = 0.0;
2122 ElapsedPeriod epWhole;
2123#endif
2124 const bool bracesIgnoreStyle = ((vsDraw.braceHighlightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACELIGHT)) ||
2126
2127 Sci::Line lineDocPrevious = -1; // Used to avoid laying out one document line multiple times
2128 AutoLineLayout ll(llc, nullptr);
2129 std::vector<DrawPhase> phases;
2130 if ((phasesDraw == phasesMultiple) && !bufferedDraw) {
2131 for (DrawPhase phase = drawBack; phase <= drawCarets; phase = static_cast<DrawPhase>(phase * 2)) {
2132 phases.push_back(phase);
2133 }
2134 } else {
2135 phases.push_back(drawAll);
2136 }
2137 for (const DrawPhase &phase : phases) {
2138 int ypos = 0;
2139 if (!bufferedDraw)
2140 ypos += screenLinePaintFirst * vsDraw.lineHeight;
2141 int yposScreen = screenLinePaintFirst * vsDraw.lineHeight;
2142 Sci::Line visibleLine = model.TopLineOfMain() + screenLinePaintFirst;
2143 while (visibleLine < model.pcs->LinesDisplayed() && yposScreen < rcArea.bottom) {
2144
2145 const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine);
2146 // Only visible lines should be handled by the code within the loop
2147 PLATFORM_ASSERT(model.pcs->GetVisible(lineDoc));
2148 const Sci::Line lineStartSet = model.pcs->DisplayFromDoc(lineDoc);
2149 const int subLine = static_cast<int>(visibleLine - lineStartSet);
2150
2151 // Copy this line and its styles from the document into local arrays
2152 // and determine the x position at which each character starts.
2153#if defined(TIME_PAINTING)
2154 ElapsedPeriod ep;
2155#endif
2156 if (lineDoc != lineDocPrevious) {
2157 ll.Set(nullptr);
2158 ll.Set(RetrieveLineLayout(lineDoc, model));
2159 LayoutLine(model, lineDoc, surface, vsDraw, ll, model.wrapWidth);
2160 lineDocPrevious = lineDoc;
2161 }
2162#if defined(TIME_PAINTING)
2163 durLayout += ep.Duration(true);
2164#endif
2165 if (ll) {
2166 ll->containsCaret = !hideSelection && (lineDoc == lineCaret);
2167 ll->hotspot = model.GetHotSpotRange();
2168
2169 PRectangle rcLine = rcTextArea;
2170 rcLine.top = static_cast<XYPOSITION>(ypos);
2171 rcLine.bottom = static_cast<XYPOSITION>(ypos + vsDraw.lineHeight);
2172
2173 const Range rangeLine(model.pdoc->LineStart(lineDoc),
2174 model.pdoc->LineStart(lineDoc + 1));
2175
2176 // Highlight the current braces if any
2177 ll->SetBracesHighlight(rangeLine, model.braces, static_cast<char>(model.bracesMatchStyle),
2178 static_cast<int>(model.highlightGuideColumn * vsDraw.spaceWidth), bracesIgnoreStyle);
2179
2180 if (leftTextOverlap && (bufferedDraw || ((phasesDraw < phasesMultiple) && (phase & drawBack)))) {
2181 // Clear the left margin
2182 PRectangle rcSpacer = rcLine;
2183 rcSpacer.right = rcSpacer.left;
2184 rcSpacer.left -= 1;
2185 surface->FillRectangle(rcSpacer, vsDraw.styles[STYLE_DEFAULT].back);
2186 }
2187
2188 DrawLine(surface, model, vsDraw, ll, lineDoc, visibleLine, xStart, rcLine, subLine, phase);
2189#if defined(TIME_PAINTING)
2190 durPaint += ep.Duration(true);
2191#endif
2192 // Restore the previous styles for the brace highlights in case layout is in cache.
2193 ll->RestoreBracesHighlight(rangeLine, model.braces, bracesIgnoreStyle);
2194
2195 if (phase & drawFoldLines) {
2196 DrawFoldLines(surface, model, vsDraw, lineDoc, rcLine);
2197 }
2198
2199 if (phase & drawCarets) {
2200 DrawCarets(surface, model, vsDraw, ll, lineDoc, xStart, rcLine, subLine);
2201 }
2202
2203 if (bufferedDraw) {
2204 const Point from = Point::FromInts(vsDraw.textStart - leftTextOverlap, 0);
2205 const PRectangle rcCopyArea = PRectangle::FromInts(vsDraw.textStart - leftTextOverlap, yposScreen,
2206 static_cast<int>(rcClient.right - vsDraw.rightMarginWidth),
2207 yposScreen + vsDraw.lineHeight);
2208 surfaceWindow->Copy(rcCopyArea, from, *pixmapLine);
2209 }
2210
2212 lineWidthMaxSeen, static_cast<int>(ll->positions[ll->numCharsInLine]));
2213#if defined(TIME_PAINTING)
2214 durCopy += ep.Duration(true);
2215#endif
2216 }
2217
2218 if (!bufferedDraw) {
2219 ypos += vsDraw.lineHeight;
2220 }
2221
2222 yposScreen += vsDraw.lineHeight;
2223 visibleLine++;
2224 }
2225 }
2226 ll.Set(nullptr);
2227#if defined(TIME_PAINTING)
2228 if (durPaint < 0.00000001)
2229 durPaint = 0.00000001;
2230#endif
2231 // Right column limit indicator
2232 PRectangle rcBeyondEOF = (vsDraw.marginInside) ? rcClient : rcArea;
2233 rcBeyondEOF.left = static_cast<XYPOSITION>(vsDraw.textStart);
2234 rcBeyondEOF.right = rcBeyondEOF.right - ((vsDraw.marginInside) ? vsDraw.rightMarginWidth : 0);
2235 rcBeyondEOF.top = static_cast<XYPOSITION>((model.pcs->LinesDisplayed() - model.TopLineOfMain()) * vsDraw.lineHeight);
2236 if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
2237 surfaceWindow->FillRectangle(rcBeyondEOF, vsDraw.styles[STYLE_DEFAULT].back);
2238 if (vsDraw.edgeState == EDGE_LINE) {
2239 const int edgeX = static_cast<int>(vsDraw.theEdge.column * vsDraw.spaceWidth);
2240 rcBeyondEOF.left = static_cast<XYPOSITION>(edgeX + xStart);
2241 rcBeyondEOF.right = rcBeyondEOF.left + 1;
2242 surfaceWindow->FillRectangle(rcBeyondEOF, vsDraw.theEdge.colour);
2243 } else if (vsDraw.edgeState == EDGE_MULTILINE) {
2244 for (size_t edge = 0; edge < vsDraw.theMultiEdge.size(); edge++) {
2245 if (vsDraw.theMultiEdge[edge].column >= 0) {
2246 const int edgeX = static_cast<int>(vsDraw.theMultiEdge[edge].column * vsDraw.spaceWidth);
2247 rcBeyondEOF.left = static_cast<XYPOSITION>(edgeX + xStart);
2248 rcBeyondEOF.right = rcBeyondEOF.left + 1;
2249 surfaceWindow->FillRectangle(rcBeyondEOF, vsDraw.theMultiEdge[edge].colour);
2250 }
2251 }
2252 }
2253 }
2254 //Platform::DebugPrintf("start display %d, offset = %d\n", model.pdoc->Length(), model.xOffset);
2255#if defined(TIME_PAINTING)
2257 "Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n",
2258 durLayout, durPaint, durLayout / durPaint, durCopy, epWhole.Duration());
2259#endif
2260 }
2261}
2262
2263void EditView::FillLineRemainder(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
2264 Sci::Line line, PRectangle rcArea, int subLine) const {
2265 int eolInSelection = 0;
2266 int alpha = SC_ALPHA_NOALPHA;
2267 if (!hideSelection) {
2268 const Sci::Position posAfterLineEnd = model.pdoc->LineStart(line + 1);
2269 eolInSelection = (subLine == (ll->lines - 1)) ? model.sel.InSelectionForEOL(posAfterLineEnd) : 0;
2270 alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha;
2271 }
2272
2273 const ColourOptional background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret);
2274
2275 if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) {
2276 surface->FillRectangle(rcArea, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection));
2277 } else {
2278 if (background.isSet) {
2279 surface->FillRectangle(rcArea, background);
2280 } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) {
2281 surface->FillRectangle(rcArea, vsDraw.styles[ll->styles[ll->numCharsInLine]].back);
2282 } else {
2283 surface->FillRectangle(rcArea, vsDraw.styles[STYLE_DEFAULT].back);
2284 }
2285 if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) {
2286 SimpleAlphaRectangle(surface, rcArea, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha);
2287 }
2288 }
2289}
2290
2291// Space (3 space characters) between line numbers and text when printing.
2292#define lineNumberPrintSpace " "
2293
2295 unsigned int r = orig.GetRed();
2296 unsigned int g = orig.GetGreen();
2297 unsigned int b = orig.GetBlue();
2298 const unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye
2299 const unsigned int il = 0xff - l;
2300 if (l == 0)
2301 return ColourDesired(0xff, 0xff, 0xff);
2302 r = r * il / l;
2303 g = g * il / l;
2304 b = b * il / l;
2305 return ColourDesired(std::min(r, 0xffu), std::min(g, 0xffu), std::min(b, 0xffu));
2306}
2307
2308Sci::Position EditView::FormatRange(bool draw, const Sci_RangeToFormat *pfr, Surface *surface, Surface *surfaceMeasure,
2309 const EditModel &model, const ViewStyle &vs) {
2310 // Can't use measurements cached for screen
2311 posCache.Clear();
2312
2313 ViewStyle vsPrint(vs);
2315
2316 // Modify the view style for printing as do not normally want any of the transient features to be printed
2317 // Printing supports only the line number margin.
2318 int lineNumberIndex = -1;
2319 for (size_t margin = 0; margin < vs.ms.size(); margin++) {
2320 if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) {
2321 lineNumberIndex = static_cast<int>(margin);
2322 } else {
2323 vsPrint.ms[margin].width = 0;
2324 }
2325 }
2326 vsPrint.fixedColumnWidth = 0;
2328 // Don't show indentation guides
2329 // If this ever gets changed, cached pixmap would need to be recreated if technology != SC_TECHNOLOGY_DEFAULT
2330 vsPrint.viewIndentationGuides = ivNone;
2331 // Don't show the selection when printing
2332 vsPrint.selColours.back.isSet = false;
2333 vsPrint.selColours.fore.isSet = false;
2334 vsPrint.selAlpha = SC_ALPHA_NOALPHA;
2336 vsPrint.whitespaceColours.back.isSet = false;
2337 vsPrint.whitespaceColours.fore.isSet = false;
2338 vsPrint.showCaretLineBackground = false;
2339 vsPrint.alwaysShowCaretLineBackground = false;
2340 // Don't highlight matching braces using indicators
2341 vsPrint.braceHighlightIndicatorSet = false;
2342 vsPrint.braceBadLightIndicatorSet = false;
2343
2344 // Set colours for printing according to users settings
2345 for (size_t sty = 0; sty < vsPrint.styles.size(); sty++) {
2347 vsPrint.styles[sty].fore = InvertedLight(vsPrint.styles[sty].fore);
2348 vsPrint.styles[sty].back = InvertedLight(vsPrint.styles[sty].back);
2350 vsPrint.styles[sty].fore = ColourDesired(0, 0, 0);
2351 vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff);
2353 vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff);
2355 if (sty <= STYLE_DEFAULT) {
2356 vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff);
2357 }
2358 }
2359 }
2360 // White background for the line numbers if SC_PRINT_SCREENCOLOURS isn't used
2362 vsPrint.styles[STYLE_LINENUMBER].back = ColourDesired(0xff, 0xff, 0xff);
2363
2364 // Printing uses different margins, so reset screen margins
2365 vsPrint.leftMarginWidth = 0;
2366 vsPrint.rightMarginWidth = 0;
2367
2368 vsPrint.Refresh(*surfaceMeasure, model.pdoc->tabInChars);
2369 // Determining width must happen after fonts have been realised in Refresh
2370 int lineNumberWidth = 0;
2371 if (lineNumberIndex >= 0) {
2372 lineNumberWidth = static_cast<int>(surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font,
2373 "99999" lineNumberPrintSpace, 5 + static_cast<int>(strlen(lineNumberPrintSpace))));
2374 vsPrint.ms[lineNumberIndex].width = lineNumberWidth;
2375 vsPrint.Refresh(*surfaceMeasure, model.pdoc->tabInChars); // Recalculate fixedColumnWidth
2376 }
2377
2378 const Sci::Line linePrintStart = model.pdoc->SciLineFromPosition(pfr->chrg.cpMin);
2379 Sci::Line linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1;
2380 if (linePrintLast < linePrintStart)
2381 linePrintLast = linePrintStart;
2382 const Sci::Line linePrintMax = model.pdoc->SciLineFromPosition(pfr->chrg.cpMax);
2383 if (linePrintLast > linePrintMax)
2384 linePrintLast = linePrintMax;
2385 //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n",
2386 // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight,
2387 // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font));
2388 Sci::Position endPosPrint = model.pdoc->Length();
2389 if (linePrintLast < model.pdoc->LinesTotal())
2390 endPosPrint = model.pdoc->LineStart(linePrintLast + 1);
2391
2392 // Ensure we are styled to where we are formatting.
2393 model.pdoc->EnsureStyledTo(endPosPrint);
2394
2395 const int xStart = vsPrint.fixedColumnWidth + pfr->rc.left;
2396 int ypos = pfr->rc.top;
2397
2398 Sci::Line lineDoc = linePrintStart;
2399
2400 Sci::Position nPrintPos = pfr->chrg.cpMin;
2401 int visibleLine = 0;
2402 int widthPrint = pfr->rc.right - pfr->rc.left - vsPrint.fixedColumnWidth;
2404 widthPrint = LineLayout::wrapWidthInfinite;
2405
2406 while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) {
2407
2408 // When printing, the hdc and hdcTarget may be the same, so
2409 // changing the state of surfaceMeasure may change the underlying
2410 // state of surface. Therefore, any cached state is discarded before
2411 // using each surface.
2412 surfaceMeasure->FlushCachedState();
2413
2414 // Copy this line and its styles from the document into local arrays
2415 // and determine the x position at which each character starts.
2416 LineLayout ll(static_cast<int>(model.pdoc->LineStart(lineDoc + 1) - model.pdoc->LineStart(lineDoc) + 1));
2417 LayoutLine(model, lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
2418
2419 ll.containsCaret = false;
2420
2422 pfr->rc.left,
2423 ypos,
2424 pfr->rc.right - 1,
2425 ypos + vsPrint.lineHeight);
2426
2427 // When document line is wrapped over multiple display lines, find where
2428 // to start printing from to ensure a particular position is on the first
2429 // line of the page.
2430 if (visibleLine == 0) {
2431 const Sci::Position startWithinLine = nPrintPos -
2432 model.pdoc->LineStart(lineDoc);
2433 for (int iwl = 0; iwl < ll.lines - 1; iwl++) {
2434 if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) {
2435 visibleLine = -iwl;
2436 }
2437 }
2438
2439 if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) {
2440 visibleLine = -(ll.lines - 1);
2441 }
2442 }
2443
2444 if (draw && lineNumberWidth &&
2445 (ypos + vsPrint.lineHeight <= pfr->rc.bottom) &&
2446 (visibleLine >= 0)) {
2447 const std::string number = std::to_string(lineDoc + 1) + lineNumberPrintSpace;
2448 PRectangle rcNumber = rcLine;
2449 rcNumber.right = rcNumber.left + lineNumberWidth;
2450 // Right justify
2451 rcNumber.left = rcNumber.right - surfaceMeasure->WidthText(
2452 vsPrint.styles[STYLE_LINENUMBER].font, number.c_str(), static_cast<int>(number.length()));
2453 surface->FlushCachedState();
2454 surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font,
2455 static_cast<XYPOSITION>(ypos + vsPrint.maxAscent), number.c_str(), static_cast<int>(number.length()),
2456 vsPrint.styles[STYLE_LINENUMBER].fore,
2457 vsPrint.styles[STYLE_LINENUMBER].back);
2458 }
2459
2460 // Draw the line
2461 surface->FlushCachedState();
2462
2463 for (int iwl = 0; iwl < ll.lines; iwl++) {
2464 if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) {
2465 if (visibleLine >= 0) {
2466 if (draw) {
2467 rcLine.top = static_cast<XYPOSITION>(ypos);
2468 rcLine.bottom = static_cast<XYPOSITION>(ypos + vsPrint.lineHeight);
2469 DrawLine(surface, model, vsPrint, &ll, lineDoc, visibleLine, xStart, rcLine, iwl, drawAll);
2470 }
2471 ypos += vsPrint.lineHeight;
2472 }
2473 visibleLine++;
2474 if (iwl == ll.lines - 1)
2475 nPrintPos = model.pdoc->LineStart(lineDoc + 1);
2476 else
2477 nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl);
2478 }
2479 }
2480
2481 ++lineDoc;
2482 }
2483
2484 // Clear cache so measurements are not used for screen
2485 posCache.Clear();
2486
2487 return nPrintPos;
2488}
Classes for case folding.
Manages the text of the document.
Character classifications used by Document and RESearch.
Returns the Unicode general category of a character.
Encapsulates a set of characters.
Manages visibility of lines for folding and wrapping.
Visual elements added over text.
Text document that handles notifications, DBCS, styling, words and end of line.
Defines the editor state that must be visible to EditorView.
static void DrawBlockCaret(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, int subLine, int xStart, Sci::Position offset, Sci::Position posCaret, PRectangle rcCaret, ColourDesired caretColour)
Definition: EditView.cxx:1343
static void DrawCaretLineFramed(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, int subLine)
Definition: EditView.cxx:840
static ColourDesired InvertedLight(ColourDesired orig) noexcept
Definition: EditView.cxx:2294
static void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegment, const char *s, ColourDesired textBack, ColourDesired textFore, bool fillBackground)
Definition: EditView.cxx:808
static void DrawEdgeLine(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, Range lineRange, int xStart)
Definition: EditView.cxx:1609
static void DrawMarkUnderline(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, Sci::Line line, PRectangle rcLine)
Definition: EditView.cxx:1635
static const char * ControlCharacterString(unsigned char ch) noexcept
Definition: EditView.cxx:275
static void DrawIndicators(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, int xStart, PRectangle rcLine, int subLine, Sci::Position lineEnd, bool under, Sci::Position hoverIndicatorPos)
Definition: EditView.cxx:1045
static void DrawIndicator(int indicNum, Sci::Position startPos, Sci::Position endPos, Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, int xStart, PRectangle rcLine, Sci::Position secondCharacter, int subLine, Indicator::State state, int value)
Definition: EditView.cxx:1025
static void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid, const ViewStyle &vsDraw)
Definition: EditView.cxx:289
static ColourDesired TextBackground(const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, ColourOptional background, int inSelection, bool inHotspot, int styleMain, Sci::Position i) noexcept
Definition: EditView.cxx:769
static ColourDesired SelectionBackground(const ViewStyle &vsDraw, bool main, bool primarySelection) noexcept
Definition: EditView.cxx:763
static void DrawTranslucentLineState(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcLine, int subLine)
Definition: EditView.cxx:1688
static void DrawFrame(Surface *surface, ColourDesired colour, int alpha, PRectangle rcFrame)
Definition: EditView.cxx:833
#define lineNumberPrintSpace
Definition: EditView.cxx:2292
static constexpr bool AnnotationBoxedOrIndented(int annotationVisible) noexcept
Definition: EditView.cxx:1281
static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourDesired fill, int alpha)
Definition: EditView.cxx:802
static void DrawWrapIndentAndMarker(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, int xStart, PRectangle rcLine, ColourOptional background, DrawWrapMarkerFn customDrawWrapMarker, bool caretActive)
Definition: EditView.cxx:1501
static void DrawFoldLines(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, Sci::Line line, PRectangle rcLine)
Definition: EditView.cxx:2049
static void DrawTranslucentSelection(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcLine, int subLine, Range lineRange, int xStart)
Definition: EditView.cxx:1649
Defines the appearance of the main text area of the editor window.
Encapsulate C++ <chrono> to simplify use.
Interface between Scintilla and lexers.
Interface for loading into a Scintilla document from a background thread.
Defines the style of indicators which are text decorations such as underlining.
A rectangle with integer coordinates.
Defines a mapping between keystrokes and commands.
static Sci_Position LineStart(Sci_Position line, Accessor &styler)
Definition: LexAbaqus.cxx:315
Defines the look of a line marker in the margin .
Defines the appearance of the editor margin.
Data structure used to partition an interval.
Manages data associated with each line of the document.
Interface to platform facilities.
#define PLATFORM_ASSERT(c)
Definition: Platform.h:544
Classes for caching layout information.
Defines global type name Position in the Sci internal namespace.
Data structure used to store sparse styles.
Interface to the edit control.
#define SC_PRINT_COLOURONWHITE
Definition: Scintilla.h:410
#define SC_MARK_UNDERLINE
Definition: Scintilla.h:148
#define INDIC_TEXTFORE
Definition: Scintilla.h:304
#define SC_WRAPVISUALFLAGLOC_START_BY_TEXT
Definition: Scintilla.h:568
#define STYLE_BRACELIGHT
Definition: Scintilla.h:199
#define ANNOTATION_INDENTED
Definition: Scintilla.h:906
#define INVALID_POSITION
Definition: Scintilla.h:44
#define ANNOTATION_BOXED
Definition: Scintilla.h:905
#define STYLE_FOLDDISPLAYTEXT
Definition: Scintilla.h:204
#define SC_PRINT_NORMAL
Definition: Scintilla.h:407
#define SC_MARGIN_NUMBER
Definition: Scintilla.h:177
#define STYLE_BRACEBAD
Definition: Scintilla.h:200
#define SC_FOLDDISPLAYTEXT_BOXED
Definition: Scintilla.h:512
#define SC_INDICFLAG_VALUEFORE
Definition: Scintilla.h:329
#define SC_TECHNOLOGY_DEFAULT
Definition: Scintilla.h:990
#define STYLE_CONTROLCHAR
Definition: Scintilla.h:201
#define SC_WRAPVISUALFLAG_START
Definition: Scintilla.h:562
#define EOLANNOTATION_BOXED
Definition: Scintilla.h:1019
#define SC_FOLDFLAG_LINEBEFORE_EXPANDED
Definition: Scintilla.h:530
#define SC_FOLDFLAG_LINEAFTER_CONTRACTED
Definition: Scintilla.h:533
#define SC_WRAPVISUALFLAG_END
Definition: Scintilla.h:561
#define STYLE_DEFAULT
Definition: Scintilla.h:197
#define SC_WRAPINDENT_DEEPINDENT
Definition: Scintilla.h:576
#define SC_FOLDFLAG_LINEBEFORE_CONTRACTED
Definition: Scintilla.h:531
#define SC_MARK_BACKGROUND
Definition: Scintilla.h:141
#define SC_WRAPVISUALFLAGLOC_END_BY_TEXT
Definition: Scintilla.h:567
#define SC_PRINT_BLACKONWHITE
Definition: Scintilla.h:409
#define EDGE_LINE
Definition: Scintilla.h:697
#define SC_INDICVALUEMASK
Definition: Scintilla.h:328
#define SC_PRINT_SCREENCOLOURS
Definition: Scintilla.h:412
#define SC_FOLDFLAG_LINEAFTER_EXPANDED
Definition: Scintilla.h:532
#define SC_PRINT_COLOURONWHITEDEFAULTBG
Definition: Scintilla.h:411
#define SC_FOLDLEVELHEADERFLAG
Definition: Scintilla.h:496
#define EOLANNOTATION_HIDDEN
Definition: Scintilla.h:1017
#define EDGE_BACKGROUND
Definition: Scintilla.h:698
#define SC_ALPHA_NOALPHA
Definition: Scintilla.h:113
#define SC_CP_UTF8
Definition: Scintilla.h:105
#define STYLE_INDENTGUIDE
Definition: Scintilla.h:202
#define SC_WRAPINDENT_INDENT
Definition: Scintilla.h:575
#define EDGE_MULTILINE
Definition: Scintilla.h:699
#define SC_PRINT_INVERTLIGHT
Definition: Scintilla.h:408
#define STYLE_LINENUMBER
Definition: Scintilla.h:198
#define SC_WRAPINDENT_FIXED
Definition: Scintilla.h:573
Classes maintaining the selection.
Main data structure for holding arrays that handle insertions and deletions efficiently.
Defines the font and colour style for a class of text.
Functions to handle UTF-8 and UTF-16 strings.
Define UniqueString, a unique_ptr based string type for storage in containers and an allocator for Un...
Store information on how the document is to be viewed.
Convenience class to ensure LineLayout objects are always disposed.
Definition: EditView.h:161
void Set(LineLayout *ll_) noexcept
Definition: EditView.h:180
bool More() const noexcept
constexpr unsigned char GetRed() const noexcept
Definition: Platform.h:206
Sci::Line SciLineFromPosition(Sci::Position pos) const noexcept
Definition: Document.cxx:441
int GetStyleClock() const noexcept
Definition: Document.h:462
void EnsureStyledTo(Sci::Position pos)
Definition: Document.cxx:2256
Sci::Position FindColumn(Sci::Line line, Sci::Position column)
Definition: Document.cxx:1592
Sci_Position SCI_METHOD Length() const override
Definition: Document.h:430
Sci::Position MovePositionOutsideChar(Sci::Position pos, Sci::Position moveDir, bool checkLineEnd=true) const noexcept
Definition: Document.cxx:697
int dbcsCodePage
Can also be SC_CP_UTF8 to enable UTF-8 mode.
Definition: Document.h:276
char CharAt(Sci::Position position) const noexcept
Definition: Document.h:391
void GetStyleRange(unsigned char *buffer, Sci::Position position, Sci::Position lengthRetrieve) const
Definition: Document.h:397
int StyleIndexAt(Sci_Position position) const noexcept
Definition: Document.h:396
bool IsWhiteLine(Sci::Line line) const
Definition: Document.cxx:1697
Sci_Position SCI_METHOD LineEnd(Sci_Position line) const override
Definition: Document.cxx:403
int LenChar(Sci::Position pos) const noexcept
Definition: Document.cxx:630
std::unique_ptr< IDecorationList > decorations
Definition: Document.h:286
int AnnotationLines(Sci::Line line) const noexcept
Definition: Document.cxx:2386
int SCI_METHOD GetLevel(Sci_Position line) const override
Definition: Document.cxx:491
int GetMark(Sci::Line line) const noexcept
Definition: Document.cxx:325
StyledText AnnotationStyledText(Sci::Line line) const noexcept
Definition: Document.cxx:2353
int IndentSize() const noexcept
Definition: Document.h:503
Sci::Line LinesTotal() const noexcept
Definition: Document.cxx:2183
void SCI_METHOD GetCharRange(char *buffer, Sci_Position position, Sci_Position lengthRetrieve) const override
Definition: Document.h:392
Sci::Position GetLineIndentPosition(Sci::Line line) const
Definition: Document.cxx:1530
StyledText EOLAnnotationStyledText(Sci::Line line) const noexcept
Definition: Document.cxx:2398
int SCI_METHOD GetLineIndentation(Sci_Position line) override
Definition: Document.cxx:1495
Sci_Position SCI_METHOD LineStart(Sci_Position line) const override
Definition: Document.cxx:395
virtual Sci::Line TopLineOfMain() const =0
SpecialRepresentations reprs
Definition: EditModel.h:30
const char * GetFoldDisplayText(Sci::Line lineDoc) const noexcept
Definition: EditModel.cxx:89
int xOffset
Horizontal scrolled amount in pixels.
Definition: EditModel.h:27
virtual Sci::Line LinesOnScreen() const =0
Document * pdoc
Definition: EditModel.h:53
Sci::Position hoverIndicatorPos
Definition: EditModel.h:48
Sci::Position braces[2]
Definition: EditModel.h:33
std::unique_ptr< IContractionState > pcs
Definition: EditModel.h:45
virtual Range GetHotSpotRange() const noexcept=0
virtual Point GetVisibleOriginInMain() const =0
SelectionPosition posDrag
Definition: EditModel.h:32
void ClearAllTabstops() noexcept
Definition: EditView.cxx:207
void RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw)
Definition: EditView.cxx:311
void DrawLine(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, Sci::Line lineVisible, int xStart, PRectangle rcLine, int subLine, DrawPhase phase)
Definition: EditView.cxx:1971
virtual ~EditView()
Definition: EditView.cxx:186
void FillLineRemainder(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcArea, int subLine) const
Definition: EditView.cxx:2263
void DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, Range lineRange, Sci::Position posLineStart, int xStart, int subLine, ColourOptional background) const
Definition: EditView.cxx:1536
void DropGraphics(bool freeObjects)
Definition: EditView.cxx:251
Sci::Position FormatRange(bool draw, const Sci_RangeToFormat *pfr, Surface *surface, Surface *surfaceMeasure, const EditModel &model, const ViewStyle &vs)
Definition: EditView.cxx:2308
PhasesDraw phasesDraw
Definition: EditView.h:68
void PaintText(Surface *surfaceWindow, const EditModel &model, PRectangle rcArea, PRectangle rcClient, const ViewStyle &vsDraw)
Definition: EditView.cxx:2074
void AllocateGraphics(const ViewStyle &vsDraw)
Definition: EditView.cxx:266
PrintParameters printParameters
Definition: EditView.h:52
LineLayoutCache llc
Definition: EditView.h:81
std::unique_ptr< Surface > pixmapIndentGuide
Definition: EditView.h:78
void DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase)
Definition: EditView.cxx:1285
void LinesAddedOrRemoved(Sci::Line lineOfPos, Sci::Line linesAdded)
Definition: EditView.cxx:237
void DrawIndentGuide(Surface *surface, Sci::Line lineVisible, int lineHeight, XYPOSITION start, PRectangle rcSegment, bool highlight)
Definition: EditView.cxx:794
Sci::Position StartEndDisplayLine(Surface *surface, const EditModel &model, Sci::Position pos, bool start, const ViewStyle &vs)
Definition: EditView.cxx:735
XYPOSITION NextTabstopPos(Sci::Line line, XYPOSITION x, XYPOSITION tabWidth) const noexcept
Definition: EditView.cxx:211
Point LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, Sci::Line topLine, const ViewStyle &vs, PointEnd pe)
Definition: EditView.cxx:597
PhasesDraw
In phasesTwo mode, drawing is performed in two phases, first the background and then the foreground.
Definition: EditView.h:67
Sci::Line DisplayFromPosition(Surface *surface, const EditModel &model, Sci::Position pos, const ViewStyle &vs)
Definition: EditView.cxx:717
void DrawForeground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line lineVisible, PRectangle rcLine, Range lineRange, Sci::Position posLineStart, int xStart, int subLine, ColourOptional background)
Definition: EditView.cxx:1721
bool ClearTabstops(Sci::Line line) noexcept
Definition: EditView.cxx:218
bool bufferedDraw
In bufferedDraw mode, graphics operations are drawn to a pixmap and then copied to the screen.
Definition: EditView.h:61
PositionCache posCache
Definition: EditView.h:82
bool drawOverstrikeCaret
Definition: EditView.h:57
void DrawEOL(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, Sci::Line line, Sci::Position lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, ColourOptional background)
Definition: EditView.cxx:864
LineLayout * RetrieveLineLayout(Sci::Line lineNumber, const EditModel &model)
Definition: EditView.cxx:327
bool SetTwoPhaseDraw(bool twoPhaseDraw) noexcept
Definition: EditView.cxx:189
bool AddTabstop(Sci::Line line, int x)
Definition: EditView.cxx:222
void LayoutLine(const EditModel &model, Sci::Line line, Surface *surface, const ViewStyle &vstyle, LineLayout *ll, int width=LineLayout::wrapWidthInfinite)
Fill in the LineLayout data for the given line.
Definition: EditView.cxx:378
std::unique_ptr< LineTabstops > ldTabstops
Definition: EditView.h:53
bool SetPhasesDraw(int phases) noexcept
Definition: EditView.cxx:196
Range RangeDisplayLine(Surface *surface, const EditModel &model, Sci::Line lineVisible, const ViewStyle &vs)
Definition: EditView.cxx:622
bool imeCaretBlockOverride
Definition: EditView.h:75
std::unique_ptr< Surface > pixmapLine
Definition: EditView.h:77
int GetNextTabstop(Sci::Line line, int x) const noexcept
Definition: EditView.cxx:229
int tabWidthMinimumPixels
Definition: EditView.h:54
void DrawFoldDisplayText(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, int xStart, PRectangle rcLine, int subLine, XYACCUMULATOR subLineStart, DrawPhase phase)
Definition: EditView.cxx:1100
void DrawEOLAnnotationText(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, int xStart, PRectangle rcLine, int subLine, XYACCUMULATOR subLineStart, DrawPhase phase)
Definition: EditView.cxx:1194
SelectionPosition SPositionFromLineX(Surface *surface, const EditModel &model, Sci::Line lineDoc, int x, const ViewStyle &vs)
Find the document position corresponding to an x coordinate on a particular document line.
Definition: EditView.cxx:698
std::unique_ptr< Surface > pixmapIndentGuideHighlight
Definition: EditView.h:79
bool additionalCaretsVisible
Definition: EditView.h:73
void DrawCarets(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line lineDoc, int xStart, PRectangle rcLine, int subLine) const
Definition: EditView.cxx:1409
bool additionalCaretsBlink
Definition: EditView.h:72
SelectionPosition SPositionFromLocation(Surface *surface, const EditModel &model, PointDocument pt, bool canReturnInvalid, bool charPosition, bool virtualSpace, const ViewStyle &vs)
Definition: EditView.cxx:647
DrawTabArrowFn customDrawTabArrow
Some platforms, notably PLAT_CURSES, do not support Scintilla's native DrawTabArrow function for draw...
Definition: EditView.h:89
bool LinesOverlap() const noexcept
Definition: EditView.cxx:203
void DrawIndentGuidesOverEmpty(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, Sci::Line lineVisible, PRectangle rcLine, int xStart, int subLine)
Definition: EditView.cxx:1917
DrawWrapMarkerFn customDrawWrapMarker
Definition: EditView.h:90
double Duration(bool reset=false) noexcept
Return duration as floating point seconds.
Definition: ElapsedPeriod.h:21
StyleAndColour sacNormal
Definition: Indicator.h:30
bool IsDynamic() const noexcept
Definition: Indicator.h:42
int Flags() const noexcept
Definition: Indicator.h:48
StyleAndColour sacHover
Definition: Indicator.h:31
LineLayout * Retrieve(Sci::Line lineNumber, Sci::Line lineCaret, int maxChars, int styleClock_, Sci::Line linesOnScreen, Sci::Line linesInDoc)
void SetLevel(int level_) noexcept
int FindPositionFromX(XYPOSITION x, Range range, bool charPosition) const noexcept
int LineStart(int line) const noexcept
Range SubLineRange(int subLine, Scope scope) const noexcept
std::unique_ptr< char[]> chars
Definition: PositionCache.h:68
void SetBracesHighlight(Range rangeLine, const Sci::Position braces[], char bracesMatchStyle, int xHighlight, bool ignoreStyle)
enum Scintilla::LineLayout::ValidLevel validity
std::unique_ptr< XYPOSITION[]> positions
Definition: PositionCache.h:70
int EndLineStyle() const noexcept
std::unique_ptr< unsigned char[]> styles
Definition: PositionCache.h:69
bool InLine(int offset, int line) const noexcept
void SetLineStart(int line, int start)
Point PointFromPosition(int posInLine, int lineHeight, PointEnd pe) const noexcept
void RestoreBracesHighlight(Range rangeLine, const Sci::Position braces[], bool ignoreStyle)
A geometric rectangle class.
Definition: Platform.h:131
static constexpr PRectangle FromInts(int left_, int top_, int right_, int bottom_) noexcept
Definition: Platform.h:142
constexpr bool Intersects(PRectangle other) const noexcept
Definition: Platform.h:166
constexpr bool Empty() const noexcept
Definition: Platform.h:178
XYPOSITION right
Definition: Platform.h:135
constexpr XYPOSITION Width() const noexcept
Definition: Platform.h:176
XYPOSITION bottom
Definition: Platform.h:136
static void DebugPrintf(const char *format,...)
Definition: PlatGTK.cxx:2032
A point in document space.
Definition: PositionCache.h:25
A geometric point class.
Definition: Platform.h:99
static constexpr Point FromInts(int x_, int y_) noexcept
Definition: Platform.h:107
XYPOSITION y
Definition: Platform.h:102
XYPOSITION x
Definition: Platform.h:101
void MeasureWidths(Surface *surface, const ViewStyle &vstyle, unsigned int styleNumber, const char *s, unsigned int len, XYPOSITION *positions, const Document *pdoc)
void SetSize(size_t size_)
The range class represents a range of text in a document.
Definition: Document.h:29
Sci::Position end
Definition: Document.h:32
bool Valid() const noexcept
Definition: Document.h:45
Sci::Position start
Definition: Document.h:31
bool ContainsCharacter(Sci::Position pos) const noexcept
Definition: Document.h:67
Sci::Position First() const noexcept
Definition: Document.h:49
Sci::Position Position() const noexcept
Definition: Selection.h:34
bool IsValid() const noexcept
Definition: Selection.h:52
Sci::Position VirtualSpace() const noexcept
Definition: Selection.h:41
void SetPosition(Sci::Position position_) noexcept
Definition: Selection.h:37
void SetVirtualSpace(Sci::Position virtualSpace_) noexcept
Definition: Selection.h:44
int CharacterInSelection(Sci::Position posCharacter) const noexcept
Definition: Selection.cxx:393
SelectionRange & RangeMain() noexcept
Definition: Selection.cxx:258
int InSelectionForEOL(Sci::Position pos) const noexcept
Definition: Selection.cxx:401
Sci::Position VirtualSpaceFor(Sci::Position pos) const noexcept
Definition: Selection.cxx:409
size_t Main() const noexcept
Definition: Selection.cxx:241
size_t Count() const noexcept
Definition: Selection.cxx:237
SelectionRange & Range(size_t r) noexcept
Definition: Selection.cxx:250
Sci::Position MainCaret() const noexcept
Definition: Selection.cxx:204
const Representation * RepresentationFromCharacter(const char *charBytes, size_t len) const
ColourDesired back
Definition: Style.h:62
ColourDesired fore
Definition: Style.h:61
FontAlias font
Definition: Style.h:71
A surface abstracts a place to draw.
Definition: Platform.h:340
virtual void SetClip(PRectangle rc)=0
static Surface * Allocate(int technology)
Definition: PlatGTK.cxx:964
virtual void PenColour(ColourDesired fore)=0
virtual void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore)=0
virtual void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back)=0
virtual void MoveTo(int x_, int y_)=0
virtual void SetDBCSMode(int codePage)=0
virtual void LineTo(int x_, int y_)=0
virtual void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back)=0
virtual void FillRectangle(PRectangle rc, ColourDesired back)=0
virtual void FlushCachedState()=0
virtual void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, ColourDesired outline, int alphaOutline, int flags)=0
virtual XYPOSITION WidthText(Font &font_, const char *s, int len)=0
virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource)=0
virtual void SetUnicodeMode(bool unicodeMode_)=0
int maskDrawInText
Mask for markers that always draw in text.
Definition: ViewStyle.h:120
ColourDesired WrapColour() const noexcept
Definition: ViewStyle.cxx:499
std::vector< Style > styles
Definition: ViewStyle.h:84
ForeBackColours hotspotColours
Definition: ViewStyle.h:113
bool showCaretLineBackground
Definition: ViewStyle.h:134
std::vector< LineMarker > markers
Definition: ViewStyle.h:86
int maskInLine
Mask for markers to be put into text because there is nowhere for them to go in margin.
Definition: ViewStyle.h:119
bool DrawCaretInsideSelection(bool inOverstrike, bool imeCaretBlockOverride) const noexcept
Definition: ViewStyle.cxx:571
std::vector< EdgeProperties > theMultiEdge
Definition: ViewStyle.h:156
int GetFrameWidth() const noexcept
Definition: ViewStyle.cxx:438
bool alwaysShowCaretLineBackground
Definition: ViewStyle.h:135
int fixedColumnWidth
Total width of margins.
Definition: ViewStyle.h:122
unsigned int maxDescent
Definition: ViewStyle.h:95
ColourDesired caretLineBackground
Definition: ViewStyle.h:136
bool SelectionBackgroundDrawn() const noexcept
Definition: ViewStyle.cxx:484
std::vector< Indicator > indicators
Definition: ViewStyle.h:88
unsigned int maxAscent
Definition: ViewStyle.h:94
ForeBackColours selColours
Definition: ViewStyle.h:99
int leftMarginWidth
Margins are ordered: Line Numbers, Selection Margin, Spacing Margin.
Definition: ViewStyle.h:117
bool braceBadLightIndicatorSet
Definition: ViewStyle.h:152
XYPOSITION tabWidth
Definition: ViewStyle.h:98
void Refresh(Surface &surface, int tabInChars)
Definition: ViewStyle.cxx:287
int rightMarginWidth
Spacing margin on right of text.
Definition: ViewStyle.h:118
bool WhiteSpaceVisible(bool inIndent) const noexcept
Definition: ViewStyle.cxx:493
ColourOptional Background(int marksOfLine, bool caretActive, bool lineContainsCaret) const noexcept
Definition: ViewStyle.cxx:453
XYPOSITION aveCharWidth
Definition: ViewStyle.h:96
XYPOSITION spaceWidth
Definition: ViewStyle.h:97
bool IsLineFrameOpaque(bool caretActive, bool lineContainsCaret) const noexcept
Definition: ViewStyle.cxx:442
bool marginInside
true: margin included in text view, false: separate views
Definition: ViewStyle.h:123
TabDrawMode tabDrawMode
Definition: ViewStyle.h:127
ForeBackColours whitespaceColours
Definition: ViewStyle.h:106
XYPOSITION controlCharWidth
Definition: ViewStyle.h:108
CaretShape CaretShapeForMode(bool inOverstrike) const noexcept
Definition: ViewStyle.cxx:579
bool braceHighlightIndicatorSet
Definition: ViewStyle.h:150
ColourDesired selAdditionalForeground
Definition: ViewStyle.h:100
ColourDesired caretcolour
Definition: ViewStyle.h:131
ColourDesired additionalCaretColour
Definition: ViewStyle.h:132
std::vector< MarginStyle > ms
Definition: ViewStyle.h:121
bool IsCaretVisible() const noexcept
Definition: ViewStyle.cxx:567
bool WhitespaceBackgroundDrawn() const noexcept
Definition: ViewStyle.cxx:489
EdgeProperties theEdge
Definition: ViewStyle.h:155
IndentView viewIndentationGuides
Definition: ViewStyle.h:129
int textStart
Starting x position of text within the view.
Definition: ViewStyle.h:124
WhiteSpaceVisibility viewWhitespace
Definition: ViewStyle.h:126
static gchar indent[100]
Definition: editor.c:91
gchar * text
Definition: editor.c:83
gint pos
Definition: editor.c:87
#define fill(Order, Group, Idx, Charset, Name)
Definition: encodings.c:62
unsigned long int lineNumber
Definition: geany_cobol.c:134
vString * line
Definition: geany_cobol.c:133
unsigned int max
ptrdiff_t Position
Definition: Position.h:19
ptrdiff_t Line
Definition: Position.h:20
Styling buffer using one element for each run rather than using a filled buffer.
Definition: Converter.h:9
double XYACCUMULATOR
Definition: Platform.h:82
static int WidthStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, const char *text, const unsigned char *styles, size_t len)
Definition: EditView.cxx:82
T MakeUpperCase(T ch) noexcept
Definition: CharacterSet.h:188
void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XYPOSITION ybase, const char *s, int len, DrawPhase phase)
Definition: EditView.cxx:119
float XYPOSITION
Definition: Platform.h:81
bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st) noexcept
Definition: EditView.cxx:69
@ ivLookForward
Definition: ViewStyle.h:43
@ ivLookBoth
Definition: ViewStyle.h:43
constexpr bool UTF8IsAscii(int ch) noexcept
Definition: UniConversion.h:50
constexpr bool IsSpaceOrTab(int ch) noexcept
Definition: PositionCache.h:17
void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, const StyledText &st, size_t start, size_t length, DrawPhase phase)
Definition: EditView.cxx:135
void(* DrawWrapMarkerFn)(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour)
Definition: MarginView.h:15
@ tdLongArrow
Definition: ViewStyle.h:47
DrawPhase
The view may be drawn in separate phases.
Definition: EditView.h:23
@ drawCarets
Definition: EditView.h:32
@ drawAll
Definition: EditView.h:33
@ drawIndicatorsFore
Definition: EditView.h:28
@ drawLineTranslucent
Definition: EditView.h:30
@ drawBack
Definition: EditView.h:24
@ drawSelectionTranslucent
Definition: EditView.h:29
@ drawText
Definition: EditView.h:26
@ drawIndentationGuides
Definition: EditView.h:27
@ drawFoldLines
Definition: EditView.h:31
@ drawIndicatorsBack
Definition: EditView.h:25
void * WindowID
Definition: Platform.h:89
@ wsInvisible
Definition: ViewStyle.h:45
constexpr bool IsUpperOrLowerCase(int ch) noexcept
Definition: CharacterSet.h:145
int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st)
Definition: EditView.cxx:99
void DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour)
Definition: MarginView.cxx:57
constexpr int LevelNumber(int level) noexcept
Definition: Document.h:167
T MakeLowerCase(T ch) noexcept
Definition: CharacterSet.h:196
Definition: main.py:1
#define NULL
Definition: rbtree.h:150
if(!stash_group_load_from_file(group, filename)) g_warning(_("Could not load keyfile %s!")
long lines
Definition: stats.c:32
Sci_PositionCR cpMin
Definition: Scintilla.h:1177
Sci_PositionCR cpMax
Definition: Scintilla.h:1178
struct Sci_Rectangle rc
Definition: Scintilla.h:1207
struct Sci_CharacterRange chrg
Definition: Scintilla.h:1209
ColourDesired colour
Definition: ViewStyle.h:69
ColourOptional back
Definition: ViewStyle.h:64
ColourOptional fore
Definition: ViewStyle.h:63
SelectionPosition caret
Definition: Selection.h:87
SelectionSegment Intersect(SelectionSegment check) const noexcept
Definition: Selection.cxx:126
bool ContainsCharacter(Sci::Position posCharacter) const noexcept
Definition: Selection.cxx:119
SelectionPosition anchor
Definition: Selection.h:88
bool Empty() const noexcept
Definition: Selection.h:72
SelectionPosition end
Definition: Selection.h:60
SelectionPosition start
Definition: Selection.h:59
ColourDesired fore
Definition: Indicator.h:15
size_t StyleAt(size_t i) const noexcept
Definition: Document.h:122
size_t LineLength(size_t start) const noexcept
Definition: Document.h:116
const unsigned char * styles
Definition: Document.h:110
const char * text
Definition: Document.h:107
const Representation * representation
int end() const noexcept