31 static auto compareFont (
const Font& a,
const Font& b) {
return Font::compare (a, b); }
34static auto operator< (
const Font& a,
const Font& b)
36 return GraphicsFontHelpers::compareFont (a, b);
42 const auto tie = [] (
auto& t) {
return std::make_tuple (t.getX(), t.getY(), t.getWidth(), t.getHeight()); };
46static auto operator< (
const Justification& a,
const Justification& b)
48 return a.getFlags() < b.getFlags();
54 struct ConfiguredArrangement
56 void draw (
const Graphics& g)
const { arrangement.draw (g, transform); }
58 GlyphArrangement arrangement;
62 template <
typename ArrangementArgs>
63 class GlyphArrangementCache
final :
public DeletedAtShutdown
66 GlyphArrangementCache() =
default;
73 template <
typename ConfigureArrangement>
86 const auto iter = cache.find (args);
88 if (iter != cache.end())
90 if (iter->second.cachePosition != cacheOrder.begin())
91 cacheOrder.splice (cacheOrder.begin(), cacheOrder, iter->second.cachePosition);
96 auto result = cache.emplace (std::move (args), CachedGlyphArrangement {
configureArrangement (args), {} }).first;
97 cacheOrder.push_front (result);
101 cached->second.cachePosition = cacheOrder.begin();
102 cached->second.configured.draw (g);
104 while (cache.size() > cacheSize)
106 cache.erase (cacheOrder.back());
107 cacheOrder.pop_back();
114 struct CachedGlyphArrangement
117 ConfiguredArrangement configured;
121 static constexpr size_t cacheSize = 128;
124 CriticalSection
lock;
127 template <
typename ArrangementArgs>
131 template <
typename Type>
135 const int maxVal = 0x3fffffff;
139 && (
int) w >= 0 && (
int) w <=
maxVal
140 && (
int) h >= 0 && (
int) h <=
maxVal);
143 return { x, y, w, h };
150 context (*contextHolder)
163 saveStateIfPending();
165 context.setFont (
Font());
176 saveStateIfPending();
177 return context.clipToRectangle (area);
187 saveStateIfPending();
188 return context.clipToRectangleList (
clipRegion);
193 saveStateIfPending();
194 context.clipToPath (path, transform);
195 return ! context.isClipEmpty();
200 saveStateIfPending();
201 context.clipToImageAlpha (image, transform);
202 return ! context.isClipEmpty();
207 saveStateIfPending();
213 return context.isClipEmpty();
218 return context.getClipBounds();
223 saveStateIfPending();
224 saveStatePending =
true;
229 if (saveStatePending)
230 saveStatePending =
false;
232 context.restoreState();
235void Graphics::saveStateIfPending()
237 if (saveStatePending)
239 saveStatePending =
false;
246 saveStateIfPending();
257 saveStateIfPending();
258 context.addTransform (transform);
263 return context.clipRegionIntersects (area);
268 saveStateIfPending();
274 context.endTransparencyLayer();
280 saveStateIfPending();
286 saveStateIfPending();
302 saveStateIfPending();
304 context.setOpacity (opacity);
309 saveStateIfPending();
316 saveStateIfPending();
327 return context.getFont();
350 auto tie()
const noexcept {
return std::tie (font, text, startX, baselineY); }
351 bool operator< (
const ArrangementArgs& other)
const {
return tie() < other.tie(); }
355 const int startX, baselineY, flags;
362 arrangement.
addLineOfText (args.font, args.text, (
float) args.startX, (
float) args.baselineY);
374 return ConfiguredArrangement { std::move (arrangement), std::move (transform) };
377 GlyphArrangementCache<ArrangementArgs>::getInstance()->draw (*
this,
391 auto tie()
const noexcept {
return std::tie (font, text, startX, baselineY, maximumLineWidth, justification, leading); }
392 bool operator< (
const ArrangementArgs& other)
const {
return tie() < other.tie(); }
396 const int startX, baselineY, maximumLineWidth;
405 (
float) args.startX, (
float) args.baselineY, (
float) args.maximumLineWidth,
406 args.justification, args.leading);
407 return ConfiguredArrangement { std::move (arrangement), {} };
410 GlyphArrangementCache<ArrangementArgs>::getInstance()->draw (*
this,
423 auto tie()
const noexcept {
return std::tie (font, text, area, justificationType, useEllipsesIfTooBig); }
424 bool operator< (
const ArrangementArgs& other)
const {
return tie() < other.tie(); }
430 const bool useEllipsesIfTooBig;
437 args.area.getWidth(), args.useEllipsesIfTooBig);
440 args.area.getX(), args.area.getY(), args.area.getWidth(), args.area.getHeight(),
441 args.justificationType);
442 return ConfiguredArrangement { std::move (arrangement), {} };
445 GlyphArrangementCache<ArrangementArgs>::getInstance()->draw (*
this,
465 const float minimumHorizontalScale)
const
467 if (text.
isEmpty() || area.
isEmpty() || ! context.clipRegionIntersects (area))
472 auto tie()
const noexcept {
return std::tie (font, text, area, justification, maximumNumberOfLines, minimumHorizontalScale); }
473 bool operator< (
const ArrangementArgs& other)
const noexcept {
return tie() < other.tie(); }
479 const int maximumNumberOfLines;
480 const float minimumHorizontalScale;
487 args.area.getX(), args.area.getY(),
488 args.area.getWidth(), args.area.getHeight(),
490 args.maximumNumberOfLines,
491 args.minimumHorizontalScale);
492 return ConfiguredArrangement { std::move (arrangement), {} };
495 GlyphArrangementCache<ArrangementArgs>::getInstance()->draw (*
this,
503 const float minimumHorizontalScale)
const
512 context.fillRect (r,
false);
517 context.fillRect (r);
537 for (
auto& r : rects)
538 context.fillRect (r,
false);
553 context.restoreState();
561 if (! (context.isClipEmpty() || path.
isEmpty()))
567 if (! (context.isClipEmpty() || path.
isEmpty()))
568 context.fillPath (path, transform);
605 context.fillRectList (rects);
689 context.fillRect (area);
704 for (
int i = 0; i < 2; ++i)
715 context.fillRectList (
checks);
720 context.restoreState();
725void Graphics::drawVerticalLine (
const int x,
float top,
float bottom)
const
731void Graphics::drawHorizontalLine (
const int y,
float left,
float right)
const
739 context.drawLine (line);
742void Graphics::drawLine (
float x1,
float y1,
float x2,
float y2)
const
747void Graphics::drawLine (
float x1,
float y1,
float x2,
float y2,
float lineThickness)
const
752void Graphics::drawLine (
Line<float> line,
const float lineThickness)
const
759void Graphics::drawDashedLine (
Line<float> line,
const float* dashLengths,
760 int numDashLengths,
float lineThickness,
int n)
const
762 jassert (n >= 0 && n < numDashLengths);
769 const double onePixAlpha = 1.0 / totalLen;
771 for (
double alpha = 0.0; alpha < 1.0;)
775 const double lastAlpha = alpha;
776 alpha += dashLengths [n] * onePixAlpha;
777 n = (n + 1) % numDashLengths;
782 line.
getStart() + (delta *
jmin (1.0, alpha)).toFloat());
785 drawLine (segment, lineThickness);
787 context.drawLine (segment);
796 saveStateIfPending();
797 context.setInterpolationQuality (newQuality);
801void Graphics::drawImageAt (
const Image& imageToDraw,
int x,
int y,
bool fillAlphaChannel)
const
803 drawImageTransformed (imageToDraw,
804 AffineTransform::translation ((
float) x, (
float) y),
809 RectanglePlacement placementWithinTarget,
bool fillAlphaChannelWithCurrentBrush)
const
812 drawImageTransformed (imageToDraw,
814 fillAlphaChannelWithCurrentBrush);
817void Graphics::drawImageWithin (
const Image& imageToDraw,
int dx,
int dy,
int dw,
int dh,
818 RectanglePlacement placementWithinTarget,
bool fillAlphaChannelWithCurrentBrush)
const
820 drawImage (imageToDraw, coordsToRectangle (dx, dy, dw, dh).toFloat(),
821 placementWithinTarget, fillAlphaChannelWithCurrentBrush);
824void Graphics::drawImage (
const Image& imageToDraw,
825 int dx,
int dy,
int dw,
int dh,
826 int sx,
int sy,
int sw,
int sh,
827 const bool fillAlphaChannelWithCurrentBrush)
const
829 if (imageToDraw.
isValid() && context.clipRegionIntersects (coordsToRectangle (dx, dy, dw, dh)))
830 drawImageTransformed (imageToDraw.
getClippedImage (coordsToRectangle (sx, sy, sw, sh)),
831 AffineTransform::scale ((
float) dw / (
float) sw, (
float) dh / (
float) sh)
832 .translated ((
float) dx, (
float) dy),
833 fillAlphaChannelWithCurrentBrush);
836void Graphics::drawImageTransformed (
const Image& imageToDraw,
838 const bool fillAlphaChannelWithCurrentBrush)
const
840 if (imageToDraw.
isValid() && ! context.isClipEmpty())
842 if (fillAlphaChannelWithCurrentBrush)
845 context.clipToImageAlpha (imageToDraw, transform);
847 context.restoreState();
851 context.drawImage (imageToDraw, transform);
857Graphics::ScopedSaveState::ScopedSaveState (
Graphics& g) : context (g)
862Graphics::ScopedSaveState::~ScopedSaveState()
Describes the layout and colours that should be used to paint a colour gradient.
Represents a colour, also including a transparency value.
Represents a colour or fill pattern to use for rendering paths.
Represents a particular font, including its size, style, etc.
Font withHeight(float height) const
Returns a copy of this font with a new height.
A set of glyphs, each with a position.
void addLineOfText(const Font &font, const String &text, float x, float y)
Appends a line of text to the arrangement.
Rectangle< float > getBoundingBox(int startIndex, int numGlyphs, bool includeWhitespace) const
Finds the smallest rectangle that will enclose a subset of the glyphs.
int getNumGlyphs() const noexcept
Returns the total number of glyphs in the arrangement.
void addFittedText(const Font &font, const String &text, float x, float y, float width, float height, Justification layout, int maximumLinesToUse, float minimumHorizontalScale=0.0f)
Tries to fit some text within a given space.
void addCurtailedLineOfText(const Font &font, const String &text, float x, float y, float maxWidthPixels, bool useEllipsis)
Adds a line of text, truncating it if it's wider than a specified size.
void addJustifiedText(const Font &font, const String &text, float x, float y, float maxLineWidth, Justification horizontalLayout, float leading=0.0f)
Adds some multi-line text, breaking lines at word-boundaries if they are too wide.
void justifyGlyphs(int startIndex, int numGlyphs, float x, float y, float width, float height, Justification justification)
Justifies a set of glyphs within a given space.
A graphics context, used for drawing a component or image.
void saveState()
Saves the current graphics state on an internal stack.
void setOpacity(float newOpacity)
Changes the opacity to use with the current colour.
void drawText(const String &text, int x, int y, int width, int height, Justification justificationType, bool useEllipsesIfTooBig=true) const
Draws a line of text within a specified rectangle.
void drawFittedText(const String &text, int x, int y, int width, int height, Justification justificationFlags, int maximumNumberOfLines, float minimumHorizontalScale=0.0f) const
Tries to draw a text string inside a given space.
Font getCurrentFont() const
Returns the currently selected font.
void setFont(const Font &newFont)
Changes the font to use for subsequent text-drawing functions.
void fillRectList(const RectangleList< float > &rectangles) const
Fills a set of rectangles using the current colour or brush.
void restoreState()
Restores a graphics state that was previously saved with saveState().
ResamplingQuality
Types of rendering quality that can be specified when drawing images.
@ mediumResamplingQuality
Uses bilinear interpolation for upsampling and area-averaging for downsampling.
bool isClipEmpty() const
Returns true if no drawing can be done because the clip region is zero.
void setFillType(const FillType &newFill)
Changes the current fill settings.
void drawArrow(Line< float > line, float lineThickness, float arrowheadWidth, float arrowheadLength) const
Draws a line with an arrowhead at its end.
void setGradientFill(const ColourGradient &gradient)
Sets the context to use a gradient for its fill pattern.
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.
void excludeClipRegion(Rectangle< int > rectangleToExclude)
Excludes a rectangle to stop it being drawn into.
void drawRect(int x, int y, int width, int height, int lineThickness=1) const
Draws a rectangular outline, using the current colour or brush.
void endTransparencyLayer()
Completes a drawing operation to a temporary semi-transparent buffer.
void setTiledImageFill(const Image &imageToUse, int anchorX, int anchorY, float opacity)
Sets the context to use a tiled image pattern for filling.
void addTransform(const AffineTransform &transform)
Adds a transformation which will be performed on all the graphics operations that the context subsequ...
bool clipRegionIntersects(Rectangle< int > area) const
Checks whether a rectangle overlaps the context's clipping region.
void fillRect(Rectangle< int > rectangle) const
Fills a rectangle with the current colour or brush.
void beginTransparencyLayer(float layerOpacity)
Begins rendering to an off-screen bitmap which will later be flattened onto the current context with ...
void drawMultiLineText(const String &text, int startX, int baselineY, int maximumLineWidth, Justification justification=Justification::left, float leading=0.0f) const
Draws text across multiple lines.
void fillPath(const Path &path) const
Fills a path using the currently selected colour or brush.
Graphics(const Image &imageToDrawOnto)
Creates a Graphics object to draw directly onto the given image.
void resetToDefaultState()
Resets the current colour, brush, and font to default settings.
void drawEllipse(float x, float y, float width, float height, float lineThickness) const
Draws an elliptical stroke using the current colour or brush.
void drawSingleLineText(const String &text, int startX, int baselineY, Justification justification=Justification::left) const
Draws a one-line text string.
bool reduceClipRegion(int x, int y, int width, int height)
Intersects the current clipping region with another region.
void fillCheckerBoard(Rectangle< float > area, float checkWidth, float checkHeight, Colour colour1, Colour colour2) const
Fills a rectangle with a checkerboard pattern, alternating between two colours.
Rectangle< int > getClipBounds() const
Returns the position of the bounding box for the current clipping region.
bool isVectorDevice() const
Returns true if this context is drawing to a vector-based device, such as a printer.
void setColour(Colour newColour)
Changes the current drawing colour.
void strokePath(const Path &path, const PathStrokeType &strokeType, const AffineTransform &transform={}) const
Draws a path's outline using the currently selected colour or brush.
void fillAll() const
Fills the context's entire clip region with the current colour or brush.
void setOrigin(Point< int > newOrigin)
Moves the position of the context's origin.
void drawRoundedRectangle(float x, float y, float width, float height, float cornerSize, float lineThickness) const
Uses the current colour or brush to draw the outline of a rectangle with rounded corners.
void fillEllipse(float x, float y, float width, float height) const
Fills an ellipse with the current colour or brush.
Holds a fixed-size bitmap.
Image getClippedImage(const Rectangle< int > &area) const
Returns an image which refers to a subsection of this image.
Rectangle< int > getBounds() const noexcept
Returns a rectangle with the same size as this image.
bool isValid() const noexcept
Returns true if this image isn't null.
Represents a type of justification to be used when positioning graphical items.
@ horizontallyJustified
Indicates that lines of text should be spread out to fill the maximum width available,...
@ left
Indicates that the item should be aligned against the left edge of the available space.
@ horizontallyCentred
Indicates that the item should be placed in the centre between the left and right sides of the availa...
@ right
Indicates that the item should be aligned against the right edge of the available space.
int getOnlyVerticalFlags() const noexcept
Returns just the flags from this object that deal with vertical layout.
int getOnlyHorizontalFlags() const noexcept
Returns just the flags from this object that deal with horizontal layout.
Point< ValueType > getEnd() const noexcept
Returns the line's end point.
Point< ValueType > getStart() const noexcept
Returns the line's start point.
Interface class for graphics context objects, used internally by the Graphics class.
virtual bool isVectorDevice() const =0
Returns true if this device is vector-based, e.g.
virtual void setOrigin(Point< int >)=0
Moves the origin to a new position.
Describes a type of stroke used to render a solid outline along a path.
void createStrokedPath(Path &destPath, const Path &sourcePath, const AffineTransform &transform=AffineTransform(), float extraAccuracy=1.0f) const
Applies this stroke type to a path and returns the resultant stroke as another Path.
A path is a sequence of lines and curves that may either form a closed shape or be open-ended.
void addRoundedRectangle(float x, float y, float width, float height, float cornerSize)
Adds a rectangle with rounded corners to the path.
void addEllipse(float x, float y, float width, float height)
Adds an ellipse to the path.
void addLineSegment(Line< float > line, float lineThickness)
Adds a line with a specified thickness.
void addArrow(Line< float > line, float lineThickness, float arrowheadWidth, float arrowheadLength)
Adds a line with an arrowhead on the end.
void setUsingNonZeroWinding(bool isNonZeroWinding) noexcept
Changes the winding-rule to be used when filling the path.
bool isEmpty() const noexcept
Returns true if the path doesn't contain any lines or curves.
A pair of (x, y) coordinates.
ValueType getDistanceFromOrigin() const noexcept
Returns the straight-line distance between this point and the origin.
Maintains a set of rectangles as a complex region.
void addWithoutMerging(RectangleType rect)
Dumbly adds a rectangle to the list without checking for overlaps.
Defines the method used to position some kind of rectangular object within a rectangular viewport.
AffineTransform getTransformToFit(const Rectangle< float > &source, const Rectangle< float > &destination) const noexcept
Returns the transform that should be applied to these source coordinates to fit them into the destina...
Manages a rectangle and allows geometric operations to be performed on it.
ValueType getRight() const noexcept
Returns the x coordinate of the rectangle's right-hand-side.
Rectangle< float > toFloat() const noexcept
Casts this rectangle to a Rectangle<float>.
Rectangle removeFromRight(ValueType amountToRemove) noexcept
Removes a strip from the right-hand edge of this rectangle, reducing this rectangle by the specified ...
ValueType getX() const noexcept
Returns the x coordinate of the rectangle's left-hand-side.
Rectangle< int > getSmallestIntegerContainer() const noexcept
Returns the smallest integer-aligned rectangle that completely contains this one.
Rectangle removeFromBottom(ValueType amountToRemove) noexcept
Removes a strip from the bottom of this rectangle, reducing this rectangle by the specified amount an...
Rectangle getIntersection(Rectangle other) const noexcept
Returns the region that is the overlap between this and another rectangle.
ValueType getWidth() const noexcept
Returns the width of the rectangle.
Rectangle removeFromTop(ValueType amountToRemove) noexcept
Removes a strip from the top of this rectangle, reducing this rectangle by the specified amount and r...
Rectangle reduced(ValueType deltaX, ValueType deltaY) const noexcept
Returns a rectangle that is smaller than this one by a given amount.
Rectangle removeFromLeft(ValueType amountToRemove) noexcept
Removes a strip from the left-hand edge of this rectangle, reducing this rectangle by the specified a...
ValueType getY() const noexcept
Returns the y coordinate of the rectangle's top edge.
bool isEmpty() const noexcept
Returns true if the rectangle's width or height are zero or less.
ValueType getHeight() const noexcept
Returns the height of the rectangle.
Rectangle expanded(ValueType deltaX, ValueType deltaY) const noexcept
Returns a rectangle that is larger than this one by a given amount.
bool isEmpty() const noexcept
Returns true if the string contains no characters.
#define JUCE_DECLARE_SINGLETON(Classname, doNotRecreateAfterDeletion)
Macro to generate the appropriate methods and boilerplate for a singleton class.
constexpr bool approximatelyEqual(Type a, Type b, Tolerance< Type > tolerance=Tolerance< Type >{} .withAbsolute(std::numeric_limits< Type >::min()) .withRelative(std::numeric_limits< Type >::epsilon()))
Returns true if the two floating-point numbers are approximately equal.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
CriticalSection::ScopedTryLockType ScopedTryLock
Automatically tries to lock and unlock a CriticalSection object.
Used by the JUCE_DECLARE_SINGLETON macros to manage a static pointer to a singleton instance.