1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

New method Graphics::fillRectList(), which performs better (and looks better when scaled) than multiple calls to fillRect or drawVerticalLine. Also fixed DPI detection in Windows.

This commit is contained in:
jules 2013-08-30 18:20:51 +01:00
parent 641cb754f0
commit dbf7053861
18 changed files with 357 additions and 143 deletions

View file

@ -60,15 +60,18 @@ public:
if (backgroundGraphics != nullptr)
col = backgroundGraphics->getBackgroundColour().contrasting();
g.setColour (col.withAlpha (0.1f));
const Rectangle<int> clip (g.getClipBounds());
for (int y = clip.getY() - (clip.getY() % snapGridSize); y < clip.getBottom(); y += snapGridSize)
g.drawHorizontalLine (y, 0.0f, (float) clip.getRight());
RectangleList<float> gridLines;
for (int x = clip.getX() - (clip.getX() % snapGridSize); x < clip.getRight(); x += snapGridSize)
g.drawVerticalLine (x, 0.0f, (float) clip.getBottom());
gridLines.addWithoutMerging (Rectangle<float> ((float) x, 0.0f, 1.0f, (float) clip.getBottom()));
for (int y = clip.getY() - (clip.getY() % snapGridSize); y < clip.getBottom(); y += snapGridSize)
gridLines.addWithoutMerging (Rectangle<float> (0.0f, (float) y, (float) clip.getRight(), 1.0f));
g.setColour (col.withAlpha (0.1f));
g.fillRectList (gridLines);
}
}

View file

@ -45,17 +45,21 @@ LiveAudioInputDisplayComp::~LiveAudioInputDisplayComp()
void LiveAudioInputDisplayComp::paint (Graphics& g)
{
g.fillAll (Colours::black);
RectangleList<float> waveform;
g.setColour (Colours::green);
const float midY = getHeight() * 0.5f;
int sampleNum = (nextSample + numElementsInArray (samples) - 1);
for (int x = jmin (getWidth(), (int) numElementsInArray (samples)); --x >= 0;)
{
const float sampleSize = midY * samples [sampleNum-- % numElementsInArray (samples)];
g.drawVerticalLine (x, midY - sampleSize, midY + sampleSize);
waveform.addWithoutMerging (Rectangle<float> ((float) x, midY - sampleSize, 1.0f, sampleSize * 2.0f));
}
g.fillAll (Colours::black);
g.setColour (Colours::green);
g.fillRectList (waveform);
}
void LiveAudioInputDisplayComp::timerCallback()

View file

@ -304,26 +304,39 @@ private:
void drawLines (Graphics& g)
{
g.setColour (Colours::blue.withAlpha ((float) owner.opacitySlider->getValue()));
for (int x = 0; x < getWidth(); ++x)
{
float y = getHeight() * 0.3f;
float width = y * fabsf (sinf (x / 100.0f + 2.0f * bouncingNumber[1]));
g.drawVerticalLine (x, y - width, y + width);
RectangleList<float> verticalLines;
for (int x = 0; x < getWidth(); ++x)
{
float y = getHeight() * 0.3f;
float length = y * fabsf (sinf (x / 100.0f + 2.0f * bouncingNumber[1]));
verticalLines.addWithoutMerging (Rectangle<float> ((float) x, y - length * 0.5f, 1.0f, length));
}
g.setColour (Colours::blue.withAlpha ((float) owner.opacitySlider->getValue()));
g.fillRectList (verticalLines);
}
g.setColour (Colours::green.withAlpha ((float) owner.opacitySlider->getValue()));
for (int y = 0; y < getHeight(); ++y)
{
float x = getWidth() * 0.3f;
float width = x * fabsf (sinf (y / 100.0f + 2.0f * bouncingNumber[2]));
g.drawHorizontalLine (y, x - width, x + width);
RectangleList<float> horizontalLines;
for (int y = 0; y < getHeight(); ++y)
{
float x = getWidth() * 0.3f;
float length = x * fabsf (sinf (y / 100.0f + 2.0f * bouncingNumber[2]));
horizontalLines.addWithoutMerging (Rectangle<float> (x - length * 0.5f, (float) y, length, 1.0f));
}
g.setColour (Colours::green.withAlpha ((float) owner.opacitySlider->getValue()));
g.fillRectList (horizontalLines);
}
g.setColour (Colours::red.withAlpha ((float) owner.opacitySlider->getValue()));
g.drawLine (bouncingPointX[0], bouncingPointY[0], bouncingPointX[1], bouncingPointY[1]);
g.drawLine (bouncingPointX[0], bouncingPointY[0],
bouncingPointX[1], bouncingPointY[1]);
g.drawLine (getWidth() - bouncingPointX[0], getHeight() - bouncingPointY[0],
getWidth() - bouncingPointX[1], getHeight() - bouncingPointY[1]);
}

