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.
14 #include "Scintilla.h"
15 #include "Indicator.h"
19 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(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
) {
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);
41 surface
->MoveTo(x
, static_cast<int>(rc
.top
) + y
);
43 if ((x
+ 2) > xLast
) {
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
++) {
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
);
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;
76 while (x
< rc
.right
) {
77 surface
->LineTo(x
- 1, static_cast<int>(rc
.top
) + y
);
79 surface
->LineTo(x
, static_cast<int>(rc
.top
) + y
);
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);
91 surface
->MoveTo(x
, ymid
);
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);
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
);
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
)) {
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
);
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
);
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
);
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_
;