Upgraded to scintilla 3.2.3
[TortoiseGit.git] / ext / scintilla / src / LineMarker.cxx
blobde88f0746a3090f673e8b5f32feda8c460764cee
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>
10 #include <vector>
11 #include <map>
13 #include "Platform.h"
15 #include "Scintilla.h"
16 #include "XPM.h"
17 #include "LineMarker.h"
19 #ifdef SCI_NAMESPACE
20 using namespace Scintilla;
21 #endif
23 void LineMarker::SetXPM(const char *textForm) {
24 delete pxpm;
25 pxpm = new XPM(textForm);
26 markType = SC_MARK_PIXMAP;
29 void LineMarker::SetXPM(const char *const *linesForm) {
30 delete pxpm;
31 pxpm = new XPM(linesForm);
32 markType = SC_MARK_PIXMAP;
35 void LineMarker::SetRGBAImage(Point sizeRGBAImage, float scale, const unsigned char *pixelsRGBAImage) {
36 delete image;
37 image = new RGBAImage(sizeRGBAImage.x, sizeRGBAImage.y, scale, pixelsRGBAImage);
38 markType = SC_MARK_RGBAIMAGE;
41 static void DrawBox(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore, ColourDesired back) {
42 PRectangle rc;
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) {
51 PRectangle rcCircle;
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;
76 switch (tFold) {
77 case LineMarker::head :
78 case LineMarker::headWithTail :
79 head = backSelected;
80 tail = backSelected;
81 break;
82 case LineMarker::body :
83 head = backSelected;
84 body = backSelected;
85 break;
86 case LineMarker::tail :
87 body = backSelected;
88 tail = backSelected;
89 break;
90 default :
91 // LineMarker::undefined
92 break;
95 if ((markType == SC_MARK_PIXMAP) && (pxpm)) {
96 pxpm->Draw(surface, rcWhole);
97 return;
99 if ((markType == SC_MARK_RGBAIMAGE) && (image)) {
100 // Make rectangle just large enough to fit image centred on centre of rcWhole
101 PRectangle rcImage;
102 rcImage.top = static_cast<int>(((rcWhole.top + rcWhole.bottom) - image->GetScaledHeight()) / 2);
103 rcImage.bottom = rcImage.top + image->GetScaledHeight();
104 rcImage.left = static_cast<int>(((rcWhole.left + rcWhole.right) - image->GetScaledWidth()) / 2);
105 rcImage.right = rcImage.left + image->GetScaledWidth();
106 surface->DrawRGBAImage(rcImage, image->GetWidth(), image->GetHeight(), image->Pixels());
107 return;
109 // Restrict most shapes a bit
110 PRectangle rc = rcWhole;
111 rc.top++;
112 rc.bottom--;
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) {
131 PRectangle rcCircle;
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) {
138 Point pts[] = {
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]),
144 fore, back);
146 } else if (markType == SC_MARK_ARROWDOWN) {
147 Point pts[] = {
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]),
153 fore, back);
155 } else if (markType == SC_MARK_PLUS) {
156 Point pts[] = {
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]),
171 fore, back);
173 } else if (markType == SC_MARK_MINUS) {
174 Point pts[] = {
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]),
181 fore, back);
183 } else if (markType == SC_MARK_SMALLRECT) {
184 PRectangle rcSmall;
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);
245 else
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);
306 else
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) {
339 char character[1];
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);
352 right += 5;
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);
361 right += 4;
363 } else if (markType == SC_MARK_SHORTARROW) {
364 Point pts[] = {
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]),
375 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 { // SC_MARK_FULLRECT
381 surface->FillRectangle(rcWhole, back);