diff options
| author | Neil <nyamatongwe@gmail.com> | 2021-03-20 17:18:10 +1100 | 
|---|---|---|
| committer | Neil <nyamatongwe@gmail.com> | 2021-03-20 17:18:10 +1100 | 
| commit | 1f630daf4b61ea12bc2ec2d688dba2586c172611 (patch) | |
| tree | 9f76118ba231a193b7077f029bcef7f43421454a | |
| parent | 434ea41aa400557964d73867008cfa8b1f64d8c4 (diff) | |
| download | scintilla-mirror-1f630daf4b61ea12bc2ec2d688dba2586c172611.tar.gz | |
Use new Surface APIs that can adapt to different stroke widths and use clipping
to allow more accurate less complex drawing code.
| -rw-r--r-- | gtk/deps.mak | 1 | ||||
| -rw-r--r-- | src/Indicator.cxx | 195 | ||||
| -rw-r--r-- | win32/deps.mak | 1 | ||||
| -rw-r--r-- | win32/nmdeps.mak | 1 | 
4 files changed, 102 insertions, 96 deletions
| diff --git a/gtk/deps.mak b/gtk/deps.mak index 749a3a0d1..3f9b954a3 100644 --- a/gtk/deps.mak +++ b/gtk/deps.mak @@ -298,7 +298,6 @@ Indicator.o: \  	../src/Platform.h \  	../include/Scintilla.h \  	../include/Sci_Position.h \ -	../src/IntegerRectangle.h \  	../src/Indicator.h \  	../src/XPM.h  KeyMap.o: \ diff --git a/src/Indicator.cxx b/src/Indicator.cxx index 9a182469d..93bf68ed0 100644 --- a/src/Indicator.cxx +++ b/src/Indicator.cxx @@ -20,18 +20,11 @@  #include "Platform.h"  #include "Scintilla.h" -#include "IntegerRectangle.h"  #include "Indicator.h"  #include "XPM.h"  using namespace Scintilla; -static PRectangle PixelGridAlign(const PRectangle &rc) noexcept { -	// Move left and right side to nearest pixel to avoid blurry visuals -	return PRectangle(std::round(rc.left), std::floor(rc.top), -		std::round(rc.right), std::floor(rc.bottom)); -} -  void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine, const PRectangle &rcCharacter, State state, int value) const {  	StyleAndColour sacDraw = sacNormal;  	if (Flags() & SC_INDICFLAG_VALUEFORE) { @@ -40,32 +33,45 @@ void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &r  	if (state == State::hover) {  		sacDraw = sacHover;  	} -	const IntegerRectangle irc(rc); -	surface->PenColour(sacDraw.fore); -	const int ymid = (irc.bottom + irc.top) / 2; + +	const int pixelDivisions = surface->PixelDivisions(); + +	const XYPOSITION strokeWidth = 1.0f; +	const XYPOSITION halfWidth = strokeWidth / 2.0f; + +	const PRectangle rcAligned(PixelAlignOutside(rc, pixelDivisions)); +	PRectangle rcFullHeightAligned = PixelAlignOutside(rcLine, pixelDivisions); +	rcFullHeightAligned.left = rcAligned.left; +	rcFullHeightAligned.right = rcAligned.right; + +	const XYPOSITION ymid = PixelAlign(rc.Centre().y, pixelDivisions); + +	// This is a reasonable clip for indicators beneath text like underlines  +	PRectangle rcClip = rcAligned; +	rcClip.bottom = rcFullHeightAligned.bottom;  	switch (sacDraw.style) {  	case INDIC_SQUIGGLE: { -			const IntegerRectangle ircSquiggle(PixelGridAlign(rc)); -			int x = ircSquiggle.left; -			const int xLast = ircSquiggle.right; -			int y = 0; -			surface->MoveTo(x, irc.top + y); +			surface->SetClip(rcClip); +			XYPOSITION x = rcAligned.left + halfWidth; +			const XYPOSITION top = rcAligned.top + halfWidth; +			const XYPOSITION xLast = rcAligned.right + halfWidth; +			XYPOSITION y = 0; +			std::vector<Point> pts; +			const XYPOSITION pitch = 1 + strokeWidth; +			pts.emplace_back(x, top + y);  			while (x < xLast) { -				if ((x + 2) > xLast) { -					y = 1; -					x = xLast; -				} else { -					x += 2; -					y = 2 - y; +				x += pitch; +				y = pitch - y; +				pts.emplace_back(x, top + y);  				} -				surface->LineTo(x, irc.top + y); -			} +			surface->PolyLine(pts.data(), std::size(pts), Stroke(sacDraw.fore, strokeWidth)); +			surface->PopClip();  		}  		break;  	case INDIC_SQUIGGLEPIXMAP: { -			const PRectangle rcSquiggle = PixelGridAlign(rc); +			const PRectangle rcSquiggle = PixelAlign(rc, 1);  			const int width = std::min(4000, static_cast<int>(rcSquiggle.Width()));  			RGBAImage image(width, 3, 1.0, nullptr); @@ -87,57 +93,61 @@ void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &r  		break;  	case INDIC_SQUIGGLELOW: { -			surface->MoveTo(irc.left, irc.top); -			int x = irc.left + 3; +			std::vector<Point> pts; +			const XYPOSITION top = rcAligned.top + halfWidth;  			int y = 0; -			while (x < rc.right) { -				surface->LineTo(x - 1, irc.top + y); +			XYPOSITION x = std::round(rcAligned.left) + halfWidth; +			pts.emplace_back(x, top + y); +			const XYPOSITION pitch = 2 + strokeWidth; +			x += pitch; +			while (x < rcAligned.right) { +				pts.emplace_back(x - 1, top + y);  				y = 1 - y; -				surface->LineTo(x, irc.top + y); -				x += 3; +				pts.emplace_back(x, top + y); +				x += pitch;  			} -			surface->LineTo(irc.right, irc.top + y);	// Finish the line +			pts.emplace_back(rcAligned.right, top + y); +			surface->PolyLine(pts.data(), std::size(pts), Stroke(sacDraw.fore, strokeWidth));  		}  		break;  	case INDIC_TT: { -			surface->MoveTo(irc.left, ymid); -			int x = irc.left + 5; -			while (x < rc.right) { -				surface->LineTo(x, ymid); -				surface->MoveTo(x-3, ymid); -				surface->LineTo(x-3, ymid+2); +			surface->SetClip(rcClip); +			const XYPOSITION yLine = ymid; +			XYPOSITION x = rcAligned.left + 5.0f; +			const XYPOSITION pitch = 4 + strokeWidth; +			while (x < rc.right + pitch) { +				const PRectangle line(x-pitch, yLine, x, yLine + strokeWidth); +				surface->FillRectangle(line, sacDraw.fore); +				const PRectangle tail(x - 2 - strokeWidth, yLine + strokeWidth, x - 2, yLine + strokeWidth * 2); +				surface->FillRectangle(tail, sacDraw.fore);  				x++; -				surface->MoveTo(x, ymid); -				x += 5; -			} -			surface->LineTo(irc.right, ymid);	// Finish the line -			if (x - 3 <= rc.right) { -				surface->MoveTo(x-3, ymid); -				surface->LineTo(x-3, ymid+2); +				x += pitch;  			} +			surface->PopClip();  		}  		break;  	case INDIC_DIAGONAL: { -			int x = irc.left; +			surface->SetClip(rcClip); +			XYPOSITION x = rcAligned.left + halfWidth; +			const XYPOSITION top = rcAligned.top + halfWidth; +			const XYPOSITION pitch = 3 + strokeWidth;  			while (x < rc.right) { -				surface->MoveTo(x, irc.top + 2); -				int endX = x+3; -				int endY = irc.top - 1; -				if (endX > rc.right) { -					endY += endX - irc.right; -					endX = irc.right; -				} -				surface->LineTo(endX, endY); -				x += 4; +				const XYPOSITION endX = x+3; +				const XYPOSITION endY = top - 1; +				surface->LineDraw(Point(x, top + 2), Point(endX, endY), Stroke(sacDraw.fore, strokeWidth)); +				x += pitch;  			} +			surface->PopClip();  		}  		break;  	case INDIC_STRIKE: { -			surface->MoveTo(irc.left, irc.top - 4); -			surface->LineTo(irc.right, irc.top - 4); +			const XYPOSITION yStrike = std::round(rcLine.Centre().y); +			const PRectangle rcStrike( +				rcAligned.left, yStrike, rcAligned.right, yStrike + strokeWidth); +			surface->FillRectangle(rcStrike, sacDraw.fore);  		}  		break; @@ -147,33 +157,28 @@ void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &r  		break;  	case INDIC_BOX: { -			surface->MoveTo(irc.left, ymid + 1); -			surface->LineTo(irc.right, ymid + 1); -			const int lineTop = static_cast<int>(rcLine.top) + 1; -			surface->LineTo(irc.right, lineTop); -			surface->LineTo(irc.left, lineTop); -			surface->LineTo(irc.left, ymid + 1); +			PRectangle rcBox = rcFullHeightAligned; +			rcBox.top = rcBox.top + 1.0f; +			rcBox.bottom = ymid + 1.0f; +			surface->RectangleFrame(rcBox, Stroke(ColourAlpha(sacDraw.fore, outlineAlpha), strokeWidth));  		}  		break;  	case INDIC_ROUNDBOX:  	case INDIC_STRAIGHTBOX:  	case INDIC_FULLBOX: { -			PRectangle rcBox = rcLine; +			PRectangle rcBox = rcFullHeightAligned;  			if (sacDraw.style != INDIC_FULLBOX) -				rcBox.top = rcLine.top + 1; -			rcBox.left = rc.left; -			rcBox.right = rc.right; -			surface->AlphaRectangle(rcBox, (sacDraw.style == INDIC_ROUNDBOX) ? 1 : 0, -						sacDraw.fore, fillAlpha, sacDraw.fore, outlineAlpha, 0); +				rcBox.top = rcBox.top + 1; +			surface->AlphaRectangle(rcBox, (sacDraw.style == INDIC_ROUNDBOX) ? 1.0f : 0.0f, +						FillStroke(ColourAlpha(sacDraw.fore, fillAlpha), ColourAlpha(sacDraw.fore, outlineAlpha), strokeWidth));  		}  		break;  	case INDIC_GRADIENT:  	case INDIC_GRADIENTCENTRE: { -			PRectangle rcBox = rc; -			rcBox.top = rcLine.top + 1; -			rcBox.bottom = rcLine.bottom; +			PRectangle rcBox = rcFullHeightAligned; +			rcBox.top = rcBox.top + 1;  			const Surface::GradientOptions options = Surface::GradientOptions::topToBottom;  			const ColourAlpha start(sacDraw.fore, fillAlpha);  			const ColourAlpha end(sacDraw.fore, 0); @@ -194,21 +199,20 @@ void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &r  		break;  	case INDIC_DOTBOX: { -			PRectangle rcBox = PixelGridAlign(rc); -			rcBox.top = rcLine.top + 1; -			rcBox.bottom = rcLine.bottom; -			const IntegerRectangle ircBox(rcBox); +			PRectangle rcBox = rcFullHeightAligned; +			rcBox.top = rcBox.top + 1;  			// Cap width at 4000 to avoid large allocations when mistakes made -			const int width = std::min(ircBox.Width(), 4000); -			RGBAImage image(width, ircBox.Height(), 1.0, nullptr); +			const int width = std::min(static_cast<int>(rcBox.Width()), 4000); +			const int height = static_cast<int>(rcBox.Height()); +			RGBAImage image(width, height, 1.0, nullptr);  			// Draw horizontal lines top and bottom  			for (int x=0; x<width; x++) { -				for (int y = 0; y<ircBox.Height(); y += ircBox.Height() - 1) { +				for (int y = 0; y< height; y += height - 1) {  					image.SetPixel(x, y, sacDraw.fore, ((x + y) % 2) ? outlineAlpha : fillAlpha);  				}  			}  			// Draw vertical lines left and right -			for (int y = 1; y<ircBox.Height(); y++) { +			for (int y = 1; y<height; y++) {  				for (int x=0; x<width; x += width-1) {  					image.SetPixel(x, y, sacDraw.fore, ((x + y) % 2) ? outlineAlpha : fillAlpha);  				} @@ -218,21 +222,25 @@ void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &r  		break;  	case INDIC_DASH: { -			int x = irc.left; +			XYPOSITION x = std::floor(rc.left); +			const XYPOSITION widthDash = 3 + std::round(strokeWidth);  			while (x < rc.right) { -				surface->MoveTo(x, ymid); -				surface->LineTo(std::min(x + 4, irc.right), ymid); -				x += 7; +				const PRectangle rcDash = PRectangle(x, ymid, +					x + widthDash, ymid + std::round(strokeWidth)); +				surface->FillRectangle(rcDash, sacDraw.fore); +				x += 3 + widthDash;  			}  		}  		break;  	case INDIC_DOTS: { -			int x = irc.left; -			while (x < irc.right) { -				const PRectangle rcDot = PRectangle::FromInts(x, ymid, x + 1, ymid + 1); +			const XYPOSITION widthDot = std::round(strokeWidth); +			XYPOSITION x = std::floor(rc.left); +			while (x < rc.right) { +				const PRectangle rcDot = PRectangle(x, ymid,  +					x + widthDot, ymid + widthDot);  				surface->FillRectangle(rcDot, sacDraw.fore); -				x += 2; +				x += widthDot * 2;  			}  		}  		break; @@ -254,21 +262,22 @@ void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &r  		if (rcCharacter.Width() >= 0.1) {  			const XYPOSITION pixelHeight = std::floor(rc.Height() - 1.0f);	// 1 pixel onto next line if multiphase  			const XYPOSITION x = (sacDraw.style == INDIC_POINT) ? (rcCharacter.left) : ((rcCharacter.right + rcCharacter.left) / 2); -			const XYPOSITION ix = std::round(x); -			const XYPOSITION iy = std::floor(rc.top + 1.0f); -			Point pts[] = { +			// 0.5f is to hit midpoint of pixels: +			const XYPOSITION ix = std::round(x) + 0.5f; +			const XYPOSITION iy = std::floor(rc.top + 1.0f) + 0.5f; +			const Point pts[] = {  				Point(ix - pixelHeight, iy + pixelHeight),	// Left  				Point(ix + pixelHeight, iy + pixelHeight),	// Right  				Point(ix, iy)								// Top  			}; -			surface->Polygon(pts, std::size(pts), sacDraw.fore, sacDraw.fore); +			surface->Polygon(pts, std::size(pts), FillStroke(sacDraw.fore));  		}  		break;  	default:  		// Either INDIC_PLAIN or unknown -		surface->MoveTo(irc.left, ymid); -		surface->LineTo(irc.right, ymid); +		surface->FillRectangle(PRectangle(rcAligned.left, ymid, +			rcAligned.right, ymid + std::round(strokeWidth)), sacDraw.fore);  	}  } diff --git a/win32/deps.mak b/win32/deps.mak index 3939a81fd..defb10c63 100644 --- a/win32/deps.mak +++ b/win32/deps.mak @@ -266,7 +266,6 @@ Indicator.o: \  	../src/Platform.h \  	../include/Scintilla.h \  	../include/Sci_Position.h \ -	../src/IntegerRectangle.h \  	../src/Indicator.h \  	../src/XPM.h  KeyMap.o: \ diff --git a/win32/nmdeps.mak b/win32/nmdeps.mak index 1e72661fc..18deb11c0 100644 --- a/win32/nmdeps.mak +++ b/win32/nmdeps.mak @@ -266,7 +266,6 @@ $(DIR_O)/Indicator.obj: \  	../src/Platform.h \  	../include/Scintilla.h \  	../include/Sci_Position.h \ -	../src/IntegerRectangle.h \  	../src/Indicator.h \  	../src/XPM.h  $(DIR_O)/KeyMap.obj: \ | 