View file

@ -390,16 +390,25 @@ public:
const MinMaxValue* cacheData = getData (channelNum, clip.getX() - area.getX());
int x = clip.getX();
RectangleList<float> waveform;
float x = (float) clip.getX();
for (int w = clip.getWidth(); --w >= 0;)
{
if (cacheData->isNonZero())
g.drawVerticalLine (x, jmax (midY - cacheData->getMaxValue() * vscale - 0.3f, topY),
jmin (midY - cacheData->getMinValue() * vscale + 0.3f, bottomY));
{
const float top = jmax (midY - cacheData->getMaxValue() * vscale - 0.3f, topY);
const float bottom = jmin (midY - cacheData->getMinValue() * vscale + 0.3f, bottomY);
++x;
waveform.addWithoutMerging (Rectangle<float> (x, top, 1.0f, bottom - top));
}
x += 1.0f;
++cacheData;
}
g.fillRectList (waveform);
}
}
}

View file

@ -348,6 +348,11 @@ void Graphics::fillRect (const float x, const float y, const float width, const
fillRect (Rectangle<float> (x, y, width, height));
}
void Graphics::fillRectList (const RectangleList<float>& rectangles) const
{
context.fillRectList (rectangles);
}
void Graphics::setPixel (int x, int y) const
{
context.fillRect (Rectangle<int> (x, y, 1, 1), false);

View file

@ -241,33 +241,39 @@ public:
//==============================================================================
/** Fills a rectangle with the current colour or brush.
@see drawRect, fillRoundedRectangle
*/
void fillRect (const Rectangle<int>& rectangle) const;
/** Fills a rectangle with the current colour or brush.
@see drawRect, fillRoundedRectangle
*/
void fillRect (const Rectangle<float>& rectangle) const;
/** Fills a rectangle with the current colour or brush.
@see drawRect, fillRoundedRectangle
*/
void fillRect (int x, int y, int width, int height) const;
/** Fills a rectangle with the current colour or brush. */
void fillRect (const Rectangle<int>& rectangle) const;
/** Fills a rectangle with the current colour or brush. */
void fillRect (const Rectangle<float>& rectangle) const;
/** Fills a rectangle with the current colour or brush.
This uses sub-pixel positioning so is slower than the fillRect method which
takes integer coordinates.
@see drawRect, fillRoundedRectangle
*/
void fillRect (float x, float y, float width, float height) const;
/** Uses the current colour or brush to fill a rectangle with rounded corners.
/** Fills a set of rectangles using the current colour or brush.
If you have a lot of rectangles to draw, it may be more efficient
to create a RectangleList and use this method than to call fillRect()
multiple times.
*/
void fillRectList (const RectangleList<float>& rectangles) const;
/** Uses the current colour or brush to fill a rectangle with rounded corners.
@see drawRoundedRectangle, Path::addRoundedRectangle
*/
void fillRoundedRectangle (float x, float y, float width, float height,
float cornerSize) const;
/** Uses the current colour or brush to fill a rectangle with rounded corners.
@see drawRoundedRectangle, Path::addRoundedRectangle
*/
void fillRoundedRectangle (const Rectangle<float>& rectangle,
@ -286,8 +292,7 @@ public:
@see fillRect
*/
void drawRect (int x, int y, int width, int height,
int lineThickness = 1) const;
void drawRect (int x, int y, int width, int height, int lineThickness = 1) const;
/** Draws four lines to form a rectangular outline, using the current colour or brush.
@ -296,8 +301,7 @@ public:
@see fillRect
*/
void drawRect (float x, float y, float width, float height,
float lineThickness = 1.0f) const;
void drawRect (float x, float y, float width, float height, float lineThickness = 1.0f) const;
/** Draws four lines to form a rectangular outline, using the current colour or brush.
@ -331,7 +335,10 @@ public:
void drawRoundedRectangle (const Rectangle<float>& rectangle,
float cornerSize, float lineThickness) const;
/** Draws a 1x1 pixel using the current colour or brush. */
/** Draws a 1x1 pixel using the current colour or brush.
Note that because the context may be transformed, this is effectively the same as
calling fillRect (x, y, 1, 1), and the actual result may involve multiple pixels.
*/
void setPixel (int x, int y) const;
//==============================================================================

View file

@ -85,6 +85,8 @@ public:
//==============================================================================
virtual void fillRect (const Rectangle<int>&, bool replaceExistingContents) = 0;
virtual void fillRectList (const RectangleList<float>&) = 0;
virtual void fillPath (const Path&, const AffineTransform&) = 0;
virtual void drawImage (const Image&, const AffineTransform&) = 0;

View file

@ -351,7 +351,16 @@ void LowLevelGraphicsPostScriptRenderer::fillRect (const Rectangle<int>& r, cons
p.addRectangle (r);
fillPath (p, AffineTransform::identity);
}
}
void LowLevelGraphicsPostScriptRenderer::fillRectList (const RectangleList<float>& list)
{
for (const Rectangle<float>* r = list.begin(), * const e = list.end(); r != e; ++r)
{
Path p;
p.addRectangle (*r);
fillPath (p, AffineTransform::identity);
}
}
//==============================================================================

View file

@ -72,12 +72,10 @@ public:
//==============================================================================
void fillRect (const Rectangle<int>&, bool replaceExistingContents) override;
void fillRectList (const RectangleList<float>&) override;
void fillPath (const Path&, const AffineTransform&) override;
void drawImage (const Image&, const AffineTransform&) override;
void drawLine (const Line <float>&) override;
void drawVerticalLine (int x, float top, float bottom) override;
void drawHorizontalLine (int x, float top, float bottom) override;

View file

@ -29,7 +29,7 @@ EdgeTable::EdgeTable (const Rectangle<int>& area,
const Path& path, const AffineTransform& transform)
: bounds (area),
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1),
lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1),
needToCheckEmptinesss (true)
{
table.malloc ((size_t) ((bounds.getHeight() + 1) * lineStrideElements));
@ -103,10 +103,10 @@ EdgeTable::EdgeTable (const Rectangle<int>& area,
EdgeTable::EdgeTable (const Rectangle<int>& rectangleToAdd)
: bounds (rectangleToAdd),
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1),
lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1),
needToCheckEmptinesss (true)
{
table.malloc ((size_t) (jmax (1, bounds.getHeight()) * lineStrideElements));
allocate();
table[0] = 0;
const int x1 = rectangleToAdd.getX() << 8;
@ -127,17 +127,11 @@ EdgeTable::EdgeTable (const Rectangle<int>& rectangleToAdd)
EdgeTable::EdgeTable (const RectangleList<int>& rectanglesToAdd)
: bounds (rectanglesToAdd.getBounds()),
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1),
lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1),
needToCheckEmptinesss (true)
{
table.malloc ((size_t) (jmax (1, bounds.getHeight()) * lineStrideElements));
int* t = table;
for (int i = bounds.getHeight(); --i >= 0;)
{
*t = 0;
t += lineStrideElements;
}
allocate();
clearLineSizes();
for (const Rectangle<int>* r = rectanglesToAdd.begin(), * const e = rectanglesToAdd.end(); r != e; ++r)
{
@ -146,10 +140,49 @@ EdgeTable::EdgeTable (const RectangleList<int>& rectanglesToAdd)
int y = r->getY() - bounds.getY();
for (int j = r->getHeight(); --j >= 0;)
addEdgePointPair (x1, x2, y++, 255);
}
sanitiseLevels (true);
}
EdgeTable::EdgeTable (const RectangleList<float>& rectanglesToAdd)
: bounds (rectanglesToAdd.getBounds().getSmallestIntegerContainer()),
maxEdgesPerLine (rectanglesToAdd.getNumRectangles() * 2),
lineStrideElements (rectanglesToAdd.getNumRectangles() * 4 + 1),
needToCheckEmptinesss (true)
{
bounds.setHeight (bounds.getHeight() + 1);
allocate();
clearLineSizes();
for (const Rectangle<float>* r = rectanglesToAdd.begin(), * const e = rectanglesToAdd.end(); r != e; ++r)
{
const int x1 = roundToInt (r->getX() * 256.0f);
const int x2 = roundToInt (r->getRight() * 256.0f);
const int y1 = roundToInt (r->getY() * 256.0f) - (bounds.getY() << 8);
const int y2 = roundToInt (r->getBottom() * 256.0f) - (bounds.getY() << 8);
if (x2 <= x1 || y2 <= y1)
continue;
int y = y1 >> 8;
const int lastLine = y2 >> 8;
if (y == lastLine)
{
addEdgePoint (x1, y, 255);
addEdgePoint (x2, y, -255);
++y;
addEdgePointPair (x1, x2, y, y2 - y1);
}
else
{
addEdgePointPair (x1, x2, y++, 255 - (y1 & 255));
while (y < lastLine)
addEdgePointPair (x1, x2, y++, 255);
jassert (y < bounds.getHeight());
addEdgePointPair (x1, x2, y, y2 & 255);
}
}
@ -166,7 +199,7 @@ EdgeTable::EdgeTable (const Rectangle<float>& rectangleToAdd)
needToCheckEmptinesss (true)
{
jassert (! rectangleToAdd.isEmpty());
table.malloc ((size_t) (jmax (1, bounds.getHeight()) * lineStrideElements));
allocate();
table[0] = 0;
const int x1 = roundToInt (rectangleToAdd.getX() * 256.0f);
@ -246,7 +279,7 @@ EdgeTable& EdgeTable::operator= (const EdgeTable& other)
lineStrideElements = other.lineStrideElements;
needToCheckEmptinesss = other.needToCheckEmptinesss;
table.malloc ((size_t) (jmax (1, bounds.getHeight()) * lineStrideElements));
allocate();
copyEdgeTableData (table, lineStrideElements, other.table, lineStrideElements, bounds.getHeight());
return *this;
}
@ -256,6 +289,21 @@ EdgeTable::~EdgeTable()
}
//==============================================================================
void EdgeTable::allocate()
{
table.malloc ((size_t) (jmax (1, bounds.getHeight()) * lineStrideElements));
}
void EdgeTable::clearLineSizes() noexcept
{
int* t = table;
for (int i = bounds.getHeight(); --i >= 0;)
{
*t = 0;
t += lineStrideElements;
}
}
void EdgeTable::copyEdgeTableData (int* dest, const int destLineStride, const int* src, const int srcLineStride, int numLines) noexcept
{
while (--numLines >= 0)
@ -266,54 +314,83 @@ void EdgeTable::copyEdgeTableData (int* dest, const int destLineStride, const in
}
}
struct EdgeTable::LineSorter
{
static int compareElements (const LineItem& item1, const LineItem& item2) noexcept
{
return item1.x - item2.x;
}
};
void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) noexcept
{
// Convert the table from relative windings to absolute levels..
int* lineStart = table;
for (int i = bounds.getHeight(); --i >= 0;)
for (int y = bounds.getHeight(); --y >= 0;)
{
int* line = lineStart;
lineStart += lineStrideElements;
int num = lineStart[0];
int num = *line;
if (num == 0)
continue;
int level = 0;
if (useNonZeroWinding)
if (num > 0)
{
while (--num > 0)
{
line += 2;
level += *line;
int corrected = abs (level);
if (corrected >> 8)
corrected = 255;
LineItem* items = reinterpret_cast<LineItem*> (lineStart + 1);
*line = corrected;
{
// sort the X coords
LineSorter sorter;
sortArray (sorter, items, 0, num - 1, false);
}
}
else
{
while (--num > 0)
// merge duplicate X coords
for (int i = 0; i < num - 1; ++i)
{
line += 2;
level += *line;
int corrected = abs (level);
if (corrected >> 8)
if (items[i].x == items[i + 1].x)
{
corrected &= 511;
if (corrected >> 8)
corrected = 511 - corrected;
items[i].level += items[i + 1].level;
memmove (items + i + 1, items + i + 2, (num - i - 2) * sizeof (LineItem));
--num;
--lineStart[0];
--i;
}
*line = corrected;
}
int level = 0;
if (useNonZeroWinding)
{
while (--num > 0)
{
level += items->level;
int corrected = std::abs (level);
if (corrected >> 8)
corrected = 255;
items->level = corrected;
++items;
}
}
else
{
while (--num > 0)
{
level += items->level;
int corrected = std::abs (level);
if (corrected >> 8)
{
corrected &= 511;
if (corrected >> 8)
corrected = 511 - corrected;
}
items->level = corrected;
++items;
}
}
items->level = 0; // force the last level to 0, just in case something went wrong in creating the table
}
line[2] = 0; // force the last level to 0, just in case something went wrong in creating the table
lineStart += lineStrideElements;
}
}
@ -351,41 +428,40 @@ void EdgeTable::addEdgePoint (const int x, const int y, const int winding)
int* line = table + lineStrideElements * y;
const int numPoints = line[0];
int n = numPoints << 1;
if (n > 0)
if (numPoints >= maxEdgesPerLine)
{
while (n > 0)
{
const int cx = line [n - 1];
if (cx <= x)
{
if (cx == x)
{
line [n] += winding;
return;
}
break;
}
n -= 2;
}
if (numPoints >= maxEdgesPerLine)
{
remapTableForNumEdges (maxEdgesPerLine + juce_edgeTableDefaultEdgesPerLine);
jassert (numPoints < maxEdgesPerLine);
line = table + lineStrideElements * y;
}
memmove (line + (n + 3), line + (n + 1), sizeof (int) * (size_t) ((numPoints << 1) - n));
remapTableForNumEdges (maxEdgesPerLine + juce_edgeTableDefaultEdgesPerLine);
jassert (numPoints < maxEdgesPerLine);
line = table + lineStrideElements * y;
}
line[0]++;
int n = numPoints << 1;
line [n + 1] = x;
line [n + 2] = winding;
line[0]++;
}
void EdgeTable::addEdgePointPair (int x1, int x2, int y, int winding)
{
jassert (y >= 0 && y < bounds.getHeight());
int* line = table + lineStrideElements * y;
const int numPoints = line[0];
if (numPoints + 1 >= maxEdgesPerLine)
{
remapTableForNumEdges (maxEdgesPerLine + juce_edgeTableDefaultEdgesPerLine);
jassert (numPoints < maxEdgesPerLine);
line = table + lineStrideElements * y;
}
line[0] += 2;
int n = numPoints << 1;
line [n + 1] = x1;
line [n + 2] = winding;
line [n + 3] = x2;
line [n + 4] = -winding;
}
void EdgeTable::translate (float dx, const int dy) noexcept

