2009-04-24 23:35:41 +00:00
|
|
|
// Scintilla source code edit control
|
|
|
|
/** @file Indicator.cxx
|
|
|
|
** Defines the style of indicators which are text decorations such as underlining.
|
|
|
|
**/
|
|
|
|
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
|
|
|
|
// The License.txt file describes the conditions under which this software may be distributed.
|
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <map>
|
|
|
|
|
2009-04-24 23:35:41 +00:00
|
|
|
#include "Platform.h"
|
|
|
|
|
|
|
|
#include "Scintilla.h"
|
|
|
|
#include "Indicator.h"
|
2015-06-07 21:19:26 +00:00
|
|
|
#include "XPM.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
|
|
|
|
#ifdef SCI_NAMESPACE
|
|
|
|
using namespace Scintilla;
|
|
|
|
#endif
|
|
|
|
|
2013-08-28 00:44:27 +00:00
|
|
|
static PRectangle PixelGridAlign(const PRectangle &rc) {
|
|
|
|
// Move left and right side to nearest pixel to avoid blurry visuals
|
2015-06-07 21:19:26 +00:00
|
|
|
return PRectangle::FromInts(int(rc.left + 0.5), int(rc.top), int(rc.right + 0.5), int(rc.bottom));
|
2013-08-28 00:44:27 +00:00
|
|
|
}
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine, DrawState drawState, int value) const {
|
|
|
|
StyleAndColour sacDraw = sacNormal;
|
|
|
|
if (Flags() & SC_INDICFLAG_VALUEFORE) {
|
|
|
|
sacDraw.fore = value & SC_INDICVALUEMASK;
|
|
|
|
}
|
|
|
|
if (drawState == drawHover) {
|
|
|
|
sacDraw = sacHover;
|
|
|
|
}
|
|
|
|
surface->PenColour(sacDraw.fore);
|
|
|
|
int ymid = static_cast<int>(rc.bottom + rc.top) / 2;
|
|
|
|
if (sacDraw.style == INDIC_SQUIGGLE) {
|
2013-08-28 00:44:27 +00:00
|
|
|
int x = int(rc.left+0.5);
|
|
|
|
int xLast = int(rc.right+0.5);
|
|
|
|
int y = 0;
|
2015-06-07 21:19:26 +00:00
|
|
|
surface->MoveTo(x, static_cast<int>(rc.top) + y);
|
2013-08-28 00:44:27 +00:00
|
|
|
while (x < xLast) {
|
|
|
|
if ((x + 2) > xLast) {
|
|
|
|
if (xLast > x)
|
|
|
|
y = 1;
|
|
|
|
x = xLast;
|
|
|
|
} else {
|
|
|
|
x += 2;
|
|
|
|
y = 2 - y;
|
|
|
|
}
|
2015-06-07 21:19:26 +00:00
|
|
|
surface->LineTo(x, static_cast<int>(rc.top) + y);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2015-06-07 21:19:26 +00:00
|
|
|
} else if (sacDraw.style == INDIC_SQUIGGLEPIXMAP) {
|
2013-08-28 00:44:27 +00:00
|
|
|
PRectangle rcSquiggle = PixelGridAlign(rc);
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
int width = Platform::Minimum(4000, static_cast<int>(rcSquiggle.Width()));
|
2013-08-28 00:44:27 +00:00
|
|
|
RGBAImage image(width, 3, 1.0, 0);
|
|
|
|
enum { alphaFull = 0xff, alphaSide = 0x2f, alphaSide2=0x5f };
|
|
|
|
for (int x = 0; x < width; x++) {
|
|
|
|
if (x%2) {
|
|
|
|
// Two halfway columns have a full pixel in middle flanked by light pixels
|
2015-06-07 21:19:26 +00:00
|
|
|
image.SetPixel(x, 0, sacDraw.fore, alphaSide);
|
|
|
|
image.SetPixel(x, 1, sacDraw.fore, alphaFull);
|
|
|
|
image.SetPixel(x, 2, sacDraw.fore, alphaSide);
|
2013-08-28 00:44:27 +00:00
|
|
|
} else {
|
|
|
|
// Extreme columns have a full pixel at bottom or top and a mid-tone pixel in centre
|
2015-06-07 21:19:26 +00:00
|
|
|
image.SetPixel(x, (x % 4) ? 0 : 2, sacDraw.fore, alphaFull);
|
|
|
|
image.SetPixel(x, 1, sacDraw.fore, alphaSide2);
|
2013-08-28 00:44:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
surface->DrawRGBAImage(rcSquiggle, image.GetWidth(), image.GetHeight(), image.Pixels());
|
2015-06-07 21:19:26 +00:00
|
|
|
} else if (sacDraw.style == INDIC_SQUIGGLELOW) {
|
|
|
|
surface->MoveTo(static_cast<int>(rc.left), static_cast<int>(rc.top));
|
|
|
|
int x = static_cast<int>(rc.left) + 3;
|
2011-07-17 22:30:49 +00:00
|
|
|
int y = 0;
|
|
|
|
while (x < rc.right) {
|
2015-06-07 21:19:26 +00:00
|
|
|
surface->LineTo(x - 1, static_cast<int>(rc.top) + y);
|
2011-07-17 22:30:49 +00:00
|
|
|
y = 1 - y;
|
2015-06-07 21:19:26 +00:00
|
|
|
surface->LineTo(x, static_cast<int>(rc.top) + y);
|
2011-07-17 22:30:49 +00:00
|
|
|
x += 3;
|
|
|
|
}
|
2015-06-07 21:19:26 +00:00
|
|
|
surface->LineTo(static_cast<int>(rc.right), static_cast<int>(rc.top) + y); // Finish the line
|
|
|
|
} else if (sacDraw.style == INDIC_TT) {
|
|
|
|
surface->MoveTo(static_cast<int>(rc.left), ymid);
|
|
|
|
int x = static_cast<int>(rc.left) + 5;
|
2009-04-24 23:35:41 +00:00
|
|
|
while (x < rc.right) {
|
|
|
|
surface->LineTo(x, ymid);
|
|
|
|
surface->MoveTo(x-3, ymid);
|
|
|
|
surface->LineTo(x-3, ymid+2);
|
|
|
|
x++;
|
|
|
|
surface->MoveTo(x, ymid);
|
|
|
|
x += 5;
|
|
|
|
}
|
2015-06-07 21:19:26 +00:00
|
|
|
surface->LineTo(static_cast<int>(rc.right), ymid); // Finish the line
|
2009-04-24 23:35:41 +00:00
|
|
|
if (x - 3 <= rc.right) {
|
|
|
|
surface->MoveTo(x-3, ymid);
|
|
|
|
surface->LineTo(x-3, ymid+2);
|
|
|
|
}
|
2015-06-07 21:19:26 +00:00
|
|
|
} else if (sacDraw.style == INDIC_DIAGONAL) {
|
|
|
|
int x = static_cast<int>(rc.left);
|
2009-04-24 23:35:41 +00:00
|
|
|
while (x < rc.right) {
|
2015-06-07 21:19:26 +00:00
|
|
|
surface->MoveTo(x, static_cast<int>(rc.top) + 2);
|
2009-04-24 23:35:41 +00:00
|
|
|
int endX = x+3;
|
2015-06-07 21:19:26 +00:00
|
|
|
int endY = static_cast<int>(rc.top) - 1;
|
2009-04-24 23:35:41 +00:00
|
|
|
if (endX > rc.right) {
|
2015-06-07 21:19:26 +00:00
|
|
|
endY += endX - static_cast<int>(rc.right);
|
|
|
|
endX = static_cast<int>(rc.right);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
surface->LineTo(endX, endY);
|
|
|
|
x += 4;
|
|
|
|
}
|
2015-06-07 21:19:26 +00:00
|
|
|
} else if (sacDraw.style == INDIC_STRIKE) {
|
|
|
|
surface->MoveTo(static_cast<int>(rc.left), static_cast<int>(rc.top) - 4);
|
|
|
|
surface->LineTo(static_cast<int>(rc.right), static_cast<int>(rc.top) - 4);
|
|
|
|
} else if ((sacDraw.style == INDIC_HIDDEN) || (sacDraw.style == INDIC_TEXTFORE)) {
|
2009-04-24 23:35:41 +00:00
|
|
|
// Draw nothing
|
2015-06-07 21:19:26 +00:00
|
|
|
} else if (sacDraw.style == INDIC_BOX) {
|
|
|
|
surface->MoveTo(static_cast<int>(rc.left), ymid + 1);
|
|
|
|
surface->LineTo(static_cast<int>(rc.right), ymid + 1);
|
|
|
|
surface->LineTo(static_cast<int>(rc.right), static_cast<int>(rcLine.top) + 1);
|
|
|
|
surface->LineTo(static_cast<int>(rc.left), static_cast<int>(rcLine.top) + 1);
|
|
|
|
surface->LineTo(static_cast<int>(rc.left), ymid + 1);
|
|
|
|
} else if (sacDraw.style == INDIC_ROUNDBOX ||
|
|
|
|
sacDraw.style == INDIC_STRAIGHTBOX ||
|
|
|
|
sacDraw.style == INDIC_FULLBOX) {
|
2009-04-24 23:35:41 +00:00
|
|
|
PRectangle rcBox = rcLine;
|
2015-06-07 21:19:26 +00:00
|
|
|
if (sacDraw.style != INDIC_FULLBOX)
|
|
|
|
rcBox.top = rcLine.top + 1;
|
2009-04-24 23:35:41 +00:00
|
|
|
rcBox.left = rc.left;
|
|
|
|
rcBox.right = rc.right;
|
2015-06-07 21:19:26 +00:00
|
|
|
surface->AlphaRectangle(rcBox, (sacDraw.style == INDIC_ROUNDBOX) ? 1 : 0,
|
|
|
|
sacDraw.fore, fillAlpha, sacDraw.fore, outlineAlpha, 0);
|
|
|
|
} else if (sacDraw.style == INDIC_DOTBOX) {
|
2013-08-28 00:44:27 +00:00
|
|
|
PRectangle rcBox = PixelGridAlign(rc);
|
|
|
|
rcBox.top = rcLine.top + 1;
|
|
|
|
rcBox.bottom = rcLine.bottom;
|
|
|
|
// Cap width at 4000 to avoid large allocations when mistakes made
|
2015-06-07 21:19:26 +00:00
|
|
|
int width = Platform::Minimum(static_cast<int>(rcBox.Width()), 4000);
|
|
|
|
RGBAImage image(width, static_cast<int>(rcBox.Height()), 1.0, 0);
|
2013-08-28 00:44:27 +00:00
|
|
|
// Draw horizontal lines top and bottom
|
|
|
|
for (int x=0; x<width; x++) {
|
2015-06-07 21:19:26 +00:00
|
|
|
for (int y = 0; y<static_cast<int>(rcBox.Height()); y += static_cast<int>(rcBox.Height()) - 1) {
|
|
|
|
image.SetPixel(x, y, sacDraw.fore, ((x + y) % 2) ? outlineAlpha : fillAlpha);
|
2013-08-28 00:44:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Draw vertical lines left and right
|
2015-06-07 21:19:26 +00:00
|
|
|
for (int y = 1; y<static_cast<int>(rcBox.Height()); y++) {
|
2013-08-28 00:44:27 +00:00
|
|
|
for (int x=0; x<width; x += width-1) {
|
2015-06-07 21:19:26 +00:00
|
|
|
image.SetPixel(x, y, sacDraw.fore, ((x + y) % 2) ? outlineAlpha : fillAlpha);
|
2013-08-28 00:44:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
surface->DrawRGBAImage(rcBox, image.GetWidth(), image.GetHeight(), image.Pixels());
|
2015-06-07 21:19:26 +00:00
|
|
|
} else if (sacDraw.style == INDIC_DASH) {
|
|
|
|
int x = static_cast<int>(rc.left);
|
2011-07-17 22:30:49 +00:00
|
|
|
while (x < rc.right) {
|
|
|
|
surface->MoveTo(x, ymid);
|
2015-06-07 21:19:26 +00:00
|
|
|
surface->LineTo(Platform::Minimum(x + 4, static_cast<int>(rc.right)), ymid);
|
2011-07-17 22:30:49 +00:00
|
|
|
x += 7;
|
|
|
|
}
|
2015-06-07 21:19:26 +00:00
|
|
|
} else if (sacDraw.style == INDIC_DOTS) {
|
|
|
|
int x = static_cast<int>(rc.left);
|
|
|
|
while (x < static_cast<int>(rc.right)) {
|
|
|
|
PRectangle rcDot = PRectangle::FromInts(x, ymid, x + 1, ymid + 1);
|
|
|
|
surface->FillRectangle(rcDot, sacDraw.fore);
|
2011-07-17 22:30:49 +00:00
|
|
|
x += 2;
|
|
|
|
}
|
2015-06-07 21:19:26 +00:00
|
|
|
} else if (sacDraw.style == INDIC_COMPOSITIONTHICK) {
|
2013-08-28 00:44:27 +00:00
|
|
|
PRectangle rcComposition(rc.left+1, rcLine.bottom-2, rc.right-1, rcLine.bottom);
|
2015-06-07 21:19:26 +00:00
|
|
|
surface->FillRectangle(rcComposition, sacDraw.fore);
|
|
|
|
} else if (sacDraw.style == INDIC_COMPOSITIONTHIN) {
|
|
|
|
PRectangle rcComposition(rc.left+1, rcLine.bottom-2, rc.right-1, rcLine.bottom-1);
|
|
|
|
surface->FillRectangle(rcComposition, sacDraw.fore);
|
2009-04-24 23:35:41 +00:00
|
|
|
} else { // Either INDIC_PLAIN or unknown
|
2015-06-07 21:19:26 +00:00
|
|
|
surface->MoveTo(static_cast<int>(rc.left), ymid);
|
|
|
|
surface->LineTo(static_cast<int>(rc.right), ymid);
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-07 21:19:26 +00:00
|
|
|
void Indicator::SetFlags(int attributes_) {
|
|
|
|
attributes = attributes_;
|
|
|
|
}
|