| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2015 - ROLI Ltd.
 - 
 -    Permission is granted to use this software under the terms of either:
 -    a) the GPL v2 (or any later version)
 -    b) the Affero GPL v3
 - 
 -    Details of these licenses can be found at: www.gnu.org/licenses
 - 
 -    JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
 -    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 -    A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 - 
 -    ------------------------------------------------------------------------------
 - 
 -    To release a closed-source product which uses JUCE, commercial licenses are
 -    available: visit www.juce.com for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - #include "../../jucer_Headers.h"
 - #include "jucer_PaintElementPath.h"
 - #include "../properties/jucer_PositionPropertyBase.h"
 - #include "jucer_PaintElementUndoableAction.h"
 - #include "../jucer_UtilityFunctions.h"
 - 
 - //==============================================================================
 - class ChangePointAction     : public PaintElementUndoableAction <PaintElementPath>
 - {
 - public:
 -     ChangePointAction (PathPoint* const point,
 -                        const int pointIndex,
 -                        const PathPoint& newValue_)
 -         : PaintElementUndoableAction <PaintElementPath> (point->owner),
 -           index (pointIndex),
 -           newValue (newValue_),
 -           oldValue (*point)
 -     {
 -     }
 - 
 -     ChangePointAction (PathPoint* const point,
 -                        const PathPoint& newValue_)
 -         : PaintElementUndoableAction <PaintElementPath> (point->owner),
 -           index (point->owner->indexOfPoint (point)),
 -           newValue (newValue_),
 -           oldValue (*point)
 -     {
 -     }
 - 
 -     bool perform()
 -     {
 -         return changeTo (newValue);
 -     }
 - 
 -     bool undo()
 -     {
 -         return changeTo (oldValue);
 -     }
 - 
 - private:
 -     const int index;
 -     PathPoint newValue, oldValue;
 - 
 -     PathPoint* getPoint() const
 -     {
 -         PathPoint* p = getElement()->getPoint (index);
 -         jassert (p != nullptr);
 -         return p;
 -     }
 - 
 -     bool changeTo (const PathPoint& value) const
 -     {
 -         showCorrectTab();
 - 
 -         PaintElementPath* const path = getElement();
 -         jassert (path != nullptr);
 - 
 -         PathPoint* const p = path->getPoint (index);
 -         jassert (p != nullptr);
 - 
 -         const bool typeChanged = (p->type != value.type);
 -         *p = value;
 -         p->owner = path;
 - 
 -         if (typeChanged)
 -             path->pointListChanged();
 - 
 -         path->changed();
 -         return true;
 -     }
 - };
 - 
 - 
 - //==============================================================================
 - class PathWindingModeProperty    : public ChoicePropertyComponent,
 -                                    public ChangeListener
 - {
 - public:
 -     PathWindingModeProperty (PaintElementPath* const owner_)
 -         : ChoicePropertyComponent ("winding rule"),
 -           owner (owner_)
 -     {
 -         choices.add ("Non-zero winding");
 -         choices.add ("Even/odd winding");
 - 
 -         owner->getDocument()->addChangeListener (this);
 -     }
 - 
 -     ~PathWindingModeProperty()
 -     {
 -         owner->getDocument()->removeChangeListener (this);
 -     }
 - 
 -     void setIndex (int newIndex)            { owner->setNonZeroWinding (newIndex == 0, true); }
 -     int getIndex() const                    { return owner->isNonZeroWinding() ? 0 : 1; }
 - 
 -     void changeListenerCallback (ChangeBroadcaster*)     { refresh(); }
 - 
 - private:
 -     PaintElementPath* const owner;
 - };
 - 
 - 
 - //==============================================================================
 - PaintElementPath::PaintElementPath (PaintRoutine* pr)
 -     : ColouredElement (pr, "Path", true, true),
 -       nonZeroWinding (true)
 - {
 - }
 - 
 - PaintElementPath::~PaintElementPath()
 - {
 - }
 - 
 - static int randomPos (int size)
 - {
 -     return size / 4 + Random::getSystemRandom().nextInt (size / 4) - size / 8;
 - }
 - 
 - void PaintElementPath::setInitialBounds (int w, int h)
 - {
 -     String s;
 - 
 -     int x = randomPos (w);
 -     int y = randomPos (h);
 - 
 -     s << "s "
 -       << x << " " << y << " l "
 -       << (x + 30) << " " << (y + 50) << " l "
 -       << (x - 30) << " " << (y + 50) << " x";
 - 
 -     restorePathFromString (s);
 - }
 - 
 - //==============================================================================
 - int PaintElementPath::getBorderSize() const
 - {
 -     return isStrokePresent ? 1 + roundFloatToInt (strokeType.stroke.getStrokeThickness())
 -                            : 0;
 - }
 - 
 - Rectangle<int> PaintElementPath::getCurrentBounds (const Rectangle<int>& parentArea) const
 - {
 -     updateStoredPath (getDocument()->getComponentLayout(), parentArea);
 - 
 -     Rectangle<float> r (path.getBounds());
 - 
 -     const int borderSize = getBorderSize();
 - 
 -     return Rectangle<int> ((int) r.getX() - borderSize,
 -                            (int) r.getY() - borderSize,
 -                            (int) r.getWidth() + borderSize * 2,
 -                            (int) r.getHeight() + borderSize * 2);
 - }
 - 
 - void PaintElementPath::setCurrentBounds (const Rectangle<int>& b,
 -                                          const Rectangle<int>& parentArea,
 -                                          const bool /*undoable*/)
 - {
 -     Rectangle<int> newBounds (b);
 -     newBounds.setSize (jmax (1, newBounds.getWidth()),
 -                        jmax (1, newBounds.getHeight()));
 - 
 -     const Rectangle<int> current (getCurrentBounds (parentArea));
 - 
 -     if (newBounds != current)
 -     {
 -         const int borderSize = getBorderSize();
 - 
 -         const int dx = newBounds.getX() - current.getX();
 -         const int dy = newBounds.getY() - current.getY();
 - 
 -         const double scaleStartX = current.getX() + borderSize;
 -         const double scaleStartY = current.getY() + borderSize;
 -         const double scaleX = (newBounds.getWidth() - borderSize * 2) / (double) (current.getWidth() - borderSize * 2);
 -         const double scaleY = (newBounds.getHeight() - borderSize * 2) / (double) (current.getHeight() - borderSize * 2);
 - 
 -         for (int i = 0; i < points.size(); ++i)
 -         {
 -             PathPoint* const destPoint = points.getUnchecked(i);
 -             PathPoint p (*destPoint);
 - 
 -             for (int j = p.getNumPoints(); --j >= 0;)
 -                 rescalePoint (p.pos[j], dx, dy,
 -                               scaleX, scaleY,
 -                               scaleStartX, scaleStartY,
 -                               parentArea);
 - 
 -             perform (new ChangePointAction (destPoint, i, p), "Move path");
 -         }
 -     }
 - }
 - 
 - void PaintElementPath::rescalePoint (RelativePositionedRectangle& pos, int dx, int dy,
 -                                      double scaleX, double scaleY,
 -                                      double scaleStartX, double scaleStartY,
 -                                      const Rectangle<int>& parentArea) const
 - {
 -     double x, y, w, h;
 -     pos.getRectangleDouble (x, y, w, h, parentArea, getDocument()->getComponentLayout());
 - 
 -     x = (x - scaleStartX) * scaleX + scaleStartX + dx;
 -     y = (y - scaleStartY) * scaleY + scaleStartY + dy;
 - 
 -     pos.updateFrom (x, y, w, h, parentArea, getDocument()->getComponentLayout());
 - }
 - 
 - //==============================================================================
 - static void drawArrow (Graphics& g, const Point<float> p1, const Point<float> p2)
 - {
 -     g.drawArrow (Line<float> (p1.x, p1.y, (p1.x + p2.x) * 0.5f, (p1.y + p2.y) * 0.5f), 1.0f, 8.0f, 10.0f);
 -     g.drawLine (p1.x + (p2.x - p1.x) * 0.49f, p1.y + (p2.y - p1.y) * 0.49f, p2.x, p2.y);
 - }
 - 
 - void PaintElementPath::draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
 - {
 -     updateStoredPath (layout, parentArea);
 -     path.setUsingNonZeroWinding (nonZeroWinding);
 - 
 -     fillType.setFillType (g, getDocument(), parentArea);
 -     g.fillPath (path);
 - 
 -     if (isStrokePresent)
 -     {
 -         strokeType.fill.setFillType (g, getDocument(), parentArea);
 -         g.strokePath (path, getStrokeType().stroke);
 -     }
 - }
 - 
 - void PaintElementPath::drawExtraEditorGraphics (Graphics& g, const Rectangle<int>& relativeTo)
 - {
 -     ComponentLayout* layout = getDocument()->getComponentLayout();
 - 
 -     for (int i = 0; i < points.size(); ++i)
 -     {
 -         PathPoint* const p = points.getUnchecked (i);
 - 
 -         const int numPoints = p->getNumPoints();
 - 
 -         if (numPoints > 0)
 -         {
 -             if (owner->getSelectedPoints().isSelected (p))
 -             {
 -                 g.setColour (Colours::red);
 -                 Point<float> p1, p2;
 - 
 -                 if (numPoints > 2)
 -                 {
 -                     p1 = p->pos[1].toXY (relativeTo, layout);
 -                     p2 = p->pos[2].toXY (relativeTo, layout);
 -                     drawArrow (g, p1, p2);
 -                 }
 - 
 -                 if (numPoints > 1)
 -                 {
 -                     p1 = p->pos[0].toXY (relativeTo, layout);
 -                     p2 = p->pos[1].toXY (relativeTo, layout);
 -                     drawArrow (g, p1, p2);
 -                 }
 - 
 -                 p2 = p->pos[0].toXY (relativeTo, layout);
 - 
 -                 if (const PathPoint* const nextPoint = points [i - 1])
 -                 {
 -                     p1 = nextPoint->pos [nextPoint->getNumPoints() - 1].toXY (relativeTo, layout);
 -                     drawArrow (g, p1, p2);
 -                 }
 -             }
 -         }
 -     }
 - }
 - 
 - void PaintElementPath::resized()
 - {
 -     ColouredElement::resized();
 - }
 - 
 - void PaintElementPath::parentSizeChanged()
 - {
 -     repaint();
 - }
 - 
 - //==============================================================================
 - void PaintElementPath::mouseDown (const MouseEvent& e)
 - {
 -     if (e.mods.isPopupMenu() || ! owner->getSelectedElements().isSelected (this))
 -         mouseDownOnSegment = -1;
 -     else
 -         mouseDownOnSegment = findSegmentAtXY (getX() + e.x, getY() + e.y);
 - 
 -     if (points [mouseDownOnSegment] != nullptr)
 -         mouseDownSelectSegmentStatus = owner->getSelectedPoints().addToSelectionOnMouseDown (points [mouseDownOnSegment], e.mods);
 -     else
 -         ColouredElement::mouseDown (e);
 - }
 - 
 - void PaintElementPath::mouseDrag (const MouseEvent& e)
 - {
 -     if (mouseDownOnSegment < 0)
 -         ColouredElement::mouseDrag (e);
 - }
 - 
 - void PaintElementPath::mouseUp (const MouseEvent& e)
 - {
 -     if (points [mouseDownOnSegment] == 0)
 -         ColouredElement::mouseUp (e);
 -     else
 -         owner->getSelectedPoints().addToSelectionOnMouseUp (points [mouseDownOnSegment],
 -                                                             e.mods, false, mouseDownSelectSegmentStatus);
 - }
 - 
 - //==============================================================================
 - void PaintElementPath::changed()
 - {
 -     ColouredElement::changed();
 -     lastPathBounds = Rectangle<int>();
 - }
 - 
 - void PaintElementPath::pointListChanged()
 - {
 -     changed();
 -     siblingComponentsChanged();
 - }
 - 
 - //==============================================================================
 - void PaintElementPath::getEditableProperties (Array <PropertyComponent*>& props)
 - {
 -     props.add (new PathWindingModeProperty (this));
 -     getColourSpecificProperties (props);
 - }
 - 
 - //==============================================================================
 - static String positionToPairOfValues (const RelativePositionedRectangle& position,
 -                                       const ComponentLayout* layout)
 - {
 -     String x, y, w, h;
 -     positionToCode (position, layout, x, y, w, h);
 -     return castToFloat (x) + ", " + castToFloat (y);
 - }
 - 
 - void PaintElementPath::fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
 - {
 -     if (fillType.isInvisible() && (strokeType.isInvisible() || ! isStrokePresent))
 -         return;
 - 
 -     const String pathVariable ("internalPath" + String (code.getUniqueSuffix()));
 - 
 -     const ComponentLayout* layout = code.document->getComponentLayout();
 - 
 -     code.privateMemberDeclarations
 -         << "Path " << pathVariable << ";\n";
 - 
 -     String r;
 -     bool somePointsAreRelative = false;
 - 
 -     if (! nonZeroWinding)
 -         r << pathVariable << ".setUsingNonZeroWinding (false);\n";
 - 
 -     for (int i = 0; i < points.size(); ++i)
 -     {
 -         const PathPoint* const p = points.getUnchecked(i);
 - 
 -         switch (p->type)
 -         {
 -         case Path::Iterator::startNewSubPath:
 -             r << pathVariable << ".startNewSubPath (" << positionToPairOfValues (p->pos[0], layout) << ");\n";
 -             somePointsAreRelative = somePointsAreRelative || ! p->pos[0].rect.isPositionAbsolute();
 -             break;
 - 
 -         case Path::Iterator::lineTo:
 -             r << pathVariable << ".lineTo (" << positionToPairOfValues (p->pos[0], layout) << ");\n";
 -             somePointsAreRelative = somePointsAreRelative || ! p->pos[0].rect.isPositionAbsolute();
 -             break;
 - 
 -         case Path::Iterator::quadraticTo:
 -             r << pathVariable << ".quadraticTo (" << positionToPairOfValues (p->pos[0], layout)
 -                 << ", " << positionToPairOfValues (p->pos[1], layout) << ");\n";
 -             somePointsAreRelative = somePointsAreRelative || ! p->pos[0].rect.isPositionAbsolute();
 -             somePointsAreRelative = somePointsAreRelative || ! p->pos[1].rect.isPositionAbsolute();
 -             break;
 - 
 -         case Path::Iterator::cubicTo:
 -             r << pathVariable << ".cubicTo (" << positionToPairOfValues (p->pos[0], layout)
 -                 << ", " << positionToPairOfValues (p->pos[1], layout)
 -                 << ", " << positionToPairOfValues (p->pos[2], layout) << ");\n";
 -             somePointsAreRelative = somePointsAreRelative || ! p->pos[0].rect.isPositionAbsolute();
 -             somePointsAreRelative = somePointsAreRelative || ! p->pos[1].rect.isPositionAbsolute();
 -             somePointsAreRelative = somePointsAreRelative || ! p->pos[2].rect.isPositionAbsolute();
 -             break;
 - 
 -         case Path::Iterator::closePath:
 -             r << pathVariable << ".closeSubPath();\n";
 -             break;
 - 
 -         default:
 -             jassertfalse;
 -             break;
 -         }
 -     }
 - 
 -     r << '\n';
 - 
 -     if (somePointsAreRelative)
 -         code.getCallbackCode (String::empty, "void", "resized()", false)
 -             << pathVariable << ".clear();\n" << r;
 -     else
 -         code.constructorCode << r;
 - 
 -     if (! fillType.isInvisible())
 -     {
 -         fillType.fillInGeneratedCode (code, paintMethodCode);
 - 
 -         paintMethodCode << "g.fillPath (" << pathVariable << ");\n";
 -     }
 - 
 -     if (isStrokePresent && ! strokeType.isInvisible())
 -     {
 -         String s;
 - 
 -         strokeType.fill.fillInGeneratedCode (code, s);
 -         s << "g.strokePath (" << pathVariable << ", " << strokeType.getPathStrokeCode() << ");\n";
 - 
 -         paintMethodCode += s;
 -     }
 - 
 -     paintMethodCode += "\n";
 - }
 - 
 - //==============================================================================
 - XmlElement* PaintElementPath::createXml() const
 - {
 -     XmlElement* e = new XmlElement (getTagName());
 -     position.applyToXml (*e);
 -     addColourAttributes (e);
 -     e->setAttribute ("nonZeroWinding", nonZeroWinding);
 -     e->addTextElement (pathToString());
 - 
 -     return e;
 - }
 - 
 - bool PaintElementPath::loadFromXml (const XmlElement& xml)
 - {
 -     if (xml.hasTagName (getTagName()))
 -     {
 -         position.restoreFromXml (xml, position);
 -         loadColourAttributes (xml);
 -         nonZeroWinding = xml.getBoolAttribute ("nonZeroWinding", true);
 - 
 -         restorePathFromString (xml.getAllSubText().trim());
 - 
 -         return true;
 -     }
 - 
 -     jassertfalse;
 -     return false;
 - }
 - 
 - //==============================================================================
 - void PaintElementPath::createSiblingComponents()
 - {
 -     ColouredElement::createSiblingComponents();
 - 
 -     for (int i = 0; i < points.size(); ++i)
 -     {
 -         switch (points.getUnchecked(i)->type)
 -         {
 -             case Path::Iterator::startNewSubPath:
 -                 siblingComponents.add (new PathPointComponent (this, i, 0));
 -                 break;
 -             case Path::Iterator::lineTo:
 -                 siblingComponents.add (new PathPointComponent (this, i, 0));
 -                 break;
 -             case Path::Iterator::quadraticTo:
 -                 siblingComponents.add (new PathPointComponent (this, i, 0));
 -                 siblingComponents.add (new PathPointComponent (this, i, 1));
 -                 break;
 -             case Path::Iterator::cubicTo:
 -                 siblingComponents.add (new PathPointComponent (this, i, 0));
 -                 siblingComponents.add (new PathPointComponent (this, i, 1));
 -                 siblingComponents.add (new PathPointComponent (this, i, 2));
 -                 break;
 -             case Path::Iterator::closePath:
 -                 break;
 - 
 -             default:
 -                 jassertfalse; break;
 -         }
 -     }
 - 
 -     for (int i = 0; i < siblingComponents.size(); ++i)
 -     {
 -         getParentComponent()->addAndMakeVisible (siblingComponents.getUnchecked(i));
 -         siblingComponents.getUnchecked(i)->updatePosition();
 -     }
 - }
 - 
 - 
 - String PaintElementPath::pathToString() const
 - {
 -     String s;
 - 
 -     for (int i = 0; i < points.size(); ++i)
 -     {
 -         const PathPoint* const p = points.getUnchecked(i);
 - 
 -         switch (p->type)
 -         {
 -             case Path::Iterator::startNewSubPath:
 -                 s << "s " << p->pos[0].toString() << ' ';
 -                 break;
 -             case Path::Iterator::lineTo:
 -                 s << "l " << p->pos[0].toString() << ' ';
 -                 break;
 -             case Path::Iterator::quadraticTo:
 -                 s << "q " << p->pos[0].toString()
 -                   << ' '  << p->pos[1].toString() << ' ';
 -                 break;
 -             case Path::Iterator::cubicTo:
 -                 s << "c " << p->pos[0].toString()
 -                   << ' '  << p->pos[1].toString() << ' '
 -                   << ' '  << p->pos[2].toString() << ' ';
 -                 break;
 -             case Path::Iterator::closePath:
 -                 s << "x ";
 -                 break;
 - 
 -             default:
 -                 jassertfalse; break;
 -         }
 -     }
 - 
 -     return s.trimEnd();
 - }
 - 
 - void PaintElementPath::restorePathFromString (const String& s)
 - {
 -     points.clear();
 - 
 -     StringArray tokens;
 -     tokens.addTokens (s, false);
 -     tokens.trim();
 -     tokens.removeEmptyStrings();
 - 
 -     for (int i = 0; i < tokens.size(); ++i)
 -     {
 -         ScopedPointer<PathPoint> p (new PathPoint (this));
 - 
 -         if (tokens[i] == "s")
 -         {
 -             p->type = Path::Iterator::startNewSubPath;
 -             p->pos [0] = RelativePositionedRectangle();
 -             p->pos [0].rect = PositionedRectangle (tokens [i + 1] + " " + tokens [i + 2]);
 -             i += 2;
 -         }
 -         else if (tokens[i] == "l")
 -         {
 -             p->type = Path::Iterator::lineTo;
 -             p->pos [0] = RelativePositionedRectangle();
 -             p->pos [0].rect = PositionedRectangle (tokens [i + 1] + " " + tokens [i + 2]);
 -             i += 2;
 -         }
 -         else if (tokens[i] == "q")
 -         {
 -             p->type = Path::Iterator::quadraticTo;
 -             p->pos [0] = RelativePositionedRectangle();
 -             p->pos [0].rect = PositionedRectangle (tokens [i + 1] + " " + tokens [i + 2]);
 -             p->pos [1] = RelativePositionedRectangle();
 -             p->pos [1].rect = PositionedRectangle (tokens [i + 3] + " " + tokens [i + 4]);
 -             i += 4;
 -         }
 -         else if (tokens[i] == "c")
 -         {
 -             p->type = Path::Iterator::cubicTo;
 -             p->pos [0] = RelativePositionedRectangle();
 -             p->pos [0].rect = PositionedRectangle (tokens [i + 1] + " " + tokens [i + 2]);
 -             p->pos [1] = RelativePositionedRectangle();
 -             p->pos [1].rect = PositionedRectangle (tokens [i + 3] + " " + tokens [i + 4]);
 -             p->pos [2] = RelativePositionedRectangle();
 -             p->pos [2].rect = PositionedRectangle (tokens [i + 5] + " " + tokens [i + 6]);
 -             i += 6;
 -         }
 -         else if (tokens[i] == "x")
 -         {
 -             p->type = Path::Iterator::closePath;
 -         }
 -         else
 -             continue;
 - 
 -         points.add (p.release());
 -     }
 - }
 - 
 - void PaintElementPath::setToPath (const Path& newPath)
 - {
 -     points.clear();
 - 
 -     Path::Iterator i (newPath);
 - 
 -     while (i.next())
 -     {
 -         ScopedPointer<PathPoint> p (new PathPoint (this));
 -         p->type = i.elementType;
 - 
 -         if (i.elementType == Path::Iterator::startNewSubPath)
 -         {
 -             p->pos [0].rect.setX (i.x1);
 -             p->pos [0].rect.setY (i.y1);
 -         }
 -         else if (i.elementType == Path::Iterator::lineTo)
 -         {
 -             p->pos [0].rect.setX (i.x1);
 -             p->pos [0].rect.setY (i.y1);
 -         }
 -         else if (i.elementType == Path::Iterator::quadraticTo)
 -         {
 -             p->pos [0].rect.setX (i.x1);
 -             p->pos [0].rect.setY (i.y1);
 -             p->pos [1].rect.setX (i.x2);
 -             p->pos [1].rect.setY (i.y2);
 -         }
 -         else if (i.elementType == Path::Iterator::cubicTo)
 -         {
 -             p->pos [0].rect.setX (i.x1);
 -             p->pos [0].rect.setY (i.y1);
 -             p->pos [1].rect.setX (i.x2);
 -             p->pos [1].rect.setY (i.y2);
 -             p->pos [2].rect.setX (i.x3);
 -             p->pos [2].rect.setY (i.y3);
 -         }
 -         else if (i.elementType == Path::Iterator::closePath)
 -         {
 -         }
 -         else
 -         {
 -             continue;
 -         }
 - 
 -         points.add (p.release());
 -     }
 - }
 - 
 - void PaintElementPath::updateStoredPath (const ComponentLayout* layout, const Rectangle<int>& relativeTo) const
 - {
 -     if (lastPathBounds != relativeTo && ! relativeTo.isEmpty())
 -     {
 -         lastPathBounds = relativeTo;
 -         path.clear();
 - 
 -         for (int i = 0; i < points.size(); ++i)
 -         {
 -             const PathPoint* const p = points.getUnchecked(i);
 - 
 -             switch (p->type)
 -             {
 -                 case Path::Iterator::startNewSubPath:
 -                     path.startNewSubPath (p->pos[0].toXY (relativeTo, layout));
 -                     break;
 - 
 -                 case Path::Iterator::lineTo:
 -                     path.lineTo (p->pos[0].toXY (relativeTo, layout));
 -                     break;
 - 
 -                 case Path::Iterator::quadraticTo:
 -                     path.quadraticTo (p->pos[0].toXY (relativeTo, layout),
 -                                       p->pos[1].toXY (relativeTo, layout));
 -                     break;
 - 
 -                 case Path::Iterator::cubicTo:
 -                     path.cubicTo (p->pos[0].toXY (relativeTo, layout),
 -                                   p->pos[1].toXY (relativeTo, layout),
 -                                   p->pos[2].toXY (relativeTo, layout));
 -                     break;
 - 
 -                 case Path::Iterator::closePath:
 -                     path.closeSubPath();
 -                     break;
 - 
 -                 default:
 -                     jassertfalse; break;
 -             }
 -         }
 -     }
 - }
 - 
 - //==============================================================================
 - class ChangeWindingAction     : public PaintElementUndoableAction <PaintElementPath>
 - {
 - public:
 -     ChangeWindingAction (PaintElementPath* const path, const bool newValue_)
 -         : PaintElementUndoableAction <PaintElementPath> (path),
 -           newValue (newValue_),
 -           oldValue (path->isNonZeroWinding())
 -     {
 -     }
 - 
 -     bool perform()
 -     {
 -         showCorrectTab();
 -         getElement()->setNonZeroWinding (newValue, false);
 -         return true;
 -     }
 - 
 -     bool undo()
 -     {
 -         showCorrectTab();
 -         getElement()->setNonZeroWinding (oldValue, false);
 -         return true;
 -     }
 - 
 - private:
 -     bool newValue, oldValue;
 - };
 - 
 - void PaintElementPath::setNonZeroWinding (const bool nonZero, const bool undoable)
 - {
 -     if (nonZero != nonZeroWinding)
 -     {
 -         if (undoable)
 -         {
 -             perform (new ChangeWindingAction (this, nonZero), "Change path winding rule");
 -         }
 -         else
 -         {
 -             nonZeroWinding = nonZero;
 -             changed();
 -         }
 -     }
 - }
 - 
 - bool PaintElementPath::isSubpathClosed (int index) const
 - {
 -     for (int i = index + 1; i < points.size(); ++i)
 -     {
 -         if (points.getUnchecked (i)->type == Path::Iterator::closePath)
 -             return true;
 - 
 -         if (points.getUnchecked (i)->type == Path::Iterator::startNewSubPath)
 -             break;
 -     }
 - 
 -     return false;
 - }
 - 
 - //==============================================================================
 - void PaintElementPath::setSubpathClosed (int index, const bool closed, const bool undoable)
 - {
 -     if (closed != isSubpathClosed (index))
 -     {
 -         for (int i = index + 1; i < points.size(); ++i)
 -         {
 -             PathPoint* p = points.getUnchecked (i);
 - 
 -             if (p->type == Path::Iterator::closePath)
 -             {
 -                 jassert (! closed);
 - 
 -                 deletePoint (i, undoable);
 -                 return;
 -             }
 - 
 -             if (p->type == Path::Iterator::startNewSubPath)
 -             {
 -                 jassert (closed);
 - 
 -                 PathPoint* pp = addPoint (i - 1, undoable);
 - 
 -                 PathPoint p2 (*pp);
 -                 p2.type = Path::Iterator::closePath;
 -                 perform (new ChangePointAction (pp, p2), "Close subpath");
 -                 return;
 -             }
 -         }
 - 
 -         jassert (closed);
 - 
 -         PathPoint* p = addPoint (points.size() - 1, undoable);
 -         PathPoint p2 (*p);
 -         p2.type = Path::Iterator::closePath;
 -         perform (new ChangePointAction (p, p2), "Close subpath");
 -     }
 - }
 - 
 - //==============================================================================
 - class AddPointAction   : public PaintElementUndoableAction <PaintElementPath>
 - {
 - public:
 -     AddPointAction (PaintElementPath* path, int pointIndexToAddItAfter_)
 -         : PaintElementUndoableAction <PaintElementPath> (path),
 -           indexAdded (-1),
 -           pointIndexToAddItAfter (pointIndexToAddItAfter_)
 -     {
 -     }
 - 
 -     bool perform()
 -     {
 -         showCorrectTab();
 - 
 -         PaintElementPath* const path = getElement();
 -         jassert (path != nullptr);
 - 
 -         PathPoint* const p = path->addPoint (pointIndexToAddItAfter, false);
 -         jassert (p != nullptr);
 - 
 -         indexAdded = path->indexOfPoint (p);
 -         jassert (indexAdded >= 0);
 -         return true;
 -     }
 - 
 -     bool undo()
 -     {
 -         showCorrectTab();
 - 
 -         PaintElementPath* const path = getElement();
 -         jassert (path != nullptr);
 - 
 -         path->deletePoint (indexAdded, false);
 -         return true;
 -     }
 - 
 -     int indexAdded;
 - 
 - private:
 -     int pointIndexToAddItAfter;
 - };
 - 
 - PathPoint* PaintElementPath::addPoint (int pointIndexToAddItAfter, const bool undoable)
 - {
 -     if (undoable)
 -     {
 -         AddPointAction* action = new AddPointAction (this, pointIndexToAddItAfter);
 -         perform (action, "Add path point");
 -         return points [action->indexAdded];
 -     }
 - 
 -     double x1 = 20.0, y1 = 20.0, x2, y2;
 - 
 -     ComponentLayout* layout = getDocument()->getComponentLayout();
 -     const Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
 - 
 -     if (points [pointIndexToAddItAfter] != nullptr)
 -         points [pointIndexToAddItAfter]->pos [points [pointIndexToAddItAfter]->getNumPoints() - 1].getXY (x1, y1, area, layout);
 -     else if (points[0] != nullptr)
 -         points[0]->pos[0].getXY (x1, y1, area, layout);
 - 
 -     x2 = x1 + 50.0;
 -     y2 = y1 + 50.0;
 - 
 -     if (points [pointIndexToAddItAfter + 1] != nullptr)
 -     {
 -         if (points [pointIndexToAddItAfter + 1]->type == Path::Iterator::closePath
 -              || points [pointIndexToAddItAfter + 1]->type == Path::Iterator::startNewSubPath)
 -         {
 -             int i = pointIndexToAddItAfter;
 -             while (i > 0)
 -                 if (points [--i]->type == Path::Iterator::startNewSubPath)
 -                     break;
 - 
 -             if (i != pointIndexToAddItAfter)
 -                 points [i]->pos[0].getXY (x2, y2, area, layout);
 -         }
 -         else
 -         {
 -             points [pointIndexToAddItAfter + 1]->pos[0].getXY (x2, y2, area, layout);
 -         }
 -     }
 -     else
 -     {
 -         int i = pointIndexToAddItAfter + 1;
 -         while (i > 0)
 -             if (points [--i]->type == Path::Iterator::startNewSubPath)
 -                 break;
 - 
 -         points[i]->pos[0].getXY (x2, y2, area, layout);
 -     }
 - 
 -     PathPoint* const p = new PathPoint (this);
 - 
 -     p->type = Path::Iterator::lineTo;
 -     p->pos[0].rect.setX ((x1 + x2) * 0.5f);
 -     p->pos[0].rect.setY ((y1 + y2) * 0.5f);
 - 
 -     points.insert (pointIndexToAddItAfter + 1, p);
 - 
 -     pointListChanged();
 -     return p;
 - }
 - 
 - //==============================================================================
 - class DeletePointAction   : public PaintElementUndoableAction <PaintElementPath>
 - {
 - public:
 -     DeletePointAction (PaintElementPath* const path, const int indexToRemove_)
 -         : PaintElementUndoableAction <PaintElementPath> (path),
 -           indexToRemove (indexToRemove_),
 -           oldValue (*path->getPoint (indexToRemove))
 -     {
 -     }
 - 
 -     bool perform()
 -     {
 -         showCorrectTab();
 - 
 -         PaintElementPath* const path = getElement();
 -         jassert (path != nullptr);
 - 
 -         path->deletePoint (indexToRemove, false);
 -         return path != nullptr;
 -     }
 - 
 -     bool undo()
 -     {
 -         showCorrectTab();
 - 
 -         PaintElementPath* const path = getElement();
 -         jassert (path != nullptr);
 - 
 -         PathPoint* p = path->addPoint (indexToRemove - 1, false);
 -         *p = oldValue;
 - 
 -         return path != nullptr;
 -     }
 - 
 -     int indexToRemove;
 - 
 - private:
 -     PathPoint oldValue;
 - };
 - 
 - void PaintElementPath::deletePoint (int pointIndex, const bool undoable)
 - {
 -     if (undoable)
 -     {
 -         perform (new DeletePointAction (this, pointIndex), "Delete path point");
 -     }
 -     else
 -     {
 -         PathPoint* const p = points [pointIndex];
 - 
 -         if (p != nullptr && pointIndex > 0)
 -         {
 -             owner->getSelectedPoints().deselect (p);
 -             owner->getSelectedPoints().changed (true);
 - 
 -             points.remove (pointIndex);
 -             pointListChanged();
 -         }
 -     }
 - }
 - 
 - //==============================================================================
 - bool PaintElementPath::getPoint (int index, int pointNumber, double& x, double& y, const Rectangle<int>& parentArea) const
 - {
 -     const PathPoint* const p = points [index];
 - 
 -     if (p == nullptr)
 -     {
 -         x = y = 0;
 -         return false;
 -     }
 - 
 -     jassert (pointNumber < 3 || p->type == Path::Iterator::cubicTo);
 -     jassert (pointNumber < 2 || p->type == Path::Iterator::cubicTo || p->type == Path::Iterator::quadraticTo);
 - 
 -     p->pos [pointNumber].getXY (x, y, parentArea, getDocument()->getComponentLayout());
 -     return true;
 - }
 - 
 - int PaintElementPath::findSegmentAtXY (int x, int y) const
 - {
 -     double x1, y1, x2, y2, x3, y3, lastX = 0.0, lastY = 0.0, subPathStartX = 0.0, subPathStartY = 0.0;
 - 
 -     ComponentLayout* const layout = getDocument()->getComponentLayout();
 -     const Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
 - 
 -     int subpathStartIndex = 0;
 - 
 -     float thickness = 10.0f;
 -     if (isStrokePresent)
 -         thickness = jmax (thickness, strokeType.stroke.getStrokeThickness());
 - 
 -     for (int i = 0; i < points.size(); ++i)
 -     {
 -         Path segmentPath;
 -         PathPoint* const p = points.getUnchecked (i);
 - 
 -         switch (p->type)
 -         {
 -         case Path::Iterator::startNewSubPath:
 -             p->pos[0].getXY (lastX, lastY, area, layout);
 -             subPathStartX = lastX;
 -             subPathStartY = lastY;
 -             subpathStartIndex = i;
 -             break;
 - 
 -         case Path::Iterator::lineTo:
 -             p->pos[0].getXY (x1, y1, area, layout);
 - 
 -             segmentPath.addLineSegment (Line<float> ((float) lastX, (float) lastY, (float) x1, (float) y1), thickness);
 -             if (segmentPath.contains ((float) x, (float) y))
 -                 return i;
 - 
 -             lastX = x1;
 -             lastY = y1;
 -             break;
 - 
 -         case Path::Iterator::quadraticTo:
 -             p->pos[0].getXY (x1, y1, area, layout);
 -             p->pos[1].getXY (x2, y2, area, layout);
 - 
 -             segmentPath.startNewSubPath ((float) lastX, (float) lastY);
 -             segmentPath.quadraticTo ((float) x1, (float) y1, (float) x2, (float) y2);
 -             PathStrokeType (thickness).createStrokedPath (segmentPath, segmentPath);
 - 
 -             if (segmentPath.contains ((float) x, (float) y))
 -                 return i;
 - 
 -             lastX = x2;
 -             lastY = y2;
 -             break;
 - 
 -         case Path::Iterator::cubicTo:
 -             p->pos[0].getXY (x1, y1, area, layout);
 -             p->pos[1].getXY (x2, y2, area, layout);
 -             p->pos[2].getXY (x3, y3, area, layout);
 - 
 -             segmentPath.startNewSubPath ((float) lastX, (float) lastY);
 -             segmentPath.cubicTo ((float) x1, (float) y1, (float) x2, (float) y2, (float) x3, (float) y3);
 -             PathStrokeType (thickness).createStrokedPath (segmentPath, segmentPath);
 - 
 -             if (segmentPath.contains ((float) x, (float) y))
 -                 return i;
 - 
 -             lastX = x3;
 -             lastY = y3;
 -             break;
 - 
 -         case Path::Iterator::closePath:
 -             segmentPath.addLineSegment (Line<float> ((float) lastX, (float) lastY, (float) subPathStartX, (float) subPathStartY), thickness);
 -             if (segmentPath.contains ((float) x, (float) y))
 -                 return subpathStartIndex;
 - 
 -             lastX = subPathStartX;
 -             lastY = subPathStartY;
 -             break;
 - 
 -         default:
 -             jassertfalse; break;
 -         }
 -     }
 - 
 -     return -1;
 - }
 - 
 - //==============================================================================
 - void PaintElementPath::movePoint (int index, int pointNumber,
 -                                   double newX, double newY,
 -                                   const Rectangle<int>& parentArea,
 -                                   const bool undoable)
 - {
 -     if (PathPoint* const p = points [index])
 -     {
 -         PathPoint newPoint (*p);
 -         jassert (pointNumber < 3 || p->type == Path::Iterator::cubicTo);
 -         jassert (pointNumber < 2 || p->type == Path::Iterator::cubicTo || p->type == Path::Iterator::quadraticTo);
 - 
 -         RelativePositionedRectangle& pr = newPoint.pos [pointNumber];
 - 
 -         double x, y, w, h;
 -         pr.getRectangleDouble (x, y, w, h, parentArea, getDocument()->getComponentLayout());
 -         pr.updateFrom (newX, newY, w, h, parentArea, getDocument()->getComponentLayout());
 - 
 -         if (undoable)
 -         {
 -             perform (new ChangePointAction (p, index, newPoint), "Move path point");
 -         }
 -         else
 -         {
 -             *p = newPoint;
 -             changed();
 -         }
 -     }
 - }
 - 
 - RelativePositionedRectangle PaintElementPath::getPoint (int index, int pointNumber) const
 - {
 -     if (PathPoint* const p = points [index])
 -     {
 -         jassert (pointNumber < 3 || p->type == Path::Iterator::cubicTo);
 -         jassert (pointNumber < 2 || p->type == Path::Iterator::cubicTo || p->type == Path::Iterator::quadraticTo);
 - 
 -         return p->pos [pointNumber];
 -     }
 - 
 -     jassertfalse;
 -     return RelativePositionedRectangle();
 - }
 - 
 - void PaintElementPath::setPoint (int index, int pointNumber, const RelativePositionedRectangle& newPos, const bool undoable)
 - {
 -     if (PathPoint* const p = points [index])
 -     {
 -         PathPoint newPoint (*p);
 - 
 -         jassert (pointNumber < 3 || p->type == Path::Iterator::cubicTo);
 -         jassert (pointNumber < 2 || p->type == Path::Iterator::cubicTo || p->type == Path::Iterator::quadraticTo);
 - 
 -         if (newPoint.pos [pointNumber] != newPos)
 -         {
 -             newPoint.pos [pointNumber] = newPos;
 - 
 -             if (undoable)
 -             {
 -                 perform (new ChangePointAction (p, index, newPoint), "Change path point position");
 -             }
 -             else
 -             {
 -                 *p = newPoint;
 -                 changed();
 -             }
 -         }
 -     }
 -     else
 -     {
 -         jassertfalse;
 -     }
 - }
 - 
 - //==============================================================================
 - class PathPointTypeProperty : public ChoicePropertyComponent,
 -                               public ChangeListener
 - {
 - public:
 -     PathPointTypeProperty (PaintElementPath* const owner_,
 -                            const int index_)
 -         : ChoicePropertyComponent ("point type"),
 -           owner (owner_),
 -           index (index_)
 -     {
 -         choices.add ("Start of sub-path");
 -         choices.add ("Line");
 -         choices.add ("Quadratic");
 -         choices.add ("Cubic");
 - 
 -         owner->getDocument()->addChangeListener (this);
 -     }
 - 
 -     ~PathPointTypeProperty()
 -     {
 -         owner->getDocument()->removeChangeListener (this);
 -     }
 - 
 -     void setIndex (int newIndex)
 -     {
 -         Path::Iterator::PathElementType type = Path::Iterator::startNewSubPath;
 - 
 -         switch (newIndex)
 -         {
 -             case 0:     type = Path::Iterator::startNewSubPath; break;
 -             case 1:     type = Path::Iterator::lineTo; break;
 -             case 2:     type = Path::Iterator::quadraticTo; break;
 -             case 3:     type = Path::Iterator::cubicTo; break;
 -             default:    jassertfalse; break;
 -         }
 - 
 -         const Rectangle<int> area (((PaintRoutineEditor*) owner->getParentComponent())->getComponentArea());
 -         owner->getPoint (index)->changePointType (type, area, true);
 -     }
 - 
 -     int getIndex() const
 -     {
 -         const PathPoint* const p = owner->getPoint (index);
 -         jassert (p != nullptr);
 - 
 -         switch (p->type)
 -         {
 -             case Path::Iterator::startNewSubPath:   return 0;
 -             case Path::Iterator::lineTo:            return 1;
 -             case Path::Iterator::quadraticTo:       return 2;
 -             case Path::Iterator::cubicTo:           return 3;
 -             case Path::Iterator::closePath:         break;
 -             default:                                jassertfalse; break;
 -         }
 - 
 -         return 0;
 -     }
 - 
 -     void changeListenerCallback (ChangeBroadcaster*)
 -     {
 -         refresh();
 -     }
 - 
 - private:
 -     PaintElementPath* const owner;
 -     const int index;
 - };
 - 
 - //==============================================================================
 - class PathPointPositionProperty   : public PositionPropertyBase
 - {
 - public:
 -     PathPointPositionProperty (PaintElementPath* const owner_,
 -                                const int index_, const int pointNumber_,
 -                                const String& name,
 -                                ComponentPositionDimension dimension_)
 -         : PositionPropertyBase (owner_, name, dimension_, false, false,
 -                                 owner_->getDocument()->getComponentLayout()),
 -           owner (owner_),
 -           index (index_),
 -           pointNumber (pointNumber_)
 -     {
 -         owner->getDocument()->addChangeListener (this);
 -     }
 - 
 -     ~PathPointPositionProperty()
 -     {
 -         owner->getDocument()->removeChangeListener (this);
 -     }
 - 
 -     void setPosition (const RelativePositionedRectangle& newPos)
 -     {
 -         owner->setPoint (index, pointNumber, newPos, true);
 -     }
 - 
 -     RelativePositionedRectangle getPosition() const
 -     {
 -         return owner->getPoint (index, pointNumber);
 -     }
 - 
 - private:
 -     PaintElementPath* const owner;
 -     const int index, pointNumber;
 - };
 - 
 - //==============================================================================
 - class PathPointClosedProperty   : public ChoicePropertyComponent,
 -                                   private ChangeListener
 - {
 - public:
 -     PathPointClosedProperty (PaintElementPath* const owner_, const int index_)
 -         : ChoicePropertyComponent ("openness"),
 -           owner (owner_),
 -           index (index_)
 -     {
 -         owner->getDocument()->addChangeListener (this);
 - 
 -         choices.add ("Subpath is closed");
 -         choices.add ("Subpath is open-ended");
 -     }
 - 
 -     ~PathPointClosedProperty()
 -     {
 -         owner->getDocument()->removeChangeListener (this);
 -     }
 - 
 -     void changeListenerCallback (ChangeBroadcaster*)
 -     {
 -         refresh();
 -     }
 - 
 -     void setIndex (int newIndex)
 -     {
 -         owner->setSubpathClosed (index, newIndex == 0, true);
 -     }
 - 
 -     int getIndex() const
 -     {
 -         return owner->isSubpathClosed (index) ? 0 : 1;
 -     }
 - 
 - private:
 -     PaintElementPath* const owner;
 -     const int index;
 - };
 - 
 - //==============================================================================
 - class AddNewPointProperty   : public ButtonPropertyComponent
 - {
 - public:
 -     AddNewPointProperty (PaintElementPath* const owner_, const int index_)
 -         : ButtonPropertyComponent ("new point", false),
 -           owner (owner_),
 -           index (index_)
 -     {
 -     }
 - 
 -     void buttonClicked()
 -     {
 -         owner->addPoint (index, true);
 -     }
 - 
 -     String getButtonText() const      { return "Add new point"; }
 - 
 - private:
 -     PaintElementPath* const owner;
 -     const int index;
 - };
 - 
 - 
 - //==============================================================================
 - PathPoint::PathPoint (PaintElementPath* const owner_)
 -     : owner (owner_)
 - {
 - }
 - 
 - PathPoint::PathPoint (const PathPoint& other)
 -     : owner (other.owner),
 -       type (other.type)
 - {
 -     pos [0] = other.pos [0];
 -     pos [1] = other.pos [1];
 -     pos [2] = other.pos [2];
 - }
 - 
 - PathPoint& PathPoint::operator= (const PathPoint& other)
 - {
 -     owner = other.owner;
 -     type = other.type;
 -     pos [0] = other.pos [0];
 -     pos [1] = other.pos [1];
 -     pos [2] = other.pos [2];
 -     return *this;
 - }
 - 
 - PathPoint::~PathPoint()
 - {
 - }
 - 
 - int PathPoint::getNumPoints() const
 - {
 -     if (type == Path::Iterator::cubicTo)        return 3;
 -     if (type == Path::Iterator::quadraticTo)    return 2;
 -     if (type == Path::Iterator::closePath)      return 0;
 - 
 -     return 1;
 - }
 - 
 - PathPoint PathPoint::withChangedPointType (const Path::Iterator::PathElementType newType,
 -                                            const Rectangle<int>& parentArea) const
 - {
 -     PathPoint p (*this);
 - 
 -     if (newType != p.type)
 -     {
 -         int oldNumPoints = getNumPoints();
 -         p.type = newType;
 -         int numPoints = p.getNumPoints();
 - 
 -         if (numPoints != oldNumPoints)
 -         {
 -             double lastX, lastY;
 -             double x, y, w, h;
 - 
 -             p.pos [numPoints - 1] = p.pos [oldNumPoints - 1];
 -             p.pos [numPoints - 1].getRectangleDouble (x, y, w, h, parentArea, owner->getDocument()->getComponentLayout());
 - 
 -             const int index = owner->points.indexOf (this);
 - 
 -             if (PathPoint* lastPoint = owner->points [index - 1])
 -             {
 -                 lastPoint->pos [lastPoint->getNumPoints() - 1]
 -                             .getRectangleDouble (lastX, lastY, w, h, parentArea, owner->getDocument()->getComponentLayout());
 -             }
 -             else
 -             {
 -                 jassertfalse;
 -                 lastX = x;
 -                 lastY = y;
 -             }
 - 
 -             for (int i = 0; i < numPoints - 1; ++i)
 -             {
 -                 p.pos[i] = p.pos [numPoints - 1];
 - 
 -                 p.pos[i].updateFrom (lastX + (x - lastX) * (i + 1) / numPoints,
 -                                      lastY + (y - lastY) * (i + 1) / numPoints,
 -                                      w, h,
 -                                      parentArea,
 -                                      owner->getDocument()->getComponentLayout());
 -             }
 -         }
 -     }
 - 
 -     return p;
 - }
 - 
 - void PathPoint::changePointType (const Path::Iterator::PathElementType newType,
 -                                  const Rectangle<int>& parentArea, const bool undoable)
 - {
 -     if (newType != type)
 -     {
 -         if (undoable)
 -         {
 -             owner->perform (new ChangePointAction (this, withChangedPointType (newType, parentArea)),
 -                             "Change path point type");
 -         }
 -         else
 -         {
 -             *this = withChangedPointType (newType, parentArea);
 -             owner->pointListChanged();
 -         }
 -     }
 - }
 - 
 - void PathPoint::getEditableProperties (Array<PropertyComponent*>& props)
 - {
 -     const int index = owner->points.indexOf (this);
 -     jassert (index >= 0);
 - 
 -     switch (type)
 -     {
 -         case Path::Iterator::startNewSubPath:
 -             props.add (new PathPointPositionProperty (owner, index, 0, "x", PositionPropertyBase::componentX));
 -             props.add (new PathPointPositionProperty (owner, index, 0, "y", PositionPropertyBase::componentY));
 - 
 -             props.add (new PathPointClosedProperty (owner, index));
 -             props.add (new AddNewPointProperty (owner, index));
 -             break;
 - 
 -         case Path::Iterator::lineTo:
 -             props.add (new PathPointTypeProperty (owner, index));
 -             props.add (new PathPointPositionProperty (owner, index, 0, "x", PositionPropertyBase::componentX));
 -             props.add (new PathPointPositionProperty (owner, index, 0, "y", PositionPropertyBase::componentY));
 -             props.add (new AddNewPointProperty (owner, index));
 -             break;
 - 
 -         case Path::Iterator::quadraticTo:
 -             props.add (new PathPointTypeProperty (owner, index));
 -             props.add (new PathPointPositionProperty (owner, index, 0, "control pt x", PositionPropertyBase::componentX));
 -             props.add (new PathPointPositionProperty (owner, index, 0, "control pt y", PositionPropertyBase::componentY));
 -             props.add (new PathPointPositionProperty (owner, index, 1, "x", PositionPropertyBase::componentX));
 -             props.add (new PathPointPositionProperty (owner, index, 1, "y", PositionPropertyBase::componentY));
 -             props.add (new AddNewPointProperty (owner, index));
 -             break;
 - 
 -         case Path::Iterator::cubicTo:
 -             props.add (new PathPointTypeProperty (owner, index));
 -             props.add (new PathPointPositionProperty (owner, index, 0, "control pt1 x", PositionPropertyBase::componentX));
 -             props.add (new PathPointPositionProperty (owner, index, 0, "control pt1 y", PositionPropertyBase::componentY));
 -             props.add (new PathPointPositionProperty (owner, index, 1, "control pt2 x", PositionPropertyBase::componentX));
 -             props.add (new PathPointPositionProperty (owner, index, 1, "control pt2 y", PositionPropertyBase::componentY));
 -             props.add (new PathPointPositionProperty (owner, index, 2, "x", PositionPropertyBase::componentX));
 -             props.add (new PathPointPositionProperty (owner, index, 2, "y", PositionPropertyBase::componentY));
 -             props.add (new AddNewPointProperty (owner, index));
 -             break;
 - 
 -         case Path::Iterator::closePath:
 -             break;
 - 
 -         default:
 -             jassertfalse;
 -             break;
 -     }
 - }
 - 
 - void PathPoint::deleteFromPath()
 - {
 -     owner->deletePoint (owner->points.indexOf (this), true);
 - }
 - 
 - //==============================================================================
 - PathPointComponent::PathPointComponent (PaintElementPath* const path_,
 -                                         const int index_,
 -                                         const int pointNumber_)
 -     : ElementSiblingComponent (path_),
 -       path (path_),
 -       routine (path_->getOwner()),
 -       index (index_),
 -       pointNumber (pointNumber_),
 -       selected (false)
 - {
 -     setSize (11, 11);
 -     setRepaintsOnMouseActivity (true);
 - 
 -     selected = routine->getSelectedPoints().isSelected (path_->points [index]);
 -     routine->getSelectedPoints().addChangeListener (this);
 - }
 - 
 - PathPointComponent::~PathPointComponent()
 - {
 -     routine->getSelectedPoints().removeChangeListener (this);
 - }
 - 
 - void PathPointComponent::updatePosition()
 - {
 -     const Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
 -     jassert (getParentComponent() != nullptr);
 - 
 -     double x, y;
 -     path->getPoint (index, pointNumber, x, y, area);
 - 
 -     setCentrePosition (roundToInt (x),
 -                        roundToInt (y));
 - }
 - 
 - void PathPointComponent::showPopupMenu()
 - {
 - }
 - 
 - void PathPointComponent::paint (Graphics& g)
 - {
 -     if (isMouseOverOrDragging())
 -         g.fillAll (Colours::red);
 - 
 -     if (selected)
 -     {
 -         g.setColour (Colours::red);
 -         g.drawRect (getLocalBounds());
 -     }
 - 
 -     g.setColour (Colours::white);
 -     g.fillRect (getWidth() / 2 - 3, getHeight() / 2 - 3, 7, 7);
 - 
 -     g.setColour (Colours::black);
 - 
 -     if (pointNumber < path->getPoint (index)->getNumPoints() - 1)
 -         g.drawRect (getWidth() / 2 - 2, getHeight() / 2 - 2, 5, 5);
 -     else
 -         g.fillRect (getWidth() / 2 - 2, getHeight() / 2 - 2, 5, 5);
 - }
 - 
 - void PathPointComponent::mouseDown (const MouseEvent& e)
 - {
 -     dragging = false;
 - 
 -     if (e.mods.isPopupMenu())
 -     {
 -         showPopupMenu();
 -         return; // this may be deleted now..
 -     }
 - 
 -     dragX = getX() + getWidth() / 2;
 -     dragY = getY() + getHeight() / 2;
 - 
 -     mouseDownSelectStatus = routine->getSelectedPoints().addToSelectionOnMouseDown (path->points [index], e.mods);
 - 
 -     owner->getDocument()->beginTransaction();
 - }
 - 
 - void PathPointComponent::mouseDrag (const MouseEvent& e)
 - {
 -     if (! e.mods.isPopupMenu())
 -     {
 -         if (selected && ! dragging)
 -             dragging = e.mouseWasDraggedSinceMouseDown();
 - 
 -         if (dragging)
 -         {
 -             const Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
 -             int x = dragX + e.getDistanceFromDragStartX() - area.getX();
 -             int y = dragY + e.getDistanceFromDragStartY() - area.getY();
 - 
 -             if (JucerDocument* const document = owner->getDocument())
 -             {
 -                 x = document->snapPosition (x);
 -                 y = document->snapPosition (y);
 -             }
 - 
 -             owner->getDocument()->getUndoManager().undoCurrentTransactionOnly();
 -             path->movePoint (index, pointNumber, x + area.getX(), y + area.getY(), area, true);
 -         }
 -     }
 - }
 - 
 - void PathPointComponent::mouseUp (const MouseEvent& e)
 - {
 -     routine->getSelectedPoints().addToSelectionOnMouseUp (path->points [index],
 -                                                           e.mods, dragging,
 -                                                           mouseDownSelectStatus);
 - }
 - 
 - void PathPointComponent::changeListenerCallback (ChangeBroadcaster* source)
 - {
 -     ElementSiblingComponent::changeListenerCallback (source);
 - 
 -     const bool nowSelected = routine->getSelectedPoints().isSelected (path->points [index]);
 - 
 -     if (nowSelected != selected)
 -     {
 -         selected = nowSelected;
 -         repaint();
 - 
 -         if (Component* parent = getParentComponent())
 -             parent->repaint();
 -     }
 - }
 
 
  |