View file

@ -55,6 +55,9 @@ public:
/** Creates an edge table containing a rectangle list. */
explicit EdgeTable (const RectangleList<int>& rectanglesToAdd);
/** Creates an edge table containing a rectangle list. */
explicit EdgeTable (const RectangleList<float>& rectanglesToAdd);
/** Creates an edge table containing a rectangle. */
explicit EdgeTable (const Rectangle<float>& rectangleToAdd);
@ -185,12 +188,18 @@ public:
private:
//==============================================================================
// table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc
struct LineItem { int x, level; };
struct LineSorter;
HeapBlock<int> table;
Rectangle<int> bounds;
int maxEdgesPerLine, lineStrideElements;
bool needToCheckEmptinesss;
void allocate();
void clearLineSizes() noexcept;
void addEdgePoint (int x, int y, int winding);
void addEdgePointPair (int x1, int x2, int y, int winding);
void remapTableForNumEdges (int newNumEdgesPerLine);
void intersectWithEdgeTableLine (int y, const int* otherLine);
void clipEdgeTableLineToRange (int* line, int x1, int x2) noexcept;

View file

@ -610,6 +610,16 @@ public:
*r *= scaleFactor;
}
/** Applies a transform to all the rectangles.
Obviously this will create a mess if the transform involves any
rotation or skewing.
*/
void transformAll (const AffineTransform& transform) noexcept
{
for (RectangleType* r = rects.begin(), * const e = rects.end(); r != e; ++r)
*r = r->transformedBy (transform);
}
//==============================================================================
/** Creates a Path object to represent this region. */
Path toPath() const

