Browse Source

New methods for Path, Line, ValueTree. Changed the Graphics::fillCheckerBoard parameters to take a Rectangle object. Fixed Component::centreWithSize to handle multi-monitor setups.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
e3d97820d1
29 changed files with 573 additions and 140 deletions
  1. +1
    -1
      extras/juce demo/Source/demos/RenderingTestComponent.cpp
  2. +1
    -2
      extras/the jucer/src/model/components/jucer_TabbedComponentHandler.h
  3. +1
    -2
      extras/the jucer/src/model/components/jucer_ViewportHandler.h
  4. +1
    -1
      extras/the jucer/src/model/jucer_PaintRoutine.cpp
  5. +1
    -1
      extras/the jucer/src/model/paintelements/jucer_FillType.cpp
  6. +1
    -1
      extras/the jucer/src/utility/jucer_ColourEditorComponent.h
  7. +208
    -53
      juce_amalgamated.cpp
  8. +76
    -13
      juce_amalgamated.h
  9. +9
    -0
      src/containers/juce_ValueTree.cpp
  10. +8
    -0
      src/containers/juce_ValueTree.h
  11. +1
    -1
      src/core/juce_StandardHeader.h
  12. +17
    -14
      src/gui/components/juce_Component.cpp
  13. +4
    -2
      src/gui/components/juce_Component.h
  14. +7
    -8
      src/gui/components/special/juce_ColourSelector.cpp
  15. +2
    -1
      src/gui/components/special/juce_ColourSelector.h
  16. +11
    -7
      src/gui/components/windows/juce_ResizableWindow.cpp
  17. +16
    -16
      src/gui/graphics/contexts/juce_Graphics.cpp
  18. +1
    -1
      src/gui/graphics/contexts/juce_Graphics.h
  19. +1
    -1
      src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp
  20. +86
    -1
      src/gui/graphics/drawables/juce_DrawablePath.cpp
  21. +15
    -1
      src/gui/graphics/drawables/juce_DrawablePath.h
  22. +23
    -6
      src/gui/graphics/geometry/juce_Line.h
  23. +55
    -0
      src/gui/graphics/geometry/juce_Path.cpp
  24. +21
    -0
      src/gui/graphics/geometry/juce_Path.h
  25. +2
    -2
      src/gui/graphics/geometry/juce_PositionedRectangle.cpp
  26. +1
    -1
      src/gui/graphics/imaging/juce_Image.h
  27. +1
    -2
      src/native/linux/juce_linux_Windowing.cpp
  28. +1
    -1
      src/native/mac/juce_mac_Network.mm
  29. +1
    -1
      src/native/windows/juce_win32_Windowing.cpp

+ 1
- 1
extras/juce demo/Source/demos/RenderingTestComponent.cpp View File

@@ -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())


+ 1
- 2
extras/the jucer/src/model/components/jucer_TabbedComponentHandler.h View File

@@ -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));
}


+ 1
- 2
extras/the jucer/src/model/components/jucer_ViewportHandler.h View File

@@ -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));
}


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

@@ -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<int> (0, 0, g.getClipBounds().getRight(), g.getClipBounds().getBottom()),
50, 50,
Colour (0xffdddddd).overlaidWith (backgroundColour),
Colour (0xffffffff).overlaidWith (backgroundColour));


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

@@ -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);


+ 1
- 1
extras/the jucer/src/utility/jucer_ColourEditorComponent.h View File

@@ -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));


+ 208
- 53
juce_amalgamated.cpp View File

