Browse Source

Big change for Drawables - they now inherit from Component, so can be added directly to other components and will draw themselves, rather than being painted into a graphics object (although you can still use them that way if you want to).

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
640a335537
23 changed files with 615 additions and 714 deletions
  1. +5
    -13
      extras/Jucer (experimental)/Source/Utility/jucer_MiscUtilities.h
  2. +1
    -1
      extras/the jucer/src/model/jucer_PaintRoutine.cpp
  3. +1
    -1
      extras/the jucer/src/model/paintelements/jucer_PaintElementImage.h
  4. +1
    -1
      src/core/juce_StandardHeader.h
  5. +91
    -82
      src/gui/components/buttons/juce_DrawableButton.cpp
  6. +9
    -5
      src/gui/components/buttons/juce_DrawableButton.h
  7. +43
    -30
      src/gui/components/buttons/juce_ToolbarButton.cpp
  8. +10
    -1
      src/gui/components/buttons/juce_ToolbarButton.h
  9. +0
    -5
      src/gui/components/controls/juce_ToolbarItemComponent.cpp
  10. +75
    -30
      src/gui/graphics/drawables/juce_Drawable.cpp
  11. +42
    -50
      src/gui/graphics/drawables/juce_Drawable.h
  12. +182
    -256
      src/gui/graphics/drawables/juce_DrawableComposite.cpp
  13. +30
    -28
      src/gui/graphics/drawables/juce_DrawableComposite.h
  14. +33
    -49
      src/gui/graphics/drawables/juce_DrawableImage.cpp
  15. +5
    -7
      src/gui/graphics/drawables/juce_DrawableImage.h
  16. +14
    -21
      src/gui/graphics/drawables/juce_DrawablePath.cpp
  17. +1
    -1
      src/gui/graphics/drawables/juce_DrawablePath.h
  18. +8
    -15
      src/gui/graphics/drawables/juce_DrawableRectangle.cpp
  19. +1
    -1
      src/gui/graphics/drawables/juce_DrawableRectangle.h
  20. +26
    -65
      src/gui/graphics/drawables/juce_DrawableShape.cpp
  21. +4
    -13
      src/gui/graphics/drawables/juce_DrawableShape.h
  22. +27
    -31
      src/gui/graphics/drawables/juce_DrawableText.cpp
  23. +6
    -8
      src/gui/graphics/drawables/juce_DrawableText.h

+ 5
- 13
extras/Jucer (experimental)/Source/Utility/jucer_MiscUtilities.h View File

@@ -162,27 +162,22 @@ public:
drawable = newDrawable;
drawable.addListener (this);
drawableObject = Drawable::createFromValueTree (drawable, 0); // xxx image provider missing
addAndMakeVisible (drawableObject);
resized();
repaint();
}
void paint (Graphics& g)
{
if (drawableObject != 0)
drawableObject->drawAt (g, 0, 0, 1.0f);
}
void resized()
{
DrawableComposite* dc = dynamic_cast <DrawableComposite*> (static_cast <Drawable*> (drawableObject));
/* DrawableComposite* dc = dynamic_cast <DrawableComposite*> (static_cast <Drawable*> (drawableObject));
if (dc != 0)
{
const RelativeCoordinate origin, right (getWidth()), bottom (getHeight());
dc->setContentArea (RelativeRectangle (origin, right, origin, bottom));
dc->resetBoundingBoxToContentArea();
}
//dc->resetBoundingBoxToContentArea();
}*/
}
void valueTreePropertyChanged (ValueTree&, const Identifier&) { updateGraphics(); }
@@ -196,10 +191,7 @@ private:
void updateGraphics()
{
if (drawableObject != 0)
{
const Rectangle<float> dirtyArea (drawableObject->refreshFromValueTree (drawable, 0));
repaint (dirtyArea.getSmallestIntegerContainer());
}
drawableObject->refreshFromValueTree (drawable, 0);
}
};


+ 1
- 1
extras/the jucer/src/model/jucer_PaintRoutine.cpp View File