View file

@ -88,7 +88,7 @@ public:
float getPhysicalPixelScaleFactor() const noexcept
{
return isOnlyTranslated ? 1.0f : complexTransform.getScaleFactor();
return isOnlyTranslated ? 1.0f : std::abs (complexTransform.getScaleFactor());
}
void moveOriginInDeviceSpace (Point<int> delta) noexcept
@ -1549,6 +1549,7 @@ struct ClipRegions
EdgeTableRegion (const Rectangle<int>& r) : edgeTable (r) {}
EdgeTableRegion (const Rectangle<float>& r) : edgeTable (r) {}
EdgeTableRegion (const RectangleList<int>& r) : edgeTable (r) {}
EdgeTableRegion (const RectangleList<float>& r) : edgeTable (r) {}
EdgeTableRegion (const Rectangle<int>& bounds, const Path& p, const AffineTransform& t) : edgeTable (bounds, p, t) {}
EdgeTableRegion (const EdgeTableRegion& other) : Base(), edgeTable (other.edgeTable) {}
@ -2207,6 +2208,28 @@ public:
}
}
void fillRectList (const RectangleList<float>& list)
{
if (clip != nullptr)
{
if (! transform.isRotated)
{
RectangleList<float> transformed (list);
if (transform.isOnlyTranslated)
transformed.offsetAll (transform.offset.toFloat());
else
transformed.transformAll (transform.getTransform());
fillShape (new EdgeTableRegionType (transformed), false);
}
else
{
fillPath (list.toPath(), AffineTransform::identity);
}
}
}
void fillPath (const Path& path, const AffineTransform& t)
{
if (clip != nullptr)
@ -2582,6 +2605,7 @@ public:
void setOpacity (float newOpacity) override { stack->fillType.setOpacity (newOpacity); }
void setInterpolationQuality (Graphics::ResamplingQuality quality) override { stack->interpolationQuality = quality; }
void fillRect (const Rectangle<int>& r, bool replace) override { stack->fillRect (r, replace); }
void fillRectList (const RectangleList<float>& list) override { stack->fillRectList (list); }
void fillPath (const Path& path, const AffineTransform& t) override { stack->fillPath (path, t); }
void drawImage (const Image& im, const AffineTransform& t) override { stack->drawImage (im, t); }
void drawVerticalLine (int x, float top, float bottom) override { if (top < bottom) stack->fillRect (Rectangle<float> ((float) x, top, 1.0f, bottom - top)); }

View file

@ -60,6 +60,7 @@ public:
//==============================================================================
void fillRect (const Rectangle<int>&, bool replaceExistingContents) override;
void fillRectList (const RectangleList<float>&) override;
void fillPath (const Path&, const AffineTransform&) override;
void drawImage (const Image& sourceImage, const AffineTransform&) override;

View file

@ -556,6 +556,34 @@ void CoreGraphicsContext::drawHorizontalLine (const int y, float left, float rig
}
}
void CoreGraphicsContext::fillRectList (const RectangleList<float>& list)
{
HeapBlock<CGRect> rects (list.getNumRectangles());
size_t num = 0;
for (const Rectangle<float>* r = list.begin(), * const e = list.end(); r != e; ++r)
rects[num++] = CGRectMake (r->getX(), flipHeight - r->getBottom(), r->getWidth(), r->getHeight());
if (state->fillType.isColour())
{
CGContextFillRects (context, rects, num);
}
else if (state->fillType.isGradient())
{
CGContextSaveGState (context);
CGContextFillRects (context, rects, num);
drawGradient();
CGContextRestoreGState (context);
}
else
{
CGContextSaveGState (context);
CGContextFillRects (context, rects, num);
drawImage (state->fillType.image, state->fillType.transform, true);
CGContextRestoreGState (context);
}
}
void CoreGraphicsContext::setFont (const Font& newFont)
{
if (state->font != newFont)

View file

@ -185,6 +185,12 @@ public:
renderingTarget->SetTransform (D2D1::IdentityMatrix());
}
void fillRectList (const RectangleList<float>& list)
{
for (const Rectangle<float>* r = list.begin(), * const e = list.end(); r != e; ++r)
fillRect (*r);
}
void fillPath (const Path& p, const AffineTransform& transform)
{
currentState->createBrush();

View file

@ -136,7 +136,7 @@ static bool canUseMultiTouch()
return registerTouchWindow != nullptr;
}
static inline Rectangle<int> rectangleFromRECT (const RECT& r) noexcept
static Rectangle<int> rectangleFromRECT (const RECT& r) noexcept
{
return Rectangle<int>::leftTopRightBottom ((int) r.left, (int) r.top, (int) r.right, (int) r.bottom);
}
@ -164,18 +164,22 @@ static void setDPIAwareness()
if (JUCEApplication::isStandaloneApp())
{
if (setProcessDPIAware == nullptr)
{
setProcessDPIAware = (SetProcessDPIAwareFunc) getUser32Function ("SetProcessDPIAware");
if (setProcessDPIAware != nullptr)
setProcessDPIAware();
if (setProcessDPIAware != nullptr)
setProcessDPIAware();
}
}
}
inline double getDPI()
static double getDPI()
{
setDPIAwareness();
HDC dc = GetDC (0);
const double dpi = (GetDeviceCaps (dc, LOGPIXELSX)
+ GetDeviceCaps (dc, LOGPIXELSY)) / 2.0;
+ GetDeviceCaps (dc, LOGPIXELSY)) / 2.0;
ReleaseDC (0, dc);
return dpi;
}
@ -1366,7 +1370,7 @@ private:
return ! component.isOpaque();
}
inline bool hasTitleBar() const noexcept { return (styleFlags & windowHasTitleBar) != 0; }
bool hasTitleBar() const noexcept { return (styleFlags & windowHasTitleBar) != 0; }
void setIcon (const Image& newIcon)
@ -3234,7 +3238,7 @@ void Desktop::Displays::findDisplays (float masterScale)
d.dpi = dpi;
if (i == 0)
d.userArea = d.userArea.getIntersection (rectangleFromRECT (workArea));
d.userArea = d.userArea.getIntersection (rectangleFromRECT (workArea) / masterScale);
displays.add (d);
}

