Update Tortoise.pot
[TortoiseGit.git] / ext / scintilla / src / LineMarker.cxx
blob40c5ae6dca1a2bdadeefe6864f96150956adac10
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 <cstring>
9 #include <cmath>
11 #include <stdexcept>
12 #include <vector>
13 #include <map>
14 #include <memory>
16 #include "Platform.h"
18 #include "Scintilla.h"
20 #include "StringCopy.h"
21 #include "XPM.h"
22 #include "LineMarker.h"
24 #ifdef SCI_NAMESPACE
25 using namespace Scintilla;
26 #endif
28 void LineMarker::SetXPM(const char *textForm) {
29 pxpm.reset(new XPM(textForm));
30 markType = SC_MARK_PIXMAP;
33 void LineMarker::SetXPM(const char *const *linesForm) {
34 pxpm.reset(new XPM(linesForm));
35 markType = SC_MARK_PIXMAP;
38 void LineMarker::SetRGBAImage(Point sizeRGBAImage, float scale, const unsigned char *pixelsRGBAImage) {
39 image.reset(new RGBAImage(static_cast<int>(sizeRGBAImage.x), static_cast<int>(sizeRGBAImage.y), scale, pixelsRGBAImage));
40 markType = SC_MARK_RGBAIMAGE;
43 static void DrawBox(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore, ColourDesired back) {
44 PRectangle rc = PRectangle::FromInts(
45 centreX - armSize,
46 centreY - armSize,
47 centreX + armSize + 1,
48 centreY + armSize + 1);
49 surface->RectangleDraw(rc, back, fore);
52 static void DrawCircle(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore, ColourDesired back) {
53 PRectangle rcCircle = PRectangle::FromInts(
54 centreX - armSize,
55 centreY - armSize,
56 centreX + armSize + 1,
57 centreY + armSize + 1);
58 surface->Ellipse(rcCircle, back, fore);
61 static void DrawPlus(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore) {
62 PRectangle rcV = PRectangle::FromInts(centreX, centreY - armSize + 2, centreX + 1, centreY + armSize - 2 + 1);
63 surface->FillRectangle(rcV, fore);
64 PRectangle rcH = PRectangle::FromInts(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY + 1);
65 surface->FillRectangle(rcH, fore);
68 static void DrawMinus(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore) {
69 PRectangle rcH = PRectangle::FromInts(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY + 1);
70 surface->FillRectangle(rcH, fore);
73 void LineMarker::Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharacter, typeOfFold tFold, int marginStyle) const {
74 if (customDraw) {
75 customDraw(surface, rcWhole, fontForCharacter, tFold, marginStyle, this);
76 return;
79 ColourDesired colourHead = back;
80 ColourDesired colourBody = back;
81 ColourDesired colourTail = back;
83 switch (tFold) {
84 case LineMarker::head :
85 case LineMarker::headWithTail :
86 colourHead = backSelected;
87 colourTail = backSelected;
88 break;
89 case LineMarker::body :
90 colourHead = backSelected;
91 colourBody = backSelected;
92 break;
93 case LineMarker::tail :
94 colourBody = backSelected;
95 colourTail = backSelected;
96 break;
97 default :
98 // LineMarker::undefined
99 break;
102 if ((markType == SC_MARK_PIXMAP) && (pxpm)) {
103 pxpm->Draw(surface, rcWhole);
104 return;
106 if ((markType == SC_MARK_RGBAIMAGE) && (image)) {
107 // Make rectangle just large enough to fit image centred on centre of rcWhole
108 PRectangle rcImage;
109 rcImage.top = ((rcWhole.top + rcWhole.bottom) - image->GetScaledHeight()) / 2;
110 rcImage.bottom = rcImage.top + image->GetScaledHeight();
111 rcImage.left = ((rcWhole.left + rcWhole.right) - image->GetScaledWidth()) / 2;
112 rcImage.right = rcImage.left + image->GetScaledWidth();
113 surface->DrawRGBAImage(rcImage, image->GetWidth(), image->GetHeight(), image->Pixels());
114 return;
116 // Restrict most shapes a bit
117 PRectangle rc = rcWhole;
118 rc.top++;
119 rc.bottom--;
120 int minDim = Platform::Minimum(static_cast<int>(rc.Width()), static_cast<int>(rc.Height()));
121 minDim--; // Ensure does not go beyond edge
122 int centreX = static_cast<int>(floor((rc.right + rc.left) / 2.0));
123 const int centreY = static_cast<int>(floor((rc.bottom + rc.top) / 2.0));
124 const int dimOn2 = minDim / 2;
125 const int dimOn4 = minDim / 4;
126 int blobSize = dimOn2-1;
127 const int armSize = dimOn2-2;
128 if (marginStyle == SC_MARGIN_NUMBER || marginStyle == SC_MARGIN_TEXT || marginStyle == SC_MARGIN_RTEXT) {
129 // On textual margins move marker to the left to try to avoid overlapping the text
130 centreX = static_cast<int>(rc.left) + dimOn2 + 1;
132 if (markType == SC_MARK_ROUNDRECT) {
133 PRectangle rcRounded = rc;
134 rcRounded.left = rc.left + 1;
135 rcRounded.right = rc.right - 1;
136 surface->RoundedRectangle(rcRounded, fore, back);
137 } else if (markType == SC_MARK_CIRCLE) {
138 PRectangle rcCircle = PRectangle::FromInts(
139 centreX - dimOn2,
140 centreY - dimOn2,
141 centreX + dimOn2,
142 centreY + dimOn2);
143 surface->Ellipse(rcCircle, fore, back);
144 } else if (markType == SC_MARK_ARROW) {
145 Point pts[] = {
146 Point::FromInts(centreX - dimOn4, centreY - dimOn2),
147 Point::FromInts(centreX - dimOn4, centreY + dimOn2),
148 Point::FromInts(centreX + dimOn2 - dimOn4, centreY),
150 surface->Polygon(pts, ELEMENTS(pts), fore, back);
152 } else if (markType == SC_MARK_ARROWDOWN) {
153 Point pts[] = {
154 Point::FromInts(centreX - dimOn2, centreY - dimOn4),
155 Point::FromInts(centreX + dimOn2, centreY - dimOn4),
156 Point::FromInts(centreX, centreY + dimOn2 - dimOn4),
158 surface->Polygon(pts, ELEMENTS(pts), fore, back);
160 } else if (markType == SC_MARK_PLUS) {
161 Point pts[] = {
162 Point::FromInts(centreX - armSize, centreY - 1),
163 Point::FromInts(centreX - 1, centreY - 1),
164 Point::FromInts(centreX - 1, centreY - armSize),
165 Point::FromInts(centreX + 1, centreY - armSize),
166 Point::FromInts(centreX + 1, centreY - 1),
167 Point::FromInts(centreX + armSize, centreY -1),
168 Point::FromInts(centreX + armSize, centreY +1),
169 Point::FromInts(centreX + 1, centreY + 1),
170 Point::FromInts(centreX + 1, centreY + armSize),
171 Point::FromInts(centreX - 1, centreY + armSize),
172 Point::FromInts(centreX - 1, centreY + 1),
173 Point::FromInts(centreX - armSize, centreY + 1),
175 surface->Polygon(pts, ELEMENTS(pts), fore, back);
177 } else if (markType == SC_MARK_MINUS) {
178 Point pts[] = {
179 Point::FromInts(centreX - armSize, centreY - 1),
180 Point::FromInts(centreX + armSize, centreY -1),
181 Point::FromInts(centreX + armSize, centreY +1),
182 Point::FromInts(centreX - armSize, centreY + 1),
184 surface->Polygon(pts, ELEMENTS(pts), fore, back);
186 } else if (markType == SC_MARK_SMALLRECT) {
187 PRectangle rcSmall;
188 rcSmall.left = rc.left + 1;
189 rcSmall.top = rc.top + 2;
190 rcSmall.right = rc.right - 1;
191 rcSmall.bottom = rc.bottom - 2;
192 surface->RectangleDraw(rcSmall, fore, back);
194 } else if (markType == SC_MARK_EMPTY || markType == SC_MARK_BACKGROUND ||
195 markType == SC_MARK_UNDERLINE || markType == SC_MARK_AVAILABLE) {
196 // An invisible marker so don't draw anything
198 } else if (markType == SC_MARK_VLINE) {
199 surface->PenColour(colourBody);
200 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
201 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
203 } else if (markType == SC_MARK_LCORNER) {
204 surface->PenColour(colourTail);
205 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
206 surface->LineTo(centreX, centreY);
207 surface->LineTo(static_cast<int>(rc.right) - 1, centreY);
209 } else if (markType == SC_MARK_TCORNER) {
210 surface->PenColour(colourTail);
211 surface->MoveTo(centreX, centreY);
212 surface->LineTo(static_cast<int>(rc.right) - 1, centreY);
214 surface->PenColour(colourBody);
215 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
216 surface->LineTo(centreX, centreY + 1);
218 surface->PenColour(colourHead);
219 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
221 } else if (markType == SC_MARK_LCORNERCURVE) {
222 surface->PenColour(colourTail);
223 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
224 surface->LineTo(centreX, centreY-3);
225 surface->LineTo(centreX+3, centreY);
226 surface->LineTo(static_cast<int>(rc.right) - 1, centreY);
228 } else if (markType == SC_MARK_TCORNERCURVE) {
229 surface->PenColour(colourTail);
230 surface->MoveTo(centreX, centreY-3);
231 surface->LineTo(centreX+3, centreY);
232 surface->LineTo(static_cast<int>(rc.right) - 1, centreY);
234 surface->PenColour(colourBody);
235 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
236 surface->LineTo(centreX, centreY-2);
238 surface->PenColour(colourHead);
239 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
241 } else if (markType == SC_MARK_BOXPLUS) {
242 DrawBox(surface, centreX, centreY, blobSize, fore, colourHead);
243 DrawPlus(surface, centreX, centreY, blobSize, colourTail);
245 } else if (markType == SC_MARK_BOXPLUSCONNECTED) {
246 if (tFold == LineMarker::headWithTail)
247 surface->PenColour(colourTail);
248 else
249 surface->PenColour(colourBody);
250 surface->MoveTo(centreX, centreY + blobSize);
251 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
253 surface->PenColour(colourBody);
254 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
255 surface->LineTo(centreX, centreY - blobSize);
257 DrawBox(surface, centreX, centreY, blobSize, fore, colourHead);
258 DrawPlus(surface, centreX, centreY, blobSize, colourTail);
260 if (tFold == LineMarker::body) {
261 surface->PenColour(colourTail);
262 surface->MoveTo(centreX + 1, centreY + blobSize);
263 surface->LineTo(centreX + blobSize + 1, centreY + blobSize);
265 surface->MoveTo(centreX + blobSize, centreY + blobSize);
266 surface->LineTo(centreX + blobSize, centreY - blobSize);
268 surface->MoveTo(centreX + 1, centreY - blobSize);
269 surface->LineTo(centreX + blobSize + 1, centreY - blobSize);
271 } else if (markType == SC_MARK_BOXMINUS) {
272 DrawBox(surface, centreX, centreY, blobSize, fore, colourHead);
273 DrawMinus(surface, centreX, centreY, blobSize, colourTail);
275 surface->PenColour(colourHead);
276 surface->MoveTo(centreX, centreY + blobSize);
277 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
279 } else if (markType == SC_MARK_BOXMINUSCONNECTED) {
280 DrawBox(surface, centreX, centreY, blobSize, fore, colourHead);
281 DrawMinus(surface, centreX, centreY, blobSize, colourTail);
283 surface->PenColour(colourHead);
284 surface->MoveTo(centreX, centreY + blobSize);
285 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
287 surface->PenColour(colourBody);
288 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
289 surface->LineTo(centreX, centreY - blobSize);
291 if (tFold == LineMarker::body) {
292 surface->PenColour(colourTail);
293 surface->MoveTo(centreX + 1, centreY + blobSize);
294 surface->LineTo(centreX + blobSize + 1, centreY + blobSize);
296 surface->MoveTo(centreX + blobSize, centreY + blobSize);
297 surface->LineTo(centreX + blobSize, centreY - blobSize);
299 surface->MoveTo(centreX + 1, centreY - blobSize);
300 surface->LineTo(centreX + blobSize + 1, centreY - blobSize);
302 } else if (markType == SC_MARK_CIRCLEPLUS) {
303 DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead);
304 DrawPlus(surface, centreX, centreY, blobSize, colourTail);
306 } else if (markType == SC_MARK_CIRCLEPLUSCONNECTED) {
307 if (tFold == LineMarker::headWithTail)
308 surface->PenColour(colourTail);
309 else
310 surface->PenColour(colourBody);
311 surface->MoveTo(centreX, centreY + blobSize);
312 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
314 surface->PenColour(colourBody);
315 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
316 surface->LineTo(centreX, centreY - blobSize);
318 DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead);
319 DrawPlus(surface, centreX, centreY, blobSize, colourTail);
321 } else if (markType == SC_MARK_CIRCLEMINUS) {
322 surface->PenColour(colourHead);
323 surface->MoveTo(centreX, centreY + blobSize);
324 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
326 DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead);
327 DrawMinus(surface, centreX, centreY, blobSize, colourTail);
329 } else if (markType == SC_MARK_CIRCLEMINUSCONNECTED) {
330 surface->PenColour(colourHead);
331 surface->MoveTo(centreX, centreY + blobSize);
332 surface->LineTo(centreX, static_cast<int>(rcWhole.bottom));
334 surface->PenColour(colourBody);
335 surface->MoveTo(centreX, static_cast<int>(rcWhole.top));
336 surface->LineTo(centreX, centreY - blobSize);
338 DrawCircle(surface, centreX, centreY, blobSize, fore, colourHead);
339 DrawMinus(surface, centreX, centreY, blobSize, colourTail);
341 } else if (markType >= SC_MARK_CHARACTER) {
342 char character[1];
343 character[0] = static_cast<char>(markType - SC_MARK_CHARACTER);
344 XYPOSITION width = surface->WidthText(fontForCharacter, character, 1);
345 rc.left += (rc.Width() - width) / 2;
346 rc.right = rc.left + width;
347 surface->DrawTextClipped(rc, fontForCharacter, rc.bottom - 2,
348 character, 1, fore, back);
350 } else if (markType == SC_MARK_DOTDOTDOT) {
351 XYPOSITION right = static_cast<XYPOSITION>(centreX - 6);
352 for (int b=0; b<3; b++) {
353 PRectangle rcBlob(right, rc.bottom - 4, right + 2, rc.bottom-2);
354 surface->FillRectangle(rcBlob, fore);
355 right += 5.0f;
357 } else if (markType == SC_MARK_ARROWS) {
358 surface->PenColour(fore);
359 int right = centreX - 2;
360 const int armLength = dimOn2 - 1;
361 for (int b = 0; b<3; b++) {
362 surface->MoveTo(right, centreY);
363 surface->LineTo(right - armLength, centreY - armLength);
364 surface->MoveTo(right, centreY);
365 surface->LineTo(right - armLength, centreY + armLength);
366 right += 4;
368 } else if (markType == SC_MARK_SHORTARROW) {
369 Point pts[] = {
370 Point::FromInts(centreX, centreY + dimOn2),
371 Point::FromInts(centreX + dimOn2, centreY),
372 Point::FromInts(centreX, centreY - dimOn2),
373 Point::FromInts(centreX, centreY - dimOn4),
374 Point::FromInts(centreX - dimOn4, centreY - dimOn4),
375 Point::FromInts(centreX - dimOn4, centreY + dimOn4),
376 Point::FromInts(centreX, centreY + dimOn4),
377 Point::FromInts(centreX, centreY + dimOn2),
379 surface->Polygon(pts, ELEMENTS(pts), fore, back);
380 } else if (markType == SC_MARK_LEFTRECT) {
381 PRectangle rcLeft = rcWhole;
382 rcLeft.right = rcLeft.left + 4;
383 surface->FillRectangle(rcLeft, back);
384 } else if (markType == SC_MARK_BOOKMARK) {
385 const int halfHeight = minDim / 3;
386 Point pts[] = {
387 Point::FromInts(static_cast<int>(rc.left), centreY-halfHeight),
388 Point::FromInts(static_cast<int>(rc.right) - 3, centreY - halfHeight),
389 Point::FromInts(static_cast<int>(rc.right) - 3 - halfHeight, centreY),
390 Point::FromInts(static_cast<int>(rc.right) - 3, centreY + halfHeight),
391 Point::FromInts(static_cast<int>(rc.left), centreY + halfHeight),
393 surface->Polygon(pts, ELEMENTS(pts), fore, back);
394 } else { // SC_MARK_FULLRECT
395 surface->FillRectangle(rcWhole, back);