@@ -540,7 +540,7 @@ void PaintRoutine::dropImageAt (const File& f, int x, int y)
if (d != 0)
{
Rectangle<float> bounds (d->getBounds());
Rectangle<float> bounds (d->getDrawableBounds());
delete d;
PaintElement* newElement


+ 1
- 1
extras/the jucer/src/model/paintelements/jucer_PaintElementImage.h View File

@@ -310,7 +310,7 @@ public:
const Rectangle<int> parentArea (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
Rectangle<int> r (getCurrentBounds (parentArea));
Rectangle<float> bounds (image->getBounds());
Rectangle<float> bounds (image->getDrawableBounds());
r.setSize ((int) (bounds.getWidth() + 0.999f), (int) (bounds.getHeight() + 0.999f));


+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 95
#define JUCE_BUILDNUMBER 96
/** Current Juce version number.


+ 91
- 82
src/gui/components/buttons/juce_DrawableButton.cpp View File

@@ -36,6 +36,7 @@ DrawableButton::DrawableButton (const String& name,
const DrawableButton::ButtonStyle buttonStyle)
: Button (name),
style (buttonStyle),
currentImage (0),
edgeIndent (3)
{
if (buttonStyle == ImageOnButtonBackground)
@@ -52,14 +53,9 @@ DrawableButton::DrawableButton (const String& name,
DrawableButton::~DrawableButton()
{
deleteImages();
}
//==============================================================================
void DrawableButton::deleteImages()
{
}
void DrawableButton::setImages (const Drawable* normal,
const Drawable* over,
const Drawable* down,
@@ -69,36 +65,18 @@ void DrawableButton::setImages (const Drawable* normal,
const Drawable* downOn,
const Drawable* disabledOn)
{
deleteImages();
jassert (normal != 0); // you really need to give it at least a normal image..
if (normal != 0)
normalImage = normal->createCopy();
if (over != 0)
overImage = over->createCopy();
if (down != 0)
downImage = down->createCopy();
if (disabled != 0)
disabledImage = disabled->createCopy();
if (normalOn != 0)
normalImageOn = normalOn->createCopy();
if (overOn != 0)
overImageOn = overOn->createCopy();
if (downOn != 0)
downImageOn = downOn->createCopy();
if (normal != 0) normalImage = normal->createCopy();
if (over != 0) overImage = over->createCopy();
if (down != 0) downImage = down->createCopy();
if (disabled != 0) disabledImage = disabled->createCopy();
if (normalOn != 0) normalImageOn = normalOn->createCopy();
if (overOn != 0) overImageOn = overOn->createCopy();
if (downOn != 0) downImageOn = downOn->createCopy();
if (disabledOn != 0) disabledImageOn = disabledOn->createCopy();
if (disabledOn != 0)
disabledImageOn = disabledOn->createCopy();
repaint();
buttonStateChanged();
}
//==============================================================================
@@ -107,7 +85,7 @@ void DrawableButton::setButtonStyle (const DrawableButton::ButtonStyle newStyle)
if (style != newStyle)
{
style = newStyle;
repaint();
buttonStateChanged();
}
}
@@ -134,21 +112,88 @@ void DrawableButton::setEdgeIndent (const int numPixelsIndent)
{
edgeIndent = numPixelsIndent;
repaint();
resized();
}
void DrawableButton::resized()
{
Button::resized();
if (style == ImageRaw)
{
currentImage->setOriginWithOriginalSize (Point<float>());
}
else if (currentImage != 0)
{
Rectangle<int> imageSpace;
if (style == ImageOnButtonBackground)
{
imageSpace = getLocalBounds().reduced (getWidth() / 4, getHeight() / 4);
}
else
{
const int textH = (style == ImageAboveTextLabel)
? jmin (16, proportionOfHeight (0.25f))
: 0;
const int indentX = jmin (edgeIndent, proportionOfWidth (0.3f));
const int indentY = jmin (edgeIndent, proportionOfHeight (0.3f));
imageSpace.setBounds (indentX, indentY,
getWidth() - indentX * 2,
getHeight() - indentY * 2 - textH);
}
currentImage->setTransformToFit (imageSpace.toFloat(), RectanglePlacement::centred);
}
}
void DrawableButton::buttonStateChanged()
{
repaint();
Drawable* imageToDraw = 0;
float opacity = 1.0f;
if (isEnabled())
{
imageToDraw = getCurrentImage();
}
else
{
imageToDraw = getToggleState() ? disabledImageOn
: disabledImage;
if (imageToDraw == 0)
{
opacity = 0.4f;
imageToDraw = getNormalImage();
}
}
if (imageToDraw != currentImage)
{
removeChildComponent (currentImage);
currentImage = imageToDraw;
if (currentImage != 0)
{
addAndMakeVisible (currentImage);
DrawableButton::resized();
}
}
if (currentImage != 0)
currentImage->setAlpha (opacity);
}
void DrawableButton::paintButton (Graphics& g,
bool isMouseOverButton,
bool isButtonDown)
{
Rectangle<int> imageSpace;
if (style == ImageOnButtonBackground)
{
const int insetX = getWidth() / 4;
const int insetY = getHeight() / 4;
imageSpace.setBounds (insetX, insetY, getWidth() - insetX * 2, getHeight() - insetY * 2);
getLookAndFeel().drawButtonBackground (g, *this,
getBackgroundColour(),
isMouseOverButton,
@@ -162,13 +207,6 @@ void DrawableButton::paintButton (Graphics& g,
? jmin (16, proportionOfHeight (0.25f))
: 0;
const int indentX = jmin (edgeIndent, proportionOfWidth (0.3f));
const int indentY = jmin (edgeIndent, proportionOfHeight (0.3f));
imageSpace.setBounds (indentX, indentY,
getWidth() - indentX * 2,
getHeight() - indentY * 2 - textH);
if (textH > 0)
{
g.setFont ((float) textH);
@@ -182,39 +220,10 @@ void DrawableButton::paintButton (Graphics& g,
Justification::centred, 1);
}
}
g.setImageResamplingQuality (Graphics::mediumResamplingQuality);
g.setOpacity (1.0f);
const Drawable* imageToDraw = 0;
if (isEnabled())
{
imageToDraw = getCurrentImage();
}
else
{
imageToDraw = getToggleState() ? disabledImageOn
: disabledImage;
if (imageToDraw == 0)
{
g.setOpacity (0.4f);
imageToDraw = getNormalImage();
}
}
if (imageToDraw != 0)
{
if (style == ImageRaw)
imageToDraw->draw (g, 1.0f);
else
imageToDraw->drawWithin (g, imageSpace.toFloat(), RectanglePlacement::centred, 1.0f);
}
}
//==============================================================================
const Drawable* DrawableButton::getCurrentImage() const throw()
Drawable* DrawableButton::getCurrentImage() const throw()
{
if (isDown())
return getDownImage();
@@ -225,15 +234,15 @@ const Drawable* DrawableButton::getCurrentImage() const throw()
return getNormalImage();
}
const Drawable* DrawableButton::getNormalImage() const throw()
Drawable* DrawableButton::getNormalImage() const throw()
{
return (getToggleState() && normalImageOn != 0) ? normalImageOn
: normalImage;
}
const Drawable* DrawableButton::getOverImage() const throw()
Drawable* DrawableButton::getOverImage() const throw()
{
const Drawable* d = normalImage;
Drawable* d = normalImage;
if (getToggleState())
{
@@ -253,9 +262,9 @@ const Drawable* DrawableButton::getOverImage() const throw()
return d;
}
const Drawable* DrawableButton::getDownImage() const throw()
Drawable* DrawableButton::getDownImage() const throw()
{
const Drawable* d = normalImage;
Drawable* d = normalImage;
if (getToggleState())
{


+ 9
- 5
src/gui/components/buttons/juce_DrawableButton.h View File

@@ -148,10 +148,10 @@ public:
//==============================================================================
/** Returns the image that the button is currently displaying. */
const Drawable* getCurrentImage() const throw();
const Drawable* getNormalImage() const throw();
const Drawable* getOverImage() const throw();
const Drawable* getDownImage() const throw();
Drawable* getCurrentImage() const throw();
Drawable* getNormalImage() const throw();
Drawable* getOverImage() const throw();
Drawable* getDownImage() const throw();
//==============================================================================
/** A set of colour IDs to use to change the colour of various aspects of the link.
@@ -174,16 +174,20 @@ protected:
void paintButton (Graphics& g,
bool isMouseOverButton,
bool isButtonDown);
/** @internal */
void buttonStateChanged();
/** @internal */
void resized();
private:
//==============================================================================
ButtonStyle style;
ScopedPointer <Drawable> normalImage, overImage, downImage, disabledImage;
ScopedPointer <Drawable> normalImageOn, overImageOn, downImageOn, disabledImageOn;
Drawable* currentImage;
Colour backgroundOff, backgroundOn;
int edgeIndent;
void deleteImages();
DrawableButton (const DrawableButton&);
DrawableButton& operator= (const DrawableButton&);
};


+ 43
- 30
src/gui/components/buttons/juce_ToolbarButton.cpp View File

@@ -34,13 +34,12 @@ BEGIN_JUCE_NAMESPACE
//==============================================================================
ToolbarButton::ToolbarButton (const int itemId_,
const String& buttonText,
Drawable* const normalImage_,
Drawable* const toggledOnImage_)
ToolbarButton::ToolbarButton (const int itemId_, const String& buttonText,
Drawable* const normalImage_, Drawable* const toggledOnImage_)
: ToolbarItemComponent (itemId_, buttonText, true),
normalImage (normalImage_),
toggledOnImage (toggledOnImage_)
toggledOnImage (toggledOnImage_),
currentImage (0)
{
jassert (normalImage_ != 0);
}
@@ -50,47 +49,61 @@ ToolbarButton::~ToolbarButton()
}
//==============================================================================
bool ToolbarButton::getToolbarItemSizes (int toolbarDepth,
bool /*isToolbarVertical*/,
int& preferredSize,
int& minSize, int& maxSize)
bool ToolbarButton::getToolbarItemSizes (int toolbarDepth, bool /*isToolbarVertical*/, int& preferredSize, int& minSize, int& maxSize)
{
preferredSize = minSize = maxSize = toolbarDepth;
return true;
}
void ToolbarButton::paintButtonArea (Graphics& g,
int width, int height,
bool /*isMouseOver*/,
bool /*isMouseDown*/)
void ToolbarButton::paintButtonArea (Graphics&, int /*width*/, int /*height*/, bool /*isMouseOver*/, bool /*isMouseDown*/)
{
}
void ToolbarButton::contentAreaChanged (const Rectangle<int>&)
{
buttonStateChanged();
}
void ToolbarButton::updateDrawable()
{
if (currentImage != 0)
{
currentImage->setTransformToFit (getContentArea().toFloat(), RectanglePlacement::centred);
currentImage->setAlpha (isEnabled() ? 1.0f : 0.5f);
}
}
void ToolbarButton::resized()
{
ToolbarItemComponent::resized();
updateDrawable();
}
void ToolbarButton::enablementChanged()
{
ToolbarItemComponent::enablementChanged();
updateDrawable();
}
void ToolbarButton::buttonStateChanged()
{
Drawable* d = normalImage;
if (getToggleState() && toggledOnImage != 0)
d = toggledOnImage;
const Rectangle<float> area (0.0f, 0.0f, (float) width, (float) height);
if (! isEnabled())
if (d != currentImage)
{
Image im (Image::ARGB, width, height, true);
removeChildComponent (currentImage);
currentImage = d;
if (d != 0)
{
Graphics g2 (im);
d->drawWithin (g2, area, RectanglePlacement::centred, 1.0f);
enablementChanged();
addAndMakeVisible (d);
updateDrawable();
}
im.desaturate();
g.drawImageAt (im, 0, 0);
}
else
{
d->drawWithin (g, area, RectanglePlacement::centred, 1.0f);
}
}
void ToolbarButton::contentAreaChanged (const Rectangle<int>&)
{
}


+ 10
- 1
src/gui/components/buttons/juce_ToolbarButton.h View File

@@ -77,11 +77,20 @@ public:
void paintButtonArea (Graphics& g, int width, int height, bool isMouseOver, bool isMouseDown);
/** @internal */
void contentAreaChanged (const Rectangle<int>& newBounds);
/** @internal */
void buttonStateChanged();
/** @internal */
void resized();
/** @internal */
void enablementChanged();
juce_UseDebuggingNewOperator
private:
ScopedPointer <Drawable> normalImage, toggledOnImage;
ScopedPointer<Drawable> normalImage, toggledOnImage;
Drawable* currentImage;
void updateDrawable();
ToolbarButton (const ToolbarButton&);
ToolbarButton& operator= (const ToolbarButton&);


+ 0
- 5
src/gui/components/controls/juce_ToolbarItemComponent.cpp View File