@@ -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 <SharedObject*> (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<int> 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<int> 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<int> Component::getLocalBounds() const throw()
{
return Rectangle<int> (0, 0, getWidth(), getHeight());
return Rectangle<int> (getWidth(), getHeight());
}

const Rectangle<int> Component::getParentOrMainMonitorBounds() const
{
return parentComponent_ != 0 ? parentComponent_->getLocalBounds()
: Desktop::getInstance().getMainMonitorArea();
}

const Rectangle<int> Component::getUnclippedArea() const
@@ -41081,8 +41094,8 @@ void Component::internalMouseWheel (MouseInputSource& source, const Point<int>&
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<int> Component::getMouseXYRelative() const
const Rectangle<int> Component::getParentMonitorArea() const
{
return Desktop::getInstance()
.getMonitorAreaContaining (relativePositionToGlobal (Point<int> (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 <Component*> (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 <Component*> (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<int> 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<float>& line, const float lineThickness, co
fillPath (p);
}

void Graphics::fillCheckerBoard (int x, int y, int width, int height,
void Graphics::fillCheckerBoard (const Rectangle<int>& 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<int> (x, y, width, height), false);
context->fillRect (area, false);
}
else
{
const Rectangle<int> clip (context->getClipBounds());
const Rectangle<int> 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<int> (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<int> (x, y, checkWidth, checkHeight), false);
}
}
}

@@ -81272,7 +81287,7 @@ LowLevelGraphicsPostScriptRenderer::LowLevelGraphicsPostScriptRenderer (OutputSt
needToClip (true)
{
stateStack.add (new SavedState());
stateStack.getLast()->clip = Rectangle<int> (0, 0, totalWidth_, totalHeight_);
stateStack.getLast()->clip = Rectangle<int> (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<float> startResolved (start.resolve (nameFinder));
const Point<float> 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<float> DrawablePath::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider)
{
Rectangle<float> damageRect;
@@ -85674,7 +85775,7 @@ const Rectangle<float> DrawablePath::refreshFromValueTree (const ValueTree& tree
needsRedraw = true;
}

relativePath = newRelativePath.release();
relativePath = newRelativePath;

if (needsRedraw)
damageRect = damageRect.getUnion (getBounds());
@@ -90602,6 +90703,61 @@ const Line<float> Path::getClippedLine (const Line<float>& 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<float> (i.x1, i.y1, i.x2, i.y2).getLength();

return length;
}

const Point<float> Path::getPointAlongPath (float distanceFromStart, const AffineTransform& transform) const
{
PathFlatteningIterator i (*this, transform);

while (i.next())
{
const Line<float> 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<float> (i.x2, i.y2);
}

float Path::getNearestPoint (const Point<float>& targetPoint, Point<float>& pointOnPath,
const AffineTransform& transform) const
{
PathFlatteningIterator i (*this, transform);
float bestPosition = 0, bestDistance = std::numeric_limits<float>::max();
float length = 0;
Point<float> pointOnLine;

while (i.next())
{
const Line<float> 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<int>& target,

void PositionedRectangle::applyToComponent (Component& comp) const throw()
{
comp.setBounds (getRectangle (Rectangle<int> (0, 0, comp.getParentWidth(), comp.getParentHeight())));
comp.setBounds (getRectangle (Rectangle<int> (comp.getParentWidth(), comp.getParentHeight())));
}

void PositionedRectangle::updateFrom (const Rectangle<int>& rectangle,
@@ -92217,7 +92373,7 @@ void PositionedRectangle::updateFromComponent (const Component& comp) throw()
if (comp.getParentComponent() == 0 && ! comp.isOnDesktop())
updateFrom (comp.getBounds(), Rectangle<int>());
else
updateFrom (comp.getBounds(), Rectangle<int> (0, 0, comp.getParentWidth(), comp.getParentHeight()));
updateFrom (comp.getBounds(), Rectangle<int> (comp.getParentWidth(), comp.getParentHeight()));
}

PositionedRectangle::AnchorPoint PositionedRectangle::getAnchorPointX() const throw()
@@ -239971,7 +240127,7 @@ private:
if (needToPaintAll)
{
contextClip.clear();
contextClip.addWithoutMerging (Rectangle<int> (0, 0, w, h));
contextClip.addWithoutMerging (Rectangle<int> (w, h));
}

if (transparent)
@@ -258345,8 +258501,7 @@ void juce_updateMultiMonitorInfo (Array <Rectangle<int> >& monitorCoords, const

if (monitorCoords.size() == 0)
{
monitorCoords.add (Rectangle<int> (0, 0,
DisplayWidth (display, DefaultScreen (display)),
monitorCoords.add (Rectangle<int> (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];



+ 76
- 13
juce_amalgamated.h View File

@@ -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<ValueType>& point) const throw()
ValueType getDistanceFromPoint (const Point<ValueType>& targetPoint,
Point<ValueType>& pointOnLine) const throw()
{
const Point<ValueType> 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<float> getClippedLine (const Line<float>& 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<float> 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<float>& targetPoint,
Point<float>& 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<int>& 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<int> getBounds() const throw() { return image == 0 ? Rectangle<int>() : Rectangle<int> (0, 0, image->width, image->height); }
const Rectangle<int> getBounds() const throw() { return image == 0 ? Rectangle<int>() : Rectangle<int> (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<int> getUnclippedArea() const;
void sendVisibilityChangeMessage();
const Rectangle<int> 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 <SwatchComponent> swatchComponents;
const int flags;
int topSpace, edgeGap;
int edgeGap;
Rectangle<int> 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;
};


+ 9
- 0
src/containers/juce_ValueTree.cpp View File

@@ -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 <SharedObject*> (object->children [index]));
}
const var& ValueTree::operator[] (const Identifier& name) const
{
return object == 0 ? var::null : object->getProperty (name);


+ 8
- 0
src/containers/juce_ValueTree.h View File

@@ -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.


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

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


+ 17
- 14
src/gui/components/juce_Component.cpp View File

@@ -791,7 +791,7 @@ const Point<int> 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<int> 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<int> Component::getLocalBounds() const throw()
{
return Rectangle<int> (0, 0, getWidth(), getHeight());
return Rectangle<int> (getWidth(), getHeight());
}
const Rectangle<int> Component::getParentOrMainMonitorBounds() const
{
return parentComponent_ != 0 ? parentComponent_->getLocalBounds()
: Desktop::getInstance().getMainMonitorArea();
}
const Rectangle<int> Component::getUnclippedArea() const
@@ -2637,8 +2641,8 @@ void Component::internalMouseWheel (MouseInputSource& source, const Point<int>&
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<int> Component::getMouseXYRelative() const
const Rectangle<int> Component::getParentMonitorArea() const
{
return Desktop::getInstance()
.getMonitorAreaContaining (relativePositionToGlobal (Point<int> (getWidth() / 2,
getHeight() / 2)));
.getMonitorAreaContaining (relativePositionToGlobal (getLocalBounds().getCentre()));
}
//==============================================================================


+ 4
- 2
src/gui/components/juce_Component.h View File

@@ -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<int> getUnclippedArea() const;
void sendVisibilityChangeMessage();
const Rectangle<int> getParentOrMainMonitorBounds() const;
//==============================================================================
// This is included here just to cause a compile error if your code is still handling


+ 7
- 8
src/gui/components/special/juce_ColourSelector.cpp View File

@@ -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;


+ 2
- 1
src/gui/components/special/juce_ColourSelector.h View File

@@ -149,7 +149,8 @@ private:
HueSelectorComp* hueSelector;
OwnedArray <SwatchComponent> swatchComponents;
const int flags;
int topSpace, edgeGap;
int edgeGap;
Rectangle<int> previewArea;
void setHue (float newH);
void setSV (float newS, float newV);


+ 11
- 7
src/gui/components/windows/juce_ResizableWindow.cpp View File

@@ -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 <Component*> (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 <Component*> (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<int> area (getLocalBounds());
repaint (area.removeFromTop (border.getTop()));
repaint (area.removeFromLeft (border.getLeft()));
repaint (area.removeFromRight (border.getRight()));
repaint (area.removeFromBottom (border.getBottom()));
}
//==============================================================================


+ 16
- 16
src/gui/graphics/contexts/juce_Graphics.cpp View File

@@ -478,7 +478,7 @@ void Graphics::drawArrow (const Line<float>& line, const float lineThickness, co
fillPath (p);
}
void Graphics::fillCheckerBoard (int x, int y, int width, int height,
void Graphics::fillCheckerBoard (const Rectangle<int>& 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<int> (x, y, width, height), false);
context->fillRect (area, false);
}
else
{
const Rectangle<int> clip (context->getClipBounds());
const Rectangle<int> 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<int> (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<int> (x, y, checkWidth, checkHeight), false);
}
}
}


+ 1
- 1
src/gui/graphics/contexts/juce_Graphics.h View File

@@ -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<int>& area,
int checkWidth, int checkHeight,
const Colour& colour1, const Colour& colour2) const;


+ 1
- 1
src/gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp View File

@@ -57,7 +57,7 @@ LowLevelGraphicsPostScriptRenderer::LowLevelGraphicsPostScriptRenderer (OutputSt
needToClip (true)
{
stateStack.add (new SavedState());
stateStack.getLast()->clip = Rectangle<int> (0, 0, totalWidth_, totalHeight_);
stateStack.getLast()->clip = Rectangle<int> (totalWidth_, totalHeight_);
const float scale = jmin ((520.0f / totalWidth_), (750.0f / totalHeight));


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

@@ -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<float> startResolved (start.resolve (nameFinder));
const Point<float> 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<float> DrawablePath::refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider)
@@ -389,7 +474,7 @@ const Rectangle<float> DrawablePath::refreshFromValueTree (const ValueTree& tree
needsRedraw = true;
}
relativePath = newRelativePath.release();
relativePath = newRelativePath;
if (needsRedraw)
damageRect = damageRect.getUnion (getBounds());


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

@@ -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;
};


+ 23
- 6
src/gui/graphics/geometry/juce_Line.h View File

@@ -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<ValueType>& point) const throw()
ValueType getDistanceFromPoint (const Point<ValueType>& targetPoint,
Point<ValueType>& pointOnLine) const throw()
{
const Point<ValueType> 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


+ 55
- 0
src/gui/graphics/geometry/juce_Path.cpp View File

@@ -1051,6 +1051,61 @@ const Line<float> Path::getClippedLine (const Line<float>& 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<float> (i.x1, i.y1, i.x2, i.y2).getLength();
return length;
}
const Point<float> Path::getPointAlongPath (float distanceFromStart, const AffineTransform& transform) const
{
PathFlatteningIterator i (*this, transform);
while (i.next())
{
const Line<float> 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<float> (i.x2, i.y2);
}
float Path::getNearestPoint (const Point<float>& targetPoint, Point<float>& pointOnPath,
const AffineTransform& transform) const
{
PathFlatteningIterator i (*this, transform);
float bestPosition = 0, bestDistance = std::numeric_limits<float>::max();
float length = 0;
Point<float> pointOnLine;
while (i.next())
{
const Line<float> 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
{


+ 21
- 0
src/gui/graphics/geometry/juce_Path.h View File

@@ -159,6 +159,27 @@ public:
*/
const Line<float> getClippedLine (const Line<float>& 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<float> 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<float>& targetPoint,
Point<float>& pointOnPath,
const AffineTransform& transform = AffineTransform::identity) const;
//==============================================================================
/** Removes all lines and curves, resetting the path completely. */
void clear() throw();


+ 2
- 2
src/gui/graphics/geometry/juce_PositionedRectangle.cpp View File

@@ -143,7 +143,7 @@ void PositionedRectangle::getRectangleDouble (const Rectangle<int>& target,
void PositionedRectangle::applyToComponent (Component& comp) const throw()
{
comp.setBounds (getRectangle (Rectangle<int> (0, 0, comp.getParentWidth(), comp.getParentHeight())));
comp.setBounds (getRectangle (Rectangle<int> (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<int>());
else
updateFrom (comp.getBounds(), Rectangle<int> (0, 0, comp.getParentWidth(), comp.getParentHeight()));
updateFrom (comp.getBounds(), Rectangle<int> (comp.getParentWidth(), comp.getParentHeight()));
}
//==============================================================================


+ 1
- 1
src/gui/graphics/imaging/juce_Image.h View File

@@ -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<int> getBounds() const throw() { return image == 0 ? Rectangle<int>() : Rectangle<int> (0, 0, image->width, image->height); }
const Rectangle<int> getBounds() const throw() { return image == 0 ? Rectangle<int>() : Rectangle<int> (image->width, image->height); }
/** Returns the image's pixel format. */
PixelFormat getFormat() const throw() { return image == 0 ? UnknownFormat : image->format; }


+ 1
- 2
src/native/linux/juce_linux_Windowing.cpp View File

@@ -2851,8 +2851,7 @@ void juce_updateMultiMonitorInfo (Array <Rectangle<int> >& monitorCoords, const
if (monitorCoords.size() == 0)
{
monitorCoords.add (Rectangle<int> (0, 0,
DisplayWidth (display, DefaultScreen (display)),
monitorCoords.add (Rectangle<int> (DisplayWidth (display, DefaultScreen (display)),
DisplayHeight (display, DefaultScreen (display))));
}
}


+ 1
- 1
src/native/mac/juce_mac_Network.mm View File

@@ -232,7 +232,7 @@ public:
- (void) createConnection
{
NSInteger oldRetainCount = [self retainCount];
NSUInteger oldRetainCount = [self retainCount];
connection = [[NSURLConnection alloc] initWithRequest: request
delegate: self];


+ 1
- 1
src/native/windows/juce_win32_Windowing.cpp View File

@@ -1185,7 +1185,7 @@ private:
if (needToPaintAll)
{
contextClip.clear();
contextClip.addWithoutMerging (Rectangle<int> (0, 0, w, h));
contextClip.addWithoutMerging (Rectangle<int> (w, h));
}
if (transparent)


Loading…
Cancel
Save