and the implementation:
// We need RenderingPrimitive declaration
// We need Juce too
// The implementation here is all private, so it's not possible to use the members directly, only through the base class declaration
class AffineTransform : public TwoDimensionalRendering::AffineTransform
{
juce::AffineTransform object;
/** Transform the given point */
virtual void transformPoint (double & x, double & y) const { object.transformPoint(x, y); }
/** Get the translated transform for this object */
virtual const TwoDimensionalRendering::AffineTransform * translated (const float deltaX, const float deltaY) const { return new AffineTransform(object.translated(deltaX, deltaY)); }
/** Get the rotated transform for this object */
virtual const TwoDimensionalRendering::AffineTransform * rotated (const float angleInRadians) const { return new AffineTransform(object.rotated(angleInRadians)); }
/** Get the rotated transform for this object around the given pivot */
virtual const TwoDimensionalRendering::AffineTransform * rotated (const float angleInRadians, const float pivotX, const float pivotY) const { return new AffineTransform(object.rotated(angleInRadians, pivotX, pivotY)); }
/** Get the scaled transform for this object */
virtual const TwoDimensionalRendering::AffineTransform * scaled (const float factorX, const float factorY) const { return new AffineTransform(object.scaled(factorX, factorY)); }
/** Get the sheared transform for this object */
virtual const TwoDimensionalRendering::AffineTransform * sheared (const float shearX, const float shearY) const { return new AffineTransform(object.sheared(shearX, shearY)); }
/** Get the inverse matrix of this one */
virtual const TwoDimensionalRendering::AffineTransform * inverted () const { return new AffineTransform(object.inverted()); }
/** Get the result of the two transformation */
virtual const TwoDimensionalRendering::AffineTransform * followedBy (const TwoDimensionalRendering::AffineTransform & other) const { return new AffineTransform(object.followedBy(((AffineTransform&)other).object)); }
/** Check if this transform is an identity matrix */
virtual bool isIdentity () const throw () { return object.isIdentity(); }
/** Check if this transform is a singularity matrix */
virtual bool isSingularity () const throw () { return object.isSingularity(); }
/** Constructor */
AffineTransform(const juce::AffineTransform & _obj) : object(_obj) {}
/** The factory is our friend */
friend class AffineTransformFactory;
friend class Path;
friend class PathStrokeType;
friend class Brush;
friend class Graphics;
};
// The implementation here is all private, so it's not possible to use the members directly, only through the base class declaration
class AffineTransformFactory : public TwoDimensionalRendering::AffineTransformFactory
{
virtual const TwoDimensionalRendering::AffineTransform * createIdentity () const { return new AffineTransform(juce::AffineTransform()); }
virtual const TwoDimensionalRendering::AffineTransform * createTranslation (const float deltaX, const float deltaY) const { return new AffineTransform(juce::AffineTransform::translation(deltaX, deltaY)); }
virtual const TwoDimensionalRendering::AffineTransform * createRotation (const float angleInRadians) const { return new AffineTransform(juce::AffineTransform::rotation(angleInRadians)); }
virtual const TwoDimensionalRendering::AffineTransform * createRotation (const float angleInRadians, const float pivotX, const float pivotY) const { return new AffineTransform(juce::AffineTransform::rotation(angleInRadians, pivotX, pivotY)); }
virtual const TwoDimensionalRendering::AffineTransform * createScale (const float factorX, const float factorY) const { return new AffineTransform(juce::AffineTransform::scale(factorX, factorY)); }
virtual void deleteTransform (const TwoDimensionalRendering::AffineTransform * transform) const { delete (AffineTransform*)transform; }
};
class Path : public TwoDimensionalRendering::Path
{
juce::Path path;
/** Check if the path is currently empty */
virtual bool isEmpty () const throw () { return path.isEmpty(); }
/** Get the bounds for this path */
virtual void getBounds (float & x, float & y, float & w, float & h) const throw () { path.getBounds(x, y, w, h); }
/** Get the bounds after the given transformation */
virtual void getBoundsTransformed (const TwoDimensionalRendering::AffineTransform & transform, float & x, float & y, float & w, float & h) const throw () { path.getBoundsTransformed(((AffineTransform&)transform).object, x, y, w, h); }
/** Return true if the path contains the given point */
virtual bool contains (const float x, const float y) const throw () { return path.contains(x, y); }
/** Return true if the path intersect the given line */
virtual bool intersectsLine (const float x1, const float y1, const float x2, const float y2) throw () { return path.intersectsLine(x1, y1, x2, y2); }
/** Clear this path */
virtual void clear () throw () { path.clear(); }
/** Start new sub path at the given position */
virtual void startNewSubPath (const float startX, const float startY) throw () { path.startNewSubPath(startX, startY); }
/** Close the sub path */
virtual void closeSubPath () throw () { path.closeSubPath(); }
/** Append a line segment from the current position to the given position */
virtual void lineTo (const float endX, const float endY) throw () { path.lineTo(endX, endY); }
/** Append a quadratic curve from the current position to the given position */
virtual void quadraticTo (const float controlPointX, const float controlPointY, const float endPointX, const float endPointY) throw () { path.quadraticTo(controlPointX, controlPointY, endPointX, endPointY); }
/** Append a Bezier curve from the current position to the given position */
virtual void cubicTo (const float controlPoint1X, const float controlPoint1Y, const float controlPoint2X, const float controlPoint2Y, const float endPointX, const float endPointY) throw () { path.cubicTo(controlPoint1X, controlPoint1Y, controlPoint2X, controlPoint2Y, endPointX, endPointY); }
/** Get the current position */
virtual void getCurrentPosition (float & x, float & y) const throw () { juce::Point pt = path.getCurrentPosition(); x = pt.getX(), y = pt.getY(); }
/** Add a rectangle as a sub path */
virtual void addRectangle (const float x, const float y, const float w, const float h) throw () { path.addRectangle(x, y, w, h); }
/** Add a rectangle with rounded corner as a sub path */
virtual void addRoundedRectangle (const float x, const float y, const float w, const float h, float cornerSizeX, float cornerSizeY) throw () { path.addRoundedRectangle(x, y, w, h, cornerSizeX, cornerSizeY); }
/** Add a triangle as a sub path */
virtual void addTriangle (const float x1, const float y1, const float x2, const float y2, const float x3, const float y3) throw () { path.addTriangle(x1, y1, x2, y2, x3, y3); }
/** Add a quadrilateral as a sub path */
virtual void addQuadrilateral (const float x1, const float y1, const float x2, const float y2, const float x3, const float y3, const float x4, const float y4) throw () { path.addQuadrilateral(x1, y1, x2, y2, x3, y3, x4, y4); }
/** Add an ellipse as a sub path */
virtual void addEllipse (const float x, const float y, const float width, const float height) throw () { path.addEllipse(x, y, width, height); }
/** Add an arc as a sub path */
virtual void addArc (const float x, const float y, const float width, const float height, const float fromRadians, const float toRadians, const bool startAsNewSubPath = false) throw () { path.addArc(x, y, width, height, fromRadians, toRadians, startAsNewSubPath); }
/** Add a centred arc as a sub path */
virtual void addCentredArc (const float centreX, const float centreY, const float radiusX, const float radiusY, const float rotationOfEllipse, const float fromRadians, const float toRadians, const bool startAsNewSubPath=false) throw () { path.addCentredArc(centreX, centreY, radiusX, radiusY, rotationOfEllipse, fromRadians, toRadians, startAsNewSubPath); }
/** Add a pie segment as a sub path */
virtual void addPieSegment (const float x, const float y, const float width, const float height, const float fromRadians, const float toRadians, const float innerCircleProportionalSize) { path.addPieSegment(x, y, width, height, fromRadians, toRadians, innerCircleProportionalSize); }
/** Add a line segment as a sub path */
virtual void addLineSegment (const float startX, const float startY, const float endX, const float endY, float lineThickness) throw () { path.addLineSegment(startX, startY, endX, endY, lineThickness); }
/** Add an arrow as a sub path */
virtual void addArrow (const float startX, const float startY, const float endX, const float endY, float lineThickness, float arrowheadWidth, float arrowheadLength) throw () { path.addArrow(startX, startY, endX, endY, lineThickness, arrowheadWidth, arrowheadLength); }
/** Add a star as a sub path */
virtual void addStar (const float centreX, const float centreY, const int numberOfPoints, const float innerRadius, const float outerRadius, const float startAngle = 0.0f) { path.addStar(centreX, centreY, numberOfPoints, innerRadius, outerRadius, startAngle); }
/** Add a bubble as a sub path */
virtual void addBubble (float bodyX, float bodyY, float bodyW, float bodyH, float cornerSize, float arrowTipX, float arrowTipY, int whichSide, float arrowPositionAlongEdgeProportional, float arrowWidth) { path.addBubble(bodyX, bodyY, bodyW, bodyH, cornerSize, arrowTipX, arrowTipY, whichSide, arrowPositionAlongEdgeProportional, arrowWidth); }
/** Add a path as a sub path */
virtual void addPath (const TwoDimensionalRendering::Path & pathToAppend, const TwoDimensionalRendering::AffineTransform & transformToApply) throw () { path.addPath(((Path&)pathToAppend).path, ((AffineTransform&)transformToApply).object); }
/** Swap this path with the given path */
virtual void swapWithPath (TwoDimensionalRendering::Path & other) { path.swapWithPath(((Path&)other).path); }
/** Apply the given transform for this path */
virtual void applyTransform (const TwoDimensionalRendering::AffineTransform & transform) throw () { path.applyTransform(((AffineTransform&)transform).object); }
/** Scale the path to fit the given bounding box */
virtual void scaleToFit (const float x, const float y, const float width, const float height, const bool preserveProportions) throw () { path.scaleToFit(x, y, width, height, preserveProportions); }
/** Get the transform used to fit the given bounding box */
virtual const TwoDimensionalRendering::AffineTransform * getTransformToScaleToFit (const float x, const float y, const float width, const float height, const bool preserveProportions) const throw () { return new AffineTransform(path.getTransformToScaleToFit(x, y, width, height, preserveProportions)); }
/** Create a new path with rounded corners */
virtual const TwoDimensionalRendering::Path * createPathWithRoundedCorners (const float cornerRadius) const throw () { return new Path(path.createPathWithRoundedCorners(cornerRadius)); }
/** Set using non-zero winding (used to change the fill mode) */
virtual void setUsingNonZeroWinding (const bool isNonZeroWinding) throw () { path.setUsingNonZeroWinding(isNonZeroWinding); }
/** Get the winding mode */
virtual bool isUsingNonZeroWinding () const throw () { return path.isUsingNonZeroWinding(); }
Path(const juce::Path & _path) : path(_path) {}
friend class PathFactory;
friend class PathStrokeType;
friend class Graphics;
};
/** This class is a wrapper of the Juce PathStrokeType class.
This is used to simplify different Juce code base in the same process. */
class PathStrokeType : public TwoDimensionalRendering::PathStrokeType
{
juce::PathStrokeType pathST;
/** Applies this stroke type to a path and returns the resultant stroke as another Path. */
virtual void createStrokedPath (TwoDimensionalRendering::Path& destPath, const TwoDimensionalRendering::Path& sourcePath, const TwoDimensionalRendering::AffineTransform& transform, const float extraAccuracy = 1.0f) const throw()
{
pathST.createStrokedPath(((Path&)destPath).path, ((Path&)sourcePath).path, ((AffineTransform&)transform).object, extraAccuracy);
}
/** Applies this stroke type to a path, creating a dashed line. */
virtual void createDashedStroke (TwoDimensionalRendering::Path& destPath, const TwoDimensionalRendering::Path& sourcePath, const float* dashLengths, int numDashLengths, const TwoDimensionalRendering::AffineTransform& transform, const float extraAccuracy = 1.0f) const throw()
{
pathST.createDashedStroke(((Path&)destPath).path, ((Path&)sourcePath).path, dashLengths, numDashLengths, ((AffineTransform&)transform).object, extraAccuracy);
}
/** Returns the stroke thickness. */
virtual float getStrokeThickness() const throw() { return pathST.getStrokeThickness(); }
/** Returns the joint style. */
virtual TwoDimensionalRendering::PathStrokeType::JointStyle getJointStyle() const throw() { return (TwoDimensionalRendering::PathStrokeType::JointStyle)(pathST.getJointStyle()); }
/** Returns the end-cap style. */
virtual TwoDimensionalRendering::PathStrokeType::EndCapStyle getEndStyle() const throw() { return (TwoDimensionalRendering::PathStrokeType::EndCapStyle)(pathST.getEndStyle()); }
PathStrokeType(const juce::PathStrokeType & type) : pathST(type) {}
friend class PathFactory;
friend class Graphics;
};
class PathFactory : public TwoDimensionalRendering::PathFactory
{
/** Create an empty path instance */
virtual TwoDimensionalRendering::Path * createEmptyPathInstance() const { return new Path(juce::Path()); }
/** Create a path stroke type object */
virtual TwoDimensionalRendering::PathStrokeType * createPathStrokeType(const float strokeThickness, const TwoDimensionalRendering::PathStrokeType::JointStyle jointStyle, const TwoDimensionalRendering::PathStrokeType::EndCapStyle endStyle) const { return new PathStrokeType(juce::PathStrokeType(strokeThickness, (juce::PathStrokeType::JointStyle)jointStyle, (juce::PathStrokeType::EndCapStyle)endStyle)); }
/** Delete a created path instance */
virtual void deletePath(TwoDimensionalRendering::Path * path) const { delete (Path*)path; }
/** Delete a path stroke type object */
virtual void deletePathStrokeType(TwoDimensionalRendering::PathStrokeType * strokeType) const { delete (PathStrokeType*)strokeType; }
};
class Colour : public TwoDimensionalRendering::Colour
{
juce::Colour colour;
/** Returns the red component of this colour. */
virtual uint8 getRed () const throw () { return colour.getRed(); }
/** Returns the green component of this colour. */
virtual uint8 getGreen () const throw () { return colour.getGreen(); }
/** Returns the blue component of this colour. */
virtual uint8 getBlue () const throw () { return colour.getBlue(); }
/** Returns the colour's alpha (opacity). */
virtual uint8 getAlpha () const throw () { return colour.getAlpha(); }
/** Returns a 32-bit integer that represents this colour. */
virtual uint32 getARGB () const throw () { return colour.getARGB(); }
/** Returns true if this colour is completely opaque. */
virtual bool isOpaque () const throw () { return colour.isOpaque(); }
/** Returns true if this colour is completely transparent. */
virtual bool isTransparent () const throw () { return colour.isTransparent(); }
/** Returns the colour's hue, saturation and brightness components all at once. */
virtual void getHSB (float & hue, float & saturation, float & brightness) const throw () { colour.getHSB(hue, saturation, brightness); }
/** Returns a colour that's the same colour as this one, but with a new alpha value. */
virtual const TwoDimensionalRendering::Colour * withAlpha (const uint8 newAlpha) const throw () { return new Colour(colour.withAlpha(newAlpha)); }
/** Returns a colour that's the same colour as this one, but with a modified alpha value. */
virtual const TwoDimensionalRendering::Colour * withMultipliedAlpha (const float alphaMultiplier) const throw () { return new Colour(colour.withMultipliedAlpha(alphaMultiplier)); }
/** Returns a colour that is the result of alpha-compositing a new colour over this one. */
virtual const TwoDimensionalRendering::Colour * overlaidWith (const TwoDimensionalRendering::Colour & foregroundColour) const throw () { return new Colour(colour.overlaidWith(((Colour&)foregroundColour).colour)); }
/** Returns a copy of this colour with a different hue. */
virtual const TwoDimensionalRendering::Colour * withHue (const float newHue) const throw () { return new Colour(colour.withHue(newHue)); }
/** Returns a copy of this colour with a different saturation. */
virtual const TwoDimensionalRendering::Colour * withSaturation (const float newSaturation) const throw () { return new Colour(colour.withSaturation(newSaturation)); }
/** Returns a copy of this colour with a different brightness. */
virtual const TwoDimensionalRendering::Colour * withBrightness (const float newBrightness) const throw () { return new Colour(colour.withBrightness(newBrightness)); }
/** Returns a copy of this colour with it hue rotated. */
virtual const TwoDimensionalRendering::Colour * withRotatedHue (const float amountToRotate) const throw () { return new Colour(colour.withRotatedHue(amountToRotate)); }
/** Returns a copy of this colour with its saturation multiplied by the given value. */
virtual const TwoDimensionalRendering::Colour * withMultipliedSaturation (const float multiplier) const throw () { return new Colour(colour.withMultipliedSaturation(multiplier)); }
/** Returns a copy of this colour with its brightness multiplied by the given value. */
virtual const TwoDimensionalRendering::Colour * withMultipliedBrightness (const float amount) const throw () { return new Colour(colour.withMultipliedBrightness(amount)); }
/** Returns a brighter version of this colour. */
virtual const TwoDimensionalRendering::Colour * brighter (float amountBrighter = 0.4f) const throw () { return new Colour(colour.brighter(amountBrighter)); }
/** Returns a darker version of this colour. */
virtual const TwoDimensionalRendering::Colour * darker (float amountDarker = 0.4f) const throw () { return new Colour(colour.darker(amountDarker)); }
/** Returns a colour that will be clearly visible against this colour. */
virtual const TwoDimensionalRendering::Colour * contrasting (const float amount=1.0f) const throw () { return new Colour(colour.contrasting(amount)); }
Colour(const juce::Colour & color) : colour(color) {}
friend class Image;
friend class ImageFactory;
friend class Brush;
friend class BrushFactory;
friend class Graphics;
};
/** This class is a wrapper of the Juce Image class.
This is used to simplify different Juce code base in the same process.
*/
class Image : public TwoDimensionalRendering::Image
{
juce::Image * image;
/** Get the image width in pixels */
virtual int getWidth () const throw () { return image->getWidth(); }
/** Get the image height in pixels */
virtual int getHeight () const throw () { return image->getHeight(); }
/** Get the pixel format used */
virtual TwoDimensionalRendering::Image::PixelFormat getFormat () const throw () { return (TwoDimensionalRendering::Image::PixelFormat)image->getFormat(); }
/** Clear the given section with the given colour */
virtual void clear (int x, int y, int w, int h, const TwoDimensionalRendering::Colour & colourToClearTo) { image->clear(x, y, w, h, ((Colour&)colourToClearTo).colour); }
/** Create a resized copy for this image */
virtual TwoDimensionalRendering::Image * createCopy (int newWidth = -1, int newHeight = -1) const { return new Image(image->createCopy(newWidth, newHeight)); }
/** Get the pixel at the given position */
virtual const TwoDimensionalRendering::Colour * getPixelAt (const int x, const int y) const { return new Colour(image->getPixelAt(x, y)); }
/** Set the pixel at the given position */
virtual void setPixelAt (const int x, const int y, const TwoDimensionalRendering::Colour & colour) { image->setPixelAt(x, y, ((Colour&)colour).colour); }
/** Change the opacity for a pixel */
virtual void multiplyAlphaAt (const int x, const int y, const float multiplier) { image->multiplyAlphaAt(x, y, multiplier); }
/** Change the opacity for the whole image */
virtual void multiplyAllAlphas (const float amountToMultiplyBy) { image->multiplyAllAlphas(amountToMultiplyBy); }
/** Remove image saturation (the image will be grey) */
virtual void desaturate () { image->desaturate(); }
/** Lock the pixel section for writing */
virtual uint8 * lockPixelDataReadWrite (int x, int y, int w, int h, int & lineStride, int & pixelStride) { return image->lockPixelDataReadWrite(x, y, w, h, lineStride, pixelStride); }
/** Then release the locked section */
virtual void releasePixelDataReadWrite (void * sourceData) { image->releasePixelDataReadWrite(sourceData); }
/** Lock the pixel section for reading only */
virtual const uint8 * lockPixelDataReadOnly (int x, int y, int w, int h, int & lineStride, int & pixelStride) const { return image->lockPixelDataReadOnly(x, y, w, h, lineStride, pixelStride); }
/** Then release the locked section */
virtual void releasePixelDataReadOnly (const void *sourceData) const { image->releasePixelDataReadOnly(sourceData); }
/** Copy the given pixel array to the given rectangle in the image */
virtual void setPixelData (int destX, int destY, int destW, int destH, const uint8 *sourcePixelData, int sourceLineStride) { image->setPixelData(destX, destY, destW, destH, sourcePixelData, sourceLineStride); }
/** Move a section of the image to somewhere else */
virtual void moveImageSection (int destX, int destY, int sourceX, int sourceY, int width, int height) { image->moveImageSection(destX, destY, sourceX, sourceY, width, height); }
Image(juce::Image * _image) : image(_image) { }
~Image() { delete image; image = 0; }
friend class ImageFactory;
friend class Graphics;
friend class ImageBrush;
friend class BrushFactory;
};
/** This is a factory used to create Images.
@warning You must call deleteImage for each pointer returned.
This is because the memory tracking tools can be confused with heap allocated in a code segment and deallocated in another segment. */
class ImageFactory : public TwoDimensionalRendering::ImageFactory
{
/** Create an empty memory based image */
virtual TwoDimensionalRendering::Image * createEmptyImage(const TwoDimensionalRendering::Image::PixelFormat format, const int imageWidth, const int imageHeight, const bool clearImage) const
{
return new Image(new juce::Image((juce::Image::PixelFormat)format, imageWidth, imageHeight, clearImage));
}
/** Create an image from a memory section */
virtual TwoDimensionalRendering::Image * createImageFromMemory(const uint8 * section, const int sectionSizeInBytes) const
{
juce::Image * image = juce::ImageFileFormat::loadFrom(section, sectionSizeInBytes);
if (!image) return 0;
return new Image(image);
}
/** Create an image from a file path (stored as UTF-8) */
virtual TwoDimensionalRendering::Image * createImageFromFile(const TwoDimensionalRendering::String & absoluteFilePath) const
{
juce::Image * image = juce::ImageFileFormat::loadFrom(juce::File(juce::String::fromUTF8(absoluteFilePath)));
if (!image) return 0;
return new Image(image);
}
/** Create a colour (alpha = 255 means opaque) */
virtual TwoDimensionalRendering::Colour * createARGBColour(const uint8 red, const uint8 green, const uint8 blue, const uint8 alpha) const
{
return new Colour(juce::Colour(red, green, blue, alpha));
}
/** Create a colour from Hue Saturation Brightness space (alpha = 255 means opaque) */
virtual TwoDimensionalRendering::Colour * createAHSBColour(const float hue, const float saturation, const float brightness, const uint8 alpha) const
{
return new Colour(juce::Colour(hue, saturation, brightness, alpha));
}
/** Delete a created image */
virtual void deleteImage(TwoDimensionalRendering::Image * image) const throw() { delete (Image*)image; }
/** Delete a created colour */
virtual void deleteColour(TwoDimensionalRendering::Colour * colour) const throw() { delete (Colour*)colour; }
};
class Brush : public TwoDimensionalRendering::Brush
{
juce::Brush * brush;
/** Create a copy for this brush */
virtual TwoDimensionalRendering::Brush * createCopy () const throw () { return new Brush(brush->createCopy()); }
/** Apply a transform to this brush (if applicable) */
virtual void applyTransform (const TwoDimensionalRendering::AffineTransform & transform) throw () { brush->applyTransform(((AffineTransform&)transform).object); }
/** Multiply the opacity for this brush */
virtual void multiplyOpacity (const float multiple) throw () { brush->multiplyOpacity(multiple); }
/** Check whether this brush is invisible */
virtual bool isInvisible () const throw () { return brush->isInvisible(); }
Brush(juce::Brush * _brush) : brush(_brush) {}
~Brush() { delete brush; brush = 0; }
friend class BrushFactory;
friend class Graphics;
};
/** This is a factory used to create Brushes.
@warning You must call deleteBrush for each pointer returned.
This is because the memory tracking tools can be confused with heap allocated in a code segment and deallocated in another segment. */
class BrushFactory : public TwoDimensionalRendering::BrushFactory
{
/** Create a gradient brush */
virtual TwoDimensionalRendering::Brush * createGradientBrush(const TwoDimensionalRendering::Colour & colour1, const float x1, const float y1, const TwoDimensionalRendering::Colour & colour2, const float x2, const float y2, const bool isRadial) const
{
return new Brush(new juce::GradientBrush(((Colour &)colour1).colour, x1, y1, ((Colour &)colour2).colour, x2, y2, isRadial));
}
/** Create a solid color brush */
virtual TwoDimensionalRendering::Brush * createSolidColourBrush(const TwoDimensionalRendering::Colour & colour) const
{
return new Brush(new juce::SolidColourBrush(((Colour &)colour).colour));
}
/** Create an image brush */
virtual TwoDimensionalRendering::Brush * createImageBrush(TwoDimensionalRendering::Image & image, const int anchorX, const int anchorY, const float opacity) const
{
return new Brush(new juce::ImageBrush(((Image &)image).image, anchorX, anchorY, opacity));
}
/** Delete a created brush */
virtual void deleteBrush(TwoDimensionalRendering::Brush * brush) const throw() { delete (Brush*)brush; }
};
class Font : public TwoDimensionalRendering::Font
{
juce::Font font;
/** Changes the name of the typeface family. */
virtual void setTypefaceName (const TwoDimensionalRendering::String & faceName) throw () { font.setTypefaceName(juce::String::fromUTF8(faceName)); }
/** Returns the name of the typeface family that this font uses. */
virtual const TwoDimensionalRendering::String getTypefaceName () const throw () { return font.getTypefaceName().toUTF8(); }
/** Returns the total height of this font. */
virtual float getHeight () const throw () { return font.getHeight(); }
/** Changes the font's height. */
virtual void setHeight (float newHeight) throw () { font.setHeight(newHeight); }
/** Changes the font's height without changing its width. */
virtual void setHeightWithoutChangingWidth (float newHeight) throw () { font.setHeightWithoutChangingWidth(newHeight); }
/** Returns the height of the font above its baseline. */
virtual float getAscent () const throw () { return font.getAscent(); }
/** Returns the amount that the font descends below its baseline. */
virtual float getDescent () const throw () { return font.getDescent(); }
/** Returns the font's style flags. */
virtual int getStyleFlags () const throw () { return font.getStyleFlags(); }
/** Changes the font's style. */
virtual void setStyleFlags (const int newFlags) throw () { font.setStyleFlags(newFlags); }
/** Makes the font bold or non-bold. */
virtual void setBold (const bool shouldBeBold) throw () { font.setBold(shouldBeBold); }
/** Returns true if the font is bold. */
virtual bool isBold () const throw () { return font.isBold(); }
/** Makes the font italic or non-italic. */
virtual void setItalic (const bool shouldBeItalic) throw () { font.setItalic(shouldBeItalic); }
/** Returns true if the font is italic. */
virtual bool isItalic () const throw () { return font.isItalic(); }
/** Makes the font underlined or non-underlined. */
virtual void setUnderline (const bool shouldBeUnderlined) throw () { font.setUnderline(shouldBeUnderlined); }
/** Returns true if the font is underlined. */
virtual bool isUnderlined () const throw () { return font.isUnderlined(); }
/** Changes the font's horizontal scale factor. */
virtual void setHorizontalScale (const float scaleFactor) throw () { font.setHorizontalScale(scaleFactor); }
/** Returns the font's horizontal scale. */
virtual float getHorizontalScale () const throw () { return font.getHorizontalScale(); }
/** Changes the font's kerning. */
virtual void setExtraKerningFactor (const float extraKerning) throw () { font.setExtraKerningFactor(extraKerning); }
/** Returns the font's kerning. */
virtual float getExtraKerningFactor () const throw () { return font.getExtraKerningFactor(); }
/** Changes all the font's characteristics with one call. */
virtual void setSizeAndStyle (const float newHeight, const int newStyleFlags, const float newHorizontalScale, const float newKerningAmount) throw ()
{ font.setSizeAndStyle(newHeight, newStyleFlags, newHorizontalScale, newKerningAmount); }
/** Resets this font's characteristics. */
virtual void resetToDefaultState () throw () { font.resetToDefaultState(); }
/** Returns the total width of a string as it would be drawn using this font. */
virtual float getStringWidthFloat (const TwoDimensionalRendering::String & text) const throw () { return font.getStringWidthFloat(juce::String::fromUTF8(text)); }
Font(const juce::Font & _font) : font(_font) {}
friend class FontFactory;
friend class Graphics;
};
class FontFactory : public TwoDimensionalRendering::FontFactory
{
/** Creates a sans-serif font in a given size. */
virtual TwoDimensionalRendering::Font * createSansSerifFont(const float fontHeight, const int styleFlags = TwoDimensionalRendering::Font::plain) const
{ return new Font(juce::Font(juce::Font::getDefaultSansSerifFontName(), fontHeight, styleFlags)); }
/** Creates a font with a given typeface and parameters. */
virtual TwoDimensionalRendering::Font * createFont(const TwoDimensionalRendering::String & typefaceName, const float fontHeight, const int styleFlags) const
{ return new Font(juce::Font(juce::String::fromUTF8(typefaceName), fontHeight, styleFlags)); }
/** Delete created font */
virtual void deleteFont(TwoDimensionalRendering::Font * font) const { delete (Font*)font; }
};
class Graphics : public TwoDimensionalRendering::Graphics
{
juce::Graphics & graphic;
/** Change the current drawing colour. */
virtual void setColour (const TwoDimensionalRendering::Colour & newColour) throw () { graphic.setColour(((Colour&)newColour).colour); }
/** Returns the colour that's currently being used. */
virtual const TwoDimensionalRendering::Colour * getCurrentColour () const throw () { return new Colour(graphic.getCurrentColour()); }
/** Changes the opacity to use with the current colour. */
virtual void setOpacity (const float newOpacity) throw () { graphic.setOpacity(newOpacity); }
/** Changes the current brush to use for drawing. */
virtual void setBrush (const TwoDimensionalRendering::Brush * const newBrush) throw () { graphic.setBrush(((Brush*)newBrush)->brush); }
/** Changes the font to use for subsequent text-drawing functions. */
virtual void setFont (const TwoDimensionalRendering::Font & newFont) throw () { graphic.setFont(((Font&)newFont).font); }
/** Changes the size and style of the currently-selected font. */
virtual void setFont (const float newFontHeight, const int fontStyleFlags = Font::plain) throw () { graphic.setFont(newFontHeight, fontStyleFlags); }
/** Returns the font that's currently being used for text operations. */
virtual const TwoDimensionalRendering::Font * getCurrentFont () const throw () { return new Font(graphic.getCurrentFont()); }
/** Draws a one-line text string. */
virtual void drawSingleLineText (const TwoDimensionalRendering::String & text, const int startX, const int baselineY) const throw () { graphic.drawSingleLineText(juce::String::fromUTF8(text), startX, baselineY); }
/** Draws text across multiple lines. */
virtual void drawMultiLineText (const TwoDimensionalRendering::String & text, const int startX, const int baselineY, const int maximumLineWidth) const throw () { graphic.drawMultiLineText(juce::String::fromUTF8(text), startX, baselineY, maximumLineWidth); }
/** Renders a string of text as a vector path. */
virtual void drawTextAsPath (const TwoDimensionalRendering::String & text, const TwoDimensionalRendering::AffineTransform & transform) const throw () { graphic.drawTextAsPath(juce::String::fromUTF8(text), ((AffineTransform&)transform).object); }
/** Draws a line of text within a specified rectangle. */
virtual void drawText (const TwoDimensionalRendering::String & text, const int x, const int y, const int width, const int height, const int justificationType, const bool useEllipsesIfTooBig) const throw () { graphic.drawText(juce::String::fromUTF8(text), x, y, width, height, justificationType, useEllipsesIfTooBig); }
/** Tries to draw a text string inside a given space. */
virtual void drawFittedText (const TwoDimensionalRendering::String & text, const int x, const int y, const int width, const int height, const int justificationFlags, const int maximumNumberOfLines, const float minimumHorizontalScale=0.7f) const throw () { graphic.drawFittedText(juce::String::fromUTF8(text), x, y, width, height, justificationFlags, maximumNumberOfLines, minimumHorizontalScale); }
/** Fills the context's entire clip region with the current colour or brush. */
virtual void fillAll () const throw () { graphic.fillAll(); }
/** Fills the context's entire clip region with a given colour. */
virtual void fillAll (const TwoDimensionalRendering::Colour & colourToUse) const throw () { graphic.fillAll(((Colour&)colourToUse).colour); }
/** Fills a rectangle with the current colour or brush. */
virtual void fillRect (const float x, const float y, const float width, const float height) const throw () { graphic.fillRect(x, y, width, height); }
/** Uses the current colour or brush to fill a rectangle with rounded corners. */
virtual void fillRoundedRectangle (const float x, const float y, const float width, const float height, const float cornerSize) const throw () { graphic.fillRoundedRectangle(x, y, width, height, cornerSize); }
/** Fills a rectangle with a checkerboard pattern, alternating between two colours. */
virtual void fillCheckerBoard (int x, int y, int width, int height, const int checkWidth, const int checkHeight, const TwoDimensionalRendering::Colour & colour1, const TwoDimensionalRendering::Colour & colour2) const throw () { graphic.fillCheckerBoard(x, y, width, height, checkWidth, checkHeight, ((Colour&)colour1).colour, ((Colour&)colour2).colour); }
/** Draws four lines to form a rectangular outline, using the current colour or brush. */
virtual void drawRect (const int x, const int y, const int width, const int height, const int lineThickness=1) const throw () { graphic.drawRect(x, y, width, height, lineThickness); }
/** Uses the current colour or brush to draw the outline of a rectangle with rounded corners. */
virtual void drawRoundedRectangle (const float x, const float y, const float width, const float height, const float cornerSize, const float lineThickness) const throw () { graphic.drawRoundedRectangle(x, y, width, height, cornerSize, lineThickness); }
/** Draws a 3D raised (or indented) bevel using two colours. */
virtual void drawBevel (const int x, const int y, const int width, const int height, const int bevelThickness, const TwoDimensionalRendering::Colour & topLeftColour, const TwoDimensionalRendering::Colour & bottomRightColour, const bool useGradient=true) const throw () { graphic.drawBevel(x, y, width, height, bevelThickness, ((Colour&)topLeftColour).colour, ((Colour&)bottomRightColour).colour, useGradient); }
/** Draws a pixel using the current colour or brush. */
virtual void setPixel (int x, int y) const throw () { graphic.setPixel(x, y); }
/** Fills an ellipse with the current colour or brush. */
virtual void fillEllipse (const float x, const float y, const float width, const float height) const throw () { graphic.fillEllipse(x, y, width, height); }
/** Draws an elliptical stroke using the current colour or brush. */
virtual void drawEllipse (const float x, const float y, const float width, const float height, const float lineThickness) const throw () { graphic.drawEllipse(x, y, width, height, lineThickness); }
/** Draws a line between two points with a given thickness. */
virtual void drawLine (const float startX, const float startY, const float endX, const float endY, const float lineThickness = 1.0f) const throw () { graphic.drawLine(startX, startY, endX, endY, lineThickness); }
/** Draws a dashed line using a custom set of dash-lengths. */
virtual void drawDashedLine (const float startX, const float startY, const float endX, const float endY, const float *const dashLengths, const int numDashLengths, const float lineThickness = 1.0f) const throw () { graphic.drawDashedLine(startX, startY, endX, endY, dashLengths, numDashLengths, lineThickness); }
/** Draws a vertical line of pixels at a given x position. */
virtual void drawVerticalLine (const int x, float top, float bottom) const throw () { graphic.drawVerticalLine(x, top, bottom); }
/** Draws a horizontal line of pixels at a given y position. */
virtual void drawHorizontalLine (const int y, float left, float right) const throw () { graphic.drawHorizontalLine(y, left, right); }
/** Fills a path using the currently selected colour or brush. */
virtual void fillPath (const TwoDimensionalRendering::Path & path, const TwoDimensionalRendering::AffineTransform & transform) const throw () { graphic.fillPath((((Path&)path).path), ((AffineTransform&)transform).object); }
/** Draws a path's outline using the currently selected colour or brush. */
virtual void strokePath (const TwoDimensionalRendering::Path & path, const TwoDimensionalRendering::PathStrokeType & strokeType, const TwoDimensionalRendering::AffineTransform & transform) const throw () { graphic.strokePath((((Path&)path).path), ((PathStrokeType&)strokeType).pathST, ((AffineTransform&)transform).object); }
/** Draws a line with an arrowhead. */
virtual void drawArrow (const float startX, const float startY, const float endX, const float endY, const float lineThickness, const float arrowheadWidth, const float arrowheadLength) const throw () { graphic.drawArrow(startX, startY, endX, endY, lineThickness, arrowheadWidth, arrowheadLength); }
/** Draws an image. */
virtual void drawImageAt (const TwoDimensionalRendering::Image * const imageToDraw, const int topLeftX, const int topLeftY, const bool fillAlphaChannelWithCurrentBrush = false) const throw () { graphic.drawImageAt(((Image*)imageToDraw)->image, topLeftX, topLeftY, fillAlphaChannelWithCurrentBrush); }
/** Draws part of an image, rescaling it to fit in a given target region. */
virtual void drawImage (const TwoDimensionalRendering::Image * const imageToDraw, int destX, int destY, int destWidth, int destHeight, int sourceX, int sourceY, int sourceWidth, int sourceHeight, const bool fillAlphaChannelWithCurrentBrush = false) const throw () { graphic.drawImage(((Image*)imageToDraw)->image, destX, destY, destWidth, destHeight, sourceX, sourceY, sourceWidth, sourceHeight, fillAlphaChannelWithCurrentBrush); }
/** Draws part of an image, having applied an affine transform to it. */
virtual void drawImageTransformed (const TwoDimensionalRendering::Image * const imageToDraw, int sourceClipX, int sourceClipY, int sourceClipWidth, int sourceClipHeight, const TwoDimensionalRendering::AffineTransform & transform, const bool fillAlphaChannelWithCurrentBrush) const throw ()
{ graphic.drawImageTransformed(((Image*)imageToDraw)->image, sourceClipX, sourceClipY, sourceClipWidth, sourceClipHeight, ((AffineTransform&)transform).object, fillAlphaChannelWithCurrentBrush); }
/** Returns the position of the bounding box for the current clipping region. */
virtual void getClipBounds (int & x, int & y, int & width, int & height) const throw () { const juce::Rectangle & rect = graphic.getClipBounds(); x = rect.getX(), y = rect.getY(), width = rect.getWidth(), height = rect.getHeight(); }
/** Checks whether a rectangle overlaps the context's clipping region. */
virtual bool clipRegionIntersects (const int x, const int y, const int width, const int height) const throw () { return graphic.clipRegionIntersects(x, y, width, height); }
/** Intersects the current clipping region with another region. */
virtual bool reduceClipRegion (const int x, const int y, const int width, const int height) throw () { return graphic.reduceClipRegion(x, y, width, height); }
/** Excludes a rectangle to stop it being drawn into. */
virtual void excludeClipRegion (const int x, const int y, const int width, const int height) throw () { graphic.excludeClipRegion(x, y, width, height); }
/** Returns true if no drawing can be done because the clip region is zero. */
virtual bool isClipEmpty () const throw () { return graphic.isClipEmpty(); }
/** Saves the current graphics state on an internal stack. */
virtual void saveState () throw () { graphic.saveState(); }
/** Restores a graphics state that was previously saved with saveState(). */
virtual void restoreState () throw () { graphic.restoreState(); }
/** Moves the position of the context's origin. */
virtual void setOrigin (const int newOriginX, const int newOriginY) throw () { graphic.setOrigin(newOriginX, newOriginY); }
/** Resets the current colour, brush, and font to default settings. */
virtual void resetToDefaultState () throw () { graphic.resetToDefaultState(); }
/** Returns true if this context is drawing to a vector-based device, such as a printer. */
virtual bool isVectorDevice () const throw () { return graphic.isVectorDevice(); }
/** Draw the given SVG file inside the given rectangle */
virtual bool drawSVG(const TwoDimensionalRendering::String & fileName, const int destX, const int destY, const int destWidth, const int destHeight, const int justification) const
{
// Find the file
juce::File file(juce::String::fromUTF8(fileName));
if (!file.existsAsFile()) return false;
juce::Drawable * drawable = juce::Drawable::createFromImageFile(file);
if (!drawable) return false;
int flags = (justification & TwoDimensionalRendering::Justification::left) ? juce::RectanglePlacement::xLeft : 0;
flags |= (justification & TwoDimensionalRendering::Justification::right) ? juce::RectanglePlacement::xRight : 0;
flags |= (justification & TwoDimensionalRendering::Justification::horizontallyCentred) ? juce::RectanglePlacement::xMid : 0;
flags |= (justification & TwoDimensionalRendering::Justification::verticallyCentred) ? juce::RectanglePlacement::yMid : 0;
flags |= (justification & TwoDimensionalRendering::Justification::top) ? juce::RectanglePlacement::yTop : 0;
flags |= (justification & TwoDimensionalRendering::Justification::bottom) ? juce::RectanglePlacement::yBottom : 0;
drawable->drawWithin(graphic, destX, destY, destWidth, destHeight, juce::RectanglePlacement(flags | juce::RectanglePlacement::doNotResize));
delete drawable;
return true;
}
Graphics(juce::Graphics & _graphic) : graphic(_graphic){}
};
class RenderingFactory : public TwoDimensionalRendering::RenderingFactory
{
AffineTransformFactory affine;
PathFactory path;
ImageFactory image;
BrushFactory brush;
FontFactory font;
virtual const TwoDimensionalRendering::AffineTransformFactory & getAffineTransformFactory() const { return affine; }
virtual const TwoDimensionalRendering::PathFactory & getPathFactory() const { return path; }
virtual const TwoDimensionalRendering::ImageFactory & getImageFactory() const { return image; }
virtual const TwoDimensionalRendering::BrushFactory & getBrushFactory() const { return brush; }
virtual const TwoDimensionalRendering::FontFactory & getFontFactory() const { return font; }
};