@@ -44,7 +44,6 @@ ToolbarItemFactory::~ToolbarItemFactory()
{
}
//==============================================================================
class ItemDragAndDropOverlayComponent : public Component
{
@@ -57,10 +56,6 @@ public:
setMouseCursor (MouseCursor::DraggingHandCursor);
}
~ItemDragAndDropOverlayComponent()
{
}
void paint (Graphics& g)
{
ToolbarItemComponent* const tc = dynamic_cast <ToolbarItemComponent*> (getParentComponent());


+ 75
- 30
src/gui/graphics/drawables/juce_Drawable.cpp View File

@@ -40,42 +40,90 @@ BEGIN_JUCE_NAMESPACE
//==============================================================================
Drawable::RenderingContext::RenderingContext (Graphics& g_,
const AffineTransform& transform_,
const float opacity_) throw()
: g (g_),
transform (transform_),
opacity (opacity_)
Drawable::Drawable()
{
setInterceptsMouseClicks (false, false);
setPaintingIsUnclipped (true);
}
//==============================================================================
Drawable::Drawable()
: parent (0)
Drawable::~Drawable()
{
}
Drawable::~Drawable()
//==============================================================================
void Drawable::draw (Graphics& g, float opacity, const AffineTransform& transform) const
{
const_cast <Drawable*> (this)->nonConstDraw (g, opacity, transform);
}
void Drawable::draw (Graphics& g, const float opacity, const AffineTransform& transform) const
void Drawable::nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform)
{
render (RenderingContext (g, transform, opacity));
g.saveState();
const float oldOpacity = getAlpha();
setAlpha (opacity);
g.addTransform (AffineTransform::translation (-originRelativeToComponent.getX(),
-originRelativeToComponent.getY())
.followedBy (getTransform())
.followedBy (transform));
paintEntireComponent (g, false);
setAlpha (oldOpacity);
g.restoreState();
}
void Drawable::drawAt (Graphics& g, const float x, const float y, const float opacity) const
void Drawable::drawAt (Graphics& g, float x, float y, float opacity) const
{
draw (g, opacity, AffineTransform::translation (x, y));
}
void Drawable::drawWithin (Graphics& g,
const Rectangle<float>& destArea,
const RectanglePlacement& placement,
const float opacity) const
void Drawable::drawWithin (Graphics& g, const Rectangle<float>& destArea, const RectanglePlacement& placement, float opacity) const
{
draw (g, opacity, placement.getTransformToFit (getDrawableBounds(), destArea));
}
//==============================================================================
DrawableComposite* Drawable::getParent() const
{
return dynamic_cast <DrawableComposite*> (getParentComponent());
}
void Drawable::transformContextToCorrectOrigin (Graphics& g)
{
g.setOrigin (originRelativeToComponent.getX(),
originRelativeToComponent.getY());
}
void Drawable::markerHasMoved()
{
}
void Drawable::parentHierarchyChanged()
{
if (! destArea.isEmpty())
draw (g, opacity, placement.getTransformToFit (getBounds(), destArea));
setBoundsToEnclose (getDrawableBounds());
}
void Drawable::setBoundsToEnclose (const Rectangle<float>& area)
{
Drawable* const parent = getParent();
Point<int> parentOrigin;
if (parent != 0)
parentOrigin = parent->originRelativeToComponent;
const Rectangle<int> newBounds (area.getSmallestIntegerContainer() + parentOrigin);
originRelativeToComponent = parentOrigin - newBounds.getPosition();
setBounds (newBounds);
}
//==============================================================================
void Drawable::setOriginWithOriginalSize (const Point<float>& originWithinParent)
{
setTransform (AffineTransform::translation (originWithinParent.getX(), originWithinParent.getY()));
}
void Drawable::setTransformToFit (const Rectangle<float>& area, const RectanglePlacement& placement)
{
if (! area.isEmpty())
setTransform (placement.getTransformToFit (getDrawableBounds(), area));
}
//==============================================================================
@@ -136,20 +184,17 @@ Drawable* Drawable::createChildFromValueTree (DrawableComposite* parent, const V
const Identifier type (tree.getType());
Drawable* d = 0;
if (type == DrawablePath::valueTreeType)
d = new DrawablePath();
else if (type == DrawableComposite::valueTreeType)
d = new DrawableComposite();
else if (type == DrawableRectangle::valueTreeType)
d = new DrawableRectangle();
else if (type == DrawableImage::valueTreeType)
d = new DrawableImage();
else if (type == DrawableText::valueTreeType)
d = new DrawableText();
if (type == DrawablePath::valueTreeType) d = new DrawablePath();
else if (type == DrawableComposite::valueTreeType) d = new DrawableComposite();
else if (type == DrawableRectangle::valueTreeType) d = new DrawableRectangle();
else if (type == DrawableImage::valueTreeType) d = new DrawableImage();
else if (type == DrawableText::valueTreeType) d = new DrawableText();
if (d != 0)
{
d->parent = parent;
if (parent != 0)
parent->insertDrawable (d);
d->refreshFromValueTree (tree, imageProvider);
}


+ 42
- 50
src/gui/graphics/drawables/juce_Drawable.h View File

@@ -26,7 +26,7 @@
#ifndef __JUCE_DRAWABLE_JUCEHEADER__
#define __JUCE_DRAWABLE_JUCEHEADER__
#include "../contexts/juce_Graphics.h"
#include "../../components/juce_Component.h"
#include "../geometry/juce_RelativeCoordinate.h"
#include "../../../text/juce_XmlElement.h"
#include "../../../containers/juce_ValueTree.h"
@@ -39,7 +39,7 @@ class DrawableComposite;
@see DrawableComposite, DrawableImage, DrawablePath, DrawableText
*/
class JUCE_API Drawable
class JUCE_API Drawable : public Component
{
protected:
//==============================================================================
@@ -62,6 +62,11 @@ public:
//==============================================================================
/** Renders this Drawable object.
Note that the preferred way to render a drawable in future is by using it
as a component and adding it to a parent, so you might want to consider that
before using this method.
@see drawWithin
*/
void draw (Graphics& g, float opacity,
@@ -75,10 +80,12 @@ public:
@code
draw (g, AffineTransform::translation (x, y)).
@endcode
Note that the preferred way to render a drawable in future is by using it
as a component and adding it to a parent, so you might want to consider that
before using this method.
*/
void drawAt (Graphics& g,
float x, float y,
float opacity) const;
void drawAt (Graphics& g, float x, float y, float opacity) const;
/** Renders the Drawable within a rectangle, scaling it to fit neatly inside without
changing its aspect-ratio.
@@ -86,6 +93,10 @@ public:
The object can placed arbitrarily within the rectangle based on a Justification type,
and can either be made as big as possible, or just reduced to fit.
Note that the preferred way to render a drawable in future is by using it
as a component and adding it to a parent, so you might want to consider that
before using this method.
@param g the graphics context to render onto
@param destArea the target rectangle to fit the drawable into
@param placement defines the alignment and rescaling to use to fit
@@ -99,51 +110,18 @@ public:
//==============================================================================
/** Holds the information needed when telling a drawable to render itself.
@see Drawable::draw
/** Resets any transformations on this drawable, and positions its origin within
its parent component.
*/
class RenderingContext
{
public:
RenderingContext (Graphics& g, const AffineTransform& transform, float opacity) throw();
void setOriginWithOriginalSize (const Point<float>& originWithinParent);
Graphics& g;
AffineTransform transform;
float opacity;
private:
RenderingContext& operator= (const RenderingContext&);
};
/** Renders this Drawable object.
@see draw
/** Sets a transform for this drawable that will position it within the specified
area of its parent component.
*/
virtual void render (const RenderingContext& context) const = 0;
//==============================================================================
/** Returns the smallest rectangle that can contain this Drawable object.
Co-ordinates are relative to the object's own origin.
*/
virtual const Rectangle<float> getBounds() const = 0;
/** Returns true if the given point is somewhere inside this Drawable.
Co-ordinates are relative to the object's own origin.
*/
virtual bool hitTest (float x, float y) const = 0;
//==============================================================================
/** Returns the name given to this drawable.
@see setName
*/
const String& getName() const throw() { return name; }
/** Assigns a name to this drawable. */
void setName (const String& newName) throw() { name = newName; }
void setTransformToFit (const Rectangle<float>& areaInParent, const RectanglePlacement& placement);
/** Returns the DrawableComposite that contains this object, if there is one. */
DrawableComposite* getParent() const throw() { return parent; }
DrawableComposite* getParent() const;
//==============================================================================
/** Tries to turn some kind of image file into a drawable.
@@ -215,7 +193,7 @@ public:
/** Tries to refresh a Drawable from the same ValueTree that was used to create it.
@returns the damage rectangle that will need repainting due to any changes that were made.
*/
virtual const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) = 0;
virtual void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) = 0;
/** Creates a ValueTree to represent this Drawable.
The VarTree that is returned can be turned back into a Drawable with
@@ -228,6 +206,12 @@ public:
/** Returns the tag ID that is used for a ValueTree that stores this type of drawable. */
virtual const Identifier getValueTreeType() const = 0;
/** Returns the area that this drawble covers.
The result is expressed in this drawable's own coordinate space, and does not take
into account any transforms that may be applied to the component.
*/
virtual const Rectangle<float> getDrawableBounds() const = 0;
//==============================================================================
/** Internal class used to manage ValueTrees that represent Drawables. */
class ValueTreeWrapperBase
@@ -250,15 +234,23 @@ public:
protected:
friend class DrawableComposite;
friend class DrawableShape;
/** @internal */
DrawableComposite* parent;
static Drawable* createChildFromValueTree (DrawableComposite* parent, const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
virtual void invalidatePoints() = 0;
void transformContextToCorrectOrigin (Graphics& g);
/** @internal */
static Drawable* createChildFromValueTree (DrawableComposite* parent, const ValueTree& tree, ImageProvider* imageProvider);
void markerHasMoved();
/** @internal */
void parentHierarchyChanged();
/** @internal */
void setBoundsToEnclose (const Rectangle<float>& area);
Point<int> originRelativeToComponent;
private:
String name;
void nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform);
Drawable (const Drawable&);
Drawable& operator= (const Drawable&);


+ 182
- 256
src/gui/graphics/drawables/juce_DrawableComposite.cpp View File

@@ -36,7 +36,8 @@ BEGIN_JUCE_NAMESPACE
//==============================================================================
DrawableComposite::DrawableComposite()
: bounds (Point<float>(), Point<float> (100.0f, 0.0f), Point<float> (0.0f, 100.0f))
: bounds (Point<float>(), Point<float> (100.0f, 0.0f), Point<float> (0.0f, 100.0f)),
updateBoundsReentrant (false)
{
setContentArea (RelativeRectangle (RelativeCoordinate (0.0),
RelativeCoordinate (100.0),
@@ -48,8 +49,8 @@ DrawableComposite::DrawableComposite (const DrawableComposite& other)
{
bounds = other.bounds;
for (int i = 0; i < other.drawables.size(); ++i)
drawables.add (other.drawables.getUnchecked(i)->createCopy());
for (int i = 0; i < other.getNumDrawables(); ++i)
insertDrawable (other.getDrawable(i)->createCopy());
markersX.addCopiesOf (other.markersX);
markersY.addCopiesOf (other.markersY);
@@ -57,18 +58,24 @@ DrawableComposite::DrawableComposite (const DrawableComposite& other)
DrawableComposite::~DrawableComposite()
{
deleteAllChildren();
}
//==============================================================================
int DrawableComposite::getNumDrawables() const throw()
{
return getNumChildComponents();
}
Drawable* DrawableComposite::getDrawable (int index) const
{
return dynamic_cast <Drawable*> (getChildComponent (index));
}
void DrawableComposite::insertDrawable (Drawable* drawable, const int index)
{
if (drawable != 0)
{
jassert (! drawables.contains (drawable)); // trying to add a drawable that's already in here!
jassert (drawable->parent == 0); // A drawable can only live inside one parent at a time!
drawables.insert (index, drawable);
drawable->parent = this;
}
addAndMakeVisible (drawable, index);
}
void DrawableComposite::insertDrawable (const Drawable& drawable, const int index)
@@ -78,50 +85,60 @@ void DrawableComposite::insertDrawable (const Drawable& drawable, const int inde
void DrawableComposite::removeDrawable (const int index, const bool deleteDrawable)
{
drawables.remove (index, deleteDrawable);
Drawable* const d = getDrawable (index);
if (deleteDrawable)
delete d;
else
removeChildComponent (d);
}
Drawable* DrawableComposite::getDrawableWithName (const String& name) const throw()
{
for (int i = drawables.size(); --i >= 0;)
if (drawables.getUnchecked(i)->getName() == name)
return drawables.getUnchecked(i);
for (int i = getNumChildComponents(); --i >= 0;)
if (getChildComponent(i)->getName() == name)
return getDrawable (i);
return 0;
}
void DrawableComposite::bringToFront (const int index)
{
if (index >= 0 && index < drawables.size() - 1)
drawables.move (index, -1);
Drawable* d = getDrawable (index);
if (d != 0)
d->toFront (false);
}
void DrawableComposite::setBoundingBox (const RelativeParallelogram& newBoundingBox)
const Rectangle<float> DrawableComposite::getDrawableBounds() const
{
bounds = newBoundingBox;
}
Rectangle<float> r;
//==============================================================================
DrawableComposite::Marker::Marker (const DrawableComposite::Marker& other)
: name (other.name), position (other.position)
{
}
for (int i = getNumDrawables(); --i >= 0;)
{
Drawable* const d = getDrawable(i);
DrawableComposite::Marker::Marker (const String& name_, const RelativeCoordinate& position_)
: name (name_), position (position_)
{
if (d != 0)
{
if (d->isTransformed())
r = r.getUnion (d->getDrawableBounds().transformed (d->getTransform()));
else
r = r.getUnion (d->getDrawableBounds());
}
}
return r;
}
bool DrawableComposite::Marker::operator!= (const DrawableComposite::Marker& other) const throw()
void DrawableComposite::markerHasMoved()
{
return name != other.name || position != other.position;
}
for (int i = getNumDrawables(); --i >= 0;)
{
Drawable* const d = getDrawable(i);
//==============================================================================
const char* const DrawableComposite::contentLeftMarkerName = "left";
const char* const DrawableComposite::contentRightMarkerName = "right";
const char* const DrawableComposite::contentTopMarkerName = "top";
const char* const DrawableComposite::contentBottomMarkerName = "bottom";
if (d != 0)
d->markerHasMoved();
}
}
const RelativeRectangle DrawableComposite::getContentArea() const
{
@@ -138,6 +155,13 @@ void DrawableComposite::setContentArea (const RelativeRectangle& newArea)
setMarker (contentRightMarkerName, true, newArea.right);
setMarker (contentTopMarkerName, false, newArea.top);
setMarker (contentBottomMarkerName, false, newArea.bottom);
refreshTransformFromBounds();
}
void DrawableComposite::setBoundingBox (const RelativeParallelogram& newBoundingBox)
{
bounds = newBoundingBox;
refreshTransformFromBounds();
}
void DrawableComposite::resetBoundingBoxToContentArea()
@@ -151,15 +175,111 @@ void DrawableComposite::resetBoundingBoxToContentArea()
void DrawableComposite::resetContentAreaAndBoundingBoxToFitChildren()
{
const Rectangle<float> bounds (getUntransformedBounds (false));
const Rectangle<float> activeArea (getDrawableBounds());
setContentArea (RelativeRectangle (RelativeCoordinate (bounds.getX()),
RelativeCoordinate (bounds.getRight()),
RelativeCoordinate (bounds.getY()),
RelativeCoordinate (bounds.getBottom())));
setContentArea (RelativeRectangle (RelativeCoordinate (activeArea.getX()),
RelativeCoordinate (activeArea.getRight()),
RelativeCoordinate (activeArea.getY()),
RelativeCoordinate (activeArea.getBottom())));
resetBoundingBoxToContentArea();
}
void DrawableComposite::refreshTransformFromBounds()
{
Point<float> resolved[3];
bounds.resolveThreePoints (resolved, getParent());
const Rectangle<float> content (getContentArea().resolve (getParent()));
AffineTransform t (AffineTransform::fromTargetPoints (content.getX(), content.getY(), resolved[0].getX(), resolved[0].getY(),
content.getRight(), content.getY(), resolved[1].getX(), resolved[1].getY(),
content.getX(), content.getBottom(), resolved[2].getX(), resolved[2].getY()));
if (! t.isSingularity())
setTransform (t);
}
void DrawableComposite::parentHierarchyChanged()
{
DrawableComposite* parent = getParent();
if (parent != 0)
originRelativeToComponent = parent->originRelativeToComponent - getPosition();
}
void DrawableComposite::childBoundsChanged (Component*)
{
updateBoundsToFitChildren();
}
void DrawableComposite::childrenChanged()
{
updateBoundsToFitChildren();
}
void DrawableComposite::updateBoundsToFitChildren()
{
if (! updateBoundsReentrant)
{
struct RentrancyCheckSetter
{
RentrancyCheckSetter (bool& b_) : b (b_) { b_ = true; }
~RentrancyCheckSetter() { b = false; }
private:
bool& b;
};
const RentrancyCheckSetter checkSetter (updateBoundsReentrant);
Rectangle<int> childArea;
for (int i = getNumChildComponents(); --i >= 0;)
childArea = childArea.getUnion (getChildComponent(i)->getBoundsInParent());
const Point<int> delta (childArea.getPosition());
childArea += getPosition();
if (childArea != getBounds())
{
if (! delta.isOrigin())
{
originRelativeToComponent -= delta;
for (int i = getNumChildComponents(); --i >= 0;)
{
Component* const c = getChildComponent(i);
if (c != 0)
c->setBounds (c->getBounds() - delta);
}
}
setBounds (childArea);
}
}
}
//==============================================================================
const char* const DrawableComposite::contentLeftMarkerName = "left";
const char* const DrawableComposite::contentRightMarkerName = "right";
const char* const DrawableComposite::contentTopMarkerName = "top";
const char* const DrawableComposite::contentBottomMarkerName = "bottom";
DrawableComposite::Marker::Marker (const DrawableComposite::Marker& other)
: name (other.name), position (other.position)
{
}
DrawableComposite::Marker::Marker (const String& name_, const RelativeCoordinate& position_)
: name (name_), position (position_)
{
}
bool DrawableComposite::Marker::operator!= (const DrawableComposite::Marker& other) const throw()
{
return name != other.name || position != other.position;
}
int DrawableComposite::getNumMarkers (const bool xAxis) const throw()
{
return (xAxis ? markersX : markersY).size();
@@ -182,7 +302,7 @@ void DrawableComposite::setMarker (const String& name, const bool xAxis, const R
if (m->position != position)
{
m->position = position;
invalidatePoints();
markerHasMoved();
}
return;
@@ -190,7 +310,7 @@ void DrawableComposite::setMarker (const String& name, const bool xAxis, const R
}
(xAxis ? markersX : markersY).add (new Marker (name, position));
invalidatePoints();
markerHasMoved();
}
void DrawableComposite::removeMarker (const bool xAxis, const int index)
@@ -202,55 +322,6 @@ void DrawableComposite::removeMarker (const bool xAxis, const int index)
}
//==============================================================================
const AffineTransform DrawableComposite::calculateTransform() const
{
Point<float> resolved[3];
bounds.resolveThreePoints (resolved, parent);
const Rectangle<float> content (getContentArea().resolve (parent));
return AffineTransform::fromTargetPoints (content.getX(), content.getY(), resolved[0].getX(), resolved[0].getY(),
content.getRight(), content.getY(), resolved[1].getX(), resolved[1].getY(),
content.getX(), content.getBottom(), resolved[2].getX(), resolved[2].getY());
}
void DrawableComposite::render (const Drawable::RenderingContext& context) const
{
if (drawables.size() > 0 && context.opacity > 0)
{
if (context.opacity >= 1.0f || drawables.size() == 1)
{
Drawable::RenderingContext contextCopy (context);
contextCopy.transform = calculateTransform().followedBy (context.transform);
for (int i = 0; i < drawables.size(); ++i)
drawables.getUnchecked(i)->render (contextCopy);
}
else
{
// To correctly render a whole composite layer with an overall transparency,
// we need to render everything opaquely into a temp buffer, then blend that
// with the target opacity...
const Rectangle<int> clipBounds (context.g.getClipBounds());
if (! clipBounds.isEmpty())
{
Image tempImage (Image::ARGB, clipBounds.getWidth(), clipBounds.getHeight(), true);
{
Graphics tempG (tempImage);
tempG.setOrigin (-clipBounds.getX(), -clipBounds.getY());
Drawable::RenderingContext tempContext (tempG, context.transform, 1.0f);
render (tempContext);
}
context.g.setOpacity (context.opacity);
context.g.drawImageAt (tempImage, clipBounds.getX(), clipBounds.getY());
}
}
}
}
const Expression DrawableComposite::getSymbolValue (const String& symbol, const String& member) const
{
jassert (member.isEmpty()) // the only symbols available in a Drawable are markers.
@@ -273,99 +344,11 @@ const Expression DrawableComposite::getSymbolValue (const String& symbol, const
throw Expression::EvaluationError (symbol, member);
}
const Rectangle<float> DrawableComposite::getUntransformedBounds (const bool includeMarkers) const
{
Rectangle<float> bounds;
int i;
for (i = 0; i < drawables.size(); ++i)
bounds = bounds.getUnion (drawables.getUnchecked(i)->getBounds());
if (includeMarkers)
{
if (markersX.size() > 0)
{
float minX = std::numeric_limits<float>::max();
float maxX = std::numeric_limits<float>::min();
for (i = markersX.size(); --i >= 0;)
{
const Marker* m = markersX.getUnchecked(i);
const float pos = (float) m->position.resolve (this);
minX = jmin (minX, pos);
maxX = jmax (maxX, pos);
}
if (minX <= maxX)
{
if (bounds.getHeight() > 0)
{
minX = jmin (minX, bounds.getX());
maxX = jmax (maxX, bounds.getRight());
}
bounds.setLeft (minX);
bounds.setWidth (maxX - minX);
}
}
if (markersY.size() > 0)
{
float minY = std::numeric_limits<float>::max();
float maxY = std::numeric_limits<float>::min();
for (i = markersY.size(); --i >= 0;)
{
const Marker* m = markersY.getUnchecked(i);
const float pos = (float) m->position.resolve (this);
minY = jmin (minY, pos);
maxY = jmax (maxY, pos);
}
if (minY <= maxY)
{
if (bounds.getHeight() > 0)
{
minY = jmin (minY, bounds.getY());
maxY = jmax (maxY, bounds.getBottom());
}
bounds.setTop (minY);
bounds.setHeight (maxY - minY);
}
}
}
return bounds;
}
const Rectangle<float> DrawableComposite::getBounds() const
{
return getUntransformedBounds (true).transformed (calculateTransform());
}
bool DrawableComposite::hitTest (float x, float y) const
{
calculateTransform().inverted().transformPoint (x, y);
for (int i = 0; i < drawables.size(); ++i)
if (drawables.getUnchecked(i)->hitTest (x, y))
return true;
return false;
}
Drawable* DrawableComposite::createCopy() const
{
return new DrawableComposite (*this);
}
void DrawableComposite::invalidatePoints()
{
for (int i = 0; i < drawables.size(); ++i)
drawables.getUnchecked(i)->invalidatePoints();
}
//==============================================================================
const Identifier DrawableComposite::valueTreeType ("Group");
@@ -564,21 +547,14 @@ void DrawableComposite::ValueTreeWrapper::removeMarker (bool xAxis, const ValueT
}
//==============================================================================
const Rectangle<float> DrawableComposite::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider)
void DrawableComposite::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider)
{
const ValueTreeWrapper wrapper (tree);
setName (wrapper.getID());
Rectangle<float> damage;
bool redrawAll = false;
const RelativeParallelogram newBounds (wrapper.getBoundingBox());
if (bounds != newBounds)
{
redrawAll = true;
damage = getBounds();
bounds = newBounds;
}
const int numMarkersX = wrapper.getNumMarkers (true);
const int numMarkersY = wrapper.getNumMarkers (false);
@@ -586,12 +562,6 @@ const Rectangle<float> DrawableComposite::refreshFromValueTree (const ValueTree&
// Remove deleted markers...
if (markersX.size() > numMarkersX || markersY.size() > numMarkersY)
{
if (! redrawAll)
{
redrawAll = true;
damage = getBounds();
}
markersX.removeRange (jmax (2, numMarkersX), markersX.size());
markersY.removeRange (jmax (2, numMarkersY), markersY.size());
}
@@ -603,19 +573,10 @@ const Rectangle<float> DrawableComposite::refreshFromValueTree (const ValueTree&
const Marker newMarker (wrapper.getMarker (true, wrapper.getMarkerState (true, i)));
Marker* m = markersX[i];
if (m == 0 || newMarker != *m)
{
if (! redrawAll)
{
redrawAll = true;
damage = getBounds();
}
if (m == 0)
markersX.add (new Marker (newMarker));
else
*m = newMarker;
}
if (m == 0)
markersX.add (new Marker (newMarker));
else if (newMarker != *m)
*m = newMarker;
}
for (i = 0; i < numMarkersY; ++i)
@@ -623,78 +584,43 @@ const Rectangle<float> DrawableComposite::refreshFromValueTree (const ValueTree&
const Marker newMarker (wrapper.getMarker (false, wrapper.getMarkerState (false, i)));
Marker* m = markersY[i];
if (m == 0 || newMarker != *m)
{
if (! redrawAll)
{
redrawAll = true;
damage = getBounds();
}
if (m == 0)
markersY.add (new Marker (newMarker));
else
*m = newMarker;
}
if (m == 0)
markersY.add (new Marker (newMarker));
else if (newMarker != *m)
*m = newMarker;
}
// Remove deleted drawables..
for (i = drawables.size(); --i >= wrapper.getNumDrawables();)
{
Drawable* const d = drawables.getUnchecked(i);
if (! redrawAll)
damage = damage.getUnion (d->getBounds());
d->parent = 0;
drawables.remove (i);
}
for (i = getNumDrawables(); --i >= wrapper.getNumDrawables();)
delete getDrawable(i);
// Update drawables and add new ones..
for (i = 0; i < wrapper.getNumDrawables(); ++i)
{
const ValueTree newDrawable (wrapper.getDrawableState (i));
Drawable* d = drawables[i];
Drawable* d = getDrawable(i);
if (d != 0)
{
if (newDrawable.hasType (d->getValueTreeType()))
{
const Rectangle<float> area (d->refreshFromValueTree (newDrawable, imageProvider));
if (! redrawAll)
damage = damage.getUnion (area);
d->refreshFromValueTree (newDrawable, imageProvider);
}
else
{
if (! redrawAll)
damage = damage.getUnion (d->getBounds());
d = createChildFromValueTree (this, newDrawable, imageProvider);
drawables.set (i, d);
if (! redrawAll)
damage = damage.getUnion (d->getBounds());
delete d;
d = 0;
}
}
else
if (d == 0)
{
d = createChildFromValueTree (this, newDrawable, imageProvider);
drawables.set (i, d);
if (! redrawAll)
damage = damage.getUnion (d->getBounds());
addAndMakeVisible (d, i);
}
}
invalidatePoints();
if (redrawAll)
damage = damage.getUnion (getBounds());
else if (! damage.isEmpty())
damage = damage.transformed (calculateTransform());
return damage;
refreshTransformFromBounds();
}
const ValueTree DrawableComposite::createValueTree (ImageProvider* imageProvider) const
@@ -706,8 +632,8 @@ const ValueTree DrawableComposite::createValueTree (ImageProvider* imageProvider
v.setBoundingBox (bounds, 0);
int i;
for (i = 0; i < drawables.size(); ++i)
v.addDrawable (drawables.getUnchecked(i)->createValueTree (imageProvider), -1, 0);
for (i = 0; i < getNumDrawables(); ++i)
v.addDrawable (getDrawable(i)->createValueTree (imageProvider), -1, 0);
for (i = 0; i < markersX.size(); ++i)
v.setMarker (true, *markersX.getUnchecked(i), 0);


+ 30
- 28
src/gui/graphics/drawables/juce_DrawableComposite.h View File

@@ -93,7 +93,7 @@ public:
@see getDrawable
*/
int getNumDrawables() const throw() { return drawables.size(); }
int getNumDrawables() const throw();
/** Returns one of the drawables that are contained in this one.
@@ -105,7 +105,7 @@ public:
@see getNumDrawables
*/
Drawable* getDrawable (int index) const throw() { return drawables [index]; }
Drawable* getDrawable (int index) const;
/** Looks for a child drawable with the specified name. */
Drawable* getDrawableWithName (const String& name) const throw();
@@ -119,20 +119,6 @@ public:
void bringToFront (int index);
//==============================================================================
/** Returns the main content rectangle.
The content area is actually defined by the markers named "left", "right", "top" and
"bottom", but this method is a shortcut that returns them all at once.
@see contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName
*/
const RelativeRectangle getContentArea() const;
/** Changes the main content area.
The content area is actually defined by the markers named "left", "right", "top" and
"bottom", but this method is a shortcut that sets them all at once.
@see setBoundingBox, contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName
*/
void setContentArea (const RelativeRectangle& newArea);
/** Sets the parallelogram that defines the target position of the content rectangle when the drawable is rendered.
@see setContentArea
*/
@@ -148,6 +134,20 @@ public:
*/
void resetBoundingBoxToContentArea();
/** Returns the main content rectangle.
The content area is actually defined by the markers named "left", "right", "top" and
"bottom", but this method is a shortcut that returns them all at once.
@see contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName
*/
const RelativeRectangle getContentArea() const;
/** Changes the main content area.
The content area is actually defined by the markers named "left", "right", "top" and
"bottom", but this method is a shortcut that sets them all at once.
@see setBoundingBox, contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName
*/
void setContentArea (const RelativeRectangle& newArea);
/** Resets the content area and the bounding transform to fit around the area occupied
by the child components (ignoring any markers).
*/
@@ -183,17 +183,9 @@ public:
//==============================================================================
/** @internal */
void render (const Drawable::RenderingContext& context) const;
/** @internal */
const Rectangle<float> getBounds() const;
/** @internal */
bool hitTest (float x, float y) const;
/** @internal */
Drawable* createCopy() const;
/** @internal */
void invalidatePoints();
/** @internal */
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
const ValueTree createValueTree (ImageProvider* imageProvider) const;
/** @internal */
@@ -202,6 +194,16 @@ public:
const Identifier getValueTreeType() const { return valueTreeType; }
/** @internal */
const Expression getSymbolValue (const String& symbol, const String& member) const;
/** @internal */
const Rectangle<float> getDrawableBounds() const;
/** @internal */
void markerHasMoved();
/** @internal */
void childBoundsChanged (Component*);
/** @internal */
void childrenChanged();
/** @internal */
void parentHierarchyChanged();
//==============================================================================
/** Internally-used class for wrapping a DrawableComposite's state into a ValueTree. */
@@ -248,12 +250,12 @@ public:
juce_UseDebuggingNewOperator
private:
OwnedArray <Drawable> drawables;
RelativeParallelogram bounds;
OwnedArray <Marker> markersX, markersY;
bool updateBoundsReentrant;
const Rectangle<float> getUntransformedBounds (bool includeMarkers) const;
const AffineTransform calculateTransform() const;
void refreshTransformFromBounds();
void updateBoundsToFitChildren();
DrawableComposite& operator= (const DrawableComposite&);
};


+ 33
- 49
src/gui/graphics/drawables/juce_DrawableImage.cpp View File

@@ -59,12 +59,16 @@ void DrawableImage::setImage (const Image& imageToUse)
{
image = imageToUse;
setBounds (imageToUse.getBounds());
if (image.isValid())
{
bounds.topLeft = RelativePoint (Point<float> (0.0f, 0.0f));
bounds.topRight = RelativePoint (Point<float> ((float) image.getWidth(), 0.0f));
bounds.bottomLeft = RelativePoint (Point<float> (0.0f, (float) image.getHeight()));
}
refreshTransformFromBounds();
}
void DrawableImage::setOpacity (const float newOpacity)
@@ -80,68 +84,57 @@ void DrawableImage::setOverlayColour (const Colour& newOverlayColour)
void DrawableImage::setBoundingBox (const RelativeParallelogram& newBounds)
{
bounds = newBounds;
refreshTransformFromBounds();
}
//==============================================================================
const AffineTransform DrawableImage::calculateTransform() const
void DrawableImage::refreshTransformFromBounds()
{
if (image.isNull())
return AffineTransform::identity;
if (! image.isNull())
{
Point<float> resolved[3];
bounds.resolveThreePoints (resolved, getParent());
Point<float> resolved[3];
bounds.resolveThreePoints (resolved, parent);
const Point<float> tr (resolved[0] + (resolved[1] - resolved[0]) / (float) image.getWidth());
const Point<float> bl (resolved[0] + (resolved[2] - resolved[0]) / (float) image.getHeight());
const Point<float> tr (resolved[0] + (resolved[1] - resolved[0]) / (float) image.getWidth());
const Point<float> bl (resolved[0] + (resolved[2] - resolved[0]) / (float) image.getHeight());
AffineTransform t (AffineTransform::fromTargetPoints (resolved[0].getX(), resolved[0].getY(),
tr.getX(), tr.getY(),
bl.getX(), bl.getY()));
return AffineTransform::fromTargetPoints (resolved[0].getX(), resolved[0].getY(),
tr.getX(), tr.getY(),
bl.getX(), bl.getY());
if (! t.isSingularity())
setTransform (t);
}
}
void DrawableImage::render (const Drawable::RenderingContext& context) const
//==============================================================================
void DrawableImage::paint (Graphics& g)
{
if (image.isValid())
{
const AffineTransform t (calculateTransform().followedBy (context.transform));
if (opacity > 0.0f && ! overlayColour.isOpaque())
{
context.g.setOpacity (context.opacity * opacity);
context.g.drawImageTransformed (image, t, false);
g.setOpacity (opacity);
g.drawImageAt (image, 0, 0, false);
}
if (! overlayColour.isTransparent())
{
context.g.setColour (overlayColour.withMultipliedAlpha (context.opacity));
context.g.drawImageTransformed (image, t, true);
g.setColour (overlayColour.withMultipliedAlpha (opacity));
g.drawImageAt (image, 0, 0, true);
}
}
}
const Rectangle<float> DrawableImage::getBounds() const
const Rectangle<float> DrawableImage::getDrawableBounds() const
{
if (image.isNull())
return Rectangle<float>();
return bounds.getBounds (parent);
return image.getBounds().toFloat();
}
bool DrawableImage::hitTest (float x, float y) const
bool DrawableImage::hitTest (int x, int y) const
{
if (image.isNull())
return false;
calculateTransform().inverted().transformPoint (x, y);
const int ix = roundToInt (x);
const int iy = roundToInt (y);
return ix >= 0
&& iy >= 0
&& ix < image.getWidth()
&& iy < image.getHeight()
&& image.getPixelAt (ix, iy).getAlpha() >= 127;
return (! image.isNull())
&& image.getPixelAt (x, y).getAlpha() >= 127;
}
Drawable* DrawableImage::createCopy() const
@@ -149,10 +142,6 @@ Drawable* DrawableImage::createCopy() const
return new DrawableImage (*this);
}
void DrawableImage::invalidatePoints()
{
}
//==============================================================================
const Identifier DrawableImage::valueTreeType ("Image");
@@ -237,7 +226,7 @@ void DrawableImage::ValueTreeWrapper::setBoundingBox (const RelativeParallelogra
//==============================================================================
const Rectangle<float> DrawableImage::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider)
void DrawableImage::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider)
{
const ValueTreeWrapper controller (tree);
setName (controller.getID());
@@ -255,19 +244,14 @@ const Rectangle<float> DrawableImage::refreshFromValueTree (const ValueTree& tre
const RelativeParallelogram newBounds (controller.getBoundingBox());
if (newOpacity != opacity || overlayColour != newOverlayColour || image != newImage || bounds != newBounds)
if (newOpacity != opacity || overlayColour != newOverlayColour || image != newImage)
{
const Rectangle<float> damage (getBounds());
repaint();
opacity = newOpacity;
overlayColour = newOverlayColour;
bounds = newBounds;
image = newImage;
return damage.getUnion (getBounds());
setImage (newImage);
}
return Rectangle<float>();
}
const ValueTree DrawableImage::createValueTree (ImageProvider* imageProvider) const


+ 5
- 7
src/gui/graphics/drawables/juce_DrawableImage.h View File

@@ -84,17 +84,15 @@ public:
//==============================================================================
/** @internal */
void render (const Drawable::RenderingContext& context) const;
void paint (Graphics& g);
/** @internal */
const Rectangle<float> getBounds() const;
/** @internal */
bool hitTest (float x, float y) const;
bool hitTest (int x, int y) const;
/** @internal */
Drawable* createCopy() const;
/** @internal */
void invalidatePoints();
const Rectangle<float> getDrawableBounds() const;
/** @internal */
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
const ValueTree createValueTree (ImageProvider* imageProvider) const;
/** @internal */
@@ -136,7 +134,7 @@ private:
Colour overlayColour;
RelativeParallelogram bounds;
const AffineTransform calculateTransform() const;
void refreshTransformFromBounds();
DrawableImage& operator= (const DrawableImage&);
};


+ 14
- 21
src/gui/graphics/drawables/juce_DrawablePath.cpp View File

@@ -42,7 +42,7 @@ DrawablePath::DrawablePath (const DrawablePath& other)
if (other.relativePath != 0)
relativePath = new RelativePointPath (*other.relativePath);
else
cachedPath = other.cachedPath;
setPath (other.path);
}
DrawablePath::~DrawablePath()
@@ -57,18 +57,18 @@ Drawable* DrawablePath::createCopy() const
//==============================================================================
void DrawablePath::setPath (const Path& newPath)
{
cachedPath = newPath;
strokeChanged();
path = newPath;
pathChanged();
}
const Path& DrawablePath::getPath() const
{
return getCachedPath();
return path;
}
const Path& DrawablePath::getStrokePath() const
{
return getCachedStrokePath();
return strokePath;
}
bool DrawablePath::rebuildPath (Path& path) const
@@ -76,7 +76,7 @@ bool DrawablePath::rebuildPath (Path& path) const
if (relativePath != 0)
{
path.clear();
relativePath->createPath (path, parent);
relativePath->createPath (path, getParent());
return true;
}
@@ -440,38 +440,31 @@ void DrawablePath::ValueTreeWrapper::Element::removePoint (UndoManager* undoMana
}
//==============================================================================
const Rectangle<float> DrawablePath::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider)
void DrawablePath::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider)
{
Rectangle<float> damageRect;
ValueTreeWrapper v (tree);
setName (v.getID());
bool needsRedraw = refreshFillTypes (v, parent, imageProvider);
if (refreshFillTypes (v, getParent(), imageProvider))
repaint();
ScopedPointer<RelativePointPath> newRelativePath (new RelativePointPath (tree));
Path newPath;
newRelativePath->createPath (newPath, parent);
newRelativePath->createPath (newPath, getParent());
if (! newRelativePath->containsAnyDynamicPoints())
newRelativePath = 0;
const PathStrokeType newStroke (v.getStrokeType());
if (strokeType != newStroke || cachedPath != newPath)
if (strokeType != newStroke || path != newPath)
{
damageRect = getBounds();
cachedPath.swapWithPath (newPath);
strokeChanged();
path.swapWithPath (newPath);
strokeType = newStroke;
needsRedraw = true;
pathChanged();
}
relativePath = newRelativePath;
if (needsRedraw)
damageRect = damageRect.getUnion (getBounds());
return damageRect;
}
const ValueTree DrawablePath::createValueTree (ImageProvider* imageProvider) const
@@ -488,7 +481,7 @@ const ValueTree DrawablePath::createValueTree (ImageProvider* imageProvider) con
}
else
{
RelativePointPath rp (getCachedPath());
RelativePointPath rp (path);
rp.writeTo (tree, 0);
}


