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:
parent
641cb754f0
commit
dbf7053861
18 changed files with 357 additions and 143 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)); }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue