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