Update Scintilla to 4.0.4
[TortoiseGit.git] / ext / scintilla / src / Indicator.cxx
blob90fab557bfb2a6677ade37a9cd3a48e3a1426f46
1 // Scintilla source code edit control
2 /** @file Indicator.cxx
3 ** Defines the style of indicators which are text decorations such as underlining.
4 **/
5 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
8 #include <stdexcept>
9 #include <vector>
10 #include <map>
11 #include <algorithm>
12 #include <memory>
14 #include "Platform.h"
16 #include "Scintilla.h"
17 #include "Indicator.h"
18 #include "XPM.h"
20 using namespace Scintilla;
22 static PRectangle PixelGridAlign(const PRectangle &rc) {
23 // Move left and right side to nearest pixel to avoid blurry visuals
24 return PRectangle::FromInts(static_cast<int>(rc.left + 0.5), static_cast<int>(rc.top),
25 static_cast<int>(rc.right + 0.5), static_cast<int>(rc.bottom));
28 void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine, const PRectangle &rcCharacter, DrawState drawState, int value) const {
29 StyleAndColour sacDraw = sacNormal;
30 if (Flags() & SC_INDICFLAG_VALUEFORE) {
31 sacDraw.fore = value & SC_INDICVALUEMASK;
33 if (drawState == drawHover) {
34 sacDraw = sacHover;
36 surface->PenColour(sacDraw.fore);
37 const int ymid = static_cast<int>(rc.bottom + rc.top) / 2;
38 if (sacDraw.style == INDIC_SQUIGGLE) {
39 int x = static_cast<int>(rc.left+0.5);
40 const int xLast = static_cast<int>(rc.right+0.5);
41 int y = 0;
42 surface->MoveTo(x, static_cast<int>(rc.top) + y);
43 while (x < xLast) {
44 if ((x + 2) > xLast) {
45 if (xLast > x)
46 y = 1;
47 x = xLast;
48 } else {
49 x += 2;
50 y = 2 - y;
52 surface->LineTo(x, static_cast<int>(rc.top) + y);
54 } else if (sacDraw.style == INDIC_SQUIGGLEPIXMAP) {
55 const PRectangle rcSquiggle = PixelGridAlign(rc);
57 const int width = std::min(4000, static_cast<int>(rcSquiggle.Width()));
58 RGBAImage image(width, 3, 1.0, 0);
59 enum { alphaFull = 0xff, alphaSide = 0x2f, alphaSide2=0x5f };
60 for (int x = 0; x < width; x++) {
61 if (x%2) {
62 // Two halfway columns have a full pixel in middle flanked by light pixels
63 image.SetPixel(x, 0, sacDraw.fore, alphaSide);
64 image.SetPixel(x, 1, sacDraw.fore, alphaFull);
65 image.SetPixel(x, 2, sacDraw.fore, alphaSide);
66 } else {
67 // Extreme columns have a full pixel at bottom or top and a mid-tone pixel in centre
68 image.SetPixel(x, (x % 4) ? 0 : 2, sacDraw.fore, alphaFull);
69 image.SetPixel(x, 1, sacDraw.fore, alphaSide2);
72 surface->DrawRGBAImage(rcSquiggle, image.GetWidth(), image.GetHeight(), image.Pixels());
73 } else if (sacDraw.style == INDIC_SQUIGGLELOW) {
74 surface->MoveTo(static_cast<int>(rc.left), static_cast<int>(rc.top));
75 int x = static_cast<int>(rc.left) + 3;
76 int y = 0;
77 while (x < rc.right) {
78 surface->LineTo(x - 1, static_cast<int>(rc.top) + y);
79 y = 1 - y;
80 surface->LineTo(x, static_cast<int>(rc.top) + y);
81 x += 3;
83 surface->LineTo(static_cast<int>(rc.right), static_cast<int>(rc.top) + y); // Finish the line
84 } else if (sacDraw.style == INDIC_TT) {
85 surface->MoveTo(static_cast<int>(rc.left), ymid);
86 int x = static_cast<int>(rc.left) + 5;
87 while (x < rc.right) {
88 surface->LineTo(x, ymid);
89 surface->MoveTo(x-3, ymid);
90 surface->LineTo(x-3, ymid+2);
91 x++;
92 surface->MoveTo(x, ymid);
93 x += 5;
95 surface->LineTo(static_cast<int>(rc.right), ymid); // Finish the line
96 if (x - 3 <= rc.right) {
97 surface->MoveTo(x-3, ymid);
98 surface->LineTo(x-3, ymid+2);
100 } else if (sacDraw.style == INDIC_DIAGONAL) {
101 int x = static_cast<int>(rc.left);
102 while (x < rc.right) {
103 surface->MoveTo(x, static_cast<int>(rc.top) + 2);
104 int endX = x+3;
105 int endY = static_cast<int>(rc.top) - 1;
106 if (endX > rc.right) {
107 endY += endX - static_cast<int>(rc.right);
108 endX = static_cast<int>(rc.right);
110 surface->LineTo(endX, endY);
111 x += 4;
113 } else if (sacDraw.style == INDIC_STRIKE) {
114 surface->MoveTo(static_cast<int>(rc.left), static_cast<int>(rc.top) - 4);
115 surface->LineTo(static_cast<int>(rc.right), static_cast<int>(rc.top) - 4);
116 } else if ((sacDraw.style == INDIC_HIDDEN) || (sacDraw.style == INDIC_TEXTFORE)) {
117 // Draw nothing
118 } else if (sacDraw.style == INDIC_BOX) {
119 surface->MoveTo(static_cast<int>(rc.left), ymid + 1);
120 surface->LineTo(static_cast<int>(rc.right), ymid + 1);
121 surface->LineTo(static_cast<int>(rc.right), static_cast<int>(rcLine.top) + 1);
122 surface->LineTo(static_cast<int>(rc.left), static_cast<int>(rcLine.top) + 1);
123 surface->LineTo(static_cast<int>(rc.left), ymid + 1);
124 } else if (sacDraw.style == INDIC_ROUNDBOX ||
125 sacDraw.style == INDIC_STRAIGHTBOX ||
126 sacDraw.style == INDIC_FULLBOX) {
127 PRectangle rcBox = rcLine;
128 if (sacDraw.style != INDIC_FULLBOX)
129 rcBox.top = rcLine.top + 1;
130 rcBox.left = rc.left;
131 rcBox.right = rc.right;
132 surface->AlphaRectangle(rcBox, (sacDraw.style == INDIC_ROUNDBOX) ? 1 : 0,
133 sacDraw.fore, fillAlpha, sacDraw.fore, outlineAlpha, 0);
134 } else if (sacDraw.style == INDIC_DOTBOX) {
135 PRectangle rcBox = PixelGridAlign(rc);
136 rcBox.top = rcLine.top + 1;
137 rcBox.bottom = rcLine.bottom;
138 // Cap width at 4000 to avoid large allocations when mistakes made
139 const int width = std::min(static_cast<int>(rcBox.Width()), 4000);
140 RGBAImage image(width, static_cast<int>(rcBox.Height()), 1.0, 0);
141 // Draw horizontal lines top and bottom
142 for (int x=0; x<width; x++) {
143 for (int y = 0; y<static_cast<int>(rcBox.Height()); y += static_cast<int>(rcBox.Height()) - 1) {
144 image.SetPixel(x, y, sacDraw.fore, ((x + y) % 2) ? outlineAlpha : fillAlpha);
147 // Draw vertical lines left and right
148 for (int y = 1; y<static_cast<int>(rcBox.Height()); y++) {
149 for (int x=0; x<width; x += width-1) {
150 image.SetPixel(x, y, sacDraw.fore, ((x + y) % 2) ? outlineAlpha : fillAlpha);
153 surface->DrawRGBAImage(rcBox, image.GetWidth(), image.GetHeight(), image.Pixels());
154 } else if (sacDraw.style == INDIC_DASH) {
155 int x = static_cast<int>(rc.left);
156 while (x < rc.right) {
157 surface->MoveTo(x, ymid);
158 surface->LineTo(std::min(x + 4, static_cast<int>(rc.right)), ymid);
159 x += 7;
161 } else if (sacDraw.style == INDIC_DOTS) {
162 int x = static_cast<int>(rc.left);
163 while (x < static_cast<int>(rc.right)) {
164 const PRectangle rcDot = PRectangle::FromInts(x, ymid, x + 1, ymid + 1);
165 surface->FillRectangle(rcDot, sacDraw.fore);
166 x += 2;
168 } else if (sacDraw.style == INDIC_COMPOSITIONTHICK) {
169 const PRectangle rcComposition(rc.left+1, rcLine.bottom-2, rc.right-1, rcLine.bottom);
170 surface->FillRectangle(rcComposition, sacDraw.fore);
171 } else if (sacDraw.style == INDIC_COMPOSITIONTHIN) {
172 const PRectangle rcComposition(rc.left+1, rcLine.bottom-2, rc.right-1, rcLine.bottom-1);
173 surface->FillRectangle(rcComposition, sacDraw.fore);
174 } else if (sacDraw.style == INDIC_POINT || sacDraw.style == INDIC_POINTCHARACTER) {
175 if (rcCharacter.Width() >= 0.1) {
176 const int pixelHeight = static_cast<int>(rc.Height() - 1.0f); // 1 pixel onto next line if multiphase
177 const XYPOSITION x = (sacDraw.style == INDIC_POINT) ? (rcCharacter.left) : ((rcCharacter.right + rcCharacter.left) / 2);
178 const int ix = static_cast<int>(x + 0.5f);
179 const int iy = static_cast<int>(rc.top + 1.0f);
180 Point pts[] = {
181 Point::FromInts(ix - pixelHeight, iy + pixelHeight), // Left
182 Point::FromInts(ix + pixelHeight, iy + pixelHeight), // Right
183 Point::FromInts(ix, iy) // Top
185 surface->Polygon(pts, 3, sacDraw.fore, sacDraw.fore);
187 } else { // Either INDIC_PLAIN or unknown
188 surface->MoveTo(static_cast<int>(rc.left), ymid);
189 surface->LineTo(static_cast<int>(rc.right), ymid);
193 void Indicator::SetFlags(int attributes_) {
194 attributes = attributes_;