Update Scintilla to version 3.4.4
[TortoiseGit.git] / ext / scintilla / src / LineMarker.cxx
blobb7adaa667850d43a5dc3841464bca4f1e8128730
1 // Scintilla source code edit control
2 /** @file LineMarker.cxx
3 ** Defines the look of a line marker in the margin.
4 **/
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.
8 #include <string.h>
9 #include <math.h>
11 #include <vector>
12 #include <map>
14 #include "Platform.h"
16 #include "Scintilla.h"
18 #include "StringCopy.h"
19 #include "XPM.h"
20 #include "LineMarker.h"
22 #ifdef SCI_NAMESPACE
23 using namespace Scintilla;
24 #endif
26 void LineMarker::SetXPM(const char *textForm) {
27 delete pxpm;
28 pxpm = new XPM(textForm);
29 markType = SC_MARK_PIXMAP;
32 void LineMarker::SetXPM(const char *const *linesForm) {
33 delete pxpm;
34 pxpm = new XPM(linesForm);
35 markType = SC_MARK_PIXMAP;
38 void LineMarker::SetRGBAImage(Point sizeRGBAImage, float scale, const unsigned char *pixelsRGBAImage) {
39 delete image;
40 image = new RGBAImage(static_cast<int>(sizeRGBAImage.x), static_cast<int>(sizeRGBAImage.y), scale, pixelsRGBAImage);
41 markType = SC_MARK_RGBAIMAGE;
44 static void DrawBox(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore, ColourDesired back) {
45 PRectangle rc = PRectangle::FromInts(
46 centreX - armSize,
47 centreY - armSize,
48 centreX + armSize + 1,
49 centreY + armSize + 1);
50 surface->RectangleDraw(rc, back, fore);
53 static void DrawCircle(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore, ColourDesired back) {
54 PRectangle rcCircle = PRectangle::FromInts(
55 centreX - armSize,
56 centreY - armSize,
57 centreX + armSize + 1,
58 centreY + armSize + 1);
59 surface->Ellipse(rcCircle, back, fore);
62 static void DrawPlus(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore) {
63 PRectangle rcV = PRectangle::FromInts(centreX, centreY - armSize + 2, centreX + 1, centreY + armSize - 2 + 1);
64 surface->FillRectangle(rcV, fore);
65 PRectangle rcH = PRectangle::FromInts(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY + 1);
66 surface->FillRectangle(rcH, fore);
69 static void DrawMinus(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore) {
70 PRectangle rcH = PRectangle::FromInts(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY + 1);
71 surface->FillRectangle(rcH, fore);
74 void LineMarker::Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharacter, typeOfFold tFold, int marginStyle) const {
75 ColourDesired head = back;
76 ColourDesired body = back;
77 ColourDesired tail = back;
79 switch (tFold) {
80 case LineMarker::head :
81 case LineMarker::headWithTail :
82 head = backSelected;
83 tail = backSelected;
84 break;
85 case LineMarker::body :
86 head = backSelected;
87 body = backSelected;
88 break;
89 case LineMarker::tail :
90 body = backSelected;
91 tail = backSelected;
92 break;
93 default :
94 // LineMarker::undefined
95 break;
98 if ((markType == SC_MARK_PIXMAP) && (pxpm)) {
99 pxpm->Draw(surface, rcWhole);
100 return;
102 if ((markType == SC_MARK_RGBAIMAGE) && (image)) {
103 // Make rectangle just large enough to fit image centred on centre of rcWhole
104 PRectangle rcImage;
105 rcImage.top = ((rcWhole.top + rcWhole.bottom) - image->GetScaledHeight()) / 2;
106 rcImage.bottom = rcImage.top + image->GetScaledHeight();
107 rcImage.left = ((rcWhole.left + rcWhole.right) - image->GetScaledWidth()) / 2;
108 rcImage.right = rcImage.left + image->GetScaledWidth();
109 surface->DrawRGBAImage(rcImage, image->GetWidth(), image->GetHeight(), image->Pixels());
110 return;
112 // Restrict most shapes a bit
113 PRectangle rc = rcWhole;
114 rc.top++;
115 rc.bottom--;
116 int minDim = Platform::Minimum(static_cast<int>(rc.Width()), static_cast<int>(rc.Height()));
117 minDim--; // Ensure does not go beyond edge
118 int centreX = static_cast<int>(floor((rc.right + rc.left) / 2.0));
119 int centreY = static_cast<int>(floor((rc.bottom + rc.top) / 2.0));
120 int dimOn2 = minDim / 2;
121 int dimOn4 = minDim / 4;
122 int blobSize = dimOn2-1;
123 int armSize = dimOn2-2;
124 if (marginStyle == SC_MARGIN_NUMBER || marginStyle == SC_MARGIN_TEXT || marginStyle == SC_MARGIN_RTEXT) {
125 // On textual margins move marker to the left to try to avoid overlapping the text
126 centreX = static_cast<int>(rc.left) + dimOn2 + 1;
128 if (markType == SC_MARK_ROUNDRECT) {
129 PRectangle rcRounded = rc;
130 rcRounded.left = rc.left + 1;
131 rcRounded.right = rc.right - 1;
132 surface->RoundedRectangle(rcRounded, fore, back);
133 } else if (markType == SC_MARK_CIRCLE) {
134 PRectangle rcCircle = PRectangle::FromInts(
135 centreX - dimOn2,
136 centreY - dimOn2,
137 centreX + dimOn2,
138 centreY + dimOn2);
139 surface->Ellipse(rcCircle, fore, back);
140 } else if (markType == SC_MARK_ARROW) {
141 Point pts[] = {
142 Point::FromInts(centreX - dimOn4, centreY - dimOn2),
143 Point::FromInts(centreX - dimOn4, centreY + dimOn2),
144 Point::FromInts(centreX + dimOn2 - dimOn4, centreY),
146 surface->Polygon(pts, ELEMENTS(pts), fore, back);
148 } else if (markType == SC_MARK_ARROWDOWN) {
149 Point pts[] = {
150 Point::FromInts(centreX - dimOn2, centreY - dimOn4),
151 Point::FromInts(centreX + dimOn2, centreY - dimOn4),
152 Point::FromInts(centreX, centreY + dimOn2 - dimOn4),
154 surface->Polygon(pts, ELEMENTS(pts), fore, back);
156 } else if (markType == SC_MARK_PLUS) {
157 Point pts[] = {
158 Point::FromInts(centreX - armSize, centreY - 1),
159 Point::FromInts(centreX - 1, centreY - 1),
160 Point::FromInts(centreX - 1, centreY - armSize),
161 Point::FromInts(centreX + 1, centreY - armSize),
162 Point::FromInts(centreX + 1, centreY - 1),
163 Point::FromInts(centreX + armSize, centreY -1),
164 Point::FromInts(centreX + armSize, centreY +1),
165 Point::FromInts(centreX + 1, centreY + 1),
166 Point::FromInts(centreX + 1, centreY + armSize),
167 Point::FromInts(centreX - 1, centreY + armSize),
168 Point::FromInts(centreX - 1, centreY + 1),
169 Point::FromInts(centreX - armSize, centreY + 1),
171 surface->Polygon(pts, ELEMENTS(pts), fore, back);
173 } else if (markType == SC_MARK_MINUS) {
174 Point pts[] = {
175 Point::FromInts(centreX - armSize, centreY - 1),
176 Point::FromInts(centreX + armSize, centreY -1),
177 Point::FromInts(centreX + armSize, centreY +1),
178 Point::FromInts(centreX - armSize, centreY + 1),
180 surface->Polygon(pts, ELEMENTS(pts), fore, back);
182 } else if (markType == SC_MARK_SMALLRECT) {
183 PRectangle rcSmall;
184 rcSmall.left = rc.left + 1;
185 rcSmall.top = rc.top + 2;
186 rcSmall.right = rc.right - 1;
187 rcSmall.bottom = rc.bottom - 2;
188 surface->RectangleDraw(rcSmall, fore, back);
190 } else if (markType == SC_MARK_EMPTY || markType == SC_MARK_BACKGROUND ||
191 markType == SC_MARK_UNDERLINE || markType == SC_MARK_AVAILABLE) {
192 // An invisible marker so don't draw anything
194 } else if (markType == SC_MARK_VLINE) {
195 surface->PenColour(body);
196 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
197 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
199 } else if (markType == SC_MARK_LCORNER) {
200 surface->PenColour(tail);
201 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
202 surface->LineTo(centreX, centreY);
203 surface->LineTo(static_cast<int>(rc.right) - 1, centreY);
205 } else if (markType == SC_MARK_TCORNER) {
206 surface->PenColour(tail);
207 surface->MoveTo(centreX, centreY);
208 surface->LineTo(static_cast<int>(rc.right) - 1, centreY);
210 surface->PenColour(body);
211 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
212 surface->LineTo(centreX, centreY + 1);
214 surface->PenColour(head);
215 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
217 } else if (markType == SC_MARK_LCORNERCURVE) {
218 surface->PenColour(tail);
219 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
220 surface->LineTo(centreX, centreY-3);
221 surface->LineTo(centreX+3, centreY);
222 surface->LineTo(static_cast<int>(rc.right) - 1, centreY);
224 } else if (markType == SC_MARK_TCORNERCURVE) {
225 surface->PenColour(tail);
226 surface->MoveTo(centreX, centreY-3);
227 surface->LineTo(centreX+3, centreY);
228 surface->LineTo(static_cast<int>(rc.right) - 1, centreY);
230 surface->PenColour(body);
231 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
232 surface->LineTo(centreX, centreY-2);
234 surface->PenColour(head);
235 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
237 } else if (markType == SC_MARK_BOXPLUS) {
238 DrawBox(surface, centreX, centreY, blobSize, fore, head);
239 DrawPlus(surface, centreX, centreY, blobSize, tail);
241 } else if (markType == SC_MARK_BOXPLUSCONNECTED) {
242 if (tFold == LineMarker::headWithTail)
243 surface->PenColour(tail);
244 else
245 surface->PenColour(body);
246 surface->MoveTo(centreX, centreY + blobSize);
247 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
249 surface->PenColour(body);
250 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
251 surface->LineTo(centreX, centreY - blobSize);
253 DrawBox(surface, centreX, centreY, blobSize, fore, head);
254 DrawPlus(surface, centreX, centreY, blobSize, tail);
256 if (tFold == LineMarker::body) {
257 surface->PenColour(tail);
258 surface->MoveTo(centreX + 1, centreY + blobSize);
259 surface->LineTo(centreX + blobSize + 1, centreY + blobSize);
261 surface->MoveTo(centreX + blobSize, centreY + blobSize);
262 surface->LineTo(centreX + blobSize, centreY - blobSize);
264 surface->MoveTo(centreX + 1, centreY - blobSize);
265 surface->LineTo(centreX + blobSize + 1, centreY - blobSize);
267 } else if (markType == SC_MARK_BOXMINUS) {
268 DrawBox(surface, centreX, centreY, blobSize, fore, head);
269 DrawMinus(surface, centreX, centreY, blobSize, tail);
271 surface->PenColour(head);
272 surface->MoveTo(centreX, centreY + blobSize);
273 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
275 } else if (markType == SC_MARK_BOXMINUSCONNECTED) {
276 DrawBox(surface, centreX, centreY, blobSize, fore, head);
277 DrawMinus(surface, centreX, centreY, blobSize, tail);
279 surface->PenColour(head);
280 surface->MoveTo(centreX, centreY + blobSize);
281 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
283 surface->PenColour(body);
284 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
285 surface->LineTo(centreX, centreY - blobSize);
287 if (tFold == LineMarker::body) {
288 surface->PenColour(tail);
289 surface->MoveTo(centreX + 1, centreY + blobSize);
290 surface->LineTo(centreX + blobSize + 1, centreY + blobSize);
292 surface->MoveTo(centreX + blobSize, centreY + blobSize);
293 surface->LineTo(centreX + blobSize, centreY - blobSize);
295 surface->MoveTo(centreX + 1, centreY - blobSize);
296 surface->LineTo(centreX + blobSize + 1, centreY - blobSize);
298 } else if (markType == SC_MARK_CIRCLEPLUS) {
299 DrawCircle(surface, centreX, centreY, blobSize, fore, head);
300 DrawPlus(surface, centreX, centreY, blobSize, tail);
302 } else if (markType == SC_MARK_CIRCLEPLUSCONNECTED) {
303 if (tFold == LineMarker::headWithTail)
304 surface->PenColour(tail);
305 else
306 surface->PenColour(body);
307 surface->MoveTo(centreX, centreY + blobSize);
308 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
310 surface->PenColour(body);
311 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
312 surface->LineTo(centreX, centreY - blobSize);
314 DrawCircle(surface, centreX, centreY, blobSize, fore, head);
315 DrawPlus(surface, centreX, centreY, blobSize, tail);
317 } else if (markType == SC_MARK_CIRCLEMINUS) {
318 surface->PenColour(head);
319 surface->MoveTo(centreX, centreY + blobSize);
320 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
322 DrawCircle(surface, centreX, centreY, blobSize, fore, head);
323 DrawMinus(surface, centreX, centreY, blobSize, tail);
325 } else if (markType == SC_MARK_CIRCLEMINUSCONNECTED) {
326 surface->PenColour(head);
327 surface->MoveTo(centreX, centreY + blobSize);
328 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
330 surface->PenColour(body);
331 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
332 surface->LineTo(centreX, centreY - blobSize);
334 DrawCircle(surface, centreX, centreY, blobSize, fore, head);
335 DrawMinus(surface, centreX, centreY, blobSize, tail);
337 } else if (markType >= SC_MARK_CHARACTER) {
338 char character[1];
339 character[0] = static_cast<char>(markType - SC_MARK_CHARACTER);
340 XYPOSITION width = surface->WidthText(fontForCharacter, character, 1);
341 rc.left += (rc.Width() - width) / 2;
342 rc.right = rc.left + width;
343 surface->DrawTextClipped(rc, fontForCharacter, rc.bottom - 2,
344 character, 1, fore, back);
346 } else if (markType == SC_MARK_DOTDOTDOT) {
347 XYPOSITION right = static_cast<XYPOSITION>(centreX - 6);
348 for (int b=0; b<3; b++) {
349 PRectangle rcBlob(right, rc.bottom - 4, right + 2, rc.bottom-2);
350 surface->FillRectangle(rcBlob, fore);
351 right += 5.0f;
353 } else if (markType == SC_MARK_ARROWS) {
354 surface->PenColour(fore);
355 int right = centreX - 2;
356 const int armLength = dimOn2 - 1;
357 for (int b = 0; b<3; b++) {
358 surface->MoveTo(right, centreY);
359 surface->LineTo(right - armLength, centreY - armLength);
360 surface->MoveTo(right, centreY);
361 surface->LineTo(right - armLength, centreY + armLength);
362 right += 4;
364 } else if (markType == SC_MARK_SHORTARROW) {
365 Point pts[] = {
366 Point::FromInts(centreX, centreY + dimOn2),
367 Point::FromInts(centreX + dimOn2, centreY),
368 Point::FromInts(centreX, centreY - dimOn2),
369 Point::FromInts(centreX, centreY - dimOn4),
370 Point::FromInts(centreX - dimOn4, centreY - dimOn4),
371 Point::FromInts(centreX - dimOn4, centreY + dimOn4),
372 Point::FromInts(centreX, centreY + dimOn4),
373 Point::FromInts(centreX, centreY + dimOn2),
375 surface->Polygon(pts, ELEMENTS(pts), fore, back);
376 } else if (markType == SC_MARK_LEFTRECT) {
377 PRectangle rcLeft = rcWhole;
378 rcLeft.right = rcLeft.left + 4;
379 surface->FillRectangle(rcLeft, back);
380 } else if (markType == SC_MARK_BOOKMARK) {
381 int halfHeight = minDim / 3;
382 Point pts[] = {
383 Point::FromInts(static_cast<int>(rc.left), centreY-halfHeight),
384 Point::FromInts(static_cast<int>(rc.right) - 3, centreY - halfHeight),
385 Point::FromInts(static_cast<int>(rc.right) - 3 - halfHeight, centreY),
386 Point::FromInts(static_cast<int>(rc.right) - 3, centreY + halfHeight),
387 Point::FromInts(static_cast<int>(rc.left), centreY + halfHeight),
389 surface->Polygon(pts, ELEMENTS(pts), fore, back);
390 } else { // SC_MARK_FULLRECT
391 surface->FillRectangle(rcWhole, back);