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.
13 #include "Scintilla.h"
15 #include "Indicator.h"
18 using namespace Scintilla
;
21 static PRectangle
PixelGridAlign(const PRectangle
&rc
) {
22 // Move left and right side to nearest pixel to avoid blurry visuals
23 return PRectangle::FromInts(int(rc
.left
+ 0.5), int(rc
.top
), int(rc
.right
+ 0.5), int(rc
.bottom
));
26 void Indicator::Draw(Surface
*surface
, const PRectangle
&rc
, const PRectangle
&rcLine
) {
27 surface
->PenColour(fore
);
28 int ymid
= static_cast<int>(rc
.bottom
+ rc
.top
) / 2;
29 if (style
== INDIC_SQUIGGLE
) {
30 int x
= int(rc
.left
+0.5);
31 int xLast
= int(rc
.right
+0.5);
33 surface
->MoveTo(x
, static_cast<int>(rc
.top
) + y
);
35 if ((x
+ 2) > xLast
) {
43 surface
->LineTo(x
, static_cast<int>(rc
.top
) + y
);
45 } else if (style
== INDIC_SQUIGGLEPIXMAP
) {
46 PRectangle rcSquiggle
= PixelGridAlign(rc
);
48 int width
= Platform::Minimum(4000, static_cast<int>(rcSquiggle
.Width()));
49 RGBAImage
image(width
, 3, 1.0, 0);
50 enum { alphaFull
= 0xff, alphaSide
= 0x2f, alphaSide2
=0x5f };
51 for (int x
= 0; x
< width
; x
++) {
53 // Two halfway columns have a full pixel in middle flanked by light pixels
54 image
.SetPixel(x
, 0, fore
, alphaSide
);
55 image
.SetPixel(x
, 1, fore
, alphaFull
);
56 image
.SetPixel(x
, 2, fore
, alphaSide
);
58 // Extreme columns have a full pixel at bottom or top and a mid-tone pixel in centre
59 image
.SetPixel(x
, (x
%4) ? 0 : 2, fore
, alphaFull
);
60 image
.SetPixel(x
, 1, fore
, alphaSide2
);
63 surface
->DrawRGBAImage(rcSquiggle
, image
.GetWidth(), image
.GetHeight(), image
.Pixels());
64 } else if (style
== INDIC_SQUIGGLELOW
) {
65 surface
->MoveTo(static_cast<int>(rc
.left
), static_cast<int>(rc
.top
));
66 int x
= static_cast<int>(rc
.left
) + 3;
68 while (x
< rc
.right
) {
69 surface
->LineTo(x
- 1, static_cast<int>(rc
.top
) + y
);
71 surface
->LineTo(x
, static_cast<int>(rc
.top
) + y
);
74 surface
->LineTo(static_cast<int>(rc
.right
), static_cast<int>(rc
.top
) + y
); // Finish the line
75 } else if (style
== INDIC_TT
) {
76 surface
->MoveTo(static_cast<int>(rc
.left
), ymid
);
77 int x
= static_cast<int>(rc
.left
) + 5;
78 while (x
< rc
.right
) {
79 surface
->LineTo(x
, ymid
);
80 surface
->MoveTo(x
-3, ymid
);
81 surface
->LineTo(x
-3, ymid
+2);
83 surface
->MoveTo(x
, ymid
);
86 surface
->LineTo(static_cast<int>(rc
.right
), ymid
); // Finish the line
87 if (x
- 3 <= rc
.right
) {
88 surface
->MoveTo(x
-3, ymid
);
89 surface
->LineTo(x
-3, ymid
+2);
91 } else if (style
== INDIC_DIAGONAL
) {
92 int x
= static_cast<int>(rc
.left
);
93 while (x
< rc
.right
) {
94 surface
->MoveTo(x
, static_cast<int>(rc
.top
) + 2);
96 int endY
= static_cast<int>(rc
.top
) - 1;
97 if (endX
> rc
.right
) {
98 endY
+= endX
- static_cast<int>(rc
.right
);
99 endX
= static_cast<int>(rc
.right
);
101 surface
->LineTo(endX
, endY
);
104 } else if (style
== INDIC_STRIKE
) {
105 surface
->MoveTo(static_cast<int>(rc
.left
), static_cast<int>(rc
.top
) - 4);
106 surface
->LineTo(static_cast<int>(rc
.right
), static_cast<int>(rc
.top
) - 4);
107 } else if (style
== INDIC_HIDDEN
) {
109 } else if (style
== INDIC_BOX
) {
110 surface
->MoveTo(static_cast<int>(rc
.left
), ymid
+ 1);
111 surface
->LineTo(static_cast<int>(rc
.right
), ymid
+ 1);
112 surface
->LineTo(static_cast<int>(rc
.right
), static_cast<int>(rcLine
.top
) + 1);
113 surface
->LineTo(static_cast<int>(rc
.left
), static_cast<int>(rcLine
.top
) + 1);
114 surface
->LineTo(static_cast<int>(rc
.left
), ymid
+ 1);
115 } else if (style
== INDIC_ROUNDBOX
|| style
== INDIC_STRAIGHTBOX
) {
116 PRectangle rcBox
= rcLine
;
117 rcBox
.top
= rcLine
.top
+ 1;
118 rcBox
.left
= rc
.left
;
119 rcBox
.right
= rc
.right
;
120 surface
->AlphaRectangle(rcBox
, (style
== INDIC_ROUNDBOX
) ? 1 : 0, fore
, fillAlpha
, fore
, outlineAlpha
, 0);
121 } else if (style
== INDIC_DOTBOX
) {
122 PRectangle rcBox
= PixelGridAlign(rc
);
123 rcBox
.top
= rcLine
.top
+ 1;
124 rcBox
.bottom
= rcLine
.bottom
;
125 // Cap width at 4000 to avoid large allocations when mistakes made
126 int width
= Platform::Minimum(static_cast<int>(rcBox
.Width()), 4000);
127 RGBAImage
image(width
, static_cast<int>(rcBox
.Height()), 1.0, 0);
128 // Draw horizontal lines top and bottom
129 for (int x
=0; x
<width
; x
++) {
130 for (int y
= 0; y
<static_cast<int>(rcBox
.Height()); y
+= static_cast<int>(rcBox
.Height()) - 1) {
131 image
.SetPixel(x
, y
, fore
, ((x
+ y
) % 2) ? outlineAlpha
: fillAlpha
);
134 // Draw vertical lines left and right
135 for (int y
= 1; y
<static_cast<int>(rcBox
.Height()); y
++) {
136 for (int x
=0; x
<width
; x
+= width
-1) {
137 image
.SetPixel(x
, y
, fore
, ((x
+ y
) % 2) ? outlineAlpha
: fillAlpha
);
140 surface
->DrawRGBAImage(rcBox
, image
.GetWidth(), image
.GetHeight(), image
.Pixels());
141 } else if (style
== INDIC_DASH
) {
142 int x
= static_cast<int>(rc
.left
);
143 while (x
< rc
.right
) {
144 surface
->MoveTo(x
, ymid
);
145 surface
->LineTo(Platform::Minimum(x
+ 4, static_cast<int>(rc
.right
)), ymid
);
148 } else if (style
== INDIC_DOTS
) {
149 int x
= static_cast<int>(rc
.left
);
150 while (x
< static_cast<int>(rc
.right
)) {
151 PRectangle rcDot
= PRectangle::FromInts(x
, ymid
, x
+ 1, ymid
+ 1);
152 surface
->FillRectangle(rcDot
, fore
);
155 } else if (style
== INDIC_COMPOSITIONTHICK
) {
156 PRectangle
rcComposition(rc
.left
+1, rcLine
.bottom
-2, rc
.right
-1, rcLine
.bottom
);
157 surface
->FillRectangle(rcComposition
, fore
);
158 } else { // Either INDIC_PLAIN or unknown
159 surface
->MoveTo(static_cast<int>(rc
.left
), ymid
);
160 surface
->LineTo(static_cast<int>(rc
.right
), ymid
);