mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-02-05 03:50:07 +00:00
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).
This commit is contained in:
parent
645637ab09
commit
640a335537
23 changed files with 619 additions and 718 deletions
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (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 (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();
|
||||
|
||||
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())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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&);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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>&)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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&);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -39,43 +39,91 @@ BEGIN_JUCE_NAMESPACE
|
|||
#include "../../../io/streams/juce_MemoryOutputStream.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
Drawable::RenderingContext::RenderingContext (Graphics& g_,
|
||||
const AffineTransform& transform_,
|
||||
const float opacity_) throw()
|
||||
: g (g_),
|
||||
transform (transform_),
|
||||
opacity (opacity_)
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Drawable::Drawable()
|
||||
: parent (0)
|
||||
{
|
||||
setInterceptsMouseClicks (false, false);
|
||||
setPaintingIsUnclipped (true);
|
||||
}
|
||||
|
||||
Drawable::~Drawable()
|
||||
{
|
||||
}
|
||||
|
||||
void Drawable::draw (Graphics& g, const float opacity, const AffineTransform& transform) const
|
||||
//==============================================================================
|
||||
void Drawable::draw (Graphics& g, float opacity, const AffineTransform& transform) const
|
||||
{
|
||||
render (RenderingContext (g, transform, opacity));
|
||||
const_cast <Drawable*> (this)->nonConstDraw (g, opacity, transform);
|
||||
}
|
||||
|
||||
void Drawable::drawAt (Graphics& g, const float x, const float y, const float opacity) const
|
||||
void Drawable::nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform)
|
||||
{
|
||||
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, 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
|
||||
{
|
||||
if (! destArea.isEmpty())
|
||||
draw (g, opacity, placement.getTransformToFit (getBounds(), destArea));
|
||||
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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
/** @internal */
|
||||
DrawableComposite* parent;
|
||||
/** @internal */
|
||||
virtual void invalidatePoints() = 0;
|
||||
friend class DrawableShape;
|
||||
|
||||
/** @internal */
|
||||
static Drawable* createChildFromValueTree (DrawableComposite* parent, const ValueTree& tree, ImageProvider* imageProvider);
|
||||
/** @internal */
|
||||
void transformContextToCorrectOrigin (Graphics& g);
|
||||
/** @internal */
|
||||
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&);
|
||||
|
|
|
|||
|
|
@ -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,51 +85,61 @@ 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;
|
||||
|
||||
for (int i = getNumDrawables(); --i >= 0;)
|
||||
{
|
||||
Drawable* const d = getDrawable(i);
|
||||
|
||||
if (d != 0)
|
||||
{
|
||||
if (d->isTransformed())
|
||||
r = r.getUnion (d->getDrawableBounds().transformed (d->getTransform()));
|
||||
else
|
||||
r = r.getUnion (d->getDrawableBounds());
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
DrawableComposite::Marker::Marker (const DrawableComposite::Marker& other)
|
||||
: name (other.name), position (other.position)
|
||||
void DrawableComposite::markerHasMoved()
|
||||
{
|
||||
}
|
||||
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)
|
||||
d->markerHasMoved();
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawableComposite::Marker::operator!= (const DrawableComposite::Marker& other) const throw()
|
||||
{
|
||||
return name != other.name || position != other.position;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const char* const DrawableComposite::contentLeftMarkerName = "left";
|
||||
const char* const DrawableComposite::contentRightMarkerName = "right";
|
||||
const char* const DrawableComposite::contentTopMarkerName = "top";
|
||||
const char* const DrawableComposite::contentBottomMarkerName = "bottom";
|
||||
|
||||
const RelativeRectangle DrawableComposite::getContentArea() const
|
||||
{
|
||||
jassert (markersX.size() >= 2 && getMarker (true, 0)->name == contentLeftMarkerName && getMarker (true, 1)->name == contentRightMarkerName);
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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&);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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&);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
setBoundsToEnclose (getDrawableBounds());
|
||||
repaint();
|
||||
}
|
||||
|
||||
void DrawableShape::invalidatePoints()
|
||||
{
|
||||
pathNeedsUpdating = true;
|
||||
strokeNeedsUpdating = true;
|
||||
}
|
||||
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -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&);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
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()));
|
||||
}
|
||||
|
||||
const Rectangle<float> DrawableText::getBounds() const
|
||||
const Rectangle<float> DrawableText::getDrawableBounds() const
|
||||
{
|
||||
return bounds.getBounds (parent);
|
||||
}
|
||||
|
||||
bool DrawableText::hitTest (float x, float y) 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
|
||||
|
|
|
|||
|
|
@ -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…
Add table
Add a link
Reference in a new issue