1 // Scintilla source code edit control
2 /** @file LineMarker.cxx
3 ** Defines the look of a line marker in the margin .
5 // Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
15 #include "Scintilla.h"
17 #include "LineMarker.h"
20 using namespace Scintilla
;
23 void LineMarker::SetXPM(const char *textForm
) {
25 pxpm
= new XPM(textForm
);
26 markType
= SC_MARK_PIXMAP
;
29 void LineMarker::SetXPM(const char *const *linesForm
) {
31 pxpm
= new XPM(linesForm
);
32 markType
= SC_MARK_PIXMAP
;
35 void LineMarker::SetRGBAImage(Point sizeRGBAImage
, const unsigned char *pixelsRGBAImage
) {
37 image
= new RGBAImage(sizeRGBAImage
.x
, sizeRGBAImage
.y
, pixelsRGBAImage
);
38 markType
= SC_MARK_RGBAIMAGE
;
41 static void DrawBox(Surface
*surface
, int centreX
, int centreY
, int armSize
, ColourDesired fore
, ColourDesired back
) {
43 rc
.left
= centreX
- armSize
;
44 rc
.top
= centreY
- armSize
;
45 rc
.right
= centreX
+ armSize
+ 1;
46 rc
.bottom
= centreY
+ armSize
+ 1;
47 surface
->RectangleDraw(rc
, back
, fore
);
50 static void DrawCircle(Surface
*surface
, int centreX
, int centreY
, int armSize
, ColourDesired fore
, ColourDesired back
) {
52 rcCircle
.left
= centreX
- armSize
;
53 rcCircle
.top
= centreY
- armSize
;
54 rcCircle
.right
= centreX
+ armSize
+ 1;
55 rcCircle
.bottom
= centreY
+ armSize
+ 1;
56 surface
->Ellipse(rcCircle
, back
, fore
);
59 static void DrawPlus(Surface
*surface
, int centreX
, int centreY
, int armSize
, ColourDesired fore
) {
60 PRectangle
rcV(centreX
, centreY
- armSize
+ 2, centreX
+ 1, centreY
+ armSize
- 2 + 1);
61 surface
->FillRectangle(rcV
, fore
);
62 PRectangle
rcH(centreX
- armSize
+ 2, centreY
, centreX
+ armSize
- 2 + 1, centreY
+1);
63 surface
->FillRectangle(rcH
, fore
);
66 static void DrawMinus(Surface
*surface
, int centreX
, int centreY
, int armSize
, ColourDesired fore
) {
67 PRectangle
rcH(centreX
- armSize
+ 2, centreY
, centreX
+ armSize
- 2 + 1, centreY
+1);
68 surface
->FillRectangle(rcH
, fore
);
71 void LineMarker::Draw(Surface
*surface
, PRectangle
&rcWhole
, Font
&fontForCharacter
, typeOfFold tFold
, int marginStyle
) {
72 ColourDesired head
= back
;
73 ColourDesired body
= back
;
74 ColourDesired tail
= back
;
77 case LineMarker::head
:
78 case LineMarker::headWithTail
:
82 case LineMarker::body
:
86 case LineMarker::tail
:
91 // LineMarker::undefined
95 if ((markType
== SC_MARK_PIXMAP
) && (pxpm
)) {
96 pxpm
->Draw(surface
, rcWhole
);
99 if ((markType
== SC_MARK_RGBAIMAGE
) && (image
)) {
100 // Make rectangle just large enough to fit image centred on centre of rcWhole
102 rcImage
.top
= static_cast<int>(((rcWhole
.top
+ rcWhole
.bottom
) - image
->GetHeight()) / 2);
103 rcImage
.bottom
= rcImage
.top
+ image
->GetHeight();
104 rcImage
.left
= static_cast<int>(((rcWhole
.left
+ rcWhole
.right
) - image
->GetWidth()) / 2);
105 rcImage
.right
= rcImage
.left
+ image
->GetWidth();
106 surface
->DrawRGBAImage(rcImage
, image
->GetWidth(), image
->GetHeight(), image
->Pixels());
109 // Restrict most shapes a bit
110 PRectangle rc
= rcWhole
;
113 int minDim
= Platform::Minimum(rc
.Width(), rc
.Height());
114 minDim
--; // Ensure does not go beyond edge
115 int centreX
= (rc
.right
+ rc
.left
) / 2;
116 int centreY
= (rc
.bottom
+ rc
.top
) / 2;
117 int dimOn2
= minDim
/ 2;
118 int dimOn4
= minDim
/ 4;
119 int blobSize
= dimOn2
-1;
120 int armSize
= dimOn2
-2;
121 if (marginStyle
== SC_MARGIN_NUMBER
|| marginStyle
== SC_MARGIN_TEXT
|| marginStyle
== SC_MARGIN_RTEXT
) {
122 // On textual margins move marker to the left to try to avoid overlapping the text
123 centreX
= rc
.left
+ dimOn2
+ 1;
125 if (markType
== SC_MARK_ROUNDRECT
) {
126 PRectangle rcRounded
= rc
;
127 rcRounded
.left
= rc
.left
+ 1;
128 rcRounded
.right
= rc
.right
- 1;
129 surface
->RoundedRectangle(rcRounded
, fore
, back
);
130 } else if (markType
== SC_MARK_CIRCLE
) {
132 rcCircle
.left
= centreX
- dimOn2
;
133 rcCircle
.top
= centreY
- dimOn2
;
134 rcCircle
.right
= centreX
+ dimOn2
;
135 rcCircle
.bottom
= centreY
+ dimOn2
;
136 surface
->Ellipse(rcCircle
, fore
, back
);
137 } else if (markType
== SC_MARK_ARROW
) {
139 Point(centreX
- dimOn4
, centreY
- dimOn2
),
140 Point(centreX
- dimOn4
, centreY
+ dimOn2
),
141 Point(centreX
+ dimOn2
- dimOn4
, centreY
),
143 surface
->Polygon(pts
, sizeof(pts
) / sizeof(pts
[0]),
146 } else if (markType
== SC_MARK_ARROWDOWN
) {
148 Point(centreX
- dimOn2
, centreY
- dimOn4
),
149 Point(centreX
+ dimOn2
, centreY
- dimOn4
),
150 Point(centreX
, centreY
+ dimOn2
- dimOn4
),
152 surface
->Polygon(pts
, sizeof(pts
) / sizeof(pts
[0]),
155 } else if (markType
== SC_MARK_PLUS
) {
157 Point(centreX
- armSize
, centreY
- 1),
158 Point(centreX
- 1, centreY
- 1),
159 Point(centreX
- 1, centreY
- armSize
),
160 Point(centreX
+ 1, centreY
- armSize
),
161 Point(centreX
+ 1, centreY
- 1),
162 Point(centreX
+ armSize
, centreY
-1),
163 Point(centreX
+ armSize
, centreY
+1),
164 Point(centreX
+ 1, centreY
+ 1),
165 Point(centreX
+ 1, centreY
+ armSize
),
166 Point(centreX
- 1, centreY
+ armSize
),
167 Point(centreX
- 1, centreY
+ 1),
168 Point(centreX
- armSize
, centreY
+ 1),
170 surface
->Polygon(pts
, sizeof(pts
) / sizeof(pts
[0]),
173 } else if (markType
== SC_MARK_MINUS
) {
175 Point(centreX
- armSize
, centreY
- 1),
176 Point(centreX
+ armSize
, centreY
-1),
177 Point(centreX
+ armSize
, centreY
+1),
178 Point(centreX
- armSize
, centreY
+ 1),
180 surface
->Polygon(pts
, sizeof(pts
) / sizeof(pts
[0]),
183 } else if (markType
== SC_MARK_SMALLRECT
) {
185 rcSmall
.left
= rc
.left
+ 1;
186 rcSmall
.top
= rc
.top
+ 2;
187 rcSmall
.right
= rc
.right
- 1;
188 rcSmall
.bottom
= rc
.bottom
- 2;
189 surface
->RectangleDraw(rcSmall
, fore
, back
);
191 } else if (markType
== SC_MARK_EMPTY
|| markType
== SC_MARK_BACKGROUND
||
192 markType
== SC_MARK_UNDERLINE
|| markType
== SC_MARK_AVAILABLE
) {
193 // An invisible marker so don't draw anything
195 } else if (markType
== SC_MARK_VLINE
) {
196 surface
->PenColour(body
);
197 surface
->MoveTo(centreX
, rcWhole
.top
);
198 surface
->LineTo(centreX
, rcWhole
.bottom
);
200 } else if (markType
== SC_MARK_LCORNER
) {
201 surface
->PenColour(tail
);
202 surface
->MoveTo(centreX
, rcWhole
.top
);
203 surface
->LineTo(centreX
, centreY
);
204 surface
->LineTo(rc
.right
- 1, centreY
);
206 } else if (markType
== SC_MARK_TCORNER
) {
207 surface
->PenColour(tail
);
208 surface
->MoveTo(centreX
, centreY
);
209 surface
->LineTo(rc
.right
- 1, centreY
);
211 surface
->PenColour(body
);
212 surface
->MoveTo(centreX
, rcWhole
.top
);
213 surface
->LineTo(centreX
, centreY
+ 1);
215 surface
->PenColour(head
);
216 surface
->LineTo(centreX
, rcWhole
.bottom
);
218 } else if (markType
== SC_MARK_LCORNERCURVE
) {
219 surface
->PenColour(tail
);
220 surface
->MoveTo(centreX
, rcWhole
.top
);
221 surface
->LineTo(centreX
, centreY
-3);
222 surface
->LineTo(centreX
+3, centreY
);
223 surface
->LineTo(rc
.right
- 1, centreY
);
225 } else if (markType
== SC_MARK_TCORNERCURVE
) {
226 surface
->PenColour(tail
);
227 surface
->MoveTo(centreX
, centreY
-3);
228 surface
->LineTo(centreX
+3, centreY
);
229 surface
->LineTo(rc
.right
- 1, centreY
);
231 surface
->PenColour(body
);
232 surface
->MoveTo(centreX
, rcWhole
.top
);
233 surface
->LineTo(centreX
, centreY
-2);
235 surface
->PenColour(head
);
236 surface
->LineTo(centreX
, rcWhole
.bottom
);
238 } else if (markType
== SC_MARK_BOXPLUS
) {
239 DrawBox(surface
, centreX
, centreY
, blobSize
, fore
, head
);
240 DrawPlus(surface
, centreX
, centreY
, blobSize
, tail
);
242 } else if (markType
== SC_MARK_BOXPLUSCONNECTED
) {
243 if (tFold
== LineMarker::headWithTail
)
244 surface
->PenColour(tail
);
246 surface
->PenColour(body
);
247 surface
->MoveTo(centreX
, centreY
+ blobSize
);
248 surface
->LineTo(centreX
, rcWhole
.bottom
);
250 surface
->PenColour(body
);
251 surface
->MoveTo(centreX
, rcWhole
.top
);
252 surface
->LineTo(centreX
, centreY
- blobSize
);
254 DrawBox(surface
, centreX
, centreY
, blobSize
, fore
, head
);
255 DrawPlus(surface
, centreX
, centreY
, blobSize
, tail
);
257 if (tFold
== LineMarker::body
) {
258 surface
->PenColour(tail
);
259 surface
->MoveTo(centreX
+ 1, centreY
+ blobSize
);
260 surface
->LineTo(centreX
+ blobSize
+ 1, centreY
+ blobSize
);
262 surface
->MoveTo(centreX
+ blobSize
, centreY
+ blobSize
);
263 surface
->LineTo(centreX
+ blobSize
, centreY
- blobSize
);
265 surface
->MoveTo(centreX
+ 1, centreY
- blobSize
);
266 surface
->LineTo(centreX
+ blobSize
+ 1, centreY
- blobSize
);
268 } else if (markType
== SC_MARK_BOXMINUS
) {
269 DrawBox(surface
, centreX
, centreY
, blobSize
, fore
, head
);
270 DrawMinus(surface
, centreX
, centreY
, blobSize
, tail
);
272 surface
->PenColour(head
);
273 surface
->MoveTo(centreX
, centreY
+ blobSize
);
274 surface
->LineTo(centreX
, rcWhole
.bottom
);
276 } else if (markType
== SC_MARK_BOXMINUSCONNECTED
) {
277 DrawBox(surface
, centreX
, centreY
, blobSize
, fore
, head
);
278 DrawMinus(surface
, centreX
, centreY
, blobSize
, tail
);
280 surface
->PenColour(head
);
281 surface
->MoveTo(centreX
, centreY
+ blobSize
);
282 surface
->LineTo(centreX
, rcWhole
.bottom
);
284 surface
->PenColour(body
);
285 surface
->MoveTo(centreX
, rcWhole
.top
);
286 surface
->LineTo(centreX
, centreY
- blobSize
);
288 if (tFold
== LineMarker::body
) {
289 surface
->PenColour(tail
);
290 surface
->MoveTo(centreX
+ 1, centreY
+ blobSize
);
291 surface
->LineTo(centreX
+ blobSize
+ 1, centreY
+ blobSize
);
293 surface
->MoveTo(centreX
+ blobSize
, centreY
+ blobSize
);
294 surface
->LineTo(centreX
+ blobSize
, centreY
- blobSize
);
296 surface
->MoveTo(centreX
+ 1, centreY
- blobSize
);
297 surface
->LineTo(centreX
+ blobSize
+ 1, centreY
- blobSize
);
299 } else if (markType
== SC_MARK_CIRCLEPLUS
) {
300 DrawCircle(surface
, centreX
, centreY
, blobSize
, fore
, head
);
301 DrawPlus(surface
, centreX
, centreY
, blobSize
, tail
);
303 } else if (markType
== SC_MARK_CIRCLEPLUSCONNECTED
) {
304 if (tFold
== LineMarker::headWithTail
)
305 surface
->PenColour(tail
);
307 surface
->PenColour(body
);
308 surface
->MoveTo(centreX
, centreY
+ blobSize
);
309 surface
->LineTo(centreX
, rcWhole
.bottom
);
311 surface
->PenColour(body
);
312 surface
->MoveTo(centreX
, rcWhole
.top
);
313 surface
->LineTo(centreX
, centreY
- blobSize
);
315 DrawCircle(surface
, centreX
, centreY
, blobSize
, fore
, head
);
316 DrawPlus(surface
, centreX
, centreY
, blobSize
, tail
);
318 } else if (markType
== SC_MARK_CIRCLEMINUS
) {
319 DrawCircle(surface
, centreX
, centreY
, blobSize
, fore
, head
);
320 DrawMinus(surface
, centreX
, centreY
, blobSize
, tail
);
322 surface
->PenColour(head
);
323 surface
->MoveTo(centreX
, centreY
+ blobSize
);
324 surface
->LineTo(centreX
, rcWhole
.bottom
);
326 } else if (markType
== SC_MARK_CIRCLEMINUSCONNECTED
) {
327 DrawCircle(surface
, centreX
, centreY
, blobSize
, fore
, head
);
328 DrawMinus(surface
, centreX
, centreY
, blobSize
, tail
);
330 surface
->PenColour(head
);
331 surface
->MoveTo(centreX
, centreY
+ blobSize
);
332 surface
->LineTo(centreX
, rcWhole
.bottom
);
334 surface
->PenColour(body
);
335 surface
->MoveTo(centreX
, rcWhole
.top
);
336 surface
->LineTo(centreX
, centreY
- blobSize
);
338 } else if (markType
>= SC_MARK_CHARACTER
) {
340 character
[0] = static_cast<char>(markType
- SC_MARK_CHARACTER
);
341 XYPOSITION width
= surface
->WidthText(fontForCharacter
, character
, 1);
342 rc
.left
+= (rc
.Width() - width
) / 2;
343 rc
.right
= rc
.left
+ width
;
344 surface
->DrawTextClipped(rc
, fontForCharacter
, rc
.bottom
- 2,
345 character
, 1, fore
, back
);
347 } else if (markType
== SC_MARK_DOTDOTDOT
) {
348 int right
= centreX
- 6;
349 for (int b
=0; b
<3; b
++) {
350 PRectangle
rcBlob(right
, rc
.bottom
- 4, right
+ 2, rc
.bottom
-2);
351 surface
->FillRectangle(rcBlob
, fore
);
354 } else if (markType
== SC_MARK_ARROWS
) {
355 surface
->PenColour(fore
);
356 int right
= centreX
- 2;
357 for (int b
=0; b
<3; b
++) {
358 surface
->MoveTo(right
- 4, centreY
- 4);
359 surface
->LineTo(right
, centreY
);
360 surface
->LineTo(right
- 5, centreY
+ 5);
363 } else if (markType
== SC_MARK_SHORTARROW
) {
365 Point(centreX
, centreY
+ dimOn2
),
366 Point(centreX
+ dimOn2
, centreY
),
367 Point(centreX
, centreY
- dimOn2
),
368 Point(centreX
, centreY
- dimOn4
),
369 Point(centreX
- dimOn4
, centreY
- dimOn4
),
370 Point(centreX
- dimOn4
, centreY
+ dimOn4
),
371 Point(centreX
, centreY
+ dimOn4
),
372 Point(centreX
, centreY
+ dimOn2
),
374 surface
->Polygon(pts
, sizeof(pts
) / sizeof(pts
[0]),
376 } else if (markType
== SC_MARK_LEFTRECT
) {
377 PRectangle rcLeft
= rcWhole
;
378 rcLeft
.right
= rcLeft
.left
+ 4;
379 surface
->FillRectangle(rcLeft
, back
);
380 } else { // SC_MARK_FULLRECT
381 surface
->FillRectangle(rcWhole
, back
);