View file

@ -80,18 +80,17 @@ public:
return true;
}
void draw (CodeEditorComponent& owner, Graphics& g, const Font& fontToUse,
const float rightClip, const float x, const int y,
const int lineH, const float characterWidth,
const Colour highlightColour) const
void getHighlightArea (RectangleList<float>& area, float x, int y, int lineH, float characterWidth) const
{
if (highlightColumnStart < highlightColumnEnd)
{
g.setColour (highlightColour);
g.fillRect (roundToInt (x + highlightColumnStart * characterWidth), y,
roundToInt ((highlightColumnEnd - highlightColumnStart) * characterWidth), lineH);
}
area.addWithoutMerging (Rectangle<float> (x + highlightColumnStart * characterWidth, (float) y,
(highlightColumnEnd - highlightColumnStart) * characterWidth, (float) lineH));
}
void draw (CodeEditorComponent& owner, Graphics& g, const Font& fontToUse,
const float rightClip, const float x, const int y,
const int lineH, const float characterWidth) const
{
Colour lastColour (0x00000001);
AttributedString as;
@ -466,7 +465,6 @@ void CodeEditorComponent::paint (Graphics& g)
g.reduceClipRegion (gutterSize, 0, verticalScrollBar.getX() - gutterSize, horizontalScrollBar.getY());
g.setFont (font);
const Colour highlightColour (findColour (CodeEditorComponent::highlightColourId));
const Rectangle<int> clip (g.getClipBounds());
const int firstLineToDraw = jmax (0, clip.getY() / lineHeight);
@ -474,10 +472,18 @@ void CodeEditorComponent::paint (Graphics& g)
const float x = (float) (gutterSize - xOffset * charWidth);
const float rightClip = (float) clip.getRight();
{
RectangleList<float> highlightArea;
for (int i = firstLineToDraw; i < lastLineToDraw; ++i)
lines.getUnchecked(i)->getHighlightArea (highlightArea, x, lineHeight * i, lineHeight, charWidth);
g.setColour (findColour (CodeEditorComponent::highlightColourId));
g.fillRectList (highlightArea);
}
for (int i = firstLineToDraw; i < lastLineToDraw; ++i)
lines.getUnchecked(i)->draw (*this, g, font, rightClip,
x, lineHeight * i, lineHeight,
charWidth, highlightColour);
lines.getUnchecked(i)->draw (*this, g, font, rightClip, x, lineHeight * i, lineHeight, charWidth);
}
void CodeEditorComponent::setScrollbarThickness (const int thickness)