1 // Scintilla source code edit control
2 /** @file Indicator.cxx
3 ** Defines the style of indicators which are text decorations such as underlining.
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.
16 #include "Scintilla.h"
17 #include "Indicator.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
) {
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);
42 surface
->MoveTo(x
, static_cast<int>(rc
.top
) + y
);
44 if ((x
+ 2) > xLast
) {
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
++) {
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
);
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;
77 while (x
< rc
.right
) {
78 surface
->LineTo(x
- 1, static_cast<int>(rc
.top
) + y
);
80 surface
->LineTo(x
, static_cast<int>(rc
.top
) + y
);
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);
92 surface
->MoveTo(x
, ymid
);
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);
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
);
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
)) {
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
);
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
);
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
);
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_
;