+ 1
- 1
src/gui/graphics/drawables/juce_DrawablePath.h View File

@@ -64,7 +64,7 @@ public:
/** @internal */
Drawable* createCopy() const;
/** @internal */
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
const ValueTree createValueTree (ImageProvider* imageProvider) const;
/** @internal */


+ 8
- 15
src/gui/graphics/drawables/juce_DrawableRectangle.cpp View File

@@ -68,13 +68,13 @@ void DrawableRectangle::setCornerSize (const RelativePoint& newSize)
bool DrawableRectangle::rebuildPath (Path& path) const
{
Point<float> points[3];
bounds.resolveThreePoints (points, parent);
bounds.resolveThreePoints (points, getParent());
const float w = Line<float> (points[0], points[1]).getLength();
const float h = Line<float> (points[0], points[2]).getLength();
const float cornerSizeX = (float) cornerSize.x.resolve (parent);
const float cornerSizeY = (float) cornerSize.y.resolve (parent);
const float cornerSizeX = (float) cornerSize.x.resolve (getParent());
const float cornerSizeY = (float) cornerSize.y.resolve (getParent());
path.clear();
@@ -92,7 +92,7 @@ bool DrawableRectangle::rebuildPath (Path& path) const
const AffineTransform DrawableRectangle::calculateTransform() const
{
Point<float> resolved[3];
bounds.resolveThreePoints (resolved, parent);
bounds.resolveThreePoints (resolved, getParent());
return AffineTransform::fromTargetPoints (resolved[0].getX(), resolved[0].getY(),
resolved[1].getX(), resolved[1].getY(),
@@ -143,13 +143,13 @@ Value DrawableRectangle::ValueTreeWrapper::getCornerSizeValue (UndoManager* undo
}
//==============================================================================
const Rectangle<float> DrawableRectangle::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider)
void DrawableRectangle::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider)
{
Rectangle<float> damageRect;
ValueTreeWrapper v (tree);
setName (v.getID());
bool needsRedraw = refreshFillTypes (v, parent, imageProvider);
if (refreshFillTypes (v, getParent(), imageProvider))
repaint();
RelativeParallelogram newBounds (v.getRectangle());
@@ -158,19 +158,12 @@ const Rectangle<float> DrawableRectangle::refreshFromValueTree (const ValueTree&
if (strokeType != newStroke || newBounds != bounds || newCornerSize != cornerSize)
{
damageRect = getBounds();
repaint();
bounds = newBounds;
strokeType = newStroke;
cornerSize = newCornerSize;
pathChanged();
strokeChanged();
needsRedraw = true;
}
if (needsRedraw)
damageRect = damageRect.getUnion (getBounds());
return damageRect;
}
const ValueTree DrawableRectangle::createValueTree (ImageProvider* imageProvider) const


+ 1
- 1
src/gui/graphics/drawables/juce_DrawableRectangle.h View File

@@ -64,7 +64,7 @@ public:
/** @internal */
Drawable* createCopy() const;
/** @internal */
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
const ValueTree createValueTree (ImageProvider* imageProvider) const;
/** @internal */


+ 26
- 65
src/gui/graphics/drawables/juce_DrawableShape.cpp View File

@@ -35,18 +35,14 @@ BEGIN_JUCE_NAMESPACE
DrawableShape::DrawableShape()
: strokeType (0.0f),
mainFill (Colours::black),
strokeFill (Colours::black),
pathNeedsUpdating (true),
strokeNeedsUpdating (true)
strokeFill (Colours::black)
{
}
DrawableShape::DrawableShape (const DrawableShape& other)
: strokeType (other.strokeType),
mainFill (other.mainFill),
strokeFill (other.strokeFill),
pathNeedsUpdating (true),
strokeNeedsUpdating (true)
strokeFill (other.strokeFill)
{
}
@@ -67,7 +63,7 @@ void DrawableShape::setStrokeFill (const FillType& newFill)
void DrawableShape::setStrokeType (const PathStrokeType& newStrokeType)
{
strokeType = newStrokeType;
strokeNeedsUpdating = true;
strokeChanged();
}
void DrawableShape::setStrokeThickness (const float newThickness)
@@ -80,18 +76,6 @@ bool DrawableShape::isStrokeVisible() const throw()
return strokeType.getStrokeThickness() > 0.0f && ! strokeFill.isInvisible();
}
void DrawableShape::setBrush (const Drawable::RenderingContext& context, const FillType& type)
{
FillType f (type);
if (f.isGradient())
f.gradient->multiplyOpacity (context.opacity);
else
f.setOpacity (f.getOpacity() * context.opacity);
f.transform = f.transform.followedBy (context.transform);
context.g.setFillType (f);
}
bool DrawableShape::refreshFillTypes (const FillAndStrokeState& newState,
Expression::EvaluationContext* /*nameFinder*/,
ImageProvider* imageProvider)
@@ -99,7 +83,7 @@ bool DrawableShape::refreshFillTypes (const FillAndStrokeState& newState,
bool hasChanged = false;
{
const FillType f (newState.getMainFill (parent, imageProvider));
const FillType f (newState.getMainFill (getParent(), imageProvider));
if (mainFill != f)
{
@@ -109,7 +93,7 @@ bool DrawableShape::refreshFillTypes (const FillAndStrokeState& newState,
}
{
const FillType f (newState.getStrokeFill (parent, imageProvider));
const FillType f (newState.getStrokeFill (getParent(), imageProvider));
if (strokeFill != f)
{
@@ -129,73 +113,50 @@ void DrawableShape::writeTo (FillAndStrokeState& state, ImageProvider* imageProv
}
//==============================================================================
void DrawableShape::render (const Drawable::RenderingContext& context) const
void DrawableShape::paint (Graphics& g)
{
setBrush (context, mainFill);
context.g.fillPath (getCachedPath(), context.transform);
transformContextToCorrectOrigin (g);
g.setFillType (mainFill);
g.fillPath (path);
if (isStrokeVisible())
{
setBrush (context, strokeFill);
context.g.fillPath (getCachedStrokePath(), context.transform);
g.setFillType (strokeFill);
g.fillPath (strokePath);
}
}
void DrawableShape::pathChanged()
{
pathNeedsUpdating = true;
strokeChanged();
}
void DrawableShape::strokeChanged()
{
strokeNeedsUpdating = true;
}
strokePath.clear();
strokeType.createStrokedPath (strokePath, path, AffineTransform::identity, 4.0f);
void DrawableShape::invalidatePoints()
{
pathNeedsUpdating = true;
strokeNeedsUpdating = true;
setBoundsToEnclose (getDrawableBounds());
repaint();
}
const Path& DrawableShape::getCachedPath() const
{
if (pathNeedsUpdating)
{
pathNeedsUpdating = false;
if (rebuildPath (cachedPath))
strokeNeedsUpdating = true;
}
return cachedPath;
}
const Path& DrawableShape::getCachedStrokePath() const
{
if (strokeNeedsUpdating)
{
cachedStroke.clear();
strokeType.createStrokedPath (cachedStroke, getCachedPath(), AffineTransform::identity, 4.0f);
strokeNeedsUpdating = false; // (must be called after getCachedPath)
}
return cachedStroke;
}
const Rectangle<float> DrawableShape::getBounds() const
const Rectangle<float> DrawableShape::getDrawableBounds() const
{
if (isStrokeVisible())
return getCachedStrokePath().getBounds();
return strokePath.getBounds();
else
return getCachedPath().getBounds();
return path.getBounds();
}
bool DrawableShape::hitTest (float x, float y) const
bool DrawableShape::hitTest (int x, int y) const
{
return getCachedPath().contains (x, y)
|| (isStrokeVisible() && getCachedStrokePath().contains (x, y));
}
const float globalX = x - originRelativeToComponent.getX();
const float globalY = y - originRelativeToComponent.getY();
return path.contains (globalX, globalY)
|| (isStrokeVisible() && strokePath.contains (globalX, globalY));
}
//==============================================================================
const Identifier DrawableShape::FillAndStrokeState::type ("type");


+ 4
- 13
src/gui/graphics/drawables/juce_DrawableShape.h View File

@@ -127,13 +127,11 @@ public:
};
/** @internal */
void invalidatePoints();
const Rectangle<float> getDrawableBounds() const;
/** @internal */
void render (const Drawable::RenderingContext& context) const;
void paint (Graphics& g);
/** @internal */
const Rectangle<float> getBounds() const;
/** @internal */
bool hitTest (float x, float y) const;
bool hitTest (int x, int y) const;
protected:
//==============================================================================
@@ -156,20 +154,13 @@ protected:
/** Writes the stroke and fill details to a FillAndStrokeState object. */
void writeTo (FillAndStrokeState& state, ImageProvider* imageProvider, UndoManager* undoManager) const;
/** Returns the current cached path outline. */
const Path& getCachedPath() const;
/** Returns the current cached stroke outline. */
const Path& getCachedStrokePath() const;
//==============================================================================
PathStrokeType strokeType;
mutable Path cachedPath, cachedStroke;
Path path, strokePath;
private:
FillType mainFill, strokeFill;
mutable bool pathNeedsUpdating, strokeNeedsUpdating;
static void setBrush (const Drawable::RenderingContext& context, const FillType& type);
DrawableShape& operator= (const DrawableShape&);
};


+ 27
- 31
src/gui/graphics/drawables/juce_DrawableText.cpp View File

@@ -57,14 +57,22 @@ DrawableText::~DrawableText()
}
//==============================================================================
void DrawableText::refreshBounds()
{
setBoundsToEnclose (getDrawableBounds());
repaint();
}
void DrawableText::setText (const String& newText)
{
text = newText;
refreshBounds();
}
void DrawableText::setColour (const Colour& newColour)
{
colour = newColour;
repaint();
}
void DrawableText::setFont (const Font& newFont, bool applySizeAndScale)
@@ -74,38 +82,45 @@ void DrawableText::setFont (const Font& newFont, bool applySizeAndScale)
if (applySizeAndScale)
{
Point<float> corners[3];
bounds.resolveThreePoints (corners, parent);
bounds.resolveThreePoints (corners, getParent());
setFontSizeControlPoint (RelativePoint (RelativeParallelogram::getPointForInternalCoord (corners,
Point<float> (font.getHorizontalScale() * font.getHeight(), font.getHeight()))));
}
refreshBounds();
}
void DrawableText::setJustification (const Justification& newJustification)
{
justification = newJustification;
repaint();
}
void DrawableText::setBoundingBox (const RelativeParallelogram& newBounds)
{
bounds = newBounds;
refreshBounds();
}
void DrawableText::setFontSizeControlPoint (const RelativePoint& newPoint)
{
fontSizeControlPoint = newPoint;
refreshBounds();
}
//==============================================================================
void DrawableText::render (const Drawable::RenderingContext& context) const
void DrawableText::paint (Graphics& g)
{
transformContextToCorrectOrigin (g);
Point<float> points[3];
bounds.resolveThreePoints (points, parent);
bounds.resolveThreePoints (points, getParent());
const float w = Line<float> (points[0], points[1]).getLength();
const float h = Line<float> (points[0], points[2]).getLength();
const Point<float> fontCoords (bounds.getInternalCoordForPoint (points, fontSizeControlPoint.resolve (parent)));
const Point<float> fontCoords (bounds.getInternalCoordForPoint (points, fontSizeControlPoint.resolve (getParent())));
const float fontHeight = jlimit (0.01f, jmax (0.01f, h), fontCoords.getY());
const float fontWidth = jlimit (0.01f, jmax (0.01f, w), fontCoords.getX());
@@ -113,27 +128,18 @@ void DrawableText::render (const Drawable::RenderingContext& context) const
f.setHeight (fontHeight);
f.setHorizontalScale (fontWidth / fontHeight);
context.g.setColour (colour.withMultipliedAlpha (context.opacity));
g.setColour (colour);
GlyphArrangement ga;
ga.addFittedText (f, text, 0, 0, w, h, justification, 0x100000);
ga.draw (context.g,
AffineTransform::fromTargetPoints (0, 0, points[0].getX(), points[0].getY(),
w, 0, points[1].getX(), points[1].getY(),
0, h, points[2].getX(), points[2].getY())
.followedBy (context.transform));
}
const Rectangle<float> DrawableText::getBounds() const
{
return bounds.getBounds (parent);
ga.draw (g, AffineTransform::fromTargetPoints (0, 0, points[0].getX(), points[0].getY(),
w, 0, points[1].getX(), points[1].getY(),
0, h, points[2].getX(), points[2].getY()));
}
bool DrawableText::hitTest (float x, float y) const
const Rectangle<float> DrawableText::getDrawableBounds() const
{
Path p;
bounds.getPath (p, parent);
return p.contains (x, y);
return bounds.getBounds (getParent());
}
Drawable* DrawableText::createCopy() const
@@ -141,10 +147,6 @@ Drawable* DrawableText::createCopy() const
return new DrawableText (*this);
}
void DrawableText::invalidatePoints()
{
}
//==============================================================================
const Identifier DrawableText::valueTreeType ("Text");
@@ -237,7 +239,7 @@ void DrawableText::ValueTreeWrapper::setFontSizeControlPoint (const RelativePoin
}
//==============================================================================
const Rectangle<float> DrawableText::refreshFromValueTree (const ValueTree& tree, ImageProvider*)
void DrawableText::refreshFromValueTree (const ValueTree& tree, ImageProvider*)
{
ValueTreeWrapper v (tree);
setName (v.getID());
@@ -252,20 +254,14 @@ const Rectangle<float> DrawableText::refreshFromValueTree (const ValueTree& tree
if (text != newText || font != newFont || justification != newJustification
|| colour != newColour || bounds != newBounds || newFontPoint != fontSizeControlPoint)
{
const Rectangle<float> damage (getBounds());
repaint();
setBoundingBox (newBounds);
setFontSizeControlPoint (newFontPoint);
setColour (newColour);
setFont (newFont, false);
setJustification (newJustification);
setText (newText);
return damage.getUnion (getBounds());
}
return Rectangle<float>();
}
const ValueTree DrawableText::createValueTree (ImageProvider*) const


+ 6
- 8
src/gui/graphics/drawables/juce_DrawableText.h View File

@@ -87,23 +87,19 @@ public:
//==============================================================================
/** @internal */
void render (const Drawable::RenderingContext& context) const;
/** @internal */
const Rectangle<float> getBounds() const;
/** @internal */
bool hitTest (float x, float y) const;
void paint (Graphics& g);
/** @internal */
Drawable* createCopy() const;
/** @internal */
void invalidatePoints();
/** @internal */
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
const ValueTree createValueTree (ImageProvider* imageProvider) const;
/** @internal */
static const Identifier valueTreeType;
/** @internal */
const Identifier getValueTreeType() const { return valueTreeType; }
/** @internal */
const Rectangle<float> getDrawableBounds() const;
//==============================================================================
/** Internally-used class for wrapping a DrawableText's state into a ValueTree. */
@@ -146,6 +142,8 @@ private:
Colour colour;
Justification justification;
void refreshBounds();
DrawableText& operator= (const DrawableText&);
};


Loading…
Cancel
Save