diff --git a/extras/juce demo/Source/demos/RenderingTestComponent.cpp b/extras/juce demo/Source/demos/RenderingTestComponent.cpp index 423406779a..c4c7ecd148 100644 --- a/extras/juce demo/Source/demos/RenderingTestComponent.cpp +++ b/extras/juce demo/Source/demos/RenderingTestComponent.cpp @@ -88,7 +88,7 @@ public: if (owner.clipToImageToggle->getToggleState()) clipToImage (g); - g.fillCheckerBoard (0, 0, getWidth(), getHeight(), 50, 50, + g.fillCheckerBoard (getLocalBounds(), 50, 50, Colour (0xffdddddd), Colours::transparentBlack); switch (owner.testTypeComboBox->getSelectedId()) diff --git a/extras/the jucer/src/model/components/jucer_TabbedComponentHandler.h b/extras/the jucer/src/model/components/jucer_TabbedComponentHandler.h index 39787f7e79..7e084cb3e7 100644 --- a/extras/the jucer/src/model/components/jucer_TabbedComponentHandler.h +++ b/extras/the jucer/src/model/components/jucer_TabbedComponentHandler.h @@ -387,8 +387,7 @@ private: { if (getNumChildComponents() == 0) { - g.fillCheckerBoard (0, 0, getWidth(), getHeight(), - 50, 50, + g.fillCheckerBoard (getLocalBounds(), 50, 50, Colour::greyLevel (0.9f).withAlpha (0.4f), Colour::greyLevel (0.8f).withAlpha (0.4f)); } diff --git a/extras/the jucer/src/model/components/jucer_ViewportHandler.h b/extras/the jucer/src/model/components/jucer_ViewportHandler.h index dc7731fe1e..1f08d19a99 100644 --- a/extras/the jucer/src/model/components/jucer_ViewportHandler.h +++ b/extras/the jucer/src/model/components/jucer_ViewportHandler.h @@ -297,8 +297,7 @@ private: void paint (Graphics& g) { - g.fillCheckerBoard (0, 0, getWidth(), getHeight(), - 50, 50, + g.fillCheckerBoard (getLocalBounds(), 50, 50, Colours::lightgrey.withAlpha (0.5f), Colours::darkgrey.withAlpha (0.5f)); } diff --git a/extras/the jucer/src/model/jucer_PaintRoutine.cpp b/extras/the jucer/src/model/jucer_PaintRoutine.cpp index c723d5a991..1fc2ab93dc 100644 --- a/extras/the jucer/src/model/jucer_PaintRoutine.cpp +++ b/extras/the jucer/src/model/jucer_PaintRoutine.cpp @@ -513,7 +513,7 @@ void PaintRoutine::fillWithBackground (Graphics& g, const bool drawOpaqueBackgro { if ((! backgroundColour.isOpaque()) && drawOpaqueBackground) { - g.fillCheckerBoard (0, 0, g.getClipBounds().getRight(), g.getClipBounds().getBottom(), + g.fillCheckerBoard (Rectangle (0, 0, g.getClipBounds().getRight(), g.getClipBounds().getBottom()), 50, 50, Colour (0xffdddddd).overlaidWith (backgroundColour), Colour (0xffffffff).overlaidWith (backgroundColour)); diff --git a/extras/the jucer/src/model/paintelements/jucer_FillType.cpp b/extras/the jucer/src/model/paintelements/jucer_FillType.cpp index 2314c71aeb..0724c3786a 100644 --- a/extras/the jucer/src/model/paintelements/jucer_FillType.cpp +++ b/extras/the jucer/src/model/paintelements/jucer_FillType.cpp @@ -328,7 +328,7 @@ void JucerFillType::loadImage (JucerDocument* const document) image = Image (Image::RGB, 100, 100, true); Graphics g (image); - g.fillCheckerBoard (0, 0, image.getWidth(), image.getHeight(), + g.fillCheckerBoard (image.getBounds(), image.getWidth() / 2, image.getHeight() / 2, Colours::white, Colours::lightgrey); diff --git a/extras/the jucer/src/utility/jucer_ColourEditorComponent.h b/extras/the jucer/src/utility/jucer_ColourEditorComponent.h index 464e5fcb6f..60ac07799f 100644 --- a/extras/the jucer/src/utility/jucer_ColourEditorComponent.h +++ b/extras/the jucer/src/utility/jucer_ColourEditorComponent.h @@ -49,7 +49,7 @@ public: { g.fillAll (Colours::grey); - g.fillCheckerBoard (2, 2, getWidth() - 4, getHeight() - 4, + g.fillCheckerBoard (getLocalBounds().reduced (2, 2), 10, 10, Colour (0xffdddddd).overlaidWith (colour), Colour (0xffffffff).overlaidWith (colour)); diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index e47f42e9d4..c6fbbbc130 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -16643,6 +16643,15 @@ ValueTree ValueTree::getParent() const return ValueTree (object != 0 ? object->parent : (SharedObject*) 0); } +ValueTree ValueTree::getSibling (const int delta) const +{ + if (object == 0 || object->parent == 0) + return invalid; + + const int index = object->parent->indexOf (*this) + delta; + return ValueTree (static_cast (object->children [index])); +} + const var& ValueTree::operator[] (const Identifier& name) const { return object == 0 ? var::null : object->getProperty (name); @@ -39263,7 +39272,7 @@ const Point Component::relativePositionToOtherComponent (const Component* c return p; } -void Component::setBounds (int x, int y, int w, int h) +void Component::setBounds (const int x, const int y, int w, int h) { // if component methods are being called from threads other than the message // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. @@ -39397,18 +39406,16 @@ void Component::setCentreRelative (const float x, const float y) void Component::centreWithSize (const int width, const int height) { - setBounds ((getParentWidth() - width) / 2, - (getParentHeight() - height) / 2, - width, - height); + const Rectangle parentArea (getParentOrMainMonitorBounds()); + + setBounds (parentArea.getCentreX() - width / 2, + parentArea.getCentreY() - height / 2, + width, height); } void Component::setBoundsInset (const BorderSize& borders) { - setBounds (borders.getLeft(), - borders.getTop(), - getParentWidth() - (borders.getLeftAndRight()), - getParentHeight() - (borders.getTopAndBottom())); + setBounds (borders.subtractedFrom (getParentOrMainMonitorBounds())); } void Component::setBoundsToFit (int x, int y, int width, int height, @@ -40239,7 +40246,13 @@ void Component::colourChanged() const Rectangle Component::getLocalBounds() const throw() { - return Rectangle (0, 0, getWidth(), getHeight()); + return Rectangle (getWidth(), getHeight()); +} + +const Rectangle Component::getParentOrMainMonitorBounds() const +{ + return parentComponent_ != 0 ? parentComponent_->getLocalBounds() + : Desktop::getInstance().getMainMonitorArea(); } const Rectangle Component::getUnclippedArea() const @@ -41081,8 +41094,8 @@ void Component::internalMouseWheel (MouseInputSource& source, const Point& Desktop& desktop = Desktop::getInstance(); BailOutChecker checker (this); - const float wheelIncrementX = amountX * (1.0f / 256.0f); - const float wheelIncrementY = amountY * (1.0f / 256.0f); + const float wheelIncrementX = amountX / 256.0f; + const float wheelIncrementY = amountY / 256.0f; const MouseEvent me (source, relativePos, source.getCurrentModifiers(), this, this, time, relativePos, time, 0, false); @@ -41521,8 +41534,7 @@ const Point Component::getMouseXYRelative() const const Rectangle Component::getParentMonitorArea() const { return Desktop::getInstance() - .getMonitorAreaContaining (relativePositionToGlobal (Point (getWidth() / 2, - getHeight() / 2))); + .getMonitorAreaContaining (relativePositionToGlobal (getLocalBounds().getCentre())); } void Component::addKeyListener (KeyListener* const newListener) @@ -73473,8 +73485,7 @@ public: { const Colour colour (owner->getSwatchColour (index)); - g.fillCheckerBoard (0, 0, getWidth(), getHeight(), - 6, 6, + g.fillCheckerBoard (getLocalBounds(), 6, 6, Colour (0xffdddddd).overlaidWith (colour), Colour (0xffffffff).overlaidWith (colour)); } @@ -73517,7 +73528,6 @@ ColourSelector::ColourSelector (const int flags_, colourSpace (0), hueSelector (0), flags (flags_), - topSpace (0), edgeGap (edgeGap_) { // not much point having a selector with no components in it! @@ -73623,7 +73633,7 @@ void ColourSelector::update() } if ((flags & showColourAtTop) != 0) - repaint (0, edgeGap, getWidth(), topSpace - edgeGap); + repaint (previewArea); sendChangeMessage (this); } @@ -73636,15 +73646,14 @@ void ColourSelector::paint (Graphics& g) { const Colour currentColour (getCurrentColour()); - g.fillCheckerBoard (edgeGap, edgeGap, getWidth() - edgeGap - edgeGap, topSpace - edgeGap - edgeGap, - 10, 10, + g.fillCheckerBoard (previewArea, 10, 10, Colour (0xffdddddd).overlaidWith (currentColour), Colour (0xffffffff).overlaidWith (currentColour)); g.setColour (Colours::white.overlaidWith (currentColour).contrasting()); g.setFont (14.0f, true); g.drawText (currentColour.toDisplayString ((flags & showAlphaChannel) != 0), - 0, edgeGap, getWidth(), topSpace - edgeGap * 2, + previewArea.getX(), previewArea.getY(), previewArea.getWidth(), previewArea.getHeight(), Justification::centred, false); } @@ -73674,7 +73683,9 @@ void ColourSelector::resized() const int swatchSpace = numSwatches > 0 ? edgeGap + swatchHeight * ((numSwatches + 7) / swatchesPerRow) : 0; const int sliderSpace = ((flags & showSliders) != 0) ? jmin (22 * numSliders + edgeGap, proportionOfHeight (0.3f)) : 0; - topSpace = ((flags & showColourAtTop) != 0) ? jmin (30 + edgeGap * 2, proportionOfHeight (0.2f)) : edgeGap; + const int topSpace = ((flags & showColourAtTop) != 0) ? jmin (30 + edgeGap * 2, proportionOfHeight (0.2f)) : edgeGap; + + previewArea.setBounds (edgeGap, edgeGap, getWidth() - edgeGap * 2, topSpace - edgeGap * 2); int y = topSpace; @@ -77606,8 +77617,8 @@ ResizableWindow::~ResizableWindow() { resizableCorner = 0; resizableBorder = 0; - deleteAndZero (contentComponent); // (avoid using a scoped pointer for this, so that it survives - // external deletion of the content comp) + delete static_cast (contentComponent); + contentComponent = 0; // have you been adding your own components directly to this window..? tut tut tut. // Read the instructions for using a ResizableWindow! @@ -77635,6 +77646,9 @@ void ResizableWindow::setContentComponent (Component* const newContentComponent, if (deleteOldOne) delete static_cast (contentComponent); // (avoid using a scoped pointer for this, so that it survives // external deletion of the content comp) + else + removeChildComponent (contentComponent); + contentComponent = newContentComponent; Component::addAndMakeVisible (contentComponent); @@ -77726,12 +77740,13 @@ void ResizableWindow::childBoundsChanged (Component* child) void ResizableWindow::activeWindowStatusChanged() { - const BorderSize borders (getContentComponentBorder()); + const BorderSize border (getContentComponentBorder()); - repaint (0, 0, getWidth(), borders.getTop()); - repaint (0, borders.getTop(), borders.getLeft(), getHeight() - borders.getBottom() - borders.getTop()); - repaint (0, getHeight() - borders.getBottom(), getWidth(), borders.getBottom()); - repaint (getWidth() - borders.getRight(), borders.getTop(), borders.getRight(), getHeight() - borders.getBottom() - borders.getTop()); + Rectangle area (getLocalBounds()); + repaint (area.removeFromTop (border.getTop())); + repaint (area.removeFromLeft (border.getLeft())); + repaint (area.removeFromRight (border.getRight())); + repaint (area.removeFromBottom (border.getBottom())); } void ResizableWindow::setResizable (const bool shouldBeResizable, @@ -80984,7 +80999,7 @@ void Graphics::drawArrow (const Line& line, const float lineThickness, co fillPath (p); } -void Graphics::fillCheckerBoard (int x, int y, int width, int height, +void Graphics::fillCheckerBoard (const Rectangle& area, const int checkWidth, const int checkHeight, const Colour& colour1, const Colour& colour2) const { @@ -80997,29 +81012,29 @@ void Graphics::fillCheckerBoard (int x, int y, int width, int height, if (colour1 == colour2) { context->setFill (colour1); - context->fillRect (Rectangle (x, y, width, height), false); + context->fillRect (area, false); } else { - const Rectangle clip (context->getClipBounds()); + const Rectangle clipped (context->getClipBounds().getIntersection (area)); - const int right = jmin (x + width, clip.getRight()); - const int bottom = jmin (y + height, clip.getBottom()); - - int cy = 0; - while (y < bottom) + if (! clipped.isEmpty()) { - int cx = cy; + context->clipToRectangle (clipped); + const int startX = area.getX() + ((clipped.getX() - area.getX()) / checkWidth) * checkWidth; + const int startY = area.getY() + ((clipped.getY() - area.getY()) / checkHeight) * checkHeight; + const int right = clipped.getRight(); + const int bottom = clipped.getBottom(); - for (int xx = x; xx < right; xx += checkWidth) + for (int i = 0; i < 2; ++i) { - context->setFill (((cx++ & 1) == 0) ? colour1 : colour2); - context->fillRect (Rectangle (xx, y, jmin (checkWidth, right - xx), jmin (checkHeight, bottom - y)), - false); - } + context->setFill (i == 0 ? colour1 : colour2); - ++cy; - y += checkHeight; + int cy = i; + for (int y = startY; y < bottom; y += checkHeight) + for (int x = startX + (cy++ & 1) * checkWidth; x < right; x += checkWidth * 2) + context->fillRect (Rectangle (x, y, checkWidth, checkHeight), false); + } } } @@ -81272,7 +81287,7 @@ LowLevelGraphicsPostScriptRenderer::LowLevelGraphicsPostScriptRenderer (OutputSt needToClip (true) { stateStack.add (new SavedState()); - stateStack.getLast()->clip = Rectangle (0, 0, totalWidth_, totalHeight_); + stateStack.getLast()->clip = Rectangle (totalWidth_, totalHeight_); const float scale = jmin ((520.0f / totalWidth_), (750.0f / totalHeight)); @@ -85575,6 +85590,7 @@ void DrawablePath::ValueTreeWrapper::setUsesNonZeroWinding (bool b, UndoManager* state.setProperty (nonZeroWinding, b, undoManager); } +const Identifier DrawablePath::ValueTreeWrapper::Element::mode ("mode"); const Identifier DrawablePath::ValueTreeWrapper::Element::startSubPathElement ("Move"); const Identifier DrawablePath::ValueTreeWrapper::Element::closeSubPathElement ("Close"); const Identifier DrawablePath::ValueTreeWrapper::Element::lineToElement ("Line"); @@ -85595,6 +85611,11 @@ DrawablePath::ValueTreeWrapper DrawablePath::ValueTreeWrapper::Element::getParen return ValueTreeWrapper (state.getParent().getParent()); } +DrawablePath::ValueTreeWrapper::Element DrawablePath::ValueTreeWrapper::Element::getPreviousElement() const +{ + return Element (state.getSibling (-1)); +} + int DrawablePath::ValueTreeWrapper::Element::getNumControlPoints() const throw() { const Identifier i (state.getType()); @@ -85622,6 +85643,18 @@ void DrawablePath::ValueTreeWrapper::Element::setControlPoint (const int index, return state.setProperty (index == 0 ? point1 : (index == 1 ? point2 : point3), point.toString(), undoManager); } +const RelativePoint DrawablePath::ValueTreeWrapper::Element::getStartPoint() const +{ + const Identifier i (state.getType()); + + if (i == startSubPathElement) + return getControlPoint (0); + + jassert (i == lineToElement || i == quadraticToElement || i == cubicToElement || i == closeSubPathElement); + + return getPreviousElement().getEndPoint(); +} + const RelativePoint DrawablePath::ValueTreeWrapper::Element::getEndPoint() const { const Identifier i (state.getType()); @@ -85629,9 +85662,77 @@ const RelativePoint DrawablePath::ValueTreeWrapper::Element::getEndPoint() const if (i == quadraticToElement) return getControlPoint (1); if (i == cubicToElement) return getControlPoint (2); + jassert (i == closeSubPathElement); return RelativePoint(); } +const String DrawablePath::ValueTreeWrapper::Element::getModeOfEndPoint() const +{ + return state [mode].toString(); +} + +void DrawablePath::ValueTreeWrapper::Element::setModeOfEndPoint (const String& newMode, UndoManager* undoManager) +{ + if (state.hasType (cubicToElement)) + state.setProperty (mode, newMode, undoManager); +} + +void DrawablePath::ValueTreeWrapper::Element::convertToLine (UndoManager* undoManager) +{ + const Identifier i (state.getType()); + + if (i == quadraticToElement || i == cubicToElement) + { + ValueTree newState (lineToElement); + Element e (newState); + e.setControlPoint (0, getEndPoint(), undoManager); + state = newState; + } +} + +void DrawablePath::ValueTreeWrapper::Element::convertToCubic (RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager) +{ + const Identifier i (state.getType()); + + if (i == lineToElement || i == quadraticToElement) + { + ValueTree newState (cubicToElement); + Element e (newState); + + const RelativePoint start (getStartPoint()); + const RelativePoint end (getEndPoint()); + const Point startResolved (start.resolve (nameFinder)); + const Point endResolved (end.resolve (nameFinder)); + e.setControlPoint (0, startResolved + (endResolved - startResolved) * 0.3f, undoManager); + e.setControlPoint (1, startResolved + (endResolved - startResolved) * 0.7f, undoManager); + e.setControlPoint (2, end, undoManager); + + state = newState; + } +} + +void DrawablePath::ValueTreeWrapper::Element::convertToPathBreak (UndoManager* undoManager) +{ + const Identifier i (state.getType()); + + if (i != startSubPathElement) + { + ValueTree newState (startSubPathElement); + Element e (newState); + e.setControlPoint (0, getEndPoint(), undoManager); + state = newState; + } +} + +void DrawablePath::ValueTreeWrapper::Element::insertPoint (double, RelativeCoordinate::NamedCoordinateFinder*, UndoManager*) +{ +} + +void DrawablePath::ValueTreeWrapper::Element::removePoint (UndoManager* undoManager) +{ + state.getParent().removeChild (state, undoManager); +} + const Rectangle DrawablePath::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) { Rectangle damageRect; @@ -85674,7 +85775,7 @@ const Rectangle DrawablePath::refreshFromValueTree (const ValueTree& tree needsRedraw = true; } - relativePath = newRelativePath.release(); + relativePath = newRelativePath; if (needsRedraw) damageRect = damageRect.getUnion (getBounds()); @@ -90602,6 +90703,61 @@ const Line Path::getClippedLine (const Line& line, const bool keep return result; } +float Path::getLength (const AffineTransform& transform) const +{ + float length = 0; + PathFlatteningIterator i (*this, transform); + + while (i.next()) + length += Line (i.x1, i.y1, i.x2, i.y2).getLength(); + + return length; +} + +const Point Path::getPointAlongPath (float distanceFromStart, const AffineTransform& transform) const +{ + PathFlatteningIterator i (*this, transform); + + while (i.next()) + { + const Line line (i.x1, i.y1, i.x2, i.y2); + const float lineLength = line.getLength(); + + if (distanceFromStart <= lineLength) + return line.getPointAlongLine (distanceFromStart); + + distanceFromStart -= lineLength; + } + + return Point (i.x2, i.y2); +} + +float Path::getNearestPoint (const Point& targetPoint, Point& pointOnPath, + const AffineTransform& transform) const +{ + PathFlatteningIterator i (*this, transform); + float bestPosition = 0, bestDistance = std::numeric_limits::max(); + float length = 0; + Point pointOnLine; + + while (i.next()) + { + const Line line (i.x1, i.y1, i.x2, i.y2); + const float distance = line.getDistanceFromPoint (targetPoint, pointOnLine); + + if (distance < bestDistance) + { + bestDistance = distance; + bestPosition = length + pointOnLine.getDistanceFrom (line.getStart()); + pointOnPath = pointOnLine; + } + + length += line.getLength(); + } + + return bestPosition; +} + const Path Path::createPathWithRoundedCorners (const float cornerRadius) const { if (cornerRadius <= 0.01f) @@ -92194,7 +92350,7 @@ void PositionedRectangle::getRectangleDouble (const Rectangle& target, void PositionedRectangle::applyToComponent (Component& comp) const throw() { - comp.setBounds (getRectangle (Rectangle (0, 0, comp.getParentWidth(), comp.getParentHeight()))); + comp.setBounds (getRectangle (Rectangle (comp.getParentWidth(), comp.getParentHeight()))); } void PositionedRectangle::updateFrom (const Rectangle& rectangle, @@ -92217,7 +92373,7 @@ void PositionedRectangle::updateFromComponent (const Component& comp) throw() if (comp.getParentComponent() == 0 && ! comp.isOnDesktop()) updateFrom (comp.getBounds(), Rectangle()); else - updateFrom (comp.getBounds(), Rectangle (0, 0, comp.getParentWidth(), comp.getParentHeight())); + updateFrom (comp.getBounds(), Rectangle (comp.getParentWidth(), comp.getParentHeight())); } PositionedRectangle::AnchorPoint PositionedRectangle::getAnchorPointX() const throw() @@ -239971,7 +240127,7 @@ private: if (needToPaintAll) { contextClip.clear(); - contextClip.addWithoutMerging (Rectangle (0, 0, w, h)); + contextClip.addWithoutMerging (Rectangle (w, h)); } if (transparent) @@ -258345,8 +258501,7 @@ void juce_updateMultiMonitorInfo (Array >& monitorCoords, const if (monitorCoords.size() == 0) { - monitorCoords.add (Rectangle (0, 0, - DisplayWidth (display, DefaultScreen (display)), + monitorCoords.add (Rectangle (DisplayWidth (display, DefaultScreen (display)), DisplayHeight (display, DefaultScreen (display)))); } } @@ -261764,7 +261919,7 @@ public: - (void) createConnection { - NSInteger oldRetainCount = [self retainCount]; + NSUInteger oldRetainCount = [self retainCount]; connection = [[NSURLConnection alloc] initWithRequest: request delegate: self]; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 778864ac66..0a3c1eedb3 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -64,7 +64,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 29 +#define JUCE_BUILDNUMBER 30 /** Current Juce version number. @@ -13289,6 +13289,14 @@ public: */ ValueTree getParent() const; + /** Returns one of this node's siblings in its parent's child list. + + The delta specifies how far to move through the list, so a value of 1 would return the node + that follows this one, -1 would return the node before it, 0 will return this node itself, etc. + If the requested position is beyond the range of available nodes, this will return ValueTree::invalid. + */ + ValueTree getSibling (int delta) const; + /** Creates an XmlElement that holds a complete image of this node and all its children. If this node is invalid, this may return 0. Otherwise, the XML that is produced can @@ -20174,25 +20182,42 @@ public: distance from the line; if the point is a long way beyond one of the line's end-point's, it'll return the straight-line distance to the nearest end-point. + pointOnLine receives the position of the point that is found. + @returns the point's distance from the line @see getPositionAlongLineOfNearestPoint */ - ValueType getDistanceFromPoint (const Point& point) const throw() + ValueType getDistanceFromPoint (const Point& targetPoint, + Point& pointOnLine) const throw() { const Point delta (end - start); const double length = delta.getX() * delta.getX() + delta.getY() * delta.getY(); if (length > 0) { - const double prop = ((point.getX() - start.getX()) * delta.getX() - + (point.getY() - start.getY()) * delta.getY()) / length; + const double prop = ((targetPoint.getX() - start.getX()) * delta.getX() + + (targetPoint.getY() - start.getY()) * delta.getY()) / length; if (prop >= 0 && prop <= 1.0) - return point.getDistanceFrom (start + delta * (ValueType) prop); + { + pointOnLine = start + delta * (ValueType) prop; + return targetPoint.getDistanceFrom (pointOnLine); + } } - return jmin (point.getDistanceFrom (start), - point.getDistanceFrom (end)); + const float fromStart = targetPoint.getDistanceFrom (start); + const float fromEnd = targetPoint.getDistanceFrom (end); + + if (fromStart < fromEnd) + { + pointOnLine = start; + return fromStart; + } + else + { + pointOnLine = end; + return fromEnd; + } } /** Finds the point on this line which is nearest to a given point, and @@ -21254,6 +21279,27 @@ public: */ const Line getClippedLine (const Line& line, bool keepSectionOutsidePath) const; + /** Returns the length of the path. + @see getPointAlongPath + */ + float getLength (const AffineTransform& transform = AffineTransform::identity) const; + + /** Returns a point that is the specified distance along the path. + If the distance is greater than the total length of the path, this will return the + end point. + @see getLength + */ + const Point getPointAlongPath (float distanceFromStart, + const AffineTransform& transform = AffineTransform::identity) const; + + /** Finds the point along the path which is nearest to a given position. + This sets pointOnPath to the nearest point, and returns the distance of this point from the start + of the path. + */ + float getNearestPoint (const Point& targetPoint, + Point& pointOnPath, + const AffineTransform& transform = AffineTransform::identity) const; + /** Removes all lines and curves, resetting the path completely. */ void clear() throw(); @@ -23944,7 +23990,7 @@ public: /** Fills a rectangle with a checkerboard pattern, alternating between two colours. */ - void fillCheckerBoard (int x, int y, int width, int height, + void fillCheckerBoard (const Rectangle& area, int checkWidth, int checkHeight, const Colour& colour1, const Colour& colour2) const; @@ -24494,7 +24540,7 @@ public: /** Returns a rectangle with the same size as this image. The rectangle's origin is always (0, 0). */ - const Rectangle getBounds() const throw() { return image == 0 ? Rectangle() : Rectangle (0, 0, image->width, image->height); } + const Rectangle getBounds() const throw() { return image == 0 ? Rectangle() : Rectangle (image->width, image->height); } /** Returns the image's pixel format. */ PixelFormat getFormat() const throw() { return image == 0 ? UnknownFormat : image->format; } @@ -25648,7 +25694,8 @@ public: /** Changes the component's size and centres it within its parent. After changing the size, the component will be moved so that it's - centred within its parent. + centred within its parent. If the component is on the desktop (or has no + parent component), then it'll be centred within the main monitor area. */ void centreWithSize (int width, int height); @@ -25809,7 +25856,7 @@ public: /** Checks whether a component is anywhere inside this component or its children. - This will recursively check through this components children to see if the + This will recursively check through this component's children to see if the given component is anywhere inside. */ bool isParentOf (const Component* possibleChild) const throw(); @@ -27224,6 +27271,7 @@ private: // how much of the component is not off the edges of its parents const Rectangle getUnclippedArea() const; void sendVisibilityChangeMessage(); + const Rectangle getParentOrMainMonitorBounds() const; // This is included here just to cause a compile error if your code is still handling // drag-and-drop with this method. If so, just update it to use the new FileDragAndDropTarget @@ -56052,7 +56100,8 @@ private: HueSelectorComp* hueSelector; OwnedArray swatchComponents; const int flags; - int topSpace, edgeGap; + int edgeGap; + Rectangle previewArea; void setHue (float newH); void setSV (float newS, float newV); @@ -59340,13 +59389,27 @@ public: const RelativePoint getControlPoint (int index) const; Value getControlPointValue (int index, UndoManager* undoManager) const; + const RelativePoint getStartPoint() const; const RelativePoint getEndPoint() const; void setControlPoint (int index, const RelativePoint& point, UndoManager* undoManager); ValueTreeWrapper getParent() const; + Element getPreviousElement() const; + + const String getModeOfEndPoint() const; + void setModeOfEndPoint (const String& newMode, UndoManager* undoManager); + + void convertToLine (UndoManager* undoManager); + void convertToCubic (RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); + void convertToPathBreak (UndoManager* undoManager); + void insertPoint (double proportionOfLength, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); + void removePoint (UndoManager* undoManager); - static const Identifier startSubPathElement, closeSubPathElement, + static const Identifier mode, startSubPathElement, closeSubPathElement, lineToElement, quadraticToElement, cubicToElement; + static const char* cornerMode; + static const char* roundedMode; + static const char* symmetricMode; ValueTree state; }; diff --git a/src/containers/juce_ValueTree.cpp b/src/containers/juce_ValueTree.cpp index 964b066e4a..ea270e8801 100644 --- a/src/containers/juce_ValueTree.cpp +++ b/src/containers/juce_ValueTree.cpp @@ -610,6 +610,15 @@ ValueTree ValueTree::getParent() const return ValueTree (object != 0 ? object->parent : (SharedObject*) 0); } +ValueTree ValueTree::getSibling (const int delta) const +{ + if (object == 0 || object->parent == 0) + return invalid; + + const int index = object->parent->indexOf (*this) + delta; + return ValueTree (static_cast (object->children [index])); +} + const var& ValueTree::operator[] (const Identifier& name) const { return object == 0 ? var::null : object->getProperty (name); diff --git a/src/containers/juce_ValueTree.h b/src/containers/juce_ValueTree.h index 371c2e046e..0a4900cd77 100644 --- a/src/containers/juce_ValueTree.h +++ b/src/containers/juce_ValueTree.h @@ -302,6 +302,14 @@ public: */ ValueTree getParent() const; + /** Returns one of this node's siblings in its parent's child list. + + The delta specifies how far to move through the list, so a value of 1 would return the node + that follows this one, -1 would return the node before it, 0 will return this node itself, etc. + If the requested position is beyond the range of available nodes, this will return ValueTree::invalid. + */ + ValueTree getSibling (int delta) const; + //============================================================================== /** Creates an XmlElement that holds a complete image of this node and all its children. diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index a1e9cb794a..066b495f37 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 29 +#define JUCE_BUILDNUMBER 30 /** Current Juce version number. diff --git a/src/gui/components/juce_Component.cpp b/src/gui/components/juce_Component.cpp index cc12be2fc7..db3f2efc96 100644 --- a/src/gui/components/juce_Component.cpp +++ b/src/gui/components/juce_Component.cpp @@ -791,7 +791,7 @@ const Point Component::relativePositionToOtherComponent (const Component* c } //============================================================================== -void Component::setBounds (int x, int y, int w, int h) +void Component::setBounds (const int x, const int y, int w, int h) { // if component methods are being called from threads other than the message // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. @@ -925,18 +925,16 @@ void Component::setCentreRelative (const float x, const float y) void Component::centreWithSize (const int width, const int height) { - setBounds ((getParentWidth() - width) / 2, - (getParentHeight() - height) / 2, - width, - height); + const Rectangle parentArea (getParentOrMainMonitorBounds()); + + setBounds (parentArea.getCentreX() - width / 2, + parentArea.getCentreY() - height / 2, + width, height); } void Component::setBoundsInset (const BorderSize& borders) { - setBounds (borders.getLeft(), - borders.getTop(), - getParentWidth() - (borders.getLeftAndRight()), - getParentHeight() - (borders.getTopAndBottom())); + setBounds (borders.subtractedFrom (getParentOrMainMonitorBounds())); } void Component::setBoundsToFit (int x, int y, int width, int height, @@ -1781,7 +1779,13 @@ void Component::colourChanged() //============================================================================== const Rectangle Component::getLocalBounds() const throw() { - return Rectangle (0, 0, getWidth(), getHeight()); + return Rectangle (getWidth(), getHeight()); +} + +const Rectangle Component::getParentOrMainMonitorBounds() const +{ + return parentComponent_ != 0 ? parentComponent_->getLocalBounds() + : Desktop::getInstance().getMainMonitorArea(); } const Rectangle Component::getUnclippedArea() const @@ -2637,8 +2641,8 @@ void Component::internalMouseWheel (MouseInputSource& source, const Point& Desktop& desktop = Desktop::getInstance(); BailOutChecker checker (this); - const float wheelIncrementX = amountX * (1.0f / 256.0f); - const float wheelIncrementY = amountY * (1.0f / 256.0f); + const float wheelIncrementX = amountX / 256.0f; + const float wheelIncrementY = amountY / 256.0f; const MouseEvent me (source, relativePos, source.getCurrentModifiers(), this, this, time, relativePos, time, 0, false); @@ -3081,8 +3085,7 @@ const Point Component::getMouseXYRelative() const const Rectangle Component::getParentMonitorArea() const { return Desktop::getInstance() - .getMonitorAreaContaining (relativePositionToGlobal (Point (getWidth() / 2, - getHeight() / 2))); + .getMonitorAreaContaining (relativePositionToGlobal (getLocalBounds().getCentre())); } //============================================================================== diff --git a/src/gui/components/juce_Component.h b/src/gui/components/juce_Component.h index 7ef57b1d82..5850a252e8 100644 --- a/src/gui/components/juce_Component.h +++ b/src/gui/components/juce_Component.h @@ -481,7 +481,8 @@ public: /** Changes the component's size and centres it within its parent. After changing the size, the component will be moved so that it's - centred within its parent. + centred within its parent. If the component is on the desktop (or has no + parent component), then it'll be centred within the main monitor area. */ void centreWithSize (int width, int height); @@ -644,7 +645,7 @@ public: /** Checks whether a component is anywhere inside this component or its children. - This will recursively check through this components children to see if the + This will recursively check through this component's children to see if the given component is anywhere inside. */ bool isParentOf (const Component* possibleChild) const throw(); @@ -2095,6 +2096,7 @@ private: // how much of the component is not off the edges of its parents const Rectangle getUnclippedArea() const; void sendVisibilityChangeMessage(); + const Rectangle getParentOrMainMonitorBounds() const; //============================================================================== // This is included here just to cause a compile error if your code is still handling diff --git a/src/gui/components/special/juce_ColourSelector.cpp b/src/gui/components/special/juce_ColourSelector.cpp index fa60c067f1..974f5e3248 100644 --- a/src/gui/components/special/juce_ColourSelector.cpp +++ b/src/gui/components/special/juce_ColourSelector.cpp @@ -311,8 +311,7 @@ public: { const Colour colour (owner->getSwatchColour (index)); - g.fillCheckerBoard (0, 0, getWidth(), getHeight(), - 6, 6, + g.fillCheckerBoard (getLocalBounds(), 6, 6, Colour (0xffdddddd).overlaidWith (colour), Colour (0xffffffff).overlaidWith (colour)); } @@ -356,7 +355,6 @@ ColourSelector::ColourSelector (const int flags_, colourSpace (0), hueSelector (0), flags (flags_), - topSpace (0), edgeGap (edgeGap_) { // not much point having a selector with no components in it! @@ -464,7 +462,7 @@ void ColourSelector::update() } if ((flags & showColourAtTop) != 0) - repaint (0, edgeGap, getWidth(), topSpace - edgeGap); + repaint (previewArea); sendChangeMessage (this); } @@ -478,15 +476,14 @@ void ColourSelector::paint (Graphics& g) { const Colour currentColour (getCurrentColour()); - g.fillCheckerBoard (edgeGap, edgeGap, getWidth() - edgeGap - edgeGap, topSpace - edgeGap - edgeGap, - 10, 10, + g.fillCheckerBoard (previewArea, 10, 10, Colour (0xffdddddd).overlaidWith (currentColour), Colour (0xffffffff).overlaidWith (currentColour)); g.setColour (Colours::white.overlaidWith (currentColour).contrasting()); g.setFont (14.0f, true); g.drawText (currentColour.toDisplayString ((flags & showAlphaChannel) != 0), - 0, edgeGap, getWidth(), topSpace - edgeGap * 2, + previewArea.getX(), previewArea.getY(), previewArea.getWidth(), previewArea.getHeight(), Justification::centred, false); } @@ -516,7 +513,9 @@ void ColourSelector::resized() const int swatchSpace = numSwatches > 0 ? edgeGap + swatchHeight * ((numSwatches + 7) / swatchesPerRow) : 0; const int sliderSpace = ((flags & showSliders) != 0) ? jmin (22 * numSliders + edgeGap, proportionOfHeight (0.3f)) : 0; - topSpace = ((flags & showColourAtTop) != 0) ? jmin (30 + edgeGap * 2, proportionOfHeight (0.2f)) : edgeGap; + const int topSpace = ((flags & showColourAtTop) != 0) ? jmin (30 + edgeGap * 2, proportionOfHeight (0.2f)) : edgeGap; + + previewArea.setBounds (edgeGap, edgeGap, getWidth() - edgeGap * 2, topSpace - edgeGap * 2); int y = topSpace; diff --git a/src/gui/components/special/juce_ColourSelector.h b/src/gui/components/special/juce_ColourSelector.h index fa94252787..e959dcbe19 100644 --- a/src/gui/components/special/juce_ColourSelector.h +++ b/src/gui/components/special/juce_ColourSelector.h @@ -149,7 +149,8 @@ private: HueSelectorComp* hueSelector; OwnedArray swatchComponents; const int flags; - int topSpace, edgeGap; + int edgeGap; + Rectangle previewArea; void setHue (float newH); void setSV (float newS, float newV); diff --git a/src/gui/components/windows/juce_ResizableWindow.cpp b/src/gui/components/windows/juce_ResizableWindow.cpp index c5c461e183..9dfe875b8d 100644 --- a/src/gui/components/windows/juce_ResizableWindow.cpp +++ b/src/gui/components/windows/juce_ResizableWindow.cpp @@ -78,8 +78,8 @@ ResizableWindow::~ResizableWindow() { resizableCorner = 0; resizableBorder = 0; - deleteAndZero (contentComponent); // (avoid using a scoped pointer for this, so that it survives - // external deletion of the content comp) + delete static_cast (contentComponent); + contentComponent = 0; // have you been adding your own components directly to this window..? tut tut tut. // Read the instructions for using a ResizableWindow! @@ -108,6 +108,9 @@ void ResizableWindow::setContentComponent (Component* const newContentComponent, if (deleteOldOne) delete static_cast (contentComponent); // (avoid using a scoped pointer for this, so that it survives // external deletion of the content comp) + else + removeChildComponent (contentComponent); + contentComponent = newContentComponent; Component::addAndMakeVisible (contentComponent); @@ -201,12 +204,13 @@ void ResizableWindow::childBoundsChanged (Component* child) //============================================================================== void ResizableWindow::activeWindowStatusChanged() { - const BorderSize borders (getContentComponentBorder()); + const BorderSize border (getContentComponentBorder()); - repaint (0, 0, getWidth(), borders.getTop()); - repaint (0, borders.getTop(), borders.getLeft(), getHeight() - borders.getBottom() - borders.getTop()); - repaint (0, getHeight() - borders.getBottom(), getWidth(), borders.getBottom()); - repaint (getWidth() - borders.getRight(), borders.getTop(), borders.getRight(), getHeight() - borders.getBottom() - borders.getTop()); + Rectangle area (getLocalBounds()); + repaint (area.removeFromTop (border.getTop())); + repaint (area.removeFromLeft (border.getLeft())); + repaint (area.removeFromRight (border.getRight())); + repaint (area.removeFromBottom (border.getBottom())); } //============================================================================== diff --git a/src/gui/graphics/contexts/juce_Graphics.cpp b/src/gui/graphics/contexts/juce_Graphics.cpp index 6b10452102..cb6306c608 100644 --- a/src/gui/graphics/contexts/juce_Graphics.cpp +++ b/src/gui/graphics/contexts/juce_Graphics.cpp @@ -478,7 +478,7 @@ void Graphics::drawArrow (const Line& line, const float lineThickness, co fillPath (p); } -void Graphics::fillCheckerBoard (int x, int y, int width, int height, +void Graphics::fillCheckerBoard (const Rectangle& area, const int checkWidth, const int checkHeight, const Colour& colour1, const Colour& colour2) const { @@ -491,29 +491,29 @@ void Graphics::fillCheckerBoard (int x, int y, int width, int height, if (colour1 == colour2) { context->setFill (colour1); - context->fillRect (Rectangle (x, y, width, height), false); + context->fillRect (area, false); } else { - const Rectangle clip (context->getClipBounds()); + const Rectangle clipped (context->getClipBounds().getIntersection (area)); - const int right = jmin (x + width, clip.getRight()); - const int bottom = jmin (y + height, clip.getBottom()); - - int cy = 0; - while (y < bottom) + if (! clipped.isEmpty()) { - int cx = cy; + context->clipToRectangle (clipped); + const int startX = area.getX() + ((clipped.getX() - area.getX()) / checkWidth) * checkWidth; + const int startY = area.getY() + ((clipped.getY() - area.getY()) / checkHeight) * checkHeight; + const int right = clipped.getRight(); + const int bottom = clipped.getBottom(); - for (int xx = x; xx < right; xx += checkWidth) + for (int i = 0; i < 2; ++i) { - context->setFill (((cx++ & 1) == 0) ? colour1 : colour2); - context->fillRect (Rectangle (xx, y, jmin (checkWidth, right - xx), jmin (checkHeight, bottom - y)), - false); - } + context->setFill (i == 0 ? colour1 : colour2); - ++cy; - y += checkHeight; + int cy = i; + for (int y = startY; y < bottom; y += checkHeight) + for (int x = startX + (cy++ & 1) * checkWidth; x < right; x += checkWidth * 2) + context->fillRect (Rectangle (x, y, checkWidth, checkHeight), false); + } } } diff --git a/src/gui/graphics/contexts/juce_Graphics.h b/src/gui/graphics/contexts/juce_Graphics.h index 080a982715..205d014062 100644 --- a/src/gui/graphics/contexts/juce_Graphics.h +++ b/src/gui/graphics/contexts/juce_Graphics.h @@ -256,7 +256,7 @@ public: /** Fills a rectangle with a checkerboard pattern, alternating between two colours. */ - void fillCheckerBoard (int x, int y, int width, int height, + void fillCheckerBoard (const Rectangle& area, int checkWidth, int checkHeight, const Colour& colour1, const Colour& colour2) const; diff --git a/src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp b/src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp index 1b9de841b3..c2b8396b35 100644 --- a/src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp +++ b/src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp @@ -57,7 +57,7 @@ LowLevelGraphicsPostScriptRenderer::LowLevelGraphicsPostScriptRenderer (OutputSt needToClip (true) { stateStack.add (new SavedState()); - stateStack.getLast()->clip = Rectangle (0, 0, totalWidth_, totalHeight_); + stateStack.getLast()->clip = Rectangle (totalWidth_, totalHeight_); const float scale = jmin ((520.0f / totalWidth_), (750.0f / totalHeight)); diff --git a/src/gui/graphics/drawables/juce_DrawablePath.cpp b/src/gui/graphics/drawables/juce_DrawablePath.cpp index 3f0c237990..cb58d8e0dd 100644 --- a/src/gui/graphics/drawables/juce_DrawablePath.cpp +++ b/src/gui/graphics/drawables/juce_DrawablePath.cpp @@ -288,6 +288,7 @@ void DrawablePath::ValueTreeWrapper::setUsesNonZeroWinding (bool b, UndoManager* } //============================================================================== +const Identifier DrawablePath::ValueTreeWrapper::Element::mode ("mode"); const Identifier DrawablePath::ValueTreeWrapper::Element::startSubPathElement ("Move"); const Identifier DrawablePath::ValueTreeWrapper::Element::closeSubPathElement ("Close"); const Identifier DrawablePath::ValueTreeWrapper::Element::lineToElement ("Line"); @@ -308,6 +309,11 @@ DrawablePath::ValueTreeWrapper DrawablePath::ValueTreeWrapper::Element::getParen return ValueTreeWrapper (state.getParent().getParent()); } +DrawablePath::ValueTreeWrapper::Element DrawablePath::ValueTreeWrapper::Element::getPreviousElement() const +{ + return Element (state.getSibling (-1)); +} + int DrawablePath::ValueTreeWrapper::Element::getNumControlPoints() const throw() { const Identifier i (state.getType()); @@ -335,6 +341,18 @@ void DrawablePath::ValueTreeWrapper::Element::setControlPoint (const int index, return state.setProperty (index == 0 ? point1 : (index == 1 ? point2 : point3), point.toString(), undoManager); } +const RelativePoint DrawablePath::ValueTreeWrapper::Element::getStartPoint() const +{ + const Identifier i (state.getType()); + + if (i == startSubPathElement) + return getControlPoint (0); + + jassert (i == lineToElement || i == quadraticToElement || i == cubicToElement || i == closeSubPathElement); + + return getPreviousElement().getEndPoint(); +} + const RelativePoint DrawablePath::ValueTreeWrapper::Element::getEndPoint() const { const Identifier i (state.getType()); @@ -342,9 +360,76 @@ const RelativePoint DrawablePath::ValueTreeWrapper::Element::getEndPoint() const if (i == quadraticToElement) return getControlPoint (1); if (i == cubicToElement) return getControlPoint (2); + jassert (i == closeSubPathElement); return RelativePoint(); } +const String DrawablePath::ValueTreeWrapper::Element::getModeOfEndPoint() const +{ + return state [mode].toString(); +} + +void DrawablePath::ValueTreeWrapper::Element::setModeOfEndPoint (const String& newMode, UndoManager* undoManager) +{ + if (state.hasType (cubicToElement)) + state.setProperty (mode, newMode, undoManager); +} + +void DrawablePath::ValueTreeWrapper::Element::convertToLine (UndoManager* undoManager) +{ + const Identifier i (state.getType()); + + if (i == quadraticToElement || i == cubicToElement) + { + ValueTree newState (lineToElement); + Element e (newState); + e.setControlPoint (0, getEndPoint(), undoManager); + state = newState; + } +} + +void DrawablePath::ValueTreeWrapper::Element::convertToCubic (RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager) +{ + const Identifier i (state.getType()); + + if (i == lineToElement || i == quadraticToElement) + { + ValueTree newState (cubicToElement); + Element e (newState); + + const RelativePoint start (getStartPoint()); + const RelativePoint end (getEndPoint()); + const Point startResolved (start.resolve (nameFinder)); + const Point endResolved (end.resolve (nameFinder)); + e.setControlPoint (0, startResolved + (endResolved - startResolved) * 0.3f, undoManager); + e.setControlPoint (1, startResolved + (endResolved - startResolved) * 0.7f, undoManager); + e.setControlPoint (2, end, undoManager); + + state = newState; + } +} + +void DrawablePath::ValueTreeWrapper::Element::convertToPathBreak (UndoManager* undoManager) +{ + const Identifier i (state.getType()); + + if (i != startSubPathElement) + { + ValueTree newState (startSubPathElement); + Element e (newState); + e.setControlPoint (0, getEndPoint(), undoManager); + state = newState; + } +} + +void DrawablePath::ValueTreeWrapper::Element::insertPoint (double, RelativeCoordinate::NamedCoordinateFinder*, UndoManager*) +{ +} + +void DrawablePath::ValueTreeWrapper::Element::removePoint (UndoManager* undoManager) +{ + state.getParent().removeChild (state, undoManager); +} //============================================================================== const Rectangle DrawablePath::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) @@ -389,7 +474,7 @@ const Rectangle DrawablePath::refreshFromValueTree (const ValueTree& tree needsRedraw = true; } - relativePath = newRelativePath.release(); + relativePath = newRelativePath; if (needsRedraw) damageRect = damageRect.getUnion (getBounds()); diff --git a/src/gui/graphics/drawables/juce_DrawablePath.h b/src/gui/graphics/drawables/juce_DrawablePath.h index cc3685be62..3bd8ab7fcf 100644 --- a/src/gui/graphics/drawables/juce_DrawablePath.h +++ b/src/gui/graphics/drawables/juce_DrawablePath.h @@ -160,13 +160,27 @@ public: const RelativePoint getControlPoint (int index) const; Value getControlPointValue (int index, UndoManager* undoManager) const; + const RelativePoint getStartPoint() const; const RelativePoint getEndPoint() const; void setControlPoint (int index, const RelativePoint& point, UndoManager* undoManager); ValueTreeWrapper getParent() const; + Element getPreviousElement() const; - static const Identifier startSubPathElement, closeSubPathElement, + const String getModeOfEndPoint() const; + void setModeOfEndPoint (const String& newMode, UndoManager* undoManager); + + void convertToLine (UndoManager* undoManager); + void convertToCubic (RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); + void convertToPathBreak (UndoManager* undoManager); + void insertPoint (double proportionOfLength, RelativeCoordinate::NamedCoordinateFinder* nameFinder, UndoManager* undoManager); + void removePoint (UndoManager* undoManager); + + static const Identifier mode, startSubPathElement, closeSubPathElement, lineToElement, quadraticToElement, cubicToElement; + static const char* cornerMode; + static const char* roundedMode; + static const char* symmetricMode; ValueTree state; }; diff --git a/src/gui/graphics/geometry/juce_Line.h b/src/gui/graphics/geometry/juce_Line.h index 9c8ded755b..8e419b1064 100644 --- a/src/gui/graphics/geometry/juce_Line.h +++ b/src/gui/graphics/geometry/juce_Line.h @@ -238,25 +238,42 @@ public: distance from the line; if the point is a long way beyond one of the line's end-point's, it'll return the straight-line distance to the nearest end-point. + pointOnLine receives the position of the point that is found. + @returns the point's distance from the line @see getPositionAlongLineOfNearestPoint */ - ValueType getDistanceFromPoint (const Point& point) const throw() + ValueType getDistanceFromPoint (const Point& targetPoint, + Point& pointOnLine) const throw() { const Point delta (end - start); const double length = delta.getX() * delta.getX() + delta.getY() * delta.getY(); if (length > 0) { - const double prop = ((point.getX() - start.getX()) * delta.getX() - + (point.getY() - start.getY()) * delta.getY()) / length; + const double prop = ((targetPoint.getX() - start.getX()) * delta.getX() + + (targetPoint.getY() - start.getY()) * delta.getY()) / length; if (prop >= 0 && prop <= 1.0) - return point.getDistanceFrom (start + delta * (ValueType) prop); + { + pointOnLine = start + delta * (ValueType) prop; + return targetPoint.getDistanceFrom (pointOnLine); + } } - return jmin (point.getDistanceFrom (start), - point.getDistanceFrom (end)); + const float fromStart = targetPoint.getDistanceFrom (start); + const float fromEnd = targetPoint.getDistanceFrom (end); + + if (fromStart < fromEnd) + { + pointOnLine = start; + return fromStart; + } + else + { + pointOnLine = end; + return fromEnd; + } } /** Finds the point on this line which is nearest to a given point, and diff --git a/src/gui/graphics/geometry/juce_Path.cpp b/src/gui/graphics/geometry/juce_Path.cpp index 7dba9b6ddb..cc6558e256 100644 --- a/src/gui/graphics/geometry/juce_Path.cpp +++ b/src/gui/graphics/geometry/juce_Path.cpp @@ -1051,6 +1051,61 @@ const Line Path::getClippedLine (const Line& line, const bool keep return result; } +float Path::getLength (const AffineTransform& transform) const +{ + float length = 0; + PathFlatteningIterator i (*this, transform); + + while (i.next()) + length += Line (i.x1, i.y1, i.x2, i.y2).getLength(); + + return length; +} + +const Point Path::getPointAlongPath (float distanceFromStart, const AffineTransform& transform) const +{ + PathFlatteningIterator i (*this, transform); + + while (i.next()) + { + const Line line (i.x1, i.y1, i.x2, i.y2); + const float lineLength = line.getLength(); + + if (distanceFromStart <= lineLength) + return line.getPointAlongLine (distanceFromStart); + + distanceFromStart -= lineLength; + } + + return Point (i.x2, i.y2); +} + +float Path::getNearestPoint (const Point& targetPoint, Point& pointOnPath, + const AffineTransform& transform) const +{ + PathFlatteningIterator i (*this, transform); + float bestPosition = 0, bestDistance = std::numeric_limits::max(); + float length = 0; + Point pointOnLine; + + while (i.next()) + { + const Line line (i.x1, i.y1, i.x2, i.y2); + const float distance = line.getDistanceFromPoint (targetPoint, pointOnLine); + + if (distance < bestDistance) + { + bestDistance = distance; + bestPosition = length + pointOnLine.getDistanceFrom (line.getStart()); + pointOnPath = pointOnLine; + } + + length += line.getLength(); + } + + return bestPosition; +} + //============================================================================== const Path Path::createPathWithRoundedCorners (const float cornerRadius) const { diff --git a/src/gui/graphics/geometry/juce_Path.h b/src/gui/graphics/geometry/juce_Path.h index 7ab52a6372..3612af289a 100644 --- a/src/gui/graphics/geometry/juce_Path.h +++ b/src/gui/graphics/geometry/juce_Path.h @@ -159,6 +159,27 @@ public: */ const Line getClippedLine (const Line& line, bool keepSectionOutsidePath) const; + /** Returns the length of the path. + @see getPointAlongPath + */ + float getLength (const AffineTransform& transform = AffineTransform::identity) const; + + /** Returns a point that is the specified distance along the path. + If the distance is greater than the total length of the path, this will return the + end point. + @see getLength + */ + const Point getPointAlongPath (float distanceFromStart, + const AffineTransform& transform = AffineTransform::identity) const; + + /** Finds the point along the path which is nearest to a given position. + This sets pointOnPath to the nearest point, and returns the distance of this point from the start + of the path. + */ + float getNearestPoint (const Point& targetPoint, + Point& pointOnPath, + const AffineTransform& transform = AffineTransform::identity) const; + //============================================================================== /** Removes all lines and curves, resetting the path completely. */ void clear() throw(); diff --git a/src/gui/graphics/geometry/juce_PositionedRectangle.cpp b/src/gui/graphics/geometry/juce_PositionedRectangle.cpp index 8619184bdb..035074204a 100644 --- a/src/gui/graphics/geometry/juce_PositionedRectangle.cpp +++ b/src/gui/graphics/geometry/juce_PositionedRectangle.cpp @@ -143,7 +143,7 @@ void PositionedRectangle::getRectangleDouble (const Rectangle& target, void PositionedRectangle::applyToComponent (Component& comp) const throw() { - comp.setBounds (getRectangle (Rectangle (0, 0, comp.getParentWidth(), comp.getParentHeight()))); + comp.setBounds (getRectangle (Rectangle (comp.getParentWidth(), comp.getParentHeight()))); } //============================================================================== @@ -167,7 +167,7 @@ void PositionedRectangle::updateFromComponent (const Component& comp) throw() if (comp.getParentComponent() == 0 && ! comp.isOnDesktop()) updateFrom (comp.getBounds(), Rectangle()); else - updateFrom (comp.getBounds(), Rectangle (0, 0, comp.getParentWidth(), comp.getParentHeight())); + updateFrom (comp.getBounds(), Rectangle (comp.getParentWidth(), comp.getParentHeight())); } //============================================================================== diff --git a/src/gui/graphics/imaging/juce_Image.h b/src/gui/graphics/imaging/juce_Image.h index fdf39a61f4..b63523998f 100644 --- a/src/gui/graphics/imaging/juce_Image.h +++ b/src/gui/graphics/imaging/juce_Image.h @@ -149,7 +149,7 @@ public: /** Returns a rectangle with the same size as this image. The rectangle's origin is always (0, 0). */ - const Rectangle getBounds() const throw() { return image == 0 ? Rectangle() : Rectangle (0, 0, image->width, image->height); } + const Rectangle getBounds() const throw() { return image == 0 ? Rectangle() : Rectangle (image->width, image->height); } /** Returns the image's pixel format. */ PixelFormat getFormat() const throw() { return image == 0 ? UnknownFormat : image->format; } diff --git a/src/native/linux/juce_linux_Windowing.cpp b/src/native/linux/juce_linux_Windowing.cpp index 92c68f47a2..6c5cf6c7fd 100644 --- a/src/native/linux/juce_linux_Windowing.cpp +++ b/src/native/linux/juce_linux_Windowing.cpp @@ -2851,8 +2851,7 @@ void juce_updateMultiMonitorInfo (Array >& monitorCoords, const if (monitorCoords.size() == 0) { - monitorCoords.add (Rectangle (0, 0, - DisplayWidth (display, DefaultScreen (display)), + monitorCoords.add (Rectangle (DisplayWidth (display, DefaultScreen (display)), DisplayHeight (display, DefaultScreen (display)))); } } diff --git a/src/native/mac/juce_mac_Network.mm b/src/native/mac/juce_mac_Network.mm index bb406af98f..d7b69fbd85 100644 --- a/src/native/mac/juce_mac_Network.mm +++ b/src/native/mac/juce_mac_Network.mm @@ -232,7 +232,7 @@ public: - (void) createConnection { - NSInteger oldRetainCount = [self retainCount]; + NSUInteger oldRetainCount = [self retainCount]; connection = [[NSURLConnection alloc] initWithRequest: request delegate: self]; diff --git a/src/native/windows/juce_win32_Windowing.cpp b/src/native/windows/juce_win32_Windowing.cpp index bc1900c917..a97e4e68f0 100644 --- a/src/native/windows/juce_win32_Windowing.cpp +++ b/src/native/windows/juce_win32_Windowing.cpp @@ -1185,7 +1185,7 @@ private: if (needToPaintAll) { contextClip.clear(); - contextClip.addWithoutMerging (Rectangle (0, 0, w, h)); + contextClip.addWithoutMerging (Rectangle (w, h)); } if (transparent)