Update Scintilla to version 3.7.1
[geany-mirror.git] / scintilla / src / Indicator.cxx
blobc23ae4e17c1eb48b6d2a77daadee5a6c3f1fac50
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>
12 #include "Platform.h"
14 #include "Scintilla.h"
15 #include "Indicator.h"
16 #include "XPM.h"
18 #ifdef SCI_NAMESPACE
19 using namespace Scintilla;
20 #endif
22 static PRectangle PixelGridAlign(const PRectangle &rc) {
23 // Move left and right side to nearest pixel to avoid blurry visuals
24 return PRectangle::FromInts(int(rc.left + 0.5), int(rc.top), int(rc.right + 0.5), int(rc.bottom));
27 void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine, const PRectangle &rcCharacter, DrawState drawState, int value) const {
28 StyleAndColour sacDraw = sacNormal;
29 if (Flags() & SC_INDICFLAG_VALUEFORE) {
30 sacDraw.fore = value & SC_INDICVALUEMASK;
32 if (drawState == drawHover) {
33 sacDraw = sacHover;
35 surface->PenColour(sacDraw.fore);
36 int ymid = static_cast<int>(rc.bottom + rc.top) / 2;
37 if (sacDraw.style == INDIC_SQUIGGLE) {
38 int x = int(rc.left+0.5);
39 int xLast = int(rc.right+0.5);
40 int y = 0;
41 surface->MoveTo(x, static_cast<int>(rc.top) + y);
42 while (x < xLast) {
43 if ((x + 2) > xLast) {
44 if (xLast > x)
45 y = 1;
46 x = xLast;
47 } else {
48 x += 2;
49 y = 2 - y;
51 surface->LineTo(x, static_cast<int>(rc.top) + y);
53 } else if (sacDraw.style == INDIC_SQUIGGLEPIXMAP) {
54 PRectangle rcSquiggle = PixelGridAlign(rc);
56 int width = Platform::Minimum(4000, static_cast<int>(rcSquiggle.Width()));
57 RGBAImage image(width, 3, 1.0, 0);
58 enum { alphaFull = 0xff, alphaSide = 0x2f, alphaSide2=0x5f };
59 for (int x = 0; x < width; x++) {
60 if (x%2) {
61 // Two halfway columns have a full pixel in middle flanked by light pixels
62 image.SetPixel(x, 0, sacDraw.fore, alphaSide);
63 image.SetPixel(x, 1, sacDraw.fore, alphaFull);
64 image.SetPixel(x, 2, sacDraw.fore, alphaSide);
65 } else {
66 // Extreme columns have a full pixel at bottom or top and a mid-tone pixel in centre
67 image.SetPixel(x, (x % 4) ? 0 : 2, sacDraw.fore, alphaFull);
68 image.SetPixel(x, 1, sacDraw.fore, alphaSide2);
71 surface->DrawRGBAImage(rcSquiggle, image.GetWidth(), image.GetHeight(), image.Pixels());
72 } else if (sacDraw.style == INDIC_SQUIGGLELOW) {
73 surface->MoveTo(static_cast<int>(rc.left), static_cast<int>(rc.top));
74 int x = static_cast<int>(rc.left) + 3;
75 int y = 0;
76 while (x < rc.right) {
77 surface->LineTo(x - 1, static_cast<int>(rc.top) + y);
78 y = 1 - y;
79 surface->LineTo(x, static_cast<int>(rc.top) + y);
80 x += 3;
82 surface->LineTo(static_cast<int>(rc.right), static_cast<int>(rc.top) + y); // Finish the line
83 } else if (sacDraw.style == INDIC_TT) {
84 surface->MoveTo(static_cast<int>(rc.left), ymid);
85 int x = static_cast<int>(rc.left) + 5;
86 while (x < rc.right) {
87 surface->LineTo(x, ymid);
88 surface->MoveTo(x-3, ymid);
89 surface->LineTo(x-3, ymid+2);
90 x++;
91 surface->MoveTo(x, ymid);
92 x += 5;
94 surface->LineTo(static_cast<int>(rc.right), ymid); // Finish the line
95 if (x - 3 <= rc.right) {
96 surface->MoveTo(x-3, ymid);
97 surface->LineTo(x-3, ymid+2);
99 } else if (sacDraw.style == INDIC_DIAGONAL) {
100 int x = static_cast<int>(rc.left);
101 while (x < rc.right) {
102 surface->MoveTo(x, static_cast<int>(rc.top) + 2);
103 int endX = x+3;
104 int endY = static_cast<int>(rc.top) - 1;
105 if (endX > rc.right) {
106 endY += endX - static_cast<int>(rc.right);
107 endX = static_cast<int>(rc.right);
109 surface->LineTo(endX, endY);
110 x += 4;
112 } else if (sacDraw.style == INDIC_STRIKE) {
113 surface->MoveTo(static_cast<int>(rc.left), static_cast<int>(rc.top) - 4);
114 surface->LineTo(static_cast<int>(rc.right), static_cast<int>(rc.top) - 4);
115 } else if ((sacDraw.style == INDIC_HIDDEN) || (sacDraw.style == INDIC_TEXTFORE)) {
116 // Draw nothing
117 } else if (sacDraw.style == INDIC_BOX) {
118 surface->MoveTo(static_cast<int>(rc.left), ymid + 1);
119 surface->LineTo(static_cast<int>(rc.right), ymid + 1);
120 surface->LineTo(static_cast<int>(rc.right), static_cast<int>(rcLine.top) + 1);
121 surface->LineTo(static_cast<int>(rc.left), static_cast<int>(rcLine.top) + 1);
122 surface->LineTo(static_cast<int>(rc.left), ymid + 1);
123 } else if (sacDraw.style == INDIC_ROUNDBOX ||
124 sacDraw.style == INDIC_STRAIGHTBOX ||
125 sacDraw.style == INDIC_FULLBOX) {
126 PRectangle rcBox = rcLine;
127 if (sacDraw.style != INDIC_FULLBOX)
128 rcBox.top = rcLine.top + 1;
129 rcBox.left = rc.left;
130 rcBox.right = rc.right;
131 surface->AlphaRectangle(rcBox, (sacDraw.style == INDIC_ROUNDBOX) ? 1 : 0,
132 sacDraw.fore, fillAlpha, sacDraw.fore, outlineAlpha, 0);
133 } else if (sacDraw.style == INDIC_DOTBOX) {
134 PRectangle rcBox = PixelGridAlign(rc);
135 rcBox.top = rcLine.top + 1;
136 rcBox.bottom = rcLine.bottom;
137 // Cap width at 4000 to avoid large allocations when mistakes made
138 int width = Platform::Minimum(static_cast<int>(rcBox.Width()), 4000);
139 RGBAImage image(width, static_cast<int>(rcBox.Height()), 1.0, 0);
140 // Draw horizontal lines top and bottom
141 for (int x=0; x<width; x++) {
142 for (int y = 0; y<static_cast<int>(rcBox.Height()); y += static_cast<int>(rcBox.Height()) - 1) {
143 image.SetPixel(x, y, sacDraw.fore, ((x + y) % 2) ? outlineAlpha : fillAlpha);
146 // Draw vertical lines left and right
147 for (int y = 1; y<static_cast<int>(rcBox.Height()); y++) {
148 for (int x=0; x<width; x += width-1) {
149 image.SetPixel(x, y, sacDraw.fore, ((x + y) % 2) ? outlineAlpha : fillAlpha);
152 surface->DrawRGBAImage(rcBox, image.GetWidth(), image.GetHeight(), image.Pixels());
153 } else if (sacDraw.style == INDIC_DASH) {
154 int x = static_cast<int>(rc.left);
155 while (x < rc.right) {
156 surface->MoveTo(x, ymid);
157 surface->LineTo(Platform::Minimum(x + 4, static_cast<int>(rc.right)), ymid);
158 x += 7;
160 } else if (sacDraw.style == INDIC_DOTS) {
161 int x = static_cast<int>(rc.left);
162 while (x < static_cast<int>(rc.right)) {
163 PRectangle rcDot = PRectangle::FromInts(x, ymid, x + 1, ymid + 1);
164 surface->FillRectangle(rcDot, sacDraw.fore);
165 x += 2;
167 } else if (sacDraw.style == INDIC_COMPOSITIONTHICK) {
168 PRectangle rcComposition(rc.left+1, rcLine.bottom-2, rc.right-1, rcLine.bottom);
169 surface->FillRectangle(rcComposition, sacDraw.fore);
170 } else if (sacDraw.style == INDIC_COMPOSITIONTHIN) {
171 PRectangle rcComposition(rc.left+1, rcLine.bottom-2, rc.right-1, rcLine.bottom-1);
172 surface->FillRectangle(rcComposition, sacDraw.fore);
173 } else if (sacDraw.style == INDIC_POINT || sacDraw.style == INDIC_POINTCHARACTER) {
174 if (rcCharacter.Width() >= 0.1) {
175 const int pixelHeight = static_cast<int>(rc.Height() - 1.0f); // 1 pixel onto next line if multiphase
176 const XYPOSITION x = (sacDraw.style == INDIC_POINT) ? (rcCharacter.left) : ((rcCharacter.right + rcCharacter.left) / 2);
177 const int ix = static_cast<int>(x + 0.5f);
178 const int iy = static_cast<int>(rc.top + 1.0f);
179 Point pts[] = {
180 Point::FromInts(ix - pixelHeight, iy + pixelHeight), // Left
181 Point::FromInts(ix + pixelHeight, iy + pixelHeight), // Right
182 Point::FromInts(ix, iy) // Top
184 surface->Polygon(pts, 3, sacDraw.fore, sacDraw.fore);
186 } else { // Either INDIC_PLAIN or unknown
187 surface->MoveTo(static_cast<int>(rc.left), ymid);
188 surface->LineTo(static_cast<int>(rc.right), ymid);
192 void Indicator::SetFlags(int attributes_) {
193 attributes = attributes_;